✨ refactor: pricing filters for dynamic counting & cleaner logic
This commit introduces a unified, maintainable solution for all model-pricing filter buttons and removes redundant code.
Key points
• Added `usePricingFilterCounts` hook
- Centralises filtering logic and returns:
- `quotaTypeModels`, `endpointTypeModels`, `dynamicCategoryCounts`, `groupCountModels`
- Keeps internal helpers private (removed public `modelsAfterCategory`).
• Updated components to consume the new hook
- `PricingSidebar.jsx`
- `FilterModalContent.jsx`
• Improved button UI/UX
- `SelectableButtonGroup.jsx` now respects `item.disabled` and auto-disables when `tagCount === 0`.
- `PricingGroups.jsx` counts models per group (after all other filters) and disables groups with zero matches.
- `PricingEndpointTypes.jsx` enumerates all endpoint types, computes filtered counts, and disables entries with zero matches.
• Removed obsolete / duplicate calculations and comments to keep components lean.
The result is consistent, real-time tag counts across all filter groups, automatic disabling of unavailable options, and a single source of truth for filter computations, making future extensions straightforward.
This commit is contained in:
@@ -28,11 +28,11 @@ import SelectableButtonGroup from '../../../common/ui/SelectableButtonGroup';
|
||||
* @param {boolean} loading 是否加载中
|
||||
* @param {Function} t i18n
|
||||
*/
|
||||
const PricingEndpointTypes = ({ filterEndpointType, setFilterEndpointType, models = [], loading = false, t }) => {
|
||||
// 获取所有可用的端点类型
|
||||
const PricingEndpointTypes = ({ filterEndpointType, setFilterEndpointType, models = [], allModels = [], loading = false, t }) => {
|
||||
// 获取系统中所有端点类型(基于 allModels,如果未提供则退化为 models)
|
||||
const getAllEndpointTypes = () => {
|
||||
const endpointTypes = new Set();
|
||||
models.forEach(model => {
|
||||
(allModels.length > 0 ? allModels : models).forEach(model => {
|
||||
if (model.supported_endpoint_types && Array.isArray(model.supported_endpoint_types)) {
|
||||
model.supported_endpoint_types.forEach(endpoint => {
|
||||
endpointTypes.add(endpoint);
|
||||
@@ -61,12 +61,16 @@ const PricingEndpointTypes = ({ filterEndpointType, setFilterEndpointType, model
|
||||
const availableEndpointTypes = getAllEndpointTypes();
|
||||
|
||||
const items = [
|
||||
{ value: 'all', label: t('全部端点'), tagCount: getEndpointTypeCount('all') },
|
||||
...availableEndpointTypes.map(endpointType => ({
|
||||
value: endpointType,
|
||||
label: getEndpointTypeLabel(endpointType),
|
||||
tagCount: getEndpointTypeCount(endpointType)
|
||||
}))
|
||||
{ value: 'all', label: t('全部端点'), tagCount: getEndpointTypeCount('all'), disabled: models.length === 0 },
|
||||
...availableEndpointTypes.map(endpointType => {
|
||||
const count = getEndpointTypeCount(endpointType);
|
||||
return ({
|
||||
value: endpointType,
|
||||
label: getEndpointTypeLabel(endpointType),
|
||||
tagCount: count,
|
||||
disabled: count === 0
|
||||
});
|
||||
})
|
||||
];
|
||||
|
||||
return (
|
||||
|
||||
@@ -34,6 +34,9 @@ const PricingGroups = ({ filterGroup, setFilterGroup, usableGroup = {}, groupRat
|
||||
const groups = ['all', ...Object.keys(usableGroup).filter(key => key !== '')];
|
||||
|
||||
const items = groups.map((g) => {
|
||||
const modelCount = g === 'all'
|
||||
? models.length
|
||||
: models.filter(m => m.enable_groups && m.enable_groups.includes(g)).length;
|
||||
let ratioDisplay = '';
|
||||
if (g === 'all') {
|
||||
ratioDisplay = t('全部');
|
||||
@@ -49,6 +52,7 @@ const PricingGroups = ({ filterGroup, setFilterGroup, usableGroup = {}, groupRat
|
||||
value: g,
|
||||
label: g === 'all' ? t('全部分组') : g,
|
||||
tagCount: ratioDisplay,
|
||||
disabled: modelCount === 0
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import PricingQuotaTypes from '../filter/PricingQuotaTypes';
|
||||
import PricingEndpointTypes from '../filter/PricingEndpointTypes';
|
||||
import PricingDisplaySettings from '../filter/PricingDisplaySettings';
|
||||
import { resetPricingFilters } from '../../../../helpers/utils';
|
||||
import { usePricingFilterCounts } from '../../../../hooks/model-pricing/usePricingFilterCounts';
|
||||
|
||||
const PricingSidebar = ({
|
||||
showWithRecharge,
|
||||
@@ -52,6 +53,21 @@ const PricingSidebar = ({
|
||||
...categoryProps
|
||||
}) => {
|
||||
|
||||
const {
|
||||
quotaTypeModels,
|
||||
endpointTypeModels,
|
||||
dynamicCategoryCounts,
|
||||
groupCountModels,
|
||||
} = usePricingFilterCounts({
|
||||
models: categoryProps.models,
|
||||
modelCategories: categoryProps.modelCategories,
|
||||
activeKey: categoryProps.activeKey,
|
||||
filterGroup,
|
||||
filterQuotaType,
|
||||
filterEndpointType,
|
||||
searchValue: categoryProps.searchValue,
|
||||
});
|
||||
|
||||
const handleResetFilters = () =>
|
||||
resetPricingFilters({
|
||||
handleChange,
|
||||
@@ -101,6 +117,7 @@ const PricingSidebar = ({
|
||||
|
||||
<PricingCategories
|
||||
{...categoryProps}
|
||||
categoryCounts={dynamicCategoryCounts}
|
||||
setActiveKey={setActiveKey}
|
||||
loading={loading}
|
||||
t={t}
|
||||
@@ -111,7 +128,7 @@ const PricingSidebar = ({
|
||||
setFilterGroup={setFilterGroup}
|
||||
usableGroup={categoryProps.usableGroup}
|
||||
groupRatio={categoryProps.groupRatio}
|
||||
models={categoryProps.models}
|
||||
models={groupCountModels}
|
||||
loading={loading}
|
||||
t={t}
|
||||
/>
|
||||
@@ -119,7 +136,7 @@ const PricingSidebar = ({
|
||||
<PricingQuotaTypes
|
||||
filterQuotaType={filterQuotaType}
|
||||
setFilterQuotaType={setFilterQuotaType}
|
||||
models={categoryProps.models}
|
||||
models={quotaTypeModels}
|
||||
loading={loading}
|
||||
t={t}
|
||||
/>
|
||||
@@ -127,7 +144,8 @@ const PricingSidebar = ({
|
||||
<PricingEndpointTypes
|
||||
filterEndpointType={filterEndpointType}
|
||||
setFilterEndpointType={setFilterEndpointType}
|
||||
models={categoryProps.models}
|
||||
models={endpointTypeModels}
|
||||
allModels={categoryProps.models}
|
||||
loading={loading}
|
||||
t={t}
|
||||
/>
|
||||
|
||||
@@ -23,6 +23,7 @@ import PricingCategories from '../../filter/PricingCategories';
|
||||
import PricingGroups from '../../filter/PricingGroups';
|
||||
import PricingQuotaTypes from '../../filter/PricingQuotaTypes';
|
||||
import PricingEndpointTypes from '../../filter/PricingEndpointTypes';
|
||||
import { usePricingFilterCounts } from '../../../../../hooks/model-pricing/usePricingFilterCounts';
|
||||
|
||||
const FilterModalContent = ({ sidebarProps, t }) => {
|
||||
const {
|
||||
@@ -48,6 +49,21 @@ const FilterModalContent = ({ sidebarProps, t }) => {
|
||||
...categoryProps
|
||||
} = sidebarProps;
|
||||
|
||||
const {
|
||||
quotaTypeModels,
|
||||
endpointTypeModels,
|
||||
dynamicCategoryCounts,
|
||||
groupCountModels,
|
||||
} = usePricingFilterCounts({
|
||||
models: categoryProps.models,
|
||||
modelCategories: categoryProps.modelCategories,
|
||||
activeKey: categoryProps.activeKey,
|
||||
filterGroup,
|
||||
filterQuotaType,
|
||||
filterEndpointType,
|
||||
searchValue: sidebarProps.searchValue,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="p-2">
|
||||
<PricingDisplaySettings
|
||||
@@ -65,14 +81,20 @@ const FilterModalContent = ({ sidebarProps, t }) => {
|
||||
t={t}
|
||||
/>
|
||||
|
||||
<PricingCategories {...categoryProps} setActiveKey={setActiveKey} loading={loading} t={t} />
|
||||
<PricingCategories
|
||||
{...categoryProps}
|
||||
categoryCounts={dynamicCategoryCounts}
|
||||
setActiveKey={setActiveKey}
|
||||
loading={loading}
|
||||
t={t}
|
||||
/>
|
||||
|
||||
<PricingGroups
|
||||
filterGroup={filterGroup}
|
||||
setFilterGroup={setFilterGroup}
|
||||
usableGroup={categoryProps.usableGroup}
|
||||
groupRatio={categoryProps.groupRatio}
|
||||
models={categoryProps.models}
|
||||
models={groupCountModels}
|
||||
loading={loading}
|
||||
t={t}
|
||||
/>
|
||||
@@ -80,7 +102,7 @@ const FilterModalContent = ({ sidebarProps, t }) => {
|
||||
<PricingQuotaTypes
|
||||
filterQuotaType={filterQuotaType}
|
||||
setFilterQuotaType={setFilterQuotaType}
|
||||
models={categoryProps.models}
|
||||
models={quotaTypeModels}
|
||||
loading={loading}
|
||||
t={t}
|
||||
/>
|
||||
@@ -88,7 +110,8 @@ const FilterModalContent = ({ sidebarProps, t }) => {
|
||||
<PricingEndpointTypes
|
||||
filterEndpointType={filterEndpointType}
|
||||
setFilterEndpointType={setFilterEndpointType}
|
||||
models={categoryProps.models}
|
||||
models={endpointTypeModels}
|
||||
allModels={categoryProps.models}
|
||||
loading={loading}
|
||||
t={t}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user