2026-06-15 14:35:40 +08:00
|
|
|
|
import { formatAspectRatio, normalizeRatioToken } from "./ratioUtils";
|
2026-06-17 18:37:26 +08:00
|
|
|
|
import { getPlatformRules } from "../../../api/platformRulesClient";
|
2026-06-15 14:35:40 +08:00
|
|
|
|
|
|
|
|
|
|
export type ProductSetOutputKey = "set" | "detail" | "model" | "video";
|
|
|
|
|
|
export type CloneOutputKey = ProductSetOutputKey | "hot";
|
|
|
|
|
|
export type PlatformRatioModeKey = ProductSetOutputKey | "hot";
|
|
|
|
|
|
|
|
|
|
|
|
export interface PlatformRatioGroup {
|
|
|
|
|
|
ratios: string[];
|
|
|
|
|
|
defaultRatio: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface EcommercePlatformSpec {
|
|
|
|
|
|
label: string;
|
|
|
|
|
|
ratios: string[];
|
|
|
|
|
|
defaultRatio: string;
|
|
|
|
|
|
ratioGroups?: Partial<Record<PlatformRatioModeKey, PlatformRatioGroup>>;
|
|
|
|
|
|
specs: string[];
|
|
|
|
|
|
tip?: string;
|
|
|
|
|
|
aliases?: string[];
|
|
|
|
|
|
}
|
2026-06-17 18:37:26 +08:00
|
|
|
|
|
|
|
|
|
|
// 业务数据由后端 API 下发(AGENTS.md 规则4),见 src/api/platformRulesClient.ts。
|
|
|
|
|
|
// 启动 gating 保证本模块求值时(随 EcommercePage chunk 加载)缓存已填充。
|
|
|
|
|
|
// 顶层读取一次:gating 后 getPlatformRules() 返回 API 数据;未就绪则返回 fallback。
|
|
|
|
|
|
const rules = getPlatformRules();
|
|
|
|
|
|
|
|
|
|
|
|
export const platformSpecOptions: EcommercePlatformSpec[] = rules.platformSpecOptions;
|
2026-06-15 14:35:40 +08:00
|
|
|
|
export const platformOptions = platformSpecOptions.map((option) => option.label);
|
2026-06-17 18:37:26 +08:00
|
|
|
|
export const marketLanguageOptions: Array<{ country: string; languages: string[] }> =
|
|
|
|
|
|
rules.marketLanguageOptions;
|
2026-06-15 14:35:40 +08:00
|
|
|
|
export const marketOptions = marketLanguageOptions.map((option) => option.country);
|
|
|
|
|
|
export const languageOptions = Array.from(new Set(marketLanguageOptions.flatMap((option) => option.languages)));
|
2026-06-17 18:37:26 +08:00
|
|
|
|
export const languageAliases: Record<string, string> = rules.languageAliases;
|
2026-06-15 14:35:40 +08:00
|
|
|
|
export const defaultPlatformSpec = platformSpecOptions[0]!;
|
|
|
|
|
|
export const getPlatformSpec = (value: string) =>
|
|
|
|
|
|
platformSpecOptions.find((option) => option.label === value || option.aliases?.includes(value)) ?? defaultPlatformSpec;
|
2026-06-17 18:37:26 +08:00
|
|
|
|
export const legacyPlatformAliases: Record<string, string> = rules.legacyPlatformAliases;
|
2026-06-15 14:35:40 +08:00
|
|
|
|
export const normalizePlatform = (value: string) => getPlatformSpec(legacyPlatformAliases[value] ?? value).label;
|
2026-06-17 18:37:26 +08:00
|
|
|
|
export const domesticPlatformLabels = new Set(rules.domesticPlatformLabels);
|
|
|
|
|
|
export const domesticPlatformLanguages = rules.domesticPlatformLanguages;
|
2026-06-15 14:35:40 +08:00
|
|
|
|
export const isDomesticPlatform = (platformValue: string) => domesticPlatformLabels.has(normalizePlatform(platformValue));
|
|
|
|
|
|
export const getPlatformRatioGroup = (value: string, mode?: PlatformRatioModeKey): PlatformRatioGroup => {
|
|
|
|
|
|
const platformSpec = getPlatformSpec(value);
|
|
|
|
|
|
return (mode ? platformSpec.ratioGroups?.[mode] : null) ?? {
|
|
|
|
|
|
ratios: platformSpec.ratios,
|
|
|
|
|
|
defaultRatio: platformSpec.defaultRatio,
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
export const getPlatformRatioOptions = (value: string, mode?: PlatformRatioModeKey) => getPlatformRatioGroup(value, mode).ratios;
|
|
|
|
|
|
export const getPlatformDefaultRatio = (value: string, mode?: PlatformRatioModeKey) => getPlatformRatioGroup(value, mode).defaultRatio;
|
|
|
|
|
|
export const getUniqueRatioOptions = (ratios: string[]) => Array.from(new Set(ratios));
|
|
|
|
|
|
export const normalizeRatioForPlatform = (platformValue: string, ratioValue: string, mode?: PlatformRatioModeKey) => {
|
|
|
|
|
|
const platformRatios = getPlatformRatioOptions(platformValue, mode);
|
|
|
|
|
|
if (platformRatios.includes(ratioValue)) return ratioValue;
|
|
|
|
|
|
const normalizedRatio = normalizeRatioToken(ratioValue);
|
|
|
|
|
|
const matchedRatio = platformRatios.find((option) => normalizeRatioToken(option).includes(normalizedRatio));
|
|
|
|
|
|
return matchedRatio ?? getPlatformDefaultRatio(platformValue, mode);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export const defaultMarketLanguageOption = marketLanguageOptions[0]!;
|
|
|
|
|
|
export const normalizeMarket = (value: string) =>
|
|
|
|
|
|
marketLanguageOptions.some((option) => option.country === value) ? value : defaultMarketLanguageOption.country;
|
|
|
|
|
|
export const normalizeLanguage = (value: string) => languageAliases[value] ?? value;
|
|
|
|
|
|
export const uniqueLanguages = (languages: string[]) => Array.from(new Set(languages));
|
|
|
|
|
|
export const appendEnglish = (languages: string[]) => Array.from(new Set([...languages, "英文"]));
|
|
|
|
|
|
export const getMarketLanguageOptions = (marketValue: string) =>
|
|
|
|
|
|
appendEnglish((marketLanguageOptions.find((option) => option.country === marketValue) ?? defaultMarketLanguageOption).languages);
|
|
|
|
|
|
export const getPlatformLanguageOptions = (platformValue: string, marketValue: string) => {
|
|
|
|
|
|
const marketLanguages = getMarketLanguageOptions(marketValue);
|
|
|
|
|
|
if (!isDomesticPlatform(platformValue)) return marketLanguages;
|
|
|
|
|
|
const localLanguages = marketLanguages.filter((item) => item !== "英文");
|
|
|
|
|
|
return uniqueLanguages([...localLanguages, ...domesticPlatformLanguages, "英文"]);
|
|
|
|
|
|
};
|
|
|
|
|
|
export const getPlatformDefaultLanguage = (platformValue: string, marketValue: string) =>
|
|
|
|
|
|
isDomesticPlatform(platformValue) ? "中文" : (getPlatformLanguageOptions(platformValue, marketValue)[0] ?? languageOptions[0] ?? "英文");
|
|
|
|
|
|
export const normalizeLanguageForPlatform = (platformValue: string, marketValue: string, languageValue: string) => {
|
|
|
|
|
|
const normalizedLanguage = normalizeLanguage(languageValue);
|
|
|
|
|
|
const platformLanguages = getPlatformLanguageOptions(platformValue, marketValue);
|
|
|
|
|
|
return platformLanguages.includes(normalizedLanguage) ? normalizedLanguage : getPlatformDefaultLanguage(platformValue, marketValue);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-17 18:37:26 +08:00
|
|
|
|
export const defaultEcommercePlatform = rules.defaultEcommercePlatform;
|
2026-06-15 14:35:40 +08:00
|
|
|
|
export const defaultProductSetOutput: ProductSetOutputKey = "set";
|
|
|
|
|
|
export const defaultCloneOutput: CloneOutputKey = "set";
|
|
|
|
|
|
|
|
|
|
|
|
export const formatUploadedImageRatio = (image?: { width?: number; height?: number; format?: string }) => {
|
|
|
|
|
|
if (!image) return null;
|
|
|
|
|
|
const format = image.format ? `\u00a0\u00a0\u00a0${image.format}` : "";
|
|
|
|
|
|
if (!image.width || !image.height) return `上传图片\u00a0\u00a0\u00a0原图比例${format}`;
|
|
|
|
|
|
return `上传图片 ${image.width}×${image.height}px\u00a0\u00a0\u00a0${formatAspectRatio(image.width, image.height)}${format}`;
|
|
|
|
|
|
};
|
2026-06-17 18:37:26 +08:00
|
|
|
|
|