---
name: Jeecg Code Generator
slug: jeecg-code-generator
category: AI Engineering
description: Jeecg Code Generator turns natural-language requirements into JeecgBoot CRUD code, including Java backend, Vue3 frontend, and menu permission SQL. Use it for new modules, field changes, and other JeecgBoot code generation tasks.
github: "https://github.com/jeecgboot/skills/tree/main/jeecg-codegen"
language: Python
stars: 225
forks: 67
install: "npx degit https://github.com/jeecgboot/skills/tree/main/jeecg-codegen ~/.claude/skills/jeecg-codegen"
installs_to: ~/.claude/skills/jeecg-codegen
source_path: jeecg-codegen/SKILL.md
collection_size: 14
category_size: 2793
collection_url: "https://dirskills.com/collections/jeecgboot/skills"
added: 2026-09-03T06:05:05.066Z
last_synced: 2026-09-03T06:05:05.066Z
canonical_url: "https://dirskills.com/skills/jeecg-code-generator"
---

# Jeecg Code Generator

Jeecg Code Generator turns natural-language requirements into JeecgBoot CRUD code, including Java backend, Vue3 frontend, and menu permission SQL. Use it for new modules, field changes, and other JeecgBoot code generation tasks.

**Install:**

```bash
npx degit https://github.com/jeecgboot/skills/tree/main/jeecg-codegen ~/.claude/skills/jeecg-codegen
```

## README

# JeecgBoot 代码生成器

将自然语言需求转换为 JeecgBoot 全套 CRUD 代码（后端 Java + 前端 Vue3 + 菜单权限 SQL），并支持对已生成模块的增量字段修改。

## 主数据复用规则

> **重要：** 生成代码涉及的字典、角色、用户、部门等主数据，必须遵循"先查后建"原则。
> 使用 `jeecg-system` skill 的 `system_utils.py` 查询和管理主数据。
> 详见 `../jeecg-system/SKILL.md`。

### ⛔ 字典创建必须写入 Flyway SQL，禁止直接走 API 创建

> **代码生成场景下，新建字典的"建"必须落到 Flyway SQL 文件，禁止调用 `find_or_create_dict()` / `create_dict()` 等 API 在远程服务器上直接创建。**
>
> **Why:** 代码生成产物（Entity、前端、Flyway SQL）会通过 git 提交并部署到测试/预发/生产环境。如果字典只通过 API 在当前开发环境创建，**部署到线上时线上数据库没有该字典**，前端下拉框会空白、列表 `_dictText` 翻译失效。Flyway SQL 跟着代码走，所有环境拉到代码后执行迁移都会自动建上，是唯一能保证环境一致性的方式。
>
> **How to apply:**
> - 查询字典 → **走 API 或 MySQL**（`jeecg-system` skill 的 `query-dicts` / `query-dict`），用于"先查后建"中的"查"
> - 创建字典 → **写入当次的 Flyway SQL 文件**（`sys_dict` INSERT + `sys_dict_item` 批量 INSERT），用于"先查后建"中的"建"
> - **禁用**：`find_or_create_dict()`、`create_dict()` 等 system_utils 中的字典创建函数（在代码生成 skill 中不能调用）
> - 同理适用于：分类字典 `sys_category` 节点新建 — 也必须写入 Flyway SQL，禁止走 `/sys/category/add` API
>
> **例外：** 角色、审批角色、用户绑定关系等"运行时主数据"，由于跨业务可复用，可走 API 创建（按 jeecg-system 原流程）。**字典与分类字典是"配置数据"，必须走 SQL。**

## ⛔ 接口禁止猜测规则

> **严格禁止猜测任何 API 接口路径或参数。** AI 不得根据命名惯例、框架约定或已知路径拼凑接口地址后直接调用。
>
> 所有接口调用必须来源于以下之一：
> 1. 用户明确提供的接口文档或地址
> 2. `jeecg-system` skill 中已记录的接口
> 3. 通过 `jeecg-system` skill 查询后确认的接口
>
> 违反此规则即使偶然成功也视为错误操作，因为猜测成功不代表行为合规。

## ⛔ 写文件前的强制自检清单（高频翻车点）

> **以下两条是 AI 凭"框架直觉"最常犯错的地方，文件写出去几乎必现 bug，调试成本极高。每次执行 Step 4 写后端/前端文件之前，必须逐条 self-check。**
>
> ### 翻车点 1：每个文件的路径必须与 SKILL/reference 描述完全一致
>
> **写每一个文件之前，必须先在 `codegen-reference.md` 顶部"文件清单"章节中找到对应文件的路径模板，逐字符比对后再写入。禁止凭"Spring Boot/JeecgBoot 框架直觉"猜测路径。**
>
> ### 翻车点 2：FormSchema 必含隐藏 id 字段
>
> **所有** FormSchema（主表 Modal 表单、一对一子表 Form、ERP 风格子表 Form、树表 Modal 表单）**首位**必须包含：
>
> ```typescript
> { label: '', field: 'id', component: 'Input', show: false },
> ```
>
> **为什么这是铁律：** `BasicForm` 的 `getFieldsValue()` 只返回 schema 中声明过的字段。即使 Modal 打开时通过 `setFieldsValue({ ...data.record })` 把 `id` 写入了表单状态，schema 没声明，提交时 `getFieldsValue()` 也会丢弃它。最终后端收到 `entity.id == null`，`getById(null)` 返回 null，Controller 返回 `Result.error("未找到对应数据")`。**编辑功能直接报错。**
>
> **位置统一规定：放在 FormSchema 数组首位**（不要纠结"最后还是最前"，统一首位）。
>
> 这两条规则不需要用户询问、不需要场景判断、不需要选项确认。**100% 强制，100% 一致。**

