Files
MES/yawei-mes/.tasks/2026-03-05_v2.0.003_报工单页面类别与字段控制.md
2026-04-02 10:39:03 +08:00

888 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 报工单页面类别与字段控制设计文档
**版本:** 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 自动显示为 CE 自动显示为 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}`
**规则 3JSON 字段格式要求**
- 必须是有效的 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_codecustom_field_xxx
**规则 2删除自定义字段**
- 只能删除自定义字段field_type=CUSTOM
- 系统字段不可删除,只能停用
- 删除前需确认是否有数据使用该字段
**规则 3修改自定义字段**
- 可修改字段名称、数据类型、控件类型
- **可修改字段所属类别(移动到其他类别)**
- 修改数据类型可能导致已有数据格式不兼容
- 建议修改前备份数据
### 9.6 自定义类别管理规则
**规则 1新增自定义类别**
- 在类别配置页面点击"新增类别"
- 输入类别名称
- 系统自动生成 category_codeF/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 字段联动(后续版本)
- 支持字段之间的显示/隐藏联动
- 支持字段值的计算联动