diff --git a/frontend/src/i18n/locales/en/admin/overview.ts b/frontend/src/i18n/locales/en/admin/overview.ts index 57e7f21137..7f69b3fa16 100644 --- a/frontend/src/i18n/locales/en/admin/overview.ts +++ b/frontend/src/i18n/locales/en/admin/overview.ts @@ -841,6 +841,18 @@ export default { finalPricePreview: 'Final per-image price preview', notConfigured: 'Not configured' }, + mediaPricing: { + title: 'Image / Video Generation Pricing', + description: + 'Configure Grok image and video generation access plus base media prices. Leave empty to use default prices.', + allowImageGeneration: 'Allow image and video generation for this group', + independentMultiplier: 'Use independent media multiplier', + imageMultiplier: 'Media multiplier', + modeHint: + 'By default, Grok media billing uses media price × current effective group multiplier. Independent mode uses media price × media multiplier. One video generation is billed as one media unit.', + finalPricePreview: 'Final per-media-unit price preview', + notConfigured: 'Not configured' + }, peakRate: { enable: 'Enable peak rate multiplier', peakStart: 'Peak start', diff --git a/frontend/src/i18n/locales/zh/admin/overview.ts b/frontend/src/i18n/locales/zh/admin/overview.ts index c15cc52990..cebf7e760e 100644 --- a/frontend/src/i18n/locales/zh/admin/overview.ts +++ b/frontend/src/i18n/locales/zh/admin/overview.ts @@ -919,6 +919,17 @@ export default { finalPricePreview: '最终单张价格预览', notConfigured: '未配置' }, + mediaPricing: { + title: '图片/视频生成计费', + description: '配置 Grok 图片和视频生成能力及媒体基础单价,留空则使用默认价格', + allowImageGeneration: '允许当前分组生图和视频生成', + independentMultiplier: '媒体倍率独立', + imageMultiplier: '媒体独立倍率', + modeHint: + '默认关闭独立倍率时,Grok 媒体费用 = 媒体价格 × 当前分组有效倍率;开启独立倍率后,Grok 媒体费用 = 媒体价格 × 媒体独立倍率。一次视频生成按 1 个媒体单位计费。', + finalPricePreview: '最终单次媒体价格预览', + notConfigured: '未配置' + }, peakRate: { enable: '启用高峰倍率', peakStart: '高峰开始', diff --git a/frontend/src/views/admin/GroupsView.vue b/frontend/src/views/admin/GroupsView.vue index 0700f127b8..b5c8334785 100644 --- a/frontend/src/views/admin/GroupsView.vue +++ b/frontend/src/views/admin/GroupsView.vue @@ -787,7 +787,7 @@ - +
- {{ t("admin.groups.imagePricing.title") }} + {{ t(imagePricingI18nKey(createForm.platform, "title")) }}

- {{ t("admin.groups.imagePricing.description") }} + {{ t(imagePricingI18nKey(createForm.platform, "description")) }}

- {{ t("admin.groups.imagePricing.modeHint") }} + {{ t(imagePricingI18nKey(createForm.platform, "modeHint")) }}

- {{ t("admin.groups.imagePricing.finalPricePreview") }} + {{ t(imagePricingI18nKey(createForm.platform, "finalPricePreview")) }}
- +
- {{ t("admin.groups.imagePricing.title") }} + {{ t(imagePricingI18nKey(editForm.platform, "title")) }}

- {{ t("admin.groups.imagePricing.description") }} + {{ t(imagePricingI18nKey(editForm.platform, "description")) }}

- {{ t("admin.groups.imagePricing.modeHint") }} + {{ t(imagePricingI18nKey(editForm.platform, "modeHint")) }}

- {{ t("admin.groups.imagePricing.finalPricePreview") }} + {{ t(imagePricingI18nKey(editForm.platform, "finalPricePreview")) }}
{ it("keeps non-media group platforms out of the image pricing controls", () => { expect(supportsImagePricingPlatform("anthropic")).toBe(false); }); + + it("uses media pricing copy for Grok groups only", () => { + expect(imagePricingI18nKey("grok", "title")).toBe( + "admin.groups.mediaPricing.title", + ); + expect(imagePricingI18nKey("openai", "title")).toBe( + "admin.groups.imagePricing.title", + ); + }); }); diff --git a/frontend/src/views/admin/groupsImagePricing.ts b/frontend/src/views/admin/groupsImagePricing.ts index 1a2c5170ce..b899fb3637 100644 --- a/frontend/src/views/admin/groupsImagePricing.ts +++ b/frontend/src/views/admin/groupsImagePricing.ts @@ -7,3 +7,8 @@ export const imagePricingPlatforms = new Set([ export const supportsImagePricingPlatform = (platform: string): boolean => imagePricingPlatforms.has(platform); + +export const imagePricingI18nKey = (platform: string, key: string): string => + platform === "grok" + ? `admin.groups.mediaPricing.${key}` + : `admin.groups.imagePricing.${key}`;