feat: 实现产需单按工序步骤生成排产明细功能
1. 重构接收产需单接口,支持按配置工序步骤生成明细 2. 新增工艺、工艺步骤CRUD接口与管理页面 3. 新增工序选择组件 4. 优化产需单页面,增加历史记录功能 5. 为排产明细添加工序步骤名称展示
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
<el-button size="small" class="aps-btn-red" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||
<el-tabs v-model="activeTab" size="small" style="margin:0 0 0 16px;" @tab-click="handleQuery">
|
||||
<el-tab-pane label="待审核" name="pending" />
|
||||
<el-tab-pane label="已接收" name="accepted" />
|
||||
<el-tab-pane label="已排产" name="scheduled" />
|
||||
</el-tabs>
|
||||
<div v-if="summaryText" class="aps-sch-summary">
|
||||
@@ -161,6 +162,104 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 已接收 Tab -->
|
||||
<div v-loading="acceptedLoading" v-show="activeTab === 'accepted'" class="detail-card aps-sch-card">
|
||||
<div class="detail-card-header">
|
||||
<span>已接收产需单</span>
|
||||
<span v-if="acceptedScheduleList.length > 0" style="font-weight:normal;font-size:12px;opacity:0.8;">
|
||||
共 {{ acceptedScheduleList.length }} 个产需单
|
||||
</span>
|
||||
</div>
|
||||
<div class="detail-card-body" style="padding:0;">
|
||||
<div v-if="acceptedScheduleList.length > 0" class="aps-sch-list">
|
||||
<div v-for="sch in acceptedScheduleList" :key="sch.scheduleId" class="aps-sch-item">
|
||||
<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 status-2">已接收</span>
|
||||
<span class="aps-sch-header-extra">
|
||||
{{ sch.customerName }} · {{ sch.businessUser }} · {{ sch.deliveryCycle }}天
|
||||
</span>
|
||||
</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">{{ sch.businessUser }}</td>
|
||||
<td class="req-td-label">联系电话</td><td class="req-td-value">{{ sch.businessPhone }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="req-td-label">订货单位</td><td class="req-td-value">{{ sch.customerName }}</td>
|
||||
<td class="req-td-label">交货期(天)</td><td class="req-td-value">{{ sch.deliveryCycle }}</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" colspan="3">{{ sch.usePurpose }}</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 v-if="sch.otherTechReq">
|
||||
<td class="req-td-label">其他技术要求</td><td class="req-td-value" colspan="3">{{ sch.otherTechReq }}</td>
|
||||
</tr>
|
||||
<tr v-if="sch.paymentDesc">
|
||||
<td class="req-td-label">付款情况说明</td><td class="req-td-value" colspan="3">{{ sch.paymentDesc }}</td>
|
||||
</tr>
|
||||
<tr v-if="sch.remark">
|
||||
<td class="req-td-label">备注</td><td class="req-td-value" colspan="3">{{ sch.remark }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div v-if="(sch.detailList || []).length > 0" class="aps-sch-item-details">
|
||||
<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 v-for="(d, di) in sch.detailList" :key="di" class="aps-sch-detail-row" @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="!acceptedLoading" style="padding:40px;text-align:center;color:#909399;">
|
||||
{{ hasQueried ? '该日期暂无已接收产需单' : '请选择日期查询' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 已排产 Tab -->
|
||||
<div v-loading="schLoading" v-show="activeTab === 'scheduled'" class="detail-card aps-sch-card">
|
||||
<div class="detail-card-header">
|
||||
@@ -169,85 +268,73 @@
|
||||
<span v-if="scheduledItemList.length > 0" style="font-weight:normal;font-size:12px;opacity:0.8;">
|
||||
共 {{ scheduledItemList.length }} 条
|
||||
</span>
|
||||
<span v-if="selectedItems.length >= 2" style="margin-left: auto;">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="warning"
|
||||
icon="el-icon-link"
|
||||
@click.stop="handleMergePrepare"
|
||||
>
|
||||
合并选中项 ({{ selectedItems.length }})
|
||||
</el-button>
|
||||
</span>
|
||||
<span v-else style="margin-left: auto;">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="warning"
|
||||
icon="el-icon-link"
|
||||
disabled
|
||||
>
|
||||
合并选中项
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div element-loading-text="正在加载已排产数据..." class="detail-card-body" style="padding:0;">
|
||||
<el-table
|
||||
v-if="scheduledItemList.length > 0"
|
||||
ref="scheduledTable"
|
||||
:data="scheduledItemList"
|
||||
border
|
||||
size="small"
|
||||
class="aps-table"
|
||||
:row-class-name="getItemRowClassName"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<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="prodDate" width="110" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="工序类型" prop="actionId" width="100" align="center" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
{{ getActionIdName(scope.row.actionId) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排产状态" prop="scheduleStatus" width="90" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span class="aps-status-tag" :class="'status-' + (scope.row.scheduleStatus || 1)">{{ statusMap[scope.row.scheduleStatus] || '未知' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格" prop="spec" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="材质" prop="material" width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="排产吨数" prop="scheduleWeight" width="100" align="right" show-overflow-tooltip />
|
||||
<el-table-column label="品名项" prop="productItem" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="品名" prop="productType" min-width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="订货单位" prop="customerName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="业务员" prop="businessUser" width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="联系电话" prop="businessPhone" width="110" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="交货期(天)" prop="deliveryCycle" width="100" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="产品用途" prop="usePurpose" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="厚度公差" prop="thicknessTolerance" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="宽度公差" prop="widthTolerance" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="表面质量" prop="surfaceQuality" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="表面处理" prop="surfaceTreatment" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="内径尺寸" prop="innerDiameter" width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="外径要求" prop="outerDiameter" width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="包装要求" prop="packReq" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="切边要求" prop="cutEdgeReq" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="单件重量" prop="singleCoilWeight" width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="交货重量偏差" prop="weightDeviation" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column label="其他技术要求" prop="otherTechReq" min-width="130" show-overflow-tooltip />
|
||||
<el-table-column label="付款情况说明" prop="paymentDesc" min-width="130" show-overflow-tooltip />
|
||||
<el-table-column label="单行排产备注" prop="rowRemark" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="备注" prop="remark" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<div style="display:flex; justify-content:center; gap:0;">
|
||||
<el-button type="text" size="small" style="color:#409EFF;padding:0 6px;" @click="handleEditScheduled(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="small" style="color:#ff4d4f;padding:0 6px;" @click="handleDeleteScheduled(scope.row)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template v-if="scheduledItemList.length > 0">
|
||||
<!-- 步骤工序 Tab -->
|
||||
<div class="aps-step-tabs">
|
||||
<span
|
||||
v-for="tab in scheduledStepTabs"
|
||||
:key="tab"
|
||||
class="aps-step-tab"
|
||||
:class="{ 'aps-step-tab-active': scheduledStepTab === tab }"
|
||||
@click="scheduledStepTab = tab"
|
||||
>
|
||||
{{ tab }}
|
||||
<span class="aps-step-tab-count">{{ scheduledItemList.filter(i => normalizeStepName(i.stepName) === tab).length }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
ref="scheduledTable"
|
||||
:data="currentStepItems"
|
||||
border
|
||||
size="small"
|
||||
class="aps-table"
|
||||
>
|
||||
<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="stepName" width="120" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="排产状态" prop="scheduleStatus" width="90" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span class="aps-status-tag" :class="'status-' + (scope.row.scheduleStatus || 1)">{{ statusMap[scope.row.scheduleStatus] || '未知' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格" prop="spec" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="材质" prop="material" width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="排产吨数" prop="scheduleWeight" width="100" align="right" show-overflow-tooltip />
|
||||
<el-table-column label="品名项" prop="productItem" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="品名" prop="productType" min-width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="订货单位" prop="customerName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="业务员" prop="businessUser" width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="联系电话" prop="businessPhone" width="110" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="交货期(天)" prop="deliveryCycle" width="100" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="产品用途" prop="usePurpose" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="厚度公差" prop="thicknessTolerance" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="宽度公差" prop="widthTolerance" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="表面质量" prop="surfaceQuality" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="表面处理" prop="surfaceTreatment" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="内径尺寸" prop="innerDiameter" width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="外径要求" prop="outerDiameter" width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="包装要求" prop="packReq" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="切边要求" prop="cutEdgeReq" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="单件重量" prop="singleCoilWeight" width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="交货重量偏差" prop="weightDeviation" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column label="其他技术要求" prop="otherTechReq" min-width="130" show-overflow-tooltip />
|
||||
<el-table-column label="付款情况说明" prop="paymentDesc" min-width="130" show-overflow-tooltip />
|
||||
<el-table-column label="单行排产备注" prop="rowRemark" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="备注" prop="remark" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<div style="display:flex; justify-content:center; gap:0;">
|
||||
<el-button type="text" size="small" style="color:#409EFF;padding:0 6px;" @click="handleEditScheduled(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="small" style="color:#ff4d4f;padding:0 6px;" @click="handleDeleteScheduled(scope.row)">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
<div v-else-if="!schLoading" style="padding:40px;text-align:center;color:#909399;">
|
||||
{{ hasQueried ? '该日期暂无已排产数据' : '请选择日期查询' }}
|
||||
</div>
|
||||
@@ -493,149 +580,48 @@
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 合并排产明细对话框 -->
|
||||
<!-- 接收产需单弹窗 - 配置工序 -->
|
||||
<el-dialog
|
||||
title="合并排产明细"
|
||||
:visible.sync="mergeDialogVisible"
|
||||
width="850px"
|
||||
title="接收产需单 - 配置工序"
|
||||
:visible.sync="receiveDialogVisible"
|
||||
width="900px"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<div style="margin-bottom:12px;font-size:13px;color:#e67e22;">
|
||||
选中 {{ mergeForm.itemCount }} 条明细,请选择一个作为合并模板,下方字段将自动填充,您可修改后确认合并。
|
||||
请为每条明细配置工序,所有明细配置完成后才能接收。
|
||||
</div>
|
||||
|
||||
<!-- 选择模板 -->
|
||||
<el-table :data="mergeSourceRows" border size="small" style="margin-bottom:12px;" @row-click="pickMergeTemplate">
|
||||
<el-table-column width="50" align="center">
|
||||
|
||||
<el-table :data="receiveDetailList" border size="small" class="aps-table" max-height="400">
|
||||
<el-table-column label="规格" prop="spec" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="材质" prop="material" width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="排产吨数" prop="scheduleWeight" width="100" align="right" />
|
||||
<el-table-column label="品名" prop="productType" min-width="90" align="center" show-overflow-tooltip />
|
||||
<el-table-column label="配置工序" min-width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-radio v-model="mergeTemplateIndex" :label="scope.$index" @click.native.stop />
|
||||
<ProcessSelect
|
||||
v-model="scope.row.processId"
|
||||
placeholder="请选择工序"
|
||||
@change="(val, data) => handleReceiveProcessChange(scope.row, val, data)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="工序步骤" min-width="300">
|
||||
<template slot-scope="scope">
|
||||
<div v-if="scope.row.stepList && scope.row.stepList.length > 0" class="receive-steps-flow">
|
||||
<template v-for="(step, index) in scope.row.stepList">
|
||||
<span :key="step.stepId" class="receive-step-tag">{{ step.stepName }}</span>
|
||||
<span v-if="index < scope.row.stepList.length - 1" :key="'arrow-' + index" class="receive-step-arrow">→</span>
|
||||
</template>
|
||||
</div>
|
||||
<span v-else style="color:#909399;font-size:12px;">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排产单号" prop="scheduleNo" min-width="130" show-overflow-tooltip />
|
||||
<el-table-column label="规格" prop="spec" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="材质" prop="material" width="80" 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>
|
||||
|
||||
<!-- 合并表单 -->
|
||||
<el-form ref="mergeFormRef" :model="mergeForm" label-width="110px" size="small">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="排产单号"><el-input v-model="mergeForm.scheduleNo" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工序类型">
|
||||
<el-select v-model="mergeForm.actionId" placeholder="请选择工序类型" clearable filterable style="width:100%">
|
||||
<el-option v-for="p in processOptions" :key="p.actionId" :label="p.name" :value="p.actionId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="订货单位"><el-input v-model="mergeForm.customerName" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="规格"><el-input v-model="mergeForm.spec" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="材质"><el-input v-model="mergeForm.material" /></el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="排产吨数(累加)">
|
||||
<el-input-number v-model="mergeForm.scheduleWeight" :min="0" :precision="3" :controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="品名"><el-input v-model="mergeForm.productType" /></el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="品名项"><el-input v-model="mergeForm.productItem" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="业务员"><el-input v-model="mergeForm.businessUser" /></el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话"><el-input v-model="mergeForm.businessPhone" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="交货期(天)">
|
||||
<el-input-number v-model="mergeForm.deliveryCycle" :min="0" :controls="false" style="width:100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="产品用途"><el-input v-model="mergeForm.usePurpose" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="厚度公差"><el-input v-model="mergeForm.thicknessTolerance" /></el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="宽度公差"><el-input v-model="mergeForm.widthTolerance" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="表面质量"><el-input v-model="mergeForm.surfaceQuality" /></el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="表面处理"><el-input v-model="mergeForm.surfaceTreatment" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="内径尺寸"><el-input v-model="mergeForm.innerDiameter" /></el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="外径要求"><el-input v-model="mergeForm.outerDiameter" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="包装要求"><el-input v-model="mergeForm.packReq" /></el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="切边要求"><el-input v-model="mergeForm.cutEdgeReq" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="单件重量"><el-input v-model="mergeForm.singleCoilWeight" /></el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="交货重量偏差"><el-input v-model="mergeForm.weightDeviation" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="其他技术要求"><el-input v-model="mergeForm.otherTechReq" /></el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="付款情况说明"><el-input v-model="mergeForm.paymentDesc" /></el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="备注"><el-input v-model="mergeForm.remark" /></el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div style="margin-top:8px;font-size:12px;color:#909399;">
|
||||
合并后 schedule_detail_ids:{{ mergeForm.scheduleDetailIds }}
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button :loading="mergeBtnLoading" type="warning" @click="confirmMerge">确 定 合 并</el-button>
|
||||
<el-button @click="mergeDialogVisible = false">取 消</el-button>
|
||||
<el-button :loading="receiveBtnLoading" type="primary" :disabled="!canConfirmReceive" @click="confirmReceive">确 定 接 收</el-button>
|
||||
<el-button @click="receiveDialogVisible = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
@@ -651,13 +637,14 @@ import {
|
||||
listScheduleItem,
|
||||
updateScheduleItem,
|
||||
delScheduleItem,
|
||||
receiveScheduleItem,
|
||||
mergeScheduleItem
|
||||
receiveScheduleItem
|
||||
} from '@/api/aps/schedule'
|
||||
import { PROCESSES } from '@/utils/meta'
|
||||
import ProcessSelect from '@/components/KLPService/ProcessSelect/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'ApsSchedule',
|
||||
components: { ProcessSelect },
|
||||
data() {
|
||||
const today = new Date()
|
||||
const y = today.getFullYear()
|
||||
@@ -676,26 +663,13 @@ export default {
|
||||
statusMap: { 1: '待审核', 2: '已接收', 3: '已驳回' },
|
||||
processOptions: PROCESSES,
|
||||
|
||||
// 已接收
|
||||
acceptedScheduleList: [],
|
||||
acceptedLoading: false,
|
||||
|
||||
// 已排产
|
||||
scheduledItemList: [],
|
||||
selectedItems: [],
|
||||
sourceColorMap: {},
|
||||
|
||||
// 合并对话框
|
||||
mergeDialogVisible: false,
|
||||
mergeBtnLoading: false,
|
||||
mergeTemplateIndex: 0,
|
||||
mergeSourceRows: [],
|
||||
mergeForm: {
|
||||
itemCount: 0, scheduleNo: '', actionId: '', customerName: '', spec: '', material: '',
|
||||
scheduleWeight: 0, productType: '', productItem: '', businessUser: '',
|
||||
businessPhone: '', deliveryCycle: undefined, usePurpose: '',
|
||||
thicknessTolerance: '', widthTolerance: '', surfaceQuality: '',
|
||||
surfaceTreatment: '', innerDiameter: '', outerDiameter: '',
|
||||
packReq: '', cutEdgeReq: '', singleCoilWeight: '',
|
||||
weightDeviation: '', otherTechReq: '', paymentDesc: '',
|
||||
remark: '', scheduleDetailIds: ''
|
||||
},
|
||||
scheduledStepTab: '',
|
||||
|
||||
// 驳回
|
||||
rejectDialogVisible: false,
|
||||
@@ -714,14 +688,37 @@ export default {
|
||||
|
||||
// 下钻
|
||||
drillDialogVisible: false,
|
||||
drillOrder: null
|
||||
drillOrder: null,
|
||||
|
||||
// 接收产需单弹窗
|
||||
receiveDialogVisible: false,
|
||||
receiveBtnLoading: false,
|
||||
receiveScheduleId: null,
|
||||
receiveDetailList: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeTab() {
|
||||
this.selectedItems = []
|
||||
computed: {
|
||||
canConfirmReceive() {
|
||||
if (!this.receiveDetailList || this.receiveDetailList.length === 0) return false
|
||||
return this.receiveDetailList.every(d => d.processId)
|
||||
},
|
||||
// 已排产按步骤分组:去掉括号及括号内文字
|
||||
scheduledStepTabs() {
|
||||
const names = this.scheduledItemList
|
||||
.map(item => this.normalizeStepName(item.stepName))
|
||||
.filter(Boolean)
|
||||
return [...new Set(names)]
|
||||
},
|
||||
// 当前选中的步骤tab对应的数据
|
||||
currentStepItems() {
|
||||
if (!this.scheduledStepTab) return this.scheduledItemList
|
||||
const tab = this.scheduledStepTab
|
||||
return this.scheduledItemList.filter(
|
||||
item => this.normalizeStepName(item.stepName) === tab
|
||||
)
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
created() {
|
||||
this.handleQuery()
|
||||
},
|
||||
@@ -775,6 +772,8 @@ export default {
|
||||
this.hasQueried = true
|
||||
if (this.activeTab === 'pending') {
|
||||
this.queryPending()
|
||||
} else if (this.activeTab === 'accepted') {
|
||||
this.queryAccepted()
|
||||
} else {
|
||||
this.queryScheduled()
|
||||
}
|
||||
@@ -808,25 +807,82 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
// ====== 已接收 ======
|
||||
queryAccepted() {
|
||||
this.acceptedLoading = true
|
||||
this.acceptedScheduleList = []
|
||||
|
||||
listRequirement({
|
||||
prodDate: this.queryDate,
|
||||
scheduleStatus: 2,
|
||||
pageNum: 1,
|
||||
pageSize: 999
|
||||
}).then(res => {
|
||||
this.acceptedScheduleList = res.rows || []
|
||||
const totalCount = this.acceptedScheduleList.reduce((sum, sch) => sum + (sch.detailList || []).length, 0)
|
||||
this.summaryText = `共 ${this.acceptedScheduleList.length} 个已接收产需单,${totalCount} 条明细`
|
||||
}).catch(() => {
|
||||
this.acceptedScheduleList = []
|
||||
this.summaryText = ''
|
||||
}).finally(() => {
|
||||
this.acceptedLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
handleAccept(sch) {
|
||||
const details = sch.detailList || []
|
||||
if (details.length === 0) {
|
||||
this.$message.warning('该产需单无可排产的明细')
|
||||
return
|
||||
}
|
||||
this.$confirm(
|
||||
`确认接收产需单「${sch.scheduleNo}」的全部排产明细吗?共 ${details.length} 条明细`,
|
||||
'提示',
|
||||
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
|
||||
).then(() => {
|
||||
this.$message.info('正在处理接收...')
|
||||
receiveScheduleItem(sch.scheduleId).then(() => {
|
||||
this.$modal.msgSuccess('接收成功,排产明细已写入')
|
||||
this.queryPending()
|
||||
}).catch(() => {
|
||||
this.$modal.msgError('接收失败')
|
||||
})
|
||||
}).catch(() => {})
|
||||
// 初始化接收明细列表,为每条明细添加 processId 和 stepList 字段
|
||||
this.receiveScheduleId = sch.scheduleId
|
||||
this.receiveDetailList = details.map(d => ({
|
||||
...d,
|
||||
processId: undefined,
|
||||
stepList: []
|
||||
}))
|
||||
this.receiveDialogVisible = true
|
||||
},
|
||||
|
||||
handleReceiveProcessChange(row, processId, processData) {
|
||||
if (processData && processData.stepList) {
|
||||
row.stepList = processData.stepList
|
||||
} else {
|
||||
row.stepList = []
|
||||
}
|
||||
},
|
||||
|
||||
confirmReceive() {
|
||||
// 验证所有明细都配置了工序
|
||||
const unconfigured = this.receiveDetailList.filter(d => !d.processId)
|
||||
if (unconfigured.length > 0) {
|
||||
this.$message.warning(`还有 ${unconfigured.length} 条明细未配置工序,请为所有明细配置工序`)
|
||||
return
|
||||
}
|
||||
// 构建接收数据,传递每条明细的 processId 和 stepList
|
||||
const receiveData = {
|
||||
scheduleId: this.receiveScheduleId,
|
||||
detailProcessList: this.receiveDetailList.map(d => ({
|
||||
scheduleDetailId: d.scheduleDetailId || d.scheduleDetailIds,
|
||||
processId: d.processId,
|
||||
stepList: (d.stepList || []).map(s => ({
|
||||
stepId: s.stepId,
|
||||
stepOrder: s.stepOrder,
|
||||
stepName: s.stepName
|
||||
}))
|
||||
}))
|
||||
}
|
||||
this.receiveBtnLoading = true
|
||||
receiveScheduleItem(receiveData).then(() => {
|
||||
this.$modal.msgSuccess('接收成功,排产明细已写入')
|
||||
this.receiveDialogVisible = false
|
||||
this.queryPending()
|
||||
}).catch(() => {
|
||||
this.$modal.msgError('接收失败')
|
||||
}).finally(() => {
|
||||
this.receiveBtnLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
handleReject(sch) {
|
||||
@@ -864,16 +920,14 @@ export default {
|
||||
queryScheduled() {
|
||||
this.schLoading = true
|
||||
this.scheduledItemList = []
|
||||
this.sourceColorMap = {}
|
||||
this.selectedItems = []
|
||||
this.scheduledStepTab = ''
|
||||
|
||||
listScheduleItem({ prodDate: this.queryDate, pageNum: 1, pageSize: 999 }).then(res => {
|
||||
this.scheduledItemList = (res.rows || []).sort((a, b) => (a.scheduleNo || '').localeCompare(b.scheduleNo || ''))
|
||||
try {
|
||||
this.sourceColorMap = this.buildGroupColorMap(this.scheduledItemList)
|
||||
} catch (e) {
|
||||
console.error('buildGroupColorMap error:', e)
|
||||
this.sourceColorMap = {}
|
||||
// 默认选中第一个步骤tab
|
||||
const tabs = this.scheduledStepTabs
|
||||
if (tabs.length > 0) {
|
||||
this.scheduledStepTab = tabs[0]
|
||||
}
|
||||
const totalWeight = this.scheduledItemList.reduce((sum, d) => {
|
||||
const w = parseFloat(d.scheduleWeight)
|
||||
@@ -934,98 +988,6 @@ export default {
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
// ====== 合并 ======
|
||||
handleSelectionChange(rows) {
|
||||
this.selectedItems = rows
|
||||
},
|
||||
|
||||
getItemRowClassName({ row }) {
|
||||
const key = row.scheduleNo
|
||||
if (!key) return ''
|
||||
const colorIndex = this.sourceColorMap[key]
|
||||
return colorIndex !== undefined ? `merge-source-${colorIndex}` : ''
|
||||
},
|
||||
|
||||
buildGroupColorMap(list) {
|
||||
const map = {}
|
||||
let colorIdx = 0
|
||||
list.forEach(item => {
|
||||
const key = item.scheduleNo
|
||||
if (!key) return
|
||||
if (!(key in map)) {
|
||||
map[key] = colorIdx % 5
|
||||
colorIdx++
|
||||
}
|
||||
})
|
||||
return map
|
||||
},
|
||||
|
||||
handleMergePrepare() {
|
||||
if (this.selectedItems.length < 2) {
|
||||
this.$message.warning('请至少选择2条排产明细进行合并')
|
||||
return
|
||||
}
|
||||
this.mergeSourceRows = [...this.selectedItems]
|
||||
this.mergeTemplateIndex = 0
|
||||
this.pickMergeTemplate(this.mergeSourceRows[0])
|
||||
this.mergeDialogVisible = true
|
||||
},
|
||||
|
||||
pickMergeTemplate(row) {
|
||||
const idx = this.mergeSourceRows.indexOf(row)
|
||||
if (idx >= 0) this.mergeTemplateIndex = idx
|
||||
this.mergeForm = {
|
||||
itemCount: this.mergeSourceRows.length,
|
||||
scheduleNo: row.scheduleNo || '',
|
||||
actionId: row.actionId != null ? Number(row.actionId) : '',
|
||||
customerName: row.customerName || '',
|
||||
spec: row.spec || '',
|
||||
material: row.material || '',
|
||||
scheduleWeight: this.mergeSourceRows.reduce((sum, r) => sum + (parseFloat(r.scheduleWeight) || 0), 0),
|
||||
productType: row.productType || '',
|
||||
productItem: row.productItem || '',
|
||||
businessUser: row.businessUser || '',
|
||||
businessPhone: row.businessPhone || '',
|
||||
deliveryCycle: row.deliveryCycle,
|
||||
usePurpose: row.usePurpose || '',
|
||||
thicknessTolerance: row.thicknessTolerance || '',
|
||||
widthTolerance: row.widthTolerance || '',
|
||||
surfaceQuality: row.surfaceQuality || '',
|
||||
surfaceTreatment: row.surfaceTreatment || '',
|
||||
innerDiameter: row.innerDiameter || '',
|
||||
outerDiameter: row.outerDiameter || '',
|
||||
packReq: row.packReq || '',
|
||||
cutEdgeReq: row.cutEdgeReq || '',
|
||||
singleCoilWeight: row.singleCoilWeight || '',
|
||||
weightDeviation: row.weightDeviation || '',
|
||||
otherTechReq: row.otherTechReq || '',
|
||||
paymentDesc: row.paymentDesc || '',
|
||||
remark: row.remark || '',
|
||||
scheduleDetailIds: this.mergeSourceRows.map(r => r.scheduleDetailIds || '').filter(Boolean).join(',')
|
||||
}
|
||||
},
|
||||
|
||||
confirmMerge() {
|
||||
this.mergeBtnLoading = true
|
||||
const ids = this.mergeSourceRows.map(r => r.scheduleId)
|
||||
const mergedBo = {
|
||||
...this.mergeForm,
|
||||
prodDate: this.queryDate,
|
||||
scheduleStatus: 2
|
||||
}
|
||||
delete mergedBo.itemCount
|
||||
mergeScheduleItem({ ids, mergedBo }).then(() => {
|
||||
this.$modal.msgSuccess(`合并成功:${ids.length} 条明细合并为 1 条`)
|
||||
this.mergeDialogVisible = false
|
||||
this.selectedItems = []
|
||||
this.queryScheduled()
|
||||
}).catch(() => {
|
||||
this.$modal.msgError('合并失败')
|
||||
}).finally(() => {
|
||||
this.mergeBtnLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// ====== 下钻 & 辅助方法 ======
|
||||
scheduleTotalWeight(sch) {
|
||||
const details = sch.detailList || []
|
||||
@@ -1038,6 +1000,12 @@ export default {
|
||||
return p ? p.name : (actionId || '')
|
||||
},
|
||||
|
||||
// 去掉步骤名称中的括号及括号内文字:镀锌(毛化)=> 镀锌
|
||||
normalizeStepName(name) {
|
||||
if (!name) return ''
|
||||
return name.replace(/[((][^))]*[))]/g, '').trim()
|
||||
},
|
||||
|
||||
handleDetailClick(sch, detail) {
|
||||
// 点击明细行查看来源订单
|
||||
if (!sch || !sch.orderList || sch.orderList.length === 0) {
|
||||
@@ -1350,20 +1318,85 @@ export default {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
// ====== 合并候选行颜色高亮(同一源排产单 → 同色) ======
|
||||
::v-deep .el-table__body tr.merge-source-0 > td {
|
||||
background-color: #f0f5ff !important;
|
||||
// ====== 接收弹窗步骤展示 ======
|
||||
.receive-steps-flow {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
::v-deep .el-table__body tr.merge-source-1 > td {
|
||||
background-color: #f6ffed !important;
|
||||
|
||||
.receive-step-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
background: $aps-silver-1;
|
||||
border: 1px solid $aps-silver-mid;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
color: $aps-text;
|
||||
}
|
||||
::v-deep .el-table__body tr.merge-source-2 > td {
|
||||
background-color: #fff7e6 !important;
|
||||
|
||||
.receive-step-arrow {
|
||||
color: $aps-red-2;
|
||||
font-size: 14px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
::v-deep .el-table__body tr.merge-source-3 > td {
|
||||
background-color: #f9f0ff !important;
|
||||
|
||||
// ====== 已排产步骤工序 Tab ======
|
||||
.aps-step-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 8px 12px;
|
||||
gap: 6px;
|
||||
background: $aps-silver-1;
|
||||
border-bottom: 1px solid $aps-border;
|
||||
}
|
||||
::v-deep .el-table__body tr.merge-source-4 > td {
|
||||
background-color: #fff0f6 !important;
|
||||
|
||||
.aps-step-tab {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 4px 14px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: $aps-text-muted;
|
||||
background: $aps-white;
|
||||
border: 1px solid $aps-silver-mid;
|
||||
border-radius: $aps-radius;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
color: $aps-red-2;
|
||||
border-color: $aps-red-2;
|
||||
}
|
||||
}
|
||||
|
||||
.aps-step-tab-active {
|
||||
color: #fff;
|
||||
background: $aps-red-2;
|
||||
border-color: $aps-red-2;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.aps-step-tab-count {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 18px;
|
||||
height: 16px;
|
||||
padding: 0 5px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
border-radius: 8px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
|
||||
.aps-step-tab-active & {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user