更新代码

This commit is contained in:
zhangyu 2025-09-23 15:53:12 +08:00
parent cabc747f2c
commit 3622a611f4
55 changed files with 717 additions and 413 deletions

View File

@ -100,14 +100,15 @@ spring:
timeout: 30 # 超时时间
keepalive: 60 # 保持连接
clearSession: true # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
topics:
- /zxwl/vehicle/+/info # 清扫车信息上报
- /zxwl/vehicle/+/gps # 定位信息上报
- /zxwl/vehicle/+/fault # 故障信息上报
- /zxwl/vehicle/+/task # 清扫任务推送、任务停止
- /zxwl/vehicle/+/task/status # 清扫任务状态上报
- /zxwl/vehicle/+/ctrl # 驾驶舱远程控制、路径采集
- /zxwl/cockpit/+/heartbeat # 网关心跳
topics: # 订阅主题
- /zxwl/vehicle/+/test
# - /zxwl/vehicle/+/info # 清扫车信息上报
# - /zxwl/vehicle/+/gps # 定位信息上报
# - /zxwl/vehicle/+/fault # 故障信息上报
# - /zxwl/vehicle/+/task # 清扫任务推送、任务停止
# - /zxwl/vehicle/+/task/status # 清扫任务状态上报
# - /zxwl/vehicle/+/ctrl # 驾驶舱远程控制、路径采集
# - /zxwl/cockpit/+/heartbeat # 网关心跳
--- # redis配置
spring:

View File

@ -28,9 +28,9 @@ spring:
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
max-file-size: 50MB
# 设置总上传的文件大小
max-request-size: 20MB
max-request-size: 50MB
mvc:
# 设置静态资源路径 防止所有请求都去查静态资源
static-path-pattern: /static/**

View File

@ -0,0 +1,13 @@
package org.zxwl.common.core.service;
import java.util.List;
/**
* 对象存储管理
*
* @author zy
*/
public interface OssStorageService {
boolean updateByBusinessId(Long businessId, List<Long> ids);
}

View File

@ -1,282 +0,0 @@
package org.zxwl.common.core.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* stream 流工具类
*
* @author zxwl
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class StreamUtils {
/**
* 将collection过滤
*
* @param collection 需要转化的集合
* @param function 过滤方法
* @return 过滤后的list
*/
public static <E> List<E> filter(Collection<E> collection, Predicate<E> function) {
if (CollUtil.isEmpty(collection)) {
return CollUtil.newArrayList();
}
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
return collection.stream().filter(function).collect(Collectors.toList());
}
/**
* 找到流中满足条件的第一个元素
*
* @param collection 需要查询的集合
* @param function 过滤方法
* @return 找到符合条件的第一个元素没有则返回null
*/
public static <E> E findFirst(Collection<E> collection, Predicate<E> function) {
if (CollUtil.isEmpty(collection)) {
return null;
}
return collection.stream().filter(function).findFirst().orElse(null);
}
/**
* 找到流中任意一个满足条件的元素
*
* @param collection 需要查询的集合
* @param function 过滤方法
* @return 找到符合条件的任意一个元素没有则返回null
*/
public static <E> Optional<E> findAny(Collection<E> collection, Predicate<E> function) {
if (CollUtil.isEmpty(collection)) {
return Optional.empty();
}
return collection.stream().filter(function).findAny();
}
/**
* 将collection拼接
*
* @param collection 需要转化的集合
* @param function 拼接方法
* @return 拼接后的list
*/
public static <E> String join(Collection<E> collection, Function<E, String> function) {
return join(collection, function, StringUtil.SEPARATOR);
}
/**
* 将collection拼接
*
* @param collection 需要转化的集合
* @param function 拼接方法
* @param delimiter 拼接符
* @return 拼接后的list
*/
public static <E> String join(Collection<E> collection, Function<E, String> function, CharSequence delimiter) {
if (CollUtil.isEmpty(collection)) {
return StringUtil.EMPTY;
}
return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));
}
/**
* 将collection排序
*
* @param collection 需要转化的集合
* @param comparing 排序方法
* @return 排序后的list
*/
public static <E> List<E> sorted(Collection<E> collection, Comparator<E> comparing) {
if (CollUtil.isEmpty(collection)) {
return CollUtil.newArrayList();
}
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList());
}
/**
* 将collection转化为类型不变的map<br>
* <B>{@code Collection<V> ----> Map<K,V>}</B>
*
* @param collection 需要转化的集合
* @param key V类型转化为K类型的lambda方法
* @param <V> collection中的泛型
* @param <K> map中的key类型
* @return 转化后的map
*/
public static <V, K> Map<K, V> toIdentityMap(Collection<V> collection, Function<V, K> key) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
}
return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
}
/**
* 将Collection转化为map(value类型与collection的泛型不同)<br>
* <B>{@code Collection<E> -----> Map<K,V> }</B>
*
* @param collection 需要转化的集合
* @param key E类型转化为K类型的lambda方法
* @param value E类型转化为V类型的lambda方法
* @param <E> collection中的泛型
* @param <K> map中的key类型
* @param <V> map中的value类型
* @return 转化后的map
*/
public static <E, K, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> key, Function<E, V> value) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
}
return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l));
}
/**
* 将collection按照规则(比如有相同的班级id)分类成map<br>
* <B>{@code Collection<E> -------> Map<K,List<E>> } </B>
*
* @param collection 需要分类的集合
* @param key 分类的规则
* @param <E> collection中的泛型
* @param <K> map中的key类型
* @return 分类后的map
*/
public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
}
return collection
.stream().filter(Objects::nonNull)
.collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));
}
/**
* 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>
* <B>{@code Collection<E> ---> Map<T,Map<U,List<E>>> } </B>
*
* @param collection 需要分类的集合
* @param key1 第一个分类的规则
* @param key2 第二个分类的规则
* @param <E> 集合元素类型
* @param <K> 第一个map中的key类型
* @param <U> 第二个map中的key类型
* @return 分类后的map
*/
public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1, Function<E, U> key2) {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
}
return collection
.stream().filter(Objects::nonNull)
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList())));
}
/**
* 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>
* <B>{@code Collection<E> ---> Map<T,Map<U,E>> } </B>
*
* @param collection 需要分类的集合
* @param key1 第一个分类的规则
* @param key2 第二个分类的规则
* @param <T> 第一个map中的key类型
* @param <U> 第二个map中的key类型
* @param <E> collection中的泛型
* @return 分类后的map
*/
public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1, Function<E, U> key2) {
if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) {
return MapUtil.newHashMap();
}
return collection
.stream().filter(Objects::nonNull)
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
}
/**
* 将collection转化为List集合但是两者的泛型不同<br>
* <B>{@code Collection<E> ------> List<T> } </B>
*
* @param collection 需要转化的集合
* @param function collection中的泛型转化为list泛型的lambda表达式
* @param <E> collection中的泛型
* @param <T> List中的泛型
* @return 转化后的list
*/
public static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function) {
if (CollUtil.isEmpty(collection)) {
return CollUtil.newArrayList();
}
return collection
.stream()
.map(function)
.filter(Objects::nonNull)
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
.collect(Collectors.toList());
}
/**
* 将collection转化为Set集合但是两者的泛型不同<br>
* <B>{@code Collection<E> ------> Set<T> } </B>
*
* @param collection 需要转化的集合
* @param function collection中的泛型转化为set泛型的lambda表达式
* @param <E> collection中的泛型
* @param <T> Set中的泛型
* @return 转化后的Set
*/
public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) {
if (CollUtil.isEmpty(collection) || function == null) {
return CollUtil.newHashSet();
}
return collection
.stream()
.map(function)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
}
/**
* 合并两个相同key类型的map
*
* @param map1 第一个需要合并的 map
* @param map2 第二个需要合并的 map
* @param merge 合并的lambda将key value1 value2合并成最终的类型,注意value可能为空的情况
* @param <K> map中的key类型
* @param <X> 第一个 map的value类型
* @param <Y> 第二个 map的value类型
* @param <V> 最终map的value类型
* @return 合并后的map
*/
public static <K, X, Y, V> Map<K, V> merge(Map<K, X> map1, Map<K, Y> map2, BiFunction<X, Y, V> merge) {
if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) {
return MapUtil.newHashMap();
} else if (MapUtil.isEmpty(map1)) {
map1 = MapUtil.newHashMap();
} else if (MapUtil.isEmpty(map2)) {
map2 = MapUtil.newHashMap();
}
Set<K> key = new HashSet<>();
key.addAll(map1.keySet());
key.addAll(map2.keySet());
Map<K, V> map = new HashMap<>();
for (K t : key) {
X x = map1.get(t);
Y y = map2.get(t);
V z = merge.apply(x, y);
if (z != null) {
map.put(t, z);
}
}
return map;
}
}

