plus-ui/.codex/skills/frontend-crud-coding/references/frontend.md
2026-06-03 12:14:45 +08:00

8.7 KiB
Raw Blame History

前端约定

优先参考的代码来源

  • 当前目标目录下最近似页面、API、types。
  • 标准单表:src/pages/demo/demo/index.tsxsrc/api/demo/demo/index.tssrc/api/demo/demo/types.ts
  • 树表:src/pages/demo/tree/index.tsxsrc/pages/workflow/category/index.tsx
  • 复杂系统页:src/pages/system/user/index.tsxsrc/pages/system/role/index.tsxsrc/pages/system/post/index.tsxsrc/pages/system/config/index.tsx
  • workflow 页:src/pages/workflow/*src/api/workflow/*
  • 监控页:src/pages/monitor/*src/api/monitor/*
  • 公共 hookssrc/hooks/useTableSelection.tssrc/hooks/useTableExport.tssrc/hooks/useDict.ts
  • 公共组件:src/components/common/RowActions.tsxTreePanel.tsxRightToolbar.tsxDictTag.tsx、上传/预览组件。
  • 工具函数:src/utils/ruoyi.tssrc/utils/permission.tssrc/utils/download.ts

基础栈与格式

  • 技术栈是 React + TypeScript + Umi Max + Ant Design + ProComponents + ahooks + Zustand + TanStack Query。
  • 包管理按仓库现状使用 pnpm。
  • .editorconfig 要求 UTF-8、2 空格缩进。
  • 当前仓库没有 Prettier格式化使用 pnpm run fmtlint 使用 pnpm lint
  • 不要在一个页面里混入与仓库不一致的格式和写法。

API 文件规则

  • 标准 API 文件放在 src/api/<module>/<business>/index.ts,同目录维护 types.ts
  • import 顺序优先跟随附近文件,标准形式: import type { PageResult, R } from '@/api/types'; import request from '@/api/request'; import type { XxxForm, XxxQuery, XxxVO } from './types';
  • 不要从 axios 引入 AxiosPromise;当前 request<T>() 返回 Promise<T>,接口函数通常返回 Promise<R<T>>
  • 列表分页接口通常返回 request<R<PageResult<XxxVO>>>({ url, method: 'get', params: query })
  • 树表列表接口通常返回 request<R<XxxVO[]>>({ url, method: 'get', params: query })
  • 详情接口返回 R<XxxVO>;复杂详情返回单独的 InfoVO
  • 标准函数命名: listXxx -> GET /<module>/<business>/list getXxx -> GET /<module>/<business>/{id} addXxx -> POST /<module>/<business> updateXxx -> PUT /<module>/<business> delXxx -> DELETE /<module>/<business>/{id or ids} changeXxxStatus -> PUT /<module>/<business>/changeStatus
  • query string 用 params,请求体用 data
  • 加密、防重复提交等 headers 直接写在请求配置里,例如用户重置密码中的 isEncryptrepeatSubmit
  • 当前仓库多数 API 使用 export function;新增标准 CRUD 优先跟随相邻模块。
  • 只有相邻模块已有聚合对象时才新增默认导出。

类型文件规则

  • 标准类型定义 VOFormQuery,必要时补 InfoVOTreeVOResetPwdForm 等扩展类型。
  • Form 通常继承 BaseEntity
  • 非树表 Query 通常继承 PageQuery
  • 树表 Query 通常不继承 PageQuery
  • ID 字段通常使用 string | number,批量删除参数使用 string | number | Array<string | number>
  • Java 数值类型映射为 numberBoolean 映射为 boolean,日期/文本默认 string
  • 日期范围查询保留 params?: Record<string, unknown> 或跟随相邻页面现有类型,不要因为它看起来宽松就删掉。
  • 列表对象、表单对象、查询对象职责分开;字段不一致时不要强行复用一个接口。
  • 能明确写出类型时不要用 any;组件库、字典或历史接口确实无法收窄时再保留。

React 页面结构规则

  • 页面默认导出函数组件,命名如 SystemUserPageDemoDemoPageWorkflowCategoryPage
  • 标准页使用 PageContainer 包裹 ProTableModalForm
  • 标准列表页常见状态: actionRefformmodalOpenmodalTitleidsselectedOne、权限布尔值。
  • 弹窗状态优先使用 useBoolean(false),表单用 Form.useForm<XxxForm>()
  • ProTable 使用: rowKey columns search={{ labelWidth: 90 }} pagination={{ defaultPageSize: 10, showSizeChanger: true }} request={async params => { ... }} toolBarRender={() => [...]}
  • 分页查询使用 toPageQuery(params),然后 updateExportParams(query),最后 return toTableData(res)
  • 表格列类型使用 ProColumns<XxxVO>[]
  • 新增/编辑弹窗使用 ModalForm<XxxForm>,字段优先使用 ProFormTextProFormDigitProFormSelectProFormTreeSelectProFormDateTimeRangePicker 等 ProForm 组件。
  • ModalForm 成功提交后返回 true,并刷新 actionRef.current?.reload()

页面行为规则

  • openAdd 负责 form.resetFields()、设置默认值、设置标题、打开弹窗。
  • openEdit 先按行或 selectedOne 找目标,再查详情,form.resetFields()form.setFieldsValue(res.data),最后打开弹窗。
  • submitForm 根据主键判断新增或修改,成功后 message.success('操作成功')、重置表单、刷新列表。
  • removehandleDelete 支持行删除和批量删除,成功后 message.success('删除成功')clearSelection()reloadAndRestreload
  • 批量按钮通常用 Popconfirm,行操作确认优先放在 RowActionsconfirm
  • 状态切换失败时要回滚或刷新,参考 src/pages/system/user/index.tsx
  • 日期范围查询使用 formatDateTimeRangeaddDateRange,参考 system/user
  • 导入上传参考 system/user/components/UserImportModal.tsx 或流程定义导入弹窗,保留 globalHeaders()appEnv.baseApi 相关方式。

字典、权限与公共工具

  • 字典使用 const dicts = useDict('sys_normal_disable', 'sys_user_gender')
  • 字典 options 可按 system/user 中的 dictOptions 函数映射为 { label, value }
  • 权限使用: const userInfo = useUserStore(state => state.userInfo); const canAdd = hasPermi(userInfo, ['system:user:add']);
  • 不要使用 Vue 权限指令 v-hasPermi
  • 常用工具: hasPermi from @/utils/permission handleTreeparseStrEmptytoPageQuerytoTableDataaddDateRangeformatDateTimeRange from @/utils/ruoyi download via useTableExport

组件与样式规则

  • 行操作优先复用 RowActions,并使用 @ant-design/icons 图标。
  • 树筛选优先复用 TreePanel,参考 system/user
  • 导出优先复用 useTableExport
  • 多选优先复用 useTableSelection
  • 标准页面尽量使用 PageContainerProTable、ProComponents 页面壳,不堆大量内联样式。
  • 需要自定义布局时先查 src/assets/styles 是否已有 .tree-table-page.table-panel.page-surface 等类。
  • 不要为了单页需求修改全局组件样式。

树表规则

  • 树表列表接口通常返回数组,页面通过 handleTree<T>(res.data || [], 'id', 'parentId') 组树。
  • ProTable 使用 pagination={false}
  • 使用 expandedRowKeysonExpandedRowsChange 控制展开。
  • 展开/折叠按钮参考 demo/treeworkflow/category,用 SortAscendingOutlined
  • 表单中上级节点使用 ProFormTreeSelect
  • 新增子节点时从当前行回填 parentId
  • 删除确认文案优先使用业务名称,而不是批量 ID 文案。

与 Vue 参考项目和生成器模板的关系

  • Vue skill 和 .claude/agents 提供的是任务分型、优先级、增量修改、自检方式,不是 React 实现模板。
  • generator 模板可用于确认字段、权限、导出、状态切换、排序、日期范围等,但不是最终答案。
  • 当前 React 项目的核心骨架是 ProTableModalFormRowActionsuseTableSelectionuseTableExport
  • 修改已有页面时,不要把现有强业务逻辑替换回 generator 的简化逻辑。

验证规则

  • 只改文档或 skill运行 skill 基础校验。
  • 改前端 TS/TSX/API/types优先运行 pnpm exec tsc --noEmitpnpm lint
  • 改页面、import、权限或较多文件运行 pnpm lint
  • 改公共 hooks、组件、构建相关或大范围页面再运行 pnpm build
  • 如果验证因为环境、依赖或权限失败,交付时说明失败命令和原因。

避免事项

  • 不要从 axios 引入 AxiosPromise
  • 不要绕开 @/api/requestuseTableExport 自造请求/下载封装。
  • 不要跳过 types.ts,把类型全写在页面里。
  • 不要把 src/pages 写成 Vue 项目的 src/views
  • 不要使用 Vue 的 refreactivetoRefsv-hasPermi、Element Plus 组件或 SCSS 页面壳。
  • 不要删除日期范围 params、权限判断、导出、导入、树筛选、列显隐等现有能力。
  • 不要为了“更整洁”重写复杂页面的大块业务逻辑。