用户需要一个机器人多部位扫描检查的可视化UI界面。我需要设计一个专业、直观的界面,包含6个部位(腰部、左臂、右臂、左手、右手、头部)的扫描检查功能。这个界面需要支持自动/手动扫描、状态实时显示、进度可视化等。
首先,我需要理解使用场景:这是一个机器人扫描检查界面,可能用于工业机器人或医疗机器人的诊断。目标用户可能是技术人员或操作员。基调应该是专业、科技感强,但也要直观易用。考虑到是工业/医疗场景,设计应该偏向实用主义,但也要有现代感。
接下来,我需要获取设计系统推荐。既然是与机器人、扫描、科技相关,我应该查询类似"industrial robot monitoring dashboard"或"medical scanning interface"的设计系统。让我调用get_design_system工具。这个设计系统推荐比较基础,只推荐了Minimalism风格和Inter字体。但我需要更专业、更具科技感的界面。让我尝试更具体的查询。设计系统推荐似乎没有提供具体的配色方案和字体搭配。我需要自己做出设计决策。基于机器人扫描界面的特点,我选择"工业科技感"的美学方向,带有些许医疗设备的精确感。配色方案应该以深色为主,搭配醒目的状态色:橙色(扫描中)、绿色(正常)、红色(异常)、灰色(等待)。字体选择上,应该使用科技感强的等宽字体或现代无衬线字体。
考虑到是电脑/平板设备,breakpoint设置为none(默认)。界面布局:顶部进度条,中央部位面板(6个部位以可视化方式排列),底部操作区,右侧或下方实时日志区。
我需要获取一些机器人或科技相关的图片资源。让我调用get_assets工具搜索一些相关图片。不过,这个界面主要是图表和状态显示,可能不需要太多图片。但也许可以添加一个机器人轮廓图作为背景或参考。让我尝试搜索"robot silhouette tech"。这个图片不太适合。也许不需要图片,因为界面主要是状态显示和控件。我可以使用CSS绘制机器人轮廓或使用SVG。
现在开始设计决策:
1. **美学方向**:工业科技感,深色主题,强调清晰的状态指示和直观的操作。
2. **布局**:使用CSS Grid创建响应式布局。顶部进度条,中间左侧为部位面板(网格排列),中间右侧为日志区,底部为操作区。在平板和电脑上自适应。
3. **配色方案**:
- 背景:深灰色(#0f172a)
- 卡片背景:深蓝灰色(#1e293b)
- 边框:浅灰色(#334155)
- 状态色:
- 等待:灰色(#64748b)
- 扫描中:橙色(#f97316)
- 正常:绿色(#22c55e)
- 异常:红色(#ef4444)
- 文字:浅灰色(#f8fafc)
- 强调色:蓝色(#3b82f6)
4. **字体**:
- 标题:'Orbitron'(科技感强的无衬线字体,适合仪表盘)
- 正文:'Inter'或'Segoe UI',但考虑到设计系统推荐Inter,使用Inter作为回退字体。
5. **动效**:状态切换时有平滑过渡,扫描时部位有脉动动画,进度条动画。
6. **交互**:按钮有hover和active状态,部位卡片在扫描时有高亮效果。
现在开始编写HTML代码。我需要包含TailwindCSS,以及Google Fonts(Orbitron和Inter)。使用Font Awesome图标。实现完整的JavaScript逻辑来控制扫描流程:开始、暂停、重置,以及部位状态更新。
考虑到代码长度,我会尽量保持结构清晰。让我构思一下HTML结构:
- 容器:深色背景,全屏高度
- 顶部标题和进度条
- 主内容区:左侧部位面板(6个部位卡片),右侧日志区
- 底部操作按钮
部位排列:头部在顶部中央,腰部在中央,左臂/右臂在两侧,左手/右手在下方两侧。
使用CSS Grid或Flexbox排列部位卡片。
JavaScript逻辑:
- 定义部位顺序数组
- 当前扫描索引
- 定时器控制
- 状态更新函数
- 日志记录函数
现在开始编写代码。我会创建一个完整的HTML文件,包含内联的CSS和JavaScript。
注意:默认中文文案,使用Font Awesome图标(通过CDN引入),无表情符号,不使用任何浏览器存储API。
让我先获取当前时间,也许可以在日志中显示时间戳。调用query_time_date工具。现在开始编写最终输出。在内部思考完成后,我需要严格按照JSON格式输出,包含summary、widget、next和breakpoint。
让我在内部构建完整的HTML代码。代码会有点长,但我会确保其功能完整和美观。
现在开始构建HTML结构。没有找到配色方案,那我就使用自己设计的配色方案。
现在编写完整的HTML代码。我会创建一个有科技感的机器人扫描界面。
注意:最终输出必须是JSON格式。现在生成最终输出。现在开始输出最终结果。我将基于自己的设计决策来创建界面。现在输出最终结果。```json{
"summary": "设计了一个工业科技感的机器人扫描检查界面,采用深色主题配合状态色高亮,可视化排列6个扫描部位,实现自动扫描流程控制、实时状态显示和进度可视化。",
"widget": {"type":"full-html","html":"<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>机器人多部位扫描检查系统</title>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.c…\">\n <link href=\"https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700;900&…\" rel=\"stylesheet\">\n <style>\n :root {\n --bg-primary: #0f172a;\n --bg-secondary: #1e293b;\n --bg-card: #1e293b;\n --border-color: #334155;\n --text-primary: #f8fafc;\n --text-secondary: #cbd5e1;\n --status-waiting: #64748b;\n --status-scanning: #f97316;\n --status-normal: #22c55e;\n --status-abnormal: #ef4444;\n --accent-blue: #3b82f6;\n --accent-purple: #8b5cf6;\n }\n \n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n \n body {\n font-family: 'Inter', sans-serif;\n background-color: var(--bg-primary);\n color: var(--text-primary);\n min-height: 100vh;\n overflow-x: hidden;\n }\n \n .header-font {\n font-family: 'Orbitron', sans-serif;\n font-weight: 700;\n letter-spacing: 0.05em;\n }\n \n .robot-body-map {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n grid-template-rows: 1fr 1fr 1fr;\n gap: 1.5rem;\n width: 100%;\n max-width: 800px;\n margin: 0 auto;\n position: relative;\n }\n \n .body-part {\n transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);\n border: 2px solid var(--border-color);\n border-radius: 1rem;\n padding: 1.5rem 1rem;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n position: relative;\n overflow: hidden;\n background-color: rgba(30, 41, 59, 0.7);\n }\n \n .body-part::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(139, 92, 246, 0.05));\n z-index: 0;\n opacity: 0;\n transition: opacity 0.3s ease;\n }\n \n .body-part:hover::before {\n opacity: 1;\n }\n \n .body-part.status-waiting {\n border-color: var(--status-waiting);\n color: var(--status-waiting);\n }\n \n .body-part.status-scanning {\n border-color: var(--status-scanning);\n color: var(--text-primary);\n background-color: rgba(249, 115, 22, 0.1);\n animation: pulse-scanning 2s infinite;\n box-shadow: 0 0 20px rgba(249, 115, 22, 0.3);\n }\n \n .body-part.status-normal {\n border-color: var(--status-normal);\n color: var(--status-normal);\n background-color: rgba(34, 197, 94, 0.05);\n }\n \n .body-part.status-abnormal {\n border-color: var(--status-abnormal);\n color: var(--status-abnormal);\n background-color: rgba(239, 68, 68, 0.05);\n animation: pulse-alert 2s infinite;\n }\n \n @keyframes pulse-scanning {\n 0%, 100% { box-shadow: 0 0 20px rgba(249, 115, 22, 0.3); }\n 50% { box-shadow: 0 0 30px rgba(249, 115, 22, 0.5); }\n }\n \n @keyframes pulse-alert {\n 0%, 100% { box-shadow: 0 0 15px rgba(239, 68, 68, 0.3); }\n 50% { box-shadow: 0 0 25px rgba(239, 68, 68, 0.5); }\n }\n \n .status-indicator {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n margin-right: 0.5rem;\n }\n \n .status-waiting .status-indicator { background-color: var(--status-waiting); }\n .status-scanning .status-indicator { background-color: var(--status-scanning); }\n .status-normal .status-indicator { background-color: var(--status-normal); }\n .status-abnormal .status-indicator { background-color: var(--status-abnormal); }\n \n .progress-bar {\n height: 12px;\n border-radius: 6px;\n background-color: var(--bg-secondary);\n overflow: hidden;\n border: 1px solid var(--border-color);\n }\n \n .progress-fill {\n height: 100%;\n background: linear-gradient(90deg, var(--accent-blue), var(--accent-purple));\n border-radius: 6px;\n transition: width 0.5s ease;\n width: 0%;\n }\n \n .log-entry {\n border-left: 3px solid var(--border-color);\n padding: 0.75rem 1rem;\n margin-bottom: 0.75rem;\n background-color: rgba(30, 41, 59, 0.5);\n border-radius: 0 0.5rem 0.5rem 0;\n transition: all 0.3s ease;\n }\n \n .log-entry:hover {\n background-color: rgba(30, 41, 59, 0.8);\n transform: translateX(5px);\n }\n \n .log-time {\n color: var(--text-secondary);\n font-size: 0.85rem;\n font-family: 'Orbitron', monospace;\n }\n \n .log-message {\n color: var(--text-primary);\n font-size: 0.95rem;\n }\n \n .btn {\n padding: 0.875rem 1.75rem;\n border-radius: 0.75rem;\n font-weight: 600;\n font-size: 1rem;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n border: none;\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n font-family: 'Inter', sans-serif;\n }\n \n .btn-primary {\n background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple));\n color: white;\n }\n \n .btn-primary:hover {\n transform: translateY(-3px);\n box-shadow: 0 10px 25px rgba(59, 130, 246, 0.4);\n }\n \n .btn-secondary {\n background-color: var(--bg-secondary);\n color: var(--text-primary);\n border: 1px solid var(--border-color);\n }\n \n .btn-secondary:hover {\n background-color: rgba(51, 65, 85, 0.5);\n transform: translateY(-2px);\n }\n \n .btn-danger {\n background-color: var(--status-abnormal);\n color: white;\n }\n \n .btn-danger:hover {\n background-color: #dc2626;\n transform: translateY(-2px);\n }\n \n @media (max-width: 1024px) {\n .robot-body-map {\n grid-template-columns: 1fr 1fr;\n grid-template-rows: repeat(3, 1fr);\n max-width: 600px;\n }\n \n .body-part {\n padding: 1.25rem 0.75rem;\n }\n }\n \n @media (max-width: 640px) {\n .robot-body-map {\n grid-template-columns: 1fr;\n grid-template-rows: repeat(6, 1fr);\n max-width: 400px;\n }\n \n .btn {\n padding: 0.75rem 1.25rem;\n font-size: 0.9rem;\n }\n }\n </style>\n</head>\n<body class=\"min-h-screen flex flex-col p-4 md:p-6\">\n <!-- 头部区域 -->\n <header class=\"mb-6 md:mb-8\">\n <div class=\"flex flex-col md:flex-row justify-between items-start md:items-center gap-4\">\n <div>\n <h1 class=\"header-font text-2xl md:text-3xl lg:text-4xl text-white mb-2\">机器人多部位扫描检查系统</h1>\n <p class=\"text-gray-400 text-sm md:text-base\">实时监控机器人6个关键部位的健康状态与扫描进度</p>\n </div>\n <div class=\"flex items-center gap-3\">\n <div class=\"flex items-center gap-2\">\n <div class=\"w-3 h-3 rounded-full bg-green-500\"></div>\n <span class=\"text-sm text-gray-300\">在线</span>\n </div>\n <div class=\"text-sm text-gray-400 font-mono\">2026-04-18 16:21:49</div>\n </div>\n </div>\n </header>\n \n <!-- 进度条 -->\n <div class=\"mb-8 md:mb-10\">\n <div class=\"flex justify-between items-center mb-3\">\n <h2 class=\"header-font text-xl md:text-2xl text-white\">整体扫描进度</h2>\n <div class=\"text-lg md:text-xl font-bold text-white\"><span id=\"progress-percentage\">0%</span></div>\n </div>\n <div class=\"progress-bar\">\n <div id=\"progress-fill\" class=\"progress-fill\"></div>\n </div>\n </div>\n \n <main class=\"flex-1 grid grid-cols-1 lg:grid-cols-3 gap-6 md:gap-8 mb-8\">\n <!-- 左侧:机器人部位面板 -->\n <section class=\"lg:col-span-2\">\n <div class=\"bg-gray-900/50 rounded-2xl p-4 md:p-6 border border-gray-800 h-full\">\n <h2 class=\"header-font text-xl md:text-2xl text-white mb-6 flex items-center gap-3\">\n <i class=\"fas fa-robot text-blue-400\"></i>\n 扫描部位状态\n </h2>\n \n <div class=\"robot-body-map\">\n <!-- 头部 -->\n <div id=\"part-head\" class=\"body-part status-waiting\" data-part=\"head\" data-order=\"1\">\n <div class=\"flex items-center mb-3\">\n <div class=\"status-indicator\"></div>\n <span class=\"header-font text-lg\">头部</span>\n </div>\n <i class=\"fas fa-brain text-3xl mb-2\"></i>\n <div class=\"text-sm mt-2\">状态: <span class=\"font-bold status-text\">等待</span></div>\n <div class=\"text-xs text-gray-400 mt-1\">ID: ROBOT-HEAD-001</div>\n </div>\n \n <!-- 空单元格 -->\n <div></div>\n \n <!-- 空单元格 -->\n <div></div>\n \n <!-- 左臂 -->\n <div id=\"part-left-arm\" class=\"body-part status-waiting\" data-part=\"left-arm\" data-order=\"3\">\n <div class=\"flex items-center mb-3\">\n <div class=\"status-indicator\"></div>\n <span class=\"header-font text-lg\">左臂</span>\n </div>\n <i class=\"fas fa-hand-point-left text-3xl mb-2\"></i>\n <div class=\"text-sm mt-2\">状态: <span class=\"font-bold status-text\">等待</span></div>\n <div class=\"text-xs text-gray-400 mt-1\">ID: ROBOT-LARM-003</div>\n </div>\n \n <!-- 腰部 -->\n <div id=\"part-waist\" class=\"body-part status-waiting\" data-part=\"waist\" data-order=\"2\">\n <div class=\"flex items-center mb-3\">\n <div class=\"status-indicator\"></div>\n <span class=\"header-font text-lg\">腰部</span>\n </div>\n <i class=\"fas fa-cogs text-3xl mb-2\"></i>\n <div class=\"text-sm mt-2\">状态: <span class=\"font-bold status-text\">等待</span></div>\n <div class=\"text-xs text-gray-400 mt-1\">ID: ROBOT-WAIST-002</div>\n </div>\n \n <!-- 右臂 -->\n <div id=\"part-right-arm\" class=\"body-part status-waiting\" data-part=\"right-arm\" data-order=\"4\">\n <div class=\"flex items-center mb-3\">\n <div class=\"status-indicator\"></div>\n <span class=\"header-font text-lg\">右臂</span>\n </div>\n <i class=\"fas fa-hand-point-right text-3xl mb-2\"></i>\n <div class=\"text-sm mt-2\">状态: <span class=\"font-bold status-text\">等待</span></div>\n <div class=\"text-xs text-gray-400 mt-1\">ID: ROBOT-RARM-004</div>\n </div>\n \n <!-- 左手 -->\n <div id=\"part-left-hand\" class=\"body-part status-waiting\" data-part=\"left-hand\" data-order=\"5\">\n <div class=\"flex items-center mb-3\">\n <div class=\"status-indicator\"></div>\n <span class=\"header-font text-lg\">左手</span>\n </div>\n <i class=\"fas fa-hand-paper text-3xl mb-2\"></i>\n <div class=\"text-sm mt-2\">状态: <span class=\"font-bold status-text\">等待</span></div>\n <div class=\"text-xs text-gray-400 mt-1\">ID: ROBOT-LHAND-005</div>\n </div>\n \n <!-- 空单元格 -->\n <div></div>\n \n <!-- 右手 -->\n <div id=\"part-right-hand\" class=\"body-part status-waiting\" data-part=\"right-hand\" data-order=\"6\">\n <div class=\"flex items-center mb-3\">\n <div class=\"status-indicator\"></div>\n <span class=\"header-font text-lg\">右手</span>\n </div>\n <i class=\"fas fa-hand-paper text-3xl mb-2\"></i>\n <div class=\"text-sm mt-2\">状态: <span class=\"font-bold status-text\">等待</span></div>\n <div class=\"text-xs text-gray-400 mt-1\">ID: ROBOT-RHAND-006</div>\n </div>\n </div>\n \n <div class=\"mt-8 pt-6 border-t border-gray-800\">\n <h3 class=\"header-font text-lg text-white mb-4\">状态图例</h3>\n <div class=\"flex flex-wrap gap-4\">\n <div class=\"flex items-center gap-2\">\n <div class=\"w-4 h-4 rounded-full bg-gray-500\"></div>\n <span class=\"text-gray-300 text-sm\">等待扫描</span>\n </div>\n <div class=\"flex items-center gap-2\">\n <div class=\"w-4 h-4 rounded-full bg-orange-500\"></div>\n <span class=\"text-gray-300 text-sm\">正在扫描</span>\n </div>\n <div class=\"flex items-center gap-2\">\n <div class=\"w-4 h-4 rounded-full bg-green-500\"></div>\n <span class=\"text-gray-300 text-sm\">检查正常</span>\n </div>\n <div class=\"flex items-center gap-2\">\n <div class=\"w-4 h-4 rounded-full bg-red-500\"></div>\n <span class=\"text-gray-300 text-sm\">检查异常</span>\n </div>\n </div>\n </div>\n </div>\n </section>\n \n <!-- 右侧:日志区域 -->\n <section class=\"lg:col-span-1\">\n <div class=\"bg-gray-900/50 rounded-2xl p-4 md:p-6 border border-gray-800 h-full flex flex-col\">\n <h2 class=\"header-font text-xl md:text-2xl text-white mb-6 flex items-center gap-3\">\n <i class=\"fas fa-clipboard-list text-green-400\"></i>\n 实时扫描日志\n </h2>\n \n <div id=\"log-container\" class=\"flex-1 overflow-y-auto pr-2 mb-6\">\n <div class=\"log-entry\">\n <div class=\"log-time\">16:21:49</div>\n <div class=\"log-message\">系统初始化完成,机器人扫描检查系统准备就绪。</div>\n </div>\n <div class=\"log-entry\">\n <div class=\"log-time\">16:21:49</div>\n <div class=\"log-message\">所有6个扫描部位已就位,等待开始扫描指令。</div>\n </div>\n </div>\n \n <div class=\"pt-6 border-t border-gray-800\">\n <h3 class=\"header-font text-lg text-white mb-4\">扫描统计</h3>\n <div class=\"grid grid-cols-2 gap-4\">\n <div class=\"bg-gray-800/50 rounded-lg p-3\">\n <div class=\"text-gray-400 text-sm mb-1\">已扫描部位</div>\n <div class=\"text-2xl font-bold text-white\"><span id=\"scanned-count\">0</span>/6</div>\n </div>\n <div class=\"bg-gray-800/50 rounded-lg p-3\">\n <div class=\"text-gray-400 text-sm mb-1\">正常数量</div>\n <div class=\"text-2xl font-bold text-green-400\"><span id=\"normal-count\">0</span></div>\n </div>\n <div class=\"bg-gray-800/50 rounded-lg p-3\">\n <div class=\"text-gray-400 text-sm mb-1\">异常数量</div>\n <div class=\"text-2xl font-bold text-red-400\"><span id=\"abnormal-count\">0</span></div>\n </div>\n <div class=\"bg-gray-800/50 rounded-lg p-3\">\n <div class=\"text-gray-400 text-sm mb-1\">扫描耗时</div>\n <div class=\"text-2xl font-bold text-blue-400\"><span id=\"scan-time\">0</span>s</div>\n </div>\n </div>\n </div>\n </div>\n </section>\n </main>\n \n <!-- 底部操作区 -->\n <footer class=\"mt-auto\">\n <div class=\"bg-gray-900/50 rounded-2xl p-6 border border-gray-800\">\n <h2 class=\"header-font text-xl md:text-2xl text-white mb-6 text-center\">扫描流程控制</h2>\n \n <div class=\"flex flex-col md:flex-row justify-center items-center gap-4 md:gap-6\">\n <button id=\"btn-start\" class=\"btn btn-primary w-full md:w-auto\">\n <i class=\"fas fa-play-circle\"></i>\n 开始自动扫描\n </button>\n \n <button id=\"btn-pause\" class=\"btn btn-secondary w-full md:w-auto\" disabled>\n <i class=\"fas fa-pause-circle\"></i>\n 暂停扫描\n </button>\n \n <button id=\"btn-reset\" class=\"btn btn-danger w-full md:w-auto\">\n <i class=\"fas fa-redo\"></i>\n 重置检查\n </button>\n \n <button id=\"btn-manual\" class=\"btn btn-secondary w-full md:w-auto\">\n <i class=\"fas fa-hand-pointer\"></i>\n 手动选择扫描\n </button>\n </div>\n \n <div class=\"mt-8 text-center text-gray-400 text-sm\">\n <p><i class=\"fas fa-info-circle mr-2\"></i>扫描顺序: 头部 → 腰部 → 左臂 → 右臂 → 左手 → 右手 | 每个部位扫描时间: 3秒</p>\n </div>\n </div>\n </footer>\n \n <script>\n // 机器人部位数据\n const bodyParts = [\n { id: 'head', name: '头部', elementId: 'part-head', order: 1, status: 'waiting' },\n { id: 'waist', name: '腰部', elementId: 'part-waist', order: 2, status: 'waiting' },\n { id: 'left-arm', name: '左臂', elementId: 'part-left-arm', order: 3, status: 'waiting' },\n { id: 'right-arm', name: '右臂', elementId: 'part-right-arm', order: 4, status: 'waiting' },\n { id: 'left-hand', name: '左手', elementId: 'part-left-hand', order: 5, status: 'waiting' },\n { id: 'right-hand', name: '右手', elementId: 'part-right-hand', order: 6, status: 'waiting' }\n ];\n \n // 扫描状态\n let currentScanIndex = -1;\n let scanInterval = null;\n let isScanning = false;\n let isPaused = false;\n let scanTime = 0;\n let scanTimer = null;\n let normalCount = 0;\n let abnormalCount = 0;\n \n // DOM 元素\n const progressFill = document.getElementById('progress-fill');\n const progressPercentage = document.getElementById('progress-percentage');\n const logContainer = document.getElementById('log-container');\n const scannedCountEl = document.getElementById('scanned-count');\n const normalCountEl = document.getElementById('normal-count');\n const abnormalCountEl = document.getElementById('abnormal-count');\n const scanTimeEl = document.getElementById('scan-time');\n \n // 按钮\n const btnStart = document.getElementById('btn-start');\n const btnPause = document.getElementById('btn-pause');\n const btnReset = document.getElementById('btn-reset');\n const btnManual = document.getElementById('btn-manual');\n \n // 添加日志\n function addLog(message) {\n const now = new Date();\n const timeString = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;\n \n const logEntry = document.createElement('div');\n logEntry.className = 'log-entry';\n logEntry.innerHTML = `\n <div class=\"log-time\">${timeString}</div>\n <div class=\"log-message\">${message}</div>\n `;\n \n logContainer.prepend(logEntry);\n \n // 限制日志数量\n const logs = logContainer.querySelectorAll('.log-entry');\n if (logs.length > 10) {\n logs[logs.length - 1].remove();\n }\n }\n \n // 更新进度\n function updateProgress() {\n const scanned = bodyParts.filter(part => part.status === 'normal' || part.status === 'abnormal').length;\n const progress = Math.round((scanned / bodyParts.length) * 100);\n \n progressFill.style.width = `${progress}%`;\n progressPercentage.textContent = `${progress}%`;\n scannedCountEl.textContent = scanned;\n \n // 更新统计\n normalCountEl.textContent = normalCount;\n abnormalCountEl.textContent = abnormalCount;\n \n return progress;\n }\n \n // 更新部位状态\n function updatePartStatus(partId, newStatus) {\n const part = bodyParts.find(p => p.id === partId);\n if (!part) return;\n \n const partElement = document.getElementById(part.elementId);\n const statusText = partElement.querySelector('.status-text');\n \n // 移除旧状态类\n partElement.classList.remove('status-waiting', 'status-scanning', 'status-normal', 'status-abnormal');\n \n // 更新状态\n part.status = newStatus;\n partElement.classList.add(`status-${newStatus}`);\n \n // 更新状态文本\n let statusName = '';\n switch(newStatus) {\n case 'waiting': statusName = '等待'; break;\n case 'scanning': statusName = '扫描中'; break;\n case 'normal': statusName = '正常'; break;\n case 'abnormal': statusName = '异常'; break;\n }\n statusText.textContent = statusName;\n \n // 更新计数\n if (newStatus === 'normal') normalCount++;\n if (newStatus === 'abnormal') abnormalCount++;\n \n updateProgress();\n }\n \n // 开始扫描计时\n function startScanTimer() {\n scanTime = 0;\n scanTimeEl.textContent = scanTime;\n \n if (scanTimer) clearInterval(scanTimer);\n \n scanTimer = setInterval(() => {\n if (isScanning && !isPaused) {\n scanTime++;\n scanTimeEl.textContent = scanTime;\n }\n }, 1000);\n }\n \n // 开始扫描\n function startScan() {\n if (isScanning) return;\n \n isScanning = true;\n isPaused = false;\n currentScanIndex = 0;\n \n btnStart.disabled = true;\n btnPause.disabled = false;\n btnReset.disabled = true;\n btnManual.disabled = true;\n \n addLog('开始自动扫描流程...');\n startScanTimer();\n \n // 开始扫描第一个部位\n scanNextPart();\n }\n \n // 扫描下一个部位\n function scanNextPart() {\n if (currentScanIndex >= bodyParts.length) {\n completeScan();\n return;\n }\n \n const part = bodyParts[currentScanIndex];\n \n // 设置当前部位为扫描中\n updatePartStatus(part.id, 'scanning');\n addLog(`开始扫描 ${part.name}...`);\n \n // 模拟扫描过程(3秒)\n if (scanInterval) clearInterval(scanInterval);\n \n scanInterval = setTimeout(() => {\n // 随机决定扫描结果(正常或异常)\n const isNormal = Math.random() > 0.2; // 80%正常,20%异常\n const resultStatus = isNormal ? 'normal' : 'abnormal';\n \n updatePartStatus(part.id, resultStatus);\n addLog(`${part.name} 扫描完成: ${isNormal ? '正常 ✓' : '异常 ✗'}`);\n \n // 移动到下一个部位\n currentScanIndex++;\n \n // 如果不是暂停状态,继续扫描\n if (!isPaused) {\n setTimeout(scanNextPart, 500); // 0.5秒后扫描下一个部位\n }\n }, 3000);\n }\n \n // 暂停/继续扫描\n function togglePause() {\n if (!isScanning) return;\n \n isPaused = !isPaused;\n \n if (isPaused) {\n btnPause.innerHTML = '<i class=\"fas fa-play-circle\"></i> 继续扫描';\n addLog('扫描已暂停');\n \n // 如果当前有正在扫描的部位,将其状态设为等待\n if (currentScanIndex >= 0 && currentScanIndex < bodyParts.length) {\n const currentPart = bodyParts[currentScanIndex];\n if (currentPart.status === 'scanning') {\n updatePartStatus(currentPart.id, 'waiting');\n }\n }\n } else {\n btnPause.innerHTML = '<i class=\"fas fa-pause-circle\"></i> 暂停扫描';\n addLog('扫描已继续');\n \n // 继续扫描\n scanNextPart();\n }\n }\n \n // 重置检查\n function resetScan() {\n // 清除所有定时器\n if (scanInterval) clearInterval(scanInterval);\n if (scanTimer) clearInterval(scanTimer);\n \n // 重置状态\n isScanning = false;\n isPaused = false;\n currentScanIndex = -1;\n scanTime = 0;\n normalCount = 0;\n abnormalCount = 0;\n \n // 重置所有部位状态\n bodyParts.forEach(part => {\n updatePartStatus(part.id, 'waiting');\n });\n \n // 重置进度条\n progressFill.style.width = '0%';\n progressPercentage.textContent = '0%';\n \n // 更新统计\n scannedCountEl.textContent = '0';\n normalCountEl.textContent = '0';\n abnormalCountEl.textContent = '0';\n scanTimeEl.textContent = '0';\n \n // 重置按钮状态\n btnStart.disabled = false;\n btnPause.disabled = true;\n btnReset.disabled = false;\n btnManual.disabled = false;\n btnPause.innerHTML = '<i class=\"fas fa-pause-circle\"></i> 暂停扫描';\n \n addLog('扫描已重置,系统恢复初始状态。');\n }\n \n // 完成扫描\n function completeScan() {\n isScanning = false;\n \n btnStart.disabled = false;\n btnPause.disabled = true;\n btnReset.disabled = false;\n btnManual.disabled = false;\n \n addLog('全部6个部位扫描完成!');\n addLog(`扫描统计: 正常 ${normalCount} 个,异常 ${abnormalCount} 个,总耗时 ${scanTime} 秒。`);\n \n // 清除扫描定时器\n if (scanInterval) clearInterval(scanInterval);\n }\n \n // 手动选择扫描部位\n function manualScan() {\n if (isScanning) {\n addLog('当前正在自动扫描中,无法手动选择。');\n return;\n }\n \n // 提示用户选择部位\n addLog('请点击上方的部位卡片进行手动扫描...');\n \n // 为所有部位添加点击事件\n bodyParts.forEach(part => {\n const partElement = document.getElementById(part.elementId);\n partElement.style.cursor = 'pointer';\n \n const originalClickHandler = partElement.onclick;\n partElement.onclick = function() {\n if (part.status === 'waiting') {\n updatePartStatus(part.id, 'scanning');\n addLog(`开始手动扫描 ${part.name}...`);\n \n // 模拟扫描过程\n setTimeout(() => {\n const isNormal = Math.random() > 0.2;\n const resultStatus = isNormal ? 'normal' : 'abnormal';\n updatePartStatus(part.id, resultStatus);\n addLog(`${part.name} 手动扫描完成: ${isNormal ? '正常 ✓' : '异常 ✗'}`);\n updateProgress();\n }, 2000);\n } else {\n addLog(`${part.name} 已经扫描过,请选择其他未扫描部位。`);\n }\n };\n });\n \n setTimeout(() => {\n addLog('手动扫描模式已激活。');\n }, 100);\n }\n \n // 事件监听\n btnStart.addEventListener('click', startScan);\n btnPause.addEventListener('click', togglePause);\n btnReset.addEventListener('click', resetScan);\n btnManual.addEventListener('click', manualScan);\n \n // 初始化\n document.addEventListener('DOMContentLoaded', function() {\n addLog('机器人扫描检查系统初始化完成。');\n updateProgress();\n });\n </script>\n</body>\n</html>"},
"next": ["增加异常部位详细报告","添加扫描历史记录","支持自定义扫描顺序","增加数据导出功能","集成声音提示系统"],
"breakpoint": "none"
}```