分页查询设备

This commit is contained in:
2025-06-28 17:18:05 +08:00
parent 1d286634c0
commit f9f5569504
22 changed files with 2078 additions and 30 deletions

View File

@ -65,6 +65,12 @@
<artifactId>fys-common-mail</artifactId>
</dependency>
<!-- 设备管理模块 -->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-equipment</artifactId>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-system</artifactId>

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

@ -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,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> content;
private long totalElements;
}

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

@ -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

@ -9,9 +9,8 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-equipment</artifactId>
<version>1.0-SNAPSHOT</version>
<description>
富源晟设备管理

View File

@ -0,0 +1,206 @@
package com.fuyuanshen.equipment.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.common.core.domain.PageResult;
import com.fuyuanshen.common.core.domain.ResponseVO;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.dto.DeviceQueryCriteria;
import com.fuyuanshen.equipment.service.DeviceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
@Slf4j
// @Api(tags = "设备:设备管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/device")
public class DeviceController {
private final DeviceService deviceService;
@GetMapping
public ResponseVO<PageResult<Device>> queryDevice(DeviceQueryCriteria criteria) {
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
PageResult<Device> devices = null;
try {
devices = deviceService.queryAll(criteria, page);
} catch (IOException e) {
log.error("queryDevice error: " + e.getMessage());
return ResponseVO.fail("");
}
return ResponseVO.success(devices);
}
//
// @Log("新增设备")
// @ApiOperation("新增设备")
// @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);
// }
//
//
// /**
// * @param deviceForm
// * @return
// * @ModelAttribute 主要用于将请求参数绑定到 Java 对象上,它会从 HTTP 请求的查询参数Query Parameters
// * 或表单数据Form Data中提取值并自动填充到指定的对象属性中。
// */
// @Log("解绑设备")
// @ApiOperation("解绑设备")
// @PostMapping(value = "/unbind")
// public ResponseVO<Object> unbindDevice(@Validated @ModelAttribute DeviceForm deviceForm) {
// deviceService.unbindDevice(deviceForm);
// return ResponseVO.success("解绑成功!!!");
// }
//
//
// @Log("修改设备")
// @ApiOperation("修改设备")
// @PutMapping(value = "/update")
// public ResponseVO<Object> updateDevice(@Validated @ModelAttribute DeviceForm deviceForm) {
// try {
// deviceService.update(deviceForm);
// } catch (Exception e) {
// log.error("updateDevice error: " + e.getMessage());
// return ResponseVO.fail("出错了");
// }
// return ResponseVO.success(null);
// }
//
//
// @Log("分配客户")
// @ApiOperation("分配客户")
// @PutMapping(value = "/assignCustomer")
// public ResponseVO<Object> assignCustomer(@Validated @RequestBody CustomerVo customerVo) {
// deviceService.assignCustomer(customerVo);
// return ResponseVO.success(null);
// }
//
//
// @Log("撤回设备")
// @ApiOperation("撤回设备")
// @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);
// }
//
//
// @ApiOperation("设备详情")
// @GetMapping(value = "/detail/{id}")
// public ResponseVO<Object> getDevice(@PathVariable Long id) {
// Device device = deviceService.getById(id);
// return ResponseVO.success(device);
// }
//
//
// @Log("删除设备")
// @ApiOperation("删除设备")
// @DeleteMapping(value = "/delete")
// public ResponseVO<Object> deleteDevice(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
// // deviceService.deleteAll(ids);
// deviceService.deleteAssign(ids);
// return ResponseVO.success(ResponseMessageConstants.DELETE_SUCCESS);
// }
//
//
// @ApiOperation("导出数据设备")
// @GetMapping(value = "/download")
// public void exportDevice(HttpServletResponse response, DeviceQueryCriteria criteria) throws IOException {
// // deviceService.download(deviceService.queryAll(criteria), response);
// User onlineuser = userService.findByName(SecurityUtils.getCurrentUsername());
//
// // 只能看到自己的创建的设备,以及被分配的设备。
// if (onlineuser.getTenantId() != null && !onlineuser.getTenantId().equals(UserConstants.SUPER_ADMIN_ID)) {
// // criteria.setTenantId(onlineuser.getTenantId());
// criteria.setCurrentOwnerId(onlineuser.getId());
// }
// exportService.export(deviceService.queryAll(criteria), response);
// }
//
//
// @ApiOperation("设备定位")
// @GetMapping(value = "/locateDevice")
// public ResponseVO<Object> locateDevice(DeviceQueryCriteria criteria) throws IOException {
// List<Device> devices = deviceService.queryAllDevices(criteria);
// return ResponseVO.success(devices);
// }
//
// @ApiOperation("设备数据模板下载")
// @GetMapping("/template")
// public void download(HttpServletRequest request, HttpServletResponse response) throws IOException, URISyntaxException {
// // String filePath = "resources" + File.separator + "template" + File.separator + "device_import.csv";
// Path path = Paths.get(ClassLoader.getSystemResource("template/device_import.csv").toURI());
// FileUtil.downloadFile(request, response, new File(path.toUri()), true);
// }
//
//
// @ApiOperation("导入设备数据")
// @PostMapping(value = "/import", consumes = "multipart/form-data")
// public ResponseVO<ImportResult> importData(@ApiParam(value = "文件", required = true) @RequestPart("file") MultipartFile 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);
// }
// }
//
// @ApiOperation("下载导入错误报告")
// @GetMapping("/download-import-errors")
// public ResponseEntity<byte[]> downloadImportErrors(@RequestParam String errorData) {
// try {
// // 解码Base64字符串
// byte[] data = Base64.getDecoder().decode(errorData);
// return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"import_errors.xlsx\"").contentType(MediaType.APPLICATION_OCTET_STREAM).body(data);
// } catch (Exception e) {
// log.error("下载错误报告失败", e);
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
// }
// }
}

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,112 @@
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 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)
// @ApiModelProperty(value = "ID")
private Long id;
// @ApiModelProperty(value = "设备记录ID")
@TableField(exist = false)
private Long assignId;
// @ApiModelProperty(value = "设备类型")
private Long deviceType;
// @ApiModelProperty(value = "设备类型名称")
private String typeName;
// @ApiModelProperty(value = "客户号")
private Long customerId;
/**
* 当前所有者
* current_owner_id
*/
// @ApiModelProperty(value = "当前所有者")
private Long currentOwnerId;
/**
* 原始所有者(创建者)
* original_owner_id
*/
// @ApiModelProperty(value = "原始所有者(创建者)")
private Long originalOwnerId;
// @ApiModelProperty(value = "所属客户")
private String customerName;
/*@ApiModelProperty(value = "设备编号")
private String deviceNo;*/
// @ApiModelProperty(value = "设备名称")
private String deviceName;
// @ApiModelProperty(value = "设备图片")
private String devicePic;
// @ApiModelProperty(value = "设备MAC")
private String deviceMac;
// @ApiModelProperty(value = "设备IMEI")
private String deviceImei;
// @ApiModelProperty(value = "设备SN")
private String deviceSn;
// @ApiModelProperty(value = "经度")
private String longitude;
// @ApiModelProperty(value = "纬度")
private String latitude;
// @ApiModelProperty(value = "备注")
private String remark;
/**
* 租户ID
*/
// @TableField(value = "tenant_id")
// // @ApiModelProperty(hidden = true)
// private Long tenantId;
/**
* 设备状态
* 0 失效
* 1 正常
*/
// @ApiModelProperty(value = "设备状态")
private Integer deviceStatus;
/**
* 绑定状态
* 0 未绑定
* 1 已绑定
*/
// @ApiModelProperty(value = "绑定状态")
private Integer bindingStatus;
public void copy(Device source) {
BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));
}
}

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)
// @ApiModelProperty(value = "ID")
private Long id;
// @ApiModelProperty(value = "设备行为")
private String deviceAction;
// @ApiModelProperty(value = "设备名称")
private String deviceName;
// @ApiModelProperty(value = "数据来源")
private String dataSource;
// @ApiModelProperty(value = "内容")
private String content;
public void copy(DeviceLog source){
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
}
}

