# 评分标准JSON结构化重构方案 ## 问题分析 **当前设计缺陷:** 1. **UI层**:使用结构化对象 `[{min_score, max_score, description}]` 2. **数据库层**:使用 `\n` 分隔的字符串存储在 `instructions` 字段 3. **数据丢失**:`min_score` 和 `max_score` 等结构化信息在保存时完全丢失 ## 解决方案 ### 方案一:使用现有 `scoring_criteria` 字段(推荐) #### 1. 数据库结构调整 ```sql -- 第一步:将 scoring_criteria 字段改为 JSONB 类型(如果不是的话) ALTER TABLE public.ak_training_projects ALTER COLUMN scoring_criteria TYPE JSONB USING scoring_criteria::jsonb; ``` #### 2. 新的JSON数据结构 ```json { "criteria": [ { "min_score": 90, "max_score": 100, "description": "优秀:动作标准,节奏控制完美,表现卓越" }, { "min_score": 80, "max_score": 89, "description": "良好:动作较为标准,节奏控制良好" }, { "min_score": 70, "max_score": 79, "description": "及格:基本掌握动作要领,需要改进" }, { "min_score": 0, "max_score": 69, "description": "不及格:动作不标准,需要重新练习" } ], "scoring_method": "comprehensive", // 综合评分方式 "weight_distribution": { "technique": 0.4, // 技术动作权重 40% "effort": 0.3, // 努力程度权重 30% "improvement": 0.3 // 进步幅度权重 30% } } ``` #### 3. 前端代码重构 **加载数据时:** ```typescript // 修改 loadProjectData 函数 function loadProjectData() { // ...现有代码... // 处理评分标准 - 使用新的JSON结构 let scoringCriteria: Array = [] const criteriaData = safeGet(projectData, 'scoring_criteria', null) if (criteriaData && typeof criteriaData === 'object') { // 新的JSON格式 const criteria = safeGet(criteriaData, 'criteria', []) if (criteria instanceof Array) { scoringCriteria = criteria.map((item: any) => ({ min_score: item.min_score?.toString() || '', max_score: item.max_score?.toString() || '', description: item.description || '' } as UTSJSONObject)) } } else if (typeof criteriaData === 'string') { // 兼容旧的 \n 分隔格式 const instructionSteps = criteriaData.split('\n').filter((step: string) => step.trim().length > 0) scoringCriteria = instructionSteps.map((step: string, index: number) => ({ min_score: (index * 20).toString(), max_score: ((index + 1) * 20).toString(), description: step.trim() } as UTSJSONObject)) } if (scoringCriteria.length === 0) { scoringCriteria = [{ min_score: '', max_score: '', description: '' } as UTSJSONObject] } // ...其他代码... } ``` **保存数据时:** ```typescript // 修改 updateProject 和 saveDraft 函数 function updateProject() { // ...现有代码... const scoringCriteria = getScoringCriteria() const scoringCriteriaJson = { criteria: scoringCriteria.map((criteria: UTSJSONObject) => ({ min_score: parseInt(safeGet(criteria, 'min_score', '0')), max_score: parseInt(safeGet(criteria, 'max_score', '100')), description: safeGet(criteria, 'description', '') })).filter(item => item.description.trim().length > 0), scoring_method: "comprehensive", weight_distribution: { technique: 0.4, effort: 0.3, improvement: 0.3 } } const { data, error } = await supaClient .from('ak_training_projects') .update({ // ...其他字段... scoring_criteria: scoringCriteriaJson, instructions: '', // 清空旧的instructions字段,避免混淆 updated_at: new Date().toISOString() }) .eq('id', projectId.value) .execute() // ...其他代码... } ``` ### 方案二:添加新字段(备选方案) 如果不想修改现有字段,可以添加新字段: ```sql -- 添加新的JSONB字段 ALTER TABLE public.ak_training_projects ADD COLUMN scoring_criteria_json JSONB; -- 创建索引以提高查询性能 CREATE INDEX idx_ak_training_projects_scoring_criteria ON public.ak_training_projects USING GIN (scoring_criteria_json); ``` ## 数据迁移脚本 ### 第一步:备份现有数据 ```sql -- 创建备份表 CREATE TABLE ak_training_projects_backup AS SELECT * FROM ak_training_projects; ``` ### 第二步:迁移现有数据 ```sql -- 将现有的 instructions 数据转换为 JSON 格式 UPDATE ak_training_projects SET scoring_criteria = jsonb_build_object( 'criteria', ARRAY( SELECT jsonb_build_object( 'min_score', (ROW_NUMBER() OVER () - 1) * 20, 'max_score', ROW_NUMBER() OVER () * 20, 'description', trim(instruction) ) FROM unnest(string_to_array(instructions, E'\n')) AS instruction WHERE trim(instruction) != '' ), 'scoring_method', 'comprehensive', 'weight_distribution', jsonb_build_object( 'technique', 0.4, 'effort', 0.3, 'improvement', 0.3 ) ) WHERE instructions IS NOT NULL AND instructions != ''; ``` ### 第三步:验证迁移结果 ```sql -- 验证JSON结构 SELECT id, title, scoring_criteria->'criteria' as criteria_array, jsonb_array_length(scoring_criteria->'criteria') as criteria_count FROM ak_training_projects WHERE scoring_criteria IS NOT NULL LIMIT 5; ``` ## 优势对比 | 特性 | 旧方案 (\n分隔) | 新方案 (JSON) | |------|-----------------|---------------| | 数据结构 | 平铺字符串 | 结构化对象 | | 分数范围 | ❌ 丢失 | ✅ 保留 | | 查询能力 | ❌ 有限 | ✅ 强大 | | 扩展性 | ❌ 困难 | ✅ 容易 | | 数据完整性 | ❌ 差 | ✅ 优秀 | | AI分析支持 | ❌ 不支持 | ✅ 原生支持 | ## 实施建议 1. **测试环境先行**:在测试环境完成迁移和测试 2. **渐进式部署**:保持向后兼容,支持新旧两种格式 3. **数据校验**:迁移后进行全面的数据完整性检查 4. **性能优化**:为JSONB字段创建合适的索引 ## 长期收益 1. **更好的数据查询**:可以直接查询特定分数范围的标准 2. **AI集成友好**:结构化数据更容易被AI系统理解和处理 3. **扩展性强**:未来可以轻松添加新的评分维度 4. **数据一致性**:避免了UI和数据库层的数据结构不匹配问题