fix(frontend): clarify OpenAI Fast/Flex policy rules

This commit is contained in:
InCerryGit
2026-08-16 23:49:21 +08:00
parent baeac1f3de
commit 22fc0cdbf5
5 changed files with 167 additions and 23 deletions
@@ -27,4 +27,30 @@ describe('OpenAI Fast/Flex policy locale keys', () => {
removeUser: 'Remove user'
})
})
it('describes target and other-model actions without whitelist terminology', () => {
expect(zh.admin.settings.openaiFastPolicy).toMatchObject({
tierAll: '全部 tier 值',
modelWhitelist: '目标模型',
fallbackAction: '其他模型处理方式',
summaryTargetModels: '目标模型',
summaryOtherModels: '其他模型'
})
expect(zh.admin.settings.openaiFastPolicy.modelWhitelistHint).toContain(
'留空时“处理方式”应用于全部模型'
)
expect(zh.admin.settings.openaiFastPolicy.modelWhitelistHint).not.toContain('白名单')
expect(en.admin.settings.openaiFastPolicy).toMatchObject({
tierAll: 'All tier values',
modelWhitelist: 'Target models',
fallbackAction: 'Other models action',
summaryTargetModels: 'Target models',
summaryOtherModels: 'Other models'
})
expect(en.admin.settings.openaiFastPolicy.modelWhitelistHint).toContain(
'Leave empty to apply Action to all models'
)
expect(en.admin.settings.openaiFastPolicy.modelWhitelistHint).not.toContain('whitelist')
})
})
+17 -8
View File
@@ -1173,7 +1173,7 @@ export default {
addRule: 'Add rule',
saveHint: 'Saved together with system settings (click the global Save button at the bottom of the page).',
serviceTier: 'service_tier match',
tierAll: 'All tiers',
tierAll: 'All tier values',
tierPriority: 'priority (fast)',
tierFlex: 'flex',
action: 'Action',
@@ -1196,13 +1196,22 @@ export default {
errorMessage: 'Error message',
errorMessagePlaceholder: 'Custom error message when blocked',
errorMessageHint: 'Leave empty for the default message.',
modelWhitelist: 'Model whitelist',
modelWhitelistHint: 'Leave empty to apply to all models. Supports exact match and wildcard prefix (e.g., gpt-5.5*).',
modelPatternPlaceholder: 'e.g., gpt-5.5 or gpt-5.5*',
addModelPattern: 'Add model pattern',
fallbackAction: 'Fallback action',
fallbackActionHint: 'Action for models not matching the whitelist.',
fallbackErrorMessagePlaceholder: 'Custom error message when non-whitelisted models are blocked'
modelWhitelist: 'Target models',
modelWhitelistHint: 'Models in this list use Action; models outside it use Other models action. Leave empty to apply Action to all models. Supports exact matches and wildcard prefixes (e.g., gpt-5.6*).',
modelPatternPlaceholder: 'e.g., gpt-5.6-sol or gpt-5.6*',
addModelPattern: 'Add target model',
fallbackAction: 'Other models action',
fallbackActionHint: 'Applies only to models outside the target list.',
fallbackErrorMessagePlaceholder: 'Custom error message when other models are blocked',
summaryTargetModels: 'Target models',
summaryAllModels: 'All models',
summaryOtherModels: 'Other models',
summaryAction: {
pass: 'Pass',
filter: 'Filter',
block: 'Block',
force_priority: 'Force priority'
}
},
wechatConnect: {
title: 'WeChat Connect',
+17 -8
View File
@@ -1167,7 +1167,7 @@ export default {
addRule: '新增规则',
saveHint: '保存时随系统设置一起提交(点击页面底部「保存」按钮)。',
serviceTier: 'service_tier 匹配',
tierAll: '全部 tier',
tierAll: '全部 tier 值',
tierPriority: 'priority(fast)',
tierFlex: 'flex',
action: '处理方式',
@@ -1190,13 +1190,22 @@ export default {
errorMessage: '错误消息',
errorMessagePlaceholder: '拦截时返回的自定义错误消息',
errorMessageHint: '留空则使用默认错误消息。',
modelWhitelist: '模型白名单',
modelWhitelistHint: '留空表示对所有模型生效;支持精确匹配与通配符(如 gpt-5.5*)。',
modelPatternPlaceholder: '例如: gpt-5.5 或 gpt-5.5*',
addModelPattern: '添加模型规则',
fallbackAction: '未匹配模型处理方式',
fallbackActionHint: '当请求模型不在白名单中时的处理方式。',
fallbackErrorMessagePlaceholder: '未匹配模型被拦截时返回的自定义错误消息'
modelWhitelist: '目标模型',
modelWhitelistHint: '列表内模型使用“处理方式”,列表外模型使用“其他模型处理方式”。留空时“处理方式”应用于全部模型。支持精确匹配与前缀通配符(如 gpt-5.6*)。',
modelPatternPlaceholder: '例如: gpt-5.6-sol 或 gpt-5.6*',
addModelPattern: '添加目标模型',
fallbackAction: '其他模型处理方式',
fallbackActionHint: '仅应用于目标列表之外的模型。',
fallbackErrorMessagePlaceholder: '其他模型被拦截时返回的自定义错误消息',
summaryTargetModels: '目标模型',
summaryAllModels: '全部模型',
summaryOtherModels: '其他模型',
summaryAction: {
pass: '透传',
filter: '过滤',
block: '拦截',
force_priority: '强制 priority'
}
},
wechatConnect: {
title: '微信登录',
+65 -7
View File
@@ -1128,6 +1128,47 @@
</button>
</div>
<div
class="mb-4 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-gray-500 dark:text-gray-400"
:data-testid="`openai-fast-policy-summary-${ruleIndex}`"
>
<span class="font-medium text-gray-700 dark:text-gray-300">
{{
t(
hasOpenAIFastPolicyTargetModels(rule)
? "admin.settings.openaiFastPolicy.summaryTargetModels"
: "admin.settings.openaiFastPolicy.summaryAllModels",
)
}}
</span>
<span aria-hidden="true">→</span>
<span
class="inline-flex items-center rounded bg-primary-50 px-2 py-0.5 font-medium text-primary-700 dark:bg-primary-900/30 dark:text-primary-300"
>
{{ openaiFastPolicyActionSummary(rule.action) }}
</span>
<template v-if="hasOpenAIFastPolicyTargetModels(rule)">
<span aria-hidden="true">·</span>
<span class="font-medium text-gray-700 dark:text-gray-300">
{{
t(
"admin.settings.openaiFastPolicy.summaryOtherModels",
)
}}
</span>
<span aria-hidden="true">→</span>
<span
class="inline-flex items-center rounded bg-gray-100 px-2 py-0.5 font-medium text-gray-700 dark:bg-dark-600 dark:text-gray-300"
>
{{
openaiFastPolicyActionSummary(
rule.fallback_action || "pass",
)
}}
</span>
</template>
</div>
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
<!-- Service Tier -->
<div>
@@ -1227,14 +1268,23 @@
</p>
</div>
<!-- Model Whitelist -->
<div class="mt-3">
<!-- Target Models -->
<div
class="mt-3"
role="group"
:aria-labelledby="`openai-fast-policy-models-label-${ruleIndex}`"
:aria-describedby="`openai-fast-policy-models-hint-${ruleIndex}`"
>
<label
:id="`openai-fast-policy-models-label-${ruleIndex}`"
class="mb-1 block text-xs font-medium text-gray-600 dark:text-gray-400"
>
{{ t("admin.settings.openaiFastPolicy.modelWhitelist") }}
</label>
<p class="mb-2 text-xs text-gray-400 dark:text-gray-500">
<p
:id="`openai-fast-policy-models-hint-${ruleIndex}`"
class="mb-2 text-xs text-gray-400 dark:text-gray-500"
>
{{
t("admin.settings.openaiFastPolicy.modelWhitelistHint")
}}
@@ -1298,11 +1348,9 @@
</button>
</div>
<!-- Fallback Action (only when model_whitelist is non-empty) -->
<!-- Other Models Action (only when target models are non-empty) -->
<div
v-if="
rule.model_whitelist && rule.model_whitelist.length > 0
"
v-if="hasOpenAIFastPolicyTargetModels(rule)"
class="mt-3"
>
<label
@@ -11975,6 +12023,16 @@ const openaiFastPolicyActionOptions = computed(() => [
{ value: "block", label: t("admin.settings.openaiFastPolicy.actionBlock") },
]);
function openaiFastPolicyActionSummary(
action: OpenAIFastPolicyRule["action"],
) {
return t(`admin.settings.openaiFastPolicy.summaryAction.${action}`);
}
function hasOpenAIFastPolicyTargetModels(rule: OpenAIFastPolicyRule) {
return Boolean(rule.model_whitelist?.some((pattern) => pattern.trim() !== ""));
}
const openaiFastPolicyScopeOptions = computed(() => [
{ value: "all", label: t("admin.settings.openaiFastPolicy.scopeAll") },
{ value: "oauth", label: t("admin.settings.openaiFastPolicy.scopeOAuth") },
@@ -229,6 +229,11 @@ vi.mock("vue-i18n", async () => {
"admin.settings.upstreamBillingProbe.intervalHint": "范围 5–1440 分钟。",
"admin.settings.upstreamBillingProbe.saved": "上游倍率自动探测设置已保存",
"admin.settings.upstreamBillingProbe.saveFailed": "保存上游倍率自动探测设置失败",
"admin.settings.openaiFastPolicy.summaryTargetModels": "目标模型",
"admin.settings.openaiFastPolicy.summaryAllModels": "全部模型",
"admin.settings.openaiFastPolicy.summaryOtherModels": "其他模型",
"admin.settings.openaiFastPolicy.summaryAction.filter": "过滤",
"admin.settings.openaiFastPolicy.summaryAction.pass": "透传",
"admin.settings.security.passkeyDeploymentHint":
"请由服务器运维在部署配置中将 webauthn.enabled 设为 true,填写 webauthn.rp_id(仅域名)与 webauthn.rp_origins(完整 HTTPS 来源),然后重启服务。",
"admin.settings.site.uploadImage": "上传图片",
@@ -1261,6 +1266,43 @@ describe("admin SettingsView payment visible method controls", () => {
expect(wrapper.text()).not.toContain("OpenAI 高级调度器");
});
it("summarizes target and other-model actions, then switches to all models", async () => {
getSettings.mockResolvedValueOnce({
...baseSettingsResponse,
openai_fast_policy_settings: {
rules: [
{
service_tier: "all",
action: "filter",
scope: "all",
model_whitelist: ["gpt-5.6-sol"],
fallback_action: "pass",
},
],
},
});
const wrapper = mountView();
await flushPromises();
await openGatewayTab(wrapper);
const summary = wrapper.get('[data-testid="openai-fast-policy-summary-0"]');
expect(summary.text()).toContain("目标模型");
expect(summary.text()).toContain("过滤");
expect(summary.text()).toContain("其他模型");
expect(summary.text()).toContain("透传");
await wrapper
.get(
'[role="group"][aria-labelledby="openai-fast-policy-models-label-0"] input[type="text"]',
)
.setValue("");
expect(summary.text()).toContain("全部模型");
expect(summary.text()).toContain("过滤");
expect(summary.text()).not.toContain("其他模型");
expect(summary.text()).not.toContain("透传");
});
it("loads and saves upstream billing probe settings from the gateway tab", async () => {
getUpstreamBillingProbeSettings.mockResolvedValueOnce({
enabled: false,