## 生成模式

> **进入交互流程之前,必须先与用户确认本次使用的生成模式。** 任何场景下都不要默默选择,必须显式告知用户当前模式;用户回复"确认"即采用默认。

本 skill 提供两种生成模式:

| 模式 | 状态 | 默认 | 说明 |
|------|------|------|------|
| **串行生成（Serial）** | Stable | ✅ 默认 | 主 Agent 顺序生成后端 → 前端 → SQL,全程单线执行,稳定可靠 |
| **并行生成（Parallel）** | ⚠️ **Beta — 可能不稳定** | ❌ | 派发两个 SubAgent 并行生成前端 / 后端代码,主 Agent 负责契约冻结与跨端校验。详见同目录下 `parallel-generation-mode.md` |

### 模式确认话术（必须执行）

进入 Step 0 之前,主 Agent **必须**先输出类似以下消息,等用户回复后再继续:

```
本次代码生成将使用【串行生成模式】（默认,稳定）。
如需使用【并行生成模式（Beta）】以缩短耗时,请明确告知。
注意：并行模式当前为 Beta 版本,可能出现前后端字段命名漂移、API URL 不一致、
字典编码错位、FormSchema 隐藏 id 字段遗漏等问题,不确定时建议使用默认串行模式。
```

### 模式选择规则

- 用户未明确要求并行 → 一律走 **串行模式**,不要主动建议并行。
- 用户明确要求并行（"并行"、"分头生成"、"前后端同时来"、"用 subagent 并行"等关键词） → 进入 **并行模式**,但必须先复述一遍 Beta 风险并等用户**再次确认**后才正式启动。
- **增量字段修改场景（场景 C）** → 强制串行,即使用户要求并行也要拒绝并解释（SubAgent 双重压缩会丢失已有代码细节）。
- 一对多 + ERP / vue3Native / 自定义增强等复杂场景 → 强烈建议串行,需向用户说明风险后由用户决定。

### 并行模式启动条件（全部满足才进入）

1. 用户明确选择了并行模式。
2. 用户已被告知 Beta 风险并**再次确认**。
3. 操作类型是"全量生成"（场景 A 或 B）,不是"增量修改"（场景 C）。
4. 主数据复用前置条件已就绪（字典已查/已建,目标数据库已确认）。

满足后,主 Agent **必须读取** `parallel-generation-mode.md` 并严格按其规范执行（契约冻结 → 派发 SubAgent → 跨端校验 → 输出清单）。任一环节失败 → 按该文档第 6 节"回退策略"切回串行从头来过。

> **铁律不变：** 即使选择并行模式,本章上方的"⛔ 接口禁止猜测"、"⛔ 字典创建必须写入 Flyway SQL"、"⛔ 写文件前的强制自检清单（路径 + FormSchema id）"、以及"⛔ 铁律:Step 2 + Step 3 是不可跳过的硬性停止门" 全部仍然 100% 强制 —— 通过派发 prompt 传达给 SubAgent。

## 交互流程

> ### ⛔ 铁律：Step 2 + Step 3 是不可跳过的硬性停止门
>
> **全量生成必须严格按顺序执行 Step 0 → Step 1 → Step 2 → 等用户回复 → Step 3 → 等用户确认 → Step 4。**
> 在用户明确回复"确认"（或等价表述）之前，**绝对禁止**开始生成任何代码、创建任何文件、执行任何 SQL。
>
> **以下念头出现时立刻停下，它们都是合理化跳过确认的借口：**
>
> | 借口 | 现实 |
> |------|------|
> | "需求描述足够清楚，可以直接推断" | 用户没有确认 ≠ 用户已认可。字段类型、路径、风格都可能偏差。 |
> | "选项都是默认值，不需要问" | 默认值是否适用由用户决定，不由 AI 决定。 |
> | "先生成再改很方便" | 用户不得不事后检查所有文件，浪费双方时间。 |
> | "用户说'Tab风格'已经隐含了风格选择" | 只说明了一个选项，其他9项仍需展示给用户确认。 |
> | "Skill 加载太慢，直接生成更高效" | 效率不是跳过确认的理由。 |
>
> **违反此铁律的代价：** 用户发现问题后，所有已生成文件都需要重新生成或逐一修改。

### Step 0 前置：判断前端目标（PC 端 / 移动端 / 两者都要）

> **此步骤必须在 Step 0 之前执行。前端目标直接决定 Step 2 中需要询问哪些选项。**

