refactor(盘库流程): 重构盘库流程页面与组件,完善排产明细功能

1.  重构盘库流程的步骤与状态映射,调整流程节点顺序与名称
2.  拆分通用盘库详情组件PlanDetailPanel,复用各流程页面
3.  新增计划审批、盘库执行页面,完善差异审批页面
4.  为排产单明细添加增删改查API与前端操作功能
5.  为排产日期添加格式化注解,完善参数接收格式
This commit is contained in:
2026-06-27 11:15:13 +08:00
parent 097d45b420
commit b94b7823e5
13 changed files with 1167 additions and 558 deletions

View File

@@ -57,7 +57,10 @@
<div class="detail-card">
<div class="detail-card-header">
<span>产需单信息</span>
<button class="header-btn" @click="handleEdit(currentReq)">编辑</button>
<div style="display:flex; gap:6px;">
<button class="header-btn" :disabled="currentReq.scheduleStatus !== 0 && currentReq.scheduleStatus !== 3" @click="handleEdit(currentReq)">编辑</button>
<button v-if="currentReq.scheduleStatus === 0 || currentReq.scheduleStatus === 3" class="header-btn" style="background:rgba(255,255,255,0.4);border-color:rgba(255,255,255,0.7);" @click="handleDispatch">{{ currentReq.scheduleStatus === 3 ? '重新下发' : '下发' }}</button>
</div>
</div>
<div class="detail-card-body">
<table class="req-info-table">
@@ -134,6 +137,10 @@
<td class="req-td-label">备注</td>
<td class="req-td-value" colspan="3">{{ currentReq.remark }}</td>
</tr>
<tr v-if="currentReq.returnReason">
<td class="req-td-label" style="color:#e74c3c;">驳回原因</td>
<td class="req-td-value" colspan="3" style="color:#e74c3c;background:#fdecea;">{{ currentReq.returnReason }}</td>
</tr>
</tbody>
</table>
</div>
@@ -141,8 +148,8 @@
<div class="detail-card">
<div class="detail-card-header">
<span>已绑定的销售订单{{ boundOrderList.length }} </span>
<button class="header-btn" @click="openBindDialog">+ 添加订单</button>
<span>已绑定的销售订单{{ (currentReq.orderList || []).length }} </span>
<button v-if="canEdit" class="header-btn" @click="openBindDialog">+ 添加订单</button>
</div>
<div class="detail-card-body" v-loading="boundLoading">
<div v-if="(currentReq.orderList || []).length === 0"
@@ -151,7 +158,7 @@
<div v-for="order in currentReq.orderList" :key="order.orderId" class="bound-order-card">
<div class="bound-order-card-header">
<span>{{ order.orderCode || ('订单 #' + order.orderId) }}</span>
<button class="link-btn" @click="handleUnbindByOrderId(order.orderId)">解绑</button>
<button v-if="canEdit" class="link-btn" @click="handleUnbindByOrderId(order.orderId)">解绑</button>
</div>
<div class="bound-order-card-body">
<div style="font-size:12px; color:#7f8c8d; margin-bottom:3px;">
@@ -172,6 +179,7 @@
<div class="detail-card">
<div class="detail-card-header">
<span>排产明细{{ requirementDetailList.length }} 合计 {{ detailTotalWeight }} T</span>
<button v-if="canEdit" class="header-btn" @click="handleDetailAdd">+ 新增</button>
</div>
<div class="detail-card-body" style="padding:0;">
<el-table :data="requirementDetailList" border size="small" v-loading="detailLoading" class="aps-table">
@@ -179,6 +187,14 @@
<el-table-column label="材质" prop="material" width="90" align="center" />
<el-table-column label="排产吨数" prop="scheduleWeight" width="100" align="right" />
<el-table-column label="备注" prop="remark" min-width="120" />
<el-table-column label="操作" width="130" align="center" fixed="right">
<template slot-scope="scope">
<span style="white-space:nowrap;">
<el-button v-if="canEdit" type="text" size="small" style="color:#409EFF;" @click="handleDetailEdit(scope.row)">编辑</el-button>
<el-button v-if="canEdit" type="text" size="small" style="color:#ff4d4f;" @click="handleDetailDelete(scope.row)">删除</el-button>
</span>
</template>
</el-table-column>
</el-table>
<el-empty v-if="requirementDetailList.length === 0 && !detailLoading" description="暂无排产明细" />
</div>
@@ -348,6 +364,29 @@
<el-button @click="bindDialogVisible = false"> </el-button>
</div>
</el-dialog>
<!-- 排产明细新增/编辑对话框 -->
<el-dialog :title="detailDialogTitle" :visible.sync="detailDialogVisible" width="500px" append-to-body
:close-on-click-modal="false">
<el-form ref="detailForm" :model="detailForm" :rules="detailFormRules" label-width="100px" size="small">
<el-form-item label="规格" prop="spec">
<el-input v-model="detailForm.spec" placeholder="请输入规格" />
</el-form-item>
<el-form-item label="材质" prop="material">
<el-input v-model="detailForm.material" placeholder="请输入材质" />
</el-form-item>
<el-form-item label="排产吨数" prop="scheduleWeight">
<el-input-number v-model="detailForm.scheduleWeight" :min="0" :precision="3" :controls="false" style="width:100%" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="detailForm.remark" type="textarea" :rows="2" placeholder="可选" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="detailBtnLoading" type="danger" @click="submitDetailForm"> </el-button>
<el-button @click="detailDialogVisible = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
@@ -360,7 +399,9 @@ import {
delRequirement,
addRel,
delRel,
addRequirementDetail
addRequirementDetail,
updateRequirementDetail,
delRequirementDetail
} from '@/api/aps/requirement'
import { listCrmOrder } from '@/api/aps/order'
import { parseProductContent } from '@/utils/productContent'
@@ -385,7 +426,6 @@ export default {
statusBadgeMap: { 0: 'gray', 1: 'blue', 2: 'green', 3: 'red' },
// 绑定订单
boundOrderList: [],
bindDialogVisible: false,
bindQuery: { keyword: '', pageNum: 1, pageSize: 50 },
candidateOrderList: [],
@@ -402,6 +442,17 @@ export default {
detailLoading: false,
requirementDetailList: [],
// 排产明细新增/编辑对话框
detailDialogVisible: false,
detailDialogTitle: '新增排产明细',
detailBtnLoading: false,
detailForm: this.getEmptyDetailForm(),
detailFormRules: {
spec: [{ required: true, message: '规格不能为空', trigger: 'blur' }],
material: [{ required: true, message: '材质不能为空', trigger: 'blur' }],
scheduleWeight: [{ required: true, message: '排产吨数不能为空', trigger: 'change' }]
},
// 新增/编辑对话框
dialogVisible: false,
dialogTitle: '新增产需单',
@@ -414,6 +465,9 @@ export default {
}
},
computed: {
canEdit() {
return this.currentReq && (this.currentReq.scheduleStatus === 0 || this.currentReq.scheduleStatus === 3)
},
detailTotalWeight() {
return this.requirementDetailList.reduce((sum, item) => {
const n = Number(item.scheduleWeight)
@@ -452,6 +506,19 @@ export default {
}
},
getEmptyDetailForm() {
return {
scheduleDetailId: undefined,
scheduleId: undefined,
orderDetailId: undefined,
spec: '',
material: '',
scheduleWeight: 0,
productType: '',
remark: ''
}
},
handleSearch() {
this.queryParams.pageNum = 1
this.getList()
@@ -651,8 +718,8 @@ export default {
},
handleUnbindByOrderId(orderId) {
const rel = this.boundOrderList.find(r => r.orderId === orderId)
if (!rel) {
const order = (this.currentReq.orderList || []).find(o => o.orderId === orderId)
if (!order) {
this.$message.warning('未找到关联记录')
return
}
@@ -661,12 +728,120 @@ export default {
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delRel(rel.relId).then(() => {
delRel(order.relId || orderId).then(() => {
this.$modal.msgSuccess('解绑成功')
this.handleReqClick(this.currentReq)
})
}).catch(() => { })
},
// ====== 下发 ======
handleDispatch() {
this.$confirm('确认下发该产需单吗?下发后将进入审核流程。', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
updateRequirement({
scheduleId: this.currentReq.scheduleId,
scheduleStatus: 1
}).then(() => {
this.$modal.msgSuccess('下发成功')
this.getList()
this.handleReqClick(this.currentReq)
}).catch(() => {
this.$modal.msgError('下发失败')
})
}).catch(() => { })
},
// ====== 排产明细新增/编辑/删除 ======
resetDetailForm() {
this.detailForm = this.getEmptyDetailForm()
},
handleDetailAdd() {
if (!this.currentReq) {
this.$message.warning('请先选择一个产需单')
return
}
this.resetDetailForm()
this.detailForm.scheduleId = this.currentReq.scheduleId
this.detailDialogTitle = '新增排产明细'
this.detailDialogVisible = true
this.$nextTick(() => {
this.$refs.detailForm && this.$refs.detailForm.clearValidate()
})
},
handleDetailEdit(row) {
this.detailForm = { ...this.getEmptyDetailForm(), ...row }
this.detailDialogTitle = '编辑排产明细'
this.detailDialogVisible = true
this.$nextTick(() => {
this.$refs.detailForm && this.$refs.detailForm.clearValidate()
})
},
submitDetailForm() {
this.$refs.detailForm.validate(valid => {
if (!valid) return
this.detailBtnLoading = true
const formData = { ...this.detailForm }
if (this.detailForm.scheduleDetailId) {
// 更新
updateRequirementDetail(formData).then(() => {
this.$modal.msgSuccess('修改成功')
this.detailDialogVisible = false
this.refreshDetailList()
}).catch(() => {
this.$modal.msgError('修改失败')
}).finally(() => {
this.detailBtnLoading = false
})
} else {
// 新增
addRequirementDetail(formData).then(() => {
this.$modal.msgSuccess('新增成功')
this.detailDialogVisible = false
this.refreshDetailList()
}).catch(() => {
this.$modal.msgError('新增失败')
}).finally(() => {
this.detailBtnLoading = false
})
}
})
},
handleDetailDelete(row) {
this.$confirm(`确认删除排产明细「${row.spec} / ${row.material}」吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delRequirementDetail(row.scheduleDetailId).then(() => {
this.$modal.msgSuccess('删除成功')
this.refreshDetailList()
}).catch(() => {
this.$modal.msgError('删除失败')
})
}).catch(() => { })
},
refreshDetailList() {
if (!this.currentReq) return
this.detailLoading = true
getRequirement(this.currentReq.scheduleId).then(res => {
if (res.data) {
this.requirementDetailList = res.data.detailList || []
}
}).catch(() => {
this.requirementDetailList = []
}).finally(() => {
this.detailLoading = false
})
},
}
}
</script>
@@ -849,6 +1024,11 @@ export default {
border-color: rgba(255, 255, 255, 0.7);
}
.detail-card-header .header-btn:disabled {
opacity: 0.45;
cursor: not-allowed;
}
.detail-card-body {
padding: 0;
}