feat(wms): 新增APS排产对比功能页面

- 添加 compare.vue 页面实现排产明细与现存钢卷对比展示
- 实现左侧排产明细表格按工序筛选功能
- 实现右侧现存钢卷信息展示包括重量统计
- 添加日期查询和汇总统计功能
- 创建 materialCoil API 接口用于获取钢卷数据
- 集成排产明细和钢卷数据的并列对比显示
This commit is contained in:
2026-06-30 09:30:39 +08:00
parent 4a9d811592
commit dbcc28fb80
2 changed files with 322 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
import request from '@/utils/request'
// 查询钢卷物料列表
export function listMaterialCoil(query) {
return request({
url: '/wms/materialCoil/list',
method: 'get',
params: query
})
}

View File

@@ -0,0 +1,312 @@
<template>
<div class="aps-compare-page">
<!-- 顶部工具栏 -->
<div class="aps-compare-toolbar">
<span class="aps-compare-label">生产日期</span>
<el-date-picker
v-model="queryDate"
type="date"
placeholder="选择生产日期"
value-format="yyyy-MM-dd"
size="small"
style="width:160px"
@change="handleQuery"
/>
<el-button size="small" class="aps-btn-red" icon="el-icon-search" @click="handleQuery">查询</el-button>
<div v-if="summaryText" class="aps-compare-summary">
<span>{{ summaryText }}</span>
</div>
</div>
<el-row :gutter="12" style="flex:1;min-height:0;">
<!-- 左侧排产明细按工序筛选 -->
<el-col :span="12" style="height:100%;display:flex;flex-direction:column;">
<div class="detail-card aps-compare-card">
<div class="detail-card-header">
<span>排产明细 按工序筛选</span>
<span v-if="scheduleList.length > 0" style="font-weight:normal;font-size:12px;opacity:0.8;">
{{ scheduleList.length }}
</span>
</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;">
<el-table
v-if="filteredScheduleList.length > 0"
:data="filteredScheduleList"
border
size="small"
class="aps-table"
>
<el-table-column label="排产单号" prop="scheduleNo" min-width="130" show-overflow-tooltip />
<el-table-column label="工序类型" prop="actionType" width="90" align="center" show-overflow-tooltip />
<el-table-column label="规格" prop="spec" min-width="100" show-overflow-tooltip />
<el-table-column label="材质" prop="material" width="80" align="center" show-overflow-tooltip />
<el-table-column label="排产吨数" prop="scheduleWeight" width="90" align="right" />
<el-table-column label="品名" prop="productType" min-width="80" show-overflow-tooltip />
<el-table-column label="订货单位" prop="customerName" min-width="120" show-overflow-tooltip />
</el-table>
<div v-else-if="!schLoading" style="padding:40px;text-align:center;color:#909399;">
{{ hasQueried ? '暂无排产明细' : '请选择日期查询' }}
</div>
</div>
</div>
</el-col>
<!-- 右侧现存钢卷 -->
<el-col :span="12" style="height:100%;display:flex;flex-direction:column;">
<div class="detail-card aps-compare-card">
<div class="detail-card-header">
<span>现存钢卷今日加工</span>
<span v-if="coilList.length > 0" style="font-weight:normal;font-size:12px;opacity:0.8;">
{{ coilTotal }} 净重合计 {{ coilTotalWeight }}
</span>
</div>
<div v-loading="coilLoading" class="detail-card-body" style="padding:0;flex:1;overflow:auto;">
<el-table
v-if="coilList.length > 0"
:data="coilList"
border
size="small"
class="aps-table"
>
<el-table-column label="入场钢卷号" prop="enterCoilNo" min-width="130" show-overflow-tooltip />
<el-table-column label="当前钢卷号" prop="currentCoilNo" min-width="130" show-overflow-tooltip />
<el-table-column label="净重(kg)" prop="netWeight" width="100" align="right" />
<el-table-column label="材料类型" prop="materialType" width="90" align="center" show-overflow-tooltip />
<el-table-column label="物品类型" prop="itemType" width="90" align="center" />
<el-table-column label="状态" prop="status" width="80" align="center">
<template slot-scope="scope">
<span :style="{ color: scope.row.status === 0 ? '#52c41a' : scope.row.status === 1 ? '#1890ff' : '#ff4d4f' }">{{ coilStatusMap[scope.row.status] || scope.row.status }}</span>
</template>
</el-table-column>
<el-table-column label="班组" prop="team" width="70" align="center" />
<el-table-column label="备注" prop="remark" min-width="100" show-overflow-tooltip />
</el-table>
<div v-else-if="!coilLoading" style="padding:40px;text-align:center;color:#909399;">
{{ hasQueried ? '暂无钢卷数据' : '请选择日期查询' }}
</div>
</div>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import { listScheduleItem } from '@/api/aps/schedule'
import { listMaterialCoil } from '@/api/aps/materialCoil'
export default {
name: 'ApsCompare',
data() {
const today = new Date()
const y = today.getFullYear()
const m = String(today.getMonth() + 1).padStart(2, '0')
const d = String(today.getDate()).padStart(2, '0')
return {
queryDate: `${y}-${m}-${d}`,
hasQueried: false,
summaryText: '',
// 左侧排产明细
schLoading: false,
scheduleList: [],
actionTypes: [],
selectedActionType: '',
coilStatusMap: { 0: '在库', 1: '在途', 2: '已出库' },
// 右侧钢卷
coilLoading: false,
coilList: [],
coilTotal: 0,
coilTotalWeight: 0
}
},
computed: {
filteredScheduleList() {
if (!this.selectedActionType) return this.scheduleList
return this.scheduleList.filter(item => (item.actionType || '') === this.selectedActionType)
}
},
created() {
this.handleQuery()
},
methods: {
handleQuery() {
if (!this.queryDate) {
this.$message.warning('请选择生产日期')
return
}
this.hasQueried = true
this.queryScheduleItems()
this.queryCoils()
},
// ====== 左侧:排产明细 ======
queryScheduleItems() {
this.schLoading = true
this.scheduleList = []
this.actionTypes = []
this.selectedActionType = ''
listScheduleItem({ prodDate: this.queryDate, pageNum: 1, pageSize: 9999 }).then(res => {
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()
}).catch(() => {
this.scheduleList = []
this.actionTypes = []
}).finally(() => {
this.schLoading = false
})
},
filterByActionType(type) {
this.selectedActionType = type
},
// ====== 右侧:钢卷 ======
queryCoils() {
this.coilLoading = true
this.coilList = []
listMaterialCoil({
pageNum: 1,
pageSize: 9999
// 可根据需要加上日期和 dataType 过滤
}).then(res => {
this.coilList = res.rows || []
this.coilTotal = res.total || this.coilList.length
this.coilTotalWeight = this.coilList.reduce((sum, c) => sum + (parseFloat(c.netWeight) || 0) / 1000, 0).toFixed(3)
this.updateSummary()
}).catch(() => {
this.coilList = []
this.coilTotal = 0
this.coilTotalWeight = 0
}).finally(() => {
this.coilLoading = false
})
},
updateSummary() {
this.summaryText = `排产 ${this.scheduleList.length} 条 | 钢卷 ${this.coilTotal}${this.coilTotalWeight}`
}
}
}
</script>
<style scoped lang="scss">
@import './scss/aps-theme.scss';
.aps-compare-page {
height: 100%;
padding: 8px;
box-sizing: border-box;
background: $aps-bg;
display: flex;
flex-direction: column;
gap: 10px;
}
.aps-compare-toolbar {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 16px;
background: $aps-white;
border: 1px solid $aps-border;
border-radius: $aps-radius;
box-shadow: $aps-shadow-sm;
flex-shrink: 0;
}
.aps-compare-label {
font-size: 13px;
font-weight: 600;
color: $aps-text;
}
.aps-compare-summary {
margin-left: auto;
font-size: 12px;
color: $aps-text-muted;
background: $aps-silver-1;
padding: 4px 12px;
border-radius: $aps-radius;
border: 1px solid $aps-border;
}
.aps-compare-card {
height: 100%;
display: flex;
flex-direction: column;
min-height: 0;
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 {
@include aps-btn-red;
}
.detail-card {
background: $aps-white;
border: 1px solid $aps-border;
border-radius: $aps-radius;
box-shadow: $aps-shadow-sm;
overflow: hidden;
}
.detail-card-header {
background: linear-gradient(to right, $aps-red-2, $aps-red-3);
color: white;
padding: 8px 14px;
font-size: 13px;
font-weight: 600;
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
}
.detail-card-body {
padding: 14px;
}
.aps-table {
width: 100%;
::v-deep th {
background: $aps-silver-1 !important;
color: $aps-text !important;
font-weight: 600 !important;
}
::v-deep td {
padding: 6px 8px;
}
}
</style>