View File

@ -0,0 +1,59 @@
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 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)
// @ApiModelProperty(value = "ID", hidden = true)
private Long id;
// @ApiModelProperty(value = "客户号")
private Long customerId;
// @ApiModelProperty(value = "创建该类型的客户")
private Long ownerCustomerId;
/**
* 租户ID
*/
// @TableField(value = "tenant_id")
// @ApiModelProperty(hidden = true)
// private Long tenantId;
@NotBlank(message = "设备类型名称不能为空")
// @ApiModelProperty(value = "类型名称", required = true)
private String typeName;
// @ApiModelProperty(value = "是否支持蓝牙")
private Boolean isSupportBle;
// @ApiModelProperty(value = "定位方式", example = "0:无;1:GPS;2:基站;3:wifi;4:北斗")
private String locateMode;
// @ApiModelProperty(value = "联网方式", example = "0:无;1:4G;2:WIFI")
private String networkWay;
// @ApiModelProperty(value = "通讯方式", example = "0:4G;1:蓝牙")
private String communicationMode;
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,64 @@
package com.fuyuanshen.equipment.domain.dto;
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 {
// @ApiModelProperty(value = "设备名称")
private String deviceName;
// @ApiModelProperty(value = "设备类型")
private Long deviceType;
// @ApiModelProperty(value = "设备MAC")
private String deviceMac;
// @ApiModelProperty(value = "设备IMEI")
private String deviceImei;
// @ApiModelProperty(value = "设备SN")
private String deviceSn;
/**
* 设备状态
* 0 失效
* 1 正常
*/
// @ApiModelProperty(value = "设备状态 0 失效 1 正常 ")
private Integer deviceStatus;
// @ApiModelProperty(value = "创建时间")
private List<Timestamp> createTime;
// @ApiModelProperty(value = "页码", example = "1")
private Integer page = 1;
// @ApiModelProperty(value = "每页数据量", example = "10")
private Integer size = 10;
// @ApiModelProperty(value = "客户id")
private Long customerId;
private Set<Long> customerIds;
// @ApiModelProperty(value = "当前所有者")
private Long currentOwnerId;
// @ApiModelProperty(value = "租户ID")
private Long tenantId;
// @ApiModelProperty(value = "通讯方式", example = "0:4G;1:蓝牙")
private Integer communicationMode;
}

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.dto.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<Object> page);
List<Device> findAll(@Param("criteria") DeviceQueryCriteria criteria);
List<Device> findAllDevices(@Param("criteria") DeviceQueryCriteria criteria);
}

View File

