Files
Mdeical_Sur_Report/工程分析/经验记录.md
2026-04-16 17:55:13 +08:00

9.1 KiB
Raw Blame History

经验记录


记录 1report-editor 新建报告时显示空白模板

A. 具体问题 超级管理员进入 /report-editor(新建报告)时,编辑区域为纯白色空白,顶部模板选择器显示"无",但 system-settings 中已配置了默认模板。

B. 产生问题原因

  1. ReportEditor.tsx 在组件卸载如页面切换时会自动将当前编辑器内容保存为草稿draft。即使用户未输入任何内容保存的 content 也是空字符串 ""
  2. 初始化 effect 中判断草稿是否有效的条件仅使用了 typeof draft.content === 'string',空字符串满足该条件,导致编辑器被填充为空白 HTML并将 contentLoadedRef.current 设为 true
  3. 由于 contentLoadedRef.current 已被置为 true,后续加载 settings.defaultTemplate 的默认模板分支被完全跳过,从而永远显示空白。
  4. 此外,草稿中未保存 loadedTemplateId,即使内容非空时恢复草稿,模板选择器也会因缺少状态而显示"无"。

C. 解决问题方案

  1. saveDraftToStorage 中将当前 loadedTemplateId 一并存入 draft。
  2. 将四处草稿恢复的判断条件从 typeof draft.content === 'string' 收紧为 typeof draft.content === 'string' && draft.content.trim().length > 0,使空白草稿不再拦截默认模板加载。
  3. 恢复草稿时同步执行 setLoadedTemplateId(draft.loadedTemplateId || ''),确保模板选择器名称正确。

D. 后续如何避免问题

  • 在前端使用 contentEditable 的自动保存机制时,保存和恢复草稿都应增加对空/仅空白内容的过滤。
  • 若草稿与某个业务状态(如当前模板 ID强关联应确保两者一并持久化和恢复避免状态不一致。
  • 对兜底初始化逻辑(如默认模板加载)增加更严格的防护,防止被无效中间状态提前截断。

记录 2关键帧一键插入占位符功能实现

A. 具体问题 用户希望视频分析面板中的关键帧截图除了拖拽插入外,还能通过点击 "插入" 按钮一键自动填充到编辑器中第一个空置的 image-placeholder

B. 产生问题原因 原先仅支持拖拽方式将关键帧放入占位符。当关键帧数量多或占位符位置较远时,操作不便。且 handleDrop 中的填充逻辑未抽离,无法被其他交互方式复用。

C. 解决问题方案

  1. handleDrop 中的 HTML 填充逻辑抽离为 fillPlaceholder(placeholder, frame) 公共函数。
  2. 新增 insertFrameToPlaceholder(frame) 函数:通过 editorRef.current.querySelector('.image-placeholder:not(.has-image)') 查找第一个空置占位符,找到则调用 fillPlaceholder,未找到则 alert('没有可插入图片的空位')
  3. 在关键帧卡片底部的 timeFormatted 与 "可拖拽" 之间新增 "插入" 按钮,使用 opacity-0 group-hover:opacity-100 transition-opacity 与 "可拖拽" 保持一致的显隐行为,并通过 e.stopPropagation() 避免触发卡片的视频跳转 onClick

D. 后续如何避免问题

  • 当同一交互效果(如填充占位符)需要支持多种触发方式(拖拽、按钮点击、快捷键等)时,应将核心逻辑抽离为独立函数,避免重复代码。
  • 在可点击子元素上务必注意事件冒泡控制,防止触发父级不必要的副作用(如此处的视频跳转)。
  • UI 提示文字(如 "插入"、"可拖拽")的显隐样式应尽量保持一致,减少用户认知成本。

记录 3关键帧 "插入" 按钮位置与样式优化

A. 具体问题 用户对已实现的 "插入" 按钮位置和样式提出优化:希望按钮位于图片中央、做成实体按钮样式、颜色与 "可拖拽" 的蓝色有明显区分。

B. 产生问题原因 初次实现时将 "插入" 按钮放在了卡片底部文字区域,采用纯文字链接样式(text-accent),视觉上不够醒目,且与 "可拖拽" 提示颜色重叠,辨识度低。

C. 解决问题方案

  1. 将 "插入" 按钮从底部文字行移到图片层的 <div className="relative"> 容器内,使用 absolute inset-0 m-auto w-fit h-fit 实现水平和垂直居中。
  2. 将按钮样式改为实体胶囊按钮:px-3 py-1.5 bg-emerald-500 text-white rounded-full shadow-mdhover 时加深为 bg-emerald-600
  3. 底部文字区域只保留 timeFormatted 和 "可拖拽" 提示,"插入" 按钮不再与它们并列。

D. 后续如何避免问题

  • 对于图片卡片上的核心操作按钮,优先考虑覆盖在图片中央或显著位置,比在底部小字中放置链接更符合用户直觉。
  • 同一卡片上的多个 hover 提示元素应保持显隐动画一致(opacity-0 group-hover:opacity-100 transition-opacity),但颜色上要有区分,避免用户混淆不同功能。
  • 使用 absolute inset-0 m-auto w-fit h-fit 是一种在 Tailwind 中不依赖 flex/grid 的居中技巧,适合在 relative 容器内居中不定宽高的元素。

记录 4关键帧 "插入" 按钮位置微调(从图片中央移回底部)

A. 具体问题 用户反馈将 "插入" 按钮放在图片正中央会遮挡图片内容,希望移回卡片底部,但仍保留实体按钮样式和蓝色。

B. 产生问题原因 按钮以 absolute 层覆盖在图片中央时,确实会遮挡部分图片内容,对于医学影像类截图可能影响用户预览。

C. 解决问题方案

  1. 将 "插入" 按钮从图片层的 absolute 覆盖层移回卡片底部的文字行,放置在 timeFormatted 与 "可拖拽" 之间。
  2. 按钮颜色恢复为蓝色(bg-accent text-white),与 "可拖拽" 蓝色保持一致,视觉上统一。
  3. 保留实体胶囊按钮样式:px-2 py-0.5 rounded-full shadow-sm,不再是纯文字链接。
  4. 显隐行为仍通过 opacity-0 group-hover:opacity-100 transition-opacity 与 "可拖拽" 同步。

D. 后续如何避免问题

  • 对于图片/截图类卡片上的操作按钮,应优先考虑不遮挡核心图片内容的区域(如底部、角落),避免影响预览。
  • 在 UI 微调过程中,可以通过小步迭代快速验证用户意图,减少一次性大改导致的方向偏差。
  • 实体按钮比纯文字链接具有更高的可点击性和辨识度,在微小空间中也能提供良好的交互体验。

记录 5自动抽帧丢失、模板选择器变"无"与自动帧插入开关

A. 具体问题 用户反馈三个关联问题:

  1. 从其他页面返回 /report-editor 后,自动抽帧的图片全部丢失。
  2. 编辑报告后切换界面再返回,"当前模板"显示为"无"。
  3. 希望 system-settings 增加"开启自动帧插入"开关,让自动抽帧直接填充占位符。

B. 产生问题原因

  1. 自动抽帧丢失autoCaptureFramescaptureFrameremoveVideohandleVideoUpload 中调用 setCapturedFrames/setVideos 后立即调用 saveDraftToStorage,但 stateRef.current 中的 capturedFramesvideos 仍是旧值React 的 setState 是异步的)。因此组件卸载前保存的 draft 里缺少新生成的自动帧。
  2. 模板选择器变"无"saveDraftToStorage 使用 useCallback 捕获了旧的 loadedTemplateIdstale closure。编辑报告时 loadedTemplateId 未通过 stateRef.current 同步,导致 draft 中的 loadedTemplateId 为空字符串,恢复后模板选择器显示"无"。
  3. 自动帧插入需求:用户希望减少手动拖拽操作,提升效率。

