# 组件方法

# 导出组件


<template>
  <q-dialog title="导出" :visible.sync="openExport" width="90%" height="90vh" append-to-body>

    <QTable :columns="exportColumn"
            :options="exportOptions"
            :show-tool="true"
            :fileName="excelConfig.sheet.name"
            :excelConfig="excelConfig"
            :fetch="listInfo"
            :fetchParams="queryParams"
    >
    </QTable>
    <div slot="footer" class="dialog-footer">
      <el-button @click="openExport = false">关 闭</el-button>
    </div>
  </q-dialog>
</template>

<script>
  export default {
    data() {
      return {
        openExport: false,
        excelConfig: {
          type: 'table',
          sheet: {
            name: '餐卡信息'
          }
        },
        exportColumn: [
          {
            type: 'selection',
            label: 'selection',
            visible: true,
            width: 55
          },
          {
            type: 'index',
            label: '序号',
            visible: true,
            width: 55
          },
          {
            prop: 'cardNo',
            label: '卡号',
            visible: true
          },
          {
            prop: 'cardType',
            label: '卡类型',
            type: 'dict.klx',
            visible: true
          },
        ]
      }
    },
    computed: {
      exportOptions() {
        return {
          ...this.dict.type,
          'czt': [
            {
              label: '正常',
              value: 0
            },
            {
              label: '挂失',
              value: 1
            }
          ]
        }
      }
    },
  }
</script>

# 导入组件


<template>
  <el-col :span="1.5">
    <el-button
        type="info"
        plain
        icon="el-icon-upload2"
        size="mini"
        @click="handleImport"
    >导入
    </el-button>
  </el-col>

  <el-dialog :title="upload.title" :visible.sync="upload.open" width="640px" append-to-body>
    <el-card class="box-card" style="margin-bottom: 20px;">
      <div slot="header" class="clearfix">
        <span>字段参考</span>
      </div>
      <div>
        <template v-for="item in dict.type.klx" v-if="dict.type.klx">
          <dict-tag :options="dict.type.klx" :value="item.value" style="display: inline-block"/>
          <el-divider direction="vertical"></el-divider>
        </template>
        <!--          <span>{{dict.type.ajlx.map(item=>item.label).join("、")}}</span>-->
        <el-divider content-position="left">卡类型</el-divider>

        <template v-for="item in exportOptions.czt" v-if="exportOptions.czt">
          <!--            <dict-tag :options="exportOptions.czt" :value="item.value" style="display: inline-block"/>-->
          <span>{{ item.label }}</span>
          <el-divider direction="vertical"></el-divider>
        </template>
        <!--          <span>{{dict.type.ysf.map(item=>item.label).join("、")}}</span>-->
        <el-divider content-position="left">状态</el-divider>
      </div>
    </el-card>
    <div style="display: flex;align-items: center;justify-content: center">
      <el-upload
          style="width: 100%;"
          ref="upload"
          :limit="1"
          accept=".xlsx, .xls"
          :headers="upload.headers"
          :action="upload.url + '?updateSupport=' + upload.updateSupport"
          :disabled="upload.isUploading"
          :on-progress="handleFileUploadProgress"
          :on-success="handleFileSuccess"
          :auto-upload="false"
          drag
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <div class="el-upload__tip text-center" slot="tip">
          <div class="el-upload__tip" slot="tip">
            <!--            <el-checkbox v-model="upload.updateSupport"/>-->
            <span style="color: red;"> 请参考上方字段进行填写</span>
          </div>
          <span>仅允许导入xls、xlsx格式文件。</span>
          <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;"
                   @click="importTemplate"
          >下载模板
          </el-link>
        </div>
      </el-upload>
    </div>
    <div slot="footer" class="dialog-footer">
      <el-button type="primary" @click="submitFileForm">确 定</el-button>
      <el-button @click="upload.open = false">取 消</el-button>
    </div>
  </el-dialog>

</template>

