添加web的合卷分卷合并操作

This commit is contained in:
2025-11-03 17:03:03 +08:00
parent 8f0d48a892
commit ffbe9e181a
15 changed files with 3307 additions and 247 deletions

View File

@@ -14,7 +14,7 @@ export function exportMaterialCoil(query) {
url: '/wms/materialCoil/export',
method: 'get',
params: query
})
})
}
export function getMaterialCoil(CoilMaterialId) {
@@ -83,3 +83,21 @@ export function getMaterialCoilDistributionByType(query) {
params: query
})
}
// 钢卷分卷
export function splitMaterialCoil(data) {
return request({
url: '/wms/materialCoil',
method: 'put',
data: data
})
}
// 钢卷合卷
export function mergeMaterialCoil(data) {
return request({
url: '/wms/materialCoil',
method: 'put',
data: data
})
}

View File

@@ -0,0 +1,86 @@
import request from '@/utils/request'
// 查询钢卷待操作列表
export function listPendingAction(query) {
return request({
url: '/wms/coilPendingAction/list',
method: 'get',
params: query
})
}
// 查询钢卷待操作详细
export function getPendingAction(actionId) {
return request({
url: '/wms/coilPendingAction/' + actionId,
method: 'get'
})
}
// 新增钢卷待操作
export function addPendingAction(data) {
return request({
url: '/wms/coilPendingAction',
method: 'post',
data: data
})
}
// 修改钢卷待操作
export function updatePendingAction(data) {
return request({
url: '/wms/coilPendingAction',
method: 'put',
data: data
})
}
// 删除钢卷待操作
export function delPendingAction(actionId) {
return request({
url: '/wms/coilPendingAction/' + actionId,
method: 'delete'
})
}
// 更新操作状态
export function updateStatus(actionId, status) {
return request({
url: `/wms/coilPendingAction/status/${actionId}/${status}`,
method: 'put'
})
}
// 开始处理操作
export function startProcess(actionId) {
return request({
url: `/wms/coilPendingAction/start/${actionId}`,
method: 'put'
})
}
// 完成操作
export function completeAction(actionId) {
return request({
url: `/wms/coilPendingAction/complete/${actionId}`,
method: 'put'
})
}
// 取消操作
export function cancelAction(actionId) {
return request({
url: `/wms/coilPendingAction/cancel/${actionId}`,
method: 'put'
})
}
// 导出钢卷待操作
export function exportPendingAction(query) {
return request({
url: '/wms/coilPendingAction/export',
method: 'post',
params: query
})
}

View File

