zt-admin-template 1.0.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.
Files changed (80) hide show
  1. package/package.json +11 -0
  2. package/template/.env.development +2 -0
  3. package/template/.env.production +2 -0
  4. package/template/.env.test +2 -0
  5. package/template/.kiro/specs/course-backend-integration/.config.kiro +1 -0
  6. package/template/.kiro/specs/course-backend-integration/design.md +234 -0
  7. package/template/.kiro/specs/course-backend-integration/requirements.md +116 -0
  8. package/template/.kiro/specs/course-backend-integration/tasks.md +0 -0
  9. package/template/COMPLETION_CHECKLIST.md +305 -0
  10. package/template/DEPLOYMENT_GUIDE.md +391 -0
  11. package/template/FINAL_SUMMARY.md +428 -0
  12. package/template/IMPLEMENTATION_SUMMARY.md +382 -0
  13. package/template/INTEGRATION_GUIDE.md +458 -0
  14. package/template/PROJECT_OVERVIEW.md +343 -0
  15. package/template/QUICK_START.md +273 -0
  16. package/template/RBAC_Tutorial.md +424 -0
  17. package/template/README.md +16 -0
  18. package/template/React_Antd_TS_Tutorial.md +279 -0
  19. package/template/START_ALL.md +163 -0
  20. package/template/SYSTEM_MANAGEMENT.md +247 -0
  21. package/template/eslint.config.js +29 -0
  22. package/template/index.html +13 -0
  23. package/template/koa-server/README.md +65 -0
  24. package/template/koa-server/app.js +625 -0
  25. package/template/koa-server/package-lock.json +1547 -0
  26. package/template/koa-server/package.json +26 -0
  27. package/template/koa-server/public/assets/index-B1Cj4mG9.css +1 -0
  28. package/template/koa-server/public/assets/index-Mgxg-xqT.js +503 -0
  29. package/template/koa-server/public/favicon.svg +1 -0
  30. package/template/koa-server/public/icons.svg +24 -0
  31. package/template/koa-server/public/index.html +14 -0
  32. package/template/koa-server/uploads/1774265088480-962006467.png +0 -0
  33. package/template/koa-server/uploads/file-1774346891704-610962013.png +0 -0
  34. package/template/koa-server/uploads/file-1774346898887-58636533.png +0 -0
  35. package/template/koa-server/uploads/file-1774346912676-771862547.png +0 -0
  36. package/template/koa-server/uploads/file-1774347025308-130037894.png +0 -0
  37. package/template/koa-server/uploads/file-1774347031104-766499773.png +0 -0
  38. package/template/koa-server/uploads/file-1774347094969-731402203.png +0 -0
  39. package/template/koa-server/uploads/file-1774347101948-330296656.png +0 -0
  40. package/template/koa-server/uploads/file-1774351682377-932868720.png +0 -0
  41. package/template/koa-server/uploads/file-1774352037654-877426905.png +0 -0
  42. package/template/koa-server/uploads/file-1774352175463-386248997.png +0 -0
  43. package/template/koa-server/uploads/file-1774361446433-405859961.png +0 -0
  44. package/template/koa-server/uploads/file-1774361512207-465806267.png +0 -0
  45. package/template/lianxi.html +15 -0
  46. package/template/package-lock.json +6307 -0
  47. package/template/package.json +36 -0
  48. package/template/public/favicon.svg +1 -0
  49. package/template/public/icons.svg +24 -0
  50. package/template/src/App.css +184 -0
  51. package/template/src/App.tsx +44 -0
  52. package/template/src/api/course.ts +86 -0
  53. package/template/src/api/menu.ts +55 -0
  54. package/template/src/api/role.ts +58 -0
  55. package/template/src/api/user.ts +58 -0
  56. package/template/src/assets/hero.png +0 -0
  57. package/template/src/assets/react.svg +1 -0
  58. package/template/src/assets/vite.svg +1 -0
  59. package/template/src/components/Child.tsx +10 -0
  60. package/template/src/components/MainLayout.tsx +169 -0
  61. package/template/src/components/SunZi.tsx +13 -0
  62. package/template/src/contexts/ThemeContext.tsx +33 -0
  63. package/template/src/hooks/usePermission.tsx +62 -0
  64. package/template/src/index.css +111 -0
  65. package/template/src/main.tsx +13 -0
  66. package/template/src/pages/Dashboard.tsx +39 -0
  67. package/template/src/pages/Users.tsx +95 -0
  68. package/template/src/pages/banner/BannerList.tsx +182 -0
  69. package/template/src/pages/course/Course.tsx +586 -0
  70. package/template/src/pages/course/CourseList.tsx +168 -0
  71. package/template/src/pages/system/menu/Menu.tsx +501 -0
  72. package/template/src/pages/system/role/Role.tsx +458 -0
  73. package/template/src/pages/system/user/User.tsx +364 -0
  74. package/template/src/types/permission.ts +21 -0
  75. package/template/src/utils/request.tsx +94 -0
  76. package/template/src/vite-env.d.ts +1 -0
  77. package/template/tsconfig.app.json +32 -0
  78. package/template/tsconfig.json +7 -0
  79. package/template/tsconfig.node.json +13 -0
  80. package/template/vite.config.ts +30 -0
