listpage_cli 0.0.209 → 0.0.211

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/bin/cli.js CHANGED
@@ -17,17 +17,28 @@ async function initCmd() {
17
17
  return initRush(targetDir, projectName);
18
18
  }
19
19
  async function initRush(targetDir, projectName) {
20
- (0, copy_1.copyRushTemplate)(targetDir);
21
20
  const { frontendName, backendName } = await (0, prompts_1.askRushQuestions)();
21
+ // 获取当前文件夹的目录名称
22
+ const appName = projectName === "." ? path_1.default.basename(targetDir) : projectName;
23
+ const vars = {
24
+ APP_NAME: appName,
25
+ BACKEND_NAME: backendName,
26
+ FRONTEND_NAME: frontendName,
27
+ };
28
+ (0, copy_1.copyRushTemplate)(targetDir, vars);
29
+ const installDeployScript = await (0, prompts_1.askInstallDeployScript)();
30
+ if (installDeployScript) {
31
+ (0, copy_1.copyDeployScriptTemplate)(targetDir, vars);
32
+ }
22
33
  (0, copy_1.updateRushJsonProjects)(path_1.default.join(targetDir, "rush.json"), frontendName, backendName);
23
34
  if (frontendName) {
24
- (0, copy_1.copyFrontendTemplate)(targetDir, frontendName);
35
+ (0, copy_1.copyFrontendTemplate)(targetDir, vars);
25
36
  }
26
37
  if (backendName) {
27
- (0, copy_1.copyBackendTemplate)(targetDir, backendName);
38
+ (0, copy_1.copyBackendTemplate)(targetDir, vars);
28
39
  }
29
40
  if (projectName !== ".")
30
- console.log(` cd ${projectName}`);
41
+ console.log(`cd ${projectName}`);
31
42
  console.log("请手动执行 rush update 安装依赖");
32
43
  }
