evoToK3Cloud-vue/src/views/system/route/index.vue
2025-12-30 21:07:25 +08:00

2167 lines
77 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">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams">
<el-form-item label="项目令号" prop="routeDescription">
<el-select v-model="queryParams.routeDescription" filterable remote :remote-method="handleQuery1"
placeholder="请输入令号" clearable :loading="loading">
<el-option v-for="item in projectCodes" :key="item" :label="item" :value="item"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-form>
<el-row :gutter="10" class="mb8">
<!-- <el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['system:route:add']">新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
v-hasPermi="['system:route:edit']">修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete"
v-hasPermi="['system:route:remove']">删除
</el-button>
</el-col>-->
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleExport"
v-hasPermi="['system:route:export']">导出
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-upload" size="mini" @click="handleImport"
v-hasPermi="['system:route:importRoute']">导入工艺
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-time" size="mini" @click="handleImportTime"
v-hasPermi="['system:route:importDataTime']">导入时间
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-share" size="mini" @click="pushRouteBom"
v-hasPermi="['system:route:pushRouteBom']">推送工艺
</el-button>
</el-col>
<el-col :span="3">
<el-input
v-model="routeGroupName"
placeholder="请输入推送分组"
size="mini"
clearable
/>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-edit" size="mini" :disabled="multiple" @click="updateProcessPlan"
v-hasPermi="['system:route:updateProcessPlan']">更新计划时间
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-setting" size="mini" @click="updateProcesTime"
v-hasPermi="['system:route:updateProcesTime']">更新生产订单
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-document" size="mini" @click="generatePDFs1"
v-hasPermi="['system:route:generatePDFs']">生成PDF
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-warning" size="mini" @click="getKindeeExcel"
v-hasPermi="['system:route:getKindeeExcel']">获取标准工艺
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-warning" size="mini" @click="getAllRouteAndUse"
v-hasPermi="['system:route:getAllRouteAndUse']">获取全部工艺
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-form :inline="true" :model="form" ref="ruleForm" size="mini" :rules="rules">
<el-table v-if="showtable" v-loading="loading" row-key="id" ref="tree" v-drag:[config]="form.routeList"
:tree-props="{ children: 'children' }" :data="form.routeList" stripe :row-class-name="tableRowClassName"
border max-height="680px" @cell-click="cellhand" :default-expand-all="true"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center"/>
<!-- <el-table-column label="主键ID" align="center" prop="id" v-if="true"/>-->
<el-table-column label="操作" width="55" align="center">
<template slot-scope="props">
<!-- <el-button type="text" icon="el-icon-check" v-if="scope.row.id < 0" @click="onSaveChild()" /> -->
<!-- <fromed v-if="props.row.parentId" /> -->
<!-- {{props.row.materialCode}} -->
<el-button v-if="props.row.parentId" size="mini" class="handle" icon="el-icon el-icon-rank"/>
</template>
</el-table-column>
<!-- <el-table-column label="项目令号" align="center">
<template slot-scope="scope">
<router-link :to="'/route1/' + scope.row.routeDescription" type="primary" :underline="false">{{
scope.row.routeDescription }}</router-link>
</template>
</el-table-column> -->
<el-table-column label="物料编码" width="120" align="center" prop="materialCode" fixed="left"/>
<el-table-column label="名称" width="120" align="center" prop="materialName" fixed="left"/>
<el-table-column label="材质" width="80" align="center" prop="material"/>
<el-table-column label="单重" width="60" align="center" prop="discWeight"/>
<el-table-column label="单台数" width="60" align="center" prop="unitQuantity">
<template slot-scope="scope">
<span :style="{
color: scope.row.firstBatchQuantity > 0 ? 'green' : 'red',
fontWeight: 'bold'
}">
{{ scope.row.firstBatchQuantity }}
</span>
</template>
</el-table-column>
<el-table-column label="本批数" width="60" align="center" prop="batchQuantity"/>
<!--
<el-table-column label="材料BOM物料编码" width="220"align="center" prop="ra wMaterialCode" />
<el-table-column label="材料BOM物料名称"width="220" align="center" prop="rawMaterialName" />
<el-table-column label="用量"width="60"align="center" prop="discUsage" />
<el-table-column label="单位"width="60" align="center" prop="bomUnit" />-->
<el-table-column label="工序号" width="60" align="center" prop="processNo"/>
<el-table-column label="工作中心" width="96" align="center">
<template slot-scope="scope">
<el-form-item v-if="scope.row.isEdit" :prop="'routeList.' + scope.$index + '.workCenter'">
<el-select v-model="scope.row.workCenter" placeholder="请选择工作中心" clearable>
<el-option v-for="dict in dict.type.work_center" :key="dict.value" :label="dict.label"
:value="dict.value"/>
</el-select>
</el-form-item>
<span v-else>
<dict-tag :options="dict.type.work_center" :value="scope.row.workCenter"/>
</span>
</template>
</el-table-column>
<el-table-column label="工序名称" width="160" align="center">
<template slot-scope="scope">
<el-form-item v-if="scope.row.id < 0 || scope.row.isEdit"
:prop="'routeList.' + scope.$index + '.processName'">
<el-select v-model="scope.row.processName" filterable remote :remote-method="handleQuery3"
placeholder="请输入工序名称" clearable :loading="loading"
@change="handleProcessNameChange(scope)">
<el-option v-for="item in processName" :key="item" :label="item" :value="item"></el-option>
</el-select>
</el-form-item>
<span v-else>{{ scope.row.processName }}</span>
</template>
</el-table-column>
<el-table-column label="序说明" width="300" align="center">
<template slot-scope="scope">
<el-form-item v-if="scope.row.id < 0 || scope.row.isEdit"
:prop="'routeList.' + scope.$index + '.processDescription'">
<el-input v-model="scope.row.processDescription"></el-input>
</el-form-item>
<span v-else>{{ scope.row.processDescription }}</span>
</template>
</el-table-column>
<!-- 工序控制列 -->
<el-table-column label="工序控制码" width="100" align="center">
<template slot-scope="scope">
<el-form-item v-if="scope.row.isEdit" :prop="'routeList.' + scope.$index + '.processControl'">
<el-select v-model="scope.row.processControl" placeholder="请选择工序控制码" clearable>
<el-option label="汇报+免检" value="汇报+免检"></el-option>
<el-option label="委外+质量" value="委外+质量"></el-option>
<el-option label="汇报+质量" value="汇报+质量"></el-option>
</el-select>
</el-form-item>
<span v-else>{{ scope.row.processControl }}</span>
</template>
</el-table-column>
<el-table-column label="活动时长" align="center">
<template slot-scope="scope">
<el-form-item v-if="scope.row.id < 0 || scope.row.isEdit"
:prop="'routeList.' + scope.$index + '.activityDuration'">
<el-input v-model="scope.row.activityDuration"></el-input>
</el-form-item>
<span v-else>{{ scope.row.activityDuration }}</span>
</template>
</el-table-column>
<el-table-column label="活动单位" align="center" prop="activityUnit"/>
<el-table-column label="序开始时间" align="center" prop="xuStartTime" width="100">
<template slot-scope="scope">
<el-form-item v-if="scope.row.id < 0 || scope.row.isEdit"
:prop="'routeList.' + scope.$index + '.xuStartTime'">
<el-date-picker v-model="scope.row.xuStartTime" type="date" placeholder="选择序开始时间"
value-format="yyyy-MM-dd" format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
<span v-else>{{ parseTime(scope.row.xuStartTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="序结束时间" align="center" prop="xuEndTime" width="100">
<template slot-scope="scope">
<el-form-item v-if="scope.row.id < 0 || scope.row.isEdit"
:prop="'routeList.' + scope.$index + '.xuEndTime'">
<el-date-picker v-model="scope.row.xuEndTime" type="date" placeholder="选择序结束时间"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
<span v-else>{{ parseTime(scope.row.xuEndTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<!-- //<el-table-column label="单位" align="center" prop="bomUnit" /> -->
<!-- <el-table-column label="单台数量" align="center" prop="unitQuantity" /> -->
<el-table-column label="计划开始时间" align="center" prop="planStartTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.planStartTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="计划结束时间" align="center" prop="planEndTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.planEndTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column class="maxWidth" label="操作" width="220" fixed="right" align="center"
class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button class="btn" size="mini" @click="onAddChild(scope)" v-if="!scope.row.parentId">
添加工艺
</el-button>
<el-button class="btn" size="mini" type="success" @click="onSave(scope)"
v-if="!scope.row.parentId && showParentSaveBtn === scope.row.id">
保存工艺
</el-button>
<template v-else-if="scope.row.parentId">
<template v-if="scope.row.isEdit">
<el-button class="btn" size="mini" type="success" @click="onSaveRow(scope)">
确定
</el-button>
<el-button class="btn" size="mini" type="info" @click="cancelEdit(scope)">
取消
</el-button>
</template>
<template v-else>
<template v-if="scope.row.id > 0">
<el-button class="btn" size="mini" type="primary" @click="handleRowEdit(scope)"
v-hasPermi="['system:route:edit']">
修改
</el-button>
<el-button class="btn" size="mini" type="danger" @click="handleDelete(scope)"
v-hasPermi="['system:route:remove']">
删除
</el-button>
</template>
<template v-else>
<el-button class="btn" size="mini" type="danger" @click="onDeleteUnsaved(scope)">
删除
</el-button>
</template>
</template>
</template>
</template>
</el-table-column>
</el-table>
</el-form>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<!-- 基本信息 -->
<el-row>
<el-col :span="12">
<el-form-item label="物料编码" prop="materialCode">
<el-input v-model="form.materialCode" placeholder="请输入物料编码"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="物料名称" prop="materialName">
<el-input v-model="form.materialName" placeholder="请输入物料名称"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="材质" prop="material">
<el-input v-model="form.material" placeholder="请输入材质"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="单重" prop="discWeight">
<el-input v-model="form.discWeight" placeholder="请输入单重"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="单位" prop="bomUnit">
<el-select v-model="form.bomUnit" placeholder="请选择单位">
<el-option label="件" value="件"></el-option>
<el-option label="套" value="套"></el-option>
<el-option label="个" value="个"></el-option>
<el-option label="米" value="米"></el-option>
<el-option label="千克" value="千克"></el-option>
<el-option label="吨" value="吨"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="单台数量" prop="unitQuantity">
<el-input-number v-model="form.unitQuantity" :min="0" placeholder="请输入单台数量"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="本批数量" prop="batchQuantity">
<el-input-number v-model="form.batchQuantity" :min="0" placeholder="请输入本批数量"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="首批数量" prop="firstBatchQuantity">
<el-input-number v-model="form.firstBatchQuantity" :min="0" placeholder="请输入首批数量"/>
</el-form-item>
</el-col>
</el-row>
<!-- 工艺信息 -->
<el-row>
<el-col :span="12">
<el-form-item label="工作中心" prop="workCenter">
<el-select v-model="form.workCenter" placeholder="请选择工作中心" clearable>
<el-option label="机一工段" value="机一工段"></el-option>
<el-option label="机二工段" value="机二工段"></el-option>
<el-option label="机三工段" value="机三工段"></el-option>
<el-option label="装一工段" value="装一工段"></el-option>
<el-option label="装二工段" value="装二工段"></el-option>
<el-option label="铆焊工段" value="铆焊工段"></el-option>
<el-option label="电钳工段" value="电钳工段"></el-option>
<el-option label="委外中心" value="委外中心"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工序名称" prop="processName">
<el-select v-model="form.processName" filterable remote :remote-method="handleQuery3"
placeholder="请输入工序名称" clearable :loading="loading" @change="handleProcessNameChange">
<el-option v-for="item in processName" :key="item" :label="item" :value="item"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="工序说明" prop="processDescription">
<el-input type="textarea" v-model="form.processDescription" placeholder="请输入工序说明"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="工序控制" prop="processControl">
<el-select v-model="form.processControl" placeholder="请选择工序控制码" clearable>
<el-option label="汇报+免检" value="汇报+免检"></el-option>
<el-option label="委外+质量" value="委外+质量"></el-option>
<el-option label="汇报+质量" value="汇报+质量"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="活动时长" prop="activityDuration">
<el-input v-model="form.activityDuration" placeholder="请输入活动时长"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="序开始时间" prop="xuStartTime">
<el-date-picker v-model="form.xuStartTime" type="date" placeholder="选择序开始时间"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="序结束时间" prop="xuEndTime">
<el-date-picker v-model="form.xuEndTime" type="date" placeholder="选择序结束时间"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
<!-- 导入导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading"
:on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<div class="el-upload__tip" slot="tip">
<el-checkbox v-model="upload.updateSupport"/>
是否更新已经存在的物料数据
</div>
<span>仅允许导入xls、xlsx格式文件。</span>
<!-- <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;"
@click="importTemplate">下载模板
</el-link>-->
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm">确 定</el-button>
<el-button @click="upload.open = false">取 消</el-button>
</div>
</el-dialog>
<el-dialog :title="timeUpload.title" :visible.sync="timeUpload.open" width="400px" append-to-body>
<el-upload ref="timeUpload" :limit="1" accept=".xlsx, .xls" :headers="timeUpload.headers" :action="timeUpload.url"
:disabled="timeUpload.isUploading" :on-progress="handleTimeFileUploadProgress"
:on-success="handleTimeFileSuccess" :auto-upload="false" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<span>仅允许导入xls、xlsx格式文件。</span>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitTimeFileForm">确 定</el-button>
<el-button @click="timeUpload.open = false">取 消</el-button>
</div>
</el-dialog>
<!-- 抽屉 -->
<el-drawer title="BOM信息" :visible.sync="BOMpop" :before-close="bomClose" :size="1100" :destroy-on-close="true" :modal="false">
<div style="padding: 20px;">
<!-- BOM信息头部 -->
<div class="bom-header">
<el-descriptions :column="3" border>
<el-descriptions-item label="当前物料编码">{{ currentMaterial.materialCode }}</el-descriptions-item>
<el-descriptions-item label="当前物料名称">{{ currentMaterial.materialName }}</el-descriptions-item>
<el-descriptions-item label="生产令号">{{ currentMaterial.productionOrderNo }}</el-descriptions-item>
</el-descriptions>
</div>
<!-- 搜索和操作按钮 -->
<div class="table-operations" style="margin: 15px 0;">
<div class="right-operations">
<el-button-group>
<el-button type="primary" size="small" @click="handleBomAdd">
<i class="el-icon-plus"></i> 新增
</el-button>
<el-button type="primary" size="small" @click="handleBomRefresh">
<i class="el-icon-refresh"></i> 刷新
</el-button>
<el-button type="success" size="small" @click="handleBomExport">
<i class="el-icon-download"></i> 导出
</el-button>
</el-button-group>
</div>
</div>
<!-- BOM数据表格 -->
<el-table :data="filteredBomData" stripe max-height="400px" border v-loading="bomLoading"
@selection-change="handleBomSelectionChange" element-loading-text="加载中..."
element-loading-spinner="el-icon-loading">
<el-table-column type="selection" width="55" align="center"/>
<el-table-column label="生产令号" width="150" align="center" prop="projectNumber"/>
<el-table-column label="物料编码" width="200" align="center" prop="materialCode" show-overflow-tooltip/>
<el-table-column label="物料名称" width="200" align="center" prop="materialName" show-overflow-tooltip/>
<el-table-column label="材质" width="70" align="center" prop="materialType"/>
<el-table-column label="库存" width="88" align="center" prop="singleWeight ">
<template slot-scope="scope">
<span>{{ scope.row.singleWeight || '0' }}</span>
</template>
</el-table-column>
<el-table-column label="用量" width="88" align="center" prop="quantity">
<template slot-scope="scope">
<span>{{ scope.row.quantity || '0' }}</span>
</template>
</el-table-column>
<el-table-column label="单位" width="88" align="center" prop="unit"/>
<el-table-column label="操作" align="center" width="150">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleBomEdit(scope.row)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete"
@click="handleBomDelete(scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- BOM编辑对话框 -->
<el-dialog :title="bomDialogTitle" :visible.sync="bomDialogVisible" width="500px" append-to-body>
<el-form ref="bomForm" :model="bomForm" :rules="bomRules" label-width="100px">
<input type="hidden" v-model="bomForm.projectNumber">
<input type="hidden" v-model="bomForm.parentMaterialCode">
<input type="hidden" v-model="bomForm.parentMaterialName">
<!-- 物料名称 - 支持搜索或手动输入 -->
<el-form-item label="物料名称" prop="materialName">
<el-autocomplete v-model="bomForm.materialName" :fetch-suggestions="handleMaterialSearch"
:trigger-on-focus="false" @select="handleMaterialSelect" placeholder="请输入物料名称"
clearable
popper-class="material-autocomplete-dropdown">
<template slot-scope="{ item }">
<div class="material-suggestion-item">
<div class="material-name">{{ item.materialName }}</div>
<div class="material-info">
<span>编码: {{ item.materialCode }}</span>
<span>材质: {{ item.materialType }}</span>
<span>单位: {{ item.classificationName }}</span>
<span>库存: {{ item.singleWeight || '0' }}</span>
</div>
</div>
</template>
</el-autocomplete>
</el-form-item>
<!-- 物料编码 - 允许手动输入 -->
<el-form-item label="物料编码" prop="materialCode">
<el-input v-model="bomForm.materialCode" placeholder="请输入物料编码"></el-input>
</el-form-item>
<!-- 材质 - 允许手动输入 -->
<el-form-item label="材质" prop="materialType">
<el-input v-model="bomForm.materialType" placeholder="请输入材质"></el-input>
</el-form-item>
<!-- 单位 -->
<el-form-item label="单位" prop="unit">
<el-select v-model="bomForm.unit" placeholder="请选择单位" clearable>
<el-option label="件" value="件"></el-option>
<el-option label="根" value="根"></el-option>
<el-option label="mm" value="mm"></el-option>
<el-option label="kg" value="kg"></el-option>
<el-option label="套" value="套"></el-option>
<el-option label="个" value="个"></el-option>
</el-select>
</el-form-item>
<!-- 当前库存 - 允许手动输入 -->
<el-form-item label="当前库存" prop="stock">
<el-input-number v-model="bomForm.stock" :min="0" :precision="2"
placeholder="请输入库存"></el-input-number>
</el-form-item>
<!-- 用量 -->
<el-form-item label="用量" prop="quantity">
<el-input-number v-model="bomForm.quantity" :min="0" :precision="2"
placeholder="请输入用量"></el-input-number>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitBomForm">确 定</el-button>
<el-button @click="bomDialogVisible = false">取 消</el-button>
</div>
</el-dialog>
<!-- 工艺路线信息部分 -->
<div class="section-title" style="margin: 20px 0 15px;">
<h3>工艺路线信息</h3>
</div>
<el-table :data="processRoutes" stripe border v-loading="processLoading">
<el-table-column label="工艺编号" prop="fnumber" width="120" align="center"/>
<el-table-column label="项目令号" prop="project_code" width="180" align="center"/>
<el-table-column label="物料编码" prop="materialCode" fixed="left" width="140" align="center"/>
<el-table-column label="物料名称" prop="materialName" fixed="left" min-width="140" align="center"/>
<el-table-column label="操作" width="120" align="center">
<template slot-scope="scope">
<el-button
type="text"
@click="handleViewRoute(scope.row)"
:type="selectedRouteId === scope.row.id ? 'success' : 'primary'">
{{ selectedRouteId === scope.row.id ? '查看中' : '查看' }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 选中的工艺路线工序信息 -->
<div v-if="selectedRoute" class="process-detail" style="margin-top: 15px;">
<div class="sub-title" style="margin-bottom: 10px;">
<h4>工序信息 - {{ selectedRoute.fnumber }}</h4>
</div>
<el-table :data="currentProcessList" stripe border max-height="300px">
<el-table-column label="工序号" prop="processNo" width="80" align="center"/>
<el-table-column label="工作中心" prop="workCenter" width="120" align="center"/>
<el-table-column label="工序名称" prop="processName" width="120" align="center"/>
<el-table-column label="工序说明" prop="processDescription" min-width="200" show-overflow-tooltip/>
<el-table-column label="工序控制" prop="processControl" width="120" align="center"/>
<el-table-column label="活动时长" align="center" width="120">
<template slot-scope="scope">
{{ scope.row.activityDuration }} {{ scope.row.activityUnit }}
</template>
</el-table-column>
</el-table>
</div>
</div>
</el-drawer>
</div>
</template>
<script>
import {
listRoute,
getRoute,
delRoute,
addRoute,
updateRoute,
getDistinctProjectCodes,
updateProcessPlan, generatePDFs, updateBom, addBom, deleteBom, getKindeeExcel,getAllRouteAndUse,updateProcesTime
} from "@/api/system/route";
import {getToken} from "../../../utils/auth";
import Fromed from './fromed'
import Bomfrom from './bomfrom'
import {getProcessInfoList, pushRouteBom, onSave, getBomInfo, getProcessRouteList} from "@/api/system/route";
import {listMaterial} from "@/api/system/material";
import dict from "@/utils/dict";
import DictData from "@/components/DictData";
DictData.install();
export default {
name: "",
dicts: ['work_center'],
components: {
Fromed,
Bomfrom
},
props: {
params:{},
showdel: {
type: Boolean,
default: true
},
obj: {
type: Object,
default() {
return {}
}
}
},
data() {
return {
timeUpload: {
open: false,
title: "",
isUploading: false,
headers: {Authorization: "Bearer " + getToken()},
url: process.env.VUE_APP_BASE_API + "/system/route/importDataTime"
},
materialOptions: [], // 用于存储物料信息
showtable: true,
expand: true,
bomData: [],
bomLoading: false,
bomSearchKey: '',
currentMaterial: {
materialCode: '',
materialName: '',
productionOrderNo: ''
},
bomPagination: {
currentPage: 1,
pageSize: 10
},
totalBomCount: 0,
BOMpop: false,
bomList: [],
//expandRowKeys:[],
omdelData: '',
routeDescription: '', // 用于存储 productionOrderNo 的变量
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单禁用
single: true,
// 非多个禁用
multiple: false,
// 显示搜索条件
showSearch: true,
// 显示父级的保存工艺按钮
showParentSaveBtn: null,
// 总条数
total: 0,
form: {
// 工艺路线表格数据
routeList: [],
},
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 工序详情对话框显示状态
processDetailsVisible: false,
// 当前显示的工序列表
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 500,
routeDescription: [],
materialCode: undefined,
materialName: undefined,
bomUnit: undefined,
processNo: undefined,
workCenter: undefined,
processName: undefined,
rawMaterialCode: undefined,
rawMaterialName: undefined,
discWeight: undefined,
discUsage: undefined,
firstBatchQuantity: undefined,
processDescription: undefined,
processControl: undefined,
activityDuration: undefined,
activityUnit: undefined,
},
// 对应关系映射:工序名称 -> 工作中心
processToWorkCenterMap: {
// 铆焊工段
'数控火焰下料': '铆焊工段',
'数控激光下料': '铆焊工段',
'数控切管下料': '铆焊工段',
'水虎鱼剪折冲': '铆焊工段',
'锯床下料': '铆焊工段',
'抛丸': '铆焊工段',
'组焊': '铆焊工段',
'普车': '机一工段',
'普铣': '机一工段',
'龙门铣': '机一工段',
'立磨': '机一工段',
'平磨': '机一工段',
'钻床': '机一工段',
'数车': '机二工段',
'数控外圆磨': '机二工段',
'走芯机': '机二工段',
'双主轴': '机二工段',
'车铣复合': '机二工段',
'线切割': '机二工段',
'卧加63': '机三工段',
'5032龙门': '机三工段',
'3018龙门': '机三工段',
'2013龙门': '机三工段',
'立加1370': '机三工段',
'立加1177': '机三工段',
'立加850': '机三工段',
'数插5035': '机三工段',
'装配1': '装一工段',
'装配2': '装二工段',
'电装': '电钳工段',
'正火': '委外中心',
'回火': '委外中心',
'调质': '委外中心',
'真空调质': '委外中心',
'整体淬火': '委外中心',
'表面淬火': '委外中心',
'真空淬火': '委外中心',
'渗碳淬火': '委外中心',
'渗氮': '委外中心',
'碳氮共渗': '委外中心',
'制齿': '委外中心',
'电火花': '委外中心',
'插床': '委外中心',
'按图订制': '委外中心',
'磷化处理': '委外中心',
'发蓝处理': '委外中心',
'QPQ处理': '委外中心',
'镀锌': '委外中心',
'镀硬铬': '委外中心',
'镀锌镍合金': '委外中心',
'阳极氧化': '委外中心',
'达克罗': '委外中心',
'喷漆': '委外中心',
'喷塑': '委外中心',
'喷砂': '委外中心',
'喷砂底漆': '委外中心'
},
// 表单参数
projectCodes: [], // 存储查询到的项令号
processName: [],
activeRows: [], // 转换为列表的数据
config: {
elementSeletor: "tbody", //元素选择
filter: ".filtered", // 过滤
onEnd: (event, oldValue, newValue) => {
// 找到父节点
const parentIndex = this.form.routeList.findIndex(item =>
item.children && item.children.some(child => child.id === newValue.id)
);
if (parentIndex !== -1) {
// 获取子节点列表
const children = this.form.routeList[parentIndex].children;
// 重新排序工序号
children.forEach((child, index) => {
child.processNo = (index + 1) * 10;
});
}
},
},
upload: {
// 是否显示弹出层
open: false,
// 弹出层标题
title: "",
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: {Authorization: "Bearer " + getToken()},
// 上传的地址
url: process.env.VUE_APP_BASE_API + "/system/route/importData"
},
id: 0,//动态增加表格列的ID
// 表单校验
rules: {
id: [
{required: true, message: "主键ID不能为空", trigger: "blur"}
],
routeDescription: [
{required: true, message: "工艺路线描述不能为空", trigger: "blur"}
],
materialCode: [
{required: true, message: "物料编码不能为空", trigger: "blur"}
],
materialName: [
{required: true, message: "物料名称不能为空", trigger: "blur"}
],
processControl: [ // 添加工序控制码的验证
{required: true, message: "工序控制码不能为空", trigger: "blur"}
],
processName: [ // 添加工序名称的验证
{required: true, message: "工序名称不能为空", trigger: "blur"}
],
activityDuration: [ // 添加活动时长的验证
{required: true, message: "活动时长不能为空", trigger: "blur"}
]
},
bomDialogVisible: false,
bomDialogTitle: '',
bomForm: {
id: undefined,
projectNumber: '', // 添加项目令号
materialCode: '',
materialName: '',
materialType: '',
quantity: 0,
unit: '',
stock: 0,
parentMaterialCode: '', // 添加父级物料编码
parentMaterialName: '', // 添加父级物料名称
},
bomRules: {
materialName: [
{required: true, message: '请输入物料名称', trigger: 'blur'}
],
materialCode: [
{required: true, message: '请输入物料编码', trigger: 'blur'}
],
materialType: [
{required: true, message: '请选择材质', trigger: 'change'}
],
unit: [
{required: true, message: '请选择单位', trigger: 'change'}
],
quantity: [
{required: true, message: '请输入用量', trigger: 'blur'}
],
projectNumber: [
{required: true, message: '项目令号不能为空', trigger: 'blur'}
],
parentMaterialCode: [
{required: true, message: '父级物料编码不能为空', trigger: 'blur'}
],
parentMaterialName: [
{required: true, message: '父级物料名称不能为空', trigger: 'blur'}
],
stock: [
{required: true, message: '库存不能为空', trigger: 'blur'}
]
},
selectedBomRows: [],
materialSearchLoading: false,
materialQuery: '', // 当前搜索关键字
materialPagination: {
pageNum: 1,
pageSize: 10,
total: 0
},
materialLoading: false, // 加载更多状态
hasMoreMaterial: true, // 是否还有更多数据
activeTab: 'bom', // 当前激活的标签页
processRouteData: [], // 工艺路线数据
processLoading: false, // 工艺信息加载状态
processRoutes: [], // 所有工艺路线
selectedRouteId: null, // 当前选中的工艺路线ID
selectedRoute: null, // 当前选中的工艺路线完整信息
currentProcessList: [], // 当前显示的工序列表
dataList: [], // 存储获取到的数据
routeGroupName: ''
};
},
created() {
this.queryParams.routeDescription = "";
console.log(this.params)
if (this.params && this.params.productionOrderNo) {
this.queryParams.routeDescription = this.params.productionOrderNo;
}
// const productionOrderNo = this.params.productionOrderNo;
// if (productionOrderNo) {
// this.queryParams.routeDescription = productionOrderNo;
// } else {
// }
this.getList();
},
watch: {
'$route.query.productionOrderNo': function (newVal) {
// 当路由参数 productionOrderNo 变化时,重新获取
this.setTotalWeight();
this.getList();
// 设置查询参数中的 routeDescription
if (newVal) {
this.queryParams.routeDescription = newVal;
}
}
},
mounted() {
this.rowDrop();
},
computed: {
filteredBomData() {
if (!this.bomSearchKey) return this.bomData;
const searchKey = this.bomSearchKey.toLowerCase();
return this.bomData.filter(item => {
return Object.values(item).some(value =>
String(value).toLowerCase().includes(searchKey)
);
});
}
},
methods: {
// dict,
getKindeeExcel() {
// 显示加载状态
const loadingInstance = this.$loading({
lock: true,
text: '正在获取已投放的工艺数据...',
spinner: 'el-icon-loading',
background: 'rgba(255, 255, 255, 0.7)',
});
this.loading = true;
// 调用 reset 方法,重置表单或状态
this.reset();
// 获取生产订单号
const rooteProdet = this.params.productionOrderNo;
// 调用 getKindeeExcel 方法
getKindeeExcel(rooteProdet)
.then(data => {
// 处理返回的数据
this.$message.success('获取工艺成功!');
})
.catch(error => {
this.$message.error(error.message); // 显示错误消息
})
.finally(() => {
// 关闭加载状态
loadingInstance.close();
this.loading = false; // 关闭 loading 状态
});
this.handleBomRefresh();
},
getAllRouteAndUse() {
// 显示加载状态
const loadingInstance = this.$loading({
lock: true,
text: '正在获取全部工艺数据...',
spinner: 'el-icon-loading',
background: 'rgba(255, 255, 255, 0.7)',
});
this.loading = true;
// 调用 reset 方法,重置表单或状态
this.reset();
// 获取生产订单号
const rooteProdet = this.params.productionOrderNo;
// 调用 getAllRouteAndUse 方法
getAllRouteAndUse(rooteProdet)
.then(data => {
// 处理返回的数据
this.$message.success('获取全部工艺成功!');
})
.catch(error => {
this.$message.error(error.message); // 显示错误消息
})
.finally(() => {
// 关闭加载状态
loadingInstance.close();
this.loading = false; // 关闭 loading 状态
});
this.handleBomRefresh();
},
// 处理工作中心变化
handleWorkCenterChange(scope) {
const {row} = scope;
const currentIndex = this.form.routeList.findIndex(item => item === row);
// 移除自动设置工序控制码的逻辑
// 只需记录工作中心的变化,不再自动填写
console.log("工作中心变化:", row.workCenter);
},
// 验证工序控制
validateProcessControl(row, index) {
// 验证逻辑保持不变
if (row.workCenter === '委外中心' && row.processControl !== '委外+质量') {
return {
valid: false,
message: '委外中心的工序控制必须为"委外+质量"',
correctValue: '委外+质量'
};
}
if (index > 0) {
const previousRow = this.form.routeList[index - 1];
if (previousRow.workCenter === row.workCenter &&
previousRow.workCenter !== '委外中心' &&
row.processControl !== '汇报+免检') {
return {
valid: false,
message: '与上道工序工作中心相同时,工序控制应为"汇报+免检"',
correctValue: '汇报+免检'
};
}
}
return {valid: true};
},
// 开始编辑行
handleRowEdit(scope) {
// 保存原始数据
scope.row.originalData = JSON.parse(JSON.stringify(scope.row));
// 设置编辑状态
this.$set(scope.row, 'isEdit', true);
// 如果是委外中心,确保工序控制正确
if (scope.row.workCenter === '委外中心') {
this.$set(scope.row, 'processControl', '委外+质量');
}
},
// 判断工序控制是否应该禁用
isProcessControlDisabled(row, index) {
return row.workCenter === '委外中心' || this.shouldBeAutoFreeInspection(row, index);
},
// 设置工序控制
setProcessControl(row, index) {
console.log('进入setProcessControl方法'); // 添加日志
if (row.workCenter === '委外中心') {
console.log('设置委外+质量'); // 添加日志
this.$set(row, 'processControl', '委外+质量');
} else if (this.shouldBeAutoFreeInspection(row, index)) {
console.log('设置汇报+免检'); // 添加日志
this.$set(row, 'processControl', '汇报+免检');
}
},
// 验证工序控制
// 判断是否应该自动设置为免检
shouldBeAutoFreeInspection(row, index) {
if (!row.parentId || index === 0 || row.workCenter === '委外中心') {
return false;
}
// 获取上一道工序
const parent = this.form.routeList.find(item => item.id === row.parentId);
if (!parent || !parent.children) {
return false;
}
const currentIndex = parent.children.findIndex(item => item === row);
if (currentIndex <= 0) {
return false;
}
const prevProcess = parent.children[currentIndex - 1];
return prevProcess && prevProcess.workCenter === row.workCenter;
},
/** 导入时间按钮操作 */
handleImportTime() {
this.timeUpload.title = "导入时间";
this.timeUpload.open = true;
},
// 处理时间文件上传进度
handleTimeFileUploadProgress(event, file, fileList) {
this.timeUpload.isUploading = true;
},
// 处理时间文件上传成功
handleTimeFileSuccess(response, file, fileList) {
this.timeUpload.open = false;
this.timeUpload.isUploading = false;
this.$refs.timeUpload.clearFiles();
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>"
+ response.msg + "</div>", "导入结果", {dangerouslyUseHTMLString: true});
this.getList();
},
// 提交时间文件上传
submitTimeFileForm() {
this.$refs.timeUpload.submit();
},
rowDrop() {
const tbody = document.querySelector('.el-table__body-wrapper tbody');
const _this = this;
// Sortable.create(tbody, {
// onEnd({newIndex, oldIndex}) {
// const currRow = _this.form.routeList[oldIndex];
// // 只处理子工序
// if (currRow.parentId) {
// const parentIndex = _this.form.routeList.findIndex(item => item.id === currRow.parentId);
// if (parentIndex > -1) {
// const children = _this.form.routeList[parentIndex].children;
// // 移动数组元素
// const targetRow = children.splice(oldIndex, 1)[0];
// children.splice(newIndex, 0, targetRow);
// // 重新计算工序号
// children.forEach((item, index) => {
// item.processNo = (index + 1) * 10; // 按10、20、30...排序
// });
// }
// }
// },
// filter: ".filtered" // 过滤掉父节点
// });
},
reorderProcessNo() {
this.form.routeList.forEach(parent => {
if (parent.children && parent.children.length) {
parent.children.forEach((child, index) => {
child.processNo = index + 1; // 使用下标+1
});
}
});
},
// BOM抽屉相关方法
bomClose(done) {
// 直接清空数据并关闭
this.bomData = [];
this.currentMaterial = {
materialCode: '',
materialName: '',
productionOrderNo: ''
};
done();
},
handleBomSearch() {
this.bomPagination.currentPage = 1;
},
handleBomRefresh() {
this.fetchBomInfo().then(response => {
this.bomData = response || [];
this.totalBomCount = this.bomData.length;
}).catch(error => {
this.$message.error('获取BOM数据失败');
this.bomData = [];
}).finally(() => {
this.bomLoading = false;
});
},
handleBomExport() {
this.download('system/bom/export', {
materialCode: this.currentMaterial.materialCode,
materialName: this.currentMaterial.materialName,
productionOrderNo: this.currentMaterial.productionOrderNo
}, `bom_${new Date().getTime()}.xlsx`);
},
handleBomSizeChange(val) {
this.bomPagination.pageSize = val;
},
handleBomCurrentChange(val) {
this.bomPagination.currentPage = val;
},
handleProcessNameChange(scope) {
console.log(scope)
const selectedProcessName = scope.row.processName;
console.log(selectedProcessName)
if (this.processToWorkCenterMap[selectedProcessName]) {
scope.row.workCenter = this.processToWorkCenterMap[selectedProcessName];
} else {
scope.row.workCenter = '';
}
},
handleQuery3(query) {
if (query === '') {
this.processName = [];
return;
}
// 开始加载
this.loading = true;
// 调用后端接口获取匹配的项目令号
getProcessInfoList(query).then((response) => {
// 加载完成
this.loading = false;
this.processName = response;
}).catch(() => {
this.loading = false; // 加载失败
this.processName = []; // 如果请求失败,清空选项
});
},
// 控制表格可移动部分
tableRowClassName({row, rowIndex}) {
// 过滤掉父节点
if (!row.parentId) {
return "filtered";
}
return "";
},
// 添加子集
onAddChild(props) {
// 是否为父级,返回父级所在下标
var index = this.form.routeList.findIndex(item => item.id === props.row.id);
// -1为未检索到不为父级
if (index === -1) {
alert("刷新试试,为检索到此目录,可能不存在")
return;
}
var routeList = this.form.routeList[index].children;
var route = routeList.sort(function (a, b) {
return a.processNo - b.processNo
})[routeList.length - 1];
var processNo = !route ? 0 : route.processNo + 10;
//routeList.push({ id: --this.id, parentId: props.row.id, processNo: processNo, children: null });
//this.showParentSaveBtn = props.row.id;
const newRow = {
id: --this.id,
parentId: props.row.id,
processNo: processNo,
children: null
};
routeList.push(newRow);
this.showParentSaveBtn = props.row.id;
// 添加新行后,监听工作中心变化
this.$nextTick(() => {
if (newRow.workCenter) {
this.setProcessControl(newRow, routeList.length - 1);
}
});
},
// 删除子集
onDelete(props) {
// 获取父级的所在下标
var index = this.form.routeList.findIndex(item => item.id === props.row.parentId);
// 获取子集的所在下标
var childrenIndex = this.form.routeList[index].children.findIndex(item => item.id === props.row.id);
// 找到子集并删除
this.form.routeList[index].children.splice(childrenIndex, 1);
// 修改其它子集的工序号
for (let i = 0; i < this.form.routeList[index].children.length; i++) {
// 修改子集中工序号
this.form.routeList[index].children[i].processNo = (i + 1) * 10;
}
},
// 修改现有的cellhand方法
cellhand(row, column) {
// 只在点击物料编码列时触发
if (column.property === 'materialCode') {
this.BOMpop = true;
this.bomLoading = true;
this.processLoading = true;
// 设置当前物料信息
this.currentMaterial = {
materialCode: row.materialCode,
materialName: row.materialName,
productionOrderNo: this.params.productionOrderNo
};
// 调用获取BOM信息的接口
getBomInfo(
row.materialCode,
row.materialName,
this.currentMaterial.productionOrderNo
)
.then(response => {
this.bomData = response || [];
this.totalBomCount = this.bomData.length;
})
.catch(error => {
console.error('获取BOM数据失败:', error);
this.$message.error('获取BOM数据失败');
this.bomData = [];
})
.finally(() => {
this.bomLoading = false;
});
// 获取工艺信息
this.getProcessRouteList();
}
},
setTotalWeight() {
const totalWeight = this.params.productionOrderNo;
if (totalWeight) {
this.queryParams.totalWeight = totalWeight;
}
},
/** 查询工艺路线列表 */
// 修改原有的 getList 方法,获取列表后自动刷新库存
async getList() {
this.loading = true;
try {
const response = await listRoute(this.queryParams);
this.form.routeList = response.rows;
this.total = response.total;
} catch (error) {
console.error('获取数据失败:', error);
} finally {
this.loading = false;
}
},
// 表单重置
reset() {
this.form = {
id: undefined,
// 物料信息
materialCode: undefined,
materialName: undefined,
material: undefined,
discWeight: undefined,
bomUnit: undefined,
unitQuantity: undefined,
batchQuantity: undefined,
firstBatchQuantity: undefined,
// 工艺信息
workCenter: undefined,
processName: undefined,
processDescription: undefined,
processControl: undefined,
activityDuration: undefined,
activityUnit: undefined,
xuStartTime: undefined,
xuEndTime: undefined
};
this.resetForm("form");
},
/** 导入钮操作 */
handleImport() {
this.upload.title = "工艺导入";
this.upload.open = true;
},
/** 下载模板操作 */
importTemplate() {
this.download('system/route/importTemplate', {}, `route_template_${new Date().getTime()}.xlsx`)
},
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true;
},
// 文件上传成功处理
handleFileSuccess(response, file, fileList) {
this.upload.open = false;
this.upload.isUploading = false;
this.$refs.upload.clearFiles();
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>"
+ response.msg + "</div>", "导入结果", {dangerouslyUseHTMLString: true});
this.getList();
},
// 提交上传文件
submitFileForm() {
this.$refs.upload.submit();
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
handleQuery1(query) {
if (query === '') {
this.projectCodes = []; // 如果没有输入任何关键字,清空选项
return;
}
// 开始加载
this.loading = true;
// 调用后端接口获取匹配的项目令号
getDistinctProjectCodes(query).then((response) => {
// 加载完成
this.loading = false;
this.projectCodes = response;
}).catch(() => {
this.loading = false; // 加载失败
this.projectCodes = []; // 如果请求失败,清空选项
});
},
//获取工序列表
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加工艺路线";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
const id = row.id || this.ids;
getRoute(id).then(response => {
this.loading = false;
// 只提取工艺相关字段
const {workCenter, processName, processDescription, processControl, activityDuration} = response.data;
this.form = {
...this.form, // 保留现有数据
id: id,
workCenter,
processName,
processDescription,
processControl,
activityDuration
};
this.open = true;
this.title = "修改工艺信息";
}).catch(() => {
this.loading = false;
});
},
/**推送工艺 */
async pushRouteBom() {
// 获取生产订单号
const productionOrderNo = this.params.productionOrderNo;
if (!productionOrderNo) {
this.$modal.msgError("未获取到生产订单号,请检查!");
return;
}
if (!this.routeGroupName || !this.routeGroupName.trim()) {
this.$modal.msgError("请填写分组名称!");
return;
}
try {
// 显示确认对话框
await this.$confirm(
'推送工艺可能需要较长时间,请耐心等待。是否继续?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
);
// 显示全屏 loading
const loading = this.$loading({
lock: true,
text: '正在推送工艺,请稍候...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
// 重置表单状态
this.reset();
// 设置超时检测
const timeout = 600000; // 10分钟超时
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
reject(new Error('推送操作超时,请检查后台处理状态'));
}, timeout);
});
// 调用推送 API 并设置超时
const response = await Promise.race([
pushRouteBom(productionOrderNo, this.routeGroupName.trim()),
timeoutPromise
]);
// 处理后端返回的数据 - 适配新的返回结构 R<ProcessRoutePushResultDTO>
const {duplicateRoutes, failedRoutes, successfulRoutes} = response.data;
// 提取物料编码和错误信息
const duplicateCodes = duplicateRoutes.join(', ');
const failedInfo = failedRoutes.map(route =>
`${route.materialCode} (${route.errorMessage || '未知错误'})`
).join(', ');
const successfulCodes = successfulRoutes.map(route => route.materialCode).join(', ');
// 显示成功消息
this.$alert(`
<div><strong>成功 (${successfulRoutes.length}):</strong></div>
<div style="margin-left: 20px;">${successfulCodes || '无'}</div>
<div><strong>失败 (${failedRoutes.length}):</strong></div>
<div style="margin-left: 20px;">${failedInfo || '无'}</div>
<div><strong>重复 (${duplicateRoutes.length}):</strong></div>
<div style="margin-left: 20px;">${duplicateCodes || ''}</div>
`, '推送完成', {
dangerouslyUseHTMLString: true,
confirmButtonText: '确定'
});
// 刷新列表
await this.getList();
// 关闭 loading
loading.close();
} catch (error) {
// 错误处理
console.error('[推送工艺失败]:', error);
// 显示错误通知
this.$notify({
title: '推送失败',
message: error.message || '推送失败请重试!',
type: 'error',
duration: 0,
showClose: true
});
} finally {
// 确保 loading 被关闭
if (this.$loading) {
this.$loading().close();
}
this.loading = false;
}
},
/** 更新计划时间间*/
updateProcessPlan(row) {
// 若未勾选任何行则提示并返回
if (!this.ids || this.ids.length === 0) {
this.$modal.msgError("请先勾选至少一条数据再更新计划时间");
return;
}
// 显示加载状态
this.loading = true;
// 调用 reset 方法重置表单或状态
this.reset();
// 获取生产订单号
const rooteProdet = this.params.productionOrderNo;
//获取物料编码
const materialCode = this.params.materialCode;
console.log(rooteProdet);
// 调用封装好的 API 方法带勾选的 ids
updateProcessPlan(rooteProdet, this.ids)
.then(response => {
// 假设后端返回的数据可以直接赋值给表单
this.form = response;
// 弹出成功消息
this.$modal.msgSuccess("更新" + rooteProdet + "工序计划时间成功");
// 调用方法更新列表
this.getList();
})
.catch(error => {
// 处理错误,弹出错误提示
this.$modal.msgError("更新,请重试!");
console.error('更新工序计划失败:', error);
})
.finally(() => {
// 隐藏加载状态
this.loading = false;
});
},
/** 更新生产订单时间*/
updateProcesTime(row) {
// 显示加载状态
this.loading = true;
// 调用 reset 方法,重置表单或状态
this.reset();
// 获取生产订单号
const rooteProdet = this.params.productionOrderNo;
console.log(rooteProdet);
// 调用封装好的 API 方法
updateProcesTime(rooteProdet)
.then(response => {
// 假设后端返回的数据可以直接赋值给表单
this.form = response;
// 弹出成功消息
this.$modal.msgSuccess("更新" + rooteProdet + "生产订单成功");
// 调用方法更新列表
this.getList();
})
.catch(error => {
// 处理错误,弹出错误提示
this.$modal.msgError("更新,请重试!");
console.error('更新生产订单失败:', error);
})
.finally(() => {
// 隐藏加载状态
this.loading = false;
});
},
generatePDFs1(row) {
// 显示加载状态
this.loading = true;
// 调用 reset 方法,重置表单或状态
this.reset();
// 获取生产订单号
const rooteProdet = this.params.productionOrderNo;
console.log(rooteProdet);
// 调用封装好的 API 方法
generatePDFs(rooteProdet)
.then(response => {
let blob = new Blob([response], {type: 'application/zip'})
let url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签
link.href = url
link.download = rooteProdet + '.zip' // 重命名文件
link.click()
URL.revokeObjectURL(url) // 释放内存
// 弹出成功消息
this.$modal.msgSuccess("生成" + rooteProdet + "的PDF 成功 ");
// 调用方法更新列表
this.getList();
})
.catch(error => {
// 处理错误,弹出错误提示
this.$modal.msgError("生成PDF失败请重试");
console.error('生成PDF失败:', error);
})
.finally(() => {
// 隐藏加载状态
this.loading = false;
});
},
/** 提交按钮 */
submitForm() {
this.$refs.form.validate(valid => {
if (valid) {
// 提交逻辑
this.buttonLoading = true;
if (this.form.id != null) {
updateRoute(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addRoute(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
} else {
this.$message.error("请填写必填项");
}
});
},
// 验证所有工序控制
/** 删除按钮操作 */
handleDelete(scope) {
const ids = [scope.row.id];
this.$modal.confirm('是否确认删除工艺路线编号为"' + ids + '"的数据项?').then(() => {
return delRoute(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(error => {
if (error !== 'cancel') {
console.error('Delete error:', error);
this.$modal.msgError("删除失败:" + (error.message || "未知错误"));
}
});
},
/** 导出按钮操作 */
handleExport() {
this.download('system/route/export', {
...this.queryParams
}, `route_${new Date().getTime()}.xlsx`)
},
// BOM选择项改变
handleBomSelectionChange(selection) {
this.selectedBomRows = selection;
},
// 新增BOM
handleBomAdd() {
this.bomDialogTitle = '新增BOM';
this.bomForm = {
id: undefined,
projectNumber: this.currentMaterial.productionOrderNo, // 使用当<E794A8><E5BD93>的项目令号
materialCode: '',
materialName: '',
materialType: '',
quantity: 0,
unit: '',
stock: 0,
parentMaterialCode: this.currentMaterial.materialCode, // 使用当前物料作为父级
parentMaterialName: this.currentMaterial.materialName
};
this.bomDialogVisible = true;
},
// 修改BOM
handleBomEdit(row) {
this.bomDialogTitle = '修改BOM';
this.bomForm = JSON.parse(JSON.stringify(row));
this.bomDialogVisible = true;
},
// 删除BOM
handleBomDelete(row) {
this.$confirm('是否确认删除该BOM数据?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return deleteBom(row.id);
}).then(() => {
this.$message.success('删除成功');
this.handleBomRefresh();
}).catch(() => {
});
},
// 提交BOM表单
submitBomForm() {
this.$refs.bomForm.validate((valid) => {
if (valid) {
const isUpdate = this.bomForm.id !== undefined;
const promise = isUpdate ? updateBom(this.bomForm) : addBom(this.bomForm);
promise.then(() => {
this.$message.success(isUpdate ? '修改成功' : '新增成功');
this.bomDialogVisible = false;
this.handleBomRefresh();
}).catch(() => {
this.$message.error(isUpdate ? '修改失败' : '新增失败');
});
}
});
},
fetchBomInfo() {
return getBomInfo(
this.currentMaterial.materialCode,
this.currentMaterial.materialName,
this.currentMaterial.productionOrderNo
);
},
// 处理物料搜
handleMaterialSearch(queryString, callback) {
if (queryString.length === 0) {
callback([]);
return;
}
this.materialSearchLoading = true;
listMaterial({
pageNum: 1,
pageSize: 10,
materialName: queryString
}).then(response => {
const suggestions = response.rows.map(item => ({
materialName: item.materialName,
materialCode: item.materialCode,
materialType: item.materialQuality,
classificationName: item.classificationName,
singleWeight: item.singleWeight || 0
}));
callback(suggestions);
}).catch(() => {
callback([]);
}).finally(() => {
this.materialSearchLoading = false;
});
},
// 处理物料选择
handleMaterialSelect(item) {
if (item) {
// 如果是从建议中选择
this.bomForm.materialName = item.materialName;
this.bomForm.materialCode = item.materialCode;
this.bomForm.materialType = item.materialType;
this.bomForm.stock = item.singleWeight;
this.bomForm.unit = item.classificationName;
}
},
// 取消编辑
cancelEdit(scope) {
// 恢复原始数据
Object.assign(scope.row, scope.row.originalData);
// 退出编辑状态
this.$set(scope.row, 'isEdit', false);
},
// 保存单行数据
onSaveRow(scope) {
// 显示加载状态
this.loading = true;
// 获取行数据并创建副本
const row = scope.row;
// 验证委外中心的工序控制
const saveData = {
id: row.id,
parentId: row.parentId,
routeDescription: row.routeDescription,
materialCode: row.materialCode,
materialName: row.materialName,
unit: row.unit,
processNo: row.processNo,
bomMaterial: row.bomMaterial,
workCenter: row.workCenter,
processName: row.processName,
rawMaterialCode: row.rawMaterialCode,
rawMaterialName: row.rawMaterialName,
discWeight: row.discWeight,
discUsage: row.discUsage,
processDescription: row.processDescription,
processControl: row.processControl,
activityDuration: row.activityDuration,
activityUnit: row.activityUnit,
material: row.material,
bomUnit: row.bomUnit,
unitQuantity: row.unitQuantity,
batchQuantity: row.batchQuantity,
firstBatchQuantity: row.firstBatchQuantity,
planStartTime: row.planStartTime,
planEndTime: row.planEndTime,
xuStartTime: row.xuStartTime,
xuEndTime: row.xuEndTime
};
// 显示加载状态
this.loading = true;
// 调用更新接口
updateRoute(saveData)
.then(response => {
this.$modal.msgSuccess("修改成功");
// 退出编辑状态
this.$set(row, 'isEdit', false);
// 刷新列表
this.getList();
})
.catch(error => {
this.$modal.msgError("修改失败:" + (error.message || "未知错误"));
})
.finally(() => {
this.loading = false;
});
},
// 同样修改整体保存方法
onSave(props) {
this.$confirm('确认保存工艺路线数据?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.loading = true;
var list = this.form.routeList.find(item => item.id === props.row.id);
var newChildrenList = list.children.filter(item => item.id < 0).map(v => ({
id: v.parentId,
routeDescription: list.routeDescription,
materialCode: list.materialCode,
materialName: list.materialName,
unit: list.unit,
processNo: v.processNo,
bomMaterial: list.bomMaterial,
workCenter: v.workCenter,
processName: v.processName,
rawMaterialCode: list.rawMaterialCode,
rawMaterialName: list.rawMaterialName,
discWeight: list.discWeight,
discUsage: list.discUsage,
processDescription: v.processDescription,
processControl: v.processControl,
activityDuration: v.activityDuration,
activityUnit: v.activityUnit,
material: list.material,
bomUnit: list.bomUnit,
unitQuantity: list.unitQuantity,
batchQuantity: list.batchQuantity,
firstBatchQuantity: list.firstBatchQuantity,
planStartTime: v.planStartTime,
planEndTime: v.planEndTime,
xuStartTime: v.xuStartTime || null,
xuEndTime: v.xuEndTime || null
}));
return onSave(newChildrenList);
}).then((response) => {
this.$modal.msgSuccess("工艺路线保存成功");
this.showParentSaveBtn = null;
this.getList();
}).catch((error) => {
if (error !== 'cancel') {
this.$modal.msgError(error.message || "工艺路线保存失败");
}
}).finally(() => {
this.loading = false;
});
},
// 删除未保存的工艺
onDeleteUnsaved(scope) {
const parentRow = this.form.routeList.find(item => item.id === scope.row.parentId);
if (parentRow && parentRow.children) {
const index = parentRow.children.findIndex(item => item === scope.row);
if (index > -1) {
// 删除当前行
parentRow.children.splice(index, 1);
// 重新排序剩余的工序号
parentRow.children.forEach((child, idx) => {
child.processNo = (idx + 1) * 10; // 按10、20、30...重新排序
});
}
}
},
// 获取工艺信息列表
getProcessRouteList() {
this.processLoading = true;
getProcessRouteList(
this.currentMaterial.materialCode,
this.currentMaterial.materialName,
this.currentMaterial.productionOrderNo
)
.then(response => {
this.processRoutes = response || [];
// 默认选中第一条工艺路线
if (this.processRoutes.length > 0) {
this.handleViewRoute(this.processRoutes[0]);
}
})
.catch(error => {
console.error('获取工艺路线数据失败:', error);
this.$message.error('获取工艺路线数据失败');
this.processRoutes = [];
this.resetRouteSelection();
})
.finally(() => {
this.processLoading = false;
});
},
// 查看工艺路线
handleViewRoute(route) {
this.selectedRouteId = route.id;
this.selectedRoute = route;
this.currentProcessList = route.processRouteDT || [];
},
// 重置工艺路线选择
resetRouteSelection() {
this.selectedRouteId = null;
this.selectedRoute = null;
this.currentProcessList = [];
}
},
// 处理工艺路线选择变化
handleRouteChange(routeId) {
const route = this.processRoutes.find(r => r.id === routeId);
if (route) {
this.selectedRoute = route;
this.currentProcessList = route.processRouteDT || [];
} else {
this.selectedRoute = null;
this.currentProcessList = [];
}
},
};
</script>
<style>
.btn {
font-size: 12px;
padding: 7px 10px !important;
border-radius: 0;
}
.handle {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-size: 20px;
border: none;
background-color: #FAFAFA;
}
.bom-header {
margin-bottom: 15px;
}
.table-operations {
display: flex;
justify-content: space-between;
align-items: center;
}
.pagination-container {
display: flex;
justify-content: flex-end;
}
.table-operations {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.left-operations,
.right-operations {
display: flex;
align-items: center;
}
.right-operations .el-button {
margin-left: 8px;
}
.material-select-dropdown {
max-height: 300px !important;
}
.material-select-dropdown .el-select-dropdown__wrap {
max-height: 300px !important;
}
.material-autocomplete-dropdown {
min-width: 500px !important;
/* 设置下拉框最小宽度 */
}
.material-suggestion-item {
padding: 8px 10px;
border-bottom: 1px solid #eee;
}
.material-suggestion-item:last-child {
border-bottom: none;
}
.material-name {
font-size: 14px;
color: #303133;
margin-bottom: 4px;
}
.material-info {
font-size: 12px;
color: #909399;
}
.material-info span {
margin-right: 15px;
}
.material-info span:last-child {
margin-right: 0;
}
/* 调整输入框宽度 */
.el-form-item[label="物料名称"] .el-autocomplete {
width: 100%;
}
/* 可以添加一些提示样式 */
.el-select.is-disabled .el-input__inner {
background-color: #f5f7fa;
border-color: #e4e7ed;
color: #909399;
cursor: not-allowed;
}
</style>