164 lines
5.1 KiB
TypeScript
164 lines
5.1 KiB
TypeScript
/* eslint-disable no-new-func */
|
||
import { cloneDeep, isString, isPlainObject, isArray } from 'lodash'
|
||
import type { formValuesType } from '/admin/components/catchForm/config/commonType'
|
||
import type { formItemType, formItemsType } from '/admin/components/catchForm/config/commonType'
|
||
import { isEqual } from 'lodash'
|
||
import type { anyObject, contextType} from '/admin/components/catchForm/config/commonType'
|
||
|
||
type handleLinkagesType = (obj: { newVal: Object; oldVal: Object; formValues: anyObject; formItems: formItemsType }) => void
|
||
|
||
// 模板转换函数,将一个由双大括号包裹的字符串,转化为js表达式并返回结果(context限制变量范围)
|
||
const templateParse = (str: string, context: contextType) => {
|
||
if (!str) return str
|
||
if (typeof str !== 'string') return str
|
||
|
||
const template = str.match(/{{(.+?)}}/)
|
||
if (template) {
|
||
try {
|
||
const parse = new Function(Object.keys(context).join(','), 'return ' + template[1])
|
||
|
||
return parse(...Object.values(context))
|
||
} catch (e) {
|
||
// console.log(str, '模板转换错误:', e)
|
||
return str
|
||
}
|
||
} else {
|
||
return str
|
||
}
|
||
}
|
||
|
||
const deepParse = (prop: any, context: contextType): any => {
|
||
const $values = context.$values
|
||
|
||
if (isString(prop)) {
|
||
return templateParse(prop, context)
|
||
}
|
||
|
||
if (isPlainObject(prop)) {
|
||
return Object.keys(prop).reduce((all, key) => {
|
||
const itemContext = { ...context }
|
||
|
||
if (prop.name && $values) {
|
||
itemContext.$val = getDataByPath($values, prop.name)
|
||
itemContext.$select = context.$selectData[prop.name]
|
||
}
|
||
|
||
return { ...all, [key]: deepParse(prop[key], itemContext) }
|
||
}, {})
|
||
}
|
||
if (isArray(prop)) {
|
||
return prop.map(item => {
|
||
return deepParse(item, context)
|
||
})
|
||
}
|
||
|
||
return prop
|
||
}
|
||
|
||
const handleLinkages: handleLinkagesType = ({ newVal, oldVal, formValues, formItems }) => {
|
||
for (const item of formItems) {
|
||
const newValue = getDataByPath(newVal, item.name)
|
||
const oldValue = getDataByPath(oldVal, item.name)
|
||
|
||
if (item.change && !isEqual(newValue, oldValue)) {
|
||
let temp = cloneDeep(formValues.value)
|
||
item.change.forEach(({ target, value }) => {
|
||
temp = setDataByPath(temp, target, value)
|
||
})
|
||
formValues.value = temp
|
||
}
|
||
|
||
if (item.children && item.component !== 'FormList') {
|
||
handleLinkages({
|
||
newVal,
|
||
oldVal,
|
||
formValues,
|
||
formItems: item.children
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
const recursionDelete = (items: formItemsType, callback: (item: formItemType) => boolean): formItemsType => {
|
||
const data = items.filter(callback)
|
||
return data.map(item => {
|
||
if (item.children) {
|
||
return {
|
||
...item,
|
||
children: recursionDelete(item.children, callback)
|
||
}
|
||
}
|
||
return item
|
||
})
|
||
}
|
||
const setDataByPath = (object: formValuesType, path: string, value: any) => {
|
||
const cloneObj = cloneDeep(object)
|
||
// 将路径字符串分割成路径数组
|
||
const pathArray = path.split('.')
|
||
// 递归函数,用于在对象的深层级找到要修改的位置并更新其值
|
||
function update(obj: formValuesType, pathArray: string[], value: any) {
|
||
// 如果路径数组为空,表示已经到达了最后一级,更新值并返回
|
||
if (pathArray.length === 1) {
|
||
obj[pathArray[0]] = value
|
||
return
|
||
}
|
||
|
||
// 获取当前路径的第一个部分
|
||
const currentKey = pathArray.shift()
|
||
|
||
if (currentKey) {
|
||
// 如果当前键不存在,则创建一个空对象
|
||
if (!obj[currentKey]) {
|
||
obj[currentKey] = {}
|
||
}
|
||
|
||
// 递归调用更新函数
|
||
update(obj[currentKey], pathArray, value)
|
||
}
|
||
}
|
||
|
||
// 调用递归函数
|
||
update(cloneObj, pathArray, value)
|
||
|
||
// 返回更新后的对象
|
||
return cloneObj
|
||
}
|
||
|
||
const isRegexString = (str: string) => {
|
||
const regexMetaCharacters = /[.*+?^${}()|[\]\\]/
|
||
|
||
return regexMetaCharacters.test(str)
|
||
}
|
||
|
||
const getRandomId = (length: number) => {
|
||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||
let randomId = ''
|
||
|
||
for (let i = 0; i < length; i++) {
|
||
const randomIndex = Math.floor(Math.random() * characters.length)
|
||
randomId += characters.charAt(randomIndex)
|
||
}
|
||
|
||
return randomId
|
||
}
|
||
|
||
const getDataByPath = (obj: anyObject, path: string) => {
|
||
// 使用正则表达式分割路径字符串
|
||
const keys = path.split('.')
|
||
|
||
// 遍历路径,逐层深入对象
|
||
let result = obj
|
||
for (const key of keys) {
|
||
if (result && typeof result === 'object' && key in result) {
|
||
result = result[key]
|
||
} else {
|
||
// 如果路径无效,返回 undefined 或者其他默认值
|
||
return undefined
|
||
}
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
export { setDataByPath, recursionDelete, isRegexString, getRandomId, handleLinkages, getDataByPath, deepParse}
|