Merge remote-tracking branch 'origin/0.8.X' into 0.8.X

This commit is contained in:
2025-11-03 17:06:30 +08:00
21 changed files with 5026 additions and 16 deletions

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询实际库区/库位自关联列表
export function listActualWarehouse(query) {
return request({
url: '/wms/actualWarehouse/list',
method: 'get',
params: query
})
}
// 查询实际库区/库位自关联详细
export function getActualWarehouse(actualWarehouseId) {
return request({
url: '/wms/actualWarehouse/' + actualWarehouseId,
method: 'get'
})
}
// 新增实际库区/库位自关联
export function addActualWarehouse(data) {
return request({
url: '/wms/actualWarehouse',
method: 'post',
data: data
})
}
// 修改实际库区/库位自关联
export function updateActualWarehouse(data) {
return request({
url: '/wms/actualWarehouse',
method: 'put',
data: data
})
}
// 删除实际库区/库位自关联
export function delActualWarehouse(actualWarehouseId) {
return request({
url: '/wms/actualWarehouse/' + actualWarehouseId,
method: 'delete'
})
}

View File

@@ -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,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>

View File

@@ -0,0 +1,120 @@
<template>
<el-select
v-model="selected"
:placeholder="placeholder"
:clearable="clearable"
:disabled="disabled"
:size="size"
filterable
@change="onChange"
style="width: 100%"
>
<el-option
v-for="item in warehouseOptions"
:key="item.actualWarehouseId"
:label="item.actualWarehouseName"
:value="item.actualWarehouseId"
>
<span :style="{ paddingLeft: item.level * 20 + 'px' }">
{{ item.actualWarehouseName }}
</span>
</el-option>
</el-select>
</template>
<script>
import { listActualWarehouse } from '@/api/wms/actualWarehouse';
export default {
name: 'ActualWarehouseSelect',
props: {
value: {
type: [Number, String, null],
default: null
},
placeholder: {
type: String,
default: '请选择实际库区/库位'
},
clearable: {
type: Boolean,
default: true
},
disabled: {
type: Boolean,
default: false
},
size: {
type: String,
default: 'mini'
},
showTop: {
type: Boolean,
default: false // 是否显示顶级节点
}
},
data() {
return {
warehouseOptions: [],
selected: this.value
};
},
watch: {
value(val) {
this.selected = val;
}
},
mounted() {
this.loadOptions();
},
methods: {
loadOptions() {
listActualWarehouse({ pageSize: 1000 }).then(response => {
console.log('实际库区/库位自关联API返回数据:', response);
const data = response.rows || [];
console.log('处理后的数据:', data);
// this.warehouseOptions = this.buildTreeOptions(data);
this.warehouseOptions = data;
console.log('构建的树形选项:', this.warehouseOptions);
}).catch(error => {
console.error("加载仓库选项失败:", error);
this.warehouseOptions = [];
});
},
buildTreeOptions(data, parentId = null, level = 0) {
const options = [];
data.forEach(item => {
if (item.parentId === parentId) {
const option = {
warehouseId: item.warehouseId,
warehouseName: item.warehouseName,
level: level
};
// 递归构建子节点
const children = this.buildTreeOptions(data, item.warehouseId, level + 1);
if (children.length > 0) {
options.push(option);
options.push(...children);
} else {
options.push(option);
}
}
});
return options;
},
onChange(val) {
this.$emit('input', val);
this.$emit('change', val);
}
}
};
</script>
<style scoped>
.el-select {
width: 100%;
}
</style>

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>

File diff suppressed because it is too large Load Diff

View File

