feat(calendar): simplify holiday highlight styles and improve accessibility
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 27s
Docker Build & Deploy / Deploy to Production (push) Successful in 6s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 2s
Docker Build & Deploy / WeChat Notification (push) Successful in 2s

- Introduced a new visual style for holiday highlights in the calendar component, replacing complex gradients with solid colors for better clarity.
- Removed the holiday badge to reduce visual noise and enhance user experience.
- Ensured that holiday information remains accessible through long-press interactions.
- Updated specifications to reflect the new design decisions and requirements for both light and dark themes.
- Added tasks for implementation, including style adjustments and accessibility enhancements.
This commit is contained in:
SunCheng
2026-02-12 21:39:27 +08:00
parent aff0cbb55e
commit 803f09cc97
21 changed files with 713 additions and 52 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

@@ -79,6 +79,10 @@
/* 边框颜色 */
--border-color: #E5E7EB;
/* 分段控制器 (Segmented Control) - From .pans/v2.pen NDWwE */
--segmented-bg: #F4F4F5;
--segmented-active-bg: #FFFFFF;
}
/* ============ 深色主题 ============ */
@@ -110,6 +114,10 @@
/* 图标色 (深色主题) */
--icon-star: #FF6B6B;
--icon-coffee: #FCD34D;
/* 分段控制器 (Segmented Control) - From .pans/v2.pen NDWwE */
--segmented-bg: #27272a;
--segmented-active-bg: #3f3f46;
}
/* ============ 通用工具类 ============ */

View File

