mobile-workflow/components/FormRender.vue

346 lines
8.7 KiB
Vue
Raw Normal View History

2024-04-28 10:10:03 +08:00
<template>
<view class="wflow-form">
<uni-forms ref="wflowForm" class="wflow-form" :rules="rules" :modelValue="_value" label-position="top"
label-width="200">
<uni-forms-item :class="`w-form-item ${item.perm === 'R' ? 'w-form-item-r':''}`" v-for="item in formFields"
v-show="showItem(item, _value[item.id])" :name="item.id" :key="item.id" :required="item.props.required">
<template v-slot:label>
<view class="w-form-title">
<text style="color: #CE5266;" v-if="item.props.required && item.perm === 'E'">* </text>
<text style="font-size: 32rpx;">{{item.title}}</text>
</view>
</template>
<w-form-item :type="item.name" v-model="_value[item.id]" :form-props="item.props"
:readonly="item.perm !== 'E'" :formData="_value" />
</uni-forms-item>
</uni-forms>
</view>
</template>
<script>
import { showItem } from '@/utils/tool.js'
import WFormItem from './WFormItem.vue'
2024-05-08 21:13:11 +08:00
import { CompareFuncs } from "./form/compare/CompareOptions.js";
2024-04-28 10:10:03 +08:00
//import FormComponents from '@/components/form/ComponentsExport.js'
export default {
name: 'FormRender',
options: { styleIsolation: 'shared' },
components: { WFormItem },
props: {
modelValue: { //表单双向绑定的值
type: Object,
default: () => {
return {}
}
},
config: { //表单联动相关配置
type: Object,
default: () => {
2024-05-08 21:13:11 +08:00
return {
ruleType: "SIMPLE",
rules: [],
}
2024-04-28 10:10:03 +08:00
}
},
jsonConf: { //表单json配置用来渲染表单
type: Array,
default: () => {
return []
}
}
},
computed: {
_value: {
get() {
return this.modelValue
},
set(val) {
emit('update:modelValue', val)
}
},
rules() {
const formRule = {}
this.formFields.forEach(v => {
2024-05-08 21:13:11 +08:00
if (v.props.required && v.perm !== 'H') {
2024-04-28 10:10:03 +08:00
formRule[v.id] = {
rules: [{
required: true,
errorMessage: '请填写' + v.title
}]
}
}
})
return formRule
},
formFields() {
const fields = []
this.jsonConf.forEach(field => this.loadInnerField(field, fields))
return fields
2024-05-08 21:13:11 +08:00
},
formItemMap() {
const map = new Map()
this.loadFormItemMap(this.jsonConf, map)
return map
2024-04-28 10:10:03 +08:00
}
},
data() {
return {
2024-05-08 21:13:11 +08:00
//缓存下原始权限设置
formPermHis: {},
compareFunc: {},
//缓存旧值
oldFormData: {},
//缓存所有用到的条件字段
conditionFields: new Set(),
execute: null
2024-04-28 10:10:03 +08:00
}
},
onReady() {
this.$refs['wflowForm'].setRules(this.rules)
},
methods: {
showItem,
loadInnerField(field, items) {
if (field.name === 'SpanLayout') {
field.props.items.forEach(f => this.loadInnerField(f, items))
} else {
items.push(field)
}
},
validate(call) {
this.$refs['wflowForm'].validate().then(res => {
call(true)
console.log('表单数据信息:', res);
}).catch(err => {
2024-04-30 00:30:46 +08:00
// call(false)
2024-04-28 10:10:03 +08:00
console.log('表单错误信息:', err);
})
2024-05-08 21:13:11 +08:00
},
loadFormItemMap(forms, map) {
forms.forEach(item => {
if (item.name === 'TableList') {
map.set(item.id, item)
this.loadFormItemMap(item.props.columns, map)
} else if (item.name === 'SpanLayout') {
this.loadFormItemMap(item.props.items, map)
} else {
map.set(item.id, item)
}
})
},
//解析表单联动规则
parserRule(cdRule) {
const condition = cdRule.condition
//在这里可以实现一个算法,按条件层级去解析,不需要解析所有条件,先不实现
if (cdRule.children.length > 0) {
for (let i = 0; i < cdRule.children.length; i++) {
const result = this.parserRule(cdRule.children[i])
if (cdRule.logic) {
//如果是且关系,有一个为假就是假
if (!result) {
return false
}
} else {
//如果是或关系,有一个为真就是真
if (result) {
return true
}
}
}
//遍历完了返回最终结果
return cdRule.logic
} else {
//解析条件
try {
return this.compare(condition)
} catch (e) {
return false
}
}
},
async doActions(actions) {
(actions || []).forEach(action => {
//执行预设的动作
switch (action.type) {
case 'SHOW':
action.targets.forEach(tg => this.showField(tg));
break;
case 'HIDE':
action.targets.forEach(tg => this.hideField(tg));
break;
case 'DISABLE':
action.targets.forEach(tg => this.disableField(tg));
break;
case 'UPDATE':
action.targets.forEach(tg => this.updateField(tg, action.value));
break;
case 'ENABLE':
action.targets.forEach(tg => this.enableField(tg, action.value));
break;
}
})
},
analyseFormRule() {
2024-05-09 13:40:16 +08:00
console.log("~~~~~~~~~~~~~~~~~~规则类型"+ this.config.ruleType)
2024-05-08 21:13:11 +08:00
if (this.config.ruleType === 'SIMPLE') {
this.analyseRules()
2024-05-18 20:34:50 +08:00
this.analyseJsRules()
2024-05-08 21:13:11 +08:00
} else {
this.analyseJsRules()
}
},
async analyseJsRules() {
2024-05-09 13:40:16 +08:00
console.log(this.execute)
console.log("~~~~~~~~~~~~~~~~~~~~~~~~~~~"+!(this.execute instanceof Function))
2024-05-08 21:13:11 +08:00
if (!(this.execute instanceof Function)) {
2024-05-09 13:40:16 +08:00
console.log("~~~~~~~~~~~~~~~~change事件")
2024-05-08 21:13:11 +08:00
this.execute = new Function(`${this.config.ruleJs || 'function doChange(){}'}\r\n return doChange`)
this.execute = this.execute()
2024-05-18 20:34:50 +08:00
} else {
console.log("~~~~~~~~~~~~~~~~change事件")
this.execute = new Function(`${this.config.ruleJs || 'function doChange(){}'}\r\n return doChange`)
this.execute = this.execute()
2024-05-08 21:13:11 +08:00
}
2024-05-09 13:40:16 +08:00
console.log("~~~~~~~~~~~~~~~~change事件11111")
console.log(this._value, this.formItemMap)
2024-05-08 21:13:11 +08:00
this.execute(this._value, this.formItemMap)
},
async analyseRules() {
(this.config.rules || []).forEach((rule, i) => {
//解析表单联动条件
const result = this.parserRule(rule.condition)
console.log(`解析规则 ${(i + 1)}: ${result}`)
this.doActions(result ? rule.action.with : rule.action.other)
})
},
compare(condition) {
//要判断组件类型,再取其值
const source = this._value[condition.field]
//动态调用函数
let compareType = null
switch (condition.fieldType) {
case 'AmountInput':
case 'NumberInput':
case 'Score':
case 'CalcFormula':
compareType = 'numCompare';
break;
case 'TextInput':
case 'TextareaInput':
case 'SelectInput':
case 'Location':
case 'Provinces':
compareType = 'strCompare'
break;
case 'MultipleSelect':
compareType = 'strArrCompare';
break;
case 'DateTime':
compareType = 'timeCompare';
break;
case 'DateTimeRange':
compareType = 'timeArrCompare';
break;
case 'DeptPicker':
case 'UserPicker':
compareType = 'orgCompare';
break;
}
return CompareFuncs[compareType][condition.compare](source,
condition.fixed ? condition.compareVal :
this._value[condition.compareVal[0]])
},
isRequired(item) {
return this.rules[item.id] !== undefined
},
hideField(id) {
const field = this.formItemMap.get(id)
if (field) {
field.perm = 'H'
}
},
showField(id) {
const field = this.formItemMap.get(id)
if (field) {
field.perm = this.formPermHis[id] || 'E'
}
},
disableField(id) {
const field = this.formItemMap.get(id)
if (field) {
field.perm = 'R'
}
},
enableField(id) {
const field = this.formItemMap.get(id)
if (field) {
field.perm = 'E'
}
},
updateField(id, val) {
const field = this.formItemMap.get(id)
if (field) {
this._value[id] = val
}
}
},
watch: {
2024-05-18 20:34:50 +08:00
config: {
deep: true,
immediate: true,
handler() {
console.log("~~~~~~~~~~~~配置",JSON.stringify(this.config))
if (this.config) {
if (Object.keys(this.formPermHis).length === 0) {
this.formItemMap.forEach(item => {
this.formPermHis[item.id] = item.perm
})
}
this.analyseFormRule()
}
}
},
2024-05-08 21:13:11 +08:00
modelValue: {
deep: true,
immediate: true,
handler() {
2024-05-18 20:34:50 +08:00
console.log("~~~~~~~~~~~~配置",JSON.stringify(this.config))
2024-05-08 21:13:11 +08:00
if (this.config) {
if (Object.keys(this.formPermHis).length === 0) {
this.formItemMap.forEach(item => {
this.formPermHis[item.id] = item.perm
})
}
this.analyseFormRule()
}
}
2024-05-18 20:34:50 +08:00
},
2024-04-28 10:10:03 +08:00
},
emits: ['update:modelValue']
}
</script>
<style lang="less" scoped>
.w-form-item {
padding: 0 16rpx 32rpx 16rpx;
background-color: white;
margin-bottom: 16rpx;
font-size: 32rpx !important;
.uni-forms-item__error {
padding-top: 0 !important;
}
.uni-easyinput__content-input {
height: 30px;
}
.w-form-title {
display: flex;
align-items: center;
padding: 13rpx 0;
}
}
</style>