From fe95f471666d93e7822a4886c1c69dafbd6b2a1e Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期一, 22 九月 2025 17:57:31 +0800
Subject: [PATCH] feat:更新保存

---
 .gitignore                                                                              |    3 
 微信授权功能使用说明.md                                                                           |  124 ++++++++++
 966120App                                                                               |    1 
 微信授权调试指南.md                                                                             |  209 +++++++++++++++++
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java |   52 ++++
 ruoyi-admin/src/main/resources/application.yml                                          |   11 
 ruoyi-ui/src/views/evaluation/index.vue                                                 |  188 +++++++++++++++
 ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java                      |   72 ++++-
 ruoyi-ui/src/api/evaluation.js                                                          |    9 
 9 files changed, 645 insertions(+), 24 deletions(-)

diff --git a/.gitignore b/.gitignore
index fc72bc7..1a65bdf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,4 +45,5 @@
 !*/build/*.java
 !*/build/*.html
 !*/build/*.xml
-node_modules/
\ No newline at end of file
+node_modules/
+966120App/
diff --git a/966120App b/966120App
new file mode 120000
index 0000000..1d91346
--- /dev/null
+++ b/966120App
@@ -0,0 +1 @@
+D:/project/鎬ユ晳杞繍/code/966120
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java
index a65988f..2786bef 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/evaluation/EvaluationController.java
@@ -1,5 +1,6 @@
 package com.ruoyi.web.controller.evaluation;
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import javax.servlet.http.HttpServletRequest;
@@ -156,6 +157,38 @@
     private String wechatAppSecret;
 
     /**
+     * 鐢熸垚寰俊鎺堟潈URL
+     */
+    @Anonymous
+    @GetMapping("/wechat/authurl")
+    public AjaxResult getWechatAuthUrl(String redirectUri, String state) {
+        try {
+            if (StringUtils.isEmpty(redirectUri)) {
+                return error("鍥炶皟鍦板潃涓嶈兘涓虹┖");
+            }
+            
+            logger.info("鐢熸垚寰俊鎺堟潈URL - 鍘熷redirectUri: {}", redirectUri);
+            
+            // 鐢熸垚寰俊鎺堟潈URL锛屼娇鐢╯nsapi_userinfo鑾峰彇鐢ㄦ埛淇℃伅
+            String authUrl = WechatUtils.generateAuthUrl(wechatAppId, redirectUri, "snsapi_userinfo", state);
+            if (authUrl == null) {
+                return error("鐢熸垚寰俊鎺堟潈URL澶辫触");
+            }
+            
+            logger.info("鐢熸垚寰俊鎺堟潈URL鎴愬姛: {}", authUrl);
+            
+            Map<String, String> result = new HashMap<>();
+            result.put("authUrl", authUrl);
+            result.put("originalRedirectUri", redirectUri);
+            result.put("appId", wechatAppId);
+            return success(result);
+        } catch (Exception e) {
+            logger.error("鐢熸垚寰俊鎺堟潈URL澶辫触", e);
+            return error("鐢熸垚寰俊鎺堟潈URL澶辫触: " + e.getMessage());
+        }
+    }
+
+    /**
      * 鑾峰彇寰俊鐢ㄦ埛淇℃伅
      */
     @Anonymous
