一、目标与一句话实现
QPL 在列表页导入一次 Excel,系统就同时建立「零部件成熟度管控表物料行」及其「P3-1 / P3-2 / P3-3 三阶段跟产审核记录」,两页数据通过业务唯一键自动挂钩——后续跟产审核的实际执行结果不再靠人工关联,而是由零部件现场(远程)爬坡单与 IQC 全检结果按同一业务键回写。
一次导入 = N 个物料行 + 每行 3 条阶段记录(P3-1 / P3-2 / P3-3)+ 每行 18 条开发节点占位
再导入 = 按业务键覆盖更新基础信息与计划面,不触碰执行面
二、关联关系总览
SHEET1 零部件成熟度管控表(物料行)
公司 / 工厂 / 供应商编码 / 物料编码 / 项目代码 / 零件层级 / 法规属性 / 零部件属性 / 检规 / SQE 三件套 / 关键日期…
⇄
SHEET2 跟产审核记录(阶段计划)
同前 5 列业务键 + 跟产审核阶段(P3-1/P3-2/P3-3) + 订单数量 / 需求到货时间 / 预计生产时间 / 是否跟产 / 无需跟产原因 / 全尺寸·全数检验数量 / 计划时间
两页仅靠业务键关联 公司|工厂|供应商编码|物料编码|项目代码 —— 模板中不需要任何内部 ID 列
落库
t_maturity_ctl(主表 / 物料行) 1
└──< t_maturity_followup(子表 / 跟产审核) N=3:P3-1 / P3-2 / P3-3
└──< 开发节点 N=18(由零部件开发计划回写)
⇠
执行面回写
零部件现场(远程)爬坡单 PP + IQC 全检「状态判定」
按 subject_key + stage 定位子表行并回写执行面字段
三、数据模型
3.1 主表 t_maturity_ctl(物料行 / 管控表记录)
| 字段 | 类型 | 必填 | 来源 | 说明 |
| id | bigint PK | — | 系统 | 物料行 ID(内部主键,不出现在导入模板中) |
| doc_no | varchar(20) | — | 系统生成 | 管控表单号:CD+YYYYMMDD+5位流水,如 CD2026091700001,同批次内连续取号 |
| subject_key | varchar(255) | — | 系统计算 | 业务唯一键,建唯一索引 uk_ctl_subject |
| company / plant | varchar(64) | ✔ | 导入 | 公司 / 工厂 |
| supplier_code / supplier_name | varchar(32/128) | ✔ / — | 导入 | 供应商编码(须存在于主数据)/ 名称 |
| project_code | varchar(32) | ✔ | 导入 | 项目代码,如 CF250-01 |
| material_code / material_name | varchar(64/128) | ✔ / — | 导入 | 物料编码 / 物料名称 |
| part_level | enum | ✔ | 导入 | 整车部 / 电子电器部 / 发动机部 |
| regulation_attr | enum | ✔ | 导入 | 法规件 / 非法规件 |
| part_attr | enum | ✔ | 导入 | 关键件 / 重要件 / 一般件 |
| inspection_spec | varchar(32) | ✔ | 导入 | 检规(有/无 或规范编号) |
| remark | varchar(64) | — | 导入 | 备注(零部件版本号) |
| sqe_dept / sqe_dept_2 / sqe | varchar(64) | ✔ | 导入 | SQE 科室 / SQE 部门 / SQE(工号) |
| mold_order_date / tooling_change_date | date | ✔ | 导入 | 开模指令下发日期 / 技改·修模日期 |
| special_gauge / copy_gauge | enum(是/否) | ✔ | 导入 | 是否开发专用检具 / 是否复制检具给春风 |
| risk_level | enum | — | 系统判定 | 风险等级(高风险供应商管理结果) |
| status | enum | — | 系统 | 拟定 / 已完成(导入生成=拟定,提交后=已完成) |
| import_batch_id | bigint | — | 系统 | 导入批次,便于回溯"哪次导入进来的" |
| created_by / created_dept / created_at / updated_at | — | — | 系统 | 审计字段 |
3.2 子表 t_maturity_followup(跟产审核记录)
| 字段 | 类型 | 可导入 | 说明 |
| id | bigint PK | — | 主键 |
| maturity_id | bigint FK | — | → 主表 id("物料行 ID 关联"的落地方式) |
| stage | enum | ✔ | P3-1 / P3-2 / P3-3 |
| 计划面(可由导入写入) |
| order_qty | decimal(18,3) | ✔ | 订单数量 |
| eta_date | date | ✔ | 需求到货时间 |
| plan_prod_date | date | ✔ | 预计生产时间 |
| is_follow | enum(是/否) | ✔ | 是否跟产 |
| no_follow_reason | varchar(255) | ✔ | 无需跟产原因(是否跟产=否 时必填) |
| full_dim_qty | decimal(18,3) | ✔ | 全尺寸检验数量 |
| full_inspect_qty | decimal(18,3) | ✔ | 全数检验数量 |
| plan_date | date | ✔ | 计划时间 |
| 执行面(导入模板中不提供,填了也忽略;由单据回写) |
| actual_finish_date | date | ✘ | 完成时间 ← 爬坡单回写 |
| conclusion | enum | ✘ | 审核结论:合格 / 返修 / 让步接收 / 退货 ← 爬坡单回写 |
| pass_rate | decimal(5,2) | ✘ | 零件合格率 ← 爬坡单回写 |
| undo_reason_plan | varchar(500) | ✘ | 未达成原因及计划 ← 爬坡单回写 |
| iqc_status | enum | ✘ | 状态判定(IQC 填写)← IQC 回写 |
| followup_result | enum | ✘ | 跟产审核完成情况:未开始 / 进行中 / 已完成 / 已逾期 / 无需跟产(系统判定) |
| source_doc_type / source_doc_no | varchar | ✘ | 回写来源:现场爬坡单 PP / 远程爬坡单 / IQC,含单号(页面可点跳转) |
唯一约束:uk_followup(maturity_id, stage) —— 一个物料行每个阶段只有一条记录,重复导入只做更新。
3.3 关系
t_maturity_ctl (1) ──< t_maturity_followup (N = 3:P3-1 / P3-2 / P3-3)
│
└──< t_dev_node (N = 18:开发节点,计划/实际完成时间由零部件开发计划回写)
- 物料行 ↔ 跟产审核记录:1 : 3(阶段枚举固定)
- 物料行 ↔ 开发节点:1 : 18(导入生成占位行,待开发计划回写)
四、关联规则(核心)
4.1 业务唯一键定义
subject_key = norm(公司) + '|' + norm(工厂) + '|' + norm(供应商编码) + '|' + norm(物料编码) + '|' + norm(项目代码)
norm():去首尾/中间空格、全角转半角、字母统一大写
- 唯一索引直接建在
subject_key 上,兜底防重(并发也挡得住)
- 是否包含项目代码:待确认——现有管控表是"新车型开发"维度、带项目代码(CF250-01),建议保留;若物料编码跨项目唯一,可去掉
4.2 子表如何挂到父行
- 导入时先用业务键在
t_maturity_ctl 查 id:命中=更新,未命中=新增并取号
- 用该
id 定位/创建子表行:不存在则插入 3 行(P3-1/P3-2/P3-3);存在则按 stage 更新
- 子表冗余一份
subject_key + stage 到查询视图,便于排查与回写定位
4.3 更新语义("以模板为准"的边界)
| 场景 | 处理 |
| 业务键命中已有行 | 更新基础信息字段(以模板为准);空白单元格=未填写,不覆盖已有值(避免把已有 SQE 等清空) |
| 业务键未命中 | 新增物料行 + 生成 3 条阶段记录 + 18 条开发节点占位 |
| 子表阶段记录 | 只覆盖计划面 9 个字段;执行面字段永不因导入被改写 |
| 重复导入同一文件 | 第二次全部判定为"更新且无变化",不产生重复行(幂等) |
4.4 执行面回写链路(导入之后)
零部件现场(远程)爬坡单 PP ──提交 / 审核通过──┐
IQC 全检填写「状态判定」 ──────────────┤
▼
按 (subject_key, stage) 定位 t_maturity_followup 行
│
回写:完成时间 / 审核结论 / 零件合格率 / 未达成原因及计划 / 状态判定 / 来源单号
- 冲突策略:以业务单据为准(覆盖任何导入值)
- 单据未生成 → 子表行保持空白,页面显示「未开始」
- 跟产单的键:单据上带管控表单号
doc_no + stage,或带全部业务键字段(推荐:单据落库时冗余 subject_key,回写零成本)
4.5 是否跟产 = 否
- 「无需跟产原因」必填校验
- 该阶段不生成跟产任务、不参与逾期统计,
followup_result = 无需跟产
4.6 逾期判定(与开发节点同口径)
| 条件 | 跟产审核完成情况 |
| 当前时间 < 计划时间 且 完成时间为空 | 进行中 |
| 完成时间非空 | 已完成 |
| 当前时间 > 计划时间 且 未完成 | 已逾期(触发钉钉提醒,与开发节点逾期提醒同逻辑) |
五、导入模板结构(双 SHEET)
SHEET1 零部件成熟度管控表(物料行基础信息)
公司* | 工厂* | 供应商编码* | 供应商名称 | 项目代码* | 物料编码* | 物料名称 | 零件层级* | 法规属性* | 零部件属性* | 检规* | 备注(零部件版本号) | SQE科室* | SQE部门* | SQE*(工号) | 开模指令下发日期* | 技改/修模日期* | 是否开发专用检具* | 是否复制检具给春风*
SHEET2 跟产审核记录(阶段计划)
公司* | 工厂* | 供应商编码* | 物料编码* | 项目代码* | 跟产审核阶段*(P3-1/P3-2/P3-3) | 订单数量 | 需求到货时间 | 预计生产时间 | 是否跟产 | 无需跟产原因 | 全尺寸检验数量 | 全数检验数量 | 计划时间
· 前 5 列 = 定位父行的业务键,必须与 SHEET1 完全同名同值(这就是"两页关联"的全部要求,无需内部 ID 列)
· SHEET2 不提供完成时间 / 审核结论 / 零件合格率 / 未达成原因及计划 / 状态判定 / 跟产审核完成情况(执行面,由回写)
· 一行物料最多 3 行阶段记录;只填 1~2 个阶段也允许,其余阶段留空待执行
六、导入流程(9 步)
| # | 步骤 | 处理 | 失败处理 |
| 1 | 模板下载 | 系统导出带表头、枚举字典校验、示例行的 xls/xlsx;按当前用户所属公司/工厂预置默认值 | — |
| 2 | 上传 | 前端校验扩展名 xls/xlsx、大小 ≤ 100MB,支持点击或拖拽 | 阻断并提示 |
| 3 | 解析 | 解析两个 SHEET,逐行 trim、日期归一化 yyyy-MM-dd、枚举去空格/大小写容错 | 报"文件无法解析" |
| 4 | 结构校验 | SHEET 名与必需列是否齐全(列顺序不敏感,列名需匹配) | 阻断并指出缺失列名 |
| 5 | 行级校验 | 必填、枚举值集、供应商编码/物料编码存在性、日期格式、数量非负 | 逐行记录错误(行号+原因) |
| 6 | 关联校验 | SHEET2 的 5 键组合必须能在 SHEET1 命中;同文件内同键重复报错;stage 仅 P3-1/P3-2/P3-3;同物料行 × 阶段唯一 | 报"父行不存在 / 重复行 / 阶段非法" |
| 7 | 差异比对 | 按业务键分为新增 / 更新 / 无变化,生成导入预览:总行数、新增、更新、错误明细 | 存在错误 → 默认全量阻断(避免半截数据),可选"仅导入正确行" |
| 8 | 落库(事务) | 主表 upsert → 子表按阶段 upsert → 新增行生成 18 条开发节点 → 写 import_batch / import_log | 任一失败回滚整个批次 |
| 9 | 结果反馈 | 提示成功 N 条 / 更新 M 条 / 失败 K 条;失败明细可下载;列表刷新出 Tab | — |
单号与批次:一次导入 N 个物料行 → 生成 N 张管控表单(CD+YYYYMMDD+5位流水,批次内连续取号),同批次共用 import_batch_id,便于整批回溯/回滚。
七、导入后的页面表现
列表页
- 导入成功 → 按"供应商 + 单个物料"逐行展示,一行一张管控表单(多 Tab 页签,Tab 标题=单号)
- 状态=拟定(可编辑 / 删除 / 提交);提交后=已完成(仅可查看)
- 列表可区分来源:手工创建 / 导入(含批次)
详情页「跟产审核记录」区(P3-1 / P3-2 / P3-3 三行固定)
- 计划面字段白底可编辑(拟定状态):订单数量、需求到货时间、预计生产时间、是否跟产、无需跟产原因、全尺寸检验数量、全数检验数量、计划时间
- 执行面字段灰底只读,单元格内标注来源单号(如 PP2026091200001,可点跳转):完成时间、审核结论、零件合格率、未达成原因及计划、状态判定(IQC填写)、跟产审核完成情况
- 状态=已完成 → 全部只读
- 再导入变更时,仅基础信息与计划面被覆盖,执行面保留并在变更日志留痕
八、异常与边界
| 类别 | 场景 | 处理 |
| 文件 | 非 xls/xlsx、> 100MB | 阻断并提示 |
| SHEET 名不对、缺列 | 阻断并指出原因 |
| 数据 | 供应商编码不存在、物料编码不存在 | 行级报错(提示检查大小写/主数据) |
| 枚举非法、日期格式错、数量为负 | 行级报错,阻断导入 |
| 关联 | SHEET2 找不到父行、同文件重复键 | 行级报错,阻断导入 |
| 阶段非法、同物料行 × 阶段重复 | 行级报错,阻断导入 |
| 冲突 | 同批次同键多行 | 保留最后一行 + warning |
| 并发 | 两人同时导入同一键 | updated_at 乐观锁,提示"该行已被 X 于 T 更新,是否覆盖" |
| 幂等 | 同一文件重复导入 | 第二次全部"更新无变化",唯一索引兜底 |
| 删除 | 管控表行删除 | 级联软删 3 条阶段记录与 18 条节点 |
九、开发要点
- 唯一索引:
uk_ctl_subject(subject_key)、uk_followup(maturity_id, stage)——防重靠数据库兜底,不靠应用判断
- 异步导入:大文件走异步任务(返回 task_id + 轮询进度),页面复用现有「文件中心 / 异步导入任务」入口
- 回写接口:爬坡单 / IQC 侧统一调用
writeBackFollowup(subjectKey, stage, payload),内部只更新执行面字段并记 source_doc_no
- 键规范化在入库前统一执行,避免"全角括号 / 大小写不同"造成假新增
- 导入日志:行号级错误明细存
import_log,页面可下载,便于 QPL 修正后重传
十、待确认项
需要业务/产品拍板的 4 项
- 项目代码是否纳入唯一键——若同一物料编码跨车型复用,必须保留;若物料编码本身已唯一,可简化
- 空白单元格是否覆盖——本方案取"空白不覆盖"(更安全);若业务要求"模板即全量",需改为空白也清空
- 导入颗粒度——本方案为"一行物料一张管控表单",与现有原型(列表一行=一张单)一致;若期望"一个批次一张单",需调整单号生成与 Tab 展示
- 跟产单与管控表的绑定方式——建议爬坡单落库时冗余
subject_key,回写零成本;若不行,则回写时按业务键反查