feat&refactor: 2026-09-22 半成品业务模型重构与功能完善
- 重构半成品流转逻辑:进度权威源改为 workpiece.currentStationNo,新增 completedText 快照字段,废除 doneProcessCodes - 清理物料品类中半成品类型,存量数据幂等清理,调整物料管理方式文案为批次/序列号 - 新增日排产状态专用更新接口,修复工单工艺校验逻辑 - 新增物料档案代理接口、深路径文件下载接口 - 优化前端界面文案与工位选择逻辑,补充追溯页半成品流转展示 - 调整WMS端物料品类校验与入库接口契约 - 新增/更新数据库表结构与实体类代码
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package enttest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bj_power_wms"
|
||||
"bj_power_wms/ent"
|
||||
"bj_power_wms/ent/migrate"
|
||||
|
||||
// required by schema hooks.
|
||||
_ "bj_power_wms/runtime"
|
||||
|
||||
"bj_power_wms/migrate"
|
||||
|
||||
"entgo.io/ent/dialect/sql/schema"
|
||||
)
|
||||
|
||||
@@ -26,13 +26,13 @@ type (
|
||||
Option func(*options)
|
||||
|
||||
options struct {
|
||||
opts []bj_power_wms.Option
|
||||
opts []ent.Option
|
||||
migrateOpts []schema.MigrateOption
|
||||
}
|
||||
)
|
||||
|
||||
// WithOptions forwards options to client creation.
|
||||
func WithOptions(opts ...bj_power_wms.Option) Option {
|
||||
func WithOptions(opts ...ent.Option) Option {
|
||||
return func(o *options) {
|
||||
o.opts = append(o.opts, opts...)
|
||||
}
|
||||
@@ -53,10 +53,10 @@ func newOptions(opts []Option) *options {
|
||||
return o
|
||||
}
|
||||
|
||||
// Open calls bj_power_wms.Open and auto-run migration.
|
||||
func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *bj_power_wms.Client {
|
||||
// Open calls ent.Open and auto-run migration.
|
||||
func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client {
|
||||
o := newOptions(opts)
|
||||
c, err := bj_power_wms.Open(driverName, dataSourceName, o.opts...)
|
||||
c, err := ent.Open(driverName, dataSourceName, o.opts...)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.FailNow()
|
||||
@@ -65,14 +65,14 @@ func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *bj_pow
|
||||
return c
|
||||
}
|
||||
|
||||
// NewClient calls bj_power_wms.NewClient and auto-run migration.
|
||||
func NewClient(t TestingT, opts ...Option) *bj_power_wms.Client {
|
||||
// NewClient calls ent.NewClient and auto-run migration.
|
||||
func NewClient(t TestingT, opts ...Option) *ent.Client {
|
||||
o := newOptions(opts)
|
||||
c := bj_power_wms.NewClient(o.opts...)
|
||||
c := ent.NewClient(o.opts...)
|
||||
migrateSchema(t, c, o)
|
||||
return c
|
||||
}
|
||||
func migrateSchema(t TestingT, c *bj_power_wms.Client, o *options) {
|
||||
func migrateSchema(t TestingT, c *ent.Client, o *options) {
|
||||
tables, err := schema.CopyTables(migrate.Tables)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -68,7 +68,7 @@ export const helpOutbound = {
|
||||
{ name: '备料出库-目标工位', source: '下拉选择 DOCK01~DOCK20(选填,可过滤搜索)。', purpose: 'AGV 配送送达的接驳台(toDock 参数)', fill: '选择如 DOCK05;不选默认运到产线入口 DOCK01' },
|
||||
{ name: '备料出库-一键分配出库', source: '系统自动按 FIFO 分配。数据来自合格区Z02的批次库存。', purpose: '从合格区按先进先出凑够缺口并出库', fill: '点按钮,系统自动算批次并二次确认' },
|
||||
{ name: '通用出库-物料', source: '下拉选择(全项目统一组件)。', purpose: '选定要出库的物料', fill: '下拉显示 编码/图号/类型(电气件/结构件/其他)/品类(原材料/半成品/成品/其他),支持远程搜索' },
|
||||
{ name: '通用出库-出库类型', source: '系统自动判定(来自物料档案的管理粒度)。', purpose: '决定走批次扣减还是 SN 扣减', fill: '只读:选物料后自动显示结构件(批次)或电气件(SN),无需也不允许手选' },
|
||||
{ name: '通用出库-出库类型', source: '系统自动判定(来自物料档案的管理粒度)。', purpose: '决定走批次扣减还是 SN 扣减', fill: '只读:选物料后自动显示批次或序列号,无需也不允许手选' },
|
||||
{ name: '通用出库-出库类别', source: '下拉点选(纯标签记录,不联动任何地方)。', purpose: '区分退料/退货/样品/报废/发货/其他,列表与出库单均显示', fill: '必选;选「其他」时需在备注填写具体原因' },
|
||||
{ name: '通用出库-归属', source: '下拉选归属类型 + 手填归属编号。', purpose: '记录出库归属(工单编号/科技项目号/其他),仅追溯不联动 MES', fill: '默认「其他」;选工单编号/科技项目号时归属编号必填,长度≤64' },
|
||||
{ name: '通用出库-目标工位', source: '下拉选择(来自 MES 工位列表,不允许手输)。', purpose: '出库送到哪个装配工位,出库记录留痕工位号', fill: '下拉选工位(可搜索);选填' },
|
||||
@@ -111,7 +111,7 @@ export const helpInspection = {
|
||||
'【三检分工与边界】\n· 来料检(incoming):对采购/外协到货、入库前的物料验收,按入库批次/SN 判定。合格才能入库上架,不合格隔离退货。\n· 过程检(process):对产线在制物料/半成品巡检,判定质量状态。\n· 完工检(finished):对 MES 回流的成品 SN 做最终检验(对象固定为成品 SN,无“批次”选项)。成品入库时质量状态为“未检”,完工检合格后置“合格”,成品方可发货;不合格可返修/让步接收。闭环:MES 报工→成品入库(未检)→WMS 完工检→合格→可发货。\n\n【检验做什么】把库存行的“质量状态”从未检翻转为合格/不合格,与存放区域无关。库存校验只取质量状态=合格的行参与出库/锁库。\n\n【报检数守恒】报检数 = 合格数 + 不合格数;合格数不得大于报检数;判定合格时合格数应等于报检数(否则请改判不合格并选处置方式)。\n\n【不合格处置(需求23 换修闭环)】判不合格必选处置:退货(须填货运单号、库存置待退) / 换修(隔离为不合格,等返修后重新报检) / 让步接收(审批后放行,质量状态置合格) / 报废 / 部分入库(仅结构件批次:一次只处理 1 个批次,按合格数拆行)。已判不合格的记录也可在列表里再次处置。\n\n【结构件 vs 电气件/其他的不合格口径】\n· 结构件(批次):一行数量 N,判不合格=整批隔离;“N 里坏 M 个”用「部分入库」填合格数 N−M,系统拆出 (N−M) 合格批次 + M 不合格批次。\n· 电气件(SN)/其他:逐个判定(检验数固定 1),每个 SN/件一条记录、一行库存,选中判不合格即隔离该件,无需拆分。\n\n【归属口径(需求22)】归属类型 = 工单编号 / 科技项目号 / 其他,默认“其他”。这里的“工单编号”是独立维度标签,与 MES 工单号不是同一东西;手动输入、不联动 MES、不校验格式(长度≤64)。\n\n【按物料统计】统计页需先选择物料再点“统计”,不做全表实时聚合。\n\n本页四个页签(录入在前、记录在后点击才加载):\n· 质量检验录入(默认打开):逐个判定——每一条待检目标(批次号/SN)独立成一行,分别选结论、填检验数/合格数,不合格数=检验数−合格数自动算出;整组点一次「提交」调 /inspection/batch-flip 原子翻转,多行同 id 自动去重。\n· 待检清单:按入库单分组展示(主行=入库单,展开看该单的批次/SN 明细与未检数量),支持整单送检、单条送检、跨行勾选送检;送检即把目标回填到「质量检验录入」并带入归属,免去手输编号。\n· 检验记录(点击才加载):历史判定记录,含「不合格数」列(=检验数−合格数,后端复核)。\n· 按物料统计:选物料后聚合其检验次数与合格率。\n\n菜单按业务分为来料/过程/完工三个入口,同一张表、同一接口,仅按检验类别默认过滤。每条检验记录可上传/查看附件(检测报告/照片)。',
|
||||
fields: [
|
||||
{ name: '三检边界', source: '菜单入口锁定检验类别。', purpose: '来料检=入库验收;过程检=在制巡检;完工检=成品 SN 终检', fill: '按左侧菜单进入对应页面,页内不再切换类别' },
|
||||
{ name: '目标类型', source: '单选,决定录入框标题与可选库存范围。完工检固定为 SN,不展示切换。', purpose: '检验对象:批次(结构件) / SN(电气件) / 其他(辅料·工装·试验设备,按 1 件判定)', fill: '批次 BATCH / 序列号 SN / 其他 OTHER(任一切换都会自动刷新“从库存选”下拉与可选库存范围)' },
|
||||
{ name: '目标类型', source: '单选,决定录入框标题与可选库存范围。完工检固定为 SN,不展示切换。', purpose: '检验对象:批次(结构件) / 序列号(电气件) / 其他(辅料·工装·试验设备,按 1 件判定)', fill: '批次 BATCH / 序列号 SN / 其他 OTHER(任一切换都会自动刷新“从库存选”下拉与可选库存范围)' },
|
||||
{ name: '检验结论', source: '单选。', purpose: '判定结果', fill: '合格 / 不合格' },
|
||||
{ name: '记录人 / 审核人', source: '手动填写(默认当前用户)。完工检显示为“审核人”。', purpose: '谁检验/审核的,追溯用', fill: '姓名' },
|
||||
{ name: '从库存选批次号/SN', source: '下拉选择,数据来自当前库存(按目标类型过滤;完工检只列成品 category=3)。', purpose: '避免手输编号、防止输错', fill: '在库存里挑待检的批次号/SN,自动加入清单' },
|
||||
@@ -158,8 +158,8 @@ export const helpStocktake = {
|
||||
export const helpSemi = {
|
||||
title: '半成品管理(流转)',
|
||||
overview:
|
||||
'产线工位"暂存/退回"的半成品先在此入库(记已完成工序),需要时再出库(重上线),MES 从下一工序继续;成品则由 MES 完工后自动回流入库(品类=成品),不经本页手工操作。\n\n闭环逻辑(与 MES 自动打通):\n' +
|
||||
'① 工位终端"暂存退库" → 调 MES 工序流转接口 → MES 自动调 WMS /api/internal/semi/inbound 入库(带 SN、工单号、已完成工序码)。\n' +
|
||||
'产线工位"暂存/退回"的半成品先在此入库(记"已完成至工位"快照),需要时再出库(重上线),MES 从下一工序继续;成品则由 MES 完工后自动回流入库(品类=成品),不经本页手工操作。\n\n闭环逻辑(与 MES 自动打通):\n' +
|
||||
'① 工位终端"暂存退库" → 调 MES 工序流转接口 → MES 自动调 WMS /api/internal/semi/inbound 入库(带 SN、工单号、completedText 展示快照)。\n' +
|
||||
'② WMS 收到后写入统一库存主表(品类=半成品),与原材料/成品同表管理——库存查询三视图、区域汇总、导出都能看到它。\n' +
|
||||
'③ 该件后续要接着做时,在本页"半成品出库"或 MES 重上线 → WMS /api/internal/semi/outbound 把状态置为出库。\n' +
|
||||
'④ MES 据此下发下一工序,工位继续装配,直至完工。\n\n' +
|
||||
@@ -169,8 +169,8 @@ export const helpSemi = {
|
||||
title: '半成品/成品入库',
|
||||
overview: '把产线退回的半成品或成品收进库房(手工录入或 MES 自动同步均走此接口)。',
|
||||
fields: [
|
||||
{ name: '物料', source: '下拉选择。来自物料档案(最近100条+模糊搜索)。', purpose: '入库物料(MES 自动同步时以请求传入为准,WMS 补齐物料名称)', fill: '选择图号' },
|
||||
{ name: '已完成工序', source: 'MES 自动带出(doneProcessCodes,如 [1,3,5]);手工录入填逗号分隔,如 1,3,5。', purpose: '该件已做到哪些工序,重上线时 MES 从下一工序继续', fill: '如 1,3,5,可空' },
|
||||
{ name: '物料', source: '下拉选择。来自物料档案(最近100条+模糊搜索,仅列成品品类 item_type=3)。', purpose: '入库物料(MES 自动同步时以请求传入为准,WMS 补齐物料名称)', fill: '选择图号' },
|
||||
{ name: '已完成至工位', source: 'MES 自动带出(completedText 展示快照);手工录入填文本,如"工位5"。', purpose: '该件进展到哪个工位的人类可读快照,WMS 只原样存展示、不解析', fill: '如 工位5,可空=未报工' },
|
||||
{ name: '工单号', source: '自动带出/手工填写。来自工单。', purpose: '来源工单', fill: '输入工单号' },
|
||||
{ name: '归属', source: '下拉:工单号 / 科技项目号 / 其他(必选,与入库管理同口径,不再有"无")。', purpose: '标记该件归属哪个工单或科技项目', fill: '必选一项;选"其他"可不填编号,选"工单号/科技项目号"须填归属编号' },
|
||||
{ name: '区域', source: '手动填写(可空)。', purpose: '存放库区', fill: '如 Z05' },
|
||||
@@ -274,14 +274,14 @@ export const helpAttachment = {
|
||||
export const helpMaterial = {
|
||||
title: '物料档案',
|
||||
overview:
|
||||
'定义每一种物料的字典:叫什么、什么规格、什么品类(原材料/半成品/成品/其他)、是【结构件(批次)】还是【电气件(SN)】。\n此处维护的物料会作为下拉选项出现在入库/出库/装箱等页面;其中"类型"直接决定后续入库方式——结构件走批次(一批多件)、电气件走 SN 逐件扫码(单件追溯)。\n\n品类来源:原材料=进货来的(外购);半成品、成品=自己生产的;其他=辅料/工装/试验设备等。成品还可以作为零部件,放进另一个成品的物料清单(BOM)里被再次加工成新的成品。\n\n品类说明:1=原材料(默认) / 2=半成品 / 3=成品 / 4=其他(辅料/工装/试验设备)。编码主数据单一来源在本表:MES 的「物料档案」页面即是本表中"成品"品类的视图(实时拉取本表,不双录)——两系统的「物料档案」指向同一份主数据,以本表为准。库存主表 inventories 的品类与其呼应。列表支持按品类筛选,导出含品类列。\n\n物料档案是库房的另一道地基:先建好物料,入库时才能选到;类型选错会导致入库方式与追溯粒度不符。\n\n命名说明:本档案维护的物料在出库/看板等页面统一以"图号"展示(客户口径)。安全库存在本档案维护,可用量低于它时会在「库房看板」首页触发缺货预警。',
|
||||
'定义每一种物料的字典:叫什么、什么规格、什么品类(原材料/成品/其他)、是【结构件(批次)】还是【电气件(SN)】。\n此处维护的物料会作为下拉选项出现在入库/出库/装箱等页面;其中"类型"直接决定后续入库方式——结构件走批次(一批多件)、电气件走 SN 逐件扫码(单件追溯)。\n\n品类来源:原材料=进货来的(外购);成品=自己生产的;其他=辅料/工装/试验设备等。成品还可以作为零部件,放进另一个成品的物料清单(BOM)里被再次加工成新的成品。\n\n品类说明:1=原材料(默认) / 3=成品 / 4=其他(辅料/工装/试验设备)。半成品不是物料品类(2026-09-22 定稿)——半成品是工件状态,由统一库存主表品类 category=2 承载,物料档案不再有半成品行。编码主数据单一来源在本表:MES 的「物料档案」页面即是本表中"成品"品类的视图(实时拉取本表,不双录)——两系统的「物料档案」指向同一份主数据,以本表为准。库存主表 inventories 的品类与其呼应。列表支持按品类筛选,导出含品类列。\n\n物料档案是库房的另一道地基:先建好物料,入库时才能选到;类型选错会导致入库方式与追溯粒度不符。\n\n命名说明:本档案维护的物料在出库/看板等页面统一以"图号"展示(客户口径)。安全库存在本档案维护,可用量低于它时会在「库房看板」首页触发缺货预警。',
|
||||
fields: [
|
||||
{ name: '图号', source: '手工填写,仓库自定义(新增后不可改)。在出库/看板等页面显示为"图号"。', purpose: '物料唯一编号(即图号)', fill: '如 SCREW-M3;新增后不可改编码' },
|
||||
{ name: '名称', source: '手工填写(必填)。', purpose: '物料名称', fill: '如 螺丝 M3' },
|
||||
{ name: '规格', source: '手工填写(必填)。', purpose: '规格型号', fill: '如 M3×8' },
|
||||
{ name: '单位', source: '手工填写(必填)。', purpose: '计量单位', fill: '如 个/套' },
|
||||
{ name: '品类', source: '必填。创建时默认"原材料";成品品类也可在 MES 的「物料档案」页维护(两系统同一份主数据,以本表为准)。', purpose: '区分原材料/半成品/成品/其他,与统一库存主表品类对应;原材料为进货、半成品/成品为自产', fill: '查询区可选 原材料/半成品/成品/其他' },
|
||||
{ name: '类型', source: '必填(与「品类」相互独立)。选择:1=结构件(批次管理) / 2=电气件(SN 管理) / 3=其他(辅料/工装/试验设备,按批次数量管理)。', purpose: '决定入库方式:结构件/其他走批次、电气件走 SN 逐件扫码', fill: '结构件(批次) / 电气件(SN) / 其他' },
|
||||
{ name: '品类', source: '必填。创建时默认"原材料";成品品类也可在 MES 的「物料档案」页维护(两系统同一份主数据,以本表为准)。', purpose: '区分原材料/成品/其他,与统一库存主表品类对应;原材料为进货、成品为自产(半成品不是物料品类,由库存 category=2 承载)', fill: '查询区可选 原材料/成品/其他' },
|
||||
{ name: '类型', source: '必填(与「品类」相互独立)。选择:批次(结构件,按批管料) / 序列号(电气件,按件唯一) / 其他(辅料/工装/试验设备,按批次数量管理)。', purpose: '决定入库方式:结构件/其他走批次、电气件走 SN 逐件扫码', fill: '批次 / 序列号 / 其他' },
|
||||
{ name: '安全库存', source: '必填整数(默认0)。', purpose: '该物料的最低库存警戒线;可用量低于它会在「库房看板」首页触发缺货预警', fill: '如 100;0=不预警' },
|
||||
{ name: '说明', source: '手工填写(可空)。', purpose: '补充描述', fill: '可空' }
|
||||
]
|
||||
|
||||
@@ -429,12 +429,12 @@ function openMatAttach(row) {
|
||||
Object.assign(attachDrawer, { visible: true, code: row.code, name: row.name })
|
||||
}
|
||||
|
||||
// 品类显示(1原材料/2半成品/3成品/4其他)
|
||||
// 品类显示(1原材料/3成品/4其他;半成品不是物料品类,防御性保留显示)
|
||||
function itemTypeText(t) {
|
||||
return t === 3 ? '成品' : t === 2 ? '半成品' : t === 4 ? '其他' : '原材料'
|
||||
return t === 3 ? '成品' : t === 4 ? '其他' : '原材料'
|
||||
}
|
||||
function itemTypeTagType(t) {
|
||||
return t === 3 ? 'success' : t === 2 ? 'warning' : t === 4 ? 'danger' : 'info'
|
||||
return t === 3 ? 'success' : t === 4 ? 'danger' : 'info'
|
||||
}
|
||||
|
||||
// 区域维护 / 物料档案共用同一组件:切换菜单时复用,watch(mode, immediate) 保证进入即加载
|
||||
@@ -867,15 +867,14 @@ async function onMaterialFile(e) {
|
||||
</el-form-item>
|
||||
<el-form-item label="类型">
|
||||
<el-select v-model="matFilter.manageMode" placeholder="全部" clearable style="width:150px" @change="searchMaterials">
|
||||
<el-option label="结构件(批次管理)" :value="1" />
|
||||
<el-option label="电气件(SN管理)" :value="2" />
|
||||
<el-option label="批次" :value="1" />
|
||||
<el-option label="序列号" :value="2" />
|
||||
<el-option label="其他(辅料/工装/试验设备)" :value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="品类">
|
||||
<el-select v-model="matFilter.itemType" placeholder="全部" clearable style="width:120px" @change="searchMaterials">
|
||||
<el-option label="原材料" :value="1" />
|
||||
<el-option label="半成品" :value="2" />
|
||||
<el-option label="成品" :value="3" />
|
||||
<el-option label="其他" :value="4" />
|
||||
</el-select>
|
||||
@@ -892,7 +891,7 @@ async function onMaterialFile(e) {
|
||||
<el-button v-if="can('material:create')" type="success" @click="openMatCreate">新增物料</el-button>
|
||||
<el-button v-if="can('material:import')" type="warning" :loading="matImporting" @click="pickMaterialFile">导入</el-button>
|
||||
<el-button v-if="can('material:export')" :loading="matExporting" @click="exportMaterials">导出</el-button>
|
||||
<el-tooltip v-if="can('material:import')" content="Excel 首行表头按名称识别(列顺序可变、可含多余列):图号 | 名称 | 规格 | 单位 | 类型(结构件/电气件/其他) | 品类(原材料/半成品/成品/其他,可选) | 说明(除「说明」「品类」外均为必填)">
|
||||
<el-tooltip v-if="can('material:import')" content="Excel 首行表头按名称识别(列顺序可变、可含多余列):图号 | 名称 | 规格 | 单位 | 类型(结构件/电气件/其他) | 品类(原材料/成品/其他,可选;半成品不是物料品类) | 说明(除「说明」「品类」外均为必填)">
|
||||
<el-link type="info" :underline="false" style="margin-left:4px">导入说明</el-link>
|
||||
</el-tooltip>
|
||||
<input ref="matFileRef" type="file" accept=".xlsx,.xls" style="display:none" @change="onMaterialFile" />
|
||||
@@ -917,7 +916,7 @@ async function onMaterialFile(e) {
|
||||
<el-table-column label="类型" width="140" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.manageMode === 3 ? 'info' : (row.manageMode === 2 ? 'warning' : 'primary')" size="small">
|
||||
{{ row.manageMode === 3 ? '其他' : (row.manageMode === 2 ? '电气件(SN)' : '结构件(批次)') }}
|
||||
{{ row.manageMode === 3 ? '其他' : (row.manageMode === 2 ? '序列号' : '批次') }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -962,15 +961,14 @@ async function onMaterialFile(e) {
|
||||
<el-form-item label="品类" required>
|
||||
<el-select v-model="mForm.itemType" placeholder="请选择" style="width:100%">
|
||||
<el-option :value="1" label="原材料" />
|
||||
<el-option :value="2" label="半成品" />
|
||||
<el-option :value="3" label="成品" />
|
||||
<el-option :value="4" label="其他(辅料/工装/试验设备)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" required>
|
||||
<el-select v-model="mForm.manageMode" placeholder="请选择" style="width:100%">
|
||||
<el-option :value="1" label="结构件(批次管理)" />
|
||||
<el-option :value="2" label="电气件(SN 管理)" />
|
||||
<el-option :value="1" label="批次" />
|
||||
<el-option :value="2" label="序列号" />
|
||||
<el-option :value="3" label="其他(辅料/工装/试验设备)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
@@ -267,7 +267,7 @@ const inboundTypeLabel = (t) => {
|
||||
const m = { purchase: '采购入库', semi: '半成品入库', finished: '成品入库', return: '退库入库', other: '其他入库' }
|
||||
return m[t] || t || '-'
|
||||
}
|
||||
const pendingTargetLabel = (d) => (d.matManageMode === 3 ? '其他' : d.manageMode === 2 ? 'SN' : '批次')
|
||||
const pendingTargetLabel = (d) => (d.matManageMode === 3 ? '其他' : d.manageMode === 2 ? '序列号' : '批次')
|
||||
|
||||
function loadPending() {
|
||||
pendingLoading.value = true
|
||||
@@ -487,8 +487,8 @@ onMounted(() => {
|
||||
<!-- 目标类型:批次(结构件) / SN(电气件) / 其他(辅料·工装·试验设备) -->
|
||||
<el-form-item v-if="!isFinal" label="目标类型">
|
||||
<el-radio-group v-model="targetType" @change="onTargetTypeChange">
|
||||
<el-radio-button value="BATCH">批次 (结构件)</el-radio-button>
|
||||
<el-radio-button value="SN">序列号 SN (电气件)</el-radio-button>
|
||||
<el-radio-button value="BATCH">批次</el-radio-button>
|
||||
<el-radio-button value="SN">序列号</el-radio-button>
|
||||
<el-radio-button value="OTHER">其他 (辅料·工装·试验设备)</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
@@ -625,8 +625,8 @@ onMounted(() => {
|
||||
</el-form-item>
|
||||
<el-form-item label="目标类型">
|
||||
<el-select v-model="pendingFilters.targetType" placeholder="全部" clearable style="width:130px" @change="searchPending">
|
||||
<el-option label="结构件" value="BATCH" />
|
||||
<el-option label="电气件" value="SN" />
|
||||
<el-option label="批次" value="BATCH" />
|
||||
<el-option label="序列号" value="SN" />
|
||||
<el-option label="其他" value="OTHER" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
@@ -482,11 +482,11 @@ onMounted(loadDicts)
|
||||
<el-form-item label="出库类型">
|
||||
<template v-if="genForm.materialCode">
|
||||
<el-tag size="small" :type="pickedType === 'sn' ? 'warning' : 'info'">
|
||||
{{ pickedType === 'sn' ? '电气件(SN 管理)' : pickedType === 'other' ? '其他(按批次管理)' : '结构件(批次管理)' }}
|
||||
{{ pickedType === 'sn' ? '序列号' : pickedType === 'other' ? '其他(按批次管理)' : '批次' }}
|
||||
</el-tag>
|
||||
<span style="color:#909399;font-size:12px;margin-left:8px">类型由所选物料档案自动判定,无需手选</span>
|
||||
</template>
|
||||
<span v-else style="color:#909399;font-size:12px">请先选择物料,系统自动带出类型(电气件/结构件)</span>
|
||||
<span v-else style="color:#909399;font-size:12px">请先选择物料,系统自动带出类型(批次/序列号)</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="出库单号">
|
||||
|
||||
@@ -18,14 +18,15 @@ function openAttach(row) {
|
||||
}
|
||||
|
||||
/* ---------- 半成品入库(category=2) ----------
|
||||
* 成品由 MES 完工自动回流入库、经 WMS 完工检验,不在本页手工入库。 */
|
||||
* 成品由 MES 完工自动回流入库、经 WMS 完工检验,不在本页手工入库。
|
||||
* 「已完成至工位」是展示快照(completedText),WMS 原样存展示、不解析。 */
|
||||
|
||||
const operator = getRealName()
|
||||
const todayStr = new Date().toLocaleDateString('sv-SE')
|
||||
|
||||
function newInForm() {
|
||||
return {
|
||||
materialCode: '', zoneCode: '', orderNo: '', completedProcess: '',
|
||||
materialCode: '', zoneCode: '', orderNo: '', completedText: '',
|
||||
// 归属:与入库管理同口径——必选(无「无」选项),选其他可不填编号,工单号/科技项目号必填编号
|
||||
ownershipType: '', ownershipNo: '',
|
||||
productStatus: '', relatedStandard: '', testRecordNo: '',
|
||||
@@ -79,7 +80,7 @@ async function submitInbound(cat) {
|
||||
await request.post('/semi/inbound', {
|
||||
sn,
|
||||
materialCode: f.materialCode,
|
||||
completedProcess: f.completedProcess.trim(),
|
||||
completedText: f.completedText.trim(),
|
||||
zoneCode: f.zoneCode || undefined,
|
||||
orderNo: f.orderNo.trim() || undefined,
|
||||
operator,
|
||||
@@ -110,7 +111,7 @@ const outReasons = ['包装', '继续生产', '检验试验', '其他']
|
||||
const outForms = reactive({ 2: { sn: '', info: null, reason: '' } })
|
||||
const outbounding = reactive({ 2: false })
|
||||
|
||||
// 扫 SN 回车:带出该件信息(物料/已完成工序/工单/归属),再点原因按钮出库
|
||||
// 扫 SN 回车:带出该件信息(物料/已完成至工位/工单/归属),再点原因按钮出库
|
||||
async function scanSn(cat) {
|
||||
const f = outForms[cat]
|
||||
const sn = f.sn.trim()
|
||||
@@ -206,10 +207,10 @@ onMounted(() => {
|
||||
<el-tab-pane label="半成品入库">
|
||||
<el-form label-width="110px" style="max-width:680px">
|
||||
<el-form-item label="物料">
|
||||
<MaterialSelect v-model="inForms[2].materialCode" placeholder="选择物料(图号/名称搜索)" />
|
||||
<MaterialSelect v-model="inForms[2].materialCode" :item-type="3" placeholder="选择成品档案物料(图号/名称搜索)" />
|
||||
</el-form-item>
|
||||
<el-form-item label="已完成工序">
|
||||
<el-input v-model="inForms[2].completedProcess" placeholder="如:1,3,5(可空)" clearable />
|
||||
<el-form-item label="已完成至工位">
|
||||
<el-input v-model="inForms[2].completedText" placeholder="如:工位5(可空=未报工)" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="工单号">
|
||||
<el-input v-model="inForms[2].orderNo" placeholder="来源工单号(可空)" clearable />
|
||||
@@ -275,7 +276,7 @@ onMounted(() => {
|
||||
</el-form>
|
||||
<el-alert v-if="outForms[2].info" type="info" :closable="false" style="max-width:680px;margin-bottom:12px">
|
||||
<div>图号:<b>{{ outForms[2].info.materialCode || '-' }}</b> 名称:{{ outForms[2].info.materialName || '-' }}</div>
|
||||
<div>已完成工序:{{ outForms[2].info.completedProcess || '-' }} 工单号:{{ outForms[2].info.orderNo || '-' }} 归属:{{ outForms[2].info.ownershipNo || '-' }}</div>
|
||||
<div>已完成至工位:{{ outForms[2].info.completedProcess || '-' }} 工单号:{{ outForms[2].info.orderNo || '-' }} 归属:{{ outForms[2].info.ownershipNo || '-' }}</div>
|
||||
</el-alert>
|
||||
<el-form label-width="110px" style="max-width:680px">
|
||||
<el-form-item label="出库原因">
|
||||
@@ -322,7 +323,7 @@ onMounted(() => {
|
||||
<el-table-column prop="materialName" label="名称" min-width="120">
|
||||
<template #default="{ row }">{{ row.materialName || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="completedProcess" label="已完成工序" min-width="100">
|
||||
<el-table-column prop="completedProcess" label="已完成至工位" min-width="100">
|
||||
<template #default="{ row }">{{ row.completedProcess || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="ownershipNo" label="归属单号" min-width="120">
|
||||
|
||||
+116
-116
@@ -1,271 +1,271 @@
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
// Code generated by ent, DO NOT EDIT.
|
||||
|
||||
package hook
|
||||
|
||||
import (
|
||||
"bj_power_wms"
|
||||
"bj_power_wms/ent"
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// The AgvTaskFunc type is an adapter to allow the use of ordinary
|
||||
// function as AgvTask mutator.
|
||||
type AgvTaskFunc func(context.Context, *bj_power_wms.AgvTaskMutation) (bj_power_wms.Value, error)
|
||||
type AgvTaskFunc func(context.Context, *ent.AgvTaskMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f AgvTaskFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.AgvTaskMutation); ok {
|
||||
func (f AgvTaskFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.AgvTaskMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.AgvTaskMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.AgvTaskMutation", m)
|
||||
}
|
||||
|
||||
// The AttachmentFunc type is an adapter to allow the use of ordinary
|
||||
// function as Attachment mutator.
|
||||
type AttachmentFunc func(context.Context, *bj_power_wms.AttachmentMutation) (bj_power_wms.Value, error)
|
||||
type AttachmentFunc func(context.Context, *ent.AttachmentMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f AttachmentFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.AttachmentMutation); ok {
|
||||
func (f AttachmentFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.AttachmentMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.AttachmentMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.AttachmentMutation", m)
|
||||
}
|
||||
|
||||
// The EventLogFunc type is an adapter to allow the use of ordinary
|
||||
// function as EventLog mutator.
|
||||
type EventLogFunc func(context.Context, *bj_power_wms.EventLogMutation) (bj_power_wms.Value, error)
|
||||
type EventLogFunc func(context.Context, *ent.EventLogMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f EventLogFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.EventLogMutation); ok {
|
||||
func (f EventLogFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.EventLogMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.EventLogMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.EventLogMutation", m)
|
||||
}
|
||||
|
||||
// The InboundDetailFunc type is an adapter to allow the use of ordinary
|
||||
// function as InboundDetail mutator.
|
||||
type InboundDetailFunc func(context.Context, *bj_power_wms.InboundDetailMutation) (bj_power_wms.Value, error)
|
||||
type InboundDetailFunc func(context.Context, *ent.InboundDetailMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f InboundDetailFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.InboundDetailMutation); ok {
|
||||
func (f InboundDetailFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.InboundDetailMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.InboundDetailMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.InboundDetailMutation", m)
|
||||
}
|
||||
|
||||
// The InboundOrderFunc type is an adapter to allow the use of ordinary
|
||||
// function as InboundOrder mutator.
|
||||
type InboundOrderFunc func(context.Context, *bj_power_wms.InboundOrderMutation) (bj_power_wms.Value, error)
|
||||
type InboundOrderFunc func(context.Context, *ent.InboundOrderMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f InboundOrderFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.InboundOrderMutation); ok {
|
||||
func (f InboundOrderFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.InboundOrderMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.InboundOrderMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.InboundOrderMutation", m)
|
||||
}
|
||||
|
||||
// The InspectionRecordFunc type is an adapter to allow the use of ordinary
|
||||
// function as InspectionRecord mutator.
|
||||
type InspectionRecordFunc func(context.Context, *bj_power_wms.InspectionRecordMutation) (bj_power_wms.Value, error)
|
||||
type InspectionRecordFunc func(context.Context, *ent.InspectionRecordMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f InspectionRecordFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.InspectionRecordMutation); ok {
|
||||
func (f InspectionRecordFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.InspectionRecordMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.InspectionRecordMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.InspectionRecordMutation", m)
|
||||
}
|
||||
|
||||
// The InventoryFunc type is an adapter to allow the use of ordinary
|
||||
// function as Inventory mutator.
|
||||
type InventoryFunc func(context.Context, *bj_power_wms.InventoryMutation) (bj_power_wms.Value, error)
|
||||
type InventoryFunc func(context.Context, *ent.InventoryMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f InventoryFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.InventoryMutation); ok {
|
||||
func (f InventoryFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.InventoryMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.InventoryMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.InventoryMutation", m)
|
||||
}
|
||||
|
||||
// The InventoryLockFunc type is an adapter to allow the use of ordinary
|
||||
// function as InventoryLock mutator.
|
||||
type InventoryLockFunc func(context.Context, *bj_power_wms.InventoryLockMutation) (bj_power_wms.Value, error)
|
||||
type InventoryLockFunc func(context.Context, *ent.InventoryLockMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f InventoryLockFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.InventoryLockMutation); ok {
|
||||
func (f InventoryLockFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.InventoryLockMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.InventoryLockMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.InventoryLockMutation", m)
|
||||
}
|
||||
|
||||
// The MaterialFunc type is an adapter to allow the use of ordinary
|
||||
// function as Material mutator.
|
||||
type MaterialFunc func(context.Context, *bj_power_wms.MaterialMutation) (bj_power_wms.Value, error)
|
||||
type MaterialFunc func(context.Context, *ent.MaterialMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f MaterialFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.MaterialMutation); ok {
|
||||
func (f MaterialFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.MaterialMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.MaterialMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.MaterialMutation", m)
|
||||
}
|
||||
|
||||
// The MaterialDemandFunc type is an adapter to allow the use of ordinary
|
||||
// function as MaterialDemand mutator.
|
||||
type MaterialDemandFunc func(context.Context, *bj_power_wms.MaterialDemandMutation) (bj_power_wms.Value, error)
|
||||
type MaterialDemandFunc func(context.Context, *ent.MaterialDemandMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f MaterialDemandFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.MaterialDemandMutation); ok {
|
||||
func (f MaterialDemandFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.MaterialDemandMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.MaterialDemandMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.MaterialDemandMutation", m)
|
||||
}
|
||||
|
||||
// The OrderMaterialLedgerFunc type is an adapter to allow the use of ordinary
|
||||
// function as OrderMaterialLedger mutator.
|
||||
type OrderMaterialLedgerFunc func(context.Context, *bj_power_wms.OrderMaterialLedgerMutation) (bj_power_wms.Value, error)
|
||||
type OrderMaterialLedgerFunc func(context.Context, *ent.OrderMaterialLedgerMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f OrderMaterialLedgerFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.OrderMaterialLedgerMutation); ok {
|
||||
func (f OrderMaterialLedgerFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.OrderMaterialLedgerMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.OrderMaterialLedgerMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.OrderMaterialLedgerMutation", m)
|
||||
}
|
||||
|
||||
// The OutboundDetailFunc type is an adapter to allow the use of ordinary
|
||||
// function as OutboundDetail mutator.
|
||||
type OutboundDetailFunc func(context.Context, *bj_power_wms.OutboundDetailMutation) (bj_power_wms.Value, error)
|
||||
type OutboundDetailFunc func(context.Context, *ent.OutboundDetailMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f OutboundDetailFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.OutboundDetailMutation); ok {
|
||||
func (f OutboundDetailFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.OutboundDetailMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.OutboundDetailMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.OutboundDetailMutation", m)
|
||||
}
|
||||
|
||||
// The OutboundOrderFunc type is an adapter to allow the use of ordinary
|
||||
// function as OutboundOrder mutator.
|
||||
type OutboundOrderFunc func(context.Context, *bj_power_wms.OutboundOrderMutation) (bj_power_wms.Value, error)
|
||||
type OutboundOrderFunc func(context.Context, *ent.OutboundOrderMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f OutboundOrderFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.OutboundOrderMutation); ok {
|
||||
func (f OutboundOrderFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.OutboundOrderMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.OutboundOrderMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.OutboundOrderMutation", m)
|
||||
}
|
||||
|
||||
// The PermissionFunc type is an adapter to allow the use of ordinary
|
||||
// function as Permission mutator.
|
||||
type PermissionFunc func(context.Context, *bj_power_wms.PermissionMutation) (bj_power_wms.Value, error)
|
||||
type PermissionFunc func(context.Context, *ent.PermissionMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f PermissionFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.PermissionMutation); ok {
|
||||
func (f PermissionFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.PermissionMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.PermissionMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.PermissionMutation", m)
|
||||
}
|
||||
|
||||
// The ReturnOrderFunc type is an adapter to allow the use of ordinary
|
||||
// function as ReturnOrder mutator.
|
||||
type ReturnOrderFunc func(context.Context, *bj_power_wms.ReturnOrderMutation) (bj_power_wms.Value, error)
|
||||
type ReturnOrderFunc func(context.Context, *ent.ReturnOrderMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f ReturnOrderFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.ReturnOrderMutation); ok {
|
||||
func (f ReturnOrderFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.ReturnOrderMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.ReturnOrderMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ReturnOrderMutation", m)
|
||||
}
|
||||
|
||||
// The RoleFunc type is an adapter to allow the use of ordinary
|
||||
// function as Role mutator.
|
||||
type RoleFunc func(context.Context, *bj_power_wms.RoleMutation) (bj_power_wms.Value, error)
|
||||
type RoleFunc func(context.Context, *ent.RoleMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f RoleFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.RoleMutation); ok {
|
||||
func (f RoleFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.RoleMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.RoleMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.RoleMutation", m)
|
||||
}
|
||||
|
||||
// The SemiFinishedFunc type is an adapter to allow the use of ordinary
|
||||
// function as SemiFinished mutator.
|
||||
type SemiFinishedFunc func(context.Context, *bj_power_wms.SemiFinishedMutation) (bj_power_wms.Value, error)
|
||||
type SemiFinishedFunc func(context.Context, *ent.SemiFinishedMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f SemiFinishedFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.SemiFinishedMutation); ok {
|
||||
func (f SemiFinishedFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.SemiFinishedMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.SemiFinishedMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.SemiFinishedMutation", m)
|
||||
}
|
||||
|
||||
// The StocktakeItemFunc type is an adapter to allow the use of ordinary
|
||||
// function as StocktakeItem mutator.
|
||||
type StocktakeItemFunc func(context.Context, *bj_power_wms.StocktakeItemMutation) (bj_power_wms.Value, error)
|
||||
type StocktakeItemFunc func(context.Context, *ent.StocktakeItemMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f StocktakeItemFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.StocktakeItemMutation); ok {
|
||||
func (f StocktakeItemFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.StocktakeItemMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.StocktakeItemMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.StocktakeItemMutation", m)
|
||||
}
|
||||
|
||||
// The StocktakeOrderFunc type is an adapter to allow the use of ordinary
|
||||
// function as StocktakeOrder mutator.
|
||||
type StocktakeOrderFunc func(context.Context, *bj_power_wms.StocktakeOrderMutation) (bj_power_wms.Value, error)
|
||||
type StocktakeOrderFunc func(context.Context, *ent.StocktakeOrderMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f StocktakeOrderFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.StocktakeOrderMutation); ok {
|
||||
func (f StocktakeOrderFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.StocktakeOrderMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.StocktakeOrderMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.StocktakeOrderMutation", m)
|
||||
}
|
||||
|
||||
// The UserFunc type is an adapter to allow the use of ordinary
|
||||
// function as User mutator.
|
||||
type UserFunc func(context.Context, *bj_power_wms.UserMutation) (bj_power_wms.Value, error)
|
||||
type UserFunc func(context.Context, *ent.UserMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f UserFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.UserMutation); ok {
|
||||
func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.UserMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.UserMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.UserMutation", m)
|
||||
}
|
||||
|
||||
// The ZoneFunc type is an adapter to allow the use of ordinary
|
||||
// function as Zone mutator.
|
||||
type ZoneFunc func(context.Context, *bj_power_wms.ZoneMutation) (bj_power_wms.Value, error)
|
||||
type ZoneFunc func(context.Context, *ent.ZoneMutation) (ent.Value, error)
|
||||
|
||||
// Mutate calls f(ctx, m).
|
||||
func (f ZoneFunc) Mutate(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
if mv, ok := m.(*bj_power_wms.ZoneMutation); ok {
|
||||
func (f ZoneFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if mv, ok := m.(*ent.ZoneMutation); ok {
|
||||
return f(ctx, mv)
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *bj_power_wms.ZoneMutation", m)
|
||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ZoneMutation", m)
|
||||
}
|
||||
|
||||
// Condition is a hook condition function.
|
||||
type Condition func(context.Context, bj_power_wms.Mutation) bool
|
||||
type Condition func(context.Context, ent.Mutation) bool
|
||||
|
||||
// And groups conditions with the AND operator.
|
||||
func And(first, second Condition, rest ...Condition) Condition {
|
||||
return func(ctx context.Context, m bj_power_wms.Mutation) bool {
|
||||
return func(ctx context.Context, m ent.Mutation) bool {
|
||||
if !first(ctx, m) || !second(ctx, m) {
|
||||
return false
|
||||
}
|
||||
@@ -280,7 +280,7 @@ func And(first, second Condition, rest ...Condition) Condition {
|
||||
|
||||
// Or groups conditions with the OR operator.
|
||||
func Or(first, second Condition, rest ...Condition) Condition {
|
||||
return func(ctx context.Context, m bj_power_wms.Mutation) bool {
|
||||
return func(ctx context.Context, m ent.Mutation) bool {
|
||||
if first(ctx, m) || second(ctx, m) {
|
||||
return true
|
||||
}
|
||||
@@ -295,21 +295,21 @@ func Or(first, second Condition, rest ...Condition) Condition {
|
||||
|
||||
// Not negates a given condition.
|
||||
func Not(cond Condition) Condition {
|
||||
return func(ctx context.Context, m bj_power_wms.Mutation) bool {
|
||||
return func(ctx context.Context, m ent.Mutation) bool {
|
||||
return !cond(ctx, m)
|
||||
}
|
||||
}
|
||||
|
||||
// HasOp is a condition testing mutation operation.
|
||||
func HasOp(op bj_power_wms.Op) Condition {
|
||||
return func(_ context.Context, m bj_power_wms.Mutation) bool {
|
||||
func HasOp(op ent.Op) Condition {
|
||||
return func(_ context.Context, m ent.Mutation) bool {
|
||||
return m.Op().Is(op)
|
||||
}
|
||||
}
|
||||
|
||||
// HasAddedFields is a condition validating `.AddedField` on fields.
|
||||
func HasAddedFields(field string, fields ...string) Condition {
|
||||
return func(_ context.Context, m bj_power_wms.Mutation) bool {
|
||||
return func(_ context.Context, m ent.Mutation) bool {
|
||||
if _, exists := m.AddedField(field); !exists {
|
||||
return false
|
||||
}
|
||||
@@ -324,7 +324,7 @@ func HasAddedFields(field string, fields ...string) Condition {
|
||||
|
||||
// HasClearedFields is a condition validating `.FieldCleared` on fields.
|
||||
func HasClearedFields(field string, fields ...string) Condition {
|
||||
return func(_ context.Context, m bj_power_wms.Mutation) bool {
|
||||
return func(_ context.Context, m ent.Mutation) bool {
|
||||
if exists := m.FieldCleared(field); !exists {
|
||||
return false
|
||||
}
|
||||
@@ -339,7 +339,7 @@ func HasClearedFields(field string, fields ...string) Condition {
|
||||
|
||||
// HasFields is a condition validating `.Field` on fields.
|
||||
func HasFields(field string, fields ...string) Condition {
|
||||
return func(_ context.Context, m bj_power_wms.Mutation) bool {
|
||||
return func(_ context.Context, m ent.Mutation) bool {
|
||||
if _, exists := m.Field(field); !exists {
|
||||
return false
|
||||
}
|
||||
@@ -355,9 +355,9 @@ func HasFields(field string, fields ...string) Condition {
|
||||
// If executes the given hook under condition.
|
||||
//
|
||||
// hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...)))
|
||||
func If(hk bj_power_wms.Hook, cond Condition) bj_power_wms.Hook {
|
||||
return func(next bj_power_wms.Mutator) bj_power_wms.Mutator {
|
||||
return bj_power_wms.MutateFunc(func(ctx context.Context, m bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
func If(hk ent.Hook, cond Condition) ent.Hook {
|
||||
return func(next ent.Mutator) ent.Mutator {
|
||||
return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||
if cond(ctx, m) {
|
||||
return hk(next).Mutate(ctx, m)
|
||||
}
|
||||
@@ -368,22 +368,22 @@ func If(hk bj_power_wms.Hook, cond Condition) bj_power_wms.Hook {
|
||||
|
||||
// On executes the given hook only for the given operation.
|
||||
//
|
||||
// hook.On(Log, bj_power_wms.Delete|bj_power_wms.Create)
|
||||
func On(hk bj_power_wms.Hook, op bj_power_wms.Op) bj_power_wms.Hook {
|
||||
// hook.On(Log, ent.Delete|ent.Create)
|
||||
func On(hk ent.Hook, op ent.Op) ent.Hook {
|
||||
return If(hk, HasOp(op))
|
||||
}
|
||||
|
||||
// Unless skips the given hook only for the given operation.
|
||||
//
|
||||
// hook.Unless(Log, bj_power_wms.Update|bj_power_wms.UpdateOne)
|
||||
func Unless(hk bj_power_wms.Hook, op bj_power_wms.Op) bj_power_wms.Hook {
|
||||
// hook.Unless(Log, ent.Update|ent.UpdateOne)
|
||||
func Unless(hk ent.Hook, op ent.Op) ent.Hook {
|
||||
return If(hk, Not(HasOp(op)))
|
||||
}
|
||||
|
||||
// FixedError is a hook returning a fixed error.
|
||||
func FixedError(err error) bj_power_wms.Hook {
|
||||
return func(bj_power_wms.Mutator) bj_power_wms.Mutator {
|
||||
return bj_power_wms.MutateFunc(func(context.Context, bj_power_wms.Mutation) (bj_power_wms.Value, error) {
|
||||
func FixedError(err error) ent.Hook {
|
||||
return func(ent.Mutator) ent.Mutator {
|
||||
return ent.MutateFunc(func(context.Context, ent.Mutation) (ent.Value, error) {
|
||||
return nil, err
|
||||
})
|
||||
}
|
||||
@@ -391,12 +391,12 @@ func FixedError(err error) bj_power_wms.Hook {
|
||||
|
||||
// Reject returns a hook that rejects all operations that match op.
|
||||
//
|
||||
// func (T) Hooks() []bj_power_wms.Hook {
|
||||
// return []bj_power_wms.Hook{
|
||||
// Reject(bj_power_wms.Delete|bj_power_wms.Update),
|
||||
// func (T) Hooks() []ent.Hook {
|
||||
// return []ent.Hook{
|
||||
// Reject(ent.Delete|ent.Update),
|
||||
// }
|
||||
// }
|
||||
func Reject(op bj_power_wms.Op) bj_power_wms.Hook {
|
||||
func Reject(op ent.Op) ent.Hook {
|
||||
hk := FixedError(fmt.Errorf("%s operation is not allowed", op))
|
||||
return On(hk, op)
|
||||
}
|
||||
@@ -404,17 +404,17 @@ func Reject(op bj_power_wms.Op) bj_power_wms.Hook {
|
||||
// Chain acts as a list of hooks and is effectively immutable.
|
||||
// Once created, it will always hold the same set of hooks in the same order.
|
||||
type Chain struct {
|
||||
hooks []bj_power_wms.Hook
|
||||
hooks []ent.Hook
|
||||
}
|
||||
|
||||
// NewChain creates a new chain of hooks.
|
||||
func NewChain(hooks ...bj_power_wms.Hook) Chain {
|
||||
return Chain{append([]bj_power_wms.Hook(nil), hooks...)}
|
||||
func NewChain(hooks ...ent.Hook) Chain {
|
||||
return Chain{append([]ent.Hook(nil), hooks...)}
|
||||
}
|
||||
|
||||
// Hook chains the list of hooks and returns the final hook.
|
||||
func (c Chain) Hook() bj_power_wms.Hook {
|
||||
return func(mutator bj_power_wms.Mutator) bj_power_wms.Mutator {
|
||||
func (c Chain) Hook() ent.Hook {
|
||||
return func(mutator ent.Mutator) ent.Mutator {
|
||||
for i := len(c.hooks) - 1; i >= 0; i-- {
|
||||
mutator = c.hooks[i](mutator)
|
||||
}
|
||||
@@ -424,8 +424,8 @@ func (c Chain) Hook() bj_power_wms.Hook {
|
||||
|
||||
// Append extends a chain, adding the specified hook
|
||||
// as the last ones in the mutation flow.
|
||||
func (c Chain) Append(hooks ...bj_power_wms.Hook) Chain {
|
||||
newHooks := make([]bj_power_wms.Hook, 0, len(c.hooks)+len(hooks))
|
||||
func (c Chain) Append(hooks ...ent.Hook) Chain {
|
||||
newHooks := make([]ent.Hook, 0, len(c.hooks)+len(hooks))
|
||||
newHooks = append(newHooks, c.hooks...)
|
||||
newHooks = append(newHooks, hooks...)
|
||||
return Chain{newHooks}
|
||||
|
||||
@@ -296,6 +296,14 @@ func applyColumnPatches(ctx context.Context) {
|
||||
slog.Warn("补齐列失败(可忽略): " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 2026-09-22 物料品类收编:半成品不是物料品类(是工件状态,由库存 category=2 承载)=====
|
||||
// 物料档案不再允许 item_type=2,幂等清理存量半成品品类行(重复执行删 0 行,无害)。
|
||||
if res, err := rawDB.ExecContext(ctx, `DELETE FROM materials WHERE item_type=2`); err != nil {
|
||||
slog.Warn("清理 item_type=2 物料失败(可忽略): " + err.Error())
|
||||
} else if n, err := res.RowsAffected(); err == nil && n > 0 {
|
||||
slog.Info(fmt.Sprintf("物料品类清理:已删除半成品品类(item_type=2)物料档案 %d 行", n))
|
||||
}
|
||||
}
|
||||
|
||||
// DropAllTables 删除 public schema 下全部表(CASCADE 连带索引/序列/外键约束)。
|
||||
|
||||
@@ -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().
|
||||
|
||||
@@ -2,7 +2,6 @@ package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -26,29 +25,31 @@ const (
|
||||
// 全部落 inventories(manage_mode=2 SN单件, category=2 半成品)。
|
||||
// 三个 semi 接口签名与响应结构保持不变,MES / 前端零改造平滑切换。
|
||||
|
||||
// semiInboundHandler 半成品/成品入库(携带已完成工序)
|
||||
// semiInboundHandler 半成品/成品入库(携带「已完成至工位」展示快照)
|
||||
// 与 MES 闭环:MES 工位报工暂存退库 / 完工回流时调用本接口,把 SN 入 WMS 库
|
||||
// (inventories,category=2 半成品 / 3 成品,客户诉求 问题记录 L222 半成品与成品要区分)。
|
||||
// 成品入库 9 字段(L218):SN/图号/归属/产品状态/相关标准/试验记录单号/记录员/记录日期/工单号。
|
||||
// 契约(2026-09-22 定稿):废除 completedProcess/doneProcessCodes 字段,改为 completedText
|
||||
// ——人类可读展示快照(如"已完成至工位5",空=未报工)。WMS 只原样存入
|
||||
// inventories.completed_process 展示,不解析、不参与任何逻辑。
|
||||
// 为保持两系统解耦,materialCode 不强制要求——优先用请求传入,都没有则留空(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"`
|
||||
Operator string `json:"operator"`
|
||||
Category int `json:"category"` // 2=半成品 3=成品(默认 2)
|
||||
OwnershipType string `json:"ownershipType"`
|
||||
OwnershipNo string `json:"ownershipNo"`
|
||||
ProductStatus string `json:"productStatus"` // 已通过/部分通过/返修(成品用)
|
||||
RelatedStandard string `json:"relatedStandard"` // 相关标准(试验方案号)
|
||||
TestRecordNo string `json:"testRecordNo"` // 试验记录单号
|
||||
RecordedBy string `json:"recordedBy"` // 记录员
|
||||
RecordedAt int64 `json:"recordedAt"` // 记录日期(unix 秒)
|
||||
Sn string `json:"sn"`
|
||||
MaterialCode string `json:"materialCode"`
|
||||
CompletedText string `json:"completedText"` // 已完成至工位(展示快照,空=未报工)
|
||||
ZoneCode string `json:"zoneCode"`
|
||||
OrderNo string `json:"orderNo"`
|
||||
Operator string `json:"operator"`
|
||||
Category int `json:"category"` // 2=半成品 3=成品(默认 2)
|
||||
OwnershipType string `json:"ownershipType"`
|
||||
OwnershipNo string `json:"ownershipNo"`
|
||||
ProductStatus string `json:"productStatus"` // 已通过/部分通过/返修(成品用)
|
||||
RelatedStandard string `json:"relatedStandard"` // 相关标准(试验方案号)
|
||||
TestRecordNo string `json:"testRecordNo"` // 试验记录单号
|
||||
RecordedBy string `json:"recordedBy"` // 记录员
|
||||
RecordedAt int64 `json:"recordedAt"` // 记录日期(unix 秒)
|
||||
}
|
||||
if err := parseJSON(r, &req); err != nil {
|
||||
fail(w, http.StatusBadRequest, "参数错误")
|
||||
@@ -80,15 +81,8 @@ 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, ",")
|
||||
}
|
||||
// 已完成至工位:MES 传人类可读快照,WMS 原样存展示(不解析、不参与任何逻辑)
|
||||
completed := req.CompletedText
|
||||
|
||||
// 物料编码:以请求传入为准;名称从物料档案补齐(档案缺失则用编码兜底)
|
||||
materialCode := req.MaterialCode
|
||||
|
||||
@@ -58,7 +58,7 @@ type stockAggRow struct {
|
||||
MaterialName string `json:"materialName"` // 物料名称
|
||||
Spec string `json:"spec"` // 规格型号
|
||||
ManageMode int `json:"manageMode"` // 库存行管理粒度 1结构件(批次)/2电气件(SN)
|
||||
ItemType int `json:"itemType"` // 物料品类(1原材料/2半成品/3成品/4其他)
|
||||
ItemType int `json:"itemType"` // 物料品类(1原材料/3成品/4其他)
|
||||
MatManageMode int `json:"matManageMode"` // 物料档案类型(1结构件/2电气件/3其他):类型标签判定用
|
||||
ZoneCode string `json:"zoneCode"` // 区域
|
||||
ShelfNo string `json:"shelfNo"` // 货架号
|
||||
@@ -90,8 +90,8 @@ func queryStockHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
layerNo := r.URL.Query().Get("layerNo") // 第几层
|
||||
positionNo := r.URL.Query().Get("positionNo") // 位置号
|
||||
qualityStatus := r.URL.Query().Get("qualityStatus")
|
||||
manageMode := r.URL.Query().Get("manageMode") // 1/2/空=全部
|
||||
category := r.URL.Query().Get("category") // 1原材料/2半成品/3成品/空=全部(完工检 SN 拾取器按成品过滤)
|
||||
manageMode := r.URL.Query().Get("manageMode") // 1/2/空=全部
|
||||
category := r.URL.Query().Get("category") // 1原材料/2半成品/3成品/空=全部(完工检 SN 拾取器按成品过滤)
|
||||
inboundNo := r.URL.Query().Get("inboundNo")
|
||||
startDate := r.URL.Query().Get("startDate") // 默认近3个月(由接口保证)
|
||||
endDate := r.URL.Query().Get("endDate")
|
||||
@@ -374,7 +374,7 @@ type materialAggRow struct {
|
||||
MaterialName string `json:"materialName"`
|
||||
Spec string `json:"spec"`
|
||||
ManageMode int `json:"manageMode"` // 库存行管理粒度 1结构件(批次)/2电气件(SN)
|
||||
ItemType int `json:"itemType"` // 物料品类(1原材料/2半成品/3成品/4其他)
|
||||
ItemType int `json:"itemType"` // 物料品类(1原材料/3成品/4其他)
|
||||
MatManageMode int `json:"matManageMode"` // 物料档案类型(1结构件/2电气件/3其他):类型标签判定用
|
||||
Category int `json:"category"` // 品类 1原材料/2半成品/3成品
|
||||
TotalQty int `json:"totalQty"` // 总数量(结构件=数量求和;电气件=SN 行数)
|
||||
@@ -717,9 +717,9 @@ func exportStockHandler(ctx *svc.ServiceContext) http.HandlerFunc {
|
||||
rows, _, err := aggregateMaterialSummary(ctx, materialSummaryArgs{
|
||||
MaterialCode: r.URL.Query().Get("materialCode"),
|
||||
MaterialName: r.URL.Query().Get("materialName"),
|
||||
ManageMode: r.URL.Query().Get("manageMode"),
|
||||
Category: r.URL.Query().Get("category"),
|
||||
Page: 1,
|
||||
ManageMode: r.URL.Query().Get("manageMode"),
|
||||
Category: r.URL.Query().Get("category"),
|
||||
Page: 1,
|
||||
PageSize: 1000000, // 全量
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -13,9 +13,13 @@ import (
|
||||
// - manage_mode=1 结构件:按"批次"管理,一次到货入一批,库存以 quantity 计数;
|
||||
// - manage_mode=2 电气件:按"SN 序列号"逐件管理,库存以单件行计数,可单件追溯;
|
||||
// - manage_mode=3 其他(辅料/工装/试验设备):按"批次数量"管理,不做 SN。
|
||||
//
|
||||
// 品类(与库存主表 inventories.category 对应,独立于类型):
|
||||
// - item_type=1 原材料 / 2 半成品 / 3 成品 / 4 其他(成品即"产品型号"档案,MES 实时从本表拉取,
|
||||
// - item_type=1 原材料 / 3 成品 / 4 其他(成品即"产品型号"档案,MES 实时从本表拉取,
|
||||
// 消除两系统双录——2026-09-08 并表定稿)。
|
||||
// 半成品不是物料品类(2026-09-22 定稿):半成品是工件状态,由库存 category=2 承载,
|
||||
// 物料档案不再有 item_type=2 行(存量由 internal/db 迁移补丁幂等清理)。
|
||||
//
|
||||
// 注意:物料档案只描述"这个物料是什么、怎么管",不承载生命周期状态。
|
||||
type Material struct {
|
||||
ent.Schema
|
||||
@@ -32,8 +36,8 @@ func (Material) Fields() []ent.Field {
|
||||
field.String("spec").Optional().Comment("规格型号"),
|
||||
field.String("unit").Optional().Comment("单位"),
|
||||
field.String("description").Optional().Comment("描述"),
|
||||
// 品类(独立于类型的维度):1=原材料 2=半成品 3=成品 4=其他
|
||||
field.Int("item_type").Default(1).Comment("品类 1原材料/2半成品/3成品/4其他"),
|
||||
// 品类(独立于类型的维度):1=原材料 3=成品 4=其他(半成品不是物料品类,由库存承载)
|
||||
field.Int("item_type").Default(1).Comment("品类 1原材料/3成品/4其他(半成品不是物料品类,由库存 category=2 承载)"),
|
||||
// 类型(管理粒度,入库「结构件/电气件/其他」三页签同源):
|
||||
// 1=结构件(批次) 2=电气件(序列号) 3=其他(辅料/工装/试验设备,按批次数量,不做 SN)
|
||||
field.Int("manage_mode").Default(1).Comment("类型 1结构件(批次)/2电气件(序列号)/3其他"),
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>WMS库房管理</title>
|
||||
<!-- 系统图标:库房箱体(内联 SVG,避免依赖外部文件) -->
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='6' fill='%231668dc'/><path d='M16 7l9 4.5v9L16 25l-9-4.5v-9L16 7z' fill='none' stroke='%23fff' stroke-width='2' stroke-linejoin='round'/><path d='M7 11.5L16 16l9-4.5M16 16v9' fill='none' stroke='%23fff' stroke-width='2' stroke-linejoin='round'/></svg>">
|
||||
<script type="module" crossorigin src="/assets/index-CaL-0-_E.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-B4QhivSo.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-hzpIaM_X.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user