Compare commits

72 Commits

Author SHA1 Message Date
砂糖
f5c069a8f9 chore: 移除项目内冗余的file-viewer相关文件和配置
1. 删除了public/file-viewer目录下所有静态资源文件、脚本和配置文件
2. 在.gitignore中新增public/file-viewer/忽略规则
2026-07-09 09:25:38 +08:00
185231948c 添加员工管理自动导入能力,修复了部门,岗位未显示 2026-07-08 18:49:37 +08:00
349f06b22b Merge remote-tracking branch 'origin/main' 2026-07-08 18:12:46 +08:00
73564a0db6 修复了已知问题以及报销合理化 2026-07-08 18:12:31 +08:00
b6d4dcdde8 feat(oa/project/report): add last report memory function when add report
当新增项目报工的时候,如果今日还未报工,自动回填上次报工的项目信息,提升用户填报体验
2026-07-08 16:10:35 +08:00
03287aeeaa Merge branch 'main' of http://49.232.154.205:10100/liujingchao/fad_oa into main 2026-07-08 15:36:40 +08:00
970f7979a5 fix(hrm): 修复部门负责人配置功能,优化部门关联逻辑
1. 修复员工部门ID优先使用自定义字段而非用户绑定部门的逻辑
2. 新增部门负责人弹窗配置功能,支持直接编辑部门负责人、联系方式
3. 调整部门关联查询的JOIN条件,使用COALESCE正确获取部门ID
4. 为无负责人的部门标签添加点击阻止冒泡,避免触发树节点展开
2026-07-08 15:36:36 +08:00
jhd
948e94f425 feat(project): 为项目时间字段添加日期格式化注解
- 为beginTime字段添加@JsonFormat和@DateTimeFormat注解
- 为finishTime字段添加@JsonFormat和@DateTimeFormat注解
- 统一日期格式为yyyy-MM-dd并设置时区为GMT+8
2026-07-08 14:15:17 +08:00
af404a66aa fix(oa): 修复合同查询条件缺失问题并添加签订日期格式化
1. 补充按项目ID和合同类型的查询条件
2. 为signTime字段添加GMT+8时区的日期格式化注解
2026-07-07 16:41:12 +08:00
4f9b1b20b1 Merge branch 'main' of http://49.232.154.205:10100/liujingchao/fad_oa into main 2026-07-07 15:34:38 +08:00
e1dc6cb7b4 feat(oa/project/dispatch): 新增项目和合同的CRUD功能
重构项目调度页面:
1. 左侧项目列表新增增删改操作按钮
2. 合同模块新增工具栏和增删改功能
3. 实现完整的项目编辑弹窗,包含表单校验和字典数据绑定
4. 实现完整的合同编辑弹窗,支持甲乙双方信息填写
5. 补充对应的API调用和状态管理逻辑
6. 调整页面样式布局优化展示效果
2026-07-07 15:34:34 +08:00
a19c9398e8 Merge remote-tracking branch 'origin/main' 2026-07-07 15:15:08 +08:00
037b1a0678 fix(hrm): 解决流程实例任务查询中的空值错误
- 添加了对 instId 参数的空值检查
- 当 instId 为空或 null 时返回空数组避免请求错误
- 防止因参数缺失导致的接口调用失败
2026-07-07 15:14:59 +08:00
fd38ddfb91 Merge branch 'main' of http://49.232.154.205:10100/liujingchao/fad_oa into main 2026-07-07 14:41:06 +08:00
649d9fdfcc fix(hrm): 修复流程数据空值时的渲染异常
针对印章详情和流程详情页面,在缺少流程实例ID时提前返回,避免调用接口产生无效请求和脏数据
2026-07-07 14:39:33 +08:00
9689d152e0 fix(oa): fix acceptance item query - rename column standard to requirement 2026-07-07 14:14:15 +08:00
2f5c205ec3 refactor(oa): 修改项目验收项查询字段
- 将查询字段从 item_name, standard, result 修改为 requirement, actual_value, notes
- 保持验收项ID、检验员、检验日期等核心字段不变
- 优化数据库查询以支持新的验收检查需求
2026-07-07 12:57:47 +08:00
689cd61009 style(oa/remind): 优化提醒页面卡片样式
调整卡片内边距、布局结构,重构左侧图标区域和右侧文字区域的样式,统一视觉风格并优化排版
2026-07-06 15:58:37 +08:00
d116101aeb Merge branch 'main' of http://49.232.154.205:10100/liujingchao/fad_oa into main 2026-07-06 15:45:29 +08:00
62796299c4 style(hrm): 调整业务详情容器的布局与卡片宽度
修改容器的flex布局方向和对齐方式,统一表单与报告卡片的最大宽度,优化页面整体排版
2026-07-06 15:45:25 +08:00
jhd
51778006c7 Merge branch 'main' of http://49.232.154.205:10100/DeXun/fad_oa 2026-07-06 15:41:38 +08:00
jhd
8bf4a6d861 feat(config): 添加服务器URL配置并优化文件预览功能
- 在 application.yml 中添加 server-url 配置项,支持各环境profile覆盖
- 在 application-dev.yml 和 application-prod.yml 中分别配置对应的服务器地址
- 移除 @flyfish-group/file-viewer-web 依赖,改用 iframe 方式实现文件预览
- 更新 drawingDesign、installFeedback、layout 和 manuals 等模块的预览逻辑
- 在 ServerConfig 中实现优先使用配置的 server-url 的逻辑
- 移除相关的 viewerCtrl 控制器和生命周期钩子函数
2026-07-06 15:40:56 +08:00
d819dd9195 feat(oa_city): add city_code and province_name columns - fix Unknown column 'city_code' error caused by Java Entity fields missing in DDL 2026-07-06 14:26:53 +08:00
4144d354c9 fix(quick-access/quick-entry): 修改待办任务的跳转路由
将待办任务的跳转链接从work/todo调整为hrm/requests,统一系统内的路由跳转路径
2026-07-06 13:46:11 +08:00
d53ac1db32 build(ruoyi-ui): 新增文件预览依赖包并更新依赖版本
- 新增了完整的文件预览器前端资源包,包含各类文件格式的解析、渲染依赖
- 更新@openim/wasm-client-sdk依赖版本为宽松匹配
- 删除了旧的紧急联系人菜单清理SQL脚本
2026-07-04 19:15:06 +08:00
8cfd69d9bb feat: add last report memory for work report form 2026-07-04 19:07:41 +08:00
jhd
5544056833 任务表单增加阶段选择框 增加审核意见功能 右侧展示优化 2026-07-02 10:36:57 +08:00
jhd
bf7ee08b08 Merge branch 'main' of http://49.232.154.205:10100/DeXun/fad_oa 2026-07-02 10:31:02 +08:00
jhd
b2a9a117bc 后端任务关联相关 2026-07-02 10:30:49 +08:00
234e5b866f chore: remove the unused flyfish file viewer static files
删除了项目中未使用的flyfish文件查看器相关的所有静态资源文件,包括各类资源脚本、样式、wasm模块和配置文件等,清理冗余代码和资源。
2026-07-01 18:01:15 +08:00
e6a4f475a4 Merge branch 'main' of http://49.232.154.205:10100/DeXun/fad_oa 2026-07-01 17:52:18 +08:00
00ad7fdf06 style(ruoyi-ui): 调整文本域样式与会议表单适配
1.  注释掉全局文本域高度统一样式
2.  给会议编辑页的三个文本域改为自适应高度,设置最小6行最大20行
2026-07-01 17:52:15 +08:00
jhd
5790f7e9ec 安装前准备页面图标改造 2026-07-01 14:40:12 +08:00
jhd
980aeb1bb0 项目总览页面图标修改 2026-07-01 14:37:37 +08:00
jhd
94c5e076f8 前端预览加权限设置页面 相关sql修改 2026-06-26 17:31:10 +08:00
046f4c5e1b 采购需求去掉横向滚动问题 2026-06-26 13:29:09 +08:00
c6a3b6723f 采购需求去掉横向滚动问题 2026-06-22 10:55:23 +08:00
c4f0070065 添加了浮窗最小话以及一键写入日期 2026-06-18 12:42:13 +08:00
acaf13ff95 添加了浮窗最小话以及一键写入日期 2026-06-18 12:41:45 +08:00
88c374952a 添加了项目前景 绩效 审批配置做了一部分有点晕 我换换脑子继续这个 还有说明菜单 2026-06-17 17:06:01 +08:00
8ad3f2d7dd Merge remote-tracking branch 'origin/main' 2026-06-17 09:44:35 +08:00
2b19ef7d68 更改会可填写信息 2026-06-17 09:44:22 +08:00
jhd
f7c4d3fb90 相关sql 2026-06-17 09:34:06 +08:00
jhd
ec464c7d28 Merge branch 'main' of http://49.232.154.205:10100/DeXun/fad_oa 2026-06-17 09:32:07 +08:00
jhd
2f92ef57de 设备总包项目管理剩余页面 2026-06-17 09:29:22 +08:00
184202b82f 添加顶部导航,添加采购与合同审批,另外添加采购流合同流说明 2026-06-16 17:27:22 +08:00
7efc03570d 修改bbug 2026-06-16 16:07:23 +08:00
c1a382c255 修改bbug 2026-06-16 15:51:19 +08:00
44949287e0 提交审批能力部分代码 2026-06-16 15:37:35 +08:00
d294c7b5cd 修复文件bug 2026-06-16 15:13:51 +08:00
8e34f2eb62 feat(flow): 修复审批通过之后状态还是pending的bug
- 在流程任务完成后调用业务状态同步辅助类
- 实现审批通过后的业务状态更新机制
- 集成印章服务与业务状态同步的协调处理
- 确保流程实例与业务数据的一致性同步
2026-06-15 17:03:18 +08:00
b7af1b87ab 采购需求添加绑定物料 2026-06-13 15:37:10 +08:00
2575483122 Merge remote-tracking branch 'origin/main' 2026-06-12 14:35:41 +08:00
22f7c53914 Merge branch 'claude/sweet-swanson-772e08' 2026-06-12 14:35:27 +08:00
9e6ae1eca9 AI审核支持微调/自定义审核重点
- 新增审核可选择审核重点(字典驱动,合同/简历各一套)并填写附加要求自由文本,
  两者合并为 requirements 随请求提交,后端追加进系统提示词,让模型按需聚焦
- 审核项存字典 oa_ai_review_item_contract / oa_ai_review_item_resume,
  用户可在系统管理→字典管理自行增删审核项(无需改代码),各预置10项
- oa_ai_review 增加 requirements 列(已应用到生产库),落库留痕;详情页展示
- 前后端贯通:analyze / analyzeStream 均新增 requirements 参数

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 14:35:27 +08:00
jhd
690729e266 Merge branch 'main' of http://49.232.154.205:10100/DeXun/fad_oa 2026-06-12 13:55:39 +08:00
jhd
1e140cf1da 设备总包项目管理部分 2026-06-12 13:54:43 +08:00
4f0b919235 feat(oa): add arrival detail management module
实现到货明细的增删改查、列表查询、状态管理以及发货流程,包含搜索筛选、弹窗表单、批量操作和数据导出功能
2026-06-12 11:09:18 +08:00
f745651370 Merge remote-tracking branch 'origin/main' 2026-06-12 10:51:02 +08:00
a4f479454f 修复流式审核点击后无输出(静默失败)
原因:旧实现在返回 SseEmitter 之前同步做文档解析/渲染,一旦抛异常会被全局
异常处理器包成 JSON(HTTP 200 + {code,msg})返回;前端按 SSE 流读取,找不到
\n\n 分隔帧便静默结束——表现为“闪一下后无输出、也无报错”。

后端:
- analyzeStream 拆分 prepareSync(仅校验+读字节,必须在请求线程内)与
  buildPrompt(解析/渲染/构建提示词)。buildPrompt 移入异步线程,任何异常都
  转为 SSE error 事件返回,不再走 JSON 静默路径
- 线程启动即推送 start 事件,确认通道已打开
- 流式接口去掉 @Log(操作日志切面会尝试序列化 SseEmitter 返回值)

前端 add.vue:
- 校验响应 content-type:非 text/event-stream(鉴权失败/异常JSON/HTML)时读出
  正文并弹出错误,避免静默
- 统计收到的事件数,全程零事件时提示“未收到流式数据,请检查后端能否访问AI服务”
- 处理 start 事件

注:服务端为 Undertow、未开 gzip 压缩,dev 代理默认透传,排除缓冲导致。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 10:37:18 +08:00
7a2603e1f9 AI审核新增改为独立流式页面:左侧实时输出+右侧文档预览
解决上传后长时间无反馈的问题——改为流式(SSE)边生成边展示。

后端:
- MiMoClient.chatStream:HttpURLConnection 读 SSE,分别回调 reasoning(思考)
  与 content(正文) 增量;支持多模态(扫描件PDF)
- IOaAiReviewService.analyzeStream + 实现:同步校验/解析文档后,异步线程调用
  流式接口,通过 SseEmitter 推送 {type:reasoning|content|done|error},
  结束后落库(含结论解析、摘要、原件OSS留存);createBy 显式回填(异步线程无登录上下文)
  · 抽出 prepare()/persist() 复用,analyze() 与 analyzeStream() 共用
- Controller 新增 POST /oa/aiReview/analyzeStream(multipart→text/event-stream)

前端:
- 新增独立二级页面 views/oa/aiReview/add.vue(路由 /hint/aiReview/add):
  · 顶部:类型/岗位/选文件/开始审核
  · 左侧:用原生 fetch 读流,实时渲染——思考过程(可折叠)+正文 Markdown 实时输出
  · 右侧:选中文件即用本地 objectURL 预览(PDF 内嵌 iframe,Word 占位提示)
  · 完成后显示匹配度/风险标签 + 查看详情
- 列表页「新增审核」由弹窗改为跳转该页面,移除弹窗相关逻辑
- router 增加 /hint/aiReview/add 隐藏路由

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 10:19:52 +08:00
23f65c738d refactor(oa): 优化到货明细服务的关联查询
- 添加批量填充关联VO的方法,避免N+1查询问题
- 新增需求和项目关联字段到到货明细VO中
- 实现根据需求ID自动填充项目ID和贸易类型的逻辑
- 重构查询方法以支持关联数据的批量加载
- 添加Excel导出忽略注解以防止关联对象被导出
2026-06-12 10:05:45 +08:00
d46754ede8 AI审核改为 列表页+详情页 结构,列表带审核摘要
- 表 oa_ai_review 增加 summary 列(审核结论摘要,纯文本,列表展示用),
  已应用到生产库;分析时由结果 Markdown 提炼前160字纯文本写入
- 列表查询清空大字段 result_md 减小响应体,详情接口仍返回完整结果
- 前端拆分:
  · index.vue 重写为列表页:搜索(类型/关键字)+表格(类型/文件名/岗位/结论标签/
    审核摘要/时间)+分页,「新增审核」改为弹窗上传(类型/岗位/文件),
    审核完成后跳转详情;行可删除
  · 新增 detail.vue 详情页:元信息(文件名+下载原件/岗位/模型/时间/审核人)
    + 结论标签 + 完整 Markdown 结果,返回列表按钮
  · router 增加 /hint/aiReview/detail/:id 隐藏路由
- 原件已通过 OSS 留存,详情页可下载,下次可直接查看

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 10:04:16 +08:00
faca2f85eb 新增 AI 合同/简历审核功能(小米 MiMo 多模态大模型)
核心诉求:合同审核站在我方(德睿福)立场,找出不利条款并给出利好我方的
修改/补充建议;简历审核评估候选人与目标岗位的匹配度。

后端(ruoyi-oa):
- 接入小米 MiMo(OpenAI 兼容 /chat/completions),mimo-v2.5 多模态模型
  · MiMoProperties 绑定 application.yml mimo: 配置(base-url/api-key/model/...)
  · MiMoClient:text + multimodal(image_url base64) 两种调用,独立长超时
    RestTemplate;mimo-v2.5 是推理模型,max-tokens 配 8192 留足思考额度
- DocumentParseUtil:PDF 文字(PDFBox)、Word(POI: docx XWPF / doc HWPF),
  扫描版 PDF(提取文字过短)用 PDFRenderer 转 PNG 走多模态
- OaAiReview 实体 + BO/VO/Mapper/Service/Controller(/oa/aiReview)
  · analyze 上传解析→构建提示词→调用大模型→留存原件(OSS)→落库
  · 合同/简历两套提示词;正则解析风险评级:高/中/低与匹配度评分:NN入库
  · 提供 list/detail/delete
- ruoyi-oa/pom.xml 增加 poi-ooxml、poi-scratchpad(Word 解析)
- application.yml 增加 mimo: 配置块

前端(ruoyi-ui):
- views/oa/aiReview/index.vue:类型切换(合同/简历)、拖拽上传(pdf/word)、
  简历目标岗位输入、审核(loading)、Markdown 结果渲染、历史记录列表
- api/oa/aiReview.js:analyze 用 FormData,超时放宽到 5 分钟

SQL(已应用到生产库):
- oa_ai_review 表;菜单挂信息下(menu_id 2063910000000000001),授权10个角色

已用真实接口端到端验证:合同审核输出利好我方意见、风险评级可正确解析。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 10:00:09 +08:00
005cf47424 feat(oa): 添加到货明细管理功能
- 创建到货明细实体类 OaArrivalDetail 包含基本信息字段
- 实现到货明细业务对象 OaArrivalDetailBo 和视图对象 OaArrivalDetailVo
- 开发到货明细服务接口 IOaArrivalDetailService 及其实现类
- 构建到货明细数据访问层 OaArrivalDetailMapper 及对应的 XML 映射文件
- 设计到货明细控制器 OaArrivalDetailController 提供完整的 CRUD 操作
- 集成分页查询、导出 Excel、新增修改删除等完整业务功能
2026-06-12 09:48:46 +08:00
6f64c3d4af 修复全局样式导致输入框文字与图标重叠
index.scss 全局压高度规则把 .el-input__inner 的 padding 写死为 0 8px !important,
覆盖了 element-ui 给带前/后缀图标输入框预留的 30px 内边距,导致日期选择器、
带搜索图标输入框、下拉选择等的占位文字/内容压在图标上。

在该规则后补回更高优先级的图标位 padding(prefix/suffix 各 28px),
并修正 mini 尺寸输入框图标行高(22px,原 26px 垂直偏移)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 10:33:18 +08:00
db7cbf8157 会议纪要改为 列表页+独立编辑页 结构,移除语音录入
- index.vue 重写为标准列表页:搜索(关键字/项目/类型/日期)+ 表格 + 分页,
  显示待办同步进度(已同步/总数),双击行或点编辑进入编辑页
- 新增 edit.vue 独立编辑页:新增 /hint/meeting/add、编辑 /hint/meeting/edit/:id,
  新建保存后自动切换为编辑路由,防止重复新增;路由复用时通过 $route watch 重置/加载
- router/index.js 增加 /hint 静态隐藏路由(与 /people、/claim 同惯例,activeMenu 高亮列表菜单)
- 按要求删除语音录入功能(SpeechRecognition 相关全部移除)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 10:29:58 +08:00
a9c9b8a5ea 会议纪要功能修复与改进
后端:
- 待办同步改走 ISysOaTaskService.insertByBo/updateByBo,新任务带操作日志和IM通知
- 任务状态映射修正:done→2执行完成,其余→0执行中(原 progress→1 会显示成"等待验收")
- 无负责人/无内容的待办仅作纪要记录,不再生成无主任务
- 更新时可清空字段改用显式 set(原来解绑项目、清空内容不生效)
- 新增接口返回纪要ID,前端据此进入编辑态,避免重复保存生成多条
- 会议编号加3位随机数防同秒撞唯一键;异常改 ServiceException;同步失败记日志
- enrich 为待办条目注入 assigneeName,列表/详情/导出可显示负责人姓名
- SysOaTaskServiceImpl.insertByBo 回填 taskId 供调用方关联

前端:
- 主持人/待办负责人改用人员单选弹窗(原多选组件取首位的方式易误操作)
- 会议类型、待办状态接入 sys_dict 字典(oa_meeting_type / oa_meeting_task_status)
- 新建保存后切换为编辑态;默认日期用本地时区(原 UTC 凌晨会差一天)
- 导出/打印带主持人、参会人、待办负责人姓名(原来只有用户ID)
- 删除已同步待办时提示任务不会被删除

SQL(已直接应用到生产库):
- 字典数据补全并修复 dict_id=0 脏数据(sys_dict_* 主键为雪花ID须显式指定)
- 菜单 2063809716454174722 icon 修为 documentation,授权10个角色
- 脚本改为幂等,去掉 DROP TABLE,del_flag 注释修正为逻辑删除值2

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 10:12:48 +08:00
e5bfa0c78c 会议纪要:原始WIP版本留底
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 10:12:12 +08:00
79e536aeca oa更新项目总览 2026-06-08 10:11:33 +08:00
3334248847 库房回退 2026-06-05 13:54:11 +08:00
370142a99f im问题修复 2026-06-02 17:25:45 +08:00
542 changed files with 34592 additions and 1041 deletions

95
CLAUDE.md Normal file
View File

