|
@@ -0,0 +1,393 @@
|
|
|
+<template>
|
|
|
+ <el-form ref="form" :model="insideData" :rules="insideRules" :label-width="labelWidth + 'px'">
|
|
|
+ <el-row>
|
|
|
+ <el-col v-for="(value, key, index) in insideConfig" :key="index" :span="24 / value.span">
|
|
|
+ <el-form-item v-if="value.if" :label="value.label" :prop="key">
|
|
|
+ <!-- 解决单选多选框高度太矮导致格式错乱问题 -->
|
|
|
+ <div style="min-height: 40px">
|
|
|
+ <!--
|
|
|
+ 输入框:
|
|
|
+ type: 'input'
|
|
|
+ itemType: 原生 input 的 type(text(默认)、number、password、textarea等,默认text)
|
|
|
+ placeholder: 输入框占位文本,默认‘请输入’+label
|
|
|
+ width: 文本宽度
|
|
|
+ -->
|
|
|
+ <el-input
|
|
|
+ v-if="value.type === 'input'"
|
|
|
+ v-model="insideData[key]"
|
|
|
+ :placeholder="value.placeholder"
|
|
|
+ :type="value.itemType"
|
|
|
+ :disabled="value.disabled"
|
|
|
+ :clearable="value.clearable"
|
|
|
+ :show-password="value.itemType === 'password'"
|
|
|
+ :autosize="{ minRows: 4, maxRows: 7 }"
|
|
|
+ :style="{ width: value.width || '100%' }"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!--
|
|
|
+ 下拉选择框:
|
|
|
+ type: 'select'
|
|
|
+ placeholder: 下拉选择框占位文本,默认‘请选择’+label
|
|
|
+ multiple: 多选,默认false
|
|
|
+ filterable: 可搜索,默认true
|
|
|
+ data: 绑定数据
|
|
|
+ keyName: 绑定key,默认‘key’
|
|
|
+ labelName: 绑定label,默认‘label’
|
|
|
+ dict: 字典
|
|
|
+ setData() 获取数据方法
|
|
|
+ binding: 执行setData()返回参数的绑定路径
|
|
|
+ -->
|
|
|
+ <el-select
|
|
|
+ v-else-if="value.type === 'select'"
|
|
|
+ v-model="insideData[key]"
|
|
|
+ :placeholder="value.placeholder"
|
|
|
+ :multiple="value.multiple"
|
|
|
+ :disabled="value.disabled"
|
|
|
+ :clearable="value.clearable"
|
|
|
+ :filterable="value.filterable"
|
|
|
+ :style="{ width: value.width || '100%' }"
|
|
|
+ >
|
|
|
+ <el-option v-for="item in value.data" :key="item[value.keyName]" :label="item[value.labelName]" :value="item[value.keyName]" />
|
|
|
+ </el-select>
|
|
|
+
|
|
|
+ <!--
|
|
|
+ 单选:
|
|
|
+ type: 'radio'
|
|
|
+ data: 绑定数据
|
|
|
+ keyName: 绑定key,默认‘key’
|
|
|
+ labelName: 绑定label,默认‘label’
|
|
|
+ dict: 字典
|
|
|
+ setData() 获取数据方法
|
|
|
+ binding: 执行setData()返回参数的绑定路径
|
|
|
+ -->
|
|
|
+ <el-radio-group v-else-if="value.type === 'radio'" v-model="insideData[key]" :disabled="value.disabled">
|
|
|
+ <el-radio v-for="item in value.data" :key="item[value.keyName]" :label="item[value.keyName]">
|
|
|
+ {{ item[value.labelName] }}
|
|
|
+ </el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+
|
|
|
+ <!--
|
|
|
+ 多选:
|
|
|
+ type: 'checkbox'
|
|
|
+ keyName: 绑定key
|
|
|
+ labelName: 绑定label
|
|
|
+ dict: 字典
|
|
|
+ setData() 获取数据方法
|
|
|
+ binding: 执行setData()返回参数的绑定路径
|
|
|
+ -->
|
|
|
+ <el-checkbox-group v-else-if="value.type === 'checkbox'" v-model="insideData[key]" :disabled="value.disabled">
|
|
|
+ <el-checkbox v-for="item in value.data" :key="item[value.keyName]" :label="item[value.keyName]">
|
|
|
+ {{ item[value.labelName] }}
|
|
|
+ </el-checkbox>
|
|
|
+ </el-checkbox-group>
|
|
|
+
|
|
|
+ <!--
|
|
|
+ 日期选择器:
|
|
|
+ type: 'datePicker'
|
|
|
+ placeholder: 日期选择框占位文本
|
|
|
+ format: 自定义显示与返回的日期格式
|
|
|
+ itemType: element原生type,默认date(date,week,month,year)
|
|
|
+ pickerOptions: elementUi原生picker-options
|
|
|
+ -->
|
|
|
+ <el-date-picker
|
|
|
+ v-else-if="value.type === 'datePicker'"
|
|
|
+ v-model="insideData[key]"
|
|
|
+ :type="value.itemType"
|
|
|
+ :placeholder="value.placeholder"
|
|
|
+ :format="value.format"
|
|
|
+ :value-format="value.format"
|
|
|
+ :picker-options="value.pickerOptions"
|
|
|
+ :disabled="value.disabled"
|
|
|
+ :clearable="value.clearable"
|
|
|
+ :style="{ width: value.width || '100%' }"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!--
|
|
|
+ 日期范围选择器:
|
|
|
+ type: 'dateRange'
|
|
|
+ beginName: 开始时间绑定名称(默认beginTime)
|
|
|
+ endName: 结束时间绑定名称(默认endTime)
|
|
|
+ -->
|
|
|
+ <el-date-picker
|
|
|
+ v-else-if="value.type === 'dateRange'"
|
|
|
+ v-model="dateRangeData[key]"
|
|
|
+ type="daterange"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ value-format="yyyy-MM-dd"
|
|
|
+ :disabled="value.disabled"
|
|
|
+ :clearable="value.clearable"
|
|
|
+ @change="dateRangeChange(value, key)"
|
|
|
+ :style="{ width: value.width || '100%' }"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!--
|
|
|
+ 单文件上传:
|
|
|
+ type: 'upload'
|
|
|
+ -->
|
|
|
+ <!-- <div v-else-if="value.type === 'upload'">
|
|
|
+ <file-select v-if="!value.disabled" v-model="fileData[key]" @selectAfter="selectFile(key)" />
|
|
|
+ <fly-img style="padding-top: 10px" :src="insideData[key]" :del="!value.disabled" @close="removeFile(key)" />
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <!--
|
|
|
+ 多文件上传:
|
|
|
+ type: 'upload'
|
|
|
+ maxSelectNum: 最多上传几个文件
|
|
|
+ -->
|
|
|
+ <!-- <div v-else-if="value.type === 'uploads'">
|
|
|
+ <file-select v-if="!value.disabled" v-model="insideData[key]" :max-select-num="value.maxSelectNum || 6" />
|
|
|
+ <div v-for="(item, index) in insideData[key]" :key="index">
|
|
|
+ <fly-img style="float: left;padding-top: 10px" :src="item" :del="!value.disabled" @close="insideData[key].splice(index, 1)" />
|
|
|
+ </div>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <!--
|
|
|
+ 插槽:
|
|
|
+ slot: 插槽命名
|
|
|
+ span: 一行有几个el-form-item
|
|
|
+ 例:
|
|
|
+ <template v-slot:key>
|
|
|
+ {{ 'demo' }}
|
|
|
+ </template>
|
|
|
+ -->
|
|
|
+ <slot v-else :name="key" />
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <!--
|
|
|
+ 搜索与重置操作按钮:
|
|
|
+ query: 搜索方法
|
|
|
+ -->
|
|
|
+ <el-col v-if="this.formConfig['operation'] !== undefined" :span="6">
|
|
|
+ <div style="margin-left: 15px">
|
|
|
+ <el-button type="primary" @click="formConfig['operation'].query()">
|
|
|
+ 搜索
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ @click="
|
|
|
+ dateRangeData = []
|
|
|
+ formConfig['operation'].reset()
|
|
|
+ "
|
|
|
+ >
|
|
|
+ 重置
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ name: 'Example',
|
|
|
+ props: {
|
|
|
+ // 表单值
|
|
|
+ value: {
|
|
|
+ type: Object
|
|
|
+ },
|
|
|
+ // 表单配置
|
|
|
+ formConfig: {
|
|
|
+ type: Object,
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ // 全局label宽度
|
|
|
+ labelWidth: {
|
|
|
+ type: Number,
|
|
|
+ default: 80
|
|
|
+ },
|
|
|
+ // 全局列数
|
|
|
+ span: {
|
|
|
+ type: Number,
|
|
|
+ default: 1
|
|
|
+ },
|
|
|
+ // 全局可清空
|
|
|
+ clearable: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ // 全局禁用
|
|
|
+ disabled: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ insideConfig: {}, // 内部配置
|
|
|
+ insideData: {}, // 内部数据
|
|
|
+ insideRules: {}, // 内部必填参数校验
|
|
|
+ dateRangeData: [], // 时间段
|
|
|
+ fileData: [] // 文件路径数组
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ value: {
|
|
|
+ handler() {
|
|
|
+ this.insideData = this.value
|
|
|
+ },
|
|
|
+ deep: true,
|
|
|
+ immediate: true
|
|
|
+ },
|
|
|
+ formConfig: {
|
|
|
+ handler() {
|
|
|
+ this.init()
|
|
|
+ },
|
|
|
+ deep: true,
|
|
|
+ immediate: true
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 初始化
|
|
|
+ init() {
|
|
|
+ this.insideConfig = {}
|
|
|
+ for (const key in this.formConfig) {
|
|
|
+ // 跳过特殊方法( operation: 搜索、重置 )
|
|
|
+ if (key === 'operation') {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ const value = this.formConfig[key]
|
|
|
+ this.insideConfig[key] = {
|
|
|
+ label: value.label,
|
|
|
+ type: value.type ? value.type : 'input',
|
|
|
+ if: value.if === undefined ? true : value.if,
|
|
|
+ span: value.span || this.span,
|
|
|
+ clearable: value.clearable === undefined ? this.clearable : value.clearable,
|
|
|
+ disabled: value.disabled === undefined ? this.disabled : value.disabled
|
|
|
+ }
|
|
|
+ switch (this.insideConfig[key].type) {
|
|
|
+ case 'input':
|
|
|
+ this.inputHandle(key, value)
|
|
|
+ break
|
|
|
+ case 'select':
|
|
|
+ this.selectHandle(key, value)
|
|
|
+ break
|
|
|
+ case 'radio':
|
|
|
+ this.radioHandel(key, value)
|
|
|
+ break
|
|
|
+ case 'checkbox':
|
|
|
+ this.checkboxHandel(key, value)
|
|
|
+ break
|
|
|
+ case 'datePicker':
|
|
|
+ this.datePickerHandel(key, value)
|
|
|
+ break
|
|
|
+ case 'upload':
|
|
|
+ this.uploadHandel(key, value)
|
|
|
+ break
|
|
|
+ case 'uploads':
|
|
|
+ this.uploadsHandel(key, value)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // el-input标签处理
|
|
|
+ inputHandle(key, value) {
|
|
|
+ this.insideConfig[key].placeholder = value.placeholder || '请输入' + value.label
|
|
|
+ this.insideConfig[key].itemType = value.itemType || 'text'
|
|
|
+ },
|
|
|
+
|
|
|
+ // el-select标签处理
|
|
|
+ selectHandle(key, value) {
|
|
|
+ this.insideConfig[key].placeholder = value.placeholder || '请选择' + value.label
|
|
|
+ this.insideConfig[key].multiple = value.multiple === undefined ? false : value.multiple
|
|
|
+ this.insideConfig[key].filterable = value.filterable === undefined ? true : value.filterable
|
|
|
+ this.insideConfig[key].keyName = value.keyName || 'key'
|
|
|
+ this.insideConfig[key].labelName = value.labelName || 'label'
|
|
|
+ this.setData(key, value)
|
|
|
+ },
|
|
|
+
|
|
|
+ // el-radio标签处理
|
|
|
+ radioHandel(key, value) {
|
|
|
+ this.insideConfig[key].keyName = value.keyName || 'key'
|
|
|
+ this.insideConfig[key].labelName = value.labelName || 'label'
|
|
|
+ this.setData(key, value)
|
|
|
+ },
|
|
|
+
|
|
|
+ // el-checkbox标签处理
|
|
|
+ checkboxHandel(key, value) {
|
|
|
+ // 默认值
|
|
|
+ if (!this.insideData[key]) {
|
|
|
+ this.$set(this.insideData, key, [])
|
|
|
+ }
|
|
|
+ this.insideConfig[key].keyName = value.keyName || 'key'
|
|
|
+ this.insideConfig[key].labelName = value.labelName || 'label'
|
|
|
+ this.setData(key, value)
|
|
|
+ },
|
|
|
+
|
|
|
+ // el-datePicker标签处理
|
|
|
+ datePickerHandel(key, value) {
|
|
|
+ this.insideConfig[key].placeholder = value.placeholder || '请选择日期'
|
|
|
+ this.insideConfig[key].itemType = value.itemType || 'date'
|
|
|
+ this.insideConfig[key].format = value.format || 'yyyy-MM-dd'
|
|
|
+ },
|
|
|
+
|
|
|
+ // 单文件上传处理
|
|
|
+ uploadHandel(key) {
|
|
|
+ if (this.insideData[key]) {
|
|
|
+ this.$set(this.fileData, key, [this.insideData[key]])
|
|
|
+ } else if (!this.fileData[key]) {
|
|
|
+ this.$set(this.fileData, key, [])
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 多文件上传处理
|
|
|
+ uploadsHandel(key, value) {
|
|
|
+ this.insideConfig[key].maxSelectNum = value.maxSelectNum || 6
|
|
|
+ if (!this.insideData[key]) {
|
|
|
+ this.$set(this.insideData, key, [])
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取数据方法
|
|
|
+ async setData(key, value) {
|
|
|
+ if (value.data) {
|
|
|
+ this.insideConfig[key].data = value.data
|
|
|
+ } else if (value.dict) {
|
|
|
+ this.insideConfig[key].keyName = 'dictValue'
|
|
|
+ this.insideConfig[key].labelName = 'dictLabel'
|
|
|
+ this.insideConfig[key].data = await this.getDicts(value.dict)
|
|
|
+ this.$forceUpdate()
|
|
|
+ } else {
|
|
|
+ const itemData = await value.setData()
|
|
|
+ if (value.binding) {
|
|
|
+ this.insideConfig[key].data = value.binding.split('.').reduce((total, cur) => total[cur], itemData)
|
|
|
+ } else {
|
|
|
+ this.insideConfig[key].data = itemData
|
|
|
+ }
|
|
|
+ this.$forceUpdate()
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 赋值开始时间结束时间
|
|
|
+ dateRangeChange(value, key) {
|
|
|
+ if (this.dateRangeData[key] !== null) {
|
|
|
+ this.$set(this.insideData, value['beginName'] || 'beginTime', this.dateRangeData[key][0])
|
|
|
+ this.$set(this.insideData, value['endName'] || 'endTime', this.dateRangeData[key][1])
|
|
|
+ } else {
|
|
|
+ this.$set(this.insideData, value['beginName'] || 'beginTime', undefined)
|
|
|
+ this.$set(this.insideData, value['endName'] || 'endTime', undefined)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 选择图片
|
|
|
+ selectFile(key) {
|
|
|
+ if (this.fileData[key].length > 0) {
|
|
|
+ this.$set(this.insideData, key, this.fileData[key][0])
|
|
|
+ } else {
|
|
|
+ this.$set(this.insideData, key, undefined)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 删除图片
|
|
|
+ removeFile(key) {
|
|
|
+ this.$set(this.fileData, key, [])
|
|
|
+ this.$set(this.insideData, key, undefined)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+</style>
|