var kForm = Vue.extend({ template: '<div>' + ' <el-form' + ' :model="forms"' + ' :rules="rules"' + ' ref="ruleForm"' + ' :label-width="labelWidth"' + ' class="form">' + ' <template v-for="data in formProps">' + ' <!-- input -->' + ' <el-form-item' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' :ref="data.prop"' + ' v-if="data.inputType === \'input\' && data.show == null ? true : data.show">' + ' <el-input' + ' :disabled="data.disabled"' + ' v-model="forms[data.prop]"' + ' :placeholder="data.placeholder">' + ' </el-input>' + ' </el-form-item>' + ' <!-- radio -->' + ' <el-form-item' + ' :ref="data.prop"' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' v-else-if="data.inputType === \'radio\' && data.show == null ? true : data.show">' + ' <el-radio-group v-model="forms[data.prop]">' + ' <el-radio' + ' @change="((val) => {radioChangeHandle(data.prop, val)})"' + ' :disabled="item.disabled"' + ' v-model="radio"' + ' :label="item.id"' + ' v-for="item in data.options"' + ' :key="item.id">' + ' {{item.name}}' + ' </el-radio>' + ' </el-radio-group>' + ' </el-form-item>' + ' <!-- checkbox -->' + ' <el-form-item' + ' :ref="data.prop"' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' v-else-if="data.inputType === \'checkbox\' && data.show == null ? true : data.show">' + ' <el-checkbox-group v-model="forms[data.prop]">' + ' <el-checkbox' + ' :disabled="data.disabled"' + ' :label="item.label"' + ' :name="forms[data.prop]"' + ' v-for="item in data.options"' + ' :key="item.id"' + ' >' + ' </el-checkbox>' + ' </el-checkbox-group>' + ' </el-form-item>' + ' <!-- textarea -->' + ' <el-form-item' + ' :ref="data.prop"' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' v-else-if="data.inputType === \'textarea\' && data.show == null ? true : data.show">' + ' <el-input' + ' :disabled="data.disabled"' + ' type="textarea"' + ' :placeholder="data.placeholder"' + ' v-model="forms[data.prop]">' + ' </el-input>' + ' </el-form-item>' + ' <!-- cascader -->' + ' <el-form-item' + ' :ref="data.prop"' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' v-else-if="data.inputType === \'cascader\' && data.show == null ? true : data.show">' + ' <el-date-picker' + ' :change-on-select="data.changeOnSelect"' + ' filterable' + ' :disabled="data.disabled"' + ' style="width: 100%;"' + ' v-model="forms[data.prop]"' + ' type="date"' + ' :placeholder="data.placeholder">' + ' </el-date-picker>' + ' </el-form-item>' + ' <!-- inputTree -->' + ' <el-form-item' + ' :ref="data.prop"' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' v-else-if="data.inputType === \'inputTree\' && data.show == null ? true : data.show">' + ' <div v-show="isReference(data.reference)">' + ' <el-popover' + ' v-model="data.visible"' + ' placement="bottom-start"' + ' width="400"' + ' trigger="click">' + ' <div class="max-height">' + ' <el-tree' + ' node-key="id"' + ' @current-change="((a, b) => {treeCurrentChangeHandle(data, a, b)})"' + ' :highlight-current="true"' + ' :default-expand-all="true"' + ' :expand-on-click-node="false"' + ' :data="data.options"' + ' :ref="data.prop"' + ' :props="data.defaultProps || defaultProps"/>' + ' </div>' + ' <el-input' + ' v-model="forms[data.prop]"' + ' readonly' + ' slot="reference"' + ' :placeholder="data.placeholder"></el-input>' + ' </el-popover>' + ' </div>' + ' <el-input' + ' v-model="forms[data.prop]"' + ' readonly' + ' v-show="!isReference(data.reference)"' + ' :placeholder="data.placeholder"></el-input>' + ' </el-form-item>' + ' <!-- tree -->' + ' <el-form-item' + ' :ref="data.prop"' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' v-else-if="data.inputType === \'tree\' && data.show == null ? true : data.show">' + ' <el-tree' + ' :check-strictly="data.checkStrictly || false"' + ' :data="data.options"' + ' show-checkbox' + ' default-expand-all' + ' node-key="id"' + ' :ref="data.prop + \'Tree\'"' + ' highlight-current' + ' @check="((a, b) => {checkHandle(data.prop, a, b)})"' + ' :props="data.defaultProps || treeDefaultProps">' + ' </el-tree>' + ' </el-form-item>' + ' <!-- 单个 select -->' + ' <el-form-item' + ' :ref="data.prop"' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' v-else-if="!isArray(data) && data.inputType === \'select\' && data.show == null ? true : data.show">' + ' <el-select' + ' @change="((val) => {selectChangeHandle(data.prop, val)})"' + ' filterable' + ' :disabled="data.disabled"' + ' :multiple="data.multiple"' + ' v-model="forms[data.prop]"' + ' :placeholder="data.placeholder"' + ' style="width: 100%">' + ' <el-option' + ' v-for="item in data.options"' + ' :key="item.id"' + ' :label="item.label"' + ' :value="item.id">' + ' </el-option>' + ' </el-select>' + ' </el-form-item>' + ' <!-- 多个 select -->' + ' <el-form-item' + ' class="more"' + ' :key="data[0].label"' + ' :label="data[0].label"' + ' v-else-if="isArray(data) && data[0].inputType === \'select\' && data.show == null ? true : data.show">' + ' <el-col' + ' :span="12"' + ' v-for="select in data"' + ' :key="select.label">' + ' <el-form-item :prop="hasProps(select.prop)">' + ' <el-select' + ' filterable' + ' :disabled="select.disabled"' + ' v-model="forms[select.prop]"' + ' :placeholder="select.placeholder"' + ' style="width: 100%">' + ' <el-option' + ' v-for="item in select.options"' + ' :key="item.id"' + ' :label="item.label"' + ' :value="item.id">' + ' </el-option>' + ' </el-select>' + ' </el-form-item>' + ' </el-col>' + ' </el-form-item>' + ' <!-- other -->' + ' <el-form-item' + ' :ref="data.prop"' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' v-else-if="data.inputType === \'other\' && data.show == null ? true : data.show">' + ' <slot :name="data.prop + \'Form\'"></slot>' + ' </el-form-item>' + ' <!-- upload -->' + ' <el-form-item' + ' :ref="data.prop"' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' v-else-if="data.inputType === \'upload\' && data.show == null ? true : data.show">' + ' <el-upload' + ' :accept="uploadForm.accept"' + ' class="upload-form"' + ' :action="uploadForm.action"' + ' :on-remove="handleUploadRemove"' + ' :multiple="uploadForm.multiple"' + ' :limit="uploadForm.limit"' + ' :on-success="((a, b) => {handleUploadSuccess(data.prop, a, b)})"' + ' :on-exceed="handleUploadExceed"' + ' :on-error="handleUploadError"' + ' :file-list="forms[data.prop]">' + ' <div class="form-inline" style="padding-right: 75px;">' + ' <el-input' + ' readonly' + ' style="width: 100%"' + ' v-model="forms[data.prop]"' + ' :placeholder="data.placeholder">' + ' </el-input>' + ' <el-button type="primary" class="upload-btn">上传</el-button>' + ' </div>' + ' </el-upload>' + ' </el-form-item>' + ' <!-- avatar -->' + ' <el-form-item' + ' :ref="data.prop"' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' v-else-if="data.inputType === \'avatar\' && data.show == null ? true : data.show">' + ' <el-upload' + ' :data="{id: forms.id}"' + ' class="avatar-uploader"' + ' :action="uploadForm.action"' + ' :show-file-list="false"' + ' :on-error="handleAvatarError"' + ' :on-success="((a, b) => {handleAvatarSuccess(data.prop, a, b)})"' + ' :before-upload="beforeAvatarUpload">' + ' <img v-if="avatarUrl" :src="avatarUrl" class="avatar">' + ' <i v-else class="el-icon-plus avatar-uploader-icon"></i>' + ' </el-upload>' + ' <el-input v-model="forms[data.prop]" type="hidden"/>' + ' </el-form-item>' + ' </el-col>' + ' <!-- datePicker -->' + ' <el-col :span="24 / 2">' + ' <el-form-item' + ' :ref="data.prop"' + ' :key="data.label"' + ' :label="data.label"' + ' :prop="hasProps(data.prop)"' + ' v-else-if="data.inputType === \'datePicker\' && data.show == null ? true : data.show">' + ' <el-date-picker' + ' @change="((a) => {datePickerChangeHandle(data.prop, a)})"' + ' style="width: 100%;"' + ' :range-separator="data.rangeSeparator ? data.rangeSeparator : dataPickerOption.rangeSeparator"' + ' v-model="forms[data.prop]"' + ' :type="data.type ? data.type : dataPickerOption.type"' + ' :placeholder="data.placeholder">' + ' </el-date-picker>' + ' </el-form-item>' + ' </template>' + ' </el-form>' + '{{forms}}' + '</div>', props: { // other类型数据存放位置 otherData: { type: Object, default () { return {} } }, // 上传配置 upload: { type: Object, default () { return { // 上传路劲 action: '/upload', // 是否支持多选文件 multiple: true, // 最大允许上传个数 limit: 3, // 接受上传的文件类型 accept: '' } } }, // 表单详情数据 formProps: { type: Array, default () { return [] } }, // 表单名宽度 labelWidth: { type: String, default: '100px' }, // 规则 rules: { type: Object, default () { return {} } }, // 数据 data: { type: Object, default () { return {} } }, // 表单字段 form: { type: Object, default () { return {} } } }, data () { return { dataPickerOption: { rangeSeparator: '至', type: 'date' // week, year, dates, daterange }, uploadForm: { // 上传路劲 action: '/upload', // 是否支持多选文件 multiple: true, // 最大允许上传个数 limit: 3, // 接受上传的文件类型 accept: '.jpg,.png,.jpeg' }, popoverVisible: false, // form表单 forms: {}, // 配置选项 select defaultProps: { children: 'children', label: 'label' }, // 配置选项 tree treeDefaultProps: { children: 'children', label: 'label' }, // 头像路劲 avatarUrl: '' } }, watch: { // 把other类型数据赋值到forms otherData: { handler (newVal) { if (isObject(newVal) && !isEmptyObject(newVal)) { for (let key in newVal) { if (this.forms.hasOwnProperty(key)) { this.$set(this.forms, key, clonedeep(newVal[key])) this.$refs.ruleForm.validateField(key) } } } }, immediate: true, deep: true }, // 当数据传递时对form表单进行赋值操作 data: { handler (newVal) { this.forms = clonedeep(this.form) if (isObject(newVal)) { for (let key in this.forms) { this.$set(this.forms, key, newVal[key]) } } }, immediate: true, deep: true }, upload: { handler (newVal) { for (let key in newVal) { if (newVal[key]) { this.uploadForm[key] = newVal[key] } } }, immediate: true, deep: true } }, methods: { isReference (reference) { if (isBoolean(reference)) { if (reference) { return true } else { return false } } else { return true } }, // 是否是数组 isArray (val) { return isArray(val) }, // 是否是必选 hasProps (prop) { let rules = this.rules for (let key in rules) { if (prop === key && isArray(rules[key])) { return key } } return '' }, // 表单数据清空 clearForm () { resetObject(this.forms) }, // 级联 handleCascaderChange (value) { }, // 表单提交 submitHandle () { let data = clonedeep(this.forms) this.$refs.ruleForm.validate((valid) => { if (valid) { console.log('submit!', data) this.$emit('submit-handle', data) } else { return false } }) }, // 表单验证 validate () { this.$refs.ruleForm.validate() }, // 表单去验证 clearValidate () { this.$refs.ruleForm.clearValidate() }, // 表单重置 resetForm () { this.$refs.ruleForm.resetFields() }, // 上级菜单选择 inputtree treeCurrentChangeHandle (data, treeData, node) { var index = -1 this.forms[data.prop] = data.defaultProps ? treeData[data.defaultProps.label] : treeData.label this.forms[data.defaultProp] = treeData.id this.formProps.forEach((item, i) => { if (item.prop === data.prop) { index = i return false } }) if (index > -1) { this.formProps[index].visible = false } }, // 当复选框被点击的时候触发 tree checkHandle (prop, checkedNodes, checkedKeys) { // console.log(prop, checkedNodes, checkedKeys) this.forms[prop] = checkedKeys.checkedKeys }, // 初始化tree initTree (prop, val = []) { prop = prop + 'Tree' this.$refs[prop][0].setCheckedKeys(val) }, // 关闭弹窗时清空tree clearTree (prop) { this.initTree(prop) }, // 打开弹窗记录数据tree openInitTree (prop) { let val = [] if (this.forms[prop]) { val = this.forms[prop] } this.initTree(prop, val) }, // 文件超出个数限制时 handleUploadExceed (files, fileList) { this.$message.warning(`当前限制选择 ${this.uploadForm.limit} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`) }, // 文件列表移除文件时 handleUploadRemove (file, fileList) { console.log(file, fileList) this.$emit('uploadRemoveHandle', file, fileList) }, // 文件上传失败 handleUploadError (file, fileList) { this.$message.error('上传失败') }, // 上传成功之后 handleUploadSuccess (prop, res, file) { this.$emit('upload-success-handle', prop, res, file) }, // 图片上传成功之后获取图片地址 handleAvatarSuccess (prop, res, file) { this.avatarUrl = URL.createObjectURL(file.raw) }, // 头像上传失败 handleAvatarError (files, fileList) { this.$message.error(`头像上传失败`) }, // 头像上传前 beforeAvatarUpload (file) { if (this.uploadForm && this.uploadForm.size) { const isLt = file.size / 1024 / 1024 < this.uploadForm.size if (!isLt) { this.$message.error('上传头像图片大小不能超过 2MB!') } return isLt } }, // select change事件 selectChangeHandle (prop, val) { console.log('selectChangeHandle', prop, val) this.$emit(prop + '-select-change-handle', val) }, // 显示/隐藏 toggleHandle (prop, status) { status = status == null ? true : status let ele = this.$refs[prop][0].$el if (status) { ele.style.display = '' } else { ele.style.display = 'none' } }, // radio change事件 radioChangeHandle (prop, val) { this.$emit(prop + '-radio-change-handle', val) }, // datePicker change事件 datePickerChangeHandle (prop, val) { console.log('datePickerChangeHandle', prop, val) this.$emit(prop + '-date-picker-change-handle', val) } } }) Vue.component('kForm', kForm)