Browse Source

1.调整语音管理的上传语音时长为后端解析
2.设备厂家管理优化图片上传
3.参数管理添加必要字段
4.优化摄像头图片抓拍

wangxiaofei 2 months ago
parent
commit
37926fa454

+ 7 - 0
pom.xml

@@ -66,6 +66,7 @@
 
         <milo.version>0.6.13</milo.version>
         <fastexcel.version>1.1.0</fastexcel.version>
+        <tika.version>2.9.0</tika.version>
 
     </properties>
 
@@ -393,6 +394,12 @@
 <!--                <version>${fastexcel.version}</version>-->
 <!--            </dependency>-->
 
+            <dependency>
+                <groupId>ws.schild</groupId>
+                <artifactId>jave-all-deps</artifactId>
+                <version>3.3.1</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 

+ 1 - 4
taphole-admin/src/main/resources/application-dev.yml

@@ -43,9 +43,6 @@ socketio:
   upgradeTimeout: 1000000		#协议升级超时时间(毫秒),默认10000。HTTP握手升级为ws协议超时时间
   pingTimeout: 6000000		    #Ping消息超时时间(毫秒),默认60000,这个时间间隔内没有接收到心跳消息就会发送超时事件
   pingInterval: 25000			#Ping消息间隔(毫秒),默认25000。客户端向服务器发送一条心跳消息间隔
-mybatis-plus:
-  global-config:
-    db-config:
-      update-strategy: not_empty
+
 #  configuration:
 #    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

+ 3 - 0
taphole-admin/src/main/resources/application.yml

@@ -51,8 +51,11 @@ mybatis-plus:
     banner: false
     db-config:
       table-prefix: la_
+      update-strategy: not_null
   configuration-properties:
     prefix: la_
+#  configuration:
+#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
 
 # Sa-token配置
 sa-token:

+ 5 - 0
taphole-common/pom.xml

@@ -307,6 +307,11 @@
 <!--            <artifactId>fastexcel</artifactId>-->
 <!--        </dependency>-->
 
+        <dependency>
+            <groupId>ws.schild</groupId>
+            <artifactId>jave-all-deps</artifactId>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 25 - 0
taphole-common/src/main/java/com/sckj/common/util/AudioUtils.java

