my.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  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. async getPhoneNumber(e) {
  317. console.log("获取手机号事件:", e);
  318. if (e.detail.errMsg !== "getPhoneNumber:ok") {
  319. console.error("用户拒绝授权手机号");
  320. common_vendor.index.showToast({
  321. title: "获取手机号失败",
  322. icon: "none"
  323. });
  324. return;
  325. }
  326. try {
  327. common_vendor.index.showLoading({ title: "获取手机号中..." });
  328. const loginResult = await new Promise((resolve, reject) => {
  329. common_vendor.index.login({
  330. provider: "weixin",
  331. success: resolve,
  332. fail: reject
  333. });
  334. });
  335. const params = {
  336. code: loginResult.code,
  337. encryptedData: e.detail.encryptedData,
  338. iv: e.detail.iv,
  339. openid: JSON.parse(common_vendor.index.getStorageSync("userInfo")).openid
  340. };
  341. console.log("获取手机号请求参数:", JSON.parse(common_vendor.index.getStorageSync("userInfo")).openid);
  342. const phoneData = await api_user.getUserPhoneNumber(params);
  343. console.log("获取手机号成功:", phoneData);
  344. if (phoneData && phoneData.phoneNumber) {
  345. const updatedUserInfo = {
  346. ...this.userInfo,
  347. phone: phoneData.phoneNumber
  348. };
  349. this.userInfo = updatedUserInfo;
  350. common_vendor.index.setStorageSync("userInfo", JSON.stringify(updatedUserInfo));
  351. common_vendor.index.showToast({
  352. title: "手机号绑定成功",
  353. icon: "success"
  354. });
  355. } else {
  356. throw new Error("未能获取到手机号");
  357. }
  358. } catch (error) {
  359. console.error("获取手机号失败:", error);
  360. common_vendor.index.showToast({
  361. title: error.message || "获取手机号失败",
  362. icon: "none"
  363. });
  364. } finally {
  365. common_vendor.index.hideLoading();
  366. }
  367. },
  368. // 添加刷新 CSRF token 的方法
  369. refreshCSRFToken() {
  370. common_vendor.index.request({
  371. url: "your-api-endpoint/csrf-token",
  372. // 替换为获取 CSRF token 的 API
  373. method: "GET",
  374. success: (res) => {
  375. if (res.data && res.data.csrfToken) {
  376. common_vendor.index.setStorageSync("csrfToken", res.data.csrfToken);
  377. console.log("CSRF token 已刷新");
  378. }
  379. },
  380. fail: (err) => {
  381. console.error("获取 CSRF token 失败", err);
  382. }
  383. });
  384. },
  385. handleMenuClick(item) {
  386. const needLogin = ["profile", "orders", "favorites"];
  387. if (needLogin.includes(item.action) && !this.isLogin) {
  388. common_vendor.index.showToast({
  389. title: "请先登录",
  390. icon: "none"
  391. });
  392. setTimeout(() => {
  393. this.wxLogin();
  394. }, 1500);
  395. return;
  396. }
  397. switch (item.action) {
  398. case "profile":
  399. common_vendor.index.navigateTo({ url: "/pages/profile/profile" });
  400. break;
  401. case "orders":
  402. common_vendor.index.navigateTo({ url: "/pages/orders/orders" });
  403. break;
  404. case "favorites":
  405. common_vendor.index.navigateTo({ url: "/pages/favorites/favorites" });
  406. break;
  407. case "settings":
  408. common_vendor.index.navigateTo({ url: "/pages/settings/settings" });
  409. break;
  410. case "help":
  411. common_vendor.index.navigateTo({ url: "/pages/help/help" });
  412. break;
  413. default:
  414. common_vendor.index.showToast({
  415. title: `点击了${item.title}`,
  416. icon: "none"
  417. });
  418. }
  419. },
  420. // 处理退出登录 - 增强版
  421. handleLogout(showConfirm = true) {
  422. const doLogout = () => {
  423. api_user.logout().then(() => {
  424. try {
  425. common_vendor.index.removeStorageSync("token");
  426. common_vendor.index.removeStorageSync("userInfo");
  427. this.isLogin = false;
  428. this.userInfo = {
  429. username: "",
  430. userId: "",
  431. avatar: "",
  432. phone: ""
  433. };
  434. if (showConfirm) {
  435. common_vendor.index.showToast({
  436. title: "已退出登录",
  437. icon: "success"
  438. });
  439. }
  440. } catch (e) {
  441. console.error("退出登录失败", e);
  442. if (showConfirm) {
  443. common_vendor.index.showToast({
  444. title: "退出登录失败",
  445. icon: "none"
  446. });
  447. }
  448. }
  449. }).catch((err) => {
  450. console.error("退出登录请求失败", err);
  451. common_vendor.index.removeStorageSync("token");
  452. common_vendor.index.removeStorageSync("userInfo");
  453. this.isLogin = false;
  454. if (showConfirm) {
  455. common_vendor.index.showToast({
  456. title: err.message || "退出登录失败",
  457. icon: "none"
  458. });
  459. }
  460. });
  461. };
  462. if (showConfirm) {
  463. common_vendor.index.showModal({
  464. title: "提示",
  465. content: "确定要退出登录吗?",
  466. success: (res) => {
  467. if (res.confirm) {
  468. doLogout();
  469. }
  470. }
  471. });
  472. } else {
  473. doLogout();
  474. }
  475. },
  476. // 格式化手机号,例如:188****8888
  477. formatPhone(phone) {
  478. if (!phone || phone.length < 11)
  479. return phone;
  480. return phone.substring(0, 3) + "****" + phone.substring(7);
  481. }
  482. }
  483. };
  484. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  485. return common_vendor.e({
  486. a: $data.isLogin
  487. }, $data.isLogin ? common_vendor.e({
  488. b: $data.userInfo.avatar || "/static/avatar.png",
  489. c: common_vendor.t($data.userInfo.username),
  490. d: $data.userInfo.phone
  491. }, $data.userInfo.phone ? {
  492. e: common_vendor.t($options.formatPhone($data.userInfo.phone))
  493. } : {}) : {
  494. f: common_assets._imports_0,
  495. g: common_vendor.o((...args) => $options.wxLogin && $options.wxLogin(...args))
  496. }, {
  497. h: common_vendor.f($data.menuItems, (item, index, i0) => {
  498. return {
  499. a: common_vendor.n(item.icon),
  500. b: common_vendor.t(item.title),
  501. c: index,
  502. d: common_vendor.o(($event) => $options.handleMenuClick(item), index)
  503. };
  504. }),
  505. i: $data.isLogin
  506. }, $data.isLogin ? {
  507. j: common_vendor.o((...args) => $options.handleLogout && $options.handleLogout(...args))
  508. } : {}, {
  509. k: $data.showAuthModal
  510. }, $data.showAuthModal ? {
  511. l: common_vendor.o((...args) => $options.getUserProfile && $options.getUserProfile(...args)),
  512. m: common_vendor.o((...args) => $options.cancelAuth && $options.cancelAuth(...args))
  513. } : {}, {
  514. n: $data.isLogin && !$data.userInfo.phone
  515. }, $data.isLogin && !$data.userInfo.phone ? {
  516. o: common_vendor.o((...args) => $options.getPhoneNumber && $options.getPhoneNumber(...args))
  517. } : {});
  518. }
  519. const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
  520. wx.createPage(MiniProgramPage);