7021f2fd创建于 2025年5月14日历史提交

// 移动端不支持自定义表达式设置的默认值
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
}