20260816220132

This commit is contained in:
oneao committed 2026-08-16 22:01:32 +08:00
1 parent b6f9a4c912
commit 72993ecdcd
179 files changed
+20050 -633

No files matched your search

@@ -0,0 +1,223 @@
---
name: date-picker-component
overview: 在 fms-vue 组件库中新增 DatePicker(单日期,支持时间)与 RangePicker(日期范围,支持时间)两个组件,复用现有 Popover 作为弹层,使用 dayjs 处理格式化(format 展示格式、valueFormat 绑定值格式),沿用现有 SCSS 主题体系。暂不做快捷选项与 disabledDate。
design:
architecture:
framework: vue
component: tdesign
styleKeywords:
- Enterprise
- Clean
- Form-Control
- Theme-Aware
fontSystem:
fontFamily: PingFang SC
heading:
size: 16px
weight: 600
subheading:
size: 14px
weight: 500
body:
size: 13px
weight: 400
colorSystem:
primary:
- "#2563EB"
- "#3B82F6"
background:
- "#FFFFFF"
- "#F8FAFC"
text:
- "#1E293B"
- "#64748B"
functional:
- "#22C55E"
- "#EF4444"
- "#F1F5F9"
todos:
- id: add-dayjs-dep
content: 在 package.json 增加 dayjs 依赖并安装
status: completed
- id: create-date-utils
content: 新建 date-utils.js,基于 dayjs 实现 format/parse/矩阵等纯函数
status: completed
dependencies:
- add-dayjs-dep
- id: create-calendar-panel
content: 新建 calendar-panel.vue 共享月历与时间选择面板
status: completed
dependencies:
- create-date-utils
- id: create-date-picker
content: 新建 date-picker.vue 单个日期时间选择器
status: completed
dependencies:
- create-calendar-panel
- id: create-range-picker
content: 新建 range-picker.vue 范围选择器含 hover 预览
status: completed
dependencies:
- create-calendar-panel
- id: create-date-scss
content: 新建 index.scss 沿用主题变量完成样式
status: completed
dependencies:
- create-calendar-panel
- create-date-picker
- create-range-picker
- id: add-demo-verify
content: 在 App.vue 增加演示区块并运行 lint/fmt 验证
status: completed
dependencies:
- create-date-picker
- create-range-picker
- create-date-scss
---
## 用户需求
在 fms-vue 组件库中新增 Date 日期选择组件,包含单个日期选择(DatePicker)与范围选择(RangePicker),并支持时间(时分秒)选择。
## 产品概述
组件以「只读输入框触发器 + 点击弹出面板」形式工作,面板复用现有 Popover 组件。DatePicker 选择单个日期时间,RangePicker 选择起止区间。两者共享一个日历面板组件。用户可在输入框看到按 format 格式化后的文本,选中后通过 v-model(或 valueFormat 字符串)回传值。
## 核心特性
- 单个日期时间选择(DatePicker)与范围选择(RangePicker)
- 点击输入框弹出日历面板,复用 Popover(manual 受控、followTriggerWidth、点击外部/Esc 关闭、定位翻转)
- 支持 format 设置展示格式(数组时多格式匹配,以第一个为准,参考 dayjs#format);valueFormat 设置绑定值格式(设为后 value/defaultValue/v-model 可为字符串,change 返回同格式字符串)
- 支持时间选择(时/分/秒),showTime 控制
- 日历面板:年月切换、星期表头、日期网格(含上下月补位)、今日标记、选中态、范围区间高亮与 hover 预览
- 清除按钮(clearable)、禁用态(disabled)、占位符(placeholder)
- 沿用现有 SCSS 主题变量与暗色/主题切换体系
- 日期处理使用 dayjs
- 暂不做:快捷选项(presets)、disabledDate 禁用日期(面板预留 disabled 钩子)
## 技术栈
- 框架:Vue 3.5 + `<script setup>`(与现有组件一致)
- 样式:SCSS,`<style scoped lang="scss">` + `@use './index.scss'`,复用现有主题 CSS 变量
- 弹层:复用 `src/components/ui/popover/popover.vue`(trigger="manual"、:open 受控、followTriggerWidth、arrow=false、placement="bottom-start")
- 图标:`@lucide/vue`(Calendar / ChevronLeft / ChevronRight / X 等)
- 日期库:dayjs(需新增依赖)
- 无统一出口文件,沿用按需 import 方式
## 实现策略
核心是把「触发器 + Popover + 日历面板」三层解耦,与现有 Select 组件结构对标。日历面板作为共享受控组件,被两个 Picker 复用;日期解析/格式化全部收敛到 `date-utils.js` 纯函数(基于 dayjs),保证可单测、可复用。
### 关键技术决策
1. **复用 Popover 而非自建浮层**:Popover 已具备定位翻转、点击外部关闭、Esc 关闭、followTriggerWidth,且 Select 已验证此模式。自建会重复这些逻辑且易出 bug。
2. **date-utils.js 纯函数封装 dayjs**:`format(date, fmt)`、`parse(str, fmt)`、`getMonthMatrix(year, month)`、`isSameDay`、`isSameMonth`、`addMonth`、`compareDate`、`isInRange` 等。Picker 只处理交互与状态,日期计算一律下沉,便于测试与扩展。
3. **format 多格式匹配**:format 为数组时,解析/展示以第一个为准(参考 dayjs#format 与 @rc-component/picker 约定)。`format` 用于展示文本,`valueFormat` 用于绑定值序列化。
4. **modelValue 类型**:内部统一用原生 `Date`(或 dayjs 对象)做运算;对外通过 `valueFormat` 决定 v-model 是 `Date` 还是字符串。RangePicker 为 `[start, end]`(对应 Date 或字符串数组)。
5. **范围 hover 预览**:RangePicker 内部维护 `hoverValue`,end 未选定前,鼠标划过日期实时高亮 `start~hover` 区间。
### 性能与可靠性
- 日历矩阵每月 42 格,`computed` 缓存,月份切换才重算,无额外遍历开销。
- Popover 仅在 open 时注册全局监听,关闭即清理(Popover 已处理),无长期监听泄漏。
- dayjs 解析失败(非法字符串)时回退 null 并保留输入框文本,避免崩溃。
## 实现要点(执行细节)
- **dayjs 依赖**:在 `fms-vue/package.json` 的 dependencies 增加 `"dayjs": "^1.11.13"`,执行 `pnpm install`。
- **复用现有 SCSS 变量**:配色、圆角、阴影沿用 `src/theme/tokens.css` 与现有组件 `index.scss` 中的 CSS 变量,确保暗色/主题切换生效。
- **日历面板 disabled 钩子**:格子渲染时预留 `(cell) => boolean` 判断位(默认返回 false),便于后续扩展 disabledDate。
- **保持 Select 交互习惯**:触发器类 Input 框、清除按钮、键盘(左右/上下/回车/Esc)可后续补,第一版至少支持点击与 Esc。
- **App.vue 演示**:参照现有 message/notification 演示区块,新增 DatePicker / RangePicker 演示,验证弹层定位、选择、清除、valueFormat 双向绑定、范围 hover、主题切换。
## 架构设计
### 组件关系
```mermaid
graph TD
DatePicker --> Popover
RangePicker --> Popover
DatePicker --> CalendarPanel
RangePicker --> CalendarPanel
CalendarPanel --> dateUtils[date-utils.js / dayjs]
Popover --> position[utils/position.js]
```
## 目录结构
```
fms-vue/
├── package.json # [MODIFY] 新增 dayjs 依赖
├── src/
│ ├── App.vue # [MODIFY] 新增 DatePicker/RangePicker 演示区块
│ └── components/ui/
│ ├── date/
│ │ ├── date-utils.js # [NEW] 基于 dayjs 的纯函数:format/parse/getMonthMatrix/isSameDay/isSameMonth/addMonth/compareDate/isInRange
│ │ ├── calendar-panel.vue # [NEW] 共享月历面板:年月切换、星期表头、日期网格、今日/选中/范围高亮、时间选择行;emit pick
│ │ ├── date-picker.vue # [NEW] 单个日期时间选择:类 Input 触发器 + Popover + calendar-panel;支持 format/valueFormat/clearable/disabled/showTime;v-model 为 Date 或字符串
│ │ ├── range-picker.vue # [NEW] 范围选择:start/end/hoverValue 管理,第一次点设 start、第二次设 end 并关闭;modelValue 为 [start,end]
│ │ └── index.scss # [NEW] 样式,沿用主题变量,选择器前缀 .fms-date-picker/.fms-range-picker/.fms-calendar-panel
│ └── popover/
│ └── popover.vue # [REUSE] 无需改动,直接复用
```
## 关键代码结构(接口约定)
```js
// date-utils.js 核心导出(接口级,非实现体)
export function format(date, fmt = 'YYYY-MM-DD HH:mm:ss')
export function parse(str, fmt = 'YYYY-MM-DD HH:mm:ss')
export function getMonthMatrix(year, month) // 返回 6×7 日期元信息数组
export function isSameDay(a, b)
export function isInRange(date, start, end)
```
DatePicker props(要点):
- `modelValue: Date | string`
- `format: string | string[]`(默认 'YYYY-MM-DD HH:mm:ss')
- `valueFormat: string`(设置后 modelValue 可为字符串)
- `showTime: boolean`
- `clearable: boolean`、`disabled: boolean`、`placeholder: string`
RangePicker props(要点):
- `modelValue: [Date|string, Date|string]`
- 其余同 DatePicker(无单值 showTime 独立开关,范围自带时间行)
## 设计风格
沿用现有 fms-vue 组件库视觉语言(与 Select/Input/Message 一致),采用简洁、规整的企业级表单控件风格。整体使用现有主题 CSS 变量,支持暗色与主题切换。
## 页面/组件设计
### DatePicker 触发器
- 顶部:类 Input 只读输入框,左侧日历图标,右侧清除/下拉箭头,聚焦与打开态有边框高亮。
- 底部无(弹层内处理)。
### 弹出面板(CalendarPanel)
- 顶部区块:左箭头 + 当前「YYYY 年 MM 月」+ 右箭头,居中布局,hover 箭头有背景反馈。
- 中部区块:星期表头(日一二三四五六),6×7 日期网格;今日有圆点/描边,选中日期实心高亮,范围区间内浅色填充,hover 预览区间浅色。
- 底部区块(showTime):时/分/秒三列数字步进器或滚动选择,确认/此刻快捷。
- 动画:面板随 Popover 的 `popover` transition 淡入下移出现。
### RangePicker 触发器
- 两个输入框段(开始 ~ 结束),中间分隔波浪号,其余同 DatePicker。
## Agent Extensions
### Skill
- **ui-ux-pro-max**
- Purpose: 设计 DatePicker/RangePicker 及日历面板的视觉风格、间距、交互细节与暗色适配,确保与现有组件库视觉一致且美观。
- Expected outcome: 产出日历面板网格、触发器、时间选择行的布局与样式规范,融入现有主题体系。
### SubAgent
- **code-explorer**
- Purpose: 在实现前进一步确认 popover.vue、select.vue、input.vue、tokens.css 的具体类名与 SCSS 变量,避免样式冲突或重复定义。
- Expected outcome: 提供可复用的 CSS 变量名与 BEM 类名清单,供 index.scss 直接使用。