From bd999ecc09fcacf4016edcba85caf9b9696d2140 Mon Sep 17 00:00:00 2001
From: lrj <owen.stl@gmail.com>
Date: 星期六, 04 十月 2025 18:40:31 +0800
Subject: [PATCH] feat: 同步本地改动(认证/评审/用户/选手模块更新;新增/调整 GraphQL schema;小程序个人信息与评审相关页面、配置与资源等)

---
 backend/src/main/java/com/rongyichuang/user/resolver/UserResolver.java |  351 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 346 insertions(+), 5 deletions(-)

diff --git a/backend/src/main/java/com/rongyichuang/user/resolver/UserResolver.java b/backend/src/main/java/com/rongyichuang/user/resolver/UserResolver.java
index 2c597ef..dff7fd5 100644
--- a/backend/src/main/java/com/rongyichuang/user/resolver/UserResolver.java
+++ b/backend/src/main/java/com/rongyichuang/user/resolver/UserResolver.java
@@ -10,16 +10,37 @@
 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瑙f瀽鍣�
@@ -38,7 +59,22 @@
     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;
 
     /**
      * 鑾峰彇褰撳墠鐢ㄦ埛妗f
@@ -54,6 +90,21 @@
 
             UserProfile profile = new UserProfile();
             profile.setId(userId.toString());
+            
+            // 鑾峰彇鐢ㄦ埛鍩烘湰淇℃伅
+            Optional<User> 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<String> roles = new ArrayList<>();
             
@@ -117,7 +168,28 @@
             }
             
             profile.setRoles(roles);
-            logger.debug("userProfile鏋勫缓瀹屾垚锛宺oles={}, name={}, phone={}", roles, profile.getName(), profile.getPhone());
+            
+            // 鑾峰彇鐢ㄦ埛澶村儚
+            try {
+                List<Media> 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鏋勫缓瀹屾垚锛宺oles={}, name={}, phone={}, avatar={}", 
+                roles, profile.getName(), profile.getPhone(), profile.getAvatar());
             profile.setCreatedAt(java.time.LocalDateTime.now().toString());
             
             return profile;
@@ -162,12 +234,281 @@
                 return new ArrayList<>();
             }
 
-            // 杩欓噷搴旇瀹炵幇鐪熸鐨勬姤鍚嶈褰曟煡璇㈤�昏緫
-            // 鏆傛椂杩斿洖绌哄垪琛�
-            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<Object[]> results = query.getResultList();
+            
+            List<UserRegistration> 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) {
-            e.printStackTrace();
+            logger.error("鑾峰彇鐢ㄦ埛鎶ュ悕璁板綍澶辫触", e);
             return new ArrayList<>();
         }
     }
+
+    /**
+     * 鑾峰彇鎴戠殑椤圭洰鍒楄〃
+     */
+    @QueryMapping
+    public List<UserProject> myProjects() {
+        try {
+            Long userId = userContextUtil.getCurrentUserId();
+            logger.debug("鑾峰彇鐢ㄦ埛椤圭洰鍒楄〃锛寀serId: {}", 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<Object[]> results = query.getResultList();
+
+            List<UserProject> 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<SubmissionMediaResponse> 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 娲诲姩鍙備笌鑰匢D
+     * @return 鎻愪氦鏂囦欢鍒楄〃
+     */
+    private List<SubmissionMediaResponse> getSubmissionFiles(Long activityPlayerId) {
+        try {
+            // 鏌ヨ鎻愪氦鐨勫獟浣撴枃浠� (target_type = 5 琛ㄧず娲诲姩鍙備笌鑰呮彁浜ょ殑鏂囦欢锛宻tate = 1 琛ㄧず鏈夋晥鐘舵��)
+            List<Media> medias = mediaRepository.findByTargetTypeAndTargetIdAndState(5, activityPlayerId, 1);
+            
+            List<SubmissionMediaResponse> 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("鑾峰彇椤圭洰鎻愪氦鏂囦欢澶辫触锛宎ctivityPlayerId: {}", activityPlayerId, e);
+            return new ArrayList<>();
+        }
+    }
+
+    /**
+     * 鏋勫缓瀹屾暣鐨勫獟浣揢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;
+    }
+
+    /**
+     * 淇濆瓨鐢ㄦ埛淇℃伅
+     */
+    @MutationMapping
+    public UserProfileInfo saveUserInfo(@Argument UserInput input) {
+        try {
+            Long userId = userContextUtil.getCurrentUserId();
+            logger.debug("杩涘叆saveUserInfo锛岃В鏋愬埌鐢ㄦ埛ID: {}", userId);
+            if (userId == null) {
+                throw new RuntimeException("鐢ㄦ埛鏈櫥褰�");
+            }
+
+            // 鏌ユ壘鐜版湁鐢ㄦ埛
+            Optional<User> userOpt = userRepository.findById(userId);
+            User user;
+            
+            if (userOpt.isPresent()) {
+                // 鐢ㄦ埛瀛樺湪锛屾洿鏂颁俊鎭�
+                user = userOpt.get();
+                logger.debug("鏇存柊鐜版湁鐢ㄦ埛淇℃伅锛岀敤鎴稩D: {}", userId);
+            } else {
+                // 鐢ㄦ埛涓嶅瓨鍦紝鍒涘缓鏂扮敤鎴�
+                user = new User();
+                user.setId(userId);
+                logger.debug("鍒涘缓鏂扮敤鎴凤紝鐢ㄦ埛ID: {}", userId);
+            }
+
+            // 鏇存柊鐢ㄦ埛鍩烘湰淇℃伅锛堜笉鍖呭惈澶村儚锛�
+            user.setName(input.getName());
+            user.setPhone(input.getPhone());
+            
+            // 澶勭悊鎬у埆杞崲锛歁ALE -> 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("鐢熸棩鏍煎紡瑙f瀽澶辫触: {}", input.getBirthday(), e);
+                }
+            }
+
+            // 淇濆瓨鐢ㄦ埛鍩烘湰淇℃伅
+            user = userRepository.save(user);
+            logger.debug("鐢ㄦ埛淇℃伅淇濆瓨鎴愬姛锛岀敤鎴稩D: {}", user.getId());
+
+            // 鏋勫缓杩斿洖缁撴灉
+            UserProfileInfo result = new UserProfileInfo();
+            result.setId(user.getId().toString());
+            result.setName(user.getName());
+            result.setPhone(user.getPhone());
+            // 姝g‘澶勭悊鎬у埆杞崲锛�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());
+            
+            // 鏌ユ壘骞惰缃ご鍍廢RL锛堜粠t_media琛ㄨ幏鍙栵級
+            try {
+                List<Media> 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());
+        }
+    }
 }
\ No newline at end of file

--
Gitblit v1.8.0