---
title: 开发文档
order: 3
category: pro
---

# PisellDateTimeDisplay 组件开发文档

## 组件信息

**组件名称**：PisellDateTimeDisplay

**组件版本**：1.0.0

**组件分类**：Pro Components / Data Display

**开发状态**：开发中

**最后更新**：2026-01-29

---

## 组件描述

PisellDateTimeDisplay 是 Pisell 2.0 组件库中专注于展示**当前时间**的组件，用于在不同终端（PC / Mobile /
Kiosk）和不同语言环境下，统一展示当前日期、时间与星期信息。

**核心价值**：

- 统一产品内所有「当前时间」的展示规范
- 避免业务自行拼接日期 / 星期字符串
- 天然支持多语言、12 / 24 小时制
- 自动随系统时间刷新
- 作为 Time 类 Plus 组件的稳定基础能力

**适用场景**：

- 后台首页当前时间
- 门店当前时间
- 欢迎页/状态页
- 大屏实时显示时间
- 当前系统时间提示

---

## 组件需求点罗列

### 功能需求

1. **核心时间展示**
  - ✅ 当前日期（Date）展示
  - ✅ 当前时间（Time）展示
  - ✅ 当前星期（Weekday）展示
  - ✅ 自动随系统时间刷新
  - ✅ 使用客户端本地时区

2. **布局样式**
  - ✅ 默认样式（两行布局：时间在上，日期+星期在下）
  - ✅ 单行样式（所有信息横向排列，用分隔符连接）
  - ✅ 竖向样式（三行布局：时间、日期、星期分别独立成行）

3. **时间格式配置**
  - ✅ 12/24小时制切换
  - ✅ 是否显示秒
  - ✅ 小时是否补零
  - ✅ 只显示小时

4. **日期格式配置**
  - ✅ 年月日顺序：Y-M-D、M-D-Y、D-M-Y
  - ✅ 英文月份简写/完整（Mar / March）
  - ✅ 英文月份数字展示（03）
  - ✅ 中文显示"年、月、日"汉字
  - ✅ 自定义分隔符（如 "-"、"/"）
  - ✅ 年月日字段显隐控制
  - ✅ 完整展示模式

5. **星期格式配置**
  - ✅ 默认展示（Sat / 周六）
  - ✅ 完整展示（Saturday / 星期六）
  - ✅ 单字母展示（S / 六）

6. **刷新机制**
  - ✅ 默认 60 秒刷新一次
  - ✅ 显示秒时 1 秒刷新一次
  - ✅ 组件卸载时清除定时器

7. **国际化支持**
  - ✅ 使用 dayjs 的 locale 功能
  - ✅ 月份名称自动翻译
  - ✅ 星期名称自动翻译
  - ✅ 跟随系统语言切换

8. **字段控制**
  - ✅ 可显隐时间、日期、星期字段
  - ✅ 可排序时间、日期、星期字段
  - ✅ 至少显示一个字段

9. **自定义格式化**
  - ✅ 支持自定义格式化字符串（类似 dayjs().format('YYYY-MM-DD HH:mm:ss')）
  - ✅ 优先级高于其他配置项

10. **样式自定义**
  - ✅ 整体区域样式（背景、圆角、边框、阴影、padding、gap）
  - ✅ 文本样式（大小、粗细、颜色、显示行数、宽度）
  - ✅ 对齐方式（左对齐、居中、右对齐）
  - ✅ 主题支持（浅色/深色模式）

---

## 组件 API

### Props 接口定义