@@ -0,0 +1,458 @@
1
+ import React, { useState } from 'react';
2
+ import {
3
+ Table,
4
+ Button,
5
+ Modal,
6
+ Form,
7
+ Input,
8
+ Select,
9
+ Switch,
10
+ Space,
11
+ Popconfirm,
12
+ message,
13
+ Card,
14
+ Row,
15
+ Col,
16
+ Tooltip,
17
+ Tree,
18
+ Divider,
19
+ } from 'antd';
20
+ import {
21
+ PlusOutlined,
22
+ EditOutlined,
23
+ DeleteOutlined,
24
+ SearchOutlined,
25
+ ReloadOutlined,
26
+ DownloadOutlined,
27
+ } from '@ant-design/icons';
28
+ import type { TableColumnsType, TreeProps } from 'antd';
29
+ import dayjs from 'dayjs';
30
+
31
+ interface RoleRecord {
32
+ id: string;
33
+ roleName: string;
34
+ roleKey: string;
35
+ roleSort: number;
36
+ status: number;
37
+ delFlag: number;
38
+ createTime: string;
39
+ remark?: string;
40
+ permissions?: string[];
41
+ }
42
+
43
+ const menuTreeData: TreeProps['treeData'] = [
44
+ {
45
+ title: '系统管理',
46
+ key: 'system',
47
+ children: [
48
+ {
49
+ title: '用户管理',
50
+ key: 'system:user:list',
51
+ children: [
52
+ { title: '查看', key: 'system:user:query' },
53
+ { title: '新增', key: 'system:user:add' },
54
+ { title: '修改', key: 'system:user:edit' },
55
+ { title: '删除', key: 'system:user:remove' },
56
+ ],
57
+ },
58
+ {
59
+ title: '角色管理',
60
+ key: 'system:role:list',
61
+ children: [
62
+ { title: '查看', key: 'system:role:query' },
63
+ { title: '新增', key: 'system:role:add' },
64
+ { title: '修改', key: 'system:role:edit' },
65
+ { title: '删除', key: 'system:role:remove' },
66
+ ],
67
+ },
68
+ {
69
+ title: '菜单管理',
70
+ key: 'system:menu:list',
71
+ children: [
72
+ { title: '查看', key: 'system:menu:query' },
73
+ { title: '新增', key: 'system:menu:add' },
74
+ { title: '修改', key: 'system:menu:edit' },
75
+ { title: '删除', key: 'system:menu:remove' },
76
+ ],
77
+ },
78
+ ],
79
+ },
80
+ {
81
+ title: '业务管理',
82
+ key: 'business',
83
+ children: [
84
+ {
85
+ title: '订单管理',
86
+ key: 'business:order:list',
87
+ children: [
88
+ { title: '查看', key: 'business:order:query' },
89
+ { title: '新增', key: 'business:order:add' },
90
+ ],
91
+ },
92
+ ],
93
+ },
94
+ ];
95
+
96
+ const Role = () => {
97
+ const [form] = Form.useForm();
98
+ const [searchForm] = Form.useForm();
99
+ const [roles, setRoles] = useState<RoleRecord[]>([]);
100
+ const [originalRoles, setOriginalRoles] = useState<RoleRecord[]>([]);
101
+ const [filteredRoles, setFilteredRoles] = useState<RoleRecord[]>([]);
102
+
103
+ const [isModalVisible, setIsModalVisible] = useState(false);
104
+ const [editingRole, setEditingRole] = useState<RoleRecord | null>(null);
105
+ const [loading, setLoading] = useState(false);
106
+ const [checkedKeys, setCheckedKeys] = useState<React.Key[]>([]);
107
+
108
+ const defaultRoles: RoleRecord[] = [
109
+ {
110
+ id: '1',
111
+ roleName: '超级管理员',
112
+ roleKey: 'admin',
113
+ roleSort: 1,
114
+ status: 0,
115
+ delFlag: 0,
116
+ createTime: '2026-01-18 10:58:15',
117
+ remark: '超级管理员',
118
+ permissions: ['*:*:*'],
119
+ },
120
+ {
121
+ id: '2',
122
+ roleName: '普通角色',
123
+ roleKey: 'common',
124
+ roleSort: 2,
125
+ status: 0,
126
+ delFlag: 0,
127
+ createTime: '2026-01-18 10:58:15',
128
+ remark: '普通角色',
129
+ permissions: ['system:user:query', 'system:role:query'],
130
+ },
131
+ {
132
+ id: '3',
133
+ roleName: '测试角色',
134
+ roleKey: 'test',
135
+ roleSort: 3,
136
+ status: 0,
137
+ delFlag: 0,
138
+ createTime: '2026-01-17 09:30:00',
139
+ remark: '测试人员角色',
140
+ permissions: ['system:user:query', 'system:menu:query'],
141
+ },
142
+ ];
143
+
144
+ React.useEffect(() => {
145
+ setRoles(defaultRoles);
146
+ setOriginalRoles(defaultRoles);
147
+ setFilteredRoles(defaultRoles);
148
+ }, []);
149
+
150
+ const columns: TableColumnsType<RoleRecord> = [
151
+ {
152
+ title: '角色编号',
153
+ dataIndex: 'id',
154
+ key: 'id',
155
+ width: 100,
156
+ },
157
+ {
158
+ title: '角色名称',
159
+ dataIndex: 'roleName',
160
+ key: 'roleName',
161
+ width: 150,
162
+ },
163
+ {
164
+ title: '权限字符',
165
+ dataIndex: 'roleKey',
166
+ key: 'roleKey',
167
+ width: 150,
168
+ },
169
+ {
170
+ title: '显示顺序',
171
+ dataIndex: 'roleSort',
172
+ key: 'roleSort',
173
+ width: 100,
174
+ },
175
+ {
176
+ title: '状态',
177
+ dataIndex: 'status',
178
+ key: 'status',
179
+ width: 80,
180
+ render: (status: number) => (
181
+ <Switch checked={status === 0} disabled />
182
+ ),
183
+ },
184
+ {
185
+ title: '创建时间',
186
+ dataIndex: 'createTime',
187
+ key: 'createTime',
188
+ width: 180,
189
+ },
190
+ {
191
+ title: '操作',
192
+ key: 'action',
193
+ width: 200,
194
+ fixed: 'right',
195
+ render: (_, record) => (
196
+ <Space size="small">
197
+ <Tooltip title="编辑">
198
+ <Button
199
+ type="primary"
200
+ size="small"
201
+ icon={<EditOutlined />}
202
+ onClick={() => handleEdit(record)}
203
+ />
204
+ </Tooltip>
205
+ <Tooltip title="删除">
206
+ <Popconfirm
207
+ title="删除角色"
208
+ description="确定删除该角色吗?"
209
+ onConfirm={() => handleDelete(record.id)}
210
+ okText="确定"
211
+ cancelText="取消"
212
+ >
213
+ <Button danger size="small" icon={<DeleteOutlined />} />
214
+ </Popconfirm>
215
+ </Tooltip>
216
+ </Space>
217
+ ),
218
+ },
219
+ ];
220
+
221
+ const handleAdd = () => {
222
+ setEditingRole(null);
223
+ form.resetFields();
224
+ setCheckedKeys([]);
225
+ setIsModalVisible(true);
226
+ };
227
+
228
+ const handleEdit = (record: RoleRecord) => {
229
+ setEditingRole(record);
230
+ form.setFieldsValue({
231
+ roleName: record.roleName,
232
+ roleKey: record.roleKey,
233
+ roleSort: record.roleSort,
234
+ status: record.status === 0,
235
+ remark: record.remark,
236
+ });
237
+ setCheckedKeys(record.permissions || []);
238
+ setIsModalVisible(true);
239
+ };
240
+
241
+ const handleDelete = (id: string) => {
242
+ setRoles(roles.filter(role => role.id !== id));
243
+ message.success('删除成功');
244
+ };
245
+
246
+ const handleModalOk = async () => {
247
+ try {
248
+ const values = await form.validateFields();
249
+ setLoading(true);
250
+
251
+ if (editingRole) {
252
+ setRoles(
253
+ roles.map(role =>
254
+ role.id === editingRole.id
255
+ ? {
256
+ ...role,
257
+ ...values,
258
+ status: values.status ? 0 : 1,
259
+ permissions: checkedKeys as string[],
260
+ }
261
+ : role
262
+ )
263
+ );
264
+ message.success('编辑成功');
265
+ } else {
266
+ const newRole: RoleRecord = {
267
+ id: String(roles.length + 1),
268
+ ...values,
269
+ status: values.status ? 0 : 1,
270
+ delFlag: 0,
271
+ createTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
272
+ permissions: checkedKeys as string[],
273
+ };
274
+ setRoles([...roles, newRole]);
275
+ message.success('添加成功');
276
+ }
277
+
278
+ setIsModalVisible(false);
279
+ form.resetFields();
280
+ setCheckedKeys([]);
281
+ } catch (error) {
282
+ console.error('Validation failed:', error);
283
+ } finally {
284
+ setLoading(false);
285
+ }
286
+ };
287
+
288
+ const handleSearch = (values: any) => {
289
+ const { roleName, roleKey, status } = values;
290
+ let filtered = [...originalRoles];
291
+
292
+ if (roleName) {
293
+ filtered = filtered.filter(role =>
294
+ role.roleName.toLowerCase().includes(roleName.toLowerCase())
295
+ );
296
+ }
297
+
298
+ if (roleKey) {
299
+ filtered = filtered.filter(role =>
300
+ role.roleKey.toLowerCase().includes(roleKey.toLowerCase())
301
+ );
302
+ }
303
+
304
+ if (status !== undefined && status !== null) {
305
+ filtered = filtered.filter(role => role.status === status);
306
+ }
307
+
308
+ setFilteredRoles(filtered);
309
+ };
310
+
311
+ const handleReset = () => {
312
+ searchForm.resetFields();
313
+ setFilteredRoles(originalRoles);
314
+ };
315
+
316
+ const handleRefresh = () => {
317
+ searchForm.resetFields();
318
+ setFilteredRoles(originalRoles);
319
+ };
320
+
321
+ const handleExport = () => {
322
+ message.success('导出成功');
323
+ };
324
+
325
+ return (
326
+ <div style={{ padding: '24px' }}>
327
+ <Card style={{ marginBottom: '24px' }}>
328
+ <Form
329
+ form={searchForm}
330
+ layout="inline"
331
+ onFinish={handleSearch}
332
+ style={{ marginBottom: '16px' }}
333
+ >
334
+ <Form.Item name="roleName" label="角色名称">
335
+ <Input placeholder="请输入角色名称" />
336
+ </Form.Item>
337
+ <Form.Item name="roleKey" label="权限字符">
338
+ <Input placeholder="请输入权限字符" />
339
+ </Form.Item>
340
+ <Form.Item name="status" label="状态">
341
+ <Select placeholder="请选择状态" style={{ width: 120 }} allowClear>
342
+ <Select.Option value={0}>正常</Select.Option>
343
+ <Select.Option value={1}>停用</Select.Option>
344
+ </Select>
345
+ </Form.Item>
346
+ <Form.Item>
347
+ <Button type="primary" htmlType="submit" icon={<SearchOutlined />}>
348
+ 搜索
349
+ </Button>
350
+ </Form.Item>
351
+ <Form.Item>
352
+ <Button onClick={handleReset}>重置</Button>
353
+ </Form.Item>
354
+ </Form>
355
+ </Card>
356
+
357
+ <Card>
358
+ <Row gutter={[16, 16]} style={{ marginBottom: '16px' }}>
359
+ <Col>
360
+ <Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
361
+ 新增
362
+ </Button>
363
+ </Col>
364
+ <Col>
365
+ <Button icon={<ReloadOutlined />} onClick={handleRefresh}>
366
+ 刷新
367
+ </Button>
368
+ </Col>
369
+ <Col>
370
+ <Button icon={<DownloadOutlined />} onClick={handleExport}>
371
+ 导出
372
+ </Button>
373
+ </Col>
374
+ </Row>
375
+
376
+ <Table
377
+ columns={columns}
378
+ dataSource={filteredRoles}
379
+ rowKey="id"
380
+ pagination={{
381
+ pageSize: 10,
382
+ total: filteredRoles.length,
383
+ showSizeChanger: true,
384
+ showQuickJumper: true,
385
+ showTotal: (total: number) => `共 ${total} 条`,
386
+ }}
387
+ scroll={{ x: 1200 }}
388
+ />
389
+ </Card>
390
+
391
+ <Modal
392
+ title={editingRole ? '编辑角色' : '新增角色'}
393
+ open={isModalVisible}
394
+ onOk={handleModalOk}
395
+ onCancel={() => {
396
+ setIsModalVisible(false);
397
+ form.resetFields();
398
+ setCheckedKeys([]);
399
+ }}
400
+ width={700}
401
+ confirmLoading={loading}
402
+ >
403
+ <Form form={form} layout="vertical" autoComplete="off">
404
+ <Form.Item
405
+ name="roleName"
406
+ label="角色名称"
407
+ rules={[{ required: true, message: '请输入角色名称' }]}
408
+ >
409
+ <Input placeholder="请输入角色名称" />
410
+ </Form.Item>
411
+
412
+ <Form.Item
413
+ name="roleKey"
414
+ label="权限字符"
415
+ rules={[{ required: true, message: '请输入权限字符' }]}
416
+ >
417
+ <Input placeholder="请输入权限字符" />
418
+ </Form.Item>
419
+
420
+ <Row gutter={16}>
421
+ <Col span={12}>
422
+ <Form.Item
423
+ name="roleSort"
424
+ label="显示顺序"
425
+ rules={[{ required: true, message: '请输入显示顺序' }]}
426
+ >
427
+ <Input type="number" placeholder="请输入显示顺序" />
428
+ </Form.Item>
429
+ </Col>
430
+ <Col span={12}>
431
+ <Form.Item name="status" label="状态" valuePropName="checked">
432
+ <Switch checkedChildren="正常" unCheckedChildren="停用" />
433
+ </Form.Item>
434
+ </Col>
435
+ </Row>
436
+
437
+ <Divider>权限分配</Divider>
438
+
439
+ <div style={{ border: '1px solid #d9d9d9', borderRadius: '4px', padding: '12px', maxHeight: '300px', overflow: 'auto' }}>
440
+ <Tree
441
+ checkable
442
+ defaultExpandAll
443
+ treeData={menuTreeData}
444
+ checkedKeys={checkedKeys}
445
+ onCheck={(keys: any) => setCheckedKeys(keys)}
446
+ />
447
+ </div>
448
+
449
+ <Form.Item name="remark" label="备注" style={{ marginTop: '16px' }}>
450
+ <Input.TextArea placeholder="请输入备注" rows={3} />
451
+ </Form.Item>
452
+ </Form>
453
+ </Modal>
454
+ </div>
455
+ );
456
+ };
457
+
458
+ export default Role;