From fe95fce777cb03fa35ba2255181250a8f80031f2 Mon Sep 17 00:00:00 2001 From: Lee <1633292@qq.com> Date: Mon, 8 Jun 2026 23:37:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/templates/browse.html | 259 ++++++++++++------- src/main/resources/templates/index.html | 233 ++++++++++------- src/main/resources/templates/login.html | 303 ++++++++++++++--------- 3 files changed, 511 insertions(+), 284 deletions(-) diff --git a/src/main/resources/templates/browse.html b/src/main/resources/templates/browse.html index 1ab1aee..76126bb 100644 --- a/src/main/resources/templates/browse.html +++ b/src/main/resources/templates/browse.html @@ -14,23 +14,27 @@ --safe-bottom: env(safe-area-inset-bottom, 0px); --safe-left: env(safe-area-inset-left, 0px); --safe-right: env(safe-area-inset-right, 0px); - --nav-height: 52px; + --nav-height: 56px; --color-primary: #6366f1; - --color-bg: #f1f5f9; + --color-primary-light: #818cf8; + --color-primary-dark: #4f46e5; + --color-bg: #f8fafc; --color-surface: #ffffff; --color-text: #1e293b; --color-text-secondary: #64748b; --color-text-muted: #94a3b8; --color-border: #e2e8f0; - --radius-lg: 20px; + --radius-xl: 24px; + --radius-lg: 18px; --radius-md: 14px; --radius-sm: 10px; --radius-full: 999px; - --shadow-sm: 0 1px 3px rgba(0,0,0,0.06); + --shadow-sm: 0 1px 3px rgba(0,0,0,0.05), 0 1px 2px rgba(0,0,0,0.03); + --shadow-md: 0 4px 12px rgba(0,0,0,0.06), 0 1px 3px rgba(0,0,0,0.04); --font-xs: 13px; --font-sm: 14px; - --font-base: 17px; - --font-lg: 19px; + --font-base: 16px; + --font-lg: 18px; } * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; } @@ -43,20 +47,30 @@ /* ==================== 导航 ==================== */ .navbar { - background: var(--color-surface); border-bottom: 1px solid var(--color-border); + background: rgba(255,255,255,0.78); + border-bottom: 1px solid rgba(226,232,240,0.6); height: var(--nav-height); padding: 0 var(--safe-left) 0 var(--safe-right); display: flex; justify-content: space-between; align-items: center; position: sticky; top: 0; z-index: 100; - backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); - background: rgba(255,255,255,0.85); + backdrop-filter: blur(24px) saturate(1.4); + -webkit-backdrop-filter: blur(24px) saturate(1.4); } - .navbar .brand { font-size: 17px; font-weight: 700; color: var(--color-text); letter-spacing: -0.3px; padding-left: 20px; } - .navbar .nav-links { padding-right: 16px; display: flex; gap: 6px; } + .navbar .brand { + font-size: 18px; font-weight: 800; color: var(--color-text); + letter-spacing: -0.4px; padding-left: 20px; + display: flex; align-items: center; gap: 6px; + } + .navbar .brand-dot { + width: 8px; height: 8px; border-radius: 50%; + background: linear-gradient(135deg, var(--color-primary), var(--color-primary-light)); + } + .navbar .nav-links { padding-right: 16px; display: flex; gap: 4px; } .navbar .nav-links a { color: var(--color-text-secondary); text-decoration: none; font-size: var(--font-sm); - padding: 8px 14px; border-radius: var(--radius-sm); transition: all 0.2s; font-weight: 500; white-space: nowrap; + padding: 8px 14px; border-radius: var(--radius-sm); transition: all 0.2s; + font-weight: 500; white-space: nowrap; } - .navbar .nav-links a:hover, .navbar .nav-links a:active { background: #f1f5f9; color: var(--color-primary); } + .navbar .nav-links a:hover { background: rgba(99,102,241,0.06); color: var(--color-primary); } /* ==================== 页面容器 ==================== */ .page-container { @@ -64,87 +78,118 @@ padding: 16px 12px calc(24px + var(--safe-bottom)); } - /* ==================== 筛选栏 — 紧凑 ==================== */ + /* ==================== 筛选栏 ==================== */ .filter-bar { - background: var(--color-surface); border-radius: var(--radius-md); - padding: 12px 14px; box-shadow: var(--shadow-sm); margin-bottom: 12px; + background: var(--color-surface); border-radius: var(--radius-xl); + padding: 18px 18px 14px; + box-shadow: var(--shadow-md); + border: 1px solid rgba(226,232,240,0.5); + margin-bottom: 14px; + animation: fadeInUp 0.4s cubic-bezier(0.16, 1, 0.3, 1); } - .filter-section { margin-bottom: 10px; } - .filter-section:last-of-type { margin-bottom: 10px; } + + .filter-section { margin-bottom: 14px; } + .filter-section:last-of-type { margin-bottom: 14px; } .filter-section-title { font-size: 11px; font-weight: 700; color: var(--color-text-muted); - text-transform: uppercase; letter-spacing: 0.6px; margin-bottom: 4px; + text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 8px; + padding-left: 2px; } /* 日期输入 */ .date-row { - display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; margin-bottom: 2px; + display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; } .date-row input[type="date"] { border: 1.5px solid var(--color-border); border-radius: var(--radius-sm); - font-size: var(--font-sm); padding: 0 10px; transition: border-color 0.2s; - background: #f8fafc; width: 100%; min-width: 0; height: 40px; min-height: 40px; - -webkit-appearance: none; line-height: 40px; + font-size: var(--font-sm); padding: 0 12px; + transition: all 0.2s; background: #f8fafc; + width: 100%; min-width: 0; height: 42px; min-height: 42px; + -webkit-appearance: none; line-height: 42px; color: var(--color-text); } .date-row input[type="date"]:focus { border-color: var(--color-primary); outline: none; - box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1); + background: white; + box-shadow: 0 0 0 3px rgba(99,102,241,0.08); } /* Chip 多选标签组 */ .chip-group { - display: flex; flex-wrap: wrap; gap: 5px; - max-height: 88px; overflow-y: auto; -webkit-overflow-scrolling: touch; + display: flex; flex-wrap: wrap; gap: 6px; + max-height: 96px; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 2px 0; } + .chip-group::-webkit-scrollbar { width: 3px; } + .chip-group::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 3px; } + .chip-group .chip { - display: inline-flex; align-items: center; gap: 3px; - padding: 4px 10px; border-radius: var(--radius-full); + display: inline-flex; align-items: center; gap: 4px; + padding: 6px 12px; border-radius: var(--radius-full); border: 1.5px solid var(--color-border); font-size: var(--font-xs); cursor: pointer; user-select: none; -webkit-user-select: none; - transition: all 0.15s; background: #fafbfc; color: var(--color-text-secondary); - white-space: nowrap; min-height: 30px; + transition: all 0.2s ease; background: #fafbfc; + color: var(--color-text-secondary); white-space: nowrap; min-height: 32px; + font-weight: 500; } - .chip-group .chip:active { transform: scale(0.96); } + .chip-group .chip:active { transform: scale(0.95); } .chip-group .chip input[type="checkbox"] { width: 14px; height: 14px; accent-color: var(--color-primary); margin: 0; flex-shrink: 0; } .chip-group .chip.selected { - background: #eef2ff; border-color: var(--color-primary); color: var(--color-primary); font-weight: 600; - } - .chip-group .chip-count { - font-size: 10px; color: var(--color-text-muted); margin-left: auto; + background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%); + border-color: var(--color-primary); color: var(--color-primary); font-weight: 600; + box-shadow: 0 2px 8px rgba(99,102,241,0.1); } /* 按钮行 */ - .btn-group-row { - display: flex; gap: 8px; margin-top: 12px; - } + .btn-group-row { display: flex; gap: 10px; margin-top: 16px; } .btn-reset { background: var(--color-surface); color: var(--color-text-secondary); - border: 1.5px solid var(--color-border); padding: 10px 18px; border-radius: var(--radius-sm); - font-weight: 500; font-size: var(--font-sm); transition: all 0.2s; - display: flex; align-items: center; justify-content: center; gap: 4px; white-space: nowrap; cursor: pointer; + border: 1.5px solid var(--color-border); padding: 11px 20px; border-radius: var(--radius-sm); + font-weight: 600; font-size: var(--font-sm); transition: all 0.2s; + display: flex; align-items: center; justify-content: center; gap: 5px; + white-space: nowrap; cursor: pointer; } - .btn-reset:active { background: #f1f5f9; } + .btn-reset:hover { border-color: var(--color-text-muted); color: var(--color-text); } + .btn-reset:active { background: #f1f5f9; transform: scale(0.98); } + .btn-search { - flex: 1; background: var(--color-primary); color: white; border: none; - padding: 10px 20px; border-radius: var(--radius-sm); font-weight: 600; font-size: var(--font-sm); - transition: background 0.2s, transform 0.1s; cursor: pointer; - display: flex; align-items: center; justify-content: center; gap: 4px; + flex: 1; background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-light) 100%); + color: white; border: none; padding: 11px 20px; border-radius: var(--radius-sm); + font-weight: 700; font-size: var(--font-sm); + transition: all 0.2s; cursor: pointer; + display: flex; align-items: center; justify-content: center; gap: 5px; + box-shadow: 0 4px 14px rgba(99,102,241,0.25); + position: relative; overflow: hidden; } - .btn-search:active { background: #4f46e5; transform: scale(0.98); } + .btn-search::after { + content: ''; position: absolute; inset: 0; + background: linear-gradient(135deg, transparent 0%, rgba(255,255,255,0.12) 100%); + pointer-events: none; + } + .btn-search:hover { box-shadow: 0 6px 20px rgba(99,102,241,0.35); transform: translateY(-1px); } + .btn-search:active { transform: translateY(0) scale(0.98); box-shadow: 0 2px 8px rgba(99,102,241,0.25); } /* ==================== 汇总栏 ==================== */ .summary-bar { - background: var(--color-surface); border-radius: var(--radius-sm); - padding: 10px 16px; margin-bottom: 10px; display: none; + background: var(--color-surface); border-radius: var(--radius-lg); + padding: 14px 18px; margin-bottom: 12px; display: none; align-items: center; justify-content: space-between; - box-shadow: var(--shadow-sm); animation: fadeInUp 0.3s ease; + box-shadow: var(--shadow-sm); + border: 1px solid rgba(226,232,240,0.5); + animation: fadeInUp 0.35s cubic-bezier(0.16, 1, 0.3, 1); } .summary-bar.visible { display: flex; } - .summary-amount { font-size: var(--font-base); font-weight: 700; color: var(--color-primary); } - .summary-count { font-size: var(--font-xs); color: var(--color-text-secondary); font-weight: 500; } + .summary-amount { + font-size: var(--font-lg); font-weight: 800; + background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-light) 100%); + -webkit-background-clip: text; -webkit-text-fill-color: transparent; + background-clip: text; + } + .summary-count { + font-size: var(--font-xs); color: var(--color-text-secondary); font-weight: 500; + background: #f1f5f9; padding: 4px 10px; border-radius: var(--radius-full); + } @keyframes fadeInUp { from { opacity: 0; transform: translateY(8px); } @@ -153,40 +198,79 @@ /* ==================== 表格 ==================== */ .table-card { - background: var(--color-surface); border-radius: var(--radius-md); - overflow: hidden; box-shadow: var(--shadow-sm); + background: var(--color-surface); border-radius: var(--radius-xl); + overflow: hidden; box-shadow: var(--shadow-md); + border: 1px solid rgba(226,232,240,0.5); + animation: fadeInUp 0.45s cubic-bezier(0.16, 1, 0.3, 1) 0.1s both; } .table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; } - .table-card table { width: 100%; min-width: 500px; margin: 0; border-collapse: collapse; } + .table-card table { width: 100%; min-width: 520px; margin: 0; border-collapse: collapse; } .table-card table thead th { - background: #f8fafc; font-size: 11px; font-weight: 700; color: var(--color-text-secondary); - text-transform: uppercase; letter-spacing: 0.4px; padding: 4px 6px; - border-bottom: 2px solid var(--color-border); white-space: nowrap; position: sticky; top: 0; + background: linear-gradient(180deg, #f8fafc 0%, #f1f5f9 100%); + font-size: 11px; font-weight: 700; color: var(--color-text-secondary); + text-transform: uppercase; letter-spacing: 0.6px; padding: 12px 14px; + border-bottom: 2px solid var(--color-border); white-space: nowrap; + position: sticky; top: 0; } - .table-card table tbody td { - padding: 3px 6px; border-bottom: 1px solid #f1f5f9; - font-size: var(--font-xs); color: var(--color-text); vertical-align: middle; - } - .table-card table tbody tr:last-child td { border-bottom: none; } - .table-card table tbody tr:active { background: #f8fafc; } - .category-badge { - display: inline-block; background: #eef2ff; color: var(--color-primary); - padding: 2px 8px; border-radius: var(--radius-full); font-size: 11px; font-weight: 600; white-space: nowrap; - } - .amount-cell { font-weight: 600; color: #ef4444; text-align: right; font-variant-numeric: tabular-nums; } + .table-card table thead th:first-child { padding-left: 18px; } + .table-card table thead th:last-child { padding-right: 18px; text-align: right; } - .empty-msg { text-align: center; padding: 40px 20px; color: var(--color-text-muted); font-size: var(--font-sm); } - .loading-bar { text-align: center; padding: 36px 20px; display: none; } + .table-card table tbody td { + padding: 12px 14px; border-bottom: 1px solid #f1f5f9; + font-size: var(--font-sm); color: var(--color-text); vertical-align: middle; + transition: background 0.15s; + } + .table-card table tbody td:first-child { padding-left: 18px; font-weight: 500; } + .table-card table tbody td:last-child { padding-right: 18px; } + .table-card table tbody tr:last-child td { border-bottom: none; } + .table-card table tbody tr:hover { background: #f8fafc; } + .table-card table tbody tr:active { background: #f1f5f9; } + + .category-badge { + display: inline-block; + background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 100%); + color: var(--color-primary); + padding: 3px 10px; border-radius: var(--radius-full); + font-size: 11px; font-weight: 600; white-space: nowrap; + } + .amount-cell { + font-weight: 700; color: #ef4444; text-align: right; + font-variant-numeric: tabular-nums; font-size: var(--font-sm); + } + + .empty-msg { + text-align: center; padding: 48px 20px; color: var(--color-text-muted); + font-size: var(--font-sm); display: flex; flex-direction: column; + align-items: center; gap: 8px; + } + .empty-msg i { font-size: 32px; opacity: 0.4; } + + .loading-bar { + text-align: center; padding: 40px 20px; display: none; + } .loading-bar.show { display: block; } - .loading-bar .spinner-border { width: 28px; height: 28px; border-width: 3px; color: var(--color-primary); } + .loading-bar .spinner-border { + width: 28px; height: 28px; border-width: 3px; color: var(--color-primary); + } + .loading-bar p { + margin-top: 12px; color: var(--color-text-muted); font-size: var(--font-sm); + } + + /* ==================== 响应式 ==================== */ + @media (min-width: 768px) { + .page-container { padding: 24px 20px 32px; } + .filter-bar { padding: 20px 22px 16px; } + .table-card table thead th { padding: 14px 16px; } + .table-card table tbody td { padding: 14px 16px; } + } @@ -217,7 +301,7 @@ - +
@@ -261,7 +348,6 @@ // ==================== 初始化 Chip 选择器 ==================== document.addEventListener('DOMContentLoaded', loadFilterOptions); - // 存储每个 filter 组的 chip 容器 ID 映射 const chipMap = { person: 'chipPerson', location: 'chipLocation', @@ -283,7 +369,6 @@ const label = document.createElement('label'); label.className = 'chip'; label.innerHTML = ' ' + escHtml(v); - // 点击 label 切换 selected 样式 label.addEventListener('change', function(e) { if (e.target.checked) { label.classList.add('selected'); @@ -331,8 +416,8 @@ renderResults(data); } catch (err) { console.error('查询失败:', err); - emptyMsg.textContent = '查询失败,请重试'; - emptyMsg.style.display = 'block'; + emptyMsg.innerHTML = '查询失败,请重试'; + emptyMsg.style.display = 'flex'; } finally { loadingBar.classList.remove('show'); } @@ -352,8 +437,8 @@ if (!data.records || data.records.length === 0) { resultTable.style.display = 'none'; - emptyMsg.textContent = '未找到匹配的事项记录'; - emptyMsg.style.display = 'block'; + emptyMsg.innerHTML = '未找到匹配的事项记录'; + emptyMsg.style.display = 'flex'; summaryBar.classList.remove('visible'); return; } @@ -381,7 +466,6 @@ } function resetFilters() { - // 取消所有 chip 勾选 ['chipPerson', 'chipLocation', 'chipCategory'].forEach(id => { const container = document.getElementById(id); if (!container) return; @@ -394,8 +478,9 @@ document.getElementById('filterEndTime').value = ''; document.getElementById('resultTable').style.display = 'none'; - document.getElementById('emptyMsg').textContent = '点击「查询」查看事项数据'; - document.getElementById('emptyMsg').style.display = 'block'; + const emptyMsg = document.getElementById('emptyMsg'); + emptyMsg.innerHTML = '点击「查询」查看事项数据'; + emptyMsg.style.display = 'flex'; document.getElementById('summaryBar').classList.remove('visible'); } diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index ee10711..181def3 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -14,25 +14,28 @@ --safe-bottom: env(safe-area-inset-bottom, 0px); --safe-left: env(safe-area-inset-left, 0px); --safe-right: env(safe-area-inset-right, 0px); - --mic-size: clamp(72px, 20vw, 92px); + --mic-size: clamp(72px, 20vw, 88px); --mic-color: #6366f1; + --mic-color-light: #818cf8; --mic-recording: #ef4444; - --nav-height: 52px; - --color-bg: #f1f5f9; + --nav-height: 56px; + --color-bg: #f8fafc; --color-surface: #ffffff; --color-text: #1e293b; --color-text-secondary: #64748b; --color-text-muted: #94a3b8; --color-border: #e2e8f0; - --radius-lg: 20px; + --radius-xl: 24px; + --radius-lg: 18px; --radius-md: 14px; --radius-sm: 10px; --radius-full: 999px; - --shadow-sm: 0 1px 3px rgba(0,0,0,0.06); - --font-xs: 14px; - --font-sm: 15px; - --font-base: 18px; - --font-lg: 20px; + --shadow-sm: 0 1px 3px rgba(0,0,0,0.05), 0 1px 2px rgba(0,0,0,0.03); + --shadow-md: 0 4px 12px rgba(0,0,0,0.06), 0 1px 3px rgba(0,0,0,0.04); + --font-xs: 13px; + --font-sm: 14px; + --font-base: 16px; + --font-lg: 18px; } * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; } @@ -45,101 +48,143 @@ /* ==================== 顶部导航 ==================== */ .navbar { - background: rgba(255,255,255,0.85); border-bottom: 1px solid var(--color-border); + background: rgba(255,255,255,0.78); + border-bottom: 1px solid rgba(226,232,240,0.6); height: var(--nav-height); padding: 0 var(--safe-left) 0 var(--safe-right); display: flex; justify-content: space-between; align-items: center; position: sticky; top: 0; z-index: 100; - backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); + backdrop-filter: blur(24px) saturate(1.4); + -webkit-backdrop-filter: blur(24px) saturate(1.4); } - .navbar .brand { font-size: 18px; font-weight: 700; color: var(--color-text); letter-spacing: -0.3px; padding-left: 20px; } - .navbar .nav-links { padding-right: 16px; display: flex; gap: 6px; } + .navbar .brand { + font-size: 18px; font-weight: 800; color: var(--color-text); + letter-spacing: -0.4px; padding-left: 20px; + display: flex; align-items: center; gap: 6px; + } + .navbar .brand-dot { + width: 8px; height: 8px; border-radius: 50%; + background: linear-gradient(135deg, var(--mic-color), var(--mic-color-light)); + } + .navbar .nav-links { padding-right: 16px; display: flex; gap: 4px; } .navbar .nav-links a { color: var(--color-text-secondary); text-decoration: none; font-size: var(--font-sm); - padding: 8px 14px; border-radius: var(--radius-sm); transition: all 0.2s; font-weight: 500; white-space: nowrap; + padding: 8px 14px; border-radius: var(--radius-sm); transition: all 0.2s; + font-weight: 500; white-space: nowrap; } - .navbar .nav-links a:hover, .navbar .nav-links a:active { background: #f1f5f9; color: var(--mic-color); } + .navbar .nav-links a:hover { background: rgba(99,102,241,0.06); color: var(--mic-color); } /* ==================== 通知栏 ==================== */ .notification { position: fixed; top: calc(var(--nav-height) + 12px + var(--safe-top)); left: 50%; transform: translateX(-50%) translateY(-8px); z-index: 9999; - background: #10b981; color: white; padding: 10px 20px; border-radius: var(--radius-full); + background: var(--color-surface); color: #059669; + padding: 10px 20px; border-radius: var(--radius-full); font-size: var(--font-sm); font-weight: 600; - box-shadow: 0 4px 16px rgba(16, 185, 129, 0.35); + box-shadow: 0 8px 24px rgba(0,0,0,0.08), 0 2px 8px rgba(0,0,0,0.04); + border: 1px solid rgba(16,185,129,0.2); opacity: 0; pointer-events: none; transition: opacity 0.3s ease, transform 0.3s ease; max-width: calc(100vw - 40px); text-align: center; + display: flex; align-items: center; gap: 8px; } .notification.show { opacity: 1; transform: translateX(-50%) translateY(0); } - .notification.error { background: #ef4444; box-shadow: 0 4px 16px rgba(239, 68, 68, 0.35); } + .notification.error { + color: #dc2626; border-color: rgba(239,68,68,0.2); + } /* ==================== 内容区 ==================== */ .content-area { max-width: 640px; margin: 0 auto; - padding: 10px 8px calc(var(--mic-size) + 20px + var(--safe-bottom) + 40px); + padding: 16px 12px calc(var(--mic-size) + 24px + var(--safe-bottom) + 48px); } /* ==================== 空状态 ==================== */ - .empty-state { text-align: center; padding: 40px 16px 24px; color: var(--color-text-muted); } - .empty-state .empty-icon { font-size: 52px; margin-bottom: 14px; display: block; opacity: 0.6; } - .empty-state .empty-title { font-size: var(--font-lg); font-weight: 600; color: var(--color-text); margin-bottom: 6px; } - .empty-state .empty-desc { font-size: var(--font-sm); color: var(--color-text-muted); line-height: 1.4; } + .empty-state { + text-align: center; padding: 48px 20px 32px; + animation: fadeInUp 0.5s cubic-bezier(0.16, 1, 0.3, 1); + } + .empty-icon-wrap { + display: inline-flex; align-items: center; justify-content: center; + width: 80px; height: 80px; border-radius: 24px; + background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 50%, #ede9fe 100%); + box-shadow: 0 4px 16px rgba(99,102,241,0.12); + margin-bottom: 20px; font-size: 36px; + } + .empty-state .empty-title { + font-size: var(--font-lg); font-weight: 700; color: var(--color-text); + margin-bottom: 8px; letter-spacing: -0.3px; + } + .empty-state .empty-desc { + font-size: var(--font-sm); color: var(--color-text-muted); line-height: 1.6; + } /* ==================== 查询结果 ==================== */ .result-card { background: transparent; border-radius: 0; padding: 0; box-shadow: none; - display: none; animation: fadeInUp 0.35s ease; + display: none; animation: fadeInUp 0.4s cubic-bezier(0.16, 1, 0.3, 1); } .result-card.visible { display: block; } /* 卡片列表 */ - .records-list { - display: -webkit-flex; display: flex; - -webkit-flex-direction: column; flex-direction: column; - gap: 5px; - } + .records-list { display: flex; flex-direction: column; gap: 8px; } .record-card { - border-radius: 12px; padding: 10px 14px; - display: -webkit-flex; display: flex; - -webkit-flex-direction: column; flex-direction: column; - gap: 2px; + background: var(--color-surface); border-radius: var(--radius-lg); + padding: 14px 16px; display: flex; flex-direction: column; gap: 6px; border-left: 4px solid #e2e8f0; - box-shadow: 0 1px 2px rgba(0,0,0,0.03); - -webkit-tap-highlight-color: rgba(0,0,0,0.05); + box-shadow: var(--shadow-sm); + transition: all 0.2s ease; + animation: cardSlideIn 0.35s cubic-bezier(0.16, 1, 0.3, 1) both; } - .record-card:active { opacity: 0.85; } + .record-card:nth-child(1) { animation-delay: 0s; } + .record-card:nth-child(2) { animation-delay: 0.05s; } + .record-card:nth-child(3) { animation-delay: 0.1s; } + .record-card:nth-child(4) { animation-delay: 0.15s; } + .record-card:nth-child(5) { animation-delay: 0.2s; } + @keyframes cardSlideIn { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } + } + .record-card:active { transform: scale(0.99); opacity: 0.9; } + .card-top { - display: -webkit-flex; display: flex; - -webkit-justify-content: space-between; justify-content: space-between; - -webkit-align-items: baseline; align-items: baseline; + display: flex; justify-content: space-between; align-items: baseline; + } + .card-time { + font-size: 14px; color: var(--color-text-secondary); font-weight: 500; + display: flex; align-items: center; gap: 6px; + } + .card-time .cat-emoji { font-size: 18px; } + .card-amount { + font-size: 20px; font-weight: 800; color: #ef4444; white-space: nowrap; + font-variant-numeric: tabular-nums; letter-spacing: -0.3px; } - .card-time { font-size: 16px; color: #64748b; font-weight: 500; } - .card-time .cat-emoji { margin-right: 4px; font-size: 18px; } - .card-amount { font-size: 20px; font-weight: 700; color: #ef4444; white-space: nowrap; } .card-detail { - font-size: 15px; color: #334155; line-height: 1.5; - display: -webkit-flex; display: flex; - -webkit-flex-wrap: wrap; flex-wrap: wrap; - gap: 4px 8px; + font-size: 14px; color: #334155; line-height: 1.5; + display: flex; flex-wrap: wrap; gap: 4px 10px; } .card-detail .meta-tag { - font-size: 13px; color: #94a3b8; white-space: nowrap; + font-size: 12px; color: var(--color-text-muted); + background: #f1f5f9; padding: 2px 8px; border-radius: var(--radius-full); } /* 底部总结 */ .summary-footer { - margin-top: 10px; padding: 14px 16px; - background: #eef2ff; border-radius: 12px; - text-align: center; font-size: 16px; font-weight: 600; - color: #4f46e5; line-height: 1.5; + margin-top: 14px; padding: 16px 20px; + background: linear-gradient(135deg, #eef2ff 0%, #ede9fe 100%); + border: 1px solid rgba(99,102,241,0.1); + border-radius: var(--radius-lg); + text-align: center; font-size: 15px; font-weight: 600; + color: #4f46e5; line-height: 1.6; + animation: fadeInUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) 0.2s both; } /* ==================== 聊天回复 ==================== */ .chat-reply { - background: var(--color-surface); border-radius: var(--radius-sm); - padding: 12px 12px; box-shadow: var(--shadow-sm); - font-size: var(--font-sm); line-height: 1.6; color: var(--color-text); - display: none; animation: fadeInUp 0.35s ease; + background: var(--color-surface); border-radius: var(--radius-lg); + padding: 16px 18px; box-shadow: var(--shadow-md); + font-size: var(--font-sm); line-height: 1.7; color: var(--color-text); + display: none; animation: fadeInUp 0.4s cubic-bezier(0.16, 1, 0.3, 1); + border: 1px solid rgba(226,232,240,0.5); } .chat-reply.visible { display: block; } .chat-reply p { margin: 0; } @@ -152,61 +197,80 @@ /* ==================== 麦克风按钮区域 ==================== */ .mic-bottom-bar { position: fixed; bottom: 0; left: 0; right: 0; z-index: 1000; - background: linear-gradient(180deg, transparent 0%, var(--color-bg) 50%, var(--color-bg) 100%); - padding: 16px 0 calc(24px + var(--safe-bottom)); + background: linear-gradient(180deg, transparent 0%, var(--color-bg) 40%, var(--color-bg) 100%); + padding: 20px 0 calc(28px + var(--safe-bottom)); display: flex; flex-direction: column; align-items: center; pointer-events: none; } .mic-container { position: relative; pointer-events: auto; } .mic-btn { width: var(--mic-size); height: var(--mic-size); border-radius: 50%; - background: var(--mic-color); border: none; color: white; - font-size: calc(var(--mic-size) * 0.4); cursor: pointer; - box-shadow: 0 4px 24px rgba(99, 102, 241, 0.4); - transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.2s ease; + background: linear-gradient(135deg, var(--mic-color) 0%, var(--mic-color-light) 100%); + border: none; color: white; + font-size: calc(var(--mic-size) * 0.38); cursor: pointer; + box-shadow: + 0 6px 24px rgba(99,102,241,0.35), + 0 2px 8px rgba(99,102,241,0.2), + inset 0 1px 0 rgba(255,255,255,0.2); + transition: transform 0.15s ease, box-shadow 0.15s ease; display: flex; align-items: center; justify-content: center; - user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; position: relative; + user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; + position: relative; + } + .mic-btn::before { + content: ''; position: absolute; inset: -6px; border-radius: 50%; + background: rgba(99,102,241,0.08); z-index: -1; + transition: all 0.3s ease; + } + .mic-btn:active { + transform: scale(0.92); + box-shadow: 0 3px 12px rgba(99,102,241,0.3), inset 0 1px 0 rgba(255,255,255,0.2); } - .mic-btn:active { transform: scale(0.94); box-shadow: 0 2px 12px rgba(99, 102, 241, 0.3); transition: transform 0.08s ease; } .mic-btn.recording { - background: var(--mic-recording); box-shadow: 0 4px 28px rgba(239, 68, 68, 0.5); + background: linear-gradient(135deg, var(--mic-recording) 0%, #f87171 100%); + box-shadow: + 0 6px 28px rgba(239,68,68,0.45), + 0 2px 8px rgba(239,68,68,0.25); animation: micPulse 1.6s ease-in-out infinite; } + .mic-btn.recording::before { background: rgba(239,68,68,0.1); } @keyframes micPulse { - 0%, 100% { box-shadow: 0 4px 28px rgba(239, 68, 68, 0.5); } - 50% { box-shadow: 0 4px 28px rgba(239, 68, 68, 0.25), 0 0 0 16px rgba(239, 68, 68, 0.08); } + 0%, 100% { box-shadow: 0 6px 28px rgba(239,68,68,0.45), 0 2px 8px rgba(239,68,68,0.25); } + 50% { box-shadow: 0 6px 28px rgba(239,68,68,0.2), 0 0 0 14px rgba(239,68,68,0.06); } } - /* 底部状态行:提示文字 + 处理中指示器 */ + /* 底部状态行 */ .mic-status-row { - display: flex; align-items: center; gap: 10px; margin-top: 10px; + display: flex; align-items: center; gap: 10px; margin-top: 12px; pointer-events: none; user-select: none; -webkit-user-select: none; } .mic-hint { font-size: var(--font-xs); color: var(--color-text-muted); font-weight: 500; } - .mic-hint.recording-hint { color: var(--mic-recording); font-weight: 600; animation: hintBlink 1.2s ease-in-out infinite; } + .mic-hint.recording-hint { + color: var(--mic-recording); font-weight: 600; + animation: hintBlink 1.2s ease-in-out infinite; + } @keyframes hintBlink { - 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } + 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } + /* 处理中指示器 */ - .processing-indicator { - display: none; align-items: center; gap: 4px; - } + .processing-indicator { display: none; align-items: center; gap: 6px; } .processing-indicator.show { display: flex; } .processing-dot { - width: 6px; height: 6px; border-radius: 50%; background: var(--mic-color); + width: 5px; height: 5px; border-radius: 50%; background: var(--mic-color); animation: dotBounce 1.2s ease-in-out infinite; } .processing-dot:nth-child(2) { animation-delay: 0.15s; } .processing-dot:nth-child(3) { animation-delay: 0.3s; } @keyframes dotBounce { - 0%, 80%, 100% { transform: scale(0.6); opacity: 0.4; } + 0%, 80%, 100% { transform: scale(0.5); opacity: 0.3; } 40% { transform: scale(1); opacity: 1; } } - .processing-text { font-size: var(--font-xs); color: var(--mic-color); font-weight: 500; } + .processing-text { font-size: var(--font-xs); color: var(--mic-color); font-weight: 600; } @media (min-width: 768px) { - .content-area { padding: 32px 20px 120px; } + .content-area { padding: 28px 20px 120px; } .navbar .brand { padding-left: 24px; } } @@ -214,9 +278,9 @@ @@ -225,7 +289,7 @@
- 🎤 +
🎤
语音记账助手
按住下方按钮说话
录入事项或查询记录
@@ -252,21 +316,18 @@ // ==================== 麦克风权限预检 ==================== (async function checkMicPermission() { try { - // 先检查当前权限状态 if (navigator.permissions) { const status = await navigator.permissions.query({ name: 'microphone' }); - if (status.state === 'granted') return; // 已有权限 + if (status.state === 'granted') return; if (status.state === 'denied') { showNotification('麦克风权限已被拒绝,请在系统设置中开启', true); return; } } - // 请求权限 const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); stream.getTracks().forEach(t => t.stop()); } catch (err) { console.log('麦克风权限预检:', err.message); - // 不强制弹通知,用户使用时还会再次触发权限请求 } })(); @@ -379,7 +440,6 @@ hapticFeedback('warning'); return; } - // 显示底部处理中指示器(不阻塞操作) processing.classList.add('show'); micHint.style.display = 'none'; await sendAudio(wavBlob); @@ -552,7 +612,8 @@ let notifyTimer = null; function showNotification(message, isError) { if (notifyTimer) clearTimeout(notifyTimer); - notification.textContent = message; + const icon = isError ? '✕' : '✓'; + notification.innerHTML = '' + icon + ' ' + escapeHtml(message); notification.className = 'notification' + (isError ? ' error' : ''); void notification.offsetWidth; notification.classList.add('show'); diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html index 0d545c5..74adc77 100644 --- a/src/main/resources/templates/login.html +++ b/src/main/resources/templates/login.html @@ -7,21 +7,24 @@ 登录 - TraceCD + -
-
📝
-

TraceCD

-

语音智能记账助手

+
+
+
+
-
+