From 05452c155891f883d4ff37dfb8c2a2eb0b070c1f Mon Sep 17 00:00:00 2001 From: CaIon Date: Sat, 7 Mar 2026 00:23:36 +0800 Subject: [PATCH] feat: integrate site display type into pricing components Add siteDisplayType prop across various pricing components to conditionally render pricing information based on the selected display type. This update enhances the user experience by ensuring that pricing details are accurately represented according to the chosen display mode, particularly for token-based views. --- web/src/components/layout/PageLayout.jsx | 35 +- .../personal/cards/PreferencesSettings.jsx | 28 +- .../filter/PricingDisplaySettings.jsx | 19 +- .../model-pricing/layout/PricingPage.jsx | 1 + .../layout/header/PricingTopSection.jsx | 3 + .../layout/header/SearchActions.jsx | 21 +- .../modal/ModelDetailSideSheet.jsx | 2 + .../modal/components/FilterModalContent.jsx | 2 + .../modal/components/ModelPricingTable.jsx | 6 +- .../view/card/PricingCardView.jsx | 4 +- .../model-pricing/view/table/PricingTable.jsx | 3 + .../view/table/PricingTableColumns.jsx | 6 +- .../usage-logs/modals/ColumnSelectorModal.jsx | 12 +- web/src/context/User/index.jsx | 3 + web/src/helpers/render.jsx | 1180 ++++++++--------- web/src/helpers/utils.jsx | 95 +- web/src/hooks/common/useHeaderBar.js | 35 +- .../model-pricing/useModelPricingData.jsx | 10 +- web/src/hooks/usage-logs/useUsageLogsData.jsx | 7 +- web/src/i18n/locales/en.json | 22 + web/src/i18n/locales/fr.json | 22 + web/src/i18n/locales/ja.json | 22 + web/src/i18n/locales/ru.json | 22 + web/src/i18n/locales/vi.json | 22 + web/src/i18n/locales/zh-CN.json | 22 + web/src/i18n/locales/zh-TW.json | 22 + 26 files changed, 963 insertions(+), 663 deletions(-) diff --git a/web/src/components/layout/PageLayout.jsx b/web/src/components/layout/PageLayout.jsx index 0799838eb..51666b5ef 100644 --- a/web/src/components/layout/PageLayout.jsx +++ b/web/src/components/layout/PageLayout.jsx @@ -41,7 +41,7 @@ import { normalizeLanguage } from '../../i18n/language'; const { Sider, Content, Header } = Layout; const PageLayout = () => { - const [, userDispatch] = useContext(UserContext); + const [userState, userDispatch] = useContext(UserContext); const [, statusDispatch] = useContext(StatusContext); const isMobile = useIsMobile(); const [collapsed, , setCollapsed] = useSidebarCollapsed(); @@ -114,15 +114,34 @@ const PageLayout = () => { linkElement.href = logo; } } - const savedLang = localStorage.getItem('i18nextLng'); - if (savedLang) { - const normalizedLang = normalizeLanguage(savedLang); - if (normalizedLang !== savedLang) { - localStorage.setItem('i18nextLng', normalizedLang); + }, []); + + useEffect(() => { + let preferredLang; + + if (userState?.user?.setting) { + try { + const settings = JSON.parse(userState.user.setting); + preferredLang = normalizeLanguage(settings.language); + } catch (e) { + // Ignore parse errors } - i18n.changeLanguage(normalizedLang); } - }, [i18n]); + + if (!preferredLang) { + const savedLang = localStorage.getItem('i18nextLng'); + if (savedLang) { + preferredLang = normalizeLanguage(savedLang); + } + } + + if (preferredLang) { + localStorage.setItem('i18nextLng', preferredLang); + if (preferredLang !== i18n.language) { + i18n.changeLanguage(preferredLang); + } + } + }, [i18n, userState?.user?.setting]); return ( { // Update language immediately for responsive UX setCurrentLanguage(lang); i18n.changeLanguage(lang); + localStorage.setItem('i18nextLng', lang); // Save to backend const res = await API.put("/api/user/self", { @@ -81,33 +82,38 @@ const PreferencesSettings = ({ t }) => { if (res.data.success) { showSuccess(t("语言偏好已保存")); - // Update user context with new setting + // Keep backend preference, context state, and local cache aligned. + let settings = {}; if (userState?.user?.setting) { try { - const settings = JSON.parse(userState.user.setting); - settings.language = lang; - userDispatch({ - type: "login", - payload: { - ...userState.user, - setting: JSON.stringify(settings), - }, - }); + settings = JSON.parse(userState.user.setting) || {}; } catch (e) { - // Ignore + settings = {}; } } + settings.language = lang; + const nextUser = { + ...userState.user, + setting: JSON.stringify(settings), + }; + userDispatch({ + type: "login", + payload: nextUser, + }); + localStorage.setItem("user", JSON.stringify(nextUser)); } else { showError(res.data.message || t("保存失败")); // Revert on error setCurrentLanguage(previousLang); i18n.changeLanguage(previousLang); + localStorage.setItem("i18nextLng", previousLang); } } catch (error) { showError(t("保存失败,请重试")); // Revert on error setCurrentLanguage(previousLang); i18n.changeLanguage(previousLang); + localStorage.setItem("i18nextLng", previousLang); } finally { setLoading(false); } diff --git a/web/src/components/table/model-pricing/filter/PricingDisplaySettings.jsx b/web/src/components/table/model-pricing/filter/PricingDisplaySettings.jsx index 71dbd2000..7c4bdbc52 100644 --- a/web/src/components/table/model-pricing/filter/PricingDisplaySettings.jsx +++ b/web/src/components/table/model-pricing/filter/PricingDisplaySettings.jsx @@ -25,6 +25,7 @@ const PricingDisplaySettings = ({ setShowWithRecharge, currency, setCurrency, + siteDisplayType, showRatio, setShowRatio, viewMode, @@ -34,11 +35,17 @@ const PricingDisplaySettings = ({ loading = false, t, }) => { + const supportsCurrencyDisplay = siteDisplayType !== 'TOKENS'; + const items = [ - { - value: 'recharge', - label: t('充值价格显示'), - }, + ...(supportsCurrencyDisplay + ? [ + { + value: 'recharge', + label: t('充值价格显示'), + }, + ] + : []), { value: 'ratio', label: t('显示倍率'), @@ -78,7 +85,7 @@ const PricingDisplaySettings = ({ const getActiveValues = () => { const activeValues = []; - if (showWithRecharge) activeValues.push('recharge'); + if (supportsCurrencyDisplay && showWithRecharge) activeValues.push('recharge'); if (showRatio) activeValues.push('ratio'); if (viewMode === 'table') activeValues.push('tableView'); if (tokenUnit === 'K') activeValues.push('tokenUnit'); @@ -98,7 +105,7 @@ const PricingDisplaySettings = ({ t={t} /> - {showWithRecharge && ( + {supportsCurrencyDisplay && showWithRecharge && ( { groupRatio={pricingData.groupRatio} usableGroup={pricingData.usableGroup} currency={pricingData.currency} + siteDisplayType={pricingData.siteDisplayType} tokenUnit={pricingData.tokenUnit} displayPrice={pricingData.displayPrice} showRatio={allProps.showRatio} diff --git a/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx b/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx index 5ce5f5cb3..fe04e4cc3 100644 --- a/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx +++ b/web/src/components/table/model-pricing/layout/header/PricingTopSection.jsx @@ -40,6 +40,7 @@ const PricingTopSection = memo( setShowWithRecharge, currency, setCurrency, + siteDisplayType, showRatio, setShowRatio, viewMode, @@ -68,6 +69,7 @@ const PricingTopSection = memo( setShowWithRecharge={setShowWithRecharge} currency={currency} setCurrency={setCurrency} + siteDisplayType={siteDisplayType} showRatio={showRatio} setShowRatio={setShowRatio} viewMode={viewMode} @@ -103,6 +105,7 @@ const PricingTopSection = memo( setShowWithRecharge={setShowWithRecharge} currency={currency} setCurrency={setCurrency} + siteDisplayType={siteDisplayType} showRatio={showRatio} setShowRatio={setShowRatio} viewMode={viewMode} diff --git a/web/src/components/table/model-pricing/layout/header/SearchActions.jsx b/web/src/components/table/model-pricing/layout/header/SearchActions.jsx index c961b8dc1..e285d3fba 100644 --- a/web/src/components/table/model-pricing/layout/header/SearchActions.jsx +++ b/web/src/components/table/model-pricing/layout/header/SearchActions.jsx @@ -35,6 +35,7 @@ const SearchActions = memo( setShowWithRecharge, currency, setCurrency, + siteDisplayType, showRatio, setShowRatio, viewMode, @@ -43,6 +44,8 @@ const SearchActions = memo( setTokenUnit, t, }) => { + const supportsCurrencyDisplay = siteDisplayType !== 'TOKENS'; + const handleCopyClick = useCallback(() => { if (copyText && selectedRowKeys.length > 0) { copyText(selectedRowKeys); @@ -91,16 +94,18 @@ const SearchActions = memo( {/* 充值价格显示开关 */} -
- {t('充值价格显示')} - -
+ {supportsCurrencyDisplay && ( +
+ {t('充值价格显示')} + +
+ )} {/* 货币单位选择 */} - {showWithRecharge && ( + {supportsCurrencyDisplay && showWithRecharge && (