```
import type { CSSProperties, ReactNode } from 'react';
import type { Dayjs } from 'dayjs';

/**
 * 布局方向
 */
export type LayoutDirection = 'horizontal' | 'vertical' | 'inline';

/**
 * 日期顺序
 */
export type DateOrder = 'YMD' | 'MDY' | 'DMY';

/**
 * 对齐方式
 */
export type TextAlign = 'left' | 'center' | 'right';

/**
 * 字段类型
 */
export type FieldType = 'time' | 'date' | 'weekday';

/**
 * 时间格式配置
 */
export interface TimeFormatConfig {
  /** 是否使用12小时制，默认 false */
  use12Hour?: boolean;
  /** 是否显示秒，默认 false */
  showSeconds?: boolean;
  /** 小时是否补零，默认 false */
  padHour?: boolean;
  /** 是否只显示小时，默认 false */
  onlyShowHour?: boolean;
}

/**
 * 日期格式配置
 */
export interface DateFormatConfig {
  /** 日期顺序，默认 'YMD' */
  order?: DateOrder;
  /** 英文月份是否简写，默认 true */
  shortMonth?: boolean;
  /** 英文月份是否数字展示，默认 false */
  numericMonth?: boolean;
  /** 中文是否显示"年月日"汉字，默认 false */
  showChineseUnit?: boolean;
  /** 分隔符，默认 '-' */
  separator?: string;
  /** 是否显示年，默认 false */
  showYear?: boolean;
  /** 是否显示月，默认 true */
  showMonth?: boolean;
  /** 是否显示日，默认 true */
  showDay?: boolean;
}

/**
 * 星期格式配置
 */
export interface WeekdayFormatConfig {
  /** 是否完整展示，默认 false */
  full?: boolean;
  /** 是否单字母展示，默认 false */
  singleLetter?: boolean;
}

/**
 * 字段配置
 */
export interface FieldConfig {
  /** 是否显示时间字段，默认 true */
  showTime?: boolean;
  /** 是否显示日期字段，默认 true */
  showDate?: boolean;
  /** 是否显示星期字段，默认 true */
  showWeekday?: boolean;
  /** 字段顺序，默认 ['time', 'date', 'weekday'] */
  fieldOrder?: FieldType[];
}

/**
 * 文本样式配置
 */
export interface TextStyleConfig {
  /** 字体大小 */
  fontSize?: number | string;
  /** 字体粗细 */
  fontWeight?: number | string;
  /** 字体颜色 */
  color?: string;
  /** 行高 */
  lineHeight?: number | string;
}

/**
 * 容器样式配置
 */
export interface ContainerStyleConfig {
  /** 背景色 */
  background?: string;
  /** 圆角 */
  borderRadius?: number | string;
  /** 边框 */
  border?: string;
  /** 阴影 */
  boxShadow?: string;
  /** 内边距 */
  padding?: number | string;
  /** 间距 */
  gap?: number | string;
}

/**
 * PisellDateTimeDisplay 组件 Props
 */
export interface PisellDateTimeDisplayProps {
  // ========== 布局配置 ==========
  
  /** 布局方向，默认 'horizontal' */
  layout?: LayoutDirection;
  
  /** 文本对齐方式，默认 'left' */
  textAlign?: TextAlign;
  
  // ========== 字段配置 ==========
  
  /** 字段显示配置 */
  fields?: FieldConfig;
  
  // ========== 格式化配置 ==========
  
  /** 时间格式配置 */
  timeFormat?: TimeFormatConfig;
  
  /** 日期格式配置 */
  dateFormat?: DateFormatConfig;
  
  /** 星期格式配置 */
  weekdayFormat?: WeekdayFormatConfig;
  
  /** 自定义格式化字符串（优先级最高，类似 dayjs().format()） */
  customFormat?: string;
  
  /** 单行模式分隔符，默认 ' · ' */
  inlineSeparator?: string;
  
  // ========== 样式配置 ==========
  
  /** 容器样式 */
  containerStyle?: ContainerStyleConfig;
  
  /** 时间文本样式 */
  timeStyle?: TextStyleConfig;
  
  /** 日期文本样式 */
  dateStyle?: TextStyleConfig;
  
  /** 星期文本样式 */
  weekdayStyle?: TextStyleConfig;
  
  // ========== 刷新配置 ==========
  
  /** 自定义刷新间隔（毫秒），不设置则根据 showSeconds 自动判断 */
  refreshInterval?: number;
  
  /** 是否禁用自动刷新，默认 false */
  disableAutoRefresh?: boolean;
  
  // ========== 国际化配置 ==========
  
  /** dayjs locale，默认使用系统语言 */
  locale?: string;
  
  // ========== 通用样式 ==========
  
  /** 自定义类名 */
  className?: string;
  
  /** 自定义样式 */
  style?: CSSProperties;
  
  // ========== 事件回调 ==========
  
  /** 时间更新回调 */
  onTimeUpdate?: (currentTime: Dayjs) => void;
  
  /** 点击回调 */
  onClick?: () => void;
}
```

