Compare commits

...

26 Commits

Author SHA1 Message Date
da1813e65a Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-17 09:54:43 +08:00
8dbb7d1113 feat(钢卷管理): 添加钢卷统计功能并优化仓库选择排序
新增钢卷统计接口和展示总净重功能
优化仓库选择组件,按使用频率排序选项
调整钢卷选择器布局和样式
2026-04-17 09:55:27 +08:00
ae77c529ae feat(wms): 添加物料卷统计总数功能
- 在WmsMaterialCoilServiceImpl中新增total_count字段统计
- 将统计结果添加到返回结果集中
- 处理空值情况并设置默认值为BigDecimal.ZERO
2026-04-17 09:54:34 +08:00
edcbf7a5f1 feat(退火操作): 新增退火操作事件记录功能
添加退火操作事件API及页面,实现退火炉操作记录功能
在计划管理页面增加操作事件记录,包括入炉、完成、添加和解绑操作
2026-04-16 17:12:08 +08:00
28622a2b16 refactor(wms): 优化钢卷计划和材料钢卷服务逻辑
- 在更新钢卷计划时设置创建时间和更新时间
- 添加登录用户信息到钢卷计划的创建者和更新者字段
- 初始化钢卷计划的状态和导出相关字段
- 移除占用仓库的冗余方法实现
- 在材料钢卷服务中同时更新数据类型和排他状态字段
2026-04-16 16:46:09 +08:00
44303cb1c7 fix(wms): 修复钢卷单个更新时的二维码步骤类型检查逻辑
- 修改了qrcodeStepType为空判断条件,从非空且不等于annealing改为直接判断是否为空
- 确保在qrcodeStepType为空时能够正确执行钢卷操作权限验证
- 修正了原有的逻辑错误,避免在特定条件下跳过必要的权限检查
2026-04-16 16:31:47 +08:00
c0f7c699a8 fix(wms): 修复钢卷更新时二维码步骤类型检查逻辑
- 在非退火步骤类型时才进行独占状态检查
- 添加对qrcodeStepType为空的边界情况处理
- 修复二维码内容更新中的空指针检查逻辑
2026-04-16 16:30:05 +08:00
e69dc5e76e fix(task): 关闭仓库使用次数定时任务
- 注释掉 cron 表达式以禁用定时执行
- 保留事务回滚配置以确保数据一致性
- 记录任务开始执行的日志信息功能仍然可用
2026-04-16 16:18:40 +08:00
ec0660acba refactor(vo): 让WmsAnnealOperateEventVo继承BaseEntity
- 添加com.klp.common.core.domain.BaseEntity导入
- 修改WmsAnnealOperateEventVo类继承BaseEntity
- 保持原有的Excel注解配置不变
2026-04-16 16:01:39 +08:00
110597657e Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-16 15:56:39 +08:00
50670b64d8 feat(material-coil): 添加退火操作的二维码步骤类型支持
- 修改IWmsMaterialCoilService接口中的updateByBo方法,增加qrcodeStepType参数
- 在WmsFurnacePlanServiceImpl中实现退火操作的库位分配功能
- 添加updateQrcodeContentForCustomStep方法支持自定义二维码步骤类型
- 更新controller调用传入null作为默认值
- 完善退火操作的二维码内容更新逻辑
2026-04-16 15:56:26 +08:00
砂糖
823afd7a00 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-04-16 15:50:58 +08:00
砂糖
344488f08e 临时修改 2026-04-16 15:50:54 +08:00
c2da7640c3 feat(wms): 添加退火操作事件管理功能
- 创建退火操作事件实体类 WmsAnnealOperateEvent
- 定义退火操作事件服务接口 IWmsAnnealOperateEventService
- 实现退火操作事件服务业务逻辑 WmsAnnealOperateEventServiceImpl
- 添加退火操作事件控制器 WmsAnnealOperateEventController
- 创建退火操作事件数据访问层 WmsAnnealOperateEventMapper
- 实现退火操作事件业务对象 WmsAnnealOperateEventBo 和视图对象 WmsAnnealOperateEventVo
- 集成 MyBatis Plus 分页查询和基础 CRUD 功能
- 添加 Excel 导出功能和操作日志记录
- 实现表单验证和重复提交防护机制
2026-04-16 14:55:43 +08:00
e99d7709d2 feat(warehouse): 添加仓库使用次数统计功能
- 在WmsMaterialCoilMapper中新增selectWarehouseIdCount方法用于统计仓库钢卷数量
- 在WmsWarehouseBo中新增orderByUseCount字段支持按使用次数排序
- 修改WmsWarehouseServiceImpl实现按使用次数或序号排序逻辑
- 创建WarehouseUseCountTask定时任务每晚1点更新仓库使用次数
- 实现定时计算各仓库中钢卷数量并更新到useCount字段功能
2026-04-16 14:25:54 +08:00
623e78629d feat(warehouse): 添加仓库使用次数字段支持
- 在WmsWarehouse实体类中新增useCount字段及注释
- 在WmsWarehouseBo业务对象中添加useCount属性
- 更新WmsWarehouseMapper.xml映射文件,增加useCount字段映射
- 在WmsWarehouseServiceImpl查询条件中加入useCount过滤逻辑
- 在WmsWarehouseVo视图对象中添加useCount字段并配置Excel导出
2026-04-16 14:03:26 +08:00
c1938e29a4 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-16 13:54:24 +08:00
54d426984b feat(wms): 添加钢卷物料统计数据接口
- 在 IWmsMaterialCoilService 中新增 getStatistics 方法用于汇总统计
- 在 WmsMaterialCoilController 中添加 /statisticsList 接口
- 在 WmsMaterialCoilMapper 中新增 selectStatistics 查询方法
- 在 WmsMaterialCoilMapper.xml 中实现统计 SQL 查询
- 在 WmsMaterialCoilServiceImpl 中实现统计业务逻辑
- 支持按筛选条件统计总毛重、总净重和总数
- 采用高性能查询方式只查询 sum/count 聚合数据
- 独立统计接口不影响原有分页查询功能
2026-04-16 13:54:12 +08:00
砂糖
440e70ee82 feat(组件): 为多选组件添加全选功能并移除板面校验
- 在多选组件中增加全选选项和功能
- 移除异常管理中的板面校验逻辑
- 修复保存按钮加载状态显示问题
2026-04-16 10:18:21 +08:00
砂糖
220a24da78 fix(wms): 修复参数名错误并移除无用导入
修复pendingAction接口中newCoilIds参数默认值问题
将createBy/updateBy统一改为createBys/updateBys
移除report模板中未使用的listCoilWithIds导入
2026-04-16 10:17:35 +08:00
c31dc4948e feat(WmsMaterialCoil): 添加按创建人筛选功能
- 在 WmsMaterialCoilBo 中新增 createBys 字段用于多创建人筛选
- 实现逗号分隔的创建人列表解析功能
- 添加非空验证和字符串清理逻辑
- 构建 in 查询条件支持多创建人匹配
- 集成到现有查询条件构建流程中
2026-04-16 09:42:37 +08:00
7b55f358b4 feat(WmsCoilPendingAction): 支持按多个创建人筛选待办操作
- 在WmsCoilPendingActionBo中新增createBys字段用于接收多个创建人参数
- 修改查询条件支持逗号分隔的多个创建人筛选功能
- 实现将createBys字符串拆分为列表并进行in查询的逻辑
- 添加空值过滤和字符串清理确保查询准确性
2026-04-16 09:15:09 +08:00
2fcc7b3279 fix(wms): 修复卷材待处理操作完成时的空值设置问题
- 添加对 newCoilIds 的空值和 "-" 值检查
- 避免在无效值情况下设置 processedCoilIds 字段
- 确保只有有效的新卷材 ID 才会被更新到操作记录中
2026-04-16 09:10:39 +08:00
砂糖
8e5ce5c119 feat(报表): 添加发货配卷时间列
在报表配置中添加发货配卷时间列,用于显示配卷事件的时间信息
2026-04-15 15:29:13 +08:00
砂糖
ee275d3ea5 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-04-15 15:28:35 +08:00
砂糖
5e80208d61 feat(wms): 在完成操作时传递新钢卷ID参数
修改completeAction接口以接收新钢卷ID参数,并在多个视图中调用时传递该参数
2026-04-15 15:28:28 +08:00
49 changed files with 1498 additions and 201 deletions

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询退火操作事件列表
export function listAnnealOperateEvent(query) {
return request({
url: '/wms/annealOperateEvent/list',
method: 'get',
params: query
})
}
// 查询退火操作事件详细
export function getAnnealOperateEvent(eventId) {
return request({
url: '/wms/annealOperateEvent/' + eventId,
method: 'get'
})
}
// 新增退火操作事件
export function addAnnealOperateEvent(data) {
return request({
url: '/wms/annealOperateEvent',
method: 'post',
data: data
})
}
// 修改退火操作事件
export function updateAnnealOperateEvent(data) {
return request({
url: '/wms/annealOperateEvent',
method: 'put',
data: data
})
}
// 删除退火操作事件
export function delAnnealOperateEvent(eventId) {
return request({
url: '/wms/annealOperateEvent/' + eventId,
method: 'delete'
})
}

View File

@@ -389,4 +389,12 @@ export function listTypeErrorCoil() {
method: 'get',
timeout: 600000
})
}
export function getCoilStatisticsList(params) {
return request({
url: '/wms/materialCoil/statisticsList',
method: 'get',
params,
})
}

View File

