Merge PR #166: feat: 图片生成计费功能
This commit is contained in:
@@ -35,7 +35,16 @@
|
||||
</template>
|
||||
|
||||
<template #cell-tokens="{ row }">
|
||||
<div class="space-y-1 text-sm">
|
||||
<!-- 图片生成请求 -->
|
||||
<div v-if="row.image_count > 0" class="flex items-center gap-1.5">
|
||||
<svg class="h-4 w-4 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<span class="font-medium text-gray-900 dark:text-white">{{ row.image_count }}{{ t('usage.imageUnit') }}</span>
|
||||
<span class="text-gray-400">({{ row.image_size || '2K' }})</span>
|
||||
</div>
|
||||
<!-- Token 请求 -->
|
||||
<div v-else class="space-y-1 text-sm">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="inline-flex items-center gap-1">
|
||||
<Icon name="arrowDown" size="sm" class="h-3.5 w-3.5 text-emerald-500" />
|
||||
|
||||
@@ -421,7 +421,8 @@ export default {
|
||||
exportExcelFailed: 'Failed to export usage data',
|
||||
billingType: 'Billing',
|
||||
balance: 'Balance',
|
||||
subscription: 'Subscription'
|
||||
subscription: 'Subscription',
|
||||
imageUnit: ' images'
|
||||
},
|
||||
|
||||
// Redeem
|
||||
@@ -849,6 +850,10 @@ export default {
|
||||
defaultValidityDays: 'Default Validity (Days)',
|
||||
validityHint: 'Number of days the subscription is valid when assigned to a user',
|
||||
noLimit: 'No limit'
|
||||
},
|
||||
imagePricing: {
|
||||
title: 'Image Generation Pricing',
|
||||
description: 'Configure pricing for gemini-3-pro-image model. Leave empty to use default prices.'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -418,7 +418,8 @@ export default {
|
||||
exportExcelFailed: '使用数据导出失败',
|
||||
billingType: '消费类型',
|
||||
balance: '余额',
|
||||
subscription: '订阅'
|
||||
subscription: '订阅',
|
||||
imageUnit: '张'
|
||||
},
|
||||
|
||||
// Redeem
|
||||
@@ -926,6 +927,10 @@ export default {
|
||||
defaultValidityDays: '默认有效期(天)',
|
||||
validityHint: '分配给用户时订阅的有效天数',
|
||||
noLimit: '无限制'
|
||||
},
|
||||
imagePricing: {
|
||||
title: '图片生成计费',
|
||||
description: '配置 gemini-3-pro-image 模型的图片生成价格,留空则使用默认价格'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -259,6 +259,10 @@ export interface Group {
|
||||
daily_limit_usd: number | null
|
||||
weekly_limit_usd: number | null
|
||||
monthly_limit_usd: number | null
|
||||
// 图片生成计费配置(仅 antigravity 平台使用)
|
||||
image_price_1k: number | null
|
||||
image_price_2k: number | null
|
||||
image_price_4k: number | null
|
||||
account_count?: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
@@ -561,6 +565,11 @@ export interface UsageLog {
|
||||
stream: boolean
|
||||
duration_ms: number
|
||||
first_token_ms: number | null
|
||||
|
||||
// 图片生成字段
|
||||
image_count: number
|
||||
image_size: string | null
|
||||
|
||||
created_at: string
|
||||
|
||||
user?: User
|
||||
|
||||
@@ -358,6 +358,51 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图片生成计费配置(antigravity 和 gemini 平台) -->
|
||||
<div v-if="createForm.platform === 'antigravity' || createForm.platform === 'gemini'" class="border-t pt-4">
|
||||
<label class="block mb-2 font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.groups.imagePricing.title') }}
|
||||
</label>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mb-3">
|
||||
{{ t('admin.groups.imagePricing.description') }}
|
||||
</p>
|
||||
<div class="grid grid-cols-3 gap-3">
|
||||
<div>
|
||||
<label class="input-label">1K ($)</label>
|
||||
<input
|
||||
v-model.number="createForm.image_price_1k"
|
||||
type="number"
|
||||
step="0.001"
|
||||
min="0"
|
||||
class="input"
|
||||
placeholder="0.134"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">2K ($)</label>
|
||||
<input
|
||||
v-model.number="createForm.image_price_2k"
|
||||
type="number"
|
||||
step="0.001"
|
||||
min="0"
|
||||
class="input"
|
||||
placeholder="0.134"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">4K ($)</label>
|
||||
<input
|
||||
v-model.number="createForm.image_price_4k"
|
||||
type="number"
|
||||
step="0.001"
|
||||
min="0"
|
||||
class="input"
|
||||
placeholder="0.268"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<template #footer>
|
||||
@@ -558,6 +603,51 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图片生成计费配置(antigravity 和 gemini 平台) -->
|
||||
<div v-if="editForm.platform === 'antigravity' || editForm.platform === 'gemini'" class="border-t pt-4">
|
||||
<label class="block mb-2 font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.groups.imagePricing.title') }}
|
||||
</label>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400 mb-3">
|
||||
{{ t('admin.groups.imagePricing.description') }}
|
||||
</p>
|
||||
<div class="grid grid-cols-3 gap-3">
|
||||
<div>
|
||||
<label class="input-label">1K ($)</label>
|
||||
<input
|
||||
v-model.number="editForm.image_price_1k"
|
||||
type="number"
|
||||
step="0.001"
|
||||
min="0"
|
||||
class="input"
|
||||
placeholder="0.134"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">2K ($)</label>
|
||||
<input
|
||||
v-model.number="editForm.image_price_2k"
|
||||
type="number"
|
||||
step="0.001"
|
||||
min="0"
|
||||
class="input"
|
||||
placeholder="0.134"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">4K ($)</label>
|
||||
<input
|
||||
v-model.number="editForm.image_price_4k"
|
||||
type="number"
|
||||
step="0.001"
|
||||
min="0"
|
||||
class="input"
|
||||
placeholder="0.268"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<template #footer>
|
||||
@@ -727,7 +817,11 @@ const createForm = reactive({
|
||||
subscription_type: 'standard' as SubscriptionType,
|
||||
daily_limit_usd: null as number | null,
|
||||
weekly_limit_usd: null as number | null,
|
||||
monthly_limit_usd: null as number | null
|
||||
monthly_limit_usd: null as number | null,
|
||||
// 图片生成计费配置(仅 antigravity 平台使用)
|
||||
image_price_1k: null as number | null,
|
||||
image_price_2k: null as number | null,
|
||||
image_price_4k: null as number | null
|
||||
})
|
||||
|
||||
const editForm = reactive({
|
||||
@@ -740,7 +834,11 @@ const editForm = reactive({
|
||||
subscription_type: 'standard' as SubscriptionType,
|
||||
daily_limit_usd: null as number | null,
|
||||
weekly_limit_usd: null as number | null,
|
||||
monthly_limit_usd: null as number | null
|
||||
monthly_limit_usd: null as number | null,
|
||||
// 图片生成计费配置(仅 antigravity 平台使用)
|
||||
image_price_1k: null as number | null,
|
||||
image_price_2k: null as number | null,
|
||||
image_price_4k: null as number | null
|
||||
})
|
||||
|
||||
// 根据分组类型返回不同的删除确认消息
|
||||
@@ -807,6 +905,9 @@ const closeCreateModal = () => {
|
||||
createForm.daily_limit_usd = null
|
||||
createForm.weekly_limit_usd = null
|
||||
createForm.monthly_limit_usd = null
|
||||
createForm.image_price_1k = null
|
||||
createForm.image_price_2k = null
|
||||
createForm.image_price_4k = null
|
||||
}
|
||||
|
||||
const handleCreateGroup = async () => {
|
||||
@@ -845,6 +946,9 @@ const handleEdit = (group: Group) => {
|
||||
editForm.daily_limit_usd = group.daily_limit_usd
|
||||
editForm.weekly_limit_usd = group.weekly_limit_usd
|
||||
editForm.monthly_limit_usd = group.monthly_limit_usd
|
||||
editForm.image_price_1k = group.image_price_1k
|
||||
editForm.image_price_2k = group.image_price_2k
|
||||
editForm.image_price_4k = group.image_price_4k
|
||||
showEditModal.value = true
|
||||
}
|
||||
|
||||
|
||||
@@ -171,7 +171,26 @@
|
||||
</template>
|
||||
|
||||
<template #cell-tokens="{ row }">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<!-- 图片生成请求 -->
|
||||
<div v-if="row.image_count > 0" class="flex items-center gap-1.5">
|
||||
<svg
|
||||
class="h-4 w-4 text-indigo-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="font-medium text-gray-900 dark:text-white">{{ row.image_count }}{{ $t('usage.imageUnit') }}</span>
|
||||
<span class="text-gray-400">({{ row.image_size || '2K' }})</span>
|
||||
</div>
|
||||
<!-- Token 请求 -->
|
||||
<div v-else class="flex items-center gap-1.5">
|
||||
<div class="space-y-1.5 text-sm">
|
||||
<!-- Input / Output Tokens -->
|
||||
<div class="flex items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user