From b2adcec61d09d6ab79e297e6e364329ee1bbf97d Mon Sep 17 00:00:00 2001 From: guoshengxiong <1923636941@qq.com> Date: Fri, 25 Apr 2025 18:09:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8C=85=E5=A4=B4bug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/baotou/entity/UserDevGroup.java | 58 +-- .../impl/PlanFeedbackApprovalServiceImpl.java | 10 +- .../service/impl/PlanRecordServiceImpl.java | 2 + .../controller/BaseMenuController.java | 36 ++ .../controller/SystemUserController.java | 342 +++++++++++++----- .../zhgd/xmgl/modules/car/entity/CarInfo.java | 28 ++ .../modules/car/mapper/xml/CarInfoMapper.xml | 12 + .../car/service/impl/CarInfoServiceImpl.java | 136 ++++--- .../xz/service/IXzHikvisionSyncService.java | 2 + .../impl/XzHikvisionSyncServiceImpl.java | 26 ++ .../java/com/zhgd/xmgl/util/DateUtils.java | 120 +++++- src/main/resources/excel/车辆导入模板.xlsx | Bin 14448 -> 14724 bytes 12 files changed, 604 insertions(+), 168 deletions(-) diff --git a/src/main/java/com/zhgd/xmgl/modules/baotou/entity/UserDevGroup.java b/src/main/java/com/zhgd/xmgl/modules/baotou/entity/UserDevGroup.java index 07107a2f4..f90044ff1 100644 --- a/src/main/java/com/zhgd/xmgl/modules/baotou/entity/UserDevGroup.java +++ b/src/main/java/com/zhgd/xmgl/modules/baotou/entity/UserDevGroup.java @@ -23,26 +23,40 @@ import io.swagger.annotations.ApiModelProperty; public class UserDevGroup implements Serializable { private static final long serialVersionUID = 1L; - /**id*/ - @TableId(type = IdType.ASSIGN_ID) - @ApiModelProperty(value="id") - private java.lang.Long id ; - /**装置或项目组id*/ - @ApiModelProperty(value="装置或项目组id") - private java.lang.Long devGroupId ; - /**用户id*/ - @ApiModelProperty(value="用户id") - private java.lang.Long userId ; - /**节点id*/ - @ApiModelProperty(value="节点id") - private java.lang.String nodeId ; - /**1装置2项目组*/ - @ApiModelProperty(value="1装置2项目组") - private java.lang.Integer type ; - /**创建时间*/ - @ApiModelProperty(value="创建时间") - private java.util.Date createDate ; - /**更新时间*/ - @ApiModelProperty(value="更新时间") - private java.util.Date updateDate ; + /** + * id + */ + @TableId(type = IdType.ASSIGN_ID) + @ApiModelProperty(value = "id") + private java.lang.Long id; + /** + * 装置或项目组id + */ + @ApiModelProperty(value = "装置或项目组id") + private java.lang.Long devGroupId; + /** + * 用户id + */ + @ApiModelProperty(value = "用户id") + private java.lang.Long userId; + /** + * 节点id(装置不变,项目祖:装置+项目组id) + */ + @ApiModelProperty(value = "节点id(装置不变,项目祖:装置+项目组id)") + private java.lang.String nodeId; + /** + * 1装置2项目组 + */ + @ApiModelProperty(value = "1装置2项目组") + private java.lang.Integer type; + /** + * 创建时间 + */ + @ApiModelProperty(value = "创建时间") + private java.util.Date createDate; + /** + * 更新时间 + */ + @ApiModelProperty(value = "更新时间") + private java.util.Date updateDate; } diff --git a/src/main/java/com/zhgd/xmgl/modules/baotou/plan/service/impl/PlanFeedbackApprovalServiceImpl.java b/src/main/java/com/zhgd/xmgl/modules/baotou/plan/service/impl/PlanFeedbackApprovalServiceImpl.java index 36c738dce..fbdcb338f 100644 --- a/src/main/java/com/zhgd/xmgl/modules/baotou/plan/service/impl/PlanFeedbackApprovalServiceImpl.java +++ b/src/main/java/com/zhgd/xmgl/modules/baotou/plan/service/impl/PlanFeedbackApprovalServiceImpl.java @@ -183,10 +183,12 @@ public class PlanFeedbackApprovalServiceImpl extends ServiceImpl recordIdMap = planFeedbackService.getNewestFeedbackList(approvalWorks.stream().map(PlanFeedbackApprovalWork::getRecordId).collect(Collectors.toList())).stream().collect(Collectors.toMap(PlanFeedback::getRecordId, Function.identity(), (o1, o2) -> o1)); for (PlanFeedbackApprovalWork approvalWork : approvalWorks) { PlanFeedback planFeedback = recordIdMap.get(approvalWork.getRecordId()); - planFeedback.setApprovalStatus(2); - planFeedbackService.updateById(planFeedback); - approvalWork.setFeedbackId(planFeedback.getId()); - planFeedbackApprovalWorkService.updateById(approvalWork); + if (planFeedback != null) { + planFeedback.setApprovalStatus(2); + planFeedbackService.updateById(planFeedback); + approvalWork.setFeedbackId(planFeedback.getId()); + planFeedbackApprovalWorkService.updateById(approvalWork); + } } } diff --git a/src/main/java/com/zhgd/xmgl/modules/baotou/plan/service/impl/PlanRecordServiceImpl.java b/src/main/java/com/zhgd/xmgl/modules/baotou/plan/service/impl/PlanRecordServiceImpl.java index b197c9bd8..f9a246609 100644 --- a/src/main/java/com/zhgd/xmgl/modules/baotou/plan/service/impl/PlanRecordServiceImpl.java +++ b/src/main/java/com/zhgd/xmgl/modules/baotou/plan/service/impl/PlanRecordServiceImpl.java @@ -276,6 +276,8 @@ public class PlanRecordServiceImpl extends ServiceImpl 0) { throw new OpenAlertException("请先删除反馈数据"); } + planFeedbackApprovalWorkService.remove(new LambdaQueryWrapper() + .eq(PlanFeedbackApprovalWork::getRecordId, id)); baseMapper.deleteById(id); } diff --git a/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/BaseMenuController.java b/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/BaseMenuController.java index 98f96866c..18c921041 100644 --- a/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/BaseMenuController.java +++ b/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/BaseMenuController.java @@ -6,7 +6,9 @@ import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.gexin.fastjson.JSON; import com.wflow.bean.entity.WflowModelHistorys; import com.wflow.mapper.WflowModelHistorysMapper; import com.wflow.mapper.WflowModelsMapper; @@ -15,6 +17,8 @@ import com.zhgd.jeecg.common.mybatis.EntityMap; import com.zhgd.xmgl.modules.basicdata.entity.*; import com.zhgd.xmgl.modules.basicdata.service.*; import com.zhgd.xmgl.modules.basicdata.service.impl.DictionaryItemServiceImpl; +import com.zhgd.xmgl.modules.basicdata.service.impl.SystemUserServiceImpl; +import com.zhgd.xmgl.util.FlowUtil; import com.zhgd.xmgl.util.MapBuilder; import com.zhgd.xmgl.util.MessageUtil; import io.swagger.annotations.Api; @@ -348,4 +352,36 @@ public class BaseMenuController { } } +// //菜单清除有下级菜单的菜单path +// @PostMapping(value = "/ttt") +// public Result ttt(@RequestBody Map param) { +// SystemUser bthg = systemUserService.getOne(new LambdaQueryWrapper() +// .eq(SystemUser::getAccount, "bthg")); +// Map objectMap = systemUserService1.doLogin(new MapBuilder() +// .put("md5Password", "67395ff68eeba39368d5fa079788089b") +// .put("md5Password", "67395ff68eeba39368d5fa079788089b") +// .build(), bthg); +// Optional.ofNullable(objectMap.get("menuAuthority")).map(m->((Map) m).get("menuList")).ifPresent(m->{ +// com.gexin.fastjson.JSONArray array = JSON.parseArray(JSON.toJSONString(m)); +// for (int i = 0; i < array.size(); i++) { +// com.gexin.fastjson.JSONObject jsonObject = array.getJSONObject(i); +// listTree(jsonObject,null); +// } +// }); +// return Result.ok(); +// } +// +// private void listTree(com.gexin.fastjson.JSONObject jsonObject,com.gexin.fastjson.JSONObject parent) { +// if (!FlowUtil.isEmpty(jsonObject.get("menuList"))) { +// com.gexin.fastjson.JSONArray menuList = jsonObject.getJSONArray("menuList"); +// for (int i = 0; i < menuList.size(); i++) { +// com.gexin.fastjson.JSONObject jsonObject1 = menuList.getJSONObject(i); +// listTree(jsonObject1,jsonObject); +// } +// baseMenuService.update(new LambdaUpdateWrapper() +// .set(BaseMenu::getPath, "") +// .eq(BaseMenu::getMenuId, jsonObject.getString("menuId"))); +// } +// } + } diff --git a/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/SystemUserController.java b/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/SystemUserController.java index 685e602de..7e9861e10 100644 --- a/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/SystemUserController.java +++ b/src/main/java/com/zhgd/xmgl/modules/basicdata/controller/SystemUserController.java @@ -2,6 +2,7 @@ package com.zhgd.xmgl.modules.basicdata.controller; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.ObjectUtil; @@ -18,8 +19,13 @@ import com.zhgd.annotation.OperLog; import com.zhgd.jeecg.common.api.vo.Result; import com.zhgd.jeecg.common.execption.OpenAlertException; import com.zhgd.xmgl.constant.Cts; +import com.zhgd.xmgl.modules.baotou.entity.DeviceUnit; +import com.zhgd.xmgl.modules.baotou.entity.ProjectGroup; +import com.zhgd.xmgl.modules.baotou.entity.ProjectGroupUnit; import com.zhgd.xmgl.modules.baotou.entity.UserDevGroup; +import com.zhgd.xmgl.modules.baotou.service.IDeviceUnitService; import com.zhgd.xmgl.modules.baotou.service.IProjectGroupService; +import com.zhgd.xmgl.modules.baotou.service.IProjectGroupUnitService; import com.zhgd.xmgl.modules.baotou.service.IUserDevGroupService; import com.zhgd.xmgl.modules.basicdata.entity.BaseRole; import com.zhgd.xmgl.modules.basicdata.entity.DictionaryItem; @@ -28,10 +34,12 @@ import com.zhgd.xmgl.modules.basicdata.service.IBaseRoleService; import com.zhgd.xmgl.modules.basicdata.service.IDictionaryItemService; import com.zhgd.xmgl.modules.basicdata.service.ISystemUserService; import com.zhgd.xmgl.modules.basicdata.service.impl.NoticeServiceImpl; +import com.zhgd.xmgl.modules.worker.entity.EnterpriseInfo; import com.zhgd.xmgl.modules.worker.entity.UserDevAuthority; import com.zhgd.xmgl.modules.worker.entity.UserEnterprise; import com.zhgd.xmgl.modules.worker.entity.WorkerInfo; import com.zhgd.xmgl.modules.worker.service.IWorkerInfoService; +import com.zhgd.xmgl.modules.worker.service.impl.EnterpriseInfoServiceImpl; import com.zhgd.xmgl.modules.worker.service.impl.UserDevAuthorityServiceImpl; import com.zhgd.xmgl.modules.worker.service.impl.UserEnterpriseServiceImpl; import com.zhgd.xmgl.modules.xz.entity.XzProjectOrg; @@ -54,7 +62,6 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.servlet.ModelAndView; import springfox.documentation.annotations.ApiIgnore; import javax.servlet.http.HttpServletResponse; @@ -62,6 +69,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; import java.util.stream.Collectors; import static com.zhgd.xmgl.util.ExcelUtils.downLoadExcel; @@ -80,6 +88,9 @@ import static com.zhgd.xmgl.util.ExcelUtils.setPullDown; @Slf4j @Api(tags = "账号") public class SystemUserController { + @Lazy + @Autowired + IProjectGroupUnitService projectGroupUnitService; @Autowired private ISystemUserService systemUserService; @Lazy @@ -112,6 +123,12 @@ public class SystemUserController { @Lazy @Autowired private NoticeServiceImpl noticeService; + @Lazy + @Autowired + private EnterpriseInfoServiceImpl enterpriseInfoService; + @Lazy + @Autowired + private IDeviceUnitService deviceUnitService; /** * 添加 @@ -701,6 +718,86 @@ public class SystemUserController { return result; } +// +// @ApiOperation(value = "导出excel", notes = "导出excel", httpMethod = "POST") +// @ApiImplicitParams({ +// @ApiImplicitParam(name = "projectSn", value = "项目sn", paramType = "body", required = true, dataType = "String"), +// @ApiImplicitParam(name = "type", value = "1项目2装置", paramType = "query", required = true, dataType = "String"), +// @ApiImplicitParam(name = "leftId", value = "左边Id", paramType = "query", required = true, dataType = "String"), +// }) +// @PostMapping(value = "/exportXls") +// public ModelAndView exportXls(@ApiIgnore @RequestBody HashMap paramMap) { +// // Step.1 组装查询条件 +// List pageList = planMilestone2RightService.queryList(paramMap); +// Map map = new HashMap<>(); +// List> listMap = new ArrayList<>(); +// if (pageList.size() > 0) { +// for (PlanMilestone2Right p : pageList) { +// Map mp = new HashMap<>(); +// mp.put("leftId", p.getLeftId()); +// mp.put("leftName", p.getClassifyName()); +// mp.put("projectSn", p.getProjectSn()); +// mp.put("name", p.getName()); +// mp.put("beginDate", DateUtil.formatDate(p.getBeginDate())); +// mp.put("endDate", p.getEndDate()); +// List nodeStatus = Arrays.asList("关键控制点", "重要事件的控制", "作业项目的节点"); +// List iss = Arrays.asList("否", "是"); +// try { +// mp.put("nodeStatus", nodeStatus.get(p.getNodeStatus() - 1)); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// try { +// mp.put("completeType", iss.get(p.getCompleteType())); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// try { +// mp.put("isImportantMilestone", iss.get(p.getIsImportantMilestone())); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// mp.put("createTime", p.getCreateTime()); +// mp.put("updateTime", p.getUpdateTime()); +// mp.put("useTimeType", Objects.equals(p.getUseTimeType(), 1) ? "开始时间" : "结束时间"); +// mp.put("type", p.getType()); +// listMap.add(mp); +// } +// } +// //将项目清单集合添加到map中 +// map.put("listMap", listMap); +// InputStream fis = null; +// try { +// fis = new ClassPathResource("excel/总体统筹计划编制导出模板.xlsx").getInputStream(); +//// fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\总体统筹计划编制导出模板.xlsx"); +// File out = new File(new File(System.getProperty("user.dir").replace("file:/", "/").replace("\\", "/"), "tmp"), "系统项目组危险源辨别评价表模板.xlsx"); +// if (!out.getParentFile().exists()) { +// out.getParentFile().mkdirs(); +// } +// IOUtils.copy(fis, out); +// //获取模板 +// TemplateExportParams params = new TemplateExportParams(out.getAbsolutePath()); +// //模板视图 +// ModelAndView mv = new ModelAndView(new JeecgTemplateExcelView()); +// //添加表格参数 +// mv.addObject(TemplateExcelConstants.PARAMS, params); +// //添加模板参数 +// mv.addObject(TemplateExcelConstants.MAP_DATA, map); +// return mv; +// } catch (IOException e) { +// log.error("", e); +// throw new OpenAlertException("系统错误"); +// } finally { +// if (fis != null) { +// try { +// fis.close(); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// } +// } + /** * 保存角色(如果不存在) * @@ -791,86 +888,6 @@ public class SystemUserController { } -// -// @ApiOperation(value = "导出excel", notes = "导出excel", httpMethod = "POST") -// @ApiImplicitParams({ -// @ApiImplicitParam(name = "projectSn", value = "项目sn", paramType = "body", required = true, dataType = "String"), -// @ApiImplicitParam(name = "type", value = "1项目2装置", paramType = "query", required = true, dataType = "String"), -// @ApiImplicitParam(name = "leftId", value = "左边Id", paramType = "query", required = true, dataType = "String"), -// }) -// @PostMapping(value = "/exportXls") -// public ModelAndView exportXls(@ApiIgnore @RequestBody HashMap paramMap) { -// // Step.1 组装查询条件 -// List pageList = planMilestone2RightService.queryList(paramMap); -// Map map = new HashMap<>(); -// List> listMap = new ArrayList<>(); -// if (pageList.size() > 0) { -// for (PlanMilestone2Right p : pageList) { -// Map mp = new HashMap<>(); -// mp.put("leftId", p.getLeftId()); -// mp.put("leftName", p.getClassifyName()); -// mp.put("projectSn", p.getProjectSn()); -// mp.put("name", p.getName()); -// mp.put("beginDate", DateUtil.formatDate(p.getBeginDate())); -// mp.put("endDate", p.getEndDate()); -// List nodeStatus = Arrays.asList("关键控制点", "重要事件的控制", "作业项目的节点"); -// List iss = Arrays.asList("否", "是"); -// try { -// mp.put("nodeStatus", nodeStatus.get(p.getNodeStatus() - 1)); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// try { -// mp.put("completeType", iss.get(p.getCompleteType())); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// try { -// mp.put("isImportantMilestone", iss.get(p.getIsImportantMilestone())); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// mp.put("createTime", p.getCreateTime()); -// mp.put("updateTime", p.getUpdateTime()); -// mp.put("useTimeType", Objects.equals(p.getUseTimeType(), 1) ? "开始时间" : "结束时间"); -// mp.put("type", p.getType()); -// listMap.add(mp); -// } -// } -// //将项目清单集合添加到map中 -// map.put("listMap", listMap); -// InputStream fis = null; -// try { -// fis = new ClassPathResource("excel/总体统筹计划编制导出模板.xlsx").getInputStream(); -//// fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\总体统筹计划编制导出模板.xlsx"); -// File out = new File(new File(System.getProperty("user.dir").replace("file:/", "/").replace("\\", "/"), "tmp"), "系统项目组危险源辨别评价表模板.xlsx"); -// if (!out.getParentFile().exists()) { -// out.getParentFile().mkdirs(); -// } -// IOUtils.copy(fis, out); -// //获取模板 -// TemplateExportParams params = new TemplateExportParams(out.getAbsolutePath()); -// //模板视图 -// ModelAndView mv = new ModelAndView(new JeecgTemplateExcelView()); -// //添加表格参数 -// mv.addObject(TemplateExcelConstants.PARAMS, params); -// //添加模板参数 -// mv.addObject(TemplateExcelConstants.MAP_DATA, map); -// return mv; -// } catch (IOException e) { -// log.error("", e); -// throw new OpenAlertException("系统错误"); -// } finally { -// if (fis != null) { -// try { -// fis.close(); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// } -// } -// } - @ApiOperation(value = "勾选导出项目子账号word", notes = "勾选导出项目子账号word", httpMethod = "POST") @ApiImplicitParams({ @ApiImplicitParam(name = "projectSn", value = "项目sn", paramType = "body", required = true, dataType = "String"), @@ -895,4 +912,167 @@ public class SystemUserController { url = Fileutils.getExportTemplateFile("excel/work/勾选导出项目子账号模板.docx").getAbsolutePath(); EasyPoiUtil.exportNewLineWord(response, map, FileUtil.file(url)); } + + @ApiOperation(value = "项目子账号批量分配装置项目组和单位权限(根据项目组和装置那里的绑定关系)", notes = "项目子账号批量分配装置项目组和单位权限(根据项目组和装置那里的绑定关系)", httpMethod = "POST") + @ApiImplicitParams({ + @ApiImplicitParam(name = "projectSn", value = "项目sn", paramType = "body", required = true, dataType = "String"), + @ApiImplicitParam(name = "userIdList", value = "用户id数组", paramType = "body", required = true, dataType = "String"), + }) + @PostMapping(value = "/batchAuthSubAccount") + public Result batchAuthSubAccount(@ApiIgnore @RequestBody HashMap param) { + List userIdList = com.gexin.fastjson.JSON.parseObject(JSON.toJSONString(param.get("userIdList")), new TypeReference>() { + }); + if (CollUtil.isEmpty(userIdList)) { + return Result.ok(); + } + String projectSn = MapUtils.getString(param, "projectSn"); + List enterpriseInfos = BeanUtil.copyToList(enterpriseInfoService.getEnterpriseInfoList(new MapBuilder() + .put("projectSn", projectSn) + .build()), EnterpriseInfo.class); + Map enterpriseNameMap = enterpriseInfos.stream().collect(Collectors.toMap(EnterpriseInfo::getEnterpriseName, Function.identity(), (o1, o2) -> o1)); + Map enterpriseMap = enterpriseInfos.stream().collect(Collectors.toMap(EnterpriseInfo::getId, Function.identity(), (o1, o2) -> o1)); + Map groupMap = projectGroupService.list(new LambdaQueryWrapper() + .eq(ProjectGroup::getProjectSn, projectSn)).stream().collect(Collectors.toMap(ProjectGroup::getId, Function.identity(), (o1, o2) -> o1)); + List deviceUnits = deviceUnitService.queryList(new MapBuilder() + .put("projectSn", projectSn) + .build()); + List systemUserList = systemUserService.getProjectChildernSystemUserList(new MapBuilder() + .put("userIdList", userIdList) + .put("projectSn", projectSn) + .build()); + Map> enterpriseUserMap = systemUserList.stream().collect(Collectors.groupingBy(SystemUser::getEnterpriseId)); + //分配装置项目组 + List userDevGroups = new ArrayList<>(); + for (DeviceUnit deviceUnit : deviceUnits) { + for (Map.Entry> entry : enterpriseUserMap.entrySet()) { + String enterpriseId = entry.getKey() + ""; + List users = entry.getValue(); + if (users != null) { + for (SystemUser user : users) { + if (Objects.equals(user.getUserType(), "1")) { + //部门用户分配所有装置项目组和单位 + addUserDevGroup(userDevGroups, deviceUnit, user); + } else if (Objects.equals(user.getUserType(), "2")) { + //项目组用户 + Optional.ofNullable(enterpriseMap.get(Convert.toLong(enterpriseId))).map(EnterpriseInfo::getEnterpriseName) + .flatMap(m -> StrUtil.split(deviceUnit.getProjectGroupIds(), ",").stream().map(s -> groupMap.get(Convert.toLong(s))) + .filter(group -> group != null && group.getProjectGroupName().equals(m)).findAny()).ifPresent(projectGroup -> { + addUserDevGroupForGroup(userDevGroups, deviceUnit, user, projectGroup); + }); + } else { + //项目组单位、监理单位、EPC/E+P+C承包商、施工单位分配(装置管理)装置项目组 + if (StrUtil.contains(deviceUnit.getSupervisingUnitIds(), enterpriseId) + || StrUtil.contains(deviceUnit.getEpcContractorIds(), enterpriseId) + || StrUtil.contains(deviceUnit.getConstructionUnitIds(), enterpriseId)) { + addUserDevGroup(userDevGroups, deviceUnit, user); + } + } + } + } + } + } + userDevGroupService.remove(new LambdaQueryWrapper() + .in(UserDevGroup::getUserId, userIdList)); + userDevGroupService.saveBatch(userDevGroups); + + //分配单位 + //部门用户分配所有装置项目组和单位 + Set authAllEnterpriseIdList = new HashSet<>(); + for (EnterpriseInfo enterpriseInfo : enterpriseInfos) { + authAllEnterpriseIdList.add(enterpriseInfo.getId()); + } + List userEnterprises = new ArrayList<>(); + //部门用户分配所有装置项目组和单位 + List projectGroupUnits = projectGroupUnitService.list(new LambdaQueryWrapper() + .eq(ProjectGroupUnit::getProjectSn, projectSn)); + for (Map.Entry> entry : enterpriseUserMap.entrySet()) { + //项目组单位、监理单位、EPC/E+P+C承包商、施工单位分配所有后代和祖级单位(项目组管理) + Set authEnterpriseIdList = new HashSet<>(); + //项目组用户 + Set authGroupEnterpriseIdList = new HashSet<>(); + Long enterpriseId = entry.getKey(); + authEnterpriseIdList.add(enterpriseId); + for (ProjectGroupUnit pgu : projectGroupUnits) { + Optional.ofNullable(groupMap.get(pgu.getProjectGroupId())).map(ProjectGroup::getProjectGroupName).map(enterpriseNameMap::get).map(EnterpriseInfo::getId) + .ifPresent(e -> { + authEnterpriseIdList.add(e); + authGroupEnterpriseIdList.add(e); + authGroupEnterpriseIdList.add(pgu.getSupervisingUnitId()); + authGroupEnterpriseIdList.add(pgu.getEpcContractorId()); + authGroupEnterpriseIdList.addAll(StrUtil.split(pgu.getConstructionUnitIds(), ",").stream().map(Convert::toLong).collect(Collectors.toList())); + });//保存项目组单位 + if (Objects.equals(pgu.getSupervisingUnitId(), enterpriseId)) { + authEnterpriseIdList.add(pgu.getEpcContractorId()); + authEnterpriseIdList.addAll(StrUtil.split(pgu.getConstructionUnitIds(), ",").stream().map(Convert::toLong).collect(Collectors.toList())); + } + if (Objects.equals(pgu.getEpcContractorId(), enterpriseId)) { + authEnterpriseIdList.add(pgu.getSupervisingUnitId()); + authEnterpriseIdList.addAll(StrUtil.split(pgu.getConstructionUnitIds(), ",").stream().map(Convert::toLong).collect(Collectors.toList())); + } + if (StrUtil.contains(pgu.getConstructionUnitIds(), enterpriseId + "")) { + authEnterpriseIdList.add(pgu.getSupervisingUnitId()); + authEnterpriseIdList.add(pgu.getEpcContractorId()); + } + } + List userList = entry.getValue(); + if (userList != null) { + for (SystemUser user : userList) { + UserEnterprise userEnterprise = new UserEnterprise(); + userEnterprise.setUserId(user.getUserId()); + userEnterprise.setEnterpriseId(StrUtil.join(",", + (Objects.equals(user.getUserType(), "1") ? authAllEnterpriseIdList : (Objects.equals(user.getUserType(), "2") ? authGroupEnterpriseIdList : authEnterpriseIdList)) + .stream().filter(Objects::nonNull).collect(Collectors.toList()))); + userEnterprises.add(userEnterprise); + } + } + } + userEnterpriseService.remove(new LambdaQueryWrapper() + .in(UserEnterprise::getUserId, userIdList)); + userEnterpriseService.saveBatch(userEnterprises); + return Result.ok(); + } + + /** + * 项目组添加装置项目组权限 + */ + private void addUserDevGroupForGroup(List userDevGroups, DeviceUnit deviceUnit, SystemUser user, ProjectGroup projectGroup) { + UserDevGroup dev = new UserDevGroup(); + dev.setDevGroupId(deviceUnit.getId()); + dev.setUserId(user.getUserId()); + dev.setNodeId(deviceUnit.getId() + ""); + dev.setType(1); + userDevGroups.add(dev); + UserDevGroup group = new UserDevGroup(); + group.setDevGroupId(projectGroup.getId()); + group.setUserId(user.getUserId()); + group.setNodeId(projectGroup.getId() + "" + deviceUnit.getId()); + group.setType(2); + userDevGroups.add(group); + } + + /** + * 添加装置项目组权限 + * + * @param userDevGroups + * @param deviceUnit + * @param user + */ + private void addUserDevGroup(List userDevGroups, DeviceUnit deviceUnit, SystemUser user) { + UserDevGroup dev = new UserDevGroup(); + dev.setDevGroupId(deviceUnit.getId()); + dev.setUserId(user.getUserId()); + dev.setNodeId(deviceUnit.getId() + ""); + dev.setType(1); + userDevGroups.add(dev); + if (StrUtil.isNotBlank(deviceUnit.getProjectGroupIds())) { + for (String groupId : StrUtil.split(deviceUnit.getProjectGroupIds(), ",")) { + UserDevGroup group = new UserDevGroup(); + group.setDevGroupId(Long.valueOf(groupId)); + group.setUserId(user.getUserId()); + group.setNodeId(groupId + deviceUnit.getId() + ""); + group.setType(2); + userDevGroups.add(group); + } + } + } } diff --git a/src/main/java/com/zhgd/xmgl/modules/car/entity/CarInfo.java b/src/main/java/com/zhgd/xmgl/modules/car/entity/CarInfo.java index 564dca9e3..fcbc4b8b1 100644 --- a/src/main/java/com/zhgd/xmgl/modules/car/entity/CarInfo.java +++ b/src/main/java/com/zhgd/xmgl/modules/car/entity/CarInfo.java @@ -140,6 +140,28 @@ public class CarInfo implements Serializable { private java.lang.String carQrCode; @ApiModelProperty(value = "特殊工种操作证") private java.lang.String specialWorkType; + @ApiModelProperty(value = "编号") + private java.lang.String num; + @ApiModelProperty(value = "到检日期yyyy-MM-dd") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date inspectionDate; + @ApiModelProperty(value = "保险终止日yyyy-MM-dd") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date insuranceTerminationDate; + @ApiModelProperty(value = "行驶证开始有效期yyyy-MM-dd") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date xszBeginDate; + @ApiModelProperty(value = "行驶证结束有效期yyyy-MM-dd") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date xszEndDate; + @ApiModelProperty(value = "计划入厂时间截止到yyyy-MM-dd") + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private Date enterFactoryEndDate; @TableField(exist = false) @ApiModelProperty(value = "企业名称") @@ -164,6 +186,12 @@ public class CarInfo implements Serializable { public String toExistString() { return "CarInfo{" + + ", enterFactoryEndDate='" + enterFactoryEndDate + '\'' + + ", xszEndDate='" + xszEndDate + '\'' + + ", xszBeginDate='" + xszBeginDate + '\'' + + ", insuranceTerminationDate='" + insuranceTerminationDate + '\'' + + ", inspectionDate='" + inspectionDate + '\'' + + ", num='" + num + '\'' + ", carNumber='" + carNumber + '\'' + ", carColor='" + carColor + '\'' + ", projectSn='" + projectSn + '\'' + diff --git a/src/main/java/com/zhgd/xmgl/modules/car/mapper/xml/CarInfoMapper.xml b/src/main/java/com/zhgd/xmgl/modules/car/mapper/xml/CarInfoMapper.xml index 70f2c04d5..4a4cc43aa 100644 --- a/src/main/java/com/zhgd/xmgl/modules/car/mapper/xml/CarInfoMapper.xml +++ b/src/main/java/com/zhgd/xmgl/modules/car/mapper/xml/CarInfoMapper.xml @@ -34,6 +34,18 @@ t.car_qr_code , t.special_work_type + , + t.num + , + t.inspection_date + , + t.insurance_termination_date + , + t.xsz_begin_date + , + t.xsz_end_date + , + t.enter_factory_end_date FROM car_info t join project p on p.project_sn = t.project_sn LEFT JOIN car_type b ON (t.car_type = b.id and t.project_sn = b.project_sn) diff --git a/src/main/java/com/zhgd/xmgl/modules/car/service/impl/CarInfoServiceImpl.java b/src/main/java/com/zhgd/xmgl/modules/car/service/impl/CarInfoServiceImpl.java index a2d9b9cee..69c756186 100644 --- a/src/main/java/com/zhgd/xmgl/modules/car/service/impl/CarInfoServiceImpl.java +++ b/src/main/java/com/zhgd/xmgl/modules/car/service/impl/CarInfoServiceImpl.java @@ -41,6 +41,7 @@ import com.zhgd.xmgl.modules.worker.service.impl.WorkerInfoServiceImpl; import com.zhgd.xmgl.modules.xz.entity.XzHikvisionSync; import com.zhgd.xmgl.modules.xz.mapper.XzHikvisionSyncMapper; import com.zhgd.xmgl.modules.xz.service.impl.XzHikvisionCompareDataServiceImpl; +import com.zhgd.xmgl.modules.xz.service.impl.XzHikvisionSyncServiceImpl; import com.zhgd.xmgl.security.entity.UserInfo; import com.zhgd.xmgl.security.util.SecurityUtils; import com.zhgd.xmgl.util.*; @@ -56,9 +57,8 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.File; -import java.io.FileInputStream; -import java.io.FilterInputStream; import java.io.InputStream; +import java.time.LocalDate; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -100,6 +100,9 @@ public class CarInfoServiceImpl extends ServiceImpl impl WorkerInfoServiceImpl workerInfoService; @Lazy @Autowired + XzHikvisionSyncServiceImpl xzHikvisionSyncService; + @Lazy + @Autowired private XzHikvisionSyncMapper xzHikvisionSyncMapper; @Autowired private EnterpriseInfoServiceImpl enterpriseInfoService; @@ -211,14 +214,14 @@ public class CarInfoServiceImpl extends ServiceImpl impl .eq(CarInfoApprovalFlow::getCarNumber, c.getCarNumber()) .last(Cts.IGNORE_DATA_SCOPE_CONDITION) ); - List otherFlows = flows.stream().filter(f -> !Objects.equals(c.getEnterpriseId(), f.getEnterpriseId())).collect(Collectors.toList()); - boolean overlap = otherFlows.stream().anyMatch(f -> DateUtil.compare(f.getReserveStartTime(), c.getReserveEndTime()) < 0 && DateUtil.compare(f.getReserveEndTime(), c.getReserveStartTime()) > 0); - if (overlap) { - List> dumplictcatePeriods = DateUtils.getTimePeriodListDumplictcatePeriod(otherFlows.stream().map(f -> (Map) new MapBuilder().put("startDate", f.getReserveStartTime()).put("endDate", f.getReserveEndTime()).build()).collect(Collectors.toList())); - List dateList = dumplictcatePeriods.stream().map(f -> DateUtil.formatDateTime(f.get("startDate")) + "到" + DateUtil.formatDateTime(f.get("endDate"))).collect(Collectors.toList()); -// throw new OpenAlertException(StrUtil.format("此预约时间段内({}),车辆已经被其他企业预约了,请修改预约时间!", StrUtil.join(",", dateList))); - throw new OpenAlertException("此预约时间段内,车辆已经被其他企业预约了,请修改预约时间!"); - } + List otherFlows = flows.stream().filter(f -> f.getEnterpriseId() != null && !Objects.equals(c.getEnterpriseId(), f.getEnterpriseId()) + && (DateUtil.compare(f.getReserveStartTime(), c.getReserveStartTime()) != 0 || DateUtil.compare(f.getReserveEndTime(), c.getReserveEndTime()) != 0)).collect(Collectors.toList()); + otherFlows.stream().filter(f -> DateUtil.compare(f.getReserveStartTime(), c.getReserveEndTime()) < 0 && DateUtil.compare(f.getReserveEndTime(), c.getReserveStartTime()) > 0).findAny().ifPresent(flowCar -> { + throw new OpenAlertException(StrUtil.format("车牌号:{},此预约时间段内({}到{}),车辆已经被其他企业预约了({}到{}),请修改预约时间!", + c.getCarNumber(), DateUtil.formatDateTime(c.getReserveStartTime()), DateUtil.formatDateTime(c.getReserveEndTime()), + DateUtil.formatDateTime(flowCar.getReserveStartTime()), DateUtil.formatDateTime(flowCar.getReserveEndTime()))); + }); + } @Override @@ -233,11 +236,13 @@ public class CarInfoServiceImpl extends ServiceImpl impl } @Override + @Transactional(propagation = Propagation.NOT_SUPPORTED) public Result uploadExcelCar(File file, String projectSn) { - Result result = new Result(); + Result result = new Result<>(); + StringBuilder notExistEnterprise = new StringBuilder(""); + String notExistEnterpriseMsg = ""; StringBuilder existCarNumName = new StringBuilder(""); String existCarNumMsg = ""; - ArrayList errIdCards = new ArrayList<>(); String rtMsg = ""; StringBuilder existWorkerName = new StringBuilder(""); String existWorkerNameMsg = ""; @@ -251,13 +256,13 @@ public class CarInfoServiceImpl extends ServiceImpl impl if (list == null || list.size() == 0) { throw new OpenAlertException(MessageUtil.get("excelNotDataErr")); } - this.checkParams(list, projectSn); + this.checkParams(list); Map enterpriseInfoMap = projectEnterpriseService.queryPageList(new MapBuilder() .put("projectSn", projectSn) .put(Cts.PAGE_SIZE, -1) .build()).getRecords().stream().collect(Collectors.toMap(EnterpriseInfo::getEnterpriseName, Function.identity(), (enterpriseInfo, enterpriseInfo2) -> enterpriseInfo)); Map numMap = carInfoMapper.selectList(new LambdaQueryWrapper() - .in(CarInfo::getCarNumber, list.stream().map(o -> o.get("车牌号")).collect(Collectors.toList())) + .in(CarInfo::getCarNumber, list.stream().map(o -> StrUtil.trim(o.get("*车牌号")).toUpperCase(Locale.ROOT)).collect(Collectors.toList())) .last(Cts.IGNORE_DATA_SCOPE_CONDITION)).stream().collect(Collectors.toMap(CarInfo::getCarNumber, Function.identity())); Map workerMap = workerInfoService.list(new LambdaQueryWrapper() .eq(WorkerInfo::getProjectSn, projectSn) @@ -267,33 +272,64 @@ public class CarInfoServiceImpl extends ServiceImpl impl .last(Cts.IGNORE_DATA_SCOPE_CONDITION) ).stream().collect(Collectors.toMap(CarType::getCarTypeName, Function.identity(), (o1, o2) -> o1)); for (Map importInfo : list) { + String carNumber = StrUtil.trim(importInfo.get("*车牌号")).toUpperCase(Locale.ROOT); + String workerName = StrUtil.trim(importInfo.get("司机姓名")); String carModuleType = importInfo.get("*车辆类型"); - CarInfo dataCar = numMap.get(importInfo.get("*车牌号")); + CarInfo dataCar = numMap.get(carNumber); CarInfo excelCar = new CarInfo(); - excelCar.setCarNumber(importInfo.get("*车牌号")); - excelCar.setCarColor(importInfo.get("*车辆颜色")); + String num = StrUtil.trim(importInfo.get("*编号")); + excelCar.setNum(num); + if (StrUtil.isNotBlank(importInfo.get("到检日期"))) { + excelCar.setInspectionDate(DateUtil.parseDate(importInfo.get("到检日期"))); + } + if (StrUtil.isNotBlank(importInfo.get("保险终止日"))) { + excelCar.setInsuranceTerminationDate(DateUtil.parseDate(importInfo.get("保险终止日"))); + } + String xszDate = importInfo.get("行驶证有效期"); + if (StrUtil.isNotBlank(xszDate)) { + List range = DateUtils.parseDateRange(xszDate); + if (range != null) { + excelCar.setXszBeginDate(range.get(0)); + excelCar.setXszEndDate(range.get(1)); + } + } + if (StrUtil.isNotBlank(importInfo.get("计划入厂时间截止到"))) { + excelCar.setEnterFactoryEndDate(DateUtil.parseDate(importInfo.get("计划入厂时间截止到"))); + } + excelCar.setCarNumber(carNumber); + excelCar.setCarColor(importInfo.get("车辆颜色")); excelCar.setAddTime(new Date()); excelCar.setProjectSn(projectSn); - String readWorkerName = importInfo.get("*司机姓名"); if (!"临时车辆".equals(carModuleType)) { - WorkerInfo workerInfo = workerMap.get(readWorkerName); + WorkerInfo workerInfo = workerMap.get(workerName); if (workerInfo == null) { - existWorkerName.append(readWorkerName); - existWorkerName.append("、"); - log.info("在人员管理中不存在:{}", readWorkerName); - continue; + if (workerName != null) { + existWorkerName.append(workerName); + existWorkerName.append("、"); + } + log.info("在人员管理中不存在:{}", workerName); + } else { + excelCar.setDriverWorkerId(String.valueOf(workerInfo.getId())); } - excelCar.setDriverWorkerId(String.valueOf(workerInfo.getId())); } - excelCar.setDriverWorkerName(readWorkerName); - excelCar.setDriverTelephone(importInfo.get("*司机电话")); + excelCar.setDriverWorkerName(workerName); + String driverTelephone = StrUtil.trim(importInfo.get("司机电话")); + excelCar.setDriverTelephone(driverTelephone); excelCar.setIsBlack(Objects.equals(importInfo.get("*是否黑名单"), "是") ? 1 : 0); excelCar.setCarType(Optional.ofNullable(carTypeMap.get(importInfo.get("*车种类型"))).map(CarType::getId).orElse(null)); excelCar.setCarModuleType("固定车辆".equals(carModuleType) ? 1 : ("长期车辆".equals(carModuleType) ? 2 : 3)); excelCar.setReserveStartTime(DateUtil.parse(importInfo.get("预约开始时间"))); excelCar.setReserveEndTime(DateUtil.parse(importInfo.get("预约结束时间"))); excelCar.setEntryAndExitPermit("单次".equals(importInfo.get("允许进出次数")) ? 0 : 1); - excelCar.setEnterpriseId(Optional.ofNullable(enterpriseInfoMap.get(importInfo.get("*单位"))).map(EnterpriseInfo::getId).orElse(null)); + String enterpriseName = StrUtil.trim(importInfo.get("*单位")); + Optional enterpriseIdOp = Optional.ofNullable(enterpriseInfoMap.get(enterpriseName)).map(EnterpriseInfo::getId); + if (!enterpriseIdOp.isPresent()) { + //没有企业的不保存 + notExistEnterprise.append(excelCar.getCarNumber()).append("(").append(enterpriseName).append(")"); + notExistEnterprise.append("、"); + continue; + } + excelCar.setEnterpriseId(enterpriseIdOp.get()); if (dataCar == null) { this.addCarInfo(excelCar); } else { @@ -308,7 +344,10 @@ public class CarInfoServiceImpl extends ServiceImpl impl this.editCarInfo(excelCar); } } - + if (!"".equals(notExistEnterprise.toString())) { + notExistEnterprise.deleteCharAt(notExistEnterprise.lastIndexOf("、")); + notExistEnterpriseMsg = "车牌号为:" + notExistEnterprise + "的车辆企业不存在。"; + } if (!"".equals(existCarNumName.toString())) { existCarNumName.deleteCharAt(existCarNumName.lastIndexOf("、")); existCarNumMsg = "车牌号为:" + existCarNumName + "的车辆已存在对应信息(车牌号等信息一致)。"; @@ -317,7 +356,7 @@ public class CarInfoServiceImpl extends ServiceImpl impl existWorkerName.deleteCharAt(existWorkerName.lastIndexOf("、")); existWorkerNameMsg = "司机姓名:" + existWorkerName + "在人员管理中不存在。"; } - rtMsg = StrUtil.format("导入成功。{}{}", existCarNumMsg, existWorkerNameMsg); + rtMsg = StrUtil.format("操作成功。{}{}{}", existCarNumMsg, existWorkerNameMsg, notExistEnterpriseMsg); result.successMsg(rtMsg); } catch (OpenAlertException e) { log.error("error:", e); @@ -335,34 +374,30 @@ public class CarInfoServiceImpl extends ServiceImpl impl return result; } - private void checkParams(List> list, String projectSn) { + private void checkParams(List> list) { for (Map importInfo : list) { + if (StringUtils.isBlank(importInfo.get("*编号"))) { + throw new OpenAlertException("有编号未填写"); + } if (StringUtils.isBlank(importInfo.get("*单位"))) { throw new OpenAlertException("有单位未填写"); } if (StringUtils.isBlank(importInfo.get("*车辆类型"))) { throw new OpenAlertException("有车辆类型未填写"); } - if (StringUtils.isBlank(importInfo.get("*车牌号"))) { + String carNum = importInfo.get("*车牌号"); + if (StringUtils.isBlank(carNum)) { throw new OpenAlertException("有车牌号未填写"); } - if (StringUtils.isBlank(importInfo.get("*车辆颜色"))) { - throw new OpenAlertException("有车辆颜色未填写"); - } if (StringUtils.isBlank(importInfo.get("*车种类型"))) { throw new OpenAlertException("有车种类型未填写"); } - if (StringUtils.isBlank(importInfo.get("*司机姓名"))) { - throw new OpenAlertException("有司机姓名未填写"); - } - if (StringUtils.isBlank(importInfo.get("*司机电话"))) { - throw new OpenAlertException("有司机电话未填写"); - } - if (StringUtils.isBlank(importInfo.get("*司机电话"))) { - throw new OpenAlertException("有司机电话未填写"); - } if (!"固定车辆".equals(importInfo.get("*车辆类型")) && DateUtil.compare(DateUtil.parse(importInfo.get("预约结束时间")), new Date()) < 0) { - throw new OpenAlertException("预约时间已失效,车辆" + importInfo.get("*车牌号") + "无法下发,请重新提交"); + throw new OpenAlertException("预约时间已失效,车辆" + carNum + "无法下发,请重新提交"); + } + String xszDate = importInfo.get("行驶证有效期"); + if (StringUtils.isNotBlank(xszDate) && !DateUtils.validateDateRange(xszDate)) { + throw new OpenAlertException(StrUtil.format("车牌号:{}的行驶证有效期格式{}填写错误,要改成“2020-10-10到2020-10-11”格式", carNum, xszDate)); } } } @@ -453,6 +488,11 @@ public class CarInfoServiceImpl extends ServiceImpl impl carInfoMapper.updateById(carInfo); carInfoMapper.update(null, new LambdaUpdateWrapper() .set(CarInfo::getSendSuccessStatus, 4) + .set(CarInfo::getInspectionDate, carInfo.getInspectionDate()) + .set(CarInfo::getInsuranceTerminationDate, carInfo.getInsuranceTerminationDate()) + .set(CarInfo::getXszBeginDate, carInfo.getXszBeginDate()) + .set(CarInfo::getXszEndDate, carInfo.getXszEndDate()) + .set(CarInfo::getEnterFactoryEndDate, carInfo.getEnterFactoryEndDate()) .eq(CarInfo::getId, carInfo.getId())); if (isReservationType(old)) { @@ -628,13 +668,13 @@ public class CarInfoServiceImpl extends ServiceImpl impl deleteCarInfoForHikvision(carInfo, true); } else { if (Objects.equals(carInfo.getCarModuleType(), CarInfoCarModuleTypeEnum.GD.getValue())) { - xzHikvisionSyncMapper.insert(new XzHikvisionSync().setProjectSn(carInfo.getProjectSn()).setType(4).setOperate(2).setWhoId(carInfo.getId()).setBigType(2).setCreateDate(getSyncTimeWithInitAndDeleteSyncIfAbsent(2, carInfo.getId()))); - xzHikvisionSyncMapper.insert(new XzHikvisionSync().setProjectSn(carInfo.getProjectSn()).setType(5).setOperate(1).setWhoId(carInfo.getId()).setBigType(2).setCreateDate(getSyncTimeWithInitAndDeleteSyncIfAbsent(2, carInfo.getId()))); + xzHikvisionSyncService.addOrUpdate(new XzHikvisionSync().setProjectSn(carInfo.getProjectSn()).setType(4).setOperate(2).setWhoId(carInfo.getId()).setBigType(2).setCreateDate(getSyncTimeWithInitAndDeleteSyncIfAbsent(2, carInfo.getId()))); + xzHikvisionSyncService.addOrUpdate(new XzHikvisionSync().setProjectSn(carInfo.getProjectSn()).setType(5).setOperate(1).setWhoId(carInfo.getId()).setBigType(2).setCreateDate(getSyncTimeWithInitAndDeleteSyncIfAbsent(2, carInfo.getId()))); } else if (Objects.equals(carInfo.getCarModuleType(), CarInfoCarModuleTypeEnum.CQ.getValue()) || Objects.equals(carInfo.getCarModuleType(), CarInfoCarModuleTypeEnum.LS.getValue())) { - xzHikvisionSyncMapper.insert(new XzHikvisionSync().setProjectSn(carInfo.getProjectSn()).setType(6).setOperate(1).setWhoId(carInfo.getId()).setBigType(2).setCreateDate(getSyncTimeWithInitAndDeleteSyncIfAbsent(2, carInfo.getId()))); + xzHikvisionSyncService.addOrUpdate(new XzHikvisionSync().setProjectSn(carInfo.getProjectSn()).setType(6).setOperate(1).setWhoId(carInfo.getId()).setBigType(2).setCreateDate(getSyncTimeWithInitAndDeleteSyncIfAbsent(2, carInfo.getId()))); } if (old.getIsBlack() == 1) { - xzHikvisionSyncMapper.insert(new XzHikvisionSync().setProjectSn(carInfo.getProjectSn()).setType(7).setOperate(3).setWhoId(carInfo.getId()).setBigType(2).setCreateDate(getSyncTimeWithInitAndDeleteSyncIfAbsent(2, carInfo.getId()))); + xzHikvisionSyncService.addOrUpdate(new XzHikvisionSync().setProjectSn(carInfo.getProjectSn()).setType(7).setOperate(3).setWhoId(carInfo.getId()).setBigType(2).setCreateDate(getSyncTimeWithInitAndDeleteSyncIfAbsent(2, carInfo.getId()))); } asyncHikvision.editCarInfoForHikvisionAsync(carInfo, old); } diff --git a/src/main/java/com/zhgd/xmgl/modules/xz/service/IXzHikvisionSyncService.java b/src/main/java/com/zhgd/xmgl/modules/xz/service/IXzHikvisionSyncService.java index ec1c7828e..2b848ff00 100644 --- a/src/main/java/com/zhgd/xmgl/modules/xz/service/IXzHikvisionSyncService.java +++ b/src/main/java/com/zhgd/xmgl/modules/xz/service/IXzHikvisionSyncService.java @@ -69,4 +69,6 @@ public interface IXzHikvisionSyncService extends IService { void retry(Map paramMap) throws Exception; List queryEqList(XzHikvisionSync sync); + + void addOrUpdate(XzHikvisionSync setCreateDate); } diff --git a/src/main/java/com/zhgd/xmgl/modules/xz/service/impl/XzHikvisionSyncServiceImpl.java b/src/main/java/com/zhgd/xmgl/modules/xz/service/impl/XzHikvisionSyncServiceImpl.java index 5099638ec..28ac29e02 100644 --- a/src/main/java/com/zhgd/xmgl/modules/xz/service/impl/XzHikvisionSyncServiceImpl.java +++ b/src/main/java/com/zhgd/xmgl/modules/xz/service/impl/XzHikvisionSyncServiceImpl.java @@ -1,5 +1,6 @@ package com.zhgd.xmgl.modules.xz.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -12,6 +13,7 @@ import com.zhgd.redis.lock.RedisRepository; import com.zhgd.xmgl.async.AsyncHikvision; import com.zhgd.xmgl.call.HikvisionCall; import com.zhgd.xmgl.constant.Cts; +import com.zhgd.xmgl.modules.basicdata.entity.SystemCities; import com.zhgd.xmgl.modules.car.entity.CarInfo; import com.zhgd.xmgl.modules.car.mapper.CarInfoMapper; import com.zhgd.xmgl.modules.project.entity.Project; @@ -38,6 +40,7 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.util.*; +import java.util.stream.Collectors; /** * @Description: 海康同步数据 @@ -255,4 +258,27 @@ public class XzHikvisionSyncServiceImpl extends ServiceImpl syncList = xzHikvisionSyncMapper.selectList(new LambdaQueryWrapper() + .eq(XzHikvisionSync::getProjectSn, sync.getProjectSn()) + .eq(XzHikvisionSync::getType, sync.getType()) + .eq(XzHikvisionSync::getWhoId, sync.getWhoId()) + .eq(XzHikvisionSync::getBigType, sync.getBigType()) + .eq(XzHikvisionSync::getOperate, sync.getOperate()) + .eq(StringUtils.isNotBlank(sync.getDeviceSn()), XzHikvisionSync::getDeviceSn, sync.getDeviceSn())); + if (CollUtil.isNotEmpty(syncList)) { + XzHikvisionSync xzHikvisionSync = syncList.get(0); + if (syncList.size() > 1) { + //删除多余的数据 + this.remove(new LambdaQueryWrapper() + .in(XzHikvisionSync::getId, syncList.stream().map(XzHikvisionSync::getId).filter(id -> !Objects.equals(xzHikvisionSync.getId(), id)).collect(Collectors.toList()))); + } + sync.setId(xzHikvisionSync.getId()); + this.updateById(sync); + } else { + this.save(sync); + } + } } diff --git a/src/main/java/com/zhgd/xmgl/util/DateUtils.java b/src/main/java/com/zhgd/xmgl/util/DateUtils.java index d1bb4a278..5ea36cb64 100644 --- a/src/main/java/com/zhgd/xmgl/util/DateUtils.java +++ b/src/main/java/com/zhgd/xmgl/util/DateUtils.java @@ -4,6 +4,7 @@ package com.zhgd.xmgl.util; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUnit; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; import com.zhgd.jeecg.common.execption.OpenAlertException; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.time.DateFormatUtils; @@ -11,10 +12,7 @@ import org.apache.commons.lang3.time.DateFormatUtils; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.time.DayOfWeek; -import java.time.LocalDate; -import java.time.ZoneId; -import java.time.ZonedDateTime; +import java.time.*; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAdjusters; import java.util.*; @@ -30,6 +28,111 @@ import java.util.regex.Pattern; **/ @Slf4j public class DateUtils { + /** + * 验证日期段格式,日期格式:yyyy-MM-dd 或 yyyy/MM/dd 或 yyyy.MM.dd 或 yyyy年MM月dd日,分割符号:到——~至— + * + * @param input + * @return + */ + public static boolean validateDateRange(String input) { + if (StrUtil.isBlank(input)) { + return true; + } + return parseDateRange(input) != null; + } + + /** + * 解析日期段格式,日期格式:yyyy-MM-dd 或 yyyy/MM/dd 或 yyyy.MM.dd 或 yyyy年MM月dd日,分割符号:到——~至— + * + * @param input + * @return + */ + public static List parseDateRange(String input) { + input = StrUtil.trim(input); + String regex = "^\\s*" + + "(?:" + + // 标准格式:yyyy-MM-dd 或 yyyy/MM/dd 或 yyyy.MM.dd + "(?\\d{4})[-/.]?(?\\d{1,2})[-/.]?(?\\d{1,2})" + + "|" + + // 中文格式:yyyy年MM月dd日 + "(?\\d{4})\\s*年\\s*(?\\d{1,2})\\s*月\\s*(?\\d{1,2})\\s*日" + + ")" + + "\\s*" + + // 分隔符 + "(?到|至|——|—|~|--+)" + + "\\s*" + + "(?:" + + // 标准格式结束日期 + "(?\\d{4})[-/.]?(?\\d{1,2})[-/.]?(?\\d{1,2})" + + "|" + + // 中文格式结束日期 + "(?\\d{4})\\s*年\\s*(?\\d{1,2})\\s*月\\s*(?\\d{1,2})\\s*日" + + ")" + + "\\s*$"; + + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(input); + + if (matcher.find()) { + try { + // 解析开始日期 + int startYear, startMonth, startDay; + if (matcher.group("stdStartY") != null) { + // 标准格式 + startYear = Integer.parseInt(matcher.group("stdStartY")); + startMonth = Integer.parseInt(matcher.group("stdStartM")); + startDay = Integer.parseInt(matcher.group("stdStartD")); + } else { + // 中文格式 + startYear = Integer.parseInt(matcher.group("cnStartY")); + startMonth = Integer.parseInt(matcher.group("cnStartM")); + startDay = Integer.parseInt(matcher.group("cnStartD")); + } + + // 解析结束日期 + int endYear, endMonth, endDay; + if (matcher.group("stdEndY") != null) { + // 标准格式 + endYear = Integer.parseInt(matcher.group("stdEndY")); + endMonth = Integer.parseInt(matcher.group("stdEndM")); + endDay = Integer.parseInt(matcher.group("stdEndD")); + } else { + // 中文格式 + endYear = Integer.parseInt(matcher.group("cnEndY")); + endMonth = Integer.parseInt(matcher.group("cnEndM")); + endDay = Integer.parseInt(matcher.group("cnEndD")); + } + + LocalDate startDate = LocalDate.of(startYear, startMonth, startDay); + LocalDate endDate = LocalDate.of(endYear, endMonth, endDay); + + return Arrays.asList(Date.from(startDate.atStartOfDay(ZoneId.systemDefault()).toInstant()), Date.from(endDate.atStartOfDay(ZoneId.systemDefault()).toInstant())); + } catch (Exception e) { + log.error("", e); + return null; // 处理无效日期 + } + } + return null; + } + + public static void main(String[] args) { + String[] testCases = { + "2020-10-10到2020-10-11", + "2020年10月10日——2020年10月11日", + "2020/10/10~2020/10/11", + "2020 年 1 月 5 日 至 2020 年 1 月 6 日", + "2020.12.31—2021.01.01" + }; + + for (String testCase : testCases) { + List dates = parseDateRange(testCase); + if (dates != null) { + System.out.printf("输入: '%s'\n开始日期: %s\n结束日期: %s\n\n", testCase, dates.get(0), dates.get(1)); + } else { + System.out.printf("输入: '%s' 解析失败\n\n", testCase); + } + } + } public static String dealDateFormat(String oldDate) { Date date1 = null; @@ -723,13 +826,4 @@ public class DateUtils { return from; } - public static void main(String[] args) { - System.out.println(getBeforeDayOfWeek(new Date(), 1)); - System.out.println(getBeforeDayOfWeek(new Date(), 2)); - System.out.println(getBeforeDayOfWeek(new Date(), 3)); - System.out.println(getBeforeDayOfWeek(new Date(), 4)); - System.out.println(getBeforeDayOfWeek(new Date(), 5)); - System.out.println(getBeforeDayOfWeek(new Date(), 6)); - System.out.println(getBeforeDayOfWeek(new Date(), 7)); - } } diff --git a/src/main/resources/excel/车辆导入模板.xlsx b/src/main/resources/excel/车辆导入模板.xlsx index 806eed85b93509c50420178b359aea449022c904..c859b9f8cab69f0416885d778cd931e134bcd447 100644 GIT binary patch delta 7770 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