**识别移动端关键词：** "移动端"、"手机端"、"UniApp"、"uniapp"、"APP端"、"小程序"、"H5"、"移动页面"、"APP页面"

根据用户描述判断：

| 用户意图 | 判定结果 | Step 2 调整 |
|---------|---------|------------|
| 明确只要移动端（含以上关键词，无 PC 相关词） | **仅移动端** | 跳过 PC 前端选项（选项2、3、6、8、9），改为询问 UniApp3 项目根路径 |
| 明确只要 PC 端（含 "vue3"、"PC端"、"web端" 等词，无移动端词） | **仅 PC 端** | 按原流程 |
| 两者都提到，或描述模糊（如"前后端代码"、"CRUD代码"） | **不确定** | 在 Step 2 前先询问用户：**"请问需要生成哪端的前端代码？① 仅 PC 端（Vue3） ② 仅移动端（UniApp3） ③ 两者都要"** |

**仅移动端时的 Step 2 选项调整：**
- 删除：前端风格（vue3/vue3Native）
- 删除：PC 前端视图目录
- 删除：PC 前端项目根路径
- 删除：一对多布局风格（PC 端特有）
- 删除：表单列数（PC 端特有）
- 新增：**UniApp3 项目根路径**（必填）
- 保留：后端模块、是否读取系统字典、后端项目根路径、数据库名称

**两者都要时：** 同时展示 PC 端和移动端的选项，分两组列出。

> ⚠️ **禁止默认跳过任何一端！** 无法判断时必须询问用户，不得自行假设"用户可能只要 PC"或"用户只要移动端"。

---

### Step 0: 判断操作类型 — 全量生成 or 增量修改？

**识别增量修改的关键词：** "加字段"、"增加字段"、"新增字段"、"加一个XX字段"、"删除字段"、"修改字段"、"改一下XX"、"给XX模块加"、"给XX表加"

如果是增量修改 → 进入 **场景C**
如果是全量生成 → 进入 **场景A** 或 **场景B**

### Step 1: 全量生成 — 判断场景

**场景A — 已有表（用户给了表名）：**
1. 通过数据库查询获取精确 DDL（见"数据库连接"章节）
2. 从 DDL 中解析：主键类型、全部字段（名称/类型/注释/是否nullable）、是否有系统字段
3. 根据字段类型和注释自动推导前端控件类型
4. 用户无需描述字段，AI 全部自动推导

**场景B — 新建表（用户用自然语言描述需求）：**
1. 从用户描述中提取：表名、实体名、功能描述、字段列表
2. 用"智能字段推导"规则推导 DB 类型和前端控件
3. 默认添加全部系统字段（create_by/create_time/update_by/update_time/sys_org_code）
4. 生成建表 DDL 写入 Flyway SQL

**场景C — 增量修改（给已有模块加/改/删字段）：**
1. **定位目标模块**：从用户提到的表名、模块名、实体名中识别目标
2. **扫描已有代码文件**：在后端和前端目录中搜索已生成的文件
   ```bash
   # <project_root>/<project_vue_root>：后端/前端项目根目录，使用前需向用户确认
   # 搜索后端 Entity 文件
   find <project_root> -name "{EntityName}.java" -path "*/entity/*"
   # 搜索前端 data.ts 文件
   find <project_vue_root>/src/views -name "{EntityName}.data.ts"
   ```
3. **读取全部已有文件**：Entity.java、*.data.ts、*List.vue、*Modal.vue（如有 Form.vue 也读取）
4. **解析当前字段列表**：从 Entity.java 解析已有字段
5. **推导新字段属性**：用"智能字段推导"规则推导 DB 类型、Java 类型、前端控件
6. **展示修改摘要**，等待用户确认后再修改

**增量修改的操作类型：**
- **加字段**：在所有文件中追加新字段定义
- **删字段**：从所有文件中移除指定字段定义
- **改字段**：修改指定字段的类型、控件、注释等

**判断表类型：**
- 提到"分类/层级/树/上下级" → **树表**
- 提到"主子表/明细/一对多/订单+商品" → **一对多**
- 默认 → **单表**

**全控件生成模式（"全控件"关键词触发）：**
当用户说"全控件"、"覆盖所有控件类型"时，触发全覆盖枚举模式，**每张表都必须包含该场景支持的所有组件类型**，不得只生成代表性字段：
- **主表**：枚举全部 FormSchema 组件 — Input/InputPassword/InputTextArea/InputNumber(整数+金额)/JDictSelectTag(下拉+radio)/JCheckbox/JSelectMultiple/JSwitch/DatePicker(5个picker变体)/TimePicker/JSelectUser/JSelectDept/JCategorySelect/JTreeSelect/JImageUpload/JUpload/JPopup+回填/JPopupDict/JAreaLinkage
- **一对一子表**：在主表全部控件基础上额外加 JEditor/JMarkdownEditor/联动组件(多级)/关联记录+他表字段/表字典各变体(radio/checkbox/multi/带条件)
- **一对多子表**：枚举全部 JVxeTypes — input/textarea/inputNumber/select(系统字典+表字典)/selectSearch/selectMultiple/checkbox(开关)/date/datetime/time/image/file/popup/departSelect/userSelect/pca
- **标准触发词**：`全控件`、`覆盖所有 FormSchema 控件`、`覆盖所有 JVxeTypes`
- **标准提示语**（用户可直接复制使用）：
  > 生成全控件主子表，主表+一对一子表覆盖所有 FormSchema 控件，一对多子表覆盖所有 JVxeTypes（含pca），Tab-in-Modal 风格（radio-group 切换）

