# 合同模块产品字段变更 ## 变更说明 合同模块的产品来源从 **CRM 产品** 改为 **MDM 物料**,涉及字段名称变更。 --- ## 数据库变更 SQL ```sql -- ============================================= -- 合同产品表字段变更 -- ============================================= -- 1. 删除旧字段(如果有数据请先备份) ALTER TABLE `crm_contract_product` DROP COLUMN `product_id`; ALTER TABLE `crm_contract_product` DROP COLUMN `product_price`; -- 2. 如果新字段不存在,则添加(根据实际情况判断是否需要执行) -- ALTER TABLE `crm_contract_product` ADD COLUMN `item_id` bigint DEFAULT NULL COMMENT 'MDM物料编号' AFTER `contract_id`; -- ALTER TABLE `crm_contract_product` ADD COLUMN `item_unit_id` bigint DEFAULT NULL COMMENT '计量单位编号' AFTER `item_id`; -- ALTER TABLE `crm_contract_product` ADD COLUMN `item_price` decimal(24,6) DEFAULT NULL COMMENT '物料原价' AFTER `item_unit_id`; ``` --- ## 涉及页面 - 合同表单页面(新建/编辑合同) - 合同详情页面 --- ## API 变更 ### 1. 创建/更新合同接口 | 方法 | 路径 | 说明 | |------|------|------| | POST | /crm/contract/create | 创建合同 | | PUT | /crm/contract/update | 更新合同 | ### 2. 请求参数变更(products 字段) #### 旧字段(已废弃) | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | productId | Long | 是 | CRM 产品编号 | | productPrice | BigDecimal | 否 | 产品价格 | | sellingPrice | BigDecimal | 否 | 销售价(用作合同价) | #### 新字段 | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | itemId | Long | 是 | MDM 物料编号 | | itemPrice | BigDecimal | 是 | 物料原价 | | contractPrice | BigDecimal | 是 | 合同价格 | | count | Integer | 是 | 数量 | ### 3. 请求示例 **旧格式(不再支持):** ```json { "name": "合同名称", "customerId": 1, "products": [ { "productId": 4, "sellingPrice": 1111, "count": 10 } ] } ``` **新格式:** ```json { "name": "合同名称", "customerId": 1, "products": [ { "itemId": 4, "itemPrice": 1000, "contractPrice": 1111, "count": 10 } ] } ``` --- ## 响应变更 ### 合同详情接口响应 | 方法 | 路径 | 说明 | |------|------|------| | GET | /crm/contract/get | 获取合同详情 | #### 产品明细字段变更 | 旧字段 | 新字段 | 说明 | |--------|--------|------| | productId | itemId | MDM 物料编号 | | productName | itemName | 物料名称 | | productNo | itemCode | 物料编码 | | productUnit | itemUnitName | 计量单位名称 | | productPrice | itemPrice | 物料原价 | | - | itemBarCode | 物料条码(新增) | --- ## 前端修改点 ### 1. 物料选择组件 将 **CRM 产品选择器** 改为 **MDM 物料选择器**。 ```html ``` ### 2. 物料选择回调 ```js methods: { handleItemChange(item) { // 选择物料后自动填充价格信息 this.product.itemId = item.id this.product.itemPrice = item.salesPrice // 物料原价 this.product.contractPrice = item.salesPrice // 合同价格(默认等于原价,可修改) } } ``` ### 3. 表格列字段修改 ```html ``` ### 4. data 数据修改 ```js // 产品明细数据结构 product: { itemId: null, // MDM 物料编号 itemPrice: null, // 物料原价 contractPrice: null, // 合同价格 count: null // 数量 } ``` --- ## MDM 物料选择器 API ### 获取物料列表 | 方法 | 路径 | 说明 | |------|------|------| | GET | /mdm/item/page | 分页查询物料 | **请求参数:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | code | String | 否 | 物料编码 | | name | String | 否 | 物料名称 | | barCode | String | 否 | 物料条码 | | status | Integer | 否 | 状态(0启用 1禁用),传 0 | **响应字段:** | 字段 | 类型 | 说明 | |------|------|------| | id | Long | 物料编号(即 itemId) | | code | String | 物料编码 | | name | String | 物料名称 | | barCode | String | 物料条码 | | salesPrice | BigDecimal | 销售价 | | unitMeasureId | Long | 计量单位编号 | | unitMeasureName | String | 计量单位名称 | --- ## 注意事项 1. **物料必须先启用**:只能选择状态为"启用"的 MDM 物料 2. **价格可修改**:`contractPrice` 默认等于物料原价,但可以手动修改 3. **过渡期**:后端暂时兼容 `productId` 和 `sellingPrice` 字段,但后续会移除兼容逻辑 4. **其他模块同步修改**:销售报价单也使用 MDM 物料,字段与合同一致 --- # 2026-09-24 增量:合同产品明细显示字段补全 + 删除合同级联清理明细 ## 一、显示字段补全 ### 背景 合同详情接口此前未解析产品明细的计量单位名称,条码字段名与前端列绑定不一致,导致以下位置 **单位列、物料条码列恒为空**(商机接口一直正常返回,本次对齐商机做法): - 合同详情 →「产品」页签(`ProductDetailsList` 共用组件) - 合同审批页 → 产品明细表 - 编辑合同弹窗 → 产品表格(已保存行次的规格型号同样为空) ### 涉及的接口 | 方法 | 路径 | 说明 | |------|------|------| | GET | /crm/contract/get | 获得合同详情(含产品明细),本次变更仅影响此接口 | > `/crm/contract/page`、`/crm/contract/page-by-customer`、`/crm/contract/page-by-business`、导出 Excel 均**不含**产品明细,不受影响。 ### 响应字段变更(data.products[]) | 字段 | 类型 | 变更 | 说明 | |------|------|------|------| | itemUnitName | String | 补全取值 | 计量单位名称,按 `itemUnitId` 解析(如「米」「个」),此前恒为 null | | barCode | String | **字段更名** | 物料条码,原字段名 `itemBarCode` 改为 `barCode`,与商机接口及前端产品明细列表列绑定(field: 'barCode')一致 | | itemSpecification | String | 新增 | 规格型号,取自 MDM 物料,与商机接口一致 | | itemBarCode | - | 已移除 | 前端如有引用请改用 `barCode` | **响应示例(节选):** ```json { "code": 0, "data": { "id": 19, "no": "WTJC2025120501", "products": [ { "id": 42, "itemId": 38, "itemCode": "PHC300AB70-4.5", "itemName": "PHC300AB70-4.5", "barCode": null, "itemSpecification": null, "itemUnitId": 3, "itemUnitName": "米", "itemPrice": 68.000000, "contractPrice": 68.000000, "count": 179208.000000, "totalPrice": 12186144.000000 } ] } } ``` ### 字段展示规则 | 字段 | 展示位置 | 说明 | |------|----------|------| | itemUnitName | 合同详情产品页签、审批页产品表、编辑弹窗产品表 | 单位列,取值 MDM 计量单位名称 | | barCode | 合同详情产品页签(物料条码列) | 与商机产品列表列绑定字段一致 | | itemSpecification | 编辑弹窗产品表格 | 详情页产品页签无此列 | ### 业务规则说明 | 场景 | 规则 | |------|------| | 单位名称来源 | 由 MDM 计量单位表按产品明细的 itemUnitId 解析;导入的合同,itemUnitId 取自物料主数据的计量单位 | | 条码取值 | 取自 MDM 物料档案的条码;物料未维护条码时为空,属正常 | | 规格型号取值 | 取自 MDM 物料档案的规格型号;未维护时为空 | | 编辑合同后保存 | 产品明细回传时 barCode / itemSpecification / itemUnitName 属于展示字段,后端不落库,由接口每次按 itemId / itemUnitId 实时解析,不影响保存结果 | ### 注意事项 - 本次为**响应字段名变更**(itemBarCode → barCode)。前端类型声明 `CrmContractApi.ContractProduct.itemBarCode` 建议同步改为 `barCode`(仅类型声明,运行时不读该字段,不改也不报错)。 - 前端页面代码**无需改动**:单位列、条码列、规格型号列绑定字段已与本次返回一致。 - 合同「产品」页签、审批页产品表复用同一列定义,修复后三处同时生效。 --- ## 二、删除合同级联清理产品明细 ### 背景 `DELETE /crm/contract/delete` 此前只删除合同主表、报价单引用与数据权限,**未删除 `crm_contract_product` 产品明细**,导致删除合同后明细成为孤儿数据(表内 deleted=0 但合同已不存在)。 ### 变更后行为 | 操作 | 影响数据 | |------|----------| | 删除合同 | 合同主表(逻辑删除)+ 产品明细(逻辑删除)+ 报价单引用解除 + 数据权限删除 | ### 注意事项 - 级联删除为**逻辑删除**(deleted=1),与合同主表口径一致,历史数据仍可追溯。 - 合同已被回款引用时依旧禁止删除(原有校验不变)。 - 历史遗留的孤儿明细(本次修复前删除产生的)不会自动清理,如需清理请按 contract_id 核对后手工处理。