create-yoya-ui 0.2.1 → 0.2.3

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 (75) hide show
  1. package/README.md +11 -10
  2. package/bin/create-yoya-ui.js +1 -1
  3. package/package.json +1 -1
  4. package/templates/admin/README.md +59 -47
  5. package/templates/admin/RULES.md +105 -0
  6. package/templates/admin/src/features/dashboard/todos/pages/todo-approval-page.js +5 -0
  7. package/templates/admin/src/features/ops/deploys/pages/deploy-list-page.js +5 -0
  8. package/templates/admin/src/features/ops/services/pages/service-list-page.js +5 -0
  9. package/templates/admin/src/features/{dicts → system/dicts}/api/dict.mgr.d.ts +24 -17
  10. package/templates/admin/src/features/{dicts → system/dicts}/api/dict.mgr.js +24 -14
  11. package/templates/admin/src/features/{dicts → system/dicts}/api/dict.mock.js +22 -4
  12. package/templates/admin/src/features/{dicts → system/dicts}/api/dict.state.d.ts +5 -0
  13. package/templates/admin/src/features/{dicts → system/dicts}/api/dict.state.js +39 -8
  14. package/templates/admin/src/features/{dicts → system/dicts}/components/dict-editor-dialog.js +1 -1
  15. package/templates/admin/src/features/{dicts → system/dicts}/pages/dict-list-page.js +41 -21
  16. package/templates/admin/src/features/{members → system/members}/api/member.mgr.d.ts +10 -9
  17. package/templates/admin/src/features/{members → system/members}/api/member.mgr.js +8 -3
  18. package/templates/admin/src/features/{members → system/members}/api/member.mock.js +1 -1
  19. package/templates/admin/src/features/{members → system/members}/api/member.req.d.ts +1 -1
  20. package/templates/admin/src/features/{members → system/members}/api/member.req.js +3 -1
  21. package/templates/admin/src/features/{members → system/members}/api/member.state.js +4 -4
  22. package/templates/admin/src/features/{members → system/members}/components/member-table.js +1 -1
  23. package/templates/admin/src/features/{permissions → system/permissions}/api/permission.mgr.d.ts +11 -9
  24. package/templates/admin/src/features/{permissions → system/permissions}/api/permission.mgr.js +10 -5
  25. package/templates/admin/src/features/{permissions → system/permissions}/api/permission.mock.js +1 -1
  26. package/templates/admin/src/features/{permissions → system/permissions}/api/permission.state.js +4 -4
  27. package/templates/admin/src/features/{permissions → system/permissions}/pages/permission-list-page.js +1 -1
  28. package/templates/admin/src/features/{roles → system/roles}/api/role.mgr.d.ts +19 -6
  29. package/templates/admin/src/features/{roles → system/roles}/api/role.mgr.js +8 -3
  30. package/templates/admin/src/features/{roles → system/roles}/api/role.mock.js +1 -1
  31. package/templates/admin/src/features/{roles → system/roles}/api/role.state.js +4 -4
  32. package/templates/admin/src/features/{roles → system/roles}/components/role-table.js +1 -1
  33. package/templates/admin/src/main.js +16 -12
  34. package/templates/admin/src/{ui/row-action-button.js → shared/ui.buttons.js} +1 -0
  35. package/templates/admin/src/{ui/placeholder-page.js → shared/ui.pages.js} +1 -0
  36. package/templates/admin/src/shell/api/shell.mock.js +42 -0
  37. package/templates/admin/src/shell/api/shell.req.js +17 -0
  38. package/templates/admin/src/shell/api/shell.state.js +90 -0
  39. package/templates/admin/src/shell/api/shell.views.js +19 -0
  40. package/templates/admin/src/shell/components/admin-shell.js +42 -0
  41. package/templates/admin/src/{ui → shell/components}/app-navbar.js +11 -12
  42. package/templates/admin/src/shell/components/app-sidebar.js +44 -0
  43. package/templates/admin/src/{ui → shell/components}/sidebar-menu.js +3 -3
  44. package/templates/admin/src/shell/router.js +40 -0
  45. package/templates/admin/node_modules/.vite/deps/_metadata.json +0 -8
  46. package/templates/admin/node_modules/.vite/deps/package.json +0 -3
  47. package/templates/admin/src/app/admin-shell.js +0 -51
  48. package/templates/admin/src/app/modules.js +0 -37
  49. package/templates/admin/src/app/router.js +0 -20
  50. package/templates/admin/src/ui/app-sidebar.js +0 -27
  51. /package/templates/admin/src/features/dashboard/{components → overview/components}/dashboard-chart.js +0 -0
  52. /package/templates/admin/src/features/dashboard/{pages → overview/pages}/dashboard-overview-page.js +0 -0
  53. /package/templates/admin/src/features/{dicts → system/dicts}/api/dict.views.d.ts +0 -0
  54. /package/templates/admin/src/features/{dicts → system/dicts}/api/dict.views.js +0 -0
  55. /package/templates/admin/src/features/{dicts → system/dicts}/components/dict-item-form-dialog.js +0 -0
  56. /package/templates/admin/src/features/{dicts → system/dicts}/utils/options.js +0 -0
  57. /package/templates/admin/src/features/{members → system/members}/api/member.state.d.ts +0 -0
  58. /package/templates/admin/src/features/{members → system/members}/api/member.views.d.ts +0 -0
  59. /package/templates/admin/src/features/{members → system/members}/api/member.views.js +0 -0
  60. /package/templates/admin/src/features/{members → system/members}/components/member-form-dialog.js +0 -0
  61. /package/templates/admin/src/features/{members → system/members}/components/member-toolbar.js +0 -0
  62. /package/templates/admin/src/features/{members → system/members}/pages/member-list-page.js +0 -0
  63. /package/templates/admin/src/features/{members → system/members}/utils/options.d.ts +0 -0
  64. /package/templates/admin/src/features/{members → system/members}/utils/options.js +0 -0
  65. /package/templates/admin/src/features/{permissions → system/permissions}/api/permission.state.d.ts +0 -0
  66. /package/templates/admin/src/features/{permissions → system/permissions}/api/permission.views.d.ts +0 -0
  67. /package/templates/admin/src/features/{permissions → system/permissions}/api/permission.views.js +0 -0
  68. /package/templates/admin/src/features/{permissions → system/permissions}/components/permission-form-dialog.js +0 -0
  69. /package/templates/admin/src/features/{roles → system/roles}/api/role.state.d.ts +0 -0
  70. /package/templates/admin/src/features/{roles → system/roles}/api/role.views.d.ts +0 -0
  71. /package/templates/admin/src/features/{roles → system/roles}/api/role.views.js +0 -0
  72. /package/templates/admin/src/features/{roles → system/roles}/components/role-form-dialog.js +0 -0
  73. /package/templates/admin/src/features/{roles → system/roles}/components/role-toolbar.js +0 -0
  74. /package/templates/admin/src/features/{roles → system/roles}/pages/role-list-page.js +0 -0
  75. /package/templates/admin/src/features/{roles → system/roles}/utils/options.js +0 -0
