38 Commits

Author SHA1 Message Date
3f4b7f0186 Merge remote-tracking branch 'origin/main' 2025-07-04 15:11:31 +08:00
f2a6f16cdd 操作说明和产品参数 2025-07-04 15:10:36 +08:00
3129db352e Merge branch 'dyf-device' 2025-07-04 08:34:52 +08:00
e8aee3039a WEB:导出数据设备 2025-07-03 17:53:10 +08:00
0271a84bc2 WEB:设备类型管理 2025-07-03 16:58:08 +08:00
4e83e3570a WEB:客户管理 2025-07-03 15:30:18 +08:00
5bc56ca36d WEB:客户管理 2025-07-03 14:17:53 +08:00
c3a9f4a365 app文件管理 2025-07-03 14:07:32 +08:00
b06e071196 WEB:客户管理 2025-07-03 11:39:49 +08:00
abe9dc2fe8 分页查询客户 2025-07-03 10:08:09 +08:00
fe6de8f5bc Merge remote-tracking branch 'origin/main' into dyf-device 2025-07-02 17:54:56 +08:00
5917234ca8 新增客户 2025-07-02 17:53:53 +08:00
3e07891760 操作视频管理 2025-07-02 16:36:40 +08:00
2a81385554 新增设备 2025-07-02 15:29:09 +08:00
5336170b2d app登录优化,操作视频管理模块接口实现 2025-07-02 15:27:32 +08:00
4220428f92 fel 2025-07-02 14:47:17 +08:00
a487e7ae67 清空所有客户端缓存 2025-07-02 14:16:11 +08:00
a69aad227a 设备类型管理 2025-07-02 11:25:41 +08:00
6b802f4546 APP:客户设备管理 2025-07-02 09:52:53 +08:00
2673320f02 WEB:客户管理 接口 2025-07-01 16:40:59 +08:00
56288830cb 查询所有客户 2025-07-01 16:20:39 +08:00
24c511b15e app登录提交 2025-07-01 16:04:47 +08:00
4eeb21b5f7 Merge branch 'main' into dyf-device
# Conflicts:
#	fys-modules/pom.xml
#	pom.xml
2025-07-01 15:28:11 +08:00
dd6d5e4911 客户管理 接口 2025-07-01 15:24:17 +08:00
9f6538b449 客户管理 接口 2025-07-01 15:24:09 +08:00
dd8b685de3 Merge remote-tracking branch 'origin/APP权限登录改造'
# Conflicts:
#	fys-admin/src/main/java/com/fuyuanshen/app/service/AppLoginService.java
2025-07-01 14:31:13 +08:00
103579421c 合并app登录权限分支 2025-07-01 14:12:41 +08:00
e0bc282097 Merge remote-tracking branch 'origin/APP权限登录改造'
# Conflicts:
#	fys-modules/pom.xml
#	pom.xml
2025-07-01 13:58:39 +08:00
53356957f3 设备管理 接口 2025-07-01 13:53:03 +08:00
440aec266b 设备类型管理接口 2025-07-01 09:32:22 +08:00
933e74235f 设备类型管理 2025-06-30 18:03:43 +08:00
eac1b2e016 添加设备 2025-06-30 16:59:12 +08:00
0969a7cd1f 模拟前端 登录测试 2025-06-30 15:44:53 +08:00
20f3edaeec 控制台 打印 图片验证码 2025-06-30 13:49:32 +08:00
4add59d197 增加 设备管理模块 接口文档 2025-06-30 09:47:23 +08:00
b89d962a50 增加 springdoc-openapi-starter-webmvc-ui 依赖 2025-06-30 09:38:24 +08:00
f9f5569504 分页查询设备 2025-06-28 17:18:05 +08:00
1d286634c0 fys-equipment 2025-06-28 13:52:06 +08:00
113 changed files with 6697 additions and 21 deletions

View File

@ -65,6 +65,18 @@
<artifactId>fys-common-mail</artifactId>
</dependency>
<!-- 客户管理模块 -->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-customer</artifactId>
</dependency>
<!-- 设备管理模块 -->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-equipment</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-system</artifactId>
@ -99,6 +111,7 @@
<artifactId>fys-app</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>

View File