**一对多表的前端布局风格：**

> ⚠️ **严禁假设布局风格！** 必须在 Step 2 询问用户，用户未回答前不得擅自选择非默认风格（如 Tab-in-Modal）。
> 过去曾犯错：用户未说明风格，却错误地选了 Tab-in-Modal (C9)，导致用户反馈后需要重新生成 Modal.vue。

一对多表有三种前端布局风格，用户未指定时**默认使用原始布局风格**。

> **重要：vue3 封装风格和 vue3Native 原生风格的一对多架构完全不同！** vue3 封装风格使用 `useJvxeMethod`，vue3Native 原生风格使用 `useValidateAntFormAndTable`。详见 `codegen-reference.md` 的 C9-C12（vue3）和 **C13（vue3Native）**。

**vue3 封装风格布局选项：**

| 风格 | 关键词 | 列表页 | Modal 布局 |
|------|--------|--------|-----------|
| **默认/原始布局** | "默认风格"、"默认"、未指定风格 | 标准列表（无 expandedRowRender） | 上面主表 BasicForm + 下面 a-tabs 子表 |
| **Tab-in-Modal (C9)** | "tab风格"、"tab切换"、"radio切换"、"标题栏切换" | 标准列表（同默认，**无** expandedRowRender） | radio-group 标题栏切换主表/子表，`wrapClassName="j-cgform-tab-modal"` |
| **内嵌子表 (C12)** | "内嵌子表"、"行展开"、"expandedRowRender" | 行展开显示子表（expandedRowRender） | 上面主表 BasicForm + 下面 a-tabs 子表（同默认） |
| **ERP (C11)** | "ERP风格"、"独立编辑" | 主表单选 + 子表独立 CRUD Tab | 仅主表 BasicForm（子表独立 Modal） |

> ⚠️ **子表外键字段名必须读实体确认，严禁猜测！**
> 生成子表 FormSchema 的隐藏外键字段前，**必须先 Read 子表 Entity.java**，以实体中的 Java 字段名为准。
> 外键字段名因开发者习惯差异很大（`companyId` / `bizCompanyId` / `mainId` / `headerId`），
> 根据主表实体名推断必然出错，会导致 MySQL `Field 'xxx' doesn't have a default value` 异常。
> 同样，Modal 中 `values.xxx = unref(mainId)` 的 `xxx` 也必须与实体字段名一致。

**vue3Native 原生风格（C13）— 架构完全不同：**
- **Modal 是薄包装器**（BasicModal + useModalInner），只调 `formComponent.submitForm()/edit()/add()`
- **Form.vue 是核心组件**，包含主表 a-form + 子表 a-tabs + 提交逻辑
- 使用 **`useValidateAntFormAndTable`** hook（不是 `useJvxeMethod`）
- 子表 API 导出为**函数**（不是 URL 字符串）
- `saveOrUpdate` **不用** `isTransformResponse: false`
- 一对一子表用原生 `a-form` + `Form.useForm`，暴露 `isForm = true`
- 一对一子表 `initFormData(mainId)` 直接传主表 ID（不传 URL 字符串）
- 一对一子表 `getFormData()` 返回对象（不是数组）
- 需要额外的 `queryDataById` API 函数
- List.vue 使用 `useModal` + `openModal(true, {...})` 模式

**vue3 封装风格 — 默认/原始布局的关键特征：**
- **Modal 结构**：BasicForm（主表）始终显示在上方 + `<a-tabs>` 包裹子表在下方
- **无** `wrapClassName="j-cgform-tab-modal"`，**无** `#title` 插槽的 radio-group
- **`refKeys` 只包含子表 key**（不包含主表 key），如 `['subMany', 'subOne']`
- 一对多子表用 `<JVxeTable>`，一对一子表抽成独立 Form.vue 组件（**必须用 `defineComponent`，不能用 `<script setup>`**）
- 列表页为标准 BasicTable，无 expandedRowRender
- `useJvxeMethod` 的第6个参数 `validateSubForm` 用于校验一对一子表
- `validateForm(index)` 的 index 对应 refKeys 中的位置（0=第一个子表，1=第二个子表）
- **`tableRefs` 只能包含 JVxeTable 的 ref**，禁止包含 Form 组件 ref（否则 `resetScrollTop` 报错）