### 默认值说明

```
{
  layout: 'horizontal',
  textAlign: 'left',
  
  fields: {
    showTime: true,
    showDate: true,
    showWeekday: true,
    fieldOrder: ['time', 'date', 'weekday']
  },
  
  timeFormat: {
    use12Hour: false,
    showSeconds: false,
    padHour: false,
    onlyShowHour: false
  },
  
  dateFormat: {
    order: 'YMD',
    shortMonth: true,
    numericMonth: false,
    showChineseUnit: false,
    separator: '-',
    showYear: false,
    showMonth: true,
    showDay: true
  },
  
  weekdayFormat: {
    full: false,
    singleLetter: false
  },
  
  inlineSeparator: ' · ',
  disableAutoRefresh: false,
  
  // refreshInterval 自动计算：
  // - showSeconds=true 时为 1000 (1秒)
  // - showSeconds=false 时为 60000 (60秒)
}
```

---

## 组件模块拆解

### 文件结构

```
pisellDateTimeDisplay/
├── index.tsx                                    # 对外导出入口
├── PisellDateTimeDisplay.tsx                    # 主组件
├── PisellDateTimeDisplay.less                   # 组件样式
├── PisellDateTimeDisplay.test.tsx               # 单元测试
├── types.ts                                     # TypeScript 类型定义
│
├── components/                                  # 子组件目录
│   ├── index.tsx                               # 子组件导出
│   ├── TimeDisplay.tsx                         # 时间展示组件
│   ├── DateDisplay.tsx                         # 日期展示组件
│   └── WeekdayDisplay.tsx                      # 星期展示组件
│
├── utils/                                       # 工具函数目录
│   ├── index.ts                                # 工具函数导出
│   ├── formatTime.ts                           # 时间格式化
│   ├── formatDate.ts                           # 日期格式化
│   ├── formatWeekday.ts                        # 星期格式化
│   └── getRefreshInterval.ts                   # 计算刷新间隔
│
├── hooks/                                       # 自定义 Hooks 目录
│   ├── index.ts                                # Hooks 导出
│   └── useCurrentTime.ts                       # 当前时间状态管理
│
└── docs/                                        # 文档目录
    ├── pisellDateTimeDisplay.md                # 使用文档
    ├── pisellDateTimeDisplay.$tab-design.md    # 设计文档
    ├── pisellDateTimeDisplay.$tab-dev.md       # 开发文档（本文件）
    └── pisellDateTimeDisplay.$tab-test.md      # 测试文档
```

### 核心模块说明

#### 1. 主组件（PisellDateTimeDisplay.tsx）

**职责**：

- 管理当前时间状态（使用 useCurrentTime hook）
- 根据配置决定显示哪些字段
- 组装子组件并应用布局
- 处理样式配置
- 设置自动刷新定时器

**伪代码**：