@ -0,0 +1,108 @@
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.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.dto.DeviceQueryCriteria;
import java.io.IOException;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
public interface DeviceService extends IService<Device> {
/**
* 查询设备数据分页
*
* @param criteria 条件
* @param page 分页参数
* @return PageResult
*/
PageResult<Device> queryAll(DeviceQueryCriteria criteria, Page<Object> page) throws IOException;
// /**
// * 查询所有数据不分页
// *
// * @param criteria 条件参数
// * @return List<DeviceDto>
// */
// List<Device> queryAll(DeviceQueryCriteria criteria);
//
// /**
// * 查询所有设备信息
// *
// * @param criteria
// * @return
// */
// List<Device> queryAllDevices(DeviceQueryCriteria criteria);
//
// /**
// * 创建
// *
// * @param resources /
// */
// void create(Device resources);
//
// /**
// * 新增设备
// *
// * @param resources
// */
// void addDevice(DeviceForm resources) throws Exception;
//
// /**
// * 编辑
// *
// * @param resources /
// */
// void update(DeviceForm resources) throws Exception;
//
// /**
// * 分配客户
// */
// void assignCustomer(CustomerVo customerVo);
//
// void withdrawDevice(DeviceForm deviceForm);
//
// /**
// * 多选删除
// *
// * @param ids /
// */
// void deleteAll(List<Long> ids);
//
// /**
// * 删除设备分配记录
// *
// * @param ids
// */
// void deleteAssign(List<Long> ids);
//
// /**
// * 导出数据
// *
// * @param all 待导出的数据
// * @param response /
// * @throws IOException /
// */
// void download(List<Device> all, HttpServletResponse response) throws IOException;
//
// /**
// * 导入设备数据
// *
// * @param file
// */
// void importData(MultipartFile file) throws IOException;
//
// /**
// * 解绑设备
// *
// * @param deviceForm
// */
// void unbindDevice(DeviceForm deviceForm);
}

View File

