# 冒险实体详情 NPC 预览修复记录(2026-04-26) ## 背景 RPG 运行态点击画面中的对面 NPC 角色形象时,详情弹窗的立绘与画布上实际显示的 NPC 不一致,并伴随 React 报错: `Encountered two children with the same key, ``.` ## 问题定位 1. 画布层 `GameCanvasEntityLayer` 渲染 NPC 时,会优先使用当前 `Encounter` 实例上的 `visual`、`imageSrc`、`monsterPresetId`,再回退到 `characterId` 对应的预设角色。 2. 详情弹窗 `AdventureEntityModal` 原本优先按 `characterId` 渲染预设角色,导致运行时遭遇已经携带独立形象时,点击后弹窗显示成另一个角色内容。 3. `AdventureEntityModal` 内部存在多个浮层共用同一个 `AnimatePresence`,直系子节点没有显式稳定 key;同时 NPC 运行时背包物品如果传入空 `id`,会把空字符串直接交给物品格列表作为 React key。 ## 落地约束 1. NPC 详情立绘必须与画布点击对象一致: - `encounter.visual` - `encounter.imageSrc` - `encounter.monsterPresetId` - `encounter.characterId` - 通用 NPC 生成形象 2. 前端只做展示优先级和 key 稳定性处理,不新增剧情规则、不改写运行时 NPC 数据来源。 3. 所有列表和并列浮层都必须具备稳定、非空、可区分的渲染 key。 ## 本次修改 1. `src/components/AdventureEntityModal.tsx` - 新增 `NpcEncounterPortrait`,让弹窗立绘优先使用遭遇实例形象,与画布渲染策略对齐。 - 新增 `selectionRenderKey`,给实体详情、标签详情、技能详情浮层提供稳定 key。 - 新增 NPC 背包物品渲染 id 规范化,避免空 id 或重复 id 触发 React key 冲突,并避免点击物品时选中错误项。 - 技能附带状态标签 key 增加兜底字段,避免空 buff id 冲突。 2. `src/components/AdventureEntityModal.test.tsx` - 覆盖“有 `characterId` 但遭遇实例提供 `imageSrc` 时,详情立绘必须显示遭遇图像”。 - 覆盖“NPC 背包物品空 id 不再触发重复 key 警告”。 ## 验证 已执行: ```bash npm run test -- AdventureEntityModal.test.tsx CharacterInfoShared.test.tsx ``` 结果:5 个测试全部通过。