[add] 接入萤石摄像头,新增子项目和摄像头预置位相关逻辑 [update] 修改geojson中方阵等重新上传逻辑

This commit is contained in:
lcj
2025-06-13 18:28:31 +08:00
parent fbea1c2c2a
commit 784c7c0783
63 changed files with 3072 additions and 341 deletions

View File

@ -98,13 +98,13 @@ spring:
spring.data:
redis:
# 地址
host: 192.168.110.126
host: 192.168.110.2
# 端口默认为6379
port: 6379
port: 9287
# 数据库索引
database: 1
database: 10
# redis 密码必须配置
password: 123456
password: syar23rdsaagdrsa
# 连接超时时间
timeout: 10s
# 是否开启ssl
@ -272,3 +272,6 @@ weather:
# dxf转 geojson 执行文件名
dxf2GeoJson:
file-name: main.exe
ys7:
app-key: "f01490bd5d5241b7809d8fc5fe84f7f8"
app-secret: "d468f270699de855fd85fe7fd6f9595f"

View File

@ -103,9 +103,9 @@ spring.data:
# 地址
host: 192.168.110.2
# 端口默认为6379
port: 6379
port: 63079
# 数据库索引
database: 1
database: 5
# redis 密码必须配置
password: HMASKEbyhaASPZXB
# 连接超时时间
@ -274,3 +274,6 @@ weather:
# dxf转 geojson 执行文件名
dxf2GeoJson:
file-name: main
ys7:
app-key: "f01490bd5d5241b7809d8fc5fe84f7f8"
app-secret: "d468f270699de855fd85fe7fd6f9595f"

View File

@ -228,9 +228,11 @@ springdoc:
packages-to-scan: org.dromara.facility
- group: 9.进度模块
packages-to-scan: org.dromara.progress
- group: 10.代码生成模块
- group: 10.其他模块
packages-to-scan: org.dromara.other
- group: 11.代码生成模块
packages-to-scan: org.dromara.generator
- group: 11.工作流模块
- group: 12.工作流模块
packages-to-scan: org.dromara.workflow
# 防止XSS攻击

View File

@ -0,0 +1,29 @@
package org.dromara.test;
import jakarta.annotation.Resource;
import org.dromara.manager.ys7manager.Ys7Manager;
import org.dromara.manager.ys7manager.Ys7RequestUtils;
import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
/**
* @author lcj
* @date 2025/6/12 17:06
*/
@SpringBootTest
public class Ys7Test {
@Resource
private Ys7Manager ys7Manager;
@Test
void test() {
String token = ys7Manager.getToken();
List<Ys7QueryDeviceResponseVo> ys7QueryDeviceResponseVos = Ys7RequestUtils.queryDeviceVoList(token, 1, 20);
System.out.println(ys7QueryDeviceResponseVos);
}
}

View File

@ -1,5 +1,6 @@
package org.dromara.common.web.handler;
import cn.hutool.core.text.AntPathMatcher;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus;
import jakarta.servlet.ServletException;
@ -14,6 +15,7 @@ import org.dromara.common.core.exception.base.BaseException;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
@ -40,7 +42,7 @@ public class GlobalExceptionHandler {
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public R<Void> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
HttpServletRequest request) {
HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
return R.fail(HttpStatus.HTTP_BAD_METHOD, e.getMessage());
@ -106,6 +108,18 @@ public class GlobalExceptionHandler {
return R.fail(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), e.getValue()));
}
@ExceptionHandler(HttpMessageNotReadableException.class)
public R<Void> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpServletRequest request) {
String path = request.getRequestURI();
AntPathMatcher matcher = new AntPathMatcher();
String pattern = "/facility/**/geoJson";
log.error("请求:{},参数格式错误:{}", path, ex.getMessage());
if (matcher.match(pattern, path)) {
return R.fail(HttpStatus.HTTP_BAD_REQUEST, "图层解析错误,请选择正确的设施或名称图层");
}
return R.fail(HttpStatus.HTTP_BAD_REQUEST, "请求参数格式错误:" + ex.getMessage());
}
/**
* 找不到路由
*/

View File

