@10yun/cv-mobile-ui 0.5.46 → 0.5.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/common_func.js +127 -0
- package/build/parse-create.js +72 -0
- package/build/parse-pages-pkg.js +288 -0
- package/build/parse-rbac.js +67 -0
- package/package.json +1 -1
- package/uview-plus/components/u-pdf-reader/style.css +2 -0
- package/uview-plus/components/u-table2/style.css +90 -0
- package/uview-plus/components/u-virtual-list/style.css +16 -0
- package/build/parse-pages.js +0 -127
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
// ---------------------- 蓝色输出工具函数(封装开始)----------------------
|
|
3
|
+
/**
|
|
4
|
+
* 原生蓝色文本输出工具
|
|
5
|
+
* @param {string} text - 要输出的文本
|
|
6
|
+
* @param {Object} options - 样式配置(可选)
|
|
7
|
+
* @param {boolean} options.bold - 是否加粗(默认 false)
|
|
8
|
+
* @param {boolean} options.bg - 是否蓝底白字(默认 false)
|
|
9
|
+
* @returns {string} 带蓝色样式的文本(含 ANSI 转义序列)
|
|
10
|
+
*/
|
|
11
|
+
function blueLog(text, options = {}) {
|
|
12
|
+
const { bold = false, bg = false } = options;
|
|
13
|
+
let styleCode = [];
|
|
14
|
+
|
|
15
|
+
// 基础样式:加粗(可选)
|
|
16
|
+
if (bold) styleCode.push(1);
|
|
17
|
+
|
|
18
|
+
// 颜色样式:前景色蓝色 / 背景色蓝色(二选一)
|
|
19
|
+
if (bg) {
|
|
20
|
+
styleCode.push(44); // 蓝色背景
|
|
21
|
+
styleCode.push(37); // 白色文本(搭配蓝色背景更清晰)
|
|
22
|
+
} else {
|
|
23
|
+
styleCode.push(34); // 蓝色前景色(文本本身蓝色)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 拼接 ANSI 序列:起始符 + 样式码 + 文本 + 重置符
|
|
27
|
+
return `\x1B[${styleCode.join(';')}m${text}\x1B[0m`;
|
|
28
|
+
}
|
|
29
|
+
// 过滤JSON注释
|
|
30
|
+
export function filter_comments(jsonString) {
|
|
31
|
+
// 过滤多行注释
|
|
32
|
+
jsonString = jsonString.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
33
|
+
// return jsonString.replace(/\/\/[^\n]*\n/g, ''); // 过滤单行注释
|
|
34
|
+
|
|
35
|
+
// 再处理单行注释,确保//不在引号内
|
|
36
|
+
jsonString = jsonString.replace(/(?:"[^"]*"|'[^']*')|\/\/.*/g, (match) => {
|
|
37
|
+
// 如果是字符串,则返回原内容,否则返回空(移除注释)
|
|
38
|
+
return match.startsWith('"') || match.startsWith("'") ? match : '';
|
|
39
|
+
});
|
|
40
|
+
// 清理多余的空白和空行
|
|
41
|
+
return jsonString.replace(/\s+/g, ' ').replace(/\s*,\s*/g, ', ');
|
|
42
|
+
console.log(content);
|
|
43
|
+
throw new Error('asda');
|
|
44
|
+
return jsonString.replace(/\/\/[\s\S]*?(\r\n|\n)/g, '');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 安全读取和解析JSON
|
|
48
|
+
export async function fs_read_json_file(filePath, isFilter = true) {
|
|
49
|
+
try {
|
|
50
|
+
const isExists = await fs_file_exists(filePath);
|
|
51
|
+
if (!isExists) {
|
|
52
|
+
throw new Error(' 不存在 ');
|
|
53
|
+
}
|
|
54
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
55
|
+
if (isFilter) {
|
|
56
|
+
return JSON.parse(filter_comments(content));
|
|
57
|
+
}
|
|
58
|
+
return JSON.parse(content);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.log(blueLog(`读取文件失败: ${filePath}`), error);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function fs_read_file(filePath, isFilter = true) {
|
|
66
|
+
try {
|
|
67
|
+
const isExists = await fs_file_exists(filePath);
|
|
68
|
+
if (!isExists) {
|
|
69
|
+
throw new Error(' 不存在 ');
|
|
70
|
+
}
|
|
71
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
72
|
+
if (isFilter) {
|
|
73
|
+
return filter_comments(content);
|
|
74
|
+
}
|
|
75
|
+
return content;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.log(blueLog(`读取文件失败: ${filePath}`), error);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 检查文件是否存在
|
|
83
|
+
export async function fs_file_exists(filePath) {
|
|
84
|
+
try {
|
|
85
|
+
await fs.access(filePath);
|
|
86
|
+
return true;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// 创建目录(如果不存在)
|
|
92
|
+
export async function fs_mkdir_dir(dirPath) {
|
|
93
|
+
try {
|
|
94
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.log(blueLog(`创建目录失败: ${dirPath}`), error);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function fs_write_file(fileDir, filePath, content) {
|
|
102
|
+
try {
|
|
103
|
+
await fs_mkdir_dir(fileDir);
|
|
104
|
+
await fs.writeFile(filePath, content, 'utf-8');
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.log(blueLog(`写入内容失败: ${filePath}`), error);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function getCurrDate() {
|
|
112
|
+
// 创建一个 Date 对象,表示当前时间
|
|
113
|
+
const now = new Date();
|
|
114
|
+
|
|
115
|
+
// 获取时间的各个组成部分
|
|
116
|
+
const year = now.getFullYear();
|
|
117
|
+
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1
|
|
118
|
+
const day = String(now.getDate()).padStart(2, '0');
|
|
119
|
+
const hours = String(now.getHours()).padStart(2, '0');
|
|
120
|
+
const minutes = String(now.getMinutes()).padStart(2, '0');
|
|
121
|
+
const seconds = String(now.getSeconds()).padStart(2, '0');
|
|
122
|
+
|
|
123
|
+
// 格式化为常见的字符串形式
|
|
124
|
+
const formattedTime1 = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; // 如 2025-09-07 10:00:00
|
|
125
|
+
const formattedTime2 = `${year}年${month}月${day}日 ${hours}:${minutes}:${seconds}`; // 如 2025年09月07日 10:00:00
|
|
126
|
+
return formattedTime1;
|
|
127
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// 生成menu.js内容
|
|
2
|
+
/**
|
|
3
|
+
* 解析
|
|
4
|
+
*/
|
|
5
|
+
export async function parseMenuContent(data) {
|
|
6
|
+
//let content = 'export default ' + JSON.stringify(diyPlus);
|
|
7
|
+
//let content = 'export default ' + JSON.stringify(diyPlus, null, 2);
|
|
8
|
+
const entries = Object.entries(data);
|
|
9
|
+
let content = 'export default {\n';
|
|
10
|
+
for (let i = 0; i < entries.length; i++) {
|
|
11
|
+
const [key, value] = entries[i];
|
|
12
|
+
|
|
13
|
+
// 处理 value,手动转成类似 JSON 但键名无引号、字符串用单引号的格式
|
|
14
|
+
let formattedValue = '{ ';
|
|
15
|
+
const valueEntries = Object.entries(value);
|
|
16
|
+
for (let j = 0; j < valueEntries.length; j++) {
|
|
17
|
+
const [subKey, subVal] = valueEntries[j];
|
|
18
|
+
formattedValue += `${subKey}: `;
|
|
19
|
+
|
|
20
|
+
if (typeof subVal === 'string') {
|
|
21
|
+
formattedValue += `'${subVal}'`; // 字符串值用单引号
|
|
22
|
+
} else {
|
|
23
|
+
formattedValue += subVal; // 非字符串直接输出
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (j < valueEntries.length - 1) {
|
|
27
|
+
formattedValue += ', '; // 非最后一个属性加逗号
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
formattedValue += ' }';
|
|
31
|
+
|
|
32
|
+
// 拼接当前行的内容
|
|
33
|
+
content += ` ${key}: ${formattedValue}`;
|
|
34
|
+
|
|
35
|
+
// 如果不是最后一个元素,加逗号换行
|
|
36
|
+
if (i < entries.length - 1) {
|
|
37
|
+
content += ',\n';
|
|
38
|
+
} else {
|
|
39
|
+
content += '\n'; // 最后一行不加逗号,只换行
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
content += '};\n';
|
|
43
|
+
return content;
|
|
44
|
+
}
|
|
45
|
+
export async function parseConfigContent(configs) {
|
|
46
|
+
// 构建要生成的JS内容
|
|
47
|
+
let jsContent = `const lastConfigEnv = import.meta.env;
|
|
48
|
+
// 本地测试接口 ,线上接口
|
|
49
|
+
const isOnline = lastConfigEnv.NODE_ENV === 'development' ? false : true;
|
|
50
|
+
// lastConfigEnv.NODE_ENV === 'production',
|
|
51
|
+
export default {
|
|
52
|
+
...lastConfigEnv,
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
// 添加CONFIGS中的配置项
|
|
56
|
+
Object.entries(configs).forEach(([key, value], index) => {
|
|
57
|
+
// 处理值为对象的情况
|
|
58
|
+
const isObject = typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
59
|
+
const valueStr = isObject ? JSON.stringify(value, null, 2) : typeof value === 'string' ? `"${value}"` : value;
|
|
60
|
+
|
|
61
|
+
jsContent += ` ${key}: ${valueStr}`;
|
|
62
|
+
|
|
63
|
+
// 添加逗号(最后一项不添加)
|
|
64
|
+
if (index < Object.entries(configs).length - 1) {
|
|
65
|
+
jsContent += ',';
|
|
66
|
+
}
|
|
67
|
+
jsContent += '\n';
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
jsContent += '};\n';
|
|
71
|
+
return jsContent;
|
|
72
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 文件操作报错参考
|
|
3
|
+
* https://www.cnblogs.com/Megasu/p/16635566.html
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'node:fs/promises';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { dirname, join as path_join } from 'node:path';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
// import { glob } from 'glob';
|
|
10
|
+
import pkg from 'glob';
|
|
11
|
+
const { glob } = pkg;
|
|
12
|
+
import { exec } from 'node:child_process';
|
|
13
|
+
// 获取 __filename 的 ESM 写法
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
// 获取 __dirname 的 ESM 写法
|
|
16
|
+
const __dirname = dirname(__filename);
|
|
17
|
+
|
|
18
|
+
// 参数:可能是 "plus" 或 配置文件路径
|
|
19
|
+
const argv = process.argv[2] || '';
|
|
20
|
+
console.log('---argv---', argv);
|
|
21
|
+
|
|
22
|
+
const TEMPLATE_PATH = path_join(__dirname, 'themp.vue');
|
|
23
|
+
const PROJECT_PATH = process.cwd();
|
|
24
|
+
const PROJECT_SRC = path_join(PROJECT_PATH, 'src');
|
|
25
|
+
const PAGES_JSON_PATH = path_join(PROJECT_SRC, 'pages.json');
|
|
26
|
+
const MENU_JS_PATH = path_join(PROJECT_SRC, 'router/menu.js');
|
|
27
|
+
const APP_CONFIG_PATH = path_join(PROJECT_SRC, 'app-config.js');
|
|
28
|
+
const RBAC_JSON_PATH = path_join(PROJECT_PATH, 'public/rbac.json');
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 工具函数
|
|
32
|
+
*/
|
|
33
|
+
import { fs_read_file, fs_read_json_file, fs_mkdir_dir, fs_write_file, fs_file_exists, getCurrDate } from './common_func.js';
|
|
34
|
+
|
|
35
|
+
import { parseMenuContent, parseConfigContent } from './parse-create.js';
|
|
36
|
+
/**
|
|
37
|
+
* 初始化模板
|
|
38
|
+
*/
|
|
39
|
+
let templateData = (await fs_read_file(TEMPLATE_PATH, false)) || '';
|
|
40
|
+
|
|
41
|
+
function console_need_log(msg, filePath) {
|
|
42
|
+
let fileNeedPath = filePath.replace(PROJECT_PATH, '');
|
|
43
|
+
console.log(msg, fileNeedPath);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 遍历配置并新建文件
|
|
48
|
+
*/
|
|
49
|
+
async function ergodic(data, pageKey = 'pagePath', root = '') {
|
|
50
|
+
for (const item of data) {
|
|
51
|
+
const pagePath = root + item[pageKey];
|
|
52
|
+
await createVueFile(pagePath);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 新建页面文件
|
|
57
|
+
*/
|
|
58
|
+
async function createVueFile(pagePath) {
|
|
59
|
+
const absPath = path_join(PROJECT_SRC, `${pagePath}.vue`);
|
|
60
|
+
if (!(await fs_file_exists(absPath))) {
|
|
61
|
+
await fs.mkdir(dirname(absPath), { recursive: true });
|
|
62
|
+
// await fs_mkdir_dir(path.dirname(absPath));
|
|
63
|
+
|
|
64
|
+
const content = templateData.replace(/<!-- path -->/g, `<text>${pagePath}</text>`);
|
|
65
|
+
// const content = templateData.replace(/\<!-- path --\>/g, `<text>${pagePath}</text>`);
|
|
66
|
+
await fs.writeFile(absPath, content, 'utf-8');
|
|
67
|
+
console_need_log('【新建文件】', absPath);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 抽取 meta 到 menu.js
|
|
73
|
+
*/
|
|
74
|
+
async function info_parse_data(pages) {
|
|
75
|
+
console.log('【菜单配置】解析meta信息');
|
|
76
|
+
let diyPlus = {};
|
|
77
|
+
|
|
78
|
+
// 遍历主包配置
|
|
79
|
+
for (const pageInfo of pages.pages) {
|
|
80
|
+
// 处理主包meta
|
|
81
|
+
if (pageInfo.meta) {
|
|
82
|
+
const key = pageInfo.path.replace(/\//g, '_');
|
|
83
|
+
diyPlus[key] = pageInfo.meta;
|
|
84
|
+
delete pageInfo.meta;
|
|
85
|
+
// console.log('【抽取meta】', pageInfo.path, '->', key);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//遍历分包
|
|
90
|
+
for (const subInfo of pages.subPackages) {
|
|
91
|
+
for (const pageInfo of subInfo.pages) {
|
|
92
|
+
// 处理分包meta
|
|
93
|
+
if (pageInfo.meta) {
|
|
94
|
+
const fullPath = subInfo.root + pageInfo.path;
|
|
95
|
+
//const fullPath = `${subInfo.root}/${pageInfo.path}`;
|
|
96
|
+
const key = fullPath.replace(/\//g, '_');
|
|
97
|
+
diyPlus[key] = pageInfo.meta;
|
|
98
|
+
delete pageInfo.meta;
|
|
99
|
+
// console.log('【抽取meta】', fullPath, '->', key);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// 生成 menu.js
|
|
104
|
+
const menuContent = await parseMenuContent(diyPlus);
|
|
105
|
+
await fs_write_file(path.dirname(MENU_JS_PATH), MENU_JS_PATH, menuContent);
|
|
106
|
+
console_need_log('【更新文件】', MENU_JS_PATH);
|
|
107
|
+
|
|
108
|
+
// 生成 rbac.json
|
|
109
|
+
|
|
110
|
+
return pages;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function info_parse_rbac(data) {
|
|
114
|
+
// let menuDiyPlus = 'export default ' + JSON.stringify(rbacAll);
|
|
115
|
+
// await fs.writeFile(projectSrc + '/router/menu.js', menuDiyPlus);
|
|
116
|
+
// await fs.writeFile(projectPath + '/public/rbac.json', JSON.stringify(rbacAll, '', 2));
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 解析主包中path路径是否携带全路径
|
|
120
|
+
* @param {*} oldArr
|
|
121
|
+
*/
|
|
122
|
+
function info_parse_path(dirPath, oldArr) {
|
|
123
|
+
let newArr = [];
|
|
124
|
+
for (let i in oldArr) {
|
|
125
|
+
let oldItem = oldArr[i];
|
|
126
|
+
if (oldItem.path.includes('src') || oldItem.path.includes(dirPath)) {
|
|
127
|
+
} else {
|
|
128
|
+
oldItem.path = dirPath + '/' + oldItem.path;
|
|
129
|
+
}
|
|
130
|
+
newArr.push(oldItem);
|
|
131
|
+
}
|
|
132
|
+
return newArr;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/*
|
|
136
|
+
* pages.json
|
|
137
|
+
* 用户 pages 分布式配置,分别为三类配置 mian、sub、common
|
|
138
|
+
* *-main 为主包所有路径配置
|
|
139
|
+
* *-sub 为当前分包所有路径配置
|
|
140
|
+
* *-common 为globalStyle、tabBar和easycom的配置
|
|
141
|
+
* 已实现空路径自动创建vue文件,模板文件:./themp.vue
|
|
142
|
+
* 内置命令 npm run pages
|
|
143
|
+
*/
|
|
144
|
+
/**
|
|
145
|
+
* 主流程
|
|
146
|
+
* 主执行函数
|
|
147
|
+
*/
|
|
148
|
+
async function main() {
|
|
149
|
+
let targetModules = null;
|
|
150
|
+
// 如果 argv 是配置文件路径
|
|
151
|
+
// 判断是否传入配置文件
|
|
152
|
+
if (argv && argv.endsWith('.json')) {
|
|
153
|
+
const moduleJsonPage = path_join(PROJECT_PATH, argv);
|
|
154
|
+
const config = await fs_read_json_file(moduleJsonPage, true);
|
|
155
|
+
targetModules = config.modules || [];
|
|
156
|
+
console.log('【启用定向模块模式】读取项目配置成功', targetModules);
|
|
157
|
+
// 生成 app-config.js
|
|
158
|
+
if (!config.CONFIGS) {
|
|
159
|
+
throw new Error(' json下的 config 内容不存在');
|
|
160
|
+
}
|
|
161
|
+
const configContent = await parseConfigContent(config.CONFIGS);
|
|
162
|
+
await fs_write_file(path.dirname(APP_CONFIG_PATH), APP_CONFIG_PATH, configContent);
|
|
163
|
+
console_need_log('【更新文件】', APP_CONFIG_PATH);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 生成 app-config.js 内容
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
let commonData = {};
|
|
170
|
+
let mainData = [];
|
|
171
|
+
let subData = [];
|
|
172
|
+
|
|
173
|
+
// 要扫描的路径,扫描目录
|
|
174
|
+
let scanDirs;
|
|
175
|
+
if (targetModules) {
|
|
176
|
+
// 只扫描指定模块
|
|
177
|
+
scanDirs = targetModules.map((m) => path_join(PROJECT_SRC, 'pages', m));
|
|
178
|
+
} else {
|
|
179
|
+
// 默认全量扫描
|
|
180
|
+
// scanDirs = [path_join(PROJECT_SRC, 'pages')];
|
|
181
|
+
scanDirs = glob.sync(path_join(PROJECT_SRC, 'pages/*'));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 遍历扫描
|
|
185
|
+
for (const dir of scanDirs) {
|
|
186
|
+
const dirPath = dir.replace(PROJECT_PATH, '').replace('/src/', '');
|
|
187
|
+
|
|
188
|
+
for (const file of glob.sync(path_join(dir, '*-common.json'))) {
|
|
189
|
+
console_need_log('【主要配置】', file);
|
|
190
|
+
const temp = await fs_read_json_file(file);
|
|
191
|
+
Object.assign(commonData, temp);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// main
|
|
195
|
+
for (const file of glob.sync(path_join(dir, '*-main.json'))) {
|
|
196
|
+
console_need_log('【主包配置】', file);
|
|
197
|
+
let temp = await fs_read_json_file(file);
|
|
198
|
+
temp = info_parse_path(dirPath, temp);
|
|
199
|
+
mainData = mainData.concat(temp);
|
|
200
|
+
|
|
201
|
+
// let temp_rbac = parseRbacMenu(temp);
|
|
202
|
+
// rbacAll.push(...temp_rbac);
|
|
203
|
+
|
|
204
|
+
// let temp_parse = parseCommonMenu(temp);
|
|
205
|
+
// pages_main_data = pages_main_data.concat(temp_parse);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// sub
|
|
209
|
+
for (const file of glob.sync(path_join(dir, '*-sub.json'))) {
|
|
210
|
+
console_need_log('【分包配置】', file);
|
|
211
|
+
const root = file.match(/pages\/([^/]+)\//)?.[0] || '';
|
|
212
|
+
// if (!root) continue;
|
|
213
|
+
// let root = fileName.match(/pages\/(\S*)\//)[0];
|
|
214
|
+
const temp = await fs_read_json_file(file);
|
|
215
|
+
|
|
216
|
+
// 处理分包中的页面文件创建
|
|
217
|
+
await ergodic(temp, 'path', root);
|
|
218
|
+
|
|
219
|
+
// let temp_rbac = parseRbacMenu(temp, root);
|
|
220
|
+
// rbacAll.push(...temp_rbac);
|
|
221
|
+
// let temp_parse = parseCommonMenu(temp, root);
|
|
222
|
+
|
|
223
|
+
subData.push({
|
|
224
|
+
root: root,
|
|
225
|
+
// root: root.replace(/\/$/, ''), // 移除末尾斜杠
|
|
226
|
+
pages: temp
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
console.log('【主要配置】 - 读取完毕');
|
|
231
|
+
console.log('【主包配置】 - 读取完毕');
|
|
232
|
+
console.log('【分包配置】 - 读取完毕');
|
|
233
|
+
// throw new Error('');
|
|
234
|
+
|
|
235
|
+
if (!commonData.tabBar) {
|
|
236
|
+
console.error('【error】tabBar 配置不存在,请检查配置');
|
|
237
|
+
throw new Error('主要配置文件不正确(tabBar配置不存在),请检查修改配置后重试');
|
|
238
|
+
}
|
|
239
|
+
// 读取并处理配置
|
|
240
|
+
// 处理通用配置中的页面文件创建
|
|
241
|
+
await ergodic(commonData.tabBar.list);
|
|
242
|
+
|
|
243
|
+
// 处理主包页面文件创建
|
|
244
|
+
await ergodic(mainData, 'path');
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* 整理页面配置
|
|
248
|
+
*/
|
|
249
|
+
// 以tabBar第一条为首页
|
|
250
|
+
// 排序首页,首页置顶
|
|
251
|
+
const firstPath = commonData.tabBar?.list[0]?.pagePath;
|
|
252
|
+
if (firstPath) {
|
|
253
|
+
const firstIndex = mainData.findIndex((p) => p.path === firstPath);
|
|
254
|
+
if (firstIndex > 0) {
|
|
255
|
+
const [firstPage] = mainData.splice(firstIndex, 1);
|
|
256
|
+
mainData.unshift(firstPage);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 拼装生成 pages.json
|
|
261
|
+
let pages = {
|
|
262
|
+
pages: mainData,
|
|
263
|
+
subPackages: subData,
|
|
264
|
+
//用于设置应用的状态栏、导航条、标题、窗口背景色等。
|
|
265
|
+
globalStyle: commonData.globalStyle,
|
|
266
|
+
tabBar: commonData.tabBar,
|
|
267
|
+
easycom: commonData.easycom,
|
|
268
|
+
//分包预载配置。
|
|
269
|
+
preloadRule: commonData.preloadRule,
|
|
270
|
+
//启动模式配置,仅开发期间生效,用于模拟直达页面的场景,如:小程序转发后,用户点击所打开的页面。
|
|
271
|
+
condition: commonData.condition
|
|
272
|
+
};
|
|
273
|
+
// 抽取meta信息(如果启用plus模式)
|
|
274
|
+
pages = await info_parse_data(pages);
|
|
275
|
+
// console.log('---pages', PAGES_JSON_PATH, pages);
|
|
276
|
+
|
|
277
|
+
// 写入pages.json
|
|
278
|
+
await fs.writeFile(PAGES_JSON_PATH, JSON.stringify(pages, '', 2));
|
|
279
|
+
// await fs.writeFile(PAGES_JSON_PATH, JSON.stringify(pages, null, 2));
|
|
280
|
+
|
|
281
|
+
console.log('【更新完毕】', getCurrDate());
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// 执行主函数
|
|
285
|
+
main().catch((err) => {
|
|
286
|
+
console.error(err);
|
|
287
|
+
process.exit(1);
|
|
288
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
var pages_already = {};
|
|
2
|
+
// 用于存放 rbac 配置
|
|
3
|
+
var rbacAll = [];
|
|
4
|
+
|
|
5
|
+
function parseCommonMenu(menuArr, root) {
|
|
6
|
+
root = root || '';
|
|
7
|
+
let newArr = [];
|
|
8
|
+
for (let i in menuArr) {
|
|
9
|
+
let menuItem = menuArr[i];
|
|
10
|
+
if (menuItem.path) {
|
|
11
|
+
if (root) {
|
|
12
|
+
// 是否重复注册
|
|
13
|
+
if (pages_already[root + menuItem.path]) {
|
|
14
|
+
continue;
|
|
15
|
+
} else {
|
|
16
|
+
pages_already[root + menuItem.path] = 1;
|
|
17
|
+
}
|
|
18
|
+
// console.log(pages_already[root + menuItem.path]);
|
|
19
|
+
}
|
|
20
|
+
delete menuArr[i].isMenu;
|
|
21
|
+
delete menuArr[i].isRbac;
|
|
22
|
+
delete menuArr[i].meta;
|
|
23
|
+
|
|
24
|
+
if (menuItem.children) {
|
|
25
|
+
let childrenArr = menuItem.children;
|
|
26
|
+
delete menuArr[i].children;
|
|
27
|
+
newArr.push(menuItem);
|
|
28
|
+
let newArr2 = parseCommonMenu(childrenArr, root);
|
|
29
|
+
newArr.push(...newArr2);
|
|
30
|
+
} else {
|
|
31
|
+
newArr.push(menuItem);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return newArr;
|
|
36
|
+
}
|
|
37
|
+
function parseRbacMenu(menuArr, root) {
|
|
38
|
+
root = root || '';
|
|
39
|
+
let newArr = [];
|
|
40
|
+
for (let i in menuArr) {
|
|
41
|
+
let menuItem = menuArr[i];
|
|
42
|
+
if (menuItem.path) {
|
|
43
|
+
let newPath = root + menuItem.path;
|
|
44
|
+
newPath = newPath.replace(/pages/g, '');
|
|
45
|
+
if (menuItem.children) {
|
|
46
|
+
let childrenArr = menuItem.children;
|
|
47
|
+
|
|
48
|
+
let newArr2 = parseRbacMenu(childrenArr, root);
|
|
49
|
+
let newItem = {
|
|
50
|
+
...menuItem,
|
|
51
|
+
path: newPath,
|
|
52
|
+
children: newArr2
|
|
53
|
+
};
|
|
54
|
+
delete newItem.style;
|
|
55
|
+
newArr.push(newItem);
|
|
56
|
+
} else {
|
|
57
|
+
let newItem = {
|
|
58
|
+
...menuItem,
|
|
59
|
+
path: newPath
|
|
60
|
+
};
|
|
61
|
+
delete newItem.style;
|
|
62
|
+
newArr.push(newItem);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return newArr;
|
|
67
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
.u-table2 {
|
|
2
|
+
width: auto;
|
|
3
|
+
overflow: auto;
|
|
4
|
+
white-space: nowrap;
|
|
5
|
+
position: relative;
|
|
6
|
+
}
|
|
7
|
+
.u-table2 .u-table-header {
|
|
8
|
+
min-width: 100% !important;
|
|
9
|
+
width: fit-content;
|
|
10
|
+
background-color: #f5f7fa;
|
|
11
|
+
}
|
|
12
|
+
.u-table2 .u-table-body {
|
|
13
|
+
min-width: 100% !important;
|
|
14
|
+
width: fit-content;
|
|
15
|
+
position: relative;
|
|
16
|
+
}
|
|
17
|
+
.u-table2 .u-table-sticky {
|
|
18
|
+
position: sticky;
|
|
19
|
+
top: 0;
|
|
20
|
+
z-index: 10;
|
|
21
|
+
}
|
|
22
|
+
.u-table2 .u-table-row {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: row;
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
position: relative;
|
|
27
|
+
}
|
|
28
|
+
.u-table2.u-table-border {
|
|
29
|
+
border-top: 1px solid #ebeef5;
|
|
30
|
+
border-left: 1px solid #ebeef5;
|
|
31
|
+
border-right: 1px solid #ebeef5;
|
|
32
|
+
}
|
|
33
|
+
.u-table2.u-table-border .u-table-cell {
|
|
34
|
+
border-right: 1px solid #ebeef5;
|
|
35
|
+
}
|
|
36
|
+
.u-table2.u-table-border .u-table-cell:last-child {
|
|
37
|
+
border-right: none;
|
|
38
|
+
}
|
|
39
|
+
.u-table2 .u-table-cell {
|
|
40
|
+
flex: 1;
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: row;
|
|
43
|
+
align-items: center;
|
|
44
|
+
padding: 10px 1px;
|
|
45
|
+
font-size: 14px;
|
|
46
|
+
white-space: nowrap;
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
text-overflow: ellipsis;
|
|
49
|
+
line-height: 1.1;
|
|
50
|
+
border-bottom: 1px solid #ebeef5;
|
|
51
|
+
}
|
|
52
|
+
.u-table2 .u-table-cell.u-text-left {
|
|
53
|
+
justify-content: flex-start;
|
|
54
|
+
text-align: left;
|
|
55
|
+
}
|
|
56
|
+
.u-table2 .u-table-cell.u-text-center {
|
|
57
|
+
justify-content: center;
|
|
58
|
+
text-align: center;
|
|
59
|
+
}
|
|
60
|
+
.u-table2 .u-table-cell.u-text-right {
|
|
61
|
+
justify-content: flex-end;
|
|
62
|
+
text-align: right;
|
|
63
|
+
}
|
|
64
|
+
.u-table2 .u-table-row-zebra {
|
|
65
|
+
background-color: #fafafa;
|
|
66
|
+
}
|
|
67
|
+
.u-table2 .u-table-row-highlight {
|
|
68
|
+
background-color: #f5f7fa;
|
|
69
|
+
}
|
|
70
|
+
.u-table2 .u-table-empty {
|
|
71
|
+
text-align: center;
|
|
72
|
+
padding: 20px;
|
|
73
|
+
color: #999;
|
|
74
|
+
}
|
|
75
|
+
.u-table-fixed-shadow {
|
|
76
|
+
position: absolute;
|
|
77
|
+
top: 0;
|
|
78
|
+
left: 0;
|
|
79
|
+
width: auto;
|
|
80
|
+
z-index: 20;
|
|
81
|
+
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.15);
|
|
82
|
+
overflow: hidden;
|
|
83
|
+
background-color: #ffffff;
|
|
84
|
+
}
|
|
85
|
+
.u-table-fixed-shadow .u-table-border .u-table-cell {
|
|
86
|
+
border-right: 1rpx solid #ebeef5;
|
|
87
|
+
}
|
|
88
|
+
.u-table-fixed-shadow .u-table-border .u-table-cell:last-child {
|
|
89
|
+
border-right: none;
|
|
90
|
+
}
|
package/build/parse-pages.js
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* https://www.cnblogs.com/Megasu/p/16635566.html
|
|
3
|
-
*/
|
|
4
|
-
import fs from 'node:fs/promises';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { dirname, join } from 'node:path';
|
|
7
|
-
import path from 'node:path';
|
|
8
|
-
import { glob } from 'glob';
|
|
9
|
-
import { exec } from 'node:child_process';
|
|
10
|
-
// 获取 __filename 的 ESM 写法
|
|
11
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
-
// 获取 __dirname 的 ESM 写法
|
|
13
|
-
const __dirname = dirname(__filename);
|
|
14
|
-
|
|
15
|
-
const argv = process.argv.slice(2)[0];
|
|
16
|
-
console.log('---', argv);
|
|
17
|
-
/* pages.json
|
|
18
|
-
* 用户 pages 分布式配置,分别为三类配置 mian、sub、common
|
|
19
|
-
* *-main 为主包所有路径配置
|
|
20
|
-
* *-sub 为当前分包所有路径配置
|
|
21
|
-
* *-common 为globalStyle、tabBar和easycom的配置
|
|
22
|
-
* 已实现空路径自动创建vue文件,模板文件:./themp.vue
|
|
23
|
-
* 内置命令 npm run pages
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
const TEMPLATE_PATH = path.join(__dirname, './themp.vue');
|
|
27
|
-
const PROJECT_PATH = process.cwd();
|
|
28
|
-
const PROJECT_SRC = path.join(PROJECT_PATH, '/src');
|
|
29
|
-
const PAGES_JSON_PATH = path.join(PROJECT_SRC, 'pages.json');
|
|
30
|
-
const MENU_JS_PATH = path.join(PROJECT_SRC, 'router/menu.js');
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* 工具函数
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
/* 初始化vue模板文件 */
|
|
37
|
-
let templateData = fs_read_file(TEMPLATE_PATH, false) || '';
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* ---------- ----------
|
|
41
|
-
* 处理项目
|
|
42
|
-
* ---------- ----------
|
|
43
|
-
*/
|
|
44
|
-
const projectPath = process.cwd();
|
|
45
|
-
const projectSrc = path.join(projectPath, '/src');
|
|
46
|
-
|
|
47
|
-
// 用于存放pages所有配置
|
|
48
|
-
var pages = {};
|
|
49
|
-
// 获取所有
|
|
50
|
-
const pages_main = glob.sync(projectSrc + '/pages/**/*-main.json');
|
|
51
|
-
const pages_sub = glob.sync(projectSrc + '/pages/**/*-sub.json');
|
|
52
|
-
const pages_common = glob.sync(projectSrc + '/pages/**/*-common.json');
|
|
53
|
-
|
|
54
|
-
/* 抽取自定义配置 meta 到 router/menu.js */
|
|
55
|
-
function info_parse_data(pages) {
|
|
56
|
-
if (argv !== 'plus') {
|
|
57
|
-
return pages;
|
|
58
|
-
}
|
|
59
|
-
console.log('plus');
|
|
60
|
-
let diyPlus = {};
|
|
61
|
-
|
|
62
|
-
// 遍历主包配置
|
|
63
|
-
for (const key in pages.pages) {
|
|
64
|
-
if (pages.pages[key]['meta']) {
|
|
65
|
-
let k = pages.pages[key].path.replace(/\//g, '_');
|
|
66
|
-
console.log('【抽取meta】 ' + pages.pages[key].path, ' -> ', k);
|
|
67
|
-
diyPlus[k] = pages.pages[key]['meta'];
|
|
68
|
-
delete pages.pages[key]['meta'];
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
//遍历分包
|
|
73
|
-
for (const key in pages.subPackages) {
|
|
74
|
-
for (const index in pages.subPackages[key].pages) {
|
|
75
|
-
let root = pages.subPackages[key].root;
|
|
76
|
-
if (pages.subPackages[key].pages[index]['meta']) {
|
|
77
|
-
let full_path = root + pages.subPackages[key].pages[index].path;
|
|
78
|
-
let k = full_path.replace(/\//g, '_');
|
|
79
|
-
console.log('【抽取meta】 ' + full_path, ' -> ', k);
|
|
80
|
-
diyPlus[k] = pages.subPackages[key].pages[index]['meta'];
|
|
81
|
-
delete pages.subPackages[key].pages[index]['meta'];
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
if (diyPlus) {
|
|
86
|
-
//let content = 'export default ' + JSON.stringify(diyPlus);
|
|
87
|
-
//let content = 'export default ' + JSON.stringify(diyPlus, null, 2);
|
|
88
|
-
let content = 'export default {\n';
|
|
89
|
-
const entries = Object.entries(diyPlus);
|
|
90
|
-
for (let i = 0; i < entries.length; i++) {
|
|
91
|
-
const [key, value] = entries[i];
|
|
92
|
-
|
|
93
|
-
// 处理 value,手动转成类似 JSON 但键名无引号、字符串用单引号的格式
|
|
94
|
-
let formattedValue = '{ ';
|
|
95
|
-
const valueEntries = Object.entries(value);
|
|
96
|
-
for (let j = 0; j < valueEntries.length; j++) {
|
|
97
|
-
const [subKey, subVal] = valueEntries[j];
|
|
98
|
-
formattedValue += `${subKey}: `;
|
|
99
|
-
|
|
100
|
-
if (typeof subVal === 'string') {
|
|
101
|
-
formattedValue += `'${subVal}'`; // 字符串值用单引号
|
|
102
|
-
} else {
|
|
103
|
-
formattedValue += subVal; // 非字符串直接输出
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (j < valueEntries.length - 1) {
|
|
107
|
-
formattedValue += ', '; // 非最后一个属性加逗号
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
formattedValue += ' }';
|
|
111
|
-
|
|
112
|
-
// 拼接当前行的内容
|
|
113
|
-
content += ` ${key}: ${formattedValue}`;
|
|
114
|
-
|
|
115
|
-
// 如果不是最后一个元素,加逗号换行
|
|
116
|
-
if (i < entries.length - 1) {
|
|
117
|
-
content += ',\n';
|
|
118
|
-
} else {
|
|
119
|
-
content += '\n'; // 最后一行不加逗号,只换行
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
content += '};';
|
|
123
|
-
console.log('【更新文件】' + projectSrc + '/router/menu.js');
|
|
124
|
-
fs.writeFileSync(projectSrc + '/router/menu.js', content);
|
|
125
|
-
}
|
|
126
|
-
return pages;
|
|
127
|
-
}
|