index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. <route lang="json">
  2. {
  3. "style": {
  4. "navigationBarTitleText": "我的荣誉",
  5. "navigationStyle": "custom"
  6. }
  7. }
  8. </route>
  9. <script setup lang="ts">
  10. import NavbarEvo from '@/components/navbar-evo.vue'
  11. import Card from '@/components/card.vue'
  12. import SectionHeading from '@/components/section-heading.vue'
  13. import {
  14. getBadges,
  15. getCertificates,
  16. getHonorStatistics,
  17. getListCollectionBadge,
  18. } from '../../../core/libs/requests'
  19. import { useRouter } from '../../../core/utils/router'
  20. import arcBottom from '@designer-hub/assets/src/libs/assets/arcBottom'
  21. import { NetImages } from '../../../core/libs/net-images'
  22. import ProgressEvo from '@/components/progress-evo.vue'
  23. import { Certificate } from '@/core/libs/models'
  24. import dayjs from 'dayjs'
  25. import { useUserStore } from '@/store'
  26. import { storeToRefs } from 'pinia'
  27. import SwiperEvo from '@/components/swiper-evo.vue'
  28. const id = ref()
  29. const isShared = ref(false)
  30. const router = useRouter()
  31. const userStore = useUserStore()
  32. const { userInfo } = storeToRefs(userStore)
  33. const active = ref('badge')
  34. const autoplay = ref<boolean>(false)
  35. const tabs = ref([
  36. { label: '徽章', value: 'badge' },
  37. { label: '证书', value: 'certificate' },
  38. ])
  39. const { data: statistics, run: setStatistics } = useRequest(() =>
  40. getHonorStatistics({ userId: id.value }),
  41. )
  42. const { data: badges, run: setBadges } = useRequest(() => getBadges({ userId: id.value }), {
  43. initialData: {},
  44. })
  45. const { data: collectionBadges, run: setCollectionBadges } = useRequest(
  46. () => getListCollectionBadge({ userId: id.value }),
  47. { initialData: [] },
  48. )
  49. const { data: certificates, run: setCertificates } = useRequest(
  50. () => getCertificates({ userId: id.value }),
  51. {
  52. initialData: [],
  53. },
  54. )
  55. const save = async (filePath: string) => {
  56. uni.downloadFile({
  57. url: filePath, // 下载资源的网络地址
  58. success: (res) => {
  59. if (res.statusCode === 200) {
  60. uni.saveImageToPhotosAlbum({
  61. filePath: res.tempFilePath, // 临时文件路径
  62. success: () => {
  63. uni.showToast({ title: '已保存相册', icon: 'none' })
  64. },
  65. fail: (err) => {
  66. uni.showToast({
  67. title: '保存失败',
  68. icon: 'none',
  69. })
  70. },
  71. })
  72. }
  73. },
  74. fail: (err) => {
  75. uni.showToast({
  76. title: '下载失败',
  77. icon: 'none',
  78. })
  79. },
  80. })
  81. }
  82. const handleGetCondition = (badge: any) => {
  83. uni.navigateTo({
  84. url: `/pages-sub/mine/honors/detail/collection?badgeId=${badge}&id=${id.value}`,
  85. })
  86. }
  87. const handleGetBadge = (badge: any) => {
  88. uni.navigateTo({
  89. url: `/pages-sub/mine/honors/leaderboard/index?id=${badge}`,
  90. })
  91. }
  92. const currentCertificate = ref<Certificate | undefined>()
  93. const isOwner = computed(() => String(userInfo.value?.userId) === id.value)
  94. onLoad(async (query?: Record<string | 'active' | 'id' | 'isShared', string>) => {
  95. // console.log('query:::::', query)
  96. if (Object.keys(query).length !== 0) {
  97. if (query?.active) {
  98. active.value = query.active
  99. }
  100. if (query?.id) {
  101. id.value = query.id
  102. }
  103. if (query?.isShared) {
  104. isShared.value = true
  105. }
  106. }
  107. await setStatistics()
  108. await setBadges()
  109. await setCertificates()
  110. await setCollectionBadges()
  111. })
  112. </script>
  113. <template>
  114. <div class="flex-grow bg-gradient-to-b from-[#181614] to-[#0f0f0f] flex flex-col gap-4 p-3.5">
  115. <div class="aspect-[1.63/1] m--3.5 overflow-hidden relative">
  116. <wd-img width="100%" mode="widthFix" :src="NetImages.HonorsHeader"></wd-img>
  117. <div class="absolute left-7 bottom-6.5">
  118. <div
  119. class="text-white text-3xl font-bold font-['Alimama_ShuHeiTi'] leading-relaxed pr-2.5"
  120. style="
  121. background: linear-gradient(92deg, #fff 0.4%, #ffebb2 107.42%);
  122. -webkit-background-clip: text;
  123. background-clip: text;
  124. -webkit-text-fill-color: transparent;
  125. "
  126. >
  127. 荣誉主页
  128. </div>
  129. <div class="mt-4 flex justify-between">
  130. <template
  131. v-for="(it, i) in [
  132. { label: '获得徽章', value: statistics?.badgeCount, unit: '枚' },
  133. { label: '获得证书', value: statistics?.certCount, unit: '个' },
  134. ]"
  135. :key="i"
  136. >
  137. <div class="flex flex-col items-center gap-1.25">
  138. <div
  139. class="text-center text-[#f6e8da]/80 text-xs font-normal font-['PingFang_SC'] leading-snug"
  140. >
  141. {{ it.label }}
  142. </div>
  143. <div class="flex items-end gap-1">
  144. <div
  145. class="text-center text-white text-2xl font-medium font-['D-DIN-PRO'] leading-6"
  146. >
  147. {{ it.value }}
  148. </div>
  149. <div
  150. class="text-center text-[#f6e8da]/80 text-xs font-normal font-['PingFang_SC'] leading-snug"
  151. >
  152. {{ it.unit }}
  153. </div>
  154. </div>
  155. </div>
  156. </template>
  157. </div>
  158. </div>
  159. </div>
  160. <NavbarEvo dark fixed transparent></NavbarEvo>
  161. <div class="flex items-center justify-around">
  162. <template v-for="(it, i) in tabs" :key="i">
  163. <div class="flex flex-col items-center gap-1" @click="active = it.value">
  164. <div
  165. class="text-center font-normal font-['PingFang_SC']"
  166. :class="`${it.value === active ? 'text-white text-lg leading-relaxed ' : 'text-white/60 text-base leading-normal'}`"
  167. >
  168. {{ it.label }}
  169. </div>
  170. <wd-img v-if="it.value === active" width="17" height="5.6" :src="arcBottom"></wd-img>
  171. </div>
  172. </template>
  173. </div>
  174. <template v-if="active === 'badge'">
  175. <!-- <view class="h-[145px]" v-if="String(userInfo.userId) === id"> -->
  176. <view class="h-[145px]">
  177. <SwiperEvo :items="collectionBadges" dot-color="#fff">
  178. <template #default="{ item }">
  179. <Card custom-class="border border-solid bg-[#25221f]! border-[rgba(255,236,185,0.20)]">
  180. <div class="grid grid-cols-[90px_1fr] gap-x-4">
  181. <div
  182. class="grid-row-start-1 grid-row-end-4 col-start-1"
  183. @click="
  184. router.push(
  185. `/pages-sub/mine/honors/detail/index?type=badge&id=${id}&data=${JSON.stringify(item)}`,
  186. )
  187. "
  188. >
  189. <wd-img width="90" height="90" :src="item.badgeYesObtainedImage"></wd-img>
  190. </div>
  191. <div class="row-start-1 col-start-2 flex items-center justify-between">
  192. <div
  193. class="text-center text-[#ffecb9] text-lg font-normal font-['PingFang_SC'] leading-relaxed"
  194. @click="
  195. router.push(
  196. `/pages-sub/mine/honors/detail/index?type=badge&id=${id}&data=${JSON.stringify(item)}`,
  197. )
  198. "
  199. >
  200. {{ item.badgeName }}
  201. </div>
  202. <div
  203. class="h-[26px] px-2.5 rounded-[30px] border border-solid border-[#ffecb9] justify-center items-center gap-2.5 inline-flex"
  204. >
  205. <div
  206. class="text-center text-[#ffecb9] text-xs font-normal font-['PingFang_SC'] leading-relaxed"
  207. @click="handleGetCondition(item.id)"
  208. >
  209. 获取条件
  210. </div>
  211. </div>
  212. </div>
  213. <div class="row-start-2 col-start-2">
  214. <div
  215. class="text-start text-white/60 text-xs font-normal font-['PingFang_SC'] leading-relaxed"
  216. >
  217. {{ item.badgeDescription }}
  218. </div>
  219. </div>
  220. <div class="row-start-3 col-start-2 flex items-center gap-4">
  221. <div class="flex-1">
  222. <ProgressEvo
  223. :height="5"
  224. :model-value="
  225. (
  226. Number.parseInt(item.userSize as any) /
  227. Number.parseInt(item.badgeSize as any)
  228. ).toFixed(2) * 100
  229. "
  230. color="linear-gradient(90deg, #FFDA72 0%, #FFECB9 100%)"
  231. ></ProgressEvo>
  232. </div>
  233. <div>
  234. <span class="text-white text-xs font-normal font-['PingFang_SC'] leading-none">
  235. {{ item.userSize }}
  236. </span>
  237. <span
  238. class="text-[#a1a1a1] text-xs font-normal font-['PingFang_SC'] leading-none"
  239. >
  240. /{{ item.badgeSize }}
  241. </span>
  242. </div>
  243. </div>
  244. <div class="row-start-4 col-start-1 flex items-center justify-center">
  245. <div
  246. class="w-[59px] h-[21px] px-2.5 bg-[#524c3b] rounded-[30px] shadow shadow-inner justify-center items-center gap-0.5 inline-flex"
  247. >
  248. <div
  249. class="text-center text-[#ffecb9] text-[10px] font-normal font-['PingFang_SC'] leading-relaxed"
  250. @click="handleGetBadge(item.id)"
  251. >
  252. 获取榜
  253. </div>
  254. </div>
  255. </div>
  256. </div>
  257. </Card>
  258. </template>
  259. </SwiperEvo>
  260. </view>
  261. <template v-for="([key, it], index) in Object.entries(badges)" :key="index">
  262. <Card
  263. v-if="!((!isOwner || isShared) && ['积分徽章', '积分徽章'].includes(key))"
  264. custom-class="bg-[#171615]! text-white border border-solid border-[rgba(255,236,185,0.20)]"
  265. >
  266. <div class="flex items-center gap-2 py-4">
  267. <div class="w-1.5 h-1.5 bg-[#ffecb9] rounded-full"></div>
  268. <SectionHeading :title="key.toString()" dark></SectionHeading>
  269. </div>
  270. <div class="grid grid-cols-3 gap-y-6">
  271. <template v-for="(item, i) in it" :key="i">
  272. <div
  273. class="w-full px-4 box-border"
  274. @click="
  275. router.push(
  276. `/pages-sub/mine/honors/detail/index?type=badge&id=${id}&data=${JSON.stringify(item)}`,
  277. )
  278. "
  279. >
  280. <wd-img
  281. width="100%"
  282. mode="widthFix"
  283. :src="item.quantity ? item.badgeYesObtainedImage : item.badgeNotObtainedImage"
  284. ></wd-img>
  285. <div
  286. class="text-center text-white text-xs font-normal font-['PingFang_SC'] leading-relaxed"
  287. >
  288. {{ item.badgeName }}
  289. </div>
  290. </div>
  291. </template>
  292. </div>
  293. </Card>
  294. </template>
  295. </template>
  296. <template v-if="active === 'certificate'">
  297. <div>
  298. <div class="grid grid-cols-2 gap-2.5">
  299. <template v-for="(it, i) in certificates" :key="i">
  300. <div class="aspect-[1.35/1]" @click="currentCertificate = it">
  301. <wd-img
  302. width="100%"
  303. height="100%"
  304. :src="it.certificateImage"
  305. mode="aspectFill"
  306. custom-class="vertical-bottom"
  307. ></wd-img>
  308. </div>
  309. </template>
  310. </div>
  311. </div>
  312. </template>
  313. <wd-overlay :show="currentCertificate !== undefined" @click="currentCertificate = undefined">
  314. <div class="h-full flex flex-col items-center justify-around">
  315. <div class="flex flex-col">
  316. <wd-img
  317. width="85vw"
  318. height="94vw"
  319. :src="currentCertificate?.certificateImage"
  320. mode="aspectFit"
  321. ></wd-img>
  322. <div
  323. class="text-center text-white text-xl font-normal font-['PingFang_SC'] uppercase mt-7"
  324. >
  325. {{ currentCertificate?.certificateName }}
  326. </div>
  327. <div class="flex center gap-3">
  328. <div class="w-3.5 h-[1.5px] bg-white"></div>
  329. <div class="text-center text-white text-sm font-normal font-['PingFang_SC'] uppercase">
  330. <!-- 2024年10月2日获得-->
  331. {{ dayjs(currentCertificate?.createTime).format('YYYY年MM月DD日') }}获得
  332. </div>
  333. <div class="w-3.5 h-[1.5px] bg-white"></div>
  334. </div>
  335. </div>
  336. <wd-button custom-class="bg-[#0CBE7D]!" @click="save(currentCertificate?.certificateImage)">
  337. 保存到本地
  338. </wd-button>
  339. </div>
  340. </wd-overlay>
  341. </div>
  342. </template>