@robsun/create-keystone-app 0.2.4 → 0.2.6
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/package.json +1 -1
- package/template/.claude/skills/keystone-dev/SKILL.md +75 -74
- package/template/.claude/skills/keystone-dev/TEMPLATES.md +73 -19
- package/template/.codex/skills/keystone-dev/SKILL.md +75 -74
- package/template/.codex/skills/keystone-dev/TEMPLATES.md +73 -19
- package/template/apps/web/package.json +1 -1
- package/template/pnpm-lock.yaml +5 -6
package/package.json
CHANGED
|
@@ -1,74 +1,75 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: keystone-dev
|
|
3
|
-
description: 基于 Keystone 平台开发业务模块。当用户需要创建新模块、添加业务功能、实现 CRUD、审批流程、数据导入导出、文件上传时使用。Use when creating modules, adding features, implementing CRUD, approval workflows, import/export, or file upload for Keystone platform.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Keystone 业务模块开发
|
|
7
|
-
|
|
8
|
-
使用 Keystone 平台快速开发业务模块。
|
|
9
|
-
|
|
10
|
-
## 工作流程
|
|
11
|
-
|
|
12
|
-
1. **解析需求** → 识别所需能力
|
|
13
|
-
2. **生成前端模块** → routes.tsx, pages/, services/, types.ts
|
|
14
|
-
3. **生成后端模块** → handler/, service/, repository/, migrations/
|
|
15
|
-
4. **自动注册** → main.tsx + manifest.go + config.yaml
|
|
16
|
-
5. **输出调整建议**
|
|
17
|
-
|
|
18
|
-
## 能力选择矩阵
|
|
19
|
-
|
|
20
|
-
根据需求关键词选用对应能力:
|
|
21
|
-
|
|
22
|
-
| 需求关键词 | 前端能力 | 后端能力 |
|
|
23
|
-
|-----------|---------|---------|
|
|
24
|
-
| 列表、查询 | ProTable + 过滤 + 分页 | ListHandler + Repository |
|
|
25
|
-
| 表单、编辑 | ProForm + 验证 | CreateHandler + UpdateHandler |
|
|
26
|
-
| 导入、批量 | DataImporter | ImportHandler + Job队列 |
|
|
27
|
-
| 导出、下载 | DataExporter | ExportHandler + Job队列 |
|
|
28
|
-
| 上传、附件 | FileUpload | UploadHandler + 存储服务 |
|
|
29
|
-
| 审批、流程 | ApprovalFlowEditor | 审批引擎 |
|
|
30
|
-
| 权限 | PermissionGuard | 权限中间件 |
|
|
31
|
-
|
|
32
|
-
详细能力清单见 [CAPABILITIES.md](CAPABILITIES.md)。
|
|
33
|
-
代码模板见 [TEMPLATES.md](TEMPLATES.md)。
|
|
34
|
-
|
|
35
|
-
## 模块结构约定
|
|
36
|
-
|
|
37
|
-
### 前端模块
|
|
38
|
-
```
|
|
39
|
-
apps/web/src/modules/{name}/
|
|
40
|
-
├── index.ts # registerModule()
|
|
41
|
-
├── routes.tsx # 路由 + 菜单 + 权限
|
|
42
|
-
├── pages/
|
|
43
|
-
│ ├── List.tsx # ProTable
|
|
44
|
-
│ ├── Detail.tsx
|
|
45
|
-
│ └── Form.tsx # ProForm
|
|
46
|
-
├── services/api.ts
|
|
47
|
-
├── types.ts
|
|
48
|
-
└── help/index.md
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### 后端模块
|
|
52
|
-
```
|
|
53
|
-
apps/server/internal/modules/{name}/
|
|
54
|
-
├── module.go
|
|
55
|
-
├── api/handler/
|
|
56
|
-
├── domain/models/
|
|
57
|
-
├── domain/service/
|
|
58
|
-
├── infra/repository/
|
|
59
|
-
└── bootstrap/migrations/
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## 权限命名
|
|
63
|
-
|
|
64
|
-
格式: `{module}:{resource}:{action}`
|
|
65
|
-
|
|
66
|
-
动作: view | create | update | delete | manage | export | import | approve
|
|
67
|
-
|
|
68
|
-
## 注册步骤
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
1.
|
|
73
|
-
2.
|
|
74
|
-
3.
|
|
1
|
+
---
|
|
2
|
+
name: keystone-dev
|
|
3
|
+
description: 基于 Keystone 平台开发业务模块。当用户需要创建新模块、添加业务功能、实现 CRUD、审批流程、数据导入导出、文件上传时使用。Use when creating modules, adding features, implementing CRUD, approval workflows, import/export, or file upload for Keystone platform.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Keystone 业务模块开发
|
|
7
|
+
|
|
8
|
+
使用 Keystone 平台快速开发业务模块。
|
|
9
|
+
|
|
10
|
+
## 工作流程
|
|
11
|
+
|
|
12
|
+
1. **解析需求** → 识别所需能力
|
|
13
|
+
2. **生成前端模块** → routes.tsx, pages/, services/, types.ts
|
|
14
|
+
3. **生成后端模块** → handler/, service/, repository/, migrations/
|
|
15
|
+
4. **自动注册** → main.tsx + manifest.go + config.yaml
|
|
16
|
+
5. **输出调整建议**
|
|
17
|
+
|
|
18
|
+
## 能力选择矩阵
|
|
19
|
+
|
|
20
|
+
根据需求关键词选用对应能力:
|
|
21
|
+
|
|
22
|
+
| 需求关键词 | 前端能力 | 后端能力 |
|
|
23
|
+
|-----------|---------|---------|
|
|
24
|
+
| 列表、查询 | ProTable + 过滤 + 分页 | ListHandler + Repository |
|
|
25
|
+
| 表单、编辑 | ProForm + 验证 | CreateHandler + UpdateHandler |
|
|
26
|
+
| 导入、批量 | DataImporter | ImportHandler + Job队列 |
|
|
27
|
+
| 导出、下载 | DataExporter | ExportHandler + Job队列 |
|
|
28
|
+
| 上传、附件 | FileUpload | UploadHandler + 存储服务 |
|
|
29
|
+
| 审批、流程 | ApprovalFlowEditor | 审批引擎 |
|
|
30
|
+
| 权限 | PermissionGuard | 权限中间件 |
|
|
31
|
+
|
|
32
|
+
详细能力清单见 [CAPABILITIES.md](CAPABILITIES.md)。
|
|
33
|
+
代码模板见 [TEMPLATES.md](TEMPLATES.md)。
|
|
34
|
+
|
|
35
|
+
## 模块结构约定
|
|
36
|
+
|
|
37
|
+
### 前端模块
|
|
38
|
+
```
|
|
39
|
+
apps/web/src/modules/{name}/
|
|
40
|
+
├── index.ts # registerModule()
|
|
41
|
+
├── routes.tsx # 路由 + 菜单 + 权限
|
|
42
|
+
├── pages/
|
|
43
|
+
│ ├── List.tsx # ProTable
|
|
44
|
+
│ ├── Detail.tsx
|
|
45
|
+
│ └── Form.tsx # ProForm
|
|
46
|
+
├── services/api.ts
|
|
47
|
+
├── types.ts
|
|
48
|
+
└── help/index.md
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 后端模块
|
|
52
|
+
```
|
|
53
|
+
apps/server/internal/modules/{name}/
|
|
54
|
+
├── module.go
|
|
55
|
+
├── api/handler/
|
|
56
|
+
├── domain/models/
|
|
57
|
+
├── domain/service/
|
|
58
|
+
├── infra/repository/
|
|
59
|
+
└── bootstrap/migrations/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 权限命名
|
|
63
|
+
|
|
64
|
+
格式: `{module}:{resource}:{action}`
|
|
65
|
+
|
|
66
|
+
动作: view | create | update | delete | manage | export | import | approve
|
|
67
|
+
|
|
68
|
+
## 注册步骤
|
|
69
|
+
|
|
70
|
+
生成代码后需完成以下注册(**缺一不可**):
|
|
71
|
+
|
|
72
|
+
1. **前端导入** `main.tsx`: `import './modules/{name}'`
|
|
73
|
+
2. **前端启用** `app.config.ts`: 添加到 `modules.enabled` 数组 ⚠️ **必须,否则菜单不显示**
|
|
74
|
+
3. **后端注册** `manifest.go`: `import {name}module "app/internal/modules/{name}"` + `Register({name}module.NewModule())`
|
|
75
|
+
4. **后端启用** `config.yaml`: 添加到 `modules.enabled`
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## 前端模板
|
|
4
4
|
|
|
5
|
+
### Ant Design v6 注意事项
|
|
6
|
+
- `Space` 使用 `orientation`,不要用 `direction`。
|
|
7
|
+
- `Modal` 使用 `destroyOnHidden`,不要用 `destroyOnClose`。
|
|
8
|
+
|
|
5
9
|
### routes.tsx
|
|
6
10
|
```tsx
|
|
7
11
|
import { RouteObject } from 'react-router-dom'
|
|
@@ -29,42 +33,78 @@ registerModule({ name: '{name}', routes })
|
|
|
29
33
|
|
|
30
34
|
### List.tsx (ProTable)
|
|
31
35
|
```tsx
|
|
36
|
+
import { useEffect, useState } from 'react'
|
|
32
37
|
import { ProTable } from '@robsun/keystone-web-core'
|
|
33
|
-
import {
|
|
34
|
-
import type { PaginatedResponse } from '@robsun/keystone-web-core'
|
|
38
|
+
import type { PaginatedData } from '@robsun/keystone-web-core'
|
|
35
39
|
import type { {Entity} } from '../types'
|
|
40
|
+
import { list{Entity} } from '../services/api'
|
|
41
|
+
|
|
42
|
+
const INITIAL_DATA: PaginatedData<{Entity}> = {
|
|
43
|
+
items: [],
|
|
44
|
+
total: 0,
|
|
45
|
+
page: 1,
|
|
46
|
+
page_size: 10,
|
|
47
|
+
}
|
|
36
48
|
|
|
37
49
|
export function Component() {
|
|
50
|
+
const [loading, setLoading] = useState(false)
|
|
51
|
+
const [data, setData] = useState(INITIAL_DATA)
|
|
52
|
+
|
|
38
53
|
const columns = [
|
|
39
54
|
{ title: 'ID', dataIndex: 'id' },
|
|
40
55
|
{ title: '名称', dataIndex: 'name' },
|
|
41
56
|
]
|
|
42
57
|
|
|
43
|
-
const fetchData = async (
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
const fetchData = async (page = data.page, pageSize = data.page_size) => {
|
|
59
|
+
setLoading(true)
|
|
60
|
+
try {
|
|
61
|
+
const result = await list{Entity}({ page, page_size: pageSize })
|
|
62
|
+
setData(result)
|
|
63
|
+
} finally {
|
|
64
|
+
setLoading(false)
|
|
65
|
+
}
|
|
46
66
|
}
|
|
47
67
|
|
|
48
|
-
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
void fetchData()
|
|
70
|
+
}, [])
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<ProTable
|
|
74
|
+
columns={columns}
|
|
75
|
+
dataSource={data.items}
|
|
76
|
+
rowKey="id"
|
|
77
|
+
loading={loading}
|
|
78
|
+
pagination={{
|
|
79
|
+
current: data.page,
|
|
80
|
+
pageSize: data.page_size,
|
|
81
|
+
total: data.total,
|
|
82
|
+
onChange: (page, pageSize) => {
|
|
83
|
+
void fetchData(page, pageSize)
|
|
84
|
+
},
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
)
|
|
49
88
|
}
|
|
50
89
|
```
|
|
51
90
|
|
|
52
91
|
### Form.tsx (ProForm)
|
|
53
92
|
```tsx
|
|
54
93
|
import { ProForm } from '@robsun/keystone-web-core'
|
|
55
|
-
import { api } from '@robsun/keystone-web-core'
|
|
56
94
|
import { useParams, useNavigate } from 'react-router-dom'
|
|
95
|
+
import { create{Entity}, update{Entity} } from '../services/api'
|
|
57
96
|
|
|
58
97
|
export function Component() {
|
|
59
|
-
const { id } = useParams()
|
|
98
|
+
const { id: rawId } = useParams()
|
|
60
99
|
const navigate = useNavigate()
|
|
61
|
-
const
|
|
100
|
+
const id = Number(rawId)
|
|
101
|
+
const isEdit = Number.isFinite(id)
|
|
62
102
|
|
|
63
103
|
const onSubmit = async (values: any) => {
|
|
64
104
|
if (isEdit) {
|
|
65
|
-
await
|
|
105
|
+
await update{Entity}(id, values)
|
|
66
106
|
} else {
|
|
67
|
-
await
|
|
107
|
+
await create{Entity}(values)
|
|
68
108
|
}
|
|
69
109
|
navigate('/{name}')
|
|
70
110
|
}
|
|
@@ -79,16 +119,30 @@ export function Component() {
|
|
|
79
119
|
|
|
80
120
|
### services/api.ts
|
|
81
121
|
```typescript
|
|
82
|
-
import { api } from '@robsun/keystone-web-core'
|
|
83
|
-
import type { ApiResponse, PaginatedResponse } from '@robsun/keystone-web-core'
|
|
122
|
+
import { api, type ApiResponse, type PaginatedData, type PaginationParams } from '@robsun/keystone-web-core'
|
|
84
123
|
import type { {Entity} } from '../types'
|
|
85
124
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
125
|
+
// 注意:使用 api 而非 apiClient,响应格式为 { data: { ... } }
|
|
126
|
+
export const list{Entity} = async (params: PaginationParams = {}) => {
|
|
127
|
+
const { data } = await api.get<ApiResponse<PaginatedData<{Entity}>>>(
|
|
128
|
+
'/{module}/{resources}',
|
|
129
|
+
{ params }
|
|
130
|
+
)
|
|
131
|
+
return data.data
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const create{Entity} = async (payload: Partial<{Entity}>) => {
|
|
135
|
+
const { data } = await api.post<ApiResponse<{Entity}>>('/{module}/{resources}', payload)
|
|
136
|
+
return data.data
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export const update{Entity} = async (id: number, payload: Partial<{Entity}>) => {
|
|
140
|
+
const { data } = await api.patch<ApiResponse<{Entity}>>(`/{module}/{resources}/${id}`, payload)
|
|
141
|
+
return data.data
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export const delete{Entity} = async (id: number) => {
|
|
145
|
+
await api.delete<ApiResponse<{ id: number }>>(`/{module}/{resources}/${id}`)
|
|
92
146
|
}
|
|
93
147
|
```
|
|
94
148
|
|
|
@@ -1,74 +1,75 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: keystone-dev
|
|
3
|
-
description: 基于 Keystone 平台开发业务模块。当用户需要创建新模块、添加业务功能、实现 CRUD、审批流程、数据导入导出、文件上传时使用。Use when creating modules, adding features, implementing CRUD, approval workflows, import/export, or file upload for Keystone platform.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Keystone 业务模块开发
|
|
7
|
-
|
|
8
|
-
使用 Keystone 平台快速开发业务模块。
|
|
9
|
-
|
|
10
|
-
## 工作流程
|
|
11
|
-
|
|
12
|
-
1. **解析需求** → 识别所需能力
|
|
13
|
-
2. **生成前端模块** → routes.tsx, pages/, services/, types.ts
|
|
14
|
-
3. **生成后端模块** → handler/, service/, repository/, migrations/
|
|
15
|
-
4. **自动注册** → main.tsx + manifest.go + config.yaml
|
|
16
|
-
5. **输出调整建议**
|
|
17
|
-
|
|
18
|
-
## 能力选择矩阵
|
|
19
|
-
|
|
20
|
-
根据需求关键词选用对应能力:
|
|
21
|
-
|
|
22
|
-
| 需求关键词 | 前端能力 | 后端能力 |
|
|
23
|
-
|-----------|---------|---------|
|
|
24
|
-
| 列表、查询 | ProTable + 过滤 + 分页 | ListHandler + Repository |
|
|
25
|
-
| 表单、编辑 | ProForm + 验证 | CreateHandler + UpdateHandler |
|
|
26
|
-
| 导入、批量 | DataImporter | ImportHandler + Job队列 |
|
|
27
|
-
| 导出、下载 | DataExporter | ExportHandler + Job队列 |
|
|
28
|
-
| 上传、附件 | FileUpload | UploadHandler + 存储服务 |
|
|
29
|
-
| 审批、流程 | ApprovalFlowEditor | 审批引擎 |
|
|
30
|
-
| 权限 | PermissionGuard | 权限中间件 |
|
|
31
|
-
|
|
32
|
-
详细能力清单见 [CAPABILITIES.md](CAPABILITIES.md)。
|
|
33
|
-
代码模板见 [TEMPLATES.md](TEMPLATES.md)。
|
|
34
|
-
|
|
35
|
-
## 模块结构约定
|
|
36
|
-
|
|
37
|
-
### 前端模块
|
|
38
|
-
```
|
|
39
|
-
apps/web/src/modules/{name}/
|
|
40
|
-
├── index.ts # registerModule()
|
|
41
|
-
├── routes.tsx # 路由 + 菜单 + 权限
|
|
42
|
-
├── pages/
|
|
43
|
-
│ ├── List.tsx # ProTable
|
|
44
|
-
│ ├── Detail.tsx
|
|
45
|
-
│ └── Form.tsx # ProForm
|
|
46
|
-
├── services/api.ts
|
|
47
|
-
├── types.ts
|
|
48
|
-
└── help/index.md
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### 后端模块
|
|
52
|
-
```
|
|
53
|
-
apps/server/internal/modules/{name}/
|
|
54
|
-
├── module.go
|
|
55
|
-
├── api/handler/
|
|
56
|
-
├── domain/models/
|
|
57
|
-
├── domain/service/
|
|
58
|
-
├── infra/repository/
|
|
59
|
-
└── bootstrap/migrations/
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## 权限命名
|
|
63
|
-
|
|
64
|
-
格式: `{module}:{resource}:{action}`
|
|
65
|
-
|
|
66
|
-
动作: view | create | update | delete | manage | export | import | approve
|
|
67
|
-
|
|
68
|
-
## 注册步骤
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
1.
|
|
73
|
-
2.
|
|
74
|
-
3.
|
|
1
|
+
---
|
|
2
|
+
name: keystone-dev
|
|
3
|
+
description: 基于 Keystone 平台开发业务模块。当用户需要创建新模块、添加业务功能、实现 CRUD、审批流程、数据导入导出、文件上传时使用。Use when creating modules, adding features, implementing CRUD, approval workflows, import/export, or file upload for Keystone platform.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Keystone 业务模块开发
|
|
7
|
+
|
|
8
|
+
使用 Keystone 平台快速开发业务模块。
|
|
9
|
+
|
|
10
|
+
## 工作流程
|
|
11
|
+
|
|
12
|
+
1. **解析需求** → 识别所需能力
|
|
13
|
+
2. **生成前端模块** → routes.tsx, pages/, services/, types.ts
|
|
14
|
+
3. **生成后端模块** → handler/, service/, repository/, migrations/
|
|
15
|
+
4. **自动注册** → main.tsx + manifest.go + config.yaml
|
|
16
|
+
5. **输出调整建议**
|
|
17
|
+
|
|
18
|
+
## 能力选择矩阵
|
|
19
|
+
|
|
20
|
+
根据需求关键词选用对应能力:
|
|
21
|
+
|
|
22
|
+
| 需求关键词 | 前端能力 | 后端能力 |
|
|
23
|
+
|-----------|---------|---------|
|
|
24
|
+
| 列表、查询 | ProTable + 过滤 + 分页 | ListHandler + Repository |
|
|
25
|
+
| 表单、编辑 | ProForm + 验证 | CreateHandler + UpdateHandler |
|
|
26
|
+
| 导入、批量 | DataImporter | ImportHandler + Job队列 |
|
|
27
|
+
| 导出、下载 | DataExporter | ExportHandler + Job队列 |
|
|
28
|
+
| 上传、附件 | FileUpload | UploadHandler + 存储服务 |
|
|
29
|
+
| 审批、流程 | ApprovalFlowEditor | 审批引擎 |
|
|
30
|
+
| 权限 | PermissionGuard | 权限中间件 |
|
|
31
|
+
|
|
32
|
+
详细能力清单见 [CAPABILITIES.md](CAPABILITIES.md)。
|
|
33
|
+
代码模板见 [TEMPLATES.md](TEMPLATES.md)。
|
|
34
|
+
|
|
35
|
+
## 模块结构约定
|
|
36
|
+
|
|
37
|
+
### 前端模块
|
|
38
|
+
```
|
|
39
|
+
apps/web/src/modules/{name}/
|
|
40
|
+
├── index.ts # registerModule()
|
|
41
|
+
├── routes.tsx # 路由 + 菜单 + 权限
|
|
42
|
+
├── pages/
|
|
43
|
+
│ ├── List.tsx # ProTable
|
|
44
|
+
│ ├── Detail.tsx
|
|
45
|
+
│ └── Form.tsx # ProForm
|
|
46
|
+
├── services/api.ts
|
|
47
|
+
├── types.ts
|
|
48
|
+
└── help/index.md
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 后端模块
|
|
52
|
+
```
|
|
53
|
+
apps/server/internal/modules/{name}/
|
|
54
|
+
├── module.go
|
|
55
|
+
├── api/handler/
|
|
56
|
+
├── domain/models/
|
|
57
|
+
├── domain/service/
|
|
58
|
+
├── infra/repository/
|
|
59
|
+
└── bootstrap/migrations/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 权限命名
|
|
63
|
+
|
|
64
|
+
格式: `{module}:{resource}:{action}`
|
|
65
|
+
|
|
66
|
+
动作: view | create | update | delete | manage | export | import | approve
|
|
67
|
+
|
|
68
|
+
## 注册步骤
|
|
69
|
+
|
|
70
|
+
生成代码后需完成以下注册(**缺一不可**):
|
|
71
|
+
|
|
72
|
+
1. **前端导入** `main.tsx`: `import './modules/{name}'`
|
|
73
|
+
2. **前端启用** `app.config.ts`: 添加到 `modules.enabled` 数组 ⚠️ **必须,否则菜单不显示**
|
|
74
|
+
3. **后端注册** `manifest.go`: `import {name}module "app/internal/modules/{name}"` + `Register({name}module.NewModule())`
|
|
75
|
+
4. **后端启用** `config.yaml`: 添加到 `modules.enabled`
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## 前端模板
|
|
4
4
|
|
|
5
|
+
### Ant Design v6 注意事项
|
|
6
|
+
- `Space` 使用 `orientation`,不要用 `direction`。
|
|
7
|
+
- `Modal` 使用 `destroyOnHidden`,不要用 `destroyOnClose`。
|
|
8
|
+
|
|
5
9
|
### routes.tsx
|
|
6
10
|
```tsx
|
|
7
11
|
import { RouteObject } from 'react-router-dom'
|
|
@@ -29,42 +33,78 @@ registerModule({ name: '{name}', routes })
|
|
|
29
33
|
|
|
30
34
|
### List.tsx (ProTable)
|
|
31
35
|
```tsx
|
|
36
|
+
import { useEffect, useState } from 'react'
|
|
32
37
|
import { ProTable } from '@robsun/keystone-web-core'
|
|
33
|
-
import {
|
|
34
|
-
import type { PaginatedResponse } from '@robsun/keystone-web-core'
|
|
38
|
+
import type { PaginatedData } from '@robsun/keystone-web-core'
|
|
35
39
|
import type { {Entity} } from '../types'
|
|
40
|
+
import { list{Entity} } from '../services/api'
|
|
41
|
+
|
|
42
|
+
const INITIAL_DATA: PaginatedData<{Entity}> = {
|
|
43
|
+
items: [],
|
|
44
|
+
total: 0,
|
|
45
|
+
page: 1,
|
|
46
|
+
page_size: 10,
|
|
47
|
+
}
|
|
36
48
|
|
|
37
49
|
export function Component() {
|
|
50
|
+
const [loading, setLoading] = useState(false)
|
|
51
|
+
const [data, setData] = useState(INITIAL_DATA)
|
|
52
|
+
|
|
38
53
|
const columns = [
|
|
39
54
|
{ title: 'ID', dataIndex: 'id' },
|
|
40
55
|
{ title: '名称', dataIndex: 'name' },
|
|
41
56
|
]
|
|
42
57
|
|
|
43
|
-
const fetchData = async (
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
const fetchData = async (page = data.page, pageSize = data.page_size) => {
|
|
59
|
+
setLoading(true)
|
|
60
|
+
try {
|
|
61
|
+
const result = await list{Entity}({ page, page_size: pageSize })
|
|
62
|
+
setData(result)
|
|
63
|
+
} finally {
|
|
64
|
+
setLoading(false)
|
|
65
|
+
}
|
|
46
66
|
}
|
|
47
67
|
|
|
48
|
-
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
void fetchData()
|
|
70
|
+
}, [])
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<ProTable
|
|
74
|
+
columns={columns}
|
|
75
|
+
dataSource={data.items}
|
|
76
|
+
rowKey="id"
|
|
77
|
+
loading={loading}
|
|
78
|
+
pagination={{
|
|
79
|
+
current: data.page,
|
|
80
|
+
pageSize: data.page_size,
|
|
81
|
+
total: data.total,
|
|
82
|
+
onChange: (page, pageSize) => {
|
|
83
|
+
void fetchData(page, pageSize)
|
|
84
|
+
},
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
)
|
|
49
88
|
}
|
|
50
89
|
```
|
|
51
90
|
|
|
52
91
|
### Form.tsx (ProForm)
|
|
53
92
|
```tsx
|
|
54
93
|
import { ProForm } from '@robsun/keystone-web-core'
|
|
55
|
-
import { api } from '@robsun/keystone-web-core'
|
|
56
94
|
import { useParams, useNavigate } from 'react-router-dom'
|
|
95
|
+
import { create{Entity}, update{Entity} } from '../services/api'
|
|
57
96
|
|
|
58
97
|
export function Component() {
|
|
59
|
-
const { id } = useParams()
|
|
98
|
+
const { id: rawId } = useParams()
|
|
60
99
|
const navigate = useNavigate()
|
|
61
|
-
const
|
|
100
|
+
const id = Number(rawId)
|
|
101
|
+
const isEdit = Number.isFinite(id)
|
|
62
102
|
|
|
63
103
|
const onSubmit = async (values: any) => {
|
|
64
104
|
if (isEdit) {
|
|
65
|
-
await
|
|
105
|
+
await update{Entity}(id, values)
|
|
66
106
|
} else {
|
|
67
|
-
await
|
|
107
|
+
await create{Entity}(values)
|
|
68
108
|
}
|
|
69
109
|
navigate('/{name}')
|
|
70
110
|
}
|
|
@@ -79,16 +119,30 @@ export function Component() {
|
|
|
79
119
|
|
|
80
120
|
### services/api.ts
|
|
81
121
|
```typescript
|
|
82
|
-
import { api } from '@robsun/keystone-web-core'
|
|
83
|
-
import type { ApiResponse, PaginatedResponse } from '@robsun/keystone-web-core'
|
|
122
|
+
import { api, type ApiResponse, type PaginatedData, type PaginationParams } from '@robsun/keystone-web-core'
|
|
84
123
|
import type { {Entity} } from '../types'
|
|
85
124
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
125
|
+
// 注意:使用 api 而非 apiClient,响应格式为 { data: { ... } }
|
|
126
|
+
export const list{Entity} = async (params: PaginationParams = {}) => {
|
|
127
|
+
const { data } = await api.get<ApiResponse<PaginatedData<{Entity}>>>(
|
|
128
|
+
'/{module}/{resources}',
|
|
129
|
+
{ params }
|
|
130
|
+
)
|
|
131
|
+
return data.data
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const create{Entity} = async (payload: Partial<{Entity}>) => {
|
|
135
|
+
const { data } = await api.post<ApiResponse<{Entity}>>('/{module}/{resources}', payload)
|
|
136
|
+
return data.data
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export const update{Entity} = async (id: number, payload: Partial<{Entity}>) => {
|
|
140
|
+
const { data } = await api.patch<ApiResponse<{Entity}>>(`/{module}/{resources}/${id}`, payload)
|
|
141
|
+
return data.data
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export const delete{Entity} = async (id: number) => {
|
|
145
|
+
await api.delete<ApiResponse<{ id: number }>>(`/{module}/{resources}/${id}`)
|
|
92
146
|
}
|
|
93
147
|
```
|
|
94
148
|
|
package/template/pnpm-lock.yaml
CHANGED
|
@@ -27,8 +27,8 @@ importers:
|
|
|
27
27
|
specifier: ^6.1.0
|
|
28
28
|
version: 6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
|
29
29
|
'@robsun/keystone-web-core':
|
|
30
|
-
specifier: 0.1.
|
|
31
|
-
version: 0.1.
|
|
30
|
+
specifier: 0.1.9
|
|
31
|
+
version: 0.1.9(@ant-design/icons@6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react-router-dom@7.11.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.2))
|
|
32
32
|
antd:
|
|
33
33
|
specifier: ^6.0.1
|
|
34
34
|
version: 6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
|
@@ -924,8 +924,8 @@ packages:
|
|
|
924
924
|
react: '>=16.9.0'
|
|
925
925
|
react-dom: '>=16.9.0'
|
|
926
926
|
|
|
927
|
-
'@robsun/keystone-web-core@0.1.
|
|
928
|
-
resolution: {integrity: sha512-
|
|
927
|
+
'@robsun/keystone-web-core@0.1.9':
|
|
928
|
+
resolution: {integrity: sha512-zbN6yiq3p/wwVOZvGj5YI6lT+xXCyWx87QIsM3IXnNyMxJl4OLRvv1xXN3u6K4uQpp2q+no4CeYLAfRwFIKNNw==}
|
|
929
929
|
peerDependencies:
|
|
930
930
|
'@ant-design/icons': ^6.1.0
|
|
931
931
|
antd: ^6.0.1
|
|
@@ -3744,7 +3744,7 @@ snapshots:
|
|
|
3744
3744
|
react: 19.2.3
|
|
3745
3745
|
react-dom: 19.2.3(react@19.2.3)
|
|
3746
3746
|
|
|
3747
|
-
'@robsun/keystone-web-core@0.1.
|
|
3747
|
+
'@robsun/keystone-web-core@0.1.9(@ant-design/icons@6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react-router-dom@7.11.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.2))':
|
|
3748
3748
|
dependencies:
|
|
3749
3749
|
'@ant-design/icons': 6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
|
3750
3750
|
'@vitejs/plugin-react': 5.1.2(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.2))
|
|
@@ -6027,4 +6027,3 @@ snapshots:
|
|
|
6027
6027
|
use-sync-external-store: 1.6.0(react@19.2.3)
|
|
6028
6028
|
|
|
6029
6029
|
zwitch@2.0.4: {}
|
|
6030
|
-
|