@@ -122,10 +122,13 @@ export function startProcess(actionId) {
}
// 完成操作
export function completeAction(actionId) {
export function completeAction(actionId, newCoilIds) {
return request({
url: `/wms/coilPendingAction/complete/${actionId}`,
method: 'put'
method: 'put',
params: {
newCoilIds: newCoilIds || '-'
}
})
}

View File

@@ -27,7 +27,7 @@
<el-option label="原料" value="raw_material" />
</el-select>
</el-form-item> -->
<el-form-item label="入场卷号">
<el-form-item label="入场卷号">
<el-input v-model="queryParams.enterCoilNo" placeholder="请输入入场卷号" clearable size="small"
@keyup.enter.native="handleQuery" />
</el-form-item>
@@ -74,8 +74,8 @@
</el-select>
</el-form-item>
<el-form-item label="品质">
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status" placeholder="请选择品质"
clearable />
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
placeholder="请选择品质" clearable />
</el-form-item>
<el-form-item label="实际库区" v-if="orderBy">
<actual-warehouse-select v-model="queryParams.actualWarehouseId" placeholder="请选择实际库区" canSelectLevel2
@@ -86,7 +86,8 @@
<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-checkbox v-if="orderBy" style="margin-left: 10px;" v-model="showCoilMap" size="small">显示钢卷地图</el-checkbox>
<el-checkbox v-if="orderBy && orderId" style="margin-left: 10px;" v-model="showOrderInfo" size="small">显示订单详情</el-checkbox>
<el-checkbox v-if="orderBy && orderId" style="margin-left: 10px;" v-model="showOrderInfo"
size="small">显示订单详情</el-checkbox>
</el-form-item>
</el-form>
@@ -122,8 +123,15 @@
</div>
<!-- 分页 -->
<pagination v-if="!rangeMode" v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize" @pagination="getList" />
<div style="display: flex; justify-content: flex-end; align-items: flex-end; gap: 10px;">
<span>
总净重{{ coilTrimStatistics.total_net_weight || 0 }}t
</span>
<pagination v-if="!rangeMode" v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize" @pagination="getList" />
</div>
<div v-if="multiple && selectedCoils.length > 0" class="selected-stats">
<div class="stats-content">
@@ -181,7 +189,7 @@
</template>
<script>
import { listMaterialCoil } from '@/api/wms/coil';
import { listMaterialCoil, getCoilStatisticsList } from '@/api/wms/coil';
import { listActualWarehouse } from "@/api/wms/actualWarehouse";
import { treeActualWarehouseTwoLevel } from "@/api/wms/actualWarehouse";
import MemoInput from '@/components/MemoInput/index.vue';
@@ -312,6 +320,7 @@ export default {
treeProps: { label: "actualWarehouseName", children: "children" },
treeLoading: false,
showOrderInfo: false,
coilTrimStatistics: {},
};
},
computed: {
@@ -503,6 +512,11 @@ export default {
queryPayload.saleId = this.currentUserId;
}
const response = await listMaterialCoil(queryPayload);
const { pageNum, pageSize, excludeBound, orderBy, ...noPager } = queryPayload;
getCoilStatisticsList(noPager).then((res) => {
console.log('钢卷统计数据:', res);
this.coilTrimStatistics = res.data || {};
});
if (response.code === 200) {
this.coilList = response.rows || [];
this.total = response.total || 0;

View File

@@ -74,8 +74,10 @@ export default {
console.log('仓库API返回数据:', response);
const data = response.data || [];
console.log('处理后的数据:', data);
this.warehouseOptions = this.buildTreeOptions(data);
console.log('构建的树形选项:', this.warehouseOptions);
let options = this.buildTreeOptions(data);
options = this.sortOptionsByUsage(options);
this.warehouseOptions = options;
console.log('构建并排序后的树形选项:', this.warehouseOptions);
}).catch(error => {
console.error("加载仓库选项失败:", error);
this.warehouseOptions = [];
@@ -106,7 +108,36 @@ export default {
return options;
},
getWarehouseUsage() {
try {
const usage = localStorage.getItem('warehouseUsage');
return usage ? JSON.parse(usage) : {};
} catch (error) {
console.error('获取仓库使用记录失败:', error);
return {};
}
},
updateWarehouseUsage(warehouseId) {
try {
const usage = this.getWarehouseUsage();
usage[warehouseId] = (usage[warehouseId] || 0) + 1;
localStorage.setItem('warehouseUsage', JSON.stringify(usage));
} catch (error) {
console.error('更新仓库使用记录失败:', error);
}
},
sortOptionsByUsage(options) {
const usage = this.getWarehouseUsage();
return options.sort((a, b) => {
const usageA = usage[a.warehouseId] || 0;
const usageB = usage[b.warehouseId] || 0;
return usageB - usageA;
});
},
onChange(val) {
if (val) {
this.updateWarehouseUsage(val);
}
this.$emit('input', val);
this.$emit('change', val);
}

View File

@@ -1,25 +1,34 @@
<template>
<div class="muti-select">
<!-- 下拉选择模式 -->
<el-select
v-if="type === 'select'"
v-model="innerValue"
multiple
:placeholder="placeholder"
:filterable="filterable"
:clearable="clearable"
:allow-create="allowAdd"
:disabled="disabled"
:size="size"
@change="handleChange"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<div v-if="type === 'select'" class="select-container">
<el-select
v-model="innerValue"
multiple
:placeholder="placeholder"
:filterable="filterable"
:clearable="clearable"
:allow-create="allowAdd"
:disabled="disabled"
:size="size"
@change="handleChange"
>
<!-- 全选选项 -->
<!-- <el-option
v-if="showSelectAll && options.length > 0"
key="selectAll"
label="全选"
value="selectAll"
@click="toggleSelectAll"
/> -->
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<!-- 复选框模式 -->
<div v-else-if="type === 'checkbox'" class="checkbox-group">
@@ -33,14 +42,14 @@
{{ item.label }}
</el-checkbox>
</el-checkbox-group>
<!-- <el-button
<el-button
v-if="showSelectAll && options.length > 0"
type="text"
size="small"
@click="toggleSelectAll"
>
{{ isAllSelected ? '取消全选' : '全选' }}
</el-button> -->
</el-button>
</div>
</div>
</template>
@@ -114,7 +123,9 @@
methods: {
// 处理选择变化
handleChange(val) {
this.$emit('change', val.join(','));
// 过滤掉 'selectAll' 选项
const filteredVal = val.filter(item => item !== 'selectAll');
this.$emit('change', filteredVal.join(','));
},
// 处理复选框变化
handleCheckboxChange(val) {

View File

@@ -14,25 +14,23 @@
<el-table v-loading="loading" :data="orderItemList">
<el-table-column label="产品类型" align="center" prop="productType" />
<el-table-column label="成品规格" align="center" prop="finishedProductSpec" />
<el-table-column label="原料规格" align="center" prop="rawMaterialSpec" />
<el-table-column label="宽度公差" align="center" prop="widthTolerance" />
<el-table-column label="厚度公差" align="center" prop="thicknessTolerance" />
<el-table-column label="成品规格" align="center" prop="finishedProductSpec" />
<el-table-column label="材质" align="center" prop="material" />
<el-table-column label="等级" align="center" prop="grade" />
<el-table-column label="重量" align="center" prop="weight" />
<el-table-column label="合同定价" align="center" prop="contractPrice" />
<el-table-column label="金额(元)" align="center">
<template slot-scope="scope">
<el-table-column label="含税单价(元/吨)" align="center" prop="contractPrice" />
<el-table-column label="含税总额" align="center">
<template slot-scope="scope">
{{ scope.row.weight * scope.row.contractPrice }}
</template>
</el-table-column>
<el-table-column label="定制人" align="center" prop="customizer" />
<el-table-column label="发货人" align="center" prop="shipper" />
<el-table-column label="排产批次" align="center" prop="productionBatch" />
<!-- <el-table-column label="产品数量" align="center" prop="productNum" /> -->
<!-- <el-table-column label="特殊要求" align="center" prop="specialRequire" /> -->
<!-- <el-table-column label="明细金额" align="center" prop="itemAmount" /> -->
<el-table-column label="无税单价(元/吨)" align="center" prop="itemAmount" />
<el-table-column label="卷数" align="center" prop="productNum" />
<el-table-column label="特殊要求" align="center" prop="specialRequire" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" v-if="editable">
<template slot-scope="scope">

View File

@@ -51,8 +51,8 @@
<el-input v-model="queryParams.signLocation" placeholder="请输入签订地点" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="合同状态" prop="contractStatus">
<el-select v-model="queryParams.contractStatus" placeholder="请选择合同状态">
<el-form-item label="合同状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择合同状态">
<el-option label="草稿" value="0" />
<el-option label="已生效" value="1" />
<el-option label="已作废" value="2" />

View File

@@ -105,13 +105,14 @@ export default {
const data = response.data || {};
this.summary = data.summary || {};
this.detailList = data.details.map(item => {
return item.coils.map(coil => {
return item.coils?.map(coil => {
return {
...item,
...coil,
}
})
}) || []
}).flat();
console.log(this.detailList);
this.loading = false;
}).catch(() => {
this.loading = false;

View File

@@ -153,30 +153,36 @@
</div>
</div>
<el-table :data="coilList" v-loading="coilLoading" class="light-table">
<el-table-column label="钢卷层级" align="center" width="80">
<template slot-scope="scope">
<el-input v-model="scope.row.furnaceLevel" placeholder="请输入钢卷层级"
@change="handlePLanCoilChange(scope.row)" />
</template>
</el-table-column>
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo" />
<!-- <el-table-column label="当前钢卷号" align="center" prop="currentCoilNo" /> -->
<el-table-column label="创建时间" align="center" prop="createTime" width="200">
<template slot-scope="scope">
<el-date-picker style="width: 185px" v-model="scope.row.createTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
placeholder="选择创建时间" @change="handlePLanCoilChange(scope.row)"/>
<el-date-picker style="width: 185px" v-model="scope.row.createTime" type="datetime"
value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择创建时间" @change="handlePLanCoilChange(scope.row)" />
</template>
</el-table-column>
<el-table-column label="钢卷去向" align="center" width="220">
<template slot-scope="scope">
<WarehouseSelect v-model="scope.row.logicWarehouseId" @change="handlePLanCoilChange(scope.row)"/>
<el-select v-model="scope.row.logicWarehouseId" @change="handlePLanCoilChange(scope.row)">
<el-option v-for="item in warehouseList" :key="item.warehouseId" :label="item.warehouseName"
:value="item.warehouseId" />
</el-select>
</template>
</el-table-column>
<el-table-column label="钢卷层级" align="center" width="80">
<template slot-scope="scope">
<el-input v-model="scope.row.furnaceLevel" placeholder="请输入钢卷层级" @change="handlePLanCoilChange(scope.row)"/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<!-- <el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleUnbind(scope.row)">
{{ unbindLabel(currentPlan.status) }}
</el-button>
</template>
</el-table-column>
</el-table-column> -->
</el-table>
</div>
</el-card>
@@ -184,12 +190,15 @@
</el-row>
<el-dialog title="完成退火" :visible.sync="completeOpen" width="720px" append-to-body>
<div class="complete-tip">请为每条钢卷分配实际库位未分配将无法完成</div>
<div class="complete-tip">请为每条钢卷分配逻辑库区去向未分配将无法完成</div>
<el-table :data="completeCoils" v-loading="completeLoading" height="360px">
<el-table-column label="入场钢卷号" prop="enterCoilNo" align="center" />
<el-table-column label="钢卷去向" align="center" width="240">
<template slot-scope="scope">
<WarehouseSelect v-model="scope.row.warehouseId" />
<el-select v-model="scope.row.warehouseId" @change="handlePLanCoilChange(scope.row)">
<el-option v-for="item in warehouseList" :key="item.warehouseId" :label="item.warehouseName"
:value="item.warehouseId" />
</el-select>
</template>
</el-table-column>
</el-table>
@@ -253,7 +262,9 @@
import { listAnnealPlan, updateAnnealPlanCoil, getAnnealPlan, addAnnealPlan, updateAnnealPlan, delAnnealPlan, changeAnnealPlanStatus, inFurnace, completeAnnealPlan, listAnnealPlanCoils, bindAnnealPlanCoils, unbindAnnealPlanCoil } from "@/api/wms/annealPlan";
import { listAnnealFurnace } from "@/api/wms/annealFurnace";
import { listMaterialCoil } from "@/api/wms/coil";
import { listWarehouse } from '@/api/wms/warehouse'
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
import { addAnnealOperateEvent } from "@/api/wms/annealOperateEvent";
export default {
name: "AnnealPlan",
@@ -308,14 +319,15 @@ export default {
completeLoading: false,
completePlanId: null,
completeCoils: [],
warehouseList: [],
};
},
created() {
this.getList();
this.loadFurnaces();
this.getMaterialCoils();
this.loadActualWarehouses();
},
this.loadWarehouses();
},
methods: {
getList() {
this.loading = true;
@@ -325,6 +337,11 @@ export default {
this.loading = false;
});
},
loadWarehouses() {
listWarehouse().then(response => {
this.warehouseList = response.data || [];
});
},
loadFurnaces() {
listAnnealFurnace({ pageNum: 1, pageSize: 999, status: 1 }).then(response => {
this.furnaceOptions = response.rows || [];
@@ -372,6 +389,7 @@ export default {
this.completeLoading = true;
listAnnealPlanCoils(this.currentPlan.planId).then(response => {
this.completeCoils = (response.data || []).map(item => ({
...item,
coilId: item.coilId,
enterCoilNo: item.enterCoilNo,
warehouseId: item.logicWarehouseId || null
@@ -395,6 +413,7 @@ export default {
planId: this.currentPlan.planId,
coilId: item.coilId
}).then(() => {
// anneal-todo: 新增操作事件
this.$message.success('已加入计划');
this.loadPlanCoils();
}).finally(() => {
@@ -526,6 +545,15 @@ export default {
});
this.loading = true;
await inFurnace({ planId: row.planId });
// 炉火开始加工
const targetFurnaceName = this.furnaceOptions.find(item => item.furnaceId === row.targetFurnaceId)?.furnaceName || '';
addAnnealOperateEvent({
annealFurnaceId: row.targetFurnaceId,
operateType: 'IN',
operateContent: '退火炉' + targetFurnaceName + '开始加工',
})
// anneal-todo: 新增操作事件
this.loading = false;
row.status = 2;
row.actualStartTime = new Date();
@@ -552,6 +580,13 @@ export default {
planId: this.completePlanId,
locations: locations
}).then(() => {
// anneal-todo: 新增操作事件
const targetFurnaceName = this.furnaceOptions.find(item => item.furnaceId === this.currentPlan.targetFurnaceId)?.furnaceName || '';
addAnnealOperateEvent({
annealFurnaceId: this.currentPlan.targetFurnaceId,
operateType: 'COMPLETE',
operateContent: '退火炉' + targetFurnaceName + '完成加工。',
})
this.$message.success('已完成');
this.completeOpen = false;
this.getList();
@@ -571,6 +606,7 @@ export default {
coilId: row.coilId
});
}).then(() => {
// anneal-todo: 新增操作事件
this.$message.success('解绑成功');
this.loadPlanCoils();
});

View File

@@ -67,8 +67,8 @@
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleUpdate(scope.row)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click.stop="handleDelete(scope.row)">删除</el-button>
<el-button size="mini" type="text" icon="el-icon-s-operation"
@click.stop="openStatusDialog(scope.row)">状态</el-button>
<!-- <el-button size="mini" type="text" icon="el-icon-s-operation"
@click.stop="openStatusDialog(scope.row)">状态</el-button> -->
<!-- <el-button v-if="scope.row.status === 0" size="mini" type="text" icon="el-icon-s-flag"
:disabled="!scope.row.coilCount" @click.stop="handleInFurnace(scope.row)">入炉</el-button> -->
<el-button v-if="scope.row.status === 2" size="mini" type="text" icon="el-icon-check"
@@ -153,6 +153,12 @@
</div> -->
</div>
<el-table :data="coilList" v-loading="coilLoading" class="light-table">
<el-table-column label="钢卷层级" align="center" width="80">
<template slot-scope="scope">
<el-input v-model="scope.row.furnaceLevel" placeholder="请输入钢卷层级"
@change="handlePLanCoilChange(scope.row)" />
</template>
</el-table-column>
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo" />
<el-table-column label="创建时间" align="center" prop="createTime">
<template slot-scope="scope">
@@ -166,7 +172,7 @@
</el-table-column>
<el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleUnbind(scope.row)">
<el-button v-if="currentPlan.status === 0" size="mini" type="text" icon="el-icon-delete" @click="handleUnbind(scope.row)">
{{ unbindLabel(currentPlan.status) }}
</el-button>
</template>
@@ -208,13 +214,13 @@
:value="item.furnaceId" />
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<!-- <el-form-item label="状态" prop="status">
<el-select v-model="form.status" placeholder="请选择">
<el-option label="未开始" :value="0" />
<el-option label="进行中" :value="2" />
<el-option label="已完成" :value="3" />
</el-select>
</el-form-item>
</el-form-item> -->
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
@@ -226,7 +232,7 @@
</el-dialog>
<el-dialog title="更新状态" :visible.sync="statusOpen" width="360px" append-to-body>
<el-form label-width="90px">
<!-- <el-form label-width="90px">
<el-form-item label="状态">
<el-select v-model="statusForm.status" placeholder="请选择">
<el-option label="未开始" :value="0" />
@@ -234,7 +240,7 @@
<el-option label="已完成" :value="3" />
</el-select>
</el-form-item>
</el-form>
</el-form> -->
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitStatus"> </el-button>
<el-button @click="statusOpen = false"> </el-button>
@@ -244,10 +250,11 @@
</template>
<script>
import { listAnnealPlan, getAnnealPlan, addAnnealPlan, updateAnnealPlan, delAnnealPlan, changeAnnealPlanStatus, inFurnace, completeAnnealPlan, listAnnealPlanCoils, bindAnnealPlanCoils, unbindAnnealPlanCoil } from "@/api/wms/annealPlan";
import { listAnnealPlan, getAnnealPlan, updateAnnealPlanCoil ,addAnnealPlan, updateAnnealPlan, delAnnealPlan, changeAnnealPlanStatus, inFurnace, completeAnnealPlan, listAnnealPlanCoils, bindAnnealPlanCoils, unbindAnnealPlanCoil } from "@/api/wms/annealPlan";
import { listAnnealFurnace } from "@/api/wms/annealFurnace";
import { listMaterialCoil } from "@/api/wms/coil";
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
import { addAnnealOperateEvent } from "@/api/wms/annealOperateEvent";
export default {
name: "AnnealPlan",
@@ -308,7 +315,6 @@ export default {
this.getList();
this.loadFurnaces();
this.getMaterialCoils();
this.loadActualWarehouses();
},
methods: {
getList() {
@@ -345,6 +351,13 @@ export default {
this.resetMaterialForm();
this.handleMaterialQuery();
},
handlePLanCoilChange(row) {
updateAnnealPlanCoil(row).then(() => {
this.$message.success('已更新');
}).finally(() => {
this.loadPlanCoils();
});
},
openCompleteDialog() {
if (!this.currentPlan.planId) {
this.$message.warning('请先选择计划');
@@ -383,6 +396,15 @@ export default {
coilId: item.coilId
}).then(() => {
this.$message.success('已加入计划');
// 查找对应id退火炉的名称
const targetFurnaceName = this.furnaceOptions.find(item => item.furnaceId === this.currentPlan.targetFurnaceId)?.furnaceName || '';
// anneal-todo: 新增操作事件
addAnnealOperateEvent({
annealFurnaceId: this.currentPlan.targetFurnaceId,
operateType: 'ADD',
operateContent: '钢卷号' + item.enterCoilNo + '加入退火炉' + targetFurnaceName,
coilId: item.coilId,
})
this.loadPlanCoils();
}).finally(() => {
this.coilLoading = false;
@@ -512,6 +534,7 @@ export default {
});
this.loading = true;
await inFurnace({ planId: row.planId });
// anneal-todo: 新增操作事件
this.loading = false;
row.status = 2;
row.actualStartTime = new Date();
@@ -540,6 +563,7 @@ export default {
}).then(() => {
this.$message.success('已完成');
this.completeOpen = false;
// anneal-todo: 新增操作事件
this.getList();
this.loadPlanCoils();
}).finally(() => {
@@ -558,6 +582,15 @@ export default {
});
}).then(() => {
this.$message.success('解绑成功');
// 查找对应id退火炉的名称
const targetFurnaceName = this.furnaceOptions.find(item => item.furnaceId === this.currentPlan.targetFurnaceId)?.furnaceName || '';
// anneal-todo: 新增操作事件
addAnnealOperateEvent({
annealFurnaceId: this.currentPlan.targetFurnaceId,
operateType: 'UNBIND',
operateContent: '钢卷号' + row.enterCoilNo + '解绑退火炉' + targetFurnaceName,
coilId: row.coilId,
})
this.loadPlanCoils();
});
},

View File

@@ -0,0 +1,408 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="退火炉" prop="annealFurnaceId">
<el-select
v-model="queryParams.annealFurnaceId"
placeholder="请选择退火炉"
clearable
@keyup.enter.native="handleQuery"
>
<el-option
v-for="item in annealFurnaceList"
:key="item.furnaceId"
:label="item.furnaceName"
:value="item.furnaceId"
/>
</el-select>
</el-form-item>
<el-form-item label="操作类型" prop="operateType">
<el-select
v-model="queryParams.operateType"
placeholder="请选择操作类型"
clearable
@keyup.enter.native="handleQuery"
>
<el-option
label="新增"
value="ADD"
/>
<el-option
label="解绑"
value="UNBIND"
/>
<el-option
label="入炉"
value="IN"
/>
<el-option
label="完成"
value="COMPLETE"
/>
</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="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
>修改</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-download"
size="mini"
@click="handleExport"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="annealOperateEventList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="主键ID" align="center" prop="eventId" v-if="true"/> -->
<el-table-column label="退火炉" align="center" prop="annealFurnaceName">
<template slot-scope="scope">
{{ getAnnealFurnaceName(scope.row.annealFurnaceId) || '-' }}
</template>
</el-table-column>
<el-table-column label="操作类型" align="center" prop="operateType">
<template slot-scope="scope">
{{ getOperateTypeName(scope.row.operateType) || '-' }}
</template>
</el-table-column>
<el-table-column label="操作描述" align="center" prop="operateContent" />
<!-- <el-table-column label="钢卷ID(可选)" align="center" prop="coilId" /> -->
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作人" align="center" prop="createBy" />
<el-table-column label="操作时间" align="center" prop="createTime" />
<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-delete"
@click="handleDelete(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"
/>
<!-- 添加或修改退火操作事件对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="退火炉" prop="annealFurnaceId">
<el-select v-model="form.annealFurnaceId" placeholder="请选择退火炉">
<el-option v-for="item in annealFurnaceList" :key="item.furnaceId" :label="item.furnaceName" :value="item.furnaceId" />
</el-select>
</el-form-item>
<el-form-item label="操作描述">
<el-input type="textarea" v-model="form.operateContent" placeholder="请输入操作描述" />
</el-form-item>
<el-form-item label="操作类型" prop="operateType">
<el-select v-model="form.operateType" placeholder="请选择操作类型" clearable>
<el-option
label="新增"
value="ADD"
/>
<el-option
label="解绑"
value="UNBIND"
/>
<el-option
label="入炉"
value="IN"
/>
<el-option
label="完成"
value="COMPLETE"
/>
</el-select>
</el-form-item>
<el-form-item label="操作人" prop="createBy">
<el-input v-model="form.createBy" placeholder="请输入操作人" />
</el-form-item>
<el-form-item label="操作时间" prop="createTime">
<el-date-picker
v-model="form.createTime"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择操作时间"
/>
</el-form-item>
<!-- <el-form-item label="钢卷ID(可选)" prop="coilId">
<el-input v-model="form.coilId" placeholder="请输入钢卷ID(可选)" />
</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 { listAnnealOperateEvent, getAnnealOperateEvent, delAnnealOperateEvent, addAnnealOperateEvent, updateAnnealOperateEvent } from "@/api/wms/annealOperateEvent";
import { listAnnealFurnace } from "@/api/wms/annealFurnace";
export default {
name: "AnnealOperateEvent",
data() {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 退火操作事件表格数据
annealOperateEventList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
annealFurnaceId: undefined,
operateType: undefined,
operateContent: undefined,
coilId: undefined,
},
// 表单参数
form: {},
// 表单校验
rules: {
eventId: [
{ required: true, message: "主键ID不能为空", trigger: "blur" }
],
annealFurnaceId: [
{ required: true, message: "退火炉ID不能为空", trigger: "blur" }
],
operateType: [
{ required: true, message: "操作类型 如:START/PAUSE/STOP/FEED/TAKE/RESET不能为空", trigger: "change" }
],
operateContent: [
{ required: true, message: "操作内容描述不能为空", trigger: "blur" }
],
coilId: [
{ required: true, message: "钢卷ID(可选)不能为空", trigger: "blur" }
],
delFlag: [
{ required: true, message: "删除标志不能为空", trigger: "blur" }
],
// remark: [
// { required: true, message: "备注不能为空", trigger: "blur" }
// ],
createBy: [
{ required: true, message: "操作人不能为空", trigger: "blur" }
],
createTime: [
{ required: true, message: "操作时间不能为空", trigger: "blur" }
],
updateTime: [
{ required: true, message: "更新时间不能为空", trigger: "blur" }
],
},
// 退火炉列表
annealFurnaceList: [],
};
},
created() {
this.getList();
this.getAnnealFurnaceList();
},
methods: {
/** 查询退火操作事件列表 */
getList() {
this.loading = true;
listAnnealOperateEvent(this.queryParams).then(response => {
this.annealOperateEventList = response.rows;
this.total = response.total;
this.loading = false;
});
},
/** 查询退火炉列表 */
getAnnealFurnaceList() {
listAnnealFurnace({ pageNum: 1, pageSize: 10000 }).then(response => {
this.annealFurnaceList = response.rows;
});
},
/** 获取退火炉名称 */
getAnnealFurnaceName(furnaceId) {
const item = this.annealFurnaceList.find(item => item.furnaceId === furnaceId);
return item ? item.furnaceName : '-';
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
/** 获取操作类型名称 */
getOperateTypeName(operateType) {
const map = {
'ADD': '新增',
'UNBIND': '解绑',
'IN': '入炉',
'COMPLETE': '完成',
}
return map[operateType] || '-';
},
// 表单重置
reset() {
this.form = {
eventId: undefined,
annealFurnaceId: undefined,
operateType: undefined,
operateContent: undefined,
coilId: undefined,
delFlag: undefined,
remark: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.eventId)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加退火操作事件";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
const eventId = row.eventId || this.ids
getAnnealOperateEvent(eventId).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;
if (this.form.eventId != null) {
updateAnnealOperateEvent(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addAnnealOperateEvent(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const eventIds = row.eventId || this.ids;
this.$modal.confirm('是否确认删除退火操作事件编号为"' + eventIds + '"的数据项?').then(() => {
this.loading = true;
return delAnnealOperateEvent(eventIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport() {
this.download('wms/annealOperateEvent/export', {
...this.queryParams
}, `annealOperateEvent_${new Date().getTime()}.xlsx`)
}
}
};
</script>

View File

@@ -82,10 +82,10 @@ export default {
{ required: true, message: '请选择位置', trigger: 'change' },
{ validator: this.validateArray, trigger: 'change' }
],
plateSurface: [
{ required: true, message: '请选择上下板面', trigger: 'change' },
{ validator: this.validateArray, trigger: 'change' }
],
// plateSurface: [
// { required: true, message: '请选择上下板面', trigger: 'change' },
// { validator: this.validateArray, trigger: 'change' }
// ],
startPosition: [
{ required: true, message: '请输入开始位置', trigger: ['blur', 'change'] },
{ validator: this.validateStartPosition, trigger: ['blur', 'change'] }

View File

@@ -56,7 +56,7 @@
<div class="section-header">
<h4 class="section-title">异常记录</h4>
<div>
<el-button type="primary" size="mini" @click="handleSave">保存</el-button>
<el-button type="primary" size="mini" @click="handleSave" :loading="buttonLoading">保存</el-button>
<el-button type="default" icon="el-icon-refresh" plain size="mini" @click="refreshAbnormalList"
:loading="abnormalLoading">
刷新
@@ -291,10 +291,10 @@ export default {
this.$message.error(`${rowIndex}行:请选择断面位置`)
return
}
if (!row.plateSurface || row.plateSurface.length === 0) {
this.$message.error(`${rowIndex}行:请选择上下板面`)
return
}
// if (!row.plateSurface || row.plateSurface.length === 0) {
// this.$message.error(`第${rowIndex}行:请选择上下板面`)
// return
// }
if (!row.defectCode) {
this.$message.error(`${rowIndex}行:请选择缺陷代码`)
return
@@ -445,7 +445,7 @@ export default {
.exception-section {
background-color: #fafafa;
border-radius: 4px;
border-radius: 4px;
padding: 16px;
border: 1px solid #e4e7ed;
}

View File

@@ -292,7 +292,7 @@
<script>
import { getMaterialCoil, mergeMaterialCoil } from '@/api/wms/coil';
import { listPendingAction, completeAction, addPendingAction, getPendingAction } from '@/api/wms/pendingAction';
import { listPendingAction, getPendingAction } from '@/api/wms/pendingAction';
import CoilSelector from '@/components/CoilSelector';
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
import RawMaterialSelector from "@/components/KLPService/RawMaterialSelect";
@@ -700,12 +700,6 @@ export default {
// 保存合卷
async handleSave() {
// 验证源卷数量
// if (this.sourceCoils.length < 2) {
// this.$message.error('至少需要2个源卷才能合卷');
// return;
// }
// 验证源卷信息
for (let i = 0; i < this.sourceCoils.length; i++) {
const item = this.sourceCoils[i];
@@ -758,7 +752,6 @@ export default {
text: '正在合卷,请稍后...',
background: 'rgba(0, 0, 0, 0.7)'
});
// this.completeAllRelatedActions();
await mergeMaterialCoil(mergeData);
this.$message.success('合卷保存成功');
@@ -802,49 +795,6 @@ export default {
});
},
// 完成所有相关的待操作记录
async completeAllRelatedActions() {
try {
// 收集所有待操作ID
const actionIds = [];
const ncs = [];
// 当前页面的actionId从路由参数获取
// if (this.actionId) {
// actionIds.push(this.actionId);
// }
// 从待合卷列表中选择的钢卷的actionId
this.sourceCoils.forEach(item => {
if (item.actionId) {
actionIds.push(item.actionId);
}
// 或许所有需要直接完成的
if (item.nc) {
ncs.push(item);
}
});
// 批量完成所有待操作
const promises1 = actionIds.map(id => completeAction(id));
const promises2 = ncs.map(item => {
addPendingAction({
actionType: this.actionTypeCode, // 合卷操作
actionStatus: '2', // 2表示已完成
coilId: item.coilId,
currentCoilNo: item.currentCoilNo || '',
priority: 0,
sourceType: 'manual',
completeTime: new Date()
})
});
await Promise.all(promises1.concat(promises2));
} catch (error) {
console.error('完成待操作失败:', error);
// 不影响主流程,只记录错误
}
},
// 取消操作
handleCancel() {
console.log('取消合卷操作', this.$tab);

View File

@@ -33,6 +33,7 @@
<el-descriptions-item label="物料名称">{{ coilInfo.itemName || '-' }}</el-descriptions-item>
<el-descriptions-item label="规格">{{ coilInfo.specification || '-' }}</el-descriptions-item>
<el-descriptions-item label="材质">{{ coilInfo.material || '-' }}</el-descriptions-item>
<el-descriptions-item label="厂家">{{ coilInfo.manufacturer || '-' }}</el-descriptions-item>
<el-descriptions-item label="原料材质">{{ coilInfo.packingStatus || '-' }}</el-descriptions-item>
<el-descriptions-item label="实测长度(m)">{{ coilInfo.actualLength || '-' }}</el-descriptions-item>
<el-descriptions-item label="实测宽度(m)">{{ coilInfo.actualWidth || '-' }}</el-descriptions-item>
@@ -721,7 +722,7 @@ export default {
}
// 2. 完成待办动作(根据业务逻辑调整)
const actionRes = await completeAction(this.actionId)
const actionRes = await completeAction(this.actionId, splitRes.data.childCoilIds.join(','))
if (actionRes.code !== 200) {
this.$message.error('完成待办动作失败:' + actionRes.msg)
return

View File

@@ -676,7 +676,7 @@ export default {
// 如果是从待操作列表进来的,标记操作为完成
if (this.actionId) {
await completeAction(this.actionId);
await completeAction(this.actionId, response.msg);
}
// 延迟返回,让用户看到成功提示

View File

@@ -324,11 +324,9 @@
</template>
<script>
import { getMaterialCoil, updateMaterialCoil, getMaterialCoilTrace, checkCoilNo } from '@/api/wms/coil';
import { getMaterialCoil, updateMaterialCoil, getMaterialCoilTrace } from '@/api/wms/coil';
import { completeAction, getPendingAction } from '@/api/wms/pendingAction';
import { listWarehouse } from '@/api/wms/warehouse';
import { listRawMaterialWithBom } from '@/api/wms/rawMaterial';
import { listProductWithBom } from '@/api/wms/product';
import { getAcidTypingPrefill } from '@/api/pocket/acidTyping';
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
@@ -870,7 +868,6 @@ export default {
enterCoilNo: this.currentInfo.enterCoilNo,
supplierCoilNo: this.currentInfo.supplierCoilNo,
abnormals: this.abnormals,
// 注意不要传newCoils否则会走批量更新逻辑
};
const response = await updateMaterialCoil(updateData);
@@ -880,7 +877,7 @@ export default {
// 如果是从待操作列表进来的,标记操作为完成
if (this.actionId) {
await completeAction(this.actionId);
await completeAction(this.actionId, response.msg);
}
// 延迟返回

View File

@@ -25,8 +25,8 @@
</el-form-item>
<el-form-item label="生效状态">
<el-select v-model="queryParams.isTransferred" @change="handleRegularSearch">
<el-option :label="1">已生效</el-option>
<el-option :label="0">未生效</el-option>
<el-option value="1" label="已生效"></el-option>
<el-option value="0" label="未生效"></el-option>
</el-select>
</el-form-item>
<el-form-item>

View File

@@ -172,6 +172,7 @@ export default {
{ label: '发货绑定目标客户', value: 'bindConsigneeUnit' },
{ label: '发货绑定单位', value: 'bindSenderUnit' },
{ label: '发货绑定负责人', value: 'bindPrincipal' },
{ label: '发货配卷时间', value: 'bindDeliveryTime' },
{ label: '发货时间', value: 'exportTime' },
],
}

View File

@@ -292,6 +292,11 @@ const defaultColumns = {
prop: "bindPrincipal",
align: "center",
},
{
title: '配卷事件',
prop: 'bindDeliveryTime',
align: 'center'
},
]
}

View File

@@ -1,7 +1,7 @@
export const dugeConfig = {
actionTypes: [505, 120],
actionQueryParams: {
createBy: 'dugekuguan'
createBys: 'dugekuguan'
},
baseQueryParams: {
createBy: 'dugekuguan',
@@ -19,7 +19,7 @@ export const dugeConfig = {
export const lajiaoConfig = {
actionTypes: [503, 120],
actionQueryParams: {
updateBy: 'lajiaokuguan'
updateBys: 'lajiaokuguan'
},
baseQueryParams: {
createBy: 'lajiaokuguan',
@@ -37,7 +37,7 @@ export const lajiaoConfig = {
export const shuangConfig = {
actionTypes: [504, 120],
actionQueryParams: {
createBy: 'shuangkuguan'
createBys: 'shuangkuguan'
},
baseQueryParams: {
createBy: 'shuangkuguan',
@@ -55,7 +55,7 @@ export const shuangConfig = {
export const tuozhiConfig = {
actionTypes: [502, 120],
actionQueryParams: {
createBy: 'tuozhikuguan'
createBys: 'tuozhikuguan'
},
baseQueryParams: {
createBy: 'tuozhikuguan',
@@ -73,7 +73,7 @@ export const tuozhiConfig = {
export const suanzhaConfig = {
actionTypes: [11, 120],
actionQueryParams: {
createBy: 'suanzhakuguan'
createBys: 'suanzhakuguan,yuanliaoku'
},
baseQueryParams: {
createBy: 'suanzhakuguan',
@@ -94,7 +94,7 @@ export const suanzhaConfig = {
export const zincConfig = {
actionTypes: [501, 120],
actionQueryParams: {
createBy: 'duxinkuguan'
createBys: 'duxinkuguan'
},
baseQueryParams: {
createBy: 'duxinkuguan',
@@ -113,7 +113,7 @@ export const zincConfig = {
export const splitConfig = {
actionTypes: [506],
actionQueryParams: {
createBy: 'fenjiankuguan'
createBys: 'fenjiankuguan'
},
baseQueryParams: {
createBy: 'fenjiankuguan',

View File

@@ -42,7 +42,7 @@ export async function fetchLossList(actionTypes, queryParams, callback) {
return listPendingAction({
actionStatus: 2,
actionType,
createBy: queryParams.createBy,
createBys: queryParams.createBys,
startTime: queryParams.byCreateTimeStart,
endTime: queryParams.byCreateTimeEnd,
pageSize: 99999,
@@ -63,6 +63,7 @@ export async function fetchLossList(actionTypes, queryParams, callback) {
...queryParams,
byCreateTimeStart: undefined,
byCreateTimeEnd: undefined,
createBys: undefined,
createBy: undefined,
actionIds: actionIds,
pageSize: 99999,

View File

@@ -68,10 +68,6 @@
</template>
<script>
import { listCoilWithIds } from "@/api/wms/coil";
import {
listPendingAction,
} from '@/api/wms/pendingAction';
import ProductInfo from "@/components/KLPService/Renderer/ProductInfo";
import RawMaterialInfo from "@/components/KLPService/Renderer/RawMaterialInfo";
import CoilNo from "@/components/KLPService/Renderer/CoilNo.vue";

View File

@@ -68,7 +68,6 @@
</template>
<script>
import { listCoilWithIds } from "@/api/wms/coil";
import ProductInfo from "@/components/KLPService/Renderer/ProductInfo";
import RawMaterialInfo from "@/components/KLPService/Renderer/RawMaterialInfo";
import CoilNo from "@/components/KLPService/Renderer/CoilNo.vue";

View File

@@ -0,0 +1,99 @@
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.WmsAnnealOperateEventVo;
import com.klp.domain.bo.WmsAnnealOperateEventBo;
import com.klp.service.IWmsAnnealOperateEventService;
import com.klp.common.core.page.TableDataInfo;
/**
* 退火操作事件
*
* @author klp
* @date 2026-04-16
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/wms/annealOperateEvent")
public class WmsAnnealOperateEventController extends BaseController {
private final IWmsAnnealOperateEventService iWmsAnnealOperateEventService;
/**
* 查询退火操作事件列表
*/
@GetMapping("/list")
public TableDataInfo<WmsAnnealOperateEventVo> list(WmsAnnealOperateEventBo bo, PageQuery pageQuery) {
return iWmsAnnealOperateEventService.queryPageList(bo, pageQuery);
}
/**
* 导出退火操作事件列表
*/
@Log(title = "退火操作事件", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(WmsAnnealOperateEventBo bo, HttpServletResponse response) {
List<WmsAnnealOperateEventVo> list = iWmsAnnealOperateEventService.queryList(bo);
ExcelUtil.exportExcel(list, "退火操作事件", WmsAnnealOperateEventVo.class, response);
}
/**
* 获取退火操作事件详细信息
*
* @param eventId 主键
*/
@GetMapping("/{eventId}")
public R<WmsAnnealOperateEventVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long eventId) {
return R.ok(iWmsAnnealOperateEventService.queryById(eventId));
}
/**
* 新增退火操作事件
*/
@Log(title = "退火操作事件", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody WmsAnnealOperateEventBo bo) {
return toAjax(iWmsAnnealOperateEventService.insertByBo(bo));
}
/**
* 修改退火操作事件
*/
@Log(title = "退火操作事件", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody WmsAnnealOperateEventBo bo) {
return toAjax(iWmsAnnealOperateEventService.updateByBo(bo));
}
/**
* 删除退火操作事件
*
* @param eventIds 主键串
*/
@Log(title = "退火操作事件", businessType = BusinessType.DELETE)
@DeleteMapping("/{eventIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] eventIds) {
return toAjax(iWmsAnnealOperateEventService.deleteWithValidByIds(Arrays.asList(eventIds), true));
}
}

View File

@@ -68,6 +68,15 @@ public class WmsMaterialCoilController extends BaseController {
return iWmsMaterialCoilService.queryPageListWithBindInfo(bo, pageQuery);
}
/**
* 统计筛选条件下的全量汇总数据
* 独立的统计接口,使用与分页列表相同的查询条件
*/
@GetMapping("/statisticsList")
public R<Map<String, java.math.BigDecimal>> getStatistics(WmsMaterialCoilBo bo) {
return R.ok(iWmsMaterialCoilService.getStatistics(bo));
}
/**
* 原料钢卷库位分布查询(先库位,再钢卷映射)
*/
@@ -225,7 +234,7 @@ public class WmsMaterialCoilController extends BaseController {
@RepeatSubmit()
@PutMapping()
public R<String> edit(@Validated(EditGroup.class) @RequestBody WmsMaterialCoilBo bo) {
return R.ok(iWmsMaterialCoilService.updateByBo(bo));
return R.ok(iWmsMaterialCoilService.updateByBo(bo, null));
}
/**

View File

@@ -0,0 +1,53 @@
package com.klp.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 退火操作事件对象 wms_anneal_operate_event
*
* @author klp
* @date 2026-04-16
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("wms_anneal_operate_event")
public class WmsAnnealOperateEvent extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 主键ID
*/
@TableId(value = "event_id")
private Long eventId;
/**
* 退火炉ID
*/
private Long annealFurnaceId;
/**
* 操作类型 如:START/PAUSE/STOP/FEED/TAKE/RESET
*/
private String operateType;
/**
* 操作内容描述
*/
private String operateContent;
/**
* 钢卷ID(可选)
*/
private Long coilId;
/**
* 删除标志0=正常,1=已删除)
*/
@TableLogic
private Integer delFlag;
/**
* 备注
*/
private String remark;
}

View File

@@ -40,6 +40,10 @@ public class WmsWarehouse extends TreeEntity<WmsWarehouse> {
* 同级排序号
*/
private Long sortNo;
/**
* 使用次数(用于排序:使用越多越靠前)
*/
private Integer useCount;
/**
* 是否启用0=否1=是)
*/

View File

@@ -0,0 +1,51 @@
package com.klp.domain.bo;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
/**
* 退火操作事件业务对象 wms_anneal_operate_event
*
* @author klp
* @date 2026-04-16
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class WmsAnnealOperateEventBo extends BaseEntity {
/**
* 主键ID
*/
private Long eventId;
/**
* 退火炉ID
*/
private Long annealFurnaceId;
/**
* 操作类型 如:START/PAUSE/STOP/FEED/TAKE/RESET
*/
private String operateType;
/**
* 操作内容描述
*/
private String operateContent;
/**
* 钢卷ID(可选)
*/
private Long coilId;
/**
* 备注
*/
private String remark;
}

View File

@@ -126,5 +126,7 @@ public class WmsCoilPendingActionBo extends BaseEntity {
// 钢卷ID列表逗号分隔
private String coilIds;
private String createBys;
}

View File

@@ -351,5 +351,8 @@ public class WmsMaterialCoilBo extends BaseEntity {
* 调拨类型
*/
private String transferType;
//根据逗号分割的创建人筛选
private String createBys;
}

View File

@@ -47,6 +47,11 @@ public class WmsWarehouseBo extends TreeEntity<WmsWarehouseBo> {
*/
private Long sortNo;
/**
* 使用次数(用于排序:使用越多越靠前)
*/
private Integer useCount;
/**
* 是否启用0=否1=是)
*/
@@ -57,5 +62,10 @@ public class WmsWarehouseBo extends TreeEntity<WmsWarehouseBo> {
*/
private String remark;
/**
* 是否按使用次数排序true=按useCount降序false或不传=按sortNo升序
*/
private Boolean orderByUseCount;
}

View File

@@ -0,0 +1,60 @@
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 com.klp.common.core.domain.BaseEntity;
import lombok.Data;
/**
* 退火操作事件视图对象 wms_anneal_operate_event
*
* @author klp
* @date 2026-04-16
*/
@Data
@ExcelIgnoreUnannotated
public class WmsAnnealOperateEventVo extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long eventId;
/**
* 退火炉ID
*/
@ExcelProperty(value = "退火炉ID")
private Long annealFurnaceId;
/**
* 操作类型 如:START/PAUSE/STOP/FEED/TAKE/RESET
*/
@ExcelProperty(value = "操作类型 如:START/PAUSE/STOP/FEED/TAKE/RESET")
private String operateType;
/**
* 操作内容描述
*/
@ExcelProperty(value = "操作内容描述")
private String operateContent;
/**
* 钢卷ID(可选)
*/
@ExcelProperty(value = "钢卷ID(可选)")
private Long coilId;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -56,6 +56,12 @@ public class WmsWarehouseVo {
@ExcelProperty(value = "同级排序号")
private Long sortNo;
/**
* 使用次数(用于排序:使用越多越靠前)
*/
@ExcelProperty(value = "使用次数")
private Integer useCount;
/**
* 是否启用0=否1=是)
*/

View File

@@ -0,0 +1,15 @@
package com.klp.mapper;
import com.klp.domain.WmsAnnealOperateEvent;
import com.klp.domain.vo.WmsAnnealOperateEventVo;
import com.klp.common.core.mapper.BaseMapperPlus;
/**
* 退火操作事件Mapper接口
*
* @author klp
* @date 2026-04-16
*/
public interface WmsAnnealOperateEventMapper extends BaseMapperPlus<WmsAnnealOperateEventMapper, WmsAnnealOperateEvent, WmsAnnealOperateEventVo> {
}

View File

@@ -97,5 +97,20 @@ List<WmsMaterialCoilDeliveryExportVo> selectDeliveryExportListByCoilIds(@Param("
* @return 不匹配的钢卷列表
*/
List<WmsMaterialCoil> selectMismatchedItemCoils();
/**
* 统计筛选条件下的全量汇总数据高性能只查sum/count
* @param qw 查询条件只使用WHERE和JOIN部分
* @return 统计结果Map包含totalGrossWeight, totalNetWeight
*/
Map<String, Object> selectStatistics(@Param("ew") QueryWrapper<WmsMaterialCoil> qw);
/**
* 统计仓库使用次数按warehouse_id出现次数排序
*
* @param warehouseIds 仓库ID列表
* @return 每个仓库的钢卷数量
*/
List<Map<String, Object>> selectWarehouseIdCount(@Param("list") List<Long> warehouseIds);
}

View File

@@ -0,0 +1,49 @@
package com.klp.service;
import com.klp.domain.WmsAnnealOperateEvent;
import com.klp.domain.vo.WmsAnnealOperateEventVo;
import com.klp.domain.bo.WmsAnnealOperateEventBo;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 退火操作事件Service接口
*
* @author klp
* @date 2026-04-16
*/
public interface IWmsAnnealOperateEventService {
/**
* 查询退火操作事件
*/
WmsAnnealOperateEventVo queryById(Long eventId);
/**
* 查询退火操作事件列表
*/
TableDataInfo<WmsAnnealOperateEventVo> queryPageList(WmsAnnealOperateEventBo bo, PageQuery pageQuery);
/**
* 查询退火操作事件列表
*/
List<WmsAnnealOperateEventVo> queryList(WmsAnnealOperateEventBo bo);
/**
* 新增退火操作事件
*/
Boolean insertByBo(WmsAnnealOperateEventBo bo);
/**
* 修改退火操作事件
*/
Boolean updateByBo(WmsAnnealOperateEventBo bo);
/**
* 校验并批量删除退火操作事件信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -42,6 +42,12 @@ public interface IWmsMaterialCoilService {
*/
List<WmsMaterialCoilVo> queryList(WmsMaterialCoilBo bo);
/**
* 统计筛选条件下的全量汇总数据高性能只查sum/count
* 独立的统计接口,不影响分页查询
*/
Map<String, java.math.BigDecimal> getStatistics(WmsMaterialCoilBo bo);
/**
* 新增钢卷物料表
*/
@@ -53,7 +59,7 @@ public interface IWmsMaterialCoilService {
* 如果newCoils为空则进行单个更新
* @return 单个更新或合卷时返回新钢卷ID分卷时返回逗号分隔的新钢卷ID字符串
*/
String updateByBo(WmsMaterialCoilBo bo);
String updateByBo(WmsMaterialCoilBo bo, String qrcodeStepType);
/**
* 合卷操作

View File

@@ -0,0 +1,112 @@
package com.klp.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
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.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.klp.domain.bo.WmsAnnealOperateEventBo;
import com.klp.domain.vo.WmsAnnealOperateEventVo;
import com.klp.domain.WmsAnnealOperateEvent;
import com.klp.mapper.WmsAnnealOperateEventMapper;
import com.klp.service.IWmsAnnealOperateEventService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 退火操作事件Service业务层处理
*
* @author klp
* @date 2026-04-16
*/
@RequiredArgsConstructor
@Service
public class WmsAnnealOperateEventServiceImpl implements IWmsAnnealOperateEventService {
private final WmsAnnealOperateEventMapper baseMapper;
/**
* 查询退火操作事件
*/
@Override
public WmsAnnealOperateEventVo queryById(Long eventId){
return baseMapper.selectVoById(eventId);
}
/**
* 查询退火操作事件列表
*/
@Override
public TableDataInfo<WmsAnnealOperateEventVo> queryPageList(WmsAnnealOperateEventBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<WmsAnnealOperateEvent> lqw = buildQueryWrapper(bo);
Page<WmsAnnealOperateEventVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询退火操作事件列表
*/
@Override
public List<WmsAnnealOperateEventVo> queryList(WmsAnnealOperateEventBo bo) {
LambdaQueryWrapper<WmsAnnealOperateEvent> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<WmsAnnealOperateEvent> buildQueryWrapper(WmsAnnealOperateEventBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<WmsAnnealOperateEvent> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getAnnealFurnaceId() != null, WmsAnnealOperateEvent::getAnnealFurnaceId, bo.getAnnealFurnaceId());
lqw.eq(StringUtils.isNotBlank(bo.getOperateType()), WmsAnnealOperateEvent::getOperateType, bo.getOperateType());
lqw.eq(StringUtils.isNotBlank(bo.getOperateContent()), WmsAnnealOperateEvent::getOperateContent, bo.getOperateContent());
lqw.eq(bo.getCoilId() != null, WmsAnnealOperateEvent::getCoilId, bo.getCoilId());
return lqw;
}
/**
* 新增退火操作事件
*/
@Override
public Boolean insertByBo(WmsAnnealOperateEventBo bo) {
WmsAnnealOperateEvent add = BeanUtil.toBean(bo, WmsAnnealOperateEvent.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setEventId(add.getEventId());
}
return flag;
}
/**
* 修改退火操作事件
*/
@Override
public Boolean updateByBo(WmsAnnealOperateEventBo bo) {
WmsAnnealOperateEvent update = BeanUtil.toBean(bo, WmsAnnealOperateEvent.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(WmsAnnealOperateEvent entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除退火操作事件
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -128,8 +128,16 @@ public class WmsCoilPendingActionServiceImpl implements IWmsCoilPendingActionSer
qw.le(bo.getEndTime() != null, "wcpa.complete_time", bo.getEndTime());
// 根据更新人查询
qw.eq(StringUtils.isNotBlank(bo.getUpdateBy()), "wcpa.update_by", bo.getUpdateBy());
// 根据创建人筛选
qw.eq(StringUtils.isNotBlank(bo.getCreateBy()), "wcpa.create_by", bo.getCreateBy());
// 根据创建人筛选(支持逗号分隔的多个创建人)
if (StringUtils.isNotBlank(bo.getCreateBys())) {
List<String> createByList = Arrays.stream(bo.getCreateBys().split(","))
.filter(StringUtils::isNotBlank)
.map(String::trim)
.collect(Collectors.toList());
if (!createByList.isEmpty()) {
qw.in("wcpa.create_by", createByList);
}
}
// 加工后的钢卷ids
qw.like(StringUtils.isNotBlank(bo.getProcessedCoilIds()), "wcpa.processed_coil_ids", bo.getProcessedCoilIds());
//逻辑删除 - 支持查询已删除记录
@@ -286,8 +294,9 @@ public class WmsCoilPendingActionServiceImpl implements IWmsCoilPendingActionSer
action.setActionId(actionId);
action.setActionStatus(2); // 已完成
action.setCompleteTime(new Date());
action.setProcessedCoilIds(newCoilIds);
if(StringUtils.isNotBlank(newCoilIds) && !newCoilIds.equals("-")) {
action.setProcessedCoilIds(newCoilIds);
}
// 如果操作人为空,设置当前登录用户为操作人
if (oldAction.getOperatorId() == null || oldAction.getOperatorName() == null) {
try {

View File

@@ -7,15 +7,19 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.exception.ServiceException;
import com.klp.common.helper.LoginHelper;
import com.klp.common.utils.StringUtils;
import com.klp.domain.*;
import com.klp.domain.bo.WmsFurnacePlanBo;
import com.klp.domain.bo.WmsFurnacePlanCoilBo;
import com.klp.domain.bo.WmsMaterialCoilBo;
import com.klp.domain.vo.WmsFurnacePlanCoilVo;
import com.klp.domain.vo.WmsFurnacePlanVo;
import com.klp.mapper.*;
import com.klp.service.IWmsFurnacePlanService;
import com.klp.service.IWmsMaterialCoilService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -41,6 +45,7 @@ public class WmsFurnacePlanServiceImpl implements IWmsFurnacePlanService {
private final WmsMaterialCoilMapper materialCoilMapper;
private final WmsActualWarehouseMapper actualWarehouseMapper;
private final WmsWarehouseMapper warehouseMapper;
private final IWmsMaterialCoilService materialCoilService;
@Override
public WmsFurnacePlanVo queryById(Long planId) {
@@ -321,15 +326,51 @@ public class WmsFurnacePlanServiceImpl implements IWmsFurnacePlanService {
throw new ServiceException("请先分配逻辑库位");
}
java.util.Map<Long, Long> locationMap = locations.stream()
.collect(Collectors.toMap(com.klp.domain.bo.WmsFurnacePlanLocationItemBo::getCoilId,
.collect(java.util.stream.Collectors.toMap(com.klp.domain.bo.WmsFurnacePlanLocationItemBo::getCoilId,
com.klp.domain.bo.WmsFurnacePlanLocationItemBo::getWarehouseId, (a, b) -> a));
for (WmsFurnacePlanCoilVo coil : coils) {
Long targetLocation = locationMap.get(coil.getCoilId());
if (targetLocation == null) {
throw new ServiceException("钢卷" + coil.getEnterCoilNo() + "未分配库位");
}
occupyWarehouse(planId, coil.getCoilId(), targetLocation);
WmsMaterialCoil oldCoil = materialCoilMapper.selectById(coil.getCoilId());
if (oldCoil == null) {
throw new ServiceException("钢卷不存在: " + coil.getCoilId());
}
WmsMaterialCoilBo updateBo = new WmsMaterialCoilBo();
// 复制老钢卷的所有信息
BeanUtils.copyProperties(oldCoil, updateBo);
// 只覆盖需要修改的字段
updateBo.setCoilId(coil.getCoilId());
updateBo.setWarehouseId(targetLocation);
updateBo.setActualWarehouseId(-1L);
updateBo.setCreateTime(new Date());
updateBo.setUpdateTime(new Date());
updateBo.setExclusiveStatus(0);
updateBo.setCreateBy(LoginHelper.getUsername());
updateBo.setUpdateBy(LoginHelper.getUsername());
updateBo.setNextWarehouseId(null);
updateBo.setStatus(0);
updateBo.setExportBy(null);
updateBo.setExportTime(null);
materialCoilService.updateByBo(updateBo, "annealing");
WmsFurnacePlanCoil wmsFurnacePlanCoil = planCoilMapper.selectOne(Wrappers.<WmsFurnacePlanCoil>lambdaQuery()
.eq(WmsFurnacePlanCoil::getPlanId, planId)
.eq(WmsFurnacePlanCoil::getCoilId, coil.getCoilId())
.eq(WmsFurnacePlanCoil::getDelFlag, 0));
if (wmsFurnacePlanCoil != null && wmsFurnacePlanCoil.getPlanCoilId() != null) {
planCoilMapper.update(null, Wrappers.<WmsFurnacePlanCoil>lambdaUpdate()
.eq(WmsFurnacePlanCoil::getPlanCoilId, wmsFurnacePlanCoil.getPlanCoilId())
.set(WmsFurnacePlanCoil::getLogicWarehouseId, targetLocation));
}
}
Date now = new Date();
WmsFurnacePlan update = new WmsFurnacePlan();
update.setPlanId(planId);
@@ -358,34 +399,6 @@ public class WmsFurnacePlanServiceImpl implements IWmsFurnacePlanService {
.set(WmsMaterialCoil::getExclusiveStatus, 2));
}
private void occupyWarehouse(Long planId, Long coilId, Long warehouseId) {
if (warehouseId == null) {
throw new ServiceException("逻辑库位不能为空");
}
WmsWarehouse warehouse = warehouseMapper.selectById(warehouseId);
if (warehouse == null || warehouse.getDelFlag() != null && warehouse.getDelFlag() == 1) {
throw new ServiceException("逻辑库位不存在");
}
// wmsfurnace_plan_coil也要插入这个去向的逻辑库区
WmsFurnacePlanCoil wmsFurnacePlanCoil = planCoilMapper.selectOne(Wrappers.<WmsFurnacePlanCoil>lambdaQuery()
.eq(WmsFurnacePlanCoil::getPlanId, planId)
.eq(WmsFurnacePlanCoil::getCoilId, coilId)
//逻辑删除
.eq(WmsFurnacePlanCoil::getDelFlag, 0));
if (wmsFurnacePlanCoil != null && wmsFurnacePlanCoil.getPlanCoilId() != null) {
planCoilMapper.update(null, Wrappers.<WmsFurnacePlanCoil>lambdaUpdate()
.eq(WmsFurnacePlanCoil::getPlanCoilId, wmsFurnacePlanCoil.getPlanCoilId())
.set(WmsFurnacePlanCoil::getLogicWarehouseId, warehouseId));
}
WmsMaterialCoil updateCoil = new WmsMaterialCoil();
updateCoil.setCoilId(coilId);
updateCoil.setWarehouseId(warehouseId);
updateCoil.setExclusiveStatus(0);
materialCoilMapper.updateById(updateCoil);
}
private List<Long> parseCoilIds(WmsFurnacePlanCoilBo bo) {
List<Long> coilIds = new ArrayList<>();

View File

@@ -342,6 +342,16 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
return TableDataInfo.build(bindResult);
}
/**
* 统计筛选条件下的全量汇总数据高性能只查sum/count
* 独立的统计接口,不影响分页查询
*/
@Override
public Map<String, BigDecimal> getStatistics(WmsMaterialCoilBo bo) {
QueryWrapper<WmsMaterialCoil> qw = buildQueryWrapperPlus(bo);
return selectMaterialCoilStatistics(qw);
}
private Page<WmsMaterialCoilVo> queryMaterialCoilPage(WmsMaterialCoilBo bo, PageQuery pageQuery) {
QueryWrapper<WmsMaterialCoil> qw = buildQueryWrapperPlus(bo);
Page<WmsMaterialCoilVo> result;
@@ -380,6 +390,32 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
}
}
/**
* 统计筛选条件下的全量汇总数据高性能只查sum/count
*/
private Map<String, BigDecimal> selectMaterialCoilStatistics(QueryWrapper<WmsMaterialCoil> qw) {
Map<String, BigDecimal> result = new HashMap<>();
result.put("total_gross_weight", BigDecimal.ZERO);
result.put("total_net_weight", BigDecimal.ZERO);
result.put("total_count", BigDecimal.ZERO);
try {
Map<String, Object> stats = baseMapper.selectStatistics(qw);
if (stats != null) {
Object grossWeight = stats.get("total_gross_weight");
Object netWeight = stats.get("total_net_weight");
Object count = stats.get("total_count");
result.put("total_count", count != null ? new BigDecimal(count.toString()) : BigDecimal.ZERO);
result.put("total_gross_weight", grossWeight != null ? new BigDecimal(grossWeight.toString()) : BigDecimal.ZERO);
result.put("total_net_weight", netWeight != null ? new BigDecimal(netWeight.toString()) : BigDecimal.ZERO);
}
} catch (Exception e) {
log.warn("统计查询失败: {}", e.getMessage());
}
return result;
}
private void fillBindInfoForPage(List<WmsMaterialCoilBindVo> records) {
// 绑定信息仅用于专用接口,避免污染通用分页结构
try {
@@ -733,7 +769,16 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
});
});
}
// 根据创建人筛选(支持逗号分隔的多个创建人)
if (StringUtils.isNotBlank(bo.getCreateBys())) {
List<String> createByList = Arrays.stream(bo.getCreateBys().split(","))
.filter(StringUtils::isNotBlank)
.map(String::trim)
.collect(Collectors.toList());
if (!createByList.isEmpty()) {
qw.in("mc.create_by", createByList);
}
}
//根据异常数量筛选(大于等于指定值)
if (bo.getMinAbnormalCount() != null) {
qw.apply("COALESCE(ca.abnormal_count, 0) >= {0}", bo.getMinAbnormalCount());
@@ -1150,7 +1195,7 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
*/
@Override
@Transactional(rollbackFor = Exception.class)
public String updateByBo(WmsMaterialCoilBo bo) {
public String updateByBo(WmsMaterialCoilBo bo, String qrcodeStepType) {
// 判断是否批量更新
if (bo.getNewCoils() != null && !bo.getNewCoils().isEmpty()) {
// 批量更新逻辑(分卷/合卷)
@@ -1160,7 +1205,7 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
if (bo.getCoilId() == null) {
throw new RuntimeException("钢卷ID不能为空");
}
return updateBySingle(bo); // 返回新钢卷ID字符串
return updateBySingle(bo, qrcodeStepType); // 返回新钢卷ID字符串
}
}
@@ -1277,11 +1322,15 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
/**
* 单个更新
* @param bo 更新数据
* @param qrcodeStepType 二维码步骤类型null/空-默认"更新", "annealing"-退火
* @return 新钢卷ID字符串
*/
private String updateBySingle(WmsMaterialCoilBo bo) {
// 检查独占状态
validateCoilOperationPermission(bo.getCoilId(), "单个更新");
private String updateBySingle(WmsMaterialCoilBo bo, String qrcodeStepType) {
if (StringUtils.isBlank(qrcodeStepType)){
// 检查独占状态
validateCoilOperationPermission(bo.getCoilId(), "单个更新");
}
// 查询原钢卷
WmsMaterialCoil oldCoil = baseMapper.selectById(bo.getCoilId());
@@ -1307,7 +1356,8 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
// 1. 将原钢卷标记为历史数据dataType = 0
LambdaUpdateWrapper<WmsMaterialCoil> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(WmsMaterialCoil::getCoilId, oldCoil.getCoilId())
.set(WmsMaterialCoil::getDataType, 0); // 设置为历史数据
.set(WmsMaterialCoil::getDataType, 0) // 设置为历史数据
.set(WmsMaterialCoil::getExclusiveStatus, 0);
baseMapper.update(null, updateWrapper);
// 2. 创建新记录
@@ -1343,7 +1393,11 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
// 3. 更新二维码内容添加更新步骤并更新current_coil_id
if (oldCoil.getQrcodeRecordId() != null) {
updateQrcodeContentForNormalUpdate(oldCoil, bo, newCoil.getCoilId());
if (StringUtils.isNotBlank(qrcodeStepType) && "annealing".equals(qrcodeStepType)) {
updateQrcodeContentForCustomStep(oldCoil, bo, newCoil.getCoilId(), "退火", "退火操作");
} else {
updateQrcodeContentForNormalUpdate(oldCoil, bo, newCoil.getCoilId());
}
}
// 只有当新的库区ID不为空时更新库区状态
@@ -2112,6 +2166,73 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
}
}
/**
* 更新二维码内容(自定义步骤类型)
* 用于退火完成等场景action和operation可以自定义
* @param oldCoil 旧钢卷记录
* @param bo 更新数据
* @param newCoilId 新钢卷ID
* @param action 自定义action如"更新"、"退火"
* @param operation 自定义operation如"信息更新"、"退火操作"
*/
private void updateQrcodeContentForCustomStep(WmsMaterialCoil oldCoil, WmsMaterialCoilBo bo, Long newCoilId, String action, String operation) {
try {
WmsGenerateRecordVo oldRecord = generateRecordService.queryById(oldCoil.getQrcodeRecordId());
if (oldRecord == null) {
throw new RuntimeException("二维码记录不存在");
}
ObjectMapper objectMapper = new ObjectMapper();
@SuppressWarnings("unchecked")
Map<String, Object> contentMap = objectMapper.readValue(oldRecord.getContent(), Map.class);
@SuppressWarnings("unchecked")
List<Map<String, Object>> steps = (List<Map<String, Object>>) contentMap.get("steps");
if (steps == null) {
steps = new ArrayList<>();
}
Map<String, Object> newStep = new HashMap<>();
newStep.put("step", steps.size() + 1);
newStep.put("action", action);
newStep.put("operation", operation);
newStep.put("old_current_coil_no", oldCoil.getCurrentCoilNo());
newStep.put("new_current_coil_no", bo.getCurrentCoilNo() != null ? bo.getCurrentCoilNo() : oldCoil.getCurrentCoilNo());
newStep.put("old_coil_id", String.valueOf(oldCoil.getCoilId()));
newStep.put("new_coil_id", String.valueOf(newCoilId));
newStep.put("operator", LoginHelper.getUsername());
List<String> changedFields = new ArrayList<>();
if (bo.getWarehouseId() != null && !bo.getWarehouseId().equals(oldCoil.getWarehouseId())) {
changedFields.add("逻辑库区ID: " + oldCoil.getWarehouseId() + "" + bo.getWarehouseId());
}
if (bo.getActualWarehouseId() != null && !bo.getActualWarehouseId().equals(oldCoil.getActualWarehouseId())) {
changedFields.add("真实库区ID: " + oldCoil.getActualWarehouseId() + "" + bo.getActualWarehouseId());
}
newStep.put("changed_fields", String.join("; ", changedFields));
newStep.put("update_time", new java.util.Date());
steps.add(newStep);
contentMap.put("steps", steps);
if (bo.getCurrentCoilNo() != null) {
contentMap.put("current_coil_no", bo.getCurrentCoilNo());
}
if (newCoilId != null) {
contentMap.put("current_coil_id", String.valueOf(newCoilId));
}
String newContentJson = objectMapper.writeValueAsString(contentMap);
WmsGenerateRecordBo updateBo = new WmsGenerateRecordBo();
updateBo.setRecordId(oldCoil.getQrcodeRecordId());
updateBo.setContent(newContentJson);
generateRecordService.updateByBo(updateBo);
} catch (Exception e) {
throw new RuntimeException("更新二维码失败: " + e.getMessage());
}
}
/**
* 保存前的数据校验
@@ -3429,7 +3550,7 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
result.put("operationType", "SPLIT");
return result;
}
// 这里不写新是因为还有退货操作,但是也和新一样可以回滚所以直接找new_coil_id即可
// 这里不写新是因为还有退货操作和退火操作,但是也和新一样可以回滚所以直接找new_coil_id即可
// 如果找到普通更新操作
Object newCoilIdObj = step.get("new_coil_id");
if (newCoilIdObj != null && newCoilIdObj.toString().equals(currentCoilId.toString())) {

View File

@@ -54,9 +54,14 @@ public class WmsWarehouseServiceImpl implements IWmsWarehouseService {
lqw.like(StringUtils.isNotBlank(bo.getWarehouseName()), WmsWarehouse::getWarehouseName, bo.getWarehouseName());
lqw.eq(bo.getWarehouseType() != null, WmsWarehouse::getWarehouseType, bo.getWarehouseType());
lqw.eq(bo.getSortNo() != null, WmsWarehouse::getSortNo, bo.getSortNo());
lqw.eq(bo.getUseCount() != null, WmsWarehouse::getUseCount, bo.getUseCount());
lqw.eq(bo.getIsEnabled() != null, WmsWarehouse::getIsEnabled, bo.getIsEnabled());
// 新增排序SortNo升序
lqw.orderByAsc(WmsWarehouse::getSortNo);
// 排序逻辑orderByUseCount为true时按useCount降序否则按sortNo升序
if (Boolean.TRUE.equals(bo.getOrderByUseCount())) {
lqw.orderByDesc(WmsWarehouse::getUseCount).orderByAsc(WmsWarehouse::getSortNo);
} else {
lqw.orderByAsc(WmsWarehouse::getSortNo);
}
return lqw;
}

View File

@@ -0,0 +1,61 @@
package com.klp.task;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.klp.domain.WmsWarehouse;
import com.klp.mapper.WmsMaterialCoilMapper;
import com.klp.mapper.WmsWarehouseMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@RequiredArgsConstructor
@Component
public class WarehouseUseCountTask {
private final WmsMaterialCoilMapper materialCoilMapper;
private final WmsWarehouseMapper warehouseMapper;
// @Scheduled(cron = "0 0 1 * * ?")
@Transactional(rollbackFor = Exception.class)
public void calculateWarehouseUseCount() {
log.info("[仓库使用次数定时任务] 开始计算仓库使用次数");
LambdaQueryWrapper<WmsWarehouse> wrapper = new LambdaQueryWrapper<>();
wrapper.select(WmsWarehouse::getWarehouseId);
List<WmsWarehouse> warehouses = warehouseMapper.selectList(wrapper);
if (warehouses.isEmpty()) {
log.info("[仓库使用次数定时任务] 未找到仓库记录");
return;
}
List<Long> warehouseIds = warehouses.stream()
.map(WmsWarehouse::getWarehouseId)
.collect(Collectors.toList());
List<Map<String, Object>> countList = materialCoilMapper.selectWarehouseIdCount(warehouseIds);
Map<Long, Long> countMap = new HashMap<>();
for (Map<String, Object> item : countList) {
Long wid = ((Number) item.get("warehouse_id")).longValue();
Long count = ((Number) item.get("coil_count")).longValue();
countMap.put(wid, count);
}
for (WmsWarehouse warehouse : warehouses) {
Long count = countMap.getOrDefault(warehouse.getWarehouseId(), 0L);
warehouse.setUseCount(count.intValue());
warehouseMapper.updateById(warehouse);
}
log.info("[仓库使用次数定时任务] 完成,共更新 {} 个仓库", warehouses.size());
}
}

View File

@@ -0,0 +1,22 @@
<?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.WmsAnnealOperateEventMapper">
<resultMap type="com.klp.domain.WmsAnnealOperateEvent" id="WmsAnnealOperateEventResult">
<result property="eventId" column="event_id"/>
<result property="annealFurnaceId" column="anneal_furnace_id"/>
<result property="operateType" column="operate_type"/>
<result property="operateContent" column="operate_content"/>
<result property="coilId" column="coil_id"/>
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
<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>

View File

@@ -902,5 +902,39 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
)
</select>
<!-- 统计筛选条件下的全量汇总数据高性能只查sum/count -->
<select id="selectStatistics" resultType="java.util.Map">
SELECT
IFNULL(SUM(mc.gross_weight), 0) AS total_gross_weight,
IFNULL(SUM(mc.net_weight), 0) AS total_net_weight,
COUNT(mc.coil_id) AS total_count
FROM wms_material_coil mc
LEFT JOIN wms_warehouse w ON mc.warehouse_id = w.warehouse_id
LEFT JOIN wms_warehouse nw ON mc.next_warehouse_id = nw.warehouse_id
LEFT JOIN wms_actual_warehouse aw ON mc.actual_warehouse_id = aw.actual_warehouse_id
LEFT JOIN sys_user su ON mc.sale_id = su.user_id
LEFT JOIN wms_raw_material rm ON mc.item_type = 'raw_material' AND mc.item_id = rm.raw_material_id
LEFT JOIN wms_product p ON mc.item_type = 'product' AND mc.item_id = p.product_id
LEFT JOIN (
SELECT coil_id, COUNT(*) AS abnormal_count
FROM wms_coil_abnormal
WHERE del_flag = 0
GROUP BY coil_id
) ca ON mc.coil_id = ca.coil_id
${ew.customSqlSegment}
</select>
<!-- 统计仓库使用次数按warehouse_id出现次数排序 -->
<select id="selectWarehouseIdCount" resultType="java.util.Map">
SELECT warehouse_id, COUNT(*) AS coil_count
FROM wms_material_coil
WHERE del_flag = 0
AND warehouse_id IN
<foreach collection="list" item="wid" open="(" separator="," close=")">
#{wid}
</foreach>
GROUP BY warehouse_id
</select>
</mapper>

View File

@@ -11,6 +11,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="warehouseName" column="warehouse_name"/>
<result property="warehouseType" column="warehouse_type"/>
<result property="sortNo" column="sort_no"/>
<result property="useCount" column="use_count"/>
<result property="isEnabled" column="is_enabled"/>
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>