diff --git a/klp-ui/src/views/wms/processSpec/coilSpecBind.vue b/klp-ui/src/views/wms/processSpec/coilSpecBind.vue index 83ce5b82..04d6bb24 100644 --- a/klp-ui/src/views/wms/processSpec/coilSpecBind.vue +++ b/klp-ui/src/views/wms/processSpec/coilSpecBind.vue @@ -178,75 +178,78 @@ - -
- 暂无参数数据 -
- + + + @@ -391,9 +394,41 @@ import { listProcessCoilRecord, batchRebindCoilRecord } from '@/api/wms/processCoilRecord' import { listProcessSpec } from '@/api/wms/processSpec' import { listProcessSpecVersion } from '@/api/wms/processSpecVersion' -import { listProcessPlan } from '@/api/wms/processPlan' -import { listProcessPlanParam } from '@/api/wms/processPlanParam' +import { listProcessPlan, addProcessPlan } from '@/api/wms/processPlan' +import { listProcessPlanParam, addProcessPlanParam } from '@/api/wms/processPlanParam' import { listAllProcessAnomaly } from '@/api/wms/processAnomaly' +import { getPresetSetupByCoilId } from '@/api/l2/timing' + +// 三段 L1 预设设定值的结构定义(对应 PLTCM_PRESET_SETUP 表) +const PRESET_PLANS = [ + { + segmentType: 'INLET', segmentName: '入口段', pointName: '入口设定值', pointCode: 'PRESET_INLET', sortOrder: 10, + params: [ + { paramCode: 'POR_TEN', paramName: '开卷机单位张力', unit: 'N/mm²' }, + { paramCode: 'CEL_TEN', paramName: '入口活套单位张力', unit: 'N/mm²' }, + { paramCode: 'FLAT_MESH_1', paramName: '矫直机1#辊插入量', unit: 'mm' }, + { paramCode: 'FLAT_MESH_2', paramName: '矫直机2#辊插入量', unit: 'mm' } + ] + }, + { + segmentType: 'PROCESS', segmentName: '工艺段', pointName: '工艺设定值', pointCode: 'PRESET_PROCESS', sortOrder: 20, + params: [ + { paramCode: 'TLV_TEN', paramName: '拉弯矫直机单位张力', unit: 'N/mm²' }, + { paramCode: 'TLV_ELONG', paramName: '拉弯矫直机延伸率', unit: '%' }, + { paramCode: 'TLV_MESH_1', paramName: '弯曲辊1#弯辊量', unit: 'mm' }, + { paramCode: 'TLV_MESH_2', paramName: '弯曲辊2#弯辊量', unit: 'mm' } + ] + }, + { + segmentType: 'OUTLET', segmentName: '出口段', pointName: '出口设定值', pointCode: 'PRESET_OUTLET', sortOrder: 30, + params: [ + { paramCode: 'TR_TEN', paramName: '酸洗出口张力辊张力', unit: 'N/mm²' }, + { paramCode: 'TRIM_TEN', paramName: '切边段单位张力', unit: 'N/mm²' }, + { paramCode: 'TEL_TEN', paramName: '联机活套单位张力', unit: 'N/mm²' }, + { paramCode: 'CXL_TEN', paramName: '出口活套单位张力', unit: 'N/mm²' } + ] + } +] const VERSION_STATUS = [ { value: 'DRAFT', label: '草稿' }, @@ -422,6 +457,7 @@ export default { detailLoading: false, detailRow: null, detailParams: [], + detailActiveTab: 'INLET', bindDialogVisible: false, removeOldRecord: false, @@ -456,6 +492,23 @@ export default { } return Object.values(planMap).sort((a, b) => (a.sortOrder || 0) - (b.sortOrder || 0)) }, + detailSegmentTabs() { + const SEG_ORDER = ['INLET', 'PROCESS', 'OUTLET'] + const SEG_LABELS = { INLET: '入口段', PROCESS: '工艺段', OUTLET: '出口段' } + const map = {} + for (const g of this.detailParamGroups) { + const seg = g.segmentType || 'OTHER' + if (!map[seg]) { + map[seg] = { segmentType: seg, segmentLabel: SEG_LABELS[seg] || seg, anomalyCount: 0, groups: [] } + } + map[seg].groups.push(g) + map[seg].anomalyCount += g.params.filter(p => p._hasAnomaly).length + } + for (const seg of SEG_ORDER) { + if (!map[seg]) map[seg] = { segmentType: seg, segmentLabel: SEG_LABELS[seg], anomalyCount: 0, groups: [] } + } + return SEG_ORDER.map(s => map[s]) + }, // 选中行是否全来自同一个版本(决定是否可以"移除旧记录") singleSourceVersion() { if (!this.selected.length) return false @@ -580,6 +633,7 @@ export default { openDetail(row) { this.detailRow = row this.detailParams = [] + this.detailActiveTab = 'INLET' this.detailDrawerVisible = true this.loadDetailData(row) }, @@ -587,6 +641,45 @@ export default { this.detailRow = null this.detailParams = [] }, + // Returns true if any preset plan points were auto-created + async autoInitPresetParams(row, existingPlans) { + try { + const existingCodes = new Set(existingPlans.map(p => p.pointCode)) + const missing = PRESET_PLANS.filter(p => !existingCodes.has(p.pointCode)) + if (!missing.length) return false + const srcId = row.enCoilId || row.coilId + if (!srcId) return false + const presetRes = await getPresetSetupByCoilId(srcId) + const preset = (presetRes && presetRes.data && presetRes.data.data) || {} + for (const def of missing) { + const planRes = await addProcessPlan({ + versionId: row.versionId, + segmentType: def.segmentType, + segmentName: def.segmentName, + pointName: def.pointName, + pointCode: def.pointCode, + sortOrder: def.sortOrder + }) + const planId = planRes.data + for (const p of def.params) { + const val = preset[p.paramCode.toLowerCase()] ?? preset[p.paramCode] + await addProcessPlanParam({ + planId, + paramCode: p.paramCode, + paramName: p.paramName, + unit: p.unit, + targetValue: (val !== null && val !== undefined && val !== '') ? Number(val) : null, + presetSrcId: srcId + }) + } + } + return true + } catch (e) { + console.error('[autoInitPresetParams] failed', e) + return false + } + }, + async loadDetailData(row) { if (!row.versionId) return this.detailLoading = true @@ -595,7 +688,14 @@ export default { listProcessPlan({ versionId: row.versionId, pageNum: 1, pageSize: 200 }), listAllProcessAnomaly({ coilId: row.coilId, versionId: row.versionId }) ]) - const plans = plansRes.rows || [] + let plans = plansRes.rows || [] + + const added = await this.autoInitPresetParams(row, plans) + if (added) { + const refreshed = await listProcessPlan({ versionId: row.versionId, pageNum: 1, pageSize: 200 }) + plans = refreshed.rows || [] + } + const anomalyList = anomalyRes.data || [] const anomalyMap = {} for (const a of anomalyList) { @@ -910,6 +1010,54 @@ export default { min-width: 0; flex: 1; } +/* ── 分段 Tab ── */ +.seg-tabs { margin-top: 0; } +.seg-tab-bar { + display: inline-flex; + background: #f0f2f5; + border-radius: 8px; + padding: 3px; + margin-bottom: 14px; + gap: 2px; +} +.seg-tab-btn { + border: none; + background: transparent; + border-radius: 6px; + padding: 6px 20px; + font-size: 13px; + color: #606266; + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 6px; + transition: background .15s, color .15s, box-shadow .15s; + white-space: nowrap; + outline: none; +} +.seg-tab-btn:hover:not(.is-active) { background: #e4e7ed; color: #303133; } +.seg-tab-btn.is-active { + background: #fff; + color: #303133; + font-weight: 600; + box-shadow: 0 1px 5px rgba(0,0,0,.1); +} +.seg-badge { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 16px; + height: 16px; + padding: 0 4px; + background: #f56c6c; + color: #fff; + border-radius: 8px; + font-size: 10px; + font-weight: 700; + line-height: 1; +} +.seg-tab-pane {} + .param-group { margin-bottom: 20px; } .param-group-hd { display: flex; @@ -918,15 +1066,8 @@ export default { margin-bottom: 6px; padding: 0 2px; } -.pg-segment { - font-size: 11px; - color: #fff; - background: #5F7BA0; - padding: 1px 9px; - border-radius: 10px; -} .pg-point { font-size: 13px; font-weight: 600; color: #303133; } -.pg-code { font-size: 11px; color: #909399; margin-left: 5px; } +.pg-code { font-size: 11px; color: #909399; } .val-danger { color: #f56c6c; font-weight: 600; } .val-ok { color: #67c23a; } .val-anomaly { color: #e6a23c; font-weight: 600; } @@ -936,6 +1077,7 @@ export default { font-size: 13px; color: #c0c4cc; } +.param-group :deep(.row-anomaly td) { background: #fff8f0 !important; } ::v-deep .row-anomaly td { background: #fff8f8 !important; } ::v-deep .el-drawer__header { padding: 16px 20px 12px; font-size: 15px; font-weight: 600; color: #303133; margin-bottom: 0; border-bottom: 1px solid #f0f2f5; } ::v-deep .el-drawer__body { overflow: hidden; }