33
44
  async function main() {
package/bin/copy.js CHANGED
@@ -7,14 +7,15 @@ exports.copyRushTemplate = copyRushTemplate;
7
7
  exports.updateRushJsonProjects = updateRushJsonProjects;
8
8
  exports.copyFrontendTemplate = copyFrontendTemplate;
9
9
  exports.copyBackendTemplate = copyBackendTemplate;
10
+ exports.copyDeployScriptTemplate = copyDeployScriptTemplate;
10
11
  exports.ensureDir = ensureDir;
11
12
  exports.isDirEmpty = isDirEmpty;
12
13
  const fs_1 = require("fs");
13
14
  const path_1 = __importDefault(require("path"));
14
15
  const utils_1 = require("./utils");
15
- function copyRushTemplate(targetDir) {
16
+ function copyRushTemplate(targetDir, vars) {
16
17
  const source = getTemplateDir("rush");
17
- copyDir(source, targetDir, {});
18
+ copyDir(source, targetDir, vars);
18
19
  }
19
20
  function updateRushJsonProjects(filepath, feAppName, beAppName) {
20
21
  const projects = [];
@@ -38,21 +39,22 @@ function updateRushJsonProjects(filepath, feAppName, beAppName) {
38
39
  json.projects = projects;
39
40
  (0, fs_1.writeFileSync)(filepath, JSON.stringify(json, null, 2), { encoding: "utf-8" });
40
41
  }
41
- function copyFrontendTemplate(targetDir, appName) {
42
- appName = (0, utils_1.composePkgName)(appName);
42
+ function copyFrontendTemplate(targetDir, vars) {
43
+ const appName = (0, utils_1.composePkgName)(vars.FRONTEND_NAME);
43
44
  targetDir = path_1.default.join(targetDir, `apps/${appName}`);
44
45
  const source = getTemplateDir("frontend");
45
- copyDir(source, targetDir, {
46
- PKG_NAME: appName,
47
- });
46
+ copyDir(source, targetDir, vars);
48
47
  }
49
- function copyBackendTemplate(targetDir, appName) {
50
- appName = (0, utils_1.composePkgName)(appName);
48
+ function copyBackendTemplate(targetDir, vars) {
49
+ const appName = (0, utils_1.composePkgName)(vars.BACKEND_NAME);
51
50
  targetDir = path_1.default.join(targetDir, `servers/${appName}`);
52
51
  const source = getTemplateDir("backend");
53
- copyDir(source, targetDir, {
54
- PKG_NAME: appName,
55
- });
52
+ copyDir(source, targetDir, vars);
53
+ }
54
+ function copyDeployScriptTemplate(targetDir, vars) {
55
+ targetDir = path_1.default.join(targetDir, `common/scripts/package-app`);
56
+ const source = getTemplateDir("package-app");
57
+ copyDir(source, targetDir, vars);
56
58
  }
57
59
  function getTemplateDir(type) {
58
60
  return path_1.default.join(__dirname, "..", "templates", `${type}-template`);
package/bin/prompts.js CHANGED
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.askRushQuestions = askRushQuestions;
7
7
  exports.askProjectPath = askProjectPath;
8
8
  exports.askOverwrite = askOverwrite;
9
+ exports.askInstallDeployScript = askInstallDeployScript;
9
10
  exports.printHelp = printHelp;
10
11
  exports.printVersion = printVersion;
11
12
  const enquirer_1 = require("enquirer");
@@ -48,6 +49,15 @@ async function askOverwrite() {
48
49
  process.exit(1);
49
50
  }
50
51
  }
52
+ async function askInstallDeployScript() {
53
+ const { ok } = await (0, enquirer_1.prompt)({
54
+ type: "confirm",
55
+ name: "ok",
56
+ message: "是否添加部署脚本?这个脚本允许你可以帮你快速构建docker镜像,并发布到阿里云等环境,但是需要本机有docker环境。",
57
+ initial: false,
58
+ });
59
+ return ok;
60
+ }
51
61
  function printHelp() {
52
62
  const h = [
53
63
  "用法: listpage_cli init",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "listpage_cli",
3
- "version": "0.0.209",
3
+ "version": "0.0.211",
4
4
  "private": false,
5
5
  "bin": {
6
6
  "listpage_cli": "bin/cli.js"
@@ -0,0 +1,58 @@
1
+ # 基于 openeuler/node 基础镜像
2
+ FROM alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/node:20.16
3
+
4
+ # 设置工作目录
5
+ WORKDIR /__APP_NAME__
6
+
7
+ # 复制 package.json 和 package-lock.json
8
+ COPY package*.json ./
9
+
10
+ # 复制 prisma 配置文件
11
+ COPY prisma ./prisma/
12
+
13
+ # 打印 Node.js 版本和当前目录信息
14
+ RUN node --version && npm --version && pwd && ls -la
15
+
16
+ # 安装依赖(增加超时时间和详细日志)
17
+ RUN npm config set fetch-timeout 600000 && \
18
+ npm config set fetch-retry-mintimeout 20000 && \
19
+ npm config set fetch-retry-maxtimeout 120000 && \
20
+ npm install --legacy-peer-deps --verbose
21
+
22
+ # 打印安装后的目录结构(检查 node_modules 是否存在)
23
+ RUN echo "=== 依赖安装完成,当前目录结构 ===" && ls -la && \
24
+ if [ -d "node_modules" ]; then \
25
+ echo "=== node_modules 目录大小 ===" && du -sh node_modules; \
26
+ else \
27
+ echo "=== node_modules 目录不存在 ==="; \
28
+ fi
29
+
30
+ # 生成 Prisma 客户端(此时应该不需要重新下载引擎)
31
+ RUN echo "=== 生成 Prisma 客户端 ===" && \
32
+ npm run prisma:gen
33
+
34
+ # 打印 Prisma 生成结果
35
+ RUN echo "=== Prisma 客户端生成完成 ===" && \
36
+ if [ -d "node_modules/.prisma" ]; then \
37
+ ls -la node_modules/.prisma/; \
38
+ else \
39
+ echo "Prisma 客户端目录不存在"; \
40
+ fi
41
+
42
+ # 复制应用代码
43
+ COPY dist ./dist/
44
+ COPY public ./public/
45
+
46
+ # 打印最终的应用目录结构
47
+ RUN echo "=== 最终应用目录结构 ===" && ls -la && \
48
+ if [ -d "dist" ]; then \
49
+ echo "=== dist 目录内容 ===" && ls -la dist/; \
50
+ else \
51
+ echo "dist 目录不存在"; \
52
+ fi
53
+
54
+ # 暴露端口
55
+ EXPOSE 3000
56
+
57
+ # 启动应用
58
+ CMD ["node", "dist/main.js"]
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "__PKG_NAME__",
2
+ "name": "__BACKEND_NAME__",
3
3
  "version": "0.0.1",
4
4
  "description": "",
5
5
  "author": "",
@@ -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.209"
26
+ "listpage-next-nest": "~0.0.211"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@nestjs/schematics": "^11.0.0",
@@ -1,13 +1,14 @@
1
1
  import { NestFactory } from '@nestjs/core';
2
2
  import { ValidationPipe } from '@nestjs/common';
3
- import { ResponseInterceptor } from 'listpage-next-nest';
3
+ import { ResponseInterceptor, StaticRouteMiddlewareFactory } from 'listpage-next-nest';
4
+ import * as path from 'path';
4
5
 
5
6
  import { AppModule } from './modules/app.module';
6
7
 
7
8
  async function bootstrap() {
8
9
  const app = await NestFactory.create(AppModule);
9
10
  app.useGlobalInterceptors(new ResponseInterceptor());
10
- app.setGlobalPrefix('api/v1');
11
+ app.setGlobalPrefix('/api/v1');
11
12
  // 启用全局验证管道
12
13
  app.useGlobalPipes(
13
14
  new ValidationPipe({
@@ -15,6 +16,17 @@ async function bootstrap() {
15
16
  transform: true,
16
17
  }),
17
18
  );
19
+ app.use(
20
+ StaticRouteMiddlewareFactory({
21
+ rootDir: path.join(__dirname, '..', 'public'),
22
+ routeMappings: [
23
+ {
24
+ prefix: '/__APP_NAME__',
25
+ htmlPath: '__APP_NAME__/index.html',
26
+ },
27
+ ],
28
+ }),
29
+ );
18
30
  // 启用CORS
19
31
  app.enableCors();
20
32
  await app.listen(3000);
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "__PKG_NAME__",
2
+ "name": "__FRONTEND_NAME__",
3
3
  "version": "1.0.0",
4
4
  "private": true,
5
5
  "type": "module",
@@ -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.209",
15
+ "listpage-next": "~0.0.211",
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",
@@ -6,4 +6,10 @@ export default defineConfig({
6
6
  server: {
7
7
  port: 8000,
8
8
  },
9
+ html: {
10
+ title: '__APP_NAME__',
11
+ },
12
+ output: {
13
+ assetPrefix: '/__APP_NAME__',
14
+ },
9
15
  });
@@ -9,7 +9,7 @@ type ResLogin = {
9
9
  token: string;
10
10
  };
11
11
 
12
- export const login = async (values: ReqLogin) => {
12
+ const login = async (values: ReqLogin) => {
13
13
  const response = await apiClient.post<ResLogin>('/auth/login', values);
14
14
  return response.data.data!;
15
15
  };
@@ -7,6 +7,8 @@ export const router = createBrowserRouter([
7
7
  element: <Layout />,
8
8
  children: [],
9
9
  },
10
- ]);
10
+ ], {
11
+ basename: '__APP_NAME__',
12
+ });
11
13
 
12
14
  export default router;
@@ -0,0 +1,28 @@
1
+ # Dependencies
2
+ node_modules/
3
+ npm-debug.log*
4
+ yarn-debug.log*
5
+ yarn-error.log*
6
+
7
+ # Build outputs
8
+ dist/
9
+ build/
10
+ temp/
11
+ output/
12
+
13
+ # Package files
14
+ *.zip
15
+ *.tar.gz
16
+
17
+ # IDE
18
+ .vscode/
19
+ .idea/
20
+ *.swp
21
+ *.swo
22
+
23
+ # OS
24
+ .DS_Store
25
+ Thumbs.db
26
+
27
+ # Logs
28
+ *.log
@@ -0,0 +1,33 @@
1
+ ## 内网部署方案
2
+
3
+ ### 步骤一:源码构建
4
+
5
+ `npm run build`
6
+
7
+ 此时会将前后端的代码打包在`output`目录下
8
+
9
+ ### 步骤二:修改 prisma 连接 url
10
+
11
+ 修改`output/prisma/schema.prisma`文件中的`datasource db`的`url`为内网的 url
12
+
13
+ ### 步骤三:内网环境仿真
14
+
15
+ 修改 dockerfile 中的基础镜像
16
+
17
+ ### 步骤四:带依赖的源码导出
18
+
19
+ `npm run package`
20
+
21
+ 此时会根据 dockerfile 中的基础镜像,将`output`目录下的代码和依赖导出到`output`目录下,比如 `docker-app-xxxxxx.tar.gz`
22
+
23
+ ### 步骤五:内网部署
24
+
25
+ 将导出的`docker-app-xxxxxx.tar.gz`文件上传到内网的服务器上,比如 `/opt/docker-app-xxxxxx.tar.gz`
26
+
27
+ 然后解压源码:
28
+
29
+ `tar -zxvf docker-app-xxxxxx.tar.gz`
30
+
31
+ ### 步骤六:启动服务
32
+
33
+ 进入到 dist 目录下, node main.js
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "package-app",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "dist/build.js",
6
+ "scripts": {
7
+ "build": "ts-node src/build.ts",
8
+ "package": "ts-node src/package.ts",
9
+ "publish": "ts-node src/publish.ts"
10
+ },
11
+ "dependencies": {
12
+ "listpage-next-deploy": "0.0.211"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "^20.0.0",
16
+ "@types/archiver": "^6.0.0",
17
+ "typescript": "^5.0.0",
18
+ "ts-node": "^10.9.0"
19
+ },
20
+ "keywords": [
21
+ "packaging",
22
+ "build",
23
+ "typescript"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT"
27
+ }
@@ -0,0 +1,6 @@
1
+ import { Builder } from "listpage-next-deploy";
2
+ import { config } from "./config";
3
+
4
+ const builder = new Builder(config);
5
+
6
+ builder.run();
@@ -0,0 +1,45 @@
1
+ import { Config } from "listpage-next-deploy";
2
+ import path from "path";
3
+
4
+ export const config = new Config({
5
+ root: path.join(__dirname, "../../../../"),
6
+ clean: true,
7
+ outputBaseDir: "common/scripts/package-app/output",
8
+ frontend: [
9
+ {
10
+ source: "apps/__FRONTEND_NAME__",
11
+ output: "public/",
12
+ outputName: "dist",
13
+ outputNewName: "__APP_NAME__",
14
+ },
15
+ ],
16
+ backend: {
17
+ source: "servers/__BACKEND_NAME__",
18
+ output: ".",
19
+ outputName: "dist",
20
+ outputNewName: "dist",
21
+ },
22
+ copyFiles: [
23
+ {
24
+ source: "servers/__BACKEND_NAME__/prisma",
25
+ dest: "common/scripts/package-app/output/prisma",
26
+ },
27
+ {
28
+ source: "servers/__BACKEND_NAME__/Dockerfile",
29
+ dest: "common/scripts/package-app/output/Dockerfile",
30
+ },
31
+ ],
32
+ docker: {
33
+ imageName: "__APP_NAME__",
34
+ imageTag: "0.0.1",
35
+ containerName: "__APP_NAME__",
36
+ // 需要和 dockerfile 中定义的 app 目录保持一致
37
+ appName: "__APP_NAME__",
38
+ registry: {
39
+ url: "registry.cn-hangzhou.aliyuncs.com",
40
+ namespace: "",
41
+ username: "",
42
+ password: "",
43
+ },
44
+ },
45
+ });
@@ -0,0 +1,5 @@
1
+ import { Packager } from "listpage-next-deploy";
2
+ import { config } from "./config";
3
+
4
+ const packager = new Packager(config);
5
+ packager.run();
@@ -0,0 +1,6 @@
1
+ import { Deployer } from "listpage-next-deploy";
2
+ import { config } from "./config";
3
+
4
+ const deployer = new Deployer(config);
5
+
6
+ deployer.run();
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "types": ["node"],
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "declaration": true,
15
+ "declarationMap": true,
16
+ "sourceMap": true
17
+ },
18
+ "include": [
19
+ "src/**/*"
20
+ ],
21
+ "exclude": [
22
+ "node_modules",
23
+ "dist"
24
+ ]
25
+ }
@@ -0,0 +1,25 @@
1
+ # 项目规则
2
+
3
+ ## 必须遵守的规则
4
+
5
+ ### 技术方案编写规则
6
+
7
+ 1. 存放目录: .trae/documents/ 下面。
8
+ 2. 文件名称: xxx 技术方案.md
9
+
10
+ ### 前端开发的规则
11
+
12
+ 1. 前端组件导出必须使用具名导出,禁止 export default 的写法!!!
13
+ 2. 当使用 ListPage 组件时,必须遵守项目内容文档:[ListPage-AI 生成规范](docs/ListPage-AI生成规范.md)。
14
+ 3. 禁止使用 React.FC 来定义组件,组件的类型应该是 `(props: Props) => JSX.Element`, 不用显式声明。
15
+ 4. 前端接口维护在 `api` 目录下, 所有的接口从 `api/index.ts` 中导出,严格遵守现在`api`目录的结构,并在需要的使用的时候从 `api/index.ts` 中引入
16
+
17
+ ### 后端开发的规则
18
+
19
+ 1. 后端接口如无特殊要求均采用 POST 请求
20
+ 2. 对于列表查询的,默认请求体一定包含 current, pageSize 两个参数
21
+ 3. 后端接口返回的格式要求如下:
22
+ - 失败时,直接抛出异常,由拦截器自行处理,不用管
23
+ - 成功时:
24
+ - 常规数据的格式:{ code: 0, data: {} },控制器返回的数据直接就是 data,不需要再包一层
25
+ - 列表数据的格式:{ code: 0, data: { list: [], total: 0, current: 1, pageSize: 10 } },控制器返回的数据直接就是 data,不需要再包一层
@@ -23,7 +23,7 @@
23
23
  - 填写唯一 `storageKey`(命名见下),配置 `initialValues`,注入 `request`、`filter.options`、`table.columns` 与 `tableProps.rowKey`。
24
24
  - 页面级动作放到 `header.extra`,表格级动作放到 `table.extra`。
25
25
  - 步骤 6:注册浮层 `floats`
26
- - `[{ key, render }]`,组件遵循 `FloatComponentProps<T>`;在页面用 `ctx.showFloat(key, record)` 调用。
26
+ - `[{ key, render }]`,组件遵循 `FloatComponentProps<T>`;在页面用 `ctx.showFloat(key, record, true)` 调用。
27
27
  - 步骤 7:自检并修正
28
28
  - 通过检查清单核对命名、分层、交互、返回类型与滚动/分页设置。
29
29
 
@@ -51,9 +51,10 @@
51
51
  - `pages/<Feature>/index.tsx`:页面入口与 `ListPage` 组装。
52
52
  - `pages/<Feature>/config/filters.tsx`:筛选表单项定义(`FilterFormOption[]`)。
53
53
  - `pages/<Feature>/config/columns.tsx`:表格列定义(`ListPageTableColumn[]`)。
54
+ - `pages/<Feature>/config/floats.tsx`:浮层定义(`ListPageFloatProps[]`)。
54
55
  - `pages/<Feature>/config/request.ts`:数据请求函数(`(params, filters) => PaginationData<T>`)。
55
56
  - `pages/<Feature>/config/render.tsx`:表格或工具栏扩展渲染。
56
- - `pages/<Feature>/components/*`:浮层组件(Drawer/Modal),遵循 `FloatComponentProps<T>`。
57
+ - `pages/<Feature>/components/*`:组件,浮层组件(Drawer/Modal)的 props 定义统一为 `FloatComponentProps<T>`。
57
58
  - `pages/<Feature>/hooks/*`:与页面相关的 Hook(如 URL 参数到初始筛选值)。
58
59
  - `pages/<Feature>/types.ts`:页面内专用类型。
59
60
  - 文件命名:语义化英文小驼峰;浮层键名使用短横线小写,例如 `create`、`runtime-config`、`logs`。
@@ -92,7 +93,7 @@
92
93
  - 为页面定义明确的记录类型 `TRecord` 与筛选类型 `TFilters`,避免使用 `any`。
93
94
  - `columns` 使用 `ListPageTableColumn<TRecord>[]`,保证 `render`、`component` 的入参类型正确。
94
95
  - `request(params, filters)` 返回 `Promise<PaginationData<TRecord>>`,`params` 显式声明 `{ current?: number; pageSize?: number }`。
95
- - 浮层组件签名使用 `React.FC<FloatComponentProps<TRecord>>`;`ctx.showFloat(key, record as TRecord)` 调用。
96
+ - 浮层组件签名使用 `React.FC<FloatComponentProps<TRecord>>`;`ctx.showFloat(key, record as TRecord, true)` 调用。
96
97
  - `header.extra` / `table.extra` 的回调参数类型标注为 `ListPageContext`,避免未定义属性调用。
97
98
  - 枚举或布尔型筛选项使用联合类型(如 `status?: 'enabled' | 'disabled'`)。
98
99
  - 日期区间 `TFilters['dateRange']` 建议声明为 `[string, string]`,在 `request` 中展开为 `startDate`、`endDate`。
@@ -133,16 +134,13 @@
133
134
  - 分层:
134
135
  - 页面级动作放 `header.extra`(新建、导入、全局跳转)。
135
136
  - 表格级动作放 `table.extra`(列设置、导出、批量执行)。
136
- - 访问上下文:`(ctx) => ...`,通过 `ctx.refreshTable()` 刷新列表,通过 `ctx.showFloat(key, record)` 打开浮层。
137
+ - 访问上下文:`(ctx) => ...`,通过 `ctx.refreshTable()` 刷新列表,通过 `ctx.showFloat(key, record, true)` 打开浮层。
137
138
 
138
139
  ## 8. 浮层 Floats 规范
139
140
 
140
141
  - 注册:`floats: Array<{ key: string; render: FloatRender }>`,`key` 使用短横线小写(如 `create`、`runtime-config`、`logs`)。
141
142
  - 组件约束:遵循 `FloatComponentProps<T>`:`{ record?: T; visible: boolean; onClose: () => void }`。
142
- - 交互规范:
143
- - 成功操作后统一 `message.success('操作成功')` 并按需 `ctx.refreshTable()`。
144
- - 避免在浮层中直接修改列表记录对象;通过接口更新后刷新。
145
-
143
+ - 浮层组件 props 不得包含 onSuccess ,保存成功后仅调用 onClose() ;
146
144
  ## 9. 状态持久化与初始化策略
147
145
 
148
146
  - `storageKey` 用于在本地持久化分页与筛选状态。
@@ -176,27 +174,27 @@ import {
176
174
  type ListPageTableColumn,
177
175
  type PaginationData,
178
176
  type ListPageContext,
179
- } from 'listpage-next';
180
- import { Button, Input, Select, Space } from 'antd';
177
+ } from "listpage-next";
178
+ import { Button, Input, Select, Space } from "antd";
181
179
 
182
180
  type User = { id: number; name: string; address: string; active?: boolean };
183
- type UserFilters = { name?: string; status?: 'enabled' | 'disabled' };
181
+ type UserFilters = { name?: string; status?: "enabled" | "disabled" };
184
182
 
185
183
  const filters: FilterFormOption[] = [
186
184
  {
187
- name: 'name',
188
- label: '姓名',
185
+ name: "name",
186
+ label: "姓名",
189
187
  component: <Input placeholder="请输入" allowClear />,
190
188
  },
191
189
  {
192
- name: 'status',
193
- label: '状态',
190
+ name: "status",
191
+ label: "状态",
194
192
  component: (
195
193
  <Select
196
194
  allowClear
197
195
  options={[
198
- { value: 'enabled', label: '启用' },
199
- { value: 'disabled', label: '停用' },
196
+ { value: "enabled", label: "启用" },
197
+ { value: "disabled", label: "停用" },
200
198
  ]}
201
199
  />
202
200
  ),
@@ -204,13 +202,13 @@ const filters: FilterFormOption[] = [
204
202
  ];
205
203
 
206
204
  const columns: ListPageTableColumn<User>[] = [
207
- { title: '姓名', dataIndex: 'name', key: 'name', component: 'text' },
208
- { title: '地址', dataIndex: 'address', key: 'address', ellipsis: true },
205
+ { title: "姓名", dataIndex: "name", key: "name", component: "text" },
206
+ { title: "地址", dataIndex: "address", key: "address", ellipsis: true },
209
207
  ];
210
208
 
211
209
  const request = async (
212
210
  params: { current?: number; pageSize?: number },
213
- filters: UserFilters,
211
+ filters: UserFilters
214
212
  ): Promise<PaginationData<User>> => {
215
213
  const { current = 1, pageSize = 10 } = params || {};
216
214
  const all: User[] = Array.from({ length: 100 }).map((_, i) => ({
@@ -220,7 +218,7 @@ const request = async (
220
218
  active: i % 2 === 0,
221
219
  }));
222
220
  let list = all.filter(
223
- (r) => !filters?.name || r.name.includes(filters.name!),
221
+ (r) => !filters?.name || r.name.includes(filters.name!)
224
222
  );
225
223
  const skip = (current - 1) * pageSize;
226
224
  return {
@@ -238,7 +236,7 @@ export default function Page() {
238
236
  initialValues={{ currentPage: 1, pageSize: 10 }}
239
237
  request={request}
240
238
  header={{
241
- title: '用户列表',
239
+ title: "用户列表",
242
240
  extra: (ctx: ListPageContext) => (
243
241
  <Space>
244
242
  <Button onClick={() => ctx.refreshTable()}>刷新</Button>
@@ -246,7 +244,7 @@ export default function Page() {
246
244
  ),
247
245
  }}
248
246
  filter={{ options: filters }}
249
- table={{ columns, tableProps: { rowKey: 'id' } }}
247
+ table={{ columns, tableProps: { rowKey: "id" } }}
250
248
  />
251
249
  );
252
250
  }
@@ -261,6 +259,6 @@ export default function Page() {
261
259
  - `table.columns` 使用原子组件或 `render`;关键列固定、宽度合理、开启 `ellipsis`。
262
260
  - 设置 `tableProps.rowKey` 与分页/滚动;选择态按需开启 `rowSelectionType` 与 `rowTitleKey`。
263
261
  - 页面级动作在 `header.extra`;表格级动作在 `table.extra`;浮层通过 `floats` 管理。
264
- - 成功后 `message.success` 与 `ctx.refreshTable()`;危险操作二次确认。
262
+ - 成功后 `message.success` ;危险操作二次确认。
265
263
 
266
264
  本规范自发布之日起执行,后续将根据使用反馈迭代完善。