11 KiB
11 KiB
name, overview, design, todos
| name | overview | design | todos | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| date-picker-component | 在 fms-vue 组件库中新增 DatePicker(单日期,支持时间)与 RangePicker(日期范围,支持时间)两个组件,复用现有 Popover 作为弹层,使用 dayjs 处理格式化(format 展示格式、valueFormat 绑定值格式),沿用现有 SCSS 主题体系。暂不做快捷选项与 disabledDate。 |
|
|
用户需求
在 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),保证可单测、可复用。
关键技术决策
- 复用 Popover 而非自建浮层:Popover 已具备定位翻转、点击外部关闭、Esc 关闭、followTriggerWidth,且 Select 已验证此模式。自建会重复这些逻辑且易出 bug。
- date-utils.js 纯函数封装 dayjs:
format(date, fmt)、parse(str, fmt)、getMonthMatrix(year, month)、isSameDay、isSameMonth、addMonth、compareDate、isInRange等。Picker 只处理交互与状态,日期计算一律下沉,便于测试与扩展。 - format 多格式匹配:format 为数组时,解析/展示以第一个为准(参考 dayjs#format 与 @rc-component/picker 约定)。
format用于展示文本,valueFormat用于绑定值序列化。 - modelValue 类型:内部统一用原生
Date(或 dayjs 对象)做运算;对外通过valueFormat决定 v-model 是Date还是字符串。RangePicker 为[start, end](对应 Date 或字符串数组)。 - 范围 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、主题切换。
架构设计
组件关系
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] 无需改动,直接复用
关键代码结构(接口约定)
// 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 | stringformat: string | string[](默认 'YYYY-MM-DD HH:mm:ss')valueFormat: string(设置后 modelValue 可为字符串)showTime: booleanclearable: 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 的
popovertransition 淡入下移出现。
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 直接使用。