package com.rongyichuang.player.service; import com.rongyichuang.player.dto.response.*; import com.rongyichuang.player.dto.response.RegionInfoResponse; import com.rongyichuang.rating.dto.response.RatingItemResponse; import com.rongyichuang.rating.entity.RatingScheme; import com.rongyichuang.rating.repository.RatingSchemeRepository; import com.rongyichuang.common.entity.Media; import com.rongyichuang.common.enums.MediaTargetType; import com.rongyichuang.common.repository.MediaRepository; import com.rongyichuang.common.dto.response.MediaResponse; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import jakarta.persistence.Query; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.util.stream.Collectors; /** * 比赛报名详情服务(用于评分页面) */ @Service public class ActivityPlayerDetailService { private static final Logger log = LoggerFactory.getLogger(ActivityPlayerDetailService.class); @PersistenceContext private EntityManager em; private final MediaRepository mediaRepository; private final RatingSchemeRepository ratingSchemeRepository; @Value("${app.media-url}") private String mediaBaseUrl; public ActivityPlayerDetailService(MediaRepository mediaRepository, RatingSchemeRepository ratingSchemeRepository) { this.mediaRepository = mediaRepository; this.ratingSchemeRepository = ratingSchemeRepository; } /** * 获取比赛报名详情(用于评分) * @param activityPlayerId 报名记录ID * @return 报名详情 */ public ActivityPlayerDetailResponse getDetailForRating(Long activityPlayerId) { log.info("获取报名详情用于评分,activityPlayerId: {}", activityPlayerId); // 查询基本信息,包含区域信息 String sql = """ SELECT ap.id as ap_id, ap.description as ap_description, ap.activity_id, ap.region_id, ap.project_name, ap.feedback, ap.state as ap_state, p.id as player_id, p.name as player_name, p.phone, p.description as player_desc, p.gender, u.birthday, p.education, p.introduction, u.id as user_id, a.name as activity_name, a.rating_scheme_id, r.id as region_id, r.name as region_name, r.full_path as region_path FROM t_activity_player ap JOIN t_player p ON p.id = ap.player_id JOIN t_user u ON u.id = p.user_id JOIN t_activity a ON a.id = ap.activity_id LEFT JOIN t_region r ON r.id = ap.region_id WHERE ap.id = ? """; @SuppressWarnings("unchecked") Query query = em.createNativeQuery(sql); query.setParameter(1, activityPlayerId); // 使用 Tuple 来获取命名字段 query.unwrap(org.hibernate.query.NativeQuery.class).setTupleTransformer( (tuple, aliases) -> { Map result = new HashMap<>(); for (int i = 0; i < aliases.length; i++) { result.put(aliases[i], tuple[i]); } return result; } ); @SuppressWarnings("unchecked") List> results = query.getResultList(); if (results.isEmpty()) { log.warn("未找到报名记录,activityPlayerId: {}", activityPlayerId); return null; } Map row = results.get(0); ActivityPlayerDetailResponse response = new ActivityPlayerDetailResponse(); response.setId(activityPlayerId); response.setDescription(row.get("ap_description") != null ? row.get("ap_description").toString() : ""); response.setProjectName(row.get("project_name") != null ? row.get("project_name").toString() : ""); response.setFeedback(row.get("feedback") != null ? row.get("feedback").toString() : ""); Object stateObj = row.get("ap_state"); if (stateObj != null) { if (stateObj instanceof Number) { response.setState(((Number) stateObj).intValue()); } else { log.warn("状态类型不匹配: {}, 类型: {}", stateObj, stateObj.getClass().getName()); response.setState(Integer.valueOf(stateObj.toString())); } } else { response.setState(0); } response.setActivityName(row.get("activity_name") != null ? row.get("activity_name").toString() : ""); // 构建学员信息 PlayerInfoResponse playerInfo = new PlayerInfoResponse(); Object playerIdObj = row.get("player_id"); if (playerIdObj != null) { if (playerIdObj instanceof Number) { playerInfo.setId(((Number) playerIdObj).longValue()); } else { log.warn("学员ID类型不匹配: {}, 类型: {}", playerIdObj, playerIdObj.getClass().getName()); playerInfo.setId(Long.valueOf(playerIdObj.toString())); } } else { playerInfo.setId(null); } playerInfo.setName(row.get("player_name") != null ? row.get("player_name").toString() : ""); playerInfo.setPhone(row.get("phone") != null ? row.get("phone").toString() : ""); playerInfo.setDescription(row.get("player_desc") != null ? row.get("player_desc").toString() : ""); Object genderObj = row.get("gender"); if (genderObj != null) { if (genderObj instanceof Number) { playerInfo.setGender(((Number) genderObj).intValue()); } else { log.warn("性别类型不匹配: {}, 类型: {}", genderObj, genderObj.getClass().getName()); playerInfo.setGender(Integer.valueOf(genderObj.toString())); } } else { playerInfo.setGender(null); } Object birthdayObj = row.get("birthday"); playerInfo.setBirthday(birthdayObj != null ? (birthdayObj instanceof java.sql.Date ? ((java.sql.Date) birthdayObj).toString() : birthdayObj.toString()) : null); playerInfo.setEducation(row.get("education") != null ? row.get("education").toString() : ""); playerInfo.setIntroduction(row.get("introduction") != null ? row.get("introduction").toString() : ""); // 构建区域信息 Object regionIdObj = row.get("region_id"); if (regionIdObj != null) { RegionInfoResponse regionInfo = new RegionInfoResponse(); if (regionIdObj instanceof Number) { regionInfo.setId(((Number) regionIdObj).longValue()); } else { log.warn("区域ID类型不匹配: {}, 类型: {}", regionIdObj, regionIdObj.getClass().getName()); regionInfo.setId(Long.valueOf(regionIdObj.toString())); } regionInfo.setName(row.get("region_name") != null ? row.get("region_name").toString() : ""); regionInfo.setFullPath(row.get("region_path") != null ? row.get("region_path").toString() : ""); response.setRegionInfo(regionInfo); log.info("找到区域信息: {}", regionInfo.getName()); } // 查询用户头像(使用USER_AVATAR关联到用户) Object userIdObj = row.get("user_id"); log.info("调试:从查询结果中获取的user_id: {}", userIdObj); if (userIdObj != null) { Long userId; if (userIdObj instanceof Number) { userId = ((Number) userIdObj).longValue(); } else { userId = Long.valueOf(userIdObj.toString()); } log.info("调试:解析后的userId: {}", userId); List avatarMedias = mediaRepository.findByTargetTypeAndTargetIdAndState( MediaTargetType.USER_AVATAR.getValue(), userId, 1); log.info("调试:查询到的头像媒体数量: {}", avatarMedias.size()); if (!avatarMedias.isEmpty()) { Media avatar = avatarMedias.get(0); String avatarUrl = buildFullMediaUrl(avatar.getPath()); playerInfo.setAvatarUrl(avatarUrl); // 设置avatar对象 playerInfo.setAvatar(convertToMediaResponse(avatar)); log.info("找到用户头像: {}", avatarUrl); } else { log.info("调试:未找到用户头像,userId: {}, targetType: {}", userId, MediaTargetType.USER_AVATAR.getValue()); } } else { log.warn("调试:user_id为null"); } response.setPlayerInfo(playerInfo); // 查询提交的资料(使用枚举常量表示参赛报名资料类型) List submissionMedias = mediaRepository.findByTargetTypeAndTargetIdAndState( MediaTargetType.ACTIVITY_PLAYER_SUBMISSION.getValue(), activityPlayerId, 1); List submissionFiles = submissionMedias.stream() .map(this::convertToSubmissionMedia) .collect(Collectors.toList()); response.setSubmissionFiles(submissionFiles); log.info("找到提交资料 {} 个", submissionFiles.size()); // 查询评分模板 Object ratingSchemeIdObj = row.get("rating_scheme_id"); Long ratingSchemeId = ratingSchemeIdObj != null ? ((Number) ratingSchemeIdObj).longValue() : null; if (ratingSchemeId != null) { RatingFormResponse ratingForm = buildRatingForm(ratingSchemeId); response.setRatingForm(ratingForm); } return response; } /** * 转换媒体文件为提交资料响应 */ private SubmissionMediaResponse convertToSubmissionMedia(Media media) { SubmissionMediaResponse response = new SubmissionMediaResponse(); response.setId(media.getId()); response.setName(media.getName()); response.setUrl(buildFullMediaUrl(media.getPath())); response.setFileExt(media.getFileExt()); response.setFileSize(media.getFileSize() != null ? media.getFileSize().longValue() : null); response.setMediaType(media.getMediaType()); response.setThumbUrl(buildFullMediaUrl(media.getThumbPath())); return response; } /** * 构建评分表单 */ private RatingFormResponse buildRatingForm(Long ratingSchemeId) { log.info("构建评分表单,ratingSchemeId: {}", ratingSchemeId); RatingScheme scheme = ratingSchemeRepository.findById(ratingSchemeId).orElse(null); if (scheme == null) { log.warn("未找到评分模板,ratingSchemeId: {}", ratingSchemeId); return null; } RatingFormResponse response = new RatingFormResponse(); response.setSchemeId(scheme.getId()); response.setSchemeName(scheme.getName()); response.setTotalMaxScore(scheme.getTotalScore()); // 转换评分项目 if (scheme.getItems() != null) { List items = scheme.getItems().stream() .map(RatingItemResponse::new) .collect(Collectors.toList()); response.setItems(items); } log.info("评分模板构建完成,包含 {} 个评分项目", response.getItems() != null ? response.getItems().size() : 0); return response; } /** * 转换媒体文件为MediaResponse */ private MediaResponse convertToMediaResponse(Media media) { MediaResponse response = new MediaResponse(); response.setId(media.getId()); response.setName(media.getName()); response.setPath(media.getPath()); response.setFileSize(media.getFileSize()); response.setFileExt(media.getFileExt()); response.setThumbPath(media.getThumbPath()); response.setDuration(media.getDuration()); response.setDescription(media.getDescription()); response.setTargetType(media.getTargetType()); response.setTargetId(media.getTargetId()); response.setMediaType(media.getMediaType()); // 设置完整URL response.setFullUrl(buildFullMediaUrl(media.getPath())); response.setFullThumbUrl(buildFullMediaUrl(media.getThumbPath())); return response; } private String buildFullMediaUrl(String path) { if (!StringUtils.hasText(path)) { return null; } // 如果已经是完整URL,直接返回 if (path.startsWith("http://") || path.startsWith("https://")) { return path; } // 如果没有配置mediaBaseUrl,返回原路径 if (!StringUtils.hasText(mediaBaseUrl)) { return path; } // 拼接完整URL String baseUrl = mediaBaseUrl.endsWith("/") ? mediaBaseUrl : mediaBaseUrl + "/"; String relativePath = path.startsWith("/") ? path.substring(1) : path; return baseUrl + relativePath; } }