"frontend/src/api/vscode:/vscode.git/clone" did not exist on "000e621eb648b3ecab36fc9ebd980c60be92dfa3"
Commit cb72262a authored by shaw's avatar shaw
Browse files

Merge PR #166: feat: 图片生成计费功能

parents f5603b07 195e227c
...@@ -418,7 +418,8 @@ export default { ...@@ -418,7 +418,8 @@ export default {
exportExcelFailed: '使用数据导出失败', exportExcelFailed: '使用数据导出失败',
billingType: '消费类型', billingType: '消费类型',
balance: '余额', balance: '余额',
subscription: '订阅' subscription: '订阅',
imageUnit: ''
}, },
// Redeem // Redeem
...@@ -926,6 +927,10 @@ export default { ...@@ -926,6 +927,10 @@ export default {
defaultValidityDays: '默认有效期(天)', defaultValidityDays: '默认有效期(天)',
validityHint: '分配给用户时订阅的有效天数', validityHint: '分配给用户时订阅的有效天数',
noLimit: '无限制' noLimit: '无限制'
},
imagePricing: {
title: '图片生成计费',
description: '配置 gemini-3-pro-image 模型的图片生成价格,留空则使用默认价格'
} }
}, },
......
...@@ -259,6 +259,10 @@ export interface Group { ...@@ -259,6 +259,10 @@ export interface Group {
daily_limit_usd: number | null daily_limit_usd: number | null
weekly_limit_usd: number | null weekly_limit_usd: number | null
monthly_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 account_count?: number
created_at: string created_at: string
updated_at: string updated_at: string
...@@ -561,6 +565,11 @@ export interface UsageLog { ...@@ -561,6 +565,11 @@ export interface UsageLog {
stream: boolean stream: boolean
duration_ms: number duration_ms: number
first_token_ms: number | null first_token_ms: number | null
// 图片生成字段
image_count: number
image_size: string | null
created_at: string created_at: string
user?: User user?: User
......
...@@ -358,6 +358,51 @@ ...@@ -358,6 +358,51 @@
</div> </div>
</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> </form>
<template #footer> <template #footer>
...@@ -558,6 +603,51 @@ ...@@ -558,6 +603,51 @@
</div> </div>
</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> </form>
<template #footer> <template #footer>
...@@ -727,7 +817,11 @@ const createForm = reactive({ ...@@ -727,7 +817,11 @@ const createForm = reactive({
subscription_type: 'standard' as SubscriptionType, subscription_type: 'standard' as SubscriptionType,
daily_limit_usd: null as number | null, daily_limit_usd: null as number | null,
weekly_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({ const editForm = reactive({
...@@ -740,7 +834,11 @@ const editForm = reactive({ ...@@ -740,7 +834,11 @@ const editForm = reactive({
subscription_type: 'standard' as SubscriptionType, subscription_type: 'standard' as SubscriptionType,
daily_limit_usd: null as number | null, daily_limit_usd: null as number | null,
weekly_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 = () => { ...@@ -807,6 +905,9 @@ const closeCreateModal = () => {
createForm.daily_limit_usd = null createForm.daily_limit_usd = null
createForm.weekly_limit_usd = null createForm.weekly_limit_usd = null
createForm.monthly_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 () => { const handleCreateGroup = async () => {
...@@ -845,6 +946,9 @@ const handleEdit = (group: Group) => { ...@@ -845,6 +946,9 @@ const handleEdit = (group: Group) => {
editForm.daily_limit_usd = group.daily_limit_usd editForm.daily_limit_usd = group.daily_limit_usd
editForm.weekly_limit_usd = group.weekly_limit_usd editForm.weekly_limit_usd = group.weekly_limit_usd
editForm.monthly_limit_usd = group.monthly_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 showEditModal.value = true
} }
......
...@@ -171,7 +171,26 @@ ...@@ -171,7 +171,26 @@
</template> </template>
<template #cell-tokens="{ row }"> <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"> <div class="space-y-1.5 text-sm">
<!-- Input / Output Tokens --> <!-- Input / Output Tokens -->
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment