Compare commits

...

177 Commits

Author SHA1 Message Date
491eed3dad refactor(ContractSelect): 优化选中合同的加载逻辑
将原有的列表搜索获取选中合同的方式,改为直接调用getOrder接口单个查询,简化代码逻辑并提升查询效率
2026-06-19 13:14:02 +08:00
66838b6c69 feat: 优化合同选择组件与钢卷修正页面功能
1. 重构ContractSelect组件,新增all模式支持远程搜索
2. 修正钢卷修正弹窗布局为两列排版,扩大弹窗宽度
3. 为钢卷修正页面添加合同绑定功能,支持新增/更新合同关联关系
2026-06-19 12:45:07 +08:00
c8c2523fe7 feat(wms): 新增多项功能并优化标签展示逻辑
1. 异常管理页面默认显示继承按钮,新增继承弹窗传参
2. 多标签页优化订货单位展示:移除"有限公司"后缀并自适应字体大小
3. 基础面板新增备注查询条件和表格列展示
4. 流程页面新增节点点击交互和悬停效果
2026-06-19 12:30:18 +08:00
d0afe5eaaf feat(wms/coil): 新增发货单状态筛选视图
1. 在ship.vue页面新增isShipView参数并默认开启
2. 在base面板新增货单状态筛选 radio 组
3. 根据isShipView切换查询逻辑和表格列展示
4. 新增对应统计计数逻辑
2026-06-18 17:00:03 +08:00
7374b810c1 feat(wms/coil/label): 优化多规格标签的订货单位显示适配
1.  修复订货单位截断逻辑,保留完整客户名称
2.  新增根据订货单位长度动态调整字体大小的功能,适配长文本显示
2026-06-18 15:49:24 +08:00
041e5aef0e feat(contract-select): 为合同选择组件添加分页功能并优化搜索逻辑
1.  移除了vis-network依赖包
2.  重构两个合同选择页面的搜索与列表逻辑,移除本地合并合同数据的操作,改为直接使用接口返回数据
3.  为所有合同tab添加分页组件,支持分页查询、搜索重置页码
4.  调整表格高度优化布局,更新搜索触发事件为失焦、回车和清空按钮
5.  新增搜索查询按钮,优化搜索交互体验
2026-06-18 15:39:42 +08:00
6120e87966 feat(wms): 新增仓储售后流程页面,添加beautiful-mermaid依赖
1. 新增wms售后流程可视化页面,支持生产全链路和售后处理两种流程图切换展示
2. 安装beautiful-mermaid依赖并配置到transpileDependencies中
2026-06-18 14:50:51 +08:00
5828dbd133 feat(hrm/meal&employee): 新增员工吃辣偏好字段与就餐统计矩阵
1.  在员工入职/信息页面新增是否吃辣单选表单字段
2.  重构就餐统计模块,替换原有简单统计为吃辣/不吃辣 × 堂食/打包 × 有效/无效的三维交叉统计矩阵
3.  新增员工吃辣偏好映射接口,自动获取员工饮食偏好进行分类统计
2026-06-18 13:50:46 +08:00
ee49fbdcc0 feat: 新增合同配置页面,优化多页面合同关联逻辑
1.  新增crm/contract/selectConfig页面,支持本地配置可选合同列表,区分手动/接口同步来源
2.  优化ContractSelect组件,新增上次选中合同置顶、本地存储选中记录功能
3.  为合卷、分条、退火计划、钢卷编辑页面添加合同必填校验与自动关联逻辑
4.  移除各业务页面冗余的合同关系手动调用代码,统一关联逻辑
2026-06-18 13:49:52 +08:00
7f1a89eb61 feat(furnace-plan): 添加合同ID字段并实现合同关联功能
- 在 WmsFurnacePlanLocationItemBo 中新增 contractId 字段
- 实现合同ID映射关系构建和数据流转
- 移除二维码步骤类型的空值检查条件
- 完成合同信息在退火加工流程中的传递
2026-06-18 13:34:47 +08:00
759bbbed63 feat(wms): 钢卷加工必须绑定合同
- 在 WmsMaterialCoilBo 中新增 contractId 字段
- 添加 IWmsCoilContractRelService 依赖注入
- 实现加工操作必须绑定合同的验证逻辑
- 添加分卷、合卷、单个更新等操作的合同验证
- 实现插入钢卷合同关联记录的功能
- 在各种钢卷操作完成后自动插入合同关联记录
2026-06-18 13:25:16 +08:00
5b0cb314e4 feat(flow): 添加投诉处理流程模块及相关服务接口
- 创建受理单关联钢卷中间表服务接口及实现类
- 添加投诉受理单主服务接口及相应控制器
- 实现各部门投诉代办任务服务功能
- 集成最终方案下发部门及执行反馈服务
- 在员工信息表中新增是否吃辣字段
- 配置klp-flow模块依赖并注册到系统中
2026-06-18 11:19:55 +08:00
2fc4bf4043 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-18 10:39:16 +08:00
2fb5a64124 feat(employee): 添加员工是否吃辣字段支持
- 在 WmsEmployeeInfo 实体类中新增 isSpicyEater 字段
- 在 WmsEmployeeInfoBo 业务对象中添加 isSpicyEater 属性
- 更新 WmsEmployeeInfoMapper.xml 映射文件配置
- 在查询条件中添加 isSpicyEater 过滤逻辑
- 在 WmsEmployeeInfoVo 视图对象中添加 Excel 导出支持
2026-06-18 10:39:00 +08:00
379aa9d44b feat(crm): 优化合同模板管理和订单明细页面功能
1. 合同模板管理:添加选中状态高亮样式,新增当前选中模板状态管理
2. 订单明细页面:
   - 合并搜索框为产品名称/材质统一搜索
   - 重构表格数据结构,拆分合同与产品明细展示
   - 添加批量/单行保存功能,自动计算产品金额字段
   - 优化筛选条件和默认日期范围,调整表格列样式与配置
2026-06-18 10:27:09 +08:00
b4a9a48ae6 refactor(wms/report/split): 统一拆分报表页面模板组件
将所有分条相关报表页面替换为通用ActionTemplate组件,移除冗余的单独模板导入,统一配置报表参数,减少重复代码
2026-06-18 10:27:00 +08:00
41716b3430 feat(wms/coil): 新增钢卷加工链追溯功能并优化成本信息展示
1. 新增钢卷加工链双向追溯API接口getCoilChain
2. 替换原有的递归 lineage 构建逻辑,使用新接口获取完整加工链数据
3. 补充完善工序类型枚举映射,新增修复工序和退火工序
4. 重构加工路径图构建逻辑,使用接口返回的depth字段计算层级
2026-06-18 09:31:32 +08:00
585017873c feat(wms): 添加钢卷加工链追溯功能
- 在IWmsMaterialCoilService中新增queryCoilChain方法实现双向追溯
- 在WmsMaterialCoilController中添加/chain/all/{coilId}接口
- 在WmsMaterialCoilMapper中新增selectByParentCoilIds批量查询方法
- 在Mapper XML中实现FIND_IN_SET匹配逗号分隔的parent_coil_id查询
- 实现完整的双向追溯逻辑:向上追溯祖先向下查找后代支持合卷场景
- 创建CoilChainVo数据传输对象包含追溯结果和节点关系信息
- 实现BFS算法构建完整的加工链父子关系映射和深度计算
2026-06-17 16:49:19 +08:00
605f7b85a1 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-17 15:28:49 +08:00
192a27afbc fix(wms): 修复卷材子记录缺少父级ID关联问题
- 在新增卷材记录时设置parentCoilId字段
- 确保新创建的卷材能够正确关联到原始卷材记录
- 解决了卷材拆分或复制操作后数据关系不完整的问题
2026-06-17 15:28:37 +08:00
768b18c22a feat(cost+wms): 新增生产指标标签功能并优化钢卷成本展示
1. 为生产指标实体、BO、VO新增tags标签字段并完善MyBatis映射
2. 在生产指标查询中添加标签模糊筛选条件
3. 新增生产指标计算结果API接口
4. 优化成本综合页面:支持标签字段的增改查,新增指标结果批量保存逻辑
5. 移除废弃的costDataService文件,重构钢卷详情页成本展示模块,新增加工路径可视化和吨钢成本计算展示
6. 注释并禁用了原有的检验任务相关代码逻辑
2026-06-17 15:09:08 +08:00
3719416cbf fix(cost): 修复报表日期格式化问题
- 修改了报告日期的格式化逻辑,使用 SimpleDateFormat 替代直接字符串拼接
- 确保日期格式统一为 yyyy-MM 格式进行查询匹配
- 避免了可能的日期格式不一致导致的查询错误
2026-06-17 14:40:39 +08:00
791be3e1a5 feat: 新增多类业务功能并优化页面展示
1. 新增钢卷周期对比查询API,增加冷轧卷、花纹板物料类型
2. 优化库存积压统计逻辑,支持成品和原料数据合并计算
3. 新增告警统计功能,实现长度/厚度告警的数量和重量统计
4. 替换岗位管理页面为冷轧厂业务流程泳道图页面
2026-06-17 11:01:47 +08:00
7b7f4b902e feat(cost): 添加生产指标计算结果批量保存功能
- 在CostProdMetricResultBo中新增resultIds和prodMetricResultList字段
- 添加/batch接口支持批量保存生产指标计算结果
- 实现batchSaveWithDelete方法支持先删除再插入操作
- 使用事务注解确保批量操作的数据一致性
- 集成CollUtil工具类处理集合操作
- 完善相关的Service接口定义
2026-06-17 10:11:10 +08:00
c547456108 feat(cost): 添加生产指标计算结果模块
- 创建 CostProdMetricResult 实体类,包含主键、报表ID、指标ID、计算日期、班组、计算值等字段
- 创建 CostProdMetricResultBo 业务对象,用于接收前端参数并进行验证
- 创建 CostProdMetricResultVo 视图对象,用于返回给前端的数据结构
- 实现 CostProdMetricResultController 控制器,提供增删改查和导出功能
- 创建 CostProdMetricResultMapper 数据访问接口,继承 BaseMapperPlus
- 实现 CostProdMetricResultServiceImpl 服务类,处理业务逻辑和数据操作
- 配置 CostProdMetricResultMapper.xml 映射文件,定义结果映射关系
- 添加完整的 CRUD 操作支持,包括分页查询、单条查询、新增、修改、删除和批量导出功能
- 集成 MyBatis-Plus 分页插件和 LambdaQueryWrapper 查询构建器
- 实现数据校验机制和 Excel 导出功能
2026-06-17 09:57:00 +08:00
931fc74ed7 feat(wms): 添加钢卷环比报表功能
- 在 IWmsMaterialCoilService 中新增 queryPeriodComparisonList 方法
- 在 WmsMaterialCoilController 中新增 /listForPeriodComparison 接口
- 在 WmsMaterialCoilMapper 中新增 selectPeriodComparisonList 查询方法
- 修改原 selectPageReportList 为 selectReportList 并调整相关调用
- 新增 WmsMaterialCoilPeriodComparisonVo 数据传输对象
- 添加环比报表专用的 SQL 查询语句,包含实际长度、理论长度、理论厚度字段
2026-06-17 08:21:42 +08:00
e7f1e584eb Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-16 17:02:31 +08:00
b43b44d044 feat(wms): 新增钢卷告警历史批量处理功能
新增批量处理历史告警接口,支持将今天以前的告警标记为指定状态,前端添加对应操作按钮,可一键处理或忽略历史告警
2026-06-16 17:02:25 +08:00
d053dd0319 refactor(domain): 将检验结果值数据类型从BigDecimal改为String
- 修改WmsInspectionDetail实体类中的itemValue字段类型为String
- 修改WmsInspectionDetailBo业务对象中的itemValue字段类型为String
- 修改WmsInspectionDetailVo视图对象中的itemValue字段类型为String
2026-06-16 16:51:33 +08:00
3b1ce45043 feat: 新增钢卷成本信息展示与能耗辅料成本报表页面
1. 在钢卷详情页新增成本信息模块,展示产线类型、投入产出量、报表信息和总成本
2. 新增成本数据服务类,支持按日期和产线获取完整成本明细与计算数据
3. 新增能耗和辅料两类成本报表页面,支持按产线筛选查看报表
4. 优化岗位管理页面,替换vis.js为ECharts实现岗位树图,新增职责弹窗查看功能
5. 优化综合成本页面,隐藏部分反填按钮和操作入口
2026-06-16 16:33:27 +08:00
5473fbf28f feat(wms): 新增岗位管理与岗位职责管理功能
1. 新增依赖包vis-network用于可视化岗位树
2. 新增岗位相关API接口,包含增删改查功能
3. 新增岗位职责相关API接口,包含增删改查功能
4. 新增岗位管理页面,支持岗位树可视化、岗位CRUD以及关联的岗位职责管理
2026-06-16 13:42:12 +08:00
2874f1727a feat(cost): 新增成本综合页面的辅料能耗反填功能
本次提交新增了全量反填、单行反填、单元格反填的批量/单独反填能力,支持辅料和能耗类型的数据反填入库,同时新增了反填进度弹窗、优化了表格列头布局和输入框后缀操作按钮样式,补充了对应的API引入和反填处理器注册逻辑。
2026-06-16 11:52:34 +08:00
a3a4986cb8 feat(wms/report): 新增产线报表页面,支持多维度数据统计与可视化
该页面实现了产线相关的钢卷产出、消耗、品质、异常库位等数据的统计分析,支持按日/周/月维度拆分数据,提供折线图可视化展示与明细表格查询,包含快捷时间范围选择、多条件筛选功能
2026-06-16 11:52:22 +08:00
f525770094 fix(wms/coil): 调整酸洗轧制动作类型区间范围并注释完成待办逻辑
1. 将acidRollingActionType判断区间从200-299修正为200-210
2. 注释掉stepSplit.vue中调用completeAction完成待办的代码逻辑
2026-06-16 11:52:10 +08:00
25beef5517 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-16 11:41:40 +08:00
e6b1e31bd1 feat(wms/coil): 优化钢卷生命周期追踪的步骤插槽数据传递
1. 给CoilTraceResult的stepBody插槽新增allSteps参数传递标准化后的全量步骤列表
2. 在LifecycleTrace中新增getCreationCoils方法,实现创建步骤钢卷列表的兜底获取逻辑:
   - 优先使用步骤自身的newCoilInfoList
   - 若为空则通过全量步骤匹配获取前序步骤的旧钢卷信息
   - 最后兜底使用当前钢卷信息
