my.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. "use strict";
  2. const common_vendor = require("../../common/vendor.js");
  3. const api_user = require("../../api/user.js");
  4. const common_assets = require("../../common/assets.js");
  5. new Proxy({}, {
  6. get(_, key) {
  7. throw new Error(`Module "util" has been externalized for browser compatibility. Cannot access "util.${key}" in client code. See https://vitejs.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.`);
  8. }
  9. });
  10. const _sfc_main = {
  11. data() {
  12. return {
  13. isLogin: false,
  14. userInfo: {
  15. username: "",
  16. userId: "",
  17. avatar: ""
  18. },
  19. menuItems: [
  20. { title: "个人资料", icon: "icon-user", action: "profile" },
  21. // { title: '我的订单', icon: 'icon-order', action: 'orders' },
  22. // { title: '我的收藏', icon: 'icon-star', action: 'favorites' },
  23. { title: "设置", icon: "icon-settings", action: "settings" },
  24. { title: "帮助中心", icon: "icon-help", action: "help" }
  25. ],
  26. showAuthModal: false,
  27. wxLoginCode: ""
  28. // 存储微信登录code
  29. };
  30. },
  31. onShow() {
  32. this.checkLoginStatus();
  33. },
  34. methods: {
  35. // 检查登录状态
  36. checkLoginStatus() {
  37. try {
  38. const token = common_vendor.index.getStorageSync("token");
  39. const userInfoStr = common_vendor.index.getStorageSync("userInfo");
  40. if (token && userInfoStr) {
  41. const userInfo = JSON.parse(userInfoStr);
  42. const loginTime = userInfo.loginTime || 0;
  43. const currentTime = (/* @__PURE__ */ new Date()).getTime();
  44. const loginExpireTime = 7 * 24 * 60 * 60 * 1e3;
  45. if (currentTime - loginTime > loginExpireTime) {
  46. console.log("登录已过期,需要重新登录");
  47. this.handleLogout(false);
  48. return;
  49. }
  50. this.isLogin = true;
  51. this.userInfo = userInfo;
  52. this.fetchUserDetail();
  53. } else {
  54. this.isLogin = false;
  55. this.userInfo = {
  56. username: "",
  57. userId: "",
  58. avatar: "",
  59. phone: ""
  60. };
  61. }
  62. } catch (e) {
  63. console.error("获取登录状态失败", e);
  64. this.isLogin = false;
  65. }
  66. },
  67. // 前往登录页
  68. goLogin() {
  69. common_vendor.index.showActionSheet({
  70. itemList: ["账号密码登录", "微信登录"],
  71. success: (res) => {
  72. if (res.tapIndex === 0) {
  73. common_vendor.index.navigateTo({
  74. url: "/pages/login/login"
  75. });
  76. } else if (res.tapIndex === 1) {
  77. this.wxLogin();
  78. }
  79. }
  80. });
  81. },
  82. // 微信登录
  83. wxLogin() {
  84. this.getWxLoginCode();
  85. },
  86. // 获取微信登录 code
  87. getWxLoginCode() {
  88. common_vendor.index.showLoading({ title: "登录中..." });
  89. common_vendor.index.login({
  90. provider: "weixin",
  91. success: (loginRes) => {
  92. console.log("获取微信登录code成功:", loginRes.code);
  93. this.wxLoginCode = loginRes.code;
  94. common_vendor.index.hideLoading();
  95. this.showAuthModal = true;
  96. },
  97. fail: (err) => {
  98. common_vendor.index.hideLoading();
  99. console.error("获取微信登录code失败:", err);
  100. common_vendor.index.showToast({
  101. title: "微信登录失败",
  102. icon: "none"
  103. });
  104. }
  105. });
  106. },
  107. // 用户点击授权按钮时调用
  108. getUserProfile() {
  109. common_vendor.wx$1.getUserProfile({
  110. desc: "用于完善用户资料",
  111. success: (profileRes) => {
  112. console.log("获取用户信息成功:", profileRes);
  113. const loginParams = {
  114. code: this.wxLoginCode,
  115. userInfo: profileRes.userInfo,
  116. signature: profileRes.signature,
  117. rawData: profileRes.rawData,
  118. encryptedData: profileRes.encryptedData,
  119. iv: profileRes.iv
  120. };
  121. this.showAuthModal = false;
  122. this.wxLoginRequest(loginParams);
  123. },
  124. fail: (err) => {
  125. console.error("获取用户信息失败:", err);
  126. this.showAuthModal = false;
  127. this.wxLoginRequest({
  128. code: this.wxLoginCode,
  129. userInfo: {
  130. nickName: "微信用户",
  131. avatarUrl: "",
  132. gender: 0,
  133. province: "",
  134. city: "",
  135. country: ""
  136. }
  137. });
  138. }
  139. });
  140. },
  141. // 取消授权
  142. cancelAuth() {
  143. this.showAuthModal = false;
  144. this.wxLoginRequest({
  145. code: this.wxLoginCode,
  146. userInfo: {
  147. nickName: "微信用户",
  148. avatarUrl: "",
  149. gender: 0,
  150. province: "",
  151. city: "",
  152. country: ""
  153. }
  154. });
  155. },
  156. // 头像选择回调
  157. onChooseAvatar(e) {
  158. const { avatarUrl } = e.detail;
  159. console.log("用户选择的头像:", avatarUrl);
  160. },
  161. // 发送微信登录请求并处理结果
  162. async wxLoginRequest(loginParams) {
  163. try {
  164. common_vendor.index.showLoading({ title: "登录中..." });
  165. console.log("发送登录请求,参数:", loginParams);
  166. const data = await api_user.wxLogin(loginParams);
  167. console.log("登录成功,返回数据:", data);
  168. const userData = this.buildUserData(data, loginParams);
  169. this.saveLoginState(data, userData);
  170. if (userData.userId) {
  171. this.fetchUserDetail();
  172. } else {
  173. console.log("无法获取用户ID,跳过获取详细信息");
  174. }
  175. if (!userData.phone) {
  176. console.log("用户未绑定手机号,可以提示用户绑定");
  177. }
  178. } catch (error) {
  179. this.handleLoginError(error, loginParams);
  180. }
  181. },
  182. /**
  183. * 构建用户数据对象
  184. * @param {Object} data - 后端返回的数据
  185. * @param {Object} loginParams - 登录参数
  186. * @returns {Object} - 构建的用户数据
  187. */
  188. buildUserData(data, loginParams) {
  189. console.log("构建用户数据,服务器返回:", data);
  190. let userData = {
  191. // 用户基本信息 - 优先使用服务器返回的数据
  192. username: data.username || data.nickName || (loginParams.userInfo ? loginParams.userInfo.nickName : "微信用户"),
  193. // 用户ID可能在不同字段
  194. userId: data.userId || data.user_id || data.id || data.openid || "",
  195. // 头像可能在不同字段
  196. avatar: data.avatar || data.avatarUrl || (loginParams.userInfo ? loginParams.userInfo.avatarUrl : "/static/avatar.png"),
  197. // 用户详细信息
  198. phone: data.phone || data.mobile || "",
  199. gender: data.gender || (loginParams.userInfo ? loginParams.userInfo.gender : 0),
  200. // 微信相关信息
  201. openid: data.openid || "",
  202. unionid: data.unionid || "",
  203. session_key: data.session_key || "",
  204. // 是否新用户
  205. is_new_user: data.is_new_user || false,
  206. // 登录时间
  207. loginTime: (/* @__PURE__ */ new Date()).getTime()
  208. };
  209. console.log("构建的用户数据:", userData);
  210. return userData;
  211. },
  212. /**
  213. * 保存登录状态和用户信息
  214. * @param {Object} data - 后端返回的数据
  215. * @param {Object} userData - 构建的用户数据
  216. */
  217. saveLoginState(data, userData) {
  218. const token = data.token || data.session_key || "";
  219. if (token) {
  220. common_vendor.index.setStorageSync("token", token);
  221. console.log("Token已保存:", token);
  222. }
  223. common_vendor.index.setStorageSync("userInfo", JSON.stringify(userData));
  224. console.log("用户信息已保存");
  225. this.isLogin = true;
  226. this.userInfo = userData;
  227. common_vendor.index.hideLoading();
  228. common_vendor.index.showToast({
  229. title: "登录成功",
  230. icon: "success"
  231. });
  232. },
  233. /**
  234. * 处理登录错误
  235. * @param {Error} error - 错误对象
  236. * @param {Object} loginParams - 登录参数
  237. */
  238. handleLoginError(error, loginParams) {
  239. common_vendor.index.hideLoading();
  240. if (error.message && (error.message.includes("code无效") || error.message.includes("已过期") || error.message.includes("已被使用") || error.status === 999)) {
  241. console.error("微信登录code无效,重新获取:", error);
  242. common_vendor.index.showToast({
  243. title: "code已过期,请重试",
  244. icon: "none",
  245. duration: 2e3
  246. });
  247. setTimeout(() => {
  248. this.getWxLoginCode();
  249. }, 1e3);
  250. return;
  251. }
  252. if (error.code === 10001) {
  253. common_vendor.index.navigateTo({
  254. url: "/pages/bind/bind?code=" + (loginParams.code || "")
  255. });
  256. } else if (error.message && error.message.includes("CSRF")) {
  257. console.error("CSRF验证失败:", error);
  258. common_vendor.index.showToast({
  259. title: "CSRF验证失败,请刷新页面重试",
  260. icon: "none",
  261. duration: 2e3
  262. });
  263. setTimeout(() => this.refreshCSRFToken(), 2e3);
  264. } else {
  265. console.error("微信登录失败:", error);
  266. common_vendor.index.showToast({
  267. title: error.message || "登录失败",
  268. icon: "none"
  269. });
  270. }
  271. },
  272. /**
  273. * 获取用户详细信息
  274. * 步骤6: 获取并更新用户详细信息
  275. */
  276. async fetchUserDetail() {
  277. try {
  278. if (!this.isLogin)
  279. return;
  280. const userId = this.userInfo.userId;
  281. const userDetail = await api_user.getUserInfo(userId);
  282. console.log("获取用户详细信息成功:", userDetail);
  283. if (userDetail) {
  284. this.updateUserInfo(userDetail);
  285. }
  286. } catch (error) {
  287. console.error("获取用户详细信息失败:", error);
  288. }
  289. },
  290. /**
  291. * 更新用户信息
  292. * @param {Object} userDetail - 用户详细信息
  293. */
  294. updateUserInfo(userDetail) {
  295. const updatedUserInfo = {
  296. ...this.userInfo,
  297. // 更新基本信息
  298. username: userDetail.username || userDetail.nickName || this.userInfo.username,
  299. avatar: userDetail.avatar || userDetail.avatarUrl || this.userInfo.avatar,
  300. phone: userDetail.phone || userDetail.mobile || this.userInfo.phone,
  301. // 更新详细信息
  302. email: userDetail.email || "",
  303. address: userDetail.address || "",
  304. birthday: userDetail.birthday || "",
  305. // 其他字段
  306. ...userDetail
  307. };
  308. this.userInfo = updatedUserInfo;
  309. common_vendor.index.setStorageSync("userInfo", JSON.stringify(updatedUserInfo));
  310. console.log("用户详细信息已更新");
  311. },
  312. /**
  313. * 获取用户手机号
  314. * @param {Object} e - 事件对象
  315. */
  316. getPhoneNumber(e) {
  317. if (e.detail.code) {
  318. common_vendor.wx$1.request({
  319. url: "http:192.168.66.187:8083/wechat/getUserPhoneNumber",
  320. method: "POST",
  321. data: {
  322. code: e.detail.code,
  323. // 刚获取的新code
  324. openid: this.data.openid
  325. }
  326. });
  327. }
  328. },
  329. /* async getPhoneNumber(e) {
  330. console.log('获取手机号事件:', e);
  331. // 检查是否成功获取
  332. if (e.detail.errMsg !== 'getPhoneNumber:ok') {
  333. console.error('用户拒绝授权手机号');
  334. uni.showToast({
  335. title: '获取手机号失败',
  336. icon: 'none'
  337. });
  338. return;
  339. }
  340. try {
  341. uni.showLoading({ title: '获取手机号中...' });
  342. // 每次都重新获取最新的登录code
  343. const loginResult = await new Promise((resolve, reject) => {
  344. uni.login({
  345. provider: 'weixin',
  346. success: (res) => resolve(res),
  347. fail: (err) => reject(err)
  348. });
  349. });
  350. if (!loginResult || !loginResult.code) {
  351. throw new Error('获取微信登录凭证失败');
  352. }
  353. console.log('成功获取新的登录code:', loginResult.code);
  354. // 获取存储的用户信息
  355. const userInfoStr = uni.getStorageSync('userInfo');
  356. if (!userInfoStr) {
  357. throw new Error('用户信息不存在,请重新登录');
  358. }
  359. const userInfo = JSON.parse(userInfoStr);
  360. // 准备请求参数
  361. const params = {
  362. code: loginResult.code,
  363. encryptedData: e.detail.encryptedData,
  364. iv: e.detail.iv,
  365. openid: userInfo.openid
  366. };
  367. console.log('获取手机号请求参数:', params);
  368. // 调用获取手机号API
  369. const phoneData = await getUserPhoneNumber(params);
  370. console.log('获取手机号成功:', phoneData);
  371. // 更新用户信息
  372. if (phoneData && phoneData.phoneNumber) {
  373. const updatedUserInfo = {
  374. ...this.userInfo,
  375. phone: phoneData.phoneNumber
  376. };
  377. // 更新状态和存储
  378. this.userInfo = updatedUserInfo;
  379. uni.setStorageSync('userInfo', JSON.stringify(updatedUserInfo));
  380. uni.showToast({
  381. title: '手机号绑定成功',
  382. icon: 'success'
  383. });
  384. } else {
  385. throw new Error('未能获取到手机号');
  386. }
  387. } catch (error) {
  388. console.error('获取手机号失败:', error);
  389. uni.showToast({
  390. title: error.message || '获取手机号失败',
  391. icon: 'none'
  392. });
  393. } finally {
  394. uni.hideLoading();
  395. }
  396. }, */
  397. // 添加刷新 CSRF token 的方法
  398. refreshCSRFToken() {
  399. common_vendor.index.request({
  400. url: "your-api-endpoint/csrf-token",
  401. // 替换为获取 CSRF token 的 API
  402. method: "GET",
  403. success: (res) => {
  404. if (res.data && res.data.csrfToken) {
  405. common_vendor.index.setStorageSync("csrfToken", res.data.csrfToken);
  406. console.log("CSRF token 已刷新");
  407. }
  408. },
  409. fail: (err) => {
  410. console.error("获取 CSRF token 失败", err);
  411. }
  412. });
  413. },
  414. handleMenuClick(item) {
  415. const needLogin = ["profile", "orders", "favorites"];
  416. if (needLogin.includes(item.action) && !this.isLogin) {
  417. common_vendor.index.showToast({
  418. title: "请先登录",
  419. icon: "none"
  420. });
  421. setTimeout(() => {
  422. this.wxLogin();
  423. }, 1500);
  424. return;
  425. }
  426. switch (item.action) {
  427. case "profile":
  428. common_vendor.index.navigateTo({ url: "/pages/profile/profile" });
  429. break;
  430. case "orders":
  431. common_vendor.index.navigateTo({ url: "/pages/orders/orders" });
  432. break;
  433. case "favorites":
  434. common_vendor.index.navigateTo({ url: "/pages/favorites/favorites" });
  435. break;
  436. case "settings":
  437. common_vendor.index.navigateTo({ url: "/pages/settings/settings" });
  438. break;
  439. case "help":
  440. common_vendor.index.navigateTo({ url: "/pages/help/help" });
  441. break;
  442. default:
  443. common_vendor.index.showToast({
  444. title: `点击了${item.title}`,
  445. icon: "none"
  446. });
  447. }
  448. },
  449. // 处理退出登录 - 增强版
  450. handleLogout(showConfirm = true) {
  451. const doLogout = () => {
  452. api_user.logout().then(() => {
  453. try {
  454. common_vendor.index.removeStorageSync("token");
  455. common_vendor.index.removeStorageSync("userInfo");
  456. this.isLogin = false;
  457. this.userInfo = {
  458. username: "",
  459. userId: "",
  460. avatar: "",
  461. phone: ""
  462. };
  463. if (showConfirm) {
  464. common_vendor.index.showToast({
  465. title: "已退出登录",
  466. icon: "success"
  467. });
  468. }
  469. } catch (e) {
  470. console.error("退出登录失败", e);
  471. if (showConfirm) {
  472. common_vendor.index.showToast({
  473. title: "退出登录失败",
  474. icon: "none"
  475. });
  476. }
  477. }
  478. }).catch((err) => {
  479. console.error("退出登录请求失败", err);
  480. common_vendor.index.removeStorageSync("token");
  481. common_vendor.index.removeStorageSync("userInfo");
  482. this.isLogin = false;
  483. if (showConfirm) {
  484. common_vendor.index.showToast({
  485. title: err.message || "退出登录失败",
  486. icon: "none"
  487. });
  488. }
  489. });
  490. };
  491. if (showConfirm) {
  492. common_vendor.index.showModal({
  493. title: "提示",
  494. content: "确定要退出登录吗?",
  495. success: (res) => {
  496. if (res.confirm) {
  497. doLogout();
  498. }
  499. }
  500. });
  501. } else {
  502. doLogout();
  503. }
  504. },
  505. // 格式化手机号,例如:188****8888
  506. formatPhone(phone) {
  507. if (!phone || phone.length < 11)
  508. return phone;
  509. return phone.substring(0, 3) + "****" + phone.substring(7);
  510. }
  511. }
  512. };
  513. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  514. return common_vendor.e({
  515. a: $data.isLogin
  516. }, $data.isLogin ? common_vendor.e({
  517. b: $data.userInfo.avatar || "/static/avatar.png",
  518. c: common_vendor.t($data.userInfo.username),
  519. d: $data.userInfo.phone
  520. }, $data.userInfo.phone ? {
  521. e: common_vendor.t($options.formatPhone($data.userInfo.phone))
  522. } : {}) : {
  523. f: common_assets._imports_0$1,
  524. g: common_vendor.o((...args) => $options.wxLogin && $options.wxLogin(...args))
  525. }, {
  526. h: common_vendor.f($data.menuItems, (item, index, i0) => {
  527. return {
  528. a: common_vendor.n(item.icon),
  529. b: common_vendor.t(item.title),
  530. c: index,
  531. d: common_vendor.o(($event) => $options.handleMenuClick(item), index)
  532. };
  533. }),
  534. i: $data.isLogin
  535. }, $data.isLogin ? {
  536. j: common_vendor.o((...args) => $options.handleLogout && $options.handleLogout(...args))
  537. } : {}, {
  538. k: $data.showAuthModal
  539. }, $data.showAuthModal ? {
  540. l: common_vendor.o((...args) => $options.getUserProfile && $options.getUserProfile(...args)),
  541. m: common_vendor.o((...args) => $options.cancelAuth && $options.cancelAuth(...args))
  542. } : {});
  543. }
  544. const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
  545. wx.createPage(MiniProgramPage);