feat(排产单): 新增排产单追踪页面和钢卷列表查询功能

- 添加排产单追踪页面,展示排产单详情和对应钢卷信息
- 新增listPlanCoils接口用于查询排产单对应的钢卷列表
- 在PlanSheetList组件中添加readonly属性控制操作按钮显示
- 优化CoilTable组件中钢卷号的列名显示
This commit is contained in:
2026-04-27 18:36:23 +08:00
parent b85971d532
commit 5b38ef734a
4 changed files with 541 additions and 7 deletions

View File

@@ -42,3 +42,11 @@ export function delPlanDetail(planDetailId) {
method: 'delete'
})
}
// 查询排产单对应的钢卷列表
export function listPlanCoils(planSheetId) {
return request({
url: '/aps/planDetail/coils/' + planSheetId,
method: 'get',
})
}

View File

@@ -46,7 +46,7 @@
<el-input v-model="queryParams.scheduler" placeholder="请输入排产人" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-if="!readonly">新增</el-button>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
@@ -65,8 +65,8 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-download" @click.stop="handleExport(scope.row)">导出</el-button>
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleUpdate(scope.row)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click.stop="handleDelete(scope.row)">删除</el-button>
<el-button v-if="!readonly" size="mini" type="text" icon="el-icon-edit" @click.stop="handleUpdate(scope.row)">修改</el-button>
<el-button v-if="!readonly" size="mini" type="text" icon="el-icon-delete" @click.stop="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
@@ -114,6 +114,10 @@ export default {
selectFirst: {
type: Boolean,
default: true
},
readonly: {
type: Boolean,
default: false
}
},
data() {

View File

@@ -0,0 +1,522 @@
<template>
<div class="app-container">
<!-- 增加操作列用于打开弹窗选择排产单选择后展示选择的排产单的信息 -->
<PlanSheetList @row-click="handleRowClick" :readonly="true" />
<div v-if="currentPlanSheetId" class="plan-detail-container" v-loading="loading">
<!-- 排产单信息 -->
<div class="card-header">
<h3>{{ currentPlanSheetInfo.planSheetName || '排产单详情' }}</h3>
</div>
<div class="plan-info">
<el-row :gutter="20">
<el-col :span="6">
<span class="label">排产单号</span>
<span>{{ currentPlanSheetInfo.planCode }}</span>
</el-col>
<el-col :span="6">
<span class="label">排产人</span>
<span>{{ currentPlanSheetInfo.scheduler }}</span>
</el-col>
<el-col :span="6">
<span class="label">排产时间</span>
<span>{{ currentPlanSheetInfo.planDate }}</span>
</el-col>
<el-col :span="6">
<span class="label">产线</span>
<span>{{ currentPlanSheetInfo.lineName }}</span>
</el-col>
</el-row>
</div>
<!-- 可编辑表格 -->
<el-row :gutter="10">
<el-col :span="12">
<!-- 统计信息 -->
<div class="coil-stats" style="margin-bottom: 10px; padding: 10px; background-color: #f5f7fa; border-radius: 4px;">
<span style="margin-right: 20px;"><strong>总条数{{ totalCount }}</strong></span>
<span><strong>总重量{{ totalWeight }} t</strong></span>
</div>
<KLPTable v-loading="loading" :data="planDetailList" style="width: 100%" border :floatLayer="true" :floatLayerConfig="floatLayerConfig">
<el-table-column label="序号" align="center" prop="bizSeqNo" width="80" fixed="left" />
<!-- 订单信息 -->
<el-table-column label="订单号" align="center" prop="orderCode" width="200" />
<el-table-column label="合同号" align="center" prop="contractCode" width="150" />
<el-table-column label="客户" align="center" prop="customerName" width="180" />
<el-table-column label="业务员" align="center" prop="salesman" width="120" />
<!-- 原料信息 -->
<el-table-column label="原料厂家" align="center" prop="rawManufacturer" width="120" />
<el-table-column label="原料材质" align="center" prop="rawMaterial" width="120" />
<el-table-column label="原料厚度" align="center" prop="rawThick" width="100" />
<el-table-column label="原料宽度" align="center" prop="rawWidth" width="100" />
<!-- 成品信息 -->
<el-table-column label="成品名称" align="center" prop="productName" width="170" />
<el-table-column label="成品材质" align="center" prop="productMaterial" width="120" />
<el-table-column label="成品镀层" align="center" prop="coatingG" width="120" />
<el-table-column label="成品宽度" align="center" prop="productWidth" width="100" />
<el-table-column label="轧制厚度" align="center" prop="rollingThick" width="100" />
<el-table-column label="标签厚度" align="center" prop="markCoatThick" width="120" />
<el-table-column label="吨钢长度区间" align="center" prop="tonSteelLengthRange" width="120" />
<el-table-column label="数量" align="center" prop="planQty" width="100" />
<el-table-column label="重量" align="center" prop="planWeight" width="100" />
<el-table-column label="表面处理" align="center" prop="surfaceTreatmentDesc" width="100" />
<el-table-column label="切边要求" align="center" prop="widthReq" width="100" />
<el-table-column label="包装要求" align="center" prop="productPackaging" width="100" />
<el-table-column label="宽度要求" align="center" prop="productEdgeReq" width="100" />
<el-table-column label="用途" align="center" prop="usageReq" width="100" />
<!-- 生产信息 -->
<el-table-column label="开始时间" align="center" prop="startTime" width="180" />
<el-table-column label="结束时间" align="center" prop="endTime" width="180" />
<el-table-column label="后处理" align="center" prop="postProcess" width="100" />
<el-table-column label="下工序" align="center" prop="nextProcess" width="100" />
<el-table-column label="取样" align="center" prop="sampleReq" width="100" />
<el-table-column label="备注" align="center" prop="remark" />
</KLPTable>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
</el-col>
<el-col :span="12">
<CoilTable :coilList="coilList" tableHeight="calc(100vh - 340px)" />
</el-col>
</el-row>
</div>
<el-empty v-else class="appempty" description="选择排产单查看详情" />
</div>
</template>
<script>
import { updatePlanDetail, listPlanDetail, addPlanDetail, delPlanDetail, listPlanCoils } from "@/api/aps/planDetail";
import { getPlanSheet } from "@/api/aps/planSheet";
import { listOrder } from '@/api/crm/order';
import { listOrderItem } from '@/api/crm/orderItem'
import PlanSheetList from "@/views/aps/planSheet/PlanSheetList.vue";
import CoilTable from "@/views/crm/components/CoilTable.vue";
export default {
name: "PlanSheet",
dicts: ['sys_lines'],
components: {
PlanSheetList,
CoilTable
},
computed: {
// 计算总条数
totalCount() {
return this.planDetailList.length;
},
// 计算总重量
totalWeight() {
return this.planDetailList.reduce((sum, item) => {
return sum + (Number(item.planWeight) || 0);
}, 0).toFixed(2);
}
},
data() {
return {
// 当前选中的排产单ID
currentPlanSheetId: undefined,
// 当前选中的明细数据
currentPlanDetail: {},
// 对话框可见状态
dialogVisible: false,
// 当前排产单详情信息
currentPlanSheetInfo: {},
// 最近选择的排产单列表
recentPlanSheets: [],
// 排产单明细表格数据
planDetailList: [],
// 总条数
total: 0,
// 加载状态
loading: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 50,
planSheetId: undefined
},
// 订单对话框
orderDialogVisible: false,
// 订单明细对话框
orderItemDialogVisible: false,
// 订单列表
orderList: [],
// 订单总数
orderTotal: 0,
// 订单加载状态
orderLoading: false,
// 订单查询参数
orderQueryParams: {
pageNum: 1,
pageSize: 50,
contractCode: undefined,
customerName: undefined,
salesman: undefined
},
// 订单明细列表
orderItemList: [],
// 订单明细加载状态
orderItemLoading: false,
// 当前编辑的行
currentEditingRow: null,
// 钢卷列表
coilList: [],
// floatLayer配置
floatLayerConfig: {
columns: [
{ label: '序号', prop: 'bizSeqNo' },
{ label: '订单号', prop: 'orderCode' },
{ label: '合同号', prop: 'contractCode' },
{ label: '客户', prop: 'customerName' },
{ label: '业务员', prop: 'salesman' },
{ label: '原料厂家', prop: 'rawManufacturer' },
{ label: '原料材质', prop: 'rawMaterial' },
{ label: '原料厚度', prop: 'rawThick' },
{ label: '原料宽度', prop: 'rawWidth' },
{ label: '成品名称', prop: 'productName' },
{ label: '成品材质', prop: 'productMaterial' },
{ label: '成品镀层', prop: 'coatingG' },
{ label: '成品宽度', prop: 'productWidth' },
{ label: '轧制厚度', prop: 'rollingThick' },
{ label: '标签厚度', prop: 'markCoatThick' },
{ label: '吨钢长度区间', prop: 'tonSteelLengthRange' },
{ label: '数量', prop: 'planQty' },
{ label: '重量', prop: 'planWeight' },
{ label: '表面处理', prop: 'surfaceTreatmentDesc' },
{ label: '切边要求', prop: 'widthReq' },
{ label: '包装要求', prop: 'productPackaging' },
{ label: '宽度要求', prop: 'productEdgeReq' },
{ label: '用途', prop: 'usageReq' },
{ label: '开始时间', prop: 'startTime' },
{ label: '结束时间', prop: 'endTime' },
{ label: '后处理', prop: 'postProcess' },
{ label: '下工序', prop: 'nextProcess' },
{ label: '取样', prop: 'sampleReq' },
{ label: '备注', prop: 'remark' },
],
title: '详细信息'
},
};
},
created() {
// 从本地存储加载最近选择的排产单
this.loadRecentPlanSheets();
},
methods: {
// 打开管理排产单对话框
openDialog() {
this.dialogVisible = true;
},
// 点击排产单行,显示详情
handleRowClick(row) {
this.currentPlanSheetId = row.planSheetId;
this.currentPlanDetail = {};
this.dialogVisible = false;
// 获取排产单详情
this.getPlanSheetDetail(row.planSheetId);
// 获取排产单对应的钢卷列表
this.getCoilList(row.planSheetId);
// 添加到最近选择的列表
this.addToRecentPlanSheets(row);
// 更新查询参数
this.queryParams.planSheetId = row.planSheetId;
// 获取排产单明细列表
this.getList();
},
// 获取排产单详情
getPlanSheetDetail(planSheetId) {
getPlanSheet(planSheetId).then(response => {
this.currentPlanSheetInfo = response.data;
});
},
// 获取排产单对应的钢卷列表
getCoilList(planSheetId) {
listPlanCoils(planSheetId).then(response => {
this.coilList = response.data;
this.total = response.total;
});
},
// 添加到最近选择的排产单列表
addToRecentPlanSheets(planSheet) {
// 移除已存在的相同排产单
this.recentPlanSheets = this.recentPlanSheets.filter(item => item.planSheetId !== planSheet.planSheetId);
// 添加到列表开头
this.recentPlanSheets.unshift(planSheet);
// 限制最近选择的数量为5个
if (this.recentPlanSheets.length > 5) {
this.recentPlanSheets = this.recentPlanSheets.slice(0, 5);
}
// 保存到本地存储
this.saveRecentPlanSheets();
},
// 从本地存储加载最近选择的排产单
loadRecentPlanSheets() {
try {
const stored = localStorage.getItem('recentPlanSheets');
if (stored) {
this.recentPlanSheets = JSON.parse(stored);
}
} catch (error) {
console.error('Failed to load recent plan sheets:', error);
this.recentPlanSheets = [];
}
},
// 保存最近选择的排产单到本地存储
saveRecentPlanSheets() {
try {
localStorage.setItem('recentPlanSheets', JSON.stringify(this.recentPlanSheets));
} catch (error) {
console.error('Failed to save recent plan sheets:', error);
}
},
// 选择最近的排产单
selectRecentPlanSheet(item) {
this.currentPlanSheetId = item.planSheetId;
this.currentPlanDetail = {};
this.currentPlanSheetInfo = item;
// 更新查询参数
this.queryParams.planSheetId = item.planSheetId;
// 获取排产单明细列表
this.getList();
},
// 处理排产明细行点击事件
handlePlanDetailChange(row) {
this.currentPlanDetail = row;
},
// 提交排产明细变更
submitDetail() {
updatePlanDetail(this.currentPlanDetail).then(response => {
this.$message({
message: "变更保存成功",
type: "success"
});
});
},
// 获取排产单明细列表
getList() {
this.loading = true;
listPlanDetail({
...this.queryParams,
planSheetId: this.currentPlanSheetId,
}).then(response => {
// 按照序号正序排序
this.planDetailList = response.rows.sort((a, b) => {
return parseInt(a.bizSeqNo) - parseInt(b.bizSeqNo);
});
this.total = response.total;
this.loading = false;
});
},
// 新增明细
handleAdd() {
const newRow = {
planSheetId: this.currentPlanSheetId,
bizSeqNo: this.planDetailList.length + 1
};
addPlanDetail(newRow).then(response => {
this.$message({
message: "新增成功",
type: "success"
});
this.getList();
});
},
// 保存行
handleSave(row) {
updatePlanDetail(row).then(response => {
this.$message({
message: "保存成功",
type: "success"
});
}).catch(error => {
this.$message({
message: "保存失败,正在重新获取数据",
type: "error"
});
// 保存失败时获取正确数据
this.getList();
});
},
// 删除行
handleDelete(row) {
this.$confirm('是否确认删除该排产单明细?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delPlanDetail(row.planDetailId).then(response => {
this.$message({
message: "删除成功",
type: "success"
});
this.getList();
});
});
},
// 打开订单选择对话框
openOrderDialog(row) {
this.currentEditingRow = row;
this.orderDialogVisible = true;
this.getOrderList();
},
// 打开订单明细选择对话框
openOrderItemDialog(row) {
this.currentEditingRow = row;
this.orderItemDialogVisible = true;
this.orderItemLoading = true;
listOrderItem({ orderId: row.orderId }).then(res => {
this.orderItemList = res.rows;
this.orderItemLoading = false;
});
},
// 获取订单列表
getOrderList() {
this.orderLoading = true;
listOrder(this.orderQueryParams).then(response => {
this.orderList = response.rows;
this.orderTotal = response.total;
this.orderLoading = false;
});
},
// 重置订单查询参数
resetOrderQuery() {
this.orderQueryParams = {
pageNum: 1,
pageSize: 10,
contractCode: undefined,
customerName: undefined,
salesman: undefined
};
this.getOrderList();
},
// 选择订单
selectOrder(row) {
this.currentEditingRow.orderCode = row.orderCode;
this.currentEditingRow.contractCode = row.contractCode;
this.currentEditingRow.customerName = row.companyName;
this.currentEditingRow.salesman = row.salesman;
this.currentEditingRow.orderId = row.orderId;
this.orderDialogVisible = false;
// 保存修改
this.handleSave(this.currentEditingRow);
},
// 选择订单明细
selectOrderItem(row) {
this.currentEditingRow.productName = row.productType;
this.currentEditingRow.productMaterial = row.material;
this.currentEditingRow.productWidth = row.width;
this.currentEditingRow.rollingThick = row.thickness;
this.currentEditingRow.markCoatThick = row.thickness;
this.currentEditingRow.tonSteelLengthRange = 0;
this.currentEditingRow.planQty = row.productNum;
this.currentEditingRow.planWeight = row.weight;
this.currentEditingRow.surfaceTreatment = row.surfaceTreatment;
this.currentEditingRow.productPackaging = row.packagingReq;
this.currentEditingRow.widthReq = row.edgeCuttingReq;
this.currentEditingRow.productEdgeReq = row.widthTolerance;
this.currentEditingRow.usageReq = row.purpose;
this.orderItemDialogVisible = false;
// 保存修改
this.handleSave(this.currentEditingRow);
},
// 处理订单行点击
handleOrderSelect(row) {
this.selectOrder(row);
}
}
};
</script>
<style scoped>
.header {
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.plan-info {
margin-bottom: 20px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.card-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
}
.plan-info .label {
font-weight: 600;
margin-right: 5px;
}
.mb20 {
margin-bottom: 20px;
}
.plan-detail-container {
margin-top: 20px;
}
.el-table {
margin-top: 10px;
}
.el-table .cell {
white-space: normal;
word-break: break-word;
}
.order-dialog-content {
padding: 10px 0;
}
.pagination-container {
margin-top: 20px;
text-align: right;
}
.appempty {
margin-top: 20px;
}
::v-deep .el-table .cell {
padding: 0;
}
/* ::v-deep .el-input__inner {
padding: 0 1px;
} */
</style>

View File

@@ -6,12 +6,12 @@
<span><strong>总净重{{ totalNetWeight }} kg</strong></span>
</div>
<KLPTable :data="data" :floatLayer="true" :floatLayerConfig="floatLayerConfig" :height="tableHeight">
<el-table-column label="入场卷号" align="center" prop="enterCoilNo">
<el-table-column label="入场卷号" align="center" prop="enterCoilNo">
<template slot-scope="scope">
<coil-no :coil-no="scope.row.enterCoilNo"></coil-no>
</template>
</el-table-column>
<el-table-column label="当前卷号" align="center" prop="currentCoilNo">
<el-table-column label="当前卷号" align="center" prop="currentCoilNo">
<template slot-scope="scope">
<current-coil-no :current-coil-no="scope.row.currentCoilNo"></current-coil-no>
</template>
@@ -113,8 +113,8 @@ export default {
return {
floatLayerConfig: {
columns: [
{ label: '入场卷号', prop: 'enterCoilNo' },
{ label: '当前卷号', prop: 'currentCoilNo' },
{ label: '入场卷号', prop: 'enterCoilNo' },
{ label: '当前卷号', prop: 'currentCoilNo' },
{ label: '厂家卷号', prop: 'supplierCoilNo' },
{ label: '逻辑库位', prop: 'warehouseName' },
{ label: '实际库位', prop: 'actualWarehouseName' },