158 lines
2.8 KiB
Vue
158 lines
2.8 KiB
Vue
|
<script setup lang="ts">
|
||
|
import { ref, onMounted } from 'vue';
|
||
|
import { majorRanking } from "@/api";
|
||
|
|
||
|
interface RankingItem {
|
||
|
rank: number;
|
||
|
major: string;
|
||
|
count: number;
|
||
|
}
|
||
|
|
||
|
// 排行数据
|
||
|
const rankingData = ref<RankingItem[]>([]);
|
||
|
|
||
|
// 获取排行数据
|
||
|
const fetchRankingData = () => {
|
||
|
majorRanking().then(res => {
|
||
|
if (res.success) {
|
||
|
rankingData.value = res.data;
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
onMounted(() => {
|
||
|
fetchRankingData();
|
||
|
});
|
||
|
</script>
|
||
|
|
||
|
<template>
|
||
|
<div class="major-ranking">
|
||
|
<div class="ranking-list">
|
||
|
<div class="ranking-header">
|
||
|
<div class="header-item rank">排名</div>
|
||
|
<div class="header-item major">专业名称</div>
|
||
|
<div class="header-item count">用户数</div>
|
||
|
</div>
|
||
|
<div class="ranking-body">
|
||
|
<div v-for="(item, index) in rankingData" :key="index" class="ranking-item">
|
||
|
<div class="item-rank" :class="{ 'top-rank': item.rank <= 3 }">
|
||
|
<span class="rank-number">{{ item.rank }}</span>
|
||
|
</div>
|
||
|
<div class="item-major">{{ item.major }}</div>
|
||
|
<div class="item-count">{{ item.count }}人</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<style scoped lang="scss">
|
||
|
.major-ranking {
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
padding: 10px 0;
|
||
|
}
|
||
|
|
||
|
.ranking-list {
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
}
|
||
|
|
||
|
.ranking-header {
|
||
|
display: flex;
|
||
|
padding: 10px 0;
|
||
|
border-bottom: 1px solid #eee;
|
||
|
font-weight: bold;
|
||
|
color: #333;
|
||
|
font-size: 14px;
|
||
|
}
|
||
|
|
||
|
.ranking-body {
|
||
|
flex: 1;
|
||
|
overflow-y: auto;
|
||
|
}
|
||
|
|
||
|
.ranking-item {
|
||
|
display: flex;
|
||
|
padding: 12px 0;
|
||
|
border-bottom: 1px solid #f5f5f5;
|
||
|
|
||
|
&:last-child {
|
||
|
border-bottom: none;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.header-item, .item-rank, .item-major, .item-count {
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
}
|
||
|
|
||
|
.rank {
|
||
|
width: 60px;
|
||
|
justify-content: center;
|
||
|
}
|
||
|
|
||
|
.major {
|
||
|
flex: 1;
|
||
|
}
|
||
|
|
||
|
.count {
|
||
|
width: 80px;
|
||
|
justify-content: flex-end;
|
||
|
}
|
||
|
|
||
|
.item-rank {
|
||
|
width: 60px;
|
||
|
justify-content: center;
|
||
|
|
||
|
.rank-number {
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
justify-content: center;
|
||
|
width: 24px;
|
||
|
height: 24px;
|
||
|
border-radius: 50%;
|
||
|
background-color: #f5f5f5;
|
||
|
font-size: 14px;
|
||
|
color: #666;
|
||
|
}
|
||
|
|
||
|
&.top-rank {
|
||
|
.rank-number {
|
||
|
background-color: #4B96FF;
|
||
|
color: #fff;
|
||
|
}
|
||
|
|
||
|
&:nth-child(1) .rank-number {
|
||
|
background-color: #f5222d;
|
||
|
}
|
||
|
|
||
|
&:nth-child(2) .rank-number {
|
||
|
background-color: #fa8c16;
|
||
|
}
|
||
|
|
||
|
&:nth-child(3) .rank-number {
|
||
|
background-color: #52c41a;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.item-major {
|
||
|
flex: 1;
|
||
|
font-size: 14px;
|
||
|
color: #333;
|
||
|
white-space: nowrap;
|
||
|
overflow: hidden;
|
||
|
text-overflow: ellipsis;
|
||
|
}
|
||
|
|
||
|
.item-count {
|
||
|
width: 80px;
|
||
|
justify-content: flex-end;
|
||
|
font-size: 14px;
|
||
|
color: #4B96FF;
|
||
|
font-weight: bold;
|
||
|
}
|
||
|
</style>
|