import { computed, ref, toRef, toRefs, watch } from 'vue' import { getChangeIndex, getValuesByKeys, judgeUseFn } from '@cip/components/cip-form-item/util' import { cloneDeep, getFieldValue } from '@cip/utils/util' export const useWatchFieldDepend = (props, context, { updateModelValue, updateOtherValue, clearValues }) => { const changeCount = ref(0) const { model, fieldKey } = toRefs(props) // 配置的config 注:大部分情况配置config与runningConfig一致 const tableDependOnValues = toRef(props, 'tableDependOnValues') const dependOnValues = ref({}) const outDependOnValues = ref({}) const runningConfig = ref() // 运行时的config const securityConfig = computed(() => props.config ?? {}) // watch(securityConfig, (val) => { // console.log('securityConfig change', val) // }) const dependOn = computed(() => securityConfig.value.dependOn || []) const outDependOn = computed(() => securityConfig.value.outDependOn || []) // 收集依赖信息 const collectDependInfo = () => { const values = getValuesByKeys(model.value, dependOn.value) const outValues = getValuesByKeys(tableDependOnValues.value, outDependOn.value) dependOnValues.value = values outDependOnValues.value = outValues } // 依赖变化时的监听 const dependOnWatchCb = ({ changeKeys, changeOldValues }, executeChangeValueEffect) => { const values = dependOnValues.value const outValues = outDependOnValues.value // 获取局部effect的key const privateEffectKeys = changeKeys .map((key, index) => { if (typeof key === 'object') return { ...key, _index: index } return key }) // 塞入初始的index .filter(key => typeof key === 'object') // 获取全局effect的key const hasGlobalEffectKey = changeKeys.find(key => typeof key === 'string') // 执行全局effect的回调 if (hasGlobalEffectKey) { // eslint-disable-next-line standard/no-callback-literal cb({ values, outValues, keys: changeKeys, oldValues: changeOldValues, executeChangeValueEffect }) } // 执行局部effect的回调 privateEffectKeys.forEach(object => { const privateEffect = object.effect || {} // eslint-disable-next-line standard/no-callback-literal cb({ values, outValues, keys: object.key, oldValues: changeOldValues[object._index], effect: privateEffect, executeChangeValueEffect }) }) // } } const cb = ({ values, outValues, keys, oldValues, effect, executeChangeValueEffect }) => { keys = [].concat(keys) // 转化为数组 oldValues = [].concat(oldValues) // 转化为数组 // 经支持 privateEffect if ( !(keys.length === 1 && keys[0] === fieldKey.value) && // 不能只有自己变了变了 oldValues.some(val => val !== undefined) && // 存在变更的依赖原始值不为undefined [1,undefined] true [undefined,undefined] false executeChangeValueEffect // model值相同 ) { if (effect?.resetValue !== undefined) { // effect.resetValue的值优先级高于config.value.resetValue if (typeof effect.resetValue === 'function') { // effect.resetValue的类型为Function effect.resetValue(getFieldValue(model.value, props.fieldKey), values, outValues) && clearValues() } else { effect.resetValue && clearValues() } } else if (securityConfig.value.resetValue) { clearValues() } } // immediateChangeValue 覆盖掉 executeChangeValueEffect if (!props.readonly && (securityConfig.value.immediateChangeValue || executeChangeValueEffect)) { // changeValue && changeValueByOld 仅在非readonly且model相等下生效 const changeValueCb = judgeUseFn('changeValue', securityConfig.value, effect) if (typeof changeValueCb === 'function') changeValue(changeValueCb, values, outValues) const changeValueByOldCb = judgeUseFn('changeValueByOld', securityConfig.value, effect) if (typeof changeValueByOldCb === 'function') { // 不合并 keys.forEach((key, i) => { const oldValue = oldValues[i] if (typeof key === 'object') { key = key.key } changeValueByOld(changeValueByOldCb, { key, oldValue }, values, outValues) }) } } const changeConfigCb = judgeUseFn('changeConfig', securityConfig.value, effect) if (typeof changeConfigCb === 'function') changeConfig(changeConfigCb, values, outValues) } // 变更字段config的方式 const changeConfig = async (cb, values, outValues) => { runningConfig.value = await cb(cloneDeep(securityConfig.value), values, outValues) } const changeValue = async (cb, values, outValues) => { const data = await cb(values, outValues) if (data) { const { value, otherValue } = data updateModelValue(value) updateOtherValue(otherValue) } } const changeValueByOld = async (cb, { key, oldValue }, values, outValues) => { // eslint-disable-next-line standard/no-callback-literal const data = await cb({ key, oldValue }, values, outValues) if (data !== undefined) { const { value, otherValue } = data updateModelValue(value) updateOtherValue(otherValue) } } const watchValue = (target, dependOn) => dependOn.map(key => { if (typeof key === 'object') key = key.key return () => getFieldValue(target.value, key) }) const generateWatchValue = () => { let result = watchValue(model, dependOn.value) if (props.inTable) { result = result.concat(watchValue(tableDependOnValues, outDependOn.value)) } return result } const getChange = (values, oldValues, depend) => { // 转为纯函数 const changeIndex = getChangeIndex(values, oldValues) const changeValue = changeIndex.map(index => values[index]) const changeOldValues = changeIndex.map(index => oldValues[index]) const changeKeys = changeIndex.map(index => depend[index]) // 此处depend为函数私有 return { changeValue, changeOldValues, changeKeys } } const depend = props.inTable ? dependOn.value.concat(outDependOn.value) : dependOn.value // 值变化 [reset changeValue changValueByOld] // 配置变化 [changeConfig] // 更换对象: 依赖收集 触发配置变化 不触发值变化 // 未更换对象: 依赖收集 触发配置变化 触发值变化 if (depend.length > 0) { let unwatch watch(model, () => { changeCount.value++ // 增加一个model变化计数器 // 重新开启监听 if (unwatch) unwatch() // model变化时重新开启监听 let firstChange = true unwatch = watch(generateWatchValue(dependOn, outDependOn), (values, oldValues) => { const change = getChange(values, oldValues, depend) // 相同的对象 判断存在数据变化才触发依赖值更新 collectDependInfo() dependOnWatchCb(change, !firstChange) firstChange = false }, { deep: true, immediate: true }) }, { immediate: true }) } return { changeCount, // model变化总计 clearValues, dependOnValues, outDependOnValues, runningConfig } }