- 将多个页面中的班组输入框替换为下拉选择框,提供甲、乙两个选项 - 调整标签预览组件的样式,移除部分内边距和边框 - 修改数值输入框的v-model绑定方式,移除.number修饰符
1054 lines
30 KiB
Vue
1054 lines
30 KiB
Vue
<template>
|
||
<div class="split-coil-container">
|
||
<!-- 顶部操作栏 -->
|
||
<div class="header-bar">
|
||
<div class="header-title">
|
||
<i class="el-icon-s-operation"></i>
|
||
<span>钢卷分条</span>
|
||
</div>
|
||
<div class="header-actions">
|
||
<el-button v-if="!readonly" type="primary" size="small" @click="handleSave" :loading="loading">保存分条</el-button>
|
||
<el-button size="small" @click="handleCancel" :disabled="loading">{{ readonly ? '返回' : '取消' }}</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 流程图区域 -->
|
||
<div class="flow-container">
|
||
<!-- 左侧:母卷信息 -->
|
||
<div class="flow-left">
|
||
<div class="flow-section-title">
|
||
<span>母卷信息</span>
|
||
</div>
|
||
<div class="coil-card mother-coil">
|
||
<div class="coil-header">
|
||
<i class="el-icon-s-grid"></i>
|
||
<span class="coil-title">钢卷信息</span>
|
||
</div>
|
||
<div class="coil-body">
|
||
<div class="coil-info-row">
|
||
<span class="label">入场钢卷号:</span>
|
||
<span class="value">{{ motherCoil.enterCoilNo || '—' }}</span>
|
||
</div>
|
||
<div class="coil-info-row">
|
||
<span class="label">当前钢卷号:</span>
|
||
<span class="value">{{ motherCoil.currentCoilNo || '—' }}</span>
|
||
</div>
|
||
<div class="coil-info-row">
|
||
<span class="label">当前库区:</span>
|
||
<span class="value">{{ motherCoil.warehouseName || '未分配' }}</span>
|
||
</div>
|
||
<div class="coil-info-row">
|
||
<span class="label">班组:</span>
|
||
<span class="value">{{ motherCoil.team || '—' }}</span>
|
||
</div>
|
||
<div class="coil-info-row" v-if="motherCoil.materialName || motherCoil.productName">
|
||
<span class="label">物料名称:</span>
|
||
<span class="value">{{ motherCoil.materialName || motherCoil.productName || '—' }}</span>
|
||
</div>
|
||
<div class="coil-info-row">
|
||
<span class="label">毛重:</span>
|
||
<span class="value">{{ motherCoil.grossWeight ? motherCoil.grossWeight + ' t' : '—' }}</span>
|
||
</div>
|
||
<div class="coil-info-row">
|
||
<span class="label">净重:</span>
|
||
<span class="value">{{ motherCoil.netWeight ? motherCoil.netWeight + ' t' : '—' }}</span>
|
||
</div>
|
||
|
||
<!-- 参数参数展示 -->
|
||
<template v-if="motherCoil.bomItems && motherCoil.bomItems.length > 0">
|
||
<el-divider content-position="left" style="margin: 15px 0 10px;">参数信息</el-divider>
|
||
<div class="bom-params">
|
||
<div class="param-item" v-for="(param, index) in motherCoil.bomItems" :key="index">
|
||
<span class="param-name">{{ param.attrKey }}:</span>
|
||
<span class="param-value">{{ param.attrValue }}</span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 中间:流程箭头 -->
|
||
<div class="flow-middle">
|
||
<div class="flow-arrow-container">
|
||
<div class="arrow-line" v-for="(item, index) in splitList" :key="index">
|
||
<div class="arrow-start"></div>
|
||
<div class="arrow-body"></div>
|
||
<div class="arrow-end"></div>
|
||
</div>
|
||
</div>
|
||
<div class="flow-label">
|
||
<i class="el-icon-d-arrow-right"></i>
|
||
<span>分割</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧:子卷列表 -->
|
||
<div class="flow-right">
|
||
<div class="flow-section-title">
|
||
<span>子卷列表</span>
|
||
<div>
|
||
<el-button v-if="!readonly" type="text" size="mini" @click="copyToAllSubCoils"
|
||
icon="el-icon-document-copy">复制到全部</el-button>
|
||
<el-button v-if="!readonly" type="text" size="mini" @click="addSplitItem"
|
||
icon="el-icon-plus">添加子卷</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="split-list">
|
||
<div class="sub-coil-card" v-for="(item, index) in splitList" :key="index">
|
||
<div class="sub-coil-header">
|
||
<span class="sub-coil-number">{{ index + 1 }}</span>
|
||
<el-button v-if="!readonly" type="text" size="mini" icon="el-icon-delete" @click="removeSplitItem(index)"
|
||
class="btn-remove"></el-button>
|
||
</div>
|
||
<div class="sub-coil-body">
|
||
<el-form size="small" label-width="90px">
|
||
<el-form-item label="卷号" required>
|
||
<el-input v-model="item.currentCoilNo" placeholder="输入子卷卷号" :disabled="readonly"></el-input>
|
||
</el-form-item>
|
||
<el-form-item label="班组" required>
|
||
<el-select v-model="item.team" placeholder="请选择班组" style="width: 100%"
|
||
:disabled="readonly">
|
||
<el-option key="甲" label="甲" value="甲" />
|
||
<el-option key="乙" label="乙" value="乙" />
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="材料类型" required>
|
||
<el-select v-model="item.materialType" placeholder="请选择材料类型" style="width: 100%" :disabled="readonly"
|
||
@change="handleMaterialTypeChange(item, index)">
|
||
<el-option label="原料" value="原料" />
|
||
<el-option label="成品" value="成品" />
|
||
<el-option label="废品" value="废品" />
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item v-if="item.materialType === '成品'" label="质量状态" prop="qualityStatus">
|
||
<el-input v-model="item.qualityStatus" placeholder="请输入质量状态" :disabled="readonly">
|
||
</el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item v-if="item.materialType === '成品'" label="切边要求" prop="trimmingRequirement">
|
||
<el-input v-model="item.trimmingRequirement" placeholder="请输入切边要求" :disabled="readonly">
|
||
</el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item v-if="item.materialType === '成品'" label="打包状态" prop="packingStatus">
|
||
<el-input v-model="item.packingStatus" placeholder="请输入打包状态" :disabled="readonly">
|
||
</el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item v-if="item.materialType === '成品'" label="包装要求" prop="packagingRequirement">
|
||
<el-input v-model="item.packagingRequirement" placeholder="请输入包装要求" :disabled="readonly">
|
||
</el-input>
|
||
</el-form-item>
|
||
|
||
<!-- 物品类型由材料类型自动决定,不显示选择框 -->
|
||
<el-form-item :label="getItemLabel(item.materialType)" :required="item.materialType !== '废品'">
|
||
<raw-material-select v-if="item.materialType === '原料' || item.materialType === '废品'"
|
||
v-model="item.itemId" placeholder="请选择原料" style="width: 100%" clearable
|
||
:disabled="readonly || !item.materialType" />
|
||
<product-select v-else-if="item.materialType === '成品'" v-model="item.itemId"
|
||
placeholder="请选择成品" style="width: 100%" clearable
|
||
:disabled="readonly || !item.materialType" />
|
||
<div v-else>请先选择物料类型</div>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="毛重(t)" required>
|
||
<el-input v-model="item.grossWeight" placeholder="请输入毛重" type="number" step="0.01"
|
||
:disabled="readonly">
|
||
<template slot="append">吨</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="净重(t)" required>
|
||
<el-input v-model="item.netWeight" placeholder="请输入净重" type="number" step="0.01"
|
||
:disabled="readonly">
|
||
<template slot="append">吨</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="长度(m)" required>
|
||
<el-input v-model="item.length" placeholder="请输入长度" type="number" step="0.01"
|
||
:disabled="readonly">
|
||
<template slot="append">米</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="逻辑库区" required>
|
||
<WarehouseSelect
|
||
v-model="item.warehouseId"
|
||
placeholder="请选择逻辑库区"
|
||
:disabled="readonly"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="真实库区" required>
|
||
<ActualWarehouseSelect
|
||
v-model="item.actualWarehouseId"
|
||
placeholder="请选择真实库区"
|
||
block
|
||
:disabled="readonly"
|
||
/>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 汇总信息 -->
|
||
<div class="summary-card">
|
||
<div class="summary-item">
|
||
<span class="summary-label">子卷数量:</span>
|
||
<span class="summary-value">{{ splitList.length }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 钢卷选择器 -->
|
||
<coil-selector :visible.sync="coilSelectorVisible" @select="handleCoilSelect" />
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { getMaterialCoil, splitMaterialCoil } from '@/api/wms/coil';
|
||
import { listWarehouse } from '@/api/wms/warehouse';
|
||
import { listRawMaterialWithBom } from '@/api/wms/rawMaterial';
|
||
import { listProductWithBom } from '@/api/wms/product';
|
||
import { completeAction } from '@/api/wms/pendingAction';
|
||
import CoilSelector from '@/components/CoilSelector';
|
||
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
|
||
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
|
||
import ProductSelect from "@/components/KLPService/ProductSelect";
|
||
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
|
||
|
||
export default {
|
||
name: 'SplitCoil',
|
||
components: {
|
||
CoilSelector,
|
||
ActualWarehouseSelect,
|
||
RawMaterialSelect,
|
||
ProductSelect,
|
||
WarehouseSelect,
|
||
},
|
||
data() {
|
||
return {
|
||
// 母卷信息
|
||
motherCoil: {
|
||
coilId: null,
|
||
enterCoilNo: '',
|
||
currentCoilNo: '',
|
||
team: '',
|
||
warehouseId: null,
|
||
warehouseName: '',
|
||
itemType: null,
|
||
itemId: null,
|
||
materialName: '',
|
||
productName: '',
|
||
grossWeight: null,
|
||
netWeight: null,
|
||
bomItems: []
|
||
},
|
||
// 子卷列表
|
||
splitList: [
|
||
{
|
||
currentCoilNo: '',
|
||
team: '',
|
||
materialType: null,
|
||
itemType: null,
|
||
itemId: null,
|
||
grossWeight: null,
|
||
netWeight: null,
|
||
warehouseId: null,
|
||
actualWarehouseId: null,
|
||
length: null,
|
||
}
|
||
],
|
||
loading: false,
|
||
// 钢卷选择器可见性
|
||
coilSelectorVisible: false,
|
||
// 库区列表
|
||
warehouseList: [],
|
||
// 原材料和产品列表(实时搜索,不再保存完整备份)
|
||
rawMaterialList: [],
|
||
productList: [],
|
||
itemSearchLoading: false,
|
||
// 只读模式
|
||
readonly: false,
|
||
// 待操作ID
|
||
actionId: null
|
||
};
|
||
},
|
||
computed: {
|
||
},
|
||
async created() {
|
||
// 先加载库区列表
|
||
await this.loadWarehouses();
|
||
|
||
// 不再一次性加载所有数据,改为实时搜索
|
||
// await this.loadAllItems();
|
||
|
||
// 从路由参数获取coilId、actionId和readonly
|
||
const coilId = this.$route.query.coilId;
|
||
const actionId = this.$route.query.actionId;
|
||
const readonly = this.$route.query.readonly;
|
||
|
||
if (coilId) {
|
||
await this.loadMotherCoil(coilId);
|
||
}
|
||
|
||
// 保存待操作ID
|
||
if (actionId) {
|
||
this.actionId = actionId;
|
||
}
|
||
|
||
// 设置只读模式
|
||
if (readonly === 'true' || readonly === true) {
|
||
this.readonly = true;
|
||
}
|
||
},
|
||
methods: {
|
||
// 处理材料类型变化
|
||
handleMaterialTypeChange(item, index) {
|
||
// 清空物品选择
|
||
this.$set(item, 'itemId', null);
|
||
|
||
// 根据材料类型设置物品类型
|
||
if (item.materialType === '成品') {
|
||
this.$set(item, 'itemType', 'product');
|
||
// 清空列表,等待用户搜索
|
||
this.productList = [];
|
||
} else if (item.materialType === '原料' || item.materialType === '废品') {
|
||
this.$set(item, 'itemType', 'raw_material');
|
||
// 清空列表,等待用户搜索
|
||
this.rawMaterialList = [];
|
||
}
|
||
},
|
||
|
||
// 动态获取标签
|
||
getItemLabel(materialType) {
|
||
if (materialType === '成品') {
|
||
return '产品类型';
|
||
} else if (materialType === '原料' || materialType === '废品') {
|
||
return '原料类型';
|
||
}
|
||
return '物品';
|
||
},
|
||
// 动态获取占位符
|
||
getItemPlaceholder(materialType) {
|
||
if (materialType === '成品') {
|
||
return '请选择产品类型';
|
||
} else if (materialType === '原料') {
|
||
return '请选择原料类型';
|
||
} else if (materialType === '废品') {
|
||
return '请选择原料类型(非必填)';
|
||
}
|
||
return '请先选择材料类型';
|
||
},
|
||
// 获取子卷的物品列表
|
||
getItemListForSplit(itemType) {
|
||
if (itemType === 'raw_material') {
|
||
return this.rawMaterialList.map(item => ({
|
||
id: item.rawMaterialId,
|
||
name: this.formatItemName(item)
|
||
}));
|
||
} else if (itemType === 'product') {
|
||
return this.productList.map(item => ({
|
||
id: item.productId,
|
||
name: this.formatItemName(item)
|
||
}));
|
||
}
|
||
return [];
|
||
},
|
||
|
||
// 格式化物品名称(添加规格和参数信息)
|
||
formatItemName(item) {
|
||
if (!item) return '';
|
||
|
||
// 获取名称(原材料或产品)
|
||
const name = item.rawMaterialName || item.productName || '';
|
||
if (!name) return '';
|
||
|
||
let displayName = name;
|
||
const specs = [];
|
||
|
||
// 1. 优先显示规格(从对象的specification字段)
|
||
if (item.specification) {
|
||
specs.push(item.specification);
|
||
}
|
||
|
||
// 2. 添加参数参数(最多2个)
|
||
if (item.bomItems && item.bomItems.length > 0) {
|
||
const bomParams = item.bomItems
|
||
.filter(bomItem => bomItem.attrKey && bomItem.attrValue)
|
||
.slice(0, 2); // 最多2个参数参数
|
||
|
||
bomParams.forEach(param => {
|
||
specs.push(`${param.attrKey}:${param.attrValue}`);
|
||
});
|
||
}
|
||
|
||
// 3. 拼接成最终格式
|
||
if (specs.length > 0) {
|
||
displayName += `(${specs.join(' ')})`;
|
||
}
|
||
|
||
return displayName;
|
||
},
|
||
|
||
// 物品类型变化(已移除,改为实时搜索)
|
||
// handleItemTypeChange(index) {
|
||
// this.splitList[index].itemId = null;
|
||
// },
|
||
|
||
// 实时搜索子卷物品(后端搜索)
|
||
async searchItemsForSplit(query, index) {
|
||
const item = this.splitList[index];
|
||
|
||
const itemType = item.itemType;
|
||
if (!itemType) {
|
||
this.$message.warning('请先选择材料类型');
|
||
return;
|
||
}
|
||
|
||
// 如果没有输入,清空列表
|
||
if (!query || query.trim() === '') {
|
||
if (itemType === 'raw_material') {
|
||
this.rawMaterialList = [];
|
||
} else if (itemType === 'product') {
|
||
this.productList = [];
|
||
}
|
||
return;
|
||
}
|
||
|
||
try {
|
||
this.itemSearchLoading = true;
|
||
const searchQuery = query.trim();
|
||
|
||
if (itemType === 'raw_material') {
|
||
// 后端搜索原材料(支持名称或规格模糊搜索)
|
||
const response = await listRawMaterialWithBom({
|
||
pageNum: 1,
|
||
pageSize: 20,
|
||
rawMaterialName: searchQuery,
|
||
specification: searchQuery // 同时传入,后端会使用 OR 条件
|
||
});
|
||
if (response.code === 200) {
|
||
this.rawMaterialList = response.rows || [];
|
||
}
|
||
} else if (itemType === 'product') {
|
||
// 后端搜索产品(支持名称或规格模糊搜索)
|
||
const response = await listProductWithBom({
|
||
pageNum: 1,
|
||
pageSize: 20,
|
||
productName: searchQuery,
|
||
specification: searchQuery // 同时传入,后端会使用 OR 条件
|
||
});
|
||
if (response.code === 200) {
|
||
this.productList = response.rows || [];
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('搜索物品失败', error);
|
||
this.$message.error('搜索失败,请重试');
|
||
} finally {
|
||
this.itemSearchLoading = false;
|
||
}
|
||
},
|
||
|
||
// 已移除 loadAllItems,改为实时搜索
|
||
|
||
// 已移除 loadItemListForSplit,改为实时搜索
|
||
|
||
// 显示钢卷选择器
|
||
showCoilSelector() {
|
||
this.coilSelectorVisible = true;
|
||
},
|
||
|
||
// 钢卷选择回调
|
||
handleCoilSelect(coil) {
|
||
this.motherCoil = {
|
||
coilId: coil.coilId,
|
||
enterCoilNo: coil.enterCoilNo || '',
|
||
currentCoilNo: coil.currentCoilNo || '',
|
||
team: coil.team || '',
|
||
warehouseId: coil.warehouseId,
|
||
warehouseName: coil.warehouseName || '',
|
||
itemType: coil.itemType,
|
||
itemId: coil.itemId,
|
||
materialName: coil.materialName || '',
|
||
productName: coil.productName || '',
|
||
grossWeight: coil.grossWeight,
|
||
netWeight: coil.netWeight,
|
||
length: coil.length,
|
||
bomItems: coil.bomItemList || coil.bomItems || []
|
||
};
|
||
this.$message.success('母卷选择成功');
|
||
},
|
||
|
||
// 加载母卷信息
|
||
async loadMotherCoil(coilId) {
|
||
try {
|
||
this.loading = true;
|
||
const response = await getMaterialCoil(coilId);
|
||
if (response.code === 200 && response.data) {
|
||
const data = response.data;
|
||
this.motherCoil = {
|
||
coilId: data.coilId,
|
||
enterCoilNo: data.enterCoilNo || '',
|
||
currentCoilNo: data.currentCoilNo || '',
|
||
team: data.team || '',
|
||
warehouseId: data.warehouseId,
|
||
warehouseName: data.warehouseName || (data.warehouse ? data.warehouse.warehouseName : ''),
|
||
itemType: data.itemType,
|
||
itemId: data.itemId,
|
||
materialName: data.materialName || (data.rawMaterial ? data.rawMaterial.rawMaterialName : ''),
|
||
productName: data.productName || (data.product ? data.product.productName : ''),
|
||
grossWeight: data.grossWeight,
|
||
netWeight: data.netWeight,
|
||
length: data.length,
|
||
bomItems: data.bomItemList || data.bomItems || []
|
||
};
|
||
}
|
||
} catch (error) {
|
||
this.$message.error('加载母卷信息失败');
|
||
console.error(error);
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
},
|
||
|
||
// 加载库区列表
|
||
async loadWarehouses() {
|
||
try {
|
||
const response = await listWarehouse({ pageNum: 1, pageSize: 1000 });
|
||
if (response.code === 200) {
|
||
this.warehouseList = response.rows || response.data || [];
|
||
}
|
||
} catch (error) {
|
||
console.error('加载库区列表失败', error);
|
||
}
|
||
},
|
||
|
||
// 添加子卷
|
||
addSplitItem() {
|
||
this.splitList.push({
|
||
currentCoilNo: '',
|
||
team: '',
|
||
materialType: null,
|
||
itemType: null,
|
||
itemId: null,
|
||
grossWeight: null,
|
||
netWeight: null,
|
||
length: null,
|
||
warehouseId: null,
|
||
actualWarehouseId: null,
|
||
qualityStatus: '',
|
||
packagingRequirement: '',
|
||
packingStatus: '',
|
||
trimmingRequirement: ''
|
||
});
|
||
},
|
||
|
||
// 删除子卷
|
||
removeSplitItem(index) {
|
||
if (this.splitList.length > 1) {
|
||
this.splitList.splice(index, 1);
|
||
} else {
|
||
this.$message.warning('至少保留一个子卷');
|
||
}
|
||
},
|
||
|
||
// 保存分条
|
||
async handleSave() {
|
||
// 验证母卷信息
|
||
if (!this.motherCoil.coilId) {
|
||
this.$message.error('请先选择母卷');
|
||
return;
|
||
}
|
||
|
||
// 验证子卷数量
|
||
if (this.splitList.length < 1) {
|
||
this.$message.error('至少需要一个子卷');
|
||
return;
|
||
}
|
||
|
||
// 验证子卷信息
|
||
for (let i = 0; i < this.splitList.length; i++) {
|
||
const item = this.splitList[i];
|
||
if (!item.currentCoilNo || item.currentCoilNo.trim() === '') {
|
||
this.$message.error(`第${i + 1}个子卷的卷号不能为空`);
|
||
return;
|
||
}
|
||
if (!item.team || item.team.trim() === '') {
|
||
this.$message.error(`第${i + 1}个子卷的班组不能为空`);
|
||
return;
|
||
}
|
||
if (!item.itemType) {
|
||
this.$message.error(`第${i + 1}个子卷的物品类型不能为空`);
|
||
return;
|
||
}
|
||
if (!item.itemId) {
|
||
this.$message.error(`第${i + 1}个子卷的物品不能为空`);
|
||
return;
|
||
}
|
||
if (item.grossWeight === null || item.grossWeight === undefined || item.grossWeight === '') {
|
||
this.$message.error(`第${i + 1}个子卷的毛重不能为空`);
|
||
return;
|
||
}
|
||
if (item.netWeight === null || item.netWeight === undefined || item.netWeight === '') {
|
||
this.$message.error(`第${i + 1}个子卷的净重不能为空`);
|
||
return;
|
||
}
|
||
if (!item.warehouseId) {
|
||
this.$message.error(`第${i + 1}个子卷的目标库区不能为空`);
|
||
return;
|
||
}
|
||
}
|
||
|
||
const loadingInstance = this.$loading({
|
||
lock: true,
|
||
text: '正在分条,请稍后...',
|
||
background: 'rgba(0, 0, 0, 0.7)'
|
||
})
|
||
|
||
try {
|
||
this.loading = true;
|
||
|
||
// 构造分条数据
|
||
const splitData = {
|
||
coilId: this.motherCoil.coilId,
|
||
enterCoilNo: this.motherCoil.enterCoilNo, // 入场钢卷号(必填)
|
||
currentCoilNo: this.motherCoil.currentCoilNo,
|
||
hasMergeSplit: 1, // 1表示分条
|
||
newCoils: this.splitList.map(item => ({
|
||
...item,
|
||
itemType: item.itemType || this.motherCoil.itemType,
|
||
itemId: item.itemId || this.motherCoil.itemId,
|
||
hasMergeSplit: 1
|
||
}))
|
||
};
|
||
|
||
const response = await splitMaterialCoil(splitData);
|
||
if (response.code === 200) {
|
||
this.$message.success('分条保存成功');
|
||
|
||
// 如果是从待操作列表进来的,标记操作为完成
|
||
if (this.actionId) {
|
||
await completeAction(this.actionId);
|
||
}
|
||
|
||
// 延迟返回,让用户看到成功提示
|
||
setTimeout(() => {
|
||
this.$router.back();
|
||
}, 100);
|
||
} else {
|
||
this.$message.error(response.msg || '分条保存失败');
|
||
}
|
||
|
||
} catch (error) {
|
||
this.$message.error('分条保存失败');
|
||
console.error(error);
|
||
} finally {
|
||
this.loading = false;
|
||
loadingInstance.close();
|
||
}
|
||
},
|
||
|
||
// 取消操作
|
||
handleCancel() {
|
||
this.$router.back();
|
||
},
|
||
|
||
// 复制到全部子卷
|
||
copyToAllSubCoils() {
|
||
if (!this.motherCoil.coilId) {
|
||
this.$message.warning('请先加载母卷信息');
|
||
return;
|
||
}
|
||
|
||
// 复制到所有子卷
|
||
this.splitList.forEach((item, index) => {
|
||
// 自动生成卷号:母卷号-1, 母卷号-2, 母卷号-3...
|
||
if (!item.currentCoilNo) {
|
||
item.currentCoilNo = `${this.motherCoil.currentCoilNo}-${index + 1}`;
|
||
}
|
||
|
||
// 复制班组
|
||
if (!item.team) {
|
||
item.team = this.motherCoil.team;
|
||
}
|
||
|
||
// 不复制 itemType 和 itemId,让它们由 materialType 自动决定
|
||
if (item.itemType) {
|
||
item.itemType = this.motherCoil.itemType;
|
||
}
|
||
|
||
if (item.itemId) {
|
||
item.itemId = this.motherCoil.itemId;
|
||
}
|
||
|
||
if (item.materialType) {
|
||
item.materialType = this.motherCoil.materialType;
|
||
}
|
||
});
|
||
|
||
// 不再预加载物品列表,改为实时搜索
|
||
|
||
this.$message.success('已复制到所有子卷');
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.split-coil-container {
|
||
padding: 20px;
|
||
background: #f5f7fa;
|
||
min-height: calc(100vh - 84px);
|
||
}
|
||
|
||
/* 顶部操作栏 */
|
||
.header-bar {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
background: #fff;
|
||
padding: 16px 20px;
|
||
margin-bottom: 20px;
|
||
border-radius: 4px;
|
||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.header-title {
|
||
font-size: 18px;
|
||
font-weight: 500;
|
||
color: #303133;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
|
||
i {
|
||
color: #0066cc;
|
||
font-size: 20px;
|
||
}
|
||
}
|
||
|
||
/* 流程图容器 */
|
||
.flow-container {
|
||
display: flex;
|
||
gap: 40px;
|
||
background: #fff;
|
||
padding: 30px;
|
||
border-radius: 4px;
|
||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||
min-height: 600px;
|
||
}
|
||
|
||
.flow-left {
|
||
flex: 0 0 300px;
|
||
}
|
||
|
||
.flow-middle {
|
||
flex: 0 0 120px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
}
|
||
|
||
.flow-right {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.flow-section-title {
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
color: #303133;
|
||
margin-bottom: 16px;
|
||
padding-left: 12px;
|
||
border-left: 4px solid #0066cc;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
.el-button--text {
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
|
||
/* 母卷卡片 */
|
||
.mother-coil {
|
||
border: 2px solid #0066cc;
|
||
box-shadow: 0 4px 12px rgba(0, 102, 204, 0.15);
|
||
}
|
||
|
||
.coil-card {
|
||
background: #fff;
|
||
border: 1px solid #e4e7ed;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.coil-header {
|
||
background: #0066cc;
|
||
color: #fff;
|
||
padding: 16px 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
|
||
i {
|
||
font-size: 20px;
|
||
}
|
||
|
||
.coil-title {
|
||
flex: 1;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
|
||
.coil-body {
|
||
padding: 20px;
|
||
}
|
||
|
||
.coil-info-row {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
margin-bottom: 12px;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.label {
|
||
color: #909399;
|
||
font-size: 14px;
|
||
min-width: 100px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.value {
|
||
color: #303133;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
flex: 1;
|
||
word-break: break-all;
|
||
|
||
&.highlight {
|
||
color: #0066cc;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 参数参数展示 */
|
||
.bom-params {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 10px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.param-item {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 13px;
|
||
|
||
.param-name {
|
||
color: #909399;
|
||
min-width: 80px;
|
||
}
|
||
|
||
.param-value {
|
||
color: #303133;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
/* 流程箭头 */
|
||
.flow-arrow-container {
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 100%;
|
||
}
|
||
|
||
.arrow-line {
|
||
position: relative;
|
||
height: 3px;
|
||
margin: 20px 0;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.arrow-start {
|
||
width: 8px;
|
||
height: 8px;
|
||
background: #0066cc;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.arrow-body {
|
||
flex: 1;
|
||
height: 3px;
|
||
background: #0066cc;
|
||
}
|
||
|
||
.arrow-end {
|
||
width: 0;
|
||
height: 0;
|
||
border-left: 12px solid #0066cc;
|
||
border-top: 8px solid transparent;
|
||
border-bottom: 8px solid transparent;
|
||
}
|
||
|
||
.flow-label {
|
||
position: absolute;
|
||
bottom: 20px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
background: #ecf5ff;
|
||
color: #0066cc;
|
||
padding: 8px 16px;
|
||
border-radius: 20px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
border: 1px solid #d9ecff;
|
||
}
|
||
|
||
/* 子卷列表 */
|
||
.split-list {
|
||
max-height: 500px;
|
||
overflow-y: auto;
|
||
margin-bottom: 20px;
|
||
padding-right: 10px;
|
||
|
||
&::-webkit-scrollbar {
|
||
width: 6px;
|
||
}
|
||
|
||
&::-webkit-scrollbar-thumb {
|
||
background: #dcdfe6;
|
||
border-radius: 3px;
|
||
}
|
||
}
|
||
|
||
.sub-coil-card {
|
||
background: #fff;
|
||
border: 1px solid #e4e7ed;
|
||
border-radius: 8px;
|
||
margin-bottom: 16px;
|
||
transition: all 0.3s;
|
||
|
||
&:hover {
|
||
border-color: #0066cc;
|
||
box-shadow: 0 2px 8px rgba(0, 102, 204, 0.15);
|
||
}
|
||
}
|
||
|
||
.sub-coil-header {
|
||
background: #f5f7fa;
|
||
padding: 12px 16px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
border-bottom: 1px solid #e4e7ed;
|
||
}
|
||
|
||
.sub-coil-number {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #0066cc;
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 50%;
|
||
background: #ecf5ff;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.btn-remove {
|
||
color: #f56c6c;
|
||
padding: 0;
|
||
|
||
&:hover {
|
||
color: #f56c6c;
|
||
}
|
||
}
|
||
|
||
.sub-coil-body {
|
||
padding: 16px;
|
||
}
|
||
|
||
/* 汇总卡片 */
|
||
.summary-card {
|
||
background: #ecf5ff;
|
||
border: 1px solid #d9ecff;
|
||
border-radius: 8px;
|
||
padding: 16px 20px;
|
||
display: flex;
|
||
justify-content: space-around;
|
||
}
|
||
|
||
.summary-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.summary-label {
|
||
font-size: 13px;
|
||
color: #606266;
|
||
}
|
||
|
||
.summary-value {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
color: #0066cc;
|
||
|
||
&.error {
|
||
color: #f56c6c;
|
||
}
|
||
}
|
||
|
||
// 优化按钮文字颜色
|
||
// 实心primary按钮:白色文字
|
||
::v-deep .el-button--primary.el-button--small:not(.is-plain) {
|
||
color: #fff;
|
||
}
|
||
|
||
// plain按钮和text按钮:蓝色文字
|
||
::v-deep .el-button--primary.el-button--small.is-plain,
|
||
::v-deep .el-button--text {
|
||
color: #409eff;
|
||
|
||
&:hover {
|
||
color: #66b1ff;
|
||
}
|
||
}
|
||
|
||
// 修复数字输入框的上下箭头溢出
|
||
.sub-coil-body {
|
||
::v-deep input[type="number"] {
|
||
appearance: textfield;
|
||
-moz-appearance: textfield;
|
||
|
||
&::-webkit-outer-spin-button,
|
||
&::-webkit-inner-spin-button {
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
margin: 0;
|
||
}
|
||
}
|
||
}
|
||
</style>
|