骨架代码规范

This commit is contained in:
杨轩
2026-08-04 14:56:20 +08:00
parent 4637b17ca9
commit fcb30e1c69
15 changed files with 21027 additions and 16 deletions
+6 -12
View File
@@ -124,8 +124,7 @@
"cacheWrite": 0
},
"contextWindow": 131072,
"maxTokens": 32768,
"api": "openai-completions"
"maxTokens": 32768
},
{
"id": "deepseek-v4-pro",
@@ -141,8 +140,7 @@
"cacheWrite": 0
},
"contextWindow": 131072,
"maxTokens": 32768,
"api": "openai-completions"
"maxTokens": 32768
},
{
"id": "deepseek-v4-flash",
@@ -158,8 +156,7 @@
"cacheWrite": 0
},
"contextWindow": 131072,
"maxTokens": 8192,
"api": "openai-completions"
"maxTokens": 8192
},
{
"id": "glm-5.1",
@@ -176,8 +173,7 @@
"cacheWrite": 0
},
"contextWindow": 131072,
"maxTokens": 32768,
"api": "openai-completions"
"maxTokens": 32768
},
{
"id": "kim-k2.6",
@@ -193,8 +189,7 @@
"cacheWrite": 0
},
"contextWindow": 131072,
"maxTokens": 32768,
"api": "openai-completions"
"maxTokens": 32768
},
{
"id": "qwen3.5-plus",
@@ -211,8 +206,7 @@
"cacheWrite": 0
},
"contextWindow": 131072,
"maxTokens": 32768,
"api": "openai-completions"
"maxTokens": 32768
}
]
}
@@ -0,0 +1,26 @@
# OpenClaw exec shell snapshot. Generated; do not edit.
if [ -n "${BASH_VERSION:-}" ]; then shopt -s expand_aliases 2>/dev/null || true; fi
unalias -a 2>/dev/null || true
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'
command_not_found_handle ()
{
if [ -x /usr/lib/command-not-found ]; then
/usr/lib/command-not-found -- "$1";
return $?;
else
if [ -x /usr/share/command-not-found/command-not-found ]; then
/usr/share/command-not-found/command-not-found -- "$1";
return $?;
else
printf "%s: command not found\n" "$1" 1>&2;
return 127;
fi;
fi
}
export PATH='/root/.nvm/versions/node/v24.18.1/bin:/usr/bin:/bin:/usr/local/bin:/root/.nvm/current/bin:/root/.local/bin:/root/.npm-global/bin:/root/bin:/root/.nix-profile/bin:/root/.local/share/pnpm'
+1 -1
View File
@@ -8,7 +8,7 @@
"scopes": [
"operator.read"
],
"updatedAtMs": 1785744116242
"updatedAtMs": 1785811501091
}
}
}
+4
View File
@@ -18,5 +18,9 @@
"e93ec401ac152a24ac60f3949838de21": {
"sessionKey": "agent:frontend:main",
"updatedAt": 1783936175588
},
"8e26fa36080dd3394a28fafce9b531aa": {
"sessionKey": "agent:planner:main",
"updatedAt": 1785809107092
}
}
@@ -1,2 +1,2 @@
openclaw-workspace-attestation:v1
2026-08-03T08:31:43.211Z
2026-08-04T06:55:13.181Z
@@ -1,2 +1,2 @@
openclaw-workspace-attestation:v1
2026-08-03T07:49:18.452Z
2026-08-04T05:33:45.985Z
@@ -1,2 +1,2 @@
openclaw-workspace-attestation:v1
2026-08-03T08:31:12.922Z
2026-08-04T06:54:25.728Z
@@ -0,0 +1,455 @@
# MICA-Server 开发规范
> 本文档是 mica-server 项目的权威开发规范,所有开发人员必须严格遵守。
---
## 一、技术栈与版本
### 1.1 核心技术栈
| 类别 | 技术 | 版本 | 说明 |
|------|------|------|------|
| **JDK** | Java | 1.8 | 禁止使用 Java 9+ 特性 |
| **框架** | Spring Boot | 2.6.7 | 统一版本 |
| **ORM** | MyBatis-Plus | 3.5.1 | 禁止手写原生 SQL(除非性能优化) |
| **构建工具** | Maven | 3.6+ | 统一使用 Maven |
| **数据库** | MySQL | 8.0+ | HikariCP 连接池 |
| **注册/配置中心** | Nacos | 2.x | 服务注册与配置管理 |
### 1.2 工具库使用优先级
1. **优先使用**: `com.witsoft.common-utils` 中 utils 包封装的类和方法
2. **其次使用**: **Hutool** 工具库
3. **再次使用**: **Apache Commons** 系列
4. **禁止**: 重复造轮子
---
## 二、代码规范
### 2.1 命名规范
#### 类命名
- **类名**: UpperCamelCase 风格,必须为名词
- 正确:`UserController`, `UserService`
- 例外:领域模型 `DO`/`BO`/`DTO`/`VO` 等后缀
- **抽象类**: 使用 `Abstract``Base` 开头
- 例如:`AbstractService`, `BaseController`
- **异常类**: 使用 `Exception` 结尾
- 例如:`BizException`, `ValidationException`
- **测试类**: 以被测试类名开头,以 `Test` 结尾
- 例如:`UserServiceTest`
#### 方法和变量命名
- **方法名/变量名**: lowerCamelCase 风格
- 正确:`queryUserList`, `localName`, `getUserName`
- 禁止:拼音与英文混合、直接使用中文
- **Service/DAO 层方法前缀**:
- 获取单个/多个对象:`query` (如 `queryUser`, `queryUserList`)
- 插入:`insert``save` (如 `insertUser`, `saveOrder`)
- 删除:`delete``batchDelete` (如 `deleteUser`, `batchDeleteOrders`)
- 修改:`update` (如 `updateUser`, `updateOrderStatus`)
#### 常量命名
- **常量名**: UPPER_CASE_UNDERSCORE 风格,力求语义完整
- 正确:`MAX_USER_COUNT`, `DEFAULT_PAGE_SIZE`
- 禁止:不规范的缩写 (如 `AbsClass` 代替 `AbstractClass`)
- **常量类组织**: 按功能分类,禁止一个常量类维护所有常量
- 例如:`CacheConsts`, `ConfigConsts`, `UserConsts`
#### 包命名
- **包名**: 统一使用小写,点分隔符之间有且仅有一个单词
- 正确:`com.witsoft.mica.service`, `com.witsoft.util`
- 禁止:`com.witsoft.mica.services` (复数)
#### 其他命名规则
- **数组定义**: `String[] args` (中括号是数组类型的一部分)
- **布尔类型变量**: 禁止加 `is` 前缀 (避免序列化错误)
- 正确:`boolean success`, 方法名 `getSuccess()`
- 错误:`boolean isSuccess`, 方法名 `isSuccess()`
### 2.2 代码格式
#### 大括号使用
```java
// 空代码块
if (flag == 0) {}
// 非空代码块
if (flag == 1) {
System.out.println("world");
} else {
System.out.println("ok");
}
```
**规则**:
- 左大括号前不换行
- 左大括号后换行
- 右大括号前换行
- 右大括号后还有 `else` 等代码则不换行
- 右大括号表示终止则必须换行
#### 缩进与空格
- **缩进**: 4 个空格,禁止使用 tab 字符
- **单行字符数**: 不超过 200 个,超出需换行
- **运算符**: 左右必须有一个空格
- **关键词**: `if`/`for`/`while` 等与括号之间必须有一个空格
- **方法参数**: 多个参数逗号后必须加空格
- 例如:`method("aa", "bb", "cc")`
#### 换行规则
- 第二行相对第一行缩进 4 个空格,从第三行开始不再继续缩进
- 运算符与下文一起换行
- 方法调用的点符号与下文一起换行
- 多个参数超长时,逗号后换行
#### 文件编码
- **IDE 编码**: UTF-8
- **换行符**: Unix 格式 (LF),禁止使用 Windows 格式 (CRLF)
### 2.3 OOP 规约
1. **静态访问**: 直接用类名访问静态变量/方法,禁止通过对象引用访问
```java
// 正确
User user = UserService.getDefaultUser();
// 错误
User user = new UserService().getDefaultUser();
```
2. **覆写方法**: 必须加 `@Override` 注解
3. **可变参数**:
- 相同参数类型、相同业务含义才可使用
- 必须放置在参数列表最后
- 避免使用 `Object` 类型
```java
public User getUsers(String type, Integer... ids)
```
4. **接口签名**:
- 原则上不允许修改方法签名
- 接口过时必须加 `@Deprecated` 注解,并说明新接口
5. **equals 方法**: 使用常量或确定有值的对象调用
```java
// 正确
"test".equals(object);
// 错误
object.equals("test"); // 可能 NPE
```
6. **序列化**:
- 新增属性时不修改 `serialVersionUID`
- 完全不兼容升级时修改 `serialVersionUID`
7. **toString 方法**: POJO 类必须编写,继承的 POJO 需调用 `super.toString()`
### 2.4 注释规范
#### 类注释模板
```java
/**
* @menu : 类描述
* @Description : 类描述
* @ModifyBrief :
* @Author : git 账号
* @Date : 创建时间
* @Version : 3.0
* @Param :
* @Return :
*/
```
#### 方法注释模板
```java
/**
* @Description : 方法描述
* @ModifyBrief :
* @Author : git 账号
* @Date : 创建时间
* @Version : 3.0
* @Param : 参数说明
* @Return : 返回值说明
*/
```
#### 注释规则
1. **所有公共接口和类**必须包含 Javadoc
2. **注释语言**: 中文描述业务背景,技术术语保留英文 (如 NPE、DTO、API)
3. **禁止**生成 "Gets the value of X" 这类无意义的 getter/setter 注释
4. **复杂算法**必须在代码块上方解释核心逻辑
5. **禁止使用 HTML 标签**
6. **代码内注释**: 复杂逻辑必须包含行内注释,解释"为什么这样做"而非"做了什么"
7. **代码与注释比例**: 约 5:1,行注释使用 `// xxxxxx`
---
## 三、异常处理规范
### 3.1 异常捕获
1. **禁止**: 捕获 `Exception` 或 `Throwable` 后不做任何处理 (吞掉异常)
2. **规范**: 必须捕获具体的异常类
3. **日志**: 捕获异常时,调用 `GlobalException.getExceptionMessage(e)`
### 3.2 异常示例
```java
// 正确
try {
userService.queryUser(userId);
} catch (UserNotFoundException e) {
log.error("用户不存在:userId={}", userId, e);
throw new BizException("用户不存在");
}
// 错误 - 禁止吞掉异常
try {
userService.queryUser(userId);
} catch (Exception e) {
// 什么都不做
}
```
---
## 四、数据库规范
### 4.1 建表规约
#### 表名命名
- **不使用复数名词**
- **业务表前缀**: `mica_`
- **命名规则**: 小写字母或数字,下划线间隔
- 正确:`mica_user_info`, `mica_order_detail`
- 禁止:`mica_users`, `1_table`, `table__name`
#### 标准字段 (所有业务表必须包含)
| 字段名 | 类型 | 长度 | 是否 NULL | 主键 | 注释 |
|--------|------|------|-----------|------|------|
| `id` | varchar | 50 | 否 | 是 | 自然主键 |
| `ecid` | varchar | 100 | 否 | 否 | 企业编码 (多租户) |
| `create_time` | datetime | 3 | 是 | 否 | 创建时间 |
| `created_by` | varchar | 50 | 是 | 否 | 创建人 |
| `update_time` | datetime | 3 | 是 | 否 | 修改时间 |
| `updated_by` | varchar | 50 | 是 | 否 | 修改人 |
| `delete_time` | datetime | 3 | 是 | 否 | 删除时间 |
| `deleted_by` | varchar | 50 | 是 | 否 | 删除人 |
| `delete_mark` | tinyint | 1 | 默认 0 | 否 | 删除标志 0:未删除 1:已删除 |
#### 字段命名
- **小写字母或数字**,下划线间隔
- **禁止数字开头**
- **禁止两个下划线中间只有数字**
- **及时更新字段注释**: 修改字段含义或追加状态时
#### 索引命名
- **唯一索引**: `uk_字段名` (如 `uk_user_name`)
- **普通索引**: `idx_字段名` (如 `idx_create_time`)
#### 数据类型
- **小数**: 必须使用 `decimal`,禁止使用 `float` 和 `double`
- **字符串**:
- `varchar` 长度不超过 5000
- 超过 5000 使用 `text` 类型,独立成表,用主键对应
### 4.2 索引规约
1. **唯一特性字段**: 即使组合字段也必须建立唯一索引
2. **关联查询**: 超过 3 个表禁止 join,被关联字段必须有索引
3. **varchar 索引**: 必须指定索引长度 (一般 20 即可达到 90% 区分度)
### 4.3 SQL 规约
1. **COUNT 统计**: 使用 `count(*)`,禁止使用 `count(列名)` 或 `count(常量)`
2. **NULL 判断**: 使用 `ISNULL()` 函数
- `NULL <> NULL` 返回 `NULL`
- `NULL = NULL` 返回 `NULL`
3. **IN 操作**: 能避免则避免,可用 `EXISTS` 替换,集合元素控制在 1000 个内
4. **数据订正**: 删除/修改前先 `SELECT` 确认
### 4.4 ORM 规约
1. **查询字段**: 禁止使用 `*`,必须明确写明需要的字段
2. **参数传递**: 使用 `#{}`,禁止使用 `${}` (防止 SQL 注入)
3. **返回结果**: 禁止直接使用 `HashMap` 或 `Hashtable`
4. **更新接口**: 只更新有改动的字段,禁止全字段更新
5. **事务控制**:
- 不要滥用 `@Transactional`
- 考虑缓存回滚、消息补偿等回滚方案
---
## 五、统一响应格式
所有 Controller 层方法返回必须遵循以下 JSON 结构:
```json
{
"code": 200,
"msg": "操作成功",
"data": [],
"extra": {},
"success": true
}
```
---
## 六、项目结构规范
### 6.1 标准分层结构
```
com.witsoft.mica.xxx/
├── controller/ # REST 接口层
├── domain/ # DTO / VO / 查询参数
├── entity/ # 数据库实体 (DO)
├── mapper/ # MyBatis-Plus Mapper
└── service/ # 业务逻辑层
├── XxxService.java
└── impl/
└── XxxServiceImpl.java
```
### 6.2 各层职责
- **Controller**: 参数校验、调用 Service、返回统一响应
- **Service**: 业务逻辑、事务控制、数据填充
- **Mapper**: 数据持久化 (仅简单 CRUD,复杂查询用 XML)
- **Entity**: 数据库实体映射 (DO)
- **Domain**:
- DTO: 数据传输对象
- VO: 展示对象
- Query: 查询参数对象
---
## 七、开发注意事项
### 7.1 代码复用
1. **复用优先**: 逻辑雷同时提取公共方法,避免重复代码
2. **工具类优先**: 优先使用已有工具类方法
### 7.2 物料数据规范
1. **业务表仅存物料 id**: 物料相关字段仅存 `material_id`
2. **关联查询填充**: 编码、名称、规格、单位等通过关联查询填充
3. **填充在 Service 层**: 关联数据填充逻辑统一在 Service 层处理
### 7.3 字典使用
1. **优先使用 DictService**: 字典取值优先使用 `DictService` 公共方法
2. **禁止手写**: 不手写字典查询逻辑
### 7.4 Java 8 兼容性
1. **禁止 List.of()**: Java 8 不兼容
2. **使用**: `Collections.emptyList()` 替代
### 7.5 版本管理
1. **首个版本直接改 DDL**: v1.0 脚本直接修改建表语句
2. **不需要 ALTER TABLE**: 初始版本不需要写迁移脚本
---
## 八、Git 提交约定
### 8.1 提交规范
1. **禁止 Agent commit**: Agent 不做任何 commit 操作,只允许查看、修改代码
2. **Commit Message**: 提示 commit 时必须附带 commit message,让用户可直接复制运行
3. **用户手动提交**: 如需提交代码,由用户手动执行 commit
### 8.2 配置文件
- **`application.yml` / `application-local.yml`**: 由用户自行提交
- **Agent 绝不碰**: 这两个配置文件的版本管理
---
## 九、部署约定
### 9.1 部署规范
1. **禁止自动部署**: Agent 不做任何自动部署操作
2. **用户手动决定**: 代码修改后由用户手动决定何时部署
### 9.2 数据库脚本管理
所有数据库脚本必须按顺序编号,并在 MEMORY.md 中记录执行状态:
```
✅ 00-init.sql - 基础表结构
✅ 10-system.sql - 系统数据
✅ 20-master-data-init.sql - 基础数据
...
```
---
## 十、物料近似查询规范 (2026-05-29 产品决策)
### 10.1 searchSimilar() 优先级
产品决定**不查询规格字段**,按以下优先级分步查询:
1. **名称精确匹配** (`material_name = keyword`) — 优先级最高
2. **名称前缀匹配** (`material_name LIKE 'keyword%'`)
3. **名称模糊匹配** (`material_name LIKE '%keyword%'`)
4. **编码模糊匹配** (`material_code LIKE '%keyword%'`) — 兜底
### 10.2 去重原则
已在前置层级匹配的物料不再在后置层级重复出现。
### 10.3 旧方法保留
保留旧 `searchByNameLike()` 方法不动,保持向后兼容。
---
## 附录:快速参考
### 命名速查表
| 类型 | 规范 | 示例 |
|------|------|------|
| 类名 | UpperCamelCase | `UserController` |
| 方法名 | lowerCamelCase | `queryUserList` |
| 变量名 | lowerCamelCase | `userName` |
| 常量名 | UPPER_CASE_UNDERSCORE | `MAX_COUNT` |
| 包名 | 小写单数 | `com.witsoft.util` |
| 表名 | 小写 + 下划线 | `mica_user_info` |
| 字段名 | 小写 + 下划线 | `user_name` |
| 唯一索引 | `uk_字段名` | `uk_user_name` |
| 普通索引 | `idx_字段名` | `idx_create_time` |
### Service 方法前缀速查
| 操作 | 前缀 | 示例 |
|------|------|------|
| 查询单个 | `query` | `queryUser` |
| 查询列表 | `query` | `queryUserList` |
| 插入 | `insert`/`save` | `insertUser` |
| 删除 | `delete` | `deleteUser` |
| 批量删除 | `batchDelete` | `batchDeleteUsers` |
| 更新 | `update` | `updateUser` |
---
**版本**: 1.0
**最后更新**: 2026-08-04
**维护者**: 后端开发团队
+55
View File
@@ -62,6 +62,61 @@
- 在更改配置或调度器之前(如 crontab、systemd 单元、nginx 配置、shell rc 文件),先检查现有状态,默认保留/合并。
- `trash` > `rm`(可恢复优于永久删除)
- 有疑问时,先询问。
- **禁止擅自提交项目代码到 git** - 必须先询问用户确认后再提交
---
## 🏗️ mica 项目开发规范
### SMDM 物料管理模块 - 开发限制
**🔴 强制性红线** (违反即停止,详细规范见 `MEMORY.md``memory/2026-08-04.md`)
| # | 红线 | 违规示例 | 正确做法 |
|---|------|---------|----------|
| 1 | **表前缀必须过滤** | `DmpMdItemInfo` | `ItemInfo` |
| 2 | **API 必须放在 apis.smdm 包** | `smd.api.ItemApi` | `apis.smdm.ItemApi` |
| 3 | **查询只能用 Mapper** | 使用 MyBatis-Plus | 原生 MyBatis XML |
| 4 | **改删必须 Feign 远程调用** | 本地直接 UPDATE/DELETE | 调用 SMDM 服务 API |
| 5 | **实体必须继承 BaseDomain** | 独立定义审计字段 | `extends BaseDomain` |
| 6 | **只使用指定 13 个业务字段** | 添加表中其他字段 | 仅用规范内字段 |
| 7 | **代码必须生成到 smd 目录** | `com.witsoft.mica.item.*` | `com.witsoft.mica.smd.*` |
**📋 核心规范摘要**:
- **包路径**: `com.witsoft.mica.smd.*` (本地业务), `com.witsoft.mica.apis.smdm.*` (Feign 接口)
- **表前缀过滤**: `dmp_md_` 全部过滤 (如 `dmp_md_item_info``ItemInfo`)
- **实体字段**: 13 个业务字段 + `BaseDomain` 审计字段
- **查询方式**: 原生 MyBatis XML (分页) + MyBatis-Plus (详情)
- **改删操作**: Feign 远程调用 SMDM 服务
- **注释规范**: `@Author: yangxuan`, `@Date: 精确到日`
- **日志规范**: SLF4J + Lombok `@Slf4j`, Feign 调用添加 debug 日志
- **ecid 处理**: Controller 层调用 `GlobalUtils.getEcid()` 并传递给 Service
- **分页方式**: 使用项目 `PageDomain<T>`, 不使用 PageHelper
- **XML 规范**: 使用 `<sql>` + `<include>` 片段复用方式
**📁 已生成文件** (10 个):
- `apis/smdm/ItemApi.java` - Feign 接口
- `smd/entity/ItemInfo.java` - 实体类
- `smd/mapper/ItemMapper.java` + `ItemMapper.xml` - MyBatis 映射
- `smd/service/ItemService.java` + `impl/ItemServiceImpl.java` - 服务层
- `smd/controller/ItemController.java` - 控制器
- `smd/dto/ItemQueryDTO.java` + `ItemFormDTO.java` - DTO
- `smd/vo/ItemVO.java` - VO
**🐛 已修正问题** (12 个):
1. ResponseModel 静态引用 → `ResponseModel.succeed(data)`
2. 分页 XML / 详情 MP 混合使用
3. 移除编码查询条件
4. Feign 调用添加 debug 日志
5. Controller 层 ecid 处理
6. 恢复分页 XML 查询
7. 使用 PageDomain (非 PageHelper)
8. 删除 queryByCode 方法
9. ResponseModel 泛型参数化
10. Map 类型转换警告
11. XML 使用 `<sql>` + `<include>` 片段
12. ItemApi ResponseModel 泛型
---
+56
View File
@@ -27,3 +27,59 @@
- **前端项目:** `mica-web`
- **后端项目:** `mica-server`
- **项目文档:** `mica-doc`
---
## 🏗️ mica 项目开发规范
### SMDM 物料管理模块 - 开发限制 (2026-08-04)
**🔴 强制性红线** (违反即停止,详细规范见 `memory/2026-08-04.md`)
| # | 红线 | 违规示例 | 正确做法 |
|---|------|---------|----------|
| 1 | **表前缀必须过滤** | `DmpMdItemInfo` | `ItemInfo` |
| 2 | **API 必须放在 apis.smdm 包** | `smd.api.ItemApi` | `apis.smdm.ItemApi` |
| 3 | **查询只能用 Mapper** | 使用 MyBatis-Plus | 原生 MyBatis XML |
| 4 | **改删必须 Feign 远程调用** | 本地直接 UPDATE/DELETE | 调用 SMDM 服务 API |
| 5 | **实体必须继承 BaseDomain** | 独立定义审计字段 | `extends BaseDomain` |
| 6 | **只使用指定 13 个业务字段** | 添加表中其他字段 | 仅用规范内字段 |
| 7 | **代码必须生成到 smd 目录** | `com.witsoft.mica.item.*` | `com.witsoft.mica.smd.*` |
**📋 核心规范摘要**:
- **包路径**: `com.witsoft.mica.smd.*` (本地业务), `com.witsoft.mica.apis.smdm.*` (Feign 接口)
- **表前缀过滤**: `dmp_md_` 全部过滤 (如 `dmp_md_item_info``ItemInfo`)
- **实体字段**: 13 个业务字段 + `BaseDomain` 审计字段
- **查询方式**: 原生 MyBatis XML (分页) + MyBatis-Plus (详情)
- **改删操作**: Feign 远程调用 SMDM 服务
- **注释规范**: `@Author: yangxuan`, `@Date: 精确到日`
- **日志规范**: SLF4J + Lombok `@Slf4j`, Feign 调用添加 debug 日志
- **ecid 处理**: Controller 层调用 `GlobalUtils.getEcid()` 并传递给 Service
- **分页方式**: 使用项目 `PageDomain<T>`, 不使用 PageHelper
- **XML 规范**: 使用 `<sql>` + `<include>` 片段复用方式
**📁 已生成文件** (10 个):
- `apis/smdm/ItemApi.java` - Feign 接口
- `smd/entity/ItemInfo.java` - 实体类
- `smd/mapper/ItemMapper.java` + `ItemMapper.xml` - MyBatis 映射
- `smd/service/ItemService.java` + `impl/ItemServiceImpl.java` - 服务层
- `smd/controller/ItemController.java` - 控制器
- `smd/dto/ItemQueryDTO.java` + `ItemFormDTO.java` - DTO
- `smd/vo/ItemVO.java` - VO
**🐛 已修正问题** (12 个):
1. ResponseModel 静态引用 → `ResponseModel.succeed(data)`
2. 分页 XML / 详情 MP 混合使用
3. 移除编码查询条件
4. Feign 调用添加 debug 日志
5. Controller 层 ecid 处理
6. 恢复分页 XML 查询
7. 使用 PageDomain (非 PageHelper)
8. 删除 queryByCode 方法
9. ResponseModel 泛型参数化
10. Map 类型转换警告
11. XML 使用 `<sql>` + `<include>` 片段
12. ItemApi ResponseModel 泛型
---
+91
View File
@@ -0,0 +1,91 @@
# dmp_smdm 数据库结构备份
**备份日期:** 2026-08-03
**数据库:** dmp_smdm (主数据管理)
**备份方式:** `SHOW CREATE TABLE`(推荐,可完整还原表结构)
## 备份文件说明
| 文件名 | 大小 | 内容 | 行数 | 用途 |
|--------|------|------|------|------|
| `dmp_smdm_create_tables_2026-08-03.sql` | 247K | 128 张表的完整 CREATE TABLE 语句 | 3084 | ✅ **可直接导入恢复** |
| `dmp_smdm_schema_2026-08-03.csv` | 163K | 所有表的字段详细信息 | 2138 | 查阅/程序处理 |
| `dmp_smdm_indexes_2026-08-03.csv` | 12K | 所有表的索引信息 | 236 | 查阅/程序处理 |
| `dmp_smdm_tables_2026-08-03.csv` | 5.0K | 表名及注释 | 129 | 快速浏览 |
## 推荐备份方式
**`SHOW CREATE TABLE` 优势:**
- ✅ 完整的建表语句(包含字段、类型、注释、索引、引擎、字符集)
- ✅ 可直接导入 MySQL 恢复表结构
- ✅ 只需要 SELECT 权限(当前用户可用)
- ✅ 格式标准,易于版本管理
**CSV 方式劣势:**
- ❌ 无法直接导入恢复
- ❌ 需要手动编写 CREATE TABLE 语句
- ❌ 索引信息分离,容易遗漏
## 恢复方法
### 方式一:直接导入 SQL 文件(推荐)
```bash
# 连接到目标数据库
mysql -h <host> -P <port> -u <user> -p <database> < dmp_smdm_create_tables_2026-08-03.sql
```
### 方式二:查看单个表结构
```bash
# 查看指定表的建表语句
cat dmp_smdm_create_tables_2026-08-03.sql | grep -A 100 "Table: dmp_md_item_info" | head -80
```
### 方式三:从 CSV 查询
```bash
# 查看某个表的完整字段
cat dmp_smdm_schema_2026-08-03.csv | grep "dmp_md_item_info"
# 查看某个表的所有索引
cat dmp_smdm_indexes_2026-08-03.csv | grep "dmp_md_item_info"
```
## 用户权限说明
**当前用户:** `witsoftd`
**权限级别:** 只读
| 权限 | 状态 | 说明 |
|------|------|------|
| SELECT | ✅ | 可查询数据 |
| SHOW DATABASES | ✅ | 可查看数据库列表 |
| SHOW VIEW | ✅ | 可查看视图定义 |
| SHOW CREATE TABLE | ✅ | 可查看建表语句 |
| INSERT/UPDATE/DELETE | ❌ | 无法修改数据 |
| CREATE/ALTER/DROP | ❌ | 无法修改结构 |
| PROCESS/LOCK TABLES | ❌ | 无法使用 mysqldump |
## 注意事项
- ⚠️ 数据库用户 `witsoftd` 为只读账号
-`SHOW CREATE TABLE` 可正常使用(只需 SELECT 权限)
- ✅ 建议定期更新此备份(每周/每月)
- 📁 备份文件位置:`/root/.openclaw/workspace-planner/backups/`
## 备份其他数据库
```bash
# 备份 dmp_serp
mysql -h 47.99.209.185 -P 50036 -u witsoftd -p'o2byaCkBvF1Y8S2L' -N -e \
"SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA='dmp_serp'" dmp_serp | \
while read table; do
echo "-- Table: $table"
mysql -h 47.99.209.185 -P 50036 -u witsoftd -p'o2byaCkBvF1Y8S2L' \
-e "SHOW CREATE TABLE \`dmp_serp\`.\`$table\`\G" dmp_serp 2>/dev/null
echo ""
> dmp_serp_create_tables.sql
# 备份 dmp_smes / dmp_spom 同理
```
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+392
View File
@@ -0,0 +1,392 @@
# 2026-08-04 工作日志
## mica 项目 - SMDM 物料管理模块开发规范
### 🔴 强制性红线 (违反即停止)
| # | 红线 | 违规示例 | 正确做法 |
|------|---------|----------|----------|
| 1 | **表前缀必须过滤** | `DmpMdItemInfo` | `ItemInfo` |
| 2 | **API 必须放在 apis.smdm 包** | `smd.api.ItemApi` | `apis.smdm.ItemApi` |
| 3 | **查询只能用 Mapper** | 使用 MyBatis-Plus | 原生 MyBatis XML |
| 4 | **改删必须 Feign 远程调用** | 本地直接 UPDATE/DELETE | 调用 SMDM 服务 API |
| 5 | **实体必须继承 BaseDomain** | 独立定义审计字段 | `extends BaseDomain` |
| 6 | **只使用指定 13 个业务字段** | 添加表中其他字段 | 仅用规范内字段 |
| 7 | **代码必须生成到 smd 目录** | `com.witsoft.mica.item.*` | `com.witsoft.mica.smd.*` |
---
### 📋 已确认的开发规范
#### 1. 包路径规范
- **代码生成目录**: `/root/projects/wit/mica-server/src/main/java/com/witsoft/mica/smd/`
- **包前缀**: `com.witsoft.mica.smd`
- **API 包路径**: `com.witsoft.mica.apis.smdm`
- **子包结构**:
```
smd/
├── controller/ # 控制器层
├── service/ # 服务层接口
├── service/impl/ # 服务层实现
├── mapper/ # MyBatis Mapper 接口
├── entity/ # 数据库实体类
├── dto/ # 数据传输对象
└── vo/ # 视图对象
```
#### 2. 表名前缀过滤规则
- **过滤前缀**: `dmp_md_`
- **示例**:
- `dmp_md_item_info``ItemInfo`
- `dmp_md_xxx``Xxx`
#### 3. 实体类规范
- **基础字段** (业务必需):
| 字段说明 | 数据库字段 | Java 字段 |
|---------|-----------|----------|
| 物料编码 | `item_code` | `itemCode` |
| 物料名称 | `item_name` | `itemName` |
| 规格型号 | `item_spec` | `itemSpec` |
| 物料类型 | `item_type` | `itemType` |
| 物料分类 | `item_categorys_code` | `itemCategorysCode` |
| 物料属性 | `properties` | `properties` |
| 主单位 | `unit_code` | `unitCode` |
| 辅单位 | `assist_unit_code` | `assistUnitCode` |
| 物料描述 | `item_desc` | `itemDesc` |
| 供应商 | `vendor_code` | `vendorCode` |
| 默认仓库 | `good_warehouse` | `goodWarehouse` |
| 批次控制 | `batch_control` | `batchControl` (默认 0/关) |
| 领料属性 | `picking_property` | `pickingProperty` (默认 AD/按单领料) |
| 状态 | `status` | `status` |
- **审计字段** (继承 `BaseDomain`):
```java
import com.witsoft.gen.base.BaseDomain;
public class ItemInfo extends BaseDomain {
// 业务字段...
}
```
- `id`, `ecid`, `createdBy`, `createTime`, `updatedBy`, `updateTime`
#### 4. 数据访问规范
- **查询权限**: 仅有数据库查询权限
- **查询方式**: 使用原生 MyBatis Mapper**不使用 MyBatis-Plus**
- **修改/删除**: 通过 Feign 远程调用 SMDM 服务
#### 5. 架构模式
```
mica-server (本地) smdm (远程服务)
│ │
├── Controller │
├── Service │
├── Mapper ──(查询)──→ 数据库
└── Feign Api ──(改删)──→ WorkshopApi 模式
```
#### 6. Feign 远程调用模式
**API 包路径**: `com.witsoft.mica.apis.smdm`
参考现有 `WorkshopApi`:
```java
@FeignClient(name = "smdm", path = "/smdm/smd/web/workshop")
public interface WorkshopApi {
@PostMapping("/getListPage")
ResponseModel queryWorkshopPageList(@RequestBody Map<String, Object> workshop);
@PostMapping("/create")
ResponseModel insertWorkshop(@RequestBody Map<String, Object> workshop);
}
```
---
## 📝 注释与日志规范
### 1. 类注释 (Javadoc 风格)
参考现有 `WorkshopController.java`:
```java
/**
* @Description : 物料信息管理
* @ModifyBrief :
* @Author : yangxuan
* @Date : 2026/8/4
* @Version : 1.0
*/
```
**规范**:
- `@Author` 固定为 `yangxuan`
- `@Date` 精确到日 (`2026/8/4`)
- `@ModifyBrief` 留空,后续修改时补充
### 2. 方法注释
```java
/**
* @Description : 物料信息列表分页查询
* @ModifyBrief :
* @Author : yangxuan
* @Date : 2026/8/4
* @Version : 1.0
* @Param : itemQueryDTO
* @Return : PageDomain<ItemVO>
*/
```
**规范**:
- 公共接口方法必须添加方法注释
- 私有方法可选添加
- `@Author` 固定为 `yangxuan`
### 3. 日志规范
**框架**: SLF4J + Lombok `@Slf4j`
**使用场景**:
- 请求入口:`log.info("物料查询请求:itemCode={}", dto.getItemCode())`
- 异常捕获:`log.error("物料查询失败", e)`
- 关键业务节点:`log.info("物料创建成功:itemCode={}", result.getItemCode())`
- Feign 调用:`log.debug("Feign 调用 - 创建物料,入参:{}", JsonUtils.toJson(dto))`
**示例**:
```java
@Slf4j
@RestController
public class ItemController {
public ResponseModel<PageDomain<ItemVO>> queryPageList(@RequestBody ItemQueryDTO dto) {
log.info("物料查询请求:ecid={}", dto.getEcid());
try {
return itemService.queryPageList(dto);
} catch (Exception e) {
log.error("物料查询失败", e);
return ResponseModel.failed("查询失败");
}
}
}
```
### 4. 字段注释
单行注释即可:
```java
/** 物料编码 */
private String itemCode;
/** 物料名称 */
private String itemName;
```
---
## 🐛 已修正的问题清单 (1-12)
以下问题在开发过程中发现并已修正,**后续开发必须遵守**:
| # | 问题 | 修正方案 | 涉及文件 |
|---|------|----------|----------|
| 1 | **ResponseModel 静态引用错误** | 使用 `ResponseModel.succeed(data)` 静态方法 | `ItemController.java`, `ItemServiceImpl.java` |
| 2 | **分页 XML / 详情 MP 混合使用** | 分页查询用原生 XML,详情查询用 `BaseMapper.selectById` | `ItemMapper.xml`, `ItemServiceImpl.java` |
| 3 | **移除编码查询条件** | 从 DTO 和 XML 移除 `itemCode` 模糊搜索 | `ItemQueryDTO.java`, `ItemMapper.xml` |
| 4 | **Feign 调用添加日志** | debug 级别:入参 + 耗时 + 返回 | `ItemServiceImpl.java` |
| 5 | **Controller 层 ecid 处理** | `GlobalUtils.getEcid()` 在 Controller 层获取并传递给 Service | `ItemController.java` |
| 6 | **恢复分页 XML 查询** | 保留完整的分页查询 SQL | `ItemMapper.xml` |
| 7 | **使用 PageDomain (非 PageHelper)** | 手动分页:先 count 查询总数,再 LIMIT 查询数据 | `ItemServiceImpl.java` |
| 8 | **删除 queryByCode 方法** | 删除所有 `queryByCode` 相关代码 | `ItemMapper.java`, `ItemService.java`, `ItemController.java` |
| 9 | **ResponseModel 泛型参数化** | 所有返回类型使用 `ResponseModel<T>` | `ItemController.java`, `ItemServiceImpl.java` |
| 10 | **Map 类型转换警告** | 使用 `Convert.convert(Map.class, dto)``@SuppressWarnings` | `ItemController.java`, `ItemServiceImpl.java` |
| 11 | **XML 使用 `<sql>` + `<include>` 片段** | 公共列定义和查询条件使用 SQL 片段复用 | `ItemMapper.xml` |
| 12 | **ItemApi ResponseModel 泛型** | Feign 接口返回 `ResponseModel<Void>` | `ItemApi.java` |
---
### 问题 1 详解:ResponseModel 静态引用
**错误**:
```java
return ResponseModel.success(result); // ❌ success 不是静态方法
```
**正确**:
```java
return ResponseModel.succeed(result); // ✅ 使用静态方法 succeed
```
---
### 问题 2 详解:分页 XML / 详情 MP
**分页查询** (原生 XML):
```java
// ItemMapper.xml
<select id="queryPageList" resultType="com.witsoft.mica.smd.vo.ItemVO">
SELECT <include refid="selectItemColumns"/>
FROM dmp_md_item_info t
<include refid="queryConditions"/>
ORDER BY t.create_time DESC
LIMIT #{dto.pageNo}, #{dto.pageSize}
</select>
```
**详情查询** (MyBatis-Plus):
```java
// ItemServiceImpl.java
ItemInfo item = itemMapper.selectById(id);
```
---
### 问题 5 详解:Controller 层 ecid 处理
**Controller**:
```java
@PostMapping("/getPageList")
public ResponseModel<PageDomain<ItemVO>> queryPageList(@RequestBody ItemQueryDTO dto) {
String ecid = GlobalUtils.getEcid();
dto.setEcid(ecid);
log.info("物料查询请求:ecid={}", ecid);
return itemService.queryPageList(dto);
}
```
**Service** (直接使用传入的 ecid):
```java
@Override
public PageDomain<ItemVO> queryPageList(ItemQueryDTO dto) {
// 直接使用 dto.getEcid(),不再自己获取
List<ItemVO> list = itemMapper.queryPageList(dto);
// ...
}
```
---
### 问题 7 详解:使用 PageDomain
**Service 手动分页**:
```java
@Override
public PageDomain<ItemVO> queryPageList(ItemQueryDTO dto) {
int pageNo = dto.getPageNo() != null ? dto.getPageNo() : 1;
int pageSize = dto.getPageSize() != null ? dto.getPageSize() : 10;
// 查询总数
long total = itemMapper.queryPageCount(dto);
// 查询分页数据
List<ItemVO> list = itemMapper.queryPageList(dto);
// 构建 PageDomain
PageDomain<ItemVO> page = new PageDomain<>(pageNo, pageSize, total);
page.setList(list);
return page;
}
```
---
### 问题 11 详解:XML SQL 片段
**ItemMapper.xml**:
```xml
<mapper namespace="com.witsoft.mica.smd.mapper.ItemMapper">
<!-- 公共列定义 -->
<sql id="selectItemColumns">
t.id, t.ecid, t.item_code, t.item_name, t.item_spec, t.item_type,
t.item_categorys_code, t.properties, t.unit_code, t.assist_unit_code,
t.item_desc, t.vendor_code, t.good_warehouse, t.batch_control,
t.picking_property, t.status, t.create_time, t.created_by,
t.update_time, t.updated_by
</sql>
<!-- 公共查询条件 -->
<sql id="queryConditions">
<where>
<if test="dto.ecid != null and dto.ecid != ''">
AND t.ecid = #{dto.ecid}
</if>
<if test="dto.itemName != null and dto.itemName != ''">
AND t.item_name LIKE CONCAT('%', #{dto.itemName}, '%')
</if>
<if test="dto.itemType != null and dto.itemType != ''">
AND t.item_type = #{dto.itemType}
</if>
<if test="dto.status != null and dto.status != ''">
AND t.status = #{dto.status}
</if>
</where>
</sql>
<!-- 分页查询 -->
<select id="queryPageList" resultType="com.witsoft.mica.smd.vo.ItemVO">
SELECT
<include refid="selectItemColumns"/>
FROM dmp_md_item_info t
<include refid="queryConditions"/>
ORDER BY t.create_time DESC
LIMIT #{dto.pageNo}, #{dto.pageSize}
</select>
<!-- 总数查询 -->
<select id="queryPageCount" resultType="long">
SELECT COUNT(*)
FROM dmp_md_item_info t
<include refid="queryConditions"/>
</select>
</mapper>
```
---
## 📁 后端完整文件清单 (10 个)
| # | 文件 | 路径 | 状态 |
|---|------|------|------|
| 1 | `ItemApi.java` | `apis/smdm/` | ✅ 已写入 |
| 2 | `ItemInfo.java` | `smd/entity/` | ✅ 已写入 |
| 3 | `ItemMapper.java` | `smd/mapper/` | ✅ 已写入 |
| 4 | `ItemMapper.xml` | `resources/mapper/smd/` | ✅ 已写入 |
| 5 | `ItemService.java` | `smd/service/` | ✅ 已写入 |
| 6 | `ItemServiceImpl.java` | `smd/service/impl/` | ✅ 已写入 |
| 7 | `ItemController.java` | `smd/controller/` | ✅ 已写入 |
| 8 | `ItemQueryDTO.java` | `smd/dto/` | ✅ 已写入 |
| 9 | `ItemFormDTO.java` | `smd/dto/` | ✅ 已写入 |
| 10 | `ItemVO.java` | `smd/vo/` | ✅ 已写入 |
---
## 📝 待办事项
### Backend (mica-server)
- [x] 创建 `apis/smdm/ItemApi.java` (Feign 接口)
- [x] 创建 `smd/entity/ItemInfo.java`
- [x] 创建 `smd/mapper/ItemMapper.java`
- [x] 创建 `smd/mapper/ItemMapper.xml`
- [x] 创建 `smd/service/ItemService.java`
- [x] 创建 `smd/service/impl/ItemServiceImpl.java`
- [x] 创建 `smd/controller/ItemController.java`
- [x] 创建 `smd/dto/ItemQueryDTO.java`
- [x] 创建 `smd/dto/ItemFormDTO.java`
- [x] 创建 `smd/vo/ItemVO.java`
### Frontend (mica-web)
- [ ] 创建物料管理 API 封装 (`app/composables/smd/useItemApi.ts`)
- [ ] 创建物料列表页面 (`app/pages/smd/item/index.vue`)
- [ ] 创建物料详情/编辑表单 (`app/pages/smd/item/form.vue`)
- [ ] 创建物料详情页面 (`app/pages/smd/item/detail.vue`)
- [ ] 更新路由配置
---
## 🔗 相关资源
- 数据库:`dmp_smdm.dmp_md_item_info`
- 连接:`mysql -h 47.99.209.185 -P 50036 -u witsoftd -p mica`
- 项目路径:`/root/projects/wit/`
- 规范文档:`/root/.openclaw/workspace-planner/memory/2026-08-04.md`