# decision_manage(决策管理)模块 — 数据库表字段详解 ## 概述 `decision_manage` 模块涉及两张核心数据库表: - **`st_strategy_config`**(仓储策略配置表):定义每个具体策略的元信息和运行参数 - **`st_sect_strategy`**(库区策略关联表):定义每个库区绑定了哪些策略,形成策略链 两张表通过 `strategy_code`(策略编码)字段产生逻辑关联——`st_sect_strategy.strategy` 中存储的 JSON 数组元素值,对应 `st_strategy_config.strategy_code`。 --- ## 一、`st_strategy_config`(仓储策略配置表) **作用**:存储每一个可用策略的完整定义,包括策略的基本信息、分类、运行参数和启用状态。每个策略对应一个 Spring Bean(继承 `Decisioner` 的处理器),系统启动时通过 `strategy_code` 与 Bean 名称自动关联。 ### 字段详解 #### 1. `id` — 策略标识(主键) | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | | 主键策略 | 无自增,手动赋值 | | 生成方式 | `IdUtil.getStringId()`(雪花ID或UUID变体) | **作用**:策略记录的唯一标识,由后端在新增时自动生成,前端不感知。`create` 方法中通过 `IdUtil.getStringId()` 赋值。 --- #### 2. `strategy_code` — 策略编码 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR(64)` | **作用**:策略的编码标识,是两张表之间的**核心关联字段**。每个策略编码与 Spring 容器中一个 `Decisioner` 子类的 `@Service("xxx")` Bean 名称严格一一对应。 **取值示例**: | 策略编码 | 对应处理器 | 分类 | |----------|-----------|------| | `fifo` | FIFORuleHandler | base | | `nearby` | NearbyRuleHandler | base | | `weight` | WeightRuleHandler | base | | `cluster` | ClusterRuleHandler | base | | `limitStorage` | LimitStorageRuleHandler | base | | `alleyAve` | AlleyAveRuleHandler | base | | `depthPriority` | DepthPriorityHandler | diy | | `fifo2` | FIFO2RuleHandler | diy | | `inventory` | InventoryRuleHandler | diy | | `passRCL` | PassRCLHandler | diy | **注意**:当前 `create` 方法中硬编码为 `"000"`,这意味着新增策略时需要在数据库中手动修正 `strategy_code` 的值,或在界面上提供修改入口。这是一个应改进的点。 **关联关系**:被 `st_sect_strategy.strategy` JSON 数组引用,也被 `Decisioner.afterPropertiesSet()` 用于查询自身配置。 --- #### 3. `strategy_name` — 策略名称 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | **作用**:策略的中文显示名称,用于后台管理界面展示,如"先进先出"、"就近放置"、"巷道均衡"等。 **约束**:`create` 方法中会校验名称唯一性——如果已存在相同名称的策略,抛出 `BadRequestException("已存在相同名称的策略【xxx】")`。 **使用场景**:在 `GET /api/strategy/decisionColumns` 接口中作为下拉选项的 `label` 字段返回给前端。 --- #### 4. `strategy_type` — 策略类型 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | **作用**:标识策略适用于哪种仓储操作场景。 **取值约定**: | 值 | 含义 | 典型策略 | |----|------|----------| | `1` | 入库策略 | limitStorage, nearby, alleyAve, weight, cluster, depthPriority, inventory | | `2` | 出库策略 | fifo, fifo2 | | `3` | 通用策略(出入库均可) | alleyAve(同时支持出入) | **使用场景**:上层调度模块根据当前任务是入库还是出库,筛选对应类型的策略进行链式调用。 --- #### 5. `class_type` — 类处理类型 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | **作用**:标识策略实现类的归属分类,用于前端分组展示或权限控制。 **取值约定**: | 值 | 含义 | 说明 | |----|------|------| | `base` | 基础策略 | 通用性强的标准策略,如 FIFO、就近、限位、均衡等 | | `diy` | 自定义策略 | 为特定项目/现场定制的策略,如深位优先、双叉分配等 | **代码中的实际使用**:当前在 Java 代码中未发现直接使用该字段做业务逻辑判断,主要用于界面上的分类筛选和展示。 --- #### 6. `param` — 策略参数 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR`(存储 JSON 字符串) | **作用**:策略运行时可配置的参数,以 JSON 字符串形式存储。这是**策略配置最核心的字段**,直接影响策略的执行行为。 **各策略的 param 格式与含义**: | 策略 | param 格式 | 含义 | |------|-----------|------| | alleyAve (巷道均衡) | `["x","z","y"]` | 排序优先级:先按排(x),再按层(z),最后按列(y) | | limitStorage (货位限位) | `["h","w","l","weight"]` | 需要匹配的维度:高度、宽度、深度、承重 | | passRCL (排/列/层过滤) | `{"y":[1,2,3,104,103,102]}` | 排除列号为 1,2,3,102,103,104 的货位 | | nearby (就近放置) | 当前未使用 param | 使用硬编码的 Top10,可扩展为从 param 读取候选数量 | | weight (轻上重下) | 通过 handler 参数传递 | 泛型声明为 String,实际解析为 JSON | **注意**:同一策略类可以在 `st_strategy_config` 中存在多条记录(不同 `strategy_code`),每条记录配置不同的 `param`,实现同一策略逻辑在不同场景下的差异化复用。例如不同库区可以有不同的排序维度。 --- #### 7. `form_data` — 策略表单配置 | 属性 | 说明 | |------|------| | Java 类型 | `JSONObject` | | 数据库类型 | `VARCHAR`(通过 `FastjsonSortTypeHandler` 序列化) | | 默认值 | `new JSONObject()`(空 JSON 对象) | | TypeHandler | `FastjsonSortTypeHandler.class` | **作用**:存储策略在前端表单中的渲染配置,例如表单字段定义、校验规则、下拉选项等。这是一个**纯前端辅助字段**,不参与后端决策逻辑。 **示例**:可能包含类似以下结构的数据(具体格式取决于前端表单设计器): ```json { "fields": [ {"name": "x", "label": "排", "type": "checkbox"}, {"name": "y", "label": "列", "type": "checkbox"}, {"name": "z", "label": "层", "type": "checkbox"} ] } ``` **与 `param` 的区别**: - `param`:策略的**运行参数**,后端 `handler()` 方法中解析并使用 - `form_data`:策略的**表单配置**,前端渲染配置界面时使用 --- #### 8. `remark` — 描述/备注 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | **作用**:策略的补充说明文本,用于记录策略的用途、注意事项、变更历史等。纯展示字段,不参与业务逻辑。 --- #### 9. `is_used` — 是否启用 | 属性 | 说明 | |------|------| | Java 类型 | `Boolean` | | 数据库类型 | `TINYINT` 或 `BIT` | | 默认值 | `null`(未设置,建议默认为 `true` 或 `false`) | **作用**:控制策略的启用/禁用状态。只有启用的策略才会在策略链中被调用。提供 `PUT /api/strategy/changeActive` 接口进行切换。 **切换逻辑**(`changeActive` 方法):每次调用将 `is_used` 值取反,实现一键启用/禁用切换。 **与 `ban` 的区别**:`is_used` 是实际在使用的启用状态控制字段;`ban` 字段在代码中未被使用,疑似冗余。 --- #### 10. `ban` — 是否禁用 | 属性 | 说明 | |------|------| | Java 类型 | `Boolean` | | 数据库类型 | `TINYINT` 或 `BIT` | **作用**:从命名推断用于禁用标记,但在当前 Java 代码中**未找到任何读写该字段的逻辑**。可能是早期设计预留的字段,后来被 `is_used` 替代,或者是数据库中有但代码中未同步使用。 **建议**:确认是否在 SQL 脚本或前端有使用,如果确认废弃则应清理。 --- #### 11. `update_name` — 修改人名称 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | **作用**:记录最后一次修改该策略配置的操作人姓名。在 `update`、`deleteAll`、`changeActive` 方法中通过 `SecurityUtils.getCurrentNickName()` 自动赋值。 --- #### 12. `update_time` — 修改时间 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | **作用**:记录最后一次修改的时间戳。在 `update`、`deleteAll`、`changeActive` 方法中通过 `DateUtil.now()` 自动赋值。 **注意**:使用 `String` 而非 `LocalDateTime` 或 `Date`,实际存储格式取决于 `DateUtil.now()` 的返回值(通常是 `yyyy-MM-dd HH:mm:ss`)。 --- #### 13. `is_delete` — 是否删除(逻辑删除标记) | 属性 | 说明 | |------|------| | Java 类型 | `Boolean` | | 数据库类型 | `TINYINT` 或 `BIT` | | 查询默认值 | `Boolean.FALSE`(在 `StrategyQuery` 中设置) | **作用**:逻辑删除标记。删除策略时不会物理删除记录,而是将该字段设为 `"1"`(注意代码中使用字符串 `"1"` 而非布尔值 `true`,存在类型不一致)。 **使用方式**: - 查询时:Mapper XML 中硬编码过滤条件 `is_delete = "0"`,只查询未删除记录 - 删除时:`deleteAll` 方法通过 `UpdateWrapper` 设置 `is_delete = "1"` **注意**:`StrategyQuery` 中虽然设置了 `is_delete = Boolean.FALSE` 作为默认参数,但 Mapper XML 中直接硬编码了 `is_delete = "0"`,Query 对象中的 `is_delete` 实际上没有在 SQL 中被引用。 --- ## 二、`st_sect_strategy`(库区策略关联表) **作用**:定义每个库区与策略链的绑定关系。一个库区可以绑定多个策略,这些策略按数组顺序组成策略链,入库/出库时依次执行。 ### 字段详解 #### 1. `id` — 主键 | 属性 | 说明 | |------|------| | Java 类型 | `Integer` | | 数据库类型 | `INT` | | 主键策略 | `IdType.AUTO`(数据库自增) | **作用**:记录的唯一标识,由数据库自动生成。 --- #### 2. `sect_code` — 库区编码 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | **作用**:标识该策略链配置属于哪个库区。库区是仓库物理空间的逻辑划分,每个库区有独立的编码(如 `A01`、`B02` 等)。 **使用场景**: - 调度模块接到入库/出库任务时,根据目标库区编码查询该库区绑定的策略链 - `SectStrategyQuery` 支持按 `sect_code` 过滤分页查询 **关联**:库区编码对应基础数据模块中库区/仓位主数据,本表不存储库区本身的详细信息。 --- #### 3. `strategy` — 策略编码列表(策略链) | 属性 | 说明 | |------|------| | Java 类型 | `List` | | 数据库类型 | `VARCHAR`(存储 JSON 数组字符串) | | TypeHandler | `ListStrTypeHandler.class` | **作用**:这是决策模块最核心的字段,定义了该库区的**策略链**——即入库/出库时依次执行的策略编码列表,**数组顺序即为执行顺序**。 **存储格式**(数据库中的实际内容): ```json ["limitStorage", "nearby", "alleyAve"] ``` **Java 中的表示**: ```java List strategy = ["limitStorage", "nearby", "alleyAve"] ``` **执行流程**:当任务到达该库区时,调度模块会按数组顺序依次调用对应的策略处理器: ``` 可用货位列表 → limitStorage.handler() // 过滤尺寸/重量不匹配的货位 → nearby.handler() // 按距离排序,取前N个 → alleyAve.handler() // 巷道均衡分配 → 最终货位列表 ``` **TypeHandler 转换机制**: - **写入时**(Java → DB):`ListStrTypeHandler.setNonNullParameter()` 调用 `JSON.toJSONString(parameter)`,将 `List` 序列化为 JSON 数组字符串 - **读取时**(DB → Java):`ListTypeHandler.getNullableResult()` 调用 `JSONArray.parseArray(s, String.class)`,将 JSON 数组反序列化为 `List`;若为 `NULL` 则返回空 `ArrayList` **策略编码的取值**:列表中的每个元素必须是 `st_strategy_config.strategy_code` 的有效值,对应一个已注册的 Spring Bean。如果填写了不存在的策略编码,运行时才会报错。 --- #### 4. `strategy_type` — 策略类型 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | **作用**:标识该条策略链配置适用于哪种操作场景。 **取值约定**: | 值 | 含义 | |----|------| | `1` | 入库策略链 | | `2` | 出库策略链 | **使用场景**:一个库区可能同时需要入库和出库的策略链配置,通过该字段区分。例如: ``` 库区 A01: - strategy_type=1: ["limitStorage", "nearby", "alleyAve"] ← 入库用 - strategy_type=2: ["fifo"] ← 出库用 ``` 调度模块根据当前任务是入库还是出库,查询对应 `strategy_type` 的策略链。 --- #### 5. `description` — 描述 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | **作用**:对该库区策略链配置的说明文本,用于后台管理界面的展示。纯文本备注,不参与业务逻辑。 --- #### 6. `update_time` — 更新时间 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | **作用**:记录最后一次修改的时间。在 Controller 的 `create` 和 `update` 方法中通过 `DateUtil.now()` 手动赋值。 --- #### 7. `update_name` — 更新人 | 属性 | 说明 | |------|------| | Java 类型 | `String` | | 数据库类型 | `VARCHAR` | **作用**:记录最后一次修改该库区策略配置的操作人。在 Controller 中通过 `SecurityUtils.getCurrentUsername()` 手动赋值。 --- ## 三、两表关联关系 ``` st_strategy_config (策略定义) st_sect_strategy (库区-策略绑定) ┌──────────────────────────┐ ┌──────────────────────────┐ │ id (PK) │ │ id (PK, AUTO) │ │ strategy_code ◄──────────┼──────────│ strategy (JSON数组) │ │ strategy_name │ 逻辑引用 │ sect_code │ │ strategy_type │ │ strategy_type │ │ class_type │ │ description │ │ param │ │ update_time │ │ form_data │ │ update_name │ │ remark │ └──────────────────────────┘ │ is_used │ │ ban │ │ update_name │ │ update_time │ │ is_delete │ └──────────────────────────┘ ``` **关联方式**:`st_sect_strategy.strategy` 中的 JSON 数组元素(如 `"fifo"`)逻辑上引用 `st_strategy_config.strategy_code`。 **当前限制**:由于使用 JSON 数组存储,数据库层面无法建立外键约束。如果策略编码被修改或删除,库区策略链中的引用不会自动更新或校验。 **查询链路**: 1. 调度模块根据任务中的库区编码 `sect_code` + 策略类型 `strategy_type` 查询 `st_sect_strategy` 2. 从 `strategy` 字段解析出策略编码列表 3. 按顺序从 Spring 容器中获取对应 Bean 名称的 `Decisioner` 实例 4. 每个 `Decisioner` 在初始化时已通过 `strategy_code` 从 `st_strategy_config` 加载了自身的配置(`param`、`form_data` 等) --- ## 四、字段补充说明 ### 缺失的常见字段 两张表均**没有**明确声明以下常见审计字段(但代码中有隐式引用): | 缺失字段 | 说明 | |----------|------| | `create_time` | 创建时间 — 实体中未声明,但 `StStrategyConfigServiceImpl.pageQuery` 中使用了 `ORDER BY create_time DESC`,说明数据库表中实际存在该字段,只是 Java 实体未映射 | | `create_name` | 创建人 — 新增方法中未赋值,可能依赖数据库默认值 | ### 类型不一致问题 | 问题 | 位置 | 详情 | |------|------|------| | `is_delete` 赋值类型 | `StStrategyConfigServiceImpl.deleteAll()` | `Boolean` 字段被赋值为字符串 `"1"` | | `update_time` 类型 | 两张表 | 使用 `String` 存储时间,而非 `LocalDateTime` | --- ## 五、设计改进建议(与字段相关) 1. **`strategy_code` 创建时硬编码 `"000"`**:`create` 方法未提供策略编码的输入入口,需要后续手动修改。建议在创建界面提供编码输入框,并增加编码唯一性校验。 2. **`ban` 字段废弃**:代码中未使用,确认后可清理。 3. **`is_delete` 赋值类型修复**:`deleteAll` 中应将 `"1"` 改为 `true`,保持与字段声明的 `Boolean` 类型一致。 4. **`update_time` 使用更合适的类型**:建议从 `String` 改为 `LocalDateTime`,利用 Java 8 时间 API 的类型安全优势。 5. **补充 `create_time` / `create_name` 映射**:数据库存在但 Java 实体未映射,导致新增记录时无法在实体层面追踪创建信息。 6. **`strategy` JSON 数组的引用完整性**:无法通过数据库约束保证 `st_sect_strategy.strategy` 中的策略编码在 `st_strategy_config` 中真实存在,建议在保存时增加后端校验逻辑。