// 移动端不支持自定义表达式设置的默认值
import {http} from "@/utils/http";
import {useUserStore} from "@/store";
import * as CustomExpression from './customExpression';
import dayjs from "dayjs";
// 获取所有用户自定义表达式的Key
const ceKeys = Object.keys(CustomExpression)
// 将key用逗号拼接,可以拼接成方法参数,例:a,b,c --> function(a,b,c){}
const ceJoin = ceKeys.join(',')
// 将用户自定义的表达式按key的顺序放到数组中,可以使用 apply 传递给方法直接调用
const $CE$ = ceKeys.map(key => CustomExpression[key])
/** 普通规则表达式 #{...} */
const normalRegExp = /#{([^}]+)?}/g
/** 用户自定义规则表达式 {{...}} */
const customRegExp = /{{([^}]+)?}}/g
/** 填值规则表达式 ${...} */
const fillRuleRegExp = /\${([^}]+)?}/g
/** action 类型 */
export const ACTION_TYPES = { ADD: 'add', EDIT: 'edit', DETAIL: 'detail', RELOAD: 'reload' }
/**
* 获取单个字段的默认值-通过回调函数返回值
* @param {Object} defVal
* @param {Object} type
* @param {Object} callback
*/
export async function loadOneFieldDefVal(defVal, type, callback) {
if(hasEffectiveValue(defVal)){
let value = await handleDefaultValue(defVal, ACTION_TYPES.ADD, {});
if ('number' === type && value) {
value = Number.parseFloat(value)
}
callback(value)
}
}
/**
* 判断给定的值是不是有效的
*/
function hasEffectiveValue(val) {
if(val || val === 0){
return true;
}
return false;
}
/**
* 获取默认值
* @param {Object} defVal
* @param {Object} action
* @param {Object} getFormData
*/
async function handleDefaultValue(defVal, action, getFormData) {
if (defVal != null) {
// 检查类型,如果类型错误则不继续运行
if (checkExpressionType(defVal)) {
let value = await getDefaultValue(defVal, action, getFormData)
if (value != null) {
return value
}
}
}
return defVal;
}
/**
* 加载form组件默认值
* @param form Form对象
* @param properties 字段配置
* @param action 操作类型(ACTION_TYPES),除填值规则外,其他表达式只在add下才执行
* @param getFormData 获取数据的方法,用于填值规则向后台传值
*/
export function loadFieldDefVal({ form, properties, action, getFormData }) {
if (Array.isArray(properties) && properties.length > 0) {
properties.forEach(async prop => {
let { defVal, type } = prop._formSchem
// key取值错误导致 树形表 表单默认值未生效 【online】树列表不支持控件默认值表达式配置 (博威)
let key = prop.key
// 2021年5月21日 Tree类型表单,系统编码不生效。【issues/I3NR39】
if (!key) {
key = prop._propertyId
}
eachHandler(key, defVal, action, (value) => {
// 处理数字类型,如果type=number并且value有值
if ('number' === type && value) {
// parseFloat() 可以直接处理字符串、整数、小数、null和undefined,
// 非数字类型直接返回NaN,不必担心报错
value = Number.parseFloat(value)
}
form.setFieldsValue({ [key]: value })
}, getFormData)
})
}
}
/** 加载JEditableTable组件默认值 */
export function loadFieldDefValForSubTable({ subForms, subTable, row, action, getFormData }) {
if (subTable && Array.isArray(subTable.columns) && subTable.columns.length > 0) {
subTable.columns.forEach(async column => {
let { key, fieldDefaultValue: defVal } = column
eachHandler(key, defVal, action, (value) => {
if (subForms.form) {
subForms.form.setFieldsValue({ [key]: value })
} else {
// update-begin---author:sunjianlei Date:20200725 for:online功能测试,行操作切换成新的行编辑-----------
let v = [{rowKey: row.id, values: {[key]: value}}];
(subForms.jvt || subForms.jet).setValues(v)
// update-end---author:sunjianlei Date:20200725 for:online功能测试,行操作切换成新的行编辑------------
}
}, getFormData)
})
}
}
async function eachHandler(key, defVal, action, callback, getFormData) {
if (defVal != null) {
// 检查类型,如果类型错误则不继续运行
if (checkExpressionType(defVal)) {
let value = await getDefaultValue(defVal, action, getFormData)
if (value != null) {
callback(value)
}
} else {
// 不合法的表达式直接返回不解析
callback(defVal)
}
}
}
/**
* 检查表达式类型是否合法,规则:
* 1、填值规则表达式不能和其他表达式混用
* 2、每次只能填写一个填值规则表达式
* 3、普通表达式和用户自定义表达式可以混用
*/
export function checkExpressionType(defVal) {
// 获取各个表达式的数量
let normalCount = 0, customCount = 0, fillRuleCount = 0
defVal.replace(fillRuleRegExp, () => fillRuleCount++)
if (fillRuleCount > 1) {
logWarn(`表达式[${defVal}]不合法:只能同时填写一个填值规则表达式!`)
return false
}
defVal.replace(normalRegExp, () => normalCount++)
defVal.replace(customRegExp, () => customCount++)
// 除填值规则外其他规则的数量
let fillRuleOtherCount = normalCount + customCount
if (fillRuleCount > 0 && fillRuleOtherCount > 0) {
logWarn(`表达式[${defVal}]不合法:填值规则表达式不能和其他表达式混用!`)
return false
}
return true
}
/** 获取所有匹配的表达式 */
function getRegExpMap(text, exp) {
let map = new Map()
if(text && text.length>0){
text.replace(exp, function (match, param, offset, string) {
map.set(match, param.trim())
return match
})
}
return map
}
/** 获取默认值,可以执行表达式,可以执行用户自定义方法,可以异步获取用户信息等 */
async function getDefaultValue(defVal, action, getFormData) {
// 只有在 add 和 reload 模式下才执行填值规则
if (action === ACTION_TYPES.ADD || action === ACTION_TYPES.RELOAD) {
// 判断是否是填值规则表达式,如果是就执行填值规则
if (fillRuleRegExp.test(defVal)) {
return await executeRegExp(defVal, fillRuleRegExp, executeFillRuleExpression, [getFormData])
}
}
// 只有在 add 模式下才执行其他表达式
if (action === ACTION_TYPES.ADD) {
// 获取并替换所有常规表达式
defVal = await executeRegExp(defVal, normalRegExp, executeNormalExpression)
// 获取并替换所有用户自定义表达式
defVal = await executeRegExp(defVal, customRegExp, executeCustomExpression)
return defVal
}
return null
}
async function executeRegExp(defVal, regExp, execFun, otherParams = []) {
let map = getRegExpMap(defVal, regExp)
// @ts-ignore
for (let origin of map.keys()) {
let exp = map.get(origin)
let result = await execFun.apply(null, [exp, origin, ...otherParams])
// 如果只有一个表达式,那么就不替换(因为一旦替换,类型就会被转成String),直接返回执行结果,保证返回的类型不变
if (origin === defVal) {
return result
}
defVal = replaceAll(defVal, origin, result)
}
return defVal
}
/** 执行【普通表达式】#{xxx} */
async function executeNormalExpression(expression, origin) {
switch (expression) {
case 'date':
return dayjs().format('YYYY-MM-DD');
case 'time':
return dayjs().format('HH:mm:ss');
case 'datetime':
return dayjs().format('YYYY-MM-DD HH:mm:ss');
default:
// 获取当前登录用户的信息
let result = getUserInfoByExpression(expression)
if (result != null) {
return result
}
// 没有符合条件的表达式,返回原始值
return origin
}
}
/** 根据表达式获取相应的用户信息 */
function getUserInfoByExpression(expression) {
let userInfo:any = useUserStore().userInfo;
if (userInfo) {
switch (expression) {
case 'sysUserId':
return userInfo.id
// 当前登录用户登录账号
case 'sysUserCode':
return userInfo.username
// 当前登录用户真实名称
case 'sysUserName':
return userInfo.realname
// 当前登录用户部门编号
case 'sysOrgCode':
return userInfo.orgCode
}
}
return null
}
/**
* 2023-09-04
* liaozhiyang
* 用new Function替换eval
*/
function _eval(str: string) {
return new Function(`return ${str}`)();
}
/** 执行【用户自定义表达式】 {{xxx}} 移动端不支持 */
async function executeCustomExpression(expression, origin) {
// 利用 eval 生成一个方法,这个方法的参数就是用户自定义的所有的表达式
let fn = _eval(`(function (${ceJoin}){ return ${expression} })`);
try {
// 然后调用这个方法,并把表达式传递进去,从而完成表达式的执行
return fn.apply(null, $CE$)
} catch (e) {
// 执行失败,输出错误并返回原始值
logWarn(e)
return origin
}
}
/** 执行【填值规则表达式】 ${xxx} */
async function executeFillRuleExpression(expression, origin, getFormData) {
let url = `/sys/fillRule/executeRuleByCode/${expression}`
let formData = {}
if (typeof getFormData === 'function') {
formData = getFormData()
}
let res:any = await http.put(url, formData)
let { success, message, result } = res;
console.log(success, message, result)
if (success) {
return result
} else {
logError(`填值规则(${expression})执行失败:${message}`)
return origin
}
}
function logWarn(message) {
console.warn('[loadFieldDefVal]:', message)
}
function logError(message) {
console.error('[loadFieldDefVal]:', message)
}
function replaceAll(text, checker, replacer) {
let lastText = text
text = text.replace(checker, replacer)
if (lastText !== text) {
return replaceAll(text, checker, replacer)
}
return text
}