需求: 在状态流中,需要一个必填表单,里面的必填字段都是未知的,需要动态生成
俗话说得好,可以cv绝不手敲代码,但是找遍了全网,没有类似的案例。。。
被逼无奈只能手写,但最后效果还是挺满意的,话不多说,上代码!
<!-- 表单必填项控件,当必填项不通过时,会触发表单通知User输入 -->
<template>
<el-dialog v-loading="loading" title="Require" :visible.sync="dialogFormVisible" append-to-body>
<el-form ref="form" :model="queryData" :rules.sync="rules">
<!-- 下拉框 -->
<el-row>
<el-col v-for="(item,index) of correctTypeGroup[2]" :key="index" :span="12">
<el-form-item v-if="refreshForm" :label="item.fieldName" :prop="item.fieldAttributeName" :label-width="formLabelWidth">
<!-- assignee -->
<el-select v-if="item.fieldAttributeName === 'assignee' " v-model="queryData[item.fieldAttributeName]" :disabled="item.readOnly === 1" @change="updateForm">
<el-option
v-for="assignee in assignees"
:key="assignee.id"
:label="assignee.name"
:value="assignee.id"
/>
</el-select>
<!-- mailNotifier v-else-if="item.fieldAttributeName === 'mailNotifier'"-->
<el-select v-else-if="item.fieldAttributeName === 'mailNotifier'" v-model="queryData[item.fieldAttributeName]" :disabled="item.readOnly === 1" multiple @change="updateForm">
<el-option
v-for="assignee in assignees"
:key="assignee.id"
:label="assignee.name"
:value="assignee.id"
/>
</el-select>
<!-- orther -->
<el-select v-else v-model="queryData[item.fieldAttributeName]" :disabled="item.readOnly === 1" @change="updateForm">
<el-option
v-for="assignee in pageEnum[item.fieldId]"
:key="assignee.id"
:label="assignee.value"
:value="assignee.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- boolean -->
<el-row>
<el-col v-for="(item,index) of correctTypeGroup[5]" :key="index" :span="6">
<el-form-item v-if="refreshForm" :label="item.fieldName" :prop="item.fieldAttributeName" :label-width="formLabelWidth">
<!-- true-label="true" falselabel="false" -->
<el-checkbox v-model="queryData[item.fieldAttributeName]" :disabled="item.readOnly === 1" checked @change="updateForm">{{ item.fieldName }}</el-checkbox>
</el-form-item>
</el-col>
</el-row>
<!-- 时间 -->
<el-row>
<el-col v-for="(item,index) of correctTypeGroup[3]" :key="index" :span="12">
<el-form-item v-if="refreshForm" :label="item.fieldName" :prop="item.fieldAttributeName" :label-width="formLabelWidth">
<el-date-picker
v-model="queryData[item.fieldAttributeName]"
:disabled="item.readOnly === 1"
type="date"
value-format="yyyy-MM-dd"
@input="updateForm"
/>
</el-form-item>
</el-col>
</el-row>
<!-- 文本框 -->
<el-row>
<el-col v-for="(item,index) of correctTypeGroup[1]" :key="index" :span="24">
<el-form-item v-if="refreshForm" :label="item.fieldName" :prop="item.fieldAttributeName" :label-width="formLabelWidth">
<el-input v-model="queryData[item.fieldAttributeName]" :disabled="item.readOnly === '1'" type="textarea" @input="updateForm" />
</el-form-item>
</el-col>
</el-row>
<!-- 数字 -->
<el-row>
<el-col v-for="(item,index) of correctTypeGroup[4]" :key="index" :span="24">
<el-form-item v-if="refreshForm" :label="item.fieldName" :prop="item.fieldAttributeName" :label-width="formLabelWidth">
<el-input v-model="queryData[item.fieldAttributeName]" onkeyup="value=value.replace(/[^\d]/g,'')" @input="updateForm" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">Cancel</el-button>
<el-button type="primary" @click="save">Save</el-button>
</div>
</el-dialog>
</template>
<script>
import { getEnumsByProjectIdAndEnumsIds } from '@/api/enum'
import { copyProperties } from '@/utils/bean-util'
import { searchAction } from '@/api/quality/action'
import { searchField } from '@/api/quality/page'
import { IsEmpty } from '@/utils/validate'
import { formatDate } from '@/utils/date'
export default {
name: 'CorrectForm',
props: {
assignees: {
type: Array,
default() {
return []
}
}
},
data() {
return {
dialogFormVisible: false,
historyData: {},
loading: false,
refreshForm: true,
queryData: {
id: '',
projectId: '',
actionId: ''
},
// 页面枚举容器
pageEnum: {
},
// 输入框类型分组容器
correctTypeGroup: {
},
formLabelWidth: '180px',
customRules: {},
rules: {}
}
},
methods: {
/**
* 提交表单的方法,此方法会校验表单,校验通过后
* 会回调父组件提供的save方法
* params: action 点击的action对象
* params: queryData 用户当前页的表单数据
*/
async submit(action, queryData, history) {
this.queryData = {
id: '',
projectId: '',
actionId: '',
nativeId: ''
}
// 获取actionList
const actionConfigList = await this.getActionConfigList(action)
// 校验参数
const result = this.validate(actionConfigList, queryData)
// 设置扭转状态的actionId
queryData.actionId = action.actionId
queryData.nativeId = action.nativeId
// 校验不通过
if (!result.success) {
// 打开dialog
this.dialogFormVisible = true
this.historyData = queryData
// 清空历史数据
// 1.文本 2.下拉框 3.时间 4.数字 5.boolean
this.correctTypeGroup = {
1: [],
2: [],
3: [],
4: [],
5: []
}
this.customRules = {}
// 输入框分组
// 获取页面所有的配置字段,因为字段type存在页面配置中
const pageFields = await this.getPageField(action)
const loadFields = []
actionConfigList.forEach(actionField => {
const pageField = pageFields.filter(pageField => pageField.fieldId === actionField.fieldId)[0]
if (pageField === undefined) {
this.$message({
message: 'get Page Config Field ERROR, FIELD NOT FIND, Place To Page Add ' + actionField.fieldId,
type: 'warning'
})
}
// 保存已加载的field,用户加载页面枚举资源
loadFields.push(pageField)
// 加入输入分组中, correctTypeGroup的数据会被循环渲染在页面上
this.correctTypeGroup[pageField.type].push(actionField)
// console.log(actionField)
if (actionField.require === 1) {
// 添加验证规则
this.customRules[actionField.fieldAttributeName] = JSON.parse(pageField.rule)
// 添加数据绑定对象
this.queryData[actionField.fieldAttributeName] = ''
}
})
// 加载页面的所有枚举值
this.loadPageEnums(loadFields)
// 拷贝属性
copyProperties(queryData, this.queryData)
copyProperties(history, this.queryData)
// 处理时间格式
this.correctTypeGroup[3].forEach(actionField => {
const timeStramp = this.queryData[actionField.fieldAttributeName]
if (!IsEmpty(timeStramp)) {
this.queryData[actionField.fieldAttributeName] = formatDate(new Date(timeStramp), 'yyyy-MM-dd')
}
})
// 校验参数
return 'fail'
}
// 提交表单
this.$emit('update', queryData, action.nativeId, null, true)
},
// 加载页面所有的枚举值
loadPageEnums(pageFields) {
// 找出枚举字段
this.pageEnum = {}
const enumFields = pageFields.filter(element => element.type === 2)
if (enumFields === undefined || enumFields.length <= 0) {
// 页面没有枚举值
return
}
const fieldEnumIds = enumFields.map(field => field.fieldId)
const queryData = {
projectId: this.historyData.projectId,
enumIds: fieldEnumIds
}
// 获取页面的枚举值,并绑定成{fieldAlias: []}数据格式
this.loading = false
getEnumsByProjectIdAndEnumsIds(queryData).then(response => {
const pageEnums = response.data
enumFields.forEach(field => {
let options = []
// 寻找当前字段的枚举值
const fieldEnums = Object.keys(pageEnums).filter(enumId => field.fieldId === enumId)
if (fieldEnums != null && fieldEnums.length > 0) {
options = pageEnums[fieldEnums[0]]
}
// 需要调用vue的set方法,刷新视图,否则视图不会刷新
this.$set(this.pageEnum, field.fieldId, options)
})
this.loading = false
}).catch(() => {
this.$message({
message: 'getEnumsByProjectIdAndEnumsIds is failed.',
type: 'warning'
})
this.loading = false
})
},
// 获取所有页面的字段
async getPageField() {
try {
const res = await searchField({})
return res.data
} catch (err) {
this.$message({
message: 'getActionConfigList is failed.',
type: 'warning'
})
}
},
// 获取action的配置list
async getActionConfigList(action) {
try {
const queryData = {
actionId: action.nativeId
}
const res = await searchAction(queryData)
return res.data
} catch (err) {
this.$message({
message: 'getActionConfigList is failed.',
type: 'warning'
})
}
},
// 验证表单的内容是否有填
validate(actionConfigList, queryData) {
return { success: actionConfigList.length < 1 }
},
// updateForm
updateForm() {
this.$forceUpdate()
},
// 提交
save() {
// this.$emit('update', this.queryData, this.queryData.nativeId, null, true)
// 切换校验规则
this.loading = true
// 跳转路由, 去新增BUG的页面
// this.$refs.form.validate(valid => {
// this.loading = false
// if (valid) {
// // 跳转路由, 去新增BUG的页面
// this.$emit('update', this.queryData, null, true)
// }
// })
// 刷新form表单,不知道为什么,表单校验内容一直加载不到
this.refreshForm = false
// 重新加载所有表单项
setTimeout(() => {
this.refreshForm = true
this.rules = this.customRules
// 数据要载入
setTimeout(() => {
this.$refs.form.validate(valid => {
this.loading = false
if (valid) {
// 跳转路由, 去新增BUG的页面
this.dialogFormVisible = false
this.$emit('update', this.queryData, null, null, true)
}
})
}, 2000)
}, 500)
}
}
}
</script>
<style scoped>
</style>
效果预览