**内嵌子表 (C12) 的关键特征（Modal 与默认布局完全一致，仅 List 不同）：**
- **List.vue** 使用 `expandedRowRender` 行展开显示 SubTable 组件，需额外创建 `subTables/` 目录
- **Modal.vue** 结构与默认布局**完全一致**：`useJvxeMethod` 6参数 + `classifyIntoFormData` + `validateSubForm`
- **后端** 子表查询必须返回 `Result<IPage<T>>`（不是 `Result<List<T>>`），SubTable 前端通过 `res.result.records` 获取数据
- **api.ts** 每个子表需要双导出：URL 字符串（供 Modal）+ API 函数（供 SubTable，`isTransformResponse:false`）
- **data.ts** 一对多子表需要双列定义：`BasicColumn[]`（SubTable 展示）+ `JVxeColumn[]`（Modal 编辑）
- 详见规则18-24.5

### Step 2: 询问用户选项（仅全量生成需要）

> **重要：必须直接向用户提问，禁止通过 Glob/Bash/Grep 等工具自动搜索 CLAUDE.md 或项目路径！**
> Skill 加载完毕后，立刻将以下选项表格输出给用户，等待用户回复，所有路径/数据库名均通过问用户获取。

一次性展示所有选项及默认值，用户说"确认"即可全部采用默认值，或只说需要改的：
1. **后端模块**：默认 `jeecg-module-system/jeecg-system-biz`
2. **前端风格**：默认 `vue3`（封装风格），可选 `vue3Native`（原生风格）
3. **前端视图目录**：默认用 entityPackage 值
4. **是否读取系统字典**：默认 `是`，读取后可自动为字段匹配已有字典编码（见"字典智能匹配"章节）
5. **后端项目根路径**：必填，请用户提供（如 `D:/jeecgboot`）
6. **前端项目根路径**：必填，请用户提供（如 `D:/jeecgboot-vue3`）
7. **数据库名称**：必填，请用户提供（用于读取字典、执行菜单 SQL）
8. **一对多布局风格**（仅有子表时展示）：默认`原始布局`（主表上方+子表 a-tabs），可选 `Tab-in-Modal`、`内嵌子表`、`ERP`
9. **表单列数**（所有含表单的场景均需展示，逐项列出）：
   - 单表 / 树表 Modal 表单：默认`单列`（span:24）
   - 一对多主表 BasicForm：默认`单列`（span:24）
   - 一对一子表 Form.vue：默认`单列`（span:24）
   - 用户可对每项单独指定，也可统一回复"全部单列"或"全部双列"

> ⚠️ **第8、9项绝对不能自行假设！** 过去曾犯错：未询问直接生成 Tab-in-Modal 风格 + 双列补充信息，用户事后指出才改正。

### Step 3: 展示摘要

> ⛔ **展示摘要后必须停止，等待用户明确回复"确认"（或"ok"、"可以"、"没问题"等等价表述）。收到确认前不得进入 Step 4。**

- **全量生成**：列出表名、字段清单（名称/类型/控件/校验/字典），等待用户确认后再生成。
  - 若需求包含"生成默认值"，摘要表格必须新增**"默认值"列**，明确列出每个字段的具体预填值（参见规则35），让用户在生成前确认，而不是生成后才发现问题。
- **增量修改**：列出要修改的文件路径 + 每个文件的具体变更内容（新增/删除/修改哪些行），等待用户确认。

> ✅ **只有用户明确确认后，才能进入 Step 4。** 用户沉默、未回复、或继续追加需求，都不等于确认。

### Step 4: 执行

**全量生成流程（根据前端目标选择执行路径）：**

> 前端目标由 Step 0 前置判断确定：**仅 PC 端** / **仅移动端** / **两者都要**。

1. **并行读取**对应子文件（见顶部"参考模板读取规则"），在同一轮 response 中发出全部 Read 调用
2. **分轮并行写入**文件——无依赖的文件在同一轮 response 中批量发出 Write 调用，**禁止逐文件串行等待**：
   - **第 1 轮前（强制）**：对每个待写后端文件，确认其路径与 `codegen-reference.md` 文件清单一致（譬如Mapper XML）
   - **第 1 轮**（并行）：Entity + Mapper + IService + ServiceImpl + Controller + Mapper.xml（后端 6 文件）
   - **第 2 轮（PC 端前端，仅"仅PC端"或"两者都要"时执行）**：
     - 第 2 轮前（强制）：①确认路径；②确认 FormSchema 首位有 `{ field: 'id', show: false }`
     - 第 2 轮（并行）：data.ts + api.ts + List.vue + Modal.vue + 子表 Vue 文件
   - **第 2 轮（移动端前端，仅"仅移动端"或"两者都要"时执行，可与 PC 端第 2 轮并行）**：
     - 读取 `uniapp/SKILL.md` 和 `uniapp/references/code-templates.md`
     - 生成：`{EntityName}List.vue` + `{EntityName}Form.vue` + `{EntityName}Data.ts`（UniApp3 三件套）
     - 更新 `pages.json` 注册路由
   - **第 3 轮前（强制）**：①确认 Flyway SQL 路径正确；②Read `references/ref-menu-sql.md` 获取菜单权限 SQL 模板，**禁止凭记忆生成 SQL**
   - **第 3 轮**（并行）：Flyway 建表 SQL + 菜单权限 SQL（严格按 ref-menu-sql.md 模板填充变量）

