feat(aps): 优化排产页面与对比页面的工序类型展示和筛选功能

1. 为待审核、已排产卡片添加自定义加载提示文本
2. 替换工序类型输入框为下拉选择器,使用全局工序枚举数据
3. 为排产表格添加工序类型名称转换显示
4. 重构对比页面的工序筛选逻辑,改为顶部单选按钮组筛选
5. 优化钢卷数据查询逻辑,关联选中的工序类型进行查询
6. 修复编辑和合并表单的字段类型转换问题
This commit is contained in:
2026-06-30 16:43:03 +08:00
parent 524f8f3333
commit f4c870aa23
2 changed files with 119 additions and 56 deletions

View File

@@ -18,6 +18,17 @@
</div> </div>
</div> </div>
<!-- 工序选择 Tab单选影响右侧钢卷查询 -->
<div class="process-tab-bar">
<el-radio-group v-model="selectedProcessActionType" size="small" @change="onProcessChange">
<el-radio-button
v-for="p in processOptions"
:key="p.actionType"
:label="p.actionType"
>{{ p.name }}</el-radio-button>
</el-radio-group>
</div>
<el-row :gutter="12" style="flex:1;min-height:0;"> <el-row :gutter="12" style="flex:1;min-height:0;">
<!-- 左侧排产明细按工序筛选 --> <!-- 左侧排产明细按工序筛选 -->
<el-col :span="12" style="height:100%;display:flex;flex-direction:column;"> <el-col :span="12" style="height:100%;display:flex;flex-direction:column;">
@@ -28,17 +39,6 @@
{{ scheduleList.length }} {{ scheduleList.length }}
</span> </span>
</div> </div>
<!-- 工序筛选按钮 -->
<div v-if="actionTypes.length > 0" class="action-filter-bar">
<el-button
v-for="at in actionTypes"
:key="at"
size="mini"
:type="selectedActionType === at ? 'danger' : 'default'"
@click="filterByActionType(at)"
>{{ at || '(空)' }}</el-button>
<el-button size="mini" :type="selectedActionType === '' ? 'danger' : ''" @click="filterByActionType('')">全部</el-button>
</div>
<div v-loading="schLoading" class="detail-card-body" style="padding:0;flex:1;overflow:auto;"> <div v-loading="schLoading" class="detail-card-body" style="padding:0;flex:1;overflow:auto;">
<el-table <el-table
v-if="filteredScheduleList.length > 0" v-if="filteredScheduleList.length > 0"
@@ -71,7 +71,7 @@
{{ coilTotal }} 净重合计 {{ coilTotalWeight }} {{ coilTotal }} 净重合计 {{ coilTotalWeight }}
</span> </span>
</div> </div>
<div v-loading="coilLoading" class="detail-card-body" style="padding:0;flex:1;overflow:auto;"> <div v-loading="coilLoading" element-loading-text="正在加载钢卷数据..." class="detail-card-body" style="padding:0;flex:1;overflow:auto;">
<el-table <el-table
v-if="coilList.length > 0" v-if="coilList.length > 0"
:data="coilList" :data="coilList"
@@ -105,6 +105,8 @@
<script> <script>
import { listScheduleItem } from '@/api/aps/schedule' import { listScheduleItem } from '@/api/aps/schedule'
import { listMaterialCoil } from '@/api/aps/materialCoil' import { listMaterialCoil } from '@/api/aps/materialCoil'
import { listLightPendingAction } from '@/api/wms/pendingAction'
import { PROCESSES } from '@/utils/meta'
export default { export default {
name: 'ApsCompare', name: 'ApsCompare',
@@ -121,10 +123,12 @@ export default {
// 左侧排产明细 // 左侧排产明细
schLoading: false, schLoading: false,
scheduleList: [], scheduleList: [],
actionTypes: [],
selectedActionType: '',
coilStatusMap: { 0: '在库', 1: '在途', 2: '已出库' }, coilStatusMap: { 0: '在库', 1: '在途', 2: '已出库' },
// 工序筛选(顶部 radio tab
processOptions: PROCESSES,
selectedProcessActionType: null,
// 右侧钢卷 // 右侧钢卷
coilLoading: false, coilLoading: false,
coilList: [], coilList: [],
@@ -134,11 +138,15 @@ export default {
}, },
computed: { computed: {
filteredScheduleList() { filteredScheduleList() {
if (!this.selectedActionType) return this.scheduleList if (!this.selectedProcessActionType) return this.scheduleList
return this.scheduleList.filter(item => (item.actionType || '') === this.selectedActionType) return this.scheduleList.filter(item => String(item.actionType) === String(this.selectedProcessActionType))
} }
}, },
created() { created() {
// 默认选中第一个工序
if (this.processOptions.length > 0) {
this.selectedProcessActionType = this.processOptions[0].actionType
}
this.handleQuery() this.handleQuery()
}, },
methods: { methods: {
@@ -156,44 +164,55 @@ export default {
queryScheduleItems() { queryScheduleItems() {
this.schLoading = true this.schLoading = true
this.scheduleList = [] this.scheduleList = []
this.actionTypes = []
this.selectedActionType = ''
listScheduleItem({ prodDate: this.queryDate, pageNum: 1, pageSize: 9999 }).then(res => { listScheduleItem({ prodDate: this.queryDate, pageNum: 1, pageSize: 9999 }).then(res => {
this.scheduleList = (res.rows || []).sort((a, b) => (a.scheduleNo || '').localeCompare(b.scheduleNo || '')) this.scheduleList = (res.rows || []).sort((a, b) => (a.scheduleNo || '').localeCompare(b.scheduleNo || ''))
// 提取所有不同的 actionType
const types = new Set()
this.scheduleList.forEach(item => {
if (item.actionType) types.add(item.actionType)
})
this.actionTypes = [...types].sort()
this.updateSummary() this.updateSummary()
}).catch(() => { }).catch(() => {
this.scheduleList = [] this.scheduleList = []
this.actionTypes = []
}).finally(() => { }).finally(() => {
this.schLoading = false this.schLoading = false
}) })
}, },
filterByActionType(type) { // ====== 右侧:钢卷(先查 pendingAction 获取 coilIds再查实际钢卷 ======
this.selectedActionType = type
},
// ====== 右侧:钢卷 ======
queryCoils() { queryCoils() {
if (!this.selectedProcessActionType) {
this.coilList = []
this.coilTotal = 0
this.coilTotalWeight = 0
return
}
this.coilLoading = true this.coilLoading = true
this.coilList = [] this.coilList = []
listMaterialCoil({ const startTime = `${this.queryDate} 00:00:00`
pageNum: 1, const endTime = `${this.queryDate} 23:59:59`
pageSize: 9999
// 可根据需要加上日期和 dataType 过滤 listLightPendingAction({
actionType: this.selectedProcessActionType,
startTime,
endTime
}).then(res => { }).then(res => {
this.coilList = res.rows || [] const rows = res.rows || (Array.isArray(res) ? res : [])
this.coilTotal = res.total || this.coilList.length const coilIds = rows.map(r => r.processedCoilId).filter(Boolean)
if (coilIds.length === 0) {
this.coilList = []
this.coilTotal = 0
this.coilTotalWeight = 0
this.updateSummary()
return
}
return listMaterialCoil({
coilIds: coilIds.join(','),
pageNum: 1,
pageSize: 1000
}).then(coilRes => {
this.coilList = coilRes.rows || []
this.coilTotal = coilRes.total || this.coilList.length
this.coilTotalWeight = this.coilList.reduce((sum, c) => sum + (parseFloat(c.netWeight) || 0) / 1000, 0).toFixed(3) this.coilTotalWeight = this.coilList.reduce((sum, c) => sum + (parseFloat(c.netWeight) || 0) / 1000, 0).toFixed(3)
this.updateSummary() this.updateSummary()
})
}).catch(() => { }).catch(() => {
this.coilList = [] this.coilList = []
this.coilTotal = 0 this.coilTotal = 0
@@ -203,6 +222,10 @@ export default {
}) })
}, },
onProcessChange() {
this.queryCoils()
},
updateSummary() { updateSummary() {
this.summaryText = `排产 ${this.scheduleList.length} 条 | 钢卷 ${this.coilTotal}${this.coilTotalWeight}` this.summaryText = `排产 ${this.scheduleList.length} 条 | 钢卷 ${this.coilTotal}${this.coilTotalWeight}`
} }
@@ -251,6 +274,21 @@ export default {
border: 1px solid $aps-border; border: 1px solid $aps-border;
} }
.process-tab-bar {
flex-shrink: 0;
padding: 6px 0;
::v-deep .el-radio-button__inner {
padding: 6px 14px;
font-size: 12px;
}
::v-deep .el-radio-button:first-child .el-radio-button__inner {
border-radius: $aps-radius 0 0 $aps-radius;
}
::v-deep .el-radio-button:last-child .el-radio-button__inner {
border-radius: 0 $aps-radius $aps-radius 0;
}
}
.aps-compare-card { .aps-compare-card {
height: 100%; height: 100%;
display: flex; display: flex;
@@ -259,15 +297,6 @@ export default {
overflow: hidden; overflow: hidden;
} }
.action-filter-bar {
padding: 8px 12px;
border-bottom: 1px solid $aps-border;
display: flex;
flex-wrap: wrap;
gap: 6px;
flex-shrink: 0;
}
.aps-btn-red { .aps-btn-red {
@include aps-btn-red; @include aps-btn-red;
} }

View File

@@ -23,14 +23,14 @@
</div> </div>
<!-- 待审核 Tab --> <!-- 待审核 Tab -->
<div v-show="activeTab === 'pending'" class="detail-card aps-sch-card"> <div v-loading="loading" v-show="activeTab === 'pending'" class="detail-card aps-sch-card">
<div class="detail-card-header"> <div class="detail-card-header">
<span>待审核产需单明细</span> <span>待审核产需单明细</span>
<span v-if="pendingScheduleList.length > 0" style="font-weight:normal;font-size:12px;opacity:0.8;"> <span v-if="pendingScheduleList.length > 0" style="font-weight:normal;font-size:12px;opacity:0.8;">
{{ pendingScheduleList.length }} 个产需单 {{ pendingScheduleList.length }} 个产需单
</span> </span>
</div> </div>
<div v-loading="loading" class="detail-card-body" style="padding:0;"> <div element-loading-text="正在加载待审核产需单..." class="detail-card-body" style="padding:0;">
<div v-if="pendingScheduleList.length > 0" class="aps-sch-list"> <div v-if="pendingScheduleList.length > 0" class="aps-sch-list">
<div v-for="sch in pendingScheduleList" :key="sch.scheduleId" class="aps-sch-item"> <div v-for="sch in pendingScheduleList" :key="sch.scheduleId" class="aps-sch-item">
<!-- 产需单头部排产单号 + 状态标签 + 操作 --> <!-- 产需单头部排产单号 + 状态标签 + 操作 -->
@@ -162,7 +162,7 @@
</div> </div>
<!-- 已排产 Tab --> <!-- 已排产 Tab -->
<div v-show="activeTab === 'scheduled'" class="detail-card aps-sch-card"> <div v-loading="schLoading" v-show="activeTab === 'scheduled'" class="detail-card aps-sch-card">
<div class="detail-card-header"> <div class="detail-card-header">
<span>已排产明细</span> <span>已排产明细</span>
<div style="display:flex; align-items:center; gap:8px;"> <div style="display:flex; align-items:center; gap:8px;">
@@ -191,7 +191,7 @@
</span> </span>
</div> </div>
</div> </div>
<div v-loading="schLoading" class="detail-card-body" style="padding:0;"> <div element-loading-text="正在加载已排产数据..." class="detail-card-body" style="padding:0;">
<el-table <el-table
v-if="scheduledItemList.length > 0" v-if="scheduledItemList.length > 0"
ref="scheduledTable" ref="scheduledTable"
@@ -205,7 +205,11 @@
<el-table-column type="selection" width="45" align="center" /> <el-table-column type="selection" width="45" align="center" />
<el-table-column label="排产单号" prop="scheduleNo" min-width="140" show-overflow-tooltip /> <el-table-column label="排产单号" prop="scheduleNo" min-width="140" show-overflow-tooltip />
<el-table-column label="生产日期" prop="prodDate" width="110" align="center" show-overflow-tooltip /> <el-table-column label="生产日期" prop="prodDate" width="110" align="center" show-overflow-tooltip />
<el-table-column label="工序类型" prop="actionType" width="100" align="center" show-overflow-tooltip /> <el-table-column label="工序类型" prop="actionType" width="100" align="center" show-overflow-tooltip>
<template slot-scope="scope">
{{ getActionTypeName(scope.row.actionType) }}
</template>
</el-table-column>
<el-table-column label="排产状态" prop="scheduleStatus" width="90" align="center"> <el-table-column label="排产状态" prop="scheduleStatus" width="90" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<span class="aps-status-tag" :class="'status-' + (scope.row.scheduleStatus || 1)">{{ statusMap[scope.row.scheduleStatus] || '未知' }}</span> <span class="aps-status-tag" :class="'status-' + (scope.row.scheduleStatus || 1)">{{ statusMap[scope.row.scheduleStatus] || '未知' }}</span>
@@ -303,17 +307,28 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="工序类型"> <el-form-item label="排产状态">
<el-input v-model="editForm.actionType" /> <el-select v-model="editForm.scheduleStatus" placeholder="请选择排产状态" style="width:100%">
<el-option v-for="(label, val) in statusMap" :key="val" :label="label" :value="Number(val)" />
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="12">
<el-form-item label="工序类型">
<el-select v-model="editForm.actionType" placeholder="请选择工序类型" clearable filterable style="width:100%">
<el-option v-for="p in processOptions" :key="p.actionType" :label="p.name" :value="p.actionType" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="订货单位"> <el-form-item label="订货单位">
<el-input v-model="editForm.customerName" /> <el-input v-model="editForm.customerName" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="规格" prop="spec"> <el-form-item label="规格" prop="spec">
<el-input v-model="editForm.spec" /> <el-input v-model="editForm.spec" />
@@ -512,7 +527,11 @@
<el-form-item label="排产单号"><el-input v-model="mergeForm.scheduleNo" /></el-form-item> <el-form-item label="排产单号"><el-input v-model="mergeForm.scheduleNo" /></el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="工序类型"><el-input v-model="mergeForm.actionType" /></el-form-item> <el-form-item label="工序类型">
<el-select v-model="mergeForm.actionType" placeholder="请选择工序类型" clearable filterable style="width:100%">
<el-option v-for="p in processOptions" :key="p.actionType" :label="p.name" :value="p.actionType" />
</el-select>
</el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="16"> <el-row :gutter="16">
@@ -635,6 +654,7 @@ import {
receiveScheduleItem, receiveScheduleItem,
mergeScheduleItem mergeScheduleItem
} from '@/api/aps/schedule' } from '@/api/aps/schedule'
import { PROCESSES } from '@/utils/meta'
export default { export default {
name: 'ApsSchedule', name: 'ApsSchedule',
@@ -654,6 +674,7 @@ export default {
pendingScheduleList: [], pendingScheduleList: [],
summaryText: '', summaryText: '',
statusMap: { 1: '待审核', 2: '已接收', 3: '已驳回' }, statusMap: { 1: '待审核', 2: '已接收', 3: '已驳回' },
processOptions: PROCESSES,
// 已排产 // 已排产
scheduledItemList: [], scheduledItemList: [],
@@ -870,6 +891,14 @@ export default {
handleEditScheduled(row) { handleEditScheduled(row) {
this.editForm = { ...this.getEmptyEditForm(), ...row } this.editForm = { ...this.getEmptyEditForm(), ...row }
// 确保 actionType 为数字类型以匹配下拉选项
if (this.editForm.actionType != null && typeof this.editForm.actionType !== 'number') {
this.editForm.actionType = Number(this.editForm.actionType)
}
// 确保 scheduleStatus 为数字类型以匹配下拉选项
if (this.editForm.scheduleStatus != null && typeof this.editForm.scheduleStatus !== 'number') {
this.editForm.scheduleStatus = Number(this.editForm.scheduleStatus)
}
this.editDialogTitle = '编辑排产明细' this.editDialogTitle = '编辑排产明细'
this.editDialogVisible = true this.editDialogVisible = true
this.$nextTick(() => { this.$nextTick(() => {
@@ -948,7 +977,7 @@ export default {
this.mergeForm = { this.mergeForm = {
itemCount: this.mergeSourceRows.length, itemCount: this.mergeSourceRows.length,
scheduleNo: row.scheduleNo || '', scheduleNo: row.scheduleNo || '',
actionType: row.actionType || '', actionType: row.actionType != null ? Number(row.actionType) : '',
customerName: row.customerName || '', customerName: row.customerName || '',
spec: row.spec || '', spec: row.spec || '',
material: row.material || '', material: row.material || '',
@@ -1004,6 +1033,11 @@ export default {
return total.toFixed(3) return total.toFixed(3)
}, },
getActionTypeName(actionType) {
const p = this.processOptions.find(item => String(item.actionType) === String(actionType))
return p ? p.name : (actionType || '')
},
handleDetailClick(sch, detail) { handleDetailClick(sch, detail) {
// 点击明细行查看来源订单 // 点击明细行查看来源订单
if (!sch || !sch.orderList || sch.orderList.length === 0) { if (!sch || !sch.orderList || sch.orderList.length === 0) {