|
52 | 52 | <span class="font-mono">{{ account.max_sessions }}</span> |
53 | 53 | </span> |
54 | 54 | </div> |
| 55 | + |
| 56 | + <!-- RPM 限制(仅 Anthropic OAuth/SetupToken 且启用时显示) --> |
| 57 | + <div v-if="showRpmLimit" class="flex items-center gap-1"> |
| 58 | + <span |
| 59 | + :class="[ |
| 60 | + 'inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[10px] font-medium', |
| 61 | + rpmClass |
| 62 | + ]" |
| 63 | + :title="rpmTooltip" |
| 64 | + > |
| 65 | + <svg class="h-2.5 w-2.5" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> |
| 66 | + <path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" /> |
| 67 | + </svg> |
| 68 | + <span class="font-mono">{{ currentRPM }}</span> |
| 69 | + <span class="text-gray-400 dark:text-gray-500">/</span> |
| 70 | + <span class="font-mono">{{ account.base_rpm }}</span> |
| 71 | + </span> |
| 72 | + </div> |
55 | 73 | </div> |
56 | 74 | </template> |
57 | 75 |
|
@@ -191,6 +209,50 @@ const sessionLimitTooltip = computed(() => { |
191 | 209 | return t('admin.accounts.capacity.sessions.normal', { idle }) |
192 | 210 | }) |
193 | 211 |
|
| 212 | +// 是否显示 RPM 限制 |
| 213 | +const showRpmLimit = computed(() => { |
| 214 | + return ( |
| 215 | + isAnthropicOAuthOrSetupToken.value && |
| 216 | + props.account.base_rpm !== undefined && |
| 217 | + props.account.base_rpm !== null && |
| 218 | + props.account.base_rpm > 0 |
| 219 | + ) |
| 220 | +}) |
| 221 | +
|
| 222 | +// 当前 RPM 计数 |
| 223 | +const currentRPM = computed(() => props.account.current_rpm ?? 0) |
| 224 | +
|
| 225 | +// RPM 状态样式 |
| 226 | +const rpmClass = computed(() => { |
| 227 | + if (!showRpmLimit.value) return '' |
| 228 | +
|
| 229 | + const current = currentRPM.value |
| 230 | + const base = props.account.base_rpm ?? 0 |
| 231 | + if (base <= 0) return 'bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-400' |
| 232 | +
|
| 233 | + const strategy = props.account.rpm_strategy || 'tiered' |
| 234 | + if (strategy === 'tiered') { |
| 235 | + const buffer = props.account.rpm_sticky_buffer ?? Math.max(1, Math.floor(base / 5)) |
| 236 | + if (current >= base + buffer) return 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400' |
| 237 | + if (current >= base) return 'bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400' |
| 238 | + } else { |
| 239 | + if (current >= base) return 'bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400' |
| 240 | + } |
| 241 | + if (current >= base * 0.8) return 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400' |
| 242 | + return 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400' |
| 243 | +}) |
| 244 | +
|
| 245 | +// RPM 提示文字 |
| 246 | +const rpmTooltip = computed(() => { |
| 247 | + if (!showRpmLimit.value) return '' |
| 248 | +
|
| 249 | + const current = currentRPM.value |
| 250 | + const base = props.account.base_rpm ?? 0 |
| 251 | + if (current >= base) return t('admin.accounts.capacity.rpm.full') |
| 252 | + if (current >= base * 0.8) return t('admin.accounts.capacity.rpm.warning') |
| 253 | + return t('admin.accounts.capacity.rpm.normal') |
| 254 | +}) |
| 255 | +
|
194 | 256 | // 格式化费用显示 |
195 | 257 | const formatCost = (value: number | null | undefined) => { |
196 | 258 | if (value === null || value === undefined) return '0' |
|
0 commit comments