@@ -1,4 +1,10 @@
<template>
<!--
时间段选择器组件 (Time Period Tabs)
用于统计页面的"周/月/年"时间段切换
样式已按 pencli 设计规范更新 (.pans/v2.pen 节点 NDWwE)
支持亮色和暗色两种主题
-->
<template>
<div class="tabs-wrapper">
<div class="segmented-control">
<div
@@ -46,10 +52,10 @@ defineEmits(['change'])
.segmented-control {
display: flex;
background: transparent;
border-radius: var(--radius-md);
padding: 0;
gap: var(--spacing-sm);
background: var(--segmented-bg);
border-radius: 8px;
padding: 4px;
gap: 4px;
height: 40px;
.tab-item {
@@ -57,13 +63,13 @@ defineEmits(['change'])
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-md);
border-radius: 6px;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
background: rgba(128, 128, 128, 0.15);
background: transparent;
&.active {
background: rgba(128, 128, 128, 0.3);
background: var(--segmented-active-bg);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
.tab-text {
@@ -73,7 +79,7 @@ defineEmits(['change'])
}
&:not(.active):hover {
background: rgba(128, 128, 128, 0.2);
background: rgba(128, 128, 128, 0.1);
}
.tab-text {

View File

@@ -31,6 +31,7 @@
v-for="day in week"
:key="day.date"
class="day-cell"
:aria-label="getAriaLabel(day)"
@click="onDayClick(day)"
@touchstart="onTouchStartHoliday($event, day)"
@touchend="onTouchEndHoliday"
@@ -48,13 +49,6 @@
}"
>
{{ day.dayNumber }}
<!-- 节假日标记 -->
<span
v-if="day.isHoliday"
class="holiday-badge"
>
{{ day.isWorkday ? '班' : '休' }}
</span>
</div>
<div
v-if="day.amount"
@@ -369,6 +363,25 @@ const formatDateKey = (date) => {
return `${year}-${month}-${day}`
}
// 生成无障碍标签
const getAriaLabel = (day) => {
const date = new Date(day.date)
const dateStr = formatDateKey(date)
let label = dateStr
if (day.isHoliday) {
const type = day.isWorkday ? '调休工作日' : '休息日'
label += ` ${day.holidayName} ${type}`
}
if (day.hasData) {
const amountType = day.isProfitable ? '收入' : '支出'
label += ` ${amountType} ${day.amount}`
}
return label
}
// 点击日期
const onDayClick = (day) => {
emit('dayClick', day)
@@ -500,7 +513,6 @@ const onTouchEnd = () => {
position: relative;
width: 100%;
overflow: hidden; /* 保持 hidden 以支持切换动画 */
padding-top: 4px; /* 新增:为第一行的徽章留出空间 */
}
.calendar-grid {
@@ -508,7 +520,6 @@ const onTouchEnd = () => {
flex-direction: column;
gap: var(--spacing-lg);
width: 100%;
padding-top: 4px; /* 新增:为第一行徽章留出空间 */
}
.calendar-week {
@@ -527,7 +538,6 @@ const onTouchEnd = () => {
}
.day-number {
position: relative; /* 为绝对定位的徽章提供定位上下文 */
display: flex;
align-items: center;
justify-content: center;
@@ -545,9 +555,25 @@ const onTouchEnd = () => {
font-weight: var(--font-semibold);
}
/* ========== 节假日样式 ========== */
/* 节假日放假样式(绿色系) */
.day-number.day-holiday {
background-color: #E8F5E9;
color: #2E7D32;
font-weight: var(--font-bold);
}
/* 调休工作日样式(橙色/黄色系) */
.day-number.day-workday {
background-color: #FFF3E0;
color: #E65100;
font-weight: var(--font-bold);
}
/* 选中状态优先级最高 */
.day-number.day-selected {
background-color: var(--accent-primary);
color: #FFFFFF;
background-color: var(--accent-primary) !important;
color: #FFFFFF !important;
font-weight: var(--font-bold);
}
@@ -570,37 +596,6 @@ const onTouchEnd = () => {
color: var(--accent-success);
}
/* ========== 节假日样式 ========== */
/* 节假日放假样式(绿色系) */
.day-number.day-holiday {
background: linear-gradient(135deg, #E8F5E9 0%, #C8E6C9 100%);
color: #2E7D32;
font-weight: var(--font-bold);
}
/* 调休工作日样式(橙色/黄色系) */
.day-number.day-workday {
background: linear-gradient(135deg, #FFF3E0 0%, #FFE0B2 100%);
color: #E65100;
font-weight: var(--font-bold);
}
/* 节假日标记 */
.holiday-badge {
position: absolute;
top: -2px;
right: -2px;
font-size: 9px;
background-color: var(--accent-danger);
color: white;
border-radius: 4px;
padding: 1px 3px;
line-height: 1.2;
font-weight: var(--font-bold);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
z-index: 100;
}
/* 节假日提示浮层 */
.holiday-tooltip-wrapper {
display: flex;

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-12

View File

@@ -0,0 +1,119 @@
## Context
当前 `TimePeriodTabs` 组件使用了自定义的透明背景和半透明灰色样式,与 pencli 设计文件 (`.pans/v2.pen`, 节点 NDWwE) 中定义的视觉规范不一致。设计稿采用了更清晰的视觉层次:浅灰色背景容器包裹着三个标签,激活态使用白色背景突出显示。此外,当前实现缺乏暗色主题的适配。
**技术栈:**
- Vue 3 Composition API (`<script setup>`)
- SCSS 样式 (基于 CSS 变量的主题系统)
- 主题系统: `Web/src/assets/theme.css`
**设计规范来源:**
- `.pans/v2.pen` 节点 NDWwE (TabsWrapper)
- 容器: padding `[8, 24]`, 垂直布局
- SegmentedControl (节点 4iQfn):
- 背景 `#F4F4F5`, 圆角 `8px`, padding `4px`, gap `4px`, height `40px`
- 激活态标签 (节点 LN1iU):
- 背景 `#FFFFFF`, 圆角 `6px`, 文字颜色 `#1A1A1A`, 字重 `600`
- 非激活态标签 (节点 7LCL4, 7VSH1):
- 背景透明, 圆角 `6px`, 文字颜色 `#6B7280`, 字重 `500`
## Goals / Non-Goals
**Goals:**
- 完全符合 pencli 设计规范的视觉样式
- 支持亮色和暗色两种主题,保持良好的对比度和可读性
- 保持组件 API 不变,不影响现有使用方式
- 激活态具有明确的视觉反馈
**Non-Goals:**
- 不修改组件的交互逻辑或事件处理
- 不改变组件的 props 或 emits 接口
- 不添加新功能(如动画效果或手势支持)
## Decisions
### 决策 1: 直接使用 CSS 变量而非硬编码颜色
**选择:**`theme.css` 中定义新的语义化 CSS 变量 `--segmented-bg``--segmented-active-bg`
**理由:**
- 项目已有成熟的 CSS 变量主题系统 (`Web/src/assets/theme.css`)
- 使用变量可以自动适配暗色主题,无需在组件中使用 `v-if` 判断
- 便于后续统一调整分段控制器样式
- 符合项目现有的样式管理模式
**备选方案 (未采用):**
- ~~硬编码颜色值~~ - 无法适配暗色主题
- ~~使用 computed 动态计算颜色~~ - 增加不必要的 JS 逻辑
### 决策 2: 暗色主题映射策略
**选择:** 暗色主题使用以下映射:
- 容器背景: `#27272a` (对应浅色的 `#F4F4F5`)
- 激活态背景: `#3f3f46` (对应浅色的 `#FFFFFF`)
- 激活态文字: `#f4f4f5` (对应浅色的 `#1A1A1A`)
- 非激活态文字: `#a1a1aa` (对应浅色的 `#6B7280`)
**理由:**
- 保持与现有深色主题色板 (`--bg-tertiary`, `--border-color`) 的一致性
- 确保 WCAG AA 级别的对比度标准(激活态文字对比度 > 4.5:1)
- 视觉层次清晰,激活态明显突出
**备选方案 (未采用):**
- ~~完全反转亮色主题颜色~~ - 对比度不足,可读性差
- ~~使用蓝色或其他强调色~~ - 与设计稿的中性灰色调不符
### 决策 3: 保留现有的 hover 和过渡效果
**选择:** 保留 `transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1)` 和 hover 状态
**理由:**
- 提升交互体验,符合现代 UI 设计规范
- 设计稿未明确禁止过渡效果
- 与应用其他组件的交互风格保持一致
## Risks / Trade-offs
### 风险 1: 新增 CSS 变量可能与未来设计稿冲突
**风险:** 如果后续设计稿为分段控制器定义了不同的颜色变量,可能需要重新调整
**缓解措施:**
- 使用语义化命名 (`--segmented-*`),明确变量用途
-`theme.css` 中添加注释标注变量来源 (`/* From .pans/v2.pen NDWwE */`)
### 风险 2: 暗色主题对比度可能不够理想
**风险:** 在某些设备或环境光下,暗色主题的激活态可能不够明显
**缓解措施:**
- 使用 Chrome DevTools 的对比度检查工具验证
- 添加微妙的阴影效果增强视觉分离 (`box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3)`)
### 权衡: 放弃完全像素级还原设计稿字体
**权衡:** 设计稿使用 `DM Sans` 字体,但项目中可能未全局加载该字体
**决策:** 依赖 `--font-primary` 变量,由主题系统统一管理字体回退
**影响:** 在未加载 `DM Sans` 的环境下,会回退到系统字体,视觉效果略有差异,但可接受
## Migration Plan
**部署步骤:**
1. 更新 `theme.css`,添加新的 CSS 变量
2. 更新 `TimePeriodTabs.vue` 组件样式
3. 验证浏览器兼容性 (Chrome, Safari, Firefox)
4. 在亮色和暗色主题下分别测试视觉效果
**回滚策略:**
- 如发现严重视觉问题,可通过 Git 回滚单个文件
- CSS 变量的添加不会破坏现有样式,可以安全回滚
**影响范围:**
- 仅影响统计 v2 页面的时间段选择器组件
- 无 API 变更,无需后端配合
## Open Questions
无待解决问题。设计规范已明确,实现路径清晰。

View File

@@ -0,0 +1,37 @@
## Why
统计 v2 页面中的时间段选择器组件(`TimePeriodTabs`)的视觉样式与 pencli 设计文件(`.pans/v2.pen`)中的节点 NDWwE 不一致。当前实现使用透明背景和半透明灰色,而设计稿要求使用浅灰色背景(`#F4F4F5`)和白色激活态,且需要适配暗色主题。
## What Changes
- 修改 `Web/src/components/TimePeriodTabs.vue` 组件样式,使其完全符合设计稿规格
- 添加外层容器背景色 `#F4F4F5` (浅色主题) 和对应的暗色主题背景色
- 调整激活态样式:使用白色背景 (`#FFFFFF`) 替代当前的半透明灰色
- 调整非激活态样式:使用透明背景替代当前的半透明灰色
- 增加容器内边距 `4px` 和圆角 `8px`
- 调整文字颜色:激活态使用 `#1A1A1A` (深色),非激活态使用 `#6B7280` (灰色)
- 添加暗色主题变体,确保在深色模式下也符合设计规范
## Capabilities
### New Capabilities
### Modified Capabilities
- `time-period-tabs-ui`: 时间段选择器组件的 UI 样式需求变更,需要完全匹配 pencli 设计稿并支持双主题
## Impact
**受影响的文件:**
- `Web/src/components/TimePeriodTabs.vue` - 组件样式重写
**受影响的页面:**
- `Web/src/views/statisticsV2/Index.vue` - 使用该组件的统计 v2 页面
**依赖:**
- `Web/src/assets/theme.css` - 可能需要添加新的主题变量
**用户体验影响:**
- 视觉效果更加符合设计规范
- 亮色/暗色主题下均有更好的对比度和可读性
- 激活态更加明显,提升交互反馈

View File

@@ -0,0 +1,104 @@
## ADDED Requirements
### Requirement: 分段控制器容器样式
时间段选择器组件 SHALL 具有一个浅灰色背景容器,包含固定的内边距、圆角和高度,以匹配 pencli 设计规范 (节点 4iQfn)。
#### Scenario: 亮色主题容器样式
- **WHEN** 用户在亮色主题下查看统计 v2 页面
- **THEN** 分段控制器容器背景色为 `#F4F4F5`
- **AND** 容器内边距为 `4px`
- **AND** 容器圆角为 `8px`
- **AND** 容器高度为 `40px`
- **AND** 容器内标签间隔为 `4px`
#### Scenario: 暗色主题容器样式
- **WHEN** 用户在暗色主题下查看统计 v2 页面
- **THEN** 分段控制器容器背景色为 `#27272a`
- **AND** 容器内边距为 `4px`
- **AND** 容器圆角为 `8px`
- **AND** 容器高度为 `40px`
- **AND** 容器内标签间隔为 `4px`
### Requirement: 激活态标签样式
当某个时间段标签被选中时,该标签 SHALL 显示白色(亮色主题)或深灰色(暗色主题)背景,文字颜色为深色(亮色)或浅色(暗色),字重为粗体,以突出显示当前选择。
#### Scenario: 亮色主题激活态
- **WHEN** 用户在亮色主题下选择"月"标签
- **THEN** "月"标签背景色为 `#FFFFFF`
- **AND** "月"标签文字颜色为 `#1A1A1A`
- **AND** "月"标签文字字重为 `600`
- **AND** "月"标签圆角为 `6px`
- **AND** "月"标签具有微妙的阴影效果
#### Scenario: 暗色主题激活态
- **WHEN** 用户在暗色主题下选择"月"标签
- **THEN** "月"标签背景色为 `#3f3f46`
- **AND** "月"标签文字颜色为 `#f4f4f5`
- **AND** "月"标签文字字重为 `600`
- **AND** "月"标签圆角为 `6px`
- **AND** "月"标签具有微妙的阴影效果
### Requirement: 非激活态标签样式
未被选中的时间段标签 SHALL 显示透明背景,灰色文字,中等字重,与激活态形成明显对比。
#### Scenario: 亮色主题非激活态
- **WHEN** 用户在亮色主题下查看"周"和"年"标签(未选中)
- **THEN** "周"和"年"标签背景色为透明
- **AND** "周"和"年"标签文字颜色为 `#6B7280`
- **AND** "周"和"年"标签文字字重为 `500`
- **AND** "周"和"年"标签圆角为 `6px`
#### Scenario: 暗色主题非激活态
- **WHEN** 用户在暗色主题下查看"周"和"年"标签(未选中)
- **THEN** "周"和"年"标签背景色为透明
- **AND** "周"和"年"标签文字颜色为 `#a1a1aa`
- **AND** "周"和"年"标签文字字重为 `500`
- **AND** "周"和"年"标签圆角为 `6px`
### Requirement: 交互反馈
标签 SHALL 在用户悬停时提供视觉反馈,并在状态切换时具有平滑的过渡动画。
#### Scenario: 悬停效果
- **WHEN** 用户将鼠标悬停在非激活态标签上
- **THEN** 标签背景透明度略微增加
- **AND** 过渡动画时长为 `0.3s`
- **AND** 使用 `cubic-bezier(0.4, 0, 0.2, 1)` 缓动函数
#### Scenario: 点击切换动画
- **WHEN** 用户点击非激活态标签
- **THEN** 新激活的标签背景和文字颜色平滑过渡到激活态样式
- **AND** 原激活的标签平滑过渡到非激活态样式
- **AND** 过渡动画时长为 `0.3s`
### Requirement: 主题自适应
分段控制器组件 SHALL 根据应用的当前主题设置自动切换样式,无需手动干预。
#### Scenario: 主题切换响应
- **WHEN** 用户从亮色主题切换到暗色主题
- **THEN** 分段控制器容器背景从 `#F4F4F5` 变为 `#27272a`
- **AND** 激活态标签背景从 `#FFFFFF` 变为 `#3f3f46`
- **AND** 激活态标签文字从 `#1A1A1A` 变为 `#f4f4f5`
- **AND** 非激活态标签文字从 `#6B7280` 变为 `#a1a1aa`
#### Scenario: 主题变量依赖
- **WHEN** 系统读取分段控制器样式
- **THEN** 容器背景使用 CSS 变量 `--segmented-bg`
- **AND** 激活态背景使用 CSS 变量 `--segmented-active-bg`
- **AND** 文字颜色使用 CSS 变量 `--text-primary``--text-secondary`
### Requirement: 可访问性对比度
激活态和非激活态的文字与背景对比度 SHALL 满足 WCAG AA 级别标准 (至少 4.5:1)。
#### Scenario: 亮色主题对比度验证
- **WHEN** 在亮色主题下测量激活态文字 (`#1A1A1A`) 与背景 (`#FFFFFF`) 的对比度
- **THEN** 对比度比值 >= 4.5:1
#### Scenario: 暗色主题对比度验证
- **WHEN** 在暗色主题下测量激活态文字 (`#f4f4f5`) 与背景 (`#3f3f46`) 的对比度
- **THEN** 对比度比值 >= 4.5:1

View File

@@ -0,0 +1,43 @@
## 1. 主题变量准备
- [x] 1.1 在 `Web/src/assets/theme.css``:root` 块中添加浅色主题分段控制器变量 `--segmented-bg: #F4F4F5``--segmented-active-bg: #FFFFFF`
- [x] 1.2 在 `Web/src/assets/theme.css``[data-theme="dark"]` 块中添加暗色主题分段控制器变量 `--segmented-bg: #27272a``--segmented-active-bg: #3f3f46`
- [x] 1.3 为新变量添加注释,标注其来源于 `.pans/v2.pen` 节点 NDWwE
## 2. 组件样式重构
- [x] 2.1 修改 `.tabs-wrapper` 的 padding 为 `var(--spacing-sm) var(--spacing-xl)` (对应设计稿的 `[8, 24]`)
- [x] 2.2 修改 `.segmented-control` 的 background 从 `transparent` 改为 `var(--segmented-bg)`
- [x] 2.3 修改 `.segmented-control` 的 border-radius 从 `var(--radius-md)` 改为 `8px`
- [x] 2.4 修改 `.segmented-control` 的 padding 从 `0` 改为 `4px`
- [x] 2.5 修改 `.segmented-control` 的 gap 从 `var(--spacing-sm)` 改为 `4px`
- [x] 2.6 确认 `.segmented-control` 的 height 保持为 `40px`
## 3. 标签项样式调整
- [x] 3.1 修改 `.tab-item` 的默认 background 从 `rgba(128, 128, 128, 0.15)` 改为 `transparent`
- [x] 3.2 修改 `.tab-item` 的 border-radius 从 `var(--radius-md)` 改为 `6px`
- [x] 3.3 修改 `.tab-item.active` 的 background 从 `rgba(128, 128, 128, 0.3)` 改为 `var(--segmented-active-bg)`
- [x] 3.4 为 `.tab-item.active` 添加阴影效果 `box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12)`
- [x] 3.5 确认 `.tab-item.active .tab-text` 的 color 使用 `var(--text-primary)` 且 font-weight 为 `var(--font-bold)` (600)
- [x] 3.6 确认 `.tab-item:not(.active) .tab-text` 的 color 使用 `var(--text-secondary)` 且 font-weight 为 `var(--font-medium)` (500)
## 4. 交互效果优化
- [x] 4.1 确认 `.tab-item` 的 transition 保持为 `all 0.3s cubic-bezier(0.4, 0, 0.2, 1)`
- [x] 4.2 移除或调整 `.tab-item:not(.active):hover` 的背景色,使其微妙增加透明度 (如 `background: rgba(128, 128, 128, 0.1)`)
## 5. 验证与测试
- [x] 5.1 在 Chrome 浏览器的亮色主题下检查分段控制器视觉效果,对比 pencli 设计稿截图
- [x] 5.2 在 Chrome 浏览器的暗色主题下检查分段控制器视觉效果,确保对比度充足
- [x] 5.3 使用 Chrome DevTools 的对比度检查工具验证激活态和非激活态文字的对比度 >= 4.5:1
- [x] 5.4 在 Safari 和 Firefox 浏览器中验证样式兼容性
- [x] 5.5 在移动设备或移动模拟器中测试触摸交互和视觉效果
- [x] 5.6 切换"周"、"月"、"年"三个标签,确认激活态切换动画流畅
- [x] 5.7 在统计 v2 页面中实际使用,确认无布局错位或样式冲突
## 6. 文档与清理
- [x] 6.1 如有必要,更新 `Web/src/components/TimePeriodTabs.vue` 文件顶部的注释,说明样式已按 pencli 设计规范更新
- [x] 6.2 检查是否有未使用的 CSS 类或变量,进行清理

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-11

View File

@@ -0,0 +1,97 @@
## Context
当前 `Calendar.vue` 组件使用复杂的 CSS 样式来高亮显示节假日:
- 休息日使用绿色渐变背景 (`linear-gradient(135deg, #E8F5E9 0%, #C8E6C9 100%)`)
- 调休工作日使用橙色渐变背景 (`linear-gradient(135deg, #FFF3E0 0%, #FFE0B2 100%)`)
- 右上角显示红色徽章("休"或"班"
这些装饰性元素增加了视觉复杂度,与 design tokens 系统的简洁性原则不符。用户反馈在多状态叠加(选中、有数据、节假日)时视觉混乱。
## Goals / Non-Goals
**Goals:**
- 简化节假日视觉样式,使用纯色背景替代渐变
- 移除节假日徽章,减少视觉噪音
- 确保所有节假日功能(识别、长按查看)保持不变
- 提升多状态叠加时的视觉一致性
**Non-Goals:**
- 不修改节假日数据获取逻辑API、数据结构
- 不影响长按浮层的交互逻辑
- 不改变日历的其他视觉状态(选中、有数据、超预算)
## Decisions
### 决策 1: 纯色背景替代渐变
**选择**: 使用 CSS 变量定义的单一背景色(如 `--bg-success-subtle``--bg-warning-subtle`
**理由**:
- 渐变背景在小尺寸 (32px×32px) 的日期单元格中效果不明显,反而增加渲染成本
- 纯色更符合 Material Design 和现代 UI 设计趋势
- 与现有 design tokens 系统一致,易于主题切换(深色模式)
**替代方案及弃用原因**:
- **保留渐变但简化**: 仍需维护额外的颜色定义,不能复用 design tokens
- **使用边框样式**: 边框在视觉上不够突出,易被忽略
### 决策 2: 移除节假日徽章
**选择**: 完全移除右上角的"休"/"班"徽章,仅依赖背景颜色和长按浮层
**理由**:
- 徽章在 9px 字号下可读性差,尤其对老年用户不友好
- 背景颜色已足够区分休息日(绿色)和工作日(橙色)
- 长按浮层提供详细信息,徽章信息冗余
- 减少绝对定位元素,简化布局
**替代方案及弃用原因**:
- **使用图标替代文字**: 图标需要额外的视觉学习成本
- **移至日期数字下方**: 占用交易金额显示区域,产生新的冲突
### 决策 3: 状态优先级规则
**选择**: 选中状态 > 数据状态 > 节假日状态
**理由**:
- 选中状态是用户当前关注焦点,应具有最高优先级
- 交易数据是核心业务信息,优先于装饰性节假日样式
- 节假日信息可通过长按浮层补充查看
## Risks / Trade-offs
### 风险 1: 颜色区分度下降
**描述**: 移除徽章后,仅依赖背景颜色区分休息日和工作日,色盲用户可能无法区分绿色和橙色
**缓解措施**:
- 在 ARIA 标签中补充文本信息(如 `aria-label="2026-01-01 春节 休息日"`
- 未来可考虑引入无障碍模式,使用图案纹理辅助颜色
### 风险 2: 现有用户习惯改变
**描述**: 已习惯徽章样式的用户可能一时不适应纯色背景
**缓解措施**:
- 本次为视觉优化,不涉及功能变更,用户可快速适应
- 长按查看详情功能保持不变,信息获取路径未阻断
### Trade-off: 简洁性 vs 信息丰富度
**选择**: 优先简洁性,通过交互(长按)补充详细信息
**理由**: 日历首屏展示的核心是日期和交易数据,节假日信息为辅助,适合按需查看
## Migration Plan
本次为纯前端样式优化,无需数据库迁移或 API 变更。
**部署步骤**:
1. 修改 `Calendar.vue` 的 SCSS 样式
2. 移除 `.holiday-badge` 相关模板代码
3. 调整 `.day-holiday``.day-workday` 类的样式为纯色背景
4. 测试多种状态组合(选中+节假日、有数据+节假日)
5. 验证长按浮层功能正常
6. 构建并部署
**回滚策略**:
- 前端样式修改,可快速通过 Git revert 回滚
- 无数据依赖,回滚无风险
## Open Questions
无待定问题。设计方案已明确。

View File

@@ -0,0 +1,26 @@
## Why
当前日历节假日的视觉呈现过于复杂,多种状态叠加(节假日、工作日、选中、有数据等)导致视觉混乱。渐变背景和红色徽章增加了视觉噪音,影响用户快速浏览日历的体验。需要简化节假日高亮样式,提升界面清晰度和可维护性。
## What Changes
- **移除复杂的渐变背景**:将节假日的绿色/橙色渐变背景改为简洁的纯色背景或边框样式
- **简化或移除节假日徽章**:移除右上角的红色"休"/"班"徽章,改用更温和的视觉提示
- **优化状态叠加逻辑**:减少多种视觉状态的冲突,确保在不同状态下节假日信息仍清晰可识别
- **保留核心功能**:节假日识别和长按查看详情功能保持不变,仅调整视觉呈现方式
## Capabilities
### New Capabilities
<!-- 无新能力 -->
### Modified Capabilities
<!-- 节假日显示规范调整 -->
- `calendar-holiday-display`: 简化节假日视觉呈现规范,从复杂渐变+徽章样式改为简洁样式
## Impact
- **影响代码**: `Web/src/views/calendarV2/modules/Calendar.vue` 的样式部分SCSS
- **不影响API**: 节假日数据获取逻辑保持不变
- **不影响功能**: 节假日识别、长按提示等功能完整保留
- **用户体验**: 提升日历界面清晰度,减少视觉干扰

View File

@@ -0,0 +1,37 @@
## MODIFIED Requirements
### Requirement: 节假日视觉样式
日历日期单元格在显示节假日包括休息日和调休工作日SHALL 使用简洁的视觉样式,避免过度的装饰性元素。视觉呈现 SHALL 保持清晰、统一,且不干扰日期本身的可读性。
#### Scenario: 休息日显示
- **WHEN** 日期为节假日休息日(如春节、国庆)或普通周末
- **THEN** 日期单元格使用浅绿色纯色背景(而非渐变),文字颜色为深绿色,不显示徽章
#### Scenario: 调休工作日显示
- **WHEN** 日期为调休工作日(需要补班)
- **THEN** 日期单元格使用浅橙色纯色背景(而非渐变),文字颜色为深橙色,不显示徽章
#### Scenario: 节假日与选中状态叠加
- **WHEN** 节假日日期被用户选中
- **THEN** 选中状态的高亮样式优先级高于节假日样式,节假日信息通过长按浮层查看
#### Scenario: 节假日与交易数据叠加
- **WHEN** 节假日日期有交易数据记录
- **THEN** 节假日背景样式与交易金额显示不冲突,金额数字保持清晰可读
### Requirement: 节假日信息查看
用户 SHALL 能够通过长按日历日期单元格查看详细的节假日信息。此功能 SHALL 保持与简化前完全一致。
#### Scenario: 长按查看节假日详情
- **WHEN** 用户长按节假日日期超过 500ms
- **THEN** 显示浮层,展示节假日名称和类型(休息日/调休工作日)
#### Scenario: 关闭节假日详情
- **WHEN** 用户点击浮层外部区域或浮层本身
- **THEN** 浮层关闭,返回日历视图
## REMOVED Requirements
### Requirement: 节假日徽章显示
**Reason**: 徽章占用空间且增加视觉噪音,与简洁化目标不符
**Migration**: 节假日信息通过背景颜色和长按浮层传达,无需徽章

View File

@@ -0,0 +1,40 @@
## 1. 模板结构调整
- [x] 1.1 在 Calendar.vue 模板中移除节假日徽章 `<span class="holiday-badge">` 元素
- [x] 1.2 确认 `.day-number` 元素保留 `day-holiday``day-workday` 类名(用于样式)
## 2. 样式重构 - 节假日背景
- [x] 2.1 将 `.day-holiday` 的渐变背景改为纯色(浅绿色),使用 CSS 变量或固定色值
- [x] 2.2 将 `.day-workday` 的渐变背景改为纯色(浅橙色),使用 CSS 变量或固定色值
- [x] 2.3 调整节假日文字颜色为深色系,确保可读性(绿色/橙色)
## 3. 样式清理
- [x] 3.1 删除 `.holiday-badge` 及其相关样式position, background, border-radius 等)
- [x] 3.2 移除 `.day-number``position: relative`(如果仅用于徽章定位)
- [x] 3.3 清理不再使用的 CSS 变量或注释
## 4. 状态优先级验证
- [x] 4.1 测试节假日 + 选中状态:确认选中状态优先显示
- [x] 4.2 测试节假日 + 有数据状态:确认交易金额显示不被遮挡
- [x] 4.3 测试节假日 + 其他月份:确认非当月日期的透明度正常
## 5. 功能回归测试
- [x] 5.1 验证长按节假日日期 500ms 后显示浮层
- [x] 5.2 验证浮层内容正确(节假日名称、类型)
- [x] 5.3 验证点击浮层外部可关闭
- [x] 5.4 确认普通周末(无 API 数据)仍正确显示为休息日
## 6. 无障碍性增强(可选)
- [x] 6.1 为节假日日期添加 `aria-label`(如 "2026-01-01 春节 休息日"
- [x] 6.2 确认屏幕阅读器能正确读取节假日信息
## 7. 视觉验证与调整
- [x] 7.1 在浅色主题下检查节假日颜色对比度
- [x] 7.2 在深色主题下检查节假日颜色对比度(如果支持)
- [x] 7.3 对比简化前后截图,确认视觉简洁性提升

View File

@@ -0,0 +1,37 @@
## MODIFIED Requirements
### Requirement: 节假日视觉样式
日历日期单元格在显示节假日包括休息日和调休工作日SHALL 使用简洁的视觉样式,避免过度的装饰性元素。视觉呈现 SHALL 保持清晰、统一,且不干扰日期本身的可读性。
#### Scenario: 休息日显示
- **WHEN** 日期为节假日休息日(如春节、国庆)或普通周末
- **THEN** 日期单元格使用浅绿色纯色背景(而非渐变),文字颜色为深绿色,不显示徽章
#### Scenario: 调休工作日显示
- **WHEN** 日期为调休工作日(需要补班)
- **THEN** 日期单元格使用浅橙色纯色背景(而非渐变),文字颜色为深橙色,不显示徽章
#### Scenario: 节假日与选中状态叠加
- **WHEN** 节假日日期被用户选中
- **THEN** 选中状态的高亮样式优先级高于节假日样式,节假日信息通过长按浮层查看
#### Scenario: 节假日与交易数据叠加
- **WHEN** 节假日日期有交易数据记录
- **THEN** 节假日背景样式与交易金额显示不冲突,金额数字保持清晰可读
### Requirement: 节假日信息查看
用户 SHALL 能够通过长按日历日期单元格查看详细的节假日信息。此功能 SHALL 保持与简化前完全一致。
#### Scenario: 长按查看节假日详情
- **WHEN** 用户长按节假日日期超过 500ms
- **THEN** 显示浮层,展示节假日名称和类型(休息日/调休工作日)
#### Scenario: 关闭节假日详情
- **WHEN** 用户点击浮层外部区域或浮层本身
- **THEN** 浮层关闭,返回日历视图
## REMOVED Requirements
### Requirement: 节假日徽章显示
**Reason**: 徽章占用空间且增加视觉噪音,与简洁化目标不符
**Migration**: 节假日信息通过背景颜色和长按浮层传达,无需徽章

View File

@@ -0,0 +1,108 @@
# Time Period Tabs UI Specification
时间段选择器组件的 UI 规格,用于统计页面的"周/月/年"时间段切换。
## Requirements
### Requirement: 分段控制器容器样式
时间段选择器组件 SHALL 具有一个浅灰色背景容器,包含固定的内边距、圆角和高度,以匹配 pencli 设计规范 (节点 4iQfn)。
#### Scenario: 亮色主题容器样式
- **WHEN** 用户在亮色主题下查看统计 v2 页面
- **THEN** 分段控制器容器背景色为 `#F4F4F5`
- **AND** 容器内边距为 `4px`
- **AND** 容器圆角为 `8px`
- **AND** 容器高度为 `40px`
- **AND** 容器内标签间隔为 `4px`
#### Scenario: 暗色主题容器样式
- **WHEN** 用户在暗色主题下查看统计 v2 页面
- **THEN** 分段控制器容器背景色为 `#27272a`
- **AND** 容器内边距为 `4px`
- **AND** 容器圆角为 `8px`
- **AND** 容器高度为 `40px`
- **AND** 容器内标签间隔为 `4px`
### Requirement: 激活态标签样式
当某个时间段标签被选中时,该标签 SHALL 显示白色(亮色主题)或深灰色(暗色主题)背景,文字颜色为深色(亮色)或浅色(暗色),字重为粗体,以突出显示当前选择。
#### Scenario: 亮色主题激活态
- **WHEN** 用户在亮色主题下选择"月"标签
- **THEN** "月"标签背景色为 `#FFFFFF`
- **AND** "月"标签文字颜色为 `#1A1A1A`
- **AND** "月"标签文字字重为 `600`
- **AND** "月"标签圆角为 `6px`
- **AND** "月"标签具有微妙的阴影效果
#### Scenario: 暗色主题激活态
- **WHEN** 用户在暗色主题下选择"月"标签
- **THEN** "月"标签背景色为 `#3f3f46`
- **AND** "月"标签文字颜色为 `#f4f4f5`
- **AND** "月"标签文字字重为 `600`
- **AND** "月"标签圆角为 `6px`
- **AND** "月"标签具有微妙的阴影效果
### Requirement: 非激活态标签样式
未被选中的时间段标签 SHALL 显示透明背景,灰色文字,中等字重,与激活态形成明显对比。
#### Scenario: 亮色主题非激活态
- **WHEN** 用户在亮色主题下查看"周"和"年"标签(未选中)
- **THEN** "周"和"年"标签背景色为透明
- **AND** "周"和"年"标签文字颜色为 `#6B7280`
- **AND** "周"和"年"标签文字字重为 `500`
- **AND** "周"和"年"标签圆角为 `6px`
#### Scenario: 暗色主题非激活态
- **WHEN** 用户在暗色主题下查看"周"和"年"标签(未选中)
- **THEN** "周"和"年"标签背景色为透明
- **AND** "周"和"年"标签文字颜色为 `#a1a1aa`
- **AND** "周"和"年"标签文字字重为 `500`
- **AND** "周"和"年"标签圆角为 `6px`
### Requirement: 交互反馈
标签 SHALL 在用户悬停时提供视觉反馈,并在状态切换时具有平滑的过渡动画。
#### Scenario: 悬停效果
- **WHEN** 用户将鼠标悬停在非激活态标签上
- **THEN** 标签背景透明度略微增加
- **AND** 过渡动画时长为 `0.3s`
- **AND** 使用 `cubic-bezier(0.4, 0, 0.2, 1)` 缓动函数
#### Scenario: 点击切换动画
- **WHEN** 用户点击非激活态标签
- **THEN** 新激活的标签背景和文字颜色平滑过渡到激活态样式
- **AND** 原激活的标签平滑过渡到非激活态样式
- **AND** 过渡动画时长为 `0.3s`
### Requirement: 主题自适应
分段控制器组件 SHALL 根据应用的当前主题设置自动切换样式,无需手动干预。
#### Scenario: 主题切换响应
- **WHEN** 用户从亮色主题切换到暗色主题
- **THEN** 分段控制器容器背景从 `#F4F4F5` 变为 `#27272a`
- **AND** 激活态标签背景从 `#FFFFFF` 变为 `#3f3f46`
- **AND** 激活态标签文字从 `#1A1A1A` 变为 `#f4f4f5`
- **AND** 非激活态标签文字从 `#6B7280` 变为 `#a1a1aa`
#### Scenario: 主题变量依赖
- **WHEN** 系统读取分段控制器样式
- **THEN** 容器背景使用 CSS 变量 `--segmented-bg`
- **AND** 激活态背景使用 CSS 变量 `--segmented-active-bg`
- **AND** 文字颜色使用 CSS 变量 `--text-primary``--text-secondary`
### Requirement: 可访问性对比度
激活态和非激活态的文字与背景对比度 SHALL 满足 WCAG AA 级别标准 (至少 4.5:1)。
#### Scenario: 亮色主题对比度验证
- **WHEN** 在亮色主题下测量激活态文字 (`#1A1A1A`) 与背景 (`#FFFFFF`) 的对比度
- **THEN** 对比度比值 >= 4.5:1
#### Scenario: 暗色主题对比度验证
- **WHEN** 在暗色主题下测量激活态文字 (`#f4f4f5`) 与背景 (`#3f3f46`) 的对比度
- **THEN** 对比度比值 >= 4.5:1