@ -1,15 +1,33 @@
package org.dromara.facility.constant;
import java.util.List;
/**
* @author lcj
* @date 2025/5/27 18:27
*/
public interface FacRedisKeyConstant {
String FAC_REDIS_PREFIX = "fac:";
/**
* 设施模块 Redis 缓存前缀
*/
String FAC_REDIS_PREFIX = "fac:facility:";
/**
* 设施模块正在操作任务 Redis 缓存前缀
*/
String FAC_IN_OPERATION_REDIS_KEY_PREFIX = FAC_REDIS_PREFIX + "inOperation:";
/**
* 设施模块类型 - 坐标
*/
String GEO_TYPE_LOCAL = "location";
/**
* 设施模块类型 - 名称
*/
String GEO_TYPE_NAME = "name";
/**
* 批量上传桩点、支架、立柱 Redis 缓存 key
*
@ -18,17 +36,62 @@ public interface FacRedisKeyConstant {
* @return Redis 缓存 key
*/
static String getBatchUploadPartsRedisKey(String sessionId, int batchNum) {
return String.format("%s%s:%s:%s", FAC_REDIS_PREFIX, "panel:parts", sessionId, batchNum);
return String.format("%s%s:%s:%s", FAC_REDIS_PREFIX, "parts", sessionId, batchNum);
}
/**
* 当前项目是否正在操作 Redis 缓存 key
* 批量上传光伏板 Redis 缓存 key
*
* @param sessionId 唯一标识
* @param batchNum 第几批数据
* @param type 类型
* @return Redis 缓存 key
*/
static String getBatchUploadPanelRedisKey(String sessionId, int batchNum, String type) {
return String.format("%s%s:%s:%s:%s", FAC_REDIS_PREFIX, "panel", sessionId, batchNum, type);
}
/**
* 项目内进行中的任务 Redis 缓存 key 前缀
*
* @param projectId 项目 ID
* @return Redis 缓存前缀
*/
static String getInOperationByProjectRedisPrefix(Long projectId) {
return String.format("%s%s:%s:", FAC_IN_OPERATION_REDIS_KEY_PREFIX, "project", projectId);
}
/**
* 当前项目下是否正在操作桩点、支架、立柱 Redis 缓存 key
*
* @param projectId 项目 ID
* @return Redis 缓存 key
*/
static String getInOperationByProjectRedisKey(Long projectId) {
return String.format("%s%s:%s", FAC_IN_OPERATION_REDIS_KEY_PREFIX, "project", projectId);
static String getPartsInOperationByProjectRedisKey(Long projectId) {
return String.format("%s%s", getInOperationByProjectRedisPrefix(projectId), "parts");
}
/**
* 当前项目下是否正在操作光伏板 Redis 缓存 key
*
* @param projectId 项目 ID
* @return Redis 缓存 key
*/
static String getPanelInOperationByProjectRedisKey(Long projectId) {
return String.format("%s%s", getInOperationByProjectRedisPrefix(projectId), "panel");
}
/**
* 获取操作的 Redis 缓存 key 列表
*
* @param projectId 项目 ID
* @return Redis 缓存 key 列表
*/
static List<String> getInOperationRedisKeyList(Long projectId) {
return List.of(
getPartsInOperationByProjectRedisKey(projectId),
getPanelInOperationByProjectRedisKey(projectId)
);
}
}

View File

@ -1,22 +0,0 @@
package org.dromara.facility.domain.dto.geojson;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author lcj
* @date 2025/4/24 10:40
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FacFeatureByLine {
private String type;
private FacGeometryByLine geometry;
private FacProperties properties;
}

View File

@ -4,6 +4,9 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/4/24 10:32
@ -11,7 +14,10 @@ import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FacFeatureByPlane {
public class FacFeatureByPlane implements Serializable {
@Serial
private static final long serialVersionUID = 6732054357362738399L;
private String type;

View File

@ -1,25 +0,0 @@
package org.dromara.facility.domain.dto.geojson;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* @author lcj
* @date 2025/4/24 10:38
*/
@Data
public class FacGeoJsonByLine implements Serializable {
@Serial
private static final long serialVersionUID = -1019429627483913266L;
private String name;
private String type;
private List<FacFeatureByLine> features;
}

View File

@ -1,24 +0,0 @@
package org.dromara.facility.domain.dto.geojson;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author lcj
* @date 2025/4/24 10:41
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FacGeometryByLine {
private String type;
private List<List<Double>> coordinates;
private Long id;
}

View File

@ -4,6 +4,8 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
@ -13,7 +15,10 @@ import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FacGeometryByPlane {
public class FacGeometryByPlane implements Serializable {
@Serial
private static final long serialVersionUID = -82255764789167107L;
private String type;

View File

@ -33,4 +33,19 @@ public class FacPhotovoltaicPanelCreateByGeoJsonReq implements Serializable {
*/
private List<FacGeoJsonByPoint> nameGeoJson;
/**
* 批次上传标识
*/
private String sessionId;
/**
* 当前批次
*/
private int batchNum;
/**
* 总批次
*/
private int totalBatch;
}

View File

@ -0,0 +1,28 @@
package org.dromara.facility.domain.vo.matrix;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/10 15:09
*/
@Data
public class FacMatrixBySubProjectVo implements Serializable {
@Serial
private static final long serialVersionUID = -3427826315362519128L;
/**
* 主键
*/
private Long matrixId;
/**
* 方阵名称
*/
private String name;
}

View File

@ -146,12 +146,14 @@ public class FacBoxTransformerServiceImpl extends ServiceImpl<FacBoxTransformerM
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByGeoJson(FacBoxTransformerCreateByGeoJsonReq geoJson) {
Long projectId = geoJson.getProjectId();
// Long projectId = geoJson.getProjectId();
Long projectId = 1930896467736707073L;
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
// 获取当前项目下方阵信息
List<FacMatrix> matrixList = matrixService.lambdaQuery()
.select(FacMatrix::getId, FacMatrix::getPositions)
.eq(FacMatrix::getProjectId, projectId).list();
if (CollUtil.isEmpty(matrixList)) {
throw new ServiceException("项目下无方阵数据,请先创建方阵信息后再添加箱变信息", HttpStatus.NOT_FOUND);

View File

@ -146,12 +146,14 @@ public class FacInverterServiceImpl extends ServiceImpl<FacInverterMapper, FacIn
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByGeoJson(FacInverterCreateByGeoJsonReq geoJson) {
Long projectId = geoJson.getProjectId();
// Long projectId = geoJson.getProjectId();
Long projectId = 1930896467736707073L;
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
// 获取当前项目下方阵信息
List<FacMatrix> matrixList = matrixService.lambdaQuery()
.select(FacMatrix::getId, FacMatrix::getPositions)
.eq(FacMatrix::getProjectId, projectId).list();
if (CollUtil.isEmpty(matrixList)) {
throw new ServiceException("项目下无方阵数据,请先创建方阵信息后再添加逆变器信息", HttpStatus.NOT_FOUND);

View File

@ -35,6 +35,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
/**
* 设施-方阵Service业务层处理
@ -257,19 +258,21 @@ public class FacMatrixServiceImpl extends ServiceImpl<FacMatrixMapper, FacMatrix
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByGeoJson(FacMatrixCreateByGeoJsonReq geoJson) {
// 判断当前项目是否正在执行桩点、立柱、支架数据
String operationRedisKey = FacRedisKeyConstant.getInOperationByProjectRedisKey(geoJson.getProjectId());
// Long projectId = geoJson.getProjectId();
Long projectId = 1930896467736707073L;
// 判断 redis key 是否存在,存在则返回
Object object = redisTemplate.opsForValue().get(operationRedisKey);
if (object != null && (Boolean) object) {
throw new ServiceException("项目下桩点、立柱、支架数据正在处理中,请等待处理完毕后操作", HttpStatus.BAD_REQUEST);
List<String> operationRedisKey = FacRedisKeyConstant.getInOperationRedisKeyList(projectId);
List<Object> list = redisTemplate.opsForValue().multiGet(operationRedisKey);
boolean hasValue = list != null && list.stream().anyMatch(Objects::nonNull);
if (hasValue) {
throw new ServiceException("项目下有设施数据正在处理中,请等待处理完毕后再操作", HttpStatus.BAD_REQUEST);
}
Long projectId = geoJson.getProjectId();
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
// 获取当前项目下方阵信息
List<FacMatrix> oldMatrixList = this.lambdaQuery()
.select(FacMatrix::getId)
.eq(FacMatrix::getProjectId, projectId).list();
List<FacMatrix> matrixList = new ArrayList<>();
List<FacGeoJson> locationGeoJsonList = geoJson.getLocationGeoJson();
@ -303,33 +306,23 @@ public class FacMatrixServiceImpl extends ServiceImpl<FacMatrixMapper, FacMatrix
matrixList.add(matrix);
}
// todo 关联数据处理
if (CollUtil.isNotEmpty(oldMatrixList)) {
boolean result = this.removeBatchByIds(oldMatrixList);
if (!result) {
throw new ServiceException("删除老方阵失败,数据库异常", HttpStatus.ERROR);
}
LambdaQueryWrapper<PgsProgressCategory> lqw = new LambdaQueryWrapper<>();
lqw.eq(PgsProgressCategory::getProjectId, projectId)
.in(PgsProgressCategory::getMatrixId, oldMatrixList.stream().map(FacMatrix::getId).toList());
List<PgsProgressCategory> progressCategories = progressCategoryService.list(lqw);
if (CollUtil.isNotEmpty(progressCategories)) {
boolean remove = progressCategoryService.remove(lqw);
if (!remove) {
throw new ServiceException("删除老方阵进度分类失败,数据库异常", HttpStatus.ERROR);
}
}
}
if (CollUtil.isNotEmpty(matrixList)) {
boolean result = this.saveBatch(matrixList);
if (!result) {
throw new ServiceException("批量新增方阵失败,数据库异常", HttpStatus.ERROR);
}
List<Long> matrixIdList = matrixList.stream().map(FacMatrix::getId).toList();
Boolean save = progressCategoryService.insertByTemplate(projectId, matrixIdList);
Boolean save = progressCategoryService.insertByTemplate(projectId, matrixList,oldMatrixList);
if (!save) {
throw new ServiceException("批量新增方阵进度分类失败,数据库异常", HttpStatus.ERROR);
}
}
if (CollUtil.isNotEmpty(oldMatrixList)) {
List<Long> oldMatrixIds = oldMatrixList.stream().map(FacMatrix::getId).toList();
boolean result = this.removeBatchByIds(oldMatrixIds);
if (!result) {
throw new ServiceException("删除老方阵失败,数据库异常", HttpStatus.ERROR);
}
}
return true;
}

View File

@ -77,8 +77,8 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
@Resource
private ScheduledExecutorService scheduledExecutorService;
@Resource
@Lazy
@Resource
private FacPhotovoltaicPanelPartsServiceImpl self; // 注入自己
/**
@ -89,24 +89,25 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
*/
@Override
public Boolean insertPartsByGeoJson(FacPhotovoltaicPanelPartsCreateByGeoJsonReq geoJson) {
// 设置 redis 防止多次操作
String operationRedisKey = FacRedisKeyConstant.getInOperationByProjectRedisKey(geoJson.getProjectId());
// Long projectId = geoJson.getProjectId();
Long projectId = 1930896467736707073L;
// 判断 redis key 是否存在,存在则返回
Object object = redisTemplate.opsForValue().get(operationRedisKey);
if (object != null && (Boolean) object) {
throw new ServiceException("项目下桩点、立柱、支架数据正在处理中,请勿重复操作", HttpStatus.BAD_REQUEST);
List<String> operationRedisKey = FacRedisKeyConstant.getInOperationRedisKeyList(projectId);
List<Object> list = redisTemplate.opsForValue().multiGet(operationRedisKey);
boolean hasValue = list != null && list.stream().anyMatch(Objects::nonNull);
if (hasValue) {
throw new ServiceException("项目下有设施数据正在处理中,请等待处理完毕后再操作", HttpStatus.BAD_REQUEST);
}
// 第一次接收请求,进行数据校验
int batchNum = geoJson.getBatchNum();
if (batchNum == 1) {
Long projectId = geoJson.getProjectId();
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
// 查询项目下光伏板
List<FacPhotovoltaicPanel> photovoltaicPanelList = photovoltaicPanelService.lambdaQuery()
.eq(FacPhotovoltaicPanel::getProjectId, projectId).list();
if (CollUtil.isEmpty(photovoltaicPanelList)) {
Long count = photovoltaicPanelService.lambdaQuery()
.eq(FacPhotovoltaicPanel::getProjectId, projectId).count();
if (count <= 0) {
throw new ServiceException("项目下无光伏板信息,请先创建光伏板信息后再添加桩点、立柱、支架信息", HttpStatus.NOT_FOUND);
}
}
@ -126,19 +127,22 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
List<FacFeatureByPoint> allData = new ArrayList<>();
for (int i = 1; i <= totalBatch; i++) {
String batchKey = FacRedisKeyConstant.getBatchUploadPartsRedisKey(sessionId, i);
Object batch = redisTemplate.opsForValue().get(batchKey);
if (batch instanceof List<?>) {
allData.addAll((List<FacFeatureByPoint>) batch);
Object batchObj = redisTemplate.opsForValue().get(batchKey);
if (batchObj instanceof List<?>) {
@SuppressWarnings("unchecked")
List<FacFeatureByPoint> batch = (List<FacFeatureByPoint>) batchObj;
allData.addAll(batch);
}
}
// 设置 redis key防止多次操作
redisTemplate.opsForValue().set(operationRedisKey, true);
messageDto.setMessage("桩点、立柱、支架数据上传完毕,数据处理中");
String operationPartsRedisKey = FacRedisKeyConstant.getPartsInOperationByProjectRedisKey(projectId);
redisTemplate.opsForValue().set(operationPartsRedisKey, true);
messageDto.setMessage("桩点、立柱、支架数据上传完毕,正在处理中");
SseMessageUtils.publishMessage(messageDto);
scheduledExecutorService.execute(() -> {
try {
// 合并后的数据处理,如入库
this.saveBatch(geoJson.getProjectId(), allData, userId);
this.saveBatch(projectId, allData, userId);
} catch (Exception e) {
messageDto.setMessage("桩点、立柱、支架数据处理失败,请联系管理员处理");
SseMessageUtils.publishMessage(messageDto);
@ -150,7 +154,7 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
String batchKey = FacRedisKeyConstant.getBatchUploadPartsRedisKey(sessionId, i);
redisTemplate.delete(batchKey);
}
redisTemplate.delete(operationRedisKey);
redisTemplate.delete(operationPartsRedisKey);
}
messageDto.setMessage("桩点、立柱、支架数据处理完毕");
SseMessageUtils.publishMessage(messageDto);
@ -625,7 +629,7 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
});
long count = photovoltaicPanelPointService.count(pointWrapper);
if (count <= 0) {
throw new ServiceException("光伏板桩点数据不存在,请导入数据后再进行操作`", HttpStatus.NOT_FOUND);
throw new ServiceException("光伏板桩点数据不存在,请导入数据后再进行操作", HttpStatus.NOT_FOUND);
}
pointWrapper.set(FacPhotovoltaicPanelPoint::getFinishDate, finishDate);
pointWrapper.set(FacPhotovoltaicPanelPoint::getFinishType, FacFinishTypeEnum.HAND.getValue());

View File

@ -14,6 +14,8 @@ import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.sse.dto.SseMessageDto;
import org.dromara.common.sse.utils.SseMessageUtils;
import org.dromara.facility.constant.FacRedisKeyConstant;
import org.dromara.facility.domain.FacMatrix;
import org.dromara.facility.domain.FacPhotovoltaicPanel;
@ -36,7 +38,6 @@ import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.utils.JSTUtil;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DataAccessException;
@ -78,6 +79,13 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private ScheduledExecutorService scheduledExecutorService;
@Lazy
@Resource
private FacPhotovoltaicPanelServiceImpl self; // 注入自己
/**
* 查询设施-光伏板
*
@ -162,166 +170,232 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByGeoJson(FacPhotovoltaicPanelCreateByGeoJsonReq geoJson) {
// 判断当前项目是否正在执行桩点、立柱、支架数据
String operationRedisKey = FacRedisKeyConstant.getInOperationByProjectRedisKey(geoJson.getProjectId());
// Long projectId = geoJson.getProjectId();
Long projectId = 1930896467736707073L;
// 判断 redis key 是否存在,存在则返回
Object object = redisTemplate.opsForValue().get(operationRedisKey);
if (object != null && (Boolean) object) {
throw new ServiceException("项目下桩点、立柱、支架数据正在处理中,请等待处理完毕后操作", HttpStatus.BAD_REQUEST);
List<String> operationRedisKey = FacRedisKeyConstant.getInOperationRedisKeyList(projectId);
List<Object> list = redisTemplate.opsForValue().multiGet(operationRedisKey);
boolean hasValue = list != null && list.stream().anyMatch(Objects::nonNull);
if (hasValue) {
throw new ServiceException("项目下有设施数据正在处理中,请等待处理完毕后再操作", HttpStatus.BAD_REQUEST);
}
Long projectId = geoJson.getProjectId();
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
// 获取项目下方阵信息
List<FacMatrix> matrixList = matrixService.lambdaQuery()
.select(FacMatrix::getId, FacMatrix::getPositions)
.eq(FacMatrix::getProjectId, projectId).list();
if (CollUtil.isEmpty(matrixList)) {
throw new ServiceException("项目下无方阵数据,请先创建方阵信息后再添加光伏板信息", HttpStatus.NOT_FOUND);
}
// 获取当下项目下光伏板的信息
List<FacPhotovoltaicPanel> oldPhotovoltaicPanelList = this.lambdaQuery()
.eq(FacPhotovoltaicPanel::getProjectId, projectId).list();
Map<String, FacPhotovoltaicPanel> photovoltaicPanelMap = oldPhotovoltaicPanelList.stream()
.collect(Collectors.toMap(
panel -> panel.getName() + "_" + panel.getProgressCategoryId(),
Function.identity(),
(existing, replacement) -> existing // 如果有重复,保留第一个
));
List<FacGeoJsonByPlane> locationGeoJsonList = geoJson.getLocationGeoJson();
List<FacFeatureByPlane> locationFeatures = new ArrayList<>();
for (FacGeoJsonByPlane geoJsonByPlane : locationGeoJsonList) {
locationFeatures.addAll(geoJsonByPlane.getFeatures());
// 获取 redis key
String sessionId = geoJson.getSessionId();
int batchNum = geoJson.getBatchNum();
int totalBatch = geoJson.getTotalBatch();
// 获取所有光伏板位置信息
List<FacGeoJsonByPlane> locationGeoJsonBatchList = geoJson.getLocationGeoJson();
if (CollUtil.isNotEmpty(locationGeoJsonBatchList)) {
List<FacFeatureByPlane> locationFeaturesBatch = new ArrayList<>();
for (FacGeoJsonByPlane geoJsonByPlane : locationGeoJsonBatchList) {
locationFeaturesBatch.addAll(geoJsonByPlane.getFeatures());
}
// 存储到 Redis设置过期时间 30 分钟
String redisKeyByLocation = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, batchNum, FacRedisKeyConstant.GEO_TYPE_LOCAL);
redisTemplate.opsForValue().set(redisKeyByLocation, locationFeaturesBatch, 1800, TimeUnit.SECONDS);
}
// 获取所有对应名称的点
List<FacGeoJsonByPoint> nameGeoJsonList = geoJson.getNameGeoJson();
List<FacFeatureByPoint> nameFeatures = new ArrayList<>();
for (FacGeoJsonByPoint geoJsonByPoint : nameGeoJsonList) {
nameFeatures.addAll(geoJsonByPoint.getFeatures());
}
// 获取进度类别信息
List<PgsProgressCategory> progressCategoryList = progressCategoryService.lambdaQuery()
.in(PgsProgressCategory::getWorkType, PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_PROGRESS_CATEGORY_WORK_TYPE).list();
Map<Long, List<PgsProgressCategory>> progressCategoryMap = progressCategoryList.stream()
.collect(Collectors.groupingBy(PgsProgressCategory::getMatrixId));
List<FacPhotovoltaicPanel> allPanels = new ArrayList<>();
List<Future<List<FacPhotovoltaicPanel>>> futures = new ArrayList<>();
Long userId = LoginHelper.getUserId();
// 构建光伏板实体集合
try (ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())) {
for (FacFeatureByPoint nameFeature : nameFeatures) {
Future<List<FacPhotovoltaicPanel>> future = executorService.submit(() -> {
List<FacPhotovoltaicPanel> panelList = new ArrayList<>();
// ① 找到该点对应的 polygon优先包含否则最近
FacFeatureByPlane matchedPolygon = JSTUtil.findNearestOrContainingPolygon(nameFeature, locationFeatures);
if (matchedPolygon == null) return Collections.emptyList();
// ② 获取 geometry 坐标
List<List<Double>> coordinates = matchedPolygon.getGeometry().getCoordinates().getFirst();
// ③ 判断所属方阵
FacMatrix matrix = matrixService.getMatrixIdBy2Coordinates(matrixList, coordinates);
if (matrix == null) return Collections.emptyList();
Long matrixId = matrix.getId();
// ④ 获取进度类别
List<PgsProgressCategory> progressCategoryListByMatrix = progressCategoryMap.get(matrixId);
if (CollUtil.isEmpty(progressCategoryListByMatrix)) return Collections.emptyList();
// ⑤ 获取名称
String name = nameFeature.getProperties() != null ? nameFeature.getProperties().getText() : null;
if (StringUtils.isBlank(name)) return Collections.emptyList();
// ⑥ 构建面板数据
for (PgsProgressCategory progressCategory : progressCategoryListByMatrix) {
FacPhotovoltaicPanel panel = new FacPhotovoltaicPanel();
panel.setMatrixId(matrixId);
panel.setName(name);
panel.setProjectId(projectId);
panel.setPositions(JSONUtil.toJsonStr(coordinates));
panel.setCreateBy(userId);
panel.setUpdateBy(userId);
String mapKey = name + "_" + progressCategory.getId();
FacPhotovoltaicPanel oldPanel = photovoltaicPanelMap.get(mapKey);
if (oldPanel != null) {
panel.setStatus(oldPanel.getStatus());
if (FacFinishStatusEnum.FINISH.getValue().equals(oldPanel.getStatus())) {
panel.setFinishType(oldPanel.getFinishType());
panel.setFinishDate(oldPanel.getFinishDate());
}
panel.setProgressCategoryId(oldPanel.getProgressCategoryId());
panel.setProgressCategoryName(oldPanel.getProgressCategoryName());
} else {
panel.setProgressCategoryId(progressCategory.getId());
panel.setProgressCategoryName(progressCategory.getName());
}
panelList.add(panel);
}
return panelList;
});
futures.add(future);
List<FacGeoJsonByPoint> nameGeoJsonBatchList = geoJson.getNameGeoJson();
if (CollUtil.isNotEmpty(nameGeoJsonBatchList)) {
List<FacFeatureByPoint> nameFeaturesBatch = new ArrayList<>();
for (FacGeoJsonByPoint geoJsonByPoint : nameGeoJsonBatchList) {
nameFeaturesBatch.addAll(geoJsonByPoint.getFeatures());
}
// 等待所有结果
for (Future<List<FacPhotovoltaicPanel>> future : futures) {
try {
allPanels.addAll(future.get());
} catch (Exception e) {
log.error("线程执行异常", e);
// 存储到 Redis设置过期时间 30 分钟
String redisKeyByName = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, batchNum, FacRedisKeyConstant.GEO_TYPE_NAME);
redisTemplate.opsForValue().set(redisKeyByName, nameFeaturesBatch, 1800, TimeUnit.SECONDS);
}
log.info("已接收第 {} 批数据,共 {} 批", batchNum, totalBatch);
Long userId = LoginHelper.getUserId();
SseMessageDto messageDto = new SseMessageDto();
messageDto.setUserIds(List.of(userId));
// 如果是最后一批,开始合并
if (batchNum == totalBatch) {
List<FacFeatureByPlane> locationFeatures = new ArrayList<>();
List<FacFeatureByPoint> nameFeatures = new ArrayList<>();
for (int i = 1; i <= totalBatch; i++) {
String batchKeyByLocation = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, i, FacRedisKeyConstant.GEO_TYPE_LOCAL);
String batchKeyByName = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, i, FacRedisKeyConstant.GEO_TYPE_NAME);
Object batchLocationObj = redisTemplate.opsForValue().get(batchKeyByLocation);
Object batchNameObj = redisTemplate.opsForValue().get(batchKeyByName);
if (batchLocationObj instanceof List<?>) {
@SuppressWarnings("unchecked")
List<FacFeatureByPlane> batch = (List<FacFeatureByPlane>) batchLocationObj;
locationFeatures.addAll(batch);
}
if (batchNameObj instanceof List<?>) {
@SuppressWarnings("unchecked")
List<FacFeatureByPoint> batch = (List<FacFeatureByPoint>) batchNameObj;
nameFeatures.addAll(batch);
}
}
}
// 自定义线程池IO 密集型线程池)
ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(
20, // 核心线程数
50, // 最大线程数
60L, // 线程空闲存活时间
TimeUnit.SECONDS, // 存活时间单位
new LinkedBlockingQueue<>(10000), // 阻塞队列容量
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:由调用线程处理任务
);
// 分批处理,避免长事务,每次处理 1000 条数据
int batchSize = 1000;
// 保存所有批次任务
List<CompletableFuture<Void>> deleteFutures = new ArrayList<>();
int deleteSize = oldPhotovoltaicPanelList.size();
for (int i = 0; i < deleteSize; i += batchSize) {
int endIndex = Math.min(i + batchSize, deleteSize);
List<FacPhotovoltaicPanel> batchList = oldPhotovoltaicPanelList.subList(i, endIndex);
// 使用事务处理每批数据
// 获取代理
FacPhotovoltaicPanelServiceImpl photovoltaicPanelService = (FacPhotovoltaicPanelServiceImpl) AopContext.currentProxy();
// 异步处理每批数据,将任务添加到异步任务列表
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> photovoltaicPanelService.deleteBatchInner(batchList), customExecutor);
deleteFutures.add(future);
}
// 等待所有批次完成操作
CompletableFuture.allOf(deleteFutures.toArray(new CompletableFuture[0])).join();
// 保存所有批次任务
List<CompletableFuture<Void>> insertFutures = new ArrayList<>();
int totalSize = allPanels.size();
for (int i = 0; i < totalSize; i += batchSize) {
int endIndex = Math.min(i + batchSize, totalSize);
List<FacPhotovoltaicPanel> batchList = allPanels.subList(i, endIndex);
// 使用事务处理每批数据
// 获取代理
FacPhotovoltaicPanelServiceImpl photovoltaicPanelService = (FacPhotovoltaicPanelServiceImpl) AopContext.currentProxy();
// 异步处理每批数据,将任务添加到异步任务列表
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> photovoltaicPanelService.insertBatchInner(batchList), customExecutor);
insertFutures.add(future);
}
// 等待所有批次完成操作
CompletableFuture.allOf(insertFutures.toArray(new CompletableFuture[0])).join();
// 关闭线程池
customExecutor.shutdown();
// 更新数量
Map<Long, List<FacPhotovoltaicPanel>> countMap = allPanels
.stream().collect(Collectors.groupingBy(FacPhotovoltaicPanel::getProgressCategoryId));
for (PgsProgressCategory progressCategory : progressCategoryList) {
Long progressCategoryId = progressCategory.getId();
int total = 0;
if (countMap.containsKey(progressCategoryId)) {
total = countMap.get(progressCategoryId).size();
}
progressCategory.setTotal(BigDecimal.valueOf(total));
}
boolean result = progressCategoryService.updateBatchById(progressCategoryList);
if (!result) {
throw new ServiceException("更新进度类别失败,数据库异常", HttpStatus.ERROR);
// 设置 redis key防止多次操作
String operationPanelRedisKey = FacRedisKeyConstant.getPanelInOperationByProjectRedisKey(projectId);
redisTemplate.opsForValue().set(operationPanelRedisKey, true);
messageDto.setMessage("光伏板数据上传完毕,正在处理中");
SseMessageUtils.publishMessage(messageDto);
scheduledExecutorService.execute(() -> {
try {
// 获取当下项目下光伏板的信息
List<FacPhotovoltaicPanel> oldPhotovoltaicPanelList = this.lambdaQuery()
.eq(FacPhotovoltaicPanel::getProjectId, projectId).list();
Map<String, FacPhotovoltaicPanel> photovoltaicPanelMap = oldPhotovoltaicPanelList.stream()
.collect(Collectors.toMap(
panel -> panel.getName() + "_" + panel.getProgressCategoryId(),
Function.identity(),
(existing, replacement) -> existing // 如果有重复,保留第一个
));
// 获取进度类别信息
List<PgsProgressCategory> progressCategoryList = progressCategoryService.lambdaQuery()
.in(PgsProgressCategory::getWorkType, PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_PROGRESS_CATEGORY_WORK_TYPE).list();
Map<Long, List<PgsProgressCategory>> progressCategoryMap = progressCategoryList.stream()
.collect(Collectors.groupingBy(PgsProgressCategory::getMatrixId));
List<FacPhotovoltaicPanel> allPanels = new ArrayList<>();
List<Future<List<FacPhotovoltaicPanel>>> futures = new ArrayList<>();
// 构建光伏板实体集合
try (ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())) {
for (FacFeatureByPoint nameFeature : nameFeatures) {
Future<List<FacPhotovoltaicPanel>> future = executorService.submit(() -> {
List<FacPhotovoltaicPanel> panelList = new ArrayList<>();
// ① 找到该点对应的 polygon优先包含否则最近
FacFeatureByPlane matchedPolygon = JSTUtil.findNearestOrContainingPolygon(nameFeature, locationFeatures);
if (matchedPolygon == null) return Collections.emptyList();
// ② 获取 geometry 坐标
List<List<Double>> coordinates = matchedPolygon.getGeometry().getCoordinates().getFirst();
// ③ 判断所属方阵
FacMatrix matrix = matrixService.getMatrixIdBy2Coordinates(matrixList, coordinates);
if (matrix == null) return Collections.emptyList();
Long matrixId = matrix.getId();
// ④ 获取进度类别
List<PgsProgressCategory> progressCategoryListByMatrix = progressCategoryMap.get(matrixId);
if (CollUtil.isEmpty(progressCategoryListByMatrix)) return Collections.emptyList();
// ⑤ 获取名称
String name = nameFeature.getProperties() != null ? nameFeature.getProperties().getText() : null;
if (StringUtils.isBlank(name)) return Collections.emptyList();
// ⑥ 构建面板数据
for (PgsProgressCategory progressCategory : progressCategoryListByMatrix) {
FacPhotovoltaicPanel panel = new FacPhotovoltaicPanel();
panel.setMatrixId(matrixId);
panel.setName(name);
panel.setProjectId(projectId);
panel.setPositions(JSONUtil.toJsonStr(coordinates));
panel.setCreateBy(userId);
panel.setUpdateBy(userId);
String mapKey = name + "_" + progressCategory.getId();
FacPhotovoltaicPanel oldPanel = photovoltaicPanelMap.get(mapKey);
if (oldPanel != null) {
panel.setStatus(oldPanel.getStatus());
if (FacFinishStatusEnum.FINISH.getValue().equals(oldPanel.getStatus())) {
panel.setFinishType(oldPanel.getFinishType());
panel.setFinishDate(oldPanel.getFinishDate());
}
panel.setProgressCategoryId(oldPanel.getProgressCategoryId());
panel.setProgressCategoryName(oldPanel.getProgressCategoryName());
} else {
panel.setProgressCategoryId(progressCategory.getId());
panel.setProgressCategoryName(progressCategory.getName());
}
panelList.add(panel);
}
return panelList;
});
futures.add(future);
}
// 等待所有结果
for (Future<List<FacPhotovoltaicPanel>> future : futures) {
try {
allPanels.addAll(future.get());
} catch (Exception e) {
log.error("线程执行异常", e);
}
}
}
// 自定义线程池IO 密集型线程池)
ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(
20, // 核心线程数
50, // 最大线程数
60L, // 线程空闲存活时间
TimeUnit.SECONDS, // 存活时间单位
new LinkedBlockingQueue<>(10000), // 阻塞队列容量
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:由调用线程处理任务
);
// 分批处理,避免长事务,每次处理 1000 条数据
int batchSize = 1000;
// 保存所有批次任务
List<CompletableFuture<Void>> deleteFutures = new ArrayList<>();
int deleteSize = oldPhotovoltaicPanelList.size();
for (int i = 0; i < deleteSize; i += batchSize) {
int endIndex = Math.min(i + batchSize, deleteSize);
List<FacPhotovoltaicPanel> batchList = oldPhotovoltaicPanelList.subList(i, endIndex);
// 使用事务处理每批数据
// 获取代理
FacPhotovoltaicPanelServiceImpl photovoltaicPanelService = self;
// 异步处理每批数据,将任务添加到异步任务列表
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> photovoltaicPanelService.deleteBatchInner(batchList), customExecutor);
deleteFutures.add(future);
}
// 等待所有批次完成操作
CompletableFuture.allOf(deleteFutures.toArray(new CompletableFuture[0])).join();
// 保存所有批次任务
List<CompletableFuture<Void>> insertFutures = new ArrayList<>();
int totalSize = allPanels.size();
for (int i = 0; i < totalSize; i += batchSize) {
int endIndex = Math.min(i + batchSize, totalSize);
List<FacPhotovoltaicPanel> batchList = allPanels.subList(i, endIndex);
// 使用事务处理每批数据
// 获取代理
FacPhotovoltaicPanelServiceImpl photovoltaicPanelService = self;
// 异步处理每批数据,将任务添加到异步任务列表
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> photovoltaicPanelService.insertBatchInner(batchList), customExecutor);
insertFutures.add(future);
}
// 等待所有批次完成操作
CompletableFuture.allOf(insertFutures.toArray(new CompletableFuture[0])).join();
// 关闭线程池
customExecutor.shutdown();
// 更新数量
Map<Long, List<FacPhotovoltaicPanel>> countMap = allPanels
.stream().collect(Collectors.groupingBy(FacPhotovoltaicPanel::getProgressCategoryId));
for (PgsProgressCategory progressCategory : progressCategoryList) {
Long progressCategoryId = progressCategory.getId();
int total = 0;
if (countMap.containsKey(progressCategoryId)) {
total = countMap.get(progressCategoryId).size();
}
progressCategory.setTotal(BigDecimal.valueOf(total));
}
boolean result = progressCategoryService.updateBatchById(progressCategoryList);
if (!result) {
throw new ServiceException("更新进度类别失败,数据库异常", HttpStatus.ERROR);
}
messageDto.setMessage("光伏板数据处理完毕");
SseMessageUtils.publishMessage(messageDto);
} catch (Exception e) {
messageDto.setMessage("光伏板数据处理失败,请联系管理员处理");
SseMessageUtils.publishMessage(messageDto);
log.error("光伏板数据处理失败", e);
throw new ServiceException("光伏板数据处理失败", HttpStatus.ERROR);
} finally {
// 清理缓存
for (int i = 1; i <= totalBatch; i++) {
String batchKeyByLocation = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, i, FacRedisKeyConstant.GEO_TYPE_LOCAL);
String batchKeyByName = FacRedisKeyConstant.getBatchUploadPanelRedisKey(sessionId, i, FacRedisKeyConstant.GEO_TYPE_NAME);
redisTemplate.delete(batchKeyByLocation);
redisTemplate.delete(batchKeyByName);
}
redisTemplate.delete(operationPanelRedisKey);
}
});
}
return true;
}

View File

@ -0,0 +1,38 @@
package org.dromara.job.once;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.manager.ys7manager.Ys7Manager;
import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo;
import org.dromara.other.service.IOthYs7DeviceService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author lcj
* @date 2025/6/13 11:08
*/
@Slf4j
//@Component
public class FullSyncYs7DeviceData implements CommandLineRunner {
@Resource
private Ys7Manager ys7Manager;
@Resource
private IOthYs7DeviceService ys7DeviceService;
@Override
public void run(String... args) throws Exception {
log.info("开始同步摄像头设备数据");
List<Ys7QueryDeviceResponseVo> ys7QueryDeviceList = ys7Manager.queryAllDeviceList();
Boolean result = ys7DeviceService.saveOrUpdateByDeviceList(ys7QueryDeviceList);
if (result) {
log.info("摄像头设备数据同步成功");
} else {
log.info("没有需要同步的设备");
}
}
}

View File

@ -0,0 +1,33 @@
package org.dromara.manager.ys7manager;
/**
* @author lcj
* @date 2025/6/12 16:56
*/
public interface Ys7Constant {
/**
* token redis 缓存 key 前缀
*/
String TOKEN_REDIS_KEY = "ys7:token";
/**
* 分页查询设备列表最大条数
*/
Integer MAX_PAGE_SIZE = 50;
/**
* 获取 token 请求地址 Post
*/
String getTokenUrlByPost = "https://open.ys7.com/api/lapp/token/get";
/**
* 分页查询设备列表请求地址 Post
*/
String queryDevicePageUrlByPost = "https://open.ys7.com/api/lapp/device/list";
/**
* 修改设备名称请求地址 Post
*/
String updateDeviceNameUrlByPost = "https://open.ys7.com/api/lapp/device/name/update";
}

View File

@ -0,0 +1,68 @@
package org.dromara.manager.ys7manager;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author lcj
* @date 2025/6/13 11:10
*/
@Slf4j
@Component
public class Ys7Manager {
@Resource
private Ys7Properties ys7Properties;
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 获取所有设备列表
*
* @return 设备列表
*/
public List<Ys7QueryDeviceResponseVo> queryAllDeviceList() {
String token = getToken();
int pageStart = 0;
int pageSize = 50;
List<Ys7QueryDeviceResponseVo> deviceList = new ArrayList<>();
while (true) {
// 分页获取设备
List<Ys7QueryDeviceResponseVo> list = Ys7RequestUtils.queryDeviceVoList(token, pageStart, pageSize);
deviceList.addAll(list);
// 获取设备数量小于分页大小,则结束循环
if (list.size() < pageSize) {
break;
}
pageStart++;
}
return deviceList;
}
/**
* 获取 token
*
* @return token
*/
public String getToken() {
String tokenRedisKey = Ys7Constant.TOKEN_REDIS_KEY;
String token = stringRedisTemplate.opsForValue().get(tokenRedisKey);
// 不为空,直接返回 token
if (token != null) {
return token;
}
// 向云服务商请求新的 token
String newToken = Ys7RequestUtils.getToken(ys7Properties.getAppKey(), ys7Properties.getAppSecret());
// 设置有效期
stringRedisTemplate.opsForValue().set(tokenRedisKey, newToken, 6, TimeUnit.DAYS);
return newToken;
}
}

View File

@ -0,0 +1,26 @@
package org.dromara.manager.ys7manager;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author lcj
* @date 2025/6/12 16:50
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "ys7")
public class Ys7Properties {
/**
* appKey
*/
private String appKey;
/**
* appSecret
*/
private String appSecret;
}

View File

@ -0,0 +1,141 @@
package org.dromara.manager.ys7manager;
import cn.hutool.core.lang.Validator;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.manager.ys7manager.vo.Ys7NoDataResponseVo;
import org.dromara.manager.ys7manager.vo.Ys7PageResponseVo;
import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo;
import org.dromara.manager.ys7manager.vo.Ys7ResponseVo;
import java.util.HashMap;
import java.util.List;
/**
* @author lcj
* @date 2025/6/12 16:54
*/
@Slf4j
public class Ys7RequestUtils {
/**
* 获取 token
*
* @param appKey appKey
* @param appSecret appSecret
* @return token
*/
public static String getToken(String appKey, String appSecret) {
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("appKey", appKey);
paramMap.put("appSecret", appSecret);
String errorMsg = "Ys7 Token 请求失败";
try (HttpResponse response = HttpRequest.post(Ys7Constant.getTokenUrlByPost)
.form(paramMap)
.execute()) {
if (!response.isOk()) {
log.error("{}{}", errorMsg, response.getStatus());
throw new ServiceException(errorMsg + response.getStatus());
}
String body = response.body();
Ys7ResponseVo responseVo = JSONUtil.toBean(body, Ys7ResponseVo.class);
if (!responseVo.getCode().equals("200")) {
log.error("{}{}", errorMsg, responseVo.getMsg());
throw new ServiceException(errorMsg + responseVo.getMsg());
}
log.info("Ys7 Token 请求成功:{}", body);
String data = responseVo.getData();
JSONObject jsonObject = JSONUtil.parseObj(data);
return jsonObject.get("accessToken", String.class);
}
}
/**
* 查询设备列表
*
* @param accessToken 萤石开放API访问令牌
* @param pageStart 分页页码起始页从0开始不超过400页
* @param pageSize 分页大小默认为10不超过50
* @return 设备列表
*/
public static List<Ys7QueryDeviceResponseVo> queryDeviceVoList(String accessToken, Integer pageStart, Integer pageSize) {
if (pageStart < 0 || pageStart > 400) {
throw new ServiceException("分页页码超出范围");
}
if (pageSize < 0 || pageSize > 50) {
pageSize = Ys7Constant.MAX_PAGE_SIZE;
}
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("accessToken", accessToken);
paramMap.put("pageStart", pageStart);
paramMap.put("pageSize", pageSize);
String errorMsg = String.format("Ys7 分页查询设备列表 第%s页大小%s 请求失败", (pageStart + 1), pageSize);
try (HttpResponse response = HttpRequest.post(Ys7Constant.queryDevicePageUrlByPost)
.form(paramMap)
.execute()) {
if (!response.isOk()) {
log.error("{}{}", errorMsg, response.getStatus());
throw new ServiceException(errorMsg + response.getStatus());
}
String body = response.body();
Ys7PageResponseVo responseVo = JSONUtil.toBean(body, Ys7PageResponseVo.class);
if (!responseVo.getCode().equals("200")) {
log.error("{}{}", errorMsg, responseVo.getMsg());
throw new ServiceException(errorMsg + responseVo.getMsg());
}
log.info("Ys7 分页查询设备列表 第{}页大小{} 请求成功:{}", (pageStart + 1), pageSize, body);
return JSONUtil.toList(responseVo.getData(), Ys7QueryDeviceResponseVo.class);
}
}
/**
* 修改设备名称
*
* @param accessToken accessToken
* @param deviceSerial 设备序列号
* @param deviceName 设备名称长度不大于50字节不能包含特殊字符
* @return 是否修改成功
*/
public static Boolean updateDeviceName(String accessToken, String deviceSerial, String deviceName) {
// 参数校验
if (StringUtils.isAnyBlank(accessToken, deviceSerial, deviceName)) {
throw new ServiceException("修改设备名称参数为空", HttpStatus.BAD_REQUEST);
}
if (deviceName.length() > 50) {
throw new ServiceException("设备名称长度不能超过50个字符", HttpStatus.BAD_REQUEST);
}
if (!Validator.isGeneralWithChinese(deviceName)) {
throw new ServiceException("设备名称不能包含特殊字符", HttpStatus.BAD_REQUEST);
}
// 组合请求体
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("accessToken", accessToken);
paramMap.put("deviceSerial", deviceSerial);
paramMap.put("deviceName", deviceName);
// 发送请求
String errorMsg = "修改设备名称请求失败";
try (HttpResponse response = HttpRequest.post(Ys7Constant.updateDeviceNameUrlByPost)
.form(paramMap)
.execute()) {
if (!response.isOk()) {
log.error("{}{}", errorMsg, response.getStatus());
throw new ServiceException(errorMsg + response.getStatus());
}
String body = response.body();
Ys7NoDataResponseVo responseVo = JSONUtil.toBean(body, Ys7NoDataResponseVo.class);
if (!responseVo.getCode().equals("200")) {
log.error("{}{}", errorMsg, responseVo.getMsg());
throw new ServiceException(errorMsg + responseVo.getMsg());
}
log.info("修改设备名称请求成功,设备 {} 名称修改为 {}", deviceSerial, deviceName);
return true;
}
}
}

View File

@ -0,0 +1,22 @@
package org.dromara.manager.ys7manager.vo;
import lombok.Data;
/**
* @author lcj
* @date 2025/6/13 14:30
*/
@Data
public class Ys7NoDataResponseVo {
/**
* 响应码
*/
private String code;
/**
* 响应信息
*/
private String msg;
}

View File

@ -0,0 +1,32 @@
package org.dromara.manager.ys7manager.vo;
import lombok.Data;
/**
* @author lcj
* @date 2025/6/12 17:35
*/
@Data
public class Ys7PageResponseVo {
/**
* 响应码
*/
private String code;
/**
* 响应数据
*/
private String data;
/**
* 响应信息
*/
private String msg;
/**
* 分页信息
*/
private String page;
}

View File

@ -0,0 +1,72 @@
package org.dromara.manager.ys7manager.vo;
import lombok.Data;
/**
* @author lcj
* @date 2025/6/12 17:33
*/
@Data
public class Ys7QueryDeviceResponseVo {
/**
* 条目索引
*/
private String id;
/**
* 设备序列号
*/
private String deviceSerial;
/**
* 设备名称
*/
private String deviceName;
/**
* 设备型号
*/
private String deviceType;
/**
* 设备在线状态1-在线0-离线
*/
private Integer status;
/**
* 布撤防状态
*/
private Integer defence;
/**
* 固件版本号
*/
private String deviceVersion;
/**
* 用户添加时间
*/
private Long addTime;
/**
* 设备最后更新时间
*/
private Long updateTime;
/**
* 设备二级类目名称
*/
private String parentCategory;
/**
* 设备风险安全等级0-安全大于0有风险风险越高值越大
*/
private Integer riskLevel;
/**
* 设备IP地址
*/
private String netAddress;
}

View File

@ -0,0 +1,27 @@
package org.dromara.manager.ys7manager.vo;
import lombok.Data;
/**
* @author lcj
* @date 2025/6/12 17:14
*/
@Data
public class Ys7ResponseVo {
/**
* 响应码
*/
private String code;
/**
* 响应数据
*/
private String data;
/**
* 响应信息
*/
private String msg;
}

View File

@ -0,0 +1,108 @@
package org.dromara.other.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.other.domain.dto.devicepreset.OthDevicePresetCreateReq;
import org.dromara.other.domain.dto.devicepreset.OthDevicePresetQueryReq;
import org.dromara.other.domain.dto.devicepreset.OthDevicePresetUpdateReq;
import org.dromara.other.domain.vo.devicepreset.OthDevicePresetVo;
import org.dromara.other.service.IOthDevicePresetService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 摄像头预置位
*
* @author lcj
* @date 2025-06-13
*/
@Validated
@RestController
@RequestMapping("/other/devicePreset")
public class OthDevicePresetController extends BaseController {
@Resource
private IOthDevicePresetService othDevicePresetService;
/**
* 查询摄像头预置位列表
*/
@SaCheckPermission("other:devicePreset:list")
@GetMapping("/list")
public TableDataInfo<OthDevicePresetVo> list(OthDevicePresetQueryReq req, PageQuery pageQuery) {
return othDevicePresetService.queryPageList(req, pageQuery);
}
/**
* 导出摄像头预置位列表
*/
@SaCheckPermission("other:devicePreset:export")
@Log(title = "摄像头预置位", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(OthDevicePresetQueryReq req, HttpServletResponse response) {
List<OthDevicePresetVo> list = othDevicePresetService.queryList(req);
ExcelUtil.exportExcel(list, "摄像头预置位", OthDevicePresetVo.class, response);
}
/**
* 获取摄像头预置位详细信息
*
* @param id 主键
*/
@SaCheckPermission("other:devicePreset:query")
@GetMapping("/{id}")
public R<OthDevicePresetVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(othDevicePresetService.queryById(id));
}
/**
* 新增摄像头预置位
*/
@SaCheckPermission("other:devicePreset:add")
@Log(title = "摄像头预置位", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Long> add(@Validated(AddGroup.class) @RequestBody OthDevicePresetCreateReq req) {
return R.ok(othDevicePresetService.insertByBo(req));
}
/**
* 修改摄像头预置位
*/
@SaCheckPermission("other:devicePreset:edit")
@Log(title = "摄像头预置位", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody OthDevicePresetUpdateReq req) {
return toAjax(othDevicePresetService.updateByBo(req));
}
/**
* 删除摄像头预置位
*
* @param ids 主键串
*/
@SaCheckPermission("other:devicePreset:remove")
@Log(title = "摄像头预置位", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(othDevicePresetService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,132 @@
package org.dromara.other.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.manager.ys7manager.Ys7Manager;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceQueryReq;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceUpdateEncryptedReq;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceUpdateReq;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceWithProjectReq;
import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo;
import org.dromara.other.service.IOthYs7DeviceService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 萤石摄像头
*
* @author lcj
* @date 2025-06-13
*/
@Validated
@RestController
@RequestMapping("/other/ys7Device")
public class OthYs7DeviceController extends BaseController {
@Resource
private IOthYs7DeviceService othYs7DeviceService;
@Resource
private Ys7Manager ys7Manager;
/**
* 查询萤石摄像头列表
*/
@SaCheckPermission("other:ys7Device:list")
@GetMapping("/list")
public TableDataInfo<OthYs7DeviceVo> list(OthYs7DeviceQueryReq req, PageQuery pageQuery) {
return othYs7DeviceService.queryPageList(req, pageQuery);
}
/**
* 导出萤石摄像头列表
*/
@SaCheckPermission("other:ys7Device:export")
@Log(title = "萤石摄像头", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(OthYs7DeviceQueryReq req, HttpServletResponse response) {
List<OthYs7DeviceVo> list = othYs7DeviceService.queryList(req);
ExcelUtil.exportExcel(list, "萤石摄像头", OthYs7DeviceVo.class, response);
}
/**
* 获取萤石摄像头详细信息
*
* @param id 主键
*/
@SaCheckPermission("other:ys7Device:query")
@GetMapping("/{id}")
public R<OthYs7DeviceVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(othYs7DeviceService.queryById(id));
}
/**
* 修改萤石摄像头
*/
@SaCheckPermission("other:ys7Device:edit")
@Log(title = "萤石摄像头", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody OthYs7DeviceUpdateReq req) {
return toAjax(othYs7DeviceService.updateByBo(req));
}
/**
* 修改萤石摄像头所属项目
*/
@SaCheckPermission("other:ys7Device:edit")
@Log(title = "萤石摄像头", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/with/project")
public R<Void> updateWithProject(@Validated @RequestBody OthYs7DeviceWithProjectReq req) {
return toAjax(othYs7DeviceService.updateWithProject(req));
}
/**
* 修改萤石摄像头视频加密
*/
@SaCheckPermission("other:ys7Device:edit")
@Log(title = "萤石摄像头", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/video/encrypted")
public R<Void> updateVideoEncrypted(@Validated @RequestBody OthYs7DeviceUpdateEncryptedReq req) {
return toAjax(othYs7DeviceService.updateVideoEncrypted(req));
}
/**
* 删除萤石摄像头
*
* @param ids 主键串
*/
@SaCheckPermission("other:ys7Device:remove")
@Log(title = "萤石摄像头", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(othYs7DeviceService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 获取 token
*/
@SaCheckPermission("other:ys7Device:query")
@GetMapping("/get/token")
public R<String> getToken() {
return R.ok(ys7Manager.getToken());
}
}

View File

@ -0,0 +1,60 @@
package org.dromara.other.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 摄像头预置位对象 oth_device_preset
*
* @author lcj
* @date 2025-06-13
*/
@Data
@TableName("oth_device_preset")
public class OthDevicePreset implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 设备序列号
*/
private String deviceSerial;
/**
* 通道号
*/
private Long channelNo;
/**
* 预置点序号
*/
private Long index;
/**
* 预置点
*/
private String name;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
}

View File

@ -0,0 +1,117 @@
package org.dromara.other.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 萤石摄像头对象 oth_ys7_device
*
* @author lcj
* @date 2025-06-13
*/
@Data
@TableName("oth_ys7_device")
public class OthYs7Device implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 设备序列号
*/
private String deviceSerial;
/**
* 设备名称
*/
private String deviceName;
/**
* 设备型号
*/
private String deviceType;
/**
* 设备在线状态(0离线 1在线)
*/
private Integer status;
/**
* 布撤防状态
*/
private Long defence;
/**
* 固件版本号
*/
private String deviceVersion;
/**
* 摄像头坐标信息
*/
private String position;
/**
* 设备添加时间
*/
private Date deviceCreateTime;
/**
* 设备最后更新时间
*/
private Date deviceUpdateTime;
/**
* 设备风险安全等级(0安全 大于0值越大风险越高)
*/
private Integer riskLevel;
/**
* 视频加密(0关闭 1开启)
*/
private Integer videoEncrypted;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 是否删除0正常 1删除
*/
@TableLogic
private Integer isDelete;
}

View File

@ -0,0 +1,40 @@
package org.dromara.other.domain.dto.devicepreset;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/13 17:16
*/
@Data
public class OthDevicePresetCreateReq implements Serializable {
@Serial
private static final long serialVersionUID = -6326735809456235573L;
/**
* 设备序列号
*/
@NotNull(message = "设备序列号不能为空")
private String deviceSerial;
/**
* 通道号
*/
private Long channelNo;
/**
* 预置点序号
*/
private Long index;
/**
* 预置点
*/
private String name;
}

View File

@ -0,0 +1,40 @@
package org.dromara.other.domain.dto.devicepreset;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/13 17:17
*/
@Data
public class OthDevicePresetQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = 440026959610596318L;
/**
* 设备序列号
*/
@NotNull(message = "设备序列号不能为空")
private String deviceSerial;
/**
* 通道号
*/
private Long channelNo;
/**
* 预置点序号
*/
private Long index;
/**
* 预置点
*/
private String name;
}

View File

@ -0,0 +1,40 @@
package org.dromara.other.domain.dto.devicepreset;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/13 17:17
*/
@Data
public class OthDevicePresetUpdateReq implements Serializable {
@Serial
private static final long serialVersionUID = -5204788392612423553L;
/**
* 主键id
*/
@NotNull(message = "主键id不能为空")
private Long id;
/**
* 通道号
*/
private Long channelNo;
/**
* 预置点序号
*/
private Long index;
/**
* 预置点
*/
private String name;
}

View File

@ -0,0 +1,48 @@
package org.dromara.other.domain.dto.ys7device;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/13 10:19
*/
@Data
public class OthYs7DeviceQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = -4341677730149529815L;
/**
* 设备序列号
*/
private String deviceSerial;
/**
* 项目id
*/
private Long projectId;
/**
* 设备名称
*/
private String deviceName;
/**
* 设备型号
*/
private String deviceType;
/**
* 固件版本号
*/
private String deviceVersion;
/**
* 设备在线状态(0离线 1在线)
*/
private Long status;
}

View File

@ -0,0 +1,28 @@
package org.dromara.other.domain.dto.ys7device;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/13 16:20
*/
@Data
public class OthYs7DeviceUpdateEncryptedReq implements Serializable {
@Serial
private static final long serialVersionUID = -5570966854443595312L;
/**
* 主键
*/
private Long id;
/**
* 视频加密(0关闭 1开启)
*/
private Integer videoEncrypted;
}

View File

@ -0,0 +1,48 @@
package org.dromara.other.domain.dto.ys7device;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/13 10:19
*/
@Data
public class OthYs7DeviceUpdateReq implements Serializable {
@Serial
private static final long serialVersionUID = -3434796275594146484L;
/**
* 主键id
*/
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 设备名称
*/
private String deviceName;
/**
* 设备型号
*/
private String deviceType;
/**
* 固件版本号
*/
private String deviceVersion;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,31 @@
package org.dromara.other.domain.dto.ys7device;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/13 16:04
*/
@Data
public class OthYs7DeviceWithProjectReq implements Serializable {
@Serial
private static final long serialVersionUID = 5874710543055812819L;
/**
* 主键
*/
@NotNull(message = "主键不能为空")
private Long id;
/**
* 项目id
*/
@NotNull(message = "项目id不能为空")
private Long projectId;
}

View File

@ -0,0 +1,34 @@
package org.dromara.other.domain.enums;
import lombok.Getter;
/**
* @author lcj
* @date 2025/6/13 16:25
*/
@Getter
public enum OthVideoEncryptedEnum {
OFF("关闭", 0),
OPEN("开启", 1);
private final String text;
private final int value;
OthVideoEncryptedEnum(String text, int value) {
this.text = text;
this.value = value;
}
// 根据 value 获取对应的 text
public static String getTextByValue(int value) {
for (OthVideoEncryptedEnum type : values()) {
if (type.getValue() == value) {
return type.getText();
}
}
return null;
}
}

View File

@ -0,0 +1,57 @@
package org.dromara.other.domain.vo.devicepreset;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.other.domain.OthDevicePreset;
import java.io.Serial;
import java.io.Serializable;
/**
* 摄像头预置位视图对象 oth_device_preset
*
* @author lcj
* @date 2025-06-13
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = OthDevicePreset.class)
public class OthDevicePresetVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long id;
/**
* 设备序列号
*/
@ExcelProperty(value = "设备序列号")
private String deviceSerial;
/**
* 通道号
*/
@ExcelProperty(value = "通道号")
private Long channelNo;
/**
* 预置点序号
*/
@ExcelProperty(value = "预置点序号")
private Long index;
/**
* 预置点
*/
@ExcelProperty(value = "预置点")
private String name;
}

View File

@ -0,0 +1,93 @@
package org.dromara.other.domain.vo.ys7device;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.other.domain.OthYs7Device;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 萤石摄像头视图对象 oth_ys7_device
*
* @author lcj
* @date 2025-06-13
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = OthYs7Device.class)
public class OthYs7DeviceVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ExcelProperty(value = "主键")
private Long id;
/**
* 项目id
*/
@ExcelProperty(value = "项目id")
private Long projectId;
/**
* 项目名称
*/
private String projectName;
/**
* 设备序列号
*/
@ExcelProperty(value = "设备序列号")
private String deviceSerial;
/**
* 设备名称
*/
@ExcelProperty(value = "设备名称")
private String deviceName;
/**
* 设备型号
*/
@ExcelProperty(value = "设备型号")
private String deviceType;
/**
* 设备在线状态(0离线 1在线)
*/
@ExcelProperty(value = "设备在线状态(0离线 1在线)")
private Integer status;
/**
* 固件版本号
*/
@ExcelProperty(value = "固件版本号")
private String deviceVersion;
/**
* 设备添加时间
*/
@ExcelProperty(value = "设备添加时间")
private Date deviceCreateTime;
/**
* 视频加密(0关闭 1开启)
*/
@ExcelProperty(value = "视频加密(0关闭 1开启)")
private Integer videoEncrypted;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@ -0,0 +1,15 @@
package org.dromara.other.mapper;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.other.domain.OthDevicePreset;
import org.dromara.other.domain.vo.devicepreset.OthDevicePresetVo;
/**
* 摄像头预置位Mapper接口
*
* @author lcj
* @date 2025-06-13
*/
public interface OthDevicePresetMapper extends BaseMapperPlus<OthDevicePreset, OthDevicePresetVo> {
}

View File

@ -0,0 +1,15 @@
package org.dromara.other.mapper;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.other.domain.OthYs7Device;
import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo;
/**
* 萤石摄像头Mapper接口
*
* @author lcj
* @date 2025-06-13
*/
public interface OthYs7DeviceMapper extends BaseMapperPlus<OthYs7Device, OthYs7DeviceVo> {
}

View File

@ -0,0 +1,98 @@
package org.dromara.other.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.other.domain.OthDevicePreset;
import org.dromara.other.domain.dto.devicepreset.OthDevicePresetCreateReq;
import org.dromara.other.domain.dto.devicepreset.OthDevicePresetQueryReq;
import org.dromara.other.domain.dto.devicepreset.OthDevicePresetUpdateReq;
import org.dromara.other.domain.vo.devicepreset.OthDevicePresetVo;
import java.util.Collection;
import java.util.List;
/**
* 摄像头预置位Service接口
*
* @author lcj
* @date 2025-06-13
*/
public interface IOthDevicePresetService extends IService<OthDevicePreset> {
/**
* 查询摄像头预置位
*
* @param id 主键
* @return 摄像头预置位
*/
OthDevicePresetVo queryById(Long id);
/**
* 分页查询摄像头预置位列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 摄像头预置位分页列表
*/
TableDataInfo<OthDevicePresetVo> queryPageList(OthDevicePresetQueryReq req, PageQuery pageQuery);
/**
* 查询符合条件的摄像头预置位列表
*
* @param req 查询条件
* @return 摄像头预置位列表
*/
List<OthDevicePresetVo> queryList(OthDevicePresetQueryReq req);
/**
* 新增摄像头预置位
*
* @param req 摄像头预置位
* @return 新增摄像头预置位主键id
*/
Long insertByBo(OthDevicePresetCreateReq req);
/**
* 修改摄像头预置位
*
* @param req 摄像头预置位
* @return 是否修改成功
*/
Boolean updateByBo(OthDevicePresetUpdateReq req);
/**
* 校验并批量删除摄像头预置位信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 获取摄像头预置位视图
*
* @param devicePreset 摄像头预置位
* @return 摄像头预置位视图
*/
OthDevicePresetVo getVo(OthDevicePreset devicePreset);
/**
* 构建查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
LambdaQueryWrapper<OthDevicePreset> buildQueryWrapper(OthDevicePresetQueryReq req);
/**
* 获取摄像头预置位分页对象视图
*
* @param devicePresetPage 摄像头预置位分页对象
* @return 摄像头预置位分页对象视图
*/
Page<OthDevicePresetVo> getVoPage(Page<OthDevicePreset> devicePresetPage);
}

View File

@ -0,0 +1,133 @@
package org.dromara.other.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo;
import org.dromara.other.domain.OthYs7Device;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceQueryReq;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceUpdateEncryptedReq;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceUpdateReq;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceWithProjectReq;
import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo;
import java.util.Collection;
import java.util.List;
/**
* 萤石摄像头Service接口
*
* @author lcj
* @date 2025-06-13
*/
public interface IOthYs7DeviceService extends IService<OthYs7Device> {
/**
* 查询萤石摄像头
*
* @param id 主键
* @return 萤石摄像头
*/
OthYs7DeviceVo queryById(Long id);
/**
* 分页查询萤石摄像头列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 萤石摄像头分页列表
*/
TableDataInfo<OthYs7DeviceVo> queryPageList(OthYs7DeviceQueryReq req, PageQuery pageQuery);
/**
* 查询符合条件的萤石摄像头列表
*
* @param req 查询条件
* @return 萤石摄像头列表
*/
List<OthYs7DeviceVo> queryList(OthYs7DeviceQueryReq req);
/**
* 修改萤石摄像头
*
* @param req 萤石摄像头
* @return 是否修改成功
*/
Boolean updateByBo(OthYs7DeviceUpdateReq req);
/**
* 设备分配项目
*
* @param req 萤石摄像头
* @return 是否分配成功
*/
Boolean updateWithProject(OthYs7DeviceWithProjectReq req);
/**
* 修改萤石摄像头视频加密
*
* @param req 萤石摄像头
* @return 是否修改成功
*/
Boolean updateVideoEncrypted(OthYs7DeviceUpdateEncryptedReq req);
/**
* 校验并批量删除萤石摄像头信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 获取萤石摄像头视图
*
* @param ys7Device 萤石摄像头
* @return 萤石摄像头视图
*/
OthYs7DeviceVo getVo(OthYs7Device ys7Device);
/**
* 构建查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
LambdaQueryWrapper<OthYs7Device> buildQueryWrapper(OthYs7DeviceQueryReq req);
/**
* 获取萤石摄像头分页对象视图
*
* @param ys7DevicePage 萤石摄像头分页对象
* @return 萤石摄像头分页对象视图
*/
Page<OthYs7DeviceVo> getVoPage(Page<OthYs7Device> ys7DevicePage);
/**
* 获取萤石摄像对象
*
* @param deviceResponseVo 萤石摄像数据
* @return 萤石摄像对象
*/
OthYs7Device getEntity(Ys7QueryDeviceResponseVo deviceResponseVo);
/**
* 获取萤石摄像对象列表
*
* @param deviceResponseVoList 萤石摄像数据列表
* @return 萤石摄像对象列表
*/
List<OthYs7Device> getEntityList(List<Ys7QueryDeviceResponseVo> deviceResponseVoList);
/**
* 根据云端数据保存或更新萤石摄像对象列表
*
* @param deviceResponseVoList 云端萤石摄像数据列表
* @return 是否有值发生更改
*/
Boolean saveOrUpdateByDeviceList(List<Ys7QueryDeviceResponseVo> deviceResponseVoList);
}

View File

@ -0,0 +1,214 @@
package org.dromara.other.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.other.domain.OthDevicePreset;
import org.dromara.other.domain.OthYs7Device;
import org.dromara.other.domain.dto.devicepreset.OthDevicePresetCreateReq;
import org.dromara.other.domain.dto.devicepreset.OthDevicePresetQueryReq;
import org.dromara.other.domain.dto.devicepreset.OthDevicePresetUpdateReq;
import org.dromara.other.domain.vo.devicepreset.OthDevicePresetVo;
import org.dromara.other.mapper.OthDevicePresetMapper;
import org.dromara.other.service.IOthDevicePresetService;
import org.dromara.other.service.IOthYs7DeviceService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
/**
* 摄像头预置位Service业务层处理
*
* @author lcj
* @date 2025-06-13
*/
@Service
public class OthDevicePresetServiceImpl extends ServiceImpl<OthDevicePresetMapper, OthDevicePreset>
implements IOthDevicePresetService {
@Resource
private IOthYs7DeviceService othYs7DeviceService;
/**
* 查询摄像头预置位
*
* @param id 主键
* @return 摄像头预置位
*/
@Override
public OthDevicePresetVo queryById(Long id) {
OthDevicePreset devicePreset = this.getById(id);
if (devicePreset == null) {
throw new RuntimeException("摄像头预置位信息不存在");
}
return this.getVo(devicePreset);
}
/**
* 分页查询摄像头预置位列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 摄像头预置位分页列表
*/
@Override
public TableDataInfo<OthDevicePresetVo> queryPageList(OthDevicePresetQueryReq req, PageQuery pageQuery) {
Page<OthDevicePreset> result = this.page(pageQuery.build(), this.buildQueryWrapper(req));
return TableDataInfo.build(this.getVoPage(result));
}
/**
* 查询符合条件的摄像头预置位列表
*
* @param req 查询条件
* @return 摄像头预置位列表
*/
@Override
public List<OthDevicePresetVo> queryList(OthDevicePresetQueryReq req) {
LambdaQueryWrapper<OthDevicePreset> lqw = buildQueryWrapper(req);
return this.list(lqw).stream().map(this::getVo).toList();
}
/**
* 新增摄像头预置位
*
* @param req 摄像头预置位
* @return 新增摄像头预置位主键id
*/
@Override
public Long insertByBo(OthDevicePresetCreateReq req) {
OthDevicePreset devicePreset = new OthDevicePreset();
BeanUtils.copyProperties(req, devicePreset);
validEntityBeforeSave(devicePreset, true);
boolean result = this.save(devicePreset);
if (!result) {
throw new ServiceException("摄像头预置位信息新增失败", HttpStatus.ERROR);
}
return devicePreset.getId();
}
/**
* 修改摄像头预置位
*
* @param req 摄像头预置位
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(OthDevicePresetUpdateReq req) {
OthDevicePreset devicePreset = new OthDevicePreset();
BeanUtils.copyProperties(req, devicePreset);
validEntityBeforeSave(devicePreset, false);
OthDevicePreset oldDevicePreset = this.getById(req.getId());
if (oldDevicePreset == null) {
throw new ServiceException("修改摄像头预置位信息失败,数据不存在", HttpStatus.NOT_FOUND);
}
boolean result = this.updateById(devicePreset);
if (!result) {
throw new ServiceException("摄像头预置位信息更新失败", HttpStatus.ERROR);
}
return true;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(OthDevicePreset entity, Boolean create) {
//TODO 做一些数据校验,如唯一约束
String deviceSerial = entity.getDeviceSerial();
if (create) {
if (StringUtils.isBlank(deviceSerial)) {
throw new ServiceException("设备序列号不能为空", HttpStatus.BAD_REQUEST);
}
}
if (StringUtils.isNotBlank(deviceSerial)) {
Long count = othYs7DeviceService.lambdaQuery()
.eq(OthYs7Device::getDeviceSerial, deviceSerial)
.count();
if (count <= 0) {
throw new ServiceException("设备不存在", HttpStatus.BAD_REQUEST);
}
}
}
/**
* 校验并批量删除摄像头预置位信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 获取摄像头预置位视图
*
* @param devicePreset 摄像头预置位
* @return 摄像头预置位视图
*/
@Override
public OthDevicePresetVo getVo(OthDevicePreset devicePreset) {
OthDevicePresetVo vo = new OthDevicePresetVo();
if (devicePreset == null) {
return vo;
}
BeanUtils.copyProperties(devicePreset, vo);
return vo;
}
/**
* 构建查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
@Override
public LambdaQueryWrapper<OthDevicePreset> buildQueryWrapper(OthDevicePresetQueryReq req) {
LambdaQueryWrapper<OthDevicePreset> lqw = new LambdaQueryWrapper<>();
String deviceSerial = req.getDeviceSerial();
Long channelNo = req.getChannelNo();
Long index = req.getIndex();
String name = req.getName();
lqw.eq(StringUtils.isNotBlank(deviceSerial), OthDevicePreset::getDeviceSerial, deviceSerial);
lqw.eq(ObjectUtils.isNotEmpty(channelNo), OthDevicePreset::getChannelNo, channelNo);
lqw.eq(ObjectUtils.isNotEmpty(index), OthDevicePreset::getIndex, index);
lqw.like(StringUtils.isNotBlank(name), OthDevicePreset::getName, name);
return lqw;
}
/**
* 获取摄像头预置位分页对象视图
*
* @param devicePresetPage 摄像头预置位分页对象
* @return 摄像头预置位分页对象视图
*/
@Override
public Page<OthDevicePresetVo> getVoPage(Page<OthDevicePreset> devicePresetPage) {
List<OthDevicePreset> devicePresetList = devicePresetPage.getRecords();
Page<OthDevicePresetVo> devicePresetVoPage = new Page<>(
devicePresetPage.getCurrent(),
devicePresetPage.getSize(),
devicePresetPage.getTotal());
if (CollUtil.isEmpty(devicePresetList)) {
return devicePresetVoPage;
}
List<OthDevicePresetVo> devicePresetVoList = devicePresetList.stream().map(this::getVo).toList();
devicePresetVoPage.setRecords(devicePresetVoList);
return devicePresetVoPage;
}
}

View File

@ -0,0 +1,407 @@
package org.dromara.other.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.manager.ys7manager.Ys7Manager;
import org.dromara.manager.ys7manager.Ys7RequestUtils;
import org.dromara.manager.ys7manager.vo.Ys7QueryDeviceResponseVo;
import org.dromara.other.domain.OthYs7Device;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceQueryReq;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceUpdateEncryptedReq;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceUpdateReq;
import org.dromara.other.domain.dto.ys7device.OthYs7DeviceWithProjectReq;
import org.dromara.other.domain.enums.OthVideoEncryptedEnum;
import org.dromara.other.domain.vo.ys7device.OthYs7DeviceVo;
import org.dromara.other.mapper.OthYs7DeviceMapper;
import org.dromara.other.service.IOthYs7DeviceService;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 萤石摄像头Service业务层处理
*
* @author lcj
* @date 2025-06-13
*/
@Slf4j
@Service
public class OthYs7DeviceServiceImpl extends ServiceImpl<OthYs7DeviceMapper, OthYs7Device>
implements IOthYs7DeviceService {
@Resource
private IBusProjectService projectService;
@Resource
private Ys7Manager ys7Manager;
/**
* 查询萤石摄像头
*
* @param id 主键
* @return 萤石摄像头
*/
@Override
public OthYs7DeviceVo queryById(Long id) {
OthYs7Device ys7Device = this.getById(id);
if (ys7Device == null) {
throw new ServiceException("萤石摄像头信息不存在", HttpStatus.NOT_FOUND);
}
return this.getVo(ys7Device);
}
/**
* 分页查询萤石摄像头列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 萤石摄像头分页列表
*/
@Override
public TableDataInfo<OthYs7DeviceVo> queryPageList(OthYs7DeviceQueryReq req, PageQuery pageQuery) {
LambdaQueryWrapper<OthYs7Device> lqw = buildQueryWrapper(req);
Page<OthYs7Device> result = this.page(pageQuery.build(), lqw);
return TableDataInfo.build(this.getVoPage(result));
}
/**
* 查询符合条件的萤石摄像头列表
*
* @param req 查询条件
* @return 萤石摄像头列表
*/
@Override
public List<OthYs7DeviceVo> queryList(OthYs7DeviceQueryReq req) {
LambdaQueryWrapper<OthYs7Device> lqw = buildQueryWrapper(req);
return this.list(lqw).stream().map(this::getVo).toList();
}
/**
* 修改萤石摄像头
*
* @param req 萤石摄像头
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(OthYs7DeviceUpdateReq req) {
// 将实体类和 DTO 进行转换
OthYs7Device ys7Device = new OthYs7Device();
BeanUtils.copyProperties(req, ys7Device);
// 数据校验
OthYs7Device oldYs7Device = this.getById(req.getId());
if (oldYs7Device == null) {
throw new ServiceException("萤石摄像头信息不存在", HttpStatus.NOT_FOUND);
}
validEntityBeforeSave(ys7Device);
// 判断是否更新名称
String deviceName = req.getDeviceName();
if (deviceName != null && !deviceName.equals(oldYs7Device.getDeviceName())) {
Long count = this.lambdaQuery()
.eq(OthYs7Device::getDeviceName, req.getDeviceName())
.count();
if (count > 0) {
throw new ServiceException("已存在同名萤石摄像头", HttpStatus.CONFLICT);
}
String token = ys7Manager.getToken();
Boolean result = Ys7RequestUtils.updateDeviceName(token, oldYs7Device.getDeviceSerial(), deviceName);
if (!result) {
throw new ServiceException("更新云端萤石摄像头名称异常", HttpStatus.ERROR);
}
}
boolean result = this.updateById(ys7Device);
if (!result) {
throw new ServiceException("更新萤石摄像头信息异常", HttpStatus.ERROR);
}
return true;
}
/**
* 设备分配项目
*
* @param req 萤石摄像头
* @return 是否分配成功
*/
@Override
public Boolean updateWithProject(OthYs7DeviceWithProjectReq req) {
Long id = req.getId();
Long projectId = req.getProjectId();
// 参数校验
if (id == null || projectId == null) {
throw new ServiceException("参数为空", HttpStatus.BAD_REQUEST);
}
OthYs7Device ys7Device = this.getById(id);
if (ys7Device == null) {
throw new ServiceException("萤石摄像头信息不存在", HttpStatus.NOT_FOUND);
}
BusProject project = projectService.getById(projectId);
if (project == null) {
throw new ServiceException("项目信息不存在", HttpStatus.NOT_FOUND);
}
// 权限校验
Long userId = LoginHelper.getUserId();
projectService.validAuth(projectId, userId);
// 更新
boolean update = this.lambdaUpdate()
.eq(OthYs7Device::getId, id)
.set(OthYs7Device::getProjectId, projectId)
.update();
if (!update) {
throw new ServiceException("更新萤石摄像头信息异常", HttpStatus.ERROR);
}
return true;
}
/**
* 修改萤石摄像头视频加密
*
* @param req 萤石摄像头
* @return 是否修改成功
*/
@Override
public Boolean updateVideoEncrypted(OthYs7DeviceUpdateEncryptedReq req) {
Long id = req.getId();
Integer videoEncrypted = req.getVideoEncrypted();
// 参数校验
if (id == null || videoEncrypted == null) {
throw new ServiceException("参数为空", HttpStatus.BAD_REQUEST);
}
OthYs7Device ys7Device = this.getById(id);
if (ys7Device == null) {
throw new ServiceException("萤石摄像头信息不存在", HttpStatus.NOT_FOUND);
}
if (videoEncrypted.equals(ys7Device.getVideoEncrypted())) {
return true;
}
String text = OthVideoEncryptedEnum.getTextByValue(videoEncrypted);
if (text == null) {
throw new ServiceException("参数错误,未知状态", HttpStatus.BAD_REQUEST);
}
boolean update = this.lambdaUpdate()
.eq(OthYs7Device::getId, id)
.set(OthYs7Device::getVideoEncrypted, videoEncrypted)
.update();
if (!update) {
throw new ServiceException("更新萤石摄像头信息异常", HttpStatus.ERROR);
}
return true;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(OthYs7Device entity) {
//TODO 做一些数据校验,如唯一约束
Long projectId = entity.getProjectId();
if (projectId != null && projectId != 0) {
if (projectService.getById(projectId) == null) {
throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND);
}
}
}
/**
* 校验并批量删除萤石摄像头信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 获取萤石摄像头视图
*
* @param ys7Device 萤石摄像头
* @return 萤石摄像头视图
*/
@Override
public OthYs7DeviceVo getVo(OthYs7Device ys7Device) {
// 对象转封装类
OthYs7DeviceVo ys7DeviceVo = new OthYs7DeviceVo();
if (ys7Device == null) {
return ys7DeviceVo;
}
BeanUtils.copyProperties(ys7Device, ys7DeviceVo);
Long projectId = ys7Device.getProjectId();
if (projectId != null && !projectId.equals(0L)) {
BusProject project = projectService.getById(projectId);
ys7DeviceVo.setProjectName(project.getProjectName());
}
return ys7DeviceVo;
}
/**
* 构建查询条件封装
*
* @param req 查询条件
* @return 查询条件封装
*/
@Override
public LambdaQueryWrapper<OthYs7Device> buildQueryWrapper(OthYs7DeviceQueryReq req) {
LambdaQueryWrapper<OthYs7Device> lqw = new LambdaQueryWrapper<>();
String deviceSerial = req.getDeviceSerial();
Long projectId = req.getProjectId();
String deviceName = req.getDeviceName();
String deviceType = req.getDeviceType();
String deviceVersion = req.getDeviceVersion();
Long status = req.getStatus();
lqw.eq(ObjectUtils.isNotEmpty(projectId), OthYs7Device::getProjectId, projectId)
.or()
.eq(OthYs7Device::getProjectId, 0L);
lqw.eq(ObjectUtils.isNotEmpty(status), OthYs7Device::getStatus, status);
lqw.like(StringUtils.isNotBlank(deviceName), OthYs7Device::getDeviceName, deviceName);
lqw.like(StringUtils.isNotBlank(deviceType), OthYs7Device::getDeviceType, deviceType);
lqw.like(StringUtils.isNotBlank(deviceSerial), OthYs7Device::getDeviceSerial, deviceSerial);
lqw.like(StringUtils.isNotBlank(deviceVersion), OthYs7Device::getDeviceVersion, deviceVersion);
lqw.orderByDesc(OthYs7Device::getProjectId);
return lqw;
}
/**
* 获取萤石摄像头分页对象视图
*
* @param ys7DevicePage 萤石摄像头分页对象
* @return 萤石摄像头分页对象视图
*/
@Override
public Page<OthYs7DeviceVo> getVoPage(Page<OthYs7Device> ys7DevicePage) {
List<OthYs7Device> ys7DeviceList = ys7DevicePage.getRecords();
Page<OthYs7DeviceVo> ys7DeviceVoPage = new Page<>(
ys7DevicePage.getCurrent(),
ys7DevicePage.getSize(),
ys7DevicePage.getTotal());
if (CollUtil.isEmpty(ys7DeviceList)) {
return ys7DeviceVoPage;
}
// 获取项目列表
Set<Long> projectIdList = ys7DeviceList.stream().map(OthYs7Device::getProjectId).collect(Collectors.toSet());
List<BusProject> projectList = projectService.lambdaQuery()
.select(BusProject::getId, BusProject::getProjectName)
.in(BusProject::getId, projectIdList)
.list();
Map<Long, BusProject> projectMap = projectList.stream().collect(Collectors.toMap(BusProject::getId, project -> project));
// 对象列表 => 封装对象列表
List<OthYs7DeviceVo> ys7DeviceVoList = ys7DeviceList.stream().map(ys7Device -> {
OthYs7DeviceVo ys7DeviceVo = new OthYs7DeviceVo();
BeanUtils.copyProperties(ys7Device, ys7DeviceVo);
Long projectId = ys7Device.getProjectId();
if (projectId != null && !projectId.equals(0L)) {
BusProject project = projectMap.get(projectId);
ys7DeviceVo.setProjectName(project.getProjectName());
}
return ys7DeviceVo;
}).toList();
ys7DeviceVoPage.setRecords(ys7DeviceVoList);
return ys7DeviceVoPage;
}
/**
* 获取萤石摄像对象
*
* @param deviceResponseVo 萤石摄像数据
* @return 萤石摄像对象
*/
@Override
public OthYs7Device getEntity(Ys7QueryDeviceResponseVo deviceResponseVo) {
OthYs7Device ys7Device = new OthYs7Device();
if (deviceResponseVo == null) {
return ys7Device;
}
ys7Device.setDeviceSerial(deviceResponseVo.getDeviceSerial());
ys7Device.setDeviceName(deviceResponseVo.getDeviceName());
ys7Device.setDeviceType(deviceResponseVo.getDeviceType());
ys7Device.setStatus(deviceResponseVo.getStatus());
ys7Device.setDefence(Long.valueOf(deviceResponseVo.getDefence()));
ys7Device.setDeviceVersion(deviceResponseVo.getDeviceVersion());
ys7Device.setPosition(deviceResponseVo.getNetAddress());
ys7Device.setDeviceCreateTime(new Date(deviceResponseVo.getAddTime()));
ys7Device.setDeviceUpdateTime(new Date(deviceResponseVo.getUpdateTime()));
ys7Device.setRiskLevel(deviceResponseVo.getRiskLevel());
return ys7Device;
}
/**
* 获取萤石摄像对象列表
*
* @param deviceResponseVoList 萤石摄像数据列表
* @return 萤石摄像对象列表
*/
@Override
public List<OthYs7Device> getEntityList(List<Ys7QueryDeviceResponseVo> deviceResponseVoList) {
if (CollUtil.isEmpty(deviceResponseVoList)) {
return List.of();
}
return deviceResponseVoList.stream().map(this::getEntity).toList();
}
/**
* 根据云端数据保存或更新萤石摄像对象列表
*
* @param deviceResponseVoList 云端萤石摄像数据列表
* @return 是否有值发生更改
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean saveOrUpdateByDeviceList(List<Ys7QueryDeviceResponseVo> deviceResponseVoList) {
if (deviceResponseVoList == null) {
return false;
}
List<OthYs7Device> deviceList = this.getEntityList(deviceResponseVoList);
// 查询数据库中的数据并构建 Map<deviceSerial, OthYs7Device>
Map<String, OthYs7Device> entityMap = this.list().stream()
.collect(Collectors.toMap(
OthYs7Device::getDeviceSerial,
Function.identity(),
(a, b) -> a));
// 记录日志
StringBuffer updateLog = new StringBuffer();
StringBuffer saveLog = new StringBuffer();
// 遍历设备列表,设置已存在的 id
List<OthYs7Device> resultList = deviceList.stream()
.peek(device -> {
OthYs7Device existing = entityMap.get(device.getDeviceSerial());
if (existing != null) {
device.setId(existing.getId());
updateLog.append("[")
.append(device.getDeviceName())
.append("")
.append(device.getDeviceSerial())
.append("]");
} else {
saveLog.append("[")
.append(device.getDeviceName())
.append("")
.append(device.getDeviceSerial())
.append("]");
}
})
.toList();
log.info("需新增信息设备:{}", saveLog);
log.info("需修改信息设备:{}", updateLog);
// 更新或保存设备列表
return saveOrUpdateBatch(resultList);
}
}

View File

@ -8,6 +8,11 @@ import java.util.List;
*/
public interface PgsProgressCategoryConstant {
/**
* 顶级父级id
*/
Long TOP_PARENT_ID = 0L;
/**
* 项目公共进度类别ID
*/

View File

@ -1,7 +1,6 @@
package org.dromara.progress.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -9,7 +8,6 @@ import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.math.BigDecimal;
import java.util.Date;
/**
* 进度类别对象 pgs_progress_category
@ -46,6 +44,11 @@ public class PgsProgressCategory extends BaseEntity {
*/
private Long matrixId;
/**
* 方阵名称
*/
private String matrixName;
/**
* 类别名称
*/
@ -91,15 +94,4 @@ public class PgsProgressCategory extends BaseEntity {
*/
private String remark;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 是否删除0正常 1删除
*/
@TableLogic
private Long isDelete;
}

View File

@ -27,6 +27,11 @@ public class PgsProgressCategoryMatrixVo implements Serializable {
*/
private Long matrixId;
/**
* 方阵名称
*/
private String name;
/**
* 总数量/百分比
*/

View File

@ -24,6 +24,11 @@ public class PgsProgressCategoryProjectVo implements Serializable {
*/
private Long projectId;
/**
* 项目名称
*/
private String name;
/**
* 总数量/百分比
*/

View File

@ -28,6 +28,11 @@ public class PgsProgressCategorySubProjectVo implements Serializable {
*/
private Long subProjectId;
/**
* 子项目名称
*/
private String name;
/**
* 总数量/百分比
*/

View File

@ -2,6 +2,7 @@ package org.dromara.progress.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.facility.domain.FacMatrix;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryCreateReq;
import org.dromara.progress.domain.dto.progresscategory.PgsProgressCategoryQueryReq;
@ -98,11 +99,12 @@ public interface IPgsProgressCategoryService extends IService<PgsProgressCategor
/**
* 根据模板创建进度类别
*
* @param projectId 项目id
* @param matrixIds 方阵id列表
* @param projectId 项目id
* @param matrixList 方阵列表
* @param oldMatrixList 旧方阵列表
* @return 是否创建成功
*/
Boolean insertByTemplate(Long projectId, List<Long> matrixIds);
Boolean insertByTemplate(Long projectId, List<FacMatrix> matrixList, List<FacMatrix> oldMatrixList);
/**
* 根据id获取进度类别坐标信息

View File

@ -113,7 +113,13 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
*/
@Override
public List<PgsProgressCategoryVo> queryList(PgsProgressCategoryQueryReq req) {
List<PgsProgressCategory> list = this.list(this.buildQueryWrapper(req));
Long matrixId = req.getMatrixId();
if (matrixService.getById(matrixId) == null) {
throw new ServiceException("方阵不存在", HttpStatus.BAD_REQUEST);
}
List<PgsProgressCategory> list = this.lambdaQuery()
.eq(PgsProgressCategory::getMatrixId, matrixId)
.list();
return this.getVoList(list);
}
@ -275,7 +281,7 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
Long projectId = req.getProjectId();
Long matrixId = req.getMatrixId();
// 精确查询
lqw.in(ObjectUtils.isNotEmpty(projectId), PgsProgressCategory::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(projectId), PgsProgressCategory::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(matrixId), PgsProgressCategory::getMatrixId, matrixId);
return lqw;
}
@ -324,13 +330,15 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
/**
* 根据模板创建进度类别
*
* @param projectId 项目id
* @param matrixIds 方阵id列表
* @param projectId 项目id
* @param matrixList 方阵列表
* @param oldMatrixList 旧方阵列表
* @return 是否创建成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByTemplate(Long projectId, List<Long> matrixIds) {
public Boolean insertByTemplate(Long projectId, List<FacMatrix> matrixList, List<FacMatrix> oldMatrixList) {
List<Long> oldMatrixIdList = oldMatrixList.stream().map(FacMatrix::getId).toList();
// 获取模板进度类别
List<PgsProgressCategoryTemplate> categoryTemplateList = pgsProgressCategoryTemplateService.lambdaQuery()
.in(PgsProgressCategoryTemplate::getProjectId, projectId, PgsProgressCategoryConstant.PUBLIC_PROJECT_ID)
@ -339,10 +347,45 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
if (CollUtil.isEmpty(categoryTemplateList)) {
throw new ServiceException("对应模板进度类别不存在", HttpStatus.NOT_FOUND);
}
// 获取百分比设施数据
Map<String, List<PgsProgressCategory>> oldPercentageCategoryMap = new HashMap<>();
Map<Long, List<PgsProgressPlan>> oldPlanMap = new HashMap<>();
Map<Long, List<PgsProgressPlanDetail>> oldPlanDetailMap = new HashMap<>();
if (CollUtil.isNotEmpty(oldMatrixList)) {
List<PgsProgressCategory> oldPercentageCategoryList = this.lambdaQuery()
.in(PgsProgressCategory::getMatrixId, oldMatrixIdList)
.ne(PgsProgressCategory::getPid, PgsProgressCategoryConstant.TOP_PARENT_ID)
.eq(PgsProgressCategory::getUnitType, PgsProgressUnitTypeEnum.PERCENTAGE.getValue())
.list();
oldPercentageCategoryMap = oldPercentageCategoryList.stream()
.collect(Collectors.groupingBy(item -> item.getMatrixName() + "_" + item.getWorkType()));
// 获取百分比设施计划数据
List<Long> oldPercentageCategoryIdList = oldPercentageCategoryList.stream().map(PgsProgressCategory::getId).toList();
if (CollUtil.isNotEmpty(oldPercentageCategoryIdList)) {
List<PgsProgressPlan> oldPlanList = progressPlanService.lambdaQuery()
.select(PgsProgressPlan::getId, PgsProgressPlan::getProgressCategoryId)
.in(PgsProgressPlan::getProgressCategoryId, oldPercentageCategoryIdList)
.list();
oldPlanMap = oldPlanList.stream()
.collect(Collectors.groupingBy(PgsProgressPlan::getProgressCategoryId));
// 获取百分比设施计划详情数据
List<Long> oldPlanIdList = oldPlanList.stream().map(PgsProgressPlan::getId).toList();
if (CollUtil.isNotEmpty(oldPlanIdList)) {
List<PgsProgressPlanDetail> oldPlanDetailList = progressPlanDetailService.lambdaQuery()
.in(PgsProgressPlanDetail::getProgressPlanId, oldPlanIdList)
.list();
oldPlanDetailMap = oldPlanDetailList.stream()
.collect(Collectors.groupingBy(PgsProgressPlanDetail::getProgressPlanId));
}
}
}
// 需修改、保存的数据
List<PgsProgressCategory> newList = new ArrayList<>();
List<FacPercentageFacility> percentageFacilityList = new ArrayList<>();
List<PgsProgressPlan> newPlanList = new ArrayList<>();
List<PgsProgressPlanDetail> newPlanDetailList = new ArrayList<>();
// 每个 matrixId 对应一套新的 ID 映射
for (Long matrixId : matrixIds) {
for (FacMatrix matrix : matrixList) {
// templateId -> newId
Map<Long, Long> localIdMap = new HashMap<>();
List<PgsProgressCategory> localList = new ArrayList<>();
@ -355,17 +398,50 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
newCategory.setUnitType(template.getUnitType());
newCategory.setWorkType(template.getWorkType());
newCategory.setProjectId(projectId);
newCategory.setMatrixId(matrixId);
newCategory.setMatrixId(matrix.getId());
newCategory.setMatrixName(matrix.getMatrixName());
newCategory.setRemark(template.getRemark());
// 先临时设置旧 pid
newCategory.setPid(template.getPid());
localList.add(newCategory);
// 创建百分比设施
if (template.getPid() != 0 && template.getUnitType().equals(PgsProgressUnitTypeEnum.PERCENTAGE.getValue())) {
String mapKey = matrix.getMatrixName() + "_" + template.getWorkType();
// 填充数据
if (CollUtil.isNotEmpty(oldPercentageCategoryMap) && oldPercentageCategoryMap.containsKey(mapKey)) {
PgsProgressCategory oldPercentageCategory = oldPercentageCategoryMap.get(mapKey).getFirst();
if (CollUtil.isNotEmpty(oldPlanMap) && oldPlanMap.containsKey(oldPercentageCategory.getId())) {
List<PgsProgressPlan> planList = oldPlanMap.get(oldPercentageCategory.getId());
// 填充计划数据
for (PgsProgressPlan plan : planList) {
PgsProgressPlan newPlan = new PgsProgressPlan();
Long planId = plan.getId();
newPlan.setId(planId);
newPlan.setProjectId(projectId);
newPlan.setMatrixId(matrix.getId());
newPlan.setProgressCategoryId(newId);
newPlanList.add(newPlan);
// 填充计划详情数据
if (CollUtil.isNotEmpty(oldPlanDetailMap) && oldPlanDetailMap.containsKey(planId)) {
List<PgsProgressPlanDetail> planDetailList = oldPlanDetailMap.get(planId);
for (PgsProgressPlanDetail planDetail : planDetailList) {
PgsProgressPlanDetail newPlanDetail = new PgsProgressPlanDetail();
newPlanDetail.setId(planDetail.getId());
newPlanDetail.setProgressCategoryId(newId);
newPlanDetailList.add(newPlanDetail);
}
}
}
}
newCategory.setCompleted(oldPercentageCategory.getCompleted());
newCategory.setPlanTotal(oldPercentageCategory.getPlanTotal());
newCategory.setIsDelay(oldPercentageCategory.getIsDelay());
newCategory.setStatus(oldPercentageCategory.getStatus());
}
newCategory.setTotal(BigDecimal.valueOf(100));
FacPercentageFacility percentageFacility = new FacPercentageFacility();
percentageFacility.setProjectId(projectId);
percentageFacility.setMatrixId(matrixId);
percentageFacility.setMatrixId(matrix.getId());
percentageFacility.setProgressCategoryId(newId);
percentageFacility.setProgressCategoryName(template.getName());
percentageFacilityList.add(percentageFacility);
@ -380,10 +456,31 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
}
newList.addAll(localList);
}
// 删除旧进度类别
LambdaQueryWrapper<PgsProgressCategory> lqw = new LambdaQueryWrapper<>();
lqw.eq(PgsProgressCategory::getProjectId, projectId);
long oldCategoryCount = this.count(lqw);
if (oldCategoryCount > 0) {
boolean remove = this.remove(lqw);
if (!remove) {
throw new ServiceException("删除旧进度类别失败", HttpStatus.ERROR);
}
}
// 批量保存新进度类别
boolean result = this.saveBatch(newList);
if (!result) {
throw new ServiceException("创建进度类别失败", HttpStatus.ERROR);
}
// 删除旧数据
LambdaQueryWrapper<FacPercentageFacility> percentageFacilityLqw = new LambdaQueryWrapper<>();
percentageFacilityLqw.eq(FacPercentageFacility::getMatrixId, oldMatrixIdList);
long count = percentageFacilityService.count(percentageFacilityLqw);
if (count > 0) {
boolean remove = percentageFacilityService.remove(percentageFacilityLqw);
if (!remove) {
throw new ServiceException("删除旧百分比设施数据失败", HttpStatus.ERROR);
}
}
// 保存百分比设施
if (CollUtil.isNotEmpty(percentageFacilityList)) {
boolean save = percentageFacilityService.saveBatch(percentageFacilityList);
@ -391,6 +488,20 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
throw new ServiceException("创建设施失败", HttpStatus.ERROR);
}
}
// 修改百分比设施计划
if (CollUtil.isNotEmpty(newPlanList)) {
boolean save = progressPlanService.updateBatchById(newPlanList);
if (!save) {
throw new ServiceException("修改设施计划失败", HttpStatus.ERROR);
}
}
// 修改百分比设施计划详情
if (CollUtil.isNotEmpty(newPlanDetailList)) {
boolean save = progressPlanDetailService.updateBatchById(newPlanDetailList);
if (!save) {
throw new ServiceException("修改设施计划详情失败", HttpStatus.ERROR);
}
}
return true;
}
@ -515,7 +626,7 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
List<Long> subProjectIdList = subProjectList.stream().map(BusProject::getId).toList();
// 获取方阵信息
List<FacMatrix> matrixList = matrixService.lambdaQuery()
.select(FacMatrix::getId)
.select(FacMatrix::getId, FacMatrix::getProjectId)
.in(FacMatrix::getProjectId, subProjectIdList)
.list();
if (CollUtil.isEmpty(matrixList)) {
@ -527,7 +638,12 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
.collect(Collectors.groupingBy(FacMatrix::getProjectId));
// 获取每个方阵下的进度类别信息
List<PgsProgressCategory> progressCategoryList = this.lambdaQuery()
.select(PgsProgressCategory::getId, PgsProgressCategory::getStatus, PgsProgressCategory::getMatrixId)
.select(PgsProgressCategory::getId,
PgsProgressCategory::getStatus,
PgsProgressCategory::getMatrixId,
PgsProgressCategory::getTotal,
PgsProgressCategory::getPlanTotal,
PgsProgressCategory::getCompleted)
.in(PgsProgressCategory::getMatrixId, matrixIdList)
.list();
// 分组matrixId -> categoryList
@ -573,6 +689,7 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
// 构建子项目VO
PgsProgressCategorySubProjectVo subProjectVo = new PgsProgressCategorySubProjectVo();
subProjectVo.setSubProjectId(subProjectId);
subProjectVo.setName(subProject.getProjectName());
subProjectVo.setTotal(total);
subProjectVo.setCompleted(completed);
subProjectVo.setPlanTotal(planTotal);
@ -588,6 +705,7 @@ public class PgsProgressCategoryServiceImpl extends ServiceImpl<PgsProgressCateg
// 构建项目VO
PgsProgressCategoryProjectVo projectVo = new PgsProgressCategoryProjectVo();
projectVo.setProjectId(projectId);
projectVo.setName(project.getProjectName());
projectVo.setTotal(totalAll);
projectVo.setCompleted(completedAll);
projectVo.setPlanTotal(planTotalAll);

View File

@ -248,9 +248,10 @@ public class PgsProgressPlanDetailServiceImpl extends ServiceImpl<PgsProgressPla
}
Long number = progressPlanDetail.getFinishedNumber();
Long finishedNumberTotal = progressPlan.getFinishedNumber();
if (finishedNumberTotal + finishedNumber > progressPlan.getPlanNumber()) {
// todo 是否判断完成百分比是否大于计划进度
/* if (finishedNumberTotal + finishedNumber > progressPlan.getPlanNumber()) {
throw new ServiceException("完成百分比不能大于计划进度", HttpStatus.BAD_REQUEST);
}
}*/
progressPlanDetail.setFinishedNumber(finishedNumber);
// 更新
boolean update = this.updateById(progressPlanDetail);

View File

@ -61,6 +61,16 @@ public class BusProjectController extends BaseController {
return R.ok(projectService.querySubList(id));
}
/**
* 查询项目下的子项目方阵列表
*/
@SaCheckPermission("project:project:list")
@GetMapping("/list/sub/matrix/{id}")
public R<List<BusSubProjectMatrixVo>> listSubProjectMatrix(@NotNull(message = "项目id不能为空")
@PathVariable Long id) {
return R.ok(projectService.querySubProjectMatrixList(id));
}
/**
* 导出项目列表
*/

View File

@ -0,0 +1,35 @@
package org.dromara.project.domain.vo.project;
import lombok.Data;
import org.dromara.facility.domain.vo.matrix.FacMatrixBySubProjectVo;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* @author lcj
* @date 2025/6/10 15:06
*/
@Data
public class BusSubProjectMatrixVo implements Serializable {
@Serial
private static final long serialVersionUID = 5817777295498328412L;
/**
* id
*/
private Long projectId;
/**
* 项目名称
*/
private String name;
/**
* 方阵列表
*/
private List<FacMatrixBySubProjectVo> children;
}

View File

@ -56,6 +56,14 @@ public interface IBusProjectService extends IService<BusProject> {
*/
List<BusSubProjectVo> querySubList(Long id);
/**
* 获取项目子项目方阵信息
*
* @param id 项目id
* @return 子项目方阵信息列表
*/
List<BusSubProjectMatrixVo> querySubProjectMatrixList(Long id);
/**
* 查询当前登录用户项目列表以及项目列表下的分包公司列表
*

View File

@ -26,6 +26,9 @@ import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.facility.domain.FacMatrix;
import org.dromara.facility.domain.vo.matrix.FacMatrixBySubProjectVo;
import org.dromara.facility.service.IFacMatrixService;
import org.dromara.manager.weathermanager.WeatherConstant;
import org.dromara.manager.weathermanager.WeatherManager;
import org.dromara.project.constant.BusProjectConstant;
@ -82,6 +85,10 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
@Resource
private StringRedisTemplate stringRedisTemplate;
@Lazy
@Resource
private IFacMatrixService matrixService;
private final Cache<String, String> WEATHER_CACHE =
Caffeine.newBuilder().initialCapacity(1024)
.maximumSize(10000L)
@ -164,6 +171,62 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
}).toList();
}
/**
* 获取项目子项目方阵信息
*
* @param id 项目id
* @return 子项目方阵信息列表
*/
@Override
public List<BusSubProjectMatrixVo> querySubProjectMatrixList(Long id) {
// 获取项目信息
BusProject project = this.getById(id);
if (project == null) {
throw new ServiceException("查询项目不存在", HttpStatus.NOT_FOUND);
}
// 获取项目下的子项目信息
List<BusProject> subProjectList = this.lambdaQuery()
.select(BusProject::getId, BusProject::getProjectName)
.eq(BusProject::getPId, id)
.list();
if (CollUtil.isEmpty(subProjectList)) {
return List.of();
}
List<Long> subProjectIdList = subProjectList.stream().map(BusProject::getId).toList();
// 获取方阵信息
List<FacMatrix> matrixList = matrixService.lambdaQuery()
.select(FacMatrix::getId, FacMatrix::getProjectId, FacMatrix::getMatrixName)
.in(FacMatrix::getProjectId, subProjectIdList)
.list();
if (CollUtil.isEmpty(matrixList)) {
return subProjectList.stream().map(subProject -> {
BusSubProjectMatrixVo vo = new BusSubProjectMatrixVo();
vo.setProjectId(subProject.getId());
vo.setName(subProject.getProjectName());
vo.setChildren(List.of());
return vo;
}).toList();
}
// 获取子项目下的方阵信息
Map<Long, List<FacMatrix>> matrixMap = matrixList.stream()
.collect(Collectors.groupingBy(FacMatrix::getProjectId));
return subProjectList.stream().map(subProject -> {
BusSubProjectMatrixVo vo = new BusSubProjectMatrixVo();
vo.setProjectId(subProject.getId());
vo.setName(subProject.getProjectName());
if (matrixMap.containsKey(subProject.getId())) {
List<FacMatrix> subProjectMatrix = matrixMap.get(subProject.getId());
vo.setChildren(subProjectMatrix.stream().map(matrix -> {
FacMatrixBySubProjectVo matrixVo = new FacMatrixBySubProjectVo();
matrixVo.setMatrixId(matrix.getId());
matrixVo.setName(matrix.getMatrixName());
return matrixVo;
}).toList());
}
return vo;
}).toList();
}
/**
* 查询当前登录用户项目列表以及项目列表下的分包公司列表
*
@ -520,7 +583,7 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
}
// 关联子项目
List<BusSubProjectVo> subProjectVoList = new ArrayList<>();
if (subProjectMap.containsKey(project.getId())){
if (subProjectMap.containsKey(project.getId())) {
subProjectVoList = subProjectMap.get(project.getId()).stream().map(subProject -> {
BusSubProjectVo subProjectVo = new BusSubProjectVo();
BeanUtils.copyProperties(subProject, subProjectVo);
@ -542,10 +605,10 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
*/
@Override
public void validAuth(Long projectId, Long userId) {
QueryWrapper<BusUserProjectRelevancy> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("project_id", projectId);
queryWrapper.eq("user_id", userId);
if (userProjectRelevancyService.count(queryWrapper) <= 0) {
LambdaQueryWrapper<BusUserProjectRelevancy> lqw = new LambdaQueryWrapper<>();
lqw.eq(BusUserProjectRelevancy::getProjectId, projectId);
lqw.eq(BusUserProjectRelevancy::getUserId, userId);
if (userProjectRelevancyService.count(lqw) <= 0) {
throw new ServiceException("当前用户无该项目权限操作", HttpStatus.FORBIDDEN);
}
}

View File

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

View File

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

View File

@ -497,3 +497,43 @@ values(1927984223038324742, '进度类别模版删除', 1927984223038324738, '4'
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1927984223038324743, '进度类别模版导出', 1927984223038324738, '5', '#', '', 1, 0, 'F', '0', '0', 'progress:progressCategoryTemplate:export', '#', 103, 1, sysdate(), null, null, '');
-- 菜单 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933345067448147969, '萤石摄像头', '1933341785996664834', '1', 'ys7Device', 'other/ys7Device/index', 1, 0, 'C', '0', '0', 'other:ys7Device:list', '#', 103, 1, sysdate(), null, null, '萤石摄像头菜单');
-- 按钮 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933345067448147970, '萤石摄像头查询', 1933345067448147969, '1', '#', '', 1, 0, 'F', '0', '0', 'other:ys7Device:query', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933345067448147971, '萤石摄像头新增', 1933345067448147969, '2', '#', '', 1, 0, 'F', '0', '0', 'other:ys7Device:add', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933345067448147972, '萤石摄像头修改', 1933345067448147969, '3', '#', '', 1, 0, 'F', '0', '0', 'other:ys7Device:edit', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933345067448147973, '萤石摄像头删除', 1933345067448147969, '4', '#', '', 1, 0, 'F', '0', '0', 'other:ys7Device:remove', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933345067448147974, '萤石摄像头导出', 1933345067448147969, '5', '#', '', 1, 0, 'F', '0', '0', 'other:ys7Device:export', '#', 103, 1, sysdate(), null, null, '');
-- 菜单 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933445976098406401, '摄像头预置位', '1933345067448147969', '1', 'devicePreset', 'other/devicePreset/index', 1, 0, 'C', '0', '0', 'other:devicePreset:list', '#', 103, 1, sysdate(), null, null, '摄像头预置位菜单');
-- 按钮 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933445976098406402, '摄像头预置位查询', 1933445976098406401, '1', '#', '', 1, 0, 'F', '0', '0', 'other:devicePreset:query', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933445976098406403, '摄像头预置位新增', 1933445976098406401, '2', '#', '', 1, 0, 'F', '0', '0', 'other:devicePreset:add', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933445976098406404, '摄像头预置位修改', 1933445976098406401, '3', '#', '', 1, 0, 'F', '0', '0', 'other:devicePreset:edit', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933445976098406405, '摄像头预置位删除', 1933445976098406401, '4', '#', '', 1, 0, 'F', '0', '0', 'other:devicePreset:remove', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1933445976098406406, '摄像头预置位导出', 1933445976098406401, '5', '#', '', 1, 0, 'F', '0', '0', 'other:devicePreset:export', '#', 103, 1, sysdate(), null, null, '');

View File

@ -34,7 +34,7 @@ create table `bus_project`
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci comment = '项目表'
collate = utf8mb4_general_ci comment = '项目表'
ROW_FORMAT = DYNAMIC;
DROP TABLE IF EXISTS bus_user_project_relevancy;
@ -52,7 +52,7 @@ CREATE TABLE `bus_user_project_relevancy`
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id'
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci comment = '系统用户与项目关联表'
collate = utf8mb4_general_ci comment = '系统用户与项目关联表'
ROW_FORMAT = DYNAMIC;
DROP TABLE IF EXISTS mat_company;
@ -74,7 +74,7 @@ CREATE TABLE `mat_company`
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id'
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci comment = '公司表'
collate = utf8mb4_general_ci comment = '公司表'
ROW_FORMAT = DYNAMIC;
DROP TABLE IF EXISTS mat_materials;
@ -101,7 +101,7 @@ CREATE TABLE `mat_materials`
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id'
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci comment = '材料名称表'
collate = utf8mb4_general_ci comment = '材料名称表'
ROW_FORMAT = DYNAMIC;
DROP TABLE IF EXISTS mat_materials_inventory;
@ -130,7 +130,7 @@ CREATE TABLE `mat_materials_inventory`
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目ID'
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci comment = '材料出/入库表'
collate = utf8mb4_general_ci comment = '材料出/入库表'
ROW_FORMAT = DYNAMIC;
DROP TABLE IF EXISTS `bus_contractor`;
@ -152,7 +152,7 @@ CREATE TABLE `bus_contractor`
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci comment = '分包单位'
collate = utf8mb4_general_ci comment = '分包单位'
ROW_FORMAT = DYNAMIC;
DROP TABLE IF EXISTS `bus_construction_user`;
@ -195,7 +195,7 @@ CREATE TABLE `bus_construction_user`
INDEX `idx_phone` (`phone` ASC) USING BTREE comment '电话'
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci comment = '施工人员表'
collate = utf8mb4_general_ci comment = '施工人员表'
ROW_FORMAT = DYNAMIC;
DROP TABLE IF EXISTS `bus_project_team`;
@ -216,7 +216,7 @@ CREATE TABLE `bus_project_team`
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id'
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci comment = '项目班组'
collate = utf8mb4_general_ci comment = '项目班组'
ROW_FORMAT = DYNAMIC;
DROP TABLE IF EXISTS `bus_project_team_member`;
@ -334,7 +334,7 @@ CREATE TABLE `bus_safety_inspection`
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE
) comment = '安全巡检工单' COLLATE = utf8mb4_unicode_ci;
) comment = '安全巡检工单' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS hse_safety_log;
CREATE TABLE `bus_safety_log`
@ -440,7 +440,7 @@ CREATE TABLE `hse_question_user_answer`
`deleted_at` datetime null comment '删除时间',
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
PRIMARY KEY (`id`) USING BTREE
) comment = '用户试卷存储' COLLATE = utf8mb4_unicode_ci;
) comment = '用户试卷存储' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `bus_attendance`;
CREATE TABLE `bus_attendance`
@ -471,7 +471,7 @@ CREATE TABLE `bus_attendance`
INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '人员id',
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id',
INDEX `idx_clock_date` (`clock_date` ASC) USING BTREE comment '打卡日期'
) comment = '考勤表' COLLATE = utf8mb4_unicode_ci;
) comment = '考勤表' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `bus_work_wage`;
CREATE TABLE `bus_work_wage`
@ -493,7 +493,7 @@ CREATE TABLE `bus_work_wage`
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id',
INDEX `idx_work_type` (`work_type` ASC) USING BTREE comment '工种'
) comment = '工种薪水' COLLATE = utf8mb4_unicode_ci;
) comment = '工种薪水' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `bus_construction_blacklist`;
CREATE TABLE `bus_construction_blacklist`
@ -540,7 +540,7 @@ CREATE TABLE `bus_construction_user_exit`
INDEX `idx_user_id` (`user_id` ASC) USING BTREE comment '用户id',
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id',
INDEX `idx_team_id` (`team_id` ASC) USING BTREE comment '班组id'
) comment = '施工人员入场退场记录信息' COLLATE = utf8mb4_unicode_ci;
) comment = '施工人员入场退场记录信息' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `bus_reissue_card`;
CREATE TABLE `bus_reissue_card`
@ -677,7 +677,7 @@ CREATE TABLE `hse_document_safety_meeting`
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_pid` (`pid` ASC) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE
) comment = '安全会议纪要' COLLATE = utf8mb4_unicode_ci;
) comment = '安全会议纪要' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS hse_questions_category;
CREATE TABLE `hse_questions_category`
@ -689,7 +689,7 @@ CREATE TABLE `hse_questions_category`
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE
) comment = '题库类别' COLLATE = utf8mb4_unicode_ci;
) comment = '题库类别' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS qlt_quality_inspection;
CREATE TABLE `qlt_quality_inspection`
@ -721,7 +721,7 @@ CREATE TABLE `qlt_quality_inspection`
PRIMARY KEY (`id`) USING BTREE,
INDEX `project_id` (`project_id` ASC) USING BTREE,
INDEX `team_id` (`team_id` ASC) USING BTREE
) comment = '质量-检查工单' COLLATE = utf8mb4_unicode_ci;
) comment = '质量-检查工单' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS qlt_quality_construction_log;
CREATE TABLE `qlt_quality_construction_log`
@ -741,7 +741,7 @@ CREATE TABLE `qlt_quality_construction_log`
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE
) comment = '质量-施工日志' COLLATE = utf8mb4_unicode_ci;
) comment = '质量-施工日志' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `app_user`;
CREATE TABLE `app_user`
@ -762,7 +762,7 @@ CREATE TABLE `app_user`
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `idx_user_account` (`user_account` ASC) USING BTREE,
UNIQUE INDEX `idx_phone` (`phone` ASC) USING BTREE
) comment = 'app用户表' COLLATE = utf8mb4_unicode_ci;
) comment = 'app用户表' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `user_relevancy`;
CREATE TABLE `user_relevancy`
@ -773,7 +773,7 @@ CREATE TABLE `user_relevancy`
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_app_id` (`app_id` ASC) USING BTREE,
INDEX `idx_web_id` (`web_id` ASC) USING BTREE
) comment = '用户关联表' COLLATE = utf8mb4_unicode_ci;
) comment = '用户关联表' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `fac_matrix`;
CREATE TABLE `fac_matrix`
@ -791,7 +791,7 @@ CREATE TABLE `fac_matrix`
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id'
) comment = '设施-方阵' COLLATE = utf8mb4_unicode_ci;
) comment = '设施-方阵' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `fac_photovoltaic_panel`;
CREATE TABLE `fac_photovoltaic_panel`
@ -813,7 +813,7 @@ CREATE TABLE `fac_photovoltaic_panel`
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE,
INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE
) comment = '设施-光伏板' COLLATE = utf8mb4_unicode_ci;
) comment = '设施-光伏板' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `fac_photovoltaic_panel_point`;
CREATE TABLE `fac_photovoltaic_panel_point`
@ -835,7 +835,7 @@ CREATE TABLE `fac_photovoltaic_panel_point`
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE,
INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE
) comment = '设施-光伏板桩点' COLLATE = utf8mb4_unicode_ci;
) comment = '设施-光伏板桩点' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `fac_photovoltaic_panel_column`;
CREATE TABLE `fac_photovoltaic_panel_column`
@ -857,7 +857,7 @@ CREATE TABLE `fac_photovoltaic_panel_column`
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE,
INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE
) comment = '设施-光伏板立柱' COLLATE = utf8mb4_unicode_ci;
) comment = '设施-光伏板立柱' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `fac_photovoltaic_panel_support`;
CREATE TABLE `fac_photovoltaic_panel_support`
@ -879,7 +879,7 @@ CREATE TABLE `fac_photovoltaic_panel_support`
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE,
INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE
) comment = '设施-光伏板支架' COLLATE = utf8mb4_unicode_ci;
) comment = '设施-光伏板支架' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `fac_inverter`;
CREATE TABLE `fac_inverter`
@ -901,7 +901,7 @@ CREATE TABLE `fac_inverter`
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE,
INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE
) comment = '设施-逆变器' COLLATE = utf8mb4_unicode_ci;
) comment = '设施-逆变器' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `fac_box_transformer`;
CREATE TABLE `fac_box_transformer`
@ -923,7 +923,7 @@ CREATE TABLE `fac_box_transformer`
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE,
INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE
) comment = '设施-箱变' COLLATE = utf8mb4_unicode_ci;
) comment = '设施-箱变' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `bus_project_file`;
CREATE TABLE `bus_project_file`
@ -956,7 +956,7 @@ CREATE TABLE `bus_project_news`
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id'
) comment = '项目新闻' COLLATE = utf8mb4_unicode_ci;
) comment = '项目新闻' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `pgs_progress_category_template`;
CREATE TABLE `pgs_progress_category_template`
@ -971,7 +971,7 @@ CREATE TABLE `pgs_progress_category_template`
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_pid` (`pid` ASC) USING BTREE comment '父类别id',
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id'
) comment ='进度类别模版' COLLATE = utf8mb4_unicode_ci;
) comment ='进度类别模版' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `pgs_progress_category`;
CREATE TABLE `pgs_progress_category`
@ -997,7 +997,7 @@ CREATE TABLE `pgs_progress_category`
INDEX `idx_pid` (`pid` ASC) USING BTREE comment '父类别id',
INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE comment '方阵id',
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id'
) comment ='进度类别' COLLATE = utf8mb4_unicode_ci;
) comment ='进度类别' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `fac_percentage_facility`;
CREATE TABLE `fac_percentage_facility`
@ -1015,7 +1015,7 @@ CREATE TABLE `fac_percentage_facility`
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id',
INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE comment '方阵id',
INDEX `idx_progress_category_id` (`progress_category_id` ASC) USING BTREE comment '进度类别id'
) comment ='设施-百分比设施' COLLATE = utf8mb4_unicode_ci;
) comment ='设施-百分比设施' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `pgs_progress_plan`;
CREATE TABLE `pgs_progress_plan`
@ -1040,7 +1040,7 @@ CREATE TABLE `pgs_progress_plan`
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id',
INDEX `idx_matrix_id` (`matrix_id` ASC) USING BTREE comment '方阵id',
INDEX `idx_progress_category_id` (`progress_category_id` ASC) USING BTREE comment '进度类别id'
) comment ='进度计划' COLLATE = utf8mb4_unicode_ci;
) comment ='进度计划' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `pgs_progress_plan_detail`;
CREATE TABLE `pgs_progress_plan_detail`
@ -1064,4 +1064,43 @@ CREATE TABLE `pgs_progress_plan_detail`
INDEX `idx_project_id` (`project_id` ASC) USING BTREE comment '项目id',
INDEX `idx_progress_plan_id` (`progress_plan_id` ASC) USING BTREE comment '进度计划id',
INDEX `idx_date` (`date` ASC) USING BTREE comment '计划时间'
) comment ='进度计划详情' COLLATE = utf8mb4_unicode_ci;
) comment ='进度计划详情' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `oth_ys7_device`;
CREATE TABLE `oth_ys7_device`
(
`id` bigint not null auto_increment comment '主键id',
`project_id` bigint default 0 not null comment '项目id',
`device_serial` varchar(255) null comment '设备序列号',
`device_name` varchar(255) null comment '设备名称',
`device_type` varchar(255) null comment '设备型号',
`status` tinyint(4) null comment '设备在线状态(0离线 1在线)',
`defence` bigint null comment '布撤防状态',
`device_version` varchar(255) null comment '固件版本号',
`position` varchar(255) null comment '摄像头坐标信息',
`device_create_time` datetime null comment '设备添加时间',
`device_update_time` datetime null comment '设备最后更新时间',
`risk_level` int null comment '设备风险安全等级(0安全 大于0值越大风险越高)',
`video_encrypted` tinyint(4) default 0 not null comment '视频加密(0关闭 1开启)',
`remark` varchar(512) null comment '备注',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
`deleted_at` datetime null comment '删除时间',
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
primary key (`id`) using btree,
index `idx_project_id` (`project_id` asc) using btree comment '项目id',
unique index `idx_device_serial` (`device_serial` asc) using btree comment '设备序列号'
) comment = '萤石摄像头' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `oth_device_preset`;
CREATE TABLE `oth_device_preset`
(
`id` bigint not null auto_increment comment '主键id',
`device_serial` varchar(255) null comment '设备序列号',
`channel_no` bigint null comment '通道号',
`index` int null comment '预置点序号',
`name` varchar(255) null comment '预置点',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
primary key (`id`) using btree
) comment = '摄像头预置位' collate = utf8mb4_unicode_ci;