3. 修复入库步骤空钢卷判断和列表渲染的逻辑
2026-06-16 11:41:33 +08:00
8c3a3eec28 fix(wms): 钢卷退火绑定的限制
- 添加详细的锁定状态描述映射
- 区分不同锁定状态的具体业务场景
- 提供更精确的错误提示信息
- 增强用户体验和问题定位效率
2026-06-16 09:26:25 +08:00
1510f43aee refactor(WmsMaterialCoilService): 简化待操作记录状态更新逻辑
- 使用新的 completeAction 方法替代手动设置状态和时间
- 移除冗余的状态赋值和时间设置代码
- 通过方法调用统一处理操作完成逻辑
2026-06-15 18:06:34 +08:00
cb8fce435c fix(wms): 修复分卷取消操作中的逻辑错误
- 移除过早删除待操作记录的代码
- 保留母卷独占锁释放功能但暂时注释
- 重新调整代码执行顺序确保业务逻辑正确性
- 修复可能导致数据不一致的操作步骤
2026-06-15 17:49:28 +08:00
7bb68483e6 feat(wms): 添加批量处理和批量忽略功能 2026-06-15 16:22:20 +08:00
696280bd47 feat(wms): 添加调拨单按时间倒序排序功能
- 在调拨单查询中增加按调拨时间倒序排序逻辑
- 确保最新的调拨单记录优先显示
- 提升调拨单列表的数据展示体验
2026-06-15 14:26:37 +08:00
bdf01feacb feat(warning): 添加钢卷告警批量处理功能
- 在 IWmsMaterialWarningService 中添加 batchHandle 方法接口
- 在 WmsMaterialWarningBo 中新增 warningIds 字段用于存储 ID 集合
- 在 WmsMaterialWarningController 中添加 /batchHandle 接口
- 在 WmsMaterialWarningServiceImpl 中实现批量处理逻辑
- 更新 Excel 导出标题中的分隔符为中文顿号
- 批量处理时自动填充处理人、处理时间和处理状态信息
2026-06-15 13:55:36 +08:00
120320c800 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-15 13:33:34 +08:00
3db1651efd feat(wms): 添加岗位和岗位职责管理功能
- 创建岗位实体类 WmsPost 和岗位职责实体类 WmsPostDuty
- 实现岗位和岗位职责的业务对象 BO 和视图对象 VO
- 开发岗位和岗位职责的服务接口及实现类
- 添加岗位和岗位职责的控制器提供 REST API 接口
- 配置 MyBatis Plus 的 Mapper 接口和 XML 映射文件
- 实现岗位和岗位职责的增删改查、分页查询和导出功能
- 添加数据验证、日志记录和防止重复提交功能
2026-06-15 13:33:23 +08:00
9d679954fa fix(wms/coil): 修复钢卷领料和合并相关的逻辑问题
1. 新增根据酸洗动作类型设置锁值的逻辑
2. 修复合并页面钢卷选择器的筛选条件和匹配逻辑
2026-06-15 13:21:54 +08:00
a2844ec54a fix(service): 修复钢卷操作中的空指针异常和逻辑错误
- 在 WmsCoilPendingActionServiceImpl 中添加钢卷存在性检查,避免空指针异常
- 当关联钢卷不存在时抛出运行时异常提示"关联的钢卷不存在"
- 修复 WmsMaterialCoilServiceImpl 中的合卷操作逻辑
- 修改条件判断避免整数缓存导致的比较错误
- 合卷操作已在 mergeCoils 方法中单独处理,此处跳过重复操作
2026-06-15 11:48:12 +08:00
91ddc8602a fix(wms): 优化钢卷锁定状态提示信息
- 添加getLockStatusDesc方法用于获取详细的锁定状态描述
- 实现针对不同锁定状态的状态码映射和中文描述
- 更新异常消息显示具体的锁定操作类型而非笼统提示
- 提升用户对钢卷当前操作状态的认知准确性
2026-06-15 11:35:24 +08:00
22fd3c4a58 refactor(WmsMaterialCoilService): 移除钢卷操作权限验证检查
- 注释掉单个更新方法中的独占状态验证逻辑
- 移除批量更新方法中的权限验证检查代码
- 保留原有的注释文档结构
- 简化方法实现逻辑,跳过操作前的状态验证步骤
2026-06-15 11:26:42 +08:00
ceab5d4be3 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-15 11:09:59 +08:00
bf8b69d193 feat(wms): 添加钢卷锁定机制并优化操作流程
- 在WmsCoilPendingActionBo中新增lockValue字段用于钢卷锁值控制
- 为insertByBo方法添加事务注解确保数据一致性
- 实现钢卷领料时的锁状态校验和上锁逻辑
- 添加unlockCoil方法在操作完成后自动解锁关联钢卷
- 在deleteBatch、completeAction和cancelAction方法中集成自动解锁功能
- 新增getLockStatusDesc方法提供详细的锁状态描述信息
- 优化合卷操作流程,使用completeAction替代手动更新状态
- 在MaterialCoilService中增强独占状态检查,支持多种锁定类型识别
2026-06-15 11:09:45 +08:00
7feaf8021b feat: 新增规格校验功能并优化钢卷号输入处理
1. 新增validSpecification规格校验函数,校验格式为数字.两位小数*数字的钢卷规格
2. 为多个页面的钢卷号输入框添加trim修饰符自动去除首尾空格
3. 在API层统一对钢卷号字段做trim预处理
4. 为原料和产品表单添加规格必填校验和格式校验
5. 新增钢卷信息修正页面,添加生产耗时自动计算功能
6. 优化部分页面的UI和代码冗余
2026-06-15 10:56:28 +08:00
6328b4ac7a Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-15 10:04:37 +08:00
183e6d08d8 feat(wms,cost): 新增多项功能并修复部分问题
1. 退火计划页面新增exclusiveStatus状态字段
2. 钢卷分步加工新增预览标签功能
3. 修复实际库位空值判断问题
4. 成本综合页面新增价格管理功能,支持配置指标单价
2026-06-15 10:04:35 +08:00
a037c56122 feat(wms): 完善退火计划钢卷绑定和解绑逻辑
- 添加钢卷映射缓存以提高查询效率
- 增加钢卷排他状态检查防止并发操作冲突
- 实现绑定计划时自动释放实际库区锁定功能
- 优化解绑操作增加数据验证和异常处理
- 修复解绑后钢卷状态更新确保一致性
- 移除冗余的批量释放库区操作提升性能
2026-06-14 12:19:48 +08:00
857daa24af feat(wms): 添加钢卷数据校验逻辑
- 实现钢卷存在性校验,确保钢卷未被删除
- 添加钢卷类型校验,只允许现存钢卷(dataType=1)参与加工
- 阻止历史钢卷被用于退火操作
- 提供详细的错误提示信息
2026-06-14 11:31:10 +08:00
0968dcaded Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-13 16:16:38 +08:00
cced2ff4aa feat(cost): 添加单价字段和使用单价标识功能
- 在CostProdMetric实体类中添加usePrice字段,用于标识是否使用单价
- 更新CostProdMetricBo、CostProdMetricVo数据传输对象,增加单价相关属性
- 修改CostProdMetricMapper.xml映射文件,添加usePrice字段映射配置
- 扩展CostProdMetricServiceImpl查询逻辑,支持按是否使用单价进行筛选
- 更新前端metric.vue页面,添加单价输入框和是否使用单价下拉选择组件
- 实现表格中单价列的显示和编辑功能,并增加条件查询支持
2026-06-13 16:16:30 +08:00
f197462b11 refactor(mes/qc): 重构质检模块接口与页面,迁移is模块业务到qc模块
1.  新增qc模块下检验主、检验明细、拉伸试验相关接口文件
2.  删除原is模块下的检验任务、样品库存、检验委托单接口与页面文件
3.  调整待办页面的检验任务标签页引用路径
4.  优化质检模板页面的检查项相关交互逻辑
2026-06-13 15:51:15 +08:00
9559e5810e refactor(domain): 重构拉伸检验细节实体的弯曲试验
- 将 bendTest90 字段重命名为 bendTest,统一弯曲试验结果字段
- 将 bendTest180 字段重命名为 bendTestReverse,明确表示反向弯曲试验
- 更新数据库映射文件中的字段映射关系
- 修改服务层查询条件中对应的字段引用
- 更新 Excel 导出注解中的字段描述和值映射
2026-06-13 14:34:24 +08:00
92ad229104 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-13 13:30:56 +08:00
ee1cb31321 feat(mes/eqp): 新增设备监控模拟页面
该页面实现了设备状态统计看板、多条件筛选搜索、自动刷新、设备卡片展示、详情弹窗查看功能,使用mock数据模拟真实设备运行状态和参数变化
2026-06-13 13:30:52 +08:00
f0de25a3a2 feat(inspection): 添加检验模块日期范围筛选功能
- 在WmsInspectionMainBo中增加inspectionDateStart和inspectionDateEnd字段用于日期范围筛选
- 在WmsInspectionMainServiceImpl中实现日期范围查询逻辑
- 在WmsInspectionTensileDetailBo中增加productionDateStart、productionDateEnd、testDateStart和testDateEnd字段
- 在WmsInspectionTensileDetailServiceImpl中实现生产日期和试验日期范围查询逻辑
- 添加DateTimeFormat注解支持日期格式化处理
2026-06-13 13:08:11 +08:00
0d40774194 feat(wms): 添加检验管理模块功能
- 新增检验项目明细相关实体类、业务对象、视图对象及服务接口
- 实现检验项目明细的增删改查、分页查询及数据校验功能
- 新增检验主记录相关实体类、业务对象、视图对象及服务接口
- 实现检验主记录的增删改查、分页查询及数据校验功能
- 新增金属材料室温拉伸试验相关实体类、业务对象、视图对象及服务接口
- 实现拉伸试验记录的增删改查、分页查询及数据校验功能
- 配置MyBatis映射文件及Excel导出功能
- 添加相应的控制器及参数验证规则
2026-06-13 13:02:43 +08:00
948e62daae fix(wms/report/comparison): 修复库存对比报表的查询参数错误
将原有的actionId、actionIds查询参数修正为coilId、coilIds,匹配接口实际需要的入参字段
2026-06-13 11:23:36 +08:00
48d12fe056 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-13 11:15:42 +08:00
6edc6e1100 feat(wms-report): 新增对比报表页面和尺寸异常统计功能
1. 新增comparison.vue对比报表页面,支持基期/当期数据对比、快速环比查询、明细表格查看和列配置
2. 在action.vue报表中添加尺寸异常统计模块,统计长度和厚度异常的卷数、总重及占比
3. 新增告警阈值配置获取逻辑,从系统配置中读取长度和厚度异常阈值
2026-06-13 11:15:38 +08:00
12ea9b0b83 refactor(wms/coil/label): 为热卷号添加动态字体大小适配
移除了硬编码的字体样式,根据热卷号长度动态调整字号,避免长文本溢出标签
2026-06-13 11:14:25 +08:00
c149216ebd refactor: 多页面UI优化、接口清理与文案调整
1. 移除质检模板页面未使用的getCheckItem接口导入
2. 给成本综合页面表格添加固定高度适配布局
3. 更新物料告警页面的表格列文案:理论值→推论值、实测值→实际值、实际偏差值→实际偏差
4. 重构重定向菜单页面的样式,优化布局与视觉效果
2026-06-13 11:14:14 +08:00
325a93fd84 refactor: 将“理论长度/厚度”统一改为“推论长度/厚度”
修改了CoilSelector组件、CoilInfo组件和报表列设置中的相关文案,将统一术语表述为“推论”,替代原有的“理论”表述。
2026-06-13 11:13:49 +08:00
f0656b57d4 fix(wms): 解决材料厚度预警中的精度比较问题
- 统一将理论厚度和规格厚度四舍五入到3位小数后再进行比较
- 避免因高精度尾数导致的比较结果与存储值不一致问题
- 对阈值也进行相同的精度处理确保比较逻辑正确
- 修复偏差值计算中重复精度转换的问题
- 优化偏差率计算中的除法精度控制
2026-06-13 10:22:22 +08:00
9c7d2dca65 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-12 16:00:45 +08:00
36b1e3da82 fix(warning): 解决退火工序告警处理问题
- 退火工序没有actionId时不创建代操作记录,直接设置actionType=600
- 当actionId为空时使用bo中的actionType作为兜底方案
- 确保退火工序的告警能够正确关联到对应的操作类型
2026-06-12 16:00:34 +08:00
c83eb79d25 fix(wms/coil/label): 修正标签页生产日期字段的时间来源
将多个标签渲染组件中的生产日期从updateTime改为createTime,统一展示正确的创建时间
2026-06-12 15:30:27 +08:00
e0cf4b46b6 feat(mes/qc): 增加物理性质和化学成分同时导入
新增了通用的综合导入组件,支持同时导入化学成分和物理性能数据,并在理化证书页面添加了对应的综合导入按钮和逻辑,实现一站式批量导入两种类型的质检数据。
2026-06-12 13:43:17 +08:00
00972112d2 feat: 多模块新增功能与优化体验
1. 隐藏客户录入页的客户编码字段
2. 为WmsMaterialWarningBo添加日期格式化注解
3. 合同产品选择时自动匹配默认材质
4. 物料告警页新增今日筛选、行样式区分与偏差率展示优化
5. 合同页新增快速新增客户功能
2026-06-12 13:31:58 +08:00
2559dc27cb feat(crm): 添加客户编码自动生成功能
- 新增 selectMaxCustomerCode 方法查询最大客户编码
- 实现客户编码自动生成逻辑,支持纯数字和带前缀格式
- 添加正则表达式解析编码规则并递增末尾数字
- 集成编码生成功能到客户插入业务流程中
2026-06-12 13:17:33 +08:00
7a0d7e1b12 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-12 13:03:34 +08:00
1cd2cf2b9a feat(wms): 添加物料预警创建时间范围查询功能
- 在WmsMaterialWarningBo中新增createStartTime和createEndTime字段
- 为新增字段添加JSON格式化注解和文档注释
- 在WmsMaterialWarningServiceImpl中实现时间范围查询逻辑
- 使用ge和le条件进行创建时间范围过滤
- 保持按创建时间倒序排列的排序规则
2026-06-12 13:03:25 +08:00
98116fa042 refactor: 多页面UI优化与功能完善
1. 优化合同页面默认备注内容
2. 修复分卷编辑接口参数缺失问题
3. 新增分卷、合卷、加工菜单路由
4. 重构导航栏默认显示逻辑
5. 升级重定向菜单页面样式与布局
6. 优化告警页面查询与展示字段
7. 重构全局搜索组件为弹窗模式
8. 优化报表页面代码格式与接口参数
2026-06-12 11:25:15 +08:00
d3c6790603 refactor(WmsMaterialWarningVo): 继承BaseEntity并移除钢卷信息的JSON忽略注解
- 继承com.klp.common.core.domain.BaseEntity类
- 移除coilVo字段的@JsonIgnore注解
- 更新类结构以支持基础实体功能
2026-06-11 17:23:48 +08:00
c1e3fa5141 fix(wms): 修复钢卷警告检查逻辑
- 注释掉新增钢卷时的长度/厚度偏差检查
- 添加actionId为空判断条件避免警告插入异常
- 优化更新钢卷时的警告检查逻辑
2026-06-11 16:49:15 +08:00
f319308196 refactor(domain): 移除WmsCoilAbnormalExportVo中的废弃字段
- 注释掉parentAbnormalId字段以优化数据结构
- 移除sourceSystem字段减少不必要的数据传输
- 删除processSource字段简化对象属性
- 保留plateSurface字段用于表列宽度设置
- 为后续代码清理和重构做准备
2026-06-11 16:25:06 +08:00
185745b7da Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-11 15:31:26 +08:00
7440706e2e style(sidebar): 优化侧边菜单样式与标识逻辑
1.  移除原有二级菜单叶子节点的小圆点样式
2.  新增子菜单标识图标组件,为有子级的菜单添加折叠箭头标识
3.  调整菜单标题渲染逻辑,统一标题样式处理
4.  修复菜单容器的定位样式问题
2026-06-11 15:31:23 +08:00
0adb29139e 修复厚度偏差曲线 2026-06-11 15:24:46 +08:00
2148a068f8 修复厚度偏差曲线 2026-06-11 15:10:56 +08:00
e1bb9e5431 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-11 15:02:08 +08:00
8b2039f06a 修复厚度偏差曲线 2026-06-11 14:59:31 +08:00
9761faa2d2 feat(wms, crm): 新增导出模式选择并修复canvas图片缩放问题
1. 为Wms异常报表页面新增多行/单行导出切换功能
2. 拆分导出菜单为单行、多行两种导出选项
3. 修复ContractExportDialog中图片缩放比例的冗余限制
2026-06-11 14:49:31 +08:00
d5f00a4b0b Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-11 14:02:52 +08:00
b9fb4b4611 refactor(wms/coil): 重构钢卷详情页面,拆分组件并优化页面结构
1.  将原钢卷详情页面拆分为多个独立组件,按功能模块划分
2.  调整路由指向,将页面入口指向新的页面文件
3.  新增状态工具类,封装通用格式化和样式
2026-06-11 14:02:49 +08:00
7d76ef0c52 feat(wms): 添加异常报表导出功能
- 在WmsMaterialCoilBo中新增abnormalExportCount字段用于控制导出格式
- 实现异常报表的Excel导出功能,支持两种导出模式
- 添加extracted方法处理导出逻辑,构建EasyExcel导出数据
- 创建createExportVo方法组装导出DTO对象,包含钢卷基本信息和异常信息
- 集成EasyExcel实现报表导出,设置响应头和文件下载格式
- 处理无异常信息钢卷的空数据行创建逻辑
2026-06-11 11:49:28 +08:00
ea71a6dd93 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-11 11:39:44 +08:00
b9b6ae7e79 fix(wms): 修复钢卷号重复校验问题
- 添加注释说明子卷与母卷钢卷号冲突的处理逻辑
- 在查询条件中增加exclusiveStatus字段过滤,避免正在处理的数据被误判为重复
- 修复入场钢卷号、当前钢卷号和供应商钢卷号的重复检查逻辑
- 确保历史数据和排他状态数据不会影响重复性校验结果
2026-06-11 11:39:29 +08:00
20a75aec4b Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-11 11:28:57 +08:00
3ad7bf40b5 feat: 新增二级菜单子导航系统(SubNav + redirectMenu)
- 新增 SubNav 组件:Navbar 下方水平子导航条,展示当前二级菜单下的三级页面,支持滚动和下拉分组
- 新增 redirectMenu 页面:点击二级菜单时卡片式展示子页面列表
- SidebarItem 深度 >=1 时改为叶子节点渲染(小圆点标记),激活高亮回退到二级菜单
- Navbar 布局重构为 Flexbox,面包屑/SubNav 根据场景切换
- 新增 productionLine Vuex 模块,轧辊研磨页改为 store 方式读取产线数据
- Sidebar activeMenu 逻辑增强:自动定位当前页所属二级菜单
2026-06-11 11:28:42 +08:00
196e628665 feat(WmsCoilAbnormal): 添加钢卷ID集合批量查询功能
- 在WmsCoilAbnormalBo中新增coilIds字段用于批量查询
- 实现逗号分隔的coilIds批量查询逻辑
- 使用Stream API处理字符串分割和类型转换
- 添加空值过滤确保查询条件的有效性
- 集成到现有的查询条件构建流程中
2026-06-11 10:24:55 +08:00
7c61c42eb5 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-11 09:49:54 +08:00
1223b634b7 refactor(wms): 移除销售人员相关字段
- 从WmsMaterialCoilExportVo中移除saleName私有字段
- 从WmsMaterialCoilVo中移除saleId和saleName私有字段
- 从WmsMaterialCoilMapper.xml的多个查询中移除sale_name映射
- 从WmsMaterialCoilMapper.xml的关联查询中移除sys_user表连接
- 移除与销售人员相关的数据库字段映射和关联关系
2026-06-11 09:49:42 +08:00
87913ba0a0 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-11 09:29:49 +08:00
eab45a8706 feat: 合同新增自动补全交货日期功能
- 签订日期变更时自动计算交货日期(签约 + 1天 + 30天 → 按5日取整)
- 选择合同模板或点击「自动补全交货日期」时自动替换合同内容中的交货时间占位符
- 新增 DC01-H 材质选项
- 修正按钮文案「管理合同」→「管理合同模板」
2026-06-11 09:29:33 +08:00
a9a7a0889e Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-10 17:45:05 +08:00
cd2e4016a6 feat(warning): 添加产线类型字段支持告警功能
- 在 WmsMaterialWarning 实体中新增 actionType 字段
- 在 WmsMaterialWarningBo 和 WmsMaterialWarningVo 中添加 actionType 属性
- 更新 WmsMaterialWarningMapper.xml 映射文件以包含 actionType 字段
- 在 WmsMaterialWarningServiceImpl 中注入 WmsCoilPendingActionMapper
- 实现告警查询时根据产线类型过滤的功能
- 在告警插入前查询并设置对应的产线类型信息
- 完善告警服务中的厚度和长度检查逻辑
2026-06-10 17:44:56 +08:00
87d72b2a0d feat(wms/coil): 增加排产厚度字段
1. 新增排产厚度字段到钢卷信息列表、报表列配置、分条/合并/录入页面
2. 优化部分代码格式与换行,修复多余空格问题
3. 调整表单布局,将排产厚度表单项加入对应页面
2026-06-10 17:22:12 +08:00
4342215c00 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-10 17:11:08 +08:00
7bf7d24f29 feat(wms/coil): 新增异常继承功能并优化钢卷列表页面
1.  为异常管理弹窗添加继承异常按钮和继承弹窗
2.  新增罩式退火原料库选项
3.  优化钢卷列表表格样式与列配置,新增标签预览、打印、数字钢卷、追溯功能
4.  复用生产工序配置常量统一维护
2026-06-10 17:11:05 +08:00
4da8d8d297 feat(wms): 添加排产厚度字段支持
- 在 WmsMaterialCoil 实体类中新增 scheduleThickness 字段
- 在 WmsMaterialCoilBo 业务对象中新增 scheduleThickness 字段
- 在 WmsMaterialCoilController 控制器中添加排产厚度列映射
- 在 WmsMaterialCoilExportVo 导出对象中添加 Excel 导出支持
- 在 WmsMaterialCoilMapper.xml 中添加数据库映射配置
- 在 WmsMaterialCoilServiceImpl 服务实现中添加查询条件支持
- 修复钢卷号重复检查逻辑中的数据类型判断问题
- 在 WmsMaterialCoilVo 视图对象中添加排产厚度字段
2026-06-10 16:49:00 +08:00
c4eab467ee feat(wms): 添加钢卷号重复检查功能
- 在新增钢卷时检查当前钢卷号是否重复
- 在简单更新时检查当前钢卷号是否重复并排除自身
- 在单个更新时检查当前钢卷号是否重复并排除自身
- 在分卷操作时检查每个子钢卷号是否重复
- 在合卷操作时检查新钢卷号是否重复
- 在子钢卷创建时检查子钢卷号是否重复
- 在退货操作时检查当前钢卷号是否重复并排除自身
- 修复历史钢卷恢复时的重复检查参数传递问题
2026-06-10 15:54:01 +08:00
fd50118161 refactor(contract/export/preview): 优化合同打印导出功能,添加页码和修复样式
1.  移除coilTable的异常行高亮逻辑
2.  修复导航栏告警badge的显示逻辑
3.  为合同导出和预览添加页码标注,调整打印样式
4.  移除冗余的合同打印预览代码
2026-06-10 11:29:41 +08:00
cc63aa80b2 fix: 修复/优化多个业务页面的逻辑与配置
1. 修正物料选项中的BX51D+Z为DX51D+Z
2. 给L2匹配面板的标准化方法添加日志与start_date/end_date字段解析
3. 优化卷材页面的日期赋值逻辑并添加调试日志
4. 简化异常表格的图片组件写法,新增继承来源列
2026-06-10 09:21:34 +08:00
c95ea7db61 feat(mes/roll/grind): 磨辊间增加机组字段 2026-06-09 17:55:42 +08:00
f50c240bbe Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-09 17:47:46 +08:00
66278e635b feat(roll): 添加机架字段支持
- 在MesRollInfo实体类中新增frame字段
- 在MesRollInfoBo业务对象中添加frame字段定义
- 实现机架字段的查询过滤功能
- 在MesRollInfoVo视图对象中增加frame字段映射
- 完成机架数据的Excel导出功能
2026-06-09 17:47:35 +08:00
74d0ba57e2 feat(crm/contract): 优化合同产品材质输入与导出样式
1. 将材质输入框改为可搜索创建的选择器,新增冷轧卷(花纹)选项和SPCC等材质选项
2. 优化合同导出表格的边框、内边距和字体样式,统一表格样式
2026-06-09 17:42:28 +08:00
e00d1357b0 refactor(wms): 优化钢卷告警数据查询逻辑解决循环依赖
- 将钢卷信息批量查询逻辑从服务层迁移到控制器层
- 在控制器中实现钢卷ID收集和批量查询功能
- 通过Map映射方式关联钢卷信息到告警数据
- 移除服务层中的WmsMaterialCoilService依赖注入
- 提高数据查询效率和代码结构清晰度
2026-06-09 17:08:01 +08:00
b9f87c6cc4 feat(warning): 添加物料预警按创建时间倒序排序功能
- 实现物料预警列表按创建时间倒序排列
- 优化查询逻辑以支持时间排序功能
2026-06-09 10:04:36 +08:00
7c9c99bf45 feat(wms): 添加钢卷警告信息关联查询功能
- 在 WmsMaterialWarningBo 中新增 coilIds 字段用于批量过滤
- 在 WmsMaterialWarningServiceImpl 中实现批量钢卷信息查询和填充逻辑
- 添加按逗号分隔的钢卷ID集合过滤功能
- 在 WmsMaterialWarningVo 中增加 coilVo 关联字段并设置为忽略导出
- 实现了钢卷警告与钢卷信息的关联显示功能
- 优化了查询性能通过批量获取钢卷数据减少数据库访问次数
2026-06-09 09:58:35 +08:00
fdb13b7261 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-09 09:41:31 +08:00
74a3803290 refactor(WmsMaterialCoilService): 修复理论厚度和长度沿用老数据导致重复告警
- 移除理论厚度为空的条件判断,统一实际长度不为空时进行计算
- 移除理论长度为空的条件判断,改为直接计算并设置理论长度
- 保持原有的体积、宽度和厚度计算公式不变
- 简化代码结构,减少不必要的条件分支
2026-06-09 09:41:14 +08:00
76497eece7 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-09 09:02:47 +08:00
d231d3619a feat(wms/report): add length/thickness diff columns and abnormal alert
1. 调整产品内容工具函数,移除冗余的quantity和taxPrice字段返回
2. 重新编排报表列配置,新增长度/厚度差值列并调整字段顺序
3. 实现差值计算逻辑与异常标红展示,从配置获取告警阈值
2026-06-09 09:02:44 +08:00
20966157c5 fix(wms): 修正材料预警服务中的数值精度计算问题
- 为理论值、实际值、允许偏差和偏差值设置统一的3位小数精度
- 将偏差率计算精度从4位小数调整为1位小数
- 修正厚度偏差计算公式中的减法运算顺序
- 在警告消息中应用相同的数值精度格式化
- 确保所有BigDecimal运算都使用HALF_UP舍入模式
2026-06-08 18:02:52 +08:00
59e58e5206 feat(warning): 更新钢卷告警检查功能支持动态阈值配置
- 在 WmsMaterialCoilBo 中新增 specThickness 字段用于存储规格厚度
- 修改 checkAndInsertWarnings 方法签名以传递 BO 对象
- 将长度和厚度告警阈值改为从系统配置表动态读取
- 长度告警阈值配置键为 material.warning.length,默认值 0.1
- 厚度告警阈值配置键为 material.warning.thickness,默认值 -0.01
- 厚度检查逻辑改为理论厚度与规格厚度对比
- 钢卷创建和更新流程中传递 BO 对象到告警检查方法
- 优化告警消息内容以反映阈值检查而非固定比例
- 移除原有的实测厚度检查规则,统一使用规格厚度作为参考标准
2026-06-08 17:45:10 +08:00
59ceeed4a4 fix(crm/contract): 优化合同预览与导出的样式及重复渲染问题
1.  为产品内容组件添加值相等判断,避免重复解析内容
2.  统一合同预览和导出弹窗的表格边框样式为2px粗边框
3.  将合同预览的字体改为黑体并调整字重,优化显示效果
4.  调整表格字体粗细的配置标准
2026-06-08 16:31:17 +08:00
fac59f4346 feat: 合同导出新增附件图片配置功能
- 新增附件图片加载区域(从 businessAnnex/techAnnex 等字段提取 OSS 图片)
- 支持图片勾选显隐、拖拽排序(上移/下移)
- 导出 HTML 预览和 PDF 均支持图片附件页渲染
- @open 重构为 onDialogOpen,自动拉取附件列表
- 新增 loadImage 辅助方法,PDF 导出支持 JPEG 图片嵌入
2026-06-08 11:21:25 +08:00
f6a74e58ea refactor(wms/coil): 抽象排产单组件,复用排产单展示逻辑
1.  新增PlanSheetViewer通用排产单展示组件,支持图片、excel、普通文件预览和空状态
2.  改造TimeInput组件,修复绑定属性写法
3.  替换typing.vue、stepSplit.vue、split.vue、merge.vue中的旧排产单代码,统一使用新组件
4.  删除冗余的排产单相关API调用和本地数据逻辑
2026-06-08 10:22:30 +08:00
857a3948d6 feat(wms): 新增钢卷通用维度告警管理功能
1. 新增告警信息路由页面与API接口
2. 在导航栏添加告警入口与未读红点提示
3. 实现告警列表查询、处理、忽略、删除与导出功能
4. 每分钟自动刷新告警状态检查
2026-06-08 10:05:52 +08:00
47b3fb24b7 feat: 新增阿里妈妈数黑体字体并更新标签样式
1. 新增阿里妈妈数黑体字体文件及授权说明文档
2. 全局替换标签默认字体为阿里妈妈数黑体
3. 统一调整多个标签页的卷号/原料号字体大小为1em
4. 修复表单输入框的v-model.number类型绑定问题
5. 删除废弃的盐雾试验、力学性能、样品标签预览组件
2026-06-08 09:05:15 +08:00
97e0df7ae1 refactor(aps/planSheet): 重构排产单详情页与列表页,替换可编辑表格为文件上传功能
1. 移除原排产单明细可编辑表格,替换为文件上传预览区域
2. 重构PlanSheetList组件,优化排产单筛选与展示UI
3. 新增排产单附件上传、预览、重新上传功能
4. 优化排产单列表的筛选、分页与操作交互
2026-06-06 17:56:13 +08:00
7c87670896 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-06 17:15:40 +08:00
cd3cc85c0a feat: 合同导出弹窗新增导出行配置(合计行/大写金额行/备注行可选)
- 新增 rowConfigs 配置,支持控制合计行、大写金额行、备注行显隐
- 新增全选/半选逻辑,与列配置交互风格一致
- 导出 HTML 模板根据行配置动态渲染
2026-06-06 17:15:31 +08:00
d70bb77755 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-06 17:11:09 +08:00
b00db10a37 feat(aps): 添加排产文件字段支持
- 在 ApsPlanSheet 实体类中新增 apsUrl 字段用于存储排产文件路径
- 在 ApsPlanSheetBo 业务对象中添加 apsUrl 属性定义
- 更新 MyBatis 映射文件 ApsPlanSheetMapper.xml 添加字段映射
- 在 ApsPlanSheetVo 视图对象中增加 apsUrl 字段并配置 Excel 导出
- 为 deliveryWaybillDetail 查询添加按创建时间倒序排序功能
2026-06-06 17:10:59 +08:00
dbeb99d9e5 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-06 17:08:51 +08:00
1a2fc9852d feat: 新增考勤模板管理功能
- 后端新增 WmsAttendanceTemplate CRUD(Controller/Service/Mapper/Domain)
- 前端新增 attendanceTemplate API 对接
- 前端新增 AttendanceTemplateManager 组件(拖拽排序 + 模板编辑)
- 优化考勤 drag.vue 页面交互
2026-06-06 17:08:31 +08:00
7aaa59cee1 feat(wms): 添加钢卷长度厚度偏差自动告警功能
- 在IWmsMaterialWarningService接口中新增checkAndInsertWarnings方法定义
- 在WmsMaterialCoilServiceImpl中注入materialWarningService依赖
- 在钢卷新增、更新、拆分等操作后自动触发偏差检查和告警插入
- 实现doCheckAndInsertWarnings方法进行长度和厚度偏差计算
- 添加checkLength方法验证长度偏差是否超过10%
- 添加checkThickness方法验证厚度偏差包括偏薄ERROR和偏厚WARNING
- 实现批量插入告警记录并添加异常处理和日志记录
2026-06-06 16:24:35 +08:00
cbebd5b6d6 feat(wms): 添加钢卷通用告警功能
- 创建 WmsMaterialWarning 实体类定义告警数据结构
- 实现 IWmsMaterialWarningService 接口提供告警业务方法
- 开发 WmsMaterialWarningController 控制器支持增删改查操作
- 设计 WmsMaterialWarningBo 和 WmsMaterialWarningVo 数据传输对象
- 配置 WmsMaterialWarningMapper 数据访问层和 XML 映射文件
- 实现 WmsMaterialWarningServiceImpl 业务逻辑处理类
- 添加告警类型、级别、状态等字段支持长度/厚度/宽度维度监控
- 集成 Excel 导出功能便于告警数据统计分析
2026-06-06 15:52:29 +08:00
24a9784035 Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-06 15:24:16 +08:00
de7ec604dd fix(wms): 修复理论长度计算为空的问题
- 移除实际宽度比较条件,简化理论厚度计算判断逻辑
- 保持体积计算公式不变,仅调整条件判断流程
- 确保在缺少理论厚度且有实际长度时能正确计算厚度值
2026-06-06 15:23:50 +08:00
696f6d9ee0 fix(crm/contract): 修复合同状态更新调用错误的接口
移除了多余的created钩子中调用字典列表的代码,将更新合同状态的接口从updateContract改为updateOrder
2026-06-06 15:12:42 +08:00
050dd1a965 feat(crm): 合同含税总金额自动填入订单总金额 & 移除冗余页面
- feat(crm/contract): 含税总额变化后自动填写订单总金额(可配置开关)
- fix(crm/receive): 修复金额单位错误(万元→元);清理未使用导入
- fix(contract/product): 产品备注设置默认值
- chore: 移除已废弃的 OrderDashboard 组件和 finance/order 页面
- feat(wms/hrm): 新增考勤异常管理页面(attendanceAbnormal.vue)
- chore: 移除 trae git 提交规则配置
2026-06-06 13:01:38 +08:00
724c1dd16f refactor(order): 调整订单列表排序规则
- 移除状态排序逻辑
- 修改排序规则为合同号倒序排列
- 更新注释说明新的排序方式
- 保持置顶优先的排序策略不变
2026-06-06 12:58:12 +08:00
0e85153b3d chore(wms/order): 删除订单模块冗余的页面和组件文件 2026-06-06 11:44:26 +08:00
af728f8ea6 refactor(crm/contract): 抽取合同导出预览组件到独立文件 2026-06-06 10:49:02 +08:00
7e07b6f970 feat(wms/attendance-check): 新增异常考勤筛选功能
1. 在考勤审核查询条件中增加异常标识字段abnormal,用于筛选异常考勤记录
2. 在服务层实现异常筛选逻辑:当abnormal为true时,查询整体状态不为"normal"的考勤记录

调整前,考勤审核查询无法直接筛选异常考勤;调整后,支持通过abnormal字段快速过滤出异常状态的考勤记录,提升审核效率。
2026-06-06 10:13:41 +08:00
8a0f5e65bb feat(wms/attendance): add batch delete attendance schedule function
1. 修改删除排班接口为POST请求方式并调整接口路径为/wms/attendanceSchedule/remove,传递删除id数据
2. 在排班页面添加多选列和批量删除按钮,实现批量删除排班记录功能,包含选中校验、删除确认和操作反馈
2026-06-05 17:14:30 +08:00
1947a5c2d5 fix(wms/attendance-schedule): 调整批量删除接口参数类型与逻辑
1. 接口参数调整:将批量删除接口的路径参数从Long数组改为接收逗号分隔的字符串,并修改为@RequestBody接收
2. 服务层逻辑重构:将deleteWithValidByIds方法参数从Collection<Long>改为String,内部实现字符串解析与转换
3. 新增参数校验:在服务层添加字符串解析逻辑,过滤空值并转换为Long列表,避免空列表操作

调整前,批量删除依赖路径参数数组,存在URL长度限制且类型转换复杂;调整后,通过请求体接收字符串参数,服务层统一解析处理,提升接口健壮性与兼容性。
2026-06-05 16:46:23 +08:00
d8498728ee Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-05 15:51:31 +08:00
53e948b3e0 refactor(contractList): 移除旧的PDF导出逻辑,改用浏览器原生打印 2026-06-05 15:51:28 +08:00
3ebc0cb86a Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-05 11:07:33 +08:00
8059b0a0bb feat(wms/material-coil): 优化钢卷异常导出功能,支持动态表头与横向拼接
1. 重构异常导出逻辑:将原纵向展开(每个异常一行)改为横向拼接(每个钢卷一行),动态计算最大异常数并生成对应表头组
2. 移除冗余代码:删除原createExportVo方法和parseDateFromObject方法,简化导出结构
3. 调整数据格式:使用List<List<Object>>存储行数据,直接填充钢卷信息、改判原因及N组异常字段

调整前,导出文件为每个异常生成独立行,导致数据冗余且结构松散;调整后,每个钢卷仅占一行,异常信息横向拼接为动态列组,提升数据紧凑性与可读性,支持大规模异常数据导出。
2026-06-05 11:07:20 +08:00
1792196dc7 fix(wms/coil): 修复位置比较时的类型校验问题
将位置字段转为整数再进行大小比较,同时添加了调试日志用于排查异常数据问题
2026-06-05 11:05:32 +08:00
d8051abf8e feat(cost): 新增钢卷囤积成本统计页面及相关接口
新增了钢卷囤积成本统计的API接口,包括囤积统计和明细列表接口,同时新建了对应的页面页面,包含筛选查询、统计卡片、维度对比图表和明细表格功能,实现钢卷囤积成本的可视化管理。
2026-06-05 10:45:46 +08:00
5e0cb69bb8 feat(wms/coil): 为钢卷相关页面添加异常继承功能
本次修改在typing.vue、merge.vue、split.vue和stepSplit.vue四个钢卷相关页面中,新增了异常继承的完整功能:
1.  重构异常信息展示区域,添加继承标记样式
2.  新增继承异常按钮,打开异常选择弹窗
3.  实现从源钢卷拉取异常列表、批量选择继承异常的功能
4.  继承的异常会标记来源并使用特殊样式展示
2026-06-05 10:45:37 +08:00
37a69b563b Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-05 10:45:01 +08:00
66f0b3fdd7 fix(wms): 修复三处业务显示与逻辑不一致问题
1. 修复异常报表接口数据字段使用错误,将rows改为data
2. 调整标签渲染PDF的图片缩放和位置,避免内容超出页面
3. 修改考勤审核页面的请假天数列标题为请假小时,匹配实际展示数据
2026-06-05 10:44:56 +08:00
5e0dc848bb fix(wms-warehouse): 修复仓库页面容器高度溢出和导出二维码逻辑 2026-06-05 10:41:49 +08:00
a5323aea76 fix(crm/contract): 优化合同预览与导出功能
1.  隐藏打印预览按钮
2.  调整合同预览页面样式间距与logo位置
3.  修改合同金额字段保留小数位数为3位
4.  优化PDF导出分页逻辑,按空白行自动分页
2026-06-05 10:41:33 +08:00
cac747d158 fix(wms/material-coil): 移除钢卷查询中不必要的用户与异常统计关联
在WmsMaterialCoilMapper.xml的钢卷分页查询SQL中,移除了与sys_user表的左连接(通过sale_id关联)以及wms_coil_abnormal异常统计的子查询关联。调整前,查询包含冗余关联,可能影响性能且非必需;调整后,简化了SQL结构,提升查询效率。
2026-06-05 10:02:32 +08:00
705d929d6e feat(wms/material-coil): 优化钢卷囤积统计查询性能
1. 重构囤积统计方法:将原Java循环计算逻辑替换为单SQL聚合查询,通过JSON_EXTRACT解析二维码步骤创建时间,一次性计算平均囤积周期与成本
2. 移除原低效实现:删除getHoardingStatistics方法中的批量查询与循环解析代码,消除N+1性能问题
3. 新增Mapper方法与XML映射:添加selectHoardingStatistics接口及对应SQL,支持与分页查询相同的条件筛选