@@ -0,0 +1,25 @@
+package com.sckj.common.util;
+
+import ws.schild.jave.MultimediaObject;
+import ws.schild.jave.info.MultimediaInfo;
+
+import java.io.File;
+
+public class AudioUtils {
+    /**
+     * 获取指定音频文件的持续时间(单位:毫秒)
+     * @param filePath 音频文件的路径
+     * @return 音频文件的持续时间,如果获取失败则返回 -1
+     */
+    public static long getAudioDuration(String filePath) {
+        try {
+            File audioFile = new File(filePath);
+            MultimediaObject multimediaObject = new MultimediaObject(audioFile);
+            MultimediaInfo info = multimediaObject.getInfo();
+            return info.getDuration();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return -1;
+    }
+}

+ 28 - 8
taphole-device/src/main/java/com/sckj/device/service/impl/TDeviceFactoryServiceImpl.java

@@ -7,6 +7,7 @@ import com.sckj.common.TapholeAdminThreadLocal;
 import com.sckj.common.core.AjaxResult;
 import com.sckj.common.core.PageResult;
 import com.sckj.common.util.StringUtils;
+import com.sckj.common.util.UrlUtils;
 import com.sckj.common.validate.commons.PageValidate;
 import com.sckj.device.entity.TDeviceFactory;
 import com.sckj.device.mapper.TDeviceFactoryMapper;
@@ -16,16 +17,21 @@ import com.sckj.device.validate.TDeviceFactorySearchValidate;
 import com.sckj.device.validate.TDeviceFactoryUpdateValidate;
 import com.sckj.device.vo.TDeviceFactoryDetailVo;
 import com.sckj.device.vo.TDeviceFactoryListedVo;
+import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
+import javax.validation.constraints.NotNull;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * 设备厂家实现类
@@ -62,8 +68,8 @@ public class TDeviceFactoryServiceImpl implements ITDeviceFactoryService {
 
         tDeviceFactoryMapper.setSearch(queryWrapper, searchValidate, new String[]{
                 "like:factoryName@factory_name:str",
-                "=:factoryPhone@factory_phone:str",
-                "=:factoryAddress@factory_address:str",
+                "like:factoryPhone@factory_phone:str",
+                "like:factoryAddress@factory_address:str",
         });
 
         IPage<TDeviceFactory> iPage = tDeviceFactoryMapper.selectPage(new Page<>(page, limit), queryWrapper);
@@ -98,6 +104,14 @@ public class TDeviceFactoryServiceImpl implements ITDeviceFactoryService {
         TDeviceFactoryDetailVo vo = new TDeviceFactoryDetailVo();
         BeanUtils.copyProperties(model, vo);
         vo.setUpdateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(model.getUpdateTime()));
+        String qcPath = model.getQcPath();
+        if (StringUtils.isNotBlank(qcPath)) {
+            String[] array = Stream.of(qcPath.split(","))
+                    .map(String::trim) // 去除每个元素的前后空格
+                    .map(UrlUtils::toAbsoluteUrl)
+                    .toArray(String[]::new);
+            vo.setQcPath(array);
+        }
         return vo;
     }
 
@@ -117,10 +131,13 @@ public class TDeviceFactoryServiceImpl implements ITDeviceFactoryService {
         model.setFactoryPhone(createValidate.getFactoryPhone());
         model.setFactoryAddress(createValidate.getFactoryAddress());
         model.setFactoryAddressDetail(createValidate.getFactoryAddressDetail());
-        for (int i = 0; i < createValidate.getQcPathList().length; i++) {
-            createValidate.getQcPathList()[i] = createValidate.getQcPathList()[i].substring(35);
+        String collect = null;
+        if(ObjectUtils.isNotEmpty(createValidate.getQcPath())){
+            collect = Arrays.stream(createValidate.getQcPath())
+                    .map(UrlUtils::toRelativeUrl)
+                    .collect(Collectors.joining(","));
         }
-        model.setQcPath(String.join(",", createValidate.getQcPathList()));
+        model.setQcPath(collect);
         tDeviceFactoryMapper.insert(model);
     }
 
@@ -145,10 +162,13 @@ public class TDeviceFactoryServiceImpl implements ITDeviceFactoryService {
         model.setFactoryPhone(updateValidate.getFactoryPhone());
         model.setFactoryAddress(updateValidate.getFactoryAddress());
         model.setFactoryAddressDetail(updateValidate.getFactoryAddressDetail());
-        for (int i = 0; i < updateValidate.getQcPathList().length; i++) {
-            updateValidate.getQcPathList()[i] = updateValidate.getQcPathList()[i].substring(35);
+        String collect = null;
+        if(ObjectUtils.isNotEmpty(updateValidate.getQcPath())){
+            collect = Arrays.stream(updateValidate.getQcPath())
+                    .map(UrlUtils::toRelativeUrl)
+                    .collect(Collectors.joining(","));
         }
-        model.setQcPath(String.join(",", updateValidate.getQcPathList()));
+        model.setQcPath(collect);
         tDeviceFactoryMapper.updateById(model);
     }
 

+ 1 - 1
taphole-device/src/main/java/com/sckj/device/validate/TDeviceFactoryCreateValidate.java

@@ -32,6 +32,6 @@ public class TDeviceFactoryCreateValidate implements Serializable {
 
     @NotNull(message = "qcPathList参数缺失")
     @ApiModelProperty(value = "质量认证证书路径")
-    private String[] qcPathList;
+    private String[] qcPath;
 
 }

+ 1 - 1
taphole-device/src/main/java/com/sckj/device/validate/TDeviceFactoryUpdateValidate.java

@@ -40,6 +40,6 @@ public class TDeviceFactoryUpdateValidate implements Serializable {
 
     @NotNull(message = "qcPathList参数缺失")
     @ApiModelProperty(value = "质量认证证书路径")
-    private String[] qcPathList;
+    private String[] qcPath;
 
 }

+ 1 - 1
taphole-device/src/main/java/com/sckj/device/vo/TDeviceFactoryDetailVo.java

@@ -36,7 +36,7 @@ public class TDeviceFactoryDetailVo implements Serializable {
     private String factoryAddressDetail;
 
     @ApiModelProperty(value = "质量认证证书路径")
-    private String qcPath;
+    private String[] qcPath;
 
 
 }

+ 3 - 0
taphole-device/src/main/java/com/sckj/device/vo/TDeviceFactoryListedVo.java

@@ -32,5 +32,8 @@ public class TDeviceFactoryListedVo implements Serializable {
     @ApiModelProperty(value = "厂家详细地址")
     private String factoryAddressDetail;
 
+    @ApiModelProperty(value = "质量认证证书路径")
+    private String qcPath;
+
 
 }

+ 50 - 28
taphole-iron/src/main/java/com/sckj/iron/service/impl/TCameraServiceImpl.java

@@ -37,6 +37,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.BeanUtils;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.Assert;
@@ -49,6 +50,7 @@ import java.io.IOException;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.concurrent.CountDownLatch;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -80,6 +82,9 @@ public class TCameraServiceImpl extends ServiceImpl<TCameraMapper, TCamera> {
     @Resource
     TIronParamServiceImpl ironParamService;
 
+    @Resource(name = "taskExecutor")
+    ThreadPoolTaskExecutor taskExecutor;
+
     /**
      * 摄像头列表
      *
@@ -155,41 +160,58 @@ public class TCameraServiceImpl extends ServiceImpl<TCameraMapper, TCamera> {
 
         List<TCameraListedVo> list = new LinkedList<>();
 
-        HCNetTools hcNetTools = new HCNetTools();
-
         TIronParam webrtc = ironParamService.lambdaQuery().eq(TIronParam::getParamName, "webrtc_url").one();
 
-        for (TCamera item : iPage.getRecords()) {
-            TCameraListedVo vo = new TCameraListedVo();
-            BeanUtils.copyProperties(item, vo);
-            vo.setAddress("rtsp://" + item.getAccount() + ":" + item.getPassword() + "@" + item.getIp() + ":" + item.getPort() + "/102");
+        final String absoluteUrl = UrlUtils.toAbsoluteUrl("/");
+
+        if (ObjectUtils.isNotEmpty(iPage.getRecords())) {
+            CountDownLatch countDownLatch = new CountDownLatch(iPage.getRecords().size());
+            for (TCamera item : iPage.getRecords()) {
+                taskExecutor.submit(() -> {
+                    try {
+                        TCameraListedVo vo = new TCameraListedVo();
+                        BeanUtils.copyProperties(item, vo);
+                        vo.setAddress("rtsp://" + item.getAccount() + ":" + item.getPassword() + "@" + item.getIp() + ":" + item.getPortRtsp() + "/102");
+                        HCNetTools hcNetTools = new HCNetTools();
+                        int result = hcNetTools.deviceLogin(item.getIp(), item.getPort(), item.getAccount(), item.getPassword());
+                        if (result > -1) {
+                            vo.setOnlineStatus("1");
+
+                            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
+                            String name = dtf.format(LocalDateTime.now()) + ".jpg";
+                            String path = "/catchpic/" + item.getIp().replace(".", "") + "/";
+                            String filePath = YmlUtils.get("like.upload-directory") + path;
+                            try {
+                                FileUtils.createParentDirectories(new File(filePath));
+                            } catch (IOException e) {
+                                throw new RuntimeException(e);
+                            }
+                            if (ObjectUtils.isNotEmpty(hcNetTools.getChannelNumber())) {
+                                boolean dvrPic = hcNetTools.getDVRPic(HikCameraUtils.analyzeChannel(hcNetTools.getChannelNumber().get(0)), filePath + name);
+                                if (dvrPic) {
+                                    vo.setCatchPicUrl(absoluteUrl + path + name);
+                                    vo.setWebrtcUrl(webrtc.getParamValue());
+                                }
+                            }
+                        } else {
+                            vo.setOnlineStatus("0");
+                        }
+                        list.add(vo);
+                    } finally {
+                        countDownLatch.countDown();
+                    }
+                });
 
-            int result = hcNetTools.deviceLogin(item.getIp(), item.getPort(), item.getAccount(), item.getPassword());
-            if (result > -1) {
-                vo.setOnlineStatus("1");
+            }
 
-                DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
-                String name = dtf.format(LocalDateTime.now()) + ".jpg";
-                String path = "/picture/" + item.getIp().replace(".", "") + "/";
-                String filePath = YmlUtils.get("like.upload-directory") + path;
-                try {
-                    FileUtils.createParentDirectories(new File(filePath));
-                } catch (IOException e) {
-                    throw new RuntimeException(e);
-                }
-                if (ObjectUtils.isNotEmpty(hcNetTools.getChannelNumber())) {
-                    boolean dvrPic = hcNetTools.getDVRPic(HikCameraUtils.analyzeChannel(hcNetTools.getChannelNumber().get(0)), filePath + name);
-                    if (dvrPic) {
-                        vo.setCatchPicUrl("http://192.168.110.65:28080/" + GlobalConfig.publicPrefix + path + name);
-                        vo.setWebrtcUrl(webrtc.getParamValue());
-                    }
-                }
-            } else {
-                vo.setOnlineStatus("0");
+            try {
+                countDownLatch.await();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
             }
-            list.add(vo);
         }
 
+
         return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), list);
     }
 

+ 61 - 11
taphole-iron/src/main/java/com/sckj/iron/service/impl/TIronModelServiceImpl.java

@@ -2,24 +2,33 @@ package com.sckj.iron.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.AES;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.sckj.common.TapholeAdminThreadLocal;
 import com.sckj.common.core.PageResult;
+import com.sckj.common.util.UrlUtils;
+import com.sckj.common.util.YmlUtils;
 import com.sckj.common.validate.commons.PageValidate;
 import com.sckj.iron.entity.TIronModel;
+import com.sckj.iron.entity.TIronParam;
 import com.sckj.iron.mapper.TIronModelMapper;
 import com.sckj.iron.validate.TIronModelCreateValidate;
 import com.sckj.iron.validate.TIronModelSearchValidate;
 import com.sckj.iron.validate.TIronModelUpdateValidate;
 import com.sckj.iron.vo.TIronModelDetailVo;
 import com.sckj.iron.vo.TIronModelListedVo;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
 
 import javax.annotation.Resource;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
@@ -30,21 +39,25 @@ import java.util.List;
  * @author zhnaghao
  */
 @Service
+@Slf4j
 public class TIronModelServiceImpl extends ServiceImpl<TIronModelMapper, TIronModel> {
 
     @Resource
     TIronModelMapper tIronModelMapper;
 
+    @Resource
+    TIronParamServiceImpl ironParamService;
+
     /**
      * 出铁相关模型列表
      *
-     * @author LikeAdmin
-     * @param pageValidate 分页参数
+     * @param pageValidate   分页参数
      * @param searchValidate 搜索参数
      * @return PageResult<TIronModelListedVo>
+     * @author LikeAdmin
      */
     public PageResult<TIronModelListedVo> list(PageValidate pageValidate, TIronModelSearchValidate searchValidate) {
-        Integer page  = pageValidate.getPageNo();
+        Integer page = pageValidate.getPageNo();
         Integer limit = pageValidate.getPageSize();
 
         QueryWrapper<TIronModel> queryWrapper = new QueryWrapper<>();
@@ -66,7 +79,7 @@ public class TIronModelServiceImpl extends ServiceImpl<TIronModelMapper, TIronMo
         IPage<TIronModel> iPage = tIronModelMapper.selectPage(new Page<>(page, limit), queryWrapper);
 
         List<TIronModelListedVo> list = new LinkedList<>();
-        for(TIronModel item : iPage.getRecords()) {
+        for (TIronModel item : iPage.getRecords()) {
             TIronModelListedVo vo = new TIronModelListedVo();
             BeanUtils.copyProperties(item, vo);
             list.add(vo);
@@ -78,9 +91,9 @@ public class TIronModelServiceImpl extends ServiceImpl<TIronModelMapper, TIronMo
     /**
      * 出铁相关模型详情
      *
-     * @author LikeAdmin
      * @param id 主键参数
      * @return TIronModel
+     * @author LikeAdmin
      */
     public TIronModelDetailVo detail(Long id) {
         TIronModel model = tIronModelMapper.selectOne(
@@ -98,8 +111,8 @@ public class TIronModelServiceImpl extends ServiceImpl<TIronModelMapper, TIronMo
     /**
      * 出铁相关模型新增
      *
-     * @author LikeAdmin
      * @param createValidate 参数
+     * @author LikeAdmin
      */
     public void add(TIronModelCreateValidate createValidate) {
         TIronModel model = new TIronModel();
@@ -110,8 +123,13 @@ public class TIronModelServiceImpl extends ServiceImpl<TIronModelMapper, TIronMo
         model.setStatus(createValidate.getStatus());
         model.setSort(createValidate.getSort());
         model.setModelPath(createValidate.getModelPath());
-        if(ObjectUtils.isNotEmpty(createValidate.getModelPath())){
+        String path = createValidate.getModelPath();
+        if (ObjectUtils.isNotEmpty(path)) {
+            String relativeUrl = UrlUtils.toRelativeUrl(path);
+            model.setModelPath(relativeUrl);
 
+        } else {
+            model.setModelPath(null);
         }
         tIronModelMapper.insert(model);
     }
@@ -119,13 +137,13 @@ public class TIronModelServiceImpl extends ServiceImpl<TIronModelMapper, TIronMo
     /**
      * 出铁相关模型编辑
      *
-     * @author LikeAdmin
      * @param updateValidate 参数
+     * @author LikeAdmin
      */
     public void edit(TIronModelUpdateValidate updateValidate) {
         TIronModel model = tIronModelMapper.selectOne(
                 new QueryWrapper<TIronModel>()
-                        .eq("id",  updateValidate.getId())
+                        .eq("id", updateValidate.getId())
                         .last("limit 1"));
 
         Assert.notNull(model, "数据不存在!");
@@ -134,17 +152,49 @@ public class TIronModelServiceImpl extends ServiceImpl<TIronModelMapper, TIronMo
         model.setModelName(updateValidate.getModelName());
         model.setModelExpression(updateValidate.getModelExpression());
         model.setModelDesc(updateValidate.getModelDesc());
-        model.setModelPath(updateValidate.getModelPath());
         model.setStatus(updateValidate.getStatus());
         model.setSort(updateValidate.getSort());
+        String path = updateValidate.getModelPath();
+        if (ObjectUtils.isNotEmpty(path)) {
+            String relativeUrl = UrlUtils.toRelativeUrl(path);
+            model.setModelPath(relativeUrl);
+            String modelFilePath = YmlUtils.get("like.upload-directory") + relativeUrl;
+//            File file = new File(YmlUtils.get("like.upload-directory") + relativeUrl);
+            try {
+                Path filePath = Paths.get(modelFilePath);
+                List<String> lines = Files.readAllLines(filePath);
+                StringBuilder content = new StringBuilder();
+                for (String line : lines) {
+                    content.append(line);
+                }
+                log.info("读取的模型文件为:{}",content.toString());
+                //随机生成密码
+//                String generateRandomKey = AES.generateRandomKey();
+                //加密
+//                String encrypt = AES.encrypt(content.toString(), generateRandomKey);
+                //解密
+                TIronParam modelKey = ironParamService.lambdaQuery().eq(TIronParam::getParamName, "model_key").one();
+                String key = "bg@CN_9999_8888";
+                if(ObjectUtils.isNotEmpty(modelKey) && ObjectUtils.isNotEmpty(modelKey.getParamValue()) ){
+                    key = modelKey.getParamValue();
+                }
+                String decrypt = AES.decrypt(content.toString(), key);
+                model.setModelExpression(decrypt);
+
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        } else {
+            model.setModelPath(null);
+        }
         tIronModelMapper.updateById(model);
     }
 
     /**
      * 出铁相关模型删除
      *
-     * @author LikeAdmin
      * @param id 主键ID
+     * @author LikeAdmin
      */
     public void del(Integer id) {
         TIronModel model = tIronModelMapper.selectOne(

+ 2 - 1
taphole-iron/src/main/java/com/sckj/iron/vo/TIronParamDetailVo.java

@@ -46,5 +46,6 @@ public class TIronParamDetailVo implements Serializable {
     @ApiModelProperty(value = "排序")
     private Integer sort;
 
-
+    @ApiModelProperty(value = "参数说明")
+    private String paramDesc;
 }

+ 2 - 1
taphole-iron/src/main/java/com/sckj/iron/vo/TIronParamListedVo.java

@@ -46,5 +46,6 @@ public class TIronParamListedVo implements Serializable {
     @ApiModelProperty(value = "排序")
     private Integer sort;
 
-
+    @ApiModelProperty(value = "参数说明")
+    private String paramDesc;
 }

+ 79 - 51
taphole-warn/src/main/java/com/sckj/warn/service/impl/TAudioServiceImpl.java

@@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.sckj.common.TapholeAdminThreadLocal;
 import com.sckj.common.core.AjaxResult;
+import com.sckj.common.exception.OperateException;
+import com.sckj.common.util.*;
 import com.sckj.common.validate.commons.PageValidate;
 import com.sckj.warn.validate.TAudioCreateValidate;
 import com.sckj.warn.validate.TAudioUpdateValidate;
@@ -17,24 +19,24 @@ import com.sckj.common.config.GlobalConfig;
 import com.sckj.common.core.PageResult;
 import com.sckj.warn.entity.TAudio;
 import com.sckj.warn.mapper.TAudioMapper;
-import com.sckj.common.util.ListUtils;
-import com.sckj.common.util.TimeUtils;
-import com.sckj.common.util.UrlUtils;
+import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
 
 import javax.annotation.Resource;
+import java.io.File;
 import java.text.SimpleDateFormat;
 import java.util.*;
 
 /**
  * 音频实现类
+ *
  * @author zhanghao
  */
 @Service
-public class TAudioServiceImpl extends ServiceImpl<TAudioMapper,TAudio>  {
+public class TAudioServiceImpl extends ServiceImpl<TAudioMapper, TAudio> {
 
     @Resource
     TAudioMapper tAudioMapper;
@@ -42,13 +44,13 @@ public class TAudioServiceImpl extends ServiceImpl<TAudioMapper,TAudio>  {
     /**
      * 音频列表
      *
-     * @author zhanghao
-     * @param pageValidate 分页参数
+     * @param pageValidate   分页参数
      * @param searchValidate 搜索参数
      * @return PageResult<TAudioListedVo>
+     * @author zhanghao
      */
     public PageResult<TAudioListedVo> list(PageValidate pageValidate, TAudioSearchValidate searchValidate) {
-        Integer page  = pageValidate.getPageNo();
+        Integer page = pageValidate.getPageNo();
         Integer limit = pageValidate.getPageSize();
 
         QueryWrapper<TAudio> queryWrapper = new QueryWrapper<>();
@@ -56,24 +58,25 @@ public class TAudioServiceImpl extends ServiceImpl<TAudioMapper,TAudio>  {
         queryWrapper.orderByDesc("id");
 
         tAudioMapper.setSearch(queryWrapper, searchValidate, new String[]{
-            "=:createBy@create_by:str",
-            "=:updateBy@update_by:str",
-            "like:name:str",
-            "=:exceptionType@exception_type:str",
-            "=:exceptionLevel@exception_level:str",
-            "=:path:str",
-            "=:status:str",
+                "=:createBy@create_by:str",
+                "=:updateBy@update_by:str",
+                "like:name:str",
+                "=:exceptionType@exception_type:str",
+                "=:exceptionLevel@exception_level:str",
+                "=:path:str",
+                "=:status:str",
         });
 
         IPage<TAudio> iPage = tAudioMapper.selectPage(new Page<>(page, limit), queryWrapper);
 
         List<TAudioListedVo> list = new LinkedList<>();
-        for(TAudio item : iPage.getRecords()) {
+        for (TAudio item : iPage.getRecords()) {
             TAudioListedVo vo = new TAudioListedVo();
             BeanUtils.copyProperties(item, vo);
-            vo.setPath("http://localhost:28080/api/uploads/" + vo.getPath());
+            String relativeUrl = UrlUtils.toAbsoluteUrl(vo.getPath());
+            vo.setPath(relativeUrl);
             vo.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(item.getCreateTime()));
-            if (item.getUpdateTime() != null){
+            if (item.getUpdateTime() != null) {
                 vo.setUpdateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(item.getUpdateTime()));
             }
             list.add(vo);
@@ -85,11 +88,11 @@ public class TAudioServiceImpl extends ServiceImpl<TAudioMapper,TAudio>  {
     /**
      * 音频详情
      *
-     * @author zhanghao
      * @param id 主键参数
      * @return TAudio
+     * @author zhanghao
      */
-    
+
     public TAudioDetailVo detail(Integer id) {
         TAudio model = tAudioMapper.selectOne(
                 new QueryWrapper<TAudio>()
@@ -98,7 +101,7 @@ public class TAudioServiceImpl extends ServiceImpl<TAudioMapper,TAudio>  {
                         .last("limit 1"));
 
         Assert.notNull(model, "数据不存在");
-
+        model.setPath(UrlUtils.toAbsoluteUrl(model.getPath()));
         TAudioDetailVo vo = new TAudioDetailVo();
         BeanUtils.copyProperties(model, vo);
         return vo;
@@ -107,19 +110,32 @@ public class TAudioServiceImpl extends ServiceImpl<TAudioMapper,TAudio>  {
     /**
      * 音频新增
      *
-     * @author zhanghao
      * @param createValidate 参数
+     * @author zhanghao
      */
-    
+
     public void add(TAudioCreateValidate createValidate) {
         TAudio model = new TAudio();
         model.setCreateTime(new Date(System.currentTimeMillis()));
         model.setCreateBy(String.valueOf(TapholeAdminThreadLocal.getAdminUsername()));
         model.setName(createValidate.getName());
-        model.setPath(createValidate.getPath());
         model.setDuration(createValidate.getDuration());
         model.setExceptionType(createValidate.getExceptionType());
         model.setExceptionLevel(createValidate.getExceptionLevel());
+        String path = createValidate.getPath();
+        if (ObjectUtils.isNotEmpty(path)) {
+            String relativeUrl = UrlUtils.toRelativeUrl(path);
+            model.setPath(relativeUrl);
+            long audioDuration = AudioUtils.getAudioDuration(YmlUtils.get("like.upload-directory") + relativeUrl);
+            if (audioDuration == -1) {
+                model.setDuration("0");
+            } else {
+                model.setDuration(String.valueOf(audioDuration * 1.0 / 1000));
+            }
+        } else {
+            model.setPath(null);
+            model.setDuration("0");
+        }
         //默认新增的音频初始状态为停用
         tAudioMapper.insert(model);
     }
@@ -127,26 +143,38 @@ public class TAudioServiceImpl extends ServiceImpl<TAudioMapper,TAudio>  {
     /**
      * 音频编辑
      *
-     * @author zhanghao
      * @param updateValidate 参数
+     * @author zhanghao
      */
-    
+
     public int edit(TAudioUpdateValidate updateValidate) {
         TAudio model = tAudioMapper.selectOne(
                 new QueryWrapper<TAudio>()
-                    .eq("id",  updateValidate.getId()).eq("del_flag", "1")
-                    .last("limit 1"));
+                        .eq("id", updateValidate.getId()).eq("del_flag", "1")
+                        .last("limit 1"));
 
-        if (model == null){
-            return 0;
-        }
+        Assert.notNull(model, "数据不存在!");
+
+        model.setId(updateValidate.getId());
         model.setUpdateTime(new Date(System.currentTimeMillis()));
         model.setUpdateBy(String.valueOf(TapholeAdminThreadLocal.getAdminUsername()));
         model.setName(updateValidate.getName());
-        model.setPath(updateValidate.getPath());
-        model.setDuration(updateValidate.getDuration());
         model.setExceptionType(updateValidate.getExceptionType());
         model.setExceptionLevel(updateValidate.getExceptionLevel());
+        String path = updateValidate.getPath();
+        if (ObjectUtils.isNotEmpty(path)) {
+            String relativeUrl = UrlUtils.toRelativeUrl(path);
+            model.setPath(relativeUrl);
+            long audioDuration = AudioUtils.getAudioDuration(YmlUtils.get("like.upload-directory") + relativeUrl);
+            if (audioDuration == -1) {
+                model.setDuration("0");
+            } else {
+                model.setDuration(String.valueOf(audioDuration * 1.0 / 1000));
+            }
+        } else {
+            model.setPath(null);
+            model.setDuration("0");
+        }
         tAudioMapper.updateById(model);
         return 1;
     }
@@ -154,29 +182,29 @@ public class TAudioServiceImpl extends ServiceImpl<TAudioMapper,TAudio>  {
     /**
      * 音频音频启用状态修改
      *
-     * @author zhanghao
      * @param updateValidate 参数
+     * @author zhanghao
      */
-    
+
     public AjaxResult<Object> status(TAudioUpdateValidate updateValidate) {
         TAudio model = tAudioMapper.selectOne(
                 new QueryWrapper<TAudio>()
-                        .eq("id",  updateValidate.getId()).eq("del_flag", "1")
+                        .eq("id", updateValidate.getId()).eq("del_flag", "1")
                         .last("limit 1"));
-        if (model == null){
+        if (model == null) {
             return AjaxResult.failed("未找到该音频");
         }
         /*如果将要修改的状态值和原来的值不同,且修改音频状态为启用*/
-        if (!model.getStatus().equals(updateValidate.getStatus()) && updateValidate.getStatus().equals("1")){
+        if (!model.getStatus().equals(updateValidate.getStatus()) && updateValidate.getStatus().equals("1")) {
             //首先查找是否存在同异常类型同危害程度的已启用音频
             TAudio tAudio = tAudioMapper.selectOne(
                     new QueryWrapper<TAudio>()
-                            .eq("exception_type",  updateValidate.getExceptionType())
-                            .eq("exception_level",  updateValidate.getExceptionLevel())
-                            .eq("status",  "1")
+                            .eq("exception_type", updateValidate.getExceptionType())
+                            .eq("exception_level", updateValidate.getExceptionLevel())
+                            .eq("status", "1")
                             .last("limit 1"));
             //存在冲突
-            if (tAudio != null){
+            if (tAudio != null) {
                 return AjaxResult.failed("存在已启用的同类音频,禁止修改");
             }
         }
@@ -191,15 +219,15 @@ public class TAudioServiceImpl extends ServiceImpl<TAudioMapper,TAudio>  {
     /**
      * 音频删除
      *
-     * @author zhanghao
      * @param id 主键ID
+     * @author zhanghao
      */
-    
+
     public void del(Integer id) {
         TAudio model = tAudioMapper.selectOne(
                 new QueryWrapper<TAudio>()
-                    .eq("id", id)
-                    .last("limit 1"));
+                        .eq("id", id)
+                        .last("limit 1"));
 
         Assert.notNull(model, "数据不存在!");
 
@@ -211,13 +239,13 @@ public class TAudioServiceImpl extends ServiceImpl<TAudioMapper,TAudio>  {
     /**
      * 音频地址查询
      *
-     * @author zhanghao
      * @param id 主键ID
+     * @author zhanghao
      */
-    public String searchPath(Long id){
+    public String searchPath(Long id) {
         TAudio model = tAudioMapper.selectOne(
                 new QueryWrapper<TAudio>()
-                        .eq("id",  id).eq("del_flag", "1")
+                        .eq("id", id).eq("del_flag", "1")
                         .last("limit 1"));
 
         Assert.notNull(model, "数据不存在!");
@@ -227,16 +255,16 @@ public class TAudioServiceImpl extends ServiceImpl<TAudioMapper,TAudio>  {
     /**
      * 音频批量删除
      *
-     * @author zhanghao
      * @param ids 主键数组
+     * @author zhanghao
      */
-    
+
     public AjaxResult<Object> del_ex(List<Long> ids) {
         List<TAudio> models = tAudioMapper.selectList(
                 new QueryWrapper<TAudio>()
                         .in("id", ids));
 
-        if (CollectionUtils.isEmpty(models)){
+        if (CollectionUtils.isEmpty(models)) {
             return AjaxResult.failed("数据不存在");
         }
         TAudio model = new TAudio();