mm_nav 0.0.0-stage → 1.1.1

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.
Files changed (41) hide show
  1. package/README.md +2 -3
  2. package/com.json +5 -0
  3. package/config.tpl.json +84 -0
  4. package/example/index.js +35 -0
  5. package/index.js +17 -0
  6. package/lib/manager.js +187 -0
  7. package/lib/nav.js +767 -0
  8. package/lib/viewmodel.js +448 -0
  9. package/package.json +31 -4
  10. package/test.js +18 -0
  11. package/tpl/admin_pc/page_channel.vue +305 -0
  12. package/tpl/admin_pc/page_config.vue +280 -0
  13. package/tpl/admin_pc/page_config_form.vue +194 -0
  14. package/tpl/admin_pc/page_default.vue +247 -0
  15. package/tpl/admin_pc/page_form.vue +180 -0
  16. package/tpl/admin_pc/page_lang.vue +264 -0
  17. package/tpl/admin_pc/page_nav.vue +321 -0
  18. package/tpl/admin_pc/page_table.vue +296 -0
  19. package/tpl/admin_pc/page_type.vue +321 -0
  20. package/tpl/admin_pc/page_view.vue +124 -0
  21. package/tpl/dev_pc/page_channel.vue +253 -0
  22. package/tpl/dev_pc/page_config.vue +253 -0
  23. package/tpl/dev_pc/page_default.vue +247 -0
  24. package/tpl/dev_pc/page_form.vue +162 -0
  25. package/tpl/dev_pc/page_nav.vue +253 -0
  26. package/tpl/dev_pc/page_table.vue +247 -0
  27. package/tpl/dev_pc/page_type.vue +313 -0
  28. package/tpl/home_pc/page_channel.vue +234 -0
  29. package/tpl/home_pc/page_default.vue +234 -0
  30. package/tpl/home_pc/page_form.vue +137 -0
  31. package/tpl/home_pc/page_list.vue +234 -0
  32. package/tpl/home_pc/page_nav.vue +221 -0
  33. package/tpl/home_pc/page_type.vue +234 -0
  34. package/tpl/home_pc/page_view.vue +125 -0
  35. package/tpl/home_phone/page_channel.vue +234 -0
  36. package/tpl/home_phone/page_default.vue +234 -0
  37. package/tpl/home_phone/page_form.vue +137 -0
  38. package/tpl/home_phone/page_list.vue +234 -0
  39. package/tpl/home_phone/page_nav.vue +237 -0
  40. package/tpl/home_phone/page_type.vue +234 -0
  41. package/tpl/home_phone/page_view.vue +125 -0