<script>
  export default {
    data() {
      return {
        // 导入参数
        upload: {
          // 是否显示弹出层(导入)
          open: false,
          // 弹出层标题(导入)
          title: '' + '导入',
          //加载动画
          loading: null,
          // 是否禁用上传
          isUploading: false,
          // 是否更新已经存在的用户数据
          updateSupport: 0,
          // 设置上传的请求头部
          headers: {Authorization: 'Bearer ' + getToken()},
          // 上传的地址
          url: process.env.VUE_APP_BASE_API + '/canteen/info/importData',
          // 下载的地址(开头无/)
          urlDownload: 'canteen/supplier/importTemplate',
        }
      }
    },
    computed: {
      exportOptions() {
        return {
          ...this.dict.type,
          'czt': [
            {
              label: '正常',
              value: 0
            },
            {
              label: '挂失',
              value: 1
            }
          ]
        }
      }
    },
    methods: {
      /** 导入按钮操作 */
      handleImport() {
        this.upload.open = true
      },
      /** 下载模板操作 */
      importTemplate() {
        this.download(this.upload.urlDownload, {}, `${this.upload.title}模板_${new Date().getTime()}.xlsx`)
      },
      // 文件上传中处理
      handleFileUploadProgress(event, file, fileList) {
        this.upload.loading = this.$loading({
          lock: true,
          text: '正在提交数据......',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.3)'
        })
        this.upload.isUploading = true
      },
      // 文件上传成功处理
      handleFileSuccess(response, file, fileList) {
        this.upload.open = false
        this.upload.loading.close()
        this.upload.isUploading = false
        this.$refs.upload.clearFiles()
        this.$alert('<div style=\'overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;\'>' + response.msg + '</div>', '导入结果', {dangerouslyUseHTMLString: true})
        this.getList()
      },
      // 提交上传文件
      submitFileForm() {
        this.$refs.upload.submit()
      }
    }
  }
</script>

<style scoped lang="scss">
  ::v-deep .el-upload-dragger {
    background-color: #fff;
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    width: 600px !important;
    height: 180px;
    text-align: center;
    cursor: pointer;
    overflow: hidden;
  }
</style>

# 动态组件


<template>
  <component :is="currentComponent" v-bind="componentProps"/>
</template>
<script>
  export default {
    data() {
      return {
        currentComponent: null,
        componentProps: {},
        formData: {} // 假设这是你要传递给组件的参数
      }
    },
    created() {
      this.componentProps = {form: this.formData}
    },
    methods: {
      async loadComponent(path) {
        try {
          // 动态导入组件
          const components = require.context('@/views', true, /\.vue$/)
          console.log('null==>', `@/views${path}.vue`)
          const component = components(`.${path}.vue`)
          this.currentComponent = component.default || component
        } catch (error) {
          this.$modal.msgError('加载组件失败:', error)
        }
      },
    }
  }
</script>

# 表单验证

使用 Element-UIForm (opens new window)表单。


<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">

  <el-row :gutter="10">
    <el-col :span="12">
      <el-form-item label="活动名称" prop="name">
        <el-input v-model="ruleForm.name"></el-input>
      </el-form-item>
    </el-col>
    <el-col :span="12">
      <el-form-item label="活动年号" prop="desc">
        <el-input type="textarea" v-model="ruleForm.desc"></el-input>
      </el-form-item>
    </el-col>
  </el-row>
  <el-row :gutter="10">
    <el-col :span="12">
      <el-form-item label="活动区域" prop="region">
        <el-select v-model="ruleForm.region" placeholder="请选择活动区域">
          <el-option label="区域一" value="shanghai"></el-option>
          <el-option label="区域二" value="beijing"></el-option>
        </el-select>
      </el-form-item>
    </el-col>
    <el-col :span="12">
      <el-form-item label="活动时间" required>
        <el-form-item prop="date1">
          <el-date-picker type="date" placeholder="选择日期" v-model="ruleForm.date1"
                          style="width: 100%;"></el-date-picker>
        </el-form-item>
      </el-form-item>
    </el-col>
  </el-row>

  <el-row :gutter="10">
    <el-col :span="12">
      <el-form-item label="活动性质" prop="type">
        <el-checkbox-group v-model="ruleForm.type">
          <el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
          <el-checkbox label="地推活动" name="type"></el-checkbox>
        </el-checkbox-group>
      </el-form-item>
    </el-col>
    <el-col :span="12">
      <el-form-item label="特殊资源" prop="resource">
        <el-radio-group v-model="ruleForm.resource">
          <el-radio label="线上品牌商赞助"></el-radio>
          <el-radio label="线下场地免费"></el-radio>
        </el-radio-group>
      </el-form-item>
    </el-col>
  </el-row>

  <el-form-item>
    <el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
    <el-button @click="resetForm('ruleForm')">重置</el-button>
  </el-form-item>