```
PisellDateTimeDisplay = (props) => {
  const {
    layout = 'horizontal',
    textAlign = 'left',
    fields = {},
    timeFormat = {},
    dateFormat = {},
    weekdayFormat = {},
    customFormat,
    inlineSeparator = ' · ',
    refreshInterval,
    disableAutoRefresh = false,
    locale,
    containerStyle = {},
    timeStyle = {},
    dateStyle = {},
    weekdayStyle = {},
    onTimeUpdate,
    onClick,
    className,
    style,
  } = props;
  
  // 使用自定义 hook 管理当前时间
  const currentTime = useCurrentTime({
    refreshInterval: refreshInterval ?? getRefreshInterval(timeFormat),
    disabled: disableAutoRefresh,
    locale,
    onUpdate: onTimeUpdate,
  });
  
  // 如果有自定义格式化，直接使用
  if (customFormat) {
    return (
      <div 
        className={`pisell-datetime-display ${className || ''}`}
        style={{ ...containerStyle, ...style }}
        onClick={onClick}
      >
        <span style={{ textAlign }}>
          {currentTime.format(customFormat)}
        </span>
      </div>
    );
  }
  
  // 获取字段配置
  const {
    showTime = true,
    showDate = true,
    showWeekday = true,
    fieldOrder = ['time', 'date', 'weekday']
  } = fields;
  
  // 根据 fieldOrder 渲染字段
  const renderField = (fieldType: FieldType) => {
    switch (fieldType) {
      case 'time':
        return showTime && (
          <TimeDisplay 
            time={currentTime}
            format={timeFormat}
            style={timeStyle}
          />
        );
      case 'date':
        return showDate && (
          <DateDisplay 
            date={currentTime}
            format={dateFormat}
            style={dateStyle}
          />
        );
      case 'weekday':
        return showWeekday && (
          <WeekdayDisplay 
            weekday={currentTime}
            format={weekdayFormat}
            style={weekdayStyle}
          />
        );
    }
  };
  
  // 单行布局
  if (layout === 'inline') {
    const fields = fieldOrder
      .map(renderField)
      .filter(Boolean)
      .join(inlineSeparator);
    
    return (
      <div 
        className="pisell-datetime-display pisell-datetime-display-inline"
        style={{ ...containerStyle, textAlign, ...style }}
        onClick={onClick}
      >
        {fields}
      </div>
    );
  }
  
  // 水平或垂直布局
  return (
    <div 
      className={`pisell-datetime-display pisell-datetime-display-${layout}`}
      style={{ ...containerStyle, textAlign, ...style }}
      onClick={onClick}
    >
      {fieldOrder.map(renderField).filter(Boolean)}
    </div>
  );
};
```

#### 2. 时间展示组件（TimeDisplay.tsx）

**职责**：

- 格式化并展示时间
- 支持 12/24 小时制
- 支持显示秒
- 支持小时补零

**关键逻辑**：

```
import { formatTime } from '../utils/formatTime';

TimeDisplay = ({ time, format, style }) => {
  const {
    use12Hour = false,
    showSeconds = false,
    padHour = false,
    onlyShowHour = false,
  } = format || {};
  
  // 格式化时间
  const formattedTime = formatTime(time, {
    use12Hour,
    showSeconds,
    padHour,
    onlyShowHour,
  });
  
  return (
    <span 
      className="pisell-datetime-display-time"
      style={style}
    >
      {formattedTime}
    </span>
  );
};
```

#### 3. 日期展示组件（DateDisplay.tsx）

**职责**：

- 格式化并展示日期
- 支持不同的日期顺序
- 支持年月日字段显隐
- 支持中文单位

**关键逻辑**：

```
import { formatDate } from '../utils/formatDate';

DateDisplay = ({ date, format, style }) => {
  const {
    order = 'YMD',
    shortMonth = true,
    numericMonth = false,
    showChineseUnit = false,
    separator = '-',
    showYear = false,
    showMonth = true,
    showDay = true,
  } = format || {};
  
  // 格式化日期
  const formattedDate = formatDate(date, {
    order,
    shortMonth,
    numericMonth,
    showChineseUnit,
    separator,
    showYear,
    showMonth,
    showDay,
  });
  
  return (
    <span 
      className="pisell-datetime-display-date"
      style={style}
    >
      {formattedDate}
    </span>
  );
};
```