package/lib/nav.js ADDED
@@ -0,0 +1,767 @@
1
+ const fs = require("fs");
2
+ const os = require("os");
3
+ const path = require("path");
4
+ const Item = require("mm_mod").Base;
5
+ const { string, array, object, file } = require("mm_helper");
6
+ const Model = require("./viewmodel.js");
7
+
8
+ /** 视图模型实例 */
9
+ const VIEW_MODEL = new Model();
10
+
11
+ /** 模板引擎实例缓存(懒加载,undefined 表示加载失败) */
12
+ let tpl_instance = null;
13
+
14
+ /**
15
+ * 获取模板引擎实例(mm_tpl 包名引用,首次使用时创建)
16
+ * @returns {object|null} 模板引擎实例;mm_tpl 不可用时返回null
17
+ */
18
+ function _getTpl() {
19
+ if (tpl_instance === null) {
20
+ try {
21
+ const { Tpl } = require("mm_tpl");
22
+ tpl_instance = new Tpl({
23
+ extname: ".vue",
24
+ chache_extname: ".cache.vue",
25
+ });
26
+ tpl_instance.dir = __dirname;
27
+ } catch (err) {
28
+ console.error("mm_tpl模板引擎加载失败:", err);
29
+ tpl_instance = undefined;
30
+ }
31
+ }
32
+ return tpl_instance || null;
33
+ }
34
+
35
+ /**
36
+ * 导航驱动类
37
+ * @augments {Item}
38
+ * @class
39
+ */
40
+ class Nav extends Item {
41
+ static config = {
42
+ // 路由
43
+ "routes": [
44
+ /*
45
+ {
46
+ // 名称
47
+ "name": "root",
48
+ // 路由路径
49
+ "path": "/",
50
+ // 组件文件路径
51
+ "component": "",
52
+ // 页面显示级别
53
+ "level": "",
54
+ // 身份验证
55
+ "oauth": {
56
+ // 是否登录
57
+ "sign_in": false,
58
+ // 要求会员级别
59
+ "vip": 0,
60
+ // 要求管理级别
61
+ "gm": 0,
62
+ // 要求商户级别
63
+ "mc": 0,
64
+ // 要求用户组
65
+ "user_group": [],
66
+ // 要求管理组
67
+ "user_admin": []
68
+ }
69
+ }
70
+ */
71
+ ],
72
+ // 顶部导航
73
+ "top_nav": [],
74
+ // 左侧导航
75
+ "left_nav": [],
76
+ // 底部导航
77
+ "bottom_nav": [],
78
+ // 右侧导航
79
+ "right_nav": [],
80
+ // 桌面导航
81
+ "desktop_nav": [],
82
+ // 快捷导航
83
+ "quick_nav": [],
84
+ // 主导航
85
+ "main_nav": [
86
+ /*
87
+ {
88
+ // 标题
89
+ "title": "",
90
+ // 路径
91
+ "url": "",
92
+ // 在没有权限下是否显示
93
+ "show": false,
94
+ // 显示顺序
95
+ "display": 3,
96
+ // 子导航
97
+ "sub": [
98
+ {
99
+ // 标题
100
+ "title": "",
101
+ // 路径
102
+ "url": "",
103
+ // 在没有权限下是否显示
104
+ "show": false
105
+ }
106
+ ]
107
+ }
108
+ */
109
+ ],
110
+ // 主程序文件 - 默认为空
111
+ "main": "",
112
+ // 驱动目录(方案B:手动配置,替代目录扫描)
113
+ "dir": "",
114
+ };
115
+ /**
116
+ * 构造函数
117
+ * @param {object} config 配置参数
118
+ * @param {object} parent 父对象(管理器实例)
119
+ * @class
120
+ */
121
+ constructor(config, parent) {
122
+ super({ ...Nav.config, ...config });
123
+
124
+ // 父级管理器引用(用于跨模块服务注入回退)
125
+ this.parent = parent || null;
126
+ // 模板路径
127
+ this.tpl_path = "./tpl/";
128
+ // 默认启用热更新
129
+ this.mode = 3;
130
+ // API 获取函数缺失告警标记
131
+ this._api_warned = false;
132
+ }
133
+ }
134
+
135
+ /**
136
+ * 调用函数
137
+ * @param {object} type 导航类型
138
+ * @returns {object} 执行结果
139
+ */
140
+ Nav.prototype.run = function (type) {
141
+ var cg = {
142
+ routes: this.config.routes,
143
+ };
144
+ cg[type] = this.config[type];
145
+ return cg;
146
+ };
147
+
148
+ /**
149
+ * 合并项
150
+ * @param {object[]} arr 目标数组
151
+ * @param {object[]} lt 导航项
152
+ */
153
+ Nav.prototype.mergeSub = function (arr, lt) {
154
+ if (lt) {
155
+ var len = lt.length;
156
+ for (var i = 0; i < len; i++) {
157
+ var o = lt[i];
158
+ if (o.name) {
159
+ var item = array.getMatch(arr, o.name, "name");
160
+ if (item) {
161
+ object.push(item, o, true);
162
+ } else {
163
+ arr.push(o);
164
+ }
165
+ }
166
+ }
167
+ }
168
+ };
169
+
170
+ /**
171
+ * 执行导航
172
+ * @param {string} type 导航类型
173
+ * @returns {object|string} 执行结果
174
+ */
175
+ Nav.prototype.exec = function (type) {
176
+ var cg = this.config;
177
+ if (cg[type]) {
178
+ return this.run(type);
179
+ }
180
+ return "";
181
+ };
182
+
183
+ /**
184
+ * 排序
185
+ */
186
+ Nav.prototype.sort = async function () {
187
+ var cg = this.config;
188
+ if (cg.top_nav) array.sortBy(cg.top_nav, "asc", "display");
189
+ if (cg.left_nav) array.sortBy(cg.left_nav, "asc", "display");
190
+ if (cg.bottom_nav) array.sortBy(cg.bottom_nav, "asc", "display");
191
+ if (cg.right_nav) array.sortBy(cg.right_nav, "asc", "display");
192
+ if (cg.desktop_nav) array.sortBy(cg.desktop_nav, "asc", "display");
193
+ if (cg.quick_nav) array.sortBy(cg.quick_nav, "asc", "display");
194
+ if (cg.main_nav) array.sortBy(cg.main_nav, "asc", "display");
195
+ };
196
+
197
+ /**
198
+ * 合并配置
199
+ * @param {object} o 配置
200
+ */
201
+ Nav.prototype.merge = function (o) {
202
+ var cg = this.config;
203
+ cg.name = o.name;
204
+ cg.sort = o.sort;
205
+ this.mergeSub(cg.routes, o.routes);
206
+ this.mergeSub(cg.top, o.top);
207
+ this.mergeSub(cg.left, o.left);
208
+ this.mergeSub(cg.bottom, o.bottom);
209
+ this.mergeSub(cg.right, o.right);
210
+ this.mergeSub(cg.desktop, o.desktop);
211
+ this.mergeSub(cg.quick, o.quick);
212
+ this.mergeSub(cg.main, o.main);
213
+ };
214
+
215
+ /**
216
+ * 新建导航
217
+ * @param {string} title 标题
218
+ * @param {string} name 名称
219
+ * @param {string} url 路径
220
+ * @param {number} display 显示顺序
221
+ * @returns {object} 导航对象
222
+ */
223
+ Nav.prototype.newNav = function (title, name, url, display = 100) {
224
+ var obj = {
225
+ title: title,
226
+ // 在没有权限下是否显示
227
+ show: false,
228
+ name: name,
229
+ url: url,
230
+ display: display,
231
+ };
232
+ return obj;
233
+ };
234
+
235
+ /**
236
+ * 新建路由
237
+ * @param {string} app 应用名
238
+ * @param {string} plugin 插件名
239
+ * @param {string} name 接口名
240
+ * @param {number} group 权限组
241
+ * @param {object} oauth 身份验证
242
+ * @returns {object} 路由对象
243
+ */
244
+ Nav.prototype.newRoutes = function (app, plugin, name, group, oauth) {
245
+ var pn = plugin === "pc" ? "" : plugin;
246
+ var n = name.replace(app + "_", "");
247
+ var obj = {
248
+ name: name,
249
+ path: "/" + app + "/" + n,
250
+ component: "/" + app + (pn ? "/" + pn : "") + "/src/pages/" + n + ".vue",
251
+ level: n.replace("_form", "").replace("_view", "").indexOf("_") === -1 ? 3 : 2,
252
+ oauth: oauth,
253
+ };
254
+ if (!oauth) {
255
+ if (!group) {
256
+ // 不验证身份
257
+ obj.oauth = {
258
+ sign_in: false,
259
+ };
260
+ } else if (group === 1) {
261
+ // 验证身份为管理员
262
+ obj.oauth = {
263
+ sign_in: true,
264
+ gm: 2,
265
+ user_admin: [],
266
+ };
267
+ } else {
268
+ // 验证身份为商户
269
+ obj.oauth = {
270
+ sign_in: true,
271
+ mc: 1,
272
+ user_group: [],
273
+ };
274
+ }
275
+ }
276
+ return obj;
277
+ };
278
+
279
+ /**
280
+ * 处理管理端API配置
281
+ * @param {string} dir 目录路径
282
+ * @param {string} app 应用名
283
+ * @param {string} plugin 插件名
284
+ * @param {Array} nav 导航数组
285
+ * @param {object} cg 配置对象
286
+ */
287
+ Nav.prototype._processManageApis = function (dir, app, plugin, nav, cg) {
288
+ var d = dir + "api_manage";
289
+ if (!file.hasDir(d)) {
290
+ d = dir + `api_${app}_manage`;
291
+ }
292
+ if (!file.hasDir(d)) {
293
+ return;
294
+ }
295
+
296
+ var list = file.getAllFile(d, "*api.json");
297
+ for (var i = 0; i < list.length; i++) {
298
+ var o = file.loadJson(list[i]);
299
+ if (o) {
300
+ delete o.oauth.scope;
301
+ var name = o.name.replace("_manage", "");
302
+ // 添加一个列表页
303
+ var obj = this.newRoutes(app, plugin, name, 1, o.oauth);
304
+
305
+ // 添加一个详情页
306
+ var obj2 = this.newRoutes(app, plugin, name + "_form", 1, o.oauth);
307
+ obj2.level += 1;
308
+
309
+ cg.routes.push(obj);
310
+ cg.routes.push(obj2);
311
+
312
+ nav.push(this.newNav(o.title, name, obj.path));
313
+ }
314
+ }
315
+ };
316
+
317
+ /**
318
+ * 处理客户端API配置
319
+ * @param {string} dir 目录路径
320
+ * @param {string} app 应用名
321
+ * @param {string} plugin 插件名
322
+ * @param {Array} nav 导航数组
323
+ * @param {object} cg 配置对象
324
+ */
325
+ Nav.prototype._processClientApis = function (dir, app, plugin, nav, cg) {
326
+ var d = dir + "api_client";
327
+ if (!file.hasDir(d)) {
328
+ d = dir + `api_${app}_client`;
329
+ }
330
+ if (!file.hasDir(d)) {
331
+ return;
332
+ }
333
+
334
+ var list = file.getAllFile(d, "*api.json");
335
+ for (var i = 0; i < list.length; i++) {
336
+ var o = file.loadJson(list[i]);
337
+ if (o && !Array.isArray(o)) {
338
+ if (o.oauth) {
339
+ delete o.oauth.scope;
340
+ }
341
+
342
+ var name = o.name;
343
+ // 添加一个列表页
344
+ var obj = this.newRoutes(app, plugin, name, 0, o.oauth);
345
+
346
+ // 添加一个详情页
347
+ var obj2 = this.newRoutes(app, plugin, name + "_view", 0, o.oauth);
348
+ obj2.level += 1;
349
+
350
+ if (name.indexOf("_") === -1) {
351
+ obj.level += 1;
352
+ obj2.level += 1;
353
+ }
354
+ cg.routes.push(obj);
355
+ cg.routes.push(obj2);
356
+
357
+ nav.push(this.newNav(o.title, name, obj.path));
358
+ }
359
+ }
360
+ };
361
+
362
+ /**
363
+ * 获取应用标题
364
+ * @param {string} app 应用名
365
+ * @param {string} file 文件路径
366
+ * @returns {string} 应用标题
367
+ */
368
+ Nav.prototype._getAppTitle = function (app, file) {
369
+ var title = "未命名";
370
+ var app_file = file.fullname("/app/" + app + "/app.json");
371
+ if (file.hasFile(app_file)) {
372
+ var jobj = file.loadJson(app_file);
373
+ if (jobj) {
374
+ title = jobj.title;
375
+ }
376
+ }
377
+ var app_config = string.left(file + "", "plugin") + "app.json";
378
+ if (file.hasFile(app_config)) {
379
+ var oj = file.loadJson(app_config);
380
+ title = oj.title;
381
+ }
382
+ return title;
383
+ };
384
+
385
+ /**
386
+ * 设置默认路由
387
+ * @param {object} cg 配置对象
388
+ * @param {string} app 应用名
389
+ */
390
+ Nav.prototype._setDefaultRoute = function (cg, app) {
391
+ if (cg.routes.length > 0) {
392
+ cg.routes.splice(0, 0, {
393
+ name: app,
394
+ path: "/" + app,
395
+ redirect: cg.routes[0].path,
396
+ });
397
+ }
398
+ };
399
+
400
+ /**
401
+ * 新建配置
402
+ * @param {string} file 文件路径
403
+ */
404
+ Nav.prototype.newConfig = function (file) {
405
+ var cg = this.config;
406
+ var l = path.sep;
407
+ var plugin = string.left(string.right(file + "", "plugin" + l), l, true);
408
+ var dir = string.left(file + "", plugin) + "server" + l;
409
+
410
+ var app = string.left(string.right(file + "", "app" + l), l, true);
411
+ var nav = [];
412
+
413
+ if (plugin.indexOf("admin") !== -1) {
414
+ this._processManageApis(dir, app, plugin, nav, cg);
415
+ } else {
416
+ this._processClientApis(dir, app, plugin, nav, cg);
417
+ }
418
+
419
+ cg.name = app + "_" + plugin;
420
+ var title = this._getAppTitle(app, file);
421
+
422
+ this._setDefaultRoute(cg, app);
423
+
424
+ cg.main = [
425
+ {
426
+ title: title,
427
+ name: app,
428
+ icon: '<i class="fa-cog"></i>',
429
+ url: "/" + app,
430
+ display: 0,
431
+ sub: nav,
432
+ },
433
+ ];
434
+ file.saveText(file, JSON.stringify(cg, null, 4));
435
+ };
436
+
437
+ /**
438
+ * 获取API作用域和路由
439
+ * @param {string} app 应用域名
440
+ * @param {object} route 路由配置
441
+ * @returns {object} 返回作用域和路由
442
+ */
443
+ Nav.prototype._getApiScope = function (app, route) {
444
+ var { path: route_path, component } = route;
445
+ var scope = app;
446
+ var p = route_path
447
+ .replace("_table", "")
448
+ .replace("_list", "")
449
+ .replace("_view", "")
450
+ .replace("_form", "");
451
+ var api_route;
452
+ if (component.indexOf("/admin") !== -1) {
453
+ scope += "_manage";
454
+ api_route = "/apis" + p;
455
+ } else {
456
+ scope += "_client";
457
+ api_route = "/api" + p;
458
+ }
459
+ return { scope, api_route };
460
+ };
461
+
462
+ /**
463
+ * 按作用域获取API集合(方案B:可选注入 config.get_api,替代原全局 api 池)
464
+ * @param {string} scope 作用域
465
+ * @returns {object|null} API集合;未配置注入函数时告警并返回null
466
+ * @private
467
+ */
468
+ Nav.prototype._getApiByScope = function (scope) {
469
+ var getter = this.parent && this.parent.config ? this.parent.config.get_api : null;
470
+ if (typeof getter !== "function") {
471
+ this._warnNoApi();
472
+ return null;
473
+ }
474
+ return getter(scope) || null;
475
+ };
476
+
477
+ /**
478
+ * API 获取函数缺失告警(仅告警一次)
479
+ * @returns {void}
480
+ * @private
481
+ */
482
+ Nav.prototype._warnNoApi = function () {
483
+ if (this._api_warned) {
484
+ return;
485
+ }
486
+ this._api_warned = true;
487
+ this.log("warn", "未配置 get_api,API配置获取返回空值");
488
+ };
489
+
490
+ /**
491
+ * 获取API配置
492
+ * @param {string} app 应用域名
493
+ * @param {object} route 路由配置
494
+ * @returns {object} 返回api配置
495
+ */
496
+ Nav.prototype.getApi = function (app, route) {
497
+ var { scope, api_route } = this._getApiScope(app, route);
498
+ var api = this._getApiByScope(scope);
499
+ if (!api) {
500
+ scope = scope.replace(app + "_", "");
501
+ api = this._getApiByScope(scope);
502
+ }
503
+ if (!api) {
504
+ return null;
505
+ }
506
+ return this._findApiConfig(api.list, scope, api_route);
507
+ };
508
+
509
+ /**
510
+ * 查找API配置
511
+ * @param {Array} list API列表
512
+ * @param {string} scope 作用域
513
+ * @param {string} api_route API路由
514
+ * @returns {object} 返回api配置
515
+ */
516
+ Nav.prototype._findApiConfig = function (list, scope, api_route) {
517
+ var config = { api: {}, param: {}, sql: {} };
518
+ for (var i = 0; i < list.length; i++) {
519
+ var o = list[i];
520
+ if (o.config.path === api_route) {
521
+ return {
522
+ scope,
523
+ api: o.config,
524
+ param: o.param.config,
525
+ sql: o.sql.config,
526
+ };
527
+ }
528
+ }
529
+ return config;
530
+ };
531
+
532
+ /**
533
+ * 获取模板文件路径
534
+ * @param {string} name 文件名
535
+ * @param {string} plugin 插件名
536
+ * @param {string} file 文件路径
537
+ * @returns {string} 模板文件路径
538
+ */
539
+ Nav.prototype._getTplPath = function (name, plugin, file) {
540
+ var f = this.tpl_path;
541
+ var l = path.sep;
542
+
543
+ f += this._getSubDir(plugin, file, l);
544
+ f += this._getPageFile(name);
545
+
546
+ return file.fullname(f, __dirname);
547
+ };
548
+
549
+ /**
550
+ * 获取子目录
551
+ * @param {string} plugin 插件名
552
+ * @param {string} file 文件路径
553
+ * @param {string} l 分隔符
554
+ * @returns {string} 子目录
555
+ * @private
556
+ */
557
+ Nav.prototype._getSubDir = function (plugin, file, l) {
558
+ if (plugin) {
559
+ return plugin + "/";
560
+ }
561
+ var subDirs = {
562
+ mobile: "mobile/",
563
+ admin: "admin/",
564
+ pc: "pc/",
565
+ };
566
+ for (var k in subDirs) {
567
+ if (file.indexOf(k + l) !== -1) {
568
+ return subDirs[k];
569
+ }
570
+ }
571
+ return "";
572
+ };
573
+
574
+ /**
575
+ * 获取页面文件名
576
+ * @param {string} name 文件名
577
+ * @returns {string} 页面文件名
578
+ * @private
579
+ */
580
+ Nav.prototype._getPageFile = function (name) {
581
+ var pageMap = [
582
+ { suffix: "_config_form", file: "page_config_form.vue" },
583
+ { suffix: "_form", file: "page_form.vue" },
584
+ { suffix: "_view", file: "page_view.vue" },
585
+ { suffix: "_table", file: "page_table.vue" },
586
+ { suffix: "_list", file: "page_list.vue" },
587
+ { suffix: "channel", file: "page_channel.vue" },
588
+ { suffix: "type", file: "page_type.vue" },
589
+ { suffix: "nav", file: "page_nav.vue" },
590
+ { suffix: "lang", file: "page_lang.vue" },
591
+ { suffix: "config", file: "page_config.vue" },
592
+ ];
593
+ for (var i = 0; i < pageMap.length; i++) {
594
+ if (name.endsWith(pageMap[i].suffix)) {
595
+ return pageMap[i].file;
596
+ }
597
+ }
598
+ return "page_default.vue";
599
+ };
600
+
601
+ /**
602
+ * 创建视图模型
603
+ * @param {string} name 文件名
604
+ * @param {string} app 应用名
605
+ * @param {string} plugin 插件名
606
+ * @param {string} file 文件路径
607
+ * @param {Array} arr 路径数组
608
+ * @param {object} route 路由配置
609
+ * @returns {object} 视图模型
610
+ */
611
+ Nav.prototype._createViewModel = function (name, app, plugin, file, arr, route) {
612
+ var model = {
613
+ id: app + "_" + name,
614
+ name: name,
615
+ app,
616
+ plugin,
617
+ file,
618
+ group: arr[arr.length - 2],
619
+ nav_config: this.config,
620
+ route,
621
+ scope: "",
622
+ api: {},
623
+ param: {},
624
+ sql: {},
625
+ };
626
+ return Object.assign(model, this.getApi(app, route));
627
+ };
628
+
629
+ /**
630
+ * 渲染并保存vue文件
631
+ * @param {string} tpl_file 模板文件路径
632
+ * @param {object} vm 视图模型
633
+ * @param {string} file 目标文件路径
634
+ */
635
+ Nav.prototype._renderAndSaveVue = function (tpl_file, vm, file) {
636
+ var tpl = _getTpl();
637
+ if (!tpl) {
638
+ this.log("error", "模板引擎不可用,跳过vue渲染", tpl_file);
639
+ return;
640
+ }
641
+ try {
642
+ var vue = tpl.view(tpl_file, vm);
643
+ if (vue) {
644
+ file.saveText(file, vue);
645
+ } else {
646
+ this.log("error", "更新模板失败", tpl.error);
647
+ }
648
+ } catch (err) {
649
+ this.log("error", "更新模板失败", err);
650
+ }
651
+ };
652
+
653
+ /**
654
+ * 创建vue文件
655
+ * @param {string} filename 文件保存路径
656
+ * @param {object} route 路由配置
657
+ */
658
+ Nav.prototype.createVue = async function (filename, route) {
659
+ var file = filename;
660
+ var l = path.sep;
661
+ file = file.replace(process.cwd(), "/");
662
+ var arr = file.substring(file.indexOf("app")).split(l);
663
+
664
+ var name = arr[arr.length - 1].replace(".vue", "");
665
+ var plugin = "";
666
+ var app = "";
667
+
668
+ if (arr.length > 3) {
669
+ plugin = arr[3];
670
+ app = arr[1];
671
+ }
672
+
673
+ var tpl_file = this._getTplPath(name, plugin, file);
674
+ var model = this._createViewModel(name, app, plugin, file, arr, route);
675
+
676
+ var vm = await VIEW_MODEL.run(model);
677
+ vm.JSON = JSON;
678
+
679
+ this._renderAndSaveVue(tpl_file, vm, file);
680
+ };
681
+
682
+ /**
683
+ * 创建路径
684
+ * @param {string} filepath 文件路径
685
+ */
686
+ Nav.prototype.mkdir = function (filepath) {
687
+ var l = path.sep;
688
+ var arr = filepath.split(l);
689
+ var dir = arr[0];
690
+ for (var i = 1; i < arr.length; i++) {
691
+ if (!fs.existsSync(dir)) {
692
+ fs.mkdirSync(dir);
693
+ }
694
+ dir = dir + l + arr[i];
695
+ }
696
+ };
697
+
698
+ /**
699
+ * 获取Vue文件目录
700
+ * @param {Array} routes 路由列表
701
+ * @returns {object} 返回路径信息
702
+ */
703
+ Nav.prototype._getVueDirInfo = function (routes) {
704
+ for (var i = 0; i < routes.length; i++) {
705
+ var f = routes[i].component;
706
+ if (f) {
707
+ var p = path.dirname(f).replace(/\\/g, "/");
708
+ var fl = f.replace("/", "").replace("/", "\\plugin\\").replace("/", "\\static\\");
709
+ var dir = path.dirname(file.fullname("./app/" + fl));
710
+ return { p, dir };
711
+ }
712
+ }
713
+ return { p: "", dir: "" };
714
+ };
715
+
716
+ /**
717
+ * 创建Vue文件
718
+ * @param {object} route 路由配置
719
+ * @param {string} p 原始路径
720
+ * @param {string} dir 目标目录
721
+ * @param {boolean} cover 是否覆盖
722
+ */
723
+ Nav.prototype._createVueFile = async function (route, p, dir, cover) {
724
+ var f = route.component;
725
+ if (!f) return;
726
+ var file = f.replace(p, dir).fullname();
727
+ if (cover || !file.hasFile(file)) {
728
+ this.mkdir(file);
729
+ await this.createVue(file, route);
730
+ }
731
+ };
732
+
733
+ /**
734
+ * 更新路由vue文件
735
+ * @param {string} route_path 路由路径
736
+ * @param {boolean} cover 是否覆盖文件
737
+ */
738
+ Nav.prototype.updateVue = async function (route_path, cover) {
739
+ var lt = this.config.routes;
740
+ var { p, dir } = this._getVueDirInfo(lt);
741
+ if (!dir) return;
742
+
743
+ for (var i = 0; i < lt.length; i++) {
744
+ if (route_path && lt[i].path.indexOf(route_path) === -1) continue;
745
+ await this._createVueFile(lt[i], p, dir, cover);
746
+ }
747
+ };
748
+
749
+ /**
750
+ * 获取模型
751
+ * @param {string} type 模型类型
752
+ * @returns {object} 返回获取到的模型
753
+ */
754
+ Nav.prototype.getModel = function (type) {
755
+ let model = { ...this.config };
756
+ let dir = this.config.dir || "";
757
+ let l = path.sep;
758
+ let app_name = string.between(dir, "app" + l, l);
759
+ let plugin_name = string.between(dir, "plugin" + l, l);
760
+ let name = path.basename(dir);
761
+ model.app = app_name;
762
+ model.plugin = plugin_name;
763
+ model.name = model.name || name;
764
+ return model;
765
+ };
766
+
767
+ module.exports = Nav;