feat: 多个页面功能优化与新增

1.  异议页面:新增状态为4时的导出PDF按钮,替换原有注释的打印按钮
2.  流程图页面:重构流程图组件,支持多流程切换、节点点击事件,优化主题配置和渲染逻辑
3.  钢卷待领页面:新增钢卷数据修正功能,新增操作列按钮和对应弹窗表单,注释绑定组件
4.  导出PDF弹窗:优化多钢卷数据展示,拆分合并附件排版,优化导出样式和分页逻辑
This commit is contained in:
2026-06-30 11:42:03 +08:00
parent 89773b273b
commit 81dec034b3
4 changed files with 873 additions and 330 deletions

View File

@@ -11,7 +11,7 @@
:name="tab.value"></el-tab-pane>
</el-tabs>
<h3 class="section-title" v-else>待领物料列表</h3>
<schedule-detail-coil-bind />
<!-- <schedule-detail-coil-bind /> -->
<el-button size="mini" icon="el-icon-refresh" @click="getMaterialCoil">刷新</el-button>
</div>
@@ -44,12 +44,13 @@
<el-table-column prop="specification" label="规格" width="100" show-overflow-tooltip></el-table-column>
<el-table-column prop="netWeight" label="净重" width="100" show-overflow-tooltip></el-table-column>
<el-table-column prop="action" label="操作" width="320">
<el-table-column prop="action" label="操作" width="360">
<template slot-scope="scope">
<el-button v-loading="buttonLoading" style="margin-left: 0px; padding: 4px !important;" type="default"
size="mini" icon="el-icon-view" @click="handlePreviewLabel(scope.row)" title="预览标签">预览</el-button>
<el-button v-loading="buttonLoading" style="margin-left: 0px; padding: 4px !important;" type="default"
size="mini" icon="el-icon-printer" @click="handlePrintLabel(scope.row)" title="打印标签">打印</el-button>
<el-button size="mini" type="default" icon="el-icon-edit" @click="handleCheck(scope.row)" style="margin-left: 0;">修正</el-button>
<el-button v-if="useSpecialSplit" :style="splitButtonStyle" icon="el-icon-scissors" size="mini"
@click="handleStartSplit(scope.row)" :loading="buttonLoading" class="action-btn">加工</el-button>
<el-button v-else type="primary" icon="el-icon-check" size="mini" @click="handlePickMaterial(scope.row)"
@@ -59,6 +60,7 @@
缺陷明细
<span v-if="scope.row.abnormalCount > 0">({{ scope.row.abnormalCount }})</span>
</el-button>
</template>
</el-table-column>
</KLPTable>
@@ -297,15 +299,206 @@
</el-dialog>
<label-render ref="labelRender" v-show="false" :content="labelRender.data" :labelType="labelRender.type" />
<!-- 数据修正对话框 -->
<el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="入场钢卷号" prop="enterCoilNo">
<el-input v-model="form.enterCoilNo" placeholder="请输入入场钢卷号" :disabled="!!form.coilId" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="当前钢卷号" prop="currentCoilNo">
<el-input v-model.trim="form.currentCoilNo" placeholder="请输入当前钢卷号" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="厂家原料卷号" prop="supplierCoilNo">
<el-input v-model.trim="form.supplierCoilNo" placeholder="请输入厂家原料卷号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所在库位" prop="warehouseId">
<warehouse-select v-model="form.warehouseId" placeholder="请选择仓库/库区/库位" style="width: 100%;" clearable />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="实际库区" prop="actualWarehouseId">
<actual-warehouse-select v-model="form.actualWarehouseId" placeholder="请选择实际库区" style="width: 100%;" clearable />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="班组" prop="team">
<el-select v-model="form.team" placeholder="请选择班组" style="width: 100%">
<el-option key="甲" label="甲" value="甲" />
<el-option key="乙" label="乙" value="乙" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="材料类型" prop="materialType">
<el-select v-model="form.materialType" placeholder="请选择材料类型" @change="handleMaterialTypeChange">
<el-option label="成品" value="成品" />
<el-option label="原料" value="原料" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="getItemLabel" prop="itemId">
<product-select v-if="form.itemType == 'product'" v-model="form.itemId" placeholder="请选择成品" style="width: 100%;" clearable />
<raw-material-select v-else-if="form.itemType == 'raw_material'" v-model="form.itemId" placeholder="请选择原料" style="width: 100%;" clearable />
<div v-else>请先选择材料类型</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="切边要求" prop="trimmingRequirement">
<el-select v-model="form.trimmingRequirement" placeholder="请选择切边要求" style="width: 100%">
<el-option label="净边料" value="净边料" />
<el-option label="毛边料" value="毛边料" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="包装要求" prop="packagingRequirement">
<el-select v-model="form.packagingRequirement" placeholder="请选择包装要求" style="width: 100%">
<el-option label="裸包" value="裸包" />
<el-option label="普包" value="普包" />
<el-option label="简包" value="简包" />
<el-option label="精包" value="精包" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="毛重" prop="grossWeight">
<el-input v-model="form.grossWeight" placeholder="请输入毛重" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="净重" prop="netWeight">
<el-input v-model="form.netWeight" placeholder="请输入净重" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="实测长度(mm)" prop="actualLength">
<el-input-number :controls="false" v-model="form.actualLength" placeholder="请输入实测长度" type="number" :step="0.01" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实测宽度(mm)" prop="actualWidth">
<el-input-number :controls="false" v-model="form.actualWidth" placeholder="请输入实测宽度" type="number" :step="0.01" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="实测厚度(mm)" prop="actualThickness">
<el-input-number :controls="false" v-model="form.actualThickness" placeholder="请输入实测厚度" type="number" :step="0.01" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="业务目的" prop="businessPurpose">
<el-select v-model="form.businessPurpose" placeholder="请选择业务目的" style="width: 100%">
<el-option v-for="item in dict.type.coil_business_purpose" :key="item.value" :value="item.value" :label="item.label" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="调制度" prop="temperGrade">
<el-input v-model="form.temperGrade" placeholder="请输入调制度" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="镀层种类" prop="coatingType">
<memo-input storageKey="coatingType" v-model="form.coatingType" placeholder="请输入镀层种类" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="钢卷表面处理" prop="coilSurfaceTreatment">
<memo-input storageKey="surfaceTreatmentDesc" v-model="form.coilSurfaceTreatment" placeholder="请输入钢卷表面处理" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排产厚度(mm)" prop="scheduleThickness">
<el-input-number :controls="false" v-model="form.scheduleThickness" placeholder="请输入排产厚度" type="number" :step="0.001" style="width: 100%;" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="生产开始时间" prop="productionStartTime">
<time-input v-model="form.productionStartTime" @input="calculateFormProductionDuration" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="生产结束时间" prop="productionEndTime">
<time-input v-model="form.productionEndTime" @input="calculateFormProductionDuration" :show-now-button="true" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="生产耗时" prop="productionDuration">
<el-input v-model="form.formattedDuration" placeholder="自动计算" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" v-if="form.coilId">
<el-col :span="24">
<el-form-item label="绑定合同" prop="contractId">
<div style="display: flex; gap: 10px; width: 100%;">
<contract-select v-model="form.contractId" placeholder="请选择合同" style="flex: 1;" clearable mode="all" />
<el-button type="success" :loading="contractLoading" @click="saveContractRel">保存合同</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listMaterialCoil, startSpecialSplit, cancelSpecialSplit } from '@/api/wms/coil'
import { listMaterialCoil, startSpecialSplit, cancelSpecialSplit, getMaterialCoil, updateMaterialCoilSimple } from '@/api/wms/coil'
import { listPendingAction, startProcess, cancelAction, delPendingAction, addPendingAction } from '@/api/wms/pendingAction'
import { listUser } from "@/api/system/user"
import { listCoilContractRel, addCoilContractRel, updateCoilContractRel } from "@/api/wms/coilContractRel"
import { parseTime } from '@/utils/klp'
import ProductInfo from '@/components/KLPService/Renderer/ProductInfo'
import RawMaterialInfo from '@/components/KLPService/Renderer/RawMaterialInfo'
import WarehouseSelect from "@/components/KLPService/WarehouseSelect"
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect"
import ProductSelect from "@/components/KLPService/ProductSelect"
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect"
import MemoInput from "@/components/MemoInput"
import TimeInput from "@/components/TimeInput"
import ContractSelect from "@/components/KLPService/ContractSelect"
import CoilCard from '@/components/KLPService/Renderer/CoilCard.vue'
import LabelRender from './LabelRender/index.vue'
import StepSplit from './stepSplit.vue'
@@ -315,7 +508,7 @@ import { getCoilTagPrintType } from '@/views/wms/coil/js/coilPrint'
export default {
name: 'DoPage',
dicts: ['action_type', 'coil_abnormal_code', 'coil_abnormal_position', 'coil_abnormal_degree'],
dicts: ['action_type', 'coil_abnormal_code', 'coil_abnormal_position', 'coil_abnormal_degree', 'coil_business_purpose'],
props: {
label: {
type: String,
@@ -337,7 +530,14 @@ export default {
LabelRender,
StepSplit,
ExceptionManager,
ScheduleDetailCoilBind
ScheduleDetailCoilBind,
WarehouseSelect,
ActualWarehouseSelect,
ProductSelect,
RawMaterialSelect,
MemoInput,
TimeInput,
ContractSelect
},
data() {
return {
@@ -396,6 +596,27 @@ export default {
title: '详细信息'
},
rules: {
enterCoilNo: [
{ required: true, message: "入场钢卷号不能为空", trigger: "blur" }
],
currentCoilNo: [
{ required: true, message: "当前钢卷号不能为空", trigger: "blur" }
],
itemId: [
{ required: true, message: "物品ID不能为空", trigger: "blur" }
],
itemType: [
{ required: true, message: "物品类型不能为空", trigger: "change" }
],
netWeight: [
{ required: true, message: "净重不能为空", trigger: "blur" }
],
grossWeight: [
{ required: true, message: "毛重不能为空", trigger: "blur" }
],
},
// 待操作列表相关
actionLoading: false,
pendingActionList: [],
@@ -410,6 +631,14 @@ export default {
buttonLoading: false,
exceptionDialogVisible: false,
currentCoilId: null,
// 数据修正相关
open: false,
title: "",
isCheck: false,
form: {},
userList: [],
contractLoading: false,
contractRelId: null,
stepSpilt: {
list: [],
loading: false,
@@ -422,6 +651,15 @@ export default {
}
},
computed: {
// 动态显示标签
getItemLabel() {
if (this.form.materialType === '成品') {
return '产品类型'
} else if (this.form.materialType === '原料') {
return '原料类型'
}
return '物品类型'
},
// 获取酸连轧工序的actionType值
acidRollingActionType() {
if (!this.dict.type.action_type) return null
@@ -558,6 +796,7 @@ export default {
}
},
created() {
this.getUserList()
// 立即加载物料列表(不依赖字典)
// this.getMaterialCoil()
// 尝试加载待操作列表(如果字典已加载)
@@ -916,6 +1155,172 @@ export default {
}
this.exceptionDialogVisible = false
},
// ========== 数据修正相关方法 ==========
getUserList() {
listUser({ pageNum: 1, pageSize: 1000 }).then(res => {
this.userList = res.rows || []
})
},
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分钟'
},
calculateFormProductionDuration() {
const { productionStartTime, productionEndTime } = this.form
if (productionStartTime && productionEndTime) {
const start = new Date(productionStartTime).getTime()
const end = new Date(productionEndTime).getTime()
if (end < start) {
this.form.productionDuration = ''
this.form.formattedDuration = ''
} else {
const durationMs = end - start
this.form.productionDuration = Math.round(durationMs / (1000 * 60))
this.form.formattedDuration = this.formatDuration(durationMs)
}
} else {
this.form.productionDuration = ''
this.form.formattedDuration = ''
}
},
handleMaterialTypeChange(value) {
this.form.itemId = null
if (value === '成品') {
this.form.itemType = 'product'
} else if (value === '原料') {
this.form.itemType = 'raw_material'
}
},
handleCheck(row) {
this.isCheck = true
this.reset()
const coilId = row.coilId
getMaterialCoil(coilId).then(response => {
this.form = response.data
if (!this.form.materialType) {
if (this.form.itemType) {
if (this.form.itemType === 'product') {
this.form.materialType = '成品'
} else if (this.form.itemType === 'raw_material') {
this.form.materialType = '原料'
}
}
}
if (this.form.productionDuration) {
this.form.formattedDuration = this.formatDuration(this.form.productionDuration * 60 * 1000)
}
this.loadContractRel(coilId)
this.open = true
this.title = "修改钢卷物料"
})
},
loadContractRel(coilId) {
if (!coilId) {
this.contractRelId = null
this.$set(this.form, 'contractId', null)
return
}
listCoilContractRel({ coilId }).then(res => {
const rows = res.rows || []
if (rows.length > 0) {
this.contractRelId = rows[0].relId
this.$set(this.form, 'contractId', rows[0].contractId)
} else {
this.contractRelId = null
this.$set(this.form, 'contractId', null)
}
})
},
saveContractRel() {
this.contractLoading = true
listCoilContractRel({ coilId: this.form.coilId }).then(res => {
const rows = res.rows || []
if (rows.length > 0) {
return updateCoilContractRel({
relId: rows[0].relId,
coilId: this.form.coilId,
contractId: this.form.contractId
})
} else {
return addCoilContractRel({
coilId: this.form.coilId,
contractId: this.form.contractId
})
}
}).then(() => {
this.$message.success('合同绑定保存成功')
}).finally(() => {
this.contractLoading = false
})
},
reset() {
this.form = {
coilId: undefined,
enterCoilNo: undefined,
currentCoilNo: undefined,
supplierCoilNo: undefined,
dataType: 1,
warehouseId: undefined,
nextWarehouseId: undefined,
qrcodeRecordId: undefined,
actualWarehouseId: undefined,
team: undefined,
hasMergeSplit: undefined,
parentCoilNos: undefined,
itemId: undefined,
itemType: undefined,
status: undefined,
remark: undefined,
delFlag: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined,
materialType: '原料',
temperGrade: undefined,
coatingType: undefined,
qualityStatus: undefined,
actualLength: undefined,
actualWidth: undefined,
actualThickness: undefined,
scheduleThickness: undefined,
productionStartTime: undefined,
productionEndTime: undefined,
productionDuration: undefined,
formattedDuration: undefined,
contractId: undefined,
}
this.resetForm("form")
},
cancel() {
this.open = false
this.reset()
},
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
const { status, exclusiveStatus, dataType, ...payload } = {
...this.form,
}
updateMaterialCoilSimple(payload).then(_ => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getMaterialCoil()
})
}
})
},
}
}
</script>