index.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. import { Button, Cell, Empty, Image, Tab, Tabs } from 'vant'
  2. import {
  3. computed,
  4. defineComponent,
  5. nextTick,
  6. onMounted,
  7. reactive,
  8. ref
  9. } from 'vue'
  10. import styles from './index.module.less'
  11. import IconTrophy from './image/icon-trophy.png'
  12. import IconLevel from '../share-active/track-review-activity/images/icon_level.png'
  13. import IconLevel2 from '../share-active/track-review-activity/images/icon_level2.png'
  14. import IconLevel3 from '../share-active/track-review-activity/images/icon_level3.png'
  15. import IconEmtry from './image/icon-emtry.png'
  16. import IconAvator from '@/common/images/icon_teacher.png'
  17. import request from '@/helpers/request'
  18. import { useRoute, useRouter } from 'vue-router'
  19. import { state as userInfo } from '@/state'
  20. import { useRect } from '@vant/use'
  21. interface IMusicItem {
  22. loaded: boolean
  23. musicSheetName: string
  24. musicSubject: string
  25. musicSheetId: number
  26. evaluationId: number
  27. rankingList: any
  28. [_: string]: any
  29. }
  30. export default defineComponent({
  31. name: 'leaderboard',
  32. setup() {
  33. const route = useRoute()
  34. const router = useRouter()
  35. const state = reactive({
  36. tabIndex: 0,
  37. musicList: [] as IMusicItem[],
  38. isSignup: false, // 是否报名
  39. isChallenge: false, // 是否挑战过
  40. score: 0
  41. })
  42. const getMusicList = async () => {
  43. try {
  44. const { data } = await request.post(
  45. `/api-student/open/activity/info/${route.query.id}`
  46. )
  47. if (Array.isArray(data.activityMusicVoList)) {
  48. state.musicList = data.activityMusicVoList.map(n => {
  49. n.rankingList = []
  50. return n
  51. })
  52. state.isChallenge = data.activityMusicVoList.filter(n => n.join)
  53. .length
  54. ? true
  55. : false
  56. }
  57. img.value = data.subjectUrl
  58. state.isSignup = data.join ? true : false
  59. } catch (error) {}
  60. }
  61. const getData = async () => {
  62. try {
  63. const { data } = await request.get(
  64. '/api-student/open/activityEvaluationRecord/queryRankingList',
  65. {
  66. params: {
  67. activityPlanId: route.query.id,
  68. activityEvaluationId:
  69. state.musicList[state.tabIndex].evaluationId,
  70. limit: 10
  71. }
  72. }
  73. )
  74. if (Array.isArray(data.rankingList)) {
  75. state.musicList[state.tabIndex].rankingList = data.rankingList
  76. }
  77. if (data.userActivityRankingVo) {
  78. state.score = data.userActivityRankingVo.score
  79. }
  80. } catch (error) {}
  81. }
  82. const img = ref()
  83. const imgShow = ref(false)
  84. const imgHeight = ref(100)
  85. const openActive = () => {
  86. router.back()
  87. // router.replace({
  88. // path: '/track-review-activity',
  89. // query: {
  90. // id: route.query.id
  91. // }
  92. // })
  93. }
  94. onMounted(async () => {
  95. await getMusicList()
  96. await getData()
  97. })
  98. const user = computed(() => {
  99. if (!state.musicList[state.tabIndex]) return {} as any
  100. const userdata = userInfo.user.data
  101. if (!userdata.userId) return {} as any
  102. const rank = state.musicList[state.tabIndex]
  103. const item = rank?.rankingList?.find(n => n.userId == userdata.userId)
  104. let step = rank?.rankingList?.findIndex(n => n.userId == userdata.userId)
  105. step = step > -1 ? step + 1 : 0
  106. return {
  107. join: rank.join,
  108. score: item?.score || 0,
  109. isTop: item ? true : false,
  110. heardUrl: userdata.heardUrl,
  111. username: userdata.username,
  112. userId: userdata.userId,
  113. step
  114. }
  115. })
  116. const imgRef = ref()
  117. const userRef = ref()
  118. return () => (
  119. <div class={styles.leaderboard}>
  120. <div class={styles.container}>
  121. <div class={styles.headImg} ref={imgRef}>
  122. <Image
  123. width="100%"
  124. fit="cover"
  125. src={img.value}
  126. onLoad={img => {
  127. nextTick(() => {
  128. const { height } = useRect(imgRef)
  129. imgShow.value = true
  130. imgHeight.value = height || 100
  131. })
  132. }}
  133. onError={err => {
  134. console.log(err)
  135. }}
  136. />
  137. </div>
  138. {imgShow.value && (
  139. <Tabs
  140. v-model:active={state.tabIndex}
  141. class={styles.tabs}
  142. animated
  143. swipeable
  144. titleInactiveColor="rgba(153,152,155,1)"
  145. titleActiveColor="#fff"
  146. onChange={index => getData()}
  147. >
  148. {state.musicList.map((item: IMusicItem) => {
  149. return (
  150. <Tab title={item.musicSheetName}>
  151. <div
  152. class={[
  153. styles.tabContent,
  154. user.value.userId &&
  155. (!state.isSignup ||
  156. !state.isChallenge ||
  157. user.value.join)
  158. ? styles.hasUser
  159. : null
  160. ]}
  161. style={{ height: `calc(100vh - ${imgHeight.value}px)` }}
  162. >
  163. <div class={styles.itemContent}>
  164. <div class={styles.item}>
  165. <div class={styles.left}>排名</div>
  166. <div class={styles.center}>昵称</div>
  167. <div class={styles.right}>评分</div>
  168. </div>
  169. {item.rankingList.map((n: any, index: number) => {
  170. const t = (index + 1).toString().padStart(2, '0')
  171. return (
  172. <div class={styles.item}>
  173. <div class={styles.left}>
  174. {index == 0 && <Image src={IconLevel} />}
  175. {index == 1 && <Image src={IconLevel2} />}
  176. {index == 2 && <Image src={IconLevel3} />}
  177. {index != 0 && index != 1 && index != 2 && t}
  178. </div>
  179. <div class={styles.center}>
  180. <Image
  181. width="38px"
  182. height="38px"
  183. fit="cover"
  184. round
  185. src={n.userAvatar || IconAvator}
  186. />
  187. <div class={styles.user}>
  188. <div class={styles.userContent}>
  189. <span class={styles.name}>
  190. {n.username}
  191. </span>
  192. <span class={styles.tag}>
  193. {n.userSubject}
  194. </span>
  195. </div>
  196. <div class={styles.times}>{n.joinDate}</div>
  197. </div>
  198. </div>
  199. <div class={styles.right}>
  200. <div class={styles.fraction}>{n.score}分</div>
  201. <div class={styles.time}>
  202. 第 {n.times} 次评测
  203. </div>
  204. </div>
  205. </div>
  206. )
  207. })}
  208. {!item.rankingList.length && (
  209. <Empty
  210. image={IconEmtry}
  211. description="该曲目暂无排名喔~"
  212. />
  213. )}
  214. </div>
  215. <div class="van-safe-area-bottom"></div>
  216. </div>
  217. </Tab>
  218. )
  219. })}
  220. </Tabs>
  221. )}
  222. {user.value.userId &&
  223. (!state.isSignup ? (
  224. <div
  225. ref={userRef}
  226. class={[styles.activeUser, 'van-safe-area-bottom']}
  227. >
  228. <Cell
  229. center
  230. title={user.value.username}
  231. label="您尚未报名参赛"
  232. v-slots={{
  233. icon: () => (
  234. <Image
  235. class={styles.avator}
  236. fit="cover"
  237. round
  238. src={user.value.heardUrl || IconAvator}
  239. />
  240. )
  241. }}
  242. />
  243. </div>
  244. ) : !state.isChallenge ? (
  245. <div
  246. ref={userRef}
  247. class={[styles.activeUser, 'van-safe-area-bottom']}
  248. >
  249. <Cell
  250. center
  251. title={user.value.username}
  252. label="您尚未评测哦!"
  253. v-slots={{
  254. icon: () => (
  255. <Image
  256. class={styles.avator}
  257. fit="cover"
  258. round
  259. src={user.value.heardUrl || IconAvator}
  260. />
  261. )
  262. }}
  263. />
  264. </div>
  265. ) : user.value.join ? (
  266. <div
  267. ref={userRef}
  268. class={[styles.activeUser, 'van-safe-area-bottom']}
  269. >
  270. <Cell
  271. center
  272. title={user.value.username}
  273. v-slots={{
  274. icon: () => (
  275. <Image
  276. class={styles.avator}
  277. fit="cover"
  278. round
  279. src={user.value.heardUrl || IconAvator}
  280. />
  281. ),
  282. label: () => {
  283. if (user.value.isTop) {
  284. return (
  285. <div>
  286. 您的评测已上榜! 当前排名
  287. <span style={{ color: '#FA6400' }}>
  288. {' '}
  289. {user.value.step}
  290. </span>
  291. </div>
  292. )
  293. } else {
  294. return <div>您的评测暂未上榜,快去挑战吧!</div>
  295. }
  296. },
  297. value: () => {
  298. if (!user.value.score && !state.score) {
  299. return
  300. }
  301. return (
  302. <span class={styles.num}>
  303. {user.value.score || state.score}分
  304. </span>
  305. )
  306. }
  307. }}
  308. />
  309. </div>
  310. ) : null)}
  311. </div>
  312. </div>
  313. )
  314. }
  315. })