package com.fdkankan.scene.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.TimeInterval; import cn.hutool.core.io.FileUtil; import cn.hutool.core.net.multipart.UploadFile; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.fdkankan.common.constant.CommonStatus; import com.fdkankan.common.constant.ErrorCode; import com.fdkankan.common.constant.ServerCode; import com.fdkankan.common.exception.BusinessException; import com.fdkankan.common.util.FileUtils; import com.fdkankan.db.response.PageInfo; import com.fdkankan.fyun.face.FYunFileServiceInterface; import com.fdkankan.model.constants.ConstantFilePath; import com.fdkankan.model.constants.UploadFilePath; import com.fdkankan.redis.constant.RedisKey; import com.fdkankan.scene.bean.EvidenceBean; import com.fdkankan.scene.bean.IconBean; import com.fdkankan.scene.bean.JMErrorCode; import com.fdkankan.scene.entity.*; import com.fdkankan.scene.httpclient.ManageHttpClient; import com.fdkankan.scene.mapper.ISceneEvidenceMapper; import com.fdkankan.scene.service.*; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fdkankan.scene.util.JmgaSSOLoginHelper; import com.fdkankan.scene.vo.*; import com.fdkankan.web.response.ResultData; import com.fdkankan.web.user.SSOUser; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.io.File; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; /** *

* 痕迹物证表 服务实现类 *

* * @author * @since 2025-08-08 */ @Slf4j @Service public class SceneEvidenceServiceImpl extends ServiceImpl implements ISceneEvidenceService { @Autowired private IScenePlusService scenePlusService; @Autowired private ISceneEditInfoService sceneEditInfoService; @Autowired private ISceneIconService sceneIconService; @Resource private ManageHttpClient manageHttpClient; @Autowired private FYunFileServiceInterface fYunFileServiceInterface; @Value("${4dkk.fdService.basePath}") private String basePath; @Autowired private JmgaSSOLoginHelper jmgaSSOLoginHelper; @Autowired private ISceneMidService sceneMidService; @Override public void saveEvidence(SaveEvidenceParamVO param, String token) throws Exception { ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum()); if (scenePlus == null) throw new BusinessException(ErrorCode.FAILURE_CODE_5005); this.addOrUpdateData(param.getNum(), scenePlus.getKNo(), token, param.getDataList()); //设置应用到全部数据 this.generalConfig(param.getNum(), param.getGeneralConfig()); this.addOrUpdateIcons(param.getNum(), param.getIcons()); //保存数据库 SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId()); this.saveEvidenceToSceneEditInfo(param.getNum(), sceneEditInfo); sceneEditInfoService.updateById(sceneEditInfo); this.reviseSceneMid(param.getNum()); //推送媒体库 // this.batchPushMedia(param, token, scenePlus); } private void reviseSceneMid(String num){ List sceneEvidences = this.listByNum(num); Set sids = new HashSet<>(); sceneEvidences.stream().forEach(v->{ JSONArray media = v.getEvidenceContent().getJSONArray("media"); if(CollUtil.isNotEmpty(media)){ media.stream().forEach(m -> { JSONObject mediaObj = JSON.parseObject(JSON.toJSONString(m)); sids.add(mediaObj.getString("sid")); }); } JSONObject bgm = v.getEvidenceContent().getJSONObject("bgm"); if(Objects.nonNull(bgm)){ sids.add(FileUtil.getPrefix(bgm.getString("name"))); } }); if(CollUtil.isEmpty(sids)){ sceneMidService.remove(new LambdaQueryWrapper().eq(SceneMid::getNum, num)); }else{ sceneMidService.remove(new LambdaQueryWrapper().eq(SceneMid::getNum, num).notIn(SceneMid::getSid, sids)); } } private void generalConfig(String num, JSONObject generalConfig){ if(CollUtil.isEmpty(generalConfig)){ return; } List sceneEvidences = this.listByNum(num); if(CollUtil.isEmpty(sceneEvidences)){ return; } sceneEvidences.stream().forEach(v->{ JSONObject visiSetting = v.getEvidenceContent().getJSONObject("visiSetting"); for (String settingKey : generalConfig.keySet()) { visiSetting.put(settingKey, generalConfig.get(settingKey)); } }); this.updateBatchById(sceneEvidences); } private void batchPushMedia(SaveEvidenceParamVO param, String token, ScenePlus scenePlus){ log.info("--------------SaveEvidenceParamVO:{}", JSON.toJSONString(param)); List params = new ArrayList<>(); List sms = new ArrayList<>(); for (EvidenceParamVO evidenceParamVO : param.getDataList()) { //media JSONArray medias = evidenceParamVO.getData().getJSONArray("media"); if(CollUtil.isNotEmpty(medias)){ for (Object o : medias) { JSONObject media = JSON.parseObject(JSON.toJSONString(o)); if(media.getIntValue("isAddMedia") != 1){ continue; } String ossPath = String.format(UploadFilePath.USER_EDIT_PATH, param.getNum()) + media.getString("src"); JSONObject item = new JSONObject(); params.add(item); item.put("num", param.getNum()); item.put("kno", scenePlus.getKNo()); item.put("filePath", ossPath); item.put("fileName", media.getString("name")); item.put("fileSize", fYunFileServiceInterface.getSpace("4dkankan", ossPath)); item.put("delSource", 0); item.put("toHaixin", 0); item.put("dictId", evidenceParamVO.getData().getInteger("dictId")); item.put("content", EvidenceBean.builder(). title(evidenceParamVO.getData().getString("title")) .collectedTime(evidenceParamVO.getData().getString("collectedTime")) .collectionModeName(evidenceParamVO.getData().getString("collectionModeName")) .createAccount(evidenceParamVO.getData().getString("createAccount")) .feature(evidenceParamVO.getData().getString("feature")) .leftPosition(evidenceParamVO.getData().getString("leftPosition")) .status(evidenceParamVO.getData().getInteger("status")).build()); ResultData resultData = manageHttpClient.addMediaLibrary(basePath, token, item); SceneMid sm = new SceneMid(); sms.add(sm); sm.setNum(param.getNum()); sm.setSid(media.getString("sid")); sm.setMid(resultData.getData().getLong("id")); } } //bgm JSONObject bgm = evidenceParamVO.getData().getJSONObject("bgm"); if(bgm != null && bgm.getIntValue("isAddMedia") == 1){ String ossPath = String.format(UploadFilePath.USER_EDIT_PATH, param.getNum()) + bgm.getString("src"); JSONObject item = new JSONObject(); params.add(item); item.put("dictId", evidenceParamVO.getData().getInteger("dictId")); item.put("num", param.getNum()); item.put("kno", scenePlus.getKNo()); item.put("filePath", ossPath); item.put("fileName", bgm.getString("name")); item.put("fileSize", fYunFileServiceInterface.getSpace("4dkankan", ossPath)); item.put("delSource", 0); item.put("toHaixin", 0); item.put("content", EvidenceBean.builder(). title(evidenceParamVO.getData().getString("title")) .collectedTime(evidenceParamVO.getData().getString("collectedTime")) .collectionModeName(evidenceParamVO.getData().getString("collectionModeName")) .createAccount(evidenceParamVO.getData().getString("createAccount")) .feature(evidenceParamVO.getData().getString("feature")) .leftPosition(evidenceParamVO.getData().getString("leftPosition")) .status(evidenceParamVO.getData().getInteger("status")).build()); ResultData resultData = manageHttpClient.addMediaLibrary(basePath, token, item); SceneMid sm = new SceneMid(); sms.add(sm); sm.setNum(param.getNum()); sm.setSid(bgm.getString("sid")); sm.setMid(resultData.getData().getLong("id")); } } if(CollUtil.isNotEmpty(sms)){ sceneMidService.saveBatch(sms); } //调用案件系统接口,进行推送 // if(CollUtil.isEmpty(params)){ // return null; // } // JSONObject playLoad = new JSONObject(); // playLoad.put("params", params); // ResultData> resultData = manageHttpClient.addMediaLibrarys(basePath, token, playLoad); // return resultData.getData().stream().map(v -> v.getLong("id")).collect(Collectors.toSet()); } private void addOrUpdateData(String num, String kno, String token, List dataList) throws Exception{ Set sidList = dataList.stream().map(v->v.getSid()).collect(Collectors.toSet()); List sceneEvidences = this.listByNumAndSids(num, sidList); Map dbMap = new HashMap<>(); if(CollUtil.isNotEmpty(sceneEvidences)){ dbMap = sceneEvidences.stream().collect(Collectors.toMap(v -> v.getSid(), v -> v)); } Map finalDbMap = dbMap; List collect = dataList.stream().map(v -> { SceneEvidence sceneEvidence = finalDbMap.get(v.getSid()); if (Objects.isNull(sceneEvidence)) { sceneEvidence = new SceneEvidence(); sceneEvidence.setNum(num); sceneEvidence.setSid(v.getSid()); // sceneEvidence.setMid(mid); } sceneEvidence.setUpdateTime(null); JSONObject evidenceContent = JSON.parseObject(v.getData().toString()); JSONArray medias = evidenceContent.getJSONArray("media"); if(CollUtil.isNotEmpty(medias)){ for (Object o : medias) { JSONObject media = (JSONObject) o; int isAddMedia = media.getIntValue("isAddMedia"); if(isAddMedia == 1){//如果标识是1,需要推送到媒体库 this.pushMedia(num, kno, v.getData(), media, token); } media.remove("isAddMedia"); } } JSONObject bgm = evidenceContent.getJSONObject("bgm"); if(bgm != null){ int isAddMedia = bgm.getIntValue("isAddMedia"); if(isAddMedia == 1){//如果标识是1,需要推送到媒体库 this.pushMedia(num, kno, v.getData(), bgm, token); } bgm.remove("isAddMedia"); } sceneEvidence.setEvidenceContent(evidenceContent); return sceneEvidence; }).collect(Collectors.toList()); this.saveOrUpdateBatch(collect); } private void pushMedia(String num, String kNo, JSONObject data, JSONObject media, String token){ String ossPath = String.format(UploadFilePath.USER_EDIT_PATH, num) + media.getString("src"); JSONObject item = new JSONObject(); item.put("num", num); item.put("kno", kNo); item.put("filePath", ossPath); item.put("fileName", media.getString("name")); item.put("fileSize", fYunFileServiceInterface.getSpace("4dkankan", ossPath)); item.put("delSource", 0); item.put("toHaixin", 0); item.put("dictId", data.getInteger("dictId")); item.put("content", EvidenceBean.builder(). title(data.getString("title")) .collectedTime(data.getString("collectedTime")) .collectionModeName(data.getString("collectionModeName")) .createAccount(data.getString("createAccount")) .feature(data.getString("feature")) .leftPosition(data.getString("leftPosition")) .status(data.getInteger("status")).build()); ResultData resultData = manageHttpClient.addMediaLibrary(basePath, token, item); SceneMid sm = new SceneMid(); sm.setNum(num); String sid = media.getString("sid"); if(StrUtil.isEmpty(sid)){ sid = FileUtil.getPrefix(media.getString("name")); } sm.setSid(sid); sm.setMid(resultData.getData().getLong("id")); sceneMidService.save(sm); media.put("mid", sm.getMid()); } private void addOrUpdateIcons(String num, List icons) throws Exception{ if(CollUtil.isEmpty(icons)){ return; } List sceneIconList = icons.stream().map(v -> { String sid = FileUtil.getPrefix(v.getName()); SceneIcon sceneIcon = new SceneIcon(); sceneIcon.setNum(num); sceneIcon.setSid(sid); sceneIcon.setName(v.getName()); sceneIcon.setDictId(v.getDictId()); sceneIcon.setBizType("evidence"); return sceneIcon; }).collect(Collectors.toList()); sceneIconService.saveBatch(sceneIconList); } @Override public void saveEvidenceToSceneEditInfo(String num, SceneEditInfo sceneEditInfo){ long count = this.count(new LambdaQueryWrapper().eq(SceneEvidence::getNum, num)); sceneEditInfo.setEvidence(count > 0 ? CommonStatus.YES.code() : CommonStatus.NO.code()); sceneEditInfo.setVersion(sceneEditInfo.getVersion() + 1); } @Override public List listByNumAndSids(String num, Set sids) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper().eq(SceneEvidence::getNum, num); if(CollUtil.isNotEmpty(sids)){ queryWrapper.in(SceneEvidence::getSid, sids); } return this.list(queryWrapper); } @Override public List listByNum(String num) { return this.list(new LambdaQueryWrapper().eq(SceneEvidence::getNum, num).orderByDesc(SceneEvidence::getUpdateTime)); } @Override public void deleteEvidence(DeleteSidListParamVO param) { ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum()); if (scenePlus == null) throw new BusinessException(ErrorCode.FAILURE_CODE_5005); //处理删除状态数据 this.remove(new LambdaQueryWrapper().eq(SceneEvidence::getNum, param.getNum()).in(SceneEvidence::getSid, param.getSidList())); //保存数据库 SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId()); this.saveEvidenceToSceneEditInfo(param.getNum(), sceneEditInfo); sceneEditInfoService.updateById(sceneEditInfo); this.reviseSceneMid(param.getNum()); } @Override public JSONObject listEvidences(String num) { JSONObject result = new JSONObject(); List sceneEvidences = this.listByNum(num); List evidenceContent = sceneEvidences.stream().map(v -> v.getEvidenceContent()).collect(Collectors.toList()); result.put("evidences", evidenceContent); List sceneIconList = sceneIconService.listByNum(num, "evidence").stream().collect(Collectors.toList()); result.put("icons", this.sortIcons(evidenceContent, sceneIconList)); return result; } private List sortIcons(List evidences, List icons){ if(CollUtil.isEmpty(icons)){ return null; } //统计使用频次 List iconBeans = Lists.newArrayList(); for (SceneIcon icon : icons) { int count = 0; for (JSONObject tag : evidences) { String sid = tag.getString("icon"); if(StrUtil.isEmpty(sid) || !icon.getName().equals(sid)){ continue; } ++count; } iconBeans.add(IconBean.builder().evidenceIconVO(BeanUtil.toBean(icon, EvidenceIconVO.class)).count(count).build()); } //排序 List collect = iconBeans.stream().sorted(Comparator.comparing(IconBean::getCount).reversed()) .map(item -> { return item.getEvidenceIconVO(); }).collect(Collectors.toList()); return collect; } @Override public void deleteIcons(DeleteHotIconParamVO param) { sceneIconService.remove( new LambdaQueryWrapper() .eq(SceneIcon::getBizType, "evidence") .eq(SceneIcon::getNum, param.getNum()) .in(SceneIcon::getName, param.getFileNameList())); } @Override public ResultData> traceEvidenceList(String token, TraceEvidenceListParamVO param) { ResultData> resultData = manageHttpClient.traceEvidenceList(basePath, token, param); return resultData; } @Override public ResultData traceEvidenceInfoList(String token, TraceEvidenceInfoListParamVo param) { return manageHttpClient.traceEvidenceInfoList(basePath, token, param); } @Override public ResultData refreshTraceEvidenceInfoList(String token, BaseSceneParamVO param) { ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum()); if(StrUtil.isEmpty(scenePlus.getKNo())){ return ResultData.ok(); } return manageHttpClient.refreshTraceEvidenceInfoList(basePath, token, scenePlus.getKNo()); } @Override public ResultData syncTraceEvidence(SaveEvidenceParamVO param) throws Exception { Integer resCode = ServerCode.SUCCESS.code(); ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum()); if (scenePlus == null) throw new BusinessException(ErrorCode.FAILURE_CODE_5005); //检验重复导入,一个痕迹物证在同一场景不能被多次导入 Map idMap = new HashMap<>(); for (EvidenceParamVO evidenceParamVO : param.getDataList()) { JSONArray media = evidenceParamVO.getData().getJSONArray("media"); for (Object o : media) { JSONObject mediaObj = JSON.parseObject(JSON.toJSONString(o)); idMap.put(mediaObj.getLong("mid"), mediaObj.getString("sid")); } JSONObject bgm = evidenceParamVO.getData().getJSONObject("bgm"); if (Objects.nonNull(bgm)) { idMap.put(bgm.getLong("mid"), FileUtil.getPrefix(bgm.getString("name"))); } } Set addMids = new HashSet<>(); Set repeatMids = new HashSet<>(); List list = sceneMidService.list(new LambdaQueryWrapper().eq(SceneMid::getNum, param.getNum()).in(SceneMid::getMid, idMap.keySet())); if(CollUtil.isNotEmpty(list)){//查出来不为空,就肯定是有重复的 Set dbMids = list.stream().map(v -> v.getMid()).collect(Collectors.toSet()); //过滤出重复的和不重复的 for (Long mid : idMap.keySet()) { if(dbMids.contains(mid)){ repeatMids.add(mid); }else{ addMids.add(mid); } } if(CollUtil.isEmpty(addMids)){//如果没有新增,那就是完全重复,直接终止程序 throw new BusinessException(JMErrorCode.FAILURE_CODE_20000.code(), JMErrorCode.FAILURE_CODE_20000.message()); }else{//如果有新增,又有重复,那就是部分导入 resCode = JMErrorCode.FAILURE_CODE_20001.code(); List repeatData = new ArrayList<>(); dataList : for (int i = 0; i < param.getDataList().size(); i++) { EvidenceParamVO evidenceParamVO = param.getDataList().get(i); JSONArray media = evidenceParamVO.getData().getJSONArray("media"); if(CollUtil.isNotEmpty(media)){ for (Object m : media) { JSONObject mediaObj = JSON.parseObject(JSON.toJSONString(m)); if(repeatMids.contains(mediaObj.getLong("mid"))){ repeatData.add(evidenceParamVO); continue dataList; } } } JSONObject bgm = evidenceParamVO.getData().getJSONObject("bgm"); if (Objects.nonNull(bgm)) { if(repeatMids.contains(bgm.getLong("mid"))){ repeatData.add(evidenceParamVO); } } } param.getDataList().removeAll(repeatData); log.info("-------------新增数据:{}", JSON.toJSONString(param.getDataList())); } } Map importMap = new HashMap<>(); List collect = param.getDataList().stream().map(v -> { JSONObject data = v.getData(); JSONArray medias = data.getJSONArray("media"); if (CollUtil.isNotEmpty(medias)) { medias.stream().forEach(m -> { LinkedHashMap media = (LinkedHashMap) m; String sid = (String) media.get("sid"); Long mid = Long.valueOf(media.get("mid").toString()); String path = (String)media.get("src"); String fileName = FileUtil.getName(path); String newFileName = sid + "." + FileUtil.extName(fileName); String meshKey = String.format(UploadFilePath.USER_EDIT_PATH, param.getNum()) + newFileName; if(path.startsWith("/oss/")){ path = path.replace("/oss/", ""); } fYunFileServiceInterface.copyFileInBucket(path, meshKey); media.put("src", newFileName); importMap.put(sid, mid); }); } JSONObject bgm = data.getJSONObject("bgm"); if(Objects.nonNull(bgm)){ String sid = FileUtil.getPrefix(bgm.getString("name")); Long mid = Long.valueOf(bgm.get("mid").toString()); importMap.put(sid, mid); } return data; }).collect(Collectors.toList()); List sceneMidList = importMap.keySet().stream().map(v -> { SceneMid sm = new SceneMid(); sm.setNum(param.getNum()); sm.setSid(v); sm.setMid(importMap.get(v)); return sm; }).collect(Collectors.toList()); sceneMidService.saveBatch(sceneMidList); this.saveEvidence(param, null); if(resCode == ServerCode.SUCCESS.code()){ return ResultData.ok(collect); }else{ return ResultData.error(resCode, "系统已为您去掉重复内容。", collect); } } // @Override // public void pushEvidence(BaseJsonArrayParamVO param) { // ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum()); // String kNo = scenePlus.getKNo(); // for (JSONObject datum : param.getData()) { // String fileName = datum.getString("fileName"); // String filePath = String.format(UploadFilePath.USER_EDIT_PATH, param.getNum()) + fileName; // datum.put("kno", kNo); // datum.put("filePath", filePath); // datum.put("fileSize", fYunFileServiceInterface.getSpace("4dkankan", filePath)); // datum.put("delSource", 0); // datum.put("toHaixin", 1); // manageHttpClient.addMediaLibrary(basePath, datum); // } // } @Override public void uploadScreenshot(String token, MultipartFile[] files, BaseJsonArrayParamVO data) throws IOException { String num = data.getNum(); Map fileDataMap = data.getData().stream().collect(Collectors.toMap(v -> v.getString("fileName"), v -> v)); ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num); if(scenePlus == null){ throw new BusinessException(ErrorCode.FAILURE_CODE_5005); } //这里注释调,因为燕海说没有KNO也可以通过此接口进行推送 // if(StrUtil.isEmpty(scenePlus.getKNo())){ // return; // } List params = new ArrayList<>(); for (MultipartFile file : files) { String fileName = file.getOriginalFilename(); // 获取文件后缀 String extName = fileName.substring(fileName.lastIndexOf(".")).toLowerCase(); fileName = UUID.randomUUID().toString().concat(extName); String path = String.format(ConstantFilePath.SCENE_TMP_PATH_V4, num).concat(fileName); FileUtil.mkParentDirs(path); file.transferTo(new File(path)); String ossPath = String.format(UploadFilePath.SCENE_NUM_PATH, num) + "screenshot/" + fileName; fYunFileServiceInterface.uploadFile(path, ossPath); FileUtils.delFile(path); JSONObject param = new JSONObject(); params.add(param); param.put("kno", scenePlus.getKNo()); param.put("filePath", ossPath); param.put("fileSize", fYunFileServiceInterface.getSpace("4dkankan", ossPath)); param.put("delSource", 1); param.put("toHaixin", 1); param.put("num", num); param.put("fileName", FileUtil.getPrefix(file.getOriginalFilename())); param.put("category", fileDataMap.get(file.getOriginalFilename()).getString("category")); } //调用案件系统接口,进行推送 JSONObject playLoad = new JSONObject(); playLoad.put("params", params); manageHttpClient.addMediaLibrarys(basePath, token, playLoad); } public static void main(String[] args) { String jsonStr = "{\"users\":[{\"name\":\"Alice\",\"age\":30},{\"name\":\"Bob\",\"age\":25}]}"; JSONObject jsonObj = JSON.parseObject(jsonStr); try { JSONArray usersArray = jsonObj.getJSONArray("users"); for (Object o : usersArray) { JSONObject userObj = (JSONObject) o; System.out.println("Name: " + userObj.getString("name") + ", Age: " + userObj.getIntValue("age")); } for (int i = 0; i < usersArray.size(); i++) { JSONObject userObj = usersArray.getJSONObject(i); System.out.println("Name: " + userObj.getString("name") + ", Age: " + userObj.getIntValue("age")); } } catch (JSONException e) { e.printStackTrace(); } } @Override public ResultData getCaseByNum(String num) { return manageHttpClient.getCaseByNum(basePath, num); } }