DimensionBoostRow.tsx 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import { InputNumber, Typography } from 'antd'
  2. import { getConfigDisplayLabel } from '../api/configCodes'
  3. import {
  4. BOOST_MAX,
  5. BOOST_MIN,
  6. getDefaultBoostForCode,
  7. type RankingParams,
  8. } from '../utils/scoring'
  9. const { Text } = Typography
  10. interface Props {
  11. boostCodes: string[]
  12. configCodes: Record<string, string>
  13. rankingParams: RankingParams
  14. onChange: (next: RankingParams) => void
  15. }
  16. export default function DimensionBoostRow({
  17. boostCodes,
  18. configCodes,
  19. rankingParams,
  20. onChange,
  21. }: Props) {
  22. if (boostCodes.length === 0) return null
  23. return (
  24. <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center', marginTop: 10 }}>
  25. <Text style={{ fontSize: 12, color: '#666', whiteSpace: 'nowrap' }}>维度 Boost</Text>
  26. {boostCodes.map((code) => {
  27. const defaultVal = getDefaultBoostForCode(code)
  28. const val = rankingParams.boostsByCode?.[code] ?? defaultVal
  29. const isCustom = code in (rankingParams.boostsByCode ?? {})
  30. return (
  31. <div key={code} style={{ display: 'flex', alignItems: 'center', gap: 2 }}>
  32. <Text style={{ fontSize: 11, color: isCustom ? '#1677ff' : undefined, whiteSpace: 'nowrap' }}>
  33. {getConfigDisplayLabel(code, configCodes)}
  34. </Text>
  35. <InputNumber
  36. size="small"
  37. min={BOOST_MIN}
  38. max={BOOST_MAX}
  39. step={0.05}
  40. value={val}
  41. onChange={(v) => {
  42. const next = { ...rankingParams.boostsByCode }
  43. if (typeof v === 'number' && v !== defaultVal) {
  44. next[code] = v
  45. } else {
  46. delete next[code]
  47. }
  48. onChange({ ...rankingParams, boostsByCode: next })
  49. }}
  50. style={{ width: 68 }}
  51. />
  52. </div>
  53. )
  54. })}
  55. </div>
  56. )
  57. }