</el-form>
<script>
  export default {
    data() {
      return {
        ruleForm: {
          name: '',
          region: '',
          date1: '',
          type: [],
          resource: '',
          desc: ''
        },
        rules: {
          pchmName: [
            {required: true, message: "材料名称" + "不能为空", trigger: "blur"}
          ],
          pchmWay: [
            {required: true, message: "采购方式" + "不能为空", trigger: "change"}
          ],
          name: [
            {required: true, message: '请输入活动名称', trigger: 'blur'},
            {min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur'}
          ],
          region: [
            {required: true, message: '请选择活动区域', trigger: 'change'}
          ],
          date1: [
            {type: 'date', required: true, message: '请选择日期', trigger: 'change'}
          ],
          type: [
            {type: 'array', required: true, message: '请至少选择一个活动性质', trigger: 'change'}
          ],
          resource: [
            {required: true, message: '请选择活动资源', trigger: 'change'}
          ],
          desc: [
            {required: true, message: '请填写活动年号', trigger: 'blur'},
            {
              validator: (rule, value, callback) => {
                if (!/^\d+$/.test(value)) {
                  callback(new Error('年号必须为数字'))
                } else {
                  const year = parseInt(value)
                  if (isNaN(year) || year < 1000 || year > 2099) {
                    callback(new Error('年号范围为1000-2099'))
                  } else {
                    callback()
                  }
                }
              },
              trigger: 'blur'
            }
          ]
        }
      };
    },
    methods: {
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            alert('submit!');
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      }
    }
  }
</script>

Expand Copy

# 时间范围

null 至 null

<template>
  <div>


    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px">
      <el-form-item label="时间范围">
        <el-select v-model="queryParams.dateType" @change="handleChange"
                   placeholder="请选择时间类型" style="width:80px;" clearable
        >
          <el-option label="" value="1"></el-option>
          <el-option label="" value="2"></el-option>
          <el-option label="" value="3"></el-option>
          <el-option label="" value="4"></el-option>
          <el-option label="范围" value="5"></el-option>
        </el-select>
        <el-date-picker
            v-model="queryParams.dateTime"
            type="daterange"
            key="daterange"
            v-if="queryParams.dateType==5"
            value-format="yyyy-MM-dd"
            range-separator=""
            start-placeholder="开始日期"
            end-placeholder="结束日期"
        >
        </el-date-picker>
        <el-date-picker
            v-model="queryParams.dateTime"
            key="date"
            v-bind="dateProps"
            v-else
        >
        </el-date-picker>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
    <div>
      <span>{{queryParams.beginTime + ' 至 '+queryParams.endTime}}</span>
    </div>
  </div>
</template>

