@@ -4563,6 +4572,7 @@ import { useOnboardingStore } from "@/stores/onboarding";
import { adminAPI } from "@/api/admin";
import type {
AdminGroup,
+ CodexModelsManifestConfig,
CompositeModelRoute,
CompositeModelRouteInput,
CompositeRouteDecision,
@@ -4590,6 +4600,7 @@ import GroupRateMultipliersModal from "@/components/admin/group/GroupRateMultipl
import GroupRPMOverridesModal from "@/components/admin/group/GroupRPMOverridesModal.vue";
import GroupCapacityBadge from "@/components/common/GroupCapacityBadge.vue";
import ReasoningEffortPolicyFields from "@/components/admin/group/ReasoningEffortPolicyFields.vue";
+import CodexManifestAccountsField from "@/components/admin/group/CodexManifestAccountsField.vue";
import PricingEntryCard from "@/components/admin/channel/PricingEntryCard.vue";
import type { PricingFormEntry } from "@/components/admin/channel/types";
import {
@@ -5175,6 +5186,20 @@ type ReasoningEffortPolicyFieldsExpose = {
};
const createReasoningEffortPolicyRef = ref(null);
const editReasoningEffortPolicyRef = ref(null);
+
+// 固定账号获取 Codex Model Manifest(仅 openai 分组编辑对话框)
+type CodexManifestAccountsFieldExpose = {
+ validate: () => boolean;
+ resetValidation: () => void;
+};
+const editCodexManifestRef = ref(null);
+const createCodexManifestDefaults = (): CodexModelsManifestConfig => ({
+ enabled: false,
+ account_ids: [],
+ fallback_to_scheduler: false,
+});
+const editCodexManifestConfig = reactive(createCodexManifestDefaults());
+const editCodexManifestAccountNames = ref>({});
const modelsListCandidatesTracker = createModelsListCandidatesTracker();
const createModelsListSelectedCount = computed(
() => createModelsListState.items.filter((item) => item.selected).length,
@@ -6166,6 +6191,8 @@ const handleCreateGroup = async () => {
createModelRoutingRules.value,
),
models_list_config: buildModelsListConfig(createModelsListState),
+ // 创建时固定账号 manifest 固定发送关闭状态(后端创建路径禁止开启)
+ codex_models_manifest_config: createCodexManifestDefaults(),
supported_model_scopes: normalizeSupportedModelScopesForPlatform(
createForm.platform,
createForm.supported_model_scopes,
@@ -6351,6 +6378,28 @@ const handleEdit = async (group: AdminGroup) => {
group.platform,
);
resetModelsListState(editModelsListState, group.models_list_config);
+ // 固定账号 manifest 配置:回显配置并异步解析已存账号名称(失败显示 #)
+ const savedCodexManifestConfig =
+ group.codex_models_manifest_config ?? createCodexManifestDefaults();
+ Object.assign(editCodexManifestConfig, {
+ enabled: savedCodexManifestConfig.enabled ?? false,
+ account_ids: [...(savedCodexManifestConfig.account_ids ?? [])],
+ fallback_to_scheduler: savedCodexManifestConfig.fallback_to_scheduler ?? false,
+ });
+ editCodexManifestAccountNames.value = {};
+ for (const id of editCodexManifestConfig.account_ids) {
+ adminAPI.accounts
+ .getById(id)
+ .then((account) => {
+ editCodexManifestAccountNames.value = {
+ ...editCodexManifestAccountNames.value,
+ [id]: account.name,
+ };
+ })
+ .catch(() => {
+ // 无法解析名称时由组件回退展示 #,提示管理员清理脏 ID。
+ });
+ }
// 加载模型路由规则(异步加载账号名称)
editModelRoutingRules.value = await convertApiFormatToRoutingRules(
group.model_routing,
@@ -6397,6 +6446,9 @@ const closeEditModal = () => {
resetMessagesDispatchFormState(editForm);
editForm.allow_live = false;
resetModelsListState(editModelsListState);
+ Object.assign(editCodexManifestConfig, createCodexManifestDefaults());
+ editCodexManifestAccountNames.value = {};
+ editCodexManifestRef.value?.resetValidation?.();
};
const handleUpdateGroup = async () => {
@@ -6415,6 +6467,16 @@ const handleUpdateGroup = async () => {
if (!validateProfitControlForm(editForm)) {
return;
}
+ // 固定账号 manifest:开启后至少一个账号,前端阻止提交并提示。
+ if (
+ editForm.platform === "openai" &&
+ editCodexManifestConfig.enabled &&
+ editCodexManifestConfig.account_ids.length === 0
+ ) {
+ appStore.showError(t("admin.groups.codexModelsManifest.selectAtLeastOne"));
+ editCodexManifestRef.value?.validate();
+ return;
+ }
submitting.value = true;
try {
@@ -6455,6 +6517,15 @@ const handleUpdateGroup = async () => {
editModelRoutingRules.value,
),
models_list_config: buildModelsListConfig(editModelsListState),
+ // 非 openai 平台提交关闭状态,与后端归一化一致
+ codex_models_manifest_config:
+ editForm.platform === "openai"
+ ? {
+ enabled: editCodexManifestConfig.enabled,
+ account_ids: [...editCodexManifestConfig.account_ids],
+ fallback_to_scheduler: editCodexManifestConfig.fallback_to_scheduler,
+ }
+ : createCodexManifestDefaults(),
supported_model_scopes: normalizeSupportedModelScopesForPlatform(
editForm.platform,
editForm.supported_model_scopes,