调整前,统计需先查询钢卷列表再批量获取二维码并循环解析,存在性能瓶颈;调整后,通过单SQL完成所有聚合计算,大幅提升查询效率,支持大规模数据统计。
2026-06-04 17:06:08 +08:00
29c21fd64f Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-04 15:46:02 +08:00
5236500f04 feat(wms/material-coil): 新增钢卷囤积统计与二维码详情查询功能
1. 新增囤积统计接口:计算已发货钢卷的平均囤积周期和平均囤积成本
   - 囤积周期 = 发货时间 - 二维码第一步创建时间
   - 囤积成本 = 囤积天数 × 钢卷净重 × 1元/吨/天
   - 支持与分页列表相同的查询条件筛选

2. 新增二维码详情查询接口:在分页查询基础上填充完整的二维码记录信息
   - 前端可通过 qrcodeRecord.content 获取二维码JSON内容
   - 采用批量查询避免N+1性能问题

调整前,钢卷查询无法获取二维码详细内容,也无法统计囤积相关指标;调整后,支持二维码内容查看和囤积成本分析,为仓储成本核算提供数据支持。
2026-06-04 15:45:51 +08:00
600867f386 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-04 14:28:38 +08:00
8183bae824 fix(crm): 统一销售金额单位为元并优化金额精度
1. 修改客户等级图表、销售报告页面的金额单位从万元改为元
2. 将金额计算和展示的精度从两位小数调整为三位小数
3. 新增合同默认编码和签订地点的默认值
2026-06-04 14:28:33 +08:00
37d6830947 fix(wms/delivery): 清除运单明细查询中的时间条件干扰
在WmsDeliveryWaybillDetailController的运单明细查询方法中,startTime/endTime参数已用于运单delivery_time筛选。为避免其被误用作钢卷update_time的查询条件,在查询前将bo中的startTime和endTime字段显式置为null。调整前,时间条件可能干扰钢卷维度的查询结果;调整后,确保运单交付时间筛选与钢卷更新时间筛选互不干扰,提升查询准确性。
2026-06-04 14:09:25 +08:00
c71dfe3ff2 feat(wms/coil): 新增钢卷异常管理相关页面与功能
1. 新增钢卷异常列表基础页、明细页、钢卷维度异常页和继承扩展页
2. 在异常管理表格中新增继承来源列
3. 完善异常增删改查、判级以及继承功能
2026-06-04 13:36:01 +08:00
ff139759d4 feat(wms/coil/abnormal): 新增钢卷异常记录的父异常ID字段
在WmsCoilAbnormal实体及相关业务对象中新增parentAbnormalId字段,用于记录异常继承关系。调整涉及数据库映射、Java实体类、业务对象、查询条件及导出映射。调整前,异常记录缺少父异常关联信息;调整后,支持按父异常ID进行筛选与关联追溯,提升异常链分析能力。
2026-06-04 13:19:33 +08:00
5176c80344 refactor(mes/wms): 优化多处日期处理与表格列展示
1. 移除磨工页面字典表格的"值"列
2. 修复TimeInput组件日期格式化逻辑,补全月份日期补零处理
3. 为卷料录入页面添加日期格式化方法,替换直接赋值逻辑并新增生产时长计算
2026-06-04 11:10:34 +08:00
31f7a9c0cb Merge remote-tracking branch 'origin/0.8.X' into 0.8.X 2026-06-04 10:59:17 +08:00
9d208770d8 feat(service): 添加按热卷号查询计划详情功能
- 在 SqlServerApiBusinessService 中实现按热卷号查询计划详情方法
- 新增调用查询扩展卷数据接口并整合到返回结果中
- 修改 PlanDetailView 构造函数以支持扩展卷数据列表
- 添加 excoilRows 属性和相应的 getter 方法
- 提供新的 fromExecuteSqlResponse 静态工厂方法处理双响应对象
- 在 SqlServerApiClient 中新增 queryExcoilByHotCoilId 查询接口
2026-06-04 10:59:07 +08:00
31d8d1ee16 feat: 多个页面优化与功能增强
1. 磨削页面:添加操作人权限控制,自动填充上次硬度值,移除字典值字段
2. 质保书页面:新增质保书类型筛选与表单字段,移除模板选择弹窗
3. 成本综合页面:添加产线校验、录入/查看切换、表格列控制与快捷操作
4. 质保书条目页面:新增类型筛选与表单字段,移除模板选择弹窗
2026-06-04 10:26:09 +08:00
b4fbb8dfc8 feat(qc/certificate): 新增证书类型字段
在QcCertificate实体及相关业务对象中新增certificateType字段,用于标识出厂合格证、检测报告、质保书等证书类型。调整涉及数据库映射、查询条件及导出映射。调整前,证书记录缺少类型分类;调整后,支持按证书类型进行筛选与统计,提升证书管理能力。
2026-06-03 17:21:12 +08:00
40ebca2573 feat(mes/eqp/check): add inspector summary statistics table
新增按实际巡检人维度的巡检汇总统计表格,展示巡检人、巡检次数、通过/不通过数量及通过率
2026-06-03 16:59:03 +08:00
ec08a360a0 feat(qc/inspection): 新增检验任务方案选择的公司和默认选中参数
1.  给SchemeSelect组件新增company和scheme两个props
2.  组件内新增模板单位查询参数并关联传入的company值
3.  组件挂载/重置时自动匹配并选中传入的默认方案
4.  同步更新表单内的归属公司和任务类型字段初始化
2026-06-03 16:54:37 +08:00
977ea2b021 refactor(wms/report): 移除actionIds相关导出逻辑 2026-06-03 16:44:44 +08:00
e507887a27 Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X 2026-06-03 16:31:54 +08:00
12a887e074 refactor(wms-report): 统一报表页面模板,提取公共逻辑为action-template
1.  将merge、repair下的多个报表页面重构为使用action-template组件
2.  提取自定义导出功能为公共组件CustomExport并复用至receive.vue和action-template
3.  统一报表页面的查询、导出、列配置等公共逻辑
2026-06-03 16:31:51 +08:00
366 changed files with 31682 additions and 13754 deletions

View File

@@ -1,9 +0,0 @@
---
alwaysApply: true
scene: git_message
---
使用中文编写提交信息, 提交信息格式为:
```
<type>(<scope>): <subject>
```

View File

