Files
klp-oa/klp-ui/src/views/wms/coil/panels/do.vue
砂糖 8d73342e9e feat(wms): 添加镀锌纵剪分条原料库支持并扩展分条功能
扩展分条功能以支持更多工序类型,包括镀锌、脱脂、拉矫平整等。添加镀锌纵剪分条原料库选项,并改进分条按钮样式和操作流程。同时调整时间格式显示为更易读的形式。

新增镀铬工序分条支持,优化分条操作界面显示当前工序名称。修复分条列表加载逻辑,确保在操作类型有效时才进行加载。添加新的分条操作页面用于管理分条任务。
2026-03-11 14:52:59 +08:00

1428 lines
52 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container acid-do-container">
<el-row :gutter="20">
<!-- 左侧物料列表 -->
<el-col :span="12">
<div class="section-card material-section">
<div class="section-header">
<!-- 当tab数量多余一个时额外渲染一个el-tab-pane. 当tab切换时切换对应的物料列表 -->
<el-tabs v-if="tabs.length > 1" v-model="currentTab" type="card" class="material-tabs">
<el-tab-pane v-for="(tab, index) in tabs" :key="tab.value" :label="tab.label"
:name="tab.value"></el-tab-pane>
</el-tabs>
<h3 class="section-title" v-else>待领物料列表</h3>
<el-button size="mini" icon="el-icon-refresh" @click="getMaterialCoil">刷新</el-button>
</div>
<!-- 搜索栏 -->
<el-form :model="materialQueryParams" ref="materialQueryForm" size="small" :inline="true" class="query-form">
<el-form-item label="入场钢卷号" prop="enterCoilNo">
<el-input v-model="materialQueryParams.enterCoilNo" placeholder="请输入入场钢卷号" clearable
@keyup.enter.native="handleMaterialQuery" style="width: 150px;" />
</el-form-item>
<el-form-item label="当前钢卷号" prop="currentCoilNo">
<el-input v-model="materialQueryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
@keyup.enter.native="handleMaterialQuery" style="width: 150px;" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleMaterialQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetMaterialQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 物料卡片列表 -->
<div v-loading="materialLoading" class="card-grid-container">
<div v-if="materialCoilList.length === 0" class="empty-state">
<i class="el-icon-box"></i>
<p>暂无待领物料</p>
</div>
<div v-for="(item, index) in materialCoilList" :key="item.coilId || index" class="material-card"
:style="{ border: item.abnormalCount > 0 ? '1px solid red' : ' 1px solid #e4e7ed' }">
<div class="card-header">
<div class="header-left">
<current-coil-no :current-coil-no="item.currentCoilNo"></current-coil-no>
<!-- <span class="material-type">{{ item.materialType || '原料' }}</span> -->
<el-popover v-if="item.rawMaterial || item.product" placement="top" width="280" trigger="hover"
popper-class="material-params-popover">
<div class="material-params-content">
<div class="params-title">
{{ item.itemType === 'raw_material' ? (item.rawMaterial && item.rawMaterial.rawMaterialName ||
'—') : (item.product && item.product.productName || '—') }}
</div>
<div class="params-list">
<div class="param-item" v-if="item.itemType === 'raw_material' && item.rawMaterial">
<div class="param-row" v-if="item.rawMaterial.rawMaterialCode">
<span class="param-label">编号</span>
<span class="param-value">{{ item.rawMaterial.rawMaterialCode }}</span>
</div>
<div class="param-row" v-if="item.rawMaterial.specification">
<span class="param-label">规格</span>
<span class="param-value">{{ item.rawMaterial.specification }}</span>
</div>
<div class="param-row" v-if="item.rawMaterial.material">
<span class="param-label">材质</span>
<span class="param-value">{{ item.rawMaterial.material }}</span>
</div>
<div class="param-row" v-if="item.rawMaterial.surfaceTreatment">
<span class="param-label">表面处理</span>
<span class="param-value">{{ item.rawMaterial.surfaceTreatment }}</span>
</div>
<div class="param-row" v-if="item.rawMaterial.zincLayer">
<span class="param-label">镀层质量</span>
<span class="param-value">{{ item.rawMaterial.zincLayer }}</span>
</div>
<div class="param-row" v-if="item.rawMaterial.manufacturer">
<span class="param-label">厂家</span>
<span class="param-value">{{ item.rawMaterial.manufacturer }}</span>
</div>
</div>
<div class="param-item" v-else-if="item.itemType === 'product' && item.product">
<div class="param-row" v-if="item.product.productCode">
<span class="param-label">编号</span>
<span class="param-value">{{ item.product.productCode }}</span>
</div>
<div class="param-row" v-if="item.product.specification">
<span class="param-label">规格</span>
<span class="param-value">{{ item.product.specification }}</span>
</div>
<div class="param-row" v-if="item.product.material">
<span class="param-label">材质</span>
<span class="param-value">{{ item.product.material }}</span>
</div>
<div class="param-row" v-if="item.product.surfaceTreatment">
<span class="param-label">表面处理</span>
<span class="param-value">{{ item.product.surfaceTreatment }}</span>
</div>
<div class="param-row" v-if="item.product.zincLayer">
<span class="param-label">镀层质量</span>
<span class="param-value">{{ item.product.zincLayer }}</span>
</div>
<div class="param-row" v-if="item.product.manufacturer">
<span class="param-label">厂家</span>
<span class="param-value">{{ item.product.manufacturer }}</span>
</div>
</div>
<div class="param-divider"></div>
<div class="param-item">
<div class="param-row" v-if="item.qualityStatus">
<span class="param-label">质量状态</span>
<span class="param-value">{{ item.qualityStatus }}</span>
</div>
<div class="param-row" v-if="item.trimmingRequirement">
<span class="param-label">切边要求</span>
<span class="param-value">{{ item.trimmingRequirement }}</span>
</div>
<div class="param-row" v-if="item.packingStatus">
<span class="param-label">打包状态</span>
<span class="param-value">{{ item.packingStatus }}</span>
</div>
<div class="param-row" v-if="item.packagingRequirement">
<span class="param-label">包装要求</span>
<span class="param-value">{{ item.packagingRequirement }}</span>
</div>
<div class="param-row" v-if="item.grossWeight">
<span class="param-label">毛重</span>
<span class="param-value">{{ item.grossWeight }}t</span>
</div>
<div class="param-row" v-if="item.netWeight">
<span class="param-label">净重</span>
<span class="param-value">{{ item.netWeight }}t</span>
</div>
<div class="param-row" v-if="item.length">
<span class="param-label">长度</span>
<span class="param-value">{{ item.length }}</span>
</div>
<div class="param-row" v-if="item.temperGrade">
<span class="param-label">调制度</span>
<span class="param-value">{{ item.temperGrade }}</span>
</div>
<div class="param-row" v-if="item.coatingType">
<span class="param-label">镀层种类</span>
<span class="param-value">{{ item.coatingType }}</span>
</div>
<div class="param-row" v-if="item.team">
<span class="param-label">班组</span>
<span class="param-value">{{ item.team }}</span>
</div>
<div class="param-row" v-if="item.updateTime">
<span class="param-label">更新时间</span>
<span class="param-value">{{ parseTime(item.updateTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</div>
<div class="param-row" v-if="item.updateBy">
<span class="param-label">更新人</span>
<span class="param-value">{{ item.updateBy }}</span>
</div>
<div class="param-row" v-if="item.remark">
<span class="param-label">备注</span>
<span class="param-value">{{ item.remark }}</span>
</div>
</div>
</div>
</div>
<i slot="reference" class="el-icon-setting param-icon"></i>
</el-popover>
<i class="el-icon-view param-icon" @click="handlePreviewLabel(item)" title="查看标签"></i>
<!-- <el-button style="margin-left: 0px; padding: 4px !important;" type="text" size="mini" @click="handlePreviewLabel(item)" title="查看标签">预览</el-button> -->
<el-button v-loading="buttonLoading" style="margin-left: 0px; padding: 4px !important;" type="text"
size="mini" @click="handlePrintLabel(item)" title="打印标签">打印</el-button>
</div>
</div>
<div class="card-body" style="position: relative;">
<div class="info-list">
<div class="info-item">
<span class="info-label">入场</span>
<span class="info-value" :title="item.enterCoilNo">{{ item.enterCoilNo || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">厂家</span>
<span class="info-value" :title="item.supplierCoilNo">{{ item.supplierCoilNo || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">库位</span>
<span class="info-value" :title="item.warehouseName">{{ item.warehouseName || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">库区</span>
<span class="info-value" :title="item.actualWarehouseName">{{ item.actualWarehouseName || '—'
}}</span>
</div>
<div class="info-item">
<span class="info-label">重量</span>
<span class="info-value">{{ item.netWeight || '—' }}t</span>
</div>
</div>
</div>
<div class="card-footer">
<el-button v-if="useSpecialSplit" :style="splitButtonStyle" icon="el-icon-scissors" size="mini"
@click="handleStartSplit(item)" :loading="buttonLoading" class="action-btn">加工</el-button>
<el-button v-else type="primary" icon="el-icon-check" size="mini" @click="handlePickMaterial(item)"
:loading="buttonLoading" class="action-btn">领料</el-button>
<el-button type="danger" icon="el-icon-alarm-clock" :plain="item.abnormalCount == 0" size="mini"
@click="handleAddAbnormal(item)" :loading="buttonLoading" class="action-btn">
异常
<span v-if="item.abnormalCount > 0">({{ item.abnormalCount }})</span>
</el-button>
</div>
</div>
</div>
<!-- 分页 -->
<pagination v-show="materialTotal > 0" :total="materialTotal" :page.sync="materialQueryParams.pageNum"
:limit.sync="materialQueryParams.pageSize" @pagination="getMaterialCoil" />
</div>
</el-col>
<!-- 右侧待操作列表 -->
<el-col :span="12">
<div class="section-card action-section" v-if="useSpecialSplit" style="margin-bottom: 20px;"
v-loading="stepSpilt.loading">
<div class="section-header ">
<h3 class="section-title">进行中的{{ label }}</h3>
<el-button size="mini" icon="el-icon-refresh" @click="getStepSplitList">刷新</el-button>
</div>
<div v-if="stepSpilt.list.length > 0" style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
<div v-for="(item, index) in stepSpilt.list" :key="item.coilId || index"
style="width: 18rem; background-color: #ffffff; border-bottom-left-radius: 0.5rem; border-bottom-right-radius: 0.5rem; border-top: 4px solid #2bf; padding-left: 1rem; padding-right: 1rem; padding-top: 1.25rem; padding-bottom: 1.25rem; display: flex; flex-direction: column; justify-content: space-around; box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);">
<p
style="font-size: 1.125rem; line-height: 1.75rem; font-weight: 700; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';">
{{ item.currentCoilNo || 'N/A' }}
</p>
<div style="padding-top: 0.75rem; padding-bottom: 0.75rem;">
<p style="color: #9ca3af; font-size: 0.875rem; line-height: 1.25rem;">
<div class="info-item">
<span class="info-label">入场</span>
<span class="info-value" :title="item.enterCoilNo">{{ item.enterCoilNo || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">厂家</span>
<span class="info-value" :title="item.supplierCoilNo">{{ item.supplierCoilNo || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">品名</span>
<span class="info-value">
<el-popover placement="top" width="280" trigger="hover" popper-class="material-params-popover">
<div class="material-params-content">
<div class="params-list">
<div class="param-item">
<div class="param-row" v-if="item.specification">
<span class="param-label">规格</span>
<span class="param-value">{{ item.specification }}</span>
</div>
<div class="param-row" v-if="item.material">
<span class="param-label">材质</span>
<span class="param-value">{{ item.material }}</span>
</div>
<div class="param-row" v-if="item.surfaceTreatment">
<span class="param-label">表面处理</span>
<span class="param-value">{{ item.surfaceTreatment }}</span>
</div>
<div class="param-row" v-if="item.zincLayer">
<span class="param-label">镀层质量</span>
<span class="param-value">{{ item.zincLayer }}</span>
</div>
<div class="param-row" v-if="item.manufacturer">
<span class="param-label">厂家</span>
<span class="param-value">{{ item.manufacturer }}</span>
</div>
</div>
</div>
</div>
<span slot="reference" style="cursor: pointer; color: #2bf;">{{ item.itemName || '—' }}</span>
</el-popover>
</span>
</div>
</p>
</div>
<div style="display: flex; justify-content: space-between;">
<svg-icon icon-class="coil" style="width: 1.5rem; height: 1.5rem;"></svg-icon>
<div style="font-size: 0.875rem; line-height: 1.25rem; display: flex; gap: 0.5rem;">
<el-button type="primary" size="mini" @click="handleContinueSplit(item)"
style="min-width: 80px; padding: 5px 15px;">
查看
</el-button>
<el-button size="mini" @click="handleCancelSplit(item)"
style="min-width: 80px; padding: 5px 15px; margin-left: 12px; border-color: #f56c6c; color: #f56c6c;"
:plain="true">
取消
</el-button>
</div>
</div>
</div>
</div>
<div v-else>
<el-empty description="暂无进行中的镀锌工序" />
</div>
</div>
<div class="section-card action-section">
<div class="section-header">
<h3 class="section-title">{{ label }}操作记录</h3>
<el-button size="mini" icon="el-icon-refresh" @click="getPendingAction">刷新</el-button>
</div>
<!-- 搜索栏 -->
<el-form :model="actionQueryParams" ref="actionQueryForm" size="small" :inline="true" class="query-form">
<el-form-item label="钢卷号" prop="currentCoilNo">
<el-input v-model="actionQueryParams.currentCoilNo" placeholder="请输入钢卷号" clearable
@keyup.enter.native="handleActionQuery" style="width: 150px;" />
</el-form-item>
<el-form-item label="操作状态" prop="actionStatus">
<el-select v-model="actionQueryParams.actionStatus" placeholder="请选择状态" clearable style="width: 120px;">
<el-option label="待处理" :value="0" />
<el-option label="处理中" :value="1" />
<el-option label="已完成" :value="2" />
<el-option label="已取消" :value="3" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleActionQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetActionQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 待操作卡片列表 -->
<div v-if="!useSpecialSplit" v-loading="actionLoading" class="card-grid-container">
<div v-if="pendingActionList.length === 0" class="empty-state">
<i class="el-icon-document"></i>
<p>暂无待操作任务</p>
</div>
<div v-for="(item, index) in pendingActionList" :key="item.actionId || index" class="action-card" :class="{
'urgent-card': item.priority === 2,
'important-card': item.priority === 1
}">
<div class="card-header">
<current-coil-no :current-coil-no="item.currentCoilNo"></current-coil-no>
<div class="status-tags">
<el-tag v-if="item.actionStatus === 0" type="info" size="mini">待处理</el-tag>
<el-tag v-else-if="item.actionStatus === 1" type="warning" size="mini">处理中</el-tag>
<el-tag v-else-if="item.actionStatus === 2" type="success" size="mini">已完成</el-tag>
<el-tag v-else-if="item.actionStatus === 3" type="danger" size="mini">已取消</el-tag>
<el-tag v-if="item.priority === 2" type="danger" size="mini">紧急</el-tag>
<el-tag v-else-if="item.priority === 1" type="warning" size="mini">重要</el-tag>
</div>
</div>
<div class="card-body">
<div class="info-list">
<div class="info-item">
<span class="info-label">来源</span>
<span class="info-value">
<el-tag v-if="item.sourceType === 'scan'" type="success" size="mini">扫码</el-tag>
<el-tag v-else type="info" size="mini">手动</el-tag>
</span>
</div>
<div class="info-item">
<span class="info-label">创建人</span>
<span class="info-value">{{ item.createBy || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">操作人</span>
<span class="info-value">{{ item.operatorName || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">扫码时间</span>
<span class="info-value">{{ parseTime(item.scanTime, '{m}-{d} {h}:{i}') || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">处理时间</span>
<span class="info-value">{{ parseTime(item.processTime, '{m}-{d} {h}:{i}') || '—' }}</span>
</div>
</div>
</div>
<div class="card-footer" v-if="!useSpecialSplit">
<!-- 待处理状态显示操作按钮 -->
<template v-if="item.actionStatus === 0">
<el-button :loading="buttonLoading" type="primary" icon="el-icon-edit" size="mini"
@click="handleProcess(item)" class="action-btn">操作</el-button>
<el-button :loading="buttonLoading" type="danger" icon="el-icon-delete" size="mini"
@click="handleDeleteAction(item)" class="action-btn">删除</el-button>
</template>
<!-- 处理中状态显示继续按钮 -->
<template v-else-if="item.actionStatus === 1">
<el-button :loading="buttonLoading" type="warning" icon="el-icon-edit" size="mini"
@click="handleProcess(item)" class="action-btn">继续</el-button>
<el-button :loading="buttonLoading" type="info" icon="el-icon-close" size="mini"
@click="handleCancel(item)" class="action-btn">取消</el-button>
</template>
<!-- 已完成或已取消状态显示删除按钮 -->
<template v-else>
<el-button :loading="buttonLoading" type="danger" icon="el-icon-delete" size="mini"
@click="handleDeleteAction(item)" class="action-btn">删除</el-button>
</template>
</div>
</div>
</div>
<el-table v-else :data="pendingActionList">
<el-table-column label="钢卷号" prop="currentCoilNo"></el-table-column>
<el-table-column label="操作状态" prop="actionStatus">
<template slot-scope="scope">
<el-tag v-if="scope.row.actionStatus === 0" type="info" size="mini">待处理</el-tag>
<el-tag v-else-if="scope.row.actionStatus === 1" type="warning" size="mini">处理中</el-tag>
<el-tag v-else-if="scope.row.actionStatus === 2" type="success" size="mini">已完成</el-tag>
<el-tag v-else-if="scope.row.actionStatus === 3" type="danger" size="mini">已取消</el-tag>
</template>
</el-table-column>
<el-table-column label="创建人" prop="createBy"></el-table-column>
<el-table-column label="操作人" prop="operatorName"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button v-if="scope.row.actionStatus === 2" :loading="buttonLoading" icon="el-icon-delete"
size="mini" @click="handleDeleteAction(scope.row)" class="action-btn">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination v-show="actionTotal > 0" :total="actionTotal" :page.sync="actionQueryParams.pageNum"
:limit.sync="actionQueryParams.pageSize" @pagination="getPendingAction" />
</div>
</el-col>
</el-row>
<el-dialog title="新增异常" :visible.sync="exceptionDialogVisible" width="600px">
<el-form ref="exceptionForm" :model="exceptionForm" label-width="80px">
<el-form-item label="位置" prop="position">
<el-radio-group v-model="exceptionForm.position">
<el-radio-button v-for="dict in dict.type.coil_abnormal_position" :key="dict.value" :label="dict.value">{{
dict.label }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="长度坐标" prop="lengthCoord">
<el-input v-model="exceptionForm.lengthCoord" placeholder="请输入长度坐标" />
</el-form-item>
<el-form-item label="缺陷代码" prop="defectCode">
<el-radio-group v-model="exceptionForm.defectCode">
<el-radio-button v-for="dict in dict.type.coil_abnormal_code" :key="dict.value" :label="dict.value">{{
dict.label }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="程度" prop="degree">
<el-radio-group v-model="exceptionForm.degree">
<el-radio-button v-for="dict in dict.type.coil_abnormal_degree" :key="dict.value" :label="dict.value">{{
dict.label }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="exceptionForm.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="info" @click="handleAbnormal">查看异常</el-button>
<el-button type="primary" @click="confirmException"> </el-button>
<el-button @click="cancelException"> </el-button>
</div>
</el-dialog>
<!-- 标签预览弹窗 -->
<el-dialog title="标签预览" :visible.sync="labelRender.visible" append-to-body>
<label-render :content="labelRender.data" :labelType="labelRender.type" />
</el-dialog>
<el-dialog title="分步加工" :visible.sync="stepSpilt.visible" width="1400px" append-to-body>
<step-split @print="handlePrintLabel" @complete="handleComposeSplit" :actionId="stepSpilt.actionId"
:coilId="stepSpilt.coilId" :actionStatus="stepSpilt.actionStatus" />
</el-dialog>
<label-render ref="labelRender" v-show="false" :content="labelRender.data" :labelType="labelRender.type" />
</div>
</template>
<script>
import { listMaterialCoil, startSpecialSplit, cancelSpecialSplit } from '@/api/wms/coil'
import { listPendingAction, startProcess, cancelAction, delPendingAction, addPendingAction } from '@/api/wms/pendingAction'
import { parseTime } from '@/utils/klp'
import ProductInfo from '@/components/KLPService/Renderer/ProductInfo'
import RawMaterialInfo from '@/components/KLPService/Renderer/RawMaterialInfo'
import { addCoilAbnormal } from '@/api/wms/coilAbnormal'
import LabelRender from './LabelRender/index.vue'
import StepSplit from './stepSplit.vue'
export default {
name: 'DoPage',
dicts: ['action_type', 'coil_abnormal_code', 'coil_abnormal_position', 'coil_abnormal_degree'],
props: {
label: {
type: String,
default: () => '酸连轧工序'
},
tabs: {
type: Array,
default: () => []
},
useSpecialSplit: {
type: Boolean,
default: false
}
},
components: {
ProductInfo,
RawMaterialInfo,
LabelRender,
StepSplit
},
data() {
return {
// 物料列表相关
materialLoading: false,
materialCoilList: [],
materialTotal: 0,
currentTab: '',
materialQueryParams: {
pageNum: 1,
pageSize: 20,
dataType: 1,
status: 0,
enterCoilNo: null,
currentCoilNo: null
},
labelRender: {
visible: false,
data: {},
type: '2'
},
// 待操作列表相关
actionLoading: false,
pendingActionList: [],
actionTotal: 0,
actionQueryParams: {
pageNum: 1,
pageSize: 20,
currentCoilNo: null,
actionType: null, // 将在created中设置为酸连轧工序的actionType
actionStatus: null
},
buttonLoading: false,
exceptionDialogVisible: false,
exceptionForm: {
coilId: null,
position: null,
lengthCoord: null,
defectCode: null,
degree: null,
remark: null
},
tagSizeMap: {
'2': {
width: 100,
height: 80,
},
'3': {
width: 180,
height: 100,
},
'4': {
width: 180,
height: 100,
},
'ge': {
width: 180,
height: 80,
},
'where': {
width: 100,
height: 80,
},
'5': {
width: 180,
height: 100,
},
'6': {
width: 180,
height: 100,
},
},
stepSpilt: {
list: [],
loading: false,
visible: false,
coilId: null,
actionId: null,
actionStatus: null
}
}
},
computed: {
// 获取酸连轧工序的actionType值
acidRollingActionType() {
if (!this.dict.type.action_type) return null
const acidAction = this.dict.type.action_type.find(item => {
const label = item.label || ''
return label.includes(this.label)
})
return acidAction ? parseInt(acidAction.value) : null
},
splitButtonStyle() {
if (this.acidRollingActionType == 501) {
return {
backgroundColor: '#2cb867',
border: '1px solid #2cb867',
color: '#111'
}
} else if (this.acidRollingActionType == 502) {
return {
backgroundColor: 'purple',
border: '1px solid purple',
color: '#fff'
}
} else if (this.acidRollingActionType == 503) {
return {
backgroundColor: '#f56c6c',
border: '1px solid #f56c6c',
color: '#fff'
}
} else if (this.acidRollingActionType == 504) {
return {
backgroundColor: 'orange',
border: '1px solid orange',
color: '#111'
}
} else if (this.acidRollingActionType == 505) {
return {
// 青色
backgroundColor: 'blue',
border: '1px solid blue',
color: '#fff'
}
} else {
return {}
}
}
},
watch: {
// 监听字典数据加载当acidRollingActionType有值时自动加载待操作列表
acidRollingActionType(newVal) {
if (newVal && !this.actionQueryParams.actionType) {
this.actionQueryParams.actionType = newVal
// 如果待操作列表为空,则加载数据
if (this.pendingActionList.length === 0) {
this.getPendingAction()
}
}
},
tabs: {
handler(newVal) {
if (newVal.length > 0) {
// this.materialQueryParams.warehouseId = newVal[0]?.value || ''
// 设置currentTab为第一个tab的value
this.currentTab = newVal[0]?.value || undefined
}
},
immediate: true
},
currentTab: {
handler(newVal) {
if (newVal) {
this.materialQueryParams.warehouseId = newVal
}
this.getMaterialCoil()
},
immediate: true
}
},
created() {
// 立即加载物料列表(不依赖字典)
// this.getMaterialCoil()
// 尝试加载待操作列表(如果字典已加载)
this.$nextTick(() => {
if (this.acidRollingActionType) {
this.actionQueryParams.actionType = this.acidRollingActionType
this.getPendingAction()
if (this.useSpecialSplit) {
this.getStepSplitList()
}
}
})
},
mounted() {
// 确保在mounted时也尝试加载字典数据可能此时才加载完成
this.$nextTick(() => {
if (this.acidRollingActionType && !this.actionQueryParams.actionType) {
this.actionQueryParams.actionType = this.acidRollingActionType
this.getPendingAction()
}
})
},
methods: {
parseTime,
// 打印标签
handlePrintLabel(row) {
const item = row.itemType === 'product' ? row.product : row.rawMaterial;
const itemName = row.itemType === 'product' ? item?.productName || '' : item?.rawMaterialName || '';
const itemType = row.itemType || '';
const warehouseId = row.warehouseId || '';
// 在镀锌颜料库的卷使用镀锌原料标签
if (itemType == 'raw_material' && (warehouseId == '1988150263284953089' || warehouseId == '1988150487185289217')) {
this.labelRender.type = '5';
}
// 脱脂原料库
else if (itemType == 'raw_material' && (warehouseId == '1988150545175736322')) {
this.labelRender.type = '6';
}
else if (itemType == 'raw_material') {
this.labelRender.type = '2';
} else if (itemType == 'product' && itemName == '冷硬卷') {
this.labelRender.type = '3';
} else if (itemType == 'product' && itemName == '热轧卷板') {
this.labelRender.type = '3';
} else if (itemType == 'product' && itemName == '镀锌卷') {
this.labelRender.type = '4';
} else if (itemType == 'product' && itemName == '冷轧卷') {
this.labelRender.type = '3';
} else if (itemType == 'product' && itemName == '镀铬卷') {
this.labelRender.type = 'ge';
} else {
this.labelRender.type = '3';
}
this.labelRender.data = {
...row,
itemName: itemName,
updateTime: row.updateTime?.split(' ')[0] || '',
};
this.$nextTick(() => {
this.$refs.labelRender.printLabel();
})
},
getStepSplitList() {
this.stepSpilt.loading = true
if (!this.acidRollingActionType) {
this.$message.error(`未找到${this.label}操作类型,请检查字典配置`)
return
}
listPendingAction({ actionType: this.acidRollingActionType, actionStatus: 0 }).then(response => {
this.stepSpilt.list = response.rows || []
this.stepSpilt.loading = false
})
},
handleComposeSplit() {
this.stepSpilt.visible = false;
this.getStepSplitList()
this.getPendingAction()
},
/** 预览标签 */
handlePreviewLabel(row) {
this.labelRender.visible = true;
const item = row.itemType === 'product' ? row.product : row.rawMaterial;
const itemName = row.itemType === 'product' ? item?.productName || '' : item?.rawMaterialName || '';
this.labelRender.type = row.itemType === 'product' ? '3' : '2'
this.labelRender.data = {
...row,
itemName: itemName,
updateTime: row.updateTime?.split(' ')[0] || '',
};
},
// ========== 物料列表相关方法 ==========
/** 查询物料列表 */
getMaterialCoil() {
this.materialLoading = true
listMaterialCoil(this.materialQueryParams).then(response => {
this.materialCoilList = response.rows || []
this.materialTotal = response.total || 0
this.materialLoading = false
}).catch(() => {
this.materialLoading = false
})
},
/** 物料搜索 */
handleMaterialQuery() {
this.materialQueryParams.pageNum = 1
this.getMaterialCoil()
},
/** 重置物料搜索 */
resetMaterialQuery() {
this.resetForm('materialQueryForm')
this.materialQueryParams.enterCoilNo = null
this.materialQueryParams.currentCoilNo = null
this.handleMaterialQuery()
},
/** 领料操作 */
handlePickMaterial(row) {
if (!this.acidRollingActionType) {
this.$message.error(`未找到${this.label}操作类型,请检查字典配置`)
return
}
this.$set(row, 'picking', true)
const pendingData = {
coilId: row.coilId,
currentCoilNo: row.currentCoilNo,
actionType: this.acidRollingActionType,
actionStatus: 0, // 待处理
sourceType: 'manual', // 手动创建
warehouseId: row.warehouseId,
priority: 0, // 默认普通优先级
remark: `PC端领料创建-${this.label}`
}
this.$modal.confirm(`是否确认从${row.warehouseName || '仓库'}领料${row.currentCoilNo || '物料'}`).then(() => {
// 用户点击确认后执行的操作
return addPendingAction(pendingData)
}).then(response => {
this.$message.success('领料成功,已创建待操作任务')
this.getPendingAction() // 刷新待操作列表
}).finally(() => {
this.$set(row, 'picking', false)
})
},
// ========== 待操作列表相关方法 ==========
/** 查询待操作列表 */
getPendingAction() {
// 确保只查询酸连轧工序的待操作
if (!this.acidRollingActionType) {
console.warn(`未找到${this.label}操作类型,请检查字典配置`)
this.pendingActionList = []
this.actionTotal = 0
this.actionLoading = false
return
}
this.actionLoading = true
// 强制使用酸连轧工序的 actionType忽略查询参数中的 actionType
const queryParams = {
...this.actionQueryParams,
actionType: this.acidRollingActionType
}
listPendingAction(queryParams).then(response => {
this.pendingActionList = response.rows || []
this.actionTotal = response.total || 0
this.actionLoading = false
}).catch(() => {
this.actionLoading = false
})
},
/** 待操作搜索 */
handleActionQuery() {
this.actionQueryParams.pageNum = 1
// 确保始终使用酸连轧工序的 actionType
if (this.acidRollingActionType) {
this.actionQueryParams.actionType = this.acidRollingActionType
}
this.getPendingAction()
},
async handleCancelSplit(row) {
this.$modal.confirm('是否取消分卷操作?').then(_ => {
this.stepSpilt.loading = true
this.buttonLoading = true
cancelSpecialSplit(row.actionId).then(response => {
this.$message.success('取消分卷成功')
this.getPendingAction() // 刷新待操作列表
this.getStepSplitList()
}).finally(() => {
this.stepSpilt.loading = false
this.buttonLoading = false
})
})
},
/** 重置待操作搜索 */
resetActionQuery() {
this.resetForm('actionQueryForm')
this.actionQueryParams.currentCoilNo = null
this.actionQueryParams.actionStatus = null
// 确保始终使用酸连轧工序的 actionType
if (this.acidRollingActionType) {
this.actionQueryParams.actionType = this.acidRollingActionType
}
this.handleActionQuery()
},
/** 处理操作 - 跳转到对应页面 */
handleProcess(row) {
const actionType = parseInt(row.actionType)
// 特殊处理:发货和移库操作不需要跳转
if (actionType === 4 || actionType === 5) {
this.$message.info(actionType === 4 ? '发货操作已在移动端完成' : '移库操作已在移动端完成')
return
}
if (actionType === 501) {
// 特殊分条,打开弹窗操作
this.handleContinueSplit(row)
return;
}
// 根据操作类型跳转到不同页面
let path = ''
// 分条操作100-199
if (actionType >= 100 && actionType <= 199) {
path = '/wms/split'
}
// 合卷操作200-299
else if (actionType == 200) {
path = '/wms/merge'
}
// 其他操作类型
else {
path = '/wms/typing'
}
if (!path) {
this.$message.error('未知的操作类型: ' + row.actionType)
return
}
// 更新状态为处理中
startProcess(row.actionId).then(response => {
if (response.code !== 200) {
this.$message.error(response.msg || '更新状态失败')
return
}
// 跳转并传递参数
const currentActionTypeLabel = this.$route?.query?.actionType
this.$router.push({
path: path,
query: {
coilId: row.coilId,
actionId: row.actionId,
...(currentActionTypeLabel ? { actionType: currentActionTypeLabel } : {})
}
})
}).catch(error => {
console.error('更新状态失败:', error)
this.$message.error('更新状态失败: ' + (error.message || error))
})
},
/** 取消操作 */
handleCancel(row) {
this.$confirm('是否确认取消该操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return cancelAction(row.actionId)
}).then(() => {
this.$message.success('操作已取消')
this.getPendingAction()
}).catch(() => { })
},
/** 删除待操作 */
handleDeleteAction(row) {
const actionId = row.actionId
this.$confirm('是否确认删除该待操作记录?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return delPendingAction(actionId)
}).then(() => {
this.getPendingAction()
this.$message.success('删除成功')
}).catch(() => { })
},
/** 获取物品名称 */
getItemName(item) {
if (item.itemType === 'product' && item.product) {
return item.product.productName || ''
} else if (item.itemType === 'raw_material' && item.rawMaterial) {
return item.rawMaterial.rawMaterialName || ''
}
return '—'
},
handleAddAbnormal(row) {
this.exceptionForm.coilId = row.coilId
this.exceptionDialogVisible = true
},
confirmException() {
addCoilAbnormal(this.exceptionForm).then(response => {
this.$message.success('异常记录添加成功')
this.cancelException();
// 重置表单
this.getMaterialCoil()
}).catch(error => {
console.error('异常记录添加失败:', error)
this.$message.error('异常记录添加失败: ' + (error.message || error))
})
},
handleAbnormal() {
this.$router.push({
path: '/quality/detail',
query: {
coilId: this.exceptionForm.coilId,
}
})
},
async handleStartSplit(row) {
this.buttonLoading = true
try {
await this.$modal.confirm('是否确认领料开始分步加工操作?')
this.stepSpilt.loading = true
await startSpecialSplit(row.coilId, this.acidRollingActionType);
// await addPendingAction({
// coilId: row.coilId,
// currentCoilNo: row.currentCoilNo,
// actionType: 501,
// actionStatus: 0,
// sourceType: 'manual',
// priority: 0,
// })
this.$message.success('加工操作已创建')
this.getPendingAction()
// this.getMaterialCoil()
this.getStepSplitList()
} finally {
this.buttonLoading = false
this.stepSpilt.loading = false
}
},
handleContinueSplit(row) {
this.stepSpilt.coilId = row.coilId
this.stepSpilt.actionId = row.actionId
this.stepSpilt.actionStatus = row.actionStatus
this.stepSpilt.visible = true
// this.buttonLoading = true
// this.getPendingAction()
// this.getMaterialCoil()
// this.buttonLoading = false
},
cancelException() {
// 重置表单
this.exceptionForm = {
coilId: null,
position: null,
lengthCoord: null,
defectCode: null,
degree: null,
remark: null
}
this.exceptionDialogVisible = false
},
}
}
</script>
<style scoped lang="scss">
.acid-do-container {
background-color: #f5f7fa;
padding: 20px;
min-height: calc(100vh - 84px);
}
.section-card {
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 4px;
padding: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 2px solid #e4e7ed;
}
.section-title {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #303133;
}
.material-section {
.section-header {
border-bottom-color: #409eff;
}
.section-title {
color: #409eff;
}
}
.action-section {
.section-header {
border-bottom-color: #67c23a;
}
.section-title {
color: #67c23a;
}
}
.query-form {
margin-bottom: 16px;
padding: 12px;
background-color: #fafafa;
border-radius: 4px;
border: 1px solid #e4e7ed;
}
// 卡片网格容器
.card-grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
max-height: calc(100vh - 320px);
overflow-y: auto;
padding-right: 4px;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
&:hover {
background: #a8a8a8;
}
}
@media (min-width: 2000px) {
grid-template-columns: repeat(4, 1fr);
}
}
// 空状态
.empty-state {
text-align: center;
padding: 60px 20px;
color: #909399;
i {
font-size: 48px;
margin-bottom: 16px;
display: block;
color: #c0c4cc;
}
p {
margin: 0;
font-size: 14px;
}
}
// 物料卡片
.material-card {
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 3px;
display: flex;
flex-direction: column;
transition: all 0.3s ease;
height: 100%;
&:hover {
border-color: #409eff;
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.12);
}
.card-header {
padding: 6px 8px;
border-bottom: 1px solid #e4e7ed;
background-color: #fafafa;
.header-left {
display: flex;
align-items: center;
gap: 6px;
}
.coil-no-tag {
font-weight: 600;
font-size: 11px;
padding: 2px 6px;
}
.material-type {
font-size: 11px;
color: #606266;
font-weight: 500;
}
.param-icon {
font-size: 13px;
color: #909399;
cursor: pointer;
transition: color 0.3s;
&:hover {
color: #409eff;
}
}
}
.card-body {
padding: 8px;
flex: 1;
.info-list {
.info-item {
display: flex;
align-items: center;
margin-bottom: 4px;
font-size: 11px;
line-height: 1.4;
&:last-child {
margin-bottom: 0;
}
.info-label {
color: #909399;
white-space: nowrap;
margin-right: 4px;
min-width: 40px;
font-size: 11px;
}
.info-value {
color: #303133;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 11px;
}
}
}
}
.card-footer {
padding: 6px 8px;
border-top: 1px solid #e4e7ed;
background-color: #fafafa;
display: flex;
justify-content: center;
.action-btn {
width: 100%;
padding: 5px 10px;
font-size: 11px;
}
}
}
// 待操作卡片
.action-card {
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 4px;
display: flex;
flex-direction: column;
transition: all 0.3s ease;
height: 100%;
&:hover {
border-color: #67c23a;
box-shadow: 0 2px 8px rgba(103, 194, 58, 0.15);
}
&.urgent-card {
border-left: 4px solid #f56c6c;
background-color: #fef0f0;
&:hover {
border-color: #f56c6c;
box-shadow: 0 2px 8px rgba(245, 108, 108, 0.2);
}
}
&.important-card {
border-left: 4px solid #e6a23c;
background-color: #fdf6ec;
&:hover {
border-color: #e6a23c;
box-shadow: 0 2px 8px rgba(230, 162, 60, 0.2);
}
}
.card-header {
padding: 10px 12px;
border-bottom: 1px solid #e4e7ed;
background-color: #fafafa;
display: flex;
justify-content: space-between;
align-items: center;
.coil-no-tag {
font-weight: 600;
font-size: 12px;
}
.status-tags {
display: flex;
gap: 4px;
flex-wrap: wrap;
}
}
.card-body {
padding: 12px;
flex: 1;
.info-list {
.info-item {
display: flex;
align-items: center;
margin-bottom: 8px;
font-size: 12px;
&:last-child {
margin-bottom: 0;
}
.info-label {
color: #909399;
white-space: nowrap;
margin-right: 6px;
min-width: 50px;
}
.info-value {
color: #303133;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.action-type-tag {
font-size: 11px;
}
}
}
}
.card-footer {
padding: 10px 12px;
border-top: 1px solid #e4e7ed;
background-color: #fafafa;
display: flex;
justify-content: center;
gap: 6px;
.action-btn {
flex: 1;
font-size: 12px;
padding: 6px 8px;
}
}
}
// 分页样式
::v-deep .pagination-container {
margin-top: 16px;
padding: 12px;
background-color: #fafafa;
border-radius: 4px;
border: 1px solid #e4e7ed;
}
// 参数弹出框样式
::v-deep .material-params-popover {
.material-params-content {
.params-title {
font-size: 14px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #e4e7ed;
}
.params-list {
.param-item {
.param-row {
display: flex;
margin-bottom: 6px;
font-size: 12px;
line-height: 1.5;
&:last-child {
margin-bottom: 0;
}
.param-label {
color: #909399;
min-width: 70px;
margin-right: 8px;
}
.param-value {
color: #303133;
flex: 1;
word-break: break-all;
}
}
}
.param-divider {
height: 1px;
background-color: #e4e7ed;
margin: 10px 0;
}
}
}
}
</style>