| | |
| | | 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; |
| | | |
| | | /** |
| | |
| | | |
| | | private final MediaRepository mediaRepository; |
| | | private final RatingSchemeRepository ratingSchemeRepository; |
| | | |
| | | @Value("${app.media-url}") |
| | | private String mediaBaseUrl; |
| | | |
| | | public ActivityPlayerDetailService(MediaRepository mediaRepository, |
| | | RatingSchemeRepository ratingSchemeRepository) { |
| | |
| | | |
| | | // 查询基本信息,包含区域信息 |
| | | String sql = """ |
| | | SELECT ap.id, ap.description, ap.activity_id, ap.region_id, |
| | | 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 r_id, r.name as region_name, r.full_path as region_path |
| | | 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") |
| | | List<Object[]> results = em.createNativeQuery(sql) |
| | | .setParameter(1, activityPlayerId) |
| | | .getResultList(); |
| | | Query query = em.createNativeQuery(sql); |
| | | query.setParameter(1, activityPlayerId); |
| | | |
| | | // 使用 Tuple 来获取命名字段 |
| | | query.unwrap(org.hibernate.query.NativeQuery.class).setTupleTransformer( |
| | | (tuple, aliases) -> { |
| | | Map<String, Object> result = new HashMap<>(); |
| | | for (int i = 0; i < aliases.length; i++) { |
| | | result.put(aliases[i], tuple[i]); |
| | | } |
| | | return result; |
| | | } |
| | | ); |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | List<Map<String, Object>> results = query.getResultList(); |
| | | |
| | | if (results.isEmpty()) { |
| | | log.warn("未找到报名记录,activityPlayerId: {}", activityPlayerId); |
| | | return null; |
| | | } |
| | | |
| | | Object[] row = results.get(0); |
| | | Map<String, Object> row = results.get(0); |
| | | ActivityPlayerDetailResponse response = new ActivityPlayerDetailResponse(); |
| | | response.setId(activityPlayerId); |
| | | response.setDescription(row[1] != null ? row[1].toString() : ""); |
| | | response.setActivityName(row[8] != null ? row[8].toString() : ""); |
| | | 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(); |
| | | playerInfo.setId(row[4] != null ? ((Number) row[4]).longValue() : null); |
| | | playerInfo.setName(row[5] != null ? row[5].toString() : ""); |
| | | playerInfo.setPhone(row[6] != null ? row[6].toString() : ""); |
| | | playerInfo.setDescription(row[7] != null ? row[7].toString() : ""); |
| | | 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() : ""); |
| | | |
| | | // 构建区域信息 |
| | | RegionInfoResponse regionInfo = new RegionInfoResponse(); |
| | | if (row[10] != null) { |
| | | regionInfo.setId(((Number) row[10]).longValue()); |
| | | regionInfo.setName(row[11] != null ? row[11].toString() : ""); |
| | | regionInfo.setFullPath(row[12] != null ? row[12].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()); |
| | | } |
| | | |
| | | // 查询学员头像(使用枚举常量表示学员头像类型) |
| | | if (playerInfo.getId() != null) { |
| | | // 查询用户头像(使用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<Media> avatarMedias = mediaRepository.findByTargetTypeAndTargetIdAndState( |
| | | MediaTargetType.STUDENT_AVATAR.getValue(), playerInfo.getId(), 1); |
| | | MediaTargetType.USER_AVATAR.getValue(), userId, 1); |
| | | log.info("调试:查询到的头像媒体数量: {}", avatarMedias.size()); |
| | | if (!avatarMedias.isEmpty()) { |
| | | Media avatar = avatarMedias.get(0); |
| | | String avatarUrl = avatar.getPath(); |
| | | String avatarUrl = buildFullMediaUrl(avatar.getPath()); |
| | | playerInfo.setAvatarUrl(avatarUrl); |
| | | log.info("找到学员头像: {}", 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); |
| | | |
| | |
| | | log.info("找到提交资料 {} 个", submissionFiles.size()); |
| | | |
| | | // 查询评分模板 |
| | | Long ratingSchemeId = row[9] != null ? ((Number) row[9]).longValue() : null; |
| | | 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); |
| | |
| | | SubmissionMediaResponse response = new SubmissionMediaResponse(); |
| | | response.setId(media.getId()); |
| | | response.setName(media.getName()); |
| | | response.setUrl(media.getPath()); |
| | | 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; |
| | | } |
| | | |
| | |
| | | |
| | | 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; |
| | | } |
| | | } |