From 47573e44b0f0b5ec8ef2dbe45f266d4f388fc9ce Mon Sep 17 00:00:00 2001
From: SunYF <123@hard_man.com>
Date: Tue, 1 Sep 2026 14:30:26 +0800
Subject: [PATCH] =?UTF-8?q?feat&fix:=20=E5=AE=8C=E5=96=84=E5=8D=8A?=
=?UTF-8?q?=E6=88=90=E5=93=81/=E5=BA=8F=E5=88=97=E5=8F=B7=E9=97=AD?=
=?UTF-8?q?=E7=8E=AF=E6=B5=81=E8=BD=AC=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
1. 调整物料编码字段为可空,优化注释说明
2. 修复Vite构建自动清空产物目录冲突问题
3. 优化前端提示文案与表单占位符
4. 为各前端项目添加内联SVG图标
5. 重构MES半成品流转逻辑,不再静默吞掉WMS错误并记录日志
6. 生成并添加空的WMS客户端静态文件
7. 完善Ent ORM模型的空值支持与查询谓词
8. 优化半成品入库接口,支持doneProcessCodes数组格式,新增SN反查物料编码逻辑
9. 更新帮助文档与操作手册
---
bj_power_dashboard/index.html | 4 +-
bj_power_mes/frontend/index.html | 2 +
bj_power_mes/internal/logic/semi.go | 7 +++-
bj_power_wms/ent/migrate/schema.go | 4 +-
bj_power_wms/ent/mutation.go | 38 +++++++++++++++++++
bj_power_wms/ent/semifinished.go | 2 +-
bj_power_wms/ent/semifinished/where.go | 10 +++++
bj_power_wms/ent/semifinished_create.go | 31 +++++++++++++--
bj_power_wms/ent/semifinished_update.go | 18 +++++++++
bj_power_wms/ent/serialnumber.go | 2 +-
bj_power_wms/ent/serialnumber/where.go | 10 +++++
bj_power_wms/ent/serialnumber_create.go | 31 +++++++++++++--
bj_power_wms/ent/serialnumber_update.go | 18 +++++++++
bj_power_wms/internal/handler/misc.go | 37 +++++++++++++++---
bj_power_wms/schema/semi_finished.go | 2 +-
bj_power_wms/schema/serial_number.go | 2 +-
bj_power_wms_client/frontend/index.html | 4 +-
bj_power_wms_client/frontend/src/help.js | 17 ++++++---
.../frontend/src/pages/Inspection.vue | 2 +-
.../frontend/src/pages/Semi.vue | 2 +-
.../frontend/src/pages/Stocktake.vue | 2 +-
bj_power_wms_client/frontend/vite.config.js | 4 +-
bj_power_wms_client/web/static/index.html | 15 ++++++++
bj_power_workstation/frontend/index.html | 2 +
操作手册.md | 33 ++++++++++++++++
25 files changed, 267 insertions(+), 32 deletions(-)
create mode 100644 bj_power_wms_client/web/static/index.html
diff --git a/bj_power_dashboard/index.html b/bj_power_dashboard/index.html
index 5bb281c..4a04c78 100644
--- a/bj_power_dashboard/index.html
+++ b/bj_power_dashboard/index.html
@@ -3,7 +3,9 @@
- 生产看板 - 北京电力智能产线
+ 生产看板
+
+
diff --git a/bj_power_mes/frontend/index.html b/bj_power_mes/frontend/index.html
index 1262f02..7d18668 100644
--- a/bj_power_mes/frontend/index.html
+++ b/bj_power_mes/frontend/index.html
@@ -4,6 +4,8 @@
MES 产线控制
+
+
diff --git a/bj_power_mes/internal/logic/semi.go b/bj_power_mes/internal/logic/semi.go
index 842170d..219ef1e 100644
--- a/bj_power_mes/internal/logic/semi.go
+++ b/bj_power_mes/internal/logic/semi.go
@@ -31,7 +31,8 @@ func (s *Service) SemiFlow(ctx context.Context, req SemiReq, operator string) er
if err != nil {
return err
}
- // 调用 WMS 内部接口
+ // 调用 WMS 内部接口(本地 SemiFlow 已保存,下面把 WMS 同步结果如实返回,
+ // 不再静默吞掉——WMS 不可达或校验失败时必须让调用方感知,才能形成闭环)。
var wmsErr error
if action == "INBOUND" {
wmsErr = s.ctx.Wms.SemiInbound(ctx, req.Sn, req.OrderNo, req.DoneProcessCodes, operator)
@@ -39,7 +40,9 @@ func (s *Service) SemiFlow(ctx context.Context, req SemiReq, operator string) er
wmsErr = s.ctx.Wms.SemiOutbound(ctx, req.Sn, req.OrderNo, req.DoneProcessCodes, operator)
}
if wmsErr != nil {
- _ = wmsErr
+ s.ctx.EventLog.Write(ctx, "semi.flow.wms_error", req.OrderNo, operator, "semi_flow", req.Sn,
+ "WMS 同步失败", map[string]any{"action": action, "error": wmsErr.Error()})
+ return wmsErr
}
s.ctx.EventLog.Write(ctx, "semi.flow", req.OrderNo, operator, "semi_flow", req.Sn, "半成品流转",
map[string]any{"action": action, "doneProcessCodes": req.DoneProcessCodes})
diff --git a/bj_power_wms/ent/migrate/schema.go b/bj_power_wms/ent/migrate/schema.go
index d133d50..347b45b 100644
--- a/bj_power_wms/ent/migrate/schema.go
+++ b/bj_power_wms/ent/migrate/schema.go
@@ -373,7 +373,7 @@ var (
SemiFinishedsColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt, Increment: true},
{Name: "sn", Type: field.TypeString, Unique: true},
- {Name: "material_code", Type: field.TypeString},
+ {Name: "material_code", Type: field.TypeString, Nullable: true},
{Name: "completed_process", Type: field.TypeString, Nullable: true},
{Name: "quantity", Type: field.TypeInt, Default: 1},
{Name: "zone_code", Type: field.TypeString, Nullable: true},
@@ -404,7 +404,7 @@ var (
SerialNumbersColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt, Increment: true},
{Name: "sn_code", Type: field.TypeString, Unique: true},
- {Name: "material_code", Type: field.TypeString},
+ {Name: "material_code", Type: field.TypeString, Nullable: true},
{Name: "batch_no", Type: field.TypeString, Nullable: true},
{Name: "status", Type: field.TypeString, Default: "在库"},
{Name: "current_zone", Type: field.TypeString, Nullable: true},
diff --git a/bj_power_wms/ent/mutation.go b/bj_power_wms/ent/mutation.go
index 0da6da6..838c252 100644
--- a/bj_power_wms/ent/mutation.go
+++ b/bj_power_wms/ent/mutation.go
@@ -10250,9 +10250,22 @@ func (m *SemiFinishedMutation) OldMaterialCode(ctx context.Context) (v string, e
return oldValue.MaterialCode, nil
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (m *SemiFinishedMutation) ClearMaterialCode() {
+ m.material_code = nil
+ m.clearedFields[semifinished.FieldMaterialCode] = struct{}{}
+}
+
+// MaterialCodeCleared returns if the "material_code" field was cleared in this mutation.
+func (m *SemiFinishedMutation) MaterialCodeCleared() bool {
+ _, ok := m.clearedFields[semifinished.FieldMaterialCode]
+ return ok
+}
+
// ResetMaterialCode resets all changes to the "material_code" field.
func (m *SemiFinishedMutation) ResetMaterialCode() {
m.material_code = nil
+ delete(m.clearedFields, semifinished.FieldMaterialCode)
}
// SetCompletedProcess sets the "completed_process" field.
@@ -10862,6 +10875,9 @@ func (m *SemiFinishedMutation) AddField(name string, value ent.Value) error {
// mutation.
func (m *SemiFinishedMutation) ClearedFields() []string {
var fields []string
+ if m.FieldCleared(semifinished.FieldMaterialCode) {
+ fields = append(fields, semifinished.FieldMaterialCode)
+ }
if m.FieldCleared(semifinished.FieldCompletedProcess) {
fields = append(fields, semifinished.FieldCompletedProcess)
}
@@ -10885,6 +10901,9 @@ func (m *SemiFinishedMutation) FieldCleared(name string) bool {
// error if the field is not defined in the schema.
func (m *SemiFinishedMutation) ClearField(name string) error {
switch name {
+ case semifinished.FieldMaterialCode:
+ m.ClearMaterialCode()
+ return nil
case semifinished.FieldCompletedProcess:
m.ClearCompletedProcess()
return nil
@@ -11171,9 +11190,22 @@ func (m *SerialNumberMutation) OldMaterialCode(ctx context.Context) (v string, e
return oldValue.MaterialCode, nil
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (m *SerialNumberMutation) ClearMaterialCode() {
+ m.material_code = nil
+ m.clearedFields[serialnumber.FieldMaterialCode] = struct{}{}
+}
+
+// MaterialCodeCleared returns if the "material_code" field was cleared in this mutation.
+func (m *SerialNumberMutation) MaterialCodeCleared() bool {
+ _, ok := m.clearedFields[serialnumber.FieldMaterialCode]
+ return ok
+}
+
// ResetMaterialCode resets all changes to the "material_code" field.
func (m *SerialNumberMutation) ResetMaterialCode() {
m.material_code = nil
+ delete(m.clearedFields, serialnumber.FieldMaterialCode)
}
// SetBatchNo sets the "batch_no" field.
@@ -11877,6 +11909,9 @@ func (m *SerialNumberMutation) AddField(name string, value ent.Value) error {
// mutation.
func (m *SerialNumberMutation) ClearedFields() []string {
var fields []string
+ if m.FieldCleared(serialnumber.FieldMaterialCode) {
+ fields = append(fields, serialnumber.FieldMaterialCode)
+ }
if m.FieldCleared(serialnumber.FieldBatchNo) {
fields = append(fields, serialnumber.FieldBatchNo)
}
@@ -11906,6 +11941,9 @@ func (m *SerialNumberMutation) FieldCleared(name string) bool {
// error if the field is not defined in the schema.
func (m *SerialNumberMutation) ClearField(name string) error {
switch name {
+ case serialnumber.FieldMaterialCode:
+ m.ClearMaterialCode()
+ return nil
case serialnumber.FieldBatchNo:
m.ClearBatchNo()
return nil
diff --git a/bj_power_wms/ent/semifinished.go b/bj_power_wms/ent/semifinished.go
index 138e8c4..83bba8e 100644
--- a/bj_power_wms/ent/semifinished.go
+++ b/bj_power_wms/ent/semifinished.go
@@ -18,7 +18,7 @@ type SemiFinished struct {
ID int `json:"id,omitempty"`
// 半成品 SN
Sn string `json:"sn,omitempty"`
- // 物料编码
+ // 物料编码(MES 未传时按 SN 反查,可空)
MaterialCode string `json:"materialCode,omitempty"`
// 已完成工序(如 135)
CompletedProcess string `json:"completedProcess,omitempty"`
diff --git a/bj_power_wms/ent/semifinished/where.go b/bj_power_wms/ent/semifinished/where.go
index 415af2b..c44ad5f 100644
--- a/bj_power_wms/ent/semifinished/where.go
+++ b/bj_power_wms/ent/semifinished/where.go
@@ -218,6 +218,16 @@ func MaterialCodeHasSuffix(v string) predicate.SemiFinished {
return predicate.SemiFinished(sql.FieldHasSuffix(FieldMaterialCode, v))
}
+// MaterialCodeIsNil applies the IsNil predicate on the "material_code" field.
+func MaterialCodeIsNil() predicate.SemiFinished {
+ return predicate.SemiFinished(sql.FieldIsNull(FieldMaterialCode))
+}
+
+// MaterialCodeNotNil applies the NotNil predicate on the "material_code" field.
+func MaterialCodeNotNil() predicate.SemiFinished {
+ return predicate.SemiFinished(sql.FieldNotNull(FieldMaterialCode))
+}
+
// MaterialCodeEqualFold applies the EqualFold predicate on the "material_code" field.
func MaterialCodeEqualFold(v string) predicate.SemiFinished {
return predicate.SemiFinished(sql.FieldEqualFold(FieldMaterialCode, v))
diff --git a/bj_power_wms/ent/semifinished_create.go b/bj_power_wms/ent/semifinished_create.go
index 1b773d1..a5e56e0 100644
--- a/bj_power_wms/ent/semifinished_create.go
+++ b/bj_power_wms/ent/semifinished_create.go
@@ -33,6 +33,14 @@ func (_c *SemiFinishedCreate) SetMaterialCode(v string) *SemiFinishedCreate {
return _c
}
+// SetNillableMaterialCode sets the "material_code" field if the given value is not nil.
+func (_c *SemiFinishedCreate) SetNillableMaterialCode(v *string) *SemiFinishedCreate {
+ if v != nil {
+ _c.SetMaterialCode(*v)
+ }
+ return _c
+}
+
// SetCompletedProcess sets the "completed_process" field.
func (_c *SemiFinishedCreate) SetCompletedProcess(v string) *SemiFinishedCreate {
_c.mutation.SetCompletedProcess(v)
@@ -189,9 +197,6 @@ func (_c *SemiFinishedCreate) check() error {
if _, ok := _c.mutation.Sn(); !ok {
return &ValidationError{Name: "sn", err: errors.New(`ent: missing required field "SemiFinished.sn"`)}
}
- if _, ok := _c.mutation.MaterialCode(); !ok {
- return &ValidationError{Name: "material_code", err: errors.New(`ent: missing required field "SemiFinished.material_code"`)}
- }
if _, ok := _c.mutation.Quantity(); !ok {
return &ValidationError{Name: "quantity", err: errors.New(`ent: missing required field "SemiFinished.quantity"`)}
}
@@ -343,6 +348,12 @@ func (u *SemiFinishedUpsert) UpdateMaterialCode() *SemiFinishedUpsert {
return u
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (u *SemiFinishedUpsert) ClearMaterialCode() *SemiFinishedUpsert {
+ u.SetNull(semifinished.FieldMaterialCode)
+ return u
+}
+
// SetCompletedProcess sets the "completed_process" field.
func (u *SemiFinishedUpsert) SetCompletedProcess(v string) *SemiFinishedUpsert {
u.Set(semifinished.FieldCompletedProcess, v)
@@ -531,6 +542,13 @@ func (u *SemiFinishedUpsertOne) UpdateMaterialCode() *SemiFinishedUpsertOne {
})
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (u *SemiFinishedUpsertOne) ClearMaterialCode() *SemiFinishedUpsertOne {
+ return u.Update(func(s *SemiFinishedUpsert) {
+ s.ClearMaterialCode()
+ })
+}
+
// SetCompletedProcess sets the "completed_process" field.
func (u *SemiFinishedUpsertOne) SetCompletedProcess(v string) *SemiFinishedUpsertOne {
return u.Update(func(s *SemiFinishedUpsert) {
@@ -903,6 +921,13 @@ func (u *SemiFinishedUpsertBulk) UpdateMaterialCode() *SemiFinishedUpsertBulk {
})
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (u *SemiFinishedUpsertBulk) ClearMaterialCode() *SemiFinishedUpsertBulk {
+ return u.Update(func(s *SemiFinishedUpsert) {
+ s.ClearMaterialCode()
+ })
+}
+
// SetCompletedProcess sets the "completed_process" field.
func (u *SemiFinishedUpsertBulk) SetCompletedProcess(v string) *SemiFinishedUpsertBulk {
return u.Update(func(s *SemiFinishedUpsert) {
diff --git a/bj_power_wms/ent/semifinished_update.go b/bj_power_wms/ent/semifinished_update.go
index 8e89224..57925ad 100644
--- a/bj_power_wms/ent/semifinished_update.go
+++ b/bj_power_wms/ent/semifinished_update.go
@@ -55,6 +55,12 @@ func (_u *SemiFinishedUpdate) SetNillableMaterialCode(v *string) *SemiFinishedUp
return _u
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (_u *SemiFinishedUpdate) ClearMaterialCode() *SemiFinishedUpdate {
+ _u.mutation.ClearMaterialCode()
+ return _u
+}
+
// SetCompletedProcess sets the "completed_process" field.
func (_u *SemiFinishedUpdate) SetCompletedProcess(v string) *SemiFinishedUpdate {
_u.mutation.SetCompletedProcess(v)
@@ -239,6 +245,9 @@ func (_u *SemiFinishedUpdate) sqlSave(ctx context.Context) (_node int, err error
if value, ok := _u.mutation.MaterialCode(); ok {
_spec.SetField(semifinished.FieldMaterialCode, field.TypeString, value)
}
+ if _u.mutation.MaterialCodeCleared() {
+ _spec.ClearField(semifinished.FieldMaterialCode, field.TypeString)
+ }
if value, ok := _u.mutation.CompletedProcess(); ok {
_spec.SetField(semifinished.FieldCompletedProcess, field.TypeString, value)
}
@@ -326,6 +335,12 @@ func (_u *SemiFinishedUpdateOne) SetNillableMaterialCode(v *string) *SemiFinishe
return _u
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (_u *SemiFinishedUpdateOne) ClearMaterialCode() *SemiFinishedUpdateOne {
+ _u.mutation.ClearMaterialCode()
+ return _u
+}
+
// SetCompletedProcess sets the "completed_process" field.
func (_u *SemiFinishedUpdateOne) SetCompletedProcess(v string) *SemiFinishedUpdateOne {
_u.mutation.SetCompletedProcess(v)
@@ -540,6 +555,9 @@ func (_u *SemiFinishedUpdateOne) sqlSave(ctx context.Context) (_node *SemiFinish
if value, ok := _u.mutation.MaterialCode(); ok {
_spec.SetField(semifinished.FieldMaterialCode, field.TypeString, value)
}
+ if _u.mutation.MaterialCodeCleared() {
+ _spec.ClearField(semifinished.FieldMaterialCode, field.TypeString)
+ }
if value, ok := _u.mutation.CompletedProcess(); ok {
_spec.SetField(semifinished.FieldCompletedProcess, field.TypeString, value)
}
diff --git a/bj_power_wms/ent/serialnumber.go b/bj_power_wms/ent/serialnumber.go
index 95325b0..91b37b5 100644
--- a/bj_power_wms/ent/serialnumber.go
+++ b/bj_power_wms/ent/serialnumber.go
@@ -18,7 +18,7 @@ type SerialNumber struct {
ID int `json:"id,omitempty"`
// 序列号
SnCode string `json:"snCode,omitempty"`
- // 物料编码
+ // 物料编码(可为空)
MaterialCode string `json:"materialCode,omitempty"`
// 所属批次
BatchNo string `json:"batchNo,omitempty"`
diff --git a/bj_power_wms/ent/serialnumber/where.go b/bj_power_wms/ent/serialnumber/where.go
index 80174a2..94919ce 100644
--- a/bj_power_wms/ent/serialnumber/where.go
+++ b/bj_power_wms/ent/serialnumber/where.go
@@ -228,6 +228,16 @@ func MaterialCodeHasSuffix(v string) predicate.SerialNumber {
return predicate.SerialNumber(sql.FieldHasSuffix(FieldMaterialCode, v))
}
+// MaterialCodeIsNil applies the IsNil predicate on the "material_code" field.
+func MaterialCodeIsNil() predicate.SerialNumber {
+ return predicate.SerialNumber(sql.FieldIsNull(FieldMaterialCode))
+}
+
+// MaterialCodeNotNil applies the NotNil predicate on the "material_code" field.
+func MaterialCodeNotNil() predicate.SerialNumber {
+ return predicate.SerialNumber(sql.FieldNotNull(FieldMaterialCode))
+}
+
// MaterialCodeEqualFold applies the EqualFold predicate on the "material_code" field.
func MaterialCodeEqualFold(v string) predicate.SerialNumber {
return predicate.SerialNumber(sql.FieldEqualFold(FieldMaterialCode, v))
diff --git a/bj_power_wms/ent/serialnumber_create.go b/bj_power_wms/ent/serialnumber_create.go
index 64c6957..6df9678 100644
--- a/bj_power_wms/ent/serialnumber_create.go
+++ b/bj_power_wms/ent/serialnumber_create.go
@@ -33,6 +33,14 @@ func (_c *SerialNumberCreate) SetMaterialCode(v string) *SerialNumberCreate {
return _c
}
+// SetNillableMaterialCode sets the "material_code" field if the given value is not nil.
+func (_c *SerialNumberCreate) SetNillableMaterialCode(v *string) *SerialNumberCreate {
+ if v != nil {
+ _c.SetMaterialCode(*v)
+ }
+ return _c
+}
+
// SetBatchNo sets the "batch_no" field.
func (_c *SerialNumberCreate) SetBatchNo(v string) *SerialNumberCreate {
_c.mutation.SetBatchNo(v)
@@ -217,9 +225,6 @@ func (_c *SerialNumberCreate) check() error {
if _, ok := _c.mutation.SnCode(); !ok {
return &ValidationError{Name: "sn_code", err: errors.New(`ent: missing required field "SerialNumber.sn_code"`)}
}
- if _, ok := _c.mutation.MaterialCode(); !ok {
- return &ValidationError{Name: "material_code", err: errors.New(`ent: missing required field "SerialNumber.material_code"`)}
- }
if _, ok := _c.mutation.Status(); !ok {
return &ValidationError{Name: "status", err: errors.New(`ent: missing required field "SerialNumber.status"`)}
}
@@ -379,6 +384,12 @@ func (u *SerialNumberUpsert) UpdateMaterialCode() *SerialNumberUpsert {
return u
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (u *SerialNumberUpsert) ClearMaterialCode() *SerialNumberUpsert {
+ u.SetNull(serialnumber.FieldMaterialCode)
+ return u
+}
+
// SetBatchNo sets the "batch_no" field.
func (u *SerialNumberUpsert) SetBatchNo(v string) *SerialNumberUpsert {
u.Set(serialnumber.FieldBatchNo, v)
@@ -597,6 +608,13 @@ func (u *SerialNumberUpsertOne) UpdateMaterialCode() *SerialNumberUpsertOne {
})
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (u *SerialNumberUpsertOne) ClearMaterialCode() *SerialNumberUpsertOne {
+ return u.Update(func(s *SerialNumberUpsert) {
+ s.ClearMaterialCode()
+ })
+}
+
// SetBatchNo sets the "batch_no" field.
func (u *SerialNumberUpsertOne) SetBatchNo(v string) *SerialNumberUpsertOne {
return u.Update(func(s *SerialNumberUpsert) {
@@ -1004,6 +1022,13 @@ func (u *SerialNumberUpsertBulk) UpdateMaterialCode() *SerialNumberUpsertBulk {
})
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (u *SerialNumberUpsertBulk) ClearMaterialCode() *SerialNumberUpsertBulk {
+ return u.Update(func(s *SerialNumberUpsert) {
+ s.ClearMaterialCode()
+ })
+}
+
// SetBatchNo sets the "batch_no" field.
func (u *SerialNumberUpsertBulk) SetBatchNo(v string) *SerialNumberUpsertBulk {
return u.Update(func(s *SerialNumberUpsert) {
diff --git a/bj_power_wms/ent/serialnumber_update.go b/bj_power_wms/ent/serialnumber_update.go
index 7fa8f74..2546d4d 100644
--- a/bj_power_wms/ent/serialnumber_update.go
+++ b/bj_power_wms/ent/serialnumber_update.go
@@ -55,6 +55,12 @@ func (_u *SerialNumberUpdate) SetNillableMaterialCode(v *string) *SerialNumberUp
return _u
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (_u *SerialNumberUpdate) ClearMaterialCode() *SerialNumberUpdate {
+ _u.mutation.ClearMaterialCode()
+ return _u
+}
+
// SetBatchNo sets the "batch_no" field.
func (_u *SerialNumberUpdate) SetBatchNo(v string) *SerialNumberUpdate {
_u.mutation.SetBatchNo(v)
@@ -272,6 +278,9 @@ func (_u *SerialNumberUpdate) sqlSave(ctx context.Context) (_node int, err error
if value, ok := _u.mutation.MaterialCode(); ok {
_spec.SetField(serialnumber.FieldMaterialCode, field.TypeString, value)
}
+ if _u.mutation.MaterialCodeCleared() {
+ _spec.ClearField(serialnumber.FieldMaterialCode, field.TypeString)
+ }
if value, ok := _u.mutation.BatchNo(); ok {
_spec.SetField(serialnumber.FieldBatchNo, field.TypeString, value)
}
@@ -368,6 +377,12 @@ func (_u *SerialNumberUpdateOne) SetNillableMaterialCode(v *string) *SerialNumbe
return _u
}
+// ClearMaterialCode clears the value of the "material_code" field.
+func (_u *SerialNumberUpdateOne) ClearMaterialCode() *SerialNumberUpdateOne {
+ _u.mutation.ClearMaterialCode()
+ return _u
+}
+
// SetBatchNo sets the "batch_no" field.
func (_u *SerialNumberUpdateOne) SetBatchNo(v string) *SerialNumberUpdateOne {
_u.mutation.SetBatchNo(v)
@@ -615,6 +630,9 @@ func (_u *SerialNumberUpdateOne) sqlSave(ctx context.Context) (_node *SerialNumb
if value, ok := _u.mutation.MaterialCode(); ok {
_spec.SetField(serialnumber.FieldMaterialCode, field.TypeString, value)
}
+ if _u.mutation.MaterialCodeCleared() {
+ _spec.ClearField(serialnumber.FieldMaterialCode, field.TypeString)
+ }
if value, ok := _u.mutation.BatchNo(); ok {
_spec.SetField(serialnumber.FieldBatchNo, field.TypeString, value)
}
diff --git a/bj_power_wms/internal/handler/misc.go b/bj_power_wms/internal/handler/misc.go
index 9774dfd..c2460cb 100644
--- a/bj_power_wms/internal/handler/misc.go
+++ b/bj_power_wms/internal/handler/misc.go
@@ -3,6 +3,8 @@ package handler
import (
"encoding/json"
"net/http"
+ "strconv"
+ "strings"
"bj_power_wms/ent"
"bj_power_wms/ent/ordermaterialledger"
@@ -15,11 +17,15 @@ import (
// 半成品 / 包装 / 台账 相关(盘点见 stocktake.go)
// semiInboundHandler 半成品入库(携带已完成工序)
+// 与 MES 闭环:MES 工位报工暂存退库时调用本接口,把半成品 SN 入 WMS 库。
+// 为保持两系统解耦,materialCode 不强制要求——优先用请求传入,
+// 其次按 SN 反查 WMS 序列号台账,都没有则留空(SN 本身即追溯锚点)。
func semiInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req struct {
Sn string `json:"sn"`
MaterialCode string `json:"materialCode"`
+ DoneProcessCodes []int `json:"doneProcessCodes"`
CompletedProcess string `json:"completedProcess"`
ZoneCode string `json:"zoneCode"`
OrderNo string `json:"orderNo"`
@@ -29,8 +35,8 @@ func semiInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
fail(w, http.StatusBadRequest, "参数错误")
return
}
- if req.Sn == "" || req.MaterialCode == "" {
- fail(w, http.StatusBadRequest, "sn 和 materialCode 必填")
+ if req.Sn == "" {
+ fail(w, http.StatusBadRequest, "sn 必填")
return
}
@@ -46,10 +52,29 @@ func semiInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return
}
+ // 已完成工序:MES 传 doneProcessCodes([]int) 优先,否则用 completedProcess 字符串
+ completed := req.CompletedProcess
+ if len(req.DoneProcessCodes) > 0 {
+ parts := make([]string, 0, len(req.DoneProcessCodes))
+ for _, c := range req.DoneProcessCodes {
+ parts = append(parts, strconv.Itoa(c))
+ }
+ completed = strings.Join(parts, ",")
+ }
+
+ // 物料编码:优先请求传入,其次按 SN 反查序列号台账
+ materialCode := req.MaterialCode
+ if materialCode == "" {
+ if snRec, e := ctx.EntClient.SerialNumber.Query().
+ Where(serialnumber.SnCodeEQ(req.Sn)).Only(ctx0()); e == nil {
+ materialCode = snRec.MaterialCode
+ }
+ }
+
rec, err := ctx.EntClient.SemiFinished.Create().
SetSn(req.Sn).
- SetMaterialCode(req.MaterialCode).
- SetNillableCompletedProcess(strPtr(req.CompletedProcess)).
+ SetNillableMaterialCode(strPtr(materialCode)).
+ SetNillableCompletedProcess(strPtr(completed)).
SetNillableZoneCode(strPtr(req.ZoneCode)).
SetStatus("在库").
SetNillableOrderNo(strPtr(req.OrderNo)).
@@ -59,10 +84,10 @@ func semiInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return
}
- // 同时记入 SN 台账(半成品也是精密件)
+ // 同时记入 SN 台账(半成品也是精密件,便于按 SN 追溯)
ctx.EntClient.SerialNumber.Create().
SetSnCode(req.Sn).
- SetMaterialCode(req.MaterialCode).
+ SetNillableMaterialCode(strPtr(materialCode)).
SetStatus("在库").
SetNillableCurrentZone(strPtr(req.ZoneCode)).
SaveX(ctx0())
diff --git a/bj_power_wms/schema/semi_finished.go b/bj_power_wms/schema/semi_finished.go
index 83ca7ac..10abb88 100644
--- a/bj_power_wms/schema/semi_finished.go
+++ b/bj_power_wms/schema/semi_finished.go
@@ -15,7 +15,7 @@ type SemiFinished struct {
func (SemiFinished) Fields() []ent.Field {
return []ent.Field{
field.String("sn").Unique().Comment("半成品 SN"),
- field.String("material_code").Comment("物料编码"),
+ field.String("material_code").Optional().Comment("物料编码(MES 未传时按 SN 反查,可空)"),
field.String("completed_process").Optional().Comment("已完成工序(如 135)"),
field.Int("quantity").Default(1).Comment("数量"),
field.String("zone_code").Optional().Comment("所在区域"),
diff --git a/bj_power_wms/schema/serial_number.go b/bj_power_wms/schema/serial_number.go
index 12bf3d4..ea595b8 100644
--- a/bj_power_wms/schema/serial_number.go
+++ b/bj_power_wms/schema/serial_number.go
@@ -14,7 +14,7 @@ type SerialNumber struct {
func (SerialNumber) Fields() []ent.Field {
return []ent.Field{
field.String("sn_code").Unique().Comment("序列号"),
- field.String("material_code").Comment("物料编码"),
+ field.String("material_code").Optional().Comment("物料编码(可为空)"),
field.String("batch_no").Optional().Comment("所属批次"),
// 状态:在库/锁定/出库/使用/报废
field.String("status").Default("在库").Comment("在库/锁定/出库/使用/报废"),
diff --git a/bj_power_wms_client/frontend/index.html b/bj_power_wms_client/frontend/index.html
index c17cd40..cd43927 100644
--- a/bj_power_wms_client/frontend/index.html
+++ b/bj_power_wms_client/frontend/index.html
@@ -4,9 +4,11 @@
库房客户端
+
+
-