Files
medical-mall/scripts/switch-pages.js
2026-05-19 17:45:27 +08:00

505 lines
14 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 切换 pages.json 到不同端的专属编译模式。
*
* 用法:
* npm run pages:consumer → 仅编译 consumer 相关页面
* npm run pages:merchant → 仅编译 merchant 相关页面
* npm run pages:admin → 仅编译 admin 相关页面
* npm run pages:full → 恢复完整 pages.json
*/
const fs = require("fs");
const path = require("path");
const root = path.resolve(__dirname, "..");
const pagesJson = path.join(root, "pages.json");
const pagesFull = path.join(root, "pages.full.json");
const backupDir = path.join(root, ".pages-backup");
const pagesModeFile = path.join(root, "utils", "pagesMode.uts");
const currentClientFile = path.join(root, "config", "current-client.uts");
const pageExtensions = [".uvue", ".vue", ".nvue"];
const consumerUserPages = [
"pages/user/boot",
"pages/user/login",
"pages/user/register",
"pages/user/forgot-password",
"pages/user/terms",
"pages/user/center",
"pages/user/profile",
"pages/user/change-password",
"pages/user/bind-phone",
"pages/user/bind-email",
];
const merchantUserPages = [
"pages/user/login",
"pages/user/boot",
"pages/user/register",
"pages/user/forgot-password",
"pages/user/terms",
"pages/user/change-password",
];
const adminUserPages = [
"pages/user/login",
"pages/user/boot",
"pages/user/forgot-password",
"pages/user/terms",
"pages/user/change-password",
];
const targetConfigs = {
consumer: {
fileName: "pages.consumer.json",
label: "消费者端",
entryPath: "pages/main/index",
homeRedirect: "/pages/main/index",
tabBarPath: "/pages/main/index",
orderedTopLevelPaths: [
"pages/main/index",
...consumerUserPages,
"pages/main/messages",
"pages/main/cart",
"pages/main/profile",
],
topLevelMatcher(pagePath) {
return (
pagePath.startsWith("pages/main/") ||
consumerUserPages.includes(pagePath)
);
},
subPackageMatcher(rootPath) {
return rootPath === "pages/mall/consumer";
},
tabBarMatcher(pagePath) {
return pagePath.startsWith("pages/main/");
},
defaultCondition() {
return {
current: 0,
list: [
{
name: "consumer端",
path: "pages/main/index",
query: "role=consumer",
},
],
};
},
},
merchant: {
fileName: "pages.merchant.json",
label: "商家端",
entryPath: "pages/user/login",
homeRedirect: "/pages/mall/merchant/index",
tabBarPath: "",
orderedTopLevelPaths: [
"pages/user/login",
"pages/user/boot",
"pages/user/register",
"pages/user/forgot-password",
"pages/user/terms",
"pages/user/change-password",
"pages/mall/merchant/index",
"pages/mall/merchant/messages",
"pages/mall/merchant/orders",
"pages/mall/merchant/growth",
"pages/mall/merchant/profile",
],
topLevelMatcher(pagePath) {
return (
merchantUserPages.includes(pagePath) ||
pagePath.startsWith("pages/mall/merchant/")
);
},
subPackageMatcher() {
return false;
},
defaultCondition() {
return {
current: 0,
list: [
{
name: "merchant端",
path: "pages/mall/merchant/index",
query: "role=merchant",
},
],
};
},
},
admin: {
fileName: "pages.admin.json",
label: "管理后台",
entryPath: "pages/user/login",
homeRedirect: "/pages/mall/admin/homePage/index",
tabBarPath: "",
orderedTopLevelPaths: [
"pages/user/login",
"pages/user/boot",
"pages/user/forgot-password",
"pages/user/terms",
"pages/user/change-password",
"pages/mall/admin/homePage/index",
"pages/mall/admin/userCenter/index",
],
topLevelMatcher(pagePath) {
return (
adminUserPages.includes(pagePath) ||
pagePath === "pages/mall/admin/homePage/index" ||
pagePath === "pages/mall/admin/userCenter/index"
);
},
subPackageMatcher(rootPath) {
return rootPath.startsWith("pages/mall/admin/");
},
defaultCondition() {
return {
current: 0,
list: [
{
name: "admin端",
path: "pages/mall/admin/homePage/index",
query: "role=admin",
},
],
};
},
},
delivery: {
fileName: "pages.delivery.json",
label: "服务人员端/上门服务端",
entryPath: "pages/user/login",
homeRedirect: "/pages/mall/delivery/home/index",
tabBarPath: "/pages/mall/delivery/home/index",
standalone: true,
},
};
const fullModeConfig = {
homeRedirect: "/pages/main/index",
tabBarPath: "/pages/main/index",
};
const mode = process.argv[2]; // 'consumer' | 'merchant' | 'admin' | 'full'
function readJson(filePath) {
const rawContent = fs.readFileSync(filePath, "utf8").replace(/^\uFEFF/, "");
return JSON.parse(rawContent);
}
function writeJson(filePath, content) {
fs.writeFileSync(filePath, `${JSON.stringify(content, null, 2)}\n`, "utf8");
}
function writePagesMode(modeName) {
fs.writeFileSync(
pagesModeFile,
`export const CURRENT_PAGES_MODE = '${modeName}'\n`,
"utf8",
);
}
function writeCurrentClient(modeName) {
fs.mkdirSync(path.dirname(currentClientFile), { recursive: true });
fs.writeFileSync(
currentClientFile,
`export const CURRENT_CLIENT: string = '${modeName}'\n`,
"utf8",
);
console.log(`🔁 已同步当前端标识 → ${modeName}`);
}
function ensureFullBackup() {
if (fs.existsSync(pagesFull)) {
return;
}
fs.copyFileSync(pagesJson, pagesFull);
console.log("📦 已备份 pages.json → pages.full.json");
}
function backupCurrentPages(targetName) {
if (!fs.existsSync(pagesJson)) {
return;
}
fs.mkdirSync(backupDir, { recursive: true });
const timestamp = new Date().toISOString().replace(/[.:]/g, "-");
const backupPath = path.join(
backupDir,
`pages.${targetName}.${timestamp}.json`,
);
fs.copyFileSync(pagesJson, backupPath);
console.log(`📦 已备份当前 pages.json → ${path.relative(root, backupPath)}`);
}
function getPageMap(fullConfig) {
return new Map(fullConfig.pages.map((page) => [page.path, page]));
}
function findMatchingPageFile(routePath) {
for (const extension of pageExtensions) {
const candidate = path.join(root, `${routePath}${extension}`);
if (fs.existsSync(candidate)) {
return candidate;
}
}
return null;
}
function clonePage(page) {
return JSON.parse(JSON.stringify(page));
}
function flattenSubPackagePages(fullConfig, rootPath) {
const targetPackage = fullConfig.subPackages.find(
(item) => item.root === rootPath,
);
if (!targetPackage) {
return [];
}
return targetPackage.pages.map((page) => ({
path: `${rootPath}/${page.path}`,
style: page.style ? JSON.parse(JSON.stringify(page.style)) : {},
}));
}
function getTopLevelPages(fullConfig, targetConfig) {
const pageMap = getPageMap(fullConfig);
const matchedFromTopLevel = fullConfig.pages
.filter((page) => targetConfig.topLevelMatcher(page.path))
.map((page) => clonePage(page));
const flattenedPages = (targetConfig.flattenRoots || []).flatMap((rootPath) =>
flattenSubPackagePages(fullConfig, rootPath),
);
const mergedMap = new Map();
for (const page of [...matchedFromTopLevel, ...flattenedPages]) {
mergedMap.set(page.path, page);
}
const orderedPages = [];
for (const pagePath of targetConfig.orderedTopLevelPaths) {
if (mergedMap.has(pagePath)) {
orderedPages.push(mergedMap.get(pagePath));
mergedMap.delete(pagePath);
} else if (pageMap.has(pagePath)) {
orderedPages.push(clonePage(pageMap.get(pagePath)));
}
}
for (const page of [...matchedFromTopLevel, ...flattenedPages]) {
if (mergedMap.has(page.path)) {
orderedPages.push(mergedMap.get(page.path));
mergedMap.delete(page.path);
}
}
return dedupePages(orderedPages);
}
function getSubPackages(fullConfig, targetConfig) {
return fullConfig.subPackages
.filter((item) => targetConfig.subPackageMatcher(item.root))
.map((item) => JSON.parse(JSON.stringify(item)));
}
function dedupePages(pages) {
const seen = new Set();
return pages.filter((page) => {
if (seen.has(page.path)) {
return false;
}
seen.add(page.path);
return true;
});
}
function getCondition(targetConfig, sourceCondition) {
if (sourceCondition && Array.isArray(sourceCondition.list)) {
const filteredList = sourceCondition.list.filter(
(item) => item.path === targetConfig.entryPath,
);
if (filteredList.length > 0) {
return {
current: 0,
list: filteredList,
};
}
}
return targetConfig.defaultCondition();
}
function validateGeneratedConfig(targetName, config) {
const missingRoutes = [];
const routeSet = new Set();
for (const page of config.pages || []) {
routeSet.add(page.path);
if (!findMatchingPageFile(page.path)) {
missingRoutes.push(page.path);
}
}
for (const subPackage of config.subPackages || []) {
for (const page of subPackage.pages || []) {
const fullPath = `${subPackage.root}/${page.path}`;
routeSet.add(fullPath);
if (!findMatchingPageFile(fullPath)) {
missingRoutes.push(fullPath);
}
}
}
for (const tabItem of config.tabBar?.list || []) {
if (!routeSet.has(tabItem.pagePath)) {
missingRoutes.push(`tabBar -> ${tabItem.pagePath}`);
}
}
for (const conditionItem of config.condition?.list || []) {
if (!routeSet.has(conditionItem.path)) {
missingRoutes.push(`condition -> ${conditionItem.path}`);
}
}
if (missingRoutes.length > 0) {
console.error(`${targetName} 配置存在无效页面引用:`);
for (const routePath of missingRoutes) {
console.error(` - ${routePath}`);
}
process.exit(1);
}
}
function buildTargetConfig(fullConfig, targetName, sourceCondition) {
const targetConfig = targetConfigs[targetName];
const nextConfig = {};
nextConfig.pages = getTopLevelPages(fullConfig, targetConfig);
nextConfig.subPackages = getSubPackages(fullConfig, targetConfig);
if (targetConfig.tabBarMatcher) {
const filteredTabBarList = (fullConfig.tabBar?.list || []).filter((item) =>
targetConfig.tabBarMatcher(item.pagePath),
);
if (filteredTabBarList.length > 0 && fullConfig.tabBar) {
nextConfig.tabBar = {
...JSON.parse(JSON.stringify(fullConfig.tabBar)),
list: filteredTabBarList,
};
}
}
for (const key of Object.keys(fullConfig)) {
if (["pages", "subPackages", "tabBar", "condition"].includes(key)) {
continue;
}
nextConfig[key] = JSON.parse(JSON.stringify(fullConfig[key]));
}
nextConfig.condition = getCondition(targetConfig, sourceCondition);
validateGeneratedConfig(targetName, nextConfig);
return nextConfig;
}
function writeTargetConfig(targetName, config) {
const targetPath = path.join(root, targetConfigs[targetName].fileName);
writeJson(targetPath, config);
fs.copyFileSync(targetPath, pagesJson);
writePagesMode(targetName);
writeCurrentClient(targetName);
const pageCount = config.pages.length;
const subPackageCount = config.subPackages.length;
const tabBarCount = config.tabBar?.list?.length || 0;
console.log(`✅ 已切换为【${targetConfigs[targetName].label}专属编译模式】`);
console.log(` 目标配置:${targetConfigs[targetName].fileName}`);
console.log(` pages${pageCount}`);
console.log(` subPackages${subPackageCount}`);
console.log(` tabBar${tabBarCount}`);
console.log(" 恢复完整版本npm run pages:full");
}
function switchStandaloneConfig(targetName) {
const targetPath = path.join(root, targetConfigs[targetName].fileName);
if (!fs.existsSync(targetPath)) {
console.error(`${targetConfigs[targetName].fileName} 不存在。`);
process.exit(1);
}
const config = readJson(targetPath);
validateGeneratedConfig(targetName, config);
fs.copyFileSync(targetPath, pagesJson);
writePagesMode(targetName);
writeCurrentClient(targetName);
const pageCount = config.pages != null ? config.pages.length : 0;
const subPackageCount =
config.subPackages != null ? config.subPackages.length : 0;
const tabBarCount =
config.tabBar != null && Array.isArray(config.tabBar.list)
? config.tabBar.list.length
: 0;
console.log(`✅ 已切换为【${targetConfigs[targetName].label}专属编译模式】`);
console.log(` 目标配置:${targetConfigs[targetName].fileName}`);
console.log(` pages${pageCount}`);
console.log(` subPackages${subPackageCount}`);
console.log(` tabBar${tabBarCount}`);
console.log(" 恢复完整版本npm run pages:full");
}
function restoreFullPages() {
if (!fs.existsSync(pagesFull)) {
console.error("❌ pages.full.json 不存在。");
console.error(" 可能当前已经是完整模式,或备份文件已被删除。");
process.exit(1);
}
backupCurrentPages("full");
fs.copyFileSync(pagesFull, pagesJson);
writePagesMode("full");
writeCurrentClient("full");
console.log("✅ 已恢复【完整 pages.json】");
console.log(" 包含 consumer + merchant + admin 全部页面。");
}
if (mode === "full") {
restoreFullPages();
} else if (Object.prototype.hasOwnProperty.call(targetConfigs, mode)) {
ensureFullBackup();
backupCurrentPages(mode);
if (targetConfigs[mode].standalone === true) {
switchStandaloneConfig(mode);
process.exit(0);
}
const fullConfig = readJson(pagesFull);
const sourceCondition = fs.existsSync(pagesJson)
? (() => {
try {
return readJson(pagesJson).condition;
} catch (error) {
return null;
}
})()
: null;
const nextConfig = buildTargetConfig(fullConfig, mode, sourceCondition);
writeTargetConfig(mode, nextConfig);
} else {
console.log("用法:");
console.log(" npm run pages:consumer 切换到消费者端专属编译模式");
console.log(" npm run pages:delivery 切换到服务人员端专属编译模式");
console.log(" npm run pages:merchant 切换到商家端专属编译模式");
console.log(" npm run pages:admin 切换到管理后台专属编译模式");
console.log(" npm run pages:full 恢复完整编译模式");
}