|
|
@@ -0,0 +1,61 @@
|
|
|
+import { InputNumber, Typography } from 'antd'
|
|
|
+import { getConfigDisplayLabel } from '../api/configCodes'
|
|
|
+import {
|
|
|
+ BOOST_MAX,
|
|
|
+ BOOST_MIN,
|
|
|
+ getDefaultBoostForCode,
|
|
|
+ type RankingParams,
|
|
|
+} from '../utils/scoring'
|
|
|
+
|
|
|
+const { Text } = Typography
|
|
|
+
|
|
|
+interface Props {
|
|
|
+ boostCodes: string[]
|
|
|
+ configCodes: Record<string, string>
|
|
|
+ rankingParams: RankingParams
|
|
|
+ onChange: (next: RankingParams) => void
|
|
|
+}
|
|
|
+
|
|
|
+export default function DimensionBoostRow({
|
|
|
+ boostCodes,
|
|
|
+ configCodes,
|
|
|
+ rankingParams,
|
|
|
+ onChange,
|
|
|
+}: Props) {
|
|
|
+ if (boostCodes.length === 0) return null
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center', marginTop: 10 }}>
|
|
|
+ <Text style={{ fontSize: 12, color: '#666', whiteSpace: 'nowrap' }}>维度 Boost</Text>
|
|
|
+ {boostCodes.map((code) => {
|
|
|
+ const defaultVal = getDefaultBoostForCode(code)
|
|
|
+ const val = rankingParams.boostsByCode?.[code] ?? defaultVal
|
|
|
+ const isCustom = code in (rankingParams.boostsByCode ?? {})
|
|
|
+ return (
|
|
|
+ <div key={code} style={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
|
|
+ <Text style={{ fontSize: 11, color: isCustom ? '#1677ff' : undefined, whiteSpace: 'nowrap' }}>
|
|
|
+ {getConfigDisplayLabel(code, configCodes)}
|
|
|
+ </Text>
|
|
|
+ <InputNumber
|
|
|
+ size="small"
|
|
|
+ min={BOOST_MIN}
|
|
|
+ max={BOOST_MAX}
|
|
|
+ step={0.05}
|
|
|
+ value={val}
|
|
|
+ onChange={(v) => {
|
|
|
+ const next = { ...rankingParams.boostsByCode }
|
|
|
+ if (typeof v === 'number' && v !== defaultVal) {
|
|
|
+ next[code] = v
|
|
|
+ } else {
|
|
|
+ delete next[code]
|
|
|
+ }
|
|
|
+ onChange({ ...rankingParams, boostsByCode: next })
|
|
|
+ }}
|
|
|
+ style={{ width: 68 }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ })}
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|