From 3d6391bf32042ee04cd370f255e50c8a8f0d3121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=82=E7=B3=96?= Date: Tue, 17 Mar 2026 18:01:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E9=92=A2=E5=8D=B7=E7=AE=A1=E7=90=86):=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=94=9F=E4=BA=A7=E6=97=B6=E9=97=B4=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=8F=8A=E8=80=97=E6=97=B6=E8=AE=A1=E7=AE=97=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加TimeInput组件用于时间输入,并在钢卷合并、分条、打字、分步操作中增加生产开始/结束时间字段 实现生产耗时自动计算功能,支持显示xx天xx小时xx分钟格式 在基础面板中增加生产时间修正对话框,支持批量修改时间 --- klp-ui/src/components/TimeInput.vue | 86 ++++++++ klp-ui/src/views/wms/coil/merge.vue | 66 +++++- klp-ui/src/views/wms/coil/panels/base.vue | 196 ++++++++++++++---- .../src/views/wms/coil/panels/stepSplit.vue | 65 ++++++ klp-ui/src/views/wms/coil/split.vue | 64 ++++++ klp-ui/src/views/wms/coil/typing.vue | 90 ++++++++ .../views/wms/coil/views/base/timeEdit.vue | 27 +++ 7 files changed, 552 insertions(+), 42 deletions(-) create mode 100644 klp-ui/src/components/TimeInput.vue create mode 100644 klp-ui/src/views/wms/coil/views/base/timeEdit.vue diff --git a/klp-ui/src/components/TimeInput.vue b/klp-ui/src/components/TimeInput.vue new file mode 100644 index 00000000..51968fd1 --- /dev/null +++ b/klp-ui/src/components/TimeInput.vue @@ -0,0 +1,86 @@ + + + + + \ No newline at end of file diff --git a/klp-ui/src/views/wms/coil/merge.vue b/klp-ui/src/views/wms/coil/merge.vue index 31550619..61d9052b 100644 --- a/klp-ui/src/views/wms/coil/merge.vue +++ b/klp-ui/src/views/wms/coil/merge.vue @@ -215,6 +215,21 @@ + +
+ + + + + + +
+ +
+ + + +
@@ -231,6 +246,7 @@ import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect import RawMaterialSelector from "@/components/KLPService/RawMaterialSelect"; import ProductSelector from "@/components/KLPService/ProductSelect"; import WarehouseSelect from "@/components/KLPService/WarehouseSelect"; +import TimeInput from "@/components/TimeInput"; import { generateCoilNoPrefix } from "@/utils/coil/coilNo"; export default { @@ -240,7 +256,8 @@ export default { ActualWarehouseSelect, RawMaterialSelector, ProductSelector, - WarehouseSelect + WarehouseSelect, + TimeInput }, dicts: ['coil_quality_status'], data() { @@ -270,6 +287,10 @@ export default { coatingType: '', actualLength: undefined, actualWidth: undefined, + productionStartTime: '', + productionEndTime: '', + productionDuration: '', + formattedDuration: '', }, rules: { currentCoilNo: [ @@ -759,6 +780,49 @@ export default { this.$router.back(); }, + // 格式化毫秒值为xx天xx小时xx分钟 + formatDuration(milliseconds) { + if (!milliseconds || milliseconds < 0) return ''; + + const seconds = Math.floor(milliseconds / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + + const remainingHours = hours % 24; + const remainingMinutes = minutes % 60; + + let result = ''; + if (days > 0) result += `${days}天`; + if (remainingHours > 0) result += `${remainingHours}小时`; + if (remainingMinutes > 0) result += `${remainingMinutes}分钟`; + + return result || '0分钟'; + }, + // 计算生产耗时 + calculateProductionDuration() { + const { productionStartTime, productionEndTime } = this.targetCoil; + if (productionStartTime && productionEndTime) { + const start = new Date(productionStartTime).getTime(); + const end = new Date(productionEndTime).getTime(); + if (end < start) { + this.$message({ + message: '结束时间不能早于开始时间', + type: 'error', + }); + this.$set(this.targetCoil, 'productionDuration', ''); + this.$set(this.targetCoil, 'formattedDuration', ''); + } else { + const durationMs = end - start; + const durationMinutes = Math.round(durationMs / (1000 * 60)); + this.$set(this.targetCoil, 'productionDuration', durationMinutes); + this.$set(this.targetCoil, 'formattedDuration', this.formatDuration(durationMinutes * 60 * 1000)); + } + } else { + this.$set(this.targetCoil, 'productionDuration', ''); + this.$set(this.targetCoil, 'formattedDuration', ''); + } + }, // closePage 关闭当前页面 closePage() { this.$router.back(); diff --git a/klp-ui/src/views/wms/coil/panels/base.vue b/klp-ui/src/views/wms/coil/panels/base.vue index 1151390c..d017cae7 100644 --- a/klp-ui/src/views/wms/coil/panels/base.vue +++ b/klp-ui/src/views/wms/coil/panels/base.vue @@ -173,7 +173,7 @@ - + + + + + + + + + @@ -396,6 +408,28 @@ + + + + + + + + + + + + + + + + @@ -553,7 +587,17 @@ export default { showNewExport: { type: Boolean, default: false, - } + }, + // 展示宽度快捷编辑 + showWidthEdit: { + type: Boolean, + default: false, + }, + // 展示生产时间快捷编辑 + showProductionTimeEdit: { + type: Boolean, + default: false, + }, }, data() { return { @@ -724,6 +768,18 @@ export default { currentCoilId: '', userList: [], logOpen: false, + productionTimeForm: { + productionStartTime: '', + productionEndTime: '', + formattedDuration: '', + productionDuration: 0, + }, + productionTimeFormRules: { + productionTime: [ + { required: true, message: "生产时间不能为空", trigger: "blur" } + ], + }, + productionTimeFormVisible: false, }; }, computed: { @@ -759,6 +815,88 @@ export default { this.userList = res.rows || []; }); }, + handleProductionTimeEdit(row) { + // 创建一个新对象,避免直接引用row + this.productionTimeForm = { ...row }; + this.productionTimeFormVisible = true; + // 初始化时计算一次 + this.calculateProductionDuration(); + }, + // 格式化毫秒值为xx天xx小时xx分钟 + formatDuration(milliseconds) { + if (!milliseconds || milliseconds < 0) return ''; + + const seconds = Math.floor(milliseconds / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + + const remainingHours = hours % 24; + const remainingMinutes = minutes % 60; + + let result = ''; + if (days > 0) result += `${days}天`; + if (remainingHours > 0) result += `${remainingHours}小时`; + if (remainingMinutes > 0) result += `${remainingMinutes}分钟`; + + return result || '0分钟'; + }, + // 计算生产耗时 + calculateProductionDuration() { + const { productionStartTime, productionEndTime } = this.productionTimeForm; + if (productionStartTime && productionEndTime) { + const start = new Date(productionStartTime).getTime(); + const end = new Date(productionEndTime).getTime(); + if (end < start) { + this.$message({ + message: '结束时间不能早于开始时间', + type: 'error', + }); + this.$set(this.productionTimeForm, 'productionDuration', ''); + this.$set(this.productionTimeForm, 'formattedDuration', ''); + } else { + const durationMs = end - start; + const durationMinutes = Math.round(durationMs / (1000 * 60)); + this.$set(this.productionTimeForm, 'productionDuration', durationMinutes); + // 同时保存格式化后的显示值 + this.$set(this.productionTimeForm, 'formattedDuration', this.formatDuration(durationMinutes * 60 * 1000)); + } + } else { + this.$set(this.productionTimeForm, 'productionDuration', ''); + this.$set(this.productionTimeForm, 'formattedDuration', ''); + } + }, + // 处理生产时间提交 + submitProductionTimeForm() { + this.$refs.productionTimeForm.validate((valid) => { + if (valid) { + // 再次验证时间逻辑 + const { productionStartTime, productionEndTime } = this.productionTimeForm; + if (productionStartTime && productionEndTime) { + const start = new Date(productionStartTime).getTime(); + const end = new Date(productionEndTime).getTime(); + if (end < start) { + this.$message({ + message: '结束时间不能早于开始时间', + type: 'error', + }); + return false; + } + } + this.buttonLoading = true; + updateMaterialCoilSimple(this.productionTimeForm).then(res => { + this.buttonLoading = false; + this.$message({ + message: '更新成功', + type: 'success', + }); + this.productionTimeFormVisible = false; + }) + } else { + return false; + } + }) + }, handleNextWarehouseChange(row) { if (!this.editNext) { return; @@ -777,37 +915,13 @@ export default { } }) }, - handleBusinessPurposeChange(row) { - if (!this.showBusinessPurpose) { - return; - } + // 处理行数据变化 + handleRowChange(row) { updateMaterialCoilSimple(row).then(res => { - if (res.code === 200) { - this.$message({ - message: '更新成功', - type: 'success', - }); - } else { - this.$message({ - message: res.msg || '更新失败', - type: 'error', - }); - } - }) - }, - handleRelatedToOrderChange(row) { - updateMaterialCoilSimple(row).then(res => { - if (res.code === 200) { - this.$message({ - message: '更新成功', - type: 'success', - }); - } else { - this.$message({ - message: res.msg || '更新失败', - type: 'error', - }); - } + this.$message({ + message: '更新成功', + type: 'success', + }); }) }, // 打印标签 diff --git a/klp-ui/src/views/wms/coil/panels/stepSplit.vue b/klp-ui/src/views/wms/coil/panels/stepSplit.vue index ccd75fb7..2493ee1b 100644 --- a/klp-ui/src/views/wms/coil/panels/stepSplit.vue +++ b/klp-ui/src/views/wms/coil/panels/stepSplit.vue @@ -149,6 +149,15 @@ + + + + + + + + + @@ -187,6 +196,9 @@ m {{ selectedSplitItem.temperGrade || '-' }} {{ selectedSplitItem.coatingType || '-' }} + {{ selectedSplitItem.productionStartTime || '-' }} + {{ selectedSplitItem.productionEndTime || '-' }} + {{ selectedSplitItem.formattedDuration || (selectedSplitItem.productionDuration ? selectedSplitItem.productionDuration + ' 分钟' : '-') }} {{ selectedSplitItem.remark || '-' }} @@ -208,6 +220,7 @@ import ProductSelect from "@/components/KLPService/ProductSelect"; import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect"; import WarehouseSelect from "@/components/KLPService/WarehouseSelect"; import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect"; +import TimeInput from "@/components/TimeInput"; import { generateCoilNoPrefix } from "@/utils/coil/coilNo"; export default { @@ -231,6 +244,7 @@ export default { RawMaterialSelect, WarehouseSelect, ActualWarehouseSelect, + TimeInput, }, dicts: ['coil_quality_status'], data() { @@ -264,6 +278,10 @@ export default { temperGrade: '', coatingType: '', remark: '', + productionStartTime: '', + productionEndTime: '', + productionDuration: '', + formattedDuration: '', }, // 已分条钢卷列表 splitList: [], @@ -443,6 +461,10 @@ export default { temperGrade: '', coatingType: '', remark: '', + productionStartTime: '', + productionEndTime: '', + productionDuration: '', + formattedDuration: '', parentCoilId: this.coilId, } }, @@ -547,6 +569,49 @@ export default { } }) }, + // 格式化毫秒值为xx天xx小时xx分钟 + formatDuration(milliseconds) { + if (!milliseconds || milliseconds < 0) return ''; + + const seconds = Math.floor(milliseconds / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + + const remainingHours = hours % 24; + const remainingMinutes = minutes % 60; + + let result = ''; + if (days > 0) result += `${days}天`; + if (remainingHours > 0) result += `${remainingHours}小时`; + if (remainingMinutes > 0) result += `${remainingMinutes}分钟`; + + return result || '0分钟'; + }, + // 计算生产耗时 + calculateProductionDuration() { + const { productionStartTime, productionEndTime } = this.splitForm; + if (productionStartTime && productionEndTime) { + const start = new Date(productionStartTime).getTime(); + const end = new Date(productionEndTime).getTime(); + if (end < start) { + this.$message({ + message: '结束时间不能早于开始时间', + type: 'error', + }); + this.$set(this.splitForm, 'productionDuration', ''); + this.$set(this.splitForm, 'formattedDuration', ''); + } else { + const durationMs = end - start; + const durationMinutes = Math.round(durationMs / (1000 * 60)); + this.$set(this.splitForm, 'productionDuration', durationMinutes); + this.$set(this.splitForm, 'formattedDuration', this.formatDuration(durationMinutes * 60 * 1000)); + } + } else { + this.$set(this.splitForm, 'productionDuration', ''); + this.$set(this.splitForm, 'formattedDuration', ''); + } + } }, } diff --git a/klp-ui/src/views/wms/coil/split.vue b/klp-ui/src/views/wms/coil/split.vue index 6246b293..13e8e6b3 100644 --- a/klp-ui/src/views/wms/coil/split.vue +++ b/klp-ui/src/views/wms/coil/split.vue @@ -218,6 +218,15 @@ --> + + + + + + + + + @@ -238,6 +247,7 @@ import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect"; import ProductSelect from "@/components/KLPService/ProductSelect"; import WarehouseSelect from "@/components/KLPService/WarehouseSelect"; +import TimeInput from "@/components/TimeInput"; import { generateCoilNoPrefix } from "@/utils/coil/coilNo"; export default { @@ -247,6 +257,7 @@ export default { RawMaterialSelect, ProductSelect, WarehouseSelect, + TimeInput, }, dicts: ['coil_quality_status'], data() { @@ -289,6 +300,10 @@ export default { coatingType: '', actualLength: undefined, actualWidth: undefined, + productionStartTime: '', + productionEndTime: '', + productionDuration: '', + formattedDuration: '', } ], loading: false, @@ -475,6 +490,10 @@ export default { coatingType: '', actualLength: undefined, actualWidth: undefined, + productionStartTime: '', + productionEndTime: '', + productionDuration: '', + formattedDuration: '', }); }, @@ -612,6 +631,51 @@ export default { // 不再预加载物品列表,改为实时搜索 this.$message.success('已复制到所有子卷'); + }, + // 格式化毫秒值为xx天xx小时xx分钟 + formatDuration(milliseconds) { + if (!milliseconds || milliseconds < 0) return ''; + + const seconds = Math.floor(milliseconds / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + + const remainingHours = hours % 24; + const remainingMinutes = minutes % 60; + + let result = ''; + if (days > 0) result += `${days}天`; + if (remainingHours > 0) result += `${remainingHours}小时`; + if (remainingMinutes > 0) result += `${remainingMinutes}分钟`; + + return result || '0分钟'; + }, + // 计算生产耗时 + calculateProductionDuration(item) { + if (!item) return; + + const { productionStartTime, productionEndTime } = item; + if (productionStartTime && productionEndTime) { + const start = new Date(productionStartTime).getTime(); + const end = new Date(productionEndTime).getTime(); + if (end < start) { + this.$message({ + message: '结束时间不能早于开始时间', + type: 'error', + }); + this.$set(item, 'productionDuration', ''); + this.$set(item, 'formattedDuration', ''); + } else { + const durationMs = end - start; + const durationMinutes = Math.round(durationMs / (1000 * 60)); + this.$set(item, 'productionDuration', durationMinutes); + this.$set(item, 'formattedDuration', this.formatDuration(durationMinutes * 60 * 1000)); + } + } else { + this.$set(item, 'productionDuration', ''); + this.$set(item, 'formattedDuration', ''); + } } } }; diff --git a/klp-ui/src/views/wms/coil/typing.vue b/klp-ui/src/views/wms/coil/typing.vue index 9db8a5f1..140f19ac 100644 --- a/klp-ui/src/views/wms/coil/typing.vue +++ b/klp-ui/src/views/wms/coil/typing.vue @@ -192,6 +192,18 @@ + + + + + + + + + + + + @@ -237,6 +249,7 @@ import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect"; import ProductSelect from "@/components/KLPService/ProductSelect"; import WarehouseSelect from "@/components/KLPService/WarehouseSelect"; +import TimeInput from "@/components/TimeInput"; import { generateCoilNoPrefix } from "@/utils/coil/coilNo"; export default { @@ -246,6 +259,7 @@ export default { RawMaterialSelect, ProductSelect, WarehouseSelect, + TimeInput, }, dicts: ['coil_quality_status'], data() { @@ -292,6 +306,10 @@ export default { coatingType: '', actualLength: undefined, actualWidth: undefined, + productionStartTime: '', + productionEndTime: '', + productionDuration: '', + formattedDuration: '', }, rules: { currentCoilNo: [ @@ -556,6 +574,18 @@ export default { nextWarehouseName: this.getWarehouseName(data.warehouseId), }; + // 填充时间相关字段 + if (data.productionStartTime) { + this.updateForm.productionStartTime = data.productionStartTime; + } + if (data.productionEndTime) { + this.updateForm.productionEndTime = data.productionEndTime; + } + if (data.productionDuration) { + this.updateForm.productionDuration = data.productionDuration; + this.updateForm.formattedDuration = this.formatDuration(data.productionDuration); + } + // 不再预加载物品列表,改为实时搜索 // 加载变更历史 @@ -751,6 +781,20 @@ export default { return false; } + // 验证时间逻辑 + const { productionStartTime, productionEndTime } = this.updateForm; + if (productionStartTime && productionEndTime) { + const start = new Date(productionStartTime).getTime(); + const end = new Date(productionEndTime).getTime(); + if (end < start) { + this.$message({ + message: '结束时间不能早于开始时间', + type: 'error', + }); + return false; + } + } + const loadingInstance = this.$loading({ lock: true, text: '正在更新钢卷信息,请稍后...', @@ -796,6 +840,50 @@ export default { }); }, + + // 格式化毫秒值为xx天xx小时xx分钟 + formatDuration(milliseconds) { + if (!milliseconds || milliseconds < 0) return ''; + + const seconds = Math.floor(milliseconds / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + + const remainingHours = hours % 24; + const remainingMinutes = minutes % 60; + + let result = ''; + if (days > 0) result += `${days}天`; + if (remainingHours > 0) result += `${remainingHours}小时`; + if (remainingMinutes > 0) result += `${remainingMinutes}分钟`; + + return result || '0分钟'; + }, + // 计算生产耗时 + calculateProductionDuration() { + const { productionStartTime, productionEndTime } = this.updateForm; + if (productionStartTime && productionEndTime) { + const start = new Date(productionStartTime).getTime(); + const end = new Date(productionEndTime).getTime(); + if (end < start) { + this.$message({ + message: '结束时间不能早于开始时间', + type: 'error', + }); + this.updateForm.productionDuration = ''; + this.updateForm.formattedDuration = ''; + } else { + const durationMs = end - start; + const durationMinutes = Math.round(durationMs / (1000 * 60)); + this.updateForm.productionDuration = durationMinutes; + this.updateForm.formattedDuration = this.formatDuration(durationMinutes * 60 * 1000); + } + } else { + this.updateForm.productionDuration = ''; + this.updateForm.formattedDuration = ''; + } + }, // 取消操作 handleCancel() { this.$router.back(); @@ -980,6 +1068,8 @@ export default { } } + + /* 表单样式优化 */ .form-card { ::v-deep .el-input-number { diff --git a/klp-ui/src/views/wms/coil/views/base/timeEdit.vue b/klp-ui/src/views/wms/coil/views/base/timeEdit.vue new file mode 100644 index 00000000..bc6df62c --- /dev/null +++ b/klp-ui/src/views/wms/coil/views/base/timeEdit.vue @@ -0,0 +1,27 @@ + + + \ No newline at end of file