Pārlūkot izejas kodu

评测排行榜

skyblued 3 gadi atpakaļ
vecāks
revīzija
18bf4f5a08

+ 9 - 0
src/router/routes-student.ts

@@ -121,6 +121,15 @@ export default [
           title: '曲目评测活动',
           isExternal: true // 是否外部浏览器可以打开
         }
+      },
+      {
+        path: '/leaderboard',
+        component: () =>
+          import('@/student/leaderboard/index'),
+        meta: {
+          title: '曲目挑战排行榜',
+          // isExternal: true // 是否外部浏览器可以打开
+        }
       }
     ]
   },

BIN
src/student/leaderboard/image/icon-emtry.png


BIN
src/student/leaderboard/image/icon-trophy.png


+ 125 - 0
src/student/leaderboard/index.module.less

@@ -0,0 +1,125 @@
+.headImg {
+  display: flex;
+}
+.tabs {
+  margin-top: -42px;
+  :global {
+    .van-tabs__wrap {
+      height: 42px;
+    }
+    .van-tabs__nav {
+      background-color: rgba(0, 0, 0, 0.68);
+      backdrop-filter: blur(10px);
+      -webkit-backdrop-filter: blur(10px);
+    }
+    .van-tabs__line {
+      background-color: transparent !important;
+      height: 0;
+      width: 0;
+      border: 8px solid transparent;
+      border-bottom-color: #fff;
+      border-radius: 0;
+    }
+    .van-empty__image {
+      width: 100px;
+      height: 114px;
+    }
+  }
+}
+.tabContent {
+  position: relative;
+  padding: 12px;
+  box-sizing: border-box;
+  overflow-y: auto;
+  padding-bottom: 80px;
+}
+.itemContent {
+  padding: 12px;
+  border-radius: 12px;
+  background-color: #fff;
+}
+.item {
+  display: flex;
+  padding: 10px 0;
+  box-sizing: border-box;
+  align-items: center;
+  .left {
+    width: 32px;
+    margin: 0 21px 0 2px;
+    text-align: center;
+  }
+  .center {
+    display: flex;
+  }
+  .right {
+    margin-left: auto;
+    text-align: right;
+    .fraction {
+      font-size: 14px;
+      font-weight: 600;
+      color: #fa6400;
+    }
+    .time {
+      font-size: 12px;
+      color: #999;
+    }
+  }
+  &:first-child {
+    padding-top: 0;
+    border-bottom: 1px solid #eee;
+  }
+  &:last-child {
+    padding-bottom: 0;
+  }
+  .user {
+    margin-left: 6px;
+    .name {
+      font-size: 14px;
+      color: #333;
+      margin-bottom: 2px;
+    }
+    .tag {
+      display: flex;
+      & > span {
+        font-size: 12px;
+        background-color: #ffe2b2;
+        color: #ff8c00;
+        border-radius: 2px;
+        margin-right: 4px;
+        padding: 1px 2px;
+      }
+    }
+  }
+}
+
+.activeUser {
+  --van-cell-line-height: 20px;
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  width: 100%;
+  box-sizing: border-box;
+  box-shadow: 0 -8px 12px #ebedf0;
+  :global {
+    .van-cell__value {
+      flex: initial;
+      margin-left: 8px;
+    }
+  }
+  .avator {
+    width: 48px;
+    height: 48px;
+    margin-right: 12px;
+  }
+  .btn {
+    padding: 4px 10px;
+    border: none;
+    background: linear-gradient(180deg, #ffa200 0%, #ff6900 100%);
+    border-radius: 16px;
+  }
+  .num {
+    font-size: 14px;
+    font-weight: 600px;
+    color: #fa6400;
+  }
+}

+ 250 - 0
src/student/leaderboard/index.tsx

@@ -0,0 +1,250 @@
+import { Button, Cell, Empty, Image, Tab, Tabs } from 'vant'
+import { computed, defineComponent, onMounted, reactive, ref } from 'vue'
+import styles from './index.module.less'
+import IconTrophy from './image/icon-trophy.png'
+import IconEmtry from './image/icon-emtry.png'
+import request from '@/helpers/request'
+import { useRoute, useRouter } from 'vue-router'
+import { state as userInfo } from '@/state'
+
+interface IMusicItem {
+  loaded: boolean
+  musicSheetName: string
+  musicSubject: string
+  musicSheetId: number
+  evaluationId: number
+  rankingList: any
+  [_: string]: any
+}
+
+export default defineComponent({
+  name: 'leaderboard',
+  setup() {
+    const route = useRoute()
+    const router = useRouter()
+    const state = reactive({
+      tabIndex: 0,
+      musicList: [] as IMusicItem[]
+    })
+    const getMusicList = async () => {
+      try {
+        const {
+          data: { activityMusicVoList, shareUrl }
+        } = await request.post(
+          `/api-student/open/activity/info/${route.query.id}`
+        )
+        if (Array.isArray(activityMusicVoList)) {
+          state.musicList = activityMusicVoList.map(n => {
+            n.rankingList = []
+            n.loaded = false
+            return n
+          })
+        }
+        img.value = shareUrl
+      } catch (error) {}
+    }
+    const getData = async () => {
+      if (state.musicList[state.tabIndex].loaded) return
+      try {
+        const { data } = await request.get(
+          '/api-student/open/activityEvaluationRecord/queryRankingList',
+          {
+            params: {
+              activityPlanId: route.query.id,
+              activityEvaluationId:
+                state.musicList[state.tabIndex].evaluationId,
+              limit: 10
+            }
+          }
+        )
+        if (Array.isArray(data.rankingList)) {
+          state.musicList[state.tabIndex].rankingList = data.rankingList
+          state.musicList[state.tabIndex].loaded = true
+        }
+      } catch (error) {}
+    }
+    const img = ref()
+    const imgShow = ref(false)
+    const imgHeight = ref(42)
+
+    const openActive = () => {
+      router.back()
+      //   router.replace({
+      //     path: '/track-review-activity',
+      //     query: {
+      //       id: route.query.id
+      //     }
+      //   })
+    }
+
+    onMounted(async () => {
+      await getMusicList()
+      await getData()
+    })
+    const user = computed(() => {
+      if (!state.musicList[state.tabIndex]) return {} as any
+      const userdata = userInfo.user.data
+      if (!userdata.userId) return {} as any
+      const rank = state.musicList[state.tabIndex]
+      const item = rank?.rankingList?.find(n => n.userId == userdata.userId)
+      let step = rank?.rankingList?.findIndex(n => n.userId == userdata.userId)
+      step = step > -1 ? step + 1 : 0
+      return {
+        join: rank.join,
+        score: rank.score,
+        isTop: item ? true : false,
+        heardUrl: userdata.heardUrl,
+        username: userdata.username,
+        userId: userdata.userId,
+        step
+      }
+    })
+    return () => (
+      <div class={styles.leaderboard}>
+        <div class={styles.container}>
+          <div class={styles.headImg}>
+            <Image
+              width="100%"
+              fit="cover"
+              src={img.value}
+              onLoad={img => {
+                imgHeight.value = img.target.height
+                imgShow.value = true
+              }}
+            />
+          </div>
+          {imgShow.value && (
+            <Tabs
+              v-model:active={state.tabIndex}
+              class={styles.tabs}
+              animated
+              swipeable
+              titleInactiveColor="#fff"
+              titleActiveColor="rgba(224,146,144,1)"
+              onChange={index => getData()}
+            >
+              {state.musicList.map((item: IMusicItem) => {
+                return (
+                  <Tab title={item.musicSheetName}>
+                    <div
+                      class={styles.tabContent}
+                      style={{ height: `calc(100vh - ${imgHeight.value}px)` }}
+                    >
+                      <div class={styles.itemContent}>
+                        <div class={styles.item}>
+                          <div class={styles.left}>排名</div>
+                          <div class={styles.center}>昵称</div>
+                          <div class={styles.right}>评分</div>
+                        </div>
+
+                        {item.rankingList.map((n: any, index: number) => {
+                          const t = (index + 1).toString().padStart(2, '0')
+                          const time = (n.joinDate + '').split(' ')[0]
+                          return (
+                            <div class={styles.item}>
+                              <div class={styles.left}>
+                                {index == 0 ? <Image src={IconTrophy} /> : t}
+                              </div>
+                              <div class={styles.center}>
+                                <Image
+                                  width="34px"
+                                  height="34px"
+                                  fit="cover"
+                                  round
+                                  src={n.userAvatar}
+                                />
+                                <div class={styles.user}>
+                                  <div class={styles.name}>{n.username}</div>
+                                  <div class={styles.tag}>
+                                    <span>{n.userSubject}</span>
+                                  </div>
+                                </div>
+                              </div>
+                              <div class={styles.right}>
+                                <div class={styles.fraction}>{n.score}分</div>
+                                <div class={styles.time}>{time}</div>
+                              </div>
+                            </div>
+                          )
+                        })}
+
+                        {!item.rankingList.length && (
+                          <Empty
+                            image={IconEmtry}
+                            description="该曲目暂无排名喔~"
+                          />
+                        )}
+                      </div>
+                    </div>
+                  </Tab>
+                )
+              })}
+            </Tabs>
+          )}
+          {user.value.userId && (
+            <div class={styles.activeUser}>
+              <Cell
+                center
+                title={user.value.username}
+                v-slots={{
+                  icon: () => (
+                    <Image
+                      class={styles.avator}
+                      fit="cover"
+                      round
+                      src={user.value.heardUrl}
+                    />
+                  ),
+                  label: () => {
+                    if (user.value.join) {
+                      if (user.value.isTop) {
+                        return (
+                          <div>
+                            您的评测已上榜! 当前排名
+                            <span style={{ color: '#FA6400' }}>
+                              {' '}
+                              {user.value.step}
+                            </span>
+                          </div>
+                        )
+                      } else {
+                        return (
+                          <div>
+                            您的评测暂未上榜,快去
+                            <span style={{ color: '#FA6400' }}>挑战</span>
+                            吧!
+                          </div>
+                        )
+                      }
+                    } else {
+                      return <div>您尚未报名参赛</div>
+                    }
+                  },
+                  value: () => {
+                    if (user.value.join) {
+                      return (
+                        <span class={styles.num}>{user.value.score}分</span>
+                      )
+                    } else {
+                      return (
+                        <Button
+                          class={styles.btn}
+                          round
+                          size="small"
+                          type="primary"
+                          onClick={() => openActive()}
+                        >
+                          立刻挑战
+                        </Button>
+                      )
+                    }
+                  }
+                }}
+              />
+            </div>
+          )}
+        </div>
+      </div>
+    )
+  }
+})

BIN
src/student/share-active/track-review-activity/images/icon-lv.png


+ 3 - 3
src/student/share-active/track-review-activity/index.tsx

@@ -319,9 +319,9 @@ export default defineComponent({
                 活动曲目
               </span>
 
-              <span class={styles.titleTips}>
-                共{this.activityMusic.length || 0}
-                首曲目
+              <span class={styles.titleTips} onClick={() => this.$router.push({path: '/leaderboard', query:{id: this.id}})}>
+                查看挑战排行榜
+                <img style={{width: '16px', marginLeft: '4px'}} src={getAssetsHomeFile('icon-lv.png')} />
               </span>
             </h2>
 

+ 3 - 0
src/student/teacher-dependent/teacher-home.module.less

@@ -5,6 +5,9 @@
   overflow: hidden;
 
   :global {
+    .van-nav-bar{
+      transition: all .3s;
+    }
     .van-tab {
       margin-top: 12px;
       margin-bottom: 5px;

+ 12 - 8
src/student/teacher-dependent/teacher-home.tsx

@@ -30,7 +30,9 @@ export default defineComponent({
       tabs: tabs || query.tabs || 'single',
       userInfo: {} as any,
       background: 'rgba(55, 205, 177, 0)',
-      height: 'auto' as any
+      headColor: '#fff',
+      height: 'auto' as any,
+
     }
   },
   async created() {},
@@ -42,12 +44,14 @@ export default defineComponent({
     })
     useEventListener(document, 'scroll', evt => {
       const { y } = useWindowScroll()
-      this.background = `rgba(55, 205, 177, ${y.value / 100})`
-      // if (y.value > 45) {
-      //   this.background = '#37cdb1'
-      // } else {
-      //   this.background = 'transparent'
-      // }
+      // this.background = `rgba(255, 255, 255, ${y.value / 100})`
+      if (y.value > 50) {
+        this.headColor = '#000'
+        this.background = '#fff'
+      } else {
+        this.background = 'transparent'
+        this.headColor = '#fff'
+      }
     })
   },
   methods: {
@@ -69,7 +73,7 @@ export default defineComponent({
           <ColHeader
             background={this.background}
             border={false}
-            color="#fff"
+            color={this.headColor}
             backIconColor="white"
             onHeaderBack={() => {
               this.$nextTick(() => {