Compare commits
4 Commits
b6ce754ba7
...
2319a053df
| Author | SHA1 | Date | |
|---|---|---|---|
| 2319a053df | |||
| 6a7761abbb | |||
| 0abc5850d8 | |||
| cc80fdd9c9 |
36
db_migrations/add_bom_remark.sql
Normal file
36
db_migrations/add_bom_remark.sql
Normal file
@ -0,0 +1,36 @@
|
||||
-- =============================================================================
|
||||
-- 一次性迁移:BOM 级备注落库
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 背景:
|
||||
-- 前端 BomManage.vue 一直有"备注"输入框(v-model="form.remark"),提交时也
|
||||
-- 确实放进了 payload(BomManage.vue:1273),但后端 BomService.save_bom() 从
|
||||
-- 未读取 data['remark'],父件级备注被**静默丢弃**——填了、保存、再打开必为空。
|
||||
--
|
||||
-- 根因是数据模型缺位:bom_table 是子件明细表(一行 = 一个子件),表里只有
|
||||
-- 子件级的 remark 列,没有任何位置存放 BOM 级备注。
|
||||
-- 连带 bug:读取侧 get_bom_detail() 用 first.BomTable.remark(第一个子件行的
|
||||
-- 备注)冒充主表备注,所以查看时会显示某个子件的备注(如"白色")或空。
|
||||
--
|
||||
-- 方案:
|
||||
-- bom_table / bom_draft_table 各增加 bom_remark 列,沿用 parent_id、is_enabled
|
||||
-- 既有的冗余写法:同一 BOM 版本的每一行存同一份值,读取时取首行。
|
||||
-- 与既有 remark(子件级)语义分离,互不干扰。
|
||||
--
|
||||
-- 存量数据:
|
||||
-- 无法回填 —— 历史上填过的备注从未入库,任何位置都找不到,只能从本迁移
|
||||
-- 之后开始记录。这是本次修复的已知代价。
|
||||
--
|
||||
-- 执行方式: docker exec -i inventory_db psql -U test -d inventory_system < 本文件
|
||||
-- 注意: 若后端启用 Redis 缓存(bom:tree:*),部署后需清缓存或重启后端,
|
||||
-- 避免 12h 内命中旧值。
|
||||
-- =============================================================================
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE bom_table ADD COLUMN IF NOT EXISTS bom_remark text;
|
||||
ALTER TABLE bom_draft_table ADD COLUMN IF NOT EXISTS bom_remark text;
|
||||
|
||||
COMMENT ON COLUMN bom_table.bom_remark IS 'BOM级备注(父件级,冗余存于每行,读取取首行)';
|
||||
COMMENT ON COLUMN bom_draft_table.bom_remark IS 'BOM级备注(父件级,冗余存于每行,读取取首行)';
|
||||
|
||||
COMMIT;
|
||||
@ -198,6 +198,8 @@ def save_bom():
|
||||
'version': 'bom_manage:version',
|
||||
'is_enabled': 'bom_manage:status',
|
||||
'bom_no': 'bom_manage:bom_no',
|
||||
# ★ 顶级 remark = BOM 级备注,与子件级 remark 共用同一权限码
|
||||
'remark': 'bom_manage:remark',
|
||||
}
|
||||
# 清洗顶级字段
|
||||
for field in list(req_data.keys()):
|
||||
@ -531,7 +533,12 @@ def save_draft():
|
||||
if not parent_id:
|
||||
return jsonify({'code': 400, 'msg': 'parent_id 不能为空'}), 400
|
||||
|
||||
bom_draft_no = BomDraftService.save_draft(bom_no, version, parent_id, children)
|
||||
# ★ 这是运行时真正生效的草稿入口(bom_draft.py 的 bom_draft_bp 未在
|
||||
# app/__init__.py 注册,是死代码),BOM 级备注必须在这里透传
|
||||
bom_draft_no = BomDraftService.save_draft(
|
||||
bom_no, version, parent_id, children,
|
||||
bom_remark=data.get('remark', '') or ''
|
||||
)
|
||||
return jsonify({'code': 200, 'msg': '草稿暂存成功', 'data': {'bom_no': bom_draft_no}})
|
||||
|
||||
|
||||
|
||||
@ -25,6 +25,10 @@ class BomTable(db.Model):
|
||||
loss_rate = db.Column(db.Numeric(5, 2), comment='损耗率%', default=0, nullable=True)
|
||||
remark = db.Column(db.Text, comment='备注')
|
||||
|
||||
# ★ BOM 级备注(父件级):与 parent_id/is_enabled 一样冗余存于本版本每一行,读取取首行。
|
||||
# 上面的 remark 是**子件级**备注,语义不同,勿混用。
|
||||
bom_remark = db.Column(db.Text, comment='BOM级备注(父件级,冗余存于每行,读取取首行)')
|
||||
|
||||
# ★ 子件引用的"自制 BOM"版本:子件物料若本身是自制件(作为其它 BOM 的父件),
|
||||
# 此列记录该子件实际引用的配方版本((bom_no, version) 共同定位),由新建/编辑 BOM 时选版本保存。
|
||||
# 外购件/无下级 BOM 的子件这两列为 NULL。
|
||||
|
||||
@ -23,6 +23,10 @@ class BomDraftTable(db.Model):
|
||||
loss_rate = db.Column(db.Numeric(5, 2), default=0, nullable=True, comment='损耗率%')
|
||||
remark = db.Column(db.Text, comment='备注')
|
||||
|
||||
# ★ BOM 级备注(父件级):与 bom_table.bom_remark 对齐,草稿暂存/发布期间不丢失。
|
||||
# 上面的 remark 是**子件级**备注。占位头行(child_id IS NULL)同样携带该值。
|
||||
bom_remark = db.Column(db.Text, comment='BOM级备注(父件级,冗余存于每行,读取取首行)')
|
||||
|
||||
# ★ 子件引用的"自制 BOM"版本:与 bom_table 的 child_bom_no/child_bom_version 对齐,
|
||||
# 保证草稿暂存/载入期间不丢失所选版本。
|
||||
child_bom_no = db.Column(db.String(100), nullable=True, index=True, comment='子件引用的自制BOM编号')
|
||||
|
||||
@ -10,7 +10,7 @@ logger = logging.getLogger(__name__)
|
||||
class BomDraftService:
|
||||
|
||||
@staticmethod
|
||||
def save_draft(bom_no, version, parent_id, children):
|
||||
def save_draft(bom_no, version, parent_id, children, bom_remark=''):
|
||||
try:
|
||||
# 1. 删除旧草稿
|
||||
old = BomDraftTable.query.filter_by(bom_no=bom_no, version=version).all()
|
||||
@ -22,7 +22,8 @@ class BomDraftService:
|
||||
if not children:
|
||||
dummy_draft = BomDraftTable(
|
||||
bom_no=bom_no, version=version, parent_id=parent_id,
|
||||
child_id=None, dosage=0, loss_rate=0, remark=''
|
||||
child_id=None, dosage=0, loss_rate=0, remark='',
|
||||
bom_remark=bom_remark
|
||||
)
|
||||
db.session.add(dummy_draft)
|
||||
else:
|
||||
@ -34,6 +35,7 @@ class BomDraftService:
|
||||
dosage=child.get('dosage', 0),
|
||||
loss_rate=child.get('loss_rate', 0),
|
||||
remark=child.get('remark', ''),
|
||||
bom_remark=bom_remark,
|
||||
child_bom_no=child.get('child_bom_no') or None,
|
||||
child_bom_version=child.get('child_bom_version') or None
|
||||
)
|
||||
@ -87,6 +89,7 @@ class BomDraftService:
|
||||
'parent_id': parent_id,
|
||||
'parent_name': parent_material.name if parent_material else '',
|
||||
'parent_spec': parent_material.spec_model if parent_material else '',
|
||||
'remark': first.bom_remark or '', # ★ BOM 级备注
|
||||
'children': children,
|
||||
}
|
||||
|
||||
@ -125,6 +128,8 @@ class BomDraftService:
|
||||
'bom_no': bom_no,
|
||||
'version': version,
|
||||
'parent_id': draft['parent_id'],
|
||||
# ★ 草稿的 BOM 级备注要带到正式表,否则发布即丢失
|
||||
'remark': draft.get('remark', '') or '',
|
||||
'children': [
|
||||
{
|
||||
'child_id': child['child_id'],
|
||||
|
||||
@ -404,7 +404,9 @@ class BomService:
|
||||
'parent_name': parent_material.name if parent_material else '',
|
||||
'parent_spec': parent_material.spec_model if parent_material else '',
|
||||
'is_enabled': first.BomTable.is_enabled,
|
||||
'remark': first.BomTable.remark or '', # ★ 主表备注
|
||||
# ★ BOM 级备注:改取 bom_remark。此前误取 first.BomTable.remark
|
||||
# (第一个子件行的备注)冒充主表备注,是本次一并修掉的连带 bug
|
||||
'remark': first.BomTable.bom_remark or '',
|
||||
'children': children
|
||||
}
|
||||
|
||||
@ -421,6 +423,8 @@ class BomService:
|
||||
parent_id = data['parent_id']
|
||||
children = data['children']
|
||||
is_enabled = data.get('is_enabled', True)
|
||||
# ★ BOM 级备注:写入本版本每一行(与 is_enabled 等父件级字段同口径)
|
||||
bom_remark = data.get('remark', '') or ''
|
||||
|
||||
if not bom_no:
|
||||
raise ValueError('BOM编号不能为空')
|
||||
@ -527,6 +531,7 @@ class BomService:
|
||||
child_id=child['child_id'],
|
||||
dosage=child.get('dosage', 0),
|
||||
remark=child.get('remark', ''),
|
||||
bom_remark=bom_remark,
|
||||
child_bom_no=child.get('child_bom_no') or None,
|
||||
child_bom_version=child.get('child_bom_version') or None,
|
||||
is_enabled=is_enabled
|
||||
|
||||
@ -145,12 +145,7 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="备注" v-if="hasFormFieldPermission('remark')">
|
||||
<el-input v-model="form.remark" placeholder="备注信息(可选)" :disabled="isReadOnlyMode" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-col :span="14">
|
||||
<el-form-item label="版本号" prop="version" v-if="hasFormFieldPermission('version')">
|
||||
<template v-if="isSaveAsMode">
|
||||
<el-radio-group v-model="form.versionUpgradeType" :disabled="isReadOnlyMode" @change="onVersionUpgradeTypeChange">
|
||||
@ -165,6 +160,21 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- ★ BOM 级备注:独立整行,放在子件列表上方。
|
||||
原位置在编号/版本号那一行的 span=6 里,扣掉 120px 的 label 后
|
||||
输入框实际只剩 60 余像素,稍长一点的备注根本看不清。 -->
|
||||
<el-form-item label="备注" v-if="hasFormFieldPermission('remark')" style="margin-bottom: 5px;">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
placeholder="BOM 级备注(可选),如适用场景、工艺要求等"
|
||||
:disabled="isReadOnlyMode"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<div style="font-weight: bold; margin: 15px 0 10px 0; border-left: 4px solid #409EFF; padding-left: 10px;">
|
||||
子件列表
|
||||
<span style="font-weight: normal; font-size: 12px; color: #909399; margin-left: 10px;">(已选 {{ filteredChildren.length }} 条)</span>
|
||||
@ -408,6 +418,9 @@ const getDraftHash = () => {
|
||||
bom_no: form.bom_no,
|
||||
version: form.version,
|
||||
parent_id: form.parent_id,
|
||||
// ★ BOM 级备注也要参与比对,否则"只改了备注"会被防呆逻辑
|
||||
// 拦成"草稿数据无变动,无需重复暂存"
|
||||
remark: form.remark || '',
|
||||
children
|
||||
})
|
||||
}
|
||||
@ -852,6 +865,7 @@ const executeSaveDraftRequest = async (targetBomNo: string) => {
|
||||
bom_no: targetBomNo,
|
||||
version: draftVersion,
|
||||
parent_id: form.parent_id,
|
||||
remark: form.remark || '',
|
||||
children
|
||||
})
|
||||
if (res.code === 200) {
|
||||
|
||||
Reference in New Issue
Block a user