初始代码
This commit is contained in:
887
yawei-mes/.tasks/2026-03-05_v2.0.003_报工单页面类别与字段控制.md
Normal file
887
yawei-mes/.tasks/2026-03-05_v2.0.003_报工单页面类别与字段控制.md
Normal file
@@ -0,0 +1,887 @@
|
||||
# 报工单页面类别与字段控制设计文档
|
||||
|
||||
**版本:** v2.0.003
|
||||
**日期:** 2026-03-05
|
||||
**负责人:** 周启威
|
||||
|
||||
---
|
||||
|
||||
## 需求整理
|
||||
|
||||
### 原始需求
|
||||
|
||||
1. **报工单中分了 ABCDE 五类**,能否在新增/编辑的时候把五类中任一一类停用,然后写一个配置表、页面上一个按钮可以控制五个类别的停用与启用
|
||||
|
||||
2. **报工单中分了 ABCDE 五类**,在这五类中的字段命名/增删改查能不能也放入配置表,五类中的字段也需要控制与自定义,现在目前程序中现有的字段也需要控制与自定义了
|
||||
|
||||
3. **规则**:停用/启用 对应的是 隐藏/显示,只要是停用就隐藏该字段
|
||||
|
||||
4. **数据类型也需要自定义**,然后控件类型也需要自定义
|
||||
|
||||
5. **分类也可以自己增加并修改**,我新增的自定义字段应该可以指定进入任一分类中
|
||||
|
||||
6. **ABCDE 的话还是自动排吧**,比如我 C 停用了,应该 D→C, E→D,默认是这样的,但是也可以自定义
|
||||
|
||||
### 需求总结
|
||||
|
||||
#### 一、类别管理需求
|
||||
|
||||
1. **系统类别(A/B/C/D/E)**:
|
||||
- 可以停用/启用(停用=隐藏)
|
||||
- 可以修改类别名称
|
||||
- 不可删除
|
||||
- 支持名称重置为默认值
|
||||
|
||||
2. **自定义类别(F/G/H...)**:
|
||||
- 可以新增自定义类别
|
||||
- 可以修改类别名称
|
||||
- 可以删除(删除前需确认该类别下无字段)
|
||||
- 可以停用/启用
|
||||
|
||||
3. **类别排序**:
|
||||
- 支持手动调整排序(拖拽或上下移动)
|
||||
- 前端显示时,启用的类别自动重新编号为 A、B、C、D...
|
||||
- 例如:C 停用后,D 自动显示为 C,E 自动显示为 D
|
||||
|
||||
#### 二、字段管理需求
|
||||
|
||||
1. **系统字段(现有字段)**:
|
||||
- 可以停用/启用(停用=隐藏)
|
||||
- 可以修改显示名称(如"报工人"改为"操作员")
|
||||
- 可以修改控件类型
|
||||
- 不可删除
|
||||
- 支持名称重置为默认值
|
||||
|
||||
2. **自定义字段(新增字段)**:
|
||||
- 可以新增自定义字段
|
||||
- 可以配置字段名称、数据类型、控件类型
|
||||
- 可以选择放入任一类别中(包括自定义类别)
|
||||
- 可以移动到其他类别
|
||||
- 可以删除
|
||||
- 可以停用/启用
|
||||
|
||||
3. **字段配置项**:
|
||||
- 字段名称(可自定义)
|
||||
- 数据类型(STRING/NUMBER/DATE/DATETIME/BOOLEAN/SELECT)
|
||||
- 控件类型(INPUT/NUMBER/DATE/DATETIME/SELECT/TEXTAREA/SWITCH)
|
||||
- 下拉选项(SELECT 类型时配置)
|
||||
- 是否必填
|
||||
- 排序
|
||||
|
||||
#### 三、数据存储需求
|
||||
|
||||
1. **系统字段**:存储在 `pro_report` 表对应列中
|
||||
2. **自定义字段**:存储在 `pro_report.custom_fields` JSON 字段中
|
||||
|
||||
#### 四、显示规则
|
||||
|
||||
1. **停用=隐藏**:停用的类别和字段在表单中完全隐藏
|
||||
2. **启用=显示**:启用的类别和字段在表单中显示
|
||||
3. **自动编号**:前端显示时,启用的类别自动重新编号为 A、B、C、D...
|
||||
|
||||
---
|
||||
|
||||
## 一、需求背景
|
||||
|
||||
报工单表单中分为五类(A-基础信息、B-数量信息、C-时间节拍、D-成本效益、E-异常记录),需要实现:
|
||||
|
||||
1. **类别控制**:
|
||||
- 能够在配置中停用/启用任一类别,停用后该类别在新增/编辑时隐藏
|
||||
- 支持新增自定义类别(如 F、G、H 等)
|
||||
- 支持修改类别名称(如将"基础信息"改为"基本信息")
|
||||
- 系统类别(A/B/C/D/E)不可删除,只能停用;自定义类别可删除
|
||||
|
||||
2. **字段控制**:五类中的字段能够单独控制停用/启用(隐藏/显示)
|
||||
|
||||
3. **字段自定义**:
|
||||
- 现有字段可以自定义显示名称(改名),例如将"报工人"改为"操作员"
|
||||
- 支持新增自定义字段,可配置字段名称、数据类型、控件类型
|
||||
- **新增自定义字段时可以选择放入任一类别中(包括自定义类别)**
|
||||
- 自定义字段的值存储在 JSON 扩展字段中
|
||||
|
||||
4. **规则**:停用=隐藏,启用=显示
|
||||
|
||||
---
|
||||
|
||||
## 二、设计方案
|
||||
|
||||
### 2.1 数据库设计
|
||||
|
||||
#### 2.1.1 类别配置表(pro_report_category_config)
|
||||
|
||||
存储系统类别和自定义类别的配置
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| id | bigint | 主键ID |
|
||||
| category_code | varchar(50) | 类别编码(A/B/C/D/E 为系统类别,F/G/H... 为自定义类别) |
|
||||
| category_name | varchar(100) | 类别名称(可自定义修改) |
|
||||
| default_category_name | varchar(100) | 默认类别名称(系统初始名称,用于重置) |
|
||||
| category_type | varchar(20) | 类别类型(SYSTEM=系统类别/CUSTOM=自定义类别) |
|
||||
| is_enabled | char(1) | 是否启用(Y=启用/N=停用),默认Y |
|
||||
| sort_order | int | 排序号 |
|
||||
| remark | varchar(500) | 备注 |
|
||||
| create_by | varchar(64) | 创建者 |
|
||||
| create_time | datetime | 创建时间 |
|
||||
| update_by | varchar(64) | 更新者 |
|
||||
| update_time | datetime | 更新时间 |
|
||||
|
||||
#### 2.1.2 字段配置表(pro_report_field_config)
|
||||
|
||||
存储每个类别下字段的启用/停用状态、自定义显示名称、数据类型和控件类型
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| id | bigint | 主键ID |
|
||||
| category_code | varchar(50) | 所属类别编码(A/B/C/D/E) |
|
||||
| field_code | varchar(100) | 字段编码(对应实体类字段名或自定义字段唯一标识,不可修改) |
|
||||
| field_name | varchar(100) | 字段显示名称(可自定义修改,如"报工人"可改为"操作员") |
|
||||
| default_field_name | varchar(100) | 默认字段名称(系统初始名称,用于重置) |
|
||||
| field_type | varchar(20) | 字段类型(SYSTEM=系统字段/CUSTOM=自定义字段) |
|
||||
| data_type | varchar(50) | 数据类型(STRING=文本/NUMBER=数字/DATE=日期/DATETIME=日期时间/BOOLEAN=布尔/SELECT=下拉选择) |
|
||||
| control_type | varchar(50) | 控件类型(INPUT=文本框/NUMBER=数字框/DATE=日期选择/DATETIME=日期时间选择/SELECT=下拉框/TEXTAREA=文本域/SWITCH=开关) |
|
||||
| options | text | 下拉选项(JSON格式,仅当control_type=SELECT时有效,如:[{"label":"选项1","value":"1"}]) |
|
||||
| is_enabled | char(1) | 是否启用(Y=启用/N=停用),默认Y |
|
||||
| is_required | char(1) | 是否必填(Y=必填/N=非必填),默认N |
|
||||
| sort_order | int | 排序号 |
|
||||
| remark | varchar(500) | 备注 |
|
||||
| create_by | varchar(64) | 创建者 |
|
||||
| create_time | datetime | 创建时间 |
|
||||
| update_by | varchar(64) | 更新者 |
|
||||
| update_time | datetime | 更新时间 |
|
||||
|
||||
### 2.2 字段清单
|
||||
|
||||
#### A. 基础信息(category_code='A')
|
||||
|
||||
| field_code | field_name | field_type | data_type | control_type | is_required | 说明 |
|
||||
|------------|------------|------------|-----------|--------------|-------------|------|
|
||||
| reportUserId | 报工人 | SYSTEM | NUMBER | SELECT | Y | 系统字段,必填 |
|
||||
| reportTime | 报工时间 | SYSTEM | DATETIME | DATETIME | Y | 系统字段,必填 |
|
||||
| reportType | 报工类型 | SYSTEM | STRING | SELECT | N | 系统字段,字典 |
|
||||
| shiftName | 班次 | SYSTEM | STRING | SELECT | N | 系统字段,字典 |
|
||||
| teamName | 班组 | SYSTEM | STRING | SELECT | N | 系统字段,字典 |
|
||||
| executionStandard | 执行标准 | SYSTEM | STRING | INPUT | N | 系统字段 |
|
||||
| workshopId | 车间 | SYSTEM | NUMBER | SELECT | Y | 系统字段,必填 |
|
||||
| stationId | 工位 | SYSTEM | NUMBER | SELECT | Y | 系统字段,必填 |
|
||||
|
||||
#### B. 数量信息(category_code='B')
|
||||
|
||||
| field_code | field_name | field_type | data_type | control_type | is_required | 说明 |
|
||||
|------------|------------|------------|-----------|--------------|-------------|------|
|
||||
| planCount | 计划数 | SYSTEM | NUMBER | INPUT | N | 系统字段,只读 |
|
||||
| reportQuantity | 报工数量 | SYSTEM | NUMBER | NUMBER | Y | 系统字段,必填 |
|
||||
| qualifiedQuantity | 合格数量 | SYSTEM | NUMBER | NUMBER | Y | 系统字段,必填 |
|
||||
| unqualifiedQuantity | 不合格数量 | SYSTEM | NUMBER | INPUT | N | 系统字段,自动计算 |
|
||||
| yieldRate | 良品率 | SYSTEM | NUMBER | INPUT | N | 系统字段,自动计算 |
|
||||
|
||||
#### C. 时间节拍(category_code='C')
|
||||
|
||||
| field_code | field_name | field_type | data_type | control_type | is_required | 说明 |
|
||||
|------------|------------|------------|-----------|--------------|-------------|------|
|
||||
| planStartTime | 计划开始时间 | SYSTEM | DATETIME | INPUT | N | 系统字段,只读 |
|
||||
| planEndTime | 计划完工时间 | SYSTEM | DATETIME | DATETIME | N | 系统字段 |
|
||||
| actualStartTime | 实际开始时间 | SYSTEM | DATETIME | DATETIME | N | 系统字段 |
|
||||
| actualEndTime | 实际完工时间 | SYSTEM | DATETIME | DATETIME | N | 系统字段 |
|
||||
| theoreticalCycleTime | 理论节拍 | SYSTEM | NUMBER | NUMBER | N | 系统字段 |
|
||||
| downtimeMinutes | 停机时间 | SYSTEM | NUMBER | NUMBER | N | 系统字段 |
|
||||
| downtimeReason | 停机原因 | SYSTEM | STRING | INPUT | N | 系统字段 |
|
||||
|
||||
#### D. 成本效益(category_code='D')
|
||||
|
||||
| field_code | field_name | field_type | data_type | control_type | is_required | 说明 |
|
||||
|------------|------------|------------|-----------|--------------|-------------|------|
|
||||
| performanceWages | 绩效工资 | SYSTEM | NUMBER | NUMBER | N | 系统字段 |
|
||||
| energyConsumption | 能耗 | SYSTEM | NUMBER | NUMBER | N | 系统字段 |
|
||||
| materialConsumption | 工耗 | SYSTEM | NUMBER | NUMBER | N | 系统字段 |
|
||||
| otherCosts | 其他成本 | SYSTEM | NUMBER | NUMBER | N | 系统字段 |
|
||||
| valueAdded | 增值 | SYSTEM | NUMBER | NUMBER | N | 系统字段 |
|
||||
| stationOee | 工位OEE | SYSTEM | NUMBER | NUMBER | N | 系统字段 |
|
||||
| currentBenefit | 本次效益 | SYSTEM | NUMBER | INPUT | N | 系统字段,自动计算 |
|
||||
| isSettle | 是否结算工资 | SYSTEM | STRING | SELECT | N | 系统字段,字典 |
|
||||
| wages | 结算工资 | SYSTEM | NUMBER | NUMBER | N | 系统字段 |
|
||||
|
||||
#### E. 异常记录(category_code='E')
|
||||
|
||||
| field_code | field_name | field_type | data_type | control_type | is_required | 说明 |
|
||||
|------------|------------|------------|-----------|--------------|-------------|------|
|
||||
| stationException | 工位异常情况 | SYSTEM | STRING | TEXTAREA | N | 系统字段 |
|
||||
| rectificationSuggestion | 整改建议 | SYSTEM | STRING | TEXTAREA | N | 系统字段 |
|
||||
| remark | 备注 | SYSTEM | STRING | TEXTAREA | N | 系统字段 |
|
||||
|
||||
---
|
||||
|
||||
### 2.3 自定义字段存储方案
|
||||
|
||||
#### 2.3.1 存储位置
|
||||
|
||||
自定义字段的值存储在 `pro_report` 表的 `custom_fields` 字段中(JSON 类型)。
|
||||
|
||||
```sql
|
||||
ALTER TABLE `pro_report` ADD COLUMN `custom_fields` json DEFAULT NULL COMMENT '自定义字段值(JSON格式)';
|
||||
```
|
||||
|
||||
#### 2.3.2 存储格式
|
||||
|
||||
```json
|
||||
{
|
||||
"custom_field_001": "自定义文本值",
|
||||
"custom_field_002": 123.45,
|
||||
"custom_field_003": "2026-03-05 10:30:00",
|
||||
"custom_field_004": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3.3 字段编码规则
|
||||
|
||||
- 系统字段:使用实体类字段名(如 `reportUserId`)
|
||||
- 自定义字段:使用 `custom_field_` + 序号(如 `custom_field_001`)
|
||||
|
||||
#### 2.3.4 数据类型映射
|
||||
|
||||
| data_type | 存储格式 | 示例 |
|
||||
|-----------|---------|------|
|
||||
| STRING | 字符串 | "文本内容" |
|
||||
| NUMBER | 数字 | 123.45 |
|
||||
| DATE | 字符串(yyyy-MM-dd) | "2026-03-05" |
|
||||
| DATETIME | 字符串(yyyy-MM-dd HH:mm:ss) | "2026-03-05 10:30:00" |
|
||||
| BOOLEAN | 布尔值 | true / false |
|
||||
| SELECT | 字符串(选项值) | "option1" |
|
||||
|
||||
#### 2.3.5 字段保存与读取规则
|
||||
|
||||
**保存报工单时**:
|
||||
1. **系统字段(field_type=SYSTEM)**:
|
||||
- 直接保存到 `pro_report` 表对应的列
|
||||
- 例如:`reportUserId` 保存到 `report_user_id` 列
|
||||
- 使用 MyBatis-Plus 自动映射
|
||||
|
||||
2. **自定义字段(field_type=CUSTOM)**:
|
||||
- 保存到 `pro_report.custom_fields` JSON 字段
|
||||
- 例如:`custom_field_001` 保存为 `{"custom_field_001": "值"}`
|
||||
- 后端需要将自定义字段值序列化为 JSON
|
||||
|
||||
**查询报工单时**:
|
||||
1. **系统字段**:
|
||||
- 直接从 `pro_report` 表对应列读取
|
||||
- MyBatis-Plus 自动映射到实体类
|
||||
|
||||
2. **自定义字段**:
|
||||
- 从 `pro_report.custom_fields` JSON 字段解析
|
||||
- 后端需要将 JSON 反序列化为 Map 或对象
|
||||
- 前端合并系统字段和自定义字段数据
|
||||
|
||||
**示例代码(后端保存)**:
|
||||
```java
|
||||
// 保存报工单
|
||||
public void saveReport(Report report, Map<String, Object> customFields) {
|
||||
// 1. 保存系统字段(MyBatis-Plus 自动处理)
|
||||
reportMapper.insert(report);
|
||||
|
||||
// 2. 保存自定义字段到 JSON
|
||||
if (customFields != null && !customFields.isEmpty()) {
|
||||
String customFieldsJson = JSON.toJSONString(customFields);
|
||||
report.setCustomFields(customFieldsJson);
|
||||
reportMapper.updateById(report);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**示例代码(后端查询)**:
|
||||
```java
|
||||
// 查询报工单
|
||||
public ReportVO getReport(Long id) {
|
||||
Report report = reportMapper.selectById(id);
|
||||
ReportVO vo = new ReportVO();
|
||||
|
||||
// 1. 复制系统字段
|
||||
BeanUtils.copyProperties(report, vo);
|
||||
|
||||
// 2. 解析自定义字段
|
||||
if (StringUtils.isNotEmpty(report.getCustomFields())) {
|
||||
Map<String, Object> customFields = JSON.parseObject(
|
||||
report.getCustomFields(),
|
||||
new TypeReference<Map<String, Object>>() {}
|
||||
);
|
||||
vo.setCustomFields(customFields);
|
||||
}
|
||||
|
||||
return vo;
|
||||
}
|
||||
```
|
||||
|
||||
**示例代码(前端保存)**:
|
||||
```javascript
|
||||
// 提交报工单
|
||||
submitForm() {
|
||||
const formData = {
|
||||
// 系统字段
|
||||
reportUserId: this.form.reportUserId,
|
||||
reportTime: this.form.reportTime,
|
||||
reportQuantity: this.form.reportQuantity,
|
||||
// ... 其他系统字段
|
||||
|
||||
// 自定义字段(单独传递)
|
||||
customFields: {
|
||||
custom_field_001: this.form.custom_field_001,
|
||||
custom_field_002: this.form.custom_field_002,
|
||||
// ... 其他自定义字段
|
||||
}
|
||||
};
|
||||
|
||||
saveReport(formData).then(response => {
|
||||
this.$modal.msgSuccess("保存成功");
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## 三、功能设计
|
||||
|
||||
### 3.1 配置管理页面
|
||||
|
||||
#### 3.1.1 类别配置
|
||||
|
||||
- 页面路径:`/production/report/categoryConfig`
|
||||
- 功能:
|
||||
- 列表展示所有类别(系统类别 + 自定义类别)的启用状态
|
||||
- 支持单个类别的启用/停用切换
|
||||
- **支持新增自定义类别**(点击"新增类别"按钮)
|
||||
- **支持修改类别名称**(双击编辑或点击编辑按钮)
|
||||
- **支持删除自定义类别**(系统类别不可删除,只能停用)
|
||||
- 支持类别名称重置为默认值(仅系统类别)
|
||||
- 支持批量启用/停用
|
||||
- 支持排序调整(拖拽排序)
|
||||
|
||||
#### 3.1.2 字段配置
|
||||
|
||||
- 页面路径:`/production/report/fieldConfig`
|
||||
- 功能:
|
||||
- 按类别分组展示字段列表(包括系统类别和自定义类别)
|
||||
- **支持新增自定义字段**(点击"新增字段"按钮,选择所属类别)
|
||||
- 支持单个字段的启用/停用切换
|
||||
- **支持字段显示名称自定义修改**(双击编辑或点击编辑按钮)
|
||||
- 支持字段名称重置为默认值(仅系统字段)
|
||||
- **支持删除自定义字段**(系统字段不可删除,只能停用)
|
||||
- 支持字段必填属性设置
|
||||
- 支持字段排序调整
|
||||
- 支持按类别筛选
|
||||
- **支持修改字段所属类别**(可将字段移动到其他类别)
|
||||
|
||||
### 3.2 报工单表单适配
|
||||
|
||||
#### 3.2.1 类别显示控制
|
||||
|
||||
- 前端加载配置接口,获取启用的类别列表
|
||||
- 根据配置动态渲染 `el-collapse-item`
|
||||
- 停用的类别完全不渲染
|
||||
- **启用的类别按 sort_order 排序后,自动重新编号为 A、B、C、D...**
|
||||
- **显示格式:`{自动编号}. {类别名称}`(如 `A. 基础信息`)**
|
||||
|
||||
**前端实现示例**:
|
||||
```javascript
|
||||
// 加载类别配置
|
||||
async loadCategoryConfig() {
|
||||
const res = await listCategoryConfig({ isEnabled: 'Y' });
|
||||
// 按 sort_order 排序
|
||||
const enabledCategories = res.rows.sort((a, b) => a.sortOrder - b.sortOrder);
|
||||
|
||||
// 自动重新编号
|
||||
this.displayCategories = enabledCategories.map((cat, index) => ({
|
||||
...cat,
|
||||
displayCode: String.fromCharCode(65 + index), // A, B, C, D...
|
||||
displayName: `${String.fromCharCode(65 + index)}. ${cat.categoryName}`
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2.2 字段显示控制
|
||||
|
||||
- 前端加载字段配置接口,获取每个类别下启用的字段列表
|
||||
- 根据配置动态渲染字段控件
|
||||
- 停用的字段完全不渲染
|
||||
- 必填字段根据配置动态添加校验规则
|
||||
|
||||
---
|
||||
|
||||
## 四、接口设计
|
||||
|
||||
### 4.1 类别配置接口
|
||||
|
||||
#### 4.1.1 查询类别配置列表
|
||||
|
||||
```
|
||||
GET /production/report/categoryConfig/list
|
||||
响应:
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"categoryCode": "A",
|
||||
"categoryName": "基础信息",
|
||||
"isEnabled": "Y",
|
||||
"sortOrder": 1
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
#### 4.1.2 更新类别配置
|
||||
|
||||
```
|
||||
PUT /production/report/categoryConfig/{id}
|
||||
请求体:
|
||||
{
|
||||
"isEnabled": "N"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 字段配置接口
|
||||
|
||||
#### 4.2.1 查询字段配置列表
|
||||
|
||||
```
|
||||
GET /production/report/fieldConfig/list?categoryCode=A
|
||||
响应:
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"categoryCode": "A",
|
||||
"fieldCode": "reportUserId",
|
||||
"fieldName": "报工人",
|
||||
"isEnabled": "Y",
|
||||
"isRequired": "Y",
|
||||
"sortOrder": 1
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
#### 4.2.2 更新字段配置
|
||||
|
||||
```
|
||||
PUT /production/report/fieldConfig/{id}
|
||||
请求体:
|
||||
{
|
||||
"fieldName": "操作员", // 自定义显示名称
|
||||
"isEnabled": "N",
|
||||
"isRequired": "N"
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2.3 重置字段名称
|
||||
|
||||
```
|
||||
PUT /production/report/fieldConfig/{id}/resetName
|
||||
响应:
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "重置成功",
|
||||
"data": {
|
||||
"fieldName": "报工人" // 恢复为默认名称
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2.4 批量更新字段配置
|
||||
|
||||
```
|
||||
PUT /production/report/fieldConfig/batch
|
||||
请求体:
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"isEnabled": "Y"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"isEnabled": "N"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、前端实现要点
|
||||
|
||||
### 5.1 配置加载
|
||||
|
||||
```javascript
|
||||
// 在 formA.vue 和 form.vue 的 created 钩子中加载配置
|
||||
async loadReportConfig() {
|
||||
// 加载类别配置
|
||||
const categoryRes = await listCategoryConfig()
|
||||
this.enabledCategories = categoryRes.rows.filter(c => c.isEnabled === 'Y')
|
||||
|
||||
// 加载字段配置
|
||||
const fieldRes = await listFieldConfig()
|
||||
this.fieldConfigMap = {}
|
||||
fieldRes.rows.forEach(f => {
|
||||
if (!this.fieldConfigMap[f.categoryCode]) {
|
||||
this.fieldConfigMap[f.categoryCode] = []
|
||||
}
|
||||
if (f.isEnabled === 'Y') {
|
||||
this.fieldConfigMap[f.categoryCode].push(f)
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 动态渲染类别
|
||||
|
||||
```vue
|
||||
<el-collapse v-model="record._sections">
|
||||
<template v-for="category in enabledCategories">
|
||||
<el-collapse-item :name="category.categoryCode" :key="category.categoryCode">
|
||||
<template slot="title">
|
||||
<b>{{ category.categoryCode }}. {{ category.categoryName }}</b>
|
||||
</template>
|
||||
<!-- 动态渲染字段 -->
|
||||
<component :is="getCategoryComponent(category.categoryCode)"
|
||||
:record="record"
|
||||
:fields="fieldConfigMap[category.categoryCode]" />
|
||||
</el-collapse-item>
|
||||
</template>
|
||||
</el-collapse>
|
||||
```
|
||||
|
||||
### 5.3 动态渲染字段
|
||||
|
||||
```vue
|
||||
<el-row :gutter="16">
|
||||
<template v-for="field in fields">
|
||||
<el-col :xs="24" :sm="12" :md="8" :key="field.fieldCode" v-if="field.isEnabled === 'Y'">
|
||||
<el-form-item
|
||||
:label="field.fieldName"
|
||||
:prop="'reportList.'+rIdx+'.'+field.fieldCode"
|
||||
:rules="field.isRequired === 'Y' ? rules[field.fieldCode] : []"
|
||||
label-width="100px">
|
||||
<!-- 根据字段类型渲染不同控件 -->
|
||||
<component :is="getFieldComponent(field.fieldCode)"
|
||||
v-model="record[field.fieldCode]"
|
||||
:disabled="record.disabledFlag" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、后端实现要点
|
||||
|
||||
### 6.1 实体类
|
||||
|
||||
```java
|
||||
// ReportCategoryConfig.java
|
||||
@Data
|
||||
@TableName("pro_report_category_config")
|
||||
public class ReportCategoryConfig extends BaseEntity {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
private String categoryCode;
|
||||
private String categoryName;
|
||||
private String isEnabled;
|
||||
private Integer sortOrder;
|
||||
}
|
||||
|
||||
// ReportFieldConfig.java
|
||||
@Data
|
||||
@TableName("pro_report_field_config")
|
||||
public class ReportFieldConfig extends BaseEntity {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
private String categoryCode;
|
||||
private String fieldCode;
|
||||
private String fieldName;
|
||||
private String isEnabled;
|
||||
private String isRequired;
|
||||
private Integer sortOrder;
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 Controller
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/production/report/categoryConfig")
|
||||
public class ReportCategoryConfigController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private IReportCategoryConfigService categoryConfigService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(ReportCategoryConfig config) {
|
||||
startPage();
|
||||
List<ReportCategoryConfig> list = categoryConfigService.selectList(config);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public AjaxResult update(@PathVariable Long id, @RequestBody ReportCategoryConfig config) {
|
||||
config.setId(id);
|
||||
return toAjax(categoryConfigService.updateById(config));
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/production/report/fieldConfig")
|
||||
public class ReportFieldConfigController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private IReportFieldConfigService fieldConfigService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(ReportFieldConfig config) {
|
||||
startPage();
|
||||
List<ReportFieldConfig> list = fieldConfigService.selectList(config);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public AjaxResult update(@PathVariable Long id, @RequestBody ReportFieldConfig config) {
|
||||
config.setId(id);
|
||||
return toAjax(fieldConfigService.updateById(config));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}/resetName")
|
||||
public AjaxResult resetName(@PathVariable Long id) {
|
||||
return fieldConfigService.resetFieldName(id);
|
||||
}
|
||||
|
||||
@PutMapping("/batch")
|
||||
public AjaxResult batchUpdate(@RequestBody List<ReportFieldConfig> configs) {
|
||||
return toAjax(fieldConfigService.updateBatchById(configs));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、菜单权限配置
|
||||
|
||||
### 7.1 新增菜单
|
||||
|
||||
| 菜单名称 | 菜单路径 | 权限标识 | 父菜单 |
|
||||
|---------|---------|---------|--------|
|
||||
| 报工单配置 | /production/report/config | production:report:config | 生产管理 |
|
||||
| 类别配置 | /production/report/categoryConfig | production:report:categoryConfig | 报工单配置 |
|
||||
| 字段配置 | /production/report/fieldConfig | production:report:fieldConfig | 报工单配置 |
|
||||
|
||||
### 7.2 权限标识
|
||||
|
||||
- `production:report:categoryConfig:list` - 查询类别配置
|
||||
- `production:report:categoryConfig:edit` - 修改类别配置
|
||||
- `production:report:fieldConfig:list` - 查询字段配置
|
||||
- `production:report:fieldConfig:edit` - 修改字段配置
|
||||
- `production:report:fieldConfig:batchEdit` - 批量修改字段配置
|
||||
|
||||
---
|
||||
|
||||
## 八、实施步骤
|
||||
|
||||
| 步骤 | 任务 | 工作量 |
|
||||
|------|------|--------|
|
||||
| 1 | 执行 SQL 脚本创建配置表和初始化数据 | 0.5h |
|
||||
| 2 | 后端:创建实体类、Mapper、Service、Controller(含重置名称接口) | 2.5h |
|
||||
| 3 | 前端:创建配置管理页面(类别配置、字段配置,含字段名称编辑) | 5h |
|
||||
| 4 | 前端:报工单表单适配(动态加载配置、动态渲染、使用自定义名称) | 4h |
|
||||
| 5 | 联调测试、修复问题 | 2h |
|
||||
| **合计** | | **约 2 个工作日** |
|
||||
|
||||
---
|
||||
|
||||
## 九、核心规则说明
|
||||
|
||||
### 9.1 字段类型规则
|
||||
|
||||
| 规则项 | 系统字段(SYSTEM) | 自定义字段(CUSTOM) |
|
||||
|--------|-------------------|---------------------|
|
||||
| **字段编码** | 使用实体类字段名(如 `reportUserId`) | 使用 `custom_field_` + 序号(如 `custom_field_001`) |
|
||||
| **存储位置** | `pro_report` 表对应列(如 `report_user_id`) | `pro_report.custom_fields` JSON 字段 |
|
||||
| **字段名称** | 可自定义修改显示名称 | 可自定义修改显示名称 |
|
||||
| **数据类型** | 固定(由数据库列类型决定) | 可配置(STRING/NUMBER/DATE/DATETIME/BOOLEAN/SELECT) |
|
||||
| **控件类型** | 可配置 | 可配置 |
|
||||
| **所属类别** | 固定(不可修改) | 可修改(可移动到其他类别) |
|
||||
| **是否可删除** | 不可删除,只能停用 | 可删除 |
|
||||
|
||||
### 9.1.1 类别类型规则
|
||||
|
||||
| 规则项 | 系统类别(SYSTEM) | 自定义类别(CUSTOM) |
|
||||
|--------|-------------------|---------------------|
|
||||
| **类别编码** | A/B/C/D/E(固定) | F/G/H/I...(自动生成) |
|
||||
| **类别名称** | 可自定义修改 | 可自定义修改 |
|
||||
| **是否可删除** | 不可删除,只能停用 | 可删除(删除前需确认该类别下无字段) |
|
||||
| **排序** | 可调整 | 可调整 |
|
||||
|
||||
### 9.2 数据保存规则
|
||||
|
||||
**规则 1:系统字段直接保存到对应列**
|
||||
- 系统字段(field_type=SYSTEM)的值直接保存到 `pro_report` 表对应的列
|
||||
- 例如:`reportUserId` → `report_user_id` 列
|
||||
- 使用 MyBatis-Plus 自动映射,无需特殊处理
|
||||
|
||||
**规则 2:自定义字段保存到 JSON**
|
||||
- 自定义字段(field_type=CUSTOM)的值保存到 `custom_fields` JSON 字段
|
||||
- 所有自定义字段值合并为一个 JSON 对象
|
||||
- 例如:`{"custom_field_001": "值1", "custom_field_002": 123}`
|
||||
|
||||
**规则 3:JSON 字段格式要求**
|
||||
- 必须是有效的 JSON 格式
|
||||
- 键名为字段编码(field_code)
|
||||
- 值类型根据 data_type 确定(字符串、数字、布尔值等)
|
||||
|
||||
### 9.3 数据查询规则
|
||||
|
||||
**规则 1:系统字段直接读取**
|
||||
- 从 `pro_report` 表对应列直接读取
|
||||
- MyBatis-Plus 自动映射到实体类
|
||||
|
||||
**规则 2:自定义字段从 JSON 解析**
|
||||
- 从 `custom_fields` JSON 字段解析
|
||||
- 后端反序列化为 Map 或对象
|
||||
- 前端合并系统字段和自定义字段数据
|
||||
|
||||
**规则 3:字段配置动态加载**
|
||||
- 前端根据字段配置表动态渲染表单
|
||||
- 系统字段和自定义字段统一处理
|
||||
- 根据 field_type 判断数据来源
|
||||
|
||||
### 9.4 字段配置规则
|
||||
|
||||
**规则 1:字段编码不可修改**
|
||||
- field_code 一旦创建不可修改
|
||||
- 系统字段编码对应实体类字段名
|
||||
- 自定义字段编码使用 `custom_field_` 前缀
|
||||
|
||||
**规则 2:字段名称可自定义**
|
||||
- field_name 可随时修改
|
||||
- 支持重置为 default_field_name
|
||||
|
||||
**规则 3:停用=隐藏**
|
||||
- is_enabled='N' 时,字段在表单中完全隐藏
|
||||
- 停用的字段不参与表单验证
|
||||
- 停用的字段不影响已保存的数据
|
||||
|
||||
**规则 4:必填字段保护**
|
||||
- 核心必填字段(报工人、报工时间、报工数量等)不允许停用
|
||||
- 前端和后端都需要校验
|
||||
|
||||
### 9.5 自定义字段管理规则
|
||||
|
||||
**规则 1:新增自定义字段**
|
||||
- 在字段配置页面点击"新增字段"
|
||||
- **选择所属类别(可选择系统类别或自定义类别)**
|
||||
- 配置字段名称、数据类型、控件类型
|
||||
- 系统自动生成 field_code(custom_field_xxx)
|
||||
|
||||
**规则 2:删除自定义字段**
|
||||
- 只能删除自定义字段(field_type=CUSTOM)
|
||||
- 系统字段不可删除,只能停用
|
||||
- 删除前需确认是否有数据使用该字段
|
||||
|
||||
**规则 3:修改自定义字段**
|
||||
- 可修改字段名称、数据类型、控件类型
|
||||
- **可修改字段所属类别(移动到其他类别)**
|
||||
- 修改数据类型可能导致已有数据格式不兼容
|
||||
- 建议修改前备份数据
|
||||
|
||||
### 9.6 自定义类别管理规则
|
||||
|
||||
**规则 1:新增自定义类别**
|
||||
- 在类别配置页面点击"新增类别"
|
||||
- 输入类别名称
|
||||
- 系统自动生成 category_code(F/G/H...)
|
||||
- 新增的类别默认启用
|
||||
|
||||
**规则 2:删除自定义类别**
|
||||
- 只能删除自定义类别(category_type=CUSTOM)
|
||||
- 系统类别(A/B/C/D/E)不可删除,只能停用
|
||||
- 删除前需确认该类别下没有字段
|
||||
- 如果类别下有字段,需要先删除或移动字段
|
||||
|
||||
**规则 3:修改自定义类别**
|
||||
- 可修改类别名称
|
||||
- 可调整排序
|
||||
- 系统类别名称可修改,但不可删除
|
||||
|
||||
**规则 4:类别编码生成规则**
|
||||
- 系统类别:A/B/C/D/E(固定)
|
||||
- 自定义类别:按字母顺序自动生成(F/G/H/I/J...)
|
||||
- 如果字母用完,使用 AA/AB/AC...(26 个字母后)
|
||||
|
||||
### 9.7 类别显示与排序规则
|
||||
|
||||
**规则 1:类别编号自动排序(默认行为)**
|
||||
- 前端显示时,只显示启用的类别
|
||||
- 启用的类别按 `sort_order` 排序后,自动重新编号为 A、B、C、D...
|
||||
- 例如:
|
||||
- 配置:A(启用)、B(启用)、C(停用)、D(启用)、E(启用)
|
||||
- 显示:A. 基础信息、B. 数量信息、C. 成本效益、D. 异常记录
|
||||
- 实际对应:A→A、B→B、D→C、E→D
|
||||
|
||||
**规则 2:自定义排序(用户手动调整)**
|
||||
- 用户可以通过拖拽或上下移动按钮调整类别顺序
|
||||
- 调整后更新 `sort_order` 字段
|
||||
- 前端按照 `sort_order` 排序显示
|
||||
- 自定义排序后,仍然自动重新编号
|
||||
|
||||
**规则 3:类别编号显示规则**
|
||||
- 前端显示格式:`{自动编号}. {类别名称}`
|
||||
- 例如:`A. 基础信息`、`B. 数量信息`
|
||||
- 自动编号不存储在数据库,仅用于前端显示
|
||||
- 数据库中的 `category_code` 保持不变
|
||||
|
||||
**规则 4:停用类别的处理**
|
||||
- 停用的类别在报工单表单中完全隐藏
|
||||
- 停用的类别不参与自动编号
|
||||
- 停用的类别在配置页面仍然显示(标记为停用状态)
|
||||
|
||||
**示例说明**:
|
||||
|
||||
| 数据库配置 | sort_order | is_enabled | 前端显示 |
|
||||
|-----------|-----------|-----------|---------|
|
||||
| A-基础信息 | 1 | Y | A. 基础信息 |
|
||||
| B-数量信息 | 2 | Y | B. 数量信息 |
|
||||
| C-时间节拍 | 3 | N | (隐藏) |
|
||||
| D-成本效益 | 4 | Y | C. 成本效益 |
|
||||
| E-异常记录 | 5 | Y | D. 异常记录 |
|
||||
| F-自定义类别 | 6 | Y | E. 自定义类别 |
|
||||
|
||||
## 十、注意事项
|
||||
|
||||
1. **必填字段保护**:报工人、报工时间、报工数量、合格数量等核心必填字段不允许停用
|
||||
2. **字段编码不可修改**:field_code(字段编码)对应数据库字段名或自定义字段标识,不允许修改
|
||||
3. **类别编号自动排序**:前端显示时,启用的类别自动重新编号为 A、B、C、D...,停用的类别不参与编号
|
||||
4. **类别编码固定**:数据库中的 category_code 保持不变(A/B/C/D/E/F/G...),仅前端显示编号会自动调整
|
||||
5. **JSON 字段性能**:自定义字段存储在 JSON 中,查询性能较差,不建议在 WHERE 条件中使用
|
||||
6. **数据类型兼容**:修改自定义字段的数据类型时,需要考虑已有数据的兼容性
|
||||
7. **配置缓存**:前端可以缓存配置数据,避免每次打开表单都请求接口
|
||||
8. **配置变更通知**:配置修改后,需要刷新页面才能生效(或使用 WebSocket 推送配置变更)
|
||||
9. **移动端适配**:配置管理页面仅在 PC 端显示,移动端隐藏配置入口
|
||||
10. **历史数据兼容**:已保存的报工单不受配置影响,配置仅影响新增/编辑时的表单显示
|
||||
11. **名称重置功能**:支持将自定义的字段名称和类别名称重置为系统默认名称
|
||||
12. **自定义字段数量限制**:建议每个类别的自定义字段不超过 20 个,避免表单过于复杂
|
||||
13. **删除类别前检查**:删除自定义类别前,需确认该类别下没有字段
|
||||
|
||||
---
|
||||
|
||||
## 十、扩展规划
|
||||
|
||||
### 10.1 自定义字段(后续版本)
|
||||
|
||||
- 支持用户自定义新增字段
|
||||
- 字段类型:文本、数字、日期、下拉、多选等
|
||||
- 自定义字段存储在 JSON 字段中
|
||||
|
||||
### 10.2 多配置方案(后续版本)
|
||||
|
||||
- 支持不同车间/工位使用不同的配置方案
|
||||
- 配置方案可以复制、导入、导出
|
||||
|
||||
### 10.3 字段联动(后续版本)
|
||||
|
||||
- 支持字段之间的显示/隐藏联动
|
||||
- 支持字段值的计算联动
|
||||
Reference in New Issue
Block a user