package/README.md CHANGED
@@ -1,23 +1,24 @@
1
1
  # create-yoya-ui
2
2
 
3
- 快速搭建 [yoya-ui](https://github.com/yoyaflow/yoya-ui) 项目的脚手架。
3
+ 快速体验 [yoya-ui](https://github.com/yoyaflow/yoya-ui) 的脚手架。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install -g create-yoya-ui
9
+ ```
4
10
 
5
11
  ## 用法
6
12
 
7
13
  ```bash
8
- npx create-yoya-ui@latest my-app # basic 模板(SPA)
9
- npx create-yoya-ui@latest my-app --template ssr # SSR 模板
10
- npx create-yoya-ui@latest my-app --template admin # 后台管理模板
14
+ create-yoya-ui my-app --template admin
11
15
  cd my-app
12
16
  npm install
17
+ npm run dev
13
18
  ```
14
19
 
15
- - **basic**:默认模板,`npm run dev` 启动 Vite 开发服务器
16
- - **ssr**:服务端渲染模板,`npm run build && npm start`(renderPage 整页渲染 + hydrateOrMount 客户端接入)
17
- - **admin**:标准后台管理模板(顶部导航 + 可折叠侧栏 + RouterViews 内容区)
20
+ - **admin**:标准后台管理模板(顶部导航 + 左侧菜单 + RouterViews 内容区)
18
21
 
19
22
  ## 模板内容
20
23
 
21
- - `templates/basic`:页面壳、按钮事件、表单收集校验、主题切换
22
- - `templates/ssr`:home-page.js(页面组件 + 词典)、server.mjs(node:http + renderPage)、client.js(hydrateOrMount)
23
- - `templates/admin`:标准后台管理模板(logo/系统名、顶部导航、用户头像、可折叠菜单、带标题内容区),内置数据概览看板与图表,以及成员 / 角色 / 权限 / 字典管理示例
24
+ - `templates/admin`:标准后台管理模板(logo/系统名、顶部导航、用户头像、左侧菜单、带标题内容区),内置数据概览看板与图表,以及成员 / 角色 / 权限 / 字典管理示例
@@ -41,7 +41,7 @@ if (templateName === 'ssr') {
41
41
  } else {
42
42
  console.log(' npm run dev');
43
43
  console.log(
44
- `\n${templateName === 'admin' ? '管理后台模板:顶部导航 + 可折叠侧栏 + RouterViews 内容区。' : ''}更多:npm run build 构建,npm run preview 预览产物。\n`
44
+ `\n${templateName === 'admin' ? '管理后台模板:顶部导航 + 左侧菜单 + RouterViews 内容区。' : ''}更多:npm run build 构建,npm run preview 预览产物。\n`
45
45
  );
46
46
  }
47
47
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-yoya-ui",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Scaffold a new yoya-ui project with Vite: basic template (SPA) or SSR template (renderPage + hydrateOrMount).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -5,7 +5,7 @@
5
5
  - 左上角:logo + 系统名
6
6
  - 中间:顶级导航
7
7
  - 右上角:用户头像
8
- - 下方:左侧可折叠菜单 + 右侧带标题的 RouterViews 内容区
8
+ - 下方:左侧菜单 + 右侧带标题的 RouterViews 内容区
9
9
  - 点击顶级导航切换左侧菜单与内容路由
10
10
 
11
11
  ## 启动
@@ -23,55 +23,67 @@ npm run dev
23
23
 
24
24
  ```text
25
25
  src/
26
- main.js 入口:初始化主题、创建路由与外壳并挂载
26
+ main.js 入口:初始化主题、加载菜单状态、装配外壳并挂载
27
27
  api/
28
28
  fetch.api.js 原始传输层(fetch 实现,换请求库只改这里)
29
29
  domain.api.js 领域请求入口:统一 Result 解析 + mock/真实切换
30
- app/
31
- modules.js 模块配置(顶级导航 左侧菜单 → 路由)
32
- router.js 路由组装(占位页兜底)
33
- admin-shell.js AdminShell 页面组件(顶栏 + 侧栏 + 内容区组合)
34
- ui/
35
- placeholder-page.js PlaceholderPage 通用占位页
36
- app-navbar.js AppNavbar 顶部导航(logo + 顶级导航 + 主题/头像)
37
- app-sidebar.js AppSidebar 左侧导航外壳
38
- sidebar-menu.js SidebarMenu 模块菜单组件
39
- features/
40
- dashboard/ 工作台(数据概览示例:数字看板 / 趋势卡 / 图表)
41
- pages/dashboard-overview-page.js 页面编排:核心指标看板 + 趋势卡 + 图表 + 资源使用
42
- components/dashboard-chart.js vChart 内置 SVG 适配器(柱状图 / 折线图)
43
- members/ 成员管理业务域(CRUD 示例)
44
- pages/member-list-page.js 页面编排:组合工具栏、表格、弹窗与分页
45
- components/
46
- member-toolbar.js MemberToolbar 搜索/新增工具栏
47
- member-table.js MemberTable 成员表格
48
- member-form-dialog.js MemberFormDialog 新增/编辑弹窗
49
- api/
50
- member.mgr.js 管理请求命令(增删改查等)
51
- member.req.js 外部请求命令(其他模块调用本域能力)
52
- member.views.js 领域结果结构(列表项 / 详情)
53
- member.state.js 状态类 MembersPageState:持有数据与筛选,动作 submit 命令后驱动视图
54
- member.mock.js 演示用内存 mock(接入真实后端后删除)
55
- utils/options.js 领域常量(角色/状态选项与文案)
56
- permissions/ 权限管理业务域(vTree 权限树示例)
57
- pages/permission-list-page.js 页面编排:权限树 + 工具栏 + 表单弹窗 + 删除确认
58
- components/
59
- permission-form-dialog.js PermissionFormDialog 新增/编辑权限弹窗
60
- api/
61
- permission.mgr.js 权限管理请求命令(查询树 / 新增 / 编辑 / 删除)
62
- permission.state.js 状态类 PermissionsPageState
63
- permission.views.js 权限节点结构
64
- permission.mock.js 演示用内存 mock
65
- roles/ 角色管理业务域(分页 CRUD 示例)
66
- pages/role-list-page.js 页面编排:搜索 + 表格 + 分页 + 表单弹窗
67
- components/ RoleToolbar / RoleTable / RoleFormDialog
68
- api/ 请求命令 / 状态类 / 结果结构 / mock
69
- dicts/ 字典管理业务域(字典类型 + 字典项主从示例)
70
- pages/dict-list-page.js 页面编排:字典类型表格 + 编辑弹窗(基本信息 + 字典值表格)
71
- components/ DictEditorDialog / DictItemFormDialog
72
- api/ 请求命令 / 状态类 / 结果结构 / mock
30
+ shared/ 跨模块共享(按类别集中管理)
31
+ ui.buttons.js 按钮类共享 UI(RowActionButton 行内操作按钮)
32
+ ui.pages.js 页面类共享 UI(PlaceholderPage 路由占位页)
33
+ shell/ 应用外壳(按 api / components 组织)
34
+ api/
35
+ shell.req.js 外壳请求命令:QueryMenus 获取菜单(可换服务端接口)
36
+ shell.mock.js 外壳 mock:模拟服务端返回(viewKey 由客户端映射页面)
37
+ shell.views.js 外壳结果结构(Module / Route)
38
+ shell.state.js 外壳状态类 ShellState:菜单 + 导航状态(当前模块/路径),加载时创建并持有路由,暴露导航动作(switchModule / navigate)
39
+ components/
40
+ admin-shell.js AdminShell 外壳装配(布局组装 + 顶栏/侧栏从状态派生)
41
+ app-navbar.js AppNavbar 顶部导航(logo + 顶级导航 + 主题/头像)
42
+ app-sidebar.js AppSidebar 左侧导航外壳
43
+ sidebar-menu.js SidebarMenu 模块菜单组件
44
+ router.js 路由组装:viewKey → 页面组件映射 + 404 占位页兜底
45
+ features/ 业务域 = 父模块节点(对应顶级菜单),下按菜单项分子模块
46
+ dashboard/ 工作台
47
+ overview/ 数据概览
48
+ pages/dashboard-overview-page.js 页面编排:核心指标看板 + 趋势卡 + 图表 + 资源使用
49
+ components/dashboard-chart.js vChart 内置 SVG 适配器(柱状图 / 折线图)
50
+ todos/ 待办审批(简单页示例)
51
+ pages/todo-approval-page.js
52
+ ops/ 运维
53
+ services/ 服务清单(简单页示例)
54
+ pages/service-list-page.js
55
+ deploys/ 部署任务(简单页示例)
56
+ pages/deploy-list-page.js
57
+ system/ 系统
58
+ members/ 成员管理业务域(CRUD 完整模块示例)
59
+ pages/member-list-page.js 页面编排:组合工具栏、表格、弹窗与分页
60
+ components/
61
+ member-toolbar.js MemberToolbar 搜索/新增工具栏
62
+ member-table.js MemberTable 成员表格
63
+ member-form-dialog.js MemberFormDialog 新增/编辑弹窗
64
+ api/
65
+ member.mgr.js 管理请求命令(增删改查等)
66
+ member.req.js 外部请求命令(其他模块调用本域能力)
67
+ member.views.js 领域结果结构(列表项 / 详情)
68
+ member.state.js 状态类 MembersPageState:持有数据与筛选,动作 submit 命令后驱动视图
69
+ member.mock.js 演示用内存 mock(接入真实后端后删除)
70
+ utils/options.js 领域常量(角色/状态选项与文案)
71
+ roles/ 角色管理业务域(分页 CRUD 示例)
72
+ pages/role-list-page.js 页面编排:搜索 + 表格 + 分页 + 表单弹窗
73
+ components/ RoleToolbar / RoleTable / RoleFormDialog
74
+ api/ 请求命令 / 状态类 / 结果结构 / mock
75
+ permissions/ 权限管理业务域(vTree 权限树示例)
76
+ pages/permission-list-page.js 页面编排:权限树 + 工具栏 + 表单弹窗 + 删除确认
77
+ components/ PermissionFormDialog
78
+ api/ 请求命令 / 状态类 / 结果结构 / mock
79
+ dicts/ 字典管理业务域(字典类型 + 字典项主从示例)
80
+ pages/dict-list-page.js 页面编排:字典类型表格 + 编辑弹窗(基本信息 + 字典值表格)
81
+ components/ DictEditorDialog / DictItemFormDialog
82
+ api/ 请求命令 / 状态类 / 结果结构 / mock
73
83
  ```
74
84
 
75
- 目录规则遵循 yoya-ui skill 的业务模块组织(feature 自包含、页面只编排、service 里 api 管数据交互、state 管状态)。
85
+ 目录规则遵循 yoya-ui skill 的业务模块组织(feature 自包含、页面只编排、api 管数据交互、state 管状态)。每个菜单项对应 `features/` 下的一个子模块目录;简单页只放 `pages/` 文件,有数据交互的页面展开 api / components / pages / utils。
76
86
 
77
- 扩展新模块:在 `app/modules.js` `modules` 数组里加一组 `{ key, label, icon, routes }`;有数据交互的页面参考 `features/members` 的 api / pages 分层。
87
+ 扩展新模块:在 `features/` 下建父模块目录(如 `features/orders/`),每个菜单项对应一个子目录;在 `shell/api/shell.mock.js` 模拟返回的菜单数据里加一组 `{ key, label, icon, routes }`(key 与父目录名一致),并把菜单项的 `viewKey` 注册到 `shell/router.js` 的视图注册表。接入真实后端时删除 `shell.mock.js`,由服务端返回同样的菜单结构即可。简单页只放 `pages/` 文件,有数据交互的页面参考 `features/system/members` 的 api / components / pages 分层。
88
+
89
+ 完整开发规则见 [RULES.md](./RULES.md)(目录结构、命名、api 分层、请求命令范式、共享组件、导航状态等)。
@@ -0,0 +1,105 @@
1
+ # yoya-ui admin 模板开发规则
2
+
3
+ 本文件是 admin 模板的开发规则全集:目录结构、命名、api 分层、请求命令范式、共享组件、导航状态、页面与 mock 接入。以代码为准,新增/修改功能时先对照本文件。
4
+
5
+ ## 1. 目录结构
6
+
7
+ ```text
8
+ src/
9
+ main.js 装配根:注册 mock → 加载状态 → 装配外壳 → 启动
10
+ api/ 全局传输层(fetch.api.js / domain.api.js)
11
+ shared/ 跨模块共享(按类别集中)
12
+ shell/ 应用外壳(也是模块,按 api / components 组织)
13
+ features/ 业务域 = 父模块节点(对应顶级菜单)
14
+ <父模块>/<菜单项>/ 每个菜单项一个子模块,自包含 api / components / pages / utils
15
+ ```
16
+
17
+ - **配置即目录**:菜单 `key` = features 父目录名 = 路由前缀(`system` ↔ `features/system/` ↔ `/system/members`)
18
+ - **模块自包含**:叶子模块只依赖自己的 api / components / pages / utils,不跨模块 import 内部实现
19
+ - **依赖方向**:跨模块唯一允许的引用是业务域 `req.js`(对外能力入口);`shared → features/<域>/api/req.js` 是允许的公开单向依赖
20
+
21
+ ## 2. 文件命名
22
+
23
+ - api 层:`<域>.<层>.js`(`member.mgr.js`、`shell.req.js`、`ui.buttons.js`)
24
+ - 页面:`<名字>-page.js`(`member-list-page.js`、`todo-approval-page.js`)
25
+ - 组件:PascalCase(`AdminShell`、`MemberTable`)
26
+ - 共享 UI 类别文件:`ui.<类别>.js`(`ui.buttons.js`、`ui.pages.js`)
27
+
28
+ ## 3. api 分层
29
+
30
+ 每个业务域(含外壳)的 `api/` 按职责分文件:
31
+
32
+ - `mgr.js`:本域管理请求命令(增删改查等)
33
+ - `req.js`:对外能力入口(其他模块 / 共享组件调用本域时使用)
34
+ - `views.js`:领域结果结构(纯数据类),由命令的 `toItem / toDetail` 映射
35
+ - `state.js`:状态类,持有数据与筛选,`subscribe(listener)` 通知视图更新
36
+ - `mock.js`:演示用内存 mock(接入真实后端后删除)
37
+
38
+ 判据:有管理动作用 `mgr.js`;只提供查询给外部用 `req.js`;两者可并存(如 `member.mgr.js` + `member.req.js`)。
39
+
40
+ ## 4. 请求命令范式
41
+
42
+ - 构造器收**单一 `init` 对象**,`id` / `parentId` / `typeId` 等字段也放里面,不单独取参数
43
+ - 导出为工厂:`命令名: (init) => new 命令类(init)`
44
+ - 消费方:`Mgr.命令({ ... }).submit()`,不写 `new`
45
+ - 命令类继承 `RequestBase`,覆写 `address() / method() / params() / body() / toItem() / toDetail()`
46
+
47
+ ```js
48
+ export default {
49
+ Query: (init) => new Query(init),
50
+ Create: (init) => new Create(init),
51
+ Update: (init) => new Update(init),
52
+ Remove: (init) => new Remove(init)
53
+ };
54
+ ```
55
+
56
+ ## 5. 共享组件
57
+
58
+ - **通用 UI**(无业务语义):放 `shared/ui.<类别>.js`
59
+ - **业务共享组件**(带业务语义且多模块使用):放 `shared/<组件>/` 自包含子目录(组件 + 状态 + 文案),对外只暴露工厂
60
+ - **数据获取走 req.js**:共享组件需要业务数据时调用所属域 `api/<域>.req.js` 的公开能力(如 `MemberReq.QueryAvailable().submit()`),不自造数据请求、不注入数据源
61
+ - **不深层 import**:只允许跨模块引用 `req.js`,不 import 业务域的 pages / components / state 内部实现
62
+ - **自包含 UI 与状态**:弹窗、下拉、open/close 状态内聚在组件内,对外暴露工厂与必要方法(`open()/close()/value()`),不暴露内部状态实现
63
+ - **浮层自洽**:弹窗/下拉类共享组件自带 fixed 定位逻辑,不依赖使用方容器样式
64
+
65
+ ## 6. 外壳与导航状态
66
+
67
+ - `ShellState` 是导航状态(当前模块 / 当前路径)的**唯一事实源**,持有 router,暴露 `switchModule(module)` / `navigate(path)`
68
+ - 路由订阅驱动同步:`router.subscribe → state.syncFromPath(path)`,状态变化时通知订阅者
69
+ - 顶栏 / 侧栏从状态**派生高亮**,组件不持有自己的激活状态
70
+ - `AdminShell` 只做装配:布局组装 + 状态接线,不直接操作 router
71
+ - 组件统一写法:节点在 `render()` 内声明式构建,内部引用(如 sidebar 实例、items Map)只用于动态更新
72
+ - 前进 / 后退、同模块内切换路由的高亮同步由状态管道自动完成,不需要手动调用
73
+
74
+ ## 7. 页面规则
75
+
76
+ - **简单 / 占位页**:只放 `pages/<页面>-page.js`,可复用 `shared/ui.pages.js` 的 `PlaceholderPage`
77
+ - **有数据交互的页面**:展开完整模块(api / components / pages / utils)
78
+ - 页面只做编排:组合子组件、绑定事件、调用 state 动作,不写请求逻辑
79
+
80
+ ## 8. mock 与数据接入
81
+
82
+ - 所有 mock 在 `main.js` 导入注册(副作用导入)
83
+ - mock 返回 `{ ok, data }` 结构,统一经 `Result.from` 解析
84
+ - 接入真实后端:删除对应 `mock.js`(或替换为真实接口),调用方零改动
85
+
86
+ ## 9. 类型声明同步
87
+
88
+ - 改了 mgr / req / views / state 的 js 接口,必须同步对应 `d.ts`
89
+ - `d.ts` 与运行时一致:导出为工厂函数类型(如 `(init?) => Query`),不用 `typeof` 构造器类型
90
+
91
+ ## 10. 新增菜单项 checklist(三处同步)
92
+
93
+ 1. `features/` 建父模块目录与菜单项子目录、页面文件
94
+ 2. `shell/api/shell.mock.js` 菜单数据加 `{ key, label, icon, routes: [{ path, title, viewKey }] }`,`key` 与目录名一致
95
+ 3. `shell/router.js` 的 `viewRegistry` 注册 `viewKey → 页面组件`
96
+
97
+ ## 11. 启动流程
98
+
99
+ `main.js` 固定顺序:
100
+
101
+ 1. 导入并注册所有 mock(含 `shell.mock.js`)
102
+ 2. `state.load()`:获取菜单 + 创建路由 + 订阅导航
103
+ 3. `AdminShell({ state })` 装配外壳
104
+ 4. `shell.render().bindTo('#app')`
105
+ 5. `state.start()` 启动路由
@@ -0,0 +1,5 @@
1
+ import { PlaceholderPage } from '../../../../shared/ui.pages.js';
2
+
3
+ export function TodoApprovalPage() {
4
+ return PlaceholderPage({ title: '待办审批', text: '待处理审批与任务。' });
5
+ }
@@ -0,0 +1,5 @@
1
+ import { PlaceholderPage } from '../../../../shared/ui.pages.js';
2
+
3
+ export function DeployListPage() {
4
+ return PlaceholderPage({ title: '部署任务', text: '发布记录与执行状态。' });
5
+ }
@@ -0,0 +1,5 @@
1
+ import { PlaceholderPage } from '../../../../shared/ui.pages.js';
2
+
3
+ export function ServiceListPage() {
4
+ return PlaceholderPage({ title: '服务清单', text: '服务列表与健康状态。' });
5
+ }
@@ -6,7 +6,9 @@ type DictTypeInstance = InstanceType<typeof Dicts.DictTypeItem>;
6
6
  type DictItemInstance = InstanceType<typeof Dicts.DictItem>;
7
7
 
8
8
  declare class QueryTypes extends RequestBase {
9
+ constructor(init?: { page?: number; pageSize?: number });
9
10
  address(): string;
11
+ params(): { page: number; pageSize: number };
10
12
  toItem(row: Record<string, unknown>): DictTypeInstance;
11
13
  }
12
14
 
@@ -19,8 +21,7 @@ declare class CreateType extends RequestBase {
19
21
 
20
22
  declare class UpdateType extends RequestBase {
21
23
  constructor(
22
- id: number,
23
- init?: { name?: string; code?: string; status?: DictStatus; remark?: string }
24
+ init?: { id: number; name?: string; code?: string; status?: DictStatus; remark?: string }
24
25
  );
25
26
  method(): 'PUT';
26
27
  address(): string;
@@ -28,21 +29,20 @@ declare class UpdateType extends RequestBase {
28
29
  }
29
30
 
30
31
  declare class RemoveType extends RequestBase {
31
- constructor(id: number);
32
+ constructor(init?: { id: number });
32
33
  method(): 'DELETE';
33
34
  address(): string;
34
35
  }
35
36
 
36
37
  declare class QueryItems extends RequestBase {
37
- constructor(typeId: number);
38
+ constructor(init?: { typeId: number });
38
39
  address(): string;
39
40
  toItem(row: Record<string, unknown>): DictItemInstance;
40
41
  }
41
42
 
42
43
  declare class CreateItem extends RequestBase {
43
44
  constructor(
44
- typeId: number,
45
- init?: { label?: string; value?: string; sort?: number; status?: DictStatus }
45
+ init?: { typeId: number; label?: string; value?: string; sort?: number; status?: DictStatus }
46
46
  );
47
47
  method(): 'POST';
48
48
  address(): string;
@@ -51,8 +51,7 @@ declare class CreateItem extends RequestBase {
51
51
 
52
52
  declare class UpdateItem extends RequestBase {
53
53
  constructor(
54
- id: number,
55
- init?: { label?: string; value?: string; sort?: number; status?: DictStatus }
54
+ init?: { id: number; label?: string; value?: string; sort?: number; status?: DictStatus }
56
55
  );
57
56
  method(): 'PUT';
58
57
  address(): string;
@@ -60,20 +59,28 @@ declare class UpdateItem extends RequestBase {
60
59
  }
61
60
 
62
61
  declare class RemoveItem extends RequestBase {
63
- constructor(id: number);
62
+ constructor(init?: { id: number });
64
63
  method(): 'DELETE';
65
64
  address(): string;
66
65
  }
67
66
 
68
67
  declare const DictMgr: {
69
- QueryTypes: typeof QueryTypes;
70
- CreateType: typeof CreateType;
71
- UpdateType: typeof UpdateType;
72
- RemoveType: typeof RemoveType;
73
- QueryItems: typeof QueryItems;
74
- CreateItem: typeof CreateItem;
75
- UpdateItem: typeof UpdateItem;
76
- RemoveItem: typeof RemoveItem;
68
+ QueryTypes: (init?: { page?: number; pageSize?: number }) => QueryTypes;
69
+ CreateType: (
70
+ init?: { name?: string; code?: string; status?: DictStatus; remark?: string }
71
+ ) => CreateType;
72
+ UpdateType: (
73
+ init?: { id: number; name?: string; code?: string; status?: DictStatus; remark?: string }
74
+ ) => UpdateType;
75
+ RemoveType: (init?: { id: number }) => RemoveType;
76
+ QueryItems: (init?: { typeId: number }) => QueryItems;
77
+ CreateItem: (
78
+ init?: { typeId: number; label?: string; value?: string; sort?: number; status?: DictStatus }
79
+ ) => CreateItem;
80
+ UpdateItem: (
81
+ init?: { id: number; label?: string; value?: string; sort?: number; status?: DictStatus }
82
+ ) => UpdateItem;
83
+ RemoveItem: (init?: { id: number }) => RemoveItem;
77
84
  };
78
85
 
79
86
  export default DictMgr;
@@ -3,10 +3,20 @@ import { RequestBase } from '@yoyaflow/yoya-ui';
3
3
  import Dicts from './dict.views.js';
4
4
 
5
5
  class QueryTypes extends RequestBase {
6
+ constructor({ page = 1, pageSize = 10 } = {}) {
7
+ super();
8
+ this.page = page;
9
+ this.pageSize = pageSize;
10
+ }
11
+
6
12
  address() {
7
13
  return '/dicts/types';
8
14
  }
9
15
 
16
+ params() {
17
+ return { page: this.page, pageSize: this.pageSize };
18
+ }
19
+
10
20
  toItem(row) {
11
21
  return new Dicts.DictTypeItem(row);
12
22
  }
@@ -35,7 +45,7 @@ class CreateType extends RequestBase {
35
45
  }
36
46
 
37
47
  class UpdateType extends RequestBase {
38
- constructor(id, { name = '', code = '', status = 'active', remark = '' } = {}) {
48
+ constructor({ id, name = '', code = '', status = 'active', remark = '' } = {}) {
39
49
  super();
40
50
  this.id = id;
41
51
  this.name = name;
@@ -58,7 +68,7 @@ class UpdateType extends RequestBase {
58
68
  }
59
69
 
60
70
  class RemoveType extends RequestBase {
61
- constructor(id) {
71
+ constructor({ id } = {}) {
62
72
  super();
63
73
  this.id = id;
64
74
  }
@@ -73,7 +83,7 @@ class RemoveType extends RequestBase {
73
83
  }
74
84
 
75
85
  class QueryItems extends RequestBase {
76
- constructor(typeId) {
86
+ constructor({ typeId } = {}) {
77
87
  super();
78
88
  this.typeId = typeId;
79
89
  }
@@ -88,7 +98,7 @@ class QueryItems extends RequestBase {
88
98
  }
89
99
 
90
100
  class CreateItem extends RequestBase {
91
- constructor(typeId, { label = '', value = '', sort = 0, status = 'active' } = {}) {
101
+ constructor({ typeId, label = '', value = '', sort = 0, status = 'active' } = {}) {
92
102
  super();
93
103
  this.typeId = typeId;
94
104
  this.label = label;
@@ -111,7 +121,7 @@ class CreateItem extends RequestBase {
111
121
  }
112
122
 
113
123
  class UpdateItem extends RequestBase {
114
- constructor(id, { label = '', value = '', sort = 0, status = 'active' } = {}) {
124
+ constructor({ id, label = '', value = '', sort = 0, status = 'active' } = {}) {
115
125
  super();
116
126
  this.id = id;
117
127
  this.label = label;
@@ -134,7 +144,7 @@ class UpdateItem extends RequestBase {
134
144
  }
135
145
 
136
146
  class RemoveItem extends RequestBase {
137
- constructor(id) {
147
+ constructor({ id } = {}) {
138
148
  super();
139
149
  this.id = id;
140
150
  }
@@ -149,12 +159,12 @@ class RemoveItem extends RequestBase {
149
159
  }
150
160
 
151
161
  export default {
152
- QueryTypes,
153
- CreateType,
154
- UpdateType,
155
- RemoveType,
156
- QueryItems,
157
- CreateItem,
158
- UpdateItem,
159
- RemoveItem
162
+ QueryTypes: (init) => new QueryTypes(init),
163
+ CreateType: (init) => new CreateType(init),
164
+ UpdateType: (init) => new UpdateType(init),
165
+ RemoveType: (init) => new RemoveType(init),
166
+ QueryItems: (init) => new QueryItems(init),
167
+ CreateItem: (init) => new CreateItem(init),
168
+ UpdateItem: (init) => new UpdateItem(init),
169
+ RemoveItem: (init) => new RemoveItem(init)
160
170
  };
@@ -1,10 +1,19 @@
1
1
  // 字典演示用内存 mock(接入真实后端后删除本文件)。
2
- import { mockRequest } from '../../../api/domain.api.js';
2
+ import { mockRequest } from '../../../../api/domain.api.js';
3
3
 
4
4
  let types = [
5
5
  { id: 1, name: '性别', code: 'gender', status: 'active', remark: '性别字典' },
6
6
  { id: 2, name: '通用状态', code: 'common_status', status: 'active', remark: '通用启停状态' },
7
- { id: 3, name: '通知类型', code: 'notice_type', status: 'active', remark: '消息通知类型' }
7
+ { id: 3, name: '通知类型', code: 'notice_type', status: 'active', remark: '消息通知类型' },
8
+ { id: 4, name: '优先级', code: 'priority', status: 'active', remark: '任务/工单优先级' },
9
+ { id: 5, name: '审批状态', code: 'approval_status', status: 'active', remark: '审批流程状态' },
10
+ { id: 6, name: '设备状态', code: 'device_status', status: 'active', remark: '设备在线/离线' },
11
+ { id: 7, name: '客户等级', code: 'customer_level', status: 'active', remark: '客户分层等级' },
12
+ { id: 8, name: '订单状态', code: 'order_status', status: 'active', remark: '订单流转状态' },
13
+ { id: 9, name: '支付方式', code: 'payment_method', status: 'active', remark: '支付渠道' },
14
+ { id: 10, name: '物流状态', code: 'logistics_status', status: 'active', remark: '物流轨迹状态' },
15
+ { id: 11, name: '用户来源', code: 'user_source', status: 'active', remark: '注册/推广来源' },
16
+ { id: 12, name: '语言', code: 'language', status: 'active', remark: '界面语言' }
8
17
  ];
9
18
 
10
19
  let items = [
@@ -19,9 +28,18 @@ let items = [
19
28
 
20
29
  const delay = (ms = 200) => new Promise((resolve) => setTimeout(resolve, ms));
21
30
 
22
- mockRequest('GET', '/dicts/types', async () => {
31
+ mockRequest('GET', '/dicts/types', async (req) => {
23
32
  await delay();
24
- return { ok: true, code: '0', data: types.slice() };
33
+ const { page = 1, pageSize = 10 } = req.params();
34
+ const start = (page - 1) * pageSize;
35
+ return {
36
+ ok: true,
37
+ code: '0',
38
+ data: types.slice(start, start + pageSize),
39
+ pageNum: page,
40
+ pageSize,
41
+ total: types.length
42
+ };
25
43
  });
26
44
 
27
45
  mockRequest('POST', '/dicts/types', async (req) => {
@@ -10,6 +10,11 @@ export default class DictsPageState {
10
10
  selectedTypeId(): number | null;
11
11
  selectedType(): DictTypeInstance | null;
12
12
  items(): DictItemInstance[];
13
+ page(): number;
14
+ pageSize(): number;
15
+ total(): number;
16
+ setPage(value: number): void;
17
+ setPageSize(value: number): void;
13
18
  subscribe(listener: () => void): () => void;
14
19
  loadTypes(): Promise<unknown>;
15
20
  selectType(id: number): void;