feat: 完成排行榜功能

This commit is contained in:
ccnetcore
2026-02-01 19:32:46 +08:00
parent 6d54c650f0
commit 33937703c7
17 changed files with 2039 additions and 24 deletions

View File

@@ -0,0 +1,15 @@
import type { RankingGetListInput, RankingItemDto } from './types';
import { get } from '@/utils/request';
// 获取排行榜列表(公开接口,无需登录)
export function getRankingList(params?: RankingGetListInput) {
const queryParams = new URLSearchParams();
if (params?.type !== undefined) {
queryParams.append('Type', params.type.toString());
}
const queryString = queryParams.toString();
const url = queryString ? `/ranking/list?${queryString}` : '/ranking/list';
return get<RankingItemDto[]>(url).json();
}

View File

@@ -0,0 +1,21 @@
// 排行榜类型枚举
export enum RankingTypeEnum {
Model = 0,
Tool = 1,
}
// 排行榜项
export interface RankingItemDto {
id: string;
name: string;
description: string;
logoUrl?: string;
score: number;
provider: string;
type: RankingTypeEnum;
}
// 排行榜查询参数
export interface RankingGetListInput {
type?: RankingTypeEnum;
}

View File

@@ -1,11 +1,5 @@
<script setup lang="ts">
import { useRouter } from 'vue-router';
const router = useRouter();
function goToModelLibrary() {
router.push('/model-library');
}
// 这是一个纯展示组件,点击事件由父组件 el-menu-item 处理
</script>
<template>
@@ -13,7 +7,6 @@ function goToModelLibrary() {
<div
class="model-library-btn"
title="查看模型库"
@click="goToModelLibrary"
>
<!-- PC端显示文字 -->
<span class="pc-text">模型库</span>

View File

@@ -0,0 +1,83 @@
<script setup lang="ts">
// 这是一个纯展示组件,点击事件由父组件 el-menu-item 处理
</script>
<template>
<div class="ranking-btn-container" data-tour="ranking-btn">
<div
class="ranking-btn"
title="查看排行榜"
>
<!-- PC端显示文字 -->
<span class="pc-text">排行榜</span>
<!-- 移动端显示图标 -->
<svg
class="mobile-icon"
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6" />
<path d="M18 9h1.5a2.5 2.5 0 0 0 0-5H18" />
<path d="M4 22h16" />
<path d="M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22" />
<path d="M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22" />
<path d="M18 2H6v7a6 6 0 0 0 12 0V2Z" />
</svg>
</div>
</div>
</template>
<style scoped lang="scss">
.ranking-btn-container {
display: flex;
align-items: center;
.ranking-btn {
display: flex;
align-items: center;
gap: 6px;
cursor: pointer;
font-size: 1.2rem;
font-weight: bold;
color: #606266;
transition: all 0.2s;
&:hover {
color: #606266;
transform: translateY(-1px);
}
// PC端显示文字隐藏图标
.pc-text {
display: inline;
margin: 0 12px;
}
.mobile-icon {
display: none;
}
}
}
// 移动端显示图标,隐藏文字
@media (max-width: 768px) {
.ranking-btn-container {
.ranking-btn {
.pc-text {
display: none;
}
.mobile-icon {
display: inline;
}
}
}
}
</style>

View File

@@ -12,7 +12,6 @@ import Avatar from './components/Avatar.vue';
import BuyBtn from './components/BuyBtn.vue';
import ContactUsBtn from './components/ContactUsBtn.vue';
import LoginBtn from './components/LoginBtn.vue';
import ModelLibraryBtn from './components/ModelLibraryBtn.vue';
import ThemeBtn from './components/ThemeBtn.vue';
const router = useRouter();
@@ -42,7 +41,7 @@ const mobileMenuVisible = ref(false);
const activeIndex = computed(() => {
if (route.path.startsWith('/console'))
return 'console';
if (route.path.startsWith('/model-library'))
if (route.path.startsWith('/model-library') || route.path.startsWith('/ranking'))
return 'model-library';
if (route.path.includes('/chat/'))
return 'chat';
@@ -71,6 +70,19 @@ function handleConsoleClick(e: MouseEvent) {
mobileMenuVisible.value = false;
}
// 修改模型库菜单的点击事件
function handleModelLibraryClick(e: MouseEvent) {
e.stopPropagation(); // 阻止事件冒泡
router.push('/model-library');
mobileMenuVisible.value = false;
}
// 跳转到模型监控外部链接
function goToModelMonitor() {
window.open('http://data.ccnetcore.com:91/?period=24h', '_blank');
mobileMenuVisible.value = false;
}
// 切换移动端菜单
function toggleMobileMenu() {
mobileMenuVisible.value = !mobileMenuVisible.value;
@@ -122,10 +134,18 @@ function toggleMobileMenu() {
<AnnouncementBtn :is-menu-item="true" />
</el-menu-item>
<!-- 模型库 -->
<el-menu-item index="/model-library" class="custom-menu-item">
<ModelLibraryBtn :is-menu-item="true" />
</el-menu-item>
<!-- 模型库下拉菜单 -->
<el-sub-menu index="model-library" class="model-library-submenu" popper-class="custom-popover">
<template #title>
<span class="menu-title" @click="handleModelLibraryClick">模型库</span>
</template>
<el-menu-item index="/ranking">
模型排行榜
</el-menu-item>
<el-menu-item index="no-route" @click="goToModelMonitor">
模型监控
</el-menu-item>
</el-sub-menu>
<!-- AI教程 -->
<el-menu-item class="custom-menu-item" index="no-route">
@@ -254,11 +274,19 @@ function toggleMobileMenu() {
</el-menu-item>
</el-sub-menu>
<!-- 模型库 -->
<el-menu-item index="/model-library">
<el-icon><Box /></el-icon>
<span>模型库</span>
</el-menu-item>
<!-- 模型库下拉菜单 -->
<el-sub-menu index="model-library">
<template #title>
<el-icon><Box /></el-icon>
<span>模型库</span>
</template>
<el-menu-item index="/ranking">
模型排行榜
</el-menu-item>
<el-menu-item index="no-route" @click="goToModelMonitor">
模型监控
</el-menu-item>
</el-sub-menu>
<!-- 控制台 -->
<el-sub-menu index="console">
@@ -412,9 +440,10 @@ function toggleMobileMenu() {
}
}
// 聊天和控制台子菜单
// 聊天、模型库和控制台子菜单
.chat-submenu,
.console-submenu {
.console-submenu,
.model-library-submenu {
:deep(.el-sub-menu__title) {
display: flex;
align-items: center;
@@ -674,4 +703,7 @@ function toggleMobileMenu() {
}
}
}
.el-sub-menu .el-sub-menu__icon-arrow{
margin-right: -20px;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -106,6 +106,19 @@ export const layoutRouter: RouteRecordRaw[] = [
},
},
// 排行榜
{
path: 'ranking',
name: 'ranking',
component: () => import('@/pages/ranking/index.vue'),
meta: {
title: '意心Ai全球大模型实时排行榜编程',
keepAlive: 0,
isDefaultChat: false,
layout: 'default',
},
},
// 支付结果
{
path: 'pay-result',