feat: 完成排行榜功能
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||
|
||||
/// <summary>
|
||||
/// 排行榜查询输入
|
||||
/// </summary>
|
||||
public class RankingGetListInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 排行榜类型:0-模型,1-工具,不传返回全部
|
||||
/// </summary>
|
||||
public RankingTypeEnum? Type { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||
|
||||
/// <summary>
|
||||
/// 排行榜项DTO
|
||||
/// </summary>
|
||||
public class RankingItemDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Logo地址
|
||||
/// </summary>
|
||||
public string? LogoUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 得分
|
||||
/// </summary>
|
||||
public decimal Score { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提供者
|
||||
/// </summary>
|
||||
public string Provider { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 排行榜类型
|
||||
/// </summary>
|
||||
public RankingTypeEnum Type { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.IServices;
|
||||
|
||||
/// <summary>
|
||||
/// 排行榜服务接口
|
||||
/// </summary>
|
||||
public interface IRankingService
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取排行榜列表(全量返回)
|
||||
/// </summary>
|
||||
/// <param name="input">查询条件</param>
|
||||
/// <returns>排行榜列表</returns>
|
||||
Task<List<RankingItemDto>> GetListAsync(RankingGetListInput input);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Mapster;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||
using Yi.Framework.AiHub.Application.Contracts.IServices;
|
||||
using Yi.Framework.AiHub.Domain.Entities;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 排行榜服务
|
||||
/// </summary>
|
||||
public class RankingService : ApplicationService, IRankingService
|
||||
{
|
||||
private readonly ISqlSugarRepository<RankingItemAggregateRoot, Guid> _repository;
|
||||
|
||||
public RankingService(ISqlSugarRepository<RankingItemAggregateRoot, Guid> repository)
|
||||
{
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取排行榜列表(全量返回,按得分降序)
|
||||
/// </summary>
|
||||
[HttpGet("ranking/list")]
|
||||
[AllowAnonymous]
|
||||
public async Task<List<RankingItemDto>> GetListAsync([FromQuery] RankingGetListInput input)
|
||||
{
|
||||
var query = _repository._DbQueryable
|
||||
.WhereIF(input.Type.HasValue, x => x.Type == input.Type!.Value)
|
||||
.OrderByDescending(x => x.Score);
|
||||
|
||||
var entities = await query.ToListAsync();
|
||||
return entities.Adapt<List<RankingItemDto>>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// 排行榜类型枚举
|
||||
/// </summary>
|
||||
public enum RankingTypeEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 模型
|
||||
/// </summary>
|
||||
Model = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 工具
|
||||
/// </summary>
|
||||
Tool = 1
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using SqlSugar;
|
||||
using Volo.Abp.Domain.Entities.Auditing;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 排行榜项聚合根
|
||||
/// </summary>
|
||||
[SugarTable("Ai_RankingItem")]
|
||||
public class RankingItemAggregateRoot : FullAuditedAggregateRoot<Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Logo地址
|
||||
/// </summary>
|
||||
public string? LogoUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 得分
|
||||
/// </summary>
|
||||
public decimal Score { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提供者
|
||||
/// </summary>
|
||||
public string? Provider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排行榜类型:0-模型,1-工具
|
||||
/// </summary>
|
||||
public RankingTypeEnum Type { get; set; }
|
||||
}
|
||||
@@ -361,7 +361,7 @@ namespace Yi.Abp.Web
|
||||
var app = context.GetApplicationBuilder();
|
||||
app.UseRouting();
|
||||
|
||||
//app.ApplicationServices.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient.CodeFirst.InitTables<SessionAggregateRoot>();
|
||||
// app.ApplicationServices.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient.CodeFirst.InitTables<RankingItemAggregateRoot>();
|
||||
// app.ApplicationServices.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient.CodeFirst.InitTables<ActivationCodeRecordAggregateRoot>();
|
||||
// app.ApplicationServices.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient.CodeFirst.InitTables<UsageStatisticsAggregateRoot>();
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
"Bash(timeout /t 5 /nobreak)",
|
||||
"Bash(git checkout:*)",
|
||||
"Bash(npm install marked --save)",
|
||||
"Bash(pnpm add marked)"
|
||||
"Bash(pnpm add marked)",
|
||||
"Bash(pnpm lint:*)",
|
||||
"Bash(pnpm list:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
||||
367
Yi.Ai.Vue3/CLAUDE.md
Normal file
367
Yi.Ai.Vue3/CLAUDE.md
Normal file
@@ -0,0 +1,367 @@
|
||||
# CLAUDE.md
|
||||
|
||||
本文件为 Claude Code (claude.ai/code) 提供本项目代码开发指导。
|
||||
|
||||
## 项目简介
|
||||
|
||||
**意心AI** - 基于 Vue 3.5 + TypeScript 开发的企业级 AI 聊天应用模板,仿豆包/通义 AI 平台。支持流式对话、AI 模型库、文件上传、Mermaid 图表渲染等功能。
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **框架**: Vue 3.5+ (Composition API) + TypeScript 5.8+
|
||||
- **构建工具**: Vite 6.3+
|
||||
- **UI 组件**: Element Plus 2.10.4 + vue-element-plus-x 1.3.7
|
||||
- **状态管理**: Pinia 3.0 + pinia-plugin-persistedstate
|
||||
- **HTTP 请求**: hook-fetch(支持流式/SSE,替代 Axios)
|
||||
- **CSS**: UnoCSS + SCSS
|
||||
- **路由**: Vue Router 4
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
# 安装依赖(必须用 pnpm)
|
||||
pnpm install
|
||||
|
||||
# 启动开发服务器(端口 17001)
|
||||
pnpm dev
|
||||
|
||||
# 生产构建
|
||||
pnpm build
|
||||
|
||||
# 预览生产构建
|
||||
pnpm preview
|
||||
|
||||
# 代码检查与修复
|
||||
pnpm lint # ESLint 检查
|
||||
pnpm fix # ESLint 自动修复
|
||||
pnpm lint:stylelint # 样式检查
|
||||
|
||||
# 规范提交(使用 cz-git)
|
||||
pnpm cz
|
||||
```
|
||||
|
||||
## 如何新增页面
|
||||
|
||||
### 1. 创建页面文件
|
||||
|
||||
页面文件统一放在 `src/pages/` 目录下:
|
||||
|
||||
```
|
||||
src/pages/
|
||||
├── chat/ # 功能模块文件夹
|
||||
│ ├── index.vue # 父级布局页
|
||||
│ ├── conversation/ # 子页面文件夹
|
||||
│ │ └── index.vue # 子页面
|
||||
│ └── image/
|
||||
│ └── index.vue
|
||||
├── console/
|
||||
│ └── index.vue
|
||||
└── your-page/ # 新增页面在这里创建
|
||||
└── index.vue
|
||||
```
|
||||
|
||||
**单页面示例** (`src/pages/your-page/index.vue`):
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="your-page">
|
||||
<h1>页面标题</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 自动导入 Vue API,无需手动 import
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
// 如需使用状态管理
|
||||
const userStore = useUserStore()
|
||||
|
||||
onMounted(() => {
|
||||
console.log('页面加载')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.your-page {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### 2. 配置路由
|
||||
|
||||
路由配置在 `src/routers/modules/staticRouter.ts`。
|
||||
|
||||
**新增独立页面**(添加到 `layoutRouter` 的 children 中):
|
||||
|
||||
```typescript
|
||||
{
|
||||
path: 'your-page', // URL 路径,最终为 /your-page
|
||||
name: 'yourPage', // 路由名称,必须唯一
|
||||
component: () => import('@/pages/your-page/index.vue'),
|
||||
meta: {
|
||||
title: '页面标题', // 页面标题,会显示在浏览器标签
|
||||
keepAlive: 0, // 是否缓存页面:0=缓存,1=不缓存
|
||||
isDefaultChat: false, // 是否为默认聊天页
|
||||
layout: 'default', // 布局类型:default/blankPage
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**新增带子路由的功能模块**:
|
||||
|
||||
```typescript
|
||||
{
|
||||
path: 'module-name',
|
||||
name: 'moduleName',
|
||||
component: () => import('@/pages/module-name/index.vue'), // 父级布局页
|
||||
redirect: '/module-name/sub-page', // 默认重定向
|
||||
meta: {
|
||||
title: '模块标题',
|
||||
icon: 'HomeFilled', // Element Plus 图标名称
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'sub-page',
|
||||
name: 'subPage',
|
||||
component: () => import('@/pages/module-name/sub-page/index.vue'),
|
||||
meta: {
|
||||
title: '子页面标题',
|
||||
},
|
||||
},
|
||||
// 带参数的路由
|
||||
{
|
||||
path: 'detail/:id',
|
||||
name: 'detailPage',
|
||||
component: () => import('@/pages/module-name/detail/index.vue'),
|
||||
meta: {
|
||||
title: '详情页',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
**无需布局的独立页面**(添加到 `staticRouter`):
|
||||
|
||||
```typescript
|
||||
{
|
||||
path: '/test/page',
|
||||
name: 'testPage',
|
||||
component: () => import('@/pages/test/page.vue'),
|
||||
meta: {
|
||||
title: '测试页面',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 页面 Meta 配置说明
|
||||
|
||||
| 属性 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| title | string | 页面标题,显示在浏览器标签页 |
|
||||
| keepAlive | number | 0=缓存页面,1=不缓存 |
|
||||
| layout | string | 布局类型:'default' 使用默认布局,'blankPage' 使用空白布局 |
|
||||
| isDefaultChat | boolean | 是否为默认聊天页面 |
|
||||
| icon | string | Element Plus 图标名称,用于菜单显示 |
|
||||
| isHide | string | '0'=在菜单中隐藏,'1'=显示 |
|
||||
| isKeepAlive | string | '0'=缓存,'1'=不缓存(字符串版) |
|
||||
|
||||
### 4. 布局说明
|
||||
|
||||
布局组件位于 `src/layouts/`:
|
||||
|
||||
- **default**: 默认布局,包含侧边栏、顶部导航等
|
||||
- **blankPage**: 空白布局,仅包含路由出口
|
||||
|
||||
在路由 meta 中通过 `layout` 字段指定:
|
||||
|
||||
```typescript
|
||||
meta: {
|
||||
layout: 'default', // 使用默认布局(有侧边栏)
|
||||
// 或
|
||||
layout: 'blankPage', // 使用空白布局(全屏页面)
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 页面跳转示例
|
||||
|
||||
```typescript
|
||||
// 在 script setup 中使用
|
||||
const router = useRouter()
|
||||
|
||||
// 跳转页面
|
||||
router.push('/chat/conversation')
|
||||
router.push({ name: 'chatConversation' })
|
||||
router.push({ path: '/chat/conversation/:id', params: { id: '123' } })
|
||||
|
||||
// 获取路由参数
|
||||
const route = useRoute()
|
||||
console.log(route.params.id)
|
||||
```
|
||||
|
||||
### 6. 完整新增页面示例
|
||||
|
||||
假设要新增一个"数据统计"页面:
|
||||
|
||||
**步骤 1**: 创建页面文件 `src/pages/statistics/index.vue`
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="statistics-page">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<span>数据统计</span>
|
||||
</template>
|
||||
<div>页面内容</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { data, loading } = useFetch('/api/statistics').get().json()
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.statistics-page {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
**步骤 2**: 在 `src/routers/modules/staticRouter.ts` 中添加路由
|
||||
|
||||
```typescript
|
||||
{
|
||||
path: 'statistics',
|
||||
name: 'statistics',
|
||||
component: () => import('@/pages/statistics/index.vue'),
|
||||
meta: {
|
||||
title: '意心Ai-数据统计',
|
||||
keepAlive: 0,
|
||||
isDefaultChat: false,
|
||||
layout: 'default',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**步骤 3**: 在菜单中添加入口(如需要)
|
||||
|
||||
如需在侧边栏显示,需在相应的位置添加菜单配置。
|
||||
|
||||
## 核心架构说明
|
||||
|
||||
### HTTP 请求封装
|
||||
|
||||
位于 `src/utils/request.ts`,使用 hook-fetch:
|
||||
|
||||
```typescript
|
||||
import { get, post, put, del } from '@/utils/request'
|
||||
|
||||
// GET 请求
|
||||
const { data } = await get('/api/endpoint').json()
|
||||
|
||||
// POST 请求
|
||||
const result = await post('/api/endpoint', { key: 'value' }).json()
|
||||
```
|
||||
|
||||
特点:
|
||||
- 自动附加 JWT Token 到请求头
|
||||
- 自动处理 401/403 错误
|
||||
- 支持 Server-Sent Events (SSE) 流式响应
|
||||
|
||||
### 状态管理
|
||||
|
||||
Pinia stores 位于 `src/stores/modules/`:
|
||||
|
||||
| Store | 用途 |
|
||||
|-------|------|
|
||||
| user.ts | 用户认证、登录状态 |
|
||||
| chat.ts | 聊天消息、流式输出 |
|
||||
| session.ts | 会话列表、当前会话 |
|
||||
| model.ts | AI 模型配置 |
|
||||
|
||||
使用方式:
|
||||
|
||||
```typescript
|
||||
const userStore = useUserStore()
|
||||
userStore.setToken(token, refreshToken)
|
||||
userStore.logout()
|
||||
```
|
||||
|
||||
### 自动导入
|
||||
|
||||
项目已配置 `unplugin-auto-import`,以下 API 无需手动 import:
|
||||
|
||||
- Vue API: `ref`, `reactive`, `computed`, `watch`, `onMounted` 等
|
||||
- Vue Router: `useRoute`, `useRouter`
|
||||
- Pinia: `createPinia`, `storeToRefs`
|
||||
- VueUse: `useFetch`, `useStorage` 等
|
||||
|
||||
### 路径别名
|
||||
|
||||
| 别名 | 对应路径 |
|
||||
|------|----------|
|
||||
| `@/` | `src/` |
|
||||
| `@components/` | `src/vue-element-plus-y/components/` |
|
||||
|
||||
### 环境变量
|
||||
|
||||
开发配置在 `.env.development`:
|
||||
|
||||
```
|
||||
VITE_WEB_BASE_API=/dev-api # API 前缀
|
||||
VITE_API_URL=http://localhost:19001/api/app # 后端地址
|
||||
VITE_SSO_SEVER_URL=http://localhost:18001 # SSO 地址
|
||||
```
|
||||
|
||||
Vite 开发服务器会自动将 `/dev-api` 代理到后端 API。
|
||||
|
||||
## 代码规范
|
||||
|
||||
### 提交规范
|
||||
|
||||
使用 `pnpm cz` 进行规范提交,类型包括:
|
||||
- `feat`: 新功能
|
||||
- `fix`: 修复
|
||||
- `docs`: 文档
|
||||
- `style`: 代码格式
|
||||
- `refactor`: 重构
|
||||
- `perf`: 性能优化
|
||||
- `test`: 测试
|
||||
- `build`: 构建
|
||||
- `ci`: CI/CD
|
||||
- `revert`: 回滚
|
||||
- `chore`: 其他
|
||||
|
||||
### Git Hooks
|
||||
|
||||
- **pre-commit**: 自动运行 ESLint 修复
|
||||
- **commit-msg**: 校验提交信息格式
|
||||
|
||||
## 构建优化
|
||||
|
||||
Vite 配置中的代码分割策略(`vite.config.ts`):
|
||||
|
||||
| Chunk 名称 | 包含内容 |
|
||||
|-----------|---------|
|
||||
| vue-vendor | Vue 核心库、Vue Router |
|
||||
| pinia | Pinia 状态管理 |
|
||||
| element-plus | Element Plus UI 库 |
|
||||
| markdown | Markdown 解析相关 |
|
||||
| utils | Lodash、VueUse 工具库 |
|
||||
| highlight | 代码高亮库 |
|
||||
| echarts | 图表库 |
|
||||
| pdf | PDF 处理库 |
|
||||
|
||||
## 后端集成
|
||||
|
||||
后端为 .NET 8 项目,本地启动命令:
|
||||
|
||||
```bash
|
||||
cd E:\devDemo\Yi\Yi.Abp.Net8\src\Yi.Abp.Web
|
||||
dotnet run
|
||||
```
|
||||
|
||||
前端开发时,后端默认运行在 `http://localhost:19001`。
|
||||
15
Yi.Ai.Vue3/src/api/ranking/index.ts
Normal file
15
Yi.Ai.Vue3/src/api/ranking/index.ts
Normal 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();
|
||||
}
|
||||
21
Yi.Ai.Vue3/src/api/ranking/types.ts
Normal file
21
Yi.Ai.Vue3/src/api/ranking/types.ts
Normal 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;
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
1322
Yi.Ai.Vue3/src/pages/ranking/index.vue
Normal file
1322
Yi.Ai.Vue3/src/pages/ranking/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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',
|
||||
|
||||
1
Yi.Ai.Vue3/types/import_meta.d.ts
vendored
1
Yi.Ai.Vue3/types/import_meta.d.ts
vendored
@@ -7,7 +7,6 @@ interface ImportMetaEnv {
|
||||
readonly VITE_WEB_BASE_API: string;
|
||||
readonly VITE_API_URL: string;
|
||||
readonly VITE_FILE_UPLOAD_API: string;
|
||||
readonly VITE_BUILD_COMPRESS: string;
|
||||
readonly VITE_SSO_SEVER_URL: string;
|
||||
readonly VITE_APP_VERSION: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user