Compare commits

...

215 Commits

Author SHA1 Message Date
cdcf5e2428 加入规程管理sql 2026-04-19 14:29:57 +08:00
deb684ce27 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-19 14:28:02 +08:00
3f300e05e9 加入规程管理sql 2026-04-19 14:27:05 +08:00
af002b84d3 feat(合同管理): 新增钢卷与合同关联功能
- 添加钢卷与合同关联的API接口
- 在合卷、分条、打字等操作中增加合同选择组件
- 创建合同选择组件ContractSelect
- 在合同详情页新增生产成果展示页签
- 实现合同列表的本地存储功能
2026-04-18 16:18:22 +08:00
143764f7f8 feat(钢卷调拨): 新增调拨类型列和改判功能
添加调拨类型列显示和钢卷改判功能,包括改判弹窗和重贴标签操作
2026-04-18 15:56:28 +08:00
0822ca7cc8 refactor(wms): 修改钢卷合卷功能返回结果卷
- 将IWmsMaterialCoilService.mergeCoils方法返回值从Boolean改为Long
- 更新WmsMaterialCoilController.mergeCoils方法以返回合卷后的新钢卷ID
- 修改WmsMaterialCoilServiceImpl.mergeCoils实现以返回合并后的钢卷ID
- 移除原有的布尔返回值,改为返回实际的业务数据ID
- 保持事务处理和业务逻辑完整性
2026-04-18 14:53:42 +08:00
5b452bad31 fix(order): 修复订单详情中钢卷信息关联错误
- 将合同ID替换为订单ID进行钢卷信息映射
- 确保钢卷列表正确关联到对应的订单记录
- 修复了因键值不匹配导致的钢卷信息丢失问题
2026-04-18 14:48:58 +08:00
4f259c5aba Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-18 14:28:55 +08:00
34dd8004c4 fix(order): 解决计划日期时间设置问题
- 将日期设置为当天的开始时间 00:00:00
- 使用Calendar类精确设置小时、分钟、秒和毫秒为零值
- 确保计划日期查询使用正确的日期范围
- 避免因时间戳差异导致的数据查询不准确问题
2026-04-18 14:28:44 +08:00
254dada485 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-04-18 14:24:22 +08:00
ee2bb280b6 refactor(mapper): 更新 MyBatis 映射文件中的对应 SQL 查询 ID
- 将 ApsPlanSheetMapper 中的 selectList 方法重命名为 selectListByReq
- 更新 MyBatis 映射文件中的对应 SQL 查询 ID
- 修改服务实现类中的方法调用以匹配新方法名
2026-04-18 14:21:42 +08:00
96082b9124 feat(wms): 添加左侧逻辑库位查询功能并优化钢卷管理界面
在钢卷管理相关页面添加左侧逻辑库位树形查询功能,方便用户快速筛选库位
移除部分冗余代码和注释,优化页面布局和交互体验
添加钢卷统计数据显示功能,提升数据可视化
2026-04-18 13:36:24 +08:00
ddb1beb629 feat(wms): 添加钢卷物料订单关联信息查询功能
- 新增 queryPageListWithOrderRel 方法支持查询钢卷关联订单列表
- 实现批量查询避免 N+1 问题,提升查询性能
- 添加 listWithOrderRel 控制器接口供前端调用
- 集成 wms_coil_contract_rel 中间表与 crm_order 联查
- 优化查询逻辑,支持按需加载订单关联信息
- 完善异常处理和日志记录机制
2026-04-18 13:01:28 +08:00
67cf5aa7cb feat(wms): 添加钢卷关联订单信息查询功能
- 在WmsCoilContractRelMapper中新增selectOrdersByCoilId和selectOrdersByCoilIds方法
- 在WmsCoilContractRelMapper.xml中实现钢卷与订单关联查询的SQL映射
- 扩展WmsCoilContractRelVo类添加订单相关字段和@JsonFormat注解
- 在WmsMaterialCoilServiceImpl中注入coilContractRelMapper并实现填充订单信息逻辑
- 在WmsMaterialCoilVo中添加orderList字段存储关联订单列表
- 实现根据钢卷ID查询完整订单信息的JOIN查询功能
2026-04-18 11:49:10 +08:00
e1cc0fda34 feat(crm): 添加每日订单查询功能
- 在 ApsPlanDetailBo 中新增 planSheetIds 字段用于批量查询
- 实现 IApsPlanDetailService 的 queryListByPlanSheetIds 方法
- 添加 CrmOrderService 的 queryByIds 批量查询接口
- 在 CrmOrderController 中新增 /daily 接口查询当日订单
- 集成 APS 排产计划数据获取当日关联的 CRM 订单
- 添加 klp-aps 模块依赖支持跨模块数据查询
2026-04-18 11:11:14 +08:00
4e5e1bbca1 feat(crm): 订单查询功能新增关联钢卷信息展示
- 集成WMS钢卷合同关联查询服务
- 实现订单与钢卷批量关联查询逻辑
- 添加钢卷详细信息映射和组装功能
- 在CrmOrderVo中新增coilList字段存储钢卷列表
- 优化查询性能,避免N+1问题
- 支持按合同ID分组获取关联钢卷数据
2026-04-18 11:03:35 +08:00
2e363f9ad8 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-18 10:23:57 +08:00
f158830abf feat(wms): 添加钢卷与合同关联关系管理功能
- 创建 WmsCoilContractRel 实体类定义钢卷与合同关联关系数据结构
- 实现 IWmsCoilContractRelService 接口提供基础CRUD操作方法
- 开发 WmsCoilContractRelServiceImpl 业务逻辑实现类
- 添加 WmsCoilContractRelController 控制器支持RESTful API接口
- 设计 WmsCoilContractRelMapper 数据访问接口及XML映射文件
- 创建 WmsCoilContractRelBo 业务对象和 WmsCoilContractRelVo 视图对象
- 集成分页查询、新增、修改、删除和导出功能
- 添加数据验证和重复提交防护机制
2026-04-18 10:23:48 +08:00
843512ab7e Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-04-18 10:23:27 +08:00
dd27069b4c feat(KLPTable): 增强浮层组件功能并优化表格显示
- 为浮层组件添加列数配置和排除列功能
- 优化浮层位置计算逻辑,防止超出视窗边界
- 调整表格列显示,移除不必要列并添加净重列
- 更新浮层样式,支持网格布局和响应式显示
- 扩展浮层配置项,支持更多自定义选项
2026-04-18 10:23:24 +08:00
b95bd5b93d Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-18 10:18:02 +08:00
4d588985e8 feat(WmsMaterialCoil): 添加调拨类型非空筛选功能
- 在WmsMaterialCoilBo中新增hasTransferType字段用于标识是否查询调拨类型不为空的钢卷
- 在WmsMaterialCoilServiceImpl中实现调拨类型非空筛选逻辑
- 当hasTransferType为true时查询调拨类型不为空且不为字符串的钢卷记录
2026-04-18 10:17:22 +08:00
3ad3fd2fee feat(PlanDetailForm): 添加订单明细选择功能以快速录入成品信息
在成品信息组中添加选择订单明细按钮,点击可打开对话框选择订单明细并自动填充表单字段。移除未使用的订单类型列并优化附件查看按钮的样式。
2026-04-17 17:02:12 +08:00
79ee9d572d feat(contract): 替换产品内容组件为订单详情组件并优化表单字段
重构合同预览和订单详情展示,使用新的OrderDetail组件替代原有的ProductContent组件
调整订单详情表单字段,增加宽度、厚度等必要字段,移除不必要字段
优化表单验证规则和显示逻辑
2026-04-17 15:11:09 +08:00
c9742b08cf fix(wms): 修复规格分割可能导致的错误并增加分页大小
处理规格分割时可能出现的空值问题,使用可选链操作符和默认值
同时增加多个报表页面的分页大小限制
2026-04-17 15:10:21 +08:00
6bd5d2ded3 feat(CrmOrderItem): 添加订单项产品规格字段
- 在CrmOrderItem实体类中新增表面处理、切边要求、包装要求、宽度、厚度、用途字段
- 在CrmOrderItemBo业务对象中同步添加对应字段定义
- 在CrmOrderItemVo视图对象中添加Excel导出注解配置
- 更新MyBatis映射文件中的结果映射和插入字段列表
- 在查询条件构建器中添加新字段的查询支持
2026-04-17 14:16:46 +08:00
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
05f0933514 feat(wms): 添加配卷时间和实际发货时间字段支持
- 在WmsDeliveryWaybillDetailVo中新增exportTime字段用于实际发货时间
- 将deliveryTime字段的Excel导出标签从发货时间改为配卷时间
- 在数据库映射文件中添加exportTime字段的映射关系
- 在查询语句中加入export_time字段以支持实际发货时间数据获取
2026-04-15 15:21:17 +08:00
ec5da2a7ca fix(WmsMaterialCoilController): 修改编辑接口返回类型
- 将返回类型从 R<Void> 更改为 R<String>
- 修改返回方式从 toAjax() 改为 R.ok()
- 确保接口返回操作结果字符串而非空值
2026-04-15 14:33:09 +08:00
7d6957165d Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-15 14:31:36 +08:00
31648431c8 feat(wms): 完善钢卷操作完成接口功能
- 在completeAction方法中添加newCoilIds参数支持
- 修改updateByBo方法返回值为String类型,支持返回新钢卷ID
- 添加分卷时返回逗号分隔的ID字符串,合卷时返回单个ID的功能
- 在操作完成时记录processedCoilIds信息
- 优化异常处理和返回值验证逻辑
2026-04-15 14:31:27 +08:00
砂糖
36ff376c55 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-04-15 14:07:49 +08:00
砂糖
f68167b102 feat(报表): 添加月视图折线图并优化分条线显示逻辑
添加月视图日数据趋势折线图展示产出和消耗数据
优化分条信息统计组件仅在分条线时显示
在日视图中添加昨日数据对比显示
重构日期选择逻辑支持多种视图模式
2026-04-15 14:07:42 +08:00
671a7e129f Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-15 14:07:07 +08:00
84a0cb43ee fix(export): 修正配卷时间字段导出标题
- 将发货时间字段标题更正为配卷时间
2026-04-15 14:06:56 +08:00
砂糖
d15f57ae6d feat(wms): 添加修复工序的样式和分条选项
为酸轧、镀锌、脱脂、拉矫、双机架和镀铬修复工序添加渐变样式标识
在分条功能中增加修复工序的原料库和成品库选项
2026-04-15 10:54:26 +08:00
砂糖
b32f826488 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-04-14 16:08:37 +08:00
砂糖
a99126a9a3 feat(CoilSelector): 添加物料类型选择并优化相关字段显示逻辑
添加物料类型选择下拉框,并根据选择的类型动态显示相关字段
将selectType默认值改为通过props传入的defaultType
优化查询逻辑,确保itemType与selectType保持一致
2026-04-14 16:08:33 +08:00
6e5b9fc962 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-14 15:45:26 +08:00
c9a93fe942 feat(crm): 添加订单定金相关字段支持
- 在CrmOrder实体类中新增unitPriceRemark、depositPayable、depositPaid、depositRatio字段
- 在CrmOrderBo业务对象中同步添加对应字段以支持查询条件
- 更新CrmOrderMapper.xml映射文件中的结果集和SQL查询语句
- 在CrmOrderServiceImpl服务实现中添加字段的查询条件处理逻辑
- 在CrmOrderVo视图对象中添加Excel导出注解配置
- 实现定金相关的业务查询功能包括应付定金、已付定金、定金比例等字段的检索
2026-04-14 15:45:15 +08:00
砂糖
5f5e5cacb4 feat(订单详情): 在钢卷选择器中添加订单详情显示功能
添加订单ID参数传递至钢卷选择器组件
在钢卷选择器中新增显示订单详情的复选框和面板
移除OrderDetail组件中未使用的API导入
2026-04-14 15:38:44 +08:00
砂糖
263c2b5f37 feat(报餐记录): 修改默认截止时间并支持动态配置
从系统配置获取报餐截止时间,默认值从12:00改为16:00
2026-04-14 11:13:56 +08:00
910ec2b22f fix(wms): 修复产品服务中更新时间字段设置问题
- 在WmsProductServiceImpl中添加了updateTime字段的正确设置
- 确保coils记录在更新时保持正确的更新时间戳
- 防止因时间字段未正确设置导致的数据同步问题
2026-04-14 10:14:52 +08:00
a62ef2d0b0 feat(wms): 添加物料卷数据过滤条件
- 添加数据类型过滤条件,只查询类型为1的数据
- 添加状态过滤条件,只查询状态为0的正常数据
- 优化物料卷查询逻辑,提高数据准确性
2026-04-14 10:10:54 +08:00
31d44c19ca Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-14 10:07:08 +08:00
fea3c78c4f feat(product): 添加批量更新钢卷itemId功能,由于只是一次性接口暂时不考虑速度
- 在IWmsProductService接口中添加batchUpdateCoilItemId方法定义
- 在WmsProductController中添加batchUpdateCoilItem REST端点
- 在WmsProductServiceImpl中实现批量更新逻辑
- 添加对WmsMaterialCoil和WmsRawMaterial实体的操作支持
- 实现根据逻辑库区ID查询并按itemType分类处理的功能
- 添加事务管理和异常回滚机制
- 返回产品和原料的数量统计结果
2026-04-14 10:06:59 +08:00
砂糖
8de4042bdf fix: 将库区显示改为规格显示并添加实际库区字段
在多个组件中将“库区”标签改为“规格”标签,并显示对应的规格数据
在CoilCard组件中添加实际库区字段的显示
2026-04-14 10:03:31 +08:00
砂糖
54bea01416 refactor(contract): 统一合同编号字段名从contractNo改为contractCode
修改多个组件中合同编号字段名以保持一致性,移除未使用的props和清理冗余代码
2026-04-14 10:03:16 +08:00
砂糖
9f3d402174 refactor(crm): 重构合同模块为订单模块并优化相关功能
重构合同模块为订单模块,包括以下主要变更:
1. 将合同编号字段从contractNo统一改为contractCode
2. 在CrmOrderBo中添加日期格式化注解
3. 重构ContractTabs组件为订单详情页
4. 添加销售员字段和相关选择器
5. 优化订单列表查询条件和展示
6. 调整订单附件管理功能
2026-04-13 17:48:19 +08:00
c3d6d7cece feat(crm): 添加订单合同详情字段映射和查询功能
- 在CrmOrderMapper.xml中新增合同名称、供应商、客户等相关字段映射
- 扩展SQL查询语句以支持合同详细信息的检索
- 在服务层实现中增加对新字段的搜索条件支持
- 添加合同签署时间、地点、内容等过滤条件的查询逻辑
- 实现供应商和客户联系信息的条件查询功能
- 集成技术附件、商务附件和生产进度的搜索过滤器
2026-04-13 16:50:18 +08:00
砂糖
37dc213605 feat(报表): 添加分条线统计组件并扩展合同字段
添加分条线专用的统计组件SplitSummary,用于展示分条处理的产出与消耗对比数据
在多个报表模板中集成该组件并添加钢卷高亮功能
扩展CrmOrder相关类的合同信息字段
2026-04-13 16:23:40 +08:00
砂糖
5ee730bffa feat(报表): 添加钢卷表格行高亮功能以标记共用卷
在分条线报表中,产出钢卷和投入钢卷可能存在共用卷的情况。添加高亮功能以便直观区分这些共用卷:
1. 在day.vue中计算共用卷ID列表
2. 在coilTable组件中实现行高亮逻辑和样式
2026-04-13 14:37:23 +08:00
砂糖
116d79e7c2 feat(wms): 新增调拨记录追溯功能并优化调拨表格
- 在调拨表格中添加生效状态列,显示已生效/未生效标签
- 新增调拨记录追溯页面,支持通过卷号查询调拨历史
- 实现常规筛选和特殊追溯两种查询方式
- 优化表格操作列显示逻辑,增加权限控制
2026-04-13 13:00:25 +08:00
砂糖
4c373e6af5 fix(wms): 修改标签中长度字段显示为钢卷长度并使用实际长度值
更新了两个标签渲染组件,将"参考长度"改为更准确的"钢卷长度"描述,并统一使用actualLength字段替代length字段显示实际长度值
2026-04-13 11:45:17 +08:00
砂糖
4beaf79fd6 feat(合同/客户): 添加发货单据展示功能
在合同和客户详情页新增发货单据标签页,展示wmsDeliveryWaybills数据
移除CustomerOrder中未使用的getSummary方法和相关代码
2026-04-11 16:24:04 +08:00
b4dc0ed9e4 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-11 16:03:26 +08:00
5efdcf99dc feat(order): 添加订单物流运单信息查询功能
- 在CrmContractOrderFinanceVo中新增wmsDeliveryWaybills字段用于存储物流运单信息
- 添加WmsDeliveryWaybillVo依赖引入
- 在CrmOrderItemServiceImpl的两个查询方法中增加物流运单数据查询逻辑
- 使用LambdaQueryWrapper按订单ID批量查询关联的物流运单信息
- 将查询到的物流运单列表设置到返回结果中
2026-04-11 16:03:16 +08:00
砂糖
3020a4244d feat(wms): 新增报表导出文件管理功能
新增报表导出文件管理模块,包含后端接口和前端页面
在各类报表页面添加保存报表功能
优化CoilSelector和CoilCard组件显示
调整分页大小和表格高度
统一各产线报表配置
修复文件预览组件高度问题
2026-04-11 15:36:50 +08:00
848ad2c3cd Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-10 15:07:38 +08:00
57b07885e3 refactor(wms): 优化调拨订单和钢卷信息更新逻辑
- 使用LambdaUpdateWrapper替代直接对象更新,支持显式设置NULL值
- 在审批通过时设置调拨状态为1
- 修复钢卷信息批量更新逻辑,使用updateBatchById提高性能
- 添加调拨后物料ID和类型校验,确保数据一致性
- 批量更新调拨明细的isTransferred字段标记为已调拨
- 过滤条件从调拨前值改为调拨后值进行验证
- 添加空值检查避免无效更新操作
2026-04-10 15:07:29 +08:00
砂糖
466ac13742 feat(钢卷卡片): 新增CoilCard组件并重构相关页面
将钢卷卡片相关逻辑抽离为独立组件CoilCard,并在correct.vue、correntAll.vue和do.vue页面中使用该组件替换原有卡片代码
在base.vue中添加发货状态筛选功能
在split.vue中新增拉矫修复工序的特殊分割逻辑
2026-04-10 15:00:20 +08:00
砂糖
8e2069cecf fix(wms): 修复调拨单二次调整按钮显示及仓库选择保存问题
修复调拨单列表中二次调整按钮的显示条件,从原审批状态为2或3改为仅状态为3时显示
移除执行全部按钮的注释状态
为仓库选择添加change事件自动保存功能
调整重新提交审批的提示信息和成功消息
2026-04-10 13:27:45 +08:00
92441e569e fix(wms): 修正转库订单审批状态判断逻辑
- 将审批通过状态从 1 修改为 2
- 确保只有在正确审批状态下才批量更新钢卷信息
2026-04-10 13:19:35 +08:00
509c41a4d4 feat(wms): 实现调拨单审批功能并完善钢卷信息批量更新
- 在WmsTransferOrderServiceImpl中添加钢卷、原料、产品的相关依赖注入
- 为approve方法添加事务注解确保数据一致性
- 实现调拨单审批状态更新功能
- 新增batchUpdateCoilsOnApprove方法处理审批通过后的钢卷信息批量更新
- 添加详细的钢卷信息校验和分组处理逻辑
- 实现按物料类型分组验证itemId存在的功能
- 添加批量查询和更新钢卷信息的完整流程
2026-04-10 13:13:58 +08:00
砂糖
ec0fa3966a fix(wms): 移除重新提交按钮并更新二次调整逻辑
移除批次调拨页面中的重新提交按钮,改为使用updateTransferOrder API更新调拨单状态
2026-04-10 11:43:47 +08:00
砂糖
9b52621df1 feat: 增加调拨单审批功能及界面优化
fix(调拨单): 修正审批状态校验逻辑
feat(调拨单): 添加审批API接口
refactor(调拨单明细): 重构表格组件支持不同状态操作
style(调拨单): 优化界面显示和操作按钮
perf(发货单): 自动设置发货时间为当前时间
chore: 删除无用调拨记录页面
2026-04-10 11:10:30 +08:00
c323ef7a52 feat(wms): 添加调拨订单项目调拨状态字段
- 在 WmsTransferOrderItem 实体中新增 isTransferred 字段用于标识是否已调拨
- 在 WmsTransferOrderItemBo 和 WmsTransferOrderItemVo 中同步添加调拨状态字段
- 在 MyBatis 映射文件中配置 isTransferred 字段映射关系
- 在查询条件中增加调拨状态过滤功能
- 添加调拨单审批状态校验逻辑确保只有审批通过才能调拨
- 在调拨操作完成后设置项目为已调拨状态(isTransferred=1)
2026-04-10 10:25:04 +08:00
1bbd3a6f4d Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-10 09:25:39 +08:00
c8987f6fdd feat(transfer): 添加调拨单审批功能和调拨类型字段
- 在WmsTransferOrder实体中添加调拨类型、审批人、审批时间和审批状态字段
- 在WmsMaterialCoil实体中添加调拨类型字段用于关联调拨信息
- 实现调拨单审批接口,支持通过或驳回操作
- 更新调拨单明细处理逻辑,确保调拨类型正确传递到钢卷信息
- 添加调拨单取消功能,可恢复调拨前的状态
- 在导出VO中增加调拨类型字段支持Excel导出
- 更新查询条件支持按调拨类型、审批状态等字段筛选
- 完善调拨流程中的数据验证和错误处理机制
2026-04-10 09:24:42 +08:00
砂糖
a19c4e4eaf feat(文件预览): 添加对PDF、Word和Excel文件的预览支持
添加新的文件预览组件,支持PDF、Word(docx)、Excel(xlsx/xls)文件类型预览
重构图片预览为独立组件,并添加相关依赖包
2026-04-10 08:42:59 +08:00
砂糖
255a6dc616 refactor(wms): 提取异常钢卷表格为公共组件 AbnormalTable
将多个页面中重复的异常钢卷表格逻辑提取为公共组件 AbnormalTable,提高代码复用性和维护性
2026-04-09 16:22:59 +08:00
砂糖
0e075fe5d4 refactor(wms): 清理异常管理组件中的注释代码并优化表单结构
移除ExceptionManager和AbnormalForm组件中已注释的旧代码
调整AbnormalForm组件字段顺序并添加缺陷描述字段
优化表单数据初始化逻辑
2026-04-09 15:40:41 +08:00
731dd21b0e Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-09 13:51:38 +08:00
39d73c0f2c fix(wms): 异常改成缺陷明细
- 将异常按钮文本从"异常"更改为"缺陷明细"
- 保留异常计数显示功能
2026-04-09 13:51:09 +08:00
砂糖
b232cbf14d feat(钢卷管理): 在多个页面添加业务目的选择功能
为钢卷管理中的校正、拆分、合并、录入等操作添加业务目的选择功能,使用字典类型coil_business_purpose提供选项
2026-04-08 17:55:30 +08:00
砂糖
7930991eb8 feat(员工信息): 新增查看功能并优化附件展示
refactor(异常管理): 重构异常记录表格布局和保存逻辑

feat(库存管理): 新增CRM卷材库存视图和分组筛选功能
2026-04-08 17:40:30 +08:00
砂糖
9c83c9d9a5 feat(wms): 添加类型不匹配钢卷管理功能并优化材料类型处理
1. 新增类型不匹配钢卷查询接口和页面
2. 优化材料类型变更处理逻辑,自动清空物品选择
3. 移除表单复制时冗余的材料类型同步调用
2026-04-08 14:29:16 +08:00
cd5bca19f6 refactor(wms): 优化钢卷不匹配数据查询逻辑
- 在WmsMaterialCoilMapper中新增selectMismatchedItemCoils方法用于查询itemId和itemType不匹配的钢卷
- 在WmsMaterialCoilMapper.xml中添加对应的SQL查询语句,使用子查询直接筛选不匹配的数据
- 重构WmsMaterialCoilServiceImpl中的queryMismatchedItemCoils方法,改用SQL子查询替代原来的多次数据库查询
- 移除原有的批量验证逻辑,直接通过数据库层面进行数据校验
- 优化性能,减少不必要的数据库访问次数
- 使用批量填充方式处理关联对象信息
2026-04-08 14:18:59 +08:00
9adbc1ea0c Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-08 13:56:05 +08:00
f92d5c16e0 feat(wms): 添加钢卷物料的物品类型校验功能
- 启用 WmsProductMapper 和 WmsRawMaterialMapper 的依赖注入
- 实现根据 itemType 参数校验 itemId 存在性的逻辑
- 添加原材料类型的校验支持
- 添加产品的校验支持
- 对无效物品类型抛出异常
- 在钢卷修改逻辑中集成物品存在性验证
2026-04-08 13:55:54 +08:00
砂糖
9bd63d90fc Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-04-08 13:50:53 +08:00
砂糖
6b0fa81224 fix: 修复产品选择组件和原材料选择组件的数据验证问题
修复产品选择和原材料选择组件中当返回数据为空时仍尝试添加的问题,增加对res.data的验证
调整发货计划列表和运单页面的样式,优化高度计算和表单内边距
2026-04-08 13:50:49 +08:00
dc2624ece1 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-08 13:39:58 +08:00
b58a14bc87 feat(wms): 添加钢卷物料的物品类型校验功能
- 启用 WmsProductMapper 和 WmsRawMaterialMapper 的依赖注入
- 实现根据 itemType 参数校验 itemId 存在性的逻辑
- 添加原材料类型的校验支持
- 添加产品的校验支持
- 对无效物品类型抛出异常
- 在钢卷修改逻辑中集成物品存在性验证
2026-04-08 13:39:03 +08:00
砂糖
c68a4573dc feat(钢卷管理): 添加发货单相关功能及统计信息
- 新增发货单数量统计显示,展示已发货和未发货数量
- 添加从发货单移除钢卷的功能
- 移除不再使用的代码注释
2026-04-08 11:25:10 +08:00
砂糖
7e487a487d feat(发货管理): 优化发货单界面布局并新增功能
重构发货单界面布局,使用可拖拽面板组件提升用户体验。新增订单绑定、逻辑库区显示等功能,并调整页面样式。

- 使用DragResizePanel组件实现可拖拽分割布局
- 新增订单绑定、解绑和切换功能
- 在详情表格中添加逻辑库区、厂家和品质字段
- 优化左侧面板可折叠功能
- 调整页面样式和响应式布局
2026-04-08 10:36:23 +08:00
砂糖
6b9c05d5ee Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-04-07 17:40:05 +08:00
砂糖
43f28a4225 feat(异常管理): 重构异常管理界面并新增多选组件
- 新增MutiSelect组件支持下拉多选和复选框两种模式
- 重构异常管理界面,支持直接在表格中编辑异常记录
- 优化钢卷信息展示,增加刷新功能
- 修改AbnormalForm组件,使用MutiSelect替代原有单选组件
- 确保异常记录列表始终显示至少10行,方便快速添加
2026-04-07 17:40:01 +08:00
60d10c03a6 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-07 16:49:06 +08:00
f9a60cec99 feat(delivery): 添加发货计划ID字段支持按计划查询发货单明细
- 在WmsDeliveryWaybillDetailBo中新增planId字段
- 在查询条件中增加planId过滤逻辑
- 实现根据发货计划ID查询所有关联发货单明细的功能
2026-04-07 16:46:16 +08:00
砂糖
1bfd3a598a fix(wms): 修正表单校验逻辑和文字描述
修复位置校验允许0值的问题,将'版面'统一改为'板面'描述
2026-04-07 15:44:33 +08:00
砂糖
505f821df0 refactor(crm): 统一搜索字段名并优化搜索功能
- 将多个页面的搜索字段统一命名为"keyword"以提高一致性
- 优化搜索按钮布局和交互,添加明确的搜索按钮
- 调整字段标签和占位文本使其更准确
- 修复合同列表导出功能中的HTML内容处理逻辑
2026-04-07 11:47:41 +08:00
砂糖
dc92939262 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-04-07 11:43:31 +08:00
e32739cb09 feat(crm): 添加关键字搜索功能
- 在 CrmContractBo 中添加 keyword 字段支持合同多字段搜索
- 在 CrmCustomerBo 中添加 keyword 字段支持客户多字段搜索
- 在 CrmOrderBo 中添加 keyword 字段支持订单多字段搜索
- 实现合同服务的关键字搜索逻辑,支持合同名称、编号、供应商、客户等多个字段
- 实现客户服务的关键字搜索逻辑,支持客户代码、公司名称、联系人等多个字段
- 实现订单服务的关键字搜索逻辑,支持订单代码、客户ID、业务员等多个字段
- 添加搜索条件的空值校验避免无效查询
2026-04-07 11:42:30 +08:00
砂糖
ab9ab90ffa feat(钢卷异常管理): 新增上下板面和主缺陷字段并完善钢卷信息展示
在异常表单中增加上下板面选择器和主缺陷复选框
在多个页面表格中新增上下板面和主缺陷字段展示
在异常管理对话框和面板中增加钢卷详细信息展示
优化表单布局和部分字段标签描述
2026-04-07 11:06:09 +08:00
砂糖
38f980dbbf feat(界面): 添加刷新按钮并优化全屏对话框样式
在导航栏添加刷新按钮方便用户操作,同时优化全屏对话框的滚动和间距样式
2026-04-07 11:05:45 +08:00
砂糖
3d27e14620 feat(调拨单明细): 添加导出和刷新功能
- 在调拨单明细弹窗中添加导出按钮,支持将明细数据导出为CSV文件
- 添加刷新按钮用于重新加载明细数据
- 实现CSV导出功能,包含字段映射和中英文表头处理
2026-04-07 11:05:33 +08:00
d67054d891 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-04-07 10:55:38 +08:00
b399587841 feat(domain): 添加卷材异常记录中的板面字段
- 在 WmsCoilAbnormal 实体中添加 plateSurface 字段
- 在 WmsCoilAbnormalBo 中添加 plateSurface 属性及相关注释
- 在 WmsCoilAbnormalMapper.xml 中映射 plateSurface 字段
- 在查询条件中添加 plateSurface 的相等匹配逻辑
- 在 WmsCoilAbnormalVo 中添加 plateSurface 属性及 Excel 导出配置
2026-04-07 10:55:30 +08:00
砂糖
04081ab0ae fix(wms): 将钢卷号长度验证从10位改为11位
更新多个视图中的钢卷号验证规则,统一将最小长度要求从10位调整为11位以满足新的业务需求
2026-04-06 13:34:25 +08:00
砂糖
1fa4c55869 feat(CoilSelector): 新增入场卷号字段并调整当前卷号显示
feat(customer): 新增客户相关配卷和财务信息查询接口

fix(base.vue): 修复发货单时间条件显示问题

refactor(CustomerEdit): 替换地址选择组件为普通输入框

feat(CoilSelector): 增加入场卷号查询条件并调整对话框宽度

style(OrderEdit): 调整客户名称和销售员选择框宽度

refactor(ChinaAreaSelect): 优化地址解析逻辑并支持空对象处理

feat(FileUpload/FileList): 新增文件预览功能组件

refactor(KLPService/CustomerSelect): 优化客户选择组件并支持自定义字段绑定

fix(AbnormalForm): 修复异常位置校验逻辑并保留当前卷号

feat(ContractTabs): 新增合同附件展示功能

refactor(warehouse/record): 重构操作记录统计展示方式

feat(contract): 集成客户选择组件并优化合同信息填充

refactor(order): 调整订单表单布局并集成合同信息

feat(FilePreview): 新增文件预览组件

feat(customer): 新增财务状态和发货配卷展示

refactor(CustomerOrder): 移除冗余代码并优化布局

feat(PlanDetailForm): 新增合同附件查看功能

