Files
Mdeical_Sur_Report/工程分析/20260419_2316/功能变更实现方案文档.md
admin 0039b18a26 feat: 模板AI区域化+默认配置优化+API密钥安全(20260419_2316)
- 默认模板: 手术步骤段落包裹进 .ai-region AI可编辑区域
- API密钥: DEFAULT_AI_PROVIDERS.kimi.apiKey 预设默认值,
  输入框增加onCopy/onCut防复制, storage.ts增加XOR+Base64透明加密
- 默认模型: kimi modelName改为 moonshot-v1-auto
- 抽帧配置: 12个位置改为指定百分比[7.9,9.3,46.2,49.1,63.9,64.8,
  68.8,73.7,80.2,85.0,96.3,98.6], 默认模式从uniform改为keep
2026-04-19 23:24:36 +08:00

4.6 KiB
Raw Blame History

功能变更实现方案文档20260419_2316

实现方案 A模板手术步骤 AI 区域化

变更点

src/utils/defaultContent.ts line 54-76。

具体实现

将原有的:

<p style="..."><strong>手术步骤、术中出现的情况及处理:</strong></p>
<p>1患者仰卧位...</p>
<p>2腹腔镜探查...</p>
...

替换为:

<p style="..."><strong>手术步骤、术中出现的情况及处理:</strong></p>
<div class="ai-region" data-ai-id="手术步骤" data-ai-title="手术步骤、术中出现的情况及处理" style="border: 1px dashed #3b82f6; padding: 16px 12px 12px; margin: 8px 0; position: relative; min-height: 60px; background: #f8fafc; border-radius: 6px;">
    <div contenteditable="false" style="position: absolute; top: -10px; right: 10px; background: #3b82f6; color: white; font-size: 10px; padding: 2px 8px; border-radius: 12px; z-index: 10; user-select: none;">手术步骤、术中出现的情况及处理-AI可编辑区域</div>
    <div class="ai-content" style="min-height: 20px;">
        <p>1患者仰卧位...</p>
        <p>2腹腔镜探查...</p>
        ...
    </div>
</div>

实现方案 BAPI 密钥安全增强

变更点 1默认值预设

src/types.ts line 92

kimi: { endpoint: 'https://api.moonshot.cn/v1', apiKey: 'sk-2IAFn8ORoSdUcCxYX6DmXJWbH7BxftSSA8kN88mD1KUDTmkv', modelName: 'moonshot-v1-auto' }

变更点 2前端防复制

src/pages/SystemSettings.tsx API Key input 添加事件拦截:

onCopy={(e) => e.preventDefault()}
onCut={(e) => e.preventDefault()}

变更点 3轻度加密存储

src/utils/storage.ts 增加透明加密层:

  • 使用 XOR + Base64 对 systemSettings key 的数据进行加解密
  • 加密密钥固定为 'MedicalReportSys2024'
  • 完全透明:所有调用方无需改动,get/set 自动处理
const CRYPTO_KEY = 'MedicalReportSys2024';

function xorEncrypt(text: string, key: string): string {
  let result = '';
  for (let i = 0; i < text.length; i++) {
    result += String.fromCharCode(text.charCodeAt(i) ^ key.charCodeAt(i % key.length));
  }
  return btoa(result);
}

function xorDecrypt(encrypted: string, key: string): string {
  const text = atob(encrypted);
  let result = '';
  for (let i = 0; i < text.length; i++) {
    result += String.fromCharCode(text.charCodeAt(i) ^ key.charCodeAt(i % key.length));
  }
  return result;
}

getset 中:

if (key === 'systemSettings') {
  data = xorEncrypt(JSON.stringify(value), CRYPTO_KEY);
  // 存储时加一个前缀标记以便区分
}

为保持向后兼容(旧数据是明文 JSON解密时先尝试 JSON.parse,如果失败再尝试 XOR 解密:

get<T>(key: string, fallback: T): T {
  try {
    const raw = localStorage.getItem(key);
    if (!raw) return fallback;
    if (key === 'systemSettings') {
      // 先尝试直接 JSON.parse兼容旧明文数据
      try {
        return JSON.parse(raw) as T;
      } catch {
        // 旧数据解析失败,尝试解密
        return JSON.parse(xorDecrypt(raw, CRYPTO_KEY)) as T;
      }
    }
    return JSON.parse(raw) as T;
  } catch {
    return fallback;
  }
}

实现方案 C默认模型名切换

变更点

  • src/types.ts line 92modelName: 'moonshot-v1-auto'
  • src/pages/SystemSettings.tsx migration fallback line 41modelName: 'moonshot-v1-auto'
  • src/pages/ReportEditor.tsx fallback line 901modelName = provider?.modelName || 'moonshot-v1-auto'

实现方案 D抽帧百分比 + 模式默认值

硬编码数组

const DEFAULT_FRAME_POSITIONS = [7.9, 9.3, 46.2, 49.1, 63.9, 64.8, 68.8, 73.7, 80.2, 85.0, 96.3, 98.6];

变更点

文件 位置 变更
src/pages/Login.tsx initData() framePositions 从均匀计算改为硬编码数组
src/pages/Login.tsx initData() frameMode 'uniform''keep'
src/pages/SystemSettings.tsx useState framePositions [5,10,...] → 硬编码数组
src/pages/SystemSettings.tsx useState frameMode 'uniform''keep'
src/pages/SystemSettings.tsx loaded settings fallback 'uniform''keep'
src/pages/SystemSettings.tsx resetToDefault() framePositions + frameMode
src/pages/ReportEditor.tsx fallback framePositions [5,10,...] → 硬编码数组

依赖与兼容性

  • 无新增 npm 依赖
  • storage 加密保持向后兼容:旧明文数据可正常读取,新写入的数据自动加密
  • 所有变更均为默认值修改,不影响已有用户配置(除非手动重置)