create-yoya-ui 0.1.2 → 0.2.0
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 +1 -1
- package/package.json +1 -1
- package/templates/admin/README.md +54 -2
- package/templates/admin/node_modules/.vite/deps/_metadata.json +8 -0
- package/templates/admin/node_modules/.vite/deps/package.json +3 -0
- package/templates/admin/package.json +4 -2
- package/templates/admin/src/api/domain.api.d.ts +10 -0
- package/templates/admin/src/api/domain.api.js +31 -0
- package/templates/admin/src/api/fetch.api.d.ts +4 -0
- package/templates/admin/src/api/fetch.api.js +20 -0
- package/templates/admin/src/app/admin-shell.js +51 -0
- package/templates/admin/src/app/modules.js +37 -0
- package/templates/admin/src/app/router.js +20 -0
- package/templates/admin/src/features/dashboard/components/dashboard-chart.js +205 -0
- package/templates/admin/src/features/dashboard/pages/dashboard-overview-page.js +197 -0
- package/templates/admin/src/features/dicts/api/dict.mgr.d.ts +79 -0
- package/templates/admin/src/features/dicts/api/dict.mgr.js +160 -0
- package/templates/admin/src/features/dicts/api/dict.mock.js +81 -0
- package/templates/admin/src/features/dicts/api/dict.state.d.ts +23 -0
- package/templates/admin/src/features/dicts/api/dict.state.js +103 -0
- package/templates/admin/src/features/dicts/api/dict.views.d.ts +41 -0
- package/templates/admin/src/features/dicts/api/dict.views.js +23 -0
- package/templates/admin/src/features/dicts/components/dict-editor-dialog.js +218 -0
- package/templates/admin/src/features/dicts/components/dict-item-form-dialog.js +79 -0
- package/templates/admin/src/features/dicts/pages/dict-list-page.js +123 -0
- package/templates/admin/src/features/dicts/utils/options.js +5 -0
- package/templates/admin/src/features/members/api/member.mgr.d.ts +47 -0
- package/templates/admin/src/features/members/api/member.mgr.js +95 -0
- package/templates/admin/src/features/members/api/member.mock.js +74 -0
- package/templates/admin/src/features/members/api/member.req.d.ts +16 -0
- package/templates/admin/src/features/members/api/member.req.js +15 -0
- package/templates/admin/src/features/members/api/member.state.d.ts +23 -0
- package/templates/admin/src/features/members/api/member.state.js +97 -0
- package/templates/admin/src/features/members/api/member.views.d.ts +33 -0
- package/templates/admin/src/features/members/api/member.views.js +23 -0
- package/templates/admin/src/features/members/components/member-form-dialog.js +83 -0
- package/templates/admin/src/features/members/components/member-table.js +58 -0
- package/templates/admin/src/features/members/components/member-toolbar.js +58 -0
- package/templates/admin/src/features/members/pages/member-list-page.js +85 -0
- package/templates/admin/src/features/members/utils/options.d.ts +4 -0
- package/templates/admin/src/features/members/utils/options.js +6 -0
- package/templates/admin/src/features/permissions/api/permission.mgr.d.ts +45 -0
- package/templates/admin/src/features/permissions/api/permission.mgr.js +79 -0
- package/templates/admin/src/features/permissions/api/permission.mock.js +68 -0
- package/templates/admin/src/features/permissions/api/permission.state.d.ts +14 -0
- package/templates/admin/src/features/permissions/api/permission.state.js +46 -0
- package/templates/admin/src/features/permissions/api/permission.views.d.ts +27 -0
- package/templates/admin/src/features/permissions/api/permission.views.js +14 -0
- package/templates/admin/src/features/permissions/components/permission-form-dialog.js +98 -0
- package/templates/admin/src/features/permissions/pages/permission-list-page.js +98 -0
- package/templates/admin/src/features/roles/api/role.mgr.d.ts +57 -0
- package/templates/admin/src/features/roles/api/role.mgr.js +101 -0
- package/templates/admin/src/features/roles/api/role.mock.js +68 -0
- package/templates/admin/src/features/roles/api/role.state.d.ts +23 -0
- package/templates/admin/src/features/roles/api/role.state.js +97 -0
- package/templates/admin/src/features/roles/api/role.views.d.ts +43 -0
- package/templates/admin/src/features/roles/api/role.views.js +24 -0
- package/templates/admin/src/features/roles/components/role-form-dialog.js +86 -0
- package/templates/admin/src/features/roles/components/role-table.js +57 -0
- package/templates/admin/src/features/roles/components/role-toolbar.js +58 -0
- package/templates/admin/src/features/roles/pages/role-list-page.js +100 -0
- package/templates/admin/src/features/roles/utils/options.js +5 -0
- package/templates/admin/src/main.js +17 -165
- package/templates/admin/src/ui/app-navbar.js +67 -0
- package/templates/admin/src/ui/app-sidebar.js +27 -0
- package/templates/admin/src/ui/placeholder-page.js +17 -0
- package/templates/admin/src/ui/row-action-button.js +12 -0
- package/templates/admin/src/ui/sidebar-menu.js +14 -0
- package/templates/admin/tsconfig.json +18 -0
- package/templates/basic/package.json +1 -1
- package/templates/ssr/package.json +1 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { vGauge, vRingStat, vTimeline, vTrendCard, vstack } from '@yoyaflow/yoya-ui';
|
|
2
|
+
import { DashboardChart } from '../components/dashboard-chart.js';
|
|
3
|
+
|
|
4
|
+
const weekLabels = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
|
|
5
|
+
|
|
6
|
+
export function DashboardOverviewPage() {
|
|
7
|
+
return {
|
|
8
|
+
render() {
|
|
9
|
+
return vstack({ gap: '16px' }, (stack) => {
|
|
10
|
+
stack.h2('数据概览');
|
|
11
|
+
|
|
12
|
+
stack.vCard((card) => {
|
|
13
|
+
card.vCardHeader('核心指标');
|
|
14
|
+
card.vCardBody((body) => {
|
|
15
|
+
body.vDigitalBoard((board) => {
|
|
16
|
+
board.columns(4);
|
|
17
|
+
board.vDigitalBoardItem((item) => {
|
|
18
|
+
item.label('服务总数');
|
|
19
|
+
item.value('128');
|
|
20
|
+
item.unit('个');
|
|
21
|
+
item.trend('+12 本月');
|
|
22
|
+
item.trendUp(true);
|
|
23
|
+
item.icon('🖥️');
|
|
24
|
+
});
|
|
25
|
+
board.vDigitalBoardItem((item) => {
|
|
26
|
+
item.label('运行中');
|
|
27
|
+
item.value('96');
|
|
28
|
+
item.unit('个');
|
|
29
|
+
item.trend('+8 本周');
|
|
30
|
+
item.trendUp(true);
|
|
31
|
+
item.tone('success');
|
|
32
|
+
item.icon('✅');
|
|
33
|
+
});
|
|
34
|
+
board.vDigitalBoardItem((item) => {
|
|
35
|
+
item.label('异常告警');
|
|
36
|
+
item.value('5');
|
|
37
|
+
item.unit('个');
|
|
38
|
+
item.trend('-2 今日');
|
|
39
|
+
item.trendUp(false);
|
|
40
|
+
item.tone('danger');
|
|
41
|
+
item.icon('⚠️');
|
|
42
|
+
});
|
|
43
|
+
board.vDigitalBoardItem((item) => {
|
|
44
|
+
item.label('平均响应');
|
|
45
|
+
item.value('243');
|
|
46
|
+
item.unit('ms');
|
|
47
|
+
item.trend('-18 今日');
|
|
48
|
+
item.trendUp(true);
|
|
49
|
+
item.tone('warning');
|
|
50
|
+
item.icon('⏱️');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
stack.div((trends) => {
|
|
57
|
+
trends.style({
|
|
58
|
+
display: 'grid',
|
|
59
|
+
gap: '12px',
|
|
60
|
+
gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))'
|
|
61
|
+
});
|
|
62
|
+
trends.child(
|
|
63
|
+
vTrendCard({
|
|
64
|
+
data: [12, 15, 11, 18, 16, 21, 24],
|
|
65
|
+
delta: '+6.4%',
|
|
66
|
+
title: '今日请求',
|
|
67
|
+
tone: 'primary',
|
|
68
|
+
unit: 'k',
|
|
69
|
+
up: true,
|
|
70
|
+
value: '84.2'
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
trends.child(
|
|
74
|
+
vTrendCard({
|
|
75
|
+
data: [320, 290, 310, 270, 260, 248, 243],
|
|
76
|
+
delta: '-18 今日',
|
|
77
|
+
title: '平均响应',
|
|
78
|
+
tone: 'success',
|
|
79
|
+
unit: 'ms',
|
|
80
|
+
up: true,
|
|
81
|
+
value: '243'
|
|
82
|
+
})
|
|
83
|
+
);
|
|
84
|
+
trends.child(
|
|
85
|
+
vTrendCard({
|
|
86
|
+
data: [6, 7, 4, 3, 5, 2, 2],
|
|
87
|
+
delta: '-5 较昨日',
|
|
88
|
+
title: '故障次数',
|
|
89
|
+
tone: 'danger',
|
|
90
|
+
unit: '次',
|
|
91
|
+
up: false,
|
|
92
|
+
value: '2'
|
|
93
|
+
})
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
stack.div((charts) => {
|
|
98
|
+
charts.style({
|
|
99
|
+
display: 'grid',
|
|
100
|
+
gap: '12px',
|
|
101
|
+
gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))'
|
|
102
|
+
});
|
|
103
|
+
charts.child(
|
|
104
|
+
DashboardChart({
|
|
105
|
+
labels: weekLabels,
|
|
106
|
+
series: [{ name: '请求量', data: [62, 71, 58, 84, 92, 76, 88] }],
|
|
107
|
+
title: '近 7 日请求量',
|
|
108
|
+
type: 'bar'
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
charts.child(
|
|
112
|
+
DashboardChart({
|
|
113
|
+
labels: weekLabels,
|
|
114
|
+
series: [
|
|
115
|
+
{ name: '错误数', data: [8, 12, 7, 15, 10, 6, 9], color: '#dc2626' },
|
|
116
|
+
{ name: '恢复数', data: [6, 10, 5, 12, 8, 5, 8], color: '#16a34a' }
|
|
117
|
+
],
|
|
118
|
+
title: '近 7 日错误与恢复',
|
|
119
|
+
type: 'line'
|
|
120
|
+
})
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
stack.div((bottom) => {
|
|
125
|
+
bottom.style({
|
|
126
|
+
display: 'grid',
|
|
127
|
+
gap: '12px',
|
|
128
|
+
gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))'
|
|
129
|
+
});
|
|
130
|
+
bottom.vCard((card) => {
|
|
131
|
+
card.vCardHeader('资源使用');
|
|
132
|
+
card.vCardBody((body) => {
|
|
133
|
+
body.hstack((row) => {
|
|
134
|
+
row.style({ flexWrap: 'wrap', gap: '20px' });
|
|
135
|
+
row.child(vRingStat({ label: '成功率', percent: 99, tone: 'success' }));
|
|
136
|
+
row.child(
|
|
137
|
+
vRingStat({ label: '容量使用', percent: 68, tone: 'primary', value: '680 GB' })
|
|
138
|
+
);
|
|
139
|
+
row.div((box) => {
|
|
140
|
+
box.style({ textAlign: 'center' });
|
|
141
|
+
box.child(vGauge({ unit: '%', value: 72, tone: 'warning' }));
|
|
142
|
+
box.p((text) => {
|
|
143
|
+
text.style({ color: 'var(--yoya-color-text-muted, #64748b)', fontSize: '12px' });
|
|
144
|
+
text.text('CPU 使用率');
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
row.div((box) => {
|
|
148
|
+
box.style({ textAlign: 'center' });
|
|
149
|
+
box.child(vGauge({ unit: '%', value: 58, tone: 'primary' }));
|
|
150
|
+
box.p((text) => {
|
|
151
|
+
text.style({ color: 'var(--yoya-color-text-muted, #64748b)', fontSize: '12px' });
|
|
152
|
+
text.text('内存使用率');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
bottom.vCard((card) => {
|
|
159
|
+
card.vCardHeader('最近动态');
|
|
160
|
+
card.vCardBody((body) => {
|
|
161
|
+
body.child(
|
|
162
|
+
vTimeline((timeline) => {
|
|
163
|
+
timeline.vTimelineItem((item) => {
|
|
164
|
+
item.status('success');
|
|
165
|
+
item.title('服务发布成功');
|
|
166
|
+
item.time('09:32 · 2026-09-01');
|
|
167
|
+
item.content((box) =>
|
|
168
|
+
box.p('api-gateway v2.4.1 已上线,金丝雀批次全部通过。')
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
timeline.vTimelineItem((item) => {
|
|
172
|
+
item.status('processing');
|
|
173
|
+
item.title('滚动发布中');
|
|
174
|
+
item.time('09:20 · 2026-09-01');
|
|
175
|
+
item.content('web-console 正在按 5% 批次滚动。');
|
|
176
|
+
});
|
|
177
|
+
timeline.vTimelineItem((item) => {
|
|
178
|
+
item.status('warning');
|
|
179
|
+
item.title('容量预警');
|
|
180
|
+
item.time('08:47 · 2026-09-01');
|
|
181
|
+
item.content('redis 内存使用率接近 80%。');
|
|
182
|
+
});
|
|
183
|
+
timeline.vTimelineItem((item) => {
|
|
184
|
+
item.status('danger');
|
|
185
|
+
item.title('告警已恢复');
|
|
186
|
+
item.time('08:15 · 2026-09-01');
|
|
187
|
+
item.content('数据库连接池告警自动恢复。');
|
|
188
|
+
});
|
|
189
|
+
})
|
|
190
|
+
);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** 字典管理请求命令类型声明(对应 dict.mgr.js)。 */
|
|
2
|
+
import { RequestBase } from '@yoyaflow/yoya-ui';
|
|
3
|
+
import Dicts, { DictStatus } from './dict.views.js';
|
|
4
|
+
|
|
5
|
+
type DictTypeInstance = InstanceType<typeof Dicts.DictTypeItem>;
|
|
6
|
+
type DictItemInstance = InstanceType<typeof Dicts.DictItem>;
|
|
7
|
+
|
|
8
|
+
declare class QueryTypes extends RequestBase {
|
|
9
|
+
address(): string;
|
|
10
|
+
toItem(row: Record<string, unknown>): DictTypeInstance;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
declare class CreateType extends RequestBase {
|
|
14
|
+
constructor(init?: { name?: string; code?: string; status?: DictStatus; remark?: string });
|
|
15
|
+
method(): 'POST';
|
|
16
|
+
address(): string;
|
|
17
|
+
body(): { name: string; code: string; status: DictStatus; remark: string };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
declare class UpdateType extends RequestBase {
|
|
21
|
+
constructor(
|
|
22
|
+
id: number,
|
|
23
|
+
init?: { name?: string; code?: string; status?: DictStatus; remark?: string }
|
|
24
|
+
);
|
|
25
|
+
method(): 'PUT';
|
|
26
|
+
address(): string;
|
|
27
|
+
body(): { name: string; code: string; status: DictStatus; remark: string };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare class RemoveType extends RequestBase {
|
|
31
|
+
constructor(id: number);
|
|
32
|
+
method(): 'DELETE';
|
|
33
|
+
address(): string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
declare class QueryItems extends RequestBase {
|
|
37
|
+
constructor(typeId: number);
|
|
38
|
+
address(): string;
|
|
39
|
+
toItem(row: Record<string, unknown>): DictItemInstance;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
declare class CreateItem extends RequestBase {
|
|
43
|
+
constructor(
|
|
44
|
+
typeId: number,
|
|
45
|
+
init?: { label?: string; value?: string; sort?: number; status?: DictStatus }
|
|
46
|
+
);
|
|
47
|
+
method(): 'POST';
|
|
48
|
+
address(): string;
|
|
49
|
+
body(): { label: string; value: string; sort: number; status: DictStatus };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
declare class UpdateItem extends RequestBase {
|
|
53
|
+
constructor(
|
|
54
|
+
id: number,
|
|
55
|
+
init?: { label?: string; value?: string; sort?: number; status?: DictStatus }
|
|
56
|
+
);
|
|
57
|
+
method(): 'PUT';
|
|
58
|
+
address(): string;
|
|
59
|
+
body(): { label: string; value: string; sort: number; status: DictStatus };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
declare class RemoveItem extends RequestBase {
|
|
63
|
+
constructor(id: number);
|
|
64
|
+
method(): 'DELETE';
|
|
65
|
+
address(): string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
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;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export default DictMgr;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// 字典管理请求命令:字典类型与字典项。
|
|
2
|
+
import { RequestBase } from '@yoyaflow/yoya-ui';
|
|
3
|
+
import Dicts from './dict.views.js';
|
|
4
|
+
|
|
5
|
+
class QueryTypes extends RequestBase {
|
|
6
|
+
address() {
|
|
7
|
+
return '/dicts/types';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
toItem(row) {
|
|
11
|
+
return new Dicts.DictTypeItem(row);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class CreateType extends RequestBase {
|
|
16
|
+
constructor({ name = '', code = '', status = 'active', remark = '' } = {}) {
|
|
17
|
+
super();
|
|
18
|
+
this.name = name;
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.status = status;
|
|
21
|
+
this.remark = remark;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
method() {
|
|
25
|
+
return 'POST';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
address() {
|
|
29
|
+
return '/dicts/types';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
body() {
|
|
33
|
+
return { name: this.name, code: this.code, status: this.status, remark: this.remark };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class UpdateType extends RequestBase {
|
|
38
|
+
constructor(id, { name = '', code = '', status = 'active', remark = '' } = {}) {
|
|
39
|
+
super();
|
|
40
|
+
this.id = id;
|
|
41
|
+
this.name = name;
|
|
42
|
+
this.code = code;
|
|
43
|
+
this.status = status;
|
|
44
|
+
this.remark = remark;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
method() {
|
|
48
|
+
return 'PUT';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
address() {
|
|
52
|
+
return `/dicts/types/${this.id}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
body() {
|
|
56
|
+
return { name: this.name, code: this.code, status: this.status, remark: this.remark };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class RemoveType extends RequestBase {
|
|
61
|
+
constructor(id) {
|
|
62
|
+
super();
|
|
63
|
+
this.id = id;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
method() {
|
|
67
|
+
return 'DELETE';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
address() {
|
|
71
|
+
return `/dicts/types/${this.id}`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
class QueryItems extends RequestBase {
|
|
76
|
+
constructor(typeId) {
|
|
77
|
+
super();
|
|
78
|
+
this.typeId = typeId;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
address() {
|
|
82
|
+
return `/dicts/types/${this.typeId}/items`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
toItem(row) {
|
|
86
|
+
return new Dicts.DictItem(row);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
class CreateItem extends RequestBase {
|
|
91
|
+
constructor(typeId, { label = '', value = '', sort = 0, status = 'active' } = {}) {
|
|
92
|
+
super();
|
|
93
|
+
this.typeId = typeId;
|
|
94
|
+
this.label = label;
|
|
95
|
+
this.value = value;
|
|
96
|
+
this.sort = sort;
|
|
97
|
+
this.status = status;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
method() {
|
|
101
|
+
return 'POST';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
address() {
|
|
105
|
+
return `/dicts/types/${this.typeId}/items`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
body() {
|
|
109
|
+
return { label: this.label, value: this.value, sort: this.sort, status: this.status };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
class UpdateItem extends RequestBase {
|
|
114
|
+
constructor(id, { label = '', value = '', sort = 0, status = 'active' } = {}) {
|
|
115
|
+
super();
|
|
116
|
+
this.id = id;
|
|
117
|
+
this.label = label;
|
|
118
|
+
this.value = value;
|
|
119
|
+
this.sort = sort;
|
|
120
|
+
this.status = status;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
method() {
|
|
124
|
+
return 'PUT';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
address() {
|
|
128
|
+
return `/dicts/items/${this.id}`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
body() {
|
|
132
|
+
return { label: this.label, value: this.value, sort: this.sort, status: this.status };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
class RemoveItem extends RequestBase {
|
|
137
|
+
constructor(id) {
|
|
138
|
+
super();
|
|
139
|
+
this.id = id;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
method() {
|
|
143
|
+
return 'DELETE';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
address() {
|
|
147
|
+
return `/dicts/items/${this.id}`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export default {
|
|
152
|
+
QueryTypes,
|
|
153
|
+
CreateType,
|
|
154
|
+
UpdateType,
|
|
155
|
+
RemoveType,
|
|
156
|
+
QueryItems,
|
|
157
|
+
CreateItem,
|
|
158
|
+
UpdateItem,
|
|
159
|
+
RemoveItem
|
|
160
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// 字典演示用内存 mock(接入真实后端后删除本文件)。
|
|
2
|
+
import { mockRequest } from '../../../api/domain.api.js';
|
|
3
|
+
|
|
4
|
+
let types = [
|
|
5
|
+
{ id: 1, name: '性别', code: 'gender', status: 'active', remark: '性别字典' },
|
|
6
|
+
{ id: 2, name: '通用状态', code: 'common_status', status: 'active', remark: '通用启停状态' },
|
|
7
|
+
{ id: 3, name: '通知类型', code: 'notice_type', status: 'active', remark: '消息通知类型' }
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
let items = [
|
|
11
|
+
{ id: 11, typeId: 1, label: '男', value: 'male', sort: 1, status: 'active' },
|
|
12
|
+
{ id: 12, typeId: 1, label: '女', value: 'female', sort: 2, status: 'active' },
|
|
13
|
+
{ id: 21, typeId: 2, label: '启用', value: 'active', sort: 1, status: 'active' },
|
|
14
|
+
{ id: 22, typeId: 2, label: '禁用', value: 'disabled', sort: 2, status: 'active' },
|
|
15
|
+
{ id: 31, typeId: 3, label: '系统通知', value: 'system', sort: 1, status: 'active' },
|
|
16
|
+
{ id: 32, typeId: 3, label: '告警', value: 'alert', sort: 2, status: 'active' },
|
|
17
|
+
{ id: 33, typeId: 3, label: '私信', value: 'message', sort: 3, status: 'disabled' }
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const delay = (ms = 200) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
21
|
+
|
|
22
|
+
mockRequest('GET', '/dicts/types', async () => {
|
|
23
|
+
await delay();
|
|
24
|
+
return { ok: true, code: '0', data: types.slice() };
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
mockRequest('POST', '/dicts/types', async (req) => {
|
|
28
|
+
await delay();
|
|
29
|
+
const type = { id: Math.max(0, ...types.map((item) => item.id)) + 1, ...req.body() };
|
|
30
|
+
types = [...types, type];
|
|
31
|
+
return { ok: true, code: '0', data: type };
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
mockRequest('PUT', /^\/dicts\/types\/\d+$/, async (req) => {
|
|
35
|
+
await delay();
|
|
36
|
+
const id = Number(req.address().split('/').pop());
|
|
37
|
+
const type = { ...types.find((item) => item.id === id), ...req.body(), id };
|
|
38
|
+
types = types.map((item) => (item.id === id ? type : item));
|
|
39
|
+
return { ok: true, code: '0', data: type };
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
mockRequest('DELETE', /^\/dicts\/types\/\d+$/, async (req) => {
|
|
43
|
+
await delay();
|
|
44
|
+
const id = Number(req.address().split('/').pop());
|
|
45
|
+
types = types.filter((item) => item.id !== id);
|
|
46
|
+
items = items.filter((item) => item.typeId !== id);
|
|
47
|
+
return { ok: true, code: '0', data: null };
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
mockRequest('GET', /^\/dicts\/types\/\d+\/items$/, async (req) => {
|
|
51
|
+
await delay();
|
|
52
|
+
const typeId = Number(req.address().split('/')[3]);
|
|
53
|
+
return {
|
|
54
|
+
ok: true,
|
|
55
|
+
code: '0',
|
|
56
|
+
data: items.filter((item) => item.typeId === typeId).sort((a, b) => a.sort - b.sort)
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
mockRequest('POST', /^\/dicts\/types\/\d+\/items$/, async (req) => {
|
|
61
|
+
await delay();
|
|
62
|
+
const typeId = Number(req.address().split('/')[3]);
|
|
63
|
+
const item = { id: Math.max(0, ...items.map((entry) => entry.id)) + 1, typeId, ...req.body() };
|
|
64
|
+
items = [...items, item];
|
|
65
|
+
return { ok: true, code: '0', data: item };
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
mockRequest('PUT', /^\/dicts\/items\/\d+$/, async (req) => {
|
|
69
|
+
await delay();
|
|
70
|
+
const id = Number(req.address().split('/').pop());
|
|
71
|
+
const item = { ...items.find((entry) => entry.id === id), ...req.body(), id };
|
|
72
|
+
items = items.map((entry) => (entry.id === id ? item : entry));
|
|
73
|
+
return { ok: true, code: '0', data: item };
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
mockRequest('DELETE', /^\/dicts\/items\/\d+$/, async (req) => {
|
|
77
|
+
await delay();
|
|
78
|
+
const id = Number(req.address().split('/').pop());
|
|
79
|
+
items = items.filter((entry) => entry.id !== id);
|
|
80
|
+
return { ok: true, code: '0', data: null };
|
|
81
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** 字典页状态类类型声明(对应 dict.state.js)。 */
|
|
2
|
+
import Dicts from './dict.views.js';
|
|
3
|
+
|
|
4
|
+
type DictTypeInstance = InstanceType<typeof Dicts.DictTypeItem>;
|
|
5
|
+
type DictItemInstance = InstanceType<typeof Dicts.DictItem>;
|
|
6
|
+
|
|
7
|
+
export default class DictsPageState {
|
|
8
|
+
constructor();
|
|
9
|
+
types(): DictTypeInstance[];
|
|
10
|
+
selectedTypeId(): number | null;
|
|
11
|
+
selectedType(): DictTypeInstance | null;
|
|
12
|
+
items(): DictItemInstance[];
|
|
13
|
+
subscribe(listener: () => void): () => void;
|
|
14
|
+
loadTypes(): Promise<unknown>;
|
|
15
|
+
selectType(id: number): void;
|
|
16
|
+
loadItems(): Promise<void>;
|
|
17
|
+
addType(payload: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
18
|
+
editType(id: number, payload: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
19
|
+
removeType(id: number): Promise<void>;
|
|
20
|
+
addItem(payload: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
21
|
+
editItem(id: number, payload: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
22
|
+
removeItem(id: number): Promise<void>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// 字典页状态类:字典类型 + 当前类型下的字典项。
|
|
2
|
+
import DictMgr from './dict.mgr.js';
|
|
3
|
+
|
|
4
|
+
export default class DictsPageState {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._types = [];
|
|
7
|
+
this._selectedTypeId = null;
|
|
8
|
+
this._items = [];
|
|
9
|
+
this._listeners = new Set();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
types() {
|
|
13
|
+
return this._types;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
selectedTypeId() {
|
|
17
|
+
return this._selectedTypeId;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
selectedType() {
|
|
21
|
+
return this._types.find((type) => type.id === this._selectedTypeId) ?? null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
items() {
|
|
25
|
+
return this._items;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
subscribe(listener) {
|
|
29
|
+
this._listeners.add(listener);
|
|
30
|
+
return () => this._listeners.delete(listener);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async loadTypes() {
|
|
34
|
+
const result = await new DictMgr.QueryTypes().submit();
|
|
35
|
+
this._types = result.data;
|
|
36
|
+
if (!this._selectedTypeId && this._types.length > 0) {
|
|
37
|
+
this._selectedTypeId = this._types[0].id;
|
|
38
|
+
}
|
|
39
|
+
await this.loadItems();
|
|
40
|
+
this._emit();
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async selectType(id) {
|
|
45
|
+
this._selectedTypeId = id;
|
|
46
|
+
await this.loadItems();
|
|
47
|
+
this._emit();
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async loadItems() {
|
|
52
|
+
if (this._selectedTypeId === null) {
|
|
53
|
+
this._items = [];
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const result = await new DictMgr.QueryItems(this._selectedTypeId).submit();
|
|
57
|
+
this._items = result.data;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async addType(payload) {
|
|
61
|
+
await new DictMgr.CreateType(payload).submit();
|
|
62
|
+
await this.loadTypes();
|
|
63
|
+
return payload;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async editType(id, payload) {
|
|
67
|
+
await new DictMgr.UpdateType(id, payload).submit();
|
|
68
|
+
await this.loadTypes();
|
|
69
|
+
return payload;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async removeType(id) {
|
|
73
|
+
await new DictMgr.RemoveType(id).submit();
|
|
74
|
+
if (this._selectedTypeId === id) {
|
|
75
|
+
this._selectedTypeId = null;
|
|
76
|
+
}
|
|
77
|
+
await this.loadTypes();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async addItem(payload) {
|
|
81
|
+
await new DictMgr.CreateItem(this._selectedTypeId, payload).submit();
|
|
82
|
+
await this.loadItems();
|
|
83
|
+
this._emit();
|
|
84
|
+
return payload;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async editItem(id, payload) {
|
|
88
|
+
await new DictMgr.UpdateItem(id, payload).submit();
|
|
89
|
+
await this.loadItems();
|
|
90
|
+
this._emit();
|
|
91
|
+
return payload;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async removeItem(id) {
|
|
95
|
+
await new DictMgr.RemoveItem(id).submit();
|
|
96
|
+
await this.loadItems();
|
|
97
|
+
this._emit();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
_emit() {
|
|
101
|
+
this._listeners.forEach((listener) => listener());
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** 字典结果结构类型声明(对应 dict.views.js)。 */
|
|
2
|
+
export type DictStatus = 'active' | 'disabled';
|
|
3
|
+
|
|
4
|
+
export class DictTypeItem {
|
|
5
|
+
id: number;
|
|
6
|
+
name: string;
|
|
7
|
+
code: string;
|
|
8
|
+
status: DictStatus;
|
|
9
|
+
remark: string;
|
|
10
|
+
constructor(init?: {
|
|
11
|
+
id: number;
|
|
12
|
+
name?: string;
|
|
13
|
+
code?: string;
|
|
14
|
+
status?: DictStatus;
|
|
15
|
+
remark?: string;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class DictItem {
|
|
20
|
+
id: number;
|
|
21
|
+
typeId: number | null;
|
|
22
|
+
label: string;
|
|
23
|
+
value: string;
|
|
24
|
+
sort: number;
|
|
25
|
+
status: DictStatus;
|
|
26
|
+
constructor(init?: {
|
|
27
|
+
id: number;
|
|
28
|
+
typeId?: number | null;
|
|
29
|
+
label?: string;
|
|
30
|
+
value?: string;
|
|
31
|
+
sort?: number;
|
|
32
|
+
status?: DictStatus;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
declare const Dicts: {
|
|
37
|
+
DictTypeItem: typeof DictTypeItem;
|
|
38
|
+
DictItem: typeof DictItem;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default Dicts;
|