create-yoya-ui 0.6.1 → 0.7.5

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 (43) hide show
  1. package/package.json +1 -1
  2. package/templates/admin/README.md +1 -1
  3. package/templates/admin/RULES.md +3 -2
  4. package/templates/admin/package.json +9 -1
  5. package/templates/admin/src/api/domain.api.d.ts +1 -1
  6. package/templates/admin/src/api/domain.api.js +1 -1
  7. package/templates/admin/src/api/fetch.api.d.ts +1 -1
  8. package/templates/admin/src/features/dashboard/overview/components/dashboard-chart.js +40 -40
  9. package/templates/admin/src/features/dashboard/overview/pages/dashboard-overview-page.js +178 -181
  10. package/templates/admin/src/features/system/dicts/api/dict.mgr.d.ts +1 -1
  11. package/templates/admin/src/features/system/dicts/api/dict.mgr.js +1 -1
  12. package/templates/admin/src/features/system/dicts/api/dict.state.d.ts +1 -1
  13. package/templates/admin/src/features/system/dicts/components/dict-editor-dialog.js +13 -9
  14. package/templates/admin/src/features/system/dicts/components/dict-item-form-dialog.js +13 -9
  15. package/templates/admin/src/features/system/dicts/pages/dict-list-page.js +37 -43
  16. package/templates/admin/src/features/system/members/api/member.mgr.d.ts +1 -1
  17. package/templates/admin/src/features/system/members/api/member.mgr.js +1 -1
  18. package/templates/admin/src/features/system/members/api/member.req.d.ts +1 -1
  19. package/templates/admin/src/features/system/members/api/member.req.js +1 -1
  20. package/templates/admin/src/features/system/members/api/member.state.d.ts +1 -1
  21. package/templates/admin/src/features/system/members/components/member-form-dialog.js +13 -9
  22. package/templates/admin/src/features/system/members/components/member-toolbar.js +34 -40
  23. package/templates/admin/src/features/system/members/pages/member-list-page.js +13 -20
  24. package/templates/admin/src/features/system/permissions/api/permission.mgr.d.ts +1 -1
  25. package/templates/admin/src/features/system/permissions/api/permission.mgr.js +1 -1
  26. package/templates/admin/src/features/system/permissions/api/permission.state.d.ts +1 -1
  27. package/templates/admin/src/features/system/permissions/components/permission-form-dialog.js +13 -9
  28. package/templates/admin/src/features/system/permissions/pages/permission-list-page.js +16 -22
  29. package/templates/admin/src/features/system/roles/api/role.mgr.d.ts +1 -1
  30. package/templates/admin/src/features/system/roles/api/role.mgr.js +1 -1
  31. package/templates/admin/src/features/system/roles/api/role.state.d.ts +1 -1
  32. package/templates/admin/src/features/system/roles/components/role-form-dialog.js +13 -9
  33. package/templates/admin/src/features/system/roles/components/role-toolbar.js +33 -39
  34. package/templates/admin/src/features/system/roles/pages/role-list-page.js +13 -19
  35. package/templates/admin/src/main.js +1 -1
  36. package/templates/admin/src/shell/api/shell.req.js +1 -1
  37. package/templates/admin/src/shell/components/admin-shell.js +18 -21
  38. package/templates/admin/vite.config.js +7 -5
  39. package/templates/basic/package.json +2 -1
  40. package/templates/ssr/package.json +2 -1
  41. package/templates/ssr/src/home-page.js +3 -2
  42. package/templates/ssr/src/server.mjs +3 -0
  43. package/templates/ssr/vite.config.js +17 -0
@@ -82,53 +82,47 @@ export function DictListPage() {
82
82
  });
83
83
  }
84
84
 
