UNPKG

@ithinkdt/cloud

Version:

iThinkDT Cloud

267 lines (234 loc) 8.41 kB
import { watch, ref, unref, shallowReactive, reactive, isRef } from 'vue' import { $fetch, useCoreCtx } from '@ithinkdt/core' import { CTX } from './ctx' export function useModuleTree({ appCode, immediate = true, includeApp = true, includeEmptyApp = true, includeAction = true, } = {}) { const { saveIcon } = useCoreCtx() const moduleMap = shallowReactive(new Map()) let allApp const result = ref([]) const loading = ref(false) const exec = (appCode) => Promise.all([$fetch.get(`${CTX.SYS}cer/module/list/all`), $fetch.get(`${CTX.SYS}pub/app/all`)]).then( ([modules, apps]) => { allApp = apps moduleMap.clear() const map = new Map(modules.map((item) => [item.id, item])) if (appCode?.trim()) { apps = apps.filter((app) => app.appCode === appCode) } else if (!includeEmptyApp) { apps = apps.filter((app) => map.get(app.id)?.children?.length) } const data = reactive( mapModules( apps.map((app) => { return { id: 'app-' + app.id, asMenu: true, isApp: true, appId: app.id, appCode: app.appCode, icon: app.logo, moduleName: app.appName, children: map.get(app.id)?.children ?? [], } }), undefined, moduleMap, [], includeAction, ), ) return includeApp ? data : data[0]?.children ?? [] }, ) if (isRef(appCode)) { watch( appCode, async (appCode) => { result.value = appCode ? await exec(appCode) : [] }, { immediate }, ) } else { exec(appCode).then((res) => { result.value = res }) } const getByKey = (key) => { const index = moduleMap.get(key) ?? [] let arr = result.value for (let i = includeApp ? 0 : 1; i < index.length - 1; i++) { arr = arr[index[i]]?.children ?? [] } return arr[index.at(-1)] ?? undefined } const getParentByKey = (key) => { const pkey = getByKey(key)?.parentKey return (pkey && getByKey(pkey)) || undefined } const refresh = () => exec(unref(appCode)).then((res) => { result.value = res }) function updateSort(array) { if (!array?.length) return array.sort((a, b) => a.sort - b.sort) for (const [i, it] of array.entries()) { const paths = moduleMap.get(it.id) paths[paths.length - 1] = i } } const transformSaveData = async ( m, parent = m.key ? getParentByKey(m.key) : m.parentKey ? getByKey(m.parentKey) : undefined, ) => { const _m = { id: m.key, parentId: m.parentKey, appId: parent?.appId || allApp.find((app) => app.appCode === m.appCode)?.id, moduleType: moduleTypeMap[m.type], visiable: m.hidden !== true, sortField: m.sort, moduleUrl: (m.type === 'federate' ? m.remote + MODULE_PATH_SPLIT : m.type === 'lowcode' ? m.lcKey + (m.remote ? MODULE_APP_SPLIT + m.remote : '') + MODULE_PATH_SPLIT : '') + m.path, icon: m.icon, moduleLevel: m.level, moduleName: m.label, moduleNameEn: m.labelEn, resources: m.resources?.filter((it) => !!it).join(';'), asMenu: m.type !== 'action', } _m.children = m.children?.length ? await Promise.all( m.children?.map((c) => { c.parentKey ||= '' return transformSaveData(c, _m) }), ) : undefined if (_m.icon && typeof _m.icon !== 'string') { const { id } = await saveIcon({ ..._m.icon, type: 'module', }) _m.icon = id } if (_m.parentId === undefined || _m.parentId?.startsWith('app-')) { _m.parentId = '0' } return _m } const mapSavedData = (saved, m, _m) => { const p = getByKey(m.parentKey) let m2 if (_m.id) { const last = getByKey(_m.id) Object.assign(last, m) } else { m2 = mapModule(saved, -1, p, moduleMap, moduleMap.get(m.parentKey), includeAction) const children = p.children || [] children.push(m2) p.children = children } updateSort(p?.children) return m2 } return { tree: result, loading, getByKey, getParentByKey, refresh, save: async (ms) => { const batch = Array.isArray(ms) const _ms = await (batch ? Promise.all(ms.map((m) => transformSaveData(m))) : transformSaveData(ms)) return $fetch .post(batch ? `${CTX.SYS}cer/module/batch/save` : `${CTX.SYS}cer/module/save`, _ms) .then((saved) => { if (batch) { refresh() return _ms.map((_m, i) => mapSavedData(saved[i], ms[i], _m)) } else { return mapSavedData(saved, ms, _ms) } }) }, del: (m) => { const id = m.key ?? m return $fetch.post(`${CTX.SYS}cer/module/delete`, { id }, { reqType: 'urlencoded' }).then(() => { const p = getParentByKey(id) const index = p.children.findIndex((c) => c.id === id) index > -1 && p.children.splice(index, 1) updateSort(p.children) }) }, } } const moduleTypeMap = { group: '00', module: '01', lowcode: '02', federate: '03', external: '04', other: '99', } const moduleTypeMap2 = Object.fromEntries(Object.entries(moduleTypeMap).map(([k, v]) => [v, k])) export const MODULE_PATH_SPLIT = ' | ' export const MODULE_APP_SPLIT = ' @ ' export { moduleTypeMap2 as moduleTypeMap } const mapModule = (m, i, parent, map, path, includeAction) => { if (!includeAction && !m.isApp && !m.asMenu) { return } const s = m.resources?.trim() path = [...path, i] map?.set(m.id, path) let children = m.asMenu && m.children?.length ? mapModules(m.children, m, map, path, includeAction) : m.isApp ? [] : undefined if (!includeAction) { children = children?.filter((it) => !!it) if (!children?.length) children = undefined } let type = moduleTypeMap2[m.moduleType ?? moduleTypeMap.module] if (type === 'group') type = 'module' const [prefix, path2] = m.moduleUrl?.split(MODULE_PATH_SPLIT) ?? [] const _m = { id: m.id, key: m.id, parentKey: parent?.id, parent: parent, label: m.moduleName, labelEn: m.moduleNameEn, resources: s ? s.split(';') : [], type: m.isApp ? 'other' : m.asMenu ? type : 'action', level: m.moduleLevel, icon: m.icon, path: type === 'federate' || type === 'lowcode' ? path2 : m.moduleUrl, remote: type === 'federate' ? prefix : type === 'lowcode' ? prefix.split(MODULE_APP_SPLIT)[1] : undefined, lcKey: type === 'lowcode' ? prefix.split(MODULE_APP_SPLIT)[0] : undefined, hidden: m.visiable === false, sort: m.sortField, appId: m.appId, appCode: m.appCode || parent?.appCode, children, } return _m } const mapModules = (modules, parent, map, path = [], includeAction) => { let i = 0 return modules.map((m) => { const _m = mapModule(m, i, parent, map, path, includeAction) if (_m) i++ return _m }) }