#### 4. 星期展示组件（WeekdayDisplay.tsx）

**职责**：

- 格式化并展示星期
- 支持完整/缩写/单字母模式

**关键逻辑**：

```
import { formatWeekday } from '../utils/formatWeekday';

WeekdayDisplay = ({ weekday, format, style }) => {
  const {
    full = false,
    singleLetter = false,
  } = format || {};
  
  // 格式化星期
  const formattedWeekday = formatWeekday(weekday, {
    full,
    singleLetter,
  });
  
  return (
    <span 
      className="pisell-datetime-display-weekday"
      style={style}
    >
      {formattedWeekday}
    </span>
  );
};
```

#### 5. 自定义 Hook（useCurrentTime.ts）

**职责**：

- 管理当前时间状态
- 设置定时器自动刷新
- 组件卸载时清除定时器
- 支持 locale 配置

**关键逻辑**：

```
import { useState, useEffect } from 'react';
import dayjs, { Dayjs } from 'dayjs';

interface UseCurrentTimeOptions {
  refreshInterval?: number;
  disabled?: boolean;
  locale?: string;
  onUpdate?: (time: Dayjs) => void;
}

export function useCurrentTime(options: UseCurrentTimeOptions): Dayjs {
  const {
    refreshInterval = 60000,
    disabled = false,
    locale,
    onUpdate,
  } = options;
  
  // 初始化时间
  const [currentTime, setCurrentTime] = useState(() => {
    const time = dayjs();
    return locale ? time.locale(locale) : time;
  });
  
  useEffect(() => {
    // 如果禁用自动刷新，只设置一次
    if (disabled) {
      return;
    }
    
    // 设置定时器
    const timer = setInterval(() => {
      const time = dayjs();
      const localizedTime = locale ? time.locale(locale) : time;
      setCurrentTime(localizedTime);
      onUpdate?.(localizedTime);
    }, refreshInterval);
    
    // 清除定时器
    return () => {
      clearInterval(timer);
    };
  }, [refreshInterval, disabled, locale, onUpdate]);
  
  return currentTime;
}
```

#### 6. 工具函数

**formatTime.ts**：

```
import type { Dayjs } from 'dayjs';

interface TimeFormatOptions {
  use12Hour: boolean;
  showSeconds: boolean;
  padHour: boolean;
  onlyShowHour: boolean;
}

/**
 * 格式化时间
 */
export function formatTime(time: Dayjs, options: TimeFormatOptions): string {
  const { use12Hour, showSeconds, padHour, onlyShowHour } = options;
  
  // 只显示小时
  if (onlyShowHour) {
    return padHour ? time.format('HH') : time.format('H');
  }
  
  // 12小时制
  if (use12Hour) {
    const hourFormat = padHour ? 'hh' : 'h';
    const timeFormat = showSeconds 
      ? `${hourFormat}:mm:ss A` 
      : `${hourFormat}:mm A`;
    return time.format(timeFormat);
  }
  
  // 24小时制
  const hourFormat = padHour ? 'HH' : 'H';
  const timeFormat = showSeconds 
    ? `${hourFormat}:mm:ss` 
    : `${hourFormat}:mm`;
  return time.format(timeFormat);
}
```

**formatDate.ts**：

