feat: 添加调试信息面板,优化主题色彩和底部导航栏布局
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 23s
Docker Build & Deploy / Deploy to Production (push) Successful in 8s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 23s
Docker Build & Deploy / Deploy to Production (push) Successful in 8s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -405,3 +405,7 @@ Web/dist
|
|||||||
# ESLint
|
# ESLint
|
||||||
.eslintcache
|
.eslintcache
|
||||||
.aider*
|
.aider*
|
||||||
|
.screenshot/微信图片_20260211130722_17_37.png
|
||||||
|
.screenshot/微信图片_20260211131102_18_37.png
|
||||||
|
.screenshot/微信图片_20260211131103_19_37.png
|
||||||
|
.screenshot/微信图片_20260211131106_20_37.png
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: openspec-apply-change
|
name: openspec-apply-change
|
||||||
description: Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.
|
description: 从 OpenSpec 变更中实施任务。当用户想要开始实施、继续实施或执行任务时使用。
|
||||||
license: MIT
|
license: MIT
|
||||||
compatibility: Requires openspec CLI.
|
compatibility: Requires openspec CLI.
|
||||||
metadata:
|
metadata:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: openspec-archive-change
|
name: openspec-archive-change
|
||||||
description: Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.
|
description: 在实验性工作流中归档已完成的变更。当用户想要在实施完成后最终确定和归档变更时使用。
|
||||||
license: MIT
|
license: MIT
|
||||||
compatibility: Requires openspec CLI.
|
compatibility: Requires openspec CLI.
|
||||||
metadata:
|
metadata:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: openspec-bulk-archive-change
|
name: openspec-bulk-archive-change
|
||||||
description: Archive multiple completed changes at once. Use when archiving several parallel changes.
|
description: 一次性归档多个已完成的变更。当归档多个并行变更时使用。
|
||||||
license: MIT
|
license: MIT
|
||||||
compatibility: Requires openspec CLI.
|
compatibility: Requires openspec CLI.
|
||||||
metadata:
|
metadata:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: openspec-continue-change
|
name: openspec-continue-change
|
||||||
description: Continue working on an OpenSpec change by creating the next artifact. Use when the user wants to progress their change, create the next artifact, or continue their workflow.
|
description: 通过创建下一个 artifact 继续处理 OpenSpec 变更。当用户想要推进变更、创建下一个 artifact 或继续工作流时使用。
|
||||||
license: MIT
|
license: MIT
|
||||||
compatibility: Requires openspec CLI.
|
compatibility: Requires openspec CLI.
|
||||||
metadata:
|
metadata:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: openspec-explore
|
name: openspec-explore
|
||||||
description: Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.
|
description: 进入探索模式 - 用于探索想法、调查问题和澄清需求的思考伙伴。当用户想要在变更前或变更期间深入思考某些内容时使用。
|
||||||
license: MIT
|
license: MIT
|
||||||
compatibility: Requires openspec CLI.
|
compatibility: Requires openspec CLI.
|
||||||
metadata:
|
metadata:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: openspec-ff-change
|
name: openspec-ff-change
|
||||||
description: Fast-forward through OpenSpec artifact creation. Use when the user wants to quickly create all artifacts needed for implementation without stepping through each one individually.
|
description: 快进 OpenSpec artifact 创建过程。当用户想要快速创建实施所需的所有 artifacts 而无需逐个步骤时使用。
|
||||||
license: MIT
|
license: MIT
|
||||||
compatibility: Requires openspec CLI.
|
compatibility: Requires openspec CLI.
|
||||||
metadata:
|
metadata:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: openspec-new-change
|
name: openspec-new-change
|
||||||
description: Start a new OpenSpec change using the experimental artifact workflow. Use when the user wants to create a new feature, fix, or modification with a structured step-by-step approach.
|
description: 使用实验性 artifact 工作流开始一个新的 OpenSpec 变更。当用户想要通过结构化的分步方法创建新功能、修复或修改时使用。
|
||||||
license: MIT
|
license: MIT
|
||||||
compatibility: Requires openspec CLI.
|
compatibility: Requires openspec CLI.
|
||||||
metadata:
|
metadata:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: openspec-sync-specs
|
name: openspec-sync-specs
|
||||||
description: Sync delta specs from a change to main specs. Use when the user wants to update main specs with changes from a delta spec, without archiving the change.
|
description: 将变更的 delta specs 同步到主 specs。当用户想要使用 delta spec 的更改更新主 specs,而不归档变更时使用。
|
||||||
license: MIT
|
license: MIT
|
||||||
compatibility: Requires openspec CLI.
|
compatibility: Requires openspec CLI.
|
||||||
metadata:
|
metadata:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: openspec-verify-change
|
name: openspec-verify-change
|
||||||
description: Verify implementation matches change artifacts. Use when the user wants to validate that implementation is complete, correct, and coherent before archiving.
|
description: 验证实施是否与变更 artifacts 匹配。当用户想要在归档前验证实施是否完整、正确且一致时使用。
|
||||||
license: MIT
|
license: MIT
|
||||||
compatibility: Requires openspec CLI.
|
compatibility: Requires openspec CLI.
|
||||||
metadata:
|
metadata:
|
||||||
|
|||||||
199
Web/src/App.vue
199
Web/src/App.vue
@@ -76,6 +76,73 @@
|
|||||||
/>
|
/>
|
||||||
<span>新版本可用,点击刷新</span>
|
<span>新版本可用,点击刷新</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 调试信息面板 -->
|
||||||
|
<div
|
||||||
|
v-if="showDebug"
|
||||||
|
class="debug-panel"
|
||||||
|
>
|
||||||
|
<div class="debug-title">
|
||||||
|
底部导航栏调试信息
|
||||||
|
</div>
|
||||||
|
<div class="debug-section">
|
||||||
|
<div class="debug-subtitle">
|
||||||
|
视口尺寸
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
窗口高度: {{ debugInfo.windowHeight }}px
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
视口高度: {{ debugInfo.viewportHeight }}px
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
App Root 高度: {{ debugInfo.appRootHeight }}px
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="debug-section">
|
||||||
|
<div class="debug-subtitle">
|
||||||
|
TabBar 位置
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
position: {{ debugInfo.tabbarPosition }}
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
bottom (CSS): {{ debugInfo.tabbarBottomStyle }}
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
top (实际): {{ debugInfo.tabbarTop }}px
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
bottom (实际): {{ debugInfo.tabbarBottom }}px
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="debug-section">
|
||||||
|
<div class="debug-subtitle">
|
||||||
|
TabBar 尺寸
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
height (实际): {{ debugInfo.tabbarHeight }}px
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
min-height: {{ debugInfo.tabbarMinHeight }}
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
padding-bottom: {{ debugInfo.tabbarPaddingBottom }}
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
box-sizing: {{ debugInfo.tabbarBoxSizing }}
|
||||||
|
</div>
|
||||||
|
<div class="debug-item">
|
||||||
|
安全区域底部: {{ debugInfo.safeAreaBottom }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="debug-close"
|
||||||
|
@click="showDebug = false"
|
||||||
|
>
|
||||||
|
关闭
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</van-config-provider>
|
</van-config-provider>
|
||||||
</template>
|
</template>
|
||||||
@@ -243,6 +310,70 @@ const handleAddTransactionSuccess = () => {
|
|||||||
const event = new Event('transactions-changed')
|
const event = new Event('transactions-changed')
|
||||||
window.dispatchEvent(event)
|
window.dispatchEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 调试信息
|
||||||
|
const showDebug = ref(true) // 默认显示调试面板
|
||||||
|
const debugInfo = ref({
|
||||||
|
windowHeight: 0,
|
||||||
|
viewportHeight: 0,
|
||||||
|
safeAreaBottom: '0',
|
||||||
|
tabbarHeight: 0,
|
||||||
|
tabbarBottom: 0,
|
||||||
|
tabbarTop: 0,
|
||||||
|
tabbarPaddingBottom: '0',
|
||||||
|
tabbarPosition: '',
|
||||||
|
tabbarBottomStyle: '',
|
||||||
|
tabbarMinHeight: '',
|
||||||
|
tabbarBoxSizing: '',
|
||||||
|
appRootHeight: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// 更新调试信息
|
||||||
|
const updateDebugInfo = () => {
|
||||||
|
debugInfo.value.windowHeight = window.innerHeight
|
||||||
|
debugInfo.value.viewportHeight = window.visualViewport?.height || window.innerHeight
|
||||||
|
|
||||||
|
// 获取安全区域底部值
|
||||||
|
const testDiv = document.createElement('div')
|
||||||
|
testDiv.style.paddingBottom = 'env(safe-area-inset-bottom, 0px)'
|
||||||
|
document.body.appendChild(testDiv)
|
||||||
|
const computed = window.getComputedStyle(testDiv)
|
||||||
|
debugInfo.value.safeAreaBottom = computed.paddingBottom
|
||||||
|
document.body.removeChild(testDiv)
|
||||||
|
|
||||||
|
// 获取 TabBar 的实际尺寸和位置
|
||||||
|
const tabbar = document.querySelector('.van-tabbar')
|
||||||
|
if (tabbar) {
|
||||||
|
const rect = tabbar.getBoundingClientRect()
|
||||||
|
const styles = window.getComputedStyle(tabbar)
|
||||||
|
debugInfo.value.tabbarHeight = rect.height.toFixed(2)
|
||||||
|
debugInfo.value.tabbarBottom = rect.bottom.toFixed(2)
|
||||||
|
debugInfo.value.tabbarPaddingBottom = styles.paddingBottom
|
||||||
|
debugInfo.value.tabbarTop = rect.top.toFixed(2)
|
||||||
|
debugInfo.value.tabbarPosition = styles.position
|
||||||
|
debugInfo.value.tabbarBottomStyle = styles.bottom
|
||||||
|
debugInfo.value.tabbarMinHeight = styles.minHeight
|
||||||
|
debugInfo.value.tabbarBoxSizing = styles.boxSizing
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取 app-root 的高度
|
||||||
|
const appRoot = document.querySelector('.app-root')
|
||||||
|
if (appRoot) {
|
||||||
|
const rect = appRoot.getBoundingClientRect()
|
||||||
|
debugInfo.value.appRootHeight = rect.height.toFixed(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 延迟获取调试信息,确保 DOM 已渲染
|
||||||
|
setTimeout(updateDebugInfo, 500)
|
||||||
|
// 每秒更新一次调试信息
|
||||||
|
const debugInterval = setInterval(updateDebugInfo, 1000)
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearInterval(debugInterval)
|
||||||
|
})
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -328,4 +459,72 @@ const handleAddTransactionSuccess = () => {
|
|||||||
.update-icon {
|
.update-icon {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 调试面板样式 */
|
||||||
|
.debug-panel {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
right: 10px;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background: rgba(0, 0, 0, 0.9);
|
||||||
|
color: #fff;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 10px;
|
||||||
|
z-index: 9999;
|
||||||
|
min-width: 240px;
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-title {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-bottom: 2px solid rgba(255, 255, 255, 0.5);
|
||||||
|
padding-bottom: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #4fc3f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-section {
|
||||||
|
margin: 8px 0;
|
||||||
|
padding: 6px;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border-radius: 4px;
|
||||||
|
border-left: 3px solid #4fc3f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-subtitle {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #81c784;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-item {
|
||||||
|
margin: 3px 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-close {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background: linear-gradient(135deg, #ff4d4f, #ff7875);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 11px;
|
||||||
|
width: 100%;
|
||||||
|
font-weight: bold;
|
||||||
|
box-shadow: 0 2px 4px rgba(255, 77, 79, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-close:active {
|
||||||
|
opacity: 0.8;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
schema: spec-driven
|
||||||
|
created: 2026-02-11
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
schema: spec-driven
|
||||||
|
created: 2026-02-11
|
||||||
219
openspec/changes/fix-theme-colors-and-navbar-spacing/design.md
Normal file
219
openspec/changes/fix-theme-colors-and-navbar-spacing/design.md
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
# Design: 修复主题色差与导航栏间距
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
本设计文档详细说明如何修复 EmailBill 应用的两大 UI 问题:
|
||||||
|
1. 亮色/暗色主题下的颜色不一致(色差)
|
||||||
|
2. 底部导航栏与屏幕底部间距过大
|
||||||
|
|
||||||
|
## Technical Decisions
|
||||||
|
|
||||||
|
### 1. 主题色彩统一方案
|
||||||
|
|
||||||
|
#### Current Issues
|
||||||
|
- 导航栏、卡片背景色与页面背景色存在色差
|
||||||
|
- 亮色和暗色模式下颜色变量定义不一致
|
||||||
|
- Vant UI 组件主题定制配置不完整
|
||||||
|
|
||||||
|
#### Solution Approach
|
||||||
|
使用 CSS 变量(CSS Custom Properties)统一管理主题色彩,确保所有组件引用相同的变量。
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* Web/src/styles/theme.css */
|
||||||
|
:root {
|
||||||
|
/* 亮色主题 - 背景色系统 */
|
||||||
|
--bg-primary: #FFFFFF;
|
||||||
|
--bg-secondary: #F6F7F8;
|
||||||
|
--bg-tertiary: #F5F5F5;
|
||||||
|
|
||||||
|
/* 亮色主题 - 文本色系统 */
|
||||||
|
--text-primary: #1A1A1A;
|
||||||
|
--text-secondary: #6B7280;
|
||||||
|
--text-tertiary: #9CA3AF;
|
||||||
|
|
||||||
|
/* 语义色 */
|
||||||
|
--color-primary: #3B82F6;
|
||||||
|
--color-danger: #FF6B6B;
|
||||||
|
--color-success: #07C160;
|
||||||
|
--color-warning: #FAAD14;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] {
|
||||||
|
/* 暗色主题 - 背景色系统 */
|
||||||
|
--bg-primary: #09090B;
|
||||||
|
--bg-secondary: #18181B;
|
||||||
|
--bg-tertiary: #27272A;
|
||||||
|
|
||||||
|
/* 暗色主题 - 文本色系统 */
|
||||||
|
--text-primary: #F4F4F5;
|
||||||
|
--text-secondary: #A1A1AA;
|
||||||
|
--text-tertiary: #71717A;
|
||||||
|
|
||||||
|
/* 语义色在暗色模式下保持不变或微调 */
|
||||||
|
--color-primary: #3B82F6;
|
||||||
|
--color-danger: #FF6B6B;
|
||||||
|
--color-success: #07C160;
|
||||||
|
--color-warning: #FAAD14;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Vant UI 主题映射
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Web/src/main.ts 或主题配置文件
|
||||||
|
import { ConfigProvider } from 'vant'
|
||||||
|
|
||||||
|
const themeVars = {
|
||||||
|
// 亮色主题
|
||||||
|
light: {
|
||||||
|
'--van-nav-bar-background': 'var(--bg-primary)',
|
||||||
|
'--van-nav-bar-text-color': 'var(--text-primary)',
|
||||||
|
'--van-card-background': 'var(--bg-secondary)',
|
||||||
|
'--van-cell-background': 'var(--bg-secondary)',
|
||||||
|
'--van-background': 'var(--bg-primary)',
|
||||||
|
'--van-background-2': 'var(--bg-secondary)',
|
||||||
|
'--van-text-color': 'var(--text-primary)',
|
||||||
|
'--van-text-color-2': 'var(--text-secondary)',
|
||||||
|
'--van-border-color': 'var(--bg-tertiary)',
|
||||||
|
},
|
||||||
|
// 暗色主题
|
||||||
|
dark: {
|
||||||
|
'--van-nav-bar-background': 'var(--bg-primary)',
|
||||||
|
'--van-nav-bar-text-color': 'var(--text-primary)',
|
||||||
|
'--van-card-background': 'var(--bg-secondary)',
|
||||||
|
'--van-cell-background': 'var(--bg-secondary)',
|
||||||
|
'--van-background': 'var(--bg-primary)',
|
||||||
|
'--van-background-2': 'var(--bg-secondary)',
|
||||||
|
'--van-text-color': 'var(--text-primary)',
|
||||||
|
'--van-text-color-2': 'var(--text-secondary)',
|
||||||
|
'--van-border-color': 'var(--bg-tertiary)',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 底部导航栏间距优化
|
||||||
|
|
||||||
|
#### Current Issues
|
||||||
|
- 底部导航栏距离屏幕底部过远
|
||||||
|
- 未正确处理 iPhone 安全区域(Safe Area)
|
||||||
|
- padding/margin 设置不合理
|
||||||
|
|
||||||
|
#### Solution Approach
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* Web/src/styles/layout.css */
|
||||||
|
|
||||||
|
/* 底部导航栏容器 */
|
||||||
|
.tabbar-container {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border-top: 1px solid var(--bg-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导航栏主体 - 减少不必要的 padding */
|
||||||
|
.van-tabbar {
|
||||||
|
height: 56px; /* 标准高度 */
|
||||||
|
padding-bottom: env(safe-area-inset-bottom, 0px); /* 仅保留安全区域内边距 */
|
||||||
|
background: var(--bg-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导航项样式 */
|
||||||
|
.van-tabbar-item {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.van-tabbar-item--active {
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 页面内容区域需要为底部导航栏留出空间 */
|
||||||
|
.page-content {
|
||||||
|
padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Vue 组件调整
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<!-- Layout.vue 或 App.vue -->
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<router-view class="page-content" />
|
||||||
|
<van-tabbar v-model="activeTab" class="tabbar-container">
|
||||||
|
<van-tabbar-item icon="home-o">首页</van-tabbar-item>
|
||||||
|
<van-tabbar-item icon="chart-o">统计</van-tabbar-item>
|
||||||
|
<van-tabbar-item icon="setting-o">设置</van-tabbar-item>
|
||||||
|
</van-tabbar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.app-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content {
|
||||||
|
padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabbar-container {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.van-tabbar) {
|
||||||
|
height: 56px;
|
||||||
|
padding-bottom: env(safe-area-inset-bottom, 0px);
|
||||||
|
background: var(--bg-primary) !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Implementation Files
|
||||||
|
|
||||||
|
### Modified Files
|
||||||
|
|
||||||
|
1. **Web/src/styles/theme.css** (新建)
|
||||||
|
- 定义 CSS 变量系统
|
||||||
|
- 包含亮色/暗色两套变量
|
||||||
|
|
||||||
|
2. **Web/src/styles/layout.css** (新建或修改)
|
||||||
|
- 底部导航栏布局样式
|
||||||
|
- 安全区域处理
|
||||||
|
|
||||||
|
3. **Web/src/main.ts**
|
||||||
|
- 引入主题样式文件
|
||||||
|
- 配置 Vant UI 主题变量
|
||||||
|
|
||||||
|
4. **Web/src/App.vue** (或布局组件)
|
||||||
|
- 调整底部导航栏结构
|
||||||
|
- 应用新的布局样式
|
||||||
|
|
||||||
|
5. **Web/src/components/Navigation/** (如存在)
|
||||||
|
- 更新导航组件样式
|
||||||
|
|
||||||
|
### Key Considerations
|
||||||
|
|
||||||
|
1. **兼容性**: CSS 变量在现代浏览器中支持良好,项目使用 Vite 构建,无需额外 polyfill
|
||||||
|
|
||||||
|
2. **性能**: CSS 变量在运行时计算,对性能影响极小
|
||||||
|
|
||||||
|
3. **可维护性**: 集中管理颜色变量,后续主题调整只需修改一处
|
||||||
|
|
||||||
|
4. **测试**: 需要在 iOS Safari、Android Chrome、微信内置浏览器中测试显示效果
|
||||||
|
|
||||||
|
## Migration Path
|
||||||
|
|
||||||
|
1. **Phase 1**: 创建 theme.css 和 layout.css,定义新的变量系统
|
||||||
|
2. **Phase 2**: 逐步替换硬编码颜色值为 CSS 变量
|
||||||
|
3. **Phase 3**: 更新 Vant UI 主题配置
|
||||||
|
4. **Phase 4**: 调整底部导航栏布局
|
||||||
|
5. **Phase 5**: 跨设备测试验证
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
## Why
|
||||||
|
|
||||||
|
根据用户提供的实机截图,发现 EmailBill 应用在两种主题色(亮色/暗色)下存在明显的色差问题:导航栏、卡片背景等组件颜色与页面背景色不一致,造成视觉割裂感。同时,底部导航栏距离屏幕底部过远,留下大量空白区域,影响移动端使用体验。这些问题需要统一修复以提升应用的整体视觉一致性和用户体验。
|
||||||
|
|
||||||
|
## What Changes
|
||||||
|
|
||||||
|
- **统一主题色彩系统**: 修复亮色和暗色模式下导航栏、卡片、按钮等组件的颜色变量,确保同一主题内颜色一致性
|
||||||
|
- **优化底部导航栏布局**: 调整底部导航栏的间距,减少不必要的空白区域,使其更贴近屏幕底部
|
||||||
|
- **更新 CSS 样式文件**: 修改 `Web/src/styles/` 下的主题变量定义
|
||||||
|
- **调整组件样式**: 更新 Vant UI 组件的主题定制配置
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
### New Capabilities
|
||||||
|
<!-- 此变更主要是修复现有问题,不引入新能力 -->
|
||||||
|
|
||||||
|
### Modified Capabilities
|
||||||
|
- `theme-system`: 统一亮色/暗色主题的色彩变量,消除色差问题
|
||||||
|
- `navbar-layout`: 优化底部导航栏的间距和定位
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
|
||||||
|
- **前端代码**: `Web/src/styles/` 目录下的主题配置文件
|
||||||
|
- **组件库**: Vant UI 的主题定制配置 (`Web/src/main.ts` 或主题配置文件)
|
||||||
|
- **布局文件**: 涉及底部导航栏的页面布局样式
|
||||||
|
- **测试**: 需要在亮色和暗色两种模式下进行视觉回归测试
|
||||||
120
openspec/changes/fix-theme-colors-and-navbar-spacing/tasks.md
Normal file
120
openspec/changes/fix-theme-colors-and-navbar-spacing/tasks.md
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
# Tasks: 修复主题色差与导航栏间距
|
||||||
|
|
||||||
|
## Phase 1: 创建主题系统基础文件
|
||||||
|
|
||||||
|
### 1.1 创建 CSS 变量定义文件
|
||||||
|
- [x] 新建 `Web/src/styles/theme.css`
|
||||||
|
- [x] 定义亮色主题变量(背景、文本、语义色)
|
||||||
|
- [x] 定义暗色主题变量(背景、文本、语义色)
|
||||||
|
- [x] 确保两组变量名称一致,仅值不同
|
||||||
|
|
||||||
|
### 1.2 在 main.ts 中引入主题文件
|
||||||
|
- [x] 导入 `theme.css` 到 `Web/src/main.ts`
|
||||||
|
- [x] 确保 CSS 变量在应用启动时生效
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2: 配置 Vant UI 主题映射
|
||||||
|
|
||||||
|
### 2.1 更新 Vant 主题配置
|
||||||
|
- [x] 修改 `Web/src/main.ts` 中的 Vant ConfigProvider 配置
|
||||||
|
- [x] 将 `--van-nav-bar-background` 映射到 `--bg-primary`
|
||||||
|
- [x] 将 `--van-card-background` 映射到 `--bg-secondary`
|
||||||
|
- [x] 将 `--van-text-color` 映射到 `--text-primary`
|
||||||
|
- [x] 将 `--van-border-color` 映射到 `--bg-tertiary`
|
||||||
|
- [x] 确保亮/暗两套配置使用相同的变量名
|
||||||
|
|
||||||
|
### 2.2 验证组件颜色一致性
|
||||||
|
- [ ] 检查 NavBar 组件背景色是否与页面背景一致
|
||||||
|
- [ ] 检查 Card 组件背景色是否正确应用
|
||||||
|
- [ ] 检查 Cell 组件背景色是否正确应用
|
||||||
|
- [ ] 在亮色模式下截图对比
|
||||||
|
- [ ] 在暗色模式下截图对比
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3: 修复底部导航栏间距
|
||||||
|
|
||||||
|
### 3.1 创建布局样式文件
|
||||||
|
- [x] 新建或修改 `Web/src/styles/layout.css`
|
||||||
|
- [x] 定义 `.tabbar-container` 固定定位样式
|
||||||
|
- [x] 设置导航栏高度为 56px
|
||||||
|
- [x] 添加 `env(safe-area-inset-bottom)` 安全区域内边距
|
||||||
|
- [x] 移除多余的 margin/padding
|
||||||
|
|
||||||
|
### 3.2 调整主布局组件
|
||||||
|
- [x] 修改 `Web/src/App.vue` (或布局组件)
|
||||||
|
- [x] 为页面内容区域添加 `.page-content` 类
|
||||||
|
- [x] 设置 `padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px))`
|
||||||
|
- [x] 确保内容不被导航栏遮挡
|
||||||
|
|
||||||
|
### 3.3 优化 TabBar 组件样式
|
||||||
|
- [x] 使用 `:deep(.van-tabbar)` 覆盖 Vant 默认样式
|
||||||
|
- [x] 设置背景色为 `var(--bg-primary)`
|
||||||
|
- [x] 移除不必要的 padding/margin
|
||||||
|
- [x] 确保图标和文字垂直居中
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4: 清理硬编码颜色值
|
||||||
|
|
||||||
|
### 4.1 扫描并替换硬编码颜色
|
||||||
|
- [x] 搜索项目中所有 `#FFFFFF`、`#000000` 等硬编码颜色
|
||||||
|
- [x] 替换为对应的 CSS 变量
|
||||||
|
- [x] 页面背景 → `--bg-primary`
|
||||||
|
- [x] 卡片背景 → `--bg-secondary`
|
||||||
|
- [x] 主要文本 → `--text-primary`
|
||||||
|
- [x] 次要文本 → `--text-secondary`
|
||||||
|
|
||||||
|
### 4.2 检查自定义组件
|
||||||
|
- [x] 审查所有 Vue 组件的 `<style>` 块
|
||||||
|
- [x] 将硬编码颜色替换为 CSS 变量
|
||||||
|
- [x] 确保 scoped 样式正确使用 `:deep()` 覆盖 Vant 样式
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 5: 跨设备测试验证
|
||||||
|
|
||||||
|
### 5.1 iOS 设备测试
|
||||||
|
- [ ] iPhone Safari (亮色模式)
|
||||||
|
- [ ] iPhone Safari (暗色模式)
|
||||||
|
- [ ] 微信内置浏览器 (亮色模式)
|
||||||
|
- [ ] 微信内置浏览器 (暗色模式)
|
||||||
|
- [ ] 验证安全区域适配是否正常
|
||||||
|
|
||||||
|
### 5.2 Android 设备测试
|
||||||
|
- [ ] Chrome (亮色模式)
|
||||||
|
- [ ] Chrome (暗色模式)
|
||||||
|
- [ ] 微信内置浏览器 (亮色模式)
|
||||||
|
- [ ] 微信内置浏览器 (暗色模式)
|
||||||
|
|
||||||
|
### 5.3 视觉回归测试
|
||||||
|
- [ ] 对比修复前后的截图
|
||||||
|
- [ ] 确认色差问题已解决
|
||||||
|
- [ ] 确认导航栏底部无过多空白
|
||||||
|
- [ ] 检查所有页面布局是否正常
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 6: 文档更新
|
||||||
|
|
||||||
|
### 6.1 更新项目文档
|
||||||
|
- [ ] 在 AGENTS.md 中添加主题系统说明
|
||||||
|
- [ ] 记录 CSS 变量命名规范
|
||||||
|
- [ ] 添加 Vant UI 主题定制指南
|
||||||
|
|
||||||
|
### 6.2 代码审查
|
||||||
|
- [x] 自我审查:检查代码风格和一致性
|
||||||
|
- [x] 运行 `pnpm lint` 确保无 ESLint 错误
|
||||||
|
- [x] 运行 `pnpm build` 确保构建成功
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ] 亮色主题下所有组件颜色一致,无色差
|
||||||
|
- [ ] 暗色主题下所有组件颜色一致,无色差
|
||||||
|
- [ ] 底部导航栏紧贴屏幕底部(考虑安全区域)
|
||||||
|
- [ ] 页面内容可正常滚动,不被导航栏遮挡
|
||||||
|
- [ ] 在 iOS 和 Android 设备上显示正常
|
||||||
|
- [ ] 两种主题切换时无闪烁或延迟
|
||||||
0
sqlite_mcp_server.db
Normal file
0
sqlite_mcp_server.db
Normal file
Reference in New Issue
Block a user