From 0a48616045ddce1562584543a0e89e5144051fde Mon Sep 17 00:00:00 2001
From: Codex Assistant <codex@example.com>
Date: 星期日, 05 十月 2025 14:52:44 +0800
Subject: [PATCH] 报名审核
---
wx/pages/judge/review.js | 522 +++++++++--------
wx/app.js | 202 +++++-
wx/pages/judge/review.wxss | 444 ++++----------
wx/pages/judge/review.wxml | 210 ++----
backend/src/main/java/com/rongyichuang/player/dto/response/CurrentJudgeRatingResponse.java | 24
backend/src/main/java/com/rongyichuang/review/resolver/ReviewResolver.java | 18
backend/src/main/java/com/rongyichuang/auth/filter/JwtAuthenticationFilter.java | 2
clear-invalid-tokens.js | 86 ++
backend/src/main/java/com/rongyichuang/player/service/ActivityPlayerRatingService.java | 47 +
wx/pages/review/index.js | 92 ++
wx/pages/review/index.wxml | 21
wx/pages/review/index.wxss | 31
backend/src/main/resources/application.yml | 2
backend/src/main/resources/graphql/player.graphqls | 2
wx/pages/project/detail.js | 2
wx/pages/message/message.js | 18
16 files changed, 883 insertions(+), 840 deletions(-)
diff --git a/backend/src/main/java/com/rongyichuang/auth/filter/JwtAuthenticationFilter.java b/backend/src/main/java/com/rongyichuang/auth/filter/JwtAuthenticationFilter.java
index e7a03b1..c0f9452 100644
--- a/backend/src/main/java/com/rongyichuang/auth/filter/JwtAuthenticationFilter.java
+++ b/backend/src/main/java/com/rongyichuang/auth/filter/JwtAuthenticationFilter.java
@@ -169,7 +169,7 @@
* 杩斿洖鏉冮檺閿欒鍝嶅簲
*/
private void sendUnauthorizedResponse(HttpServletResponse response) throws IOException {
- response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"errors\":[{\"message\":\"娌℃湁鏉冮檺璁块棶锛岃鍏堢櫥褰昞",\"extensions\":{\"code\":\"UNAUTHORIZED\"}}]}");
}
diff --git a/backend/src/main/java/com/rongyichuang/player/dto/response/CurrentJudgeRatingResponse.java b/backend/src/main/java/com/rongyichuang/player/dto/response/CurrentJudgeRatingResponse.java
index f71bf5c..df38ac5 100644
--- a/backend/src/main/java/com/rongyichuang/player/dto/response/CurrentJudgeRatingResponse.java
+++ b/backend/src/main/java/com/rongyichuang/player/dto/response/CurrentJudgeRatingResponse.java
@@ -12,6 +12,7 @@
private BigDecimal totalScore;
private Integer status;
private String remark;
+ private String ratedAt;
private List<CurrentJudgeRatingItemResponse> items;
public CurrentJudgeRatingResponse() {}
@@ -48,6 +49,14 @@
this.remark = remark;
}
+ public String getRatedAt() {
+ return ratedAt;
+ }
+
+ public void setRatedAt(String ratedAt) {
+ this.ratedAt = ratedAt;
+ }
+
public List<CurrentJudgeRatingItemResponse> getItems() {
return items;
}
@@ -64,15 +73,18 @@
private String ratingItemName;
private BigDecimal score;
private BigDecimal weightedScore;
+ private BigDecimal maxScore;
public CurrentJudgeRatingItemResponse() {}
public CurrentJudgeRatingItemResponse(Long ratingItemId, String ratingItemName,
- BigDecimal score, BigDecimal weightedScore) {
+ BigDecimal score, BigDecimal weightedScore,
+ BigDecimal maxScore) {
this.ratingItemId = ratingItemId;
this.ratingItemName = ratingItemName;
this.score = score;
this.weightedScore = weightedScore;
+ this.maxScore = maxScore;
}
public Long getRatingItemId() {
@@ -106,5 +118,13 @@
public void setWeightedScore(BigDecimal weightedScore) {
this.weightedScore = weightedScore;
}
+
+ public BigDecimal getMaxScore() {
+ return maxScore;
+ }
+
+ public void setMaxScore(BigDecimal maxScore) {
+ this.maxScore = maxScore;
+ }
}
-}
\ No newline at end of file
+}
diff --git a/backend/src/main/java/com/rongyichuang/player/service/ActivityPlayerRatingService.java b/backend/src/main/java/com/rongyichuang/player/service/ActivityPlayerRatingService.java
index e41faf5..94615e1 100644
--- a/backend/src/main/java/com/rongyichuang/player/service/ActivityPlayerRatingService.java
+++ b/backend/src/main/java/com/rongyichuang/player/service/ActivityPlayerRatingService.java
@@ -233,16 +233,35 @@
// 鑾峰彇璇勫垎椤�
List<ActivityPlayerRatingItem> items = activityPlayerRatingItemRepository
.findByActivityPlayerRatingId(rating.getId());
-
- List<CurrentJudgeRatingResponse.CurrentJudgeRatingItemResponse> itemResponses = items.stream()
- .map(item -> new CurrentJudgeRatingResponse.CurrentJudgeRatingItemResponse(
- item.getRatingItemId(),
- "", // 璇勫垎椤瑰悕绉版殏鏃朵负绌�
- item.getScore(),
- item.getScore() // 浣跨敤寰楀垎浣滀负鍔犳潈寰楀垎
- ))
+
+ List<Long> ratingItemIds = items.stream()
+ .map(ActivityPlayerRatingItem::getRatingItemId)
+ .filter(java.util.Objects::nonNull)
+ .distinct()
.collect(java.util.stream.Collectors.toList());
-
+
+ java.util.Map<Long, RatingItem> ratingItemMap = ratingItemIds.isEmpty()
+ ? java.util.Collections.emptyMap()
+ : ratingItemRepository.findAllById(ratingItemIds).stream()
+ .collect(java.util.stream.Collectors.toMap(RatingItem::getId, java.util.function.Function.identity()));
+
+ List<CurrentJudgeRatingResponse.CurrentJudgeRatingItemResponse> itemResponses = items.stream()
+ .map(item -> {
+ RatingItem ratingItem = ratingItemMap.get(item.getRatingItemId());
+ String name = ratingItem != null ? ratingItem.getName() : "";
+ BigDecimal maxScore = ratingItem != null && ratingItem.getMaxScore() != null
+ ? BigDecimal.valueOf(ratingItem.getMaxScore()) : null;
+ return new CurrentJudgeRatingResponse.CurrentJudgeRatingItemResponse(
+ item.getRatingItemId(),
+ name,
+ item.getScore(),
+ item.getScore(),
+ maxScore
+ );
+ })
+ .collect(java.util.stream.Collectors.toList());
+
+ response.setRatedAt(rating.getUpdateTime() != null ? rating.getUpdateTime().toString() : null);
response.setItems(itemResponses);
return response;
}
@@ -403,7 +422,12 @@
((Number) row.get("rating_item_id")).longValue(),
(String) row.get("rating_item_name"),
(BigDecimal) row.get("score"),
- (BigDecimal) row.get("score") // weightedScore 鏆傛椂浣跨敤鐩稿悓鍊�
+ (BigDecimal) row.get("score"),
+ row.get("max_score") instanceof BigDecimal
+ ? (BigDecimal) row.get("max_score")
+ : row.get("max_score") instanceof Number
+ ? BigDecimal.valueOf(((Number) row.get("max_score")).doubleValue())
+ : null
))
.collect(java.util.stream.Collectors.toList());
@@ -412,6 +436,7 @@
response.setTotalScore(rating.getTotalScore());
response.setStatus(rating.getState());
response.setRemark(rating.getFeedback());
+ response.setRatedAt(rating.getUpdateTime() != null ? rating.getUpdateTime().toString() : null);
response.setItems(items);
return response;
@@ -421,4 +446,4 @@
return null;
}
}
-}
\ No newline at end of file
+}
diff --git a/backend/src/main/java/com/rongyichuang/review/resolver/ReviewResolver.java b/backend/src/main/java/com/rongyichuang/review/resolver/ReviewResolver.java
index e8c8503..0f513a3 100644
--- a/backend/src/main/java/com/rongyichuang/review/resolver/ReviewResolver.java
+++ b/backend/src/main/java/com/rongyichuang/review/resolver/ReviewResolver.java
@@ -31,10 +31,10 @@
*/
@QueryMapping
public ReviewProjectPageResponse unReviewedProjects(
- @Argument String searchKeyword,
@Argument int page,
- @Argument int pageSize) {
- log.info("鏌ヨ鎴戞湭璇勫鐨勯」鐩垪琛紝searchKeyword: {}, page: {}, pageSize: {}", searchKeyword, page, pageSize);
+ @Argument int pageSize,
+ @Argument String searchKeyword) {
+ log.info("鏌ヨ鎴戞湭璇勫鐨勯」鐩垪琛紝page: {}, pageSize: {}, searchKeyword: {}", page, pageSize, searchKeyword);
Long currentJudgeId = userContextUtil.getCurrentJudgeId();
if (currentJudgeId == null) {
@@ -49,10 +49,10 @@
*/
@QueryMapping
public ReviewProjectPageResponse reviewedProjects(
- @Argument String searchKeyword,
@Argument int page,
- @Argument int pageSize) {
- log.info("鏌ヨ鎴戝凡璇勫鐨勯」鐩垪琛紝searchKeyword: {}, page: {}, pageSize: {}", searchKeyword, page, pageSize);
+ @Argument int pageSize,
+ @Argument String searchKeyword) {
+ log.info("鏌ヨ鎴戝凡璇勫鐨勯」鐩垪琛紝page: {}, pageSize: {}, searchKeyword: {}", page, pageSize, searchKeyword);
Long currentJudgeId = userContextUtil.getCurrentJudgeId();
if (currentJudgeId == null) {
@@ -67,10 +67,10 @@
*/
@QueryMapping
public ReviewProjectPageResponse studentUnReviewedProjects(
- @Argument String searchKeyword,
@Argument int page,
- @Argument int pageSize) {
- log.info("鏌ヨ瀛﹀憳鏈瘎瀹$殑椤圭洰鍒楄〃锛宻earchKeyword: {}, page: {}, pageSize: {}", searchKeyword, page, pageSize);
+ @Argument int pageSize,
+ @Argument String searchKeyword) {
+ log.info("鏌ヨ瀛﹀憳鏈瘎瀹$殑椤圭洰鍒楄〃锛宲age: {}, pageSize: {}, searchKeyword: {}", page, pageSize, searchKeyword);
Long currentJudgeId = userContextUtil.getCurrentJudgeId();
if (currentJudgeId == null) {
diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml
index f4b9dda..9f5dff8 100644
--- a/backend/src/main/resources/application.yml
+++ b/backend/src/main/resources/application.yml
@@ -86,7 +86,7 @@
base-url: https://rych.9village.cn
jwt:
secret: ryc-jwt-secret-key-2024-secure-256bit-hmac-sha-algorithm-compatible
- expiration: 86400000 # 24灏忔椂
+ expiration: 7200000 # 2灏忔椂
media-url: https://ryc-1379367838.cos.ap-chengdu.myqcloud.com
# 寰俊灏忕▼搴忛厤缃�
diff --git a/backend/src/main/resources/graphql/player.graphqls b/backend/src/main/resources/graphql/player.graphqls
index 2d165f0..e686a1d 100644
--- a/backend/src/main/resources/graphql/player.graphqls
+++ b/backend/src/main/resources/graphql/player.graphqls
@@ -96,6 +96,7 @@
totalScore: Float
status: Int
remark: String
+ ratedAt: String
items: [CurrentJudgeRatingItemResponse!]!
}
@@ -105,6 +106,7 @@
ratingItemName: String!
score: Float
weightedScore: Float
+ maxScore: Float
}
type ProjectStageTimelineResponse {
diff --git a/clear-invalid-tokens.js b/clear-invalid-tokens.js
new file mode 100644
index 0000000..f445506
--- /dev/null
+++ b/clear-invalid-tokens.js
@@ -0,0 +1,86 @@
+// 娓呯悊鏃犳晥token鐨勮剼鏈�
+// 杩欎釜鑴氭湰闇�瑕佸湪灏忕▼搴忓紑鍙戣�呭伐鍏风殑鎺у埗鍙颁腑杩愯
+
+console.log('馃Ч 寮�濮嬫竻鐞嗘棤鏁堢殑JWT token...');
+
+// 妫�鏌ュ綋鍓嶅瓨鍌ㄧ殑token
+const currentToken = wx.getStorageSync('token');
+console.log('褰撳墠token:', currentToken ? `${currentToken.substring(0, 20)}...` : '鏃�');
+
+// 妫�鏌oken鏍煎紡鏄惁鏈夋晥
+function isValidJWTFormat(token) {
+ if (!token || typeof token !== 'string') {
+ return false;
+ }
+
+ // JWT搴旇鏈�3涓儴鍒嗭紝鐢�.鍒嗛殧
+ const parts = token.split('.');
+ if (parts.length !== 3) {
+ console.log('鉂� Token鏍煎紡鏃犳晥锛氫笉鏄�3涓儴鍒�');
+ return false;
+ }
+
+ // 妫�鏌ユ槸鍚﹀寘鍚祴璇曠敤鐨勬棤鏁堢鍚�
+ if (token.includes('invalid_token')) {
+ console.log('鉂� 妫�娴嬪埌娴嬭瘯鐢ㄧ殑鏃犳晥token');
+ return false;
+ }
+
+ try {
+ // 灏濊瘯瑙g爜header鍜宲ayload
+ const header = JSON.parse(atob(parts[0]));
+ const payload = JSON.parse(atob(parts[1]));
+
+ console.log('Token header:', header);
+ console.log('Token payload:', payload);
+
+ // 妫�鏌ユ槸鍚﹁繃鏈�
+ const now = Math.floor(Date.now() / 1000);
+ if (payload.exp && payload.exp < now) {
+ console.log('鉂� Token宸茶繃鏈�');
+ return false;
+ }
+
+ console.log('鉁� Token鏍煎紡鏈夋晥');
+ return true;
+ } catch (e) {
+ console.log('鉂� Token瑙g爜澶辫触:', e.message);
+ return false;
+ }
+}
+
+// 娓呯悊鏃犳晥token
+if (currentToken) {
+ if (!isValidJWTFormat(currentToken)) {
+ console.log('馃棏锔� 娓呯悊鏃犳晥token...');
+
+ // 娓呴櫎瀛樺偍鐨勮璇佷俊鎭�
+ wx.removeStorageSync('token');
+ wx.removeStorageSync('userInfo');
+ wx.removeStorageSync('sessionKey');
+
+ // 娓呴櫎globalData涓殑璁よ瘉淇℃伅
+ const app = getApp();
+ if (app) {
+ app.globalData.token = null;
+ app.globalData.userInfo = null;
+ app.globalData.sessionKey = null;
+ }
+
+ console.log('鉁� 鏃犳晥token宸叉竻鐞�');
+ console.log('馃挕 寤鸿閲嶆柊鍚姩灏忕▼搴忎互鑾峰彇鏂扮殑鏈夋晥token');
+ } else {
+ console.log('鉁� 褰撳墠token鏈夋晥锛屾棤闇�娓呯悊');
+ }
+} else {
+ console.log('鈩癸笍 褰撳墠娌℃湁瀛樺偍token');
+}
+
+console.log('馃帀 娓呯悊瀹屾垚锛�');
+
+// 浣跨敤璇存槑
+console.log('\n馃搵 浣跨敤璇存槑:');
+console.log('1. 鍦ㄥ皬绋嬪簭寮�鍙戣�呭伐鍏蜂腑鎵撳紑鎺у埗鍙�');
+console.log('2. 澶嶅埗骞剁矘璐磋繖娈典唬鐮�');
+console.log('3. 鎸夊洖杞︽墽琛�');
+console.log('4. 濡傛灉娓呯悊浜嗘棤鏁坱oken锛岃閲嶆柊鍚姩灏忕▼搴�');
\ No newline at end of file
diff --git a/wx/app.js b/wx/app.js
index 41ba5ea..57d5a4b 100644
--- a/wx/app.js
+++ b/wx/app.js
@@ -4,7 +4,7 @@
userInfo: null,
token: null,
sessionKey: null, // 寰俊浼氳瘽瀵嗛挜锛岀敤浜庤В瀵嗘墜鏈哄彿绛夋晱鎰熸暟鎹�
- baseUrl: 'http://localhost:8080/graphql', // 鍚庡彴GraphQL鎺ュ彛鍦板潃
+ baseUrl: 'http://localhost:8080/api/graphql', // 鍚庡彴GraphQL鎺ュ彛鍦板潃
hasPhoneAuth: false, // 鏄惁宸叉巿鏉冩墜鏈哄彿
rejectPhone: false, // 鏄惁鎷掔粷杩囨墜鏈哄彿鎺堟潈
cos: {
@@ -276,56 +276,174 @@
// GraphQL璇锋眰灏佽
graphqlRequest(query, variables = {}) {
return new Promise((resolve, reject) => {
- // 纭繚token鐨勪竴鑷存�э細浼樺厛浣跨敤globalData涓殑token锛屽鏋滄病鏈夊垯浠巗torage鑾峰彇
- let token = this.globalData.token
- if (!token) {
- token = wx.getStorageSync('token')
- if (token) {
- this.globalData.token = token // 鍚屾鍒癵lobalData
- }
- }
+ this._makeGraphQLRequest(query, variables, resolve, reject, false)
+ })
+ },
- wx.request({
- url: this.globalData.baseUrl,
- method: 'POST',
- header: {
- 'Content-Type': 'application/json',
- 'Authorization': token ? `Bearer ${token}` : ''
- },
- data: {
- query: query,
- variables: variables
- },
- success: (res) => {
- console.log('GraphQL鍝嶅簲:', res.data)
-
- // 妫�鏌TTP鐘舵�佺爜
- if (res.statusCode !== 200) {
+ // 鍐呴儴GraphQL璇锋眰鏂规硶锛屾敮鎸侀噸璇曟満鍒�
+ _makeGraphQLRequest(query, variables, resolve, reject, isRetry = false) {
+ // 纭繚token鐨勪竴鑷存�э細浼樺厛浣跨敤globalData涓殑token锛屽鏋滄病鏈夊垯浠巗torage鑾峰彇
+ let token = this.globalData.token
+ if (!token) {
+ token = wx.getStorageSync('token')
+ if (token) {
+ this.globalData.token = token // 鍚屾鍒癵lobalData
+ }
+ }
+
+ wx.request({
+ url: this.globalData.baseUrl,
+ method: 'POST',
+ header: {
+ 'Content-Type': 'application/json',
+ 'Authorization': token ? `Bearer ${token}` : ''
+ },
+ data: {
+ query: query,
+ variables: variables
+ },
+ success: (res) => {
+ console.log('GraphQL鍝嶅簲:', res.data)
+
+ // 妫�鏌TTP鐘舵�佺爜
+ if (res.statusCode !== 200) {
+ // 瀵逛簬401鐘舵�佺爜锛屽彲鑳芥槸璁よ瘉閿欒锛岄渶瑕佹鏌ュ搷搴斿唴瀹�
+ if (res.statusCode === 401 && res.data && res.data.errors) {
+ console.log('鏀跺埌401鐘舵�佺爜锛屾鏌ユ槸鍚︿负璁よ瘉閿欒')
+ // 缁х画澶勭悊锛岃涓嬮潰鐨凣raphQL閿欒妫�鏌ラ�昏緫澶勭悊璁よ瘉閿欒
+ } else {
console.error('GraphQL HTTP閿欒:', res.statusCode)
reject(new Error(`HTTP閿欒: ${res.statusCode}`))
return
}
+ }
- // 妫�鏌raphQL閿欒
- if (res.data.errors) {
- console.error('GraphQL閿欒:', res.data.errors)
- reject(new Error(res.data.errors[0]?.message || 'GraphQL璇锋眰閿欒'))
+ // 妫�鏌raphQL閿欒
+ if (res.data && res.data.errors) {
+ console.error('GraphQL閿欒:', res.data.errors)
+
+ // 妫�鏌ユ槸鍚︽槸璁よ瘉閿欒锛坱oken杩囨湡鎴栨棤鏁堬級
+ const authErrors = res.data.errors.filter(error =>
+ error.message && (
+ error.message.includes('娌℃湁鏉冮檺璁块棶') ||
+ error.message.includes('璇峰厛鐧诲綍') ||
+ error.message.includes('UNAUTHORIZED') ||
+ error.extensions?.code === 'UNAUTHORIZED'
+ )
+ )
+
+ if (authErrors.length > 0 && !isRetry) {
+ console.log('馃攧 妫�娴嬪埌璁よ瘉閿欒锛屽皾璇曢噸鏂扮櫥褰�...')
+ // 娓呴櫎杩囨湡鐨勮璇佷俊鎭�
+ this.globalData.token = null
+ this.globalData.userInfo = null
+ this.globalData.sessionKey = null
+ wx.removeStorageSync('token')
+ wx.removeStorageSync('userInfo')
+ wx.removeStorageSync('sessionKey')
+
+ // 閲嶆柊鐧诲綍
+ wx.login({
+ success: (loginRes) => {
+ if (loginRes.code) {
+ console.log('馃攧 閲嶆柊鑾峰彇寰俊code鎴愬姛锛岃皟鐢ㄥ悗绔櫥褰�...')
+ this._retryAfterLogin(loginRes.code, query, variables, resolve, reject)
+ } else {
+ console.error('鉂� 閲嶆柊鑾峰彇寰俊code澶辫触')
+ reject(new Error('閲嶆柊鐧诲綍澶辫触'))
+ }
+ },
+ fail: (err) => {
+ console.error('鉂� 閲嶆柊鐧诲綍澶辫触:', err)
+ reject(new Error('閲嶆柊鐧诲綍澶辫触'))
+ }
+ })
return
}
-
- // 妫�鏌ユ暟鎹�
- if (res.data.data !== undefined) {
- resolve(res.data.data)
- } else {
- console.error('GraphQL鍝嶅簲寮傚父:', res.data)
- reject(new Error('GraphQL鍝嶅簲鏁版嵁寮傚父'))
- }
- },
- fail: (err) => {
- console.error('GraphQL缃戠粶璇锋眰澶辫触:', err)
- reject(new Error('缃戠粶璇锋眰澶辫触'))
+
+ reject(new Error(res.data.errors[0]?.message || 'GraphQL璇锋眰閿欒'))
+ return
}
- })
+
+ // 妫�鏌ユ暟鎹�
+ if (res.data.data !== undefined) {
+ resolve(res.data.data)
+ } else {
+ console.error('GraphQL鍝嶅簲寮傚父:', res.data)
+ reject(new Error('GraphQL鍝嶅簲鏁版嵁寮傚父'))
+ }
+ },
+ fail: (err) => {
+ console.error('GraphQL缃戠粶璇锋眰澶辫触:', err)
+ reject(new Error('缃戠粶璇锋眰澶辫触'))
+ }
+ })
+ },
+
+ // 閲嶆柊鐧诲綍鍚庨噸璇旼raphQL璇锋眰
+ _retryAfterLogin(code, query, variables, resolve, reject) {
+ const that = this
+ const deviceInfo = this.getDeviceInfo()
+ const requestData = {
+ code: code,
+ loginIp: '127.0.0.1', // 灏忕▼搴忔棤娉曡幏鍙栫湡瀹濱P锛屼娇鐢ㄩ粯璁ゅ��
+ deviceInfo: deviceInfo
+ }
+
+ wx.request({
+ url: 'http://localhost:8080/api/auth/wx-login',
+ method: 'POST',
+ header: {
+ 'Content-Type': 'application/json'
+ },
+ data: requestData,
+ success: (res) => {
+ console.log('馃攧 閲嶆柊鐧诲綍鍝嶅簲:', res.data)
+
+ if (res.statusCode !== 200 || res.data.error) {
+ console.error('鉂� 閲嶆柊鐧诲綍澶辫触:', res.data.error || res.data.message)
+ reject(new Error('閲嶆柊鐧诲綍澶辫触'))
+ return
+ }
+
+ // 妫�鏌ュ搷搴旀暟鎹牸寮�
+ let loginResult = null
+ if (res.data.token && res.data.userInfo) {
+ loginResult = res.data
+ } else if (res.data.success && res.data.data) {
+ loginResult = res.data.data
+ }
+
+ if (loginResult && loginResult.token) {
+ console.log('鉁� 閲嶆柊鐧诲綍鎴愬姛锛屾洿鏂皌oken')
+
+ // 淇濆瓨鏂扮殑鐧诲綍淇℃伅
+ try {
+ wx.setStorageSync('token', loginResult.token)
+ wx.setStorageSync('userInfo', loginResult.userInfo)
+ if (loginResult.sessionKey) {
+ wx.setStorageSync('sessionKey', loginResult.sessionKey)
+ }
+ } catch (storageErr) {
+ console.error('鉂� 淇濆瓨閲嶆柊鐧诲綍淇℃伅澶辫触:', storageErr)
+ }
+
+ that.globalData.token = loginResult.token
+ that.globalData.userInfo = loginResult.userInfo
+ that.globalData.sessionKey = loginResult.sessionKey
+
+ // 浣跨敤鏂皌oken閲嶈瘯鍘熷璇锋眰
+ console.log('馃攧 浣跨敤鏂皌oken閲嶈瘯GraphQL璇锋眰...')
+ that._makeGraphQLRequest(query, variables, resolve, reject, true)
+ } else {
+ console.error('鉂� 閲嶆柊鐧诲綍鍝嶅簲鏍煎紡閿欒')
+ reject(new Error('閲嶆柊鐧诲綍鍝嶅簲鏍煎紡閿欒'))
+ }
+ },
+ fail: (err) => {
+ console.error('鉂� 閲嶆柊鐧诲綍缃戠粶璇锋眰澶辫触:', err)
+ reject(new Error('閲嶆柊鐧诲綍缃戠粶璇锋眰澶辫触'))
+ }
})
}
})
\ No newline at end of file
diff --git a/wx/pages/judge/review.js b/wx/pages/judge/review.js
index 27afd37..e317235 100644
--- a/wx/pages/judge/review.js
+++ b/wx/pages/judge/review.js
@@ -1,6 +1,6 @@
// pages/judge/review.js
const app = getApp()
-const { graphqlRequest, formatDate } = require('../../lib/utils')
+const { graphqlRequest, formatDate: formatDateUtil } = require('../../lib/utils')
Page({
data: {
@@ -10,13 +10,15 @@
// 鎻愪氦浣滃搧淇℃伅
submission: null,
activityPlayerId: '',
-
+ stageId: null,
+ submissionId: null,
+
// 娲诲姩淇℃伅
activity: null,
-
+
// 璇勫鏍囧噯
criteria: [],
-
+
// 璇勫垎鏁版嵁
scores: {},
@@ -31,24 +33,7 @@
reviewStatus: 'PENDING', // PENDING, COMPLETED
// 宸叉湁璇勫璁板綍
- existingReview: null,
-
- // 濯掍綋棰勮
- showMediaPreview: false,
- currentMedia: null,
- mediaType: 'image',
-
- // 鏂囦欢涓嬭浇
- downloadingFiles: [],
-
- // 璇勫垎绛夌骇
- scoreOptions: [
- { value: 1, label: '1鍒� - 寰堝樊' },
- { value: 2, label: '2鍒� - 杈冨樊' },
- { value: 3, label: '3鍒� - 涓�鑸�' },
- { value: 4, label: '4鍒� - 鑹ソ' },
- { value: 5, label: '5鍒� - 浼樼' }
- ]
+ existingReview: null
},
onLoad(options) {
@@ -62,6 +47,32 @@
// 椤甸潰鏄剧ず鏃舵鏌ヨ瘎瀹$姸鎬�
if (this.data.submissionId) {
this.checkReviewStatus()
+ }
+ },
+
+ transformMediaFile(file) {
+ const url = file.fullUrl || file.url
+ const thumbUrl = file.fullThumbUrl || url
+ const ext = (file.fileExt || '').toLowerCase()
+ let mediaType = 'file'
+
+ if (file.mediaType === 1 || ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic'].includes(ext)) {
+ mediaType = 'image'
+ } else if (file.mediaType === 2 || ['mp4', 'mov', 'avi', 'wmv', 'mkv', 'webm', 'flv'].includes(ext)) {
+ mediaType = 'video'
+ } else if (ext === 'pdf') {
+ mediaType = 'pdf'
+ } else if (['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'wps', 'txt', 'rtf'].includes(ext)) {
+ mediaType = 'word'
+ }
+
+ return {
+ id: file.id,
+ name: file.name,
+ url,
+ thumbUrl,
+ mediaType,
+ size: file.fileSize || 0
}
},
@@ -102,13 +113,11 @@
submissionFiles {
id
name
- url
fullUrl
+ fullThumbUrl
fileExt
fileSize
mediaType
- thumbUrl
- fullThumbUrl
}
ratingForm {
schemeId
@@ -117,10 +126,8 @@
items {
id
name
- description
maxScore
- weight
- sortOrder
+ orderNo
}
}
}
@@ -137,62 +144,64 @@
id: detail.id,
title: detail.projectName,
description: detail.description,
- files: detail.submissionFiles ? detail.submissionFiles.map(file => ({
- id: file.id,
- name: file.name,
- url: file.fullUrl || file.url,
- type: file.fileExt,
- size: file.fileSize,
- isDownloading: this.data.downloadingFiles.indexOf(file.id) > -1
- })) : [],
- images: detail.submissionFiles ? detail.submissionFiles
- .filter(file => file.mediaType === 1)
- .map(file => file.fullUrl || file.url) : [],
- videos: detail.submissionFiles ? detail.submissionFiles
- .filter(file => file.mediaType === 2)
- .map(file => file.fullUrl || file.url) : [],
+ submittedAt: detail.submitTime || null,
+ team: detail.team || null,
participant: {
- id: detail.playerInfo.id,
- name: detail.playerInfo.name,
+ id: detail.playerInfo?.id,
+ name: detail.playerInfo?.name,
+ phone: detail.playerInfo?.phone || detail.playerInfo?.userInfo?.phone || '',
+ avatar: detail.playerInfo?.userInfo?.avatarUrl || '/images/default-avatar.svg',
+ gender: this.getGenderLabel(detail.playerInfo?.gender),
+ birthday: this.getBirthdayText(detail.playerInfo?.birthday),
+ region: detail.regionInfo?.fullPath || detail.regionInfo?.name || '',
+ education: detail.playerInfo?.education || '',
school: detail.regionInfo ? detail.regionInfo.name : '',
- major: detail.playerInfo.education || '',
- avatar: detail.playerInfo.userInfo?.avatarUrl || '/images/default-avatar.svg'
+ major: detail.playerInfo?.education || ''
},
- status: detail.state === 1 ? 'APPROVED' : detail.state === 2 ? 'REJECTED' : 'PENDING'
+ status: detail.state === 1 ? 'APPROVED' : detail.state === 2 ? 'REJECTED' : 'PENDING',
+ mediaList: (detail.submissionFiles || []).map(file => this.transformMediaFile(file))
}
-
- // 鏋勫缓activity瀵硅薄
- const activity = {
- id: detail.stageId,
- title: detail.activityName,
- description: detail.description,
- judgeCriteria: detail.ratingForm ? detail.ratingForm.items || [] : []
- }
-
- // 鍒濆鍖栬瘎鍒嗘暟鎹�
+
+ const criteria = (detail.ratingForm?.items || []).map(item => {
+ const maxScore = item.maxScore || 0
+ return {
+ id: item.id,
+ name: item.name,
+ maxScore,
+ description: item.description || '鏆傛棤鎻忚堪',
+ step: maxScore > 20 ? 1 : 0.5,
+ currentScore: 0
+ }
+ })
+
const scores = {}
- let maxScore = 0
-
- if (activity.judgeCriteria) {
- activity.judgeCriteria.forEach(criterion => {
- scores[criterion.id] = 0 // 鏆傛椂璁句负0锛屽悗缁渶瑕佹煡璇㈠凡鏈夎瘎鍒�
- maxScore += criterion.maxScore
- })
- }
-
+ criteria.forEach(criterion => {
+ scores[criterion.id] = 0
+ })
+
+ const maxScore = detail.ratingForm?.totalMaxScore || criteria.reduce((sum, item) => sum + (item.maxScore || 0), 0)
+
this.setData({
submission,
- activity,
- criteria: activity.judgeCriteria || [],
+ activity: {
+ id: detail.id,
+ stageId: detail.stageId,
+ ratingSchemeId: detail.ratingForm?.schemeId || null,
+ totalMaxScore: maxScore
+ },
+ stageId: detail.stageId || null,
+ submissionId: detail.id,
+ criteria,
scores,
maxScore,
- existingReview: null, // 鏆傛椂璁句负null锛屽悗缁渶瑕佹煡璇㈠凡鏈夎瘎鍒�
+ totalScore: 0,
+ existingReview: null,
reviewStatus: 'PENDING',
comment: ''
})
-
+
this.calculateTotalScore()
-
+
// 妫�鏌ユ槸鍚﹀凡鏈夎瘎鍒�
this.checkReviewStatus()
}
@@ -215,7 +224,7 @@
currentJudgeRating(activityPlayerId: $activityPlayerId) {
id
totalScore
- comment
+ remark
status
ratedAt
items {
@@ -239,38 +248,98 @@
if (rating.items) {
rating.items.forEach(item => {
- scores[item.ratingItemId] = item.score
- totalScore += item.score
+ const numericScore = item.score !== undefined && item.score !== null ? Number(item.score) : 0
+ scores[item.ratingItemId] = numericScore
+ totalScore += numericScore
})
}
-
+
+ const updatedCriteria = this.data.criteria.map(criterion => {
+ const value = scores[criterion.id] !== undefined ? scores[criterion.id] : 0
+ return {
+ ...criterion,
+ currentScore: value
+ }
+ })
+
+ const normalizedTotal = Number(totalScore.toFixed(2))
+
this.setData({
scores,
- totalScore,
- comment: rating.comment || '',
- existingReview: rating,
- reviewStatus: rating.status || 'COMPLETED'
+ criteria: updatedCriteria,
+ totalScore: normalizedTotal,
+ comment: rating.remark || rating.comment || '',
+ existingReview: {
+ ...rating,
+ totalScore: rating.totalScore ? Number(rating.totalScore) : normalizedTotal,
+ reviewedAt: rating.ratedAt || rating.reviewedAt || rating.updateTime || null
+ },
+ reviewStatus: 'COMPLETED'
})
console.log('宸插姞杞界幇鏈夎瘎鍒�:', rating)
} else {
console.log('褰撳墠璇勫灏氭湭璇勫垎')
}
+
+ this.calculateTotalScore()
} catch (error) {
console.error('妫�鏌ヨ瘎瀹$姸鎬佸け璐�:', error)
}
},
+ normalizeScore(value, criterion) {
+ const maxScore = Number(criterion.maxScore || 0)
+ const step = Number(criterion.step || (maxScore > 20 ? 1 : 0.5))
+ if (Number.isNaN(value)) {
+ value = 0
+ }
+ let normalized = Math.round(value / step) * step
+ if (normalized < 0) normalized = 0
+ if (normalized > maxScore) normalized = maxScore
+ return Number(normalized.toFixed(2))
+ },
+
+ updateCriterionScore(criterionId, index, value) {
+ const criterion = this.data.criteria[index]
+ if (!criterion) return
+ const normalized = this.normalizeScore(value, criterion)
+
+ this.setData({
+ [`scores.${criterionId}`]: normalized,
+ [`criteria[${index}].currentScore`]: normalized
+ })
+
+ this.calculateTotalScore()
+ },
+
// 璇勫垎鏀瑰彉
onScoreChange(e) {
- const { criterionId } = e.currentTarget.dataset
- const { value } = e.detail
-
- this.setData({
- [`scores.${criterionId}`]: parseInt(value)
- })
-
- this.calculateTotalScore()
+ const { criterionId, index } = e.currentTarget.dataset
+ const criterion = this.data.criteria[index]
+ if (!criterion) return
+
+ const inputValue = Number(e.detail.value)
+ const newScore = this.normalizeScore(inputValue, criterion)
+ this.updateCriterionScore(criterionId, index, newScore)
+ },
+
+ increaseScore(e) {
+ const { criterionId, index } = e.currentTarget.dataset
+ const criterion = this.data.criteria[index]
+ if (!criterion) return
+ const current = Number(this.data.scores[criterionId] || criterion.currentScore || 0)
+ const step = criterion.step || (criterion.maxScore > 20 ? 1 : 0.5)
+ this.updateCriterionScore(criterionId, index, current + step)
+ },
+
+ decreaseScore(e) {
+ const { criterionId, index } = e.currentTarget.dataset
+ const criterion = this.data.criteria[index]
+ if (!criterion) return
+ const current = Number(this.data.scores[criterionId] || criterion.currentScore || 0)
+ const step = criterion.step || (criterion.maxScore > 20 ? 1 : 0.5)
+ this.updateCriterionScore(criterionId, index, current - step)
},
// 璁$畻鎬诲垎
@@ -279,11 +348,11 @@
let totalScore = 0
criteria.forEach(criterion => {
- const score = scores[criterion.id] || 0
- totalScore += score * (criterion.weight || 1)
+ const score = Number(scores[criterion.id] || 0)
+ totalScore += score
})
- this.setData({ totalScore })
+ this.setData({ totalScore: Number(totalScore.toFixed(2)) })
},
// 璇勫鎰忚杈撳叆
@@ -295,106 +364,58 @@
// 濯掍綋鐐瑰嚮
onMediaTap(e) {
- const { url, type } = e.currentTarget.dataset
-
- if (type === 'image') {
+ const index = Number(e.currentTarget.dataset.index)
+ const mediaList = this.data.submission?.mediaList || []
+ const media = mediaList[index]
+ if (!media) return
+
+ if (media.mediaType === 'image') {
+ const imageUrls = mediaList
+ .filter(item => item.mediaType === 'image')
+ .map(item => item.url)
wx.previewImage({
- current: url,
- urls: this.data.submission.images || []
+ current: media.url,
+ urls: imageUrls
})
- } else if (type === 'video') {
- this.setData({
- showMediaPreview: true,
- currentMedia: url,
- mediaType: 'video'
+ } else if (media.mediaType === 'video') {
+ wx.navigateTo({
+ url: `/pages/video/video?url=${encodeURIComponent(media.url)}&title=${encodeURIComponent(media.name)}`
})
+ } else {
+ this.openDocumentMedia(media)
}
},
- // 鍏抽棴濯掍綋棰勮
- onCloseMediaPreview() {
- this.setData({
- showMediaPreview: false,
- currentMedia: null
- })
- },
-
- // 涓嬭浇鏂囦欢
- async onDownloadFile(e) {
- const { fileId, fileName, fileUrl } = e.currentTarget.dataset
-
+ async openDocumentMedia(media) {
try {
- // 娣诲姞鍒颁笅杞戒腑鍒楄〃
- const downloadingFiles = [...this.data.downloadingFiles, fileId]
-
- // 鍚屾椂鏇存柊鏂囦欢鐨刬sDownloading瀛楁
- const submission = { ...this.data.submission }
- if (submission.files) {
- submission.files = submission.files.map(file => ({
- ...file,
- isDownloading: file.id === fileId ? true : file.isDownloading
- }))
- }
-
- this.setData({
- downloadingFiles,
- submission
+ wx.showLoading({ title: '鎵撳紑涓�...' })
+ const downloadRes = await new Promise((resolve, reject) => {
+ wx.downloadFile({
+ url: media.url,
+ success: resolve,
+ fail: reject
+ })
})
-
- wx.showLoading({ title: '涓嬭浇涓�...' })
-
- const result = await wx.downloadFile({
- url: fileUrl,
- success: (res) => {
- if (res.statusCode === 200) {
- // 淇濆瓨鍒扮浉鍐屾垨鏂囦欢
- wx.saveFile({
- tempFilePath: res.tempFilePath,
- success: () => {
- wx.showToast({
- title: '涓嬭浇鎴愬姛',
- icon: 'success'
- })
- },
- fail: () => {
- wx.showToast({
- title: '淇濆瓨澶辫触',
- icon: 'error'
- })
- }
- })
- }
- },
- fail: () => {
- wx.showToast({
- title: '涓嬭浇澶辫触',
- icon: 'error'
- })
- }
+
+ if (downloadRes.statusCode !== 200) {
+ throw new Error('鏂囦欢涓嬭浇澶辫触')
+ }
+
+ await new Promise((resolve, reject) => {
+ wx.openDocument({
+ filePath: downloadRes.tempFilePath,
+ showMenu: true,
+ success: resolve,
+ fail: reject
+ })
})
} catch (error) {
- console.error('涓嬭浇鏂囦欢澶辫触:', error)
+ console.error('鎵撳紑鏂囦欢澶辫触:', error)
wx.showToast({
- title: '涓嬭浇澶辫触',
+ title: '鏃犳硶鎵撳紑鏂囦欢',
icon: 'error'
})
} finally {
- // 浠庝笅杞戒腑鍒楄〃绉婚櫎
- const downloadingFiles = this.data.downloadingFiles.filter(id => id !== fileId)
-
- // 鍚屾椂鏇存柊鏂囦欢鐨刬sDownloading瀛楁
- const submission = { ...this.data.submission }
- if (submission.files) {
- submission.files = submission.files.map(file => ({
- ...file,
- isDownloading: file.id === fileId ? false : file.isDownloading
- }))
- }
-
- this.setData({
- downloadingFiles,
- submission
- })
wx.hideLoading()
}
},
@@ -402,6 +423,7 @@
// 楠岃瘉璇勫鏁版嵁
validateReview() {
const { scores, criteria, comment } = this.data
+ const commentText = (comment || '').trim()
// 妫�鏌ユ槸鍚︽墍鏈夋爣鍑嗛兘宸茶瘎鍒�
for (let criterion of criteria) {
@@ -415,7 +437,7 @@
}
// 妫�鏌ヨ瘎瀹℃剰瑙�
- if (!comment.trim()) {
+ if (!commentText) {
wx.showToast({
title: '璇峰~鍐欒瘎瀹℃剰瑙�',
icon: 'error'
@@ -423,7 +445,7 @@
return false
}
- if (comment.trim().length < 10) {
+ if (commentText.length < 10) {
wx.showToast({
title: '璇勫鎰忚鑷冲皯10涓瓧绗�',
icon: 'error'
@@ -432,54 +454,6 @@
}
return true
- },
-
- // 淇濆瓨鑽夌
- async onSaveDraft() {
- try {
- wx.showLoading({ title: '淇濆瓨涓�...' })
-
- const { activityPlayerId, scores, comment, criteria, activity } = this.data
-
- // 鏋勫缓璇勫垎椤规暟缁�
- const ratings = criteria.map(criterion => ({
- itemId: criterion.id,
- score: scores[criterion.id] || 0
- }))
-
- const mutation = `
- mutation SaveActivityPlayerRating($input: ActivityPlayerRatingInput!) {
- saveActivityPlayerRating(input: $input)
- }
- `
-
- const input = {
- activityPlayerId,
- stageId: activity.stageId,
- ratings,
- comment: comment.trim()
- }
-
- const result = await graphqlRequest(mutation, { input })
-
- if (result && result.saveActivityPlayerRating) {
- wx.showToast({
- title: '鑽夌宸蹭繚瀛�',
- icon: 'success'
- })
-
- // 閲嶆柊鍔犺浇璇勫垎鐘舵��
- await this.checkReviewStatus()
- }
- } catch (error) {
- console.error('淇濆瓨鑽夌澶辫触:', error)
- wx.showToast({
- title: '淇濆瓨澶辫触',
- icon: 'error'
- })
- } finally {
- wx.hideLoading()
- }
},
// 鎻愪氦璇勫
@@ -505,12 +479,23 @@
this.setData({ submitting: true })
wx.showLoading({ title: '鎻愪氦涓�...' })
- const { activityPlayerId, scores, comment, criteria, activity } = this.data
+ const { activityPlayerId, scores, comment, criteria, stageId } = this.data
+ const commentText = (comment || '').trim()
+
+ if (!stageId) {
+ wx.showToast({
+ title: '缂哄皯闃舵淇℃伅锛屾棤娉曟彁浜�',
+ icon: 'none'
+ })
+ this.setData({ submitting: false })
+ wx.hideLoading()
+ return
+ }
// 鏋勫缓璇勫垎椤规暟缁�
const ratings = criteria.map(criterion => ({
itemId: criterion.id,
- score: scores[criterion.id] || 0
+ score: Number(scores[criterion.id] || 0)
}))
const mutation = `
@@ -521,9 +506,9 @@
const input = {
activityPlayerId,
- stageId: activity.stageId,
+ stageId,
ratings,
- comment: comment.trim()
+ comment: commentText
}
const result = await graphqlRequest(mutation, { input })
@@ -569,34 +554,17 @@
// 鑱旂郴鍙傝禌鑰�
onContactParticipant() {
const { submission } = this.data
-
- if (submission.participant) {
- wx.showActionSheet({
- itemList: ['鍙戦�佹秷鎭�', '鏌ョ湅璇︽儏'],
- success: (res) => {
- switch (res.tapIndex) {
- case 0:
- // 鍙戦�佹秷鎭姛鑳�
- wx.navigateTo({
- url: `/pages/chat/chat?userId=${submission.participant.id}`
- })
- break
- case 1:
- // 鏌ョ湅鐢ㄦ埛璇︽儏
- wx.navigateTo({
- url: `/pages/user/profile?userId=${submission.participant.id}`
- })
- break
- }
- }
+ const phone = submission?.participant?.phone
+ if (phone) {
+ wx.makePhoneCall({
+ phoneNumber: phone
+ })
+ } else {
+ wx.showToast({
+ title: '鏆傛棤鑱旂郴鏂瑰紡',
+ icon: 'none'
})
}
- },
-
- // 鑾峰彇璇勫垎绛夌骇鏂囨湰
- getScoreLabel(score) {
- const option = this.data.scoreOptions.find(opt => opt.value === score)
- return option ? option.label : `${score}鍒哷
},
// 鑾峰彇鏂囦欢澶у皬鏂囨湰
@@ -610,9 +578,47 @@
}
},
+ // 缁熶竴澶勭悊鎬у埆鏄剧ず鏂囨湰
+ getGenderLabel(gender) {
+ if (gender === null || gender === undefined || gender === '') {
+ return '鏈~鍐�'
+ }
+
+ const normalized = String(gender).trim().toLowerCase()
+
+ if (normalized === '') {
+ return '鏈~鍐�'
+ }
+
+ if (normalized === 'male' || normalized === 'm') {
+ return '鐢�'
+ }
+ if (normalized === 'female' || normalized === 'f') {
+ return '濂�'
+ }
+
+ if (/^-?\d+$/.test(normalized)) {
+ const numeric = Number(normalized)
+ if (numeric === 1) return '鐢�'
+ if (numeric === 0) return '濂�'
+ if (numeric === 2) return '濂�'
+ }
+
+ return gender === undefined || gender === null ? '鏈~鍐�' : String(gender)
+ },
+
+ // 缁熶竴澶勭悊鍑虹敓鏃ユ湡鏄剧ず鏂囨湰
+ getBirthdayText(dateString) {
+ if (!dateString) {
+ return '鏈~鍐�'
+ }
+ const formatted = formatDateUtil(dateString, 'YYYY-MM-DD')
+ return formatted || '鏈~鍐�'
+ },
+
// 鏍煎紡鍖栨棩鏈�
formatDate(dateString) {
- return formatDate(dateString, 'YYYY-MM-DD HH:mm')
+ return formatDateUtil(dateString, 'YYYY-MM-DD HH:mm')
},
// 鍒嗕韩椤甸潰
@@ -622,4 +628,4 @@
path: '/pages/index/index'
}
}
-})
\ No newline at end of file
+})
diff --git a/wx/pages/judge/review.wxml b/wx/pages/judge/review.wxml
index 1ed466d..fd5c086 100644
--- a/wx/pages/judge/review.wxml
+++ b/wx/pages/judge/review.wxml
@@ -16,32 +16,33 @@
{{reviewStatus === 'COMPLETED' ? '宸茶瘎瀹�' : '寰呰瘎瀹�'}}
</view>
</view>
-
+
<view class="submission-detail">
<text class="submission-title">{{submission.title}}</text>
- <text class="submission-desc">{{submission.description}}</text>
-
+ <text class="submission-desc">{{submission.description || '鏆傛棤椤圭洰鎻忚堪'}}</text>
+
<!-- 鍙傝禌鑰呬俊鎭� -->
<view class="participant-info">
<view class="participant-header">
<text class="participant-label">鍙傝禌鑰咃細</text>
<view class="contact-btn" bindtap="onContactParticipant">
- <text class="contact-icon">馃挰</text>
- <text class="contact-text">鑱旂郴</text>
+ <text class="contact-icon">馃摓</text>
+ <text class="contact-text">鎷ㄦ墦鐢佃瘽</text>
</view>
</view>
-
+
<view class="participant-detail">
<image class="participant-avatar" src="{{submission.participant.avatar}}" mode="aspectFill"></image>
<view class="participant-text">
- <text class="participant-name">{{submission.participant.name}}</text>
- <text class="participant-school">{{submission.participant.school}} - {{submission.participant.major}}</text>
+ <text class="participant-name">{{submission.participant.name || '鍖垮悕'}}</text>
+ <text class="participant-meta">鎬у埆锛歿{submission.participant.gender || '鏈~鍐�'}}锛屽嚭鐢熸棩鏈燂細{{submission.participant.birthday || '鏈~鍐�'}}</text>
+ <text class="participant-field">鎵�灞炲尯鍩燂細{{submission.participant.region || '鏈~鍐�'}}</text>
+ <text class="participant-field">瀛﹀巻锛歿{submission.participant.education || '鏈~鍐�'}}</text>
</view>
</view>
-
- <!-- 鍥㈤槦淇℃伅 -->
- <view wx:if="{{submission.team}}" class="team-info">
- <text class="team-label">鍥㈤槦锛歿{submission.team.name}}</text>
+
+ <view wx:if="{{submission.team && submission.team.members}}" class="team-info">
+ <text class="team-label">鍥㈤槦锛歿{submission.team.name || '鏈懡鍚嶅洟闃�'}}</text>
<view class="team-members">
<view wx:for="{{submission.team.members}}" wx:key="id" class="team-member">
<text class="member-name">{{item.name}}</text>
@@ -50,74 +51,36 @@
</view>
</view>
</view>
-
- <text class="submit-time">鎻愪氦鏃堕棿锛歿{formatDate(submission.submittedAt)}}</text>
+
</view>
</view>
- <!-- 浣滃搧濯掍綋 -->
- <view wx:if="{{submission.images.length > 0 || submission.videos.length > 0}}" class="media-section">
- <text class="section-title">浣滃搧灞曠ず</text>
-
- <!-- 鍥剧墖 -->
- <view wx:if="{{submission.images.length > 0}}" class="media-grid">
- <view
- wx:for="{{submission.images}}"
- wx:key="*this"
- class="media-item image-item"
- data-url="{{item}}"
- data-type="image"
- bindtap="onMediaTap"
- >
- <image class="media-image" src="{{item}}" mode="aspectFill"></image>
- </view>
- </view>
-
- <!-- 瑙嗛 -->
- <view wx:if="{{submission.videos.length > 0}}" class="media-grid">
- <view
- wx:for="{{submission.videos}}"
- wx:key="*this"
- class="media-item video-item"
- data-url="{{item}}"
- data-type="video"
- bindtap="onMediaTap"
- >
- <video class="media-video" src="{{item}}" poster="{{item}}" controls></video>
- <view class="play-overlay">
- <text class="play-icon">鈻�</text>
- </view>
- </view>
- </view>
- </view>
-
- <!-- 浣滃搧鏂囦欢 -->
- <view wx:if="{{submission.files.length > 0}}" class="files-section">
- <text class="section-title">浣滃搧鏂囦欢</text>
-
- <view class="file-list">
- <view
- wx:for="{{submission.files}}"
+ <!-- 浣滃搧绱犳潗 -->
+ <view wx:if="{{submission.mediaList && submission.mediaList.length > 0}}" class="media-section">
+ <text class="section-title">鍙傝禌浣滃搧</text>
+ <view class="media-list">
+ <view
+ wx:for="{{submission.mediaList}}"
wx:key="id"
- class="file-item"
+ class="media-item"
+ bindtap="onMediaTap"
+ data-index="{{index}}"
>
- <view class="file-info">
- <text class="file-icon">馃搫</text>
- <view class="file-detail">
- <text class="file-name">{{item.name}}</text>
- <text class="file-size">{{getFileSizeText(item.size)}}</text>
- </view>
+ <view class="media-thumb-wrapper">
+ <image
+ wx:if="{{item.mediaType === 'image' || item.mediaType === 'video'}}"
+ class="media-thumb"
+ src="{{item.thumbUrl}}"
+ mode="aspectFill"
+ />
+ <view wx:elif="{{item.mediaType === 'pdf'}}" class="media-icon pdf">PDF</view>
+ <view wx:elif="{{item.mediaType === 'word'}}" class="media-icon doc">DOC</view>
+ <view wx:else class="media-icon file">FILE</view>
+ <view wx:if="{{item.mediaType === 'video'}}" class="media-play">鈻�</view>
</view>
-
- <view
- class="download-btn {{item.isDownloading ? 'downloading' : ''}}"
- data-file-id="{{item.id}}"
- data-file-name="{{item.name}}"
- data-file-url="{{item.url}}"
- bindtap="onDownloadFile"
- >
- <text class="download-icon">{{item.isDownloading ? '鈴�' : '猬�'}}</text>
- <text class="download-text">{{item.isDownloading ? '涓嬭浇涓�' : '涓嬭浇'}}</text>
+ <view class="media-info">
+ <text class="media-name">{{item.name}}</text>
+ <text class="media-size">{{getFileSizeText(item.size)}}</text>
</view>
</view>
</view>
@@ -126,84 +89,70 @@
<!-- 璇勫鏍囧噯 -->
<view class="criteria-section">
<text class="section-title">璇勫鏍囧噯</text>
-
+
<view class="criteria-list">
<view wx:for="{{criteria}}" wx:key="id" class="criterion-item">
<view class="criterion-header">
<text class="criterion-name">{{item.name}}</text>
- <text class="criterion-score">{{scores[item.id] || 0}}/{{item.maxScore}}鍒�</text>
+ <text class="criterion-score">{{scores[item.id] || 0}} / {{item.maxScore}} 鍒�</text>
</view>
-
- <text class="criterion-desc">{{item.description}}</text>
-
- <!-- 璇勫垎閫夋嫨鍣� -->
- <view class="score-selector">
- <picker
- range="{{scoreOptions}}"
- range-key="label"
- value="{{(scores[item.id] || 1) - 1}}"
+
+ <text class="criterion-desc">{{item.description || '鏆傛棤璇勫垎璇存槑'}}</text>
+
+ <view class="score-control">
+ <view class="score-btn" data-criterion-id="{{item.id}}" data-index="{{index}}" bindtap="decreaseScore">-</view>
+ <input
+ class="score-input"
+ type="digit"
+ value="{{scores[item.id] || 0}}"
data-criterion-id="{{item.id}}"
- bindchange="onScoreChange"
- disabled="{{reviewStatus === 'COMPLETED'}}"
- >
- <view class="score-picker {{reviewStatus === 'COMPLETED' ? 'disabled' : ''}}">
- <text class="score-text">{{getScoreLabel(scores[item.id] || 0)}}</text>
- <text class="picker-arrow">{{reviewStatus === 'COMPLETED' ? '' : '鈻�'}}</text>
- </view>
- </picker>
+ data-index="{{index}}"
+ bindinput="onScoreChange"
+ placeholder="0"
+ />
+ <view class="score-btn" data-criterion-id="{{item.id}}" data-index="{{index}}" bindtap="increaseScore">+</view>
</view>
</view>
</view>
-
- <!-- 鎬诲垎鏄剧ず -->
+
<view class="total-score">
<text class="total-label">鎬诲垎锛�</text>
- <text class="total-value">{{totalScore}}/{{maxScore}}鍒�</text>
+ <text class="total-value">{{totalScore}} / {{maxScore}} 鍒�</text>
</view>
</view>
<!-- 璇勫鎰忚 -->
<view class="comment-section">
<text class="section-title">璇勫鎰忚</text>
-
- <textarea
- class="comment-input {{reviewStatus === 'COMPLETED' ? 'disabled' : ''}}"
- placeholder="璇峰~鍐欒缁嗙殑璇勫鎰忚锛屽寘鎷綔鍝佺殑浼樼偣銆佷笉瓒冲拰鏀硅繘寤鸿..."
+ <textarea
+ class="comment-input"
+ placeholder="璇峰~鍐欒缁嗚瘎瀹℃剰瑙侊紝鍖呮嫭浣滃搧浼樼偣銆佷笉瓒冲拰鏀硅繘寤鸿..."
value="{{comment}}"
maxlength="1000"
show-confirm-bar="{{false}}"
- disabled="{{reviewStatus === 'COMPLETED'}}"
bindinput="onCommentInput"
></textarea>
-
<view class="comment-counter">
- <text class="counter-text">{{comment.length}}/1000</text>
+ <text class="counter-text">{{comment.length}} / 1000</text>
</view>
</view>
- <!-- 宸叉湁璇勫璁板綍 -->
+ <!-- 鏃㈡湁璇勫 -->
<view wx:if="{{existingReview}}" class="existing-review">
- <text class="section-title">璇勫璁板綍</text>
-
+ <text class="section-title">鍘嗗彶璇勫</text>
<view class="review-info">
- <text class="review-time">璇勫鏃堕棿锛歿{formatDate(existingReview.reviewedAt)}}</text>
- <text class="review-total">鎬诲垎锛歿{existingReview.totalScore}}/{{maxScore}}鍒�</text>
+ <text class="review-time">璇勫鏃堕棿锛歿{formatDate(existingReview.reviewedAt) || '鏈煡'}}</text>
+ <text class="review-total">鎬诲垎锛歿{existingReview.totalScore}} / {{maxScore}} 鍒�</text>
</view>
-
<view class="other-reviews-btn" bindtap="onViewOtherReviews">
<text class="other-reviews-icon">馃懃</text>
- <text class="other-reviews-text">鏌ョ湅鍏朵粬璇勫</text>
+ <text class="other-reviews-text">鏌ョ湅鍏朵粬璇勫璇勫垎</text>
</view>
</view>
- <!-- 搴曢儴鎿嶄綔鏍� -->
- <view wx:if="{{reviewStatus !== 'COMPLETED'}}" class="bottom-actions">
- <view class="action-btn draft-btn" bindtap="onSaveDraft">
- <text class="btn-icon">馃捑</text>
- <text class="btn-text">淇濆瓨鑽夌</text>
- </view>
-
- <view
+ <!-- 搴曢儴鎿嶄綔 -->
+ <view class="bottom-actions">
+ <view
class="action-btn submit-btn {{submitting ? 'submitting' : ''}}"
bindtap="onSubmitReview"
>
@@ -212,27 +161,4 @@
</view>
</view>
</view>
-
- <!-- 瑙嗛棰勮妯℃�佹 -->
- <view wx:if="{{showMediaPreview}}" class="media-preview-modal">
- <view class="modal-overlay" bindtap="onCloseMediaPreview"></view>
- <view class="modal-content">
- <view class="modal-header">
- <text class="modal-title">瑙嗛棰勮</text>
- <view class="close-btn" bindtap="onCloseMediaPreview">
- <text class="close-icon">鉁�</text>
- </view>
- </view>
-
- <view class="modal-body">
- <video
- wx:if="{{mediaType === 'video'}}"
- class="preview-video"
- src="{{currentMedia}}"
- controls
- autoplay
- ></video>
- </view>
- </view>
- </view>
-</view>
\ No newline at end of file
+</view>
diff --git a/wx/pages/judge/review.wxss b/wx/pages/judge/review.wxss
index fab5a9e..24f04d5 100644
--- a/wx/pages/judge/review.wxss
+++ b/wx/pages/judge/review.wxss
@@ -5,7 +5,7 @@
padding-bottom: 120rpx;
}
-/* 鍔犺浇鐘舵�� */
+/* Loading */
.loading-container {
display: flex;
flex-direction: column;
@@ -34,12 +34,10 @@
100% { transform: rotate(360deg); }
}
-/* 璇勫鍐呭 */
.review-content {
padding: 30rpx;
}
-/* 閫氱敤鏍峰紡 */
.section-title {
font-size: 32rpx;
font-weight: 600;
@@ -48,8 +46,11 @@
display: block;
}
-/* 浣滃搧淇℃伅 */
-.submission-info {
+.submission-info,
+.media-section,
+.criteria-section,
+.comment-section,
+.existing-review {
background-color: #fff;
border-radius: 16rpx;
padding: 30rpx;
@@ -87,12 +88,6 @@
color: #155724;
}
-.submission-detail {
- display: flex;
- flex-direction: column;
- gap: 20rpx;
-}
-
.submission-title {
font-size: 30rpx;
font-weight: 600;
@@ -128,15 +123,12 @@
display: flex;
align-items: center;
gap: 8rpx;
- padding: 8rpx 16rpx;
- background-color: #007aff;
+ padding: 10rpx 24rpx;
+ background: linear-gradient(135deg, #34c759 0%, #2ea043 100%);
color: #fff;
- border-radius: 16rpx;
- font-size: 22rpx;
-}
-
-.contact-icon {
- font-size: 20rpx;
+ border-radius: 24rpx;
+ font-size: 24rpx;
+ box-shadow: 0 6rpx 16rpx rgba(46, 160, 67, 0.25);
}
.participant-detail {
@@ -146,13 +138,13 @@
}
.participant-avatar {
- width: 80rpx;
- height: 80rpx;
- border-radius: 40rpx;
+ width: 96rpx;
+ height: 96rpx;
+ border-radius: 48rpx;
+ background-color: #f0f0f0;
}
.participant-text {
- flex: 1;
display: flex;
flex-direction: column;
gap: 8rpx;
@@ -160,196 +152,127 @@
.participant-name {
font-size: 28rpx;
- font-weight: 500;
+ font-weight: 600;
color: #333;
}
-.participant-school {
+.participant-meta {
+ font-size: 24rpx;
+ color: #555;
+ line-height: 1.4;
+}
+
+.participant-field {
font-size: 24rpx;
color: #666;
+ line-height: 1.4;
}
.team-info {
margin-top: 20rpx;
- padding-top: 20rpx;
- border-top: 1rpx solid #f0f0f0;
+ background-color: #f8f9fa;
+ border-radius: 12rpx;
+ padding: 20rpx;
}
.team-label {
font-size: 26rpx;
- color: #666;
- font-weight: 500;
- margin-bottom: 16rpx;
- display: block;
+ font-weight: 600;
+ color: #333;
}
.team-members {
+ margin-top: 12rpx;
display: flex;
- flex-wrap: wrap;
- gap: 16rpx;
+ flex-direction: column;
+ gap: 8rpx;
}
.team-member {
+ font-size: 24rpx;
+ color: #555;
+}
+
+.media-list {
display: flex;
flex-direction: column;
- align-items: center;
- padding: 12rpx 20rpx;
- background-color: #f8f9fa;
- border-radius: 12rpx;
-}
-
-.member-name {
- font-size: 24rpx;
- color: #333;
- font-weight: 500;
-}
-
-.member-role {
- font-size: 20rpx;
- color: #666;
- margin-top: 4rpx;
-}
-
-.submit-time {
- font-size: 24rpx;
- color: #999;
- margin-top: 10rpx;
-}
-
-/* 濯掍綋灞曠ず */
-.media-section {
- background-color: #fff;
- border-radius: 16rpx;
- padding: 30rpx;
- margin-bottom: 30rpx;
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
-}
-
-.media-grid {
- display: grid;
- grid-template-columns: repeat(2, 1fr);
gap: 20rpx;
}
.media-item {
- position: relative;
- border-radius: 12rpx;
- overflow: hidden;
- aspect-ratio: 1;
-}
-
-.media-image,
-.media-video {
- width: 100%;
- height: 100%;
- object-fit: cover;
-}
-
-.play-overlay {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- width: 60rpx;
- height: 60rpx;
- background-color: rgba(0, 0, 0, 0.6);
- border-radius: 50%;
display: flex;
align-items: center;
- justify-content: center;
-}
-
-.play-icon {
- color: #fff;
- font-size: 24rpx;
- margin-left: 4rpx;
-}
-
-/* 鏂囦欢鍒楄〃 */
-.files-section {
- background-color: #fff;
- border-radius: 16rpx;
- padding: 30rpx;
- margin-bottom: 30rpx;
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
-}
-
-.file-list {
- display: flex;
- flex-direction: column;
- gap: 20rpx;
-}
-
-.file-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
+ gap: 24rpx;
padding: 20rpx;
background-color: #f8f9fa;
border-radius: 12rpx;
}
-.file-info {
+.media-thumb-wrapper {
+ width: 120rpx;
+ height: 120rpx;
+ border-radius: 12rpx;
+ overflow: hidden;
+ position: relative;
+ background: #eaeaea;
+}
+
+.media-thumb {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+.media-icon {
+ width: 100%;
+ height: 100%;
display: flex;
align-items: center;
- gap: 16rpx;
- flex: 1;
- min-width: 0;
-}
-
-.file-icon {
+ justify-content: center;
font-size: 32rpx;
+ font-weight: 600;
+ color: #fff;
}
-.file-detail {
+.media-icon.pdf { background: #e74c3c; }
+.media-icon.doc { background: #1e88e5; }
+.media-icon.file { background: #6c757d; }
+
+.media-play {
+ position: absolute;
+ bottom: 8rpx;
+ right: 8rpx;
+ width: 44rpx;
+ height: 44rpx;
+ background: rgba(0, 0, 0, 0.6);
+ border-radius: 50%;
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 24rpx;
+}
+
+.media-info {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
- gap: 4rpx;
+ gap: 6rpx;
}
-.file-name {
- font-size: 26rpx;
+.media-name {
+ font-size: 28rpx;
+ font-weight: 600;
color: #333;
- font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
-.file-size {
+.media-size {
font-size: 22rpx;
color: #666;
-}
-
-.download-btn {
- display: flex;
- align-items: center;
- gap: 8rpx;
- padding: 12rpx 20rpx;
- background-color: #007aff;
- color: #fff;
- border-radius: 20rpx;
- font-size: 22rpx;
- transition: all 0.3s ease;
-}
-
-.download-btn.downloading {
- background-color: #6c757d;
-}
-
-.download-icon {
- font-size: 20rpx;
-}
-
-/* 璇勫鏍囧噯 */
-.criteria-section {
- background-color: #fff;
- border-radius: 16rpx;
- padding: 30rpx;
- margin-bottom: 30rpx;
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
}
.criteria-list {
@@ -392,33 +315,35 @@
display: block;
}
-.score-selector {
- width: 100%;
-}
-
-.score-picker {
+.score-control {
display: flex;
- justify-content: space-between;
align-items: center;
- padding: 16rpx 20rpx;
- background-color: #fff;
- border: 2rpx solid #e0e0e0;
- border-radius: 8rpx;
- font-size: 26rpx;
+ gap: 20rpx;
+ margin-top: 16rpx;
}
-.score-picker.disabled {
- background-color: #f5f5f5;
- color: #999;
+.score-btn {
+ width: 60rpx;
+ height: 60rpx;
+ border-radius: 12rpx;
+ background: #eef2ff;
+ color: #4c60ff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 36rpx;
+ font-weight: 600;
}
-.score-text {
- color: #333;
-}
-
-.picker-arrow {
- color: #999;
- font-size: 20rpx;
+.score-input {
+ flex: 1;
+ height: 60rpx;
+ border: 2rpx solid #dcdfe6;
+ border-radius: 12rpx;
+ text-align: center;
+ font-size: 28rpx;
+ padding: 0 12rpx;
+ background: #fff;
}
.total-score {
@@ -444,15 +369,6 @@
font-weight: 700;
}
-/* 璇勫鎰忚 */
-.comment-section {
- background-color: #fff;
- border-radius: 16rpx;
- padding: 30rpx;
- margin-bottom: 30rpx;
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
-}
-
.comment-input {
width: 100%;
min-height: 200rpx;
@@ -466,29 +382,16 @@
box-sizing: border-box;
}
-.comment-input.disabled {
- background-color: #f5f5f5;
- color: #999;
-}
-
.comment-counter {
- display: flex;
- justify-content: flex-end;
+ text-align: right;
margin-top: 12rpx;
-}
-
-.counter-text {
font-size: 22rpx;
color: #999;
}
-/* 宸叉湁璇勫璁板綍 */
.existing-review {
- background-color: #fff;
- border-radius: 16rpx;
- padding: 30rpx;
- margin-bottom: 30rpx;
- box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
+ background-color: #fff7e6;
+ border: 2rpx solid #ffb347;
}
.review-info {
@@ -496,49 +399,35 @@
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
- padding: 20rpx;
- background-color: #f8f9fa;
- border-radius: 12rpx;
-}
-
-.review-time,
-.review-total {
- font-size: 24rpx;
+ font-size: 26rpx;
color: #666;
}
.other-reviews-btn {
display: flex;
align-items: center;
- justify-content: center;
- gap: 12rpx;
- padding: 16rpx;
- background-color: #007aff;
+ gap: 8rpx;
+ padding: 14rpx 24rpx;
+ border-radius: 24rpx;
+ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: #fff;
- border-radius: 12rpx;
font-size: 26rpx;
}
-.other-reviews-icon {
- font-size: 24rpx;
-}
-
-/* 搴曢儴鎿嶄綔鏍� */
.bottom-actions {
position: fixed;
- bottom: 0;
left: 0;
right: 0;
- display: flex;
- gap: 20rpx;
+ bottom: 0;
padding: 20rpx 30rpx;
- background-color: #fff;
- border-top: 1rpx solid #e0e0e0;
- box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.1);
+ background-color: rgba(255, 255, 255, 0.95);
+ box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
+ display: flex;
+ justify-content: center;
+ align-items: stretch;
}
.action-btn {
- flex: 1;
display: flex;
align-items: center;
justify-content: center;
@@ -548,11 +437,8 @@
font-size: 28rpx;
font-weight: 500;
transition: all 0.3s ease;
-}
-
-.draft-btn {
- background-color: #6c757d;
- color: #fff;
+ flex: 1;
+ width: 100%;
}
.submit-btn {
@@ -568,101 +454,25 @@
font-size: 24rpx;
}
-/* 瑙嗛棰勮妯℃�佹 */
-.media-preview-modal {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 1000;
-}
-
-.modal-overlay {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.8);
-}
-
-.modal-content {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- width: 90%;
- max-width: 600rpx;
- background-color: #fff;
- border-radius: 16rpx;
- overflow: hidden;
-}
-
-.modal-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 20rpx 30rpx;
- border-bottom: 1rpx solid #e0e0e0;
-}
-
-.modal-title {
- font-size: 30rpx;
- font-weight: 600;
- color: #333;
-}
-
-.close-btn {
- width: 60rpx;
- height: 60rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 50%;
- background-color: #f8f9fa;
-}
-
-.close-icon {
- font-size: 24rpx;
- color: #666;
-}
-
-.modal-body {
- padding: 30rpx;
-}
-
-.preview-video {
- width: 100%;
- height: 400rpx;
- border-radius: 12rpx;
-}
-
-/* 鍝嶅簲寮忛�傞厤 */
@media (max-width: 375px) {
.container {
padding-bottom: 100rpx;
}
-
+
.review-content {
padding: 20rpx;
}
-
+
.submission-info,
.media-section,
- .files-section,
.criteria-section,
.comment-section,
.existing-review {
padding: 20rpx;
margin-bottom: 20rpx;
}
-
- .media-grid {
- grid-template-columns: 1fr;
- }
-
+
.bottom-actions {
padding: 15rpx 20rpx;
}
-}
\ No newline at end of file
+}
diff --git a/wx/pages/message/message.js b/wx/pages/message/message.js
index 4fa1f29..e390706 100644
--- a/wx/pages/message/message.js
+++ b/wx/pages/message/message.js
@@ -21,8 +21,22 @@
// 鍔犺浇娑堟伅鍒楄〃
loadMessages() {
- // 妫�鏌ョ敤鎴锋槸鍚﹀凡鐧诲綍
- const userInfo = app.globalData.userInfo
+ // 妫�鏌ョ敤鎴锋槸鍚﹀凡鐧诲綍锛屽鏋済lobalData涓病鏈夛紝灏濊瘯浠庢湰鍦板瓨鍌ㄦ仮澶�
+ let userInfo = app.globalData.userInfo
+ if (!userInfo || !userInfo.userId) {
+ console.log('globalData涓病鏈塽serInfo锛屽皾璇曚粠鏈湴瀛樺偍鎭㈠')
+ try {
+ const storedUserInfo = wx.getStorageSync('userInfo')
+ if (storedUserInfo && storedUserInfo.userId) {
+ console.log('浠庢湰鍦板瓨鍌ㄦ仮澶島serInfo鎴愬姛')
+ app.globalData.userInfo = storedUserInfo
+ userInfo = storedUserInfo
+ }
+ } catch (error) {
+ console.error('浠庢湰鍦板瓨鍌ㄦ仮澶島serInfo澶辫触:', error)
+ }
+ }
+
if (!userInfo || !userInfo.userId) {
console.error('鐢ㄦ埛鏈櫥褰曟垨userId涓嶅瓨鍦�')
wx.showToast({
diff --git a/wx/pages/project/detail.js b/wx/pages/project/detail.js
index 6ce3629..49a5ed8 100644
--- a/wx/pages/project/detail.js
+++ b/wx/pages/project/detail.js
@@ -597,4 +597,4 @@
path: `/pages/project/detail?id=${this.data.projectId}`
}
}
-})
+})
\ No newline at end of file
diff --git a/wx/pages/review/index.js b/wx/pages/review/index.js
index b30b1cd..3a9dd0e 100644
--- a/wx/pages/review/index.js
+++ b/wx/pages/review/index.js
@@ -2,6 +2,14 @@
const app = getApp()
const { graphqlRequest, formatDate } = require('../../lib/utils')
+const GET_RATING_STATS_QUERY = `
+ query GetRatingStats($activityPlayerId: ID!) {
+ judgeRatingsForPlayer(activityPlayerId: $activityPlayerId) {
+ hasRated
+ }
+ }
+`
+
Page({
data: {
loading: false,
@@ -55,7 +63,7 @@
// 鍒囨崲閫夐」鍗�
switchTab(e) {
- const index = e.currentTarget.dataset.index
+ const index = parseInt(e.currentTarget.dataset.index) || 0
if (index === this.data.currentTab) return
this.setData({
@@ -110,10 +118,29 @@
])
} catch (error) {
console.error('鍔犺浇鏁版嵁澶辫触:', error)
- wx.showToast({
- title: '鍔犺浇澶辫触',
- icon: 'none'
- })
+
+ // 妫�鏌ユ槸鍚︽槸璁よ瘉鐩稿叧閿欒
+ if (error.message && (
+ error.message.includes('娌℃湁鏉冮檺璁块棶') ||
+ error.message.includes('璇峰厛鐧诲綍') ||
+ error.message.includes('閲嶆柊鐧诲綍')
+ )) {
+ wx.showToast({
+ title: '姝e湪閲嶆柊鐧诲綍...',
+ icon: 'loading',
+ duration: 2000
+ })
+
+ // 绛夊緟涓�娈垫椂闂村悗閲嶈瘯
+ setTimeout(() => {
+ this.loadData()
+ }, 2000)
+ } else {
+ wx.showToast({
+ title: '鍔犺浇澶辫触锛岃閲嶈瘯',
+ icon: 'none'
+ })
+ }
} finally {
this.setData({ loading: false })
wx.stopPullDownRefresh()
@@ -223,13 +250,13 @@
const projects = data.items.map(item => ({
...item,
submitTime: item.submitTime ? formatDate(item.submitTime) : '',
- reviewTime: item.reviewTime ? formatDate(item.reviewTime) : '',
- statusText: this.getStatusText(item.status),
- statusType: this.getStatusType(item.status)
+ reviewTime: item.reviewTime ? formatDate(item.reviewTime) : ''
}))
+ const projectsWithRatingCount = await this.enrichProjectsWithRatingCounts(projects)
+
this.setData({
- projectList: isLoadMore ? [...this.data.projectList, ...projects] : projects,
+ projectList: isLoadMore ? [...this.data.projectList, ...projectsWithRatingCount] : projectsWithRatingCount,
hasMore: data.hasMore || false,
currentPage: variables.page
})
@@ -274,26 +301,39 @@
}
},
- // 鑾峰彇鐘舵�佹枃鏈�
- getStatusText(status) {
- const statusMap = {
- 'SUBMITTED': '宸叉彁浜�',
- 'UNDER_REVIEW': '璇勫涓�',
- 'REVIEWED': '宸茶瘎瀹�',
- 'REJECTED': '宸叉嫆缁�'
+ async enrichProjectsWithRatingCounts(projects) {
+ if (!Array.isArray(projects) || projects.length === 0) {
+ return projects || []
}
- return statusMap[status] || status
+
+ try {
+ const counts = await Promise.all(projects.map(project => this.getProjectRatingCount(project.id)))
+ return projects.map((project, index) => ({
+ ...project,
+ ratingCount: counts[index]
+ }))
+ } catch (error) {
+ console.error('鎵归噺鑾峰彇璇勫娆℃暟澶辫触:', error)
+ return projects.map(project => ({
+ ...project,
+ ratingCount: typeof project.ratingCount === 'number' ? project.ratingCount : 0
+ }))
+ }
},
- // 鑾峰彇鐘舵�佺被鍨�
- getStatusType(status) {
- const typeMap = {
- 'SUBMITTED': 'info',
- 'UNDER_REVIEW': 'warning',
- 'REVIEWED': 'success',
- 'REJECTED': 'danger'
+ async getProjectRatingCount(activityPlayerId) {
+ if (!activityPlayerId) {
+ return 0
}
- return typeMap[status] || 'info'
+
+ try {
+ const result = await graphqlRequest(GET_RATING_STATS_QUERY, { activityPlayerId })
+ const ratings = result?.judgeRatingsForPlayer || []
+ return ratings.filter(item => item?.hasRated).length
+ } catch (error) {
+ console.error(`鑾峰彇椤圭洰 ${activityPlayerId} 鐨勮瘎瀹℃鏁板け璐�:`, error)
+ return 0
+ }
},
// 鑾峰彇绌虹姸鎬佹枃鏈�
@@ -323,4 +363,4 @@
]
return emptyDescs[currentTab] || ''
}
-})
\ No newline at end of file
+})
diff --git a/wx/pages/review/index.wxml b/wx/pages/review/index.wxml
index a05628d..893f084 100644
--- a/wx/pages/review/index.wxml
+++ b/wx/pages/review/index.wxml
@@ -74,8 +74,9 @@
<view class="project-info">
<view class="project-header">
<text class="project-name">{{project.projectName || '鏈懡鍚嶉」鐩�'}}</text>
- <view class="project-status" wx:if="{{project.status}}">
- <text class="status-text status-{{project.statusType}}">{{project.statusText}}</text>
+ <view class="review-count" wx:if="{{project.ratingCount !== undefined}}">
+ <text class="review-count-label">璇勫娆℃暟锛�</text>
+ <text class="review-count-value">{{project.ratingCount}}</text>
</view>
</view>
@@ -87,13 +88,13 @@
</view>
<view class="project-actions">
- <view
- class="review-btn"
- bindtap="goToReviewDetail"
- data-project="{{project}}"
- >
- <text class="btn-text">璇勫</text>
- </view>
+ <view
+ class="review-btn"
+ bindtap="goToReviewDetail"
+ data-activity-player-id="{{project.activityPlayerId || project.id}}"
+ >
+ <text class="btn-text">璇勫</text>
+ </view>
</view>
</view>
</view>
@@ -104,4 +105,4 @@
<text class="load-more-text" wx:else>鍔犺浇涓�...</text>
</view>
</view>
-</view>
\ No newline at end of file
+</view>
diff --git a/wx/pages/review/index.wxss b/wx/pages/review/index.wxss
index 5023c95..875f1ae 100644
--- a/wx/pages/review/index.wxss
+++ b/wx/pages/review/index.wxss
@@ -204,30 +204,25 @@
margin-right: 20rpx;
}
-.project-status {
+.review-count {
flex-shrink: 0;
-}
-
-.status-text {
- font-size: 24rpx;
+ display: flex;
+ align-items: center;
padding: 6rpx 12rpx;
+ background: #f1f5ff;
border-radius: 12rpx;
- font-weight: 500;
+ gap: 6rpx;
}
-.status-text.status-warning {
- background: #fff3e0;
- color: #f57c00;
+.review-count-label {
+ font-size: 24rpx;
+ color: #5a6c90;
}
-.status-text.status-success {
- background: #e8f5e8;
- color: #388e3c;
-}
-
-.status-text.status-info {
- background: #e3f2fd;
- color: #1976d2;
+.review-count-value {
+ font-size: 28rpx;
+ color: #1a3a7b;
+ font-weight: 600;
}
.project-details {
@@ -286,4 +281,4 @@
.load-more-text {
font-size: 26rpx;
color: #999;
-}
\ No newline at end of file
+}
--
Gitblit v1.8.0