package com.rongyichuang.user.resolver; import com.rongyichuang.auth.dto.LoginResponse.EmployeeInfo; import com.rongyichuang.auth.dto.LoginResponse.JudgeInfo; import com.rongyichuang.auth.dto.LoginResponse.PlayerInfo; import com.rongyichuang.common.util.UserContextUtil; import com.rongyichuang.employee.entity.Employee; import com.rongyichuang.employee.service.EmployeeService; import com.rongyichuang.judge.entity.Judge; import com.rongyichuang.judge.service.JudgeService; import com.rongyichuang.player.entity.Player; import com.rongyichuang.player.service.PlayerService; import com.rongyichuang.player.repository.ActivityPlayerRepository; import com.rongyichuang.common.repository.MediaRepository; import com.rongyichuang.common.entity.Media; import com.rongyichuang.common.enums.MediaTargetType; import com.rongyichuang.user.dto.response.UserProfile; import com.rongyichuang.user.dto.response.UserStats; import com.rongyichuang.user.dto.response.UserRegistration; import com.rongyichuang.user.dto.response.UserProject; import com.rongyichuang.user.dto.request.UserInput; import com.rongyichuang.user.dto.response.UserProfileInfo; import com.rongyichuang.user.entity.User; import com.rongyichuang.user.repository.UserRepository; import com.rongyichuang.player.dto.response.SubmissionMediaResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.graphql.data.method.annotation.Argument; import org.springframework.graphql.data.method.annotation.QueryMapping; import org.springframework.graphql.data.method.annotation.MutationMapping; import org.springframework.stereotype.Controller; import org.springframework.util.StringUtils; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import jakarta.persistence.Query; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; import java.time.LocalDate; import java.time.format.DateTimeFormatter; /** * 用户GraphQL解析器 */ @Controller public class UserResolver { private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(UserResolver.class); @Autowired private EmployeeService employeeService; @Autowired private JudgeService judgeService; @Autowired private PlayerService playerService; @Autowired private ActivityPlayerRepository activityPlayerRepository; @Autowired private MediaRepository mediaRepository; @Autowired private UserRepository userRepository; @PersistenceContext private EntityManager entityManager; @Autowired private UserContextUtil userContextUtil; @Value("${app.media-url}") private String mediaBaseUrl; /** * 获取当前用户档案 */ @QueryMapping public UserProfile userProfile() { try { Long userId = userContextUtil.getCurrentUserId(); logger.debug("进入userProfile,解析到用户ID: {}", userId); if (userId == null) { throw new RuntimeException("用户未登录"); } UserProfile profile = new UserProfile(); profile.setId(userId.toString()); // 获取用户基本信息 Optional userOpt = userRepository.findById(userId); User user = null; if (userOpt.isPresent()) { user = userOpt.get(); // 设置性别 if (user.getGender() != null) { profile.setGender(user.getGender() == 1 ? "MALE" : "FEMALE"); } // 设置生日 if (user.getBirthday() != null) { profile.setBirthday(user.getBirthday().toString()); } } List roles = new ArrayList<>(); // 检查是否是员工 logger.debug("开始查询员工信息,userId={}", userId); Employee employee = employeeService.findByUserId(userId); logger.debug("员工查询结果: {}", employee != null ? ("id=" + employee.getId() + ", name=" + employee.getName()) : "无"); if (employee != null) { profile.setName(employee.getName()); profile.setPhone(employee.getPhone()); roles.add("EMPLOYEE"); EmployeeInfo employeeInfo = new EmployeeInfo( employee.getId(), employee.getName(), employee.getRoleId(), employee.getDescription() ); profile.setEmployee(employeeInfo); } // 检查是否是评委 logger.debug("开始查询评委信息,userId={}", userId); Judge judge = judgeService.findByUserId(userId); logger.debug("评委查询结果: {}", judge != null ? ("id=" + judge.getId() + ", name=" + judge.getName()) : "无"); if (judge != null) { if (profile.getName() == null) { profile.setName(judge.getName()); profile.setPhone(judge.getPhone()); } roles.add("JUDGE"); JudgeInfo judgeInfo = new JudgeInfo( judge.getId(), judge.getName(), judge.getTitle(), judge.getCompany(), judge.getDescription() ); profile.setJudge(judgeInfo); } // 检查是否是学员 logger.debug("开始查询学员信息,userId={}", userId); Player player = playerService.findByUserId(userId); logger.debug("学员查询结果: {}", player != null ? ("id=" + player.getId() + ", name=" + player.getName()) : "无"); if (player != null) { if (profile.getName() == null) { profile.setName(player.getName()); profile.setPhone(player.getPhone()); } roles.add("PLAYER"); PlayerInfo playerInfo = new PlayerInfo( player.getId(), player.getName(), player.getPhone(), player.getDescription() ); profile.setPlayer(playerInfo); } profile.setRoles(roles); // 获取用户头像 try { List avatarMediaList = mediaRepository.findByTargetTypeAndTargetIdAndState( MediaTargetType.USER_AVATAR.getValue(), userId, 1 ); if (!avatarMediaList.isEmpty()) { Media avatarMedia = avatarMediaList.get(0); String fullAvatarUrl = buildFullMediaUrl(avatarMedia.getPath()); profile.setAvatar(fullAvatarUrl); logger.debug("找到用户头像: {} -> {}", avatarMedia.getPath(), fullAvatarUrl); } else { logger.debug("用户{}没有找到头像", userId); } } catch (Exception e) { logger.warn("获取用户头像失败: {}", e.getMessage()); } logger.debug("userProfile构建完成,roles={}, name={}, phone={}, avatar={}", roles, profile.getName(), profile.getPhone(), profile.getAvatar()); profile.setCreatedAt(java.time.LocalDateTime.now().toString()); return profile; } catch (Exception e) { logger.error("获取用户档案失败", e); throw new RuntimeException("获取用户档案失败: " + e.getMessage(), e); } } /** * 获取用户统计数据 */ @QueryMapping public UserStats userStats() { try { Long userId = userContextUtil.getCurrentUserId(); if (userId == null) { return null; } UserStats stats = new UserStats(); stats.setTotalRegistrations(0); stats.setOngoingActivities(0); stats.setCompletedActivities(0); stats.setAwards(0); return stats; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 获取我的报名记录 */ @QueryMapping public List myRegistrations(@Argument Integer limit) { try { Long userId = userContextUtil.getCurrentUserId(); if (userId == null) { return new ArrayList<>(); } // 构建SQL查询,获取用户的报名记录 StringBuilder sql = new StringBuilder(); sql.append("SELECT ap.id, a.id as activity_id, a.name as activity_name, "); sql.append("ap.project_name, ap.state, ap.create_time, "); sql.append("m.path as cover_image_path "); sql.append("FROM t_activity_player ap "); sql.append("INNER JOIN t_player p ON ap.player_id = p.id "); sql.append("INNER JOIN t_activity a ON ap.activity_id = a.id "); sql.append("LEFT JOIN t_media m ON a.cover_image_id = m.id "); sql.append("WHERE p.user_id = :userId "); sql.append("ORDER BY ap.create_time DESC"); if (limit != null && limit > 0) { sql.append(" LIMIT :limit"); } Query query = entityManager.createNativeQuery(sql.toString()); query.setParameter("userId", userId); if (limit != null && limit > 0) { query.setParameter("limit", limit); } @SuppressWarnings("unchecked") List results = query.getResultList(); List registrations = new ArrayList<>(); for (Object[] row : results) { UserRegistration registration = new UserRegistration(); registration.setId(String.valueOf(row[0])); // 创建ActivityInfo UserRegistration.ActivityInfo activityInfo = new UserRegistration.ActivityInfo(); activityInfo.setId(String.valueOf(row[1])); activityInfo.setTitle((String) row[2]); // 设置封面图片 if (row[6] != null) { UserRegistration.MediaInfo mediaInfo = new UserRegistration.MediaInfo(); mediaInfo.setPath((String) row[6]); mediaInfo.setFullUrl(buildFullMediaUrl((String) row[6])); activityInfo.setCoverImage(mediaInfo); } registration.setActivity(activityInfo); // 设置状态 Integer state = (Integer) row[4]; String status = "pending"; if (state != null) { switch (state) { case 0: status = "pending"; break; case 1: status = "approved"; break; case 2: status = "rejected"; break; default: status = "unknown"; break; } } registration.setStatus(status); // 设置报名时间 if (row[5] != null) { registration.setRegistrationTime(row[5].toString()); } registrations.add(registration); } return registrations; } catch (Exception e) { logger.error("获取用户报名记录失败", e); return new ArrayList<>(); } } /** * 获取我的项目列表 */ @QueryMapping public List myProjects() { try { Long userId = userContextUtil.getCurrentUserId(); logger.debug("获取用户项目列表,userId: {}", userId); if (userId == null) { return new ArrayList<>(); } // 查询用户的所有项目(state = 0, 1, 2) // 使用 t_activity_player join t_player join t_user 的方式通过用户ID查询 String sql = """ SELECT ap.id, ap.project_name, a.name as activity_name, ap.state, ap.create_time FROM t_activity_player ap JOIN t_player p ON ap.player_id = p.id JOIN t_activity a ON a.id = ap.activity_id WHERE p.user_id = ? AND ap.state IN (0, 1, 2) ORDER BY ap.create_time DESC """; Query query = entityManager.createNativeQuery(sql); query.setParameter(1, userId); @SuppressWarnings("unchecked") List results = query.getResultList(); List projects = new ArrayList<>(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); for (Object[] row : results) { String id = row[0].toString(); String projectName = row[1] != null ? row[1].toString() : ""; String activityName = row[2] != null ? row[2].toString() : ""; String status = row[3] != null ? row[3].toString() : "0"; String createTime = row[4] != null ? row[4].toString() : ""; UserProject project = new UserProject(id, projectName, activityName, status, createTime); // 查询项目的提交文件 List submissionFiles = getSubmissionFiles(Long.parseLong(id)); project.setSubmissionFiles(submissionFiles); projects.add(project); } logger.debug("查询到 {} 个项目", projects.size()); return projects; } catch (Exception e) { logger.error("获取用户项目列表失败", e); return new ArrayList<>(); } } /** * 获取项目的提交文件 * @param activityPlayerId 活动参与者ID * @return 提交文件列表 */ private List getSubmissionFiles(Long activityPlayerId) { try { // 查询提交的媒体文件 (target_type = 5 表示活动参与者提交的文件,state = 1 表示有效状态) List medias = mediaRepository.findByTargetTypeAndTargetIdAndState(5, activityPlayerId, 1); List submissionFiles = new ArrayList<>(); for (Media media : medias) { SubmissionMediaResponse response = new SubmissionMediaResponse(); response.setId(media.getId()); response.setName(media.getName()); response.setPath(media.getPath()); response.setUrl(buildFullMediaUrl(media.getPath())); response.setFullUrl(buildFullMediaUrl(media.getPath())); response.setFullThumbUrl(buildFullMediaUrl(media.getThumbPath())); response.setFileExt(media.getFileExt()); response.setFileSize(media.getFileSize() != null ? media.getFileSize().longValue() : null); response.setMediaType(media.getMediaType()); response.setThumbUrl(buildFullMediaUrl(media.getThumbPath())); submissionFiles.add(response); } return submissionFiles; } catch (Exception e) { logger.error("获取项目提交文件失败,activityPlayerId: {}", activityPlayerId, e); return new ArrayList<>(); } } /** * 构建完整的媒体URL * @param path 媒体路径 * @return 完整的URL */ private String buildFullMediaUrl(String path) { if (!StringUtils.hasText(path)) { return null; } // 如果路径已经是完整URL,直接返回 if (path.startsWith("http://") || path.startsWith("https://")) { return path; } // 构建完整URL if (StringUtils.hasText(mediaBaseUrl)) { // 确保baseUrl以/结尾,path不以/开头 String baseUrl = mediaBaseUrl.endsWith("/") ? mediaBaseUrl : mediaBaseUrl + "/"; String relativePath = path.startsWith("/") ? path.substring(1) : path; return baseUrl + relativePath; } // 如果没有配置baseUrl,返回原路径 return path; } /** * 保存用户信息 */ @MutationMapping public UserProfileInfo saveUserInfo(@Argument UserInput input) { try { Long userId = userContextUtil.getCurrentUserId(); logger.debug("进入saveUserInfo,解析到用户ID: {}", userId); if (userId == null) { throw new RuntimeException("用户未登录"); } // 查找现有用户 Optional userOpt = userRepository.findById(userId); User user; if (userOpt.isPresent()) { // 用户存在,更新信息 user = userOpt.get(); logger.debug("更新现有用户信息,用户ID: {}", userId); } else { // 用户不存在,创建新用户 user = new User(); user.setId(userId); logger.debug("创建新用户,用户ID: {}", userId); } // 更新用户基本信息(不包含头像) user.setName(input.getName()); user.setPhone(input.getPhone()); // 处理性别转换:MALE -> 1, FEMALE -> 0 if ("MALE".equals(input.getGender())) { user.setGender(1); } else if ("FEMALE".equals(input.getGender())) { user.setGender(0); } // 处理生日转换 if (StringUtils.hasText(input.getBirthday())) { try { LocalDate birthday = LocalDate.parse(input.getBirthday()); user.setBirthday(birthday); } catch (Exception e) { logger.warn("生日格式解析失败: {}", input.getBirthday(), e); } } // 保存用户基本信息 user = userRepository.save(user); logger.debug("用户信息保存成功,用户ID: {}", user.getId()); // 构建返回结果 UserProfileInfo result = new UserProfileInfo(); result.setId(user.getId().toString()); result.setName(user.getName()); result.setPhone(user.getPhone()); // 正确处理性别转换:1 -> MALE, 0 -> FEMALE, null -> null if (user.getGender() != null) { result.setGender(user.getGender() == 1 ? "MALE" : "FEMALE"); } else { result.setGender(null); } result.setBirthday(user.getBirthday() != null ? user.getBirthday().toString() : null); result.setWxOpenId(user.getWxOpenid()); result.setUnionId(user.getWxUnionid()); // 查找并设置头像URL(从t_media表获取) try { List avatarMedias = mediaRepository.findByTargetTypeAndTargetIdAndState( MediaTargetType.USER_AVATAR.getValue(), userId, 1 ); if (!avatarMedias.isEmpty()) { Media avatarMedia = avatarMedias.get(0); result.setAvatar(buildFullMediaUrl(avatarMedia.getPath())); } } catch (Exception e) { logger.warn("获取头像失败: {}", e.getMessage(), e); } return result; } catch (Exception e) { logger.error("保存用户信息失败", e); throw new RuntimeException("保存用户信息失败: " + e.getMessage()); } } }