@@ -163,7 +196,7 @@
     public AjaxResult getWechatUserInfo(String code, HttpServletRequest request) {
         try {
             
-            if (StringUtils.isEmpty(code)) {
+            if (code.isEmpty()) {
                 return error("鎺堟潈鐮佷笉鑳戒负绌�");
             }
 
@@ -182,7 +215,22 @@
                 return error("鑾峰彇寰俊鐢ㄦ埛淇℃伅澶辫触");
             }
 
-            return success(userInfo);
+            // 澶勭悊鐢ㄦ埛淇℃伅锛岀‘淇濆瓧娈靛悕绉颁竴鑷�
+            Map<String, Object> result = new HashMap<>();
+            result.put("openid", userInfo.getString("openid"));
+            result.put("nickname", userInfo.getString("nickname"));
+            result.put("headimgurl", userInfo.getString("headimgurl"));
+            result.put("sex", userInfo.getInteger("sex"));
+            result.put("province", userInfo.getString("province"));
+            result.put("city", userInfo.getString("city"));
+            result.put("country", userInfo.getString("country"));
+            result.put("unionid", userInfo.getString("unionid"));
+            // 娉ㄦ剰锛氬井淇$綉椤垫巿鏉冩棤娉曠洿鎺ヨ幏鍙栨墜鏈哄彿锛岄渶瑕侀�氳繃鍏朵粬鏂瑰紡
+            // 濡傞渶鑾峰彇鎵嬫満鍙凤紝闇�瑕佷娇鐢ㄥ井淇″皬绋嬪簭鐨刧etPhoneNumber鎺ュ彛鎴栧井淇″紑鏀惧钩鍙扮殑鎵嬫満鍙峰揩閫熼獙璇佺粍浠�
+            result.put("phone", "");
+            result.put("phoneNote", "寰俊缃戦〉鎺堟潈鏃犳硶鐩存帴鑾峰彇鎵嬫満鍙凤紝璇锋墜鍔ㄨ緭鍏�");
+
+            return success(result);
         } catch (Exception e) {
             logger.error("鑾峰彇寰俊鐢ㄦ埛淇℃伅澶辫触", e);
             return error("鑾峰彇寰俊鐢ㄦ埛淇℃伅澶辫触");
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 69c5d06..626c3a6 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -147,6 +147,11 @@
 
 # 寰俊閰嶇疆
 wechat:
-  appId: your_wechat_appid
-  appSecret: your_wechat_appsecret
-  redirectUri: http://yourdomain.com/evaluation
\ No newline at end of file
+  appId: wx70f6a7346ee842c0
+  appSecret: 2d6c59de85e876b7eadebeba62e5417a
+  redirectUri: http://yourdomain.com/evaluation
+  # 寮�鍙戠幆澧冮厤缃�
+  dev:
+    enabled: true  # 鏄惁鍚敤寮�鍙戞ā寮�
+    mockUserInfo: true  # 鏄惁妯℃嫙鐢ㄦ埛淇℃伅
+    ngrokUrl: http://your-ngrok-url.ngrok.io  # 鍐呯綉绌块�忓湴鍧�
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java
index 5b3e6e8..53ff3a3 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WechatUtils.java
@@ -4,7 +4,7 @@
 import com.alibaba.fastjson2.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.web.client.RestTemplate;
+import com.ruoyi.common.utils.http.HttpUtils;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -18,7 +18,8 @@
     
     private static final Logger log = LoggerFactory.getLogger(WechatUtils.class);
     
-    private static final String WECHAT_API_BASE_URL = "https://api.weixin.qq.com";
+    private static final String WECHAT_API_BASE_URL = "https://open.weixin.qq.com";
+    private static final String WECHAT_API_BASE_URL_SERVER = "https://api.weixin.qq.com";
     
     /**
      * 鑾峰彇寰俊Access Token
@@ -29,10 +30,10 @@
      */
     public static String getAccessToken(String appId, String appSecret) {
         try {
-            String url = WECHAT_API_BASE_URL + "/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
+            String url = WECHAT_API_BASE_URL_SERVER + "/cgi-bin/token";
+            String param = "grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
             
-            RestTemplate restTemplate = new RestTemplate();
-            String response = restTemplate.getForObject(url, String.class);
+            String response = HttpUtils.sendGet(url, param);
             
             JSONObject jsonObject = JSON.parseObject(response);
             if (jsonObject.containsKey("access_token")) {
@@ -56,10 +57,10 @@
      */
     public static JSONObject getWechatUserInfo(String accessToken, String openid) {
         try {
-            String url = WECHAT_API_BASE_URL + "/cgi-bin/user/info?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
+            String url = WECHAT_API_BASE_URL_SERVER + "/cgi-bin/user/info";
+            String param = "access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
             
-            RestTemplate restTemplate = new RestTemplate();
-            String response = restTemplate.getForObject(url, String.class);
+            String response = HttpUtils.sendGet(url, param);
             
             JSONObject jsonObject = JSON.parseObject(response);
             if (jsonObject.containsKey("openid")) {
@@ -84,10 +85,10 @@
      */
     public static JSONObject getWebAccessToken(String appId, String appSecret, String code) {
         try {
-            String url = WECHAT_API_BASE_URL + "/sns/oauth2/access_token?appid=" + appId + "&secret=" + appSecret + "&code=" + code + "&grant_type=authorization_code";
+            String url = WECHAT_API_BASE_URL_SERVER + "/sns/oauth2/access_token";
+            String param = "appid=" + appId + "&secret=" + appSecret + "&code=" + code + "&grant_type=authorization_code";
             
-            RestTemplate restTemplate = new RestTemplate();
-            String response = restTemplate.getForObject(url, String.class);
+            String response = HttpUtils.sendGet(url, param);
             
             JSONObject jsonObject = JSON.parseObject(response);
             if (jsonObject.containsKey("access_token")) {
@@ -111,10 +112,10 @@
      */
     public static JSONObject getWebUserInfo(String accessToken, String openid) {
         try {
-            String url = WECHAT_API_BASE_URL + "/sns/userinfo?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
+            String url = WECHAT_API_BASE_URL_SERVER + "/sns/userinfo";
+            String param = "access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
             
-            RestTemplate restTemplate = new RestTemplate();
-            String response = restTemplate.getForObject(url, String.class);
+            String response = HttpUtils.sendGet(url, param);
             
             JSONObject jsonObject = JSON.parseObject(response);
             if (jsonObject.containsKey("openid")) {
@@ -140,8 +141,16 @@
      */
     public static String generateAuthUrl(String appId, String redirectUri, String scope, String state) {
         try {
-            String encodedRedirectUri = java.net.URLEncoder.encode(redirectUri, "UTF-8");
-            return WECHAT_API_BASE_URL + "/connect/oauth2/authorize?appid=" + appId + "&redirect_uri=" + encodedRedirectUri + "&response_type=code&scope=" + scope + "&state=" + state + "#wechat_redirect";
+            // 娓呯悊鍜岄獙璇乺edirectUri
+            String cleanRedirectUri = cleanRedirectUri(redirectUri);
+            
+            // URL缂栫爜
+            String encodedRedirectUri = java.net.URLEncoder.encode(cleanRedirectUri, "UTF-8");
+            
+            return WECHAT_API_BASE_URL + "/connect/oauth2/authorize?appid=" + appId + 
+                   "&redirect_uri=" + encodedRedirectUri + 
+                   "&response_type=code&scope=" + scope + 
+                   "&state=" + state + "#wechat_redirect";
         } catch (Exception e) {
             log.error("鐢熸垚寰俊鎺堟潈URL寮傚父: {}", e.getMessage());
             return null;
@@ -149,6 +158,37 @@
     }
     
     /**
+     * 娓呯悊鍜岄獙璇乺edirectUri
+     * 
+     * @param redirectUri 鍘熷鍥炶皟鍦板潃
+     * @return 娓呯悊鍚庣殑鍥炶皟鍦板潃
+     */
+    private static String cleanRedirectUri(String redirectUri) {
+        if (StringUtils.isEmpty(redirectUri)) {
+            return redirectUri;
+        }
+        
+        try {
+            // 绉婚櫎绔彛鍙凤紙寰俊鎺堟潈涓嶆敮鎸佺鍙e彿锛�
+            if (redirectUri.contains(":81") || redirectUri.contains(":8080") || redirectUri.contains(":3000")) {
+                redirectUri = redirectUri.replaceAll(":(81|8080|3000|8081|8082|8083|8084|8085|8086|8087|8088|8089|8090)", "");
+                log.warn("妫�娴嬪埌绔彛鍙凤紝宸茶嚜鍔ㄧЩ闄�: {}", redirectUri);
+            }
+            
+            // 纭繚浣跨敤HTTPS锛堢敓浜х幆澧冿級
+            if (redirectUri.startsWith("http://") && !redirectUri.contains("localhost") && !redirectUri.contains("127.0.0.1")) {
+                redirectUri = redirectUri.replace("http://", "https://");
+                log.warn("鐢熶骇鐜寤鸿浣跨敤HTTPS锛屽凡鑷姩杞崲: {}", redirectUri);
+            }
+            
+            return redirectUri;
+        } catch (Exception e) {
+            log.error("娓呯悊redirectUri寮傚父: {}", e.getMessage());
+            return redirectUri;
+        }
+    }
+    
+    /**
      * 鍒ゆ柇鏄惁涓哄井淇℃祻瑙堝櫒
      * 
      * @param userAgent 鐢ㄦ埛浠g悊瀛楃涓�
diff --git a/ruoyi-ui/src/api/evaluation.js b/ruoyi-ui/src/api/evaluation.js
index fba017e..41651b8 100644
--- a/ruoyi-ui/src/api/evaluation.js
+++ b/ruoyi-ui/src/api/evaluation.js
@@ -17,6 +17,15 @@
   })
 }
 
+// 鐢熸垚寰俊鎺堟潈URL
+export function getWechatAuthUrl(redirectUri, state) {
+  return request({
+    url: '/evaluation/wechat/authurl',
+    method: 'get',
+    params: { redirectUri, state }
+  })
+}
+
 // 鑾峰彇寰俊鐢ㄦ埛淇℃伅
 export function getWechatUserInfo(code) {
   return request({
diff --git a/ruoyi-ui/src/views/evaluation/index.vue b/ruoyi-ui/src/views/evaluation/index.vue
index 017d5af..d4db6f1 100644
--- a/ruoyi-ui/src/views/evaluation/index.vue
+++ b/ruoyi-ui/src/views/evaluation/index.vue
@@ -20,11 +20,41 @@
         <!-- 瀹㈡埛淇℃伅 -->
         <div class="form-section">
           <h3>瀹㈡埛淇℃伅</h3>
+          
+          <!-- 寰俊鎺堟潈淇℃伅鏄剧ず -->
+          <div v-if="evaluationForm.wechatOpenid" class="wechat-info">
+            <div class="wechat-user">
+              <img v-if="evaluationForm.wechatAvatar" :src="evaluationForm.wechatAvatar" class="wechat-avatar" />
+              <div class="wechat-details">
+                <div class="wechat-nickname">{{ evaluationForm.wechatNickname }}</div>
+                <div class="wechat-openid">宸叉巿鏉冨井淇$櫥褰�</div>
+              </div>
+            </div>
+          </div>
+          
+          <!-- 寰俊鎺堟潈鎸夐挳 -->
+          <div v-if="isWechatBrowser() && !evaluationForm.wechatOpenid" class="wechat-auth-section">
+            <el-button 
+              type="primary" 
+              size="small" 
+              @click="redirectToWechatAuth" 
+              icon="el-icon-user"
+              :loading="wechatAuthLoading"
+            >
+              {{ wechatAuthLoading ? '姝e湪璺宠浆...' : '寰俊涓�閿櫥褰�' }}
+            </el-button>
+            <div class="wechat-tip">鐐瑰嚮鍙嚜鍔ㄨ幏鍙栨偍鐨勫井淇′俊鎭�</div>
+          </div>
+          
           <el-form-item label="濮撳悕" prop="customerName">
             <el-input v-model="evaluationForm.customerName" placeholder="璇疯緭鍏ユ偍鐨勫鍚�" />
           </el-form-item>
           <el-form-item label="鎵嬫満鍙�" prop="customerPhone">
             <el-input v-model="evaluationForm.customerPhone" placeholder="璇疯緭鍏ユ偍鐨勬墜鏈哄彿" />
+            <div v-if="evaluationForm.wechatOpenid" class="phone-tip">
+              <i class="el-icon-info"></i>
+              寰俊鎺堟潈鏃犳硶鐩存帴鑾峰彇鎵嬫満鍙凤紝璇锋墜鍔ㄨ緭鍏�
+            </div>
           </el-form-item>
         </div>
 
@@ -118,7 +148,7 @@
 </template>
 
 <script>
-import { getEvaluationDimensions, submitEvaluation, getWechatUserInfo } from "@/api/evaluation";
+import { getEvaluationDimensions, submitEvaluation, getWechatUserInfo, getWechatAuthUrl } from "@/api/evaluation";
 
 export default {
   name: "Evaluation",
@@ -147,7 +177,8 @@
       },
       submitting: false,
       showResult: false,
-      resultMessage: ''
+      resultMessage: '',
+      wechatAuthLoading: false
     };
   },
   created() {
@@ -178,7 +209,10 @@
     // 澶勭悊寰俊鎺堟潈
     async handleWechatAuth() {
       const code = this.$route.query.code;
+      const state = this.$route.query.state;
+      
       if (code) {
+        // 鏈夋巿鏉冪爜锛岃幏鍙栫敤鎴蜂俊鎭�
         try {
           const response = await getWechatUserInfo(code);
           if (response.code === 200) {
@@ -187,10 +221,59 @@
             this.evaluationForm.wechatNickname = userInfo.nickname;
             this.evaluationForm.wechatAvatar = userInfo.headimgurl;
             this.evaluationForm.wechatPhone = userInfo.phone || '';
+            
+            // 濡傛灉鑾峰彇鍒颁簡寰俊鏄电О锛岃嚜鍔ㄥ~鍏呭埌濮撳悕瀛楁
+            if (userInfo.nickname && !this.evaluationForm.customerName) {
+              this.evaluationForm.customerName = userInfo.nickname;
+            }
+            
+            this.$message.success('寰俊鎺堟潈鎴愬姛锛屽凡鑷姩鑾峰彇鎮ㄧ殑淇℃伅');
+          } else {
+            this.$message.error(response.msg || '鑾峰彇寰俊鐢ㄦ埛淇℃伅澶辫触');
           }
         } catch (error) {
           console.error('鑾峰彇寰俊鐢ㄦ埛淇℃伅澶辫触:', error);
+          this.$message.error('鑾峰彇寰俊鐢ㄦ埛淇℃伅澶辫触锛岃閲嶈瘯');
         }
+      } else {
+        // 娌℃湁鎺堟潈鐮侊紝妫�鏌ユ槸鍚﹂渶瑕佽烦杞埌寰俊鎺堟潈
+        const hasWechatInfo = this.evaluationForm.wechatOpenid;
+        if (!hasWechatInfo) {
+          await this.redirectToWechatAuth();
+        }
+      }
+    },
+
+    // 璺宠浆鍒板井淇℃巿鏉�
+    async redirectToWechatAuth() {
+      this.wechatAuthLoading = true;
+      try {
+        // 鏋勫缓褰撳墠椤甸潰鐨勫畬鏁碪RL浣滀负鍥炶皟鍦板潃
+        const currentUrl = window.location.origin + window.location.pathname;
+        const params = new URLSearchParams(window.location.search);
+        params.delete('code'); // 绉婚櫎鍙兘瀛樺湪鐨刢ode鍙傛暟
+        params.delete('state'); // 绉婚櫎鍙兘瀛樺湪鐨剆tate鍙傛暟
+        const redirectUri = currentUrl + (params.toString() ? '?' + params.toString() : '');
+        
+        console.log('鍑嗗鐢熸垚寰俊鎺堟潈URL锛屽洖璋冨湴鍧�:', redirectUri);
+        
+        const response = await getWechatAuthUrl(redirectUri, 'evaluation');
+        if (response.code === 200) {
+          console.log('寰俊鎺堟潈URL鐢熸垚鎴愬姛:', response.data);
+          console.log('鍘熷鍥炶皟鍦板潃:', response.data.originalRedirectUri);
+          console.log('寰俊AppID:', response.data.appId);
+          
+          // 璺宠浆鍒板井淇℃巿鏉冮〉闈�
+          window.location.href = response.data.authUrl;
+        } else {
+          console.error('鐢熸垚寰俊鎺堟潈URL澶辫触:', response.msg);
+          this.$message.error('寰俊鎺堟潈鏈嶅姟鏆傛椂涓嶅彲鐢紝璇锋墜鍔ㄥ~鍐欎俊鎭�');
+        }
+      } catch (error) {
+        console.error('璺宠浆寰俊鎺堟潈澶辫触:', error);
+        this.$message.error('寰俊鎺堟潈澶辫触锛岃鎵嬪姩濉啓淇℃伅');
+      } finally {
+        this.wechatAuthLoading = false;
       }
     },
 
@@ -465,6 +548,72 @@
   min-height: 60px !important;
 }
 
+/* 寰俊鎺堟潈鐩稿叧鏍峰紡 */
+.wechat-info {
+  background: #f0f9ff;
+  border: 1px solid #b3d8ff;
+  border-radius: 6px;
+  padding: 12px;
+  margin-bottom: 16px;
+}
+
+.wechat-user {
+  display: flex;
+  align-items: center;
+}
+
+.wechat-avatar {
+  width: 40px;
+  height: 40px;
+  border-radius: 50%;
+  margin-right: 12px;
+  border: 2px solid #409EFF;
+}
+
+.wechat-details {
+  flex: 1;
+}
+
+.wechat-nickname {
+  font-weight: bold;
+  color: #333;
+  font-size: 14px;
+  margin-bottom: 4px;
+}
+
+.wechat-openid {
+  color: #666;
+  font-size: 12px;
+}
+
+.wechat-auth-section {
+  text-align: center;
+  padding: 16px;
+  background: #f8f9fa;
+  border-radius: 6px;
+  margin-bottom: 16px;
+  border: 1px dashed #ddd;
+}
+
+.wechat-tip {
+  color: #666;
+  font-size: 12px;
+  margin-top: 8px;
+}
+
+.phone-tip {
+  color: #909399;
+  font-size: 12px;
+  margin-top: 4px;
+  display: flex;
+  align-items: center;
+}
+
+.phone-tip i {
+  margin-right: 4px;
+  color: #409EFF;
+}
+
 /* 浼樺寲琛ㄥ崟椤归棿璺� */
 .el-form-item {
   margin-bottom: 12px;
@@ -628,6 +777,41 @@
     padding: 8px 24px;
     font-size: 13px;
   }
+  
+  /* 绉诲姩绔井淇℃巿鏉冩牱寮� */
+  .wechat-info {
+    padding: 10px;
+    margin-bottom: 12px;
+  }
+  
+  .wechat-avatar {
+    width: 36px;
+    height: 36px;
+    margin-right: 10px;
+  }
+  
+  .wechat-nickname {
+    font-size: 13px;
+  }
+  
+  .wechat-openid {
+    font-size: 11px;
+  }
+  
+  .wechat-auth-section {
+    padding: 12px;
+    margin-bottom: 12px;
+  }
+  
+  .wechat-tip {
+    font-size: 11px;
+    margin-top: 6px;
+  }
+  
+  .phone-tip {
+    font-size: 11px;
+    margin-top: 3px;
+  }
 }
 
 /* 瓒呭皬灞忓箷閫傞厤 */
diff --git "a/\345\276\256\344\277\241\346\216\210\346\235\203\345\212\237\350\203\275\344\275\277\347\224\250\350\257\264\346\230\216.md" "b/\345\276\256\344\277\241\346\216\210\346\235\203\345\212\237\350\203\275\344\275\277\347\224\250\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..55a2f7d
--- /dev/null
+++ "b/\345\276\256\344\277\241\346\216\210\346\235\203\345\212\237\350\203\275\344\275\277\347\224\250\350\257\264\346\230\216.md"
@@ -0,0 +1,124 @@
+# 寰俊鎺堟潈鍔熻兘浣跨敤璇存槑
+
+## 鍔熻兘姒傝堪
+
+鏈姛鑳藉疄鐜颁簡鍦ㄨ瘎浠烽〉闈腑鑾峰彇寰俊鐢ㄦ埛鐨凮penId銆佸ご鍍忋�佹樀绉扮瓑淇℃伅锛屾彁鍗囩敤鎴蜂綋楠屻��
+
+## 瀹炵幇鐨勫姛鑳�
+
+### 1. 寰俊鎺堟潈URL鐢熸垚
+- 鍚庣鎺ュ彛锛歚GET /evaluation/wechat/authurl`
+- 鍔熻兘锛氱敓鎴愬井淇$綉椤垫巿鏉僓RL锛屼娇鐢╜snsapi_userinfo`鏉冮檺鑾峰彇鐢ㄦ埛鍩烘湰淇℃伅
+
+### 2. 寰俊鐢ㄦ埛淇℃伅鑾峰彇
+- 鍚庣鎺ュ彛锛歚GET /evaluation/wechat/userinfo`
+- 鍔熻兘锛氶�氳繃鎺堟潈鐮佽幏鍙栧井淇$敤鎴蜂俊鎭紝鍖呮嫭锛�
+  - OpenId锛氱敤鎴峰敮涓�鏍囪瘑
+  - 鏄电О锛氱敤鎴峰井淇℃樀绉�
+  - 澶村儚锛氱敤鎴峰井淇″ご鍍廢RL
+  - 鎬у埆銆佺渷浠姐�佸煄甯傘�佸浗瀹剁瓑鍩烘湰淇℃伅
+
+### 3. 鍓嶇鑷姩鎺堟潈娴佺▼
+- 妫�娴嬪井淇℃祻瑙堝櫒鐜
+- 鑷姩璺宠浆鍒板井淇℃巿鏉冮〉闈�
+- 鎺堟潈鎴愬姛鍚庤嚜鍔ㄨ幏鍙栫敤鎴蜂俊鎭�
+- 鑷姩濉厖鐢ㄦ埛鏄电О鍒板鍚嶅瓧娈�
+
+## 閰嶇疆瑕佹眰
+
+### 1. 寰俊鍏紬骞冲彴閰嶇疆
+鍦╜application.yml`涓厤缃井淇ppID鍜孉ppSecret锛�
+```yaml
+wechat:
+  appId: your_wechat_appid
+  appSecret: your_wechat_appsecret
+```
+
+### 2. 寰俊鍏紬骞冲彴缃戦〉鎺堟潈鍩熷悕閰嶇疆
+闇�瑕佸湪寰俊鍏紬骞冲彴鍚庡彴閰嶇疆鎺堟潈鍥炶皟鍩熷悕锛屼緥濡傦細
+- `yourdomain.com`
+
+## 浣跨敤娴佺▼
+
+### 1. 鐢ㄦ埛璁块棶璇勪环椤甸潰
+- 鍦ㄥ井淇℃祻瑙堝櫒涓墦寮�璇勪环椤甸潰
+- 绯荤粺鑷姩妫�娴嬪井淇$幆澧�
+
+### 2. 寰俊鎺堟潈
+- 濡傛灉鐢ㄦ埛鏈巿鏉冿紝鏄剧ず"寰俊涓�閿櫥褰�"鎸夐挳
+- 鐐瑰嚮鎸夐挳璺宠浆鍒板井淇℃巿鏉冮〉闈�
+- 鐢ㄦ埛纭鎺堟潈鍚庤繑鍥炶瘎浠烽〉闈�
+
+### 3. 淇℃伅鑷姩濉厖
+- 鎺堟潈鎴愬姛鍚庤嚜鍔ㄨ幏鍙栫敤鎴蜂俊鎭�
+- 鑷姩濉厖鏄电О鍒板鍚嶅瓧娈�
+- 鏄剧ず鐢ㄦ埛澶村儚鍜屾巿鏉冪姸鎬�
+
+### 4. 鎵嬪姩杈撳叆鎵嬫満鍙�
+- 鐢变簬寰俊缃戦〉鎺堟潈鏃犳硶鐩存帴鑾峰彇鎵嬫満鍙�
+- 鐢ㄦ埛闇�瑕佹墜鍔ㄨ緭鍏ユ墜鏈哄彿
+- 绯荤粺浼氭樉绀烘彁绀轰俊鎭鏄庡師鍥�
+
+## 鎶�鏈疄鐜�
+
+### 鍚庣瀹炵幇
+1. **WechatUtils宸ュ叿绫�**锛氬皝瑁呭井淇PI璋冪敤
+2. **EvaluationController**锛氭彁渚涘井淇℃巿鏉冪浉鍏虫帴鍙�
+3. **缃戦〉鎺堟潈娴佺▼**锛氫娇鐢∣Auth2.0鏍囧噯娴佺▼
+
+### 鍓嶇瀹炵幇
+1. **鑷姩妫�娴嬪井淇$幆澧�**锛氶�氳繃User-Agent鍒ゆ柇
+2. **鎺堟潈URL鐢熸垚**锛氬姩鎬佹瀯寤哄洖璋冨湴鍧�
+3. **鐢ㄦ埛淇℃伅灞曠ず**锛氱編瑙傜殑UI灞曠ず鎺堟潈鐘舵��
+4. **閿欒澶勭悊**锛氬畬鍠勭殑閿欒鎻愮ず鍜岄檷绾ф柟妗�
+
+## 娉ㄦ剰浜嬮」
+
+### 1. 鎵嬫満鍙疯幏鍙栭檺鍒�
+- 寰俊缃戦〉鎺堟潈鏃犳硶鐩存帴鑾峰彇鐢ㄦ埛鎵嬫満鍙�
+- 濡傞渶鑾峰彇鎵嬫満鍙凤紝闇�瑕侊細
+  - 浣跨敤寰俊灏忕▼搴忕殑`getPhoneNumber`鎺ュ彛
+  - 鎴栦娇鐢ㄥ井淇″紑鏀惧钩鍙扮殑鎵嬫満鍙峰揩閫熼獙璇佺粍浠�
+
+### 2. 鎺堟潈鍩熷悕閰嶇疆
+- 蹇呴』鍦ㄥ井淇″叕浼楀钩鍙伴厤缃纭殑鎺堟潈鍥炶皟鍩熷悕
+- 鍩熷悕蹇呴』涓庡疄闄呰闂煙鍚嶄竴鑷�
+
+### 3. HTTPS瑕佹眰
+- 鐢熶骇鐜蹇呴』浣跨敤HTTPS鍗忚
+- 寰俊鎺堟潈瑕佹眰瀹夊叏杩炴帴
+
+### 4. 鐢ㄦ埛浣撻獙浼樺寲
+- 鎻愪緵鎵嬪姩杈撳叆閫夐」浣滀负闄嶇骇鏂规
+- 娓呮櫚鐨勬彁绀轰俊鎭鏄庢巿鏉冪姸鎬�
+- 鍝嶅簲寮忚璁¢�傞厤绉诲姩绔�
+
+## 鎵╁睍鍔熻兘
+
+### 1. 寰俊灏忕▼搴忛泦鎴�
+濡傞渶鍦ㄥ皬绋嬪簭涓娇鐢紝鍙互锛�
+- 浣跨敤`wx.getUserProfile`鑾峰彇鐢ㄦ埛淇℃伅
+- 浣跨敤`wx.getPhoneNumber`鑾峰彇鎵嬫満鍙�
+
+### 2. 寰俊寮�鏀惧钩鍙伴泦鎴�
+濡傞渶鑾峰彇鏇村淇℃伅锛屽彲浠ワ細
+- 鐢宠寰俊寮�鏀惧钩鍙拌处鍙�
+- 浣跨敤鎵嬫満鍙峰揩閫熼獙璇佺粍浠�
+- 鑾峰彇UnionID杩涜澶氬钩鍙扮敤鎴风粺涓�
+
+## 娴嬭瘯寤鸿
+
+1. **鍔熻兘娴嬭瘯**
+   - 鍦ㄥ井淇℃祻瑙堝櫒涓祴璇曞畬鏁存巿鏉冩祦绋�
+   - 娴嬭瘯鎺堟潈鎴愬姛鍜屽け璐ョ殑鎯呭喌
+   - 娴嬭瘯闈炲井淇℃祻瑙堝櫒鐨勯檷绾ф柟妗�
+
+2. **鍏煎鎬ф祴璇�**
+   - 娴嬭瘯涓嶅悓鐗堟湰鐨勫井淇℃祻瑙堝櫒
+   - 娴嬭瘯涓嶅悓璁惧鐨勬樉绀烘晥鏋�
+   - 娴嬭瘯缃戠粶寮傚父鎯呭喌
+
+3. **瀹夊叏鎬ф祴璇�**
+   - 楠岃瘉鎺堟潈鐮佺殑鏈夋晥鎬�
+   - 娴嬭瘯鎭舵剰璇锋眰鐨勫鐞�
+   - 楠岃瘉鐢ㄦ埛淇℃伅鐨勫畬鏁存��
diff --git "a/\345\276\256\344\277\241\346\216\210\346\235\203\350\260\203\350\257\225\346\214\207\345\215\227.md" "b/\345\276\256\344\277\241\346\216\210\346\235\203\350\260\203\350\257\225\346\214\207\345\215\227.md"
new file mode 100644
index 0000000..3bc49d5
--- /dev/null
+++ "b/\345\276\256\344\277\241\346\216\210\346\235\203\350\260\203\350\257\225\346\214\207\345\215\227.md"
@@ -0,0 +1,209 @@
+# 寰俊鎺堟潈璋冭瘯鎸囧崡
+
+## 闂鍒嗘瀽
+
+鎮ㄩ亣鍒扮殑 `redirect_uri 鍙傛暟閿欒` 闂锛屼富瑕佸師鍥犲涓嬶細
+
+### 1. 鍩熷悕閰嶇疆闂
+浠庢偍鐨刄RL鍙互鐪嬪嚭锛�
+```
+redirect_uri=http%3A%2F%2Fwx.966120.com.cn%3A81%2Fevaluation%3Fvehicle%3D%25E7%25B2%25AC12345
+```
+
+**闂锛�**
+- 鍩熷悕 `wx.966120.com.cn:81` 鍙兘鏈湪寰俊鍏紬骞冲彴閰嶇疆
+- 绔彛鍙� `:81` 鍦ㄥ井淇℃巿鏉冧腑涓嶈鏀寔
+- 闇�瑕侀厤缃纭殑鎺堟潈鍥炶皟鍩熷悕
+
+### 2. 寰俊鍏紬骞冲彴閰嶇疆瑕佹眰
+
+#### 缃戦〉鎺堟潈鍩熷悕閰嶇疆
+1. 鐧诲綍寰俊鍏紬骞冲彴 (https://mp.weixin.qq.com)
+2. 杩涘叆"璁剧疆涓庡紑鍙�" -> "鍏紬鍙疯缃�" -> "鍔熻兘璁剧疆"
+3. 鍦�"缃戦〉鎺堟潈鍩熷悕"涓坊鍔狅細`wx.966120.com.cn`
+4. **娉ㄦ剰锛氫笉瑕佸寘鍚鍙e彿锛屼笉瑕佸寘鍚崗璁�**
+
+## 瑙e喅鏂规
+
+### 鏂规涓�锛氫慨澶嶅煙鍚嶉厤缃紙鎺ㄨ崘锛�
+
+#### 1. 寰俊鍏紬骞冲彴閰嶇疆
+```
+缃戦〉鎺堟潈鍩熷悕锛歸x.966120.com.cn
+```
+
+#### 2. 淇敼搴旂敤閰嶇疆
+鍦� `application.yml` 涓厤缃纭殑鍩熷悕锛�
+```yaml
+wechat:
+  appId: wx70f6a7346ee842c0
+  appSecret: 2d6c59de85e876b7eadebeba62e5417a
+  redirectUri: https://wx.966120.com.cn/evaluation  # 浣跨敤HTTPS锛屾棤绔彛鍙�
+```
+
+#### 3. 鏈嶅姟鍣ㄩ厤缃�
+- 纭繚 `wx.966120.com.cn` 鍩熷悕鎸囧悜鎮ㄧ殑鏈嶅姟鍣�
+- 閰嶇疆HTTPS璇佷功锛堝井淇℃巿鏉冭姹侶TTPS锛�
+- 閰嶇疆鍙嶅悜浠g悊锛屽皢80/443绔彛杞彂鍒版偍鐨勫簲鐢ㄧ鍙�
+
+### 鏂规浜岋細寮�鍙戠幆澧冭皟璇�
+
+#### 1. 浣跨敤鍐呯綉绌块�忓伐鍏�
+
+**鎺ㄨ崘宸ュ叿锛�**
+- **ngrok** (鍏嶈垂鐗�)
+- **natapp** (鍥藉唴璁块棶鏇寸ǔ瀹�)
+- **frp** (鑷缓)
+
+**ngrok浣跨敤姝ラ锛�**
+```bash
+# 1. 涓嬭浇ngrok
+# 2. 娉ㄥ唽璐﹀彿鑾峰彇authtoken
+ngrok authtoken YOUR_AUTHTOKEN
+
+# 3. 鍚姩鍐呯綉绌块��
+ngrok http 8080
+
+# 4. 鑾峰緱鍏綉鍦板潃锛屽锛歨ttps://abc123.ngrok.io
+```
+
+#### 2. 閰嶇疆寮�鍙戠幆澧�
+```yaml
+wechat:
+  appId: wx70f6a7346ee842c0
+  appSecret: 2d6c59de85e876b7eadebeba62e5417a
+  redirectUri: https://your-ngrok-url.ngrok.io/evaluation
+```
+
+#### 3. 寰俊鍏紬骞冲彴閰嶇疆
+鍦ㄧ綉椤垫巿鏉冨煙鍚嶄腑娣诲姞锛歚your-ngrok-url.ngrok.io`
+
+### 鏂规涓夛細鏈湴寮�鍙戞ā鎷�
+
+#### 1. 娣诲姞寮�鍙戠幆澧冮厤缃�
+```yaml
+wechat:
+  appId: wx70f6a7346ee842c0
+  appSecret: 2d6c59de85e876b7eadebeba62e5417a
+  redirectUri: https://wx.966120.com.cn/evaluation
+  # 寮�鍙戠幆澧冮厤缃�
+  dev:
+    enabled: true
+    mockUserInfo: true
+    ngrokUrl: https://your-ngrok-url.ngrok.io
+```
+
+#### 2. 淇敼鍚庣浠g爜鏀寔寮�鍙戞ā寮�
+```java
+@Value("${wechat.dev.enabled:false}")
+private boolean devModeEnabled;
+
+@Value("${wechat.dev.mockUserInfo:false}")
+private boolean mockUserInfo;
+
+// 鍦ㄧ敓鎴愭巿鏉僓RL鏃舵坊鍔犲紑鍙戞ā寮忓垽鏂�
+if (devModeEnabled && mockUserInfo) {
+    // 杩斿洖妯℃嫙鐨勬巿鏉僓RL锛岀洿鎺ヨ烦杞埌鍥炶皟鍦板潃
+    String mockCode = "dev_mock_code_" + System.currentTimeMillis();
+    String mockRedirectUri = redirectUri + "?code=" + mockCode + "&state=" + state;
+    return success(Map.of("authUrl", mockRedirectUri));
+}
+```
+
+## 璋冭瘯姝ラ
+
+### 1. 妫�鏌ュ綋鍓嶉厤缃�
+```bash
+# 妫�鏌ュ簲鐢ㄩ厤缃�
+curl -X GET "http://localhost:8080/evaluation/wechat/authurl?redirectUri=http://wx.966120.com.cn/evaluation&state=test"
+```
+
+### 2. 楠岃瘉寰俊鎺堟潈URL
+鐢熸垚鐨刄RL搴旇鏄繖鏍风殑鏍煎紡锛�
+```
+https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx70f6a7346ee842c0&redirect_uri=https%3A%2F%2Fwx.966120.com.cn%2Fevaluation&response_type=code&scope=snsapi_userinfo&state=test#wechat_redirect
+```
+
+### 3. 妫�鏌ュ煙鍚嶈В鏋�
+```bash
+# 妫�鏌ュ煙鍚嶆槸鍚﹁В鏋愭纭�
+nslookup wx.966120.com.cn
+ping wx.966120.com.cn
+```
+
+### 4. 妫�鏌TTPS璇佷功
+```bash
+# 妫�鏌TTPS鏄惁姝e父
+curl -I https://wx.966120.com.cn
+```
+
+## 甯歌閿欒鍙婅В鍐虫柟妗�
+
+### 1. redirect_uri 鍙傛暟閿欒
+**鍘熷洜锛�** 鍩熷悕鏈湪寰俊鍏紬骞冲彴閰嶇疆鎴栭厤缃敊璇�
+**瑙e喅锛�** 鍦ㄥ井淇″叕浼楀钩鍙版纭厤缃綉椤垫巿鏉冨煙鍚�
+
+### 2. 鍩熷悕涓嶅尮閰�
+**鍘熷洜锛�** 鍥炶皟鍦板潃涓庨厤缃殑鎺堟潈鍩熷悕涓嶄竴鑷�
+**瑙e喅锛�** 纭繚鍥炶皟鍦板潃鐨勫煙鍚嶄笌閰嶇疆鐨勬巿鏉冨煙鍚嶅畬鍏ㄤ竴鑷�
+
+### 3. 绔彛鍙烽棶棰�
+**鍘熷洜锛�** 寰俊鎺堟潈涓嶆敮鎸佺鍙e彿
+**瑙e喅锛�** 浣跨敤鍙嶅悜浠g悊锛屽皢80/443绔彛杞彂鍒板簲鐢ㄧ鍙�
+
+### 4. HTTPS瑕佹眰
+**鍘熷洜锛�** 鐢熶骇鐜蹇呴』浣跨敤HTTPS
+**瑙e喅锛�** 閰嶇疆SSL璇佷功锛屼娇鐢℉TTPS鍗忚
+
+## 娴嬭瘯楠岃瘉
+
+### 1. 鏈湴娴嬭瘯
+```bash
+# 鍚姩搴旂敤
+mvn spring-boot:run
+
+# 娴嬭瘯鎺堟潈URL鐢熸垚
+curl "http://localhost:8080/evaluation/wechat/authurl?redirectUri=https://wx.966120.com.cn/evaluation&state=test"
+```
+
+### 2. 寰俊鐜娴嬭瘯
+1. 鍦ㄥ井淇′腑鎵撳紑鐢熸垚鐨勬巿鏉僓RL
+2. 纭鑳芥甯歌烦杞埌寰俊鎺堟潈椤甸潰
+3. 鎺堟潈鍚庤兘姝e父鍥炶皟鍒版偍鐨勫簲鐢�
+
+### 3. 鐢ㄦ埛淇℃伅鑾峰彇娴嬭瘯
+```bash
+# 浣跨敤鎺堟潈鐮佽幏鍙栫敤鎴蜂俊鎭�
+curl "http://localhost:8080/evaluation/wechat/userinfo?code=YOUR_AUTH_CODE"
+```
+
+## 娉ㄦ剰浜嬮」
+
+1. **鍩熷悕閰嶇疆**锛氬繀椤诲湪寰俊鍏紬骞冲彴閰嶇疆姝g‘鐨勬巿鏉冨煙鍚�
+2. **HTTPS瑕佹眰**锛氱敓浜х幆澧冨繀椤讳娇鐢℉TTPS
+3. **绔彛鍙烽檺鍒�**锛氬井淇℃巿鏉冧笉鏀寔绔彛鍙�
+4. **缂栫爜闂**锛氱‘淇漊RL缂栫爜姝g‘
+5. **娴嬭瘯鐜**锛氬紑鍙戞椂鍙互浣跨敤鍐呯綉绌块�忓伐鍏�
+
+## 鎺ㄨ崘閰嶇疆
+
+### 鐢熶骇鐜
+```yaml
+wechat:
+  appId: wx70f6a7346ee842c0
+  appSecret: 2d6c59de85e876b7eadebeba62e5417a
+  redirectUri: https://wx.966120.com.cn/evaluation
+```
+
+### 寮�鍙戠幆澧�
+```yaml
+wechat:
+  appId: wx70f6a7346ee842c0
+  appSecret: 2d6c59de85e876b7eadebeba62e5417a
+  redirectUri: https://your-ngrok-url.ngrok.io/evaluation
+  dev:
+    enabled: true
+    mockUserInfo: true
+```
+
+鎸夌収浠ヤ笂姝ラ閰嶇疆鍚庯紝鎮ㄧ殑寰俊鎺堟潈鍔熻兘搴旇鑳芥甯稿伐浣溿��

--
Gitblit v1.9.1