mine.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. <!-- pages/mine/mine.vue -->
  2. <template>
  3. <view class="mine-container">
  4. <!-- 顶部用户信息区域 -->
  5. <view class="user-header ">
  6. <headerInfo title="个人中心"></headerInfo>
  7. <view class="user-info-section">
  8. <view class="avatar-section">
  9. <u-avatar
  10. @click="toUser"
  11. size="144rpx"
  12. shape="circle"
  13. :src="userAvatar"
  14. mode="aspectFill"
  15. :show-level="false"
  16. default-url="/static/img/default-avatar.png"
  17. ></u-avatar>
  18. <!-- <image
  19. @click="toUser"
  20. :src="userAvatar"
  21. mode="aspectFill"
  22. class="avatar"
  23. ></image> -->
  24. <view class="user-text-info">
  25. <view class="user-name-section">
  26. <view v-if="isLoggedIn">
  27. <view class="name-section">
  28. <view class="user-name" @click="toUser">
  29. {{ displayName }}
  30. </view>
  31. <view class="department-badge" v-if="dept">
  32. {{dept}}
  33. </view>
  34. </view>
  35. <view class="user-account">
  36. 账号:{{ userAccount }}
  37. </view>
  38. </view>
  39. <!-- 修改点:去掉 open-type,改为点击跳转登录页 -->
  40. <button v-else
  41. class="login-button"
  42. @click="goToLogin"
  43. >
  44. 请点击登录
  45. </button>
  46. </view>
  47. </view>
  48. </view>
  49. </view>
  50. </view>
  51. <!-- 菜单功能区域(保持不变) -->
  52. <view class="menu-section">
  53. <view class="menu-card">
  54. <!-- 订单列表 -->
  55. <!-- <view class="menu-item" @click="toOrderList">
  56. <view class="menu-item-left">
  57. <image src="/static/img/mine/icon-mine-order.png" class="menu-icon"></image>
  58. <text class="menu-text">订单列表</text>
  59. </view>
  60. <image src="/static/img/arrow-right.png" class="arrow-icon"></image>
  61. </view> -->
  62. <!-- 地址簿 -->
  63. <view class="menu-item" @click="toAddressBook">
  64. <view class="menu-item-left">
  65. <image src="/static/img/mine/icon-mine-address.png" class="menu-icon"></image>
  66. <text class="menu-text">地址簿</text>
  67. </view>
  68. <image src="/static/img/arrow-right.png" class="arrow-icon"></image>
  69. </view>
  70. <!-- 到付月结码 -->
  71. <view class="menu-item" @click="toSettlementCode">
  72. <view class="menu-item-left">
  73. <image src="/static/img/mine/icon-mine-qr.png" class="menu-icon"></image>
  74. <text class="menu-text">到付月结码</text>
  75. </view>
  76. <image src="/static/img/arrow-right.png" class="arrow-icon"></image>
  77. </view>
  78. <!-- 联系客服 -->
  79. <view class="menu-item" @click="makePhoneCall">
  80. <view class="menu-item-left">
  81. <image src="/static/img/mine/icon-mine-server.png" class="menu-icon"></image>
  82. <text class="menu-text">联系客服</text>
  83. </view>
  84. <image src="/static/img/arrow-right.png" class="arrow-icon"></image>
  85. </view>
  86. <!-- 隐私政策 -->
  87. <view class="menu-item" @click="toPrivacyPolicy">
  88. <view class="menu-item-left">
  89. <image src="/static/img/mine/icon-mine-policy.png" class="menu-icon"></image>
  90. <text class="menu-text">用户协议</text>
  91. </view>
  92. <image src="/static/img/arrow-right.png" class="arrow-icon"></image>
  93. </view>
  94. <!-- 隐私政策 -->
  95. <view class="menu-item" @click="toPrivacyPolicy1">
  96. <view class="menu-item-left">
  97. <image src="/static/img/mine/icon-mine-policy.png" class="menu-icon"></image>
  98. <text class="menu-text">隐私政策</text>
  99. </view>
  100. <image src="/static/img/arrow-right.png" class="arrow-icon"></image>
  101. </view>
  102. <!-- 关于我们 -->
  103. <view class="menu-item" @click="toAboutUs">
  104. <view class="menu-item-left">
  105. <image src="/static/img/mine/icon-mine-about.png" class="menu-icon"></image>
  106. <text class="menu-text">关于我们</text>
  107. </view>
  108. <image src="/static/img/arrow-right.png" class="arrow-icon"></image>
  109. </view>
  110. <!-- 退出登录(仅登录后显示) -->
  111. <view
  112. class="menu-item logout-item"
  113. v-if="isLoggedIn"
  114. @click="userLogoutFn">
  115. <text class="menu-text logout-text">退出登录</text>
  116. </view>
  117. </view>
  118. </view>
  119. <!-- 加载提示 -->
  120. <u-loading-page :loading="pageLoading" bg-color="transparent"></u-loading-page>
  121. </view>
  122. </template>
  123. <script setup>
  124. import { ref, computed, onMounted } from "vue";
  125. import headerInfo from "@/components/headerInfo.vue";
  126. import { userLogout } from "@/api/user.js";
  127. import { getAdServicePhone } from "@/api/home.js";
  128. import { checkLoginShowModal } from "@/utils/util.js"; // 移除 quickLogin 导入
  129. import { onLoad, onShow, onShareAppMessage } from '@dcloudio/uni-app'
  130. import { useAppStore } from "@/stores/app";
  131. const appStore = useAppStore();
  132. // 响应式数据(移除了 isLogging, isProcessing)
  133. const pageLoading = ref(false);
  134. const phoneNumber = ref('');
  135. // 计算属性
  136. const isLoggedIn = computed(() => {
  137. return appStore.token;
  138. });
  139. const userAvatar = computed(() => {
  140. return appStore.userInfo?.avatar || '/static/img/default-avatar.png';
  141. });
  142. const displayName = computed(() => {
  143. return appStore.userInfo?.nickName || appStore.userInfo?.userName;
  144. });
  145. const dept = computed(() => {
  146. return appStore.userInfo?.dept?.deptName || "";
  147. });
  148. // 修改 userAccount 脱敏展示
  149. const userAccount = computed(() => {
  150. const raw = appStore.userInfo?.userName || appStore.userInfo?.phonenumber || '';
  151. if (!raw) return '';
  152. // 脱敏处理
  153. if (/^\d{11}$/.test(raw)) {
  154. // 手机号:前3后4
  155. return raw.slice(0, 3) + '****' + raw.slice(-4);
  156. } else {
  157. // 其他字符串
  158. if (raw.length <= 4) {
  159. return raw;
  160. } else {
  161. return raw.charAt(0) + '****' + raw.charAt(raw.length - 1);
  162. }
  163. }
  164. });
  165. onShareAppMessage((res) => {
  166. return appStore.onShareAppMessageObj;
  167. });
  168. onLoad(() => {
  169. getAdServicePhoneFn();
  170. checkUserStatus();
  171. });
  172. onShow(() => {
  173. if (appStore.token) {
  174. appStore.USERINFO();
  175. }
  176. });
  177. // 检查用户状态
  178. async function checkUserStatus() {
  179. if (appStore.token && !appStore.userName) {
  180. pageLoading.value = true;
  181. try {
  182. await appStore.USERINFO();
  183. } catch (error) {
  184. console.error('获取用户信息失败:', error);
  185. } finally {
  186. pageLoading.value = false;
  187. }
  188. }
  189. }
  190. // 获取客服电话
  191. function getAdServicePhoneFn() {
  192. getAdServicePhone({}).then(res => {
  193. phoneNumber.value = res.contact || '';
  194. }).catch(err => {
  195. console.log(err);
  196. });
  197. }
  198. // 跳转到登录页(新增)
  199. function goToLogin() {
  200. uni.navigateTo({
  201. url: '/pages/mine/login'
  202. });
  203. }
  204. // 跳转到用户信息页(保留原有逻辑)
  205. async function toUser() {
  206. // if (!await checkLoginShowModal()) return;
  207. // uni.navigateTo({ url: '/pages/user/user' });
  208. }
  209. // 跳转到订单列表
  210. async function toOrderList() {
  211. if (!await checkLoginShowModal()) return;
  212. uni.navigateTo({ url: '/pages/order/index' });
  213. }
  214. // 跳转到地址簿
  215. async function toAddressBook() {
  216. if (!await checkLoginShowModal()) return;
  217. uni.navigateTo({ url: '/pages/address/address_list' });
  218. }
  219. // 跳转到月结码
  220. async function toSettlementCode() {
  221. if (!await checkLoginShowModal()) return;
  222. uni.navigateTo({ url: '/pages/mine/settlementCode' });
  223. }
  224. // 跳转到隐私政策
  225. async function toPrivacyPolicy() {
  226. uni.navigateTo({
  227. url: '/pages/webView/webView?title=用户协议&url=' + encodeURIComponent('https://rjsd.mychery.com/user_agreement.html')
  228. });
  229. }
  230. // 跳转到隐私政策
  231. async function toPrivacyPolicy1() {
  232. uni.navigateTo({
  233. url: '/pages/webView/webView?title=隐私政策&url=' + encodeURIComponent('https://rjsd.mychery.com/privacy_policy.html')
  234. });
  235. }
  236. // 跳转到关于我们
  237. async function toAboutUs() {
  238. uni.navigateTo({ url: '/pages/about/index' });
  239. }
  240. // 拨打电话
  241. const makePhoneCall = () => {
  242. if (!phoneNumber.value) {
  243. uni.showToast({ title: '客服电话暂时无法接通', icon: 'none' });
  244. return;
  245. }
  246. uni.makePhoneCall({ phoneNumber: phoneNumber.value });
  247. };
  248. // 退出登录
  249. function userLogoutFn() {
  250. uni.showModal({
  251. title: '提示',
  252. content: '确认要退出登录吗?',
  253. success: function(res) {
  254. if (res.confirm) {
  255. appStore.LOGOUT();
  256. }
  257. }
  258. });
  259. }
  260. </script>
  261. <style lang="less" scoped>
  262. /* 样式优化:昵称和部门自适应布局,部门背景完整 */
  263. .mine-container {
  264. height: 100vh;
  265. background: linear-gradient(135deg, #CFE9FF 0%, #F5F7FA 50.86%);
  266. position: relative;
  267. .user-header {
  268. padding: 0rpx 24rpx;
  269. .user-info-section {
  270. margin-top: 32rpx;
  271. display: flex;
  272. flex-direction: column;
  273. gap: 20rpx;
  274. .avatar-section {
  275. display: flex;
  276. align-items: center;
  277. min-height: 144rpx;
  278. .avatar {
  279. width: 144rpx;
  280. height: 144rpx;
  281. border-radius: 50%;
  282. }
  283. .user-text-info {
  284. flex: 1;
  285. display: flex;
  286. flex-direction: column;
  287. justify-content: center;
  288. min-height: 144rpx;
  289. overflow: hidden; /* 防止内部内容溢出 */
  290. }
  291. .user-name-section {
  292. margin-left: 16rpx;
  293. min-height: 100rpx;
  294. display: flex;
  295. flex-direction: column;
  296. justify-content: center;
  297. width: 100%; /* 确保占满父容器宽度 */
  298. .name-section {
  299. display: flex;
  300. align-items: center;
  301. margin-bottom: 8rpx;
  302. width: 540rpx;
  303. overflow: hidden; /* 隐藏超出部分,避免影响布局 */
  304. }
  305. .user-name {
  306. min-width: 0; /* 允许截断 */
  307. font-weight: bold;
  308. font-size: 36rpx;
  309. color: #333333;
  310. white-space: nowrap;
  311. overflow: hidden;
  312. text-overflow: ellipsis;
  313. line-height: 1;
  314. }
  315. .login-button {
  316. background: transparent;
  317. font-size: 40rpx;
  318. font-weight: 600;
  319. color: #333;
  320. line-height: 56rpx;
  321. padding: 0;
  322. margin: 0;
  323. text-align: left;
  324. height: auto;
  325. min-height: 56rpx;
  326. display: flex;
  327. align-items: center;
  328. justify-content: flex-start;
  329. &::after {
  330. border: none;
  331. }
  332. }
  333. }
  334. .user-account {
  335. height: 44rpx;
  336. font-weight: 400;
  337. font-size: 28rpx;
  338. color: #333333;
  339. line-height: 44rpx;
  340. margin-top: 4rpx;
  341. }
  342. }
  343. .department-badge {
  344. background: #1B64F0;
  345. border-radius: 8rpx;
  346. font-size: 24rpx;
  347. color: #FFFFFF;
  348. text-align: center;
  349. margin-left: 8rpx;
  350. padding: 7rpx 16rpx;
  351. line-height: 1;
  352. white-space: nowrap;
  353. overflow: hidden;
  354. text-overflow: ellipsis;
  355. }
  356. }
  357. }
  358. .menu-section {
  359. padding: 0 20rpx;
  360. margin-top: 20rpx;
  361. .menu-card {
  362. overflow: hidden;
  363. }
  364. .menu-item {
  365. display: flex;
  366. align-items: center;
  367. justify-content: space-between;
  368. padding: 32rpx;
  369. background: #FFFFFF;
  370. border-radius: 24rpx;
  371. margin-bottom: 20rpx;
  372. min-height: 112rpx;
  373. .menu-item-left {
  374. display: flex;
  375. align-items: center;
  376. gap: 24rpx;
  377. flex: 1;
  378. }
  379. .menu-icon {
  380. width: 48rpx;
  381. height: 48rpx;
  382. flex-shrink: 0;
  383. }
  384. .menu-text {
  385. font-size: 32rpx;
  386. font-weight: 500;
  387. color: #333333;
  388. line-height: 45rpx;
  389. }
  390. .arrow-icon {
  391. width: 48rpx;
  392. height: 48rpx;
  393. opacity: 0.5;
  394. flex-shrink: 0;
  395. }
  396. &.logout-item {
  397. height: 88rpx;
  398. background: #FEEAEA;
  399. border-radius: 32rpx;
  400. display: flex;
  401. justify-content: center;
  402. align-items: center;
  403. .logout-text {
  404. font-weight: 400;
  405. font-size: 32rpx;
  406. color: #F52929;
  407. text-align: center;
  408. }
  409. }
  410. }
  411. }
  412. }
  413. .menu-item {
  414. transition: all 0.3s ease;
  415. opacity: 1;
  416. &:active {
  417. background-color: rgba(66, 133, 244, 0.05);
  418. transform: translateX(8rpx);
  419. }
  420. &[disabled] {
  421. opacity: 0.6;
  422. pointer-events: none;
  423. }
  424. }
  425. .department-badge {
  426. transition: all 0.3s ease;
  427. &:active {
  428. transform: scale(0.95);
  429. }
  430. }
  431. @media (max-width: 375px) {
  432. .menu-section {
  433. padding: 0 20rpx !important;
  434. }
  435. .menu-card {
  436. padding: 0 20rpx !important;
  437. }
  438. .menu-text {
  439. font-size: 30rpx !important;
  440. }
  441. }
  442. view, text, image {
  443. will-change: auto;
  444. backface-visibility: hidden;
  445. -webkit-backface-visibility: hidden;
  446. }
  447. </style>