C. 解决问题方案

  1. 修复状态同步:将 loadedTemplateId 纳入 stateRef.current,并在 saveDraftToStorage 调用前先强制同步 stateRef.current = { reportData, videos, capturedFrames, activeTab, loadedTemplateId }。同时,在所有修改 videoscapturedFrames 的函数(handleVideoUploadremoveVideocaptureFrameautoCaptureFrames)中,手动将最新状态同步到 stateRef.current 后再 saveDraftToStorage
  2. 新增自动帧插入开关
    • SystemSettings 类型增加 autoInsertFrames?: boolean
    • SystemSettings.tsx 增加 checkbox 开关,并在每个 framePositions 百分比旁显示绿色 Check 对勾。
    • ReportEditor.tsxautoCaptureFrames 中,每生成一帧后若开关开启,则查找第一个 .image-placeholder:not(.has-image) 并填充图片;若找不到则静默跳过,不弹窗。循环结束后统一更新 contentRef.current 并保存草稿。

D. 后续如何避免问题

  • 当多个状态需要同时持久化到 localStorage如通过 draft 机制),应避免依赖异步 setState 后的自动同步。在保存前手动将最新计算值同步到 ref 或直接在保存函数中传入最新值,是更可靠的做法。
  • useCallback 的依赖数组虽然能触发重新创建函数,但函数体内部若同时读取 state 和 ref仍可能出现 stale closure。将可变状态统一收敛到 ref 中,并在保存前强制刷新 ref可有效避免此类问题。
  • 新增业务开关时,类型定义、设置页面、消费逻辑三个点必须同步修改,并在 UI 上给予用户明确的视觉反馈(如此次的绿色对勾标记)。