View File

@ -13,6 +13,7 @@ import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.zxwl.common.core.utils.IpUtils;
import org.zxwl.common.core.utils.SpringUtil;
import org.zxwl.common.core.utils.StringUtil;
import org.zxwl.common.log.annotation.Log;
import org.zxwl.common.log.event.OperLogEvent;
@ -60,7 +61,6 @@ public class LogAspect {
return object;
}
// @Async
public void saveLog(JoinPoint joinPoint, long time, Exception e) {
OperLogEvent systemLog = new OperLogEvent();
systemLog.setExecuteTime(time);
@ -80,7 +80,7 @@ public class LogAspect {
if (log.operateType() != null) {
systemLog.setOperateType(log.operateType().toString());
}
if (!"".equals(log.operateExplain())) {
if (StringUtil.isNotBlank(log.operateExplain())) {
systemLog.setOperateExplain(log.operateExplain());
}
}

View File

@ -27,7 +27,6 @@ public class MqttInboundConfig {
@Resource
private MqttConfig mqttConfig;
private MqttMessageReceiver mqttMessageReceiver;
/**

View File

@ -5,14 +5,18 @@ import cn.hutool.core.map.MapUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
@Slf4j
@Component
@ -56,7 +60,6 @@ public class RedisUtil {
}
public static Boolean exist(String key) {
System.out.println("key = " + key);
try {
return Objects.equals(redisTemplate.hasKey(key), Boolean.TRUE);
} catch (Exception e) {
@ -124,7 +127,7 @@ public class RedisUtil {
public static void putHashAll(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
} catch (Exception e) {
} catch (Exception e) {
log.error("Error putting hashMap: {}", e.getMessage(), e);
}
}
@ -133,7 +136,7 @@ public class RedisUtil {
try {
redisTemplate.opsForHash().putAll(key, map);
redisTemplate.expire(key, time, timeUnit);
} catch (Exception e) {
} catch (Exception e) {
log.error("Error putting hashMap: {}", e.getMessage(), e);
}
}
@ -232,4 +235,118 @@ public class RedisUtil {
return count;
});
}
/**
* 获取前缀匹配的所有 key 名称
*
* @param keyPrefix key 前缀 "user:profile:"
* @return key集合
*/
public static Set<String> getKeysByPrefix(String keyPrefix) {
Set<String> keys = new HashSet<>();
redisTemplate.execute((RedisConnection connection) -> {
ScanOptions options = ScanOptions.scanOptions()
.match(keyPrefix + "*")
.count(100)
.build();
try (Cursor<byte[]> cursor = connection.scan(options)) {
while (cursor.hasNext()) {
byte[] rawKey = cursor.next();
keys.add(new String(rawKey));
}
}
return null;
});
return keys;
}
/**
* 获取指定前缀的所有 key 后缀
*
* @param keyPrefix 前缀 "ZXWL:COCKPIT:ONLINE"
* @return 后缀集合去除前缀后的部分
*/
public static Set<String> getSuffixesByPrefix(String keyPrefix) {
Set<String> suffixes = new HashSet<>();
redisTemplate.execute((RedisConnection connection) -> {
// 构造 SCAN 模式前缀 + "*"
ScanOptions options = ScanOptions.scanOptions()
.match(keyPrefix + "*") // 匹配所有以前缀开头的 key
.count(100)
.build();
try (Cursor<byte[]> cursor = connection.scan(options)) {
while (cursor.hasNext()) {
String fullKey = new String(cursor.next());
// 判断是否以前缀开头双重保险
if (fullKey.startsWith(keyPrefix)) {
String suffix = fullKey.substring(keyPrefix.length());
if (!suffix.isEmpty()) {
suffixes.add(suffix);
}
}
}
} catch (Exception e) {
throw new RuntimeException("Error scanning Redis keys", e);
}
return null;
});
return suffixes;
}
/**
* 通用方法根据前缀扫描 Hash Key检查指定 field 是否满足条件返回 Key 的后缀集合
*
* @param keyPrefix Hash Key 前缀
* @param fieldName 要检查的 field
* @param condition 条件判断器Predicate<String>接收 field value字符串返回是否匹配
* @return 满足条件的 Key 后缀集合
*/
public static Set<String> getKeySuffixesByHashField(String keyPrefix, String fieldName, Predicate<String> condition) {
Set<String> suffixes = new HashSet<>();
redisTemplate.execute((RedisConnection connection) -> {
ScanOptions options = ScanOptions.scanOptions()
.match(keyPrefix + "*")
.count(100)
.build();
try (Cursor<byte[]> cursor = connection.scan(options)) {
while (cursor.hasNext()) {
byte[] rawKey = cursor.next();
String fullKey = new String(rawKey, StandardCharsets.UTF_8);
// 判断键是否为哈希类型
DataType type = connection.type(rawKey);
if (type == null || !type.equals(DataType.HASH)) {
continue; // 如果不是哈希类型则跳过
}
// 获取指定 field 的值
byte[] rawValue = connection.hGet(rawKey, fieldName.getBytes(StandardCharsets.UTF_8));
if (rawValue != null) {
String value = new String(rawValue, StandardCharsets.UTF_8).trim();
// 使用传入的条件判断器进行匹配
if (condition.test(value)) {
if (fullKey.startsWith(keyPrefix)) {
String suffix = fullKey.substring(keyPrefix.length());
suffixes.add(suffix);
}
}
}
}
} catch (Exception e) {
throw new RuntimeException("Error scanning Redis hash keys", e);
}
return null;
});
return suffixes;
}
}

View File

@ -18,7 +18,6 @@ public class ScheduleConfig {
@Scheduled(cron = "0/10 * * * * ?")
public void checkCockpitStatus() {
long threshold = Instant.now().minus(30, ChronoUnit.SECONDS).getEpochSecond();
RedisUtil.removeRangeByScore(RedisKeyConst.COCKPIT_ONLINE_KEY, 0, threshold);
RedisUtil.removeRangeByScore(RedisKeyConst.COCKPIT_ONLINE, 0, threshold);
}
}

View File

@ -2,29 +2,22 @@ package org.zxwl.sweeper.constant;
public interface RedisKeyConst {
String HEARTBEAT_PREFIX = "ZXWL:GATEWAY:HEARTBEAT:"; //网关心跳
String DELAY_PREFIX = "ZXWL:GATEWAY:DELAY:"; //网关时延
String DISPATCH_UNDO_VID_LIST = "ZXWL:DISPATCH:UNDO"; //调度记录未完成的VID列表
String GATEWAY_INFO_IP = "ZXWL:GATEWAY:INFO:IP"; //记录网关IP信息
String GATEWAY_INFO_URL = "ZXWL:GATEWAY:INFO:URL"; //记录网关摄像头地址信息
String HEARTBEAT_PREFIX = "ZXWL:GATEWAY:HEARTBEAT:"; // 网关心跳
String DELAY_PREFIX = "ZXWL:GATEWAY:DELAY:"; // 网关时延
String DISPATCH_UNDO_VID_LIST = "ZXWL:DISPATCH:UNDO"; // 调度记录未完成的VID列表
String GATEWAY_INFO_IP = "ZXWL:GATEWAY:INFO:IP"; // 记录网关IP信息
String GATEWAY_INFO_URL = "ZXWL:GATEWAY:INFO:URL"; // 记录网关摄像头地址信息
// vehicle车俩
String VEHICLE_CTRL_RESPONSE = "ZXWL:VEHICLE:CTRL:RESPONSE:"; //车辆控制响应
String VEHICLE_STATUS = "ZXWL:VEHICLE:ONLINE:"; //车辆在线状态
String VEHICLE_FAULT_STATUS = "ZXWL:VEHICLE:FAULT:"; //车辆故障状态
String VEHICLE_POWER = "ZXWL:VEHICLE:POWER:"; //车辆电量
String VEHICLE_STATUS_INFO = "ZXWL:VEHICLE:STATUS:INFO:"; //车俩状态
String VEHICLE_CTRL_RESPONSE = "ZXWL:VEHICLE:CTRL:RESPONSE:"; // 车辆控制响应
String VEHICLE_ONLINE = "ZXWL:VEHICLE:ONLINE:"; // 车辆实时状态
String VEHICLE_FAULT = "ZXWL:VEHICLE:FAULT:"; // 车辆故障状态
String VEHICLE_POWER = "ZXWL:VEHICLE:POWER:"; // 车辆剩余电量
// route路径
String ROUTE_KEY_PREFIX = "routeName:";
String COCKPIT_ONLINE = "ZXWL:COCKPIT:ONLINE:"; //驾驶实时状态
// task任务
String TASK_RESPONSE = "ZXWL:VEHICLE:TASK:RESPONSE:"; //任务响应
// cockpit驾驶舱
String COCKPIT_ONLINE_PREFIX = "ZXWL:COCKPIT:ONLINE:";
String COCKPIT_ONLINE_KEY = "ZXWL:COCKPIT:ONLINE";
String ROUTE_KEY_PREFIX = "routeName:"; // 路径采集
String DEVICE_STATUS_KEY_PREFIX = "ZXWL:DEVICE_STATUS:";
}

View File

@ -10,6 +10,7 @@ import org.zxwl.common.core.validate.UpdateGroup;
import org.zxwl.common.log.annotation.Log;
import org.zxwl.common.log.enums.ModuleType;
import org.zxwl.common.log.enums.OperateType;
import org.zxwl.common.satoken.utils.LoginHelper;
import org.zxwl.common.web.base.BaseController;
import org.zxwl.sweeper.enums.RepairStatusEnum;
import org.zxwl.sweeper.model.faultRepair.*;
@ -32,14 +33,36 @@ public class FaultRepairController extends BaseController {
private final FaultRepairService faultRepairService;
/**
* 分页列表
*
* @param query 查询条件
*/
@GetMapping
public Result<Page<FaultRepairVo>> queryPage(FaultRepairQuery query) {
return Result.success(faultRepairService.queryPage(query));
}
@GetMapping
public Result<FaultRepairDataVo> data() {
return Result.success(faultRepairService.data());
/**
* 我提交的列表 报修人员查询
*
* @param query 查询条件
*/
@GetMapping("/mySubmitList")
public Result<Page<FaultRepairVo>> mySubmitList(FaultRepairQuery query) {
query.setReportUserId(LoginHelper.getUserId());
return Result.success(faultRepairService.queryPage(query));
}
/**
* 代办列表维修人员查询
*
* @param query 查询条件
*/
@GetMapping("/pendList")
public Result<Page<FaultRepairVo>> pendList(FaultRepairQuery query) {
query.setAssignToUserId(LoginHelper.getUserId());
return Result.success(faultRepairService.queryPage(query));
}
@PostMapping
@ -90,4 +113,14 @@ public class FaultRepairController extends BaseController {
public Result<Void> cancel(@PathVariable("id") Long id) {
return toResult(faultRepairService.updateByStatus(id, RepairStatusEnum.CANCEL.getValue()));
}
/**
* 统计数据待办数量处理中数量
*
* @return Result
*/
@GetMapping("/data")
public Result<FaultRepairDataVo> data() {
return Result.success(faultRepairService.data());
}
}

View File

@ -1,11 +1,20 @@
package org.zxwl.sweeper.controller;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zxwl.common.mqtt.handler.MqttMessageSender;
import org.zxwl.common.utils.RedisUtil;
import org.zxwl.sweeper.model.taskInfo.TaskStatusReport;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RequiredArgsConstructor
@ -15,10 +24,34 @@ public class TestController {
private final MqttMessageSender mqttMessageSender;
private final KafkaTemplate<String, Object> kafkaTemplate;
@PostMapping("/mqtt")
public void mqtt(String topic, Integer qos, String message) {
log.info("测试mqtt发送消息-topic: {}, qos: {}, message: {}", topic, qos, message);
mqttMessageSender.send(topic, qos, message);
}
@PostMapping("/kafka")
public void kafka(@RequestBody TaskStatusReport taskStatusReport) {
kafkaTemplate.send("zxwl.vehicle.123456.task.status", JSONUtil.toJsonStr(taskStatusReport));
}
@PostMapping("/redis")
public void redis() {
Map<String,Object> map = new HashMap<>();
map.put("name","zhangyu");
map.put("age",25);
RedisUtil.putHashAll("user", map);
RedisUtil.setValue("name", "zhangyu");
RedisUtil.addZSet("status", "1", Instant.now().getEpochSecond());
RedisUtil.addZSet("status", "2", Instant.now().getEpochSecond());
System.out.println(RedisUtil.exist("name"));
System.out.println(RedisUtil.exist("user"));
System.out.println(RedisUtil.exist("status"));
}
}

View File

@ -1,5 +1,6 @@
package org.zxwl.sweeper.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@ -7,15 +8,28 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zxwl.common.core.domain.Result;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleDetail;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleQuery;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleVO;
import org.zxwl.sweeper.service.VehicleAppInfoService;
@RestController
@RequiredArgsConstructor
@RequestMapping("/vehicleApp")
public class VehicleAppInfoController {
public class VehicleAppController {
private final VehicleAppInfoService vehicleAppInfoService;
/**
* 小程序首页-车辆列表实时展示任务执行状态故障电量充电状态等
*
* @param query 查询
* @return Result
*/
@GetMapping()
public Result<Page<VehicleVO>> pageList(VehicleQuery query) {
return Result.success(vehicleAppInfoService.pageList(query));
}
@GetMapping("/detail/{vid}")
public Result<VehicleDetail> vehicleDetail(@PathVariable("vid") Long vid) {
return Result.success(vehicleAppInfoService.getVehicleDetail(vid));

View File

@ -12,7 +12,7 @@ import org.zxwl.common.log.annotation.Log;
import org.zxwl.common.log.enums.ModuleType;
import org.zxwl.common.log.enums.OperateType;
import org.zxwl.common.web.base.BaseController;
import org.zxwl.sweeper.model.VehicleInfoAPPVO;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleInfoAPPVO;
import org.zxwl.sweeper.model.app.vehicleCard.VehicleCard;
import org.zxwl.sweeper.model.vehicleInfo.*;
import org.zxwl.sweeper.service.VehicleInfoService;
@ -107,6 +107,13 @@ public class VehicleInfoController extends BaseController {
return toResult(vehicleInfoService.bindCockpit(id, cid));
}
@PutMapping("unbinding")
//@SaCheckPermission("vehicle:info:unbinding")
@Log(module = ModuleType.VEHICLE, operateType = OperateType.OTHER, operateExplain = "车辆解绑")
public Result<Void> unbindCockpit(@RequestParam("id") Long id) {
return toResult(vehicleInfoService.unbindCockpit(id));
}
@GetMapping("exist")
public Result<Void> existVehicleInfo(@RequestParam("vid") String vid) {
return toResult(vehicleInfoService.exitVehicleInfo(vid));

View File

@ -1,5 +1,6 @@
package org.zxwl.sweeper.listener;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -14,7 +15,6 @@ import org.zxwl.sweeper.constant.KafkaTopicConst;
import org.zxwl.sweeper.constant.RedisKeyConst;
import org.zxwl.sweeper.utils.KafkaUtil;
import java.time.Instant;
import java.util.Optional;
@Slf4j
@ -29,8 +29,8 @@ public class CockpitKafkaConsumer {
if (message.isPresent()) {
String cid = KafkaUtil.getVIdByTopic(topic, 3);
if (CharSequenceUtil.isEmpty(cid)) return;
// RedisUtil.setValueWithExpire(RedisKeyConst.COCKPIT_ONLINE_PREFIX + cid, LocalDateTimeUtil.now(), 30);
RedisUtil.addZSet(RedisKeyConst.COCKPIT_ONLINE_KEY, cid, Instant.now().getEpochSecond());
RedisUtil.setValueWithExpire(RedisKeyConst.COCKPIT_ONLINE + cid, LocalDateTimeUtil.now(), 30);
// RedisUtil.addZSet(RedisKeyConst.COCKPIT_ONLINE, cid, Instant.now().getEpochSecond());
ack.acknowledge();
}
}

View File

@ -14,6 +14,8 @@ import org.zxwl.common.utils.RedisUtil;
import org.zxwl.sweeper.constant.KafkaTopicConst;
import org.zxwl.sweeper.constant.RedisKeyConst;
import org.zxwl.sweeper.model.reply.ReplyHeader;
import org.zxwl.sweeper.model.taskInfo.TaskStatusReport;
import org.zxwl.sweeper.service.TaskInfoService;
import java.util.Optional;
@ -22,6 +24,8 @@ import java.util.Optional;
@RequiredArgsConstructor
public class TaskKafkaConsumer {
private final TaskInfoService taskInfoService;
@KafkaListener(id = "task_push", topicPattern = KafkaTopicConst.VEHICLE_TASK)
public void handleVehicleTask(ConsumerRecord<String, String> consumerRecord, Acknowledgment ack,
@Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {
@ -46,6 +50,9 @@ public class TaskKafkaConsumer {
if (message.isPresent()) {
String msg = message.get();
log.info("task_status_push <==> {}", msg);
// 同步更新任务状态
TaskStatusReport taskStatusReport = JSONUtil.toBean(msg, TaskStatusReport.class);
taskInfoService.updateStatus(taskStatusReport.getId(), taskStatusReport.getStatus());
ack.acknowledge();
}
}

View File

@ -57,25 +57,21 @@ public class VehicleKafkaConsumer {
@KafkaListener(id = "vehicle_base_info", topicPattern = KafkaTopicConst.VEHICLE_INFO)
public void handleVehicleInfo(ConsumerRecord<String, String> consumerRecord, Acknowledgment ack,
@Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {
@Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {
Optional<String> message = Optional.ofNullable(consumerRecord.value());
if (message.isPresent()) {
String msg = message.get();
String vid = KafkaUtil.getVIdByTopic(topic, 3);
if (CharSequenceUtil.isEmpty(vid)) return;
// 车俩在线状态
RedisUtil.setValueWithExpire(RedisKeyConst.VEHICLE_STATUS + vid,
System.currentTimeMillis(), 30);
JSONObject jsonObject = new JSONObject(msg);
Optional<Object> optional = RedisUtil.getValue(RedisKeyConst.DELAY_PREFIX + vid);
if (optional.isPresent()) {
jsonObject.set("delay", optional.get());
}else {
} else {
jsonObject.set("delay", 999);
}
// log.info("[kafka] ==> Topic: {}, Message: {}", topic, jsonObject);
VehicleInfoWebSocket.sendBroadcast(vid, 1, jsonObject.toString());
Map<String, Object> map = BeanUtil.beanToMap(jsonObject);
@ -83,18 +79,18 @@ public class VehicleKafkaConsumer {
vehicleInfoReport.setVid(vid);
vehicleInfoReport.setCreatedAt(LocalDateTime.now());
// 车俩电池容量
RedisUtil.setValue(RedisKeyConst.VEHICLE_POWER + vid ,vehicleInfoReport.getPower());
RedisUtil.setValue(RedisKeyConst.VEHICLE_POWER + vid, vehicleInfoReport.getPower());
// 车俩实时状态信息(档位水位充电状态速度电机温度垃圾豆容量等)
RedisUtil.putHashAll(RedisKeyConst.VEHICLE_STATUS_INFO + vid, map, 30, TimeUnit.SECONDS);
mongoTemplate.save(vehicleInfoReport, "v_vehicle_info");
RedisUtil.putHashAll(RedisKeyConst.VEHICLE_ONLINE + vid, map, 30, TimeUnit.SECONDS);
mongoTemplate.save(vehicleInfoReport, "v_vehicle_info");
ack.acknowledge();
}
}
@KafkaListener(id = "vehicle_gps_info", topicPattern = KafkaTopicConst.VEHICLE_GPS)
public void handleGPSInfo(ConsumerRecord<String, String> consumerRecord, Acknowledgment ack,
@Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {
@Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {
Optional<String> message = Optional.ofNullable(consumerRecord.value());
if (message.isPresent()) {
String msg = message.get();
@ -133,7 +129,7 @@ public class VehicleKafkaConsumer {
VehicleFaultInfo vehicleFaultInfo = JSONUtil.toBean(msg, VehicleFaultInfo.class);
vehicleFaultInfo.setVin(vid);
vehicleFaultInfo.setCreatedAt(LocalDateTime.now());
RedisUtil.setValueWithExpire(RedisKeyConst.VEHICLE_FAULT_STATUS + vid ,
RedisUtil.setValueWithExpire(RedisKeyConst.VEHICLE_FAULT + vid,
System.currentTimeMillis(), 30);
mongoTemplate.save(vehicleFaultInfo, "v_fault_info");
ack.acknowledge();

View File

@ -1,8 +1,13 @@
package org.zxwl.sweeper.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.zxwl.sweeper.entity.VehicleInfo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.zxwl.sweeper.entity.VehicleInfo;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleVO;
import java.util.Set;
/**
* <p>
@ -15,4 +20,8 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface VehicleInfoMapper extends BaseMapper<VehicleInfo> {
Page<VehicleVO> queryPage(@Param("page") Page<VehicleInfo> page,
@Param("key") String key,
@Param("status") Integer status,
@Param("vids") Set<String> vids);
}

View File

@ -73,7 +73,7 @@ public class CockpitInfoVO {
this.picture = EnvUtil.getProperty("minio.pathPrefix") + cockpitInfo.getPicture();
}
if (RedisUtil.exist(RedisKeyConst.COCKPIT_ONLINE_PREFIX + cockpitInfo.getCid())) {
if (RedisUtil.exist(RedisKeyConst.COCKPIT_ONLINE + cockpitInfo.getCid())) {
this.status = OnlineEnum.ONLINE.getValue();
} else {
this.status = OnlineEnum.OFFLINE.getValue();

View File

@ -30,7 +30,7 @@ public class CockpitStatusInfoVO {
if (cockpitInfo != null) {
this.name = cockpitInfo.getName();
this.faultStatus = cockpitInfo.getFaultStatus();
if (RedisUtil.exist(RedisKeyConst.COCKPIT_ONLINE_PREFIX + cockpitInfo.getCid())) {
if (RedisUtil.exist(RedisKeyConst.COCKPIT_ONLINE + cockpitInfo.getCid())) {
this.status = OnlineEnum.ONLINE.getValue();
} else {
this.status = OnlineEnum.OFFLINE.getValue();

View File

@ -17,10 +17,29 @@ import org.zxwl.sweeper.entity.FaultRepair;
@Setter
public class FaultRepairQuery extends BaseQuery<FaultRepair> {
private String title;
/**
* 搜索
*/
private String key;
/**
* 状态 0-待处理 1-处理中 2-已处理中 3-已关闭 4-已取消
*/
private Integer status;
/**
* 优先级 0- 1- 2- 3-紧急
*/
private Integer priority;
/**
* 报修人id
*/
private Long reportUserId;
/**
* 维修人id
*/
private Long assignToUserId;
}

View File

@ -23,7 +23,6 @@ public class FaultRepairVo {
*/
private Long id;
/**
* 标题
*/
@ -34,21 +33,11 @@ public class FaultRepairVo {
*/
private String description;
/**
* 报修人id
*/
private Long reportUserId;
/**
* 报修人姓名
*/
private String reportName;
/**
* 报修人手机号
*/
private String reportPhone;
/**
* 优先级
*/
@ -69,21 +58,11 @@ public class FaultRepairVo {
*/
private String statusCn;
/**
* 指派给维修人员ID
*/
private Long assignToUserId;
/**
* 指派给维修人员姓名
*/
private String assignName;
/**
* 维修人员手机号
*/
private String assignPhone;
/**
* 维修结果描述
*/

View File

@ -1,8 +1,6 @@
package org.zxwl.sweeper.model.taskInfo;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
@ -59,8 +57,4 @@ public class TaskInfoDTO {
BeanUtil.copyProperties(this, taskInfo);
return taskInfo;
}
public static void main(String[] args) {
System.out.println(JSONUtil.toJsonStr(new TaskInfoDTO(), JSONConfig.create().setIgnoreNullValue(false)));
}
}

View File

@ -60,6 +60,9 @@ public class TaskInfoVO {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime created;
/**
* 执行状态
*/
private Integer status;
public TaskInfoVO(TaskInfo taskInfo) {

View File

@ -24,6 +24,10 @@ public class TaskPushInfo {
* 清扫次数
*/
private Integer count;
/**
* 路径信息
*/
private RoutePushInfo routeInfo;
public TaskPushInfo(TaskInfo taskInfo, RoutePushInfo routeInfo) {

View File

@ -0,0 +1,19 @@
package org.zxwl.sweeper.model.taskInfo;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TaskStatusReport {
/**
* 任务id
*/
private Long id;
/**
* 任务状态
*/
private Integer status;
}

View File

@ -15,7 +15,7 @@ public class TaskRecordQuery extends BaseQuery<TaskRecord> {
private Long vehicleId;
/**
* 执行状态 0 待执行 1 执行中 2 已完成
* 执行状态 0 待执行 1 执行中 2 已完成 3-执行异常
*/
private Integer status;

View File

@ -12,6 +12,9 @@ import java.time.LocalDateTime;
@Setter
public class TaskRecordVO {
/**
* 任务记录主键id
*/
private Long id;
/**
@ -19,10 +22,13 @@ public class TaskRecordVO {
*/
private String taskName;
/**
* 车辆名称
*/
private String vehicleName;
/**
* 执行状态 0 待执行 1 执行中 2 已完成
* 执行状态 0 待执行 1 执行中 2 已完成 3 执行异常
*/
private Integer status;

View File

@ -19,7 +19,15 @@ public class VehicleInfoQuery extends BaseQuery<VehicleInfo> {
* 车辆名称/车牌号
*/
private String key;
/**
* 车辆编号
*/
private String vid;
/**
* 驾驶舱编号
*/
private String cid;
/**

View File

@ -94,7 +94,7 @@ public class VehicleInfoVO {
if (CharSequenceUtil.isNotEmpty(vehicleInfo.getPicture())) {
this.picture = EnvUtil.getProperty("minio.pathPrefix") + vehicleInfo.getPicture();
}
if (RedisUtil.exist(RedisKeyConst.VEHICLE_STATUS + vehicleInfo.getVid())) {
if (RedisUtil.exist(RedisKeyConst.VEHICLE_ONLINE + vehicleInfo.getVid())) {
this.status = OnlineEnum.ONLINE.getValue();
} else {
this.status = OnlineEnum.OFFLINE.getValue();

View File

@ -29,8 +29,14 @@ public class VehicleStatusVO {
*/
private Integer status;
/**
* 路径id
*/
private Long currentRouteId;
/**
* 经纬度
*/
private Coordinate coordinate;
public VehicleStatusVO(VehicleInfo vehicleInfo, Long currentRouteId) {

View File

@ -8,7 +8,9 @@ import org.zxwl.sweeper.model.taskInfo.app.TaskInfoAPPVO;
@Setter
public class VehicleDetail {
private VehicleSimpleInfoVO vehicleSimpleInfoVO; //车辆信息
private VehicleSimpleInfoVO vehicleSimpleInfoVO; //基础信息
private VehicleOperatingStatusVO vehicleOperatingStatusVO; //实时状态
private TaskInfoAPPVO taskInfoVO; //当前任务
}

View File

@ -1,4 +1,4 @@
package org.zxwl.sweeper.model;
package org.zxwl.sweeper.model.vehicleInfo.app;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.text.CharSequenceUtil;
@ -55,13 +55,13 @@ public class VehicleInfoAPPVO {
if (CharSequenceUtil.isNotEmpty(vehicleInfo.getPicture())) {
this.picture = EnvUtil.getProperty("minio.pathPrefix") + vehicleInfo.getPicture();
}
if (RedisUtil.exist(RedisKeyConst.VEHICLE_STATUS + vehicleInfo.getVid())) {
if (RedisUtil.exist(RedisKeyConst.VEHICLE_ONLINE + vehicleInfo.getVid())) {
this.status = OnlineEnum.ONLINE.getValue();
} else {
this.status = OnlineEnum.OFFLINE.getValue();
}
if (RedisUtil.exist(RedisKeyConst.VEHICLE_FAULT_STATUS + vehicleInfo.getVid())) {
if (RedisUtil.exist(RedisKeyConst.VEHICLE_FAULT + vehicleInfo.getVid())) {
this.faultStatus = OnlineEnum.ONLINE.getValue();
} else {
this.faultStatus = OnlineEnum.OFFLINE.getValue();

View File

@ -0,0 +1,16 @@
package org.zxwl.sweeper.model.vehicleInfo.app;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class VehicleOperatingStatusVO {
private Float gear; //档位 0:空档 1:前进档 2:倒档 3:驻车档
private Float waterLevel; //水位 %
private Boolean chargeStatus; //充电状态
private Float speed; //车辆速度 km/h
private Float motorTemp; //电机温度
private Float power; //剩余电量 %
}

View File

@ -0,0 +1,23 @@
package org.zxwl.sweeper.model.vehicleInfo.app;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.zxwl.common.mybatis.page.BaseQuery;
import org.zxwl.sweeper.entity.VehicleInfo;
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
public class VehicleQuery extends BaseQuery<VehicleInfo> {
/**
* 车辆名称/车牌号
*/
private String key;
/**
* 状态 0-任务执行中 1-待执行 2-故障 3-充电
*/
private Integer status;
}

View File

@ -52,12 +52,12 @@ public class VehicleSimpleInfoVO {
if (CharSequenceUtil.isNotEmpty(vehicleInfo.getPicture())) {
this.picture = EnvUtil.getProperty("minio.pathPrefix") + vehicleInfo.getPicture();
}
if (RedisUtil.exist(RedisKeyConst.VEHICLE_STATUS + vehicleInfo.getVid())) {
if (RedisUtil.exist(RedisKeyConst.VEHICLE_ONLINE + vehicleInfo.getVid())) {
this.status = OnlineEnum.ONLINE.getValue();
} else {
this.status = OnlineEnum.OFFLINE.getValue();
}
if (RedisUtil.exist(RedisKeyConst.VEHICLE_FAULT_STATUS + vehicleInfo.getVid())) {
if (RedisUtil.exist(RedisKeyConst.VEHICLE_FAULT + vehicleInfo.getVid())) {
this.faultStatus = OnlineEnum.ONLINE.getValue();
} else {
this.faultStatus = OnlineEnum.OFFLINE.getValue();

View File

@ -0,0 +1,59 @@
package org.zxwl.sweeper.model.vehicleInfo.app;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class VehicleVO {
/**
* 主键id
*/
private Long id;
/**
* 车辆编号
*/
private String vid;
/**
* 车辆名称
*/
private String name;
/**
* 车牌号
*/
private String plateNumber;
/**
* 车辆图片
*/
private String picture;
/**
* 状态 0 离线 1 在线
*/
private int status;
/**
* 故障状态
*/
private int faultStatus;
/**
* 任务状态
*/
private int taskStatus;
/**
* 剩余电量
*/
private double power;
/**
* 充电状态
*/
private boolean chargeStatus;
}

View File

@ -30,13 +30,13 @@ public class VehicleStatusInfoVO {
if (vehicleInfo != null) {
this.name = vehicleInfo.getName();
if (RedisUtil.exist(RedisKeyConst.VEHICLE_STATUS + vehicleInfo.getVid())) {
if (RedisUtil.exist(RedisKeyConst.VEHICLE_ONLINE + vehicleInfo.getVid())) {
this.status = OnlineEnum.ONLINE.getValue();
} else {
this.status = OnlineEnum.OFFLINE.getValue();
}
if (RedisUtil.exist(RedisKeyConst.VEHICLE_FAULT_STATUS + vehicleInfo.getVid())) {
if (RedisUtil.exist(RedisKeyConst.VEHICLE_FAULT + vehicleInfo.getVid())) {
this.faultStatus = OnlineEnum.ONLINE.getValue();
} else {
this.faultStatus = OnlineEnum.OFFLINE.getValue();

View File

@ -14,6 +14,7 @@ import org.zxwl.sweeper.model.faultRepair.*;
* @since 2025-09-19
*/
public interface FaultRepairService extends IService<FaultRepair> {
Page<FaultRepairVo> queryPage(FaultRepairQuery query); // 分页查询
FaultRepairDataVo data(); // 统计代办和处理中总数量

View File

@ -35,4 +35,6 @@ public interface TaskInfoService extends IService<TaskInfo> {
boolean start(Long id); //开始
boolean stop(Long id); //停止
void updateStatus(Long id, Integer status); //车端任务状态上报更新
}

View File

@ -1,8 +1,13 @@
package org.zxwl.sweeper.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleDetail;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleQuery;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleVO;
public interface VehicleAppInfoService {
Page<VehicleVO> pageList(VehicleQuery query);
VehicleDetail getVehicleDetail(Long vehicleId);
}

View File

@ -3,7 +3,7 @@ package org.zxwl.sweeper.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.zxwl.sweeper.entity.VehicleInfo;
import org.zxwl.sweeper.model.VehicleInfoAPPVO;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleInfoAPPVO;
import org.zxwl.sweeper.model.app.vehicleCard.VehicleCard;
import org.zxwl.sweeper.model.vehicleInfo.*;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleSimpleInfoVO;
@ -47,6 +47,8 @@ public interface VehicleInfoService extends IService<VehicleInfo> {
boolean bindCockpit(Long id, String cid); //绑定驾驶舱
boolean unbindCockpit(Long id); //解绑驾驶舱
boolean hasGateway(String vid); //判断是否具有网关
Long onlineCount(); //在线数

View File

@ -175,7 +175,7 @@ public class CockpitInfoServiceImpl extends ServiceImpl<CockpitInfoMapper, Cockp
long remoteCtrlCount = dispatchRecordMapper.selectCount(Wrappers.query(DispatchRecord.class).lambda()
.ne(DispatchRecord::getStatus, DispatchStatusEnum.DISPATCH_END.getValue()));
long onlineCount = RedisUtil.countKeysByPrefix(RedisKeyConst.COCKPIT_ONLINE_PREFIX);
long onlineCount = RedisUtil.countKeysByPrefix(RedisKeyConst.COCKPIT_ONLINE);
CockpitStatisticsVO statisticsVO = new CockpitStatisticsVO();
statisticsVO.setOnlineCount(onlineCount);

View File

@ -5,6 +5,9 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zxwl.common.core.service.OssStorageService;
import org.zxwl.common.satoken.utils.LoginHelper;
import org.zxwl.sweeper.entity.FaultRepair;
import org.zxwl.sweeper.enums.RepairStatusEnum;
import org.zxwl.sweeper.mapper.FaultRepairMapper;
@ -29,6 +32,8 @@ public class FaultRepairServiceImpl extends ServiceImpl<FaultRepairMapper, Fault
private final FaultRepairMapper faultRepairMapper;
private final OssStorageService ossStorageService;
@Override
public Page<FaultRepairVo> queryPage(FaultRepairQuery query) {
return faultRepairMapper.queryPage(query.toPage(), query);
@ -46,19 +51,28 @@ public class FaultRepairServiceImpl extends ServiceImpl<FaultRepairMapper, Fault
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean add(FaultRepairDTO faultRepairDTO) {
return save(faultRepairDTO.toFaultRepair());
FaultRepair faultRepair = faultRepairDTO.toFaultRepair();
faultRepair.setReportUserId(LoginHelper.getUserId());
save(faultRepair);
return ossStorageService.updateByBusinessId(faultRepair.getId(), faultRepairDTO.getFileIds());
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean edit(FaultRepairDTO faultRepairDTO) {
return updateById(faultRepairDTO.toFaultRepair());
FaultRepair faultRepair = faultRepairDTO.toFaultRepair();
updateById(faultRepair);
return ossStorageService.updateByBusinessId(faultRepair.getId(), faultRepairDTO.getFileIds());
}
@Override
public boolean assign(FaultRepairAllocateDTO dto) {
return update(new LambdaUpdateWrapper<FaultRepair>()
.eq(FaultRepair::getId, dto.getId())
.set(FaultRepair::getStatus, RepairStatusEnum.PROCESS.getValue())
.set(FaultRepair::getAssignToUserId, dto.getAssignToUserId()));
}

View File

@ -26,6 +26,7 @@ import org.zxwl.sweeper.constant.MqttTopicConst;
import org.zxwl.sweeper.constant.RedisKeyConst;
import org.zxwl.sweeper.entity.RouteInfo;
import org.zxwl.sweeper.entity.TaskInfo;
import org.zxwl.sweeper.enums.EnableEnum;
import org.zxwl.sweeper.enums.TaskStatusEnum;
import org.zxwl.sweeper.mapper.RouteInfoMapper;
import org.zxwl.sweeper.mapper.TaskInfoMapper;
@ -284,7 +285,7 @@ public class RouteInfoServiceImpl extends ServiceImpl<RouteInfoMapper, RouteInfo
// 判断路径信息是否存在已启用
LambdaQueryWrapper<RouteInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.in(RouteInfo::getId, ids);
wrapper.eq(RouteInfo::getStatus, 1);
wrapper.eq(RouteInfo::getStatus, EnableEnum.ENABLE.getValue());
if (exists(wrapper)) {
throw new BusinessException(SystemErrorCode.ROUTE_STATUS_EXIST);
}
@ -295,7 +296,7 @@ public class RouteInfoServiceImpl extends ServiceImpl<RouteInfoMapper, RouteInfo
public boolean enable(Long id) {
LambdaUpdateWrapper<RouteInfo> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(Objects.nonNull(id), RouteInfo::getId, id);
updateWrapper.set(RouteInfo::getStatus, 1);
updateWrapper.set(RouteInfo::getStatus, EnableEnum.ENABLE.getValue());
return routeInfoMapper.update(updateWrapper) > 0;
}

View File

@ -15,10 +15,11 @@ import org.zxwl.common.json.utils.JacksonUtil;
import org.zxwl.common.mqtt.handler.MqttMessageSender;
import org.zxwl.common.satoken.utils.LoginHelper;
import org.zxwl.common.utils.RedisUtil;
import org.zxwl.sweeper.constant.RedisKeyConst;
import org.zxwl.sweeper.constant.MqttTopicConst;
import org.zxwl.sweeper.constant.RedisKeyConst;
import org.zxwl.sweeper.entity.RouteInfo;
import org.zxwl.sweeper.entity.TaskInfo;
import org.zxwl.sweeper.entity.TaskRecord;
import org.zxwl.sweeper.entity.VehicleInfo;
import org.zxwl.sweeper.enums.TaskStatusEnum;
import org.zxwl.sweeper.mapper.TaskInfoMapper;
@ -36,6 +37,7 @@ import org.zxwl.sweeper.service.TaskInfoService;
import org.zxwl.sweeper.service.TaskRecordService;
import org.zxwl.sweeper.service.VehicleInfoService;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@ -152,13 +154,22 @@ public class TaskInfoServiceImpl extends ServiceImpl<TaskInfoMapper, TaskInfo> i
@Override
public boolean start(Long id) {
// 获取任务详情
TaskInfo taskInfo = taskInfoMapper.selectById(id);
if (taskInfo == null) {
throw new BusinessException(SystemErrorCode.TASK_NOT_EXIST);
}
// 获取路径详情
RouteInfo routeInfo = routeInfoService.getById(taskInfo.getRouteId());
// 判断是否存在未完成调度,避免同一车辆被分配多个任务
boolean result = taskInfoMapper.exists(new LambdaQueryWrapper<TaskInfo>()
.eq(TaskInfo::getVehicleId, taskInfo.getVehicleId())
.eq(TaskInfo::getStatus, TaskStatusEnum.EXECUTING.getValue()));
if (result) {
throw new BusinessException(SystemErrorCode.TASK_EXECUTING);
}
TaskPushInfo taskPushInfo = new TaskPushInfo(taskInfo, new RoutePushInfo(routeInfo));
String vid = getVidByVehicleId(taskInfo.getVehicleId());
@ -208,14 +219,39 @@ public class TaskInfoServiceImpl extends ServiceImpl<TaskInfoMapper, TaskInfo> i
ResponseMessage responseMessage = JacksonUtil.parseObject((String) o, ResponseMessage.class);
if (responseMessage != null && responseMessage.getCode().equals(200)) {
taskRecordService.updateRecordCompleted(taskInfo.getId(), taskInfo.getVehicleId());
updateTaskStatus(taskInfo.getId(), TaskStatusEnum.COMPLETED.getValue());
updateTaskStatus(taskInfo.getId(), TaskStatusEnum.UN_EXECUTED.getValue());
return true;
}
}
return false;
}
/**
* 车端任务状态上报更新
*
* @param id 任务id
* @param status 任务状态
*/
@Override
public void updateStatus(Long id, Integer status) {
// 判断车端上报的任务状态是否已完成或执行异常是则同步更新
if (TaskStatusEnum.COMPLETED.getValue().equals(status) || TaskStatusEnum.EXCEPTION.getValue().equals(status)) {
LambdaUpdateWrapper<TaskInfo> task = new LambdaUpdateWrapper<>();
task.set(TaskInfo::getStatus, TaskStatusEnum.UN_EXECUTED.getValue());
task.eq(TaskInfo::getId, id);
task.eq(TaskInfo::getStatus, TaskStatusEnum.EXECUTING.getValue());
taskInfoMapper.update(task);
LambdaUpdateWrapper<TaskRecord> record = new LambdaUpdateWrapper<>();
record.set(TaskRecord::getStatus, status);
record.set(TaskRecord::getEndTime, LocalDateTime.now());
record.eq(TaskRecord::getTaskId, id);
record.eq(TaskRecord::getStatus, TaskStatusEnum.EXECUTING.getValue());
record.ne(TaskRecord::getStatus, status);
taskRecordService.update(record);
}
}
private boolean updateTaskStatus(Long taskId, int status) {
LambdaUpdateWrapper<TaskInfo> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(TaskInfo::getStatus, status);

View File

@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.zxwl.common.core.exception.BusinessException;
import org.zxwl.common.core.exception.SystemErrorCode;
import org.zxwl.sweeper.entity.TaskRecord;
import org.zxwl.sweeper.enums.TaskStatusEnum;
import org.zxwl.sweeper.mapper.TaskRecordMapper;
@ -78,7 +80,14 @@ public class TaskRecordServiceImpl extends ServiceImpl<TaskRecordMapper, TaskRec
@Override
public boolean delete(Set<Long> ids) {
return taskRecordMapper.deleteByIds(ids) > 0;
// 检查是否存在未完成调度的任务
boolean result = taskRecordMapper.exists(new LambdaUpdateWrapper<TaskRecord>()
.in(TaskRecord::getId, ids)
.eq(TaskRecord::getStatus, TaskStatusEnum.EXECUTING.getValue()));
if (result) {
throw new BusinessException(SystemErrorCode.DELETE_FAILURE_EXIST_UNDO_RECORD);
}
return removeByIds(ids);
}
@Override

View File

@ -1,28 +1,105 @@
package org.zxwl.sweeper.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.zxwl.common.core.utils.EnvUtil;
import org.zxwl.common.utils.RedisUtil;
import org.zxwl.sweeper.constant.RedisKeyConst;
import org.zxwl.sweeper.mapper.VehicleInfoMapper;
import org.zxwl.sweeper.model.taskInfo.app.TaskInfoAPPVO;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleDetail;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleSimpleInfoVO;
import org.zxwl.sweeper.model.vehicleInfo.app.*;
import org.zxwl.sweeper.service.TaskInfoService;
import org.zxwl.sweeper.service.VehicleAppInfoService;
import org.zxwl.sweeper.service.VehicleInfoService;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@Service
@RequiredArgsConstructor
public class VehicleAppInfoServiceImpl implements VehicleAppInfoService {
private final VehicleInfoMapper vehicleInfoMapper;
private final VehicleInfoService vehicleInfoService;
private final TaskInfoService taskInfoService;
@Override
public Page<VehicleVO> pageList(VehicleQuery query) {
// 根据查询状态查询对应车辆实际运行状态如故障剩余电量和充电状态等
// 从Redis字符串或哈希缓存中获取所有的车辆vid集合关联sql和封装分页返回
Set<String> faultAll = RedisUtil.getSuffixesByPrefix(RedisKeyConst.VEHICLE_FAULT); // 车辆故障状态
Set<String> charge = RedisUtil.getKeySuffixesByHashField( // 车辆实时状态
RedisKeyConst.VEHICLE_ONLINE,
"chargeStatus",
"true"::equalsIgnoreCase //支持多种匹配模式(如值为true(布尔)值为某个数字(如1,100)值满足某种条件(>0))
);
// 根据 status 过滤 vids
Set<String> vids = new HashSet<>();
Integer status = query.getStatus();
if (status != null) {
switch (status) {
case 2: // 故障
vids.addAll(faultAll);
break;
case 3: // 充电
vids.addAll(charge);
break;
default:
break;
}
if ((status == 2 || status == 3) && CollUtil.isEmpty(vids)) {
return new Page<>(query.getPageNum(), query.getPageSize());
}
}
// 查询数据库分页
Page<VehicleVO> page = vehicleInfoMapper.queryPage(query.toPage(), query.getKey(), status, vids);
for (VehicleVO infoVO : page.getRecords()) {
if (CharSequenceUtil.isNotEmpty(infoVO.getPicture())) {
infoVO.setPicture(EnvUtil.getProperty("minio.pathPrefix") + infoVO.getPicture());
}
// 在线状态
if (RedisUtil.exist(RedisKeyConst.VEHICLE_ONLINE + infoVO.getVid())) {
infoVO.setStatus(1);
}
// 故障状态
if (RedisUtil.exist(RedisKeyConst.VEHICLE_FAULT + infoVO.getVid())) {
infoVO.setFaultStatus(1);
}
// 剩余电量
Optional<Object> power = RedisUtil.getValue(RedisKeyConst.VEHICLE_POWER + infoVO.getVid());
if (power.isPresent()) {
infoVO.setPower((double) power.orElse(0d));
}
// 充电状态
infoVO.setChargeStatus(charge.contains(infoVO.getVid()));
}
return page;
}
@Override
public VehicleDetail getVehicleDetail(Long vehicleId) {
VehicleDetail vehicleDetail = new VehicleDetail();
VehicleSimpleInfoVO vehicleSimpleInfo = vehicleInfoService.getVehicleSimpleInfo(vehicleId);
vehicleDetail.setVehicleSimpleInfoVO(vehicleSimpleInfo);
TaskInfoAPPVO taskInfoAPPVO = taskInfoService.currentTaskInfo(vehicleId);
vehicleDetail.setTaskInfoVO(taskInfoAPPVO);
// 车辆信息
VehicleSimpleInfoVO vehicleInfo = vehicleInfoService.getVehicleSimpleInfo(vehicleId);
// 任务信息
TaskInfoAPPVO taskInfo = taskInfoService.currentTaskInfo(vehicleId);
// 实时状态
if (vehicleInfo != null) {
Map<Object, Object> map = RedisUtil.getAllHashValue(RedisKeyConst.VEHICLE_ONLINE + vehicleInfo.getVid());
VehicleOperatingStatusVO operatingStatusVO = BeanUtil.toBean(map, VehicleOperatingStatusVO.class);
vehicleDetail.setVehicleOperatingStatusVO(operatingStatusVO);
}
vehicleDetail.setVehicleSimpleInfoVO(vehicleInfo);
vehicleDetail.setTaskInfoVO(taskInfo);
return vehicleDetail;
}
}

View File

@ -26,7 +26,7 @@ import org.zxwl.sweeper.mapper.DispatchRecordMapper;
import org.zxwl.sweeper.mapper.RouteInfoMapper;
import org.zxwl.sweeper.mapper.TaskInfoMapper;
import org.zxwl.sweeper.mapper.VehicleInfoMapper;
import org.zxwl.sweeper.model.VehicleInfoAPPVO;
import org.zxwl.sweeper.model.vehicleInfo.app.VehicleInfoAPPVO;
import org.zxwl.sweeper.model.app.vehicleCard.VehicleCard;
import org.zxwl.sweeper.model.cache.DeviceStatusCache;
import org.zxwl.sweeper.model.vehicleInfo.*;
@ -237,6 +237,14 @@ public class VehicleInfoServiceImpl extends ServiceImpl<VehicleInfoMapper, Vehic
return update(updateWrapper);
}
@Override
public boolean unbindCockpit(Long id) {
LambdaUpdateWrapper<VehicleInfo> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(VehicleInfo::getCid, null);
updateWrapper.eq(VehicleInfo::getId, id);
return update(updateWrapper);
}
@Override
public boolean hasGateway(String vid) {
VehicleInfo vehicleInfo = getOne(Wrappers.lambdaQuery(VehicleInfo.class).eq(VehicleInfo::getVid, vid));
@ -284,9 +292,9 @@ public class VehicleInfoServiceImpl extends ServiceImpl<VehicleInfoMapper, Vehic
long count = vehicleInfoMapper.selectCount(Wrappers.query(VehicleInfo.class).lambda()
.eq(VehicleInfo::getEnableStatus, EnableEnum.ENABLE.getValue()));
long onlineCount = RedisUtil.countKeysByPrefix(RedisKeyConst.VEHICLE_STATUS);
long onlineCount = RedisUtil.countKeysByPrefix(RedisKeyConst.VEHICLE_ONLINE);
long faultCount = RedisUtil.countKeysByPrefix(RedisKeyConst.VEHICLE_FAULT_STATUS);
long faultCount = RedisUtil.countKeysByPrefix(RedisKeyConst.VEHICLE_FAULT);
VehicleStatisticsVo statisticsVo = new VehicleStatisticsVo();
statisticsVo.setCount(count);

View File

@ -7,16 +7,12 @@
a.id,
a.title,
a.description,
a.report_user_id,
d.real_name reportName,
d.phone reportPhone,
a.priority,
b.dict_label priorityCn,
a.status,
c.dict_label statusCn,
a.assign_to_user_id,
e.real_name assignName,
e.phone assignPhone,
a.repair_result,
a.remark,
a.created,
@ -27,8 +23,14 @@
left join sys_user_info d on d.id = a.report_user_id
left join sys_user_info e on e.id = a.assign_to_user_id
where a.deleted = 0
<if test="query.title != null and query.title != ''">
AND a.title LIKE CONCAT('%', #{query.title}, '%')
<if test="query.key != null and query.key != ''">
AND a.title LIKE CONCAT('%', #{query.key}, '%')
</if>
<if test="query.reportUserId != null">
AND a.report_user_id = #{query.reportUserId}
</if>
<if test="query.assignToUserId != null">
AND a.assign_to_user_id = #{query.assignToUserId}
</if>
<if test="query.status != null">
and a.title = #{query.status}

View File

@ -26,4 +26,41 @@
id, vid, name, picture, status, enable_status, cid, plate_number, has_gateway, model, manufacture_date, organize_id, created, last, deleted
</sql>
<select id="queryPage" resultType="org.zxwl.sweeper.model.vehicleInfo.app.VehicleVO">
SELECT
s1.id,
s1.vid,
s1.name,
s1.picture,
s1.plate_number,
s1.enable_status,
IF(s2.count > 0, 1, 0) taskStatus
FROM info_vehicle_info s1
LEFT JOIN (
SELECT vehicle_id, count(*) count
FROM info_task_info
WHERE deleted = 0 AND status = 1
GROUP BY vehicle_id
) s2 ON s1.id = s2.vehicle_id
WHERE s1.deleted = 0 AND s1.enable_status = 1
<if test="key != null and key != ''">
AND (s1.vid LIKE CONCAT('%', #{key}, '%') OR s1.cid LIKE CONCAT('%', #{key}, '%'))
</if>
<if test="status != null">
<if test="status == 0">
AND s2.count > 0
</if>
<if test="status == 1">
AND (s2.count IS NULL OR s2.count = 0)
</if>
</if>
<if test="vids != null and vids.size() > 0">
AND s1.vid IN
<foreach item="item" index="index" collection="vids" open="(" separator="," close=")">
#{item}
</foreach>
</if>
ORDER BY s1.created DESC
</select>
</mapper>

View File

@ -3,6 +3,7 @@ package org.zxwl.system.controller;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
@ -45,6 +46,17 @@ public class OssController extends BaseController {
return Result.success(ossService.queryPageList(query));
}
/**
* 根据业务id获取附件集合
*
* @param businessId 业务主键id
*/
@GetMapping("/listByBusinessId/{businessId}")
public Result<List<OssInfoVO>> listByBusinessId(@PathVariable Long businessId) {
List<OssInfoVO> list = ossService.listByBusinessId(businessId);
return Result.success(list);
}
/**
* 上传OSS对象存储
*
@ -87,7 +99,7 @@ public class OssController extends BaseController {
@DeleteMapping("{ids}")
//@SaCheckPermission("sys:oss:delete")
@Log(module = ModuleType.SYSTEM, operateType = OperateType.DELETE, operateExplain = "OSS对象存储删除")
public Result<Void> delete(@PathVariable("ids") List<Long> ids) {
public Result<Void> delete(@NotEmpty(message = "主键不能为空") @PathVariable("ids") List<Long> ids) {
return toResult(ossService.removeByIds(ValidatorUtil.checkIds(ids)));
}
}

View File

@ -6,6 +6,8 @@ import org.zxwl.system.entity.OssInfo;
import org.zxwl.system.model.oss.OssInfoQuery;
import org.zxwl.system.model.oss.OssInfoVO;
import java.util.List;
/**
* <p>
* 接口
@ -17,4 +19,6 @@ import org.zxwl.system.model.oss.OssInfoVO;
public interface OssService extends IService<OssInfo> {
Page<OssInfoVO> queryPageList(OssInfoQuery query); //分页
List<OssInfoVO> listByBusinessId(Long businessId);
}

View File

@ -13,7 +13,7 @@ import org.zxwl.common.core.domain.dto.DictTypeInfoDTO;
import org.zxwl.common.core.exception.BusinessException;
import org.zxwl.common.core.exception.SystemErrorCode;
import org.zxwl.common.core.service.DictService;
import org.zxwl.common.core.utils.StreamUtils;
import org.zxwl.common.core.utils.StreamUtil;
import org.zxwl.system.entity.DictType;
import org.zxwl.system.enums.EnableEnum;
import org.zxwl.system.mapper.DictTypeMapper;
@ -130,7 +130,7 @@ public class DictTypeServiceImpl extends ServiceImpl<DictTypeMapper, DictType> i
@Override
public String getDictLabel(String dictCode, String dictValue, String separator) {
List<DictItemSimpleVO> datas = listByDictCode(dictCode);
Map<String, String> map = StreamUtils.toMap(datas, DictItemSimpleVO::getDictValue, DictItemSimpleVO::getDictLabel);
Map<String, String> map = StreamUtil.toMap(datas, DictItemSimpleVO::getDictValue, DictItemSimpleVO::getDictLabel);
if (StringUtils.containsAny(dictValue, separator)) {
return Arrays.stream(dictValue.split(separator))
.map(v -> map.getOrDefault(v, StringUtils.EMPTY))
@ -151,7 +151,7 @@ public class DictTypeServiceImpl extends ServiceImpl<DictTypeMapper, DictType> i
@Override
public String getDictValue(String dictCode, String dictLabel, String separator) {
List<DictItemSimpleVO> datas = listByDictCode(dictCode);
Map<String, String> map = StreamUtils.toMap(datas, DictItemSimpleVO::getDictLabel, DictItemSimpleVO::getDictValue);
Map<String, String> map = StreamUtil.toMap(datas, DictItemSimpleVO::getDictLabel, DictItemSimpleVO::getDictValue);
if (StringUtils.containsAny(dictLabel, separator)) {
return Arrays.stream(dictLabel.split(separator))
.map(l -> map.getOrDefault(l, StringUtils.EMPTY))

View File

@ -1,10 +1,13 @@
package org.zxwl.system.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.zxwl.common.core.service.OssStorageService;
import org.zxwl.system.entity.OssInfo;
import org.zxwl.system.mapper.OssMapper;
import org.zxwl.system.model.oss.OssInfoQuery;
@ -23,7 +26,7 @@ import java.util.List;
*/
@Service
@RequiredArgsConstructor
public class OssServiceImpl extends ServiceImpl<OssMapper, OssInfo> implements OssService {
public class OssServiceImpl extends ServiceImpl<OssMapper, OssInfo> implements OssService, OssStorageService {
private final OssMapper ossMapper;
@ -33,4 +36,18 @@ public class OssServiceImpl extends ServiceImpl<OssMapper, OssInfo> implements O
List<OssInfoVO> list = page.getRecords().stream().map(OssInfoVO::new).toList();
return new Page<OssInfoVO>(page.getCurrent(), page.getSize(), page.getTotal()).setRecords(list);
}
@Override
public List<OssInfoVO> listByBusinessId(Long businessId) {
List<OssInfo> list = ossMapper.selectList(new LambdaQueryWrapper<OssInfo>().eq(OssInfo::getBusinessId, businessId));
return list.stream().map(OssInfoVO::new).toList();
}
@Override
public boolean updateByBusinessId(Long businessId, List<Long> ids) {
LambdaUpdateWrapper<OssInfo> updateWrapper = Wrappers.lambdaUpdate();
updateWrapper.set(OssInfo::getBusinessId, businessId);
updateWrapper.in(OssInfo::getId, ids);
return update(updateWrapper);
}
}

View File

@ -10,7 +10,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.zxwl.common.core.exception.BusinessException;
import org.zxwl.common.core.exception.SystemErrorCode;
import org.zxwl.common.core.utils.StreamUtils;
import org.zxwl.common.core.utils.StreamUtil;
import org.zxwl.common.satoken.utils.SecureUtil;
import org.zxwl.system.entity.RoleInfo;
import org.zxwl.system.entity.UserInfo;
@ -90,7 +90,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
// 删除旧数据
userRoleMapper.delete(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getUserId, userId));
// 插入新数据
List<UserRole> list = StreamUtils.toList(roleIds, roleId -> {
List<UserRole> list = StreamUtil.toList(roleIds, roleId -> {
UserRole ur = new UserRole();
ur.setUserId(userId);
ur.setRoleId(roleId);