@specpow/framework 0.5.21 → 0.5.22

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.
@@ -0,0 +1,158 @@
1
+ # MES CRUD Module Schema
2
+ # 基于 MES 项目(mom-master + implat-ui)真实代码模式定制
3
+ # 工件流: proposal → specs → design → tasks → api-docs → menu-register → apply
4
+
5
+ name: mes-crud-module
6
+ description: |
7
+ MES 系统专属 CRUD 模块生成器。
8
+ 基于 mom-master(Spring Boot + MyBatis-Plus + Oracle)后端
9
+ 和 implat-ui(Vue2 + ViewUI + VXETable)前端的真实代码模式。
10
+ 生成的代码直接匹配项目约定,无需二次适配。
11
+
12
+ apply:
13
+ requires:
14
+ - tasks # 实施前必须完成所有工件
15
+
16
+ artifacts:
17
+ - id: proposal
18
+ name: 模块提案
19
+ description: 描述要生成的 CRUD 模块(实体、字段、业务规则)
20
+ requires: []
21
+ template: proposal.md
22
+ instruction: |
23
+ 根据用户描述,生成 MES CRUD 模块提案。
24
+ 包含:模块名称、所属业务中心(modules-center)、核心实体、表名、
25
+ CRUD 操作列表、字段清单、业务规则。
26
+
27
+ 注意 MES 项目约定:
28
+ - 后端位于 modules-center/{module}-center/
29
+ - 包名: com.twsz.mom.{module}
30
+ - 实体继承 BaseModel(雪花 ID + 审计字段自动填充)
31
+ - 表名使用下划线命名,可选模块前缀
32
+ - 状态字段统一用 is_effect (1=启用, 0=停用)
33
+ output: proposal.md
34
+
35
+ - id: specs
36
+ name: 接口规范
37
+ description: 定义 MES 标准 CRUD 接口行为契约
38
+ requires: [proposal]
39
+ template: spec.md
40
+ instruction: |
41
+ 创建 MES 标准 CRUD 接口规范。使用 Delta Spec 格式。
42
+
43
+ MES 项目接口约定(必须遵守):
44
+ - POST /{entity}/search — 分页查询(请求体: PageForm<{Entity}>)
45
+ - POST /{entity}/add — 新增(请求体: Entity)
46
+ - PUT /{entity}/update — 修改(请求体: Entity)
47
+ - DELETE /{entity}/delete — 批量删除(请求体: Long[] ids)
48
+ - GET /{entity}/get/{id} — 详情查询
49
+ - POST /{entity}/list — 不分页列表(请求体: Entity)
50
+ - POST /{entity}/export — Excel 导出(EasyExcel)
51
+
52
+ 响应统一使用 ResponseWrapper<T>。
53
+ 分页使用 PageForm<T>(size + current + condition)。
54
+
55
+ 前端接口约定:
56
+ - API 文件位于 src/api/{domain}/{entity}.js
57
+ - 使用 import axios from '@/libs/request'
58
+ - search 发送 { size, current, condition } 接收 { records, total }
59
+ - delete 传 ID 数组(支持批量)
60
+
61
+ 规范是行为契约,描述系统做什么,不描述怎么做。
62
+ 每个需求必须可验证(Given/When/Then)。
63
+ output: specs/{{entity}}/spec.md
64
+
65
+ - id: design
66
+ name: 模块设计
67
+ description: 数据库表设计 + 前后端代码结构 + 接口定义
68
+ requires: [proposal, specs]
69
+ template: design.md
70
+ instruction: |
71
+ 创建 MES CRUD 模块设计文档。包含:
72
+
73
+ 1. 数据库设计(Oracle)
74
+ - 表结构(遵循 BaseModel 审计字段约定)
75
+ - 主键: id NUMBER(19) 雪花算法
76
+ - 审计字段: created_by, created_date, last_updated_by, last_updated_date
77
+ - 状态字段: is_effect NUMBER(1) DEFAULT 1
78
+
79
+ 2. 后端代码结构
80
+ - Entity: 继承 BaseModel,@TableName,@Data
81
+ - Mapper: 继承 BaseMapper<T>,XML 含 Columns/Where/Joins 片段
82
+ - Service: 继承 IService<T>
83
+ - ServiceImpl: 继承 ServiceImpl<Mapper, Entity>
84
+ - Controller: @RestController,返回 ResponseWrapper<T>
85
+
86
+ 3. 前端代码结构
87
+ - API: src/api/{domain}/{entity}.js
88
+ - 列表页: src/views/{domain}/{entity}/index.vue(indexPage mixin + search-table)
89
+ - 表单页: src/views/{domain}/{entity}/{entity}-form.vue(master-sub + BaseMixin)
90
+
91
+ 4. 接口定义表
92
+
93
+ 如果变更较小(< 3 个文件),可以跳过此工件。
94
+ output: design.md
95
+ conditional: true
96
+
97
+ - id: tasks
98
+ name: 任务列表
99
+ description: 按 MES 项目约定拆分的实现任务(SDD 引擎逐个执行)
100
+ requires: [proposal, specs, design]
101
+ template: tasks.md
102
+ instruction: |
103
+ 创建 MES CRUD 模块实现任务列表。每个任务应:
104
+ 1. 包含精确的文件路径(匹配项目包结构)
105
+ 2. 包含完整的代码模板或明确的修改指令
106
+ 3. 包含验证步骤
107
+ 4. 任务之间尽量独立(便于 SDD 并行)
108
+
109
+ MES 后端任务顺序:
110
+ 1. 建表 SQL(Oracle 语法)
111
+ 2. Entity 实体类(继承 BaseModel)
112
+ 3. Mapper 接口 + XML(含 Columns/Where/Joins 片段)
113
+ 4. Service 接口 + 实现
114
+ 5. Controller
115
+
116
+ MES 前端任务顺序:
117
+ 6. API 接口文件
118
+ 7. 列表页(index.vue + indexPage mixin)
119
+ 8. 表单页({entity}-form.vue + master-sub)
120
+ 9. 菜单注册(c_sys_resource SQL)
121
+
122
+ 格式:
123
+ - [ ] Task N: <标题>
124
+ <详细描述,包含精确文件路径和代码>
125
+ 验证: <如何验证>
126
+ output: tasks.md
127
+
128
+ - id: api-docs
129
+ name: API 接口文档
130
+ description: MES 标准 RESTful 接口文档(含请求/响应示例)
131
+ requires: [design]
132
+ template: api-docs.md
133
+ instruction: |
134
+ 生成 MES 标准 API 接口文档:
135
+ - 接口概览表
136
+ - 每个接口的请求参数和响应示例(JSON 格式)
137
+ - 使用 ResponseWrapper 包装格式
138
+ - PageForm 分页请求格式
139
+ - 通用错误码说明(使用 HttpStatus 枚举)
140
+ output: api-docs.md
141
+
142
+ - id: menu-register
143
+ name: 菜单注册
144
+ description: c_sys_resource 表菜单 + 按钮权限注册 SQL
145
+ requires: [tasks]
146
+ template: menu-register.md
147
+ instruction: |
148
+ 生成 MES 菜单注册配置:
149
+ - c_sys_resource 表 INSERT 语句(菜单 + 按钮权限)
150
+ - 前端路由配置参考
151
+ - 权限标识约定: {module}:{entity}:{action}
152
+
153
+ MES 菜单注册约定:
154
+ - type=1 路由菜单, type=2 按钮权限, type=3 API 资源
155
+ - component 字段为 Vue 组件路径(如 "pm/entity/index")
156
+ - permission 字段为权限标识(如 "pm:entity:add")
157
+ - 路由由后端动态返回,前端通过 addRoutes 注册
158
+ output: menu-register.md
@@ -0,0 +1,238 @@
1
+ # MES API 接口文档: {{Entity}}
2
+
3
+ > 模块: {{module}} | 实体: {{Entity}} | 基础路径: `/{{entity}}`
4
+ > 响应格式: `ResponseWrapper<T>` | 分页格式: `PageForm<T>`
5
+
6
+ ---
7
+
8
+ ## 接口概览
9
+
10
+ | Method | Path | 描述 | 认证 |
11
+ |--------|------|------|------|
12
+ | POST | `/{{entity}}/search` | 分页查询 | 需要 |
13
+ | GET | `/{{entity}}/get/{id}` | 详情查询 | 需要 |
14
+ | POST | `/{{entity}}/add` | 新增 | 需要 |
15
+ | PUT | `/{{entity}}/update` | 修改 | 需要 |
16
+ | DELETE | `/{{entity}}/delete` | 批量删除 | 需要 |
17
+ | POST | `/{{entity}}/list` | 不分页列表 | 需要 |
18
+ | POST | `/{{entity}}/export` | Excel 导出 | 需要 |
19
+
20
+ ---
21
+
22
+ ## 1. 分页查询
23
+
24
+ **请求**: `POST /{{entity}}/search`
25
+
26
+ **请求体** (`PageForm<{{Entity}}>`):
27
+ ```json
28
+ {
29
+ "size": 20,
30
+ "current": 1,
31
+ "condition": {
32
+ "isEffect": 1
33
+ }
34
+ }
35
+ ```
36
+
37
+ | 参数 | 类型 | 必填 | 说明 |
38
+ |------|------|------|------|
39
+ | size | number | 否 | 每页条数,默认 20 |
40
+ | current | number | 否 | 页码,默认 1 |
41
+ | condition | object | 否 | 查询条件(实体字段) |
42
+
43
+ **响应示例**:
44
+ ```json
45
+ {
46
+ "code": 200,
47
+ "message": "操作成功",
48
+ "data": {
49
+ "records": [
50
+ {
51
+ "id": "1234567890123456789",
52
+ "isEffect": 1,
53
+ "createdBy": "admin",
54
+ "createdDate": "2025/01/01 00:00:00",
55
+ "lastUpdatedBy": "admin",
56
+ "lastUpdatedDate": "2025/01/01 00:00:00"
57
+ }
58
+ ],
59
+ "total": 100,
60
+ "size": 20,
61
+ "current": 1
62
+ }
63
+ }
64
+ ```
65
+
66
+ > **注意**: id 为 Long 类型,序列化为字符串(`@JsonSerialize(using = ToStringSerializer.class)`)避免 JS 精度丢失。
67
+
68
+ ---
69
+
70
+ ## 2. 详情查询
71
+
72
+ **请求**: `GET /{{entity}}/get/{id}`
73
+
74
+ | 参数 | 类型 | 必填 | 说明 |
75
+ |------|------|------|------|
76
+ | id | number | 是 | 记录 ID(路径参数) |
77
+
78
+ **响应示例**:
79
+ ```json
80
+ {
81
+ "code": 200,
82
+ "message": "操作成功",
83
+ "data": {
84
+ "id": "1234567890123456789",
85
+ "isEffect": 1,
86
+ "createdBy": "admin",
87
+ "createdDate": "2025/01/01 00:00:00",
88
+ "lastUpdatedBy": "admin",
89
+ "lastUpdatedDate": "2025/01/01 00:00:00"
90
+ }
91
+ }
92
+ ```
93
+
94
+ ---
95
+
96
+ ## 3. 新增
97
+
98
+ **请求**: `POST /{{entity}}/add`
99
+
100
+ **请求体**:
101
+ ```json
102
+ {
103
+ "isEffect": 1
104
+ }
105
+ ```
106
+
107
+ > id、createdBy、createdDate、lastUpdatedBy、lastUpdatedDate 由系统自动填充,无需传入。
108
+
109
+ **响应示例**:
110
+ ```json
111
+ {
112
+ "code": 200,
113
+ "message": "操作成功",
114
+ "data": null
115
+ }
116
+ ```
117
+
118
+ ---
119
+
120
+ ## 4. 修改
121
+
122
+ **请求**: `PUT /{{entity}}/update`
123
+
124
+ **请求体**:
125
+ ```json
126
+ {
127
+ "id": "1234567890123456789",
128
+ "isEffect": 1
129
+ }
130
+ ```
131
+
132
+ > lastUpdatedBy、lastUpdatedDate 由系统自动更新。
133
+
134
+ **响应示例**:
135
+ ```json
136
+ {
137
+ "code": 200,
138
+ "message": "操作成功",
139
+ "data": null
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ## 5. 批量删除
146
+
147
+ **请求**: `DELETE /{{entity}}/delete`
148
+
149
+ **请求体**:
150
+ ```json
151
+ [1, 2, 3]
152
+ ```
153
+
154
+ | 参数 | 类型 | 必填 | 说明 |
155
+ |------|------|------|------|
156
+ | body | Long[] | 是 | 待删除记录 ID 数组 |
157
+
158
+ **响应示例**:
159
+ ```json
160
+ {
161
+ "code": 200,
162
+ "message": "操作成功",
163
+ "data": null
164
+ }
165
+ ```
166
+
167
+ ---
168
+
169
+ ## 6. 不分页列表
170
+
171
+ **请求**: `POST /{{entity}}/list`
172
+
173
+ **请求体**:
174
+ ```json
175
+ {
176
+ "isEffect": 1
177
+ }
178
+ ```
179
+
180
+ **响应示例**:
181
+ ```json
182
+ {
183
+ "code": 200,
184
+ "message": "操作成功",
185
+ "data": [
186
+ { "id": "1234567890123456789", "isEffect": 1 }
187
+ ]
188
+ }
189
+ ```
190
+
191
+ > 默认限制最多返回 10000 条(可通过 entity.rowNum 覆盖)。
192
+
193
+ ---
194
+
195
+ ## 7. Excel 导出
196
+
197
+ **请求**: `POST /{{entity}}/export`
198
+
199
+ **请求体**: 同查询条件(实体字段)
200
+
201
+ **响应**: Excel 文件流(`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`)
202
+
203
+ ---
204
+
205
+ ## 通用错误码(HttpStatus 枚举)
206
+
207
+ | 错误码 | 常量名 | 说明 |
208
+ |--------|--------|------|
209
+ | 200 | SUCCESS | 操作成功 |
210
+ | 600 | ERROR | 系统错误 |
211
+ | 601 | UNAUTHORIZED | 未认证 |
212
+ | 608 | PARAM_NULL | 参数为空 |
213
+ | 620 | OBJECT_EXIST | 对象已存在 |
214
+ | 621 | OBJECT_INSERT_FAIL | 新增失败 |
215
+ | 622 | OBJECT_UPDATE_FAIL | 修改失败 |
216
+ | 623 | OBJECT_DELETE_FAIL | 删除失败 |
217
+ | 634 | OBJECT_NOT_EXIST | 对象不存在 |
218
+
219
+ **错误响应格式**:
220
+ ```json
221
+ {
222
+ "code": 621,
223
+ "message": "新增失败",
224
+ "data": null
225
+ }
226
+ ```
227
+
228
+ ---
229
+
230
+ ## ResponseWrapper 结构
231
+
232
+ ```java
233
+ {
234
+ "code": 200, // int — HttpStatus 枚举值
235
+ "message": "操作成功", // String — 提示信息
236
+ "data": T // 泛型 — 业务数据
237
+ }
238
+ ```
@@ -0,0 +1,422 @@
1
+ # MES CRUD 模块设计: {{Entity}}
2
+
3
+ > 模块: {{module}} | 业务中心: {{module}}-center | 表: {{table_name}}
4
+
5
+ ---
6
+
7
+ ## 1. 数据库设计(Oracle)
8
+
9
+ ### 建表 SQL
10
+
11
+ ```sql
12
+ CREATE TABLE {{table_name}} (
13
+ id NUMBER(19) NOT NULL,
14
+ -- ============================================================
15
+ -- 业务字段(根据提案中的字段清单补充)
16
+ -- ============================================================
17
+ is_effect NUMBER(1) DEFAULT 1,
18
+ -- ============================================================
19
+ -- 审计字段(BaseModel / TimeModel 自动填充)
20
+ -- ============================================================
21
+ created_by VARCHAR2(64) DEFAULT '',
22
+ created_date TIMESTAMP DEFAULT SYSTIMESTAMP,
23
+ last_updated_by VARCHAR2(64) DEFAULT '',
24
+ last_updated_date TIMESTAMP DEFAULT SYSTIMESTAMP,
25
+ -- ============================================================
26
+ CONSTRAINT pk_{{table_name}} PRIMARY KEY (id)
27
+ );
28
+
29
+ COMMENT ON TABLE {{table_name}} IS '{{table_comment}}';
30
+ -- COMMENT ON COLUMN {{table_name}}.xxx IS 'xxx';
31
+
32
+ -- 雪花算法 ID 序列(可选,若由应用层生成则不需要)
33
+ -- CREATE SEQUENCE seq_{{table_name}} START WITH 1 INCREMENT BY 1 NOCACHE;
34
+ ```
35
+
36
+ ---
37
+
38
+ ## 2. 后端代码结构
39
+
40
+ ### 目录布局
41
+
42
+ ```
43
+ modules-center/{{module}}-center/{{module}}-service/
44
+ └── src/main/java/com/twsz/mom/{{module}}/
45
+ ├── controller/
46
+ │ └── {{Entity}}Controller.java
47
+ ├── service/
48
+ │ ├── {{Entity}}Service.java
49
+ │ └── impl/
50
+ │ └── {{Entity}}ServiceImpl.java
51
+ ├── mapper/
52
+ │ └── {{Entity}}Mapper.java
53
+ └── model/
54
+ └── {{Entity}}.java
55
+
56
+ └── src/main/resources/
57
+ └── mapper/
58
+ └── {{Entity}}Mapper.xml
59
+ ```
60
+
61
+ ### Entity(继承 BaseModel)
62
+
63
+ ```java
64
+ @Data
65
+ @EqualsAndHashCode(callSuper = true)
66
+ @JsonInclude(JsonInclude.Include.NON_NULL)
67
+ @TableName("{{table_name}}")
68
+ public class {{Entity}} extends BaseModel {
69
+ // 业务字段(审计字段由 BaseModel → TimeModel 提供)
70
+ private Integer isEffect;
71
+ // ... 根据提案补充
72
+ }
73
+ ```
74
+
75
+ > **BaseModel 继承链**: `ViewModel`(fields/columns/orderBy/动态查询)→ `TimeModel`(审计字段自动填充)→ `BaseModel`(id 雪花算法)
76
+
77
+ ### Mapper(继承 BaseMapper)
78
+
79
+ ```java
80
+ @Mapper
81
+ public interface {{Entity}}Mapper extends BaseMapper<{{Entity}}> {
82
+ IPage<{{Entity}}> pageSearch(Page<{{Entity}}> page, @Param("entity") {{Entity}} entity);
83
+ List<{{Entity}}> list(@Param("entity") {{Entity}} entity);
84
+ }
85
+ ```
86
+
87
+ ### Mapper XML(标准片段模板)
88
+
89
+ ```xml
90
+ <mapper namespace="com.twsz.mom.{{module}}.mapper.{{Entity}}Mapper">
91
+ <resultMap id="BaseResultMap" type="com.twsz.mom.{{module}}.model.{{Entity}}"/>
92
+
93
+ <!-- 动态列(支持 ViewModel.fields 部分列查询) -->
94
+ <sql id="{{Entity}}Columns">
95
+ <choose>
96
+ <when test="entity.fields != null">
97
+ <foreach collection="entity.columns" item="it" separator=",">t.${it}</foreach>
98
+ </when>
99
+ <otherwise>t.*</otherwise>
100
+ </choose>
101
+ </sql>
102
+
103
+ <!-- 动态 WHERE(每个字段一个 if 判断) -->
104
+ <sql id="{{Entity}}Where">
105
+ <where>
106
+ <if test="entity.id != null">AND t.id = #{entity.id}</if>
107
+ <if test="entity.isEffect != null">AND t.is_effect = #{entity.isEffect}</if>
108
+ <!-- 根据字段清单补充 -->
109
+ </where>
110
+ <choose>
111
+ <when test="entity.orderBy != null and entity.orderBy != ''">
112
+ ORDER BY t.${entity.orderBy}
113
+ </when>
114
+ <otherwise>ORDER BY t.id DESC</otherwise>
115
+ </choose>
116
+ </sql>
117
+
118
+ <sql id="{{Entity}}Joins"></sql>
119
+
120
+ <select id="pageSearch" resultMap="BaseResultMap">
121
+ SELECT <include refid="{{Entity}}Columns"/>
122
+ FROM {{table_name}} t
123
+ <include refid="{{Entity}}Joins"/>
124
+ <include refid="{{Entity}}Where"/>
125
+ </select>
126
+
127
+ <select id="list" resultMap="BaseResultMap">
128
+ SELECT * FROM (
129
+ SELECT <include refid="{{Entity}}Columns"/>
130
+ FROM {{table_name}} t
131
+ <include refid="{{Entity}}Joins"/>
132
+ <include refid="{{Entity}}Where"/>
133
+ ) tt WHERE rownum &lt;=
134
+ <choose>
135
+ <when test="entity.rowNum != null">#{entity.rowNum}</when>
136
+ <otherwise>10000</otherwise>
137
+ </choose>
138
+ </select>
139
+ </mapper>
140
+ ```
141
+
142
+ ### Service 接口
143
+
144
+ ```java
145
+ public interface {{Entity}}Service extends IService<{{Entity}}> {
146
+ ResponseWrapper<String> insert({{Entity}} entity);
147
+ ResponseWrapper<String> update({{Entity}} entity);
148
+ ResponseWrapper<String> deleteByIds(Collection<Long> ids);
149
+ ResponseWrapper<Page<{{Entity}}>> search(PageForm<{{Entity}}> pageForm);
150
+ List<{{Entity}}> list({{Entity}} entity);
151
+ }
152
+ ```
153
+
154
+ ### Service 实现
155
+
156
+ ```java
157
+ @Slf4j
158
+ @Service
159
+ public class {{Entity}}ServiceImpl extends ServiceImpl<{{Entity}}Mapper, {{Entity}}>
160
+ implements {{Entity}}Service {
161
+
162
+ @Override
163
+ public ResponseWrapper<String> insert({{Entity}} entity) {
164
+ if (super.save(entity)) {
165
+ return ResponseWrapper.defaultSuccess();
166
+ }
167
+ return ResponseWrapper.ofStatus(HttpStatus.OBJECT_INSERT_FAIL);
168
+ }
169
+
170
+ @Override
171
+ public ResponseWrapper<String> update({{Entity}} entity) {
172
+ if (super.updateById(entity)) {
173
+ return ResponseWrapper.defaultSuccess();
174
+ }
175
+ return ResponseWrapper.ofStatus(HttpStatus.OBJECT_UPDATE_FAIL);
176
+ }
177
+
178
+ @Override
179
+ public ResponseWrapper<String> deleteByIds(Collection<Long> ids) {
180
+ if (super.removeByIds(ids)) {
181
+ return ResponseWrapper.defaultSuccess();
182
+ }
183
+ return ResponseWrapper.ofStatus(HttpStatus.OBJECT_DELETE_FAIL);
184
+ }
185
+
186
+ @Override
187
+ public ResponseWrapper<Page<{{Entity}}>> search(PageForm<{{Entity}}> pageForm) {
188
+ Page<{{Entity}}> p = new Page<>(pageForm.getCurrent(), pageForm.getSize());
189
+ baseMapper.pageSearch(p, pageForm.getCondition());
190
+ return ResponseWrapper.ofSuccess(p);
191
+ }
192
+
193
+ @Override
194
+ public List<{{Entity}}> list({{Entity}} entity) {
195
+ return baseMapper.list(entity);
196
+ }
197
+ }
198
+ ```
199
+
200
+ ### Controller
201
+
202
+ ```java
203
+ @Slf4j
204
+ @RestController
205
+ @RequestMapping("/{{entity}}")
206
+ public class {{Entity}}Controller {
207
+
208
+ @Resource
209
+ private {{Entity}}Service {{entity}}Service;
210
+
211
+ @PostMapping(value = "add")
212
+ public ResponseWrapper<String> add(@RequestBody {{Entity}} entity) {
213
+ return {{entity}}Service.insert(entity);
214
+ }
215
+
216
+ @PutMapping(value = "update")
217
+ public ResponseWrapper<String> update(@RequestBody {{Entity}} entity) {
218
+ return {{entity}}Service.update(entity);
219
+ }
220
+
221
+ @PostMapping(value = "search")
222
+ public ResponseWrapper<Page<{{Entity}}>> search(@RequestBody PageForm<{{Entity}}> pageForm) {
223
+ return {{entity}}Service.search(pageForm);
224
+ }
225
+
226
+ @DeleteMapping(value = "delete")
227
+ public ResponseWrapper<String> delete(@RequestBody Long[] ids) {
228
+ return {{entity}}Service.deleteByIds(Arrays.asList(ids));
229
+ }
230
+
231
+ @GetMapping(value = "get/{id}")
232
+ public ResponseWrapper<{{Entity}}> get(@PathVariable Long id) {
233
+ return ResponseWrapper.ofSuccess({{entity}}Service.getById(id));
234
+ }
235
+
236
+ @PostMapping(value = "list")
237
+ public ResponseWrapper<List<{{Entity}}>> list(@RequestBody {{Entity}} entity) {
238
+ return ResponseWrapper.ofSuccess({{entity}}Service.list(entity));
239
+ }
240
+
241
+ @PostMapping(value = "export")
242
+ public void export(@RequestBody {{Entity}} condition, HttpServletResponse response) throws IOException {
243
+ // EasyExcel 导出
244
+ }
245
+ }
246
+ ```
247
+
248
+ ---
249
+
250
+ ## 3. 前端代码结构
251
+
252
+ ### 目录布局
253
+
254
+ ```
255
+ src/
256
+ ├── api/{{domain}}/
257
+ │ └── {{entity}}.js
258
+ └── views/{{domain}}/{{entity}}/
259
+ ├── index.vue # 列表页
260
+ └── {{entity}}-form.vue # 表单页
261
+ ```
262
+
263
+ ### API 接口文件
264
+
265
+ ```js
266
+ import axios from '@/libs/request'
267
+ import { exportExcel } from '../file'
268
+
269
+ const apiPrefix = '/{{entity}}'
270
+
271
+ const search{{Entity}} = data => {
272
+ return axios.request({ url: `${apiPrefix}/search`, method: 'POST', data })
273
+ }
274
+
275
+ const save{{Entity}} = data => {
276
+ const url = data.id ? `${apiPrefix}/update` : `${apiPrefix}/add`
277
+ const method = data.id ? 'PUT' : 'POST'
278
+ return axios.request({ url, method, data })
279
+ }
280
+
281
+ const delete{{Entity}} = ids => {
282
+ return axios.request({
283
+ url: `${apiPrefix}/delete`,
284
+ method: 'DELETE',
285
+ data: Array.isArray(ids) ? ids : [ids]
286
+ })
287
+ }
288
+
289
+ const list{{Entity}} = data => {
290
+ return axios.request({ url: `${apiPrefix}/list`, method: 'POST', data })
291
+ }
292
+
293
+ const export{{Entity}} = data => {
294
+ return exportExcel(`${apiPrefix}/export`, data)
295
+ }
296
+
297
+ export default { search{{Entity}}, save{{Entity}}, delete{{Entity}}, list{{Entity}}, export{{Entity}} }
298
+ ```
299
+
300
+ ### 列表页(index.vue)
301
+
302
+ ```vue
303
+ <template>
304
+ <div class="master-index">
305
+ <search-table v-show="showIndexPage" ref="searchTable" :option="option" :columns="tableColumns">
306
+ <template #condition-form>
307
+ <Form ref="conditionForm" class="search-condition-form" label-colon @keyup.enter.native="refresh">
308
+ <!-- 搜索条件表单字段 -->
309
+ </Form>
310
+ </template>
311
+ </search-table>
312
+ <tw-card v-show="!showIndexPage" :back="triggerBack">
313
+ <{{Entity}}Form :readonly="readonly" :form="formData" :key="instanceKey"
314
+ @on-success="handleSuccess" />
315
+ </tw-card>
316
+ </div>
317
+ </template>
318
+
319
+ <script>
320
+ import { indexPage } from '_c/table-form/index-mixin'
321
+ import {{Entity}}Api from '@/api/{{domain}}/{{entity}}'
322
+ import {{Entity}}Form from './{{entity}}-form'
323
+
324
+ export default {
325
+ mixins: [indexPage],
326
+ components: { {{Entity}}Form },
327
+ data() {
328
+ return {
329
+ option: {
330
+ tableName: '{{entity}}',
331
+ searchForm: {},
332
+ fixedTableHeight: true,
333
+ add: { enable: true, method: this.add },
334
+ edit: { enable: true, method: this.edit },
335
+ view: { enable: true, method: this.view },
336
+ delete: { enable: true, method: {{Entity}}Api.delete{{Entity}} },
337
+ export: { enable: true, method: {{Entity}}Api.export{{Entity}} },
338
+ search: { query: {{Entity}}Api.search{{Entity}} },
339
+ },
340
+ tableColumns: [
341
+ { type: 'selection' },
342
+ // 表格列定义
343
+ { title: this.$t('operate||操作'), slot: 'operate' }
344
+ ]
345
+ }
346
+ }
347
+ }
348
+ </script>
349
+ ```
350
+
351
+ ### 表单页({{entity}}-form.vue)
352
+
353
+ ```vue
354
+ <template>
355
+ <master-sub :readonly="readonly">
356
+ <template v-if="!readonly" #master-header-toolbar>
357
+ <Button type="primary" :loading="loading" @click="doSubmit">{{ $t('submit||提交') }}</Button>
358
+ </template>
359
+ <template #master-form>
360
+ <Form ref="mform" :model="mform" :label-width="120" :disabled="readonly" class="form">
361
+ <!-- 表单字段 -->
362
+ </Form>
363
+ </template>
364
+ </master-sub>
365
+ </template>
366
+
367
+ <script>
368
+ import { BaseMixin } from '@/mixin'
369
+ import {{Entity}}Api from '@/api/{{domain}}/{{entity}}'
370
+
371
+ export default {
372
+ mixins: [BaseMixin],
373
+ props: {
374
+ readonly: { type: Boolean, default: false },
375
+ form: { type: Object, default: () => ({}) }
376
+ },
377
+ data() { return { mform: {}, default: {} } },
378
+ created() {
379
+ this.mform = Object.assign({}, this.default, this.form)
380
+ },
381
+ methods: {
382
+ doSubmit() {
383
+ this.$refs.mform.validate(valid => {
384
+ if (valid) {
385
+ this.asyncLoading({{Entity}}Api.save{{Entity}}(this.mform)).then(res => {
386
+ this.$Message.success({ background: true, content: this.$t('submit.success||提交成功') })
387
+ this.$emit('on-success', this.mform)
388
+ })
389
+ }
390
+ })
391
+ }
392
+ }
393
+ }
394
+ </script>
395
+ ```
396
+
397
+ ---
398
+
399
+ ## 4. 接口定义
400
+
401
+ | Method | Path | 描述 | 请求体 | 响应 |
402
+ |--------|------|------|--------|------|
403
+ | POST | /{{entity}}/search | 分页查询 | `PageForm<{{Entity}}>` | `ResponseWrapper<Page<{{Entity}}>>` |
404
+ | POST | /{{entity}}/add | 新增 | `{{Entity}}` | `ResponseWrapper<String>` |
405
+ | PUT | /{{entity}}/update | 修改 | `{{Entity}}` | `ResponseWrapper<String>` |
406
+ | DELETE | /{{entity}}/delete | 批量删除 | `Long[]` | `ResponseWrapper<String>` |
407
+ | GET | /{{entity}}/get/{id} | 详情 | — | `ResponseWrapper<{{Entity}}>` |
408
+ | POST | /{{entity}}/list | 不分页列表 | `{{Entity}}` | `ResponseWrapper<List<{{Entity}}>>` |
409
+ | POST | /{{entity}}/export | Excel 导出 | `{{Entity}}` | Excel 文件流 |
410
+
411
+ ---
412
+
413
+ ## 5. 前后端分工
414
+
415
+ | 功能 | 前端 | 后端 |
416
+ |------|------|------|
417
+ | 列表页 | search-table + indexPage mixin | POST /search(PageForm 分页) |
418
+ | 新增 | master-sub 表单 + save(无 id → add) | POST /add |
419
+ | 编辑 | master-sub 表单 + save(有 id → update) | PUT /update |
420
+ | 删除 | 确认弹窗 + delete(ids) | DELETE /delete |
421
+ | 导出 | exportExcel Blob 下载 | POST /export(EasyExcel) |
422
+ | 菜单 | 动态路由(后端返回 component 路径) | c_sys_resource 注册 |
@@ -0,0 +1,126 @@
1
+ # 菜单注册: {{Entity}}
2
+
3
+ > 模块: {{module}} | 实体: {{Entity}} | 组件路径: `{{domain}}/{{entity}}/index`
4
+
5
+ ---
6
+
7
+ ## 1. 菜单配置
8
+
9
+ | 配置项 | 值 | 说明 |
10
+ |--------|-----|------|
11
+ | 菜单名称 | {{moduleName}} | 显示在侧边栏的名称 |
12
+ | 父级菜单 | 根据实际选择 | c_sys_resource.pid |
13
+ | 排序 | 100 | 同级菜单排序 |
14
+ | 图标 | ios-folder | ViewUI 图标名称 |
15
+ | 路由路径 | /{{domain}}/{{entity}} | 前端路由 |
16
+ | 组件路径 | {{domain}}/{{entity}}/index | Vue 组件路径(相对 src/views/) |
17
+
18
+ ---
19
+
20
+ ## 2. c_sys_resource 表结构
21
+
22
+ | 字段 | 类型 | 说明 |
23
+ |------|------|------|
24
+ | id | bigint | 主键(雪花算法) |
25
+ | title | varchar | 菜单/按钮显示名称 |
26
+ | pid | bigint | 父级 ID(0 = 顶级) |
27
+ | sort | int | 排序号 |
28
+ | enable | int | 1=启用 |
29
+ | type | int | 1=路由菜单, 2=按钮权限, 3=API 资源 |
30
+ | path | varchar | URL 路径 |
31
+ | component | varchar | Vue 组件路径 |
32
+ | icon | varchar | 图标 |
33
+ | permission | varchar | 权限标识 |
34
+
35
+ ---
36
+
37
+ ## 3. SQL 插入语句
38
+
39
+ ```sql
40
+ -- ============================================================
41
+ -- 菜单注册(c_sys_resource)
42
+ -- ============================================================
43
+
44
+ -- 1. 菜单项(type=1 路由菜单)
45
+ -- 请先确认父级菜单 ID(替换下面的 @parentId)
46
+ -- 可通过 SELECT id FROM c_sys_resource WHERE title = '父级菜单名' 获取
47
+
48
+ INSERT INTO c_sys_resource (id, title, pid, sort, enable, type, path, component, icon, permission, created_by, created_date, last_updated_by, last_updated_date)
49
+ VALUES (
50
+ -- id: 使用雪花算法生成,或手动指定一个不冲突的大数字
51
+ {{menu_id}}, -- 菜单 ID(需唯一)
52
+ '{{moduleName}}', -- 菜单名称
53
+ {{parent_id}}, -- 父级菜单 ID(0=顶级)
54
+ 100, -- 排序号
55
+ 1, -- 启用
56
+ 1, -- type=1 路由菜单
57
+ '/{{domain}}/{{entity}}', -- 路由路径
58
+ '{{domain}}/{{entity}}/index', -- 组件路径
59
+ 'ios-folder', -- 图标
60
+ '{{module}}:{{entity}}:view', -- 权限标识
61
+ 'admin',
62
+ SYSTIMESTAMP,
63
+ 'admin',
64
+ SYSTIMESTAMP
65
+ );
66
+
67
+ -- 2. 按钮权限(type=2 按钮)
68
+ -- @menuId 替换为上面插入的菜单 ID
69
+
70
+ INSERT INTO c_sys_resource (id, title, pid, sort, enable, type, path, component, icon, permission, created_by, created_date, last_updated_by, last_updated_date)
71
+ VALUES
72
+ -- 查询按钮
73
+ ({{menu_id}} + 1, '{{moduleName}}查询', {{menu_id}}, 1, 1, 2, '#', '', '', '{{module}}:{{entity}}:view', 'admin', SYSTIMESTAMP, 'admin', SYSTIMESTAMP),
74
+ -- 新增按钮
75
+ ({{menu_id}} + 2, '{{moduleName}}新增', {{menu_id}}, 2, 1, 2, '#', '', '', '{{module}}:{{entity}}:add', 'admin', SYSTIMESTAMP, 'admin', SYSTIMESTAMP),
76
+ -- 修改按钮
77
+ ({{menu_id}} + 3, '{{moduleName}}修改', {{menu_id}}, 3, 1, 2, '#', '', '', '{{module}}:{{entity}}:edit', 'admin', SYSTIMESTAMP, 'admin', SYSTIMESTAMP),
78
+ -- 删除按钮
79
+ ({{menu_id}} + 4, '{{moduleName}}删除', {{menu_id}}, 4, 1, 2, '#', '', '', '{{module}}:{{entity}}:delete', 'admin', SYSTIMESTAMP, 'admin', SYSTIMESTAMP),
80
+ -- 导出按钮
81
+ ({{menu_id}} + 5, '{{moduleName}}导出', {{menu_id}}, 5, 1, 2, '#', '', '', '{{module}}:{{entity}}:export', 'admin', SYSTIMESTAMP, 'admin', SYSTIMESTAMP);
82
+ ```
83
+
84
+ ---
85
+
86
+ ## 4. 权限标识
87
+
88
+ | 权限标识 | 描述 | 前端使用方式 |
89
+ |---------|------|-------------|
90
+ | `{{module}}:{{entity}}:view` | 查看 | `v-hasPerm="'{{module}}:{{entity}}:view'"` |
91
+ | `{{module}}:{{entity}}:add` | 新增 | `v-hasPerm="'{{module}}:{{entity}}:add'"` |
92
+ | `{{module}}:{{entity}}:edit` | 修改 | `v-hasPerm="'{{module}}:{{entity}}:edit'"` |
93
+ | `{{module}}:{{entity}}:delete` | 删除 | `v-hasPerm="'{{module}}:{{entity}}:delete'"` |
94
+ | `{{module}}:{{entity}}:export` | 导出 | `v-hasPerm="'{{module}}:{{entity}}:export'"` |
95
+
96
+ ---
97
+
98
+ ## 5. 前端路由(参考)
99
+
100
+ > MES 项目使用动态路由:后端通过 `c_sys_resource` 返回路由配置,前端通过 `router.addRoutes()` 注册。
101
+ > 以下仅为参考,实际路由由后端 `GET /resource/listTreeByUser` 接口返回。
102
+
103
+ ```javascript
104
+ // 后端返回的路由数据结构(resources)
105
+ {
106
+ title: '{{moduleName}}',
107
+ path: '/{{domain}}/{{entity}}',
108
+ component: '{{domain}}/{{entity}}/index', // 前端 import.meta.glob 解析
109
+ icon: 'ios-folder',
110
+ permission: '{{module}}:{{entity}}:view',
111
+ }
112
+ ```
113
+
114
+ ---
115
+
116
+ ## 6. 刷新缓存
117
+
118
+ 执行 SQL 后,需要刷新 Redis 中的资源缓存:
119
+
120
+ ```bash
121
+ # 通过 API 刷新
122
+ curl -X GET http://localhost:8000/api/sys/resource/reloadCache \
123
+ -H "Authorization: Bearer <token>"
124
+ ```
125
+
126
+ > **注意**: 执行 SQL 前请先确认 `pid` 的值(根据实际父级菜单调整),菜单 ID 需确保全局唯一。
@@ -0,0 +1,64 @@
1
+ # MES CRUD 模块提案
2
+
3
+ ## 模块信息
4
+
5
+ | 配置项 | 值 |
6
+ |--------|-----|
7
+ | 模块名称 | {{moduleName}} |
8
+ | 所属业务中心 | modules-center/{{module}}-center |
9
+ | 后端包名 | com.twsz.mom.{{module}} |
10
+ | 前端域 | src/views/{{domain}}/ |
11
+
12
+ ## 核心实体
13
+
14
+ | 配置项 | 值 |
15
+ |--------|-----|
16
+ | 实体类名 | {{Entity}} |
17
+ | 表名 | {{table_name}} |
18
+ | 表注释 | {{table_comment}} |
19
+ | 描述 | {{description}} |
20
+
21
+ ## CRUD 操作
22
+
23
+ - [ ] 分页查询(POST /{{entity}}/search)
24
+ - [ ] 详情查询(GET /{{entity}}/get/{id})
25
+ - [ ] 新增(POST /{{entity}}/add)
26
+ - [ ] 修改(PUT /{{entity}}/update)
27
+ - [ ] 批量删除(DELETE /{{entity}}/delete)
28
+ - [ ] 不分页列表(POST /{{entity}}/list)
29
+ - [ ] Excel 导出(POST /{{entity}}/export)
30
+
31
+ ## 字段清单
32
+
33
+ | 字段名 | 数据库列名 | Oracle 类型 | Java 类型 | 必填 | 说明 |
34
+ |--------|-----------|-------------|-----------|------|------|
35
+ | id | id | NUMBER(19) | Long | 自动 | 主键(雪花算法,BaseModel 提供) |
36
+ | — | created_by | VARCHAR2(64) | String | 自动 | 创建人(TimeModel 提供) |
37
+ | — | created_date | TIMESTAMP | LocalDateTime | 自动 | 创建时间(TimeModel 提供) |
38
+ | — | last_updated_by | VARCHAR2(64) | String | 自动 | 更新人(TimeModel 提供) |
39
+ | — | last_updated_date | TIMESTAMP | LocalDateTime | 自动 | 更新时间(TimeModel 提供) |
40
+ | | | | | | |
41
+ | is_effect | is_effect | NUMBER(1) | Integer | 是 | 启用状态(1=启用, 0=停用) |
42
+
43
+ > 请补充业务字段。审计字段(created_by 等)和主键(id)由 BaseModel 自动提供,无需在 Entity 中声明。
44
+
45
+ ## 业务规则
46
+
47
+ 1.
48
+ 2.
49
+ 3.
50
+
51
+ ## 查询条件
52
+
53
+ | 字段 | 查询方式 | 说明 |
54
+ |------|---------|------|
55
+ | | LIKE / = / BETWEEN / IN | |
56
+
57
+ ## 非目标
58
+
59
+ - 不包含:
60
+
61
+ ## 关联模块
62
+
63
+ - 依赖:
64
+ - 被依赖:
@@ -0,0 +1,94 @@
1
+ # MES CRUD 接口规范: {{Entity}}
2
+
3
+ > 模块: {{module}} | 实体: {{Entity}} | 表: {{table_name}}
4
+
5
+ ## ADDED Requirements
6
+
7
+ ### API-001: 分页查询
8
+ 系统应当提供 `POST /{{entity}}/search` 接口,接收 `PageForm<{{Entity}}>` 请求体,返回分页结果。
9
+
10
+ **验收标准:**
11
+ - **Given** 数据库中存在 {{Entity}} 记录
12
+ - **When** 用户请求 `POST /{{entity}}/search`,请求体为 `{ "size": 20, "current": 1, "condition": {} }`
13
+ - **Then** 返回 `ResponseWrapper<Page<{{Entity}}>>`,包含 records 数组和 total 总数
14
+
15
+ ### API-002: 详情查询
16
+ 系统应当提供 `GET /{{entity}}/get/{id}` 接口。
17
+
18
+ **验收标准:**
19
+ - **Given** 存在 ID 为 1 的记录
20
+ - **When** 用户请求 `GET /{{entity}}/get/1`
21
+ - **Then** 返回 `ResponseWrapper<{{Entity}}>`,data 为该记录详情
22
+
23
+ ### API-003: 新增
24
+ 系统应当提供 `POST /{{entity}}/add` 接口,接收实体 JSON。
25
+
26
+ **验收标准:**
27
+ - **Given** 用户提供必填字段,请求体为合法的 {{Entity}} JSON
28
+ - **When** 用户请求 `POST /{{entity}}/add`
29
+ - **Then** 创建记录(雪花 ID 自动生成,审计字段自动填充),返回 `ResponseWrapper<String>` 成功
30
+
31
+ ### API-004: 修改
32
+ 系统应当提供 `PUT /{{entity}}/update` 接口。
33
+
34
+ **验收标准:**
35
+ - **Given** 存在待修改的记录
36
+ - **When** 用户请求 `PUT /{{entity}}/update`,请求体包含 id 和修改字段
37
+ - **Then** 更新记录(last_updated_by/last_updated_date 自动更新),返回 `ResponseWrapper<String>` 成功
38
+
39
+ ### API-005: 批量删除
40
+ 系统应当提供 `DELETE /{{entity}}/delete` 接口,接收 ID 数组。
41
+
42
+ **验收标准:**
43
+ - **Given** 存在待删除的记录
44
+ - **When** 用户请求 `DELETE /{{entity}}/delete`,请求体为 `[1, 2, 3]`
45
+ - **Then** 删除指定记录,返回 `ResponseWrapper<String>` 成功
46
+
47
+ ### API-006: 不分页列表
48
+ 系统应当提供 `POST /{{entity}}/list` 接口。
49
+
50
+ **验收标准:**
51
+ - **Given** 数据库中存在匹配记录
52
+ - **When** 用户请求 `POST /{{entity}}/list`
53
+ - **Then** 返回 `ResponseWrapper<List<{{Entity}}>>`(限制最多 10000 条)
54
+
55
+ ### API-007: Excel 导出
56
+ 系统应当提供 `POST /{{entity}}/export` 接口。
57
+
58
+ **验收标准:**
59
+ - **Given** 存在可导出的记录
60
+ - **When** 用户请求 `POST /{{entity}}/export`
61
+ - **Then** 返回 Excel 文件流(EasyExcel),文件名包含模块名
62
+
63
+ ---
64
+
65
+ ## 前端接口规范
66
+
67
+ ### FE-001: API 接口文件
68
+ 系统应当在 `src/api/{{domain}}/{{entity}}.js` 中封装以下方法:
69
+ - `search{{Entity}}(data)` — POST /{{entity}}/search
70
+ - `save{{Entity}}(data)` — POST /{{entity}}/add 或 PUT /{{entity}}/update(根据是否有 id 判断)
71
+ - `delete{{Entity}}(ids)` — DELETE /{{entity}}/delete
72
+ - `list{{Entity}}(data)` — POST /{{entity}}/list
73
+ - `export{{Entity}}(data)` — POST /{{entity}}/export
74
+
75
+ **验收标准:**
76
+ - **Given** API 文件已创建
77
+ - **When** 前端页面调用 API 方法
78
+ - **Then** 正确发送 HTTP 请求并返回 Promise
79
+
80
+ ### FE-002: 列表页
81
+ 系统应当在 `src/views/{{domain}}/{{entity}}/index.vue` 中实现列表页。
82
+
83
+ **验收标准:**
84
+ - **Given** 用户有查看权限
85
+ - **When** 用户访问列表页
86
+ - **Then** 展示搜索条件表单 + 数据表格 + 分页,支持新增/编辑/查看/删除/导出操作
87
+
88
+ ### FE-003: 表单页
89
+ 系统应当在 `src/views/{{domain}}/{{entity}}/{{entity}}-form.vue` 中实现表单页。
90
+
91
+ **验收标准:**
92
+ - **Given** 用户点击新增或编辑按钮
93
+ - **When** 表单页展示
94
+ - **Then** 展示可编辑表单,必填字段有验证规则,提交后返回列表
@@ -0,0 +1,208 @@
1
+ # MES CRUD 任务列表: {{Entity}}
2
+
3
+ ## 全局约束
4
+
5
+ - 后端: `modules-center/{{module}}-center/{{module}}-service/`
6
+ - 前端: `implat-ui/src/`
7
+ - 数据库: Oracle
8
+ - 分支: `feature/{{entity}}-crud`
9
+
10
+ ---
11
+
12
+ ## 后端任务
13
+
14
+ ### Task-001: 建表 SQL(Oracle)
15
+
16
+ - 文件: `sql/{{table_name}}.sql`
17
+ - 依赖: 无
18
+ - 描述: 创建数据库表,字段与提案中的字段清单对应
19
+ - 代码模板:
20
+
21
+ ```sql
22
+ CREATE TABLE {{table_name}} (
23
+ id NUMBER(19) NOT NULL,
24
+ -- 业务字段(根据提案补充)
25
+ is_effect NUMBER(1) DEFAULT 1,
26
+ created_by VARCHAR2(64) DEFAULT '',
27
+ created_date TIMESTAMP DEFAULT SYSTIMESTAMP,
28
+ last_updated_by VARCHAR2(64) DEFAULT '',
29
+ last_updated_date TIMESTAMP DEFAULT SYSTIMESTAMP,
30
+ CONSTRAINT pk_{{table_name}} PRIMARY KEY (id)
31
+ );
32
+ COMMENT ON TABLE {{table_name}} IS '{{table_comment}}';
33
+ ```
34
+
35
+ - 验证: SQL 可在 Oracle 客户端执行
36
+
37
+ ### Task-002: 创建 Entity 实体类
38
+
39
+ - 文件: `modules-center/{{module}}-center/{{module}}-service/src/main/java/com/twsz/mom/{{module}}/model/{{Entity}}.java`
40
+ - 依赖: Task-001
41
+ - 描述: 继承 `BaseModel`,声明业务字段。审计字段(createdBy 等)和主键(id)由 BaseModel 自动提供。
42
+ - 代码模板:
43
+
44
+ ```java
45
+ package com.twsz.mom.{{module}}.model;
46
+
47
+ import com.baomidou.mybatisplus.annotation.TableName;
48
+ import com.fasterxml.jackson.annotation.JsonInclude;
49
+ import com.twsz.mom.common.ds.model.BaseModel;
50
+ import lombok.Data;
51
+ import lombok.EqualsAndHashCode;
52
+
53
+ @Data
54
+ @EqualsAndHashCode(callSuper = true)
55
+ @JsonInclude(JsonInclude.Include.NON_NULL)
56
+ @TableName("{{table_name}}")
57
+ public class {{Entity}} extends BaseModel {
58
+ // 业务字段(审计字段由 BaseModel → TimeModel 提供)
59
+ private Integer isEffect;
60
+ // ... 根据提案中的字段清单补充
61
+ }
62
+ ```
63
+
64
+ - 验证: 编译通过
65
+
66
+ ### Task-003: 创建 Mapper 接口 + XML
67
+
68
+ - 文件:
69
+ - `modules-center/{{module}}-center/{{module}}-service/src/main/java/com/twsz/mom/{{module}}/mapper/{{Entity}}Mapper.java`
70
+ - `modules-center/{{module}}-center/{{module}}-service/src/main/resources/mapper/{{Entity}}Mapper.xml`
71
+ - 依赖: Task-002
72
+ - 描述: 继承 `BaseMapper<{{Entity}}>`,XML 包含标准的 Columns/Where/Joins 片段
73
+ - 代码模板(Mapper 接口):
74
+
75
+ ```java
76
+ package com.twsz.mom.{{module}}.mapper;
77
+
78
+ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
79
+ import com.baomidou.mybatisplus.core.metadata.IPage;
80
+ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
81
+ import com.twsz.mom.{{module}}.model.{{Entity}};
82
+ import org.apache.ibatis.annotations.Mapper;
83
+ import org.apache.ibatis.annotations.Param;
84
+ import java.util.List;
85
+
86
+ @Mapper
87
+ public interface {{Entity}}Mapper extends BaseMapper<{{Entity}}> {
88
+ IPage<{{Entity}}> pageSearch(Page<{{Entity}}> page, @Param("entity") {{Entity}} entity);
89
+ List<{{Entity}}> list(@Param("entity") {{Entity}} entity);
90
+ }
91
+ ```
92
+
93
+ - 代码模板(XML): 参见 design.md 中的标准 XML 模板
94
+ - 验证: 编译通过,namespace 与 Mapper 接口全限定名匹配
95
+
96
+ ### Task-004: 创建 Service 接口 + 实现
97
+
98
+ - 文件:
99
+ - `modules-center/{{module}}-center/{{module}}-service/src/main/java/com/twsz/mom/{{module}}/service/{{Entity}}Service.java`
100
+ - `modules-center/{{module}}-center/{{module}}-service/src/main/java/com/twsz/mom/{{module}}/service/impl/{{Entity}}ServiceImpl.java`
101
+ - 依赖: Task-003
102
+ - 描述: 继承 `IService<{{Entity}}>` / `ServiceImpl<Mapper, Entity>`,实现标准 CRUD 方法
103
+ - 代码模板: 参见 design.md 中的 Service 模板
104
+ - 验证: 编译通过
105
+
106
+ ### Task-005: 创建 Controller
107
+
108
+ - 文件: `modules-center/{{module}}-center/{{module}}-service/src/main/java/com/twsz/mom/{{module}}/controller/{{Entity}}Controller.java`
109
+ - 依赖: Task-004
110
+ - 描述: `@RestController`,`@RequestMapping("/{{entity}}")`,返回 `ResponseWrapper<T>`
111
+ - 代码模板: 参见 design.md 中的 Controller 模板
112
+ - 验证: 编译通过,启动后可访问接口
113
+
114
+ ---
115
+
116
+ ## 前端任务
117
+
118
+ ### Task-006: 创建 API 接口文件
119
+
120
+ - 文件: `implat-ui/src/api/{{domain}}/{{entity}}.js`
121
+ - 依赖: Task-005
122
+ - 描述: 封装 search/save/delete/list/export 五个标准方法
123
+ - 代码模板:
124
+
125
+ ```js
126
+ import axios from '@/libs/request'
127
+ import { exportExcel } from '../file'
128
+
129
+ const apiPrefix = '/{{entity}}'
130
+
131
+ const search{{Entity}} = data =>
132
+ axios.request({ url: `${apiPrefix}/search`, method: 'POST', data })
133
+
134
+ const save{{Entity}} = data => {
135
+ const url = data.id ? `${apiPrefix}/update` : `${apiPrefix}/add`
136
+ const method = data.id ? 'PUT' : 'POST'
137
+ return axios.request({ url, method, data })
138
+ }
139
+
140
+ const delete{{Entity}} = ids =>
141
+ axios.request({ url: `${apiPrefix}/delete`, method: 'DELETE', data: Array.isArray(ids) ? ids : [ids] })
142
+
143
+ const list{{Entity}} = data =>
144
+ axios.request({ url: `${apiPrefix}/list`, method: 'POST', data })
145
+
146
+ const export{{Entity}} = data =>
147
+ exportExcel(`${apiPrefix}/export`, data)
148
+
149
+ export default { search{{Entity}}, save{{Entity}}, delete{{Entity}}, list{{Entity}}, export{{Entity}} }
150
+ ```
151
+
152
+ - 验证: 无语法错误
153
+
154
+ ### Task-007: 创建列表页
155
+
156
+ - 文件: `implat-ui/src/views/{{domain}}/{{entity}}/index.vue`
157
+ - 依赖: Task-006
158
+ - 描述: 使用 `indexPage` mixin + `<search-table>` 组件,配置 option 对象和 tableColumns
159
+ - 代码模板: 参见 design.md 中的列表页模板
160
+ - 关键约定:
161
+ - `mixins: [indexPage]` — 提供 showIndexPage/add/edit/view/refresh/triggerBack
162
+ - `option.search.query` — 绑定 API search 方法
163
+ - `option.delete.method` — 绑定 API delete 方法
164
+ - `$t('key||中文')` — i18n 格式
165
+ - 验证: 页面可渲染,表格可加载数据
166
+
167
+ ### Task-008: 创建表单页
168
+
169
+ - 文件: `implat-ui/src/views/{{domain}}/{{entity}}/{{entity}}-form.vue`
170
+ - 依赖: Task-006
171
+ - 描述: 使用 `<master-sub>` 组件 + `BaseMixin`,实现新增/编辑表单
172
+ - 代码模板: 参见 design.md 中的表单页模板
173
+ - 关键约定:
174
+ - `mixins: [BaseMixin]` — 提供 loading/asyncLoading
175
+ - `this.$refs.mform.validate()` — 表单验证
176
+ - `this.$emit('on-success', data)` — 提交成功回调
177
+ - `class="form"` — 自动两列布局
178
+ - 验证: 表单验证生效,提交成功返回列表
179
+
180
+ ### Task-009: 菜单注册
181
+
182
+ - 文件: `sql/menu_{{entity}}.sql`
183
+ - 依赖: Task-008
184
+ - 描述: 向 `c_sys_resource` 表插入菜单和按钮权限记录
185
+ - 代码模板: 参见 menu-register.md
186
+ - 权限标识:
187
+ - `{{module}}:{{entity}}:view` — 查看
188
+ - `{{module}}:{{entity}}:add` — 新增
189
+ - `{{module}}:{{entity}}:edit` — 修改
190
+ - `{{module}}:{{entity}}:delete` — 删除
191
+ - `{{module}}:{{entity}}:export` — 导出
192
+ - 验证: 执行 SQL 后刷新缓存,菜单可见
193
+
194
+ ---
195
+
196
+ ## 任务依赖图
197
+
198
+ ```
199
+ Task-001 (建表)
200
+ └─ Task-002 (Entity)
201
+ └─ Task-003 (Mapper + XML)
202
+ └─ Task-004 (Service)
203
+ └─ Task-005 (Controller)
204
+ └─ Task-006 (API 接口)
205
+ ├─ Task-007 (列表页)
206
+ └─ Task-008 (表单页)
207
+ └─ Task-009 (菜单注册)
208
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@specpow/framework",
3
- "version": "0.5.21",
3
+ "version": "0.5.22",
4
4
  "description": "Spec-Powered AI Development Framework - 融合 OpenSpec 规范驱动 + Superpowers 执行引擎的企业级 AI 辅助编程框架",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",