- Introduced a new restore button in the SW debug panel for restoring data from ZIP backups. - Implemented `BackupPartManager` to handle automatic chunking during backup processes. - Enhanced the backup process to include tasks, prompts, and assets, with progress updates. - Updated version to 0.6.7 and adjusted build time in `version.json`. - Refactored existing backup logic to support the new restoration features.
1140 lines
63 KiB
HTML
1140 lines
63 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Service Worker 调试面板</title>
|
|
<link rel="stylesheet" href="./sw-debug/styles.css">
|
|
<!-- JSZip for backup functionality - local copy for reliability -->
|
|
<script src="./sw-debug/jszip.min.js"></script>
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<h1>
|
|
<span class="icon">⚙️</span>
|
|
<span id="panelTitle">Service Worker 调试面板</span>
|
|
<span id="swStatus" class="status-indicator inactive">
|
|
<span class="dot"></span>
|
|
<span class="text">未连接</span>
|
|
</span>
|
|
<span id="analysisModeIndicator" class="mode-indicator analysis-mode" style="display: none;">
|
|
<span class="icon">🔍</span>
|
|
<span class="text">分析模式</span>
|
|
</span>
|
|
</h1>
|
|
<div class="header-actions">
|
|
<!-- 移动端状态面板切换按钮 -->
|
|
<button id="toggleStatusPanel" class="icon-btn mobile-only" title="显示/隐藏状态信息">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/>
|
|
</svg>
|
|
</button>
|
|
<!-- 模式切换按钮 -->
|
|
<button id="toggleAnalysisMode" class="icon-btn" title="切换到分析模式(导入用户日志)">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/>
|
|
</svg>
|
|
</button>
|
|
<!-- 导入日志按钮 (分析模式下显示) -->
|
|
<button id="importLogs" style="display: none;">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M17 8l-5-5-5 5M12 3v12"/>
|
|
</svg>
|
|
导入日志
|
|
</button>
|
|
<input type="file" id="importLogsInput" accept=".json" style="display: none;">
|
|
<!-- 数据备份按钮 -->
|
|
<button id="backupData" class="success" title="备份应用数据(提示词、项目、素材)">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
|
|
<polyline points="17 21 17 13 7 13 7 21"/>
|
|
<polyline points="7 3 7 8 15 8"/>
|
|
</svg>
|
|
数据备份
|
|
</button>
|
|
<!-- 恢复备份按钮 -->
|
|
<button id="restoreBackup" class="primary" title="从备份 ZIP 恢复数据">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M3 15v4a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-4M7 10l5 5 5-5M12 15V3"/>
|
|
</svg>
|
|
恢复备份
|
|
</button>
|
|
<input type="file" id="restoreBackupInput" accept=".zip" style="display: none;">
|
|
<button id="toggleTheme" class="icon-btn" title="切换深色/浅色主题">
|
|
<svg id="themeIcon" class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
|
</svg>
|
|
</button>
|
|
<button id="toggleDebug" class="danger debug-mode-only">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/>
|
|
</svg>
|
|
停止调试
|
|
</button>
|
|
<button id="exportLogs" class="success">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/>
|
|
</svg>
|
|
导出日志
|
|
</button>
|
|
|
|
<!-- 设置弹窗 -->
|
|
<div class="export-modal-overlay" id="settingsModalOverlay" style="display: none;">
|
|
<div class="export-modal" style="max-width: 450px;">
|
|
<div class="export-modal-header">
|
|
<h3>⚙️ 日志设置</h3>
|
|
<button class="close-btn" id="closeSettingsModal">×</button>
|
|
</div>
|
|
<div class="export-modal-content" style="padding: 16px;">
|
|
<div class="setting-group">
|
|
<label class="setting-label">日志最大保留条数</label>
|
|
<select id="settingMaxLogs" style="width: 100%; padding: 8px; border-radius: 4px; border: 1px solid var(--border-color);">
|
|
<option value="200">200 条</option>
|
|
<option value="500" selected>500 条(默认)</option>
|
|
<option value="1000">1000 条</option>
|
|
<option value="2000">2000 条</option>
|
|
</select>
|
|
</div>
|
|
<div class="setting-group" style="margin-top: 16px;">
|
|
<label class="setting-label">自动清理超过指定时间的日志</label>
|
|
<select id="settingAutoClean" style="width: 100%; padding: 8px; border-radius: 4px; border: 1px solid var(--border-color);">
|
|
<option value="0" selected>不自动清理</option>
|
|
<option value="30">30 分钟前</option>
|
|
<option value="60">1 小时前</option>
|
|
<option value="120">2 小时前</option>
|
|
</select>
|
|
</div>
|
|
<div class="setting-group" style="margin-top: 16px;">
|
|
<label style="display: flex; align-items: center; cursor: pointer;">
|
|
<input type="checkbox" id="settingKeepBookmarks" checked style="margin-right: 8px;">
|
|
自动清理时保留收藏的日志
|
|
</label>
|
|
</div>
|
|
<div style="margin-top: 20px; text-align: right;">
|
|
<button id="saveSettings" class="primary" style="padding: 8px 24px;">保存</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 快捷键帮助弹窗 -->
|
|
<div class="export-modal-overlay" id="shortcutsModalOverlay" style="display: none;">
|
|
<div class="export-modal" style="max-width: 400px;">
|
|
<div class="export-modal-header">
|
|
<h3>⌨️ 键盘快捷键</h3>
|
|
<button class="close-btn" id="closeShortcutsModal">×</button>
|
|
</div>
|
|
<div class="export-modal-content" style="padding: 16px;">
|
|
<table style="width: 100%; border-collapse: collapse; font-size: 13px;">
|
|
<tr><td style="padding: 8px 0; width: 140px;"><kbd style="background:#e0e0e0;padding:2px 6px;border-radius:3px;">1</kbd> - <kbd style="background:#e0e0e0;padding:2px 6px;border-radius:3px;">5</kbd></td><td>切换 Tab</td></tr>
|
|
<tr><td style="padding: 8px 0;"><kbd style="background:#e0e0e0;padding:2px 6px;border-radius:3px;">Space</kbd></td><td>暂停/恢复实时日志</td></tr>
|
|
<tr><td style="padding: 8px 0;"><kbd style="background:#e0e0e0;padding:2px 6px;border-radius:3px;">Ctrl</kbd>+<kbd style="background:#e0e0e0;padding:2px 6px;border-radius:3px;">L</kbd></td><td>清空当前 Tab 日志</td></tr>
|
|
<tr><td style="padding: 8px 0;"><kbd style="background:#e0e0e0;padding:2px 6px;border-radius:3px;">Esc</kbd></td><td>关闭弹窗</td></tr>
|
|
<tr><td style="padding: 8px 0;"><kbd style="background:#e0e0e0;padding:2px 6px;border-radius:3px;">?</kbd></td><td>显示此帮助</td></tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 导出日志弹窗 -->
|
|
<div class="export-modal-overlay" id="exportModalOverlay">
|
|
<div class="export-modal">
|
|
<div class="export-modal-header">
|
|
<h3>📥 导出日志</h3>
|
|
<button class="export-modal-close" id="closeExportModal">×</button>
|
|
</div>
|
|
<div class="export-modal-body">
|
|
<!-- 全选 -->
|
|
<label class="export-checkbox export-select-all">
|
|
<input type="checkbox" id="selectAllExport">
|
|
<span>全选</span>
|
|
</label>
|
|
|
|
<!-- 基本信息 -->
|
|
<div class="export-section">
|
|
<label class="export-checkbox export-section-header">
|
|
<input type="checkbox" data-section="basic" checked>
|
|
<span>基本信息</span>
|
|
</label>
|
|
<div class="export-section-items">
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="basic" value="swStatus" checked>
|
|
<span>SW 状态</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="basic" value="memory" checked>
|
|
<span>内存信息</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="basic" value="cache" checked>
|
|
<span>缓存信息</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Fetch 请求日志 -->
|
|
<div class="export-section">
|
|
<label class="export-checkbox export-section-header">
|
|
<input type="checkbox" data-section="fetch">
|
|
<span>Fetch 请求日志</span>
|
|
</label>
|
|
<div class="export-section-items">
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="fetch" value="sw-internal">
|
|
<span>SW 内部 API</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="fetch" value="xhr">
|
|
<span>XHR/API</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="fetch" value="image">
|
|
<span>图片</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="fetch" value="video">
|
|
<span>视频</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="fetch" value="font">
|
|
<span>字体</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="fetch" value="static">
|
|
<span>静态资源</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="fetch" value="cache-url">
|
|
<span>缓存 URL</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="fetch" value="asset-library">
|
|
<span>素材库</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 控制台日志 -->
|
|
<div class="export-section">
|
|
<label class="export-checkbox export-section-header">
|
|
<input type="checkbox" data-section="console">
|
|
<span>控制台日志</span>
|
|
</label>
|
|
<div class="export-section-items">
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="console" value="error">
|
|
<span>Error</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="console" value="warn">
|
|
<span>Warn</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="console" value="info">
|
|
<span>Info</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="console" value="log">
|
|
<span>Log</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="console" value="debug">
|
|
<span>Debug</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- PostMessage 日志 -->
|
|
<div class="export-section">
|
|
<label class="export-checkbox export-section-header">
|
|
<input type="checkbox" data-section="postmessage">
|
|
<span>PostMessage 日志</span>
|
|
</label>
|
|
<div class="export-section-items">
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="postmessage" value="receive">
|
|
<span>应用页面</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="postmessage" value="send">
|
|
<span>SW</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- LLM API 日志 -->
|
|
<div class="export-section">
|
|
<label class="export-checkbox export-section-header">
|
|
<input type="checkbox" data-section="llmapi" checked>
|
|
<span>LLM API 日志</span>
|
|
</label>
|
|
<div class="export-section-items">
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="llmapi" value="image" checked>
|
|
<span>图片生成</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="llmapi" value="video" checked>
|
|
<span>视频生成</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="llmapi" value="chat" checked>
|
|
<span>对话</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="llmapi" value="character" checked>
|
|
<span>角色</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 内存日志 -->
|
|
<div class="export-section">
|
|
<label class="export-checkbox export-section-header">
|
|
<input type="checkbox" data-section="memory">
|
|
<span>内存日志</span>
|
|
</label>
|
|
<div class="export-section-items">
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="memory" value="startup">
|
|
<span>启动快照</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="memory" value="periodic">
|
|
<span>定期快照</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="memory" value="error">
|
|
<span>错误</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="memory" value="freeze">
|
|
<span>卡死</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="memory" value="whitescreen">
|
|
<span>白屏</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="memory" value="longtask">
|
|
<span>长任务</span>
|
|
</label>
|
|
<label class="export-checkbox">
|
|
<input type="checkbox" name="memory" value="beforeunload">
|
|
<span>页面关闭</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="export-modal-footer">
|
|
<button id="cancelExport" class="secondary">取消</button>
|
|
<button id="doExport" class="primary">确认导出</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button id="clearLogs" class="danger debug-mode-only">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
|
</svg>
|
|
清空日志
|
|
</button>
|
|
<button id="refreshStatus" class="debug-mode-only">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/>
|
|
</svg>
|
|
刷新状态
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="container">
|
|
<div class="panels">
|
|
<!-- Left Panel: Status & Cache -->
|
|
<div class="left-panel">
|
|
<div class="panel">
|
|
<div class="panel-header">
|
|
SW 状态信息
|
|
</div>
|
|
<div class="panel-content">
|
|
<div class="stat-grid" id="statusGrid">
|
|
<div class="stat-item">
|
|
<span class="label">版本</span>
|
|
<span class="value" id="swVersion">-</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="label">调试模式</span>
|
|
<span class="value" id="debugMode">关闭</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="label">Pending 图片请求</span>
|
|
<span class="value" id="pendingImages">0</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="label">Pending 视频请求</span>
|
|
<span class="value" id="pendingVideos">0</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="label">视频 Blob 缓存</span>
|
|
<span class="value" id="videoBlobCache">0</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="label">已完成请求缓存</span>
|
|
<span class="value" id="completedRequests">0</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="label">工作流处理器</span>
|
|
<span class="value" id="workflowHandler">未初始化</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="label">调试日志数</span>
|
|
<span class="value" id="debugLogsCount">0</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="failedDomainsSection" style="margin-top: 16px; display: none;">
|
|
<div class="stat-item" style="flex-direction: column; align-items: flex-start;">
|
|
<span class="label">失败域名</span>
|
|
<div class="failed-domains" id="failedDomains"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<div class="panel-header">
|
|
内存监控
|
|
<span id="memoryUpdateTime" style="font-size: 11px; opacity: 0.6; margin-left: 10px;"></span>
|
|
</div>
|
|
<div class="panel-content">
|
|
<div class="stat-grid" id="memoryGrid">
|
|
<div class="stat-item">
|
|
<span class="label">JS 堆已使用</span>
|
|
<span class="value" id="memoryUsed">-</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="label">JS 堆总大小</span>
|
|
<span class="value" id="memoryTotal">-</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="label">JS 堆上限</span>
|
|
<span class="value" id="memoryLimit">-</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="label">使用率</span>
|
|
<span class="value" id="memoryPercent">-</span>
|
|
</div>
|
|
</div>
|
|
<p id="memoryWarning" style="display: none; margin-top: 12px; padding: 8px; background: #fff3cd; border-radius: 4px; font-size: 12px; color: #856404;">
|
|
⚠️ 内存使用率较高,可能导致页面崩溃
|
|
</p>
|
|
<p id="memoryNotSupported" style="display: none; margin-top: 8px; font-size: 11px; opacity: 0.6;">
|
|
注:performance.memory 仅 Chrome 支持
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<div class="panel-header">
|
|
缓存统计
|
|
<button id="refreshCache">刷新</button>
|
|
</div>
|
|
<div class="panel-content">
|
|
<ul class="cache-list" id="cacheList">
|
|
<li class="cache-item">
|
|
<span class="name">加载中...</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right Panel: Logs -->
|
|
<div class="panel logs-panel">
|
|
<div class="tabs">
|
|
<div class="tab active" data-tab="fetch">Fetch 请求日志 <span id="fetchCount" style="opacity:0.6"></span></div>
|
|
<div class="tab" data-tab="console">控制台日志 <span id="consoleCount" style="opacity:0.6">(0)</span><span id="consoleErrorDot" class="error-dot" style="display:none"></span></div>
|
|
<div class="tab" data-tab="postmessage">PostMessage日志 <span id="postmessageCount" style="opacity:0.6">(0)</span></div>
|
|
<div class="tab" data-tab="llmapi">LLM API <span id="llmapiErrorDot" class="error-dot" style="display:none"></span></div>
|
|
<div class="tab debug-mode-only" data-tab="gist">Gist 管理</div>
|
|
<div class="tab" data-tab="crash">内存日志 <span id="crashCount" style="opacity:0.6">(0)</span><span id="crashErrorDot" class="error-dot" style="display:none"></span></div>
|
|
</div>
|
|
|
|
<!-- Fetch Logs Tab -->
|
|
<div class="tab-content active" id="fetchTab">
|
|
<div class="stats-bar" id="fetchStatsBar">
|
|
<div class="stat"><span>总请求:</span> <span class="stat-value" id="statTotalRequests">0</span></div>
|
|
<div class="stat"><span>成功率:</span> <span class="stat-value" id="statSuccessRate">-</span></div>
|
|
<div class="stat"><span>平均耗时:</span> <span class="stat-value" id="statAvgDuration">-</span></div>
|
|
<div class="stat"><span>缓存命中:</span> <span class="stat-value" id="statCacheHit">-</span></div>
|
|
<div class="stat stat-clickable" id="statSlowRequestsWrapper" title="点击过滤慢请求 (>1s)"><span>慢请求:</span> <span class="stat-value" id="statSlowRequests">0</span></div>
|
|
<div class="stat stat-chart" title="耗时分布: <100ms | 100-500ms | 500ms-1s | >1s">
|
|
<span>分布:</span>
|
|
<div class="duration-chart" id="durationChart">
|
|
<div class="chart-bar fast" id="chartFast" style="width: 0%"></div>
|
|
<div class="chart-bar medium" id="chartMedium" style="width: 0%"></div>
|
|
<div class="chart-bar slow" id="chartSlow" style="width: 0%"></div>
|
|
<div class="chart-bar very-slow" id="chartVerySlow" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="logs-toolbar">
|
|
<select id="filterType">
|
|
<option value="">全部类型</option>
|
|
<option value="xhr">XHR/API</option>
|
|
<option value="sw-internal" selected>SW内部API</option>
|
|
<option value="image">图片</option>
|
|
<option value="video">视频</option>
|
|
<option value="font">字体</option>
|
|
<option value="static">静态资源</option>
|
|
<option value="navigation">导航</option>
|
|
<option value="cache-url">缓存URL</option>
|
|
<option value="asset-library">素材库</option>
|
|
<option value="passthrough">放行</option>
|
|
</select>
|
|
<select id="filterStatus">
|
|
<option value="">全部状态</option>
|
|
<option value="error">❌ 失败请求</option>
|
|
<option value="200">200 OK</option>
|
|
<option value="206">206 Partial</option>
|
|
<option value="304">304 Not Modified</option>
|
|
<option value="404">404 Not Found</option>
|
|
<option value="500">5xx Error</option>
|
|
<option value="slow">慢请求 (>1s)</option>
|
|
</select>
|
|
<select id="filterTimeRange">
|
|
<option value="">全部时间</option>
|
|
<option value="5">最近 5 分钟</option>
|
|
<option value="15">最近 15 分钟</option>
|
|
<option value="30">最近 30 分钟</option>
|
|
<option value="60">最近 1 小时</option>
|
|
</select>
|
|
<input type="text" id="filterUrl" placeholder="搜索 URL...">
|
|
<label class="regex-toggle" title="启用正则表达式搜索">
|
|
<input type="checkbox" id="filterUrlRegex">
|
|
<span style="font-size: 11px; margin-left: 2px;">.*</span>
|
|
</label>
|
|
<button id="togglePause" title="暂停/恢复实时更新 (快捷键: Space)">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="5 3 19 12 5 21 5 3"/></svg>
|
|
实时
|
|
</button>
|
|
<button id="toggleSelectMode" title="批量选择模式">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
|
|
选择
|
|
</button>
|
|
<div id="batchActions" class="batch-actions" style="display: none;">
|
|
<button id="selectAll">全选</button>
|
|
<button id="batchBookmark">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>
|
|
收藏
|
|
</button>
|
|
<button id="batchDelete" class="danger">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
删除
|
|
</button>
|
|
<span id="selectedCount" class="selected-count">已选 0 条</span>
|
|
</div>
|
|
<button id="copyFetchLogs" title="复制日志">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
复制
|
|
</button>
|
|
<button id="exportFetchCSV" title="导出为 CSV">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
|
|
CSV
|
|
</button>
|
|
<button id="showShortcuts" class="icon-btn" title="显示快捷键帮助">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="M6 8h.01M10 8h.01M14 8h.01M18 8h.01M8 12h8M6 16h.01M18 16h.01M10 16h4"/></svg>
|
|
</button>
|
|
<button id="showSettings" class="icon-btn" title="日志设置">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
|
</button>
|
|
<label class="bookmark-toggle" title="只显示收藏的日志">
|
|
<input type="checkbox" id="showBookmarksOnly">
|
|
<span>⭐</span>
|
|
</label>
|
|
<label class="switch-toggle">
|
|
<span class="switch-label">自动滚动</span>
|
|
<input type="checkbox" id="autoScroll" checked>
|
|
<span class="switch-slider"></span>
|
|
</label>
|
|
</div>
|
|
<div class="logs-container" id="logsContainer">
|
|
<div class="empty-state">
|
|
<span class="icon">📋</span>
|
|
<p>暂无日志,请先启用调试模式</p>
|
|
<button id="enableDebugBtn" class="primary">启用调试</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Console Logs Tab -->
|
|
<div class="tab-content" id="consoleTab">
|
|
<div class="logs-toolbar">
|
|
<select id="filterConsoleLevel">
|
|
<option value="">全部级别</option>
|
|
<option value="error">Error</option>
|
|
<option value="warn">Warn</option>
|
|
<option value="info">Info</option>
|
|
<option value="log">Log</option>
|
|
<option value="debug">Debug</option>
|
|
</select>
|
|
<input type="text" id="filterConsoleText" placeholder="搜索日志内容...">
|
|
<button id="clearConsoleLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
清空
|
|
</button>
|
|
<button id="copyConsoleLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
复制
|
|
</button>
|
|
</div>
|
|
<div class="logs-container" id="consoleContainer">
|
|
<div id="consoleLogsContainer">
|
|
<div class="empty-state">
|
|
<span class="icon">📝</span>
|
|
<p>暂无控制台日志</p>
|
|
<p style="font-size: 12px; opacity: 0.7;">warn/error 始终捕获;开启调试后也捕获 log/info/debug(仅在调试模式启用时完整记录)</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- PostMessage Logs Tab -->
|
|
<div class="tab-content" id="postmessageTab">
|
|
<div class="logs-toolbar">
|
|
<button id="togglePmPause" title="暂停/恢复实时日志">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="5 3 19 12 5 21 5 3"/></svg>
|
|
实时
|
|
</button>
|
|
<select id="filterMessageSource">
|
|
<option value="">全部来源</option>
|
|
<option value="main">应用页面</option>
|
|
<option value="sw">SW</option>
|
|
</select>
|
|
<select id="filterMessageTypeSelect">
|
|
<option value="">全部消息类型</option>
|
|
</select>
|
|
<select id="filterPmTimeRange">
|
|
<option value="">全部时间</option>
|
|
<option value="5">最近 5 分钟</option>
|
|
<option value="15">最近 15 分钟</option>
|
|
<option value="30">最近 30 分钟</option>
|
|
</select>
|
|
<input type="text" id="filterMessageType" placeholder="搜索消息类型...">
|
|
<button id="clearPostmessageLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
清空
|
|
</button>
|
|
<button id="copyPostmessageLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
复制
|
|
</button>
|
|
</div>
|
|
<div class="logs-container" id="postmessageContainer">
|
|
<div id="postmessageLogsContainer">
|
|
<div class="empty-state">
|
|
<span class="icon">📨</span>
|
|
<p>暂无 PostMessage 日志</p>
|
|
<p style="font-size: 12px; opacity: 0.7;">记录主线程与 Service Worker 之间的消息通信(仅在调试模式启用时记录)</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- LLM API Logs Tab -->
|
|
<div class="tab-content" id="llmapiTab">
|
|
<div class="logs-toolbar">
|
|
<select id="filterLLMApiType">
|
|
<option value="">全部类型</option>
|
|
<option value="image">图片生成</option>
|
|
<option value="video">视频生成</option>
|
|
<option value="chat">对话</option>
|
|
<option value="character">角色</option>
|
|
</select>
|
|
<select id="filterLLMApiStatus">
|
|
<option value="">全部状态</option>
|
|
<option value="success">成功</option>
|
|
<option value="error">失败</option>
|
|
<option value="pending">进行中</option>
|
|
</select>
|
|
<button id="refreshLLMApiLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
|
|
刷新
|
|
</button>
|
|
<button id="copyLLMApiLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
复制
|
|
</button>
|
|
<button id="exportLLMApiLogs" class="success">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
|
|
导出
|
|
</button>
|
|
<button id="clearLLMApiLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
清空
|
|
</button>
|
|
<button id="toggleLLMApiSelectMode">☑️ 选择</button>
|
|
<div id="llmapiBatchActions" class="batch-actions" style="display: none;">
|
|
<button id="llmapiSelectAll">全选</button>
|
|
<button id="llmapiBatchDelete" class="danger">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
删除
|
|
</button>
|
|
<span id="llmapiSelectedCount" style="color: var(--text-muted); font-size: 12px;">已选 0 条</span>
|
|
</div>
|
|
</div>
|
|
<div class="logs-container" id="llmapiContainer">
|
|
<div id="llmapiLogsContainer">
|
|
<div class="empty-state">
|
|
<span class="icon">🤖</span>
|
|
<p>暂无 LLM API 调用记录</p>
|
|
<p style="font-size: 12px; opacity: 0.7;">图片/视频/对话等 AI 接口调用会自动记录</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Gist Management Tab -->
|
|
<div class="tab-content" id="gistTab">
|
|
<div class="logs-toolbar">
|
|
<button id="refreshGistBtn">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
|
|
刷新数据
|
|
</button>
|
|
<span id="gistStatus" style="font-size: 12px; margin-left: 10px; color: var(--text-secondary);">点击刷新加载数据</span>
|
|
</div>
|
|
|
|
<div class="gist-panel-content">
|
|
<!-- Section 1: Config Info -->
|
|
<div class="gist-section">
|
|
<div class="gist-section-header" data-section="config">
|
|
<span class="gist-section-icon">⚙️</span>
|
|
<span>配置信息</span>
|
|
<span class="gist-section-toggle">▼</span>
|
|
</div>
|
|
<div class="gist-section-content" id="gistConfigSection">
|
|
<div class="gist-config-grid">
|
|
<div class="gist-config-item">
|
|
<span class="label">GitHub Token</span>
|
|
<span class="value" id="gistTokenStatus">-</span>
|
|
</div>
|
|
<div class="gist-config-item">
|
|
<span class="label">主 Gist ID</span>
|
|
<span class="value" id="gistId">-</span>
|
|
</div>
|
|
<div class="gist-config-item">
|
|
<span class="label">分片系统</span>
|
|
<span class="value" id="gistShardEnabled">-</span>
|
|
</div>
|
|
<div class="gist-config-item">
|
|
<span class="label">同步密码</span>
|
|
<span class="value" id="gistPasswordStatus">-</span>
|
|
</div>
|
|
<div class="gist-config-item">
|
|
<span class="label">设备 ID</span>
|
|
<span class="value" id="gistDeviceId">-</span>
|
|
</div>
|
|
<div class="gist-config-item">
|
|
<span class="label">最后同步</span>
|
|
<span class="value" id="gistLastSync">-</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 2: Shard Overview -->
|
|
<div class="gist-section">
|
|
<div class="gist-section-header" data-section="shards">
|
|
<span class="gist-section-icon">📦</span>
|
|
<span>分片概览</span>
|
|
<span class="gist-section-toggle">▼</span>
|
|
</div>
|
|
<div class="gist-section-content" id="gistShardSection">
|
|
<div class="gist-shard-stats">
|
|
<div class="gist-stat-card">
|
|
<div class="stat-number" id="shardTotalCount">-</div>
|
|
<div class="stat-label">总分片</div>
|
|
</div>
|
|
<div class="gist-stat-card active">
|
|
<div class="stat-number" id="shardActiveCount">-</div>
|
|
<div class="stat-label">活跃</div>
|
|
</div>
|
|
<div class="gist-stat-card full">
|
|
<div class="stat-number" id="shardFullCount">-</div>
|
|
<div class="stat-label">已满</div>
|
|
</div>
|
|
<div class="gist-stat-card">
|
|
<div class="stat-number" id="shardFileCount">-</div>
|
|
<div class="stat-label">总文件</div>
|
|
</div>
|
|
<div class="gist-stat-card">
|
|
<div class="stat-number" id="shardTotalSize">-</div>
|
|
<div class="stat-label">总大小</div>
|
|
</div>
|
|
</div>
|
|
<div class="gist-shard-list" id="gistShardList">
|
|
<div class="empty-state" style="padding: 20px;">加载分片信息...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 3: Debug Operations -->
|
|
<div class="gist-section">
|
|
<div class="gist-section-header" data-section="operations">
|
|
<span class="gist-section-icon">🛠️</span>
|
|
<span>调试操作</span>
|
|
<span class="gist-section-toggle">▼</span>
|
|
</div>
|
|
<div class="gist-section-content" id="gistOperationsSection">
|
|
<div class="gist-debug-actions compact">
|
|
<!-- Row 1: Connection & Tasks -->
|
|
<div class="debug-action-row">
|
|
<div class="debug-action-group">
|
|
<span class="debug-group-label">连接</span>
|
|
<button class="debug-btn" id="debugTestConnection" title="测试 GitHub API 连接">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
|
|
测试连接
|
|
</button>
|
|
<button class="debug-btn" id="debugListGists" title="列出所有同步 Gist">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
|
|
列出 Gists
|
|
</button>
|
|
</div>
|
|
<div class="debug-action-group">
|
|
<span class="debug-group-label">任务</span>
|
|
<button class="debug-btn" id="debugPreviewTaskMerge" title="预览任务合并结果">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
预览合并
|
|
</button>
|
|
<button class="debug-btn warning" id="debugImportRemoteTasks" title="从远程导入缺失的任务">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
|
导入任务
|
|
</button>
|
|
</div>
|
|
<div class="debug-action-group">
|
|
<span class="debug-group-label">画板</span>
|
|
<button class="debug-btn" id="debugPreviewBoardMerge" title="预览画板合并结果">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
预览合并
|
|
</button>
|
|
<button class="debug-btn" id="debugDownloadBoard" title="下载指定画板内容">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
|
下载画板
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<!-- Row 2: Media & Diagnostics -->
|
|
<div class="debug-action-row">
|
|
<div class="debug-action-group">
|
|
<span class="debug-group-label">媒体</span>
|
|
<button class="debug-btn" id="debugListShardFiles" title="列出分片中的所有文件">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>
|
|
分片列表
|
|
</button>
|
|
<button class="debug-btn" id="debugTestMediaDownload" title="测试下载单个媒体文件">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
|
|
测试下载
|
|
</button>
|
|
</div>
|
|
<div class="debug-action-group">
|
|
<span class="debug-group-label">数据库</span>
|
|
<button class="debug-btn" id="debugCheckSyncLogDb" title="检查同步日志数据库状态">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>
|
|
检查日志库
|
|
</button>
|
|
<button class="debug-btn" id="debugDiagnoseDb" title="诊断所有数据库结构">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
|
|
诊断结构
|
|
</button>
|
|
</div>
|
|
<div class="debug-action-group">
|
|
<span class="debug-group-label">测试</span>
|
|
<button class="debug-btn" id="debugWriteTestLog" title="写入一条测试日志">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
|
|
写入日志
|
|
</button>
|
|
<button class="debug-btn" id="debugPerformanceTest" title="运行性能基准测试">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v4"/><path d="m16.24 7.76-2.12 2.12"/><path d="M21 12h-4"/><path d="m16.24 16.24-2.12-2.12"/><path d="M12 21v-4"/><path d="m7.76 16.24 2.12-2.12"/><path d="M3 12h4"/><path d="m7.76 7.76 2.12 2.12"/></svg>
|
|
性能测试
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p class="debug-hint">调试日志将输出到下方的「同步日志」区域</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 4: Sync Logs -->
|
|
<div class="gist-section gist-section-expanded">
|
|
<div class="gist-section-header" data-section="synclogs">
|
|
<span class="gist-section-icon">📋</span>
|
|
<span>同步日志</span>
|
|
<span class="gist-section-toggle">▼</span>
|
|
</div>
|
|
<div class="gist-section-content" id="gistSyncLogsSection">
|
|
<!-- Log Controls -->
|
|
<div class="sync-log-controls">
|
|
<div class="sync-log-filters">
|
|
<select id="syncLogLevelFilter" class="sync-log-select">
|
|
<option value="">全部级别</option>
|
|
<option value="error">错误</option>
|
|
<option value="warning">警告</option>
|
|
<option value="success">成功</option>
|
|
<option value="info">信息</option>
|
|
<option value="debug">调试</option>
|
|
</select>
|
|
<select id="syncLogCategoryFilter" class="sync-log-select">
|
|
<option value="">全部类型</option>
|
|
<option value="sync">主同步</option>
|
|
<option value="upload">上传</option>
|
|
<option value="download">下载</option>
|
|
<option value="merge">合并</option>
|
|
<option value="conflict">冲突</option>
|
|
<option value="media">媒体</option>
|
|
<option value="shard">分片</option>
|
|
<option value="api">API</option>
|
|
</select>
|
|
<select id="syncLogSessionFilter" class="sync-log-select">
|
|
<option value="">全部会话</option>
|
|
</select>
|
|
<input type="text" id="syncLogSearch" class="sync-log-search" placeholder="搜索日志..." />
|
|
</div>
|
|
<div class="sync-log-actions">
|
|
<button class="debug-btn" id="refreshSyncLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
|
|
刷新
|
|
</button>
|
|
<button class="debug-btn" id="toggleAutoRefresh" title="自动刷新日志 (3秒间隔)">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
|
|
<span id="autoRefreshLabel">自动</span>
|
|
</button>
|
|
<button class="debug-btn" id="copySyncLogs" title="复制当前筛选的日志到剪贴板">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
复制
|
|
</button>
|
|
<button class="debug-btn" id="exportSyncLogs" title="导出日志为 JSON">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
|
|
导出
|
|
</button>
|
|
<button class="debug-btn warning" id="clearSyncLogs" title="清空所有日志">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
清空
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Log Stats (clickable to filter) -->
|
|
<div class="sync-log-stats" id="syncLogStats">
|
|
<div class="sync-log-stat clickable" data-filter="" title="显示所有日志">
|
|
<span class="stat-value" id="syncLogTotal">-</span>
|
|
<span class="stat-label">总条数</span>
|
|
</div>
|
|
<div class="sync-log-stat error clickable" data-filter="error" title="点击筛选错误日志">
|
|
<span class="stat-value" id="syncLogErrors">-</span>
|
|
<span class="stat-label">错误</span>
|
|
</div>
|
|
<div class="sync-log-stat warning clickable" data-filter="warning" title="点击筛选警告日志">
|
|
<span class="stat-value" id="syncLogWarnings">-</span>
|
|
<span class="stat-label">警告</span>
|
|
</div>
|
|
<div class="sync-log-stat success clickable" data-filter="success" title="点击筛选成功日志">
|
|
<span class="stat-value" id="syncLogSuccesses">-</span>
|
|
<span class="stat-label">成功</span>
|
|
</div>
|
|
<div class="sync-log-stat">
|
|
<span class="stat-value" id="syncLogSessions">-</span>
|
|
<span class="stat-label">会话数</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Log List -->
|
|
<div class="sync-log-list" id="syncLogList">
|
|
<div class="empty-state" style="padding: 40px;">点击刷新加载同步日志</div>
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
<div class="sync-log-pagination" id="syncLogPagination">
|
|
<button class="debug-btn-small" id="syncLogPrevPage" disabled>上一页</button>
|
|
<span id="syncLogPageInfo">-</span>
|
|
<button class="debug-btn-small" id="syncLogNextPage" disabled>下一页</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 5: Data Diagnostics -->
|
|
<div class="gist-section">
|
|
<div class="gist-section-header" data-section="diagnostics">
|
|
<span class="gist-section-icon">🔍</span>
|
|
<span>数据诊断</span>
|
|
<span class="gist-section-toggle">▼</span>
|
|
</div>
|
|
<div class="gist-section-content" id="gistDiagnosticsSection">
|
|
<!-- Sub-tabs for diagnostics with refresh button -->
|
|
<div class="gist-subtabs" style="display: flex; align-items: center; gap: 12px;">
|
|
<div style="display: flex; gap: 4px;">
|
|
<button class="gist-subtab active" data-subtab="tasks">任务对比</button>
|
|
<button class="gist-subtab" data-subtab="boards">画板对比</button>
|
|
<button class="gist-subtab" data-subtab="media">素材对比</button>
|
|
<button class="gist-subtab" data-subtab="files">远程文件</button>
|
|
</div>
|
|
<button class="debug-btn-small" id="refreshLocalDiagnostics" title="刷新本地数据">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:12px;height:12px;"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
|
|
刷新本地
|
|
</button>
|
|
<button class="debug-btn-small" id="loadRemoteDiagnostics" title="从 GitHub Gist 加载远程数据进行对比" style="background: var(--primary-color); color: white; border-color: var(--primary-color);">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:12px;height:12px;"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
|
加载远程数据
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Tasks Comparison -->
|
|
<div class="gist-subtab-content active" id="tasksSubtab">
|
|
<div class="gist-comparison-summary" id="taskComparisonSummary">
|
|
<div class="comparison-stat">
|
|
<span class="label">本地任务</span>
|
|
<span class="value" id="localTaskCount">-</span>
|
|
</div>
|
|
<div class="comparison-stat">
|
|
<span class="label">远程任务</span>
|
|
<span class="value" id="remoteTaskCount">-</span>
|
|
</div>
|
|
<div class="comparison-stat local-only">
|
|
<span class="label">仅本地</span>
|
|
<span class="value" id="localOnlyTaskCount">-</span>
|
|
</div>
|
|
<div class="comparison-stat remote-only">
|
|
<span class="label">仅远程</span>
|
|
<span class="value" id="remoteOnlyTaskCount">-</span>
|
|
</div>
|
|
<div class="comparison-stat synced">
|
|
<span class="label">已同步</span>
|
|
<span class="value" id="syncedTaskCount">-</span>
|
|
</div>
|
|
</div>
|
|
<div class="gist-comparison-table" id="taskComparisonTable">
|
|
<div class="empty-state" style="padding: 20px;">点击刷新加载任务对比数据</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Boards Comparison -->
|
|
<div class="gist-subtab-content" id="boardsSubtab">
|
|
<div class="gist-comparison-summary" id="boardComparisonSummary">
|
|
<div class="comparison-stat">
|
|
<span class="label">本地画板</span>
|
|
<span class="value" id="localBoardCount">-</span>
|
|
</div>
|
|
<div class="comparison-stat">
|
|
<span class="label">远程画板</span>
|
|
<span class="value" id="remoteBoardCount">-</span>
|
|
</div>
|
|
<div class="comparison-stat local-only">
|
|
<span class="label">仅本地</span>
|
|
<span class="value" id="localOnlyBoardCount">-</span>
|
|
</div>
|
|
<div class="comparison-stat remote-only">
|
|
<span class="label">仅远程</span>
|
|
<span class="value" id="remoteOnlyBoardCount">-</span>
|
|
</div>
|
|
</div>
|
|
<div class="gist-comparison-table" id="boardComparisonTable">
|
|
<div class="empty-state" style="padding: 20px;">点击刷新加载画板对比数据</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Media Comparison -->
|
|
<div class="gist-subtab-content" id="mediaSubtab">
|
|
<div class="gist-comparison-summary" id="mediaComparisonSummary">
|
|
<div class="comparison-stat">
|
|
<span class="label">本地缓存</span>
|
|
<span class="value" id="localMediaCount">-</span>
|
|
</div>
|
|
<div class="comparison-stat">
|
|
<span class="label">远程索引</span>
|
|
<span class="value" id="remoteMediaCount">-</span>
|
|
</div>
|
|
<div class="comparison-stat local-only">
|
|
<span class="label">仅本地</span>
|
|
<span class="value" id="localOnlyMediaCount">-</span>
|
|
</div>
|
|
<div class="comparison-stat remote-only">
|
|
<span class="label">仅远程</span>
|
|
<span class="value" id="remoteOnlyMediaCount">-</span>
|
|
</div>
|
|
</div>
|
|
<div class="gist-comparison-table" id="mediaComparisonTable">
|
|
<div class="empty-state" style="padding: 20px;">点击刷新加载素材对比数据</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Remote Files Browser -->
|
|
<div class="gist-subtab-content" id="filesSubtab">
|
|
<div class="gist-files-container">
|
|
<div class="gist-file-list-panel">
|
|
<div class="panel-header">文件列表</div>
|
|
<div id="gistFileList" class="gist-file-list">
|
|
<div class="empty-state" style="padding: 20px;">点击刷新加载文件列表</div>
|
|
</div>
|
|
</div>
|
|
<div class="gist-file-preview-panel">
|
|
<div class="panel-header-multi">
|
|
<div class="panel-title">内容预览</div>
|
|
<div id="previewFileName" class="preview-filename"></div>
|
|
</div>
|
|
<div id="gistFileContent" class="gist-file-content">
|
|
<div class="empty-state" style="padding: 20px;">选择文件查看内容</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Crash Logs Tab -->
|
|
<div class="tab-content" id="crashTab">
|
|
<div class="logs-toolbar">
|
|
<select id="filterCrashType">
|
|
<option value="">全部类型</option>
|
|
<option value="startup">启动快照</option>
|
|
<option value="periodic">定期快照</option>
|
|
<option value="error">错误</option>
|
|
<option value="beforeunload">页面关闭</option>
|
|
<option value="freeze">卡死</option>
|
|
<option value="whitescreen">白屏</option>
|
|
<option value="longtask">长任务</option>
|
|
</select>
|
|
<button id="refreshCrashLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
|
|
刷新
|
|
</button>
|
|
<button id="copyCrashLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
复制
|
|
</button>
|
|
<button id="clearCrashLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
清空
|
|
</button>
|
|
<button id="exportCrashLogs">
|
|
<svg class="icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
|
|
导出
|
|
</button>
|
|
</div>
|
|
<div class="logs-container" id="crashContainer">
|
|
<div id="crashLogsContainer">
|
|
<div class="empty-state">
|
|
<span class="icon">💥</span>
|
|
<p>暂无内存日志</p>
|
|
<p style="font-size: 12px; opacity: 0.7;">页面启动、内存超限、错误和关闭时的快照会自动记录</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="module" src="./sw-debug/app.js"></script>
|
|
</body>
|
|
</html>
|