@ -0,0 +1,603 @@
package com.fuyuanshen.equipment.service.impl;
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.common.core.domain.PageResult;
import com.fuyuanshen.common.core.utils.PageUtil;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.dto.DeviceQueryCriteria;
import com.fuyuanshen.equipment.mapper.DeviceMapper;
import com.fuyuanshen.equipment.service.DeviceService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.*;
/**
* @Description:
* @Author: WY
* @Date: 2025/5/16
**/
@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {
private final DeviceMapper deviceMapper;
/**
* 分页查询设备
*
* @param criteria 条件
* @param page 分页参数
* @return
* @throws IOException
*/
@Override
public PageResult<Device> queryAll(DeviceQueryCriteria criteria, Page<Object> page) throws IOException {
IPage<Device> devices = deviceMapper.findAll(criteria, page);
List<Device> records = devices.getRecords();
for (Device record : records) {
if (record.getDevicePic() == null) {
record.setDevicePic("");
}
}
return PageUtil.toPage(devices);
}
//
// @Override
// public List<Device> queryAll(DeviceQueryCriteria criteria) {
// return deviceMapper.findAll(criteria);
// }
//
// @Override
// public List<Device> queryAllDevices(DeviceQueryCriteria criteria) {
// return deviceMapper.findAllDevices(criteria);
// }
//
// @Override
// @Transactional(rollbackFor = Exception.class)
// public void create(Device resources) {
// deviceMapper.insert(resources);
// }
//
//
// /**
// * 新增设备
// *
// * @param deviceForm
// * @throws Exception
// */
// @Override
// @Transactional(rollbackFor = Exception.class)
// public void addDevice(DeviceForm deviceForm) throws Exception {
//
// // 获取当前登录用户信息
// // Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// // String username1 = authentication.getName();
// // 从缓存获取
// // UserDetails currentUser = SecurityUtils.getCurrentUser();
// // String username = currentUser.getUsername();
// // JwtUserDto jwtUserDto = userCacheManager.getUserCache(username);
// User currentUser = userMapper.findByUsername(SecurityUtils.getCurrentUsername());
//
// if (StringUtils.isNotEmpty(deviceForm.getDeviceMac())) {
// QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
// queryWrapper.eq("device_mac", deviceForm.getDeviceMac());
// // queryWrapper.eq("tenant_id", currentUser.getTenantId());
// if ((deviceMapper.selectOne(queryWrapper)) != null) {
// throw new BadRequestException("设备 mac地址 有误,请仔细核对!!!");
// }
// }
//
// QueryWrapper<DeviceTypeGrants> deviceTypeGrantsQueryWrapper = new QueryWrapper<>();
// deviceTypeGrantsQueryWrapper.eq("customer_id", currentUser.getId());
// deviceTypeGrantsQueryWrapper.eq("device_type_id", deviceForm.getDeviceType());
// Long count = deviceTypeGrantsMapper.selectCount(deviceTypeGrantsQueryWrapper);
// if (count <= 0) {
// throw new BadRequestException("请先授权设备类型!!!");
// }
//
// // 保存图片并获取URL
// String imageUrl = saveDeviceImage(deviceForm.getFile(), deviceForm.getDeviceMac());
// // 设置图片路径
// deviceForm.setDevicePic(imageUrl);
//
// // 转换对象并插入数据库
// Device device = new Device();
// BeanUtil.copyProperties(deviceForm, device, true);
//
// // 添加租户ID
// device.setTenantId(currentUser.getTenantId());
// // 默认状态正常
// device.setDeviceStatus(DeviceStatusEnum.NORMAL.getCode());
// // SnowflakeGenerator snowflakeGenerator = new SnowflakeGenerator();
// // device.setId(snowflakeGenerator.next());
// device.setCurrentOwnerId(currentUser.getId());
// device.setOriginalOwnerId(currentUser.getId());
// DeviceType deviceType = deviceTypeMapper.selectById(deviceForm.getDeviceType());
// device.setTypeName(deviceType.getTypeName());
//
// deviceMapper.insert(device);
//
// // 新增设备类型记录
// DeviceAssignments assignments = new DeviceAssignments();
// assignments.setDeviceId(device.getId());
// assignments.setAssignedAt(LocalDateTime.now());
// // 分配者
// assignments.setAssignerId(currentUser.getId());
// assignments.setAssignerName(currentUser.getUsername());
// // 接收者
// assignments.setAssigneeId(currentUser.getId());
// assignments.setActive(DeviceActiveStatusEnum.ACTIVE.getCode());
// String lever = currentUser.getId() + ":";
// assignments.setLever(lever);
// deviceAssignmentsService.save(assignments);
//
// }
// /**
// * 更新设备信息
// *
// * @param deviceForm /
// * @throws Exception
// */
// @Override
// @Transactional(rollbackFor = Exception.class)
// public void update(DeviceForm deviceForm) throws Exception {
// Device device = getById(deviceForm.getId());
//
// // 处理上传的图片
// String imageUrl = saveDeviceImage(deviceForm.getFile(), device.getDeviceMac());
// deviceForm.setDevicePic(imageUrl);
//
// // 更新字段
// BeanUtil.copyProperties(deviceForm, device, true);
// device.setUpdateTime(new Timestamp(System.currentTimeMillis()));
// deviceMapper.updateById(device);
// }
//
//
// /**
// * 保存设备图片并返回访问路径
// *
// * @param file MultipartFile
// * @param deviceMac 设备MAC用于生成唯一文件名
// * @return 文件存储路径 URL 形式
// */
// private String saveDeviceImage(MultipartFile file, String deviceMac) throws IOException {
// if (file == null || file.isEmpty()) {
// return null;
// }
//
// String originalFileName = file.getOriginalFilename();
// String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
// String newFileName = "PS_" + deviceMac + "." + fileExtension;
//
// File newFile = new File(filePath + DeviceConstants.FILE_ACCESS_ISOLATION + File.separator + newFileName);
//
// if (!newFile.getParentFile().exists()) {
// newFile.getParentFile().mkdirs();
// }
//
// log.info("图片保存路径: {}", newFile.getAbsolutePath());
// file.transferTo(newFile);
//
// return ip + DeviceConstants.FILE_ACCESS_PREFIX + "/" + DeviceConstants.FILE_ACCESS_ISOLATION + "/" + newFileName;
// }
//
//
// /**
// * 分配客户 历史记录版本
// *
// * @param customerVo
// */
//
// public void assignCustomer1(CustomerVo customerVo) {
//
// // 防止管理员误操作
// User currentUser = userService.findById(SecurityUtils.getCurrentUserId());
// if (currentUser.getTenantId().equals(UserConstants.SUPER_ADMIN_ID)) {
// throw new BadRequestException(ExceptionMessages.ADMIN_OPERATION_NOT_ALLOWED);
// }
//
// List<DeviceAssignments> assignments = new ArrayList<>();
// List<DeviceTypeGrants> deviceTypeGrants = new ArrayList<>();
// List<Device> devices = new ArrayList<>();
// customerVo.getDeviceIds().forEach(deviceId -> {
//
// // 阻止重复分配
// Device device = deviceMapper.selectById(deviceId);
// if (device.getCustomerId() != null && device.getCustomerId().equals(customerVo.getCustomerId())) {
// throw new BadRequestException("设备 " + device.getDeviceName() + " 已被分配给客户 " + device.getCustomerName());
// }
//
// // 自定义16位id
// Long generatedId = NanoId.generate(NanoIdLengthEnum.HIGH_CONCURRENCY.getLength());
//
// // -- 记录分配历史
// DeviceAssignments deviceAssignments = new DeviceAssignments();
// deviceAssignments.setId(generatedId);
// deviceAssignments.setDeviceId(deviceId);
// deviceAssignments.setFromCustomerId(currentUser.getId());
// deviceAssignments.setToCustomerId(customerVo.getCustomerId());
// deviceAssignments.setAssignedAt(LocalDateTime.now());
// deviceAssignments.setDeviceTypeGranted(DeviceAuthorizationStatus.AUTHORIZED.getValue());
// assignments.add(deviceAssignments);
//
// // -- 授权设备类型给客户
// // QueryWrapper<DeviceTypeGrants> deviceTypeGrantsQueryWrapper = new QueryWrapper<>();
// // Long count = deviceTypeGrantsMapper.selectCount(deviceTypeGrantsQueryWrapper);
// DeviceTypeGrants deviceTypeGrant = new DeviceTypeGrants();
// deviceTypeGrant.setGrantedAt(new Date());
// // 设备类型
// deviceTypeGrant.setDeviceTypeId(device.getDeviceType());
// deviceTypeGrant.setAssignmentId(generatedId);
// // 被授权的客户
// deviceTypeGrant.setCustomerId(customerVo.getCustomerId());
// // 授权方客户
// deviceTypeGrant.setGrantorCustomerId(currentUser.getId());
// deviceTypeGrants.add(deviceTypeGrant);
//
// // -- 更新设备所有者
// device.setCurrentOwnerId(customerVo.getCustomerId());
// devices.add(device);
// });
//
// deviceAssignmentsService.saveBatch(assignments);
// deviceTypeGrantsService.saveBatch(deviceTypeGrants);
// this.updateBatchById(devices);
//
// }
//
//
// /**
// * 分配客户
// *
// * @param customerVo
// */
// @Override
// @Transactional(rollbackFor = Exception.class)
// public void assignCustomer(CustomerVo customerVo) {
//
// // 获取当前登录用户
// User currentUser = userService.findById(SecurityUtils.getCurrentUserId());
// // 防止管理员误操作
// AdminCheckUtil.checkIfSuperAdmin(currentUser);
// // 获取分配用户信息
// User assignUser = userService.findById(customerVo.getCustomerId());
//
// // 获取分配设备信息
// List<Device> devices = deviceMapper.selectBatchIds(customerVo.getDeviceIds());
//
// // 批量更新设备状态
// List<DeviceTypeGrants> deviceTypeGrants = new ArrayList<>();
// for (Device device : devices) {
//
// // 如果设备已分配给需要分配的客户,则跳过
// LambdaQueryWrapper<DeviceAssignments> wrapper = new LambdaQueryWrapper<>();
// wrapper.eq(DeviceAssignments::getDeviceId, device.getId()).eq(DeviceAssignments::getAssigneeId, customerVo.getCustomerId()).ne(DeviceAssignments::getActive, DeviceActiveStatusEnum.INACTIVE.getCode());
// List<DeviceAssignments> deviceAssignments = deviceAssignmentsMapper.selectList(wrapper);
// if (CollectionUtil.isNotEmpty(deviceAssignments)) {
// log.info("设备 {} 已分配给客户 {}", device.getDeviceName(), device.getCustomerName());
// continue;
// }
//
// // 更改分配客户
// QueryWrapper<DeviceAssignments> q = new QueryWrapper<>();
// q.eq("device_id", device.getId());
// q.eq("assignee_id", currentUser.getId());
// q.ne("active", DeviceActiveStatusEnum.INACTIVE.getCode());
// DeviceAssignments d = new DeviceAssignments();
// d.setAssigneeName(assignUser.getUsername());
// deviceAssignmentsMapper.update(d, q);
//
// // 设备失效
// // 获取用户的设备记录
// DeviceAssignments assignment = deviceAssignmentsMapper.selectOne(new LambdaQueryWrapper<DeviceAssignments>().eq(DeviceAssignments::getDeviceId, device.getId()).eq(DeviceAssignments::getAssigneeId, currentUser.getId()).eq(DeviceAssignments::getActive, DeviceActiveStatusEnum.ACTIVE.getCode()));
//
// LambdaQueryWrapper<DeviceAssignments> q1 = new LambdaQueryWrapper<>();
// q1.eq(DeviceAssignments::getDeviceId, device.getId()).ne(DeviceAssignments::getAssigneeId, currentUser.getId()).like(DeviceAssignments::getLever, assignment.getLever());
//
// DeviceAssignments d1 = new DeviceAssignments();
// d1.setActive(DeviceActiveStatusEnum.INACTIVE.getCode());
// deviceAssignmentsMapper.update(d1, q1);
//
// // device.setCustomerId(assignUser.getId());
// // device.setCustomerName(assignUser.getUsername());
//
// // 新增设备类型记录
// DeviceAssignments assignments = new DeviceAssignments();
// assignments.setDeviceId(device.getId());
// assignments.setAssignedAt(LocalDateTime.now());
// // 分配者
// assignments.setAssignerId(currentUser.getId());
// assignments.setAssignerName(currentUser.getUsername());
// // 接收者
// assignments.setAssigneeId(assignUser.getId());
// // assignments.setAssigneeName(assignUser.getUsername());
// assignments.setActive(DeviceActiveStatusEnum.ACTIVE.getCode());
// String lever = assignment.getLever() + ":" + assignUser.getId();
// assignments.setLever(lever);
// deviceAssignmentsService.save(assignments);
//
// // // 获取当前用户的所有祖先用户
// // List<User> ancestorsById = userMapper.findAncestorsById(currentUser.getId());
// // Set<Long> excludedTenantIds = new HashSet<>();
// // if (CollectionUtil.isNotEmpty(ancestorsById)) {
// // // 提取所有需要排除的 tenant_id
// // excludedTenantIds = ancestorsById.stream().map(User::getTenantId).distinct().collect(Collectors.toSet());
// // }
// // excludedTenantIds.add(currentUser.getTenantId());
// // // 构建查询条件device_mac 相同,并且 tenant_id 不在 excludedTenantIds 列表中
// // Wrapper<Device> wrapper = new QueryWrapper<Device>().eq("device_mac", device.getDeviceMac()).notIn("tenant_id", excludedTenantIds);
// //
// // // 构建要更新的数据
// // Device updateDevice = new Device();
// // updateDevice.setDeviceStatus(0);
// // updateDevice.setUpdateTime(new Timestamp(System.currentTimeMillis()));
//
// // 根据条件批量更新
// // deviceMapper.update(updateDevice, wrapper);
//
// // 创建并保存设备类型授权记录
// createAndSaveDeviceTypeGrants(device, currentUser, customerVo, deviceTypeGrants);
// }
//
// this.updateBatchById(devices);
//
// deviceTypeGrantsService.saveBatch(deviceTypeGrants);
//
// //
// // // 批量分配
// // Set<DeviceType> deviceTypes = new HashSet<>();
// // for (Device device : devices) {
// // device.setId(null);
// // device.setCustomerName(null);
// // device.setCustomerId(null);
// // device.setTenantId(user.getTenantId());
// // device.setCreateTime(timestamp);
// // device.setCreateBy(currentUser.getUsername());
// // device.setUpdateTime(timestamp);
// //
// // // 查询设备类型
// // DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
// // // SnowflakeGenerator snowflakeGenerator = new SnowflakeGenerator();
// // Long id = NanoId.generate(NanoIdLengthEnum.HIGH_CONCURRENCY.getLength());
// // deviceType.setId(id);
// // deviceType.setCreateTime(timestamp);
// // deviceType.setCreateBy(currentUser.getUsername());
// // deviceType.setCustomerId(customerVo.getCustomerId());
// // deviceTypes.add(deviceType);
// //
// // device.setDeviceType(deviceType.getId());
// // }
// // this.saveBatch(devices);
// // deviceTypeService.saveBatch(deviceTypes);
//
// }
//
//
// /**
// * 撤回设备
// *
// * @param deviceForm
// */
// @Override
// public void withdrawDevice(DeviceForm deviceForm) {
// DeviceAssignments assignment = deviceAssignmentsMapper.selectById(deviceForm.getAssignId());
// // 接收者
// assignment.setAssigneeName("");
// deviceAssignmentsMapper.updateById(assignment);
//
// LambdaQueryWrapper<DeviceAssignments> q1 = new LambdaQueryWrapper<>();
// q1.eq(DeviceAssignments::getAssignerId, assignment.getAssigneeId())
// .like(DeviceAssignments::getLever, assignment.getLever())
// .ne(DeviceAssignments::getId, assignment.getId());
//
// DeviceAssignments d1 = new DeviceAssignments();
// d1.setActive(DeviceActiveStatusEnum.INACTIVE.getCode());
// deviceAssignmentsMapper.update(d1, q1);
//
// }
//
//
// /**
// * 创建并保存设备类型授权记录
// *
// * @param device 当前设备对象
// * @param currentUser 当前登录用户
// * @param customerVo 客户信息
// * @param deviceTypeGrants 授权记录集合
// */
// private void createAndSaveDeviceTypeGrants(Device device, User currentUser, CustomerVo customerVo, List<DeviceTypeGrants> deviceTypeGrants) {
// Long generatedId = NanoId.generate(NanoIdLengthEnum.HIGH_CONCURRENCY.getLength());
// DeviceTypeGrants deviceTypeGrant = new DeviceTypeGrants();
// deviceTypeGrant.setGrantedAt(new Date());
// deviceTypeGrant.setDeviceTypeId(device.getDeviceType());
// deviceTypeGrant.setAssignmentId(generatedId);
// deviceTypeGrant.setCustomerId(customerVo.getCustomerId());
// deviceTypeGrant.setGrantorCustomerId(currentUser.getId());
// deviceTypeGrants.add(deviceTypeGrant);
// }
//
//
// /**
// * 删除设备
// *
// * @param ids /
// */
// @Override
// @Transactional(rollbackFor = Exception.class)
// public void deleteAll(List<Long> ids) {
//
// SecurityUtils.getCurrentUserId();
//
// // Step 1: 查询所有传入的设备(根据 ID
// List<Device> allDevices = deviceMapper.selectBatchIds(ids);
// // Step 2: 使用 Java Stream 过滤出 customer_id 不为 null 的设备
// Set<Long> nonNullCustomerIds = allDevices.stream().filter(device -> device.getCustomerId() != null && device.getDeviceStatus() == 1).map(Device::getId).collect(Collectors.toSet());
// // Step 3: 从原始 ids 中“去掉”这些非空 customer_id 的设备 ID
// List<Long> remainingIds = ids.stream().filter(id -> !nonNullCustomerIds.contains(id)).collect(Collectors.toList());
// if (CollectionUtil.isEmpty(remainingIds)) {
// throw new BadRequestException("已分配的设备不允许删除!!!");
// }
// List<Device> devices = deviceMapper.selectBatchIds(remainingIds);
// for (Device device : devices) {
// String devicePic = device.getDevicePic();
// if (StringUtils.isNotBlank(devicePic)) {
// File file = new File(devicePic);
// if (file.exists()) {
// if (file.delete()) {
// log.info("设备图片删除成功");
// } else {
// log.error("设备图片删除失败");
// }
// }
// }
// }
//
// deviceMapper.deleteBatchIds(ids);
// }
// /**
// * 删除设备分配记录分配记录id
// *
// * @param ids
// */
// public void deleteAssign1(List<Long> ids) {
// Long currentUserId = SecurityUtils.getCurrentUserId();
// // Step 1: 查询所有传入的设备(根据 ID
// // List<DeviceAssignments> deviceAssignments = deviceAssignmentsMapper.selectBatchIds(ids);
// QueryWrapper<DeviceAssignments> wrapper = new QueryWrapper<>();
// // wrapper.eq("active", DeviceActiveStatusEnum.INACTIVE.getCode());
// wrapper.in("device_id", ids);
// wrapper.eq("assigner_id", currentUserId);
// List<DeviceAssignments> deviceAssignments = deviceAssignmentsMapper.selectList(wrapper);
// // Step 2: 使用 Java Stream 过滤出 customer_id 不为 null 的设备
// Set<Long> nonNullCustomerIds = deviceAssignments.stream().filter(device -> !StringUtils.isNotEmpty(device.getAssigneeName())).map(DeviceAssignments::getId).collect(Collectors.toSet());
// if (CollectionUtil.isEmpty(nonNullCustomerIds)) {
// throw new BadRequestException("已分配的设备不允许删除!!!");
// }
//
// // QueryWrapper<DeviceAssignments> de = new QueryWrapper<>();
// // wrapper.eq("active", DeviceActiveStatusEnum.INACTIVE.getCode());
// // wrapper.in("device_id", ids);
// // wrapper.eq("assignee_id", currentUserId);
// // deviceAssignmentsMapper.delete(de);
//
// deviceAssignmentsMapper.deleteBatchIds(nonNullCustomerIds);
// }
//
//
// /**
// * 删除设备分配记录分配记录id
// *
// * @param ids
// */
// @Override
// @Transactional(rollbackFor = Exception.class)
// public void deleteAssign(List<Long> ids) {
// // Step 1: 查询所有传入的设备(根据 ID
// List<DeviceAssignments> deviceAssignments = deviceAssignmentsMapper.selectBatchIds(ids);
// // Step 2: 使用 Java Stream 过滤出 customer_id 不为 null 的设备
// Set<Long> nonNullCustomerIds = deviceAssignments.stream()
// .filter(device -> !StringUtils.isNotEmpty(device.getAssigneeName()))
// .map(DeviceAssignments::getId).collect(Collectors.toSet());
// if (CollectionUtil.isEmpty(nonNullCustomerIds)) {
// throw new BadRequestException("已分配的设备不允许删除!!!");
// }
//
// deviceAssignmentsMapper.deleteBatchIds(nonNullCustomerIds);
// deviceTypeGrantsMapper.delete(new QueryWrapper<DeviceTypeGrants>().in("assignment_id", nonNullCustomerIds));
// }
//
//
// @Override
// public void download(List<Device> all, HttpServletResponse response) throws IOException {
// List<Map<String, Object>> list = new ArrayList<>();
// for (Device device : all) {
// Map<String, Object> map = new LinkedHashMap<>();
// map.put("设备类型", device.getTypeName());
// map.put("客户号", device.getCustomerId());
// // map.put("设备编号", device.getDeviceNo());
// map.put("设备名称", device.getDeviceName());
// // map.put("设备图片", device.getDevicePic());
// map.put("设备MAC", device.getDeviceMac());
// map.put("设备SN", device.getDeviceSn());
// map.put("创建者", device.getCreateBy());
// map.put("更新者", device.getUpdateBy());
// map.put("创建时间", device.getCreateTime());
// map.put("更新时间", device.getUpdateTime());
// list.add(map);
// }
// FileUtil.downloadExcel(list, response);
// }
//
// @Override
// @Transactional(rollbackFor = Exception.class)
// public void importData(MultipartFile file) throws IOException {
// String line = "";
// String csvSplitBy = ",";
// List<Device> devices = new ArrayList<>();
// User currentUser = userService.findByName(SecurityUtils.getCurrentUsername());
//
// InputStream inputStream = file.getInputStream();
// InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "GB2312");
// BufferedReader br = new BufferedReader(inputStreamReader);
//
// // BufferedReader br = new BufferedReader(new FileReader((File) file));
// br.readLine(); // 跳过第一行
// while ((line = br.readLine()) != null) {
// // 使用分隔符分割并存储到List中
// String[] values = line.split(csvSplitBy);
// Device device = new Device();
// device.setDeviceName(values[0]);
// device.setDeviceMac(values[1]);
// device.setDeviceSn(values[2]);
// device.setCreateBy(currentUser.getUsername());
// device.setUpdateBy(currentUser.getUsername());
// devices.add(device);
// }
//
// this.saveBatch(devices);
// }
//
//
// /**
// * 解绑设备
// *
// * @param deviceForm
// */
// @Override
// @Transactional
// public void unbindDevice(DeviceForm deviceForm) {
//
// QueryWrapper<APPDevice> queryWrapper = new QueryWrapper<>();
// if (StringUtils.isNotEmpty(deviceForm.getDeviceMac())) {
// queryWrapper.eq("device_mac", deviceForm.getDeviceMac());
// }
// if (StringUtils.isNotEmpty(deviceForm.getDeviceImei())) {
// queryWrapper.eq("device_imei", deviceForm.getDeviceImei());
// }
// appDeviceMapper.delete(queryWrapper);
// Device device = new Device();
// device.setId(deviceForm.getId());
// device.setBindingStatus(BindingStatusEnum.UNBOUND.getCode());
// deviceMapper.updateById(device);
// }
}

