<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>
				<!-- {{item.name}} -->
				<w-form-item :type="item.name" :title="item.title" 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'
	import {
		CompareFuncs
	} from "./form/compare/CompareOptions.js";
	//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: () => {
					return {
						ruleType: "SIMPLE",
						rules: [],
					}
				}
			},
			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 => {
					if (v.props.required && v.perm !== 'H') {
						formRule[v.id] = {
							rules: [{
								required: true,
								errorMessage: '请填写' + v.title
							}]
						}
					}
				})
				return formRule
			},
			formFields() {
				const fields = []
				this.jsonConf.forEach(field => this.loadInnerField(field, fields))
				return fields
			},
			formItemMap() {
				const map = new Map()
				this.loadFormItemMap(this.jsonConf, map)
				return map
			}
		},
		data() {
			return {
				//缓存下原始权限设置
				formPermHis: {},
				compareFunc: {},
				//缓存旧值
				oldFormData: {},
				//缓存所有用到的条件字段
				conditionFields: new Set(),
				execute: null,
				// 特殊标识
				isUse: 1
			}
		},
		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 => {
					// console.log(4444444, JSON.stringify(this.modelValue))
					const dataList = Object.values(this.modelValue);
					const result = dataList[0] instanceof Array ? dataList[0][dataList[0].length - 1] : dataList;
					// console.log(JSON.stringify(dataList[0]))
					// console.log(4444444, JSON.stringify(this.formFields[this.formFields.length - 1].props.columns))
					const flag = this.formFields[this.formFields.length - 1].props.columns ? this.formFields[this.formFields.length - 1].props.columns.every((v, i)=> {
						if((i == this.formFields[this.formFields.length - 1].props.columns.length - 1) && result[v.id]){
							// console.log(5555555, JSON.stringify(result[v.id]))
							if(result[v.id][0].id){
								return true
							} else {
								// console.log(22222, JSON.stringify(v.props.columns))
								return v.props.columns.every(e => {
									// console.log(1111111, e.props.required,e.id, JSON.stringify(result[e.id]), JSON.stringify(result[v.id]))
									return e.props.required == false || (e.props.required == true && result[v.id][0][e.id] != null&& result[v.id][0][e.id] != undefined);
								})
							}
							return
						}
						if(result instanceof Array){
							// console.log(22222, v.props.required, JSON.stringify(result[result.length - 1]), v.id)
							return v.props.required == false || (v.props.required == true && result[result.length - 1][0][v.id] != null && result[result.length - 1][0][v.id] != "")
						}
						// console.log(22222, v.props.required, JSON.stringify(result), v.id)
						return v.props.required == false || (v.props.required == true && result[v.id] != null);
					}) : true;
					// console.log(3333333, flag)
					call(flag)
					console.log('表单数据信息：', JSON.stringify(res));
				}).catch(err => {
					call(false)
					console.log('表单错误信息：', err);
				})
			},
			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() {
				// console.log("~~~~~~~~~~~~~~~~~~规则类型"+ this.config.ruleType)
				if (this.config.ruleType === 'SIMPLE') {
					this.analyseRules()
					this.analyseJsRules()
				} else {
					this.analyseJsRules()
				}
			},
			async analyseJsRules() {
				// if (!(this.execute instanceof Function)) {
				// 	this.execute = new Function(`${this.config.ruleJs || 'function doChange(){}'}\r\n return doChange`)
				// 	this.execute = this.execute()
				// } else {
				// 	this.execute = new Function(`${this.config.ruleJs || 'function doChange(){}'}\r\n return doChange`)
				// 	this.execute = this.execute()
				// }
				// console.log(this._value, this.formItemMap,888999)
				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: {
			config: {
				deep: true,
				immediate: true,
				handler(newVal, oldVal) {
					// console.log("~~~~~~~~~~~~config配置",JSON.stringify(this.config))
					if (this.config) {
						this.execute = new Function(`${this.config.ruleJs || 'function doChange(){}'}\r\n return doChange`)
						this.execute = this.execute()
						if (Object.keys(this.formPermHis).length === 0) {
							this.formItemMap.forEach(item => {
								this.formPermHis[item.id] = item.perm
							})
						}
						this.analyseFormRule()
					}
				}
			},
			modelValue: {
				deep: true,
				immediate: true,
				handler(newVal, oldVal) {
					// console.log("~~~~~~~~~~~~modelValue配置",JSON.stringify(newVal))
					// console.log("~~~~~~~~~~~~modelValue配置",JSON.stringify(oldVal))
					if (this.config) {
						if (Object.keys(this.formPermHis).length === 0) {
							this.formItemMap.forEach(item => {
								this.formPermHis[item.id] = item.perm
							})
						}
						this.analyseFormRule()
					}
				}
			},
		},
		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>