@@ -0,0 +1,95 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
福安德综合办公系统 (FAD OA) — 基于 RuoYi-Flowable-Plus 二次开发,面向工程项目的投标管理、进度控制、成本核算及日常 OA 办公。
**Tech Stack**: Spring Boot 2.7 + MyBatis-Plus 3.5 + Flowable 6.8 + Vue 2 + Element UI + MySQL 8.0 + Redis
## Build & Run
```bash
# Backend build (dev profile, skip tests)
mvn clean package -D maven.test.skip=true -P dev
# Backend build (prod)
mvn clean package -D maven.test.skip=true -P prod
# Frontend dev server (port 80)
cd ruoyi-ui && npm run dev
# Frontend lint
cd ruoyi-ui && npm run lint
# Frontend prod build
cd ruoyi-ui && npm run build:prod
```
Active Maven profile defaults to `dev` (`pom.xml` line 72). Backend entry point: `ruoyi-admin/`.
## Database
Init script: `script/sql/mysql/ry-vue-flowable-xg.sql`. Module-specific migrations live in `sql/` (e.g. `oa_approval.sql`, `warehouse_*.sql`, `hrm_*.sql`).
Dev DB: `fad_oa_dev` @ 49.232.154.205:13306
Prod DB: `fad_oa` @ 49.232.154.205:13306
Redis: 49.232.154.205:6379 (password: WANGyu11!)
**Menu SQL pattern**: When adding menus to `sys_menu`, use fixed snowflake IDs (not RAND()). Reference `sql/warehouse_phase0_menu.sql` for the correct pattern. Menu changes require COMMIT + restart backend to flush Redis cache — clearing Redis is not enough on its own.
## Module Architecture
| Module | Purpose |
|--------|---------|
| `ruoyi-admin/` | Spring Boot entry point, YAML configs |
| `ruoyi-framework/` | Security (Sa-Token), interceptors, global config |
| `ruoyi-system/` | Users, roles, menus, depts, dicts, posts |
| `ruoyi-flowable/` | Flowable workflow engine integration |
| `ruoyi-oa/` | Core OA: projects, contracts, bidding, finance, warehouse, approval |
| `ruoyi-ui/` | Vue 2 frontend (Element UI) |
| `fad-hrm/` | HRM: employees, attendance, leave, travel, seal, payroll, flow tasks |
| `fad-app/` | Mobile app API endpoints |
| `fad-export/` | Foreign trade public web pages |
| `fad-rolling-mill/` | Rolling mill business module |
| `klp-wms/` | Warehouse management module |
## Dynamic Menu System (Critical)
Menus are **not hardcoded in Vue Router**. They are stored in `sys_menu` DB table and delivered by `GET /getRouters`. The frontend flow:
1. `ruoyi-ui/src/store/modules/permission.js``GenerateRoutes` action
2. Calls `getRouters()``@/api/menu.js``GET /getRouters`
3. Backend returns JSON with `component` paths (e.g. `"hrm/employee/index"`)
4. `filterAsyncRouter()` resolves strings to actual Vue components via dynamic `import()`
5. Routes are added at runtime via `router.addRoutes()`
**Implication**: Adding a new page requires both a `sys_menu` INSERT (with correct `component` path) AND the actual `.vue` file at `ruoyi-ui/src/views/<component>`. No changes to `router/index.js` are needed for C-type page menus — only hidden/detail routes go there.
F-type menus (buttons) use `perms` field for permission checks (e.g. `system:user:add`). M-type menus are directory containers with no component.
## HRM Module Structure
The HRM module (`fad-hrm/` backend, `ruoyi-ui/src/views/hrm/` frontend) is a self-contained HR system built on a custom flow engine (NOT Flowable — uses its own `hrm_flow_*` tables).
**Two separate approval systems exist**:
- **HRM flow engine**: `hrm_flow_task`, `hrm_flow_instance` etc. — handles leave/travel/seal/reimburse/appropriation workflows. Pages: `hrm/requests/`
- **OA approval center**: `oa_approval_instance` table — lightweight generic approval for purchase/contract. Pages: `oa/approval/`
Both have items named "我的审批" in the menu. They serve different data sources and must NOT be conflated.
## Key Auth Patterns
- Uses **Sa-Token** (not Spring Security), configured in `application.yml`
- `@SaCheckPermission` for API-level permission checks
- Frontend permission checks: `v-hasPermi` directive and `auth.hasPermiOr()` in `@/plugins/auth`
- Menu visibility is controlled by `sys_role_menu` table — role-to-menu many-to-many
## API Response Conventions
The backend uses two response wrappers:
- `TableDataInfo<T>`: `{ total, rows, code, msg }` — paginated lists → frontend accesses `res.rows`
- `R<T>`: `{ data, code, msg }` — single entities → frontend accesses `res.data`
Frontend API modules are in `ruoyi-ui/src/api/`. The axios interceptor in `@/utils/request` unwraps the HTTP response, so `.then(res => ...)` receives the JSON body directly (not the full axios response).

View File