```
import type { Dayjs } from 'dayjs';

interface DateFormatOptions {
  order: 'YMD' | 'MDY' | 'DMY';
  shortMonth: boolean;
  numericMonth: boolean;
  showChineseUnit: boolean;
  separator: string;
  showYear: boolean;
  showMonth: boolean;
  showDay: boolean;
}

/**
 * 格式化日期
 */
export function formatDate(date: Dayjs, options: DateFormatOptions): string {
  const {
    order,
    shortMonth,
    numericMonth,
    showChineseUnit,
    separator,
    showYear,
    showMonth,
    showDay,
  } = options;
  
  // 判断语言（中文需要特殊处理）
  const isChinese = date.locale() === 'zh-cn' || date.locale() === 'zh';
  
  // 构建格式化字符串
  const parts: string[] = [];
  
  // 年
  const yearFormat = isChinese && showChineseUnit ? 'YYYY年' : 'YYYY';
  
  // 月
  let monthFormat = '';
  if (numericMonth) {
    monthFormat = isChinese && showChineseUnit ? 'MM月' : 'MM';
  } else {
    monthFormat = shortMonth ? 'MMM' : 'MMMM';
    if (isChinese && showChineseUnit) {
      monthFormat = 'M月';
    }
  }
  
  // 日
  const dayFormat = isChinese && showChineseUnit ? 'DD日' : 'DD';
  
  // 根据顺序组装
  switch (order) {
    case 'YMD':
      if (showYear) parts.push(yearFormat);
      if (showMonth) parts.push(monthFormat);
      if (showDay) parts.push(dayFormat);
      break;
    case 'MDY':
      if (showMonth) parts.push(monthFormat);
      if (showDay) parts.push(dayFormat);
      if (showYear) parts.push(yearFormat);
      break;
    case 'DMY':
      if (showDay) parts.push(dayFormat);
      if (showMonth) parts.push(monthFormat);
      if (showYear) parts.push(yearFormat);
      break;
  }
  
  // 中文且有单位时，不使用分隔符
  if (isChinese && showChineseUnit) {
    return date.format(parts.join(''));
  }
  
  // 其他情况使用分隔符
  return date.format(parts.join(separator));
}
```

**formatWeekday.ts**：

```
import type { Dayjs } from 'dayjs';

interface WeekdayFormatOptions {
  full: boolean;
  singleLetter: boolean;
}

/**
 * 格式化星期
 */
export function formatWeekday(weekday: Dayjs, options: WeekdayFormatOptions): string {
  const { full, singleLetter } = options;
  
  // 单字母
  if (singleLetter) {
    const isChinese = weekday.locale() === 'zh-cn' || weekday.locale() === 'zh';
    if (isChinese) {
      // 中文：一、二、三、四、五、六、日
      const weekdayMap = ['日', '一', '二', '三', '四', '五', '六'];
      return weekdayMap[weekday.day()];
    } else {
      // 英文：S, M, T, W, T, F, S
      return weekday.format('dd').charAt(0);
    }
  }
  
  // 完整
  if (full) {
    const isChinese = weekday.locale() === 'zh-cn' || weekday.locale() === 'zh';
    if (isChinese) {
      return weekday.format('dddd'); // 星期一
    } else {
      return weekday.format('dddd'); // Monday
    }
  }
  
  // 默认（缩写）
  const isChinese = weekday.locale() === 'zh-cn' || weekday.locale() === 'zh';
  if (isChinese) {
    return weekday.format('ddd'); // 周一
  } else {
    return weekday.format('ddd'); // Mon
  }
}
```

**getRefreshInterval.ts**：

```
import type { TimeFormatConfig } from '../types';

/**
 * 根据时间格式配置计算刷新间隔
 */
export function getRefreshInterval(timeFormat?: TimeFormatConfig): number {
  const showSeconds = timeFormat?.showSeconds ?? false;
  
  // 显示秒时 1 秒刷新
  if (showSeconds) {
    return 1000;
  }
  
  // 否则 60 秒刷新
  return 60000;
}
```

---

## 组件实现方案

### 技术选型

**基础依赖**：