**增量修改流程：**
1. 并行读取所有需修改的文件
2. 并行发出所有 Edit 调用（同一轮 response）
3. 增量修改模板见 `references/ref-d-misc.md`
4. 若增量是"加字段"且涉及主表 formSchema：再次确认首位仍保留 `{ field: 'id', show: false }`，不要被新加的字段挤掉

### Step 5: 输出清单
列出所有生成/修改的文件路径 + 后续操作说明（执行SQL、重启后端等）。

### Step 6: 询问是否生成移动端代码（仅全量生成时执行）

> ⚠️ **增量修改（场景C）跳过此步骤。**
> ⚠️ **"仅移动端"场景（Step 0 前置已判定）也跳过此步骤**，移动端代码已在 Step 4 中一并生成，无需重复询问。

**适用场景：** 仅当前端目标为"仅 PC 端"时，文件清单输出完毕后，**必须**向用户询问：

> "是否同时生成对应的移动端（UniApp3）CRUD 代码？（回复"是"/"y"/"需要"确认，其他内容跳过）"

**用户确认后的执行方式：**

1. 读取 `uniapp/SKILL.md`，按其中定义的交互流程执行移动端代码生成
2. 本次已收集的实体信息（实体名、包路径、字段列表、API路径前缀等）**直接复用**，无需用户重复输入
3. 仍需向用户询问 `uniapp/SKILL.md` Step 0 中移动端特有的配置项（UniApp3 项目根目录）
4. 后端代码已在本次全量生成中完成，移动端 skill 只生成前端代码，无需重复生成后端

### 本地环境自动执行菜单 SQL 规则

**前置条件（必须）：执行任何 SQL 之前，必须先询问用户要执行到哪个数据库。** 不要自动假设目标数据库名称，即使配置文件中有默认值。用户本机可能有多个数据库实例。

**判断条件：** 数据库连接地址为 `127.0.0.1` 或 `localhost`（即本地开发环境）。

**自动执行方式：** 确认目标数据库后，生成 Flyway SQL 文件后，同时通过 Bash 工具直接执行菜单权限 SQL：

```bash
# 先询问用户目标数据库名，假设用户确认为 {dbname}
# 先检查菜单是否已存在，避免重复插入
mysql --no-defaults --default-character-set=utf8mb4 -h127.0.0.1 -P3306 -uroot -proot {dbname} -e "SELECT id FROM sys_permission WHERE id='{timestamp}01'"
# 不存在则执行全部菜单 + 角色授权 SQL
mysql --no-defaults --default-character-set=utf8mb4 -h127.0.0.1 -P3306 -uroot -proot {dbname} < {flyway_sql_file_path}
```

**注意事项：**
- **执行 SQL 前必须先询问用户目标数据库名称**，不能自动假设（即使从 application-dev.yml 读到了数据库名，也必须展示给用户并等待确认）
- 仅在本地环境（127.0.0.1/localhost）自动执行，远程环境只生成 Flyway 文件
- 执行前先检查主菜单 ID 是否已存在，避免重复插入
- **执行已有 SQL 文件前必须先读取内容审查**，重点检查：主菜单的 `is_leaf` 必须为 `0`（有按钮子级时），`is_leaf=1` 会导致按钮权限在权限管理树中不可见
- 如果 MySQL 执行失败，提示用户手动执行 Flyway SQL，不中断整体流程
- 输出结果中标注 `菜单 SQL：已自动执行 ✓`

## 数据库连接

**已有表场景必须先查数据库！** 通过以下方式获取精确 DDL：

**重要：执行任何 SQL 之前，必须先询问用户要执行到哪个数据库。** 不要自动假设数据库名称。先读取 `application-dev.yml` 获取配置中的数据库名，然后向用户确认是否使用该数据库。

**场景A（已有表）— 一条命令取全部信息（DDL + 字段注释 + 字典列表 合并执行）：**

```bash
# 同一条 mysql 命令内完成三件事，减少连接次数
mysql --no-defaults --default-character-set=utf8mb4 -h127.0.0.1 -P3306 -uroot -proot {dbname} \
  -e "SHOW CREATE TABLE 表名\G" \
  -e "SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT, COLUMN_KEY, EXTRA FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='{dbname}' AND TABLE_NAME='表名' ORDER BY ORDINAL_POSITION" \
  -e "SELECT d.dict_code, d.dict_name, GROUP_CONCAT(i.item_text,'=',i.item_value ORDER BY i.sort_order SEPARATOR ', ') AS items FROM sys_dict d LEFT JOIN sys_dict_item i ON d.id=i.dict_id AND i.status=1 WHERE d.del_flag=0 GROUP BY d.dict_code,d.dict_name ORDER BY d.dict_code"
```

### ⛔ 数据库不可达时的强制回退路径