@ -63,7 +63,6 @@ public class AppAuthController {
@PostMapping("/login")
public R<LoginVo> login(@RequestBody AppSmsLoginBody appSmsLoginBody) {
// SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class);
LoginHelper.getLoginUser();
ValidatorUtils.validate(appSmsLoginBody);
SmsLoginBody loginBody = new SmsLoginBody();
loginBody.setPhonenumber(appSmsLoginBody.getPhonenumber());

View File

@ -0,0 +1,54 @@
package com.fuyuanshen.app.controller;
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
import com.fuyuanshen.app.domain.dto.AppFileDto;
import com.fuyuanshen.app.domain.vo.AppFileVo;
import com.fuyuanshen.app.service.AppFileService;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.web.core.BaseController;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* APP 文件管理
* @date 2025-06-27
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/file")
public class AppFileController extends BaseController {
private final AppFileService appFileService;
/**
* 查询文件列表
*/
@GetMapping("/list")
public R<List<AppFileVo>> list(AppBusinessFileBo bo) {
return R.ok(appFileService.list(bo));
}
/**
* 上传文件
*/
@PostMapping("/upload")
public R<Void> upload(@Validated @ModelAttribute AppFileDto bo) {
return toAjax(appFileService.add(bo));
}
/**
* 文件删除
*/
@DeleteMapping("/delete")
public R<Void> delete(Long[] ids) {
if(ids == null || ids.length == 0){
return R.fail("请选择要删除的文件");
}
return toAjax(appFileService.delete(ids));
}
}

View File

@ -0,0 +1,71 @@
package com.fuyuanshen.app.controller;
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
import com.fuyuanshen.app.service.IAppOperationVideoService;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.core.domain.model.AppLoginUser;
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
import com.fuyuanshen.common.web.core.BaseController;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* APP 操作视频管理
* @date 2025-06-27
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/operationVideo")
public class AppOperationVideoController extends BaseController {
private final IAppOperationVideoService appOperationVideoService;
/**
* 查询操作视频列表
*/
@GetMapping("/listOperationVideos")
public List<AppOperationVideoVo> listOperationVideos(AppOperationVideoBo bo) {
return appOperationVideoService.queryList(bo);
}
/**
* 查询操作视频详情信息
*/
@GetMapping("/getOperationVideoInfo")
public AppOperationVideoVo getOperationVideoInfo(AppOperationVideoBo bo) {
return appOperationVideoService.queryById(bo.getId());
}
/**
* 操作视频添加
*/
@PostMapping("/addOperationVideo")
public R<Void> addOperationVideo(@RequestBody AppOperationVideoBo bo) {
AppLoginUser loginUser = AppLoginHelper.getLoginUser();
if (loginUser != null) {
bo.setCreateBy(loginUser.getUserId());
}
return toAjax(appOperationVideoService.insertByBo(bo));
}
/**
* 操作视频编辑
*/
@PostMapping("/editOperationVideo")
public R<Void> editOperationVideo(@RequestBody AppOperationVideoBo bo) {
return toAjax(appOperationVideoService.updateByBo(bo));
}
/**
* 操作视频删除
*/
@DeleteMapping("/deleteOperationVideo")
public R<Void> deleteOperationVideo(Long[] ids) {
return toAjax(appOperationVideoService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,21 @@
package com.fuyuanshen.app.domain.dto;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
@Data
public class AppFileDto {
private Long deviceId;
/**
* 文件类型(1:操作说明2:产品参数)
*/
private Long fileType;
/**
* 文件
*/
private MultipartFile file;
}

View File

@ -0,0 +1,8 @@
package com.fuyuanshen.app.domain.dto;
import lombok.Data;
@Data
public class AppVideoDto {
}

View File

@ -0,0 +1,68 @@
package com.fuyuanshen.app.service;
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
import com.fuyuanshen.app.domain.dto.AppFileDto;
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
import com.fuyuanshen.app.domain.vo.AppFileVo;
import com.fuyuanshen.common.oss.core.OssClient;
import com.fuyuanshen.common.oss.factory.OssFactory;
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
import com.fuyuanshen.system.domain.vo.SysOssVo;
import com.fuyuanshen.system.service.ISysOssService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 登录校验方法
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Slf4j
@Service
public class AppFileService {
private final ISysOssService sysOssService;
private final IAppBusinessFileService appBusinessFileService;
public List<AppFileVo> list(AppBusinessFileBo bo) {
bo.setCreateBy(AppLoginHelper.getUserId());
return appBusinessFileService.queryAppFileList(bo);
}
public Boolean add(AppFileDto bo) {
// 上传文件
SysOssVo upload = sysOssService.upload(bo.getFile());
if (upload == null) {
return false;
}
AppBusinessFileBo appBusinessFileBo = new AppBusinessFileBo();
appBusinessFileBo.setFileId(upload.getOssId());
appBusinessFileBo.setBusinessId(bo.getDeviceId());
appBusinessFileBo.setFileType(bo.getFileType());
appBusinessFileBo.setCreateBy(AppLoginHelper.getUserId());
return appBusinessFileService.insertByBo(appBusinessFileBo);
}
public Boolean delete(Long[] ids) {
AppBusinessFileBo bo = new AppBusinessFileBo();
bo.setCreateBy(AppLoginHelper.getUserId());
bo.setIds(List.of(ids));
List<AppBusinessFileVo> appBusinessFileVos = appBusinessFileService.queryList(bo);
List<Long> fileIds = appBusinessFileVos.stream().map(AppBusinessFileVo::getFileId).toList();
List<SysOssVo> list = sysOssService.listByIds(fileIds);
for (SysOssVo sysOss : list) {
OssClient storage = OssFactory.instance(sysOss.getService());
storage.delete(sysOss.getUrl());
}
return appBusinessFileService.deleteWithValidByIds(List.of(ids), true);
}
}

View File

@ -51,7 +51,7 @@ public class AppLoginService {
private Integer lockTime;
private final ISysTenantService tenantService;
private final IAppRoleService appRoleService;
private final IAppRoleService roleService;
/**
@ -63,7 +63,7 @@ public class AppLoginService {
/**
* 退出登录
*/
/*public void logout() {
public void logout() {
try {
AppLoginUser loginUser = AppLoginHelper.getLoginUser();
if (ObjectUtil.isNull(loginUser)) {
@ -81,7 +81,7 @@ public class AppLoginService {
} catch (NotLoginException ignored) {
}
}
}*/
}
/**
* 记录登录信息

View File

@ -144,6 +144,10 @@ public class CaptchaController {
Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
code = exp.getValue(String.class);
}
log.info("图片验证码:{}", code);
log.info("图片验证码uuid{}", uuid);
RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
CaptchaVo captchaVo = new CaptchaVo();
captchaVo.setUuid(uuid);

View File

@ -157,6 +157,11 @@ public class SysLoginService {
loginUser.setUsername(user.getUserName());
loginUser.setNickname(user.getNickName());
loginUser.setUserType(user.getUserType());
// 用户级别
loginUser.setUserLevel(user.getUserLevel());
// pid
loginUser.setPid(user.getPid());
loginUser.setMenuPermission(permissionService.getMenuPermission(userId));
loginUser.setRolePermission(permissionService.getRolePermission(userId));
if (ObjectUtil.isNotNull(user.getDeptId())) {
@ -242,7 +247,7 @@ public class SysLoginService {
log.info("登录租户:{} 已被停用.", tenantId);
throw new TenantException("tenant.blocked");
} else if (ObjectUtil.isNotNull(tenant.getExpireTime())
&& new Date().after(tenant.getExpireTime())) {
&& new Date().after(tenant.getExpireTime())) {
log.info("登录租户:{} 已超过有效期.", tenantId);
throw new TenantException("tenant.expired");
}

View File

@ -270,3 +270,26 @@ justauth:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitea
# 文件存储路径
file:
mac:
path: ~/file/
avatar: ~/avatar/
linux:
path: /home/eladmin/file/
avatar: /home/eladmin/avatar/
windows:
path: C:\eladmin\file\
avatar: C:\eladmin\avatar\
# 文件大小 /M
maxSize: 100
avatarMaxSize: 5
device:
pic: C:\eladmin\file\ #设备图片存储路径
ip: http://fuyuanshen.com:81/ #服务器地址
app_avatar:
pic: C:\eladmin\file\ #设备图片存储路径
#ip: http://fuyuanshen.com:81/ #服务器地址
ip: https://fuyuanshen.com/ #服务器地址

View File

@ -0,0 +1,272 @@
--- # 监控中心配置
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: "fys_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:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 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://localhost:3306/fys-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: root
# # 从库数据源
# 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: 123.207.99.140
# 端口默认为6379
port: 6379
# 数据库索引
database: 2
# redis 密码必须配置
password: ccxx11234
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson:
# redis key前缀
keyPrefix:
# 线程池数量
threads: 4
# Netty线程池数量
nettyThreads: 8
# 单节点配置
singleServerConfig:
# 客户端名称 不能用中文
clientName: fys-Vue-Plus
# 最小空闲连接数
connectionMinimumIdleSize: 8
# 连接池大小
connectionPoolSize: 32
# 连接空闲超时,单位:毫秒
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: true
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30
# 以下配置来自于 com.fuyuanshen.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: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
--- # 三方授权
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:1898/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
gitea:
# 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204
# gitea 服务器地址
server-url: https://demo.gitea.com
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitea

View File

@ -39,6 +39,7 @@ logging:
org.springframework: warn
org.mybatis.spring.mapper: error
org.apache.fury: warn
com.fuyuanshen.web.service.impl.ClientServiceImpl: debug
config: classpath:logback-plus.xml
# 用户配置
@ -135,7 +136,7 @@ tenant:
# https://baomidou.com/config/
mybatis-plus:
# 自定义配置 是否全局开启逻辑删除 关闭后 所有逻辑删除功能将失效
enableLogicDelete: true
enableLogicDelete: false
# 多包名使用 例如 com.fuyuanshen.**.mapper,org.xxx.**.mapper
mapperPackage: com.fuyuanshen.**.mapper
# 对应的 XML 文件位置
@ -211,6 +212,10 @@ springdoc:
packages-to-scan: com.fuyuanshen.generator
- group: 5.工作流模块
packages-to-scan: com.fuyuanshen.workflow
- group: 设备管理模块
packages-to-scan: com.fuyuanshen.equipment
- group: 客户管理模块
packages-to-scan: com.fuyuanshen.customer
# 防止XSS攻击
xss:

View File

@ -93,6 +93,12 @@
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-core</artifactId>
<version>3.5.12</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@ -0,0 +1,28 @@
package com.fuyuanshen.common.core.constant;
/**
* 响应消息常量类
*
* @author: 默苍璃
* @date: 2025-06-2117:21
*/
public class ResponseMessageConstants {
/**
* 删除操作成功提示
*/
public static final String DELETE_SUCCESS = "删除成功!";
/**
* 新增操作成功提示
*/
public static final String SAVE_SUCCESS = "新增成功!";
/**
* 更新操作成功提示
*/
public static final String UPDATE_SUCCESS = "更新成功!";
// 可根据业务需求继续扩展其他常用提示信息
}

View File

@ -22,6 +22,11 @@ public interface TenantConstants {
*/
String TENANT_ADMIN_ROLE_KEY = "admin";
/**
* 富源晟内部员工 roleKey
*/
String FYS_ROLE_KEY = "fel";
/**
* 租户管理员角色名称
*/

View File

@ -0,0 +1,24 @@
package com.fuyuanshen.common.core.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* 分页结果封装类
* @author Zheng Jie
* @date 2018-11-23
* @param <T>
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageResult<T> implements Serializable {
private List<T> rows;
private long total;
}

View File

@ -0,0 +1,64 @@
package com.fuyuanshen.common.core.domain;
import lombok.Data;
/**
* @Description: 返回体
* @Author: WY
* @Date: 2025/6/2
**/
@Data
public class ResponseVO<T> {
private Integer code; // 成功:0 失败:-1
private String msg;
private T data;
public ResponseVO(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public ResponseVO(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
// 静态方法,用于创建成功的响应
public static <T> ResponseVO<T> success() {
return new ResponseVO<>(0, "操作成功", null);
}
public static <T> ResponseVO<T> success(T data) {
return new ResponseVO<>(0, "操作成功", data);
}
public static <T> ResponseVO<T> success(String msg, T data) {
return new ResponseVO<>(0, msg, data);
}
// 静态方法,用于创建失败的响应
public static <T> ResponseVO<T> fail(String msg) {
return new ResponseVO<>(-1, msg, null);
}
public static <T> ResponseVO<T> fail(String msg, T data) {
return new ResponseVO<>(-1, msg, data);
}
// 链式方法 - 添加泛型支持
public <R> ResponseVO<R> withData(R data) {
return new ResponseVO<>(this.code, this.msg, data);
}
public ResponseVO<T> withMsg(String msg) {
this.msg = msg;
return this;
}
public ResponseVO<T> withCode(Integer code) {
this.code = code;
return this;
}
}

View File

@ -1,5 +1,6 @@
package com.fuyuanshen.common.core.domain.model;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.fuyuanshen.common.core.domain.dto.PostDTO;
@ -31,6 +32,7 @@ public class LoginUser implements Serializable {
* 用户ID
*/
private Long userId;
private Long pid;
/**
* 部门ID
@ -132,6 +134,11 @@ public class LoginUser implements Serializable {
*/
private String deviceType;
/**
* 用户等级
*/
private Byte userLevel;
/**
* 获取登录id
*/

View File

@ -0,0 +1,73 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.common.core.utils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fuyuanshen.common.core.domain.PageResult;
import java.util.Collections;
import java.util.List;
/**
* 分页工具
* @author Zheng Jie
* @date 2018-12-10
*/
public class PageUtil extends cn.hutool.core.util.PageUtil {
/**
* List 分页
*/
public static <T> List<T> paging(int page, int size , List<T> list) {
int fromIndex = page * size;
int toIndex = page * size + size;
if(fromIndex > list.size()){
return Collections.emptyList();
} else if(toIndex >= list.size()) {
return list.subList(fromIndex,list.size());
} else {
return list.subList(fromIndex,toIndex);
}
}
/**
* Page 数据处理
*/
public static <T> PageResult<T> toPage(IPage<T> page) {
return new PageResult<>(page.getRecords(), page.getTotal());
}
/**
* 自定义分页
*/
public static <T> PageResult<T> toPage(List<T> list) {
return new PageResult<>(list, list.size());
}
/**
* 返回空数据
*/
public static <T> PageResult<T> noData () {
return new PageResult<>(null, 0);
}
/**
* 自定义分页
*/
public static <T> PageResult<T> toPage(List<T> list, long totalElements) {
return new PageResult<>(list, totalElements);
}
}

View File

@ -26,6 +26,11 @@
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<dependency>
<groupId>com.github.therapi</groupId>
<artifactId>therapi-runtime-javadoc</artifactId>

View File

@ -0,0 +1,78 @@
package com.fuyuanshen.common.encrypt.utils;
import com.fuyuanshen.common.core.domain.model.PasswordLoginBody;
/**
* 登录测试
*
* @author: 默苍璃
* @date: 2025-06-3014:29
*/
public class EncryptUtilsTest {
public static void main(String[] args) {
// System.out.println(EncryptUtils.encryptByBase64("123456"));
System.out.println(EncryptUtils.encryptByBase64("1234567890abcdef"));
String g = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==";
String s = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y=";
String s1 = EncryptUtils.encryptByRsa("MTIzNDU2Nzg5MGFiY2RlZg==", g);
System.out.println(s1);
String s2 = EncryptUtils.decryptByRsa("jJPaW7hgFXD/gjdkrfBOEUdXpPZnQg/LZUASoOJAOLU/XRVXO/5666CzyALjw7neK1ujvRuys4MdKCvr9cRARw==", s);
System.out.println(s2);
String s3 = EncryptUtils.decryptByBase64(s2);
System.out.println(s3);
String s4 = EncryptUtils.encryptByAes("123456", s3);
System.out.println(s4);
String s5 = EncryptUtils.decryptByAes(s4, s3);
System.out.println(s5);
// 1. 构造 LoginBody 对象
PasswordLoginBody loginBody = new PasswordLoginBody();
loginBody.setClientId("e5cd7e4891bf95d1d19206ce24a7b32e");
loginBody.setGrantType("password");
loginBody.setTenantId("894078");
loginBody.setCode("0");
loginBody.setUuid("1c285b27f516486f9535face77023aeb");
// loginBody.setUsername("admin");
// loginBody.setPassword("admin123");
loginBody.setUsername("dyf");
loginBody.setPassword("123456");
// 2. 使用更清晰的方式拼接 JSON 字符串
String jsonLoginBody = String.format(
"{"
+ "\"clientId\":\"%s\","
+ "\"grantType\":\"%s\","
+ "\"tenantId\":\"%s\","
+ "\"code\":\"%s\","
+ "\"uuid\":\"%s\","
+ "\"username\":\"%s\","
+ "\"password\":\"%s\""
+ "}",
loginBody.getClientId(),
loginBody.getGrantType(),
loginBody.getTenantId(),
loginBody.getCode(),
loginBody.getUuid(),
loginBody.getUsername(),
loginBody.getPassword()
);
String S5 = EncryptUtils.encryptByAes(jsonLoginBody, s3);
System.out.println(S5);
String S6 = EncryptUtils.decryptByAes(S5, s3);
System.out.println(S6);
}
}

View File

@ -0,0 +1,105 @@
package com.fuyuanshen.app.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.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
import com.fuyuanshen.common.log.annotation.Log;
import com.fuyuanshen.common.web.core.BaseController;
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.core.validate.AddGroup;
import com.fuyuanshen.common.core.validate.EditGroup;
import com.fuyuanshen.common.log.enums.BusinessType;
import com.fuyuanshen.common.excel.utils.ExcelUtil;
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
import com.fuyuanshen.app.service.IAppBusinessFileService;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
/**
* app业务文件
*
* @author Lion Li
* @date 2025-07-03
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/businessFile")
public class AppBusinessFileController extends BaseController {
private final IAppBusinessFileService appBusinessFileService;
/**
* 查询app业务文件列表
*/
@SaCheckPermission("app:businessFile:list")
@GetMapping("/list")
public TableDataInfo<AppBusinessFileVo> list(AppBusinessFileBo bo, PageQuery pageQuery) {
return appBusinessFileService.queryPageList(bo, pageQuery);
}
/**
* 导出app业务文件列表
*/
@SaCheckPermission("app:businessFile:export")
@Log(title = "app业务文件", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(AppBusinessFileBo bo, HttpServletResponse response) {
List<AppBusinessFileVo> list = appBusinessFileService.queryList(bo);
ExcelUtil.exportExcel(list, "app业务文件", AppBusinessFileVo.class, response);
}
/**
* 获取app业务文件详细信息
*
* @param id 主键
*/
@SaCheckPermission("app:businessFile:query")
@GetMapping("/{id}")
public R<AppBusinessFileVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(appBusinessFileService.queryById(id));
}
/**
* 新增app业务文件
*/
@SaCheckPermission("app:businessFile:add")
@Log(title = "app业务文件", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody AppBusinessFileBo bo) {
return toAjax(appBusinessFileService.insertByBo(bo));
}
/**
* 修改app业务文件
*/
@SaCheckPermission("app:businessFile:edit")
@Log(title = "app业务文件", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody AppBusinessFileBo bo) {
return toAjax(appBusinessFileService.updateByBo(bo));
}
/**
* 删除app业务文件
*
* @param ids 主键串
*/
@SaCheckPermission("app:businessFile:remove")
@Log(title = "app业务文件", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(appBusinessFileService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,105 @@
package com.fuyuanshen.app.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.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
import com.fuyuanshen.common.log.annotation.Log;
import com.fuyuanshen.common.web.core.BaseController;
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.core.validate.AddGroup;
import com.fuyuanshen.common.core.validate.EditGroup;
import com.fuyuanshen.common.log.enums.BusinessType;
import com.fuyuanshen.common.excel.utils.ExcelUtil;
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
import com.fuyuanshen.app.service.IAppOperationVideoService;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
/**
* 操作视频
*
* @author Lion Li
* @date 2025-07-02
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/operationVideo")
public class AppOperationVideoController extends BaseController {
private final IAppOperationVideoService appOperationVideoService;
/**
* 查询操作视频列表
*/
@SaCheckPermission("app:operationVideo:list")
@GetMapping("/list")
public TableDataInfo<AppOperationVideoVo> list(AppOperationVideoBo bo, PageQuery pageQuery) {
return appOperationVideoService.queryPageList(bo, pageQuery);
}
/**
* 导出操作视频列表
*/
@SaCheckPermission("app:operationVideo:export")
@Log(title = "操作视频", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(AppOperationVideoBo bo, HttpServletResponse response) {
List<AppOperationVideoVo> list = appOperationVideoService.queryList(bo);
ExcelUtil.exportExcel(list, "操作视频", AppOperationVideoVo.class, response);
}
/**
* 获取操作视频详细信息
*
* @param id 主键
*/
@SaCheckPermission("app:operationVideo:query")
@GetMapping("/{id}")
public R<AppOperationVideoVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(appOperationVideoService.queryById(id));
}
/**
* 新增操作视频
*/
@SaCheckPermission("app:operationVideo:add")
@Log(title = "操作视频", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody AppOperationVideoBo bo) {
return toAjax(appOperationVideoService.insertByBo(bo));
}
/**
* 修改操作视频
*/
@SaCheckPermission("app:operationVideo:edit")
@Log(title = "操作视频", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody AppOperationVideoBo bo) {
return toAjax(appOperationVideoService.updateByBo(bo));
}
/**
* 删除操作视频
*
* @param ids 主键串
*/
@SaCheckPermission("app:operationVideo:remove")
@Log(title = "操作视频", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(appOperationVideoService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,105 @@
package com.fuyuanshen.app.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.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
import com.fuyuanshen.common.log.annotation.Log;
import com.fuyuanshen.common.web.core.BaseController;
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.core.validate.AddGroup;
import com.fuyuanshen.common.core.validate.EditGroup;
import com.fuyuanshen.common.log.enums.BusinessType;
import com.fuyuanshen.common.excel.utils.ExcelUtil;
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
import com.fuyuanshen.app.service.IAppPersonnelInfoService;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
/**
* 人员信息登记
*
* @author Lion Li
* @date 2025-07-02
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/personnelInfo")
public class AppPersonnelInfoController extends BaseController {
private final IAppPersonnelInfoService appPersonnelInfoService;
/**
* 查询人员信息登记列表
*/
@SaCheckPermission("app:personnelInfo:list")
@GetMapping("/list")
public TableDataInfo<AppPersonnelInfoVo> list(AppPersonnelInfoBo bo, PageQuery pageQuery) {
return appPersonnelInfoService.queryPageList(bo, pageQuery);
}
/**
* 导出人员信息登记列表
*/
@SaCheckPermission("app:personnelInfo:export")
@Log(title = "人员信息登记", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(AppPersonnelInfoBo bo, HttpServletResponse response) {
List<AppPersonnelInfoVo> list = appPersonnelInfoService.queryList(bo);
ExcelUtil.exportExcel(list, "人员信息登记", AppPersonnelInfoVo.class, response);
}
/**
* 获取人员信息登记详细信息
*
* @param id 主键
*/
@SaCheckPermission("app:personnelInfo:query")
@GetMapping("/{id}")
public R<AppPersonnelInfoVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(appPersonnelInfoService.queryById(id));
}
/**
* 新增人员信息登记
*/
@SaCheckPermission("app:personnelInfo:add")
@Log(title = "人员信息登记", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) {
return toAjax(appPersonnelInfoService.insertByBo(bo));
}
/**
* 修改人员信息登记
*/
@SaCheckPermission("app:personnelInfo:edit")
@Log(title = "人员信息登记", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody AppPersonnelInfoBo bo) {
return toAjax(appPersonnelInfoService.updateByBo(bo));
}
/**
* 删除人员信息登记
*
* @param ids 主键串
*/
@SaCheckPermission("app:personnelInfo:remove")
@Log(title = "人员信息登记", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(appPersonnelInfoService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,89 @@
package com.fuyuanshen.app.controller.equipment;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.app.domain.APPDevice;
import com.fuyuanshen.app.domain.APPDeviceType;
import com.fuyuanshen.app.domain.dto.APPUnbindDTO;
import com.fuyuanshen.app.domain.query.APPDeviceQueryCriteria;
import com.fuyuanshen.app.service.equipment.APPDeviceService;
import com.fuyuanshen.common.core.domain.PageResult;
import com.fuyuanshen.common.core.domain.ResponseVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
@Slf4j
@Tag(name = "APP客户设备管理", description = "APP客户设备管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/app/device")
public class APPDeviceController {
private final APPDeviceService appDeviceService;
@PostMapping(value = "/list")
@Operation(summary = "APP客户设备列表")
public ResponseVO<PageResult<APPDevice>> appDeviceList(@RequestBody APPDeviceQueryCriteria criteria) {
Page<APPDevice> page = new Page<>(criteria.getPage(), criteria.getSize());
PageResult<APPDevice> devices = null;
try {
devices = appDeviceService.appDeviceList(page, criteria);
} catch (Exception e) {
log.error("queryDevice error: " + e.getMessage());
return ResponseVO.fail("");
}
return ResponseVO.success(devices);
}
@PostMapping(value = "/typeList")
@Operation(summary = "APP客户设备类型列表")
public ResponseVO<List<APPDeviceType>> appTypeList(@RequestBody APPDeviceQueryCriteria criteria) {
List<APPDeviceType> typeList = appDeviceService.appTypeList(criteria);
return ResponseVO.success(typeList);
}
@PostMapping(value = "/bind")
@Operation(summary = "APP客户设备绑定")
public ResponseVO<String> appBindDevice(@RequestBody APPDeviceQueryCriteria criteria) {
appDeviceService.appBindDevice(criteria);
return ResponseVO.success("绑定成功!");
}
@GetMapping
@Operation(summary = "WEB端查看APP客户设备绑定")
public ResponseVO<PageResult<APPDevice>> queryAPPDevice(APPDeviceQueryCriteria criteria) {
Page<APPDevice> page = new Page<>(criteria.getPage(), criteria.getSize());
PageResult<APPDevice> devices = null;
try {
devices = appDeviceService.queryAll(page, criteria);
} catch (Exception e) {
log.error("queryDevice error: " + e.getMessage());
return ResponseVO.fail("");
}
return ResponseVO.success(devices);
}
@PostMapping(value = "/unbind")
@Operation(summary = "WEB端APP客户设备解绑")
public ResponseVO<String> unbindAPPDevice(@Validated @ModelAttribute APPUnbindDTO deviceForm) {
appDeviceService.unbindAPPDevice(deviceForm);
return ResponseVO.success("解绑成功!!!");
}
}

View File

@ -0,0 +1,106 @@
package com.fuyuanshen.app.domain;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* @Description: 设备表
* @Author: WY
* @Date: 2025/5/16
**/
@Data
@TableName("app_device")
public class APPDevice extends TenantEntity {
@TableId(value = "app_device_id", type = IdType.AUTO)
@Schema(name = "ID")
private Long id;
@Schema(name = "设备类型")
private Long deviceType;
@Schema(name = "设备类型名称")
private String deviceTypeName;
@Schema(name = "客户号")
private Long customerId;
@Schema(name = "所属客户")
private String customerName;
/*@Schema(name = "设备编号")
private String deviceNo;*/
@Schema(name = "设备名称")
private String deviceName;
@Schema(name = "设备图片")
private String devicePic;
@Schema(name = "设备MAC")
private String deviceMac;
@Schema(name = "设备IMEI")
private String deviceImei;
@Schema(name = "设备SN")
private String deviceSn;
@Schema(name = "经度")
private String longitude;
@Schema(name = "纬度")
private String latitude;
@Schema(name = "备注")
private String remark;
@TableField(exist = false)
@Schema(name = "设备类型名称")
private String typeName;
/**
* 租户ID
*/
@TableField(value = "tenant_id")
@Schema(hidden = true)
private String tenantId;
/**
* 设备状态
* 0 失效
* 1 正常
*/
@Schema(name = "设备状态")
private Integer deviceStatus;
/**
* 绑定状态
* 0 未绑定
* 1 已绑定
*/
@Schema(name = "绑定状态")
private Integer bindingStatus;
/**
* 绑定类型
* 0 APP
* 1 小程序
*/
@Schema(name = "绑定类型")
private Integer bindingType;
public void copy(APPDevice source) {
BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
}
}

View File

@ -0,0 +1,56 @@
package com.fuyuanshen.app.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serializable;
/**
* @Description: 设备类型
* @Author: WY
* @Date: 2025/5/14
**/
@Data
@TableName("app_device_type")
public class APPDeviceType extends TenantEntity {
@TableId(value = "id", type = IdType.AUTO)
@Schema(name = "ID", hidden = true)
private Long id;
@Schema(name = "客户号")
private Long customerId;
@Schema(name = "创建该类型的客户")
private Long ownerCustomerId;
/**
* 租户ID
*/
// @TableField(value = "tenant_id")
// @ApiModelProperty(hidden = true)
// private Long tenantId;
@NotBlank(message = "设备类型名称不能为空")
@Schema(name = "类型名称", required = true)
private String typeName;
@Schema(name = "是否支持蓝牙")
private Boolean isSupportBle;
@Schema(name = "定位方式", example = "0:无;1:GPS;2:基站;3:wifi;4:北斗")
private String locateMode;
@Schema(name = "联网方式", example = "0:无;1:4G;2:WIFI")
private String networkWay;
@Schema(name = "通讯方式", example = "0:4G;1:蓝牙")
private String communicationMode;
}

View File

@ -0,0 +1,51 @@
package com.fuyuanshen.app.domain;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* app业务文件对象 app_business_file
*
* @author Lion Li
* @date 2025-07-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("app_business_file")
public class AppBusinessFile extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 文件id
*/
private Long fileId;
/**
* 业务id
*/
private Long businessId;
/**
* 文件类型(1:操作说明2:产品参数)
*/
private Long fileType;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,51 @@
package com.fuyuanshen.app.domain;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* 操作视频对象 app_operation_video
*
* @author Lion Li
* @date 2025-07-02
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("app_operation_video")
public class AppOperationVideo extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 视频名称
*/
private String videoName;
/**
* 视频链接
*/
private String videoUrl;
/**
* 设备di
*/
private Long deviceId;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,55 @@
package com.fuyuanshen.app.domain;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
/**
* 人员信息登记对象 app_personnel_info
*
* @author Lion Li
* @date 2025-07-02
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("app_personnel_info")
public class AppPersonnelInfo extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 设备id
*/
private Long deviceId;
/**
* 人员姓名
*/
private String name;
/**
* 部门名称
*/
private String deptName;
/**
* 单位名称
*/
private String unitName;
/**
* 发送信息
*/
private String sendMsg;
}

View File

@ -0,0 +1,52 @@
package com.fuyuanshen.app.domain.bo;
import com.fuyuanshen.app.domain.AppBusinessFile;
import com.fuyuanshen.common.core.validate.EditGroup;
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.List;
/**
* app业务文件业务对象 app_business_file
*
* @author Lion Li
* @date 2025-07-03
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = AppBusinessFile.class, reverseConvertGenerate = false)
public class AppBusinessFileBo extends BaseEntity {
/**
* 主键id
*/
@NotNull(message = "主键id不能为空", groups = { EditGroup.class })
private Long id;
/**
* 文件id
*/
private Long fileId;
/**
* 业务id
*/
private Long businessId;
/**
* 文件类型(1:操作说明2:产品参数)
*/
private Long fileType;
/**
* 备注
*/
private String remark;
private List<Long> ids;
}

View File

@ -0,0 +1,49 @@
package com.fuyuanshen.app.domain.bo;
import com.fuyuanshen.app.domain.AppOperationVideo;
import com.fuyuanshen.common.core.validate.EditGroup;
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 操作视频业务对象 app_operation_video
*
* @author Lion Li
* @date 2025-07-02
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = AppOperationVideo.class, reverseConvertGenerate = false)
public class AppOperationVideoBo extends BaseEntity {
/**
* 主键id
*/
@NotNull(message = "主键id不能为空", groups = { EditGroup.class })
private Long id;
/**
* 视频名称
*/
private String videoName;
/**
* 视频链接
*/
private String videoUrl;
/**
* 设备di
*/
private Long deviceId;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,56 @@
package com.fuyuanshen.app.domain.bo;
import com.fuyuanshen.app.domain.AppPersonnelInfo;
import com.fuyuanshen.common.core.validate.AddGroup;
import com.fuyuanshen.common.core.validate.EditGroup;
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 人员信息登记业务对象 app_personnel_info
*
* @author Lion Li
* @date 2025-07-02
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = AppPersonnelInfo.class, reverseConvertGenerate = false)
public class AppPersonnelInfoBo extends BaseEntity {
/**
* 主键
*/
@NotNull(message = "主键不能为空", groups = { AddGroup.class, EditGroup.class })
private Long id;
/**
* 设备id
*/
@NotNull(message = "设备id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long deviceId;
/**
* 人员姓名
*/
private String name;
/**
* 部门名称
*/
private String deptName;
/**
* 单位名称
*/
private String unitName;
/**
* 发送信息
*/
private String sendMsg;
}

View File

@ -0,0 +1,26 @@
package com.fuyuanshen.app.domain.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* @author: 默苍璃
* @date: 2025-06-1818:36
*/
@Data
public class APPUnbindDTO {
// @NotBlank(message = "设备MAC不能为空")
@Schema(name = "设备MAC", required = true)
private String deviceMac;
@Schema(name = "设备IMEI")
private String deviceImei;
@NotNull(message = "客户号不能为空")
@Schema(name = "客户号")
private Long customerId;
}

View File

@ -0,0 +1,65 @@
package com.fuyuanshen.app.domain.query;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.sql.Timestamp;
import java.util.List;
import java.util.Set;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
@Data
public class APPDeviceQueryCriteria {
@Schema(name = "设备名称")
private String deviceName;
@Schema(name = "设备类型")
private Long deviceType;
@Schema(name = "设备MAC")
private String deviceMac;
@Schema(name = "设备IMEI")
private String deviceImei;
@Schema(name = "设备SN")
private String deviceSn;
/**
* 设备状态
* 0 失效
* 1 正常
*/
@Schema(name = "设备状态 0 失效 1 正常 ")
private Integer deviceStatus;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
@Schema(name = "创建时间")
private List<Timestamp> createTime;
@Schema(name = "页码", example = "1")
private Integer page = 1;
@Schema(name = "每页数据量", example = "10")
private Integer size = 10;
@Schema(name = "客户id")
private Long customerId;
private Set<Long> customerIds;
@Schema(name = "当前所有者")
private Long currentOwnerId;
@Schema(name = "租户ID")
private Long tenantId;
@Schema(name = "通讯方式", example = "0:4G;1:蓝牙")
private Integer communicationMode;
}

View File

@ -0,0 +1,62 @@
package com.fuyuanshen.app.domain.vo;
import com.fuyuanshen.app.domain.AppBusinessFile;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fuyuanshen.common.excel.annotation.ExcelDictFormat;
import com.fuyuanshen.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;
/**
* app业务文件视图对象 app_business_file
*
* @author Lion Li
* @date 2025-07-03
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = AppBusinessFile.class)
public class AppBusinessFileVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long id;
/**
* 文件id
*/
@ExcelProperty(value = "文件id")
private Long fileId;
/**
* 业务id
*/
@ExcelProperty(value = "业务id")
private Long businessId;
/**
* 文件类型(1:操作说明2:产品参数)
*/
@ExcelProperty(value = "文件类型(1:操作说明2:产品参数)")
private Long fileType;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@ -0,0 +1,21 @@
package com.fuyuanshen.app.domain.vo;
import lombok.Data;
@Data
public class AppFileVo {
private Long id;
/**
* 文件id
*/
private Long fileId;
/**
* 文件名称
*/
private String fileName;
/**
* 文件url
*/
private String fileUrl;
}

View File

@ -0,0 +1,62 @@
package com.fuyuanshen.app.domain.vo;
import com.fuyuanshen.app.domain.AppOperationVideo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fuyuanshen.common.excel.annotation.ExcelDictFormat;
import com.fuyuanshen.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;
/**
* 操作视频视图对象 app_operation_video
*
* @author Lion Li
* @date 2025-07-02
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = AppOperationVideo.class)
public class AppOperationVideoVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long id;
/**
* 视频名称
*/
@ExcelProperty(value = "视频名称")
private String videoName;
/**
* 视频链接
*/
@ExcelProperty(value = "视频链接")
private String videoUrl;
/**
* 设备di
*/
@ExcelProperty(value = "设备di")
private Long deviceId;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@ -0,0 +1,68 @@
package com.fuyuanshen.app.domain.vo;
import com.fuyuanshen.app.domain.AppPersonnelInfo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fuyuanshen.common.excel.annotation.ExcelDictFormat;
import com.fuyuanshen.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;
/**
* 人员信息登记视图对象 app_personnel_info
*
* @author Lion Li
* @date 2025-07-02
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = AppPersonnelInfo.class)
public class AppPersonnelInfoVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ExcelProperty(value = "主键")
private Long id;
/**
* 设备id
*/
@ExcelProperty(value = "设备id")
private Long deviceId;
/**
* 人员姓名
*/
@ExcelProperty(value = "人员姓名")
private String name;
/**
* 部门名称
*/
@ExcelProperty(value = "部门名称")
private String deptName;
/**
* 单位名称
*/
@ExcelProperty(value = "单位名称")
private String unitName;
/**
* 发送信息
*/
@ExcelProperty(value = "发送信息")
private String sendMsg;
}

View File

@ -0,0 +1,20 @@
package com.fuyuanshen.app.mapper;
import com.fuyuanshen.app.domain.AppBusinessFile;
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
import com.fuyuanshen.app.domain.vo.AppFileVo;
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* app业务文件Mapper接口
*
* @author Lion Li
* @date 2025-07-03
*/
public interface AppBusinessFileMapper extends BaseMapperPlus<AppBusinessFile, AppBusinessFileVo> {
List<AppFileVo> queryAppFileList(AppBusinessFileBo bo);
}

View File

@ -0,0 +1,17 @@
package com.fuyuanshen.app.mapper;
import com.fuyuanshen.app.domain.AppOperationVideo;
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Mapper;
/**
* 操作视频Mapper接口
*
* @author Lion Li
* @date 2025-07-02
*/
@Mapper
public interface AppOperationVideoMapper extends BaseMapperPlus<AppOperationVideo, AppOperationVideoVo> {
}

View File

@ -0,0 +1,17 @@
package com.fuyuanshen.app.mapper;
import com.fuyuanshen.app.domain.AppPersonnelInfo;
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Mapper;
/**
* 人员信息登记Mapper接口
*
* @author Lion Li
* @date 2025-07-02
*/
@Mapper
public interface AppPersonnelInfoMapper extends BaseMapperPlus<AppPersonnelInfo, AppPersonnelInfoVo> {
}

View File

@ -0,0 +1,39 @@
package com.fuyuanshen.app.mapper.equipment;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.app.domain.APPDevice;
import com.fuyuanshen.app.domain.query.APPDeviceQueryCriteria;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
@Mapper
public interface APPDeviceMapper extends BaseMapper<APPDevice> {
/**
* APP用户设备列表
*
* @param page
* @param criteria
* @return
*/
IPage<APPDevice> appDeviceList(Page<APPDevice> page,@Param("criteria") APPDeviceQueryCriteria criteria);
/**
* 分页查询APP/小程序设备
*
* @param criteria
* @param page
* @return
*/
IPage<APPDevice> queryAll(Page<APPDevice> page, @Param("criteria") APPDeviceQueryCriteria criteria);
}

View File

@ -0,0 +1,72 @@
package com.fuyuanshen.app.service;
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
import com.fuyuanshen.app.domain.vo.AppFileVo;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* app业务文件Service接口
*
* @author Lion Li
* @date 2025-07-03
*/
public interface IAppBusinessFileService {
/**
* 查询app业务文件
*
* @param id 主键
* @return app业务文件
*/
AppBusinessFileVo queryById(Long id);
/**
* 分页查询app业务文件列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return app业务文件分页列表
*/
TableDataInfo<AppBusinessFileVo> queryPageList(AppBusinessFileBo bo, PageQuery pageQuery);
/**
* 查询符合条件的app业务文件列表
*
* @param bo 查询条件
* @return app业务文件列表
*/
List<AppBusinessFileVo> queryList(AppBusinessFileBo bo);
/**
* 新增app业务文件
*
* @param bo app业务文件
* @return 是否新增成功
*/
Boolean insertByBo(AppBusinessFileBo bo);
/**
* 修改app业务文件
*
* @param bo app业务文件
* @return 是否修改成功
*/
Boolean updateByBo(AppBusinessFileBo bo);
/**
* 校验并批量删除app业务文件信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
List<AppFileVo> queryAppFileList(AppBusinessFileBo bo);
}

View File

@ -0,0 +1,68 @@
package com.fuyuanshen.app.service;
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 操作视频Service接口
*
* @author Lion Li
* @date 2025-07-02
*/
public interface IAppOperationVideoService {
/**
* 查询操作视频
*
* @param id 主键
* @return 操作视频
*/
AppOperationVideoVo queryById(Long id);
/**
* 分页查询操作视频列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 操作视频分页列表
*/
TableDataInfo<AppOperationVideoVo> queryPageList(AppOperationVideoBo bo, PageQuery pageQuery);
/**
* 查询符合条件的操作视频列表
*
* @param bo 查询条件
* @return 操作视频列表
*/
List<AppOperationVideoVo> queryList(AppOperationVideoBo bo);
/**
* 新增操作视频
*
* @param bo 操作视频
* @return 是否新增成功
*/
Boolean insertByBo(AppOperationVideoBo bo);
/**
* 修改操作视频
*
* @param bo 操作视频
* @return 是否修改成功
*/
Boolean updateByBo(AppOperationVideoBo bo);
/**
* 校验并批量删除操作视频信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -0,0 +1,68 @@
package com.fuyuanshen.app.service;
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 人员信息登记Service接口
*
* @author Lion Li
* @date 2025-07-02
*/
public interface IAppPersonnelInfoService {
/**
* 查询人员信息登记
*
* @param id 主键
* @return 人员信息登记
*/
AppPersonnelInfoVo queryById(Long id);
/**
* 分页查询人员信息登记列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 人员信息登记分页列表
*/
TableDataInfo<AppPersonnelInfoVo> queryPageList(AppPersonnelInfoBo bo, PageQuery pageQuery);
/**
* 查询符合条件的人员信息登记列表
*
* @param bo 查询条件
* @return 人员信息登记列表
*/
List<AppPersonnelInfoVo> queryList(AppPersonnelInfoBo bo);
/**
* 新增人员信息登记
*
* @param bo 人员信息登记
* @return 是否新增成功
*/
Boolean insertByBo(AppPersonnelInfoBo bo);
/**
* 修改人员信息登记
*
* @param bo 人员信息登记
* @return 是否修改成功
*/
Boolean updateByBo(AppPersonnelInfoBo bo);
/**
* 校验并批量删除人员信息登记信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@ -0,0 +1,60 @@
package com.fuyuanshen.app.service.equipment;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fuyuanshen.app.domain.APPDevice;
import com.fuyuanshen.app.domain.APPDeviceType;
import com.fuyuanshen.app.domain.dto.APPUnbindDTO;
import com.fuyuanshen.app.domain.query.APPDeviceQueryCriteria;
import com.fuyuanshen.common.core.domain.PageResult;
import java.util.List;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
public interface APPDeviceService extends IService<APPDevice> {
/**
* APP用户设备列表
*
* @param criteria
*/
PageResult<APPDevice> appDeviceList(Page<APPDevice> page, APPDeviceQueryCriteria criteria);
/**
* APP用户设备类型列表
*
* @param criteria
* @return
*/
List<APPDeviceType> appTypeList(APPDeviceQueryCriteria criteria);
/**
* APP/小程序用户设备绑定
*
* @param criteria
*/
void appBindDevice(APPDeviceQueryCriteria criteria);
/**
* 分页查询APP/小程序设备绑定
*
* @param criteria
* @param page
* @return
*/
PageResult<APPDevice> queryAll(Page<APPDevice> page, APPDeviceQueryCriteria criteria);
/**
* APP/小程序用户设备解绑
*
* @param deviceForm
*/
void unbindAPPDevice(APPUnbindDTO deviceForm);
}

View File

@ -0,0 +1,142 @@
package com.fuyuanshen.app.service.impl;
import com.fuyuanshen.app.domain.vo.AppFileVo;
import com.fuyuanshen.common.core.utils.MapstructUtils;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.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 lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.fuyuanshen.app.domain.bo.AppBusinessFileBo;
import com.fuyuanshen.app.domain.vo.AppBusinessFileVo;
import com.fuyuanshen.app.domain.AppBusinessFile;
import com.fuyuanshen.app.mapper.AppBusinessFileMapper;
import com.fuyuanshen.app.service.IAppBusinessFileService;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* app业务文件Service业务层处理
*
* @author Lion Li
* @date 2025-07-03
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class AppBusinessFileServiceImpl implements IAppBusinessFileService {
private final AppBusinessFileMapper baseMapper;
/**
* 查询app业务文件
*
* @param id 主键
* @return app业务文件
*/
@Override
public AppBusinessFileVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 分页查询app业务文件列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return app业务文件分页列表
*/
@Override
public TableDataInfo<AppBusinessFileVo> queryPageList(AppBusinessFileBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<AppBusinessFile> lqw = buildQueryWrapper(bo);
Page<AppBusinessFileVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的app业务文件列表
*
* @param bo 查询条件
* @return app业务文件列表
*/
@Override
public List<AppBusinessFileVo> queryList(AppBusinessFileBo bo) {
LambdaQueryWrapper<AppBusinessFile> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<AppBusinessFile> buildQueryWrapper(AppBusinessFileBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<AppBusinessFile> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(AppBusinessFile::getId);
lqw.eq(bo.getFileId()!=null, AppBusinessFile::getFileId, bo.getFileId());
lqw.eq(bo.getBusinessId() != null, AppBusinessFile::getBusinessId, bo.getBusinessId());
lqw.eq(bo.getFileType() != null, AppBusinessFile::getFileType, bo.getFileType());
lqw.in(bo.getIds()!=null, AppBusinessFile::getId, bo.getIds());
return lqw;
}
/**
* 新增app业务文件
*
* @param bo app业务文件
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(AppBusinessFileBo bo) {
AppBusinessFile add = MapstructUtils.convert(bo, AppBusinessFile.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改app业务文件
*
* @param bo app业务文件
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(AppBusinessFileBo bo) {
AppBusinessFile update = MapstructUtils.convert(bo, AppBusinessFile.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(AppBusinessFile entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除app业务文件信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
@Override
public List<AppFileVo> queryAppFileList(AppBusinessFileBo bo) {
return baseMapper.queryAppFileList(bo);
}
}

View File

@ -0,0 +1,134 @@
package com.fuyuanshen.app.service.impl;
import com.fuyuanshen.common.core.utils.MapstructUtils;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.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 lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.fuyuanshen.app.domain.bo.AppOperationVideoBo;
import com.fuyuanshen.app.domain.vo.AppOperationVideoVo;
import com.fuyuanshen.app.domain.AppOperationVideo;
import com.fuyuanshen.app.mapper.AppOperationVideoMapper;
import com.fuyuanshen.app.service.IAppOperationVideoService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 操作视频Service业务层处理
*
* @author Lion Li
* @date 2025-07-02
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class AppOperationVideoServiceImpl implements IAppOperationVideoService {
private final AppOperationVideoMapper baseMapper;
/**
* 查询操作视频
*
* @param id 主键
* @return 操作视频
*/
@Override
public AppOperationVideoVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 分页查询操作视频列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 操作视频分页列表
*/
@Override
public TableDataInfo<AppOperationVideoVo> queryPageList(AppOperationVideoBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<AppOperationVideo> lqw = buildQueryWrapper(bo);
Page<AppOperationVideoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的操作视频列表
*
* @param bo 查询条件
* @return 操作视频列表
*/
@Override
public List<AppOperationVideoVo> queryList(AppOperationVideoBo bo) {
LambdaQueryWrapper<AppOperationVideo> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<AppOperationVideo> buildQueryWrapper(AppOperationVideoBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<AppOperationVideo> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(AppOperationVideo::getId);
lqw.like(StringUtils.isNotBlank(bo.getVideoName()), AppOperationVideo::getVideoName, bo.getVideoName());
lqw.eq(StringUtils.isNotBlank(bo.getVideoUrl()), AppOperationVideo::getVideoUrl, bo.getVideoUrl());
lqw.eq(bo.getDeviceId() != null, AppOperationVideo::getDeviceId, bo.getDeviceId());
return lqw;
}
/**
* 新增操作视频
*
* @param bo 操作视频
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(AppOperationVideoBo bo) {
AppOperationVideo add = MapstructUtils.convert(bo, AppOperationVideo.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改操作视频
*
* @param bo 操作视频
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(AppOperationVideoBo bo) {
AppOperationVideo update = MapstructUtils.convert(bo, AppOperationVideo.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(AppOperationVideo entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除操作视频信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

View File

@ -0,0 +1,135 @@
package com.fuyuanshen.app.service.impl;
import com.fuyuanshen.common.core.utils.MapstructUtils;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.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 lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo;
import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo;
import com.fuyuanshen.app.domain.AppPersonnelInfo;
import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper;
import com.fuyuanshen.app.service.IAppPersonnelInfoService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 人员信息登记Service业务层处理
*
* @author Lion Li
* @date 2025-07-02
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class AppPersonnelInfoServiceImpl implements IAppPersonnelInfoService {
private final AppPersonnelInfoMapper baseMapper;
/**
* 查询人员信息登记
*
* @param id 主键
* @return 人员信息登记
*/
@Override
public AppPersonnelInfoVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 分页查询人员信息登记列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 人员信息登记分页列表
*/
@Override
public TableDataInfo<AppPersonnelInfoVo> queryPageList(AppPersonnelInfoBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<AppPersonnelInfo> lqw = buildQueryWrapper(bo);
Page<AppPersonnelInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的人员信息登记列表
*
* @param bo 查询条件
* @return 人员信息登记列表
*/
@Override
public List<AppPersonnelInfoVo> queryList(AppPersonnelInfoBo bo) {
LambdaQueryWrapper<AppPersonnelInfo> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<AppPersonnelInfo> buildQueryWrapper(AppPersonnelInfoBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<AppPersonnelInfo> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getDeviceId() != null, AppPersonnelInfo::getDeviceId, bo.getDeviceId());
lqw.like(StringUtils.isNotBlank(bo.getName()), AppPersonnelInfo::getName, bo.getName());
lqw.like(StringUtils.isNotBlank(bo.getDeptName()), AppPersonnelInfo::getDeptName, bo.getDeptName());
lqw.like(StringUtils.isNotBlank(bo.getUnitName()), AppPersonnelInfo::getUnitName, bo.getUnitName());
lqw.eq(StringUtils.isNotBlank(bo.getSendMsg()), AppPersonnelInfo::getSendMsg, bo.getSendMsg());
return lqw;
}
/**
* 新增人员信息登记
*
* @param bo 人员信息登记
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(AppPersonnelInfoBo bo) {
AppPersonnelInfo add = MapstructUtils.convert(bo, AppPersonnelInfo.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改人员信息登记
*
* @param bo 人员信息登记
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(AppPersonnelInfoBo bo) {
AppPersonnelInfo update = MapstructUtils.convert(bo, AppPersonnelInfo.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(AppPersonnelInfo entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除人员信息登记信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

View File

@ -0,0 +1,182 @@
package com.fuyuanshen.app.service.impl.equipment;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyuanshen.app.domain.APPDevice;
import com.fuyuanshen.app.domain.APPDeviceType;
import com.fuyuanshen.app.domain.dto.APPUnbindDTO;
import com.fuyuanshen.app.domain.query.APPDeviceQueryCriteria;
import com.fuyuanshen.app.mapper.equipment.APPDeviceMapper;
import com.fuyuanshen.app.service.equipment.APPDeviceService;
import com.fuyuanshen.common.core.domain.PageResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
@Slf4j
@Service
@RequiredArgsConstructor
public class APPDeviceServiceImpl extends ServiceImpl<APPDeviceMapper, APPDevice> implements APPDeviceService {
private final APPDeviceMapper appDeviceMapper;
/**
* APP用户设备列表
*
* @param criteria
*/
@Override
public PageResult<APPDevice> appDeviceList(Page<APPDevice> page, APPDeviceQueryCriteria criteria) {
// criteria.setCustomerId(SecurityUtils.getCurrentUserId());
// IPage<APPDevice> devices = appDeviceMapper.appDeviceList(page, criteria);
// return new PageResult<>(devices.getRecords(), devices.getTotal());
return null;
}
/**
* APP用户设备类型列表
*
* @param criteria
* @return
*/
@Override
public List<APPDeviceType> appTypeList(APPDeviceQueryCriteria criteria) {
// criteria.setCustomerId(SecurityUtils.getCurrentUserId());
// return appDeviceTypeMapper.appTypeList(criteria);
return null;
}
/**
* APP/小程序用户设备绑定
*
* @param criteria
*/
@Override
@Transactional
public void appBindDevice(APPDeviceQueryCriteria criteria) {
//
// List<Device> devices = new ArrayList<>();
//
// if (criteria.getCommunicationMode().equals(CommunicationModeEnum.BLUETOOTH.getValue())) {
// devices = deviceMapper.selectList(new QueryWrapper<Device>().eq("device_mac", criteria.getDeviceMac()));
// if (CollectionUtil.isEmpty(devices)) {
// throw new BadRequestException("请先将设备入库!!!");
// }
// List<APPDevice> appDevices = appDeviceMapper.selectList(new QueryWrapper<APPDevice>()
// .eq("device_mac", criteria.getDeviceMac()).eq("binding_type", UserType.APP.getValue()));
// if (CollectionUtil.isNotEmpty(appDevices)) {
// throw new BadRequestException("该设备已绑定!!!");
// }
// }
//
// if (criteria.getCommunicationMode().equals(CommunicationModeEnum.FOUR_G.getValue())) {
// devices = deviceMapper.selectList(new QueryWrapper<Device>().eq("device_imei", criteria.getDeviceImei()));
// if (CollectionUtil.isEmpty(devices)) {
// throw new BadRequestException("请先将设备入库!!!");
// }
// List<APPDevice> appDevices = appDeviceMapper.selectList(new QueryWrapper<APPDevice>()
// .eq("device_imei", criteria.getDeviceImei()).eq("binding_type", UserType.APP.getValue()));
// if (CollectionUtil.isNotEmpty(appDevices)) {
// throw new BadRequestException("该设备已绑定!!!");
// }
// }
//
// Device device = devices.get(0);
// device.setBindingStatus(BindingStatusEnum.BOUND.getCode());
// deviceMapper.updateById(device);
//
// APPDevice appDevice = new APPDevice();
// BeanUtil.copyProperties(device, appDevice);
// appDevice.setBindingType(UserType.APP.getValue());
// appDevice.setBindingStatus(BindingStatusEnum.BOUND.getCode());
// Long currentUserId = SecurityUtils.getCurrentUserId();
// appDevice.setCustomerId(currentUserId);
// appDevice.setCreateTime(new Timestamp(System.currentTimeMillis()));
// // 设备类型名称
// appDevice.setDeviceTypeName(device.getTypeName());
// appDeviceMapper.insert(appDevice);
//
// APPDeviceType appDeviceType = appDeviceTypeMapper.selectById(device.getDeviceType());
// if (appDeviceType == null) {
// DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
// APPDeviceType type = new APPDeviceType();
// BeanUtil.copyProperties(deviceType, type);
// type.setCustomerId(currentUserId);
// appDeviceTypeMapper.insert(type);
// }
}
/**
* 分页查询APP/小程序设备
*
* @param criteria
* @param page
* @return
*/
@Override
public PageResult<APPDevice> queryAll(Page<APPDevice> page, APPDeviceQueryCriteria criteria) {
// IPage<APPDevice> devices = appDeviceMapper.queryAll(page, criteria);
// return new PageResult<>(devices.getRecords(), devices.getTotal());
return null;
}
/**
* APP/小程序用户设备解绑
*
* @param deviceForm
*/
@Override
@Transactional
public void unbindAPPDevice(APPUnbindDTO deviceForm) {
// QueryWrapper<APPDevice> queryWrapper = new QueryWrapper<>();
// QueryWrapper<Device> qw = new QueryWrapper<>();
// if (StringUtils.isNotEmpty(deviceForm.getDeviceMac())) {
// queryWrapper.eq("device_mac", deviceForm.getDeviceMac());
// qw.eq("device_mac", deviceForm.getDeviceMac());
// }
// if (StringUtils.isNotEmpty(deviceForm.getDeviceImei())) {
// queryWrapper.eq("device_imei", deviceForm.getDeviceImei());
// qw.eq("device_imei", deviceForm.getDeviceImei());
// }
// queryWrapper.eq("binding_type", UserType.APP.getValue());
// APPDevice appDevice = appDeviceMapper.selectOne(queryWrapper);
// appDeviceMapper.delete(queryWrapper);
//
// List<Device> devices = deviceMapper.selectList(qw);
// List<Long> ids = devices.stream()
// .map(Device::getId)
// .collect(Collectors.toList());
// if (CollectionUtil.isNotEmpty(ids)) {
// appDeviceTypeMapper.deleteBatchIds(ids);
// }
// Device device = new Device();
// device.setId(appDevice.getId());
// device.setBindingStatus(BindingStatusEnum.UNBOUND.getCode());
// deviceMapper.updateById(device);
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fuyuanshen.app.mapper.AppBusinessFileMapper">
<select id="queryAppFileList" resultType="com.fuyuanshen.app.domain.vo.AppFileVo">
select a.business_id id,a.file_id,b.file_name,b.url fileUrl from app_business_file a left join sys_oss b on a.file_id = b.oss_id
where
<if test="businessId != null">
and a.business_id = #{businessId}
</if>
<if test="fileId != null">
and a.file_id = #{fileId}
</if>
<if test="createBy != null">
a.create_by = #{createBy}
</if>
order by a.create_time desc
</select>
</mapper>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fuyuanshen.app.mapper.AppOperationVideoMapper">
</mapper>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fuyuanshen.app.mapper.AppPersonnelInfoMapper">
</mapper>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.fuyuanshen.app.mapper.equipment.APPDeviceMapper">
<resultMap id="BaseResultMap" type="com.fuyuanshen.app.domain.APPDevice">
<id column="id" property="id"/>
<result column="device_type" property="deviceType"/>
<result column="customer_id" property="customerId"/>
<!--<result column="device_no" property="deviceNo"/>-->
<result column="device_name" property="deviceName"/>
<result column="device_pic" property="devicePic"/>
<result column="device_mac" property="deviceMac"/>
<result column="device_sn" property="deviceSn"/>
<result column="device_status" property="deviceStatus"/>
<result column="remark" property="remark"/>
<result column="create_by" property="createBy"/>
<result column="update_by" property="updateBy"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
<result column="binding_status" property="bindingStatus"/>
</resultMap>
<!-- APP用户设备列表 -->
<select id="appDeviceList" resultType="com.fuyuanshen.app.domain.APPDevice">
select d.* from app_device as d
<where>
<!-- 时间范围等其他条件保持原样 -->
<if test="criteria.deviceName != null and criteria.deviceName.trim() != ''">
and d.device_name like concat('%', TRIM(#{criteria.deviceName}), '%')
</if>
<if test="criteria.deviceMac != null and criteria.deviceMac.trim() != ''">
and d.device_mac = #{criteria.deviceMac}
</if>
<if test="criteria.deviceImei != null and criteria.deviceImei.trim() != ''">
and d.device_imei = #{criteria.deviceImei}
</if>
<if test="criteria.deviceSn != null">
and d.device_sn = #{criteria.deviceSn}
</if>
<if test="criteria.deviceType != null">
and d.device_type = #{criteria.deviceType}
</if>
<if test="criteria.deviceStatus != null">
and d.device_status = #{criteria.deviceStatus}
</if>
<if test="criteria.createTime != null and criteria.createTime.size() != 0">
and d.create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]}
</if>
<if test="criteria.tenantId != null">
AND tenant_id = #{criteria.tenantId}
</if>
and d.customer_id = #{criteria.customerId}
</where>
order by d.create_time desc
</select>
<!-- 分页查询APP/小程序设备 -->
<select id="queryAll" resultType="com.fuyuanshen.app.domain.APPDevice">
select d.* from app_device as d
<where>
<!-- 时间范围等其他条件保持原样 -->
<if test="criteria.deviceName != null and criteria.deviceName.trim() != ''">
and d.device_name like concat('%', TRIM(#{criteria.deviceName}), '%')
</if>
<if test="criteria.deviceMac != null and criteria.deviceMac.trim() != ''">
and d.device_mac = #{criteria.deviceMac}
</if>
<if test="criteria.deviceImei != null and criteria.deviceImei.trim() != ''">
and d.device_imei = #{criteria.deviceImei}
</if>
<if test="criteria.deviceSn != null">
and d.device_sn = #{criteria.deviceSn}
</if>
<if test="criteria.deviceType != null">
and d.device_type = #{criteria.deviceType}
</if>
<if test="criteria.deviceStatus != null">
and d.device_status = #{criteria.deviceStatus}
</if>
<if test="criteria.createTime != null and criteria.createTime.size() != 0">
and d.create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]}
</if>
<if test="criteria.tenantId != null">
AND tenant_id = #{criteria.tenantId}
</if>
and d.customer_id = #{criteria.customerId}
</where>
order by d.create_time desc
</select>
</mapper>

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-modules</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fys-customer</artifactId>
<description>
富源晟客户管理
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-core</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-doc</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-mybatis</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-translation</artifactId>
</dependency>
<!-- OSS功能模块 -->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-oss</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-log</artifactId>
</dependency>
<!-- excel-->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-excel</artifactId>
</dependency>
<!-- SMS功能模块 -->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-sms</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-tenant</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-security</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-web</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-idempotent</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-sensitive</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-encrypt</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-sse</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.1</version>
<exclusions>
<exclusion>
<artifactId>poi-ooxml-schemas</artifactId>
<groupId>org.apache.poi</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,94 @@
package com.fuyuanshen.customer.controller;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.common.core.domain.ResponseVO;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.customer.domain.Customer;
import com.fuyuanshen.customer.domain.query.UserQueryCriteria;
import com.fuyuanshen.customer.domain.vo.ConsumerVo;
import com.fuyuanshen.customer.service.CustomerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.undertow.util.BadRequestException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Set;
/**
* @author: 默苍璃
* @date: 2025-07-0114:20
*/
@Slf4j
@Tag(name = "WEB客户管理", description = "WEB客户管理")
@RestController
@RequestMapping("/api/customers")
@RequiredArgsConstructor
public class CustomerController {
private final CustomerService customerService;
/**
* 分页查询客户(限制子客户)
*
* @param criteria
* @return
*/
@Operation(summary = "分页查询客户")
@GetMapping(value = "/customer")
public TableDataInfo<ConsumerVo> queryCustomer(UserQueryCriteria criteria) {
Page<Customer> page = new Page<>(criteria.getPageNum(), criteria.getPageSize());
return customerService.queryCustomers(criteria, page);
}
@GetMapping(value = "/allCustomer")
@Operation(summary = "查询所有客户")
public ResponseVO<List<Customer>> queryAllCustomer(UserQueryCriteria criteria) {
List<Customer> customers = customerService.queryAllCustomers(criteria);
return ResponseVO.success(customers);
}
// @Log("新增客户")
@Operation(summary = "新增客户")
@PostMapping(value = "/addCustomer")
public ResponseVO<Object> addCustomer(@Validated @RequestBody Customer customer) throws BadRequestException {
if (StringUtils.isBlank(customer.getPassword())) {
throw new BadRequestException("账号密码不能为空");
}
customer.setPassword(BCrypt.hashpw(customer.getPassword()));
customerService.addCustomer(customer);
return ResponseVO.success("新增客户成功!!!");
}
// @Log("修改客户")
@Operation(summary = "修改客户")
@PutMapping(value = "updateCustomer")
public ResponseVO<Object> updateCustomer(@RequestBody Customer resources) throws Exception {
customerService.updateCustomer(resources);
return ResponseVO.success(null);
}
// @Log("删除客户")
@Operation(summary = "删除客户")
@DeleteMapping(value = "/deleteCustomer")
public ResponseVO<Object> deleteCustomer(@RequestBody Set<Long> ids) throws BadRequestException {
if (CollectionUtil.isEmpty(ids)) {
throw new BadRequestException("请选择要删除的客户");
}
customerService.delete(ids);
return ResponseVO.success(null);
}
}

View File

@ -0,0 +1,131 @@
package com.fuyuanshen.customer.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fuyuanshen.common.core.constant.SystemConstants;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* 用户对象 sys_user
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@TableName("sys_user")
public class Customer extends TenantEntity {
/**
* 用户ID
*/
@TableId(value = "user_id")
private Long customerId;
/**
* 父id
*/
private Long pid;
/**
* 部门ID
*/
private Long deptId;
/**
* 用户账号
*/
@NotNull
private String userName;
/**
* 用户昵称
*/
@NotNull
private String nickName;
@TableField(value = "user_level")
private Byte userLevel;
/**
* 用户类型sys_user系统用户
*/
private String userType;
/**
* 用户邮箱
*/
private String email;
/**
* 手机号码
*/
private String phonenumber;
/**
* 用户性别
*/
private String sex;
/**
* 用户头像
*/
private Long avatar;
/**
* 密码
*/
@TableField(
insertStrategy = FieldStrategy.NOT_EMPTY,
updateStrategy = FieldStrategy.NOT_EMPTY,
whereStrategy = FieldStrategy.NOT_EMPTY
)
private String password;
/**
* 帐号状态0正常 1停用
*/
private String status;
/**
* 删除标志0代表存在 1代表删除
*/
@TableLogic
private String delFlag;
@NotNull
@Schema(name = "是否启用")
private Boolean enabled;
/**
* 最后登录IP
*/
private String loginIp;
/**
* 最后登录时间
*/
private Date loginDate;
/**
* 备注
*/
private String remark;
public Customer(Long userId) {
this.customerId = userId;
}
public boolean isSuperAdmin() {
return SystemConstants.SUPER_ADMIN_ID.equals(this.customerId);
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright 2019-2025 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fuyuanshen.customer.domain.query;
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author Zheng Jie
* @date 2018-11-23
*/
@Data
public class UserQueryCriteria extends BaseEntity {
@Schema(name = "ID")
private Long id;
@Schema(name = "ids")
private Set<Long> ids;
@Schema(name = "pid")
private Long pid;
@Schema(name = "多个ID")
private Set<Long> deptIds = new HashSet<>();
@Schema(name = "模糊查询")
private String blurry;
@Schema(name = "是否启用")
private Boolean enabled;
@Schema(name = "部门ID")
private Long deptId;
// @Schema(name = "创建时间")
// // private List<Timestamp> createTime;
@Schema(name = "页码", example = "1")
private Integer pageNum = 1;
@Schema(name = "每页数据量", example = "10")
private Integer pageSize = 10;
@Schema(name = "偏移量", hidden = true)
private long offset;
/**
* 用户类型
* 0 app
* 1 小程序
*/
@Schema(name = "用户类型 0 app 1 小程序")
private Integer userType;
/**
* 账号
*/
@Schema(name = "APP/小程序账号")
private String username;
/**
* 客户名称
*/
@Schema(name = "客户名称")
private String customerName;
}

View File

@ -0,0 +1,89 @@
package com.fuyuanshen.customer.domain.vo;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* @author: 默苍璃
* @date: 2025-06-1211:34
*/
@Getter
@Setter
public class ConsumerVo extends TenantEntity {
@Schema(name = "ID", hidden = true)
private Long customerId;
@Schema(hidden = true)
private Long deptId;
@Schema(hidden = true)
private Long pid;
@Schema(hidden = true)
private Byte userLevel;
@Schema(name = "账号")
private String userName;
@Schema(name = "用户昵称")
private String nickName;
@Schema(name = "邮箱")
private String email;
@Schema(name = "电话号码")
private String phone;
@Schema(name = "用户性别")
private String gender;
@Schema(name = "头像真实名称", hidden = true)
private String avatarName;
@Schema(name = "头像存储的路径", hidden = true)
private String avatarPath;
@Schema(name = "密码")
private String password;
@Schema(name = "是否启用")
private Boolean enabled;
@Schema(name = "是否为admin账号", hidden = true)
private Boolean isAdmin = false;
@Schema(name = "最后修改密码的时间", hidden = true)
private Date pwdResetTime;
private List<ConsumerVo> children;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ConsumerVo consumer = (ConsumerVo) o;
return Objects.equals(customerId, consumer.customerId) && Objects.equals(userName, consumer.userName);
}
@Override
public int hashCode() {
return Objects.hash(customerId, userName);
}
}

View File

@ -0,0 +1,60 @@
package com.fuyuanshen.customer.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fuyuanshen.customer.domain.Customer;
import com.fuyuanshen.customer.domain.query.UserQueryCriteria;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author: 默苍璃
* @date: 2025-07-0114:37
*/
@Mapper
public interface CustomerMapper extends BaseMapper<Customer> {
/**
* 分页查询客户
*
* @param criteria
* @return
*/
List<Customer> findCustomers(@Param("criteria") UserQueryCriteria criteria);
/**
* 获取分页总数
*
* @param criteria
* @return
*/
Long countCustomers(@Param("criteria") UserQueryCriteria criteria);
/**
* 查询所有客户
*
* @param criteria
* @return
*/
List<Customer> queryAllCustomers(@Param("criteria") UserQueryCriteria criteria);
/**
* 根据条件查询客户
*
* @param criteria
* @return
*/
List<Customer> queryCustomers(@Param("criteria") UserQueryCriteria criteria);
/**
* 根据id查询客户
*
* @param customerId
* @return
*/
Customer queryCustomerById(@Param("customerId") Long customerId, @Param("pid") Long pid);
}

View File

@ -0,0 +1,59 @@
package com.fuyuanshen.customer.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.customer.domain.Customer;
import com.fuyuanshen.customer.domain.query.UserQueryCriteria;
import com.fuyuanshen.customer.domain.vo.ConsumerVo;
import io.undertow.util.BadRequestException;
import java.util.List;
import java.util.Set;
/**
* @author: 默苍璃
* @date: 2025-07-0114:31
*/
public interface CustomerService {
/**
* 分页查询客户
*
* @param criteria
* @param page
* @return
*/
TableDataInfo<ConsumerVo> queryCustomers(UserQueryCriteria criteria, Page<Customer> page);
/**
* 查询所有客户
*
* @param criteria
* @return
*/
List<Customer> queryAllCustomers(UserQueryCriteria criteria);
/**
* 新增客户
*
* @param customer /
*/
void addCustomer(Customer customer) throws BadRequestException;
/**
* 修改客户
*
* @param resources /
* @throws Exception /
*/
void updateCustomer(Customer resources) throws Exception;
/**
* 删除客户
*
* @param ids /
*/
void delete(Set<Long> ids);
}

View File

@ -0,0 +1,113 @@
package com.fuyuanshen.customer.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyuanshen.common.core.domain.model.LoginUser;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.satoken.utils.LoginHelper;
import com.fuyuanshen.customer.domain.Customer;
import com.fuyuanshen.customer.domain.query.UserQueryCriteria;
import com.fuyuanshen.customer.domain.vo.ConsumerVo;
import com.fuyuanshen.customer.mapper.CustomerMapper;
import com.fuyuanshen.customer.service.CustomerService;
import io.undertow.util.BadRequestException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Set;
/**
* @author: 默苍璃
* @date: 2025-07-0114:31
*/
@Service
@RequiredArgsConstructor
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements CustomerService {
private final CustomerMapper customerMapper;
/**
* 分页查询客户
*
* @param criteria
* @param page
* @return
*/
@Override
public TableDataInfo<ConsumerVo> queryCustomers(UserQueryCriteria criteria, Page<Customer> page) {
criteria.setOffset(page.offset());
criteria.setPid(LoginHelper.getUserId());
List<Customer> users = customerMapper.findCustomers(criteria);
List<ConsumerVo> consumerVoList = BeanUtil.copyToList(users, ConsumerVo.class);
Long total = customerMapper.countCustomers(criteria);
// return PageUtil.toPage(consumerVoList, total);
return new TableDataInfo<ConsumerVo>(consumerVoList, total);
}
/**
* 查询所有客户
*
* @param criteria
* @return
*/
@Override
public List<Customer> queryAllCustomers(UserQueryCriteria criteria) {
List<Customer> users = customerMapper.queryAllCustomers(criteria);
return users;
}
/**
* 新增客户
*
* @param customer /
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void addCustomer(Customer customer) throws BadRequestException {
LoginUser loginUser = LoginHelper.getLoginUser();
UserQueryCriteria userQueryCriteria = new UserQueryCriteria();
userQueryCriteria.setCustomerName(customer.getUserName());
List<Customer> customers = customerMapper.queryCustomers(userQueryCriteria);
if (!customers.isEmpty()) {
throw new BadRequestException("用户名已存在!!!");
}
customer.setUserLevel((byte) (loginUser.getUserLevel() + 1));
customer.setPid(loginUser.getUserId());
save(customer);
}
/**
* 修改客户
*
* @param resources /
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void updateCustomer(Customer resources) throws Exception {
saveOrUpdate(resources);
}
/**
* 删除客户
*
* @param ids /
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void delete(Set<Long> ids) {
customerMapper.deleteByIds(ids);
}
}

View File

@ -0,0 +1 @@
spring.application.name=fys-customer

View File

@ -0,0 +1,204 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.fuyuanshen.customer.mapper.CustomerMapper">
<resultMap id="BaseResultMap" type="com.fuyuanshen.customer.domain.Customer">
<id column="user_user_id" property="customerId"/>
<result column="user_dept_id" property="deptId"/>
<result column="user_user_name" property="userName"/>
<result column="user_nick_name" property="nickName"/>
<result column="user_email" property="email"/>
<result column="user_pid" property="pid"/>
<result column="user_create_by" property="createBy"/>
<result column="user_update_by" property="updateBy"/>
<result column="user_create_time" property="createTime"/>
<result column="user_update_time" property="updateTime"/>
<result column="tenant_id" property="tenantId"/>
</resultMap>
<!-- 公共查询字段 -->
<sql id="selectUserColumns">
u
.
user_user_id
AS user_user_id,
u.user_name,
u.nick_name AS nickName,
u.email,
u.phone,
u.gender,
u.avatar_name AS avatarName,
u.avatar_path AS avatarPath,
u.enabled,
IF(u.is_admin = 1, true, false) AS isAdmin,
u.pwd_reset_time AS pwdResetTime,
u.dept_id AS deptId,
u.tenant_id AS tenantId
</sql>
<sql id="Base_Column_List">
u1
.
user_id
as user_user_id, u1.dept_id as user_dept_id, u1.user_name as user_user_name,
u1.nick_name as user_nick_name, u1.email as user_email, u1.phone as user_phone,
u1.gender as user_gender, u1.avatar_name as user_avatar_name, u1.avatar_path as user_avatar_path,
u1.enabled as user_enabled, u1.pwd_reset_time as user_pwd_reset_time, u1.create_by as user_create_by,
u1.update_by as user_update_by, u1.create_time as user_create_time, u1.update_time as user_update_time,
u1.user_level, u1.pid as user_pid,u1.is_admin AS admin,
d.dept_id as dept_id, d.name as dept_name
</sql>
<sql id="Job_Column_List">
j
.
job_id
as job_id, j.name as job_name
</sql>
<sql id="Role_Column_List">
r
.
role_id
as role_id, r.name as role_name, r.level as role_level, r.data_scope as role_data_scope
</sql>
<sql id="Whrer_Sql">
<where>
<if test="criteria.id != null">
and u1.user_id = #{criteria.id}
</if>
<if test="criteria.enabled != null">
and u1.enabled = #{criteria.enabled}
</if>
<if test="criteria.deptIds != null and criteria.deptIds.size() != 0">
and u1.dept_id in
<foreach collection="criteria.deptIds" item="deptId" open="(" separator="," close=")">
#{deptId}
</foreach>
</if>
<if test="criteria.blurry != null and criteria.blurry != ''">
and (
u1.user_name like concat('%', #{criteria.blurry}, '%')
or u1.nick_name like concat('%', #{criteria.blurry}, '%')
or u1.email like concat('%', #{criteria.blurry}, '%')
)
</if>
<if test="criteria.createTime != null and criteria.createTime.size() != 0">
and u1.create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]}
</if>
</where>
</sql>
<!-- 分页查询客户 -->
<select id="findCustomers" resultType="com.fuyuanshen.customer.domain.Customer">
select
u.user_id as customerId, u.nick_name , u.user_name, u.enabled, u.create_time
from sys_user u
<where>
<if test="criteria.ids != null and !criteria.ids.isEmpty()">
and u.pid IN
<foreach item="item" collection="criteria.ids" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="criteria.pid != null">
and u.pid = #{criteria.pid}
</if>
<if test="criteria.blurry != null and criteria.blurry.trim() != ''">
and u.nick_name like concat('%', TRIM(#{criteria.blurry}), '%')
</if>
<if test="criteria.enabled != null">
and u.enabled = #{criteria.enabled}
</if>
<if test="criteria.params.beginTime != null and criteria.params.endTime != null">
and u.create_time between #{criteria.params.beginTime} and #{criteria.params.endTime}
</if>
</where>
order by u.user_id desc
<if test="criteria.offset != null">
limit #{criteria.offset}, #{criteria.pageSize}
</if>
</select>
<!-- 获取分页总数 -->
<select id="countCustomers" resultType="java.lang.Long">
select count(*)
from sys_user u
<where>
<if test="criteria.ids != null and !criteria.ids.isEmpty()">
and u.pid IN
<foreach item="item" collection="criteria.ids" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="criteria.pid != null">
and u.pid = #{criteria.pid}
</if>
<if test="criteria.blurry != null and criteria.blurry.trim() != ''">
and u.nick_name like concat('%', TRIM(#{criteria.blurry}), '%')
</if>
<if test="criteria.enabled != null">
and u.enabled = #{criteria.enabled}
</if>
<if test="criteria.params.beginTime != null and criteria.params.endTime != null">
and u.create_time between #{criteria.params.beginTime} and #{criteria.params.endTime}
</if>
</where>
</select>
<!-- 查询所有客户 -->
<select id="queryAllCustomers" resultType="com.fuyuanshen.customer.domain.Customer">
select u.user_id as customerId,
u.nick_name,
u.user_name,
u.enabled,
u.create_time
from sys_user u
<where>
<!-- 增加非空判断 -->
<if test="criteria.ids != null and !criteria.ids.isEmpty()">
u.pid IN
<foreach item="item" collection="criteria.ids" open="(" separator="," close=")">
#{item}
</foreach>
</if>
</where>
</select>
<!-- 根据条件查询客户 -->
<select id="queryCustomers" resultType="com.fuyuanshen.customer.domain.Customer"
parameterType="com.fuyuanshen.customer.domain.query.UserQueryCriteria">
select u.user_id as customerId,
u.nick_name,
u.user_name,
u.enabled,
u.create_time
from sys_user u
<where>
<if test="criteria.customerName != null and criteria.customerName.trim() != ''">
and u.user_name = TRIM(#{criteria.customerName})
</if>
</where>
</select>
<!-- 根据id查询客户 -->
<select id="queryCustomerById" resultType="com.fuyuanshen.customer.domain.Customer">
select u.*
from sys_user u
<where>
<if test="customerId!= null">
and u.user_id = customerId)
</if>
<if test="pid != null">
and u.pid = pid)
</if>
</where>
</select>
</mapper>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
</web-app>

View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-modules</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fys-equipment</artifactId>
<description>
富源晟设备管理
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-core</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-doc</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-mybatis</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-translation</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-system</artifactId>
</dependency>
<!-- OSS功能模块 -->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-oss</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-log</artifactId>
</dependency>
<!-- excel-->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-excel</artifactId>
</dependency>
<!-- SMS功能模块 -->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-sms</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-tenant</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-security</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-web</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-idempotent</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-sensitive</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-encrypt</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-common-sse</artifactId>
</dependency>
<!-- 客户管理模块 -->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-customer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,30 @@
package com.fuyuanshen.equipment.constants;
/**
* @author: 默苍璃
* @date: 2025-06-0609:42
*/
public class DeviceConstants {
/**
* 文件访问路径前缀
*/
public static final String FILE_ACCESS_PREFIX = "images";
/**
* 文件访问路径前缀
*/
public static final String FILE_ACCESS_ISOLATION = "device";
/**
* 错误报告目录
*/
public static final String ERROR_REPORT_DIR = "error_reports";
/**
* 文件访问IP地址
*/
// public static final String FILE_ACCESS_IP = "http://fuyuanshen.com:81/";
public static final String FILE_ACCESS_IP = "https://fuyuanshen.com/";
}

View File

@ -0,0 +1,14 @@
package com.fuyuanshen.equipment.constants;
/**
* @author: 默苍璃
* @date: 2025-06-1109:26
*/
public class ExceptionMessages {
/**
* 禁止管理员操作客户数据的提示
*/
public static final String ADMIN_OPERATION_NOT_ALLOWED = "警告:请不要随意操作客户数据!";
}

View File

@ -0,0 +1,8 @@
package com.fuyuanshen.equipment.constants;
public class RedisConstants {
public static final String APP_FORGOT_PASSWORD_SMS_TOKEN = "app_sms_forgotPassword:";
public static final String APP_REGISTER_SMS_TOKEN = "app_sms_register:";
}

View File

@ -0,0 +1,14 @@
package com.fuyuanshen.equipment.constants;
/**
* @author: 默苍璃
* @date: 2025-06-0609:42
*/
public class RoleConstants {
/**
* 添加客户默认绑定角色
*/
public static final String ROLE_CUSTOMER = "普通客户";
}

View File

@ -0,0 +1,193 @@
package com.fuyuanshen.equipment.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.common.core.constant.ResponseMessageConstants;
import com.fuyuanshen.common.core.domain.ResponseVO;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.dto.ImportResult;
import com.fuyuanshen.equipment.domain.form.DeviceForm;
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
import com.fuyuanshen.equipment.domain.vo.CustomerVo;
import com.fuyuanshen.equipment.service.DeviceService;
import com.fuyuanshen.equipment.service.impl.DeviceExportService;
import com.fuyuanshen.system.domain.vo.SysOssVo;
import com.fuyuanshen.system.service.ISysOssService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
@Slf4j
@Tag(name = "设备管理", description = "设备:设备管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/device")
public class DeviceController {
private final ISysOssService ossService;
private final DeviceService deviceService;
private final DeviceExportService exportService;
@Operation(summary = "分页查询设备列表", security = {@SecurityRequirement(name = "bearer-key")})
@GetMapping
public TableDataInfo<Device> queryDevice(DeviceQueryCriteria criteria) throws IOException {
Page<Device> page = new Page<>(criteria.getPage(), criteria.getSize());
return deviceService.queryAll(criteria, page);
}
// @Log("新增设备")
@Operation(summary = "新增设备")
@PostMapping(value = "/add")
public ResponseVO<Object> addDevice(@Validated @ModelAttribute DeviceForm deviceForm) {
try {
deviceService.addDevice(deviceForm);
} catch (Exception e) {
log.error("addDevice error: " + e.getMessage());
return ResponseVO.fail(e.getMessage());
}
return ResponseVO.success(null);
}
// @Log("修改设备")
@Operation(summary = "修改设备")
@PutMapping(value = "/update")
public ResponseVO<Object> updateDevice(@Validated @ModelAttribute DeviceForm deviceForm) {
try {
deviceService.update(deviceForm);
} catch (Exception e) {
e.printStackTrace();
log.error("updateDevice error: " + e.getMessage());
return ResponseVO.fail("出错了");
}
return ResponseVO.success(null);
}
@Operation(summary = "设备详情")
@GetMapping(value = "/detail/{id}")
public ResponseVO<Object> getDevice(@PathVariable Long id) {
Device device = deviceService.getById(id);
return ResponseVO.success(device);
}
// @Log("删除设备")
@Operation(summary = "删除设备")
@DeleteMapping(value = "/delete")
public ResponseVO<Object> deleteDevice(@Parameter(name = "传ID数组[]") @RequestBody List<Long> ids) {
deviceService.deleteAll(ids);
return ResponseVO.success(ResponseMessageConstants.DELETE_SUCCESS);
}
@Operation(summary = "设备定位")
@GetMapping(value = "/locateDevice")
public ResponseVO<Object> locateDevice(DeviceQueryCriteria criteria) throws IOException {
List<Device> devices = deviceService.queryAllDevices(criteria);
return ResponseVO.success(devices);
}
// @Log("分配客户")
@Operation(summary = "分配客户")
@PutMapping(value = "/assignCustomer")
public ResponseVO<Object> assignCustomer(@Validated @RequestBody CustomerVo customerVo) {
deviceService.assignCustomer(customerVo);
return ResponseVO.success(null);
}
// @Log("撤回设备")
@Operation(summary = "撤回分配设备")
@PostMapping(value = "/withdraw")
public ResponseVO<Object> withdrawDevice(@Validated @ModelAttribute DeviceForm deviceForm) {
try {
deviceService.withdrawDevice(deviceForm);
} catch (Exception e) {
log.error("updateDevice error: " + e.getMessage());
return ResponseVO.fail("出错了");
}
return ResponseVO.success(null);
}
/**
* @param deviceForm
* @return
* @ModelAttribute 主要用于将请求参数绑定到 Java 对象上,它会从 HTTP 请求的查询参数Query Parameters
* 或表单数据Form Data中提取值并自动填充到指定的对象属性中。
*/
// @Log("解绑设备")
@Operation(summary = "解绑设备")
@PostMapping(value = "/unbind")
public ResponseVO<Object> unbindDevice(@Validated @ModelAttribute DeviceForm deviceForm) {
deviceService.unbindDevice(deviceForm);
return ResponseVO.success("解绑成功!!!");
}
@Operation(summary = "导出数据设备")
@GetMapping(value = "/download")
public void exportDevice(HttpServletResponse response, DeviceQueryCriteria criteria) throws IOException {
List<Device> devices = deviceService.queryAll(criteria);
exportService.export(devices, response);
}
@Operation(summary = "导入设备数据")
@PostMapping(value = "/import", consumes = "multipart/form-data")
public ResponseVO<ImportResult> importData(@Parameter(name = "文件", required = true) @RequestPart("file") MultipartFile file) {
SysOssVo upload = ossService.upload(file);
// String suffix = FileUtil.getExtensionName(file.getOriginalFilename());
// if (!("xlsx".equalsIgnoreCase(suffix))) {
// throw new BadRequestException("只能上传Excel——xlsx格式文件");
// }
//
// ImportResult result = new ImportResult();
// try {
// User currentUser = userMapper.findByUsername(SecurityUtils.getCurrentUsername());
// DeviceImportParams params = DeviceImportParams.builder().ip(ip).deviceService(deviceService).tenantId(currentUser.getTenantId()).file(file).filePath(filePath).deviceMapper(deviceMapper).deviceAssignmentsService(deviceAssignmentsService).deviceTypeMapper(deviceTypeMapper).userId(currentUser.getId()).userMapper(userMapper).build();
// // 创建监听器
// UploadDeviceDataListener listener = new UploadDeviceDataListener(params);
// // 读取Excel
// EasyExcel.read(file.getInputStream(), DeviceExcelImportDTO.class, listener).sheet().doRead();
// // 获取导入结果
// result = listener.getImportResult();
// // 设置响应消息
// String message = String.format("成功导入 %d 条数据,失败 %d 条", result.getSuccessCount(), result.getFailureCount());
// // 返回带有正确泛型的响应
// return ResponseVO.<ImportResult>success(message, result);
// } catch (Exception e) {
// log.error("导入设备数据出错: {}", e.getMessage(), e);
// // 在异常情况下,设置默认结果
// String errorMessage = String.format("导入失败: %s。成功 %d 条,失败 %d 条", e.getMessage(), result.getSuccessCount(), result.getFailureCount());
// // 使用新方法确保类型正确
// return ResponseVO.<ImportResult>fail(errorMessage, result);
return null;
}
}

View File

@ -0,0 +1,82 @@
package com.fuyuanshen.equipment.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.common.core.domain.ResponseVO;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.equipment.domain.DeviceType;
import com.fuyuanshen.equipment.domain.form.DeviceTypeForm;
import com.fuyuanshen.equipment.domain.query.DeviceTypeQueryCriteria;
import com.fuyuanshen.equipment.service.DeviceTypeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/13
**/
@Tag(name = "设备类型管理", description = "设备类型管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/deviceType")
public class DeviceTypeController {
private final DeviceTypeService deviceTypeService;
@GetMapping
@Operation(summary = "分页查询设备类型")
public TableDataInfo<DeviceType> queryDeviceType(DeviceTypeQueryCriteria criteria) {
Page<DeviceType> page = new Page<>(criteria.getPage(), criteria.getSize());
return deviceTypeService.queryAll(criteria, page);
}
@GetMapping(value = "/all")
@Operation(summary = "查询所有设备类型")
public ResponseVO<Object> queryDeviceTypes() {
List<DeviceType> deviceTypes = deviceTypeService.queryDeviceTypes();
return ResponseVO.success(deviceTypes);
}
// @Log("新增设备类型")
@Operation(summary = "新增设备类型")
@PostMapping(value = "/add")
public ResponseVO<Object> createDeviceType(@Validated @RequestBody DeviceType resources) {
deviceTypeService.create(resources);
return ResponseVO.success(null);
}
// @Log("修改设备类型")
@Operation(summary = "修改设备类型")
@PutMapping(value = "/update")
public ResponseVO<Object> updateDeviceType(@Validated @RequestBody DeviceTypeForm resources) {
deviceTypeService.update(resources);
return ResponseVO.success(null);
}
// @Log("删除设备类型")
@Operation(summary = "删除设备类型")
@DeleteMapping(value = "/delete")
public ResponseVO<Object> deleteDeviceType(@Parameter(name = "传ID数组[]") @RequestBody List<Long> ids) {
deviceTypeService.deleteAll(ids);
return ResponseVO.success("删除成功!!!");
}
@GetMapping(value = "/communicationMode")
@Operation(summary = "获取设备类型通讯方式")
public ResponseVO<DeviceType> getCommunicationMode(@Parameter(name = "设备类型ID", required = true) Long id) {
return ResponseVO.success(deviceTypeService.getCommunicationMode(id));
}
}

View File

@ -0,0 +1,76 @@
package com.fuyuanshen.equipment.converter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
/**
* @author: 默苍璃
* @date: 2025-06-0618:56
*/
public class IgnoreFailedImageConverter implements Converter<URL> {
private static final Logger logger = LoggerFactory.getLogger(IgnoreFailedImageConverter.class);
@Override
public Class<?> supportJavaTypeKey() {
return URL.class;
}
// @Override
// public CellDataTypeEnum supportExcelTypeKey() {
// return CellDataTypeEnum.STRING;
// }
@Override
public WriteCellData<?> convertToExcelData(URL value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
if (value == null) {
return null;
}
try {
URLConnection conn = value.openConnection();
conn.setConnectTimeout(2000); // 2秒超时
conn.setReadTimeout(3000); // 3秒超时
try (InputStream inputStream = conn.getInputStream()) {
// byte[] bytes = FileUtils.readInputStream(inputStream, value.toString());
// 替代 FileUtils.readInputStream 的自定义方法
byte[] bytes = readInputStream(inputStream);
return new WriteCellData<>(bytes);
}
} catch (Exception e) {
// 静默忽略错误,只记录日志
logger.debug("忽略图片加载失败: {}, 原因: {}", value, e.getMessage());
// return null; // 返回null表示不写入图片
return new WriteCellData<>(new byte[0]); // 返回空数组而不是 null
}
}
/**
* 替代 FileUtils.readInputStream 的自定义方法
*
* @param inputStream 输入流
* @return 字节数组
* @throws Exception 读取异常
*/
private byte[] readInputStream(InputStream inputStream) throws Exception {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
return outputStream.toByteArray();
}
}

View File

@ -0,0 +1,44 @@
package com.fuyuanshen.equipment.converter;// package com.fuyuanshen.modules.system.converter;
//
// import com.alibaba.excel.converters.Converter;
// import com.alibaba.excel.enums.CellDataTypeEnum;
// import com.alibaba.excel.metadata.GlobalConfiguration;
// import com.alibaba.excel.metadata.data.ReadCellData;
// import com.alibaba.excel.metadata.property.ExcelContentProperty;
//
// import java.io.ByteArrayOutputStream;
// import java.io.IOException;
//
// /**
// * @author: 默苍璃
// * @date: 2025-06-0710:01
// */
//
// public class ImageReadConverter implements Converter<byte[]> {
//
// @Override
// public Class<?> supportJavaTypeKey() {
// return byte[].class;
// }
//
// // @Override
// // public CellDataTypeEnum supportExcelTypeKey() {
// // return CellDataTypeEnum.IMAGE;
// // }
//
// @Override
// public byte[] convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws IOException {
// if (cellData.getType() == CellDataTypeEnum.IMAGE) {
// ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// cellData.getImageValueList().forEach(image -> {
// try {
// outputStream.write(image.getImageBytes());
// } catch (IOException e) {
// throw new RuntimeException(e);
// }
// });
// return outputStream.toByteArray();
// }
// return null;
// }
// }

View File

@ -0,0 +1,42 @@
package com.fuyuanshen.equipment.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.update.Update;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
* @author: 默苍璃
* @date: 2025-06-1308:57
*/
@Getter
@Setter
@TableName("customer_device")
public class CustomerDevice extends TenantEntity {
@NotNull(groups = Update.class)
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField(value = "customer_id")
private Long customerId;
@TableField(value = "device_id")
private Long deviceId;
/**
* 设备状态
* 0 失效
* 1 正常
*/
@TableField(value = "assign_status")
private Byte assignStatus;
}

View File

@ -0,0 +1,108 @@
package com.fuyuanshen.equipment.domain;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* @Description: 设备表
* @Author: WY
* @Date: 2025/5/16
**/
@Data
@TableName("device")
@JsonInclude(JsonInclude.Include.ALWAYS) // 关键注解
public class Device extends TenantEntity {
@TableId(value = "id", type = IdType.AUTO)
@Schema(name = "ID")
private Long id;
@Schema(name = "设备记录ID")
@TableField(exist = false)
private Long assignId;
@Schema(name = "设备类型")
private Long deviceType;
@Schema(name = "设备类型名称")
private String typeName;
@Schema(name = "客户号")
private Long customerId;
@Schema(name = "所属客户")
private String customerName;
/**
* 当前所有者
* current_owner_id
*/
@Schema(name = "当前所有者")
private Long currentOwnerId;
/**
* 原始所有者(创建者)
* original_owner_id
*/
@Schema(name = "原始所有者(创建者)")
private Long originalOwnerId;
/*@Schema( name = "设备编号")
private String deviceNo;*/
@Schema(name = "设备名称")
private String deviceName;
@Schema(name = "设备图片")
private String devicePic;
@Schema(name = "设备MAC")
private String deviceMac;
@Schema(name = "设备IMEI")
private String deviceImei;
@Schema(name = "设备SN")
private String deviceSn;
@Schema(name = "经度")
private String longitude;
@Schema(name = "纬度")
private String latitude;
@Schema(name = "备注")
private String remark;
/**
* 设备状态
* 0 失效
* 1 正常
*/
@Schema(name = "设备状态")
private Integer deviceStatus;
/**
* 绑定状态
* 0 未绑定
* 1 已绑定
*/
@Schema(name = "绑定状态")
private Integer bindingStatus;
/**
* 创建人名称
*/
private String createByName;
}

View File

@ -0,0 +1,86 @@
package com.fuyuanshen.equipment.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 设备分配记录表
*
* @TableName device_assignments
*/
@TableName(value = "device_assignments")
@Data
public class DeviceAssignments extends TenantEntity {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 设备id
*/
private Long deviceId;
/**
* 分配方
*/
private Long fromCustomerId;
/**
* 接收方
*/
private Long toCustomerId;
/**
* 分配者
* assigner_name
*/
private Long assignerId;
private String assignerName;
/**
* 接收者
* assignee_name
*/
private Long assigneeId;
private String assigneeName;
/**
* 分配时间
*/
private LocalDateTime assignedAt;
/**
* 0 未授权
* 1 已授权
* 是否同步授权了设备类型
*/
private Integer deviceTypeGranted;
/**
* 0 否
* 1 是
* 是否直接分配(用于父级显示)
*/
private Integer direct;
/**
* 0 否
* 1 是
* 设备是否有效
*/
private Integer active;
/**
* 分配等级(用于失效)
*/
private String lever;
}

View File

@ -0,0 +1,40 @@
package com.fuyuanshen.equipment.domain;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import lombok.Data;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/24
**/
@Data
@TableName("device_log")
public class DeviceLog extends TenantEntity {
@TableId(value = "id", type = IdType.AUTO)
// @Schema(value = "ID")
private Long id;
// @Schema(value = "设备行为")
private String deviceAction;
// @Schema(value = "设备名称")
private String deviceName;
// @Schema(value = "数据来源")
private String dataSource;
// @Schema(value = "内容")
private String content;
public void copy(DeviceLog source){
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
}
}

View File

@ -0,0 +1,55 @@
package com.fuyuanshen.equipment.domain;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.annotation.*;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* @Description: 设备类型
* @Author: WY
* @Date: 2025/5/14
**/
@Data
@TableName("device_type")
public class DeviceType extends TenantEntity {
@TableId(value = "id", type = IdType.AUTO)
@Schema(name = "ID", hidden = true)
private Long id;
@Schema(name = "客户号")
private Long customerId;
@Schema(name = "创建该类型的客户")
private Long ownerCustomerId;
@NotBlank(message = "设备类型名称不能为空")
@Schema(name = "类型名称", required = true)
private String typeName;
@Schema(name = "是否支持蓝牙")
private Boolean isSupportBle;
@Schema(name = "定位方式", example = "0:无;1:GPS;2:基站;3:wifi;4:北斗")
private String locateMode;
@Schema(name = "联网方式", example = "0:无;1:4G;2:WIFI")
private String networkWay;
@Schema(name = "通讯方式", example = "0:4G;1:蓝牙")
private String communicationMode;
/**
* 创建人名称
*/
private String createByName;
public void copy(DeviceType source) {
BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
}
}

View File

@ -0,0 +1,95 @@
package com.fuyuanshen.equipment.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import lombok.Data;
import java.util.Date;
/**
* 设备分配权限表 (解决跨客户共享)
*
* @TableName device_type_grants
*/
@TableName(value = "device_type_grants")
@Data
public class DeviceTypeGrants extends TenantEntity {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 设备类型
*/
private Long deviceTypeId;
/**
* 被授权的客户
*/
private Long customerId;
/**
* 授权方客户
*/
private Long grantorCustomerId;
/**
* 生成日期
*/
private Date grantedAt;
/**
* 关联分配记录
*/
private Long assignmentId;
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass() != that.getClass()) {
return false;
}
DeviceTypeGrants other = (DeviceTypeGrants) that;
return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId())) && (this.getDeviceTypeId() == null ? other.getDeviceTypeId() == null : this.getDeviceTypeId().equals(other.getDeviceTypeId())) && (this.getCustomerId() == null ? other.getCustomerId() == null : this.getCustomerId().equals(other.getCustomerId())) && (this.getGrantorCustomerId() == null ? other.getGrantorCustomerId() == null : this.getGrantorCustomerId().equals(other.getGrantorCustomerId())) && (this.getGrantedAt() == null ? other.getGrantedAt() == null : this.getGrantedAt().equals(other.getGrantedAt())) && (this.getAssignmentId() == null ? other.getAssignmentId() == null : this.getAssignmentId().equals(other.getAssignmentId()));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
result = prime * result + ((getDeviceTypeId() == null) ? 0 : getDeviceTypeId().hashCode());
result = prime * result + ((getCustomerId() == null) ? 0 : getCustomerId().hashCode());
result = prime * result + ((getGrantorCustomerId() == null) ? 0 : getGrantorCustomerId().hashCode());
result = prime * result + ((getGrantedAt() == null) ? 0 : getGrantedAt().hashCode());
result = prime * result + ((getAssignmentId() == null) ? 0 : getAssignmentId().hashCode());
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", deviceTypeId=").append(deviceTypeId);
sb.append(", customerId=").append(customerId);
sb.append(", grantorCustomerId=").append(grantorCustomerId);
sb.append(", grantedAt=").append(grantedAt);
sb.append(", assignmentId=").append(assignmentId);
sb.append("]");
return sb.toString();
}
}

View File

@ -0,0 +1,80 @@
package com.fuyuanshen.equipment.domain.dto;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.fuyuanshen.equipment.converter.IgnoreFailedImageConverter;
import lombok.Data;
import java.net.URL;
/**
* @author: 默苍璃
* @date: 2025-06-0618:16
*/
@Data
@HeadRowHeight(20) // 表头行高
@ContentRowHeight(100) // 内容行高
public class DeviceExcelExportDTO {
@ExcelProperty("ID")
private Long id;
@ExcelProperty("设备类型")
private Long deviceType;
// @ExcelProperty("客户号")
// private Long customerId;
@ExcelProperty("所属客户")
private String customerName;
@ExcelProperty("设备名称")
@ColumnWidth(20)
private String deviceName;
@ExcelProperty(value = "设备图片", converter = IgnoreFailedImageConverter.class)
@ColumnWidth(15) // 设置图片列宽度
private URL devicePic; // 使用URL类型
@ExcelProperty("设备MAC")
@ColumnWidth(20)
private String deviceMac;
@ExcelProperty("设备IMEI")
@ColumnWidth(20)
private String deviceImei;
@ExcelProperty("经度")
private String longitude;
@ExcelProperty("纬度")
private String latitude;
@ExcelProperty("备注")
@ColumnWidth(30)
private String remark;
@ExcelProperty("设备类型名称")
@ColumnWidth(20)
private String typeName;
/**
* 设备状态
* 0 失效
* 1 正常
*/
@ExcelProperty("设备状态")
@ColumnWidth(20)
private String deviceStatus;
@ExcelProperty("创建时间")
@ColumnWidth(20)
private String createTime;
@ExcelProperty("创建人")
@ColumnWidth(20)
private String createBy;
}

View File

@ -0,0 +1,65 @@
package com.fuyuanshen.equipment.domain.dto;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import com.alibaba.excel.converters.bytearray.ByteArrayImageConverter;
import lombok.Data;
/**
* @author: 默苍璃
* @date: 2025-06-0710:00
*/
@Data
@HeadRowHeight(20) // 表头行高
@ContentRowHeight(100) // 内容行高
public class DeviceExcelImportDTO {
@ExcelProperty("设备类型")
private Long deviceType;
@ExcelProperty("客户号")
private Long customerId;
@ExcelProperty("设备名称")
@ColumnWidth(20)
private String deviceName;
@ExcelProperty(value = "设备图片", converter = ByteArrayImageConverter.class)
@ColumnWidth(15)
private byte[] devicePic;
// 添加图片写入方法
public void setDevicePicFromBytes(byte[] bytes) {
this.devicePic = bytes;
}
@ExcelProperty("设备MAC")
@ColumnWidth(20)
private String deviceMac;
@ExcelProperty("设备IMEI")
@ColumnWidth(20)
private String deviceImei;
@ExcelProperty("设备SN")
@ColumnWidth(20)
private String deviceSn;
@ExcelProperty("经度")
private String longitude;
@ExcelProperty("纬度")
private String latitude;
@ExcelProperty("备注")
@ColumnWidth(30)
private String remark;
@ExcelProperty("设备类型名称")
@ColumnWidth(20)
private String typeName;
}

View File

@ -0,0 +1,25 @@
package com.fuyuanshen.equipment.domain.dto;
import lombok.Data;
import java.util.List;
/**
* @author: 默苍璃
* @date: 2025-06-0717:01
*/
@Data
public class ImportResult {
private int successCount;
private int failureCount;
private List<DeviceExcelImportDTO> failedRecords;
// private byte[] errorExcelData; // 存储失败数据的Excel字节流
private String errorExcelUrl; // 改为存储错误报告的URL
// 添加成功/失败统计信息
public String getSummary() {
return String.format("成功导入 %d 条数据,失败 %d 条", successCount, failureCount);
}
}

View File

@ -0,0 +1,56 @@
package com.fuyuanshen.equipment.domain.form;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
/**
* @Description: 设备表单
* @Author: WY
* @Date: 2025/5/17
**/
@Data
public class DeviceForm {
@Schema(title = "ID", hidden = true)
private Long id;
@Schema(title = "设备记录ID")
private Long assignId;
@Schema(title = "设备类型")
private Long deviceTypeId;
@Schema(title = "客户号")
private Long customerId;
/*@Schema(value = "设备编号")
private String deviceNo;*/
@NotBlank(message = "设备名称不能为空")
@Schema(title = "设备名称", required = true)
private String deviceName;
@Schema(title = "设备图片存储路径", hidden = true)
private String devicePic;
// @NotBlank(message = "设备MAC不能为空")
@Schema(title = "设备MAC")
private String deviceMac;
@Schema(title = "设备IMEI")
private String deviceImei;
// @NotBlank(message = "设备SN不能为空")
@Schema(title = "设备SN", required = true)
private String deviceSn;
@Schema(title = "设备图片")
private MultipartFile file;
@Schema(title = "备注")
private String remark;
}

View File

@ -0,0 +1,39 @@
package com.fuyuanshen.equipment.domain.form;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* @Description: 设备类型
* @Author: WY
* @Date: 2025/5/14
**/
@Data
public class DeviceTypeForm {
@Schema(name = "ID", hidden = true)
private Long id;
@Schema(name = "类型名称", required = true)
private String typeName;
@Schema(name = "是否支持蓝牙")
private Boolean isSupportBle;
@Schema(name = "定位方式", example = "0:无;1:GPS;2:基站;3:wifi;4:北斗")
private String locateMode;
@Schema(name = "联网方式", example = "0:无;1:4G;2:WIFI")
private String networkWay;
@Schema(name = "通讯方式", example = "0:4G;1:蓝牙")
private String communicationMode;
}

View File

@ -0,0 +1,68 @@
package com.fuyuanshen.equipment.domain.query;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.sql.Timestamp;
import java.util.List;
import java.util.Set;
/**
* 设备查询参数
*
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
@Data
public class DeviceQueryCriteria {
@Schema(name = "设备id")
private Long deviceId;
@Schema(name = "设备名称")
private String deviceName;
@Schema(name = "设备类型")
private Long deviceTypeId;
@Schema(name = "设备MAC")
private String deviceMac;
@Schema(name = "设备IMEI")
private String deviceImei;
@Schema(name = "设备SN")
private String deviceSn;
/**
* 设备状态
* 0 失效
* 1 正常
*/
@Schema(name = "设备状态 0 失效 1 正常 ")
private Integer deviceStatus;
@Schema(name = "创建时间")
private List<Timestamp> createTime;
@Schema(name = "页码", example = "1")
private Integer page = 1;
@Schema(name = "每页数据量", example = "10")
private Integer size = 10;
@Schema(name = "客户id")
private Long customerId;
private Set<Long> customerIds;
@Schema(name = "当前所有者")
private Long currentOwnerId;
@Schema(name = "租户ID")
private Long tenantId;
@Schema(name = "通讯方式", example = "0:4G;1:蓝牙")
private Integer communicationMode;
}

View File

@ -0,0 +1,39 @@
package com.fuyuanshen.equipment.domain.query;
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.util.Set;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/14
**/
@Data
public class DeviceTypeQueryCriteria extends BaseEntity implements Serializable {
@Schema(name = "设备类型id")
private Long deviceTypeId;
@Schema(name = "型号名称")
private String typeName;
@Schema(name = "所属客户")
private Set<Long> customerIds;
@Schema(name = "所属客户")
private Long customerId;
@Schema(name = "com.fuyuanshen")
private Long tenantId;
@Schema(name = "页码", example = "1")
private Integer page = 1;
@Schema(name = "每页数据量", example = "10")
private Integer size = 10;
}

View File

@ -0,0 +1,27 @@
package com.fuyuanshen.equipment.domain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.validation.annotation.Validated;
import java.util.List;
/**
* @Description: 分配客户的Vo类
* @Author: WY
* @Date: 2025/5/28
**/
@Data
@Validated
public class CustomerVo {
@Schema(name = "客户ID")
@NotNull(message = "客户ID不能为空")
private Long customerId;
@Schema(name = "设备ID")
@NotNull(message = "设备ID不能为空")
private List<Long> deviceIds;
}

View File

@ -0,0 +1,35 @@
package com.fuyuanshen.equipment.enums;
/**
* @author: 默苍璃
* @date: 2025-06-1818:17
*/
public enum BindingStatusEnum {
UNBOUND(0, "未绑定"), BOUND(1, "已绑定");
private final int code;
private final String description;
BindingStatusEnum(int code, String description) {
this.code = code;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
public static BindingStatusEnum fromCode(int code) {
for (BindingStatusEnum status : values()) {
if (status.getCode() == code) {
return status;
}
}
throw new IllegalArgumentException("Invalid binding status code: " + code);
}
}

View File

@ -0,0 +1,45 @@
package com.fuyuanshen.equipment.enums;
import com.fasterxml.jackson.annotation.JsonValue;
/**
* 通讯方式枚举
*
* @author: 默苍璃
* @date: 2025-06-2414:11
*/
public enum CommunicationModeEnum {
FOUR_G(0, "4G"),
BLUETOOTH(1, "蓝牙");
private final int value;
private final String label;
CommunicationModeEnum(int value, String label) {
this.value = value;
this.label = label;
}
@JsonValue
public int getValue() {
return value;
}
public String getLabel() {
return label;
}
/**
* 根据值获取标签
*/
public static String getLabelByValue(int value) {
for (CommunicationModeEnum mode : values()) {
if (mode.getValue() == value) {
return mode.getLabel();
}
}
return null;
}
}

View File

@ -0,0 +1,44 @@
package com.fuyuanshen.equipment.enums;
/**
* 设备有效性状态枚举
*
* @author: 默苍璃
* @date: 2025-06-2113:26
*/
public enum DeviceActiveStatusEnum {
INACTIVE(0, "无效"), ACTIVE(1, "有效");
private final Integer code;
private final String description;
DeviceActiveStatusEnum(Integer code, String description) {
this.code = code;
this.description = description;
}
public Integer getCode() {
return code;
}
public String getDescription() {
return description;
}
/**
* 根据 code 获取描述
*
* @param code 状态码
* @return 描述信息
*/
public static String getDescriptionByCode(Integer code) {
for (DeviceActiveStatusEnum status : values()) {
if (status.getCode().equals(code)) {
return status.getDescription();
}
}
return null;
}
}

View File

@ -0,0 +1,45 @@
package com.fuyuanshen.equipment.enums;
/**
* @author: 默苍璃
* @date: 2025-06-1918:50
*/
public enum DeviceAuthorizationStatus {
/**
* 未授权
*/
UNAUTHORIZED(0),
/**
* 已授权
*/
AUTHORIZED(1);
private final int value;
DeviceAuthorizationStatus(int value) {
this.value = value;
}
public int getValue() {
return value;
}
/**
* 根据整数值获取对应的枚举值
*
* @param value 整数值0 或 1
* @return 对应的 DeviceAuthorizationStatus 枚举
* @throws IllegalArgumentException 如果值不是 0 或 1
*/
public static DeviceAuthorizationStatus fromValue(int value) {
for (DeviceAuthorizationStatus status : values()) {
if (status.getValue() == value) {
return status;
}
}
throw new IllegalArgumentException("Invalid device authorization status value: " + value);
}
}

View File

@ -0,0 +1,51 @@
package com.fuyuanshen.equipment.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 设备状态枚举
*
* @author: 默苍璃
* @date: 2025-06-1916:02
*/
@Getter
@AllArgsConstructor
public enum DeviceStatusEnum {
/**
* 失效
*/
INVALID(0, "失效"),
/**
* 正常
*/
NORMAL(1, "正常");
/**
* 状态码
*/
private final Integer code;
/**
* 描述
*/
private final String description;
/**
* 根据状态码获取描述
*
* @param code 状态码
* @return 描述
*/
public static String getDescriptionByCode(Integer code) {
for (DeviceStatusEnum status : DeviceStatusEnum.values()) {
if (status.getCode().equals(code)) {
return status.getDescription();
}
}
return null;
}
}

View File

@ -0,0 +1,34 @@
package com.fuyuanshen.equipment.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
@Mapper
public interface DeviceMapper extends BaseMapper<Device> {
/**
* 分页查询设备
*
* @param criteria
* @param page
* @return
*/
IPage<Device> findAll(@Param("criteria") DeviceQueryCriteria criteria, Page<Device> page);
List<Device> findAll(@Param("criteria") DeviceQueryCriteria criteria);
List<Device> findAllDevices(@Param("criteria") DeviceQueryCriteria criteria);
}

View File

@ -0,0 +1,39 @@
package com.fuyuanshen.equipment.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.equipment.domain.DeviceType;
import com.fuyuanshen.equipment.domain.query.DeviceTypeQueryCriteria;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/14
**/
@Mapper
public interface DeviceTypeMapper extends BaseMapper<DeviceType> {
/**
* 分页查询设备类型
*
* @param criteria
* @param page
* @return
*/
IPage<DeviceType> findAll(@Param("criteria") DeviceTypeQueryCriteria criteria, Page<DeviceType> page);
/**
* 查询所有设备类型
*
* @param criteria
* @return
*/
List<DeviceType> findAll(@Param("criteria") DeviceTypeQueryCriteria criteria);
}

View File

@ -0,0 +1,84 @@
package com.fuyuanshen.equipment.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fuyuanshen.common.core.domain.PageResult;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.form.DeviceForm;
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
import com.fuyuanshen.equipment.domain.vo.CustomerVo;
import java.io.IOException;
import java.util.List;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
public interface DeviceService extends IService<Device> {
/**
* 查询设备数据分页
*
* @param criteria 条件
* @param page 分页参数
* @return PageResult
*/
TableDataInfo<Device> queryAll(DeviceQueryCriteria criteria, Page<Device> page) throws IOException;
/**
* 查询所有数据不分页
*
* @param criteria 条件参数
* @return List<DeviceDto>
*/
List<Device> queryAll(DeviceQueryCriteria criteria);
/**
* 查询所有设备信息
*
* @param criteria
* @return
*/
List<Device> queryAllDevices(DeviceQueryCriteria criteria);
/**
* 新增设备
*
* @param resources
*/
void addDevice(DeviceForm resources) throws Exception;
/**
* 修改设备
*
* @param resources /
*/
void update(DeviceForm resources) throws Exception;
/**
* 批量删除
*
* @param ids /
*/
void deleteAll(List<Long> ids);
/**
* 分配客户
*/
void assignCustomer(CustomerVo customerVo);
/**
* 撤回设备
*/
void withdrawDevice(DeviceForm deviceForm);
/**
* 解绑设备
*
* @param deviceForm
*/
void unbindDevice(DeviceForm deviceForm);
}

View File

@ -0,0 +1,72 @@
package com.fuyuanshen.equipment.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fuyuanshen.common.core.domain.PageResult;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.equipment.domain.DeviceType;
import com.fuyuanshen.equipment.domain.form.DeviceTypeForm;
import com.fuyuanshen.equipment.domain.query.DeviceTypeQueryCriteria;
import java.util.List;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/14
**/
public interface DeviceTypeService extends IService<DeviceType> {
/**
* 查询数据分页
*
* @param criteria 条件
* @param page 分页参数
* @return PageResult
*/
TableDataInfo<DeviceType> queryAll(DeviceTypeQueryCriteria criteria, Page<DeviceType> page);
/**
* 查询所有数据不分页
*
* @param criteria 条件参数
* @return List<DeviceTypeDto>
*/
List<DeviceType> queryAll(DeviceTypeQueryCriteria criteria);
/**
* 查询所有设备类型
*
* @return
*/
List<DeviceType> queryDeviceTypes();
/**
* 新增设备类型
*
* @param resources /
*/
void create(DeviceType resources);
/**
* 修改设备类型
*
* @param resources /
*/
void update(DeviceTypeForm resources);
/**
* 多选删除
*
* @param ids /
*/
void deleteAll(List<Long> ids);
/**
* 获取设备类型通讯方式
*
* @param id /
* @return DeviceTypeDto
*/
DeviceType getCommunicationMode(Long id);
}

View File

@ -0,0 +1,86 @@
package com.fuyuanshen.equipment.service.impl;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.DateUtils;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.dto.DeviceExcelExportDTO;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author: 默苍璃
* @date: 2025-06-0618:22
*/
@Service
public class DeviceExportService {
public void export(List<Device> devices, HttpServletResponse response) {
try {
String fileName = "设备列表_" + System.currentTimeMillis() + ".xlsx";
// 使用URLEncoder进行RFC 5987编码
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 使用RFC 5987标准编码文件名
response.setHeader("Content-disposition", "attachment;filename*=UTF-8''" + encodedFileName);
// 转换为DTO列表
List<DeviceExcelExportDTO> dtoList = devices.stream().map(device -> {
DeviceExcelExportDTO dto = new DeviceExcelExportDTO();
dto.setId(device.getId());
dto.setDeviceType(device.getDeviceType());
dto.setCustomerName(device.getCustomerName());
dto.setDeviceName(device.getDeviceName());
dto.setDeviceMac(device.getDeviceMac());
// 设备IMEI
dto.setDeviceImei(device.getDeviceImei());
dto.setLongitude(device.getLongitude());
dto.setLatitude(device.getLatitude());
dto.setRemark(device.getRemark());
dto.setTypeName(device.getTypeName());
dto.setCreateBy(device.getCreateByName());
Integer deviceStatus = device.getDeviceStatus();
dto.setDeviceStatus(deviceStatus == 1 ? "正常" : "失效");
// 时间戳转换
dto.setCreateTime(DateUtils.format(device.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
// 处理图片URL转换
handleDevicePic(device, dto);
return dto;
}).collect(Collectors.toList());
// 写入Excel
EasyExcel.write(response.getOutputStream(), DeviceExcelExportDTO.class).sheet("设备数据").doWrite(dtoList);
} catch (IOException e) {
throw new RuntimeException("导出Excel失败", e);
}
}
private void handleDevicePic(Device device, DeviceExcelExportDTO dto) {
String picUrl = device.getDevicePic();
if (picUrl != null && !picUrl.trim().isEmpty()) {
try {
// 尝试创建URL对象会自动验证格式
dto.setDevicePic(new URL(picUrl));
} catch (MalformedURLException e) {
// 不是有效URL时设置为null
dto.setDevicePic(null);
}
} else {
dto.setDevicePic(null);
}
}
}

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