- React 18+
- dayjs（日期时间处理和国际化）
- dayjs/locale/*（多语言支持）

**样式方案**：

- Less 预处理器
- CSS Variables（动态样式）
- BEM 命名规范

### 实现步骤

#### 第一步：定义类型（types.ts）

参考"组件 API"部分的完整类型定义。

#### 第二步：实现工具函数

已在"核心模块说明"部分详细说明。

#### 第三步：实现自定义 Hook

已在"核心模块说明"部分详细说明。

#### 第四步：实现子组件

已在"核心模块说明"部分详细说明。

#### 第五步：实现主组件

已在"核心模块说明"部分详细说明。

#### 第六步：编写样式

**PisellDateTimeDisplay.less**：

```
.pisell-datetime-display {
  display: flex;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  
  // 水平布局（默认）
  &-horizontal {
    flex-direction: column;
    gap: 4px;
    
    .pisell-datetime-display-time {
      font-size: 24px;
      font-weight: 600;
      line-height: 1.2;
    }
    
    .pisell-datetime-display-date,
    .pisell-datetime-display-weekday {
      font-size: 18px;
      font-weight: 400;
      line-height: 1.2;
    }
  }
  
  // 垂直布局
  &-vertical {
    flex-direction: column;
    gap: 8px;
    
    .pisell-datetime-display-time,
    .pisell-datetime-display-date,
    .pisell-datetime-display-weekday {
      font-size: 18px;
      font-weight: 400;
      line-height: 1.2;
    }
  }
  
  // 单行布局
  &-inline {
    flex-direction: row;
    align-items: center;
    gap: 0;
    
    font-size: 20px;
    font-weight: 400;
    line-height: 1.2;
  }
  
  // 时间
  &-time {
    display: inline-block;
  }
  
  // 日期
  &-date {
    display: inline-block;
  }
  
  // 星期
  &-weekday {
    display: inline-block;
  }
}

// 深色模式支持
@media (prefers-color-scheme: dark) {
  .pisell-datetime-display {
    color: rgba(255, 255, 255, 0.85);
  }
}
```

#### 第七步：导出组件

**index.tsx**：

```
export { default as PisellDateTimeDisplay } from './PisellDateTimeDisplay';
export type {
  PisellDateTimeDisplayProps,
  LayoutDirection,
  DateOrder,
  TextAlign,
  FieldType,
  TimeFormatConfig,
  DateFormatConfig,
  WeekdayFormatConfig,
  FieldConfig,
  TextStyleConfig,
  ContainerStyleConfig,
} from './types';
```

---

## 组件组成与引用关系

### 组件结构图

```
┌────────────────────────────────────────────┐
│   PisellDateTimeDisplay (主组件)           │
│  - 状态管理 (useCurrentTime)              │
│  - 布局控制                                │
│  - 样式配置                                │
│  - 字段排序                                │
└───────────┬────────────────────────────────┘
            │
            ├──> useCurrentTime (自定义 Hook)
            │    - useState (当前时间)
            │    - useEffect (定时器)
            │    - dayjs (时间处理)
            │    - locale (国际化)
            │
            ├──> TimeDisplay (时间展示组件)
            │    - formatTime (时间格式化)
            │    - dayjs.format()
            │
            ├──> DateDisplay (日期展示组件)
            │    - formatDate (日期格式化)
            │    - dayjs.format()
            │
            └──> WeekdayDisplay (星期展示组件)
                 - formatWeekday (星期格式化)
                 - dayjs.format()
```

### 依赖关系

**外部依赖**：

- React 18+ (核心框架)
- dayjs (日期时间处理)
- dayjs/locale/* (多语言支持)

**内部依赖**：

- types.ts → 类型定义
- utils/* → 格式化工具函数
- hooks/useCurrentTime.ts → 时间状态管理
- components/* → 子组件

### 可复用部分

**可被其他组件复用的部分**：

1. `useCurrentTime` - 当前时间状态管理（可用于其他时间类组件）
2. `formatTime` - 时间格式化工具（可独立使用）
3. `formatDate` - 日期格式化工具（可独立使用）
4. `formatWeekday` - 星期格式化工具（可独立使用）
5. `getRefreshInterval` - 刷新间隔计算（可独立使用）

---

## 扩展性设计

### 可扩展点

1. **自定义格式化**：
  - 通过 `customFormat` 属性支持任意 dayjs 格式化字符串
  - 优先级高于其他配置项

2. **插槽支持**：
  - 未来可以添加 `renderTime`、`renderDate`、`renderWeekday` 插槽
  - 支持完全自定义渲染逻辑

3. **时区支持**：
  - 未来可以添加 `timezone` 属性
  - 使用 dayjs-timezone 插件实现

4. **相对时间**：
  - 未来可以添加 `relative` 模式
  - 显示"x 分钟前"等相对时间

5. **时间范围**：
  - 未来可以支持时间范围展示
  - 如"开始时间 - 结束时间"

---

## 开发注意事项

### 1. 类型安全

- 严格使用 TypeScript
- 为所有 Props 提供明确的类型定义
- 导出所有公共类型

### 2. 性能优化

- 主组件使用 React.memo
- 格式化函数使用 useMemo 缓存
- 定时器正确清理，避免内存泄漏

### 3. 国际化

- 使用 dayjs 的 locale 功能
- 中文和英文格式差异需要特殊处理
- 月份、星期名称自动翻译

### 4. 刷新机制

- 显示秒时 1 秒刷新，否则 60 秒刷新
- 组件卸载时必须清除定时器
- 支持禁用自动刷新

### 5. 样式一致性

- 遵循设计规范中的颜色、字号、间距
- 支持浅色/深色主题
- 样式完全可自定义

### 6. 可访问性

- 提供语义化的 HTML 结构
- 考虑屏幕阅读器支持

### 7. 测试覆盖

- 单元测试覆盖核心逻辑
- 测试各种格式配置组合
- 测试定时器清理

### 8. 代码规范

- 遵循项目 ESLint 规则
- 使用 Prettier 格式化代码
- 添加 JSDoc 注释

---

## 开发时间评估

| 任务       | 预计时间    | 备注                                           |
|----------|---------|----------------------------------------------|
| 类型定义     | 1h      | 定义完整的 Props 接口                               |
| 工具函数     | 2h      | formatTime/Date/Weekday + getRefreshInterval |
| 自定义 Hook | 1.5h    | useCurrentTime + 定时器管理                       |
| 子组件开发    | 2h      | TimeDisplay/DateDisplay/WeekdayDisplay       |
| 主组件开发    | 1.5h    | 组装子组件 + 布局控制                                 |
| 样式编写     | 1h      | Less 样式 + 主题支持                               |
| 单元测试     | 2h      | 覆盖核心逻辑 + 定时器测试                               |
| 文档完善     | 1h      | 使用文档                                         |
| **总计**   | **12h** | **约 1.5 个工作日**                               |

---

## 中文默认展示参考

根据 Figma 设计稿，中文环境下的默认展示格式：

```
// 默认样式（两行布局）
13:45
3月21日 周六

// 单行样式
2026年3月21日 周六 14:30

// 竖向样式
13:45
2026年3月21日
周六
```

对应配置：

```
// 默认样式
{
  layout: 'horizontal',
  dateFormat: {
    showYear: false,
    showMonth: true,
    showDay: true,
    showChineseUnit: true,
  },
  weekdayFormat: {
    full: false,
    singleLetter: false,
  }
}

// 单行样式
{
  layout: 'inline',
  dateFormat: {
    showYear: true,
    showMonth: true,
    showDay: true,
    showChineseUnit: true,
  },
  weekdayFormat: {
    full: false,
  },
  inlineSeparator: ' '
}

// 竖向样式
{
  layout: 'vertical',
  dateFormat: {
    showYear: true,
    showMonth: true,
    showDay: true,
    showChineseUnit: true,
  },
  weekdayFormat: {
    full: false,
  }
}
```
