mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-05-05 21:50:44 +08:00
feat(channel): 模型标签输入 + $/MTok 价格单位 + 左开右闭区间 + i18n
- 模型输入改为标签列表(输入回车添加,支持粘贴批量导入) - 价格显示单位改为 $/MTok(每百万 token),提交时自动转换 - Token 模式增加图片输出价格字段(适配 Gemini 图片模型按 token 计费) - 区间边界改为左开右闭 (min, max],右边界包含 - 默认价格作为未命中区间时的回退价格 - 添加完整中英文 i18n 翻译
This commit is contained in:
@@ -1,125 +1,66 @@
|
||||
<template>
|
||||
<div class="flex items-start gap-2 rounded border border-gray-200 bg-white p-2 dark:border-dark-500 dark:bg-dark-700">
|
||||
<!-- Token mode: context range + prices -->
|
||||
<!-- Token mode: context range + prices ($/MTok) -->
|
||||
<template v-if="mode === 'token'">
|
||||
<div class="w-20">
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.minTokens', 'Min (K)') }}</label>
|
||||
<input
|
||||
:value="interval.min_tokens"
|
||||
@input="emitField('min_tokens', toInt(($event.target as HTMLInputElement).value))"
|
||||
type="number"
|
||||
min="0"
|
||||
class="input mt-0.5 text-xs"
|
||||
/>
|
||||
<label class="text-xs text-gray-400">Min</label>
|
||||
<input :value="interval.min_tokens" @input="emitField('min_tokens', toInt(($event.target as HTMLInputElement).value))"
|
||||
type="number" min="0" class="input mt-0.5 text-xs" />
|
||||
</div>
|
||||
<div class="w-20">
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.maxTokens', 'Max (K)') }}</label>
|
||||
<input
|
||||
:value="interval.max_tokens ?? ''"
|
||||
@input="emitField('max_tokens', toIntOrNull(($event.target as HTMLInputElement).value))"
|
||||
type="number"
|
||||
min="0"
|
||||
class="input mt-0.5 text-xs"
|
||||
:placeholder="'∞'"
|
||||
/>
|
||||
<label class="text-xs text-gray-400">Max <span class="text-gray-300">(含)</span></label>
|
||||
<input :value="interval.max_tokens ?? ''" @input="emitField('max_tokens', toIntOrNull(($event.target as HTMLInputElement).value))"
|
||||
type="number" min="0" class="input mt-0.5 text-xs" :placeholder="'∞'" />
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.inputPrice', 'Input') }}</label>
|
||||
<input
|
||||
:value="interval.input_price"
|
||||
@input="emitField('input_price', ($event.target as HTMLInputElement).value)"
|
||||
type="number"
|
||||
step="any" min="0"
|
||||
class="input mt-0.5 text-xs"
|
||||
/>
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.inputPrice', '输入') }} <span class="text-gray-300">$/M</span></label>
|
||||
<input :value="interval.input_price" @input="emitField('input_price', ($event.target as HTMLInputElement).value)"
|
||||
type="number" step="any" min="0" class="input mt-0.5 text-xs" />
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.outputPrice', 'Output') }}</label>
|
||||
<input
|
||||
:value="interval.output_price"
|
||||
@input="emitField('output_price', ($event.target as HTMLInputElement).value)"
|
||||
type="number"
|
||||
step="any" min="0"
|
||||
class="input mt-0.5 text-xs"
|
||||
/>
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.outputPrice', '输出') }} <span class="text-gray-300">$/M</span></label>
|
||||
<input :value="interval.output_price" @input="emitField('output_price', ($event.target as HTMLInputElement).value)"
|
||||
type="number" step="any" min="0" class="input mt-0.5 text-xs" />
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.cacheWritePrice', 'Cache W') }}</label>
|
||||
<input
|
||||
:value="interval.cache_write_price"
|
||||
@input="emitField('cache_write_price', ($event.target as HTMLInputElement).value)"
|
||||
type="number"
|
||||
step="any" min="0"
|
||||
class="input mt-0.5 text-xs"
|
||||
/>
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.cacheWritePrice', '缓存W') }} <span class="text-gray-300">$/M</span></label>
|
||||
<input :value="interval.cache_write_price" @input="emitField('cache_write_price', ($event.target as HTMLInputElement).value)"
|
||||
type="number" step="any" min="0" class="input mt-0.5 text-xs" />
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.cacheReadPrice', 'Cache R') }}</label>
|
||||
<input
|
||||
:value="interval.cache_read_price"
|
||||
@input="emitField('cache_read_price', ($event.target as HTMLInputElement).value)"
|
||||
type="number"
|
||||
step="any" min="0"
|
||||
class="input mt-0.5 text-xs"
|
||||
/>
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.cacheReadPrice', '缓存R') }} <span class="text-gray-300">$/M</span></label>
|
||||
<input :value="interval.cache_read_price" @input="emitField('cache_read_price', ($event.target as HTMLInputElement).value)"
|
||||
type="number" step="any" min="0" class="input mt-0.5 text-xs" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Per-request / Image mode: tier label + price -->
|
||||
<!-- Per-request / Image mode: tier label + context range + price -->
|
||||
<template v-else>
|
||||
<div class="w-24">
|
||||
<label class="text-xs text-gray-400">
|
||||
{{ mode === 'image'
|
||||
? t('admin.channels.form.resolution', 'Resolution')
|
||||
: t('admin.channels.form.tierLabel', 'Tier')
|
||||
}}
|
||||
{{ mode === 'image' ? t('admin.channels.form.resolution', '分辨率') : t('admin.channels.form.tierLabel', '层级') }}
|
||||
</label>
|
||||
<input
|
||||
:value="interval.tier_label"
|
||||
@input="emitField('tier_label', ($event.target as HTMLInputElement).value)"
|
||||
type="text"
|
||||
class="input mt-0.5 text-xs"
|
||||
:placeholder="mode === 'image' ? '1K / 2K / 4K' : ''"
|
||||
/>
|
||||
<input :value="interval.tier_label" @input="emitField('tier_label', ($event.target as HTMLInputElement).value)"
|
||||
type="text" class="input mt-0.5 text-xs" :placeholder="mode === 'image' ? '1K / 2K / 4K' : ''" />
|
||||
</div>
|
||||
<div class="w-20">
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.minTokens', 'Min') }}</label>
|
||||
<input
|
||||
:value="interval.min_tokens"
|
||||
@input="emitField('min_tokens', toInt(($event.target as HTMLInputElement).value))"
|
||||
type="number"
|
||||
min="0"
|
||||
class="input mt-0.5 text-xs"
|
||||
/>
|
||||
<label class="text-xs text-gray-400">Min</label>
|
||||
<input :value="interval.min_tokens" @input="emitField('min_tokens', toInt(($event.target as HTMLInputElement).value))"
|
||||
type="number" min="0" class="input mt-0.5 text-xs" />
|
||||
</div>
|
||||
<div class="w-20">
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.maxTokens', 'Max') }}</label>
|
||||
<input
|
||||
:value="interval.max_tokens ?? ''"
|
||||
@input="emitField('max_tokens', toIntOrNull(($event.target as HTMLInputElement).value))"
|
||||
type="number"
|
||||
min="0"
|
||||
class="input mt-0.5 text-xs"
|
||||
:placeholder="'∞'"
|
||||
/>
|
||||
<label class="text-xs text-gray-400">Max <span class="text-gray-300">(含)</span></label>
|
||||
<input :value="interval.max_tokens ?? ''" @input="emitField('max_tokens', toIntOrNull(($event.target as HTMLInputElement).value))"
|
||||
type="number" min="0" class="input mt-0.5 text-xs" :placeholder="'∞'" />
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.perRequestPrice', 'Price') }}</label>
|
||||
<input
|
||||
:value="interval.per_request_price"
|
||||
@input="emitField('per_request_price', ($event.target as HTMLInputElement).value)"
|
||||
type="number"
|
||||
step="any" min="0"
|
||||
class="input mt-0.5 text-xs"
|
||||
/>
|
||||
<label class="text-xs text-gray-400">{{ t('admin.channels.form.perRequestPrice', '单次价格') }} <span class="text-gray-300">$</span></label>
|
||||
<input :value="interval.per_request_price" @input="emitField('per_request_price', ($event.target as HTMLInputElement).value)"
|
||||
type="number" step="any" min="0" class="input mt-0.5 text-xs" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
@click="emit('remove')"
|
||||
class="mt-4 rounded p-0.5 text-gray-400 hover:text-red-500"
|
||||
>
|
||||
<button type="button" @click="emit('remove')" class="mt-4 rounded p-0.5 text-gray-400 hover:text-red-500">
|
||||
<Icon name="x" size="sm" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user