index.tsx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import { Button, Cell, Empty, Image, Tab, Tabs } from 'vant'
  2. import { computed, defineComponent, onMounted, reactive, ref } from 'vue'
  3. import styles from './index.module.less'
  4. import IconTrophy from './image/icon-trophy.png'
  5. import IconEmtry from './image/icon-emtry.png'
  6. import request from '@/helpers/request'
  7. import { useRoute, useRouter } from 'vue-router'
  8. import { state as userInfo } from '@/state'
  9. interface IMusicItem {
  10. loaded: boolean
  11. musicSheetName: string
  12. musicSubject: string
  13. musicSheetId: number
  14. evaluationId: number
  15. rankingList: any
  16. [_: string]: any
  17. }
  18. export default defineComponent({
  19. name: 'leaderboard',
  20. setup() {
  21. const route = useRoute()
  22. const router = useRouter()
  23. const state = reactive({
  24. tabIndex: 0,
  25. musicList: [] as IMusicItem[]
  26. })
  27. const getMusicList = async () => {
  28. try {
  29. const {
  30. data: { activityMusicVoList, shareUrl }
  31. } = await request.post(
  32. `/api-student/open/activity/info/${route.query.id}`
  33. )
  34. if (Array.isArray(activityMusicVoList)) {
  35. state.musicList = activityMusicVoList.map(n => {
  36. n.rankingList = []
  37. n.loaded = false
  38. return n
  39. })
  40. }
  41. img.value = shareUrl
  42. } catch (error) {}
  43. }
  44. const getData = async () => {
  45. if (state.musicList[state.tabIndex].loaded) return
  46. try {
  47. const { data } = await request.get(
  48. '/api-student/open/activityEvaluationRecord/queryRankingList',
  49. {
  50. params: {
  51. activityPlanId: route.query.id,
  52. activityEvaluationId:
  53. state.musicList[state.tabIndex].evaluationId,
  54. limit: 10
  55. }
  56. }
  57. )
  58. if (Array.isArray(data.rankingList)) {
  59. state.musicList[state.tabIndex].rankingList = data.rankingList
  60. state.musicList[state.tabIndex].loaded = true
  61. }
  62. } catch (error) {}
  63. }
  64. const img = ref()
  65. const imgShow = ref(false)
  66. const imgHeight = ref(42)
  67. const openActive = () => {
  68. router.back()
  69. // router.replace({
  70. // path: '/track-review-activity',
  71. // query: {
  72. // id: route.query.id
  73. // }
  74. // })
  75. }
  76. onMounted(async () => {
  77. await getMusicList()
  78. await getData()
  79. })
  80. const user = computed(() => {
  81. if (!state.musicList[state.tabIndex]) return {} as any
  82. const userdata = userInfo.user.data
  83. if (!userdata.userId) return {} as any
  84. const rank = state.musicList[state.tabIndex]
  85. const item = rank?.rankingList?.find(n => n.userId == userdata.userId)
  86. let step = rank?.rankingList?.findIndex(n => n.userId == userdata.userId)
  87. step = step > -1 ? step + 1 : 0
  88. return {
  89. join: rank.join,
  90. score: rank.score,
  91. isTop: item ? true : false,
  92. heardUrl: userdata.heardUrl,
  93. username: userdata.username,
  94. userId: userdata.userId,
  95. step
  96. }
  97. })
  98. return () => (
  99. <div class={styles.leaderboard}>
  100. <div class={styles.container}>
  101. <div class={styles.headImg}>
  102. <Image
  103. width="100%"
  104. fit="cover"
  105. src={img.value}
  106. onLoad={img => {
  107. imgHeight.value = img.target.height
  108. imgShow.value = true
  109. }}
  110. />
  111. </div>
  112. {imgShow.value && (
  113. <Tabs
  114. v-model:active={state.tabIndex}
  115. class={styles.tabs}
  116. animated
  117. swipeable
  118. titleInactiveColor="#fff"
  119. titleActiveColor="rgba(224,146,144,1)"
  120. onChange={index => getData()}
  121. >
  122. {state.musicList.map((item: IMusicItem) => {
  123. return (
  124. <Tab title={item.musicSheetName}>
  125. <div
  126. class={styles.tabContent}
  127. style={{ height: `calc(100vh - ${imgHeight.value}px)` }}
  128. >
  129. <div class={styles.itemContent}>
  130. <div class={styles.item}>
  131. <div class={styles.left}>排名</div>
  132. <div class={styles.center}>昵称</div>
  133. <div class={styles.right}>评分</div>
  134. </div>
  135. {item.rankingList.map((n: any, index: number) => {
  136. const t = (index + 1).toString().padStart(2, '0')
  137. const time = (n.joinDate + '').split(' ')[0]
  138. return (
  139. <div class={styles.item}>
  140. <div class={styles.left}>
  141. {index == 0 ? <Image src={IconTrophy} /> : t}
  142. </div>
  143. <div class={styles.center}>
  144. <Image
  145. width="34px"
  146. height="34px"
  147. fit="cover"
  148. round
  149. src={n.userAvatar}
  150. />
  151. <div class={styles.user}>
  152. <div class={styles.name}>{n.username}</div>
  153. <div class={styles.tag}>
  154. <span>{n.userSubject}</span>
  155. </div>
  156. </div>
  157. </div>
  158. <div class={styles.right}>
  159. <div class={styles.fraction}>{n.score}分</div>
  160. <div class={styles.time}>{time}</div>
  161. </div>
  162. </div>
  163. )
  164. })}
  165. {!item.rankingList.length && (
  166. <Empty
  167. image={IconEmtry}
  168. description="该曲目暂无排名喔~"
  169. />
  170. )}
  171. </div>
  172. </div>
  173. </Tab>
  174. )
  175. })}
  176. </Tabs>
  177. )}
  178. {user.value.userId && (
  179. <div class={styles.activeUser}>
  180. <Cell
  181. center
  182. title={user.value.username}
  183. v-slots={{
  184. icon: () => (
  185. <Image
  186. class={styles.avator}
  187. fit="cover"
  188. round
  189. src={user.value.heardUrl}
  190. />
  191. ),
  192. label: () => {
  193. if (user.value.join) {
  194. if (user.value.isTop) {
  195. return (
  196. <div>
  197. 您的评测已上榜! 当前排名
  198. <span style={{ color: '#FA6400' }}>
  199. {' '}
  200. {user.value.step}
  201. </span>
  202. </div>
  203. )
  204. } else {
  205. return (
  206. <div>
  207. 您的评测暂未上榜,快去
  208. <span style={{ color: '#FA6400' }}>挑战</span>
  209. 吧!
  210. </div>
  211. )
  212. }
  213. } else {
  214. return <div>您尚未报名参赛</div>
  215. }
  216. },
  217. value: () => {
  218. if (user.value.join) {
  219. return (
  220. <span class={styles.num}>{user.value.score}分</span>
  221. )
  222. } else {
  223. return (
  224. <Button
  225. class={styles.btn}
  226. round
  227. size="small"
  228. type="primary"
  229. onClick={() => openActive()}
  230. >
  231. 去挑战
  232. </Button>
  233. )
  234. }
  235. }
  236. }}
  237. />
  238. </div>
  239. )}
  240. </div>
  241. </div>
  242. )
  243. }
  244. })