2 changed files with 399 additions and 0 deletions
			
			
		@ -0,0 +1,124 @@
					 | 
				
			||||
/** | 
				
			||||
 * 数据字典工具类 | 
				
			||||
 */ | 
				
			||||
import { useDictStoreWithOut } from '@/store/modules/dict' | 
				
			||||
 | 
				
			||||
const dictStore = useDictStoreWithOut() | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * 获取 dictType 对应的数据字典数组 | 
				
			||||
 * | 
				
			||||
 * @param dictType 数据类型 | 
				
			||||
 * @returns {*|Array} 数据字典数组 | 
				
			||||
 */ | 
				
			||||
export interface DictDataType { | 
				
			||||
  dictType: string | 
				
			||||
  label: string | 
				
			||||
  value: string | number | boolean | 
				
			||||
  colorType: string | 
				
			||||
  cssClass: string | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const getDictOptions = (dictType: string) => { | 
				
			||||
  return dictStore.getDictMap[dictType] | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const getIntDictOptions = (dictType: string) => { | 
				
			||||
  const dictOption: DictDataType[] = [] | 
				
			||||
  const dictOptions: DictDataType[] = getDictOptions(dictType) | 
				
			||||
  dictOptions.forEach((dict: DictDataType) => { | 
				
			||||
    dictOption.push({ | 
				
			||||
      ...dict, | 
				
			||||
      value: parseInt(dict.value + '') | 
				
			||||
    }) | 
				
			||||
  }) | 
				
			||||
 | 
				
			||||
  return dictOption | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const getStrDictOptions = (dictType: string) => { | 
				
			||||
  const dictOption: DictDataType[] = [] | 
				
			||||
  const dictOptions: DictDataType[] = getDictOptions(dictType) | 
				
			||||
  dictOptions.forEach((dict: DictDataType) => { | 
				
			||||
    dictOption.push({ | 
				
			||||
      ...dict, | 
				
			||||
      value: dict.value + '' | 
				
			||||
    }) | 
				
			||||
  }) | 
				
			||||
  return dictOption | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const getBoolDictOptions = (dictType: string) => { | 
				
			||||
  const dictOption: DictDataType[] = [] | 
				
			||||
  const dictOptions: DictDataType[] = getDictOptions(dictType) | 
				
			||||
  dictOptions.forEach((dict: DictDataType) => { | 
				
			||||
    dictOption.push({ | 
				
			||||
      ...dict, | 
				
			||||
      value: dict.value + '' === 'true' ? true : false | 
				
			||||
    }) | 
				
			||||
  }) | 
				
			||||
  return dictOption | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const getDictObj = (dictType: string, value: any) => { | 
				
			||||
  const dictOptions: DictDataType[] = getDictOptions(dictType) | 
				
			||||
  dictOptions.forEach((dict: DictDataType) => { | 
				
			||||
    if (dict.value === value.toString()) { | 
				
			||||
      return dict | 
				
			||||
    } | 
				
			||||
  }) | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export enum DICT_TYPE { | 
				
			||||
  USER_TYPE = 'user_type', | 
				
			||||
  COMMON_STATUS = 'common_status', | 
				
			||||
  SYSTEM_TENANT_PACKAGE_ID = 'system_tenant_package_id', | 
				
			||||
 | 
				
			||||
  // ========== SYSTEM 模块 ==========
 | 
				
			||||
  SYSTEM_USER_SEX = 'system_user_sex', | 
				
			||||
  SYSTEM_MENU_TYPE = 'system_menu_type', | 
				
			||||
  SYSTEM_ROLE_TYPE = 'system_role_type', | 
				
			||||
  SYSTEM_DATA_SCOPE = 'system_data_scope', | 
				
			||||
  SYSTEM_NOTICE_TYPE = 'system_notice_type', | 
				
			||||
  SYSTEM_OPERATE_TYPE = 'system_operate_type', | 
				
			||||
  SYSTEM_LOGIN_TYPE = 'system_login_type', | 
				
			||||
  SYSTEM_LOGIN_RESULT = 'system_login_result', | 
				
			||||
  SYSTEM_SMS_CHANNEL_CODE = 'system_sms_channel_code', | 
				
			||||
  SYSTEM_SMS_TEMPLATE_TYPE = 'system_sms_template_type', | 
				
			||||
  SYSTEM_SMS_SEND_STATUS = 'system_sms_send_status', | 
				
			||||
  SYSTEM_SMS_RECEIVE_STATUS = 'system_sms_receive_status', | 
				
			||||
  SYSTEM_ERROR_CODE_TYPE = 'system_error_code_type', | 
				
			||||
  SYSTEM_OAUTH2_GRANT_TYPE = 'system_oauth2_grant_type', | 
				
			||||
 | 
				
			||||
  // ========== INFRA 模块 ==========
 | 
				
			||||
  INFRA_BOOLEAN_STRING = 'infra_boolean_string', | 
				
			||||
  INFRA_REDIS_TIMEOUT_TYPE = 'infra_redis_timeout_type', | 
				
			||||
  INFRA_JOB_STATUS = 'infra_job_status', | 
				
			||||
  INFRA_JOB_LOG_STATUS = 'infra_job_log_status', | 
				
			||||
  INFRA_API_ERROR_LOG_PROCESS_STATUS = 'infra_api_error_log_process_status', | 
				
			||||
  INFRA_CONFIG_TYPE = 'infra_config_type', | 
				
			||||
  INFRA_CODEGEN_TEMPLATE_TYPE = 'infra_codegen_template_type', | 
				
			||||
  INFRA_CODEGEN_SCENE = 'infra_codegen_scene', | 
				
			||||
  INFRA_FILE_STORAGE = 'infra_file_storage', | 
				
			||||
 | 
				
			||||
  // ========== BPM 模块 ==========
 | 
				
			||||
  BPM_MODEL_CATEGORY = 'bpm_model_category', | 
				
			||||
  BPM_MODEL_FORM_TYPE = 'bpm_model_form_type', | 
				
			||||
  BPM_TASK_ASSIGN_RULE_TYPE = 'bpm_task_assign_rule_type', | 
				
			||||
  BPM_PROCESS_INSTANCE_STATUS = 'bpm_process_instance_status', | 
				
			||||
  BPM_PROCESS_INSTANCE_RESULT = 'bpm_process_instance_result', | 
				
			||||
  BPM_TASK_ASSIGN_SCRIPT = 'bpm_task_assign_script', | 
				
			||||
  BPM_OA_LEAVE_TYPE = 'bpm_oa_leave_type', | 
				
			||||
 | 
				
			||||
  // ========== PAY 模块 ==========
 | 
				
			||||
  PAY_CHANNEL_WECHAT_VERSION = 'pay_channel_wechat_version', // 微信渠道版本
 | 
				
			||||
  PAY_CHANNEL_ALIPAY_SIGN_TYPE = 'pay_channel_alipay_sign_type', // 支付渠道支付宝算法类型
 | 
				
			||||
  PAY_CHANNEL_ALIPAY_MODE = 'pay_channel_alipay_mode', // 支付宝公钥类型
 | 
				
			||||
  PAY_CHANNEL_ALIPAY_SERVER_TYPE = 'pay_channel_alipay_server_type', // 支付宝网关地址
 | 
				
			||||
  PAY_CHANNEL_CODE_TYPE = 'pay_channel_code_type', // 支付渠道编码类型
 | 
				
			||||
  PAY_ORDER_NOTIFY_STATUS = 'pay_order_notify_status', // 商户支付订单回调状态
 | 
				
			||||
  PAY_ORDER_STATUS = 'pay_order_status', // 商户支付订单状态
 | 
				
			||||
  PAY_ORDER_REFUND_STATUS = 'pay_order_refund_status', // 商户支付订单退款状态
 | 
				
			||||
  PAY_REFUND_ORDER_STATUS = 'pay_refund_order_status', // 退款订单状态
 | 
				
			||||
  PAY_REFUND_ORDER_TYPE = 'pay_refund_order_type' // 退款订单类别
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,275 @@
					 | 
				
			||||
interface TreeHelperConfig { | 
				
			||||
  id: string | 
				
			||||
  children: string | 
				
			||||
  pid: string | 
				
			||||
} | 
				
			||||
const DEFAULT_CONFIG: TreeHelperConfig = { | 
				
			||||
  id: 'id', | 
				
			||||
  children: 'children', | 
				
			||||
  pid: 'pid' | 
				
			||||
} | 
				
			||||
export const defaultProps = { | 
				
			||||
  children: 'children', | 
				
			||||
  label: 'name', | 
				
			||||
  value: 'id' | 
				
			||||
} | 
				
			||||
 | 
				
			||||
const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config) | 
				
			||||
 | 
				
			||||
// tree from list
 | 
				
			||||
export const listToTree = <T = any>(list: any[], config: Partial<TreeHelperConfig> = {}): T[] => { | 
				
			||||
  const conf = getConfig(config) as TreeHelperConfig | 
				
			||||
  const nodeMap = new Map() | 
				
			||||
  const result: T[] = [] | 
				
			||||
  const { id, children, pid } = conf | 
				
			||||
 | 
				
			||||
  for (const node of list) { | 
				
			||||
    node[children] = node[children] || [] | 
				
			||||
    nodeMap.set(node[id], node) | 
				
			||||
  } | 
				
			||||
  for (const node of list) { | 
				
			||||
    const parent = nodeMap.get(node[pid]) | 
				
			||||
    ;(parent ? parent.children : result).push(node) | 
				
			||||
  } | 
				
			||||
  return result | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const treeToList = <T = any>(tree: any, config: Partial<TreeHelperConfig> = {}): T => { | 
				
			||||
  config = getConfig(config) | 
				
			||||
  const { children } = config | 
				
			||||
  const result: any = [...tree] | 
				
			||||
  for (let i = 0; i < result.length; i++) { | 
				
			||||
    if (!result[i][children!]) continue | 
				
			||||
    result.splice(i + 1, 0, ...result[i][children!]) | 
				
			||||
  } | 
				
			||||
  return result | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const findNode = <T = any>(tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}): T | null => { | 
				
			||||
  config = getConfig(config) | 
				
			||||
  const { children } = config | 
				
			||||
  const list = [...tree] | 
				
			||||
  for (const node of list) { | 
				
			||||
    if (func(node)) return node | 
				
			||||
    node[children!] && list.push(...node[children!]) | 
				
			||||
  } | 
				
			||||
  return null | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const findNodeAll = <T = any>(tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}): T[] => { | 
				
			||||
  config = getConfig(config) | 
				
			||||
  const { children } = config | 
				
			||||
  const list = [...tree] | 
				
			||||
  const result: T[] = [] | 
				
			||||
  for (const node of list) { | 
				
			||||
    func(node) && result.push(node) | 
				
			||||
    node[children!] && list.push(...node[children!]) | 
				
			||||
  } | 
				
			||||
  return result | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const findPath = <T = any>(tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}): T | T[] | null => { | 
				
			||||
  config = getConfig(config) | 
				
			||||
  const path: T[] = [] | 
				
			||||
  const list = [...tree] | 
				
			||||
  const visitedSet = new Set() | 
				
			||||
  const { children } = config | 
				
			||||
  while (list.length) { | 
				
			||||
    const node = list[0] | 
				
			||||
    if (visitedSet.has(node)) { | 
				
			||||
      path.pop() | 
				
			||||
      list.shift() | 
				
			||||
    } else { | 
				
			||||
      visitedSet.add(node) | 
				
			||||
      node[children!] && list.unshift(...node[children!]) | 
				
			||||
      path.push(node) | 
				
			||||
      if (func(node)) { | 
				
			||||
        return path | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
  return null | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const findPathAll = (tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}) => { | 
				
			||||
  config = getConfig(config) | 
				
			||||
  const path: any[] = [] | 
				
			||||
  const list = [...tree] | 
				
			||||
  const result: any[] = [] | 
				
			||||
  const visitedSet = new Set(), | 
				
			||||
    { children } = config | 
				
			||||
  while (list.length) { | 
				
			||||
    const node = list[0] | 
				
			||||
    if (visitedSet.has(node)) { | 
				
			||||
      path.pop() | 
				
			||||
      list.shift() | 
				
			||||
    } else { | 
				
			||||
      visitedSet.add(node) | 
				
			||||
      node[children!] && list.unshift(...node[children!]) | 
				
			||||
      path.push(node) | 
				
			||||
      func(node) && result.push([...path]) | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
  return result | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const filter = <T = any>(tree: T[], func: (n: T) => boolean, config: Partial<TreeHelperConfig> = {}): T[] => { | 
				
			||||
  config = getConfig(config) | 
				
			||||
  const children = config.children as string | 
				
			||||
  function listFilter(list: T[]) { | 
				
			||||
    return list | 
				
			||||
      .map((node: any) => ({ ...node })) | 
				
			||||
      .filter((node) => { | 
				
			||||
        node[children] = node[children] && listFilter(node[children]) | 
				
			||||
        return func(node) || (node[children] && node[children].length) | 
				
			||||
      }) | 
				
			||||
  } | 
				
			||||
  return listFilter(tree) | 
				
			||||
} | 
				
			||||
 | 
				
			||||
export const forEach = <T = any>(tree: T[], func: (n: T) => any, config: Partial<TreeHelperConfig> = {}): void => { | 
				
			||||
  config = getConfig(config) | 
				
			||||
  const list: any[] = [...tree] | 
				
			||||
  const { children } = config | 
				
			||||
  for (let i = 0; i < list.length; i++) { | 
				
			||||
    // func 返回true就终止遍历,避免大量节点场景下无意义循环,引起浏览器卡顿
 | 
				
			||||
    if (func(list[i])) { | 
				
			||||
      return | 
				
			||||
    } | 
				
			||||
    children && list[i][children] && list.splice(i + 1, 0, ...list[i][children]) | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * @description: Extract tree specified structure | 
				
			||||
 */ | 
				
			||||
export const treeMap = <T = any>(treeData: T[], opt: { children?: string; conversion: Fn }): T[] => { | 
				
			||||
  return treeData.map((item) => treeMapEach(item, opt)) | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * @description: Extract tree specified structure | 
				
			||||
 */ | 
				
			||||
export const treeMapEach = (data: any, { children = 'children', conversion }: { children?: string; conversion: Fn }) => { | 
				
			||||
  const haveChildren = Array.isArray(data[children]) && data[children].length > 0 | 
				
			||||
  const conversionData = conversion(data) || {} | 
				
			||||
  if (haveChildren) { | 
				
			||||
    return { | 
				
			||||
      ...conversionData, | 
				
			||||
      [children]: data[children].map((i: number) => | 
				
			||||
        treeMapEach(i, { | 
				
			||||
          children, | 
				
			||||
          conversion | 
				
			||||
        }) | 
				
			||||
      ) | 
				
			||||
    } | 
				
			||||
  } else { | 
				
			||||
    return { | 
				
			||||
      ...conversionData | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * 递归遍历树结构 | 
				
			||||
 * @param treeDatas 树 | 
				
			||||
 * @param callBack 回调 | 
				
			||||
 * @param parentNode 父节点 | 
				
			||||
 */ | 
				
			||||
export const eachTree = (treeDatas: any[], callBack: Fn, parentNode = {}) => { | 
				
			||||
  treeDatas.forEach((element) => { | 
				
			||||
    const newNode = callBack(element, parentNode) || element | 
				
			||||
    if (element.children) { | 
				
			||||
      eachTree(element.children, callBack, newNode) | 
				
			||||
    } | 
				
			||||
  }) | 
				
			||||
} | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * 构造树型结构数据 | 
				
			||||
 * @param {*} data 数据源 | 
				
			||||
 * @param {*} id id字段 默认 'id' | 
				
			||||
 * @param {*} parentId 父节点字段 默认 'parentId' | 
				
			||||
 * @param {*} children 孩子节点字段 默认 'children' | 
				
			||||
 */ | 
				
			||||
export const handleTree = (data: any[], id?: string, parentId?: string, children?: string) => { | 
				
			||||
  if (!Array.isArray(data)) { | 
				
			||||
    console.warn('data must be an array') | 
				
			||||
    return [] | 
				
			||||
  } | 
				
			||||
  const config = { | 
				
			||||
    id: id || 'id', | 
				
			||||
    parentId: parentId || 'parentId', | 
				
			||||
    childrenList: children || 'children' | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  const childrenListMap = {} | 
				
			||||
  const nodeIds = {} | 
				
			||||
  const tree: any[] = [] | 
				
			||||
 | 
				
			||||
  for (const d of data) { | 
				
			||||
    const parentId = d[config.parentId] | 
				
			||||
    if (childrenListMap[parentId] == null) { | 
				
			||||
      childrenListMap[parentId] = [] | 
				
			||||
    } | 
				
			||||
    nodeIds[d[config.id]] = d | 
				
			||||
    childrenListMap[parentId].push(d) | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  for (const d of data) { | 
				
			||||
    const parentId = d[config.parentId] | 
				
			||||
    if (nodeIds[parentId] == null) { | 
				
			||||
      tree.push(d) | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  for (const t of tree) { | 
				
			||||
    adaptToChildrenList(t) | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  function adaptToChildrenList(o) { | 
				
			||||
    if (childrenListMap[o[config.id]] !== null) { | 
				
			||||
      o[config.childrenList] = childrenListMap[o[config.id]] | 
				
			||||
    } | 
				
			||||
    if (o[config.childrenList]) { | 
				
			||||
      for (const c of o[config.childrenList]) { | 
				
			||||
        adaptToChildrenList(c) | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
  return tree | 
				
			||||
} | 
				
			||||
/** | 
				
			||||
 * 构造树型结构数据 | 
				
			||||
 * @param {*} data 数据源 | 
				
			||||
 * @param {*} id id字段 默认 'id' | 
				
			||||
 * @param {*} parentId 父节点字段 默认 'parentId' | 
				
			||||
 * @param {*} children 孩子节点字段 默认 'children' | 
				
			||||
 * @param {*} rootId 根Id 默认 0 | 
				
			||||
 */ | 
				
			||||
export const handleTree2 = (data, id, parentId, children, rootId) => { | 
				
			||||
  id = id || 'id' | 
				
			||||
  parentId = parentId || 'parentId' | 
				
			||||
  children = children || 'children' | 
				
			||||
  rootId = | 
				
			||||
    rootId || | 
				
			||||
    Math.min( | 
				
			||||
      ...data.map((item) => { | 
				
			||||
        return item[parentId] | 
				
			||||
      }) | 
				
			||||
    ) || | 
				
			||||
    0 | 
				
			||||
  //对源数据深度克隆
 | 
				
			||||
  const cloneData = JSON.parse(JSON.stringify(data)) | 
				
			||||
  //循环所有项
 | 
				
			||||
  const treeData = cloneData.filter((father) => { | 
				
			||||
    const branchArr = cloneData.filter((child) => { | 
				
			||||
      //返回每一项的子级数组
 | 
				
			||||
      return father[id] === child[parentId] | 
				
			||||
    }) | 
				
			||||
    branchArr.length > 0 ? (father.children = branchArr) : '' | 
				
			||||
    //返回第一层
 | 
				
			||||
    return father[parentId] === rootId | 
				
			||||
  }) | 
				
			||||
  return treeData !== '' ? treeData : data | 
				
			||||
} | 
				
			||||
		Reference in new issue