@@ -129,6 +129,10 @@
<artifactId>klp-cost</artifactId>
</dependency>
<dependency>
<groupId>com.klp</groupId>
<artifactId>klp-flow</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -361,6 +361,15 @@ public class SqlServerApiClient {
);
}
public ExecuteSqlResponse queryExcoilByHotCoilId(String hotCoilId) {
return executeSql(
"oracle",
"select * from JXPLTCM.PLTCM_PDO_EXCOIL where HOT_COILID = :hotCoilId",
singletonParam("hotCoilId", hotCoilId)
);
}
public ExecuteSqlResponse queryPlanListByHotCoilIdLike(String hotCoilId, int page, int pageSize) {
int endRow = page * pageSize;
int startRow = endRow - pageSize;

View File

@@ -122,7 +122,10 @@ public class SqlServerApiBusinessService {
* 计划详情:按热卷号查询。
*/
public PlanDetailView getPlanByHotCoilId(String hotCoilId) {
return PlanDetailView.fromExecuteSqlResponse(hotCoilId, client.queryPlanByHotCoilId(hotCoilId));
SqlServerApiClient.ExecuteSqlResponse planResponse = client.queryPlanByHotCoilId(hotCoilId);
SqlServerApiClient.ExecuteSqlResponse excoilResponse = null;
excoilResponse = client.queryExcoilByHotCoilId(hotCoilId);
return PlanDetailView.fromExecuteSqlResponse(hotCoilId, planResponse, excoilResponse);
}
/**
@@ -421,11 +424,13 @@ public class SqlServerApiBusinessService {
private final String coilId;
private final List<Map<String, Object>> rows;
private final Map<String, Object> firstRow;
private final List<Map<String, Object>> excoilRows;
public PlanDetailView(String coilId, List<Map<String, Object>> rows, Map<String, Object> firstRow) {
public PlanDetailView(String coilId, List<Map<String, Object>> rows, Map<String, Object> firstRow, List<Map<String, Object>> excoilRows) {
this.coilId = coilId;
this.rows = rows;
this.firstRow = firstRow;
this.excoilRows = excoilRows;
}
public String getCoilId() {
@@ -440,10 +445,21 @@ public class SqlServerApiBusinessService {
return firstRow;
}
public List<Map<String, Object>> getExcoilRows() {
return excoilRows;
}
public static PlanDetailView fromExecuteSqlResponse(String coilId, SqlServerApiClient.ExecuteSqlResponse response) {
List<Map<String, Object>> rows = asRowList(response);
Map<String, Object> firstRow = rows.isEmpty() ? Collections.<String, Object>emptyMap() : rows.get(0);
return new PlanDetailView(coilId, rows, firstRow);
return new PlanDetailView(coilId, rows, firstRow, Collections.<Map<String, Object>>emptyList());
}
public static PlanDetailView fromExecuteSqlResponse(String coilId, SqlServerApiClient.ExecuteSqlResponse response, SqlServerApiClient.ExecuteSqlResponse excoilResponse) {
List<Map<String, Object>> rows = asRowList(response);
Map<String, Object> firstRow = rows.isEmpty() ? Collections.<String, Object>emptyMap() : rows.get(0);
List<Map<String, Object>> excoilRows = asRowList(excoilResponse);
return new PlanDetailView(coilId, rows, firstRow, excoilRows);
}
}

View File

@@ -52,6 +52,11 @@ public class ApsPlanSheetBo extends BaseEntity {
*/
private String planType;
/**
* 排产文件
*/
private String apsUrl;
/**
* 排产人
*/

View File

@@ -49,6 +49,10 @@ public class ApsPlanSheet extends BaseEntity {
* 排产类型
*/
private String planType;
/**
* 排产文件
*/
private String apsUrl;
/**
* 排产人
*/

View File

@@ -60,6 +60,12 @@ public class ApsPlanSheetVo {
@ExcelProperty(value = "排产类型")
private String planType;
/**
* 排产文件
*/
@ExcelProperty(value = "排产文件")
private String apsUrl;
/**
* 排产人
*/

View File

@@ -11,6 +11,7 @@
<result property="lineName" column="line_name"/>
<result property="planCode" column="plan_code"/>
<result property="planType" column="plan_type"/>
<result property="apsUrl" column="aps_url"/>
<result property="scheduler" column="scheduler"/>
<result property="remark" column="remark"/>
<result property="delFlag" column="del_flag"/>
@@ -27,6 +28,7 @@
s.line_name AS lineName,
s.plan_code AS planCode,
s.plan_type AS planType,
s.aps_url AS apsUrl,
s.scheduler AS scheduler,
s.remark AS masterRemark,
d.remark AS detailRemark,

View File

@@ -0,0 +1,109 @@
package com.klp.cost.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.cost.domain.vo.CostProdMetricResultVo;
import com.klp.cost.domain.bo.CostProdMetricResultBo;
import com.klp.cost.service.ICostProdMetricResultService;
import com.klp.common.core.page.TableDataInfo;
/**
* 生产指标计算结果
*
* @author klp
* @date 2026-06-17
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/cost/prodMetricResult")
public class CostProdMetricResultController extends BaseController {
private final ICostProdMetricResultService iCostProdMetricResultService;
/**
* 查询生产指标计算结果列表
*/
@GetMapping("/list")
public TableDataInfo<CostProdMetricResultVo> list(CostProdMetricResultBo bo, PageQuery pageQuery) {
return iCostProdMetricResultService.queryPageList(bo, pageQuery);
}
/**
* 导出生产指标计算结果列表
*/
@Log(title = "生产指标计算结果", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(CostProdMetricResultBo bo, HttpServletResponse response) {
List<CostProdMetricResultVo> list = iCostProdMetricResultService.queryList(bo);
ExcelUtil.exportExcel(list, "生产指标计算结果", CostProdMetricResultVo.class, response);
}
/**
* 获取生产指标计算结果详细信息
*
* @param resultId 主键
*/
@GetMapping("/{resultId}")
public R<CostProdMetricResultVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long resultId) {
return R.ok(iCostProdMetricResultService.queryById(resultId));
}
/**
* 新增生产指标计算结果
*/
@Log(title = "生产指标计算结果", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody CostProdMetricResultBo bo) {
return toAjax(iCostProdMetricResultService.insertByBo(bo));
}
/**
* 批量保存生产指标计算结果(先删除再插入)
*/
@Log(title = "生产指标计算结果", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/batch")
public R<Void> batchSave(@RequestBody CostProdMetricResultBo bo) {
return toAjax(iCostProdMetricResultService.batchSaveWithDelete(bo));
}
/**
* 修改生产指标计算结果
*/
@Log(title = "生产指标计算结果", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody CostProdMetricResultBo bo) {
return toAjax(iCostProdMetricResultService.updateByBo(bo));
}
/**
* 删除生产指标计算结果
*
* @param resultIds 主键串
*/
@Log(title = "生产指标计算结果", businessType = BusinessType.DELETE)
@DeleteMapping("/{resultIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] resultIds) {
return toAjax(iCostProdMetricResultService.deleteWithValidByIds(Arrays.asList(resultIds), true));
}
}

View File

@@ -42,13 +42,21 @@ public class CostProdMetric extends BaseEntity {
*/
private String metricFormula;
/**
* 指标计算结果值
* 单价
*/
private BigDecimal metricValue;
/**
* 是否使用单价 0=否 1=是
*/
private Integer usePrice;
/**
* 备注
*/
private String remark;
/**
* 标签
*/
private String tags;
/**
* 删除标识 0=正常 2=删除
*/

View File

@@ -0,0 +1,60 @@
package com.klp.cost.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 生产指标计算结果对象 cost_prod_metric_result
*
* @author klp
* @date 2026-06-17
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("cost_prod_metric_result")
public class CostProdMetricResult extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 主键ID
*/
@TableId(value = "result_id")
private Long resultId;
/**
* 报表ID关联生产日报
*/
private Long reportId;
/**
* 指标ID关联cost_prod_metric
*/
private Long metricId;
/**
* 计算日期
*/
private Date metricDate;
/**
* 班组
*/
private String teamGroup;
/**
* 计算值
*/
private BigDecimal calcValue;
/**
* 标签
*/
private String tags;
/**
* 删除标识 0=正常 2=删除
*/
@TableLogic
private Long delFlag;
}

View File

@@ -44,14 +44,23 @@ public class CostProdMetricBo extends BaseEntity {
private String metricFormula;
/**
* 指标计算结果值
* 单价
*/
private BigDecimal metricValue;
/**
* 是否使用单价 0=否 1=是
*/
private Integer usePrice;
/**
* 备注
*/
private String remark;
/**
* 标签
*/
private String tags;
}

View File

@@ -0,0 +1,72 @@
package com.klp.cost.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;
/**
* 生产指标计算结果业务对象 cost_prod_metric_result
*
* @author klp
* @date 2026-06-17
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class CostProdMetricResultBo extends BaseEntity {
/**
* 主键ID
*/
private Long resultId;
/**
* 报表ID关联生产日报
*/
private Long reportId;
/**
* 指标ID关联cost_prod_metric
*/
private Long metricId;
/**
* 计算日期
*/
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date metricDate;
/**
* 班组
*/
private String teamGroup;
/**
* 计算值
*/
private BigDecimal calcValue;
/**
* 标签
*/
private String tags;
/**
* 要删除的主键ID集合
*/
private List<Long> resultIds;
/**
* 要批量插入的数据集合
*/
private List<CostProdMetricResultBo> prodMetricResultList;
}

View File

@@ -0,0 +1,70 @@
package com.klp.cost.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;
/**
* 生产指标计算结果视图对象 cost_prod_metric_result
*
* @author klp
* @date 2026-06-17
*/
@Data
@ExcelIgnoreUnannotated
public class CostProdMetricResultVo {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long resultId;
/**
* 报表ID关联生产日报
*/
@ExcelProperty(value = "报表ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "关=联生产日报")
private Long reportId;
/**
* 指标ID关联cost_prod_metric
*/
@ExcelProperty(value = "指标ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "关=联cost_prod_metric")
private Long metricId;
/**
* 计算日期
*/
@ExcelProperty(value = "计算日期")
private Date metricDate;
/**
* 班组
*/
@ExcelProperty(value = "班组")
private String teamGroup;
/**
* 计算值
*/
@ExcelProperty(value = "计算值")
private BigDecimal calcValue;
/**
* 标签
*/
@ExcelProperty(value = "标签")
private String tags;
}

View File

@@ -52,16 +52,27 @@ public class CostProdMetricVo {
private String metricFormula;
/**
* 指标计算结果值
* 单价
*/
@ExcelProperty(value = "指标计算结果值")
@ExcelProperty(value = "单价")
private BigDecimal metricValue;
/**
* 是否使用单价 0=否 1=是
*/
@ExcelProperty(value = "是否使用单价")
private Integer usePrice;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 标签
*/
@ExcelProperty(value = "标签")
private String tags;
}

View File

@@ -0,0 +1,15 @@
package com.klp.cost.mapper;
import com.klp.cost.domain.CostProdMetricResult;
import com.klp.cost.domain.vo.CostProdMetricResultVo;
import com.klp.common.core.mapper.BaseMapperPlus;
/**
* 生产指标计算结果Mapper接口
*
* @author klp
* @date 2026-06-17
*/
public interface CostProdMetricResultMapper extends BaseMapperPlus<CostProdMetricResultMapper, CostProdMetricResult, CostProdMetricResultVo> {
}

View File

@@ -0,0 +1,54 @@
package com.klp.cost.service;
import com.klp.cost.domain.CostProdMetricResult;
import com.klp.cost.domain.vo.CostProdMetricResultVo;
import com.klp.cost.domain.bo.CostProdMetricResultBo;
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-06-17
*/
public interface ICostProdMetricResultService {
/**
* 查询生产指标计算结果
*/
CostProdMetricResultVo queryById(Long resultId);
/**
* 查询生产指标计算结果列表
*/
TableDataInfo<CostProdMetricResultVo> queryPageList(CostProdMetricResultBo bo, PageQuery pageQuery);
/**
* 查询生产指标计算结果列表
*/
List<CostProdMetricResultVo> queryList(CostProdMetricResultBo bo);
/**
* 新增生产指标计算结果
*/
Boolean insertByBo(CostProdMetricResultBo bo);
/**
* 修改生产指标计算结果
*/
Boolean updateByBo(CostProdMetricResultBo bo);
/**
* 校验并批量删除生产指标计算结果信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 批量保存生产指标计算结果(先删除再插入)
*/
Boolean batchSaveWithDelete(CostProdMetricResultBo bo);
}

View File

@@ -0,0 +1,135 @@
package com.klp.cost.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
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 org.springframework.transaction.annotation.Transactional;
import com.klp.cost.domain.bo.CostProdMetricResultBo;
import com.klp.cost.domain.vo.CostProdMetricResultVo;
import com.klp.cost.domain.CostProdMetricResult;
import com.klp.cost.mapper.CostProdMetricResultMapper;
import com.klp.cost.service.ICostProdMetricResultService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.stream.Collectors;
/**
* 生产指标计算结果Service业务层处理
*
* @author klp
* @date 2026-06-17
*/
@RequiredArgsConstructor
@Service
public class CostProdMetricResultServiceImpl implements ICostProdMetricResultService {
private final CostProdMetricResultMapper baseMapper;
/**
* 查询生产指标计算结果
*/
@Override
public CostProdMetricResultVo queryById(Long resultId){
return baseMapper.selectVoById(resultId);
}
/**
* 查询生产指标计算结果列表
*/
@Override
public TableDataInfo<CostProdMetricResultVo> queryPageList(CostProdMetricResultBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<CostProdMetricResult> lqw = buildQueryWrapper(bo);
Page<CostProdMetricResultVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询生产指标计算结果列表
*/
@Override
public List<CostProdMetricResultVo> queryList(CostProdMetricResultBo bo) {
LambdaQueryWrapper<CostProdMetricResult> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<CostProdMetricResult> buildQueryWrapper(CostProdMetricResultBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<CostProdMetricResult> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getReportId() != null, CostProdMetricResult::getReportId, bo.getReportId());
lqw.eq(bo.getMetricId() != null, CostProdMetricResult::getMetricId, bo.getMetricId());
lqw.eq(bo.getMetricDate() != null, CostProdMetricResult::getMetricDate, bo.getMetricDate());
lqw.eq(StringUtils.isNotBlank(bo.getTeamGroup()), CostProdMetricResult::getTeamGroup, bo.getTeamGroup());
lqw.eq(bo.getCalcValue() != null, CostProdMetricResult::getCalcValue, bo.getCalcValue());
lqw.eq(StringUtils.isNotBlank(bo.getTags()), CostProdMetricResult::getTags, bo.getTags());
return lqw;
}
/**
* 新增生产指标计算结果
*/
@Override
public Boolean insertByBo(CostProdMetricResultBo bo) {
CostProdMetricResult add = BeanUtil.toBean(bo, CostProdMetricResult.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setResultId(add.getResultId());
}
return flag;
}
/**
* 修改生产指标计算结果
*/
@Override
public Boolean updateByBo(CostProdMetricResultBo bo) {
CostProdMetricResult update = BeanUtil.toBean(bo, CostProdMetricResult.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(CostProdMetricResult entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除生产指标计算结果
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 批量保存(先删除再插入)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean batchSaveWithDelete(CostProdMetricResultBo bo) {
if (CollUtil.isNotEmpty(bo.getProdMetricResultList())) {
if (CollUtil.isNotEmpty(bo.getResultIds())) {
baseMapper.deleteBatchIds(bo.getResultIds());
}
List<CostProdMetricResult> list = bo.getProdMetricResultList().stream()
.map(item -> BeanUtil.toBean(item, CostProdMetricResult.class))
.collect(Collectors.toList());
return baseMapper.insertBatch(list);
}
return false;
}
}

View File

@@ -66,6 +66,8 @@ public class CostProdMetricServiceImpl implements ICostProdMetricService {
lqw.like(StringUtils.isNotBlank(bo.getMetricName()), CostProdMetric::getMetricName, bo.getMetricName());
lqw.eq(StringUtils.isNotBlank(bo.getMetricFormula()), CostProdMetric::getMetricFormula, bo.getMetricFormula());
lqw.eq(bo.getMetricValue() != null, CostProdMetric::getMetricValue, bo.getMetricValue());
lqw.eq(bo.getUsePrice() != null, CostProdMetric::getUsePrice, bo.getUsePrice());
lqw.like(StringUtils.isNotBlank(bo.getTags()), CostProdMetric::getTags, bo.getTags());
return lqw;
}

View File

@@ -71,7 +71,10 @@ public class CostProdReportServiceImpl implements ICostProdReportService {
lqw.eq(StringUtils.isNotBlank(bo.getLineType()), CostProdReport::getLineType, bo.getLineType());
lqw.eq(bo.getInputWeight() != null, CostProdReport::getInputWeight, bo.getInputWeight());
lqw.eq(bo.getOutputWeight() != null, CostProdReport::getOutputWeight, bo.getOutputWeight());
lqw.apply(bo.getReportDate() != null, "DATE_FORMAT(report_date, '%Y-%m') = {0}", bo.getReportDate());
if (bo.getReportDate() != null) {
String monthStr = new java.text.SimpleDateFormat("yyyy-MM").format(bo.getReportDate());
lqw.apply("DATE_FORMAT(report_date, '%Y-%m') = {0}", monthStr);
}
return lqw;
}

View File

@@ -11,7 +11,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="metricName" column="metric_name"/>
<result property="metricFormula" column="metric_formula"/>
<result property="metricValue" column="metric_value"/>
<result property="usePrice" column="use_price"/>
<result property="remark" column="remark"/>
<result property="tags" column="tags"/>
<result property="delFlag" column="del_flag"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>

View File

@@ -0,0 +1,23 @@
<?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.cost.mapper.CostProdMetricResultMapper">
<resultMap type="com.klp.cost.domain.CostProdMetricResult" id="CostProdMetricResultResult">
<result property="resultId" column="result_id"/>
<result property="reportId" column="report_id"/>
<result property="metricId" column="metric_id"/>
<result property="metricDate" column="metric_date"/>
<result property="teamGroup" column="team_group"/>
<result property="calcValue" column="calc_value"/>
<result property="tags" column="tags"/>
<result property="delFlag" column="del_flag"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
</resultMap>
</mapper>

View File

@@ -12,4 +12,9 @@ import com.klp.common.core.mapper.BaseMapperPlus;
*/
public interface CrmCustomerMapper extends BaseMapperPlus<CrmCustomerMapper, CrmCustomer, CrmCustomerVo> {
/**
* 查询当前最大的customer_code用于自动生成新编码
*/
String selectMaxCustomerCode();
}

View File

@@ -91,6 +91,25 @@ public class CrmCustomerServiceImpl implements ICrmCustomerService {
@Override
public Boolean insertByBo(CrmCustomerBo bo) {
CrmCustomer add = BeanUtil.toBean(bo, CrmCustomer.class);
// 自动生成customer_code查询最大编码并加1
if (StringUtils.isBlank(add.getCustomerCode())) {
String maxCode = baseMapper.selectMaxCustomerCode();
if (StringUtils.isBlank(maxCode)) {
add.setCustomerCode("00001");
} else {
// 提取末尾数字后缀并递增,支持纯数字("00001")和带前缀("KH00001")两种格式
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("^(.*?)(\\d+)$");
java.util.regex.Matcher matcher = pattern.matcher(maxCode);
if (matcher.matches()) {
String prefix = matcher.group(1);
String numStr = matcher.group(2);
long num = Long.parseLong(numStr) + 1;
add.setCustomerCode(prefix + String.format("%0" + numStr.length() + "d", num));
} else {
add.setCustomerCode(maxCode + "1");
}
}
}
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {

View File

@@ -250,11 +250,9 @@ public class CrmOrderServiceImpl implements ICrmOrderService {
qw.eq("co.del_flag", 0);
//排序规则:
// 1. 置顶优先 (is_top=1 排在前面)
// 2. 状态为1(已生效)的排在前
// 3. 创建时间倒序
// 2. 合同号倒序KLPY+年月日+序号,降序最新在前
qw.orderByDesc("co.is_top")
.orderByDesc("CASE WHEN co.status = 1 THEN 1 ELSE 0 END")
.orderByDesc("co.create_time");
.orderByDesc("co.contract_code");
return qw;
}

View File

@@ -23,5 +23,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="delFlag" column="del_flag"/>
</resultMap>
<select id="selectMaxCustomerCode" resultType="String">
SELECT customer_code FROM crm_customer WHERE del_flag = 0 ORDER BY LENGTH(customer_code) DESC, customer_code DESC LIMIT 1
</select>
</mapper>

19
klp-flow/pom.xml Normal file
View File

@@ -0,0 +1,19 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.klp</groupId>
<artifactId>klp-oa</artifactId>
<version>0.8.3</version>
</parent>
<artifactId>klp-flow</artifactId>
<name>klp-flow</name>
<description>流程管理模块</description>
<dependencies>
<dependency>
<groupId>com.klp</groupId>
<artifactId>klp-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,99 @@
package com.klp.flow.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.flow.domain.vo.TsAcceptCoilRelVo;
import com.klp.flow.domain.bo.TsAcceptCoilRelBo;
import com.klp.flow.service.ITsAcceptCoilRelService;
import com.klp.common.core.page.TableDataInfo;
/**
* 受理单关联钢卷中间
*
* @author klp
* @date 2026-06-18
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/flow/acceptCoilRel")
public class TsAcceptCoilRelController extends BaseController {
private final ITsAcceptCoilRelService iTsAcceptCoilRelService;
/**
* 查询受理单关联钢卷中间列表
*/
@GetMapping("/list")
public TableDataInfo<TsAcceptCoilRelVo> list(TsAcceptCoilRelBo bo, PageQuery pageQuery) {
return iTsAcceptCoilRelService.queryPageList(bo, pageQuery);
}
/**
* 导出受理单关联钢卷中间列表
*/
@Log(title = "受理单关联钢卷中间", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(TsAcceptCoilRelBo bo, HttpServletResponse response) {
List<TsAcceptCoilRelVo> list = iTsAcceptCoilRelService.queryList(bo);
ExcelUtil.exportExcel(list, "受理单关联钢卷中间", TsAcceptCoilRelVo.class, response);
}
/**
* 获取受理单关联钢卷中间详细信息
*
* @param relId 主键
*/
@GetMapping("/{relId}")
public R<TsAcceptCoilRelVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long relId) {
return R.ok(iTsAcceptCoilRelService.queryById(relId));
}
/**
* 新增受理单关联钢卷中间
*/
@Log(title = "受理单关联钢卷中间", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody TsAcceptCoilRelBo bo) {
return toAjax(iTsAcceptCoilRelService.insertByBo(bo));
}
/**
* 修改受理单关联钢卷中间
*/
@Log(title = "受理单关联钢卷中间", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody TsAcceptCoilRelBo bo) {
return toAjax(iTsAcceptCoilRelService.updateByBo(bo));
}
/**
* 删除受理单关联钢卷中间
*
* @param relIds 主键串
*/
@Log(title = "受理单关联钢卷中间", businessType = BusinessType.DELETE)
@DeleteMapping("/{relIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] relIds) {
return toAjax(iTsAcceptCoilRelService.deleteWithValidByIds(Arrays.asList(relIds), true));
}
}

View File

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

View File

@@ -0,0 +1,99 @@
package com.klp.flow.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.flow.domain.vo.TsComplaintTaskVo;
import com.klp.flow.domain.bo.TsComplaintTaskBo;
import com.klp.flow.service.ITsComplaintTaskService;
import com.klp.common.core.page.TableDataInfo;
/**
* 各部门投诉代办任务&意见
*
* @author klp
* @date 2026-06-18
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/flow/complaintTask")
public class TsComplaintTaskController extends BaseController {
private final ITsComplaintTaskService iTsComplaintTaskService;
/**
* 查询各部门投诉代办任务&意见列表
*/
@GetMapping("/list")
public TableDataInfo<TsComplaintTaskVo> list(TsComplaintTaskBo bo, PageQuery pageQuery) {
return iTsComplaintTaskService.queryPageList(bo, pageQuery);
}
/**
* 导出各部门投诉代办任务&意见列表
*/
@Log(title = "各部门投诉代办任务&意见", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(TsComplaintTaskBo bo, HttpServletResponse response) {
List<TsComplaintTaskVo> list = iTsComplaintTaskService.queryList(bo);
ExcelUtil.exportExcel(list, "各部门投诉代办任务&意见", TsComplaintTaskVo.class, response);
}
/**
* 获取各部门投诉代办任务&意见详细信息
*
* @param taskId 主键
*/
@GetMapping("/{taskId}")
public R<TsComplaintTaskVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long taskId) {
return R.ok(iTsComplaintTaskService.queryById(taskId));
}
/**
* 新增各部门投诉代办任务&意见
*/
@Log(title = "各部门投诉代办任务&意见", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody TsComplaintTaskBo bo) {
return toAjax(iTsComplaintTaskService.insertByBo(bo));
}
/**
* 修改各部门投诉代办任务&意见
*/
@Log(title = "各部门投诉代办任务&意见", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody TsComplaintTaskBo bo) {
return toAjax(iTsComplaintTaskService.updateByBo(bo));
}
/**
* 删除各部门投诉代办任务&意见
*
* @param taskIds 主键串
*/
@Log(title = "各部门投诉代办任务&意见", businessType = BusinessType.DELETE)
@DeleteMapping("/{taskIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] taskIds) {
return toAjax(iTsComplaintTaskService.deleteWithValidByIds(Arrays.asList(taskIds), true));
}
}

View File

@@ -0,0 +1,99 @@
package com.klp.flow.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.flow.domain.vo.TsPlanExecuteRelVo;
import com.klp.flow.domain.bo.TsPlanExecuteRelBo;
import com.klp.flow.service.ITsPlanExecuteRelService;
import com.klp.common.core.page.TableDataInfo;
/**
* 最终方案下发部门及执行反馈
*
* @author klp
* @date 2026-06-18
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/flow/planExecuteRel")
public class TsPlanExecuteRelController extends BaseController {
private final ITsPlanExecuteRelService iTsPlanExecuteRelService;
/**
* 查询最终方案下发部门及执行反馈列表
*/
@GetMapping("/list")
public TableDataInfo<TsPlanExecuteRelVo> list(TsPlanExecuteRelBo bo, PageQuery pageQuery) {
return iTsPlanExecuteRelService.queryPageList(bo, pageQuery);
}
/**
* 导出最终方案下发部门及执行反馈列表
*/
@Log(title = "最终方案下发部门及执行反馈", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(TsPlanExecuteRelBo bo, HttpServletResponse response) {
List<TsPlanExecuteRelVo> list = iTsPlanExecuteRelService.queryList(bo);
ExcelUtil.exportExcel(list, "最终方案下发部门及执行反馈", TsPlanExecuteRelVo.class, response);
}
/**
* 获取最终方案下发部门及执行反馈详细信息
*
* @param relId 主键
*/
@GetMapping("/{relId}")
public R<TsPlanExecuteRelVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long relId) {
return R.ok(iTsPlanExecuteRelService.queryById(relId));
}
/**
* 新增最终方案下发部门及执行反馈
*/
@Log(title = "最终方案下发部门及执行反馈", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody TsPlanExecuteRelBo bo) {
return toAjax(iTsPlanExecuteRelService.insertByBo(bo));
}
/**
* 修改最终方案下发部门及执行反馈
*/
@Log(title = "最终方案下发部门及执行反馈", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody TsPlanExecuteRelBo bo) {
return toAjax(iTsPlanExecuteRelService.updateByBo(bo));
}
/**
* 删除最终方案下发部门及执行反馈
*
* @param relIds 主键串
*/
@Log(title = "最终方案下发部门及执行反馈", businessType = BusinessType.DELETE)
@DeleteMapping("/{relIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] relIds) {
return toAjax(iTsPlanExecuteRelService.deleteWithValidByIds(Arrays.asList(relIds), true));
}
}

View File

@@ -0,0 +1,45 @@
package com.klp.flow.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 受理单关联钢卷中间对象 ts_accept_coil_rel
*
* @author klp
* @date 2026-06-18
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("ts_accept_coil_rel")
public class TsAcceptCoilRel extends BaseEntity {
private static final long serialVersionUID=1L;
/**
*
*/
@TableId(value = "rel_id")
private Long relId;
/**
* 投诉受理单ID
*/
private Long acceptId;
/**
* 钢卷ID
*/
private Long coilId;
/**
* 备注
*/
private String remark;
/**
* 删除标识 0=正常 2=删除
*/
@TableLogic
private Long delFlag;
}

View File

@@ -0,0 +1,88 @@
package com.klp.flow.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;
/**
* 投诉受理单主对象 ts_complaint_accept
*
* @author klp
* @date 2026-06-18
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("ts_complaint_accept")
public class TsComplaintAccept extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 受理单主键
*/
@TableId(value = "accept_id")
private Long acceptId;
/**
* 投诉编号 TS-2026-001
*/
private String complaintNo;
/**
* 投诉日期
*/
private Date complaintDate;
/**
* 投诉情况描述
*/
private String complaintContent;
/**
* 客户诉求
*/
private String customerDemand;
/**
* 客户照片凭证等
*/
private String file;
/**
* 审核状态 0待审核 1已通过 2未通过
*/
private Long auditStatus;
/**
* 审核意见
*/
private String auditOpinion;
/**
* 审核人ID
*/
private Long auditUserId;
/**
* 审核时间
*/
private Date auditTime;
/**
* 流程阶段:
1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=方案下发执行反馈中 5=全部办结
*/
private Long flowStatus;
/**
* 总负责人ID
*/
private Long principalUserId;
/**
* 总负责人整合后的完整处理方案
*/
private String planContent;
/**
* 备注
*/
private String remark;
/**
* 删除标识 0=正常 2=删除
*/
@TableLogic
private Long delFlag;
}

View File

@@ -0,0 +1,71 @@
package com.klp.flow.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;
/**
* 各部门投诉代办任务&意见对象 ts_complaint_task
*
* @author klp
* @date 2026-06-18
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("ts_complaint_task")
public class TsComplaintTask extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 代办任务ID
*/
@TableId(value = "task_id")
private Long taskId;
/**
* 关联投诉受理单ID
*/
private Long acceptId;
/**
* 负责部门ID销售/质量/生产)
*/
private Long deptId;
/**
* 任务状态 0待填写意见 1已完成填写
*/
private Long taskStatus;
/**
* 意见单号
*/
private String fillNo;
/**
* 部门处理意见
*/
private String deptOpinion;
/**
* 填写意见的部门员工ID
*/
private Long fillUserId;
/**
* 意见填写时间
*/
private Date fillTime;
/**
* 意见文件
*/
private String fillFile;
/**
* 备注
*/
private String remark;
/**
* 删除标识 0=正常 2=删除
*/
@TableLogic
private Long delFlag;
}

View File

@@ -0,0 +1,71 @@
package com.klp.flow.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;
/**
* 最终方案下发部门及执行反馈对象 ts_plan_execute_rel
*
* @author klp
* @date 2026-06-18
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("ts_plan_execute_rel")
public class TsPlanExecuteRel extends BaseEntity {
private static final long serialVersionUID=1L;
/**
*
*/
@TableId(value = "rel_id")
private Long relId;
/**
* 关联最终方案ID
*/
private Long acceptId;
/**
* 被下发执行的部门ID
*/
private Long deptId;
/**
* 执行状态 0待执行反馈 1已反馈完成
*/
private Long executeStatus;
/**
* 部门执行结果反馈
*/
private String executeResult;
/**
* 反馈单号
*/
private String feedbackNo;
/**
* 反馈人
*/
private Long feedbackUserId;
/**
* 反馈时间
*/
private Date feedbackTime;
/**
* 反馈文件
*/
private String feedbackFile;
/**
* 备注
*/
private String remark;
/**
* 删除标识 0=正常 2=删除
*/
@TableLogic
private Long delFlag;
}

View File

@@ -0,0 +1,41 @@
package com.klp.flow.domain.bo;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
/**
* 受理单关联钢卷中间业务对象 ts_accept_coil_rel
*
* @author klp
* @date 2026-06-18
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TsAcceptCoilRelBo extends BaseEntity {
/**
*
*/
private Long relId;
/**
* 投诉受理单ID
*/
private Long acceptId;
/**
* 钢卷ID
*/
private Long coilId;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,94 @@
package com.klp.flow.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;
/**
* 投诉受理单主业务对象 ts_complaint_accept
*
* @author klp
* @date 2026-06-18
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TsComplaintAcceptBo extends BaseEntity {
/**
* 受理单主键
*/
private Long acceptId;
/**
* 投诉编号 TS-2026-001
*/
private String complaintNo;
/**
* 投诉日期
*/
private Date complaintDate;
/**
* 投诉情况描述
*/
private String complaintContent;
/**
* 客户诉求
*/
private String customerDemand;
/**
* 客户照片凭证等
*/
private String file;
/**
* 审核状态 0待审核 1已通过 2未通过
*/
private Long auditStatus;
/**
* 审核意见
*/
private String auditOpinion;
/**
* 审核人ID
*/
private Long auditUserId;
/**
* 审核时间
*/
private Date auditTime;
/**
* 流程阶段:
1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=方案下发执行反馈中 5=全部办结
*/
private Long flowStatus;
/**
* 总负责人ID
*/
private Long principalUserId;
/**
* 总负责人整合后的完整处理方案
*/
private String planContent;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,73 @@
package com.klp.flow.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;
/**
* 各部门投诉代办任务&意见业务对象 ts_complaint_task
*
* @author klp
* @date 2026-06-18
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TsComplaintTaskBo extends BaseEntity {
/**
* 代办任务ID
*/
private Long taskId;
/**
* 关联投诉受理单ID
*/
private Long acceptId;
/**
* 负责部门ID销售/质量/生产)
*/
private Long deptId;
/**
* 任务状态 0待填写意见 1已完成填写
*/
private Long taskStatus;
/**
* 意见单号
*/
private String fillNo;
/**
* 部门处理意见
*/
private String deptOpinion;
/**
* 填写意见的部门员工ID
*/
private Long fillUserId;
/**
* 意见填写时间
*/
private Date fillTime;
/**
* 意见文件
*/
private String fillFile;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,73 @@
package com.klp.flow.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;
/**
* 最终方案下发部门及执行反馈业务对象 ts_plan_execute_rel
*
* @author klp
* @date 2026-06-18
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class TsPlanExecuteRelBo extends BaseEntity {
/**
*
*/
private Long relId;
/**
* 关联最终方案ID
*/
private Long acceptId;
/**
* 被下发执行的部门ID
*/
private Long deptId;
/**
* 执行状态 0待执行反馈 1已反馈完成
*/
private Long executeStatus;
/**
* 部门执行结果反馈
*/
private String executeResult;
/**
* 反馈单号
*/
private String feedbackNo;
/**
* 反馈人
*/
private Long feedbackUserId;
/**
* 反馈时间
*/
private Date feedbackTime;
/**
* 反馈文件
*/
private String feedbackFile;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,47 @@
package com.klp.flow.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.klp.common.annotation.ExcelDictFormat;
import com.klp.common.convert.ExcelDictConvert;
import lombok.Data;
/**
* 受理单关联钢卷中间视图对象 ts_accept_coil_rel
*
* @author klp
* @date 2026-06-18
*/
@Data
@ExcelIgnoreUnannotated
public class TsAcceptCoilRelVo {
private static final long serialVersionUID = 1L;
/**
*
*/
@ExcelProperty(value = "")
private Long relId;
/**
* 投诉受理单ID
*/
@ExcelProperty(value = "投诉受理单ID")
private Long acceptId;
/**
* 钢卷ID
*/
@ExcelProperty(value = "钢卷ID")
private Long coilId;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -0,0 +1,110 @@
package com.klp.flow.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;
/**
* 投诉受理单主视图对象 ts_complaint_accept
*
* @author klp
* @date 2026-06-18
*/
@Data
@ExcelIgnoreUnannotated
public class TsComplaintAcceptVo {
private static final long serialVersionUID = 1L;
/**
* 受理单主键
*/
@ExcelProperty(value = "受理单主键")
private Long acceptId;
/**
* 投诉编号 TS-2026-001
*/
@ExcelProperty(value = "投诉编号 TS-2026-001")
private String complaintNo;
/**
* 投诉日期
*/
@ExcelProperty(value = "投诉日期")
private Date complaintDate;
/**
* 投诉情况描述
*/
@ExcelProperty(value = "投诉情况描述")
private String complaintContent;
/**
* 客户诉求
*/
@ExcelProperty(value = "客户诉求")
private String customerDemand;
/**
* 客户照片凭证等
*/
@ExcelProperty(value = "客户照片凭证等")
private String file;
/**
* 审核状态 0待审核 1已通过 2未通过
*/
@ExcelProperty(value = "审核状态 0待审核 1已通过 2未通过")
private Long auditStatus;
/**
* 审核意见
*/
@ExcelProperty(value = "审核意见")
private String auditOpinion;
/**
* 审核人ID
*/
@ExcelProperty(value = "审核人ID")
private Long auditUserId;
/**
* 审核时间
*/
@ExcelProperty(value = "审核时间")
private Date auditTime;
/**
* 流程阶段:
1=待审核 2=部门意见填写中 3=待总负责人汇总方案 4=方案下发执行反馈中 5=全部办结
*/
@ExcelProperty(value = "流程阶段")
private Long flowStatus;
/**
* 总负责人ID
*/
@ExcelProperty(value = "总负责人ID")
private Long principalUserId;
/**
* 总负责人整合后的完整处理方案
*/
@ExcelProperty(value = "总负责人整合后的完整处理方案")
private String planContent;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -0,0 +1,86 @@
package com.klp.flow.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;
/**
* 各部门投诉代办任务&意见视图对象 ts_complaint_task
*
* @author klp
* @date 2026-06-18
*/
@Data
@ExcelIgnoreUnannotated
public class TsComplaintTaskVo {
private static final long serialVersionUID = 1L;
/**
* 代办任务ID
*/
@ExcelProperty(value = "代办任务ID")
private Long taskId;
/**
* 关联投诉受理单ID
*/
@ExcelProperty(value = "关联投诉受理单ID")
private Long acceptId;
/**
* 负责部门ID销售/质量/生产)
*/
@ExcelProperty(value = "负责部门ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "销=售/质量/生产")
private Long deptId;
/**
* 任务状态 0待填写意见 1已完成填写
*/
@ExcelProperty(value = "任务状态 0待填写意见 1已完成填写")
private Long taskStatus;
/**
* 意见单号
*/
@ExcelProperty(value = "意见单号")
private String fillNo;
/**
* 部门处理意见
*/
@ExcelProperty(value = "部门处理意见")
private String deptOpinion;
/**
* 填写意见的部门员工ID
*/
@ExcelProperty(value = "填写意见的部门员工ID")
private Long fillUserId;
/**
* 意见填写时间
*/
@ExcelProperty(value = "意见填写时间")
private Date fillTime;
/**
* 意见文件
*/
@ExcelProperty(value = "意见文件")
private String fillFile;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -0,0 +1,85 @@
package com.klp.flow.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;
/**
* 最终方案下发部门及执行反馈视图对象 ts_plan_execute_rel
*
* @author klp
* @date 2026-06-18
*/
@Data
@ExcelIgnoreUnannotated
public class TsPlanExecuteRelVo {
private static final long serialVersionUID = 1L;
/**
*
*/
@ExcelProperty(value = "")
private Long relId;
/**
* 关联最终方案ID
*/
@ExcelProperty(value = "关联最终方案ID")
private Long acceptId;
/**
* 被下发执行的部门ID
*/
@ExcelProperty(value = "被下发执行的部门ID")
private Long deptId;
/**
* 执行状态 0待执行反馈 1已反馈完成
*/
@ExcelProperty(value = "执行状态 0待执行反馈 1已反馈完成")
private Long executeStatus;
/**
* 部门执行结果反馈
*/
@ExcelProperty(value = "部门执行结果反馈")
private String executeResult;
/**
* 反馈单号
*/
@ExcelProperty(value = "反馈单号")
private String feedbackNo;
/**
* 反馈人
*/
@ExcelProperty(value = "反馈人")
private Long feedbackUserId;
/**
* 反馈时间
*/
@ExcelProperty(value = "反馈时间")
private Date feedbackTime;
/**
* 反馈文件
*/
@ExcelProperty(value = "反馈文件")
private String feedbackFile;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -0,0 +1,15 @@
package com.klp.flow.mapper;
import com.klp.flow.domain.TsAcceptCoilRel;
import com.klp.flow.domain.vo.TsAcceptCoilRelVo;
import com.klp.common.core.mapper.BaseMapperPlus;
/**
* 受理单关联钢卷中间Mapper接口
*
* @author klp
* @date 2026-06-18
*/
public interface TsAcceptCoilRelMapper extends BaseMapperPlus<TsAcceptCoilRelMapper, TsAcceptCoilRel, TsAcceptCoilRelVo> {
}

View File

@@ -0,0 +1,15 @@
package com.klp.flow.mapper;
import com.klp.flow.domain.TsComplaintAccept;
import com.klp.flow.domain.vo.TsComplaintAcceptVo;
import com.klp.common.core.mapper.BaseMapperPlus;
/**
* 投诉受理单主Mapper接口
*
* @author klp
* @date 2026-06-18
*/
public interface TsComplaintAcceptMapper extends BaseMapperPlus<TsComplaintAcceptMapper, TsComplaintAccept, TsComplaintAcceptVo> {
}

View File

@@ -0,0 +1,15 @@
package com.klp.flow.mapper;
import com.klp.flow.domain.TsComplaintTask;
import com.klp.flow.domain.vo.TsComplaintTaskVo;
import com.klp.common.core.mapper.BaseMapperPlus;
/**
* 各部门投诉代办任务&意见Mapper接口
*
* @author klp
* @date 2026-06-18
*/
public interface TsComplaintTaskMapper extends BaseMapperPlus<TsComplaintTaskMapper, TsComplaintTask, TsComplaintTaskVo> {
}

View File

@@ -0,0 +1,15 @@
package com.klp.flow.mapper;
import com.klp.flow.domain.TsPlanExecuteRel;
import com.klp.flow.domain.vo.TsPlanExecuteRelVo;
import com.klp.common.core.mapper.BaseMapperPlus;
/**
* 最终方案下发部门及执行反馈Mapper接口
*
* @author klp
* @date 2026-06-18
*/
public interface TsPlanExecuteRelMapper extends BaseMapperPlus<TsPlanExecuteRelMapper, TsPlanExecuteRel, TsPlanExecuteRelVo> {
}

View File

@@ -0,0 +1,49 @@
package com.klp.flow.service;
import com.klp.flow.domain.TsAcceptCoilRel;
import com.klp.flow.domain.vo.TsAcceptCoilRelVo;
import com.klp.flow.domain.bo.TsAcceptCoilRelBo;
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-06-18
*/
public interface ITsAcceptCoilRelService {
/**
* 查询受理单关联钢卷中间
*/
TsAcceptCoilRelVo queryById(Long relId);
/**
* 查询受理单关联钢卷中间列表
*/
TableDataInfo<TsAcceptCoilRelVo> queryPageList(TsAcceptCoilRelBo bo, PageQuery pageQuery);
/**
* 查询受理单关联钢卷中间列表
*/
List<TsAcceptCoilRelVo> queryList(TsAcceptCoilRelBo bo);
/**
* 新增受理单关联钢卷中间
*/
Boolean insertByBo(TsAcceptCoilRelBo bo);
/**
* 修改受理单关联钢卷中间
*/
Boolean updateByBo(TsAcceptCoilRelBo bo);
/**
* 校验并批量删除受理单关联钢卷中间信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -0,0 +1,49 @@
package com.klp.flow.service;
import com.klp.flow.domain.TsComplaintAccept;
import com.klp.flow.domain.vo.TsComplaintAcceptVo;
import com.klp.flow.domain.bo.TsComplaintAcceptBo;
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-06-18
*/
public interface ITsComplaintAcceptService {
/**
* 查询投诉受理单主
*/
TsComplaintAcceptVo queryById(Long acceptId);
/**
* 查询投诉受理单主列表
*/
TableDataInfo<TsComplaintAcceptVo> queryPageList(TsComplaintAcceptBo bo, PageQuery pageQuery);
/**
* 查询投诉受理单主列表
*/
List<TsComplaintAcceptVo> queryList(TsComplaintAcceptBo bo);
/**
* 新增投诉受理单主
*/
Boolean insertByBo(TsComplaintAcceptBo bo);
/**
* 修改投诉受理单主
*/
Boolean updateByBo(TsComplaintAcceptBo bo);
/**
* 校验并批量删除投诉受理单主信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -0,0 +1,49 @@
package com.klp.flow.service;
import com.klp.flow.domain.TsComplaintTask;
import com.klp.flow.domain.vo.TsComplaintTaskVo;
import com.klp.flow.domain.bo.TsComplaintTaskBo;
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-06-18
*/
public interface ITsComplaintTaskService {
/**
* 查询各部门投诉代办任务&意见
*/
TsComplaintTaskVo queryById(Long taskId);
/**
* 查询各部门投诉代办任务&意见列表
*/
TableDataInfo<TsComplaintTaskVo> queryPageList(TsComplaintTaskBo bo, PageQuery pageQuery);
/**
* 查询各部门投诉代办任务&意见列表
*/
List<TsComplaintTaskVo> queryList(TsComplaintTaskBo bo);
/**
* 新增各部门投诉代办任务&意见
*/
Boolean insertByBo(TsComplaintTaskBo bo);
/**
* 修改各部门投诉代办任务&意见
*/
Boolean updateByBo(TsComplaintTaskBo bo);
/**
* 校验并批量删除各部门投诉代办任务&意见信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -0,0 +1,49 @@
package com.klp.flow.service;
import com.klp.flow.domain.TsPlanExecuteRel;
import com.klp.flow.domain.vo.TsPlanExecuteRelVo;
import com.klp.flow.domain.bo.TsPlanExecuteRelBo;
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-06-18
*/
public interface ITsPlanExecuteRelService {
/**
* 查询最终方案下发部门及执行反馈
*/
TsPlanExecuteRelVo queryById(Long relId);
/**
* 查询最终方案下发部门及执行反馈列表
*/
TableDataInfo<TsPlanExecuteRelVo> queryPageList(TsPlanExecuteRelBo bo, PageQuery pageQuery);
/**
* 查询最终方案下发部门及执行反馈列表
*/
List<TsPlanExecuteRelVo> queryList(TsPlanExecuteRelBo bo);
/**
* 新增最终方案下发部门及执行反馈
*/
Boolean insertByBo(TsPlanExecuteRelBo bo);
/**
* 修改最终方案下发部门及执行反馈
*/
Boolean updateByBo(TsPlanExecuteRelBo bo);
/**
* 校验并批量删除最终方案下发部门及执行反馈信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -0,0 +1,109 @@
package com.klp.flow.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 lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.klp.flow.domain.bo.TsAcceptCoilRelBo;
import com.klp.flow.domain.vo.TsAcceptCoilRelVo;
import com.klp.flow.domain.TsAcceptCoilRel;
import com.klp.flow.mapper.TsAcceptCoilRelMapper;
import com.klp.flow.service.ITsAcceptCoilRelService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 受理单关联钢卷中间Service业务层处理
*
* @author klp
* @date 2026-06-18
*/
@RequiredArgsConstructor
@Service
public class TsAcceptCoilRelServiceImpl implements ITsAcceptCoilRelService {
private final TsAcceptCoilRelMapper baseMapper;
/**
* 查询受理单关联钢卷中间
*/
@Override
public TsAcceptCoilRelVo queryById(Long relId){
return baseMapper.selectVoById(relId);
}
/**
* 查询受理单关联钢卷中间列表
*/
@Override
public TableDataInfo<TsAcceptCoilRelVo> queryPageList(TsAcceptCoilRelBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<TsAcceptCoilRel> lqw = buildQueryWrapper(bo);
Page<TsAcceptCoilRelVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询受理单关联钢卷中间列表
*/
@Override
public List<TsAcceptCoilRelVo> queryList(TsAcceptCoilRelBo bo) {
LambdaQueryWrapper<TsAcceptCoilRel> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<TsAcceptCoilRel> buildQueryWrapper(TsAcceptCoilRelBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<TsAcceptCoilRel> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getAcceptId() != null, TsAcceptCoilRel::getAcceptId, bo.getAcceptId());
lqw.eq(bo.getCoilId() != null, TsAcceptCoilRel::getCoilId, bo.getCoilId());
return lqw;
}
/**
* 新增受理单关联钢卷中间
*/
@Override
public Boolean insertByBo(TsAcceptCoilRelBo bo) {
TsAcceptCoilRel add = BeanUtil.toBean(bo, TsAcceptCoilRel.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setRelId(add.getRelId());
}
return flag;
}
/**
* 修改受理单关联钢卷中间
*/
@Override
public Boolean updateByBo(TsAcceptCoilRelBo bo) {
TsAcceptCoilRel update = BeanUtil.toBean(bo, TsAcceptCoilRel.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(TsAcceptCoilRel entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除受理单关联钢卷中间
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -0,0 +1,120 @@
package com.klp.flow.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.flow.domain.bo.TsComplaintAcceptBo;
import com.klp.flow.domain.vo.TsComplaintAcceptVo;
import com.klp.flow.domain.TsComplaintAccept;
import com.klp.flow.mapper.TsComplaintAcceptMapper;
import com.klp.flow.service.ITsComplaintAcceptService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 投诉受理单主Service业务层处理
*
* @author klp
* @date 2026-06-18
*/
@RequiredArgsConstructor
@Service
public class TsComplaintAcceptServiceImpl implements ITsComplaintAcceptService {
private final TsComplaintAcceptMapper baseMapper;
/**
* 查询投诉受理单主
*/
@Override
public TsComplaintAcceptVo queryById(Long acceptId){
return baseMapper.selectVoById(acceptId);
}
/**
* 查询投诉受理单主列表
*/
@Override
public TableDataInfo<TsComplaintAcceptVo> queryPageList(TsComplaintAcceptBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<TsComplaintAccept> lqw = buildQueryWrapper(bo);
Page<TsComplaintAcceptVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询投诉受理单主列表
*/
@Override
public List<TsComplaintAcceptVo> queryList(TsComplaintAcceptBo bo) {
LambdaQueryWrapper<TsComplaintAccept> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<TsComplaintAccept> buildQueryWrapper(TsComplaintAcceptBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<TsComplaintAccept> lqw = Wrappers.lambdaQuery();
lqw.eq(StringUtils.isNotBlank(bo.getComplaintNo()), TsComplaintAccept::getComplaintNo, bo.getComplaintNo());
lqw.eq(bo.getComplaintDate() != null, TsComplaintAccept::getComplaintDate, bo.getComplaintDate());
lqw.eq(StringUtils.isNotBlank(bo.getComplaintContent()), TsComplaintAccept::getComplaintContent, bo.getComplaintContent());
lqw.eq(StringUtils.isNotBlank(bo.getCustomerDemand()), TsComplaintAccept::getCustomerDemand, bo.getCustomerDemand());
lqw.eq(StringUtils.isNotBlank(bo.getFile()), TsComplaintAccept::getFile, bo.getFile());
lqw.eq(bo.getAuditStatus() != null, TsComplaintAccept::getAuditStatus, bo.getAuditStatus());
lqw.eq(StringUtils.isNotBlank(bo.getAuditOpinion()), TsComplaintAccept::getAuditOpinion, bo.getAuditOpinion());
lqw.eq(bo.getAuditUserId() != null, TsComplaintAccept::getAuditUserId, bo.getAuditUserId());
lqw.eq(bo.getAuditTime() != null, TsComplaintAccept::getAuditTime, bo.getAuditTime());
lqw.eq(bo.getFlowStatus() != null, TsComplaintAccept::getFlowStatus, bo.getFlowStatus());
lqw.eq(bo.getPrincipalUserId() != null, TsComplaintAccept::getPrincipalUserId, bo.getPrincipalUserId());
lqw.eq(StringUtils.isNotBlank(bo.getPlanContent()), TsComplaintAccept::getPlanContent, bo.getPlanContent());
return lqw;
}
/**
* 新增投诉受理单主
*/
@Override
public Boolean insertByBo(TsComplaintAcceptBo bo) {
TsComplaintAccept add = BeanUtil.toBean(bo, TsComplaintAccept.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setAcceptId(add.getAcceptId());
}
return flag;
}
/**
* 修改投诉受理单主
*/
@Override
public Boolean updateByBo(TsComplaintAcceptBo bo) {
TsComplaintAccept update = BeanUtil.toBean(bo, TsComplaintAccept.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(TsComplaintAccept entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除投诉受理单主
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -0,0 +1,116 @@
package com.klp.flow.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.flow.domain.bo.TsComplaintTaskBo;
import com.klp.flow.domain.vo.TsComplaintTaskVo;
import com.klp.flow.domain.TsComplaintTask;
import com.klp.flow.mapper.TsComplaintTaskMapper;
import com.klp.flow.service.ITsComplaintTaskService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 各部门投诉代办任务&意见Service业务层处理
*
* @author klp
* @date 2026-06-18
*/
@RequiredArgsConstructor
@Service
public class TsComplaintTaskServiceImpl implements ITsComplaintTaskService {
private final TsComplaintTaskMapper baseMapper;
/**
* 查询各部门投诉代办任务&意见
*/
@Override
public TsComplaintTaskVo queryById(Long taskId){
return baseMapper.selectVoById(taskId);
}
/**
* 查询各部门投诉代办任务&意见列表
*/
@Override
public TableDataInfo<TsComplaintTaskVo> queryPageList(TsComplaintTaskBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<TsComplaintTask> lqw = buildQueryWrapper(bo);
Page<TsComplaintTaskVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询各部门投诉代办任务&意见列表
*/
@Override
public List<TsComplaintTaskVo> queryList(TsComplaintTaskBo bo) {
LambdaQueryWrapper<TsComplaintTask> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<TsComplaintTask> buildQueryWrapper(TsComplaintTaskBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<TsComplaintTask> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getAcceptId() != null, TsComplaintTask::getAcceptId, bo.getAcceptId());
lqw.eq(bo.getDeptId() != null, TsComplaintTask::getDeptId, bo.getDeptId());
lqw.eq(bo.getTaskStatus() != null, TsComplaintTask::getTaskStatus, bo.getTaskStatus());
lqw.eq(StringUtils.isNotBlank(bo.getFillNo()), TsComplaintTask::getFillNo, bo.getFillNo());
lqw.eq(StringUtils.isNotBlank(bo.getDeptOpinion()), TsComplaintTask::getDeptOpinion, bo.getDeptOpinion());
lqw.eq(bo.getFillUserId() != null, TsComplaintTask::getFillUserId, bo.getFillUserId());
lqw.eq(bo.getFillTime() != null, TsComplaintTask::getFillTime, bo.getFillTime());
lqw.eq(StringUtils.isNotBlank(bo.getFillFile()), TsComplaintTask::getFillFile, bo.getFillFile());
return lqw;
}
/**
* 新增各部门投诉代办任务&意见
*/
@Override
public Boolean insertByBo(TsComplaintTaskBo bo) {
TsComplaintTask add = BeanUtil.toBean(bo, TsComplaintTask.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setTaskId(add.getTaskId());
}
return flag;
}
/**
* 修改各部门投诉代办任务&意见
*/
@Override
public Boolean updateByBo(TsComplaintTaskBo bo) {
TsComplaintTask update = BeanUtil.toBean(bo, TsComplaintTask.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(TsComplaintTask entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除各部门投诉代办任务&意见
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -0,0 +1,116 @@
package com.klp.flow.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.flow.domain.bo.TsPlanExecuteRelBo;
import com.klp.flow.domain.vo.TsPlanExecuteRelVo;
import com.klp.flow.domain.TsPlanExecuteRel;
import com.klp.flow.mapper.TsPlanExecuteRelMapper;
import com.klp.flow.service.ITsPlanExecuteRelService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 最终方案下发部门及执行反馈Service业务层处理
*
* @author klp
* @date 2026-06-18
*/
@RequiredArgsConstructor
@Service
public class TsPlanExecuteRelServiceImpl implements ITsPlanExecuteRelService {
private final TsPlanExecuteRelMapper baseMapper;
/**
* 查询最终方案下发部门及执行反馈
*/
@Override
public TsPlanExecuteRelVo queryById(Long relId){
return baseMapper.selectVoById(relId);
}
/**
* 查询最终方案下发部门及执行反馈列表
*/
@Override
public TableDataInfo<TsPlanExecuteRelVo> queryPageList(TsPlanExecuteRelBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<TsPlanExecuteRel> lqw = buildQueryWrapper(bo);
Page<TsPlanExecuteRelVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询最终方案下发部门及执行反馈列表
*/
@Override
public List<TsPlanExecuteRelVo> queryList(TsPlanExecuteRelBo bo) {
LambdaQueryWrapper<TsPlanExecuteRel> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<TsPlanExecuteRel> buildQueryWrapper(TsPlanExecuteRelBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<TsPlanExecuteRel> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getAcceptId() != null, TsPlanExecuteRel::getAcceptId, bo.getAcceptId());
lqw.eq(bo.getDeptId() != null, TsPlanExecuteRel::getDeptId, bo.getDeptId());
lqw.eq(bo.getExecuteStatus() != null, TsPlanExecuteRel::getExecuteStatus, bo.getExecuteStatus());
lqw.eq(StringUtils.isNotBlank(bo.getExecuteResult()), TsPlanExecuteRel::getExecuteResult, bo.getExecuteResult());
lqw.eq(StringUtils.isNotBlank(bo.getFeedbackNo()), TsPlanExecuteRel::getFeedbackNo, bo.getFeedbackNo());
lqw.eq(bo.getFeedbackUserId() != null, TsPlanExecuteRel::getFeedbackUserId, bo.getFeedbackUserId());
lqw.eq(bo.getFeedbackTime() != null, TsPlanExecuteRel::getFeedbackTime, bo.getFeedbackTime());
lqw.eq(StringUtils.isNotBlank(bo.getFeedbackFile()), TsPlanExecuteRel::getFeedbackFile, bo.getFeedbackFile());
return lqw;
}
/**
* 新增最终方案下发部门及执行反馈
*/
@Override
public Boolean insertByBo(TsPlanExecuteRelBo bo) {
TsPlanExecuteRel add = BeanUtil.toBean(bo, TsPlanExecuteRel.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setRelId(add.getRelId());
}
return flag;
}
/**
* 修改最终方案下发部门及执行反馈
*/
@Override
public Boolean updateByBo(TsPlanExecuteRelBo bo) {
TsPlanExecuteRel update = BeanUtil.toBean(bo, TsPlanExecuteRel.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(TsPlanExecuteRel entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除最终方案下发部门及执行反馈
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -0,0 +1,20 @@
<?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.flow.mapper.TsAcceptCoilRelMapper">
<resultMap type="com.klp.flow.domain.TsAcceptCoilRel" id="TsAcceptCoilRelResult">
<result property="relId" column="rel_id"/>
<result property="acceptId" column="accept_id"/>
<result property="coilId" column="coil_id"/>
<result property="remark" column="remark"/>
<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"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,30 @@
<?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.flow.mapper.TsComplaintAcceptMapper">
<resultMap type="com.klp.flow.domain.TsComplaintAccept" id="TsComplaintAcceptResult">
<result property="acceptId" column="accept_id"/>
<result property="complaintNo" column="complaint_no"/>
<result property="complaintDate" column="complaint_date"/>
<result property="complaintContent" column="complaint_content"/>
<result property="customerDemand" column="customer_demand"/>
<result property="file" column="file"/>
<result property="auditStatus" column="audit_status"/>
<result property="auditOpinion" column="audit_opinion"/>
<result property="auditUserId" column="audit_user_id"/>
<result property="auditTime" column="audit_time"/>
<result property="flowStatus" column="flow_status"/>
<result property="principalUserId" column="principal_user_id"/>
<result property="planContent" column="plan_content"/>
<result property="remark" column="remark"/>
<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"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,26 @@
<?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.flow.mapper.TsComplaintTaskMapper">
<resultMap type="com.klp.flow.domain.TsComplaintTask" id="TsComplaintTaskResult">
<result property="taskId" column="task_id"/>
<result property="acceptId" column="accept_id"/>
<result property="deptId" column="dept_id"/>
<result property="taskStatus" column="task_status"/>
<result property="fillNo" column="fill_no"/>
<result property="deptOpinion" column="dept_opinion"/>
<result property="fillUserId" column="fill_user_id"/>
<result property="fillTime" column="fill_time"/>
<result property="fillFile" column="fill_file"/>
<result property="remark" column="remark"/>
<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"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,26 @@
<?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.flow.mapper.TsPlanExecuteRelMapper">
<resultMap type="com.klp.flow.domain.TsPlanExecuteRel" id="TsPlanExecuteRelResult">
<result property="relId" column="rel_id"/>
<result property="acceptId" column="accept_id"/>
<result property="deptId" column="dept_id"/>
<result property="executeStatus" column="execute_status"/>
<result property="executeResult" column="execute_result"/>
<result property="feedbackNo" column="feedback_no"/>
<result property="feedbackUserId" column="feedback_user_id"/>
<result property="feedbackTime" column="feedback_time"/>
<result property="feedbackFile" column="feedback_file"/>
<result property="remark" column="remark"/>
<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"/>
</resultMap>
</mapper>

View File

@@ -70,6 +70,10 @@ public class QcCertificate extends BaseEntity {
* 质保证明说明(注释)
*/
private String note;
/**
* 证书类型(如:出厂合格证、检测报告、质保书等)
*/
private String certificateType;
/**
* 备注
*/

View File

@@ -82,6 +82,11 @@ public class QcCertificateBo extends BaseEntity {
*/
private String note;
/**
* 证书类型(如:出厂合格证、检测报告、质保书等)
*/
private String certificateType;
/**
* 备注
*/

View File

@@ -100,5 +100,11 @@ public class QcCertificateVo {
@ExcelProperty(value = "备注")
private String remark;
/**
* 证书类型(如:出厂合格证、检测报告、质保书等)
*/
@ExcelProperty(value = "证书类型")
private String certificateType;
}

View File

@@ -75,6 +75,7 @@ public class QcCertificateServiceImpl implements IQcCertificateService {
lqw.le(bo.getApproveTimeEnd() != null, QcCertificate::getApproveTime, bo.getApproveTimeEnd());
lqw.eq(StringUtils.isNotBlank(bo.getNote()), QcCertificate::getNote, bo.getNote());
lqw.eq(StringUtils.isNotBlank(bo.getCertificateType()), QcCertificate::getCertificateType, bo.getCertificateType());
return lqw;
}

View File

@@ -26,6 +26,9 @@ public class MesRollInfo extends BaseEntity {
/** 产线ID */
private Long lineId;
/** 机架 */
private String frame;
/** 轧辊编号 */
private String rollNo;

View File

@@ -25,6 +25,9 @@ public class MesRollInfoBo extends BaseEntity {
/** 产线ID查询过滤 / 新增归属) */
private Long lineId;
/** 机架 */
private String frame;
@NotBlank(message = "轧辊编号不能为空", groups = {AddGroup.class, EditGroup.class})
private String rollNo;

View File

@@ -25,6 +25,9 @@ public class MesRollInfoVo {
@ExcelProperty("产线名称")
private String lineName;
@ExcelProperty("机架")
private String frame;
@ExcelProperty("轧辊编号")
private String rollNo;

View File

@@ -77,6 +77,7 @@ public class MesRollInfoServiceImpl implements IMesRollInfoService {
lqw.like(StringUtils.isNotBlank(bo.getRollNo()), MesRollInfo::getRollNo, bo.getRollNo());
lqw.eq(StringUtils.isNotBlank(bo.getRollType()), MesRollInfo::getRollType, bo.getRollType());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), MesRollInfo::getStatus, bo.getStatus());
lqw.like(StringUtils.isNotBlank(bo.getFrame()), MesRollInfo::getFrame, bo.getFrame());
lqw.like(StringUtils.isNotBlank(bo.getManufacturer()), MesRollInfo::getManufacturer, bo.getManufacturer());
lqw.orderByAsc(MesRollInfo::getRollType, MesRollInfo::getRollId);
return lqw;

View File

@@ -18,6 +18,7 @@
<result property="approveTime" column="approve_time"/>
<result property="note" column="note"/>
<result property="remark" column="remark"/>
<result property="certificateType" column="certificate_type"/>
<result property="delFlag" column="del_flag"/>
<result property="createTime" column="create_time"/>
<result property="createBy" column="create_by"/>

View File

@@ -44,6 +44,7 @@
"@vue-office/excel": "^1.7.14",
"@vue/composition-api": "^1.7.2",
"axios": "0.24.0",
"beautiful-mermaid": "^1.1.3",
"bpmn-js-token-simulation": "0.10.0",
"clipboard": "2.0.8",
"core-js": "3.25.3",

View File

@@ -0,0 +1,430 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>冷轧厂业务流程泳道图</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:"Microsoft YaHei","SimHei",sans-serif;background:#f0f4f8;color:#1e293b;overflow-x:hidden}
.header{background:linear-gradient(135deg,#0f2b47 0%,#1a4a7a 50%,#2c6fad 100%);color:#fff;padding:14px 28px;display:flex;align-items:center;gap:16px;box-shadow:0 3px 16px rgba(0,0,0,.2)}
.header h1{font-size:20px;letter-spacing:2px;font-weight:700}
.header .tag{background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.2);border-radius:12px;padding:3px 14px;font-size:11.5px}
.tabs-wrap{background:#dde3ec;padding:8px 16px 0;position:sticky;top:0;z-index:200;box-shadow:0 2px 6px rgba(0,0,0,.05)}
.tabs{display:flex;gap:3px;overflow-x:auto;padding-bottom:0}
.tabs::-webkit-scrollbar{height:0}
.tab{flex-shrink:0;padding:9px 16px;font-size:12px;border:none;background:transparent;cursor:pointer;border-radius:7px 7px 0 0;color:#5a6a7a;font-weight:500;transition:all .2s;white-space:nowrap}
.tab:hover{background:rgba(255,255,255,.5)}
.tab.on{background:#fff;color:#0f2b47;font-weight:700;box-shadow:0 -1px 4px rgba(0,0,0,.05)}
.tab .tn{display:inline-block;background:#3b6ea5;color:#fff;border-radius:50%;width:17px;height:17px;line-height:17px;font-size:9.5px;text-align:center;margin-right:4px}
.tab.on .tn{background:#1a4a7a}
.panel{display:none;padding:18px 20px 36px}
.panel.on{display:block}
/* ========== 公司架构图 ========== */
.org-outer{background:#fff;border-radius:10px;box-shadow:0 3px 16px rgba(0,0,0,.06);overflow-x:auto;padding:24px 16px 32px;position:relative}
.org-row{display:flex;justify-content:center;gap:10px;flex-wrap:wrap;position:relative;margin-bottom:2px}
.org-node{text-align:center;padding:8px 16px;border-radius:9px;font-weight:700;cursor:pointer;transition:all .2s;position:relative;z-index:2;white-space:nowrap}
.org-node:hover{transform:translateY(-2px);box-shadow:0 6px 20px rgba(0,0,0,.15)}
.org-node.lv0{background:linear-gradient(135deg,#0f2b47,#1a4a7a);color:#fff;font-size:15px;padding:13px 28px;min-width:220px}
.org-node.lv1{background:linear-gradient(135deg,#1e3a5f,#2563eb);color:#fff;font-size:13px;padding:9px 20px;min-width:160px}
.org-node.lv2{background:linear-gradient(135deg,#1d4ed8,#3b82f6);color:#fff;font-size:12px;padding:8px 14px;min-width:155px}
.org-node.lv3{background:#dbeafe;border:1.5px solid #60a5fa;color:#1e40af;font-size:11.5px;padding:6px 11px;min-width:120px;font-weight:600}
.org-node .nd-sub{font-size:9.5px;font-weight:400;opacity:.7;display:block;margin-top:2px}
.org-vline{width:2px;height:16px;background:#93c5fd;margin:0 auto}
.org-tip{text-align:center;font-size:11px;color:#94a3b8;margin-top:10px}
/* ========== 岗位职责 ========== */
.resp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(370px,1fr));gap:16px}
.resp-card{background:#fff;border-radius:10px;box-shadow:0 2px 12px rgba(0,0,0,.05);overflow:hidden;transition:all .2s}
.resp-card:hover{box-shadow:0 4px 20px rgba(0,0,0,.1)}
.resp-hd{padding:14px 18px;cursor:pointer;display:flex;align-items:center;gap:12px;user-select:none;transition:background .2s}
.resp-hd:hover{background:#f0f5ff}
.resp-icon{width:42px;height:42px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0}
.resp-title{font-size:14px;font-weight:700;color:#1e293b}
.resp-sub{font-size:11px;color:#64748b;margin-top:2px}
.resp-arrow{margin-left:auto;font-size:12px;color:#94a3b8;transition:transform .3s}
.resp-card.open .resp-arrow{transform:rotate(90deg)}
.resp-bd{display:none;padding:0 18px 16px;border-top:1px solid #f1f5f9}
.resp-card.open .resp-bd{display:block}
.resp-item{padding:8px 0;border-bottom:1px solid #f8fafc;display:flex;gap:8px;font-size:12.5px;line-height:1.6}
.resp-item:last-child{border-bottom:none}
.resp-bullet{color:#3b82f6;font-weight:700;flex-shrink:0;margin-top:1px}
.resp-tag{display:inline-block;font-size:10px;padding:2px 8px;border-radius:4px;margin-left:8px;font-weight:500}
.resp-tag.core{background:#dbeafe;color:#1e40af}
.resp-tag.support{background:#dcfce7;color:#166534}
.resp-tag.check{background:#fef3c7;color:#92400e}
/* SVG连线动画 */
.sw-svg path{transition:opacity .3s}
.sw-svg path.line-walk{opacity:.85!important;stroke-width:2.8!important}
.sw-svg path.line-walk-done{opacity:.5!important}
.sw-svg path.line-dimmed{opacity:.08!important}
.footer{text-align:center;padding:18px;color:#94a3b8;font-size:10.5px}
</style>
</head>
<body>
<!-- <div class="header">
<h1>⚙️ 冷轧厂业务流程泳道图</h1>
<span class="tag">架构 · 岗位 · 10 条流程 · 步进回放</span>
</div> -->
<div class="tabs-wrap"><div class="tabs" id="tabs"></div></div>
<div id="panels"></div>
<!-- <div class="footer">冷轧厂业务流程泳道图 · 冶金自动化工程</div> -->
<script>
// ═══════════════════════════════════
// 数据定义
// ═══════════════════════════════════
const ORG_TREE = {
name:"股东大会 / 董事会", lv:0, sub:"最高决策层",
children:[
{name:"监事会", lv:1, sub:"监督审计", children:[]},
{name:"总经理", lv:1, sub:"全面经营管理", children:[
{name:"副总经理(生产/设备)", lv:2, sub:"生产运营+设备保障", children:[
{name:"生产部", lv:3, sub:"计划·调度·酸轧·连退·精整"},
{name:"设备部", lv:3, sub:"机械·电气·液压·点检"},
{name:"安全环保部", lv:3, sub:"安监·环保·培训"},
{name:"工厂/分厂厂长", lv:3, sub:"酸轧·连退·镀锌等车间"}
]},
{name:"副总经理(技术/质量)", lv:2, sub:"技术+质量管控", children:[
{name:"技术中心/研发部", lv:3, sub:"工艺标准·新产品开发"},
{name:"质量检验部", lv:3, sub:"来料检·过程检·成品检·实验室"},
{name:"理化检测中心", lv:3, sub:"力学·化学·金相分析"}
]},
{name:"副总经理(营销/供应链)", lv:2, sub:"销售+采购+物流", children:[
{name:"销售部", lv:3, sub:"国内·海外·大客户"},
{name:"采购部", lv:3, sub:"热轧卷·辅料·备件"},
{name:"物流仓储部", lv:3, sub:"原料库·成品库·运输调度"},
{name:"市场部", lv:3, sub:"市场分析·行业研究"}
]},
{name:"总工程师", lv:2, sub:"技术总负责", children:[
{name:"工艺技术科", lv:3, sub:"工艺规程·技术攻关"},
{name:"自动化信息科", lv:3, sub:"L2/MES·信息化"}
]},
{name:"财务总监", lv:2, sub:"资金+成本管控", children:[
{name:"财务部", lv:3, sub:"成本·预算·资金·税务"}
]},
{name:"职能支撑部门", lv:2, sub:"行政+IT+管理", children:[
{name:"综合管理部/办公室", lv:3, sub:"行政·人资·法务"},
{name:"企管部/运营改善部", lv:3, sub:"KPI·流程优化"},
{name:"IT信息化部", lv:3, sub:"ERP·网络·信息安全"}
]}
]}
]
};
const JOBS = [
{name:"生产部",icon:"🏭",color:"#3b82f6",bg:"#dbeafe",lead:"副总经理(生产/设备)",
duties:[
{t:"主生产计划编制与下达",d:"根据销售订单、产能、原料到货编制月/周主生产计划,分解至各产线",tag:"core"},
{t:"车间日/班次排产",d:"编制各车间日计划、班次排产表,协调产线切换与规格衔接",tag:"core"},
{t:"生产调度与异常协调",d:"实时监控产线运行状态,处理停机、改规、换辊等生产异常",tag:"core"},
{t:"订单进度跟踪与反馈",d:"跟踪订单从排产到完工全流程,向销售部反馈进度",tag:"core"},
{t:"产能平衡与瓶颈分析",d:"分析各产线产能利用率,识别瓶颈并提出改善建议",tag:"support"},
{t:"原料需求提报",d:"根据排产计划向采购部提报原料需求计划",tag:"support"}
]},
{name:"设备部",icon:"🔧",color:"#059669",bg:"#d1fae5",lead:"副总经理(生产/设备)",
duties:[
{t:"设备日常/专业点检",d:"执行日常点检、专业点检,记录设备状态数据",tag:"core"},
{t:"维修计划编制与实施",d:"编制定修/年修计划,组织实施维修作业",tag:"core"},
{t:"故障应急响应",d:"处理突发设备故障,组织抢修恢复生产",tag:"core"},
{t:"备件需求提报与管理",d:"提报备件采购需求,管理备件库存与台账",tag:"support"},
{t:"设备技术改造方案",d:"提出设备技改需求,配合总工程师评审方案",tag:"support"},
{t:"维修后验收与归档",d:"组织维修后设备验收,更新设备档案",tag:"check"}
]},
{name:"技术中心/研发部",icon:"🔬",color:"#7c3aed",bg:"#ede9fe",lead:"副总经理(技术/质量)",
duties:[
{t:"工艺标准/工艺卡制定",d:"制定各钢种、各产线工艺标准,编制工艺卡",tag:"core"},
{t:"新产品/新工艺开发",d:"研发新产品、新工艺路线,组织试制与验证",tag:"core"},
{t:"工艺参数下发与交底",d:"向车间下发工艺参数MES/纸质),组织新工艺交底",tag:"core"},
{t:"工艺异常分析与处置",d:"分析工艺异常原因,制定处置方案",tag:"core"},
{t:"工艺变更管理",d:"评审并管理工艺变更,确保变更受控可追溯",tag:"check"},
{t:"封锁品评审",d:"参与封锁品/待判品技术评审,给出处置建议",tag:"check"}
]},
{name:"质量检验部",icon:"✅",color:"#dc2626",bg:"#fee2e2",lead:"副总经理(技术/质量)",
duties:[
{t:"来料取样与检测",d:"对进厂原料/辅料取样检验,出具检验报告",tag:"core"},
{t:"来料合格/不合格判定",d:"依据标准判定来料是否合格,通知采购和仓储",tag:"core"},
{t:"过程检验",d:"按产线执行过程检验(酸洗、轧制、退火、镀锌等)",tag:"core"},
{t:"成品检验与判定",d:"对成品进行力学/表面/尺寸检验,做出合格/不合格判定",tag:"core"},
{t:"合格品放行",d:"确认成品检验合格后签发放行单,通知仓储发货",tag:"core"},
{t:"封锁品/待判品管理",d:"管理封锁品标识与隔离,组织技术中心评审",tag:"check"},
{t:"质量异议现场确认",d:"参与客户质量异议的实物确认与复检",tag:"check"}
]},
{name:"理化检测中心",icon:"🧪",color:"#b45309",bg:"#fef3c7",lead:"副总经理(技术/质量)",
duties:[
{t:"力学性能检测",d:"拉伸、硬度、冲击等力学性能测试",tag:"core"},
{t:"化学成分分析",d:"直读光谱、碳硫分析、化学成分测定",tag:"core"},
{t:"金相组织检验",d:"金相制样、显微组织观察与评级",tag:"core"},
{t:"镀层/涂层检测",d:"镀锌量、涂层厚度、附着力检测",tag:"core"},
{t:"检测报告出具",d:"出具标准检测报告,支持质量判定",tag:"support"}
]},
{name:"销售部",icon:"📊",color:"#2563eb",bg:"#dbeafe",lead:"副总经理(营销/供应链)",
duties:[
{t:"合同评审与签订",d:"组织合同交期/技术/产能评审,签订销售合同",tag:"core"},
{t:"下达销售订单",d:"先交技术中心确认工艺可行性,再下达生产部排产",tag:"core"},
{t:"发货计划编制与跟踪",d:"编制发货计划,跟踪发货确认与签收",tag:"core"},
{t:"质量异议接收与处理",d:"接收客户质量异议,协调技术/质检处理",tag:"core"},
{t:"客户关系维护与回访",d:"维护大客户关系,异议关闭后组织回访",tag:"support"},
{t:"市场信息反馈",d:"收集市场需求、价格走势信息,反馈至生产/技术",tag:"support"}
]},
{name:"采购部",icon:"📦",color:"#ca8a04",bg:"#fef9c3",lead:"副总经理(营销/供应链)",
duties:[
{t:"采购计划编制",d:"根据生产部/设备部需求编制原料/辅料/备件采购计划",tag:"core"},
{t:"采购订单下达与跟踪",d:"下达采购订单,跟踪交期与物流",tag:"core"},
{t:"到货通知与协调",d:"到货前通知物流仓储部准备接收",tag:"core"},
{t:"不合格品退货处理",d:"质量检验部判定不合格后协调退货",tag:"check"},
{t:"质量索赔",d:"对不合格来料向供应商发起质量索赔",tag:"check"},
{t:"供应商管理",d:"供应商资质评审、绩效评价、目录维护",tag:"support"}
]},
{name:"物流仓储部",icon:"🚛",color:"#0d9488",bg:"#ccfbf1",lead:"副总经理(营销/供应链)",
duties:[
{t:"原料入库与投料管理",d:"原料验收入库,按生产计划投料至各车间",tag:"core"},
{t:"成品入库与出库",d:"成品验收入库,按发货计划备货出库",tag:"core"},
{t:"到货接收与暂存",d:"到货暂存待检区,通知质检检验",tag:"core"},
{t:"发货/运输调度",d:"组织发货装车,调度运输",tag:"core"},
{t:"日常出入库记录",d:"记录每日出入库明细,维护库存台账",tag:"support"},
{t:"库存盘点与差异处理",d:"配合财务部进行定期盘点,处理账实差异",tag:"check"},
{t:"呆滞/封锁品报告",d:"定期报告呆滞品与封锁品,通知质检/财务",tag:"check"}
]},
{name:"安全环保部",icon:"🛡️",color:"#dc2626",bg:"#fee2e2",lead:"副总经理(生产/设备)",
duties:[
{t:"安全/环保培训",d:"组织全员安全培训、特种作业培训、环保培训",tag:"core"},
{t:"日常安全检查",d:"执行日常安全巡查,发现隐患并督促整改",tag:"core"},
{t:"环保监测",d:"监测废水、废气排放,确保达标",tag:"core"},
{t:"事故报告与调查",d:"安全事故报告、调查与处理",tag:"core"},
{t:"隐患整改跟踪",d:"跟踪车间隐患整改进度,闭环管理",tag:"check"},
{t:"外部检查对接",d:"对接政府安监/环保检查",tag:"support"}
]},
{name:"总工程师",icon:"🏗️",color:"#7c3aed",bg:"#ede9fe",lead:"总经理",
duties:[
{t:"技改方案评审",d:"评审技术改造方案的技术可行性",tag:"core"},
{t:"定修/年修计划审批",d:"审批定修/年修计划的技术方案",tag:"core"},
{t:"重大工艺变更审批",d:"审批重大工艺变更方案",tag:"core"},
{t:"项目实施协调",d:"协调技改项目实施中的停机窗口",tag:"core"},
{t:"验收与移交",d:"组织技改项目验收与设备移交",tag:"check"},
{t:"资料归档管理",d:"督促技改资料归档至综合管理部",tag:"support"}
]},
{name:"财务部",icon:"💰",color:"#059669",bg:"#d1fae5",lead:"财务总监",
duties:[
{t:"成本核算与分析",d:"各产线/产品成本核算,差异分析",tag:"core"},
{t:"预算编制与管控",d:"年度/月度预算编制,预算执行监控",tag:"core"},
{t:"开票与结算",d:"销售开票、采购付款结算",tag:"core"},
{t:"应收账款跟踪",d:"跟踪应收账款回收,预警逾期",tag:"core"},
{t:"定期盘点组织",d:"组织月/季/年度库存盘点",tag:"check"},
{t:"盘点差异处理",d:"盘点差异审核与账务调整",tag:"check"}
]},
{name:"综合管理部/办公室",icon:"📋",color:"#64748b",bg:"#f1f5f9",lead:"总经理",
duties:[
{t:"行政管理",d:"公司行政事务、会议组织、文件管理",tag:"core"},
{t:"人力资源管理",d:"招聘、培训、薪酬、绩效考核",tag:"core"},
{t:"法务管理",d:"合同审查、法律风险防控",tag:"core"},
{t:"事故调查配合",d:"配合安全环保部事故调查的行政工作",tag:"support"},
{t:"资料归档接收",d:"接收技改/项目归档资料",tag:"support"}
]},
{name:"IT信息化部",icon:"💻",color:"#2563eb",bg:"#dbeafe",lead:"总经理",
duties:[
{t:"MES/L2系统运维",d:"维护MES、L2系统稳定运行故障响应",tag:"core"},
{t:"ERP系统管理",d:"ERP系统配置、数据维护、用户权限管理",tag:"core"},
{t:"网络与信息安全",d:"网络基础设施运维,信息安全防护",tag:"core"},
{t:"系统开发与集成",d:"新系统开发、系统集成、报表定制",tag:"support"},
{t:"数据备份与容灾",d:"数据库备份、容灾方案实施",tag:"support"}
]},
{name:"各车间",icon:"⚙️",color:"#475569",bg:"#f1f5f9",lead:"工厂/分厂厂长",
duties:[
{t:"产线生产执行",d:"按排产计划执行生产作业,确保产量/质量达标",tag:"core"},
{t:"工艺纪律执行",d:"严格执行工艺参数,接受技术中心抽查",tag:"core"},
{t:"设备日常点检",d:"执行设备日常点检,上报隐患与故障",tag:"core"},
{t:"过程质量自检",d:"执行生产过程自检,配合质量检验部过程检",tag:"check"},
{t:"完工入库操作",d:"成品完工后办理入库/转库手续",tag:"support"},
{t:"安全与5S管理",d:"执行安全操作规程保持5S现场",tag:"check"}
]}
];
// ═══════════════════════════════════
// Tab 0: 公司架构图
// ═══════════════════════════════════
(function(){
const tb = document.createElement('button');
tb.className = 'tab on';
tb.innerHTML = '<span class="tn">🏢</span>公司架构';
document.getElementById('tabs').appendChild(tb);
const pn = document.createElement('div');
pn.className = 'panel on';
pn.id = 'org';
let h = '<div class="org-outer" id="org-outer">';
h += '<div class="org-row" id="org-r0" style="margin-bottom:10px">';
h += '<div class="org-node lv0" data-name="股东大会/董事会">股东大会 / 董事会<span class="nd-sub">最高决策层</span></div>';
h += '</div>';
const gmNode = ORG_TREE.children[1];
h += '<div class="org-row" id="org-r1" style="gap:40px;margin-bottom:10px">';
h += '<div class="org-branch"><div class="org-node lv1" data-name="监事会">监事会<span class="nd-sub">监督审计</span></div></div>';
h += '<div class="org-branch"><div class="org-node lv1" id="org-gm" data-name="总经理">总经理<span class="nd-sub">全面经营管理</span></div></div>';
h += '</div>';
h += '<div class="org-row" id="org-r2" style="gap:12px 6px;margin-bottom:10px">';
gmNode.children.forEach((vp,vi) => {
h += '<div class="org-branch" id="org-vp-'+vi+'">';
h += '<div class="org-node lv2" data-name="'+vp.name+'">'+vp.name+'<span class="nd-sub">'+vp.sub+'</span></div>';
if(vp.children && vp.children.length){
h += '<div class="org-vline"></div>';
h += '<div style="display:flex;gap:5px;flex-wrap:wrap;justify-content:center">';
vp.children.forEach(dp => {
h += '<div class="org-node lv3" data-name="'+dp.name+'">'+dp.name+'<span class="nd-sub">'+dp.sub+'</span></div>';
});
h += '</div>';
}
h += '</div>';
});
h += '</div></div>';
h += '<p class="org-tip">💡 点击节点可跳转至岗位职责</p>';
pn.innerHTML = h;
pn.addEventListener('click', function(e){
const node = e.target.closest('.org-node');
if(node && node.dataset.name) jumpToJob(node.dataset.name);
});
document.getElementById('panels').appendChild(pn);
tb.onclick = () => {
document.querySelectorAll('.tab').forEach(x => x.classList.remove('on'));
document.querySelectorAll('.panel').forEach(x => x.classList.remove('on'));
tb.classList.add('on');
pn.classList.add('on');
setTimeout(drawOrgLines, 100);
};
})();
function jumpToJob(name){
const tabs = document.querySelectorAll('.tab');
if(tabs[1]) tabs[1].click();
setTimeout(() => {
const cards = document.querySelectorAll('.resp-card');
cards.forEach(c => {
if(c.dataset.name === name && !c.classList.contains('open')){
c.querySelector('.resp-hd').click();
}
});
const target = [...cards].find(c => c.dataset.name === name);
if(target) target.scrollIntoView({behavior:'smooth',block:'center'});
}, 280);
}
function drawOrgLines(){
const outer = document.getElementById('org-outer');
if(!outer) return;
let svg = document.getElementById('org-svg');
if(svg) svg.remove();
const w = outer.scrollWidth, h = outer.scrollHeight;
svg = document.createElementNS('http://www.w3.org/2000/svg','svg');
svg.id = 'org-svg';
svg.setAttribute('width', w);
svg.setAttribute('height', h);
svg.setAttribute('viewBox','0 0 '+w+' '+h);
svg.style.cssText = 'position:absolute;top:0;left:0;pointer-events:none;overflow:visible;z-index:1';
outer.appendChild(svg);
const or = outer.getBoundingClientRect();
function pos(el){
const r = el.getBoundingClientRect();
return {cx:r.left-or.left+r.width/2, cy:r.top-or.top+r.height/2, l:r.left-or.left, t:r.top-or.top, R:r.left-or.left+r.width, b:r.top-or.top+r.height};
}
function mkCurve(x1,y1,x2,y2,color){
const dy = Math.abs(y2-y1)*0.35;
const path = document.createElementNS('http://www.w3.org/2000/svg','path');
path.setAttribute('d','M'+x1+' '+y1+' C'+x1+' '+(y1<y2?y1+dy:y1-dy)+' '+x2+' '+(y2>dy?y2-dy:y2+dy)+' '+x2+' '+y2);
path.setAttribute('fill','none');
path.setAttribute('stroke',color||'#93c5fd');
path.setAttribute('stroke-width','2');
svg.appendChild(path);
}
const r0n = document.querySelector('#org-r0 .org-node');
const r1ns = document.querySelectorAll('#org-r1 .org-node');
if(r0n && r1ns.length>=2){
const p0 = pos(r0n);
r1ns.forEach(n => { const p1=pos(n); mkCurve(p0.cx,p0.b,p1.cx,p1.t,'#93c5fd'); });
}
const gm = document.getElementById('org-gm');
const vpBranches = document.querySelectorAll('#org-r2 > .org-branch');
if(gm && vpBranches.length){
const pGm = pos(gm);
vpBranches.forEach(br => {
const vpn = br.querySelector(':scope > .org-node');
if(!vpn) return;
const pVp = pos(vpn);
mkCurve(pGm.cx,pGm.b,pVp.cx,pVp.t,'#93c5fd');
});
}
vpBranches.forEach(br => {
const vpn = br.querySelector(':scope > .org-node');
if(!vpn) return;
const pVp = pos(vpn);
const depts = br.querySelectorAll(':scope > div:last-child .org-node');
depts.forEach(dn => { const pD=pos(dn); mkCurve(pVp.cx,pVp.b,pD.cx,pD.t,'#93c5fd'); });
});
}
// ═══════════════════════════════════
// Tab 1: 岗位职责
// ═══════════════════════════════════
(function(){
const tb = document.createElement('button');
tb.className = 'tab';
tb.innerHTML = '<span class="tn">👤</span>岗位职责';
document.getElementById('tabs').appendChild(tb);
const pn = document.createElement('div');
pn.className = 'panel';
pn.id = 'jobs';
let h = '<div class="resp-grid">';
JOBS.forEach(j => {
h += '<div class="resp-card" data-name="'+j.name+'">';
h += '<div class="resp-hd" onclick="this.parentElement.classList.toggle(\'open\')">';
h += '<div class="resp-icon" style="background:'+j.bg+';color:'+j.color+'">'+j.icon+'</div>';
h += '<div><div class="resp-title">'+j.name+'</div><div class="resp-sub">上级:'+j.lead+'</div></div>';
h += '<div class="resp-arrow">▶</div>';
h += '</div>';
h += '<div class="resp-bd">';
j.duties.forEach(d => {
const tc = d.tag==='core'?'core':(d.tag==='check'?'check':'support');
const tl = d.tag==='core'?'核心':(d.tag==='check'?'验收':'支撑');
h += '<div class="resp-item"><span class="resp-bullet">•</span><div><b>'+d.t+'</b><span class="resp-tag '+tc+'">'+tl+'</span><br><span style="color:#64748b;font-size:11.5px">'+d.d+'</span></div></div>';
});
h += '</div></div>';
});
h += '</div>';
pn.innerHTML = h;
document.getElementById('panels').appendChild(pn);
tb.onclick = () => {
document.querySelectorAll('.tab').forEach(x => x.classList.remove('on'));
document.querySelectorAll('.panel').forEach(x => x.classList.remove('on'));
tb.classList.add('on');
pn.classList.add('on');
};
})();
// ═══════════════════════════════════
// 初始化
// ═══════════════════════════════════
window.addEventListener('load', () => {
setTimeout(() => drawOrgLines(), 350);
});
window.addEventListener('resize', () => {
const ap = document.querySelector('.panel.on');
if(!ap) return;
if(ap.id === 'org') drawOrgLines();
else if(ap.id !== 'jobs') drawLines(ap.id);
});
</script>
</body>
</html>

View File

@@ -0,0 +1,19 @@
import request from '@/utils/request'
const BASE = '/wms/materialCoil'
export function getCoilHoardingStats(data) {
return request({
url: BASE + '/hoardingStatistics',
method: 'post',
data: data
})
}
export function listCoilHoardingDetail(query) {
return request({
url: BASE + '/listWithQrcode',
method: 'get',
params: query
})
}

View File

@@ -0,0 +1,53 @@
import request from '@/utils/request'
// 查询生产指标计算结果列表
export function listProdMetricResult(query) {
return request({
url: '/cost/prodMetricResult/list',
method: 'get',
params: query
})
}
// 查询生产指标计算结果详细
export function getProdMetricResult(resultId) {
return request({
url: '/cost/prodMetricResult/' + resultId,
method: 'get'
})
}
// 新增生产指标计算结果
export function addProdMetricResult(data) {
return request({
url: '/cost/prodMetricResult',
method: 'post',
data: data
})
}
// 修改生产指标计算结果
export function updateProdMetricResult(data) {
return request({
url: '/cost/prodMetricResult',
method: 'put',
data: data
})
}
// 删除生产指标计算结果
export function delProdMetricResult(resultId) {
return request({
url: '/cost/prodMetricResult/' + resultId,
method: 'delete'
})
}
// 批量保存计算结果(先删后插)
export function batchSaveProdMetricResult(data) {
return request({
url: '/cost/prodMetricResult/batch',
method: 'post',
data: data
})
}

View File

@@ -1,44 +0,0 @@
import request from '@/utils/request'
// 查询检验委托单表列表
export function listInspectionCommission(query) {
return request({
url: '/is/inspectionCommission/list',
method: 'get',
params: query
})
}
// 查询检验委托单表详细
export function getInspectionCommission(commissionId) {
return request({
url: '/is/inspectionCommission/' + commissionId,
method: 'get'
})
}
// 新增检验委托单表
export function addInspectionCommission(data) {
return request({
url: '/is/inspectionCommission',
method: 'post',
data: data
})
}
// 修改检验委托单表
export function updateInspectionCommission(data) {
return request({
url: '/is/inspectionCommission',
method: 'put',
data: data
})
}
// 删除检验委托单表
export function delInspectionCommission(commissionId) {
return request({
url: '/is/inspectionCommission/' + commissionId,
method: 'delete'
})
}

View File

@@ -1,44 +0,0 @@
import request from '@/utils/request'
// 查询检验任务表列表
export function listInspectionTask(query) {
return request({
url: '/is/inspectionTask/list',
method: 'get',
params: query
})
}
// 查询检验任务表详细
export function getInspectionTask(taskId) {
return request({
url: '/is/inspectionTask/' + taskId,
method: 'get'
})
}
// 新增检验任务表
export function addInspectionTask(data) {
return request({
url: '/is/inspectionTask',
method: 'post',
data: data
})
}
// 修改检验任务表
export function updateInspectionTask(data) {
return request({
url: '/is/inspectionTask',
method: 'put',
data: data
})
}
// 删除检验任务表
export function delInspectionTask(taskId) {
return request({
url: '/is/inspectionTask/' + taskId,
method: 'delete'
})
}

View File

@@ -1,44 +0,0 @@
import request from '@/utils/request'
// 查询样品库存表列表
export function listSampleInventory(query) {
return request({
url: '/is/sampleInventory/list',
method: 'get',
params: query
})
}
// 查询样品库存表详细
export function getSampleInventory(sampleId) {
return request({
url: '/is/sampleInventory/' + sampleId,
method: 'get'
})
}
// 新增样品库存表
export function addSampleInventory(data) {
return request({
url: '/is/sampleInventory',
method: 'post',
data: data
})
}
// 修改样品库存表
export function updateSampleInventory(data) {
return request({
url: '/is/sampleInventory',
method: 'put',
data: data
})
}
// 删除样品库存表
export function delSampleInventory(sampleId) {
return request({
url: '/is/sampleInventory/' + sampleId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询检验项目明细列表
export function listInspectionDetail(query) {
return request({
url: '/wms/inspectionDetail/list',
method: 'get',
params: query
})
}
// 查询检验项目明细详细
export function getInspectionDetail(detailId) {
return request({
url: '/wms/inspectionDetail/' + detailId,
method: 'get'
})
}
// 新增检验项目明细
export function addInspectionDetail(data) {
return request({
url: '/wms/inspectionDetail',
method: 'post',
data: data
})
}
// 修改检验项目明细
export function updateInspectionDetail(data) {
return request({
url: '/wms/inspectionDetail',
method: 'put',
data: data
})
}
// 删除检验项目明细
export function delInspectionDetail(detailId) {
return request({
url: '/wms/inspectionDetail/' + detailId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询检验主列表
export function listInspectionMain(query) {
return request({
url: '/wms/inspectionMain/list',
method: 'get',
params: query
})
}
// 查询检验主详细
export function getInspectionMain(mainId) {
return request({
url: '/wms/inspectionMain/' + mainId,
method: 'get'
})
}
// 新增检验主
export function addInspectionMain(data) {
return request({
url: '/wms/inspectionMain',
method: 'post',
data: data
})
}
// 修改检验主
export function updateInspectionMain(data) {
return request({
url: '/wms/inspectionMain',
method: 'put',
data: data
})
}
// 删除检验主
export function delInspectionMain(mainId) {
return request({
url: '/wms/inspectionMain/' + mainId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询金属材料室温拉伸试验主记录列表
export function listInspectionTensile(query) {
return request({
url: '/wms/inspectionTensile/list',
method: 'get',
params: query
})
}
// 查询金属材料室温拉伸试验主记录详细
export function getInspectionTensile(testId) {
return request({
url: '/wms/inspectionTensile/' + testId,
method: 'get'
})
}
// 新增金属材料室温拉伸试验主记录
export function addInspectionTensile(data) {
return request({
url: '/wms/inspectionTensile',
method: 'post',
data: data
})
}
// 修改金属材料室温拉伸试验主记录
export function updateInspectionTensile(data) {
return request({
url: '/wms/inspectionTensile',
method: 'put',
data: data
})
}
// 删除金属材料室温拉伸试验主记录
export function delInspectionTensile(testId) {
return request({
url: '/wms/inspectionTensile/' + testId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询金属材料室温拉伸试验样品明细列表
export function listInspectionTensileDetail(query) {
return request({
url: '/wms/inspectionTensileDetail/list',
method: 'get',
params: query
})
}
// 查询金属材料室温拉伸试验样品明细详细
export function getInspectionTensileDetail(detailId) {
return request({
url: '/wms/inspectionTensileDetail/' + detailId,
method: 'get'
})
}
// 新增金属材料室温拉伸试验样品明细
export function addInspectionTensileDetail(data) {
return request({
url: '/wms/inspectionTensileDetail',
method: 'post',
data: data
})
}
// 修改金属材料室温拉伸试验样品明细
export function updateInspectionTensileDetail(data) {
return request({
url: '/wms/inspectionTensileDetail',
method: 'put',
data: data
})
}
// 删除金属材料室温拉伸试验样品明细
export function delInspectionTensileDetail(detailId) {
return request({
url: '/wms/inspectionTensileDetail/' + detailId,
method: 'delete'
})
}

View File

@@ -38,8 +38,9 @@ export function updateAttendanceSchedule(data) {
// 删除排班记录(支持批量删除传递csv格式字符串如1,2,3)
export function delAttendanceSchedule(ids) {
return request({
url: '/wms/attendanceSchedule/' + ids,
method: 'delete'
url: '/wms/attendanceSchedule/remove',
method: 'delete',
data: ids,
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询排班模板列表
export function listAttendanceTemplate(query) {
return request({
url: '/wms/attendanceTemplate/list',
method: 'get',
params: query
})
}
// 查询排班模板详细
export function getAttendanceTemplate(templateId) {
return request({
url: '/wms/attendanceTemplate/' + templateId,
method: 'get'
})
}
// 新增排班模板
export function addAttendanceTemplate(data) {
return request({
url: '/wms/attendanceTemplate',
method: 'post',
data: data
})
}
// 修改排班模板
export function updateAttendanceTemplate(data) {
return request({
url: '/wms/attendanceTemplate',
method: 'put',
data: data
})
}
// 删除排班模板
export function delAttendanceTemplate(templateId) {
return request({
url: '/wms/attendanceTemplate/' + templateId,
method: 'delete'
})
}

View File

@@ -35,27 +35,42 @@ export function getMaterialCoil(CoilMaterialId) {
}
export function addMaterialCoil(data) {
// 对data进行预处理将currentCoilNo去除首位的空格
const payload = {
...data,
currentCoilNo: data.currentCoilNo.trim(),
}
return request({
url: '/wms/materialCoil',
method: 'post',
data: data
data: payload
})
}
export function updateMaterialCoil(data) {
// 对data进行预处理将currentCoilNo去除首位的空格
const payload = {
...data,
currentCoilNo: data.currentCoilNo.trim(),
}
return request({
url: '/wms/materialCoil',
method: 'put',
data: data
data: payload
})
}
// 简单更新钢卷物料表
export function updateMaterialCoilSimple(data) {
// 对data进行预处理将currentCoilNo去除首位的空格
const payload = {
...data,
currentCoilNo: data.currentCoilNo.trim(),
}
return request({
url: '/wms/materialCoil/update',
method: 'put',
data: data
data: payload
})
}
@@ -107,19 +122,32 @@ export function getMaterialCoilDistributionByActualWarehouse(query) {
// 钢卷分卷
export function splitMaterialCoil(data) {
const payload = {
...data,
// currentCoilNo: data.currentCoilNo.trim(),
newCoils: data.newCoils?.map(item => ({
...item,
currentCoilNo: item.currentCoilNo?.trim(),
})),
}
return request({
url: '/wms/materialCoil',
method: 'put',
data: data
data: payload
})
}
// 钢卷合卷
export function mergeMaterialCoil(data) {
// 对data进行预处理将currentCoilNo去除首位的空格
const payload = {
...data,
currentCoilNo: data.currentCoilNo.trim(),
}
return request({
url: '/wms/materialCoil/merge',
method: 'post',
data: data
data: payload
})
}
@@ -283,10 +311,15 @@ export function startSpecialSplit(coilId, actionType) {
* 创建一个分条
*/
export function createSpecialChild(parentCoilId, pendingActionId, data) {
// 对data进行预处理将currentCoilNo去除首位的空格
const payload = {
...data,
currentCoilNo: data.currentCoilNo.trim(),
}
return request({
url: '/wms/materialCoil/specialSplit/createChild',
method: 'post',
data: data,
data: payload,
params: {
parentCoilId,
pendingActionId
@@ -496,4 +529,21 @@ export function getExportColumns() {
url: '/wms/materialCoil/exportColumns',
method: 'get',
})
}
export function listForPeriodComparison(data) {
return request({
url: '/wms/materialCoil/listForPeriodComparison',
method: 'post',
timeout: 600000,
data: data
})
}
// 钢卷加工链追溯查询(双向:向上到根节点,向下到所有后代)
export function getCoilChain(coilId) {
return request({
url: '/wms/materialCoil/chain/all/' + coilId,
method: 'get'
})
}

View File

@@ -0,0 +1,62 @@
import request from '@/utils/request'
// 查询钢卷通用维度告警(长度/厚度/宽度)列表
export function listMaterialWarning(query) {
return request({
url: '/wms/materialWarning/list',
method: 'get',
params: query
})
}
// 查询钢卷通用维度告警(长度/厚度/宽度)详细
export function getMaterialWarning(warningId) {
return request({
url: '/wms/materialWarning/' + warningId,
method: 'get'
})
}
// 新增钢卷通用维度告警(长度/厚度/宽度)
export function addMaterialWarning(data) {
return request({
url: '/wms/materialWarning',
method: 'post',
data: data
})
}
// 修改钢卷通用维度告警(长度/厚度/宽度)
export function updateMaterialWarning(data) {
return request({
url: '/wms/materialWarning',
method: 'put',
data: data
})
}
// 批量处理钢卷通用维度告警(长度/厚度/宽度)
export function batchHandleMaterial(data) {
return request({
url: '/wms/materialWarning/batchHandle',
method: 'put',
data: data
})
}
// 批量处理历史告警(标记今天以前的所有记录为指定状态)
export function batchHandleHistory(data) {
return request({
url: '/wms/materialWarning/batchHandleHistory',
method: 'put',
data: data
})
}
// 删除钢卷通用维度告警(长度/厚度/宽度)
export function delMaterialWarning(warningId) {
return request({
url: '/wms/materialWarning/' + warningId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询岗位列表
export function listPost(query) {
return request({
url: '/wms/post/list',
method: 'get',
params: query
})
}
// 查询岗位详细
export function getPost(postId) {
return request({
url: '/wms/post/' + postId,
method: 'get'
})
}
// 新增岗位
export function addPost(data) {
return request({
url: '/wms/post',
method: 'post',
data: data
})
}
// 修改岗位
export function updatePost(data) {
return request({
url: '/wms/post',
method: 'put',
data: data
})
}
// 删除岗位
export function delPost(postId) {
return request({
url: '/wms/post/' + postId,
method: 'delete'
})
}

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询岗位职责列表
export function listPostDuty(query) {
return request({
url: '/wms/postDuty/list',
method: 'get',
params: query
})
}
// 查询岗位职责详细
export function getPostDuty(dutyId) {
return request({
url: '/wms/postDuty/' + dutyId,
method: 'get'
})
}
// 新增岗位职责
export function addPostDuty(data) {
return request({
url: '/wms/postDuty',
method: 'post',
data: data
})
}
// 修改岗位职责
export function updatePostDuty(data) {
return request({
url: '/wms/postDuty',
method: 'put',
data: data
})
}
// 删除岗位职责
export function delPostDuty(dutyId) {
return request({
url: '/wms/postDuty/' + dutyId,
method: 'delete'
})
}

View File

@@ -0,0 +1,19 @@
A. 在哪里可以下载阿里妈妈数黑体?
渠道一https://www.iconfont.cn/fonts/detail?cnid=a9fXc2HD9n7s
渠道二fonts.alibabagroup.com
B. 阿里阿里妈妈数黑体简介
基本信息阿里妈妈数黑体为中文简体字库收纳的中文字符包括但不限于GB2312共计6767个汉字英文大小写共52个常用标点符号共206个总计7025个字符。
设计说明:阿里妈妈数黑体字型饱满、体态中正,布白极具现代韵律,落笔厚实而简练;字里行间流露出先锋、前卫和时尚的视觉感受。适用于电商、广告、品牌形象、推广物料等场景。
C. 使用反馈、商业合作等问题请email
alimama-font@list.alibaba-inc.com
——
重要!安装前请先阅读此文档
请先按照下面流程安装文件夹里的字体包。
1. 打开字体文件夹根据不同系统需要选择OTF或TTF版本
2. 字体所包含只有一个字重(双击安装)。

View File

@@ -0,0 +1,15 @@
阿里妈妈数黑体法律声明
1. 阿里妈妈数黑体字体及包含该字体的字库软件,合称“阿里妈妈数黑体”。
2. 阿里妈妈数黑体的知识产权和相关权益归属于淘宝(中国)软件有限公司(以下简称“阿里妈妈”),受《中华人民共和国著作权法》及其他适用法律法规、国际公约、条约的保护。
3. 阿里妈妈授权个人、企业等用户在遵守本声明相关条款的前提下可以下载、安装和使用上述阿里妈妈字体该授权是免费的普通许可用户可基于合法目的用于商业用途或非商业用途但不得以任何违反本声明第4条及法律法规、政策、规章或公序良俗的方式使用。
4. 除本法律声明中明确授权之外阿里妈妈未授予用户关于阿里妈妈数黑体的其他权利。未经阿里妈妈授权任何人不得1对阿里妈妈数黑体进行仿制、转换、翻译、反编译、反向工程、拆分、破解或以其他方式试图从该字库软件获取源代码2删除、覆盖或修改阿里妈妈数黑体法律声明的全部或部分内容3将阿里妈妈数黑体进行单独定价出售、出租、出借、转让、转授权、或采取其他未经阿里妈妈授权的行为4) 发布任何使外界误认其与阿里妈妈或其关联公司存在合作、赞助或背书等商业关联的不实信息。
5. 阿里妈妈授予用户的上述授权不附带任何明示或暗示的保证,不对任何人因从非阿里妈妈官方渠道或指定渠道下载、安装或使用阿里妈妈数黑体而引发的任何直接或间接损失承担责任。
6. 本声明的解释、履行与争议解决适用中华人民共和国的法律。用户与阿里妈妈就阿里妈妈数黑体的使用若发生争议,双方应友好协商,若协商不成,任一方有权向浙江省杭州市有管辖权的人民法院提起诉讼。
反馈与咨询联系方alimama-font@list.alibaba-inc.com

View File

@@ -93,6 +93,7 @@
// 明确默认状态样式(关键修复)
background: transparent !important;
box-shadow: none !important;
position: relative;
overflow: hidden !important;
text-overflow: ellipsis !important;
@@ -303,4 +304,18 @@
#app .sidebar-container .nest-menu .el-submenu .el-submenu__title {
margin: 0 4px;
}
}
// 子菜单标识图标
.submenu-indicator {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
display: inline-flex;
align-items: center;
opacity: 0.5;
font-size: 12px;
}
// 叶子页面无标识

View File

@@ -1,11 +1,28 @@
<template>
<div class="template-manager">
<div class="left-panel">
<div class="custom-tabs">
<div
:class="['custom-tab', { active: activeTab === 'shared' }]"
@click="switchTab('shared')"
>共享模板</div>
<div
:class="['custom-tab', { active: activeTab === 'personal' }]"
@click="switchTab('personal')"
>自用模板</div>
</div>
<div class="panel-header">
<span class="panel-title">模板列表</span>
<el-button icon="el-icon-plus" size="mini" type="primary" @click="addTemplate">新增</el-button>
<div class="panel-header-actions">
<el-button icon="el-icon-plus" size="mini" type="primary" @click="addTemplate">新增</el-button>
<el-button icon="el-icon-download" size="mini" type="success" @click="exportCsv" :disabled="!currentTemplate.id">导出</el-button>
<el-button icon="el-icon-upload2" size="mini" type="info" @click="importCsv">导入</el-button>
</div>
</div>
<div class="template-list">
<div class="shared-toolbar" v-show="activeTab === 'shared'">
<el-input v-model="sharedQueryParams.templateName" placeholder="搜索模板名称" size="small" clearable prefix-icon="el-icon-search" @input="handleSearchTemplate" style="width: 200px;" />
</div>
<div class="template-list" v-loading="templateLoading">
<div
v-for="template in templateList"
:key="template.id"
@@ -25,7 +42,18 @@
<el-empty description="暂无模板" />
</div>
</div>
<div class="shared-pagination" v-show="activeTab === 'shared'">
<el-pagination
background
layout="prev, pager, next"
:current-page="sharedQueryParams.pageNum"
:page-size="sharedQueryParams.pageSize"
:total="sharedTotal"
@current-change="handleSharedPageChange"
/>
</div>
</div>
<input type="file" ref="csvInput" accept=".csv" style="display:none" @change="handleCsvImport" />
<div class="right-panel">
<div class="panel-header">
<span class="panel-title">员工配置</span>
@@ -62,6 +90,8 @@
</template>
<script>
import { listAttendanceTemplate, addAttendanceTemplate, updateAttendanceTemplate, delAttendanceTemplate } from '@/api/wms/attendanceTemplate'
export default {
name: 'AttendanceTemplateManager',
props: {
@@ -72,7 +102,16 @@ export default {
},
data() {
return {
templateList: [],
activeTab: 'shared',
sharedTemplateList: [],
sharedTemplateLoading: false,
sharedQueryParams: {
pageNum: 1,
pageSize: 20,
templateName: ''
},
sharedTotal: 0,
personalTemplateList: [],
currentTemplate: {
id: '',
name: '',
@@ -83,22 +122,202 @@ export default {
selectedEmployeeIds: [],
}
},
computed: {
templateList() {
return this.activeTab === 'shared' ? this.sharedTemplateList : this.personalTemplateList
},
templateLoading() {
return this.activeTab === 'shared' ? this.sharedTemplateLoading : false
}
},
mounted() {
this.loadTemplates()
},
methods: {
loadTemplates() {
try {
const templates = localStorage.getItem('attendanceTemplates')
this.templateList = templates ? JSON.parse(templates) : []
} catch (e) {
this.templateList = []
if (this.activeTab === 'shared') {
this.sharedTemplateLoading = true
const query = {
pageNum: this.sharedQueryParams.pageNum,
pageSize: this.sharedQueryParams.pageSize
}
if (this.sharedQueryParams.templateName) {
query.templateName = this.sharedQueryParams.templateName
}
listAttendanceTemplate(query).then(res => {
this.sharedTemplateList = (res.rows || []).map(row => ({
id: row.templateId,
name: row.templateName,
employeeIds: this.parseTemplateContent(row.templateContent),
employeeCount: this.parseTemplateContent(row.templateContent).length,
createTime: row.createTime
}))
this.sharedTotal = res.total || 0
}).finally(() => {
this.sharedTemplateLoading = false
})
} else {
try {
const templates = localStorage.getItem('attendanceTemplates')
this.personalTemplateList = templates ? JSON.parse(templates) : []
} catch (e) {
this.personalTemplateList = []
}
}
},
saveTemplates() {
localStorage.setItem('attendanceTemplates', JSON.stringify(this.templateList))
this.$emit('update')
parseTemplateContent(content) {
if (!content) return []
try {
const parsed = JSON.parse(content)
return Array.isArray(parsed) ? parsed : []
} catch (e) {
return content.split(',').filter(Boolean)
}
},
buildTemplateContent(employeeIds) {
return JSON.stringify(employeeIds)
},
handleSearchTemplate() {
this.sharedQueryParams.pageNum = 1
this.loadTemplates()
},
handleSharedPageChange(pageNum) {
this.sharedQueryParams.pageNum = pageNum
this.loadTemplates()
},
switchTab(tab) {
if (this.activeTab === tab) return
this.activeTab = tab
this.loadTemplates()
this.resetForm()
},
savePersonalTemplates() {
localStorage.setItem('attendanceTemplates', JSON.stringify(this.personalTemplateList))
},
exportCsv() {
if (!this.currentTemplate.id || !this.currentTemplate.employeeIds.length) {
this.$message.warning('当前模板没有员工可导出')
return
}
const empMap = {}
this.employeeList.forEach(emp => {
empMap[emp.key] = emp.label
})
let csvContent = '\uFEFF员工ID,员工姓名\n'
this.currentTemplate.employeeIds.forEach(id => {
const name = empMap[id] || id
csvContent += `${id},${name}\n`
})
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })
const link = document.createElement('a')
const url = URL.createObjectURL(blob)
link.setAttribute('href', url)
link.setAttribute('download', `${this.currentTemplate.name}.csv`)
link.style.visibility = 'hidden'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
},
importCsv() {
this.$refs.csvInput.click()
},
handleCsvImport(event) {
const file = event.target.files[0]
if (!file) return
const reader = new FileReader()
reader.onload = async (e) => {
const content = e.target.result
const lines = content.split('\n').filter(line => line.trim())
if (lines.length === 0) {
this.$message.warning('CSV文件内容为空')
event.target.value = ''
return
}
const header = lines[0].trim()
if (header !== '员工ID,员工姓名' && header !== '员工ID\t员工姓名') {
this.$message.warning('CSV文件格式不正确表头应为"员工ID,员工姓名"')
event.target.value = ''
return
}
const empKeySet = new Set()
const empLabelMap = {}
this.employeeList.forEach(emp => {
empKeySet.add(String(emp.key))
empLabelMap[emp.label] = emp.key
})
const matchedIds = []
const notFoundNames = []
const lines_data = lines.slice(1)
for (const line of lines_data) {
const trimmed = line.trim()
if (!trimmed) continue
const parts = trimmed.includes('\t') ? trimmed.split('\t') : trimmed.split(',')
const key = parts[0] ? parts[0].trim() : ''
const label = parts.length > 1 ? parts.slice(1).join(',').trim() : key
if (key && empKeySet.has(String(key))) {
matchedIds.push(key)
} else if (label && empLabelMap[label] !== undefined) {
matchedIds.push(empLabelMap[label])
} else {
notFoundNames.push(label || key)
}
}
if (matchedIds.length === 0) {
this.$message.warning('CSV文件中没有匹配到任何员工')
event.target.value = ''
return
}
const templateName = file.name.replace(/\.csv$/i, '')
if (this.activeTab === 'shared') {
await addAttendanceTemplate({
templateName: templateName,
templateContent: this.buildTemplateContent(matchedIds)
})
this.loadTemplates()
const newTemplate = this.sharedTemplateList.find(t => t.name === templateName)
if (newTemplate) {
this.currentTemplate = JSON.parse(JSON.stringify(newTemplate))
this.selectedEmployeeIds = [...newTemplate.employeeIds]
}
} else {
const templateData = {
id: Date.now().toString(),
name: templateName,
employeeIds: matchedIds,
employeeCount: matchedIds.length,
createTime: new Date().toLocaleString('zh-CN')
}
this.personalTemplateList.push(templateData)
this.savePersonalTemplates()
this.currentTemplate = JSON.parse(JSON.stringify(templateData))
this.selectedEmployeeIds = [...matchedIds]
}
this.$emit('update')
if (notFoundNames.length > 0) {
this.$message.warning(`成功导入${matchedIds.length}名员工,${notFoundNames.length}名未匹配:${notFoundNames.join('、')}`)
} else {
this.$message.success(`成功导入${matchedIds.length}名员工`)
}
}
reader.readAsText(file, 'UTF-8')
event.target.value = ''
},
addTemplate() {
@@ -118,20 +337,29 @@ export default {
},
deleteTemplate(template) {
this.$confirm('确定删除?', '提示', {
const confirmMsg = this.activeTab === 'shared'
? '删除后该模板所有人都无法使用,确定删除?'
: '确定删除?'
this.$confirm(confirmMsg, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const index = this.templateList.findIndex(t => t.id === template.id)
if (index > -1) {
this.templateList.splice(index, 1)
this.saveTemplates()
this.$message.success('删除成功')
if (this.currentTemplate.id === template.id) {
this.resetForm()
}).then(async () => {
if (this.activeTab === 'shared') {
await delAttendanceTemplate(template.id)
} else {
const index = this.personalTemplateList.findIndex(t => t.id === template.id)
if (index > -1) {
this.personalTemplateList.splice(index, 1)
this.savePersonalTemplates()
}
}
this.$message.success('删除成功')
if (this.currentTemplate.id === template.id) {
this.resetForm()
}
this.loadTemplates()
this.$emit('update')
}).catch(() => {
this.$message.info('已取消')
})
@@ -142,32 +370,52 @@ export default {
this.selectedEmployeeIds = [...template.employeeIds]
},
saveTemplate() {
async saveTemplate() {
if (!this.currentTemplate.name.trim()) {
this.$message.warning('请输入模板名称')
return
}
const templateData = {
id: this.currentTemplate.id || Date.now().toString(),
name: this.currentTemplate.name.trim(),
employeeIds: [...this.selectedEmployeeIds],
employeeCount: this.selectedEmployeeIds.length,
createTime: this.currentTemplate.id ? this.currentTemplate.createTime : new Date().toLocaleString('zh-CN')
}
if (this.currentTemplate.id) {
const index = this.templateList.findIndex(t => t.id === this.currentTemplate.id)
if (index > -1) {
this.templateList[index] = templateData
if (this.activeTab === 'shared') {
const apiData = {
templateName: this.currentTemplate.name.trim(),
templateContent: this.buildTemplateContent(this.selectedEmployeeIds)
}
this.$message.success('修改成功')
} else {
this.templateList.push(templateData)
this.$message.success('新增成功')
}
this.saveTemplates()
if (this.currentTemplate.id) {
apiData.templateId = this.currentTemplate.id
await updateAttendanceTemplate(apiData)
this.$message.success('修改成功')
} else {
await addAttendanceTemplate(apiData)
this.$message.success('新增成功')
}
this.loadTemplates()
this.$emit('update')
} else {
const templateData = {
id: this.currentTemplate.id || Date.now().toString(),
name: this.currentTemplate.name.trim(),
employeeIds: [...this.selectedEmployeeIds],
employeeCount: this.selectedEmployeeIds.length,
createTime: this.currentTemplate.id ? this.currentTemplate.createTime : new Date().toLocaleString('zh-CN')
}
if (this.currentTemplate.id) {
const index = this.personalTemplateList.findIndex(t => t.id === this.currentTemplate.id)
if (index > -1) {
this.personalTemplateList[index] = templateData
}
this.$message.success('修改成功')
} else {
this.personalTemplateList.push(templateData)
this.$message.success('新增成功')
}
this.savePersonalTemplates()
this.$emit('update')
}
},
resetForm() {
@@ -220,6 +468,21 @@ export default {
color: #303133;
}
.panel-header-actions {
display: flex;
gap: 6px;
}
.shared-toolbar {
margin-bottom: 10px;
}
.shared-pagination {
display: flex;
justify-content: center;
padding: 10px 0 4px;
}
.template-list {
flex: 1;
overflow-y: auto;
@@ -315,4 +578,31 @@ export default {
padding-top: 10px;
border-top: 1px solid #e4e7ed;
}
.custom-tabs {
display: flex;
border-bottom: 1px solid #e4e7ed;
margin-bottom: 12px;
}
.custom-tab {
padding: 6px 14px;
font-size: 13px;
color: #909399;
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
transition: color 0.2s, border-color 0.2s;
user-select: none;
}
.custom-tab:hover {
color: #606266;
}
.custom-tab.active {
color: #1890ff;
border-bottom-color: #1890ff;
font-weight: 500;
}
</style>

View File

@@ -201,9 +201,9 @@ export const optionalColumns = [
{ label: '表面处理', value: 'surfaceTreatmentDesc' },
{ label: '镀层质量', value: 'zincLayer' },
{ label: '实测长度', value: 'actualLength' },
{ label: '论长度', value: 'theoreticalLength' },
{ label: '论长度', value: 'theoreticalLength' },
{ label: '实测厚度', value: 'actualThickness' },
{ label: '论厚度', value: 'theoreticalThickness' },
{ label: '论厚度', value: 'theoreticalThickness' },
{ label: '实测宽度', value: 'actualWidth' },
{ label: '毛重', value: 'grossWeight' },
{ label: '净重', value: 'netWeight' },

View File

@@ -0,0 +1,563 @@
<template>
<el-dialog title="综合导入" :visible.sync="dialogVisible" width="1200px" top="3vh" append-to-body @close="handleClose">
<div class="import-container">
<div class="import-steps">
<div class="step" :class="{ active: true, done: importStatus !== 'idle' && importStatus !== 'validated' }">
<div class="step-badge">1</div>
<div class="step-label">下载模板</div>
</div>
<div class="step-connector" :class="{ done: importStatus !== 'idle' }" />
<div class="step" :class="{ active: importStatus === 'validated' || importStatus === 'processing' || importStatus === 'finished', done: importStatus !== 'idle' && importStatus !== 'validated' }">
<div class="step-badge">2</div>
<div class="step-label">上传文件</div>
</div>
<div class="step-connector" :class="{ done: importStatus === 'processing' || importStatus === 'finished' }" />
<div class="step" :class="{ active: importStatus === 'validated' || importStatus === 'processing' || importStatus === 'finished', done: importStatus === 'processing' || importStatus === 'finished' }">
<div class="step-badge">3</div>
<div class="step-label">校验数据</div>
</div>
<div class="step-connector" :class="{ done: importStatus === 'processing' || importStatus === 'finished' }" />
<div class="step" :class="{ active: importStatus === 'processing' || importStatus === 'finished', done: importStatus === 'finished' }">
<div class="step-badge step-badge-success">4</div>
<div class="step-label">批量导入</div>
</div>
</div>
<div class="import-toolbar">
<div class="toolbar-left">
<el-upload ref="importUpload" action="" :auto-upload="false" :show-file-list="false"
:on-change="handleFileChange" accept=".xlsx,.xls"
:disabled="importStatus !== 'idle' && importStatus !== 'validated'">
<el-button :type="importFile ? 'default' : 'primary'" :icon="importFile ? 'el-icon-document' : 'el-icon-upload2'">
{{ importFile ? importFile.name : '选择Excel文件' }}
</el-button>
</el-upload>
<el-button type="success" plain icon="el-icon-check" @click="handleValidate"
:disabled="!importFile || validateLoading || importStatus !== 'idle'" :loading="validateLoading">校验数据</el-button>
</div>
<div class="toolbar-right">
<el-button v-if="importStatus === 'validated'" type="primary" icon="el-icon-upload-success" @click="startImport" :loading="importLoading">开始导入</el-button>
<el-button plain icon="el-icon-download" @click="downloadTemplate">下载模板</el-button>
<el-button plain icon="el-icon-refresh" @click="resetImport">重置</el-button>
</div>
</div>
<div v-if="importTableData.length > 0" class="data-preview">
<el-tabs v-model="activeTab" type="card">
<el-tab-pane label="化学成分" name="chem">
<el-table ref="chemTable" :data="chemPreviewData" border size="small" max-height="300" stripe>
<el-table-column label="#" width="48" type="index" align="center" />
<el-table-column prop="coilNo" label="入场钢卷号" width="140" />
<el-table-column prop="supplierCoilNo" label="厂家卷号" width="120" />
<el-table-column prop="c" label="C(%)" width="70" align="center" />
<el-table-column prop="si" label="Si(%)" width="70" align="center" />
<el-table-column prop="mn" label="Mn(%)" width="70" align="center" />
<el-table-column prop="p" label="P(%)" width="70" align="center" />
<el-table-column prop="s" label="S(%)" width="70" align="center" />
<el-table-column prop="als" label="Als(%)" width="70" align="center" />
<el-table-column prop="al" label="Al(%)" width="70" align="center" />
<el-table-column prop="ti" label="Ti(%)" width="70" align="center" />
<el-table-column prop="cr" label="Cr(%)" width="70" align="center" />
<el-table-column prop="ni" label="Ni(%)" width="70" align="center" />
<el-table-column prop="cu" label="Cu(%)" width="70" align="center" />
<el-table-column prop="n" label="N(%)" width="70" align="center" />
<el-table-column prop="fe" label="Fe(%)" width="70" align="center" />
<el-table-column prop="b" label="B(%)" width="70" align="center" />
</el-table>
</el-tab-pane>
<el-tab-pane label="物理性能" name="phys">
<el-table ref="physTable" :data="physPreviewData" border size="small" max-height="300" stripe>
<el-table-column label="#" width="48" type="index" align="center" />
<el-table-column prop="coilNo" label="入场钢卷号" width="140" />
<el-table-column prop="supplierCoilNo" label="厂家卷号" width="120" />
<el-table-column prop="yieldStrength" label="屈服强度(MPa)" width="110" align="center" />
<el-table-column prop="tensileStrength" label="抗拉强度(MPa)" width="110" align="center" />
<el-table-column prop="elongation" label="伸长率(%)" width="80" align="center" />
<el-table-column prop="plasticExtensionStrength" label="规定塑性延伸强度(MPa)" width="120" align="center" />
<el-table-column prop="hardness" label="硬度(HRB)" width="80" align="center" />
<el-table-column prop="coatingMass" label="镀层重量(g/m²)" width="100" align="center" />
<el-table-column prop="bendingTest" label="弯曲试验" width="80" align="center" />
<el-table-column prop="surfaceQuality" label="表面质量" width="80" align="center" />
<el-table-column prop="surfaceStructure" label="表面结构" width="80" align="center" />
<el-table-column prop="coatingSurfaceStructure" label="镀层表面结构" width="90" align="center" />
<el-table-column prop="edgeStatus" label="边缘状态" width="80" align="center" />
</el-table>
</el-tab-pane>
</el-tabs>
</div>
<div v-if="importStatus === 'processing'" class="import-progress">
<div class="progress-header">
<i class="el-icon-loading" />
<span>正在批量导入数据请稍候...</span>
</div>
<el-progress :percentage="importProgress" :stroke-width="8" />
<div style="margin-top: 8px; font-size: 12px; color: #606266;">
化学成分: {{ chemImportedCount }} / {{ chemTotalCount }} &nbsp;&nbsp; 物理性能: {{ physImportedCount }} / {{ physTotalCount }}
</div>
</div>
<div v-if="importStatus === 'finished'" class="result-panel result-success">
<div class="result-icon"><i class="el-icon-circle-check" /></div>
<div class="result-body">
<div class="result-title">导入完成</div>
<div class="result-desc">
共成功导入 <b>{{ chemImportedCount }}</b> 条化学成分数据<b>{{ physImportedCount }}</b> 条物理性能数据
</div>
</div>
</div>
<div v-if="importStatus === 'error'" class="result-panel result-error">
<div class="result-icon"><i class="el-icon-circle-close" /></div>
<div class="result-body">
<div class="result-title">导入失败</div>
<div class="result-desc">{{ importErrorMsg }}</div>
</div>
</div>
</div>
<el-dialog title="选择对应入场卷号" :visible.sync="ambiguousVisible" width="600px" append-to-body :close-on-click-modal="false">
<div style="font-size: 12px; color: #909399; margin-bottom: 12px;">
厂家卷号匹配到多条入场卷号请为每行选择对应记录
</div>
<el-table :data="ambiguousRows" border size="small" max-height="350">
<el-table-column label="厂家卷号" prop="supplierCoilNo" width="140" />
<el-table-column label="选择入场卷号" min-width="280">
<template slot-scope="scope">
<el-select v-model="scope.row.selected" placeholder="请选择入场卷号" size="small" style="width: 100%;">
<el-option
v-for="opt in scope.row.options"
:key="opt"
:label="opt"
:value="opt"
/>
</el-select>
</template>
</el-table-column>
</el-table>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="confirmAmbiguous"> </el-button>
<el-button @click="ambiguousVisible = false"> </el-button>
</div>
</el-dialog>
</el-dialog>
</template>
<script>
import * as XLSX from 'xlsx';
import { batchAddChemicalItem } from "@/api/mes/qc/chemicalItem";
import { batchAddPhysicalItem } from "@/api/mes/qc/physicalItem";
import { listMaterialCoil } from "@/api/wms/coil";
const TEMPLATE_HEADERS = [
'入场钢卷号', '厂家卷号',
'C(%)', 'Si(%)', 'Mn(%)', 'P(%)', 'S(%)', 'Als(%)', 'Al(%)', 'Ti(%)', 'Cr(%)', 'Ni(%)', 'Cu(%)', 'N(%)', 'Fe(%)', 'B(%)',
'屈服强度(MPa)', '抗拉强度(MPa)', '伸长率(%)', '规定塑性延伸强度(MPa)', '硬度(HRB)', '镀层重量(g/m²)',
'弯曲试验', '表面质量', '表面结构', '镀层表面结构', '边缘状态'
];
const HEADER_MAP = {
'入场钢卷号': 'coilNo',
'厂家卷号': 'supplierCoilNo',
'C(%)': 'c', 'Si(%)': 'si', 'Mn(%)': 'mn', 'P(%)': 'p', 'S(%)': 's',
'Als(%)': 'als', 'Al(%)': 'al', 'Ti(%)': 'ti', 'Cr(%)': 'cr', 'Ni(%)': 'ni',
'Cu(%)': 'cu', 'N(%)': 'n', 'Fe(%)': 'fe', 'B(%)': 'b',
'屈服强度(MPa)': 'yieldStrength', '抗拉强度(MPa)': 'tensileStrength', '伸长率(%)': 'elongation',
'规定塑性延伸强度(MPa)': 'plasticExtensionStrength', '硬度(HRB)': 'hardness',
'镀层重量(g/m²)': 'coatingMass', '弯曲试验': 'bendingTest', '表面质量': 'surfaceQuality',
'表面结构': 'surfaceStructure', '镀层表面结构': 'coatingSurfaceStructure', '边缘状态': 'edgeStatus'
};
const CHEM_FIELDS = ['c', 'si', 'mn', 'p', 's', 'als', 'al', 'ti', 'cr', 'ni', 'cu', 'n', 'fe', 'b'];
const PHYS_FIELDS = ['yieldStrength', 'tensileStrength', 'elongation', 'plasticExtensionStrength', 'hardness', 'coatingMass', 'bendingTest', 'surfaceQuality', 'surfaceStructure', 'coatingSurfaceStructure', 'edgeStatus'];
export default {
name: "CombinedImport",
props: {
visible: { type: Boolean, default: false }
},
data() {
return {
importFile: null,
importRawData: [],
importTableData: [],
importErrorList: [],
importProgress: 0,
importStatus: 'idle',
importErrorMsg: '',
validateLoading: false,
importLoading: false,
ambiguousVisible: false,
ambiguousRows: [],
activeTab: 'chem',
chemImportedCount: 0,
physImportedCount: 0,
chemTotalCount: 0,
physTotalCount: 0
};
},
computed: {
dialogVisible: {
get() { return this.visible; },
set(val) { this.$emit('update:visible', val); }
},
chemPreviewData() {
return this.importTableData.map(row => {
const item = { coilNo: row.coilNo, supplierCoilNo: row.supplierCoilNo };
CHEM_FIELDS.forEach(f => { item[f] = row[f] || ''; });
return item;
});
},
physPreviewData() {
return this.importTableData.map(row => {
const item = { coilNo: row.coilNo, supplierCoilNo: row.supplierCoilNo };
PHYS_FIELDS.forEach(f => { item[f] = row[f] || ''; });
return item;
});
},
hasChemData() {
return this.importTableData.some(row => CHEM_FIELDS.some(f => row[f]));
},
hasPhysData() {
return this.importTableData.some(row => PHYS_FIELDS.some(f => row[f]));
}
},
methods: {
handleClose() {
this.resetImport();
this.$emit('close');
},
handleFileChange(file) {
if (this.validateLoading || this.importLoading) return;
this.importFile = file.raw;
this.importErrorList = [];
this.importStatus = 'idle';
this.readExcel();
},
async readExcel() {
if (!this.importFile) return;
try {
const reader = new FileReader();
reader.readAsArrayBuffer(this.importFile);
reader.onload = async (e) => {
try {
const data = new Uint8Array(e.target.result);
const wb = XLSX.read(data, { type: 'array' });
const ws = wb.Sheets[wb.SheetNames[0]];
const json = XLSX.utils.sheet_to_json(ws, { header: 1 });
this.validateHeaders(json[0]);
this.importRawData = json.slice(1).filter(r => r.some(c => c != null && c !== ''));
this.formatExcel();
this.$message.success(`成功解析Excel共读取到 ${this.importRawData.length} 条数据`);
} catch (err) { this.handleError('解析Excel失败' + err.message); }
};
} catch (err) { this.handleError('读取文件失败:' + err.message); }
},
validateHeaders(headers) {
this.importErrorList = [];
if (!headers || headers.length < TEMPLATE_HEADERS.length) {
this.importErrorList.push({ rowNum: 1, errorMsg: `表头数量不匹配,要求至少${TEMPLATE_HEADERS.length}` });
return;
}
TEMPLATE_HEADERS.forEach((h, i) => {
if (headers[i] !== h) this.importErrorList.push({ rowNum: 1, errorMsg: `${i + 1}列表头错误,要求:"${h}",实际:"${headers[i] || ''}"` });
});
if (this.importErrorList.length > 0) this.$message.error('Excel表头格式不符合要求请检查');
},
formatExcel() {
this.importTableData = [];
if (!this.importRawData.length) return;
this.importRawData.forEach((row, i) => {
const obj = {};
TEMPLATE_HEADERS.forEach((h, j) => { obj[HEADER_MAP[h]] = row[j] != null ? String(row[j]).trim() : ''; });
obj.rowNum = i + 2;
obj._status = 'pending';
this.importTableData.push(obj);
});
},
async handleValidate() {
if (!this.importFile || !this.importRawData.length) { this.$message.warning('暂无数据可校验'); return; }
this.validateLoading = true;
this.importErrorList = [];
this.ambiguousRows = [];
const dataRows = this.importRawData;
for (let i = 0; i < dataRows.length; i++) {
const rowNum = i + 2;
let coilNo = '', supplierCoilNo = '';
TEMPLATE_HEADERS.forEach((h, j) => {
if (HEADER_MAP[h] === 'coilNo') coilNo = dataRows[i][j];
if (HEADER_MAP[h] === 'supplierCoilNo') supplierCoilNo = dataRows[i][j];
});
coilNo = String(coilNo || '').trim();
supplierCoilNo = String(supplierCoilNo || '').trim();
if (!coilNo && !supplierCoilNo) {
this.importErrorList.push({ rowNum, errorMsg: '入场钢卷号和厂家卷号不能同时为空' });
}
}
if (this.importErrorList.length === 0) {
this.importTableData.forEach((row, idx) => {
const cn = (row.coilNo || '').trim();
const sn = (row.supplierCoilNo || '').trim();
row._sno = sn;
row._idx = idx;
row._fillCoilNo = cn;
if (sn && !cn) row._needMatch = true;
});
const needMatchRows = this.importTableData.filter(r => r._needMatch);
if (needMatchRows.length > 0) {
const uniqueSnos = [...new Set(needMatchRows.map(r => r._sno))];
const multiMap = {};
try {
const results = await Promise.all(
uniqueSnos.map(sno => listMaterialCoil({ supplierCoilNo: sno, pageNum: 1, pageSize: 50 }))
);
uniqueSnos.forEach((sno, idx) => {
const rows = (results[idx] && results[idx].rows) || [];
const enterNos = [...new Set(rows.map(r => r.enterCoilNo).filter(Boolean))];
multiMap[sno] = enterNos;
});
} catch (err) {
this.validateLoading = false;
this.handleError('厂家卷号匹配失败:' + err.message);
return;
}
const ambiguousList = [];
needMatchRows.forEach(row => {
const candidates = multiMap[row._sno] || [];
if (candidates.length === 0) {
this.importErrorList.push({ rowNum: (row.rowNum || (row._idx + 2)), errorMsg: `厂家卷号"${row._sno}"未匹配到入场卷号` });
} else if (candidates.length === 1) {
row.coilNo = candidates[0];
} else {
ambiguousList.push({
_idx: row._idx,
supplierCoilNo: row._sno,
options: candidates,
selected: null
});
}
});
if (ambiguousList.length > 0) {
this.ambiguousRows = ambiguousList;
this.validateLoading = false;
this.ambiguousVisible = true;
return;
}
}
}
this.finishValidation();
},
confirmAmbiguous() {
const unselected = this.ambiguousRows.filter(r => !r.selected);
if (unselected.length > 0) {
this.$message.warning('请为所有行选择入场卷号');
return;
}
this.ambiguousRows.forEach(item => {
this.importTableData[item._idx].coilNo = item.selected;
});
this.ambiguousVisible = false;
this.validateLoading = true;
this.finishValidation();
},
finishValidation() {
if (this.importErrorList.length > 0) {
this.$message.error(`数据校验失败,共发现${this.importErrorList.length}条错误`);
} else {
this.importTableData.forEach(row => { row._status = 'valid'; });
const hasChem = this.importTableData.some(r => CHEM_FIELDS.some(f => r[f]));
const hasPhys = this.importTableData.some(r => PHYS_FIELDS.some(f => r[f]));
if (!hasChem && !hasPhys) {
this.$message.warning('Excel中没有填写任何化学成分或物理性能数据');
} else {
this.$message.success('数据校验通过');
this.importStatus = 'validated';
}
}
this.validateLoading = false;
},
async startImport() {
const rows = this.importTableData.filter(r => r._status === 'valid');
if (!rows.length) { this.$message.warning('没有可导入的数据'); return; }
const chemRows = rows.filter(r => CHEM_FIELDS.some(f => r[f]));
const physRows = rows.filter(r => PHYS_FIELDS.some(f => r[f]));
if (!chemRows.length && !physRows.length) {
this.$message.warning('没有可导入的数据');
return;
}
let confirmMsg = '确认导入以下数据?';
if (chemRows.length) confirmMsg += ` 化学成分${chemRows.length}`;
if (physRows.length) confirmMsg += ` 物理性能${physRows.length}`;
const ok = await this.$confirm(confirmMsg, '导入确认', { confirmButtonText: '确认导入', cancelButtonText: '取消', type: 'warning' }).catch(() => false);
if (!ok) return;
this.importLoading = true;
this.importStatus = 'processing';
this.importProgress = 0;
this.chemTotalCount = chemRows.length;
this.physTotalCount = physRows.length;
this.chemImportedCount = 0;
this.physImportedCount = 0;
this.importErrorMsg = '';
try {
const promises = [];
if (chemRows.length) {
const chemPayload = chemRows.map(row => {
const item = { coilId: null, coilNo: row.coilNo };
CHEM_FIELDS.forEach(f => { if (row[f]) item[f] = row[f]; });
return item;
});
promises.push(
batchAddChemicalItem(chemPayload).then(res => {
if (res.code !== 200) throw new Error(res.msg || '化学成分批量导入失败');
this.chemImportedCount = chemPayload.length;
this.importProgress = 50;
})
);
}
if (physRows.length) {
const physPayload = physRows.map(row => {
const item = { coilId: null, coilNo: row.coilNo };
PHYS_FIELDS.forEach(f => { if (row[f]) item[f] = row[f]; });
return item;
});
promises.push(
batchAddPhysicalItem(physPayload).then(res => {
if (res.code !== 200) throw new Error(res.msg || '物理性能批量导入失败');
this.physImportedCount = physPayload.length;
this.importProgress = 100;
})
);
}
await Promise.all(promises);
this.importStatus = 'finished';
this.importProgress = 100;
this.$message.success(`导入完成!化学成分${this.chemImportedCount}条,物理性能${this.physImportedCount}`);
this.$emit('success');
} catch (err) {
this.handleError(err.message);
} finally {
this.importLoading = false;
}
},
resetImport() {
if (this.validateLoading || this.importLoading || this.importStatus === 'processing') { this.$message.warning('当前有操作正在进行中'); return; }
this.importFile = null;
this.importRawData = [];
this.importTableData = [];
this.importErrorList = [];
this.importProgress = 0;
this.importStatus = 'idle';
this.importErrorMsg = '';
this.chemImportedCount = 0;
this.physImportedCount = 0;
this.chemTotalCount = 0;
this.physTotalCount = 0;
this.activeTab = 'chem';
this.$refs.importUpload?.clearFiles();
},
downloadTemplate() {
const sampleRow = [
'示例卷号', '示例厂家卷号',
'0.05', '0.02', '0.30', '0.015', '0.008', '0.040', '0.04', '0.05', '0.03', '0.02', '0.03', '0.005', '98', '0.001',
'300', '420', '35', '260', '85', '275', '合格', '良好', '光面', '无锌花', '良好'
];
const wb = XLSX.utils.book_new();
const ws = XLSX.utils.aoa_to_sheet([TEMPLATE_HEADERS, sampleRow]);
ws['!cols'] = [
{ wch: 16 }, { wch: 16 },
{ wch: 8 }, { wch: 8 }, { wch: 8 }, { wch: 8 }, { wch: 8 }, { wch: 8 }, { wch: 8 }, { wch: 8 }, { wch: 8 }, { wch: 8 }, { wch: 8 }, { wch: 8 }, { wch: 8 }, { wch: 8 },
{ wch: 16 }, { wch: 16 }, { wch: 10 }, { wch: 20 }, { wch: 10 }, { wch: 16 },
{ wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 12 }, { wch: 10 }
];
XLSX.utils.book_append_sheet(wb, ws, '综合导入模板');
XLSX.writeFile(wb, '综合导入模板.xlsx');
},
handleError(msg) {
this.$message.error(msg);
this.importStatus = 'error';
this.importErrorMsg = msg;
this.validateLoading = false;
this.importLoading = false;
}
}
};
</script>
<style scoped>
.import-container { padding: 0 4px; }
.import-steps {
display: flex; align-items: center; justify-content: center;
margin-bottom: 24px; padding: 20px 0 16px;
border-bottom: 1px solid #f0f0f0;
}
.step {
display: flex; flex-direction: column; align-items: center; gap: 6px;
opacity: 0.45; transition: all 0.3s;
}
.step.active { opacity: 1; }
.step.done { opacity: 0.65; }
.step-badge {
width: 32px; height: 32px; border-radius: 50%;
background: #dcdfe6; color: #fff;
display: flex; align-items: center; justify-content: center;
font-size: 14px; font-weight: 600; transition: all 0.3s;
}
.step.active .step-badge { background: #409eff; box-shadow: 0 2px 8px rgba(64,158,255,0.35); }
.step.done .step-badge { background: #67c23a; }
.step-badge-success { background: #67c23a !important; }
.step.active .step-badge-success { background: #67c23a !important; box-shadow: 0 2px 8px rgba(103,194,58,0.35) !important; }
.step-label { font-size: 12px; color: #606266; white-space: nowrap; }
.step.active .step-label { color: #303133; font-weight: 600; }
.step-connector {
width: 48px; height: 2px; background: #dcdfe6;
margin: 0 4px; margin-bottom: 24px; transition: all 0.3s;
}
.step-connector.done { background: #67c23a; }
.import-toolbar {
display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap;
gap: 8px; margin-bottom: 16px; padding: 12px 16px;
background: #fafafa; border-radius: 8px; border: 1px solid #eee;
}
.toolbar-left, .toolbar-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.data-preview { margin-bottom: 12px; }
.import-progress {
padding: 24px; background: #f6ffed; border-radius: 8px;
border: 1px solid #b7eb8f; margin-bottom: 12px;
}
.progress-header {
display: flex; align-items: center; gap: 8px;
margin-bottom: 12px; font-size: 14px; color: #52c41a; font-weight: 500;
}
.result-panel {
display: flex; align-items: center; gap: 16px;
padding: 20px 24px; border-radius: 8px; margin-bottom: 12px;
}
.result-success { background: #f6ffed; border: 1px solid #b7eb8f; }
.result-error { background: #fff2f0; border: 1px solid #ffa39e; }
.result-icon { font-size: 36px; line-height: 1; }
.result-success .result-icon { color: #52c41a; }
.result-error .result-icon { color: #ff4d4f; }
.result-title { font-size: 16px; font-weight: 600; margin-bottom: 4px; }
.result-success .result-title { color: #389e0d; }
.result-error .result-title { color: #cf1322; }
.result-desc { font-size: 13px; color: #606266; }
</style>

View File

@@ -1,25 +1,45 @@
<template>
<div :class="{'show':show}" class="header-search">
<div class="header-search">
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
<el-select
ref="headerSearchSelect"
v-model="search"
:remote-method="querySearch"
filterable
default-first-option
remote
placeholder="Search"
class="header-search-select"
@change="change"
<el-dialog
:visible.sync="show"
:close-on-click-modal="true"
width="560px"
append-to-body
:show-close="false"
custom-class="header-search-dialog"
@opened="$refs.searchInput && $refs.searchInput.focus()"
>
<el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
</el-select>
<div class="search-body">
<div class="search-input-wrap">
<svg-icon class-name="search-prefix" icon-class="search" />
<input
ref="searchInput"
v-model="search"
class="search-input"
placeholder="搜索菜单"
@input="querySearch($event.target.value)"
/>
</div>
<ul v-if="options.length" class="search-results">
<li
v-for="option in options"
:key="option.item.path"
class="search-result-item"
@click="change(option.item)"
>
<span>{{ option.item.title.join(' > ') }}</span>
</li>
</ul>
<div v-if="search && options.length === 0" class="no-result">
无匹配结果
</div>
</div>
</el-dialog>
</div>
</template>
<script>
// fuse is a lightweight fuzzy-search module
// make search results more in line with expectations
import Fuse from 'fuse.js/dist/fuse.min.js'
import path from 'path'
@@ -45,13 +65,6 @@ export default {
},
searchPool(list) {
this.initFuse(list)
},
show(value) {
if (value) {
document.body.addEventListener('click', this.close)
} else {
document.body.removeEventListener('click', this.close)
}
}
},
mounted() {
@@ -59,30 +72,20 @@ export default {
},
methods: {
click() {
this.show = !this.show
if (this.show) {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
}
},
close() {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
this.show = true
this.search = ''
this.options = []
this.show = false
},
change(val) {
const path = val.path;
if(this.ishttp(val.path)) {
// http(s):// 路径新窗口打开
const pindex = path.indexOf("http");
window.open(path.substr(pindex, path.length), "_blank");
if (this.ishttp(val.path)) {
const pindex = val.path.indexOf('http')
window.open(val.path.substr(pindex, val.path.length), '_blank')
} else {
this.$router.push(val.path)
}
this.show = false
this.search = ''
this.options = []
this.$nextTick(() => {
this.show = false
})
},
initFuse(list) {
this.fuse = new Fuse(list, {
@@ -100,13 +103,10 @@ export default {
}]
})
},
// Filter out the routes that can be displayed in the sidebar
// And generate the internationalized title
generateRoutes(routes, basePath = '/', prefixTitle = []) {
let res = []
for (const router of routes) {
// skip hidden router
if (router.hidden) { continue }
const data = {
@@ -118,13 +118,10 @@ export default {
data.title = [...data.title, router.meta.title]
if (router.redirect !== 'noRedirect') {
// only push the routes with title
// special case: need to exclude parent router without redirect
res.push(data)
}
}
// recursive child routes
if (router.children) {
const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
if (tempRoutes.length >= 1) {
@@ -150,39 +147,81 @@ export default {
<style lang="scss" scoped>
.header-search {
font-size: 0 !important;
.search-icon {
cursor: pointer;
font-size: 18px;
vertical-align: middle;
}
}
</style>
.header-search-select {
font-size: 18px;
transition: width 0.2s;
width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
display: inline-block;
vertical-align: middle;
<style lang="scss">
.header-search-dialog {
border-radius: 8px;
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;
padding-right: 0;
box-shadow: none !important;
border-bottom: 1px solid #d9d9d9;
vertical-align: middle;
}
.el-dialog__header {
padding: 0;
}
&.show {
.header-search-select {
width: 210px;
margin-left: 10px;
.el-dialog__body {
padding: 0;
}
.search-body {
.search-input-wrap {
display: flex;
align-items: center;
margin: 12px 20px;
padding-bottom: 12px;
border-bottom: 1px solid #e8e8e8;
.search-prefix {
font-size: 18px;
color: #999;
flex-shrink: 0;
margin-right: 12px;
}
.search-input {
flex: 1;
border: none;
outline: none;
font-size: 16px;
line-height: 32px;
height: 32px;
background: transparent;
&::placeholder {
color: #bfbfbf;
}
}
}
.search-results {
max-height: 360px;
overflow-y: auto;
padding: 0;
margin: 0;
list-style: none;
.search-result-item {
padding: 10px 20px;
cursor: pointer;
font-size: 14px;
color: #333;
transition: background 0.15s;
&:hover {
background: #f0f2f5;
}
}
}
.no-result {
padding: 32px 0;
text-align: center;
color: #999;
font-size: 14px;
}
}
}

View File

@@ -1,7 +1,14 @@
<template>
<div>
<div style="display: flex; align-items: center; margin-bottom: 12px;">
<el-select v-model="selectedValue" placeholder="请选择合同" style="width: 100%">
<div style="display: flex; align-items: center; margin-bottom: 0px;">
<!-- all模式远程搜索 -->
<el-select v-if="mode == 'all'" v-model="selectedValue" placeholder="请选择合同" style="width: 100%" clearable
filterable remote :remote-method="handleRemoteSearch" :loading="selectLoading">
<el-option v-for="item in contractList" :key="item.orderId" :value="item.orderId"
:label="item.contractCode" />
</el-select>
<!-- today模式本地 -->
<el-select v-else v-model="selectedValue" placeholder="请选择合同" style="width: 100%" clearable filterable>
<el-option v-for="item in contractList" :key="item.orderId" :value="item.orderId"
:label="item.contractCode" />
</el-select>
@@ -55,13 +62,14 @@
<!-- 所有合同tab -->
<el-tab-pane label="所有合同" name="all">
<div style="margin-bottom: 16px;">
<el-input v-model="searchKeyword" placeholder="搜索合同" @input="handleSearch" clearable
<el-input v-model="searchKeyword" placeholder="搜索合同" @blur="handleSearch"
@keyup.enter.native="handleSearch" @clear="handleSearch" clearable
size="small">
<el-button slot="append" icon="el-icon-search" size="small"></el-button>
<el-button slot="append" icon="el-icon-search" @click="handleSearch" size="small"></el-button>
</el-input>
</div>
<el-table :data="allContracts" style="width: 100%" size="mini" height="600">
<el-table :data="allContracts" style="width: 100%" size="mini" height="520">
<el-table-column prop="contractCode" label="合同编号" width="160" />
<el-table-column prop="contractName" label="合同名称" width="180" />
<el-table-column prop="customer" label="客户" width="140" />
@@ -93,6 +101,10 @@
</el-table-column>
</el-table>
<el-pagination v-if="allTotal > 0" background layout="total, prev, pager, next, jumper"
:total="allTotal" :page-size="allPageSize" :current-page.sync="allPageNum"
@current-change="handleAllPageChange" style="margin-top: 12px; text-align: right;" />
<div v-if="allContracts.length === 0" style="text-align: center; padding: 20px;">
暂无合同数据
</div>
@@ -104,7 +116,7 @@
</template>
<script>
import { listOrder, listTodayOrder } from '@/api/crm/order';
import { listOrder, listTodayOrder, getOrder } from '@/api/crm/order';
export default {
name: "ContractSelect",
@@ -125,6 +137,11 @@ export default {
searchKeyword: '',
allContracts: [],
activeTab: 'configured', // 默认显示已配置合同tab
allPageNum: 1,
allPageSize: 20,
allTotal: 0,
selectLoading: false,
selectTimer: null,
}
},
computed: {
@@ -134,15 +151,17 @@ export default {
},
set(val) {
this.$emit('input', val);
if (val) {
localStorage.setItem('lastSelectedContractId', val);
}
}
}
},
mounted() {
if (this.mode == "today") {
// 从localstorage中获取合同列表
this.loadFromLocalStorage();
} else {
this.loadContractList();
this.handleRemoteSearch('');
}
},
methods: {
@@ -172,33 +191,36 @@ export default {
}
},
// 加载合同列表
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();
// 加载合同列表today模式
async loadContractList() {
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)
);
// 上一次选择的合同放在列表第一位
this.sortLastSelectedToFirst();
// 保存到localStorage
this.saveToLocalStorage();
},
// 将上一次选择的合同排到列表第一位
sortLastSelectedToFirst() {
const lastId = localStorage.getItem('lastSelectedContractId');
if (!lastId) return;
const index = this.contractList.findIndex(item => String(item.orderId) === String(lastId));
if (index > 0) {
const [item] = this.contractList.splice(index, 1);
this.contractList.unshift(item);
}
},
// 打开选择弹窗
@@ -212,15 +234,12 @@ export default {
async loadAllContracts() {
try {
const res = await listOrder({
pageNum: 1,
pageSize: 1000,
pageNum: this.allPageNum,
pageSize: this.allPageSize,
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)
);
this.allTotal = res.total || 0;
this.allContracts = res.rows || [];
} catch (error) {
console.error('Failed to load all contracts:', error);
this.allContracts = [];
@@ -229,6 +248,12 @@ export default {
// 搜索合同
handleSearch() {
this.allPageNum = 1;
this.loadAllContracts();
},
handleAllPageChange(page) {
this.allPageNum = page;
this.loadAllContracts();
},
@@ -256,7 +281,53 @@ export default {
// 刷新合同列表
handleRefresh() {
this.loadContractList();
if (this.mode == 'all') {
this.handleRemoteSearch('');
} else {
this.loadContractList();
}
},
// all模式远程搜索
handleRemoteSearch(query) {
if (this.selectTimer) {
clearTimeout(this.selectTimer);
}
if (!query) {
this.selectTimer = null;
this.doRemoteSearch('');
return;
}
this.selectLoading = true;
this.selectTimer = setTimeout(() => {
this.doRemoteSearch(query);
}, 300);
},
async doRemoteSearch(query) {
try {
const res = await listOrder({
pageNum: 1,
pageSize: 100,
keyword: query || undefined,
});
this.contractList = res.rows || [];
// 初始加载时,确保已选中的合同在列表中
if (!query && this.value && !this.contractList.some(item => String(item.orderId) === String(this.value))) {
try {
const contract = await getOrder(this.value);
if (contract.data) {
this.contractList.unshift(contract.data);
}
} catch (e) {
console.error('Failed to fetch selected contract:', e);
}
}
} catch (error) {
console.error('Failed to search contracts:', error);
} finally {
this.selectLoading = false;
}
},
}
}

View File

@@ -145,6 +145,7 @@
<script>
import { listProduct, getProduct, addProduct } from '@/api/wms/product';
import MemoInput from '@/components/MemoInput/index.vue';
import { validSpecification } from '@/utils/validate';
export default {
name: 'ProductSelector',
@@ -184,7 +185,8 @@ export default {
{ required: true, message: "计量单位不能为空", trigger: "blur" }
],
specification: [
{ required: true, message: "规格不能为空", trigger: "blur" }
{ required: true, message: "规格不能为空", trigger: "blur" },
{ validator: validSpecification, trigger: 'blur' }
],
},
buttonLoading: false,

View File

@@ -130,6 +130,7 @@
<script>
import { listRawMaterial, getRawMaterial, updateRawMaterial, addRawMaterial } from '@/api/wms/rawMaterial';
import MemoInput from '@/components/MemoInput/index.vue'
import { validSpecification } from '@/utils/validate';
export default {
name: 'RawMaterialSelector',
@@ -197,7 +198,8 @@ export default {
{ required: true, message: "计量单位不能为空", trigger: "blur" }
],
specification: [
{ required: true, message: "规格不能为空", trigger: "blur" }
{ required: true, message: "规格不能为空", trigger: "blur" },
{ validator: validSpecification, trigger: 'blur' }
],
},
// 提交按钮加载状态

View File

@@ -180,6 +180,14 @@ export default {
visible: {
type: Boolean,
default: false
},
company: {
type: String,
default: ''
},
scheme: {
type: String,
default: ''
}
},
data() {
@@ -194,11 +202,16 @@ export default {
queryParams: {
pageNum: 1,
pageSize: 999,
templateName: undefined
templateName: undefined,
templateUnit: undefined
},
selectedCoils: [],
form: {
taskCode: undefined
taskCode: undefined,
taskType: undefined,
belongCompany: undefined,
enterCoilNos: undefined,
supplierCoilNos: undefined
},
schemeAddOpen: false,
schemeAddLoading: false,
@@ -239,12 +252,16 @@ export default {
this.selectedTemplate = null;
this.checkItemList = [];
this.form.taskCode = undefined;
this.form.belongCompany = undefined;
this.form.taskType = undefined;
this.selectedCoils = [];
this.selectedEnterCoilNos = [];
this.tempEnterCoilNo = '';
this.selectedSupplierCoilNos = [];
this.tempSupplierCoilNo = '';
this.enterCoilNoError = false;
this.queryParams.templateName = undefined;
this.queryParams.templateUnit = this.company || undefined;
this.getList();
}
}
@@ -256,6 +273,12 @@ export default {
this.templateList = response.rows || [];
this.total = response.total || 0;
this.loading = false;
if (this.scheme && this.templateList.length > 0) {
const match = this.templateList.find(t => t.templateName === this.scheme);
if (match) {
this.handleSchemeClick(match);
}
}
});
},
handleQuery() {

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