UNPKG

@ithinkdt/cloud

Version:

iThinkDT Cloud

257 lines (232 loc) 9.93 kB
import { HttpError, merge, qsParse } from '@ithinkdt/common' import { $fetch } from '@ithinkdt/core' import { sourceApp } from './ctx' import { moduleTypeMap, MODULE_PATH_SPLIT, MODULE_APP_SPLIT } from './module' export let _token function logout(ctx, token) { return fetch(`${ctx}logout`, { method: 'post', redirect: 'error', credentials: 'omit', headers: new Headers({ Authorization: `Bearer ${token}`, }), }).catch((error) => { console.debug('调用登出接口错误', error) }) } export function getDictApi(ctx) { return { async fetchDicts(types) { const api = types.length > 1 ? 'Types' : 'Type' const res = await $fetch.get(`${ctx}cli/dict/value/getBy${api}`, { [`dict${api}`]: types.join(','), }) return api === 'Types' ? res : { [types[0]]: res } }, labelGetter: (dict, locale) => (locale === 'zh-CN' ? dict.dictValue : dict.dictValueEn) ?? dict.dictValue, valueGetter: (dict) => dict.dictKey, } } let context export function loadFrontConfig(appCode, { _BASE, SYS, YIDA }, apps) { return Promise.all([ apps?.length ? Promise.resolve({ data: apps }) : fetch(`${_BASE}${SYS}pub/app/all`, { credentials: 'omit' }) .then((resp) => resp.json()) .catch((error) => { console.log(`未能获取到前端应用信息 (${error.message}),使用默认配置。`) return { data: [], } }), fetch(`${_BASE}${SYS}pub/busConfig/getFrontConfig`, { credentials: 'omit' }) .then((resp) => resp.json()) .catch((error) => { console.log(`未能获取到前端配置 (${error.message}),使用默认配置。`) return { data: [], } }), YIDA ? fetch(`${_BASE}${YIDA}/pub/yida/app/personalize/${appCode}`) .then((resp) => resp.json()) .catch((error) => { console.log(`未能获取到前端配置 (${error.message}),使用默认配置。`) return { data: {}, } }) : Promise.resolve({}), ]).then(async ([{ data: apps }, { data: configs }, { data: personalize = {} }]) => { const map = {} for (const it of configs) { map[it.configKey] = it.configValue } context = {} for (let { appCode, url = '' } of apps) { if (!url.endsWith('/')) url = url + '/' context[appCode] = url context[appCode.replaceAll('-', '_').toUpperCase()] = url } const logo = await fetch( `${_BASE}${SYS}pub/logo/${apps.find((app) => app.appCode === appCode)?.logo || map.FRONT_LOGO_ID}`, ).then((resp) => resp.text()) return { ...map, context, apps, appName(appCode, locale) { const app = apps.find((app) => app.appCode === appCode) return ( app?.[locale.startsWith('zh') ? 'appName' : 'appNameEn'] ?? app?.appName ?? app?.appNameEn ?? '系统' ) }, logo, multiTab: personalize.multiTab ?? map.FRONT_MULTI_TAB === 'true', i18n: map.FRONT_I18N === 'true', accordionMenu: personalize.accordionMenu ?? map.FRONT_ACCORDION_MENU === 'true', collpaseBtnPlacement: personalize.collpaseBtnPlacement ?? (map.FRONT_COLLPASE_BTN_PLACEMENT || 'default'), menuPlacement: personalize.menuPlacement ?? (map.FRONT_MENU_PLACEMENT || 'sidebar'), appearence: personalize.showAppearence ?? map.FRONT_APPEARENCE === 'true', theme: { light: JSON.parse(map.FRONT_THEME_LIGHT ?? '{}'), dark: merge({}, JSON.parse(map.FRONT_THEME_LIGHT ?? '{}'), JSON.parse(map.FRONT_THEME_DARK ?? '{}')), }, locale: map.FRONT_LOCALE || undefined, watermark: personalize.watermark ?? map.FRONT_WATERMARK === 'true', renderWatermark: new Function('user', `return (${map.FRONT_WATERMARK_RENDER})`), footer: map.FRONT_FOOTER.trim() || undefined, timeout: Number.parseFloat(map.FRONT_REQUEST_TIMEOUT) || undefined, domain: map.FRONT_COOKIE_DOMAIN || undefined, sso: map.FRONT_SSO_ENABLED === 'false' ? false : { selfLogin: map.FRONT_LOCAL_LOGIN === 'true', login: (redirect) => { return new Function('redirect', `return \`${map.FRONT_SSO_LOGIN_URL}\``)( encodeURIComponent(redirect), ) }, logout: async (redirect, { appCode, username, token }) => { await logout(_BASE + SYS, token) return new Function( 'redirect', 'appCode', 'username', `return \`${map.FRONT_SSO_LOGOUT_URL}\``, )(encodeURIComponent(redirect), encodeURIComponent(appCode), encodeURIComponent(username)) }, parseToken: (fromUrl) => { const url = new URL(fromUrl) return new Function('url', 'query', map.FRONT_SSO_PARSE_URL)( fromUrl, qsParse(url.search || '?' + (url.hash.split('?')[1] || '')), ) }, }, } }) } function mapModules(modules, appCode, locale) { return (modules ?? []).map((it) => { const children = mapModules(it.children, appCode, locale) let type = it.asMenu ? children.some((it) => it.type !== 'action' && it.hidden !== true) ? 'group' : (it.moduleType && moduleTypeMap[it.moduleType]) || 'module' : 'action' let moduleUrl = it.moduleUrl if (type === 'module' && appCode !== sourceApp) { type = 'federate' moduleUrl = appCode + MODULE_PATH_SPLIT + moduleUrl } let lcKey let remote if (type === 'federate') { remote = moduleUrl?.split(MODULE_PATH_SPLIT)[0] if (!remote || remote === sourceApp) { type = 'module' remote = undefined moduleUrl = moduleUrl?.split(MODULE_PATH_SPLIT)[1] } else { remote = context[remote] + 'routes.js?_t=' + Date.now() } } else if (type === 'lowcode') { const [prefix] = moduleUrl?.split(MODULE_PATH_SPLIT) ?? [] lcKey = prefix?.split(MODULE_APP_SPLIT)[0] remote = prefix?.split(MODULE_APP_SPLIT)[1] } return { key: it.id, type, label: (locale === 'zh-CN' ? it.moduleName : it.moduleNameEn) ?? it.moduleName ?? it.text, hidden: it.visiable === false, path: ['federate', 'lowcode'].includes(type) ? moduleUrl.split(MODULE_PATH_SPLIT)[1] : moduleUrl, remote, lcKey, level: it.moduleLevel, icon: it.icon, children: children, parentKey: it.parentId, actions: type === 'action' ? moduleUrl?.split(',').filter((it) => !!it) : children.map((it) => it.actions).flat(Number.POSITIVE_INFINITY), } }) } export function getAuthApi(appCode, ctx, base) { return { login(user) { return $fetch.post(`${ctx}login`, user, { alert: false, redirect: 'error' }) }, logout({ token }) { return logout(base + ctx, token) }, async loadAuthInfo(token, locale) { _token = token const [user, modules] = await Promise.allSettled([ $fetch.get(`${ctx}cli/userinfo`, undefined, { alert: false }), $fetch.get(`${ctx}cli/modules`, appCode ? { appCode } : undefined, { alert: false }), ]) if (user?.reason instanceof HttpError) { if (user?.reason.code === 403) { throw new Error('forbidden') } if (user?.reason.code === 408) { throw new Error('timeout') } throw user?.reason } const _ms = appCode ? modules.value[0]?.children : modules.value if (_ms) for (const m of _ms) { m.asMenu = true } return { user: { ...user.value, nickname: user.value.personName, }, modules: mapModules(_ms, appCode, locale), } }, changePwd({ old: curPassword, new: newPassword }) { return $fetch.post( `${ctx}cli/user/password/change`, { curPassword, newPassword }, { reqType: 'urlencoded' }, ) }, jwt: { headerField: 'Authorization', cookieField: 'access_token', tokenFormatter: (token) => `Bearer ${token}`, tokenParser: (str) => str?.slice(7), unauthCodes: [401, 604, 606], }, } }