@@ -0,0 +1,538 @@
<template>
<div class="app-container">
<!-- 搜索栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item label="钢卷号" prop="currentCoilNo">
<el-input
v-model="queryParams.currentCoilNo"
placeholder="请输入钢卷号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="操作类型" prop="actionType">
<el-select v-model="queryParams.actionType" placeholder="请选择操作类型">
<el-option v-for="item in dict.type.action_type" :key="item.value" :label="item.label" :value="item.value" />
</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-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-refresh"
size="mini"
@click="handleRefresh"
>刷新</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 数据表格 -->
<el-table
v-loading="loading"
:data="actionList"
@selection-change="handleSelectionChange"
:row-class-name="tableRowClassName"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="钢卷号" align="center" prop="currentCoilNo" width="140" :show-overflow-tooltip="true">
<template slot-scope="scope">
<el-tag type="info" size="small">{{ scope.row.currentCoilNo }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作类型" align="center" prop="actionType" width="100">
<template slot-scope="scope">
<dict-tag :options="dict.type.action_type" :value="scope.row.actionType"/>
</template>
</el-table-column>
<el-table-column label="操作状态" align="center" prop="actionStatus" width="100">
<template slot-scope="scope">
<el-tag v-if="scope.row.actionStatus === 0" type="info" size="small">待处理</el-tag>
<el-tag v-else-if="scope.row.actionStatus === 1" type="warning" size="small">处理中</el-tag>
<el-tag v-else-if="scope.row.actionStatus === 2" type="success" size="small">已完成</el-tag>
<el-tag v-else-if="scope.row.actionStatus === 3" type="danger" size="small">已取消</el-tag>
</template>
</el-table-column>
<el-table-column label="优先级" align="center" prop="priority" width="90">
<template slot-scope="scope">
<el-tag v-if="scope.row.priority === 0" type="info" size="mini">普通</el-tag>
<el-tag v-else-if="scope.row.priority === 1" type="warning" size="mini">重要</el-tag>
<el-tag v-else-if="scope.row.priority === 2" type="danger" size="mini">紧急</el-tag>
</template>
</el-table-column>
<el-table-column label="来源" align="center" prop="sourceType" width="80">
<template slot-scope="scope">
<el-tag v-if="scope.row.sourceType === 'scan'" type="success" size="mini">
<i class="el-icon-mobile"></i> 扫码
</el-tag>
<el-tag v-else type="info" size="mini">
<i class="el-icon-edit-outline"></i> 手动
</el-tag>
</template>
</el-table-column>
<el-table-column label="扫码时间" align="center" prop="scanTime" width="155" :show-overflow-tooltip="true">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.scanTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作人" align="center" prop="operatorName" width="100" />
<el-table-column label="处理时间" align="center" prop="processTime" width="155" :show-overflow-tooltip="true">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.processTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width" fixed="right">
<template slot-scope="scope">
<!-- 待处理状态显示操作按钮 -->
<template v-if="scope.row.actionStatus === 0">
<el-button
size="mini"
type="primary"
icon="el-icon-edit"
@click="handleProcess(scope.row)"
>操作</el-button>
<el-button
size="mini"
type="danger"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</el-button>
</template>
<!-- 处理中状态显示继续按钮 -->
<template v-else-if="scope.row.actionStatus === 1">
<el-button
size="mini"
type="warning"
icon="el-icon-edit"
@click="handleProcess(scope.row)"
>继续</el-button>
<el-button
size="mini"
type="info"
icon="el-icon-close"
@click="handleCancel(scope.row)"
>取消</el-button>
</template>
<!-- 已完成或已取消状态显示删除按钮 -->
<template v-else>
<el-button
size="mini"
type="danger"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</el-button>
</template>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<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="600px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="钢卷" prop="coilId">
<el-button size="small" @click="showCoilSelector">
<i class="el-icon-search"></i> 选择钢卷
</el-button>
<span v-if="form.currentCoilNo" style="margin-left: 10px;">
<el-tag type="info">{{ form.currentCoilNo }}</el-tag>
</span>
</el-form-item>
<el-form-item label="操作类型" prop="actionType">
<el-select v-model="form.actionType" placeholder="请选择操作类型">
<el-option label="合卷" :value="1" />
<el-option label="分卷" :value="2" />
<el-option label="更新" :value="3" />
</el-select>
</el-form-item>
<el-form-item label="优先级" prop="priority">
<el-select v-model="form.priority" placeholder="请选择优先级">
<el-option label="普通" :value="0" />
<el-option label="重要" :value="1" />
<el-option label="紧急" :value="2" />
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 钢卷选择器 -->
<coil-selector
:visible.sync="coilSelectorVisible"
@select="handleCoilSelect"
/>
</div>
</template>
<script>
import {
listPendingAction,
getPendingAction,
delPendingAction,
addPendingAction,
updatePendingAction,
startProcess,
completeAction,
cancelAction
} from '@/api/wms/pendingAction';
import CoilSelector from '@/components/CoilSelector';
export default {
name: 'CoilActflow',
dicts: ['action_type'],
components: {
CoilSelector
},
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 待操作列表数据
actionList: [],
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
currentCoilNo: null,
actionType: null,
actionStatus: null, // 默认查询待处理
priority: null
},
// 表单参数
form: {},
// 表单校验
rules: {
coilId: [
{ required: true, message: '请选择钢卷', trigger: 'blur' }
],
actionType: [
{ required: true, message: '请选择操作类型', trigger: 'change' }
]
},
// 钢卷选择器可见性
coilSelectorVisible: false
};
},
created() {
this.getList();
// 设置定时刷新(可选,用于移动端扫码后自动刷新)
this.startAutoRefresh();
},
beforeDestroy() {
// 清除定时器
if (this.refreshTimer) {
clearInterval(this.refreshTimer);
}
},
methods: {
/** 查询待操作列表 */
getList() {
this.loading = true;
listPendingAction(this.queryParams).then(response => {
console.log('response.rows', response.rows);
this.actionList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
actionId: null,
coilId: null,
currentCoilNo: null,
actionType: null,
actionStatus: null,
priority: 0,
sourceType: 'manual',
remark: null
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.actionId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = '添加待操作';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const actionId = row.actionId || this.ids;
getPendingAction(actionId).then(response => {
this.form = response.data;
this.open = true;
this.title = '修改待操作';
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate(valid => {
if (valid) {
if (this.form.actionId != null) {
updatePendingAction(this.form).then(response => {
this.$message.success('修改成功');
this.open = false;
this.getList();
});
} else {
addPendingAction(this.form).then(response => {
this.$message.success('新增成功');
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const actionIds = row.actionId || this.ids;
this.$confirm('是否确认删除该待操作记录?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return delPendingAction(actionIds);
}).then(() => {
this.getList();
this.$message.success('删除成功');
}).catch(() => {});
},
/** 处理操作 - 跳转到对应页面 */
handleProcess(row) {
console.log('=== 开始处理操作 ===');
console.log('待操作记录:', row);
console.log('操作类型:', row.actionType);
console.log('钢卷ID:', row.coilId);
// 根据操作类型跳转到不同页面
let path = '';
// 注意action_type字典中 1=合卷, 2=分卷, 3=更新
if (row.actionType === 1 || row.actionType === '1') {
// 合卷
path = '/wms/merge';
} else if (row.actionType === 2 || row.actionType === '2') {
// 分卷
path = '/wms/split';
} else {
// 更新
path = '/wms/typing';
}
console.log('跳转路径:', path);
if (!path) {
this.$message.error('未知的操作类型: ' + row.actionType);
return;
}
// 更新状态为处理中
console.log('调用startProcessactionId:', row.actionId);
startProcess(row.actionId).then(response => {
console.log('开始处理响应:', response);
if (response.code !== 200) {
this.$message.error(response.msg || '更新状态失败');
return;
}
// 跳转并传递参数
console.log('准备跳转到:', path, '参数:', { coilId: row.coilId, actionId: row.actionId });
this.$router.push({
path: path,
query: {
coilId: row.coilId,
actionId: row.actionId
}
});
}).catch(error => {
console.error('更新状态失败:', error);
this.$message.error('更新状态失败: ' + (error.message || error));
});
},
/** 取消操作 */
handleCancel(row) {
this.$confirm('是否确认取消该操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return cancelAction(row.actionId);
}).then(() => {
this.$message.success('操作已取消');
this.getList();
}).catch(() => {});
},
/** 刷新列表 */
handleRefresh() {
this.getList();
this.$message.success('刷新成功');
},
/** 自动刷新 */
startAutoRefresh() {
// 每30秒自动刷新一次用于移动端扫码后自动更新列表
this.refreshTimer = setInterval(() => {
// 只在查看待处理状态时自动刷新
this.getList();
}, 30000);
},
/** 表格行样式 */
tableRowClassName({ row }) {
if (row.priority === 2) {
return 'urgent-row';
} else if (row.priority === 1) {
return 'important-row';
}
return '';
},
/** 显示钢卷选择器 */
showCoilSelector() {
this.coilSelectorVisible = true;
},
/** 钢卷选择回调 */
handleCoilSelect(coil) {
this.form.coilId = coil.coilId;
this.form.currentCoilNo = coil.currentCoilNo;
}
}
};
</script>
<style scoped lang="scss">
.app-container {
::v-deep .urgent-row {
background: #fef0f0 !important;
}
::v-deep .important-row {
background: #fdf6ec !important;
}
// 优化按钮文字颜色
// 实心按钮:白色文字(在深色背景上清晰可见)
::v-deep .el-button--primary.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--danger.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--warning.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--info.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--success.el-button--mini:not(.is-plain) {
color: #fff;
}
// plain按钮同色系深色文字在浅色背景上
::v-deep .el-button--primary.el-button--mini.is-plain {
color: #409eff;
}
::v-deep .el-button--danger.el-button--mini.is-plain {
color: #f56c6c;
}
::v-deep .el-button--warning.el-button--mini.is-plain {
color: #e6a23c;
}
}
</style>

View File

@@ -7,8 +7,8 @@
<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>
<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>
@@ -18,29 +18,69 @@
<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>
<el-button v-if="!readonly" 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"
<el-button
v-if="!readonly"
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)">
<template v-if="item.coilId">
<div class="source-detail-row">
<span class="detail-label">入场钢卷号</span>
<span class="detail-value">{{ item.enterCoilNo || '—' }}</span>
</div>
<div class="source-detail-row">
<span class="detail-label">当前库区</span>
<span class="detail-value">{{ item.warehouseName || '未分配' }}</span>
</div>
<div class="source-detail-row" v-if="item.materialName || item.productName">
<span class="detail-label">物料名称</span>
<span class="detail-value">{{ item.materialName || item.productName || '—' }}</span>
</div>
</template>
<!-- 第二个位置显示待合卷列表 -->
<template v-else-if="index === 1 && !readonly">
<div class="pending-list-title">待合卷钢卷列表</div>
<div class="pending-coil-list" v-if="pendingMergeList.length > 0">
<div
class="pending-coil-item"
v-for="pending in pendingMergeList"
:key="pending.actionId"
@click="selectPendingCoil(pending, index)"
>
<div class="pending-coil-no">{{ pending.currentCoilNo }}</div>
<div class="pending-coil-info">
<span class="pending-label">扫码时间</span>
<span class="pending-value">{{ formatTime(pending.scanTime) }}</span>
</div>
</div>
</div>
<div v-else class="empty-tip">
<i class="el-icon-info"></i>
暂无其他待合卷钢卷
</div>
</template>
<!-- 其他位置显示选择按钮 -->
<el-button v-else-if="!readonly" type="text" size="small" @click="selectCoil(index)">
<i class="el-icon-search"></i> 选择钢卷
</el-button>
<div v-else class="empty-tip">未选择钢卷</div>
</div>
</div>
</div>
@@ -51,14 +91,14 @@
<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"
<line
v-for="(item, index) in sourceCoils"
:key="index"
:x1="0"
:y1="50 + index * 80"
:x2="100"
:y2="200"
stroke="#0066cc"
:x1="0"
:y1="50 + index * 80"
:x2="100"
:y2="200"
stroke="#0066cc"
stroke-width="2"
stroke-dasharray="5,5"
/>
@@ -83,31 +123,68 @@
<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-input v-model="targetCoil.currentCoilNo" placeholder="输入目标卷号" :disabled="readonly"></el-input>
</el-form-item>
<el-form-item label="钢种">
<el-input v-model="targetCoil.grade" placeholder="继承源卷"></el-input>
<el-form-item label="班组">
<el-input v-model="targetCoil.team" placeholder="请输入班组名称" :disabled="readonly"></el-input>
</el-form-item>
<el-form-item label="厚度(mm)">
<el-input-number
v-model="targetCoil.thickness"
:min="0"
:precision="2"
controls-position="right"
<el-form-item label="物品类型">
<el-select v-model="targetCoil.itemType" placeholder="请选择" style="width: 100%" :disabled="readonly">
<el-option label="原材料" value="raw_material" />
<el-option label="产品" value="product" />
</el-select>
</el-form-item>
<el-form-item label="物品">
<el-select
v-model="targetCoil.itemId"
placeholder="请选择物品"
filterable
remote
:remote-method="searchItems"
:loading="itemSearchLoading"
style="width: 100%"
></el-input-number>
clearable
:disabled="readonly"
>
<el-option
v-for="item in currentItemList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</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 label="毛重(t)">
<el-input
v-model.number="targetCoil.grossWeight"
placeholder="请输入毛重"
type="number"
step="0.01"
:disabled="readonly"
>
<template slot="append"></template>
</el-input>
</el-form-item>
<el-form-item label="重(t)">
<el-input v-model="totalWeight" disabled></el-input>
<el-form-item label="重(t)">
<el-input
v-model.number="targetCoil.netWeight"
placeholder="请输入净重"
type="number"
step="0.01"
:disabled="readonly"
>
<template slot="append"></template>
</el-input>
</el-form-item>
<el-form-item label="目标库区">
<el-select v-model="targetCoil.nextWarehouseId" placeholder="请选择" style="width: 100%" clearable :disabled="readonly">
<el-option
v-for="warehouse in warehouseList"
:key="warehouse.warehouseId"
:label="warehouse.warehouseName"
:value="warehouse.warehouseId"
/>
</el-select>
</el-form-item>
</el-form>
</div>
@@ -120,10 +197,9 @@
合卷规则
</div>
<ul class="rule-list">
<li>同一钢种才可合</li>
<li>厚度差异不超过±0.05mm</li>
<li>宽度必须完全一致</li>
<li>目标卷重量为源卷总和</li>
<li>至少需要2个源</li>
<li>所有源卷的物品类型和物品ID应保持一致</li>
<li>请确保录入正确的新钢卷号和班组信息</li>
</ul>
</div>
</div>
@@ -139,6 +215,10 @@
<script>
import { getMaterialCoil, mergeMaterialCoil } from '@/api/wms/coil';
import { listWarehouse } from '@/api/wms/warehouse';
import { listRawMaterial } from '@/api/wms/rawMaterial';
import { listProduct } from '@/api/wms/product';
import { listPendingAction, completeAction } from '@/api/wms/pendingAction';
import CoilSelector from '@/components/CoilSelector';
export default {
@@ -153,51 +233,306 @@ export default {
// 目标卷信息
targetCoil: {
currentCoilNo: '',
grade: '',
thickness: null,
width: null,
warehouseId: null,
team: null,
team: '',
itemType: null,
itemId: null
itemId: null,
grossWeight: null,
netWeight: null,
nextWarehouseId: null
},
loading: false,
// 钢卷选择器可见性
coilSelectorVisible: false,
// 当前选择的源卷索引
currentSelectIndex: -1
currentSelectIndex: -1,
// 库区列表
warehouseList: [],
// 原材料和产品列表
rawMaterialList: [],
productList: [],
itemSearchLoading: false,
// 只读模式
readonly: false,
// 待合卷列表(其他待操作的合卷任务)
pendingMergeList: [],
pendingLoading: false
};
},
computed: {
// 源卷总重量
totalWeight() {
return this.sourceCoils.reduce((sum, item) => sum + (Number(item.weight) || 0), 0).toFixed(2);
// 当前物品列表(根据物品类型动态切换)
currentItemList() {
if (this.targetCoil.itemType === 'raw_material') {
return this.rawMaterialList.map(item => ({
id: item.rawMaterialId,
name: item.rawMaterialName
}));
} else if (this.targetCoil.itemType === 'product') {
return this.productList.map(item => ({
id: item.productId,
name: item.productName
}));
}
return [];
}
},
created() {
// 初始化至少2个源卷
this.sourceCoils = [
{ coilId: null, currentCoilNo: '', grade: '', weight: 0, thickness: null, width: null },
{ coilId: null, currentCoilNo: '', grade: '', weight: 0, thickness: null, width: null }
];
watch: {
// 监听物品类型变化,加载对应的列表
'targetCoil.itemType'(newVal, oldVal) {
if (newVal !== oldVal) {
this.targetCoil.itemId = null; // 清空物品ID
this.loadItemList(newVal);
}
}
},
async created() {
// 加载库区列表
await this.loadWarehouses();
// 从路由参数获取coilId、actionId和readonly
const coilId = this.$route.query.coilId;
const actionId = this.$route.query.actionId;
const readonly = this.$route.query.readonly;
// 保存当前页面的待操作ID
if (actionId) {
this.actionId = actionId;
}
// 设置只读模式
if (readonly === 'true' || readonly === true) {
this.readonly = true;
}
// 如果有coilId加载该钢卷作为第一个源卷
if (coilId) {
await this.loadFirstCoil(coilId);
// 加载其他待合卷的钢卷列表
await this.loadPendingMergeList();
} else {
// 没有coilId初始化空的源卷
this.sourceCoils = [
{
coilId: null,
enterCoilNo: '',
currentCoilNo: '',
itemType: null,
itemId: null,
warehouseName: '',
materialName: '',
productName: ''
},
{
coilId: null,
enterCoilNo: '',
currentCoilNo: '',
itemType: null,
itemId: null,
warehouseName: '',
materialName: '',
productName: ''
}
];
}
},
methods: {
// 加载第一个钢卷(从待操作进入时)
async loadFirstCoil(coilId) {
try {
this.loading = true;
const response = await getMaterialCoil(coilId);
if (response.code === 200 && response.data) {
const data = response.data;
// 初始化源卷列表,第一个是当前钢卷
this.sourceCoils = [
{
coilId: data.coilId,
enterCoilNo: data.enterCoilNo || '',
currentCoilNo: data.currentCoilNo || '',
itemType: data.itemType,
itemId: data.itemId,
warehouseName: data.warehouseName || (data.warehouse ? data.warehouse.warehouseName : ''),
materialName: data.materialName || (data.rawMaterial ? data.rawMaterial.rawMaterialName : ''),
productName: data.productName || (data.product ? data.product.productName : '')
},
{
coilId: null,
enterCoilNo: '',
currentCoilNo: '',
itemType: null,
itemId: null,
warehouseName: '',
materialName: '',
productName: ''
}
];
// 自动填充目标卷信息
this.targetCoil.itemType = data.itemType;
this.targetCoil.itemId = data.itemId;
this.targetCoil.nextWarehouseId = data.warehouseId;
// 加载对应的物品列表
if (data.itemType) {
await this.loadItemList(data.itemType);
}
}
} catch (error) {
this.$message.error('加载钢卷信息失败');
console.error(error);
} finally {
this.loading = false;
}
},
// 加载待合卷列表
async loadPendingMergeList() {
try {
this.pendingLoading = true;
const response = await listPendingAction({
actionType: 1, // 1=合卷
actionStatus: 0, // 0=待处理
pageNum: 1,
pageSize: 50
});
if (response.code === 200) {
// 排除当前钢卷
const currentCoilId = this.sourceCoils[0].coilId;
this.pendingMergeList = (response.rows || []).filter(item => item.coilId !== currentCoilId);
}
} catch (error) {
console.error('加载待合卷列表失败', error);
} finally {
this.pendingLoading = false;
}
},
// 选择待操作中的钢卷
async selectPendingCoil(pending, index) {
try {
this.loading = true;
const response = await getMaterialCoil(pending.coilId);
if (response.code === 200 && response.data) {
const data = response.data;
this.$set(this.sourceCoils, index, {
coilId: data.coilId,
enterCoilNo: data.enterCoilNo || '',
currentCoilNo: data.currentCoilNo || '',
itemType: data.itemType,
itemId: data.itemId,
warehouseName: data.warehouseName || (data.warehouse ? data.warehouse.warehouseName : ''),
materialName: data.materialName || (data.rawMaterial ? data.rawMaterial.rawMaterialName : ''),
productName: data.productName || (data.product ? data.product.productName : ''),
actionId: pending.actionId // 保存待操作ID用于后续完成操作
});
this.$message.success('已添加到合卷列表');
}
} catch (error) {
this.$message.error('加载钢卷信息失败');
console.error(error);
} finally {
this.loading = false;
}
},
// 格式化时间
formatTime(time) {
if (!time) return '';
const date = new Date(time);
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
return `${month}-${day} ${hour}:${minute}`;
},
// 加载库区列表
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);
}
},
// 加载物品列表(根据类型)
async loadItemList(itemType) {
if (!itemType) return;
try {
this.itemSearchLoading = true;
if (itemType === 'raw_material') {
const response = await listRawMaterial({ pageNum: 1, pageSize: 100 });
if (response.code === 200) {
this.rawMaterialList = response.rows || [];
}
} else if (itemType === 'product') {
const response = await listProduct({ pageNum: 1, pageSize: 100 });
if (response.code === 200) {
this.productList = response.rows || [];
}
}
} catch (error) {
console.error('加载物品列表失败', error);
} finally {
this.itemSearchLoading = false;
}
},
// 搜索物品
async searchItems(query) {
if (!this.targetCoil.itemType) {
this.$message.warning('请先选择物品类型');
return;
}
try {
this.itemSearchLoading = true;
if (this.targetCoil.itemType === 'raw_material') {
const response = await listRawMaterial({
rawMaterialName: query,
pageNum: 1,
pageSize: 50
});
if (response.code === 200) {
this.rawMaterialList = response.rows || [];
}
} else if (this.targetCoil.itemType === 'product') {
const response = await listProduct({
productName: query,
pageNum: 1,
pageSize: 50
});
if (response.code === 200) {
this.productList = response.rows || [];
}
}
} catch (error) {
console.error('搜索物品失败', error);
} finally {
this.itemSearchLoading = false;
}
},
// 添加源卷
addSourceCoil() {
this.sourceCoils.push({
coilId: null,
enterCoilNo: '',
currentCoilNo: '',
grade: '',
weight: 0,
thickness: null,
width: null,
warehouseId: null,
team: null,
itemType: null,
itemId: null
itemId: null,
warehouseName: '',
materialName: '',
productName: ''
});
},
// 删除源卷
removeSourceCoil(index) {
if (this.sourceCoils.length > 2) {
@@ -206,7 +541,7 @@ export default {
this.$message.warning('至少需要2个源卷才能合卷');
}
},
// 选择钢卷
selectCoil(index) {
this.currentSelectIndex = index;
@@ -218,31 +553,25 @@ export default {
const index = this.currentSelectIndex;
this.$set(this.sourceCoils, index, {
coilId: coil.coilId,
enterCoilNo: coil.enterCoilNo || '',
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
itemId: coil.itemId,
warehouseName: coil.warehouseName || '',
materialName: coil.materialName || '',
productName: coil.productName || ''
});
// 如果是第一个源卷,自动填充目标卷信息
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.targetCoil.nextWarehouseId = coil.warehouseId;
}
this.$message.success('钢卷选择成功');
},
// 保存合卷
async handleSave() {
// 验证源卷数量
@@ -266,52 +595,48 @@ export default {
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;
}
// 验证班组
if (!this.targetCoil.team || this.targetCoil.team.trim() === '') {
this.$message.error('请输入班组名称');
return;
}
try {
this.loading = true;
// 构造合卷数据
// 入场钢卷号:所有源卷的入场钢卷号拼接(逗号分隔)
const enterCoilNos = this.sourceCoils
.map(item => item.enterCoilNo)
.filter(no => no) // 过滤空值
.join(',');
const mergeData = {
enterCoilNo: enterCoilNos, // 拼接的入场钢卷号
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,
grossWeight: this.targetCoil.grossWeight,
netWeight: this.targetCoil.netWeight,
nextWarehouseId: this.targetCoil.nextWarehouseId,
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
enterCoilNo: item.enterCoilNo,
currentCoilNo: item.currentCoilNo
}))
};
console.log('提交的合卷数据:', mergeData);
const response = await mergeMaterialCoil(mergeData);
if (response.code === 200) {
this.$message.success('合卷保存成功');
// 完成所有相关的待操作记录
await this.completeAllRelatedActions();
// 延迟返回,让用户看到成功提示
setTimeout(() => {
this.$router.back();
@@ -326,7 +651,38 @@ export default {
this.loading = false;
}
},
// 完成所有相关的待操作记录
async completeAllRelatedActions() {
try {
// 收集所有待操作ID
const actionIds = [];
// 当前页面的actionId从路由参数获取
if (this.actionId) {
actionIds.push(this.actionId);
}
// 从待合卷列表中选择的钢卷的actionId
this.sourceCoils.forEach(item => {
if (item.actionId) {
actionIds.push(item.actionId);
}
});
// 批量完成所有待操作
console.log('需要完成的待操作ID列表:', actionIds);
const promises = actionIds.map(id => completeAction(id));
await Promise.all(promises);
console.log('所有待操作已完成');
} catch (error) {
console.error('完成待操作失败:', error);
// 不影响主流程,只记录错误
}
},
// 取消操作
handleCancel() {
this.$router.back();
@@ -361,7 +717,7 @@ export default {
display: flex;
align-items: center;
gap: 8px;
i {
color: #0066cc;
font-size: 20px;
@@ -416,11 +772,11 @@ export default {
overflow-y: auto;
padding-right: 10px;
margin-bottom: 20px;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #dcdfe6;
border-radius: 3px;
@@ -433,7 +789,7 @@ export default {
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);
@@ -481,13 +837,107 @@ export default {
.source-coil-body {
padding: 12px 16px;
text-align: center;
&:empty {
text-align: center;
}
.empty-tip {
text-align: center;
color: #909399;
font-size: 13px;
padding: 10px 0;
i {
display: block;
font-size: 24px;
margin-bottom: 5px;
}
}
}
/* 待合卷列表 */
.pending-list-title {
font-size: 13px;
font-weight: 500;
color: #606266;
margin-bottom: 10px;
padding-bottom: 8px;
border-bottom: 1px solid #e4e7ed;
}
.pending-coil-list {
max-height: 300px;
overflow-y: auto;
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-thumb {
background: #dcdfe6;
border-radius: 2px;
}
}
.pending-coil-item {
padding: 10px;
margin-bottom: 8px;
background: #f5f7fa;
border: 1px solid #e4e7ed;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
&:hover {
background: #ecf5ff;
border-color: #0066cc;
}
.pending-coil-no {
font-size: 14px;
font-weight: 500;
color: #303133;
margin-bottom: 4px;
}
.pending-coil-info {
font-size: 12px;
color: #909399;
.pending-label {
margin-right: 4px;
}
}
}
.source-detail-row {
display: flex;
align-items: flex-start;
margin-bottom: 8px;
font-size: 13px;
&:last-child {
margin-bottom: 0;
}
.detail-label {
color: #909399;
min-width: 90px;
flex-shrink: 0;
}
.detail-value {
color: #303133;
flex: 1;
word-break: break-all;
}
}
.btn-remove {
color: #f56c6c;
padding: 0;
&:hover {
color: #f56c6c;
}
@@ -562,12 +1012,43 @@ export default {
.rule-list {
padding-left: 20px;
margin: 0;
li {
color: #606266;
font-size: 13px;
line-height: 24px;
}
}
// 优化按钮文字颜色
// 实心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;
}
}
// 修复数字输入框的上下箭头溢出
.target-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>

View File

@@ -7,8 +7,8 @@
<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>
<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>
@@ -18,30 +18,52 @@
<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>
<span class="coil-title">钢卷信息</span>
</div>
<div class="coil-body">
<div class="coil-info-row">
<span class="label">钢种</span>
<span class="value">{{ motherCoil.grade || '—' }}</span>
<span class="label">入场钢卷号</span>
<span class="value">{{ motherCoil.enterCoilNo || '—' }}</span>
</div>
<div class="coil-info-row">
<span class="label">厚度</span>
<span class="value">{{ motherCoil.thickness || '—' }} mm</span>
<span class="label">当前钢卷号</span>
<span class="value">{{ motherCoil.currentCoilNo || '—' }}</span>
</div>
<div class="coil-info-row">
<span class="label">宽度</span>
<span class="value">{{ motherCoil.width || '' }} mm</span>
<span class="label">当前库区</span>
<span class="value">{{ motherCoil.warehouseName || '未分配' }}</span>
</div>
<div class="coil-info-row">
<span class="label">重量</span>
<span class="value highlight">{{ motherCoil.weight || '—' }} t</span>
<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>
<!-- BOM参数展示 -->
<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>
@@ -65,43 +87,101 @@
<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>
<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
type="text"
size="mini"
icon="el-icon-delete"
<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="70px">
<el-form-item label="卷号">
<el-input v-model="item.currentCoilNo" placeholder="输入子卷卷号"></el-input>
<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="重量(t)">
<el-input-number
v-model="item.weight"
:min="0"
:precision="2"
controls-position="right"
style="width: 100%"
></el-input-number>
<el-form-item label="班组" required>
<el-input v-model="item.team" placeholder="输入班组名称" :disabled="readonly"></el-input>
</el-form-item>
<el-form-item label="长度(m)">
<el-input-number
v-model="item.length"
:min="0"
:precision="2"
controls-position="right"
<el-form-item label="物品类型" required>
<el-select
v-model="item.itemType"
placeholder="请选择"
style="width: 100%"
></el-input-number>
@change="handleItemTypeChange(index)"
:disabled="readonly"
>
<el-option label="原材料" value="raw_material" />
<el-option label="产品" value="product" />
</el-select>
</el-form-item>
<el-form-item label="物品" required>
<el-select
v-model="item.itemId"
placeholder="请选择物品"
filterable
remote
:remote-method="(query) => searchItemsForSplit(query, index)"
:loading="itemSearchLoading"
style="width: 100%"
:disabled="readonly"
>
<el-option
v-for="option in getItemListForSplit(item.itemType)"
:key="option.id"
:label="option.name"
:value="option.id"
/>
</el-select>
</el-form-item>
<el-form-item label="毛重(t)" required>
<el-input
v-model.number="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.number="item.netWeight"
placeholder="请输入净重"
type="number"
step="0.01"
:disabled="readonly"
>
<template slot="append">吨</template>
</el-input>
</el-form-item>
<el-form-item label="目标库区" required>
<el-select
v-model="item.nextWarehouseId"
placeholder="请选择目标库区"
style="width: 100%"
filterable
:disabled="readonly"
>
<el-option
v-for="warehouse in warehouseList"
:key="warehouse.warehouseId"
:label="warehouse.warehouseName"
:value="warehouse.warehouseId"
/>
</el-select>
</el-form-item>
</el-form>
</div>
@@ -114,18 +194,6 @@
<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>
@@ -140,6 +208,9 @@
<script>
import { getMaterialCoil, splitMaterialCoil } from '@/api/wms/coil';
import { listWarehouse } from '@/api/wms/warehouse';
import { listRawMaterial } from '@/api/wms/rawMaterial';
import { listProduct } from '@/api/wms/product';
import CoilSelector from '@/components/CoilSelector';
export default {
@@ -152,45 +223,146 @@ export default {
// 母卷信息
motherCoil: {
coilId: null,
enterCoilNo: '',
currentCoilNo: '',
grade: '',
thickness: null,
width: null,
weight: null,
team: '',
warehouseId: null,
team: null,
warehouseName: '',
itemType: null,
itemId: null,
enterCoilNo: '',
supplierCoilNo: ''
materialName: '',
productName: '',
grossWeight: null,
netWeight: null,
bomItems: []
},
// 子卷列表
splitList: [
{ currentCoilNo: '', weight: 0, length: 0 }
{
currentCoilNo: '',
team: '',
itemType: null,
itemId: null,
grossWeight: null,
netWeight: null,
nextWarehouseId: null
}
],
loading: false,
// 钢卷选择器可见性
coilSelectorVisible: false
coilSelectorVisible: false,
// 库区列表
warehouseList: [],
// 原材料和产品列表
rawMaterialList: [],
productList: [],
itemSearchLoading: false,
// 只读模式
readonly: 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参数则加载母卷信息
async created() {
// 先加载库区列表
await this.loadWarehouses();
// 从路由参数获取coilId和readonly
const coilId = this.$route.query.coilId;
const readonly = this.$route.query.readonly;
if (coilId) {
this.loadMotherCoil(coilId);
await this.loadMotherCoil(coilId);
}
// 设置只读模式
if (readonly === 'true' || readonly === true) {
this.readonly = true;
}
},
methods: {
// 获取子卷的物品列表
getItemListForSplit(itemType) {
if (itemType === 'raw_material') {
return this.rawMaterialList.map(item => ({
id: item.rawMaterialId,
name: item.rawMaterialName
}));
} else if (itemType === 'product') {
return this.productList.map(item => ({
id: item.productId,
name: item.productName
}));
}
return [];
},
// 物品类型变化
handleItemTypeChange(index) {
this.splitList[index].itemId = null;
this.loadItemListForSplit(this.splitList[index].itemType);
},
// 搜索子卷物品
async searchItemsForSplit(query, index) {
const itemType = this.splitList[index].itemType;
if (!itemType) {
this.$message.warning('请先选择物品类型');
return;
}
try {
this.itemSearchLoading = true;
if (itemType === 'raw_material') {
const response = await listRawMaterial({
rawMaterialName: query,
pageNum: 1,
pageSize: 50
});
if (response.code === 200) {
this.rawMaterialList = response.rows || [];
}
} else if (itemType === 'product') {
const response = await listProduct({
productName: query,
pageNum: 1,
pageSize: 50
});
if (response.code === 200) {
this.productList = response.rows || [];
}
}
} catch (error) {
console.error('搜索物品失败', error);
} finally {
this.itemSearchLoading = false;
}
},
// 加载子卷物品列表
async loadItemListForSplit(itemType) {
if (!itemType) return;
try {
this.itemSearchLoading = true;
if (itemType === 'raw_material') {
const response = await listRawMaterial({ pageNum: 1, pageSize: 100 });
if (response.code === 200) {
this.rawMaterialList = response.rows || [];
}
} else if (itemType === 'product') {
const response = await listProduct({ pageNum: 1, pageSize: 100 });
if (response.code === 200) {
this.productList = response.rows || [];
}
}
} catch (error) {
console.error('加载物品列表失败', error);
} finally {
this.itemSearchLoading = false;
}
},
// 显示钢卷选择器
showCoilSelector() {
this.coilSelectorVisible = true;
@@ -200,17 +372,18 @@ export default {
handleCoilSelect(coil) {
this.motherCoil = {
coilId: coil.coilId,
enterCoilNo: coil.enterCoilNo || '',
currentCoilNo: coil.currentCoilNo || '',
grade: coil.grade || '',
thickness: coil.thickness,
width: coil.width,
weight: coil.weight,
team: coil.team || '',
warehouseId: coil.warehouseId,
team: coil.team,
warehouseName: coil.warehouseName || '',
itemType: coil.itemType,
itemId: coil.itemId,
enterCoilNo: coil.enterCoilNo || '',
supplierCoilNo: coil.supplierCoilNo || ''
materialName: coil.materialName || '',
productName: coil.productName || '',
grossWeight: coil.grossWeight,
netWeight: coil.netWeight,
bomItems: coil.bomItemList || coil.bomItems || []
};
this.$message.success('母卷选择成功');
},
@@ -224,17 +397,18 @@ export default {
const data = response.data;
this.motherCoil = {
coilId: data.coilId,
enterCoilNo: data.enterCoilNo || '',
currentCoilNo: data.currentCoilNo || '',
grade: data.grade || '',
thickness: data.thickness,
width: data.width,
weight: data.weight,
team: data.team || '',
warehouseId: data.warehouseId,
team: data.team,
warehouseName: data.warehouseName || (data.warehouse ? data.warehouse.warehouseName : ''),
itemType: data.itemType,
itemId: data.itemId,
enterCoilNo: data.enterCoilNo || '',
supplierCoilNo: data.supplierCoilNo || ''
materialName: data.materialName || (data.rawMaterial ? data.rawMaterial.rawMaterialName : ''),
productName: data.productName || (data.product ? data.product.productName : ''),
grossWeight: data.grossWeight,
netWeight: data.netWeight,
bomItems: data.bomItemList || data.bomItems || []
};
}
} catch (error) {
@@ -245,15 +419,32 @@ export default {
}
},
// 加载库区列表
async loadWarehouses() {
try {
const response = await listWarehouse({ pageNum: 1, pageSize: 1000 });
if (response.code === 200) {
this.warehouseList = response.rows || response.data || [];
console.log('库区列表加载成功,数量:', this.warehouseList.length);
}
} catch (error) {
console.error('加载库区列表失败', error);
}
},
// 添加子卷
addSplitItem() {
this.splitList.push({
currentCoilNo: '',
weight: 0,
length: 0
team: '',
itemType: null,
itemId: null,
grossWeight: null,
netWeight: null,
nextWarehouseId: null
});
},
// 删除子卷
removeSplitItem(index) {
if (this.splitList.length > 1) {
@@ -262,7 +453,7 @@ export default {
this.$message.warning('至少保留一个子卷');
}
},
// 保存分卷
async handleSave() {
// 验证母卷信息
@@ -277,12 +468,6 @@ export default {
return;
}
// 验证重量
if (this.remainWeight < 0) {
this.$message.error('子卷总重量不能超过母卷重量');
return;
}
// 验证子卷信息
for (let i = 0; i < this.splitList.length; i++) {
const item = this.splitList[i];
@@ -290,8 +475,28 @@ export default {
this.$message.error(`第${i + 1}个子卷的卷号不能为空`);
return;
}
if (!item.weight || item.weight <= 0) {
this.$message.error(`${i + 1}个子卷的重量必须大于0`);
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.nextWarehouseId) {
this.$message.error(`第${i + 1}个子卷的目标库区不能为空`);
return;
}
}
@@ -302,24 +507,24 @@ export default {
// 构造分卷数据
const splitData = {
coilId: this.motherCoil.coilId,
enterCoilNo: this.motherCoil.enterCoilNo, // 入场钢卷号(必填)
currentCoilNo: this.motherCoil.currentCoilNo,
hasMergeSplit: 1, // 1表示分卷
newCoils: this.splitList.map(item => ({
enterCoilNo: this.motherCoil.enterCoilNo, // 子卷继承母卷的入场钢卷号
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
team: item.team,
itemType: item.itemType || this.motherCoil.itemType,
itemId: item.itemId || this.motherCoil.itemId,
grossWeight: item.grossWeight,
netWeight: item.netWeight,
nextWarehouseId: item.nextWarehouseId,
hasMergeSplit: 1
}))
};
console.log('提交的分卷数据:', splitData);
const response = await splitMaterialCoil(splitData);
if (response.code === 200) {
this.$message.success('分卷保存成功');
@@ -337,10 +542,46 @@ export default {
this.loading = false;
}
},
// 取消操作
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;
}
// 复制物品类型和物品ID
if (!item.itemType) {
item.itemType = this.motherCoil.itemType;
}
if (!item.itemId) {
item.itemId = this.motherCoil.itemId;
}
});
// 加载物品列表
if (this.motherCoil.itemType) {
this.loadItemListForSplit(this.motherCoil.itemType);
}
this.$message.success('已复制到所有子卷');
}
}
};
@@ -372,7 +613,7 @@ export default {
display: flex;
align-items: center;
gap: 8px;
i {
color: #0066cc;
font-size: 20px;
@@ -418,7 +659,7 @@ export default {
display: flex;
justify-content: space-between;
align-items: center;
.el-button--text {
font-size: 12px;
}
@@ -444,15 +685,15 @@ export default {
display: flex;
align-items: center;
gap: 10px;
i {
font-size: 20px;
}
.coil-id {
.coil-title {
flex: 1;
font-size: 16px;
font-weight: 600;
letter-spacing: 1px;
}
}
@@ -462,24 +703,27 @@ export default {
.coil-info-row {
display: flex;
align-items: center;
align-items: flex-start;
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
.label {
color: #909399;
font-size: 14px;
min-width: 70px;
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;
@@ -488,6 +732,30 @@ export default {
}
}
/* BOM参数展示 */
.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;
@@ -549,11 +817,11 @@ export default {
overflow-y: auto;
margin-bottom: 20px;
padding-right: 10px;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #dcdfe6;
border-radius: 3px;
@@ -566,7 +834,7 @@ export default {
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);
@@ -598,7 +866,7 @@ export default {
.btn-remove {
color: #f56c6c;
padding: 0;
&:hover {
color: #f56c6c;
}
@@ -634,10 +902,41 @@ export default {
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>

View File

@@ -0,0 +1,843 @@
<template>
<div class="typing-coil-container">
<!-- 顶部操作栏 -->
<div class="header-bar">
<div class="header-title">
<i class="el-icon-edit"></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="content-wrapper">
<!-- 左侧当前信息 -->
<div class="left-panel">
<el-card class="info-card">
<div slot="header" class="card-header">
<span><i class="el-icon-info"></i> 当前信息</span>
</div>
<div class="info-section">
<div class="info-row">
<span class="info-label">入场钢卷号</span>
<span class="info-value">{{ currentInfo.enterCoilNo || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">当前钢卷号</span>
<span class="info-value">{{ currentInfo.currentCoilNo || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">厂家原料卷号</span>
<span class="info-value">{{ currentInfo.supplierCoilNo || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">班组</span>
<span class="info-value">{{ currentInfo.team || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">物品类型</span>
<span class="info-value">{{ getItemTypeText(currentInfo.itemType) }}</span>
</div>
<div class="info-row">
<span class="info-label">物料名称</span>
<span class="info-value">{{ currentInfo.itemName || '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">毛重</span>
<span class="info-value">{{ currentInfo.grossWeight ? currentInfo.grossWeight + ' t' : '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">净重</span>
<span class="info-value">{{ currentInfo.netWeight ? currentInfo.netWeight + ' t' : '—' }}</span>
</div>
<div class="info-row">
<span class="info-label">目标库区</span>
<span class="info-value">{{ currentInfo.nextWarehouseName || '—' }}</span>
</div>
<div class="info-row" v-if="currentInfo.remark">
<span class="info-label">备注</span>
<span class="info-value">{{ currentInfo.remark }}</span>
</div>
</div>
</el-card>
</div>
<!-- 右侧更新表单 -->
<div class="right-panel">
<el-card class="form-card">
<div slot="header" class="card-header">
<span><i class="el-icon-edit-outline"></i> {{ readonly ? '查看信息' : '更新信息' }}</span>
<el-button v-if="!readonly" type="text" size="mini" @click="copyFromCurrent" icon="el-icon-document-copy">
复制当前信息
</el-button>
</div>
<el-form
ref="updateForm"
:model="updateForm"
:rules="rules"
label-width="120px"
size="small"
>
<el-form-item label="当前钢卷号" prop="currentCoilNo">
<el-input
v-model="updateForm.currentCoilNo"
placeholder="请输入当前钢卷号"
:disabled="readonly"
>
<template slot="prepend">
<i class="el-icon-document"></i>
</template>
</el-input>
</el-form-item>
<el-form-item label="班组" prop="team">
<el-input
v-model="updateForm.team"
placeholder="请输入班组名称"
:disabled="readonly"
>
<template slot="prepend">
<i class="el-icon-user-solid"></i>
</template>
</el-input>
</el-form-item>
<el-form-item label="物品类型" prop="itemType">
<el-select
v-model="updateForm.itemType"
placeholder="请选择物品类型"
style="width: 100%"
:disabled="readonly"
>
<el-option label="原材料" value="raw_material" />
<el-option label="产品" value="product" />
</el-select>
</el-form-item>
<el-form-item label="物品" prop="itemId">
<el-select
v-model="updateForm.itemId"
placeholder="请选择物品"
filterable
remote
:remote-method="searchItems"
:loading="itemSearchLoading"
style="width: 100%"
:disabled="readonly"
>
<el-option
v-for="item in currentItemList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="毛重(t)" prop="grossWeight">
<el-input
v-model.number="updateForm.grossWeight"
placeholder="请输入毛重"
type="number"
step="0.01"
:disabled="readonly"
>
<template slot="append"></template>
</el-input>
</el-form-item>
<el-form-item label="净重(t)" prop="netWeight">
<el-input
v-model.number="updateForm.netWeight"
placeholder="请输入净重"
type="number"
step="0.01"
:disabled="readonly"
>
<template slot="append"></template>
</el-input>
</el-form-item>
<el-form-item label="目标库区" prop="nextWarehouseId">
<el-select
v-model="updateForm.nextWarehouseId"
placeholder="请选择目标库区"
style="width: 100%"
filterable
:disabled="readonly"
>
<el-option
v-for="warehouse in warehouseList"
:key="warehouse.warehouseId"
:label="warehouse.warehouseName"
:value="warehouse.warehouseId"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="updateForm.remark"
type="textarea"
:rows="4"
placeholder="请输入备注信息(非必填)"
maxlength="500"
show-word-limit
:disabled="readonly"
/>
</el-form-item>
</el-form>
</el-card>
</div>
</div>
<!-- 变更历史占满整行 -->
<div class="history-section">
<el-card class="history-card">
<div slot="header" class="card-header">
<span><i class="el-icon-time"></i> 变更历史</span>
<el-button type="text" size="mini" @click="loadHistory" :loading="historyLoading">
<i class="el-icon-refresh"></i> 刷新
</el-button>
</div>
<el-timeline v-if="historySteps.length > 0">
<el-timeline-item
v-for="(step, index) in historySteps"
:key="index"
:timestamp="`步骤 ${step.display_step || step.step}`"
placement="top"
:type="step.operation === '新增' ? 'success' : 'primary'"
>
<div class="history-item">
<div class="history-title">{{ step.operation || step.action }}</div>
<div class="history-detail" v-if="step.operator">
<span class="detail-label">操作人</span>
<span>{{ step.operator }}</span>
</div>
<div class="history-detail" v-if="step.old_current_coil_no">
<span class="detail-label">原钢卷号</span>
<span>{{ step.old_current_coil_no }}</span>
</div>
<div class="history-detail" v-if="step.new_current_coil_no">
<span class="detail-label">新钢卷号</span>
<span>{{ step.new_current_coil_no }}</span>
</div>
</div>
</el-timeline-item>
</el-timeline>
<div v-else class="empty-history">
<i class="el-icon-document"></i>
<p>暂无变更历史</p>
</div>
</el-card>
</div>
</div>
</template>
<script>
import { getMaterialCoil, updateMaterialCoil, getMaterialCoilTrace } from '@/api/wms/coil';
import { completeAction } from '@/api/wms/pendingAction';
import { listWarehouse } from '@/api/wms/warehouse';
import { listRawMaterial } from '@/api/wms/rawMaterial';
import { listProduct } from '@/api/wms/product';
export default {
name: 'TypingCoil',
data() {
return {
loading: false,
historyLoading: false,
// 当前信息(只读)
currentInfo: {
coilId: null,
enterCoilNo: '',
currentCoilNo: '',
supplierCoilNo: '',
team: '',
itemType: null,
itemId: null,
itemName: '',
grossWeight: null,
netWeight: null,
warehouseId: null,
nextWarehouseId: null,
nextWarehouseName: '',
status: 0,
remark: ''
},
// 更新表单
updateForm: {
currentCoilNo: '',
team: '',
itemType: null,
itemId: null,
grossWeight: null,
netWeight: null,
nextWarehouseId: null,
remark: ''
},
rules: {
currentCoilNo: [
{ required: true, message: '请输入当前钢卷号', trigger: 'blur' }
],
team: [
{ required: true, message: '请输入班组', trigger: 'blur' }
],
itemType: [
{ required: true, message: '请选择物品类型', trigger: 'change' }
],
itemId: [
{ required: true, message: '请选择物品', trigger: 'change' }
],
grossWeight: [
{ required: true, message: '请输入毛重', trigger: 'blur' },
{ type: 'number', message: '毛重必须为数字', trigger: 'blur' }
],
netWeight: [
{ required: true, message: '请输入净重', trigger: 'blur' },
{ type: 'number', message: '净重必须为数字', trigger: 'blur' }
],
nextWarehouseId: [
{ required: true, message: '请选择目标库区', trigger: 'change' }
]
},
warehouseList: [],
historySteps: [],
actionId: null,
// 原材料和产品列表
rawMaterialList: [],
productList: [],
itemSearchLoading: false,
// 只读模式
readonly: false
};
},
computed: {
// 当前物品列表(根据物品类型动态切换)
currentItemList() {
if (this.updateForm.itemType === 'raw_material') {
return this.rawMaterialList.map(item => ({
id: item.rawMaterialId,
name: item.rawMaterialName
}));
} else if (this.updateForm.itemType === 'product') {
return this.productList.map(item => ({
id: item.productId,
name: item.productName
}));
}
return [];
}
},
watch: {
// 监听物品类型变化,加载对应的列表
'updateForm.itemType'(newVal, oldVal) {
if (newVal !== oldVal) {
this.updateForm.itemId = null;
this.loadItemList(newVal);
}
}
},
async created() {
// 先加载库区列表
await this.loadWarehouses();
// 从路由参数获取coilId和actionId
const coilId = this.$route.query.coilId;
const actionId = this.$route.query.actionId;
const readonly = this.$route.query.readonly;
if (coilId) {
await this.loadCoilInfo(coilId);
}
if (actionId) {
this.actionId = actionId;
}
// 设置只读模式
if (readonly === 'true' || readonly === true) {
this.readonly = true;
}
},
methods: {
// 加载钢卷信息
async loadCoilInfo(coilId) {
try {
this.loading = true;
const response = await getMaterialCoil(coilId);
if (response.code === 200 && response.data) {
const data = response.data;
// 填充当前信息(左侧)
this.currentInfo = {
coilId: data.coilId,
enterCoilNo: data.enterCoilNo || '',
currentCoilNo: data.currentCoilNo || '',
supplierCoilNo: data.supplierCoilNo || '',
team: data.team || '',
itemType: data.itemType || null,
itemId: data.itemId || null,
itemName: this.getItemName(data),
grossWeight: data.grossWeight,
netWeight: data.netWeight,
warehouseId: data.warehouseId,
nextWarehouseId: data.nextWarehouseId,
nextWarehouseName: this.getWarehouseName(data.nextWarehouseId),
remark: data.remark || ''
};
console.log('当前信息加载完成:', this.currentInfo);
// 重新获取库区名称确保warehouseList已加载
if (data.nextWarehouseId) {
this.currentInfo.nextWarehouseName = this.getWarehouseName(data.nextWarehouseId);
}
// 加载对应类型的物品列表
if (data.itemType) {
await this.loadItemList(data.itemType);
}
// 加载变更历史
this.loadHistory();
}
} catch (error) {
this.$message.error('加载钢卷信息失败');
console.error(error);
} finally {
this.loading = false;
}
},
// 获取物料名称
getItemName(data) {
if (data.rawMaterial) {
return data.rawMaterial.rawMaterialName;
} else if (data.product) {
return data.product.productName;
}
return '';
},
// 获取物品类型文本
getItemTypeText(itemType) {
if (itemType === 'raw_material') return '原材料';
if (itemType === 'product') return '产品';
return '—';
},
// 获取库区名称
getWarehouseName(warehouseId) {
if (!warehouseId) return '';
const warehouse = this.warehouseList.find(w => w.warehouseId === warehouseId);
return warehouse ? warehouse.warehouseName : '';
},
// 加载库区列表
async loadWarehouses() {
try {
const response = await listWarehouse({ pageNum: 1, pageSize: 1000 });
if (response.code === 200) {
this.warehouseList = response.rows || response.data || [];
console.log('库区列表加载成功,数量:', this.warehouseList.length);
}
} catch (error) {
console.error('加载库区列表失败', error);
}
},
// 加载物品列表(根据类型)
async loadItemList(itemType) {
if (!itemType) return;
try {
this.itemSearchLoading = true;
if (itemType === 'raw_material') {
const response = await listRawMaterial({ pageNum: 1, pageSize: 100 });
if (response.code === 200) {
this.rawMaterialList = response.rows || [];
}
} else if (itemType === 'product') {
const response = await listProduct({ pageNum: 1, pageSize: 100 });
if (response.code === 200) {
this.productList = response.rows || [];
}
}
} catch (error) {
console.error('加载物品列表失败', error);
} finally {
this.itemSearchLoading = false;
}
},
// 搜索物品
async searchItems(query) {
if (!this.updateForm.itemType) {
this.$message.warning('请先选择物品类型');
return;
}
try {
this.itemSearchLoading = true;
if (this.updateForm.itemType === 'raw_material') {
const response = await listRawMaterial({
rawMaterialName: query,
pageNum: 1,
pageSize: 50
});
if (response.code === 200) {
this.rawMaterialList = response.rows || [];
}
} else if (this.updateForm.itemType === 'product') {
const response = await listProduct({
productName: query,
pageNum: 1,
pageSize: 50
});
if (response.code === 200) {
this.productList = response.rows || [];
}
}
} catch (error) {
console.error('搜索物品失败', error);
} finally {
this.itemSearchLoading = false;
}
},
// 物品选择变化
handleItemChange(itemId) {
console.log('选择的物品ID:', itemId);
},
// 加载变更历史
async loadHistory() {
if (!this.currentInfo.enterCoilNo) {
return;
}
try {
this.historyLoading = true;
const response = await getMaterialCoilTrace({
enterCoilNo: this.currentInfo.enterCoilNo,
currentCoilNo: this.currentInfo.currentCoilNo || undefined
});
if (response.code === 200 && response.data) {
this.historySteps = response.data.steps || [];
}
} catch (error) {
console.error('加载变更历史失败', error);
} finally {
this.historyLoading = false;
}
},
// 复制当前信息到更新表单
copyFromCurrent() {
this.updateForm = {
currentCoilNo: this.currentInfo.currentCoilNo,
team: this.currentInfo.team,
itemType: this.currentInfo.itemType,
itemId: this.currentInfo.itemId,
grossWeight: parseFloat(this.currentInfo.grossWeight) || null,
netWeight: parseFloat(this.currentInfo.netWeight) || null,
nextWarehouseId: this.currentInfo.nextWarehouseId,
remark: this.currentInfo.remark
};
console.log('复制的表单数据:', this.updateForm);
// 加载对应的物品列表
if (this.updateForm.itemType) {
this.loadItemList(this.updateForm.itemType);
}
this.$message.success('已复制当前信息');
},
// 保存更新
async handleSave() {
this.$refs.updateForm.validate(async (valid) => {
if (!valid) {
return false;
}
try {
this.loading = true;
// 构造更新数据使用标准update接口会创建历史版本
const updateData = {
coilId: this.currentInfo.coilId,
enterCoilNo: this.currentInfo.enterCoilNo, // 入场钢卷号,从当前信息获取(必填)
supplierCoilNo: this.currentInfo.supplierCoilNo, // 厂家原料卷号(保持不变)
currentCoilNo: this.updateForm.currentCoilNo,
team: this.updateForm.team,
itemType: this.updateForm.itemType,
itemId: this.updateForm.itemId,
grossWeight: this.updateForm.grossWeight,
netWeight: this.updateForm.netWeight,
warehouseId: this.currentInfo.warehouseId, // 当前库区ID保持不变
nextWarehouseId: this.updateForm.nextWarehouseId, // 目标库区ID
remark: this.updateForm.remark
};
console.log('提交的更新数据:', updateData);
const response = await updateMaterialCoil(updateData);
if (response.code === 200) {
this.$message.success('钢卷信息更新成功');
// 如果是从待操作列表进来的,标记操作为完成
if (this.actionId) {
await completeAction(this.actionId);
}
// 延迟返回
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">
.typing-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;
}
}
/* 主内容区 */
.content-wrapper {
display: grid;
grid-template-columns: 400px 1fr;
gap: 20px;
align-items: stretch; // 改为stretch让子元素高度一致
}
/* 左侧面板 */
.left-panel {
min-width: 0;
display: flex;
flex-direction: column;
}
/* 右侧面板 */
.right-panel {
min-width: 0;
display: flex;
flex-direction: column;
}
/* 确保两侧卡片高度一致 */
.info-card,
.form-card {
flex: 1;
display: flex;
flex-direction: column;
::v-deep .el-card__body {
flex: 1;
display: flex;
flex-direction: column;
}
}
/* 变更历史区域(占满整行) */
.history-section {
margin-top: 20px;
}
/* 卡片头部 */
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
font-weight: 500;
i {
color: #0066cc;
margin-right: 5px;
}
}
/* 当前信息展示 */
.info-section {
.info-row {
display: flex;
align-items: flex-start;
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
.info-label {
color: #909399;
font-size: 14px;
min-width: 110px;
flex-shrink: 0;
}
.info-value {
color: #303133;
font-size: 14px;
font-weight: 500;
flex: 1;
word-break: break-all;
}
}
}
/* 变更历史 */
.history-card {
::v-deep .el-card__body {
max-height: 400px;
overflow-y: auto;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #dcdfe6;
border-radius: 3px;
}
}
::v-deep .el-timeline {
padding-left: 10px;
}
}
.history-item {
.history-title {
font-weight: 500;
color: #303133;
margin-bottom: 8px;
}
.history-detail {
font-size: 13px;
color: #606266;
margin-bottom: 4px;
.detail-label {
color: #909399;
margin-right: 5px;
}
}
}
.empty-history {
text-align: center;
padding: 40px 0;
color: #909399;
i {
font-size: 48px;
margin-bottom: 10px;
display: block;
}
p {
margin: 0;
}
}
/* 表单样式优化 */
.form-card {
::v-deep .el-input-number {
width: 100%;
.el-input__inner {
text-align: left;
}
}
::v-deep .el-form-item {
margin-bottom: 20px;
}
// 修复数字输入框的样式
::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;
}
}
}
// 优化按钮文字颜色
// 实心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;
}
}
</style>

View File

@@ -0,0 +1,137 @@
package com.klp.controller;
import java.util.List;
import java.util.Arrays;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.klp.common.annotation.RepeatSubmit;
import com.klp.common.annotation.Log;
import com.klp.common.core.controller.BaseController;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.domain.R;
import com.klp.common.core.validate.AddGroup;
import com.klp.common.core.validate.EditGroup;
import com.klp.common.enums.BusinessType;
import com.klp.common.utils.poi.ExcelUtil;
import com.klp.domain.vo.WmsCoilPendingActionVo;
import com.klp.domain.bo.WmsCoilPendingActionBo;
import com.klp.service.IWmsCoilPendingActionService;
import com.klp.common.core.page.TableDataInfo;
/**
* 钢卷待操作
*
* @author Joshi
* @date 2025-11-03
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/wms/coilPendingAction")
public class WmsCoilPendingActionController extends BaseController {
private final IWmsCoilPendingActionService iWmsCoilPendingActionService;
/**
* 查询钢卷待操作列表
*/
@GetMapping("/list")
public TableDataInfo<WmsCoilPendingActionVo> list(WmsCoilPendingActionBo bo, PageQuery pageQuery) {
return iWmsCoilPendingActionService.queryPageList(bo, pageQuery);
}
/**
* 导出钢卷待操作列表
*/
@Log(title = "钢卷待操作", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(WmsCoilPendingActionBo bo, HttpServletResponse response) {
List<WmsCoilPendingActionVo> list = iWmsCoilPendingActionService.queryList(bo);
ExcelUtil.exportExcel(list, "钢卷待操作", WmsCoilPendingActionVo.class, response);
}
/**
* 获取钢卷待操作详细信息
*
* @param actionId 主键
*/
@GetMapping("/{actionId}")
public R<WmsCoilPendingActionVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long actionId) {
return R.ok(iWmsCoilPendingActionService.queryById(actionId));
}
/**
* 新增钢卷待操作
*/
@Log(title = "钢卷待操作", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody WmsCoilPendingActionBo bo) {
return toAjax(iWmsCoilPendingActionService.insertByBo(bo));
}
/**
* 修改钢卷待操作
*/
@Log(title = "钢卷待操作", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody WmsCoilPendingActionBo bo) {
return toAjax(iWmsCoilPendingActionService.updateByBo(bo));
}
/**
* 删除钢卷待操作
*
* @param actionIds 主键串
*/
@Log(title = "钢卷待操作", businessType = BusinessType.DELETE)
@DeleteMapping("/{actionIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable("actionIds") Long[] actionIds) {
return toAjax(iWmsCoilPendingActionService.deleteWithValidByIds(Arrays.asList(actionIds), true));
}
/**
* 更新操作状态
*/
@Log(title = "钢卷待操作", businessType = BusinessType.UPDATE)
@PutMapping("/status/{actionId}/{status}")
public R<Void> updateStatus(@PathVariable("actionId") Long actionId,
@PathVariable("status") Integer status) {
return toAjax(iWmsCoilPendingActionService.updateStatus(actionId, status));
}
/**
* 开始处理操作
*/
@Log(title = "钢卷待操作", businessType = BusinessType.UPDATE)
@PutMapping("/start/{actionId}")
public R<Void> startProcess(@PathVariable("actionId") Long actionId) {
return toAjax(iWmsCoilPendingActionService.startProcess(actionId));
}
/**
* 完成操作
*/
@Log(title = "钢卷待操作", businessType = BusinessType.UPDATE)
@PutMapping("/complete/{actionId}")
public R<Void> completeAction(@PathVariable("actionId") Long actionId) {
return toAjax(iWmsCoilPendingActionService.completeAction(actionId));
}
/**
* 取消操作
*/
@Log(title = "钢卷待操作", businessType = BusinessType.UPDATE)
@PutMapping("/cancel/{actionId}")
public R<Void> cancelAction(@PathVariable("actionId") Long actionId) {
return toAjax(iWmsCoilPendingActionService.cancelAction(actionId));
}
}

View File

@@ -0,0 +1,100 @@
package com.klp.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
/**
* 钢卷待操作对象 wms_coil_pending_action
*
* @author Joshi
* @date 2025-11-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("wms_coil_pending_action")
public class WmsCoilPendingAction extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "action_id", type = IdType.AUTO)
private Long actionId;
/**
* 关联的钢卷ID
*/
private Long coilId;
/**
* 当前钢卷号
*/
private String currentCoilNo;
/**
* 操作类型1=分卷2=合卷3=更新)
*/
private Integer actionType;
/**
* 操作状态0=待处理1=处理中2=已完成3=已取消)
*/
private Integer actionStatus;
/**
* 扫码时间
*/
private Date scanTime;
/**
* 扫码设备(移动端设备信息)
*/
private String scanDevice;
/**
* 优先级0=普通1=重要2=紧急)
*/
private Integer priority;
/**
* 来源类型scan=扫码manual=手动创建)
*/
private String sourceType;
/**
* 所在库区ID
*/
private Long warehouseId;
/**
* 操作人ID
*/
private Long operatorId;
/**
* 操作人姓名
*/
private String operatorName;
/**
* 处理时间
*/
private Date processTime;
/**
* 完成时间
*/
private Date completeTime;
/**
* 删除标志0=正常1=已删除)
*/
@TableLogic
private Integer delFlag;
}

View File

@@ -0,0 +1,99 @@
package com.klp.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.klp.common.core.validate.AddGroup;
import com.klp.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.util.Date;
import com.klp.common.core.domain.BaseEntity;
/**
* 钢卷待操作业务对象 wms_coil_pending_action
*
* @author Joshi
* @date 2025-11-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class WmsCoilPendingActionBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long actionId;
/**
* 关联的钢卷ID
*/
@NotNull(message = "关联的钢卷ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long coilId;
/**
* 当前钢卷号
*/
@NotBlank(message = "当前钢卷号不能为空", groups = { AddGroup.class, EditGroup.class })
private String currentCoilNo;
/**
* 操作类型1=分卷2=合卷3=更新)
*/
@NotNull(message = "操作类型不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer actionType;
/**
* 操作状态0=待处理1=处理中2=已完成3=已取消)
*/
private Integer actionStatus;
/**
* 扫码时间
*/
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX", timezone = "GMT+8")
private Date scanTime;
/**
* 扫码设备(移动端设备信息)
*/
private String scanDevice;
/**
* 优先级0=普通1=重要2=紧急)
*/
private Integer priority;
/**
* 来源类型scan=扫码manual=手动创建)
*/
private String sourceType;
/**
* 所在库区ID
*/
private Long warehouseId;
/**
* 操作人ID
*/
private Long operatorId;
/**
* 操作人姓名
*/
private String operatorName;
/**
* 处理时间
*/
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX", timezone = "GMT+8")
private Date processTime;
/**
* 完成时间
*/
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX", timezone = "GMT+8")
private Date completeTime;
}

View File

@@ -0,0 +1,148 @@
package com.klp.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.klp.common.annotation.ExcelDictFormat;
import com.klp.common.convert.ExcelDictConvert;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 钢卷待操作视图对象 wms_coil_pending_action
*
* @author Joshi
* @date 2025-11-03
*/
@Data
@ExcelIgnoreUnannotated
public class WmsCoilPendingActionVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long actionId;
/**
* 关联的钢卷ID
*/
@ExcelProperty(value = "钢卷ID")
private Long coilId;
/**
* 当前钢卷号
*/
@ExcelProperty(value = "钢卷号")
private String currentCoilNo;
/**
* 操作类型1=分卷2=合卷3=更新)
*/
@ExcelProperty(value = "操作类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wms_coil_action_type")
private Integer actionType;
/**
* 操作状态0=待处理1=处理中2=已完成3=已取消)
*/
@ExcelProperty(value = "操作状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wms_action_status")
private Integer actionStatus;
/**
* 扫码时间
*/
@ExcelProperty(value = "扫码时间")
private Date scanTime;
/**
* 扫码设备
*/
@ExcelProperty(value = "扫码设备")
private String scanDevice;
/**
* 优先级0=普通1=重要2=紧急)
*/
@ExcelProperty(value = "优先级", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wms_action_priority")
private Integer priority;
/**
* 来源类型
*/
@ExcelProperty(value = "来源类型")
private String sourceType;
/**
* 所在库区ID
*/
private Long warehouseId;
/**
* 库区名称
*/
@ExcelProperty(value = "库区")
private String warehouseName;
/**
* 操作人ID
*/
private Long operatorId;
/**
* 操作人姓名
*/
@ExcelProperty(value = "操作人")
private String operatorName;
/**
* 处理时间
*/
@ExcelProperty(value = "处理时间")
private Date processTime;
/**
* 完成时间
*/
@ExcelProperty(value = "完成时间")
private Date completeTime;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
private Date createTime;
// 钢卷相关信息(关联查询)
/**
* 钢种
*/
private String grade;
/**
* 厚度
*/
private Double thickness;
/**
* 宽度
*/
private Double width;
/**
* 重量
*/
private Double weight;
}

View File

@@ -0,0 +1,16 @@
package com.klp.mapper;
import com.klp.common.core.mapper.BaseMapperPlus;
import com.klp.domain.WmsCoilPendingAction;
import com.klp.domain.vo.WmsCoilPendingActionVo;
/**
* 钢卷待操作Mapper接口
*
* @author Joshi
* @date 2025-11-03
*/
public interface WmsCoilPendingActionMapper extends BaseMapperPlus<WmsCoilPendingActionMapper, WmsCoilPendingAction, WmsCoilPendingActionVo> {
}

View File

@@ -0,0 +1,69 @@
package com.klp.service;
import com.klp.domain.vo.WmsCoilPendingActionVo;
import com.klp.domain.bo.WmsCoilPendingActionBo;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.page.TableDataInfo;
import java.util.Collection;
import java.util.List;
/**
* 钢卷待操作Service接口
*
* @author Joshi
* @date 2025-11-03
*/
public interface IWmsCoilPendingActionService {
/**
* 查询钢卷待操作
*/
WmsCoilPendingActionVo queryById(Long actionId);
/**
* 查询钢卷待操作列表
*/
TableDataInfo<WmsCoilPendingActionVo> queryPageList(WmsCoilPendingActionBo bo, PageQuery pageQuery);
/**
* 查询钢卷待操作列表
*/
List<WmsCoilPendingActionVo> queryList(WmsCoilPendingActionBo bo);
/**
* 新增钢卷待操作
*/
Boolean insertByBo(WmsCoilPendingActionBo bo);
/**
* 修改钢卷待操作
*/
Boolean updateByBo(WmsCoilPendingActionBo bo);
/**
* 校验并批量删除钢卷待操作信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 更新操作状态
*/
Boolean updateStatus(Long actionId, Integer status);
/**
* 开始处理操作
*/
Boolean startProcess(Long actionId);
/**
* 完成操作
*/
Boolean completeAction(Long actionId);
/**
* 取消操作
*/
Boolean cancelAction(Long actionId);
}

View File

@@ -0,0 +1,180 @@
package com.klp.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.utils.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.klp.common.helper.LoginHelper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.klp.domain.bo.WmsCoilPendingActionBo;
import com.klp.domain.vo.WmsCoilPendingActionVo;
import com.klp.domain.WmsCoilPendingAction;
import com.klp.mapper.WmsCoilPendingActionMapper;
import com.klp.service.IWmsCoilPendingActionService;
import java.util.List;
import java.util.Collection;
import java.util.Date;
/**
* 钢卷待操作Service业务层处理
*
* @author Joshi
* @date 2025-11-03
*/
@RequiredArgsConstructor
@Service
public class WmsCoilPendingActionServiceImpl implements IWmsCoilPendingActionService {
private final WmsCoilPendingActionMapper baseMapper;
/**
* 查询钢卷待操作
*/
@Override
public WmsCoilPendingActionVo queryById(Long actionId){
return baseMapper.selectVoById(actionId);
}
/**
* 查询钢卷待操作列表
*/
@Override
public TableDataInfo<WmsCoilPendingActionVo> queryPageList(WmsCoilPendingActionBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<WmsCoilPendingAction> lqw = buildQueryWrapper(bo);
Page<WmsCoilPendingActionVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询钢卷待操作列表
*/
@Override
public List<WmsCoilPendingActionVo> queryList(WmsCoilPendingActionBo bo) {
LambdaQueryWrapper<WmsCoilPendingAction> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<WmsCoilPendingAction> buildQueryWrapper(WmsCoilPendingActionBo bo) {
LambdaQueryWrapper<WmsCoilPendingAction> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getCoilId() != null, WmsCoilPendingAction::getCoilId, bo.getCoilId());
lqw.like(StringUtils.isNotBlank(bo.getCurrentCoilNo()), WmsCoilPendingAction::getCurrentCoilNo, bo.getCurrentCoilNo());
lqw.eq(bo.getActionType() != null, WmsCoilPendingAction::getActionType, bo.getActionType());
lqw.eq(bo.getActionStatus() != null, WmsCoilPendingAction::getActionStatus, bo.getActionStatus());
lqw.eq(bo.getWarehouseId() != null, WmsCoilPendingAction::getWarehouseId, bo.getWarehouseId());
lqw.eq(bo.getPriority() != null, WmsCoilPendingAction::getPriority, bo.getPriority());
lqw.like(StringUtils.isNotBlank(bo.getSourceType()), WmsCoilPendingAction::getSourceType, bo.getSourceType());
lqw.orderByDesc(WmsCoilPendingAction::getPriority);
lqw.orderByDesc(WmsCoilPendingAction::getScanTime);
return lqw;
}
/**
* 新增钢卷待操作
*/
@Override
public Boolean insertByBo(WmsCoilPendingActionBo bo) {
WmsCoilPendingAction add = BeanUtil.toBean(bo, WmsCoilPendingAction.class);
validEntityBeforeSave(add);
// 设置默认值
if (add.getActionStatus() == null) {
add.setActionStatus(0); // 默认待处理
}
if (StringUtils.isBlank(add.getSourceType())) {
add.setSourceType("manual"); // 默认手动创建
}
if (add.getScanTime() == null && "scan".equals(add.getSourceType())) {
add.setScanTime(new Date());
}
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setActionId(add.getActionId());
}
return flag;
}
/**
* 修改钢卷待操作
*/
@Override
public Boolean updateByBo(WmsCoilPendingActionBo bo) {
WmsCoilPendingAction update = BeanUtil.toBean(bo, WmsCoilPendingAction.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(WmsCoilPendingAction entity){
// TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除钢卷待操作
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
// TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 更新操作状态
*/
@Override
public Boolean updateStatus(Long actionId, Integer status) {
WmsCoilPendingAction action = new WmsCoilPendingAction();
action.setActionId(actionId);
action.setActionStatus(status);
return baseMapper.updateById(action) > 0;
}
/**
* 开始处理操作
*/
@Override
public Boolean startProcess(Long actionId) {
WmsCoilPendingAction action = new WmsCoilPendingAction();
action.setActionId(actionId);
action.setActionStatus(1); // 处理中
action.setProcessTime(new Date());
try {
action.setOperatorId(LoginHelper.getUserId());
action.setOperatorName(LoginHelper.getUsername());
} catch (Exception e) {
// 如果获取登录用户失败,不影响主流程
}
return baseMapper.updateById(action) > 0;
}
/**
* 完成操作
*/
@Override
public Boolean completeAction(Long actionId) {
WmsCoilPendingAction action = new WmsCoilPendingAction();
action.setActionId(actionId);
action.setActionStatus(2); // 已完成
action.setCompleteTime(new Date());
return baseMapper.updateById(action) > 0;
}
/**
* 取消操作
*/
@Override
public Boolean cancelAction(Long actionId) {
WmsCoilPendingAction action = new WmsCoilPendingAction();
action.setActionId(actionId);
action.setActionStatus(3); // 已取消
return baseMapper.updateById(action) > 0;
}
}

View File

@@ -230,7 +230,8 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
contentMap.put("enter_coil_no", bo.getEnterCoilNo()); // 入场钢卷号(唯一不变)
contentMap.put("current_coil_no", currentCoilNo); // 当前钢卷号(可变)
contentMap.put("coil_id", "null"); // 钢卷ID新增时暂时为null插入后更新
contentMap.put("coil_id", "null"); // 初始钢卷ID新增时暂时为null插入后更新
contentMap.put("current_coil_id", "null"); // 当前有效的钢卷ID新增时暂时为null插入后更新
// 创建steps数组
List<Map<String, Object>> steps = new ArrayList<>();
@@ -399,15 +400,17 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
if (newCoil.getItemId() == null) {
newCoil.setItemId(oldCoil.getItemId());
}
// 确保warehouseId有值如果前端没传使用原值
if (newCoil.getWarehouseId() == null) {
newCoil.setWarehouseId(oldCoil.getWarehouseId());
}
validEntityBeforeSave(newCoil);
boolean flag = baseMapper.insert(newCoil) > 0;
if (flag) {
bo.setCoilId(newCoil.getCoilId());
// 如果生成了新二维码,更新二维码中的coilId
if (warehouseChanged) {
updateQrcodeCoilId(qrcodeRecordId, newCoil.getCoilId());
}
// 无论库区是否变化都需要更新二维码中的current_coil_id
updateQrcodeCoilId(qrcodeRecordId, newCoil.getCoilId());
}
return flag;
}
@@ -430,7 +433,8 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
contentMap.put("enter_coil_no", oldCoil.getEnterCoilNo()); // 入场钢卷号(始终不变)
contentMap.put("current_coil_no", currentCoilNo); // 当前钢卷号
contentMap.put("coil_id", "null"); // 钢卷ID更新时暂时为null插入后更新
contentMap.put("coil_id", String.valueOf(oldCoil.getCoilId())); // 初始钢卷ID记录最初的ID
contentMap.put("current_coil_id", "null"); // 当前钢卷ID更新时暂时为null插入后更新
// 复制原钢卷的历史steps
List<Map<String, Object>> steps = new ArrayList<>();
@@ -630,7 +634,8 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
Map<String, Object> contentMap = new HashMap<>();
contentMap.put("enter_coil_no", oldCoil.getEnterCoilNo());
contentMap.put("current_coil_no", newCoilBo.getCurrentCoilNo());
contentMap.put("coil_id", "null"); // 钢卷ID分卷时暂时为null插入后更新
contentMap.put("coil_id", String.valueOf(oldCoil.getCoilId())); // 初始钢卷ID记录原钢卷的ID
contentMap.put("current_coil_id", "null"); // 当前钢卷ID分卷时暂时为null插入后更新
// 复制原钢卷的历史steps
List<Map<String, Object>> steps = new ArrayList<>();
@@ -700,7 +705,8 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
}
contentMap.put("enter_coil_no", enterCoilNo);
contentMap.put("current_coil_no", mergedCoilBo.getCurrentCoilNo());
contentMap.put("coil_id", "null"); // 钢卷ID合卷时暂时为null,插入后更新
contentMap.put("coil_id", "null"); // 初始钢卷ID合卷时为null
contentMap.put("current_coil_id", "null"); // 当前钢卷ID合卷时暂时为null插入后更新
// 合并所有参与合卷的原始钢卷的历史steps
List<Map<String, Object>> steps = new ArrayList<>();
@@ -790,8 +796,13 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> contentMap = objectMapper.readValue(record.getContent(), Map.class);
// 更新coilId
contentMap.put("coil_id", String.valueOf(coilId));
// 如果是第一次设置coilId从"null"变为实际ID则同时设置coil_id和current_coil_id
if ("null".equals(contentMap.get("coil_id"))) {
contentMap.put("coil_id", String.valueOf(coilId)); // 初始ID不再改变
}
// 始终更新current_coil_id为最新的钢卷ID
contentMap.put("current_coil_id", String.valueOf(coilId));
// 更新二维码记录
String newContentJson = objectMapper.writeValueAsString(contentMap);
@@ -854,6 +865,10 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
// 更新当前钢卷号到最外层(方便快速查看)
contentMap.put("current_coil_no", bo.getCurrentCoilNo());
// 更新当前钢卷ID注意这里需要获取新插入的钢卷ID但在这个方法中还没有新ID
// 所以这个方法只在库区不变化时调用此时钢卷ID不变
// contentMap.put("current_coil_id", String.valueOf(bo.getCoilId())); // 保持当前ID不变
// 更新二维码记录
String newContentJson = objectMapper.writeValueAsString(contentMap);
WmsGenerateRecordBo updateBo = new WmsGenerateRecordBo();

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.klp.mapper.WmsCoilPendingActionMapper">
<resultMap type="com.klp.domain.WmsCoilPendingAction" id="WmsCoilPendingActionResult">
<result property="actionId" column="action_id" />
<result property="coilId" column="coil_id" />
<result property="currentCoilNo" column="current_coil_no" />
<result property="actionType" column="action_type" />
<result property="actionStatus" column="action_status" />
<result property="scanTime" column="scan_time" />
<result property="scanDevice" column="scan_device" />
<result property="priority" column="priority" />
<result property="sourceType" column="source_type" />
<result property="warehouseId" column="warehouse_id" />
<result property="operatorId" column="operator_id" />
<result property="operatorName" column="operator_name" />
<result property="processTime" column="process_time" />
<result property="completeTime" column="complete_time" />
<result property="remark" column="remark" />
<result property="delFlag" column="del_flag" />
<result property="createTime" column="create_time" />
<result property="createBy" column="create_by" />
<result property="updateTime" column="update_time" />
<result property="updateBy" column="update_by" />
</resultMap>
</mapper>