mirror of
https://gitee.com/ccnetcore/Yi
synced 2026-04-07 01:36:35 +08:00
feat: 增加尊享产品
This commit is contained in:
@@ -34,8 +34,17 @@ const progressColor = computed(() => {
|
||||
return '#67c23a'; // 绿色
|
||||
});
|
||||
|
||||
// 格式化数字
|
||||
// 格式化数字 - 转换为万为单位
|
||||
function formatNumber(num: number): string {
|
||||
if (num === 0)
|
||||
return '0';
|
||||
const wan = num / 10000;
|
||||
// 保留2位小数,去掉末尾的0
|
||||
return wan.toFixed(2).replace(/\.?0+$/, '');
|
||||
}
|
||||
|
||||
// 格式化原始数字(带千分位)
|
||||
function formatRawNumber(num: number): string {
|
||||
return num.toLocaleString();
|
||||
}
|
||||
/*
|
||||
@@ -61,18 +70,21 @@ async function fetchPremiumTokenPackage() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await getPremiumTokenPackage();
|
||||
if (res.success && res.data) {
|
||||
console.log('尊享服务Token包数据:', res);
|
||||
if (res.data) {
|
||||
// 适配新的接口字段名
|
||||
const data = res.data;
|
||||
packageData.value = {
|
||||
totalQuota: res.data.totalQuota || 0,
|
||||
usedQuota: res.data.usedQuota || 0,
|
||||
remainingQuota: res.data.remainingQuota || 0,
|
||||
usagePercentage: res.data.usagePercentage || 0,
|
||||
packageName: res.data.packageName || 'Token包',
|
||||
expireDate: res.data.expireDate || '',
|
||||
totalQuota: data.premiumTotalTokens || 0, // 尊享包总token
|
||||
usedQuota: data.premiumUsedTokens || 0, // 尊享包已使用token
|
||||
remainingQuota: data.premiumRemainingTokens || 0, // 尊享包剩余token
|
||||
usagePercentage: data.usagePercentage || 0,
|
||||
packageName: data.packageName || '尊享Token包',
|
||||
expireDate: data.expireDate || '',
|
||||
};
|
||||
|
||||
// 计算剩余额度(如果接口没返回)
|
||||
if (!packageData.value.remainingQuota) {
|
||||
if (packageData.value.remainingQuota === 0 && packageData.value.totalQuota > 0) {
|
||||
packageData.value.remainingQuota = packageData.value.totalQuota - packageData.value.usedQuota;
|
||||
}
|
||||
}
|
||||
@@ -137,7 +149,10 @@ onMounted(() => {
|
||||
{{ formatNumber(packageData.totalQuota) }}
|
||||
</div>
|
||||
<div class="stat-unit">
|
||||
Tokens
|
||||
万 Tokens
|
||||
</div>
|
||||
<div class="stat-raw" :title="`原始值: ${formatRawNumber(packageData.totalQuota)} Tokens`">
|
||||
({{ formatRawNumber(packageData.totalQuota) }})
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -149,7 +164,10 @@ onMounted(() => {
|
||||
{{ formatNumber(packageData.usedQuota) }}
|
||||
</div>
|
||||
<div class="stat-unit">
|
||||
Tokens
|
||||
万 Tokens
|
||||
</div>
|
||||
<div class="stat-raw" :title="`原始值: ${formatRawNumber(packageData.usedQuota)} Tokens`">
|
||||
({{ formatRawNumber(packageData.usedQuota) }})
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -161,7 +179,10 @@ onMounted(() => {
|
||||
{{ formatNumber(packageData.remainingQuota) }}
|
||||
</div>
|
||||
<div class="stat-unit">
|
||||
Tokens
|
||||
万 Tokens
|
||||
</div>
|
||||
<div class="stat-raw" :title="`原始值: ${formatRawNumber(packageData.remainingQuota)} Tokens`">
|
||||
({{ formatRawNumber(packageData.remainingQuota) }})
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -345,6 +366,18 @@ onMounted(() => {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.stat-raw {
|
||||
font-size: 11px;
|
||||
opacity: 0.7;
|
||||
margin-top: 4px;
|
||||
cursor: help;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.stat-raw:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 进度条部分 */
|
||||
.progress-section {
|
||||
padding: 20px;
|
||||
|
||||
@@ -48,6 +48,9 @@ const totalTokens = ref(0);
|
||||
const usageData = ref<any[]>([]);
|
||||
const modelUsageData = ref<any[]>([]);
|
||||
|
||||
// 计算属性:是否有模型数据
|
||||
const hasModelData = computed(() => modelUsageData.value.length > 0);
|
||||
|
||||
// 获取用量数据
|
||||
async function fetchUsageData() {
|
||||
loading.value = true;
|
||||
@@ -156,9 +159,67 @@ function updateLineChart() {
|
||||
|
||||
// 更新饼图 - 动态适应数据量
|
||||
function updatePieChart() {
|
||||
if (!pieChartInstance || modelUsageData.value.length === 0)
|
||||
if (!pieChartInstance)
|
||||
return;
|
||||
|
||||
// 空数据状态
|
||||
if (modelUsageData.value.length === 0) {
|
||||
const emptyOption = {
|
||||
graphic: [
|
||||
{
|
||||
type: 'group',
|
||||
left: 'center',
|
||||
top: 'center',
|
||||
children: [
|
||||
{
|
||||
type: 'circle',
|
||||
shape: {
|
||||
r: 80,
|
||||
},
|
||||
style: {
|
||||
fill: '#f5f7fa',
|
||||
stroke: '#e9ecef',
|
||||
lineWidth: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
style: {
|
||||
text: '📊',
|
||||
fontSize: 48,
|
||||
x: -24,
|
||||
y: -40,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
style: {
|
||||
text: '暂无数据',
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
fill: '#909399',
|
||||
x: -36,
|
||||
y: 20,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
style: {
|
||||
text: '还没有模型使用记录',
|
||||
fontSize: 14,
|
||||
fill: '#c0c4cc',
|
||||
x: -70,
|
||||
y: 50,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
pieChartInstance.setOption(emptyOption, true);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = modelUsageData.value.map(item => ({
|
||||
name: item.model,
|
||||
value: item.tokens,
|
||||
@@ -168,6 +229,7 @@ function updatePieChart() {
|
||||
const isSmallContainer = pieContainerSize.width.value < 600;
|
||||
|
||||
const option = {
|
||||
graphic: [], // 清空graphic配置
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} tokens ({d}%)',
|
||||
@@ -222,14 +284,76 @@ function updatePieChart() {
|
||||
],
|
||||
};
|
||||
|
||||
pieChartInstance.setOption(option);
|
||||
pieChartInstance.setOption(option, true);
|
||||
}
|
||||
|
||||
// 更新柱状图 - 动态适应数据量
|
||||
function updateBarChart() {
|
||||
if (!barChartInstance || modelUsageData.value.length === 0)
|
||||
if (!barChartInstance)
|
||||
return;
|
||||
|
||||
// 空数据状态
|
||||
if (modelUsageData.value.length === 0) {
|
||||
const emptyOption = {
|
||||
graphic: [
|
||||
{
|
||||
type: 'group',
|
||||
left: 'center',
|
||||
top: 'center',
|
||||
children: [
|
||||
{
|
||||
type: 'rect',
|
||||
shape: {
|
||||
width: 160,
|
||||
height: 160,
|
||||
r: 12,
|
||||
},
|
||||
style: {
|
||||
fill: '#f5f7fa',
|
||||
stroke: '#e9ecef',
|
||||
lineWidth: 2,
|
||||
},
|
||||
left: -80,
|
||||
top: -80,
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
style: {
|
||||
text: '📈',
|
||||
fontSize: 48,
|
||||
x: -24,
|
||||
y: -40,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
style: {
|
||||
text: '暂无数据',
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
fill: '#909399',
|
||||
x: -36,
|
||||
y: 20,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
style: {
|
||||
text: '还没有模型使用记录',
|
||||
fontSize: 14,
|
||||
fill: '#c0c4cc',
|
||||
x: -70,
|
||||
y: 50,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
barChartInstance.setOption(emptyOption, true);
|
||||
return;
|
||||
}
|
||||
|
||||
const models = modelUsageData.value.map(item => item.model);
|
||||
const tokens = modelUsageData.value.map(item => item.tokens);
|
||||
|
||||
@@ -237,6 +361,7 @@ function updateBarChart() {
|
||||
const isSmallContainer = barContainerSize.width.value < 600;
|
||||
|
||||
const option = {
|
||||
graphic: [], // 清空graphic配置
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
@@ -302,7 +427,7 @@ function updateBarChart() {
|
||||
],
|
||||
};
|
||||
|
||||
barChartInstance.setOption(option);
|
||||
barChartInstance.setOption(option, true);
|
||||
}
|
||||
|
||||
// 调整图表大小
|
||||
|
||||
Reference in New Issue
Block a user