feat: 兼容claude格式
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.SystemStatistics;
|
||||
|
||||
/// <summary>
|
||||
/// 模型Token统计DTO
|
||||
/// </summary>
|
||||
public class ModelTokenStatisticsDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 模型ID
|
||||
/// </summary>
|
||||
public string ModelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模型名称
|
||||
/// </summary>
|
||||
public string ModelName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Token消耗量
|
||||
/// </summary>
|
||||
public long Tokens { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Token消耗量(万)
|
||||
/// </summary>
|
||||
public decimal TokensInWan { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 使用次数
|
||||
/// </summary>
|
||||
public long Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 成本(RMB)
|
||||
/// </summary>
|
||||
public decimal Cost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 1亿Token成本(RMB)
|
||||
/// </summary>
|
||||
public decimal CostPerHundredMillion { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.SystemStatistics;
|
||||
|
||||
/// <summary>
|
||||
/// 利润统计输入
|
||||
/// </summary>
|
||||
public class ProfitStatisticsInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前成本(RMB)
|
||||
/// </summary>
|
||||
public decimal CurrentCost { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.SystemStatistics;
|
||||
|
||||
/// <summary>
|
||||
/// 利润统计输出
|
||||
/// </summary>
|
||||
public class ProfitStatisticsOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 日期
|
||||
/// </summary>
|
||||
public string Date { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 尊享包已消耗Token数(单位:个)
|
||||
/// </summary>
|
||||
public long TotalUsedTokens { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 尊享包已消耗Token数(单位:亿)
|
||||
/// </summary>
|
||||
public decimal TotalUsedTokensInHundredMillion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 尊享包剩余库存Token数(单位:个)
|
||||
/// </summary>
|
||||
public long TotalRemainingTokens { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 尊享包剩余库存Token数(单位:亿)
|
||||
/// </summary>
|
||||
public decimal TotalRemainingTokensInHundredMillion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前成本(RMB)
|
||||
/// </summary>
|
||||
public decimal CurrentCost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 1亿Token成本(RMB)
|
||||
/// </summary>
|
||||
public decimal CostPerHundredMillion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总成本(RMB)
|
||||
/// </summary>
|
||||
public decimal TotalCost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总收益(RMB)
|
||||
/// </summary>
|
||||
public decimal TotalRevenue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 利润率(%)
|
||||
/// </summary>
|
||||
public decimal ProfitRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 按200售价计算的成本(RMB)
|
||||
/// </summary>
|
||||
public decimal CostAt200Price { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.SystemStatistics;
|
||||
|
||||
/// <summary>
|
||||
/// Token统计输入
|
||||
/// </summary>
|
||||
public class TokenStatisticsInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 指定日期(当天零点)
|
||||
/// </summary>
|
||||
public DateTime Date { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.SystemStatistics;
|
||||
|
||||
/// <summary>
|
||||
/// Token统计输出
|
||||
/// </summary>
|
||||
public class TokenStatisticsOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 日期
|
||||
/// </summary>
|
||||
public string Date { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模型统计列表
|
||||
/// </summary>
|
||||
public List<ModelTokenStatisticsDto> ModelStatistics { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.SystemStatistics;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.IServices;
|
||||
|
||||
/// <summary>
|
||||
/// 系统使用量统计服务接口
|
||||
/// </summary>
|
||||
public interface ISystemUsageStatisticsService
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取利润统计数据
|
||||
/// </summary>
|
||||
Task<ProfitStatisticsOutput> GetProfitStatisticsAsync(ProfitStatisticsInput input);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定日期各模型Token统计
|
||||
/// </summary>
|
||||
Task<TokenStatisticsOutput> GetTokenStatisticsAsync(TokenStatisticsInput input);
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
using Mapster;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SqlSugar;
|
||||
using System.Globalization;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.SystemStatistics;
|
||||
using Yi.Framework.AiHub.Application.Contracts.IServices;
|
||||
using Yi.Framework.AiHub.Domain.Entities;
|
||||
using Yi.Framework.AiHub.Domain.Entities.Chat;
|
||||
using Yi.Framework.AiHub.Domain.Entities.Model;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 系统使用量统计服务实现
|
||||
/// </summary>
|
||||
[Authorize(Roles = "admin")]
|
||||
public class SystemUsageStatisticsService : ApplicationService, ISystemUsageStatisticsService
|
||||
{
|
||||
private readonly ISqlSugarRepository<PremiumPackageAggregateRoot> _premiumPackageRepository;
|
||||
private readonly ISqlSugarRepository<AiRechargeAggregateRoot> _rechargeRepository;
|
||||
private readonly ISqlSugarRepository<MessageAggregateRoot> _messageRepository;
|
||||
private readonly ISqlSugarRepository<AiModelEntity, Guid> _modelRepository;
|
||||
|
||||
public SystemUsageStatisticsService(
|
||||
ISqlSugarRepository<PremiumPackageAggregateRoot> premiumPackageRepository,
|
||||
ISqlSugarRepository<AiRechargeAggregateRoot> rechargeRepository,
|
||||
ISqlSugarRepository<MessageAggregateRoot> messageRepository,
|
||||
ISqlSugarRepository<AiModelEntity, Guid> modelRepository)
|
||||
{
|
||||
_premiumPackageRepository = premiumPackageRepository;
|
||||
_rechargeRepository = rechargeRepository;
|
||||
_messageRepository = messageRepository;
|
||||
_modelRepository = modelRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取利润统计数据
|
||||
/// </summary>
|
||||
[HttpPost("system-statistics/profit")]
|
||||
public async Task<ProfitStatisticsOutput> GetProfitStatisticsAsync(ProfitStatisticsInput input)
|
||||
{
|
||||
// 1. 获取尊享包总消耗和剩余库存
|
||||
var premiumPackages = await _premiumPackageRepository._DbQueryable.ToListAsync();
|
||||
long totalUsedTokens = premiumPackages.Sum(p => p.UsedTokens);
|
||||
long totalRemainingTokens = premiumPackages.Sum(p => p.RemainingTokens);
|
||||
|
||||
// 2. 计算1亿Token成本
|
||||
decimal costPerHundredMillion = totalUsedTokens > 0
|
||||
? input.CurrentCost / (totalUsedTokens / 100000000m)
|
||||
: 0;
|
||||
|
||||
// 3. 计算总成本(剩余+已使用的总成本)
|
||||
long totalTokens = totalUsedTokens + totalRemainingTokens;
|
||||
decimal totalCost = totalTokens > 0
|
||||
? (totalTokens / 100000000m) * costPerHundredMillion
|
||||
: 0;
|
||||
|
||||
// 4. 获取总收益(RechargeType=PremiumPackage的充值金额总和)
|
||||
decimal totalRevenue = await _rechargeRepository._DbQueryable
|
||||
.Where(x => x.RechargeType == Domain.Shared.Enums.RechargeTypeEnum.PremiumPackage)
|
||||
.SumAsync(x => x.RechargeAmount);
|
||||
|
||||
// 5. 计算利润率
|
||||
decimal profitRate = totalCost > 0
|
||||
? (totalRevenue / totalCost - 1) * 100
|
||||
: 0;
|
||||
|
||||
// 6. 按200售价计算成本
|
||||
decimal costAt200Price = totalRevenue > 0
|
||||
? (totalCost / totalRevenue) * 200
|
||||
: 0;
|
||||
|
||||
// 7. 格式化日期
|
||||
var today = DateTime.Now;
|
||||
string dayOfWeek = today.ToString("dddd", new CultureInfo("zh-CN"));
|
||||
string weekDay = dayOfWeek switch
|
||||
{
|
||||
"星期一" => "周1",
|
||||
"星期二" => "周2",
|
||||
"星期三" => "周3",
|
||||
"星期四" => "周4",
|
||||
"星期五" => "周5",
|
||||
"星期六" => "周6",
|
||||
"星期日" => "周日",
|
||||
_ => dayOfWeek
|
||||
};
|
||||
|
||||
return new ProfitStatisticsOutput
|
||||
{
|
||||
Date = $"{today:M月d日} {weekDay}",
|
||||
TotalUsedTokens = totalUsedTokens,
|
||||
TotalUsedTokensInHundredMillion = totalUsedTokens / 100000000m,
|
||||
TotalRemainingTokens = totalRemainingTokens,
|
||||
TotalRemainingTokensInHundredMillion = totalRemainingTokens / 100000000m,
|
||||
CurrentCost = input.CurrentCost,
|
||||
CostPerHundredMillion = costPerHundredMillion,
|
||||
TotalCost = totalCost,
|
||||
TotalRevenue = totalRevenue,
|
||||
ProfitRate = profitRate,
|
||||
CostAt200Price = costAt200Price
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定日期各模型Token统计
|
||||
/// </summary>
|
||||
[HttpPost("system-statistics/token")]
|
||||
public async Task<TokenStatisticsOutput> GetTokenStatisticsAsync(TokenStatisticsInput input)
|
||||
{
|
||||
var day = input.Date.Date;
|
||||
var nextDay = day.AddDays(1);
|
||||
|
||||
// 1. 获取所有尊享模型(包含被禁用的),按ModelId去重
|
||||
var premiumModels = await _modelRepository._DbQueryable
|
||||
.Where(x => x.IsPremium)
|
||||
.ToListAsync();
|
||||
|
||||
if (premiumModels.Count == 0)
|
||||
{
|
||||
return new TokenStatisticsOutput
|
||||
{
|
||||
Date = FormatDate(day),
|
||||
ModelStatistics = new List<ModelTokenStatisticsDto>()
|
||||
};
|
||||
}
|
||||
|
||||
// 按ModelId去重,保留第一个模型的名称
|
||||
var distinctModels = premiumModels
|
||||
.GroupBy(x => x.ModelId)
|
||||
.Select(g => g.First())
|
||||
.ToList();
|
||||
|
||||
var modelIds = distinctModels.Select(x => x.ModelId).ToList();
|
||||
|
||||
// 2. 查询指定日期内各模型的Token使用统计
|
||||
var modelStats = await _messageRepository._DbQueryable
|
||||
.Where(x => modelIds.Contains(x.ModelId))
|
||||
.Where(x => x.CreationTime >= day && x.CreationTime < nextDay)
|
||||
.Where(x => x.Role == "system")
|
||||
.GroupBy(x => x.ModelId)
|
||||
.Select(x => new
|
||||
{
|
||||
ModelId = x.ModelId,
|
||||
Tokens = SqlFunc.AggregateSum(x.TokenUsage.TotalTokenCount),
|
||||
Count = SqlFunc.AggregateCount(x.Id)
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
var modelStatDict = modelStats.ToDictionary(x => x.ModelId, x => x);
|
||||
|
||||
// 3. 构建结果列表,使用去重后的模型列表
|
||||
var result = new List<ModelTokenStatisticsDto>();
|
||||
foreach (var model in distinctModels)
|
||||
{
|
||||
modelStatDict.TryGetValue(model.ModelId, out var stat);
|
||||
long tokens = stat?.Tokens ?? 0;
|
||||
long count = stat?.Count ?? 0;
|
||||
|
||||
// 这里成本设为0,因为需要前端传入或者从配置中获取
|
||||
decimal cost = 0;
|
||||
decimal costPerHundredMillion = tokens > 0 && cost > 0
|
||||
? cost / (tokens / 100000000m)
|
||||
: 0;
|
||||
|
||||
result.Add(new ModelTokenStatisticsDto
|
||||
{
|
||||
ModelId = model.ModelId,
|
||||
ModelName = model.Name,
|
||||
Tokens = tokens,
|
||||
TokensInWan = tokens / 10000m,
|
||||
Count = count,
|
||||
Cost = cost,
|
||||
CostPerHundredMillion = costPerHundredMillion
|
||||
});
|
||||
}
|
||||
|
||||
return new TokenStatisticsOutput
|
||||
{
|
||||
Date = FormatDate(day),
|
||||
ModelStatistics = result
|
||||
};
|
||||
}
|
||||
|
||||
private string FormatDate(DateTime date)
|
||||
{
|
||||
string dayOfWeek = date.ToString("dddd", new CultureInfo("zh-CN"));
|
||||
string weekDay = dayOfWeek switch
|
||||
{
|
||||
"星期一" => "周1",
|
||||
"星期二" => "周2",
|
||||
"星期三" => "周3",
|
||||
"星期四" => "周4",
|
||||
"星期五" => "周5",
|
||||
"星期六" => "周6",
|
||||
"星期日" => "周日",
|
||||
_ => dayOfWeek
|
||||
};
|
||||
return $"{date:M月d日} {weekDay}";
|
||||
}
|
||||
}
|
||||
17
Yi.Ai.Vue3/src/api/systemStatistics/index.ts
Normal file
17
Yi.Ai.Vue3/src/api/systemStatistics/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { post } from '@/utils/request';
|
||||
import type {
|
||||
ProfitStatisticsInput,
|
||||
ProfitStatisticsOutput,
|
||||
TokenStatisticsInput,
|
||||
TokenStatisticsOutput,
|
||||
} from './types';
|
||||
|
||||
// 获取利润统计数据
|
||||
export function getProfitStatistics(data: ProfitStatisticsInput) {
|
||||
return post<ProfitStatisticsOutput>('/system-statistics/profit', data).json();
|
||||
}
|
||||
|
||||
// 获取指定日期各模型Token统计
|
||||
export function getTokenStatistics(data: TokenStatisticsInput) {
|
||||
return post<TokenStatisticsOutput>('/system-statistics/token', data).json();
|
||||
}
|
||||
41
Yi.Ai.Vue3/src/api/systemStatistics/types.ts
Normal file
41
Yi.Ai.Vue3/src/api/systemStatistics/types.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
// 利润统计输入
|
||||
export interface ProfitStatisticsInput {
|
||||
currentCost: number;
|
||||
}
|
||||
|
||||
// 利润统计输出
|
||||
export interface ProfitStatisticsOutput {
|
||||
date: string;
|
||||
totalUsedTokens: number;
|
||||
totalUsedTokensInHundredMillion: number;
|
||||
totalRemainingTokens: number;
|
||||
totalRemainingTokensInHundredMillion: number;
|
||||
currentCost: number;
|
||||
costPerHundredMillion: number;
|
||||
totalCost: number;
|
||||
totalRevenue: number;
|
||||
profitRate: number;
|
||||
costAt200Price: number;
|
||||
}
|
||||
|
||||
// Token统计输入
|
||||
export interface TokenStatisticsInput {
|
||||
date: string;
|
||||
}
|
||||
|
||||
// 模型Token统计DTO
|
||||
export interface ModelTokenStatisticsDto {
|
||||
modelId: string;
|
||||
modelName: string;
|
||||
tokens: number;
|
||||
tokensInWan: number;
|
||||
count: number;
|
||||
cost: number;
|
||||
costPerHundredMillion: number;
|
||||
}
|
||||
|
||||
// Token统计输出
|
||||
export interface TokenStatisticsOutput {
|
||||
date: string;
|
||||
modelStatistics: ModelTokenStatisticsDto[];
|
||||
}
|
||||
219
Yi.Ai.Vue3/src/pages/console/system-statistics/index.vue
Normal file
219
Yi.Ai.Vue3/src/pages/console/system-statistics/index.vue
Normal file
@@ -0,0 +1,219 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Refresh } from '@element-plus/icons-vue';
|
||||
import { getProfitStatistics, getTokenStatistics } from '@/api/systemStatistics';
|
||||
import type { ProfitStatisticsOutput, TokenStatisticsOutput } from '@/api/systemStatistics/types';
|
||||
|
||||
// ==================== 利润统计 ====================
|
||||
const profitLoading = ref(false);
|
||||
const profitData = ref<ProfitStatisticsOutput | null>(null);
|
||||
const currentCost = ref<number>(0);
|
||||
|
||||
// 获取利润统计
|
||||
async function fetchProfitStatistics() {
|
||||
if (!currentCost.value || currentCost.value <= 0) {
|
||||
ElMessage.warning('请输入当前成本');
|
||||
return;
|
||||
}
|
||||
|
||||
profitLoading.value = true;
|
||||
try {
|
||||
const res = await getProfitStatistics({
|
||||
currentCost: currentCost.value,
|
||||
});
|
||||
profitData.value = res.data;
|
||||
}
|
||||
catch (error: any) {
|
||||
ElMessage.error(error.message || '获取利润统计失败');
|
||||
}
|
||||
finally {
|
||||
profitLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Token统计 ====================
|
||||
const tokenLoading = ref(false);
|
||||
const tokenData = ref<TokenStatisticsOutput | null>(null);
|
||||
const selectedDate = ref<string>(new Date().toISOString().split('T')[0]);
|
||||
|
||||
// 获取Token统计
|
||||
async function fetchTokenStatistics() {
|
||||
if (!selectedDate.value) {
|
||||
ElMessage.warning('请选择日期');
|
||||
return;
|
||||
}
|
||||
|
||||
tokenLoading.value = true;
|
||||
try {
|
||||
const res = await getTokenStatistics({
|
||||
date: selectedDate.value,
|
||||
});
|
||||
tokenData.value = res.data;
|
||||
}
|
||||
catch (error: any) {
|
||||
ElMessage.error(error.message || '获取Token统计失败');
|
||||
}
|
||||
finally {
|
||||
tokenLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
// 页面加载时不自动获取数据,等待用户输入参数后手动获取
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="system-statistics">
|
||||
<div class="statistics-container">
|
||||
<!-- 利润统计卡片 -->
|
||||
<el-card class="statistics-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<h3>利润统计</h3>
|
||||
<el-button type="primary" size="small" :icon="Refresh" :loading="profitLoading" @click="fetchProfitStatistics">
|
||||
查询
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="input-section">
|
||||
<el-form :inline="true">
|
||||
<el-form-item label="当前成本(RMB)">
|
||||
<el-input-number
|
||||
v-model="currentCost"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
placeholder="请输入当前成本"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div v-if="profitData" v-loading="profitLoading" class="data-display">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="日期">{{ profitData.date }}</el-descriptions-item>
|
||||
<el-descriptions-item label="当前成本">{{ profitData.currentCost.toFixed(2) }} RMB</el-descriptions-item>
|
||||
<el-descriptions-item label="尊享包已消耗">
|
||||
{{ profitData.totalUsedTokensInHundredMillion.toFixed(2) }}亿 ({{ profitData.totalUsedTokens }})
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="尊享包剩余库存">
|
||||
{{ profitData.totalRemainingTokensInHundredMillion.toFixed(2) }}亿 ({{ profitData.totalRemainingTokens }})
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="1亿Token成本">
|
||||
{{ profitData.costPerHundredMillion.toFixed(2) }} RMB
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="总成本">
|
||||
{{ profitData.totalCost.toFixed(2) }} RMB
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="总收益">
|
||||
{{ profitData.totalRevenue.toFixed(2) }} RMB
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="利润率">
|
||||
<el-tag :type="profitData.profitRate > 0 ? 'success' : 'danger'">
|
||||
{{ profitData.profitRate.toFixed(1) }}%
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="按200售价计算成本" :span="2">
|
||||
{{ profitData.costAt200Price.toFixed(2) }} RMB
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- Token统计卡片 -->
|
||||
<el-card class="statistics-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<h3>Token统计</h3>
|
||||
<el-button type="primary" size="small" :icon="Refresh" :loading="tokenLoading" @click="fetchTokenStatistics">
|
||||
查询
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="input-section">
|
||||
<el-form :inline="true">
|
||||
<el-form-item label="选择日期">
|
||||
<el-date-picker
|
||||
v-model="selectedDate"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div v-if="tokenData" v-loading="tokenLoading" class="data-display">
|
||||
<div class="date-info">
|
||||
<h4>{{ tokenData.date }}</h4>
|
||||
</div>
|
||||
|
||||
<el-table :data="tokenData.modelStatistics" border stripe>
|
||||
<el-table-column prop="modelName" label="模型名称" min-width="150" />
|
||||
<el-table-column prop="modelId" label="模型ID" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="Token消耗" min-width="120">
|
||||
<template #default="{ row }">
|
||||
{{ row.tokensInWan.toFixed(0) }}w
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="count" label="使用次数" width="100" />
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.system-statistics {
|
||||
padding: 20px;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
|
||||
.statistics-container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.statistics-card {
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.input-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.data-display {
|
||||
.date-info {
|
||||
margin-bottom: 16px;
|
||||
|
||||
h4 {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
1
Yi.Ai.Vue3/types/import_meta.d.ts
vendored
1
Yi.Ai.Vue3/types/import_meta.d.ts
vendored
@@ -7,6 +7,7 @@ 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