From 2708a02588504263281a3295e7ad3c31ade029e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=95=E5=BE=B7=E8=B6=85?= <13143889+he-dechao@user.noreply.gitee.com> Date: Tue, 12 Aug 2025 17:20:09 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=87=80=E7=A9=BA=E5=BD=A2=E5=8F=98?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E7=9B=91=E6=B5=8B=E5=90=8E=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/dite/znpt/config/TaskConfig.java | 24 +++ .../domain/entity/VideoMonitorEntity.java | 170 ++++++++++++++++ .../com/dite/znpt/domain/vo/VideoReq.java | 29 +++ .../com/dite/znpt/enums/VideoMonitorEnum.java | 45 +++++ .../znpt/mapper/VideoMonitorEntityMapper.java | 12 ++ .../znpt/service/VideoMonitorService.java | 60 ++++++ .../dite/znpt/service/impl/ClearanceTask.java | 51 +++++ .../service/impl/VideoMonitorServiceImpl.java | 181 ++++++++++++++++++ .../java/com/dite/znpt/util/PythonUtil.java | 49 +++++ .../resources/mapper/VideoMonitorMapper.xml | 53 +++++ .../controller/VideoMonitorController.java | 77 ++++++++ 11 files changed, 751 insertions(+) create mode 100644 core/src/main/java/com/dite/znpt/config/TaskConfig.java create mode 100644 core/src/main/java/com/dite/znpt/domain/entity/VideoMonitorEntity.java create mode 100644 core/src/main/java/com/dite/znpt/domain/vo/VideoReq.java create mode 100644 core/src/main/java/com/dite/znpt/enums/VideoMonitorEnum.java create mode 100644 core/src/main/java/com/dite/znpt/mapper/VideoMonitorEntityMapper.java create mode 100644 core/src/main/java/com/dite/znpt/service/VideoMonitorService.java create mode 100644 core/src/main/java/com/dite/znpt/service/impl/ClearanceTask.java create mode 100644 core/src/main/java/com/dite/znpt/service/impl/VideoMonitorServiceImpl.java create mode 100644 core/src/main/java/com/dite/znpt/util/PythonUtil.java create mode 100644 core/src/main/resources/mapper/VideoMonitorMapper.xml create mode 100644 web/src/main/java/com/dite/znpt/web/controller/VideoMonitorController.java diff --git a/core/src/main/java/com/dite/znpt/config/TaskConfig.java b/core/src/main/java/com/dite/znpt/config/TaskConfig.java new file mode 100644 index 0000000..2726c63 --- /dev/null +++ b/core/src/main/java/com/dite/znpt/config/TaskConfig.java @@ -0,0 +1,24 @@ +package com.dite.znpt.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +/** + * @author hedechao + * @date 2025/8/11 11:02 + * @Description: 形变配置线程 + */ +@Configuration +public class TaskConfig { + @Bean("clearanceExecutor") // 方法返回的对象会被注册成 Bean,名字叫 clearanceExecutor + public ThreadPoolTaskExecutor clearanceExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(2); // 核心线程数 + executor.setMaxPoolSize(4); // 最大线程数 + executor.setQueueCapacity(100); // 队列容量 + executor.setThreadNamePrefix("clearance-"); // 线程名前缀 + executor.initialize(); // 初始化 + return executor; + } +} diff --git a/core/src/main/java/com/dite/znpt/domain/entity/VideoMonitorEntity.java b/core/src/main/java/com/dite/znpt/domain/entity/VideoMonitorEntity.java new file mode 100644 index 0000000..d289d9a --- /dev/null +++ b/core/src/main/java/com/dite/znpt/domain/entity/VideoMonitorEntity.java @@ -0,0 +1,170 @@ +package com.dite.znpt.domain.entity; + +import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serializable; +import java.util.Date; +import lombok.Data; + +/** + * 视频监测信息 + */ +@ApiModel(description="视频监测信息") +@Schema(description="视频监测信息") +@Data +@TableName(value = "video_monitor") +public class VideoMonitorEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 视频id + */ + @TableId(value = "video_id", type = IdType.ASSIGN_UUID) + @ApiModelProperty(value="视频id") + @Schema(description="视频id") + private String videoId; + + /** + * 项目id + */ + @TableField(value = "project_id") + @ApiModelProperty(value="项目id") + @Schema(description="项目id") + private String projectId; + + /** + * 机组id + */ + @TableField(value = "turbine_id") + @ApiModelProperty(value="机组id") + @Schema(description="机组id") + private String turbineId; + + /** + * 视频名称 + */ + @TableField(value = "video_name") + @ApiModelProperty(value="视频名称") + @Schema(description="视频名称") + private String videoName; + + /** + * 视频路径 + */ + @TableField(value = "video_path") + @ApiModelProperty(value="视频路径") + @Schema(description="视频路径") + private String videoPath; + + /** + * 0 正常 1 已删除 + */ + @TableField(value = "is_deleted") + @ApiModelProperty(value="0 正常 1 已删除") + @Schema(description="0 正常 1 已删除") + private Boolean isDeleted; + + /** + * 0 待审核 1 已上线 2 下线 + */ + @TableField(value = "`status`") + @ApiModelProperty(value="0 待审核 1 已上线 2 下线") + @Schema(description="0 待审核 1 已上线 2 下线") + private Byte status; + + /** + * 预处理后的视频路径 + */ + @TableField(value = "pre_image_path") + @ApiModelProperty(value="预处理后的视频路径") + @Schema(description="预处理后的视频路径") + private String preImagePath; + + /** + * 是否处理,默认0 + */ + @TableField(value = "pre_treatment") + @ApiModelProperty(value="是否处理,默认0") + @Schema(description="是否处理,默认0") + private Boolean preTreatment; + + /** + * 修改人 + */ + @TableField(value = "update_by") + @ApiModelProperty(value="修改人") + @Schema(description="修改人") + private String updateBy; + + /** + * 创建时间 + */ + @TableField(value = "create_time",fill = FieldFill.INSERT) + @ApiModelProperty(value="创建时间") + @Schema(description="创建时间") + private Date createTime; + + /** + * 创建人 + */ + @TableField(value = "create_by") + @ApiModelProperty(value="创建人") + @Schema(description="创建人") + private String createBy; + + /** + * 修改时间 + */ + @TableField(value = "update_time",fill = FieldFill.INSERT_UPDATE) + @ApiModelProperty(value="修改时间") + @Schema(description="修改时间") + private Date updateTime; + + /** + * 风速 + */ + @TableField(value = "wind_speed") + @ApiModelProperty(value="风速") + @Schema(description="风速") + private String windSpeed; + + /** + * 转速 + */ + @TableField(value = "rpm") + @ApiModelProperty(value="转速") + @Schema(description="转速") + private String rpm; + + /** + * 检测类型 + */ + @TableField(value = "`type`") + @ApiModelProperty(value="检测类型") + @Schema(description="检测类型") + private String type; + + /** + * 业务扩展字段 + */ + @TableField(value = "extra",typeHandler = JacksonTypeHandler.class) + @ApiModelProperty(value="业务扩展字段") + @Schema(description="业务扩展字段") + private JSONObject extra; + + /** + * 上传时间 + */ + @TableField(value = "upload_time") + @ApiModelProperty(value="上传时间") + @Schema(description="上传时间") + private Date uploadTime; +} \ No newline at end of file diff --git a/core/src/main/java/com/dite/znpt/domain/vo/VideoReq.java b/core/src/main/java/com/dite/znpt/domain/vo/VideoReq.java new file mode 100644 index 0000000..1b146e2 --- /dev/null +++ b/core/src/main/java/com/dite/znpt/domain/vo/VideoReq.java @@ -0,0 +1,29 @@ +package com.dite.znpt.domain.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * @author hedechao + * @date 2025/8/8 09:10 + * @Description: + */ +@Data +@ApiModel("视频列表查询实体") +public class VideoReq implements Serializable { + @Serial + private static final long serialVersionUID = 771014582625089979L; + @ApiModelProperty("项目id") + private String projectId; + @ApiModelProperty("视频类型") + private String[] type; + @ApiModelProperty("机组id") + private String turbineId; + @ApiModelProperty("是否已审核,0未审核,1已审核") + private Boolean State; +} + diff --git a/core/src/main/java/com/dite/znpt/enums/VideoMonitorEnum.java b/core/src/main/java/com/dite/znpt/enums/VideoMonitorEnum.java new file mode 100644 index 0000000..4149417 --- /dev/null +++ b/core/src/main/java/com/dite/znpt/enums/VideoMonitorEnum.java @@ -0,0 +1,45 @@ +package com.dite.znpt.enums; + +import cn.hutool.json.JSONObject; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +public enum VideoMonitorEnum { + CLEARANCE("clearance","净空监测"), + DEFORMATION("deformation","形变监测"); + + private final String code; + private final String desc; + + VideoMonitorEnum(String code, String desc) { + this.code = code; + this.desc = desc; + } + + public static VideoMonitorEnum getByCode(String code) { + for (VideoMonitorEnum e : VideoMonitorEnum.values()) { + if (e.code.equals(code)) { + return e; + } + } + return null; + } + + public static String getDescByCode(String code) { + VideoMonitorEnum e = getByCode(code); + return null == e ? null : e.desc; + } + + public static List listAll() { + List list = new ArrayList<>(UserStatusEnum.values().length); + for (VideoMonitorEnum e : VideoMonitorEnum.values()) { + JSONObject jsonObject = new JSONObject(); + jsonObject.set(e.code, e.desc); + list.add(jsonObject); + } + return list; + } +} diff --git a/core/src/main/java/com/dite/znpt/mapper/VideoMonitorEntityMapper.java b/core/src/main/java/com/dite/znpt/mapper/VideoMonitorEntityMapper.java new file mode 100644 index 0000000..831e9a3 --- /dev/null +++ b/core/src/main/java/com/dite/znpt/mapper/VideoMonitorEntityMapper.java @@ -0,0 +1,12 @@ +package com.dite.znpt.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.dite.znpt.domain.entity.VideoMonitorEntity; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +public interface VideoMonitorEntityMapper extends BaseMapper { + List selectAllByProjectIdAndPartId(@Param("projectId") String projectId, @Param("partId") String partId); + + int batchInsert(@Param("list") List list); +} \ No newline at end of file diff --git a/core/src/main/java/com/dite/znpt/service/VideoMonitorService.java b/core/src/main/java/com/dite/znpt/service/VideoMonitorService.java new file mode 100644 index 0000000..6ef70bb --- /dev/null +++ b/core/src/main/java/com/dite/znpt/service/VideoMonitorService.java @@ -0,0 +1,60 @@ +package com.dite.znpt.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.dite.znpt.domain.PageResult; +import com.dite.znpt.domain.entity.VideoMonitorEntity; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + +/** + *

+ * 视频信息 服务类 + *

+ * + * @author hdc + * @since 2025-08-07 + */ +public interface VideoMonitorService extends IService { + /** + * 批量上传视频 + */ + List uploadBatch(String projectId, + String partId, + String type, + MultipartFile[] files) throws IOException; + + /** + * 单文件上传 + */ + VideoMonitorEntity upload(String projectId, + String partId, + String type, + MultipartFile file) throws IOException; + + /** + * 分页列表 + */ + PageResult page(Integer pageNo, + Integer pageSize, + String projectId, + String partId); + + /** + * 列表 + */ + List list(String projectId, String partId); + + /** + * 删除 + */ + void delete(String videoId); + + /** + * 下载/播放 + */ + void download(String videoId, HttpServletResponse response) throws IOException; + +} diff --git a/core/src/main/java/com/dite/znpt/service/impl/ClearanceTask.java b/core/src/main/java/com/dite/znpt/service/impl/ClearanceTask.java new file mode 100644 index 0000000..1990405 --- /dev/null +++ b/core/src/main/java/com/dite/znpt/service/impl/ClearanceTask.java @@ -0,0 +1,51 @@ +package com.dite.znpt.service.impl; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.dite.znpt.domain.entity.VideoMonitorEntity; +import com.dite.znpt.enums.FilePathEnum; +import com.dite.znpt.util.PythonUtil; +import lombok.RequiredArgsConstructor; + +import java.io.File; +import java.nio.charset.StandardCharsets; + +@RequiredArgsConstructor +public class ClearanceTask implements Runnable { + + private final String videoAbsolutePath; // 上传后的完整磁盘路径 + private final String outputDir; // 结果目录 + private final String videoId; // 数据库主键,用于更新状态 + private final VideoMonitorServiceImpl service; + + @Override + public void run() { + try { + // 1. 调用 Python(阻塞,但跑在子线程) + PythonUtil.runClearance(videoAbsolutePath,outputDir); + // 2. 更新数据库:status = 已完成 / 预处理成功 + VideoMonitorEntity update = new VideoMonitorEntity(); + update.setVideoId(videoId); + update.setPreTreatment(true); // 或自定义状态字段 + update.setPreImagePath(FilePathEnum.VIDEO.getFileDownPath(outputDir)); + File resultFile = new File(outputDir, "results.json"); + if (!resultFile.exists()) { + throw new IllegalStateException("results.json 不存在"); + } + String jsonStr = FileUtil.readString(resultFile, StandardCharsets.UTF_8); + + // 3. 转成 hutool 的 JSONObject(对应 MySQL 的 JSON 字段) + JSONObject jsonObj = JSONUtil.parseObj(jsonStr); + update.setExtra(jsonObj); + service.updateById(update); + + } catch (Exception e) { + // 失败时可将 status 置为失败 + VideoMonitorEntity update = new VideoMonitorEntity(); + update.setVideoId(videoId); + update.setStatus((byte) -1); // 自定义失败码 + service.updateById(update); + } + } +} diff --git a/core/src/main/java/com/dite/znpt/service/impl/VideoMonitorServiceImpl.java b/core/src/main/java/com/dite/znpt/service/impl/VideoMonitorServiceImpl.java new file mode 100644 index 0000000..f5aca30 --- /dev/null +++ b/core/src/main/java/com/dite/znpt/service/impl/VideoMonitorServiceImpl.java @@ -0,0 +1,181 @@ +package com.dite.znpt.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.dite.znpt.constant.Message; +import com.dite.znpt.domain.PageResult; +import com.dite.znpt.domain.entity.VideoMonitorEntity; +import com.dite.znpt.enums.FilePathEnum; +import com.dite.znpt.enums.VideoMonitorEnum; +import com.dite.znpt.exception.ServiceException; +import com.dite.znpt.mapper.VideoMonitorEntityMapper; +import com.dite.znpt.service.ProjectService; +import com.dite.znpt.service.TurbineService; +import com.dite.znpt.service.VideoMonitorService; +import com.google.common.collect.Lists; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.rmi.ServerException; +import java.util.Date; +import java.util.List; +import java.util.Objects; + +/** + *

+ * 视频信息 服务实现类 + *

+ * + * @author hdc + * @since 2025-08-07 + */ +@Service +public class VideoMonitorServiceImpl extends ServiceImpl implements VideoMonitorService { + @Resource + private TurbineService turbineService; + @Autowired + private ProjectService projectService; + @Resource(name = "clearanceExecutor") + private ThreadPoolTaskExecutor clearanceExecutor; + @Override + @Transactional(rollbackFor = Exception.class) + public List uploadBatch(String projectId, + String turbineId, + String type, + MultipartFile[] files) throws IOException { + if (files == null || files.length == 0) { + throw new ServiceException("上传文件为空"); + } + if (Objects.isNull(projectService.detail(projectId))) { + throw new ServiceException(Message.PROJECT_ID_IS_NOT_EXIST); + } + if (StrUtil.isNotBlank(turbineId) && turbineService.getById(turbineId) == null) { + throw new ServiceException(Message.PART_ID_IS_NOT_EXIST); + } + String userId = StpUtil.getLoginIdAsString(); + String dateStr = DateUtil.today(); + String storeDir = FilePathEnum.VIDEO.getFileAbsolutePathPrefix() + + projectId; + if (!turbineId.isEmpty() ) + storeDir+=File.separator+turbineId+ File.separator + dateStr; + else + storeDir+=File.separator + dateStr; + + FileUtil.mkdir(storeDir); + + List list = Lists.newArrayList(); + + for (MultipartFile file : files) { + String original = file.getOriginalFilename(); + String suffix = FileUtil.extName(original); + if (suffix != null && !suffix.equals("mp4")) throw new ServerException("非视频文件"); + String uuid = IdUtil.simpleUUID(); + String fileName = uuid + StrUtil.DOT + suffix; + String absolutePath = storeDir + File.separator + fileName; + + File dest = new File(absolutePath); + file.transferTo(dest); + + VideoMonitorEntity entity = new VideoMonitorEntity(); + entity.setVideoId(uuid); + entity.setProjectId(projectId); + entity.setTurbineId(turbineId); + entity.setVideoName(original); + entity.setVideoPath(FilePathEnum.VIDEO.getFileDownPath(absolutePath)); + entity.setType(type); + entity.setStatus((byte) 0); // 待审核 + entity.setPreTreatment(false); + entity.setIsDeleted(false); + entity.setCreateTime(new Date()); + entity.setUploadTime(new Date()); + entity.setUpdateBy(userId); + entity.setCreateBy(userId); + list.add(entity); + if (type.equals(VideoMonitorEnum.CLEARANCE.getCode())) + clearanceExecutor.execute( + new ClearanceTask(absolutePath, storeDir+File.separator+ type+File.separator+uuid, uuid, this) + ); + else if (type.equals(VideoMonitorEnum.DEFORMATION.getCode())) { + //TODO + } + } + + saveBatch(list); + return list; + } + + @Override + public VideoMonitorEntity upload(String projectId, + String partId, + String type, + MultipartFile file) throws IOException { + return uploadBatch(projectId, partId, type, new MultipartFile[]{file}).get(0); + } + + @Override + public PageResult page(Integer pageNo, + Integer pageSize, + String projectId, + String partId) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(StrUtil.isNotBlank(projectId),VideoMonitorEntity::getProjectId, projectId) + .eq(StrUtil.isNotBlank(partId), VideoMonitorEntity::getTurbineId, partId) + .orderByDesc(VideoMonitorEntity::getCreateTime); + Page page = page(Page.of(pageNo, pageSize), wrapper); + return PageResult.ok(page.getRecords(), page.getTotal()); + } + + @Override + public List list(String projectId, String partId) { + return lambdaQuery() + .eq(StrUtil.isNotBlank(projectId),VideoMonitorEntity::getProjectId, projectId) + .eq(StrUtil.isNotBlank(partId), VideoMonitorEntity::getTurbineId, partId) + .list(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(String videoId) { + VideoMonitorEntity entity = getById(videoId); + if (Objects.isNull(entity)) { + throw new ServiceException("视频不存在"); + } + entity.setIsDeleted(true); + entity.setUpdateBy(StpUtil.getLoginIdAsString()); + updateById(entity); + // 物理删除文件 + FileUtil.del(FilePathEnum.VIDEO.getFileAbsolutePath(entity.getVideoPath())); + } + + @Override + public void download(String videoId, HttpServletResponse response) throws IOException { + VideoMonitorEntity entity = getById(videoId); + if (entity == null || Boolean.TRUE.equals(entity.getIsDeleted())) { + throw new ServiceException("视频不存在或已删除"); + } + File file = new File(FilePathEnum.VIDEO.getFileAbsolutePath(entity.getVideoPath())); + if (!file.exists()) { + throw new ServiceException("视频文件不存在"); + } + response.setContentType("video/mp4"); + response.setHeader("Content-Disposition", + "inline; filename=" + URLEncoder.encode(entity.getVideoName(), StandardCharsets.UTF_8)); + FileUtil.writeToStream(file, response.getOutputStream()); + } +} diff --git a/core/src/main/java/com/dite/znpt/util/PythonUtil.java b/core/src/main/java/com/dite/znpt/util/PythonUtil.java new file mode 100644 index 0000000..a4329ea --- /dev/null +++ b/core/src/main/java/com/dite/znpt/util/PythonUtil.java @@ -0,0 +1,49 @@ +package com.dite.znpt.util; + +import cn.hutool.extra.spring.SpringUtil; +import org.springframework.core.env.Environment; + +import java.io.IOException; + +/** + * @author hedechao + * @Date 2025/8/11 09:04 + * @Description: 形变python脚本执行工具 + */ +public class PythonUtil { + /** + * 调用叶片净空计算脚本 + * + * @param videoPath 待检测视频路径 + * @throws IOException 如果启动进程失败 + * @throws InterruptedException 如果等待进程完成被中断 + */ + public static void runClearance( + String videoPath, + String outputPath + ) throws IOException, InterruptedException { + String pyScriptPath=SpringUtil.getBean(Environment.class).getProperty("pyScript.clearance"); + String modelPath=SpringUtil.getBean(Environment.class).getProperty("model.tip-hub"); + // 1. 构造命令 + ProcessBuilder pb = new ProcessBuilder( + "python", // 也可以是 python3 / 绝对路径 + pyScriptPath, + "--video_path=" + videoPath, + "--model_path=" + modelPath, + "--output_dir=" + outputPath + ); + + // 2. 把子进程的标准输出 / 错误流重定向到 Java 控制台(可选) + pb.redirectOutput(ProcessBuilder.Redirect.INHERIT); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); + + // 3. 启动进程并等待完成 + Process process = pb.start(); + int exitCode = process.waitFor(); + if (exitCode != 0) { + throw new RuntimeException("脚本返回非 0 状态码: " + exitCode); + } + + System.out.println("净空计算完成,结果已保存到: " + outputPath); + } +} diff --git a/core/src/main/resources/mapper/VideoMonitorMapper.xml b/core/src/main/resources/mapper/VideoMonitorMapper.xml new file mode 100644 index 0000000..9f6741e --- /dev/null +++ b/core/src/main/resources/mapper/VideoMonitorMapper.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + video_id, project_id, part_id, video_name, video_path, is_deleted, `status`, pre_image_path, + pre_treatment, update_by, create_time, create_by, update_time, wind_speed, rpm, `type`, + extra, upload_time + + + + + insert into video_monitor + (project_id, part_id, video_name, video_path, is_deleted, `status`, pre_image_path, + pre_treatment, update_by, create_time, create_by, update_time, wind_speed, rpm, + `type`, extra, upload_time) + values + + (#{item.projectId}, #{item.partId}, #{item.videoName}, #{item.videoPath}, #{item.isDeleted}, + #{item.status}, #{item.preImagePath}, #{item.preTreatment}, #{item.updateBy}, #{item.createTime}, + #{item.createBy}, #{item.updateTime}, #{item.windSpeed}, #{item.rpm}, #{item.type}, + #{item.extra}, #{item.uploadTime}) + + + \ No newline at end of file diff --git a/web/src/main/java/com/dite/znpt/web/controller/VideoMonitorController.java b/web/src/main/java/com/dite/znpt/web/controller/VideoMonitorController.java new file mode 100644 index 0000000..845fb61 --- /dev/null +++ b/web/src/main/java/com/dite/znpt/web/controller/VideoMonitorController.java @@ -0,0 +1,77 @@ +package com.dite.znpt.web.controller; + +import com.dite.znpt.domain.PageResult; +import com.dite.znpt.domain.Result; +import com.dite.znpt.domain.entity.VideoMonitorEntity; +import com.dite.znpt.service.VideoMonitorService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + +/** + * @author hedechao + * @date 2025/8/8 17:15 + * @Description: + */ +@Api(tags = "视频监测") +@RestController +@RequestMapping("/video-monitor") +@RequiredArgsConstructor +public class VideoMonitorController { +@Resource + VideoMonitorService videoService; + + @ApiOperation("分页查询") + @GetMapping("/page") + public PageResult page(@RequestParam(defaultValue = "1") Integer pageNo, + @RequestParam(defaultValue = "10") Integer pageSize, + @RequestParam String projectId, + @RequestParam(required = false) String turbineId) { + return videoService.page(pageNo, pageSize, projectId, turbineId); + } + + @ApiOperation("列表查询") + @GetMapping("/list") + public Result> list(@RequestParam(required = false) String projectId, + @RequestParam(required = false) String turbineId) { + return Result.ok(videoService.list(projectId, turbineId)); + } + + @ApiOperation("批量上传") + @PostMapping("/{projectId}/upload-batch") + public Result> uploadBatch(@PathVariable String projectId, + @RequestParam(required = false) String turbineId, + @RequestParam String type, + @RequestParam("files") MultipartFile[] files) throws IOException { + return Result.ok(videoService.uploadBatch(projectId, turbineId, type, files)); + } + + @ApiOperation("单文件上传") + @PostMapping("/{projectId}/upload") + public Result upload(@PathVariable String projectId, + @RequestParam(required = false) String turbineId, + @RequestParam String type, + @RequestParam("file") MultipartFile file) throws IOException { + return Result.ok(videoService.upload(projectId, turbineId, type, file)); + } + + @ApiOperation("删除") + @DeleteMapping("/{videoId}") + public Result delete(@PathVariable String videoId) { + videoService.delete(videoId); + return Result.ok(); + } + + @ApiOperation("下载/播放") + @GetMapping("/download/{videoId}") + public void download(@PathVariable String videoId, HttpServletResponse response) throws IOException { + videoService.download(videoId, response); + } +} From 19e9bb7978255689e2f16abaaabf86f03196ac35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=95=E5=BE=B7=E8=B6=85?= <13143889+he-dechao@user.noreply.gitee.com> Date: Tue, 12 Aug 2025 17:21:49 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=87=80=E7=A9=BA=E5=BD=A2=E5=8F=98?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E7=9B=91=E6=B5=8B=E5=90=8E=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/main/resources/mapper/VideoMonitorMapper.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/mapper/VideoMonitorMapper.xml b/core/src/main/resources/mapper/VideoMonitorMapper.xml index 9f6741e..37a7f78 100644 --- a/core/src/main/resources/mapper/VideoMonitorMapper.xml +++ b/core/src/main/resources/mapper/VideoMonitorMapper.xml @@ -44,7 +44,7 @@ `type`, extra, upload_time) values - (#{item.projectId}, #{item.partId}, #{item.videoName}, #{item.videoPath}, #{item.isDeleted}, + (#{item.projectId}, #{item.turbineId}, #{item.videoName}, #{item.videoPath}, #{item.isDeleted}, #{item.status}, #{item.preImagePath}, #{item.preTreatment}, #{item.updateBy}, #{item.createTime}, #{item.createBy}, #{item.updateTime}, #{item.windSpeed}, #{item.rpm}, #{item.type}, #{item.extra}, #{item.uploadTime}) From e19d8490459ba62a93dcc159fc14c56f7945d301 Mon Sep 17 00:00:00 2001 From: "Mr.j" <2221464500@qq.com> Date: Wed, 13 Aug 2025 09:28:41 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E6=9F=A5=E8=AF=A2=E8=A1=A8=E6=A0=BC=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E9=A1=BA=E5=88=A9=E4=B8=8B=E6=8B=89=E5=92=8C=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E6=9D=A1=E4=B8=8D=E5=9B=BA=E5=AE=9A=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/vo/EquipmentApprovalListReq.java | 3 ++ .../impl/EquipmentApprovalServiceImpl.java | 32 +++++++++++++--- .../service/impl/EquipmentServiceImpl.java | 38 +++++++++++++------ 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/com/dite/znpt/domain/vo/EquipmentApprovalListReq.java b/core/src/main/java/com/dite/znpt/domain/vo/EquipmentApprovalListReq.java index 39b5833..55cae55 100644 --- a/core/src/main/java/com/dite/znpt/domain/vo/EquipmentApprovalListReq.java +++ b/core/src/main/java/com/dite/znpt/domain/vo/EquipmentApprovalListReq.java @@ -43,6 +43,9 @@ public class EquipmentApprovalListReq implements Serializable { @ApiModelProperty("当前页码") private Integer page; + @ApiModelProperty("当前页码 - 与前端保持一致") + private Integer pageNum; + @ApiModelProperty("每页大小") private Integer pageSize; diff --git a/core/src/main/java/com/dite/znpt/service/impl/EquipmentApprovalServiceImpl.java b/core/src/main/java/com/dite/znpt/service/impl/EquipmentApprovalServiceImpl.java index 3ef83e0..99636dd 100644 --- a/core/src/main/java/com/dite/znpt/service/impl/EquipmentApprovalServiceImpl.java +++ b/core/src/main/java/com/dite/znpt/service/impl/EquipmentApprovalServiceImpl.java @@ -45,6 +45,12 @@ public class EquipmentApprovalServiceImpl implements EquipmentApprovalService { public IPage getPendingApprovals(EquipmentApprovalListReq req) { log.info("开始执行待审批设备分页查询,请求参数: {}", req); + // 获取分页参数 + Integer pageNum = req.getPageNum() != null ? req.getPageNum() : 1; + Integer pageSize = req.getPageSize() != null ? req.getPageSize() : 10; + + log.info("分页参数 - pageNum: {}, pageSize: {}", pageNum, pageSize); + // 使用分页插件 PageUtil.startPage(); @@ -63,10 +69,12 @@ public class EquipmentApprovalServiceImpl implements EquipmentApprovalService { .collect(Collectors.toList()); // 获取分页信息 - PageInfo pageInfo = new PageInfo<>(respList); + PageInfo pageInfo = new PageInfo<>(approvalList); + + log.info("待审批设备分页查询完成,共查询 {} 条记录,当前页码: {}, 总页码: {}", pageInfo.getTotal(), pageInfo.getPageNum(), pageInfo.getPages()); // 创建响应分页对象 - Page result = new Page<>(pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal()); + Page result = new Page<>(pageNum, pageSize, pageInfo.getTotal()); result.setRecords(respList); return result; @@ -76,6 +84,12 @@ public class EquipmentApprovalServiceImpl implements EquipmentApprovalService { public IPage getApprovedApprovals(EquipmentApprovalListReq req) { log.info("开始执行已审批设备分页查询,请求参数: {}", req); + // 获取分页参数 + Integer pageNum = req.getPageNum() != null ? req.getPageNum() : 1; + Integer pageSize = req.getPageSize() != null ? req.getPageSize() : 10; + + log.info("分页参数 - pageNum: {}, pageSize: {}", pageNum, pageSize); + // 使用分页插件 PageUtil.startPage(); @@ -94,10 +108,12 @@ public class EquipmentApprovalServiceImpl implements EquipmentApprovalService { .collect(Collectors.toList()); // 获取分页信息 - PageInfo pageInfo = new PageInfo<>(respList); + PageInfo pageInfo = new PageInfo<>(approvalList); + + log.info("已审批设备分页查询完成,共查询 {} 条记录,当前页码: {}, 总页码: {}", pageInfo.getTotal(), pageInfo.getPageNum(), pageInfo.getPages()); // 创建响应分页对象 - Page result = new Page<>(pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal()); + Page result = new Page<>(pageNum, pageSize, pageInfo.getTotal()); result.setRecords(respList); return result; @@ -484,11 +500,13 @@ public class EquipmentApprovalServiceImpl implements EquipmentApprovalService { public IPage getMyProcurementApplications(EquipmentApprovalListReq req) { log.info("开始获取我的采购申请,请求参数: {}", req); - // 创建分页对象 - Integer pageNum = req.getPage() != null ? req.getPage() : 1; + // 创建分页对象 - 使用pageNum保持一致性 + Integer pageNum = req.getPageNum() != null ? req.getPageNum() : 1; Integer pageSize = req.getPageSize() != null ? req.getPageSize() : 10; Page page = new Page<>(pageNum, pageSize); + log.info("分页参数 - pageNum: {}, pageSize: {}", pageNum, pageSize); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); // 只查询当前用户的申请 @@ -500,6 +518,8 @@ public class EquipmentApprovalServiceImpl implements EquipmentApprovalService { IPage result = equipmentApprovalMapper.selectPage(page, wrapper); + log.info("我的采购申请分页查询完成,共查询 {} 条记录,当前页码: {}, 总页码: {}", result.getTotal(), result.getCurrent(), result.getPages()); + return convertToRespPage(result); } diff --git a/core/src/main/java/com/dite/znpt/service/impl/EquipmentServiceImpl.java b/core/src/main/java/com/dite/znpt/service/impl/EquipmentServiceImpl.java index b30a5d4..f7d6185 100644 --- a/core/src/main/java/com/dite/znpt/service/impl/EquipmentServiceImpl.java +++ b/core/src/main/java/com/dite/znpt/service/impl/EquipmentServiceImpl.java @@ -40,6 +40,12 @@ public class EquipmentServiceImpl extends ServiceImpl page(EquipmentListReq req) { log.info("开始执行设备分页查询,请求参数: {}", req); + // 获取分页参数 + Integer pageNum = req.getPageNum() != null ? req.getPageNum() : 1; + Integer pageSize = req.getPageSize() != null ? req.getPageSize() : 10; + + log.info("分页参数 - pageNum: {}, pageSize: {}", pageNum, pageSize); + // 使用分页插件 PageUtil.startPage(); @@ -261,18 +267,20 @@ public class EquipmentServiceImpl extends ServiceImpl equipmentList = this.list(queryWrapper); - log.info("查询完成,当前页记录数: {}", equipmentList.size()); - + log.info("查询完成,当前页记录数: {}, 总记录数: {}", + equipmentList.size()); + // 转换为响应对象 List equipmentRespList = equipmentList.stream() .map(this::convertToResp) .collect(Collectors.toList()); - // 获取分页信息 - PageInfo pageInfo = new PageInfo<>(equipmentRespList); - - // 创建响应分页对象 - Page respPage = new Page<>(pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal()); + // 获取分页信息 - 使用正确的实体类型 + PageInfo pageInfo = new PageInfo<>(equipmentList); + + log.info("获取总数: {}", pageInfo.getTotal()); + // 创建响应分页对象 - 使用正确的分页参数 + Page respPage = new Page<>(pageNum, pageSize, pageInfo.getTotal()); respPage.setRecords(equipmentRespList); return respPage; @@ -498,6 +506,12 @@ public class EquipmentServiceImpl extends ServiceImpl procurementPage(EquipmentListReq req) { log.info("开始执行设备采购记录分页查询,请求参数: {}", req); + // 获取分页参数 + Integer pageNum = req.getPageNum() != null ? req.getPageNum() : 1; + Integer pageSize = req.getPageSize() != null ? req.getPageSize() : 10; + + log.info("分页参数 - pageNum: {}, pageSize: {}", pageNum, pageSize); + // 使用分页插件 PageUtil.startPage(); @@ -617,11 +631,13 @@ public class EquipmentServiceImpl extends ServiceImpl pageInfo = new PageInfo<>(records); + // 获取分页信息 - 使用正确的实体类型 + PageInfo pageInfo = new PageInfo<>(equipmentList); - // 创建响应分页对象 - Page result = new Page<>(pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal()); + log.info("设备采购分页查询完成,共查询 {} 条记录,当前页码: {}, 总页码: {}", pageInfo.getTotal(), pageInfo.getPageNum(), pageInfo.getPages()); + + // 创建响应分页对象 - 使用正确的分页参数 + Page result = new Page<>(pageNum, pageSize, pageInfo.getTotal()); result.setRecords(records); return result;