my.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. <template>
  2. <view class="my-container">
  3. <view class="user-info" v-if="isLogin">
  4. <image class="avatar" :src="userInfo.avatar || '/static/avatar.png'"></image>
  5. <view class="user-details">
  6. <text class="username">{{ userInfo.username }}</text>
  7. <!-- <text class="user-id">ID: {{ userInfo.userId }}</text> -->
  8. <text class="user-phone" v-if="userInfo.phone">手机: {{ formatPhone(userInfo.phone) }}</text>
  9. </view>
  10. </view>
  11. <view class="user-info" v-else @click="wxLogin">
  12. <image class="avatar" src="/static/avatar.png"></image>
  13. <view class="user-details">
  14. <text class="username">点击登录</text>
  15. <text class="user-id">登录后查看更多信息</text>
  16. </view>
  17. </view>
  18. <view class="menu-list">
  19. <view class="menu-item" v-for="(item, index) in menuItems" :key="index" @click="handleMenuClick(item)">
  20. <view class="menu-item-left">
  21. <text class="iconfont" :class="item.icon"></text>
  22. <text class="menu-text">{{ item.title }}</text>
  23. </view>
  24. <text class="iconfont icon-right"></text>
  25. </view>
  26. </view>
  27. <view class="logout-btn" @click="handleLogout" v-if="isLogin">
  28. <text>退出登录</text>
  29. </view>
  30. <!-- 添加一个隐藏的授权按钮,在需要时显示 -->
  31. <view class="auth-modal" v-if="showAuthModal">
  32. <view class="auth-content">
  33. <text class="auth-title">微信授权登录</text>
  34. <text class="auth-desc">请授权获取您的微信头像和昵称</text>
  35. <button class="auth-btn" @tap="getUserProfile">确认授权</button>
  36. <button class="auth-cancel" @tap="cancelAuth">取消</button>
  37. </view>
  38. </view>
  39. <!-- 添加获取手机号按钮 -->
  40. <!-- <button
  41. v-if="isLogin && !userInfo.phone"
  42. open-type="getPhoneNumber"
  43. @getphonenumber="getPhoneNumber"
  44. class="get-phone-btn">
  45. 绑定手机号
  46. </button> -->
  47. <!-- <button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">获取手机号</button> -->
  48. </view>
  49. </template>
  50. <script>
  51. // 直接导入所有需要的 API 函数
  52. import { log } from 'util';
  53. import { wxLogin, getUserInfo, getUserPhoneNumber, logout } from '../../api/user.js';
  54. export default {
  55. data() {
  56. return {
  57. isLogin: false,
  58. userInfo: {
  59. username: '',
  60. userId: '',
  61. avatar: ''
  62. },
  63. menuItems: [
  64. { title: '个人资料', icon: 'icon-user', action: 'profile' },
  65. // { title: '我的订单', icon: 'icon-order', action: 'orders' },
  66. // { title: '我的收藏', icon: 'icon-star', action: 'favorites' },
  67. { title: '设置', icon: 'icon-settings', action: 'settings' },
  68. { title: '帮助中心', icon: 'icon-help', action: 'help' }
  69. ],
  70. showAuthModal: false,
  71. wxLoginCode: '' // 存储微信登录code
  72. }
  73. },
  74. onShow() {
  75. // 每次显示页面时检查登录状态
  76. this.checkLoginStatus();
  77. },
  78. methods: {
  79. // 检查登录状态
  80. checkLoginStatus() {
  81. try {
  82. const token = uni.getStorageSync('token');
  83. const userInfoStr = uni.getStorageSync('userInfo');
  84. if (token && userInfoStr) {
  85. const userInfo = JSON.parse(userInfoStr);
  86. // 检查登录是否过期(可选:如果需要登录有效期)
  87. const loginTime = userInfo.loginTime || 0;
  88. const currentTime = new Date().getTime();
  89. const loginExpireTime = 7 * 24 * 60 * 60 * 1000; // 例如7天过期
  90. if (currentTime - loginTime > loginExpireTime) {
  91. console.log('登录已过期,需要重新登录');
  92. this.handleLogout(false); // 静默登出,不显示提示
  93. return;
  94. }
  95. // 设置登录状态
  96. this.isLogin = true;
  97. this.userInfo = userInfo;
  98. // 可选:每次打开页面时刷新用户信息
  99. this.fetchUserDetail();
  100. } else {
  101. // 未登录状态
  102. this.isLogin = false;
  103. this.userInfo = {
  104. username: '',
  105. userId: '',
  106. avatar: '',
  107. phone: ''
  108. };
  109. }
  110. } catch (e) {
  111. console.error('获取登录状态失败', e);
  112. this.isLogin = false;
  113. }
  114. },
  115. // 前往登录页
  116. goLogin() {
  117. // 显示登录方式选择
  118. uni.showActionSheet({
  119. itemList: ['账号密码登录', '微信登录'],
  120. success: (res) => {
  121. if (res.tapIndex === 0) {
  122. // 账号密码登录
  123. uni.navigateTo({
  124. url: '/pages/login/login'
  125. });
  126. } else if (res.tapIndex === 1) {
  127. // 微信登录
  128. this.wxLogin();
  129. }
  130. }
  131. });
  132. },
  133. // 微信登录
  134. wxLogin() {
  135. // #ifdef MP-WEIXIN
  136. this.getWxLoginCode();
  137. // #endif
  138. // #ifndef MP-WEIXIN
  139. uni.showToast({
  140. title: '请在微信环境中使用微信登录',
  141. icon: 'none'
  142. });
  143. // #endif
  144. },
  145. // 获取微信登录 code
  146. getWxLoginCode() {
  147. uni.showLoading({ title: '登录中...' });
  148. // 调用uni.login获取临时code
  149. uni.login({
  150. provider: 'weixin',
  151. success: (loginRes) => {
  152. console.log('获取微信登录code成功:', loginRes.code);
  153. // 保存code,并显示授权弹窗
  154. this.wxLoginCode = loginRes.code;
  155. uni.hideLoading();
  156. this.showAuthModal = true;
  157. },
  158. fail: (err) => {
  159. uni.hideLoading();
  160. console.error('获取微信登录code失败:', err);
  161. uni.showToast({
  162. title: '微信登录失败',
  163. icon: 'none'
  164. });
  165. }
  166. });
  167. },
  168. // 用户点击授权按钮时调用
  169. getUserProfile() {
  170. // 这个方法直接绑定到按钮的点击事件
  171. wx.getUserProfile({
  172. desc: '用于完善用户资料',
  173. success: (profileRes) => {
  174. console.log('获取用户信息成功:', profileRes);
  175. // 准备完整的登录参数
  176. const loginParams = {
  177. code: this.wxLoginCode,
  178. userInfo: profileRes.userInfo,
  179. signature: profileRes.signature,
  180. rawData: profileRes.rawData,
  181. encryptedData: profileRes.encryptedData,
  182. iv: profileRes.iv
  183. };
  184. // 隐藏授权弹窗
  185. this.showAuthModal = false;
  186. // 发送登录请求
  187. this.wxLoginRequest(loginParams);
  188. },
  189. fail: (err) => {
  190. console.error('获取用户信息失败:', err);
  191. this.showAuthModal = false;
  192. // 如果用户拒绝授权,仍然可以使用code登录,但没有用户信息
  193. this.wxLoginRequest({
  194. code: this.wxLoginCode,
  195. userInfo: {
  196. nickName: '微信用户',
  197. avatarUrl: '',
  198. gender: 0,
  199. province: '',
  200. city: '',
  201. country: ''
  202. }
  203. });
  204. }
  205. });
  206. },
  207. // 取消授权
  208. cancelAuth() {
  209. this.showAuthModal = false;
  210. // 使用code进行静默登录
  211. this.wxLoginRequest({
  212. code: this.wxLoginCode,
  213. userInfo: {
  214. nickName: '微信用户',
  215. avatarUrl: '',
  216. gender: 0,
  217. province: '',
  218. city: '',
  219. country: ''
  220. }
  221. });
  222. },
  223. // 头像选择回调
  224. onChooseAvatar(e) {
  225. const { avatarUrl } = e.detail;
  226. // 这里可以将头像上传到服务器或进行其他处理
  227. console.log('用户选择的头像:', avatarUrl);
  228. },
  229. // 发送微信登录请求并处理结果
  230. async wxLoginRequest(loginParams) {
  231. try {
  232. uni.showLoading({ title: '登录中...' });
  233. console.log('发送登录请求,参数:', loginParams);
  234. // 发送登录请求
  235. const data = await wxLogin(loginParams);
  236. console.log('登录成功,返回数据:', data);
  237. // 构建用户信息对象
  238. const userData = this.buildUserData(data, loginParams);
  239. // 保存登录状态
  240. this.saveLoginState(data, userData);
  241. // 步骤6: 获取用户详细信息 - 如果需要的话
  242. if (userData.userId) {
  243. this.fetchUserDetail();
  244. } else {
  245. console.log('无法获取用户ID,跳过获取详细信息');
  246. }
  247. // 检查是否需要获取手机号
  248. if (!userData.phone) {
  249. console.log('用户未绑定手机号,可以提示用户绑定');
  250. // 这里可以显示提示或自动弹出获取手机号的按钮
  251. }
  252. } catch (error) {
  253. this.handleLoginError(error, loginParams);
  254. }
  255. },
  256. /**
  257. * 构建用户数据对象
  258. * @param {Object} data - 后端返回的数据
  259. * @param {Object} loginParams - 登录参数
  260. * @returns {Object} - 构建的用户数据
  261. */
  262. buildUserData(data, loginParams) {
  263. console.log('构建用户数据,服务器返回:', data);
  264. // 处理不同的返回格式
  265. let userData = {
  266. // 用户基本信息 - 优先使用服务器返回的数据
  267. username: data.username || data.nickName ||
  268. (loginParams.userInfo ? loginParams.userInfo.nickName : '微信用户'),
  269. // 用户ID可能在不同字段
  270. userId: data.userId || data.user_id || data.id || data.openid || '',
  271. // 头像可能在不同字段
  272. avatar: data.avatar || data.avatarUrl ||
  273. (loginParams.userInfo ? loginParams.userInfo.avatarUrl : '/static/avatar.png'),
  274. // 用户详细信息
  275. phone: data.phone || data.mobile || '',
  276. gender: data.gender || (loginParams.userInfo ? loginParams.userInfo.gender : 0),
  277. // 微信相关信息
  278. openid: data.openid || '',
  279. unionid: data.unionid || '',
  280. session_key: data.session_key || '',
  281. // 是否新用户
  282. is_new_user: data.is_new_user || false,
  283. // 登录时间
  284. loginTime: new Date().getTime()
  285. };
  286. console.log('构建的用户数据:', userData);
  287. return userData;
  288. },
  289. /**
  290. * 保存登录状态和用户信息
  291. * @param {Object} data - 后端返回的数据
  292. * @param {Object} userData - 构建的用户数据
  293. */
  294. saveLoginState(data, userData) {
  295. // 保存token - 可能在不同字段
  296. const token = data.token || data.session_key || '';
  297. if (token) {
  298. uni.setStorageSync('token', token);
  299. console.log('Token已保存:', token);
  300. }
  301. // 保存用户信息
  302. uni.setStorageSync('userInfo', JSON.stringify(userData));
  303. console.log('用户信息已保存');
  304. // 更新页面状态
  305. this.isLogin = true;
  306. this.userInfo = userData;
  307. // 显示成功提示
  308. uni.hideLoading();
  309. uni.showToast({
  310. title: '登录成功',
  311. icon: 'success'
  312. });
  313. },
  314. /**
  315. * 处理登录错误
  316. * @param {Error} error - 错误对象
  317. * @param {Object} loginParams - 登录参数
  318. */
  319. handleLoginError(error, loginParams) {
  320. uni.hideLoading();
  321. // 检查是否是 code 无效错误
  322. if (error.message && (
  323. error.message.includes('code无效') ||
  324. error.message.includes('已过期') ||
  325. error.message.includes('已被使用') ||
  326. error.status === 999)) {
  327. console.error('微信登录code无效,重新获取:', error);
  328. uni.showToast({
  329. title: 'code已过期,请重试',
  330. icon: 'none',
  331. duration: 2000
  332. });
  333. // 延迟一下再重新获取code,避免频繁调用
  334. setTimeout(() => {
  335. this.getWxLoginCode();
  336. }, 1000);
  337. return;
  338. }
  339. // 其他错误处理保持不变
  340. if (error.code === 10001) {
  341. // 微信未绑定账号,跳转到绑定页面
  342. uni.navigateTo({
  343. url: '/pages/bind/bind?code=' + (loginParams.code || '')
  344. });
  345. } else if (error.message && error.message.includes('CSRF')) {
  346. // CSRF 错误处理
  347. console.error('CSRF验证失败:', error);
  348. uni.showToast({
  349. title: 'CSRF验证失败,请刷新页面重试',
  350. icon: 'none',
  351. duration: 2000
  352. });
  353. setTimeout(() => this.refreshCSRFToken(), 2000);
  354. } else {
  355. // 其他错误
  356. console.error('微信登录失败:', error);
  357. uni.showToast({
  358. title: error.message || '登录失败',
  359. icon: 'none'
  360. });
  361. }
  362. },
  363. /**
  364. * 获取用户详细信息
  365. * 步骤6: 获取并更新用户详细信息
  366. */
  367. async fetchUserDetail() {
  368. try {
  369. if (!this.isLogin) return;
  370. // 获取用户ID
  371. const userId = this.userInfo.userId;
  372. // 调用获取用户详情API
  373. const userDetail = await getUserInfo(userId);
  374. console.log('获取用户详细信息成功:', userDetail);
  375. if (userDetail) {
  376. // 更新用户信息
  377. this.updateUserInfo(userDetail);
  378. }
  379. } catch (error) {
  380. console.error('获取用户详细信息失败:', error);
  381. }
  382. },
  383. /**
  384. * 更新用户信息
  385. * @param {Object} userDetail - 用户详细信息
  386. */
  387. updateUserInfo(userDetail) {
  388. // 合并现有信息和新获取的详细信息
  389. const updatedUserInfo = {
  390. ...this.userInfo,
  391. // 更新基本信息
  392. username: userDetail.username || userDetail.nickName || this.userInfo.username,
  393. avatar: userDetail.avatar || userDetail.avatarUrl || this.userInfo.avatar,
  394. phone: userDetail.phone || userDetail.mobile || this.userInfo.phone,
  395. // 更新详细信息
  396. email: userDetail.email || '',
  397. address: userDetail.address || '',
  398. birthday: userDetail.birthday || '',
  399. // 其他字段
  400. ...userDetail
  401. };
  402. // 更新状态和存储
  403. this.userInfo = updatedUserInfo;
  404. uni.setStorageSync('userInfo', JSON.stringify(updatedUserInfo));
  405. console.log('用户详细信息已更新');
  406. },
  407. /**
  408. * 获取用户手机号
  409. * @param {Object} e - 事件对象
  410. */
  411. getPhoneNumber(e) {
  412.   if (e.detail.code) {
  413.     // 立即发送到后端,不缓存,不复用
  414.     wx.request({
  415.       url: 'http:192.168.66.187:8083/wechat/getUserPhoneNumber',
  416.       method: 'POST',
  417.       data: {
  418.         code: e.detail.code,  // 刚获取的新code
  419.         openid: this.data.openid
  420.       }
  421.     })
  422.   }
  423. },
  424. /* async getPhoneNumber(e) {
  425. console.log('获取手机号事件:', e);
  426. // 检查是否成功获取
  427. if (e.detail.errMsg !== 'getPhoneNumber:ok') {
  428. console.error('用户拒绝授权手机号');
  429. uni.showToast({
  430. title: '获取手机号失败',
  431. icon: 'none'
  432. });
  433. return;
  434. }
  435. try {
  436. uni.showLoading({ title: '获取手机号中...' });
  437. // 每次都重新获取最新的登录code
  438. const loginResult = await new Promise((resolve, reject) => {
  439. uni.login({
  440. provider: 'weixin',
  441. success: (res) => resolve(res),
  442. fail: (err) => reject(err)
  443. });
  444. });
  445. if (!loginResult || !loginResult.code) {
  446. throw new Error('获取微信登录凭证失败');
  447. }
  448. console.log('成功获取新的登录code:', loginResult.code);
  449. // 获取存储的用户信息
  450. const userInfoStr = uni.getStorageSync('userInfo');
  451. if (!userInfoStr) {
  452. throw new Error('用户信息不存在,请重新登录');
  453. }
  454. const userInfo = JSON.parse(userInfoStr);
  455. // 准备请求参数
  456. const params = {
  457. code: loginResult.code,
  458. encryptedData: e.detail.encryptedData,
  459. iv: e.detail.iv,
  460. openid: userInfo.openid
  461. };
  462. console.log('获取手机号请求参数:', params);
  463. // 调用获取手机号API
  464. const phoneData = await getUserPhoneNumber(params);
  465. console.log('获取手机号成功:', phoneData);
  466. // 更新用户信息
  467. if (phoneData && phoneData.phoneNumber) {
  468. const updatedUserInfo = {
  469. ...this.userInfo,
  470. phone: phoneData.phoneNumber
  471. };
  472. // 更新状态和存储
  473. this.userInfo = updatedUserInfo;
  474. uni.setStorageSync('userInfo', JSON.stringify(updatedUserInfo));
  475. uni.showToast({
  476. title: '手机号绑定成功',
  477. icon: 'success'
  478. });
  479. } else {
  480. throw new Error('未能获取到手机号');
  481. }
  482. } catch (error) {
  483. console.error('获取手机号失败:', error);
  484. uni.showToast({
  485. title: error.message || '获取手机号失败',
  486. icon: 'none'
  487. });
  488. } finally {
  489. uni.hideLoading();
  490. }
  491. }, */
  492. // 添加刷新 CSRF token 的方法
  493. refreshCSRFToken() {
  494. // 这里实现获取新的 CSRF token 的逻辑
  495. // 可能需要调用特定的 API 或刷新页面
  496. uni.request({
  497. url: 'your-api-endpoint/csrf-token', // 替换为获取 CSRF token 的 API
  498. method: 'GET',
  499. success: (res) => {
  500. if (res.data && res.data.csrfToken) {
  501. uni.setStorageSync('csrfToken', res.data.csrfToken);
  502. console.log('CSRF token 已刷新');
  503. }
  504. },
  505. fail: (err) => {
  506. console.error('获取 CSRF token 失败', err);
  507. }
  508. });
  509. },
  510. handleMenuClick(item) {
  511. // 检查是否需要登录
  512. const needLogin = ['profile', 'orders', 'favorites'];
  513. if (needLogin.includes(item.action) && !this.isLogin) {
  514. uni.showToast({
  515. title: '请先登录',
  516. icon: 'none'
  517. });
  518. setTimeout(() => {
  519. this.wxLogin()
  520. //this.goLogin();
  521. }, 1500);
  522. return;
  523. }
  524. // 根据action跳转到对应页面
  525. switch(item.action) {
  526. case 'profile':
  527. uni.navigateTo({ url: '/pages/profile/profile' });
  528. break;
  529. case 'orders':
  530. uni.navigateTo({ url: '/pages/orders/orders' });
  531. break;
  532. case 'favorites':
  533. uni.navigateTo({ url: '/pages/favorites/favorites' });
  534. break;
  535. case 'settings':
  536. uni.navigateTo({ url: '/pages/settings/settings' });
  537. break;
  538. case 'help':
  539. uni.navigateTo({ url: '/pages/help/help' });
  540. break;
  541. default:
  542. uni.showToast({
  543. title: `点击了${item.title}`,
  544. icon: 'none'
  545. });
  546. }
  547. },
  548. // 处理退出登录 - 增强版
  549. handleLogout(showConfirm = true) {
  550. const doLogout = () => {
  551. // 调用登出 API
  552. logout().then(() => {
  553. // 清除登录信息
  554. try {
  555. uni.removeStorageSync('token');
  556. uni.removeStorageSync('userInfo');
  557. // 更新状态
  558. this.isLogin = false;
  559. this.userInfo = {
  560. username: '',
  561. userId: '',
  562. avatar: '',
  563. phone: ''
  564. };
  565. // 显示提示(如果需要)
  566. if (showConfirm) {
  567. uni.showToast({
  568. title: '已退出登录',
  569. icon: 'success'
  570. });
  571. }
  572. } catch (e) {
  573. console.error('退出登录失败', e);
  574. if (showConfirm) {
  575. uni.showToast({
  576. title: '退出登录失败',
  577. icon: 'none'
  578. });
  579. }
  580. }
  581. }).catch(err => {
  582. console.error('退出登录请求失败', err);
  583. // 即使 API 请求失败,也清除本地登录状态
  584. uni.removeStorageSync('token');
  585. uni.removeStorageSync('userInfo');
  586. this.isLogin = false;
  587. if (showConfirm) {
  588. uni.showToast({
  589. title: err.message || '退出登录失败',
  590. icon: 'none'
  591. });
  592. }
  593. });
  594. };
  595. // 是否需要显示确认对话框
  596. if (showConfirm) {
  597. uni.showModal({
  598. title: '提示',
  599. content: '确定要退出登录吗?',
  600. success: (res) => {
  601. if (res.confirm) {
  602. doLogout();
  603. }
  604. }
  605. });
  606. } else {
  607. // 直接登出,不显示确认
  608. doLogout();
  609. }
  610. },
  611. // 格式化手机号,例如:188****8888
  612. formatPhone(phone) {
  613. if (!phone || phone.length < 11) return phone;
  614. return phone.substring(0, 3) + '****' + phone.substring(7);
  615. }
  616. }
  617. }
  618. </script>
  619. <style>
  620. .my-container {
  621. padding: 20rpx;
  622. background-color: #f5f5f5;
  623. min-height: 100vh;
  624. }
  625. .user-info {
  626. display: flex;
  627. align-items: center;
  628. background-color: #ffffff;
  629. padding: 30rpx;
  630. border-radius: 12rpx;
  631. margin-bottom: 20rpx;
  632. }
  633. .avatar {
  634. width: 120rpx;
  635. height: 120rpx;
  636. border-radius: 60rpx;
  637. margin-right: 20rpx;
  638. }
  639. .user-details {
  640. display: flex;
  641. flex-direction: column;
  642. }
  643. .username {
  644. font-size: 36rpx;
  645. font-weight: bold;
  646. margin-bottom: 10rpx;
  647. }
  648. .user-id {
  649. font-size: 24rpx;
  650. color: #999;
  651. }
  652. .user-phone {
  653. font-size: 24rpx;
  654. color: #666;
  655. margin-top: 6rpx;
  656. }
  657. .menu-list {
  658. background-color: #ffffff;
  659. border-radius: 12rpx;
  660. margin-bottom: 20rpx;
  661. }
  662. .menu-item {
  663. display: flex;
  664. justify-content: space-between;
  665. align-items: center;
  666. padding: 30rpx;
  667. border-bottom: 1rpx solid #f5f5f5;
  668. }
  669. .menu-item:last-child {
  670. border-bottom: none;
  671. }
  672. .menu-item-left {
  673. display: flex;
  674. align-items: center;
  675. }
  676. .menu-text {
  677. margin-left: 20rpx;
  678. font-size: 28rpx;
  679. }
  680. .logout-btn {
  681. background-color: #ffffff;
  682. border-radius: 12rpx;
  683. padding: 30rpx;
  684. text-align: center;
  685. color: #ff0000;
  686. font-size: 32rpx;
  687. }
  688. /* 这里应该引入iconfont,但为了简化,我们先不添加 */
  689. .iconfont {
  690. font-size: 36rpx;
  691. color: #007AFF;
  692. }
  693. .icon-right {
  694. color: #cccccc;
  695. }
  696. /* 授权弹窗样式 */
  697. .auth-modal {
  698. position: fixed;
  699. top: 0;
  700. left: 0;
  701. right: 0;
  702. bottom: 0;
  703. background-color: rgba(0, 0, 0, 0.5);
  704. display: flex;
  705. justify-content: center;
  706. align-items: center;
  707. z-index: 999;
  708. }
  709. .auth-content {
  710. width: 80%;
  711. background-color: #fff;
  712. border-radius: 12rpx;
  713. padding: 40rpx;
  714. display: flex;
  715. flex-direction: column;
  716. align-items: center;
  717. }
  718. .auth-title {
  719. font-size: 36rpx;
  720. font-weight: bold;
  721. margin-bottom: 20rpx;
  722. }
  723. .auth-desc {
  724. font-size: 28rpx;
  725. color: #666;
  726. margin-bottom: 40rpx;
  727. text-align: center;
  728. }
  729. .auth-btn {
  730. width: 100%;
  731. height: 80rpx;
  732. line-height: 80rpx;
  733. background-color: #07c160;
  734. color: #fff;
  735. border-radius: 8rpx;
  736. margin-bottom: 20rpx;
  737. }
  738. .auth-cancel {
  739. width: 100%;
  740. height: 80rpx;
  741. line-height: 80rpx;
  742. background-color: #f5f5f5;
  743. color: #333;
  744. border-radius: 8rpx;
  745. }
  746. /* 添加获取手机号按钮样式 */
  747. .get-phone-btn {
  748. margin-top: 20rpx;
  749. background-color: #07c160;
  750. color: #fff;
  751. border-radius: 8rpx;
  752. font-size: 28rpx;
  753. padding: 16rpx 0;
  754. }
  755. </style>