profile.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <script setup>
  2. import { computed, onMounted, ref } from 'vue';
  3. import { onShow } from '@dcloudio/uni-app';
  4. import { useUserStore } from '@/stores/user';
  5. import { resolveUserAvatarUrl } from '@/utils/avatar';
  6. import ClientSkeleton from '@/components/client/client-skeleton.vue';
  7. import ClientImageLoader from '@/components/client/client-image-loader.vue';
  8. import { fetchServicePhone, dialServicePhone } from '@/utils/service-contact';
  9. import { IMG_LOGO_WATERMARK } from '@/utils/staticAsset';
  10. // Store
  11. const userStore = useUserStore();
  12. const avatarDisplayUrl = computed(() => resolveUserAvatarUrl(userStore.userInfo?.avatarUrl, userStore.userInfo?.role));
  13. const headerStyle = { background: 'linear-gradient(145deg, #087f57, #0a9f6d)' };
  14. const servicePhone = ref('');
  15. const profileLoading = ref(true);
  16. async function loadServicePhone() {
  17. servicePhone.value = await fetchServicePhone();
  18. }
  19. async function onCallService() {
  20. const p = servicePhone.value || (await fetchServicePhone());
  21. servicePhone.value = p;
  22. dialServicePhone(p);
  23. }
  24. // 退出登录
  25. function handleLogout() {
  26. uni.showModal({
  27. title: '提示',
  28. content: '确定退出登录?',
  29. success: async (res) => {
  30. if (res.confirm) {
  31. await userStore.logout();
  32. }
  33. }
  34. });
  35. }
  36. onMounted(() => {
  37. if (!userStore.isLoggedIn) {
  38. uni.reLaunch({ url: '/pages/login/login' });
  39. profileLoading.value = false;
  40. }
  41. else if (!userStore.isDeliverer) {
  42. uni.showToast({ title: '您不是配送员', icon: 'none' });
  43. setTimeout(() => userStore.navigateToHome(), 1500);
  44. profileLoading.value = false;
  45. }
  46. else {
  47. (async () => {
  48. try {
  49. await loadServicePhone();
  50. }
  51. finally {
  52. profileLoading.value = false;
  53. }
  54. })();
  55. }
  56. });
  57. onShow(() => {
  58. if (!userStore.isLoggedIn || !userStore.isDeliverer)
  59. return;
  60. void loadServicePhone();
  61. });
  62. </script>
  63. <template>
  64. <view class="deliverer-profile">
  65. <ClientSkeleton v-if="profileLoading" variant="hero-list" :rows="2" />
  66. <template v-else>
  67. <!-- 用户信息卡片 -->
  68. <view class="user-card" :style="headerStyle">
  69. <image class="header-watermark" :src="staticAssetUrl('images/logo11.png')" mode="aspectFit" />
  70. <view class="user-info">
  71. <view class="avatar">
  72. <ClientImageLoader class="avatar-img" :src="avatarDisplayUrl" mode="aspectFill" radius="50%" />
  73. </view>
  74. <view class="user-detail">
  75. <text class="user-name">{{ userStore.userInfo?.realName || '配送员' }}</text>
  76. </view>
  77. </view>
  78. </view>
  79. <!-- 功能菜单 -->
  80. <view class="menu-list">
  81. <view class="menu-item" @click="onCallService">
  82. <view class="menu-left">
  83. <view class="menu-icon-badge">
  84. <text class="menu-icon">☎</text>
  85. </view>
  86. <text class="menu-text">联系客服</text>
  87. </view>
  88. <text class="menu-arrow">›</text>
  89. </view>
  90. </view>
  91. <!-- 退出登录 -->
  92. <view class="logout-btn" @click="handleLogout">
  93. <text>退出登录</text>
  94. </view>
  95. </template>
  96. </view>
  97. </template>
  98. <style lang="scss" scoped>
  99. .deliverer-profile {
  100. min-height: 100vh;
  101. background: #f3f7f5;
  102. }
  103. // 用户信息卡片
  104. .user-card {
  105. position: relative;
  106. padding: 56rpx 20rpx 26rpx;
  107. margin: 16rpx 16rpx 8rpx;
  108. border-radius: 18rpx;
  109. color: #ffffff;
  110. overflow: hidden;
  111. .user-info {
  112. position: relative;
  113. z-index: 2;
  114. display: flex;
  115. align-items: center;
  116. .avatar {
  117. width: 120rpx;
  118. height: 120rpx;
  119. background: rgba(255, 255, 255, 0.2);
  120. border-radius: 60rpx;
  121. display: flex;
  122. align-items: center;
  123. justify-content: center;
  124. margin-right: 24rpx;
  125. overflow: hidden;
  126. border: 2rpx solid rgba(255, 255, 255, 0.45);
  127. .avatar-img {
  128. width: 100%;
  129. height: 100%;
  130. }
  131. }
  132. .user-detail {
  133. display: flex;
  134. flex-direction: column;
  135. .user-name {
  136. font-size: 34rpx;
  137. font-weight: 700;
  138. }
  139. }
  140. }
  141. }
  142. .header-watermark {
  143. position: absolute;
  144. right: -12rpx;
  145. top: 50%;
  146. transform: translateY(-50%);
  147. width: 240rpx;
  148. height: 240rpx;
  149. opacity: 0.12;
  150. z-index: 1;
  151. }
  152. // 功能菜单
  153. .menu-list {
  154. background: #ffffff;
  155. margin: 10rpx 16rpx 16rpx;
  156. border-radius: 18rpx;
  157. overflow: hidden;
  158. border: 1rpx solid #d9e9e1;
  159. .menu-item {
  160. display: flex;
  161. align-items: center;
  162. justify-content: space-between;
  163. padding: 22rpx 16rpx;
  164. border-bottom: 1rpx solid rgba(217, 233, 225, 0.9);
  165. &:last-child {
  166. border-bottom: none;
  167. }
  168. .menu-left {
  169. display: flex;
  170. align-items: center;
  171. .menu-icon-badge {
  172. width: 64rpx;
  173. height: 64rpx;
  174. border-radius: 18rpx;
  175. display: flex;
  176. align-items: center;
  177. justify-content: center;
  178. background: linear-gradient(135deg, #10b981 0%, #34d399 100%);
  179. margin-right: 16rpx;
  180. box-shadow: 0 6rpx 16rpx rgba(16, 185, 129, 0.22);
  181. }
  182. .menu-icon {
  183. font-size: 34rpx;
  184. color: #ffffff;
  185. }
  186. .menu-text {
  187. font-size: 28rpx;
  188. color: #1f2a26;
  189. font-weight: 600;
  190. }
  191. }
  192. .menu-arrow {
  193. font-size: 32rpx;
  194. color: #9aa9a2;
  195. }
  196. }
  197. }
  198. // 退出登录
  199. .logout-btn {
  200. margin: 10rpx 16rpx 24rpx;
  201. height: 88rpx;
  202. background: #ffffff;
  203. border-radius: 18rpx;
  204. border: 1rpx solid #d9e9e1;
  205. display: flex;
  206. align-items: center;
  207. justify-content: center;
  208. text {
  209. font-size: 28rpx;
  210. color: #087f57;
  211. font-weight: 700;
  212. }
  213. }
  214. </style>