token用量添加计费单位
This commit is contained in:
parent
80c131445f
commit
8ea251b144
@ -12,6 +12,8 @@
|
|||||||
size="small"
|
size="small"
|
||||||
prefix-icon="el-icon-search"
|
prefix-icon="el-icon-search"
|
||||||
placeholder="请输入模型名称"
|
placeholder="请输入模型名称"
|
||||||
|
@keyup.enter.native="$emit('search')"
|
||||||
|
@clear="$emit('search')"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="模型类型">
|
<el-form-item label="模型类型">
|
||||||
@ -21,6 +23,8 @@
|
|||||||
filterable
|
filterable
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="请选择模型类型"
|
placeholder="请选择模型类型"
|
||||||
|
@change="$emit('search')"
|
||||||
|
@clear="$emit('search')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in modelTypeOptions"
|
v-for="item in modelTypeOptions"
|
||||||
@ -37,6 +41,8 @@
|
|||||||
filterable
|
filterable
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="请选择供应商"
|
placeholder="请选择供应商"
|
||||||
|
@change="$emit('search')"
|
||||||
|
@clear="$emit('search')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in providerOptions"
|
v-for="item in providerOptions"
|
||||||
|
|||||||
@ -232,7 +232,24 @@
|
|||||||
computed: {
|
computed: {
|
||||||
filteredModelList() {
|
filteredModelList() {
|
||||||
const selectedStatus = this.activeStatus === 'pending' ? 0 : 1
|
const selectedStatus = this.activeStatus === 'pending' ? 0 : 1
|
||||||
return this.modelList.filter(model => Number(model.listing_status) === selectedStatus)
|
const modelName = this.normalizeSearchText(this.searchForm.name)
|
||||||
|
const modelType = this.normalizeSearchText(this.searchForm.type)
|
||||||
|
const provider = this.normalizeSearchText(this.searchForm.provider)
|
||||||
|
|
||||||
|
return this.modelList.filter(model => {
|
||||||
|
if (Number(model.listing_status) !== selectedStatus) return false
|
||||||
|
|
||||||
|
const displayName = this.normalizeSearchText(this.getModelDisplayName(model))
|
||||||
|
const id = this.normalizeSearchText(this.getModelId(model))
|
||||||
|
const type = this.normalizeSearchText(this.getModelType(model))
|
||||||
|
const modelProvider = this.normalizeSearchText(this.getProvider(model))
|
||||||
|
|
||||||
|
const nameMatched = !modelName || displayName.includes(modelName) || id.includes(modelName)
|
||||||
|
const typeMatched = !modelType || type === modelType || type.includes(modelType)
|
||||||
|
const providerMatched = !provider || modelProvider === provider || modelProvider.includes(provider)
|
||||||
|
|
||||||
|
return nameMatched && typeMatched && providerMatched
|
||||||
|
})
|
||||||
},
|
},
|
||||||
pagedModelList() {
|
pagedModelList() {
|
||||||
const start = (this.currentPage - 1) * this.pageSize
|
const start = (this.currentPage - 1) * this.pageSize
|
||||||
@ -282,6 +299,9 @@
|
|||||||
if (this.searchForm.provider) params.provider = this.searchForm.provider
|
if (this.searchForm.provider) params.provider = this.searchForm.provider
|
||||||
return params
|
return params
|
||||||
},
|
},
|
||||||
|
normalizeSearchText(value) {
|
||||||
|
return String(value || '').trim().toLowerCase()
|
||||||
|
},
|
||||||
extractModelData(res) {
|
extractModelData(res) {
|
||||||
const data = res?.data ?? res
|
const data = res?.data ?? res
|
||||||
if (data?.model_list) return data
|
if (data?.model_list) return data
|
||||||
|
|||||||
@ -24,7 +24,10 @@
|
|||||||
<div class="stat-title">{{ item.label }}</div>
|
<div class="stat-title">{{ item.label }}</div>
|
||||||
<i :class="item.icon"></i>
|
<i :class="item.icon"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-value">{{ item.value }}</div>
|
<div class="stat-value">
|
||||||
|
{{ item.value }}
|
||||||
|
<span v-if="item.unit" class="stat-unit">{{ item.unit }}</span>
|
||||||
|
</div>
|
||||||
<div class="stat-desc">{{ item.desc }}</div>
|
<div class="stat-desc">{{ item.desc }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -91,18 +94,35 @@
|
|||||||
<el-tag size="mini" type="info">{{ scope.row.model || '-' }}</el-tag>
|
<el-tag size="mini" type="info">{{ scope.row.model || '-' }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="request_count" label="请求次数" width="100"></el-table-column>
|
<el-table-column prop="request_count" label="请求次数" width="110">
|
||||||
<el-table-column prop="prompt_tokens" label="输入Token" min-width="110">
|
<template slot-scope="scope">
|
||||||
<template slot-scope="scope">{{ formatNumber(scope.row.prompt_tokens) }}</template>
|
<span class="usage-number">{{ formatNumber(scope.row.request_count) }}</span>
|
||||||
|
<span class="usage-unit">次</span>
|
||||||
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="completion_tokens" label="输出Token" min-width="110">
|
<el-table-column prop="prompt_tokens" label="输入Token" min-width="130">
|
||||||
<template slot-scope="scope">{{ formatNumber(scope.row.completion_tokens) }}</template>
|
<template slot-scope="scope">
|
||||||
|
<span class="usage-number">{{ formatNumber(scope.row.prompt_tokens) }}</span>
|
||||||
|
<span class="usage-unit">Token</span>
|
||||||
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="total_tokens" label="总Token" min-width="110">
|
<el-table-column prop="completion_tokens" label="输出Token" min-width="130">
|
||||||
<template slot-scope="scope">{{ formatNumber(scope.row.total_tokens) }}</template>
|
<template slot-scope="scope">
|
||||||
|
<span class="usage-number">{{ formatNumber(scope.row.completion_tokens) }}</span>
|
||||||
|
<span class="usage-unit">Token</span>
|
||||||
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="amount" label="费用(元)" min-width="110">
|
<el-table-column prop="total_tokens" label="总Token" min-width="130">
|
||||||
<template slot-scope="scope">¥{{ formatAmount(scope.row.amount) }}</template>
|
<template slot-scope="scope">
|
||||||
|
<span class="usage-number">{{ formatNumber(scope.row.total_tokens) }}</span>
|
||||||
|
<span class="usage-unit">Token</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="amount" label="费用" min-width="110">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span class="usage-amount">¥{{ formatAmount(scope.row.amount) }}</span>
|
||||||
|
<span class="usage-unit">元</span>
|
||||||
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column prop="last_usage_time" label="最近使用时间" min-width="160" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="last_usage_time" label="最近使用时间" min-width="160" show-overflow-tooltip></el-table-column>
|
||||||
@ -158,9 +178,9 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
statCards() {
|
statCards() {
|
||||||
return [
|
return [
|
||||||
{ label: '请求次数', value: this.formatNumber(this.summary.request_count), desc: '当前筛选范围', type: 'purple', icon: 'el-icon-s-promotion' },
|
{ label: '请求次数', value: this.formatNumber(this.summary.request_count), unit: '次', desc: '当前筛选范围', type: 'purple', icon: 'el-icon-s-promotion' },
|
||||||
{ label: 'Token消耗', value: this.formatNumber(this.summary.total_tokens), desc: `输入 ${this.formatNumber(this.summary.prompt_tokens)} / 输出 ${this.formatNumber(this.summary.completion_tokens)}`, type: 'green', icon: 'el-icon-coin' },
|
{ label: 'Token消耗', value: this.formatNumber(this.summary.total_tokens), unit: 'Token', desc: `输入 ${this.formatNumber(this.summary.prompt_tokens)} Token / 输出 ${this.formatNumber(this.summary.completion_tokens)} Token`, type: 'green', icon: 'el-icon-coin' },
|
||||||
{ label: 'Token总费用', value: `¥${this.formatAmount(this.summary.amount)}`, desc: '按调用记录汇总', type: 'orange', icon: 'el-icon-wallet' }
|
{ label: 'Token总费用', value: `¥${this.formatAmount(this.summary.amount)}`, unit: '元', desc: '按调用记录汇总', type: 'orange', icon: 'el-icon-wallet' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
filterTimeText() {
|
filterTimeText() {
|
||||||
@ -245,7 +265,7 @@ export default {
|
|||||||
return Number(value || 0).toLocaleString()
|
return Number(value || 0).toLocaleString()
|
||||||
},
|
},
|
||||||
formatAmount(value) {
|
formatAmount(value) {
|
||||||
return Number(value || 0).toFixed(6).replace(/0+$/, '').replace(/\.$/, '.00')
|
return Number(value || 0).toFixed(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,6 +420,13 @@ export default {
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stat-unit {
|
||||||
|
margin-left: 6px;
|
||||||
|
color: #667085;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
.stat-desc {
|
.stat-desc {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
color: #98a2b3;
|
color: #98a2b3;
|
||||||
@ -505,6 +532,19 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.usage-number,
|
||||||
|
.usage-amount {
|
||||||
|
color: #344054;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.usage-unit {
|
||||||
|
margin-left: 4px;
|
||||||
|
color: #98a2b3;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
.stat-grid {
|
.stat-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|||||||
@ -191,12 +191,12 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const res = await reqApikeyList(params)
|
const res = await reqApikeyList(params)
|
||||||
if (res && res.status === false) {
|
if (res && res.status === false) {
|
||||||
throw new Error(res.msg || '获取 API Key 列表失败')
|
// throw new Error(res.msg || '获取 API Key 列表失败')
|
||||||
}
|
}
|
||||||
this.tokenList = this.normalizeApiKeyList(res)
|
this.tokenList = this.normalizeApiKeyList(res)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.tokenList = []
|
this.tokenList = []
|
||||||
this.$message.error(error && error.message ? error.message : '获取 API Key 列表失败')
|
// this.$message.error(error && error.message ? error.message : '获取 API Key 列表失败')
|
||||||
} finally {
|
} finally {
|
||||||
this.tableLoading = false
|
this.tableLoading = false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -281,7 +281,7 @@ export default {
|
|||||||
return Number(value || 0).toLocaleString()
|
return Number(value || 0).toLocaleString()
|
||||||
},
|
},
|
||||||
formatAmount(value) {
|
formatAmount(value) {
|
||||||
return Number(value || 0).toFixed(6).replace(/0+$/, '').replace(/\.$/, '.00')
|
return Number(value || 0).toFixed(2)
|
||||||
},
|
},
|
||||||
initCharts() {
|
initCharts() {
|
||||||
if (this.$refs.tokenRatioChart && !this.tokenRatioChart) {
|
if (this.$refs.tokenRatioChart && !this.tokenRatioChart) {
|
||||||
@ -373,8 +373,8 @@ export default {
|
|||||||
return [
|
return [
|
||||||
item.name,
|
item.name,
|
||||||
`${this.formatNumber(item.value)} Token`,
|
`${this.formatNumber(item.value)} Token`,
|
||||||
`调用次数:${this.formatNumber(rankItem.request_count)}`,
|
`调用次数:${this.formatNumber(rankItem.request_count)} 次`,
|
||||||
`预估费用:¥ ${this.formatAmount(rankItem.amount)}`
|
`预估费用:¥ ${this.formatAmount(rankItem.amount)} 元`
|
||||||
].join('<br/>')
|
].join('<br/>')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user