listpage_cli 0.0.206 → 0.0.208

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "listpage_cli",
3
- "version": "0.0.206",
3
+ "version": "0.0.208",
4
4
  "private": false,
5
5
  "bin": {
6
6
  "listpage_cli": "bin/cli.js"
@@ -23,7 +23,7 @@
23
23
  "class-transformer": "^0.5.1",
24
24
  "class-validator": "~0.14.2",
25
25
  "rxjs": "^7.8.1",
26
- "listpage-next-nest": "~0.0.206"
26
+ "listpage-next-nest": "~0.0.208"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@nestjs/schematics": "^11.0.0",
@@ -12,7 +12,7 @@
12
12
  "dependencies": {
13
13
  "react": "^19.2.0",
14
14
  "react-dom": "^19.2.0",
15
- "listpage-next": "~0.0.206",
15
+ "listpage-next": "~0.0.208",
16
16
  "react-router-dom": ">=6.0.0",
17
17
  "@ant-design/v5-patch-for-react-19": "~1.0.3",
18
18
  "ahooks": "^3.9.5",
@@ -5,12 +5,13 @@ const isDev = process.env.NODE_ENV === 'development';
5
5
  // 创建axios实例
6
6
  const apiClient = new HttpClient({
7
7
  token: 'admin',
8
+ tokenKey: '',
8
9
  successCodes: [20000, 200],
9
10
  server: {
10
11
  protocol: undefined,
11
12
  host: isDev ? 'localhost' : undefined,
12
13
  port: isDev ? '3000' : undefined,
13
- publicPath: '/api/v1/mbti',
14
+ publicPath: '/api/v1',
14
15
  },
15
16
  config: {
16
17
  timeout: 10000,
@@ -0,0 +1,5 @@
1
+ import user from './user';
2
+
3
+ export default {
4
+ user,
5
+ };
@@ -0,0 +1,19 @@
1
+ import apiClient from './config';
2
+
3
+ type ReqLogin = {
4
+ email: string;
5
+ password: string;
6
+ };
7
+
8
+ type ResLogin = {
9
+ token: string;
10
+ };
11
+
12
+ export const login = async (values: ReqLogin) => {
13
+ const response = await apiClient.post<ResLogin>('/auth/login', values);
14
+ return response.data.data!;
15
+ };
16
+
17
+ export default {
18
+ login,
19
+ };
@@ -0,0 +1,3 @@
1
+ export const Home = () => {
2
+ return <>Home</>;
3
+ };
@@ -0,0 +1,266 @@
1
+ # AI 生成规范
2
+
3
+ ## 总则
4
+
5
+ - 本规范仅约束 `listpage-next` 的使用与输出格式,避免输出与其无关的项目通用规则。
6
+ - 生成的页面应围绕 `ListPage` 组件完整配置:`storageKey`、`initialValues`、`request`、`filter.options`、`table.columns`、`tableProps.rowKey` 必须齐全。
7
+ - 页面内的动作分层清晰:页面级动作用 `header.extra`,表格级动作用 `table.extra`,浮层通过 `floats` 管理。
8
+ - 所有数据请求函数必须返回 `PaginationData<T>`,筛选与分页参数通过 `params`/`filters` 传入。
9
+
10
+ ## AI 生成流程(步骤)
11
+
12
+ - 步骤 1:创建目录结构
13
+ - `pages/<Feature>/index.tsx`、`config/{filters,columns,request,floats}.tsx`、`components/*`(浮层)、`hooks/*`(可选)、`types.ts`(可选)。
14
+ - 步骤 2:定义筛选 `filters.tsx`
15
+ - 使用 AntD 组件,默认加 `allowClear`;
16
+ - 步骤 3:定义表格列 `columns.tsx`
17
+ - 原子列优先使用 `component: 'text' | 'link' | 'switch'`;复杂渲染用 `render(value, record)`。
18
+ - 固定关键列(如选择、操作)并设置 `width`、`ellipsis`、`onHeaderCell`。
19
+ - 步骤 4:实现请求 `request.ts`
20
+ - 签名:`(params, filters) => Promise<PaginationData<T>>`;失败返回空分页结构。
21
+ - 处理日期区间:`daterange` 在请求中展开为 `startDate`/`endDate`。
22
+ - 步骤 5:组装页面 `index.tsx`
23
+ - 填写唯一 `storageKey`(命名见下),配置 `initialValues`,注入 `request`、`filter.options`、`table.columns` 与 `tableProps.rowKey`。
24
+ - 页面级动作放到 `header.extra`,表格级动作放到 `table.extra`。
25
+ - 步骤 6:注册浮层 `floats`
26
+ - `[{ key, render }]`,组件遵循 `FloatComponentProps<T>`;在页面用 `ctx.showFloat(key, record)` 调用。
27
+ - 步骤 7:自检并修正
28
+ - 通过检查清单核对命名、分层、交互、返回类型与滚动/分页设置。
29
+
30
+ ## 命名与输出约定
31
+
32
+ - `storageKey`:`LISTPAGE_{FEATURE}` 或 `LISTPAGE_{FEATURE}_{VERSION}`,示例:`LISTPAGE_POLICY`、`LISTPAGE_CRAWLER_DATASOURCES_V2`。
33
+ - 浮层 `key`:短横线小写,例如 `create`、`runtime-config`、`logs`。
34
+ - 目录与文件:英文小驼峰;`columns.tsx`、`filters.tsx`、`request.ts`、`render.tsx`、`types.ts`。
35
+ - 事件命名:语义化动词名词组合,如 `summary`、`batch-start`。
36
+ - 行键 `rowKey`:必须与数据唯一字段一致,如 `id` 或 `name`。
37
+
38
+ ## 禁止事项
39
+
40
+ - 不在组件中直接修改列表记录对象;通过接口更新后调用 `ctx.refreshTable()`。
41
+ - 不在筛选输入变更时自动请求;仅在筛选操作或分页/排序变更时请求。
42
+
43
+ ## 1. 目标与范围
44
+
45
+ - 统一基于 `listpage-next` 的列表页开发方式,降低重复和不一致。
46
+ - 适用于包含 Header、Filter、Toolbar、Table、Floats 的页面。
47
+
48
+ ## 2. 页面架构与目录约定
49
+
50
+ - 目录结构建议:
51
+ - `pages/<Feature>/index.tsx`:页面入口与 `ListPage` 组装。
52
+ - `pages/<Feature>/config/filters.tsx`:筛选表单项定义(`FilterFormOption[]`)。
53
+ - `pages/<Feature>/config/columns.tsx`:表格列定义(`ListPageTableColumn[]`)。
54
+ - `pages/<Feature>/config/request.ts`:数据请求函数(`(params, filters) => PaginationData<T>`)。
55
+ - `pages/<Feature>/config/render.tsx`:表格或工具栏扩展渲染。
56
+ - `pages/<Feature>/components/*`:浮层组件(Drawer/Modal),遵循 `FloatComponentProps<T>`。
57
+ - `pages/<Feature>/hooks/*`:与页面相关的 Hook(如 URL 参数到初始筛选值)。
58
+ - `pages/<Feature>/types.ts`:页面内专用类型。
59
+ - 文件命名:语义化英文小驼峰;浮层键名使用短横线小写,例如 `create`、`runtime-config`、`logs`。
60
+
61
+ ## 3. 核心组件与属性
62
+
63
+ - `ListPage` 由以下部分组成:
64
+ - `header`:页面级标题与入口动作(新建、导入)。
65
+ - `filter`:筛选区域(`options: FilterFormOption[]`)。
66
+ - `toolbar`:页面级工具栏,自定义与整体相关的批量动作。
67
+ - `table`:数据表格(列、选择、扩展渲染、`tableProps`)。
68
+ - `floats`:浮层体系(`Array<{ key: string; render: FloatRender }>`)。
69
+ - 推荐属性:
70
+ - `storageKey`:必填且唯一,持久化页内状态(示例:`LISTPAGE_POLICY`、`LISTPAGE_CRAWLER_DATASOURCES_V2`)。
71
+ - `initialValues`:一次性初始化值(仅组件首次挂载读取,如 `currentPage`、`pageSize`、`filterValues`)。
72
+ - `request(params, filters)`:统一返回 `PaginationData<T>`;参数包含分页、排序等。
73
+ - `table.tableProps.rowKey`:必填,保证选择与行操作正确。
74
+ - `rowSelectionType`:`'checkbox' | 'radio'`,开启选择能力。
75
+ - `pageRef`:`Ref<ListPageContext>`,用于外部控制或组合式页面。
76
+
77
+ ## 3.1 ListPageProps 速查(AI 必须输出)
78
+
79
+ - `storageKey: string` 唯一键名用于状态持久化。
80
+ - `initialValues?: { currentPage?: number; pageSize?: number; filterValues?: Record<string, any> }`
81
+ - `request: (params: any, filters: any) => Promise<PaginationData<any>>`
82
+ - `header?: { title?: string; extra?: (ctx: ListPageContext) => React.ReactNode }`
83
+ - `filter?: { options: FilterFormOption[]; labelInline?: boolean }`
84
+ - `toolbar?: { render?: (ctx: ListPageContext) => React.ReactNode }`
85
+ - `table: { columns: ListPageTableColumn[]; extra?: (ctx: ListPageContext) => React.ReactNode; rowSelectionType?: 'checkbox' | 'radio'; rowTitleKey?: string; tableProps?: { rowKey: string; size?: 'small'|'middle'|'large'; scroll?: { x?: number; y?: number }; pagination?: { pageSizeOptions?: number[] } } }`
86
+ - `floats?: Array<{ key: string; render: FloatRender }>`
87
+ - `pageRef?: React.RefObject<ListPageContext>`
88
+ - `styles?: { page?: React.CSSProperties }`
89
+
90
+ ## 3.2 类型优先策略(AI 必须遵循)
91
+
92
+ - 为页面定义明确的记录类型 `TRecord` 与筛选类型 `TFilters`,避免使用 `any`。
93
+ - `columns` 使用 `ListPageTableColumn<TRecord>[]`,保证 `render`、`component` 的入参类型正确。
94
+ - `request(params, filters)` 返回 `Promise<PaginationData<TRecord>>`,`params` 显式声明 `{ current?: number; pageSize?: number }`。
95
+ - 浮层组件签名使用 `React.FC<FloatComponentProps<TRecord>>`;`ctx.showFloat(key, record as TRecord)` 调用。
96
+ - `header.extra` / `table.extra` 的回调参数类型标注为 `ListPageContext`,避免未定义属性调用。
97
+ - 枚举或布尔型筛选项使用联合类型(如 `status?: 'enabled' | 'disabled'`)。
98
+ - 日期区间 `TFilters['dateRange']` 建议声明为 `[string, string]`,在 `request` 中展开为 `startDate`、`endDate`。
99
+
100
+ ## 4. 数据请求与类型规范
101
+
102
+ - 返回类型:`PaginationData<T> = { list: T[]; total: number; current: number; pageSize: number }`。
103
+ - 入参:`params`(分页、排序),`filters`(筛选表单值)。
104
+ - 实现要点:
105
+ - 保持幂等与可重入,失败时返回空数据结构而非抛错。
106
+ - 仅在筛选变更时重置到第 1 页;分页变更不重置筛选条件。
107
+ - 日期字符串统一为 `YYYY-MM-DD`;区间使用 `daterange` 组件并在 `request` 中展开为 `startDate`/`endDate`。
108
+
109
+ ## 5. 筛选 Filter 规范
110
+
111
+ - 组件:使用 AntD 控件或 `listpage-next` 内置组件(如 `AsyncSelect`、`daterange`)。
112
+ - 定义:`FilterFormOption[]`,每项包含 `name`、`label`、`component`(或字符串组件类型)与可选 `props`/`colSpan`。
113
+ - 交互:
114
+ - 表单值变化不自动请求;点击筛选或分页变更才请求。
115
+ - `allowClear` 作为默认交互;多选时使用 `mode='multiple'` 并控制 `maxTagCount`。
116
+ - 异步选择:
117
+ - `AsyncSelect.request` 返回包含 `list` 的分页结构;`list` 元素支持 `{ label, value }` 或纯值,统一为对象更易维护。
118
+ - 支持 `showSearch` 与服务端过滤(`(_, search) => { ... }`)。
119
+
120
+ ## 6. 表格 Table 规范
121
+
122
+ - 列定义:`ListPageTableColumn<T>` 支持:
123
+ - 原子渲染 `component: 'text' | 'link' | 'switch' | ...` 或自定义函数 `render(value, record, index)`。
124
+ - 列样式:`width`、`ellipsis`、`fixed`、`align`、`onHeaderCell`。
125
+ - 行内操作列统一放右侧,宽度尽量固定;危险操作配合二次确认。
126
+ - 表格扩展:
127
+ - `table.extra(ctx)` 提供与表格数据相关的工具入口(如批量操作),通过 `ctx.selection` 读取选择态。
128
+ - `rowTitleKey` 用于选择态顶部标题展示,提升可读性。
129
+ - 分页:统一在 `tableProps.pagination` 配置页码与每页条数选项;切换时保留当前筛选条件。
130
+
131
+ ## 7. Header 与 Toolbar 规范
132
+
133
+ - 分层:
134
+ - 页面级动作放 `header.extra`(新建、导入、全局跳转)。
135
+ - 表格级动作放 `table.extra`(列设置、导出、批量执行)。
136
+ - 访问上下文:`(ctx) => ...`,通过 `ctx.refreshTable()` 刷新列表,通过 `ctx.showFloat(key, record)` 打开浮层。
137
+
138
+ ## 8. 浮层 Floats 规范
139
+
140
+ - 注册:`floats: Array<{ key: string; render: FloatRender }>`,`key` 使用短横线小写(如 `create`、`runtime-config`、`logs`)。
141
+ - 组件约束:遵循 `FloatComponentProps<T>`:`{ record?: T; visible: boolean; onClose: () => void }`。
142
+ - 交互规范:
143
+ - 成功操作后统一 `message.success('操作成功')` 并按需 `ctx.refreshTable()`。
144
+ - 避免在浮层中直接修改列表记录对象;通过接口更新后刷新。
145
+
146
+ ## 9. 状态持久化与初始化策略
147
+
148
+ - `storageKey` 用于在本地持久化分页与筛选状态。
149
+ - `initialValues` 仅在首次挂载时读取并覆盖一次,之后页面内部表单驱动状态,外部变更 `state` 不实时生效,以避免性能问题与状态抖动。
150
+
151
+ ## 10. 上下文与事件机制
152
+
153
+ - `ListPageContext` 提供:`refreshTable`、`showFloat`、`selection`、`emit(event, payload)` 等能力。
154
+ - 事件范式:在列或按钮中 `ctx.emit('summary', record)`,页面或上层组件监听并处理跨区域动作。
155
+ - 引用:通过 `pageRef` 访问上下文能力,组合式页面可外部控制。
156
+
157
+ ## 11. 组件扩展与常用内置
158
+
159
+ - `AsyncButton`:处理异步点击,自动 loading,建议用于批量/长耗时操作。
160
+ - `AsyncSelect`:异步下拉;统一返回分页结构,支持搜索与多选。
161
+ - `daterange`:日期区间组件,统一格式与占位文案;在 `request` 中落盘为 `startDate`/`endDate`。
162
+
163
+ ## 12. 性能与可维护性
164
+
165
+ - 在 `render` 中避免重计算;复杂渲染提取到独立组件并 `memo`。
166
+ - 控制列宽、固定必要列,保证表格横向滚动体验;开启 `scroll: { x, y }`。
167
+ - 远程筛选与分页尽量由后端承担,前端仅拼装参数。
168
+ - 选择态相关操作尽量批量提交,减少重复请求。
169
+
170
+ ## 13. 最小模板示例
171
+
172
+ ```ts
173
+ import {
174
+ ListPage,
175
+ type FilterFormOption,
176
+ type ListPageTableColumn,
177
+ type PaginationData,
178
+ type ListPageContext,
179
+ } from 'listpage-next';
180
+ import { Button, Input, Select, Space } from 'antd';
181
+
182
+ type User = { id: number; name: string; address: string; active?: boolean };
183
+ type UserFilters = { name?: string; status?: 'enabled' | 'disabled' };
184
+
185
+ const filters: FilterFormOption[] = [
186
+ {
187
+ name: 'name',
188
+ label: '姓名',
189
+ component: <Input placeholder="请输入" allowClear />,
190
+ },
191
+ {
192
+ name: 'status',
193
+ label: '状态',
194
+ component: (
195
+ <Select
196
+ allowClear
197
+ options={[
198
+ { value: 'enabled', label: '启用' },
199
+ { value: 'disabled', label: '停用' },
200
+ ]}
201
+ />
202
+ ),
203
+ },
204
+ ];
205
+
206
+ const columns: ListPageTableColumn<User>[] = [
207
+ { title: '姓名', dataIndex: 'name', key: 'name', component: 'text' },
208
+ { title: '地址', dataIndex: 'address', key: 'address', ellipsis: true },
209
+ ];
210
+
211
+ const request = async (
212
+ params: { current?: number; pageSize?: number },
213
+ filters: UserFilters,
214
+ ): Promise<PaginationData<User>> => {
215
+ const { current = 1, pageSize = 10 } = params || {};
216
+ const all: User[] = Array.from({ length: 100 }).map((_, i) => ({
217
+ id: i + 1,
218
+ name: `Edward ${i + 1}`,
219
+ address: `Address ${i + 1}`,
220
+ active: i % 2 === 0,
221
+ }));
222
+ let list = all.filter(
223
+ (r) => !filters?.name || r.name.includes(filters.name!),
224
+ );
225
+ const skip = (current - 1) * pageSize;
226
+ return {
227
+ list: list.slice(skip, skip + pageSize),
228
+ total: list.length,
229
+ current,
230
+ pageSize,
231
+ };
232
+ };
233
+
234
+ export default function Page() {
235
+ return (
236
+ <ListPage
237
+ storageKey="demo-listpage"
238
+ initialValues={{ currentPage: 1, pageSize: 10 }}
239
+ request={request}
240
+ header={{
241
+ title: '用户列表',
242
+ extra: (ctx: ListPageContext) => (
243
+ <Space>
244
+ <Button onClick={() => ctx.refreshTable()}>刷新</Button>
245
+ </Space>
246
+ ),
247
+ }}
248
+ filter={{ options: filters }}
249
+ table={{ columns, tableProps: { rowKey: 'id' } }}
250
+ />
251
+ );
252
+ }
253
+ ```
254
+
255
+ ## 14. 生成检查清单(AI 必须自检)
256
+
257
+ - `storageKey` 唯一且语义化(如 `LISTPAGE_{FEATURE}`)。
258
+ - `initialValues` 首次挂载设置分页与 `filterValues`(如需)。
259
+ - `request(params, filters)` 返回 `PaginationData<T>`,失败返回空结构。
260
+ - `filter.options` 定义完整,异步选择遵循返回结构;日期区间用 `daterange` 并在请求中展开。
261
+ - `table.columns` 使用原子组件或 `render`;关键列固定、宽度合理、开启 `ellipsis`。
262
+ - 设置 `tableProps.rowKey` 与分页/滚动;选择态按需开启 `rowSelectionType` 与 `rowTitleKey`。
263
+ - 页面级动作在 `header.extra`;表格级动作在 `table.extra`;浮层通过 `floats` 管理。
264
+ - 成功后 `message.success` 与 `ctx.refreshTable()`;危险操作二次确认。
265
+
266
+ 本规范自发布之日起执行,后续将根据使用反馈迭代完善。
File without changes