feat(dict): 新增字典管理页面
2026-04-06 13:16:45 +08:00
4075ead84e feat(crm): 新增客户相关订单数据查询接口
- 添加根据客户ID查询异议和财务信息的功能
- 添加根据客户ID查询发货单配卷的功能
- 实现客户订单关联数据的多层查询逻辑
- 集成CRM订单、异议、应收和发货单据的数据关联
- 提供完整的客户订单数据视图支持
2026-04-06 11:24:44 +08:00
031d7ba708 feat(crm): 添加合同实体中的客户ID字段支持
- 在CrmContract实体类中新增customerId字段
- 在CrmContractBo业务对象中添加customerId属性
- 更新CrmContractMapper.xml映射文件加入customer_id结果映射
- 在查询条件中增加customerId过滤逻辑
- 为CrmContractVo视图对象添加customerId字段并配置Excel导出
2026-04-06 10:43:32 +08:00
e82d015cea feat(aps): 添加排产单明细分页查询合同的技术涵
- 在ApsPlanDetailMapper中新增selectVoPagePlus方法支持分页查询
- 在ApsPlanDetailMapper.xml中添加对应的SQL查询语句
- 在ApsPlanDetailServiceImpl中实现分页查询逻辑和查询条件构建
- 在ApsPlanDetailVo中添加techAnnex字段用于显示技术附件信息
- 集成MyBatis-Plus分页插件和查询包装器功能
- 优化查询条件构建,支持按计划单ID、订单ID、合同编号等多条件筛选
- 实现按创建时间倒序排列的排序功能
2026-04-06 10:36:50 +08:00
82c801cf9c refactor(WmsTransferOrderService): 优化调拨单删除逻辑
- 添加事务注解确保数据一致性
- 注入调拨单明细相关的mapper和服务
- 删除调拨单时先删除关联的明细记录
- 使用LambdaQueryWrapper进行明细记录查询和删除
- 保持原有业务校验逻辑不变
- 提升代码结构清晰度和可维护性
2026-04-06 10:28:52 +08:00
砂糖
3f86f0be38 refactor: 将vxe-table和xe-utils依赖移至klp-ui的package.json
删除根目录的package.json和package-lock.json文件,将vxe-table和xe-utils依赖项合并到klp-ui的package.json中,以简化项目结构
2026-04-04 09:42:51 +08:00
砂糖
31d79a6c53 feat: 优化物料类型选择逻辑和表格配置
添加物料类型选择逻辑,根据原料或产品类型设置selectType
调整表格树形配置,无分组条件时禁用树形显示
移除调拨状态列和必填备注校验,自动生成调拨单号和时间
2026-04-03 16:26:39 +08:00
砂糖
ba3d2c2b35 feat(wms报表): 在splitConfig中添加actionQueryParams和baseQueryParams
为分条报表配置添加创建者查询参数,用于过滤特定用户创建的数据
2026-04-03 15:39:46 +08:00
砂糖
c4c9641901 feat: 添加钢卷ID字段并实现导出功能
- 在WmsActualWarehouseVo中添加coilId字段
- 在WmsActualWarehouseServiceImpl中设置coilId值
- 在WarehouseBird组件中添加导出库内钢卷信息功能
- 在CoilTable组件中添加总卷数和总净重统计显示
2026-04-03 15:34:19 +08:00
砂糖
b9385858f3 feat(PlanDetailForm): 添加订单选择功能并优化表单结构
refactor(CoilNo): 调整线圈号显示逻辑
2026-04-03 14:53:45 +08:00
砂糖
b9da0d6d76 feat(wms): 添加发货单时间范围查询功能
在基板面板中新增发货单时间范围选择器,并调整后端接口以支持格式化日期参数
2026-04-03 14:40:53 +08:00
0d4d7f4235 fix(wms): 修复卷料创建时字段初始化问题
- 移除父卷料ID的设置
- 清空导出相关字段避免数据残留
- 设置创建和更新时间为当前时间
- 添加创建人和更新人为当前登录用户
- 确保新创建的卷料状态正确初始化
2026-04-03 14:19:18 +08:00
47198a0d01 feat(wms): 添加按时间范围查询已绑定钢卷ID功能
- 在 IWmsDeliveryWaybillDetailService 接口中新增 getBoundCoilIdsByTimeRange 方法
- 在控制器中添加 startTime 和 endTime 参数支持时间范围查询
- 实现服务层方法根据时间段筛选已绑定的钢卷ID列表
- 使用 LambdaQueryWrapper 构建时间范围查询条件
- 对查询结果进行空值检查和去重处理
- 保持原有无时间范围查询的兼容性逻辑
2026-04-03 13:48:54 +08:00
砂糖
e6d63ef4f7 feat(库存管理): 将库存变动功能改为消耗功能
- 修改界面标签从"变动"改为"消耗"
- 移除增加/减少类型选择,只保留消耗功能
- 更新按钮图标和文字为消耗相关
- 为设备选择器添加可清空功能
- 初始化表单数量字段默认值为0
2026-04-03 13:21:38 +08:00
砂糖
e673dcbaeb feat(库存管理): 重构库存页面并添加分组功能
添加vxe-table依赖支持表格分组和筛选
重构库存页面为左右布局,左侧仓库树右侧分组表格
实现按物料类型、名称、材质等多维度分组功能
添加全表搜索和列筛选功能
移除不再使用的stockIo组件和旧版库存页面
2026-04-03 11:30:19 +08:00
砂糖
74eae50ab0 feat(contract): 新增产品内容组件并优化合同管理功能
refactor(contract): 重构合同预览和列表组件
fix(contract): 修复合同ID类型校验问题
style(contract): 优化合同列表样式
docs(contract): 更新合同默认内容模板
2026-04-02 16:49:07 +08:00
砂糖
5ec293fc94 feat(物料管理): 添加质量状态多选查询功能
在物料管理模块中新增质量状态多选查询功能,包括:
1. 后端添加qualityStatusCsv字段支持多选查询
2. 前端CoilSelector组件增加品质多选下拉框
3. 服务层实现多选条件过滤逻辑
2026-04-02 14:24:52 +08:00
砂糖
d31bd14692 feat(字典组件): 添加DictSelect组件并替换多处muti-select
添加DictSelect组件作为全局组件,并在多个报表模板中替换原有的muti-select组件
优化字典项筛选逻辑,调整样式和提示文本
2026-04-02 09:10:58 +08:00
821af42976 fix(export): 修正导出VO中的字段标签
- 将WmsMaterialCoilAllExportVo中的打包状态字段标签修正为原料材质
- 将WmsMaterialCoilExportVo中的打包状态字段标签修正为原料材质
2026-04-01 18:20:45 +08:00
砂糖
579bf3796f feat(wms): 新增钢卷表面处理字段及相关功能
在钢卷相关实体类、前端页面和查询逻辑中新增钢卷表面处理字段,包括:
1. 在WmsMaterialCoil、WmsMaterialCoilVo、WmsMaterialCoilBo中新增coilSurfaceTreatment字段
2. 在前端多个页面中新增钢卷表面处理的展示和编辑功能
3. 在查询逻辑中新增对钢卷表面处理的过滤条件
4. 新增仓库操作记录页面及相关统计图表功能
2026-04-01 14:50:56 +08:00
砂糖
f959f97099 feat(contract): 新增合同预览和列表组件
refactor(QRCode): 优化二维码组件并修复空值检查
将QRCode组件从print目录移动到components目录,并添加空值检查防止错误

feat(crm): 在合同模型中添加交货日期字段
在CrmContract、CrmContractVo、CrmContractBo及相关Mapper中添加deliveryDate字段

refactor(wms): 统一使用全局QRCode组件路径
将多个文件中的QRCode引用路径从相对路径改为@/components/QRCode

style(order): 调整订单页面标签顺序
调整操作记录和发货配卷标签的顺序

chore: 删除废弃的打印相关文件
移除print目录下不再使用的QRCode、CodeRenderer等组件和页面
2026-04-01 10:44:51 +08:00
砂糖
800cf0c8d1 fix(wms报表): 修正异常率计算逻辑并统一百分比格式
- 在异常率计算中增加质量状态判断条件
- 将分母从totalCount改为outCount以匹配业务需求
- 统一异常率和正品率的百分比格式输出
2026-03-31 18:54:56 +08:00
砂糖
0223102269 feat(wms/report): 添加差值计算和异常信息展示功能
refactor(wms/report): 替换合计信息为差值显示
feat(wms/coil): 增加创建时间和创建人字段
feat(crm/contract): 添加合同导出按钮
2026-03-31 18:37:17 +08:00
砂糖
abcc644f74 feat(crm/contract): 添加状态变更功能并优化代码
在合同管理页面添加状态变更下拉选择功能,支持草稿、已生效、已作废和已完成四种状态切换。同时移除base.vue中无用的注释代码。
2026-03-31 14:16:08 +08:00
砂糖
62444ef743 feat(crm): 添加订单和合同的发货配卷查询功能
添加新的API接口和组件用于查询订单和合同下的发货配卷情况
在订单和合同详情页中新增"发货配卷"标签页展示相关数据
2026-03-31 13:49:00 +08:00
砂糖
a253d1ccea feat(crm): 传递合同ID至订单页面并完善标签逻辑
在合同页面将合同ID传递给订单页面,确保订单与合同关联
优化标签渲染逻辑,根据仓库类型显示不同标签
移除无用注释和代码
2026-03-31 11:32:16 +08:00
砂糖
aca10bcd45 feat(客户管理): 新增税号字段并优化客户信息展示
feat(订单管理): 增加宽度和厚度公差字段,优化销售员选择方式

feat(合同管理): 新增合同管理模块及相关API接口

refactor(文件列表): 重构文件列表组件样式和布局

fix(QRCode): 修复内容为空时仍触发生成的bug

perf(线圈管理): 优化用户列表加载条件,减少不必要请求

style(代码): 移除多余的空行和注释代码
2026-03-31 11:16:48 +08:00
b7d8463198 fix(crm): 修复客户查询条件匹配逻辑
- 将联系人姓名字段从精确匹配改为模糊匹配
- 将联系方式字段从精确匹配改为模糊匹配
- 将地址字段从精确匹配改为模糊匹配
- 将银行信息字段从精确匹配改为模糊匹配
- 将税号字段从精确匹配改为模糊匹配
- 提升客户搜索功能的灵活性和准确性
2026-03-30 15:07:41 +08:00
砂糖
4617328b8e Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-03-30 14:34:55 +08:00
砂糖
070b0aea8d fix(wms): 修复异常表单和报表导出功能
修正异常表单中的产线字段名从line改为productionLine
优化报表导出功能,使用actionIds替代coilIds
为异常管理添加程度字典显示和产线字段
移除冗余代码并统一报表模板中的导出逻辑
2026-03-30 14:34:51 +08:00
6835a35c02 feat(crm): 订单ID数据类型优化及配卷查询功能扩展
- 将CrmOrder、CrmOrderItem及其相关BO、VO类中的orderId和itemId字段从String类型改为Long类型
- 修改selectOrderItemsByOrderIds方法参数类型为List<Long>
- 在CrmOrderItemController中新增根据订单ID和合同ID查询配卷的接口
- 实现queryCoilsByOrderId和queryCoilsByContractId服务方法
- 移除WmsMaterialCoilServiceImpl中冗余的嵌套对象构建逻辑
- 更新销售报表中订单ID的类型转换和分组逻辑以适配Long类型
2026-03-30 14:33:06 +08:00
02469383f4 fix(exception): 修改全局异常处理器返回具体错误信息
- 修改 RuntimeException 处理器返回具体的异常消息而不是通用提示
- 修改 Exception 处理器返回具体的异常消息而不是通用提示
- 移除了硬编码的"系统异常,请联系管理员处理"消息
- 保留了原有的错误日志记录功能
2026-03-30 13:57:35 +08:00
15a3f843f1 feat(crm): 添加某一合同下财务和异议信息查询功能
- 在CrmOrderItemController中新增getContractFinance接口用于查询合同关联的财务和异议数据
- 在CrmOrderItemService及其实现类中添加queryFinanceAndObjectionByContractId方法
- 创建CrmContractOrderFinanceVo数据传输对象封装异议列表和应收款列表
- 实现通过合同ID查询其下属订单的销售异议和财务信息的完整逻辑
- 修改全局异常处理器统一返回系统异常提示信息
2026-03-30 13:47:10 +08:00
8a5f2bc4df feat(crm): 添加订单关联合同ID和附件字段支持
- 在CrmOrder实体类中新增contractId和annexFiles字段
- 在CrmOrderBo业务对象中同步添加对应字段
- 更新CrmOrderMapper.xml映射文件中的结果映射和查询字段
- 在CrmOrderServiceImpl服务实现中添加字段查询条件支持
- 在CrmOrderVo视图对象中增加Excel导出注解配置
2026-03-30 13:39:27 +08:00
ca176de4ef feat(crm): 添加合同管理功能模块
- 新增合同信息实体类、业务对象和视图对象
- 创建合同产品明细相关的实体、业务对象和视图对象
- 实现合同信息的增删改查和分页查询功能
- 实现合同产品明细的增删改查和分页查询功能
- 添加合同信息和产品明细的导出Excel功能
- 创建合同信息和产品明细的数据库映射配置
- 实现合同服务层业务逻辑和数据校验功能
- 配置合同相关控制器接口和请求映射关系
2026-03-30 13:28:37 +08:00
d26bdb38ca Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-03-30 13:19:26 +08:00
2dff94c3bd feat(order): 添加订单项宽度公差和厚度公差字段
- 在CrmOrderItem实体类中新增widthTolerance和thicknessTolerance字段
- 在CrmOrderItemBo业务对象中添加对应的公差字段定义
- 更新CrmOrderItemMapper.xml映射文件中的结果映射和查询字段
- 在服务实现类中添加公差字段的查询条件支持
- 在CrmOrderItemVo视图对象中增加Excel导出支持的公差字段
2026-03-30 13:19:17 +08:00
砂糖
bb9252e3a2 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-03-30 13:13:49 +08:00
砂糖
aacf433462 feat: 修改打包状态为原料材质并优化异常管理功能
修改所有打包状态字段为原料材质,统一业务术语
重构异常管理功能,新增异常记录列表和删除功能
优化分条钢卷面板显示更多物料信息
将切边要求和包装要求改为下拉选择框
2026-03-30 13:13:46 +08:00
e553bfcb22 feat(crm): 添加客户纳税人识别号字段支持
- 在 CrmCustomer 实体类中新增 taxNumber 字段
- 在 CrmCustomerBo 业务对象中添加 taxNumber 属性
- 在 CrmCustomerVo 视图对象中增加 taxNumber 并配置 Excel 导出
- 更新 MyBatis 映射文件 CrmCustomerMapper.xml 添加字段映射
- 在查询条件构建中加入纳税人识别号的过滤逻辑
2026-03-30 12:57:57 +08:00
cb9998e0c4 feat(wms): 添加钢卷异常记录中的产线名称字段
- 在 WmsCoilAbnormal 实体类中新增 productionLine 字段
- 在 WmsCoilAbnormalBo 中添加 productionLine 查询条件字段
- 更新数据库映射文件 WmsCoilAbnormalMapper.xml 映射关系
- 在服务层实现类中添加产线名称查询过滤逻辑
- 在 WmsCoilAbnormalVo 视图对象中添加产线名称导出支持
2026-03-30 12:57:19 +08:00
15058727d0 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-03-30 11:10:52 +08:00
ab7af2ade8 feat(wms): 添加配送单详情中的原材料和产品信息字段
- 在 WmsDeliveryWaybillDetailVo 中新增物品名称、规格、材质等属性
- 添加厂家、表面处理描述、镀层等原材料/产品相关信息
- 在 Mapper 中增加原材料和产品的关联查询逻辑
- 实现原材料和产品表的左连接查询支持
- 添加状态描述字段用于显示库存状态信息
- 完善 Excel 导出功能中的新字段映射配置
2026-03-30 11:10:44 +08:00
砂糖
9cf0d289c3 feat(wms): 添加表面处理字段显示和查询功能
在发货单明细表和钢卷选择器中添加表面处理字段的显示和查询功能
同时优化钢卷选择时的品质状态校验逻辑
2026-03-30 11:02:36 +08:00
砂糖
4988630db9 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-03-30 10:29:07 +08:00
cdf49ab8fe feat(wms): 添加发货单明细查询功能支持导出功能
- 在WmsDeliveryWaybillDetailMapper中新增VO查询方法
- 实现联查发货单、计划、钢卷信息的数据映射
- 更新WmsDeliveryWaybillDetailVo实体类字段结构
- 优化服务层查询逻辑并添加分页支持
- 配置MyBatis XML映射文件查询语句
- 整合多表关联数据展示完整业务信息
2026-03-30 10:15:10 +08:00
砂糖
a43cedc00f feat(wms/delivery): 改进发货单页面布局和交互
添加可拖拽分割线调整表格和详情区域高度
固定顶部操作栏和表格区域滚动
优化页面整体样式和用户体验
2026-03-30 09:50:52 +08:00
砂糖
667c411997 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-03-30 09:29:46 +08:00
砂糖
05fb0358a2 fix(wms): 在导出功能中添加waybillId参数
确保导出功能包含必要的waybillId参数以正确过滤数据
2026-03-30 09:29:40 +08:00
e767502d7b Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-03-28 18:10:29 +08:00
112cdce0d0 feat(wms): 完善物料卷VO结构并优化运单查询排序
- 在WmsMaterialCoilVo中新增actualWarehouse字段存储仓库信息
- 为WmsMaterialCoilVo补充WmsActualWarehouse导入声明
- 在物料卷服务实现中设置仓库名称和实际仓库信息
- 为运单查询条件添加按创建时间降序排列功能
2026-03-28 18:10:21 +08:00
砂糖
49427608ad Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-03-28 17:52:03 +08:00
砂糖
97cb78bbbe feat(wms): 在钢卷修正页面添加实测厚度输入框
为钢卷修正功能添加实测厚度(m)的输入框,使用户能够输入钢卷的实测厚度数据
2026-03-28 17:52:00 +08:00
086d01fa3f Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-03-28 16:39:41 +08:00
c3f2f5ef83 refactor(WmsTransferOrderItemService): 优化调拨单明细查询速率
- 简化导入语句,使用通配符导入相关域类和映射器
- 添加WmsWarehouseMapper依赖注入以支持仓库信息批量查询
- 将原有的分步查询逻辑重构为统一的fillBatchInfo方法
- 实现批量查询钢卷、原料、产品和仓库信息以提高性能
- 添加物料类型名称映射和前后置物料信息填充功能
- 在创建和更新钢卷时设置物料类型字段
2026-03-28 16:39:33 +08:00
砂糖
8d6c3302a3 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-03-28 15:58:27 +08:00
砂糖
97cc86c6c4 feat(钢卷操作): 将操作类型显示从静态文本改为可编辑的下拉选择框
修改操作类型显示方式,从静态文本替换为可编辑的下拉选择框,支持用户直接修改操作类型。同时保留原有字典类型的选项支持,提升用户体验和操作便捷性。
2026-03-28 15:58:23 +08:00
f3d5e1f0bf feat(transfer): 添加调拨订单项确认功能中的订单项ID参数支持
- 在confirmTransfer方法中添加orderItemId参数获取
- 更新查询条件以支持根据订单项ID进行筛选
- 添加对orderItemId和transferId为null的安全检查
- 优化查询包装器的条件判断逻辑
2026-03-28 15:27:35 +08:00
砂糖
499654907b feat(调拨单): 新增调拨单管理功能
- 新增调拨单主表和明细表相关API接口
- 新增调拨单主表和明细表前端页面
- 新增钢卷选择器组件和调拨明细表格组件
- 修改产品信息和原料信息渲染组件支持更多字段
- 修改产品选择和原料选择组件支持数值类型值
- 修改钢卷号渲染组件支持更多字段和外部数据
- 新增调拨单匹配物料接口
2026-03-28 14:08:27 +08:00
00939dae2f refactor(wms): 优化调拨单项目物料信息填充逻辑
- 将通用的fillMaterialInfo方法拆分为fillMaterialInfoBefore和fillMaterialInfoAfter两个专用方法
- 修复了物料信息填充时字段映射错误问题,确保Before和After字段正确设置
- 增强了代码可读性和维护性,明确区分前后物料信息处理逻辑
- 保持了原有的业务逻辑不变,仅优化方法结构和字段赋值准确性
2026-03-28 13:35:48 +08:00
6e23e932da refactor(transfer): 优化转库订单项目确认逻辑
- 移除 WmsTransferOrderItemBo 中的 itemType 字段
- 将 itemType 替换为 materialTypeAfter 的转换逻辑
- 添加对 itemId、itemType 和 warehouseId 的空值检查
- 实现字段选择性更新机制
- 修复查询条件添加 transferId 筛选
- 完善默认值回退逻辑
2026-03-28 11:47:33 +08:00
c554508000 feat(transfer): 添加调拨订单项目中的钢卷详情查询和重复检查功能
- 优化导入语句,使用java.util.*统一导入
- 在分页查询中添加钢卷详情关联查询逻辑
- 通过coilId收集并查询对应的钢卷信息并建立映射关系
- 为每个调拨订单项目设置关联的钢卷详情信息
- 添加调拨单内钢卷重复性检查机制
- 防止同一调拨单下添加相同coilId的重复项目
- 提供详细的重复钢卷号错误提示信息
2026-03-28 11:33:19 +08:00
317b7187f5 perf(WmsTransferOrderItemService): 优化调拨明细信息查询性能
- 使用流式处理批量获取钢卷ID并去重
- 通过单次查询获取所有相关钢卷信息
- 使用Map映射避免循环中的重复数据库查询
- 移除原有的逐条查询逻辑减少数据库交互次数
- 提升列表查询的整体性能表现
2026-03-28 10:58:15 +08:00
d28f50ba65 feat(wms): 完善调拨单明细查询功能
- 新增钢卷信息查询和服务注入
- 新增库房服务依赖以获取库区名称
- 实现调拨单明细详情信息填充功能
- 添加改前后物料信息的完整查询支持
- 扩展VO类以包含物料类型名称和库区名称字段
- 优化查询方法以自动填充关联的物料和库房信息
- 实现物料类型转换显示为中文描述功能
- 添加异常处理确保库房信息查询失败时不影响主流程
2026-03-28 10:39:43 +08:00
862efcfabd Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-03-28 09:27:38 +08:00
d51b555fa2 fix(excel): 修复排产表导出功能中的日期格式和表格合并问题
- 添加SimpleDateFormat用于日期格式化处理
- 将计划日期格式化为yyyy-MM-dd格式避免显示异常
- 修正表格合并区域从38列扩展到40列
- 为整个合并区域的所有单元格应用标题样式
- 确保合并单元格后样式的一致性显示
2026-03-28 09:27:30 +08:00
砂糖
f685ea4cea Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-03-28 09:09:55 +08:00
砂糖
9c2d8cfb4a feat(计划单): 添加序号字段并在表格中显示
在计划单详情表单中添加序号输入字段,并在详情表格中新增序号列显示。移除不再使用的修改按钮代码。
2026-03-28 09:09:50 +08:00
ba722e0439 refactor(aps): 重构排产单查询和导出功能
- 移除日期范围、产线ID和客户名称查询条件
- 修改排序规则为按业务序号升序排列
- 删除查询请求DTO中的废弃字段
- 优化Excel导出功能,添加标题动态显示和表头样式
- 实现前7列数据居中对齐和自动合并功能
- 修复POI依赖导入路径问题
- 更新转储订单项映射配置
2026-03-27 18:21:53 +08:00
砂糖
bc00846f14 feat(排产单): 新增只读模式并优化导出功能
添加只读视图组件 read.vue,修改 detail.vue 和 index.vue 以支持 readonly 属性
将导出按钮移至行操作列并支持单行导出
优化排产日期列宽度和操作列布局
2026-03-27 17:27:06 +08:00
1c9a59636a feat(wms): 添加调拨单明细取消功能并优化字段映射
- 在IWmsTransferOrderItemService中新增cancelTransfer方法
- 修改WmsTransferOrderItem实体类将itemId字段重命名为orderItemId
- 在WmsTransferOrderItemBo和WmsTransferOrderItemVo中同步字段名称变更
- 为WmsTransferOrderBo的transferTime字段添加日期格式化注解
- 在WmsTransferOrderItemController中添加cancel接口支持取消操作
- 实现WmsTransferOrderItemServiceImpl的cancelTransfer业务逻辑
- 移除未使用的工具类依赖和冗余的coilService注入
- 修复confirmTransfer方法中的字段赋值错误
2026-03-27 17:13:45 +08:00
b842f267cc feat(transfer): 新增调拨单明细确认功能
- 在IWmsTransferOrderItemService接口中添加confirmTransfer方法
- 在WmsTransferOrderItemBo中增加itemType字段用于物料类型标识
- 创建WmsTransferOrderItemController的confirm端点处理确认请求
- 实现WmsTransferOrderItemServiceImpl中的confirmTransfer业务逻辑
- 集成IWmsMaterialCoilService服务更新钢卷相关状态信息
- 完成调拨单明细数据同步更新确保数据一致性
2026-03-27 16:59:20 +08:00
5be8f2857e Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-03-27 16:44:03 +08:00
62eb5aedfb feat(wms): 添加调拨单明细批量新增功能
- 在 IWmsTransferOrderItemService 中添加 batchInsert 方法
- 在 WmsTransferOrderItemBo 中新增 coilIds 字段用于接收钢卷id列表
- 在 WmsTransferOrderItemController 中添加 /batch 接口支持批量新增
- 在 WmsTransferOrderItemServiceImpl 中实现批量插入业务逻辑
- 新增 WmsMaterialCoil 相关依赖注入和数据查询操作
- 实现根据 itemType 自动设置 materialType 的转换逻辑
2026-03-27 16:43:42 +08:00
砂糖
cd00b9562d refactor(wms/report): 重构报表模块数据获取逻辑,提取公共方法到fetch.js
feat(wms/report): 新增报表结果存储页面,支持JSON数据横向对比

style(wms/coil/do): 调整钢卷修正页面样式和代码格式

fix(wms/coil/do): 修复操作记录查询参数传递问题,优化钢卷选择逻辑
2026-03-27 16:37:59 +08:00
c294149274 feat(wms): 新增调拨单明细物料匹配或创建功能
- 在IWmsTransferOrderItemService接口中添加matchOrCreateMaterial方法
- 在WmsTransferOrderItemController中添加/matchOrCreate接口端点
- 实现matchOrCreateMaterial业务逻辑,支持根据itemId和itemType匹配或新增物料
- 添加从原料到产品的转换匹配逻辑
- 添加从产品到原料的转换匹配逻辑
- 集成WmsRawMaterialMapper和WmsProductMapper数据访问层
- 实现基于名称、规格、制造商等字段的精确匹配机制
- 支持itemType参数区分原料(material)和成品(product)处理流程
2026-03-27 16:32:32 +08:00
0d3bde95f3 feat(wms): 添加调拨单功能模块
- 创建调拨单主表实体类、业务对象类和视图对象类
- 创建调拨单明细表实体类、业务对象类和视图对象类
- 实现调拨单主表和明细表的数据库映射和XML配置文件
- 开发调拨单主表和明细表的服务接口及实现类
- 创建调拨单主表和明细表的控制器,提供CRUD操作接口
- 实现分页查询、新增、修改、删除和导出功能
- 添加参数验证和数据校验机制
- 集成MyBatis-Plus进行数据库操作
- 配置Excel导出功能支持调拨单数据导出
2026-03-27 16:15:17 +08:00
15a2920053 feat(WmsCoilPendingAction): 添加按钢卷ID列表查询功能
- 在WmsCoilPendingActionBo中新增coilIds字段用于存储钢卷ID列表
- 实现字符串形式的钢卷ID逗号分隔解析为Long类型列表
- 扩展buildQueryWrapperPlus方法支持按多个钢卷ID批量查询
- 添加非空验证确保coilIds参数有效时才进行in条件构建
- 保持原有单个coilId查询逻辑不变,实现向后兼容
- 提供更灵活的批量查询接口以提升数据检索效率
2026-03-27 16:08:59 +08:00
砂糖
ab3914811a feat(wms): 新增报结果存储API及页面
refactor(aps): 修改导出接口为POST并调整表格高度
2026-03-27 13:00:58 +08:00
砂糖
19b48d711a Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-03-27 09:57:27 +08:00
砂糖
1e6be8cd76 feat(aps): 新增排产单管理功能模块
添加排产单主表和明细表的API接口
实现排产单列表、新增、修改、删除功能
添加排产单明细表单和列表展示组件
2026-03-27 09:57:24 +08:00
2041cb3e5d fix(wms): 删除钢卷时同步更新二维码状态为失效
- 在删除钢卷操作中添加二维码状态更新逻辑
- 遍历钢卷列表检查是否存在关联的二维码记录ID
- 将关联的二维码记录状态设置为0表示失效
- 通过generateRecordService更新二维码记录状态
- 确保删除钢卷后对应的二维码同步失效
2026-03-27 09:55:09 +08:00
d4b5f09882 fix(wms): 解决合卷操作中钢卷重复检查问题
- 添加钢卷ID去重验证逻辑
- 防止相同钢卷重复参与合卷操作
- 抛出明确的业务异常提示重复问题
2026-03-27 09:43:14 +08:00
278cb24d54 feat(aps): 添加日期时间格式化注解支持
- 在 ApsPlanDetail 实体类中为 startTime 和 endTime 字段添加 JsonFormat 和 DateTimeFormat 注解
- 在 ApsPlanDetailBo 业务对象中为 startTime 和 endTime 字段添加 JsonFormat 和 DateTimeFormat 注解
- 在 ApsPlanDetailVo 视图对象中为 startTime 和 endTime 字段添加 JsonFormat 和 DateTimeFormat 注解
- 在 ApsPlanSheet 实体类中为 planDate 字段添加 JsonFormat 和 DateTimeFormat 注解
- 在 ApsPlanSheetBo 业务对象中为 planDate 字段添加 JsonFormat 和 DateTimeFormat 注解
- 在 ApsPlanSheetVo 视图对象中为 planDate 字段添加 JsonFormat 和 DateTimeFormat 注解
- 统一日期时间字段的序列化和反序列化格式配置
2026-03-26 16:21:40 +08:00
1b9787f983 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-03-26 15:14:06 +08:00
0f760e90b5 feat(aps): 添加根据排产单ID删除明细功能
- 在ApsPlanDetailMapper中新增deleteByPlanSheetIds方法
- 在ApsPlanDetailMapper.xml中添加对应的DELETE语句实现软删除
- 在ApsPlanDetailServiceImpl中实现deleteByPlanSheetIds方法
- 在ApsPlanSheetServiceImpl中注入IApsPlanDetailService依赖
- 在排产单删除时调用planDetailService.deleteByPlanSheetIds方法
- 在IApsPlanDetailService接口中定义deleteByPlanSheetIds方法
2026-03-26 15:13:54 +08:00
砂糖
5d3cbde044 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-03-26 15:13:11 +08:00
砂糖
a389a98664 feat(wms): 新增分条报表配置及功能优化
- 添加分条报表相关配置及视图组件
- 优化标签打印尺寸及布局
- 增加实测厚度字段及相关展示逻辑
- 重构报表数据获取逻辑,统一处理异常情况
- 完善分条操作表单,增加异常信息管理
2026-03-26 15:13:08 +08:00
38862cf0ea feat(aps): 添加排产单导出功能
- 新增 ApsPlanSheetQueryReq 查询参数类
- 新增 ApsPlanSheetRowVo 数据传输对象
- 实现 controller 层 exportAll 接口
- 实现 service 层 exportExcel 导出逻辑
- 添加 mapper 层 selectList 查询方法
- 配置 mybatis xml 查询映射
- 优化 Excel 导出样式和数据处理
2026-03-26 14:59:33 +08:00
281f86ca8c feat(aps): 添加排产单和排产明细功能模块
- 创建排产单主实体类 ApsPlanSheet 和业务对象 ApsPlanSheetBo
- 创建排产单明细实体类 ApsPlanDetail 和业务对象 ApsPlanDetailBo
- 实现排产单主和明细的控制器、服务层和数据访问层
- 添加排产单主和明细的查询、新增、修改、删除和导出功能
- 配置 MyBatis Plus 映射和 XML 结果映射
- 实现分页查询和条件筛选功能
- 添加数据校验和业务逻辑处理
2026-03-26 11:35:33 +08:00
360 changed files with 26646 additions and 7338 deletions

View File

@@ -0,0 +1,99 @@
package com.klp.aps.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.aps.domain.vo.ApsPlanDetailVo;
import com.klp.aps.domain.bo.ApsPlanDetailBo;
import com.klp.aps.service.IApsPlanDetailService;
import com.klp.common.core.page.TableDataInfo;
/**
* 排产单明细
*
* @author klp
* @date 2026-03-26
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/aps/planDetail")
public class ApsPlanDetailController extends BaseController {
private final IApsPlanDetailService iApsPlanDetailService;
/**
* 查询排产单明细列表
*/
@GetMapping("/list")
public TableDataInfo<ApsPlanDetailVo> list(ApsPlanDetailBo bo, PageQuery pageQuery) {
return iApsPlanDetailService.queryPageList(bo, pageQuery);
}
/**
* 导出排产单明细列表
*/
@Log(title = "排产单明细", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ApsPlanDetailBo bo, HttpServletResponse response) {
List<ApsPlanDetailVo> list = iApsPlanDetailService.queryList(bo);
ExcelUtil.exportExcel(list, "排产单明细", ApsPlanDetailVo.class, response);
}
/**
* 获取排产单明细详细信息
*
* @param planDetailId 主键
*/
@GetMapping("/{planDetailId}")
public R<ApsPlanDetailVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long planDetailId) {
return R.ok(iApsPlanDetailService.queryById(planDetailId));
}
/**
* 新增排产单明细
*/
@Log(title = "排产单明细", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ApsPlanDetailBo bo) {
return toAjax(iApsPlanDetailService.insertByBo(bo));
}
/**
* 修改排产单明细
*/
@Log(title = "排产单明细", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ApsPlanDetailBo bo) {
return toAjax(iApsPlanDetailService.updateByBo(bo));
}
/**
* 删除排产单明细
*
* @param planDetailIds 主键串
*/
@Log(title = "排产单明细", businessType = BusinessType.DELETE)
@DeleteMapping("/{planDetailIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] planDetailIds) {
return toAjax(iApsPlanDetailService.deleteWithValidByIds(Arrays.asList(planDetailIds), true));
}
}

View File

@@ -0,0 +1,105 @@
package com.klp.aps.controller;
import java.util.List;
import java.util.Arrays;
import com.klp.aps.domain.dto.ApsPlanSheetQueryReq;
import com.klp.aps.domain.dto.ApsQuickSheetQueryReq;
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.aps.domain.vo.ApsPlanSheetVo;
import com.klp.aps.domain.bo.ApsPlanSheetBo;
import com.klp.aps.service.IApsPlanSheetService;
import com.klp.common.core.page.TableDataInfo;
/**
* 排产单主
*
* @author klp
* @date 2026-03-26
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/aps/planSheet")
public class ApsPlanSheetController extends BaseController {
private final IApsPlanSheetService iApsPlanSheetService;
/**
* 查询排产单主列表
*/
@GetMapping("/list")
public TableDataInfo<ApsPlanSheetVo> list(ApsPlanSheetBo bo, PageQuery pageQuery) {
return iApsPlanSheetService.queryPageList(bo, pageQuery);
}
/**
* 导出排产单主列表
*/
@Log(title = "排产单主", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ApsPlanSheetBo bo, HttpServletResponse response) {
List<ApsPlanSheetVo> list = iApsPlanSheetService.queryList(bo);
ExcelUtil.exportExcel(list, "排产单主", ApsPlanSheetVo.class, response);
}
@PostMapping("/exportAll")
public void export(@Validated ApsPlanSheetQueryReq req, javax.servlet.http.HttpServletResponse response) {
iApsPlanSheetService.exportExcel(req, response);
}
/**
* 获取排产单主详细信息
*
* @param planSheetId 主键
*/
@GetMapping("/{planSheetId}")
public R<ApsPlanSheetVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long planSheetId) {
return R.ok(iApsPlanSheetService.queryById(planSheetId));
}
/**
* 新增排产单主
*/
@Log(title = "排产单主", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ApsPlanSheetBo bo) {
return toAjax(iApsPlanSheetService.insertByBo(bo));
}
/**
* 修改排产单主
*/
@Log(title = "排产单主", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ApsPlanSheetBo bo) {
return toAjax(iApsPlanSheetService.updateByBo(bo));
}
/**
* 删除排产单主
*
* @param planSheetIds 主键串
*/
@Log(title = "排产单主", businessType = BusinessType.DELETE)
@DeleteMapping("/{planSheetIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] planSheetIds) {
return toAjax(iApsPlanSheetService.deleteWithValidByIds(Arrays.asList(planSheetIds), true));
}
}