View File

@ -0,0 +1,174 @@
<?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.equipment.mapper.DeviceMapper">
<resultMap id="BaseResultMap" type="com.fuyuanshen.equipment.domain.Device">
<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>
<sql id="Base_Column_List">
id
, device_type, customer_id, device_name, device_pic, device_mac, device_sn,
remark, create_by, update_by, create_time, update_time
</sql>
<sql id="device_Column_List">
d
.
id
,d.device_type,
d.customer_id, d.device_name, d.device_pic, d.device_mac,
d.device_sn, d.remark, d.create_by, d.update_by, d.create_time, d.update_time,
d.binding_status, d.device_status, d.current_owner_id, d.original_owner_id, d.customer_name,
d.device_imei, d.longitude, d.latitude, d.tenant_id
</sql>
<!-- 分页查询设备 -->
<select id="findAll" resultType="com.fuyuanshen.equipment.domain.Device">
select
d.id,d.device_name,
d.device_pic, d.device_mac, d.device_sn, d.update_by,d.device_imei,
d.update_time, d.device_type, d.remark, d.binding_status,t.type_name
-- da.assignee_id AS customerId, da.assignee_name AS customerName, da.active AS deviceStatus,
-- da.assigned_at AS create_time , da.assigner_name AS create_by , da.id AS assignId
from device d
LEFT JOIN device_type t ON d.device_type = t.id
-- LEFT JOIN device_assignments da ON da.device_id = d.id
<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 d.device_mac = #{criteria.deviceMac}
</if>
<if test="criteria.deviceImei != null">
and d.device_imei = #{criteria.deviceImei}
</if>
<if test="criteria.deviceType != null">
and d.device_type = #{criteria.deviceType}
</if>
<if test="criteria.deviceStatus != null">
-- and da.active = #{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>
<!-- 下面这两个条件只需满足一个 -->
<!-- <if test="criteria.customerId != null"> -->
<!-- AND ( -->
<!-- tenant_id = #{criteria.tenantId} -->
<!-- OR d.customer_id = #{criteria.customerId} -->
<!-- ) -->
<!-- </if> -->
<!-- <if test="criteria.customerId == null"> -->
<!-- AND tenant_id = #{criteria.tenantId} -->
<!-- </if> -->
</where>
-- ORDER BY create_time DESC
</select>
<select id="findAll1" resultType="com.fuyuanshen.equipment.domain.Device">
SELECT
d.id, d.customer_id, d.customer_name, d.device_name,
d.device_pic, d.device_mac, d.device_sn, d.create_by, d.update_by,
d.create_time, d.update_time, d.device_type, d.remark, d.device_status, t.type_name
from device d
left join device_type t
on d.device_type = t.id
<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 d.device_mac = #{criteria.deviceMac}
</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.createTime != null and criteria.createTime.size() != 0">
and d.create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]}
</if>
<!-- 将两个客户相关条件合并成一个逻辑组 -->
<if test="criteria.customerId != null or (criteria.customerIds != null and !criteria.customerIds.isEmpty())">
AND (
<!-- 条件1: 用户或其下属创建,且 customer_id 为空 -->
<if test="criteria.customerId != null">
d.create_by IN (
SELECT username FROM sys_user
WHERE user_id = #{criteria.customerId} OR pid = #{criteria.customerId}
) AND d.customer_id IS NULL
</if>
<!-- 如果前面的条件不存在,则只保留第二个条件 -->
<choose>
<when test="criteria.customerId != null and (criteria.customerIds != null and !criteria.customerIds.isEmpty())">
OR
</when>
<when test="criteria.customerId == null and (criteria.customerIds != null and !criteria.customerIds.isEmpty())">
<!-- 仅当第一个条件不存在时才开始括号 -->
</when>
</choose>
<!-- 条件2: 客户ID在列表中 -->
<if test="criteria.customerIds != null and !criteria.customerIds.isEmpty()">
(d.customer_id IN
<foreach item="customerId" collection="criteria.customerIds" open="(" separator="," close=")">
#{customerId}
</foreach>
)
</if>
)
</if>
</where>
order by d.id desc
</select>
<select id="findAllDevices" resultType="com.fuyuanshen.equipment.domain.Device">
select
d.id, d.customer_id, d.device_name,
d.device_pic, d.device_mac, d.device_sn, d.create_by, d.update_by,
d.create_time, d.update_time, d.longitude, d.latitude, d.remark
from device 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 d.device_mac = #{criteria.deviceMac}
</if>
<if test="criteria.deviceType != null">
and d.device_type = #{criteria.deviceType}
</if>
<if test="criteria.createTime != null and criteria.createTime.size() != 0">
and d.create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]}
</if>
</where>
order by d.id desc
</select>
</mapper>

View File

@ -1,8 +0,0 @@
package com.fuyuanshen;
import io.quarkus.test.junit.QuarkusIntegrationTest;
@QuarkusIntegrationTest
class ExampleResourceIT extends ExampleResourceTest {
// Execute the same tests but in packaged mode.
}

View File

@ -1,20 +0,0 @@
package com.fuyuanshen;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
@QuarkusTest
class ExampleResourceTest {
@Test
void testHelloEndpoint() {
given()
.when().get("/hello")
.then()
.statusCode(200)
.body(is("Hello from Quarkus REST"));
}
}

View File

@ -333,6 +333,13 @@
<version>${revision}</version>
</dependency>
<!-- 设备管理模块 -->
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-equipment</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.fuyuanshen</groupId>
<artifactId>fys-job</artifactId>
@ -351,6 +358,8 @@
<version>${revision}</version>
</dependency>
<!-- 工作流模块 -->
<dependency>
<groupId>com.fuyuanshen</groupId>