| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.ruoyi.projectManagement.service; |
| | | |
| | | import com.fasterxml.jackson.core.type.TypeReference; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | import com.ruoyi.projectManagement.dto.ProjectWorkflowDtos; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; |
| | | import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; |
| | | import org.springframework.jdbc.support.GeneratedKeyHolder; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDate; |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class ProjectWorkflowService { |
| | | private static final TypeReference<List<Map<String, Object>>> FILE_LIST_TYPE = new TypeReference<>() { }; |
| | | private static final List<String> PHASE_CODES = List.of("INITIATION", "DEVELOPMENT", "APPLICATION", "RESULT", "ACCEPTANCE"); |
| | | private static final List<String> PHASE_NAMES = List.of("ç«é¡¹", "å¼å", "ç³æ¥", "ç³æ¥ç»æ", "éªæ¶"); |
| | | |
| | | private final NamedParameterJdbcTemplate jdbc; |
| | | private final ObjectMapper objectMapper; |
| | | |
| | | public Map<String, Object> getWorkbench(Long projectId) { |
| | | requireProject(projectId); |
| | | List<Map<String, Object>> modules = query(""" |
| | | select m.id, m.project_id as projectId, m.module_name as moduleName, |
| | | m.planned_start_date as plannedStartDate, m.summary, |
| | | m.project_weight as projectWeight, m.current_progress as currentProgress, |
| | | (select count(*) from project_management_progress_report r where r.module_id=m.id and r.is_deleted=0) as reportCount, |
| | | m.create_time as createTime, m.update_time as updateTime |
| | | from project_management_module m |
| | | where m.project_id=:projectId and m.is_deleted=0 order by m.id |
| | | """, Map.of("projectId", projectId)); |
| | | for (Map<String, Object> module : modules) { |
| | | Long moduleId = asLong(module.get("id")); |
| | | module.put("members", query(""" |
| | | select id, module_id as moduleId, user_id as userId, user_name as userName, |
| | | module_share as moduleShare |
| | | from project_management_module_member |
| | | where module_id=:moduleId and is_deleted=0 order by id |
| | | """, Map.of("moduleId", moduleId))); |
| | | } |
| | | |
| | | List<Map<String, Object>> followUps = query(""" |
| | | select id, project_id as projectId, follow_date as followDate, detail, |
| | | attachments, create_user_id as createUserId, create_user_name as createUserName, |
| | | create_time as createTime |
| | | from project_management_follow_up |
| | | where project_id=:projectId and is_deleted=0 order by follow_date desc,id desc |
| | | """, Map.of("projectId", projectId)); |
| | | parseAttachments(followUps); |
| | | |
| | | List<Map<String, Object>> reports = query(""" |
| | | select r.id, r.project_id as projectId, r.module_id as moduleId, |
| | | m.module_name as moduleName, r.reporter_ids as reporterIds, |
| | | r.reporter_names as reporterNames, r.progress, r.report_date as reportDate, |
| | | r.reporter_shares as reporterShares, r.remark, r.attachments, r.create_time as createTime |
| | | from project_management_progress_report r |
| | | left join project_management_module m on m.id=r.module_id |
| | | where r.project_id=:projectId and r.is_deleted=0 order by r.report_date desc,r.id desc |
| | | """, Map.of("projectId", projectId)); |
| | | parseAttachments(reports); |
| | | for (Map<String, Object> row : reports) { |
| | | row.put("reporterIdList", parseLongList(row.get("reporterIds"))); |
| | | row.put("reporterNameList", parseStringList(row.get("reporterNames"))); |
| | | row.put("reporterShareList", parseFileList(row.get("reporterShares"))); |
| | | } |
| | | |
| | | List<Map<String, Object>> materials = query(""" |
| | | select id, project_id as projectId, material_name as materialName, |
| | | material_type as materialType, remark, attachments, |
| | | create_user_name as createUserName, create_time as createTime |
| | | from project_management_material |
| | | where project_id=:projectId and is_deleted=0 order by id desc |
| | | """, Map.of("projectId", projectId)); |
| | | parseAttachments(materials); |
| | | |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | result.put("modules", modules); |
| | | result.put("followUps", followUps); |
| | | result.put("reports", reports); |
| | | result.put("materials", materials); |
| | | result.put("sourceBusiness", getSourceBusiness(projectId)); |
| | | result.put("memberStatistics", memberStatistics(projectId)); |
| | | result.put("followWindow", getFollowWindow(projectId)); |
| | | return result; |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void startProject(Long projectId) { |
| | | requireProject(projectId); |
| | | Integer basicReady = jdbc.queryForObject(""" |
| | | select count(*) from project_management_info |
| | | where id=:projectId and is_delete=0 and project_classification is not null |
| | | and project_classification<>'' and plan_start_time is not null and plan_end_time is not null |
| | | and project_leader_id is not null and project_manager_ids is not null |
| | | and json_length(project_manager_ids)>0 and follow_cycle is not null and follow_cycle<>'' |
| | | and project_executor_ids is not null and json_length(project_executor_ids)>0 |
| | | """, Map.of("projectId", projectId), Integer.class); |
| | | if (basicReady == null || basicReady == 0) throw new ServiceException("请å
宿´å¡«å项ç®åºæ¬æ
åµ"); |
| | | List<Map<String, Object>> modules = query(""" |
| | | select id,module_name as moduleName,planned_start_date as plannedStartDate, |
| | | summary,project_weight as projectWeight |
| | | from project_management_module where project_id=:projectId and is_deleted=0 |
| | | """, Map.of("projectId", projectId)); |
| | | if (modules.isEmpty()) throw new ServiceException("项ç®å¼å§å请è³å°æ·»å ä¸ä¸ªé¡¹ç®æ¨¡å"); |
| | | BigDecimal total = BigDecimal.ZERO; |
| | | for (Map<String, Object> module : modules) { |
| | | if (isBlank(Objects.toString(module.get("moduleName"), "")) || module.get("plannedStartDate") == null |
| | | || isBlank(Objects.toString(module.get("summary"), ""))) { |
| | | throw new ServiceException("è¯·å®æ´å¡«åæ¯ä¸ªæ¨¡åçåç§°ãé¢è®¡å¼å§æ¶é´åæ¨¡åæ¦è¦"); |
| | | } |
| | | total = total.add(nvl((BigDecimal) module.get("projectWeight"))); |
| | | Long moduleId = asLong(module.get("id")); |
| | | Integer memberCount = jdbc.queryForObject(""" |
| | | select count(*) from project_management_module_member |
| | | where module_id=:moduleId and is_deleted=0 |
| | | """, Map.of("moduleId", moduleId), Integer.class); |
| | | if (memberCount == null || memberCount == 0) throw new ServiceException("æ¯ä¸ªæ¨¡åè³å°éæ©ä¸åæ§è¡äºº"); |
| | | } |
| | | if (total.setScale(2, RoundingMode.HALF_UP).compareTo(BigDecimal.valueOf(100).setScale(2)) != 0) { |
| | | throw new ServiceException("项ç®å¼å§åï¼æææ¨¡åç项ç®å·¥ä½éå æ¯å计å¿
须为100%"); |
| | | } |
| | | jdbc.update("update project_management_info set current_phase='å¼å',update_time=now() where id=:projectId", Map.of("projectId", projectId)); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void transitionStage(ProjectWorkflowDtos.StageTransitionRequest request) { |
| | | requireProject(request.getProjectId()); |
| | | String current = jdbc.queryForObject("select current_phase from project_management_info where id=:id and is_delete=0", |
| | | Map.of("id", request.getProjectId()), String.class); |
| | | if ("ç«é¡¹".equals(current)) current = "å¼å"; |
| | | Map<String, String> nextStages = Map.of( |
| | | "å¼å", "ç³æ¥", |
| | | "ç³æ¥", "ç³æ¥ç»æ", |
| | | "ç³æ¥ç»æ", "éªæ¶", |
| | | "éªæ¶", "已宿" |
| | | ); |
| | | String expected = nextStages.get(current); |
| | | if (expected == null || !expected.equals(request.getTargetStage())) { |
| | | throw new ServiceException("项ç®é¶æ®µåªè½æå¼åãç³æ¥ãç³æ¥ç»æãéªæ¶ã已宿çé¡ºåºæ¨è¿"); |
| | | } |
| | | if ("å¼å".equals(current)) { |
| | | Integer unfinished = jdbc.queryForObject(""" |
| | | select count(*) from project_management_module |
| | | where project_id=:projectId and is_deleted=0 and current_progress<100 |
| | | """, Map.of("projectId", request.getProjectId()), Integer.class); |
| | | if (unfinished != null && unfinished > 0) { |
| | | throw new ServiceException("ææé¡¹ç®æ¨¡åè¿åº¦è¾¾å°100%åæè½è¿å
¥ç³æ¥é¶æ®µ"); |
| | | } |
| | | } |
| | | jdbc.update("update project_management_info set current_phase=:stage,update_time=now() where id=:projectId", |
| | | new MapSqlParameterSource().addValue("stage", expected).addValue("projectId", request.getProjectId())); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateProjectExecutors(ProjectWorkflowDtos.ProjectExecutorsRequest request) { |
| | | requireProject(request.getProjectId()); |
| | | validateMembers(request.getExecutors()); |
| | | List<Map<String, Object>> rows = query(""" |
| | | select project_executor_ids as executorIds from project_management_info |
| | | where id=:projectId and is_delete=0 |
| | | """, Map.of("projectId", request.getProjectId())); |
| | | List<Long> oldIds = rows.isEmpty() ? List.of() : parseLongList(rows.getFirst().get("executorIds")); |
| | | List<Long> newIds = request.getExecutors().stream().map(ProjectWorkflowDtos.MemberRequest::getUserId).toList(); |
| | | for (Long removedId : oldIds.stream().filter(id -> !newIds.contains(id)).toList()) { |
| | | if (hasPositiveProjectShare(request.getProjectId(), removedId)) { |
| | | throw new ServiceException("è¯¥é¡¹ç®æ§è¡äººå·²æé¡¹ç®æ±æ¥å·¥ä½å æ¯ï¼ä¸è½å é¤"); |
| | | } |
| | | } |
| | | jdbc.update(""" |
| | | update project_management_info set project_executor_ids=:ids,project_executor_names=:names,update_time=now() |
| | | where id=:projectId and is_delete=0 |
| | | """, new MapSqlParameterSource().addValue("projectId", request.getProjectId()) |
| | | .addValue("ids", json(newIds)) |
| | | .addValue("names", json(request.getExecutors().stream().map(ProjectWorkflowDtos.MemberRequest::getUserName).toList()))); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long savePhase(ProjectWorkflowDtos.PhaseRequest request) { |
| | | requireProject(request.getProjectId()); |
| | | ensurePhases(request.getProjectId()); |
| | | int index = PHASE_CODES.indexOf(Objects.toString(request.getPhaseCode(), "")); |
| | | if (index < 0) throw new ServiceException("项ç®é¶æ®µä¸æ£ç¡®"); |
| | | String status = Objects.toString(request.getStatus(), "IN_PROGRESS").toUpperCase(); |
| | | if (!List.of("NOT_STARTED", "IN_PROGRESS", "COMPLETED").contains(status)) { |
| | | throw new ServiceException("é¶æ®µç¶æä¸æ£ç¡®"); |
| | | } |
| | | if (index > 0 && !"NOT_STARTED".equals(status)) { |
| | | Integer previousDone = jdbc.queryForObject(""" |
| | | select count(*) from project_management_phase |
| | | where project_id=:projectId and phase_code=:phaseCode and status='COMPLETED' and is_deleted=0 |
| | | """, new MapSqlParameterSource().addValue("projectId", request.getProjectId()) |
| | | .addValue("phaseCode", PHASE_CODES.get(index - 1)), Integer.class); |
| | | if (previousDone == null || previousDone == 0) { |
| | | throw new ServiceException("请å
宿ä¸ä¸é¶æ®µâ" + PHASE_NAMES.get(index - 1) + "â"); |
| | | } |
| | | } |
| | | MapSqlParameterSource p = new MapSqlParameterSource() |
| | | .addValue("projectId", request.getProjectId()).addValue("phaseCode", request.getPhaseCode()) |
| | | .addValue("status", status).addValue("formData", jsonObject(request.getFormData())) |
| | | .addValue("remark", request.getRemark()).addValue("attachments", json(request.getAttachments())) |
| | | .addValue("userName", currentUserName()); |
| | | jdbc.update(""" |
| | | update project_management_phase set status=:status,form_data=:formData,remark=:remark, |
| | | attachments=:attachments,completed_time=case when :status='COMPLETED' then now() else null end, |
| | | update_user_name=:userName,update_time=now() |
| | | where project_id=:projectId and phase_code=:phaseCode and is_deleted=0 |
| | | """, p); |
| | | String currentPhase = "COMPLETED".equals(status) && index == PHASE_CODES.size() - 1 |
| | | ? "已宿" : PHASE_NAMES.get(index); |
| | | jdbc.update("update project_management_info set current_phase=:phase,update_time=now() where id=:projectId", |
| | | new MapSqlParameterSource().addValue("phase", currentPhase).addValue("projectId", request.getProjectId())); |
| | | return jdbc.queryForObject("select id from project_management_phase where project_id=:projectId and phase_code=:phaseCode and is_deleted=0", |
| | | p, Long.class); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long saveModule(ProjectWorkflowDtos.ModuleSaveRequest request) { |
| | | requireProject(request.getProjectId()); |
| | | if (isBlank(request.getModuleName())) { |
| | | throw new ServiceException("请è¾å
¥æ¨¡ååç§°"); |
| | | } |
| | | if (request.getPlannedStartDate() == null) throw new ServiceException("è¯·éæ©æ¨¡åé¢è®¡å¼å§æ¶é´"); |
| | | if (isBlank(request.getSummary())) throw new ServiceException("请è¾å
¥æ¨¡åæ¦è¦"); |
| | | BigDecimal weight = percent(request.getProjectWeight(), "模åå¨é¡¹ç®ä¸çå·¥ä½éå æ¯"); |
| | | BigDecimal otherWeight = jdbc.queryForObject(""" |
| | | select coalesce(sum(project_weight),0) from project_management_module |
| | | where project_id=:projectId and is_deleted=0 and (:id is null or id<>:id) |
| | | """, new MapSqlParameterSource().addValue("projectId", request.getProjectId()).addValue("id", request.getId()), BigDecimal.class); |
| | | BigDecimal available = BigDecimal.valueOf(100).subtract(nvl(otherWeight)); |
| | | if (weight.compareTo(available) > 0) { |
| | | throw new ServiceException("å
¶ä»æ¨¡åå·²å " + nvl(otherWeight).stripTrailingZeros().toPlainString() |
| | | + "%ï¼å½å模åæå¤å¯è®¾ç½®" + available.stripTrailingZeros().toPlainString() + "%"); |
| | | } |
| | | validateMembers(request.getMembers()); |
| | | List<Long> projectExecutorIds = projectExecutorIds(request.getProjectId()); |
| | | if (request.getMembers().stream().anyMatch(member -> !projectExecutorIds.contains(member.getUserId()))) { |
| | | throw new ServiceException("æ¨¡åæ§è¡äººå¿
é¡»å
å å
¥é¡¹ç®æ§è¡äºº"); |
| | | } |
| | | |
| | | if (request.getId() != null) { |
| | | Integer reportCount = jdbc.queryForObject("select count(*) from project_management_progress_report where module_id=:id and is_deleted=0", |
| | | Map.of("id", request.getId()), Integer.class); |
| | | if (reportCount != null && reportCount > 0) { |
| | | Map<String, Object> old = query(""" |
| | | select module_name as moduleName,planned_start_date as plannedStartDate, |
| | | summary,project_weight as projectWeight from project_management_module |
| | | where id=:id and project_id=:projectId and is_deleted=0 |
| | | """, new MapSqlParameterSource().addValue("id", request.getId()).addValue("projectId", request.getProjectId())).stream() |
| | | .findFirst().orElseThrow(() -> new ServiceException("é¡¹ç®æ¨¡åä¸åå¨")); |
| | | boolean changed = !Objects.equals(Objects.toString(old.get("moduleName"), ""), request.getModuleName().trim()) |
| | | || !Objects.equals(Objects.toString(old.get("plannedStartDate"), ""), Objects.toString(request.getPlannedStartDate(), "")) |
| | | || !Objects.equals(Objects.toString(old.get("summary"), ""), Objects.toString(request.getSummary(), "")) |
| | | || nvl((BigDecimal) old.get("projectWeight")).compareTo(weight) != 0; |
| | | if (changed) throw new ServiceException("该模åå·²æè¿åº¦æ±æ¥ï¼æ¨¡ååºç¡ä¿¡æ¯åå æ¯ä¸è½ä¿®æ¹ï¼ä»
å¯è°æ´æ§è¡äºº"); |
| | | } |
| | | List<Long> oldMemberIds = query(""" |
| | | select user_id as userId from project_management_module_member |
| | | where module_id=:moduleId and is_deleted=0 |
| | | """, Map.of("moduleId", request.getId())).stream().map(row -> asLong(row.get("userId"))).toList(); |
| | | List<Long> newMemberIds = request.getMembers().stream().map(ProjectWorkflowDtos.MemberRequest::getUserId).toList(); |
| | | for (Long removedId : oldMemberIds.stream().filter(id -> !newMemberIds.contains(id)).toList()) { |
| | | if (hasPositiveModuleShare(request.getId(), removedId)) { |
| | | throw new ServiceException("è¯¥æ¨¡åæ§è¡äººå·²ææ¬æ¨¡åå·¥ä½å æ¯ï¼ä¸è½å é¤"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | Long moduleId = request.getId(); |
| | | MapSqlParameterSource params = new MapSqlParameterSource() |
| | | .addValue("projectId", request.getProjectId()) |
| | | .addValue("moduleName", request.getModuleName().trim()) |
| | | .addValue("plannedStartDate", request.getPlannedStartDate()) |
| | | .addValue("summary", request.getSummary()) |
| | | .addValue("projectWeight", weight); |
| | | if (moduleId == null) { |
| | | GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); |
| | | jdbc.update(""" |
| | | insert into project_management_module |
| | | (project_id,module_name,planned_start_date,summary,project_weight,current_progress,is_deleted,create_time,update_time) |
| | | values (:projectId,:moduleName,:plannedStartDate,:summary,:projectWeight,0,0,now(),now()) |
| | | """, params, keyHolder, new String[]{"id"}); |
| | | moduleId = Objects.requireNonNull(keyHolder.getKey()).longValue(); |
| | | } else { |
| | | params.addValue("id", moduleId); |
| | | int rows = jdbc.update(""" |
| | | update project_management_module set module_name=:moduleName, |
| | | planned_start_date=:plannedStartDate,summary=:summary,project_weight=:projectWeight,update_time=now() |
| | | where id=:id and project_id=:projectId and is_deleted=0 |
| | | """, params); |
| | | if (rows == 0) throw new ServiceException("é¡¹ç®æ¨¡åä¸åå¨"); |
| | | jdbc.update("update project_management_module_member set is_deleted=1 where module_id=:id", Map.of("id", moduleId)); |
| | | } |
| | | for (ProjectWorkflowDtos.MemberRequest member : request.getMembers()) { |
| | | jdbc.update(""" |
| | | insert into project_management_module_member |
| | | (module_id,user_id,user_name,module_share,is_deleted,create_time,update_time) |
| | | values (:moduleId,:userId,:userName,:moduleShare,0,now(),now()) |
| | | """, new MapSqlParameterSource() |
| | | .addValue("moduleId", moduleId) |
| | | .addValue("userId", member.getUserId()) |
| | | .addValue("userName", member.getUserName()) |
| | | .addValue("moduleShare", BigDecimal.ZERO)); |
| | | } |
| | | return moduleId; |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteModule(Long id) { |
| | | int count = jdbc.queryForObject("select count(*) from project_management_progress_report where module_id=:id and is_deleted=0", Map.of("id", id), Integer.class); |
| | | if (count > 0) throw new ServiceException("该模åå·²æè¿åº¦æ±æ¥ï¼ä¸è½å é¤"); |
| | | jdbc.update("update project_management_module set is_deleted=1,update_time=now() where id=:id", Map.of("id", id)); |
| | | jdbc.update("update project_management_module_member set is_deleted=1,update_time=now() where module_id=:id", Map.of("id", id)); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long saveFollowUp(ProjectWorkflowDtos.FollowUpRequest request) { |
| | | requireProject(request.getProjectId()); |
| | | Long leaderId = jdbc.queryForObject("select project_leader_id from project_management_info where id=:id", |
| | | Map.of("id", request.getProjectId()), Long.class); |
| | | if (leaderId == null || !leaderId.equals(SecurityUtils.getUserId())) { |
| | | throw new ServiceException("åªæé¡¹ç®è´è´£äººå¯ä»¥å¡«å项ç®è·è¿"); |
| | | } |
| | | if (request.getFollowDate() == null || isBlank(request.getDetail())) { |
| | | throw new ServiceException("请填åè·è¿æ¥æåè·è¿è¯¦æ
"); |
| | | } |
| | | validateFollowWindow(request.getProjectId(), request.getFollowDate(), request.getId()); |
| | | MapSqlParameterSource p = new MapSqlParameterSource() |
| | | .addValue("id", request.getId()).addValue("projectId", request.getProjectId()) |
| | | .addValue("followDate", request.getFollowDate()).addValue("detail", request.getDetail()) |
| | | .addValue("attachments", json(request.getAttachments())) |
| | | .addValue("userId", SecurityUtils.getUserId()).addValue("userName", currentUserName()); |
| | | if (request.getId() == null) { |
| | | GeneratedKeyHolder keys = new GeneratedKeyHolder(); |
| | | jdbc.update(""" |
| | | insert into project_management_follow_up |
| | | (project_id,follow_date,detail,attachments,create_user_id,create_user_name,is_deleted,create_time,update_time) |
| | | values (:projectId,:followDate,:detail,:attachments,:userId,:userName,0,now(),now()) |
| | | """, p, keys, new String[]{"id"}); |
| | | return Objects.requireNonNull(keys.getKey()).longValue(); |
| | | } |
| | | jdbc.update(""" |
| | | update project_management_follow_up set follow_date=:followDate,detail=:detail, |
| | | attachments=:attachments,update_time=now() where id=:id and project_id=:projectId and is_deleted=0 |
| | | """, p); |
| | | return request.getId(); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long saveReport(ProjectWorkflowDtos.ProgressReportRequest request) { |
| | | requireProject(request.getProjectId()); |
| | | if (request.getModuleId() == null || request.getReportDate() == null) { |
| | | throw new ServiceException("è¯·éæ©é¡¹ç®æ¨¡ååæ±æ¥æ¶é´"); |
| | | } |
| | | BigDecimal progress = percent(request.getProgress(), "模åè¿åº¦"); |
| | | BigDecimal current = jdbc.queryForObject(""" |
| | | select current_progress from project_management_module |
| | | where id=:moduleId and project_id=:projectId and is_deleted=0 |
| | | """, new MapSqlParameterSource().addValue("moduleId", request.getModuleId()).addValue("projectId", request.getProjectId()), BigDecimal.class); |
| | | if (current == null) throw new ServiceException("é¡¹ç®æ¨¡åä¸åå¨"); |
| | | if (progress.compareTo(current) < 0) throw new ServiceException("æ¬æ¬¡è¿åº¦ä¸è½ä½äºæ¨¡åå½åè¿åº¦"); |
| | | List<ProjectWorkflowDtos.MemberRequest> reporterShares = normalizeReporterShares(request); |
| | | validateReporterShares(reporterShares); |
| | | List<Long> moduleMemberIds = query(""" |
| | | select user_id as userId from project_management_module_member |
| | | where module_id=:moduleId and is_deleted=0 |
| | | """, Map.of("moduleId", request.getModuleId())).stream().map(row -> asLong(row.get("userId"))).toList(); |
| | | if (!moduleMemberIds.contains(SecurityUtils.getUserId())) throw new ServiceException("åªæè¯¥æ¨¡åæ§è¡äººå¯ä»¥æäº¤è¿åº¦æ±æ¥"); |
| | | if (reporterShares.stream().anyMatch(member -> !moduleMemberIds.contains(member.getUserId()))) { |
| | | throw new ServiceException("æ±æ¥äººååªè½éæ©è¯¥æ¨¡åæ§è¡äºº"); |
| | | } |
| | | request.setReporterIds(reporterShares.stream().map(ProjectWorkflowDtos.MemberRequest::getUserId).toList()); |
| | | request.setReporterNames(reporterShares.stream().map(ProjectWorkflowDtos.MemberRequest::getUserName).toList()); |
| | | MapSqlParameterSource p = new MapSqlParameterSource() |
| | | .addValue("id", request.getId()).addValue("projectId", request.getProjectId()) |
| | | .addValue("moduleId", request.getModuleId()) |
| | | .addValue("reporterIds", json(request.getReporterIds())) |
| | | .addValue("reporterNames", json(request.getReporterNames())) |
| | | .addValue("reporterShares", json(reporterShares)) |
| | | .addValue("progress", progress).addValue("reportDate", request.getReportDate()) |
| | | .addValue("remark", request.getRemark()).addValue("attachments", json(request.getAttachments())); |
| | | Long reportId = request.getId(); |
| | | if (reportId == null) { |
| | | GeneratedKeyHolder keys = new GeneratedKeyHolder(); |
| | | jdbc.update(""" |
| | | insert into project_management_progress_report |
| | | (project_id,module_id,reporter_ids,reporter_names,reporter_shares,progress,report_date,remark,attachments,is_deleted,create_time,update_time) |
| | | values (:projectId,:moduleId,:reporterIds,:reporterNames,:reporterShares,:progress,:reportDate,:remark,:attachments,0,now(),now()) |
| | | """, p, keys, new String[]{"id"}); |
| | | reportId = Objects.requireNonNull(keys.getKey()).longValue(); |
| | | } else { |
| | | jdbc.update(""" |
| | | update project_management_progress_report set module_id=:moduleId,reporter_ids=:reporterIds, |
| | | reporter_names=:reporterNames,reporter_shares=:reporterShares,progress=:progress,report_date=:reportDate,remark=:remark, |
| | | attachments=:attachments,update_time=now() |
| | | where id=:id and project_id=:projectId and is_deleted=0 |
| | | """, p); |
| | | } |
| | | jdbc.update("update project_management_module set current_progress=:progress,update_time=now() where id=:moduleId", |
| | | new MapSqlParameterSource().addValue("progress", progress).addValue("moduleId", request.getModuleId())); |
| | | return reportId; |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long saveMaterial(ProjectWorkflowDtos.MaterialRequest request) { |
| | | requireProject(request.getProjectId()); |
| | | if (isBlank(request.getMaterialName())) throw new ServiceException("请è¾å
¥èµæåç§°"); |
| | | MapSqlParameterSource p = new MapSqlParameterSource() |
| | | .addValue("id", request.getId()).addValue("projectId", request.getProjectId()) |
| | | .addValue("materialName", request.getMaterialName()).addValue("materialType", request.getMaterialType()) |
| | | .addValue("remark", request.getRemark()).addValue("attachments", json(request.getAttachments())) |
| | | .addValue("userId", SecurityUtils.getUserId()).addValue("userName", currentUserName()); |
| | | if (request.getId() == null) { |
| | | GeneratedKeyHolder keys = new GeneratedKeyHolder(); |
| | | jdbc.update(""" |
| | | insert into project_management_material |
| | | (project_id,material_name,material_type,remark,attachments,create_user_id,create_user_name,is_deleted,create_time,update_time) |
| | | values (:projectId,:materialName,:materialType,:remark,:attachments,:userId,:userName,0,now(),now()) |
| | | """, p, keys, new String[]{"id"}); |
| | | return Objects.requireNonNull(keys.getKey()).longValue(); |
| | | } |
| | | jdbc.update(""" |
| | | update project_management_material set material_name=:materialName,material_type=:materialType, |
| | | remark=:remark,attachments=:attachments,update_time=now() |
| | | where id=:id and project_id=:projectId and is_deleted=0 |
| | | """, p); |
| | | return request.getId(); |
| | | } |
| | | |
| | | public void softDelete(String table, Long id) { |
| | | if (!List.of("project_management_follow_up", "project_management_progress_report", "project_management_material", "government_policy_file").contains(table)) { |
| | | throw new ServiceException("䏿¯æçå é¤ç±»å"); |
| | | } |
| | | jdbc.getJdbcTemplate().update("update " + table + " set is_deleted=1,update_time=now() where id=?", id); |
| | | } |
| | | |
| | | public List<Map<String, Object>> listCategories() { |
| | | return query(""" |
| | | select id,parent_id as parentId,category_name as categoryName,sort,remark |
| | | from project_management_category where is_deleted=0 order by sort,id |
| | | """, Map.of()); |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long saveCategory(ProjectWorkflowDtos.CategoryRequest request) { |
| | | if (isBlank(request.getCategoryName())) throw new ServiceException("请è¾å
¥åç±»åç§°"); |
| | | Long parentId = request.getParentId() == null ? 0L : request.getParentId(); |
| | | if (request.getId() != null && request.getId().equals(parentId)) throw new ServiceException("ä¸çº§åç±»ä¸è½éæ©èªå·±"); |
| | | MapSqlParameterSource p = new MapSqlParameterSource().addValue("id", request.getId()) |
| | | .addValue("parentId", parentId).addValue("categoryName", request.getCategoryName().trim()) |
| | | .addValue("sort", request.getSort() == null ? 0 : request.getSort()).addValue("remark", request.getRemark()); |
| | | if (request.getId() == null) { |
| | | GeneratedKeyHolder keys = new GeneratedKeyHolder(); |
| | | jdbc.update(""" |
| | | insert into project_management_category(parent_id,category_name,sort,remark,is_deleted,create_time,update_time) |
| | | values (:parentId,:categoryName,:sort,:remark,0,now(),now()) |
| | | """, p, keys, new String[]{"id"}); |
| | | return Objects.requireNonNull(keys.getKey()).longValue(); |
| | | } |
| | | jdbc.update(""" |
| | | update project_management_category set parent_id=:parentId,category_name=:categoryName, |
| | | sort=:sort,remark=:remark,update_time=now() where id=:id and is_deleted=0 |
| | | """, p); |
| | | return request.getId(); |
| | | } |
| | | |
| | | public void deleteCategory(Long id) { |
| | | int children = jdbc.queryForObject("select count(*) from project_management_category where parent_id=:id and is_deleted=0", Map.of("id", id), Integer.class); |
| | | if (children > 0) throw new ServiceException("请å
å é¤ä¸çº§åç±»"); |
| | | jdbc.update("update project_management_category set is_deleted=1,update_time=now() where id=:id", Map.of("id", id)); |
| | | } |
| | | |
| | | public List<Map<String, Object>> listPolicies(String keyword) { |
| | | MapSqlParameterSource p = new MapSqlParameterSource().addValue("keyword", keyword == null ? "" : keyword.trim()); |
| | | List<Map<String, Object>> rows = query(""" |
| | | select id,policy_name as policyName,publish_date as publishDate,policy_url as policyUrl, |
| | | attachments,maintainer_name as maintainerName,remark,create_time as createTime |
| | | from government_policy_file where is_deleted=0 |
| | | and (:keyword='' or policy_name like concat('%',:keyword,'%')) |
| | | order by publish_date desc,id desc |
| | | """, p); |
| | | parseAttachments(rows); |
| | | return rows; |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long savePolicy(ProjectWorkflowDtos.PolicyRequest request) { |
| | | if (isBlank(request.getPolicyName())) throw new ServiceException("请è¾å
¥æ¿çåç§°"); |
| | | String maintainer = isBlank(request.getMaintainerName()) ? currentUserName() : request.getMaintainerName(); |
| | | MapSqlParameterSource p = new MapSqlParameterSource().addValue("id", request.getId()) |
| | | .addValue("policyName", request.getPolicyName()).addValue("publishDate", request.getPublishDate()) |
| | | .addValue("policyUrl", request.getPolicyUrl()).addValue("attachments", json(request.getAttachments())) |
| | | .addValue("maintainer", maintainer).addValue("remark", request.getRemark()); |
| | | if (request.getId() == null) { |
| | | GeneratedKeyHolder keys = new GeneratedKeyHolder(); |
| | | jdbc.update(""" |
| | | insert into government_policy_file |
| | | (policy_name,publish_date,policy_url,attachments,maintainer_name,remark,is_deleted,create_time,update_time) |
| | | values (:policyName,:publishDate,:policyUrl,:attachments,:maintainer,:remark,0,now(),now()) |
| | | """, p, keys, new String[]{"id"}); |
| | | return Objects.requireNonNull(keys.getKey()).longValue(); |
| | | } |
| | | jdbc.update(""" |
| | | update government_policy_file set policy_name=:policyName,publish_date=:publishDate, |
| | | policy_url=:policyUrl,attachments=:attachments,maintainer_name=:maintainer, |
| | | remark=:remark,update_time=now() where id=:id and is_deleted=0 |
| | | """, p); |
| | | return request.getId(); |
| | | } |
| | | |
| | | private List<Map<String, Object>> memberStatistics(Long projectId) { |
| | | List<Map<String, Object>> reports = query(""" |
| | | select r.module_id as moduleId,r.progress,r.reporter_ids as reporterIds, |
| | | r.reporter_names as reporterNames,r.reporter_shares as reporterShares, |
| | | m.project_weight as projectWeight |
| | | from project_management_progress_report r |
| | | join project_management_module m on m.id=r.module_id and m.is_deleted=0 |
| | | where r.project_id=:projectId and r.is_deleted=0 |
| | | order by r.module_id,r.report_date,r.id |
| | | """, Map.of("projectId", projectId)); |
| | | Map<Long, BigDecimal> previousProgress = new LinkedHashMap<>(); |
| | | Map<Long, Map<String, Object>> totals = new LinkedHashMap<>(); |
| | | for (Map<String, Object> report : reports) { |
| | | Long moduleId = asLong(report.get("moduleId")); |
| | | BigDecimal progress = nvl((BigDecimal) report.get("progress")); |
| | | BigDecimal previous = previousProgress.getOrDefault(moduleId, BigDecimal.ZERO); |
| | | BigDecimal delta = progress.subtract(previous).max(BigDecimal.ZERO); |
| | | previousProgress.put(moduleId, progress.max(previous)); |
| | | List<Map<String, Object>> shares = parseFileList(report.get("reporterShares")); |
| | | if (shares.isEmpty()) shares = equalReporterShares(report.get("reporterIds"), report.get("reporterNames")); |
| | | BigDecimal moduleWeight = nvl((BigDecimal) report.get("projectWeight")); |
| | | for (Map<String, Object> share : shares) { |
| | | Long userId = asLong(share.get("userId")); |
| | | if (userId == null) continue; |
| | | String userName = Objects.toString(share.get("userName"), ""); |
| | | BigDecimal memberShare = new BigDecimal(Objects.toString(share.get("moduleShare"), "0")); |
| | | BigDecimal contribution = moduleWeight.multiply(delta).multiply(memberShare) |
| | | .divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP); |
| | | Map<String, Object> total = totals.computeIfAbsent(userId, id -> { |
| | | Map<String, Object> item = new LinkedHashMap<>(); |
| | | item.put("userId", id); item.put("userName", userName); item.put("value", BigDecimal.ZERO); |
| | | return item; |
| | | }); |
| | | total.put("value", ((BigDecimal) total.get("value")).add(contribution)); |
| | | } |
| | | } |
| | | return totals.values().stream() |
| | | .sorted((a, b) -> ((BigDecimal) b.get("value")).compareTo((BigDecimal) a.get("value"))) |
| | | .toList(); |
| | | } |
| | | |
| | | private Map<String, Object> getFollowWindow(Long projectId) { |
| | | List<Map<String, Object>> projectRows = query(""" |
| | | select follow_cycle as followCycle,plan_start_time as planStartTime |
| | | from project_management_info where id=:projectId and is_delete=0 |
| | | """, Map.of("projectId", projectId)); |
| | | if (projectRows.isEmpty()) return Map.of(); |
| | | String cycle = Objects.toString(projectRows.getFirst().get("followCycle"), ""); |
| | | LocalDate last = jdbc.query(""" |
| | | select follow_date from project_management_follow_up |
| | | where project_id=:projectId and is_deleted=0 order by follow_date desc,id desc limit 1 |
| | | """, Map.of("projectId", projectId), rs -> rs.next() ? rs.getDate(1).toLocalDate() : null); |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | result.put("cycle", cycle); |
| | | result.put("lastFollowDate", last); |
| | | LocalDate planStart = projectRows.getFirst().get("planStartTime") instanceof java.sql.Date date ? date.toLocalDate() : null; |
| | | LocalDate base = last == null ? planStart : last; |
| | | if (base != null) { |
| | | LocalDate due = nextDue(base, cycle); |
| | | result.put("dueDate", due); |
| | | result.put("windowStart", due.minusDays(3)); |
| | | result.put("windowEnd", due.plusDays(3)); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private void ensurePhases(Long projectId) { |
| | | for (int i = 0; i < PHASE_CODES.size(); i++) { |
| | | jdbc.update(""" |
| | | insert into project_management_phase |
| | | (project_id,phase_code,phase_name,phase_order,status,is_deleted,create_time,update_time) |
| | | select :projectId,:phaseCode,:phaseName,:phaseOrder,'NOT_STARTED',0,now(),now() |
| | | where not exists(select 1 from project_management_phase |
| | | where project_id=:projectId and phase_code=:phaseCode and is_deleted=0) |
| | | """, new MapSqlParameterSource().addValue("projectId", projectId) |
| | | .addValue("phaseCode", PHASE_CODES.get(i)).addValue("phaseName", PHASE_NAMES.get(i)) |
| | | .addValue("phaseOrder", i + 1)); |
| | | } |
| | | } |
| | | |
| | | private Map<String, Object> getSourceBusiness(Long projectId) { |
| | | List<Map<String, Object>> rows = query(""" |
| | | select sl.id,sl.project_name as projectName,sl.customer_id as customerId, |
| | | sl.customer_name as customerName,sl.salesman,sl.entry_date as entryDate, |
| | | sl.remarks,sl.attachment_materials as attachmentMaterials, |
| | | sl.business_approval_status as approvalStatus, |
| | | sl.business_approval_remark as approvalRemark |
| | | from project_management_info p |
| | | join sales_ledger sl on sl.id=p.source_business_id |
| | | where p.id=:projectId and p.source_business_id is not null |
| | | """, Map.of("projectId", projectId)); |
| | | if (rows.isEmpty()) return Map.of(); |
| | | Map<String, Object> row = rows.getFirst(); |
| | | row.put("attachmentList", parseFileList(row.get("attachmentMaterials"))); |
| | | return row; |
| | | } |
| | | |
| | | private void validateFollowWindow(Long projectId, LocalDate followDate, Long excludeId) { |
| | | MapSqlParameterSource p = new MapSqlParameterSource().addValue("projectId", projectId).addValue("excludeId", excludeId); |
| | | LocalDate last = jdbc.query(""" |
| | | select follow_date from project_management_follow_up |
| | | where project_id=:projectId and is_deleted=0 and (:excludeId is null or id<>:excludeId) |
| | | order by follow_date desc,id desc limit 1 |
| | | """, p, rs -> rs.next() ? rs.getDate(1).toLocalDate() : null); |
| | | String cycle = jdbc.queryForObject("select follow_cycle from project_management_info where id=:projectId", Map.of("projectId", projectId), String.class); |
| | | LocalDate base = last; |
| | | if (base == null) { |
| | | base = jdbc.query("select plan_start_time from project_management_info where id=:projectId", Map.of("projectId", projectId), |
| | | rs -> rs.next() && rs.getDate(1) != null ? rs.getDate(1).toLocalDate() : null); |
| | | } |
| | | if (base == null) throw new ServiceException("请å
å¡«å项ç®é¢è®¡å¼å§æ¶é´"); |
| | | LocalDate due = nextDue(base, cycle); |
| | | if (followDate.isBefore(due.minusDays(3)) || followDate.isAfter(due.plusDays(3))) { |
| | | throw new ServiceException("æ¬æ¬¡è·è¿åºå¨" + due.minusDays(3) + "è³" + due.plusDays(3) + "ä¹é´å¡«å"); |
| | | } |
| | | } |
| | | |
| | | private LocalDate nextDue(LocalDate base, String cycle) { |
| | | return switch (Objects.toString(cycle, "MONTH").toUpperCase()) { |
| | | case "QUARTER", "å£åº¦", "æ¯å£åº¦" -> base.plusMonths(3); |
| | | case "YEAR", "年度", "æ¯å¹´" -> base.plusYears(1); |
| | | default -> base.plusMonths(1); |
| | | }; |
| | | } |
| | | |
| | | private void validateMembers(List<ProjectWorkflowDtos.MemberRequest> members) { |
| | | if (members == null || members.isEmpty()) throw new ServiceException("请è³å°éæ©ä¸åæ¨¡åæ§è¡äºº"); |
| | | List<Long> ids = new ArrayList<>(); |
| | | for (ProjectWorkflowDtos.MemberRequest member : members) { |
| | | if (member.getUserId() == null || isBlank(member.getUserName())) throw new ServiceException("æ¨¡åæ§è¡äººä¸è½ä¸ºç©º"); |
| | | if (ids.contains(member.getUserId())) throw new ServiceException("æ¨¡åæ§è¡äººä¸è½éå¤"); |
| | | ids.add(member.getUserId()); |
| | | } |
| | | } |
| | | |
| | | private List<Long> projectExecutorIds(Long projectId) { |
| | | List<Map<String, Object>> rows = query(""" |
| | | select project_executor_ids as executorIds from project_management_info |
| | | where id=:projectId and is_delete=0 |
| | | """, Map.of("projectId", projectId)); |
| | | return rows.isEmpty() ? List.of() : parseLongList(rows.getFirst().get("executorIds")); |
| | | } |
| | | |
| | | private boolean hasPositiveProjectShare(Long projectId, Long userId) { |
| | | return hasPositiveShare(query(""" |
| | | select reporter_ids as reporterIds,reporter_names as reporterNames,reporter_shares as reporterShares |
| | | from project_management_progress_report where project_id=:projectId and is_deleted=0 |
| | | """, Map.of("projectId", projectId)), userId); |
| | | } |
| | | |
| | | private boolean hasPositiveModuleShare(Long moduleId, Long userId) { |
| | | return hasPositiveShare(query(""" |
| | | select reporter_ids as reporterIds,reporter_names as reporterNames,reporter_shares as reporterShares |
| | | from project_management_progress_report where module_id=:moduleId and is_deleted=0 |
| | | """, Map.of("moduleId", moduleId)), userId); |
| | | } |
| | | |
| | | private boolean hasPositiveShare(List<Map<String, Object>> reports, Long userId) { |
| | | for (Map<String, Object> report : reports) { |
| | | List<Map<String, Object>> shares = parseFileList(report.get("reporterShares")); |
| | | if (shares.isEmpty()) shares = equalReporterShares(report.get("reporterIds"), report.get("reporterNames")); |
| | | for (Map<String, Object> share : shares) { |
| | | if (Objects.equals(asLong(share.get("userId")), userId) |
| | | && new BigDecimal(Objects.toString(share.get("moduleShare"), "0")).compareTo(BigDecimal.ZERO) > 0) { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | private void validateReporterShares(List<ProjectWorkflowDtos.MemberRequest> members) { |
| | | if (members == null || members.isEmpty()) throw new ServiceException("请è³å°éæ©ä¸åæ±æ¥äºº"); |
| | | BigDecimal sum = BigDecimal.ZERO; |
| | | List<Long> ids = new ArrayList<>(); |
| | | for (ProjectWorkflowDtos.MemberRequest member : members) { |
| | | if (member.getUserId() == null || isBlank(member.getUserName())) throw new ServiceException("æ±æ¥äººä¸è½ä¸ºç©º"); |
| | | if (ids.contains(member.getUserId())) throw new ServiceException("æ±æ¥äººä¸è½éå¤"); |
| | | ids.add(member.getUserId()); |
| | | sum = sum.add(percent(member.getModuleShare(), "æ¬æ¬¡æ±æ¥äººåæ¯é")); |
| | | } |
| | | if (sum.setScale(2, RoundingMode.HALF_UP).compareTo(BigDecimal.valueOf(100).setScale(2)) != 0) { |
| | | throw new ServiceException("æ¬æ¬¡æ±æ¥äººåæ¯éå计å¿
须为100%"); |
| | | } |
| | | } |
| | | |
| | | private List<ProjectWorkflowDtos.MemberRequest> normalizeReporterShares(ProjectWorkflowDtos.ProgressReportRequest request) { |
| | | if (request.getReporterShares() != null && !request.getReporterShares().isEmpty()) return request.getReporterShares(); |
| | | List<Long> ids = request.getReporterIds() == null ? List.of() : request.getReporterIds(); |
| | | List<String> names = request.getReporterNames() == null ? List.of() : request.getReporterNames(); |
| | | if (ids.isEmpty()) return new ArrayList<>(); |
| | | BigDecimal share = BigDecimal.valueOf(100).divide(BigDecimal.valueOf(ids.size()), 2, RoundingMode.DOWN); |
| | | List<ProjectWorkflowDtos.MemberRequest> result = new ArrayList<>(); |
| | | for (int i = 0; i < ids.size(); i++) { |
| | | ProjectWorkflowDtos.MemberRequest member = new ProjectWorkflowDtos.MemberRequest(); |
| | | member.setUserId(ids.get(i)); member.setUserName(i < names.size() ? names.get(i) : ""); |
| | | member.setModuleShare(i == ids.size() - 1 ? BigDecimal.valueOf(100).subtract(share.multiply(BigDecimal.valueOf(i))) : share); |
| | | result.add(member); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private List<Map<String, Object>> equalReporterShares(Object rawIds, Object rawNames) { |
| | | List<Long> ids = parseLongList(rawIds); |
| | | List<String> names = parseStringList(rawNames); |
| | | if (ids.isEmpty()) return new ArrayList<>(); |
| | | BigDecimal share = BigDecimal.valueOf(100).divide(BigDecimal.valueOf(ids.size()), 2, RoundingMode.DOWN); |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | for (int i = 0; i < ids.size(); i++) { |
| | | Map<String, Object> item = new LinkedHashMap<>(); |
| | | item.put("userId", ids.get(i)); item.put("userName", i < names.size() ? names.get(i) : ""); |
| | | item.put("moduleShare", i == ids.size() - 1 ? BigDecimal.valueOf(100).subtract(share.multiply(BigDecimal.valueOf(i))) : share); |
| | | result.add(item); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private BigDecimal percent(BigDecimal value, String label) { |
| | | BigDecimal val = nvl(value); |
| | | if (val.compareTo(BigDecimal.ZERO) < 0 || val.compareTo(BigDecimal.valueOf(100)) > 0) { |
| | | throw new ServiceException(label + "å¿
é¡»å¨0å°100ä¹é´"); |
| | | } |
| | | return val.setScale(2, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | private void requireProject(Long projectId) { |
| | | if (projectId == null) throw new ServiceException("项ç®ä¸è½ä¸ºç©º"); |
| | | Integer count = jdbc.queryForObject("select count(*) from project_management_info where id=:id and is_delete=0", Map.of("id", projectId), Integer.class); |
| | | if (count == null || count == 0) throw new ServiceException("项ç®ä¸åå¨"); |
| | | } |
| | | |
| | | private List<Map<String, Object>> query(String sql, Map<String, ?> params) { |
| | | return jdbc.queryForList(sql, params); |
| | | } |
| | | |
| | | private List<Map<String, Object>> query(String sql, MapSqlParameterSource params) { |
| | | return jdbc.queryForList(sql, params); |
| | | } |
| | | |
| | | private void parseAttachments(List<Map<String, Object>> rows) { |
| | | for (Map<String, Object> row : rows) row.put("attachmentList", parseFileList(row.get("attachments"))); |
| | | } |
| | | |
| | | private List<Map<String, Object>> parseFileList(Object raw) { |
| | | if (raw == null || raw.toString().isBlank()) return new ArrayList<>(); |
| | | try { |
| | | return objectMapper.readValue(raw.toString(), FILE_LIST_TYPE); |
| | | } catch (Exception ignored) { |
| | | return new ArrayList<>(); |
| | | } |
| | | } |
| | | |
| | | private List<Long> parseLongList(Object raw) { |
| | | if (raw == null || raw.toString().isBlank()) return new ArrayList<>(); |
| | | try { |
| | | return objectMapper.readValue(raw.toString(), new TypeReference<>() { }); |
| | | } catch (Exception ignored) { |
| | | return new ArrayList<>(); |
| | | } |
| | | } |
| | | |
| | | private List<String> parseStringList(Object raw) { |
| | | if (raw == null || raw.toString().isBlank()) return new ArrayList<>(); |
| | | try { |
| | | return objectMapper.readValue(raw.toString(), new TypeReference<>() { }); |
| | | } catch (Exception ignored) { |
| | | return new ArrayList<>(); |
| | | } |
| | | } |
| | | |
| | | private Map<String, Object> parseObjectMap(Object raw) { |
| | | if (raw == null || raw.toString().isBlank()) return new LinkedHashMap<>(); |
| | | try { |
| | | return objectMapper.readValue(raw.toString(), new TypeReference<>() { }); |
| | | } catch (Exception ignored) { |
| | | return new LinkedHashMap<>(); |
| | | } |
| | | } |
| | | |
| | | private String json(Object value) { |
| | | try { |
| | | return objectMapper.writeValueAsString(value == null ? List.of() : value); |
| | | } catch (Exception e) { |
| | | throw new ServiceException("éä»¶æäººåæ°æ®æ ¼å¼ä¸æ£ç¡®"); |
| | | } |
| | | } |
| | | |
| | | private String jsonObject(Object value) { |
| | | try { |
| | | return objectMapper.writeValueAsString(value == null ? Map.of() : value); |
| | | } catch (Exception e) { |
| | | throw new ServiceException("é¶æ®µä¿¡æ¯æ ¼å¼ä¸æ£ç¡®"); |
| | | } |
| | | } |
| | | |
| | | private String currentUserName() { |
| | | return SecurityUtils.getLoginUser() == null ? "" : SecurityUtils.getLoginUser().getNickName(); |
| | | } |
| | | |
| | | private boolean isBlank(String value) { |
| | | return value == null || value.trim().isEmpty(); |
| | | } |
| | | |
| | | private BigDecimal nvl(BigDecimal value) { |
| | | return value == null ? BigDecimal.ZERO : value; |
| | | } |
| | | |
| | | private Long asLong(Object value) { |
| | | return value == null ? null : Long.valueOf(value.toString()); |
| | | } |
| | | } |