diff --git a/apps/aether-gateway/src/tests/control/admin/providers.rs b/apps/aether-gateway/src/tests/control/admin/providers.rs
index e65167bd8..da687e1cf 100644
--- a/apps/aether-gateway/src/tests/control/admin/providers.rs
+++ b/apps/aether-gateway/src/tests/control/admin/providers.rs
@@ -780,6 +780,14 @@ async fn gateway_updates_admin_provider_locally_with_trusted_admin_principal() {
let provider_catalog_repository = Arc::new(InMemoryProviderCatalogReadRepository::seed(
vec![
sample_provider("provider-openai", "openai", 10)
+ .with_billing_fields(
+ Some("free_tier".to_string()),
+ None,
+ None,
+ Some(30),
+ None,
+ None,
+ )
.with_transport_fields(
true,
false,
@@ -974,6 +982,7 @@ async fn gateway_updates_admin_provider_locally_with_trusted_admin_principal() {
.iter()
.find(|provider| provider.id == "provider-openai")
.expect("provider should exist");
+ assert_eq!(updated_provider.billing_type.as_deref(), Some("free_tier"));
assert_eq!(
updated_provider.request_timeout_secs,
Some(aether_contracts::MAX_EXECUTION_REQUEST_TIMEOUT_SECS as f64)
@@ -1106,6 +1115,7 @@ async fn gateway_creates_admin_provider_locally_with_trusted_admin_principal() {
.find(|provider| provider.id == "provider-existing")
.expect("existing provider should remain");
assert_eq!(created.provider_type, "codex");
+ assert_eq!(created.billing_type.as_deref(), Some("pay_as_you_go"));
assert_eq!(created.provider_priority, 0);
assert_eq!(existing.provider_priority, 1);
assert_eq!(created.website.as_deref(), Some("https://codex.example"));
diff --git a/frontend/src/features/providers/components/ProviderFormDialog.vue b/frontend/src/features/providers/components/ProviderFormDialog.vue
index b1f90f2a5..791628cd5 100644
--- a/frontend/src/features/providers/components/ProviderFormDialog.vue
+++ b/frontend/src/features/providers/components/ProviderFormDialog.vue
@@ -123,39 +123,11 @@
-
+
-
-
- {{ legacyT('计费与限流') }}
-
-
- {{ legacyT('请求配置') }}
-
-
-
-
-
-
-
-
+
+ {{ legacyT('请求配置') }}
+
@@ -229,49 +201,6 @@
/>
-
-
-
@@ -426,7 +355,6 @@ import {
} from '@/api/endpoints'
import { parseApiError } from '@/utils/errorParser'
import { parseNumberInput } from '@/utils/form'
-import { dateTimeLocalToRfc3339, formatDateTimeLocalInput } from '@/utils/date'
const props = defineProps<{
modelValue: boolean
@@ -468,12 +396,6 @@ const form = ref({
provider_type: 'custom' as ProviderType,
description: '',
website: '',
- // 计费配置
- billing_type: 'pay_as_you_go' as 'monthly_quota' | 'pay_as_you_go' | 'free_tier',
- monthly_quota_usd: undefined as number | undefined,
- quota_reset_day: 30,
- quota_last_reset_at: '', // 周期开始时间
- quota_expires_at: '',
provider_priority: 100,
keep_priority_on_conversion: false, // 格式转换时是否保持优先级
// 状态配置
@@ -504,11 +426,6 @@ function resetForm() {
provider_type: 'custom',
description: '',
website: '',
- billing_type: 'pay_as_you_go',
- monthly_quota_usd: undefined,
- quota_reset_day: 30,
- quota_last_reset_at: '',
- quota_expires_at: '',
provider_priority: defaultPriority.value,
keep_priority_on_conversion: false,
is_active: true,
@@ -542,11 +459,6 @@ function loadProviderData() {
provider_type: props.provider.provider_type || 'custom',
description: props.provider.description || '',
website: props.provider.website || '',
- billing_type: (props.provider.billing_type as 'monthly_quota' | 'pay_as_you_go' | 'free_tier') || 'pay_as_you_go',
- monthly_quota_usd: props.provider.monthly_quota_usd || undefined,
- quota_reset_day: props.provider.quota_reset_day || 30,
- quota_last_reset_at: formatDateTimeLocalInput(props.provider.quota_last_reset_at),
- quota_expires_at: formatDateTimeLocalInput(props.provider.quota_expires_at),
provider_priority: props.provider.provider_priority || 999,
keep_priority_on_conversion: props.provider.keep_priority_on_conversion ?? false,
is_active: props.provider.is_active,
@@ -595,23 +507,6 @@ watch(() => form.value.provider_type, () => {
// 提交表单
const handleSubmit = async () => {
- // 月卡类型必须设置周期开始时间
- if (form.value.billing_type === 'monthly_quota' && !form.value.quota_last_reset_at) {
- showError(legacyT('月卡类型必须设置周期开始时间'), legacyT('验证失败'))
- return
- }
-
- const quotaLastResetAt = dateTimeLocalToRfc3339(form.value.quota_last_reset_at)
- if (form.value.billing_type === 'monthly_quota' && !quotaLastResetAt) {
- showError(legacyT('周期开始时间必须是合法时间'), legacyT('验证失败'))
- return
- }
- const quotaExpiresAt = dateTimeLocalToRfc3339(form.value.quota_expires_at)
- if (form.value.quota_expires_at && !quotaExpiresAt) {
- showError(legacyT('过期时间必须是合法时间'), legacyT('验证失败'))
- return
- }
-
loading.value = true
try {
const currentPoolAdvanced = normalizePoolAdvancedConfig(props.provider?.pool_advanced)
@@ -620,11 +515,6 @@ const handleSubmit = async () => {
provider_type: form.value.provider_type,
description: form.value.description || undefined,
website: form.value.website || undefined,
- billing_type: form.value.billing_type,
- monthly_quota_usd: form.value.monthly_quota_usd,
- quota_reset_day: form.value.quota_reset_day,
- quota_last_reset_at: quotaLastResetAt,
- quota_expires_at: quotaExpiresAt,
keep_priority_on_conversion: form.value.keep_priority_on_conversion,
responses_websocket_enabled: form.value.responses_websocket_enabled,
is_active: form.value.is_active,
diff --git a/frontend/src/features/providers/components/__tests__/ProviderFormDialog.transfer-limits.spec.ts b/frontend/src/features/providers/components/__tests__/ProviderFormDialog.transfer-limits.spec.ts
index 3144dce81..f0d8f7d69 100644
--- a/frontend/src/features/providers/components/__tests__/ProviderFormDialog.transfer-limits.spec.ts
+++ b/frontend/src/features/providers/components/__tests__/ProviderFormDialog.transfer-limits.spec.ts
@@ -137,6 +137,36 @@ function clickButton(text: string) {
button.click()
}
+const billingFieldNames = [
+ 'billing_type',
+ 'monthly_quota_usd',
+ 'quota_reset_day',
+ 'quota_last_reset_at',
+ 'quota_expires_at',
+] as const
+
+function expectBillingConfigurationHidden() {
+ for (const text of [
+ '计费类型',
+ '月卡额度',
+ '按量付费',
+ '免费套餐',
+ '周期额度 (USD)',
+ '重置周期 (天)',
+ '周期开始时间',
+ '过期时间',
+ ]) {
+ expect(document.body.textContent).not.toContain(text)
+ }
+}
+
+function expectBillingFieldsOmitted(payload: unknown) {
+ expect(payload).toEqual(expect.any(Object))
+ for (const field of billingFieldNames) {
+ expect(payload).not.toHaveProperty(field)
+ }
+}
+
beforeEach(() => {
endpointMocks.createProvider.mockReset()
endpointMocks.createProvider.mockResolvedValue({ id: 'provider-new', name: 'New Provider' })
@@ -226,6 +256,41 @@ describe('ProviderFormDialog transfer limits', () => {
})
})
+describe('ProviderFormDialog billing configuration', () => {
+ it('hides billing configuration and omits billing fields when creating', async () => {
+ mountDialog(null)
+ await settle()
+
+ expectBillingConfigurationHidden()
+
+ await setInput('#name', 'New Provider')
+ clickButton('创建')
+ await settle()
+
+ expect(endpointMocks.createProvider).toHaveBeenCalledTimes(1)
+ expectBillingFieldsOmitted(endpointMocks.createProvider.mock.calls[0]?.[0])
+ })
+
+ it('hides existing monthly quota configuration and preserves it when editing', async () => {
+ mountDialog(makeProvider({
+ billing_type: 'monthly_quota',
+ monthly_quota_usd: 200,
+ quota_reset_day: 30,
+ quota_last_reset_at: '2026-08-01T00:00:00Z',
+ quota_expires_at: '2026-09-01T00:00:00Z',
+ }))
+ await settle()
+
+ expectBillingConfigurationHidden()
+
+ clickButton('保存')
+ await settle()
+
+ expect(endpointMocks.updateProvider).toHaveBeenCalledTimes(1)
+ expectBillingFieldsOmitted(endpointMocks.updateProvider.mock.calls[0]?.[1])
+ })
+})
+
describe('ProviderFormDialog provider types', () => {
it('creates an experimental Claude Code provider from the add dialog', async () => {
mountDialog(null)
diff --git a/frontend/src/views/public/guide/ConceptsGuide.vue b/frontend/src/views/public/guide/ConceptsGuide.vue
index 0f7ecdc99..dbdfc7700 100644
--- a/frontend/src/views/public/guide/ConceptsGuide.vue
+++ b/frontend/src/views/public/guide/ConceptsGuide.vue
@@ -68,14 +68,6 @@ import { BookOpen } from 'lucide-vue-next'
- 提供商类型:自定义或反代;一般自定义即可,反代请进入反代章节。
- -
- 计费类型:
-
- - 按量付费:持续使用
- - 月卡额度:按周期(天)限额
- - 免费套餐:不计入成本即倍率为0
-
-
- 最大重试次数:在缓存亲和调度模式下,首次请求失败后的重试次数。
-
超时时间:
diff --git a/frontend/src/views/public/guide/content/concepts.md b/frontend/src/views/public/guide/content/concepts.md
index 20c56a60b..1fa780504 100644
--- a/frontend/src/views/public/guide/content/concepts.md
+++ b/frontend/src/views/public/guide/content/concepts.md
@@ -15,16 +15,12 @@
## 2. 添加提供商
1. **提供商类型**: 自定义或反代; 一般自定义即可, 反代请进入反代章节
-2. **计费类型**:
- - 按量付费: 持续使用
- - 月卡额度: 按周期(天)限额
- - 免费套餐: 不计入成本即倍率为0
-3. **最大重试次数**
+2. **最大重试次数**
- 在缓存亲和调度模式下, 首次请求失败后的重试次数。
-4. **超时时间**
+3. **超时时间**
- 流式首字超时时间: 流式请求收到首字前的超时时间
- 非流请求超时时间: 非流请求的总超时时间
-5. **保持优先级**
+4. **保持优先级**
- 通过格式转换的请求, 是否保持当前优先级。
