--- name: page-codegen description: 'Use when: generating Vue 3 page code from either a page-spec JSON or a natural language description. Outputs index.vue + data.ts + index.scss following Robot Admin conventions. Triggers on: page generation, code generation, 生成页面, 代码生成, vue页面, codegen, 页面骨架, scaffold, 建个页面, 写个页面, 帮我做个页面, 口述需求, natural language page request.' --- # Skill: 页面代码生成(page-codegen) 根据 **page-spec JSON**(来自 prototype-scan / api-contract)自动生成完整的 Vue 3 页面代码, 严格遵循 Robot Admin 项目编码规范。 --- ## 触发 | 模式 | 输入 | 何时使用 | | ----------------------- | ------------------------------------- | -------------------- | | **模式 0(自然语言)** | 用户口述页面需求,无 JSON 文件 | 日常对话直接提需求时 | | **模式 1(JSON 输入)** | 来自 prototype-scan 的 page-spec JSON | 有原型/详设文档时 | - 输出统一:`index.vue` + `data.ts` + `index.scss`(三件套) - 可选追加:`layouts/` 目录(多布局变体)、composables(复杂业务逻辑) --- ## 模式 0 — 自然语言转 page-spec(内部步骤) 用户口述需求时,AI **先在内部完成以下推导**,不必向用户索要 JSON,直接进入生成流程。 ### 推导步骤 **① 提取页面基础信息** 从用户描述中识别: - 页面中文名 / 所属模块(domain) - 核心资源名称(resource),驼峰命名 - 交互模式(参照下方模式映射表) **② 关键词 → 交互模式映射** | 用户描述中出现的关键词 | 映射模式 | | ----------------------------------- | ------------------------- | | 列表、查询、搜索 + 表格 | `LIST` | | 左侧树 + 右侧表格 | `TREE_LIST` | | 主表 + 明细 / 上下两个表格 | `MASTER_DETAIL` | | 独立表单页 / 多 Tab 表单 / 步骤表单 | `FORM_PAGE` | | 弹窗表单 / 新增编辑弹窗 | `LIST`(含 `FORM_MODAL`) | | 详情页 + 子表 Tab | `DETAIL_TABS` | | 统计 / 大屏 / 图表 | `DASHBOARD` | **③ 字段推导** - 用户提到的字段名 → camelCase 字段名 + 推断组件类型(input/select/date...) - 用户提到"状态"类字段 → 自动生成 `STATUS_TAG_CONFIG`,固定右侧列 - 未提及但常规必有的字段 → 自动补充 `id`、`createTime`、`status` **④ 内部生成 page-spec 骨架(仅用于后续步骤,不输出给用户)** ```json { "pageName": "推断的页面名", "domain": "推断的模块路径", "resource": "推断的资源名", "mode": "推断的交互模式", "columns": [], "form": [], "query": [], "toolbar": [], "operations": [] } ``` **⑤ 不确定时的处理原则** - 模式不明确 → 优先推断为 `LIST`(最常见) - 字段描述模糊 → 用 `input` 类型占位,代码注释标注 `// TODO: 请确认字段类型` - 接口路径未提及 → 按 `//` 惯例自动生成,注释提醒替换 - **不向用户索要 JSON,直接用推断结果生成代码** --- ## 输出文件结构 根据页面模式(mode),输出不同复杂度的文件结构: ### 简单页面(LIST / FORM_MODAL) ``` src/views/// ├── index.vue # 页面主文件 ├── data.ts # 类型 + 配置 + 常量 └── index.scss # 页面样式 ``` ### 中等复杂页面(TREE_LIST / MASTER_DETAIL) ``` src/views/// ├── index.vue ├── data.ts ├── index.scss └── components/ # 局部子组件 ├── DetailDrawer.vue └── FormModal.vue ``` ### 高度复杂页面(FORM_PAGE / DETAIL_TABS / COMPOSITE) ``` src/views/// ├── index.vue ├── data.ts ├── index.scss ├── components/ │ ├── BasicInfo.vue │ └── SubTable.vue └── composables/ # 业务逻辑 └── useXxxLogic.ts ``` --- ## data.ts 生成规则 ### 区块顺序(固定) ```typescript /* * @Author: ChenYu ycyplus@gmail.com * @Date: {{date}} * @Description: {{页面中文名}} — 数据配置 * Copyright (c) {{year}} by CHENY, All Rights Reserved 😎. */ import type { SelectOption, DataRecord } from '@robot-admin/naive-ui-components' import type { TableColumn, UseTableCrudConfig } from '@robot-admin/request-core/naive' import { PRESET_RULES } from '@robot-admin/form-validate' // ================= 业务类型定义 ================= // 从 page-spec.columns + page-spec.form 合并字段生成 interface export interface {{ResourceName}} extends DataRecord { id: number | string // ... 所有字段 } export interface {{ResourceName}}FormData { // ... 表单字段(id 可选) } export interface SearchForm { // ... 查询字段 } // ================= 选项配置 ================= // 下拉框 / 筛选器的选项数据 export const STATUS_OPTIONS: SelectOption[] = [ { label: '启用', value: 1 }, { label: '禁用', value: 0 }, ] // ================= Tag 映射配置 ================= // 用于状态类列渲染彩色标签 export const STATUS_TAG_CONFIG: Record = { 1: { text: '启用', type: 'success' }, 0: { text: '禁用', type: 'error' }, } // ================= 图标配置 ================= export const ICON_CONFIG = { search: 'mdi:magnify', plus: 'mdi:plus', refresh: 'mdi:refresh', edit: 'mdi:pencil', delete: 'mdi:delete', eye: 'mdi:eye', // ... 根据 page-spec.toolbar + operations 的 icon 字段 } as const // ================= 格式化函数 ================= // 简短的格式化函数(列渲染用) // ================= 表格列配置 ================= export const getTableColumns = (): TableColumn[] => [ // 从 page-spec.columns 映射 { key: 'fieldName', title: '列标题', width: 120, // 可编辑列追加 editable / editType / editProps // 状态列追加 render 函数(渲染 NTag) }, ] // ================= 表单验证规则 ================= export const FORM_RULES: FormRules = { // 从 page-spec.form 的 rules 字段映射 fieldName: [ PRESET_RULES.required('字段名'), // ... ], } // ================= 表单默认值 ================= export const FORM_DEFAULTS: {{ResourceName}}FormData = { // 所有字段的初始值 } // ================= useTableCrud 配置 ================= // 仅 LIST 模式页面使用 export const getTableCrudConfig = (): UseTableCrudConfig => ({ api: { list: '//', create: '//', update: '///:id', remove: '///:id', get: '///:id', }, columns: getTableColumns(), defaultPageSize: 20, }) ``` ### 关键映射规则 **page-spec.columns → TableColumn:** | page-spec 字段 | TableColumn 字段 | | -------------------------- | ------------------------------- | | `key` | `key` | | `title` | `title` | | `width` | `width` | | `sortable` | `sortable: true` | | `render: 'tag'` + `tagMap` | `render: (row) => h(NTag, ...)` | | `render: 'text'` | 默认文本渲染 | **page-spec.form → FormRules:** | page-spec 字段 | FormRules 映射 | | ----------------------- | -------------------------------------- | | `required: true` | `PRESET_RULES.required('字段名')` | | `rules: 'email'` | `PRESET_RULES.email('邮箱')` | | `rules: 'mobile'` | `PRESET_RULES.mobile('手机号')` | | `rules: 'length(2,20)'` | `PRESET_RULES.length('字段名', 2, 20)` | | `rules: 'range(0,100)'` | `PRESET_RULES.range('字段名', 0, 100)` | --- ## index.vue 生成规则 ### 文件头 ```vue ``` ### Script 区块顺序(固定) ```vue ``` ### 自动导入清单(无需 import) 以下 API 自动导入,生成代码中**不要写 import 语句**: ``` Vue: ref, computed, watch, onMounted, nextTick, reactive, readonly, h Router: useRoute, useRouter Pinia: defineStore, storeToRefs VueUse: useLocalStorage, useClipboard, useDebounceFn NaiveUI: NCard, NButton, NSpace, NInput, NSelect, NTag, NModal, NDrawer, NGrid, NGi, NTabs, NTabPane, NAlert, NSwitch, NRadioGroup, ... useMessage, useDialog, useNotification Store: s_userStore, s_themeStore, ... ``` ### Template 区块:按页面模式展开 --- #### 模式 A:LIST(查询 + 表格) ```vue ``` --- #### 模式 B:TREE_LIST(树形 + 表格) ```vue ``` --- #### 模式 C:FORM_PAGE(独立表单页) ```vue ``` --- #### 模式 D:MASTER_DETAIL(主表 + 明细) ```vue ``` --- ## index.scss 生成规则 ```scss // 页面容器 .{{kebab-name}} { display: flex; flex-direction: column; gap: 16px; .header-card { :deep(.n-card__content) { padding: 16px; } } .content-card { height: calc(100vh - 220px); overflow: auto; } // 根据页面模式追加: // TREE_LIST → .main-content { ... } // MASTER_DETAIL → .detail-section { ... } } ``` --- ## 操作列按钮生成 从 page-spec.operations 生成 tableActions 数组: ```typescript const tableActions = computed(() => [ { label: '编辑', type: 'primary' as const, icon: ICON_CONFIG.edit, onClick: (row: ResourceItem) => handleEdit(row), // 条件显示 show: (row: ResourceItem) => row.status === 1, }, { label: '删除', type: 'error' as const, icon: ICON_CONFIG.delete, onClick: (row: ResourceItem) => handleDelete(row), confirm: { title: '确认删除', content: '删除后不可恢复' }, }, ]) ``` > ⚠️ **操作列按钮必须与 page-spec 严格一一对应,不可自编按钮** --- ## 状态列渲染 状态类列必须用 NTag 彩色标签渲染: ```typescript // data.ts export const STATUS_TAG_CONFIG = { active: { text: '在职', type: 'success' }, inactive: { text: '离职', type: 'error' }, probation: { text: '试用期', type: 'warning' }, } as const // 列定义中 { key: 'status', title: '状态', width: 100, render: (row: Employee) => { const config = STATUS_TAG_CONFIG[row.status] return config ? h(NTag, { type: config.type, size: 'small' }, () => config.text) : '-' }, } ``` --- ## 生成校验 Checklist - [ ] `defineOptions({ name: '...' })` 存在 - [ ] 文件头注释完整(Author/Date/Description) - [ ] JSDoc 注释覆盖所有导出函数 - [ ] 请求函数从 `@robot-admin/request-core/axios` 导入,Naive CRUD 从 `/naive` 导入 - [ ] 使用 `@robot-admin/form-validate` 的 PRESET_RULES - [ ] 使用 `@robot-admin/naive-ui-components` 的 C_Table / C_Form / C_ActionBar - [ ] 自动导入的 API 未被手动 import(ref/computed/NCard/useMessage 等) - [ ] 样式使用 `