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