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); + } +}