@@ -147,7 +147,7 @@ export default {
};
// 调用API获取数据
listMaterialCoil(params).then(res => {
listMaterialCoil({ ...params, dataType: 1 }).then(res => {
this.list = res.rows || [];
this.total = res.total || 0;
this.loading = false;

View File

@@ -18,6 +18,9 @@
<el-form-item label="所在库位" prop="warehouseId" v-if="!hideWarehouseQuery">
<warehouse-select v-model="queryParams.warehouseId" placeholder="请选择仓库/库区/库位" style="width: 100%; display: inline-block;" clearable />
</el-form-item>
<el-form-item label="实际库区" prop="actualWarehouseId" v-if="!hideWarehouseQuery">
<actual-warehouse-select v-model="queryParams.actualWarehouseId" placeholder="请选择实际库位" style="width: 100%; display: inline-block;" clearable />
</el-form-item>
<el-form-item label="厂家卷号" prop="supplierCoilNo">
<el-input v-model="queryParams.supplierCoilNo" placeholder="请输入厂家原料卷号" clearable
@keyup.enter.native="handleQuery" />
@@ -68,7 +71,8 @@
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo" />
<el-table-column label="当前钢卷号" align="center" prop="currentCoilNo" />
<el-table-column label="厂家卷号" align="center" prop="supplierCoilNo" />
<el-table-column label="仓库" align="center" prop="warehouseName" v-if="!hideWarehouseQuery"/>
<el-table-column label="逻辑库位" align="center" prop="warehouseName" v-if="!hideWarehouseQuery"/>
<el-table-column label="实际库区" align="center" prop="actualWarehouseName" v-if="!hideWarehouseQuery"/>
<el-table-column label="物料类型" align="center" prop="itemType">
<template slot-scope="scope">
{{ scope.row.itemType == 'product' ? '成品' : '原料' }}
@@ -94,6 +98,8 @@
</template>
</el-table-column> -->
<el-table-column label="更新时间" align="center" prop="updateTime" />
<el-table-column label="更新人" align="center" prop="updateBy" />
<el-table-column label="二维码" v-if="qrcode">
<template slot-scope="scope">
<QRCode :content="scope.row.qrcodeRecordId" :size="50" />
@@ -140,6 +146,9 @@
<el-form-item label="所在库位" prop="warehouseId">
<warehouse-select v-model="form.warehouseId" placeholder="请选择仓库/库区/库位" style="width: 100%;" clearable />
</el-form-item>
<el-form-item label="实际库区" prop="actualWarehouseId">
<actual-warehouse-select v-model="form.actualWarehouseId" placeholder="请选择实际库区" style="width: 100%;" clearable />
</el-form-item>
<el-form-item label="班组" prop="team">
<el-input v-model="form.team" placeholder="请输入班组" />
</el-form-item>
@@ -200,6 +209,7 @@ import RawMaterialInfo from "@/components/KLPService/Renderer/RawMaterialInfo";
import CoilTraceResult from "./CoilTraceResult.vue"; // 路径根据实际存放位置调整
import LabelRender from './LabelRender/index.vue'
import MaterialSelect from "@/components/KLPService/MaterialSelect";
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
import { findItemWithBom } from "@/store/modules/category";
export default {
@@ -214,7 +224,8 @@ export default {
RawMaterialInfo,
BomInfoMini,
CoilTraceResult,
LabelRender
LabelRender,
ActualWarehouseSelect
},
dicts: ['product_coil_status'],
props: {
@@ -278,6 +289,7 @@ export default {
supplierCoilNo: undefined,
warehouseId: undefined,
nextWarehouseId: undefined,
actualWarehouseId: undefined,
qrcodeRecordId: undefined,
team: undefined,
hasMergeSplit: undefined,
@@ -409,6 +421,7 @@ export default {
warehouseId: undefined,
nextWarehouseId: undefined,
qrcodeRecordId: undefined,
actualWarehouseId: undefined,
team: undefined,
hasMergeSplit: undefined,
parentCoilNos: undefined,
@@ -532,8 +545,9 @@ export default {
'入场钢卷号': item.enterCoilNo || '',
'当前钢卷号': item.currentCoilNo || '',
'厂家原料卷号': item.supplierCoilNo || '',
'库区': item.itemType === 'product' ? '成品' : '原料',
'仓': item.warehouseName || '',
'物料类型': item.itemType === 'product' ? '成品' : '原料',
'仓': item.warehouseName || '',
'实际库区': item.actualWarehouseName || '',
'物品': findItemWithBom(item.itemType, item.itemId)?.itemName || '',
'数据类型': item.dataType === 0 ? '历史数据' : '当前数据',
'班组': item.team || '',

View File

@@ -0,0 +1,942 @@
<template>
<div class="split-coil-container">
<!-- 顶部操作栏 -->
<div class="header-bar">
<div class="header-title">
<i class="el-icon-s-operation"></i>
<span>钢卷分卷</span>
</div>
<div class="header-actions">
<el-button v-if="!readonly" type="primary" size="small" @click="handleSave" :loading="loading">保存分卷</el-button>
<el-button size="small" @click="handleCancel" :disabled="loading">{{ readonly ? '返回' : '取消' }}</el-button>
</div>
</div>
<!-- 流程图区域 -->
<div class="flow-container">
<!-- 左侧母卷信息 -->
<div class="flow-left">
<div class="flow-section-title">
<span>母卷信息</span>
</div>
<div class="coil-card mother-coil">
<div class="coil-header">
<i class="el-icon-s-grid"></i>
<span class="coil-title">钢卷信息</span>
</div>
<div class="coil-body">
<div class="coil-info-row">
<span class="label">入场钢卷号</span>
<span class="value">{{ motherCoil.enterCoilNo || '—' }}</span>
</div>
<div class="coil-info-row">
<span class="label">当前钢卷号</span>
<span class="value">{{ motherCoil.currentCoilNo || '—' }}</span>
</div>
<div class="coil-info-row">
<span class="label">当前库区</span>
<span class="value">{{ motherCoil.warehouseName || '未分配' }}</span>
</div>
<div class="coil-info-row">
<span class="label">班组</span>
<span class="value">{{ motherCoil.team || '—' }}</span>
</div>
<div class="coil-info-row" v-if="motherCoil.materialName || motherCoil.productName">
<span class="label">物料名称</span>
<span class="value">{{ motherCoil.materialName || motherCoil.productName || '—' }}</span>
</div>
<div class="coil-info-row">
<span class="label">毛重</span>
<span class="value">{{ motherCoil.grossWeight ? motherCoil.grossWeight + ' t' : '—' }}</span>
</div>
<div class="coil-info-row">
<span class="label">净重</span>
<span class="value">{{ motherCoil.netWeight ? motherCoil.netWeight + ' t' : '—' }}</span>
</div>
<!-- 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>
<!-- 中间流程箭头 -->
<div class="flow-middle">
<div class="flow-arrow-container">
<div class="arrow-line" v-for="(item, index) in splitList" :key="index">
<div class="arrow-start"></div>
<div class="arrow-body"></div>
<div class="arrow-end"></div>
</div>
</div>
<div class="flow-label">
<i class="el-icon-d-arrow-right"></i>
<span>分割</span>
</div>
</div>
<!-- 右侧子卷列表 -->
<div class="flow-right">
<div class="flow-section-title">
<span>子卷列表</span>
<div>
<el-button v-if="!readonly" type="text" size="mini" @click="copyToAllSubCoils" icon="el-icon-document-copy">复制到全部</el-button>
<el-button v-if="!readonly" type="text" size="mini" @click="addSplitItem" icon="el-icon-plus">添加子卷</el-button>
</div>
</div>
<div class="split-list">
<div class="sub-coil-card" v-for="(item, index) in splitList" :key="index">
<div class="sub-coil-header">
<span class="sub-coil-number">{{ index + 1 }}</span>
<el-button
v-if="!readonly"
type="text"
size="mini"
icon="el-icon-delete"
@click="removeSplitItem(index)"
class="btn-remove"
></el-button>
</div>
<div class="sub-coil-body">
<el-form size="small" label-width="90px">
<el-form-item label="卷号" required>
<el-input v-model="item.currentCoilNo" placeholder="输入子卷卷号" :disabled="readonly"></el-input>
</el-form-item>
<el-form-item label="班组" required>
<el-input v-model="item.team" placeholder="输入班组名称" :disabled="readonly"></el-input>
</el-form-item>
<el-form-item label="物品类型" required>
<el-select
v-model="item.itemType"
placeholder="请选择"
style="width: 100%"
@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>
</div>
</div>
<!-- 汇总信息 -->
<div class="summary-card">
<div class="summary-item">
<span class="summary-label">子卷数量:</span>
<span class="summary-value">{{ splitList.length }}</span>
</div>
</div>
</div>
</div>
<!-- 钢卷选择器 -->
<coil-selector
:visible.sync="coilSelectorVisible"
@select="handleCoilSelect"
/>
</div>
</template>
<script>
import { getMaterialCoil, splitMaterialCoil } from '@/api/wms/coil';
import { listWarehouse } from '@/api/wms/warehouse';
import { listRawMaterial } from '@/api/wms/rawMaterial';
import { listProduct } from '@/api/wms/product';
import CoilSelector from '@/components/CoilSelector';
export default {
name: 'SplitCoil',
components: {
CoilSelector
},
data() {
return {
// 母卷信息
motherCoil: {
coilId: null,
enterCoilNo: '',
currentCoilNo: '',
team: '',
warehouseId: null,
warehouseName: '',
itemType: null,
itemId: null,
materialName: '',
productName: '',
grossWeight: null,
netWeight: null,
bomItems: []
},
// 子卷列表
splitList: [
{
currentCoilNo: '',
team: '',
itemType: null,
itemId: null,
grossWeight: null,
netWeight: null,
nextWarehouseId: null
}
],
loading: false,
// 钢卷选择器可见性
coilSelectorVisible: false,
// 库区列表
warehouseList: [],
// 原材料和产品列表
rawMaterialList: [],
productList: [],
itemSearchLoading: false,
// 只读模式
readonly: false
};
},
computed: {
},
async created() {
// 先加载库区列表
await this.loadWarehouses();
// 从路由参数获取coilId和readonly
const coilId = this.$route.query.coilId;
const readonly = this.$route.query.readonly;
if (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;
},
// 钢卷选择回调
handleCoilSelect(coil) {
this.motherCoil = {
coilId: coil.coilId,
enterCoilNo: coil.enterCoilNo || '',
currentCoilNo: coil.currentCoilNo || '',
team: coil.team || '',
warehouseId: coil.warehouseId,
warehouseName: coil.warehouseName || '',
itemType: coil.itemType,
itemId: coil.itemId,
materialName: coil.materialName || '',
productName: coil.productName || '',
grossWeight: coil.grossWeight,
netWeight: coil.netWeight,
bomItems: coil.bomItemList || coil.bomItems || []
};
this.$message.success('母卷选择成功');
},
// 加载母卷信息
async loadMotherCoil(coilId) {
try {
this.loading = true;
const response = await getMaterialCoil(coilId);
if (response.code === 200 && response.data) {
const data = response.data;
this.motherCoil = {
coilId: data.coilId,
enterCoilNo: data.enterCoilNo || '',
currentCoilNo: data.currentCoilNo || '',
team: data.team || '',
warehouseId: data.warehouseId,
warehouseName: data.warehouseName || (data.warehouse ? data.warehouse.warehouseName : ''),
itemType: data.itemType,
itemId: data.itemId,
materialName: data.materialName || (data.rawMaterial ? data.rawMaterial.rawMaterialName : ''),
productName: data.productName || (data.product ? data.product.productName : ''),
grossWeight: data.grossWeight,
netWeight: data.netWeight,
bomItems: data.bomItemList || data.bomItems || []
};
}
} catch (error) {
this.$message.error('加载母卷信息失败');
console.error(error);
} finally {
this.loading = false;
}
},
// 加载库区列表
async loadWarehouses() {
try {
const response = await listWarehouse({ pageNum: 1, pageSize: 1000 });
if (response.code === 200) {
this.warehouseList = response.rows || response.data || [];
console.log('库区列表加载成功,数量:', this.warehouseList.length);
}
} catch (error) {
console.error('加载库区列表失败', error);
}
},
// 添加子卷
addSplitItem() {
this.splitList.push({
currentCoilNo: '',
team: '',
itemType: null,
itemId: null,
grossWeight: null,
netWeight: null,
nextWarehouseId: null
});
},
// 删除子卷
removeSplitItem(index) {
if (this.splitList.length > 1) {
this.splitList.splice(index, 1);
} else {
this.$message.warning('至少保留一个子卷');
}
},
// 保存分卷
async handleSave() {
// 验证母卷信息
if (!this.motherCoil.coilId) {
this.$message.error('请先选择母卷');
return;
}
// 验证子卷数量
if (this.splitList.length < 1) {
this.$message.error('至少需要一个子卷');
return;
}
// 验证子卷信息
for (let i = 0; i < this.splitList.length; i++) {
const item = this.splitList[i];
if (!item.currentCoilNo || item.currentCoilNo.trim() === '') {
this.$message.error(`第${i + 1}个子卷的卷号不能为空`);
return;
}
if (!item.team || item.team.trim() === '') {
this.$message.error(`第${i + 1}个子卷的班组不能为空`);
return;
}
if (!item.itemType) {
this.$message.error(`第${i + 1}个子卷的物品类型不能为空`);
return;
}
if (!item.itemId) {
this.$message.error(`第${i + 1}个子卷的物品不能为空`);
return;
}
if (item.grossWeight === null || item.grossWeight === undefined || item.grossWeight === '') {
this.$message.error(`第${i + 1}个子卷的毛重不能为空`);
return;
}
if (item.netWeight === null || item.netWeight === undefined || item.netWeight === '') {
this.$message.error(`第${i + 1}个子卷的净重不能为空`);
return;
}
if (!item.nextWarehouseId) {
this.$message.error(`第${i + 1}个子卷的目标库区不能为空`);
return;
}
}
try {
this.loading = true;
// 构造分卷数据
const splitData = {
coilId: this.motherCoil.coilId,
enterCoilNo: this.motherCoil.enterCoilNo, // 入场钢卷号(必填)
currentCoilNo: this.motherCoil.currentCoilNo,
hasMergeSplit: 1, // 1表示分卷
newCoils: this.splitList.map(item => ({
enterCoilNo: this.motherCoil.enterCoilNo, // 子卷继承母卷的入场钢卷号
currentCoilNo: item.currentCoilNo,
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('分卷保存成功');
// 延迟返回,让用户看到成功提示
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();
},
// 复制到全部子卷
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('已复制到所有子卷');
}
}
};
</script>
<style scoped lang="scss">
.split-coil-container {
padding: 20px;
background: #f5f7fa;
min-height: calc(100vh - 84px);
}
/* 顶部操作栏 */
.header-bar {
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
padding: 16px 20px;
margin-bottom: 20px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.header-title {
font-size: 18px;
font-weight: 500;
color: #303133;
display: flex;
align-items: center;
gap: 8px;
i {
color: #0066cc;
font-size: 20px;
}
}
/* 流程图容器 */
.flow-container {
display: flex;
gap: 40px;
background: #fff;
padding: 30px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
min-height: 600px;
}
.flow-left {
flex: 0 0 300px;
}
.flow-middle {
flex: 0 0 120px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
}
.flow-right {
flex: 1;
min-width: 0;
}
.flow-section-title {
font-size: 16px;
font-weight: 500;
color: #303133;
margin-bottom: 16px;
padding-left: 12px;
border-left: 4px solid #0066cc;
display: flex;
justify-content: space-between;
align-items: center;
.el-button--text {
font-size: 12px;
}
}
/* 母卷卡片 */
.mother-coil {
border: 2px solid #0066cc;
box-shadow: 0 4px 12px rgba(0, 102, 204, 0.15);
}
.coil-card {
background: #fff;
border: 1px solid #e4e7ed;
border-radius: 8px;
overflow: hidden;
}
.coil-header {
background: #0066cc;
color: #fff;
padding: 16px 20px;
display: flex;
align-items: center;
gap: 10px;
i {
font-size: 20px;
}
.coil-title {
flex: 1;
font-size: 16px;
font-weight: 600;
}
}
.coil-body {
padding: 20px;
}
.coil-info-row {
display: flex;
align-items: flex-start;
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
.label {
color: #909399;
font-size: 14px;
min-width: 100px;
flex-shrink: 0;
}
.value {
color: #303133;
font-size: 14px;
font-weight: 500;
flex: 1;
word-break: break-all;
&.highlight {
color: #0066cc;
font-size: 16px;
font-weight: 600;
}
}
}
/* BOM参数展示 */
.bom-params {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
margin-top: 10px;
}
.param-item {
display: flex;
align-items: center;
font-size: 13px;
.param-name {
color: #909399;
min-width: 80px;
}
.param-value {
color: #303133;
font-weight: 500;
}
}
/* 流程箭头 */
.flow-arrow-container {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 100%;
}
.arrow-line {
position: relative;
height: 3px;
margin: 20px 0;
display: flex;
align-items: center;
}
.arrow-start {
width: 8px;
height: 8px;
background: #0066cc;
border-radius: 50%;
}
.arrow-body {
flex: 1;
height: 3px;
background: #0066cc;
}
.arrow-end {
width: 0;
height: 0;
border-left: 12px solid #0066cc;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
}
.flow-label {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: #ecf5ff;
color: #0066cc;
padding: 8px 16px;
border-radius: 20px;
font-size: 14px;
font-weight: 500;
display: flex;
align-items: center;
gap: 6px;
border: 1px solid #d9ecff;
}
/* 子卷列表 */
.split-list {
max-height: 500px;
overflow-y: auto;
margin-bottom: 20px;
padding-right: 10px;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #dcdfe6;
border-radius: 3px;
}
}
.sub-coil-card {
background: #fff;
border: 1px solid #e4e7ed;
border-radius: 8px;
margin-bottom: 16px;
transition: all 0.3s;
&:hover {
border-color: #0066cc;
box-shadow: 0 2px 8px rgba(0, 102, 204, 0.15);
}
}
.sub-coil-header {
background: #f5f7fa;
padding: 12px 16px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e4e7ed;
}
.sub-coil-number {
font-size: 16px;
font-weight: 600;
color: #0066cc;
width: 32px;
height: 32px;
border-radius: 50%;
background: #ecf5ff;
display: flex;
align-items: center;
justify-content: center;
}
.btn-remove {
color: #f56c6c;
padding: 0;
&:hover {
color: #f56c6c;
}
}
.sub-coil-body {
padding: 16px;
}
/* 汇总卡片 */
.summary-card {
background: #ecf5ff;
border: 1px solid #d9ecff;
border-radius: 8px;
padding: 16px 20px;
display: flex;
justify-content: space-around;
}
.summary-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.summary-label {
font-size: 13px;
color: #606266;
}
.summary-value {
font-size: 20px;
font-weight: 600;
color: #0066cc;
&.error {
color: #f56c6c;
}
}
// 优化按钮文字颜色
// 实心primary按钮白色文字
::v-deep .el-button--primary.el-button--small:not(.is-plain) {
color: #fff;
}
// plain按钮和text按钮蓝色文字
::v-deep .el-button--primary.el-button--small.is-plain,
::v-deep .el-button--text {
color: #409eff;
&:hover {
color: #66b1ff;
}
}
// 修复数字输入框的上下箭头溢出
.sub-coil-body {
::v-deep input[type="number"] {
appearance: textfield;
-moz-appearance: textfield;
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
-webkit-appearance: none;
appearance: none;
margin: 0;
}
}
}
</style>

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,370 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="60px">
<el-form-item label="库位编码" prop="actualWarehouseCode">
<el-input
v-model="queryParams.actualWarehouseCode"
placeholder="请输入库位编码"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="库位名称" prop="actualWarehouseName">
<el-input
v-model="queryParams.actualWarehouseName"
placeholder="请输入库位名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<!-- <el-form-item label="库位类型" prop="warehouseType">
<el-select v-model="queryParams.warehouseType" placeholder="请选择库位类型" clearable>
<el-option
v-for="dict in dict.type.warehouse_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item> -->
<el-form-item label="启用状态" prop="isEnabled">
<el-select v-model="queryParams.isEnabled" placeholder="请选择启用状态" clearable>
<el-option label="启用" :value="1" />
<el-option label="禁用" :value="0" />
</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="info"
plain
icon="el-icon-sort"
size="mini"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<KLPTable
v-if="refreshTable"
v-loading="loading"
:data="warehouseList"
row-key="warehouseId"
:default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
>
<!-- <el-table-column label="上级节点" prop="parentId" /> -->
<el-table-column label="库位编码" align="center" prop="actualWarehouseCode" />
<el-table-column label="库位名称" align="center" prop="actualWarehouseName" />
<!-- <el-table-column label="库位类型" align="center" prop="warehouseType">
<template slot-scope="scope">
<dict-tag :options="dict.type.warehouse_type" :value="scope.row.warehouseType"/>
</template>
</el-table-column> -->
<el-table-column label="排序号" align="center" prop="sortNo" />
<el-table-column label="启用状态" align="center" prop="isEnabled">
<template slot-scope="scope">
<span>{{ scope.row.isEnabled == 1 ? '启用' : '禁用' }}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>修改</el-button>
<!-- <el-button
size="mini"
type="text"
icon="el-icon-plus"
@click="handleAdd(scope.row)"
>新增</el-button> -->
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</el-button>
</template>
</el-table-column>
</KLPTable>
<!-- 添加或修改库位/库区/库位自关联对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<!-- <el-form-item label="上级节点" prop="parentId">
<WarehouseSelect v-model="form.parentId" placeholder="请选择上级节点" />
</el-form-item> -->
<el-form-item label="库位编码" prop="actualWarehouseCode">
<el-input v-model="form.actualWarehouseCode" placeholder="请输入库位编码" />
</el-form-item>
<el-form-item label="库位名称" prop="actualWarehouseName">
<el-input v-model="form.actualWarehouseName" placeholder="请输入库位名称" />
</el-form-item>
<!-- <el-form-item label="库位类型" prop="warehouseType">
<el-select v-model="form.warehouseType" placeholder="请选择库位类型">
<el-option
v-for="dict in dict.type.warehouse_type"
:key="dict.value"
:label="dict.label"
:value="parseInt(dict.value)"
></el-option>
</el-select>
</el-form-item> -->
<el-form-item label="排序号" prop="sortNo">
<el-input v-model="form.sortNo" placeholder="请输入排序号" />
</el-form-item>
<el-form-item label="启用状态" prop="isEnabled">
<el-select v-model="form.isEnabled" placeholder="请选择启用状态">
<el-option label="启用" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listActualWarehouse, getActualWarehouse, delActualWarehouse, addActualWarehouse, updateActualWarehouse } from "@/api/wms/actualWarehouse";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
// import ActualWarehouseSelect from '@/components/ActualWarehouseSelect';
export default {
name: "ActualWarehouse",
// dicts: ['warehouse_type'],
components: {
Treeselect,
// ActualWarehouseSelect
},
data() {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 显示搜索条件
showSearch: true,
// 库位/库区/库位自关联表格数据
warehouseList: [],
// 库位/库区/库位自关联树选项
warehouseOptions: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 是否展开,默认全部展开
isExpandAll: true,
// 重新渲染表格状态
refreshTable: true,
// 查询参数
queryParams: {
parentId: undefined,
actualWarehouseCode: undefined,
actualWarehouseName: undefined,
warehouseType: undefined,
sortNo: undefined,
isEnabled: undefined,
},
// 表单参数
form: {},
// 表单校验
rules: {
actualWarehouseCode: [
{ required: true, message: "库区编码不能为空", trigger: "blur" }
],
actualWarehouseName: [
{ required: true, message: "库区名称不能为空", trigger: "blur" }
],
// warehouseType: [
// { required: true, message: "类型不能为空", trigger: "change" }
// ],
}
};
},
created() {
this.getList();
},
methods: {
/** 查询库位/库区/库位自关联列表 */
getList() {
this.loading = true;
listActualWarehouse({...this.queryParams, pageNum: 1, pageSize: 1000}).then(response => {
const list = response.rows;
// const list = this.handleTree(response.data, "warehouseId", "parentId");
// // 递归遍历list通过sortNo排序
const sort = (list) => {
list.sort((a, b) => a.sortNo - b.sortNo);
list.forEach(item => {
if (item.children) {
sort(item.children);
}
});
};
sort(list)
this.warehouseList = list;
this.loading = false;
});
},
/** 转换库位/库区/库位自关联数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.warehouseId,
label: node.warehouseName,
children: node.children
};
},
/** 查询库位/库区/库位自关联下拉树结构 */
getTreeselect() {
listActualWarehouse().then(response => {
this.warehouseOptions = [];
const data = { warehouseId: 0, warehouseName: '顶级节点', children: [] };
data.children = this.handleTree(response.data, "warehouseId", "parentId");
this.warehouseOptions.push(data);
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
warehouseId: null,
parentId: null,
actualWarehouseCode: null,
actualWarehouseName: null,
warehouseType: 1,
sortNo: null,
isEnabled: 1,
delFlag: null,
remark: null,
createTime: null,
createBy: null,
updateTime: null,
updateBy: null
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd(row) {
this.reset();
this.getTreeselect();
if (row != null && row.warehouseId) {
this.form.parentId = row.warehouseId;
} else {
this.form.parentId = 0;
}
this.open = true;
this.title = "添加库位/库区/库位自关联";
},
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
this.$nextTick(() => {
this.refreshTable = true;
});
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
this.getTreeselect();
if (row != null) {
this.form.parentId = row.warehouseId;
}
getActualWarehouse(row.warehouseId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改库位/库区/库位自关联";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
// 处理 parentId 为 0 的情况
let submitData = { ...this.form };
if (submitData.parentId === 0) {
delete submitData.parentId;
}
if (this.form.actualWarehouseId != null) {
updateActualWarehouse(submitData).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addActualWarehouse(submitData).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
this.$modal.confirm('是否确认删除库位/库区/库位自关联编号为"' + row.actualWarehouseId + '"的数据项?').then(() => {
this.loading = true;
return delActualWarehouse(row.actualWarehouseId);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
}
}
};
</script>

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>