| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- import classNames from 'classnames'
- import dayjs from 'dayjs'
- import { useState, useEffect } from 'react'
- import './index.less'
- enum ModeType {
- LINE = 'line',
- CARD = 'card'
- }
- type TimeLineListProps<T> = {
- rowKey?: ((item: T) => React.Key) | keyof T
- dataSource: T[]
- renderItem?: (item: T, index: number) => React.ReactNode
- dataField: keyof T
- mode: 'line' | 'card'
- }
- function TimeLineList<T>({
- dataField = 'createTime',
- dataSource = [],
- mode = 'line',
- renderItem
- }: TimeLineListProps<T>) {
- // 用二维数组去存数据
- const [dataMap, setDataMap] = useState<Nullable<T[][]>>(null)
- useEffect(() => {
- const formatTimeMap = () => {
- // 先去重,按日期进行分组
- const uniKeys = Array.from(new Set(dataSource.map(item => item?.[dataField])))
- const uniDataMap = []
- // 构建二维数组
- uniKeys.forEach(key => {
- uniDataMap.push(dataSource.filter(item => item?.[dataField] === key))
- })
- setDataMap(uniDataMap)
- }
- dataSource?.length && formatTimeMap(dataSource)
- }, [dataSource])
- if (!dataMap) return null
- // 渲染左侧日期
- const renderDate = (dataIndex: number, diffTime: number, renderTime: dayjs.Dayjs) => {
- let node = null
- if (dataIndex === 0) {
- switch (diffTime) {
- case 0:
- node = '今天'
- break
- case 1:
- node = '昨天'
- break
- case 2:
- node = renderTime.format('MM-DD')
- break
- default:
- node = (
- <div
- className={classNames('flex flex-col justify-center', {
- 'items-center': mode === ModeType.LINE
- })}>
- <span className="year">{renderTime.get('year')}</span>
- <span className="date">{renderTime.format('MM-DD')}</span>
- </div>
- )
- break
- }
- }
- return node
- }
- // render mode timeline
- const renderTimelineItem = () => {
- return dataMap.map(t =>
- t.map((item, i) => {
- const itemTime = dayjs(item?.[dataField])
- const currentTime = dayjs()
- if (itemTime && currentTime) {
- const renderTime = currentTime.diff(itemTime, 'day')
- return (
- <div key={item.id} className="time-item-content time-item-has-line">
- <div className="time-item-label time-item-label-has-line">
- <div
- className={classNames(i > 0 ? 'time-item-label-square' : 'time-item-label-base', {
- 'time-item-label-forward': renderTime <= 2
- })}>
- {renderDate(i, renderTime, itemTime)}
- </div>
- </div>
- <div className="time-item-render time-item-render-has-line">{renderItem?.(item, i)}</div>
- </div>
- )
- }
- return null
- })
- )
- }
- // render mode card
- const renderCardItem = () => {
- return dataMap.map(t =>
- t.map((item, i) => {
- const itemTime = dayjs(item?.[dataField])
- const currentTime = dayjs()
- if (itemTime && currentTime) {
- const renderTime = currentTime.diff(itemTime, 'day')
- return (
- <div
- key={item.id}
- className={classNames('time-item-content time-item-has-card', {
- 'time-item-last': t.length - 1 === i
- })}>
- <div className="time-item-label time-item-label-has-card">
- <div
- className={classNames('time-item-label-base', {
- 'time-item-label-forward': renderTime <= 2
- })}>
- {renderDate(i, renderTime, itemTime)}
- </div>
- </div>
- <div className="time-item-render time-item-render-has-card">{renderItem?.(item, i)}</div>
- <div className={classNames({ 'time-item-label-tail': t.length - 1 === i })} />
- </div>
- )
- }
- return null
- })
- )
- }
- return (
- <div className="w-full h-full time-list-container">
- {mode === ModeType.LINE ? renderTimelineItem() : renderCardItem()}
- </div>
- )
- }
- export default TimeLineList
|