This commit is contained in:
jhd
2026-06-29 14:50:09 +08:00
2 changed files with 347 additions and 125 deletions

View File

@@ -1,14 +1,15 @@
<template>
<div class="app-container" style="height: calc(100vh - 84px); display: flex;">
<!-- 左侧订单列表 -->
<div class="left-panel" v-loading="orderLoading" style="width: 30%; border-right: 1px solid #e4e7ed; overflow-y: auto;">
<div class="left-panel" v-loading="orderLoading"
style="width: 30%; border-right: 1px solid #e4e7ed; overflow-y: auto;">
<!-- 筛选区 -->
<div class="filter-section" style="padding: 10px; border-bottom: 1px solid #e4e7ed;">
<!-- 第一行搜索 + 按钮 + 记录数 -->
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;">
<div style="display: flex; align-items: center; gap: 4px; flex-wrap: wrap;">
<el-input v-model="queryParams.keyword" placeholder="请输入关键字" clearable
@keyup.enter.native="handleSearch" style="width: 160px;" />
<el-input v-model="queryParams.keyword" placeholder="请输入关键字" clearable @keyup.enter.native="handleSearch"
style="width: 160px;" />
<el-button class="aps-btn-red" icon="el-icon-search" size="mini" @click="handleSearch">筛选</el-button>
<el-button icon="el-icon-sort" size="mini" @click="toggleMoreFilter"
:class="showMoreFilter ? 'aps-btn-red' : 'aps-btn-silver'"></el-button>
@@ -67,13 +68,9 @@
<!-- 列表区域 -->
<div class="custom-list">
<div class="list-body">
<div
v-for="item in orderList"
:key="item.orderId"
class="list-item"
<div v-for="item in orderList" :key="item.orderId" class="list-item"
:class="{ 'list-item-active': currentOrder && currentOrder.orderId === item.orderId }"
@click="handleOrderClick(item)"
>
@click="handleOrderClick(item)">
<!-- 第一行订单编号 + 客户公司 -->
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<div style="display: flex; align-items: center; gap: 8px;">
@@ -99,30 +96,23 @@
<div style="font-size: 12px; color: #909399;">
签订地点: {{ item.signLocation || '-' }}
</div>
<el-tag
:type="statusTagType(item.orderStatus)"
size="small"
>{{ statusLabel(item.orderStatus) }}</el-tag>
<el-tag :type="statusTagType(item.orderStatus)" size="small">{{ statusLabel(item.orderStatus) }}</el-tag>
</div>
</div>
<div v-if="orderList.length === 0 && !orderLoading" style="padding: 40px; text-align: center; color: #909399;">
<div v-if="orderList.length === 0 && !orderLoading"
style="padding: 40px; text-align: center; color: #909399;">
暂无订单数据
</div>
</div>
</div>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
style="padding: 10px; margin-bottom: 10px !important;"
/>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" style="padding: 10px; margin-bottom: 10px !important;" />
</div>
<!-- 右侧内容区域 -->
<div class="right-panel" v-if="currentOrder && currentOrder.orderId" style="flex: 1; display: flex; flex-direction: column;">
<div class="right-panel" v-if="currentOrder && currentOrder.orderId"
style="flex: 1; display: flex; flex-direction: column;">
<div class="detail-panel">
<!-- 订单基本信息含甲乙双方卡片 -->
<div class="detail-card">
@@ -131,29 +121,68 @@
</div>
<div class="detail-card-body">
<div class="form-grid-2">
<div class="form-field"><label>销售员</label><div class="field-value">{{ currentOrder.salesman }}</div></div>
<div class="form-field"><label>合同号</label><div class="field-value">{{ currentOrder.contractCode }}</div></div>
<div class="form-field"><label>签订时间</label><div class="field-value">{{ currentOrder.signTime }}</div></div>
<div class="form-field"><label>交货日期</label><div class="field-value">{{ currentOrder.deliveryDate }}</div></div>
<div class="form-field"><label>订单总金额</label><div class="field-value">{{ currentOrder.orderAmount }}</div></div>
<div class="form-field"><label>签订地点</label><div class="field-value">{{ currentOrder.signLocation }}</div></div>
<div class="form-field" style="grid-column:1/3;"><label>备注</label><div class="field-value">{{ currentOrder.remark }}</div></div>
<div class="form-field"><label>销售员</label>
<div class="field-value">{{ currentOrder.salesman }}</div>
</div>
<div class="form-field"><label>合同号</label>
<div class="field-value">{{ currentOrder.contractCode }}</div>
</div>
<div class="form-field"><label>签订时间</label>
<div class="field-value">{{ currentOrder.signTime }}</div>
</div>
<div class="form-field"><label>交货日期</label>
<div class="field-value">{{ currentOrder.deliveryDate }}</div>
</div>
<div class="form-field"><label>订单总金额</label>
<div class="field-value">{{ currentOrder.orderAmount }}</div>
</div>
<div class="form-field"><label>签订地点</label>
<div class="field-value">{{ currentOrder.signLocation }}</div>
</div>
<div class="form-field" style="grid-column:1/3;"><label>备注</label>
<div class="field-value">{{ currentOrder.remark }}</div>
</div>
</div>
<div class="section-divider"></div>
<div class="form-grid-2">
<div class="form-field"><label>供方名称甲方</label><div class="field-value">{{ currentOrder.supplier }}</div></div>
<div class="form-field"><label>供方地址</label><div class="field-value">{{ currentOrder.supplierAddress }}</div></div>
<div class="form-field"><label>供方电话</label><div class="field-value">{{ currentOrder.supplierPhone }}</div></div>
<div class="form-field"><label>供方开户行</label><div class="field-value">{{ currentOrder.supplierBank }}</div></div>
<div class="form-field"><label>供方账号</label><div class="field-value">{{ currentOrder.supplierAccount }}</div></div>
<div class="form-field"><label>供方税号</label><div class="field-value">{{ currentOrder.supplierTaxNo }}</div></div>
<div class="form-field" style="border-top:1px solid #e8e8e8;padding-top:8px;margin-top:4px;grid-column:1/3;"></div>
<div class="form-field"><label>需方名称乙方</label><div class="field-value">{{ currentOrder.customer }}</div></div>
<div class="form-field"><label>需方地址</label><div class="field-value">{{ currentOrder.customerAddress }}</div></div>
<div class="form-field"><label>需方电话</label><div class="field-value">{{ currentOrder.customerPhone }}</div></div>
<div class="form-field"><label>需方开户行</label><div class="field-value">{{ currentOrder.customerBank }}</div></div>
<div class="form-field"><label>需方账号</label><div class="field-value">{{ currentOrder.customerAccount }}</div></div>
<div class="form-field"><label>需方税</label><div class="field-value">{{ currentOrder.customerTaxNo }}</div></div>
<div class="form-field"><label>供方名称甲方</label>
<div class="field-value">{{ currentOrder.supplier }}</div>
</div>
<div class="form-field"><label>供方地址</label>
<div class="field-value">{{ currentOrder.supplierAddress }}</div>
</div>
<div class="form-field"><label>供方电话</label>
<div class="field-value">{{ currentOrder.supplierPhone }}</div>
</div>
<div class="form-field"><label>供方开户行</label>
<div class="field-value">{{ currentOrder.supplierBank }}</div>
</div>
<div class="form-field"><label>供方账</label>
<div class="field-value">{{ currentOrder.supplierAccount }}</div>
</div>
<div class="form-field"><label>供方税号</label>
<div class="field-value">{{ currentOrder.supplierTaxNo }}</div>
</div>
<div class="form-field"
style="border-top:1px solid #e8e8e8;padding-top:8px;margin-top:4px;grid-column:1/3;"></div>
<div class="form-field"><label>需方名称乙方</label>
<div class="field-value">{{ currentOrder.customer }}</div>
</div>
<div class="form-field"><label>需方地址</label>
<div class="field-value">{{ currentOrder.customerAddress }}</div>
</div>
<div class="form-field"><label>需方电话</label>
<div class="field-value">{{ currentOrder.customerPhone }}</div>
</div>
<div class="form-field"><label>需方开户行</label>
<div class="field-value">{{ currentOrder.customerBank }}</div>
</div>
<div class="form-field"><label>需方账号</label>
<div class="field-value">{{ currentOrder.customerAccount }}</div>
</div>
<div class="form-field"><label>需方税号</label>
<div class="field-value">{{ currentOrder.customerTaxNo }}</div>
</div>
</div>
</div>
</div>
@@ -165,6 +194,11 @@
</div>
<div class="detail-card-body" style="padding:0;">
<div v-if="productList.length > 0" class="aps-product-table-wrap">
<div class="aps-product-summary">
<span>产品名称{{ productName }}</span>
<span>总数量{{ totalQuantity }} </span>
<span>含税总额{{ totalTaxTotal }}</span>
</div>
<el-table :data="productList" border size="small" class="aps-product-table">
<el-table-column label="规格" prop="spec" min-width="120" />
<el-table-column label="材质" prop="material" width="100" align="center" />
@@ -176,11 +210,6 @@
<el-table-column label="税额" prop="taxAmount" width="90" align="right" />
<el-table-column label="备注" prop="remark" min-width="120" />
</el-table>
<div class="aps-product-summary">
<span>产品名称{{ productName }}</span>
<span>总数量{{ totalQuantity }} </span>
<span>含税总额{{ totalTaxTotal }}</span>
</div>
</div>
<el-empty v-else description="暂无产品明细" />
</div>

