更新录入合卷分卷添加选择分类
This commit is contained in:
186
klp-ui/src/components/CoilSelector/index.vue
Normal file
186
klp-ui/src/components/CoilSelector/index.vue
Normal file
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="选择钢卷"
|
||||
:visible.sync="dialogVisible"
|
||||
width="900px"
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 搜索区域 -->
|
||||
<el-form :inline="true" :model="queryParams" class="search-form">
|
||||
<el-form-item label="卷号">
|
||||
<el-input
|
||||
v-model="queryParams.currentCoilNo"
|
||||
placeholder="请输入卷号"
|
||||
clearable
|
||||
size="small"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="钢种">
|
||||
<el-input
|
||||
v-model="queryParams.grade"
|
||||
placeholder="请输入钢种"
|
||||
clearable
|
||||
size="small"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="coilList"
|
||||
@row-click="handleRowClick"
|
||||
highlight-current-row
|
||||
height="400px"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column type="index" width="50" align="center" label="序号" />
|
||||
<el-table-column label="卷号" align="center" prop="currentCoilNo" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="钢种" align="center" prop="grade" width="100" />
|
||||
<el-table-column label="厚度(mm)" align="center" prop="thickness" width="100" />
|
||||
<el-table-column label="宽度(mm)" align="center" prop="width" width="100" />
|
||||
<el-table-column label="重量(t)" align="center" prop="weight" width="100" />
|
||||
<el-table-column label="库区" align="center" prop="warehouseName" width="120" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="操作" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" @click.stop="handleSelect(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listMaterialCoil } from '@/api/wms/coil';
|
||||
|
||||
export default {
|
||||
name: 'CoilSelector',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 过滤条件(可以预设一些查询条件)
|
||||
filters: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
coilList: [],
|
||||
total: 0,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
currentCoilNo: null,
|
||||
grade: null,
|
||||
dataType: 1 // 只查询当前数据,不查询历史数据
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
dialogVisible: {
|
||||
get() {
|
||||
return this.visible;
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:visible', val);
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
if (val) {
|
||||
this.resetQuery();
|
||||
this.getList();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 获取钢卷列表
|
||||
async getList() {
|
||||
try {
|
||||
this.loading = true;
|
||||
const params = { ...this.queryParams, ...this.filters };
|
||||
const response = await listMaterialCoil(params);
|
||||
if (response.code === 200) {
|
||||
this.coilList = response.rows || [];
|
||||
this.total = response.total || 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取钢卷列表失败', error);
|
||||
this.$message.error('获取钢卷列表失败');
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 搜索
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
},
|
||||
|
||||
// 重置
|
||||
resetQuery() {
|
||||
this.queryParams = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
currentCoilNo: null,
|
||||
grade: null,
|
||||
dataType: 1
|
||||
};
|
||||
this.getList();
|
||||
},
|
||||
|
||||
// 点击行
|
||||
handleRowClick(row) {
|
||||
this.handleSelect(row);
|
||||
},
|
||||
|
||||
// 选择钢卷
|
||||
handleSelect(row) {
|
||||
this.$emit('select', row);
|
||||
this.handleClose();
|
||||
},
|
||||
|
||||
// 关闭对话框
|
||||
handleClose() {
|
||||
this.dialogVisible = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.search-form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
::v-deep .el-dialog__body {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
573
klp-ui/src/views/wms/coil/merge.vue
Normal file
573
klp-ui/src/views/wms/coil/merge.vue
Normal file
@@ -0,0 +1,573 @@
|
||||
<template>
|
||||
<div class="merge-coil-container">
|
||||
<!-- 顶部操作栏 -->
|
||||
<div class="header-bar">
|
||||
<div class="header-title">
|
||||
<i class="el-icon-connection"></i>
|
||||
<span>钢卷合卷</span>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<el-button type="primary" size="small" @click="handleSave" :loading="loading">保存合卷</el-button>
|
||||
<el-button size="small" @click="handleCancel" :disabled="loading">取消</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 流程图区域 -->
|
||||
<div class="flow-container">
|
||||
<!-- 左侧:源卷列表 -->
|
||||
<div class="flow-left">
|
||||
<div class="flow-section-title">
|
||||
<span>源卷列表</span>
|
||||
<el-button type="text" size="mini" @click="addSourceCoil" icon="el-icon-plus">添加钢卷</el-button>
|
||||
</div>
|
||||
|
||||
<div class="source-list">
|
||||
<div class="source-coil-card" v-for="(item, index) in sourceCoils" :key="index">
|
||||
<div class="source-coil-header">
|
||||
<div class="source-number">{{ index + 1 }}</div>
|
||||
<div class="source-info">
|
||||
<div class="source-id">{{ item.currentCoilNo || '待选择' }}</div>
|
||||
<div class="source-weight">{{ item.weight || '—' }} t</div>
|
||||
</div>
|
||||
<el-button
|
||||
type="text"
|
||||
size="mini"
|
||||
icon="el-icon-delete"
|
||||
@click="removeSourceCoil(index)"
|
||||
class="btn-remove"
|
||||
></el-button>
|
||||
</div>
|
||||
<div class="source-coil-body">
|
||||
<el-button type="text" size="small" @click="selectCoil(index)">
|
||||
<i class="el-icon-search"></i> 选择钢卷
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中间:流程箭头(汇聚) -->
|
||||
<div class="flow-middle">
|
||||
<div class="merge-arrow-container">
|
||||
<svg width="120" height="100%" viewBox="0 0 120 400" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- 多条线汇聚到一点 -->
|
||||
<line
|
||||
v-for="(item, index) in sourceCoils"
|
||||
:key="index"
|
||||
:x1="0"
|
||||
:y1="50 + index * 80"
|
||||
:x2="100"
|
||||
:y2="200"
|
||||
stroke="#0066cc"
|
||||
stroke-width="2"
|
||||
stroke-dasharray="5,5"
|
||||
/>
|
||||
<!-- 箭头 -->
|
||||
<polygon points="100,200 110,195 110,205" fill="#0066cc"/>
|
||||
</svg>
|
||||
</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">目标卷信息</div>
|
||||
<div class="target-coil-card">
|
||||
<div class="target-coil-header">
|
||||
<i class="el-icon-s-grid"></i>
|
||||
<span>新钢卷</span>
|
||||
</div>
|
||||
<div class="target-coil-body">
|
||||
<el-form size="small" label-width="90px">
|
||||
<el-form-item label="卷号">
|
||||
<el-input v-model="targetCoil.currentCoilNo" placeholder="输入目标卷号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="钢种">
|
||||
<el-input v-model="targetCoil.grade" placeholder="继承源卷"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="厚度(mm)">
|
||||
<el-input-number
|
||||
v-model="targetCoil.thickness"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="宽度(mm)">
|
||||
<el-input-number
|
||||
v-model="targetCoil.width"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="重量(t)">
|
||||
<el-input v-model="totalWeight" disabled></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 合卷规则说明 -->
|
||||
<div class="rule-card">
|
||||
<div class="rule-title">
|
||||
<i class="el-icon-warning-outline"></i>
|
||||
合卷规则
|
||||
</div>
|
||||
<ul class="rule-list">
|
||||
<li>同一钢种才可合卷</li>
|
||||
<li>厚度差异不超过±0.05mm</li>
|
||||
<li>宽度必须完全一致</li>
|
||||
<li>目标卷重量为源卷总和</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 钢卷选择器 -->
|
||||
<coil-selector
|
||||
:visible.sync="coilSelectorVisible"
|
||||
@select="handleCoilSelect"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getMaterialCoil, mergeMaterialCoil } from '@/api/wms/coil';
|
||||
import CoilSelector from '@/components/CoilSelector';
|
||||
|
||||
export default {
|
||||
name: 'MergeCoil',
|
||||
components: {
|
||||
CoilSelector
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 源卷列表
|
||||
sourceCoils: [],
|
||||
// 目标卷信息
|
||||
targetCoil: {
|
||||
currentCoilNo: '',
|
||||
grade: '',
|
||||
thickness: null,
|
||||
width: null,
|
||||
warehouseId: null,
|
||||
team: null,
|
||||
itemType: null,
|
||||
itemId: null
|
||||
},
|
||||
loading: false,
|
||||
// 钢卷选择器可见性
|
||||
coilSelectorVisible: false,
|
||||
// 当前选择的源卷索引
|
||||
currentSelectIndex: -1
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 源卷总重量
|
||||
totalWeight() {
|
||||
return this.sourceCoils.reduce((sum, item) => sum + (Number(item.weight) || 0), 0).toFixed(2);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 初始化至少2个源卷
|
||||
this.sourceCoils = [
|
||||
{ coilId: null, currentCoilNo: '', grade: '', weight: 0, thickness: null, width: null },
|
||||
{ coilId: null, currentCoilNo: '', grade: '', weight: 0, thickness: null, width: null }
|
||||
];
|
||||
},
|
||||
methods: {
|
||||
// 添加源卷
|
||||
addSourceCoil() {
|
||||
this.sourceCoils.push({
|
||||
coilId: null,
|
||||
currentCoilNo: '',
|
||||
grade: '',
|
||||
weight: 0,
|
||||
thickness: null,
|
||||
width: null,
|
||||
warehouseId: null,
|
||||
team: null,
|
||||
itemType: null,
|
||||
itemId: null
|
||||
});
|
||||
},
|
||||
|
||||
// 删除源卷
|
||||
removeSourceCoil(index) {
|
||||
if (this.sourceCoils.length > 2) {
|
||||
this.sourceCoils.splice(index, 1);
|
||||
} else {
|
||||
this.$message.warning('至少需要2个源卷才能合卷');
|
||||
}
|
||||
},
|
||||
|
||||
// 选择钢卷
|
||||
selectCoil(index) {
|
||||
this.currentSelectIndex = index;
|
||||
this.coilSelectorVisible = true;
|
||||
},
|
||||
|
||||
// 钢卷选择回调
|
||||
handleCoilSelect(coil) {
|
||||
const index = this.currentSelectIndex;
|
||||
this.$set(this.sourceCoils, index, {
|
||||
coilId: coil.coilId,
|
||||
currentCoilNo: coil.currentCoilNo || '',
|
||||
grade: coil.grade || '',
|
||||
weight: coil.weight || 0,
|
||||
thickness: coil.thickness,
|
||||
width: coil.width,
|
||||
warehouseId: coil.warehouseId,
|
||||
team: coil.team,
|
||||
itemType: coil.itemType,
|
||||
itemId: coil.itemId
|
||||
});
|
||||
|
||||
// 如果是第一个源卷,自动填充目标卷信息
|
||||
if (index === 0) {
|
||||
this.targetCoil.grade = coil.grade;
|
||||
this.targetCoil.thickness = coil.thickness;
|
||||
this.targetCoil.width = coil.width;
|
||||
this.targetCoil.warehouseId = coil.warehouseId;
|
||||
this.targetCoil.team = coil.team;
|
||||
this.targetCoil.itemType = coil.itemType;
|
||||
this.targetCoil.itemId = coil.itemId;
|
||||
}
|
||||
|
||||
this.$message.success('钢卷选择成功');
|
||||
},
|
||||
|
||||
// 保存合卷
|
||||
async handleSave() {
|
||||
// 验证源卷数量
|
||||
if (this.sourceCoils.length < 2) {
|
||||
this.$message.error('至少需要2个源卷才能合卷');
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证源卷信息
|
||||
for (let i = 0; i < this.sourceCoils.length; i++) {
|
||||
const item = this.sourceCoils[i];
|
||||
if (!item.coilId) {
|
||||
this.$message.error(`第${i + 1}个源卷未选择`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 验证目标卷卷号
|
||||
if (!this.targetCoil.currentCoilNo || this.targetCoil.currentCoilNo.trim() === '') {
|
||||
this.$message.error('请输入目标卷卷号');
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证源卷规格一致性
|
||||
const firstCoil = this.sourceCoils[0];
|
||||
for (let i = 1; i < this.sourceCoils.length; i++) {
|
||||
const coil = this.sourceCoils[i];
|
||||
if (coil.grade !== firstCoil.grade) {
|
||||
this.$message.error('源卷钢种不一致,无法合卷');
|
||||
return;
|
||||
}
|
||||
if (Math.abs(coil.thickness - firstCoil.thickness) > 0.05) {
|
||||
this.$message.error('源卷厚度差异超过±0.05mm,无法合卷');
|
||||
return;
|
||||
}
|
||||
if (coil.width !== firstCoil.width) {
|
||||
this.$message.error('源卷宽度不一致,无法合卷');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
|
||||
// 构造合卷数据
|
||||
const mergeData = {
|
||||
currentCoilNo: this.targetCoil.currentCoilNo,
|
||||
grade: this.targetCoil.grade,
|
||||
thickness: this.targetCoil.thickness,
|
||||
width: this.targetCoil.width,
|
||||
weight: Number(this.totalWeight),
|
||||
warehouseId: this.targetCoil.warehouseId,
|
||||
team: this.targetCoil.team,
|
||||
itemType: this.targetCoil.itemType,
|
||||
itemId: this.targetCoil.itemId,
|
||||
hasMergeSplit: 2, // 2表示合卷
|
||||
newCoils: this.sourceCoils.map(item => ({
|
||||
coilId: item.coilId,
|
||||
currentCoilNo: item.currentCoilNo,
|
||||
grade: item.grade,
|
||||
thickness: item.thickness,
|
||||
width: item.width,
|
||||
weight: item.weight
|
||||
}))
|
||||
};
|
||||
|
||||
const response = await mergeMaterialCoil(mergeData);
|
||||
if (response.code === 200) {
|
||||
this.$message.success('合卷保存成功');
|
||||
// 延迟返回,让用户看到成功提示
|
||||
setTimeout(() => {
|
||||
this.$router.back();
|
||||
}, 1000);
|
||||
} else {
|
||||
this.$message.error(response.msg || '合卷保存失败');
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('合卷保存失败');
|
||||
console.error(error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 取消操作
|
||||
handleCancel() {
|
||||
this.$router.back();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.merge-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: 1;
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
.flow-middle {
|
||||
flex: 0 0 120px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.flow-right {
|
||||
flex: 1;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
/* 源卷列表 */
|
||||
.source-list {
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
padding-right: 10px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #dcdfe6;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.source-coil-card {
|
||||
background: #fff;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 12px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: #0066cc;
|
||||
box-shadow: 0 2px 8px rgba(0, 102, 204, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.source-coil-header {
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
border-bottom: 1px solid #f5f7fa;
|
||||
}
|
||||
|
||||
.source-number {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
background: #0066cc;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.source-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.source-id {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.source-weight {
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.source-coil-body {
|
||||
padding: 12px 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.btn-remove {
|
||||
color: #f56c6c;
|
||||
padding: 0;
|
||||
|
||||
&:hover {
|
||||
color: #f56c6c;
|
||||
}
|
||||
}
|
||||
|
||||
/* 流程箭头 */
|
||||
.merge-arrow-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
/* 目标卷卡片 */
|
||||
.target-coil-card {
|
||||
background: #fff;
|
||||
border: 2px solid #0066cc;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 12px rgba(0, 102, 204, 0.15);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.target-coil-header {
|
||||
background: #0066cc;
|
||||
color: #fff;
|
||||
padding: 16px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.target-coil-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* 规则说明卡片 */
|
||||
.rule-card {
|
||||
background: #fff9f0;
|
||||
border: 1px solid #ffe9c2;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.rule-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #e6a23c;
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.rule-list {
|
||||
padding-left: 20px;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
643
klp-ui/src/views/wms/coil/split.vue
Normal file
643
klp-ui/src/views/wms/coil/split.vue
Normal file
@@ -0,0 +1,643 @@
|
||||
<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 type="primary" size="small" @click="handleSave" :loading="loading">保存分卷</el-button>
|
||||
<el-button size="small" @click="handleCancel" :disabled="loading">取消</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 流程图区域 -->
|
||||
<div class="flow-container">
|
||||
<!-- 左侧:母卷信息 -->
|
||||
<div class="flow-left">
|
||||
<div class="flow-section-title">
|
||||
<span>母卷信息</span>
|
||||
<el-button type="text" size="mini" @click="showCoilSelector" icon="el-icon-search">选择母卷</el-button>
|
||||
</div>
|
||||
<div class="coil-card mother-coil">
|
||||
<div class="coil-header">
|
||||
<i class="el-icon-s-grid"></i>
|
||||
<span class="coil-id">{{ motherCoil.currentCoilNo || '—' }}</span>
|
||||
</div>
|
||||
<div class="coil-body">
|
||||
<div class="coil-info-row">
|
||||
<span class="label">钢种:</span>
|
||||
<span class="value">{{ motherCoil.grade || '—' }}</span>
|
||||
</div>
|
||||
<div class="coil-info-row">
|
||||
<span class="label">厚度:</span>
|
||||
<span class="value">{{ motherCoil.thickness || '—' }} mm</span>
|
||||
</div>
|
||||
<div class="coil-info-row">
|
||||
<span class="label">宽度:</span>
|
||||
<span class="value">{{ motherCoil.width || '—' }} mm</span>
|
||||
</div>
|
||||
<div class="coil-info-row">
|
||||
<span class="label">重量:</span>
|
||||
<span class="value highlight">{{ motherCoil.weight || '—' }} t</span>
|
||||
</div>
|
||||
</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>
|
||||
<el-button type="text" size="mini" @click="addSplitItem" icon="el-icon-plus">添加子卷</el-button>
|
||||
</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
|
||||
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="70px">
|
||||
<el-form-item label="卷号">
|
||||
<el-input v-model="item.currentCoilNo" placeholder="输入子卷卷号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="重量(t)">
|
||||
<el-input-number
|
||||
v-model="item.weight"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="长度(m)">
|
||||
<el-input-number
|
||||
v-model="item.length"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
></el-input-number>
|
||||
</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 class="summary-item">
|
||||
<span class="summary-label">总重量:</span>
|
||||
<span class="summary-value" :class="{ 'error': totalWeight > motherCoil.weight }">
|
||||
{{ totalWeight.toFixed(2) }} t
|
||||
</span>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span class="summary-label">剩余重量:</span>
|
||||
<span class="summary-value" :class="{ 'error': remainWeight < 0 }">
|
||||
{{ remainWeight.toFixed(2) }} t
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 钢卷选择器 -->
|
||||
<coil-selector
|
||||
:visible.sync="coilSelectorVisible"
|
||||
@select="handleCoilSelect"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getMaterialCoil, splitMaterialCoil } from '@/api/wms/coil';
|
||||
import CoilSelector from '@/components/CoilSelector';
|
||||
|
||||
export default {
|
||||
name: 'SplitCoil',
|
||||
components: {
|
||||
CoilSelector
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 母卷信息
|
||||
motherCoil: {
|
||||
coilId: null,
|
||||
currentCoilNo: '',
|
||||
grade: '',
|
||||
thickness: null,
|
||||
width: null,
|
||||
weight: null,
|
||||
warehouseId: null,
|
||||
team: null,
|
||||
itemType: null,
|
||||
itemId: null,
|
||||
enterCoilNo: '',
|
||||
supplierCoilNo: ''
|
||||
},
|
||||
// 子卷列表
|
||||
splitList: [
|
||||
{ currentCoilNo: '', weight: 0, length: 0 }
|
||||
],
|
||||
loading: false,
|
||||
// 钢卷选择器可见性
|
||||
coilSelectorVisible: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 子卷总重量
|
||||
totalWeight() {
|
||||
return this.splitList.reduce((sum, item) => sum + (Number(item.weight) || 0), 0);
|
||||
},
|
||||
// 剩余重量
|
||||
remainWeight() {
|
||||
return (Number(this.motherCoil.weight) || 0) - this.totalWeight;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 如果URL中有coilId参数,则加载母卷信息
|
||||
const coilId = this.$route.query.coilId;
|
||||
if (coilId) {
|
||||
this.loadMotherCoil(coilId);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 显示钢卷选择器
|
||||
showCoilSelector() {
|
||||
this.coilSelectorVisible = true;
|
||||
},
|
||||
|
||||
// 钢卷选择回调
|
||||
handleCoilSelect(coil) {
|
||||
this.motherCoil = {
|
||||
coilId: coil.coilId,
|
||||
currentCoilNo: coil.currentCoilNo || '',
|
||||
grade: coil.grade || '',
|
||||
thickness: coil.thickness,
|
||||
width: coil.width,
|
||||
weight: coil.weight,
|
||||
warehouseId: coil.warehouseId,
|
||||
team: coil.team,
|
||||
itemType: coil.itemType,
|
||||
itemId: coil.itemId,
|
||||
enterCoilNo: coil.enterCoilNo || '',
|
||||
supplierCoilNo: coil.supplierCoilNo || ''
|
||||
};
|
||||
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,
|
||||
currentCoilNo: data.currentCoilNo || '',
|
||||
grade: data.grade || '',
|
||||
thickness: data.thickness,
|
||||
width: data.width,
|
||||
weight: data.weight,
|
||||
warehouseId: data.warehouseId,
|
||||
team: data.team,
|
||||
itemType: data.itemType,
|
||||
itemId: data.itemId,
|
||||
enterCoilNo: data.enterCoilNo || '',
|
||||
supplierCoilNo: data.supplierCoilNo || ''
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('加载母卷信息失败');
|
||||
console.error(error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 添加子卷
|
||||
addSplitItem() {
|
||||
this.splitList.push({
|
||||
currentCoilNo: '',
|
||||
weight: 0,
|
||||
length: 0
|
||||
});
|
||||
},
|
||||
|
||||
// 删除子卷
|
||||
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;
|
||||
}
|
||||
|
||||
// 验证重量
|
||||
if (this.remainWeight < 0) {
|
||||
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.weight || item.weight <= 0) {
|
||||
this.$message.error(`第${i + 1}个子卷的重量必须大于0`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
|
||||
// 构造分卷数据
|
||||
const splitData = {
|
||||
coilId: this.motherCoil.coilId,
|
||||
currentCoilNo: this.motherCoil.currentCoilNo,
|
||||
hasMergeSplit: 1, // 1表示分卷
|
||||
newCoils: this.splitList.map(item => ({
|
||||
currentCoilNo: item.currentCoilNo,
|
||||
weight: item.weight,
|
||||
length: item.length,
|
||||
hasMergeSplit: 1,
|
||||
// 继承母卷的基本信息
|
||||
grade: this.motherCoil.grade,
|
||||
thickness: this.motherCoil.thickness,
|
||||
width: this.motherCoil.width,
|
||||
warehouseId: this.motherCoil.warehouseId,
|
||||
team: this.motherCoil.team,
|
||||
itemType: this.motherCoil.itemType,
|
||||
itemId: this.motherCoil.itemId
|
||||
}))
|
||||
};
|
||||
|
||||
const response = await splitMaterialCoil(splitData);
|
||||
if (response.code === 200) {
|
||||
this.$message.success('分卷保存成功');
|
||||
// 延迟返回,让用户看到成功提示
|
||||
setTimeout(() => {
|
||||
this.$router.back();
|
||||
}, 1000);
|
||||
} else {
|
||||
this.$message.error(response.msg || '分卷保存失败');
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('分卷保存失败');
|
||||
console.error(error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 取消操作
|
||||
handleCancel() {
|
||||
this.$router.back();
|
||||
}
|
||||
}
|
||||
};
|
||||
</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-id {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.coil-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.coil-info-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
min-width: 70px;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #303133;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
|
||||
&.highlight {
|
||||
color: #0066cc;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 流程箭头 */
|
||||
.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;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user