mine.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <route lang="json5">
  2. {
  3. layout: 'tabbar',
  4. needLogin: true,
  5. style: {
  6. navigationStyle: 'custom',
  7. },
  8. }
  9. </route>
  10. <script lang="ts" setup>
  11. import { pendingRedDots } from '@/api/order'
  12. import { getWalletAccountInfo } from '@/api/wallet'
  13. import { t } from '@/locale'
  14. import { useUserStore } from '@/store/user'
  15. import { formatNumber } from '@/utils'
  16. import { toPage } from '@/utils/page'
  17. defineOptions({
  18. name: 'Mine', // 我的
  19. })
  20. // 获取屏幕边界到安全区域距离
  21. const systemInfo = uni.getSystemInfoSync()
  22. const safeAreaInsets = systemInfo.safeAreaInsets
  23. // 用户状态管理
  24. const userStore = useUserStore()
  25. // 判断是否已登录
  26. const isLoggedIn = computed(() => !!userStore.token)
  27. // 获取用户信息
  28. const userInfo = computed(() => userStore.userInfo)
  29. const groupList = ref([
  30. { name: t('mine.group.toPay'), url: `/pages/myOrders/myOrders`, dotName: 'toPayNum', type: 1, icon: '/static/icons/to-pay.png' },
  31. { name: t('mine.group.success'), url: `/pages/myOrders/myOrders`, type: 2, dotName: 'successNum', icon: '/static/icons/success.png' },
  32. { name: t('mine.group.failed'), url: `/pages/myOrders/myOrders`, type: 3, dotName: 'failedNum', icon: '/static/icons/failed.png' },
  33. { name: t('mine.group.reward'), url: `/pages/myOrders/myOrders`, type: 4, dotName: 'rewardNum', icon: '/static/icons/reward.png' },
  34. ])
  35. const menuList = ref([
  36. { name: t('mine.menu.profile'), url: '/pages/mine/myProfile', icon: '/static/icons/my-profile.png' },
  37. { name: t('mine.menu.address'), url: '/pages/mine/addressBook', icon: '/static/icons/address-book.png' },
  38. { name: t('mine.menu.share'), url: '/pages/mine/share', icon: '/static/icons/share.png' },
  39. { name: t('mine.menu.favorite'), url: '/pages/mine/myFavorite', icon: '/static/icons/my-favorite.png' },
  40. { name: t('mine.menu.chat'), icon: '/static/icons/live-chat.png' },
  41. { name: t('mine.menu.activity'), url: '/pages/referEarn/referEarn', icon: '/static/icons/activity-group.png' },
  42. ])
  43. function menuClick(item: any) {
  44. if (item.url) {
  45. toPage({ url: item.url })
  46. }
  47. else {
  48. openWhatsApp()
  49. }
  50. }
  51. // 跳转whatsapp
  52. function openWhatsApp() {
  53. // 判断手机是否安装whatsapp
  54. // pname:Android 需要查询的包名 action:ios 需要查询的 URL Scheme
  55. // installed ture:安装 false:未安装
  56. const installed = plus.runtime.isApplicationExist({
  57. pname: 'com.whatsapp',
  58. action: 'whatsapp://',
  59. })
  60. // 电话号码
  61. const phoneNumber = '+8615058371889'
  62. // whatsapp 联系人聊天页面链接
  63. const whatsappUrl = `whatsapp://send?phone=${phoneNumber}`
  64. // whatsapp包名
  65. const pname = 'com.whatsapp'
  66. // 判断手机系统,走不同方法
  67. if (plus.os.name === 'Android') {
  68. if (installed) {
  69. // 手机已安装 直接跳转
  70. plus.runtime.openURL(whatsappUrl)
  71. }
  72. else {
  73. // 手机未安装,跳转到手机商城并搜索whatsapp (国内目前搜不到)
  74. plus.nativeUI.actionSheet(
  75. {
  76. title: '选择应用',
  77. cancel: '取消',
  78. buttons: [{ title: '应用市场' }],
  79. },
  80. ({ index }) => {
  81. switch (index) {
  82. case 1:
  83. plus.runtime.openURL(
  84. `market://details?id=${pname}`,
  85. () => {
  86. // 手机没有应用市场
  87. plus.nativeUI.alert('本机未安装指定的应用')
  88. },
  89. )
  90. }
  91. },
  92. )
  93. }
  94. }
  95. }
  96. const walletInfo = ref<any>({})
  97. async function getWalletInfo() {
  98. // 获取钱包信息-查询余额
  99. const res = await getWalletAccountInfo()
  100. console.log(res)
  101. walletInfo.value = res?.data
  102. }
  103. const pendingRedDotsData = ref<any>({})
  104. async function getPendingRedDots() {
  105. try {
  106. const res = await pendingRedDots()
  107. if (res.code === '200') {
  108. console.log(res)
  109. pendingRedDotsData.value = res?.data
  110. }
  111. }
  112. catch {}
  113. }
  114. onShow(() => {
  115. getWalletInfo()
  116. getPendingRedDots()
  117. })
  118. onLoad(() => {
  119. // 页面加载时的逻辑
  120. userStore.getUserInfo()
  121. })
  122. </script>
  123. <template>
  124. <view
  125. class="flex items-center justify-between bg-[rgba(var(--wot-color-theme-rgb),0.3)] pb-72rpx pl-24rpx pr-54rpx"
  126. :style="{ paddingTop: `${safeAreaInsets?.top + 24}px` }"
  127. >
  128. <view class="flex items-center">
  129. <wd-img
  130. width="96rpx"
  131. height="96rpx"
  132. round
  133. :src="isLoggedIn ? userInfo?.headPic : '/static/images/default-avatar.png'"
  134. />
  135. <!-- 已登录 -->
  136. <view v-if="isLoggedIn" class="ml-24rpx text-32rpx font-bold">
  137. {{ userInfo?.name || userInfo?.username || 'User' }}
  138. </view>
  139. <!-- 未登录 -->
  140. <view v-else class="ml-24rpx flex items-center">
  141. <wd-button size="small" custom-class="mr-20rpx! bg-transparent!" plain @click="toPage({ url: '/pages/register/register' })">
  142. {{ $t('mine.auth.register') }}
  143. </wd-button>
  144. <wd-button size="small" @click="toPage({ url: '/pages/login/login' })">
  145. {{ $t('mine.auth.login') }}
  146. </wd-button>
  147. </view>
  148. </view>
  149. <wd-icon name="setting" color="#3A444C" size="36rpx" @click="toPage({ url: '/pages/mine/setting' })" />
  150. </view>
  151. <view class="relative rounded-tl-24rpx rounded-tr-24rpx bg-white px-24rpx pb-36rpx pt-32rpx -top-24rpx" @click="toPage({ url: '/pages/wallet/myWallet' })">
  152. <view class="mb-24rpx text-32rpx">
  153. {{ $t('mine.wallet.title') }}
  154. </view>
  155. <view
  156. class="flex items-center justify-between rounded-12rpx bg-[rgba(var(--wot-color-theme-rgb),0.1)] px-16rpx py-34rpx"
  157. >
  158. <view class="flex items-center">
  159. <wd-img width="84rpx" height="84rpx" round src="/static/icons/wallet-balance.png" />
  160. <view class="ml-18rpx">
  161. <view class="mb-3px text-22rpx text-#595959">
  162. {{ $t('mine.wallet.balance') }}
  163. </view>
  164. <view class="text-44rpx text-[var(--wot-color-theme)] font-bold">
  165. {{ formatNumber(walletInfo.balance) }}
  166. </view>
  167. </view>
  168. </view>
  169. <view class="flex flex-col items-end" @click.stop="toPage({ url: '/pages/wallet/recharge' })">
  170. <wd-button size="small">
  171. {{ $t('mine.wallet.recharge') }}
  172. </wd-button>
  173. </view>
  174. </view>
  175. </view>
  176. <view class="mb-24rpx bg-white px-24rpx pb-32rpx pt-26rpx">
  177. <view class="mb-24rpx flex items-center justify-between">
  178. <text class="text-32rpx">
  179. {{ $t('mine.group.title') }}
  180. </text>
  181. <view class="flex items-center" @click="toPage({ url: '/pages/myOrders/myOrders' })">
  182. <text class="mr-8rpx text-22rpx text-#3A444C">
  183. {{ $t('mine.group.all') }}
  184. </text>
  185. <wd-icon name="chevron-right" size="28rpx" />
  186. </view>
  187. </view>
  188. <view class="grid grid-cols-4 gap-24rpx">
  189. <view v-for="(item, index) in groupList" :key="index" class="flex flex-col items-center" @click="toPage({ url: item.url, params: { type: item.type } })">
  190. <wd-badge :model-value="item.type === 3 ? 0 : pendingRedDotsData[item.dotName]" :max="99">
  191. <wd-img width="48rpx" height="48rpx" :src="item.icon" />
  192. </wd-badge>
  193. <view class="mt-24rpx text-22rpx text-#3A444C">
  194. {{ item.name }}
  195. </view>
  196. </view>
  197. </view>
  198. </view>
  199. <view class="grid grid-cols-3 gap-48rpx bg-white py-65rpx">
  200. <view v-for="(item, index) in menuList" :key="index" class="flex flex-col items-center" @click="menuClick(item)">
  201. <wd-img width="48rpx" height="48rpx" :src="item.icon" />
  202. <view class="mt-24rpx text-22rpx text-#3A444C">
  203. {{ item.name }}
  204. </view>
  205. </view>
  206. </view>
  207. </template>