View File

@@ -31,51 +31,130 @@
</span>
</div>
<div class="detail-card-body" style="padding:0;" v-loading="loading">
<el-table
v-if="pendingScheduleList.length > 0"
:data="pendingScheduleList"
border
size="small"
class="aps-table"
@row-click="handleScheduleClick"
:expand-row-keys="expandedRowKeys"
@expand-change="handleExpandChange"
row-key="scheduleId"
>
<el-table-column type="expand" width="40">
<template slot-scope="{ row }">
<el-table :data="expandDetailMap[row.scheduleId] || []" border size="mini" style="margin:6px 0;" @row-click.stop="handleRowClick">
<el-table-column label="规格" prop="spec" min-width="120" />
<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="productType" min-width="100" />
<el-table-column label="备注" prop="remark" min-width="100" />
</el-table>
</template>
</el-table-column>
<el-table-column label="排产单号" prop="scheduleNo" min-width="140" />
<el-table-column label="订货单位" prop="customerName" min-width="140" />
<el-table-column label="业务员" prop="businessUser" width="80" align="center" />
<el-table-column label="明细数量" width="80" align="center">
<template slot-scope="{ row }">
{{ (row.detailList || []).length }}
</template>
</el-table-column>
<el-table-column label="排产总吨数" width="100" align="right">
<template slot-scope="{ row }">
{{ scheduleTotalWeight(row) }}
</template>
</el-table-column>
<el-table-column label="交货期(天)" prop="deliveryCycle" width="90" align="center" />
<el-table-column label="操作" width="140" align="center" fixed="right">
<template slot-scope="scope">
<span style="white-space:nowrap;">
<el-button type="text" size="small" style="color:#52c41a;" @click.stop="handleAccept(scope.row)">接收</el-button>
<el-button type="text" size="small" style="color:#ff4d4f;" @click.stop="handleReject(scope.row)">驳回</el-button>
</span>
</template>
</el-table-column>
</el-table>
<div v-if="pendingScheduleList.length > 0" class="aps-sch-list">
<div class="aps-sch-item" v-for="sch in pendingScheduleList" :key="sch.scheduleId">
<!-- 产需单头部排产单号 + 状态标签 + 操作 -->
<div class="aps-sch-item-header">
<div class="aps-sch-item-header-left">
<span class="aps-sch-no">{{ sch.scheduleNo }}</span>
<span class="aps-status-tag" :class="'status-' + (sch.scheduleStatus || 1)">{{ statusMap[sch.scheduleStatus] || '待审核' }}</span>
<span class="aps-sch-header-extra">
{{ sch.customerName }} · {{ sch.businessUser }} · {{ sch.deliveryCycle }}
</span>
</div>
<div class="aps-sch-item-actions">
<el-button type="text" size="small" style="color:#52c41a;" @click.stop="handleAccept(sch)">接收</el-button>
<el-button type="text" size="small" style="color:#ff4d4f;" @click.stop="handleReject(sch)">驳回</el-button>
</div>
</div>
<!-- 产需单完整信息表 -->
<table class="req-info-table">
<tbody>
<tr>
<td class="req-td-label">排产单号</td>
<td class="req-td-value">{{ sch.scheduleNo }}</td>
<td class="req-td-label">生产日期</td>
<td class="req-td-value">{{ sch.prodDate }}</td>
</tr>
<tr>
<td class="req-td-label">排产状态</td>
<td class="req-td-value">
<span class="aps-status-tag" :class="'status-' + (sch.scheduleStatus || 1)">{{ statusMap[sch.scheduleStatus] || '未知' }}</span>
</td>
<td class="req-td-label">业务员</td>
<td class="req-td-value">{{ sch.businessUser }}</td>
</tr>
<tr>
<td class="req-td-label">联系电话</td>
<td class="req-td-value">{{ sch.businessPhone }}</td>
<td class="req-td-label">订货单位</td>
<td class="req-td-value">{{ sch.customerName }}</td>
</tr>
<tr>
<td class="req-td-label">交货期()</td>
<td class="req-td-value">{{ sch.deliveryCycle }}</td>
<td class="req-td-label">产品用途</td>
<td class="req-td-value">{{ sch.usePurpose }}</td>
</tr>
<tr>
<td class="req-td-label">品名</td>
<td class="req-td-value" colspan="3">{{ sch.productType }}</td>
</tr>
<tr>
<td class="req-td-label">厚度公差</td>
<td class="req-td-value">{{ sch.thicknessTolerance }}</td>
<td class="req-td-label">宽度公差</td>
<td class="req-td-value">{{ sch.widthTolerance }}</td>
</tr>
<tr>
<td class="req-td-label">表面质量</td>
<td class="req-td-value">{{ sch.surfaceQuality }}</td>
<td class="req-td-label">表面处理</td>
<td class="req-td-value">{{ sch.surfaceTreatment }}</td>
</tr>
<tr>
<td class="req-td-label">内径尺寸</td>
<td class="req-td-value">{{ sch.innerDiameter }}</td>
<td class="req-td-label">外径要求</td>
<td class="req-td-value">{{ sch.outerDiameter }}</td>
</tr>
<tr>
<td class="req-td-label">包装要求</td>
<td class="req-td-value">{{ sch.packReq }}</td>
<td class="req-td-label">切边要求</td>
<td class="req-td-value">{{ sch.cutEdgeReq }}</td>
</tr>
<tr>
<td class="req-td-label">单件重量</td>
<td class="req-td-value">{{ sch.singleCoilWeight }}</td>
<td class="req-td-label">交货重量偏差</td>
<td class="req-td-value">{{ sch.weightDeviation }}</td>
</tr>
<tr>
<td class="req-td-label">其他技术要求</td>
<td class="req-td-value" colspan="3">{{ sch.otherTechReq }}</td>
</tr>
<tr>
<td class="req-td-label">付款情况说明</td>
<td class="req-td-value" colspan="3">{{ sch.paymentDesc }}</td>
</tr>
<tr>
<td class="req-td-label">备注</td>
<td class="req-td-value" colspan="3">{{ sch.remark }}</td>
</tr>
<tr v-if="sch.returnReason">
<td class="req-td-label" style="color:#e74c3c;">驳回原因</td>
<td class="req-td-value" colspan="3" style="color:#e74c3c;background:#fdecea;">{{ sch.returnReason }}</td>
</tr>
</tbody>
</table>
<!-- 明细列表 -->
<div class="aps-sch-item-details" v-if="(sch.detailList || []).length > 0">
<div class="aps-sch-detail-header">
<span class="aps-sch-detail-col col-spec">规格</span>
<span class="aps-sch-detail-col col-material">材质</span>
<span class="aps-sch-detail-col col-weight">排产吨数</span>
<span class="aps-sch-detail-col col-type">品名</span>
<span class="aps-sch-detail-col col-remark">备注</span>
</div>
<div
class="aps-sch-detail-row"
v-for="(d, di) in sch.detailList"
:key="di"
@click="handleDetailClick(sch, d)"
>
<span class="aps-sch-detail-col col-spec">{{ d.spec }}</span>
<span class="aps-sch-detail-col col-material">{{ d.material }}</span>
<span class="aps-sch-detail-col col-weight">{{ d.scheduleWeight }}</span>
<span class="aps-sch-detail-col col-type">{{ sch.productType || d.productType || '' }}</span>
<span class="aps-sch-detail-col col-remark">{{ d.remark }}</span>
</div>
</div>
<div v-else class="aps-sch-item-empty">暂无明细</div>
</div>
</div>
<div v-else-if="!loading" style="padding:40px;text-align:center;color:#909399;">
{{ hasQueried ? '该日期暂无待审核产需单' : '请选择日期查询' }}
</div>
@@ -217,9 +296,8 @@ export default {
// 待审核
pendingScheduleList: [],
expandedRowKeys: [],
expandDetailMap: {},
summaryText: '',
statusMap: { 1: '待审核', 2: '已接收', 3: '已驳回' },
// 已排产
scheduledItemList: [],
@@ -293,17 +371,6 @@ export default {
const list = res.rows || []
this.pendingScheduleList = list
// 构建展开映射
const map = {}
list.forEach(sch => {
map[sch.scheduleId] = (sch.detailList || []).map(d => ({
...d,
scheduleId: sch.scheduleId,
productType: sch.productType || d.productType || ''
}))
})
this.expandDetailMap = map
const totalWeight = list.reduce((sum, sch) => {
const details = sch.detailList || []
return sum + details.reduce((s, d) => s + (parseFloat(d.scheduleWeight) || 0), 0)
@@ -446,31 +513,15 @@ export default {
}).catch(() => {})
},
// ====== 下钻 ======
// ====== 待审核辅助方法 ======
// ====== 下钻 & 辅助方法 ======
scheduleTotalWeight(sch) {
const details = sch.detailList || []
const total = details.reduce((sum, d) => sum + (parseFloat(d.scheduleWeight) || 0), 0)
return total.toFixed(3)
},
handleScheduleClick(sch) {
// 父行单击展开/折叠
const idx = this.expandedRowKeys.indexOf(sch.scheduleId)
if (idx >= 0) {
this.expandedRowKeys.splice(idx, 1)
} else {
this.expandedRowKeys.push(sch.scheduleId)
}
},
handleExpandChange() {
// noop
},
handleRowClick(row) {
// 子行(明细行)点击查看来源订单
const sch = this.pendingScheduleList.find(s => s.scheduleId === row.scheduleId)
handleDetailClick(sch, detail) {
// 点击明细行查看来源订单
if (!sch || !sch.orderList || sch.orderList.length === 0) {
this.$message.warning('未找到关联订单')
return
@@ -637,4 +688,146 @@ export default {
::v-deep .el-tabs__item.is-active {
color: $aps-red-2 !important;
}
// ====== 待审核自定义列表 ======
.aps-sch-list {
display: flex;
flex-direction: column;
gap: 10px;
padding: 8px;
}
.aps-sch-item {
background: $aps-white;
border: 1px solid $aps-border;
border-radius: $aps-radius;
box-shadow: $aps-shadow-sm;
overflow: hidden;
}
.aps-sch-item-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 14px;
background: linear-gradient(135deg, $aps-silver-1 0%, #f8f9fb 100%);
border-bottom: 1px solid $aps-border;
}
.aps-sch-item-header-left {
display: flex;
align-items: center;
gap: 12px;
flex: 1;
min-width: 0;
}
.aps-sch-header-extra {
font-size: 12px;
color: $aps-text-muted;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
// 状态标签
.aps-status-tag {
display: inline-block;
font-size: 11px;
padding: 2px 8px;
border-radius: 3px;
font-weight: 500;
white-space: nowrap;
&.status-1 { background: #fff3e0; color: #e67e22; }
&.status-2 { background: #e8f5e9; color: #388e3c; }
&.status-3 { background: #fdecea; color: #e74c3c; }
}
// 产需单信息表
.req-info-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
td {
padding: 5px 10px;
border: 1px solid $aps-silver-mid;
vertical-align: middle;
}
.req-td-label {
width: 100px;
background: $aps-silver-1;
color: $aps-text-muted;
font-weight: 500;
text-align: right;
white-space: nowrap;
}
.req-td-value {
color: $aps-text;
}
}
.aps-sch-no {
color: $aps-red-2;
font-weight: 600;
font-size: 13px;
}
.aps-sch-item-actions {
display: flex;
gap: 6px;
flex-shrink: 0;
margin-left: 12px;
}
// 明细表
.aps-sch-item-details {
padding: 0;
}
.aps-sch-detail-header {
display: flex;
padding: 7px 14px;
background: $aps-silver-1;
border-bottom: 1px solid $aps-border;
font-size: 12px;
font-weight: 600;
color: $aps-text;
}
.aps-sch-detail-row {
display: flex;
padding: 7px 14px;
border-bottom: 1px solid $aps-silver-mid;
font-size: 12px;
color: $aps-text;
cursor: pointer;
transition: background 0.15s;
&:last-child {
border-bottom: none;
}
&:hover {
background: $aps-red-1;
}
}
.aps-sch-detail-col {
&.col-spec { flex: 1.2; min-width: 100px; }
&.col-material { flex: 0 0 80px; text-align: center; }
&.col-weight { flex: 0 0 90px; text-align: right; font-weight: 500; }
&.col-type { flex: 1; min-width: 80px; padding: 0 8px; }
&.col-remark { flex: 1; min-width: 80px; }
}
.aps-sch-item-empty {
padding: 20px;
text-align: center;
color: $aps-text-muted;
font-size: 12px;
}
</style>