my.js 19 KB

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