diff --git a/nursing-unit-services/nu-services-biz/pom.xml b/nursing-unit-services/nu-services-biz/pom.xml
index cc3ca517..7a22fc94 100644
--- a/nursing-unit-services/nu-services-biz/pom.xml
+++ b/nursing-unit-services/nu-services-biz/pom.xml
@@ -1,60 +1,60 @@
-
- com.nursingunit.boot
- nursing-unit-services
- 2.0.0
-
- 4.0.0
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ com.nursingunit.boot
+ nursing-unit-services
+ 2.0.0
+
+ 4.0.0
- nu-services-biz
+ nu-services-biz
-
-
- com.nursingunit.boot
- nu-services-local-api
- ${nursingunit.version}
-
-
- org.hibernate
- hibernate-core
-
-
- org.jeecgframework.boot
- hibernate-re
-
+
+
+ com.nursingunit.boot
+ nu-services-local-api
+ ${nursingunit.version}
+
+
+ org.hibernate
+ hibernate-core
+
+
+ org.jeecgframework.boot
+ hibernate-re
+
-
-
- org.jeecgframework
- weixin4j
-
+
+
+ org.jeecgframework
+ weixin4j
+
-
-
- com.belerweb
- pinyin4j
- 2.5.0
-
+
+
+ com.belerweb
+ pinyin4j
+ 2.5.0
+
-
-
- com.nursingunit.boot
- nursing-unit-common
- ${nursingunit.version}
-
+
+
+ com.nursingunit.boot
+ nursing-unit-common
+ ${nursingunit.version}
+
com.nursingunit.boot
nu-system-local-api
2.0.0
compile
-
- com.nursingunit.boot
- nu-admin-local-api
- ${nursingunit.version}
-
+
+ com.nursingunit.boot
+ nu-admin-local-api
+ ${nursingunit.version}
+
com.nursingunit.boot
nu-admin-biz
@@ -73,6 +73,35 @@
2.0.0
compile
+
+
+
+
+ org.bytedeco
+ javacv
+ 1.5.9
+
+
+ org.bytedeco
+ javacpp
+
+
+
+
+
+
+ org.bytedeco
+ ffmpeg
+ 6.0-1.5.9
+
+
+
+
+ org.bytedeco
+ ffmpeg
+ 6.0-1.5.9
+ linux-x86_64
+
diff --git a/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/entity/DirectiveOrder.java b/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/entity/DirectiveOrder.java
index 9d521c00..e38e30c5 100644
--- a/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/entity/DirectiveOrder.java
+++ b/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/entity/DirectiveOrder.java
@@ -1,9 +1,6 @@
package com.nu.modules.biz.order.entity;
-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.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@@ -11,6 +8,7 @@ import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
+import javax.persistence.Column;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
@@ -212,6 +210,8 @@ public class DirectiveOrder implements Serializable {
/**
* tplink监控视频上传任务ID
*/
+ @TableField(updateStrategy = FieldStrategy.IGNORED)
+ @Column(nullable = true, updatable = true)
private String tplinkTaskId;
/**
* tplink切片crc64
diff --git a/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/job/DirectiveOrderEndTplinkJob.java b/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/job/DirectiveOrderEndTplinkJob.java
index 9097698f..78fd034b 100644
--- a/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/job/DirectiveOrderEndTplinkJob.java
+++ b/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/job/DirectiveOrderEndTplinkJob.java
@@ -1,7 +1,6 @@
package com.nu.modules.biz.order.job;
import com.alibaba.fastjson.JSONObject;
-import com.nu.entity.CosFileInfoEntity;
import com.nu.entity.DirectiveOrderEntity;
import com.nu.modules.biz.order.entity.DirectiveOrder;
import com.nu.modules.biz.order.service.IDirectiveOrderJobService;
@@ -9,7 +8,6 @@ import com.nu.modules.sysconfig.ISysConfigApi;
import com.nu.modules.tplink.camera.service.ICameraInfoJobService;
import com.nu.utils.CosFileUtil;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.DateUtils;
@@ -18,7 +16,6 @@ import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.util.CollectionUtils;
import java.util.Date;
import java.util.List;
@@ -65,10 +62,28 @@ public class DirectiveOrderEndTplinkJob implements Job {
{
List directiveOrderList = directiveOrderService.getUploadingTplink();
directiveOrderList.forEach(order -> {
- Map result = tplinkService.getUploadToServerProcess(order.getTplinkTaskId());
- System.out.println("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
- System.out.println(result.toString());
- System.out.println("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
+ try {
+ Map result = tplinkService.getUploadToServerProcess(order.getTplinkTaskId());
+ System.out.println("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
+ System.out.println(result.toString());
+ System.out.println("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
+
+ if("success".equals(result.get("result")) ){
+ if("1000".equals(result.get("process"))){
+ order.setTplinkParams("成功");
+ order.setOrderEndTime(new Date());
+ order.setTplinkTaskId(null);
+ directiveOrderService.updateById(order);
+ }
+ }else{
+ order.setTplinkParams(result.toString());
+ order.setOrderEndTime(new Date());
+ order.setTplinkTaskId(null);
+ directiveOrderService.updateById(order);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
});
}
// //任务一:COS上传进度查询
diff --git a/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/job/Mp4TestJob.java b/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/job/Mp4TestJob.java
new file mode 100644
index 00000000..86230c47
--- /dev/null
+++ b/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/job/Mp4TestJob.java
@@ -0,0 +1,192 @@
+package com.nu.modules.biz.order.job;
+
+import lombok.extern.slf4j.Slf4j;
+import org.bytedeco.ffmpeg.ffmpeg;
+import org.bytedeco.javacpp.Loader;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.Duration;
+import java.time.LocalDateTime;
+
+/**
+ * 测试mp4视频切割与拼接
+ * 策略:完全基于时间轴计算,不依赖视频元数据
+ */
+@Slf4j
+public class Mp4TestJob implements Job {
+
+ // ================= 常量配置 =================
+ // 宿主机映射到容器内的路径
+ private static final String BASE_PATH = "/opt/biz";
+ private static final String INPUT_FILE_CONTAINER = BASE_PATH + "/upFiles101/2510101004-20260429130857-2039611288698490882.mp4";
+
+ // 视频元数据(硬编码)
+ private static final LocalDateTime VIDEO_START_TIME = LocalDateTime.of(2026, 4, 29, 10, 59, 58);
+ private static final long VIDEO_TOTAL_DURATION = 3601L; // 1小时01秒
+
+ @Override
+ public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+ try {
+ // 确保输出目录存在
+ File outputDir = new File(BASE_PATH);
+ if (!outputDir.exists()) {
+ outputDir.mkdirs();
+ }
+
+ // ================= 任务规划 =================
+ // 目标:
+ // 1. 切 Part1: 11:15:15 -> 11:30:15
+ // 2. 切 Part2: 11:30:16 -> 11:45:15
+ // 3. 拼接: Part1的后半段(从11:20:15开始) + Part2的前半段(到11:40:15结束)
+
+ // 1. 处理 Part 1
+ LocalDateTime p1StartTarget = LocalDateTime.of(2026, 4, 29, 11, 15, 15);
+ LocalDateTime p1EndTarget = LocalDateTime.of(2026, 4, 29, 11, 30, 15);
+ String part1File = BASE_PATH + "/part1_111515.mp4";
+
+ // 计算在源文件中的偏移量和时长
+ long p1Offset = getSecondsFromStart(p1StartTarget);
+ long p1Duration = Duration.between(p1StartTarget, p1EndTarget).getSeconds();
+ cutVideo(INPUT_FILE_CONTAINER, part1File, p1Offset, p1Duration);
+
+ // 2. 处理 Part 2
+ LocalDateTime p2StartTarget = LocalDateTime.of(2026, 4, 29, 11, 30, 16);
+ LocalDateTime p2EndTarget = LocalDateTime.of(2026, 4, 29, 11, 45, 15);
+ String part2File = BASE_PATH + "/part2_113016.mp4";
+
+ long p2Offset = getSecondsFromStart(p2StartTarget);
+ long p2Duration = Duration.between(p2StartTarget, p2EndTarget).getSeconds();
+ cutVideo(INPUT_FILE_CONTAINER, part2File, p2Offset, p2Duration);
+
+ // 3. 拼接逻辑
+ // 需求:取 Part1 中 11:20:15 之后的内容 + Part2 中 11:40:15 之前的内容
+ LocalDateTime splicePointP1 = LocalDateTime.of(2026, 4, 29, 11, 20, 15);
+ LocalDateTime splicePointP2 = LocalDateTime.of(2026, 4, 29, 11, 40, 15);
+
+ String finalFile = BASE_PATH + "/final_112015_114015.mp4";
+ spliceVideo(part1File, part2File, finalFile, splicePointP1, p1StartTarget, splicePointP2, p2StartTarget);
+
+ } catch (Exception e) {
+ log.error("视频处理失败", e);
+ throw new JobExecutionException(e);
+ }
+ }
+
+ /**
+ * 计算目标时间相对于视频开始时间(2026-04-29 10:59:58)的秒数偏移
+ */
+ private long getSecondsFromStart(LocalDateTime targetTime) {
+ return Duration.between(VIDEO_START_TIME, targetTime).getSeconds();
+ }
+
+ /**
+ * 切割视频
+ * @param input 输入文件
+ * @param output 输出文件
+ * @param startTime 在源文件中的开始偏移量(秒)
+ * @param duration 持续时间(秒)
+ */
+ private void cutVideo(String input, String output, long startTime, long duration) throws IOException, InterruptedException {
+ log.info("开始切割: [偏移{}秒, 时长{}秒] -> {}", startTime, duration, output);
+ long start = System.currentTimeMillis();
+
+ String ffmpeg = Loader.load(ffmpeg.class);
+ ProcessBuilder pb = new ProcessBuilder(
+ ffmpeg,
+ "-ss", String.valueOf(startTime),
+ "-i", input,
+ "-t", String.valueOf(duration),
+ "-c", "copy",
+ "-avoid_negative_ts", "make_zero",
+ output
+ );
+ // 继承标准输出和错误流,方便调试
+ pb.inheritIO().start().waitFor();
+
+ long cost = System.currentTimeMillis() - start;
+ log.info("切割完成: {}, 耗时: {}秒", output, cost / 1000);
+ }
+
+ /**
+ * 拼接视频
+ * 逻辑:
+ * 1. 计算 Part1 需要截取的时长 (从 splicePoint 到 Part1 结束)
+ * 2. 计算 Part2 需要截取的时长 (从 Part2 开始 到 splicePoint)
+ * 3. 生成临时列表并执行拼接
+ */
+ private void spliceVideo(String part1, String part2, String output,
+ LocalDateTime p1SplicePoint, LocalDateTime p1Base,
+ LocalDateTime p2SplicePoint, LocalDateTime p2Base) throws IOException, InterruptedException {
+
+ log.info("开始拼接: {} + {} -> {}", part1, part2, output);
+ long start = System.currentTimeMillis();
+
+ // 1. 计算 Part1 截取时长:目标拼接点 - Part1起始时间
+ long p1CutDuration = Duration.between(p1Base, p1SplicePoint).getSeconds();
+
+ // 2. 计算 Part2 截取时长:目标拼接点 - Part2起始时间
+ long p2CutDuration = Duration.between(p2Base, p2SplicePoint).getSeconds();
+
+ // 3. 创建临时 concat 文件
+ // 注意:这里使用 input seeking 方式 (-ss 在 -i 之前) 性能最好
+ String concatFile = BASE_PATH + "/concat_list.txt";
+ try (FileWriter writer = new FileWriter(concatFile)) {
+ // 第一部分:从 part1 开头截取 p1CutDuration 秒
+ writer.write("file '" + part1 + "'\n");
+ // 第二部分:从 part2 开头截取 p2CutDuration 秒
+ writer.write("file '" + part2 + "'\n");
+ }
+
+ String ffmpeg = Loader.load(ffmpeg.class);
+ // 使用 -ss 配合 -t 对 concat 流进行切片
+ // 这里有个技巧:因为我们要的是 Part1 的后半段,但 concat 只能顺序读。
+ // 所以更简单的做法是:分别切出这两段临时文件,再合并。
+ // 但为了演示 concat 协议,我们采用“先合并再修剪”或者“分别修剪再合并”。
+ // 鉴于 -c copy 的限制,最稳妥的“拼接特定片段”方案是:
+ // 1. 先切出 Part1 的后半段临时文件
+ // 2. 再切出 Part2 的前半段临时文件
+ // 3. 合并这两个临时文件
+
+ // --- 修正方案:三步走 ---
+ String temp1 = BASE_PATH + "/temp_p1_part.mp4";
+ String temp2 = BASE_PATH + "/temp_p2_part.mp4";
+
+ // 步骤 A: 提取 Part1 的后半段 (从 p1CutDuration 开始,直到文件结束)
+ // 注意:这里不需要 -t,直接截取到末尾
+ ProcessBuilder pb1 = new ProcessBuilder(ffmpeg, "-ss", String.valueOf(p1CutDuration), "-i", part1, "-c", "copy", "-avoid_negative_ts", "make_zero", temp1);
+ pb1.inheritIO().start().waitFor();
+
+ // 步骤 B: 提取 Part2 的前半段 (从 0 开始,时长 p2CutDuration)
+ ProcessBuilder pb2 = new ProcessBuilder(ffmpeg, "-i", part2, "-t", String.valueOf(p2CutDuration), "-c", "copy", temp2);
+ pb2.inheritIO().start().waitFor();
+
+ // 步骤 C: 拼接 temp1 和 temp2
+ try (FileWriter writer = new FileWriter(concatFile)) {
+ writer.write("file '" + temp1 + "'\n");
+ writer.write("file '" + temp2 + "'\n");
+ }
+
+ ProcessBuilder pbConcat = new ProcessBuilder(
+ ffmpeg,
+ "-f", "concat",
+ "-safe", "0",
+ "-i", concatFile,
+ "-c", "copy",
+ output
+ );
+ pbConcat.inheritIO().start().waitFor();
+
+ // 清理临时文件
+ new File(concatFile).delete();
+ new File(temp1).delete();
+ new File(temp2).delete();
+
+ long cost = System.currentTimeMillis() - start;
+ log.info("拼接完成: {}, 耗时: {}秒", output, cost / 1000);
+ }
+}
diff --git a/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/mapper/xml/DirectiveOrderMapper.xml b/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/mapper/xml/DirectiveOrderMapper.xml
index d6c61968..3d0d8e39 100644
--- a/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/mapper/xml/DirectiveOrderMapper.xml
+++ b/nursing-unit-services/nu-services-biz/src/main/java/com/nu/modules/biz/order/mapper/xml/DirectiveOrderMapper.xml
@@ -751,7 +751,7 @@