View File

@@ -0,0 +1,230 @@
package com.klp.aps.domain.bo;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 排产单明细业务对象 aps_plan_detail
*
* @author klp
* @date 2026-03-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class ApsPlanDetailBo extends BaseEntity {
/**
* 排产明细主键ID
*/
private Long planDetailId;
/**
* 关联排产单ID
*/
private Long planSheetId;
/**
* 关联排产单ID列表用于批量查询
*/
private List<Long> planSheetIds;
/**
* 内容序号
*/
private String bizSeqNo;
/**
* 订单ID
*/
private Long orderId;
/**
* 销售内容:订单号
*/
private String orderCode;
/**
* 销售内容:订单合同号
*/
private String contractCode;
/**
* 销售内容:客户
*/
private String customerName;
/**
* 销售内容:业务员
*/
private String salesman;
/**
* 原料信息:厂家
*/
private String rawManufacturer;
/**
* 原料信息:材质
*/
private String rawMaterial;
/**
* 原料信息:厚度mm
*/
private BigDecimal rawThick;
/**
* 原料信息:宽度mm
*/
private BigDecimal rawWidth;
/**
* 原料钢卷ID
*/
private Long rawMaterialId;
/**
* 原料卷号
*/
private String rawCoilNos;
/**
* 钢卷位置
*/
private String rawLocation;
/**
* 包装要求
*/
private String rawPackaging;
/**
* 宽度要求
*/
private String rawEdgeReq;
/**
* 镀层种类
*/
private String rawCoatingType;
/**
* 原料净重
*/
private BigDecimal rawNetWeight;
/**
* 成品信息:成品名称
*/
private String productName;
/**
* 成品信息:材质
*/
private String productMaterial;
/**
* 成品信息:镀层g
*/
private BigDecimal coatingG;
/**
* 成品信息:成品宽度
*/
private BigDecimal productWidth;
/**
* 成品信息:轧制厚度
*/
private BigDecimal rollingThick;
/**
* 成品信息:标签厚度
*/
private BigDecimal markCoatThick;
/**
* 成品信息:吨钢长度区间m
*/
private String tonSteelLengthRange;
/**
* 成品信息:数量
*/
private BigDecimal planQty;
/**
* 成品信息:重量
*/
private BigDecimal planWeight;
/**
* 成品信息:表面处理
*/
private String surfaceTreatment;
/**
* 成品信息:切边要求
*/
private String widthReq;
/**
* 成品信息:包装要求
*/
private String productPackaging;
/**
* 成品信息:宽度要求
*/
private String productEdgeReq;
/**
* 成品信息:用途
*/
private String usageReq;
/**
* 后处理
*/
private String postProcess;
/**
* 下工序
*/
private String nextProcess;
/**
* 取样
*/
private String sampleReq;
/**
* 生产开始时间
*/
@JsonFormat(pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startTime;
/**
* 生产结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date endTime;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,66 @@
package com.klp.aps.domain.bo;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 排产单主业务对象 aps_plan_sheet
*
* @author klp
* @date 2026-03-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class ApsPlanSheetBo extends BaseEntity {
/**
* 排产单主键ID
*/
private Long planSheetId;
/**
* 排产日期
*/
@JsonFormat(pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date planDate;
/**
* 产线ID
*/
private Long lineId;
/**
* 产线名称
*/
private String lineName;
/**
* 排产单号
*/
private String planCode;
/**
* 排产类型
*/
private String planType;
/**
* 排产人
*/
private String scheduler;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,13 @@
package com.klp.aps.domain.dto;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
@Data
public class ApsPlanSheetQueryReq {
// planSheetId
private Long planSheetId;
}

View File

@@ -0,0 +1,59 @@
package com.klp.aps.domain.dto;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.List;
@Data
public class ApsPlanSheetSaveReq {
@NotEmpty(message = "rows 不能为空")
private List<ApsQuickSheetSaveReq.Row> rows;
@Data
public static class Row {
private Long quickSheetId;
private Long lineId;
private String lineName;
private String planCode;
private String planType;
private String scheduler;
private String remark;
private String bizSeqNo;
private String orderCode;
private String contractCode;
private String customerName;
private String salesman;
private String productName;
private String productMaterial;
private String coatingG;
private String productWidth;
private String rollingThick;
private String markCoatThick;
private String tonSteelLengthRange;
private String planQty;
private String planWeight;
private String surfaceTreatment;
private String widthReq;
private String usageReq;
private String postProcess;
private String nextProcess;
private String sampleReq;
private String rawManufacturer;
private String rawMaterial;
private String rawThick;
private String rawWidth;
private String rawMaterialId;
private String rawCoilNos;
private String rawLocation;
private String rawPackaging;
private String rawEdgeReq;
private String rawCoatingType;
private String rawNetWeight;
private String startTime;
private String endTime;
}
}

View File

@@ -0,0 +1,193 @@
package com.klp.aps.domain.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.util.Date;
/**
* 排产单明细对象 aps_plan_detail
*
* @author klp
* @date 2026-03-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("aps_plan_detail")
public class ApsPlanDetail extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 排产明细主键ID
*/
@TableId(value = "plan_detail_id")
private Long planDetailId;
/**
* 关联排产单ID
*/
private Long planSheetId;
/**
* 内容序号
*/
private String bizSeqNo;
/**
* 订单ID
*/
private Long orderId;
/**
* 销售内容:订单号
*/
private String orderCode;
/**
* 销售内容:订单合同号
*/
private String contractCode;
/**
* 销售内容:客户
*/
private String customerName;
/**
* 销售内容:业务员
*/
private String salesman;
/**
* 原料信息:厂家
*/
private String rawManufacturer;
/**
* 原料信息:材质
*/
private String rawMaterial;
/**
* 原料信息:厚度mm
*/
private BigDecimal rawThick;
/**
* 原料信息:宽度mm
*/
private BigDecimal rawWidth;
/**
* 原料钢卷ID
*/
private Long rawMaterialId;
/**
* 原料卷号
*/
private String rawCoilNos;
/**
* 钢卷位置
*/
private String rawLocation;
/**
* 包装要求
*/
private String rawPackaging;
/**
* 宽度要求
*/
private String rawEdgeReq;
/**
* 镀层种类
*/
private String rawCoatingType;
/**
* 原料净重
*/
private BigDecimal rawNetWeight;
/**
* 成品信息:成品名称
*/
private String productName;
/**
* 成品信息:材质
*/
private String productMaterial;
/**
* 成品信息:镀层g
*/
private BigDecimal coatingG;
/**
* 成品信息:成品宽度
*/
private BigDecimal productWidth;
/**
* 成品信息:轧制厚度
*/
private BigDecimal rollingThick;
/**
* 成品信息:标签厚度
*/
private BigDecimal markCoatThick;
/**
* 成品信息:吨钢长度区间m
*/
private String tonSteelLengthRange;
/**
* 成品信息:数量
*/
private BigDecimal planQty;
/**
* 成品信息:重量
*/
private BigDecimal planWeight;
/**
* 成品信息:表面处理
*/
private String surfaceTreatment;
/**
* 成品信息:切边要求
*/
private String widthReq;
/**
* 成品信息:包装要求
*/
private String productPackaging;
/**
* 成品信息:宽度要求
*/
private String productEdgeReq;
/**
* 成品信息:用途
*/
private String usageReq;
/**
* 后处理
*/
private String postProcess;
/**
* 下工序
*/
private String nextProcess;
/**
* 取样
*/
private String sampleReq;
/**
* 生产开始时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/**
* 生产结束时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
/**
* 备注
*/
private String remark;
/**
* 删除标记(0正常 1删除)
*/
@TableLogic
private Long delFlag;
}

View File

@@ -0,0 +1,66 @@
package com.klp.aps.domain.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* 排产单主对象 aps_plan_sheet
*
* @author klp
* @date 2026-03-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("aps_plan_sheet")
public class ApsPlanSheet extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 排产单主键ID
*/
@TableId(value = "plan_sheet_id")
private Long planSheetId;
/**
* 排产日期
*/
@JsonFormat(pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date planDate;
/**
* 产线ID
*/
private Long lineId;
/**
* 产线名称
*/
private String lineName;
/**
* 排产单号
*/
private String planCode;
/**
* 排产类型
*/
private String planType;
/**
* 排产人
*/
private String scheduler;
/**
* 备注
*/
private String remark;
/**
* 删除标记(0正常 1删除)
*/
@TableLogic
private Long delFlag;
}

View File

@@ -0,0 +1,271 @@
package com.klp.aps.domain.vo;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
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 org.springframework.format.annotation.DateTimeFormat;
/**
* 排产单明细视图对象 aps_plan_detail
*
* @author klp
* @date 2026-03-26
*/
@Data
@ExcelIgnoreUnannotated
public class ApsPlanDetailVo {
private static final long serialVersionUID = 1L;
/**
* 排产明细主键ID
*/
@ExcelProperty(value = "排产明细主键ID")
private Long planDetailId;
/**
* 关联排产单ID
*/
@ExcelProperty(value = "关联排产单ID")
private Long planSheetId;
/**
* 内容序号
*/
@ExcelProperty(value = "内容序号")
private String bizSeqNo;
/**
* 订单ID
*/
@ExcelProperty(value = "订单ID")
private Long orderId;
/**
* 销售内容:订单号
*/
@ExcelProperty(value = "销售内容:订单号")
private String orderCode;
/**
* 销售内容:订单合同号
*/
@ExcelProperty(value = "销售内容:订单合同号")
private String contractCode;
/**
* 销售内容:客户
*/
@ExcelProperty(value = "销售内容:客户")
private String customerName;
/**
* 销售内容:业务员
*/
@ExcelProperty(value = "销售内容:业务员")
private String salesman;
/**
* 原料信息:厂家
*/
@ExcelProperty(value = "原料信息:厂家")
private String rawManufacturer;
/**
* 原料信息:材质
*/
@ExcelProperty(value = "原料信息:材质")
private String rawMaterial;
/**
* 原料信息:厚度mm
*/
@ExcelProperty(value = "原料信息:厚度mm")
private BigDecimal rawThick;
/**
* 原料信息:宽度mm
*/
@ExcelProperty(value = "原料信息:宽度mm")
private BigDecimal rawWidth;
/**
* 原料钢卷ID
*/
@ExcelProperty(value = "原料钢卷ID")
private Long rawMaterialId;
/**
* 原料卷号
*/
@ExcelProperty(value = "原料卷号")
private String rawCoilNos;
/**
* 钢卷位置
*/
@ExcelProperty(value = "钢卷位置")
private String rawLocation;
/**
* 包装要求
*/
@ExcelProperty(value = "包装要求")
private String rawPackaging;
/**
* 宽度要求
*/
@ExcelProperty(value = "宽度要求")
private String rawEdgeReq;
/**
* 镀层种类
*/
@ExcelProperty(value = "镀层种类")
private String rawCoatingType;
/**
* 原料净重
*/
@ExcelProperty(value = "原料净重")
private BigDecimal rawNetWeight;
/**
* 成品信息:成品名称
*/
@ExcelProperty(value = "成品信息:成品名称")
private String productName;
/**
* 成品信息:材质
*/
@ExcelProperty(value = "成品信息:材质")
private String productMaterial;
/**
* 成品信息:镀层g
*/
@ExcelProperty(value = "成品信息:镀层g")
private BigDecimal coatingG;
/**
* 成品信息:成品宽度
*/
@ExcelProperty(value = "成品信息:成品宽度")
private BigDecimal productWidth;
/**
* 成品信息:轧制厚度
*/
@ExcelProperty(value = "成品信息:轧制厚度")
private BigDecimal rollingThick;
/**
* 成品信息:标签厚度
*/
@ExcelProperty(value = "成品信息:标签厚度")
private BigDecimal markCoatThick;
/**
* 成品信息:吨钢长度区间m
*/
@ExcelProperty(value = "成品信息:吨钢长度区间m")
private String tonSteelLengthRange;
/**
* 成品信息:数量
*/
@ExcelProperty(value = "成品信息:数量")
private BigDecimal planQty;
/**
* 成品信息:重量
*/
@ExcelProperty(value = "成品信息:重量")
private BigDecimal planWeight;
/**
* 成品信息:表面处理
*/
@ExcelProperty(value = "成品信息:表面处理")
private String surfaceTreatment;
/**
* 成品信息:切边要求
*/
@ExcelProperty(value = "成品信息:切边要求")
private String widthReq;
/**
* 成品信息:包装要求
*/
@ExcelProperty(value = "成品信息:包装要求")
private String productPackaging;
/**
* 成品信息:宽度要求
*/
@ExcelProperty(value = "成品信息:宽度要求")
private String productEdgeReq;
/**
* 成品信息:用途
*/
@ExcelProperty(value = "成品信息:用途")
private String usageReq;
/**
* 后处理
*/
@ExcelProperty(value = "后处理")
private String postProcess;
/**
* 下工序
*/
@ExcelProperty(value = "下工序")
private String nextProcess;
/**
* 取样
*/
@ExcelProperty(value = "取样")
private String sampleReq;
/**
* 生产开始时间
*/
@ExcelProperty(value = "生产开始时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/**
* 生产结束时间
*/
@ExcelProperty(value = "生产结束时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 技术附件
*/
@ExcelProperty(value = "技术附件")
private String techAnnex;
}

View File

@@ -0,0 +1,56 @@
package com.klp.aps.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class ApsPlanSheetRowVo {
private Long detailSheetId;
private java.time.LocalDate planDate;
private Long lineId;
private String lineName;
private String planCode;
private String planType;
private String scheduler;
private String masterRemark;
private String updateBy;
private String bizSeqNo;
private String orderCode;
private String contractCode;
private String customerName;
private String salesman;
private String productName;
private String productMaterial;
private BigDecimal coatingG;
private BigDecimal productWidth;
private BigDecimal rollingThick;
private BigDecimal markCoatThick;
private String tonSteelLengthRange;
private BigDecimal planQty;
private BigDecimal planWeight;
private String surfaceTreatment;
private String widthReq;
private String usageReq;
private String postProcess;
private String nextProcess;
private String sampleReq;
private String rawManufacturer;
private String rawMaterial;
private BigDecimal rawThick;
private BigDecimal rawWidth;
private String rawMaterialId;
private String rawCoilNos;
private String rawLocation;
private String rawPackaging;
private String rawEdgeReq;
private String rawCoatingType;
private BigDecimal rawNetWeight;
private LocalDateTime startTime;
private LocalDateTime endTime;
private String detailRemark;
}

View File

@@ -0,0 +1,76 @@
package com.klp.aps.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
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 org.springframework.format.annotation.DateTimeFormat;
/**
* 排产单主视图对象 aps_plan_sheet
*
* @author klp
* @date 2026-03-26
*/
@Data
@ExcelIgnoreUnannotated
public class ApsPlanSheetVo {
private static final long serialVersionUID = 1L;
/**
* 排产单主键ID
*/
@ExcelProperty(value = "排产单主键ID")
private Long planSheetId;
/**
* 排产日期
*/
@ExcelProperty(value = "排产日期")
@JsonFormat(pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date planDate;
/**
* 产线ID
*/
@ExcelProperty(value = "产线ID")
private Long lineId;
/**
* 产线名称
*/
@ExcelProperty(value = "产线名称")
private String lineName;
/**
* 排产单号
*/
@ExcelProperty(value = "排产单号")
private String planCode;
/**
* 排产类型
*/
@ExcelProperty(value = "排产类型")
private String planType;
/**
* 排产人
*/
@ExcelProperty(value = "排产人")
private String scheduler;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -0,0 +1,24 @@
package com.klp.aps.mapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.klp.aps.domain.entity.ApsPlanDetail;
import com.klp.aps.domain.vo.ApsPlanDetailVo;
import com.klp.common.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
/**
* 排产单明细Mapper接口
*
* @author klp
* @date 2026-03-26
*/
public interface ApsPlanDetailMapper extends BaseMapperPlus<ApsPlanDetailMapper, ApsPlanDetail, ApsPlanDetailVo> {
int deleteByPlanSheetIds(Collection<Long> planSheetIds);
Page<ApsPlanDetailVo> selectVoPagePlus(Page<ApsPlanDetailVo> page, @Param("ew") QueryWrapper<ApsPlanDetail> queryWrapper);
}

View File

@@ -0,0 +1,22 @@
package com.klp.aps.mapper;
import com.klp.aps.domain.dto.ApsPlanSheetQueryReq;
import com.klp.aps.domain.dto.ApsQuickSheetQueryReq;
import com.klp.aps.domain.entity.ApsPlanSheet;
import com.klp.aps.domain.vo.ApsPlanSheetRowVo;
import com.klp.aps.domain.vo.ApsPlanSheetVo;
import com.klp.aps.domain.vo.ApsQuickSheetRowVo;
import com.klp.common.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* 排产单主Mapper接口
*
* @author klp
* @date 2026-03-26
*/
public interface ApsPlanSheetMapper extends BaseMapperPlus<ApsPlanSheetMapper, ApsPlanSheet, ApsPlanSheetVo> {
List<ApsPlanSheetRowVo> selectListByReq(ApsPlanSheetQueryReq req);
}

View File

@@ -0,0 +1,58 @@
package com.klp.aps.service;
import com.klp.aps.domain.vo.ApsPlanDetailVo;
import com.klp.aps.domain.bo.ApsPlanDetailBo;
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-03-26
*/
public interface IApsPlanDetailService {
/**
* 查询排产单明细
*/
ApsPlanDetailVo queryById(Long planDetailId);
/**
* 查询排产单明细列表
*/
TableDataInfo<ApsPlanDetailVo> queryPageList(ApsPlanDetailBo bo, PageQuery pageQuery);
/**
* 查询排产单明细列表
*/
List<ApsPlanDetailVo> queryList(ApsPlanDetailBo bo);
/**
* 根据排产单ID列表查询明细
*/
List<ApsPlanDetailVo> queryListByPlanSheetIds(List<Long> planSheetIds);
/**
* 新增排产单明细
*/
Boolean insertByBo(ApsPlanDetailBo bo);
/**
* 修改排产单明细
*/
Boolean updateByBo(ApsPlanDetailBo bo);
/**
* 校验并批量删除排产单明细信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据排产单ID删除明细
*/
int deleteByPlanSheetIds(Collection<Long> planSheetIds);
}

View File

@@ -0,0 +1,54 @@
package com.klp.aps.service;
import com.klp.aps.domain.dto.ApsPlanSheetQueryReq;
import com.klp.aps.domain.dto.ApsQuickSheetQueryReq;
import com.klp.aps.domain.vo.ApsPlanSheetVo;
import com.klp.aps.domain.bo.ApsPlanSheetBo;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.List;
/**
* 排产单主Service接口
*
* @author klp
* @date 2026-03-26
*/
public interface IApsPlanSheetService {
/**
* 查询排产单主
*/
ApsPlanSheetVo queryById(Long planSheetId);
/**
* 查询排产单主列表
*/
TableDataInfo<ApsPlanSheetVo> queryPageList(ApsPlanSheetBo bo, PageQuery pageQuery);
/**
* 查询排产单主列表
*/
List<ApsPlanSheetVo> queryList(ApsPlanSheetBo bo);
/**
* 新增排产单主
*/
Boolean insertByBo(ApsPlanSheetBo bo);
/**
* 修改排产单主
*/
Boolean updateByBo(ApsPlanSheetBo bo);
/**
* 校验并批量删除排产单主信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
void exportExcel(ApsPlanSheetQueryReq req, HttpServletResponse response);
}

View File

@@ -0,0 +1,210 @@
package com.klp.aps.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.aps.domain.bo.ApsPlanDetailBo;
import com.klp.aps.domain.vo.ApsPlanDetailVo;
import com.klp.aps.domain.entity.ApsPlanDetail;
import com.klp.aps.mapper.ApsPlanDetailMapper;
import com.klp.aps.service.IApsPlanDetailService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 排产单明细Service业务层处理
*
* @author klp
* @date 2026-03-26
*/
@RequiredArgsConstructor
@Service
public class ApsPlanDetailServiceImpl implements IApsPlanDetailService {
private final ApsPlanDetailMapper baseMapper;
/**
* 查询排产单明细
*/
@Override
public ApsPlanDetailVo queryById(Long planDetailId){
return baseMapper.selectVoById(planDetailId);
}
/**
* 查询排产单明细列表
*/
@Override
public TableDataInfo<ApsPlanDetailVo> queryPageList(ApsPlanDetailBo bo, PageQuery pageQuery) {
QueryWrapper<ApsPlanDetail> qw = buildQueryWrapperPlus(bo);
Page<ApsPlanDetailVo> result = baseMapper.selectVoPagePlus(pageQuery.build(), qw);
return TableDataInfo.build(result);
}
private QueryWrapper<ApsPlanDetail> buildQueryWrapperPlus(ApsPlanDetailBo bo) {
Map<String, Object> params = bo.getParams();
QueryWrapper<ApsPlanDetail> qw = new QueryWrapper<>();
qw.eq("d.del_flag", 0);
qw.eq(bo.getPlanSheetId() != null, "d.plan_sheet_id", bo.getPlanSheetId());
qw.eq(bo.getOrderId() != null, "d.order_id", bo.getOrderId());
qw.eq(StringUtils.isNotBlank(bo.getBizSeqNo()), "d.biz_seq_no", bo.getBizSeqNo());
qw.eq(StringUtils.isNotBlank(bo.getOrderCode()), "d.order_code", bo.getOrderCode());
qw.eq(StringUtils.isNotBlank(bo.getContractCode()), "d.contract_code", bo.getContractCode());
qw.like(StringUtils.isNotBlank(bo.getCustomerName()), "d.customer_name", bo.getCustomerName());
qw.eq(StringUtils.isNotBlank(bo.getSalesman()), "d.salesman", bo.getSalesman());
qw.eq(StringUtils.isNotBlank(bo.getRawManufacturer()), "d.raw_manufacturer", bo.getRawManufacturer());
qw.eq(StringUtils.isNotBlank(bo.getRawMaterial()), "d.raw_material", bo.getRawMaterial());
qw.eq(bo.getRawThick() != null, "d.raw_thick", bo.getRawThick());
qw.eq(bo.getRawWidth() != null, "d.raw_width", bo.getRawWidth());
qw.eq(bo.getRawMaterialId() != null, "d.raw_material_id", bo.getRawMaterialId());
qw.eq(StringUtils.isNotBlank(bo.getRawCoilNos()), "d.raw_coil_nos", bo.getRawCoilNos());
qw.eq(StringUtils.isNotBlank(bo.getRawLocation()), "d.raw_location", bo.getRawLocation());
qw.eq(StringUtils.isNotBlank(bo.getRawPackaging()), "d.raw_packaging", bo.getRawPackaging());
qw.eq(StringUtils.isNotBlank(bo.getRawEdgeReq()), "d.raw_edge_req", bo.getRawEdgeReq());
qw.eq(StringUtils.isNotBlank(bo.getRawCoatingType()), "d.raw_coating_type", bo.getRawCoatingType());
qw.eq(bo.getRawNetWeight() != null, "d.raw_net_weight", bo.getRawNetWeight());
qw.like(StringUtils.isNotBlank(bo.getProductName()), "d.product_name", bo.getProductName());
qw.eq(StringUtils.isNotBlank(bo.getProductMaterial()), "d.product_material", bo.getProductMaterial());
qw.eq(bo.getCoatingG() != null, "d.coating_g", bo.getCoatingG());
qw.eq(bo.getProductWidth() != null, "d.product_width", bo.getProductWidth());
qw.eq(bo.getRollingThick() != null, "d.rolling_thick", bo.getRollingThick());
qw.eq(bo.getMarkCoatThick() != null, "d.mark_coat_thick", bo.getMarkCoatThick());
qw.eq(StringUtils.isNotBlank(bo.getTonSteelLengthRange()), "d.ton_steel_length_range", bo.getTonSteelLengthRange());
qw.eq(bo.getPlanQty() != null, "d.plan_qty", bo.getPlanQty());
qw.eq(bo.getPlanWeight() != null, "d.plan_weight", bo.getPlanWeight());
qw.eq(StringUtils.isNotBlank(bo.getSurfaceTreatment()), "d.surface_treatment", bo.getSurfaceTreatment());
qw.eq(StringUtils.isNotBlank(bo.getWidthReq()), "d.width_req", bo.getWidthReq());
qw.eq(StringUtils.isNotBlank(bo.getProductPackaging()), "d.product_packaging", bo.getProductPackaging());
qw.eq(StringUtils.isNotBlank(bo.getProductEdgeReq()), "d.product_edge_req", bo.getProductEdgeReq());
qw.eq(StringUtils.isNotBlank(bo.getUsageReq()), "d.usage_req", bo.getUsageReq());
qw.eq(StringUtils.isNotBlank(bo.getPostProcess()), "d.post_process", bo.getPostProcess());
qw.eq(StringUtils.isNotBlank(bo.getNextProcess()), "d.next_process", bo.getNextProcess());
qw.eq(StringUtils.isNotBlank(bo.getSampleReq()), "d.sample_req", bo.getSampleReq());
qw.eq(bo.getStartTime() != null, "d.start_time", bo.getStartTime());
qw.eq(bo.getEndTime() != null, "d.end_time", bo.getEndTime());
//根据创建时间倒叙
qw.orderByDesc("d.create_time");
return qw;
}
/**
* 查询排产单明细列表
*/
@Override
public List<ApsPlanDetailVo> queryList(ApsPlanDetailBo bo) {
LambdaQueryWrapper<ApsPlanDetail> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
/**
* 根据排产单ID列表查询明细
*/
@Override
public List<ApsPlanDetailVo> queryListByPlanSheetIds(List<Long> planSheetIds) {
if (planSheetIds == null || planSheetIds.isEmpty()) {
return new java.util.ArrayList<>();
}
LambdaQueryWrapper<ApsPlanDetail> lqw = Wrappers.lambdaQuery();
lqw.in(ApsPlanDetail::getPlanSheetId, planSheetIds);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<ApsPlanDetail> buildQueryWrapper(ApsPlanDetailBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<ApsPlanDetail> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getPlanSheetId() != null, ApsPlanDetail::getPlanSheetId, bo.getPlanSheetId());
lqw.eq(StringUtils.isNotBlank(bo.getBizSeqNo()), ApsPlanDetail::getBizSeqNo, bo.getBizSeqNo());
lqw.eq(bo.getOrderId() != null, ApsPlanDetail::getOrderId, bo.getOrderId());
lqw.eq(StringUtils.isNotBlank(bo.getOrderCode()), ApsPlanDetail::getOrderCode, bo.getOrderCode());
lqw.eq(StringUtils.isNotBlank(bo.getContractCode()), ApsPlanDetail::getContractCode, bo.getContractCode());
lqw.like(StringUtils.isNotBlank(bo.getCustomerName()), ApsPlanDetail::getCustomerName, bo.getCustomerName());
lqw.eq(StringUtils.isNotBlank(bo.getSalesman()), ApsPlanDetail::getSalesman, bo.getSalesman());
lqw.eq(StringUtils.isNotBlank(bo.getRawManufacturer()), ApsPlanDetail::getRawManufacturer, bo.getRawManufacturer());
lqw.eq(StringUtils.isNotBlank(bo.getRawMaterial()), ApsPlanDetail::getRawMaterial, bo.getRawMaterial());
lqw.eq(bo.getRawThick() != null, ApsPlanDetail::getRawThick, bo.getRawThick());
lqw.eq(bo.getRawWidth() != null, ApsPlanDetail::getRawWidth, bo.getRawWidth());
lqw.eq(bo.getRawMaterialId() != null, ApsPlanDetail::getRawMaterialId, bo.getRawMaterialId());
lqw.eq(StringUtils.isNotBlank(bo.getRawCoilNos()), ApsPlanDetail::getRawCoilNos, bo.getRawCoilNos());
lqw.eq(StringUtils.isNotBlank(bo.getRawLocation()), ApsPlanDetail::getRawLocation, bo.getRawLocation());
lqw.eq(StringUtils.isNotBlank(bo.getRawPackaging()), ApsPlanDetail::getRawPackaging, bo.getRawPackaging());
lqw.eq(StringUtils.isNotBlank(bo.getRawEdgeReq()), ApsPlanDetail::getRawEdgeReq, bo.getRawEdgeReq());
lqw.eq(StringUtils.isNotBlank(bo.getRawCoatingType()), ApsPlanDetail::getRawCoatingType, bo.getRawCoatingType());
lqw.eq(bo.getRawNetWeight() != null, ApsPlanDetail::getRawNetWeight, bo.getRawNetWeight());
lqw.like(StringUtils.isNotBlank(bo.getProductName()), ApsPlanDetail::getProductName, bo.getProductName());
lqw.eq(StringUtils.isNotBlank(bo.getProductMaterial()), ApsPlanDetail::getProductMaterial, bo.getProductMaterial());
lqw.eq(bo.getCoatingG() != null, ApsPlanDetail::getCoatingG, bo.getCoatingG());
lqw.eq(bo.getProductWidth() != null, ApsPlanDetail::getProductWidth, bo.getProductWidth());
lqw.eq(bo.getRollingThick() != null, ApsPlanDetail::getRollingThick, bo.getRollingThick());
lqw.eq(bo.getMarkCoatThick() != null, ApsPlanDetail::getMarkCoatThick, bo.getMarkCoatThick());
lqw.eq(StringUtils.isNotBlank(bo.getTonSteelLengthRange()), ApsPlanDetail::getTonSteelLengthRange, bo.getTonSteelLengthRange());
lqw.eq(bo.getPlanQty() != null, ApsPlanDetail::getPlanQty, bo.getPlanQty());
lqw.eq(bo.getPlanWeight() != null, ApsPlanDetail::getPlanWeight, bo.getPlanWeight());
lqw.eq(StringUtils.isNotBlank(bo.getSurfaceTreatment()), ApsPlanDetail::getSurfaceTreatment, bo.getSurfaceTreatment());
lqw.eq(StringUtils.isNotBlank(bo.getWidthReq()), ApsPlanDetail::getWidthReq, bo.getWidthReq());
lqw.eq(StringUtils.isNotBlank(bo.getProductPackaging()), ApsPlanDetail::getProductPackaging, bo.getProductPackaging());
lqw.eq(StringUtils.isNotBlank(bo.getProductEdgeReq()), ApsPlanDetail::getProductEdgeReq, bo.getProductEdgeReq());
lqw.eq(StringUtils.isNotBlank(bo.getUsageReq()), ApsPlanDetail::getUsageReq, bo.getUsageReq());
lqw.eq(StringUtils.isNotBlank(bo.getPostProcess()), ApsPlanDetail::getPostProcess, bo.getPostProcess());
lqw.eq(StringUtils.isNotBlank(bo.getNextProcess()), ApsPlanDetail::getNextProcess, bo.getNextProcess());
lqw.eq(StringUtils.isNotBlank(bo.getSampleReq()), ApsPlanDetail::getSampleReq, bo.getSampleReq());
lqw.eq(bo.getStartTime() != null, ApsPlanDetail::getStartTime, bo.getStartTime());
lqw.eq(bo.getEndTime() != null, ApsPlanDetail::getEndTime, bo.getEndTime());
return lqw;
}
/**
* 新增排产单明细
*/
@Override
public Boolean insertByBo(ApsPlanDetailBo bo) {
ApsPlanDetail add = BeanUtil.toBean(bo, ApsPlanDetail.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setPlanDetailId(add.getPlanDetailId());
}
return flag;
}
/**
* 修改排产单明细
*/
@Override
public Boolean updateByBo(ApsPlanDetailBo bo) {
ApsPlanDetail update = BeanUtil.toBean(bo, ApsPlanDetail.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(ApsPlanDetail entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除排产单明细
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
public int deleteByPlanSheetIds(Collection<Long> planSheetIds) {
return baseMapper.deleteByPlanSheetIds(planSheetIds);
}
}

View File

@@ -0,0 +1,329 @@
package com.klp.aps.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.klp.aps.domain.dto.ApsPlanSheetQueryReq;
import com.klp.aps.domain.dto.ApsQuickSheetQueryReq;
import com.klp.aps.domain.vo.ApsPlanSheetRowVo;
import com.klp.aps.domain.vo.ApsQuickSheetRowVo;
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.exception.ServiceException;
import com.klp.common.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import com.klp.aps.domain.bo.ApsPlanSheetBo;
import com.klp.aps.domain.vo.ApsPlanSheetVo;
import com.klp.aps.domain.entity.ApsPlanSheet;
import com.klp.aps.mapper.ApsPlanSheetMapper;
import com.klp.aps.service.IApsPlanSheetService;
import com.klp.aps.service.IApsPlanDetailService;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 排产单主Service业务层处理
*
* @author klp
* @date 2026-03-26
*/
@RequiredArgsConstructor
@Service
public class ApsPlanSheetServiceImpl implements IApsPlanSheetService {
private final ApsPlanSheetMapper baseMapper;
private final IApsPlanDetailService planDetailService;
/**
* 查询排产单主
*/
@Override
public ApsPlanSheetVo queryById(Long planSheetId) {
return baseMapper.selectVoById(planSheetId);
}
/**
* 查询排产单主列表
*/
@Override
public TableDataInfo<ApsPlanSheetVo> queryPageList(ApsPlanSheetBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<ApsPlanSheet> lqw = buildQueryWrapper(bo);
Page<ApsPlanSheetVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询排产单主列表
*/
@Override
public List<ApsPlanSheetVo> queryList(ApsPlanSheetBo bo) {
LambdaQueryWrapper<ApsPlanSheet> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<ApsPlanSheet> buildQueryWrapper(ApsPlanSheetBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<ApsPlanSheet> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getPlanDate() != null, ApsPlanSheet::getPlanDate, bo.getPlanDate());
lqw.eq(bo.getLineId() != null, ApsPlanSheet::getLineId, bo.getLineId());
lqw.like(StringUtils.isNotBlank(bo.getLineName()), ApsPlanSheet::getLineName, bo.getLineName());
lqw.eq(StringUtils.isNotBlank(bo.getPlanCode()), ApsPlanSheet::getPlanCode, bo.getPlanCode());
lqw.eq(StringUtils.isNotBlank(bo.getPlanType()), ApsPlanSheet::getPlanType, bo.getPlanType());
lqw.eq(StringUtils.isNotBlank(bo.getScheduler()), ApsPlanSheet::getScheduler, bo.getScheduler());
return lqw;
}
/**
* 新增排产单主
*/
@Override
public Boolean insertByBo(ApsPlanSheetBo bo) {
ApsPlanSheet add = BeanUtil.toBean(bo, ApsPlanSheet.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setPlanSheetId(add.getPlanSheetId());
}
return flag;
}
/**
* 修改排产单主
*/
@Override
public Boolean updateByBo(ApsPlanSheetBo bo) {
ApsPlanSheet update = BeanUtil.toBean(bo, ApsPlanSheet.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(ApsPlanSheet entity) {
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除排产单主
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
planDetailService.deleteByPlanSheetIds(ids);
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
public void exportExcel(ApsPlanSheetQueryReq req, HttpServletResponse response) {
List<ApsPlanSheetRowVo> rows = queryListAll(req);
try (Workbook wb = new XSSFWorkbook()) {
Sheet sheet = wb.createSheet("快速排产表");
int r = 0;
Row title = sheet.createRow(r++);
title.setHeightInPoints(36f);
Cell t0 = title.createCell(0);
Long planSheetId = req.getPlanSheetId();
if (planSheetId != null) {
ApsPlanSheetVo planSheet = queryById(planSheetId);
// 格式化日期
String dateStr = "";
if (planSheet.getPlanDate() != null) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
dateStr = sdf.format(planSheet.getPlanDate());
}
t0.setCellValue(dateStr + "————" + planSheet.getLineName() + "————" + planSheet.getPlanCode());
} else {
t0.setCellValue("快速排产表");
}
// 1. 先创建标题样式
CellStyle titleStyle = wb.createCellStyle();
titleStyle.setAlignment(HorizontalAlignment.CENTER);
titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
XSSFFont titleFont = ((XSSFWorkbook) wb).createFont();
titleFont.setBold(true);
titleFont.setFontHeightInPoints((short) 15);
titleStyle.setFont(titleFont);
// 2. 合并区域
CellRangeAddress titleRegion = new CellRangeAddress(0, 0, 0, 40);
sheet.addMergedRegion(titleRegion);
// 3. 给【整个合并区域】设置样式
for (int i = titleRegion.getFirstColumn(); i <= titleRegion.getLastColumn(); i++) {
Cell cell = title.getCell(i);
if (cell == null) {
cell = title.createCell(i);
}
cell.setCellStyle(titleStyle);
}
String[] headers = new String[]{
"产线", "排产日期", "排产单号", "排产类型", "排产人", "修改人", "计划备注",
"内容序号", "销售内容", "订单合同号", "客户", "业务员",
"成品名称", "材质", "镀层g", "成品宽度", "轧制厚度", "标丝厚度", "吨钢长度区间m",
"数量", "重量", "表面处理", "切边要求", "宽度要求", "用途", "后处理", "下工序", "取样",
"厂家", "原料信息", "原料厚度mm", "宽度mm", "原料钢卷", "原料卷号", "钢卷位置", "包装要求", "镀层种类", "原料净重",
"开始时间", "结束时间", "明细备注"
};
// ===================== 【绝对不报错】表头样式 =====================
org.apache.poi.ss.usermodel.CellStyle headStyle = wb.createCellStyle();
org.apache.poi.ss.usermodel.Font headFont = wb.createFont();
// 1. 字体加粗
headFont.setBold(true);
headStyle.setFont(headFont);
// 2. 居中
headStyle.setAlignment(org.apache.poi.ss.usermodel.HorizontalAlignment.CENTER);
headStyle.setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment.CENTER);
// 3. 背景颜色(浅蓝色)
headStyle.setFillPattern(org.apache.poi.ss.usermodel.FillPatternType.SOLID_FOREGROUND);
headStyle.setFillForegroundColor(org.apache.poi.ss.usermodel.IndexedColors.PALE_BLUE.getIndex());
// 4. 自动换行
headStyle.setWrapText(true);
// 创建表头行
org.apache.poi.ss.usermodel.Row head = sheet.createRow(r++);
head.setHeightInPoints(24);
// 设置表头内容 + 样式
for (int i = 0; i < headers.length; i++) {
org.apache.poi.ss.usermodel.Cell cell = head.createCell(i);
cell.setCellValue(headers[i]);
cell.setCellStyle(headStyle);
}
// ================== 【统一样式前7列居中】 ==================
CellStyle centerStyle = wb.createCellStyle();
centerStyle.setAlignment(HorizontalAlignment.CENTER);
centerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// ================== 数据行 ==================
int dataStartRow = r;
if (rows != null && !rows.isEmpty()) {
for (ApsPlanSheetRowVo row : rows) {
Row rr = sheet.createRow(r++);
int cc = 0;
// ====== 前7列相同内容需要居中 + 后续合并 ======
rr.createCell(cc++).setCellValue(nvl(row.getLineName(), row.getLineId()));
rr.createCell(cc++).setCellValue(row.getPlanDate() == null ? "" : row.getPlanDate().toString());
rr.createCell(cc++).setCellValue(nvl(row.getPlanCode(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getPlanType(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getScheduler(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getUpdateBy(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getMasterRemark(), ""));
// 前7列设置居中
for (int i = 0; i < 7; i++) {
rr.getCell(i).setCellStyle(centerStyle);
}
// ====== 后面列不变 ======
rr.createCell(cc++).setCellValue(nvl(row.getBizSeqNo(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getOrderCode(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getContractCode(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getCustomerName(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getSalesman(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getProductName(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getProductMaterial(), ""));
rr.createCell(cc++).setCellValue(row.getCoatingG() == null ? "" : row.getCoatingG().toPlainString());
rr.createCell(cc++).setCellValue(row.getProductWidth() == null ? "" : row.getProductWidth().toPlainString());
rr.createCell(cc++).setCellValue(row.getRollingThick() == null ? "" : row.getRollingThick().toPlainString());
rr.createCell(cc++).setCellValue(row.getMarkCoatThick() == null ? "" : row.getMarkCoatThick().toPlainString());
rr.createCell(cc++).setCellValue(nvl(row.getTonSteelLengthRange(), ""));
rr.createCell(cc++).setCellValue(row.getPlanQty() == null ? "" : row.getPlanQty().toPlainString());
rr.createCell(cc++).setCellValue(row.getPlanWeight() == null ? "" : row.getPlanWeight().toPlainString());
rr.createCell(cc++).setCellValue(nvl(row.getSurfaceTreatment(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getWidthReq(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawEdgeReq(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getUsageReq(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getPostProcess(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getNextProcess(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getSampleReq(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawManufacturer(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawMaterial(), ""));
rr.createCell(cc++).setCellValue(row.getRawThick() == null ? "" : row.getRawThick().toPlainString());
rr.createCell(cc++).setCellValue(row.getRawWidth() == null ? "" : row.getRawWidth().toPlainString());
rr.createCell(cc++).setCellValue(nvl(row.getRawMaterialId(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawCoilNos(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawLocation(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawPackaging(), ""));
rr.createCell(cc++).setCellValue(nvl(row.getRawCoatingType(), ""));
rr.createCell(cc++).setCellValue(row.getRawNetWeight() == null ? "" : row.getRawNetWeight().toPlainString());
rr.createCell(cc++).setCellValue(row.getStartTime() == null ? "" : row.getStartTime().toString());
rr.createCell(cc++).setCellValue(row.getEndTime() == null ? "" : row.getEndTime().toString());
rr.createCell(cc++).setCellValue(nvl(row.getDetailRemark(), ""));
}
}
// ================== 【核心前7列自动合并】 ==================
int dataEndRow = r - 1;
if (dataStartRow <= dataEndRow) {
for (int col = 0; col < 7; col++) { // 0~6 共7列
CellRangeAddress region = new CellRangeAddress(
dataStartRow,
dataEndRow,
col,
col
);
sheet.addMergedRegion(region);
}
}
// 自适应列宽
for (int i = 0; i < headers.length; i++) {
sheet.autoSizeColumn(i, true);
int w = sheet.getColumnWidth(i);
sheet.setColumnWidth(i, Math.min(Math.max(w, 3000), 12000));
}
String filename = "aps_quick_sheet_" + System.currentTimeMillis() + ".xlsx";
String encoded = URLEncoder.encode(filename, StandardCharsets.UTF_8.name());
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encoded);
try (ServletOutputStream os = response.getOutputStream()) {
wb.write(os);
os.flush();
}
} catch (IOException e) {
throw new ServiceException("导出失败:" + e.getMessage());
}
}
private List<ApsPlanSheetRowVo> queryListAll(ApsPlanSheetQueryReq req) {
return baseMapper.selectListByReq(req);
}
private String nvl(Object v, Object fallback) {
if (v == null) return String.valueOf(fallback);
String s = String.valueOf(v);
return s == null ? String.valueOf(fallback) : s;
}
}

View File

@@ -0,0 +1,71 @@
<?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.aps.mapper.ApsPlanDetailMapper">
<resultMap type="com.klp.aps.domain.entity.ApsPlanDetail" id="ApsPlanDetailResult">
<result property="planDetailId" column="plan_detail_id"/>
<result property="planSheetId" column="plan_sheet_id"/>
<result property="bizSeqNo" column="biz_seq_no"/>
<result property="orderId" column="order_id"/>
<result property="orderCode" column="order_code"/>
<result property="contractCode" column="contract_code"/>
<result property="customerName" column="customer_name"/>
<result property="salesman" column="salesman"/>
<result property="rawManufacturer" column="raw_manufacturer"/>
<result property="rawMaterial" column="raw_material"/>
<result property="rawThick" column="raw_thick"/>
<result property="rawWidth" column="raw_width"/>
<result property="rawMaterialId" column="raw_material_id"/>
<result property="rawCoilNos" column="raw_coil_nos"/>
<result property="rawLocation" column="raw_location"/>
<result property="rawPackaging" column="raw_packaging"/>
<result property="rawEdgeReq" column="raw_edge_req"/>
<result property="rawCoatingType" column="raw_coating_type"/>
<result property="rawNetWeight" column="raw_net_weight"/>
<result property="productName" column="product_name"/>
<result property="productMaterial" column="product_material"/>
<result property="coatingG" column="coating_g"/>
<result property="productWidth" column="product_width"/>
<result property="rollingThick" column="rolling_thick"/>
<result property="markCoatThick" column="mark_coat_thick"/>
<result property="tonSteelLengthRange" column="ton_steel_length_range"/>
<result property="planQty" column="plan_qty"/>
<result property="planWeight" column="plan_weight"/>
<result property="surfaceTreatment" column="surface_treatment"/>
<result property="widthReq" column="width_req"/>
<result property="productPackaging" column="product_packaging"/>
<result property="productEdgeReq" column="product_edge_req"/>
<result property="usageReq" column="usage_req"/>
<result property="postProcess" column="post_process"/>
<result property="nextProcess" column="next_process"/>
<result property="sampleReq" column="sample_req"/>
<result property="startTime" column="start_time"/>
<result property="endTime" column="end_time"/>
<result property="remark" column="remark"/>
<result property="delFlag" column="del_flag"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<delete id="deleteByPlanSheetIds">
UPDATE aps_plan_detail SET del_flag = 2 WHERE plan_sheet_id IN
<foreach collection="collection" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<select id="selectVoPagePlus" resultType="com.klp.aps.domain.vo.ApsPlanDetailVo">
SELECT
d.*,
c.tech_annex AS techAnnex
FROM aps_plan_detail d
LEFT JOIN crm_order o ON d.order_id = o.order_id AND o.del_flag = 0
LEFT JOIN crm_contract c ON o.contract_id = c.contract_id AND c.del_flag = 0
${ew.customSqlSegment}
</select>
</mapper>

View File

@@ -0,0 +1,77 @@
<?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.aps.mapper.ApsPlanSheetMapper">
<resultMap type="com.klp.aps.domain.entity.ApsPlanSheet" id="ApsPlanSheetResult">
<result property="planSheetId" column="plan_sheet_id"/>
<result property="planDate" column="plan_date"/>
<result property="lineId" column="line_id"/>
<result property="lineName" column="line_name"/>
<result property="planCode" column="plan_code"/>
<result property="planType" column="plan_type"/>
<result property="scheduler" column="scheduler"/>
<result property="remark" column="remark"/>
<result property="delFlag" column="del_flag"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<select id="selectListByReq" parameterType="com.klp.aps.domain.dto.ApsPlanSheetQueryReq" resultType="com.klp.aps.domain.vo.ApsPlanSheetRowVo">
SELECT
d.plan_detail_id AS detailSheetId,
s.plan_date AS planDate,
s.line_id AS lineId,
s.line_name AS lineName,
s.plan_code AS planCode,
s.plan_type AS planType,
s.scheduler AS scheduler,
s.remark AS masterRemark,
d.remark AS detailRemark,
s.update_by AS updateBy,
d.biz_seq_no AS bizSeqNo,
d.order_code AS orderCode,
d.contract_code AS contractCode,
d.customer_name AS customerName,
d.salesman AS salesman,
d.product_name AS productName,
d.product_material AS productMaterial,
d.coating_g AS coatingG,
d.product_width AS productWidth,
d.rolling_thick AS rollingThick,
d.mark_coat_thick AS markCoatThick,
d.ton_steel_length_range AS tonSteelLengthRange,
d.plan_qty AS planQty,
d.plan_weight AS planWeight,
d.surface_treatment AS surfaceTreatment,
d.width_req AS widthReq,
d.usage_req AS usageReq,
d.post_process AS postProcess,
d.next_process AS nextProcess,
d.sample_req AS sampleReq,
d.raw_manufacturer AS rawManufacturer,
d.raw_material AS rawMaterial,
d.raw_thick AS rawThick,
d.raw_width AS rawWidth,
CAST(d.raw_material_id AS CHAR) AS rawMaterialId,
d.raw_coil_nos AS rawCoilNos,
d.raw_location AS rawLocation,
d.raw_packaging AS rawPackaging,
d.raw_edge_req AS rawEdgeReq,
d.raw_coating_type AS rawCoatingType,
d.raw_net_weight AS rawNetWeight,
d.start_time AS startTime,
d.end_time AS endTime
FROM aps_plan_sheet s
INNER JOIN aps_plan_detail d ON d.plan_sheet_id = s.plan_sheet_id AND d.del_flag = 0
WHERE s.del_flag = 0
<if test="planSheetId != null">
AND s.plan_sheet_id = #{planSheetId}
</if>
ORDER BY CAST(d.biz_seq_no AS UNSIGNED) ASC
</select>
</mapper>

View File

@@ -12,7 +12,7 @@
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
@@ -43,5 +43,9 @@
<groupId>com.klp</groupId>
<artifactId>klp-wms</artifactId>
</dependency>
<dependency>
<groupId>com.klp</groupId>
<artifactId>klp-aps</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,99 @@
package com.klp.crm.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.crm.domain.vo.CrmContractVo;
import com.klp.crm.domain.bo.CrmContractBo;
import com.klp.crm.service.ICrmContractService;
import com.klp.common.core.page.TableDataInfo;
/**
* 合同信息
*
* @author klp
* @date 2026-03-30
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/crm/contract")
public class CrmContractController extends BaseController {
private final ICrmContractService iCrmContractService;
/**
* 查询合同信息列表
*/
@GetMapping("/list")
public TableDataInfo<CrmContractVo> list(CrmContractBo bo, PageQuery pageQuery) {
return iCrmContractService.queryPageList(bo, pageQuery);
}
/**
* 导出合同信息列表
*/
@Log(title = "合同信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(CrmContractBo bo, HttpServletResponse response) {
List<CrmContractVo> list = iCrmContractService.queryList(bo);
ExcelUtil.exportExcel(list, "合同信息", CrmContractVo.class, response);
}
/**
* 获取合同信息详细信息
*
* @param contractId 主键
*/
@GetMapping("/{contractId}")
public R<CrmContractVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long contractId) {
return R.ok(iCrmContractService.queryById(contractId));
}
/**
* 新增合同信息
*/
@Log(title = "合同信息", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody CrmContractBo bo) {
return toAjax(iCrmContractService.insertByBo(bo));
}
/**
* 修改合同信息
*/
@Log(title = "合同信息", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody CrmContractBo bo) {
return toAjax(iCrmContractService.updateByBo(bo));
}
/**
* 删除合同信息
*
* @param contractIds 主键串
*/
@Log(title = "合同信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{contractIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] contractIds) {
return toAjax(iCrmContractService.deleteWithValidByIds(Arrays.asList(contractIds), true));
}
}

View File

@@ -0,0 +1,99 @@
package com.klp.crm.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.crm.domain.vo.CrmContractProductVo;
import com.klp.crm.domain.bo.CrmContractProductBo;
import com.klp.crm.service.ICrmContractProductService;
import com.klp.common.core.page.TableDataInfo;
/**
* 合同产品明细
*
* @author klp
* @date 2026-03-30
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/crm/contractProduct")
public class CrmContractProductController extends BaseController {
private final ICrmContractProductService iCrmContractProductService;
/**
* 查询合同产品明细列表
*/
@GetMapping("/list")
public TableDataInfo<CrmContractProductVo> list(CrmContractProductBo bo, PageQuery pageQuery) {
return iCrmContractProductService.queryPageList(bo, pageQuery);
}
/**
* 导出合同产品明细列表
*/
@Log(title = "合同产品明细", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(CrmContractProductBo bo, HttpServletResponse response) {
List<CrmContractProductVo> list = iCrmContractProductService.queryList(bo);
ExcelUtil.exportExcel(list, "合同产品明细", CrmContractProductVo.class, response);
}
/**
* 获取合同产品明细详细信息
*
* @param contractProductId 主键
*/
@GetMapping("/{contractProductId}")
public R<CrmContractProductVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long contractProductId) {
return R.ok(iCrmContractProductService.queryById(contractProductId));
}
/**
* 新增合同产品明细
*/
@Log(title = "合同产品明细", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody CrmContractProductBo bo) {
return toAjax(iCrmContractProductService.insertByBo(bo));
}
/**
* 修改合同产品明细
*/
@Log(title = "合同产品明细", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody CrmContractProductBo bo) {
return toAjax(iCrmContractProductService.updateByBo(bo));
}
/**
* 删除合同产品明细
*
* @param contractProductIds 主键串
*/
@Log(title = "合同产品明细", businessType = BusinessType.DELETE)
@DeleteMapping("/{contractProductIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] contractProductIds) {
return toAjax(iCrmContractProductService.deleteWithValidByIds(Arrays.asList(contractProductIds), true));
}
}

View File

@@ -1,12 +1,17 @@
package com.klp.crm.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import java.util.Date;
import com.klp.aps.domain.bo.ApsPlanDetailBo;
import com.klp.aps.domain.bo.ApsPlanSheetBo;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.annotation.Validated;
import com.klp.common.annotation.RepeatSubmit;
import com.klp.common.annotation.Log;
@@ -21,6 +26,10 @@ import com.klp.crm.domain.vo.CrmOrderVo;
import com.klp.crm.domain.bo.CrmOrderBo;
import com.klp.crm.service.ICrmOrderService;
import com.klp.common.core.page.TableDataInfo;
import com.klp.aps.domain.vo.ApsPlanSheetVo;
import com.klp.aps.domain.vo.ApsPlanDetailVo;
import com.klp.aps.service.IApsPlanSheetService;
import com.klp.aps.service.IApsPlanDetailService;
/**
* 正式订单主
@@ -35,6 +44,8 @@ import com.klp.common.core.page.TableDataInfo;
public class CrmOrderController extends BaseController {
private final ICrmOrderService iCrmOrderService;
private final IApsPlanSheetService iApsPlanSheetService;
private final IApsPlanDetailService iApsPlanDetailService;
/**
* 查询正式订单主列表
@@ -96,4 +107,54 @@ public class CrmOrderController extends BaseController {
@PathVariable String[] orderIds) {
return toAjax(iCrmOrderService.deleteWithValidByIds(Arrays.asList(orderIds), true));
}
/**
* 查询每日订单(根据排产计划获取今天的订单)
*
* @param planDate 排产日期,默认今天
*/
@GetMapping("/daily")
public R<List<CrmOrderVo>> getDailyOrders(
@RequestParam(value = "planDate", required = false)
@DateTimeFormat(pattern = "yyyy-MM-dd") Date planDate) {
if (planDate == null) {
planDate = new Date();
}
// 将日期设置为当天的开始时间 00:00:00
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.setTime(planDate);
calendar.set(java.util.Calendar.HOUR_OF_DAY, 0);
calendar.set(java.util.Calendar.MINUTE, 0);
calendar.set(java.util.Calendar.SECOND, 0);
calendar.set(java.util.Calendar.MILLISECOND, 0);
planDate = calendar.getTime();
ApsPlanSheetBo bo = new ApsPlanSheetBo();
bo.setPlanDate(planDate);
List<ApsPlanSheetVo> planSheetList = iApsPlanSheetService.queryList(bo);
if (planSheetList == null || planSheetList.isEmpty()) {
return R.ok(new ArrayList<>());
}
List<Long> planSheetIds = new ArrayList<>();
for (ApsPlanSheetVo sheet : planSheetList) {
planSheetIds.add(sheet.getPlanSheetId());
}
ApsPlanDetailBo detailBo = new ApsPlanDetailBo();
detailBo.setPlanSheetIds(planSheetIds);
List<ApsPlanDetailVo> detailList = iApsPlanDetailService.queryListByPlanSheetIds(planSheetIds);
if (detailList == null || detailList.isEmpty()) {
return R.ok(new ArrayList<>());
}
List<Long> orderIds = new ArrayList<>();
for (ApsPlanDetailVo detail : detailList) {
if (detail.getOrderId() != null) {
orderIds.add(detail.getOrderId());
}
}
if (orderIds.isEmpty()) {
return R.ok(new ArrayList<>());
}
List<CrmOrderVo> orders = iCrmOrderService.queryByIds(orderIds);
return R.ok(orders);
}
}

View File

@@ -18,8 +18,10 @@ import com.klp.common.core.validate.EditGroup;
import com.klp.common.enums.BusinessType;
import com.klp.common.utils.poi.ExcelUtil;
import com.klp.crm.domain.vo.CrmOrderItemVo;
import com.klp.crm.domain.vo.CrmContractOrderFinanceVo;
import com.klp.crm.domain.bo.CrmOrderItemBo;
import com.klp.crm.service.ICrmOrderItemService;
import com.klp.domain.vo.WmsMaterialCoilVo;
import com.klp.common.core.page.TableDataInfo;
/**
@@ -96,4 +98,38 @@ public class CrmOrderItemController extends BaseController {
@PathVariable String[] itemIds) {
return toAjax(iCrmOrderItemService.deleteWithValidByIds(Arrays.asList(itemIds), true));
}
// 根据合同id查询该合同下属订单关联的异议和财务信息。。
@GetMapping("/contractFinance/{contractId}")
public R<CrmContractOrderFinanceVo> getContractFinance(@NotNull(message = "合同ID不能为空")
@PathVariable Long contractId) {
return R.ok(iCrmOrderItemService.queryFinanceAndObjectionByContractId(contractId));
}
// 根据订单id查询发货单据中的配卷。
@GetMapping("/coils/order/{orderId}")
public R<List<WmsMaterialCoilVo>> getCoilsByOrderId(@NotNull(message = "订单ID不能为空")
@PathVariable Long orderId) {
return R.ok(iCrmOrderItemService.queryCoilsByOrderId(orderId));
}
// 根据合同id查询发货单据中的配卷。
@GetMapping("/coils/contract/{contractId}")
public R<List<WmsMaterialCoilVo>> getCoilsByContractId(@NotNull(message = "合同ID不能为空")
@PathVariable Long contractId) {
return R.ok(iCrmOrderItemService.queryCoilsByContractId(contractId));
}
// 根据客户id查询该客户下属订单关联的异议和财务信息。
@GetMapping("/customerFinance/{customerId}")
public R<CrmContractOrderFinanceVo> getCustomerFinance(@NotNull(message = "客户ID不能为空")
@PathVariable String customerId) {
return R.ok(iCrmOrderItemService.queryFinanceAndObjectionByCustomerId(customerId));
}
// 根据客户id查询发货单据中的配卷。
@GetMapping("/coils/customer/{customerId}")
public R<List<WmsMaterialCoilVo>> getCoilsByCustomerId(@NotNull(message = "客户ID不能为空")
@PathVariable String customerId) {
return R.ok(iCrmOrderItemService.queryCoilsByCustomerId(customerId));
}
}

View File

@@ -0,0 +1,135 @@
package com.klp.crm.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 合同信息对象 crm_contract
*
* @author klp
* @date 2026-03-30
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("crm_contract")
public class CrmContract extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 合同主键ID
*/
@TableId(value = "contract_id")
private Long contractId;
/**
* 合同名称
*/
private String contractName;
/**
* 合同编号
*/
private String contractNo;
/**
* 供方
*/
private String supplier;
/**
* 需方
*/
private String customer;
/**
* 客户ID
*/
private Long customerId;
/**
* 签订时间
*/
private Date signTime;
/**
* 交货日期
*/
private Date deliveryDate;
/**
* 签订地点
*/
private String signLocation;
/**
* 产品内容
*/
private String productContent;
/**
* 合同内容
*/
private String contractContent;
/**
* 供方地址
*/
private String supplierAddress;
/**
* 供方电话
*/
private String supplierPhone;
/**
* 供方开户行
*/
private String supplierBank;
/**
* 供方账号
*/
private String supplierAccount;
/**
* 供方税号
*/
private String supplierTaxNo;
/**
* 需方地址
*/
private String customerAddress;
/**
* 需方电话
*/
private String customerPhone;
/**
* 需方开户行
*/
private String customerBank;
/**
* 需方账号
*/
private String customerAccount;
/**
* 需方税号
*/
private String customerTaxNo;
/**
* 技术附件
*/
private String techAnnex;
/**
* 商务附件
*/
private String businessAnnex;
/**
* 排产函
*/
private String productionSchedule;
/**
* 合同状态 0=草稿 1=生效 2=作废 3=已完成
*/
private Long status;
/**
* 备注
*/
private String remark;
/**
* 删除标识 0正常 2删除
*/
@TableLogic
private Long delFlag;
}

View File

@@ -0,0 +1,74 @@
package com.klp.crm.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* 合同产品明细对象 crm_contract_product
*
* @author klp
* @date 2026-03-30
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("crm_contract_product")
public class CrmContractProduct extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 合同产品主键ID
*/
@TableId(value = "contract_product_id")
private Long contractProductId;
/**
* 关联合同ID绑定wms_contract表主键
*/
private Long contractId;
/**
* 产品名称
*/
private String productName;
/**
* 规格最小值(mm)
*/
private BigDecimal specMin;
/**
* 规格最大值(mm)
*/
private BigDecimal specMax;
/**
* 材质
*/
private String material;
/**
* 数量(吨)
*/
private BigDecimal quantity;
/**
* 含税单价(元/吨)
*/
private BigDecimal taxInclusiveUnitPrice;
/**
* 不含税单价(元/吨)
*/
private BigDecimal exTaxUnitPrice;
/**
* 含税总额(元)
*/
private BigDecimal taxInclusiveAmount;
/**
* 删除标识 0正常 2删除
*/
@TableLogic
private Long delFlag;
/**
* 备注
*/
private String remark;
}

View File

@@ -56,6 +56,10 @@ public class CrmCustomer extends BaseEntity {
* 银行信息多条需权限查看JSON格式存储
*/
private String bankInfo;
/**
* 纳税人识别号/税号
*/
private String taxNumber;
/**
* 备注
*/

View File

@@ -26,7 +26,7 @@ public class CrmOrder extends BaseEntity {
* 订单ID主键
*/
@TableId(value = "order_id")
private String orderId;
private Long orderId;
/**
* 订单编号
*/
@@ -85,6 +85,141 @@ public class CrmOrder extends BaseEntity {
*/
private String contractCode;
/**
* 合同名称
*/
private String contractName;
/**
* 供方
*/
private String supplier;
/**
* 需方
*/
private String customer;
/**
* 签订时间
*/
private Date signTime;
/**
* 签订地点
*/
private String signLocation;
/**
* 产品内容
*/
private String productContent;
/**
* 合同内容
*/
private String contractContent;
/**
* 供方地址
*/
private String supplierAddress;
/**
* 供方电话
*/
private String supplierPhone;
/**
* 供方开户行
*/
private String supplierBank;
/**
* 供方账号
*/
private String supplierAccount;
/**
* 供方税号
*/
private String supplierTaxNo;
/**
* 需方地址
*/
private String customerAddress;
/**
* 需方电话
*/
private String customerPhone;
/**
* 需方开户行
*/
private String customerBank;
/**
* 需方账号
*/
private String customerAccount;
/**
* 需方税号
*/
private String customerTaxNo;
/**
* 技术附件
*/
private String techAnnex;
/**
* 商务附件
*/
private String businessAnnex;
/**
* 排产函
*/
private String productionSchedule;
/**
* 算单价备注
*/
private String unitPriceRemark;
/**
* 应付定金(万元)
*/
private BigDecimal depositPayable;
/**
* 已付定金(万元)
*/
private BigDecimal depositPaid;
/**
* 定金比例(%
*/
private BigDecimal depositRatio;
/**
* 合同状态 0=草稿 1=生效 2=作废 3=已完成
*/
private Long status;
/**
* 关联合同IDwms_contract.contract_id
*/
private Long contractId;
/**
* 附件多个文件URL用逗号分隔
*/
private String annexFiles;
/**
* 删除标识 0正常 2删除
*/

View File

@@ -24,11 +24,11 @@ public class CrmOrderItem extends BaseEntity {
* 正式订单明细ID主键
*/
@TableId(value = "item_id")
private String itemId;
private Long itemId;
/**
* 关联正式订单ID外键
*/
private String orderId;
private Long orderId;
/**
* 产品类型
*/
@@ -69,6 +69,14 @@ public class CrmOrderItem extends BaseEntity {
* 重量
*/
private BigDecimal weight;
/**
* 宽度公差
*/
private BigDecimal widthTolerance;
/**
* 厚度公差
*/
private BigDecimal thicknessTolerance;
/**
* 合同定价
*/
@@ -85,10 +93,34 @@ public class CrmOrderItem extends BaseEntity {
* 排产批次
*/
private String productionBatch;
/**
* 表面处理
*/
private String surfaceTreatment;
/**
* 切边要求
*/
private String edgeCuttingReq;
/**
* 包装要求
*/
private String packagingReq;
/**
* 宽度
*/
private BigDecimal width;
/**
* 厚度
*/
private BigDecimal thickness;
/**
* 用途
*/
private String purpose;
/**
* 删除标识 0正常 2删除
*/
@TableLogic
private Long delFlag;
}
}

View File

@@ -0,0 +1,161 @@
package com.klp.crm.domain.bo;
import org.springframework.format.annotation.DateTimeFormat;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 合同信息业务对象 crm_contract
*
* @author klp
* @date 2026-03-30
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class CrmContractBo extends BaseEntity {
/**
* 合同主键ID
*/
private Long contractId;
/**
* 合同名称
*/
private String contractName;
/**
* 合同编号
*/
private String contractNo;
/**
* 供方
*/
private String supplier;
/**
* 需方
*/
private String customer;
/**
* 客户ID
*/
private Long customerId;
/**
* 签订时间
*/
private Date signTime;
/**
* 交货日期
*/
@JsonFormat(pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date deliveryDate;
/**
* 签订地点
*/
private String signLocation;
/**
* 产品内容
*/
private String productContent;
/**
* 合同内容
*/
private String contractContent;
/**
* 供方地址
*/
private String supplierAddress;
/**
* 供方电话
*/
private String supplierPhone;
/**
* 供方开户行
*/
private String supplierBank;
/**
* 供方账号
*/
private String supplierAccount;
/**
* 供方税号
*/
private String supplierTaxNo;
/**
* 需方地址
*/
private String customerAddress;
/**
* 需方电话
*/
private String customerPhone;
/**
* 需方开户行
*/
private String customerBank;
/**
* 需方账号
*/
private String customerAccount;
/**
* 需方税号
*/
private String customerTaxNo;
/**
* 技术附件
*/
private String techAnnex;
/**
* 商务附件
*/
private String businessAnnex;
/**
* 排产函
*/
private String productionSchedule;
/**
* 合同状态 0=草稿 1=生效 2=作废 3=已完成
*/
private Long status;
/**
* 备注
*/
private String remark;
/**
* 关键字搜索
*/
private String keyword;
}

View File

@@ -0,0 +1,77 @@
package com.klp.crm.domain.bo;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.math.BigDecimal;
/**
* 合同产品明细业务对象 crm_contract_product
*
* @author klp
* @date 2026-03-30
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class CrmContractProductBo extends BaseEntity {
/**
* 合同产品主键ID
*/
private Long contractProductId;
/**
* 关联合同ID绑定wms_contract表主键
*/
private Long contractId;
/**
* 产品名称
*/
private String productName;
/**
* 规格最小值(mm)
*/
private BigDecimal specMin;
/**
* 规格最大值(mm)
*/
private BigDecimal specMax;
/**
* 材质
*/
private String material;
/**
* 数量(吨)
*/
private BigDecimal quantity;
/**
* 含税单价(元/吨)
*/
private BigDecimal taxInclusiveUnitPrice;
/**
* 不含税单价(元/吨)
*/
private BigDecimal exTaxUnitPrice;
/**
* 含税总额(元)
*/
private BigDecimal taxInclusiveAmount;
/**
* 备注
*/
private String remark;
}

View File

@@ -62,10 +62,20 @@ public class CrmCustomerBo extends BaseEntity {
*/
private String bankInfo;
/**
* 纳税人识别号/税号
*/
private String taxNumber;
/**
* 备注
*/
private String remark;
/**
* 关键字搜索
*/
private String keyword;
}

View File

@@ -8,6 +8,7 @@ import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 正式订单主业务对象 crm_order
@@ -23,7 +24,7 @@ public class CrmOrderBo extends BaseEntity {
/**
* 订单ID主键
*/
private String orderId;
private Long orderId;
/**
* 订单编号
@@ -53,6 +54,8 @@ public class CrmOrderBo extends BaseEntity {
/**
* 交货日期
*/
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date deliveryDate;
/**
@@ -95,5 +98,147 @@ public class CrmOrderBo extends BaseEntity {
*/
private String contractCode;
/**
* 合同名称
*/
private String contractName;
/**
* 供方
*/
private String supplier;
/**
* 需方
*/
private String customer;
/**
* 签订时间
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date signTime;
/**
* 签订地点
*/
private String signLocation;
/**
* 产品内容
*/
private String productContent;
/**
* 合同内容
*/
private String contractContent;
/**
* 供方地址
*/
private String supplierAddress;
/**
* 供方电话
*/
private String supplierPhone;
/**
* 供方开户行
*/
private String supplierBank;
/**
* 供方账号
*/
private String supplierAccount;
/**
* 供方税号
*/
private String supplierTaxNo;
/**
* 需方地址
*/
private String customerAddress;
/**
* 需方电话
*/
private String customerPhone;
/**
* 需方开户行
*/
private String customerBank;
/**
* 需方账号
*/
private String customerAccount;
/**
* 需方税号
*/
private String customerTaxNo;
/**
* 技术附件
*/
private String techAnnex;
/**
* 商务附件
*/
private String businessAnnex;
/**
* 排产函
*/
private String productionSchedule;
/**
* 算单价备注
*/
private String unitPriceRemark;
/**
* 应付定金(万元)
*/
private BigDecimal depositPayable;
/**
* 已付定金(万元)
*/
private BigDecimal depositPaid;
/**
* 定金比例(%
*/
private BigDecimal depositRatio;
/**
* 合同状态 0=草稿 1=生效 2=作废 3=已完成
*/
private Long status;
/**
* 关联合同IDwms_contract.contract_id
*/
private Long contractId;
/**
* 附件多个文件URL用逗号分隔
*/
private String annexFiles;
/**
* 关键字搜索
*/
private String keyword;
}

View File

@@ -21,12 +21,12 @@ public class CrmOrderItemBo extends BaseEntity {
/**
* 正式订单明细ID主键
*/
private String itemId;
private Long itemId;
/**
* 关联正式订单ID外键
*/
private String orderId;
private Long orderId;
/**
* 产品类型
@@ -57,7 +57,7 @@ public class CrmOrderItemBo extends BaseEntity {
* 备注
*/
private String remark;
/**
* 成品规格
*/
@@ -78,6 +78,16 @@ public class CrmOrderItemBo extends BaseEntity {
*/
private BigDecimal weight;
/**
* 宽度公差
*/
private BigDecimal widthTolerance;
/**
* 厚度公差
*/
private BigDecimal thicknessTolerance;
/**
* 合同定价
*/
@@ -98,5 +108,34 @@ public class CrmOrderItemBo extends BaseEntity {
*/
private String productionBatch;
/**
* 表面处理
*/
private String surfaceTreatment;
}
/**
* 切边要求
*/
private String edgeCuttingReq;
/**
* 包装要求
*/
private String packagingReq;
/**
* 宽度
*/
private BigDecimal width;
/**
* 厚度
*/
private BigDecimal thickness;
/**
* 用途
*/
private String purpose;
}

View File

@@ -0,0 +1,18 @@
package com.klp.crm.domain.vo;
import com.klp.domain.vo.WmsDeliveryWaybillVo;
import com.klp.domain.vo.WmsReceivableVo;
import lombok.Data;
import java.util.List;
@Data
public class CrmContractOrderFinanceVo {
private List<CrmSalesObjectionVo> objectionList;
private List<WmsReceivableVo> receivableList;
// setWmsDeliveryWaybills
private List<WmsDeliveryWaybillVo> wmsDeliveryWaybills;
}

View File

@@ -0,0 +1,91 @@
package com.klp.crm.domain.vo;
import java.math.BigDecimal;
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;
/**
* 合同产品明细视图对象 crm_contract_product
*
* @author klp
* @date 2026-03-30
*/
@Data
@ExcelIgnoreUnannotated
public class CrmContractProductVo {
private static final long serialVersionUID = 1L;
/**
* 合同产品主键ID
*/
@ExcelProperty(value = "合同产品主键ID")
private Long contractProductId;
/**
* 关联合同ID绑定wms_contract表主键
*/
@ExcelProperty(value = "关联合同ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "绑=定wms_contract表主键")
private Long contractId;
/**
* 产品名称
*/
@ExcelProperty(value = "产品名称")
private String productName;
/**
* 规格最小值(mm)
*/
@ExcelProperty(value = "规格最小值(mm)")
private BigDecimal specMin;
/**
* 规格最大值(mm)
*/
@ExcelProperty(value = "规格最大值(mm)")
private BigDecimal specMax;
/**
* 材质
*/
@ExcelProperty(value = "材质")
private String material;
/**
* 数量(吨)
*/
@ExcelProperty(value = "数量(吨)")
private BigDecimal quantity;
/**
* 含税单价(元/吨)
*/
@ExcelProperty(value = "含税单价(元/吨)")
private BigDecimal taxInclusiveUnitPrice;
/**
* 不含税单价(元/吨)
*/
@ExcelProperty(value = "不含税单价(元/吨)")
private BigDecimal exTaxUnitPrice;
/**
* 含税总额(元)
*/
@ExcelProperty(value = "含税总额(元)")
private BigDecimal taxInclusiveAmount;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -0,0 +1,180 @@
package com.klp.crm.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
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;
/**
* 合同信息视图对象 crm_contract
*
* @author klp
* @date 2026-03-30
*/
@Data
@ExcelIgnoreUnannotated
public class CrmContractVo {
private static final long serialVersionUID = 1L;
/**
* 合同主键ID
*/
@ExcelProperty(value = "合同主键ID")
private Long contractId;
/**
* 合同名称
*/
@ExcelProperty(value = "合同名称")
private String contractName;
/**
* 合同编号
*/
@ExcelProperty(value = "合同编号")
private String contractNo;
/**
* 供方
*/
@ExcelProperty(value = "供方")
private String supplier;
/**
* 需方
*/
@ExcelProperty(value = "需方")
private String customer;
/**
* 客户ID
*/
@ExcelProperty(value = "客户ID")
private Long customerId;
/**
* 签订时间
*/
@ExcelProperty(value = "签订时间")
private Date signTime;
/**
* 交货日期
*/
@ExcelProperty(value = "交货日期")
private Date deliveryDate;
/**
* 签订地点
*/
@ExcelProperty(value = "签订地点")
private String signLocation;
/**
* 产品内容
*/
@ExcelProperty(value = "产品内容")
private String productContent;
/**
* 合同内容
*/
@ExcelProperty(value = "合同内容")
private String contractContent;
/**
* 供方地址
*/
@ExcelProperty(value = "供方地址")
private String supplierAddress;
/**
* 供方电话
*/
@ExcelProperty(value = "供方电话")
private String supplierPhone;
/**
* 供方开户行
*/
@ExcelProperty(value = "供方开户行")
private String supplierBank;
/**
* 供方账号
*/
@ExcelProperty(value = "供方账号")
private String supplierAccount;
/**
* 供方税号
*/
@ExcelProperty(value = "供方税号")
private String supplierTaxNo;
/**
* 需方地址
*/
@ExcelProperty(value = "需方地址")
private String customerAddress;
/**
* 需方电话
*/
@ExcelProperty(value = "需方电话")
private String customerPhone;
/**
* 需方开户行
*/
@ExcelProperty(value = "需方开户行")
private String customerBank;
/**
* 需方账号
*/
@ExcelProperty(value = "需方账号")
private String customerAccount;
/**
* 需方税号
*/
@ExcelProperty(value = "需方税号")
private String customerTaxNo;
/**
* 技术附件
*/
@ExcelProperty(value = "技术附件")
private String techAnnex;
/**
* 商务附件
*/
@ExcelProperty(value = "商务附件")
private String businessAnnex;
/**
* 排产函
*/
@ExcelProperty(value = "排产函")
private String productionSchedule;
/**
* 合同状态 0=草稿 1=生效 2=作废 3=已完成
*/
@ExcelProperty(value = "合同状态 0=草稿 1=生效 2=作废 3=已完成")
private Long status;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -78,6 +78,12 @@ public class CrmCustomerVo {
@ExcelDictFormat(readConverterExp = "多=条需权限查看JSON格式存储")
private String bankInfo;
/**
* 纳税人识别号/税号
*/
@ExcelProperty(value = "纳税人识别号/税号")
private String taxNumber;
/**
* 备注
*/

View File

@@ -25,14 +25,14 @@ public class CrmOrderItemVo {
*/
@ExcelProperty(value = "正式订单明细ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "主=键")
private String itemId;
private Long itemId;
/**
* 关联正式订单ID外键
*/
@ExcelProperty(value = "关联正式订单ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "外=键")
private String orderId;
private Long orderId;
/**
* 产品类型
@@ -95,6 +95,18 @@ public class CrmOrderItemVo {
@ExcelProperty(value = "重量")
private BigDecimal weight;
/**
* 宽度公差
*/
@ExcelProperty(value = "宽度公差")
private BigDecimal widthTolerance;
/**
* 厚度公差
*/
@ExcelProperty(value = "厚度公差")
private BigDecimal thicknessTolerance;
/**
* 合同定价
*/
@@ -119,5 +131,40 @@ public class CrmOrderItemVo {
@ExcelProperty(value = "排产批次")
private String productionBatch;
/**
* 表面处理
*/
@ExcelProperty(value = "表面处理")
private String surfaceTreatment;
}
/**
* 切边要求
*/
@ExcelProperty(value = "切边要求")
private String edgeCuttingReq;
/**
* 包装要求
*/
@ExcelProperty(value = "包装要求")
private String packagingReq;
/**
* 宽度
*/
@ExcelProperty(value = "宽度")
private BigDecimal width;
/**
* 厚度
*/
@ExcelProperty(value = "厚度")
private BigDecimal thickness;
/**
* 用途
*/
@ExcelProperty(value = "用途")
private String purpose;
}

View File

@@ -2,12 +2,15 @@ package com.klp.crm.domain.vo;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
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 com.klp.domain.vo.WmsMaterialCoilVo;
import lombok.Data;
@@ -28,7 +31,7 @@ public class CrmOrderVo extends BaseEntity {
*/
@ExcelProperty(value = "订单ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "主=键")
private String orderId;
private Long orderId;
/**
* 订单编号
@@ -114,6 +117,168 @@ public class CrmOrderVo extends BaseEntity {
@ExcelProperty(value = "合同号")
private String contractCode;
/**
* 合同名称
*/
@ExcelProperty(value = "合同名称")
private String contractName;
/**
* 供方
*/
@ExcelProperty(value = "供方")
private String supplier;
/**
* 需方
*/
@ExcelProperty(value = "需方")
private String customer;
/**
* 签订时间
*/
@ExcelProperty(value = "签订时间")
private Date signTime;
/**
* 签订地点
*/
@ExcelProperty(value = "签订地点")
private String signLocation;
/**
* 产品内容
*/
@ExcelProperty(value = "产品内容")
private String productContent;
/**
* 合同内容
*/
@ExcelProperty(value = "合同内容")
private String contractContent;
/**
* 供方地址
*/
@ExcelProperty(value = "供方地址")
private String supplierAddress;
/**
* 供方电话
*/
@ExcelProperty(value = "供方电话")
private String supplierPhone;
/**
* 供方开户行
*/
@ExcelProperty(value = "供方开户行")
private String supplierBank;
/**
* 供方账号
*/
@ExcelProperty(value = "供方账号")
private String supplierAccount;
/**
* 供方税号
*/
@ExcelProperty(value = "供方税号")
private String supplierTaxNo;
/**
* 需方地址
*/
@ExcelProperty(value = "需方地址")
private String customerAddress;
/**
* 需方电话
*/
@ExcelProperty(value = "需方电话")
private String customerPhone;
/**
* 需方开户行
*/
@ExcelProperty(value = "需方开户行")
private String customerBank;
/**
* 需方账号
*/
@ExcelProperty(value = "需方账号")
private String customerAccount;
/**
* 需方税号
*/
@ExcelProperty(value = "需方税号")
private String customerTaxNo;
/**
* 技术附件
*/
@ExcelProperty(value = "技术附件")
private String techAnnex;
/**
* 商务附件
*/
@ExcelProperty(value = "商务附件")
private String businessAnnex;
/**
* 排产函
*/
@ExcelProperty(value = "排产函")
private String productionSchedule;
/**
* 算单价备注
*/
@ExcelProperty(value = "算单价备注")
private String unitPriceRemark;
/**
* 应付定金(万元)
*/
@ExcelProperty(value = "应付定金(万元)")
private BigDecimal depositPayable;
/**
* 已付定金(万元)
*/
@ExcelProperty(value = "已付定金(万元)")
private BigDecimal depositPaid;
/**
* 定金比例(%
*/
@ExcelProperty(value = "定金比例(%")
private BigDecimal depositRatio;
/**
* 合同状态 0=草稿 1=生效 2=作废 3=已完成
*/
@ExcelProperty(value = "合同状态")
private Long status;
/**
* 关联合同IDwms_contract.contract_id
*/
@ExcelProperty(value = "关联合同ID")
private Long contractId;
/**
* 附件多个文件URL用逗号分隔
*/
@ExcelProperty(value = "附件")
private String annexFiles;
// @ExcelProperty(value = "客户编号")
private String customerCode;
@@ -130,4 +295,8 @@ public class CrmOrderVo extends BaseEntity {
private String createByName;
//更新人
private String updateByName;
/**
* 关联的钢卷列表
*/
private List<WmsMaterialCoilVo> coilList;
}

View File

@@ -98,7 +98,7 @@ public class CrmSalesReportVo {
/**
* 订单ID
*/
private String orderId;
private Long orderId;
/**
* 订单编号

View File

@@ -0,0 +1,15 @@
package com.klp.crm.mapper;
import com.klp.crm.domain.CrmContract;
import com.klp.crm.domain.vo.CrmContractVo;
import com.klp.common.core.mapper.BaseMapperPlus;
/**
* 合同信息Mapper接口
*
* @author klp
* @date 2026-03-30
*/
public interface CrmContractMapper extends BaseMapperPlus<CrmContractMapper, CrmContract, CrmContractVo> {
}

View File

@@ -0,0 +1,15 @@
package com.klp.crm.mapper;
import com.klp.crm.domain.CrmContractProduct;
import com.klp.crm.domain.vo.CrmContractProductVo;
import com.klp.common.core.mapper.BaseMapperPlus;
/**
* 合同产品明细Mapper接口
*
* @author klp
* @date 2026-03-30
*/
public interface CrmContractProductMapper extends BaseMapperPlus<CrmContractProductMapper, CrmContractProduct, CrmContractProductVo> {
}

View File

@@ -21,5 +21,5 @@ public interface CrmOrderItemMapper extends BaseMapperPlus<CrmOrderItemMapper, C
* @param orderIds 订单ID列表
* @return 订单明细列表
*/
List<CrmOrderItem> selectOrderItemsByOrderIds(@Param("orderIds") List<String> orderIds);
List<CrmOrderItem> selectOrderItemsByOrderIds(@Param("orderIds") List<Long> orderIds);
}

View File

@@ -0,0 +1,49 @@
package com.klp.crm.service;
import com.klp.crm.domain.CrmContractProduct;
import com.klp.crm.domain.vo.CrmContractProductVo;
import com.klp.crm.domain.bo.CrmContractProductBo;
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-03-30
*/
public interface ICrmContractProductService {
/**
* 查询合同产品明细
*/
CrmContractProductVo queryById(Long contractProductId);
/**
* 查询合同产品明细列表
*/
TableDataInfo<CrmContractProductVo> queryPageList(CrmContractProductBo bo, PageQuery pageQuery);
/**
* 查询合同产品明细列表
*/
List<CrmContractProductVo> queryList(CrmContractProductBo bo);
/**
* 新增合同产品明细
*/
Boolean insertByBo(CrmContractProductBo bo);
/**
* 修改合同产品明细
*/
Boolean updateByBo(CrmContractProductBo bo);
/**
* 校验并批量删除合同产品明细信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -0,0 +1,49 @@
package com.klp.crm.service;
import com.klp.crm.domain.CrmContract;
import com.klp.crm.domain.vo.CrmContractVo;
import com.klp.crm.domain.bo.CrmContractBo;
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-03-30
*/
public interface ICrmContractService {
/**
* 查询合同信息
*/
CrmContractVo queryById(Long contractId);
/**
* 查询合同信息列表
*/
TableDataInfo<CrmContractVo> queryPageList(CrmContractBo bo, PageQuery pageQuery);
/**
* 查询合同信息列表
*/
List<CrmContractVo> queryList(CrmContractBo bo);
/**
* 新增合同信息
*/
Boolean insertByBo(CrmContractBo bo);
/**
* 修改合同信息
*/
Boolean updateByBo(CrmContractBo bo);
/**
* 校验并批量删除合同信息信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -9,6 +9,10 @@ import com.klp.common.core.domain.PageQuery;
import java.util.Collection;
import java.util.List;
import com.klp.crm.domain.vo.CrmContractOrderFinanceVo;
import com.klp.domain.vo.WmsMaterialCoilVo;
import java.util.List;
/**
* 正式订单明细Service接口
*
@@ -46,4 +50,29 @@ public interface ICrmOrderItemService {
* 校验并批量删除正式订单明细信息
*/
Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid);
/**
* 根据合同ID查询下属订单的异议和财务信息
*/
CrmContractOrderFinanceVo queryFinanceAndObjectionByContractId(Long contractId);
/**
* 根据订单ID查询发货单配卷
*/
List<WmsMaterialCoilVo> queryCoilsByOrderId(Long orderId);
/**
* 根据合同ID查询发货单配卷
*/
List<WmsMaterialCoilVo> queryCoilsByContractId(Long contractId);
/**
* 根据客户ID查询下属订单的异议和财务信息
*/
CrmContractOrderFinanceVo queryFinanceAndObjectionByCustomerId(String customerId);
/**
* 根据客户ID查询发货单配卷
*/
List<WmsMaterialCoilVo> queryCoilsByCustomerId(String customerId);
}

View File

@@ -22,6 +22,11 @@ public interface ICrmOrderService {
*/
CrmOrderVo queryById(String orderId);
/**
* 根据ID列表查询正式订单
*/
List<CrmOrderVo> queryByIds(List<Long> orderIds);
/**
* 查询正式订单主列表
*/

View File

@@ -0,0 +1,117 @@
package com.klp.crm.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.crm.domain.bo.CrmContractProductBo;
import com.klp.crm.domain.vo.CrmContractProductVo;
import com.klp.crm.domain.CrmContractProduct;
import com.klp.crm.mapper.CrmContractProductMapper;
import com.klp.crm.service.ICrmContractProductService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 合同产品明细Service业务层处理
*
* @author klp
* @date 2026-03-30
*/
@RequiredArgsConstructor
@Service
public class CrmContractProductServiceImpl implements ICrmContractProductService {
private final CrmContractProductMapper baseMapper;
/**
* 查询合同产品明细
*/
@Override
public CrmContractProductVo queryById(Long contractProductId){
return baseMapper.selectVoById(contractProductId);
}
/**
* 查询合同产品明细列表
*/
@Override
public TableDataInfo<CrmContractProductVo> queryPageList(CrmContractProductBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<CrmContractProduct> lqw = buildQueryWrapper(bo);
Page<CrmContractProductVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询合同产品明细列表
*/
@Override
public List<CrmContractProductVo> queryList(CrmContractProductBo bo) {
LambdaQueryWrapper<CrmContractProduct> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<CrmContractProduct> buildQueryWrapper(CrmContractProductBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<CrmContractProduct> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getContractId() != null, CrmContractProduct::getContractId, bo.getContractId());
lqw.like(StringUtils.isNotBlank(bo.getProductName()), CrmContractProduct::getProductName, bo.getProductName());
lqw.eq(bo.getSpecMin() != null, CrmContractProduct::getSpecMin, bo.getSpecMin());
lqw.eq(bo.getSpecMax() != null, CrmContractProduct::getSpecMax, bo.getSpecMax());
lqw.eq(StringUtils.isNotBlank(bo.getMaterial()), CrmContractProduct::getMaterial, bo.getMaterial());
lqw.eq(bo.getQuantity() != null, CrmContractProduct::getQuantity, bo.getQuantity());
lqw.eq(bo.getTaxInclusiveUnitPrice() != null, CrmContractProduct::getTaxInclusiveUnitPrice, bo.getTaxInclusiveUnitPrice());
lqw.eq(bo.getExTaxUnitPrice() != null, CrmContractProduct::getExTaxUnitPrice, bo.getExTaxUnitPrice());
lqw.eq(bo.getTaxInclusiveAmount() != null, CrmContractProduct::getTaxInclusiveAmount, bo.getTaxInclusiveAmount());
return lqw;
}
/**
* 新增合同产品明细
*/
@Override
public Boolean insertByBo(CrmContractProductBo bo) {
CrmContractProduct add = BeanUtil.toBean(bo, CrmContractProduct.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setContractProductId(add.getContractProductId());
}
return flag;
}
/**
* 修改合同产品明细
*/
@Override
public Boolean updateByBo(CrmContractProductBo bo) {
CrmContractProduct update = BeanUtil.toBean(bo, CrmContractProduct.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(CrmContractProduct entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除合同产品明细
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -0,0 +1,152 @@
package com.klp.crm.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.crm.domain.bo.CrmContractBo;
import com.klp.crm.domain.vo.CrmContractVo;
import com.klp.crm.domain.CrmContract;
import com.klp.crm.mapper.CrmContractMapper;
import com.klp.crm.service.ICrmContractService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 合同信息Service业务层处理
*
* @author klp
* @date 2026-03-30
*/
@RequiredArgsConstructor
@Service
public class CrmContractServiceImpl implements ICrmContractService {
private final CrmContractMapper baseMapper;
/**
* 查询合同信息
*/
@Override
public CrmContractVo queryById(Long contractId){
return baseMapper.selectVoById(contractId);
}
/**
* 查询合同信息列表
*/
@Override
public TableDataInfo<CrmContractVo> queryPageList(CrmContractBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<CrmContract> lqw = buildQueryWrapper(bo);
Page<CrmContractVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询合同信息列表
*/
@Override
public List<CrmContractVo> queryList(CrmContractBo bo) {
LambdaQueryWrapper<CrmContract> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<CrmContract> buildQueryWrapper(CrmContractBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<CrmContract> lqw = Wrappers.lambdaQuery();
if (StringUtils.isNotBlank(bo.getKeyword())) {
lqw.and(w -> w.like(CrmContract::getContractName, bo.getKeyword())
.or().like(CrmContract::getContractNo, bo.getKeyword())
.or().like(CrmContract::getSupplier, bo.getKeyword())
.or().like(CrmContract::getCustomer, bo.getKeyword())
.or().like(CrmContract::getSignLocation, bo.getKeyword())
.or().like(CrmContract::getProductContent, bo.getKeyword())
.or().like(CrmContract::getContractContent, bo.getKeyword())
.or().like(CrmContract::getSupplierAddress, bo.getKeyword())
.or().like(CrmContract::getSupplierPhone, bo.getKeyword())
.or().like(CrmContract::getSupplierBank, bo.getKeyword())
.or().like(CrmContract::getSupplierAccount, bo.getKeyword())
.or().like(CrmContract::getSupplierTaxNo, bo.getKeyword())
.or().like(CrmContract::getCustomerAddress, bo.getKeyword())
.or().like(CrmContract::getCustomerPhone, bo.getKeyword())
.or().like(CrmContract::getCustomerBank, bo.getKeyword())
.or().like(CrmContract::getCustomerAccount, bo.getKeyword())
.or().like(CrmContract::getCustomerTaxNo, bo.getKeyword())
.or().like(CrmContract::getRemark, bo.getKeyword()));
}
lqw.like(StringUtils.isNotBlank(bo.getContractName()), CrmContract::getContractName, bo.getContractName());
lqw.eq(StringUtils.isNotBlank(bo.getContractNo()), CrmContract::getContractNo, bo.getContractNo());
lqw.eq(StringUtils.isNotBlank(bo.getSupplier()), CrmContract::getSupplier, bo.getSupplier());
lqw.eq(StringUtils.isNotBlank(bo.getCustomer()), CrmContract::getCustomer, bo.getCustomer());
lqw.eq(bo.getCustomerId() != null, CrmContract::getCustomerId, bo.getCustomerId());
lqw.eq(bo.getSignTime() != null, CrmContract::getSignTime, bo.getSignTime());
lqw.eq(bo.getDeliveryDate() != null, CrmContract::getDeliveryDate, bo.getDeliveryDate());
lqw.eq(StringUtils.isNotBlank(bo.getSignLocation()), CrmContract::getSignLocation, bo.getSignLocation());
lqw.eq(StringUtils.isNotBlank(bo.getProductContent()), CrmContract::getProductContent, bo.getProductContent());
lqw.eq(StringUtils.isNotBlank(bo.getContractContent()), CrmContract::getContractContent, bo.getContractContent());
lqw.eq(StringUtils.isNotBlank(bo.getSupplierAddress()), CrmContract::getSupplierAddress, bo.getSupplierAddress());
lqw.eq(StringUtils.isNotBlank(bo.getSupplierPhone()), CrmContract::getSupplierPhone, bo.getSupplierPhone());
lqw.eq(StringUtils.isNotBlank(bo.getSupplierBank()), CrmContract::getSupplierBank, bo.getSupplierBank());
lqw.eq(StringUtils.isNotBlank(bo.getSupplierAccount()), CrmContract::getSupplierAccount, bo.getSupplierAccount());
lqw.eq(StringUtils.isNotBlank(bo.getSupplierTaxNo()), CrmContract::getSupplierTaxNo, bo.getSupplierTaxNo());
lqw.eq(StringUtils.isNotBlank(bo.getCustomerAddress()), CrmContract::getCustomerAddress, bo.getCustomerAddress());
lqw.eq(StringUtils.isNotBlank(bo.getCustomerPhone()), CrmContract::getCustomerPhone, bo.getCustomerPhone());
lqw.eq(StringUtils.isNotBlank(bo.getCustomerBank()), CrmContract::getCustomerBank, bo.getCustomerBank());
lqw.eq(StringUtils.isNotBlank(bo.getCustomerAccount()), CrmContract::getCustomerAccount, bo.getCustomerAccount());
lqw.eq(StringUtils.isNotBlank(bo.getCustomerTaxNo()), CrmContract::getCustomerTaxNo, bo.getCustomerTaxNo());
lqw.eq(StringUtils.isNotBlank(bo.getTechAnnex()), CrmContract::getTechAnnex, bo.getTechAnnex());
lqw.eq(StringUtils.isNotBlank(bo.getBusinessAnnex()), CrmContract::getBusinessAnnex, bo.getBusinessAnnex());
lqw.eq(StringUtils.isNotBlank(bo.getProductionSchedule()), CrmContract::getProductionSchedule, bo.getProductionSchedule());
lqw.eq(bo.getStatus() != null, CrmContract::getStatus, bo.getStatus());
return lqw;
}
/**
* 新增合同信息
*/
@Override
public Boolean insertByBo(CrmContractBo bo) {
CrmContract add = BeanUtil.toBean(bo, CrmContract.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setContractId(add.getContractId());
}
return flag;
}
/**
* 修改合同信息
*/
@Override
public Boolean updateByBo(CrmContractBo bo) {
CrmContract update = BeanUtil.toBean(bo, CrmContract.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(CrmContract entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除合同信息
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -61,14 +61,27 @@ public class CrmCustomerServiceImpl implements ICrmCustomerService {
private LambdaQueryWrapper<CrmCustomer> buildQueryWrapper(CrmCustomerBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<CrmCustomer> lqw = Wrappers.lambdaQuery();
if (StringUtils.isNotBlank(bo.getKeyword())) {
lqw.and(w -> w.like(CrmCustomer::getCustomerCode, bo.getKeyword())
.or().like(CrmCustomer::getCompanyName, bo.getKeyword())
.or().like(CrmCustomer::getContactPerson, bo.getKeyword())
.or().like(CrmCustomer::getContactWay, bo.getKeyword())
.or().like(CrmCustomer::getIndustry, bo.getKeyword())
.or().like(CrmCustomer::getCustomerLevel, bo.getKeyword())
.or().like(CrmCustomer::getAddress, bo.getKeyword())
.or().like(CrmCustomer::getBankInfo, bo.getKeyword())
.or().like(CrmCustomer::getTaxNumber, bo.getKeyword())
.or().like(CrmCustomer::getRemark, bo.getKeyword()));
}
lqw.eq(StringUtils.isNotBlank(bo.getCustomerCode()), CrmCustomer::getCustomerCode, bo.getCustomerCode());
lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), CrmCustomer::getCompanyName, bo.getCompanyName());
lqw.eq(StringUtils.isNotBlank(bo.getContactPerson()), CrmCustomer::getContactPerson, bo.getContactPerson());
lqw.eq(StringUtils.isNotBlank(bo.getContactWay()), CrmCustomer::getContactWay, bo.getContactWay());
lqw.like(StringUtils.isNotBlank(bo.getContactPerson()), CrmCustomer::getContactPerson, bo.getContactPerson());
lqw.like(StringUtils.isNotBlank(bo.getContactWay()), CrmCustomer::getContactWay, bo.getContactWay());
lqw.eq(StringUtils.isNotBlank(bo.getIndustry()), CrmCustomer::getIndustry, bo.getIndustry());
lqw.eq(StringUtils.isNotBlank(bo.getCustomerLevel()), CrmCustomer::getCustomerLevel, bo.getCustomerLevel());
lqw.eq(StringUtils.isNotBlank(bo.getAddress()), CrmCustomer::getAddress, bo.getAddress());
lqw.eq(StringUtils.isNotBlank(bo.getBankInfo()), CrmCustomer::getBankInfo, bo.getBankInfo());
lqw.like(StringUtils.isNotBlank(bo.getAddress()), CrmCustomer::getAddress, bo.getAddress());
lqw.like(StringUtils.isNotBlank(bo.getBankInfo()), CrmCustomer::getBankInfo, bo.getBankInfo());
lqw.like(StringUtils.isNotBlank(bo.getTaxNumber()), CrmCustomer::getTaxNumber, bo.getTaxNumber());
return lqw;
}

View File

@@ -7,17 +7,35 @@ 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 com.klp.crm.domain.CrmSalesObjection;
import com.klp.domain.WmsMaterialCoil;
import com.klp.domain.WmsReceivable;
import com.klp.domain.vo.WmsDeliveryWaybillVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.klp.crm.domain.bo.CrmOrderItemBo;
import com.klp.crm.domain.vo.CrmOrderItemVo;
import com.klp.crm.domain.vo.CrmContractOrderFinanceVo;
import com.klp.crm.domain.vo.CrmSalesObjectionVo;
import com.klp.domain.vo.WmsReceivableVo;
import com.klp.domain.vo.WmsMaterialCoilVo;
import com.klp.domain.bo.WmsMaterialCoilBo;
import com.klp.crm.domain.CrmOrderItem;
import com.klp.crm.domain.CrmOrder;
import com.klp.domain.WmsDeliveryWaybill;
import com.klp.domain.WmsDeliveryWaybillDetail;
import com.klp.crm.mapper.CrmOrderItemMapper;
import com.klp.crm.mapper.CrmOrderMapper;
import com.klp.crm.mapper.CrmSalesObjectionMapper;
import com.klp.crm.service.ICrmOrderItemService;
import com.klp.mapper.WmsReceivableMapper;
import com.klp.mapper.WmsDeliveryWaybillMapper;
import com.klp.mapper.WmsDeliveryWaybillDetailMapper;
import com.klp.service.IWmsMaterialCoilService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.*;
import java.util.stream.Collectors;
/**
* 正式订单明细Service业务层处理
@@ -30,12 +48,18 @@ import java.util.Collection;
public class CrmOrderItemServiceImpl implements ICrmOrderItemService {
private final CrmOrderItemMapper baseMapper;
private final CrmOrderMapper crmOrderMapper;
private final CrmSalesObjectionMapper crmSalesObjectionMapper;
private final WmsReceivableMapper wmsReceivableMapper;
private final WmsDeliveryWaybillMapper wmsDeliveryWaybillMapper;
private final WmsDeliveryWaybillDetailMapper wmsDeliveryWaybillDetailMapper;
private final IWmsMaterialCoilService iWmsMaterialCoilService;
/**
* 查询正式订单明细
*/
@Override
public CrmOrderItemVo queryById(String itemId){
public CrmOrderItemVo queryById(String itemId) {
return baseMapper.selectVoById(itemId);
}
@@ -61,7 +85,7 @@ public class CrmOrderItemServiceImpl implements ICrmOrderItemService {
private LambdaQueryWrapper<CrmOrderItem> buildQueryWrapper(CrmOrderItemBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<CrmOrderItem> lqw = Wrappers.lambdaQuery();
lqw.eq(StringUtils.isNotBlank(bo.getOrderId()), CrmOrderItem::getOrderId, bo.getOrderId());
lqw.eq(bo.getOrderId() != null, CrmOrderItem::getOrderId, bo.getOrderId());
lqw.eq(StringUtils.isNotBlank(bo.getProductType()), CrmOrderItem::getProductType, bo.getProductType());
lqw.eq(StringUtils.isNotBlank(bo.getRawMaterialSpec()), CrmOrderItem::getRawMaterialSpec, bo.getRawMaterialSpec());
lqw.eq(bo.getProductNum() != null, CrmOrderItem::getProductNum, bo.getProductNum());
@@ -71,10 +95,18 @@ public class CrmOrderItemServiceImpl implements ICrmOrderItemService {
lqw.eq(StringUtils.isNotBlank(bo.getMaterial()), CrmOrderItem::getMaterial, bo.getMaterial());
lqw.eq(StringUtils.isNotBlank(bo.getGrade()), CrmOrderItem::getGrade, bo.getGrade());
lqw.eq(bo.getWeight() != null, CrmOrderItem::getWeight, bo.getWeight());
lqw.eq(bo.getWidthTolerance() != null, CrmOrderItem::getWidthTolerance, bo.getWidthTolerance());
lqw.eq(bo.getThicknessTolerance() != null, CrmOrderItem::getThicknessTolerance, bo.getThicknessTolerance());
lqw.eq(bo.getContractPrice() != null, CrmOrderItem::getContractPrice, bo.getContractPrice());
lqw.eq(StringUtils.isNotBlank(bo.getCustomizer()), CrmOrderItem::getCustomizer, bo.getCustomizer());
lqw.eq(StringUtils.isNotBlank(bo.getShipper()), CrmOrderItem::getShipper, bo.getShipper());
lqw.eq(StringUtils.isNotBlank(bo.getProductionBatch()), CrmOrderItem::getProductionBatch, bo.getProductionBatch());
lqw.eq(StringUtils.isNotBlank(bo.getSurfaceTreatment()), CrmOrderItem::getSurfaceTreatment, bo.getSurfaceTreatment());
lqw.eq(StringUtils.isNotBlank(bo.getEdgeCuttingReq()), CrmOrderItem::getEdgeCuttingReq, bo.getEdgeCuttingReq());
lqw.eq(StringUtils.isNotBlank(bo.getPackagingReq()), CrmOrderItem::getPackagingReq, bo.getPackagingReq());
lqw.eq(bo.getWidth() != null, CrmOrderItem::getWidth, bo.getWidth());
lqw.eq(bo.getThickness() != null, CrmOrderItem::getThickness, bo.getThickness());
lqw.eq(StringUtils.isNotBlank(bo.getPurpose()), CrmOrderItem::getPurpose, bo.getPurpose());
return lqw;
}
@@ -106,7 +138,7 @@ public class CrmOrderItemServiceImpl implements ICrmOrderItemService {
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(CrmOrderItem entity){
private void validEntityBeforeSave(CrmOrderItem entity) {
//TODO 做一些数据校验,如唯一约束
}
@@ -115,9 +147,198 @@ public class CrmOrderItemServiceImpl implements ICrmOrderItemService {
*/
@Override
public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
if(isValid){
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}
@Override
public CrmContractOrderFinanceVo queryFinanceAndObjectionByContractId(Long contractId) {
CrmContractOrderFinanceVo result = new CrmContractOrderFinanceVo();
LambdaQueryWrapper<CrmOrder> orderWrapper = new LambdaQueryWrapper<>();
orderWrapper.eq(CrmOrder::getContractId, contractId);
List<CrmOrder> orders = crmOrderMapper.selectList(orderWrapper);
if (orders == null || orders.isEmpty()) {
return result;
}
List<Long> orderIds = orders.stream()
.map(CrmOrder::getOrderId)
.collect(Collectors.toList());
LambdaQueryWrapper<CrmSalesObjection> objectionWrapper = new LambdaQueryWrapper<>();
objectionWrapper.in(CrmSalesObjection::getOrderId, orderIds);
List<CrmSalesObjectionVo> objectionList = crmSalesObjectionMapper.selectVoList(objectionWrapper);
result.setObjectionList(objectionList);
LambdaQueryWrapper<com.klp.domain.WmsReceivable> receivableWrapper = new LambdaQueryWrapper<>();
receivableWrapper.in(WmsReceivable::getOrderId, orderIds);
List<WmsReceivableVo> receivableList = wmsReceivableMapper.selectVoList(receivableWrapper);
result.setReceivableList(receivableList);
LambdaQueryWrapper<WmsDeliveryWaybill> waybillWrapper = new LambdaQueryWrapper<>();
waybillWrapper.in(WmsDeliveryWaybill::getOrderId, orderIds);
List<WmsDeliveryWaybillVo> wmsDeliveryWaybills = wmsDeliveryWaybillMapper.selectVoList(waybillWrapper);
result.setWmsDeliveryWaybills(wmsDeliveryWaybills);
return result;
}
@Override
public List<WmsMaterialCoilVo> queryCoilsByOrderId(Long orderId) {
LambdaQueryWrapper<WmsDeliveryWaybill> waybillWrapper = new LambdaQueryWrapper<>();
waybillWrapper.eq(WmsDeliveryWaybill::getOrderId, orderId);
List<WmsDeliveryWaybill> waybills = wmsDeliveryWaybillMapper.selectList(waybillWrapper);
if (waybills == null || waybills.isEmpty()) {
return Collections.emptyList();
}
List<Long> waybillIds = waybills.stream()
.map(WmsDeliveryWaybill::getWaybillId)
.collect(Collectors.toList());
LambdaQueryWrapper<WmsDeliveryWaybillDetail> detailWrapper = new LambdaQueryWrapper<>();
detailWrapper.in(WmsDeliveryWaybillDetail::getWaybillId, waybillIds);
List<WmsDeliveryWaybillDetail> details = wmsDeliveryWaybillDetailMapper.selectList(detailWrapper);
if (details == null || details.isEmpty()) {
return Collections.emptyList();
}
String coilIds = details.stream()
.map(WmsDeliveryWaybillDetail::getCoilId)
.map(String::valueOf)
.collect(Collectors.joining(","));
WmsMaterialCoilBo coilBo = new WmsMaterialCoilBo();
coilBo.setCoilIds(coilIds);
return iWmsMaterialCoilService.queryList(coilBo);
}
@Override
public List<WmsMaterialCoilVo> queryCoilsByContractId(Long contractId) {
LambdaQueryWrapper<CrmOrder> orderWrapper = new LambdaQueryWrapper<>();
orderWrapper.eq(CrmOrder::getContractId, contractId);
List<CrmOrder> orders = crmOrderMapper.selectList(orderWrapper);
if (orders == null || orders.isEmpty()) {
return Collections.emptyList();
}
List<Long> orderIds = orders.stream()
.map(CrmOrder::getOrderId)
.collect(Collectors.toList());
LambdaQueryWrapper<WmsDeliveryWaybill> waybillWrapper = new LambdaQueryWrapper<>();
waybillWrapper.in(WmsDeliveryWaybill::getOrderId, orderIds);
List<WmsDeliveryWaybill> waybills = wmsDeliveryWaybillMapper.selectList(waybillWrapper);
if (waybills == null || waybills.isEmpty()) {
return Collections.emptyList();
}
List<Long> waybillIds = waybills.stream()
.map(WmsDeliveryWaybill::getWaybillId)
.collect(Collectors.toList());
LambdaQueryWrapper<WmsDeliveryWaybillDetail> detailWrapper = new LambdaQueryWrapper<>();
detailWrapper.in(WmsDeliveryWaybillDetail::getWaybillId, waybillIds);
List<WmsDeliveryWaybillDetail> details = wmsDeliveryWaybillDetailMapper.selectList(detailWrapper);
if (details == null || details.isEmpty()) {
return Collections.emptyList();
}
String coilIds = details.stream()
.map(WmsDeliveryWaybillDetail::getCoilId)
.map(String::valueOf)
.collect(Collectors.joining(","));
WmsMaterialCoilBo coilBo = new WmsMaterialCoilBo();
coilBo.setCoilIds(coilIds);
return iWmsMaterialCoilService.queryList(coilBo);
}
@Override
public CrmContractOrderFinanceVo queryFinanceAndObjectionByCustomerId(String customerId) {
CrmContractOrderFinanceVo result = new CrmContractOrderFinanceVo();
LambdaQueryWrapper<CrmOrder> orderWrapper = new LambdaQueryWrapper<>();
orderWrapper.eq(CrmOrder::getCustomerId, customerId);
List<CrmOrder> orders = crmOrderMapper.selectList(orderWrapper);
if (orders == null || orders.isEmpty()) {
return result;
}
List<Long> orderIds = orders.stream()
.map(CrmOrder::getOrderId)
.collect(Collectors.toList());
LambdaQueryWrapper<CrmSalesObjection> objectionWrapper = new LambdaQueryWrapper<>();
objectionWrapper.in(CrmSalesObjection::getOrderId, orderIds);
List<CrmSalesObjectionVo> objectionList = crmSalesObjectionMapper.selectVoList(objectionWrapper);
result.setObjectionList(objectionList);
LambdaQueryWrapper<com.klp.domain.WmsReceivable> receivableWrapper = new LambdaQueryWrapper<>();
receivableWrapper.in(WmsReceivable::getOrderId, orderIds);
List<WmsReceivableVo> receivableList = wmsReceivableMapper.selectVoList(receivableWrapper);
result.setReceivableList(receivableList);
LambdaQueryWrapper<WmsDeliveryWaybill> waybillWrapper = new LambdaQueryWrapper<>();
waybillWrapper.in(WmsDeliveryWaybill::getOrderId, orderIds);
List<WmsDeliveryWaybillVo> wmsDeliveryWaybills = wmsDeliveryWaybillMapper.selectVoList(waybillWrapper);
result.setWmsDeliveryWaybills(wmsDeliveryWaybills);
return result;
}
@Override
public List<WmsMaterialCoilVo> queryCoilsByCustomerId(String customerId) {
LambdaQueryWrapper<CrmOrder> orderWrapper = new LambdaQueryWrapper<>();
orderWrapper.eq(CrmOrder::getCustomerId, customerId);
List<CrmOrder> orders = crmOrderMapper.selectList(orderWrapper);
if (orders == null || orders.isEmpty()) {
return Collections.emptyList();
}
List<Long> orderIds = orders.stream()
.map(CrmOrder::getOrderId)
.collect(Collectors.toList());
LambdaQueryWrapper<WmsDeliveryWaybill> waybillWrapper = new LambdaQueryWrapper<>();
waybillWrapper.in(WmsDeliveryWaybill::getOrderId, orderIds);
List<WmsDeliveryWaybill> waybills = wmsDeliveryWaybillMapper.selectList(waybillWrapper);
if (waybills == null || waybills.isEmpty()) {
return Collections.emptyList();
}
List<Long> waybillIds = waybills.stream()
.map(WmsDeliveryWaybill::getWaybillId)
.collect(Collectors.toList());
LambdaQueryWrapper<WmsDeliveryWaybillDetail> detailWrapper = new LambdaQueryWrapper<>();
detailWrapper.in(WmsDeliveryWaybillDetail::getWaybillId, waybillIds);
List<WmsDeliveryWaybillDetail> details = wmsDeliveryWaybillDetailMapper.selectList(detailWrapper);
if (details == null || details.isEmpty()) {
return Collections.emptyList();
}
String coilIds = details.stream()
.map(WmsDeliveryWaybillDetail::getCoilId)
.map(String::valueOf)
.collect(Collectors.joining(","));
WmsMaterialCoilBo coilBo = new WmsMaterialCoilBo();
coilBo.setCoilIds(coilIds);
return iWmsMaterialCoilService.queryList(coilBo);
}
}

View File

@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.klp.common.utils.StringUtils;
import com.klp.crm.domain.vo.CrmOrderOperationTraceVo;
import com.klp.mapper.WmsCoilContractRelMapper;
import com.klp.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -17,6 +18,11 @@ import com.klp.crm.domain.vo.CrmOrderVo;
import com.klp.crm.domain.CrmOrder;
import com.klp.crm.mapper.CrmOrderMapper;
import com.klp.crm.service.ICrmOrderService;
import com.klp.domain.WmsCoilContractRel;
import com.klp.domain.bo.WmsMaterialCoilBo;
import com.klp.domain.vo.WmsMaterialCoilVo;
import com.klp.service.IWmsCoilContractRelService;
import com.klp.service.IWmsMaterialCoilService;
import java.util.*;
import java.util.stream.Collectors;
@@ -35,6 +41,10 @@ public class CrmOrderServiceImpl implements ICrmOrderService {
private final ISysUserService userService;
private final WmsCoilContractRelMapper coilContractRelMapper;
private final IWmsMaterialCoilService materialCoilService;
/**
* 查询正式订单主
*/
@@ -43,6 +53,19 @@ public class CrmOrderServiceImpl implements ICrmOrderService {
return baseMapper.selectVoById(orderId);
}
/**
* 根据ID列表查询正式订单
*/
@Override
public List<CrmOrderVo> queryByIds(List<Long> orderIds) {
if (orderIds == null || orderIds.isEmpty()) {
return new ArrayList<>();
}
LambdaQueryWrapper<CrmOrder> lqw = Wrappers.lambdaQuery();
lqw.in(CrmOrder::getOrderId, orderIds);
return baseMapper.selectVoList(lqw);
}
/**
* 查询正式订单主列表
*/
@@ -76,12 +99,75 @@ public class CrmOrderServiceImpl implements ICrmOrderService {
}
}
}
// 查询订单关联的钢卷ID列表
List<Long> contractIds = records.stream()
.map(CrmOrderVo::getOrderId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (!contractIds.isEmpty()) {
// 批量查询钢卷与合同关联关系
LambdaQueryWrapper<WmsCoilContractRel> coilQw = Wrappers.lambdaQuery();
coilQw.in(WmsCoilContractRel::getContractId, contractIds);
coilQw.eq(WmsCoilContractRel::getDelFlag, 0);
List<WmsCoilContractRel> coilRels = coilContractRelMapper.selectList(coilQw);
// 按contractId分组,收集coilId列表
Map<Long, List<Long>> coilIdMap = coilRels.stream()
.filter(rel -> rel.getContractId() != null && rel.getCoilId() != null)
.collect(Collectors.groupingBy(
WmsCoilContractRel::getContractId,
Collectors.mapping(WmsCoilContractRel::getCoilId, Collectors.toList())
));
// 查询所有相关钢卷的详细信息
Set<Long> allCoilIds = coilIdMap.values().stream()
.flatMap(List::stream)
.collect(Collectors.toSet());
Map<Long, WmsMaterialCoilVo> coilVoMap = Collections.emptyMap();
if (!allCoilIds.isEmpty()) {
WmsMaterialCoilBo coilBo = new WmsMaterialCoilBo();
coilBo.setCoilIds(allCoilIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
List<WmsMaterialCoilVo> allCoils = materialCoilService.queryList(coilBo);
coilVoMap = allCoils.stream()
.collect(Collectors.toMap(WmsMaterialCoilVo::getCoilId, c -> c, (a, b) -> a));
}
// 设置到每个订单的coilIds和coilList字段
for (CrmOrderVo vo : records) {
if (vo.getOrderId() != null && coilIdMap.containsKey(vo.getOrderId())) {
List<Long> coilIdList = coilIdMap.get(vo.getOrderId());
// 设置coilList钢卷详细信息列表
List<WmsMaterialCoilVo> coilList = coilIdList.stream()
.map(coilVoMap::get)
.filter(Objects::nonNull)
.collect(Collectors.toList());
vo.setCoilList(coilList);
}
}
}
return TableDataInfo.build(result);
}
private QueryWrapper<CrmOrder> buildQueryWrapperPlus(CrmOrderBo bo) {
Map<String, Object> params = bo.getParams();
QueryWrapper<CrmOrder> qw = Wrappers.query();
if (StringUtils.isNotBlank(bo.getKeyword())) {
qw.and(w -> w.like("co.order_code", bo.getKeyword())
.or().like("co.customer_id", bo.getKeyword())
.or().like("co.salesman", bo.getKeyword())
.or().like("co.audit_user", bo.getKeyword())
.or().like("co.contract_code", bo.getKeyword())
.or().like("co.annex_files", bo.getKeyword())
.or().like("co.remark", bo.getKeyword())
.or().like("co.contract_name", bo.getKeyword())
.or().like("co.supplier", bo.getKeyword())
.or().like("co.customer", bo.getKeyword()));
}
qw.eq(StringUtils.isNotBlank(bo.getOrderCode()), "co.order_code", bo.getOrderCode());
qw.eq(bo.getOrderType() != null, "co.order_type", bo.getOrderType());
qw.eq(StringUtils.isNotBlank(bo.getCustomerId()), "co.customer_id", bo.getCustomerId());
@@ -95,6 +181,33 @@ public class CrmOrderServiceImpl implements ICrmOrderService {
qw.eq(bo.getFinanceStatus() != null, "co.finance_status", bo.getFinanceStatus());
qw.eq(bo.getUnpaidAmount() != null, "co.unpaid_amount", bo.getUnpaidAmount());
qw.like(StringUtils.isNotBlank(bo.getContractCode()), "co.contract_code", bo.getContractCode());
qw.like(StringUtils.isNotBlank(bo.getContractName()), "co.contract_name", bo.getContractName());
qw.like(StringUtils.isNotBlank(bo.getSupplier()), "co.supplier", bo.getSupplier());
qw.like(StringUtils.isNotBlank(bo.getCustomer()), "co.customer", bo.getCustomer());
qw.eq(bo.getSignTime() != null, "co.sign_time", bo.getSignTime());
qw.like(StringUtils.isNotBlank(bo.getSignLocation()), "co.sign_location", bo.getSignLocation());
qw.eq(StringUtils.isNotBlank(bo.getProductContent()), "co.product_content", bo.getProductContent());
qw.eq(StringUtils.isNotBlank(bo.getContractContent()), "co.contract_content", bo.getContractContent());
qw.like(StringUtils.isNotBlank(bo.getSupplierAddress()), "co.supplier_address", bo.getSupplierAddress());
qw.like(StringUtils.isNotBlank(bo.getSupplierPhone()), "co.supplier_phone", bo.getSupplierPhone());
qw.like(StringUtils.isNotBlank(bo.getSupplierBank()), "co.supplier_bank", bo.getSupplierBank());
qw.like(StringUtils.isNotBlank(bo.getSupplierAccount()), "co.supplier_account", bo.getSupplierAccount());
qw.like(StringUtils.isNotBlank(bo.getSupplierTaxNo()), "co.supplier_tax_no", bo.getSupplierTaxNo());
qw.like(StringUtils.isNotBlank(bo.getCustomerAddress()), "co.customer_address", bo.getCustomerAddress());
qw.like(StringUtils.isNotBlank(bo.getCustomerPhone()), "co.customer_phone", bo.getCustomerPhone());
qw.like(StringUtils.isNotBlank(bo.getCustomerBank()), "co.customer_bank", bo.getCustomerBank());
qw.like(StringUtils.isNotBlank(bo.getCustomerAccount()), "co.customer_account", bo.getCustomerAccount());
qw.like(StringUtils.isNotBlank(bo.getCustomerTaxNo()), "co.customer_tax_no", bo.getCustomerTaxNo());
qw.like(StringUtils.isNotBlank(bo.getTechAnnex()), "co.tech_annex", bo.getTechAnnex());
qw.like(StringUtils.isNotBlank(bo.getBusinessAnnex()), "co.business_annex", bo.getBusinessAnnex());
qw.like(StringUtils.isNotBlank(bo.getProductionSchedule()), "co.production_schedule", bo.getProductionSchedule());
qw.like(StringUtils.isNotBlank(bo.getUnitPriceRemark()), "co.unit_price_remark", bo.getUnitPriceRemark());
qw.eq(bo.getDepositPayable() != null, "co.deposit_payable", bo.getDepositPayable());
qw.eq(bo.getDepositPaid() != null, "co.deposit_paid", bo.getDepositPaid());
qw.eq(bo.getDepositRatio() != null, "co.deposit_ratio", bo.getDepositRatio());
qw.eq(bo.getStatus() != null, "co.status", bo.getStatus());
qw.eq(bo.getContractId() != null, "co.contract_id", bo.getContractId());
qw.like(StringUtils.isNotBlank(bo.getAnnexFiles()), "co.annex_files", bo.getAnnexFiles());
//逻辑删除
qw.eq("co.del_flag", 0);
//根据orderType排序预订单是0 正是订单是1 0排在前面 1排在后面 升序
@@ -128,6 +241,33 @@ public class CrmOrderServiceImpl implements ICrmOrderService {
lqw.eq(bo.getFinanceStatus() != null, CrmOrder::getFinanceStatus, bo.getFinanceStatus());
lqw.eq(bo.getUnpaidAmount() != null, CrmOrder::getUnpaidAmount, bo.getUnpaidAmount());
lqw.like(StringUtils.isNotBlank(bo.getContractCode()), CrmOrder::getContractCode, bo.getContractCode());
lqw.like(StringUtils.isNotBlank(bo.getContractName()), CrmOrder::getContractName, bo.getContractName());
lqw.like(StringUtils.isNotBlank(bo.getSupplier()), CrmOrder::getSupplier, bo.getSupplier());
lqw.like(StringUtils.isNotBlank(bo.getCustomer()), CrmOrder::getCustomer, bo.getCustomer());
lqw.eq(bo.getSignTime() != null, CrmOrder::getSignTime, bo.getSignTime());
lqw.like(StringUtils.isNotBlank(bo.getSignLocation()), CrmOrder::getSignLocation, bo.getSignLocation());
lqw.eq(StringUtils.isNotBlank(bo.getProductContent()), CrmOrder::getProductContent, bo.getProductContent());
lqw.eq(StringUtils.isNotBlank(bo.getContractContent()), CrmOrder::getContractContent, bo.getContractContent());
lqw.like(StringUtils.isNotBlank(bo.getSupplierAddress()), CrmOrder::getSupplierAddress, bo.getSupplierAddress());
lqw.like(StringUtils.isNotBlank(bo.getSupplierPhone()), CrmOrder::getSupplierPhone, bo.getSupplierPhone());
lqw.like(StringUtils.isNotBlank(bo.getSupplierBank()), CrmOrder::getSupplierBank, bo.getSupplierBank());
lqw.like(StringUtils.isNotBlank(bo.getSupplierAccount()), CrmOrder::getSupplierAccount, bo.getSupplierAccount());
lqw.like(StringUtils.isNotBlank(bo.getSupplierTaxNo()), CrmOrder::getSupplierTaxNo, bo.getSupplierTaxNo());
lqw.like(StringUtils.isNotBlank(bo.getCustomerAddress()), CrmOrder::getCustomerAddress, bo.getCustomerAddress());
lqw.like(StringUtils.isNotBlank(bo.getCustomerPhone()), CrmOrder::getCustomerPhone, bo.getCustomerPhone());
lqw.like(StringUtils.isNotBlank(bo.getCustomerBank()), CrmOrder::getCustomerBank, bo.getCustomerBank());
lqw.like(StringUtils.isNotBlank(bo.getCustomerAccount()), CrmOrder::getCustomerAccount, bo.getCustomerAccount());
lqw.like(StringUtils.isNotBlank(bo.getCustomerTaxNo()), CrmOrder::getCustomerTaxNo, bo.getCustomerTaxNo());
lqw.like(StringUtils.isNotBlank(bo.getTechAnnex()), CrmOrder::getTechAnnex, bo.getTechAnnex());
lqw.like(StringUtils.isNotBlank(bo.getBusinessAnnex()), CrmOrder::getBusinessAnnex, bo.getBusinessAnnex());
lqw.like(StringUtils.isNotBlank(bo.getProductionSchedule()), CrmOrder::getProductionSchedule, bo.getProductionSchedule());
lqw.like(StringUtils.isNotBlank(bo.getUnitPriceRemark()), CrmOrder::getUnitPriceRemark, bo.getUnitPriceRemark());
lqw.eq(bo.getDepositPayable() != null, CrmOrder::getDepositPayable, bo.getDepositPayable());
lqw.eq(bo.getDepositPaid() != null, CrmOrder::getDepositPaid, bo.getDepositPaid());
lqw.eq(bo.getDepositRatio() != null, CrmOrder::getDepositRatio, bo.getDepositRatio());
lqw.eq(bo.getStatus() != null, CrmOrder::getStatus, bo.getStatus());
lqw.eq(bo.getContractId() != null, CrmOrder::getContractId, bo.getContractId());
lqw.like(StringUtils.isNotBlank(bo.getAnnexFiles()), CrmOrder::getAnnexFiles, bo.getAnnexFiles());
return lqw;
}

View File

@@ -59,7 +59,7 @@ public class CrmSalesReportServiceImpl implements ICrmSalesReportService {
List<CrmSalesReportVo.OrderDetail> orderDetails = baseMapper.selectOrderDetailList(bo);
if (StringUtils.isNotNull(orderDetails) && !orderDetails.isEmpty()) {
// 提取所有订单ID
List<String> orderIds = orderDetails.stream()
List<Long> orderIds = orderDetails.stream()
.map(CrmSalesReportVo.OrderDetail::getOrderId)
.filter(StringUtils::isNotNull)
.distinct()
@@ -70,7 +70,7 @@ public class CrmSalesReportServiceImpl implements ICrmSalesReportService {
List<CrmOrderItem> orderItems = crmOrderItemMapper.selectOrderItemsByOrderIds(orderIds);
// 将明细按订单ID分组
Map<String, List<CrmOrderItem>> orderItemMap = orderItems.stream()
Map<Long, List<CrmOrderItem>> orderItemMap = orderItems.stream()
.collect(Collectors.groupingBy(CrmOrderItem::getOrderId));
// 为每个订单设置对应的明细列表

View File

@@ -0,0 +1,42 @@
<?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.crm.mapper.CrmContractMapper">
<resultMap type="com.klp.crm.domain.CrmContract" id="CrmContractResult">
<result property="contractId" column="contract_id"/>
<result property="contractName" column="contract_name"/>
<result property="contractNo" column="contract_no"/>
<result property="supplier" column="supplier"/>
<result property="customer" column="customer"/>
<result property="customerId" column="customer_id"/>
<result property="deliveryDate" column="delivery_date"/>
<result property="signTime" column="sign_time"/>
<result property="signLocation" column="sign_location"/>
<result property="productContent" column="product_content"/>
<result property="contractContent" column="contract_content"/>
<result property="supplierAddress" column="supplier_address"/>
<result property="supplierPhone" column="supplier_phone"/>
<result property="supplierBank" column="supplier_bank"/>
<result property="supplierAccount" column="supplier_account"/>
<result property="supplierTaxNo" column="supplier_tax_no"/>
<result property="customerAddress" column="customer_address"/>
<result property="customerPhone" column="customer_phone"/>
<result property="customerBank" column="customer_bank"/>
<result property="customerAccount" column="customer_account"/>
<result property="customerTaxNo" column="customer_tax_no"/>
<result property="techAnnex" column="tech_annex"/>
<result property="businessAnnex" column="business_annex"/>
<result property="productionSchedule" column="production_schedule"/>
<result property="status" column="status"/>
<result property="remark" column="remark"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="delFlag" column="del_flag"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,27 @@
<?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.crm.mapper.CrmContractProductMapper">
<resultMap type="com.klp.crm.domain.CrmContractProduct" id="CrmContractProductResult">
<result property="contractProductId" column="contract_product_id"/>
<result property="contractId" column="contract_id"/>
<result property="productName" column="product_name"/>
<result property="specMin" column="spec_min"/>
<result property="specMax" column="spec_max"/>
<result property="material" column="material"/>
<result property="quantity" column="quantity"/>
<result property="taxInclusiveUnitPrice" column="tax_inclusive_unit_price"/>
<result property="exTaxUnitPrice" column="ex_tax_unit_price"/>
<result property="taxInclusiveAmount" column="tax_inclusive_amount"/>
<result property="delFlag" column="del_flag"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="remark" column="remark"/>
</resultMap>
</mapper>

View File

@@ -14,6 +14,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="customerLevel" column="customer_level"/>
<result property="address" column="address"/>
<result property="bankInfo" column="bank_info"/>
<result property="taxNumber" column="tax_number"/>
<result property="remark" column="remark"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>

View File

@@ -17,10 +17,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="material" column="material"/>
<result property="grade" column="grade"/>
<result property="weight" column="weight"/>
<result property="widthTolerance" column="width_tolerance"/>
<result property="thicknessTolerance" column="thickness_tolerance"/>
<result property="contractPrice" column="contract_price"/>
<result property="customizer" column="customizer"/>
<result property="shipper" column="shipper"/>
<result property="productionBatch" column="production_batch"/>
<result property="surfaceTreatment" column="surface_treatment"/>
<result property="edgeCuttingReq" column="edge_cutting_req"/>
<result property="packagingReq" column="packaging_req"/>
<result property="width" column="width"/>
<result property="thickness" column="thickness"/>
<result property="purpose" column="purpose"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
@@ -42,10 +50,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
material,
grade,
weight,
width_tolerance,
thickness_tolerance,
contract_price,
customizer,
shipper,
production_batch,
surface_treatment,
edge_cutting_req,
packaging_req,
width,
thickness,
purpose,
create_by,
create_time,
update_by,

View File

@@ -20,6 +20,33 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="unpaidAmount" column="unpaid_amount"/>
<result property="remark" column="remark"/>
<result property="contractCode" column="contract_code"/>
<result property="contractName" column="contract_name"/>
<result property="supplier" column="supplier"/>
<result property="customer" column="customer"/>
<result property="signTime" column="sign_time"/>
<result property="signLocation" column="sign_location"/>
<result property="productContent" column="product_content"/>
<result property="contractContent" column="contract_content"/>
<result property="supplierAddress" column="supplier_address"/>
<result property="supplierPhone" column="supplier_phone"/>
<result property="supplierBank" column="supplier_bank"/>
<result property="supplierAccount" column="supplier_account"/>
<result property="supplierTaxNo" column="supplier_tax_no"/>
<result property="customerAddress" column="customer_address"/>
<result property="customerPhone" column="customer_phone"/>
<result property="customerBank" column="customer_bank"/>
<result property="customerAccount" column="customer_account"/>
<result property="customerTaxNo" column="customer_tax_no"/>
<result property="techAnnex" column="tech_annex"/>
<result property="businessAnnex" column="business_annex"/>
<result property="productionSchedule" column="production_schedule"/>
<result property="unitPriceRemark" column="unit_price_remark"/>
<result property="depositPayable" column="deposit_payable"/>
<result property="depositPaid" column="deposit_paid"/>
<result property="depositRatio" column="deposit_ratio"/>
<result property="status" column="status"/>
<result property="contractId" column="contract_id"/>
<result property="annexFiles" column="annex_files"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
@@ -43,6 +70,33 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
co.unpaid_amount AS unpaidAmount,
co.remark,
co.contract_code AS contractCode,
co.contract_name AS contractName,
co.supplier,
co.customer,
co.sign_time AS signTime,
co.sign_location AS signLocation,
co.product_content AS productContent,
co.contract_content AS contractContent,
co.supplier_address AS supplierAddress,
co.supplier_phone AS supplierPhone,
co.supplier_bank AS supplierBank,
co.supplier_account AS supplierAccount,
co.supplier_tax_no AS supplierTaxNo,
co.customer_address AS customerAddress,
co.customer_phone AS customerPhone,
co.customer_bank AS customerBank,
co.customer_account AS customerAccount,
co.customer_tax_no AS customerTaxNo,
co.tech_annex AS techAnnex,
co.business_annex AS businessAnnex,
co.production_schedule AS productionSchedule,
co.unit_price_remark AS unitPriceRemark,
co.deposit_payable AS depositPayable,
co.deposit_paid AS depositPaid,
co.deposit_ratio AS depositRatio,
co.status,
co.contract_id AS contractId,
co.annex_files AS annexFiles,
co.create_by AS createBy,
co.create_time AS createTime,
co.update_by AS updateBy,
@@ -75,6 +129,33 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
co.unpaid_amount AS unpaidAmount,
co.remark,
co.contract_code AS contractCode,
co.contract_name AS contractName,
co.supplier,
co.customer,
co.sign_time AS signTime,
co.sign_location AS signLocation,
co.product_content AS productContent,
co.contract_content AS contractContent,
co.supplier_address AS supplierAddress,
co.supplier_phone AS supplierPhone,
co.supplier_bank AS supplierBank,
co.supplier_account AS supplierAccount,
co.supplier_tax_no AS supplierTaxNo,
co.customer_address AS customerAddress,
co.customer_phone AS customerPhone,
co.customer_bank AS customerBank,
co.customer_account AS customerAccount,
co.customer_tax_no AS customerTaxNo,
co.tech_annex AS techAnnex,
co.business_annex AS businessAnnex,
co.production_schedule AS productionSchedule,
co.unit_price_remark AS unitPriceRemark,
co.deposit_payable AS depositPayable,
co.deposit_paid AS depositPaid,
co.deposit_ratio AS depositRatio,
co.status,
co.contract_id AS contractId,
co.annex_files AS annexFiles,
co.create_by AS createBy,
co.create_time AS createTime,
co.update_by AS updateBy,

View File

@@ -40,6 +40,9 @@
"@babel/parser": "7.7.4",
"@jiaminghi/data-view": "^2.10.0",
"@riophae/vue-treeselect": "0.4.0",
"@vue-office/docx": "^1.6.3",
"@vue-office/excel": "^1.7.14",
"@vue/composition-api": "^1.7.2",
"axios": "0.24.0",
"bpmn-js-token-simulation": "0.10.0",
"clipboard": "2.0.8",
@@ -74,12 +77,15 @@
"vue": "2.6.12",
"vue-count-to": "1.0.13",
"vue-cropper": "0.5.5",
"vue-demi": "^0.14.10",
"vue-flv-player": "^1.0.3",
"vue-konva": "^2.1.7",
"vue-meta": "2.4.0",
"vue-router": "3.4.9",
"vuedraggable": "2.24.3",
"vuex": "3.6.0",
"vxe-table": "^2.11.0",
"xe-utils": "^3.5.31",
"xlsx": "^0.18.5",
"xml-js": "1.6.11"
},

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询排产单明细列表
export function listPlanDetail(query) {
return request({
url: '/aps/planDetail/list',
method: 'get',
params: query
})
}
// 查询排产单明细详细
export function getPlanDetail(planDetailId) {
return request({
url: '/aps/planDetail/' + planDetailId,
method: 'get'
})
}
// 新增排产单明细
export function addPlanDetail(data) {
return request({
url: '/aps/planDetail',
method: 'post',
data: data
})
}
// 修改排产单明细
export function updatePlanDetail(data) {
return request({
url: '/aps/planDetail',
method: 'put',
data: data
})
}
// 删除排产单明细
export function delPlanDetail(planDetailId) {
return request({
url: '/aps/planDetail/' + planDetailId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询排产单主列表
export function listPlanSheet(query) {
return request({
url: '/aps/planSheet/list',
method: 'get',
params: query
})
}
// 查询排产单主详细
export function getPlanSheet(planSheetId) {
return request({
url: '/aps/planSheet/' + planSheetId,
method: 'get'
})
}
// 新增排产单主
export function addPlanSheet(data) {
return request({
url: '/aps/planSheet',
method: 'post',
data: data
})
}
// 修改排产单主
export function updatePlanSheet(data) {
return request({
url: '/aps/planSheet',
method: 'put',
data: data
})
}
// 删除排产单主
export function delPlanSheet(planSheetId) {
return request({
url: '/aps/planSheet/' + planSheetId,
method: 'delete'
})
}

View File

@@ -0,0 +1,62 @@
import request from '@/utils/request'
// 查询合同信息列表
export function listContract(query) {
return request({
url: '/crm/contract/list',
method: 'get',
params: query
})
}
// 查询合同信息详细
export function getContract(contractId) {
return request({
url: '/crm/contract/' + contractId,
method: 'get'
})
}
// 新增合同信息
export function addContract(data) {
return request({
url: '/crm/contract',
method: 'post',
data: data
})
}
// 修改合同信息
export function updateContract(data) {
return request({
url: '/crm/contract',
method: 'put',
data: data
})
}
// 删除合同信息
export function delContract(contractId) {
return request({
url: '/crm/contract/' + contractId,
method: 'delete'
})
}
// 查询合同下的所有订单异议和收款记录
export function listContractOrderObjection(contractId) {
return request({
url: '/crm/orderItem/contractFinance/' + contractId,
method: 'get',
})
}
/**
* 查询该合同下的配卷情况
*/
export function listContractPackaging(contractId) {
return request({
url: '/crm/orderItem/coils/contract/' + contractId,
method: 'get',
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询合同产品明细列表
export function listContractProduct(query) {
return request({
url: '/crm/contractProduct/list',
method: 'get',
params: query
})
}
// 查询合同产品明细详细
export function getContractProduct(contractProductId) {
return request({
url: '/crm/contractProduct/' + contractProductId,
method: 'get'
})
}
// 新增合同产品明细
export function addContractProduct(data) {
return request({
url: '/crm/contractProduct',
method: 'post',
data: data
})
}
// 修改合同产品明细
export function updateContractProduct(data) {
return request({
url: '/crm/contractProduct',
method: 'put',
data: data
})
}
// 删除合同产品明细
export function delContractProduct(contractProductId) {
return request({
url: '/crm/contractProduct/' + contractProductId,
method: 'delete'
})
}

View File

@@ -42,3 +42,19 @@ export function delCustomer(customerId) {
method: 'delete'
})
}
// 查询该客户相关的配卷情况
export function listCoilByCustomerId(customerId) {
return request({
url: '/crm/orderItem/coils/customer/' + customerId,
method: 'get'
})
}
// 查询该项目相关的订单异议和财务信息
export function listFinanceByCustomerId(customerId) {
return request({
url: '/crm/orderItem/customerFinance/' + customerId,
method: 'get'
})
}

View File

@@ -42,3 +42,24 @@ export function delOrder(orderId) {
method: 'delete'
})
}
/**
* 查询该订单下的所有配卷
*/
export function listOrderPackaging(orderId) {
return request({
url: `/crm/orderItem/coils/order/${orderId}`,
method: 'get',
})
}
/**
* 查询今日订单
*/
export function listTodayOrder(query) {
return request({
url: '/crm/order/daily',
method: 'get',
params: query
})
}

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

@@ -378,4 +378,23 @@ export function listWithBindInfoCoil(params) {
params,
timeout: 600000
})
}
/**
* 类型不匹配的卷
*/
export function listTypeErrorCoil() {
return request({
url: '/wms/materialCoil/queryMismatchedItemCoils',
method: 'get',
timeout: 600000
})
}
export function getCoilStatisticsList(params) {
return request({
url: '/wms/materialCoil/statisticsList',
method: 'get',
params,
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询钢卷与合同关联关系列表
export function listCoilContractRel(query) {
return request({
url: '/wms/coilContractRel/list',
method: 'get',
params: query
})
}
// 查询钢卷与合同关联关系详细
export function getCoilContractRel(relId) {
return request({
url: '/wms/coilContractRel/' + relId,
method: 'get'
})
}
// 新增钢卷与合同关联关系
export function addCoilContractRel(data) {
return request({
url: '/wms/coilContractRel',
method: 'post',
data: data
})
}
// 修改钢卷与合同关联关系
export function updateCoilContractRel(data) {
return request({
url: '/wms/coilContractRel',
method: 'put',
data: data
})
}
// 删除钢卷与合同关联关系
export function delCoilContractRel(relId) {
return request({
url: '/wms/coilContractRel/' + relId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询报导出文件列表
export function listExportFile(query) {
return request({
url: '/wms/exportFile/list',
method: 'get',
params: query
})
}
// 查询报导出文件详细
export function getExportFile(id) {
return request({
url: '/wms/exportFile/' + id,
method: 'get'
})
}
// 新增报导出文件
export function addExportFile(data) {
return request({
url: '/wms/exportFile',
method: 'post',
data: data
})
}
// 修改报导出文件
export function updateExportFile(data) {
return request({
url: '/wms/exportFile',
method: 'put',
data: data
})
}
// 删除报导出文件
export function delExportFile(id) {
return request({
url: '/wms/exportFile/' + id,
method: 'delete'
})
}

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

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询报结果存储JSON+横向对比专用)列表
export function listReportResultStorage(query) {
return request({
url: '/wms/reportResultStorage/list',
method: 'get',
params: query
})
}
// 查询报结果存储JSON+横向对比专用)详细
export function getReportResultStorage(storageId) {
return request({
url: '/wms/reportResultStorage/' + storageId,
method: 'get'
})
}
// 新增报结果存储JSON+横向对比专用)
export function addReportResultStorage(data) {
return request({
url: '/wms/reportResultStorage',
method: 'post',
data: data
})
}
// 修改报结果存储JSON+横向对比专用)
export function updateReportResultStorage(data) {
return request({
url: '/wms/reportResultStorage',
method: 'put',
data: data
})
}
// 删除报结果存储JSON+横向对比专用)
export function delReportResultStorage(storageId) {
return request({
url: '/wms/reportResultStorage/' + storageId,
method: 'delete'
})
}

View File

@@ -0,0 +1,52 @@
import request from '@/utils/request'
// 查询调拨单主列表
export function listTransferOrder(query) {
return request({
url: '/wms/transferOrder/list',
method: 'get',
params: query
})
}
// 查询调拨单主详细
export function getTransferOrder(orderId) {
return request({
url: '/wms/transferOrder/' + orderId,
method: 'get'
})
}
// 新增调拨单主
export function addTransferOrder(data) {
return request({
url: '/wms/transferOrder',
method: 'post',
data: data
})
}
// 修改调拨单主
export function updateTransferOrder(data) {
return request({
url: '/wms/transferOrder',
method: 'put',
data: data
})
}
// 删除调拨单主
export function delTransferOrder(orderId) {
return request({
url: '/wms/transferOrder/' + orderId,
method: 'delete'
})
}
// 审批调拨单
export function approveTransferOrder(orderId, status) {
return request({
url: '/wms/transferOrder/approve/' + orderId + '/' + status,
method: 'put'
})
}

View File

@@ -0,0 +1,116 @@
import request from '@/utils/request'
// 查询调拨单明细列表
export function listTransferOrderItem(query) {
return request({
url: '/wms/transferOrderItem/list',
method: 'get',
params: query
})
}
// 查询调拨单明细详细
export function getTransferOrderItem(orderItemId) {
return request({
url: '/wms/transferOrderItem/' + orderItemId,
method: 'get'
})
}
// 新增调拨单明细
export function addTransferOrderItem(data) {
return request({
url: '/wms/transferOrderItem',
method: 'post',
data: data
})
}
// 修改调拨单明细
export function updateTransferOrderItem(data) {
return request({
url: '/wms/transferOrderItem',
method: 'put',
data: data
})
}
// 删除调拨单明细
export function delTransferOrderItem(orderItemId) {
return request({
url: '/wms/transferOrderItem/' + orderItemId,
method: 'delete'
})
}
/**
* 同步物料信息
*/
export function matchOrCreateMaterial({ itemId, itemType }) {
if (!itemId || !itemType) {
return Promise.reject('参数错误')
}
const data = {
itemId,
itemType
}
return request({
url: '/wms/transferOrderItem/itemType/matchOrCreate',
method: 'get',
params: data
})
}
/**
* 批量新增调拨信息
*/
export function batchAddTransferOrderItem({ transferId, coilIds }) {
if (!transferId || !coilIds || coilIds.length === 0) {
return Promise.reject('参数错误')
}
const data = {
transferId,
coilIds
}
return request({
url: '/wms/transferOrderItem/batch',
method: 'post',
data: data
})
}
/**
* 确认调拨
*/
export function confirmTransferOrderItem(item) {
if (!item.orderItemId) {
return Promise.reject('参数错误')
}
return request({
url: '/wms/transferOrderItem/confirm',
method: 'post',
data: item
})
}
/**
* 取消调拨
*/
export function cancelTransferOrderItem(orderItemId) {
if (!orderItemId) {
return Promise.reject('参数错误')
}
return request({
url: '/wms/transferOrderItem/cancel',
method: 'post',
params: {
orderItemId
}
})
}

View File

@@ -944,6 +944,14 @@ body {
}
}
.el-dialog.is-fullscreen {
.el-dialog__body {
padding: $--spacing-lg;
max-height: calc(100vh - 100px);
overflow-y: auto;
}
}
// 抽屉
.el-drawer {
// background: $--metal-gradient-light;

View File

@@ -47,12 +47,17 @@ function formatAreaText(value) {
return { standard, custom };
}
// 非组合格式(纯标准地址/纯自定义地址)→ 默认归为standard
return { standard: trimVal, custom: '' };
// 非组合格式(纯任意字符串)→ 归为custom
return { standard: '', custom: trimVal };
}
// ========== 场景3输入是对象 → 格式化为组合字符串 ==========
if (typeof value === 'object' && !Array.isArray(value)) {
// 处理空对象
if (Object.keys(value).length === 0) {
return '[]()';
}
const { standard = '', custom = '' } = value;
// 转字符串并去空格
const standardStr = String(standard).trim();
@@ -71,11 +76,19 @@ function formatAreaText(value) {
*/
function formatAreaTextEnhanced(value, keyType = 'name') {
// 先调用基础版解析/格式化
const result = formatAreaText(value);
let result = formatAreaText(value);
// 如果是解析模式返回对象且keyType为name转换code为name
// 如果是解析模式返回对象且keyType为name检查是否为代码输入
if (typeof result === 'object' && keyType === 'name') {
result.standard = convertCodeToName(result.standard);
// 检查custom是否可能是代码不包含中文
if (result.custom && !/[\u4e00-\u9fa5]/.test(result.custom)) {
// 尝试转换code为name
const convertedName = convertCodeToName(result.custom);
// 如果转换成功返回非空字符串则将其移到standard字段
if (convertedName) {
result = { standard: convertedName, custom: '' };
}
}
}
return result;

View File

@@ -26,6 +26,7 @@
<script>
import areaData from './data.js'
import { formatAreaTextEnhanced } from './index.js'
export default {
name: 'ChinaAreaSelectWithDetail',
@@ -105,32 +106,9 @@ export default {
* @param {String} val - 外部传入的「[标准地址](自定义地址)」格式值
*/
parseCombineValue(val) {
if (!val) {
this.areaValue = []
this.detailAddress = ''
return
}
// 核心正则:匹配「[xxx](yyy)」格式分组提取xxx和yyy无匹配则为空
const reg = /\[([^\]]*)\]\(([^)]*)\)/
const matchResult = val.match(reg)
// 提取标准地址(第一个分组)和自定义地址(第二个分组)
const standardAddress = matchResult?.[1] || ''
const customAddress = matchResult?.[2] || ''
// 1. 处理自定义地址:直接赋值
this.detailAddress = customAddress.trim()
// 2. 处理标准地址转换为区域选择器的code数组
if (standardAddress) {
const standardArr = standardAddress.split('/').filter(Boolean)
this.areaValue = this.keyType === 'name'
? this.convertNameToCode(standardArr) // name转code
: standardArr.filter(code => !!areaData[code]) // code直接过滤无效值
} else {
this.areaValue = []
}
const formattedAddress = formatAreaTextEnhanced(val)
this.areaValue = formattedAddress.standard.split('/').filter(Boolean)
this.detailAddress = formattedAddress.custom.trim()
},
/**

View File

@@ -1,6 +1,12 @@
export const defaultColumns = [
{
label: '卷号',
label: '入场卷号',
align: 'center',
prop: 'enterCoilNo',
showOverflowTooltip: true
},
{
label: '当前卷号',
align: 'center',
prop: 'currentCoilNo',
showOverflowTooltip: true

View File

@@ -21,32 +21,39 @@
@close="handleClose" append-to-body :fullscreen="orderBy">
<!-- 搜索区域 -->
<el-form v-if="!rangeMode" inline :model="queryParams" class="search-form">
<!-- <el-form-item label="类型">
<el-select v-model="queryParams.selectType" placeholder="请选择类型" size="small">
<el-form-item label="入场卷号">
<el-input v-model="queryParams.enterCoilNo" placeholder="请输入入场卷号" clearable size="small"
@keyup.enter.native="handleQuery" />
</el-form-item>
<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-select v-model="queryParams.itemType" placeholder="请选择物料类型" size="small" clearable>
<el-option label="成品" value="product" />
<el-option label="原料" value="raw_material" />
</el-select>
</el-form-item> -->
<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="物料">
<muti-select v-model="queryParams.itemName" :options="dict.type.coil_itemname" placeholder="请选择物料"
<el-form-item label="物料名称" v-if="queryParams.itemType">
<muti-select v-model="queryParams.itemName" :options="dict.type.coil_itemname" placeholder="请选择物料名称"
clearable />
</el-form-item>
<el-form-item label="规格">
<el-form-item label="规格" v-if="queryParams.itemType">
<memo-input storageKey="coilSpec" v-model="queryParams.itemSpecification" placeholder="请输入规格" clearable
size="small" @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="材质">
<el-form-item label="材质" v-if="queryParams.itemType">
<muti-select v-model="queryParams.itemMaterial" :options="dict.type.coil_material" placeholder="请选择材质"
clearable />
</el-form-item>
<el-form-item label="厂家">
<el-form-item label="厂家" v-if="queryParams.itemType">
<muti-select v-model="queryParams.itemManufacturer" :options="dict.type.coil_manufacturer" placeholder="请选择厂家"
clearable />
</el-form-item>
<el-form-item label="表面处理" v-if="queryParams.itemType">
<el-input v-model="queryParams.itemSurfaceTreatmentDesc" placeholder="请输入表面处理" clearable size="small" />
</el-form-item>
<el-form-item label="切边" prop="trimmingRequirement" v-if="orderBy">
<el-select v-model="queryParams.trimmingRequirement" placeholder="请选择切边" clearable style="width: 100%">
<el-option label="净边" value="净边" />
@@ -60,6 +67,10 @@
<el-option label="简包" value="简包" />
</el-select>
</el-form-item>
<el-form-item label="品质">
<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
canSelectDisabled :clearInput="false" clearable />
@@ -69,6 +80,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-form-item>
</el-form>
@@ -78,6 +91,7 @@
<!-- 自定义列 -->
<el-table-column v-for="column in renderColumns" :label="column.label" :align="column.align" :prop="column.prop"
:width="column.width" :show-overflow-tooltip="column.showOverflowTooltip" />
<el-table-column v-if="orderBy" label="表面处理" prop="surfaceTreatmentDesc"></el-table-column>
<el-table-column v-if="orderBy" label="品质" prop="qualityStatus"></el-table-column>
<el-table-column v-if="orderBy" label="切边" prop="trimmingRequirement"></el-table-column>
<el-table-column v-if="orderBy" label="包装" prop="packagingRequirement"></el-table-column>
@@ -95,6 +109,7 @@
<!-- 自定义列 -->
<el-table-column v-for="column in renderColumns" :label="column.label" :align="column.align"
:prop="column.prop" :width="column.width" :show-overflow-tooltip="column.showOverflowTooltip" />
<el-table-column v-if="orderBy" label="表面处理" prop="surfaceTreatmentDesc"></el-table-column>
<el-table-column v-if="orderBy" label="品质" prop="qualityStatus"></el-table-column>
<el-table-column v-if="orderBy" label="切边" prop="trimmingRequirement"></el-table-column>
<el-table-column v-if="orderBy" label="包装" prop="packagingRequirement"></el-table-column>
@@ -102,8 +117,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">
@@ -121,7 +143,10 @@
<el-table v-if="multiple && selectedCoils.length > 0" :data="selectedCoils">
<el-table-column v-for="column in renderColumns" :label="column.label" :align="column.align" :prop="column.prop"
:width="column.width" :show-overflow-tooltip="column.showOverflowTooltip" />
<el-table-column v-if="orderBy" label="表面处理" prop="surfaceTreatmentDesc"></el-table-column>
<el-table-column v-if="orderBy" label="品质" prop="qualityStatus"></el-table-column>
<el-table-column v-if="orderBy" label="切边" prop="trimmingRequirement"></el-table-column>
<el-table-column v-if="orderBy" label="包装" prop="packagingRequirement"></el-table-column>
<el-table-column label="操作" width="50">
<template slot-scope="scope">
@@ -147,12 +172,18 @@
:id="selectedNodeId" :canToggle="false" :canRelease="false" />
</div>
</DragResizeBox>
<DragResizeBox v-if="orderBy && orderId && showOrderInfo" storageKey="coil-order-info">
<div style="height: 100%; width: 100%; background-color: #fff;">
<order-detail v-if="orderBy && orderId && showOrderInfo" :orderId="orderId" :editable="false" />
</div>
</DragResizeBox>
</el-dialog>
</div>
</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';
@@ -161,6 +192,7 @@ import { defaultColumns } from './data';
import ActualWarehouseSelect from '@/components/KLPService/ActualWarehouseSelect/index.vue';
import WarehouseBirdMini from '@/views/wms/warehouse/components/WarehouseBirdMini.vue';
import DragResizeBox from '@/components/DragResizeBox/index.vue';
import OrderDetail from '@/views/crm/components/OrderDetail.vue';
export default {
name: 'CoilSelector',
@@ -169,9 +201,10 @@ export default {
MutiSelect,
ActualWarehouseSelect,
WarehouseBirdMini,
DragResizeBox
DragResizeBox,
OrderDetail
},
dicts: ['coil_itemname', 'coil_material', 'coil_manufacturer'],
dicts: ['coil_itemname', 'coil_material', 'coil_manufacturer', 'coil_quality_status'],
props: {
// 非触发器模式下,外部控制显隐(触发器模式下无效)
visible: {
@@ -180,7 +213,7 @@ export default {
},
dialogWidth: {
type: String,
default: '1000px'
default: '1200px'
},
// 过滤条件(可以预设一些查询条件)
filters: {
@@ -238,6 +271,14 @@ export default {
type: Boolean,
default: false
},
orderId: {
type: String,
default: null
},
defaultType: {
type: String,
default: 'product'
}
},
data() {
return {
@@ -251,14 +292,15 @@ export default {
selectedCoil: null,
queryParams: {
pageNum: 1,
pageSize: 10,
pageSize: 50,
currentCoilNo: null,
grade: null,
itemSpecification: null,
itemMaterial: null,
itemManufacturer: null,
actualWarehouseId: null,
selectType: 'product',
itemType: this.defaultType,
selectType: this.defaultType,
status: 0, // 不包含已发货的钢卷
dataType: 1 // 只查询当前数据,不查询历史数据
},
@@ -271,6 +313,8 @@ export default {
warehouseTree: [],
treeProps: { label: "actualWarehouseName", children: "children" },
treeLoading: false,
showOrderInfo: false,
coilTrimStatistics: {},
};
},
computed: {
@@ -455,12 +499,18 @@ export default {
...this.queryParams,
...this.filters,
};
queryPayload.selectType = queryPayload.itemType;
// 处于销售视角且my视图时只查询当前用户的钢卷
console.log('this.salesRestricted', this.salesRestricted, this.currentTab, this.currentUserId);
if (this.salesRestricted && this.currentTab === 'my') {
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;
@@ -506,7 +556,8 @@ export default {
currentCoilNo: null,
grade: null,
dataType: 1,
selectType: 'raw_material',
itemType: this.defaultType,
selectType: this.defaultType,
};
this.getList();
},
@@ -518,8 +569,9 @@ export default {
this.$message.warning('您没有权限选择此钢卷');
return; // 终止后续逻辑
}
if (this.disableO && row.qualityStatus == 'O') {
this.$message.warning('O卷不能选择');
const disabledOList = ['O', 'C+', 'C', 'C-', 'D+', 'D', 'D-']
if (this.disableO && disabledOList.includes(row.qualityStatus)) {
this.$message.warning(`${row.qualityStatus}卷不能选择`);
return;
}
this.handleSelect(row);

View File

@@ -20,7 +20,7 @@
<div
v-if="editable"
@click="openDictDialog"
style="cursor: pointer; height: 24px; width: 24px; margin-top: 4px; display: flex; align-items: center; justify-content: center; border: 1px solid #828991; margin-left: 8px; border-radius: 2px;"
style="cursor: pointer; min-height: 24px; min-width: 24px; margin-top: 4px; display: flex; align-items: center; justify-content: center; border: 1px solid #828991; margin-left: 8px; border-radius: 2px;"
>
<i class="el-icon-setting"></i>
</div>
@@ -28,7 +28,7 @@
<div
v-if="refresh"
@click="handleRefresh"
style="cursor: pointer; height: 24px; width: 24px; margin-top: 4px; display: flex; align-items: center; justify-content: center; border: 1px solid #828991; margin-left: 8px; border-radius: 2px;"
style="cursor: pointer; min-height: 24px; min-width: 24px; margin-top: 4px; display: flex; align-items: center; justify-content: center; border: 1px solid #828991; margin-left: 8px; border-radius: 2px;"
>
<i class="el-icon-refresh"></i>
</div>
@@ -52,7 +52,7 @@
<el-row :gutter="15">
<el-col :span="kisv ? 24 : 12">
<el-form-item label="值/标签" prop="dictValue" v-if="kisv">
<el-input v-model="form.dictValue" placeholder="请输入字典值(标签自动同步)" />
<el-input v-model="form.dictValue" placeholder="请输入字典值,在此处输入用于新增字典项" />
</el-form-item>
<el-form-item label="字典标签" prop="dictLabel" v-else>
<el-input v-model="form.dictLabel" placeholder="请输入字典标签" />

View File

@@ -0,0 +1,159 @@
<template>
<div class="drag-resize-panel" :class="{ 'vertical': direction === 'vertical' }">
<div class="panel-a" :style="panelAstyle">
<slot name="panelA"></slot>
</div>
<div class="resizer" :class="{ 'vertical-resizer': direction === 'vertical' }" @mousedown="startResize"></div>
<div class="panel-b" :style="panelBstyle">
<slot name="panelB"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'DragResizePanel',
props: {
direction: {
type: String,
default: 'horizontal',
validator: function(value) {
return ['horizontal', 'vertical'].includes(value);
}
},
// 设置panelA的初始大小最大值和最小值默认值为300px10000px100px
// panelB占据剩余空间
initialSize: {
type: Number,
default: 300
},
minSize: {
type: Number,
default: 100
},
maxSize: {
type: Number,
default: 10000
}
},
data() {
return {
currentSize: this.initialSize,
isResizing: false,
startPosition: 0
};
},
computed: {
panelAstyle() {
if (this.direction === 'horizontal') {
return { width: this.currentSize + 'px' };
} else {
return { height: this.currentSize + 'px' };
}
},
panelBstyle() {
if (this.direction === 'horizontal') {
return { flex: 1 };
} else {
return { flex: 1 };
}
}
},
methods: {
startResize(e) {
e.preventDefault();
this.isResizing = true;
this.startPosition = this.direction === 'horizontal' ? e.clientX : e.clientY;
this.startSize = this.currentSize;
document.addEventListener('mousemove', this.handleResize);
document.addEventListener('mouseup', this.stopResize);
},
handleResize(e) {
if (!this.isResizing) return;
const delta = this.direction === 'horizontal' ? e.clientX - this.startPosition : e.clientY - this.startPosition;
const newSize = this.startSize + delta;
if (newSize >= this.minSize && newSize <= this.maxSize) {
this.currentSize = newSize;
}
},
stopResize() {
this.isResizing = false;
document.removeEventListener('mousemove', this.handleResize);
document.removeEventListener('mouseup', this.stopResize);
}
}
};
</script>
<style scoped>
.drag-resize-panel {
display: flex;
height: 100%;
overflow: hidden;
}
.drag-resize-panel.vertical {
flex-direction: column;
}
.panel-a {
position: relative;
overflow: hidden;
}
.panel-b {
position: relative;
overflow: auto;
}
.resizer {
width: 4px;
cursor: col-resize;
position: relative;
transition: background-color 0.3s;
height: 100%;
}
.resizer.vertical-resizer {
width: 100%;
height: 4px;
cursor: row-resize;
}
.resizer:hover {
background-color: #409eff;
}
.resizer::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 40px;
width: 2px;
background-color: #c0c4cc;
border-radius: 1px;
transition: background-color 0.3s;
}
.resizer.vertical-resizer::before {
width: 40px;
height: 2px;
}
.resizer:hover::before {
background-color: #409eff;
}
.resizer:active {
background-color: #409eff;
}
.resizer:active::before {
background-color: #fff;
}
</style>

View File

@@ -1,52 +1,61 @@
<template>
<div class="file-list-container">
<el-table
:data="fileList"
border
size="small"
v-loading="loading"
style="width: 100%;"
>
<el-table-column
label="文件名"
prop="originalName"
min-width="200"
>
<template slot-scope="scope">
<i class="el-icon-document" style="margin-right: 8px;"></i>
{{ scope.row.originalName }}
</template>
</el-table-column>
<el-table-column
label="操作"
width="100"
align="center"
>
<template slot-scope="scope">
<el-button
type="text"
icon="el-icon-download"
@click="downloadFile(scope.row)"
size="small"
>
下载
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 空数据提示 -->
<div v-if="fileList.length === 0 && !loading" class="empty-tip">
<el-empty description="暂无文件数据"></el-empty>
</div>
<!-- 自定义文件列表 -->
<div v-else class="file-list" v-loading="loading">
<div
v-for="file in fileList"
:key="file.ossId"
class="file-item"
>
<div class="file-info">
<i class="el-icon-document"></i>
<span class="file-name">{{ file.originalName }}</span>
</div>
<div class="file-actions">
<el-button
type="text"
icon="el-icon-view"
@click="handlePreview(file)"
size="small"
class="preview-btn"
>
预览
</el-button>
<el-button
type="text"
icon="el-icon-download"
@click="downloadFile(file)"
size="small"
class="download-btn"
>
下载
</el-button>
</div>
</div>
</div>
<!-- 文件预览组件 -->
<file-preview
:visible.sync="previewVisible"
:file-url="previewFileUrl"
:file-name="previewFileName"
/>
</div>
</template>
<script>
import { listByIds } from "@/api/system/oss";
import FilePreview from "../FilePreview";
export default {
name: "FileList",
components: {
FilePreview
},
props: {
ossIds: {
type: String,
@@ -56,7 +65,11 @@ export default {
data() {
return {
fileList: [],
loading: false // 加载状态
loading: false, // 加载状态
// 预览相关
previewVisible: false,
previewFileUrl: '',
previewFileName: ''
}
},
watch: {
@@ -94,6 +107,12 @@ export default {
return;
}
this.$download.oss(file.ossId);
},
// 预览文件
handlePreview(file) {
this.previewFileUrl = file.url;
this.previewFileName = file.originalName;
this.previewVisible = true;
}
}
}
@@ -112,8 +131,64 @@ export default {
height: 200px;
}
::v-deep .el-table {
--el-table-header-text-color: #606266;
--el-table-row-hover-bg-color: #f5f7fa;
.file-list {
width: 100%;
border: 1px solid #ebeef5;
border-radius: 4px;
overflow: hidden;
}
.file-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
border-bottom: 1px solid #ebeef5;
transition: background-color 0.3s;
}
.file-actions {
display: flex;
align-items: center;
gap: 16px;
}
.file-item:last-child {
border-bottom: none;
}
.file-item:hover {
background-color: #f5f7fa;
}
.file-info {
display: flex;
align-items: center;
flex: 1;
}
.file-info .el-icon-document {
margin-right: 8px;
color: #409eff;
font-size: 16px;
}
.file-name {
font-size: 14px;
color: #606266;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
}
.download-btn {
margin: 0;
font-size: 14px;
color: #409eff;
}
.download-btn:hover {
color: #66b1ff;
}
</style>

View File

@@ -0,0 +1,122 @@
<template>
<el-dialog
:title="title"
:visible.sync="dialogVisible"
:width="width"
:close-on-click-modal="false"
destroy-on-close
append-to-body
@close="handleClose"
>
<!-- 图片预览 -->
<ImagePreview v-if="fileType === 'image'" :src="fileUrl" />
<!-- PDF预览 -->
<PdfPreview v-else-if="fileType === 'pdf'" :src="fileUrl" />
<!-- Word预览 -->
<DocxPreview v-else-if="fileType === 'docx'" :src="fileUrl" />
<!-- Excel预览 (xlsx) -->
<XlsxPreview v-else-if="fileType === 'xlsx'" :src="fileUrl" />
<!-- Excel预览 (xls) -->
<XlsPreview v-else-if="fileType === 'xls'" :src="fileUrl" />
<!-- 不支持的文件类型 -->
<div v-else class="preview-not-supported">
<el-empty description="暂不支持预览此文件类型"></el-empty>
</div>
</el-dialog>
</template>
<script>
import ImagePreview from './preview/image/index.vue';
import PdfPreview from './preview/pdf/index.vue';
import DocxPreview from './preview/docx/index.vue';
import XlsxPreview from './preview/xlsx/index.vue';
import XlsPreview from './preview/xls/index.vue';
export default {
name: "FilePreview",
components: {
ImagePreview,
PdfPreview,
DocxPreview,
XlsxPreview,
XlsPreview
},
props: {
visible: {
type: Boolean,
default: false
},
fileUrl: {
type: String,
required: true
},
fileName: {
type: String,
default: "文件预览"
},
width: {
type: String,
default: "80%"
}
},
data() {
return {
dialogVisible: false
};
},
watch: {
visible: {
handler(val) {
this.dialogVisible = val;
},
immediate: true
},
dialogVisible(val) {
if (!val) {
this.$emit('update:visible', false);
}
}
},
computed: {
title() {
return this.fileName || "文件预览";
},
fileType() {
const fileName = this.fileName || '';
const ext = fileName.split('.').pop()?.toLowerCase();
if (['png', 'jpg', 'jpeg', 'bmp', 'webp'].includes(ext)) {
return 'image';
} else if (ext === 'pdf') {
return 'pdf';
} else if (ext === 'docx') {
return 'docx';
} else if (ext === 'xlsx') {
return 'xlsx';
} else if (ext === 'xls') {
return 'xls';
} else {
return 'other';
}
}
},
methods: {
handleClose() {
this.$emit('update:visible', false);
}
}
};
</script>
<style scoped>
.preview-not-supported {
display: flex;
justify-content: center;
align-items: center;
height: 400px;
}
</style>

View File

@@ -0,0 +1,38 @@
<template>
<div class="docx-preview">
<vue-office-docx :src="src" @render-error="handleDocxError" />
</div>
</template>
<script>
import VueOfficeDocx from '@vue-office/docx';
import '@vue-office/docx/lib/index.css';
export default {
name: "DocxPreview",
components: {
VueOfficeDocx
},
props: {
src: {
type: String,
required: true,
description: "Word文件的URL或路径"
}
},
methods: {
handleDocxError(err) {
console.error('docx预览失败:', err);
this.$message.error('文档预览失败,请下载查看');
}
}
};
</script>
<style scoped>
.docx-preview {
width: 100%;
height: 70vh;
overflow-y: auto;
}
</style>

View File

@@ -0,0 +1,99 @@
<template>
<div class="preview-image">
<div class="image-controls">
<el-button type="primary" size="small" @click="zoomIn">放大</el-button>
<el-button type="primary" size="small" @click="zoomOut">缩小</el-button>
<el-button type="primary" size="small" @click="resetZoom">重置</el-button>
</div>
<div class="image-container" ref="imageContainer">
<img
:src="src"
:style="{ transform: `scale(${scale})` }"
class="preview-image-content"
@wheel="handleWheel"
/>
</div>
</div>
</template>
<script>
export default {
name: "ImagePreview",
props: {
src: {
type: String,
required: true,
description: "图片文件的URL或路径"
}
},
data() {
return {
scale: 1
};
},
methods: {
// 放大图片
zoomIn() {
if (this.scale < 3) {
this.scale += 0.1;
}
},
// 缩小图片
zoomOut() {
if (this.scale > 0.1) {
this.scale -= 0.1;
}
},
// 重置缩放
resetZoom() {
this.scale = 1;
},
// 鼠标滚轮缩放
handleWheel(event) {
event.preventDefault();
const delta = event.deltaY > 0 ? -0.1 : 0.1;
if ((this.scale > 0.1 || delta > 0) && (this.scale < 3 || delta < 0)) {
this.scale += delta;
}
}
}
};
</script>
<style scoped>
.preview-image {
width: 100%;
height: 70vh;
background-color: #f5f7fa;
display: flex;
flex-direction: column;
}
.image-controls {
padding: 10px;
display: flex;
gap: 10px;
border-bottom: 1px solid #e4e7ed;
background-color: #ffffff;
}
.image-container {
flex: 1;
overflow: auto;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 20px;
}
.preview-image-content {
transition: transform 0.3s ease;
cursor: zoom-in;
max-width: 100%;
max-height: 100%;
}
.preview-image-content:hover {
cursor: zoom-in;
}
</style>

View File

@@ -0,0 +1,34 @@
<template>
<div class="preview-pdf">
<iframe
:src="src"
class="preview-pdf-content"
frameborder="0"
/>
</div>
</template>
<script>
export default {
name: "PdfPreview",
props: {
src: {
type: String,
required: true,
description: "PDF文件的URL或路径"
}
}
};
</script>
<style scoped>
.preview-pdf {
width: 100%;
height: 70vh;
}
.preview-pdf-content {
width: 100%;
height: 100%;
}
</style>

View File

@@ -0,0 +1,238 @@
<template>
<div class="xls-preview">
<!-- 加载状态 -->
<div v-if="loading" class="loading">
<div class="spinner"></div>
<p>正在加载Excel文件...</p>
</div>
<!-- 错误信息 -->
<div v-if="error" class="error">{{ error }}</div>
<!-- Excel内容展示 -->
<div v-if="workbook" class="workbook-container">
<!-- 工作表标签 -->
<div class="sheet-tabs">
<button v-for="(sheet, index) in workbook.SheetNames" :key="index"
:class="{ active: activeSheetIndex === index }" @click="activeSheetIndex = index">
{{ sheet }}
</button>
</div>
<!-- 表格内容区域 -->
<div class="sheet-content">
<table v-if="activeSheetData">
<tbody>
<tr v-for="(row, rowIndex) in activeSheetData" :key="rowIndex">
<td v-for="(cell, colIndex) in row" :key="colIndex" :class="{
'header-cell': rowIndex === 0,
'odd-row': rowIndex % 2 === 1
}">
{{ cell || '' }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
import * as XLSX from 'xlsx';
export default {
name: "XlsPreview",
props: {
src: {
type: String,
required: true,
description: "Excel文件的URL或路径"
}
},
data () {
return {
workbook: null, // 解析后的Excel工作簿
activeSheetIndex: 0, // 当前激活的工作表索引
loading: false, // 加载状态
error: null // 错误信息
};
},
watch: {
src: {
immediate: true,
handler () {
this.loadAndParseExcel();
}
}
},
computed: {
// 获取当前激活的工作表数据
activeSheetData () {
if (!this.workbook || !this.workbook.SheetNames.length) return null;
const sheetName = this.workbook.SheetNames[this.activeSheetIndex];
const worksheet = this.workbook.Sheets[sheetName];
// 将工作表转换为二维数组
return XLSX.utils.sheet_to_json(worksheet, { header: 1 });
}
},
methods: {
/**
* 加载并解析Excel文件
*/
async loadAndParseExcel () {
this.loading = true;
this.error = null;
this.workbook = null;
try {
// 验证URL格式
if (!this.src || (this.src.startsWith('http') && !this.isValidUrl(this.src))) {
throw new Error('无效的文件路径');
}
// 加载文件
const response = await fetch(this.src);
if (!response.ok) {
throw new Error(`加载失败: ${response.status} ${response.statusText}`);
}
// 转换为ArrayBuffer
const arrayBuffer = await response.arrayBuffer();
// 解析Excel
this.workbook = XLSX.read(arrayBuffer, {
type: 'array',
cellDates: true, // 解析日期类型
cellText: false // 保持单元格原始类型
});
// 重置到第一个工作表
this.activeSheetIndex = 0;
} catch (err) {
this.error = err.message;
console.error('Excel处理错误:', err);
} finally {
this.loading = false;
}
},
/**
* 验证URL格式
*/
isValidUrl (url) {
try {
new URL(url);
return true;
} catch (e) {
return false;
}
}
}
};
</script>
<style scoped>
.xls-preview {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
border: 1px solid #e5e7eb;
border-radius: 6px;
overflow: hidden;
width: 100%;
height: 70vh;
}
/* 加载状态样式 */
.loading {
padding: 40px 20px;
text-align: center;
color: #6b7280;
}
.spinner {
width: 40px;
height: 40px;
margin: 0 auto 16px;
border: 4px solid #e5e7eb;
border-top-color: #3b82f6;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* 错误信息样式 */
.error {
padding: 20px;
color: #dc2626;
background-color: #fee2e2;
border-bottom: 1px solid #fecaca;
}
/* 工作表标签样式 */
.sheet-tabs {
display: flex;
background-color: #f9fafb;
border-bottom: 1px solid #e5e7eb;
overflow-x: auto;
white-space: nowrap;
}
.sheet-tabs button {
padding: 8px 16px;
border: none;
background: none;
font-size: 14px;
color: #4b5563;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.2s;
}
.sheet-tabs button:hover:not(.active) {
background-color: #f3f4f6;
color: #1f2937;
}
.sheet-tabs button.active {
border-bottom-color: #3b82f6;
color: #3b82f6;
font-weight: 500;
}
/* 表格内容样式 */
.sheet-content {
overflow: auto;
max-height: 600px;
}
table {
width: 100%;
border-collapse: collapse;
min-width: max-content;
}
td {
padding: 8px 12px;
border: 1px solid #e5e7eb;
min-width: 80px;
font-size: 14px;
color: #1f2937;
}
.header-cell {
background-color: #f3f4f6;
font-weight: 500;
color: #111827;
}
.odd-row {
background-color: #f9fafb;
}
</style>

View File

@@ -0,0 +1,42 @@
<template>
<div class="xlsx-preview" :style="{ height: height }">
<vue-office-excel :src="src" @render-error="handleExcelError" />
</div>
</template>
<script>
import VueOfficeExcel from '@vue-office/excel';
import '@vue-office/excel/lib/index.css';
export default {
name: "XlsxPreview",
components: {
VueOfficeExcel
},
props: {
src: {
type: String,
required: true,
description: "Excel文件的URL或路径"
},
height: {
type: String,
default: "70vh",
description: "预览区域高度"
}
},
methods: {
handleExcelError(err) {
console.error('excel预览失败:', err);
this.$message.error('Excel预览失败请下载查看');
}
}
};
</script>
<style scoped>
.xlsx-preview {
width: 100%;
overflow-y: auto;
}
</style>

View File

@@ -32,19 +32,31 @@
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
</el-link>
<div class="ele-upload-list__item-content-action">
<el-link :underline="false" @click="handlePreview(file)" type="primary">预览</el-link>
<el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
</div>
</li>
</transition-group>
<!-- 文件预览组件 -->
<file-preview
:visible.sync="previewVisible"
:file-url="previewFileUrl"
:file-name="previewFileName"
/>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
import { listByIds, delOss } from "@/api/system/oss";
import FilePreview from "../FilePreview";
export default {
name: "FileUpload",
components: {
FilePreview
},
props: {
// 值
value: [String, Object, Array],
@@ -85,6 +97,10 @@ export default {
},
fileList: [],
loading: false,
// 预览相关
previewVisible: false,
previewFileUrl: '',
previewFileName: ''
};
},
watch: {
@@ -232,6 +248,12 @@ export default {
}
return strs != "" ? strs.substr(0, strs.length - 1) : "";
},
// 预览文件
handlePreview(file) {
this.previewFileUrl = file.url;
this.previewFileName = file.name;
this.previewVisible = true;
},
},
};
</script>

View File

@@ -0,0 +1,269 @@
<template>
<div>
<div style="display: flex; align-items: center; margin-bottom: 12px;">
<el-select v-model="selectedValue" placeholder="请选择合同" style="width: 100%">
<el-option v-for="item in contractList" :key="item.orderId" :value="item.orderId"
:label="item.contractCode" />
</el-select>
<!-- 编辑按钮点击打开弹窗 -->
<el-button v-if="mode == 'today'" @click="openSelectDialog" type="primary" size="small" style="margin-left: 8px; padding: 0 12px;">
<i class="el-icon-setting"></i>
</el-button>
<!-- 刷新时不会移除手动添加的合同 -->
<el-button @click="handleRefresh" type="info" size="small" style="margin-left: 8px; padding: 0 12px;">
<i class="el-icon-refresh"></i>
</el-button>
</div>
<!-- 查询所有的合同和当前localstorage中的合同可以对localstorage中的合同进行新增和删除手动新增的合同带有手动添加的标记 -->
<el-dialog title="可选合同配置" :visible.sync="dialogVisible" width="80%">
<el-tabs v-model="activeTab">
<!-- 已配置合同tab -->
<el-tab-pane label="可选合同" name="configured">
<div v-if="contractList.length === 0" style="text-align: center; padding: 20px;">
暂无已配置合同
</div>
<el-table v-else :data="contractList" style="width: 100%" size="mini" height="600">
<el-table-column prop="contractCode" label="合同编号" width="160" />
<el-table-column prop="contractName" label="合同名称" width="180" />
<el-table-column prop="customer" label="客户" width="140" />
<el-table-column prop="salesman" label="销售人员" width="100" />
<el-table-column prop="deliveryDate" label="交付日期" width="110">
<template slot-scope="scope">
{{ scope.row.deliveryDate || '-' }}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
<el-table-column label="添加方式" width="90">
<template slot-scope="scope">
<el-tag v-if="scope.row.isManual" type="success" size="small">手动</el-tag>
<el-tag v-else type="info" size="small">接口</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="70">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="removeContract(scope.row.orderId)" plain>
移除
</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<!-- 所有合同tab -->
<el-tab-pane label="所有合同" name="all">
<div style="margin-bottom: 16px;">
<el-input v-model="searchKeyword" placeholder="搜索合同" @input="handleSearch" clearable size="small">
<el-button slot="append" icon="el-icon-search" size="small"></el-button>
</el-input>
</div>
<el-table :data="allContracts" style="width: 100%" size="mini" height="600">
<el-table-column prop="contractCode" label="合同编号" width="160" />
<el-table-column prop="contractName" label="合同名称" width="180" />
<el-table-column prop="customer" label="客户" width="140" />
<el-table-column prop="salesman" label="销售人员" width="100" />
<el-table-column prop="deliveryDate" label="交付日期" width="110">
<template slot-scope="scope">
{{ scope.row.deliveryDate || '-' }}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
<el-table-column label="状态" width="80">
<template slot-scope="scope">
<el-tag v-if="isContractInList(scope.row.orderId)" type="success" size="small">已添加</el-tag>
<el-tag v-else type="info" size="small">未添加</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template slot-scope="scope">
<el-button
v-if="!isContractInList(scope.row.orderId)"
type="primary"
size="mini"
@click="addContract(scope.row)"
plain
>
添加
</el-button>
<el-button
v-else
type="danger"
size="mini"
@click="removeContract(scope.row.orderId)"
plain
>
移除
</el-button>
</template>
</el-table-column>
</el-table>
<div v-if="allContracts.length === 0" style="text-align: center; padding: 20px;">
暂无合同数据
</div>
</el-tab-pane>
</el-tabs>
</el-dialog>
</div>
</template>
<script>
import { listOrder, listTodayOrder } from '@/api/crm/order';
export default {
name: "ContractSelect",
props: {
value: {
type: String,
default: ""
},
mode: {
type: String,
default: "today" // today 或 all
}
},
data() {
return {
contractList: [],
dialogVisible: false,
searchKeyword: '',
allContracts: [],
activeTab: 'configured', // 默认显示已配置合同tab
}
},
computed: {
selectedValue: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
}
}
},
mounted() {
if (this.mode == "today") {
// 从localstorage中获取合同列表
this.loadFromLocalStorage();
} else {
this.loadContractList();
}
},
methods: {
// 从localStorage中加载合同列表
loadFromLocalStorage() {
try {
const storedContracts = localStorage.getItem('todayContracts');
if (storedContracts) {
this.contractList = JSON.parse(storedContracts);
} else {
// 如果localStorage中没有从接口获取
this.loadContractList();
}
} catch (error) {
console.error('Failed to load contracts from localStorage:', error);
this.loadContractList();
}
},
// 保存合同列表到localStorage
saveToLocalStorage() {
try {
localStorage.setItem('todayContracts', JSON.stringify(this.contractList));
} catch (error) {
console.error('Failed to save contracts to localStorage:', error);
}
},
// 加载合同列表
async loadContractList(keyword) {
if (this.mode == "all") {
const res = await listOrder({
pageNum: 1,
pageSize: 1000,
keyword: keyword || undefined,
});
this.contractList = res.rows || [];
}
else if (this.mode == "today") {
const res = await listTodayOrder();
// 获取现有手动添加的合同
const existingManualContracts = this.contractList.filter(item => item.isManual);
// 将接口返回的合同标记为非手动添加
const apiContracts = (res.data || []).map(item => ({
...item,
isManual: false
}));
// 合并合同列表,保留手动添加的合同
this.contractList = [...apiContracts, ...existingManualContracts];
// 去重,避免重复合同
this.contractList = this.contractList.filter((item, index, self) =>
index === self.findIndex(t => t.orderId === item.orderId)
);
// 保存到localStorage
this.saveToLocalStorage();
}
},
// 打开选择弹窗
async openSelectDialog() {
this.dialogVisible = true;
// 加载所有合同供选择
await this.loadAllContracts();
},
// 加载所有合同
async loadAllContracts() {
try {
const res = await listOrder({
pageNum: 1,
pageSize: 1000,
keyword: this.searchKeyword || undefined,
});
// 合并现有合同(包括手动添加的)
const existingContracts = this.contractList;
this.allContracts = [...res.rows || [], ...existingContracts].filter((item, index, self) =>
index === self.findIndex(t => t.orderId === item.orderId)
);
} catch (error) {
console.error('Failed to load all contracts:', error);
this.allContracts = [];
}
},
// 搜索合同
handleSearch() {
this.loadAllContracts();
},
// 检查合同是否在列表中
isContractInList(orderId) {
return this.contractList.some(item => item.orderId === orderId);
},
// 添加合同
addContract(contract) {
if (!this.isContractInList(contract.orderId)) {
this.contractList.push({
...contract,
isManual: true // 标记为手动添加
});
this.saveToLocalStorage();
}
},
// 移除合同
removeContract(orderId) {
this.contractList = this.contractList.filter(item => item.orderId !== orderId);
this.saveToLocalStorage();
},
// 刷新合同列表
handleRefresh() {
this.loadContractList();
},
}
}
</script>

View File

@@ -1,6 +1,6 @@
<template>
<el-select filterable v-model="_customerId" remote :remote-method="remoteSearchCustomer" :loading="customerLoading" placeholder="请选择客户">
<el-option v-for="item in customerList" :key="item.customerId" :label="item.name" :value="item.customerId" />
<el-select filterable v-model="_customerId" remote :remote-method="remoteSearchCustomer" :style="style" :loading="customerLoading" placeholder="请选择客户">
<el-option v-for="item in customerList" :key="item[bindField]" :label="item.companyName" :value="item[bindField]" />
</el-select>
</template>
@@ -13,6 +13,14 @@
value: {
type: String,
default: ''
},
bindField: {
type: String,
default: 'customerId'
},
style: {
type: Object,
default: () => ({})
}
},
computed: {
@@ -22,6 +30,12 @@
},
set(value) {
this.$emit('input', value);
// 找到对应的客户信息
const customer = this.customerList.find(item => item[this.bindField] === value);
// 触发 change 事件,传递客户信息
if (customer) {
this.$emit('change', customer);
}
}
}
},
@@ -37,7 +51,7 @@
methods: {
remoteSearchCustomer(query) {
this.customerLoading = true;
listCustomer({ name: query, pageNum: 1, pageSize: 10 }).then(response => {
listCustomer({ companyName: query, pageNum: 1, pageSize: 10 }).then(response => {
this.customerList = response.rows;
}).finally(() => {
this.customerLoading = false;

View File

@@ -153,7 +153,7 @@ export default {
},
props: {
value: {
type: String,
type: [String, Number],
default: ''
},
readonly: {
@@ -224,7 +224,7 @@ export default {
this.selectedId = val || '';
if (this.selectedId) {
const res = await getProduct(this.selectedId);
if (res.code === 200) this.selectedRow = res.data;
if (res.code === 200 && res.data != null) this.selectedRow = res.data || {};
} else {
this.selectedRow = {};
}
@@ -233,6 +233,7 @@ export default {
dialogVisible(val) {
if (val) {
this.getList();
this.listRecentlySelected();
}
}
},
@@ -274,7 +275,7 @@ export default {
// 选中项不在列表则追加,保证选中高亮
if (this.selectedId && !this.productList.some(item => item.productId === this.selectedId)) {
const res = await getProduct(this.selectedId);
res.code === 200 && this.productList.push(res.data);
res.code === 200 && res.data && this.productList.push(res.data);
}
}
} catch (error) {
@@ -408,10 +409,10 @@ export default {
this.resetForm("form");
},
},
mounted() {
this.listRecentlySelected();
this.getList();
},
// mounted() {
// this.getList();
// },
};
</script>

View File

@@ -139,7 +139,7 @@ export default {
props: {
// 绑定值原材料ID 单选字符串格式
value: {
type: String,
type: [String, Number],
default: ''
},
// 是否只读
@@ -222,7 +222,7 @@ export default {
// 有选中ID则获取详情赋值
if (this.selectedId) {
const res = await getRawMaterial(this.selectedId);
if (res.code === 200) this.selectedRow = res.data;
if (res.code === 200) this.selectedRow = res.data || {};
} else {
this.selectedRow = {};
}
@@ -231,6 +231,7 @@ export default {
// 弹窗打开时加载数据
dialogVisible(val) {
if (val) {
this.listRecentlySelected();
this.getList();
}
}
@@ -359,7 +360,7 @@ export default {
// 选中的项不在列表中则追加进去,保证选中高亮
if (this.selectedId && !this.rawMaterialList.some(item => item.rawMaterialId === this.selectedId)) {
const res = await getRawMaterial(this.selectedId);
res.code === 200 && this.rawMaterialList.push(res.data);
res.code === 200 && res.data && this.rawMaterialList.push(res.data);
}
}
} catch (error) {
@@ -417,10 +418,10 @@ export default {
this.dialogVisible = false;
}
},
mounted() {
this.listRecentlySelected();
this.getList();
}
// mounted() {
// this.listRecentlySelected();
// this.getList();
// }
};
</script>

View File

@@ -0,0 +1,286 @@
<template>
<div class="material-card" :style="cardStyle">
<div class="card-header">
<div class="header-left">
<current-coil-no :current-coil-no="coil.currentCoilNo"></current-coil-no>
<!-- <span class="material-type">{{ coil.materialType || '原料' }}</span> -->
<el-popover placement="top" width="280" trigger="hover" popper-class="material-params-popover">
<div class="material-params-content">
<div class="params-title">
{{ coil.itemName || '—' }}
</div>
<div class="params-list">
<div class="param-coil">
<div class="param-row" v-if="coil.specification">
<span class="param-label">规格</span>
<span class="param-value">{{ coil.specification }}</span>
</div>
<div class="param-row" v-if="coil.material">
<span class="param-label">材质</span>
<span class="param-value">{{ coil.material }}</span>
</div>
<div class="param-row" v-if="coil.surfaceTreatmentDesc">
<span class="param-label">表面处理</span>
<span class="param-value">{{ coil.surfaceTreatmentDesc }}</span>
</div>
<div class="param-row" v-if="coil.zincLayer">
<span class="param-label">镀层质量</span>
<span class="param-value">{{ coil.zincLayer }}</span>
</div>
<div class="param-row" v-if="coil.manufacturer">
<span class="param-label">厂家</span>
<span class="param-value">{{ coil.manufacturer }}</span>
</div>
</div>
<div class="param-divider"></div>
<div class="param-coil">
<div class="param-row" v-if="coil.actualWarehouseName">
<span class="param-label">实际库区</span>
<span class="param-value">{{ coil.actualWarehouseName }}</span>
</div>
<div class="param-row" v-if="coil.qualityStatus">
<span class="param-label">质量状态</span>
<span class="param-value">{{ coil.qualityStatus }}</span>
</div>
<div class="param-row" v-if="coil.trimmingRequirement">
<span class="param-label">切边要求</span>
<span class="param-value">{{ coil.trimmingRequirement }}</span>
</div>
<div class="param-row" v-if="coil.packingStatus">
<span class="param-label">原料材质</span>
<span class="param-value">{{ coil.packingStatus }}</span>
</div>
<div class="param-row" v-if="coil.packagingRequirement">
<span class="param-label">包装要求</span>
<span class="param-value">{{ coil.packagingRequirement }}</span>
</div>
<div class="param-row" v-if="coil.grossWeight">
<span class="param-label">毛重</span>
<span class="param-value">{{ coil.grossWeight }}t</span>
</div>
<div class="param-row" v-if="coil.netWeight">
<span class="param-label">净重</span>
<span class="param-value">{{ coil.netWeight }}t</span>
</div>
<div class="param-row" v-if="coil.length">
<span class="param-label">长度</span>
<span class="param-value">{{ coil.length }}</span>
</div>
<div class="param-row" v-if="coil.actualLength">
<span class="param-label">实测长度</span>
<span class="param-value">{{ coil.actualLength }}</span>
</div>
<div class="param-row" v-if="coil.actualThickness">
<span class="param-label">实测厚度</span>
<span class="param-value">{{ coil.actualThickness }}</span>
</div>
<div class="param-row" v-if="coil.actualWidth">
<span class="param-label">实测宽度</span>
<span class="param-value">{{ coil.actualWidth }}</span>
</div>
<div class="param-row" v-if="coil.temperGrade">
<span class="param-label">调制度</span>
<span class="param-value">{{ coil.temperGrade }}</span>
</div>
<div class="param-row" v-if="coil.coatingType">
<span class="param-label">镀层种类</span>
<span class="param-value">{{ coil.coatingType }}</span>
</div>
<div class="param-row" v-if="coil.coilSurfaceTreatment">
<span class="param-label">钢卷表面处理</span>
<span class="param-value">{{ coil.coilSurfaceTreatment }}</span>
</div>
<div class="param-row" v-if="coil.team">
<span class="param-label">班组</span>
<span class="param-value">{{ coil.team }}</span>
</div>
<div class="param-row" v-if="coil.updateTime">
<span class="param-label">更新时间</span>
<span class="param-value">{{ parseTime(coil.updateTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</div>
<div class="param-row" v-if="coil.updateBy">
<span class="param-label">更新人</span>
<span class="param-value">{{ coil.updateBy }}</span>
</div>
<div class="param-row" v-if="coil.transferType">
<span class="param-label">调拨标记</span>
<span class="param-value">{{ coil.transferType }}</span>
</div>
<div class="param-row" v-if="coil.remark">
<span class="param-label">备注</span>
<span class="param-value">{{ coil.remark }}</span>
</div>
</div>
</div>
</div>
<i slot="reference" class="el-icon-setting param-icon"></i>
</el-popover>
<slot name="header"></slot>
<!-- <i class="el-icon-view param-icon" @click="handlePreviewLabel(coil)" title="查看标签"></i>
<el-button v-loading="buttonLoading" style="margin-left: 0px; padding: 4px !important;" type="text" size="mini"
@click="handlePrintLabel(coil)" title="打印标签">打印</el-button> -->
</div>
</div>
<div class="card-body" style="position: relative;">
<slot name="body">
<div class="info-list">
<div class="info-coil">
<span class="info-label">入场</span>
<span class="info-value" :title="coil.enterCoilNo">{{ coil.enterCoilNo || '—' }}</span>
</div>
<div class="info-coil">
<span class="info-label">厂家</span>
<span class="info-value" :title="coil.supplierCoilNo">{{ coil.supplierCoilNo || '—' }}</span>
</div>
<div class="info-coil">
<span class="info-label">库位</span>
<span class="info-value" :title="coil.warehouseName">{{ coil.warehouseName || '—' }}</span>
</div>
<div class="info-coil">
<span class="info-label">规格</span>
<span class="info-value" :title="coil.specification">{{ coil.specification || '—'
}}</span>
</div>
<div class="info-coil">
<span class="info-label">重量</span>
<span class="info-value">{{ coil.netWeight || '—' }}t</span>
</div>
</div>
</slot>
</div>
<div class="card-footer">
<slot name="footer"></slot>
<!-- <el-button v-if="useSpecialSplit" :style="splitButtonStyle" icon="el-icon-scissors" size="mini"
@click="handleStartSplit(coil)" :loading="buttonLoading" class="action-btn">加工</el-button>
<el-button v-else type="primary" icon="el-icon-check" size="mini" @click="handlePickMaterial(coil)"
:loading="buttonLoading" class="action-btn">领料</el-button>
<el-button type="danger" icon="el-icon-alarm-clock" :plain="coil.abnormalCount == 0" size="mini"
@click="handleAddAbnormal(coil)" :loading="buttonLoading" class="action-btn">
缺陷明细
<span v-if="coil.abnormalCount > 0">({{ coil.abnormalCount }})</span>
</el-button> -->
</div>
</div>
</template>
<script>
export default {
name: 'CoilCard',
props: {
coil: {
type: Object,
default: () => { }
},
cardStyle: {
type: Object,
default: () => { }
}
}
}
</script>
<style scoped>
.material-card {
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 3px;
display: flex;
flex-direction: column;
transition: all 0.3s ease;
height: 100%;
&:hover {
border-color: #409eff;
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.12);
}
.card-header {
padding: 6px 8px;
border-bottom: 1px solid #e4e7ed;
background-color: #fafafa;
.header-left {
display: flex;
align-items: center;
gap: 6px;
}
.coil-no-tag {
font-weight: 600;
font-size: 11px;
padding: 2px 6px;
}
.material-type {
font-size: 11px;
color: #606266;
font-weight: 500;
}
.param-icon {
font-size: 13px;
color: #909399;
cursor: pointer;
transition: color 0.3s;
&:hover {
color: #409eff;
}
}
}
.card-body {
padding: 8px;
flex: 1;
.info-list {
.info-item {
display: flex;
align-items: center;
margin-bottom: 4px;
font-size: 11px;
line-height: 1.4;
&:last-child {
margin-bottom: 0;
}
.info-label {
color: #909399;
white-space: nowrap;
margin-right: 4px;
min-width: 40px;
font-size: 11px;
}
.info-value {
color: #303133;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 11px;
}
}
}
}
.card-footer {
padding: 6px 8px;
border-top: 1px solid #e4e7ed;
background-color: #fafafa;
display: flex;
justify-content: center;
.action-btn {
width: 100%;
padding: 5px 10px;
font-size: 11px;
}
}
}
</style>

View File

@@ -2,7 +2,7 @@
<div :class="{'g-coil-no': isGCoilNo}">
<!-- 有coilId时显示popover无则只显示标签 -->
<el-popover
v-if="coilId"
v-if="coilId || (coil && coil.currentCoilNo)"
placement="left"
width="200"
trigger="hover"
@@ -38,6 +38,10 @@
<span class="label">实测长度</span>
<span class="value">{{ actualLength }}</span>
</div>
<div class="info-item" v-if="actualLength">
<span class="label">实测厚度</span>
<span class="value">{{ actualThickness }}</span>
</div>
<div class="info-item" v-if="actualWidth">
<span class="label">实测宽度</span>
<span class="value">{{ actualWidth }}</span>
@@ -69,6 +73,10 @@ export default {
type: String,
default: ''
},
coil: {
type: Object,
default: () => {}
}
},
data() { // 修正data应该是函数
return {
@@ -80,34 +88,37 @@ export default {
return this.coilNo && this.coilNo.startsWith('G');
},
specification() {
return this.coilInfo.specification || '-'
return this.coilInfo.specification || this.coil?.specification || '-'
},
itemName() {
return this.coilInfo.itemName || '-'
return this.coilInfo.itemName || this.coil?.itemName || '-'
},
material() {
return this.coilInfo.material || '-'
return this.coilInfo.material || this.coil?.material || '-'
},
manufacturer() {
return this.coilInfo.manufacturer || '-'
return this.coilInfo.manufacturer || this.coil?.manufacturer || '-'
},
currentCoilNo() {
return this.coilNo || this.coilInfo?.currentCoilNo || '-'
return this.coilNo || this.coil?.currentCoilNo || this.coilInfo?.currentCoilNo || '-'
},
netWeight() {
return this.coilInfo.netWeight || '-'
return this.coilInfo.netWeight || this.coil?.netWeight || '-'
},
supplierCoilNo() {
return this.coilInfo.supplierCoilNo || '-'
return this.coilInfo.supplierCoilNo || this.coil?.supplierCoilNo || '-'
},
length() {
return this.coilInfo.length || '-'
return this.coilInfo.length || this.coil?.length || '-'
},
actualLength() {
return this.coilInfo.actualLength || '-'
return this.coilInfo.actualLength || this.coil?.actualLength || '-'
},
actualWidth() {
return this.coilInfo.actualWidth || '-'
return this.coilInfo.actualWidth || this.coil?.actualWidth || '-'
},
actualThickness() {
return this.coilInfo.actualThickness || this.coil?.actualThickness || '-'
},
},
methods: {
@@ -133,7 +144,7 @@ export default {
if (newVal) {
this.getCoilInfo();
} else {
this.coilInfo = {};
this.coilInfo = this.coil || {};
}
}
}

View File

@@ -64,8 +64,8 @@ export default {
return {};
}
return {
productId: this.product.itemId || '',
productName: this.product.itemName || '',
productId: this.product.itemId || this.product.productId || '',
productName: this.product.itemName || this.product.productName || '',
// productCode: this.product.productCode || '',
specification: this.product.specification || '',
material: this.product.material || '',

View File

@@ -51,8 +51,8 @@ export default {
return {};
}
return {
rawMaterialId: this.material.itemId || '',
rawMaterialName: this.material.itemName || '',
rawMaterialId: this.material.itemId || this.material.rawMaterialId || '',
rawMaterialName: this.material.itemName || this.material.rawMaterialName || '',
// rawMaterialCode: this.material.rawMaterialCode || '',
specification: this.material.specification || '',
material: this.material.material || '',

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

@@ -7,7 +7,6 @@
<script>
import { listWarehouse } from '@/api/wms/warehouse';
// import { listActualWarehouse } from '@/api/wms/actualWarehouse';
import { treeActualWarehouseTwoLevel } from '@/api/wms/actualWarehouse';
export default {

View File

@@ -2,7 +2,7 @@
<transition name="el-fade-in-linear">
<div v-if="tooltipVisible && data" class="row-tooltip" :style="adjustedTooltipStyle" ref="rowTooltip">
<slot>
<div class="tooltip-list">
<div class="tooltip-list" :style="{ gridTemplateColumns: `repeat(${columnCount}, 1fr)` }">
<div class="tooltip-item" v-for="field in visibleColumns" :key="field.prop">
<span class="label">{{ field.label }}</span>
<span class="value">{{ formatTooltipValue(data, field) }}</span>
@@ -21,6 +21,10 @@ export default {
type: Array,
default: () => []
},
columnCount: {
type: Number,
default: 2
},
data: {
type: Object,
default: () => ({})
@@ -45,15 +49,34 @@ export default {
const tooltipRect = this.$refs.rowTooltip?.getBoundingClientRect();
if (!tooltipRect) return this.tooltipStyle;
// 检查是否超出底部边界
if (parseInt(top) + tooltipRect.height > window.innerHeight) {
return { ...this.tooltipStyle, top: `${window.innerHeight - tooltipRect.height - 12}px` };
let adjustedTop = parseInt(top);
let adjustedLeft = parseInt(left);
const offset = 16;
// 检查是否超出底部边界 - 如果超出,将浮层显示在鼠标上方
if (adjustedTop + tooltipRect.height > window.innerHeight) {
adjustedTop = adjustedTop - tooltipRect.height - offset;
}
// 检查是否超出右侧边界
if (parseInt(left) + tooltipRect.width > window.innerWidth) {
return { ...this.tooltipStyle, left: `${window.innerWidth - tooltipRect.width - 16}px` };
// 检查是否超出右侧边界 - 如果超出,将浮层显示在鼠标左侧
if (adjustedLeft + tooltipRect.width > window.innerWidth) {
adjustedLeft = adjustedLeft - tooltipRect.width - offset;
}
return this.tooltipStyle;
// 检查是否超出顶部边界
if (adjustedTop < 0) {
adjustedTop = offset;
}
// 检查是否超出左侧边界
if (adjustedLeft < 0) {
adjustedLeft = offset;
}
return {
top: `${adjustedTop}px`,
left: `${adjustedLeft}px`
};
}
},
methods: {
@@ -98,9 +121,28 @@ export default {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
padding: 12px 14px;
pointer-events: none;
z-index: 5;
/* max-height: 70%; */
z-index: 9999;
overflow: auto;
transition: all 0.3s ease-in-out;
}
.tooltip-list {
display: grid;
gap: 8px;
}
.tooltip-item {
display: flex;
align-items: flex-start;
}
.tooltip-item .label {
flex-shrink: 0;
color: #666;
}
.tooltip-item .value {
color: #333;
word-break: break-word;
}
</style>

Some files were not shown because too many files have changed in this diff Show More