> **MySQL 连不上时（端口拒绝/账号错误/服务未启动），禁止直接降级到"跳过查询，全部新建"或"凭命名惯例猜测"。必须按以下优先级走 fallback：**
>
> 1. **优先：用 `jeecg-system` skill 的 HTTP API 查询。** `jeecg-system` 通过 JeecgBoot 后端 REST 接口工作，**不依赖数据库直连**，只要后端服务在跑（本地或远程）就能用。
>    - 调用方式：`python <skill目录>/jeecg-system/scripts/system_creator.py --api-base <地址> --token <X-Access-Token> --action query-dicts`
>    - 需要的两项信息：**后端 API 地址**（如 `http://localhost:8080/jeecg-boot`）+ **X-Access-Token**（用户从浏览器 F12 → Network → Request Headers 复制）
>    - 必须主动向用户索取这两项，**不得跳过**
> 2. **退而求其次：在项目 SQL 文件中搜索表定义**（`grep -r "CREATE TABLE.*表名"` 在 docs/db/ 目录下）。**仅适用于查 DDL**，不能用于字典/角色/用户等主数据查询。
> 3. **最后才考虑跳过查询**：上述两条都不可行（用户明确拒绝提供 token、后端服务也不可达），且**用户书面确认后**，方可在 Flyway SQL 中新建所需字典。
>
> **违反此回退顺序即视为违规**，包括"MySQL 连不上 → 直接跳过字典查询 → 全部新建"这种降级方式。

#### ⛔⛔ MySQL 连接失败 → 强制 STOP GATE（铁律，无例外）

> **MySQL 命令报 `Can't connect`/`10061`/`Access denied`/`ERROR 2002`/`ERROR 1045` 等任何连接错误时，必须立即停止后续所有工作（包括但不限于：搜 SQL 文件、读 application-dev.yml、生成代码、派发 SubAgent、写 Flyway SQL），并向用户输出以下话术等待回复：**
>
> ```
> ⚠️ MySQL 连接失败（{粘贴具体错误信息}）。按 SKILL.md "⛔ 数据库不可达时的强制回退路径"，
> 在继续之前必须先用 jeecg-system HTTP API 查询。请提供：
>   1. 后端 API 地址（例如 http://localhost:8080/jeecg-boot）
>   2. X-Access-Token（浏览器 F12 → Network → Request Headers 复制）
> 若两者都无法提供，请明确告知，我会再次确认是否接受"基于初始化 SQL 推断（可能与
> 真实库不一致）"作为兜底方案。
> ```
>
> **在收到用户对 API 地址 + token 的明确回复之前，禁止执行下方任一动作：**
> - 在项目目录下 `grep` / `Grep` 搜索字典编码、角色编码、用户、部门
> - 读取 `db/jeecgboot-mysql-*.sql` 等任何初始化 SQL 文件用于推断主数据存在状态
> - 读取 `application-dev.yml` / `application-prod.yml` 寻找其他数据库连接
> - 直接判定字典/角色不存在并准备新建
> - 进入摘要展示（Step 3）
> - 派发 SubAgent
> - 生成 Flyway SQL

#### ❌ 错误降级模式清单（识别后立刻停止）

以下行为在 MySQL 连接失败时**全部视为违规**，即使表面"看起来合理"或"看起来能完成任务"：

| 错误行为 | 为什么是错的 | 正确做法 |
|---------|------------|---------|
| 在 `db/jeecgboot-mysql-*.sql` 初始化文件中 grep 字典 / 角色 / 用户的存在状态 | 初始化文件只代表系统**初始**状态。业务团队已通过 Flyway 增量 SQL、运行时 API、生产库迁移添加了新数据，初始化文件与真实数据库早已脱节。靠它判断"字典是否存在"会产出与真实环境矛盾的代码 | 走 STOP GATE 索要 API + token |
| 用初始化 SQL 中的 `admin` role ID（如 `f6817f48af4fb3af11b9e8bf182f618b`）直接写菜单授权 SQL | 用户生产库的 admin role ID 可能与初始化文件不同，菜单授权会打到错的 role 上或失败 | 走 STOP GATE 索要 API + token，然后用 jeecg-system 查 admin role |
| 在 `flyway/sql/mysql/` 目录下 grep 字典编码看是否被引用过 | grep 命中只能说明"项目代码引用过这个字典"，不能证明"运行时数据库当前确实存在该字典" | 同上 |
| 静默跳过字典查询，直接把所有字典都按"新建"写入本次 Flyway SQL | 与真实库已有的同名字典冲突，部署到非本地环境会主键/唯一约束报错 | 走 STOP GATE |
| 看到 Flyway 目录里有 `V*_dict.sql` 等历史文件就推断字典已建 | 文件存在 ≠ 字典已 INSERT 成功 ≠ 当前未被删除 / 修改 | 走 STOP GATE |
| 用项目其他 SQL 文件中出现的 dict_code（如 `valid_status`）就断言它"存在" | 仅 DDL 类信息允许从 SQL 文件回退查询；字典 / 角色 / 用户**任何主数据状态都不允许**靠 grep 推断 | 走 STOP GATE |

**任何时候若发现自己即将执行上述清单中的动作，必须立刻停下，回到 STOP GATE 话术。**

#### ✅ 用户拒绝提供 API + token 后的处理

