From ba94ceae1315174798ae1967ef62268c6d16cd5b Mon Sep 17 00:00:00 2001 From: Codex Assistant <codex@example.com> Date: 星期一, 06 十月 2025 22:07:06 +0800 Subject: [PATCH] feat: 评审与活动相关改动 - backend(GraphQL): Activity schema 增加 updateActivityState(id, state);实现 resolver/service 仅更新 state=2 作为逻辑删除 - backend(GraphQL): region.graphqls 新增 Query leafRegions - backend(GraphQL): player.graphqls 的 projectReviewApplications 增加可选参数 regionId - backend(Service): listProjectReviewApplications 绑定 regionId 参数,修复 QueryParameterException - frontend(web): 新增 api/activity.js 的 updateActivityState 并接入 activity-list 删除逻辑 - frontend(web): review-list.vue 权限仅校验登录,移除角色限制;查询参数修正为 name/regionId - frontend(web): 删除未引用的 ActivityList.vue - frontend(web): projectReviewNew.js GraphQL 查询增加 name 参数 --- backend/src/main/java/com/rongyichuang/judge/service/JudgeService.java | 198 +++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 174 insertions(+), 24 deletions(-) diff --git a/backend/src/main/java/com/rongyichuang/judge/service/JudgeService.java b/backend/src/main/java/com/rongyichuang/judge/service/JudgeService.java index 63eef94..c4d82ec 100644 --- a/backend/src/main/java/com/rongyichuang/judge/service/JudgeService.java +++ b/backend/src/main/java/com/rongyichuang/judge/service/JudgeService.java @@ -2,23 +2,33 @@ import com.rongyichuang.judge.dto.request.JudgeInput; import com.rongyichuang.judge.dto.response.JudgeResponse; +import com.rongyichuang.judge.dto.response.JudgeStatsResponse; import com.rongyichuang.judge.entity.Judge; -import com.rongyichuang.judge.entity.Tag; +import com.rongyichuang.tag.entity.Tag; import com.rongyichuang.judge.repository.JudgeRepository; import com.rongyichuang.common.entity.Media; import com.rongyichuang.common.repository.MediaRepository; import com.rongyichuang.common.dto.request.MediaInput; import com.rongyichuang.common.dto.response.MediaResponse; import com.rongyichuang.common.service.MediaService; -import com.rongyichuang.judge.repository.TagRepository; +import com.rongyichuang.common.exception.BusinessException; +import com.rongyichuang.common.enums.MediaTargetType; +import com.rongyichuang.common.util.UserContextUtil; +import com.rongyichuang.tag.repository.TagRepository; +import com.rongyichuang.user.service.UserService; +import com.rongyichuang.user.entity.User; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Sort; +import org.springframework.jdbc.core.JdbcTemplate; +import java.util.Optional; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; @@ -31,13 +41,24 @@ private final TagRepository tagRepository; private final MediaRepository mediaRepository; private final MediaService mediaService; + private final UserService userService; + private final JdbcTemplate jdbcTemplate; + private final UserContextUtil userContextUtil; + + @Value("${app.media-url}") + private String mediaBaseUrl; public JudgeService(JudgeRepository judgeRepository, TagRepository tagRepository, - MediaRepository mediaRepository, MediaService mediaService) { + MediaRepository mediaRepository, MediaService mediaService, + UserService userService, JdbcTemplate jdbcTemplate, + UserContextUtil userContextUtil) { this.judgeRepository = judgeRepository; this.tagRepository = tagRepository; this.mediaRepository = mediaRepository; this.mediaService = mediaService; + this.userService = userService; + this.jdbcTemplate = jdbcTemplate; + this.userContextUtil = userContextUtil; } public List<JudgeResponse> findAll() { @@ -58,17 +79,93 @@ .orElse(null); } + /** + * 鏍规嵁鐢ㄦ埛ID鑾峰彇璇勫淇℃伅 + */ + public Judge findByUserId(Long userId) { + Optional<Judge> judge = judgeRepository.findByUserId(userId); + return judge.orElse(null); + } + + /** + * 鑾峰彇褰撳墠璇勫鐨勭粺璁℃暟鎹� + */ + public JudgeStatsResponse getJudgeStats() { + log.info("鑾峰彇璇勫缁熻鏁版嵁"); + + Long currentJudgeId = userContextUtil.getCurrentJudgeId(); + if (currentJudgeId == null) { + throw new RuntimeException("褰撳墠鐢ㄦ埛涓嶆槸璇勫锛屾棤娉曟煡璇㈣瘎瀹$粺璁�"); + } + + // 鏌ヨ鎴戞湭璇勫鐨勬暟閲� + String unReviewedSql = "SELECT COUNT(*) FROM t_activity_player ap " + + "WHERE EXISTS (" + + " SELECT 1 FROM t_activity_judge aj " + + " WHERE ap.activity_id = aj.activity_id " + + " AND ap.stage_id = aj.stage_id " + + " AND aj.judge_id = ? " + + ") " + + "AND NOT EXISTS (" + + " SELECT 1 FROM t_activity_player_rating apr " + + " WHERE ap.id = apr.activity_player_id " + + " AND apr.judge_id = ? " + + " AND apr.state = 1 " + + ") " + + "AND ap.state = 1"; + Integer unReviewedCount = jdbcTemplate.queryForObject(unReviewedSql, Integer.class, currentJudgeId, currentJudgeId); + + // 鏌ヨ鎴戝凡璇勫鐨勬暟閲� + String reviewedSql = "SELECT COUNT(*) FROM t_activity_player ap " + + "WHERE EXISTS (" + + " SELECT 1 FROM t_activity_judge aj " + + " WHERE ap.activity_id = aj.activity_id " + + " AND ap.stage_id = aj.stage_id " + + " AND aj.judge_id = ? " + + ") " + + "AND EXISTS (" + + " SELECT 1 FROM t_activity_player_rating apr " + + " WHERE ap.id = apr.activity_player_id " + + " AND apr.judge_id = ? " + + " AND apr.state = 1 " + + ") " + + "AND ap.state = 1"; + Integer reviewedCount = jdbcTemplate.queryForObject(reviewedSql, Integer.class, currentJudgeId, currentJudgeId); + + // 璁$畻鎬绘暟 + Integer totalCount = (unReviewedCount != null ? unReviewedCount : 0) + (reviewedCount != null ? reviewedCount : 0); + + log.info("璇勫缁熻鏁版嵁 - 寰呰瘎瀹�: {}, 宸茶瘎瀹�: {}, 鎬绘暟: {}", unReviewedCount, reviewedCount, totalCount); + + return new JudgeStatsResponse( + unReviewedCount != null ? unReviewedCount : 0, + reviewedCount != null ? reviewedCount : 0, + totalCount + ); + } + @Transactional public JudgeResponse save(JudgeInput input) { Judge judge; + User user; + + // 澶勭悊User琛ㄩ�昏緫 + if (input.getPassword() != null && !input.getPassword().trim().isEmpty() && !"鈥⑩�⑩�⑩�⑩�⑩�⑩�⑩��".equals(input.getPassword())) { + // 鏈夊瘑鐮佷笖涓嶆槸鍗犱綅绗︽椂锛屽垱寤烘垨鏇存柊鐢ㄦ埛锛堝寘鍚瘑鐮侊級 + user = userService.findOrCreateUserByPhone(input.getPhone(), input.getName(), input.getPassword()); + } else { + // 鏃犲瘑鐮佹垨鏄崰浣嶇鏃讹紝鍙洿鏂扮敤鎴峰熀鏈俊鎭紙涓嶆洿鏂板瘑鐮侊級 + user = userService.findOrCreateUserByPhone(input.getPhone(), input.getName(), null); + } + if (input.getId() != null) { judge = judgeRepository.findById(input.getId()) - .orElseThrow(() -> new RuntimeException("璇勫涓嶅瓨鍦�")); + .orElseThrow(() -> new BusinessException("璇勫涓嶅瓨鍦�")); } else { judge = new Judge(); // 鏂板璇勫鏃舵鏌ユ墜鏈哄彿鏄惁宸插瓨鍦� if (judgeRepository.existsByPhone(input.getPhone())) { - throw new RuntimeException("鎵嬫満鍙风爜宸插瓨鍦紝璇蜂娇鐢ㄥ叾浠栨墜鏈哄彿鐮�"); + throw new BusinessException("PHONE_EXISTS", "鎵嬫満鍙风爜宸插瓨鍦紝璇蜂娇鐢ㄥ叾浠栨墜鏈哄彿鐮�"); } } @@ -76,16 +173,18 @@ judge.setPhone(input.getPhone()); judge.setGender(input.getGender()); judge.setDescription(input.getDescription()); - - // 澶村儚澶勭悊宸茬Щ闄わ紝鍥犱负鏁版嵁搴撹〃缁撴瀯涓病鏈塧vatar_media_id瀛楁 + judge.setTitle(input.getTitle()); + judge.setCompany(input.getCompany()); + judge.setIntroduction(input.getIntroduction()); + judge.setUserId(user.getId()); // 璁剧疆鍏宠仈鐨勭敤鎴稩D // 澶村儚淇℃伅閫氳繃t_media琛ㄧ殑target_type鍜宼arget_id鍏宠仈 // 璁剧疆涓撲笟鏍囩 if (input.getMajorIds() != null && !input.getMajorIds().isEmpty()) { - List<Tag> specialties = tagRepository.findAllById(input.getMajorIds()); - judge.setSpecialties(specialties); + List<Tag> specialtiesList = tagRepository.findAllById(input.getMajorIds()); + judge.setSpecialties(new HashSet<>(specialtiesList)); } else { - judge.setSpecialties(Collections.emptyList()); + judge.setSpecialties(Collections.emptySet()); } Judge savedJudge = judgeRepository.save(judge); @@ -95,7 +194,7 @@ @Transactional public void delete(Long id) { Judge judge = judgeRepository.findById(id) - .orElseThrow(() -> new RuntimeException("璇勫涓嶅瓨鍦�")); + .orElseThrow(() -> new BusinessException("璇勫涓嶅瓨鍦�")); judgeRepository.delete(judge); } @@ -108,16 +207,21 @@ response.setPhone(judge.getPhone()); response.setGender(judge.getGender()); response.setDescription(judge.getDescription()); + response.setTitle(judge.getTitle()); + response.setCompany(judge.getCompany()); + response.setIntroduction(judge.getIntroduction()); - // 鏌ヨ澶村儚淇℃伅锛歵arget_type=1琛ㄧず璇勫锛宼arget_id涓鸿瘎濮擨D + // 鏌ヨ澶村儚淇℃伅锛氫娇鐢ㄦ灇涓惧父閲忚〃绀鸿瘎濮斿ご鍍忕被鍨� log.info("=== Querying media for judge ID: {}", judge.getId()); - List<Media> avatarMedias = mediaRepository.findByTargetTypeAndTargetIdAndState(1, judge.getId(), 1); + List<Media> avatarMedias = mediaRepository.findByTargetTypeAndTargetIdAndState( + MediaTargetType.JUDGE_AVATAR.getValue(), judge.getId(), 1); log.info("=== Found {} media records", avatarMedias.size()); if (!avatarMedias.isEmpty()) { // 鍙栫涓�涓獟浣撲綔涓哄ご鍍� Media avatarMedia = avatarMedias.get(0); - String avatarUrl = avatarMedia.getPath(); + String avatarPath = avatarMedia.getPath(); + String avatarUrl = buildFullMediaUrl(avatarPath); log.info("=== Setting avatarUrl: {}", avatarUrl); response.setAvatarUrl(avatarUrl); } else { @@ -138,20 +242,63 @@ return response; } + + /** + * 鏋勫缓瀹屾暣鐨勫獟浣揢RL + * @param path 濯掍綋璺緞 + * @return 瀹屾暣鐨刄RL + */ + private String buildFullMediaUrl(String path) { + if (!StringUtils.hasText(path)) { + return null; + } + + // 濡傛灉璺緞宸茬粡鏄畬鏁碪RL锛岀洿鎺ヨ繑鍥� + if (path.startsWith("http://") || path.startsWith("https://")) { + return path; + } + + // 鏋勫缓瀹屾暣URL + if (StringUtils.hasText(mediaBaseUrl)) { + // 纭繚baseUrl浠�/缁撳熬锛宲ath涓嶄互/寮�澶� + String baseUrl = mediaBaseUrl.endsWith("/") ? mediaBaseUrl : mediaBaseUrl + "/"; + String relativePath = path.startsWith("/") ? path.substring(1) : path; + return baseUrl + relativePath; + } + + // 濡傛灉娌℃湁閰嶇疆baseUrl锛岃繑鍥炲師璺緞 + return path; + } /** * 淇濆瓨濯掍綋淇℃伅 */ public MediaResponse saveMediaInfo(MediaInput input) { - Media media = mediaService.saveMedia( - input.getName(), - input.getPath(), - input.getFileSize(), - input.getFileExt(), - input.getMediaType(), - input.getTargetType(), - input.getTargetId() - ); + Media media; + + // 濡傛灉鏈夌缉鐣ュ浘璺緞锛屼娇鐢ㄦ敮鎸佺缉鐣ュ浘鐨勬柟娉� + if (input.getThumbPath() != null && !input.getThumbPath().trim().isEmpty()) { + media = mediaService.saveMedia( + input.getName(), + input.getPath(), + input.getFileSize(), + input.getFileExt(), + input.getMediaType(), + input.getTargetType(), + input.getTargetId(), + input.getThumbPath() + ); + } else { + media = mediaService.saveMedia( + input.getName(), + input.getPath(), + input.getFileSize(), + input.getFileExt(), + input.getMediaType(), + input.getTargetType(), + input.getTargetId() + ); + } MediaResponse response = new MediaResponse(); response.setId(media.getId()); @@ -162,6 +309,9 @@ response.setMediaType(media.getMediaType()); response.setTargetType(media.getTargetType()); response.setTargetId(media.getTargetId()); + response.setThumbPath(media.getThumbPath()); + response.setDuration(media.getDuration()); + response.setDescription(media.getDescription()); return response; } -- Gitblit v1.8.0