From e78bd59a1ac477aa0fb134e2074387fa9d45b4ce Mon Sep 17 00:00:00 2001 From: tangcy <406968399@qq.com> Date: Tue, 7 Apr 2026 17:23:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=83=A8=E5=88=86bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/WorkTicketController.java | 13 +- .../com/admin/contractor/domain/WorkPlan.java | 5 +- .../contractor/mapper/SysDeptMapper.java | 10 + .../service/IWorkTicketService.java | 2 +- .../service/impl/WorkPlanServiceImpl.java | 216 ++++++----- .../service/impl/WorkTicketServiceImpl.java | 7 +- .../OwnerAccessAuditController.java | 42 ++- .../owner/domain/OwnerAccessAuditEvent.java | 4 +- .../domain/vo/OwnerAccessAuditFileVO.java | 27 ++ .../owner/mapper/OwnerAccessAuditMapper.java | 2 + .../service/IOwnerAccessAuditService.java | 20 + .../impl/OwnerAccessAuditServiceImpl.java | 345 +++++++++++++++++- .../controller/PcCameraLedgerController.java | 2 +- .../admin/property/domain/PcCameraLedger.java | 4 +- .../admin/property/enums/PcCameraStatus.java | 2 - .../property/mapper/PcCameraAllocMapper.java | 4 +- .../service/impl/PcCameraBizServiceImpl.java | 28 +- .../resources/mapper/AccessPermitMapper.xml | 11 + .../resources/mapper/PcCameraAllocMapper.xml | 3 + .../resources/mapper/PcCameraLedgerMapper.xml | 2 +- .../resources/mapper/PcRiskProjectMapper.xml | 1 + .../main/resources/mapper/SysDeptMapper.xml | 18 + .../main/resources/mapper/WorkPlanMapper.xml | 14 +- .../resources/mapper/WorkTicketMapper.xml | 1 + .../mapper/owner/OwnerAccessAuditMapper.xml | 12 + .../system/controller/SysDeptController.java | 15 +- .../system/controller/SysUserController.java | 13 - .../service/impl/SysDeptServiceImpl.java | 27 ++ .../service/impl/SysUserServiceImpl.java | 3 - .../system/utils/ThirdPartyHttpClient.java | 8 +- .../resources/mapper/system/SysDeptMapper.xml | 2 +- 31 files changed, 710 insertions(+), 153 deletions(-) create mode 100644 ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/domain/vo/OwnerAccessAuditFileVO.java diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/controller/WorkTicketController.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/controller/WorkTicketController.java index d3fd8950..7992df6d 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/controller/WorkTicketController.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/controller/WorkTicketController.java @@ -143,12 +143,13 @@ public class WorkTicketController extends BaseController { @Log(title = "工作票审批", businessType = BusinessType.UPDATE) @PutMapping("/approve/{ticketId}") public AjaxResult approve(@Parameter(description = "工作票 ID") @PathVariable("ticketId") Long ticketId, - @Parameter(description = "审核意见") @RequestParam(required = false) String reviewComment, - @Parameter(description = "施工作业必要性:0 不必要 1 必要") @RequestParam(required = false) String reviewNecessity, - @Parameter(description = "施工作业可行性:0 不可行 1 可行") @RequestParam(required = false) String reviewFeasibility, - @Parameter(description = "票证内容完整性(JSON 数组)") @RequestParam(required = false) String reviewCompleteness, - @Parameter(description = "施工条件确认:0 不符合 1 符合") @RequestParam(required = false) String reviewCondition) { - return toAjax(workTicketService.approveWorkTicket(ticketId, reviewComment, reviewNecessity, reviewFeasibility, reviewCompleteness, reviewCondition)); + @Parameter(description = "审核意见") @RequestParam(required = false) String reviewComment, + @Parameter(description = "审批后状态:2已签发(默认)") @RequestParam(required = false, defaultValue = "2") String status, + @Parameter(description = "施工作业必要性:0 不必要 1 必要") @RequestParam(required = false) String reviewNecessity, + @Parameter(description = "施工作业可行性:0 不可行 1 可行") @RequestParam(required = false) String reviewFeasibility, + @Parameter(description = "票证内容完整性(JSON 数组)") @RequestParam(required = false) String reviewCompleteness, + @Parameter(description = "施工条件确认:0 不符合 1 符合") @RequestParam(required = false) String reviewCondition) { + return toAjax(workTicketService.approveWorkTicket(ticketId, reviewComment, status, reviewNecessity, reviewFeasibility, reviewCompleteness, reviewCondition)); } /** diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/domain/WorkPlan.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/domain/WorkPlan.java index b80548a3..4f767168 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/domain/WorkPlan.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/domain/WorkPlan.java @@ -63,6 +63,9 @@ public class WorkPlan extends BaseEntity { @Schema(description = "施工单位名称") private String constructionUnitName; + @Schema(description = "项目所属部门全路径") + private String constructionUnitFullPath; + @Schema(description = "监理单位ID(sys_dept,dept_type=2)") private Long supervisionUnitId; @@ -75,7 +78,7 @@ public class WorkPlan extends BaseEntity { @Schema(description = "风险等级") private String riskLevel; - @Schema(description = "项目状态:0草稿,1已提交,2进行中,3已完成,4已取消") + @Schema(description = "项目状态:0草稿,1已提交,2进行中,3已完成") private String projectStatus; @Schema(description = "实施状态:0未实施,1实施中,2整改中,3待完工确认") diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/mapper/SysDeptMapper.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/mapper/SysDeptMapper.java index 6cc084f9..d19681f6 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/mapper/SysDeptMapper.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/mapper/SysDeptMapper.java @@ -3,6 +3,8 @@ package com.admin.contractor.mapper; import org.apache.ibatis.annotations.Param; import com.ruoyi.system.api.domain.SysDept; +import java.util.List; + /** * 部门表查询(用于根据用户部门取施工单位名称等) * @@ -25,4 +27,12 @@ public interface SysDeptMapper { * @return 部门信息,不存在返回 null */ SysDept selectDeptById(@Param("deptId") Long deptId); + + /** + * 根据部门ID列表批量查询部门基础信息(用于名称和全路径组装)。 + * + * @param deptIds 部门ID列表 + * @return 部门信息列表 + */ + List selectDeptListByIds(@Param("deptIds") List deptIds); } diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/IWorkTicketService.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/IWorkTicketService.java index 271470d4..1b6e8a2f 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/IWorkTicketService.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/IWorkTicketService.java @@ -82,7 +82,7 @@ public interface IWorkTicketService { * @param reviewComment 审核意见 * @return 结果 */ - int approveWorkTicket(Long ticketId, String reviewComment, String reviewNecessity, String reviewFeasibility, String reviewCompleteness, String reviewCondition); + int approveWorkTicket(Long ticketId, String reviewComment, String status, String reviewNecessity, String reviewFeasibility, String reviewCompleteness, String reviewCondition); /** * 审批工作票(驳回) diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/impl/WorkPlanServiceImpl.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/impl/WorkPlanServiceImpl.java index 610ec4c2..5203c555 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/impl/WorkPlanServiceImpl.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/impl/WorkPlanServiceImpl.java @@ -20,6 +20,7 @@ import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.security.utils.SecurityUtils; import com.admin.contractor.mapper.SysUserMapper; +import com.ruoyi.system.api.domain.SysDept; import com.ruoyi.system.api.domain.SysUser; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -29,10 +30,13 @@ import org.springframework.transaction.annotation.Transactional; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; -import java.util.LinkedHashMap; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; /** * 工作计划Service业务层处理 @@ -159,6 +163,15 @@ public class WorkPlanServiceImpl implements IWorkPlanService { */ @Override public List selectWorkPlanList(WorkPlan workPlan) { + if (workPlan.getConstructionUnitId() == null) { + Long currentUserId = SecurityUtils.getUserId(); + if (currentUserId != null) { + SysUser currentUser = sysUserMapper.selectUserById(currentUserId); + if (currentUser != null && currentUser.getDeptId() != null) { + workPlan.setConstructionUnitId(currentUser.getDeptId()); + } + } + } List list = workPlanMapper.selectWorkPlanList(workPlan); // 加载作业班成员信息、草稿状态显示文字、关联的工作票ID、风险控制卡ID、球机申领表ID for (WorkPlan plan : list) { @@ -534,109 +547,118 @@ public class WorkPlanServiceImpl implements IWorkPlanService { return list; } - // 按项目ID聚合(一个项目一条记录),汇总普通工作票状态和危险工作票状态 - Map> groupByProject = new LinkedHashMap<>(); - for (WorkPlan wp : list) { - Long projectId = wp.getProjectId(); - if (projectId == null) { - // projectId 为空的记录单独分组 - groupByProject.computeIfAbsent(-1L, k -> new ArrayList<>()).add(wp); - } else { - groupByProject.computeIfAbsent(projectId, k -> new ArrayList<>()).add(wp); + // SQL 侧保留“每项目最新票证”查询;Java 侧只做组织信息补齐,避免 SQL 继续膨胀。 + enrichDepartmentInfo(list); + for (WorkPlan item : list) { + loadSysUsers(item); + } + return list; + } + + private void enrichDepartmentInfo(List list) { + if (sysDeptMapper == null || list == null || list.isEmpty()) { + return; + } + + // 第一步:收集当前页需要的施工单位/监理单位部门ID。 + Set seedDeptIds = new HashSet<>(); + for (WorkPlan item : list) { + if (item.getConstructionUnitId() != null) { + seedDeptIds.add(item.getConstructionUnitId()); + } + if (item.getSupervisionUnitId() != null) { + seedDeptIds.add(item.getSupervisionUnitId()); + } + } + if (seedDeptIds.isEmpty()) { + return; + } + + // 第二步:先批量查“直接部门”。 + Map deptMap = new HashMap<>(); + List directDepts = sysDeptMapper.selectDeptListByIds(new ArrayList<>(seedDeptIds)); + for (SysDept dept : directDepts) { + deptMap.put(dept.getDeptId(), dept); + } + + // 第三步:根据 ancestors 收集全路径上的祖先部门ID,再一次性补查。 + Set pathDeptIds = new HashSet<>(seedDeptIds); + for (SysDept dept : directDepts) { + pathDeptIds.addAll(parseAncestorIds(dept.getAncestors())); + } + + Set toLoad = new HashSet<>(pathDeptIds); + toLoad.removeAll(deptMap.keySet()); + if (!toLoad.isEmpty()) { + List ancestorDepts = sysDeptMapper.selectDeptListByIds(new ArrayList<>(toLoad)); + for (SysDept dept : ancestorDepts) { + deptMap.put(dept.getDeptId(), dept); } } - List result = new ArrayList<>(); - for (Map.Entry> entry : groupByProject.entrySet()) { - List rows = entry.getValue(); - if (rows.isEmpty()) { + // 第四步:回填监理单位名称和施工单位全路径。 + for (WorkPlan item : list) { + fillSupervisionUnitName(item, deptMap); + fillConstructionUnitFullPath(item, deptMap); + } + } + + private void fillSupervisionUnitName(WorkPlan item, Map deptMap) { + if (item.getSupervisionUnitId() == null || StringUtils.isNotEmpty(item.getSupervisionUnitName())) { + return; + } + SysDept dept = deptMap.get(item.getSupervisionUnitId()); + if (dept != null) { + item.setSupervisionUnitName(dept.getDeptName()); + } + } + + private void fillConstructionUnitFullPath(WorkPlan item, Map deptMap) { + if (item.getConstructionUnitId() == null) { + return; + } + SysDept currentDept = deptMap.get(item.getConstructionUnitId()); + if (currentDept == null) { + return; + } + + // ancestors 格式一般为 "0,100,101",这里按顺序拼接成 "集团/事业部/部门"。 + List orderedDeptIds = new ArrayList<>(parseAncestorIds(currentDept.getAncestors())); + orderedDeptIds.add(currentDept.getDeptId()); + + List names = new ArrayList<>(); + for (Long deptId : orderedDeptIds) { + SysDept dept = deptMap.get(deptId); + if (dept != null && StringUtils.isNotEmpty(dept.getDeptName())) { + names.add(dept.getDeptName()); + } + } + if (!names.isEmpty()) { + item.setConstructionUnitFullPath(String.join("/", names)); + } + } + + private List parseAncestorIds(String ancestors) { + if (StringUtils.isEmpty(ancestors)) { + return Collections.emptyList(); + } + List ids = new ArrayList<>(); + String[] parts = ancestors.split(","); + for (String part : parts) { + if (StringUtils.isEmpty(part)) { continue; } - WorkPlan first = rows.get(0); - WorkPlan agg = new WorkPlan(); - - // 复制项目本身的基础信息 - agg.setProjectId(first.getProjectId()); - agg.setProjectCode(first.getProjectCode()); - agg.setProjectName(first.getProjectName()); - agg.setWorkLocation(first.getWorkLocation()); - agg.setWorkLocationDetail(first.getWorkLocationDetail()); - agg.setLongitude(first.getLongitude()); - agg.setLatitude(first.getLatitude()); - agg.setWorkStartTime(first.getWorkStartTime()); - agg.setWorkEndTime(first.getWorkEndTime()); - agg.setSupervisorId(first.getSupervisorId()); - agg.setSupervisorName(first.getSupervisorName()); - agg.setSupervisorPosition(first.getSupervisorPosition()); - agg.setSysUsers(first.getSysUsers()); - agg.setConstructionUnitId(first.getConstructionUnitId()); - agg.setConstructionUnitName(first.getConstructionUnitName()); - agg.setSupervisionUnitId(first.getSupervisionUnitId()); - agg.setSupervisionUnitName(first.getSupervisionUnitName()); - agg.setWorkType(first.getWorkType()); - agg.setRiskLevel(first.getRiskLevel()); - agg.setProjectStatus(first.getProjectStatus()); - agg.setImplementationStatus(first.getImplementationStatus()); - agg.setApprovalStatus(first.getApprovalStatus()); - agg.setApprover(first.getApprover()); - agg.setApprovalTime(first.getApprovalTime()); - agg.setApprovalComment(first.getApprovalComment()); - agg.setCurrentProgress(first.getCurrentProgress()); - agg.setDelFlag(first.getDelFlag()); - agg.setRemark(first.getRemark()); - agg.setCreateBy(first.getCreateBy()); - agg.setCreateTime(first.getCreateTime()); - agg.setUpdateBy(first.getUpdateBy()); - agg.setUpdateTime(first.getUpdateTime()); - - // 现场完工复核相关字段 - agg.setCompletionReviewResult(first.getCompletionReviewResult()); - agg.setCompletionReviewPhotos(first.getCompletionReviewPhotos()); - agg.setCompletionReviewBy(first.getCompletionReviewBy()); - agg.setCompletionReviewTime(first.getCompletionReviewTime()); - agg.setCompletionReviewRemark(first.getCompletionReviewRemark()); - - // 票证与出入证信息汇总:直接取第一条记录的状态(SQL 已分别查询普通工作票和危险作业票) - String normalTicketStatus = null; - String hazardousTicketStatus = null; - String issuer = null; - String accessPermitNumber = null; - String accessPermitValidity = null; - String accessPermitStatus = null; - - for (WorkPlan row : rows) { - // 普通工作票状态(SQL 已过滤 ticket_type != '危险作业票') - if (normalTicketStatus == null && row.getWorkTicketStatus() != null) { - normalTicketStatus = row.getWorkTicketStatus(); - } - // 危险作业票状态(SQL 已过滤 ticket_type = '危险作业票') - if (hazardousTicketStatus == null && row.getHazardousWorkTicketStatus() != null) { - hazardousTicketStatus = row.getHazardousWorkTicketStatus(); - } - // 签发人(从普通工作票获取) - if (issuer == null && row.getIssuer() != null) { - issuer = row.getIssuer(); - } - // 出入证信息 - if (accessPermitNumber == null && row.getAccessPermitNumber() != null) { - accessPermitNumber = row.getAccessPermitNumber(); - accessPermitValidity = row.getAccessPermitValidity(); - accessPermitStatus = row.getAccessPermitStatus(); - } + String trimmed = part.trim(); + if ("0".equals(trimmed)) { + continue; + } + try { + ids.add(Long.valueOf(trimmed)); + } catch (NumberFormatException ignored) { + // ignore illegal ancestor id } - - agg.setWorkTicketStatus(normalTicketStatus); - agg.setHazardousWorkTicketStatus(hazardousTicketStatus); - agg.setIssuer(issuer); - agg.setAccessPermitNumber(accessPermitNumber); - agg.setAccessPermitValidity(accessPermitValidity); - agg.setAccessPermitStatus(accessPermitStatus); - - // 关联的草稿状态文字与作业班成员信息 - loadSysUsers(agg); - result.add(agg); } - return result; + return ids; } /** diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/impl/WorkTicketServiceImpl.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/impl/WorkTicketServiceImpl.java index e696ba70..5786a416 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/impl/WorkTicketServiceImpl.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/contractor/service/impl/WorkTicketServiceImpl.java @@ -237,7 +237,7 @@ public class WorkTicketServiceImpl implements IWorkTicketService { */ @Override @Transactional - public int approveWorkTicket(Long ticketId, String reviewComment, String reviewNecessity, String reviewFeasibility, String reviewCompleteness, String reviewCondition) { + public int approveWorkTicket(Long ticketId, String reviewComment, String status, String reviewNecessity, String reviewFeasibility, String reviewCompleteness, String reviewCondition) { WorkTicket ticket = workTicketMapper.selectWorkTicketById(ticketId); if (ticket == null) { throw new ServiceException("工作票申请不存在"); @@ -260,9 +260,14 @@ public class WorkTicketServiceImpl implements IWorkTicketService { } } String reviewer = SecurityUtils.getUsername(); + // 默认审批通过后置为已签发 + if (StringUtils.isEmpty(status)) { + status = "2"; + } // 更新状态为已签发,并保存审核确认信息 WorkTicket updateTicket = new WorkTicket(); updateTicket.setTicketId(ticketId); + updateTicket.setStatus(status); updateTicket.setReviewer(reviewer); updateTicket.setReviewTime(new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); updateTicket.setReviewComment(reviewComment); diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/controller/OwnerAccessAuditController.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/controller/OwnerAccessAuditController.java index aa8d935b..9fe1e165 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/controller/OwnerAccessAuditController.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/controller/OwnerAccessAuditController.java @@ -3,6 +3,7 @@ package com.admin.owner.controller; import com.admin.owner.domain.OwnerAccessAuditEvent; import com.admin.owner.domain.OwnerAccessAuditIssue; import com.admin.owner.domain.OwnerAccessAuditItem; +import com.admin.owner.domain.vo.OwnerAccessAuditFileVO; import com.admin.owner.service.IOwnerAccessAuditService; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.core.web.domain.AjaxResult; @@ -13,9 +14,18 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.util.List; @Tag(name = "准入事件审计(业主端)") @@ -40,6 +50,23 @@ public class OwnerAccessAuditController extends BaseController { return success(ownerAccessAuditService.detail(eventId)); } + @Operation(summary = "查询附件展示列表(主表附件+分组材料)") + @GetMapping("/{eventId}/files") + public AjaxResult files(@Parameter(description = "事件ID") @PathVariable Long eventId) { + List list = ownerAccessAuditService.listFiles(eventId); + return success(list); + } + + @Operation(summary = "附件打包下载") + @GetMapping("/{eventId}/files/download") + public void downloadFilesZip( + @Parameter(description = "事件ID") @PathVariable Long eventId, + HttpServletRequest request, + HttpServletResponse response + ) throws Exception { + ownerAccessAuditService.downloadFilesZip(eventId, request, response); + } + @Operation(summary = "创建准入事件审计(仅初始化事件与默认检查项;提交请优先使用 POST /submit)") @Log(title = "准入事件审计", businessType = BusinessType.INSERT) @PostMapping @@ -48,7 +75,7 @@ public class OwnerAccessAuditController extends BaseController { return success(id); } - @Operation(summary = "一步提交全部表单(基础信息+检查项+问题单+结论)。无 eventId 时先创建事件并落默认检查项再保存;issues 传 [] 可清空问题;不传 issues 则不改动原有问题") + @Operation(summary = "一步提交全部表单(基础信息+检查项+问题单+结论)") @Log(title = "准入事件审计-一步提交", businessType = BusinessType.UPDATE) @PostMapping("/submit") public AjaxResult submitAll(@Validated @RequestBody OwnerAccessAuditEvent event) { @@ -56,39 +83,38 @@ public class OwnerAccessAuditController extends BaseController { return success(eventId); } - @Operation(summary = "更新基础信息(分步接口,建议改用 POST /submit)") + @Operation(summary = "更新基础信息") @Log(title = "准入事件审计", businessType = BusinessType.UPDATE) @PutMapping("/base") public AjaxResult updateBase(@Validated @RequestBody OwnerAccessAuditEvent event) { return toAjax(ownerAccessAuditService.updateBaseInfo(event)); } - @Operation(summary = "更新检查项(分步接口,建议改用 POST /submit)") + @Operation(summary = "更新检查项") @Log(title = "准入事件审计-检查项", businessType = BusinessType.UPDATE) @PutMapping("/item") public AjaxResult updateItem(@Validated @RequestBody OwnerAccessAuditItem item) { return toAjax(ownerAccessAuditService.updateItem(item)); } - @Operation(summary = "批量更新检查项(分步接口,建议改用 POST /submit)") + @Operation(summary = "批量更新检查项") @Log(title = "准入事件审计-检查项", businessType = BusinessType.UPDATE) @PutMapping("/items") public AjaxResult updateItems(@Validated @RequestBody List items) { return toAjax(ownerAccessAuditService.updateItems(items)); } - @Operation(summary = "新增问题单(分步接口,建议改用 POST /submit)") + @Operation(summary = "新增问题单") @Log(title = "准入事件审计-问题单", businessType = BusinessType.INSERT) @PostMapping("/issue") public AjaxResult addIssue(@Validated @RequestBody OwnerAccessAuditIssue issue) { return toAjax(ownerAccessAuditService.addIssue(issue)); } - @Operation(summary = "删除问题单(分步接口,建议改用 POST /submit 整单替换 issues)") + @Operation(summary = "删除问题单") @Log(title = "准入事件审计-问题单", businessType = BusinessType.DELETE) @DeleteMapping("/issue/{issueId}") public AjaxResult deleteIssue(@PathVariable Long issueId) { return toAjax(ownerAccessAuditService.deleteIssue(issueId)); } } - diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/domain/OwnerAccessAuditEvent.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/domain/OwnerAccessAuditEvent.java index ac5b994a..4b2b9132 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/domain/OwnerAccessAuditEvent.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/domain/OwnerAccessAuditEvent.java @@ -70,6 +70,9 @@ public class OwnerAccessAuditEvent extends BaseEntity { @Schema(description = "附件URL(多个用逗号分隔)") private String attachmentUrls; + @Schema(description = "主表与关联表合计文件数量") + private Integer totalFileCount; + private String delFlag; @Schema(description = "检查项列表(详情返回用)") @@ -78,4 +81,3 @@ public class OwnerAccessAuditEvent extends BaseEntity { @Schema(description = "问题列表(详情返回用)") private List issues; } - diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/domain/vo/OwnerAccessAuditFileVO.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/domain/vo/OwnerAccessAuditFileVO.java new file mode 100644 index 00000000..5797365c --- /dev/null +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/domain/vo/OwnerAccessAuditFileVO.java @@ -0,0 +1,27 @@ +package com.admin.owner.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "准入审计附件展示对象") +public class OwnerAccessAuditFileVO { + + @Schema(description = "文件URL") + private String fileUrl; + + @Schema(description = "展示类型(图片/视频/文档/其他)") + private String displayType; + + @Schema(description = "文件名") + private String fileName; + + @Schema(description = "分类") + private String category; + + @Schema(description = "上传时间") + private String uploadTime; + + @Schema(description = "文件大小") + private String fileSize; +} diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/mapper/OwnerAccessAuditMapper.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/mapper/OwnerAccessAuditMapper.java index 0a13cdee..c6588149 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/mapper/OwnerAccessAuditMapper.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/mapper/OwnerAccessAuditMapper.java @@ -21,6 +21,8 @@ public interface OwnerAccessAuditMapper { List selectItemsByEventId(@Param("eventId") Long eventId); + List selectItemsByEventIds(@Param("eventIds") List eventIds); + int insertItemsBatch(@Param("list") List list); int updateItem(OwnerAccessAuditItem item); diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/service/IOwnerAccessAuditService.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/service/IOwnerAccessAuditService.java index 7a07a1d2..96a7169b 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/service/IOwnerAccessAuditService.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/service/IOwnerAccessAuditService.java @@ -3,7 +3,10 @@ package com.admin.owner.service; import com.admin.owner.domain.OwnerAccessAuditEvent; import com.admin.owner.domain.OwnerAccessAuditIssue; import com.admin.owner.domain.OwnerAccessAuditItem; +import com.admin.owner.domain.vo.OwnerAccessAuditFileVO; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.util.List; public interface IOwnerAccessAuditService { @@ -36,5 +39,22 @@ public interface IOwnerAccessAuditService { * @return 事件ID */ Long submitAll(OwnerAccessAuditEvent event); + + /** + * 查询附件展示列表(主表附件 + 子表材料附件)。 + * + * @param eventId 事件ID + * @return 附件展示列表 + */ + List listFiles(Long eventId); + + /** + * 根据事件ID下载附件压缩包。 + * + * @param eventId 事件ID + * @param request 请求对象 + * @param response 响应对象 + */ + void downloadFilesZip(Long eventId, HttpServletRequest request, HttpServletResponse response) throws Exception; } diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/service/impl/OwnerAccessAuditServiceImpl.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/service/impl/OwnerAccessAuditServiceImpl.java index da9ffb86..d6a6a16b 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/service/impl/OwnerAccessAuditServiceImpl.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/owner/service/impl/OwnerAccessAuditServiceImpl.java @@ -3,23 +3,38 @@ package com.admin.owner.service.impl; import com.admin.owner.domain.OwnerAccessAuditEvent; import com.admin.owner.domain.OwnerAccessAuditIssue; import com.admin.owner.domain.OwnerAccessAuditItem; +import com.admin.owner.domain.vo.OwnerAccessAuditFileVO; import com.admin.owner.mapper.OwnerAccessAuditMapper; import com.admin.owner.service.IOwnerAccessAuditService; import com.admin.contractor.mapper.SysDeptMapper; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.core.utils.file.FileUtils; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.system.api.domain.SysDept; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.HashSet; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; @Service public class OwnerAccessAuditServiceImpl implements IOwnerAccessAuditService { @@ -30,9 +45,22 @@ public class OwnerAccessAuditServiceImpl implements IOwnerAccessAuditService { @Resource private SysDeptMapper sysDeptMapper; + private static final String CATEGORY_EVENT_ATTACHMENT = "审计事件附件"; + private static final String CATEGORY_GROUP_1 = "准入过程"; + private static final String CATEGORY_GROUP_2 = "检测与质量"; + private static final String CATEGORY_GROUP_3 = "操作日志与合规"; + private static final String CATEGORY_UNKNOWN = "其他"; + private static final String DEFAULT_FILE_SIZE = "-"; + private static final String DISPLAY_TYPE_IMAGE = "图片"; + private static final String DISPLAY_TYPE_VIDEO = "视频"; + private static final String DISPLAY_TYPE_DOC = "文档"; + private static final String DISPLAY_TYPE_OTHER = "其他"; + @Override public List list(OwnerAccessAuditEvent query) { - return ownerAccessAuditMapper.selectEventList(query); + List events = ownerAccessAuditMapper.selectEventList(query); + fillTotalFileCount(events); + return events; } @Override @@ -195,7 +223,12 @@ public class OwnerAccessAuditServiceImpl implements IOwnerAccessAuditService { throw new ServiceException("事件信息不能为空"); } Long eventId = event.getEventId(); + List submitItems = event.getItems(); + List submitIssues = event.getIssues(); if (eventId == null) { + // 新建并提交时,先只创建主记录,避免 createEvent 与后续同步逻辑重复写入检查项/问题单 + event.setItems(null); + event.setIssues(null); eventId = createEvent(event); } else { OwnerAccessAuditEvent existing = ownerAccessAuditMapper.selectEventById(eventId); @@ -204,6 +237,8 @@ public class OwnerAccessAuditServiceImpl implements IOwnerAccessAuditService { } } event.setEventId(eventId); + event.setItems(submitItems); + event.setIssues(submitIssues); if (event.getItems() != null && !event.getItems().isEmpty()) { syncItemsByEventId(eventId, event.getItems()); @@ -232,6 +267,110 @@ public class OwnerAccessAuditServiceImpl implements IOwnerAccessAuditService { return eventId; } + @Override + public List listFiles(Long eventId) { + if (eventId == null) { + throw new ServiceException("事件ID不能为空"); + } + OwnerAccessAuditEvent event = ownerAccessAuditMapper.selectEventById(eventId); + if (event == null) { + throw new ServiceException("事件不存在"); + } + + List result = new ArrayList<>(); + appendFiles( + result, + null, + event.getAttachmentUrls(), + CATEGORY_EVENT_ATTACHMENT, + selectUploadTime(event.getUpdateTime(), event.getCreateTime()) + ); + + List items = ownerAccessAuditMapper.selectItemsByEventId(eventId); + for (OwnerAccessAuditItem item : items) { + appendFiles( + result, + null, + item.getMaterialUrls(), + resolveItemCategory(item.getGroupCode()), + selectUploadTime(item.getUpdateTime(), item.getCreateTime()) + ); + } + return result; + } + + @Override + public void downloadFilesZip(Long eventId, HttpServletRequest request, HttpServletResponse response) throws Exception { + List files = listFiles(eventId); + if (files == null || files.isEmpty()) { + throw new ServiceException("暂无可下载文件"); + } + + response.setContentType("application/zip"); + FileUtils.setAttachmentResponseHeader(response, "owner_access_audit_" + eventId + ".zip"); + + Set urlDedup = new HashSet<>(); + Map nameCounter = new HashMap<>(); + StringBuilder failed = new StringBuilder(); + + try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) { + byte[] buffer = new byte[8192]; + for (OwnerAccessAuditFileVO file : files) { + if (file == null || StringUtils.isEmpty(file.getFileUrl())) { + continue; + } + if (!urlDedup.add(file.getFileUrl())) { + continue; + } + + String targetUrl = normalizeFileUrl(file.getFileUrl(), request); + String entryName = uniqueEntryName(safeFileName(file.getFileName(), file.getFileUrl()), nameCounter); + + HttpURLConnection conn = null; + try { + URL url = new URL(targetUrl); + conn = (HttpURLConnection) url.openConnection(); + conn.setConnectTimeout(3000); + conn.setReadTimeout(10000); + conn.setRequestMethod("GET"); + + int code = conn.getResponseCode(); + if (code < 200 || code >= 300) { + failed.append(file.getFileUrl()).append(" -> HTTP ").append(code).append("\n"); + continue; + } + + try (InputStream in = conn.getInputStream()) { + zos.putNextEntry(new ZipEntry(entryName)); + int len; + while ((len = in.read(buffer)) != -1) { + zos.write(buffer, 0, len); + } + zos.closeEntry(); + } + } catch (Exception ex) { + failed.append(file.getFileUrl()).append(" -> ").append(ex.getMessage()).append("\n"); + } finally { + if (conn != null) { + conn.disconnect(); + } + } + } + + if (failed.length() > 0) { + byte[] bytes = failed.toString().getBytes(StandardCharsets.UTF_8); + try (InputStream in = new ByteArrayInputStream(bytes)) { + zos.putNextEntry(new ZipEntry("download_failed.txt")); + int len; + while ((len = in.read(buffer)) != -1) { + zos.write(buffer, 0, len); + } + zos.closeEntry(); + } + } + } + } + /** * 一步提交:结论 1/2 => 通过(3),3/4 => 不通过(4);无结论 => 审核中(1) */ @@ -292,8 +431,210 @@ public class OwnerAccessAuditServiceImpl implements IOwnerAccessAuditService { } } + private void appendFiles( + List target, + Set dedupKeySet, + String rawUrls, + String category, + Date uploadTime + ) { + if (StringUtils.isEmpty(rawUrls)) { + return; + } + String uploadTimeStr = formatDate(uploadTime); + for (String url : splitUrls(rawUrls)) { + if (dedupKeySet != null) { + String dedupKey = category + "|" + url; + if (!dedupKeySet.add(dedupKey)) { + continue; + } + } + OwnerAccessAuditFileVO row = new OwnerAccessAuditFileVO(); + row.setFileUrl(url); + row.setFileName(extractFileName(url)); + row.setDisplayType(resolveDisplayType(url)); + row.setCategory(category); + row.setUploadTime(uploadTimeStr); + row.setFileSize(DEFAULT_FILE_SIZE); + target.add(row); + } + } + + private void fillTotalFileCount(List events) { + if (events == null || events.isEmpty()) { + return; + } + + List eventIds = new ArrayList<>(); + Map countByEventId = new HashMap<>(); + for (OwnerAccessAuditEvent event : events) { + if (event.getEventId() == null) { + continue; + } + eventIds.add(event.getEventId()); + countByEventId.put(event.getEventId(), countUrls(event.getAttachmentUrls())); + } + + if (!eventIds.isEmpty()) { + List items = ownerAccessAuditMapper.selectItemsByEventIds(eventIds); + for (OwnerAccessAuditItem item : items) { + if (item.getEventId() == null) { + continue; + } + int current = countByEventId.containsKey(item.getEventId()) ? countByEventId.get(item.getEventId()) : 0; + countByEventId.put(item.getEventId(), current + countUrls(item.getMaterialUrls())); + } + } + + for (OwnerAccessAuditEvent event : events) { + if (event.getEventId() == null) { + event.setTotalFileCount(0); + continue; + } + event.setTotalFileCount(countByEventId.getOrDefault(event.getEventId(), 0)); + } + } + + private int countUrls(String rawUrls) { + return splitUrls(rawUrls).size(); + } + + private List splitUrls(String rawUrls) { + List urls = new ArrayList<>(); + if (StringUtils.isEmpty(rawUrls)) { + return urls; + } + String[] parts = rawUrls.split(","); + for (String part : parts) { + if (StringUtils.isEmpty(part)) { + continue; + } + String url = part.trim(); + if (StringUtils.isNotEmpty(url)) { + urls.add(url); + } + } + return urls; + } + + private String resolveItemCategory(String groupCode) { + if ("1".equals(groupCode)) { + return CATEGORY_GROUP_1; + } + if ("2".equals(groupCode)) { + return CATEGORY_GROUP_2; + } + if ("3".equals(groupCode)) { + return CATEGORY_GROUP_3; + } + return CATEGORY_UNKNOWN; + } + + private Date selectUploadTime(Date updateTime, Date createTime) { + return updateTime != null ? updateTime : createTime; + } + + private String formatDate(Date date) { + if (date == null) { + return ""; + } + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); + } + + private String extractFileName(String url) { + if (StringUtils.isEmpty(url)) { + return ""; + } + String raw = url; + int queryIndex = raw.indexOf('?'); + if (queryIndex >= 0) { + raw = raw.substring(0, queryIndex); + } + int slashIndex = raw.lastIndexOf('/'); + String name = slashIndex >= 0 ? raw.substring(slashIndex + 1) : raw; + if (StringUtils.isEmpty(name)) { + return raw; + } + try { + return URLDecoder.decode(name, StandardCharsets.UTF_8.name()); + } catch (Exception ex) { + return name; + } + } + + private String resolveDisplayType(String url) { + String fileName = extractFileName(url).toLowerCase(); + if (fileName.endsWith(".jpg") + || fileName.endsWith(".jpeg") + || fileName.endsWith(".png") + || fileName.endsWith(".gif") + || fileName.endsWith(".bmp") + || fileName.endsWith(".webp")) { + return DISPLAY_TYPE_IMAGE; + } + if (fileName.endsWith(".mp4") + || fileName.endsWith(".avi") + || fileName.endsWith(".mov") + || fileName.endsWith(".wmv") + || fileName.endsWith(".mkv")) { + return DISPLAY_TYPE_VIDEO; + } + if (fileName.endsWith(".pdf") + || fileName.endsWith(".doc") + || fileName.endsWith(".docx") + || fileName.endsWith(".xls") + || fileName.endsWith(".xlsx") + || fileName.endsWith(".ppt") + || fileName.endsWith(".pptx") + || fileName.endsWith(".txt") + || fileName.endsWith(".zip") + || fileName.endsWith(".rar") + || fileName.endsWith(".7z")) { + return DISPLAY_TYPE_DOC; + } + return DISPLAY_TYPE_OTHER; + } + + private String normalizeFileUrl(String rawUrl, HttpServletRequest request) { + String url = rawUrl.trim(); + if (url.startsWith("http://") || url.startsWith("https://")) { + return url; + } + String base = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort(); + if (url.startsWith("/")) { + return base + url; + } + return base + "/" + url; + } + + private String safeFileName(String fileName, String fallbackUrl) { + String name = fileName; + if (StringUtils.isEmpty(name)) { + int slash = fallbackUrl.lastIndexOf('/'); + name = slash >= 0 ? fallbackUrl.substring(slash + 1) : fallbackUrl; + } + name = name.replace("\\", "_").replace("/", "_"); + if (StringUtils.isEmpty(name)) { + return "file"; + } + return name; + } + + private String uniqueEntryName(String fileName, Map nameCounter) { + String key = fileName.toLowerCase(); + int count = nameCounter.getOrDefault(key, 0); + nameCounter.put(key, count + 1); + if (count == 0) { + return fileName; + } + int dot = fileName.lastIndexOf('.'); + if (dot > 0) { + return fileName.substring(0, dot) + "_" + count + fileName.substring(dot); + } + return fileName + "_" + count; + } + private String generateEventNo() { return "ZR" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); } } - diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/controller/PcCameraLedgerController.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/controller/PcCameraLedgerController.java index a43e5da5..458f71d7 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/controller/PcCameraLedgerController.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/controller/PcCameraLedgerController.java @@ -82,7 +82,7 @@ public class PcCameraLedgerController extends BaseController { return toAjax(pcCameraLedgerService.deletePcCameraLedgerByCameraIds(cameraIds)); } - @Operation(summary = "球机台账-状态变更", description = "状态:0闲置 1已分配 2待回收 3已入库") + @Operation(summary = "球机台账-状态变更", description = "状态:0在库 1已分配 2待回收") @Log(title = "球机台账-状态", businessType = BusinessType.UPDATE) @PutMapping("/changeStatus") public AjaxResult changeStatus(@RequestParam("cameraId") Long cameraId, diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/domain/PcCameraLedger.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/domain/PcCameraLedger.java index 20c038c6..b5494e8e 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/domain/PcCameraLedger.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/domain/PcCameraLedger.java @@ -22,8 +22,8 @@ public class PcCameraLedger extends BaseEntity { @Schema(description = "型号") private String model; - @Excel(name = "状态", readConverterExp = "0=在库,1=已分配,2=已回收待入库,3=已入库") - @Schema(description = "状态:0在库 1已分配 2已回收待入库 3已入库") + @Excel(name = "状态", readConverterExp = "0=在库,1=已分配,2=已回收待入库") + @Schema(description = "状态:0在库 1已分配 2已回收待入库") private String status; @Excel(name = "所属单位") diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/enums/PcCameraStatus.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/enums/PcCameraStatus.java index fdce4402..0c151dd6 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/enums/PcCameraStatus.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/enums/PcCameraStatus.java @@ -8,7 +8,5 @@ public interface PcCameraStatus { String ALLOCATED = "1"; /** 台账 status:2已回收待入库 */ String RETURNED_PENDING_INBOUND = "2"; - /** 台账 status:3已入库(等同在库,可按你业务区分) */ - String INBOUNDED = "3"; } diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/mapper/PcCameraAllocMapper.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/mapper/PcCameraAllocMapper.java index d18565b2..1286ea30 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/mapper/PcCameraAllocMapper.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/mapper/PcCameraAllocMapper.java @@ -39,7 +39,7 @@ public interface PcCameraAllocMapper { /** 单条更新分配记录为入库通过(填仓库等,alloc_status=3, audit_status=1) */ int updateInboundApproveOne(PcCameraAlloc alloc); - /** 批量更新分配记录为入库驳回(audit_status=2) */ + /** 批量更新分配记录为入库驳回(alloc_status回退为1,audit_status=2) */ int updateInboundReject(@Param("allocIds") List allocIds, @Param("auditBy") String auditBy, @Param("auditRemark") String auditRemark); /** @@ -51,4 +51,4 @@ public interface PcCameraAllocMapper { * 根据摄像机编号查询当前使用该相机的项目ID(已分配且未回收完成) */ Long selectProjectIdByCameraNo(@Param("cameraNo") String cameraNo); -} \ No newline at end of file +} diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/service/impl/PcCameraBizServiceImpl.java b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/service/impl/PcCameraBizServiceImpl.java index bed318d2..c8fae788 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/service/impl/PcCameraBizServiceImpl.java +++ b/ruoyi-modules/aidmt-manage-ms/src/main/java/com/admin/property/service/impl/PcCameraBizServiceImpl.java @@ -68,11 +68,7 @@ public class PcCameraBizServiceImpl implements IPcCameraBizService { // 逐个乐观更新,避免并发重复分配 for (Long cameraId : cameraIds) { int ok0 = ledgerMapper.updateStatusIfMatch(cameraId, PcCameraStatus.IN_STOCK, PcCameraStatus.ALLOCATED); - int ok3 = 0; if (ok0 == 0) { - ok3 = ledgerMapper.updateStatusIfMatch(cameraId, PcCameraStatus.INBOUNDED, PcCameraStatus.ALLOCATED); - } - if (ok0 == 0 && ok3 == 0) { PcCameraLedger one = ledgerMapper.selectPcCameraLedgerByCameraId(cameraId); throw new ServiceException("球机不可分配,编号=" + (one != null ? one.getCameraNo() : cameraId) + ",当前状态=" + (one != null ? one.getStatus() : "未知")); } @@ -189,7 +185,7 @@ public class PcCameraBizServiceImpl implements IPcCameraBizService { } for (PcCameraAlloc a : allocs) { - int ok = ledgerMapper.updateStatusIfMatch(a.getCameraId(), PcCameraStatus.RETURNED_PENDING_INBOUND, PcCameraStatus.INBOUNDED); + int ok = ledgerMapper.updateStatusIfMatch(a.getCameraId(), PcCameraStatus.RETURNED_PENDING_INBOUND, PcCameraStatus.IN_STOCK); if (ok == 0) { PcCameraLedger one = ledgerMapper.selectPcCameraLedgerByCameraId(a.getCameraId()); throw new ServiceException("入库失败,球机状态不匹配,编号=" + (one != null ? one.getCameraNo() : a.getCameraId())); @@ -199,7 +195,11 @@ public class PcCameraBizServiceImpl implements IPcCameraBizService { PcCameraLedger ledger = new PcCameraLedger(); ledger.setCameraId(a.getCameraId()); ledger.setCameraNo(existingLedger.getCameraNo()); + ledger.setModel(existingLedger.getModel()); + ledger.setStatus(existingLedger.getStatus()); + ledger.setOwnerUnit(existingLedger.getOwnerUnit()); ledger.setWarehouse(dto.getWarehouse()); + ledger.setRemark(existingLedger.getRemark()); ledger.setUpdateBy(username); ledgerMapper.updatePcCameraLedger(ledger); } @@ -207,7 +207,12 @@ public class PcCameraBizServiceImpl implements IPcCameraBizService { return rows; } - /** ④ 入库审核驳回:仅更新分配记录 audit_status=2(单条审核) */ + /** + * ④ 入库审核驳回: + * 1. 分配记录回退到“已分配”状态,回到回收入库列表重新提交; + * 2. 台账状态从“待入库”回滚到“已分配”,与分配记录保持一致; + * 3. 审核状态标记为驳回,保留驳回意见。 + */ @Override @Transactional(rollbackFor = Exception.class) public int rejectInbound(PcCameraInboundAuditDTO dto) { @@ -222,6 +227,15 @@ public class PcCameraBizServiceImpl implements IPcCameraBizService { } } - return allocMapper.updateInboundReject(java.util.Collections.singletonList(dto.getAllocId()), username, dto.getAuditRemark()); + // 审核驳回后,退回到回收提交节点,需要回滚台账状态。 + for (PcCameraAlloc a : allocs) { + int ok = ledgerMapper.updateStatusIfMatch(a.getCameraId(), PcCameraStatus.RETURNED_PENDING_INBOUND, PcCameraStatus.ALLOCATED); + if (ok == 0) { + PcCameraLedger one = ledgerMapper.selectPcCameraLedgerByCameraId(a.getCameraId()); + throw new ServiceException("驳回失败,球机台账状态不匹配,编号=" + (one != null ? one.getCameraNo() : a.getCameraId())); + } + } + + return allocMapper.updateInboundReject(Collections.singletonList(dto.getAllocId()), username, dto.getAuditRemark()); } } diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/AccessPermitMapper.xml b/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/AccessPermitMapper.xml index d747512a..8836bf25 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/AccessPermitMapper.xml +++ b/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/AccessPermitMapper.xml @@ -36,11 +36,21 @@ @@ -101,6 +111,7 @@ left join sys_user u on u.user_id = wt.supervisor_id and u.del_flag = '0' left join sys_dept d on d.dept_id = u.dept_id and d.del_flag = '0' where ap.del_flag = '0' + and wp.approval_status = '1' and wp.project_name like concat('%', #{projectName}, '%') diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/PcCameraAllocMapper.xml b/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/PcCameraAllocMapper.xml index 6899f093..5b1ac4ec 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/PcCameraAllocMapper.xml +++ b/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/PcCameraAllocMapper.xml @@ -144,6 +144,7 @@ a.return_time as returnTime, a.return_photo_urls as returnPhotoUrls, a.return_remark as returnRemark, + a.alloc_status as allocStatus, a.audit_status as auditStatus, l.camera_no as cameraNo, l.model as model, @@ -155,6 +156,7 @@ left join pc_camera_risk p on p.application_id = a.application_id and p.del_flag='0' left join work_plan wp on wp.project_id = p.project_id and wp.del_flag='0' where a.del_flag='0' + and a.alloc_status != 1 and a.audit_status = #{auditStatus} @@ -207,6 +209,7 @@ update pc_camera_alloc set + alloc_status = '1', audit_status = '2', audit_by = #{auditBy}, audit_time = now(), diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/PcCameraLedgerMapper.xml b/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/PcCameraLedgerMapper.xml index 85bce84b..d487e24d 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/PcCameraLedgerMapper.xml +++ b/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/PcCameraLedgerMapper.xml @@ -66,7 +66,7 @@ + + diff --git a/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/WorkPlanMapper.xml b/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/WorkPlanMapper.xml index 0e384751..2e0f1409 100644 --- a/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/WorkPlanMapper.xml +++ b/ruoyi-modules/aidmt-manage-ms/src/main/resources/mapper/WorkPlanMapper.xml @@ -47,6 +47,7 @@ + + + insert into owner_access_audit_item( event_id, group_code, item_name, score, compliance, problem_desc, material_urls, severity, diff --git a/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/controller/SysDeptController.java b/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/controller/SysDeptController.java index d6f9039a..18b1bce1 100644 --- a/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/controller/SysDeptController.java +++ b/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/controller/SysDeptController.java @@ -50,6 +50,7 @@ public class SysDeptController extends BaseController @GetMapping("/list") public TableDataInfo list(SysDept dept) { + markSkipThirdPartyScore(dept); // 如果没有指定审核状态,默认只查询审核通过的部门 if (StringUtils.isEmpty(dept.getAuditStatus())) { @@ -70,9 +71,11 @@ public class SysDeptController extends BaseController @GetMapping("/audit/list") public TableDataInfo auditList(SysDept dept) { + markSkipThirdPartyScore(dept); startPage(); List depts = deptService.selectDeptList(dept); - return getDataTable(depts); + List deptsWithHierarchy = deptService.buildDeptHierarchyList(depts); + return getDataTable(deptsWithHierarchy); } /** @@ -227,4 +230,14 @@ public class SysDeptController extends BaseController return toAjax(deptService.changeDeptStatus(deptId, status)); } + + private void markSkipThirdPartyScore(SysDept dept) + { + if (dept == null) + { + return; + } + // 部门列表默认不依赖第三方评分,避免外部不可用导致接口超时/报错 + dept.getParams().put("skipThirdPartyScore", true); + } } diff --git a/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/controller/SysUserController.java b/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/controller/SysUserController.java index 3c1a1b95..50d492e5 100644 --- a/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/controller/SysUserController.java +++ b/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/controller/SysUserController.java @@ -80,7 +80,6 @@ public class SysUserController extends BaseController * 获取用户列表 */ @Operation(summary = "获取用户列表") - @RequiresPermissions("system:user:list") @GetMapping("/list") public TableDataInfo list(SysUser user) { @@ -91,7 +90,6 @@ public class SysUserController extends BaseController @Operation(summary = "导出用户数据") @Log(title = "用户管理", businessType = BusinessType.EXPORT) - @RequiresPermissions("system:user:export") @PostMapping("/export") public void export(HttpServletResponse response, SysUser user) { @@ -102,7 +100,6 @@ public class SysUserController extends BaseController @Operation(summary = "导入用户数据") @Log(title = "用户管理", businessType = BusinessType.IMPORT) - @RequiresPermissions("system:user:import") @PostMapping("/importData") public AjaxResult importData(@Parameter(description = "导入文件") MultipartFile file, @Parameter(description = "是否更新支持") boolean updateSupport) throws Exception { @@ -230,7 +227,6 @@ public class SysUserController extends BaseController * 根据用户编号获取详细信息 */ @Operation(summary = "根据用户编号获取详细信息") - @RequiresPermissions("system:user:query") @GetMapping(value = { "/", "/{userId}" }) public AjaxResult getInfo(@Parameter(description = "用户ID") @PathVariable(value = "userId", required = false) Long userId) { @@ -256,7 +252,6 @@ public class SysUserController extends BaseController * 新增用户 */ @Operation(summary = "新增用户") - @RequiresPermissions("system:user:add") @Log(title = "用户管理", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@Validated @RequestBody SysUser user) @@ -289,7 +284,6 @@ public class SysUserController extends BaseController * 修改用户 */ @Operation(summary = "修改用户") - @RequiresPermissions("system:user:edit") @Log(title = "用户管理", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@Validated @RequestBody SysUser user) @@ -323,7 +317,6 @@ public class SysUserController extends BaseController * 删除用户 */ @Operation(summary = "删除用户") - @RequiresPermissions("system:user:remove") @Log(title = "用户管理", businessType = BusinessType.DELETE) @DeleteMapping("/{userIds}") public AjaxResult remove(@Parameter(description = "用户ID数组") @PathVariable Long[] userIds) @@ -339,7 +332,6 @@ public class SysUserController extends BaseController * 重置密码 */ @Operation(summary = "重置用户密码") - @RequiresPermissions("system:user:edit") @Log(title = "用户管理", businessType = BusinessType.UPDATE) @PutMapping("/resetPwd") public AjaxResult resetPwd(@RequestBody SysUser user) @@ -355,7 +347,6 @@ public class SysUserController extends BaseController * 状态修改 */ @Operation(summary = "修改用户状态") - @RequiresPermissions("system:user:edit") @Log(title = "用户管理", businessType = BusinessType.UPDATE) @PutMapping("/changeStatus") public AjaxResult changeStatus(@RequestBody SysUser user) @@ -370,7 +361,6 @@ public class SysUserController extends BaseController * 根据用户编号获取授权角色 */ @Operation(summary = "根据用户编号获取授权角色") - @RequiresPermissions("system:user:query") @GetMapping("/authRole/{userId}") public AjaxResult authRole(@Parameter(description = "用户ID") @PathVariable("userId") Long userId) { @@ -386,7 +376,6 @@ public class SysUserController extends BaseController * 用户授权角色 */ @Operation(summary = "用户授权角色") - @RequiresPermissions("system:user:edit") @Log(title = "用户管理", businessType = BusinessType.GRANT) @PutMapping("/authRole") public AjaxResult insertAuthRole(@Parameter(description = "用户ID") Long userId, @Parameter(description = "角色ID数组") Long[] roleIds) @@ -401,7 +390,6 @@ public class SysUserController extends BaseController * 获取部门树列表 */ @Operation(summary = "获取部门树列表") - @RequiresPermissions("system:user:list") @GetMapping("/deptTree") public AjaxResult deptTree(SysDept dept) { @@ -413,7 +401,6 @@ public class SysUserController extends BaseController * status:0正常 1停用 2待审核 3审核不通过。审核通过传 0 或 1,审核不通过传 3(此时 auditOpinion 必填)。 */ @Operation(summary = "审核用户", description = "请求体:status(0正常/1停用/3审核不通过);status=3 时 auditOpinion 必填") - @RequiresPermissions("system:user:audit") @Log(title = "用户审核", businessType = BusinessType.UPDATE) @PutMapping("/audit/{userId}") public AjaxResult audit(@Parameter(description = "用户ID") @PathVariable Long userId, @RequestBody java.util.Map params) diff --git a/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java index 57b6c4f9..73b78361 100644 --- a/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java +++ b/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java @@ -54,6 +54,10 @@ public class SysDeptServiceImpl implements ISysDeptService public List selectDeptList(SysDept dept) { List depts = deptMapper.selectDeptList(dept); + if (shouldSkipThirdPartyScore(dept)) + { + return depts; + } // 为每个部门获取企业评分(只针对施工单位、监理单位、业主单位) if (thirdPartyService != null && depts != null && !depts.isEmpty()) { ObjectMapper objectMapper = new ObjectMapper(); @@ -126,10 +130,33 @@ public class SysDeptServiceImpl implements ISysDeptService @Override public List selectDeptTreeList(SysDept dept) { + if (dept == null) + { + dept = new SysDept(); + } + dept.getParams().put("skipThirdPartyScore", true); List depts = SpringUtils.getAopProxy(this).selectDeptList(dept); return buildDeptTreeSelect(depts); } + private boolean shouldSkipThirdPartyScore(SysDept dept) + { + if (dept == null || dept.getParams() == null) + { + return false; + } + Object flag = dept.getParams().get("skipThirdPartyScore"); + if (flag instanceof Boolean) + { + return (Boolean) flag; + } + if (flag instanceof String) + { + return Boolean.parseBoolean((String) flag); + } + return false; + } + /** * 构建前端所需要树结构 * diff --git a/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index 664f31f5..1e8030db 100644 --- a/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -72,7 +72,6 @@ public class SysUserServiceImpl implements ISysUserService * @return 用户信息集合信息 */ @Override - @DataScope(deptAlias = "d", userAlias = "u") public List selectUserList(SysUser user) { return userMapper.selectUserList(user); @@ -85,7 +84,6 @@ public class SysUserServiceImpl implements ISysUserService * @return 用户信息集合信息 */ @Override - @DataScope(deptAlias = "d", userAlias = "u") public List selectAllocatedList(SysUser user) { return userMapper.selectAllocatedList(user); @@ -98,7 +96,6 @@ public class SysUserServiceImpl implements ISysUserService * @return 用户信息集合信息 */ @Override - @DataScope(deptAlias = "d", userAlias = "u") public List selectUnallocatedList(SysUser user) { return userMapper.selectUnallocatedList(user); diff --git a/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/utils/ThirdPartyHttpClient.java b/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/utils/ThirdPartyHttpClient.java index 63767b53..61d3c94f 100644 --- a/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/utils/ThirdPartyHttpClient.java +++ b/ruoyi-modules/aidmt-system-ms/src/main/java/com/ruoyi/system/utils/ThirdPartyHttpClient.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.http.*; import org.springframework.stereotype.Component; +import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; import javax.annotation.PostConstruct; @@ -21,12 +22,17 @@ import java.util.Collections; public class ThirdPartyHttpClient { private static final String BASE_URL = "http://1.13.245.108/trainCore"; + private static final int CONNECT_TIMEOUT_MS = 1500; + private static final int READ_TIMEOUT_MS = 2500; private static final ObjectMapper objectMapper = new ObjectMapper(); private RestTemplate restTemplate; @PostConstruct public void init() { - restTemplate = new RestTemplate(); + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setConnectTimeout(CONNECT_TIMEOUT_MS); + factory.setReadTimeout(READ_TIMEOUT_MS); + restTemplate = new RestTemplate(factory); } /** diff --git a/ruoyi-modules/aidmt-system-ms/src/main/resources/mapper/system/SysDeptMapper.xml b/ruoyi-modules/aidmt-system-ms/src/main/resources/mapper/system/SysDeptMapper.xml index 113b4c9d..9cf4b079 100644 --- a/ruoyi-modules/aidmt-system-ms/src/main/resources/mapper/system/SysDeptMapper.xml +++ b/ruoyi-modules/aidmt-system-ms/src/main/resources/mapper/system/SysDeptMapper.xml @@ -72,7 +72,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ${params.dataScope} - order by d.parent_id, d.order_num + order by d.create_time desc, d.dept_id desc