@infly/libs 2.0.42 → 2.0.44
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/README.md +92 -67
- package/adapters/vue2/build/webpack5/inline-runtime-plugin.js +35 -0
- package/adapters/vue2/build/webpack5/remove-legacy-assets-plugin.js +84 -0
- package/adapters/vue2/build/webpack5/webpack.base.js +437 -0
- package/adapters/vue2/module/Permission.js +204 -0
- package/adapters/vue2/postinstall.js +46 -0
- package/adapters/vue2/project-preview.js +148 -0
- package/adapters/vue2/script-config.js +26 -0
- package/adapters/vue2/store/index.js +1 -0
- package/adapters/vue2/store/modules/user.js +268 -0
- package/bin/cli.js +71 -71
- package/build/build-dist/index.js +863 -863
- package/build/build-dist/script-management.js +5 -5
- package/build/docker/compose-command.js +74 -74
- package/build/docker/compose-release.js +91 -91
- package/build/webpack5/inline-runtime-plugin.js +1 -35
- package/build/webpack5/remove-legacy-assets-plugin.js +1 -84
- package/build/webpack5/webpack.base.js +1 -435
- package/compat/init.js +9 -0
- package/index.js +8 -20
- package/module/Permission.js +1 -204
- package/module/REST.js +31 -19
- package/module/TokenService.js +9 -0
- package/module/Uts.js +460 -7252
- package/module/cjs/request-url-rules.cjs +6 -0
- package/module/cjs/rest-error-rules.cjs +33 -0
- package/package.json +121 -92
- package/script/build/deps.js +1 -1
- package/script/build/webhook.js +3 -2
- package/script/git-automation/git-clone.js +3 -4
- package/script/git-automation/index.js +2 -2
- package/script/index.js +1 -26
- package/script/webhook/webhook.js +7 -2
- package/store/index.js +1 -0
- package/store/modules/user.js +1 -268
- package/tools/auto-export.js +1 -2
- package/tools/file-export.js +6 -4
- package/tools/project-command.js +194 -194
- package/tools/project-preview.js +1 -148
- package/tools/select-option.js +60 -60
- package/.prettierrc +0 -5
- package/build/build-dist/script-management.test.js +0 -16
- package/build/docker/compose-command.test.js +0 -148
- package/build/docker/compose-release.test.js +0 -101
- package/build/docker/docker-build-push.test.js +0 -124
- package/build/webpack5/webpack.base.test.js +0 -59
- package/lib/index.js +0 -6
- package/lib/server/connect.js +0 -3011
- package/lib/server/serve-static.js +0 -4848
- package/script/pts/cloud-scenes.mjs +0 -65
- package/script/pts/cloud.js +0 -151
- package/script/pts/generate-cloud-params.mjs +0 -210
- package/script/pts/generate-cloud-params.test.mjs +0 -67
- package/tools/project-command.test.js +0 -267
- package/tools/select-option.test.js +0 -52
- package/webpack.config.js +0 -38
|
@@ -1,435 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const path = require("path");
|
|
4
|
-
const InlineRuntimePlugin = require("./inline-runtime-plugin");
|
|
5
|
-
const RemoveLegacyAssetsPlugin = require("./remove-legacy-assets-plugin");
|
|
6
|
-
|
|
7
|
-
// 环境变量与常量配置
|
|
8
|
-
const ENV = {
|
|
9
|
-
IS_PROD: ["production", "staging"].includes(process.env.NODE_ENV),
|
|
10
|
-
IS_STAGING: process.env.ENV === "staging",
|
|
11
|
-
IS_DEV: process.env.ENV === "development"
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
// 强制禁用 modern mode(staging 环境)
|
|
15
|
-
if (ENV.IS_STAGING) {
|
|
16
|
-
process.env.VUE_CLI_MODERN_MODE = "false";
|
|
17
|
-
process.env.VUE_CLI_MODERN_BUILD = "false";
|
|
18
|
-
console.log("\n\x1b[36m⚡ Building for STAGING with Modern Bundle only (仅现代浏览器)...\x1b[0m");
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 解析项目路径(兼容monorepo)
|
|
23
|
-
* @param {string} dir 相对路径
|
|
24
|
-
* @returns {string} 绝对路径
|
|
25
|
-
*/
|
|
26
|
-
function resolve(dir) {
|
|
27
|
-
return path.join(process.cwd(), dir);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Node.js polyfill
|
|
32
|
-
*/
|
|
33
|
-
function createNodePolyfills() {
|
|
34
|
-
return {
|
|
35
|
-
path: require.resolve("path-browserify")
|
|
36
|
-
// 需要时可添加更多 polyfill
|
|
37
|
-
// fs: false,
|
|
38
|
-
// stream: require.resolve('stream-browserify'),
|
|
39
|
-
// crypto: require.resolve('crypto-browserify')
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* CSS/SCSS配置
|
|
45
|
-
*/
|
|
46
|
-
function cssModule(cssConfig = {}) {
|
|
47
|
-
const { additionalData = "" } = cssConfig || {};
|
|
48
|
-
return {
|
|
49
|
-
loaderOptions: {
|
|
50
|
-
sass: {
|
|
51
|
-
implementation: require("sass"),
|
|
52
|
-
sassOptions: {
|
|
53
|
-
api: "modern",
|
|
54
|
-
quietDeps: true,
|
|
55
|
-
silenceDeprecations: ["legacy-js-api", "function-units", "import"],
|
|
56
|
-
// 添加以下配置来优化内存使用
|
|
57
|
-
outputStyle: "compressed", // 压缩输出
|
|
58
|
-
sourceMap: false // 禁用 source map(开发环境可启用)
|
|
59
|
-
},
|
|
60
|
-
// 使用 webpackImporter 来优化模块解析
|
|
61
|
-
webpackImporter: true,
|
|
62
|
-
additionalData
|
|
63
|
-
},
|
|
64
|
-
css: {
|
|
65
|
-
esModule: true,
|
|
66
|
-
modules: {
|
|
67
|
-
auto: true,
|
|
68
|
-
localIdentName: "[name]_[local]_[hash:base64:5]"
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
extract: ENV.IS_PROD
|
|
73
|
-
? {
|
|
74
|
-
ignoreOrder: true,
|
|
75
|
-
// 添加缓存配置
|
|
76
|
-
chunkFilename: "css/[name].[contenthash:8].css"
|
|
77
|
-
}
|
|
78
|
-
: false
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* 基础 configureWebpack 配置
|
|
84
|
-
*/
|
|
85
|
-
function configureWebpack(extraConfig = {}) {
|
|
86
|
-
const { name, alias } = extraConfig || {};
|
|
87
|
-
const config = {
|
|
88
|
-
name,
|
|
89
|
-
resolve: {
|
|
90
|
-
alias: {
|
|
91
|
-
vue$: "vue/dist/vue.esm.js",
|
|
92
|
-
...(alias || {}),
|
|
93
|
-
"@": resolve("src")
|
|
94
|
-
},
|
|
95
|
-
fallback: createNodePolyfills(),
|
|
96
|
-
// 优化模块解析
|
|
97
|
-
extensions: [".js", ".vue", ".json", ".jsx"],
|
|
98
|
-
modules: ["node_modules"]
|
|
99
|
-
},
|
|
100
|
-
target: ["web", "es5"],
|
|
101
|
-
output: {
|
|
102
|
-
environment: {
|
|
103
|
-
arrowFunction: false,
|
|
104
|
-
bigIntLiteral: false,
|
|
105
|
-
const: false,
|
|
106
|
-
destructuring: false,
|
|
107
|
-
dynamicImport: false,
|
|
108
|
-
forOf: false,
|
|
109
|
-
module: false
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
performance: { hints: false },
|
|
113
|
-
ignoreWarnings: [{ module: /sass-loader/ }],
|
|
114
|
-
|
|
115
|
-
// 添加文件系统缓存(Webpack 5 核心优化)
|
|
116
|
-
cache: {
|
|
117
|
-
type: "filesystem",
|
|
118
|
-
cacheDirectory: resolve("node_modules/.cache/webpack"),
|
|
119
|
-
buildDependencies: {
|
|
120
|
-
config: [__filename]
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
// 开发环境优化
|
|
126
|
-
if (ENV.IS_DEV) {
|
|
127
|
-
config.optimization = {
|
|
128
|
-
removeAvailableModules: false,
|
|
129
|
-
removeEmptyChunks: false,
|
|
130
|
-
splitChunks: false,
|
|
131
|
-
runtimeChunk: true
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return config;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* chainWebpack配置
|
|
140
|
-
*/
|
|
141
|
-
function chainWebpack(config, options = {}) {
|
|
142
|
-
const { htmlPluginOptions = {} } = options || {};
|
|
143
|
-
|
|
144
|
-
config.plugins.delete("preload");
|
|
145
|
-
config.plugins.delete("prefetch");
|
|
146
|
-
|
|
147
|
-
if (Object.keys(htmlPluginOptions).length) {
|
|
148
|
-
config.plugin("html").tap((args) => {
|
|
149
|
-
const originalOptions = args[0] || {};
|
|
150
|
-
return [{ ...originalOptions, ...htmlPluginOptions }];
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// 强制禁用 modern mode(staging 环境)
|
|
155
|
-
if (ENV.IS_STAGING) {
|
|
156
|
-
// 删除 @vue/cli-service 的 modern mode 相关插件
|
|
157
|
-
config.plugins.delete("modern-mode-plugin");
|
|
158
|
-
|
|
159
|
-
// 强制修改 HTML 插件配置
|
|
160
|
-
config.plugin("html").tap((args) => {
|
|
161
|
-
args[0] = args[0] || {};
|
|
162
|
-
|
|
163
|
-
// 彻底禁用 modern mode
|
|
164
|
-
args[0].modern = false;
|
|
165
|
-
args[0].modulePreload = false;
|
|
166
|
-
args[0].scriptLoading = "defer";
|
|
167
|
-
|
|
168
|
-
// 删除所有 modern/legacy 相关的钩子和回调
|
|
169
|
-
delete args[0].modernBuild;
|
|
170
|
-
delete args[0].legacyBuild;
|
|
171
|
-
delete args[0].modernManifest;
|
|
172
|
-
delete args[0].legacyManifest;
|
|
173
|
-
|
|
174
|
-
// 关键:重写 templateParameters 来阻止 modern mode 注入
|
|
175
|
-
const originalTemplateParameters = args[0].templateParameters || {};
|
|
176
|
-
args[0].templateParameters = (compilation, assets, assetTags, options) => {
|
|
177
|
-
const params =
|
|
178
|
-
typeof originalTemplateParameters === "function"
|
|
179
|
-
? originalTemplateParameters(compilation, assets, assetTags, options)
|
|
180
|
-
: originalTemplateParameters;
|
|
181
|
-
|
|
182
|
-
// 移除 modern/legacy 相关的参数
|
|
183
|
-
if (params) {
|
|
184
|
-
delete params.modernBuild;
|
|
185
|
-
delete params.legacyBuild;
|
|
186
|
-
delete params.modernManifest;
|
|
187
|
-
delete params.legacyManifest;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return params;
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
return args;
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// 添加自定义插件来处理 legacy 文件问题
|
|
197
|
-
config.plugin("remove-legacy-assets").use(RemoveLegacyAssetsPlugin);
|
|
198
|
-
|
|
199
|
-
// Babel 配置:只转译现代浏览器
|
|
200
|
-
config.module
|
|
201
|
-
.rule("js")
|
|
202
|
-
.use("babel-loader")
|
|
203
|
-
.tap((options) => ({
|
|
204
|
-
...options,
|
|
205
|
-
presets: [
|
|
206
|
-
[
|
|
207
|
-
"@babel/preset-env",
|
|
208
|
-
{
|
|
209
|
-
targets: {
|
|
210
|
-
esmodules: true,
|
|
211
|
-
chrome: "60",
|
|
212
|
-
firefox: "60",
|
|
213
|
-
safari: "11",
|
|
214
|
-
edge: "79"
|
|
215
|
-
},
|
|
216
|
-
modules: false
|
|
217
|
-
}
|
|
218
|
-
]
|
|
219
|
-
],
|
|
220
|
-
cacheDirectory: true,
|
|
221
|
-
cacheCompression: false
|
|
222
|
-
}));
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// 注册 runtime 内联插件
|
|
226
|
-
config.plugin("inline-runtime").use(InlineRuntimePlugin);
|
|
227
|
-
|
|
228
|
-
// SVG图标
|
|
229
|
-
config.module.rule("svg").exclude.add(resolve("src/icons")).end();
|
|
230
|
-
config.module
|
|
231
|
-
.rule("icons")
|
|
232
|
-
.test(/\.svg$/)
|
|
233
|
-
.include.add(resolve("src/icons"))
|
|
234
|
-
.end()
|
|
235
|
-
.use("svg-sprite-loader")
|
|
236
|
-
.loader("svg-sprite-loader")
|
|
237
|
-
.options({ symbolId: "icon-[name]" })
|
|
238
|
-
.end();
|
|
239
|
-
|
|
240
|
-
// Vue Loader 优化
|
|
241
|
-
config.module
|
|
242
|
-
.rule("vue")
|
|
243
|
-
.use("vue-loader")
|
|
244
|
-
.loader("vue-loader")
|
|
245
|
-
.tap((options) => ({
|
|
246
|
-
...options,
|
|
247
|
-
compilerOptions: {
|
|
248
|
-
...(options.compilerOptions || {}),
|
|
249
|
-
preserveWhitespace: true,
|
|
250
|
-
whitespace: "preserve"
|
|
251
|
-
}
|
|
252
|
-
}))
|
|
253
|
-
.end();
|
|
254
|
-
|
|
255
|
-
// 优化 Babel Loader 缓存(非 staging 环境)
|
|
256
|
-
if (!ENV.IS_STAGING) {
|
|
257
|
-
config.module
|
|
258
|
-
.rule("js")
|
|
259
|
-
.use("babel-loader")
|
|
260
|
-
.loader("babel-loader")
|
|
261
|
-
.tap((options) => ({
|
|
262
|
-
...options,
|
|
263
|
-
cacheDirectory: true,
|
|
264
|
-
cacheCompression: false
|
|
265
|
-
}));
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// 图片资源
|
|
269
|
-
config.module
|
|
270
|
-
.rule("images")
|
|
271
|
-
.test(/\.(png|jpe?g|gif|webp)$/i)
|
|
272
|
-
.set("type", "asset")
|
|
273
|
-
.set("parser", { dataUrlCondition: { maxSize: 4 * 1024 } });
|
|
274
|
-
|
|
275
|
-
// SVG资源(非图标)
|
|
276
|
-
config.module
|
|
277
|
-
.rule("svg-assets")
|
|
278
|
-
.test(/\.(svg)$/i)
|
|
279
|
-
.exclude.add(resolve("src/icons"))
|
|
280
|
-
.end()
|
|
281
|
-
.set("type", "asset/resource");
|
|
282
|
-
|
|
283
|
-
// 媒体资源
|
|
284
|
-
config.module
|
|
285
|
-
.rule("media")
|
|
286
|
-
.test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)$/i)
|
|
287
|
-
.set("type", "asset")
|
|
288
|
-
.set("parser", { dataUrlCondition: { maxSize: 4 * 1024 } });
|
|
289
|
-
|
|
290
|
-
// 字体资源
|
|
291
|
-
config.module
|
|
292
|
-
.rule("fonts")
|
|
293
|
-
.test(/\.(woff2?|eot|ttf|otf)$/i)
|
|
294
|
-
.set("type", "asset/resource");
|
|
295
|
-
|
|
296
|
-
// 生产环境优化
|
|
297
|
-
if (ENV.IS_PROD) {
|
|
298
|
-
config.plugin("html").tap((args) => {
|
|
299
|
-
const options = args[0] || {};
|
|
300
|
-
const now = new Date();
|
|
301
|
-
return [
|
|
302
|
-
{
|
|
303
|
-
...options,
|
|
304
|
-
scriptLoading: "blocking",
|
|
305
|
-
inject: true,
|
|
306
|
-
buildTimestamp: now.toLocaleString(),
|
|
307
|
-
buildVersion: process.env.npm_package_version || "1.0.0",
|
|
308
|
-
buildEnv: process.env.NODE_ENV
|
|
309
|
-
}
|
|
310
|
-
];
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
config.optimization.splitChunks({
|
|
314
|
-
chunks: "all",
|
|
315
|
-
minSize: 20000,
|
|
316
|
-
minChunks: 1,
|
|
317
|
-
maxAsyncRequests: 30,
|
|
318
|
-
maxInitialRequests: 30,
|
|
319
|
-
enforceSizeThreshold: 50000,
|
|
320
|
-
cacheGroups: {
|
|
321
|
-
// 最高优先级:ElementUI 框架(单独分包)
|
|
322
|
-
elementUI: {
|
|
323
|
-
name: "chunk-element-ui",
|
|
324
|
-
test: /[\\/]node_modules[\\/]_?element-ui(.*)/,
|
|
325
|
-
priority: 40,
|
|
326
|
-
chunks: "all",
|
|
327
|
-
reuseExistingChunk: true
|
|
328
|
-
},
|
|
329
|
-
// 高优先级:ECharts 图表库(体积大,单独分包)
|
|
330
|
-
echarts: {
|
|
331
|
-
name: "chunk-echarts",
|
|
332
|
-
test: /[\\/]node_modules[\\/](echarts|zrender|v-charts)(.*)/,
|
|
333
|
-
priority: 35,
|
|
334
|
-
chunks: "async",
|
|
335
|
-
reuseExistingChunk: true
|
|
336
|
-
},
|
|
337
|
-
// Infly UI 组件库
|
|
338
|
-
inflyUI: {
|
|
339
|
-
name: "chunk-infly-ui",
|
|
340
|
-
test: /[\\/]packages[\\/]infly-ui[\\/]/,
|
|
341
|
-
priority: 31,
|
|
342
|
-
chunks: "all",
|
|
343
|
-
reuseExistingChunk: true
|
|
344
|
-
},
|
|
345
|
-
// Infly 工具库(monorepo 共享代码)
|
|
346
|
-
inflyLibs: {
|
|
347
|
-
name: "chunk-infly-libs",
|
|
348
|
-
test: /[\\/]packages[\\/]infly-libs[\\/]/,
|
|
349
|
-
priority: 30,
|
|
350
|
-
chunks: "all",
|
|
351
|
-
reuseExistingChunk: true
|
|
352
|
-
},
|
|
353
|
-
// Vue 全家桶(vue、vue-router、vuex)
|
|
354
|
-
vue: {
|
|
355
|
-
name: "chunk-vue",
|
|
356
|
-
test: /[\\/]node_modules[\\/](vue|vue-router|vuex)(.*)/,
|
|
357
|
-
priority: 25,
|
|
358
|
-
chunks: "all",
|
|
359
|
-
reuseExistingChunk: true
|
|
360
|
-
},
|
|
361
|
-
// 工具库(axios、lodash、moment 等)
|
|
362
|
-
utils: {
|
|
363
|
-
name: "chunk-utils",
|
|
364
|
-
test: /[\\/]node_modules[\\/](axios|nprogress|path-to-regexp|qrcanvas|html2canvas|element-china-area-data|vue-awesome-swiper|normalize\.css)(.*)/,
|
|
365
|
-
priority: 20,
|
|
366
|
-
chunks: "all",
|
|
367
|
-
reuseExistingChunk: true
|
|
368
|
-
},
|
|
369
|
-
// 其他 node_modules 库
|
|
370
|
-
libs: {
|
|
371
|
-
name: "chunk-libs",
|
|
372
|
-
test: /[\\/]node_modules[\\/]/,
|
|
373
|
-
priority: 10,
|
|
374
|
-
chunks: "initial",
|
|
375
|
-
reuseExistingChunk: true
|
|
376
|
-
},
|
|
377
|
-
// 公共组件(被多次引用的组件)
|
|
378
|
-
commons: {
|
|
379
|
-
name: "chunk-commons",
|
|
380
|
-
test: resolve("src/components"),
|
|
381
|
-
minChunks: 3,
|
|
382
|
-
priority: 5,
|
|
383
|
-
reuseExistingChunk: true
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
config.optimization.runtimeChunk("single");
|
|
389
|
-
|
|
390
|
-
config.optimization.minimizer("terser").tap((args) => {
|
|
391
|
-
const options = args[0] || {};
|
|
392
|
-
const terserOptions = options.terserOptions || {};
|
|
393
|
-
options.terserOptions = {
|
|
394
|
-
...terserOptions,
|
|
395
|
-
compress: {
|
|
396
|
-
...(terserOptions.compress || {}),
|
|
397
|
-
drop_console: true,
|
|
398
|
-
drop_debugger: true,
|
|
399
|
-
pure_funcs: ["console.log"]
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
return [options];
|
|
403
|
-
});
|
|
404
|
-
} else {
|
|
405
|
-
config.devtool("eval-cheap-module-source-map");
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* devServer 优化配置
|
|
411
|
-
*/
|
|
412
|
-
function devServer() {
|
|
413
|
-
return {
|
|
414
|
-
hot: true,
|
|
415
|
-
client: {
|
|
416
|
-
logging: "warn", // 减少控制台日志
|
|
417
|
-
overlay: false
|
|
418
|
-
},
|
|
419
|
-
// 优化监听性能
|
|
420
|
-
watchFiles: {
|
|
421
|
-
options: {
|
|
422
|
-
ignored: /node_modules/,
|
|
423
|
-
usePolling: false
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
module.exports = {
|
|
430
|
-
cssModule,
|
|
431
|
-
configureWebpack,
|
|
432
|
-
chainWebpack,
|
|
433
|
-
devServer,
|
|
434
|
-
projectResolve: resolve
|
|
435
|
-
};
|
|
1
|
+
module.exports = require("../../adapters/vue2/build/webpack5/webpack.base.js");
|
package/compat/init.js
ADDED
package/index.js
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
const projectPreview = require("./tools/project-preview");
|
|
3
|
-
const path = require("path");
|
|
1
|
+
"use strict";
|
|
4
2
|
|
|
5
|
-
function init() {
|
|
6
|
-
|
|
7
|
-
const currentDir = process.cwd();
|
|
8
|
-
const packageDir = __dirname;
|
|
9
|
-
|
|
10
|
-
// 如果当前目录就是 infly-libs 包目录,跳过执行
|
|
11
|
-
if (currentDir === packageDir) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
projectPreview.scriptInit();
|
|
16
|
-
buildDist.scriptInit();
|
|
3
|
+
function init(projectRoot) {
|
|
4
|
+
return require("./compat/init").init(projectRoot);
|
|
17
5
|
}
|
|
18
6
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
init
|
|
23
|
-
};
|
|
7
|
+
module.exports = Object.freeze({
|
|
8
|
+
name: "@infly/libs",
|
|
9
|
+
framework: "agnostic",
|
|
10
|
+
init,
|
|
11
|
+
});
|
package/module/Permission.js
CHANGED
|
@@ -1,204 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import TokenService from "./TokenService";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 路由拦截器
|
|
6
|
-
* @param {Object} config 配置项
|
|
7
|
-
* @param {Array} config.whiteList 白名单路径
|
|
8
|
-
* @param {String} config.pagePathCacheKey 页面路径缓存的键
|
|
9
|
-
* @param {Object} config.router 路由实例
|
|
10
|
-
* @param {Object} config.store Vuex store 实例
|
|
11
|
-
* @param {Object} config.NProgress NProgress 实例
|
|
12
|
-
* @param {Function} config.getUserInfo 获取用户信息的函数
|
|
13
|
-
* @param {Function} config.resetToken 重置 token 的函数
|
|
14
|
-
* @param {Function} config.showMessage 显示消息的函数
|
|
15
|
-
* @returns {void}
|
|
16
|
-
*/
|
|
17
|
-
export function initPermission({
|
|
18
|
-
whiteList = ["/login", "/404", "/403", "/error/401", "/error/404"],
|
|
19
|
-
getUserInfoAction = "user/getInfo",
|
|
20
|
-
resetTokenAction = "user/resetToken",
|
|
21
|
-
refreshTokenAction = "user/refreshToken",
|
|
22
|
-
pagePathCacheKey, // 页面路径缓存
|
|
23
|
-
router,
|
|
24
|
-
store,
|
|
25
|
-
defaultSettings,
|
|
26
|
-
settings = defaultSettings || {},
|
|
27
|
-
NProgress,
|
|
28
|
-
Message,
|
|
29
|
-
getUserInfo,
|
|
30
|
-
resetToken,
|
|
31
|
-
showMessage
|
|
32
|
-
}) {
|
|
33
|
-
const { title: projectTitle } = settings || {};
|
|
34
|
-
const { dispatch } = store || {};
|
|
35
|
-
// 转为 Set,将白名单查找从 O(n) 优化为 O(1)
|
|
36
|
-
const whiteSet = new Set(whiteList);
|
|
37
|
-
|
|
38
|
-
// afterEach 已统一调用 NProgress.done(),此处无需重复
|
|
39
|
-
const redirectToLogin = (to, next) => {
|
|
40
|
-
next(`/login?redirect=${to.path}`);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const handleGetUserInfo = () => {
|
|
44
|
-
if (Uts.isFunction(getUserInfo)) {
|
|
45
|
-
return getUserInfo();
|
|
46
|
-
} else if (Uts.isFunction(dispatch)) {
|
|
47
|
-
return dispatch(getUserInfoAction);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const handleResetToken = () => {
|
|
52
|
-
if (Uts.isFunction(resetToken)) {
|
|
53
|
-
return resetToken();
|
|
54
|
-
} else if (Uts.isFunction(dispatch)) {
|
|
55
|
-
return dispatch(resetTokenAction);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// 降级链:优先调用自定义 showMessage,其次 Message,最后 console
|
|
60
|
-
const handleShowMessage = (message, type = "error") => {
|
|
61
|
-
if (Uts.isFunction(showMessage)) {
|
|
62
|
-
showMessage(message);
|
|
63
|
-
} else if (Uts.isFunction(Message)) {
|
|
64
|
-
Message[type](message);
|
|
65
|
-
} else {
|
|
66
|
-
console.log(message);
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const handlePageTitle = (path) => {
|
|
71
|
-
const title = projectTitle || "后台管理系统";
|
|
72
|
-
return path ? `${path} - ${title}` : title;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
NProgress.configure({ showSpinner: false });
|
|
76
|
-
|
|
77
|
-
// 辅助函数:处理 URL token 参数
|
|
78
|
-
const handleUrlTokenParam = async (to, next, accessTokenKey, accessToken) => {
|
|
79
|
-
if (!to.query[accessTokenKey]) return false;
|
|
80
|
-
|
|
81
|
-
// 优先从地址栏获取token, 更新存储token值
|
|
82
|
-
if (accessToken && Uts.isFunction(dispatch)) {
|
|
83
|
-
try {
|
|
84
|
-
await dispatch(refreshTokenAction, { token: accessToken });
|
|
85
|
-
} catch (error) {
|
|
86
|
-
console.error("[Token Refresh Error]:", error);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// 用解构 rest 移除 token 参数,避免修改原对象
|
|
91
|
-
const { [accessTokenKey]: _, ...newQuery } = to.query;
|
|
92
|
-
next({ path: to.path, query: newQuery, replace: true });
|
|
93
|
-
return true;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// 辅助函数:检查权限
|
|
97
|
-
const checkPermission = (permission) => {
|
|
98
|
-
if (!permission) return true;
|
|
99
|
-
|
|
100
|
-
const hasPermission = Uts.getPM(permission);
|
|
101
|
-
|
|
102
|
-
if (!hasPermission) {
|
|
103
|
-
console.warn(`[权限不足] 需要权限: ${permission}`);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return hasPermission;
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// 辅助函数:处理已认证用户的路由
|
|
110
|
-
const handleAuthenticatedRoute = async (to, next, permission) => {
|
|
111
|
-
// 已登录用户访问登录页
|
|
112
|
-
if (to.path === "/login") {
|
|
113
|
-
const { PMRedirectPath } = (await handleGetUserInfo()) || {};
|
|
114
|
-
const redirectPath = to.query.redirect;
|
|
115
|
-
|
|
116
|
-
if (redirectPath) {
|
|
117
|
-
// 查找 redirect 路由对应的权限
|
|
118
|
-
const matched = router.resolve(redirectPath)?.route;
|
|
119
|
-
const redirectPermission = matched?.meta?.permission;
|
|
120
|
-
// 无需权限 或 有权限,则走 redirect
|
|
121
|
-
if (!redirectPermission || checkPermission(redirectPermission)) {
|
|
122
|
-
return next({ path: redirectPath });
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// 否则跳到第一个有权限的页面
|
|
127
|
-
return next({ path: PMRedirectPath || "/" });
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
// 获取用户信息
|
|
132
|
-
const { PMRedirectPath } = (await handleGetUserInfo()) || {};
|
|
133
|
-
|
|
134
|
-
// 合并权限检查,避免重复调用 checkPermission
|
|
135
|
-
if (permission && !checkPermission(permission)) {
|
|
136
|
-
// 有兜底路径时优先跳转,否则跳 403
|
|
137
|
-
if (PMRedirectPath) {
|
|
138
|
-
return next({ path: PMRedirectPath });
|
|
139
|
-
}
|
|
140
|
-
if (!whiteSet.has(to.path)) {
|
|
141
|
-
return next({ path: "/error/403" });
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
next();
|
|
146
|
-
} catch (error) {
|
|
147
|
-
const { message = "" } = error || {};
|
|
148
|
-
console.error("[认证失败]:", message || error);
|
|
149
|
-
|
|
150
|
-
// 可选:显示错误消息
|
|
151
|
-
// handleShowMessage(message || "验证失败,请重新登录");
|
|
152
|
-
|
|
153
|
-
await handleResetToken();
|
|
154
|
-
redirectToLogin(to, next);
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
router.beforeEach(async (to, from, next) => {
|
|
159
|
-
NProgress.start();
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
const Token = TokenService.getToken();
|
|
163
|
-
const accessTokenKey = TokenService.getUrlTokenKey();
|
|
164
|
-
const accessToken = TokenService.getUrlToken();
|
|
165
|
-
const { permission } = to.meta || {};
|
|
166
|
-
|
|
167
|
-
// 设置页面标题
|
|
168
|
-
document.title = handlePageTitle(to.meta?.title);
|
|
169
|
-
|
|
170
|
-
// 缓存页面路径(非白名单页面)
|
|
171
|
-
if (pagePathCacheKey && !whiteSet.has(to.path)) {
|
|
172
|
-
localStorage.setItem(pagePathCacheKey, window.location.href);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// 1. 处理 URL token 参数
|
|
176
|
-
if (await handleUrlTokenParam(to, next, accessTokenKey, accessToken)) {
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// 2. 检查白名单路径
|
|
181
|
-
if (whiteSet.has(to.path)) {
|
|
182
|
-
return next();
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// 3. 未登录用户,重定向到登录页
|
|
186
|
-
if (!Token) {
|
|
187
|
-
return redirectToLogin(to, next);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// 4. 已登录用户的路由处理
|
|
191
|
-
await handleAuthenticatedRoute(to, next, permission);
|
|
192
|
-
} catch (error) {
|
|
193
|
-
console.error("[路由守卫错误]:", error);
|
|
194
|
-
|
|
195
|
-
// 发生未预期的错误时,重定向到登录页
|
|
196
|
-
await handleResetToken();
|
|
197
|
-
redirectToLogin(to, next);
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
router.afterEach(() => {
|
|
202
|
-
NProgress.done();
|
|
203
|
-
});
|
|
204
|
-
}
|
|
1
|
+
export * from "../adapters/vue2/module/Permission.js";
|