<script>
  export default {
    components: {},
    data() {
      return {
        queryParams: {
          pageNum:1,
          pageSize:10,
          dateType: '1',
          dateTime: null,
          beginTime: null,
          endTime: null
        },
        dateProps: {
          type: 'date',
          placeholder: '选择一个日期',
          valueFormat: 'yyyy-MM-dd'
        },
        timeTypeMap: {
          1: 'day',
          2: 'week',
          3: 'month',
          4: 'year',
          5: 'range'
        }
      }
    },
    watch: {
      'queryParams.dateTime': {
        handler(date) {
          console.log('mealDate==>', date)
          this.queryParams.beginTime = null
          this.queryParams.endTime = null
          if (date) {
            if (this.queryParams.dateType in this.timeTypeMap) {
              let timeType = this.timeTypeMap[this.queryParams.dateType]
              let time = this.getRange(date, timeType)

              // 对于 dateType 为 2 时,设置格式
              if (this.queryParams.dateType == 2) {
                this.dateProps.format = time.startTime.split(' ')[0] + ' 至 ' + time.endTime.split(' ')[0]
                // this.dateProps.format = time.startTime + ' 至 ' + time.endTime
              }

              // 设置 beginTime 和 endTime
              this.queryParams.beginTime = time.startTime
              this.queryParams.endTime = time.endTime
            }
            this.getList()
          }

        },
        deep: true
      },
      'queryParams.dateType': {
        handler(value) {
          if (value) {
            if (value == 5) {
              const today = new Date().toISOString().split('T')[0]
              this.queryParams.dateTime = [today, today]
            } else {
              this.queryParams.dateTime = new Date().toISOString().split('T')[0]
            }
          }
        },
        deep: true,
        immediate: true
      }
    },
    methods: {
      getRange(input, type,flag = true) {
        let startDate
        let endDate
        // 将输入(例如 '2025-02')分解为年份和月份
        if (type === 'range') {
          startDate = new Date(input[0])
          endDate = new Date(input[1])
        } else {
          const [year, month] = input.split('-').map(Number)
          if (type === 'month') {
            // 获取该月份的第一天和最后一天
            startDate = new Date(year, month - 1, 1)
            endDate = new Date(year, month, 0)
            // 在开始和结束日期上加一天
            startDate.setDate(startDate.getDate() + 1) // 一天
            endDate.setDate(endDate.getDate() + 1) // 延后一天
          } else if (type === 'year') {

            // 获取该年的第一天和最后一天
            startDate = new Date(year, 0, 1)
            endDate = new Date(year, 11, 31)

            // 在开始和结束日期上加一天
            startDate.setDate(startDate.getDate() + 1) // 一天
            endDate.setDate(endDate.getDate() + 1) // 延后一天
          } else if (type === 'week') {
            const inputDate = new Date(input)
            startDate = new Date(inputDate)
            const dayOfWeek = startDate.getDay()
            const diff = startDate.getDate() - dayOfWeek + (dayOfWeek == 0 ? -6 : 1) // 0表示周日
            startDate.setDate(diff)
            endDate = new Date(startDate)
            endDate.setDate(startDate.getDate() + 6)
          } else if (type === 'day') {
            startDate = new Date(input)
            endDate = new Date(input)
          }
        }

        return {
          startTime: startDate.toISOString().split('T')[0] + (flag ? ' 00:00:00' : ''), 
          endTime: endDate.toISOString().split('T')[0] + (flag ? ' 23:59:59' : '')
        }
      },
      handleQuery() {
        console.log('null==>', this.queryParams)
        this.getList()
      },
      resetQuery() {
        this.queryParams = {
          pageNum:1,
          pageSize:10,
          dateType: '1',
          dateTime: null,
          beginTime: null,
          endTime: null
        }
        this.dateProps = {
          type: 'date',
          placeholder: '选择一个日期',
          valueFormat: 'yyyy-MM-dd'
        }
      },
      handleChange(data) {
        console.log('handleChange==>', data)
        // this.queryParams.dateType = data
        this.queryParams.dateTime = null
        if (data == 2) {
          this.dateProps = {
            type: 'week',
            format: '',
            placeholder: '选择周',
            valueFormat: 'yyyy-MM-dd',
            pickerOptions: {
              firstDayOfWeek: 1
            }
          }
        } else if (data == 3) {
          this.dateProps = {
            type: 'month',
            placeholder: '选择一个月',
            valueFormat: 'yyyy-MM'
          }
        } else if (data == 4) {
          this.dateProps = {
            type: 'year',
            placeholder: '选择一个年',
            valueFormat: 'yyyy'
          }
        } else if (data == 5) {
        } else {
          this.dateProps = {
            type: 'date',
            placeholder: '选择一个日期',
            valueFormat: 'yyyy-MM-dd'
          }
        }
      },
      getList() {
        // getTimeStatic().then(res=>{
        //
        // })
      },
    }
  }

</script>

Expand Copy