@@ -1,6 +1,7 @@
package com.ruoyi.hrm.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
@@ -18,8 +19,10 @@ import com.ruoyi.hrm.domain.vo.HrmMyApplyVo;
import com.ruoyi.hrm.domain.vo.HrmReimburseReqVo;
import com.ruoyi.hrm.domain.vo.HrmSealReqVo;
import com.ruoyi.hrm.domain.vo.HrmTravelReqVo;
import com.ruoyi.hrm.domain.HrmFlowInstance;
import com.ruoyi.hrm.mapper.HrmAppropriationReqMapper;
import com.ruoyi.hrm.mapper.HrmEmployeeMapper;
import com.ruoyi.hrm.mapper.HrmFlowInstanceMapper;
import com.ruoyi.hrm.mapper.HrmLeaveReqMapper;
import com.ruoyi.hrm.mapper.HrmReimburseReqMapper;
import com.ruoyi.hrm.mapper.HrmSealReqMapper;
@@ -32,7 +35,9 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@@ -48,6 +53,8 @@ public class HrmMyApplyController extends BaseController {
private final HrmSealReqMapper sealReqMapper;
private final HrmReimburseReqMapper reimburseReqMapper;
private final HrmAppropriationReqMapper appropriationReqMapper;
private final HrmFlowInstanceMapper flowInstanceMapper;
private final ObjectMapper objectMapper;
@GetMapping("/list")
public TableDataInfo<HrmMyApplyVo> list(String bizType, String status, String keyword, PageQuery pageQuery) {
@@ -55,29 +62,43 @@ public class HrmMyApplyController extends BaseController {
if (currentUserId == null) {
return TableDataInfo.build();
}
HrmEmployee emp = employeeMapper.selectOne(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<HrmEmployee>()
.eq(HrmEmployee::getUserId, currentUserId));
if (emp == null) {
// 极端场景一个 sys_user 可能对应多条员工记录(历史孤儿/副本没清干净),
// 用 list + limit 1 兜底,别用 selectOne 直接抛异常。
List<HrmEmployee> empList = employeeMapper.selectList(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<HrmEmployee>()
.eq(HrmEmployee::getUserId, currentUserId)
.orderByAsc(HrmEmployee::getEmpId)
.last("limit 1"));
if (empList.isEmpty()) {
return TableDataInfo.build();
}
HrmEmployee emp = empList.get(0);
SysUser sysUser = sysUserMapper.selectUserById(emp.getUserId());
String nickName = sysUser != null ? sysUser.getNickName() : null;
List<HrmMyApplyVo> all = new ArrayList<>();
if (bizType == null || bizType.isEmpty() || "leave".equals(bizType)) {
all.addAll(mapLeave(leaveReqMapper.selectVoWithProjectList(buildLeaveBo(emp.getEmpId(), status)), nickName));
all.addAll(mapLeave(leaveReqMapper.selectVoWithProjectList(buildLeaveBo(emp.getEmpId())), nickName));
}
if (bizType == null || bizType.isEmpty() || "travel".equals(bizType)) {
all.addAll(mapTravel(travelReqMapper.selectVoWithProjectList(buildTravelBo(emp.getEmpId(), status)), nickName));
all.addAll(mapTravel(travelReqMapper.selectVoWithProjectList(buildTravelBo(emp.getEmpId())), nickName));
}
if (bizType == null || bizType.isEmpty() || "seal".equals(bizType)) {
all.addAll(mapSeal(sealReqMapper.selectVoWithProjectList(buildSealBo(emp.getEmpId(), status)), nickName));
all.addAll(mapSeal(sealReqMapper.selectVoWithProjectList(buildSealBo(emp.getEmpId())), nickName));
}
if (bizType == null || bizType.isEmpty() || "reimburse".equals(bizType)) {
all.addAll(mapReimburse(reimburseReqMapper.selectVoWithProjectList(buildReimburseBo(emp.getEmpId(), status)), nickName));
all.addAll(mapReimburse(reimburseReqMapper.selectVoWithProjectList(buildReimburseBo(emp.getEmpId())), nickName));
}
if (bizType == null || bizType.isEmpty() || "appropriation".equals(bizType)) {
all.addAll(mapAppropriation(appropriationReqMapper.selectVoWithProjectList(buildAppropriationBo(emp.getEmpId(), status)), nickName));
all.addAll(mapAppropriation(appropriationReqMapper.selectVoWithProjectList(buildAppropriationBo(emp.getEmpId())), nickName));
}
// 状态唯一来源:流程实例表 hrm_flow_instance
overrideStatusByFlowInstance(all);
// 状态过滤放到实例覆盖之后(业务表已无 status 字段可下推)
if (status != null && !status.isEmpty()) {
all = all.stream().filter(v -> status.equalsIgnoreCase(v.getStatus())).collect(Collectors.toList());
}
if (keyword != null && !keyword.isEmpty()) {
@@ -93,6 +114,52 @@ public class HrmMyApplyController extends BaseController {
return TableDataInfo.build(page);
}
private void overrideStatusByFlowInstance(List<HrmMyApplyVo> all) {
if (all == null || all.isEmpty()) return;
Map<String, List<Long>> bizIdsByType = all.stream()
.filter(v -> v.getBizType() != null && v.getBizId() != null)
.collect(Collectors.groupingBy(
HrmMyApplyVo::getBizType,
Collectors.mapping(HrmMyApplyVo::getBizId, Collectors.toList())
));
Map<String, String> statusByKey = new HashMap<>();
bizIdsByType.forEach((bizType, bizIds) -> {
if (bizIds.isEmpty()) return;
List<HrmFlowInstance> insts = flowInstanceMapper.selectList(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<HrmFlowInstance>()
.eq(HrmFlowInstance::getBizType, bizType)
.in(HrmFlowInstance::getBizId, bizIds)
);
for (HrmFlowInstance inst : insts) {
if (inst.getStatus() == null) continue;
// 合并多个流程实例:优先终态 (approved/rejected/withdrawn) > 进行中 (running/pending)
// 否则前面遗留的"running"会盖掉新的"approved",导致前端永远显示审批中
statusByKey.merge(bizType + "_" + inst.getBizId(), inst.getStatus(),
(oldS, newS) -> _statusPriority(newS) > _statusPriority(oldS) ? newS : oldS);
}
});
for (HrmMyApplyVo v : all) {
String s = statusByKey.get(v.getBizType() + "_" + v.getBizId());
if (s != null) v.setStatus(s);
}
}
private int _statusPriority(String s) {
if (s == null) return 0;
switch (s) {
case "approved":
case "done":
return 3;
case "rejected":
case "withdrawn":
return 2;
case "running":
case "pending":
default:
return 1;
}
}
private boolean contains(HrmMyApplyVo v, String lower) {
return Objects.toString(v.getTitle(), "").toLowerCase().contains(lower)
|| Objects.toString(v.getRemark(), "").toLowerCase().contains(lower)
@@ -101,27 +168,30 @@ public class HrmMyApplyController extends BaseController {
|| Objects.toString(v.getBizId(), "").contains(lower);
}
private HrmLeaveReqBo buildLeaveBo(Long empId, String status) { HrmLeaveReqBo bo = new HrmLeaveReqBo(); bo.setEmpId(empId); bo.setStatus(status); return bo; }
private HrmTravelReqBo buildTravelBo(Long empId, String status) { HrmTravelReqBo bo = new HrmTravelReqBo(); bo.setEmpId(empId); bo.setStatus(status); return bo; }
private HrmSealReqBo buildSealBo(Long empId, String status) { HrmSealReqBo bo = new HrmSealReqBo(); bo.setEmpId(empId); bo.setStatus(status); return bo; }
private HrmReimburseReqBo buildReimburseBo(Long empId, String status) { HrmReimburseReqBo bo = new HrmReimburseReqBo(); bo.setEmpId(empId); bo.setStatus(status); return bo; }
private HrmAppropriationReqBo buildAppropriationBo(Long empId, String status) { HrmAppropriationReqBo bo = new HrmAppropriationReqBo(); bo.setEmpId(empId); bo.setStatus(status); return bo; }
private HrmLeaveReqBo buildLeaveBo(Long empId) { HrmLeaveReqBo bo = new HrmLeaveReqBo(); bo.setEmpId(empId); return bo; }
private HrmTravelReqBo buildTravelBo(Long empId) { HrmTravelReqBo bo = new HrmTravelReqBo(); bo.setEmpId(empId); return bo; }
private HrmSealReqBo buildSealBo(Long empId) { HrmSealReqBo bo = new HrmSealReqBo(); bo.setEmpId(empId); return bo; }
private HrmReimburseReqBo buildReimburseBo(Long empId) { HrmReimburseReqBo bo = new HrmReimburseReqBo(); bo.setEmpId(empId); return bo; }
private HrmAppropriationReqBo buildAppropriationBo(Long empId) { HrmAppropriationReqBo bo = new HrmAppropriationReqBo(); bo.setEmpId(empId); return bo; }
private List<HrmMyApplyVo> mapLeave(List<HrmLeaveReqVo> list, String nickName) { return list.stream().map(v -> toVo("leave", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime())).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapTravel(List<HrmTravelReqVo> list, String nickName) { return list.stream().map(v -> toVo("travel", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime())).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapSeal(List<HrmSealReqVo> list, String nickName) { return list.stream().map(v -> toVo("seal", v.getBizId(), v.getEmpId(), nickName, v.getRemark(), v.getStatus(), v.getCreateTime())).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapReimburse(List<HrmReimburseReqVo> list, String nickName) { return list.stream().map(v -> toVo("reimburse", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime())).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapAppropriation(List<HrmAppropriationReqVo> list, String nickName) { return list.stream().map(v -> toVo("appropriation", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime())).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapLeave(List<HrmLeaveReqVo> list, String nickName) { return list.stream().map(v -> toVo("leave", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapTravel(List<HrmTravelReqVo> list, String nickName) { return list.stream().map(v -> toVo("travel", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapSeal(List<HrmSealReqVo> list, String nickName) { return list.stream().map(v -> toVo("seal", v.getBizId(), v.getEmpId(), nickName, v.getPurpose() != null ? v.getPurpose() : v.getRemark(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapReimburse(List<HrmReimburseReqVo> list, String nickName) { return list.stream().map(v -> toVo("reimburse", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapAppropriation(List<HrmAppropriationReqVo> list, String nickName) { return list.stream().map(v -> toVo("appropriation", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private HrmMyApplyVo toVo(String bizType, Long bizId, Long empId, String nickName, String title, String status, java.util.Date createTime) {
@SuppressWarnings("unchecked")
private HrmMyApplyVo toVo(String bizType, Long bizId, Long empId, String nickName, String title, java.util.Date createTime, Object source) {
HrmMyApplyVo vo = new HrmMyApplyVo();
vo.setBizType(bizType);
vo.setBizId(bizId);
vo.setEmpId(empId);
vo.setNickName(nickName);
vo.setTitle(title);
vo.setStatus(status);
vo.setCreateTime(createTime);
if (source != null) {
vo.setBizData(objectMapper.convertValue(source, Map.class));
}
return vo;
}
}

View File

@@ -65,24 +65,6 @@ public class HrmSealReqController extends BaseController {
return toAjax(service.deleteWithValidByIds(java.util.Arrays.asList(bizIds), true));
}
@Log(title = "用印申请", businessType = BusinessType.UPDATE)
@PostMapping("/{bizId}/approve")
public R<Void> approve(@PathVariable @NotNull Long bizId) {
return toAjax(service.updateStatus(bizId, "approved"));
}
@Log(title = "用印申请", businessType = BusinessType.UPDATE)
@PostMapping("/{bizId}/reject")
public R<Void> reject(@PathVariable @NotNull Long bizId) {
return toAjax(service.updateStatus(bizId, "rejected"));
}
@Log(title = "用印申请", businessType = BusinessType.UPDATE)
@PostMapping("/{bizId}/cancel")
public R<Void> cancel(@PathVariable @NotNull Long bizId) {
return toAjax(service.updateStatus(bizId, "canceled"));
}
@Log(title = "用印盖章(Java)", businessType = BusinessType.UPDATE)
@PostMapping("/{bizId}/stamp/java")
public R<String> stampJava(@PathVariable @NotNull Long bizId, @Validated @RequestBody HrmSealStampBo bo) {

View File

@@ -45,9 +45,6 @@ public class HrmAppropriationReq extends BaseEntity {
/** 拨款事由 */
private String reason;
/** 状态 draft/pending/approved/rejected/canceled */
private String status;
/** 申请附件oss_id列表(CSV) */
private String accessoryApplyIds;

View File

@@ -25,7 +25,6 @@ public class HrmLeaveReq extends BaseEntity implements Serializable {
private Date endTime;
private java.math.BigDecimal hours;
private String reason;
private String status;
private String accessoryApplyIds;
private String accessoryReceiptIds;
private String remark;

View File

@@ -27,8 +27,6 @@ public class HrmReimburseReq extends BaseEntity {
private String reason;
private String status;
private String accessoryApplyIds;
private String accessoryReceiptIds;

View File

@@ -46,9 +46,6 @@ public class HrmSealReq extends BaseEntity {
/** 回执附件ID列表(CSV对应sys_oss或直接URL) */
private String receiptFileIds;
/** 状态 draft/running/approved/rejected/canceled */
private String status;
/** 备注 */
private String remark;

View File

@@ -24,7 +24,6 @@ public class HrmTravelReq extends BaseEntity {
private String travelType;
private String destination;
private String reason;
private String status;
private String accessoryApplyIds;
private String accessoryReceiptIds;
private String payeeName;

View File

@@ -44,9 +44,6 @@ public class HrmAppropriationReqBo extends BaseEntity {
/** 拨款事由 */
private String reason;
/** 状态 draft/pending/approved/rejected/canceled */
private String status;
/** 无模板时,自选审批人 userId */
private Long manualAssigneeUserId;

View File

@@ -35,7 +35,6 @@ public class HrmLeaveReqBo extends BaseEntity {
private java.math.BigDecimal hours;
private String reason;
private String status;
/**
* 流程模板ID前端选择模板流程时传入

View File

@@ -26,8 +26,6 @@ public class HrmReimburseReqBo extends BaseEntity {
private String reason;
private String status;
// 无模板时,自选审批人 userId
private Long manualAssigneeUserId;

View File

@@ -40,9 +40,6 @@ public class HrmSealReqBo extends BaseEntity {
/** 备注 */
private String remark;
/** 状态 draft/running/approved/rejected/canceled */
private String status;
/** 关联流程模板ID旧字段兼容历史前端/代码) */
private Long flowTplId;

View File

@@ -30,7 +30,6 @@ public class HrmTravelReqBo extends BaseEntity {
private String travelType;
private String destination;
private String reason;
private String status;
// 无模板时,自选审批人 userId
private Long manualAssigneeUserId;

View File

@@ -91,9 +91,6 @@ public class HrmAppropriationReqVo implements Serializable {
@Excel(name = "拨款事由")
private String reason;
@Excel(name = "状态")
private String status;
@Excel(name = "申请附件")
private String accessoryApplyIds;

View File

@@ -6,6 +6,7 @@ import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
@Data
public class HrmFlowInstanceVo implements Serializable {
@@ -41,4 +42,7 @@ public class HrmFlowInstanceVo implements Serializable {
private Date createTime;
private String updateBy;
private Date updateTime;
/** 业务表回填的数据,用于列表关键信息展示 */
private Map<String, Object> bizData;
}

View File

@@ -59,8 +59,6 @@ public class HrmLeaveReqVo implements Serializable {
private BigDecimal hours;
@Excel(name = "原因")
private String reason;
@Excel(name = "状态")
private String status;
@Excel(name = "申请附件")
private String accessoryApplyIds;
@Excel(name = "回执附件")

View File

@@ -4,6 +4,7 @@ import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.Map;
@Data
public class HrmMyApplyVo implements Serializable {
@@ -21,4 +22,5 @@ public class HrmMyApplyVo implements Serializable {
private Date endTime;
private Date actualEndTime;
private String remark;
private Map<String, Object> bizData;
}

View File

@@ -79,9 +79,6 @@ public class HrmReimburseReqVo implements Serializable {
@Excel(name = "报销事由")
private String reason;
@Excel(name = "状态")
private String status;
@Excel(name = "报销单据附件")
private String accessoryApplyIds;

View File

@@ -91,9 +91,6 @@ public class HrmSealReqVo implements Serializable {
@Excel(name = "PDF页数")
private Integer pdfPageTotal;
@Excel(name = "状态")
private String status;
@Excel(name = "备注")
private String remark;

View File

@@ -58,8 +58,6 @@ public class HrmTravelReqVo implements Serializable {
private String destination;
@Excel(name = "原因")
private String reason;
@Excel(name = "状态")
private String status;
@Excel(name = "申请附件")
private String accessoryApplyIds;
@Excel(name = "回执附件")

View File

@@ -1,8 +1,33 @@
package com.ruoyi.hrm.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import com.ruoyi.hrm.domain.HrmEmployee;
import com.ruoyi.hrm.domain.bo.HrmEmployeeBo;
import com.ruoyi.hrm.domain.vo.HrmEmployeeVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface HrmEmployeeMapper extends BaseMapperPlus<HrmEmployeeMapper, HrmEmployee, HrmEmployeeVo> {
/**
* 按 empId 查询员工详情。JOIN sys_dept / sys_post 补上 dept_name / post_name。
* <p>
* 注意:不能沿用父接口的 selectVoById那是 default 方法先跑 selectById 再 BeanCopy
* 拿不到 JOIN 出来的 dept_name / post_name。
*/
HrmEmployeeVo selectEmployeeVoById(@Param("empId") Long empId);
/**
* 员工列表(含 dept / post 名称)。传 BO自己在 XML 里拼过滤条件,
* 别用 LambdaQueryWrapper——JOIN 里字段名会跟 sys_user / sys_dept 冲突。
*/
List<HrmEmployeeVo> selectEmployeeVoList(@Param("bo") HrmEmployeeBo bo);
/**
* 员工分页(含 dept / post 名称)。
*/
Page<HrmEmployeeVo> selectEmployeeVoPage(IPage<HrmEmployee> page, @Param("bo") HrmEmployeeBo bo);
}

View File

@@ -26,11 +26,6 @@ public interface IHrmAppropriationReqService {
Boolean updateByBo(HrmAppropriationReqBo bo);
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
*状态更新draft/running/approved/rejected/canceled
*/
Boolean updateStatus(Long bizId, String status);
}

View File

@@ -27,11 +27,6 @@ public interface IHrmSealReqService {
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 简单状态更新draft/running/approved/rejected/canceled
*/
Boolean updateStatus(Long bizId, String status);
/**
* Java 盖章,返回盖章后文件 URL
*/

View File

@@ -1,120 +0,0 @@
package com.ruoyi.hrm.service.impl;
import com.ruoyi.hrm.domain.HrmLeaveReq;
import com.ruoyi.hrm.domain.HrmReimburseReq;
import com.ruoyi.hrm.domain.HrmTravelReq;
import com.ruoyi.hrm.domain.HrmSealReq;
import com.ruoyi.hrm.domain.HrmAppropriationReq;
import com.ruoyi.hrm.mapper.HrmLeaveReqMapper;
import com.ruoyi.hrm.mapper.HrmReimburseReqMapper;
import com.ruoyi.hrm.mapper.HrmTravelReqMapper;
import com.ruoyi.hrm.mapper.HrmSealReqMapper;
import com.ruoyi.hrm.mapper.HrmAppropriationReqMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* 将流程结果同步到业务表状态。
* 业务表状态规范pending/approved/rejected
*/
@Component
@RequiredArgsConstructor
public class BizStatusSyncHelper {
private final HrmLeaveReqMapper leaveReqMapper;
private final HrmTravelReqMapper travelReqMapper;
private final HrmSealReqMapper sealReqMapper;
private final HrmReimburseReqMapper reimburseReqMapper;
private final HrmAppropriationReqMapper appropriationReqMapper;
public void setBizApproved(String bizType, Long bizId) {
if (bizType == null || bizId == null) return;
if ("leave".equalsIgnoreCase(bizType)) {
HrmLeaveReq u = new HrmLeaveReq();
u.setBizId(bizId);
u.setStatus("approved");
leaveReqMapper.updateById(u);
} else if ("travel".equalsIgnoreCase(bizType)) {
HrmTravelReq u = new HrmTravelReq();
u.setBizId(bizId);
u.setStatus("approved");
travelReqMapper.updateById(u);
} else if ("seal".equalsIgnoreCase(bizType)) {
HrmSealReq u = new HrmSealReq();
u.setBizId(bizId);
u.setStatus("approved");
sealReqMapper.updateById(u);
} else if ("reimburse".equalsIgnoreCase(bizType)) {
HrmReimburseReq u = new HrmReimburseReq();
u.setBizId(bizId);
u.setStatus("approved");
reimburseReqMapper.updateById(u);
} else if ("appropriation".equalsIgnoreCase(bizType)) {
HrmAppropriationReq u = new HrmAppropriationReq();
u.setBizId(bizId);
u.setStatus("approved");
appropriationReqMapper.updateById(u);
}
}
public void setBizPending(String bizType, Long bizId) {
if (bizType == null || bizId == null) return;
if ("leave".equalsIgnoreCase(bizType)) {
HrmLeaveReq u = new HrmLeaveReq();
u.setBizId(bizId);
u.setStatus("pending");
leaveReqMapper.updateById(u);
} else if ("travel".equalsIgnoreCase(bizType)) {
HrmTravelReq u = new HrmTravelReq();
u.setBizId(bizId);
u.setStatus("pending");
travelReqMapper.updateById(u);
} else if ("seal".equalsIgnoreCase(bizType)) {
HrmSealReq u = new HrmSealReq();
u.setBizId(bizId);
u.setStatus("pending");
sealReqMapper.updateById(u);
} else if ("reimburse".equalsIgnoreCase(bizType)) {
HrmReimburseReq u = new HrmReimburseReq();
u.setBizId(bizId);
u.setStatus("pending");
reimburseReqMapper.updateById(u);
} else if ("appropriation".equalsIgnoreCase(bizType)) {
HrmAppropriationReq u = new HrmAppropriationReq();
u.setBizId(bizId);
u.setStatus("pending");
appropriationReqMapper.updateById(u);
}
}
public void setBizRejected(String bizType, Long bizId) {
if (bizType == null || bizId == null) return;
if ("leave".equalsIgnoreCase(bizType)) {
HrmLeaveReq u = new HrmLeaveReq();
u.setBizId(bizId);
u.setStatus("rejected");
leaveReqMapper.updateById(u);
} else if ("travel".equalsIgnoreCase(bizType)) {
HrmTravelReq u = new HrmTravelReq();
u.setBizId(bizId);
u.setStatus("rejected");
travelReqMapper.updateById(u);
} else if ("seal".equalsIgnoreCase(bizType)) {
HrmSealReq u = new HrmSealReq();
u.setBizId(bizId);
u.setStatus("rejected");
sealReqMapper.updateById(u);
} else if ("reimburse".equalsIgnoreCase(bizType)) {
HrmReimburseReq u = new HrmReimburseReq();
u.setBizId(bizId);
u.setStatus("rejected");
reimburseReqMapper.updateById(u);
} else if ("appropriation".equalsIgnoreCase(bizType)) {
HrmAppropriationReq u = new HrmAppropriationReq();
u.setBizId(bizId);
u.setStatus("rejected");
appropriationReqMapper.updateById(u);
}
}
}

View File

@@ -1,7 +1,6 @@
package com.ruoyi.hrm.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
@@ -71,7 +70,6 @@ public class HrmAppropriationReqServiceImpl implements IHrmAppropriationReqServi
@Transactional(rollbackFor = Exception.class)
public HrmAppropriationReqVo insertByBo(HrmAppropriationReqBo bo) {
HrmAppropriationReq add = BeanUtil.toBean(bo, HrmAppropriationReq.class);
add.setStatus(defaultStatus(add.getStatus()));
boolean ok = baseMapper.insert(add) > 0;
HrmAppropriationReqVo bean = BeanUtil.toBean(add, HrmAppropriationReqVo.class);
@@ -81,7 +79,7 @@ public class HrmAppropriationReqServiceImpl implements IHrmAppropriationReqServi
saveInvoiceItems("appropriation", add.getBizId(), bo.getInvoiceItems());
}
if (ok && "pending".equalsIgnoreCase(add.getStatus())) {
if (ok) {
// 获取流程启动人ID
Long startUserId = LoginHelper.getUserId();
@@ -137,15 +135,6 @@ public class HrmAppropriationReqServiceImpl implements IHrmAppropriationReqServi
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateStatus(Long bizId, String status) {
HrmAppropriationReq req = new HrmAppropriationReq();
req.setBizId(bizId);
req.setStatus(status);
return baseMapper.updateById(req) > 0;
}
private void saveInvoiceItems(String bizType, Long bizId, List<HrmInvoiceItemBo> boList) {
invoiceItemMapper.delete(Wrappers.<HrmInvoiceItem>lambdaQuery()
.eq(HrmInvoiceItem::getBizType, bizType)
@@ -163,20 +152,5 @@ public class HrmAppropriationReqServiceImpl implements IHrmAppropriationReqServi
invoiceItemMapper.insert(item);
}
}
@SuppressWarnings("unused")
private LambdaQueryWrapper<HrmAppropriationReq> buildQueryWrapper(HrmAppropriationReqBo bo) {
LambdaQueryWrapper<HrmAppropriationReq> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getBizId() != null, HrmAppropriationReq::getBizId, bo.getBizId());
lqw.eq(bo.getEmpId() != null, HrmAppropriationReq::getEmpId, bo.getEmpId());
lqw.eq(bo.getProjectId() != null, HrmAppropriationReq::getProjectId, bo.getProjectId());
lqw.eq(bo.getAppropriationType() != null, HrmAppropriationReq::getAppropriationType, bo.getAppropriationType());
lqw.eq(bo.getStatus() != null, HrmAppropriationReq::getStatus, bo.getStatus());
return lqw;
}
private String defaultStatus(String status) {
return status == null ? "draft" : status;
}
}

View File

@@ -1,7 +1,6 @@
package com.ruoyi.hrm.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
@@ -26,25 +25,30 @@ public class HrmEmployeeServiceImpl implements IHrmEmployeeService {
@Override
public HrmEmployeeVo queryById(Long empId) {
return baseMapper.selectVoById(empId);
// 走 JOIN 版本,返回带 deptName/postName 的完整 VO
return baseMapper.selectEmployeeVoById(empId);
}
@Override
public HrmEmployeeVo queryByUserId(Long userId) {
return baseMapper.selectVoOne(Wrappers.<HrmEmployee>lambdaQuery().eq(HrmEmployee::getUserId, userId));
// 同一个 sys_user 极端情况可能对应多条员工,取 empId 最小的一条兜底
HrmEmployeeBo bo = new HrmEmployeeBo();
bo.setUserId(userId);
List<HrmEmployeeVo> list = baseMapper.selectEmployeeVoList(bo);
return list.isEmpty() ? null : list.get(0);
}
@Override
public TableDataInfo<HrmEmployeeVo> queryPageList(HrmEmployeeBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<HrmEmployee> lqw = buildQueryWrapper(bo);
Page<HrmEmployeeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
// 显式调用 XML 里带 JOIN 的自定义方法,父接口的 selectVoPage default 只会走单表 selectPage
// 拿不到 dept_name / post_name。
Page<HrmEmployeeVo> result = baseMapper.selectEmployeeVoPage(pageQuery.build(), bo);
return TableDataInfo.build(result);
}
@Override
public List<HrmEmployeeVo> queryList(HrmEmployeeBo bo) {
LambdaQueryWrapper<HrmEmployee> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
return baseMapper.selectEmployeeVoList(bo);
}
@Override
@@ -70,17 +74,4 @@ public class HrmEmployeeServiceImpl implements IHrmEmployeeService {
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
return baseMapper.deleteBatchIds(ids) > 0;
}
private LambdaQueryWrapper<HrmEmployee> buildQueryWrapper(HrmEmployeeBo bo) {
LambdaQueryWrapper<HrmEmployee> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getEmpId() != null, HrmEmployee::getEmpId, bo.getEmpId());
lqw.eq(bo.getUserId() != null, HrmEmployee::getUserId, bo.getUserId());
lqw.like(bo.getEmpNo() != null, HrmEmployee::getEmpNo, bo.getEmpNo());
lqw.like(bo.getEmpName() != null, HrmEmployee::getEmpName, bo.getEmpName());
lqw.eq(bo.getStatus() != null, HrmEmployee::getStatus, bo.getStatus());
lqw.eq(bo.getDeptId() != null, HrmEmployee::getDeptId, bo.getDeptId());
lqw.eq(bo.getPostId() != null, HrmEmployee::getPostId, bo.getPostId());
lqw.orderByAsc(HrmEmployee::getEmpNo);
return lqw;
}
}

View File

@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.service.UserService;
@@ -27,7 +28,9 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@@ -42,6 +45,11 @@ public class HrmFlowInstanceServiceImpl implements IHrmFlowInstanceService {
private final UserService userService;
private final HrmFlowCcMapper ccMapper;
private final HrmTravelReqMapper travelReqMapper;
private final HrmLeaveReqMapper leaveReqMapper;
private final HrmSealReqMapper sealReqMapper;
private final HrmReimburseReqMapper reimburseReqMapper;
private final HrmAppropriationReqMapper appropriationReqMapper;
private final ObjectMapper objectMapper;
private final ApplicationEventPublisher eventPublisher;
@Override
@@ -188,9 +196,55 @@ public class HrmFlowInstanceServiceImpl implements IHrmFlowInstanceService {
}
}
}
fillInstanceBizData(result.getRecords());
return TableDataInfo.build(result);
}
@SuppressWarnings("unchecked")
private void fillInstanceBizData(List<HrmFlowInstanceVo> records) {
if (records == null || records.isEmpty()) return;
Map<String, List<Long>> bizIdsByType = records.stream()
.filter(v -> v.getBizType() != null && v.getBizId() != null)
.collect(Collectors.groupingBy(
HrmFlowInstanceVo::getBizType,
Collectors.mapping(HrmFlowInstanceVo::getBizId, Collectors.toList())
));
Map<String, Object> bizDataMap = new HashMap<>();
bizIdsByType.forEach((bizType, bizIds) -> {
if (bizIds.isEmpty()) return;
switch (bizType) {
case "leave":
leaveReqMapper.selectBatchIds(bizIds).forEach(d ->
bizDataMap.put("leave_" + d.getBizId(), objectMapper.convertValue(d, Map.class)));
break;
case "travel":
travelReqMapper.selectBatchIds(bizIds).forEach(d ->
bizDataMap.put("travel_" + d.getBizId(), objectMapper.convertValue(d, Map.class)));
break;
case "seal":
sealReqMapper.selectBatchIds(bizIds).forEach(d ->
bizDataMap.put("seal_" + d.getBizId(), objectMapper.convertValue(d, Map.class)));
break;
case "reimburse":
reimburseReqMapper.selectBatchIds(bizIds).forEach(d ->
bizDataMap.put("reimburse_" + d.getBizId(), objectMapper.convertValue(d, Map.class)));
break;
case "appropriation":
appropriationReqMapper.selectBatchIds(bizIds).forEach(d ->
bizDataMap.put("appropriation_" + d.getBizId(), objectMapper.convertValue(d, Map.class)));
break;
default:
break;
}
});
records.forEach(vo -> {
Object data = bizDataMap.get(vo.getBizType() + "_" + vo.getBizId());
if (data != null) {
vo.setBizData((Map<String, Object>) data);
}
});
}
@Override
public List<HrmFlowInstanceVo> queryList(HrmFlowInstanceBo bo) {
LambdaQueryWrapper<HrmFlowInstance> lqw = buildQueryWrapper(bo);

View File

@@ -40,7 +40,6 @@ public class HrmFlowTaskServiceImpl implements IHrmFlowTaskService {
private final IHrmSealReqService sealReqService;
private final IHrmFlowCcService ccService;
private final FlowAssigneeHelper assigneeHelper;
private final BizStatusSyncHelper bizStatusSyncHelper;
// 注入五个业务Mapper
private final HrmLeaveReqMapper leaveReqMapper;
@@ -199,16 +198,12 @@ private void fillBizData(List<HrmFlowTaskVo> tasks) {
inst.setStatus("approved");
inst.setCurrentNodeId(null);
instanceMapper.updateById(inst);
// 若业务为用印,更新用印状态为已批准,并执行盖章
if ("seal".equalsIgnoreCase(inst.getBizType())) {
sealReqService.updateStatus(inst.getBizId(), "approved");
if (stampBo != null) {
// 盖章动作也写入流转历史
saveAction(taskId, inst.getInstId(), task.getBizType(), task.getBizId(), task.getAssigneeUserId(), "stamp", "盖章", operatorUserId);
sealReqService.stampWithJava(inst.getBizId(), stampBo);
}
// 若业务为用印,执行盖章(状态由 hrm_flow_instance 统一维护,不再回写业务表)
if ("seal".equalsIgnoreCase(inst.getBizType()) && stampBo != null) {
// 盖章动作也写入流转历史
saveAction(taskId, inst.getInstId(), task.getBizType(), task.getBizId(), task.getAssigneeUserId(), "stamp", "盖章", operatorUserId);
sealReqService.stampWithJava(inst.getBizId(), stampBo);
}
bizStatusSyncHelper.setBizApproved(inst.getBizType(), inst.getBizId());
return true;
}
@@ -279,12 +274,9 @@ private void fillBizData(List<HrmFlowTaskVo> tasks) {
inst.setStatus("approved");
inst.setCurrentNodeId(null);
instanceMapper.updateById(inst);
// 若业务为用印,更新用印状态为已批准
if ("seal".equalsIgnoreCase(inst.getBizType())) {
sealReqService.updateStatus(inst.getBizId(), "approved");
if (stampBo != null) {
sealReqService.stampWithJava(inst.getBizId(), stampBo);
}
// 若业务为用印且传入盖章参数,执行盖章
if ("seal".equalsIgnoreCase(inst.getBizType()) && stampBo != null) {
sealReqService.stampWithJava(inst.getBizId(), stampBo);
}
}
return true;
@@ -308,10 +300,6 @@ private void fillBizData(List<HrmFlowTaskVo> tasks) {
inst.setStatus("rejected");
inst.setCurrentNodeId(null);
instanceMapper.updateById(inst);
if ("seal".equalsIgnoreCase(inst.getBizType())) {
sealReqService.updateStatus(inst.getBizId(), "rejected");
}
bizStatusSyncHelper.setBizRejected(inst.getBizType(), inst.getBizId());
return true;
}
@@ -345,7 +333,6 @@ private void fillBizData(List<HrmFlowTaskVo> tasks) {
reTask.setStatus("pending");
baseMapper.insert(reTask);
bizStatusSyncHelper.setBizPending(inst.getBizType(), inst.getBizId());
return true;
}
@@ -358,9 +345,6 @@ private void fillBizData(List<HrmFlowTaskVo> tasks) {
reTask.setAssigneeUserId(actionUserId != null ? actionUserId : task.getAssigneeUserId());
reTask.setStatus("pending");
baseMapper.insert(reTask);
if ("seal".equalsIgnoreCase(inst.getBizType())) {
sealReqService.updateStatus(inst.getBizId(), "running");
}
return true;
}

View File

@@ -1,6 +1,10 @@
package com.ruoyi.hrm.service.impl;
import cn.hutool.core.io.IoUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
@@ -26,22 +30,34 @@ import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 发票识别服务实现:本地三段式管线,无任何外部 API 调用
* 单据识别服务实现:按附件类型分流
*
* <p><b>图片单据</b>jpg/png 等,可不是规范发票):直接调用小米 MiMo 多模态大模型识别,
* 返回标题 + 金额(复用 application.yml 中 mimo.* 配置)。
*
* <p><b>PDF 电子发票</b>:本地三段式管线,无外部 API
* <ol>
* <li>PDFBox 文本层抽取:原生电子发票直接搞定(毫秒级,几乎零算力)</li>
* <li>ZXing 二维码识别:拍照/扫描发票 PDF从二维码读结构化字段</li>
@@ -57,11 +73,28 @@ import java.util.regex.Pattern;
public class HrmInvoiceOcrServiceImpl implements IHrmInvoiceOcrService {
private final SysOssMapper sysOssMapper;
private final ObjectMapper jsonMapper = new ObjectMapper();
/** 可通过 application.yml 覆盖;默认 jar 同级目录下的 tessdata */
@Value("${fad.ocr.tessdata-path:}")
private String tessdataPathConfig;
// === 小米 MiMo 多模态大模型(识别图片单据,复用 application.yml 里的 mimo.* 配置)===
@Value("${mimo.base-url:https://api.xiaomimimo.com/v1}")
private String mimoBaseUrl;
@Value("${mimo.api-key:}")
private String mimoApiKey;
@Value("${mimo.model:mimo-v2.5}")
private String mimoModel;
@Value("${mimo.max-tokens:8192}")
private Integer mimoMaxTokens;
@Value("${mimo.timeout:180}")
private Integer mimoTimeout;
/** 走多模态识别的图片后缀 */
private static final Set<String> IMAGE_SUFFIXES =
new HashSet<>(Arrays.asList("jpg", "jpeg", "png", "webp", "bmp", "gif"));
private String tessdataPath;
@PostConstruct
@@ -108,9 +141,6 @@ public class HrmInvoiceOcrServiceImpl implements IHrmInvoiceOcrService {
throw new ServiceException("附件不存在: " + ossId);
}
String suffix = StringUtils.defaultIfBlank(oss.getFileSuffix(), "").toLowerCase().replace(".", "");
if (!"pdf".equals(suffix)) {
throw new ServiceException("仅支持 PDF 电子发票,当前文件类型: " + suffix);
}
byte[] fileBytes;
try (InputStream in = OssFactory.instance().getObjectContent(oss.getUrl())) {
@@ -119,6 +149,15 @@ public class HrmInvoiceOcrServiceImpl implements IHrmInvoiceOcrService {
throw new ServiceException("读取附件失败: " + e.getMessage());
}
// 图片单据:直接走小米多模态大模型识别(可识别非发票单据)
if (IMAGE_SUFFIXES.contains(suffix)) {
log.info("[Invoice] 图片单据走多模态识别, suffix={}", suffix);
return recognizeImageByMiMo(fileBytes, suffix);
}
if (!"pdf".equals(suffix)) {
throw new ServiceException("仅支持 PDF 电子发票或图片单据(jpg/png),当前文件类型: " + suffix);
}
try (PDDocument doc = PDDocument.load(new ByteArrayInputStream(fileBytes))) {
// 第一步:文本层
String text = extractText(doc);
@@ -342,4 +381,149 @@ public class HrmInvoiceOcrServiceImpl implements IHrmInvoiceOcrService {
return null;
}
}
// ==================== 图片单据:小米多模态识别 ====================
private static final String VISION_SYSTEM_PROMPT =
"你是财务单据识别助手。用户上传的是报销/拨款单据图片,可能是增值税发票、收据、出租车/火车票、"
+ "餐饮小票、合同、对账单等,不一定是规范发票。请仔细识别图片中的费用条目与金额。";
private static final String VISION_USER_PROMPT =
"请识别这张单据,只输出严格的 JSON不要任何解释文字、不要 markdown 代码块),格式:"
+ "{\"items\":[{\"title\":\"简洁的费用标题,如 滴滴出行-市内交通 / 餐饮-海底捞 / XX酒店住宿\",\"amount\":数字}],"
+ "\"totalAmount\":数字}。amount 与 totalAmount 均为纯数字(不带货币符号/逗号);"
+ "识别不到金额则填 0一般一张单据对应一条 items若单据内含多笔明细可拆成多条。";
/** 图片 → 多模态识别 → 结构化结果 */
private HrmInvoiceOcrResultVo recognizeImageByMiMo(byte[] bytes, String suffix) {
if (StringUtils.isBlank(mimoApiKey)) {
throw new ServiceException("未配置 AI 识别服务mimo.api-key无法识别图片单据");
}
String mime = "jpg".equals(suffix) ? "jpeg" : suffix;
String dataUri = "data:image/" + mime + ";base64,"
+ java.util.Base64.getEncoder().encodeToString(bytes);
String content = callMiMoVision(dataUri);
return parseVisionJson(content);
}
/** 调用小米 MiMo /chat/completionsOpenAI 兼容,多模态、非流式),返回 message.content */
private String callMiMoVision(String imageDataUri) {
ObjectNode body = jsonMapper.createObjectNode();
body.put("model", mimoModel);
body.put("max_completion_tokens", mimoMaxTokens);
body.put("max_tokens", mimoMaxTokens);
body.put("temperature", 0.2);
body.put("stream", false);
ArrayNode messages = body.putArray("messages");
messages.addObject().put("role", "system").put("content", VISION_SYSTEM_PROMPT);
ObjectNode userMsg = messages.addObject();
userMsg.put("role", "user");
ArrayNode contentArr = userMsg.putArray("content");
contentArr.addObject().put("type", "text").put("text", VISION_USER_PROMPT);
ObjectNode img = contentArr.addObject();
img.put("type", "image_url");
img.putObject("image_url").put("url", imageDataUri);
HttpURLConnection conn = null;
try {
URL url = new URL(mimoBaseUrl + "/chat/completions");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setConnectTimeout(10_000);
conn.setReadTimeout((mimoTimeout == null ? 180 : mimoTimeout) * 1000);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("api-key", mimoApiKey);
conn.setRequestProperty("Authorization", "Bearer " + mimoApiKey);
try (OutputStream os = conn.getOutputStream()) {
os.write(jsonMapper.writeValueAsString(body).getBytes(StandardCharsets.UTF_8));
}
int code = conn.getResponseCode();
if (code >= 400) {
String err = readStream(conn.getErrorStream());
throw new ServiceException("AI 识别服务返回 " + code + "" + StringUtils.substring(err, 0, 300));
}
JsonNode root = jsonMapper.readTree(readStream(conn.getInputStream()));
JsonNode message = root.path("choices").path(0).path("message");
String content = message.path("content").asText("");
if (StringUtils.isBlank(content)) {
String finish = root.path("choices").path(0).path("finish_reason").asText("");
if ("length".equals(finish)) {
throw new ServiceException("AI 识别输出被截断,请重试或提高 mimo.max-tokens");
}
throw new ServiceException("AI 未返回有效识别内容");
}
return content;
} catch (ServiceException e) {
throw e;
} catch (Exception e) {
log.error("[Invoice] 调用 MiMo 多模态识别失败", e);
throw new ServiceException("AI 识别服务调用失败:" + e.getMessage());
} finally {
if (conn != null) conn.disconnect();
}
}
/** 解析模型返回的 JSON容错去掉 markdown 代码块,截取首尾花括号) */
private HrmInvoiceOcrResultVo parseVisionJson(String content) {
HrmInvoiceOcrResultVo vo = new HrmInvoiceOcrResultVo();
vo.setInvoiceType("AI图片识别");
List<HrmInvoiceOcrResultVo.Item> items = new ArrayList<>();
try {
String jsonStr = extractJson(content);
JsonNode root = jsonMapper.readTree(jsonStr);
JsonNode arr = root.path("items");
if (arr.isArray()) {
for (JsonNode n : arr) {
HrmInvoiceOcrResultVo.Item it = new HrmInvoiceOcrResultVo.Item();
it.setItemName(StringUtils.trimToEmpty(n.path("title").asText("")));
it.setAmount(parseBigDecimal(n.path("amount").asText(null)));
items.add(it);
}
}
JsonNode total = root.get("totalAmount");
if (total != null && !total.isNull()) {
vo.setTotalAmount(parseBigDecimal(total.asText(null)));
}
} catch (Exception e) {
log.warn("[Invoice] 解析 AI 识别 JSON 失败,原始内容: {}", StringUtils.substring(content, 0, 300));
}
if (items.isEmpty()) {
HrmInvoiceOcrResultVo.Item it = new HrmInvoiceOcrResultVo.Item();
it.setItemName("");
it.setAmount(vo.getTotalAmount());
items.add(it);
}
// 无总额时用明细汇总
if (vo.getTotalAmount() == null) {
BigDecimal sum = BigDecimal.ZERO;
for (HrmInvoiceOcrResultVo.Item it : items) {
if (it.getAmount() != null) sum = sum.add(it.getAmount());
}
vo.setTotalAmount(sum);
}
vo.setItems(items);
return vo;
}
/** 从可能带 ```json 包裹或前后缀文字的字符串里截取 JSON 主体 */
private static String extractJson(String raw) {
if (raw == null) return "{}";
String s = raw.trim();
int begin = s.indexOf('{');
int end = s.lastIndexOf('}');
return (begin >= 0 && end > begin) ? s.substring(begin, end + 1) : s;
}
private static String readStream(InputStream in) {
if (in == null) return "";
try (BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
StringBuilder sb = new StringBuilder();
String l;
while ((l = r.readLine()) != null) sb.append(l).append('\n');
return sb.toString();
} catch (Exception e) {
return "";
}
}
}

View File

@@ -1,7 +1,6 @@
package com.ruoyi.hrm.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
@@ -65,12 +64,11 @@ public class HrmLeaveReqServiceImpl implements IHrmLeaveReqService {
@Transactional(rollbackFor = Exception.class)
public HrmLeaveReqVo insertByBo(HrmLeaveReqBo bo) {
HrmLeaveReq add = BeanUtil.toBean(bo, HrmLeaveReq.class);
add.setStatus(defaultStatus(add.getStatus()));
boolean ok = baseMapper.insert(add) > 0;
HrmLeaveReqVo bean = BeanUtil.toBean(add, HrmLeaveReqVo.class);
// 当提交为 pending 时,自动启动流程实例hrm_flow_instance/hrm_flow_task
if (ok && "pending".equalsIgnoreCase(add.getStatus())) {
// 插入成功后自动启动流程实例hrm_flow_instance/hrm_flow_task,状态由 flow_instance 唯一维护
if (ok) {
Long startUserId = LoginHelper.getUserId();
@@ -173,18 +171,4 @@ public class HrmLeaveReqServiceImpl implements IHrmLeaveReqService {
return stats;
}
private LambdaQueryWrapper<HrmLeaveReq> buildQueryWrapper(HrmLeaveReqBo bo) {
LambdaQueryWrapper<HrmLeaveReq> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getBizId() != null, HrmLeaveReq::getBizId, bo.getBizId());
lqw.eq(bo.getEmpId() != null, HrmLeaveReq::getEmpId, bo.getEmpId());
lqw.eq(bo.getProjectId() != null, HrmLeaveReq::getProjectId, bo.getProjectId());
lqw.eq(bo.getLeaveType() != null, HrmLeaveReq::getLeaveType, bo.getLeaveType());
lqw.eq(bo.getStatus() != null, HrmLeaveReq::getStatus, bo.getStatus());
lqw.eq(bo.getStartTime() != null, HrmLeaveReq::getStartTime, bo.getStartTime());
return lqw;
}
private String defaultStatus(String status) {
return status == null ? "draft" : status;
}
}

View File

@@ -2,7 +2,6 @@ package com.ruoyi.hrm.service.impl;
import com.ruoyi.common.helper.LoginHelper;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
@@ -68,7 +67,6 @@ public class HrmReimburseReqServiceImpl implements IHrmReimburseReqService {
@Transactional(rollbackFor = Exception.class)
public HrmReimburseReqVo insertByBo(HrmReimburseReqBo bo) {
HrmReimburseReq add = BeanUtil.toBean(bo, HrmReimburseReq.class);
add.setStatus(defaultStatus(add.getStatus()));
boolean ok = baseMapper.insert(add) > 0;
HrmReimburseReqVo bean = BeanUtil.toBean(add, HrmReimburseReqVo.class);
@@ -78,7 +76,7 @@ public class HrmReimburseReqServiceImpl implements IHrmReimburseReqService {
saveInvoiceItems("reimburse", add.getBizId(), bo.getInvoiceItems());
}
if (ok && "pending".equalsIgnoreCase(add.getStatus())) {
if (ok) {
Long startUserId = LoginHelper.getUserId();
HrmFlowTemplate tpl = null;
@@ -135,16 +133,6 @@ public class HrmReimburseReqServiceImpl implements IHrmReimburseReqService {
}
private LambdaQueryWrapper<HrmReimburseReq> buildQueryWrapper(HrmReimburseReqBo bo) {
LambdaQueryWrapper<HrmReimburseReq> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getBizId() != null, HrmReimburseReq::getBizId, bo.getBizId());
lqw.eq(bo.getEmpId() != null, HrmReimburseReq::getEmpId, bo.getEmpId());
lqw.eq(bo.getProjectId() != null, HrmReimburseReq::getProjectId, bo.getProjectId());
lqw.eq(bo.getReimburseType() != null, HrmReimburseReq::getReimburseType, bo.getReimburseType());
lqw.eq(bo.getStatus() != null, HrmReimburseReq::getStatus, bo.getStatus());
return lqw;
}
private void saveInvoiceItems(String bizType, Long bizId, List<HrmInvoiceItemBo> boList) {
// 先清除旧数据,再插入新数据(更新场景兼容)
invoiceItemMapper.delete(Wrappers.<HrmInvoiceItem>lambdaQuery()
@@ -163,9 +151,5 @@ public class HrmReimburseReqServiceImpl implements IHrmReimburseReqService {
invoiceItemMapper.insert(item);
}
}
private String defaultStatus(String status) {
return status == null ? "draft" : status;
}
}

View File

@@ -2,8 +2,6 @@ package com.ruoyi.hrm.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
@@ -128,7 +126,6 @@ public class HrmSealReqServiceImpl implements IHrmSealReqService {
@Transactional(rollbackFor = Exception.class)
public HrmSealReqVo insertByBo(HrmSealReqBo bo) {
HrmSealReq add = BeanUtil.toBean(bo, HrmSealReq.class);
add.setStatus(defaultStatus(add.getStatus()));
validEntityBeforeSave(add);
boolean ok = baseMapper.insert(add) > 0;
@@ -144,7 +141,6 @@ public class HrmSealReqServiceImpl implements IHrmSealReqService {
start.setContentJson(bo.getContentJson());
Long instId = flowInstanceService.startInstance(start);
updateStatus(add.getBizId(), "running");
bean.setInstId(instId);
}
return bean;
@@ -169,15 +165,6 @@ public class HrmSealReqServiceImpl implements IHrmSealReqService {
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateStatus(Long bizId, String status) {
HrmSealReq req = new HrmSealReq();
req.setBizId(bizId);
req.setStatus(status);
return baseMapper.updateById(req) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public String stampWithJava(Long bizId, HrmSealStampBo cmd) {
@@ -203,25 +190,10 @@ public class HrmSealReqServiceImpl implements IHrmSealReqService {
throw new ServiceException("Python盖章接口未实现");
}
private LambdaQueryWrapper<HrmSealReq> buildQueryWrapper(HrmSealReqBo bo) {
LambdaQueryWrapper<HrmSealReq> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getBizId() != null, HrmSealReq::getBizId, bo.getBizId());
lqw.eq(bo.getEmpId() != null, HrmSealReq::getEmpId, bo.getEmpId());
lqw.eq(bo.getProjectId() != null, HrmSealReq::getProjectId, bo.getProjectId());
lqw.eq(bo.getSealType() != null, HrmSealReq::getSealType, bo.getSealType());
lqw.eq(bo.getStatus() != null, HrmSealReq::getStatus, bo.getStatus());
lqw.orderByDesc(HrmSealReq::getCreateTime);
return lqw;
}
private void validEntityBeforeSave(HrmSealReq entity) {
// 预留数据校验,如唯一约束
}
private String defaultStatus(String status) {
return status == null ? "draft" : status;
}
private String doPdfStamp(HrmSealStampBo cmd) {
try (InputStream pdfIn = getObject(cmd.getTargetFileUrl());
InputStream imgIn = getObject(cmd.getStampImageUrl());

View File

@@ -1,17 +1,18 @@
package com.ruoyi.hrm.service.impl;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.hrm.domain.HrmFlowInstance;
import com.ruoyi.hrm.domain.HrmFlowTemplate;
import com.ruoyi.hrm.domain.HrmTravelReq;
import com.ruoyi.hrm.domain.bo.HrmFlowStartBo;
import com.ruoyi.hrm.domain.bo.HrmTravelReqBo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.hrm.domain.vo.HrmTravelReqVo;
import com.ruoyi.hrm.mapper.HrmFlowInstanceMapper;
import com.ruoyi.hrm.mapper.HrmFlowTemplateMapper;
import com.ruoyi.hrm.mapper.HrmTravelReqMapper;
import com.ruoyi.hrm.service.IHrmFlowInstanceService;
@@ -31,6 +32,7 @@ public class HrmTravelReqServiceImpl implements IHrmTravelReqService {
private final HrmTravelReqMapper baseMapper;
private final HrmFlowTemplateMapper flowTemplateMapper;
private final IHrmFlowInstanceService flowInstanceService;
private final HrmFlowInstanceMapper flowInstanceMapper;
@Override
public HrmTravelReqVo queryById(Long bizId) {
@@ -58,15 +60,12 @@ public class HrmTravelReqServiceImpl implements IHrmTravelReqService {
@Transactional(rollbackFor = Exception.class)
public HrmTravelReqVo insertByBo(HrmTravelReqBo bo) {
HrmTravelReq add = BeanUtil.toBean(bo, HrmTravelReq.class);
add.setStatus(defaultStatus(add.getStatus()));
boolean ok = baseMapper.insert(add) > 0;
HrmTravelReqVo bean = BeanUtil.toBean(add, HrmTravelReqVo.class);
// 业务表状态规范pending/approved/rejected
// 当提交为 pending 时自动启动流程实例hrm_flow_instance/hrm_flow_task
// 1) 优先前端明确选择了模板tplId 不为空)
// 插入成功后自动启动流程实例hrm_flow_instance/hrm_flow_task状态由 flow_instance 唯一维护
HrmFlowTemplate tpl = null;
if (ok && "pending".equalsIgnoreCase(add.getStatus())) {
if (ok) {
if(bo.getTplId() != null){
// 选择启用的最高版本模板(允许无模板:走自选审批人一次性审批)
tpl = flowTemplateMapper.selectOne(Wrappers.<HrmFlowTemplate>lambdaQuery()
@@ -116,20 +115,6 @@ public class HrmTravelReqServiceImpl implements IHrmTravelReqService {
return baseMapper.deleteBatchIds(ids) > 0;
}
private LambdaQueryWrapper<HrmTravelReq> buildQueryWrapper(HrmTravelReqBo bo) {
LambdaQueryWrapper<HrmTravelReq> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getBizId() != null, HrmTravelReq::getBizId, bo.getBizId());
lqw.eq(bo.getEmpId() != null, HrmTravelReq::getEmpId, bo.getEmpId());
lqw.eq(bo.getProjectId() != null, HrmTravelReq::getProjectId, bo.getProjectId());
lqw.eq(bo.getStatus() != null, HrmTravelReq::getStatus, bo.getStatus());
lqw.eq(bo.getStartTime() != null, HrmTravelReq::getStartTime, bo.getStartTime());
return lqw;
}
private String defaultStatus(String status) {
return status == null ? "draft" : status;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int earlyEnd(Long bizId) {
@@ -138,22 +123,23 @@ public class HrmTravelReqServiceImpl implements IHrmTravelReqService {
throw new RuntimeException("出差申请不存在");
}
String status = travelReq.getStatus();
if (!"approved".equals(status) && !"in_progress".equals(status)) {
throw new RuntimeException("当前状态不能提前结束,只有已通过或进行中的出差才能提前结束");
// 出差是否已通过,改由流程实例判定
HrmFlowInstance inst = flowInstanceMapper.selectOne(Wrappers.<HrmFlowInstance>lambdaQuery()
.eq(HrmFlowInstance::getBizType, "travel")
.eq(HrmFlowInstance::getBizId, bizId)
.orderByDesc(HrmFlowInstance::getInstId)
.last("limit 1"));
if (inst == null || !"approved".equalsIgnoreCase(inst.getStatus())) {
throw new RuntimeException("当前状态不能提前结束,只有已通过的出差才能提前结束");
}
// 3. 检查是否已经提前结束过
if (travelReq.getActualEndTime() != null) {
throw new RuntimeException("该出差已经提前结束过了");
}
// 4. 更新实际结束时间为当前时间
// 更新实际结束时间为当前时间;「已完成」由 actualEndTime 判定,无需单独回写状态
travelReq.setActualEndTime(new Date());
// 5. 可选:更新状态为已完成
travelReq.setStatus("completed");
// 6. 执行更新
int result = baseMapper.updateById(travelReq);
if (result <= 0) {
throw new RuntimeException("提前结束失败");

View File

@@ -11,7 +11,6 @@
<result column="bank_name" property="bankName"/>
<result column="bank_account" property="bankAccount"/>
<result column="reason" property="reason"/>
<result column="status" property="status"/>
<result column="accessory_apply_ids" property="accessoryApplyIds"/>
<result column="accessory_receipt_ids" property="accessoryReceiptIds"/>
<result column="remark" property="remark"/>
@@ -99,9 +98,6 @@
<if test="bo.appropriationType != null and bo.appropriationType != ''">
AND a.appropriation_type = #{bo.appropriationType}
</if>
<if test="bo.status != null and bo.status != ''">
AND a.status = #{bo.status}
</if>
ORDER BY a.create_time DESC
</select>
@@ -139,9 +135,6 @@
<if test="bo.appropriationType != null and bo.appropriationType != ''">
AND a.appropriation_type = #{bo.appropriationType}
</if>
<if test="bo.status != null and bo.status != ''">
AND a.status = #{bo.status}
</if>
ORDER BY a.create_time DESC
</select>
</mapper>

View File

@@ -48,31 +48,58 @@
<result column="update_time" property="updateTime"/>
</resultMap>
<!-- 基础 SELECT + JOIN。dept_id 兼容员工表未维护部门时兜底到 sys_user.dept_id -->
<sql id="selectVo">
SELECT
e.emp_id, e.user_id, e.emp_no, e.emp_name, e.gender, e.mobile, e.email, e.id_no,
e.hire_date, e.employment_type, e.status, su.dept_id, e.post_id, e.remark,
e.hire_date, e.employment_type, e.status,
COALESCE(e.dept_id, su.dept_id) AS dept_id,
e.post_id, e.remark,
e.create_by, e.create_time, e.update_by, e.update_time,
d.dept_name,
p.post_name
FROM hrm_employee e
left join sys_user su on su.user_id = e.user_id
LEFT JOIN sys_dept d ON su.dept_id = d.dept_id AND d.del_flag = 0
LEFT JOIN sys_user su ON su.user_id = e.user_id
LEFT JOIN sys_dept d ON d.dept_id = COALESCE(e.dept_id, su.dept_id) AND d.del_flag = '0'
LEFT JOIN sys_post p ON e.post_id = p.post_id
WHERE e.del_flag = 0
</sql>
<!-- 使用 JOIN 查询的 select 语句,确保使用 VoResultMap -->
<select id="selectVoPage" resultMap="VoResultMap">
<include refid="selectVo"/>
</select>
<sql id="whereBo">
<if test="bo != null">
<if test="bo.empId != null"> AND e.emp_id = #{bo.empId} </if>
<if test="bo.userId != null"> AND e.user_id = #{bo.userId} </if>
<if test="bo.empNo != null and bo.empNo != ''">
AND e.emp_no LIKE CONCAT('%', #{bo.empNo}, '%')
</if>
<if test="bo.empName != null and bo.empName != ''">
AND (e.emp_name LIKE CONCAT('%', #{bo.empName}, '%')
OR e.emp_no LIKE CONCAT('%', #{bo.empName}, '%'))
</if>
<if test="bo.status != null and bo.status != ''">
AND e.status = #{bo.status}
</if>
<if test="bo.deptId != null">
AND COALESCE(e.dept_id, su.dept_id) = #{bo.deptId}
</if>
<if test="bo.postId != null"> AND e.post_id = #{bo.postId} </if>
</if>
</sql>
<select id="selectVoList" resultMap="VoResultMap">
<include refid="selectVo"/>
</select>
<select id="selectVoById" resultMap="VoResultMap">
<select id="selectEmployeeVoById" resultMap="VoResultMap">
<include refid="selectVo"/>
AND e.emp_id = #{empId}
</select>
<select id="selectEmployeeVoList" resultMap="VoResultMap">
<include refid="selectVo"/>
<include refid="whereBo"/>
ORDER BY e.emp_no
</select>
<select id="selectEmployeeVoPage" resultMap="VoResultMap">
<include refid="selectVo"/>
<include refid="whereBo"/>
ORDER BY e.emp_no
</select>
</mapper>

View File

@@ -10,7 +10,6 @@
<result column="end_time" property="endTime"/>
<result column="hours" property="hours"/>
<result column="reason" property="reason"/>
<result column="status" property="status"/>
<result column="accessory_apply_ids" property="accessoryApplyIds"/>
<result column="accessory_receipt_ids" property="accessoryReceiptIds"/>
<result column="remark" property="remark"/>
@@ -98,9 +97,6 @@
<if test="bo.leaveType != null and bo.leaveType != ''">
AND l.leave_type = #{bo.leaveType}
</if>
<if test="bo.status != null and bo.status != ''">
AND l.status = #{bo.status}
</if>
<if test="bo.startTime != null">
AND l.start_time = #{bo.startTime}
</if>
@@ -141,9 +137,6 @@
<if test="bo.leaveType != null and bo.leaveType != ''">
AND l.leave_type = #{bo.leaveType}
</if>
<if test="bo.status != null and bo.status != ''">
AND l.status = #{bo.status}
</if>
<if test="bo.startTime != null">
AND l.start_time = #{bo.startTime}
</if>
@@ -154,20 +147,22 @@
SELECT
COUNT(*) as totalRequests,
SUM(hours) as totalHours
FROM hrm_leave_req
WHERE del_flag = 0
AND status = 'approved'
FROM hrm_leave_req l
WHERE l.del_flag = 0
AND EXISTS (SELECT 1 FROM hrm_flow_instance fi
WHERE fi.biz_type = 'leave' AND fi.biz_id = l.biz_id AND fi.status = 'approved')
</select>
<select id="selectLeaveByType" resultType="java.util.Map">
SELECT
leave_type as leaveType,
l.leave_type as leaveType,
COUNT(*) as count,
SUM(hours) as totalHours
FROM hrm_leave_req
WHERE del_flag = 0
AND status = 'approved'
GROUP BY leave_type
SUM(l.hours) as totalHours
FROM hrm_leave_req l
WHERE l.del_flag = 0
AND EXISTS (SELECT 1 FROM hrm_flow_instance fi
WHERE fi.biz_type = 'leave' AND fi.biz_id = l.biz_id AND fi.status = 'approved')
GROUP BY l.leave_type
ORDER BY totalHours DESC
</select>
@@ -180,21 +175,23 @@
JOIN hrm_employee e ON l.emp_id = e.emp_id AND e.del_flag = 0
LEFT JOIN sys_dept d ON e.dept_id = d.dept_id AND d.del_flag = '0'
WHERE l.del_flag = 0
AND l.status = 'approved'
AND EXISTS (SELECT 1 FROM hrm_flow_instance fi
WHERE fi.biz_type = 'leave' AND fi.biz_id = l.biz_id AND fi.status = 'approved')
GROUP BY d.dept_id, d.dept_name
ORDER BY totalHours DESC
</select>
<select id="selectLeaveByMonth" resultType="java.util.Map">
SELECT
DATE_FORMAT(start_time, '%Y-%m') as month,
DATE_FORMAT(l.start_time, '%Y-%m') as month,
COUNT(*) as count,
SUM(hours) as totalHours
FROM hrm_leave_req
WHERE del_flag = 0
AND status = 'approved'
AND YEAR(start_time) = #{year}
GROUP BY DATE_FORMAT(start_time, '%Y-%m')
SUM(l.hours) as totalHours
FROM hrm_leave_req l
WHERE l.del_flag = 0
AND EXISTS (SELECT 1 FROM hrm_flow_instance fi
WHERE fi.biz_type = 'leave' AND fi.biz_id = l.biz_id AND fi.status = 'approved')
AND YEAR(l.start_time) = #{year}
GROUP BY DATE_FORMAT(l.start_time, '%Y-%m')
ORDER BY month
</select>
@@ -206,7 +203,8 @@
SELECT COUNT(DISTINCT l.emp_id)
FROM hrm_leave_req l
WHERE l.del_flag = 0
AND l.status = 'approved'
AND EXISTS (SELECT 1 FROM hrm_flow_instance fi
WHERE fi.biz_type = 'leave' AND fi.biz_id = l.biz_id AND fi.status = 'approved')
AND NOW() BETWEEN l.start_time AND l.end_time
</select>
</mapper>

View File

@@ -8,7 +8,6 @@
<result column="reimburse_type" property="reimburseType"/>
<result column="total_amount" property="totalAmount"/>
<result column="reason" property="reason"/>
<result column="status" property="status"/>
<result column="accessory_apply_ids" property="accessoryApplyIds"/>
<result column="accessory_receipt_ids" property="accessoryReceiptIds"/>
<result column="remark" property="remark"/>
@@ -96,9 +95,6 @@
<if test="bo.reimburseType != null and bo.reimburseType != ''">
AND r.reimburse_type = #{bo.reimburseType}
</if>
<if test="bo.status != null and bo.status != ''">
AND r.status = #{bo.status}
</if>
ORDER BY r.create_time DESC
</select>
@@ -136,9 +132,6 @@
<if test="bo.reimburseType != null and bo.reimburseType != ''">
AND r.reimburse_type = #{bo.reimburseType}
</if>
<if test="bo.status != null and bo.status != ''">
AND r.status = #{bo.status}
</if>
ORDER BY r.create_time DESC
</select>
</mapper>

View File

@@ -11,7 +11,6 @@
<result column="receipt_required" property="receiptRequired"/>
<result column="receipt_status" property="receiptStatus"/>
<result column="receipt_file_ids" property="receiptFileIds"/>
<result column="status" property="status"/>
<result column="remark" property="remark"/>
<result column="create_by" property="createBy"/>
<result column="create_time" property="createTime"/>
@@ -100,9 +99,6 @@
<if test="bo.sealType != null and bo.sealType != ''">
AND s.seal_type = #{bo.sealType}
</if>
<if test="bo.status != null and bo.status != ''">
AND s.status = #{bo.status}
</if>
ORDER BY s.create_time DESC
</select>
@@ -140,9 +136,6 @@
<if test="bo.sealType != null and bo.sealType != ''">
AND s.seal_type = #{bo.sealType}
</if>
<if test="bo.status != null and bo.status != ''">
AND s.status = #{bo.status}
</if>
ORDER BY s.create_time DESC
</select>
</mapper>

View File

@@ -10,7 +10,6 @@
<result column="travel_type" property="travelType"/>
<result column="destination" property="destination"/>
<result column="reason" property="reason"/>
<result column="status" property="status"/>
<result column="accessory_apply_ids" property="accessoryApplyIds"/>
<result column="accessory_receipt_ids" property="accessoryReceiptIds"/>
<result column="payee_name" property="payeeName"/>
@@ -99,9 +98,6 @@
<if test="bo.projectId != null">
AND t.project_id = #{bo.projectId}
</if>
<if test="bo.status != null and bo.status != ''">
AND t.status = #{bo.status}
</if>
<if test="bo.startTime != null">
AND t.start_time = #{bo.startTime}
</if>
@@ -139,9 +135,6 @@
<if test="bo.projectId != null">
AND t.project_id = #{bo.projectId}
</if>
<if test="bo.status != null and bo.status != ''">
AND t.status = #{bo.status}
</if>
<if test="bo.startTime != null">
AND t.start_time = #{bo.startTime}
</if>

View File

@@ -0,0 +1,47 @@
const mysql = require('mysql2/promise');
async function run() {
const conn = await mysql.createConnection({
host: '49.232.154.205',
port: 13306,
user: 'root',
password: 'Root@12345',
database: 'fad_oa_dev'
});
console.log('Connected. Running migration...\n');
// 1. Add manager_id to fad_rm_project
await conn.execute(`
ALTER TABLE fad_rm_project
ADD COLUMN manager_id BIGINT DEFAULT NULL COMMENT '项目经理用户ID关联sys_user.user_id'
AFTER manager
`);
console.log('✓ Added manager_id to fad_rm_project');
// 2. Create fad_rm_project_member table
await conn.execute(`
CREATE TABLE IF NOT EXISTS fad_rm_project_member (
member_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '成员ID',
project_id BIGINT NOT NULL COMMENT '项目ID',
user_id BIGINT NOT NULL COMMENT '用户ID',
role VARCHAR(50) DEFAULT 'member' COMMENT '角色: manager/member/viewer',
create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
del_flag INT DEFAULT 0 COMMENT '删除标志',
PRIMARY KEY (member_id),
UNIQUE KEY uk_project_user (project_id, user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目成员表'
`);
console.log('✓ Created fad_rm_project_member table');
await conn.end();
console.log('\nMigration complete!');
}
run().catch(err => {
console.error('Migration failed:', err.message);
process.exit(1);
});

40
fad-rolling-mill/pom.xml Normal file
View File

@@ -0,0 +1,40 @@
<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.ruoyi</groupId>
<artifactId>ruoyi-flowable-plus</artifactId>
<version>0.8.3</version>
</parent>
<artifactId>fad-rolling-mill</artifactId>
<name>fad-rolling-mill</name>
<description>连轧机/可逆轧机设备总包项目管理系统</description>
<dependencies>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-system</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
<version>3.5.9</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.35</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,132 @@
const mysql = require('mysql2/promise');
async function run() {
const conn = await mysql.createConnection({
host: '49.232.154.205', port: 13306, user: 'root', password: 'Root@12345',
database: 'fad_oa_dev',
supportBigNumbers: true,
bigNumberStrings: true
});
// 获取真实项目ID避免JS Number精度丢失
const [projs] = await conn.execute('SELECT project_id, project_name FROM fad_rm_project ORDER BY project_id');
const PROJ_A = projs[0].project_id; // 1380mm六辊可逆轧机设备总包项目
const PROJ_B = projs[1].project_id; // 测试项目A
console.log('项目A ID:', PROJ_A, projs[0].project_name);
console.log('项目B ID:', PROJ_B, projs[1].project_name);
console.log('');
// 清除两项目现有数据
const tables = ['fad_rm_budget','fad_rm_tech_plan_item','fad_rm_layout_file','fad_rm_tech_review_item','fad_rm_drawing_design','fad_rm_drawing_review','fad_rm_procurement_progress','fad_rm_mfg_device','fad_rm_drawing_compare','fad_rm_doc_lib','fad_rm_site_mod','fad_rm_shipping_checklist','fad_rm_manual','fad_rm_install_tool','fad_rm_install_feedback','fad_rm_acceptance_checklist','fad_rm_commissioning_checklist'];
for (const t of tables) {
await conn.execute('DELETE FROM ' + t + ' WHERE project_id IN (?,?)', [PROJ_A, PROJ_B]);
}
console.log('已清除两项目旧数据\n');
//==================== 项目A6 done + 5 progress + 6 pending ====================
console.log('--- 项目A1380mm六辊可逆轧机设备总包项目 ---');
await conn.execute("INSERT INTO fad_rm_budget (project_id,category,item,budget_amount,spent_amount,status) VALUES (?,?,?,?,?,?)", [PROJ_A,'电气','主电机','500000','480000','approved']);
await conn.execute("INSERT INTO fad_rm_budget (project_id,category,item,budget_amount,spent_amount,status) VALUES (?,?,?,?,?,?)", [PROJ_A,'机械','轧机机架','800000','790000','approved']);
await conn.execute("INSERT INTO fad_rm_budget (project_id,category,item,budget_amount,spent_amount,status) VALUES (?,?,?,?,?,?)", [PROJ_A,'液压','液压站','300000','290000','approved']);
console.log(' budget: 3条 (全部approved → done)');
await conn.execute("INSERT INTO fad_rm_tech_plan_item (project_id,item_name,description,owner,status) VALUES (?,?,?,?,?)", [PROJ_A,'1380mm六辊轧机技术方案','主传动系统方案设计','张工','approved']);
await conn.execute("INSERT INTO fad_rm_tech_plan_item (project_id,item_name,description,owner,status) VALUES (?,?,?,?,?)", [PROJ_A,'AGC液压系统方案','厚度自动控制系统','李工','pending']);
console.log(' tech_plan: 2条 → progress');
await conn.execute("INSERT INTO fad_rm_layout_file (project_id,file_name,file_type,status) VALUES (?,?,?,?)", [PROJ_A,'车间总布局图','dwg','approved']);
await conn.execute("INSERT INTO fad_rm_layout_file (project_id,file_name,file_type,status) VALUES (?,?,?,?)", [PROJ_A,'设备基础图','pdf','pending']);
console.log(' layout: 2条 → progress');
console.log(' tech_review: 0条 → pending');
await conn.execute("INSERT INTO fad_rm_drawing_design (project_id,drawing_name,drawing_no,drawer,status) VALUES (?,?,?,?,?)", [PROJ_A,'轧机机架装配图','DR-001','王工','approved']);
await conn.execute("INSERT INTO fad_rm_drawing_design (project_id,drawing_name,drawing_no,drawer,status) VALUES (?,?,?,?,?)", [PROJ_A,'主传动系统图','DR-002','王工','approved']);
console.log(' drawing_design: 2条 (全部approved → done)');
console.log(' drawing_review: 0条 → pending');
console.log(' procurement: 0条 → pending');
console.log(' manufacturing: 0条 → pending');
console.log(' drawing_compare: 0条 → pending');
console.log(' doc_lib: 0条 → pending');
console.log(' site_mod: 0条 → pending');
await conn.execute("INSERT INTO fad_rm_shipping_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)", [PROJ_A,'主电机','1','1']);
await conn.execute("INSERT INTO fad_rm_shipping_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)", [PROJ_A,'轧机机架','1','2']);
await conn.execute("INSERT INTO fad_rm_shipping_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)", [PROJ_A,'液压站','1','3']);
console.log(' shipping: 3条 (全部已勾选 → done)');
console.log(' manuals: 0条 → pending');
await conn.execute("INSERT INTO fad_rm_install_tool (project_id,name,spec,qty,unit,status,category) VALUES (?,?,?,?,?,?,?)", [PROJ_A,'千斤顶','50T','4','台','已到位','起重工具']);
await conn.execute("INSERT INTO fad_rm_install_tool (project_id,name,spec,qty,unit,status,category) VALUES (?,?,?,?,?,?,?)", [PROJ_A,'扭力扳手','200N·m','2','把','待确认','安装工具']);
await conn.execute("INSERT INTO fad_rm_install_tool (project_id,name,spec,qty,unit,status,category) VALUES (?,?,?,?,?,?,?)", [PROJ_A,'水平仪','0.02mm/m','1','台','待确认','测量工具']);
console.log(' install_tool: 3条 → progress');
console.log(' install_feedback: 0条 → pending');
console.log(' acceptance: 0条 → pending');
console.log(' commissioning: 0条 → pending');
//==================== 项目B3 done + 8 progress + 6 pending ====================
console.log('\n--- 项目B测试项目A ---');
await conn.execute("INSERT INTO fad_rm_budget (project_id,category,item,budget_amount,spent_amount,status) VALUES (?,?,?,?,?,?)", [PROJ_B,'电气','传感器','50000','30000','approved']);
await conn.execute("INSERT INTO fad_rm_budget (project_id,category,item,budget_amount,spent_amount,status) VALUES (?,?,?,?,?,?)", [PROJ_B,'机械','支架','80000','0','draft']);
console.log(' budget: 2条 (1 approved → progress)');
console.log(' tech_plan: 0条 → pending');
console.log(' layout: 0条 → pending');
await conn.execute("INSERT INTO fad_rm_tech_review_item (project_id,review_type,item_name,conclusion,reviewer) VALUES (?,?,?,?,?)", [PROJ_B,'电气','PLC控制柜方案','approved','赵工']);
await conn.execute("INSERT INTO fad_rm_tech_review_item (project_id,review_type,item_name,conclusion,reviewer) VALUES (?,?,?,?,?)", [PROJ_B,'机械','底座安装方案','pending','钱工']);
console.log(' tech_review: 2条 → progress');
console.log(' drawing_design: 0条 → pending');
await conn.execute("INSERT INTO fad_rm_drawing_review (project_id,drawing_name,drawing_no,reviewer,status) VALUES (?,?,?,?,?)", [PROJ_B,'底座基础图','BASE-001','孙工','approved']);
console.log(' drawing_review: 1条 (approved → done)');
await conn.execute("INSERT INTO fad_rm_procurement_progress (project_id,item_name,supplier_name,amount,current_stage) VALUES (?,?,?,?,?)", [PROJ_B,'电机','上海电机厂','120000','1']);
await conn.execute("INSERT INTO fad_rm_procurement_progress (project_id,item_name,supplier_name,amount,current_stage) VALUES (?,?,?,?,?)", [PROJ_B,'减速机','南京减速机厂','80000','2']);
console.log(' procurement: 2条 → progress');
await conn.execute("INSERT INTO fad_rm_mfg_device (project_id,device_name,spec,supplier_name,delivery_date) VALUES (?,?,?,?,?)", [PROJ_B,'主电机','500kW','上海电机厂','2026-08-15']);
await conn.execute("INSERT INTO fad_rm_mfg_device (project_id,device_name,spec,supplier_name,delivery_date) VALUES (?,?,?,?,?)", [PROJ_B,'减速机','ZLY560','南京减速机厂','2026-09-01']);
console.log(' manufacturing: 2条 → progress');
console.log(' drawing_compare: 0条 → pending');
await conn.execute("INSERT INTO fad_rm_doc_lib (project_id,doc_name,category,version,uploader,description) VALUES (?,?,?,?,?,?)", [PROJ_B,'技术规格书','技术文档','V1.0','周工','电机技术参数']);
await conn.execute("INSERT INTO fad_rm_doc_lib (project_id,doc_name,category,version,uploader,description) VALUES (?,?,?,?,?,?)", [PROJ_B,'检测报告','质检报告','V1.0','吴工','出厂检测报告']);
console.log(' doc_lib: 2条 → progress');
await conn.execute("INSERT INTO fad_rm_site_mod (project_id,device_name,location,mod_reason,status) VALUES (?,?,?,?,?)", [PROJ_B,'底座','基础坑','基础尺寸偏差20mm','pending']);
console.log(' site_mod: 1条 → progress');
console.log(' shipping: 0条 → pending');
await conn.execute("INSERT INTO fad_rm_manual (project_id,manual_name,doc_type,version,description) VALUES (?,?,?,?,?)", [PROJ_B,'操作手册','说明书','V1.0','主电机操作说明']);
await conn.execute("INSERT INTO fad_rm_manual (project_id,manual_name,doc_type,version,description) VALUES (?,?,?,?,?)", [PROJ_B,'维护手册','维护手册','V1.0','日常维护指南']);
console.log(' manuals: 2条 → progress');
console.log(' install_tool: 0条 → pending');
await conn.execute("INSERT INTO fad_rm_install_feedback (project_id,title,location,issue_desc,status) VALUES (?,?,?,?,?)", [PROJ_B,'地脚螺栓孔偏位','基础坑','地脚螺栓孔位偏差5mm','pending']);
await conn.execute("INSERT INTO fad_rm_install_feedback (project_id,title,location,issue_desc,status) VALUES (?,?,?,?,?)", [PROJ_B,'电缆预留不足','电气室','进线电缆预留长度不够','solved']);
console.log(' install_feedback: 2条 → progress');
await conn.execute("INSERT INTO fad_rm_acceptance_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)", [PROJ_B,'设备外观检查','1','1']);
await conn.execute("INSERT INTO fad_rm_acceptance_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)", [PROJ_B,'安装精度检查','1','2']);
await conn.execute("INSERT INTO fad_rm_acceptance_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)", [PROJ_B,'电气接线检查','1','3']);
console.log(' acceptance: 3条 (全部已勾选 → done)');
console.log(' commissioning: 0条 → pending');
await conn.end();
console.log('\n=== 测试数据插入完成 ===');
console.log('项目A: 3 done (budget, drawing_design, shipping) + 3 progress (tech_plan, layout, install_tool) + 11 pending');
console.log('项目B: 2 done (drawing_review, acceptance) + 8 progress + 7 pending');
}
run().catch(e => { console.error(e); process.exit(1); });

View File

@@ -0,0 +1,585 @@
const mysql = require('mysql2/promise');
async function run() {
const conn = await mysql.createConnection({
host: '49.232.154.205', port: 13306, user: 'root', password: 'Root@12345',
database: 'fad_oa_dev',
supportBigNumbers: true,
bigNumberStrings: true
});
// 获取测试项目A的ID
const [projs] = await conn.execute(
"SELECT project_id, project_name FROM fad_rm_project WHERE project_name LIKE '%测试%' ORDER BY project_id LIMIT 1"
);
if (projs.length === 0) {
console.error('未找到测试项目');
await conn.end();
return;
}
const PID = projs[0].project_id;
console.log('测试项目A ID:', PID, projs[0].project_name);
// 清除该项目所有旧数据
// 注fad_rm_mfg_stage 通过 device_id 关联fad_rm_site_mod_media 通过 mod_id 关联,单独处理
const tables = [
'fad_rm_budget','fad_rm_tech_plan_item','fad_rm_layout_file','fad_rm_tech_review_item',
'fad_rm_drawing_design','fad_rm_drawing_review','fad_rm_procurement_quote',
'fad_rm_procurement_contract','fad_rm_procurement_progress','fad_rm_mfg_device',
'fad_rm_drawing_compare','fad_rm_doc_lib','fad_rm_site_mod',
'fad_rm_shipping_checklist','fad_rm_shipping_item',
'fad_rm_manual','fad_rm_install_tool','fad_rm_install_personnel',
'fad_rm_install_precision','fad_rm_install_progress','fad_rm_install_daily',
'fad_rm_install_handover','fad_rm_install_feedback','fad_rm_acceptance_item',
'fad_rm_acceptance_checklist','fad_rm_commissioning_checklist',
'fad_rm_commissioning_clause','fad_rm_commissioning_record'
];
for (const t of tables) {
await conn.execute('DELETE FROM ' + t + ' WHERE project_id = ?', [PID]);
}
// 制造阶段通过 device_id 关联
await conn.execute(
'DELETE FROM fad_rm_mfg_stage WHERE device_id IN (SELECT device_id FROM fad_rm_mfg_device WHERE project_id = ?)',
[PID]
);
// 现场修改多媒体通过 mod_id 关联
await conn.execute('DELETE FROM fad_rm_site_mod_media WHERE mod_id IN (SELECT mod_id FROM fad_rm_site_mod WHERE project_id = ?)', [PID]);
console.log('已清除测试项目A旧数据\n');
// =====================================================================
// 1. 项目预算 fad_rm_budget
// =====================================================================
console.log('--- 1. 项目预算 ---');
await conn.execute(
"INSERT INTO fad_rm_budget (project_id,category,item,budget_amount,spent_amount,status) VALUES (?,?,?,?,?,?)",
[PID, '电气设备', '传感器模组', 50000, 30000, 'approved']
);
await conn.execute(
"INSERT INTO fad_rm_budget (project_id,category,item,budget_amount,spent_amount,status) VALUES (?,?,?,?,?,?)",
[PID, '机械设备', '底座支架加工', 80000, 0, 'draft']
);
await conn.execute(
"INSERT INTO fad_rm_budget (project_id,category,item,budget_amount,spent_amount,status) VALUES (?,?,?,?,?,?)",
[PID, '液压设备', '液压缸总成', 120000, 50000, 'approved']
);
await conn.execute(
"INSERT INTO fad_rm_budget (project_id,category,item,budget_amount,spent_amount,status) VALUES (?,?,?,?,?,?)",
[PID, '安装费用', '现场安装调试费', 60000, 0, 'draft']
);
console.log(' 4条预算 √');
// =====================================================================
// 2. 技术方案 fad_rm_tech_plan_item
// =====================================================================
console.log('--- 2. 技术方案 ---');
await conn.execute(
"INSERT INTO fad_rm_tech_plan_item (project_id,item_name,description,owner,status) VALUES (?,?,?,?,?)",
[PID, 'PLC控制方案设计', '西门子S7-1500系列PLC控制方案', '赵工', 'done']
);
await conn.execute(
"INSERT INTO fad_rm_tech_plan_item (project_id,item_name,description,owner,status) VALUES (?,?,?,?,?)",
[PID, '液压系统方案', '液压站及管路布局设计', '钱工', 'progress']
);
await conn.execute(
"INSERT INTO fad_rm_tech_plan_item (project_id,item_name,description,owner,status) VALUES (?,?,?,?,?)",
[PID, '电气布线方案', '主电机及辅机电气管线走向', '孙工', 'pending']
);
console.log(' 3条方案 √');
// =====================================================================
// 3. 布局图 fad_rm_layout_file
// =====================================================================
console.log('--- 3. 布局图 ---');
await conn.execute(
"INSERT INTO fad_rm_layout_file (project_id,file_name,file_type,upload_date,status,version,file_url) VALUES (?,?,?,?,?,?,?)",
[PID, '设备基础布局图', 'DWG', '2026-06-01', 'approved', 'V1.0', '/upload/rm/layout/PID/base_layout.dwg']
);
await conn.execute(
"INSERT INTO fad_rm_layout_file (project_id,file_name,file_type,upload_date,status,version,file_url) VALUES (?,?,?,?,?,?,?)",
[PID, '电气室布局图', 'PDF', '2026-06-05', 'pending', 'V0.9', '/upload/rm/layout/PID/electrical_room.pdf']
);
await conn.execute(
"INSERT INTO fad_rm_layout_file (project_id,file_name,file_type,upload_date,status,version,file_url) VALUES (?,?,?,?,?,?,?)",
[PID, '液压站平面图', 'DWG', '2026-06-10', 'pending', 'V1.0', '/upload/rm/layout/PID/hydraulic_plan.dwg']
);
console.log(' 3个布局图 √');
// =====================================================================
// 4. 技术审查 fad_rm_tech_review_item
// =====================================================================
console.log('--- 4. 技术审查 ---');
await conn.execute(
"INSERT INTO fad_rm_tech_review_item (project_id,review_type,item_name,conclusion,reviewer,review_date,review_opinion) VALUES (?,?,?,?,?,?,?)",
[PID, 'electrical', 'PLC控制柜方案', 'pass', '赵工', '2026-06-08', '方案符合要求,同意通过']
);
await conn.execute(
"INSERT INTO fad_rm_tech_review_item (project_id,review_type,item_name,conclusion,reviewer,review_date,review_opinion) VALUES (?,?,?,?,?,?,?)",
[PID, 'mechanical', '底座安装方案', 'pending', '钱工', null, '待补充强度计算书']
);
await conn.execute(
"INSERT INTO fad_rm_tech_review_item (project_id,review_type,item_name,conclusion,reviewer,review_date,review_opinion) VALUES (?,?,?,?,?,?,?)",
[PID, 'hydraulic', '液压管路设计审查', 'pass', '孙工', '2026-06-12', '管路走向合理,密封选型正确']
);
console.log(' 3条审查 √');
// =====================================================================
// 5. 图纸设计 fad_rm_drawing_design
// =====================================================================
console.log('--- 5. 图纸设计 ---');
await conn.execute(
"INSERT INTO fad_rm_drawing_design (project_id,drawing_name,drawing_no,version,drawing_type,drawer,start_date,end_date,file_url,status) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '底座基础图', 'BASE-001', 'V1.0', '零件图', '王工', '2026-05-20', '2026-06-01', '/upload/rm/dwg/PID/base_001.dwg', 'completed']
);
await conn.execute(
"INSERT INTO fad_rm_drawing_design (project_id,drawing_name,drawing_no,version,drawing_type,drawer,start_date,end_date,file_url,status) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '电气原理图', 'ELEC-001', 'V0.8', '电气原理图', '周工', '2026-06-01', null, '/upload/rm/dwg/PID/elec_001.dwg', 'in_progress']
);
await conn.execute(
"INSERT INTO fad_rm_drawing_design (project_id,drawing_name,drawing_no,version,drawing_type,drawer,start_date,end_date,file_url,status) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '液压系统图', 'HYD-001', 'V1.0', '液压原理图', '吴工', '2026-05-25', '2026-06-10', '/upload/rm/dwg/PID/hyd_001.dwg', 'completed']
);
console.log(' 3张图纸 √');
// =====================================================================
// 6. 图纸审查 fad_rm_drawing_review
// =====================================================================
console.log('--- 6. 图纸审查 ---');
await conn.execute(
"INSERT INTO fad_rm_drawing_review (project_id,drawing_name,drawing_no,version,file_url,status,reviewer,review_date,review_opinion) VALUES (?,?,?,?,?,?,?,?,?)",
[PID, '底座基础图', 'BASE-001', 'V1.0', '/upload/rm/dwg/PID/base_001.dwg', 'approved', '孙工', '2026-06-05', '尺寸标注完整,同意通过']
);
await conn.execute(
"INSERT INTO fad_rm_drawing_review (project_id,drawing_name,drawing_no,version,file_url,status,reviewer,review_date,review_opinion) VALUES (?,?,?,?,?,?,?,?,?)",
[PID, '电气原理图', 'ELEC-001', 'V0.8', '/upload/rm/dwg/PID/elec_001.dwg', 'pending', '李工', null, null]
);
await conn.execute(
"INSERT INTO fad_rm_drawing_review (project_id,drawing_name,drawing_no,version,file_url,status,reviewer,review_date,review_opinion) VALUES (?,?,?,?,?,?,?,?,?)",
[PID, '液压系统图', 'HYD-001', 'V1.0', '/upload/rm/dwg/PID/hyd_001.dwg', 'approved', '赵工', '2026-06-12', '液压原理正确,同意通过']
);
console.log(' 3条审查 √');
// =====================================================================
// 7. 采购管理
// =====================================================================
console.log('--- 7. 采购管理 ---');
// 7a. 供应商报价
await conn.execute(
"INSERT INTO fad_rm_procurement_quote (project_id,supplier_name,item_name,spec,qty,unit,unit_price,total_price,delivery_days,warranty_months,score_price,score_delivery,score_warranty,score_total,score_rank,status) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '上海电机厂', '主电机', '500kW', 1, '台', 120000, 120000, 45, 24, 8.5, 7.0, 9.0, 8.2, 1, '2']
);
await conn.execute(
"INSERT INTO fad_rm_procurement_quote (project_id,supplier_name,item_name,spec,qty,unit,unit_price,total_price,delivery_days,warranty_months,score_price,score_delivery,score_warranty,score_total,score_rank,status) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '南京减速机厂', '减速机', 'ZLY560', 1, '台', 80000, 80000, 60, 18, 7.5, 6.5, 8.0, 7.3, 2, '1']
);
// 7b. 采购合同
await conn.execute(
"INSERT INTO fad_rm_procurement_contract (project_id,contract_no,contract_name,supplier_name,total_amount,sign_date,file_url,status,clauses,penalty_clause) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, 'CG-2026-001', '主电机采购合同', '上海电机厂', 120000, '2026-06-01', '/upload/rm/contract/PID/motor_contract.pdf', 'signed', '1. 供方提供500kW主电机1台\n2. 交货期45天\n3. 质保期24个月', '逾期交货按合同总价0.5%/天罚款']
);
await conn.execute(
"INSERT INTO fad_rm_procurement_contract (project_id,contract_no,contract_name,supplier_name,total_amount,sign_date,file_url,status,clauses,penalty_clause) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, 'CG-2026-002', '减速机采购合同', '南京减速机厂', 80000, '2026-06-05', '/upload/rm/contract/PID/reducer_contract.pdf', 'draft', '1. 供方提供ZLY560减速机1台\n2. 交货期60天', '']
);
// 7c. 采购进度
await conn.execute(
"INSERT INTO fad_rm_procurement_progress (project_id,item_name,supplier_name,contract_no,amount,order_date,current_stage,expect_date,actual_date,stages) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '主电机', '上海电机厂', 'CG-2026-001', 120000, '2026-06-01', '5', '2026-07-15', null, '{"0":"done","1":"done","2":"done","3":"done","4":"done","5":"progress"}']
);
await conn.execute(
"INSERT INTO fad_rm_procurement_progress (project_id,item_name,supplier_name,contract_no,amount,order_date,current_stage,expect_date,actual_date,stages) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '减速机', '南京减速机厂', 'CG-2026-002', 80000, '2026-06-05', '2', '2026-08-01', null, '{"0":"done","1":"done","2":"progress"}']
);
console.log(' 报价2条 + 合同2份 + 进度2条 √');
// =====================================================================
// 8. 制造进度
// =====================================================================
console.log('--- 8. 制造进度 ---');
// 设备1: 主电机
await conn.execute(
"INSERT INTO fad_rm_mfg_device (project_id,device_name,spec,supplier_name,contract_no,order_date,delivery_date,penalty_rate) VALUES (?,?,?,?,?,?,?,?)",
[PID, '主电机', '500kW', '上海电机厂', 'CG-2026-001', '2026-06-01', '2026-07-15', 500]
);
const [dev1] = await conn.execute('SELECT LAST_INSERT_ID() as id');
const DEV1_ID = dev1[0].id;
// 主电机制造阶段
const stages1 = [
['0', '原材料采购', '2', '2026-06-01', '2026-06-10', '2026-06-01', '2026-06-09', 1],
['1', '机加工', '2', '2026-06-11', '2026-06-20', '2026-06-11', '2026-06-19', 2],
['2', '绕组焊接', '2', '2026-06-21', '2026-06-28', '2026-06-21', '2026-06-27', 3],
['3', '组装', '1', '2026-06-29', '2026-07-05', '2026-06-29', null, 4],
['4', '喷漆', '0', '2026-07-06', '2026-07-08', null, null, 5],
['5', '验收', '0', '2026-07-09', '2026-07-12', null, null, 6],
['6', '包装', '0', '2026-07-13', '2026-07-13', null, null, 7],
['7', '发货', '0', '2026-07-14', '2026-07-15', null, null, 8],
];
for (const st of stages1) {
await conn.execute(
"INSERT INTO fad_rm_mfg_stage (device_id,stage_key,stage_name,status,plan_start_date,plan_end_date,actual_start,actual_end,sort_order) VALUES (?,?,?,?,?,?,?,?,?)",
[DEV1_ID, st[0], st[1], st[2], st[3], st[4], st[5], st[6], st[7]]
);
}
// 设备2: 减速机
await conn.execute(
"INSERT INTO fad_rm_mfg_device (project_id,device_name,spec,supplier_name,contract_no,order_date,delivery_date,penalty_rate) VALUES (?,?,?,?,?,?,?,?)",
[PID, '减速机', 'ZLY560', '南京减速机厂', 'CG-2026-002', '2026-06-05', '2026-08-01', 300]
);
const [dev2] = await conn.execute('SELECT LAST_INSERT_ID() as id');
const DEV2_ID = dev2[0].id;
const stages2 = [
['0', '原材料采购', '2', '2026-06-05', '2026-06-15', '2026-06-05', '2026-06-14', 1],
['1', '机加工', '2', '2026-06-16', '2026-06-30', '2026-06-16', '2026-06-28', 2],
['2', '焊接', '1', '2026-07-01', '2026-07-10', '2026-07-01', null, 3],
['3', '组装', '0', '2026-07-11', '2026-07-18', null, null, 4],
['4', '喷漆', '0', '2026-07-19', '2026-07-20', null, null, 5],
['5', '验收', '0', '2026-07-21', '2026-07-25', null, null, 6],
['6', '包装', '0', '2026-07-26', '2026-07-27', null, null, 7],
['7', '发货', '0', '2026-07-28', '2026-08-01', null, null, 8],
];
for (const st of stages2) {
await conn.execute(
"INSERT INTO fad_rm_mfg_stage (device_id,stage_key,stage_name,status,plan_start_date,plan_end_date,actual_start,actual_end,sort_order) VALUES (?,?,?,?,?,?,?,?,?)",
[DEV2_ID, st[0], st[1], st[2], st[3], st[4], st[5], st[6], st[7]]
);
}
console.log(' 2台设备 + 16个阶段 √');
// =====================================================================
// 9. 图纸优化比较 fad_rm_drawing_compare
// =====================================================================
console.log('--- 9. 图纸优化比较 ---');
await conn.execute(
"INSERT INTO fad_rm_drawing_compare (project_id,drawing_name,old_version,new_version,optimizer,compare_date,status,before_desc,after_desc,old_file_url,new_file_url,diff_notes) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '底座基础图', 'V1.0', 'V1.1', '王工', '2026-06-15', 'approved', '原始设计地脚螺栓孔距为800mm现场反馈偏大',
'优化为760mm与设备实际安装孔距匹配', '/upload/rm/dwg/PID/base_001_v1.0.dwg', '/upload/rm/dwg/PID/base_001_v1.1.dwg',
'孔距调整800→760mm增加4个M24螺纹孔']
);
await conn.execute(
"INSERT INTO fad_rm_drawing_compare (project_id,drawing_name,old_version,new_version,optimizer,compare_date,status,before_desc,after_desc,old_file_url,new_file_url,diff_notes) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '电气原理图', 'V1.0', 'V1.1', '周工', '2026-06-16', 'pending', '原设计主电机回路未设置软启动器',
'增加软启动器及旁路接触器', '/upload/rm/dwg/PID/elec_001_v1.0.dwg', '/upload/rm/dwg/PID/elec_001_v1.1.dwg',
'新增软启动器回路;调整热继电器整定值']
);
console.log(' 2条优化记录 √');
// =====================================================================
// 10. 资料库 fad_rm_doc_lib
// =====================================================================
console.log('--- 10. 资料库 ---');
await conn.execute(
"INSERT INTO fad_rm_doc_lib (project_id,doc_name,category,file_url) VALUES (?,?,?,?)",
[PID, '电机技术规格书', '技术文档', '/upload/rm/doc/PID/motor_spec.pdf']
);
await conn.execute(
"INSERT INTO fad_rm_doc_lib (project_id,doc_name,category,file_url) VALUES (?,?,?,?)",
[PID, '出厂检测报告', '质检报告', '/upload/rm/doc/PID/inspection_report.pdf']
);
await conn.execute(
"INSERT INTO fad_rm_doc_lib (project_id,doc_name,category,file_url) VALUES (?,?,?,?)",
[PID, '安装手册', '技术文档', '/upload/rm/doc/PID/install_manual.pdf']
);
await conn.execute(
"INSERT INTO fad_rm_doc_lib (project_id,doc_name,category,file_url) VALUES (?,?,?,?)",
[PID, '验收报告模板', '质检报告', '/upload/rm/doc/PID/acceptance_template.pdf']
);
console.log(' 4份资料 √');
// =====================================================================
// 11. 现场修改 fad_rm_site_mod + media
// =====================================================================
console.log('--- 11. 现场修改 ---');
await conn.execute(
"INSERT INTO fad_rm_site_mod (project_id,device_name,location,mod_reason,solution,mod_person,mod_date,status,prevent_action,drawing_updated) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '底座', '基础坑', '地脚螺栓孔位偏差20mm', '现场扩孔处理,增加垫片调整', '李工', '2026-06-10', 'done',
'加强来料检验,增加出厂前预装工序', '1']
);
await conn.execute(
"INSERT INTO fad_rm_site_mod (project_id,device_name,location,mod_reason,solution,mod_person,mod_date,status,prevent_action,drawing_updated) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '电机', '电机基础', '电机底座与基础安装孔距不匹配', '重新加工电机底座安装板', '王工', '2026-06-12', 'pending',
'要求供应商提供实物尺寸确认后再出图', '0']
);
// 现场修改多媒体
const [modRows] = await conn.execute(
"SELECT mod_id FROM fad_rm_site_mod WHERE project_id = ? ORDER BY mod_id LIMIT 1", [PID]
);
if (modRows.length > 0) {
const MOD_ID = modRows[0].mod_id;
await conn.execute(
"INSERT INTO fad_rm_site_mod_media (mod_id,media_type,file_name,file_url,file_size) VALUES (?,?,?,?,?)",
[MOD_ID, 'image', '地脚螺栓偏差.jpg', '/upload/rm/site/PID/bolt_deviation.jpg', 204800]
);
await conn.execute(
"INSERT INTO fad_rm_site_mod_media (mod_id,media_type,file_name,file_url,file_size) VALUES (?,?,?,?,?)",
[MOD_ID, 'image', '扩孔处理后.jpg', '/upload/rm/site/PID/after_repair.jpg', 153600]
);
}
console.log(' 2条修改记录 + 2张现场照片 √');
// =====================================================================
// 12. 发货清单
// =====================================================================
console.log('--- 12. 发货清单 ---');
// 12a. 发货前CheckList
await conn.execute(
"INSERT INTO fad_rm_shipping_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '主电机已装箱固定', '1', 1]
);
await conn.execute(
"INSERT INTO fad_rm_shipping_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '减速机已打包防锈', '1', 2]
);
await conn.execute(
"INSERT INTO fad_rm_shipping_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '随机备件清点齐全', '0', 3]
);
await conn.execute(
"INSERT INTO fad_rm_shipping_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '技术资料已随货', '0', 4]
);
// 12b. 发货设备项
await conn.execute(
"INSERT INTO fad_rm_shipping_item (project_id,device_name,spec,qty,packed,photos,note,destination,ship_date,status) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '主电机', '500kW', 2, '1', '["motor_packed_1.jpg","motor_packed_2.jpg"]', '注意防潮', '江苏张家港项目现场', '2026-07-20', '0']
);
await conn.execute(
"INSERT INTO fad_rm_shipping_item (project_id,device_name,spec,qty,packed,photos,note,destination,ship_date,status) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '减速机', 'ZLY560', 1, '0', '[]', '轻拿轻放', '江苏张家港项目现场', null, '0']
);
console.log(' 4条CheckList + 2项设备 √');
// =====================================================================
// 13. 说明书 fad_rm_manual
// =====================================================================
console.log('--- 13. 说明书 ---');
await conn.execute(
"INSERT INTO fad_rm_manual (project_id,manual_name,doc_type,version,upload_date,file_url,description) VALUES (?,?,?,?,?,?,?)",
[PID, '主电机操作手册', '说明书', 'V1.0', '2026-06-01', '/upload/rm/manual/PID/motor_manual.pdf', '500kW主电机操作与维护说明']
);
await conn.execute(
"INSERT INTO fad_rm_manual (project_id,manual_name,doc_type,version,upload_date,file_url,description) VALUES (?,?,?,?,?,?,?)",
[PID, '减速机维护手册', '维护手册', 'V1.0', '2026-06-05', '/upload/rm/manual/PID/reducer_maintenance.pdf', 'ZLY560减速机日常维护指南']
);
await conn.execute(
"INSERT INTO fad_rm_manual (project_id,manual_name,doc_type,version,upload_date,file_url,description) VALUES (?,?,?,?,?,?,?)",
[PID, '随机备件清单', '备件清单', 'V1.0', '2026-06-10', '/upload/rm/manual/PID/spare_parts.pdf', '随机备件明细及订购信息']
);
console.log(' 3份说明书 √');
// =====================================================================
// 14. 安装准备6张子表
// =====================================================================
console.log('--- 14. 安装准备 ---');
// 14a. 安装工具
await conn.execute(
"INSERT INTO fad_rm_install_tool (project_id,name,name_en,spec,qty,unit,unit_price,total_price,priority,arrival_date,purpose,responsible,status,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '千斤顶', 'Jack', '50T', 4, '台', 1200, 4800, '高', '2026-06-01', '设备就位顶升', '刘工', '已到位', '起重吊装']
);
await conn.execute(
"INSERT INTO fad_rm_install_tool (project_id,name,name_en,spec,qty,unit,unit_price,total_price,priority,arrival_date,purpose,responsible,status,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '扭力扳手', 'Torque Wrench', '200N·m', 2, '把', 850, 1700, '中', '2026-06-05', '螺栓紧固', '刘工', '已到位', '机械安装']
);
await conn.execute(
"INSERT INTO fad_rm_install_tool (project_id,name,name_en,spec,qty,unit,unit_price,total_price,priority,arrival_date,purpose,responsible,status,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '水平仪', 'Level Meter', '0.02mm/m', 1, '台', 3500, 3500, '高', '2026-06-10', '设备水平度检测', '陈工', '已到位', '测量仪器']
);
await conn.execute(
"INSERT INTO fad_rm_install_tool (project_id,name,name_en,spec,qty,unit,unit_price,total_price,priority,arrival_date,purpose,responsible,status,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '激光对中仪', 'Laser Aligner', '0.001mm', 1, '台', 28000, 28000, '高', '2026-06-15', '联轴器对中', '陈工', '待确认', '测量仪器']
);
// 14b. 安装人员
await conn.execute(
"INSERT INTO fad_rm_install_personnel (project_id,name,name_en,position,position_en,plan_in,plan_out,days,daily_rate,total_wages,duty,qualification,phone) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '刘建国', 'Liu JG', '安装队长', 'Installation Foreman', '2026-06-15', '2026-08-30', 76, 500, 38000, '现场安装总协调', '10年以上安装经验', '13800001111']
);
await conn.execute(
"INSERT INTO fad_rm_install_personnel (project_id,name,name_en,position,position_en,plan_in,plan_out,days,daily_rate,total_wages,duty,qualification,phone) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '陈伟', 'Chen W', '机械安装工', 'Mechanical Fitter', '2026-06-15', '2026-08-30', 76, 350, 26600, '机械设备安装', '中级钳工', '13800002222']
);
await conn.execute(
"INSERT INTO fad_rm_install_personnel (project_id,name,name_en,position,position_en,plan_in,plan_out,days,daily_rate,total_wages,duty,qualification,phone) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '张明', 'Zhang M', '电气安装工', 'Electrician', '2026-06-20', '2026-08-15', 56, 400, 22400, '电气设备安装接线', '中级电工', '13800003333']
);
// 14c. 安装精度标准
await conn.execute(
"INSERT INTO fad_rm_install_precision (project_id,system_name,item_name,name_en,target_value,unit,importance,tool,method_desc,standard_ref,requirement,is_qualified) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '轧辊系统', '辊缝平行度', 'Roll Gap Parallelism', '≤0.02', 'mm/m', '★★★', '精密水平仪', '使用水平仪在辊面两端测量',
'GB/T 1239.2', '0.02mm/m以内', '1']
);
await conn.execute(
"INSERT INTO fad_rm_install_precision (project_id,system_name,item_name,name_en,target_value,unit,importance,tool,method_desc,standard_ref,requirement,is_qualified) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '主机框架', '机架垂直度', 'Frame Verticality', '≤0.05', 'mm/m', '★★★', '经纬仪', '使用经纬仪测量机架四角立柱',
'GB 50231', '0.05mm/m以内', '1']
);
await conn.execute(
"INSERT INTO fad_rm_install_precision (project_id,system_name,item_name,name_en,target_value,unit,importance,tool,method_desc,standard_ref,requirement,is_qualified) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, 'AGC系统', '液压缸垂直度', 'Cylinder Verticality', '≤0.10', 'mm/m', '★★', '框式水平仪', '使用框式水平仪在缸体外壁测量',
'JB/T 7929', '0.10mm/m以内', '0']
);
// 14d. 安装进度计划
await conn.execute(
"INSERT INTO fad_rm_install_progress (project_id,item_name,plan_start,plan_end,actual_start,actual_end,status,delay_reason,images,videos) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '基础验收', '2026-06-15', '2026-06-20', '2026-06-15', '2026-06-19', 'done', null,
'["foundation_1.jpg","foundation_2.jpg"]', '["foundation_check.mp4"]']
);
await conn.execute(
"INSERT INTO fad_rm_install_progress (project_id,item_name,plan_start,plan_end,actual_start,actual_end,status,delay_reason,images,videos) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '底座安装', '2026-06-21', '2026-06-28', '2026-06-21', null, 'progress', null,
'["base_install_1.jpg"]', '[]']
);
await conn.execute(
"INSERT INTO fad_rm_install_progress (project_id,item_name,plan_start,plan_end,actual_start,actual_end,status,delay_reason,images,videos) VALUES (?,?,?,?,?,?,?,?,?,?)",
[PID, '主电机安装', '2026-06-29', '2026-07-10', null, null, 'pending', null, '[]', '[]']
);
// 14e. 施工日志
await conn.execute(
"INSERT INTO fad_rm_install_daily (project_id,log_date,weather,temperature,work_content,photo_urls) VALUES (?,?,?,?,?,?)",
[PID, '2026-06-15', '晴', '28°C', '基础验收:检查基础尺寸、标高、地脚螺栓位置,完成验收记录',
'["daily_0615_1.jpg","daily_0615_2.jpg"]']
);
await conn.execute(
"INSERT INTO fad_rm_install_daily (project_id,log_date,weather,temperature,work_content,photo_urls) VALUES (?,?,?,?,?,?)",
[PID, '2026-06-16', '多云', '26°C', '基础清理:清除基础表面杂物,打磨地脚螺栓孔',
'["daily_0616_1.jpg"]']
);
await conn.execute(
"INSERT INTO fad_rm_install_daily (project_id,log_date,weather,temperature,work_content,photo_urls) VALUES (?,?,?,?,?,?)",
[PID, '2026-06-21', '晴', '30°C', '底座安装:底座吊装就位,初找水平',
'["daily_0621_1.jpg","daily_0621_2.jpg","daily_0621_3.jpg"]']
);
// 14f. 工序交接
await conn.execute(
"INSERT INTO fad_rm_install_handover (project_id,transfer_from,transfer_to,content,handover_date,sign_photo_url) VALUES (?,?,?,?,?,?)",
[PID, '土建施工队', '安装施工队', '设备基础及地脚螺栓验收交接,基础尺寸符合图纸要求', '2026-06-14', '/upload/rm/handover/PID/handover_001.jpg']
);
await conn.execute(
"INSERT INTO fad_rm_install_handover (project_id,transfer_from,transfer_to,content,handover_date,sign_photo_url) VALUES (?,?,?,?,?,?)",
[PID, '安装施工队', '电气施工队', '电机基础已安装完成,移交电气施工队进行接线', '2026-06-28', null]
);
console.log(' 工具4件 + 人员3人 + 精度3项 + 进度3项 + 日志3条 + 交接2条 √');
// =====================================================================
// 15. 安装问题反馈 fad_rm_install_feedback
// =====================================================================
console.log('--- 15. 安装问题反馈 ---');
await conn.execute(
"INSERT INTO fad_rm_install_feedback (project_id,device_name,title,location,issue_desc,proposer,issue_date,feedback_date,status,resolution,solution,prevent_action) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '底座', '地脚螺栓孔偏位', '基础坑', 'A列2号地脚螺栓孔位偏差5mm无法安装', '刘建国', '2026-06-22', null,
'pending', null, '现场扩孔至设计尺寸', '加强预埋件定位精度控制']
);
await conn.execute(
"INSERT INTO fad_rm_install_feedback (project_id,device_name,title,location,issue_desc,proposer,issue_date,feedback_date,status,resolution,solution,prevent_action) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '电缆', '进线电缆预留不足', '电气室', '主电机进线电缆预留长度不够,需增加中间接线盒', '张明', '2026-06-23', '2026-06-25',
'resolved', '已增加中间接线盒,电缆已接续完成', '增加一个中间接线盒过渡', '后续设计阶段预留足够电缆长度余量']
);
await conn.execute(
"INSERT INTO fad_rm_install_feedback (project_id,device_name,title,location,issue_desc,proposer,issue_date,feedback_date,status,resolution,solution,prevent_action) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
[PID, '液压站', '液压管接头渗油', '液压站', '液压站出口管接头处轻微渗油,需更换密封圈', '刘建国', '2026-06-24', '2026-06-26',
'resolved', '已更换密封圈,打压测试无渗漏', '更换O型密封圈并重新紧固', '来料检验增加密封圈材质检测']
);
console.log(' 3条反馈 √');
// =====================================================================
// 16. 安装验收
// =====================================================================
console.log('--- 16. 安装验收 ---');
// 16a. 验收条目
await conn.execute(
"INSERT INTO fad_rm_acceptance_item (project_id,item_name,standard,result,inspector,inspect_date) VALUES (?,?,?,?,?,?)",
[PID, '设备外观检查', '无锈蚀、无变形、无损伤', '1', '赵工', '2026-06-25']
);
await conn.execute(
"INSERT INTO fad_rm_acceptance_item (project_id,item_name,standard,result,inspector,inspect_date) VALUES (?,?,?,?,?,?)",
[PID, '安装精度检查', '水平度≤0.05mm/m垂直度≤0.05mm/m', '1', '赵工', '2026-06-25']
);
await conn.execute(
"INSERT INTO fad_rm_acceptance_item (project_id,item_name,standard,result,inspector,inspect_date) VALUES (?,?,?,?,?,?)",
[PID, '电气接线检查', '接线正确绝缘电阻≥1MΩ', '0', null, null]
);
// 16b. 验收CheckList
await conn.execute(
"INSERT INTO fad_rm_acceptance_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '设备外观检查', '1', 1]
);
await conn.execute(
"INSERT INTO fad_rm_acceptance_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '安装精度检查', '1', 2]
);
await conn.execute(
"INSERT INTO fad_rm_acceptance_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '电气接线检查', '1', 3]
);
await conn.execute(
"INSERT INTO fad_rm_acceptance_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '空载试运行', '0', 4]
);
console.log(' 验收条目3条 + CheckList4项 √');
// =====================================================================
// 17. 热负荷试车
// =====================================================================
console.log('--- 17. 热负荷试车 ---');
// 17a. 试车CheckList
await conn.execute(
"INSERT INTO fad_rm_commissioning_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '冷却水系统已投入', '0', 1]
);
await conn.execute(
"INSERT INTO fad_rm_commissioning_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '润滑系统已运行正常', '0', 2]
);
await conn.execute(
"INSERT INTO fad_rm_commissioning_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '电气保护整定值已确认', '0', 3]
);
await conn.execute(
"INSERT INTO fad_rm_commissioning_checklist (project_id,item_text,is_checked,sort_order) VALUES (?,?,?,?)",
[PID, '紧急停止按钮功能测试通过', '0', 4]
);
// 17b. 试车条款
await conn.execute(
"INSERT INTO fad_rm_commissioning_clause (project_id,clause_content,sort_order) VALUES (?,?,?)",
[PID, '轧机在额定转速下连续运行2小时轴承温升不超过40°C', 1]
);
await conn.execute(
"INSERT INTO fad_rm_commissioning_clause (project_id,clause_content,sort_order) VALUES (?,?,?)",
[PID, '轧制力控制系统响应时间不超过50ms', 2]
);
await conn.execute(
"INSERT INTO fad_rm_commissioning_clause (project_id,clause_content,sort_order) VALUES (?,?,?)",
[PID, '厚度控制精度达到±0.05mm', 3]
);
// 17c. 试车记录
await conn.execute(
"INSERT INTO fad_rm_commissioning_record (project_id,record_date,record_type,param_name,param_value,result,issue_desc) VALUES (?,?,?,?,?,?,?)",
[PID, '2026-06-26', '0', '电机空载电流', '120A', '1', null]
);
await conn.execute(
"INSERT INTO fad_rm_commissioning_record (project_id,record_date,record_type,param_name,param_value,result,issue_desc) VALUES (?,?,?,?,?,?,?)",
[PID, '2026-06-26', '0', '轴承温升', '35°C', '1', null]
);
console.log(' CheckList4项 + 条款3条 + 记录2条 √');
await conn.end();
console.log('\n=======================================');
console.log('测试项目A — 全部17阶段数据插入完成');
console.log('=======================================');
}
run().catch(e => { console.error('插入失败:', e); process.exit(1); });

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmAcceptanceChecklistBo;
import com.ruoyi.rm.domain.vo.RmAcceptanceChecklistVo;
import com.ruoyi.rm.service.IRmAcceptanceChecklistService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/acceptanceChecklist")
public class RmAcceptanceChecklistController extends BaseController {
private final IRmAcceptanceChecklistService service;
@GetMapping("/list")
public TableDataInfo<RmAcceptanceChecklistVo> list(RmAcceptanceChecklistBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{checkId}")
public R<RmAcceptanceChecklistVo> getInfo(@PathVariable @NotNull Long checkId) {
return R.ok(service.queryById(checkId));
}
@Log(title = "验收检查清单", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmAcceptanceChecklistBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "验收检查清单", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmAcceptanceChecklistBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "验收检查清单", businessType = BusinessType.DELETE)
@DeleteMapping("/{checkIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] checkIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(checkIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmAcceptanceChecklistVo>> all(RmAcceptanceChecklistBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmAcceptanceItemBo;
import com.ruoyi.rm.domain.vo.RmAcceptanceItemVo;
import com.ruoyi.rm.service.IRmAcceptanceItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/acceptanceItem")
public class RmAcceptanceItemController extends BaseController {
private final IRmAcceptanceItemService service;
@GetMapping("/list")
public TableDataInfo<RmAcceptanceItemVo> list(RmAcceptanceItemBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{acceptItemId}")
public R<RmAcceptanceItemVo> getInfo(@PathVariable @NotNull Long acceptItemId) {
return R.ok(service.queryById(acceptItemId));
}
@Log(title = "安装验收项", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmAcceptanceItemBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "安装验收项", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmAcceptanceItemBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "安装验收项", businessType = BusinessType.DELETE)
@DeleteMapping("/{acceptItemIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] acceptItemIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(acceptItemIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmAcceptanceItemVo>> all(RmAcceptanceItemBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,61 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmBudgetBo;
import com.ruoyi.rm.domain.vo.RmBudgetVo;
import com.ruoyi.rm.service.IRmBudgetService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/budget")
public class RmBudgetController extends BaseController {
private final IRmBudgetService service;
@GetMapping("/list")
public TableDataInfo<RmBudgetVo> list(RmBudgetBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{budgetId}")
public R<RmBudgetVo> getInfo(@PathVariable @NotNull Long budgetId) {
return R.ok(service.queryById(budgetId));
}
@Log(title = "项目预算", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmBudgetBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "项目预算", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmBudgetBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "项目预算", businessType = BusinessType.DELETE)
@DeleteMapping("/{budgetIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] budgetIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(budgetIds), true));
}
@GetMapping("/all")
public R<List<RmBudgetVo>> all(RmBudgetBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmColorCardBo;
import com.ruoyi.rm.domain.vo.RmColorCardVo;
import com.ruoyi.rm.service.IRmColorCardService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/colorCard")
public class RmColorCardController extends BaseController {
private final IRmColorCardService service;
@GetMapping("/list")
public TableDataInfo<RmColorCardVo> list(RmColorCardBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{colorCardId}")
public R<RmColorCardVo> getInfo(@PathVariable @NotNull Long colorCardId) {
return R.ok(service.queryById(colorCardId));
}
@Log(title = "色卡管理", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmColorCardBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "色卡管理", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmColorCardBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "色卡管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{colorCardIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] colorCardIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(colorCardIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmColorCardVo>> all(RmColorCardBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmCommissioningChecklistBo;
import com.ruoyi.rm.domain.vo.RmCommissioningChecklistVo;
import com.ruoyi.rm.service.IRmCommissioningChecklistService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/commissioningChecklist")
public class RmCommissioningChecklistController extends BaseController {
private final IRmCommissioningChecklistService service;
@GetMapping("/list")
public TableDataInfo<RmCommissioningChecklistVo> list(RmCommissioningChecklistBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{checkId}")
public R<RmCommissioningChecklistVo> getInfo(@PathVariable @NotNull Long checkId) {
return R.ok(service.queryById(checkId));
}
@Log(title = "热负荷试车CheckList", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmCommissioningChecklistBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "热负荷试车CheckList", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmCommissioningChecklistBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "热负荷试车CheckList", businessType = BusinessType.DELETE)
@DeleteMapping("/{checkIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] checkIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(checkIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmCommissioningChecklistVo>> all(RmCommissioningChecklistBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmCommissioningClauseBo;
import com.ruoyi.rm.domain.vo.RmCommissioningClauseVo;
import com.ruoyi.rm.service.IRmCommissioningClauseService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/commissioningClause")
public class RmCommissioningClauseController extends BaseController {
private final IRmCommissioningClauseService service;
@GetMapping("/list")
public TableDataInfo<RmCommissioningClauseVo> list(RmCommissioningClauseBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{clauseId}")
public R<RmCommissioningClauseVo> getInfo(@PathVariable @NotNull Long clauseId) {
return R.ok(service.queryById(clauseId));
}
@Log(title = "热负荷试车条款", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmCommissioningClauseBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "热负荷试车条款", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmCommissioningClauseBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "热负荷试车条款", businessType = BusinessType.DELETE)
@DeleteMapping("/{clauseIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] clauseIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(clauseIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmCommissioningClauseVo>> all(RmCommissioningClauseBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,69 @@
package com.ruoyi.rm.controller;
import java.util.List;
import java.util.Arrays;
import lombok.RequiredArgsConstructor;
import javax.validation.constraints.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.rm.domain.vo.RmCommissioningVo;
import com.ruoyi.rm.domain.bo.RmCommissioningBo;
import com.ruoyi.rm.service.IRmCommissioningService;
import com.ruoyi.common.core.page.TableDataInfo;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/commissioning")
public class RmCommissioningController extends BaseController {
private final IRmCommissioningService iRmCommissioningService;
@GetMapping("/list")
public TableDataInfo<RmCommissioningVo> list(RmCommissioningBo bo, PageQuery pageQuery) {
return iRmCommissioningService.queryPageList(bo, pageQuery);
}
@GetMapping("/all")
public R<List<RmCommissioningVo>> all(RmCommissioningBo bo) {
return R.ok(iRmCommissioningService.queryList(bo));
}
@GetMapping("/byProject/{projectId}")
public R<RmCommissioningVo> getByProjectId(@PathVariable Long projectId) {
return R.ok(iRmCommissioningService.queryByProjectId(projectId));
}
@GetMapping("/{commissioningId}")
public R<RmCommissioningVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long commissioningId) {
return R.ok(iRmCommissioningService.queryById(commissioningId));
}
@PostMapping()
@RepeatSubmit()
public R<Void> add(@Validated(AddGroup.class) @RequestBody RmCommissioningBo bo) {
return toAjax(iRmCommissioningService.insertByBo(bo));
}
@PutMapping()
@RepeatSubmit()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody RmCommissioningBo bo) {
return toAjax(iRmCommissioningService.updateByBo(bo));
}
@DeleteMapping("/{commissioningIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] commissioningIds) {
return toAjax(iRmCommissioningService.deleteWithValidByIds(Arrays.asList(commissioningIds), true));
}
}

View File

@@ -0,0 +1,25 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.rm.service.IRmDashboardService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotNull;
import java.util.Map;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/dashboard")
public class RmDashboardController extends BaseController {
private final IRmDashboardService dashboardService;
@GetMapping("/stageStatus/{projectId}")
public R<Map<String, Object>> stageStatus(@PathVariable @NotNull Long projectId) {
return R.ok(dashboardService.getStageStatus(projectId));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmDocLibBo;
import com.ruoyi.rm.domain.vo.RmDocLibVo;
import com.ruoyi.rm.service.IRmDocLibService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/docLib")
public class RmDocLibController extends BaseController {
private final IRmDocLibService service;
@GetMapping("/list")
public TableDataInfo<RmDocLibVo> list(RmDocLibBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{docId}")
public R<RmDocLibVo> getInfo(@PathVariable @NotNull Long docId) {
return R.ok(service.queryById(docId));
}
@Log(title = "图纸资料库", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmDocLibBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "图纸资料库", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmDocLibBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "图纸资料库", businessType = BusinessType.DELETE)
@DeleteMapping("/{docIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] docIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(docIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmDocLibVo>> all(RmDocLibBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmDrawingCompareBo;
import com.ruoyi.rm.domain.vo.RmDrawingCompareVo;
import com.ruoyi.rm.service.IRmDrawingCompareService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/drawingCompare")
public class RmDrawingCompareController extends BaseController {
private final IRmDrawingCompareService service;
@GetMapping("/list")
public TableDataInfo<RmDrawingCompareVo> list(RmDrawingCompareBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{compareId}")
public R<RmDrawingCompareVo> getInfo(@PathVariable @NotNull Long compareId) {
return R.ok(service.queryById(compareId));
}
@Log(title = "图纸优化比较", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmDrawingCompareBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "图纸优化比较", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmDrawingCompareBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "图纸优化比较", businessType = BusinessType.DELETE)
@DeleteMapping("/{compareIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] compareIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(compareIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmDrawingCompareVo>> all(RmDrawingCompareBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmDrawingDesignBo;
import com.ruoyi.rm.domain.vo.RmDrawingDesignVo;
import com.ruoyi.rm.service.IRmDrawingDesignService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/drawingDesign")
public class RmDrawingDesignController extends BaseController {
private final IRmDrawingDesignService service;
@GetMapping("/list")
public TableDataInfo<RmDrawingDesignVo> list(RmDrawingDesignBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{drawingId}")
public R<RmDrawingDesignVo> getInfo(@PathVariable @NotNull Long drawingId) {
return R.ok(service.queryById(drawingId));
}
@Log(title = "图纸详细设计", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmDrawingDesignBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "图纸详细设计", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmDrawingDesignBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "图纸详细设计", businessType = BusinessType.DELETE)
@DeleteMapping("/{drawingIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] drawingIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(drawingIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmDrawingDesignVo>> all(RmDrawingDesignBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmDrawingReviewBo;
import com.ruoyi.rm.domain.vo.RmDrawingReviewVo;
import com.ruoyi.rm.service.IRmDrawingReviewService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/drawingReview")
public class RmDrawingReviewController extends BaseController {
private final IRmDrawingReviewService service;
@GetMapping("/list")
public TableDataInfo<RmDrawingReviewVo> list(RmDrawingReviewBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{reviewId}")
public R<RmDrawingReviewVo> getInfo(@PathVariable @NotNull Long reviewId) {
return R.ok(service.queryById(reviewId));
}
@Log(title = "图纸审查", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmDrawingReviewBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "图纸审查", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmDrawingReviewBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "图纸审查", businessType = BusinessType.DELETE)
@DeleteMapping("/{reviewIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] reviewIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(reviewIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmDrawingReviewVo>> all(RmDrawingReviewBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,35 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.rm.domain.bo.RmFileReviewBo;
import com.ruoyi.rm.domain.vo.RmFileReviewVo;
import com.ruoyi.rm.service.IRmFileReviewService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/fileReview")
public class RmFileReviewController extends BaseController {
private final IRmFileReviewService fileReviewService;
@GetMapping("/list")
public R<List<RmFileReviewVo>> list(String fileModule, Long fileId) {
return R.ok(fileReviewService.queryByFile(fileModule, fileId));
}
@PostMapping
public R<RmFileReviewVo> add(@RequestBody RmFileReviewBo bo) {
return R.ok(fileReviewService.addReview(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmInstallFeedbackBo;
import com.ruoyi.rm.domain.vo.RmInstallFeedbackVo;
import com.ruoyi.rm.service.IRmInstallFeedbackService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/installFeedback")
public class RmInstallFeedbackController extends BaseController {
private final IRmInstallFeedbackService service;
@GetMapping("/list")
public TableDataInfo<RmInstallFeedbackVo> list(RmInstallFeedbackBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{feedbackId}")
public R<RmInstallFeedbackVo> getInfo(@PathVariable @NotNull Long feedbackId) {
return R.ok(service.queryById(feedbackId));
}
@Log(title = "安装问题反馈", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmInstallFeedbackBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "安装问题反馈", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmInstallFeedbackBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "安装问题反馈", businessType = BusinessType.DELETE)
@DeleteMapping("/{feedbackIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] feedbackIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(feedbackIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmInstallFeedbackVo>> all(RmInstallFeedbackBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmInstallPersonnelBo;
import com.ruoyi.rm.domain.vo.RmInstallPersonnelVo;
import com.ruoyi.rm.service.IRmInstallPersonnelService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/installPersonnel")
public class RmInstallPersonnelController extends BaseController {
private final IRmInstallPersonnelService service;
@GetMapping("/list")
public TableDataInfo<RmInstallPersonnelVo> list(RmInstallPersonnelBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{personnelId}")
public R<RmInstallPersonnelVo> getInfo(@PathVariable @NotNull Long personnelId) {
return R.ok(service.queryById(personnelId));
}
@Log(title = "安装人员", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmInstallPersonnelBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "安装人员", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmInstallPersonnelBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "安装人员", businessType = BusinessType.DELETE)
@DeleteMapping("/{personnelIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] personnelIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(personnelIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmInstallPersonnelVo>> all(RmInstallPersonnelBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmInstallPrecisionBo;
import com.ruoyi.rm.domain.vo.RmInstallPrecisionVo;
import com.ruoyi.rm.service.IRmInstallPrecisionService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/installPrecision")
public class RmInstallPrecisionController extends BaseController {
private final IRmInstallPrecisionService service;
@GetMapping("/list")
public TableDataInfo<RmInstallPrecisionVo> list(RmInstallPrecisionBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{precisionId}")
public R<RmInstallPrecisionVo> getInfo(@PathVariable @NotNull Long precisionId) {
return R.ok(service.queryById(precisionId));
}
@Log(title = "安装精度", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmInstallPrecisionBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "安装精度", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmInstallPrecisionBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "安装精度", businessType = BusinessType.DELETE)
@DeleteMapping("/{precisionIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] precisionIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(precisionIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmInstallPrecisionVo>> all(RmInstallPrecisionBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmInstallProgressBo;
import com.ruoyi.rm.domain.vo.RmInstallProgressVo;
import com.ruoyi.rm.service.IRmInstallProgressService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/installProgress")
public class RmInstallProgressController extends BaseController {
private final IRmInstallProgressService service;
@GetMapping("/list")
public TableDataInfo<RmInstallProgressVo> list(RmInstallProgressBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{progressId}")
public R<RmInstallProgressVo> getInfo(@PathVariable @NotNull Long progressId) {
return R.ok(service.queryById(progressId));
}
@Log(title = "安装进度", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmInstallProgressBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "安装进度", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmInstallProgressBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "安装进度", businessType = BusinessType.DELETE)
@DeleteMapping("/{progressIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] progressIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(progressIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmInstallProgressVo>> all(RmInstallProgressBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmInstallToolBo;
import com.ruoyi.rm.domain.vo.RmInstallToolVo;
import com.ruoyi.rm.service.IRmInstallToolService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/installTool")
public class RmInstallToolController extends BaseController {
private final IRmInstallToolService service;
@GetMapping("/list")
public TableDataInfo<RmInstallToolVo> list(RmInstallToolBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{toolId}")
public R<RmInstallToolVo> getInfo(@PathVariable @NotNull Long toolId) {
return R.ok(service.queryById(toolId));
}
@Log(title = "安装工具", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmInstallToolBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "安装工具", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmInstallToolBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "安装工具", businessType = BusinessType.DELETE)
@DeleteMapping("/{toolIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] toolIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(toolIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmInstallToolVo>> all(RmInstallToolBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmLayoutFileBo;
import com.ruoyi.rm.domain.vo.RmLayoutFileVo;
import com.ruoyi.rm.service.IRmLayoutFileService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/layout")
public class RmLayoutFileController extends BaseController {
private final IRmLayoutFileService service;
@GetMapping("/list")
public TableDataInfo<RmLayoutFileVo> list(RmLayoutFileBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{layoutFileId}")
public R<RmLayoutFileVo> getInfo(@PathVariable @NotNull Long layoutFileId) {
return R.ok(service.queryById(layoutFileId));
}
@Log(title = "布局图确定", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmLayoutFileBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "布局图确定", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmLayoutFileBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "布局图确定", businessType = BusinessType.DELETE)
@DeleteMapping("/{layoutFileIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] layoutFileIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(layoutFileIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmLayoutFileVo>> all(RmLayoutFileBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmManualBo;
import com.ruoyi.rm.domain.vo.RmManualVo;
import com.ruoyi.rm.service.IRmManualService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/manual")
public class RmManualController extends BaseController {
private final IRmManualService service;
@GetMapping("/list")
public TableDataInfo<RmManualVo> list(RmManualBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{manualId}")
public R<RmManualVo> getInfo(@PathVariable @NotNull Long manualId) {
return R.ok(service.queryById(manualId));
}
@Log(title = "设备说明书", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmManualBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "设备说明书", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmManualBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "设备说明书", businessType = BusinessType.DELETE)
@DeleteMapping("/{manualIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] manualIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(manualIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmManualVo>> all(RmManualBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmMfgDeviceBo;
import com.ruoyi.rm.domain.vo.RmMfgDeviceVo;
import com.ruoyi.rm.service.IRmMfgDeviceService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/mfgDevice")
public class RmMfgDeviceController extends BaseController {
private final IRmMfgDeviceService service;
@GetMapping("/list")
public TableDataInfo<RmMfgDeviceVo> list(RmMfgDeviceBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{deviceId}")
public R<RmMfgDeviceVo> getInfo(@PathVariable @NotNull Long deviceId) {
return R.ok(service.queryById(deviceId));
}
@Log(title = "设备制造", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmMfgDeviceBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "设备制造", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmMfgDeviceBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "设备制造", businessType = BusinessType.DELETE)
@DeleteMapping("/{deviceIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] deviceIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(deviceIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmMfgDeviceVo>> all(RmMfgDeviceBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmMfgStageBo;
import com.ruoyi.rm.domain.vo.RmMfgStageVo;
import com.ruoyi.rm.service.IRmMfgStageService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/mfgStage")
public class RmMfgStageController extends BaseController {
private final IRmMfgStageService service;
@GetMapping("/list")
public TableDataInfo<RmMfgStageVo> list(RmMfgStageBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{stageId}")
public R<RmMfgStageVo> getInfo(@PathVariable @NotNull Long stageId) {
return R.ok(service.queryById(stageId));
}
@Log(title = "制造阶段", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmMfgStageBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "制造阶段", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmMfgStageBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "制造阶段", businessType = BusinessType.DELETE)
@DeleteMapping("/{stageIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] stageIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(stageIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmMfgStageVo>> all(RmMfgStageBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmProcurementContractBo;
import com.ruoyi.rm.domain.vo.RmProcurementContractVo;
import com.ruoyi.rm.service.IRmProcurementContractService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/contract")
public class RmProcurementContractController extends BaseController {
private final IRmProcurementContractService service;
@GetMapping("/list")
public TableDataInfo<RmProcurementContractVo> list(RmProcurementContractBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{contractId}")
public R<RmProcurementContractVo> getInfo(@PathVariable @NotNull Long contractId) {
return R.ok(service.queryById(contractId));
}
@Log(title = "合同管理", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmProcurementContractBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "合同管理", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmProcurementContractBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "合同管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{contractIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] contractIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(contractIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmProcurementContractVo>> all(RmProcurementContractBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmProcurementProgressBo;
import com.ruoyi.rm.domain.vo.RmProcurementProgressVo;
import com.ruoyi.rm.service.IRmProcurementProgressService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/procProgress")
public class RmProcurementProgressController extends BaseController {
private final IRmProcurementProgressService service;
@GetMapping("/list")
public TableDataInfo<RmProcurementProgressVo> list(RmProcurementProgressBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{progressId}")
public R<RmProcurementProgressVo> getInfo(@PathVariable @NotNull Long progressId) {
return R.ok(service.queryById(progressId));
}
@Log(title = "采购进度", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmProcurementProgressBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "采购进度", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmProcurementProgressBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "采购进度", businessType = BusinessType.DELETE)
@DeleteMapping("/{progressIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] progressIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(progressIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmProcurementProgressVo>> all(RmProcurementProgressBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmProcurementQuoteBo;
import com.ruoyi.rm.domain.vo.RmProcurementQuoteVo;
import com.ruoyi.rm.service.IRmProcurementQuoteService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/quote")
public class RmProcurementQuoteController extends BaseController {
private final IRmProcurementQuoteService service;
@GetMapping("/list")
public TableDataInfo<RmProcurementQuoteVo> list(RmProcurementQuoteBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{quoteId}")
public R<RmProcurementQuoteVo> getInfo(@PathVariable @NotNull Long quoteId) {
return R.ok(service.queryById(quoteId));
}
@Log(title = "报价管理", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmProcurementQuoteBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "报价管理", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmProcurementQuoteBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "报价管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{quoteIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] quoteIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(quoteIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmProcurementQuoteVo>> all(RmProcurementQuoteBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,61 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmProjectBo;
import com.ruoyi.rm.domain.vo.RmProjectVo;
import com.ruoyi.rm.service.IRmProjectService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/project")
public class RmProjectController extends BaseController {
private final IRmProjectService service;
@GetMapping("/list")
public TableDataInfo<RmProjectVo> list(RmProjectBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{projectId}")
public R<RmProjectVo> getInfo(@PathVariable @NotNull Long projectId) {
return R.ok(service.queryById(projectId));
}
@Log(title = "轧机项目管理", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmProjectBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "轧机项目管理", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmProjectBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "轧机项目管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{projectIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] projectIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(projectIds), true));
}
@GetMapping("/all")
public R<List<RmProjectVo>> all(RmProjectBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,61 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmProjectMemberBo;
import com.ruoyi.rm.domain.vo.RmProjectMemberVo;
import com.ruoyi.rm.service.IRmProjectMemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/projectMember")
public class RmProjectMemberController extends BaseController {
private final IRmProjectMemberService service;
@GetMapping("/list")
public TableDataInfo<RmProjectMemberVo> list(RmProjectMemberBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{memberId}")
public R<RmProjectMemberVo> getInfo(@PathVariable @NotNull Long memberId) {
return R.ok(service.queryById(memberId));
}
@Log(title = "项目成员", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmProjectMemberBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "项目成员", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmProjectMemberBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "项目成员", businessType = BusinessType.DELETE)
@DeleteMapping("/{memberIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] memberIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(memberIds), true));
}
@GetMapping("/all")
public R<List<RmProjectMemberVo>> all(RmProjectMemberBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmShippingChecklistBo;
import com.ruoyi.rm.domain.vo.RmShippingChecklistVo;
import com.ruoyi.rm.service.IRmShippingChecklistService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/shippingChecklist")
public class RmShippingChecklistController extends BaseController {
private final IRmShippingChecklistService service;
@GetMapping("/list")
public TableDataInfo<RmShippingChecklistVo> list(RmShippingChecklistBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{checklistId}")
public R<RmShippingChecklistVo> getInfo(@PathVariable @NotNull Long checklistId) {
return R.ok(service.queryById(checklistId));
}
@Log(title = "发货前检查清单", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmShippingChecklistBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "发货前检查清单", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmShippingChecklistBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "发货前检查清单", businessType = BusinessType.DELETE)
@DeleteMapping("/{checklistIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] checklistIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(checklistIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmShippingChecklistVo>> all(RmShippingChecklistBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmShippingItemBo;
import com.ruoyi.rm.domain.vo.RmShippingItemVo;
import com.ruoyi.rm.service.IRmShippingItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/shippingItem")
public class RmShippingItemController extends BaseController {
private final IRmShippingItemService service;
@GetMapping("/list")
public TableDataInfo<RmShippingItemVo> list(RmShippingItemBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{itemId}")
public R<RmShippingItemVo> getInfo(@PathVariable @NotNull Long itemId) {
return R.ok(service.queryById(itemId));
}
@Log(title = "发货设备项", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmShippingItemBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "发货设备项", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmShippingItemBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "发货设备项", businessType = BusinessType.DELETE)
@DeleteMapping("/{itemIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] itemIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(itemIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmShippingItemVo>> all(RmShippingItemBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmSiteModBo;
import com.ruoyi.rm.domain.vo.RmSiteModVo;
import com.ruoyi.rm.service.IRmSiteModService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/siteMod")
public class RmSiteModController extends BaseController {
private final IRmSiteModService service;
@GetMapping("/list")
public TableDataInfo<RmSiteModVo> list(RmSiteModBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{modId}")
public R<RmSiteModVo> getInfo(@PathVariable @NotNull Long modId) {
return R.ok(service.queryById(modId));
}
@Log(title = "现场修改", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmSiteModBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "现场修改", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmSiteModBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "现场修改", businessType = BusinessType.DELETE)
@DeleteMapping("/{modIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] modIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(modIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmSiteModVo>> all(RmSiteModBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,54 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmSiteModMediaBo;
import com.ruoyi.rm.domain.vo.RmSiteModMediaVo;
import com.ruoyi.rm.service.IRmSiteModMediaService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/siteModMedia")
public class RmSiteModMediaController extends BaseController {
private final IRmSiteModMediaService service;
@GetMapping("/list")
public TableDataInfo<RmSiteModMediaVo> list(RmSiteModMediaBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{mediaId}")
public R<RmSiteModMediaVo> getInfo(@PathVariable @NotNull Long mediaId) {
return R.ok(service.queryById(mediaId));
}
@Log(title = "现场修改多媒体", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmSiteModMediaBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "现场修改多媒体", businessType = BusinessType.DELETE)
@DeleteMapping("/{mediaIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] mediaIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(mediaIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmSiteModMediaVo>> all(RmSiteModMediaBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,38 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.rm.domain.bo.RmStageConfirmBo;
import com.ruoyi.rm.domain.vo.RmStageConfirmVo;
import com.ruoyi.rm.service.IRmStageConfirmService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotNull;
import java.util.List;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/stageConfirm")
public class RmStageConfirmController extends BaseController {
private final IRmStageConfirmService stageConfirmService;
@GetMapping("/{projectId}")
public R<List<RmStageConfirmVo>> list(@PathVariable @NotNull Long projectId) {
return R.ok(stageConfirmService.queryByProjectId(projectId));
}
@PostMapping
public R<Void> confirm(@RequestBody @Validated RmStageConfirmBo bo) {
return toAjax(stageConfirmService.confirmStage(bo));
}
@PostMapping("/override")
public R<Void> override(@RequestBody @Validated RmStageConfirmBo bo) {
bo.setConfirmType("override");
return toAjax(stageConfirmService.confirmStage(bo));
}
}

View File

@@ -0,0 +1,61 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmStageImageBo;
import com.ruoyi.rm.domain.vo.RmStageImageVo;
import com.ruoyi.rm.service.IRmStageImageService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.List;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/stageImage")
public class RmStageImageController extends BaseController {
private final IRmStageImageService service;
@GetMapping("/list")
public TableDataInfo<RmStageImageVo> list(RmStageImageBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{imageId}")
public R<RmStageImageVo> getInfo(@PathVariable @NotNull Long imageId) {
return R.ok(service.queryById(imageId));
}
@Log(title = "阶段图片", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmStageImageBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "阶段图片", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmStageImageBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "阶段图片", businessType = BusinessType.DELETE)
@DeleteMapping("/{imageIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] imageIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(imageIds), true));
}
@GetMapping("/all")
public R<List<RmStageImageVo>> all(RmStageImageBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,64 @@
package com.ruoyi.rm.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.rm.domain.bo.RmStageUserPermBo;
import com.ruoyi.rm.domain.vo.RmStageUserPermVo;
import com.ruoyi.rm.service.IRmStageUserPermService;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.stream.Collectors;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/stageUserPerm")
public class RmStageUserPermController extends BaseController {
private final IRmStageUserPermService stageUserPermService;
private final SysUserMapper sysUserMapper;
private final SysUserRoleMapper sysUserRoleMapper;
@GetMapping("/list")
public R<List<RmStageUserPermVo>> list(RmStageUserPermBo bo) {
return R.ok(stageUserPermService.queryList(bo));
}
@PostMapping("/batchSave")
public R<Void> batchSave(@RequestBody List<RmStageUserPermBo> list) {
stageUserPermService.batchSave(list);
return R.ok("保存成功");
}
@GetMapping("/users")
public R<List<Map<String, Object>>> listUsers() {
List<SysUser> users = sysUserMapper.selectList(
Wrappers.<SysUser>lambdaQuery()
.eq(SysUser::getStatus, "0")
.orderByAsc(SysUser::getUserId));
// Build userId -> roleIds map
List<SysUserRole> allUserRoles = sysUserRoleMapper.selectList(Wrappers.emptyWrapper());
Map<Long, List<Long>> userRoleMap = allUserRoles.stream()
.collect(Collectors.groupingBy(SysUserRole::getUserId,
Collectors.mapping(SysUserRole::getRoleId, Collectors.toList())));
List<Map<String, Object>> result = new ArrayList<>();
for (SysUser user : users) {
Map<String, Object> item = new LinkedHashMap<>();
item.put("userId", user.getUserId());
item.put("nickName", user.getNickName());
item.put("roleIds", userRoleMap.getOrDefault(user.getUserId(), Collections.emptyList()));
result.add(item);
}
return R.ok(result);
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmTechPlanItemBo;
import com.ruoyi.rm.domain.vo.RmTechPlanItemVo;
import com.ruoyi.rm.service.IRmTechPlanItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/techPlan")
public class RmTechPlanItemController extends BaseController {
private final IRmTechPlanItemService service;
@GetMapping("/list")
public TableDataInfo<RmTechPlanItemVo> list(RmTechPlanItemBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{planItemId}")
public R<RmTechPlanItemVo> getInfo(@PathVariable @NotNull Long planItemId) {
return R.ok(service.queryById(planItemId));
}
@Log(title = "技术方案确定", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmTechPlanItemBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "技术方案确定", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmTechPlanItemBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "技术方案确定", businessType = BusinessType.DELETE)
@DeleteMapping("/{planItemIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] planItemIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(planItemIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmTechPlanItemVo>> all(RmTechPlanItemBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.rm.controller;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.rm.domain.bo.RmTechReviewItemBo;
import com.ruoyi.rm.domain.vo.RmTechReviewItemVo;
import com.ruoyi.rm.service.IRmTechReviewItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Arrays;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/rm/techReview")
public class RmTechReviewItemController extends BaseController {
private final IRmTechReviewItemService service;
@GetMapping("/list")
public TableDataInfo<RmTechReviewItemVo> list(RmTechReviewItemBo bo, PageQuery pageQuery) {
return service.queryPageList(bo, pageQuery);
}
@GetMapping("/{reviewItemId}")
public R<RmTechReviewItemVo> getInfo(@PathVariable @NotNull Long reviewItemId) {
return R.ok(service.queryById(reviewItemId));
}
@Log(title = "技术审查", businessType = BusinessType.INSERT)
@PostMapping
public R<Void> add(@Validated @RequestBody RmTechReviewItemBo bo) {
return toAjax(service.insertByBo(bo));
}
@Log(title = "技术审查", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> edit(@Validated @RequestBody RmTechReviewItemBo bo) {
return toAjax(service.updateByBo(bo));
}
@Log(title = "技术审查", businessType = BusinessType.DELETE)
@DeleteMapping("/{reviewItemIds}")
public R<Void> remove(@PathVariable @NotEmpty Long[] reviewItemIds) {
return toAjax(service.deleteWithValidByIds(Arrays.asList(reviewItemIds), true));
}
@GetMapping("/all")
public R<java.util.List<RmTechReviewItemVo>> all(RmTechReviewItemBo bo) {
return R.ok(service.queryList(bo));
}
}

View File

@@ -0,0 +1,16 @@
package com.ruoyi.rm.domain.bo;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmAcceptanceChecklistBo extends BaseEntity {
private Long checkId;
private Long projectId;
private String itemText;
private String isChecked;
private Integer sortOrder;
private String remark;
}

View File

@@ -0,0 +1,24 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmAcceptanceItemBo extends BaseEntity {
private Long acceptItemId;
private Long projectId;
private String itemName;
private String requirement;
private String actualValue;
private String result;
private String notes;
private String inspector;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date inspectDate;
private String remark;
}

View File

@@ -0,0 +1,22 @@
package com.ruoyi.rm.domain.bo;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmBudgetBo extends BaseEntity {
private Long budgetId;
private Long projectId;
private String category;
private String item;
private BigDecimal budgetAmount;
private BigDecimal spentAmount;
private String status;
private String archiveBatch;
private String remark;
}

View File

@@ -0,0 +1,22 @@
package com.ruoyi.rm.domain.bo;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmColorCardBo extends BaseEntity {
private Long colorCardId;
private Long projectId;
private String colorName;
private String hexValue;
private String standard;
private String standardLabel;
private String category;
private String usageDesc;
private String description;
private Integer sortOrder;
private String remark;
}

View File

@@ -0,0 +1,19 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmCommissioningBo extends BaseEntity {
private Long commissioningId;
private Long projectId;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date commissioningDate;
private String confirmer;
private String remark;
}

View File

@@ -0,0 +1,16 @@
package com.ruoyi.rm.domain.bo;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmCommissioningChecklistBo extends BaseEntity {
private Long checkId;
private Long projectId;
private String itemText;
private String isChecked;
private Integer sortOrder;
private String remark;
}

View File

@@ -0,0 +1,18 @@
package com.ruoyi.rm.domain.bo;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmCommissioningClauseBo extends BaseEntity {
private Long clauseId;
private Long projectId;
private String clause;
private String standard;
private String result;
private String passFlag;
private Integer sortOrder;
private String remark;
}

View File

@@ -0,0 +1,24 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmDocLibBo extends BaseEntity {
private Long docId;
private Long projectId;
private String docName;
private String category;
private String version;
private String uploader;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date uploadDate;
private String fileUrl;
private String description;
private String remark;
}

View File

@@ -0,0 +1,26 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmDrawingCompareBo extends BaseEntity {
private Long compareId;
private Long projectId;
private String drawingName;
private String oldVersion;
private String newVersion;
private String optimizer;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date compareDate;
private String status;
private String beforeDesc;
private String afterDesc;
private String diffNotes;
private String remark;
}

View File

@@ -0,0 +1,28 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmDrawingDesignBo extends BaseEntity {
private Long drawingId;
private Long projectId;
private String drawingName;
private String drawingNo;
private String version;
private String drawingType;
private String drawer;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date startDate;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date endDate;
private String fileUrl;
private String status;
private String remark;
}

View File

@@ -0,0 +1,27 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmDrawingReviewBo extends BaseEntity {
private Long reviewId;
private Long projectId;
private Long drawingId;
private String drawingName;
private String drawingNo;
private String version;
private String fileUrl;
private String status;
private String reviewer;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date reviewDate;
private String reviewOpinion;
private String remark;
}

View File

@@ -0,0 +1,16 @@
package com.ruoyi.rm.domain.bo;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmFileReviewBo extends BaseEntity {
private Long id;
private Long fileId;
private String fileModule;
private Long reviewerId;
private String content;
private String reviewAction;
}

View File

@@ -0,0 +1,26 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmInstallFeedbackBo extends BaseEntity {
private Long feedbackId;
private Long projectId;
private String title;
private String location;
private String proposer;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date feedbackDate;
private String issueDesc;
private String solution;
private String preventAction;
private String status;
private String attachmentUrl;
private String remark;
}

View File

@@ -0,0 +1,27 @@
package com.ruoyi.rm.domain.bo;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmInstallPersonnelBo extends BaseEntity {
private Long personnelId;
private Long projectId;
private String name;
private String nameEn;
private String position;
private String positionEn;
private String planIn;
private String planOut;
private Integer days;
private BigDecimal dailyRate;
private BigDecimal totalWages;
private String duty;
private String qualification;
private String phone;
private String remark;
}

View File

@@ -0,0 +1,26 @@
package com.ruoyi.rm.domain.bo;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmInstallPrecisionBo extends BaseEntity {
private Long precisionId;
private Long projectId;
private String systemName;
private String itemName;
private String nameEn;
private String targetValue;
private String unit;
private String importance;
private String tool;
private String methodDesc;
private String standardRef;
private String requirement;
private String actualValue;
private String isQualified;
private String photos;
private String remark;
}

View File

@@ -0,0 +1,30 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmInstallProgressBo extends BaseEntity {
private Long progressId;
private Long projectId;
private String itemName;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date planStart;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date planEnd;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date actualStart;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date actualEnd;
private String status;
private String delayReason;
private String images;
private String videos;
private String remark;
}

View File

@@ -0,0 +1,31 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmInstallToolBo extends BaseEntity {
private Long toolId;
private Long projectId;
private String name;
private String nameEn;
private String spec;
private Integer qty;
private String unit;
private BigDecimal unitPrice;
private BigDecimal totalPrice;
private String priority;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date arrivalDate;
private String purpose;
private String responsible;
private String status;
private String category;
private String remark;
}

View File

@@ -0,0 +1,24 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmLayoutFileBo extends BaseEntity {
private Long layoutFileId;
private Long projectId;
private String fileName;
private String version;
private String fileType;
private String fileUrl;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date uploadDate;
private String status;
private String remark;
}

View File

@@ -0,0 +1,23 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmManualBo extends BaseEntity {
private Long manualId;
private Long projectId;
private String manualName;
private String docType;
private String version;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date uploadDate;
private String fileUrl;
private String description;
private String remark;
}

View File

@@ -0,0 +1,27 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmMfgDeviceBo extends BaseEntity {
private Long deviceId;
private Long projectId;
private String deviceName;
private String spec;
private String supplierName;
private String contractNo;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date orderDate;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date deliveryDate;
private BigDecimal penaltyRate;
private String remark;
}

View File

@@ -0,0 +1,35 @@
package com.ruoyi.rm.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
public class RmMfgStageBo extends BaseEntity {
private Long stageId;
private Long deviceId;
private String stageKey;
private String stageName;
private String status;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date planStartDate;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date planEndDate;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date actualStart;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date actualEnd;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date submittedDate;
private String manufacturingPhotos;
private String manufacturingVideo;
private String materialReport;
private String precisionReport;
private Integer sortOrder;
private String remark;
}

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