diff --git a/klp-admin/src/main/resources/db/migration/V16__qc_quality_review_warehouse.sql b/klp-admin/src/main/resources/db/migration/V16__qc_quality_review_warehouse.sql new file mode 100644 index 000000000..d4c00eafc --- /dev/null +++ b/klp-admin/src/main/resources/db/migration/V16__qc_quality_review_warehouse.sql @@ -0,0 +1,10 @@ +-- ------------------------------------------------------------ +-- 质量评审 — 钢卷明细增加逻辑库区字段 +-- V16__qc_quality_review_warehouse.sql +-- ------------------------------------------------------------ + +ALTER TABLE `qc_quality_review_coil` + ADD COLUMN `before_warehouse_id` bigint DEFAULT NULL COMMENT '改判前逻辑库区ID' AFTER `before_quality`, + ADD COLUMN `before_warehouse_name` varchar(100) DEFAULT NULL COMMENT '改判前逻辑库区名称' AFTER `before_warehouse_id`, + ADD COLUMN `target_warehouse_id` bigint DEFAULT NULL COMMENT '改判后目标库区ID' AFTER `regrade_quality`, + ADD COLUMN `target_warehouse_name` varchar(100) DEFAULT NULL COMMENT '改判后目标库区名称' AFTER `target_warehouse_id`; diff --git a/klp-mes/src/main/java/com/klp/mes/qc/domain/QcQualityReviewCoil.java b/klp-mes/src/main/java/com/klp/mes/qc/domain/QcQualityReviewCoil.java index cf8f3a68c..6cfdc4422 100644 --- a/klp-mes/src/main/java/com/klp/mes/qc/domain/QcQualityReviewCoil.java +++ b/klp-mes/src/main/java/com/klp/mes/qc/domain/QcQualityReviewCoil.java @@ -55,9 +55,21 @@ public class QcQualityReviewCoil extends BaseEntity { /** 改判前质量等级 */ private String beforeQuality; + /** 改判前逻辑库区ID */ + private Long beforeWarehouseId; + + /** 改判前逻辑库区名称 */ + private String beforeWarehouseName; + /** 改判后质量状态(字典:regrade_quality_type) */ private String regradeQuality; + /** 改判后目标库区ID */ + private Long targetWarehouseId; + + /** 改判后目标库区名称 */ + private String targetWarehouseName; + /** 执行状态:0=待执行 1=已执行 */ private Long executeStatus; diff --git a/klp-mes/src/main/java/com/klp/mes/qc/domain/bo/QcQualityReviewCoilBo.java b/klp-mes/src/main/java/com/klp/mes/qc/domain/bo/QcQualityReviewCoilBo.java index a9c304d05..1f64a2aef 100644 --- a/klp-mes/src/main/java/com/klp/mes/qc/domain/bo/QcQualityReviewCoilBo.java +++ b/klp-mes/src/main/java/com/klp/mes/qc/domain/bo/QcQualityReviewCoilBo.java @@ -55,9 +55,21 @@ public class QcQualityReviewCoilBo extends BaseEntity { /** 改判前质量等级 */ private String beforeQuality; + /** 改判前逻辑库区ID */ + private Long beforeWarehouseId; + + /** 改判前逻辑库区名称 */ + private String beforeWarehouseName; + /** 改判后质量状态 */ private String regradeQuality; + /** 改判后目标库区ID */ + private Long targetWarehouseId; + + /** 改判后目标库区名称 */ + private String targetWarehouseName; + /** 执行状态 */ private Long executeStatus; diff --git a/klp-mes/src/main/java/com/klp/mes/qc/domain/vo/QcQualityReviewCoilVo.java b/klp-mes/src/main/java/com/klp/mes/qc/domain/vo/QcQualityReviewCoilVo.java index 21e203f75..10bf13148 100644 --- a/klp-mes/src/main/java/com/klp/mes/qc/domain/vo/QcQualityReviewCoilVo.java +++ b/klp-mes/src/main/java/com/klp/mes/qc/domain/vo/QcQualityReviewCoilVo.java @@ -53,9 +53,21 @@ public class QcQualityReviewCoilVo extends BaseEntity { /** 改判前质量等级 */ private String beforeQuality; + /** 改判前逻辑库区ID */ + private Long beforeWarehouseId; + + /** 改判前逻辑库区名称 */ + private String beforeWarehouseName; + /** 改判后质量状态 */ private String regradeQuality; + /** 改判后目标库区ID */ + private Long targetWarehouseId; + + /** 改判后目标库区名称 */ + private String targetWarehouseName; + /** 执行状态 */ private Long executeStatus; diff --git a/klp-mes/src/main/java/com/klp/mes/qc/service/impl/QcQualityReviewServiceImpl.java b/klp-mes/src/main/java/com/klp/mes/qc/service/impl/QcQualityReviewServiceImpl.java index df9f7862c..83642a870 100644 --- a/klp-mes/src/main/java/com/klp/mes/qc/service/impl/QcQualityReviewServiceImpl.java +++ b/klp-mes/src/main/java/com/klp/mes/qc/service/impl/QcQualityReviewServiceImpl.java @@ -11,7 +11,9 @@ import com.klp.common.core.page.TableDataInfo; import com.klp.common.utils.StringUtils; import com.klp.common.helper.LoginHelper; import com.klp.domain.WmsMaterialCoil; +import com.klp.domain.WmsWarehouse; import com.klp.mapper.WmsMaterialCoilMapper; +import com.klp.mapper.WmsWarehouseMapper; import com.klp.service.IWmsMaterialCoilService; import com.klp.mes.qc.domain.QcQualityReview; import com.klp.mes.qc.domain.QcQualityReviewCoil; @@ -43,13 +45,11 @@ import java.util.*; @Service public class QcQualityReviewServiceImpl implements IQcQualityReviewService { - /** 技术部逻辑库ID(C/D级改判后移入此库区) */ - private static final Long TECH_WAREHOUSE_ID = 2019583656787259393L; - private final QcQualityReviewMapper baseMapper; private final QcQualityReviewCoilMapper coilMapper; private final QcQualityReviewLogMapper logMapper; private final WmsMaterialCoilMapper wmsMaterialCoilMapper; + private final WmsWarehouseMapper wmsWarehouseMapper; private final IWmsMaterialCoilService wmsMaterialCoilService; /** @@ -313,12 +313,11 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService { coil.getCoilId(), coil.getRegradeQuality(), reason); } - // 2. 根据改判后质量等级自动更新钢卷所在逻辑库区 - Long targetWarehouseId = determineTargetWarehouse(coil.getRegradeQuality()); - if (targetWarehouseId != null && coil.getCoilId() != null) { + // 2. 使用手动指定的目标逻辑库区更新钢卷所在库区 + if (coil.getTargetWarehouseId() != null && coil.getCoilId() != null) { wmsMaterialCoilMapper.update(null, Wrappers.lambdaUpdate() .eq(WmsMaterialCoil::getCoilId, coil.getCoilId()) - .set(WmsMaterialCoil::getWarehouseId, targetWarehouseId)); + .set(WmsMaterialCoil::getWarehouseId, coil.getTargetWarehouseId())); } // 3. 更新明细执行状态 @@ -359,10 +358,12 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService { coil.setGroupSeq(seq); } // 若未传改判前质量等级,从钢卷表获取 - if (StringUtils.isBlank(coil.getBeforeQuality()) && coil.getCoilId() != null) { + if (coil.getCoilId() != null) { WmsMaterialCoil wmsCoil = wmsMaterialCoilMapper.selectById(coil.getCoilId()); if (wmsCoil != null) { - coil.setBeforeQuality(wmsCoil.getQualityStatus()); + if (StringUtils.isBlank(coil.getBeforeQuality())) { + coil.setBeforeQuality(wmsCoil.getQualityStatus()); + } if (StringUtils.isBlank(coil.getCurrentCoilNo())) { coil.setCurrentCoilNo(wmsCoil.getCurrentCoilNo()); } @@ -372,6 +373,14 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService { if (coil.getNetWeight() == null) { coil.setNetWeight(wmsCoil.getNetWeight()); } + // 自动带出当前逻辑库区 + if (coil.getBeforeWarehouseId() == null && wmsCoil.getWarehouseId() != null) { + coil.setBeforeWarehouseId(wmsCoil.getWarehouseId()); + WmsWarehouse wh = wmsWarehouseMapper.selectById(wmsCoil.getWarehouseId()); + if (wh != null) { + coil.setBeforeWarehouseName(wh.getWarehouseName()); + } + } } } coilMapper.insert(coil); @@ -402,23 +411,6 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService { return "QR-" + dateStr + "-" + String.format("%04d", count + 1); } - /** - * 根据改判后质量等级确定目标逻辑库区 - * O/A/B → 不移动,C+/C/C- → 技术部逻辑库,D+/D/D- → 技术部逻辑库 - */ - private Long determineTargetWarehouse(String regradeQuality) { - if (regradeQuality == null) return null; - // O/A/B 级不移动 - if ("O".equals(regradeQuality) || "A".equals(regradeQuality) || "B".equals(regradeQuality)) { - return null; - } - // C/D 级 → 技术部逻辑库 - if (regradeQuality.startsWith("C") || regradeQuality.startsWith("D")) { - return TECH_WAREHOUSE_ID; - } - return null; - } - private void validEntityBeforeSave(QcQualityReview entity) { if (StringUtils.isBlank(entity.getProductName())) { throw new RuntimeException("产品名称不能为空"); diff --git a/klp-mes/src/main/resources/mapper/qc/QcQualityReviewCoilMapper.xml b/klp-mes/src/main/resources/mapper/qc/QcQualityReviewCoilMapper.xml index b22759e1b..42879a406 100644 --- a/klp-mes/src/main/resources/mapper/qc/QcQualityReviewCoilMapper.xml +++ b/klp-mes/src/main/resources/mapper/qc/QcQualityReviewCoilMapper.xml @@ -16,7 +16,11 @@ + + + + diff --git a/klp-ui/src/api/wms/attendance.js b/klp-ui/src/api/wms/attendance.js index d1d4090c9..402a8d202 100644 --- a/klp-ui/src/api/wms/attendance.js +++ b/klp-ui/src/api/wms/attendance.js @@ -63,6 +63,19 @@ export function exportAttendanceReport(params) { url: '/wms/attendanceRecords/exportReport', method: 'post', params: params, - responseType: 'blob' + responseType: 'blob', + // enames 是数组,需要特殊序列化避免逗号被二次编码 + paramsSerializer: params => { + const searchParams = new URLSearchParams(); + Object.keys(params).forEach(key => { + const val = params[key]; + if (Array.isArray(val)) { + searchParams.append(key, val.join(',')); + } else if (val !== undefined && val !== null && val !== '') { + searchParams.append(key, val); + } + }); + return searchParams.toString(); + } }) } diff --git a/klp-ui/src/api/wms/employeeInfo.js b/klp-ui/src/api/wms/employeeInfo.js index ba694c670..0e6d4124a 100644 --- a/klp-ui/src/api/wms/employeeInfo.js +++ b/klp-ui/src/api/wms/employeeInfo.js @@ -42,3 +42,20 @@ export function delEmployeeInfo(infoId) { method: 'delete' }) } + +// 获取所有不重复的部门名称 +export function getDepts() { + return request({ + url: '/wms/employeeInfo/depts', + method: 'get' + }) +} + +// 根据部门查询在职员工 +export function getEmployeesByDept(dept) { + return request({ + url: '/wms/employeeInfo/employeesByDept', + method: 'get', + params: { dept } + }) +} diff --git a/klp-ui/src/views/crm/components/CoilTable.vue b/klp-ui/src/views/crm/components/CoilTable.vue index 3739463ab..26d7b08d1 100644 --- a/klp-ui/src/views/crm/components/CoilTable.vue +++ b/klp-ui/src/views/crm/components/CoilTable.vue @@ -55,7 +55,7 @@ - + @@ -282,4 +282,10 @@ export default { }, } } - \ No newline at end of file + + + \ No newline at end of file diff --git a/klp-ui/src/views/crm/contract/components/ProductContent.vue b/klp-ui/src/views/crm/contract/components/ProductContent.vue index 0525b001d..0f16f2a7f 100644 --- a/klp-ui/src/views/crm/contract/components/ProductContent.vue +++ b/klp-ui/src/views/crm/contract/components/ProductContent.vue @@ -39,49 +39,49 @@
-
+
{{ index + 1 }}
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -397,6 +397,10 @@ export default { align-items: center; } +.edit-cell { + padding: 0px; +} + .table-cell:last-child { border-right: none; } diff --git a/klp-ui/src/views/erp/purchaseAudit/index.vue b/klp-ui/src/views/erp/purchaseAudit/index.vue index cec0e9d61..7d7e3ab8c 100644 --- a/klp-ui/src/views/erp/purchaseAudit/index.vue +++ b/klp-ui/src/views/erp/purchaseAudit/index.vue @@ -66,7 +66,7 @@

从左侧选择一条采购合同进行审核

-
+
{{ current.planNo }} @@ -91,8 +91,9 @@
采购要求共 {{ current.items.length }} 项
- - + + + @@ -131,6 +132,7 @@ export default { return { loading: true, buttonLoading: false, + detailLoading: false, total: 0, pendingCount: 0, planList: [], @@ -175,10 +177,11 @@ export default { this.getList() }, selectPlan(row) { + this.detailLoading = true getPurchasePlan(row.planId).then(res => { this.current = res.data || {} this.auditOpinion = this.current.auditOpinion || '' - }) + }).finally(() => { this.detailLoading = false }) }, doAudit(status) { this.buttonLoading = true @@ -192,10 +195,11 @@ export default { this.getList(true) // 刷新列表但保留右侧当前计划 this.loadPendingCount() // 右侧停留在刚审核的计划:状态/历史即时更新,驳回后可直接重新审核 + this.detailLoading = true getPurchasePlan(pid).then(res => { this.current = res.data || {} this.auditOpinion = '' - }) + }).finally(() => { this.detailLoading = false }) }).finally(() => { this.buttonLoading = false }) }, auditText(s) { diff --git a/klp-ui/src/views/erp/purchaseDelivery/index.vue b/klp-ui/src/views/erp/purchaseDelivery/index.vue index 610554d87..c81bf2814 100644 --- a/klp-ui/src/views/erp/purchaseDelivery/index.vue +++ b/klp-ui/src/views/erp/purchaseDelivery/index.vue @@ -53,7 +53,7 @@

从左侧选择一条采购合同

-
+
{{ current.planNo }} @@ -61,6 +61,7 @@
刷新到货 + 下载模板 采购要求
- - - + + + + @@ -162,6 +164,7 @@ import { refreshArrival } from '@/api/erp/purchasePlan' import { getToken } from '@/utils/auth' +import * as XLSX from 'xlsx' export default { name: 'ErpPurchaseDelivery', @@ -176,6 +179,7 @@ export default { deliveryList: [], deliveryLoading: false, refreshing: false, + detailLoading: false, upload: { headers: { Authorization: 'Bearer ' + getToken() } }, progressColor: '#5b8db8' } @@ -220,7 +224,8 @@ export default { refreshDetail() { const planId = this.current.planId if (!planId) return - getPurchasePlan(planId).then(res => { this.current = { ...this.current, ...(res.data || {}) } }) + this.detailLoading = true + getPurchasePlan(planId).then(res => { this.current = { ...this.current, ...(res.data || {}) } }).finally(() => { this.detailLoading = false }) this.deliveryLoading = true listDelivery(planId).then(res => { this.deliveryList = res.data || [] }).finally(() => { this.deliveryLoading = false }) }, @@ -269,6 +274,15 @@ export default { }, contractStatusText(v) { return { 0: '草稿', 1: '生效', 2: '作废', 3: '已完成' }[v] || '—' + }, + downloadTemplate() { + const headers = ['日期', '牌号', '规格', '卷号', '单卷重量', '车号', '数量', '件数', '销售', '钢厂到站'] + const sampleRow = ['2026-01-01', 'Q235B', '1.0*1250*C', 'COIL0001', '20.50', '辽A12345', '60.8', '3', 'XS001', '沈阳站'] + const wb = XLSX.utils.book_new() + const ws = XLSX.utils.aoa_to_sheet([headers, sampleRow]) + ws['!cols'] = headers.map(h => ({ wch: h.length > 4 ? 14 : 10 })) + XLSX.utils.book_append_sheet(wb, ws, '到货模板') + XLSX.writeFile(wb, '到货导入模板.xlsx') } } } diff --git a/klp-ui/src/views/erp/purchasePlan/index.vue b/klp-ui/src/views/erp/purchasePlan/index.vue index a79b336a0..48d9fa6db 100644 --- a/klp-ui/src/views/erp/purchasePlan/index.vue +++ b/klp-ui/src/views/erp/purchasePlan/index.vue @@ -124,10 +124,13 @@
- + - + + + + @@ -157,7 +160,7 @@
-
+
{{ current.planNo }} @@ -212,9 +215,10 @@ - - - + + + + @@ -367,6 +371,7 @@ export default { }, buttonLoading: false, submitLoading: false, + detailLoading: false, selectedContracts: [], // 合同选择器 pickerOpen: false, @@ -419,7 +424,8 @@ export default { refreshDetail() { const planId = this.current.planId if (!planId) return - getPurchasePlan(planId).then(res => { this.current = { ...this.current, ...(res.data || {}) } }) + this.detailLoading = true + getPurchasePlan(planId).then(res => { this.current = { ...this.current, ...(res.data || {}) } }).finally(() => { this.detailLoading = false }) }, // ---- 新增 / 编辑 ---- resetForm() { @@ -431,6 +437,7 @@ export default { this.mode = 'edit' }, handleEdit() { + this.detailLoading = true getPurchasePlan(this.current.planId).then(res => { const d = res.data || {} this.form = { @@ -440,7 +447,7 @@ export default { } this.selectedContracts = [] this.mode = 'edit' - }) + }).finally(() => { this.detailLoading = false }) }, cancelEdit() { this.mode = this.planList.length ? 'view' : 'empty' @@ -520,7 +527,7 @@ export default { }).catch(() => cb([])) }, blankItem() { - return { spec: '', weight: '', manufacturer: '' } + return { spec: '', material: '', weight: '', manufacturer: '' } }, addItem() { // 新行继承上一行的厂商(同批多为同厂),规格/重量留空 diff --git a/klp-ui/src/views/mes/qc/qualityReview/index.vue b/klp-ui/src/views/mes/qc/qualityReview/index.vue index 7e5f634e0..3d16e6490 100644 --- a/klp-ui/src/views/mes/qc/qualityReview/index.vue +++ b/klp-ui/src/views/mes/qc/qualityReview/index.vue @@ -124,12 +124,22 @@ {{ scope.row.beforeQuality }} - + + + + + + + @@ -170,9 +180,15 @@ - + + + + +
@@ -228,7 +244,7 @@
- +
@@ -274,19 +290,37 @@ - + - + + + + - + + + + + + + @@ -372,6 +406,7 @@ import { listQualityReview, getQualityReview, addQualityReview, updateQualityRev submitQualityReview, approveQualityReview, rejectQualityReview, executeQualityReview, listQualityReviewCoil, listQualityReviewLog } from '@/api/mes/qc/qualityReview' import CoilSelector from '@/components/CoilSelector' +import { listWarehouse } from '@/api/wms/warehouse' export default { name: 'QualityReview', @@ -398,6 +433,7 @@ export default { // 钢卷选择 showCoilSelector: false, + warehouseOptions: [], // 库区下拉选项 // 编辑弹窗 dialogVisible: false, @@ -436,6 +472,11 @@ export default { created() { this.getList() }, + watch: { + dialogVisible(val) { + if (val) this.loadWarehouseOptions() + } + }, methods: { // ===== 列表 ===== handleQuery() { @@ -546,24 +587,51 @@ export default { // ===== 钢卷选择(弹窗内) ===== onDialogCoilConfirm(selected) { if (!selected || selected.length === 0) return + const existingIds = new Set(this.editForm.coilList.map(c => c.coilId)) + const newSelected = selected.filter(coil => !existingIds.has(coil.coilId)) + const dupCount = selected.length - newSelected.length + if (dupCount > 0) { + this.$message.warning(`已跳过 ${dupCount} 个重复钢卷`) + } + if (newSelected.length === 0) return const startIdx = this.editForm.coilList.length || 0 - const newCoils = selected.map((coil, idx) => ({ + const newCoils = newSelected.map((coil, idx) => ({ coilId: coil.coilId, currentCoilNo: coil.currentCoilNo, supplierCoilNo: coil.supplierCoilNo || coil.enterCoilNo, - spec: coil.specification, // CoilSelector返回的字段名为specification + spec: coil.specification, netWeight: coil.netWeight, defectDesc: '', - regradeQuality: '', // 改判后等级,由创建者填写 + regradeQuality: '', + beforeWarehouseId: coil.warehouseId || null, + beforeWarehouseName: this.getWarehouseName(coil.warehouseId), + targetWarehouseId: null, + targetWarehouseName: '', groupSeq: startIdx + idx + 1, beforeQuality: coil.qualityStatus || 'O' })) this.editForm.coilList = [...(this.editForm.coilList || []), ...newCoils] }, + getWarehouseName(warehouseId) { + if (!warehouseId) return '' + const wh = this.warehouseOptions.find(w => w.warehouseId === warehouseId) + return wh ? wh.warehouseName : '' + }, handleRemoveCoil(index) { this.coilList.splice(index, 1) }, + // ===== 库区选择 ===== + loadWarehouseOptions() { + listWarehouse().then(res => { + this.warehouseOptions = res.data || [] + }) + }, + onTargetWarehouseChange(row) { + const selected = this.warehouseOptions.find(w => w.warehouseId === row.targetWarehouseId) + row.targetWarehouseName = selected ? selected.warehouseName : '' + }, + // ===== 提交送审 ===== handleSubmit() { this.$confirm('确认提交送审?', '提示', { type: 'warning' }).then(() => { diff --git a/klp-ui/src/views/mes/qc/qualityReview/todo.vue b/klp-ui/src/views/mes/qc/qualityReview/todo.vue index 5ad6a251b..fe0b5eb07 100644 --- a/klp-ui/src/views/mes/qc/qualityReview/todo.vue +++ b/klp-ui/src/views/mes/qc/qualityReview/todo.vue @@ -64,9 +64,15 @@ - + + + + +
diff --git a/klp-ui/src/views/wms/coil/do/trace.vue b/klp-ui/src/views/wms/coil/do/trace.vue index 613adcd49..69d7b90a0 100644 --- a/klp-ui/src/views/wms/coil/do/trace.vue +++ b/klp-ui/src/views/wms/coil/do/trace.vue @@ -1,7 +1,7 @@