feat: enhance SelectableButtonGroup with checkbox support and refactor pricing display settings (#1365)

- Add withCheckbox prop to SelectableButtonGroup component for checkbox-prefixed buttons
- Support both single value and array activeValue for multi-selection scenarios
- Refactor PricingDisplaySettings to use consistent SelectableButtonGroup styling
- Replace Switch components with checkbox-enabled SelectableButtonGroup
- Replace Select dropdown with SelectableButtonGroup for currency selection
- Maintain unified UI/UX across all pricing filter components
- Add proper JSDoc documentation for new withCheckbox functionality

This improves visual consistency and provides a more cohesive user experience
in the model pricing filter interface.
This commit is contained in:
t0ng7u
2025-07-23 04:10:44 +08:00
parent 4247883173
commit 6d06cb8fb3
2 changed files with 115 additions and 49 deletions

View File

@@ -19,7 +19,7 @@ For commercial licensing, please contact support@quantumnous.com
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';
import { useIsMobile } from '../../../hooks/common/useIsMobile'; import { useIsMobile } from '../../../hooks/common/useIsMobile';
import { Divider, Button, Tag, Row, Col, Collapsible } from '@douyinfe/semi-ui'; import { Divider, Button, Tag, Row, Col, Collapsible, Checkbox } from '@douyinfe/semi-ui';
import { IconChevronDown, IconChevronUp } from '@douyinfe/semi-icons'; import { IconChevronDown, IconChevronUp } from '@douyinfe/semi-icons';
/** /**
@@ -27,12 +27,13 @@ import { IconChevronDown, IconChevronUp } from '@douyinfe/semi-icons';
* *
* @param {string} title 标题 * @param {string} title 标题
* @param {Array<{value:any,label:string,icon?:React.ReactNode,tagCount?:number}>} items 按钮项 * @param {Array<{value:any,label:string,icon?:React.ReactNode,tagCount?:number}>} items 按钮项
* @param {*} activeValue 当前激活的值 * @param {*|Array} activeValue 当前激活的值,可以是单个值或数组(多选)
* @param {(value:any)=>void} onChange 选择改变回调 * @param {(value:any)=>void} onChange 选择改变回调
* @param {function} t i18n * @param {function} t i18n
* @param {object} style 额外样式 * @param {object} style 额外样式
* @param {boolean} collapsible 是否支持折叠默认true * @param {boolean} collapsible 是否支持折叠默认true
* @param {number} collapseHeight 折叠时的高度默认200 * @param {number} collapseHeight 折叠时的高度默认200
* @param {boolean} withCheckbox 是否启用前缀 Checkbox 来控制激活状态
*/ */
const SelectableButtonGroup = ({ const SelectableButtonGroup = ({
title, title,
@@ -42,7 +43,8 @@ const SelectableButtonGroup = ({
t = (v) => v, t = (v) => v,
style = {}, style = {},
collapsible = true, collapsible = true,
collapseHeight = 200 collapseHeight = 200,
withCheckbox = false
}) => { }) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const isMobile = useIsMobile(); const isMobile = useIsMobile();
@@ -82,7 +84,52 @@ const SelectableButtonGroup = ({
const contentElement = ( const contentElement = (
<Row gutter={[8, 8]} style={{ lineHeight: '32px', ...style }} ref={contentRef}> <Row gutter={[8, 8]} style={{ lineHeight: '32px', ...style }} ref={contentRef}>
{items.map((item) => { {items.map((item) => {
const isActive = activeValue === item.value; const isActive = Array.isArray(activeValue)
? activeValue.includes(item.value)
: activeValue === item.value;
// 当启用前缀 Checkbox 时,按钮本身不可点击,仅 Checkbox 可控制状态切换
if (withCheckbox) {
return (
<Col
{...(isMobile
? { span: 12 }
: { xs: 24, sm: 24, md: 24, lg: 12, xl: 8 }
)}
key={item.value}
>
<Button
onClick={() => { /* disabled */ }}
theme={isActive ? 'light' : 'outline'}
type={isActive ? 'primary' : 'tertiary'}
icon={
<Checkbox
checked={isActive}
onChange={() => onChange(item.value)}
style={{ pointerEvents: 'auto' }}
/>
}
style={{ width: '100%', cursor: 'default' }}
>
{item.icon && (
<span style={{ marginRight: 4 }}>{item.icon}</span>
)}
<span style={{ marginRight: item.tagCount !== undefined ? 4 : 0 }}>{item.label}</span>
{item.tagCount !== undefined && (
<Tag
color='white'
shape="circle"
size="small"
>
{item.tagCount}
</Tag>
)}
</Button>
</Col>
);
}
// 默认行为
return ( return (
<Col <Col
{...(isMobile {...(isMobile

View File

@@ -18,7 +18,8 @@ For commercial licensing, please contact support@quantumnous.com
*/ */
import React from 'react'; import React from 'react';
import { Divider, Switch, Select, Tooltip } from '@douyinfe/semi-ui'; import { Tooltip } from '@douyinfe/semi-ui';
import SelectableButtonGroup from '../../../common/ui/SelectableButtonGroup';
import { IconHelpCircle } from '@douyinfe/semi-icons'; import { IconHelpCircle } from '@douyinfe/semi-icons';
const PricingDisplaySettings = ({ const PricingDisplaySettings = ({
@@ -30,51 +31,69 @@ const PricingDisplaySettings = ({
setShowRatio, setShowRatio,
t t
}) => { }) => {
return ( const items = [
<div className="mb-6"> {
<Divider margin='12px' align='left'> value: 'recharge',
{t('显示设置')} label: t('以充值价格显示')
</Divider> },
<div className="px-2"> {
<div className="flex items-center justify-between mb-3"> value: 'ratio',
<span className="text-sm text-gray-700">{t('以充值价格显示')}</span> label: (
<Switch <span className="flex items-center gap-1">
checked={showWithRecharge} {t('显示倍率')}
onChange={setShowWithRecharge} <Tooltip content={t('倍率是用于系统计算不同模型的最终价格用的,如果您不理解倍率,请忽略')}>
size="small" <IconHelpCircle
/>
</div>
{showWithRecharge && (
<div className="mt-2 mb-3">
<div className="text-xs text-gray-500 mb-1">{t('货币单位')}</div>
<Select
value={currency}
onChange={setCurrency}
size="small" size="small"
className="w-full" style={{ color: 'var(--semi-color-text-2)', cursor: 'help' }}
> />
<Select.Option value="USD">USD ($)</Select.Option> </Tooltip>
<Select.Option value="CNY">CNY (¥)</Select.Option> </span>
</Select> ),
</div> }
)} ];
<div className="flex items-center justify-between">
<div className="flex items-center gap-1"> const currencyItems = [
<span className="text-sm text-gray-700">{t('显示倍率')}</span> { value: 'USD', label: 'USD ($)' },
<Tooltip content={t('倍率是用于系统计算不同模型的最终价格用的,如果您不理解倍率,请忽略')}> { value: 'CNY', label: 'CNY (¥)' }
<IconHelpCircle ];
size="small"
style={{ color: 'var(--semi-color-text-2)', cursor: 'help' }} const handleChange = (value) => {
/> if (value === 'recharge') {
</Tooltip> setShowWithRecharge(!showWithRecharge);
</div> } else if (value === 'ratio') {
<Switch setShowRatio(!showRatio);
checked={showRatio} }
onChange={setShowRatio} };
size="small"
/> const getActiveValues = () => {
</div> const activeValues = [];
</div> if (showWithRecharge) activeValues.push('recharge');
if (showRatio) activeValues.push('ratio');
return activeValues;
};
return (
<div>
<SelectableButtonGroup
title={t('显示设置')}
items={items}
activeValue={getActiveValues()}
onChange={handleChange}
withCheckbox
collapsible={false}
t={t}
/>
{showWithRecharge && (
<SelectableButtonGroup
title={t('货币单位')}
items={currencyItems}
activeValue={currency}
onChange={setCurrency}
collapsible={false}
t={t}
/>
)}
</div> </div>
); );
}; };