只有当用户**明确回复**"无法提供 token / 后端服务也不可用 / 接受基于初始化 SQL 推断的兜底方案"之后，才允许进入优先级 2 / 3。此时必须再次在摘要中显式标注：

```
⚠️ 本次字典 / 角色 / 菜单授权基于项目初始化 SQL 推断生成，与你的真实数据库状态可能不一致。
   部署到非本地环境前，请手动核对 sys_dict / sys_role 是否已存在同名记录。
```

用户回复"确认"后才能继续派发 SubAgent / 生成 SQL。

## Flyway 版本号规则

**生成 Flyway SQL 前必须检查已有版本号，并同时获取时间戳 — 两条命令并行发出：**

```bash
# 并行执行（同一轮 response 发出两个 Bash 调用）
ls {后端根路径}/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/ | sort -V | tail -5
date +%s%3N
```

版本命名规则：`V{YYYYMMDD}_{序号}__{描述}.sql`
- 检查当天是否已有文件（如 `V20260311_1__xxx.sql`）
- 如果有，序号递增（`V20260311_2__xxx.sql`）
- 如果没有，从 `_1` 开始

## 菜单 SQL 的 ID 生成

**时间戳在 Flyway 版本检查时已并行获取（见上方）**，直接使用，无需再单独执行 `date` 命令。

用这个时间戳作为基础 ID，依次拼接 01-14：
- 主菜单: `{timestamp}01`
- 添加按钮: `{timestamp}02`
- 编辑按钮: `{timestamp}03`
- ... 以此类推

## 字典智能匹配

> ⛔ **MySQL 不可达时的强制回退：**
> 本章节的 `mysql` 命令是默认方式，但 MySQL 连不上时**必须**按"数据库连接"章节的"⛔ 数据库不可达时的强制回退路径"执行：
> 1. 先尝试 `jeecg-system` skill 的 `scripts/system_creator.py --action query-dicts`（需用户提供 API 地址 + token）
> 2. 不能用"MySQL 连不上"作为跳过字典查询、直接新建字典的理由
>
> 详见 `## 数据库连接` 章节末尾的"⛔ 数据库不可达时的强制回退路径"。

**用户选择"读取系统字典"后，执行以下查询获取全部可用字典：**

```bash
# 查询所有字典编码及其选项值（{dbname} 需替换为用户确认的数据库名）
mysql --no-defaults --default-character-set=utf8mb4 -h127.0.0.1 -P3306 -uroot -proot {dbname} -e "
SELECT d.dict_code, d.dict_name, GROUP_CONCAT(i.item_text, '=', i.item_value ORDER BY i.sort_order SEPARATOR ', ') AS items
FROM sys_dict d
LEFT JOIN sys_dict_item i ON d.id = i.dict_id AND i.status = 1
WHERE d.del_flag = 0
GROUP BY d.dict_code, d.dict_name
ORDER BY d.dict_code
"
```

**匹配规则：** 拿到字典列表后，按以下优先级为字段匹配字典：
1. **用户明确指定** — 用户说"状态用字典 order_status"，直接使用
2. **字段名精确匹配** — 字段名（如 `status`）与 dict_code 完全一致
3. **语义关键词匹配** — 字段注释含"状态/类型/级别/分类"等关键词，搜索 dict_name 包含相同关键词的字典
4. **不匹配** — 找不到合适字典时，不使用字典注解，按普通 Input 处理

**匹配成功后的效果：**
- Entity: 自动添加 `@Dict(dicCode = "matched_dict_code")`
- data.ts columns: `dataIndex` 使用 `fieldName_dictText` 后缀
- data.ts formSchema: `component` 使用 `JDictSelectTag`，`componentProps: { dictCode: 'matched_dict_code' }`
- data.ts searchFormSchema: 同样使用 `JDictSelectTag` 组件

**展示格式：** 在 Step 3 表结构摘要中，匹配到字典的字段标注字典编码和选项值，如：
```
| 字段名 | 类型 | 控件 | 字典 |
| status | varchar(10) | JDictSelectTag | order_status (待付款=0, 已付款=1, 已完成=2) |
```

## 三种字典控件完整用法

JeecgBoot 支持三种字典类型，每种在后端 Entity、前端 data.ts 的 columns/formSchema/searchFormSchema/superQuerySchema 中的写法不同。

### 1. 系统字典（从 sys_dict 表获取）

适用场景：固定枚举值（状态、类型、级别等），值存储在 `sys_dict` + `sys_dict_item` 表中。

**查询可用字典：**
```bash
mysql ... -e "
SELECT d.dict_code, d.dict_name, GROUP_CONCAT(i.item_text, '=', i.item_value ORDER BY i.sort_order SEPARATOR ', ') AS items
FROM sys_dict d LEFT JOIN sys_dict_item i ON d.id = i.dict_id AND i.status = 1
WHERE d.del_flag = 0 GROUP BY d.dict_code, d.dict_name ORDER BY d.dict_code"
```

**后端 Entity：**
```java
@Excel(name = "学校状态", width = 15, dicCode = "valid_status")
@Dict(dicC
