feat&refactor: 2026-09-22 半成品业务模型重构与功能完善

- 重构半成品流转逻辑:进度权威源改为 workpiece.currentStationNo,新增 completedText 快照字段,废除 doneProcessCodes
- 清理物料品类中半成品类型,存量数据幂等清理,调整物料管理方式文案为批次/序列号
- 新增日排产状态专用更新接口,修复工单工艺校验逻辑
- 新增物料档案代理接口、深路径文件下载接口
- 优化前端界面文案与工位选择逻辑,补充追溯页半成品流转展示
- 调整WMS端物料品类校验与入库接口契约
- 新增/更新数据库表结构与实体类代码
This commit is contained in:
SunYF
2026-09-22 14:42:52 +08:00
parent 09cfc6ca1c
commit d3eda6b588
49 changed files with 1155 additions and 1122 deletions
+14 -11
View File
@@ -14,7 +14,7 @@ import (
"github.com/zeromicro/go-zero/core/logx"
)
// itemTypeLabel 物料品类标签:1原材料/2半成品/3成品/4其他(辅料/工装/试验设备)
// itemTypeLabel 物料品类标签:1原材料/3成品/4其他(半成品品类已下线,防御性保留 2 的显示)
func itemTypeLabel(t int) string {
switch t {
case invCatSemi:
@@ -41,8 +41,11 @@ func validateMaterialRequired(name, spec, unit string, itemType, manageMode int)
return "规格型号为必填项"
case strings.TrimSpace(unit) == "":
return "单位为必填项"
case itemType < 1 || itemType > invItemOther:
return "品类为必填项(原材料 / 半成品 / 成品 / 其他)"
case itemType == invCatSemi:
// 2026-09-22 定稿:半成品是工件状态(由库存 category=2 承载),不再是物料品类
return "半成品不再是物料品类,请选择成品档案并在库存中记录工序状态"
case itemType != invCatRaw && itemType != invCatFinished && itemType != invItemOther:
return "品类为必填项(原材料 / 成品 / 其他)"
case manageMode != 1 && manageMode != 2 && manageMode != invManageOther:
return "类型为必填项(结构件 / 电气件 / 其他)"
}
@@ -60,9 +63,9 @@ func createMaterialHandler(ctx *svc.ServiceContext) http.HandlerFunc {
Description string `json:"description"`
ManageMode int `json:"manageMode"` // 1批次/2序列号
TemplateCode string `json:"templateCode"`
ItemType int `json:"itemType"` // 1原材料/2半成品/3成品/4其他
ItemType int `json:"itemType"` // 1原材料/3成品/4其他(半成品不是物料品类)
SafetyStock int `json:"safetyStock"` // 安全库存(低于触发缺货预警)
IsActive *bool `json:"isActive"` // 启用状态(nil 视为启用)
IsActive *bool `json:"isActive"` // 启用状态(nil 视为启用)
}
if err := parseJSON(r, &req); err != nil {
fail(w, http.StatusBadRequest, "参数错误")
@@ -317,7 +320,7 @@ func getMaterialHandler(ctx *svc.ServiceContext) http.HandlerFunc {
}
// materialTypesHandler 内部接口:批量查询物料品类(item_type)。
// body: {"codes":["A","B"]} → data: {"types":{"A":1,"B":3}}(1原材料/2半成品/3成品/4其他)。
// body: {"codes":["A","B"]} → data: {"types":{"A":1,"B":3}}(1原材料/3成品/4其他)。
// 供 MES 递归展开产品物料清单使用:成品子项(item_type=3)需继续展开到原材料。
func materialTypesHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
@@ -500,8 +503,8 @@ func parseManageMode(s string) int {
return 0
}
// parseItemType 解析导入模板"品类"列:原材料/半成品/成品/其他(兼容 1/2/3/4);无法识别返回 0。
// 注意:"半成品"含"成品"子串,必须先判半成品再判成品。
// parseItemType 解析导入模板"品类"列:原材料/成品/其他(兼容 1/3/4);无法识别返回 0。
// 注意:"半成品"不再是物料品类(2026-09-22),且含"成品"子串,必须先排除再判成品。
func parseItemType(s string) int {
s = strings.TrimSpace(s)
if s == "" {
@@ -511,13 +514,13 @@ func parseItemType(s string) int {
case strings.Contains(s, "原材料"):
return 1
case strings.Contains(s, "半成品"):
return 2
return 0 // 半成品已不是物料品类,导入该行按"品类无法识别"整体拒绝
case strings.Contains(s, "成品"):
return 3
case strings.Contains(s, "其他"):
return 4
}
if n := atoi(s, 0); n >= 1 && n <= 4 {
if n := atoi(s, 0); n == 1 || n == 3 || n == 4 {
return n
}
return 0
@@ -653,7 +656,7 @@ func excelMaterialImportHandler(ctx *svc.ServiceContext) http.HandlerFunc {
continue
}
if catCol >= 0 && cell(catCol) != "" && pr.itemType == 0 {
errs = append(errs, importErr{pr.row, pr.code, "品类无法识别,请填写「原材料/半成品/成品/其他」(兼容 1/2/3/4)"})
errs = append(errs, importErr{pr.row, pr.code, "品类无法识别,请填写「原材料/成品/其他」(兼容 1/3/4;半成品不是物料品类)"})
continue
}
exists, _ := ctx.EntClient.Material.Query().