diff --git a/xinnengyuan/.gitignore b/xinnengyuan/.gitignore
index 2adafeb0..e1e3d8ac 100644
--- a/xinnengyuan/.gitignore
+++ b/xinnengyuan/.gitignore
@@ -54,3 +54,4 @@ docs
/file
.idea/
chat-memory/
+queries/
diff --git a/xinnengyuan/pom.xml b/xinnengyuan/pom.xml
index 7022d665..70e17df4 100644
--- a/xinnengyuan/pom.xml
+++ b/xinnengyuan/pom.xml
@@ -86,6 +86,15 @@
true
+
+ menu
+
+ menu
+ info
+ ruoyi
+ 123456
+
+
prod
diff --git a/xinnengyuan/ruoyi-admin/src/main/resources/application-dev.yml b/xinnengyuan/ruoyi-admin/src/main/resources/application-dev.yml
index 229ef4d1..953e8f06 100644
--- a/xinnengyuan/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/xinnengyuan/ruoyi-admin/src/main/resources/application-dev.yml
@@ -4,7 +4,7 @@ server:
port: 8899
--- # 监控中心配置
spring.boot.admin.client:
- # 增加客户端开关
+ # 增加客户端开关
enabled: false
url: http://192.168.110.119:9090/admin
instance:
@@ -41,7 +41,7 @@ spring:
api-key: sk-8d8df92fcbac4bd2922edba30b0bb8fa
chat:
options:
- model: qwen-plus
+ model: qwen3-max
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
@@ -66,7 +66,7 @@ spring:
# username: xinnengyuan
# password: mEZPC5Sdf3r2HENi
# 从库数据源
-# slave:
+ # slave:
# lazy: true
# type: ${spring.datasource.type}
# driverClassName: com.mysql.cj.jdbc.Driver
@@ -368,3 +368,14 @@ drone:
chat:
server:
port: 19099
+# rabbitmq 配置
+rabbitmq:
+ exchange-name: dev-normal-exchange
+ queue-name: dev-normal-queue
+ routing-key: dev.normal.routing.key
+ delay-exchange-name: dev-delay-queue
+ delay-queue-name: dev-delay-exchange
+ delay-routing-key: dev.delay.routing.key
+ dead-letter-exchange: dev-dlx-exchange
+ dead-letter-queue: dev-dlx-queue
+ dead-letter-routing-key: dev.dlx.routing.key
diff --git a/xinnengyuan/ruoyi-admin/src/main/resources/application-local.yml b/xinnengyuan/ruoyi-admin/src/main/resources/application-local.yml
index 64b0ccdc..38eebf83 100644
--- a/xinnengyuan/ruoyi-admin/src/main/resources/application-local.yml
+++ b/xinnengyuan/ruoyi-admin/src/main/resources/application-local.yml
@@ -343,3 +343,14 @@ drone:
chat:
server:
port: 18088
+# rabbitmq 配置
+rabbitmq:
+ exchange-name: local-normal-exchange
+ queue-name: local-normal-queue
+ routing-key: local.normal.routing.key
+ delay-exchange-name: local-delay-queue
+ delay-queue-name: local-delay-exchange
+ delay-routing-key: local.delay.routing.key
+ dead-letter-exchange: local-dlx-exchange
+ dead-letter-queue: local-dlx-queue
+ dead-letter-routing-key: local.dlx.routing.key
diff --git a/xinnengyuan/ruoyi-admin/src/main/resources/application-menu.yml b/xinnengyuan/ruoyi-admin/src/main/resources/application-menu.yml
new file mode 100644
index 00000000..68773c98
--- /dev/null
+++ b/xinnengyuan/ruoyi-admin/src/main/resources/application-menu.yml
@@ -0,0 +1,356 @@
+# 开发环境配置
+server:
+ # 服务器的HTTP端口,默认为8080
+ port: 9528
+--- # 临时文件存储位置 避免临时文件被系统清理报错
+spring.servlet.multipart.location: /ruoyi/server/temp
+
+--- # 监控中心配置
+spring.boot.admin.client:
+ # 增加客户端开关
+ enabled: false
+ url: http://localhost:9090/admin
+ instance:
+ service-host-type: IP
+ metadata:
+ username: ${spring.boot.admin.client.username}
+ userpassword: ${spring.boot.admin.client.password}
+ username: @monitor.username@
+ password: @monitor.password@
+
+--- # snail-job 配置
+snail-job:
+ enabled: false
+ # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
+ group: "ruoyi_group"
+ # SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config`表
+ token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
+ server:
+ host: 127.0.0.1
+ port: 17888
+ # 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
+ namespace: ${spring.profiles.active}
+ # 随主应用端口漂移
+ port: 2${server.port}
+ # 客户端ip指定
+ host:
+ # RPC类型: netty, grpc
+ rpc-type: grpc
+
+--- # 数据源配置
+spring:
+ ai:
+ dashscope:
+ api-key: sk-8d8df92fcbac4bd2922edba30b0bb8fa
+ chat:
+ options:
+ model: qwen3-max
+ datasource:
+ type: com.zaxxer.hikari.HikariDataSource
+ # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
+ dynamic:
+ # 性能分析插件(有性能损耗 不建议生产环境使用)
+ p6spy: false
+ # 设置默认的数据源或者数据源组,默认值即为 master
+ primary: master
+ # 严格模式 匹配不到数据源则报错
+ strict: true
+ datasource:
+ # 主库数据源
+ master:
+ type: ${spring.datasource.type}
+ driverClassName: com.mysql.cj.jdbc.Driver
+ # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
+ # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
+ url: jdbc:mysql://192.168.110.2:13386/xinnengyuanmenu?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+ username: xinnengyuanmenu
+ password: 2RkXFG8ZE6r5LL7B
+ # # 从库数据源
+ # slave:
+ # lazy: true
+ # type: ${spring.datasource.type}
+ # driverClassName: com.mysql.cj.jdbc.Driver
+ # url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+ # username:
+ # password:
+ # oracle:
+ # type: ${spring.datasource.type}
+ # driverClassName: oracle.jdbc.OracleDriver
+ # url: jdbc:oracle:thin:@//localhost:1521/XE
+ # username: ROOT
+ # password: root
+ # postgres:
+ # type: ${spring.datasource.type}
+ # driverClassName: org.postgresql.Driver
+ # url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
+ # username: root
+ # password: root
+ # sqlserver:
+ # type: ${spring.datasource.type}
+ # driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
+ # url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
+ # username: SA
+ # password: root
+ hikari:
+ # 最大连接池数量
+ maxPoolSize: 20
+ # 最小空闲线程数量
+ minIdle: 10
+ # 配置获取连接等待超时的时间
+ connectionTimeout: 30000
+ # 校验超时时间
+ validationTimeout: 5000
+ # 空闲连接存活最大时间,默认10分钟
+ idleTimeout: 600000
+ # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
+ maxLifetime: 1800000
+ # 多久检查一次连接的活性
+ keepaliveTime: 30000
+
+--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
+spring.data:
+ redis:
+ # 地址
+ host: 192.168.110.2
+ # 端口,默认为6379
+ port: 9287
+ # 数据库索引
+ database: 21
+ # redis 密码必须配置
+ password: syar23rdsaagdrsa
+ # 连接超时时间
+ timeout: 10s
+ # 是否开启ssl
+ ssl.enabled: false
+
+# redisson 配置
+redisson:
+ # redis key前缀
+ keyPrefix:
+ # 线程池数量
+ threads: 16
+ # Netty线程池数量
+ nettyThreads: 32
+ # 单节点配置
+ singleServerConfig:
+ # 客户端名称
+ clientName: ${ruoyi.name}
+ # 最小空闲连接数
+ connectionMinimumIdleSize: 32
+ # 连接池大小
+ connectionPoolSize: 64
+ # 连接空闲超时,单位:毫秒
+ idleConnectionTimeout: 10000
+ # 命令等待超时,单位:毫秒
+ timeout: 3000
+ # 发布和订阅连接池大小
+ subscriptionConnectionPoolSize: 50
+
+--- # mail 邮件发送
+mail:
+ enabled: false
+ host: smtp.163.com
+ port: 465
+ # 是否需要用户名密码验证
+ auth: true
+ # 发送方,遵循RFC-822标准
+ from: xxx@163.com
+ # 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
+ user: xxx@163.com
+ # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
+ pass: xxxxxxxxxx
+ # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
+ starttlsEnable: true
+ # 使用SSL安全连接
+ sslEnable: true
+ # SMTP超时时长,单位毫秒,缺省值不超时
+ timeout: 0
+ # Socket连接超时值,单位毫秒,缺省值不超时
+ connectionTimeout: 0
+
+--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
+# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
+sms:
+ # 配置源类型用于标定配置来源(interface,yaml)
+ config-type: yaml
+ # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制
+ restricted: false
+ # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
+ minute-max: 1
+ # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
+ account-max: 30
+ # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
+ blends:
+ # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
+ # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
+ config1:
+ # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
+ supplier: alibaba
+ # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。
+ access-key-id: 您的accessKey
+ # 称为accessSecret有些称之为apiSecret
+ access-key-secret: 您的accessKeySecret
+ signature: 您的短信签名
+ sdk-app-id: 您的sdkAppId
+ config2:
+ # 登录
+ supplier: tencent
+ access-key-id: AKIDb3JK5dx4wa0DCxWqvxlKejvysZ3ITVJv
+ access-key-secret: c5LPFsJI8k7GDxTkoeFj4A1ukQr66rPi
+ signature: 重庆远界大数据研究院
+ sdk-app-id: 1401018866
+ template-id: 2491779
+ config3:
+ # 注册
+ supplier: tencent
+ access-key-id: AKIDb3JK5dx4wa0DCxWqvxlKejvysZ3ITVJv
+ access-key-secret: c5LPFsJI8k7GDxTkoeFj4A1ukQr66rPi
+ signature: 重庆远界大数据研究院
+ sdk-app-id: 1401018866
+ template-id: 2491776
+ config4:
+ # 质量工单逾期
+ supplier: tencent
+ access-key-id: AKIDb3JK5dx4wa0DCxWqvxlKejvysZ3ITVJv
+ access-key-secret: c5LPFsJI8k7GDxTkoeFj4A1ukQr66rPi
+ signature: 重庆远界大数据研究院
+ sdk-app-id: 1401018866
+ template-id: 2534747
+ config5:
+ # 设计图纸
+ supplier: tencent
+ access-key-id: AKIDb3JK5dx4wa0DCxWqvxlKejvysZ3ITVJv
+ access-key-secret: c5LPFsJI8k7GDxTkoeFj4A1ukQr66rPi
+ signature: 重庆远界大数据研究院
+ sdk-app-id: 1401018866
+ template-id: 2534750
+ config6:
+ # 安全工单
+ supplier: tencent
+ access-key-id: AKIDb3JK5dx4wa0DCxWqvxlKejvysZ3ITVJv
+ access-key-secret: c5LPFsJI8k7GDxTkoeFj4A1ukQr66rPi
+ signature: 重庆远界大数据研究院
+ sdk-app-id: 1401018866
+ template-id: 2534848
+
+--- # 三方授权
+justauth:
+ # 前端外网访问地址
+ address: http://localhost:80
+ type:
+ maxkey:
+ # maxkey 服务器地址
+ # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
+ server-url: http://sso.maxkey.top
+ client-id: 876892492581044224
+ client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
+ redirect-uri: ${justauth.address}/social-callback?source=maxkey
+ topiam:
+ # topiam 服务器地址
+ server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol
+ client-id: 449c4*********937************759
+ client-secret: ac7***********1e0************28d
+ redirect-uri: ${justauth.address}/social-callback?source=topiam
+ scopes: [ openid, email, phone, profile ]
+ qq:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=qq
+ union-id: false
+ weibo:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=weibo
+ gitee:
+ client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
+ client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
+ redirect-uri: ${justauth.address}/social-callback?source=gitee
+ dingtalk:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=dingtalk
+ baidu:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=baidu
+ csdn:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=csdn
+ coding:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=coding
+ coding-group-name: xx
+ oschina:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=oschina
+ alipay_wallet:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
+ alipay-public-key: MIIB**************DAQAB
+ wechat_open:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=wechat_open
+ wechat_mp:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
+ wechat_enterprise:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
+ agent-id: 1000002
+ gitlab:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=gitlab
+# 和风天气 https://dev.qweather.com/
+weather:
+ key-id: T65EAABUXC
+ project-id: 2JTHPUQ5YY
+ private-key: MC4CAQAwBQYDK2VwBCIEIMAglX7IsxYiTeM+FXXnvCUsIggajeP4s8gAllewm6BN
+ api-host: n35rk53njv.re.qweatherapi.com
+# dxf转 geojson 执行文件名
+dxf2GeoJson:
+ file-name: main
+ys7:
+ app-key: xxx
+ app-secret: xxx
+ job:
+ capture-enabled: false # 控制是否启用萤石抓拍任务
+ device-sync-enabled: false # 控制是否同步萤石设备
+# 斯巴达算法
+sparta:
+ url: http://119.3.204.120:8040
+ client-id: test
+ client-secret: 115fcb08fa6742a1b086d9bb80a6ad59
+# 身份证加密密钥(32 位)
+id-card:
+ encrypt-key: 7ae260d150a14027d2238a1cf80a48ef
+recognizer:
+ url: http://192.168.110.5:50071
+
+qrCode:
+ url: http://xny.yj-3d.com:7788
+# 无人机大图
+drone:
+ url: http://192.168.110.2:9512
+# 聊天服务
+chat:
+ server:
+ port: 18088
+# rabbitmq 配置
+rabbitmq:
+ exchange-name: local-normal-exchange
+ queue-name: local-normal-queue
+ routing-key: local.normal.routing.key
+ delay-exchange-name: local-delay-queue
+ delay-queue-name: local-delay-exchange
+ delay-routing-key: local.delay.routing.key
+ dead-letter-exchange: local-dlx-exchange
+ dead-letter-queue: local-dlx-queue
+ dead-letter-routing-key: local.dlx.routing.key
diff --git a/xinnengyuan/ruoyi-admin/src/main/resources/application-prod.yml b/xinnengyuan/ruoyi-admin/src/main/resources/application-prod.yml
index 235b008a..5b6e6e05 100644
--- a/xinnengyuan/ruoyi-admin/src/main/resources/application-prod.yml
+++ b/xinnengyuan/ruoyi-admin/src/main/resources/application-prod.yml
@@ -358,3 +358,14 @@ drone:
chat:
server:
port: 19099
+# rabbitmq 配置
+rabbitmq:
+ exchange-name: prod-normal-exchange
+ queue-name: prod-normal-queue
+ routing-key: prod.normal.routing.key
+ delay-exchange-name: prod-delay-queue
+ delay-queue-name: prod-delay-exchange
+ delay-routing-key: prod.delay.routing.key
+ dead-letter-exchange: prod-dlx-exchange
+ dead-letter-queue: prod-dlx-queue
+ dead-letter-routing-key: prod.dlx.routing.key
diff --git a/xinnengyuan/ruoyi-admin/src/main/resources/application.yml b/xinnengyuan/ruoyi-admin/src/main/resources/application.yml
index 9b5259f3..6cf84cfe 100644
--- a/xinnengyuan/ruoyi-admin/src/main/resources/application.yml
+++ b/xinnengyuan/ruoyi-admin/src/main/resources/application.yml
@@ -95,7 +95,13 @@ spring:
deserialization:
# 允许对象忽略json中不存在的属性
fail_on_unknown_properties: false
-
+ rabbitmq:
+ host: 192.168.110.2
+ port: 5672
+ username: admin
+ password: yuanjiexny
+ publisher-returns: true
+ publisher-confirm-type: correlated
# Sa-Token配置
sa-token:
# token名称 (同时也是cookie名称)
@@ -109,7 +115,7 @@ sa-token:
# token有效期,单位s 默认30天, -1代表永不过期
timeout: 2592000
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
- active-timeout: 86400
+ active-timeout: 2592000
# 同一账号最大登录数量,-1代表不限
max-login-count: -1
@@ -305,6 +311,12 @@ springdoc:
packages-to-scan: org.dromara.ai
- group: 31.投标管理模块
packages-to-scan: org.dromara.bidding
+ - group: 32.设备模块
+ packages-to-scan: org.dromara.device
+ - group: 33.摄像头模块
+ packages-to-scan: org.dromara.other
+ - group: 34.机械模块
+ packages-to-scan: org.dromara.mechanical
# knife4j的增强配置,不需要增强可以不配
knife4j:
enable: true
diff --git a/xinnengyuan/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TimestampUtils.java b/xinnengyuan/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TimestampUtils.java
new file mode 100644
index 00000000..b35d6364
--- /dev/null
+++ b/xinnengyuan/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TimestampUtils.java
@@ -0,0 +1,146 @@
+package org.dromara.common.core.utils;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * 时间戳转换工具类(包含时分秒提取)
+ */
+public class TimestampUtils {
+
+ // 默认时区(东八区)
+ private static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone("GMT+8");
+
+ // 完整日期格式
+ private static final String FULL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
+ // 时分秒格式
+ private static final String TIME_FORMAT = "HH:mm:ss";
+
+ // 日期格式
+ private static final String DATE_FORMAT = "yyyy-MM-dd";
+
+ /**
+ * 将日期字符串转为秒级时间戳(优化版)
+ * 支持格式:"2025-12-03 23:59:59"、"2025-12-03"等
+ * @param dateStr 日期字符串
+ * @return 秒级时间戳
+ */
+ public static Long parseDateToTimestamp(String dateStr) {
+ if (StrUtil.isBlank(dateStr)) {
+ return null;
+ }
+
+ // 使用Hutool的DateUtil进行智能解析(推荐)
+ try {
+ Date date = DateUtil.parse(dateStr);
+ return date.getTime() / 1000L; // 转为秒级时间戳
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ String.format("日期格式错误:%s,支持格式:yyyy-MM-dd HH:mm:ss、yyyy-MM-dd等", dateStr)
+ );
+ }
+ }
+
+ /**
+ * 将时间戳转换为完整日期格式(yyyy-MM-dd HH:mm:ss)
+ */
+ public static String formatTimestamp(Object timestamp) {
+ if (timestamp == null) {
+ return null;
+ }
+
+ String timestampStr = timestamp.toString().trim();
+ if (StrUtil.isBlank(timestampStr)) {
+ return null;
+ }
+
+ Long time = parseToMilliseconds(timestampStr);
+ SimpleDateFormat sdf = new SimpleDateFormat(FULL_DATE_FORMAT);
+ sdf.setTimeZone(DEFAULT_TIME_ZONE);
+ return sdf.format(new Date(time));
+ }
+
+ /**
+ * 提取时间戳中的时分秒部分(HH:mm:ss)
+ */
+ public static String extractTime(Object timestamp) {
+ if (timestamp == null) {
+ return null;
+ }
+
+ String timestampStr = timestamp.toString().trim();
+ if (StrUtil.isBlank(timestampStr)) {
+ return null;
+ }
+
+ Long time = parseToMilliseconds(timestampStr);
+ SimpleDateFormat sdf = new SimpleDateFormat(TIME_FORMAT);
+ sdf.setTimeZone(DEFAULT_TIME_ZONE);
+ return sdf.format(new Date(time));
+ }
+
+ /**
+ * 提取时间戳中的日期部分(yyyy-MM-dd)
+ */
+ public static String extractDate(Object timestamp) {
+ if (timestamp == null) {
+ return null;
+ }
+
+ String timestampStr = timestamp.toString().trim();
+ if (StrUtil.isBlank(timestampStr)) {
+ return null;
+ }
+
+ Long time = parseToMilliseconds(timestampStr);
+ SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
+ sdf.setTimeZone(DEFAULT_TIME_ZONE);
+ return sdf.format(new Date(time));
+ }
+
+ /**
+ * 解析时间戳字符串为毫秒级时间戳
+ */
+ private static Long parseToMilliseconds(String timestampStr) {
+ try {
+ Long time = Long.parseLong(timestampStr);
+ // 10位秒级时间戳转为13位毫秒级
+ if (timestampStr.length() == 10) {
+ time = time * 1000;
+ }
+ return time;
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("时间戳格式错误:" + timestampStr);
+ }
+ }
+
+ /**
+ * 获取时间戳对应的小时
+ */
+ public static int getHour(Object timestamp) {
+ String timeStr = extractTime(timestamp);
+ return Integer.parseInt(timeStr.split(":")[0]);
+ }
+
+ /**
+ * 获取时间戳对应的分钟
+ */
+ public static int getMinute(Object timestamp) {
+ String timeStr = extractTime(timestamp);
+ return Integer.parseInt(timeStr.split(":")[1]);
+ }
+
+ /**
+ * 获取时间戳对应的秒
+ */
+ public static int getSecond(Object timestamp) {
+ String timeStr = extractTime(timestamp);
+ return Integer.parseInt(timeStr.split(":")[2]);
+ }
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/pom.xml b/xinnengyuan/ruoyi-modules/ruoyi-system/pom.xml
index 4bffab53..c9925bb7 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/pom.xml
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/pom.xml
@@ -29,6 +29,10 @@
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
com.twelvemonkeys.imageio
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/ai/chat/DashScopeChat.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/ai/chat/DashScopeChat.java
index b24f8d6d..91c9932f 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/ai/chat/DashScopeChat.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/ai/chat/DashScopeChat.java
@@ -25,7 +25,7 @@ import java.util.concurrent.CompletableFuture;
public class DashScopeChat {
@Resource
- private SimpleChat simpleChat;
+ private DashScopeSimpleChat dashScopeSimpleChat;
@Resource
private IAIChatMemoryService chatMemoryService;
@@ -66,10 +66,8 @@ public class DashScopeChat {
.collectList()
.flatMapMany(tokens -> {
String aiResponse = String.join("", tokens);
- if (isFirst) {
- // 异步生成标题
- generateChatTitleAsync(chatId, message, aiResponse, userId);
- }
+ // 异步生成标题
+ generateChatTitleAsync(chatId, message, aiResponse, userId);
// 返回完整的流结果
return Flux.fromIterable(tokens);
});
@@ -100,7 +98,7 @@ public class DashScopeChat {
用户:%s
AI:%s
""", userMessage, aiResponse);
- String title = simpleChat.doChat(prompt);
+ String title = dashScopeSimpleChat.doChat(prompt);
log.info("用户:{} 生成标题成功:{} -> {}", userId, chatId, title);
// 保存对话数据
AIChatMemory memory = new AIChatMemory();
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/ai/chat/SimpleChat.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/ai/chat/DashScopeSimpleChat.java
similarity index 88%
rename from xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/ai/chat/SimpleChat.java
rename to xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/ai/chat/DashScopeSimpleChat.java
index 4f2dbdff..eaa2e68d 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/ai/chat/SimpleChat.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/ai/chat/DashScopeSimpleChat.java
@@ -9,11 +9,11 @@ import org.springframework.stereotype.Component;
* @date 2025-11-04 15:26
*/
@Component
-public class SimpleChat {
+public class DashScopeSimpleChat {
private final ChatClient dashScopeChatClient;
- public SimpleChat(ChatClient.Builder chatClientBuilder) {
+ public DashScopeSimpleChat(ChatClient.Builder chatClientBuilder) {
this.dashScopeChatClient = chatClientBuilder
// 设置 ChatClient 中 ChatModel 的 Options 参数
.defaultOptions(
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/bigscreen/controller/PersonalHomeController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/bigscreen/controller/PersonalHomeController.java
index c481c94b..563b71b6 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/bigscreen/controller/PersonalHomeController.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/bigscreen/controller/PersonalHomeController.java
@@ -41,7 +41,6 @@ import org.dromara.patch.service.IPdMasterService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.system.domain.SysMenu;
import org.dromara.system.domain.vo.RouterVo;
-import org.dromara.system.mapper.SysRoleMapper;
import org.dromara.system.service.impl.SysMenuServiceImpl;
import org.dromara.system.service.impl.SysUserServiceImpl;
import org.dromara.warm.flow.core.FlowEngine;
@@ -97,8 +96,7 @@ public class PersonalHomeController extends BaseController {
@Resource
private IBusProjectService projectService;
- private final SysRoleMapper roleMapper;
- private final SysMenuServiceImpl sysMenuService;
+ private final SysMenuServiceImpl sysMenuService;
// region AI 模块
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/bigscreen/controller/UEController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/bigscreen/controller/UEController.java
new file mode 100644
index 00000000..efc4a1d4
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/bigscreen/controller/UEController.java
@@ -0,0 +1,39 @@
+package org.dromara.bigscreen.controller;
+
+import jakarta.annotation.Resource;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.bigscreen.domain.vo.ProjectPeopleVo;
+import org.dromara.bigscreen.service.ProjectBigScreenService;
+import org.dromara.common.core.domain.R;
+import org.dromara.project.domain.vo.project.BusProjectVo;
+import org.dromara.project.service.IBusProjectService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * UE大屏
+ *
+ * @author Lion Li
+ * @date 2025-11-04
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/UE/screen")
+public class UEController {
+
+ @Resource
+ private IBusProjectService projectService;
+
+
+ @GetMapping("/projectInfo/{projectId}")
+ public R getProjectPeople(@NotNull(message = "主键不能为空")
+ @PathVariable Long projectId) {
+ return R.ok(projectService.selectById(projectId));
+ }
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusTotalsupplyplanServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusTotalsupplyplanServiceImpl.java
index 1b2c659f..a6959892 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusTotalsupplyplanServiceImpl.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusTotalsupplyplanServiceImpl.java
@@ -1,6 +1,7 @@
package org.dromara.cailiaoshebei.service.impl;
import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
@@ -104,7 +105,7 @@ public class BusTotalsupplyplanServiceImpl extends ServiceImpl buildQueryWrapper(BusTotalsupplyplanBo bo) {
Map params = bo.getParams();
LambdaQueryWrapper lqw = Wrappers.lambdaQuery();
- lqw.eq(bo.getProjectId() != null ,BusTotalsupplyplan::getProjectId,bo.getProjectId());
+ lqw.eq(bo.getProjectId() != null, BusTotalsupplyplan::getProjectId, bo.getProjectId());
lqw.eq(StringUtils.isNotBlank(bo.getTexture()), BusTotalsupplyplan::getTexture, bo.getTexture());
lqw.eq(StringUtils.isNotBlank(bo.getBrand()), BusTotalsupplyplan::getBrand, bo.getBrand());
lqw.eq(StringUtils.isNotBlank(bo.getQualityStandard()), BusTotalsupplyplan::getQualityStandard, bo.getQualityStandard());
@@ -239,7 +240,14 @@ public class BusTotalsupplyplanServiceImpl extends ServiceImpl data.getId() != null).toList();
+ if (CollUtil.isEmpty(allData)) {
throw new ServiceException("未读取到有效数据", HttpStatus.BAD_REQUEST);
}
// 处理导入的数据
@@ -248,7 +256,7 @@ public class BusTotalsupplyplanServiceImpl extends ServiceImpl list(BusComplaintBoxBo bo, PageQuery pageQuery) {
+ LoginUser loginUser = LoginHelper.getLoginUser();
+ if (loginUser != null) {
+ bo.setUserId(loginUser.getUserId());
+ }
+ return busComplaintBoxService.appQueryPageList(bo, pageQuery);
+ }
+
+
+
+ /**
+ * 获取意见箱详细信息
+ *
+ * @param id 主键
+ */
+// @SaCheckPermission("appComplaintBox:complaintBox:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "主键不能为空")
+ @PathVariable Long id) {
+ return R.ok(busComplaintBoxService.appQueryById(id));
+ }
+
+ /**
+ * 新增意见箱
+ */
+// @SaCheckPermission("appComplaintBox:complaintBox:add")
+ @Log(title = "意见箱", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R add(@Validated(AddGroup.class) @RequestBody BusComplaintBoxBo bo) {
+ return toAjax(busComplaintBoxService.insertByBo(bo));
+ }
+
+
+ /**
+ * 新增意见回复
+ */
+// @SaCheckPermission("appComplaintBox:complaintBox:add")
+ @Log(title = "意见箱", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping("/postAReply")
+ public R postAReply(@Validated(AddGroup.class) @RequestBody BusComplaintBoxMessageLoggingBo bo) {
+ return toAjax(busComplaintBoxMessageLoggingService.insertAppByBo(bo));
+ }
+
+ /**
+ * 修改意见阅读状态
+ */
+// @SaCheckPermission("appComplaintBox:complaintBox:edit")
+ @Log(title = "意见箱", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping("/editCheckStatus")
+ public R editCheckStatus(@Validated(EditGroup.class) @RequestBody BusComplaintBoxBo bo) {
+ return toAjax(busComplaintBoxService.editCheckStatus(bo));
+ }
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/app/domain/vo/AppDetailsOfTheOpinionVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/app/domain/vo/AppDetailsOfTheOpinionVo.java
new file mode 100644
index 00000000..72e47704
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/app/domain/vo/AppDetailsOfTheOpinionVo.java
@@ -0,0 +1,16 @@
+package org.dromara.complaintBox.app.domain.vo;
+
+import lombok.Data;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxMessageLoggingVo;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxVo;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class AppDetailsOfTheOpinionVo implements Serializable {
+
+ private BusComplaintBoxVo busComplaintBoxVo;
+
+ private List messageLoggingVos;
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/controller/BusComplaintBoxController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/controller/BusComplaintBoxController.java
new file mode 100644
index 00000000..6137f009
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/controller/BusComplaintBoxController.java
@@ -0,0 +1,124 @@
+package org.dromara.complaintBox.controller;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.complaintBox.domain.bo.BusComplaintBoxDisposeLoggingBo;
+import org.dromara.complaintBox.domain.bo.BusComplaintBoxMessageLoggingBo;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxDisposeLoggingVo;
+import org.dromara.complaintBox.domain.vo.ComplaintBoxCountVo;
+import org.dromara.complaintBox.domain.vo.DetailsOfTheOpinionVo;
+import org.dromara.complaintBox.service.IBusComplaintBoxDisposeLoggingService;
+import org.dromara.complaintBox.service.IBusComplaintBoxMessageLoggingService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxVo;
+import org.dromara.complaintBox.domain.bo.BusComplaintBoxBo;
+import org.dromara.complaintBox.service.IBusComplaintBoxService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+import java.util.List;
+
+/**
+ * 意见箱
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/complaintBox/complaintBox")
+public class BusComplaintBoxController extends BaseController {
+
+ private final IBusComplaintBoxService busComplaintBoxService;
+ @Lazy
+ @Autowired
+ private IBusComplaintBoxMessageLoggingService busComplaintBoxMessageLoggingService;
+ @Lazy
+ @Autowired
+ private IBusComplaintBoxDisposeLoggingService disposeLoggingService;
+
+
+ /**
+ * 查询意见箱列表
+ */
+ @SaCheckPermission("complaintBox:complaintBox:list")
+ @GetMapping("/list")
+ public TableDataInfo list(BusComplaintBoxBo bo, PageQuery pageQuery) {
+ return busComplaintBoxService.queryPageList(bo, pageQuery);
+ }
+ /**
+ * 查询意见处理记录列表
+ */
+ @SaCheckPermission("complaintBox:complaintBox:list")
+ @GetMapping("/getDisposeLogList")
+ public TableDataInfo getDisposeLogList(BusComplaintBoxDisposeLoggingBo bo, PageQuery pageQuery) {
+ return disposeLoggingService.queryPageList(bo, pageQuery);
+ }
+ /**
+ * web获取各个处理状态数量
+ */
+ @SaCheckPermission("complaintBox:complaintBox:list")
+ @GetMapping("/getCount")
+ public R> getCount(BusComplaintBoxBo bo) {
+ return R.ok(busComplaintBoxService.getCount(bo));
+ }
+
+ /**
+ * 获取意见箱详细信息
+ *
+ * @param id 主键
+ */
+// @SaCheckPermission("complaintBox:complaintBox:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "主键不能为空")
+ @PathVariable Long id) {
+ return R.ok(busComplaintBoxService.getInfo(id));
+ }
+
+ /**
+ * 新增意见回复
+ */
+ @SaCheckPermission("complaintBox:complaintBox:add")
+ @Log(title = "意见箱", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping("/postAReply")
+ public R postAReply(@Validated(AddGroup.class) @RequestBody BusComplaintBoxMessageLoggingBo bo) {
+ return toAjax(busComplaintBoxMessageLoggingService.insertWebByBo(bo));
+ }
+
+
+ /**
+ * 修改意见阅读状态
+ */
+ @SaCheckPermission("complaintBox:complaintBox:edit")
+ @Log(title = "意见箱", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping("/editCheckStatus")
+ public R editCheckStatus(@Validated(EditGroup.class) @RequestBody BusComplaintBoxBo bo) {
+ return toAjax(busComplaintBoxService.editCheckStatus(bo));
+ }
+
+ /**
+ * 修改意见阅读状态
+ */
+ @SaCheckPermission("complaintBox:complaintBox:edit")
+ @Log(title = "意见箱", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping("/editStatus")
+ public R editStatus(@Validated(EditGroup.class) @RequestBody BusComplaintBoxBo bo) {
+ return toAjax(busComplaintBoxService.editStatus(bo));
+ }
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/BusComplaintBox.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/BusComplaintBox.java
new file mode 100644
index 00000000..108d526c
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/BusComplaintBox.java
@@ -0,0 +1,91 @@
+package org.dromara.complaintBox.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 意见箱对象 bus_complaint_box
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("bus_complaint_box")
+public class BusComplaintBox extends BaseEntity {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键ID
+ */
+ @TableId(value = "id")
+ private Long id;
+
+ /**
+ * 公司id(当前登录人的顶层下一级部门id)
+ */
+ private Long companyId;
+
+ /**
+ * 项目id
+ */
+ private Long projectId;
+
+ /**
+ * 用户id
+ */
+ private Long userId;
+
+ /**
+ * 用户名
+ */
+ private String userName;
+
+ /**
+ * 头像地址
+ */
+ private Long avatar;
+
+ /**
+ * 标题
+ */
+ private String title;
+
+ /**
+ * 意见类型(1、功能建议,2、Bug反馈,3、体验问题,4其他意见)
+ */
+ private String opinionType;
+
+ /**
+ * 详细描述
+ */
+ private String detail;
+
+ /**
+ * 上传图片(id,id之间使用','分割)
+ */
+ private String fileId;
+
+ /**
+ * 是否匿名提交(0、否,1、是)
+ */
+ private String isCryptonym;
+
+ /**
+ * 处理状态(0、待处理,5、处理中,9、已解决,10、退回,14、不予解决())
+ */
+ private String status;
+
+ /**
+ * 当前处理人id
+ */
+ private Long currentDisposeUserId;
+
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/BusComplaintBoxDisposeLogging.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/BusComplaintBoxDisposeLogging.java
new file mode 100644
index 00000000..8a874e68
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/BusComplaintBoxDisposeLogging.java
@@ -0,0 +1,61 @@
+package org.dromara.complaintBox.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 意见箱-意见处理记录对象 bus_complaint_box_dispose_logging
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("bus_complaint_box_dispose_logging")
+public class BusComplaintBoxDisposeLogging extends BaseEntity {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键ID
+ */
+ @TableId(value = "id")
+ private Long id;
+
+ /**
+ * 意见id
+ */
+ private Long complaintId;
+
+ /**
+ * 用户id
+ */
+ private Long userId;
+
+ /**
+ * 用户名
+ */
+ private String userName;
+
+ /**
+ * 头像地址
+ */
+ private Long avatar;
+
+ /**
+ * 是否退回(0、否,1、是)
+ */
+ private String isRefund;
+
+ /**
+ * 退回原因
+ */
+ private String cause;
+
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/BusComplaintBoxMessageLogging.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/BusComplaintBoxMessageLogging.java
new file mode 100644
index 00000000..9ccaf50a
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/BusComplaintBoxMessageLogging.java
@@ -0,0 +1,76 @@
+package org.dromara.complaintBox.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 意见箱-意见沟通记录对象 bus_complaint_box_message_logging
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("bus_complaint_box_message_logging")
+public class BusComplaintBoxMessageLogging extends BaseEntity {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键ID
+ */
+ @TableId(value = "id")
+ private Long id;
+
+ /**
+ * 意见id
+ */
+ private Long complaintId;
+
+ /**
+ * 回复用户id
+ */
+ private Long replyUserId;
+
+ /**
+ * 回复用户名
+ */
+ private String replyUserName;
+
+ /**
+ * 回复用户头像地址
+ */
+ private Long replyAvatar;
+
+ /**
+ * 被回复用户id
+ */
+ private Long repliedUserId;
+
+ /**
+ * 被回复用户名
+ */
+ private String repliedUserName;
+
+ /**
+ * 被回复用户头像地址
+ */
+ private Long repliedAvatar;
+
+ /**
+ * 消息内容
+ */
+ private String details;
+
+ /**
+ * 处理状态(0、未读,1、已读)
+ */
+ private String status;
+
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/bo/BusComplaintBoxBo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/bo/BusComplaintBoxBo.java
new file mode 100644
index 00000000..c99a891f
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/bo/BusComplaintBoxBo.java
@@ -0,0 +1,95 @@
+package org.dromara.complaintBox.domain.bo;
+
+import org.dromara.complaintBox.domain.BusComplaintBox;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 意见箱业务对象 bus_complaint_box
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = BusComplaintBox.class, reverseConvertGenerate = false)
+public class BusComplaintBoxBo extends BaseEntity {
+
+ /**
+ * 主键ID
+ */
+ @NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
+ private Long id;
+
+ /**
+ * 公司id(当前登录人的顶层下一级部门id)
+ */
+ private Long companyId;
+
+ /**
+ * 项目id
+ */
+ private Long projectId;
+
+ /**
+ * 用户id
+ */
+ @NotNull(message = "主键ID不能为空", groups = { AddGroup.class })
+ private Long userId;
+ /**
+ * 当前处理人id
+ */
+ private Long currentDisposeUserId;
+
+ /**
+ * 用户名
+ */
+ private String userName;
+
+ /**
+ * 头像地址
+ */
+ private Long avatar;
+
+ /**
+ * 标题
+ */
+ private String title;
+
+ /**
+ * 意见类型(1、功能建议,2、Bug反馈,3、体验问题,4其他意见)
+ */
+ private String opinionType;
+
+ /**
+ * 详细描述
+ */
+ private String detail;
+
+ /**
+ * 上传图片(id,id之间使用','分割)
+ */
+ private String fileId;
+
+ /**
+ * 是否匿名提交(0、否,1、是)
+ */
+ private String isCryptonym;
+
+ /**
+ * 处理状态(0、待处理,5、处理中,9、已解决,14、关闭)
+ */
+ private String status;
+
+ /**
+ * 退回原因
+ */
+ private String cause;
+
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/bo/BusComplaintBoxDisposeLoggingBo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/bo/BusComplaintBoxDisposeLoggingBo.java
new file mode 100644
index 00000000..a8b74939
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/bo/BusComplaintBoxDisposeLoggingBo.java
@@ -0,0 +1,60 @@
+package org.dromara.complaintBox.domain.bo;
+
+import org.dromara.complaintBox.domain.BusComplaintBoxDisposeLogging;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 意见箱-意见处理记录业务对象 bus_complaint_box_dispose_logging
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = BusComplaintBoxDisposeLogging.class, reverseConvertGenerate = false)
+public class BusComplaintBoxDisposeLoggingBo extends BaseEntity {
+
+ /**
+ * 主键ID
+ */
+ @NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
+ private Long id;
+
+ /**
+ * 意见id
+ */
+ private Long complaintId;
+
+ /**
+ * 用户id
+ */
+ private Long userId;
+
+ /**
+ * 用户名
+ */
+ private String userName;
+
+ /**
+ * 头像地址
+ */
+ private Long avatar;
+
+ /**
+ * 是否退回(0、否,1、是)
+ */
+ private String isRefund;
+
+ /**
+ * 退回原因
+ */
+ private String cause;
+
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/bo/BusComplaintBoxMessageLoggingBo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/bo/BusComplaintBoxMessageLoggingBo.java
new file mode 100644
index 00000000..1da3700c
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/bo/BusComplaintBoxMessageLoggingBo.java
@@ -0,0 +1,80 @@
+package org.dromara.complaintBox.domain.bo;
+
+import org.dromara.complaintBox.domain.BusComplaintBoxMessageLogging;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 意见箱-意见沟通记录业务对象 bus_complaint_box_message_logging
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = BusComplaintBoxMessageLogging.class, reverseConvertGenerate = false)
+public class BusComplaintBoxMessageLoggingBo extends BaseEntity {
+
+ /**
+ * 主键ID
+ */
+ @NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
+ private Long id;
+
+ /**
+ * 意见id
+ */
+ private Long complaintId;
+
+ /**
+ * 回复用户id
+ */
+ private Long replyUserId;
+
+ /**
+ * 回复用户名
+ */
+ private String replyUserName;
+
+ /**
+ * 回复用户头像地址
+ */
+ private Long replyAvatar;
+
+ /**
+ * 被回复用户id
+ */
+ private Long repliedUserId;
+
+ /**
+ * 被回复用户名
+ */
+ private String repliedUserName;
+
+ /**
+ * 被回复用户头像地址
+ */
+ private Long repliedAvatar;
+
+ /**
+ * 消息内容
+ */
+ private String details;
+
+ /**
+ * 处理状态(0、未读,1、已读)
+ */
+ private String status;
+
+ /**
+ * 上一条沟通记录id
+ */
+ private Long oldId;
+
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/BusComplaintBoxDisposeLoggingVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/BusComplaintBoxDisposeLoggingVo.java
new file mode 100644
index 00000000..26b3108c
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/BusComplaintBoxDisposeLoggingVo.java
@@ -0,0 +1,82 @@
+package org.dromara.complaintBox.domain.vo;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import org.dromara.complaintBox.domain.BusComplaintBoxDisposeLogging;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 意见箱-意见处理记录视图对象 bus_complaint_box_dispose_logging
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = BusComplaintBoxDisposeLogging.class)
+public class BusComplaintBoxDisposeLoggingVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键ID
+ */
+ @ExcelProperty(value = "主键ID")
+ private Long id;
+
+ /**
+ * 意见id
+ */
+ @ExcelProperty(value = "意见id")
+ private Long complaintId;
+
+ /**
+ * 用户id
+ */
+ @ExcelProperty(value = "用户id")
+ private Long userId;
+
+ /**
+ * 用户名
+ */
+ @ExcelProperty(value = "用户名")
+ private String userName;
+
+ /**
+ * 头像地址
+ */
+ @ExcelProperty(value = "头像地址")
+ private Long avatar;
+
+ /**
+ * 是否退回(0、否,1、是)
+ */
+ @ExcelProperty(value = "是否退回", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "0=、否,1、是")
+ private String isRefund;
+
+ /**
+ * 退回原因
+ */
+ @ExcelProperty(value = "退回原因")
+ private String cause;
+
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/BusComplaintBoxMessageLoggingVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/BusComplaintBoxMessageLoggingVo.java
new file mode 100644
index 00000000..d4fbea39
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/BusComplaintBoxMessageLoggingVo.java
@@ -0,0 +1,99 @@
+package org.dromara.complaintBox.domain.vo;
+
+import org.dromara.complaintBox.domain.BusComplaintBoxMessageLogging;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 意见箱-意见沟通记录视图对象 bus_complaint_box_message_logging
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = BusComplaintBoxMessageLogging.class)
+public class BusComplaintBoxMessageLoggingVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键ID
+ */
+ @ExcelProperty(value = "主键ID")
+ private Long id;
+
+ /**
+ * 意见id
+ */
+ @ExcelProperty(value = "意见id")
+ private Long complaintId;
+
+ /**
+ * 回复用户id
+ */
+ private Long replyUserId;
+
+ /**
+ * 回复用户名
+ */
+ private String replyUserName;
+
+ /**
+ * 回复用户头像地址
+ */
+ private Long replyAvatar;
+ private String replyAvatarUrl;
+
+ /**
+ * 被回复用户id
+ */
+ private Long repliedUserId;
+
+ /**
+ * 被回复用户名
+ */
+ private String repliedUserName;
+
+ /**
+ * 被回复用户头像地址
+ */
+ private Long repliedAvatar;
+ private String repliedAvatarUrl;
+
+ /**
+ * 消息内容
+ */
+ @ExcelProperty(value = "消息内容")
+ private String details;
+
+ /**
+ * 处理状态(0、未读,1、已读)
+ */
+ @ExcelProperty(value = "处理状态", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "0=、未读,1、已读")
+ private String status;
+
+ /**
+ * 发起人类型(0、发起人,1、处理人)
+ */
+ private Integer type;
+
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/BusComplaintBoxVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/BusComplaintBoxVo.java
new file mode 100644
index 00000000..a344d742
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/BusComplaintBoxVo.java
@@ -0,0 +1,125 @@
+package org.dromara.complaintBox.domain.vo;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import org.dromara.complaintBox.domain.BusComplaintBox;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 意见箱视图对象 bus_complaint_box
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = BusComplaintBox.class)
+public class BusComplaintBoxVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 主键ID
+ */
+ @ExcelProperty(value = "主键ID")
+ private Long id;
+
+ /**
+ * 公司id(当前登录人的顶层下一级部门id)
+ */
+ @ExcelProperty(value = "公司id", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "当=前登录人的顶层下一级部门id")
+ private Long companyId;
+
+ /**
+ * 项目id
+ */
+ @ExcelProperty(value = "项目id")
+ private Long projectId;
+
+ /**
+ * 用户id
+ */
+ @ExcelProperty(value = "用户id")
+ private Long userId;
+
+ /**
+ * 用户名
+ */
+ @ExcelProperty(value = "用户名")
+ private String userName;
+
+ /**
+ * 头像地址
+ */
+ @ExcelProperty(value = "头像地址")
+ private Long avatar;
+ private String avatarUrl;
+
+ /**
+ * 标题
+ */
+ @ExcelProperty(value = "标题")
+ private String title;
+
+ /**
+ * 意见类型(1、功能建议,2、Bug反馈,3、体验问题,4其他意见)
+ */
+ @ExcelProperty(value = "意见类型", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "1=、功能建议,2、Bug反馈,3、体验问题,4其他意见")
+ private String opinionType;
+
+ /**
+ * 详细描述
+ */
+ @ExcelProperty(value = "详细描述")
+ private String detail;
+
+ /**
+ * 上传图片(id,id之间使用','分割)
+ */
+ @ExcelProperty(value = "上传图片", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "i=d,id之间使用','分割")
+ private String fileId;
+ private List fileUrls;
+
+ /**
+ * 是否匿名提交(0、否,1、是)
+ */
+ @ExcelProperty(value = "是否匿名提交", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "0=、否,1、是")
+ private String isCryptonym;
+
+ /**
+ * 处理状态(0、待处理,5、处理中,9、已解决,14、关闭)
+ */
+ @ExcelProperty(value = "处理状态", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "0=、待处理,5、处理中,9、已解决,14、关闭")
+ private String status;
+
+ /**
+ * 当前处理人id
+ */
+ private Long currentDisposeUserId;
+
+ private Integer count;
+
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/ComplaintBoxCountVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/ComplaintBoxCountVo.java
new file mode 100644
index 00000000..646e0b70
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/ComplaintBoxCountVo.java
@@ -0,0 +1,18 @@
+package org.dromara.complaintBox.domain.vo;
+
+import lombok.Data;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+
+import java.io.Serializable;
+
+@Data
+public class ComplaintBoxCountVo implements Serializable {
+
+ private String type;
+
+// @Translation(type = TransConstant.DICT_TYPE_TO_LABEL, mapper = "type",other = "opinion_processing_status")
+ private String typeName;
+
+ private Integer count;
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/DetailsOfTheOpinionVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/DetailsOfTheOpinionVo.java
new file mode 100644
index 00000000..d5e2bc22
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/domain/vo/DetailsOfTheOpinionVo.java
@@ -0,0 +1,14 @@
+package org.dromara.complaintBox.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class DetailsOfTheOpinionVo implements Serializable {
+
+ private BusComplaintBoxVo busComplaintBoxVo;
+
+ private List messageLoggingVos;
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/mapper/BusComplaintBoxDisposeLoggingMapper.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/mapper/BusComplaintBoxDisposeLoggingMapper.java
new file mode 100644
index 00000000..833d26fb
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/mapper/BusComplaintBoxDisposeLoggingMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.complaintBox.mapper;
+
+import org.dromara.complaintBox.domain.BusComplaintBoxDisposeLogging;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxDisposeLoggingVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 意见箱-意见处理记录Mapper接口
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+public interface BusComplaintBoxDisposeLoggingMapper extends BaseMapperPlus {
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/mapper/BusComplaintBoxMapper.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/mapper/BusComplaintBoxMapper.java
new file mode 100644
index 00000000..03ba0d72
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/mapper/BusComplaintBoxMapper.java
@@ -0,0 +1,26 @@
+package org.dromara.complaintBox.mapper;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.complaintBox.domain.BusComplaintBox;
+import org.dromara.complaintBox.domain.bo.BusComplaintBoxBo;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.complaintBox.domain.vo.ComplaintBoxCountVo;
+
+import java.util.List;
+
+/**
+ * 意见箱Mapper接口
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+public interface BusComplaintBoxMapper extends BaseMapperPlus {
+
+ Page selectVoPageList(@Param("page") Page page, @Param("bo") BusComplaintBoxBo bo);
+
+ Page selectVoPageWebList(@Param("page") Page page, @Param("bo") BusComplaintBoxBo bo);
+
+ List getCount(@Param("bo") BusComplaintBoxBo bo);
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/mapper/BusComplaintBoxMessageLoggingMapper.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/mapper/BusComplaintBoxMessageLoggingMapper.java
new file mode 100644
index 00000000..744f6045
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/mapper/BusComplaintBoxMessageLoggingMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.complaintBox.mapper;
+
+import org.dromara.complaintBox.domain.BusComplaintBoxMessageLogging;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxMessageLoggingVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 意见箱-意见沟通记录Mapper接口
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+public interface BusComplaintBoxMessageLoggingMapper extends BaseMapperPlus {
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/IBusComplaintBoxDisposeLoggingService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/IBusComplaintBoxDisposeLoggingService.java
new file mode 100644
index 00000000..dcfbfb32
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/IBusComplaintBoxDisposeLoggingService.java
@@ -0,0 +1,70 @@
+package org.dromara.complaintBox.service;
+
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxDisposeLoggingVo;
+import org.dromara.complaintBox.domain.bo.BusComplaintBoxDisposeLoggingBo;
+import org.dromara.complaintBox.domain.BusComplaintBoxDisposeLogging;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 意见箱-意见处理记录Service接口
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+public interface IBusComplaintBoxDisposeLoggingService extends IService{
+
+ /**
+ * 查询意见箱-意见处理记录
+ *
+ * @param id 主键
+ * @return 意见箱-意见处理记录
+ */
+ BusComplaintBoxDisposeLoggingVo queryById(Long id);
+
+ /**
+ * 分页查询意见箱-意见处理记录列表
+ *
+ * @param bo 查询条件
+ * @param pageQuery 分页参数
+ * @return 意见箱-意见处理记录分页列表
+ */
+ TableDataInfo queryPageList(BusComplaintBoxDisposeLoggingBo bo, PageQuery pageQuery);
+
+ /**
+ * 查询符合条件的意见箱-意见处理记录列表
+ *
+ * @param bo 查询条件
+ * @return 意见箱-意见处理记录列表
+ */
+ List queryList(BusComplaintBoxDisposeLoggingBo bo);
+
+ /**
+ * 新增意见箱-意见处理记录
+ *
+ * @param bo 意见箱-意见处理记录
+ * @return 是否新增成功
+ */
+ Boolean insertByBo(BusComplaintBoxDisposeLoggingBo bo);
+
+ /**
+ * 修改意见箱-意见处理记录
+ *
+ * @param bo 意见箱-意见处理记录
+ * @return 是否修改成功
+ */
+ Boolean updateByBo(BusComplaintBoxDisposeLoggingBo bo);
+
+ /**
+ * 校验并批量删除意见箱-意见处理记录信息
+ *
+ * @param ids 待删除的主键集合
+ * @param isValid 是否进行有效性校验
+ * @return 是否删除成功
+ */
+ Boolean deleteWithValidByIds(Collection ids, Boolean isValid);
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/IBusComplaintBoxMessageLoggingService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/IBusComplaintBoxMessageLoggingService.java
new file mode 100644
index 00000000..5bd0169a
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/IBusComplaintBoxMessageLoggingService.java
@@ -0,0 +1,84 @@
+package org.dromara.complaintBox.service;
+
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxMessageLoggingVo;
+import org.dromara.complaintBox.domain.bo.BusComplaintBoxMessageLoggingBo;
+import org.dromara.complaintBox.domain.BusComplaintBoxMessageLogging;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 意见箱-意见沟通记录Service接口
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+public interface IBusComplaintBoxMessageLoggingService extends IService{
+
+ /**
+ * 查询意见箱-意见沟通记录
+ *
+ * @param id 主键
+ * @return 意见箱-意见沟通记录
+ */
+ BusComplaintBoxMessageLoggingVo queryById(Long id);
+
+ /**
+ * 分页查询意见箱-意见沟通记录列表
+ *
+ * @param bo 查询条件
+ * @param pageQuery 分页参数
+ * @return 意见箱-意见沟通记录分页列表
+ */
+ TableDataInfo queryPageList(BusComplaintBoxMessageLoggingBo bo, PageQuery pageQuery);
+
+ /**
+ * 查询符合条件的意见箱-意见沟通记录列表
+ *
+ * @param bo 查询条件
+ * @return 意见箱-意见沟通记录列表
+ */
+ List queryList(BusComplaintBoxMessageLoggingBo bo);
+
+ /**
+ * 新增意见箱-意见沟通记录
+ *
+ * @param bo 意见箱-意见沟通记录
+ * @return 是否新增成功
+ */
+ Boolean insertAppByBo(BusComplaintBoxMessageLoggingBo bo);
+ /**
+ * 新增意见箱-意见沟通记录
+ *
+ * @param bo 意见箱-意见沟通记录
+ * @return 是否新增成功
+ */
+ Boolean insertWebByBo(BusComplaintBoxMessageLoggingBo bo);
+
+ /**
+ * 修改意见箱-意见沟通记录
+ *
+ * @param bo 意见箱-意见沟通记录
+ * @return 是否修改成功
+ */
+ Boolean updateByBo(BusComplaintBoxMessageLoggingBo bo);
+
+ /**
+ * 校验并批量删除意见箱-意见沟通记录信息
+ *
+ * @param ids 待删除的主键集合
+ * @param isValid 是否进行有效性校验
+ * @return 是否删除成功
+ */
+ Boolean deleteWithValidByIds(Collection ids, Boolean isValid);
+
+ /**
+ * 通过意见id获取沟通记录
+ * @param id
+ * @return
+ */
+ List getMessageLogListByComplaintId(Long id);
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/IBusComplaintBoxService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/IBusComplaintBoxService.java
new file mode 100644
index 00000000..8400a950
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/IBusComplaintBoxService.java
@@ -0,0 +1,117 @@
+package org.dromara.complaintBox.service;
+
+import org.dromara.complaintBox.app.domain.vo.AppDetailsOfTheOpinionVo;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxVo;
+import org.dromara.complaintBox.domain.bo.BusComplaintBoxBo;
+import org.dromara.complaintBox.domain.BusComplaintBox;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.dromara.complaintBox.domain.vo.ComplaintBoxCountVo;
+import org.dromara.complaintBox.domain.vo.DetailsOfTheOpinionVo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 意见箱Service接口
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+public interface IBusComplaintBoxService extends IService{
+
+ /**
+ * 查询意见箱
+ *
+ * @param id 主键
+ * @return 意见箱
+ */
+ BusComplaintBoxVo queryById(Long id);
+
+ /**
+ * 分页查询意见箱列表
+ *
+ * @param bo 查询条件
+ * @param pageQuery 分页参数
+ * @return 意见箱分页列表
+ */
+ TableDataInfo queryPageList(BusComplaintBoxBo bo, PageQuery pageQuery);
+
+ /**
+ * 查询符合条件的意见箱列表
+ *
+ * @param bo 查询条件
+ * @return 意见箱列表
+ */
+ List queryList(BusComplaintBoxBo bo);
+
+ /**
+ * 新增意见箱
+ *
+ * @param bo 意见箱
+ * @return 是否新增成功
+ */
+ Boolean insertByBo(BusComplaintBoxBo bo);
+
+ /**
+ * 修改意见箱
+ *
+ * @param bo 意见箱
+ * @return 是否修改成功
+ */
+ Boolean updateByBo(BusComplaintBoxBo bo);
+
+ /**
+ * 校验并批量删除意见箱信息
+ *
+ * @param ids 待删除的主键集合
+ * @param isValid 是否进行有效性校验
+ * @return 是否删除成功
+ */
+ Boolean deleteWithValidByIds(Collection ids, Boolean isValid);
+
+ /**
+ * app获取当前用户提出意见列表
+ * @param bo
+ * @param pageQuery
+ * @return
+ */
+ TableDataInfo appQueryPageList(BusComplaintBoxBo bo, PageQuery pageQuery);
+
+ /**
+ * APP获取当前意见详情
+ * @param id
+ * @return
+ */
+ AppDetailsOfTheOpinionVo appQueryById(Long id);
+
+ /**
+ * 获取当前意见详情
+ * @param id
+ * @return
+ */
+ DetailsOfTheOpinionVo getInfo(Long id);
+
+ /**
+ * 修改沟通记录阅读状态
+ * @param bo
+ * @return
+ */
+ int editCheckStatus(BusComplaintBoxBo bo);
+
+ /**
+ * web获取各个处理状态数量
+ * @param bo
+ * @return
+ */
+ List getCount(BusComplaintBoxBo bo);
+
+ /**
+ * 修改意见状态
+ * @param bo
+ * @return
+ */
+ int editStatus(BusComplaintBoxBo bo);
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/impl/BusComplaintBoxDisposeLoggingServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/impl/BusComplaintBoxDisposeLoggingServiceImpl.java
new file mode 100644
index 00000000..5bd6fa4a
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/impl/BusComplaintBoxDisposeLoggingServiceImpl.java
@@ -0,0 +1,134 @@
+package org.dromara.complaintBox.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.dromara.complaintBox.domain.bo.BusComplaintBoxDisposeLoggingBo;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxDisposeLoggingVo;
+import org.dromara.complaintBox.domain.BusComplaintBoxDisposeLogging;
+import org.dromara.complaintBox.mapper.BusComplaintBoxDisposeLoggingMapper;
+import org.dromara.complaintBox.service.IBusComplaintBoxDisposeLoggingService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 意见箱-意见处理记录Service业务层处理
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@RequiredArgsConstructor
+@Service
+public class BusComplaintBoxDisposeLoggingServiceImpl extends ServiceImpl implements IBusComplaintBoxDisposeLoggingService {
+
+ private final BusComplaintBoxDisposeLoggingMapper baseMapper;
+
+ /**
+ * 查询意见箱-意见处理记录
+ *
+ * @param id 主键
+ * @return 意见箱-意见处理记录
+ */
+ @Override
+ public BusComplaintBoxDisposeLoggingVo queryById(Long id){
+ return baseMapper.selectVoById(id);
+ }
+
+ /**
+ * 分页查询意见箱-意见处理记录列表
+ *
+ * @param bo 查询条件
+ * @param pageQuery 分页参数
+ * @return 意见箱-意见处理记录分页列表
+ */
+ @Override
+ public TableDataInfo queryPageList(BusComplaintBoxDisposeLoggingBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper lqw = buildQueryWrapper(bo);
+ Page result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(result);
+ }
+
+ /**
+ * 查询符合条件的意见箱-意见处理记录列表
+ *
+ * @param bo 查询条件
+ * @return 意见箱-意见处理记录列表
+ */
+ @Override
+ public List queryList(BusComplaintBoxDisposeLoggingBo bo) {
+ LambdaQueryWrapper lqw = buildQueryWrapper(bo);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper buildQueryWrapper(BusComplaintBoxDisposeLoggingBo bo) {
+ Map params = bo.getParams();
+ LambdaQueryWrapper lqw = Wrappers.lambdaQuery();
+ lqw.orderByDesc(BusComplaintBoxDisposeLogging::getCreateTime);
+ lqw.eq(bo.getComplaintId() != null, BusComplaintBoxDisposeLogging::getComplaintId, bo.getComplaintId());
+ lqw.eq(bo.getUserId() != null, BusComplaintBoxDisposeLogging::getUserId, bo.getUserId());
+ lqw.like(StringUtils.isNotBlank(bo.getUserName()), BusComplaintBoxDisposeLogging::getUserName, bo.getUserName());
+ lqw.eq(StringUtils.isNotBlank(bo.getIsRefund()), BusComplaintBoxDisposeLogging::getIsRefund, bo.getIsRefund());
+ return lqw;
+ }
+
+ /**
+ * 新增意见箱-意见处理记录
+ *
+ * @param bo 意见箱-意见处理记录
+ * @return 是否新增成功
+ */
+ @Override
+ public Boolean insertByBo(BusComplaintBoxDisposeLoggingBo bo) {
+ BusComplaintBoxDisposeLogging add = MapstructUtils.convert(bo, BusComplaintBoxDisposeLogging.class);
+ validEntityBeforeSave(add);
+ boolean flag = baseMapper.insert(add) > 0;
+ if (flag) {
+ bo.setId(add.getId());
+ }
+ return flag;
+ }
+
+ /**
+ * 修改意见箱-意见处理记录
+ *
+ * @param bo 意见箱-意见处理记录
+ * @return 是否修改成功
+ */
+ @Override
+ public Boolean updateByBo(BusComplaintBoxDisposeLoggingBo bo) {
+ BusComplaintBoxDisposeLogging update = MapstructUtils.convert(bo, BusComplaintBoxDisposeLogging.class);
+ validEntityBeforeSave(update);
+ return baseMapper.updateById(update) > 0;
+ }
+
+ /**
+ * 保存前的数据校验
+ */
+ private void validEntityBeforeSave(BusComplaintBoxDisposeLogging entity){
+ //TODO 做一些数据校验,如唯一约束
+ }
+
+ /**
+ * 校验并批量删除意见箱-意见处理记录信息
+ *
+ * @param ids 待删除的主键集合
+ * @param isValid 是否进行有效性校验
+ * @return 是否删除成功
+ */
+ @Override
+ public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) {
+ if(isValid){
+ //TODO 做一些业务上的校验,判断是否需要校验
+ }
+ return baseMapper.deleteByIds(ids) > 0;
+ }
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/impl/BusComplaintBoxMessageLoggingServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/impl/BusComplaintBoxMessageLoggingServiceImpl.java
new file mode 100644
index 00000000..8055cc0c
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/impl/BusComplaintBoxMessageLoggingServiceImpl.java
@@ -0,0 +1,223 @@
+package org.dromara.complaintBox.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.complaintBox.domain.BusComplaintBox;
+import org.dromara.complaintBox.mapper.BusComplaintBoxMapper;
+import org.dromara.complaintBox.service.IBusComplaintBoxService;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.service.ISysUserService;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+import org.dromara.complaintBox.domain.bo.BusComplaintBoxMessageLoggingBo;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxMessageLoggingVo;
+import org.dromara.complaintBox.domain.BusComplaintBoxMessageLogging;
+import org.dromara.complaintBox.mapper.BusComplaintBoxMessageLoggingMapper;
+import org.dromara.complaintBox.service.IBusComplaintBoxMessageLoggingService;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 意见箱-意见沟通记录Service业务层处理
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@RequiredArgsConstructor
+@Service
+public class BusComplaintBoxMessageLoggingServiceImpl extends ServiceImpl implements IBusComplaintBoxMessageLoggingService {
+
+ private final BusComplaintBoxMessageLoggingMapper baseMapper;
+ @Lazy
+ private final ISysUserService sysUserService;
+// @Lazy
+ private final BusComplaintBoxMapper busComplaintBoxMapper;
+
+ /**
+ * 查询意见箱-意见沟通记录
+ *
+ * @param id 主键
+ * @return 意见箱-意见沟通记录
+ */
+ @Override
+ public BusComplaintBoxMessageLoggingVo queryById(Long id){
+ return baseMapper.selectVoById(id);
+ }
+
+ /**
+ * 分页查询意见箱-意见沟通记录列表
+ *
+ * @param bo 查询条件
+ * @param pageQuery 分页参数
+ * @return 意见箱-意见沟通记录分页列表
+ */
+ @Override
+ public TableDataInfo queryPageList(BusComplaintBoxMessageLoggingBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper lqw = buildQueryWrapper(bo);
+ Page result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(result);
+ }
+
+ /**
+ * 查询符合条件的意见箱-意见沟通记录列表
+ *
+ * @param bo 查询条件
+ * @return 意见箱-意见沟通记录列表
+ */
+ @Override
+ public List queryList(BusComplaintBoxMessageLoggingBo bo) {
+ LambdaQueryWrapper lqw = buildQueryWrapper(bo);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper buildQueryWrapper(BusComplaintBoxMessageLoggingBo bo) {
+ Map params = bo.getParams();
+ LambdaQueryWrapper lqw = Wrappers.lambdaQuery();
+ lqw.orderByDesc(BusComplaintBoxMessageLogging::getId);
+ lqw.eq(bo.getComplaintId() != null, BusComplaintBoxMessageLogging::getComplaintId, bo.getComplaintId());
+ lqw.eq(StringUtils.isNotBlank(bo.getDetails()), BusComplaintBoxMessageLogging::getDetails, bo.getDetails());
+ lqw.eq(StringUtils.isNotBlank(bo.getStatus()), BusComplaintBoxMessageLogging::getStatus, bo.getStatus());
+ return lqw;
+ }
+
+ /**
+ * 新增意见箱-意见沟通记录
+ *
+ * @param bo 意见箱-意见沟通记录
+ * @return 是否新增成功
+ */
+ @Override
+ public Boolean insertAppByBo(BusComplaintBoxMessageLoggingBo bo) {
+ LoginUser loginUser = LoginHelper.getLoginUser();
+ if (loginUser == null) {
+ throw new ServiceException("登录信息出错,请重新登录!!!");
+ }
+ BusComplaintBox busComplaintBox = busComplaintBoxMapper.selectById(bo.getComplaintId());
+ if (busComplaintBox == null) {
+ throw new ServiceException("意见信息找不到!!!");
+ }
+ if ("14".equals(busComplaintBox.getStatus()) || "9".equals(busComplaintBox.getStatus())) {
+ throw new ServiceException("意见已关闭!!!");
+ }
+ SysUserVo sysUserVo = sysUserService.selectUserById(loginUser.getUserId());
+ bo.setReplyUserId(sysUserVo.getUserId());
+ bo.setReplyUserName(sysUserVo.getNickName());
+ bo.setReplyAvatar(sysUserVo.getAvatar());
+ BusComplaintBoxMessageLogging add = MapstructUtils.convert(bo, BusComplaintBoxMessageLogging.class);
+ if (busComplaintBox.getCurrentDisposeUserId() != null) {
+ SysUserVo userVo = sysUserService.selectUserById(busComplaintBox.getCurrentDisposeUserId());
+ if (userVo != null) {
+ add.setRepliedUserId(userVo.getUserId());
+ add.setRepliedUserName(userVo.getUserName());
+ add.setRepliedAvatar(userVo.getAvatar());
+ }
+ }
+
+ validEntityBeforeSave(add);
+ boolean flag = baseMapper.insert(add) > 0;
+ if (flag) {
+ bo.setId(add.getId());
+ }
+ return flag;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean insertWebByBo(BusComplaintBoxMessageLoggingBo bo) {
+ LoginUser loginUser = LoginHelper.getLoginUser();
+ if (loginUser == null) {
+ throw new ServiceException("登录信息出错,请重新登录!!!");
+ }
+ BusComplaintBox busComplaintBox = busComplaintBoxMapper.selectById(bo.getComplaintId());
+ if (busComplaintBox == null) {
+ throw new ServiceException("意见信息找不到!!!");
+ }
+ if (busComplaintBox.getCurrentDisposeUserId()!= null && !loginUser.getUserId().equals(busComplaintBox.getCurrentDisposeUserId())) {
+ throw new ServiceException("处理人异常");
+ }
+ if ("0".equals(busComplaintBox.getStatus())){
+ throw new ServiceException("意见未处理,不能发布信息");
+ }
+ if ("14".equals(busComplaintBox.getStatus()) || "9".equals(busComplaintBox.getStatus())) {
+ throw new ServiceException("意见已关闭!!!");
+ }
+ SysUserVo sysUserVo = sysUserService.selectUserById(loginUser.getUserId());
+ bo.setReplyUserId(sysUserVo.getUserId());
+ bo.setReplyUserName(sysUserVo.getNickName());
+ bo.setReplyAvatar(sysUserVo.getAvatar());
+ BusComplaintBoxMessageLogging add = MapstructUtils.convert(bo, BusComplaintBoxMessageLogging.class);
+ add.setRepliedUserId(busComplaintBox.getUserId());
+ add.setRepliedUserName(busComplaintBox.getUserName());
+ add.setRepliedAvatar(busComplaintBox.getAvatar());
+
+ validEntityBeforeSave(add);
+ boolean flag = baseMapper.insert(add) > 0;
+// if ("0".equals(busComplaintBox.getStatus())){
+// busComplaintBox.setStatus("5");
+// busComplaintBox.setCurrentDisposeUserId(sysUserVo.getUserId());
+// busComplaintBoxMapper.updateById(busComplaintBox);
+// }
+ if (flag) {
+ bo.setId(add.getId());
+ }
+ return flag;
+ }
+
+ /**
+ * 修改意见箱-意见沟通记录
+ *
+ * @param bo 意见箱-意见沟通记录
+ * @return 是否修改成功
+ */
+ @Override
+ public Boolean updateByBo(BusComplaintBoxMessageLoggingBo bo) {
+ BusComplaintBoxMessageLogging update = MapstructUtils.convert(bo, BusComplaintBoxMessageLogging.class);
+ validEntityBeforeSave(update);
+ return baseMapper.updateById(update) > 0;
+ }
+
+ /**
+ * 保存前的数据校验
+ */
+ private void validEntityBeforeSave(BusComplaintBoxMessageLogging entity){
+ //TODO 做一些数据校验,如唯一约束
+ }
+
+ /**
+ * 校验并批量删除意见箱-意见沟通记录信息
+ *
+ * @param ids 待删除的主键集合
+ * @param isValid 是否进行有效性校验
+ * @return 是否删除成功
+ */
+ @Override
+ public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) {
+ if(isValid){
+ //TODO 做一些业务上的校验,判断是否需要校验
+ }
+ return baseMapper.deleteByIds(ids) > 0;
+ }
+
+ /**
+ * 根据意见id获取沟通记录
+ * @param id
+ * @return
+ */
+ @Override
+ public List getMessageLogListByComplaintId(Long id) {
+ return baseMapper.selectVoList(new LambdaQueryWrapper().eq(BusComplaintBoxMessageLogging::getComplaintId, id));
+ }
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/impl/BusComplaintBoxServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/impl/BusComplaintBoxServiceImpl.java
new file mode 100644
index 00000000..f4a0df4a
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/complaintBox/service/impl/BusComplaintBoxServiceImpl.java
@@ -0,0 +1,380 @@
+package org.dromara.complaintBox.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.annotation.Resource;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.complaintBox.app.domain.vo.AppDetailsOfTheOpinionVo;
+import org.dromara.complaintBox.domain.BusComplaintBoxDisposeLogging;
+import org.dromara.complaintBox.domain.BusComplaintBoxMessageLogging;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxMessageLoggingVo;
+import org.dromara.complaintBox.domain.vo.ComplaintBoxCountVo;
+import org.dromara.complaintBox.domain.vo.DetailsOfTheOpinionVo;
+import org.dromara.complaintBox.mapper.BusComplaintBoxMessageLoggingMapper;
+import org.dromara.complaintBox.service.IBusComplaintBoxDisposeLoggingService;
+import org.dromara.complaintBox.service.IBusComplaintBoxMessageLoggingService;
+import org.dromara.system.domain.vo.SysDeptVo;
+import org.dromara.system.domain.vo.SysOssVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.service.ISysDeptService;
+import org.dromara.system.service.ISysOssService;
+import org.dromara.system.service.ISysUserService;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+import org.dromara.complaintBox.domain.bo.BusComplaintBoxBo;
+import org.dromara.complaintBox.domain.vo.BusComplaintBoxVo;
+import org.dromara.complaintBox.domain.BusComplaintBox;
+import org.dromara.complaintBox.mapper.BusComplaintBoxMapper;
+import org.dromara.complaintBox.service.IBusComplaintBoxService;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 意见箱Service业务层处理
+ *
+ * @author Lion Li
+ * @date 2025-11-29
+ */
+@RequiredArgsConstructor
+@Service
+public class BusComplaintBoxServiceImpl extends ServiceImpl implements IBusComplaintBoxService {
+
+ private final BusComplaintBoxMapper baseMapper;
+// @Lazy
+ private final BusComplaintBoxMessageLoggingMapper messageLoggingMapper;
+ @Lazy
+ @Resource
+ private ISysUserService sysUserService;
+ @Lazy
+ @Resource
+ private ISysDeptService sysDeptService;
+ @Lazy
+ @Resource
+ private ISysOssService sysOssService;
+ @Lazy
+ @Resource
+ private IBusComplaintBoxDisposeLoggingService disposeLoggingService;
+
+ /**
+ * 查询意见箱
+ *
+ * @param id 主键
+ * @return 意见箱
+ */
+ @Override
+ public BusComplaintBoxVo queryById(Long id){
+ return baseMapper.selectVoById(id);
+ }
+
+ /**
+ * 分页查询意见箱列表
+ *
+ * @param bo 查询条件
+ * @param pageQuery 分页参数
+ * @return 意见箱分页列表
+ */
+ @Override
+ public TableDataInfo queryPageList(BusComplaintBoxBo bo, PageQuery pageQuery) {
+ Page result = baseMapper.selectVoPageWebList(pageQuery.build(), bo);
+ return TableDataInfo.build(result);
+ }
+
+ /**
+ * 查询符合条件的意见箱列表
+ *
+ * @param bo 查询条件
+ * @return 意见箱列表
+ */
+ @Override
+ public List queryList(BusComplaintBoxBo bo) {
+ LambdaQueryWrapper lqw = buildQueryWrapper(bo);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper buildQueryWrapper(BusComplaintBoxBo bo) {
+ Map params = bo.getParams();
+ LambdaQueryWrapper lqw = Wrappers.lambdaQuery();
+ lqw.orderByDesc(BusComplaintBox::getId);
+ lqw.eq(bo.getCompanyId() != null, BusComplaintBox::getCompanyId, bo.getCompanyId());
+ lqw.eq(bo.getProjectId() != null, BusComplaintBox::getProjectId, bo.getProjectId());
+ lqw.eq(bo.getUserId() != null, BusComplaintBox::getUserId, bo.getUserId());
+ lqw.eq(bo.getCurrentDisposeUserId() != null,
+ BusComplaintBox::getCurrentDisposeUserId, bo.getCurrentDisposeUserId())
+ .or()
+ .isNull(BusComplaintBox::getCurrentDisposeUserId);
+ lqw.eq(StringUtils.isNotBlank(bo.getTitle()), BusComplaintBox::getTitle, bo.getTitle());
+ lqw.eq(StringUtils.isNotBlank(bo.getOpinionType()), BusComplaintBox::getOpinionType, bo.getOpinionType());
+ lqw.eq(StringUtils.isNotBlank(bo.getDetail()), BusComplaintBox::getDetail, bo.getDetail());
+ lqw.eq(StringUtils.isNotBlank(bo.getFileId()), BusComplaintBox::getFileId, bo.getFileId());
+ lqw.eq(StringUtils.isNotBlank(bo.getIsCryptonym()), BusComplaintBox::getIsCryptonym, bo.getIsCryptonym());
+ lqw.eq(StringUtils.isNotBlank(bo.getStatus()), BusComplaintBox::getStatus, bo.getStatus());
+ return lqw;
+ }
+
+ /**
+ * 新增意见箱
+ *
+ * @param bo 意见箱
+ * @return 是否新增成功
+ */
+ @Override
+ public Boolean insertByBo(BusComplaintBoxBo bo) {
+ BusComplaintBox add = MapstructUtils.convert(bo, BusComplaintBox.class);
+ //获取用户信息进行填充
+ SysUserVo sysUserVo = sysUserService.selectUserById(add.getUserId());
+ add.setAvatar(sysUserVo.getAvatar());
+ add.setUserName(sysUserVo.getNickName());
+ //获取部门信息
+ SysDeptVo sysDeptVo =sysDeptService.selectDeptById(sysUserVo.getDeptId());
+ if (sysDeptVo != null) {
+ String[] split = sysDeptVo.getAncestors().split(",");
+ if (split.length > 0) {
+ //当祖级列表长度大于3时取第2个作为公司id
+ if (split.length > 1) {
+ add.setCompanyId(Long.parseLong(split[1]));
+ }else {
+ add.setCompanyId(Long.parseLong(split[0]));
+ }
+ }
+ }
+ validEntityBeforeSave(add);
+ boolean flag = baseMapper.insert(add) > 0;
+ if (flag) {
+ bo.setId(add.getId());
+ }
+ return flag;
+ }
+
+ /**
+ * 修改意见箱
+ *
+ * @param bo 意见箱
+ * @return 是否修改成功
+ */
+ @Override
+ public Boolean updateByBo(BusComplaintBoxBo bo) {
+ BusComplaintBox update = MapstructUtils.convert(bo, BusComplaintBox.class);
+ validEntityBeforeSave(update);
+ return baseMapper.updateById(update) > 0;
+ }
+
+ /**
+ * 保存前的数据校验
+ */
+ private void validEntityBeforeSave(BusComplaintBox entity){
+ //TODO 做一些数据校验,如唯一约束
+ }
+
+ /**
+ * 校验并批量删除意见箱信息
+ *
+ * @param ids 待删除的主键集合
+ * @param isValid 是否进行有效性校验
+ * @return 是否删除成功
+ */
+ @Override
+ public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) {
+ if(isValid){
+ //TODO 做一些业务上的校验,判断是否需要校验
+ }
+ return baseMapper.deleteByIds(ids) > 0;
+ }
+
+ /**
+ * app获取当前用户提出意见列表
+ * @param bo
+ * @param pageQuery
+ * @return
+ */
+ @Override
+ public TableDataInfo appQueryPageList(BusComplaintBoxBo bo, PageQuery pageQuery) {
+ Page result = baseMapper.selectVoPageList(pageQuery.build(), bo);
+ return TableDataInfo.build(result);
+ }
+
+ /**
+ * app获取当前意见详情
+ * @param id
+ * @return
+ */
+ @Override
+ public AppDetailsOfTheOpinionVo appQueryById(Long id) {
+ AppDetailsOfTheOpinionVo vo = new AppDetailsOfTheOpinionVo();
+ BusComplaintBoxVo busComplaintBoxVo = baseMapper.selectVoById(id);
+ if(busComplaintBoxVo == null){
+ throw new ServiceException("找不到意见信息!!!");
+ }
+ if (busComplaintBoxVo.getAvatar() != null){
+ SysOssVo ossVo = sysOssService.getById(busComplaintBoxVo.getAvatar());
+ if (ossVo != null){
+ busComplaintBoxVo.setAvatarUrl(ossVo.getUrl());
+ }
+ }
+ if (busComplaintBoxVo.getFileId() != null){
+ String[] split = busComplaintBoxVo.getFileId().split(",");
+ List fileIds = Arrays.stream(split)
+ .filter(str -> str != null && !str.trim().isEmpty()) // 过滤空值和空白字符串
+ .map(str -> {
+ try {
+ return Long.valueOf(str.trim());
+ } catch (NumberFormatException e) {
+ // 转换失败时可返回null,后续再过滤
+ return null;
+ }
+ })
+ .filter(Objects::nonNull) // 过滤转换失败的null值
+ .toList();
+ List sysOssVos = sysOssService.listByIds(fileIds);
+ List urls = new ArrayList<>();
+ sysOssVos.forEach(sysOssVo -> {
+ if (sysOssVo != null){
+ urls.add(sysOssVo.getUrl());
+ }
+ });
+ busComplaintBoxVo.setFileUrls(urls);
+ }
+ vo.setBusComplaintBoxVo(busComplaintBoxVo);
+ List messageLoggingVos = messageLoggingMapper.selectVoList(new LambdaQueryWrapper().eq(BusComplaintBoxMessageLogging::getComplaintId, id));
+ if(CollectionUtils.isNotEmpty(messageLoggingVos)){
+ messageLoggingVos.forEach(mvo->{
+ if (mvo.getReplyAvatar() != null){
+ SysOssVo ossVo = sysOssService.getById(mvo.getReplyAvatar());
+ if (ossVo != null){
+ mvo.setReplyAvatarUrl(ossVo.getUrl());
+ }
+ }
+ if (mvo.getRepliedAvatar() != null){
+ SysOssVo ossVo = sysOssService.getById(mvo.getRepliedAvatar());
+ if (ossVo != null){
+ mvo.setRepliedAvatarUrl(ossVo.getUrl());
+ }
+ }
+ });
+ vo.setMessageLoggingVos(messageLoggingVos);
+ }
+ return vo;
+ }
+
+ @Override
+ public DetailsOfTheOpinionVo getInfo(Long id) {
+ DetailsOfTheOpinionVo vo = new DetailsOfTheOpinionVo();
+ BusComplaintBoxVo busComplaintBoxVo = baseMapper.selectVoById(id);
+ if(busComplaintBoxVo == null){
+ throw new ServiceException("找不到意见信息!!!");
+ }
+ vo.setBusComplaintBoxVo(busComplaintBoxVo);
+ List messageLoggingVos = messageLoggingMapper.selectVoList(new LambdaQueryWrapper().eq(BusComplaintBoxMessageLogging::getComplaintId, id));
+ if(CollectionUtils.isNotEmpty(messageLoggingVos)){
+ messageLoggingVos.forEach(messageLoggingVo->{
+ messageLoggingVo.setType(messageLoggingVo.getReplyUserId().equals(busComplaintBoxVo.getUserId()) ? 0 : 1);
+ if (messageLoggingVo.getReplyAvatar() != null){
+ SysOssVo ossVo = sysOssService.getById(messageLoggingVo.getReplyAvatar());
+ if (ossVo != null){
+ messageLoggingVo.setReplyAvatarUrl(ossVo.getUrl());
+ }
+ }
+ if (messageLoggingVo.getRepliedAvatar() != null){
+ SysOssVo ossVo = sysOssService.getById(messageLoggingVo.getRepliedAvatar());
+ if (ossVo != null){
+ messageLoggingVo.setRepliedAvatarUrl(ossVo.getUrl());
+ }
+ }
+ });
+ vo.setMessageLoggingVos(messageLoggingVos);
+ }
+ return vo;
+
+ }
+
+
+
+ /**
+ * app修改沟通记录阅读状态
+ * @param bo
+ * @return
+ */
+ @Override
+ public int editCheckStatus(BusComplaintBoxBo bo) {
+ if (bo.getId() == null || bo.getUserId() == null) {
+ return 1;
+ }
+ Long count = messageLoggingMapper.selectCount(new LambdaQueryWrapper()
+ .eq(BusComplaintBoxMessageLogging::getStatus,"0")
+ .eq(BusComplaintBoxMessageLogging::getComplaintId, bo.getId())
+ .eq(BusComplaintBoxMessageLogging::getRepliedUserId, bo.getUserId()));
+ if (count == 0) {
+ return 1;
+ }
+ return messageLoggingMapper.update(new LambdaUpdateWrapper()
+ .set(BusComplaintBoxMessageLogging::getStatus,"1")
+ .eq(BusComplaintBoxMessageLogging::getComplaintId,bo.getId())
+ .eq(BusComplaintBoxMessageLogging::getRepliedUserId,bo.getUserId()));
+ }
+
+ @Override
+ public List getCount(BusComplaintBoxBo bo) {
+
+ return baseMapper.getCount(bo);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int editStatus(BusComplaintBoxBo bo) {
+ if (bo.getStatus() == null){
+ throw new ServiceException("意见状态不能为空");
+ }
+ BusComplaintBoxVo busComplaintBoxVo = baseMapper.selectVoById(bo.getId());
+ if (busComplaintBoxVo == null){
+ throw new ServiceException("找不到意见!!");
+ }
+ if ("14".equals(busComplaintBoxVo.getStatus())){
+ throw new ServiceException("该意见已经关闭,不允许再修改状态");
+ }
+ LambdaUpdateWrapper lqw = new LambdaUpdateWrapper();
+ lqw.set(BusComplaintBox::getStatus, bo.getStatus());
+ lqw.eq(BusComplaintBox::getId, bo.getId());
+ if ("5".equals(bo.getStatus())){
+ BusComplaintBoxDisposeLogging logging = new BusComplaintBoxDisposeLogging();
+ logging.setComplaintId(bo.getId());
+ LoginUser loginUser = LoginHelper.getLoginUser();
+ SysUserVo sysUserVo = sysUserService.selectUserById(loginUser.getUserId());
+ if (sysUserVo == null){
+ throw new ServiceException("找不到当前登录用户信息!");
+ }
+ lqw.set(BusComplaintBox::getCurrentDisposeUserId, loginUser.getUserId());
+ logging.setUserId(loginUser.getUserId());
+ logging.setUserName(sysUserVo.getNickName());
+ logging.setAvatar(sysUserVo.getAvatar());
+ disposeLoggingService.save(logging);
+ }
+ if ("0".equals(bo.getStatus())){
+ lqw.set(BusComplaintBox::getCurrentDisposeUserId, null);
+ BusComplaintBoxDisposeLogging logging = disposeLoggingService.getBaseMapper()
+ .selectOne(new LambdaQueryWrapper()
+ .eq(BusComplaintBoxDisposeLogging::getComplaintId, bo.getId())
+ .eq(BusComplaintBoxDisposeLogging::getUserId, busComplaintBoxVo.getCurrentDisposeUserId())
+ .eq(BusComplaintBoxDisposeLogging::getIsRefund, "0"));
+ if (logging == null){
+ throw new ServiceException("找不到处理人记录");
+ }
+ logging.setIsRefund("1");
+ logging.setCause(bo.getCause());
+ disposeLoggingService.updateById(logging);
+ }
+ return baseMapper.update(lqw);
+ }
+
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserController.java
index 063db64e..73728aa0 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserController.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserController.java
@@ -412,6 +412,7 @@ public class SubConstructionUserController extends BaseController {
vo.setUploadFile("部分上传");
}
dataList.add(vo);
+ order++;
}
// 写入当前Sheet的数据
excelWriter.write(dataList, writeSheet);
@@ -456,7 +457,9 @@ public class SubConstructionUserController extends BaseController {
} else {
vo.setUploadFile("部分上传");
}
+ vo.setTeamName(null);
dataList.add(vo);
+ order++;
}
// 写入当前Sheet的数据
excelWriter.write(dataList, writeSheet);
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserFileController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserFileController.java
index 9f49dfe0..0a5ff30a 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserFileController.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/controller/SubConstructionUserFileController.java
@@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
+import java.util.Map;
/**
* 施工人员文件存储
@@ -45,6 +46,21 @@ public class SubConstructionUserFileController extends BaseController {
return R.ok(constructionUserFileService.queryList(req));
}
+
+ /**
+ * 下载用户文件的ZIP(按类型分文件夹)
+ * @param userId 用户ID
+ */
+ @GetMapping("/downloadFiles")
+ public void downloadUserFilesByType(Long userId,String type, HttpServletResponse response) {
+ try {
+ constructionUserFileService.generateTypeGroupZip(userId,type, response);
+ } catch (Exception e) {
+ e.printStackTrace();
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+ }
+
/**
* 导出施工人员文件存储列表
*/
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserChangeProjectReq.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserChangeProjectReq.java
index 9e95b14a..5e9848fa 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserChangeProjectReq.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserChangeProjectReq.java
@@ -34,4 +34,11 @@ public class SubConstructionUserChangeProjectReq implements Serializable {
*/
@NotNull(message = "分包公司id不能为空")
private Long contractorId;
+
+
+ /**
+ * 工种
+ */
+ private String typeOfWork;
+
}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserVo.java
index b57de4fe..6be001ec 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserVo.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/vo/constructionuser/SubConstructionUserVo.java
@@ -9,12 +9,15 @@ import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.contractor.domain.SubConstructionUser;
+import org.dromara.contractor.domain.vo.constructionuserfile.SubConstructionUserFileVo;
+import org.dromara.project.domain.vo.constructionuserexit.BusConstructionUserExitVo;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;
+import java.util.List;
/**
@@ -295,5 +298,29 @@ public class SubConstructionUserVo implements Serializable {
*/
private Long sysUserId;
+ /**
+ * 岗位(默认为0普通员工,1组长)
+ */
private String postId;
+
+ /**
+ * 分包管理人员ID
+ */
+ private String fbId;
+
+ /**
+ * 分包管理人员名称
+ */
+ @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "fbId")
+ private String fbName;
+
+ /**
+ * 文件
+ */
+ List subConstructionUserFileVos;
+
+ /**
+ * 记录
+ */
+ List busConstructionUserExitVos;
}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubConstructionUserFileService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubConstructionUserFileService.java
index 65bcfecc..04af8b5f 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubConstructionUserFileService.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/ISubConstructionUserFileService.java
@@ -9,6 +9,7 @@ import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUse
import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileSaveReq;
import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileTemplateReq;
import org.dromara.contractor.domain.vo.constructionuserfile.SubConstructionUserFileVo;
+import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@@ -82,4 +83,12 @@ public interface ISubConstructionUserFileService extends IService getFileByUserId(Long userId);
+
+ /**
+ * 获取施工人员文件列表
+ */
+ Map> fileList(Long userId);
+
+
+ void generateTypeGroupZip(Long userId,String type, HttpServletResponse response) throws Exception;
}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserFileServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserFileServiceImpl.java
index 7c28b00c..1fb5f21b 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserFileServiceImpl.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserFileServiceImpl.java
@@ -45,6 +45,9 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
@@ -231,7 +234,7 @@ public class SubConstructionUserFileServiceImpl extends ServiceImpl userIdList = constructionUserFileList.stream().map(SubConstructionUserFile::getUserId).toList();
@@ -470,6 +473,94 @@ public class SubConstructionUserFileServiceImpl extends ServiceImpl> fileList(Long userId) {
+
+ List subConstructionUserFileVos = baseMapper.selectVoList(Wrappers.lambdaQuery()
+ .eq(SubConstructionUserFile::getUserId, userId));
+ Map> resultMap = subConstructionUserFileVos.stream().collect(Collectors.groupingBy(SubConstructionUserFileVo::getFileType));
+ return resultMap;
+ }
+
+
+
+
+ @Override
+ public void generateTypeGroupZip(Long userId,String type, HttpServletResponse response) throws Exception {
+
+ // 1. 查询该用户的所有文件
+ List list = lambdaQuery()
+ .eq(SubConstructionUserFile::getUserId, userId)
+ .eq(StrUtil.isNotBlank(type),SubConstructionUserFile::getFileType, type)
+ .list();
+ if (list.isEmpty()) {
+ throw new ServiceException("该用户没有文件");
+ }
+ List userFileType = dictTypeService.selectDictDataByType("user_file_type");
+ Map collect = userFileType.stream().collect(Collectors.toMap(SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel));
+
+ // 3. 设置响应头(ZIP文件下载)
+ response.setContentType("application/zip");
+ response.setHeader("Content-Disposition", "attachment; filename=\"user_files.zip\"");
+
+ // 4. 压缩流直接写入响应(无临时文件)
+ try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
+ // 遍历每个文件类型分组
+ for (SubConstructionUserFile entry : list) {
+ String fileType = entry.getFileType(); // 文件夹名称:文件类型(如"01")
+
+ String fileTypeName = collect.get(fileType);
+
+ String fileUrl = entry.getPath();
+ if (StringUtils.isBlank(fileUrl)) {
+ continue;
+ }
+ String[] split = fileUrl.split(",");
+ List ossIds = Arrays.stream(split).map(Long::valueOf).toList();
+ List sysOssVos = ossService.listByIds(ossIds);
+ for (SysOssVo sysOssVo : sysOssVos) {
+ String ossVoUrl = sysOssVo.getUrl();
+ if (StringUtils.isBlank(ossVoUrl)) {
+ continue;
+ }
+ String zipEntryName = fileTypeName + "/" + sysOssVo.getOriginalName();
+ ZipEntry zipEntry = new ZipEntry(zipEntryName);
+ zipOut.putNextEntry(zipEntry);
+ // 下载远程文件并写入ZIP
+ URL url = new URL(ossVoUrl);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setRequestMethod("GET");
+ connection.setConnectTimeout(5000);
+ connection.setReadTimeout(10000);
+
+ try (InputStream in = connection.getInputStream()) {
+ byte[] buffer = new byte[1024 * 8];
+ int len;
+ while ((len = in.read(buffer)) != -1) {
+ zipOut.write(buffer, 0, len);
+ }
+ } finally {
+ connection.disconnect();
+ zipOut.closeEntry(); // 关闭当前条目
+ }
+ }
+ }
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/**
* 递归扫描指定目录,找到 “姓名-Id” 格式的文件夹并解析
*/
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java
index 1ae52ec8..2217c133 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/service/impl/SubConstructionUserServiceImpl.java
@@ -38,9 +38,11 @@ import org.dromara.contractor.domain.SubConstructionUser;
import org.dromara.contractor.domain.SubConstructionUserFile;
import org.dromara.contractor.domain.SubContractor;
import org.dromara.contractor.domain.dto.constructionuser.*;
+import org.dromara.contractor.domain.dto.constructionuserfile.SubConstructionUserFileQueryReq;
import org.dromara.contractor.domain.enums.SubConstructionUserFileStatusEnum;
import org.dromara.contractor.domain.exportvo.BusConstructionUserExportVo;
import org.dromara.contractor.domain.vo.constructionuser.*;
+import org.dromara.contractor.domain.vo.constructionuserfile.SubConstructionUserFileVo;
import org.dromara.contractor.domain.vo.contractor.SubContractorVo;
import org.dromara.contractor.mapper.SubConstructionUserMapper;
import org.dromara.contractor.service.ISubConstructionUserFileService;
@@ -48,10 +50,12 @@ import org.dromara.contractor.service.ISubConstructionUserService;
import org.dromara.contractor.service.ISubContractorService;
import org.dromara.project.domain.*;
import org.dromara.project.domain.dto.attendance.TodayUserDto;
+import org.dromara.project.domain.dto.constructionuserexit.BusConstructionUserExitQueryReq;
import org.dromara.project.domain.enums.BusAttendanceClockStatusEnum;
import org.dromara.project.domain.enums.BusAttendanceCommuterEnum;
import org.dromara.project.domain.enums.BusConstructionUserAttendanceStatusEnum;
import org.dromara.project.domain.vo.attendance.AttendanceTodayUserVo;
+import org.dromara.project.domain.vo.constructionuserexit.BusConstructionUserExitVo;
import org.dromara.project.domain.vo.projectteam.BusProjectTeamAppVo;
import org.dromara.project.service.*;
import org.dromara.system.domain.SysUser;
@@ -157,6 +161,10 @@ public class SubConstructionUserServiceImpl extends ServiceImpl subConstructionUserFileVos = constructionUserFileService.queryList(req);
+ vo.setSubConstructionUserFileVos(subConstructionUserFileVos);
+ BusConstructionUserExitQueryReq busConstructionUserExitQueryReq = new BusConstructionUserExitQueryReq();
+ busConstructionUserExitQueryReq.setUserId(constructionUser.getSysUserId());
+ List busConstructionUserExitVos = busConstructionUserExitService.queryList(busConstructionUserExitQueryReq);
+ vo.setBusConstructionUserExitVos(busConstructionUserExitVos);
+ return vo;
}
/**
@@ -230,7 +247,7 @@ public class SubConstructionUserServiceImpl extends ServiceImpl lambdaUpdate = Wrappers.lambdaUpdate(SubConstructionUser.class)
.eq(SubConstructionUser::getId, id)
.set(SubConstructionUser::getProjectId, req.getProjectId())
- .set(SubConstructionUser::getContractorId, req.getContractorId());
+ .set(SubConstructionUser::getContractorId, req.getContractorId())
+ .set(SubConstructionUser::getTypeOfWork, req.getTypeOfWork())
+ ;
+
+ userProjectRelevancyService.deleteByUserId(constructionUser.getSysUserId());
+
+ roleService.deleteRoleByUserIdAndProjectId(constructionUser.getSysUserId(), req.getProjectId());
+
return this.update(lambdaUpdate);
}
@@ -890,6 +914,22 @@ public class SubConstructionUserServiceImpl extends ServiceImpllambdaQuery()
+ .eq(BusProjectTeamMember::getTeamId, constructionUser.getTeamId())
+ .last("limit 1")
+ );
+ if (one != null) {
+ constructionUserVo.setPostId(one.getPostId());
+ }
+ }
+ }
return constructionUserVo;
}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesVolumeCatalogController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesVolumeCatalogController.java
index f6e342cf..d5a4310c 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesVolumeCatalogController.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/controller/DesVolumeCatalogController.java
@@ -26,6 +26,7 @@ import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogCreateReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogQueryReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogUpdateReq;
import org.dromara.design.domain.vo.CopyUserVo;
+import org.dromara.design.domain.vo.DelayContVo;
import org.dromara.design.domain.vo.DesUserVo;
import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileVo;
@@ -45,10 +46,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.ZoneId;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
import java.util.stream.Collectors;
/**
@@ -131,6 +129,16 @@ public class DesVolumeCatalogController extends BaseController {
return toAjax(desVolumeCatalogService.viewerFile(id));
}
+ /**
+ * 计划过期统计
+ */
+ @GetMapping("/delayCont/{projectId}")
+ public R delayCont(@PathVariable Long projectId) {
+ return R.ok(desVolumeCatalogService.delayCont(projectId));
+ }
+
+
+
/**
* 新增卷册目录
*/
@@ -167,6 +175,9 @@ public class DesVolumeCatalogController extends BaseController {
}
+
+
+
/**
* 收资清单模板导出
*/
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/volumecatalog/DesVolumeCatalogQueryReq.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/volumecatalog/DesVolumeCatalogQueryReq.java
index 750602b9..47b290af 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/volumecatalog/DesVolumeCatalogQueryReq.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/dto/volumecatalog/DesVolumeCatalogQueryReq.java
@@ -46,4 +46,9 @@ public class DesVolumeCatalogQueryReq implements Serializable {
*/
private String designSubitem;
+ /**
+ * 0-不延期,1-延期
+ */
+ private String delay;
+
}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/DelayContVo.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/DelayContVo.java
new file mode 100644
index 00000000..7d54aa4b
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/domain/vo/DelayContVo.java
@@ -0,0 +1,23 @@
+package org.dromara.design.domain.vo;
+
+
+import lombok.Data;
+
+@Data
+public class DelayContVo {
+
+ /**
+ * 总数
+ */
+ private Integer total;
+
+ /**
+ * 延迟数
+ */
+ private Integer delay;
+
+ /**
+ * 今日数
+ */
+ private Integer today;
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesVolumeCatalogService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesVolumeCatalogService.java
index a5e5cb04..bf3f5e04 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesVolumeCatalogService.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesVolumeCatalogService.java
@@ -11,7 +11,9 @@ import org.dromara.design.domain.DesVolumeFile;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogCreateReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogQueryReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogUpdateReq;
+import org.dromara.design.domain.vo.DelayContVo;
import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo;
+import org.springframework.web.bind.annotation.PathVariable;
import java.util.Collection;
import java.util.List;
@@ -130,4 +132,9 @@ public interface IDesVolumeCatalogService extends IService {
* @return 设计子项列表
*/
List listDesignSubitem(Long projectId);
+
+ /**
+ * 统计
+ */
+ DelayContVo delayCont(Long projectId);
}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesVolumeFileService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesVolumeFileService.java
index 948060ed..2958cf2f 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesVolumeFileService.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/IDesVolumeFileService.java
@@ -100,4 +100,7 @@ public interface IDesVolumeFileService extends IService {
TableDataInfo queryAppPageList(DesVolumeFileAppPageDto dto, PageQuery pageQuery);
AuditFileVo auditFile(AuditFileDto dto);
+
+
+
}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesVolumeCatalogServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesVolumeCatalogServiceImpl.java
index f1a03153..4f66d4ef 100644
--- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesVolumeCatalogServiceImpl.java
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/design/service/impl/DesVolumeCatalogServiceImpl.java
@@ -28,6 +28,7 @@ import org.dromara.design.domain.bo.DesUserBo;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogCreateReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogQueryReq;
import org.dromara.design.domain.dto.volumecatalog.DesVolumeCatalogUpdateReq;
+import org.dromara.design.domain.vo.DelayContVo;
import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo;
import org.dromara.design.mapper.DesVolumeCatalogMapper;
import org.dromara.design.service.*;
@@ -43,6 +44,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -236,6 +239,17 @@ public class DesVolumeCatalogServiceImpl extends ServiceImpl list = this.lambdaQuery()
+ .eq(DesVolumeCatalog::getProjectId, projectId).list();
+ DelayContVo delayContVo = new DelayContVo();
+ delayContVo.setTotal(list.size());
+ delayContVo.setDelay((int)list.stream().filter(item -> item.getPlannedCompletion().isBefore(LocalDate.now()) && item.getDesignState().equals("2")).count());
+ delayContVo.setToday((int)list.stream().filter(item -> item.getPlannedCompletion().isEqual(LocalDate.now())).count());
+ return delayContVo;
+ }
+
/**
* 修改卷册目录
*
@@ -353,6 +367,7 @@ public class DesVolumeCatalogServiceImpl extends ServiceImpl wrapper.gt(DesVolumeCatalog::getPlannedCompletion, LocalDateTime.now())
+ .or()
+ .eq(DesVolumeCatalog::getDesignState, "1")
+ );
+ }
return lqw;
}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceAccessRecordController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceAccessRecordController.java
new file mode 100644
index 00000000..fcb25f86
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceAccessRecordController.java
@@ -0,0 +1,123 @@
+package org.dromara.device.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.project.domain.BusProject;
+import org.dromara.project.service.IBusProjectService;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.device.domain.vo.DeviceAccessRecordVo;
+import org.dromara.device.domain.bo.DeviceAccessRecordBo;
+import org.dromara.device.service.IDeviceAccessRecordService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 设备进出场记录
+ *
+ * @author Lion Li
+ * @date 2025-12-01
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/device/accessRecord")
+public class DeviceAccessRecordController extends BaseController {
+
+ private final IDeviceAccessRecordService deviceAccessRecordService;
+
+ private final IBusProjectService projectService;
+
+ /**
+ * 查询设备进出场记录列表
+ */
+// @SaCheckPermission("device:accessRecord:list")
+ @GetMapping("/list")
+ public TableDataInfo list(DeviceAccessRecordBo bo, PageQuery pageQuery) {
+ return deviceAccessRecordService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 导出设备进出场记录列表
+ */
+ @SaCheckPermission("device:accessRecord:export")
+ @Log(title = "设备进出场记录", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(DeviceAccessRecordBo bo, HttpServletResponse response) {
+ List list = deviceAccessRecordService.queryList(bo);
+ ExcelUtil.exportExcel(list, "设备进出场记录", DeviceAccessRecordVo.class, response);
+ }
+
+ /**
+ * 获取设备进出场记录详细信息
+ *
+ * @param id 主键
+ */
+// @SaCheckPermission("device:accessRecord:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "主键不能为空")
+ @PathVariable Long id) {
+ return R.ok(deviceAccessRecordService.queryById(id));
+ }
+
+ /**
+ * 子项目列表
+ */
+ @GetMapping("/childProjectList/{projectId}")
+ public R> childProjectId(@PathVariable Long projectId) {
+ List list = projectService.lambdaQuery()
+ .select(BusProject::getId, BusProject::getProjectName)
+ .eq(BusProject::getPId, projectId).list();
+ return R.ok(list);
+ }
+
+
+ /**
+ * 新增设备进出场记录
+ */
+ @SaCheckPermission("device:accessRecord:add")
+ @Log(title = "设备进出场记录", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R add(@Validated(AddGroup.class) @RequestBody DeviceAccessRecordBo bo) {
+ return toAjax(deviceAccessRecordService.insertByBo(bo));
+ }
+
+
+
+ /**
+ * 修改设备进出场记录
+ */
+// @SaCheckPermission("device:accessRecord:edit")
+ @Log(title = "设备进出场记录", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R edit(@Validated(EditGroup.class) @RequestBody DeviceAccessRecordBo bo) {
+ return toAjax(deviceAccessRecordService.updateByBo(bo));
+ }
+
+ /**
+ * 删除设备进出场记录
+ *
+ * @param ids 主键串
+ */
+ @SaCheckPermission("device:accessRecord:remove")
+ @Log(title = "设备进出场记录", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R remove(@NotEmpty(message = "主键不能为空")
+ @PathVariable Long[] ids) {
+ return toAjax(deviceAccessRecordService.deleteWithValidByIds(List.of(ids), true));
+ }
+}
diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceInfoController.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceInfoController.java
new file mode 100644
index 00000000..caaa5ca4
--- /dev/null
+++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/device/controller/DeviceInfoController.java
@@ -0,0 +1,150 @@
+package org.dromara.device.controller;
+
+import java.util.List;
+import java.util.Map;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.device.domain.bo.DeviceAccessRecordBo;
+import org.dromara.device.domain.vo.DeviceAccessRecordVo;
+import org.dromara.device.domain.vo.DeviceInfoCountVo;
+import org.dromara.device.service.IDeviceAccessRecordService;
+import org.redisson.api.RList;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.device.domain.vo.DeviceInfoVo;
+import org.dromara.device.domain.bo.DeviceInfoBo;
+import org.dromara.device.service.IDeviceInfoService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 设备信息
+ *
+ * @author Lion Li
+ * @date 2025-12-01
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/device/info")
+public class DeviceInfoController extends BaseController {
+
+ private final IDeviceInfoService deviceInfoService;
+
+ private final IDeviceAccessRecordService deviceAccessRecordService;
+
+ /**
+ * 查询设备信息列表
+ */
+ @SaCheckPermission("device:info:list")
+ @GetMapping("/list")
+ public TableDataInfo list(DeviceInfoBo bo, PageQuery pageQuery) {
+ return deviceInfoService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 导出设备信息列表
+ */
+ @SaCheckPermission("device:info:export")
+ @Log(title = "设备信息", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(DeviceInfoBo bo, HttpServletResponse response) {
+ List list = deviceInfoService.queryList(bo);
+ ExcelUtil.exportExcel(list, "设备信息", DeviceInfoVo.class, response);
+ }
+
+ /**
+ * 获取设备信息详细信息
+ *
+ * @param id 主键
+ */
+// @SaCheckPermission("device:info:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "主键不能为空")
+ @PathVariable Long id) {
+ return R.ok(deviceInfoService.queryById(id));
+ }
+
+ /**
+ * 进出场纪录
+ */
+ @GetMapping("/recordList")
+ public R> recordList(DeviceAccessRecordBo bo) {
+ List list = deviceAccessRecordService.queryList(bo);
+ return R.ok(list);
+ }
+
+
+ /**
+ * 设备信息统计
+ */
+ @SaCheckPermission("device:info:list")
+ @GetMapping("/count/{projectId}")
+ public R