diff --git a/web/index.html b/web/index.html index 1cdeb9d..f3cb412 100644 --- a/web/index.html +++ b/web/index.html @@ -275,125 +275,131 @@ gap: 10px; } - /* JSON 树形展示样式 */ + /* JSON 卡片式展示 */ .json-viewer { background: #f8f9fa; border-radius: 8px; - padding: 20px; - font-family: 'Courier New', monospace; - font-size: 14px; - line-height: 1.8; - overflow-x: auto; + padding: 0; max-height: 60vh; + overflow-y: auto; } - .json-line { - display: flex; - align-items: center; - padding: 2px 0; - position: relative; + .json-section { + margin-bottom: 10px; } - .json-line:hover { - background: rgba(102, 126, 234, 0.05); - } - - .json-indent { - display: inline-block; - width: 20px; - flex-shrink: 0; - } - - .json-toggle { - display: inline-block; - width: 20px; - height: 20px; - text-align: center; - cursor: pointer; - user-select: none; - color: #999; - flex-shrink: 0; - font-size: 12px; - line-height: 20px; - } - - .json-toggle:hover { - color: #667eea; - } - - .json-toggle.collapsed::before { - content: '▶'; - } - - .json-toggle.expanded::before { - content: '▼'; - } - - .json-key { - color: #0066cc; + .json-section-title { + background: #667eea; + color: white; + padding: 12px 20px; font-weight: bold; - margin-right: 8px; + font-size: 16px; + border-radius: 8px 8px 0 0; + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; + user-select: none; } - .json-separator { - color: #999; - margin: 0 4px; + .json-section-title:hover { + background: #5568d3; } - .json-string { + .json-section-toggle { + font-size: 12px; + } + + .json-section-body { + background: white; + border-radius: 0 0 8px 8px; + } + + .json-section-body.collapsed { + display: none; + } + + .json-field { + display: flex; + padding: 12px 20px; + border-bottom: 1px solid #eee; + align-items: flex-start; + } + + .json-field:last-child { + border-bottom: none; + } + + .json-field:hover { + background: #f8f9fa; + } + + .json-field-label { + min-width: 200px; + font-weight: bold; + color: #0066cc; + padding-right: 20px; + flex-shrink: 0; + } + + .json-field-value { + flex: 1; + word-break: break-all; + color: #333; + font-family: 'Courier New', monospace; + font-size: 13px; + } + + .json-field-value.string { color: #22863a; } - .json-number { + .json-field-value.number { color: #005cc5; } - .json-boolean { + .json-field-value.boolean { color: #d73a49; } - .json-null { + .json-field-value.null { color: #6f42c1; } - .json-bracket { - color: #666; - font-weight: bold; + .json-field-actions { + margin-left: 10px; + display: flex; + gap: 5px; } .json-copy-btn { - opacity: 0; - margin-left: 10px; - padding: 2px 8px; - font-size: 11px; + padding: 4px 10px; + font-size: 12px; background: #667eea; color: white; border: none; - border-radius: 3px; + border-radius: 4px; cursor: pointer; - transition: opacity 0.2s; - } - - .json-line:hover .json-copy-btn { - opacity: 1; + white-space: nowrap; } .json-copy-btn:hover { background: #5568d3; } - .json-children { - display: block; + .json-raw-btn { + padding: 4px 10px; + font-size: 12px; + background: #6c757d; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + white-space: nowrap; } - .json-children.collapsed { - display: none; - } - - .json-summary { - color: #999; - font-style: italic; - margin-left: 8px; + .json-raw-btn:hover { + background: #5a6268; } /* Toast 通知 */ @@ -613,122 +619,106 @@ document.getElementById(modalId).classList.remove('active'); } - // JSON 树形渲染 - function renderJSONTree(obj, level = 0) { - const lines = []; - const indent = ' '.repeat(level * 2); + // JSON 卡片式渲染 + function renderJSONCard(obj, parentPath = '') { + let html = ''; - if (obj === null) { - return `null`; + if (typeof obj !== 'object' || obj === null) { + return ''; } - if (typeof obj !== 'object') { - if (typeof obj === 'string') { - return `"${escapeHtml(obj)}"`; - } else if (typeof obj === 'number') { - return `${obj}`; - } else if (typeof obj === 'boolean') { - return `${obj}`; + for (const [key, value] of Object.entries(obj)) { + const path = parentPath ? `${parentPath}.${key}` : key; + + if (value !== null && typeof value === 'object') { + // 对象或数组 - 创建折叠区域 + const isArray = Array.isArray(value); + const itemCount = isArray ? value.length : Object.keys(value).length; + const sectionId = 'section-' + Math.random().toString(36).substr(2, 9); + + html += ` +