From 375c18a6d2713ff19b22093eec57315992d8333f Mon Sep 17 00:00:00 2001
From: Codex Assistant <codex@example.com>
Date: 星期四, 06 十一月 2025 13:33:52 +0800
Subject: [PATCH] 增加评审下载
---
tmp/review-2/README.txt | 5
backend/src/main/java/com/rongyichuang/activity/entity/Activity.java | 14
tmp/review-export/players/海选/docx-xml/[Content_Types].xml | 1
backend/src/main/java/com/rongyichuang/review/dto/response/ReviewExportResponse.java | 42 +
tmp/review-2/players/海选/12-匿名用户.docx | 0
wx/pages/activity/detail.wxml | 6
web/src/views/activity-list.vue | 27
doc/12-匿名用户.docx | 0
doc/~$选评分表)2025年成渝德眉资创业大赛海选.doc | 0
backend/src/main/java/com/rongyichuang/review/dto/response/ReviewExportJobStatus.java | 44 +
tmp/docx-海选-12/word/settings.xml | 2
tmp/review-export/players/海选/12-匿名用户.docx | 0
backend/src/main/java/com/rongyichuang/review/service/ReviewExportService.java | 432 ++++++++++++++++
doc/(海选评分表)2025年成渝德眉资创业大赛海选.doc | 0
wx/pages/registration/registration.js | 8
tmp/docx-海选-12-new/word/document.xml | 2
wx/pages/activity/detail.js | 113 ++++
tmp/docx-海选-12-new/_rels/.rels | 1
tmp/docx-海选-12-new/docProps/app.xml | 2
tmp/review-export/players/海选/docx-xml/word/_rels/document.xml.rels | 1
tmp/docx-海选-12-new/docProps/core.xml | 1
tmp/docx-海选-12-new/word/_rels/document.xml.rels | 1
tmp/docx-海选-12/[Content_Types].xml | 1
tmp/docx-海选-12/word/document.xml | 2
tmp/review-export-2/players/海选/12-匿名用户.docx | 0
backend/src/main/resources/graphql/activity.graphqls | 1
tmp/review-export/players/海选/docx-xml/_rels/.rels | 1
tmp/review-export/players/海选/docx-xml/word/document.xml | 2
tmp/docx-海选-12/docProps/app.xml | 2
web/src/api/activity.js | 2
tmp/docx-layout-sample.docx | 0
tmp/docx-海选-12/word/_rels/document.xml.rels | 1
backend/src/main/java/com/rongyichuang/config/SecurityConfig.java | 3
tmp/review-export/README.txt | 7
backend/src/main/java/com/rongyichuang/judge/service/CosService.java | 33 +
web/vite.config.ts | 15
tmp/review-export/players/海选/docx-xml/docProps/core.xml | 1
backend/src/main/java/com/rongyichuang/activity/dto/ActivityResponse.java | 11
backend/src/main/java/com/rongyichuang/review/service/ReviewExportJobService.java | 66 ++
tmp/review-export-2/README.txt | 7
web/src/api/reviewExport.js | 70 ++
tmp/docx-海选-12/docProps/core.xml | 1
tmp/review-0/README.txt | 4
web/src/views/ActivityDetail.vue | 180 ++++++
tmp/docx-海选-12-new/[Content_Types].xml | 1
tmp/docx-海选-12-new/word/settings.xml | 2
backend/src/main/java/com/rongyichuang/review/resolver/ReviewResolver.java | 48 +
wx/pages/registration/registration.wxml | 23
tmp/review-0/players/海选/12-匿名用户.docx | 0
tmp/review-export/players/海选/docx-xml/docProps/app.xml | 2
/dev/null | 156 ------
backend/pom.xml | 38
tmp/review-1/README.txt | 5
backend/src/test/java/com/rongyichuang/review/DocxLayoutTest.java | 114 ++++
tmp/docx-海选-12/_rels/.rels | 1
backend/src/main/resources/graphql/review.graphqls | 35 +
tmp/review-export/players/海选/docx-xml/word/settings.xml | 2
57 files changed, 1,326 insertions(+), 213 deletions(-)
diff --git a/PasswordTest.java b/PasswordTest.java
deleted file mode 100644
index cccdc80..0000000
--- a/PasswordTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-
-public class PasswordTest {
- public static void main(String[] args) {
- BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
- String hashedPassword = "$2a$10$VBHNbQlhM1OnQ8QTLkEVSeXBfLAlD9AJqNjErsYC664SUzMZZxjp.";
- String plainPassword = "123456";
-
- boolean matches = encoder.matches(plainPassword, hashedPassword);
- System.out.println("Password matches: " + matches);
-
- // 涔熸祴璇曚竴涓嬫柊鐢熸垚鐨勫瘑鐮�
- String newHash = encoder.encode(plainPassword);
- System.out.println("New hash: " + newHash);
- System.out.println("New hash matches: " + encoder.matches(plainPassword, newHash));
- }
-}
diff --git a/backend/pom.xml b/backend/pom.xml
index 18701af..dfcd6f6 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -146,6 +146,18 @@
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
+
+ <!-- Apache POI for Word/Excel document generation -->
+ <dependency>
+ <groupId>org.apache.poi</groupId>
+ <artifactId>poi</artifactId>
+ <version>5.2.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.poi</groupId>
+ <artifactId>poi-ooxml</artifactId>
+ <version>5.2.5</version>
+ </dependency>
</dependencies>
<build>
@@ -155,8 +167,16 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
- <skip>true</skip>
+ <!-- 鐢熸垚鍙墽琛岀殑鑳栧寘锛屼究浜庢湰鍦扮洿鎺ヨ繍琛� -->
+ <skip>false</skip>
</configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
</plugin>
<!-- 鍦ㄦ墦鍖呴樁娈靛鍒舵墍鏈変緷璧栧埌 target/lib -->
@@ -182,21 +202,7 @@
</executions>
</plugin>
- <!-- 鐢熸垚鍙墽琛岀槮 JAR锛氬啓鍏� Main-Class 涓� Class-Path 鎸囧悜 lib/ -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <version>3.4.2</version>
- <configuration>
- <archive>
- <manifest>
- <addClasspath>true</addClasspath>
- <classpathPrefix>lib/</classpathPrefix>
- <mainClass>com.rongyichuang.RycBackendApplication</mainClass>
- </manifest>
- </archive>
- </configuration>
- </plugin>
+ <!-- 浣跨敤 Spring Boot repackage 鐢熸垚鍙墽琛岃儢鍖咃紝绉婚櫎鑷畾涔� Jar 娓呭崟浠ラ伩鍏嶅啿绐� -->
</plugins>
</build>
</project>
\ No newline at end of file
diff --git a/backend/src/main/java/com/rongyichuang/activity/dto/ActivityResponse.java b/backend/src/main/java/com/rongyichuang/activity/dto/ActivityResponse.java
index b603d44..f80d70f 100644
--- a/backend/src/main/java/com/rongyichuang/activity/dto/ActivityResponse.java
+++ b/backend/src/main/java/com/rongyichuang/activity/dto/ActivityResponse.java
@@ -23,6 +23,8 @@
private Integer state;
private LocalDateTime createTime;
private LocalDateTime updateTime;
+ // 鏈�杩戜竴娆¤瘎瀹″鍑篫IP涓嬭浇URL
+ private String reviewExportUrl;
// 鍏宠仈鏁版嵁
private RatingSchemeResponse ratingScheme;
@@ -57,6 +59,7 @@
this.state = activity.getState();
this.createTime = activity.getCreateTime();
this.updateTime = activity.getUpdateTime();
+ this.reviewExportUrl = activity.getReviewExportUrl();
// 璁剧疆鐘舵�佸悕绉�
this.stateName = getStateNameByValue(activity.getState());
@@ -191,6 +194,14 @@
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
+
+ public String getReviewExportUrl() {
+ return reviewExportUrl;
+ }
+
+ public void setReviewExportUrl(String reviewExportUrl) {
+ this.reviewExportUrl = reviewExportUrl;
+ }
public RatingSchemeResponse getRatingScheme() {
return ratingScheme;
diff --git a/backend/src/main/java/com/rongyichuang/activity/entity/Activity.java b/backend/src/main/java/com/rongyichuang/activity/entity/Activity.java
index 41ac1e7..5ceeec0 100644
--- a/backend/src/main/java/com/rongyichuang/activity/entity/Activity.java
+++ b/backend/src/main/java/com/rongyichuang/activity/entity/Activity.java
@@ -51,6 +51,12 @@
*/
@Column(name = "state", nullable = false)
private Integer state = 1;
+
+ /**
+ * 璇勫瀵煎嚭ZIP涓嬭浇URL锛堟渶杩戜竴娆″鍑猴級
+ */
+ @Column(name = "review_export_url", length = 512)
+ private String reviewExportUrl;
// 鍏宠仈璇勫垎妯℃澘
@ManyToOne(fetch = FetchType.LAZY)
@@ -195,6 +201,14 @@
public void setState(Integer state) {
this.state = state;
}
+
+ public String getReviewExportUrl() {
+ return reviewExportUrl;
+ }
+
+ public void setReviewExportUrl(String reviewExportUrl) {
+ this.reviewExportUrl = reviewExportUrl;
+ }
// 涓氬姟鏂规硶
public boolean isMainActivity() {
diff --git a/backend/src/main/java/com/rongyichuang/config/SecurityConfig.java b/backend/src/main/java/com/rongyichuang/config/SecurityConfig.java
index 0accc67..92af34a 100644
--- a/backend/src/main/java/com/rongyichuang/config/SecurityConfig.java
+++ b/backend/src/main/java/com/rongyichuang/config/SecurityConfig.java
@@ -48,7 +48,8 @@
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
- .requestMatchers("/auth/**", "/actuator/**", "/test/**", "/cleanup/**").permitAll()
+ // 娉ㄦ剰锛氬簲鐢ㄨ缃簡 context-path=/api锛屼负閬垮厤鍖归厤姝т箟锛岃繖閲屽悓鏃跺尮閰嶅幓闄ゅ拰鍖呭惈 context-path 鐨勮矾寰�
+ .requestMatchers("/auth/**", "/api/auth/**", "/actuator/**", "/test/**", "/cleanup/**").permitAll()
.requestMatchers("/api/health/**").permitAll() // 鍏佽鍋ュ悍妫�鏌ョ鐐硅闂�
.requestMatchers("/upload/**").permitAll()
.requestMatchers("/graphiql/**", "/graphql/**", "/api/graphql/**", "/api/graphiql/**").permitAll() // 鍏佽GraphQL鍜孏raphiQL璁块棶
diff --git a/backend/src/main/java/com/rongyichuang/judge/service/CosService.java b/backend/src/main/java/com/rongyichuang/judge/service/CosService.java
index 4e0273e..44bc63d 100644
--- a/backend/src/main/java/com/rongyichuang/judge/service/CosService.java
+++ b/backend/src/main/java/com/rongyichuang/judge/service/CosService.java
@@ -124,6 +124,39 @@
}
/**
+ * 鐩存帴涓婁紶鏈湴鏂囦欢鍒癈OS
+ */
+ public String uploadLocalFile(java.io.File file, String fileName) throws Exception {
+ // 鐢熸垚鏂囦欢璺緞锛氭寜鏃ユ湡鍒嗙洰褰�
+ String dateDir = new java.text.SimpleDateFormat("yyyyMMdd").format(new Date());
+ String key = dateDir + "/" + fileName;
+
+ System.out.println("=== COS鏈湴鏂囦欢涓婁紶璋冭瘯淇℃伅 ===");
+ System.out.println("鏂囦欢Key: " + key);
+ System.out.println("鏂囦欢澶у皬: " + file.length());
+ System.out.println("鏂囦欢璺緞: " + file.getAbsolutePath());
+
+ // 鍒涘缓COS瀹㈡埛绔�
+ COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
+ ClientConfig clientConfig = new ClientConfig(new Region(region));
+ COSClient cosClient = new COSClient(cred, clientConfig);
+
+ try {
+ // 鍒涘缓涓婁紶璇锋眰
+ com.qcloud.cos.model.PutObjectRequest putObjectRequest =
+ new com.qcloud.cos.model.PutObjectRequest(bucket, key, file);
+
+ // 鎵ц涓婁紶
+ com.qcloud.cos.model.PutObjectResult result = cosClient.putObject(putObjectRequest);
+ System.out.println("涓婁紶鎴愬姛锛孍Tag: " + result.getETag());
+
+ return key; // 杩斿洖鐩稿璺緞
+ } finally {
+ cosClient.shutdown();
+ }
+ }
+
+ /**
* 鑾峰彇鏂囦欢璁块棶 URL
*/
public String getFileUrl(String key) {
diff --git a/backend/src/main/java/com/rongyichuang/review/dto/response/ReviewExportJobStatus.java b/backend/src/main/java/com/rongyichuang/review/dto/response/ReviewExportJobStatus.java
new file mode 100644
index 0000000..e96bbd3
--- /dev/null
+++ b/backend/src/main/java/com/rongyichuang/review/dto/response/ReviewExportJobStatus.java
@@ -0,0 +1,44 @@
+package com.rongyichuang.review.dto.response;
+
+/**
+ * 璇勫瀵煎嚭浠诲姟鐘舵�佸搷搴�
+ */
+public class ReviewExportJobStatus {
+ public enum Status {
+ PENDING,
+ RUNNING,
+ SUCCEEDED,
+ FAILED
+ }
+
+ private String jobId;
+ private Status status;
+ private String url;
+ private String message;
+ private Integer progress; // 0-100锛屽彲閫�
+
+ public ReviewExportJobStatus() {}
+
+ public ReviewExportJobStatus(String jobId, Status status, String url, String message, Integer progress) {
+ this.jobId = jobId;
+ this.status = status;
+ this.url = url;
+ this.message = message;
+ this.progress = progress;
+ }
+
+ public String getJobId() { return jobId; }
+ public void setJobId(String jobId) { this.jobId = jobId; }
+
+ public Status getStatus() { return status; }
+ public void setStatus(Status status) { this.status = status; }
+
+ public String getUrl() { return url; }
+ public void setUrl(String url) { this.url = url; }
+
+ public String getMessage() { return message; }
+ public void setMessage(String message) { this.message = message; }
+
+ public Integer getProgress() { return progress; }
+ public void setProgress(Integer progress) { this.progress = progress; }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/com/rongyichuang/review/dto/response/ReviewExportResponse.java b/backend/src/main/java/com/rongyichuang/review/dto/response/ReviewExportResponse.java
new file mode 100644
index 0000000..c33d828
--- /dev/null
+++ b/backend/src/main/java/com/rongyichuang/review/dto/response/ReviewExportResponse.java
@@ -0,0 +1,42 @@
+package com.rongyichuang.review.dto.response;
+
+/**
+ * 璇勫瀵煎嚭鍝嶅簲DTO
+ */
+public class ReviewExportResponse {
+ private boolean success;
+ private String url;
+ private String message;
+
+ public ReviewExportResponse() {}
+
+ public ReviewExportResponse(boolean success, String url, String message) {
+ this.success = success;
+ this.url = url;
+ this.message = message;
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
\ 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..aa7f6a6 100644
--- a/backend/src/main/java/com/rongyichuang/review/resolver/ReviewResolver.java
+++ b/backend/src/main/java/com/rongyichuang/review/resolver/ReviewResolver.java
@@ -4,13 +4,19 @@
import com.rongyichuang.review.dto.response.ReviewProjectPageResponse;
import com.rongyichuang.review.dto.response.ReviewProjectResponse;
import com.rongyichuang.review.dto.response.ReviewStatisticsResponse;
+import com.rongyichuang.review.dto.response.ReviewExportResponse;
+import com.rongyichuang.review.dto.response.ReviewExportJobStatus;
import com.rongyichuang.review.service.ReviewService;
+import com.rongyichuang.review.service.ReviewExportService;
+import com.rongyichuang.review.service.ReviewExportJobService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.data.method.annotation.Argument;
+import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
+import java.util.List;
/**
* 璇勫绠$悊GraphQL瑙f瀽鍣�
@@ -25,6 +31,12 @@
@Autowired
private UserContextUtil userContextUtil;
+
+ @Autowired
+ private ReviewExportService reviewExportService;
+
+ @Autowired
+ private ReviewExportJobService reviewExportJobService;
/**
* 鏌ヨ鎴戞湭璇勫鐨勯」鐩垪琛�
@@ -94,4 +106,40 @@
return reviewService.getReviewStatistics(currentJudgeId);
}
+
+ /**
+ * 瀵煎嚭璇勫ZIP锛岃繑鍥炰笅杞介摼鎺�
+ */
+ @MutationMapping
+ public ReviewExportResponse exportReviewZip(@Argument Long activityId, @Argument List<Long> stageIds) {
+ log.info("瀵煎嚭璇勫ZIP锛宎ctivityId: {}, stageIds: {}", activityId, stageIds);
+ // 鏉冮檺鏍¢獙锛氫粎鍛樺伐锛堢鐞嗗憳/涓诲姙鏂癸級鍙墽琛屽鍑�
+ if (!userContextUtil.isCurrentUserEmployee()) {
+ log.warn("瀵煎嚭璇勫ZIP琚嫆缁濓紝褰撳墠鐢ㄦ埛鏃犲憳宸ユ潈闄愶紝activityId: {}", activityId);
+ return new ReviewExportResponse(false, null, "褰撳墠鐢ㄦ埛鏃犳潈闄愬鍑鸿瘎瀹℃暟鎹�");
+ }
+
+ return reviewExportService.exportReviewZip(activityId, stageIds);
+ }
+
+ /**
+ * 寮傛瀵煎嚭锛氬惎鍔ㄨ瘎瀹″鍑轰换鍔★紝杩斿洖浠诲姟ID
+ */
+ @MutationMapping
+ public String startReviewExportJob(@Argument Long activityId, @Argument List<Long> stageIds) {
+ log.info("鍚姩璇勫瀵煎嚭浠诲姟锛宎ctivityId: {}, stageIds: {}", activityId, stageIds);
+ if (!userContextUtil.isCurrentUserEmployee()) {
+ log.warn("鍚姩璇勫瀵煎嚭浠诲姟琚嫆缁濓紝褰撳墠鐢ㄦ埛鏃犲憳宸ユ潈闄愶紝activityId: {}", activityId);
+ return null;
+ }
+ return reviewExportJobService.startJob(activityId, stageIds);
+ }
+
+ /**
+ * 鏌ヨ瀵煎嚭浠诲姟鐘舵��
+ */
+ @QueryMapping
+ public ReviewExportJobStatus getReviewExportJobStatus(@Argument String jobId) {
+ return reviewExportJobService.getStatus(jobId);
+ }
}
\ No newline at end of file
diff --git a/backend/src/main/java/com/rongyichuang/review/service/ReviewExportJobService.java b/backend/src/main/java/com/rongyichuang/review/service/ReviewExportJobService.java
new file mode 100644
index 0000000..38f6562
--- /dev/null
+++ b/backend/src/main/java/com/rongyichuang/review/service/ReviewExportJobService.java
@@ -0,0 +1,66 @@
+package com.rongyichuang.review.service;
+
+import com.rongyichuang.review.dto.response.ReviewExportJobStatus;
+import com.rongyichuang.review.dto.response.ReviewExportResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * 寮傛璇勫瀵煎嚭浠诲姟鏈嶅姟
+ */
+@Service
+@Slf4j
+public class ReviewExportJobService {
+
+ private final ReviewExportService reviewExportService;
+
+ private final ExecutorService executor = Executors.newFixedThreadPool(Math.max(2, Runtime.getRuntime().availableProcessors() / 2));
+
+ private final ConcurrentHashMap<String, ReviewExportJobStatus> jobStatusMap = new ConcurrentHashMap<>();
+
+ public ReviewExportJobService(ReviewExportService reviewExportService) {
+ this.reviewExportService = reviewExportService;
+ }
+
+ /**
+ * 鍚姩瀵煎嚭浠诲姟
+ */
+ public String startJob(Long activityId, List<Long> stageIds) {
+ String jobId = UUID.randomUUID().toString();
+ ReviewExportJobStatus init = new ReviewExportJobStatus(jobId, ReviewExportJobStatus.Status.PENDING, null, null, 0);
+ jobStatusMap.put(jobId, init);
+
+ executor.submit(() -> {
+ ReviewExportJobStatus running = new ReviewExportJobStatus(jobId, ReviewExportJobStatus.Status.RUNNING, null, null, 10);
+ jobStatusMap.put(jobId, running);
+ try {
+ ReviewExportResponse res = reviewExportService.exportReviewZip(activityId, stageIds);
+ if (res != null && res.isSuccess()) {
+ ReviewExportJobStatus done = new ReviewExportJobStatus(jobId, ReviewExportJobStatus.Status.SUCCEEDED, res.getUrl(), res.getMessage(), 100);
+ jobStatusMap.put(jobId, done);
+ } else {
+ String msg = res != null ? res.getMessage() : "瀵煎嚭澶辫触";
+ ReviewExportJobStatus failed = new ReviewExportJobStatus(jobId, ReviewExportJobStatus.Status.FAILED, null, msg, 100);
+ jobStatusMap.put(jobId, failed);
+ }
+ } catch (Exception e) {
+ log.error("瀵煎嚭浠诲姟鎵ц澶辫触, jobId: {}", jobId, e);
+ ReviewExportJobStatus failed = new ReviewExportJobStatus(jobId, ReviewExportJobStatus.Status.FAILED, null, e.getMessage(), 100);
+ jobStatusMap.put(jobId, failed);
+ }
+ });
+
+ return jobId;
+ }
+
+ /**
+ * 鏌ヨ浠诲姟鐘舵��
+ */
+ public ReviewExportJobStatus getStatus(String jobId) {
+ return jobStatusMap.get(jobId);
+ }
+
+}
\ No newline at end of file
diff --git a/backend/src/main/java/com/rongyichuang/review/service/ReviewExportService.java b/backend/src/main/java/com/rongyichuang/review/service/ReviewExportService.java
new file mode 100644
index 0000000..edad964
--- /dev/null
+++ b/backend/src/main/java/com/rongyichuang/review/service/ReviewExportService.java
@@ -0,0 +1,432 @@
+package com.rongyichuang.review.service;
+
+import com.rongyichuang.activity.entity.Activity;
+import com.rongyichuang.activity.repository.ActivityRepository;
+import com.rongyichuang.player.repository.ActivityPlayerRepository;
+import com.rongyichuang.review.dto.response.ReviewExportResponse;
+import com.rongyichuang.judge.service.CosService;
+import com.rongyichuang.player.entity.ActivityPlayer;
+import com.rongyichuang.activity.repository.ActivityPlayerRatingRepository;
+import com.rongyichuang.activity.repository.ActivityPlayerRatingItemRepository;
+import com.rongyichuang.rating.repository.RatingItemRepository;
+import com.rongyichuang.rating.entity.RatingItem;
+import com.rongyichuang.judge.repository.JudgeRepository;
+import com.rongyichuang.judge.entity.Judge;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
+import org.apache.poi.xwpf.usermodel.XWPFTableRow;
+import org.apache.poi.xwpf.usermodel.XWPFTableCell;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGridCol;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblBorders;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder;
+import java.math.BigInteger;
+
+@Service
+public class ReviewExportService {
+ private static final Logger log = LoggerFactory.getLogger(ReviewExportService.class);
+
+ private final ActivityRepository activityRepository;
+ private final ActivityPlayerRepository activityPlayerRepository;
+ private final ActivityPlayerRatingRepository activityPlayerRatingRepository;
+ private final ActivityPlayerRatingItemRepository activityPlayerRatingItemRepository;
+ private final RatingItemRepository ratingItemRepository;
+ private final JudgeRepository judgeRepository;
+ private final CosService cosService;
+
+ public ReviewExportService(ActivityRepository activityRepository,
+ ActivityPlayerRepository activityPlayerRepository,
+ ActivityPlayerRatingRepository activityPlayerRatingRepository,
+ ActivityPlayerRatingItemRepository activityPlayerRatingItemRepository,
+ RatingItemRepository ratingItemRepository,
+ JudgeRepository judgeRepository,
+ CosService cosService) {
+ this.activityRepository = activityRepository;
+ this.activityPlayerRepository = activityPlayerRepository;
+ this.activityPlayerRatingRepository = activityPlayerRatingRepository;
+ this.activityPlayerRatingItemRepository = activityPlayerRatingItemRepository;
+ this.ratingItemRepository = ratingItemRepository;
+ this.judgeRepository = judgeRepository;
+ this.cosService = cosService;
+ }
+
+ /**
+ * 瀵煎嚭璇勫缁撴灉ZIP锛堝崰浣嶅疄鐜帮細鐢熸垚绠�鍗曠殑README姹囨�诲苟涓婁紶锛岃繑鍥濽RL锛�
+ */
+ public ReviewExportResponse exportReviewZip(Long activityId, List<Long> stageIds) {
+ try {
+ // 1) 鏍¢獙娲诲姩
+ Optional<Activity> activityOpt = activityRepository.findById(activityId);
+ if (activityOpt.isEmpty()) {
+ return new ReviewExportResponse(false, null, "娲诲姩涓嶅瓨鍦�: " + activityId);
+ }
+ Activity activity = activityOpt.get();
+
+ // 2) 缁勭粐瀵煎嚭鏂囦欢鍚�
+ // 浠呬繚鐣欏瓧姣嶃�佹暟瀛椼�佽繛瀛楃锛屼互鍙婃墍鏈塙nicode瀛楁瘝瀛楃锛堟兜鐩栦腑鏂囩瓑锛夛紱鍏朵粬鏇挎崲涓轰笅鍒掔嚎
+ String safeName = activity.getName() != null ? activity.getName().replaceAll("[^\\p{L}\\p{N}-]", "_") : "activity";
+ String ts = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
+ String fileName = String.format("review-%s-%s.zip", safeName, ts);
+
+ // 3) 鏋勫缓涓存椂ZIP
+ File zipFile = new File(System.getProperty("java.io.tmpdir"), "ryc-export-" + UUID.randomUUID() + ".zip");
+ try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
+ // README锛堥伩鍏嶅湪姝ゅ鍏抽棴ZipOutputStream锛�
+ ZipEntry readme = new ZipEntry("README.txt");
+ zos.putNextEntry(readme);
+ StringBuilder readmeSb = new StringBuilder();
+ readmeSb.append("钃夋槗鍒涜瘎瀹″鍑篭n");
+ readmeSb.append("娲诲姩: ").append(activity.getName()).append(" (ID=").append(activity.getId()).append(")\n");
+ readmeSb.append("瀵煎嚭鏃堕棿: ").append(LocalDateTime.now()).append("\n");
+ if (stageIds != null && !stageIds.isEmpty()) {
+ readmeSb.append("闃舵ID: ").append(stageIds).append("\n");
+ // 绠�瑕佺粺璁℃瘡涓樁娈垫姤鍚嶄汉鏁帮紙鍗犱綅缁熻锛�
+ for (Long stageId : stageIds) {
+ int playerCount = activityPlayerRepository.findByStageId(stageId).size();
+ readmeSb.append("闃舵 ").append(stageId).append(" 鎶ュ悕浜烘暟: ").append(playerCount).append("\n");
+ }
+ } else {
+ // 涓绘椿鍔ㄦ姤鍚嶄汉鏁帮紙涓嶅尯鍒嗛樁娈碉級
+ int playerCount = activityPlayerRepository.findByActivityId(activityId).size();
+ readmeSb.append("娲诲姩鎶ュ悕浜烘暟: ").append(playerCount).append("\n");
+ }
+ byte[] readmeBytes = readmeSb.toString().getBytes(StandardCharsets.UTF_8);
+ zos.write(readmeBytes);
+ zos.closeEntry();
+
+ // 鐢熸垚姣忎釜閫夋墜鐨凞OCX璇勫垎琛紝鎵撳寘鍒癦IP涓紙鍩虹瀹炵幇锛�
+ if (stageIds != null && !stageIds.isEmpty()) {
+ for (Long stageId : stageIds) {
+ Activity stage = activityRepository.findById(stageId).orElse(null);
+ String stageName = stage != null ? stage.getName() : ("闃舵" + stageId);
+ List<ActivityPlayer> players = activityPlayerRepository.findByStageIdAndStateWithPlayerOrderByCreateTimeDesc(stageId, 1);
+ for (ActivityPlayer ap : players) {
+ addPlayerDocToZip(zos, activity, stageName, ap);
+ }
+ }
+ } else {
+ List<ActivityPlayer> players = activityPlayerRepository.findByActivityIdWithPlayerAndRegion(activityId);
+ for (ActivityPlayer ap : players) {
+ String stageName = ap.getStageId() != null ? activityRepository.findById(ap.getStageId()).map(Activity::getName).orElse("闃舵" + ap.getStageId()) : "涓绘椿鍔�";
+ addPlayerDocToZip(zos, activity, stageName, ap);
+ }
+ }
+ }
+
+ // 4) 涓婁紶鍒癈OS
+ String key = cosService.uploadLocalFile(zipFile, fileName);
+ String url = cosService.getFileUrl(key);
+ log.info("璇勫瀵煎嚭涓婁紶瀹屾垚锛孋OS Key: {}, URL: {}", key, url);
+
+ // 5) 鍐欏叆 t_activity.review_export_url
+ if (stageIds != null && !stageIds.isEmpty()) {
+ for (Long stageId : stageIds) {
+ Activity stage = activityRepository.findById(stageId).orElse(null);
+ if (stage != null) {
+ stage.setReviewExportUrl(url);
+ activityRepository.save(stage);
+ }
+ }
+ } else {
+ activity.setReviewExportUrl(url);
+ activityRepository.save(activity);
+ }
+
+ // 鍒犻櫎涓存椂鏂囦欢
+ try { zipFile.delete(); } catch (Exception ignore) {}
+
+ return new ReviewExportResponse(true, url, "瀵煎嚭鎴愬姛");
+ } catch (Exception ex) {
+ log.error("瀵煎嚭璇勫ZIP澶辫触", ex);
+ return new ReviewExportResponse(false, null, "瀵煎嚭澶辫触: " + ex.getMessage());
+ }
+ }
+
+ private void addPlayerDocToZip(ZipOutputStream zos, Activity activity, String stageName, ActivityPlayer ap) throws Exception {
+ String projectName = ap.getProjectName() != null ? ap.getProjectName() : "鏈懡鍚嶉」鐩�";
+ String playerName = ap.getPlayer() != null && ap.getPlayer().getName() != null ? ap.getPlayer().getName() : ("閫夋墜" + ap.getPlayerId());
+
+ // 鐢熸垚DOCX鍐呭
+ XWPFDocument doc = new XWPFDocument();
+ // 璁剧疆椤甸潰涓篈4骞跺簲鐢ㄥ悎鐞嗛〉杈硅窛锛屼繚璇佹墦鍗扮増寮�
+ applyPageSettings(doc);
+ // 鏍囬
+ XWPFParagraph title = doc.createParagraph();
+ title.setAlignment(ParagraphAlignment.CENTER);
+ XWPFRun tr = title.createRun();
+ tr.setText("璇勫璇勫垎琛�");
+ tr.setBold(true);
+ tr.setFontSize(18);
+
+ // 鍩烘湰淇℃伅
+ XWPFParagraph p1 = doc.createParagraph();
+ XWPFRun r1 = p1.createRun();
+ r1.setText("娲诲姩锛�" + safeText(activity.getName()) + " 闃舵锛�" + safeText(stageName));
+
+ XWPFParagraph p2 = doc.createParagraph();
+ XWPFRun r2 = p2.createRun();
+ r2.setText("椤圭洰锛�" + safeText(projectName) + " 閫夋墜锛�" + safeText(playerName));
+
+ // 鏌ヨ鎵�鏈夎瘎濮旇瘎鍒�
+ List<com.rongyichuang.activity.entity.ActivityPlayerRating> ratings = activityPlayerRatingRepository.findByActivityPlayerId(ap.getId());
+ if (ratings == null || ratings.isEmpty()) {
+ // 鏃犺瘎鍒嗘椂锛屼粛鐒剁敓鎴愯瘎鍒嗛」妯℃澘琛ㄦ牸锛屼究浜庢墦鍗版垨绾夸笅璇勫垎
+ XWPFParagraph pEmpty = doc.createParagraph();
+ XWPFRun re = pEmpty.createRun();
+ re.setText("灏氭棤璇勫垎锛堜互涓嬩负璇勫垎椤规ā鏉匡級");
+ re.setItalic(true);
+
+ // 浣跨敤娲诲姩鐨勮瘎鍒嗘柟妗堢敓鎴愮┖琛ㄦ牸锛堣缃〃鏍煎搴﹀拰鍒楀锛岄伩鍏嶈〃鏍兼尋鍘嬶級
+ XWPFTable table = doc.createTable();
+ applyTableLayout(table, new int[]{6072, 1500, 1500});
+ XWPFTableRow header = table.getRow(0);
+ ensureCells(header, 3);
+ setCellText(header.getCell(0), "璇勫垎椤�");
+ setCellText(header.getCell(1), "寰楀垎");
+ setCellText(header.getCell(2), "婊″垎");
+
+ // 浼樺厛浣跨敤闃舵鐨勮瘎鍒嗘柟妗堬紱濡傛灉閫夋墜娌℃湁闃舵鎴栭樁娈典笉瀛樺湪锛屽垯鍥為��鍒颁富娲诲姩璇勫垎鏂规
+ Long schemeIdToUse = null;
+ if (ap.getStageId() != null) {
+ try {
+ Activity stageEntity = activityRepository.findById(ap.getStageId()).orElse(null);
+ if (stageEntity != null && stageEntity.getRatingSchemeId() != null) {
+ schemeIdToUse = stageEntity.getRatingSchemeId();
+ }
+ } catch (Exception ignore) {}
+ }
+ if (schemeIdToUse == null) {
+ schemeIdToUse = activity.getRatingSchemeId();
+ }
+
+ List<RatingItem> items = schemeIdToUse != null
+ ? ratingItemRepository.findBySchemeIdOrderByOrderNo(schemeIdToUse)
+ : new ArrayList<>();
+ for (RatingItem item : items) {
+ XWPFTableRow row = table.createRow();
+ ensureCells(row, 3);
+ setCellText(row.getCell(0), safeText(item.getName()));
+ setCellText(row.getCell(1), "-");
+ setCellText(row.getCell(2), item.getMaxScore() != null ? String.valueOf(item.getMaxScore()) : "-");
+ }
+ } else {
+ for (com.rongyichuang.activity.entity.ActivityPlayerRating rating : ratings) {
+ XWPFParagraph judgeTitle = doc.createParagraph();
+ XWPFRun jr = judgeTitle.createRun();
+ String judgeName = rating.getJudgeId() != null ? judgeRepository.findById(rating.getJudgeId()).map(Judge::getName).orElse("璇勫" + rating.getJudgeId()) : "鏈煡璇勫";
+ jr.setText("璇勫锛�" + safeText(judgeName) + " 鎬诲垎锛�" + (rating.getTotalScore() != null ? rating.getTotalScore() : "-") );
+ jr.setBold(true);
+
+ // 鏋勫缓璇勫垎椤硅〃鏍�
+ XWPFTable table = doc.createTable();
+ applyTableLayout(table, new int[]{6072, 1500, 1500});
+ XWPFTableRow header = table.getRow(0);
+ ensureCells(header, 3);
+ setCellText(header.getCell(0), "璇勫垎椤�");
+ setCellText(header.getCell(1), "寰楀垎");
+ setCellText(header.getCell(2), "婊″垎");
+
+ List<RatingItem> items = rating.getRatingSchemeId() != null ? ratingItemRepository.findBySchemeIdOrderByOrderNo(rating.getRatingSchemeId()) : new ArrayList<>();
+ // 鏌ヨ璇勫垎椤瑰緱鍒�
+ List<com.rongyichuang.activity.entity.ActivityPlayerRatingItem> ratingItems = activityPlayerRatingItemRepository.findByActivityPlayerRatingId(rating.getId());
+ Map<Long, java.math.BigDecimal> scoreMap = new HashMap<>();
+ for (com.rongyichuang.activity.entity.ActivityPlayerRatingItem ri : ratingItems) {
+ scoreMap.put(ri.getRatingItemId(), ri.getScore());
+ }
+ for (RatingItem item : items) {
+ XWPFTableRow row = table.createRow();
+ ensureCells(row, 3);
+ setCellText(row.getCell(0), safeText(item.getName()));
+ java.math.BigDecimal s = scoreMap.get(item.getId());
+ setCellText(row.getCell(1), s != null ? s.toPlainString() : "-");
+ setCellText(row.getCell(2), item.getMaxScore() != null ? String.valueOf(item.getMaxScore()) : "-");
+ }
+ }
+ }
+
+ // 鍦ㄦ枃妗e簳閮ㄦ坊鍔犱笓瀹惰瘎瀹$瀛楀尯鍩燂紙鍙傝�冩ā鏉挎牸寮忥級
+ addSignatureSection(doc);
+
+ // 鍐欏叆鍒癦IP
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+ doc.write(baos);
+ String fileBase = sanitizeFileName(stageName) + "/" + sanitizeFileName(projectName + "-" + playerName) + ".docx";
+ String entryName = "players/" + fileBase;
+ ZipEntry entry = new ZipEntry(entryName);
+ zos.putNextEntry(entry);
+ zos.write(baos.toByteArray());
+ zos.closeEntry();
+ }
+ doc.close();
+ }
+
+ private String sanitizeFileName(String name) {
+ return name == null ? "unknown" : name.replaceAll("[^\\p{L}\\p{N}-]", "_");
+ }
+
+ private String safeText(String text) {
+ return text == null ? "-" : text;
+ }
+
+ /**
+ * 璁剧疆琛ㄦ牸鐨勬�诲搴﹀拰鍒楀锛岄伩鍏嶅嚭鐜板垪瀹借繃绐勫鑷村唴瀹规尋鍦ㄤ竴璧�
+ * @param table 琛ㄦ牸
+ * @param colWidthsTwips 姣忓垪瀹藉害锛堝崟浣嶏細twips锛夛紝绀轰緥锛歿6072, 1500, 1500}
+ */
+ private void applyTableLayout(XWPFTable table, int[] colWidthsTwips) {
+ // 璁剧疆琛ㄦ牸鎬诲搴︼紙椤甸潰鏍囧噯瀹藉害绾� 9072 twips锛�
+ CTTbl ctTbl = table.getCTTbl();
+ CTTblPr tblPr = ctTbl.getTblPr() == null ? ctTbl.addNewTblPr() : ctTbl.getTblPr();
+ CTTblWidth tblW = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();
+ tblW.setType(STTblWidth.DXA);
+ int total = 0;
+ for (int w : colWidthsTwips) total += w;
+ tblW.setW(BigInteger.valueOf(total));
+
+ // 璁剧疆鍒楃綉鏍硷紙鍒楀锛�
+ CTTblGrid grid = ctTbl.getTblGrid() == null ? ctTbl.addNewTblGrid() : ctTbl.getTblGrid();
+ // 娓呯悊宸叉湁鍒楀畾涔夛紙濡傛灉鏈夛級
+ while (grid.sizeOfGridColArray() > 0) {
+ grid.removeGridCol(0);
+ }
+ for (int w : colWidthsTwips) {
+ CTTblGridCol col = grid.addNewGridCol();
+ col.setW(BigInteger.valueOf(w));
+ }
+
+ // 璁剧疆琛ㄦ牸杈规锛屼繚璇佹墦鍗版晥鏋滄竻鏅�
+ CTTblBorders borders = tblPr.isSetTblBorders() ? tblPr.getTblBorders() : tblPr.addNewTblBorders();
+ CTBorder border = borders.isSetInsideH() ? borders.getInsideH() : borders.addNewInsideH();
+ border.setVal(STBorder.SINGLE);
+ border.setSz(BigInteger.valueOf(8)); // 8鍏垎涔嬩竴鐐� = 1pt
+ border.setColor("000000");
+ border = borders.isSetInsideV() ? borders.getInsideV() : borders.addNewInsideV();
+ border.setVal(STBorder.SINGLE);
+ border.setSz(BigInteger.valueOf(8));
+ border.setColor("000000");
+ border = borders.isSetTop() ? borders.getTop() : borders.addNewTop();
+ border.setVal(STBorder.SINGLE);
+ border.setSz(BigInteger.valueOf(8));
+ border.setColor("000000");
+ border = borders.isSetBottom() ? borders.getBottom() : borders.addNewBottom();
+ border.setVal(STBorder.SINGLE);
+ border.setSz(BigInteger.valueOf(8));
+ border.setColor("000000");
+ border = borders.isSetLeft() ? borders.getLeft() : borders.addNewLeft();
+ border.setVal(STBorder.SINGLE);
+ border.setSz(BigInteger.valueOf(8));
+ border.setColor("000000");
+ // 淇鍙宠竟妗嗘湭璁剧疆绮楃粏鐨勯棶棰橈紝纭繚鍥涘懆杈规涓�鑷�
+ border = borders.isSetRight() ? borders.getRight() : borders.addNewRight();
+ border.setVal(STBorder.SINGLE);
+ border.setSz(BigInteger.valueOf(8));
+ border.setColor("000000");
+ }
+
+ /**
+ * 纭繚涓�琛屾湁鎸囧畾鏁伴噺鐨勫崟鍏冩牸
+ */
+ private void ensureCells(XWPFTableRow row, int cellCount) {
+ int existing = row.getTableCells().size();
+ for (int i = existing; i < cellCount; i++) {
+ row.addNewTableCell();
+ }
+ }
+
+ /**
+ * 璁剧疆鍗曞厓鏍兼枃鏈苟涓鸿鍗曞厓鏍艰缃搴︼紙涓庣綉鏍煎尮閰嶏級
+ */
+ private void setCellText(XWPFTableCell cell, String text) {
+ // 鐩存帴璁剧疆鏂囨湰
+ try {
+ // 娓呯┖榛樿娈佃惤锛岄伩鍏嶉噸澶嶏紙鏌愪簺鎯呭喌涓嬪崟鍏冩牸鍙兘娌℃湁榛樿娈佃惤锛�
+ if (cell.getParagraphs().size() > 0) {
+ cell.removeParagraph(0);
+ }
+ } catch (Exception ignore) {}
+ XWPFParagraph p = cell.addParagraph();
+ p.setAlignment(ParagraphAlignment.LEFT);
+ XWPFRun run = p.createRun();
+ run.setFontSize(12);
+ // 浣跨敤涓枃瀛椾綋锛屼繚璇佷腑鏂囨樉绀烘晥鏋滄洿鎺ヨ繎妯℃澘
+ try {
+ run.setFontFamily("瀹嬩綋");
+ } catch (Exception ignore) {}
+ run.setText(text);
+
+ // 涓哄崟鍏冩牸璁剧疆瀹藉害锛圖XA锛変互闃插湪鏌愪簺Word鐗堟湰涓湭搴旂敤琛ㄦ牸缃戞牸瀹藉害
+ CTTcPr tcPr = cell.getCTTc().isSetTcPr() ? cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr();
+ CTTblWidth w = tcPr.isSetTcW() ? tcPr.getTcW() : tcPr.addNewTcW();
+ w.setType(STTblWidth.DXA);
+ // 瀹藉害鍊肩敱鎵�鍦ㄥ垪鍐冲畾锛岃繖閲屼笉閲嶅璁剧疆鍏蜂綋鏁板�硷紝閬垮厤涓庤〃鏍肩綉鏍煎啿绐�
+ }
+
+ /**
+ * 娣诲姞涓撳璇勫绛惧瓧鍖哄煙锛堜袱鍒楋細绛惧瓧銆佹棩鏈燂級
+ */
+ private void addSignatureSection(XWPFDocument doc) {
+ // 鐣欏嚭涓�瀹氱殑涓婅竟璺�
+ XWPFParagraph spacer = doc.createParagraph();
+ spacer.setSpacingBefore(200);
+
+ XWPFTable signTable = doc.createTable(1, 2);
+ applyTableLayout(signTable, new int[]{6500, 2572});
+ XWPFTableRow row = signTable.getRow(0);
+
+ ensureCells(row, 2);
+ setCellText(row.getCell(0), "涓撳璇勫绛惧瓧锛歘______________");
+ setCellText(row.getCell(1), "绛惧瓧鏃ユ湡锛歘_________");
+ }
+
+ /**
+ * 璁剧疆椤甸潰澶у皬涓庨〉杈硅窛锛圓4锛岄粯璁よ竟璺濈害1鑻卞锛�
+ */
+ private void applyPageSettings(XWPFDocument doc) {
+ try {
+ // A4 灏哄锛氬 11907 twips锛�21cm锛夛紝楂� 16840 twips锛�29.7cm锛�
+ var body = doc.getDocument().getBody();
+ var sectPr = body.isSetSectPr() ? body.getSectPr() : body.addNewSectPr();
+ var pgSz = sectPr.isSetPgSz() ? sectPr.getPgSz() : sectPr.addNewPgSz();
+ pgSz.setW(BigInteger.valueOf(11907));
+ pgSz.setH(BigInteger.valueOf(16840));
+
+ // 椤佃竟璺濓細绾� 1 鑻卞锛�1440 twips锛夛紝鍙牴鎹渶瑕佸井璋�
+ var pgMar = sectPr.isSetPgMar() ? sectPr.getPgMar() : sectPr.addNewPgMar();
+ pgMar.setLeft(BigInteger.valueOf(1440));
+ pgMar.setRight(BigInteger.valueOf(1440));
+ pgMar.setTop(BigInteger.valueOf(1440));
+ pgMar.setBottom(BigInteger.valueOf(1440));
+ } catch (Exception ignore) {
+ // 鍏煎鎬ц�冭檻锛氫笉褰卞搷鏂囨。鐢熸垚
+ }
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/resources/graphql/activity.graphqls b/backend/src/main/resources/graphql/activity.graphqls
index ba530a4..e497252 100644
--- a/backend/src/main/resources/graphql/activity.graphqls
+++ b/backend/src/main/resources/graphql/activity.graphqls
@@ -70,6 +70,7 @@
createTime: String
updateTime: String
+ reviewExportUrl: String
coverImage: MediaResponse
diff --git a/backend/src/main/resources/graphql/review.graphqls b/backend/src/main/resources/graphql/review.graphqls
index 6c3e122..818e2d5 100644
--- a/backend/src/main/resources/graphql/review.graphqls
+++ b/backend/src/main/resources/graphql/review.graphqls
@@ -13,6 +13,41 @@
# 鑾峰彇璇勫缁熻鏁版嵁
reviewStatistics: ReviewStatisticsResponse!
+
+ # 鏌ヨ璇勫瀵煎嚭浠诲姟鐘舵��
+ getReviewExportJobStatus(jobId: String!): ReviewExportJobStatus
+}
+
+# 鎵╁睍鍙樻洿绫诲瀷锛氳瘎瀹″鍑�
+extend type Mutation {
+ # 瀵煎嚭鎸囧畾姣旇禌鎴栭樁娈电殑璇勫缁撴灉涓篫IP骞惰繑鍥炰笅杞介摼鎺�
+ exportReviewZip(activityId: ID!, stageIds: [ID]): ReviewExportResponse!
+
+ # 鍚姩寮傛璇勫瀵煎嚭浠诲姟锛岃繑鍥炰换鍔D
+ startReviewExportJob(activityId: ID!, stageIds: [ID]): String!
+}
+
+# 璇勫瀵煎嚭鍝嶅簲
+type ReviewExportResponse {
+ success: Boolean!
+ url: String
+ message: String
+}
+
+# 璇勫瀵煎嚭浠诲姟鐘舵��
+type ReviewExportJobStatus {
+ jobId: String!
+ status: ReviewExportJobStatusEnum!
+ url: String
+ message: String
+ progress: Int
+}
+
+enum ReviewExportJobStatusEnum {
+ PENDING
+ RUNNING
+ SUCCEEDED
+ FAILED
}
# 璇勫椤圭洰鍒嗛〉鍝嶅簲绫诲瀷
diff --git a/backend/src/test/java/com/rongyichuang/review/DocxLayoutTest.java b/backend/src/test/java/com/rongyichuang/review/DocxLayoutTest.java
new file mode 100644
index 0000000..0895adc
--- /dev/null
+++ b/backend/src/test/java/com/rongyichuang/review/DocxLayoutTest.java
@@ -0,0 +1,114 @@
+package com.rongyichuang.review;
+
+import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
+import org.apache.poi.xwpf.usermodel.XWPFTableRow;
+import org.apache.poi.xwpf.usermodel.XWPFTableCell;
+import org.junit.jupiter.api.Test;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGridCol;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.math.BigInteger;
+
+/**
+ * 蹇�熼獙璇丏OCX琛ㄦ牸瀹藉害涓庣瀛楀尯鍩熷竷灞�
+ */
+public class DocxLayoutTest {
+
+ private void applyTableLayout(XWPFTable table, int[] colWidthsTwips) {
+ CTTbl ctTbl = table.getCTTbl();
+ CTTblPr tblPr = ctTbl.getTblPr() == null ? ctTbl.addNewTblPr() : ctTbl.getTblPr();
+ CTTblWidth tblW = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();
+ tblW.setType(STTblWidth.DXA);
+ int total = 0;
+ for (int w : colWidthsTwips) total += w;
+ tblW.setW(BigInteger.valueOf(total));
+
+ CTTblGrid grid = ctTbl.getTblGrid() == null ? ctTbl.addNewTblGrid() : ctTbl.getTblGrid();
+ while (grid.sizeOfGridColArray() > 0) {
+ grid.removeGridCol(0);
+ }
+ for (int w : colWidthsTwips) {
+ CTTblGridCol col = grid.addNewGridCol();
+ col.setW(BigInteger.valueOf(w));
+ }
+ }
+
+ private void ensureCells(XWPFTableRow row, int cellCount) {
+ int existing = row.getTableCells().size();
+ for (int i = existing; i < cellCount; i++) {
+ row.addNewTableCell();
+ }
+ }
+
+ private void setCellText(XWPFTableCell cell, String text) {
+ while (cell.getParagraphs().size() > 0) {
+ cell.removeParagraph(0);
+ }
+ XWPFParagraph p = cell.addParagraph();
+ p.setAlignment(ParagraphAlignment.LEFT);
+ XWPFRun run = p.createRun();
+ run.setFontSize(12);
+ run.setText(text);
+
+ CTTcPr tcPr = cell.getCTTc().isSetTcPr() ? cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr();
+ CTTblWidth w = tcPr.isSetTcW() ? tcPr.getTcW() : tcPr.addNewTcW();
+ w.setType(STTblWidth.DXA);
+ }
+
+ @Test
+ public void generateSampleDoc() throws Exception {
+ XWPFDocument doc = new XWPFDocument();
+
+ XWPFParagraph title = doc.createParagraph();
+ title.setAlignment(ParagraphAlignment.CENTER);
+ XWPFRun tr = title.createRun();
+ tr.setText("璇勫璇勫垎琛紙甯冨眬楠岃瘉锛�");
+ tr.setBold(true);
+ tr.setFontSize(18);
+
+ XWPFTable table = doc.createTable();
+ applyTableLayout(table, new int[]{6072, 1500, 1500});
+ XWPFTableRow header = table.getRow(0);
+ ensureCells(header, 3);
+ setCellText(header.getCell(0), "璇勫垎椤�");
+ setCellText(header.getCell(1), "寰楀垎");
+ setCellText(header.getCell(2), "婊″垎");
+
+ for (int i = 1; i <= 5; i++) {
+ XWPFTableRow row = table.createRow();
+ ensureCells(row, 3);
+ setCellText(row.getCell(0), "绀轰緥椤圭洰" + i);
+ setCellText(row.getCell(1), String.valueOf(10 * i));
+ setCellText(row.getCell(2), "100");
+ }
+
+ // 绛惧瓧鍖�
+ XWPFParagraph spacer = doc.createParagraph();
+ spacer.setSpacingBefore(200);
+
+ XWPFTable signTable = doc.createTable(1, 2);
+ applyTableLayout(signTable, new int[]{6500, 2572});
+ XWPFTableRow row = signTable.getRow(0);
+ ensureCells(row, 2);
+ setCellText(row.getCell(0), "涓撳璇勫绛惧瓧锛歘______________");
+ setCellText(row.getCell(1), "绛惧瓧鏃ユ湡锛歘_________");
+
+ File out = new File("d:/code/new-ryc/tmp/docx-layout-sample.docx");
+ out.getParentFile().mkdirs();
+ try (FileOutputStream fos = new FileOutputStream(out)) {
+ doc.write(fos);
+ }
+ doc.close();
+ }
+}
\ No newline at end of file
diff --git a/check-all-education-data.js b/check-all-education-data.js
deleted file mode 100644
index 6b8d0ce..0000000
--- a/check-all-education-data.js
+++ /dev/null
@@ -1,131 +0,0 @@
-// 妫�鏌ユ墍鏈夊弬璧涗汉鐨勫鍘嗘暟鎹�
-const axios = require('axios');
-
-async function checkAllEducationData() {
- try {
- console.log('=== 妫�鏌ユ墍鏈夊弬璧涗汉鐨勫鍘嗘暟鎹� ===');
-
- // 鏌ヨ鎵�鏈夊弬璧涗汉
- const listQuery = `
- query {
- activityPlayerApplications(page: 1, size: 50) {
- content {
- id
- playerName
- projectName
- }
- totalElements
- }
- }
- `;
-
- const listResponse = await axios.post('http://localhost:8080/api/graphql', {
- query: listQuery
- }, {
- headers: {
- 'Content-Type': 'application/json'
- }
- });
-
- if (listResponse.data.errors) {
- console.log('鏌ヨ閿欒:', listResponse.data.errors);
- return;
- }
-
- const applications = listResponse.data.data?.activityPlayerApplications?.content || [];
- const total = listResponse.data.data?.activityPlayerApplications?.totalElements || 0;
-
- console.log(`鎬诲叡鎵惧埌 ${total} 涓弬璧涗汉锛屽紑濮嬫鏌ュ鍘嗘暟鎹�...`);
-
- let educationStats = {
- total: 0,
- hasEducation: 0,
- noEducation: 0,
- educationTypes: {}
- };
-
- // 妫�鏌ユ瘡涓弬璧涗汉鐨勫鍘�
- for (let i = 0; i < applications.length; i++) {
- const app = applications[i];
-
- // 鏌ヨ璇︽儏
- const detailQuery = `
- query GetActivityPlayerDetail($id: ID!) {
- activityPlayerDetail(id: $id) {
- id
- playerInfo {
- name
- education
- }
- }
- }
- `;
-
- try {
- const detailResponse = await axios.post('http://localhost:8080/api/graphql', {
- query: detailQuery,
- variables: { id: app.id }
- }, {
- headers: {
- 'Content-Type': 'application/json'
- }
- });
-
- if (detailResponse.data.errors) {
- console.log(`鍙傝禌浜� ${app.id} 鏌ヨ閿欒:`, detailResponse.data.errors);
- continue;
- }
-
- const detail = detailResponse.data.data?.activityPlayerDetail;
- if (!detail) {
- console.log(`鍙傝禌浜� ${app.id} 鏈壘鍒拌鎯卄);
- continue;
- }
-
- educationStats.total++;
- const education = detail.playerInfo.education || '';
-
- if (education && education.trim()) {
- educationStats.hasEducation++;
- if (educationStats.educationTypes[education]) {
- educationStats.educationTypes[education]++;
- } else {
- educationStats.educationTypes[education] = 1;
- }
-
- console.log(`鉁� 鍙傝禌浜� ${detail.playerInfo.name} (ID: ${app.id}) 鏈夊鍘�: "${education}"`);
- } else {
- educationStats.noEducation++;
- console.log(`鉂� 鍙傝禌浜� ${detail.playerInfo.name} (ID: ${app.id}) 瀛﹀巻涓虹┖`);
- }
-
- } catch (error) {
- console.log(`鍙傝禌浜� ${app.id} 鏌ヨ澶辫触:`, error.message);
- }
- }
-
- console.log('\n=== 瀛﹀巻鏁版嵁缁熻 ===');
- console.log(`鎬诲弬璧涗汉鏁�: ${educationStats.total}`);
- console.log(`鏈夊鍘嗘暟鎹�: ${educationStats.hasEducation}`);
- console.log(`鏃犲鍘嗘暟鎹�: ${educationStats.noEducation}`);
-
- if (educationStats.hasEducation > 0) {
- console.log('\n瀛﹀巻鍒嗗竷:');
- Object.entries(educationStats.educationTypes).forEach(([education, count]) => {
- console.log(` ${education}: ${count} 浜篳);
- });
- } else {
- console.log('\n鉂� 鎵�鏈夊弬璧涗汉閮芥病鏈夊鍘嗘暟鎹紒');
- console.log('鍙兘鐨勫師鍥�:');
- console.log('1. 鐢ㄦ埛鍦ㄦ敞鍐屾椂纭疄娌℃湁閫夋嫨瀛﹀巻');
- console.log('2. 娉ㄥ唽琛ㄥ崟鐨勫鍘嗗瓧娈垫湁闂');
- console.log('3. 鏁版嵁鎻愪氦鏃跺鍘嗗瓧娈典涪澶�');
- console.log('4. 鏁版嵁搴撳瓨鍌ㄦ椂鏈夐棶棰�');
- }
-
- } catch (error) {
- console.error('妫�鏌ュけ璐�:', error.message);
- }
-}
-
-checkAllEducationData();
\ No newline at end of file
diff --git a/check-database-activity-times.js b/check-database-activity-times.js
deleted file mode 100644
index ce45aac..0000000
--- a/check-database-activity-times.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const mysql = require('mysql2/promise');
-
-async function checkDatabaseActivityTimes() {
- console.log('馃攳 妫�鏌ユ暟鎹簱涓殑姣旇禌鏃堕棿鏁版嵁...\n');
-
- const connection = await mysql.createConnection({
- host: 'localhost',
- user: 'root',
- password: 'root',
- database: 'ryc',
- port: 3306
- });
-
- try {
- // 鏌ヨActivity琛ㄤ腑鐨勬椂闂村瓧娈�
- const [activities] = await connection.execute(`
- SELECT
- id,
- name,
- signup_deadline,
- match_time,
- created_at,
- updated_at
- FROM Activity
- WHERE id IN (16, 19, 22, 25, 28, 31)
- ORDER BY id
- `);
-
- console.log('馃搳 鏁版嵁搴撲腑鐨勬瘮璧涙椂闂存暟鎹�:');
- console.log('鈹�'.repeat(80));
-
- activities.forEach(activity => {
- console.log(`馃弳 ID: ${activity.id} - ${activity.name}`);
- console.log(` 馃搮 signup_deadline: ${activity.signup_deadline}`);
- console.log(` 馃弫 match_time: ${activity.match_time}`);
- console.log(` 馃摑 created_at: ${activity.created_at}`);
- console.log(` 馃攧 updated_at: ${activity.updated_at}`);
- console.log('鈹�'.repeat(40));
- });
-
- // 妫�鏌ユ槸鍚︽湁鍏朵粬鏃堕棿鐩稿叧鐨勫瓧娈�
- const [columns] = await connection.execute(`
- SHOW COLUMNS FROM Activity LIKE '%time%' OR SHOW COLUMNS FROM Activity LIKE '%date%'
- `);
-
- console.log('\n馃攳 Activity琛ㄤ腑鎵�鏈夋椂闂寸浉鍏冲瓧娈�:');
- columns.forEach(col => {
- console.log(` ${col.Field}: ${col.Type} (${col.Null === 'YES' ? 'nullable' : 'not null'})`);
- });
-
- } catch (error) {
- console.error('鉂� 鏁版嵁搴撴煡璇㈠け璐�:', error.message);
- } finally {
- await connection.end();
- }
-}
-
-checkDatabaseActivityTimes();
\ No newline at end of file
diff --git a/check-db-gender-education.js b/check-db-gender-education.js
deleted file mode 100644
index 87cd75b..0000000
--- a/check-db-gender-education.js
+++ /dev/null
@@ -1,139 +0,0 @@
-// 鐩存帴鏌ヨ鐗瑰畾鍙傝禌浜虹殑璇︽儏鏁版嵁
-const axios = require('axios');
-
-async function checkPlayerDetail(playerId) {
- const detailQuery = `
- query GetActivityPlayerDetail($id: ID!) {
- activityPlayerDetail(id: $id) {
- id
- projectName
- playerInfo {
- id
- name
- gender
- education
- birthday
- }
- regionInfo {
- name
- }
- }
- }
- `;
-
- try {
- const detailResponse = await axios.post('http://localhost:8080/api/graphql', {
- query: detailQuery,
- variables: { id: playerId }
- }, {
- headers: {
- 'Content-Type': 'application/json'
- }
- });
-
- if (detailResponse.data.errors) {
- console.log(' 璇︽儏鏌ヨ閿欒:', detailResponse.data.errors);
- return;
- }
-
- const detail = detailResponse.data.data?.activityPlayerDetail;
- if (!detail) {
- console.log(' 鏈壘鍒拌鎯呮暟鎹�');
- return;
- }
-
- console.log(' 璇︽儏鏁版嵁:');
- console.log(` 濮撳悕: ${detail.playerInfo.name}`);
- console.log(` 鎬у埆 (鍘熷): ${detail.playerInfo.gender} (${typeof detail.playerInfo.gender})`);
- console.log(` 瀛﹀巻 (鍘熷): "${detail.playerInfo.education}" (${typeof detail.playerInfo.education})`);
- console.log(` 鐢熸棩: ${detail.playerInfo.birthday}`);
- console.log(` 鍦板尯: ${detail.regionInfo?.name}`);
-
- // 娴嬭瘯鎬у埆杞崲閫昏緫
- let genderText = '鏈~鍐�';
- if (detail.playerInfo.gender === 0) genderText = '濂�';
- if (detail.playerInfo.gender === 1) genderText = '鐢�';
- console.log(` 鎬у埆杞崲缁撴灉: ${genderText}`);
-
- // 娴嬭瘯瀛﹀巻澶勭悊閫昏緫
- const education = detail.playerInfo.education || '';
- console.log(` 瀛﹀巻闀垮害: ${education.length}`);
- console.log(` 瀛﹀巻澶勭悊缁撴灉: ${education || '鏈~鍐�'}`);
-
- // 妫�鏌ラ棶棰�
- if (detail.playerInfo.gender === 1 && genderText === '濂�') {
- console.log(` 鉂� 鎬у埆杞崲閿欒: 搴旇鏄敺锛屼絾鏄剧ず涓哄コ`);
- }
- if (detail.playerInfo.education && detail.playerInfo.education.trim() && (education || '鏈~鍐�') === '鏈~鍐�') {
- console.log(` 鉂� 瀛﹀巻鏄剧ず閿欒: 鏈夊鍘嗕絾鏄剧ず涓烘湭濉啓`);
- }
-
- // 妫�鏌ュ綋鍓嶇殑getGenderText鍑芥暟閫昏緫
- console.log(` 褰撳墠getGenderText閫昏緫娴嬭瘯:`);
- console.log(` gender === 0 ? '濂�' : gender === 1 ? '鐢�' : '鏈~鍐�'`);
- const currentLogic = detail.playerInfo.gender === 0 ? '濂�' : detail.playerInfo.gender === 1 ? '鐢�' : '鏈~鍐�';
- console.log(` 缁撴灉: ${currentLogic}`);
-
- } catch (error) {
- console.log(` 鏌ヨ璇︽儏澶辫触: ${error.message}`);
- }
-}
-
-async function checkSpecificPlayerData() {
- try {
- // 鍏堟煡璇㈠弬璧涗汉鍒楄〃
- const listQuery = `
- query {
- activityPlayerApplications(page: 1, size: 20) {
- content {
- id
- playerName
- projectName
- phone
- state
- }
- }
- }
- `;
-
- console.log('=== 鏌ヨ鍙傝禌浜哄垪琛� ===');
- const listResponse = await axios.post('http://localhost:8080/api/graphql', {
- query: listQuery
- }, {
- headers: {
- 'Content-Type': 'application/json'
- }
- });
-
- if (listResponse.data.errors) {
- console.log('鍒楄〃鏌ヨ閿欒:', listResponse.data.errors);
- return;
- }
-
- const applications = listResponse.data.data?.activityPlayerApplications?.content || [];
-
- if (applications.length === 0) {
- console.log('娌℃湁鎵惧埌鍙傝禌浜烘暟鎹�');
- return;
- }
-
- console.log(`鎵惧埌 ${applications.length} 涓弬璧涗汉锛屽紑濮嬫煡璇㈣鎯�...`);
-
- // 鏌ヨ姣忎釜鍙傝禌浜虹殑璇︽儏
- for (let i = 0; i < Math.min(applications.length, 10); i++) {
- const app = applications[i];
- console.log(`\n=== 鍙傝禌浜� ${i + 1} (ID: ${app.id}) ===`);
- console.log(` 濮撳悕: ${app.playerName}`);
- console.log(` 椤圭洰鍚�: ${app.projectName}`);
- console.log(` 鐘舵��: ${app.state}`);
-
- // 鏌ヨ璇︽儏
- await checkPlayerDetail(app.id);
- }
-
- } catch (error) {
- console.error('鏌ヨ澶辫触:', error.message);
- }
-}
-
-checkSpecificPlayerData();
\ No newline at end of file
diff --git a/check-phone-db.js b/check-phone-db.js
deleted file mode 100644
index c4a5d4a..0000000
--- a/check-phone-db.js
+++ /dev/null
@@ -1,87 +0,0 @@
-const mysql = require('mysql2/promise');
-
-async function checkPhoneInDatabase() {
- const connection = await mysql.createConnection({
- host: '139.155.104.10',
- port: 3306,
- user: 'ryc',
- password: 'KiYap3E8X8RLcM6T',
- database: 'ryc',
- connectTimeout: 60000
- });
-
- try {
- console.log('=== 妫�鏌ユ暟鎹簱琛ㄧ粨鏋勫拰鎵嬫満鍙� 13981970816 ===\n');
-
- // 1. 鏌ョ湅鎵�鏈夎〃
- console.log('1. 鏌ョ湅鏁版嵁搴撲腑鐨勬墍鏈夎〃:');
- const [tables] = await connection.execute('SHOW TABLES');
- console.log('鏁版嵁搴撹〃:', tables.map(t => Object.values(t)[0]));
- console.log('');
-
- // 2. 鏌ョ湅鐢ㄦ埛鐩稿叧琛ㄧ殑缁撴瀯
- const userTables = tables.filter(t => Object.values(t)[0].includes('user')).map(t => Object.values(t)[0]);
-
- for (const tableName of userTables) {
- console.log(`${tableName} 琛ㄧ粨鏋�:`);
- try {
- const [structure] = await connection.execute(`DESCRIBE ${tableName}`);
- structure.forEach(col => {
- console.log(` ${col.Field}: ${col.Type}, Null: ${col.Null}, Key: ${col.Key}, Default: ${col.Default}`);
- });
- console.log('');
- } catch (err) {
- console.log(` 鏃犳硶鏌ョ湅 ${tableName} 琛ㄧ粨鏋�:`, err.message);
- }
- }
-
- // 3. 鏌ユ壘鍖呭惈phone瀛楁鐨勮〃
- console.log('3. 鏌ユ壘鍖呭惈phone瀛楁鐨勮〃:');
- for (const table of tables.map(t => Object.values(t)[0])) {
- try {
- const [columns] = await connection.execute(`SHOW COLUMNS FROM ${table} LIKE '%phone%'`);
- if (columns.length > 0) {
- console.log(`${table} 琛ㄥ寘鍚玴hone瀛楁:`, columns);
- }
- } catch (err) {
- // 蹇界暐閿欒锛岀户缁笅涓�涓〃
- }
- }
- console.log('');
-
- // 4. 濡傛灉鎵惧埌浜嗙敤鎴疯〃锛屾煡璇㈡墜鏈哄彿
- if (userTables.length > 0) {
- const mainUserTable = userTables[0]; // 浣跨敤绗竴涓敤鎴疯〃
- console.log(`4. 鍦� ${mainUserTable} 琛ㄤ腑鏌ユ壘鎵嬫満鍙� 13981970816:`);
-
- try {
- // 鍏堟煡鐪嬭〃缁撴瀯纭畾瀛楁鍚�
- const [structure] = await connection.execute(`DESCRIBE ${mainUserTable}`);
- const phoneField = structure.find(col => col.Field.toLowerCase().includes('phone'));
- const idField = structure.find(col => col.Field.toLowerCase().includes('id') && col.Key === 'PRI');
-
- if (phoneField) {
- const query = `SELECT * FROM ${mainUserTable} WHERE ${phoneField.Field} = ?`;
- const [users] = await connection.execute(query, ['13981970816']);
- console.log('鏌ヨ缁撴灉:', users);
-
- // 涔熸煡璇㈠寘鍚鎵嬫満鍙风殑璁板綍
- const likeQuery = `SELECT * FROM ${mainUserTable} WHERE ${phoneField.Field} LIKE ?`;
- const [likeUsers] = await connection.execute(likeQuery, ['%13981970816%']);
- console.log('妯$硦鏌ヨ缁撴灉:', likeUsers);
- } else {
- console.log('鏈壘鍒皃hone瀛楁');
- }
- } catch (err) {
- console.log('鏌ヨ鐢ㄦ埛琛ㄥ嚭閿�:', err.message);
- }
- }
-
- } catch (error) {
- console.error('鏁版嵁搴撴煡璇㈤敊璇�:', error);
- } finally {
- await connection.end();
- }
-}
-
-checkPhoneInDatabase();
\ No newline at end of file
diff --git a/check-user-judge.js b/check-user-judge.js
deleted file mode 100644
index f15066c..0000000
--- a/check-user-judge.js
+++ /dev/null
@@ -1,75 +0,0 @@
-const mysql = require('mysql2/promise');
-
-async function checkUserJudgeInfo() {
- const connection = await mysql.createConnection({
- host: '139.155.104.10',
- port: 3306,
- user: 'ryc',
- password: 'KiYap3E8X8RLcM6T',
- database: 'ryc'
- });
-
- try {
- console.log('妫�鏌ョ敤鎴稩D=152鐨勪俊鎭�...\n');
-
- // 妫�鏌ョ敤鎴峰熀鏈俊鎭�
- const [userRows] = await connection.execute(
- 'SELECT id, name, phone, wx_openid FROM t_user WHERE id = ?',
- [152]
- );
-
- if (userRows.length > 0) {
- console.log('鐢ㄦ埛鍩烘湰淇℃伅:');
- console.log(userRows[0]);
- } else {
- console.log('鏈壘鍒扮敤鎴稩D=152鐨勮褰�');
- return;
- }
-
- // 妫�鏌ヨ瘎濮斾俊鎭�
- const [judgeRows] = await connection.execute(
- 'SELECT id, user_id, name, title, company, state FROM t_judge WHERE user_id = ?',
- [152]
- );
-
- if (judgeRows.length > 0) {
- console.log('\n璇勫淇℃伅:');
- console.log(judgeRows[0]);
- } else {
- console.log('\n鏈壘鍒拌鐢ㄦ埛鐨勮瘎濮旇褰�');
- }
-
- // 妫�鏌ュ憳宸ヤ俊鎭�
- const [employeeRows] = await connection.execute(
- 'SELECT id, user_id, name, phone, role_id, state FROM t_employee WHERE user_id = ?',
- [152]
- );
-
- if (employeeRows.length > 0) {
- console.log('\n鍛樺伐淇℃伅:');
- console.log(employeeRows[0]);
- } else {
- console.log('\n鏈壘鍒拌鐢ㄦ埛鐨勫憳宸ヨ褰�');
- }
-
- // 妫�鏌ュ鍛樹俊鎭�
- const [playerRows] = await connection.execute(
- 'SELECT id, user_id, name, phone, state FROM t_player WHERE user_id = ?',
- [152]
- );
-
- if (playerRows.length > 0) {
- console.log('\n瀛﹀憳淇℃伅:');
- console.log(playerRows[0]);
- } else {
- console.log('\n鏈壘鍒拌鐢ㄦ埛鐨勫鍛樿褰�');
- }
-
- } catch (error) {
- console.error('鏌ヨ澶辫触:', error);
- } finally {
- await connection.end();
- }
-}
-
-checkUserJudgeInfo().catch(console.error);
\ No newline at end of file
diff --git a/clear-invalid-tokens.js b/clear-invalid-tokens.js
deleted file mode 100644
index f445506..0000000
--- a/clear-invalid-tokens.js
+++ /dev/null
@@ -1,86 +0,0 @@
-// 娓呯悊鏃犳晥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/debug-backend-user-context.js b/debug-backend-user-context.js
deleted file mode 100644
index 8ca4ded..0000000
--- a/debug-backend-user-context.js
+++ /dev/null
@@ -1,266 +0,0 @@
-const axios = require('axios');
-
-// 閰嶇疆
-const BASE_URL = 'http://localhost:8080/api';
-
-// 鑾峰彇鏂扮殑寰俊鐧诲綍token
-async function getNewWxToken() {
- console.log('=== 鑾峰彇鏂扮殑寰俊鐧诲綍token ===');
-
- try {
- // 浣跨敤GraphQL mutation杩涜寰俊鐧诲綍
- const wxLoginMutation = `
- mutation WxLogin($input: WxLoginRequest!) {
- wxLogin(input: $input) {
- token
- userInfo {
- userId
- name
- phone
- userType
- }
- success
- message
- hasJudge
- }
- }
- `;
-
- // 闇�瑕佷竴涓柊鐨勫井淇ode
- const wxCode = 'NEED_NEW_WX_CODE_HERE'; // 璇锋浛鎹负鏂扮殑寰俊code
-
- if (wxCode === 'NEED_NEW_WX_CODE_HERE') {
- console.log('鉂� 璇峰厛鏇挎崲鑴氭湰涓殑寰俊code');
- return null;
- }
-
- const response = await axios.post(`${BASE_URL}/graphql`, {
- query: wxLoginMutation,
- variables: {
- input: {
- code: wxCode,
- wxOpenid: "ogxxA1-KrSVTdqI9T1uaB1BQwPGU", // 浣跨敤宸茬煡鐨刼penid
- loginIp: "127.0.0.1",
- deviceInfo: "test-device",
- phoneAuthorized: false
- }
- }
- });
-
- if (response.data.errors) {
- console.log('鉂� 寰俊鐧诲綍澶辫触:', response.data.errors);
- return null;
- }
-
- const loginData = response.data.data.wxLogin;
- console.log('鉁� 寰俊鐧诲綍鎴愬姛:');
- console.log('- Token:', loginData.token ? '宸茬敓鎴�' : '鏈敓鎴�');
- console.log('- 鐢ㄦ埛ID:', loginData.userInfo?.userId);
- console.log('- 鐢ㄦ埛鍚�:', loginData.userInfo?.name);
- console.log('- 鐢ㄦ埛绫诲瀷:', loginData.userInfo?.userType);
- console.log('- 鏄惁鏈夎瘎濮旀潈闄�:', loginData.hasJudge);
-
- return loginData.token;
-
- } catch (error) {
- console.error('鉂� 寰俊鐧诲綍澶辫触:', error.response?.data || error.message);
- return null;
- }
-}
-
-// 浣跨敤宸茬煡鐨則oken杩涜娴嬭瘯
-async function testWithKnownToken() {
- console.log('\n=== 浣跨敤宸茬煡token娴嬭瘯 ===');
-
- // 杩欓噷浣跨敤涓�涓凡鐭ョ殑token锛堢敤鎴烽渶瑕佹彁渚涳級
- const knownToken = 'PASTE_YOUR_VALID_TOKEN_HERE';
-
- if (knownToken === 'PASTE_YOUR_VALID_TOKEN_HERE') {
- console.log('鉂� 璇峰厛鏇挎崲鑴氭湰涓殑token');
- return;
- }
-
- await debugUserContext(knownToken);
-}
-
-// 璋冭瘯鐢ㄦ埛涓婁笅鏂�
-async function debugUserContext(token) {
- console.log('\n=== 璋冭瘯鐢ㄦ埛涓婁笅鏂� ===');
-
- // 1. 娴嬭瘯鑾峰彇褰撳墠鐢ㄦ埛淇℃伅
- console.log('1. 娴嬭瘯鑾峰彇褰撳墠鐢ㄦ埛淇℃伅:');
- try {
- const userQuery = `
- query GetCurrentUser {
- currentUser {
- id
- name
- phone
- }
- }
- `;
-
- const response = await axios.post(`${BASE_URL}/graphql`, {
- query: userQuery
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- }
- });
-
- if (response.data.errors) {
- console.log('鉂� 鑾峰彇褰撳墠鐢ㄦ埛澶辫触:', response.data.errors);
- } else if (response.data.data?.currentUser) {
- const user = response.data.data.currentUser;
- console.log('鉁� 褰撳墠鐢ㄦ埛淇℃伅:');
- console.log(` 鐢ㄦ埛ID: ${user.id}`);
- console.log(` 濮撳悕: ${user.name}`);
- console.log(` 鎵嬫満鍙�: ${user.phone}`);
- } else {
- console.log('鈿狅笍 鏃犳硶鑾峰彇褰撳墠鐢ㄦ埛淇℃伅');
- }
- } catch (error) {
- console.log('鉂� 鑾峰彇褰撳墠鐢ㄦ埛澶辫触:', error.response?.data || error.message);
- }
-
- // 2. 娴嬭瘯鑾峰彇褰撳墠璇勫淇℃伅
- console.log('\n2. 娴嬭瘯鑾峰彇褰撳墠璇勫淇℃伅:');
- try {
- const judgeQuery = `
- query GetCurrentJudge {
- currentJudgeInfo {
- judgeId
- judgeName
- title
- company
- }
- }
- `;
-
- const response = await axios.post(`${BASE_URL}/graphql`, {
- query: judgeQuery
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- }
- });
-
- if (response.data.errors) {
- console.log('鉂� 鑾峰彇褰撳墠璇勫澶辫触:', response.data.errors);
- } else if (response.data.data?.currentJudgeInfo) {
- const judge = response.data.data.currentJudgeInfo;
- console.log('鉁� 褰撳墠璇勫淇℃伅:');
- console.log(` 璇勫ID: ${judge.judgeId}`);
- console.log(` 璇勫鍚�: ${judge.judgeName}`);
- console.log(` 鑱屼綅: ${judge.title}`);
- console.log(` 鍏徃: ${judge.company}`);
- } else {
- console.log('鈿狅笍 鏃犳硶鑾峰彇褰撳墠璇勫淇℃伅锛堝彲鑳戒笉鏄瘎濮旓級');
- }
- } catch (error) {
- console.log('鉂� 鑾峰彇褰撳墠璇勫澶辫触:', error.response?.data || error.message);
- }
-
- // 3. 娴嬭瘯璇勫缁熻鏌ヨ
- console.log('\n3. 娴嬭瘯璇勫缁熻鏌ヨ:');
- try {
- const statsQuery = `
- query GetReviewStats {
- reviewStatistics {
- unReviewedCount
- reviewedCount
- studentUnReviewedCount
- }
- }
- `;
-
- const response = await axios.post(`${BASE_URL}/graphql`, {
- query: statsQuery
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- }
- });
-
- if (response.data.errors) {
- console.log('鉂� 鑾峰彇璇勫缁熻澶辫触:', response.data.errors);
- response.data.errors.forEach(error => {
- console.log(` 閿欒: ${error.message}`);
- if (error.extensions) {
- console.log(` 鎵╁睍淇℃伅:`, error.extensions);
- }
- });
- } else if (response.data.data?.reviewStatistics) {
- const stats = response.data.data.reviewStatistics;
- console.log('鉁� 璇勫缁熻:');
- console.log(` 鏈瘎瀹�: ${stats.unReviewedCount}`);
- console.log(` 宸茶瘎瀹�: ${stats.reviewedCount}`);
- console.log(` 瀛﹀憳鏈瘎瀹�: ${stats.studentUnReviewedCount}`);
- }
- } catch (error) {
- console.log('鉂� 鑾峰彇璇勫缁熻澶辫触:', error.response?.data || error.message);
- }
-
- // 4. 娴嬭瘯绠�鍗曠殑璇勫椤圭洰鏌ヨ
- console.log('\n4. 娴嬭瘯璇勫椤圭洰鏌ヨ:');
- try {
- const projectsQuery = `
- query GetUnreviewedProjects {
- unReviewedProjects(searchKeyword: "", page: 1, pageSize: 1) {
- totalCount
- currentPage
- }
- }
- `;
-
- const response = await axios.post(`${BASE_URL}/graphql`, {
- query: projectsQuery
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- }
- });
-
- if (response.data.errors) {
- console.log('鉂� 鑾峰彇璇勫椤圭洰澶辫触:', response.data.errors);
- response.data.errors.forEach(error => {
- console.log(` 閿欒: ${error.message}`);
- });
- } else if (response.data.data?.unReviewedProjects) {
- const projects = response.data.data.unReviewedProjects;
- console.log('鉁� 璇勫椤圭洰鏌ヨ鎴愬姛:');
- console.log(` 鎬绘暟: ${projects.totalCount}`);
- console.log(` 褰撳墠椤�: ${projects.currentPage}`);
- }
- } catch (error) {
- console.log('鉂� 鑾峰彇璇勫椤圭洰澶辫触:', error.response?.data || error.message);
- }
-}
-
-// 涓诲嚱鏁�
-async function main() {
- console.log('馃攳 寮�濮嬭皟璇曞悗绔敤鎴蜂笂涓嬫枃闂...\n');
-
- // 閫夋嫨娴嬭瘯鏂瑰紡
- const useNewToken = false; // 璁剧疆涓簍rue浣跨敤鏂皌oken锛宖alse浣跨敤宸茬煡token
-
- if (useNewToken) {
- const token = await getNewWxToken();
- if (token) {
- await debugUserContext(token);
- }
- } else {
- await testWithKnownToken();
- }
-}
-
-// 杩愯涓诲嚱鏁�
-if (require.main === module) {
- main();
-}
-
-module.exports = { debugUserContext, getNewWxToken };
\ No newline at end of file
diff --git a/debug-check-phone.js b/debug-check-phone.js
deleted file mode 100644
index 3c6dccc..0000000
--- a/debug-check-phone.js
+++ /dev/null
@@ -1,101 +0,0 @@
-const axios = require('axios');
-
-const API_BASE_URL = 'http://localhost:8080/api/graphql';
-const LOGIN_URL = 'http://localhost:8080/api/auth/web-login';
-
-// 鐧诲綍鍑芥暟
-async function login(phone, password) {
- try {
- const response = await axios.post(LOGIN_URL, {
- phone: phone,
- password: password
- });
-
- if (response.data.token) {
- return response.data;
- } else {
- console.error('鐧诲綍澶辫触: 娌℃湁杩斿洖token');
- return null;
- }
- } catch (error) {
- console.error('鐧诲綍璇锋眰澶辫触:', error.message);
- return null;
- }
-}
-
-// 鏌ヨ鎵�鏈夊憳宸�
-async function getAllEmployees(token) {
- const query = `
- query {
- employees {
- id
- name
- phone
- roleId
- description
- state
- createTime
- updateTime
- }
- }
- `;
-
- try {
- const response = await axios.post(API_BASE_URL, {
- query: query
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`
- }
- });
-
- if (response.data.errors) {
- console.error('鏌ヨ鍛樺伐澶辫触:', response.data.errors);
- return [];
- }
-
- return response.data.data.employees;
- } catch (error) {
- console.error('鏌ヨ鍛樺伐璇锋眰澶辫触:', error.message);
- return [];
- }
-}
-
-async function main() {
- console.log('寮�濮嬫鏌ユ墜鏈哄彿浣跨敤鎯呭喌...');
-
- // 浣跨敤绠$悊鍛樿处鍙风櫥褰�
- const loginResult = await login('17898163888', '123456');
- if (!loginResult) {
- console.error('鐧诲綍澶辫触');
- return;
- }
-
- console.log('鐧诲綍鎴愬姛');
-
- // 鑾峰彇鎵�鏈夊憳宸�
- const employees = await getAllEmployees(loginResult.token);
- console.log(`\n鎵惧埌 ${employees.length} 涓憳宸�:`);
-
- employees.forEach(emp => {
- console.log(`鍛樺伐ID: ${emp.id}, 濮撳悕: ${emp.name}, 鎵嬫満鍙�: ${emp.phone}, 瑙掕壊: ${emp.roleId}, 鐘舵��: ${emp.state}`);
- });
-
- // 妫�鏌ョ壒瀹氭墜鏈哄彿
- const targetPhones = ['13981970816', '13512331233'];
-
- targetPhones.forEach(targetPhone => {
- const existingEmployee = employees.find(emp => emp.phone === targetPhone);
-
- if (existingEmployee) {
- console.log(`\n鉂� 鎵嬫満鍙� ${targetPhone} 宸茶鍛樺伐浣跨敤:`);
- console.log(` 鍛樺伐ID: ${existingEmployee.id}`);
- console.log(` 鍛樺伐濮撳悕: ${existingEmployee.name}`);
- console.log(` 瑙掕壊: ${existingEmployee.roleId}`);
- } else {
- console.log(`\n鉁� 鎵嬫満鍙� ${targetPhone} 鏈浠讳綍鍛樺伐浣跨敤`);
- }
- });
-}
-
-main().catch(console.error);
\ No newline at end of file
diff --git a/debug-dataset-issue.md b/debug-dataset-issue.md
deleted file mode 100644
index bfb4134..0000000
--- a/debug-dataset-issue.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# onDetailTap 涓� dataset.id 閿欒闂璋冭瘯鎶ュ憡
-
-## 闂鎻忚堪
-鐢ㄦ埛鍙嶉 `onDetailTap` 涓娇鐢ㄧ殑 `dataset.id` 鏄敊璇殑銆�
-
-## 宸叉鏌ョ殑鍐呭
-
-### 1. 妯℃澘缁戝畾妫�鏌�
-- 鉁� 妯℃澘涓纭娇鐢ㄤ簡 `data-id="{{item.id}}"`
-- 鉁� 鎸夐挳姝g‘缁戝畾浜� `catchtap="onDetailTap"`
-- 鉁� 淇浜嗘嫾鍐欓敊璇細`<viwe>` 鈫� `<view>`
-
-### 2. 鏁版嵁娴佹鏌�
-- 鉁� GraphQL 鏌ヨ杩斿洖鐨勬椿鍔ㄦ暟鎹腑 ID 瀛楁姝e父
-- 鉁� 鎵�鏈夋椿鍔� ID 閮芥槸瀛楃涓茬被鍨�
-- 鉁� `onDetailTap` 鍑芥暟姝g‘鑾峰彇 `e.currentTarget.dataset.id`
-- 鉁� `goToActivityDetail` 鍑芥暟姝g‘浼犻�掑弬鏁�
-
-### 3. 鍙傛暟浼犻�掓鏌�
-- 鉁� `utils.navigateTo` 姝g‘鏋勫缓 URL 鍙傛暟
-- 鉁� 璇︽儏椤� `onLoad` 姝g‘鎺ユ敹 `options.id` 鍙傛暟
-
-## 鍙兘鐨勯棶棰樺師鍥�
-
-### 1. 浜嬩欢鍐掓场闂
-铏界劧浣跨敤浜� `catchtap` 闃绘鍐掓场锛屼絾鍙兘瀛樺湪鍏朵粬鐐瑰嚮浜嬩欢骞叉壈銆�
-
-### 2. 鏁版嵁鏇存柊鏃舵満闂
-鍙兘鍦ㄦ暟鎹繕鏈畬鍏ㄥ姞杞芥椂灏辫Е鍙戜簡鐐瑰嚮浜嬩欢銆�
-
-### 3. 灏忕▼搴忕幆澧冪壒娈婃��
-鍦ㄥ疄闄呭皬绋嬪簭鐜涓彲鑳藉瓨鍦ㄤ笌娴嬭瘯鐜涓嶅悓鐨勮涓恒��
-
-### 4. 缂撳瓨闂
-鍙兘瀛樺湪鏃т唬鐮佺紦瀛樺鑷寸殑闂銆�
-
-## 寤鸿鐨勮皟璇曟楠�
-
-### 1. 娣诲姞璋冭瘯鏃ュ織
-鍦� `onDetailTap` 鍑芥暟涓坊鍔犺缁嗙殑璋冭瘯鏃ュ織锛�
-
-```javascript
-onDetailTap(e) {
- console.log('=== onDetailTap 璋冭瘯淇℃伅 ===');
- console.log('浜嬩欢瀵硅薄:', e);
- console.log('currentTarget:', e.currentTarget);
- console.log('dataset:', e.currentTarget.dataset);
- console.log('dataset.id:', e.currentTarget.dataset.id);
- console.log('dataset.id 绫诲瀷:', typeof e.currentTarget.dataset.id);
-
- const id = e.currentTarget.dataset.id;
- if (id) {
- console.log('鍑嗗璺宠浆锛孖D:', id);
- this.goToActivityDetail(id);
- } else {
- console.log('鉂� ID 涓虹┖鎴栨湭瀹氫箟');
- console.log('瀹屾暣 dataset:', JSON.stringify(e.currentTarget.dataset));
- }
-}
-```
-
-### 2. 妫�鏌ユ暟鎹姞杞界姸鎬�
-纭繚鍦ㄦ暟鎹畬鍏ㄥ姞杞藉悗鎵嶆樉绀烘寜閽細
-
-```xml
-<button
- wx:if="{{item.id}}"
- class="ghost-btn"
- catchtap="onDetailTap"
- data-id="{{item.id}}"
->
- 鏌ョ湅璇︽儏
-</button>
-```
-
-### 3. 娓呴櫎缂撳瓨
-- 娓呴櫎灏忕▼搴忕紦瀛�
-- 閲嶆柊缂栬瘧椤圭洰
-- 閲嶅惎寮�鍙戣�呭伐鍏�
-
-## 褰撳墠鐘舵��
-- 鉁� 淇浜嗘ā鏉夸腑鐨勬嫾鍐欓敊璇�
-- 鉁� 楠岃瘉浜嗘暟鎹祦鐨勬纭��
-- 鈴� 绛夊緟鐢ㄦ埛鍙嶉鍏蜂綋鐨勯敊璇儏鍐�
-
-## 涓嬩竴姝ヨ鍔�
-1. 璇风敤鎴锋彁渚涘叿浣撶殑閿欒淇℃伅鎴栨埅鍥�
-2. 鍦ㄥ疄闄呯幆澧冧腑娣诲姞璋冭瘯鏃ュ織
-3. 妫�鏌ユ槸鍚﹀瓨鍦ㄧ壒瀹氭潯浠朵笅鐨勯棶棰�
\ No newline at end of file
diff --git a/debug-employee-check.js b/debug-employee-check.js
deleted file mode 100644
index b1b271d..0000000
--- a/debug-employee-check.js
+++ /dev/null
@@ -1,133 +0,0 @@
-const axios = require('axios');
-
-const BASE_URL = 'http://localhost:8080';
-
-// 鐧诲綍鍑芥暟
-async function login() {
- try {
- const loginData = {
- phone: '17898163888',
- password: '123456'
- };
-
- console.log('姝e湪鐧诲綍...');
- const response = await axios.post(`${BASE_URL}/api/auth/web-login`, loginData);
-
- if (response.status === 200 && response.data.success) {
- console.log('鐧诲綍鎴愬姛');
- return response.data.data.token;
- } else {
- console.error('鐧诲綍澶辫触:', response.data);
- return null;
- }
- } catch (error) {
- console.error('鐧诲綍璇锋眰澶辫触:', error.message);
- return null;
- }
-}
-
-// 鏌ヨ褰撳墠鐢ㄦ埛淇℃伅
-async function getCurrentUserInfo(token) {
- try {
- const query = `
- query {
- currentUser {
- id
- name
- phone
- }
- }
- `;
-
- const response = await axios.post(`${BASE_URL}/api/graphql`, {
- query: query
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- }
- });
-
- console.log('褰撳墠鐢ㄦ埛淇℃伅:', JSON.stringify(response.data, null, 2));
- return response.data.data.currentUser;
- } catch (error) {
- console.error('鏌ヨ褰撳墠鐢ㄦ埛澶辫触:', error.message);
- return null;
- }
-}
-
-// 鏌ヨ鎵�鏈夊憳宸�
-async function getAllEmployees(token) {
- try {
- const query = `
- query {
- employees {
- id
- name
- phone
- roleId
- description
- }
- }
- `;
-
- const response = await axios.post(`${BASE_URL}/api/graphql`, {
- query: query
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- }
- });
-
- console.log('鎵�鏈夊憳宸ヤ俊鎭�:', JSON.stringify(response.data, null, 2));
- return response.data.data.employees;
- } catch (error) {
- console.error('鏌ヨ鍛樺伐澶辫触:', error.message);
- return null;
- }
-}
-
-// 涓诲嚱鏁�
-async function main() {
- console.log('=== 妫�鏌ュ綋鍓嶇敤鎴锋槸鍚﹀凡缁忔槸鍛樺伐 ===');
-
- // 1. 鐧诲綍
- const token = await login();
- if (!token) {
- console.error('鐧诲綍澶辫触锛岄��鍑�');
- return;
- }
-
- // 2. 鑾峰彇褰撳墠鐢ㄦ埛淇℃伅
- const currentUser = await getCurrentUserInfo(token);
- if (!currentUser) {
- console.error('鑾峰彇褰撳墠鐢ㄦ埛淇℃伅澶辫触');
- return;
- }
-
- // 3. 鑾峰彇鎵�鏈夊憳宸ヤ俊鎭�
- const employees = await getAllEmployees(token);
- if (!employees) {
- console.error('鑾峰彇鍛樺伐淇℃伅澶辫触');
- return;
- }
-
- // 4. 妫�鏌ュ綋鍓嶇敤鎴锋槸鍚﹀凡缁忔槸鍛樺伐
- const currentUserPhone = currentUser.phone;
- const isEmployee = employees.some(emp => emp.phone === currentUserPhone);
-
- console.log('\n=== 妫�鏌ョ粨鏋� ===');
- console.log(`褰撳墠鐢ㄦ埛鎵嬫満鍙�: ${currentUserPhone}`);
- console.log(`鏄惁宸茬粡鏄憳宸�: ${isEmployee}`);
-
- if (isEmployee) {
- const employeeInfo = employees.find(emp => emp.phone === currentUserPhone);
- console.log('鍛樺伐淇℃伅:', employeeInfo);
- console.log('\n杩欏氨鏄负浠�涔堝垱寤烘柊鍛樺伐澶辫触鐨勫師鍥狅細褰撳墠鐧诲綍鐢ㄦ埛宸茬粡鏄憳宸ヤ簡锛�');
- } else {
- console.log('褰撳墠鐢ㄦ埛涓嶆槸鍛樺伐锛屽彲浠ュ垱寤烘柊鍛樺伐璁板綍');
- }
-}
-
-main().catch(console.error);
\ No newline at end of file
diff --git a/debug-employee.js b/debug-employee.js
deleted file mode 100644
index 396aac3..0000000
--- a/debug-employee.js
+++ /dev/null
@@ -1,63 +0,0 @@
-const axios = require('axios');
-
-async function debugEmployeeSave() {
- try {
- console.log('1. 鐧诲綍鑾峰彇token...');
- const loginResponse = await axios.post('http://localhost:8080/api/auth/web-login', {
- phone: '17898163888',
- password: '123456'
- });
-
- const token = loginResponse.data.token;
- console.log('鐧诲綍鎴愬姛');
-
- // 2. 灏濊瘯淇濆瓨鍛樺伐
- console.log('2. 淇濆瓨鍛樺伐...');
- const uniquePhone = '139' + Date.now().toString().slice(-8);
- console.log('浣跨敤鎵嬫満鍙�:', uniquePhone);
-
- const employeeData = {
- name: '璋冭瘯鍛樺伐' + Date.now(),
- phone: uniquePhone,
- password: '123456',
- roleId: 'EMPLOYEE',
- description: '璋冭瘯鍛樺伐鎻忚堪'
- };
-
- console.log('鍛樺伐鏁版嵁:', JSON.stringify(employeeData, null, 2));
-
- const saveResponse = await axios.post('http://localhost:8080/api/graphql', {
- query: `
- mutation SaveEmployee($input: EmployeeInput!) {
- saveEmployee(input: $input) {
- id
- name
- phone
- roleId
- description
- }
- }
- `,
- variables: {
- input: employeeData
- }
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- }
- });
-
- console.log('淇濆瓨鍝嶅簲鐘舵��:', saveResponse.status);
- console.log('淇濆瓨鍝嶅簲鏁版嵁:', JSON.stringify(saveResponse.data, null, 2));
-
- } catch (error) {
- console.error('閿欒:', error.message);
- if (error.response) {
- console.error('鍝嶅簲鐘舵��:', error.response.status);
- console.error('鍝嶅簲鏁版嵁:', JSON.stringify(error.response.data, null, 2));
- }
- }
-}
-
-debugEmployeeSave();
\ No newline at end of file
diff --git a/debug-gender-education-data.js b/debug-gender-education-data.js
deleted file mode 100644
index a772b1d..0000000
--- a/debug-gender-education-data.js
+++ /dev/null
@@ -1,90 +0,0 @@
-// 璋冭瘯鎬у埆鍜屽鍘嗘樉绀洪棶棰�
-const axios = require('axios');
-
-async function testGenderEducationData() {
- try {
- // 浣跨敤GraphQL鏌ヨ鑾峰彇瀹為檯鐨勫弬璧涗汉璇︽儏鏁版嵁
- const query = `
- query GetActivityPlayerDetail($id: ID!) {
- activityPlayerDetail(id: $id) {
- id
- projectName
- description
- playerInfo {
- id
- name
- gender
- birthday
- education
- userInfo {
- avatarUrl
- }
- }
- regionInfo {
- id
- name
- }
- }
- }
- `;
-
- // 娴嬭瘯鍑犱釜涓嶅悓鐨勫弬璧涗汉ID
- const testIds = [1, 2, 3]; // 鍙互鏍规嵁瀹為檯鏁版嵁璋冩暣
-
- for (const id of testIds) {
- console.log(`\n=== 娴嬭瘯鍙傝禌浜篒D: ${id} ===`);
-
- try {
- const response = await axios.post('http://localhost:8080/api/graphql', {
- query: query,
- variables: { id: id.toString() }
- }, {
- headers: {
- 'Content-Type': 'application/json'
- }
- });
-
- if (response.data.errors) {
- console.log('GraphQL閿欒:', response.data.errors);
- continue;
- }
-
- const detail = response.data.data?.activityPlayerDetail;
- if (!detail) {
- console.log('鏈壘鍒版暟鎹�');
- continue;
- }
-
- console.log('鍘熷鍚庣鏁版嵁:');
- console.log(' 濮撳悕:', detail.playerInfo.name);
- console.log(' 鎬у埆 (鍘熷鍊�):', detail.playerInfo.gender, typeof detail.playerInfo.gender);
- console.log(' 瀛﹀巻 (鍘熷鍊�):', detail.playerInfo.education, typeof detail.playerInfo.education);
- console.log(' 鐢熸棩:', detail.playerInfo.birthday);
- console.log(' 鍦板尯:', detail.regionInfo?.name);
-
- // 妯℃嫙鍓嶇鐨勬�у埆杞崲閫昏緫
- function getGenderText(gender) {
- console.log(' 鎬у埆杞崲杈撳叆:', gender, typeof gender);
- if (gender === 0) return '濂�'
- if (gender === 1) return '鐢�'
- return '鏈~鍐�'
- }
-
- const convertedGender = getGenderText(detail.playerInfo.gender);
- console.log(' 鎬у埆杞崲缁撴灉:', convertedGender);
-
- // 妫�鏌ュ鍘嗗鐞�
- const education = detail.playerInfo.education || '';
- console.log(' 瀛﹀巻澶勭悊缁撴灉:', education || '鏈~鍐�');
-
- } catch (error) {
- console.log(`ID ${id} 鏌ヨ澶辫触:`, error.message);
- }
- }
-
- } catch (error) {
- console.error('娴嬭瘯澶辫触:', error.message);
- }
-}
-
-testGenderEducationData();
\ No newline at end of file
diff --git a/debug-jwt-token.js b/debug-jwt-token.js
deleted file mode 100644
index 3baf224..0000000
--- a/debug-jwt-token.js
+++ /dev/null
@@ -1,288 +0,0 @@
-const axios = require('axios');
-
-// 閰嶇疆
-const BASE_URL = 'http://localhost:8080/api';
-
-// JWT token瑙g爜鍑芥暟锛堜笉楠岃瘉绛惧悕锛屼粎鐢ㄤ簬璋冭瘯锛�
-function decodeJwtToken(token) {
- try {
- // JWT token鏍煎紡锛歨eader.payload.signature
- const parts = token.split('.');
- if (parts.length !== 3) {
- throw new Error('Invalid JWT token format');
- }
-
- // 瑙g爜header
- const header = JSON.parse(Buffer.from(parts[0], 'base64url').toString());
-
- // 瑙g爜payload
- const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString());
-
- return {
- header,
- payload,
- signature: parts[2]
- };
- } catch (error) {
- console.error('JWT token瑙g爜澶辫触:', error.message);
- return null;
- }
-}
-
-// 娴嬭瘯JWT token鍐呭
-async function debugJwtToken(token) {
- console.log('=== JWT Token 璋冭瘯 ===');
-
- if (!token || token === 'PASTE_YOUR_VALID_TOKEN_HERE') {
- console.log('鉂� 璇锋彁渚涙湁鏁堢殑JWT token');
- return;
- }
-
- console.log('Token闀垮害:', token.length);
- console.log('Token鍓�50瀛楃:', token.substring(0, 50) + '...');
-
- // 瑙g爜JWT token
- const decoded = decodeJwtToken(token);
- if (decoded) {
- console.log('\n馃搵 JWT Token 鍐呭:');
- console.log('Header:', JSON.stringify(decoded.header, null, 2));
- console.log('Payload:', JSON.stringify(decoded.payload, null, 2));
-
- // 妫�鏌ュ叧閿瓧娈�
- if (decoded.payload.userId) {
- console.log(`\n馃攳 鐢ㄦ埛ID: ${decoded.payload.userId}`);
- console.log(` 绫诲瀷: ${typeof decoded.payload.userId}`);
- console.log(` 鏄惁涓鸿礋鏁�: ${decoded.payload.userId < 0}`);
- } else {
- console.log('\n鈿狅笍 Token涓病鏈夋壘鍒皍serId瀛楁');
- }
-
- if (decoded.payload.sub) {
- console.log(`\n馃攳 Subject: ${decoded.payload.sub}`);
- }
-
- if (decoded.payload.exp) {
- const expDate = new Date(decoded.payload.exp * 1000);
- const now = new Date();
- console.log(`\n鈴� Token杩囨湡鏃堕棿: ${expDate.toLocaleString()}`);
- console.log(` 褰撳墠鏃堕棿: ${now.toLocaleString()}`);
- console.log(` 鏄惁宸茶繃鏈�: ${now > expDate}`);
- }
- }
-
- // 娴嬭瘯token楠岃瘉
- console.log('\n=== Token 楠岃瘉娴嬭瘯 ===');
- await testTokenValidation(token);
-}
-
-// 娴嬭瘯token楠岃瘉
-async function testTokenValidation(token) {
- try {
- // 1. 娴嬭瘯绠�鍗曠殑GraphQL鏌ヨ
- console.log('1. 娴嬭瘯绠�鍗曟煡璇�:');
- const simpleQuery = `
- query {
- __typename
- }
- `;
-
- const response = await axios.post(`${BASE_URL}/graphql`, {
- query: simpleQuery
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- }
- });
-
- if (response.status === 200) {
- console.log('鉁� Token楠岃瘉閫氳繃锛堝熀纭�鏌ヨ鎴愬姛锛�');
- } else {
- console.log('鉂� Token楠岃瘉澶辫触锛岀姸鎬佺爜:', response.status);
- }
-
- } catch (error) {
- console.log('鉂� Token楠岃瘉澶辫触:', error.response?.status, error.response?.data || error.message);
- }
-
- try {
- // 2. 娴嬭瘯闇�瑕佽璇佺殑鏌ヨ
- console.log('\n2. 娴嬭瘯璁よ瘉鏌ヨ:');
- const authQuery = `
- query GetCurrentUser {
- currentUser {
- id
- name
- phone
- }
- }
- `;
-
- const response = await axios.post(`${BASE_URL}/graphql`, {
- query: authQuery
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- }
- });
-
- if (response.data.errors) {
- console.log('鉂� 璁よ瘉鏌ヨ澶辫触:', response.data.errors);
- } else if (response.data.data?.currentUser) {
- const user = response.data.data.currentUser;
- console.log('鉁� 璁よ瘉鏌ヨ鎴愬姛:');
- console.log(` 鐢ㄦ埛ID: ${user.id}`);
- console.log(` 濮撳悕: ${user.name}`);
- console.log(` 鎵嬫満鍙�: ${user.phone}`);
-
- // 妫�鏌ョ敤鎴稩D鏄惁鍖归厤
- if (user.id === 152) {
- console.log('鉁� 鐢ㄦ埛ID鍖归厤锛�152锛�');
- } else {
- console.log(`鈿狅笍 鐢ㄦ埛ID涓嶅尮閰嶏紝鏈熸湜152锛屽疄闄�${user.id}`);
- }
- } else {
- console.log('鈿狅笍 璁よ瘉鏌ヨ杩斿洖绌虹粨鏋�');
- }
-
- } catch (error) {
- console.log('鉂� 璁よ瘉鏌ヨ澶辫触:', error.response?.status, error.response?.data || error.message);
- }
-
- try {
- // 3. 娴嬭瘯璇勫鏌ヨ
- console.log('\n3. 娴嬭瘯璇勫鏌ヨ:');
- const judgeQuery = `
- query GetCurrentJudge {
- currentJudgeInfo {
- judgeId
- judgeName
- title
- company
- }
- }
- `;
-
- const response = await axios.post(`${BASE_URL}/graphql`, {
- query: judgeQuery
- }, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- 'Content-Type': 'application/json'
- }
- });
-
- if (response.data.errors) {
- console.log('鉂� 璇勫鏌ヨ澶辫触:', response.data.errors);
- } else if (response.data.data?.currentJudgeInfo) {
- const judge = response.data.data.currentJudgeInfo;
- console.log('鉁� 璇勫鏌ヨ鎴愬姛:');
- console.log(` 璇勫ID: ${judge.judgeId}`);
- console.log(` 璇勫鍚�: ${judge.judgeName}`);
-
- // 妫�鏌ヨ瘎濮擨D鏄惁鍖归厤
- if (judge.judgeId === 72) {
- console.log('鉁� 璇勫ID鍖归厤锛�72锛�');
- } else {
- console.log(`鈿狅笍 璇勫ID涓嶅尮閰嶏紝鏈熸湜72锛屽疄闄�${judge.judgeId}`);
- }
- } else {
- console.log('鈿狅笍 璇勫鏌ヨ杩斿洖绌虹粨鏋滐紙鍙兘涓嶆槸璇勫锛�');
- }
-
- } catch (error) {
- console.log('鉂� 璇勫鏌ヨ澶辫触:', error.response?.status, error.response?.data || error.message);
- }
-}
-
-// 鑾峰彇鏂扮殑寰俊鐧诲綍token骞惰皟璇�
-async function getAndDebugNewToken() {
- console.log('=== 鑾峰彇鏂扮殑寰俊鐧诲綍token ===');
-
- try {
- const wxLoginMutation = `
- mutation WxLogin($input: WxLoginRequest!) {
- wxLogin(input: $input) {
- token
- userInfo {
- userId
- name
- phone
- userType
- }
- success
- message
- hasJudge
- }
- }
- `;
-
- // 闇�瑕佷竴涓柊鐨勫井淇ode
- const wxCode = 'NEED_NEW_WX_CODE_HERE'; // 璇锋浛鎹负鏂扮殑寰俊code
-
- if (wxCode === 'NEED_NEW_WX_CODE_HERE') {
- console.log('鉂� 璇峰厛鏇挎崲鑴氭湰涓殑寰俊code');
- return;
- }
-
- const response = await axios.post(`${BASE_URL}/graphql`, {
- query: wxLoginMutation,
- variables: {
- input: {
- code: wxCode,
- wxOpenid: "ogxxA1-KrSVTdqI9T1uaB1BQwPGU", // 浣跨敤宸茬煡鐨刼penid
- loginIp: "127.0.0.1",
- deviceInfo: "test-device",
- phoneAuthorized: false
- }
- }
- });
-
- if (response.data.errors) {
- console.log('鉂� 寰俊鐧诲綍澶辫触:', response.data.errors);
- return;
- }
-
- const loginData = response.data.data.wxLogin;
- console.log('鉁� 寰俊鐧诲綍鎴愬姛:');
- console.log('- 鐢ㄦ埛ID:', loginData.userInfo?.userId);
- console.log('- 鐢ㄦ埛鍚�:', loginData.userInfo?.name);
- console.log('- 鐢ㄦ埛绫诲瀷:', loginData.userInfo?.userType);
- console.log('- 鏄惁鏈夎瘎濮旀潈闄�:', loginData.hasJudge);
-
- if (loginData.token) {
- console.log('\n寮�濮嬭皟璇曟柊鑾峰彇鐨則oken...');
- await debugJwtToken(loginData.token);
- } else {
- console.log('鉂� 鏈幏鍙栧埌token');
- }
-
- } catch (error) {
- console.error('鉂� 寰俊鐧诲綍澶辫触:', error.response?.data || error.message);
- }
-}
-
-// 涓诲嚱鏁�
-async function main() {
- console.log('馃攳 寮�濮婮WT Token璋冭瘯...\n');
-
- // 閫夋嫨璋冭瘯鏂瑰紡
- const useExistingToken = true; // 璁剧疆涓簍rue浣跨敤宸叉湁token锛宖alse鑾峰彇鏂皌oken
-
- if (useExistingToken) {
- // 浣跨敤宸叉湁鐨則oken杩涜璋冭瘯
- const existingToken = 'PASTE_YOUR_VALID_TOKEN_HERE'; // 璇锋浛鎹负浣犵殑token
- await debugJwtToken(existingToken);
- } else {
- // 鑾峰彇鏂皌oken骞惰皟璇�
- await getAndDebugNewToken();
- }
-}
-
-// 杩愯涓诲嚱鏁�
-if (require.main === module) {
- main();
-}
-
-module.exports = { debugJwtToken, decodeJwtToken };
\ No newline at end of file
diff --git a/debug-saveUserInfo.js b/debug-saveUserInfo.js
deleted file mode 100644
index c2c0311..0000000
--- a/debug-saveUserInfo.js
+++ /dev/null
@@ -1,148 +0,0 @@
-// 璋冭瘯saveUserInfo GraphQL璇锋眰鐨勮剼鏈�
-const fetch = require('node-fetch');
-
-console.log('=== 璋冭瘯saveUserInfo GraphQL璇锋眰 ===');
-
-// 娴嬭瘯鐢ㄧ殑token锛堣鏇挎崲涓哄疄闄呯殑token锛�
-const testToken = 'YOUR_TOKEN_HERE'; // 璇蜂粠灏忕▼搴忔帶鍒跺彴鑾峰彇瀹為檯token
-
-// GraphQL鏌ヨ
-const mutation = `
- mutation SaveUserInfo($input: UserInput!) {
- saveUserInfo(input: $input) {
- id
- name
- avatar
- phone
- gender
- birthday
- wxOpenId
- unionId
- }
- }
-`;
-
-const variables = {
- input: {
- name: "娴嬭瘯鐢ㄦ埛",
- phone: "13981970816",
- gender: "MALE",
- birthday: "2025-10-07"
- }
-};
-
-async function testSaveUserInfo() {
- console.log('\n--- 娴嬭瘯鍙傛暟 ---');
- console.log('GraphQL Endpoint:', 'http://localhost:8080/api/graphql');
- console.log('Token:', testToken ? `${testToken.substring(0, 20)}...` : '鏃�');
- console.log('Variables:', JSON.stringify(variables, null, 2));
-
- if (!testToken || testToken === 'YOUR_TOKEN_HERE') {
- console.log('\n鉂� 璇峰厛璁剧疆鏈夋晥鐨則oken');
- console.log('馃挕 鍦ㄥ皬绋嬪簭寮�鍙戣�呭伐鍏锋帶鍒跺彴杩愯: console.log("token:", wx.getStorageSync("token"))');
- return;
- }
-
- try {
- console.log('\n--- 鍙戦�佽姹� ---');
-
- const headers = {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${testToken}`
- };
-
- console.log('璇锋眰澶�:', headers);
-
- const response = await fetch('http://localhost:8080/api/graphql', {
- method: 'POST',
- headers: headers,
- body: JSON.stringify({
- query: mutation,
- variables: variables
- })
- });
-
- console.log('\n--- 鍝嶅簲淇℃伅 ---');
- console.log('鐘舵�佺爜:', response.status);
- console.log('鐘舵�佹枃鏈�:', response.statusText);
-
- const responseText = await response.text();
- console.log('鍝嶅簲鍐呭:', responseText);
-
- if (responseText) {
- try {
- const result = JSON.parse(responseText);
-
- if (result.errors) {
- console.log('\n鉂� GraphQL閿欒:');
- result.errors.forEach((error, index) => {
- console.log(`閿欒 ${index + 1}:`, error.message);
- if (error.extensions) {
- console.log('鎵╁睍淇℃伅:', error.extensions);
- }
- });
- }
-
- if (result.data && result.data.saveUserInfo) {
- console.log('\n鉁� 淇濆瓨鎴愬姛:');
- console.log(JSON.stringify(result.data.saveUserInfo, null, 2));
- }
-
- } catch (parseError) {
- console.log('\n鉂� JSON瑙f瀽澶辫触:', parseError.message);
- }
- }
-
- } catch (error) {
- console.log('\n鉂� 璇锋眰澶辫触:', error.message);
- }
-}
-
-// 娴嬭瘯token鏈夋晥鎬�
-function testTokenFormat(token) {
- console.log('\n--- Token鏍煎紡妫�鏌� ---');
-
- if (!token || token === 'YOUR_TOKEN_HERE') {
- console.log('鉂� 娌℃湁鎻愪緵token');
- return false;
- }
-
- const parts = token.split('.');
- if (parts.length !== 3) {
- console.log('鉂� Token鏍煎紡鏃犳晥锛堜笉鏄疛WT鏍煎紡锛�');
- return false;
- }
-
- try {
- const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString());
- console.log('Token payload:', {
- userId: payload.userId,
- phone: payload.phone,
- exp: payload.exp ? new Date(payload.exp * 1000).toLocaleString() : 'N/A',
- iat: payload.iat ? new Date(payload.iat * 1000).toLocaleString() : 'N/A'
- });
-
- const now = Math.floor(Date.now() / 1000);
- const isExpired = payload.exp && payload.exp <= now;
- console.log('Token鏄惁杩囨湡:', isExpired);
-
- return !isExpired;
- } catch (error) {
- console.log('鉂� Token瑙f瀽澶辫触:', error.message);
- return false;
- }
-}
-
-// 鎵ц娴嬭瘯
-console.log('寮�濮嬫祴璇�...');
-const isValidToken = testTokenFormat(testToken);
-
-if (isValidToken) {
- testSaveUserInfo();
-} else {
- console.log('\n馃敡 瑙e喅姝ラ:');
- console.log('1. 鍦ㄥ皬绋嬪簭寮�鍙戣�呭伐鍏锋帶鍒跺彴鑾峰彇token:');
- console.log(' console.log("token:", wx.getStorageSync("token"))');
- console.log('2. 灏嗚幏鍙栧埌鐨則oken鏇挎崲鑴氭湰涓殑 YOUR_TOKEN_HERE');
- console.log('3. 閲嶆柊杩愯姝よ剼鏈�');
-}
\ No newline at end of file
diff --git a/debug-user-info.js b/debug-user-info.js
deleted file mode 100644
index 3364a11..0000000
--- a/debug-user-info.js
+++ /dev/null
@@ -1,222 +0,0 @@
-// 璋冭瘯灏忕▼搴忕敤鎴蜂俊鎭樉绀洪棶棰� - 淇鍚庣増鏈�
-console.log('=== 璋冭瘯灏忕▼搴忕敤鎴蜂俊鎭樉绀洪棶棰� - 淇鍚庣増鏈� ===');
-
-// 妯℃嫙灏忕▼搴忕幆澧� - 浣跨敤姝g‘鐨勭敤鎴蜂俊鎭粨鏋�
-const mockApp = {
- globalData: {
- userInfo: {
- userId: 'test123',
- name: '寮犱笁',
- phone: '13800138000',
- email: 'test@example.com',
- avatar: 'https://example.com/avatar.jpg', // 鐩存帴鍦╱serInfo涓�
- gender: 'MALE', // 瀛楃涓叉牸寮忔垨鏁板瓧鏍煎紡
- birthday: '1990-05-15' // 鐩存帴鍦╱serInfo涓�
- }
- }
-};
-
-// 娴嬭瘯鏁板瓧鏍煎紡鐨勬�у埆
-const mockAppWithNumericGender = {
- globalData: {
- userInfo: {
- userId: 'test456',
- name: '鏉庡洓',
- phone: '13900139000',
- email: 'test2@example.com',
- avatarUrl: 'https://example.com/avatar2.jpg', // 鍏煎鏃у瓧娈靛悕
- gender: 1, // 鏁板瓧鏍煎紡锛�0涓虹敺锛�1涓哄コ
- birthDate: '1992-08-20' // 鍏煎鏃у瓧娈靛悕
- }
- }
-};
-
-// 妯℃嫙椤甸潰鏁版嵁
-const pageData = {
- formData: {
- name: '',
- phone: '',
- email: '',
- avatarUrl: '',
- gender: null,
- education: '',
- birthDate: ''
- },
- displayUserInfo: {},
- genderOptions: ['鐢�', '濂�'],
- genderIndex: -1,
- educationOptions: ['楂樹腑鍙婁互涓�', '澶т笓', '鏈', '纭曞+', '鍗氬+'],
- educationIndex: -1,
- localAvatarPath: ''
-};
-
-// 妯℃嫙淇鍚庣殑 loadUserInfo 鏂规硶
-function loadUserInfo(app = mockApp) {
- console.log('\n--- 鎵ц淇鍚庣殑 loadUserInfo ---');
- const userInfo = app.globalData.userInfo;
- console.log('鍏ㄥ眬鐢ㄦ埛淇℃伅:', JSON.stringify(userInfo, null, 2));
-
- if (userInfo) {
- let displayUserInfo = {
- name: userInfo.name || '',
- phone: userInfo.phone || '',
- avatarUrl: userInfo.avatar || userInfo.avatarUrl || '',
- gender: null,
- education: '',
- birthDate: ''
- };
-
- // 澶勭悊鎬у埆淇℃伅 - 鐩存帴浠巙serInfo鑾峰彇
- if (userInfo.gender !== undefined && userInfo.gender !== null) {
- // 濡傛灉鏄瓧绗︿覆鏍煎紡锛岃浆鎹负鏁板瓧
- if (typeof userInfo.gender === 'string') {
- displayUserInfo.gender = userInfo.gender === 'MALE' ? 0 : 1;
- } else {
- displayUserInfo.gender = parseInt(userInfo.gender);
- }
- }
-
- // 澶勭悊鐢熸棩淇℃伅 - 鐩存帴浠巙serInfo鑾峰彇
- if (userInfo.birthday || userInfo.birthDate) {
- displayUserInfo.birthDate = userInfo.birthday || userInfo.birthDate;
- }
-
- pageData.displayUserInfo = displayUserInfo;
- console.log('璁剧疆 displayUserInfo:', JSON.stringify(pageData.displayUserInfo, null, 2));
- }
-}
-
-// 妯℃嫙淇鍚庣殑 prefillUserInfo 鏂规硶
-function prefillUserInfo(app = mockApp) {
- console.log('\n--- 鎵ц淇鍚庣殑 prefillUserInfo ---');
- const userInfo = app.globalData.userInfo;
-
- if (userInfo) {
- console.log('鐢ㄦ埛淇℃伅:', JSON.stringify(userInfo, null, 2));
-
- // 鏇存柊 formData
- pageData.formData.name = userInfo.name || '';
- pageData.formData.phone = userInfo.phone || '';
- pageData.formData.email = userInfo.email || '';
- pageData.formData.avatarUrl = userInfo.avatar || userInfo.avatarUrl || '';
-
- // 澶勭悊鎬у埆淇℃伅 - 鐩存帴浠巙serInfo鑾峰彇
- if (userInfo.gender !== undefined && userInfo.gender !== null) {
- let genderIndex;
- // 濡傛灉鏄瓧绗︿覆鏍煎紡锛岃浆鎹负鏁板瓧
- if (typeof userInfo.gender === 'string') {
- genderIndex = userInfo.gender === 'MALE' ? 0 : 1;
- } else {
- genderIndex = parseInt(userInfo.gender);
- }
- pageData.formData.gender = genderIndex;
- pageData.genderIndex = genderIndex;
- console.log('璁剧疆鎬у埆:', genderIndex === 0 ? '鐢�' : '濂�', '绱㈠紩:', genderIndex);
- }
-
- // 澶勭悊鐢熸棩淇℃伅 - 鐩存帴浠巙serInfo鑾峰彇
- if (userInfo.birthday || userInfo.birthDate) {
- const birthDate = userInfo.birthday || userInfo.birthDate;
- pageData.formData.birthDate = birthDate;
- console.log('璁剧疆鐢熸棩:', birthDate);
- }
-
- console.log('鏈�缁� formData:', JSON.stringify(pageData.formData, null, 2));
- }
-}
-
-// 妯℃嫙妯℃澘鏄剧ず閫昏緫
-function simulateTemplateDisplay() {
- console.log('\n--- 妯℃嫙妯℃澘鏄剧ず ---');
-
- // 澶村儚鏄剧ず閫昏緫
- const avatarSrc = pageData.localAvatarPath || pageData.formData.avatarUrl || '../../images/default-avatar.svg';
- console.log('澶村儚鏄剧ず璺緞:', avatarSrc);
-
- // 鎬у埆鏄剧ず閫昏緫
- const genderDisplay = pageData.formData.gender !== null ?
- pageData.genderOptions[pageData.formData.gender] : '璇烽�夋嫨鎬у埆';
- console.log('鎬у埆鏄剧ず鏂囨湰:', genderDisplay);
-
- // 鐢熸棩鏄剧ず閫昏緫
- const birthDateDisplay = pageData.formData.birthDate || '璇烽�夋嫨鐢熸棩';
- console.log('鐢熸棩鏄剧ず鏂囨湰:', birthDateDisplay);
-
- // 妫�鏌ラ棶棰�
- console.log('\n--- 闂璇婃柇 ---');
-
- if (!pageData.formData.avatarUrl) {
- console.log('鉂� 澶村儚URL涓虹┖');
- } else {
- console.log('鉁� 澶村儚URL姝e父:', pageData.formData.avatarUrl);
- }
-
- if (pageData.formData.gender === null || pageData.formData.gender === undefined) {
- console.log('鉂� 鎬у埆鏈缃�');
- } else {
- console.log('鉁� 鎬у埆姝e父:', pageData.formData.gender, '鏄剧ず涓�:', genderDisplay);
- }
-
- if (!pageData.formData.birthDate) {
- console.log('鉂� 鐢熸棩鏈缃�');
- } else {
- console.log('鉁� 鐢熸棩姝e父:', pageData.formData.birthDate);
- }
-}
-
-// 鎵ц娴嬭瘯
-console.log('\n=== 寮�濮嬫祴璇� - 瀛楃涓叉牸寮忔�у埆 ===');
-
-// 1. 娴嬭瘯瀛楃涓叉牸寮忕殑鐢ㄦ埛淇℃伅
-loadUserInfo(mockApp);
-prefillUserInfo(mockApp);
-
-// 妯℃嫙妯℃澘鏄剧ず閫昏緫
-console.log('\n--- 妯℃嫙妯℃澘鏄剧ず閫昏緫 (瀛楃涓叉牸寮�) ---');
-let avatarSrc = pageData.localAvatarPath || pageData.formData.avatarUrl || '/images/default-avatar.png';
-console.log('澶村儚鏄剧ず:', avatarSrc);
-
-let genderDisplay = pageData.genderIndex !== -1 ? pageData.genderOptions[pageData.genderIndex] : '璇烽�夋嫨鎬у埆';
-console.log('鎬у埆鏄剧ず:', genderDisplay);
-
-let birthDateDisplay = pageData.formData.birthDate || '璇烽�夋嫨鐢熸棩';
-console.log('鐢熸棩鏄剧ず:', birthDateDisplay);
-
-console.log('\n=== 寮�濮嬫祴璇� - 鏁板瓧鏍煎紡鎬у埆 ===');
-
-// 2. 閲嶇疆椤甸潰鏁版嵁
-pageData.formData = {
- name: '',
- phone: '',
- email: '',
- avatarUrl: '',
- gender: -1,
- education: '',
- birthDate: ''
-};
-pageData.genderIndex = -1;
-pageData.educationIndex = -1;
-
-// 娴嬭瘯鏁板瓧鏍煎紡鐨勭敤鎴蜂俊鎭�
-loadUserInfo(mockAppWithNumericGender);
-prefillUserInfo(mockAppWithNumericGender);
-
-// 妯℃嫙妯℃澘鏄剧ず閫昏緫
-console.log('\n--- 妯℃嫙妯℃澘鏄剧ず閫昏緫 (鏁板瓧鏍煎紡) ---');
-avatarSrc = pageData.localAvatarPath || pageData.formData.avatarUrl || '/images/default-avatar.png';
-console.log('澶村儚鏄剧ず:', avatarSrc);
-
-genderDisplay = pageData.genderIndex !== -1 ? pageData.genderOptions[pageData.genderIndex] : '璇烽�夋嫨鎬у埆';
-console.log('鎬у埆鏄剧ず:', genderDisplay);
-
-birthDateDisplay = pageData.formData.birthDate || '璇烽�夋嫨鐢熸棩';
-console.log('鐢熸棩鏄剧ず:', birthDateDisplay);
-
-// 4. 璇婃柇缁撴灉
-console.log('\n=== 璇婃柇缁撴灉 ===');
-console.log('澶村儚URL:', pageData.formData.avatarUrl ? '鉁� 姝e父' : '鉁� 缂哄け');
-console.log('鎬у埆淇℃伅:', pageData.genderIndex !== -1 ? '鉁� 姝e父' : '鉁� 缂哄け');
-console.log('鐢熸棩淇℃伅:', pageData.formData.birthDate ? '鉁� 姝e父' : '鉁� 缂哄け');
-console.log('\n淇瀹屾垚锛佺敤鎴蜂俊鎭粨鏋勫凡缁熶竴锛屾敮鎸佸绉嶆牸寮忕殑鎬у埆鍜岀敓鏃ュ瓧娈点��');
-
-console.log('\n=== 璋冭瘯瀹屾垚 ===');
\ No newline at end of file
diff --git "a/doc/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx" "b/doc/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx"
new file mode 100644
index 0000000..35f5483
--- /dev/null
+++ "b/doc/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx"
Binary files differ
diff --git "a/doc/~$\351\200\211\350\257\204\345\210\206\350\241\250\357\274\2112025\345\271\264\346\210\220\346\270\235\345\276\267\347\234\211\350\265\204\345\210\233\344\270\232\345\244\247\350\265\233\346\265\267\351\200\211.doc" "b/doc/~$\351\200\211\350\257\204\345\210\206\350\241\250\357\274\2112025\345\271\264\346\210\220\346\270\235\345\276\267\347\234\211\350\265\204\345\210\233\344\270\232\345\244\247\350\265\233\346\265\267\351\200\211.doc"
new file mode 100644
index 0000000..dde355f
--- /dev/null
+++ "b/doc/~$\351\200\211\350\257\204\345\210\206\350\241\250\357\274\2112025\345\271\264\346\210\220\346\270\235\345\276\267\347\234\211\350\265\204\345\210\233\344\270\232\345\244\247\350\265\233\346\265\267\351\200\211.doc"
Binary files differ
diff --git "a/doc/\357\274\210\346\265\267\351\200\211\350\257\204\345\210\206\350\241\250\357\274\2112025\345\271\264\346\210\220\346\270\235\345\276\267\347\234\211\350\265\204\345\210\233\344\270\232\345\244\247\350\265\233\346\265\267\351\200\211.doc" "b/doc/\357\274\210\346\265\267\351\200\211\350\257\204\345\210\206\350\241\250\357\274\2112025\345\271\264\346\210\220\346\270\235\345\276\267\347\234\211\350\265\204\345\210\233\344\270\232\345\244\247\350\265\233\346\265\267\351\200\211.doc"
new file mode 100644
index 0000000..fa63e6d
--- /dev/null
+++ "b/doc/\357\274\210\346\265\267\351\200\211\350\257\204\345\210\206\350\241\250\357\274\2112025\345\271\264\346\210\220\346\270\235\345\276\267\347\234\211\350\265\204\345\210\233\344\270\232\345\244\247\350\265\233\346\265\267\351\200\211.doc"
Binary files differ
diff --git a/get-valid-token.js b/get-valid-token.js
deleted file mode 100644
index 1170a36..0000000
--- a/get-valid-token.js
+++ /dev/null
@@ -1,139 +0,0 @@
-const http = require('http');
-
-// 妯℃嫙寰俊鐧诲綍鑾峰彇鏈夋晥token
-function wxLogin() {
- const postData = JSON.stringify({
- code: '0d3mWR000zzp6V1526100pOK7a2mWR0W', // 鏇挎崲涓哄疄闄呯殑寰俊code
- encryptedData: '',
- iv: ''
- });
-
- const options = {
- hostname: 'localhost',
- port: 8080,
- path: '/api/auth/wx-login',
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Content-Length': Buffer.byteLength(postData)
- }
- };
-
- console.log('鍙戦�佸井淇$櫥褰曡姹�...');
-
- const req = http.request(options, (res) => {
- console.log('鍝嶅簲鐘舵�佺爜:', res.statusCode);
-
- let data = '';
- res.on('data', (chunk) => {
- data += chunk;
- });
-
- res.on('end', () => {
- console.log('鍝嶅簲鍐呭:', data);
- try {
- const response = JSON.parse(data);
- if (response.token) {
- console.log('\n鑾峰彇鍒皌oken:', response.token);
- console.log('鐢ㄦ埛淇℃伅:', response.userInfo);
-
- // 浣跨敤鑾峰彇鍒扮殑token娴嬭瘯saveUserInfo
- setTimeout(() => {
- testSaveUserInfo(response.token);
- }, 1000);
- } else {
- console.log('鐧诲綍澶辫触:', response);
- }
- } catch (e) {
- console.log('瑙f瀽鍝嶅簲澶辫触:', e.message);
- }
- });
- });
-
- req.on('error', (e) => {
- console.error('璇锋眰閿欒:', e.message);
- });
-
- req.write(postData);
- req.end();
-}
-
-// 浣跨敤鏈夋晥token娴嬭瘯saveUserInfo
-function testSaveUserInfo(token) {
- console.log('\n=== 浣跨敤鏈夋晥token娴嬭瘯saveUserInfo ===');
-
- const mutation = `
- mutation SaveUserInfo($input: UserInput!) {
- saveUserInfo(input: $input) {
- id
- name
- phone
- gender
- birthday
- wxOpenId
- unionId
- }
- }
- `;
-
- const variables = {
- input: {
- name: "娴嬭瘯鐢ㄦ埛JWT",
- phone: "13981970816",
- gender: "MALE",
- birthday: "2025-10-07"
- }
- };
-
- const postData = JSON.stringify({
- query: mutation,
- variables: variables
- });
-
- const options = {
- hostname: 'localhost',
- port: 8080,
- path: '/api/graphql',
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Content-Length': Buffer.byteLength(postData),
- 'Authorization': `Bearer ${token}`
- }
- };
-
- console.log('鍙戦�丟raphQL璇锋眰锛屾惡甯︽湁鏁坱oken...');
-
- const req = http.request(options, (res) => {
- console.log('鍝嶅簲鐘舵�佺爜:', res.statusCode);
-
- let data = '';
- res.on('data', (chunk) => {
- data += chunk;
- });
-
- res.on('end', () => {
- console.log('鍝嶅簲鍐呭:', data);
- try {
- const response = JSON.parse(data);
- if (response.errors) {
- console.log('GraphQL閿欒:', response.errors);
- } else {
- console.log('淇濆瓨鐢ㄦ埛淇℃伅鎴愬姛:', response.data);
- }
- } catch (e) {
- console.log('瑙f瀽鍝嶅簲澶辫触:', e.message);
- }
- });
- });
-
- req.on('error', (e) => {
- console.error('璇锋眰閿欒:', e.message);
- });
-
- req.write(postData);
- req.end();
-}
-
-// 寮�濮嬫祴璇�
-wxLogin();
\ No newline at end of file
diff --git a/simulate-miniprogram-debug.js b/simulate-miniprogram-debug.js
deleted file mode 100644
index 488aaab..0000000
--- a/simulate-miniprogram-debug.js
+++ /dev/null
@@ -1,145 +0,0 @@
-// 妯℃嫙灏忕▼搴忚皟璇� - 妫�鏌ョ敤鎴锋暟鎹粨鏋�
-console.log('=== 妯℃嫙灏忕▼搴忚皟璇曪細妫�鏌ョ敤鎴锋暟鎹粨鏋� ===\n');
-
-// 妯℃嫙浠庢湰鍦板瓨鍌ㄨ幏鍙栫殑鐢ㄦ埛鏁版嵁锛堝熀浜庡悗绔棩蹇楀垎鏋愶級
-const mockUserInfoFromStorage = {
- userId: "-83348",
- name: "娴嬭瘯鐢ㄦ埛",
- phone: "138****8888",
- avatar: "https://example.com/avatar.jpg",
- roles: ["PLAYER"]
- // 娉ㄦ剰锛氳繖閲屽彲鑳界己灏� gender 鍜� birthday 瀛楁
-};
-
-console.log('馃摫 妯℃嫙灏忕▼搴忓惎鍔�...');
-console.log('馃攳 浠庢湰鍦板瓨鍌ㄦ仮澶嶇殑鐢ㄦ埛鏁版嵁:', JSON.stringify(mockUserInfoFromStorage, null, 2));
-
-// 妯℃嫙娉ㄥ唽椤甸潰鐨� loadUserInfo 鏂规硶
-function simulateLoadUserInfo(userInfo) {
- console.log('\n馃攧 妯℃嫙 loadUserInfo 鏂规硶鎵ц...');
- console.log('馃攳 瀹為檯鐢ㄦ埛鏁版嵁:', JSON.stringify(userInfo, null, 2));
-
- if (userInfo) {
- let displayUserInfo = {
- name: userInfo.name || '',
- phone: userInfo.phone || '',
- avatarUrl: userInfo.avatar || userInfo.avatarUrl || '',
- gender: null,
- education: '',
- birthDate: ''
- };
-
- // 澶勭悊鎬у埆淇℃伅 - 鐩存帴浠巙serInfo鑾峰彇
- if (userInfo.gender !== undefined && userInfo.gender !== null) {
- console.log('馃懁 鍙戠幇鎬у埆瀛楁:', userInfo.gender, '绫诲瀷:', typeof userInfo.gender);
- // 濡傛灉鏄瓧绗︿覆鏍煎紡锛岃浆鎹负鏁板瓧
- if (typeof userInfo.gender === 'string') {
- displayUserInfo.gender = userInfo.gender === 'MALE' ? 0 : 1;
- } else {
- displayUserInfo.gender = parseInt(userInfo.gender);
- }
- console.log('馃懁 澶勭悊鍚庣殑鎬у埆:', displayUserInfo.gender);
- } else {
- console.log('鉂� 鏈壘鍒版�у埆瀛楁鎴栧瓧娈典负绌�');
- }
-
- // 澶勭悊鐢熸棩淇℃伅 - 鐩存帴浠巙serInfo鑾峰彇
- if (userInfo.birthday || userInfo.birthDate) {
- const birthDate = userInfo.birthday || userInfo.birthDate;
- console.log('馃巶 鍙戠幇鐢熸棩瀛楁:', birthDate);
- displayUserInfo.birthDate = birthDate;
- } else {
- console.log('鉂� 鏈壘鍒扮敓鏃ュ瓧娈� (birthday 鎴� birthDate)');
- }
-
- console.log('鉁� 鏈�缁� displayUserInfo:', JSON.stringify(displayUserInfo, null, 2));
- return displayUserInfo;
- } else {
- console.log('鈿狅笍 鏈壘鍒扮敤鎴蜂俊鎭�');
- return null;
- }
-}
-
-// 妯℃嫙娉ㄥ唽椤甸潰鐨� prefillUserInfo 鏂规硶
-function simulatePrefillUserInfo(userInfo) {
- console.log('\n馃攧 妯℃嫙 prefillUserInfo 鏂规硶鎵ц...');
- console.log('馃攳 棰勫~鍏呯敤鎴蜂俊鎭�:', userInfo);
-
- if (userInfo) {
- const updateData = {
- 'formData.name': userInfo.name || '',
- 'formData.phone': userInfo.phone || '',
- 'formData.email': userInfo.email || '',
- 'formData.avatarUrl': userInfo.avatar || userInfo.avatarUrl || ''
- };
-
- // 澶勭悊鎬у埆淇℃伅 - 鐩存帴浠巙serInfo鑾峰彇
- if (userInfo.gender !== undefined && userInfo.gender !== null) {
- let genderIndex;
- console.log('馃懁 澶勭悊鎬у埆瀛楁:', userInfo.gender, '绫诲瀷:', typeof userInfo.gender);
- // 濡傛灉鏄瓧绗︿覆鏍煎紡锛岃浆鎹负鏁板瓧
- if (typeof userInfo.gender === 'string') {
- genderIndex = userInfo.gender === 'MALE' ? 0 : 1;
- } else {
- genderIndex = parseInt(userInfo.gender);
- }
- updateData['formData.gender'] = genderIndex;
- updateData['genderIndex'] = genderIndex;
- console.log('馃懁 璁剧疆鎬у埆:', genderIndex === 0 ? '鐢�' : '濂�');
- } else {
- console.log('鉂� 鎬у埆瀛楁缂哄け锛屾棤娉曢濉厖');
- }
-
- // 澶勭悊鐢熸棩淇℃伅 - 鐩存帴浠巙serInfo鑾峰彇
- if (userInfo.birthday || userInfo.birthDate) {
- const birthDate = userInfo.birthday || userInfo.birthDate;
- updateData['formData.birthDate'] = birthDate;
- console.log('馃巶 璁剧疆鐢熸棩:', birthDate);
- } else {
- console.log('鉂� 鐢熸棩瀛楁缂哄け锛屾棤娉曢濉厖');
- }
-
- console.log('鉁� 棰勫~鍏呮暟鎹�:', JSON.stringify(updateData, null, 2));
- console.log('馃柤锔� 璁剧疆澶村儚URL:', updateData['formData.avatarUrl']);
-
- return updateData;
- } else {
- console.log('鈿狅笍 鏈壘鍒扮敤鎴蜂俊鎭紝璺宠繃棰勫~鍏�');
- return null;
- }
-}
-
-// 鎵ц妯℃嫙娴嬭瘯
-console.log('\n=== 寮�濮嬫ā鎷熸祴璇� ===');
-
-// 娴嬭瘯1锛氱己灏戞�у埆鍜岀敓鏃ュ瓧娈电殑鎯呭喌
-console.log('\n馃搵 娴嬭瘯1锛氱己灏戞�у埆鍜岀敓鏃ュ瓧娈电殑鐢ㄦ埛鏁版嵁');
-simulateLoadUserInfo(mockUserInfoFromStorage);
-simulatePrefillUserInfo(mockUserInfoFromStorage);
-
-// 娴嬭瘯2锛氬寘鍚�у埆鍜岀敓鏃ュ瓧娈电殑鎯呭喌
-console.log('\n馃搵 娴嬭瘯2锛氬寘鍚�у埆鍜岀敓鏃ュ瓧娈电殑鐢ㄦ埛鏁版嵁');
-const completeUserInfo = {
- ...mockUserInfoFromStorage,
- gender: 0, // 鐢锋��
- birthday: '1990-01-01'
-};
-simulateLoadUserInfo(completeUserInfo);
-simulatePrefillUserInfo(completeUserInfo);
-
-// 娴嬭瘯3锛氬瓧绗︿覆鏍煎紡鐨勬�у埆
-console.log('\n馃搵 娴嬭瘯3锛氬瓧绗︿覆鏍煎紡鐨勬�у埆');
-const stringGenderUserInfo = {
- ...mockUserInfoFromStorage,
- gender: 'MALE',
- birthDate: '1995-05-15'
-};
-simulateLoadUserInfo(stringGenderUserInfo);
-simulatePrefillUserInfo(stringGenderUserInfo);
-
-console.log('\n=== 妯℃嫙娴嬭瘯瀹屾垚 ===');
-console.log('\n馃攳 鍒嗘瀽缁撴灉锛�');
-console.log('1. 濡傛灉鍚庣杩斿洖鐨勭敤鎴锋暟鎹腑缂哄皯 gender 鍜� birthday/birthDate 瀛楁锛�');
-console.log(' 閭d箞杩欎簺瀛楁灏变笉浼氳棰勫~鍏呭埌琛ㄥ崟涓��');
-console.log('2. 闇�瑕佹鏌ュ悗绔� GraphQL 鏌ヨ鏄惁鍖呭惈浜嗚繖浜涘瓧娈点��');
-console.log('3. 闇�瑕佹鏌ュ悗绔暟鎹簱涓槸鍚﹀瓨鍌ㄤ簡杩欎簺瀛楁鐨勫�笺��');
\ No newline at end of file
diff --git a/test-image.svg b/test-image.svg
deleted file mode 100644
index 4746b23..0000000
--- a/test-image.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
- <rect width="100" height="100" fill="#4CAF50"/>
- <text x="50" y="55" text-anchor="middle" fill="white" font-family="Arial" font-size="14">娴嬭瘯鍥剧墖</text>
-</svg>
\ No newline at end of file
diff --git a/test_miniprogram_activities_fix.js b/test_miniprogram_activities_fix.js
deleted file mode 100644
index c9772ac..0000000
--- a/test_miniprogram_activities_fix.js
+++ /dev/null
@@ -1,142 +0,0 @@
-const mysql = require('mysql2/promise');
-
-// 鏁版嵁搴撻厤缃�
-const dbConfig = {
- host: '139.155.104.10',
- port: 3306,
- user: 'ryc',
- password: 'KiYap3E8X8RLcM6T',
- database: 'ryc'
-};
-
-async function testActivityStatesAndMapping() {
- let connection;
-
- try {
- console.log('=== 灏忕▼搴忔椿鍔ㄧ姸鎬佹槧灏勪慨澶嶆祴璇� ===\n');
-
- // 杩炴帴鏁版嵁搴�
- connection = await mysql.createConnection(dbConfig);
- console.log('鉁� 鏁版嵁搴撹繛鎺ユ垚鍔�');
-
- // 1. 妫�鏌ユ暟鎹簱涓殑娲诲姩鐘舵�佸垎甯�
- console.log('\n馃搳 鏁版嵁搴撴椿鍔ㄧ姸鎬佸垎甯�:');
- const [stateStats] = await connection.execute(`
- SELECT
- state,
- COUNT(*) as count,
- CASE
- WHEN state = 0 THEN '鏈彂甯�(鍒犻櫎)'
- WHEN state = 1 THEN '鍙戝竷'
- WHEN state = 2 THEN '鍏抽棴'
- ELSE '鏈煡鐘舵��'
- END as state_name
- FROM t_activity
- WHERE pid = 0
- GROUP BY state
- ORDER BY state
- `);
-
- stateStats.forEach(row => {
- console.log(` State ${row.state} (${row.state_name}): ${row.count} 涓椿鍔╜);
- });
-
- // 2. 楠岃瘉淇鍚庣殑鐘舵�佹槧灏勯�昏緫
- console.log('\n馃敡 淇鍚庣殑鐘舵�佹槧灏勯�昏緫:');
- console.log(' upcoming (鍗冲皢寮�濮�) -> state=1 (鍙戝竷)');
- console.log(' ongoing (杩涜涓�) -> state=1 (鍙戝竷)');
- console.log(' ended (宸茬粨鏉�) -> state=2 (鍏抽棴)');
- console.log(' all (鍏ㄩ儴) -> state=null (鍚庣杩囨护 state!=0)');
-
- // 3. 妯℃嫙涓嶅悓绛涢�夋潯浠剁殑鏌ヨ缁撴灉
- console.log('\n馃И 妯℃嫙灏忕▼搴忕瓫閫夋煡璇�:');
-
- // 妯℃嫙 filterStatus = 'all' (state = null)
- const [allActivities] = await connection.execute(`
- SELECT id, name, state,
- CASE
- WHEN state = 0 THEN '鏈彂甯�(鍒犻櫎)'
- WHEN state = 1 THEN '鍙戝竷'
- WHEN state = 2 THEN '鍏抽棴'
- ELSE '鏈煡鐘舵��'
- END as state_name
- FROM t_activity
- WHERE pid = 0 AND state != 0
- ORDER BY create_time DESC
- LIMIT 5
- `);
- console.log(`\n 绛涢�夋潯浠�: 鍏ㄩ儴 (all) - 搴旇鎺掗櫎宸插垹闄ゆ椿鍔�:`);
- console.log(` 鏌ヨ缁撴灉: ${allActivities.length} 涓椿鍔╜);
- allActivities.forEach(activity => {
- console.log(` - ${activity.name} (state=${activity.state}, ${activity.state_name})`);
- });
-
- // 妯℃嫙 filterStatus = 'upcoming' 鎴� 'ongoing' (state = 1)
- const [publishedActivities] = await connection.execute(`
- SELECT id, name, state,
- CASE
- WHEN state = 0 THEN '鏈彂甯�(鍒犻櫎)'
- WHEN state = 1 THEN '鍙戝竷'
- WHEN state = 2 THEN '鍏抽棴'
- ELSE '鏈煡鐘舵��'
- END as state_name
- FROM t_activity
- WHERE pid = 0 AND state = 1
- ORDER BY create_time DESC
- LIMIT 5
- `);
- console.log(`\n 绛涢�夋潯浠�: 鍗冲皢寮�濮�/杩涜涓� (upcoming/ongoing) - state=1:`);
- console.log(` 鏌ヨ缁撴灉: ${publishedActivities.length} 涓椿鍔╜);
- publishedActivities.forEach(activity => {
- console.log(` - ${activity.name} (state=${activity.state}, ${activity.state_name})`);
- });
-
- // 妯℃嫙 filterStatus = 'ended' (state = 2)
- const [closedActivities] = await connection.execute(`
- SELECT id, name, state,
- CASE
- WHEN state = 0 THEN '鏈彂甯�(鍒犻櫎)'
- WHEN state = 1 THEN '鍙戝竷'
- WHEN state = 2 THEN '鍏抽棴'
- ELSE '鏈煡鐘舵��'
- END as state_name
- FROM t_activity
- WHERE pid = 0 AND state = 2
- ORDER BY create_time DESC
- LIMIT 5
- `);
- console.log(`\n 绛涢�夋潯浠�: 宸茬粨鏉� (ended) - state=2:`);
- console.log(` 鏌ヨ缁撴灉: ${closedActivities.length} 涓椿鍔╜);
- closedActivities.forEach(activity => {
- console.log(` - ${activity.name} (state=${activity.state}, ${activity.state_name})`);
- });
-
- // 4. 楠岃瘉鏄惁杩樻湁state=0鐨勬椿鍔ㄤ細琚樉绀�
- const [deletedActivities] = await connection.execute(`
- SELECT id, name, state
- FROM t_activity
- WHERE pid = 0 AND state = 0
- `);
-
- console.log(`\n鉁� 楠岃瘉缁撴灉:`);
- console.log(` - 鏁版嵁搴撲腑鏈� ${deletedActivities.length} 涓凡鍒犻櫎娲诲姩 (state=0)`);
- console.log(` - 淇鍚庣殑鏄犲皠纭繚杩欎簺娲诲姩涓嶄細鍦ㄤ换浣曠瓫閫夋潯浠朵笅鏄剧ず`);
- console.log(` - 'all' 绛涢�変細鎺掗櫎 state=0 鐨勬椿鍔╜);
- console.log(` - 鍏朵粬绛涢�夋潯浠跺彧浼氭煡璇� state=1 鎴� state=2 鐨勬椿鍔╜);
-
- if (deletedActivities.length === 0) {
- console.log(` - 褰撳墠鏁版嵁搴撲腑娌℃湁宸插垹闄ょ殑娲诲姩锛屼慨澶嶄富瑕佽В鍐充簡鐘舵�佹槧灏勯棶棰榒);
- }
-
- } catch (error) {
- console.error('鉂� 娴嬭瘯澶辫触:', error.message);
- } finally {
- if (connection) {
- await connection.end();
- console.log('\n馃攲 鏁版嵁搴撹繛鎺ュ凡鍏抽棴');
- }
- }
-}
-
-// 杩愯娴嬭瘯
-testActivityStatesAndMapping();
\ No newline at end of file
diff --git a/test_miniprogram_fix.js b/test_miniprogram_fix.js
deleted file mode 100644
index 7f1d1d4..0000000
--- a/test_miniprogram_fix.js
+++ /dev/null
@@ -1,102 +0,0 @@
-// 娴嬭瘯灏忕▼搴忕淇鍚庣殑GraphQL鏌ヨ
-const axios = require('axios');
-
-const testQuery = `
- query GetActivityPlayerDetail($id: ID!) {
- activityPlayerDetail(id: $id) {
- id
- projectName
- description
- activityName
- stageId
- state
- playerInfo {
- id
- name
- phone
- gender
- birthday
- education
- introduction
- userInfo {
- userId
- name
- phone
- avatarUrl
- }
- }
- regionInfo {
- id
- name
- fullPath
- }
- submissionFiles {
- id
- name
- url
- fullUrl
- fileExt
- fileSize
- mediaType
- thumbUrl
- fullThumbUrl
- }
- ratingForm {
- schemeId
- schemeName
- totalMaxScore
- items {
- id
- name
- maxScore
- orderNo
- }
- }
- }
- }
-`;
-
-async function testGraphQLQuery() {
- try {
- console.log('娴嬭瘯淇鍚庣殑灏忕▼搴忕GraphQL鏌ヨ...');
-
- const response = await axios.post('http://localhost:8080/api/graphql', {
- query: testQuery,
- variables: {
- id: "1" // 浣跨敤涓�涓祴璇旾D
- }
- }, {
- headers: {
- 'Content-Type': 'application/json',
- 'Authorization': 'Bearer test-token' // 濡傛灉闇�瑕佽璇�
- }
- });
-
- if (response.data.errors) {
- console.error('GraphQL鏌ヨ鍑洪敊:', response.data.errors);
- return false;
- }
-
- console.log('鉁� GraphQL鏌ヨ鎴愬姛!');
- console.log('杩斿洖鐨勬暟鎹粨鏋�:', JSON.stringify(response.data.data, null, 2));
- return true;
-
- } catch (error) {
- console.error('鉂� 璇锋眰澶辫触:', error.message);
- if (error.response) {
- console.error('鍝嶅簲鐘舵��:', error.response.status);
- console.error('鍝嶅簲鏁版嵁:', error.response.data);
- }
- return false;
- }
-}
-
-// 杩愯娴嬭瘯
-testGraphQLQuery().then(success => {
- if (success) {
- console.log('\n馃帀 灏忕▼搴忕GraphQL鏌ヨ淇鎴愬姛锛�');
- console.log('鐜板湪灏忕▼搴忕鏌ヨ鐨勫瓧娈典笌Web绔繚鎸佷竴鑷达紝涓嶅啀鍖呭惈涓嶅瓨鍦ㄧ殑description銆亀eight銆乻ortOrder瀛楁銆�');
- } else {
- console.log('\n鉂� 娴嬭瘯澶辫触锛岃妫�鏌ヤ慨澶嶆槸鍚︽纭��');
- }
-});
\ No newline at end of file
diff --git a/tmp/docx-layout-sample.docx b/tmp/docx-layout-sample.docx
new file mode 100644
index 0000000..68ca0eb
--- /dev/null
+++ b/tmp/docx-layout-sample.docx
Binary files differ
diff --git "a/tmp/docx-\346\265\267\351\200\211-12-new/\133Content_Types\135.xml" "b/tmp/docx-\346\265\267\351\200\211-12-new/\133Content_Types\135.xml"
new file mode 100644
index 0000000..f4911a1
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12-new/\133Content_Types\135.xml"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default ContentType="application/vnd.openxmlformats-package.relationships+xml" Extension="rels"/><Default ContentType="application/xml" Extension="xml"/><Override ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" PartName="/docProps/app.xml"/><Override ContentType="application/vnd.openxmlformats-package.core-properties+xml" PartName="/docProps/core.xml"/><Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" PartName="/word/document.xml"/><Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" PartName="/word/settings.xml"/></Types>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12-new/_rels/.rels" "b/tmp/docx-\346\265\267\351\200\211-12-new/_rels/.rels"
new file mode 100644
index 0000000..e477e23
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12-new/_rels/.rels"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Target="word/document.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"/><Relationship Id="rId2" Target="docProps/app.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"/><Relationship Id="rId3" Target="docProps/core.xml" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"/></Relationships>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12-new/docProps/app.xml" "b/tmp/docx-\346\265\267\351\200\211-12-new/docProps/app.xml"
new file mode 100644
index 0000000..0066519
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12-new/docProps/app.xml"
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"><Application>Apache POI</Application></Properties>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12-new/docProps/core.xml" "b/tmp/docx-\346\265\267\351\200\211-12-new/docProps/core.xml"
new file mode 100644
index 0000000..28da7d3
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12-new/docProps/core.xml"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dcterms:created xsi:type="dcterms:W3CDTF">2025-11-06T05:16:40Z</dcterms:created><dc:creator>Apache POI</dc:creator></cp:coreProperties>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12-new/word/_rels/document.xml.rels" "b/tmp/docx-\346\265\267\351\200\211-12-new/word/_rels/document.xml.rels"
new file mode 100644
index 0000000..4ec4c54
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12-new/word/_rels/document.xml.rels"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Target="settings.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings"/></Relationships>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12-new/word/document.xml" "b/tmp/docx-\346\265\267\351\200\211-12-new/word/document.xml"
new file mode 100644
index 0000000..15fa295
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12-new/word/document.xml"
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:body><w:p><w:pPr><w:jc w:val="center"/></w:pPr><w:r><w:rPr><w:b w:val="on"/><w:sz w:val="36"/></w:rPr><w:t>璇勫璇勫垎琛�</w:t></w:r></w:p><w:p><w:r><w:t>娲诲姩锛氭櫤鎱ф櫤鑳介」鐩粍 闃舵锛氭捣閫�</w:t></w:r></w:p><w:p><w:r><w:t>椤圭洰锛�12 閫夋墜锛氬尶鍚嶇敤鎴�</w:t></w:r></w:p><w:p><w:r><w:rPr><w:i w:val="on"/></w:rPr><w:t>灏氭棤璇勫垎锛堜互涓嬩负璇勫垎椤规ā鏉匡級</w:t></w:r></w:p><w:tbl><w:tblPr><w:tblW w:w="9072" w:type="dxa"/><w:tblBorders><w:top w:val="single" w:sz="8" w:color="000000"/><w:left w:val="single" w:sz="8" w:color="000000"/><w:bottom w:val="single" w:sz="8" w:color="000000"/><w:right w:val="single" w:sz="8" w:color="000000"/><w:insideH w:val="single" w:sz="8" w:color="000000"/><w:insideV w:val="single" w:sz="8" w:color="000000"/></w:tblBorders></w:tblPr><w:tblGrid><w:gridCol w:w="6072"/><w:gridCol w:w="1500"/><w:gridCol w:w="1500"/></w:tblGrid><w:tr><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>璇勫垎椤�</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>寰楀垎</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>婊″垎</w:t></w:r></w:p></w:tc></w:tr><w:tr><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>鍚圭摱瀛�</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>-</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>25</w:t></w:r></w:p></w:tc></w:tr><w:tr><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>鐡舵暟</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>-</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>25</w:t></w:r></w:p></w:tc></w:tr><w:tr><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>閰掑搧</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>-</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>50</w:t></w:r></w:p></w:tc></w:tr></w:tbl><w:p><w:pPr><w:spacing w:before="200"/></w:pPr></w:p><w:tbl><w:tblPr><w:tblW w:w="9072" w:type="dxa"/><w:tblBorders><w:top w:val="single" w:sz="8" w:color="000000"/><w:left w:val="single" w:sz="8" w:color="000000"/><w:bottom w:val="single" w:sz="8" w:color="000000"/><w:right w:val="single" w:sz="8" w:color="000000"/><w:insideH w:val="single" w:sz="8" w:color="000000"/><w:insideV w:val="single" w:sz="8" w:color="000000"/></w:tblBorders></w:tblPr><w:tblGrid><w:gridCol w:w="6500"/><w:gridCol w:w="2572"/></w:tblGrid><w:tr><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>涓撳璇勫绛惧瓧锛歘______________</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/><w:rFonts w:ascii="瀹嬩綋" w:hAnsi="瀹嬩綋" w:cs="瀹嬩綋" w:eastAsia="瀹嬩綋"/></w:rPr><w:t>绛惧瓧鏃ユ湡锛歘_________</w:t></w:r></w:p></w:tc></w:tr></w:tbl><w:sectPr><w:pgSz w:w="11907" w:h="16840"/><w:pgMar w:left="1440" w:right="1440" w:top="1440" w:bottom="1440"/></w:sectPr></w:body></w:document>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12-new/word/settings.xml" "b/tmp/docx-\346\265\267\351\200\211-12-new/word/settings.xml"
new file mode 100644
index 0000000..ebf5750
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12-new/word/settings.xml"
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"/>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12/\133Content_Types\135.xml" "b/tmp/docx-\346\265\267\351\200\211-12/\133Content_Types\135.xml"
new file mode 100644
index 0000000..f4911a1
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12/\133Content_Types\135.xml"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default ContentType="application/vnd.openxmlformats-package.relationships+xml" Extension="rels"/><Default ContentType="application/xml" Extension="xml"/><Override ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" PartName="/docProps/app.xml"/><Override ContentType="application/vnd.openxmlformats-package.core-properties+xml" PartName="/docProps/core.xml"/><Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" PartName="/word/document.xml"/><Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" PartName="/word/settings.xml"/></Types>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12/_rels/.rels" "b/tmp/docx-\346\265\267\351\200\211-12/_rels/.rels"
new file mode 100644
index 0000000..e477e23
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12/_rels/.rels"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Target="word/document.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"/><Relationship Id="rId2" Target="docProps/app.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"/><Relationship Id="rId3" Target="docProps/core.xml" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"/></Relationships>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12/docProps/app.xml" "b/tmp/docx-\346\265\267\351\200\211-12/docProps/app.xml"
new file mode 100644
index 0000000..0066519
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12/docProps/app.xml"
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"><Application>Apache POI</Application></Properties>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12/docProps/core.xml" "b/tmp/docx-\346\265\267\351\200\211-12/docProps/core.xml"
new file mode 100644
index 0000000..94b9fd8
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12/docProps/core.xml"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dcterms:created xsi:type="dcterms:W3CDTF">2025-11-06T03:40:51Z</dcterms:created><dc:creator>Apache POI</dc:creator></cp:coreProperties>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12/word/_rels/document.xml.rels" "b/tmp/docx-\346\265\267\351\200\211-12/word/_rels/document.xml.rels"
new file mode 100644
index 0000000..4ec4c54
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12/word/_rels/document.xml.rels"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Target="settings.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings"/></Relationships>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12/word/document.xml" "b/tmp/docx-\346\265\267\351\200\211-12/word/document.xml"
new file mode 100644
index 0000000..8df0fba
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12/word/document.xml"
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:body><w:p><w:pPr><w:jc w:val="center"/></w:pPr><w:r><w:rPr><w:b w:val="on"/><w:sz w:val="36"/></w:rPr><w:t>璇勫璇勫垎琛�</w:t></w:r></w:p><w:p><w:r><w:t>娲诲姩锛氭櫤鎱ф櫤鑳介」鐩粍 闃舵锛氭捣閫�</w:t></w:r></w:p><w:p><w:r><w:t>椤圭洰锛�12 閫夋墜锛氬尶鍚嶇敤鎴�</w:t></w:r></w:p><w:p><w:r><w:t>灏氭棤璇勫垎</w:t></w:r></w:p></w:body></w:document>
\ No newline at end of file
diff --git "a/tmp/docx-\346\265\267\351\200\211-12/word/settings.xml" "b/tmp/docx-\346\265\267\351\200\211-12/word/settings.xml"
new file mode 100644
index 0000000..ebf5750
--- /dev/null
+++ "b/tmp/docx-\346\265\267\351\200\211-12/word/settings.xml"
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"/>
\ No newline at end of file
diff --git a/tmp/review-0/README.txt b/tmp/review-0/README.txt
new file mode 100644
index 0000000..0fab9d1
--- /dev/null
+++ b/tmp/review-0/README.txt
@@ -0,0 +1,4 @@
+钃夋槗鍒涜瘎瀹″鍑�
+娲诲姩: 鏅烘収鏅鸿兘椤圭洰缁� (ID=74)
+瀵煎嚭鏃堕棿: 2025-11-06T11:56:25.701008300
+娲诲姩鎶ュ悕浜烘暟: 5
diff --git "a/tmp/review-0/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx" "b/tmp/review-0/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx"
new file mode 100644
index 0000000..9e1a899
--- /dev/null
+++ "b/tmp/review-0/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx"
Binary files differ
diff --git a/tmp/review-1/README.txt b/tmp/review-1/README.txt
new file mode 100644
index 0000000..fe713f3
--- /dev/null
+++ b/tmp/review-1/README.txt
@@ -0,0 +1,5 @@
+钃夋槗鍒涜瘎瀹″鍑�
+娲诲姩: 鏅烘収鏅鸿兘椤圭洰缁� (ID=74)
+瀵煎嚭鏃堕棿: 2025-11-06T11:57:45.558184200
+闃舵ID: [76]
+闃舵 76 鎶ュ悕浜烘暟: 0
diff --git a/tmp/review-2/README.txt b/tmp/review-2/README.txt
new file mode 100644
index 0000000..c485535
--- /dev/null
+++ b/tmp/review-2/README.txt
@@ -0,0 +1,5 @@
+钃夋槗鍒涜瘎瀹″鍑�
+娲诲姩: 鏅烘収鏅鸿兘椤圭洰缁� (ID=74)
+瀵煎嚭鏃堕棿: 2025-11-06T11:40:51.537055800
+闃舵ID: [75]
+闃舵 75 鎶ュ悕浜烘暟: 5
diff --git "a/tmp/review-2/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx" "b/tmp/review-2/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx"
new file mode 100644
index 0000000..a0a7177
--- /dev/null
+++ "b/tmp/review-2/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx"
Binary files differ
diff --git a/tmp/review-export-2/README.txt b/tmp/review-export-2/README.txt
new file mode 100644
index 0000000..a3706a0
--- /dev/null
+++ b/tmp/review-export-2/README.txt
@@ -0,0 +1,7 @@
+钃夋槗鍒涜瘎瀹″鍑�
+娲诲姩: 鏅烘収鏅鸿兘椤圭洰缁� (ID=74)
+瀵煎嚭鏃堕棿: 2025-11-06T13:16:40.539277500
+闃舵ID: [75, 76, 77]
+闃舵 75 鎶ュ悕浜烘暟: 5
+闃舵 76 鎶ュ悕浜烘暟: 0
+闃舵 77 鎶ュ悕浜烘暟: 0
diff --git "a/tmp/review-export-2/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx" "b/tmp/review-export-2/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx"
new file mode 100644
index 0000000..9e0df2a
--- /dev/null
+++ "b/tmp/review-export-2/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx"
Binary files differ
diff --git a/tmp/review-export/README.txt b/tmp/review-export/README.txt
new file mode 100644
index 0000000..b1c4d66
--- /dev/null
+++ b/tmp/review-export/README.txt
@@ -0,0 +1,7 @@
+钃夋槗鍒涜瘎瀹″鍑�
+娲诲姩: 鏅烘収鏅鸿兘椤圭洰缁� (ID=74)
+瀵煎嚭鏃堕棿: 2025-11-06T13:03:21.174946400
+闃舵ID: [75, 76, 77]
+闃舵 75 鎶ュ悕浜烘暟: 5
+闃舵 76 鎶ュ悕浜烘暟: 0
+闃舵 77 鎶ュ悕浜烘暟: 0
diff --git "a/tmp/review-export/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx" "b/tmp/review-export/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx"
new file mode 100644
index 0000000..c1e79cc
--- /dev/null
+++ "b/tmp/review-export/players/\346\265\267\351\200\211/12-\345\214\277\345\220\215\347\224\250\346\210\267.docx"
Binary files differ
diff --git "a/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/\133Content_Types\135.xml" "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/\133Content_Types\135.xml"
new file mode 100644
index 0000000..f4911a1
--- /dev/null
+++ "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/\133Content_Types\135.xml"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default ContentType="application/vnd.openxmlformats-package.relationships+xml" Extension="rels"/><Default ContentType="application/xml" Extension="xml"/><Override ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" PartName="/docProps/app.xml"/><Override ContentType="application/vnd.openxmlformats-package.core-properties+xml" PartName="/docProps/core.xml"/><Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" PartName="/word/document.xml"/><Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" PartName="/word/settings.xml"/></Types>
\ No newline at end of file
diff --git "a/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/_rels/.rels" "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/_rels/.rels"
new file mode 100644
index 0000000..e477e23
--- /dev/null
+++ "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/_rels/.rels"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Target="word/document.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"/><Relationship Id="rId2" Target="docProps/app.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"/><Relationship Id="rId3" Target="docProps/core.xml" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"/></Relationships>
\ No newline at end of file
diff --git "a/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/docProps/app.xml" "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/docProps/app.xml"
new file mode 100644
index 0000000..0066519
--- /dev/null
+++ "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/docProps/app.xml"
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"><Application>Apache POI</Application></Properties>
\ No newline at end of file
diff --git "a/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/docProps/core.xml" "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/docProps/core.xml"
new file mode 100644
index 0000000..c994295
--- /dev/null
+++ "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/docProps/core.xml"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dcterms:created xsi:type="dcterms:W3CDTF">2025-11-06T05:03:21Z</dcterms:created><dc:creator>Apache POI</dc:creator></cp:coreProperties>
\ No newline at end of file
diff --git "a/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/word/_rels/document.xml.rels" "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/word/_rels/document.xml.rels"
new file mode 100644
index 0000000..4ec4c54
--- /dev/null
+++ "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/word/_rels/document.xml.rels"
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Target="settings.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings"/></Relationships>
\ No newline at end of file
diff --git "a/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/word/document.xml" "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/word/document.xml"
new file mode 100644
index 0000000..45dc992
--- /dev/null
+++ "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/word/document.xml"
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:body><w:p><w:pPr><w:jc w:val="center"/></w:pPr><w:r><w:rPr><w:b w:val="on"/><w:sz w:val="36"/></w:rPr><w:t>璇勫璇勫垎琛�</w:t></w:r></w:p><w:p><w:r><w:t>娲诲姩锛氭櫤鎱ф櫤鑳介」鐩粍 闃舵锛氭捣閫�</w:t></w:r></w:p><w:p><w:r><w:t>椤圭洰锛�12 閫夋墜锛氬尶鍚嶇敤鎴�</w:t></w:r></w:p><w:p><w:r><w:rPr><w:i w:val="on"/></w:rPr><w:t>灏氭棤璇勫垎锛堜互涓嬩负璇勫垎椤规ā鏉匡級</w:t></w:r></w:p><w:tbl><w:tblPr><w:tblW w:w="9072" w:type="dxa"/><w:tblBorders><w:top w:val="single" w:sz="8" w:color="000000"/><w:left w:val="single" w:sz="8" w:color="000000"/><w:bottom w:val="single" w:sz="8" w:color="000000"/><w:right w:val="single"/><w:insideH w:val="single" w:sz="8" w:color="000000"/><w:insideV w:val="single" w:sz="8" w:color="000000"/></w:tblBorders></w:tblPr><w:tblGrid><w:gridCol w:w="6072"/><w:gridCol w:w="1500"/><w:gridCol w:w="1500"/></w:tblGrid><w:tr><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>璇勫垎椤�</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>寰楀垎</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>婊″垎</w:t></w:r></w:p></w:tc></w:tr><w:tr><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>鍚圭摱瀛�</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>-</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>25</w:t></w:r></w:p></w:tc></w:tr><w:tr><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>鐡舵暟</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>-</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>25</w:t></w:r></w:p></w:tc></w:tr><w:tr><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>閰掑搧</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>-</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>50</w:t></w:r></w:p></w:tc></w:tr></w:tbl><w:p><w:pPr><w:spacing w:before="200"/></w:pPr></w:p><w:tbl><w:tblPr><w:tblW w:w="9072" w:type="dxa"/><w:tblBorders><w:top w:val="single" w:sz="8" w:color="000000"/><w:left w:val="single" w:sz="8" w:color="000000"/><w:bottom w:val="single" w:sz="8" w:color="000000"/><w:right w:val="single"/><w:insideH w:val="single" w:sz="8" w:color="000000"/><w:insideV w:val="single" w:sz="8" w:color="000000"/></w:tblBorders></w:tblPr><w:tblGrid><w:gridCol w:w="6500"/><w:gridCol w:w="2572"/></w:tblGrid><w:tr><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>涓撳璇勫绛惧瓧锛歘______________</w:t></w:r></w:p></w:tc><w:tc><w:tcPr><w:tcW w:type="dxa"/></w:tcPr><w:p><w:pPr><w:jc w:val="left"/></w:pPr><w:r><w:rPr><w:sz w:val="24"/></w:rPr><w:t>绛惧瓧鏃ユ湡锛歘_________</w:t></w:r></w:p></w:tc></w:tr></w:tbl></w:body></w:document>
\ No newline at end of file
diff --git "a/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/word/settings.xml" "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/word/settings.xml"
new file mode 100644
index 0000000..ebf5750
--- /dev/null
+++ "b/tmp/review-export/players/\346\265\267\351\200\211/docx-xml/word/settings.xml"
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"/>
\ No newline at end of file
diff --git a/update-activity-times.js b/update-activity-times.js
deleted file mode 100644
index 6d7fcf5..0000000
--- a/update-activity-times.js
+++ /dev/null
@@ -1,55 +0,0 @@
-const mysql = require('mysql2/promise');
-const fs = require('fs');
-
-async function updateActivityTimes() {
- const connection = await mysql.createConnection({
- host: '139.155.104.10',
- port: 3306,
- user: 'root',
- password: 'Xml@uk2025',
- database: 'ryc',
- authPlugins: {
- mysql_native_password: () => () => Buffer.alloc(0)
- }
- });
-
- try {
- console.log('杩炴帴鏁版嵁搴撴垚鍔�');
-
- // 璇诲彇SQL鏂囦欢
- const sqlContent = fs.readFileSync('./update-activity-times.sql', 'utf8');
-
- // 鍒嗗壊SQL璇彞
- const sqlStatements = sqlContent
- .split(';')
- .map(stmt => stmt.trim())
- .filter(stmt => stmt && !stmt.startsWith('--'));
-
- console.log(`鍑嗗鎵ц ${sqlStatements.length} 鏉QL璇彞`);
-
- // 鎵ц姣忔潯SQL璇彞
- for (let i = 0; i < sqlStatements.length; i++) {
- const sql = sqlStatements[i];
- if (sql) {
- console.log(`鎵цSQL ${i + 1}: ${sql.substring(0, 50)}...`);
- const [result] = await connection.execute(sql);
-
- if (sql.toLowerCase().startsWith('select')) {
- console.log('鏌ヨ缁撴灉:', result);
- } else {
- console.log(`褰卞搷琛屾暟: ${result.affectedRows}`);
- }
- }
- }
-
- console.log('鎵�鏈塖QL璇彞鎵ц瀹屾垚');
-
- } catch (error) {
- console.error('鎵ц澶辫触:', error);
- } finally {
- await connection.end();
- console.log('鏁版嵁搴撹繛鎺ュ凡鍏抽棴');
- }
-}
-
-updateActivityTimes();
\ No newline at end of file
diff --git a/update-activity-times.sql b/update-activity-times.sql
deleted file mode 100644
index 10c1c81..0000000
--- a/update-activity-times.sql
+++ /dev/null
@@ -1,65 +0,0 @@
--- 鏇存柊Activity琛ㄤ腑鐨勬椂闂存暟鎹紝涓烘瘡涓瘮璧涜缃笉鍚岀殑鏃堕棿
--- 杩欎釜鑴氭湰灏嗕负涓嶅悓鐨勬瘮璧涜缃笉鍚岀殑鎶ュ悕鎴鏃堕棿鍜屾瘮璧涙椂闂�
-
--- 鏇存柊姣旇禌ID 16 (2011)
-UPDATE t_activity SET
- signup_deadline = '2025-01-15 18:00:00',
- match_time = '2025-01-20 09:00:00'
-WHERE id = 16;
-
--- 鏇存柊姣旇禌ID 19 (2012)
-UPDATE t_activity SET
- signup_deadline = '2025-01-20 18:00:00',
- match_time = '2025-01-25 09:00:00'
-WHERE id = 19;
-
--- 鏇存柊姣旇禌ID 22 (2013)
-UPDATE t_activity SET
- signup_deadline = '2025-01-25 18:00:00',
- match_time = '2025-01-30 09:00:00'
-WHERE id = 22;
-
--- 鏇存柊姣旇禌ID 25 (2020)
-UPDATE t_activity SET
- signup_deadline = '2025-02-01 18:00:00',
- match_time = '2025-02-05 09:00:00'
-WHERE id = 25;
-
--- 鏇存柊姣旇禌ID 28 (2021)
-UPDATE t_activity SET
- signup_deadline = '2025-02-05 18:00:00',
- match_time = '2025-02-10 09:00:00'
-WHERE id = 28;
-
--- 鏇存柊姣旇禌ID 31 (2030)
-UPDATE t_activity SET
- signup_deadline = '2025-02-10 18:00:00',
- match_time = '2025-02-15 09:00:00'
-WHERE id = 31;
-
--- 鏇存柊姣旇禌ID 34 (2031)
-UPDATE t_activity SET
- signup_deadline = '2025-02-15 18:00:00',
- match_time = '2025-02-20 09:00:00'
-WHERE id = 34;
-
--- 鏇存柊姣旇禌ID 37 (3001)
-UPDATE t_activity SET
- signup_deadline = '2025-02-20 18:00:00',
- match_time = '2025-02-25 09:00:00'
-WHERE id = 37;
-
--- 鏇存柊姣旇禌ID 40 (3002)
-UPDATE t_activity SET
- signup_deadline = '2025-02-25 18:00:00',
- match_time = '2025-03-01 09:00:00'
-WHERE id = 40;
-
--- 鏇存柊姣旇禌ID 43 (3003)
-UPDATE t_activity SET
- signup_deadline = '2025-03-01 18:00:00',
- match_time = '2025-03-05 09:00:00'
-WHERE id = 43;
-
--- 楠岃瘉鏇存柊缁撴灉
-SELECT id, name, signup_deadline, match_time FROM t_activity WHERE id IN (16, 19, 22, 25, 28, 31, 34, 37, 40, 43) ORDER BY id;
\ No newline at end of file
diff --git a/verify-user-judge-mapping.js b/verify-user-judge-mapping.js
deleted file mode 100644
index e69db8c..0000000
--- a/verify-user-judge-mapping.js
+++ /dev/null
@@ -1,156 +0,0 @@
-const mysql = require('mysql2/promise');
-
-// 浠巃pplication.yml璇诲彇鐨勬暟鎹簱閰嶇疆
-const dbConfig = {
- host: '139.155.104.10',
- port: 3306,
- user: 'ryc',
- password: 'KiYap3E8X8RLcM6T',
- database: 'ryc',
- connectTimeout: 60000,
- acquireTimeout: 60000,
- timeout: 60000
-};
-
-async function verifyUserJudgeMapping() {
- console.log('=== 楠岃瘉鐢ㄦ埛ID=152鐨勮瘎濮旀潈闄� ===\n');
-
- let connection;
- try {
- // 杩炴帴鏁版嵁搴�
- console.log('姝e湪杩炴帴鏁版嵁搴�...');
- connection = await mysql.createConnection(dbConfig);
- console.log('鉁� 鏁版嵁搴撹繛鎺ユ垚鍔焅n');
-
- // 1. 鏌ヨ鐢ㄦ埛ID=152鐨勫熀鏈俊鎭�
- console.log('1. 鏌ヨ鐢ㄦ埛ID=152鐨勫熀鏈俊鎭�:');
- const [userRows] = await connection.execute(
- 'SELECT id, name, phone, state, create_time FROM t_user WHERE id = ?',
- [152]
- );
-
- if (userRows.length === 0) {
- console.log('鉂� 鐢ㄦ埛ID=152涓嶅瓨鍦�');
- return;
- }
-
- const user = userRows[0];
- console.log('鉁� 鐢ㄦ埛淇℃伅:');
- console.log(` ID: ${user.id}`);
- console.log(` 濮撳悕: ${user.name}`);
- console.log(` 鎵嬫満鍙�: ${user.phone}`);
- console.log(` 鐘舵��: ${user.state}`);
- console.log(` 鍒涘缓鏃堕棿: ${user.create_time}`);
-
- // 2. 鏌ヨ璇ョ敤鎴峰搴旂殑璇勫璁板綍
- console.log('\n2. 鏌ヨ鐢ㄦ埛ID=152瀵瑰簲鐨勮瘎濮旇褰�:');
- const [judgeRows] = await connection.execute(
- 'SELECT id, name, user_id, phone, state, title, company, create_time FROM t_judge WHERE user_id = ?',
- [152]
- );
-
- if (judgeRows.length === 0) {
- console.log('鉂� 鐢ㄦ埛ID=152娌℃湁瀵瑰簲鐨勮瘎濮旇褰�');
-
- // 妫�鏌ユ槸鍚︽湁鍚屾墜鏈哄彿鐨勮瘎濮旇褰�
- console.log('\n3. 妫�鏌ユ槸鍚︽湁鍚屾墜鏈哄彿鐨勮瘎濮旇褰�:');
- const [judgeByPhoneRows] = await connection.execute(
- 'SELECT id, name, user_id, phone, state FROM t_judge WHERE phone = ?',
- [user.phone]
- );
-
- if (judgeByPhoneRows.length > 0) {
- console.log('鈿狅笍 鍙戠幇鍚屾墜鏈哄彿鐨勮瘎濮旇褰�:');
- judgeByPhoneRows.forEach(judge => {
- console.log(` 璇勫ID: ${judge.id}, 鐢ㄦ埛ID: ${judge.user_id}, 濮撳悕: ${judge.name}, 鐘舵��: ${judge.state}`);
- });
- } else {
- console.log('鉂� 娌℃湁鎵惧埌鍚屾墜鏈哄彿鐨勮瘎濮旇褰�');
- }
- return;
- }
-
- const judge = judgeRows[0];
- console.log('鉁� 璇勫淇℃伅:');
- console.log(` 璇勫ID: ${judge.id}`);
- console.log(` 鐢ㄦ埛ID: ${judge.user_id}`);
- console.log(` 濮撳悕: ${judge.name}`);
- console.log(` 鎵嬫満鍙�: ${judge.phone}`);
- console.log(` 鐘舵��: ${judge.state}`);
- console.log(` 鑱屼綅: ${judge.title || '鏈缃�'}`);
- console.log(` 鍏徃: ${judge.company || '鏈缃�'}`);
- console.log(` 鍒涘缓鏃堕棿: ${judge.create_time}`);
-
- // 楠岃瘉鏄惁鏄瘎濮擨D=72
- if (judge.id === 72) {
- console.log('鉁� 纭锛氱敤鎴稩D=152瀵瑰簲璇勫ID=72');
- } else {
- console.log(`鈿狅笍 娉ㄦ剰锛氱敤鎴稩D=152瀵瑰簲璇勫ID=${judge.id}锛屼笉鏄�72`);
- }
-
- // 3. 妫�鏌ヨ瘎濮旂姸鎬�
- console.log('\n3. 妫�鏌ヨ瘎濮旂姸鎬�:');
- if (judge.state === 1) {
- console.log('鉁� 璇勫鐘舵�佹甯革紙state=1锛�');
- } else {
- console.log(`鉂� 璇勫鐘舵�佸紓甯革紙state=${judge.state}锛塦);
- }
-
- // 4. 鏌ヨ璇勫鍙備笌鐨勬椿鍔�
- console.log('\n4. 鏌ヨ璇勫鍙備笌鐨勬椿鍔�:');
- const [activityJudgeRows] = await connection.execute(
- 'SELECT aj.activity_id, a.name as activity_name, aj.stage_id FROM t_activity_judge aj LEFT JOIN t_activity a ON aj.activity_id = a.id WHERE aj.judge_id = ? LIMIT 5',
- [judge.id]
- );
-
- if (activityJudgeRows.length > 0) {
- console.log('鉁� 璇勫鍙備笌鐨勬椿鍔�:');
- activityJudgeRows.forEach(activity => {
- console.log(` 娲诲姩ID: ${activity.activity_id}, 娲诲姩鍚嶇О: ${activity.activity_name || '鏈煡'}, 闃舵ID: ${activity.stage_id}`);
- });
- } else {
- console.log('鈿狅笍 璇勫娌℃湁鍙備笌浠讳綍娲诲姩');
- }
-
- // 5. 鏌ヨ鏈�杩戠殑寰俊鐧诲綍璁板綍
- console.log('\n5. 鏌ヨ鐢ㄦ埛鏈�杩戠殑寰俊鐧诲綍璁板綍:');
- const [wxLoginRows] = await connection.execute(
- 'SELECT id, wx_openid, user_id, login_time, phone_authorized FROM t_wx_login_record WHERE user_id = ? ORDER BY login_time DESC LIMIT 3',
- [152]
- );
-
- if (wxLoginRows.length > 0) {
- console.log('鉁� 鏈�杩戠殑寰俊鐧诲綍璁板綍:');
- wxLoginRows.forEach(record => {
- console.log(` 璁板綍ID: ${record.id}, OpenID: ${record.wx_openid}, 鐧诲綍鏃堕棿: ${record.login_time}, 鎵嬫満鎺堟潈: ${record.phone_authorized}`);
- });
- } else {
- console.log('鈿狅笍 娌℃湁鎵惧埌寰俊鐧诲綍璁板綍');
- }
-
- // 6. 鎬荤粨
- console.log('\n=== 鎬荤粨 ===');
- if (judge.state === 1) {
- console.log('鉁� 鐢ㄦ埛ID=152纭疄鏈夋湁鏁堢殑璇勫鏉冮檺');
- console.log('鉁� 濡傛灉鍚庣浠嶇劧鎷掔粷璁块棶锛屽彲鑳芥槸UserContextUtil鐨勯�昏緫鏈夐棶棰�');
- } else {
- console.log('鉂� 璇勫璁板綍瀛樺湪浣嗙姸鎬佸紓甯革紝杩欏彲鑳芥槸鏉冮檺琚嫆缁濈殑鍘熷洜');
- }
-
- } catch (error) {
- console.error('鉂� 鏁版嵁搴撴煡璇㈠け璐�:', error.message);
- console.error('閿欒璇︽儏:', error);
- } finally {
- if (connection) {
- await connection.end();
- console.log('\n鏁版嵁搴撹繛鎺ュ凡鍏抽棴');
- }
- }
-}
-
-// 杩愯楠岃瘉
-if (require.main === module) {
- verifyUserJudgeMapping();
-}
-
-module.exports = { verifyUserJudgeMapping };
\ No newline at end of file
diff --git a/web/src/api/activity.js b/web/src/api/activity.js
index 8c42f87..ee9ab7a 100644
--- a/web/src/api/activity.js
+++ b/web/src/api/activity.js
@@ -44,6 +44,7 @@
stateName
createTime
updateTime
+ reviewExportUrl
ratingScheme {
id
name
@@ -61,6 +62,7 @@
state
stateName
sortOrder
+ reviewExportUrl
ratingScheme {
id
name
diff --git a/web/src/api/reviewExport.js b/web/src/api/reviewExport.js
new file mode 100644
index 0000000..779aad1
--- /dev/null
+++ b/web/src/api/reviewExport.js
@@ -0,0 +1,70 @@
+import { graphqlRequest } from '@/config/api'
+
+// 瀵煎嚭璇勫ZIP鐨凣raphQL鍙樻洿
+const EXPORT_REVIEW_ZIP_MUTATION = `
+ mutation ExportReviewZip($activityId: ID!, $stageIds: [ID]) {
+ exportReviewZip(activityId: $activityId, stageIds: $stageIds) {
+ success
+ url
+ message
+ }
+ }
+`
+
+// 寮傛瀵煎嚭锛氬惎鍔ㄨ瘎瀹″鍑轰换鍔�
+const START_REVIEW_EXPORT_JOB_MUTATION = `
+ mutation StartReviewExportJob($activityId: ID!, $stageIds: [ID]) {
+ startReviewExportJob(activityId: $activityId, stageIds: $stageIds)
+ }
+`
+
+// 鏌ヨ璇勫瀵煎嚭浠诲姟鐘舵��
+const GET_REVIEW_EXPORT_JOB_STATUS_QUERY = `
+ query GetReviewExportJobStatus($jobId: String!) {
+ getReviewExportJobStatus(jobId: $jobId) {
+ jobId
+ status
+ url
+ message
+ progress
+ }
+ }
+`
+
+/**
+ * 瑙﹀彂璇勫瀵煎嚭ZIP
+ * @param {number|string} activityId 娲诲姩ID锛堜富娲诲姩ID锛�
+ * @param {Array<number>|null} stageIds 鍙�夌殑闃舵ID鍒楄〃锛涜嫢涓虹┖鍒欏鍑烘暣涓椿鍔�
+ * @returns {Promise<{success: boolean, url?: string, message?: string}>}
+ */
+export const exportReviewZip = async (activityId, stageIds = null) => {
+ const result = await graphqlRequest(EXPORT_REVIEW_ZIP_MUTATION, { activityId, stageIds })
+ return result?.data?.exportReviewZip
+}
+
+/**
+ * 鍚姩璇勫瀵煎嚭浠诲姟锛岃繑鍥� jobId
+ * @param {number|string} activityId
+ * @param {Array<number>|null} stageIds
+ * @returns {Promise<string|null>} jobId
+ */
+export const startReviewExportJob = async (activityId, stageIds = null) => {
+ const result = await graphqlRequest(START_REVIEW_EXPORT_JOB_MUTATION, { activityId, stageIds })
+ return result?.data?.startReviewExportJob || null
+}
+
+/**
+ * 鏌ヨ璇勫瀵煎嚭浠诲姟鐘舵��
+ * @param {string} jobId
+ * @returns {Promise<{jobId: string, status: string, url?: string, message?: string, progress?: number} | null>}
+ */
+export const getReviewExportJobStatus = async (jobId) => {
+ const result = await graphqlRequest(GET_REVIEW_EXPORT_JOB_STATUS_QUERY, { jobId })
+ return result?.data?.getReviewExportJobStatus || null
+}
+
+export default {
+ exportReviewZip,
+ startReviewExportJob,
+ getReviewExportJobStatus
+}
\ No newline at end of file
diff --git a/web/src/views/ActivityDetail.vue b/web/src/views/ActivityDetail.vue
index 886b867..61575e3 100644
--- a/web/src/views/ActivityDetail.vue
+++ b/web/src/views/ActivityDetail.vue
@@ -5,6 +5,7 @@
<div class="card-header">
<span>姣旇禌璇︽儏</span>
<div>
+ <el-button v-if="canExport" type="primary" :loading="exportingActivity" @click="handleExportActivity">瀵煎嚭璇勫ZIP</el-button>
<el-button @click="handleEdit">缂栬緫姣旇禌</el-button>
<el-button @click="goBack">杩斿洖</el-button>
</div>
@@ -23,6 +24,18 @@
<el-descriptions-item label="姣旇禌鍦板潃">{{ activity.address || '-' }}</el-descriptions-item>
<el-descriptions-item label="璇勫垎妯℃澘">
{{ activity.ratingScheme ? activity.ratingScheme.name : '-' }}
+ </el-descriptions-item>
+ <el-descriptions-item label="鏈�杩戣瘎瀹″鍑�" :span="2">
+ <template v-if="activity.reviewExportUrl">
+ <a :href="activity.reviewExportUrl" target="_blank">鐐瑰嚮涓嬭浇</a>
+ </template>
+ <template v-else>
+ 鏆傛棤
+ </template>
+ <span v-if="exportJobActivity && exportingActivity" class="export-status">
+ 瀵煎嚭浠诲姟杩涜涓�
+ <span v-if="exportJobActivity.progress !== null && exportJobActivity.progress !== undefined">锛坽{ exportJobActivity.progress }}%锛�</span>
+ </span>
</el-descriptions-item>
<el-descriptions-item label="鍒涘缓鏃堕棿" :span="2">{{ formatDateTime(activity.createTime) }}</el-descriptions-item>
</el-descriptions>
@@ -54,11 +67,32 @@
<el-tag :type="getStateType(row.state)">{{ row.stateName }}</el-tag>
</template>
</el-table-column>
- <el-table-column label="鎿嶄綔" width="220" fixed="right">
+ <el-table-column label="鏈�杩戝鍑�" width="200">
+ <template #default="{ row }">
+ <template v-if="row.reviewExportUrl">
+ <a :href="row.reviewExportUrl" target="_blank">涓嬭浇ZIP</a>
+ </template>
+ <template v-else>
+ <span style="color: #909399;">鏆傛棤</span>
+ </template>
+ <div v-if="exportJobStageMap[row.id] && exportingStageId === row.id" class="export-status">
+ 瀵煎嚭浠诲姟杩涜涓�
+ <span v-if="exportJobStageMap[row.id].progress !== null && exportJobStageMap[row.id].progress !== undefined">锛坽{ exportJobStageMap[row.id].progress }}%锛�</span>
+ </div>
+ </template>
+ </el-table-column>
+ <el-table-column label="鎿嶄綔" width="320" fixed="right">
<template #default="{ row }">
<el-button size="small" @click="viewStageDetail(row)">鏌ョ湅璇︽儏</el-button>
<el-button size="small" type="warning" @click="closeStage(row)" v-if="row.state === 1">鍏抽棴</el-button>
<el-button size="small" type="danger" @click="deleteStage(row)">鍒犻櫎</el-button>
+ <el-button
+ v-if="canExport"
+ size="small"
+ type="primary"
+ :loading="exportingStageId === row.id"
+ @click="handleExportStage(row)"
+ >瀵煎嚭闃舵璇勫</el-button>
</template>
</el-table-column>
</el-table>
@@ -125,10 +159,12 @@
</template>
<script setup>
-import { ref, onMounted, computed } from 'vue'
+import { ref, onMounted, onUnmounted, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getActivity } from '@/api/activity'
+import { exportReviewZip, startReviewExportJob, getReviewExportJobStatus } from '@/api/reviewExport'
+import { isEmployee } from '@/utils/auth'
const router = useRouter()
const route = useRoute()
@@ -138,6 +174,13 @@
const activity = ref(null)
const stageDialogVisible = ref(false)
const selectedStage = ref(null)
+const exportingActivity = ref(false)
+const exportingStageId = ref(null)
+// 寮傛瀵煎嚭浠诲姟鐘舵��
+const exportJobActivity = ref(null) // { jobId, status, progress, message }
+const exportJobStageMap = ref({}) // { [stageId]: { jobId, status, progress, message } }
+let activityPollTimer = null
+const stagePollTimers = {}
// 璁$畻灞炴��
const sortedStages = computed(() => {
@@ -248,6 +291,139 @@
onMounted(() => {
loadActivity()
})
+
+onUnmounted(() => {
+ if (activityPollTimer) {
+ clearInterval(activityPollTimer)
+ activityPollTimer = null
+ }
+ Object.keys(stagePollTimers).forEach((sid) => {
+ if (stagePollTimers[sid]) {
+ clearInterval(stagePollTimers[sid])
+ delete stagePollTimers[sid]
+ }
+ })
+})
+
+// 鏄惁鍙墽琛屽鍑猴紙浠呭憳宸ワ級
+const canExport = computed(() => isEmployee())
+
+// 瀵煎嚭涓绘椿鍔ㄨ瘎瀹IP
+const handleExportActivity = async () => {
+ try {
+ await ElMessageBox.confirm('灏嗗鍑鸿姣旇禌涓嬫墍鏈夐樁娈电殑宸茶瘎鍒嗘暟鎹负ZIP锛岀‘璁ょ户缁紵', '纭瀵煎嚭', {
+ confirmButtonText: '纭畾',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning'
+ })
+ exportingActivity.value = true
+ // 浼樺厛浣跨敤寮傛瀵煎嚭浠诲姟
+ const jobId = await startReviewExportJob(route.params.id)
+ if (jobId) {
+ exportJobActivity.value = { jobId, status: 'PENDING', progress: 0 }
+ // 杞浠诲姟鐘舵��
+ activityPollTimer = setInterval(async () => {
+ try {
+ const status = await getReviewExportJobStatus(jobId)
+ if (status) {
+ exportJobActivity.value = status
+ if (status.status === 'SUCCEEDED') {
+ clearInterval(activityPollTimer)
+ activityPollTimer = null
+ ElMessage.success('瀵煎嚭鎴愬姛')
+ await loadActivity()
+ exportingActivity.value = false
+ } else if (status.status === 'FAILED') {
+ clearInterval(activityPollTimer)
+ activityPollTimer = null
+ ElMessage.error(status.message || '瀵煎嚭澶辫触')
+ exportingActivity.value = false
+ }
+ }
+ } catch (e) {
+ console.warn('鏌ヨ瀵煎嚭浠诲姟鐘舵�佸け璐ワ細', e?.message || e)
+ }
+ }, 2000)
+ } else {
+ // 鍥為��锛氫娇鐢ㄥ悓姝ュ鍑�
+ const res = await exportReviewZip(route.params.id)
+ if (res?.success) {
+ ElMessage.success('瀵煎嚭鎴愬姛')
+ await loadActivity()
+ } else {
+ ElMessage.error(res?.message || '瀵煎嚭澶辫触')
+ }
+ exportingActivity.value = false
+ }
+ } catch (e) {
+ // 鐢ㄦ埛鍙栨秷鎴栧紓甯�
+ if (e && e.message) {
+ console.warn('瀵煎嚭鎿嶄綔鍙栨秷鎴栧け璐ワ細', e.message)
+ }
+ } finally {
+ // 寮傛瀵煎嚭鏃剁敱杞鍥炶皟璐熻矗鍏抽棴 loading锛涙澶勪粎鍦ㄦ湭鍚姩浠诲姟鏃堕噸缃�
+ if (!activityPollTimer) {
+ exportingActivity.value = false
+ }
+ }
+}
+
+// 瀵煎嚭鎸囧畾闃舵璇勫ZIP
+const handleExportStage = async (stage) => {
+ try {
+ await ElMessageBox.confirm(`灏嗗鍑恒��${stage.name}銆戦樁娈电殑宸茶瘎鍒嗘暟鎹负ZIP锛岀‘璁ょ户缁紵`, '纭瀵煎嚭', {
+ confirmButtonText: '纭畾',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning'
+ })
+ exportingStageId.value = stage.id
+ const jobId = await startReviewExportJob(route.params.id, [stage.id])
+ if (jobId) {
+ exportJobStageMap.value[stage.id] = { jobId, status: 'PENDING', progress: 0 }
+ // 杞闃舵瀵煎嚭鐘舵��
+ stagePollTimers[stage.id] = setInterval(async () => {
+ try {
+ const status = await getReviewExportJobStatus(jobId)
+ if (status) {
+ exportJobStageMap.value[stage.id] = status
+ if (status.status === 'SUCCEEDED') {
+ clearInterval(stagePollTimers[stage.id])
+ delete stagePollTimers[stage.id]
+ ElMessage.success('瀵煎嚭鎴愬姛')
+ await loadActivity()
+ exportingStageId.value = null
+ } else if (status.status === 'FAILED') {
+ clearInterval(stagePollTimers[stage.id])
+ delete stagePollTimers[stage.id]
+ ElMessage.error(status.message || '瀵煎嚭澶辫触')
+ exportingStageId.value = null
+ }
+ }
+ } catch (e) {
+ console.warn('鏌ヨ闃舵瀵煎嚭浠诲姟鐘舵�佸け璐ワ細', e?.message || e)
+ }
+ }, 2000)
+ } else {
+ // 鍥為��锛氬悓姝ュ鍑�
+ const res = await exportReviewZip(route.params.id, [stage.id])
+ if (res?.success) {
+ ElMessage.success('瀵煎嚭鎴愬姛')
+ await loadActivity()
+ } else {
+ ElMessage.error(res?.message || '瀵煎嚭澶辫触')
+ }
+ exportingStageId.value = null
+ }
+ } catch (e) {
+ if (e && e.message) {
+ console.warn('瀵煎嚭闃舵鎿嶄綔鍙栨秷鎴栧け璐ワ細', e.message)
+ }
+ } finally {
+ if (!stagePollTimers[stage.id]) {
+ exportingStageId.value = null
+ }
+ }
+}
</script>
<style scoped>
diff --git a/web/src/views/activity-list.vue b/web/src/views/activity-list.vue
index 65b8f86..c1eec42 100644
--- a/web/src/views/activity-list.vue
+++ b/web/src/views/activity-list.vue
@@ -54,9 +54,17 @@
<el-tag :type="getStatusType(row.stateName)">{{ row.stateName }}</el-tag>
</template>
</el-table-column>
- <el-table-column label="鎿嶄綔" width="120" fixed="right" align="center">
+ <el-table-column label="鎿嶄綔" width="180" fixed="right" align="center">
<template #default="{ row }">
<div class="table-actions">
+ <el-button
+ text
+ :icon="View"
+ size="small"
+ @click="handleView(row)"
+ class="action-btn view-btn"
+ title="璇︽儏"
+ />
<el-button
text
:icon="Edit"
@@ -99,7 +107,7 @@
import { ElMessage, ElMessageBox } from 'element-plus'
import { useRouter } from 'vue-router'
import { getActivities, updateActivityState } from '@/api/activity'
-import { Search, Plus, Edit, Delete } from '@element-plus/icons-vue'
+import { Search, Plus, Edit, Delete, View } from '@element-plus/icons-vue'
console.log('=== activity-list.vue 缁勪欢寮�濮嬪姞杞� ===')
@@ -177,6 +185,11 @@
// 缂栬緫姣旇禌
const handleEdit = (row: any) => {
router.push(`/activity/edit/${row.id}`)
+}
+
+// 鏌ョ湅璇︽儏
+const handleView = (row: any) => {
+ router.push(`/activity/${row.id}`)
}
// 鍒犻櫎姣旇禌
@@ -351,6 +364,16 @@
background: rgba(245, 108, 108, 0.1) !important;
}
+.view-btn {
+ color: #67C23A;
+}
+
+.view-btn:hover {
+ color: #5daf34;
+ transform: scale(1.2);
+ background: rgba(103, 194, 58, 0.1) !important;
+}
+
.pagination {
margin-top: 20px;
display: flex;
diff --git a/web/vite.config.ts b/web/vite.config.ts
index d0a27bd..e44174f 100644
--- a/web/vite.config.ts
+++ b/web/vite.config.ts
@@ -15,22 +15,11 @@
open: true,
proxy: {
'/api': {
+ // 灏咥PI浠g悊鍥炴湰鍦板悗绔紝渚夸簬瀹屾暣鑱旇皟锛堝悗绔繍琛屽湪 http://127.0.0.1:8080/api锛�
target: 'http://127.0.0.1:8080',
changeOrigin: true,
secure: false,
- configure: (proxy, options) => {
- proxy.on('error', (err, req, res) => {
- console.log('proxy error', err);
- });
- proxy.on('proxyReq', (proxyReq, req, res) => {
- console.log('Sending Request to the Target:', req.method, req.url);
- });
- proxy.on('proxyRes', (proxyRes, req, res) => {
- console.log('Received Response from the Target:', proxyRes.statusCode, req.url);
- });
- },
- // 涓嶉渶瑕侀噸鍐欒矾寰勶紝鍥犱负鍚庣鐨刢ontext-path灏辨槸/api
- // rewrite: (path) => path.replace(/^\/api/, '/api')
+ // 涓嶉渶瑕侀噸鍐欒矾寰勶紝鍥犱负鍚庣鐨刢ontext-path灏辨槸 /api
}
}
},
diff --git a/wx/pages/activity/detail.js b/wx/pages/activity/detail.js
index 83989e1..38c6a70 100644
--- a/wx/pages/activity/detail.js
+++ b/wx/pages/activity/detail.js
@@ -9,6 +9,10 @@
myApplication: null,
buttonDisabled: false,
buttonText: '鎴戣鎶ュ悕',
+ // 瀵煎嚭鐩稿叧
+ isEmployee: false,
+ exportingActivity: false,
+ exportingStageId: null,
loading: true,
error: null
},
@@ -88,12 +92,16 @@
}
}
+ // 瑙掕壊锛氭槸鍚﹀憳宸ワ紙涓诲姙鏂�/绠$悊鍛橈級
+ const isEmployee = !!(app.globalData?.userInfo?.employee && app.globalData.userInfo.employee.id)
+
this.setData({
activity: res.activity,
myApplication: myApplication,
loading: false,
buttonDisabled: buttonDisabled,
- buttonText: buttonText
+ buttonText: buttonText,
+ isEmployee: isEmployee
});
} else {
throw new Error('鏈壘鍒版瘮璧涗俊鎭�');
@@ -135,5 +143,108 @@
return `${startDate} - ${endDate}`;
}
return startDate || endDate;
+ },
+
+ // 澶嶅埗閾炬帴鍒板壀璐存澘
+ copyLink(e) {
+ const url = e.currentTarget.dataset.url
+ if (!url) {
+ wx.showToast({ title: '鏆傛棤閾炬帴', icon: 'none' })
+ return
+ }
+ wx.setClipboardData({
+ data: url,
+ success: () => {
+ wx.showToast({ title: '宸插鍒朵笅杞介摼鎺�', icon: 'success' })
+ }
+ })
+ },
+
+ // 鍦╓ebView鍐呮墦寮�閾炬帴锛堢敤浜庨瑙�/涓嬭浇锛�
+ openWebView(e) {
+ const url = e.currentTarget.dataset.url
+ if (!url) {
+ wx.showToast({ title: '鏆傛棤閾炬帴', icon: 'none' })
+ return
+ }
+ wx.navigateTo({
+ url: `/pages/webview/webview?url=${encodeURIComponent(url)}&title=${encodeURIComponent('璇勫瀵煎嚭ZIP')}`
+ })
+ },
+
+ // 瑙﹀彂瀵煎嚭锛堜富娲诲姩锛�
+ async handleExportActivity() {
+ if (!this.data.isEmployee) {
+ wx.showToast({ title: '鏃犳潈闄愭墽琛屽鍑�', icon: 'none' })
+ return
+ }
+ if (!this.data.activityId) {
+ wx.showToast({ title: '鏃犳晥鐨勬椿鍔↖D', icon: 'none' })
+ return
+ }
+ this.setData({ exportingActivity: true })
+ const mutation = `
+ mutation ExportReviewZip($activityId: ID!, $stageIds: [ID]) {
+ exportReviewZip(activityId: $activityId, stageIds: $stageIds) {
+ success
+ url
+ message
+ }
+ }
+ `
+ try {
+ const res = await app.graphqlRequest(mutation, { activityId: this.data.activityId, stageIds: null })
+ const result = res && res.exportReviewZip
+ if (result && result.success) {
+ wx.showToast({ title: '瀵煎嚭鎴愬姛', icon: 'success' })
+ // 鍒锋柊浠ユ樉绀烘渶鏂伴摼鎺�
+ await this.loadActivityDetail(this.data.activityId)
+ } else {
+ wx.showToast({ title: result?.message || '瀵煎嚭澶辫触', icon: 'none' })
+ }
+ } catch (err) {
+ console.error('瀵煎嚭澶辫触:', err)
+ wx.showToast({ title: '瀵煎嚭澶辫触', icon: 'none' })
+ } finally {
+ this.setData({ exportingActivity: false })
+ }
+ },
+
+ // 瑙﹀彂瀵煎嚭锛堥樁娈碉級
+ async handleExportStage(e) {
+ if (!this.data.isEmployee) {
+ wx.showToast({ title: '鏃犳潈闄愭墽琛屽鍑�', icon: 'none' })
+ return
+ }
+ const stageId = e.currentTarget.dataset.stageId
+ if (!stageId) {
+ wx.showToast({ title: '鏃犳晥鐨勯樁娈礗D', icon: 'none' })
+ return
+ }
+ this.setData({ exportingStageId: stageId })
+ const mutation = `
+ mutation ExportReviewZip($activityId: ID!, $stageIds: [ID]) {
+ exportReviewZip(activityId: $activityId, stageIds: $stageIds) {
+ success
+ url
+ message
+ }
+ }
+ `
+ try {
+ const res = await app.graphqlRequest(mutation, { activityId: this.data.activityId, stageIds: [stageId] })
+ const result = res && res.exportReviewZip
+ if (result && result.success) {
+ wx.showToast({ title: '瀵煎嚭鎴愬姛', icon: 'success' })
+ await this.loadActivityDetail(this.data.activityId)
+ } else {
+ wx.showToast({ title: result?.message || '瀵煎嚭澶辫触', icon: 'none' })
+ }
+ } catch (err) {
+ console.error('瀵煎嚭闃舵澶辫触:', err)
+ wx.showToast({ title: '瀵煎嚭澶辫触', icon: 'none' })
+ } finally {
+ this.setData({ exportingStageId: null })
+ }
}
});
diff --git a/wx/pages/activity/detail.wxml b/wx/pages/activity/detail.wxml
index d155420..85b3986 100644
--- a/wx/pages/activity/detail.wxml
+++ b/wx/pages/activity/detail.wxml
@@ -34,6 +34,7 @@
<text class="info-label">姣旇禌寮�濮嬫椂闂�</text>
<text class="info-value">{{filters.formatDateTime(activity.matchTime)}}</text>
</view>
+ <!-- 鏈�杩戣瘎瀹″鍑轰俊鎭笉灞曠ず涓嬭浇鍦板潃锛屾暣浣撶Щ闄� -->
</view>
</view>
@@ -48,6 +49,10 @@
<view class="timeline-content">
<view class="stage-name">{{item.name}}</view>
<view class="stage-date">{{filters.formatDate(item.matchTime)}}</view>
+ <view class="stage-export">
+ <!-- 涓嶅睍绀轰笅杞藉湴鍧�锛屼粎淇濈暀瀵煎嚭鎸夐挳锛堝憳宸ュ彲瑙侊級 -->
+ <button wx:if="{{isEmployee}}" class="mini-btn primary" size="mini" bindtap="handleExportStage" data-stage-id="{{item.id}}" loading="{{exportingStageId === item.id}}">瀵煎嚭闃舵璇勫</button>
+ </view>
</view>
</view>
</view>
@@ -65,6 +70,7 @@
<!-- 搴曢儴鎿嶄綔鏍� -->
<view class="footer-actions">
<button class="register-btn" bindtap="handleRegister" disabled="{{buttonDisabled}}">{{buttonText}}</button>
+ <button wx:if="{{isEmployee}}" class="export-btn" bindtap="handleExportActivity" loading="{{exportingActivity}}">瀵煎嚭璇勫ZIP</button>
</view>
</block>
</view>
\ No newline at end of file
diff --git a/wx/pages/registration/registration.js b/wx/pages/registration/registration.js
index 2180b15..cdaf2bf 100644
--- a/wx/pages/registration/registration.js
+++ b/wx/pages/registration/registration.js
@@ -1140,6 +1140,11 @@
errors.phone = '璇疯緭鍏ユ纭殑鎵嬫満鍙�';
}
+ // 椤圭洰鍚嶇О涓哄繀濉」
+ if (!formData.projectName || !formData.projectName.trim()) {
+ errors.projectName = '璇疯緭鍏ラ」鐩悕绉�';
+ }
+
// 淇濇寔鍘熸湁閫昏緫锛氫笉寮哄埗闄勪欢蹇呭~锛屼笉鏍¢獙鎵�灞炲尯鍩熷繀濉�
this.setData({ errors });
@@ -1258,7 +1263,7 @@
},
regionId: formData.regionId,
projectName: formData.projectName,
- description: formData.description
+ // 椤圭洰鎻忚堪涓嶉噰闆嗭紝涓嶆彁浜ゅ埌鍚庣
}
// 绗竴姝ワ細鍏堟彁浜ゆ敞鍐屾暟鎹埌鍚庡彴锛岃幏寰楁敞鍐孖D
@@ -1336,7 +1341,6 @@
},
regionId: submitData.regionId || null,
projectName: submitData.projectName || '',
- description: submitData.description || '',
attachmentMediaIds: [] // 鍏堜笉浼犻檮浠�
};
diff --git a/wx/pages/registration/registration.wxml b/wx/pages/registration/registration.wxml
index dbc28e8..0bba1f1 100644
--- a/wx/pages/registration/registration.wxml
+++ b/wx/pages/registration/registration.wxml
@@ -157,12 +157,12 @@
</view>
</view>
- <!-- 椤圭洰淇℃伅鍗$墖锛堟寜闇�姹傞殣钘忥級 -->
- <view wx:if="{{false}}" class="card">
+ <!-- 椤圭洰淇℃伅鍗$墖 -->
+ <view class="card">
<view class="card-title">椤圭洰淇℃伅</view>
<!-- 椤圭洰鍚嶇О -->
<view class="form-item {{errors.projectName ? 'error' : ''}}">
- <text class="label">椤圭洰鍚嶇О</text>
+ <text class="label required">椤圭洰鍚嶇О</text>
<view class="input-wrapper">
<input
class="input"
@@ -174,23 +174,6 @@
/>
</view>
<text wx:if="{{errors.projectName}}" class="error-text">{{errors.projectName}}</text>
- </view>
-
- <!-- 椤圭洰鎻忚堪 -->
- <view class="form-item vertical-layout {{errors.description ? 'error' : ''}}">
- <text class="label">椤圭洰鎻忚堪</text>
- <view class="input-wrapper">
- <textarea
- class="textarea"
- placeholder-class="placeholder-class"
- placeholder="璇疯缁嗘弿杩版偍鐨勯」鐩唴瀹广�佺洰鏍囧拰鐗硅壊"
- value="{{formData.description}}"
- data-field="description"
- bindinput="onInputChange"
- maxlength="1000"
- />
- </view>
- <text wx:if="{{errors.description}}" class="error-text">{{errors.description}}</text>
</view>
</view>
--
Gitblit v1.8.0