From d5970329a491624fdb87dde430d6a9ec497ca860 Mon Sep 17 00:00:00 2001 From: jingrow Date: Mon, 3 Nov 2025 00:00:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96pagetypeOverride.ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/core/registry/pagetypeOverride.ts | 180 +++++++----------- 1 file changed, 64 insertions(+), 116 deletions(-) diff --git a/apps/jingrow/frontend/src/core/registry/pagetypeOverride.ts b/apps/jingrow/frontend/src/core/registry/pagetypeOverride.ts index 9c017bf..06a0af5 100644 --- a/apps/jingrow/frontend/src/core/registry/pagetypeOverride.ts +++ b/apps/jingrow/frontend/src/core/registry/pagetypeOverride.ts @@ -37,14 +37,18 @@ function extractAppName(absPath: string): string { return 'jingrow' } -function appsOrder(): string[] { - return Array.isArray(__APPS_ORDER__) && __APPS_ORDER__.length > 0 ? __APPS_ORDER__ : ['jingrow'] -} +// 缓存应用顺序和排名,避免重复计算 +const APP_ORDER: readonly string[] = Object.freeze( + Array.isArray(__APPS_ORDER__) && __APPS_ORDER__.length > 0 ? __APPS_ORDER__ : ['jingrow'] +) +const APP_RANK_CACHE = new Map() -function rankByAppsOrder(appName: string): number { - const order = appsOrder() - const idx = order.indexOf(appName) - return idx >= 0 ? idx : -1 +function getAppRank(appName: string): number { + if (!APP_RANK_CACHE.has(appName)) { + const idx = APP_ORDER.indexOf(appName) + APP_RANK_CACHE.set(appName, idx >= 0 ? idx : -1) + } + return APP_RANK_CACHE.get(appName)! } for (const [p, loader] of Object.entries(globAllApps)) { @@ -57,8 +61,8 @@ for (const [p, loader] of Object.entries(globLocal)) { } function sortByPriority(a: string, b: string): number { - const ra = rankByAppsOrder(allPagetypeViews[a].appName) - const rb = rankByAppsOrder(allPagetypeViews[b].appName) + const ra = getAppRank(allPagetypeViews[a].appName) + const rb = getAppRank(allPagetypeViews[b].appName) if (ra !== rb) return rb - ra if (a.length !== b.length) return a.length - b.length return a.localeCompare(b) @@ -82,46 +86,34 @@ function ensureIndexed(entity: string): Indexed { return indexedByEntity[entity] } -// 构建索引 +// 性能优化:使用正则表达式一次性提取路径信息,避免多次字符串扫描 +const PAGETYPE_PATH_REGEX = /\/pagetype\/([^/]+)\/([^/]+)\.vue$/i + +// 文件类型映射表(预编译,避免运行时字符串拼接) +function getBucketType(folderName: string, baseName: string): keyof Indexed | null { + if (baseName === folderName) return 'detail' + if (baseName === `${folderName}_toolbar`) return 'toolbar' + if (baseName === `${folderName}_list`) return 'list' + if (baseName === `${folderName}_list_toolbar`) return 'listToolbar' + if (baseName === `${folderName}_list_filterbar`) return 'filterbar' + if (baseName === `${folderName}_list_actions`) return 'actions' + return null +} + +// 构建索引(优化版:正则表达式 + 快速映射) for (const file of Object.keys(allPagetypeViews)) { - const segs = file.split('/').filter(Boolean) - const len = segs.length - if (!file.includes('/pagetype/')) continue - const pagetypeIdx = segs.indexOf('pagetype') - if (pagetypeIdx < 0 || pagetypeIdx + 2 >= len) continue + const match = file.match(PAGETYPE_PATH_REGEX) + if (!match) continue - const fileName = segs[len - 1] - const folderName = segs[pagetypeIdx + 1] - const baseName = fileName.replace(/\.vue$/i, '') - // 统一转为小写进行索引和匹配 + const [, folderName, fileName] = match + const baseName = fileName.replace(/\.vue$/i, '').toLowerCase() const folderNameLower = folderName.toLowerCase() - const baseNameLower = baseName.toLowerCase() const entity = folderNameLower const bucket = ensureIndexed(entity) - // 详情页覆盖:.vue - if (baseNameLower === folderNameLower) { - bucket.detail.push(file) - } - // 详情页工具栏覆盖:_toolbar.vue - else if (baseNameLower === `${folderNameLower}_toolbar`) { - bucket.toolbar.push(file) - } - // 列表页覆盖:_list.vue - else if (baseNameLower === `${folderNameLower}_list`) { - bucket.list.push(file) - } - // 列表页工具栏覆盖:_list_toolbar.vue - else if (baseNameLower === `${folderNameLower}_list_toolbar`) { - bucket.listToolbar.push(file) - } - // 列表页过滤栏覆盖:_list_filterbar.vue - else if (baseNameLower === `${folderNameLower}_list_filterbar`) { - bucket.filterbar.push(file) - } - // 列表页操作列覆盖:_list_actions.vue - else if (baseNameLower === `${folderNameLower}_list_actions`) { - bucket.actions.push(file) + const type = getBucketType(folderNameLower, baseName) + if (type) { + bucket[type].push(file) } } @@ -135,23 +127,35 @@ Object.values(indexedByEntity).forEach(({ detail, toolbar, list, listToolbar, fi actions.sort(sortByPriority) }) +// 统一的字符串标准化函数(避免重复计算) +function normalizeSlug(slug: string): string { + return slug.toLowerCase().replace(/-/g, '_') +} + +// 通用的解析函数(消除代码重复) +async function resolveOverride( + pagetypeSlug: string, + bucketType: keyof Indexed +): Promise { + if (!pagetypeSlug) return null + const entityKey = normalizeSlug(pagetypeSlug) + const bucket = indexedByEntity[entityKey] + if (!bucket || bucket[bucketType].length === 0) return null + const pick = bucket[bucketType][0] + try { + const mod = await allPagetypeViews[pick].loader() + return mod?.default ?? mod + } catch { + return null + } +} + /** * 解析并返回指定 pagetype 的详情覆盖组件 * @param pagetypeSlug 路由中的原始 pagetype(保持小写与下划线) */ export async function resolvePagetypeDetailOverride(pagetypeSlug: string): Promise { - if (!pagetypeSlug) return null - const targetHyphen = pagetypeSlug.toLowerCase() - const targetUnderscore = targetHyphen.replace(/-/g, '_') - const bucket = indexedByEntity[targetUnderscore] - if (!bucket || bucket.detail.length === 0) return null - const pick = bucket.detail[0] - try { - const mod = await allPagetypeViews[pick].loader() - return mod?.default ?? mod - } catch (_e) { - return null - } + return resolveOverride(pagetypeSlug, 'detail') } /** @@ -159,18 +163,7 @@ export async function resolvePagetypeDetailOverride(pagetypeSlug: string): Promi * 约定文件名:/src/views/pagetype//_toolbar.vue */ export async function resolvePagetypeToolbarOverride(pagetypeSlug: string): Promise { - if (!pagetypeSlug) return null - const targetHyphen = pagetypeSlug.toLowerCase() - const targetUnderscore = targetHyphen.replace(/-/g, '_') - const bucket = indexedByEntity[targetUnderscore] - if (!bucket || bucket.toolbar.length === 0) return null - const pick = bucket.toolbar[0] - try { - const mod = await allPagetypeViews[pick].loader() - return mod?.default ?? mod - } catch (_e) { - return null - } + return resolveOverride(pagetypeSlug, 'toolbar') } /** @@ -178,18 +171,7 @@ export async function resolvePagetypeToolbarOverride(pagetypeSlug: string): Prom * 约定文件名:/src/views/pagetype//_list.vue */ export async function resolvePagetypeListOverride(pagetypeSlug: string): Promise { - if (!pagetypeSlug) return null - const targetHyphen = pagetypeSlug.toLowerCase() - const targetUnderscore = targetHyphen.replace(/-/g, '_') - const bucket = indexedByEntity[targetUnderscore] - if (!bucket || bucket.list.length === 0) return null - const pick = bucket.list[0] - try { - const mod = await allPagetypeViews[pick].loader() - return mod?.default ?? mod - } catch (_e) { - return null - } + return resolveOverride(pagetypeSlug, 'list') } /** @@ -197,18 +179,7 @@ export async function resolvePagetypeListOverride(pagetypeSlug: string): Promise * 约定文件名:/src/views/pagetype//_list_filterbar.vue */ export async function resolvePagetypeListFilterBarOverride(pagetypeSlug: string): Promise { - if (!pagetypeSlug) return null - const targetHyphen = pagetypeSlug.toLowerCase() - const targetUnderscore = targetHyphen.replace(/-/g, '_') - const bucket = indexedByEntity[targetUnderscore] - if (!bucket || bucket.filterbar.length === 0) return null - const pick = bucket.filterbar[0] - try { - const mod = await allPagetypeViews[pick].loader() - return mod?.default ?? mod - } catch (_e) { - return null - } + return resolveOverride(pagetypeSlug, 'filterbar') } /** @@ -216,18 +187,7 @@ export async function resolvePagetypeListFilterBarOverride(pagetypeSlug: string) * 约定文件名:/src/views/pagetype//_list_toolbar.vue */ export async function resolvePagetypeListToolbarOverride(pagetypeSlug: string): Promise { - if (!pagetypeSlug) return null - const targetHyphen = pagetypeSlug.toLowerCase() - const targetUnderscore = targetHyphen.replace(/-/g, '_') - const bucket = indexedByEntity[targetUnderscore] - if (!bucket || bucket.listToolbar.length === 0) return null - const pick = bucket.listToolbar[0] - try { - const mod = await allPagetypeViews[pick].loader() - return mod?.default ?? mod - } catch (_e) { - return null - } + return resolveOverride(pagetypeSlug, 'listToolbar') } /** @@ -235,17 +195,5 @@ export async function resolvePagetypeListToolbarOverride(pagetypeSlug: string): * 约定文件名:/src/views/pagetype//_list_actions.vue */ export async function resolvePagetypeListActionsOverride(pagetypeSlug: string): Promise { - if (!pagetypeSlug) return null - const targetHyphen = pagetypeSlug.toLowerCase() - const targetUnderscore = targetHyphen.replace(/-/g, '_') - const bucket = indexedByEntity[targetUnderscore] - if (!bucket || bucket.actions.length === 0) return null - const pick = bucket.actions[0] - try { - const mod = await allPagetypeViews[pick].loader() - return mod?.default ?? mod - } catch (_e) { - return null - } + return resolveOverride(pagetypeSlug, 'actions') } -