85
- return {
86
- render() {
87
- return vstack({ gap: '16px' }, (stack) => {
88
- stack.h2('字典管理');
89
- stack.vCard((card) => {
90
- card.vCardHeader((header) => {
91
- header.hstack({ alignItems: 'center', gap: '10px' }, (toolbar) => {
92
- toolbar.vButton('新增字典', (btn) => {
93
- btn.variant('primary');
94
- btn.on('click', () => editorDialog.open(null));
95
- });
96
- toolbar.spacer();
97
- toolbar.span((hint) => {
98
- hint.style('color', 'var(--yoya-color-text-muted, #64748b)');
99
- hint.child('点击「编辑」可在弹窗中维护基本信息与字典值');
100
- });
101
- });
85
+ // 页面也是组件:没有对外命令方法 → 形态 A 薄工厂,直接返回视图节点
86
+ return vstack({ gap: '16px' }, (stack) => {
87
+ stack.h2('字典管理');
88
+ stack.vCard((card) => {
89
+ card.vCardHeader((header) => {
90
+ header.hstack({ alignItems: 'center', gap: '10px' }, (toolbar) => {
91
+ toolbar.vButton('新增字典', (btn) => {
92
+ btn.variant('primary');
93
+ btn.on('click', () => editorDialog.open(null));
102
94
  });
103
- card.vCardBody((body) => {
104
- body.vstack({ gap: '12px' }, (content) => {
105
- content.vTable((table) => {
106
- table.vThead((head) => {
107
- head.vTr((row) => {
108
- row.vTh('名称');
109
- row.vTh('编码');
110
- row.vTh('状态');
111
- row.vTh('备注');
112
- row.vTh('操作');
113
- });
114
- });
115
- table.vTbody((tbody) => {
116
- tbody.keyed(
117
- state.types,
118
- (type) => type.id,
119
- (type) => buildTypeRow(type)
120
- );
121
- });
95
+ toolbar.spacer();
96
+ toolbar.span((hint) => {
97
+ hint.style('color', 'var(--yoya-color-text-muted, #64748b)');
98
+ hint.child('点击「编辑」可在弹窗中维护基本信息与字典值');
99
+ });
100
+ });
101
+ });
102
+ card.vCardBody((body) => {
103
+ body.vstack({ gap: '12px' }, (content) => {
104
+ content.vTable((table) => {
105
+ table.vThead((head) => {
106
+ head.vTr((row) => {
107
+ row.vTh('名称');
108
+ row.vTh('编码');
109
+ row.vTh('状态');
110
+ row.vTh('备注');
111
+ row.vTh('操作');
122
112
  });
123
- content.child(pagination);
113
+ });
114
+ table.vTbody((tbody) => {
115
+ tbody.keyed(
116
+ state.types,
117
+ (type) => type.id,
118
+ (type) => buildTypeRow(type)
119
+ );
124
120
  });
125
121
  });
122
+ content.child(pagination);
126
123
  });
127
- stack.child(editorDialog);
128
124
  });
129
- },
130
- refresh() {
131
- return load();
132
- }
133
- };
125
+ });
126
+ stack.child(editorDialog);
127
+ });
134
128
  }
@@ -1,5 +1,5 @@
1
1
  /** 管理请求命令类型声明(对应 member.mgr.js)。 */
2
- import { RequestBase } from '@yoyaflow/yoya-ui/api';
2
+ import { RequestBase } from '@yoyaflow/yoya-core/api';
3
3
  import Members from './member.views.js';
4
4
 
5
5
  type MemberListItem = InstanceType<typeof Members.ListItem>;
@@ -1,5 +1,5 @@
1
1
  // 管理请求命令:字段在构造器声明,方法由 RequestBase 基类提供、子类覆写。
2
- import { RequestBase } from '@yoyaflow/yoya-ui/api';
2
+ import { RequestBase } from '@yoyaflow/yoya-core/api';
3
3
  import Members from './member.views.js';
4
4
 
5
5
  class Query extends RequestBase {
@@ -1,5 +1,5 @@
1
1
  /** 外部请求命令类型声明(对应 member.req.js)。 */
2
- import { RequestBase } from '@yoyaflow/yoya-ui/api';
2
+ import { RequestBase } from '@yoyaflow/yoya-core/api';
3
3
  import Members from './member.views.js';
4
4
 
5
5
  type MemberListItem = InstanceType<typeof Members.ListItem>;
@@ -1,5 +1,5 @@
1
1
  // 外部请求命令:其他模块调用本域能力的入口。
2
- import { RequestBase } from '@yoyaflow/yoya-ui/api';
2
+ import { RequestBase } from '@yoyaflow/yoya-core/api';
3
3
  import Members from './member.views.js';
4
4
 
5
5
  class QueryAvailable extends RequestBase {
@@ -1,6 +1,6 @@
1
1
  /** 页面数据状态类类型声明(对应 member.state.js)。 */
2
2
  import type { SignalHandle } from '@yoyaflow/yoya-ui';
3
- import type { Result } from '@yoyaflow/yoya-ui/api';
3
+ import type { Result } from '@yoyaflow/yoya-core/api';
4
4
  import Members from './member.views.js';
5
5
 
6
6
  type MemberListItem = InstanceType<typeof Members.ListItem>;
@@ -1,4 +1,4 @@
1
- import { vDialog } from '@yoyaflow/yoya-ui';
1
+ import { vDialog, vNode } from '@yoyaflow/yoya-ui';
2
2
  import { fieldValue } from '../../../../shared/state.rows.js';
3
3
  import { roleOptions, statusOptions } from '../utils/options.js';
4
4
 
@@ -79,13 +79,17 @@ export function MemberFormDialog({ onSubmit }) {
79
79
  dialog.close();
80
80
  }
81
81
 
82
- return {
83
- render() {
84
- return dialog;
85
- },
86
- open,
87
- close() {
82
+ // 有对外命令方法(open / close)→ 形态 B:命令写在 api 上,视图就是自己的弹窗节点
83
+ return vNode((api) => {
84
+ api.open = (member = null) => {
85
+ open(member);
86
+ return api;
87
+ };
88
+ api.close = () => {
88
89
  dialog.close();
89
- }
90
- };
90
+ return api;
91
+ };
92
+
93
+ return dialog;
94
+ });
91
95
  }
@@ -2,10 +2,40 @@ import { vForm } from '@yoyaflow/yoya-ui';
2
2
  import { statusOptions } from '../utils/options.js';
3
3
 
4
4
  export function MemberToolbar({ onSearch, onAdd }) {
5
- let form = null;
5
+ // 形态 A 薄工厂:没有对外命令方法,结构就地声明;句柄留在函数作用域里给事件回调读值
6
+ const form = vForm((f) => {
7
+ f.style({ display: 'flex', flexWrap: 'wrap', gap: '12px', alignItems: 'center' });
8
+ f.vFormItem((item) => {
9
+ item.style({ display: 'flex', alignItems: 'center', gap: '8px' });
10
+ item.label('关键词').name('keyword');
11
+ item.control((editor) => editor.vInput({ name: 'keyword', placeholder: '姓名 / 邮箱' }));
12
+ });
13
+ f.vFormItem((item) => {
14
+ item.style({ display: 'flex', alignItems: 'center', gap: '8px' });
15
+ item.label('状态').name('status');
16
+ item.control((editor) =>
17
+ editor.vSelect({ name: 'status', options: statusOptions, placeholder: '全部' })
18
+ );
19
+ });
20
+ f.vButton('查询', (btn) => {
21
+ btn.variant('primary');
22
+ btn.on('click', search);
23
+ });
24
+ f.vButton('重置', (btn) => btn.on('click', reset));
25
+ f.vButton('新增成员', (btn) => {
26
+ btn.variant('primary');
27
+ btn.style('marginLeft', 'auto');
28
+ btn.access('system:member:create');
29
+ btn.on('click', onAdd);
30
+ });
31
+ f.on('submit', (event) => {
32
+ event.preventDefault();
33
+ search();
34
+ });
35
+ });
6
36
 
7
37
  function values() {
8
- return form ? form.values() : {};
38
+ return form.values();
9
39
  }
10
40
 
11
41
  function search() {
@@ -13,45 +43,9 @@ export function MemberToolbar({ onSearch, onAdd }) {
13
43
  }
14
44
 
15
45
  function reset() {
16
- if (form) {
17
- form.values({ keyword: '', status: '' });
18
- }
46
+ form.values({ keyword: '', status: '' });
19
47
  search();
20
48
  }
21
49
 
22
- return {
23
- render() {
24
- return vForm((f) => {
25
- form = f;
26
- f.style({ display: 'flex', flexWrap: 'wrap', gap: '12px', alignItems: 'center' });
27
- f.vFormItem((item) => {
28
- item.style({ display: 'flex', alignItems: 'center', gap: '8px' });
29
- item.label('关键词').name('keyword');
30
- item.control((editor) => editor.vInput({ name: 'keyword', placeholder: '姓名 / 邮箱' }));
31
- });
32
- f.vFormItem((item) => {
33
- item.style({ display: 'flex', alignItems: 'center', gap: '8px' });
34
- item.label('状态').name('status');
35
- item.control((editor) =>
36
- editor.vSelect({ name: 'status', options: statusOptions, placeholder: '全部' })
37
- );
38
- });
39
- f.vButton('查询', (btn) => {
40
- btn.variant('primary');
41
- btn.on('click', search);
42
- });
43
- f.vButton('重置', (btn) => btn.on('click', reset));
44
- f.vButton('新增成员', (btn) => {
45
- btn.variant('primary');
46
- btn.style('marginLeft', 'auto');
47
- btn.access('system:member:create');
48
- btn.on('click', onAdd);
49
- });
50
- f.on('submit', (event) => {
51
- event.preventDefault();
52
- search();
53
- });
54
- });
55
- }
56
- };
50
+ return form;
57
51
  }
@@ -65,26 +65,19 @@ export function MemberListPage() {
65
65
  }
66
66
  }
67
67
 
68
- return {
69
- render() {
70
- return vstack({ gap: '16px' }, (stack) => {
71
- stack.h2('成员管理');
72
- stack.vCard((card) => {
73
- card.vCardHeader('成员列表');
74
- card.vCardBody((body) => {
75
- body.vstack({ gap: '12px' }, (content) => {
76
- content.child(toolbar);
77
- content.child(table);
78
- content.child(pagination);
79
- });
80
- });
68
+ // 页面也是组件:没有对外命令方法 → 形态 A 薄工厂,直接返回视图节点
69
+ return vstack({ gap: '16px' }, (stack) => {
70
+ stack.h2('成员管理');
71
+ stack.vCard((card) => {
72
+ card.vCardHeader('成员列表');
73
+ card.vCardBody((body) => {
74
+ body.vstack({ gap: '12px' }, (content) => {
75
+ content.child(toolbar);
76
+ content.child(table);
77
+ content.child(pagination);
81
78
  });
82
- stack.child(dialog);
83
79
  });
84
- },
85
- // 页面也是组件:父级 / 路由可以调用实例方法刷新
86
- refresh() {
87
- return load();
88
- }
89
- };
80
+ });
81
+ stack.child(dialog);
82
+ });
90
83
  }
@@ -1,5 +1,5 @@
1
1
  /** 权限管理请求命令类型声明(对应 permission.mgr.js)。 */
2
- import { RequestBase } from '@yoyaflow/yoya-ui/api';
2
+ import { RequestBase } from '@yoyaflow/yoya-core/api';
3
3
  import Permissions, { PermissionType } from './permission.views.js';
4
4
 
5
5
  type PermissionNodeInstance = InstanceType<typeof Permissions.PermissionNode>;
@@ -1,5 +1,5 @@
1
1
  // 权限管理请求命令:查询树、新增、编辑、删除。
2
- import { RequestBase } from '@yoyaflow/yoya-ui/api';
2
+ import { RequestBase } from '@yoyaflow/yoya-core/api';
3
3
  import Permissions from './permission.views.js';
4
4
 
5
5
  class QueryTree extends RequestBase {
@@ -1,6 +1,6 @@
1
1
  /** 权限页状态类类型声明(对应 permission.state.js)。 */
2
2
  import type { SignalHandle } from '@yoyaflow/yoya-ui';
3
- import type { Result } from '@yoyaflow/yoya-ui/api';
3
+ import type { Result } from '@yoyaflow/yoya-core/api';
4
4
  import Permissions from './permission.views.js';
5
5
 
6
6
  type PermissionNodeInstance = InstanceType<typeof Permissions.PermissionNode>;
@@ -1,4 +1,4 @@
1
- import { vDialog } from '@yoyaflow/yoya-ui';
1
+ import { vDialog, vNode } from '@yoyaflow/yoya-ui';
2
2
 
3
3
  const typeOptions = [
4
4
  ['menu', '菜单'],
@@ -86,13 +86,17 @@ export function PermissionFormDialog({ onSubmit }) {
86
86
  dialog.close();
87
87
  }
88
88
 
89
- return {
90
- render() {
91
- return dialog;
92
- },
93
- open,
94
- close() {
89
+ // 有对外命令方法(open / close)→ 形态 B:命令写在 api 上,视图就是自己的弹窗节点
90
+ return vNode((api) => {
91
+ api.open = (init = {}) => {
92
+ open(init);
93
+ return api;
94
+ };
95
+ api.close = () => {
95
96
  dialog.close();
96
- }
97
- };
97
+ return api;
98
+ };
99
+
100
+ return dialog;
101
+ });
98
102
  }
@@ -65,30 +65,24 @@ export function PermissionListPage() {
65
65
  }
66
66
  }
67
67
 
68
- return {
69
- render() {
70
- return vstack({ gap: '16px' }, (stack) => {
71
- stack.h2('权限管理');
72
- stack.vCard((card) => {
73
- card.vCardHeader('权限树');
74
- card.vCardBody((body) => {
75
- body.vstack({ gap: '12px' }, (content) => {
76
- content.hstack({ gap: '10px' }, (toolbar) => {
77
- toolbar.vButton('新增根权限', (btn) => {
78
- btn.variant('primary');
79
- btn.on('click', () => dialog.open({}));
80
- });
81
- toolbar.vButton('刷新', (btn) => btn.on('click', () => load()));
82
- });
83
- content.child(tree);
68
+ // 页面也是组件:没有对外命令方法 → 形态 A 薄工厂,直接返回视图节点
69
+ return vstack({ gap: '16px' }, (stack) => {
70
+ stack.h2('权限管理');
71
+ stack.vCard((card) => {
72
+ card.vCardHeader('权限树');
73
+ card.vCardBody((body) => {
74
+ body.vstack({ gap: '12px' }, (content) => {
75
+ content.hstack({ gap: '10px' }, (toolbar) => {
76
+ toolbar.vButton('新增根权限', (btn) => {
77
+ btn.variant('primary');
78
+ btn.on('click', () => dialog.open({}));
84
79
  });
80
+ toolbar.vButton('刷新', (btn) => btn.on('click', () => load()));
85
81
  });
82
+ content.child(tree);
86
83
  });
87
- stack.child(dialog);
88
84
  });
89
- },
90
- refresh() {
91
- return load();
92
- }
93
- };
85
+ });
86
+ stack.child(dialog);
87
+ });
94
88
  }
@@ -1,5 +1,5 @@
1
1
  /** 角色管理请求命令类型声明(对应 role.mgr.js)。 */
2
- import { RequestBase } from '@yoyaflow/yoya-ui/api';
2
+ import { RequestBase } from '@yoyaflow/yoya-core/api';
3
3
  import Roles, { RoleStatus } from './role.views.js';
4
4
 
5
5
  type RoleListItem = InstanceType<typeof Roles.ListItem>;
@@ -1,5 +1,5 @@
1
1
  // 角色管理请求命令。
2
- import { RequestBase } from '@yoyaflow/yoya-ui/api';
2
+ import { RequestBase } from '@yoyaflow/yoya-core/api';
3
3
  import Roles from './role.views.js';
4
4
 
5
5
  class Query extends RequestBase {
@@ -1,6 +1,6 @@
1
1
  /** 角色页状态类类型声明(对应 role.state.js)。 */
2
2
  import type { SignalHandle } from '@yoyaflow/yoya-ui';
3
- import type { Result } from '@yoyaflow/yoya-ui/api';
3
+ import type { Result } from '@yoyaflow/yoya-core/api';
4
4
  import Roles from './role.views.js';
5
5
 
6
6
  type RoleListItem = InstanceType<typeof Roles.ListItem>;
@@ -1,4 +1,4 @@
1
- import { vDialog } from '@yoyaflow/yoya-ui';
1
+ import { vDialog, vNode } from '@yoyaflow/yoya-ui';
2
2
  import { fieldValue } from '../../../../shared/state.rows.js';
3
3
  import { statusOptions } from '../utils/options.js';
4
4
 
@@ -80,13 +80,17 @@ export function RoleFormDialog({ onSubmit }) {
80
80
  dialog.close();
81
81
  }
82
82
 
83
- return {
84
- render() {
85
- return dialog;
86
- },
87
- open,
88
- close() {
83
+ // 有对外命令方法(open / close)→ 形态 B:命令写在 api 上,视图就是自己的弹窗节点
84
+ return vNode((api) => {
85
+ api.open = (role = null) => {
86
+ open(role);
87
+ return api;
88
+ };
89
+ api.close = () => {
89
90
  dialog.close();
90
- }
91
- };
91
+ return api;
92
+ };
93
+
94
+ return dialog;
95
+ });
92
96
  }
@@ -2,10 +2,39 @@ import { vForm } from '@yoyaflow/yoya-ui';
2
2
  import { statusOptions } from '../utils/options.js';
3
3
 
4
4
  export function RoleToolbar({ onSearch, onAdd }) {
5
- let form = null;
5
+ // 形态 A 薄工厂:没有对外命令方法,结构就地声明;句柄留在函数作用域里给事件回调读值
6
+ const form = vForm((f) => {
7
+ f.style({ display: 'flex', flexWrap: 'wrap', gap: '12px', alignItems: 'center' });
8
+ f.vFormItem((item) => {
9
+ item.style({ display: 'flex', alignItems: 'center', gap: '8px' });
10
+ item.label('关键词').name('keyword');
11
+ item.control((editor) => editor.vInput({ name: 'keyword', placeholder: '名称 / 标识' }));
12
+ });
13
+ f.vFormItem((item) => {
14
+ item.style({ display: 'flex', alignItems: 'center', gap: '8px' });
15
+ item.label('状态').name('status');
16
+ item.control((editor) =>
17
+ editor.vSelect({ name: 'status', options: statusOptions, placeholder: '全部' })
18
+ );
19
+ });
20
+ f.vButton('查询', (btn) => {
21
+ btn.variant('primary');
22
+ btn.on('click', search);
23
+ });
24
+ f.vButton('重置', (btn) => btn.on('click', reset));
25
+ f.vButton('新增角色', (btn) => {
26
+ btn.variant('primary');
27
+ btn.style('marginLeft', 'auto');
28
+ btn.on('click', onAdd);
29
+ });
30
+ f.on('submit', (event) => {
31
+ event.preventDefault();
32
+ search();
33
+ });
34
+ });
6
35
 
7
36
  function values() {
8
- return form ? form.values() : {};
37
+ return form.values();
9
38
  }
10
39
 
11
40
  function search() {
@@ -13,44 +42,9 @@ export function RoleToolbar({ onSearch, onAdd }) {
13
42
  }
14
43
 
15
44
  function reset() {
16
- if (form) {
17
- form.values({ keyword: '', status: '' });
18
- }
45
+ form.values({ keyword: '', status: '' });
19
46
  search();
20
47
  }
21
48
 
22
- return {
23
- render() {
24
- return vForm((f) => {
25
- form = f;
26
- f.style({ display: 'flex', flexWrap: 'wrap', gap: '12px', alignItems: 'center' });
27
- f.vFormItem((item) => {
28
- item.style({ display: 'flex', alignItems: 'center', gap: '8px' });
29
- item.label('关键词').name('keyword');
30
- item.control((editor) => editor.vInput({ name: 'keyword', placeholder: '名称 / 标识' }));
31
- });
32
- f.vFormItem((item) => {
33
- item.style({ display: 'flex', alignItems: 'center', gap: '8px' });
34
- item.label('状态').name('status');
35
- item.control((editor) =>
36
- editor.vSelect({ name: 'status', options: statusOptions, placeholder: '全部' })
37
- );
38
- });
39
- f.vButton('查询', (btn) => {
40
- btn.variant('primary');
41
- btn.on('click', search);
42
- });
43
- f.vButton('重置', (btn) => btn.on('click', reset));
44
- f.vButton('新增角色', (btn) => {
45
- btn.variant('primary');
46
- btn.style('marginLeft', 'auto');
47
- btn.on('click', onAdd);
48
- });
49
- f.on('submit', (event) => {
50
- event.preventDefault();
51
- search();
52
- });
53
- });
54
- }
55
- };
49
+ return form;
56
50
  }
@@ -73,25 +73,19 @@ export function RoleListPage() {
73
73
  }
74
74
  }
75
75
 
76
- return {
77
- render() {
78
- return vstack({ gap: '16px' }, (stack) => {
79
- stack.h2('角色管理');
80
- stack.vCard((card) => {
81
- card.vCardHeader('角色列表');
82
- card.vCardBody((body) => {
83
- body.vstack({ gap: '12px' }, (content) => {
84
- content.child(toolbar);
85
- content.child(table);
86
- content.child(pagination);
87
- });
88
- });
76
+ // 页面也是组件:没有对外命令方法 → 形态 A 薄工厂,直接返回视图节点
77
+ return vstack({ gap: '16px' }, (stack) => {
78
+ stack.h2('角色管理');
79
+ stack.vCard((card) => {
80
+ card.vCardHeader('角色列表');
81
+ card.vCardBody((body) => {
82
+ body.vstack({ gap: '12px' }, (content) => {
83
+ content.child(toolbar);
84
+ content.child(table);
85
+ content.child(pagination);
89
86
  });
90
- stack.child(dialog);
91
87
  });
92
- },
93
- refresh() {
94
- return load();
95
- }
96
- };
88
+ });
89
+ stack.child(dialog);
90
+ });
97
91
  }
@@ -17,7 +17,7 @@ async function bootstrap() {
17
17
  const state = new ShellState();
18
18
  await state.load();
19
19
  const shell = AdminShell({ state });
20
- shell.render().bindTo('#app');
20
+ shell.bindTo('#app');
21
21
  state.start();
22
22
  }
23
23
 
@@ -1,5 +1,5 @@
1
1
  // 外壳请求命令:其他模块(启动装配)调用本域能力的入口,方便后续替换为服务端接口(去掉 mock 即可)。
2
- import { RequestBase } from '@yoyaflow/yoya-ui/api';
2
+ import { RequestBase } from '@yoyaflow/yoya-core/api';
3
3
  import Shell from './shell.views.js';
4
4
 
5
5
  class QueryMenus extends RequestBase {