fix: 修复权重配置预览显示错误分类数量问题
- 修改 WeightPreviewTooltip 组件,只显示实际选中的分类权重 - 对于非按顺序匹配规则,不显示权重预览信息 - 确保权重指示器和预览提示都显示正确的分类数量 - 解决选择2个分类却显示4个分类的问题
This commit is contained in:
parent
6c44d31666
commit
d7411de33d
|
|
@ -0,0 +1,165 @@
|
||||||
|
# 按顺序匹配规则权重配置功能演示
|
||||||
|
|
||||||
|
## 功能概述
|
||||||
|
|
||||||
|
现在当用户选择"按顺序匹配"规则类型时,可以在同一个编辑界面中直接调整权重,而不需要保存后再在外面单独调整。这大大改善了用户体验。
|
||||||
|
|
||||||
|
## 主要改进
|
||||||
|
|
||||||
|
### 1. 实时权重编辑
|
||||||
|
- **之前**: 需要先保存匹配规则,然后在外部单独编辑权重
|
||||||
|
- **现在**: 选中分类后,右侧权重立即变为可编辑的输入框
|
||||||
|
|
||||||
|
### 2. 精确保存机制
|
||||||
|
- **保存逻辑**: 只保存选中分类的权重,自动删除未选中分类的权重记录
|
||||||
|
- **数据一致性**: 确保权重配置与分类选择完全同步
|
||||||
|
|
||||||
|
### 3. 简化的用户界面
|
||||||
|
- **集成设计**: 分类选择和权重编辑在同一行完成
|
||||||
|
- **即时反馈**: 选中/取消选中分类时,权重编辑状态立即切换
|
||||||
|
- **清晰布局**: 移除重复的权重配置区域,界面更简洁
|
||||||
|
|
||||||
|
## 使用流程
|
||||||
|
|
||||||
|
### 步骤 1: 选择匹配规则
|
||||||
|
1. 在模板详情页面,展开轨道片段
|
||||||
|
2. 点击"编辑"按钮进入匹配规则编辑模式
|
||||||
|
3. 在规则类型下拉框中选择"按顺序匹配"
|
||||||
|
|
||||||
|
### 步骤 2: 选择AI分类
|
||||||
|
1. 在"按权重顺序匹配的分类"区域选择需要的AI分类
|
||||||
|
2. 可以选择多个分类,系统会按权重顺序尝试匹配
|
||||||
|
|
||||||
|
### 步骤 3: 配置权重(新功能)
|
||||||
|
1. 选择分类后,下方会自动显示"权重配置"区域
|
||||||
|
2. 每个选中的分类都有独立的权重调整控件
|
||||||
|
3. 使用滑块或数字输入框调整权重值(0-100)
|
||||||
|
4. 实时查看权重等级和排序
|
||||||
|
|
||||||
|
### 步骤 4: 保存配置
|
||||||
|
1. 点击"保存"按钮
|
||||||
|
2. 系统会同时保存匹配规则和权重配置
|
||||||
|
3. 无需额外的权重配置步骤
|
||||||
|
|
||||||
|
## 技术实现
|
||||||
|
|
||||||
|
### 前端组件修改
|
||||||
|
- `SegmentMatchingRuleEditor.tsx`: 集成权重编辑功能
|
||||||
|
- `TemplateDetailModal.tsx`: 优化权重相关功能的显示逻辑
|
||||||
|
|
||||||
|
### 核心功能
|
||||||
|
1. **权重数据加载**: 在编辑"按顺序匹配"规则时自动加载权重数据
|
||||||
|
2. **实时权重调整**: 支持滑块和数字输入的实时权重修改
|
||||||
|
3. **统一保存**: 保存匹配规则时同时保存权重配置
|
||||||
|
4. **智能显示**: 根据规则类型智能显示/隐藏权重相关功能
|
||||||
|
|
||||||
|
### 用户体验优化
|
||||||
|
- **一体化操作**: 规则配置和权重设置在同一界面完成
|
||||||
|
- **即时反馈**: 权重调整后立即显示等级和排序变化
|
||||||
|
- **清晰指引**: 提供操作说明和提示信息
|
||||||
|
- **响应式设计**: 适配不同屏幕尺寸
|
||||||
|
|
||||||
|
## 代码示例
|
||||||
|
|
||||||
|
### 权重编辑界面结构
|
||||||
|
```tsx
|
||||||
|
{/* 权重配置区域 - 只在有模板ID且选择了分类时显示 */}
|
||||||
|
{templateId && SegmentMatchingRuleHelper.isPriorityOrder(editingRule) && (
|
||||||
|
<div className="mt-4 pt-3 border-t border-blue-200">
|
||||||
|
<label className="block text-xs font-medium text-blue-800">
|
||||||
|
权重配置
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{/* 权重调整控件 */}
|
||||||
|
{selectedClassifications.map((classification) => (
|
||||||
|
<div key={classification.id} className="bg-gray-50 border rounded-md p-2">
|
||||||
|
{/* 滑块控制 */}
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
value={currentWeight}
|
||||||
|
onChange={(e) => handleWeightChange(classification.id, parseInt(e.target.value))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 数字输入 */}
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
value={currentWeight}
|
||||||
|
onChange={(e) => handleWeightChange(classification.id, parseInt(e.target.value))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 保存逻辑
|
||||||
|
```tsx
|
||||||
|
const handleSaveRule = async () => {
|
||||||
|
// 保存匹配规则
|
||||||
|
await updateSegmentMatchingRule(segmentId, editingRule);
|
||||||
|
|
||||||
|
// 如果是按顺序匹配规则,同时保存权重配置
|
||||||
|
if (SegmentMatchingRuleHelper.isPriorityOrder(editingRule) && templateId) {
|
||||||
|
await TemplateSegmentWeightService.setSegmentWeights(
|
||||||
|
templateId,
|
||||||
|
segmentId,
|
||||||
|
editingWeights
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 测试建议
|
||||||
|
|
||||||
|
1. **功能测试**:
|
||||||
|
- 验证只有"按顺序匹配"规则显示权重配置
|
||||||
|
- 测试权重调整的实时响应
|
||||||
|
- 确认保存后权重配置正确应用
|
||||||
|
|
||||||
|
2. **用户体验测试**:
|
||||||
|
- 测试界面的直观性和易用性
|
||||||
|
- 验证操作流程的流畅性
|
||||||
|
- 检查不同屏幕尺寸的适配
|
||||||
|
|
||||||
|
3. **边界情况测试**:
|
||||||
|
- 测试权重值边界(0-100)
|
||||||
|
- 验证无AI分类时的处理
|
||||||
|
- 测试网络错误时的降级处理
|
||||||
|
|
||||||
|
## 问题修复
|
||||||
|
|
||||||
|
### 权重指示器分类数量显示错误
|
||||||
|
|
||||||
|
**问题描述**:
|
||||||
|
用户选择了2个分类(全身/上半身)并设置权重后,前端显示"自定义 (平均: 8.5)最高: 10•4 分类",但实际只选择了2个分类。
|
||||||
|
|
||||||
|
**问题原因**:
|
||||||
|
`SegmentWeightIndicator` 组件使用 `getSegmentWeightsWithDefaults` 方法获取权重数据,该方法返回所有激活AI分类的权重(包括默认值),而不是只返回用户实际选择的分类。
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
1. 在 `SegmentWeightIndicator` 组件中添加 `segmentMatchingRule` 参数
|
||||||
|
2. 根据匹配规则类型智能统计分类数量:
|
||||||
|
- 对于"按顺序匹配"规则:只统计用户选择的分类
|
||||||
|
- 对于其他规则类型:使用所有权重数据
|
||||||
|
3. 修改权重统计逻辑,过滤出实际相关的分类权重
|
||||||
|
|
||||||
|
**修复效果**:
|
||||||
|
- ✅ 现在显示准确的分类数量(如:2 分类)
|
||||||
|
- ✅ 权重统计只基于实际选择的分类
|
||||||
|
- ✅ 平均权重和最高权重计算更准确
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
这个功能改进显著提升了用户体验,将原本需要多步操作的权重配置集成到匹配规则编辑的单一界面中。用户现在可以:
|
||||||
|
|
||||||
|
- ✅ 在一个界面完成规则和权重配置
|
||||||
|
- ✅ 实时预览权重调整效果
|
||||||
|
- ✅ 享受更流畅的操作体验
|
||||||
|
- ✅ 减少操作步骤和学习成本
|
||||||
|
- ✅ 看到准确的分类数量和权重统计
|
||||||
|
|
||||||
|
这种设计符合现代UI/UX的最佳实践,提供了更加直观和高效的用户交互体验。
|
||||||
|
|
@ -59,38 +59,21 @@ export const SegmentWeightIndicator: React.FC<SegmentWeightIndicatorProps> = ({
|
||||||
// 计算权重摘要 - 只统计实际选择的分类
|
// 计算权重摘要 - 只统计实际选择的分类
|
||||||
let relevantWeights: Record<string, number> = {};
|
let relevantWeights: Record<string, number> = {};
|
||||||
|
|
||||||
console.log('SegmentWeightIndicator Debug:', {
|
|
||||||
segmentMatchingRule,
|
|
||||||
isPriorityOrder: segmentMatchingRule ? SegmentMatchingRuleHelper.isPriorityOrder(segmentMatchingRule) : false,
|
|
||||||
allWeights: weights,
|
|
||||||
allWeightsCount: Object.keys(weights).length
|
|
||||||
});
|
|
||||||
|
|
||||||
if (segmentMatchingRule && SegmentMatchingRuleHelper.isPriorityOrder(segmentMatchingRule)) {
|
if (segmentMatchingRule && SegmentMatchingRuleHelper.isPriorityOrder(segmentMatchingRule)) {
|
||||||
// 对于按顺序匹配规则,只统计选择的分类
|
// 对于按顺序匹配规则,只统计选择的分类
|
||||||
const selectedCategoryIds = typeof segmentMatchingRule === 'object' && 'PriorityOrder' in segmentMatchingRule
|
const selectedCategoryIds = typeof segmentMatchingRule === 'object' && 'PriorityOrder' in segmentMatchingRule
|
||||||
? segmentMatchingRule.PriorityOrder.category_ids
|
? segmentMatchingRule.PriorityOrder.category_ids
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
console.log('PriorityOrder Debug:', {
|
|
||||||
selectedCategoryIds,
|
|
||||||
selectedCount: selectedCategoryIds.length
|
|
||||||
});
|
|
||||||
|
|
||||||
// 只包含选择的分类的权重
|
// 只包含选择的分类的权重
|
||||||
relevantWeights = Object.fromEntries(
|
relevantWeights = Object.fromEntries(
|
||||||
Object.entries(weights).filter(([classificationId]) =>
|
Object.entries(weights).filter(([classificationId]) =>
|
||||||
selectedCategoryIds.includes(classificationId)
|
selectedCategoryIds.includes(classificationId)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('Filtered weights:', {
|
|
||||||
relevantWeights,
|
|
||||||
relevantCount: Object.keys(relevantWeights).length
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// 对于其他规则类型,使用所有权重
|
// 对于其他规则类型,不显示权重信息(因为不相关)
|
||||||
relevantWeights = weights;
|
relevantWeights = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const weightValues = Object.values(relevantWeights);
|
const weightValues = Object.values(relevantWeights);
|
||||||
|
|
@ -221,12 +204,14 @@ export const SegmentWeightIndicator: React.FC<SegmentWeightIndicatorProps> = ({
|
||||||
interface WeightPreviewTooltipProps {
|
interface WeightPreviewTooltipProps {
|
||||||
templateId: string;
|
templateId: string;
|
||||||
trackSegmentId: string;
|
trackSegmentId: string;
|
||||||
|
segmentMatchingRule?: any; // 添加匹配规则参数
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WeightPreviewTooltip: React.FC<WeightPreviewTooltipProps> = ({
|
export const WeightPreviewTooltip: React.FC<WeightPreviewTooltipProps> = ({
|
||||||
templateId,
|
templateId,
|
||||||
trackSegmentId,
|
trackSegmentId,
|
||||||
|
segmentMatchingRule,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
const [showTooltip, setShowTooltip] = useState(false);
|
const [showTooltip, setShowTooltip] = useState(false);
|
||||||
|
|
@ -235,14 +220,35 @@ export const WeightPreviewTooltip: React.FC<WeightPreviewTooltipProps> = ({
|
||||||
|
|
||||||
const loadWeights = async () => {
|
const loadWeights = async () => {
|
||||||
if (loading) return;
|
if (loading) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const weightData = await TemplateSegmentWeightService.getSegmentWeightsWithDefaults(
|
const allWeights = await TemplateSegmentWeightService.getSegmentWeightsWithDefaults(
|
||||||
templateId,
|
templateId,
|
||||||
trackSegmentId
|
trackSegmentId
|
||||||
);
|
);
|
||||||
setWeights(weightData);
|
|
||||||
|
// 过滤权重数据,只显示实际选中的分类
|
||||||
|
let relevantWeights: Record<string, number> = {};
|
||||||
|
|
||||||
|
if (segmentMatchingRule && SegmentMatchingRuleHelper.isPriorityOrder(segmentMatchingRule)) {
|
||||||
|
// 对于按顺序匹配规则,只显示选择的分类
|
||||||
|
const selectedCategoryIds = typeof segmentMatchingRule === 'object' && 'PriorityOrder' in segmentMatchingRule
|
||||||
|
? segmentMatchingRule.PriorityOrder.category_ids
|
||||||
|
: [];
|
||||||
|
|
||||||
|
// 只包含选择的分类的权重
|
||||||
|
relevantWeights = Object.fromEntries(
|
||||||
|
Object.entries(allWeights).filter(([classificationId]) =>
|
||||||
|
selectedCategoryIds.includes(classificationId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 对于其他规则类型,不显示权重信息
|
||||||
|
relevantWeights = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
setWeights(relevantWeights);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载权重预览失败:', error);
|
console.error('加载权重预览失败:', error);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -791,6 +791,7 @@ export const TemplateDetailModal: React.FC<TemplateDetailModalProps> = ({
|
||||||
<WeightPreviewTooltip
|
<WeightPreviewTooltip
|
||||||
templateId={currentTemplate.id}
|
templateId={currentTemplate.id}
|
||||||
trackSegmentId={segment.id}
|
trackSegmentId={segment.id}
|
||||||
|
segmentMatchingRule={segment.matching_rule}
|
||||||
>
|
>
|
||||||
<SegmentWeightIndicator
|
<SegmentWeightIndicator
|
||||||
templateId={currentTemplate.id}
|
templateId={currentTemplate.id}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue