From e92f1bdfaee841e32c2b8bfa2a431945bb6b35e5 Mon Sep 17 00:00:00 2001 From: nepiedg Date: Tue, 31 Mar 2026 21:29:54 +0800 Subject: [PATCH] feat: refresh h5 debug workflow and ui design --- docs/design-system.md | 396 +++++++++ src/api/auth.js | 5 +- src/api/request.js | 1 + src/pages/logs/index.vue | 387 ++++----- src/pages/mode-select/index.vue | 14 + src/pages/onboarding/index.vue | 173 ++-- src/pages/profile/index.vue | 243 ++---- src/pages/stats/index.vue | 1407 +++++++++++-------------------- vite.config.js | 6 +- 9 files changed, 1303 insertions(+), 1329 deletions(-) create mode 100644 docs/design-system.md diff --git a/docs/design-system.md b/docs/design-system.md new file mode 100644 index 0000000..24b1dd3 --- /dev/null +++ b/docs/design-system.md @@ -0,0 +1,396 @@ +# 戒烟助手 - 设计语言文档 + +> 所有页面和组件必须遵循此文档,确保视觉一致性。 + +--- + +## 1. 色彩体系 + +### 品牌色 — 薄荷绿 + +| 用途 | 色值 | 示例场景 | +|------|------|---------| +| 主色 | `#34C8A0` | 按钮、进度条、选中态边框 | +| 主色深 | `#1a8c62` | 选中文字、强调文字 | +| 主色最深 | `#0D3D2E` | 页面标题、数值文字 | +| 辅助文字 | `#52806E` | 副标题 | +| 次要文字 | `#7aA898` | 说明文字、标签、单位 | +| 淡底色 | `#9CC5B5` | placeholder 文字 | + +### 功能色 + +| 用途 | 色值 | 场景 | +|------|------|------| +| 成功/正向 | `#1a8c62` | 下降趋势、达成状态 | +| 警告 | `#B45309` | 上升趋势、需注意 | +| 警告背景 | `rgba(251, 191, 36, 0.14)` | 警告标签底色 | +| 危险 | `#DC2626` | 高数值指标 | +| 信息蓝 | `#2563EB` | 对比数据(实际值) | + +### 背景与表面 + +| 用途 | 色值 | +|------|------| +| 页面背景渐变 | `linear-gradient(180deg, #E6F7F2 0%, #F0FBF7 40%, #FAFFFE 100%)` | +| 卡片底色 | `rgba(255, 255, 255, 0.88)` | +| 卡片边框 | `rgba(52, 200, 160, 0.14)` | +| 卡片阴影 | `0 4rpx 18rpx rgba(52, 200, 160, 0.07)` | +| 浅底色块 | `rgba(52, 200, 160, 0.06)` | +| 选中底色 | `rgba(52, 200, 160, 0.09)` | +| 选中边框 | `rgba(52, 200, 160, 0.45)` | + +--- + +## 2. 字体规范 + +### 字体栈 + +```css +font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; +``` + +### 字号层级 + +| 级别 | 字号 | 字重 | 颜色 | 用途 | +|------|------|------|------|------| +| H1 | 38rpx | 700 | `#0D3D2E` | 页面大标题 | +| H2 | 28rpx | 600 | `#0D3D2E` | 卡片标题 | +| H3 | 26rpx | 600 | `#1a5c45` | 区块标签(section-label) | +| 数值大 | 52rpx | 700 | `#0D3D2E` | 核心指标数字 | +| 数值中 | 38-42rpx | 700 | `#0D3D2E` | 次要指标数字 | +| 正文 | 25rpx | 400 | `#52806E` | 描述文字 | +| 辅助 | 21-22rpx | 400 | `#7aA898` | 标签、单位、说明 | +| 小字 | 20rpx | 500 | `#7aA898` | 注释、补充信息 | + +--- + +## 3. 间距与圆角 + +### 间距 + +| 级别 | 数值 | 用途 | +|------|------|------| +| xs | 6-8rpx | 元素内部微间距 | +| sm | 14-16rpx | 标签之间、紧凑元素间距 | +| md | 20rpx | 卡片之间、区块之间 | +| lg | 28rpx | 页面侧边距 | + +### 圆角 + +| 元素 | 圆角 | +|------|------| +| 卡片 | 24rpx | +| 选项卡片 | 20rpx | +| 标签(pill) | 999rpx | +| 按钮 | 48rpx(大按钮)/ 999rpx(小标签) | +| 输入框/选择器 | 12-14rpx | +| 圆形按钮/圆环 | 50% | +| 数据色块 | 14rpx | + +--- + +## 4. 组件样式规范 + +### 4.1 卡片(Card) + +所有独立内容区域使用卡片包裹。 + +```css +.card { + background: rgba(255, 255, 255, 0.88); + border-radius: 24rpx; + border: 1.5rpx solid rgba(52, 200, 160, 0.14); + box-shadow: 0 4rpx 18rpx rgba(52, 200, 160, 0.07); + padding: 24rpx; + margin-bottom: 20rpx; +} +``` + +**禁止**:使用旧版灰蓝阴影 `rgba(15, 23, 42, 0.06)`,统一使用薄荷绿阴影。 + +### 4.2 选择卡片(Mode Card / Option Card) + +```css +/* 默认态 */ +.option-card { + background: rgba(255, 255, 255, 0.72); + border: 2rpx solid rgba(52, 200, 160, 0.1); + border-radius: 20rpx; + box-shadow: 0 2rpx 10rpx rgba(52, 200, 160, 0.04); +} + +/* 选中态 */ +.option-card-active { + background: rgba(52, 200, 160, 0.09); + border-color: rgba(52, 200, 160, 0.45); + box-shadow: 0 4rpx 16rpx rgba(52, 200, 160, 0.14); +} +``` + +### 4.3 标签选项(Pill Tag) + +```css +/* 默认态 */ +.tag { + padding: 14rpx 26rpx; + border-radius: 999rpx; + background: rgba(255, 255, 255, 0.9); + font-size: 25rpx; + color: #4a7a66; + border: 1.5rpx solid rgba(52, 200, 160, 0.18); +} + +/* 选中态 */ +.tag-active { + background: rgba(52, 200, 160, 0.12); + border-color: rgba(52, 200, 160, 0.45); + color: #1a7f61; + font-weight: 600; +} +``` + +### 4.4 按钮 + +```css +/* 主按钮 */ +.btn-primary { + height: 96rpx; + background: linear-gradient(180deg, #3DD9AE 0%, #34C8A0 100%); + border-radius: 48rpx; + color: #FFFFFF; + font-size: 32rpx; + font-weight: 600; + box-shadow: 0 12rpx 28rpx rgba(52, 200, 160, 0.28); +} + +/* 圆形操作按钮(+/-) */ +.btn-circle { + width: 60rpx; + height: 60rpx; + border-radius: 50%; + background: rgba(52, 200, 160, 0.1); + color: #34C8A0; + font-size: 38rpx; + border: 1.5rpx solid rgba(52, 200, 160, 0.25); +} +``` + +### 4.5 输入框 + +```css +.input { + background: rgba(52, 200, 160, 0.06); + border: 1.5rpx solid rgba(52, 200, 160, 0.2); + border-radius: 12rpx; + color: #0D3D2E; + font-weight: 600; +} + +/* placeholder */ +placeholder-style: "color: #9CC5B5" +``` + +### 4.6 进度条 + +```css +.progress-bar { + height: 10rpx; + background: rgba(52, 200, 160, 0.1); + border-radius: 999rpx; +} + +.progress-fill { + background: linear-gradient(90deg, #34C8A0, #3DD9AE); + border-radius: 999rpx; +} + +/* 未完成态 */ +.progress-fill-pending { + background: rgba(52, 200, 160, 0.3); +} +``` + +### 4.7 圆环指标(Ring) + +```css +.ring { + width: 110rpx; + height: 110rpx; + border-radius: 50%; + /* 使用 conic-gradient 动态渲染 */ + /* 主色: #34C8A0, 底色: #E8F8F3 */ +} + +.ring-inner { + width: 82rpx; + height: 82rpx; + border-radius: 50%; + background: #FFFFFF; + box-shadow: 0 4rpx 12rpx rgba(52, 200, 160, 0.1); +} +``` + +### 4.8 状态标签(Chip) + +```css +/* 正向 */ +.chip-good { + background: rgba(52, 200, 160, 0.12); + color: #1a8c62; +} + +/* 警告 */ +.chip-warn { + background: rgba(251, 191, 36, 0.14); + color: #B45309; +} + +/* 中性 */ +.chip-neutral { + background: rgba(52, 200, 160, 0.06); + color: #7aA898; +} +``` + +### 4.9 Segment(Tab 切换) + +```css +.segment { + background: rgba(255, 255, 255, 0.82); + padding: 6rpx; + border-radius: 22rpx; + border: 1.5rpx solid rgba(52, 200, 160, 0.14); + box-shadow: 0 4rpx 16rpx rgba(52, 200, 160, 0.07); +} + +.segment-item { + font-size: 24rpx; + font-weight: 600; + color: #7aA898; + border-radius: 16rpx; +} + +.segment-active { + background: #FFFFFF; + color: #0D3D2E; + box-shadow: 0 4rpx 12rpx rgba(52, 200, 160, 0.12); +} +``` + +### 4.10 空状态 + +```css +.empty-block { + padding: 32rpx; + border-radius: 16rpx; + background: rgba(52, 200, 160, 0.04); +} + +/* 虚线边框变体 */ +.empty-block-dashed { + border: 2rpx dashed rgba(52, 200, 160, 0.2); + background: transparent; +} + +.empty-text { + font-size: 24rpx; + color: #7aA898; +} +``` + +### 4.11 底部安全区 + +```css +.bottom-safe { + height: calc(32rpx + env(safe-area-inset-bottom)); +} + +/* 固定底部按钮区域 */ +.footer-fixed { + position: fixed; + left: 0; right: 0; bottom: 0; + padding: 20rpx 28rpx; + padding-bottom: calc(20rpx + env(safe-area-inset-bottom)); + background: linear-gradient(180deg, transparent 0%, rgba(240, 251, 247, 0.97) 35%); +} +``` + +--- + +## 5. 数据可视化配色 + +| 数据类型 | 色值/色阶 | +|---------|----------| +| 0 / 无数据 | `rgba(52, 200, 160, 0.06)` | +| 低(1-3) | `rgba(52, 200, 160, 0.18)` | +| 中(4-8) | `rgba(251, 191, 36, 0.2)` | +| 高(9+) | `rgba(239, 68, 68, 0.15)` | +| 圆环已完成 | `#34C8A0` | +| 圆环未完成 | `#E8F8F3` | + +--- + +## 6. 禁止事项 + +| 禁止 | 替代方案 | +|------|---------| +| 灰蓝色阴影 `rgba(15, 23, 42, *)` | 薄荷绿阴影 `rgba(52, 200, 160, *)` | +| 旧主色 `#1AA37A` / `#1aa37a` | 新主色 `#34C8A0`(按钮/进度条)或 `#1a8c62`(文字) | +| 灰色文字 `#6B7280` / `#94A3B8` | 绿调文字 `#7aA898` / `#52806E` | +| 灰色背景 `#F1F5F9` / `#F8FAFC` | 绿调背景 `rgba(52, 200, 160, 0.06)` | +| 纯白卡片背景 `#FFFFFF` | 半透明白 `rgba(255, 255, 255, 0.88)` | +| `backdrop-filter: blur()` | 不再使用模糊滤镜(性能考虑),用不透明度代替 | +| 旧页面背景渐变 `#edf2f8 → #fbfdff` | 薄荷绿渐变 `#E6F7F2 → #FAFFFE` | + +--- + +## 7. 快速参考 + +开发新页面时复制此基础结构: + +```vue + + + +``` diff --git a/src/api/auth.js b/src/api/auth.js index 0c6608b..f548de6 100644 --- a/src/api/auth.js +++ b/src/api/auth.js @@ -2,13 +2,14 @@ import { request } from './request' import { MINI_PROGRAM_ID } from '@/config' import { storage, SESSION_KEY, USER_KEY } from '@/utils/storage' -const H5_DEBUG_SESSION_KEY = 'o3dUk5QYaPdfMN9hBxeuouE0q63E' +const H5_DEBUG_SESSION_KEY = 'FxLFPHHBw49loODmRSvqdg==' export function applyH5DebugSession() { let applied = false // #ifdef H5 - if (process.env.NODE_ENV === 'development' && !storage.get(SESSION_KEY)) { + if (process.env.NODE_ENV === 'development' && storage.get(SESSION_KEY) !== H5_DEBUG_SESSION_KEY) { storage.set(SESSION_KEY, H5_DEBUG_SESSION_KEY) + storage.remove(USER_KEY) applied = true } // #endif diff --git a/src/api/request.js b/src/api/request.js index 4c0e420..23898ca 100644 --- a/src/api/request.js +++ b/src/api/request.js @@ -13,6 +13,7 @@ function isInvalidToken(res) { export const request = { async request(options) { const sessionKey = storage.get(SESSION_KEY) + // 测试 const isRetryAfter401 = options._retryAfter401 === true return new Promise((resolve, reject) => { diff --git a/src/pages/logs/index.vue b/src/pages/logs/index.vue index d1c347a..132d764 100644 --- a/src/pages/logs/index.vue +++ b/src/pages/logs/index.vue @@ -1,29 +1,41 @@