d-render
Version:
数据渲染库 - form、table、search-form
169 lines (155 loc) • 5.37 kB
text/typescript
import { unref, Ref } from 'vue'
import { getFieldValue, isNotEmpty, setFieldValue, cloneDeep, IAnyObject, IRenderConfig, IRenderConfigDependOn, TFormConfig } from '@d-render/shared'
interface IEffectFunc {
value: (...args: Array<unknown>) => unknown | Promise<unknown>
}
interface IEffect{
[key: string]: string | IEffectFunc
}
export type IObjectKey = IRenderConfigDependOn
export type IKey = IObjectKey | string
export const getValuesByKeys = (data: IAnyObject = {}, keys:Array<IKey> = []) => {
const result = {}
keys.forEach((key) => {
if (typeof key === 'object') {
const object = key
setFieldValue(result, object.key, getFieldValue(data, object.key), true)
} else {
setFieldValue(result, key, getFieldValue(data, key), true)
}
})
return result
}
export const setValuesByKeys = (target:IAnyObject = {}, keys:Array<IKey> = [], values: IAnyObject = {}) => {
keys.forEach((key) => {
if (typeof key === 'object') {
const object = key
setFieldValue(target, object.key, getFieldValue(values, object.key), true)
} else {
setFieldValue(target, key, getFieldValue(values, key), true)
}
})
}
// 去除对象的指定属性后返回去除属性的集合仅适用于单层对象
const filterProperty = (object: IAnyObject, properties: Array<string>) => {
// 进行一次浅拷贝防止deleteProperty删除修改原始对象
const newObject = { ...object }
const omitObject = properties.reduce((acc: Record<string, unknown>, key) => {
const v = object[key]
Reflect.deleteProperty(object, key)
acc[key] = v
return acc
}, {})
return [newObject, omitObject]
}
// 深克隆非指定属性
export const cloneDeepConfig = (config: TFormConfig) => {
// const fixedKeys = ['dependOn', 'changeConfig', 'changeValue', 'changeValueByOld', 'outDependOn', 'asyncOptions', '$render']
// const [volatileConfig, fixedConfig] = filterProperty(config, fixedKeys)
// const newConfig =
return cloneDeep(config)
}
export const isHideLabel = (config: TFormConfig) => {
return (
config.hideLabel ||
(isNotEmpty(config.labelWidth) && !config.labelWidth) ||
!config.label
)
}
export const getLabelWidth = (config: TFormConfig) => {
if (config.hideLabel) return '0px'
if (isNotEmpty(config.labelWidth)) {
if (isNaN(config.labelWidth as unknown as number)) return config.labelWidth as string
return config.labelWidth + 'px'
}
if (!config.label) return '0px' // 兼容老的设计
return undefined
}
export const getChangeIndex = (values: Array<unknown>, oldValues: Array<unknown>) => {
const result: Array<number> = []
values.forEach((v, i) => {
if (typeof v === 'object') {
// 数组 对象相等判断
// 无法通过值来判断对象级数组是否变化 (地址引用导致2个值一直都是相等的)
result.push(i)
} else {
if (v !== oldValues[i]) {
result.push(i)
}
}
})
return result
}
export const secureNewFn = (...params: Array<string>) => {
const funcBody = params.pop()
try {
// eslint-disable-next-line no-new-func
return new Function(...params, funcBody as string)
} catch (error) {
console.error(error)
return () => {}
}
}
export const judgeUseFn = (key: string, config: IRenderConfig, effect: IEffect) => {
// console.log(key, config, effect);
// eslint-disable-next-line no-new-func
if (key === 'changeValue' && config.changeValueStr) {
return secureNewFn(
'dependOnValues',
'outDependOnValues',
config.changeValueStr
)
}
if (key === 'changeConfig' && config.changeConfigStr) {
return secureNewFn(
'config',
'dependOnValues',
'outDependOnValues',
config.changeConfigStr
)
}
// 对asyncOptions的特殊处理
// @ts-ignore
if (key === 'asyncOptions' && typeof config.asyncOptions === 'string') { return secureNewFn('dependOnValues', 'outDependOnValues', config.asyncOptions) }
if (!effect) return config[key] // 没有effect 参数则直接使用config[key]
if (effect && key in effect) {
// 有effect 且 effect对象明确存在key(不管其值为什么)
if (typeof effect[key] === 'function') return effect[key] // effect中的值为函数 则认为此次响应使用局部方法
return config[key]
}
}
export class UpdateModelQueue {
getModel: () => IAnyObject | Ref<IAnyObject>
updateModel: (value: IAnyObject) => void
data: Map<string, unknown> = new Map()
isCollect?: boolean
constructor (getModel: () => IAnyObject | Ref<IAnyObject>, updateModel: (value: IAnyObject) => void) {
this.getModel = getModel
this.updateModel = updateModel
}
init () {
this.data = new Map()
}
append (key: string, value: unknown) {
if (!this.isCollect) {
this.init()
this.isCollect = true
// setTimeout(() => {
// }, 20)
}
this.data?.set(key, value) // = value
this.update() // 直接触发
// setFieldValue(this.data, key, value)
}
update () {
const model = unref(this.getModel()) // 维持model是最新的
// eslint-disable-next-line no-unused-vars
for (const key of this.data.keys()) {
const value = this.data.get(key)
setFieldValue(model, key, value, true)
}
this.isCollect = false
this.updateModel(model)
this.init() // 清空原来的数据
}
}