@fjyueke/arco-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +85 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +244 -0
  4. package/metaData/components/action-sheet/doc.md +102 -0
  5. package/metaData/components/action-sheet/example/index.tsx +199 -0
  6. package/metaData/components/action-sheet/example/methods.tsx +6 -0
  7. package/metaData/components/avatar/doc.md +57 -0
  8. package/metaData/components/avatar/example/group.tsx +69 -0
  9. package/metaData/components/avatar/example/index.tsx +196 -0
  10. package/metaData/components/badge/doc.md +28 -0
  11. package/metaData/components/badge/example/index.tsx +128 -0
  12. package/metaData/components/button/doc.md +45 -0
  13. package/metaData/components/button/example/index.tsx +264 -0
  14. package/metaData/components/carousel/doc.md +89 -0
  15. package/metaData/components/carousel/example/index.tsx +1481 -0
  16. package/metaData/components/cell/doc.md +68 -0
  17. package/metaData/components/cell/example/arrow.tsx +13 -0
  18. package/metaData/components/cell/example/cell.tsx +71 -0
  19. package/metaData/components/cell/example/group.tsx +63 -0
  20. package/metaData/components/cell/example/index.tsx +19 -0
  21. package/metaData/components/checkbox/doc.md +91 -0
  22. package/metaData/components/checkbox/example/checkbox.tsx +158 -0
  23. package/metaData/components/checkbox/example/group.tsx +103 -0
  24. package/metaData/components/checkbox/example/index.tsx +25 -0
  25. package/metaData/components/circle-progress/doc.md +40 -0
  26. package/metaData/components/circle-progress/example/index.tsx +323 -0
  27. package/metaData/components/collapse/doc.md +74 -0
  28. package/metaData/components/collapse/example/collapse.tsx +183 -0
  29. package/metaData/components/collapse/example/group.tsx +136 -0
  30. package/metaData/components/collapse/example/index.tsx +16 -0
  31. package/metaData/components/collapse/example/utils.tsx +20 -0
  32. package/metaData/components/context-provider/doc.md +44 -0
  33. package/metaData/components/context-provider/example/index.tsx +208 -0
  34. package/metaData/components/count-down/doc.md +40 -0
  35. package/metaData/components/count-down/example/hooks.tsx +118 -0
  36. package/metaData/components/count-down/example/index.tsx +63 -0
  37. package/metaData/components/date-picker/doc.md +102 -0
  38. package/metaData/components/date-picker/example/index.tsx +545 -0
  39. package/metaData/components/dialog/doc.md +200 -0
  40. package/metaData/components/dialog/example/index.tsx +328 -0
  41. package/metaData/components/dialog/example/methods.tsx +56 -0
  42. package/metaData/components/divider/doc.md +25 -0
  43. package/metaData/components/divider/example/index.tsx +87 -0
  44. package/metaData/components/dropdown/doc.md +80 -0
  45. package/metaData/components/dropdown/example/dropdown.tsx +308 -0
  46. package/metaData/components/dropdown/example/index.tsx +19 -0
  47. package/metaData/components/dropdown/example/options.tsx +103 -0
  48. package/metaData/components/dropdown-menu/doc.md +91 -0
  49. package/metaData/components/dropdown-menu/example/dropdown-menu.tsx +270 -0
  50. package/metaData/components/dropdown-menu/example/index.tsx +16 -0
  51. package/metaData/components/ellipsis/doc.md +33 -0
  52. package/metaData/components/ellipsis/example/index.tsx +93 -0
  53. package/metaData/components/ellipsis/example/js-ellipsis.tsx +229 -0
  54. package/metaData/components/ellipsis/example/native-ellipsis.tsx +48 -0
  55. package/metaData/components/form/doc.md +90 -0
  56. package/metaData/components/form/example/form-item-context.tsx +8 -0
  57. package/metaData/components/form/example/form-item.tsx +378 -0
  58. package/metaData/components/form/example/index.tsx +87 -0
  59. package/metaData/components/form/example/linked-container.tsx +66 -0
  60. package/metaData/components/grid/doc.md +39 -0
  61. package/metaData/components/grid/example/index.tsx +252 -0
  62. package/metaData/components/icon/doc.md +15 -0
  63. package/metaData/components/icon/example/index.tsx +32 -0
  64. package/metaData/components/image/doc.md +62 -0
  65. package/metaData/components/image/example/index.tsx +528 -0
  66. package/metaData/components/image-picker/doc.md +116 -0
  67. package/metaData/components/image-picker/example/add-icon.tsx +14 -0
  68. package/metaData/components/image-picker/example/index.tsx +175 -0
  69. package/metaData/components/image-preview/doc.md +119 -0
  70. package/metaData/components/image-preview/example/index.tsx +1290 -0
  71. package/metaData/components/image-preview/example/methods.tsx +72 -0
  72. package/metaData/components/index-bar/doc.md +83 -0
  73. package/metaData/components/index-bar/example/group.tsx +93 -0
  74. package/metaData/components/index-bar/example/index.tsx +271 -0
  75. package/metaData/components/index-bar/example/side-bar.tsx +82 -0
  76. package/metaData/components/input/doc.md +60 -0
  77. package/metaData/components/input/example/hooks.tsx +259 -0
  78. package/metaData/components/input/example/index.tsx +134 -0
  79. package/metaData/components/input/example/props.tsx +183 -0
  80. package/metaData/components/keyboard/doc.md +73 -0
  81. package/metaData/components/keyboard/example/index.tsx +238 -0
  82. package/metaData/components/load-more/doc.md +48 -0
  83. package/metaData/components/load-more/example/index.tsx +395 -0
  84. package/metaData/components/loading/doc.md +34 -0
  85. package/metaData/components/loading/example/index.tsx +312 -0
  86. package/metaData/components/masking/doc.md +93 -0
  87. package/metaData/components/masking/example/index.tsx +410 -0
  88. package/metaData/components/masking/example/methods.tsx +88 -0
  89. package/metaData/components/nav-bar/doc.md +40 -0
  90. package/metaData/components/nav-bar/example/back-icon.tsx +28 -0
  91. package/metaData/components/nav-bar/example/index.tsx +305 -0
  92. package/metaData/components/notice-bar/doc.md +34 -0
  93. package/metaData/components/notice-bar/example/index.tsx +294 -0
  94. package/metaData/components/notify/doc.md +81 -0
  95. package/metaData/components/notify/example/index.tsx +171 -0
  96. package/metaData/components/notify/example/methods.tsx +83 -0
  97. package/metaData/components/pagination/doc.md +41 -0
  98. package/metaData/components/pagination/example/arrow.tsx +14 -0
  99. package/metaData/components/pagination/example/index.tsx +292 -0
  100. package/metaData/components/picker/doc.md +89 -0
  101. package/metaData/components/picker/example/index.tsx +217 -0
  102. package/metaData/components/picker-view/doc.md +57 -0
  103. package/metaData/components/picker-view/example/cascader.tsx +141 -0
  104. package/metaData/components/picker-view/example/index.tsx +297 -0
  105. package/metaData/components/picker-view/example/multi-picker.tsx +66 -0
  106. package/metaData/components/picker-view/example/picker-cell.tsx +416 -0
  107. package/metaData/components/popover/doc.md +144 -0
  108. package/metaData/components/popover/example/index.tsx +23 -0
  109. package/metaData/components/popover/example/menu.tsx +145 -0
  110. package/metaData/components/popover/example/popover-inner.tsx +147 -0
  111. package/metaData/components/popover/example/popover.tsx +268 -0
  112. package/metaData/components/popup/doc.md +101 -0
  113. package/metaData/components/popup/example/index.tsx +125 -0
  114. package/metaData/components/popup/example/methods.tsx +6 -0
  115. package/metaData/components/popup-swiper/doc.md +108 -0
  116. package/metaData/components/popup-swiper/example/index.tsx +332 -0
  117. package/metaData/components/popup-swiper/example/methods.tsx +6 -0
  118. package/metaData/components/portal/doc.md +14 -0
  119. package/metaData/components/portal/example/index.tsx +35 -0
  120. package/metaData/components/progress/doc.md +42 -0
  121. package/metaData/components/progress/example/index.tsx +256 -0
  122. package/metaData/components/pull-refresh/doc.md +37 -0
  123. package/metaData/components/pull-refresh/example/android-pull-refresh.tsx +260 -0
  124. package/metaData/components/pull-refresh/example/index.tsx +44 -0
  125. package/metaData/components/pull-refresh/example/ios-pull-refresh.tsx +216 -0
  126. package/metaData/components/radio/doc.md +89 -0
  127. package/metaData/components/radio/example/group.tsx +92 -0
  128. package/metaData/components/radio/example/index.tsx +25 -0
  129. package/metaData/components/radio/example/radio.tsx +22 -0
  130. package/metaData/components/rate/doc.md +33 -0
  131. package/metaData/components/rate/example/index.tsx +281 -0
  132. package/metaData/components/search-bar/doc.md +97 -0
  133. package/metaData/components/search-bar/example/association.tsx +89 -0
  134. package/metaData/components/search-bar/example/cancel-button.tsx +34 -0
  135. package/metaData/components/search-bar/example/highlight.tsx +66 -0
  136. package/metaData/components/search-bar/example/index.tsx +251 -0
  137. package/metaData/components/show-monitor/doc.md +34 -0
  138. package/metaData/components/show-monitor/example/index.tsx +646 -0
  139. package/metaData/components/skeleton/doc.md +101 -0
  140. package/metaData/components/skeleton/example/elements.tsx +290 -0
  141. package/metaData/components/skeleton/example/index.tsx +96 -0
  142. package/metaData/components/skeleton/example/skeleton-context.tsx +7 -0
  143. package/metaData/components/slider/doc.md +42 -0
  144. package/metaData/components/slider/example/index.tsx +326 -0
  145. package/metaData/components/slider/example/marks.tsx +50 -0
  146. package/metaData/components/slider/example/popover.tsx +38 -0
  147. package/metaData/components/slider/example/thumb.tsx +48 -0
  148. package/metaData/components/slider/example/useSliderIcon.tsx +38 -0
  149. package/metaData/components/slider/example/useSliderInit.tsx +170 -0
  150. package/metaData/components/stepper/doc.md +46 -0
  151. package/metaData/components/stepper/example/index.tsx +166 -0
  152. package/metaData/components/stepper/example/useButtonClick.tsx +74 -0
  153. package/metaData/components/stepper/example/useInputEvent.tsx +65 -0
  154. package/metaData/components/stepper/example/useValue.tsx +43 -0
  155. package/metaData/components/steps/doc.md +57 -0
  156. package/metaData/components/steps/example/index.tsx +123 -0
  157. package/metaData/components/steps/example/step.tsx +126 -0
  158. package/metaData/components/sticky/doc.md +45 -0
  159. package/metaData/components/sticky/example/index.tsx +430 -0
  160. package/metaData/components/swipe-action/doc.md +44 -0
  161. package/metaData/components/swipe-action/example/index.tsx +338 -0
  162. package/metaData/components/swipe-action/example/item.tsx +40 -0
  163. package/metaData/components/swipe-load/doc.md +43 -0
  164. package/metaData/components/swipe-load/example/index.tsx +339 -0
  165. package/metaData/components/swipe-load/example/type.tsx +153 -0
  166. package/metaData/components/switch/doc.md +38 -0
  167. package/metaData/components/switch/example/index.tsx +237 -0
  168. package/metaData/components/tab-bar/doc.md +57 -0
  169. package/metaData/components/tab-bar/example/index.tsx +18 -0
  170. package/metaData/components/tab-bar/example/item.tsx +74 -0
  171. package/metaData/components/tab-bar/example/tab-bar.tsx +105 -0
  172. package/metaData/components/tabs/doc.md +187 -0
  173. package/metaData/components/tabs/example/index.tsx +514 -0
  174. package/metaData/components/tabs/example/tab-cell-underline.tsx +320 -0
  175. package/metaData/components/tabs/example/tab-cell.tsx +433 -0
  176. package/metaData/components/tabs/example/tab-pane.tsx +349 -0
  177. package/metaData/components/tag/doc.md +80 -0
  178. package/metaData/components/tag/example/index.tsx +23 -0
  179. package/metaData/components/tag/example/list.tsx +97 -0
  180. package/metaData/components/tag/example/tag.tsx +85 -0
  181. package/metaData/components/textarea/doc.md +67 -0
  182. package/metaData/components/textarea/example/index.tsx +258 -0
  183. package/metaData/components/toast/doc.md +90 -0
  184. package/metaData/components/toast/example/index.tsx +335 -0
  185. package/metaData/components/toast/example/methods.tsx +87 -0
  186. package/metaData/components/transition/doc.md +19 -0
  187. package/metaData/components/transition/example/index.tsx +113 -0
  188. package/metaData/components/uploader/doc.md +82 -0
  189. package/metaData/components/uploader/example/index.tsx +208 -0
  190. package/metaData/components-index.json +242 -0
  191. package/package.json +56 -0
@@ -0,0 +1,102 @@
1
+ ### 数据录入
2
+
3
+ # 日期时间选择器 DatePicker
4
+
5
+ 日期时间选择器,基于`Picker`组件扩展,支持指定范围,单位可精确到秒。
6
+
7
+ ======
8
+
9
+ > 属性/Props
10
+
11
+ |参数|描述|类型|默认值|
12
+ |----------|-------------|------|------|
13
+ |onOk|点击选中时执行的回调|(timestamp: number \| \[number, number\], obj: IDateObj \| \[IDateObj, IDateObj\]) =\> void|-|
14
+ |currentTs|当前选中的时间,timestamp|number \| \[number, number\]|Date.now()|
15
+ |onChange|选中后的回调|(timestamp: number \| \[number, number\], obj: IDateObj \| \[IDateObj, IDateObj\]) =\> void|-|
16
+ |onValueChange|每列数据选择变化后的回调函数|(timestamp: number, obj: IDateObj, index: number) =\> void|-|
17
+ |mode|可选列类型,date \- 年月日,time \- 时分秒,datetime \- 年月日时分秒|"date" \| "time" \| "datetime"|"datetime"|
18
+ |typeArr|可选列数组|ItemType\[\]|[]|
19
+ |minTs|最小可选日期,timestamp|number \| \{ startTs: number; endTs: number; \}|当前时间的前十年|
20
+ |maxTs|最大可选日期,timestamp|number \| \{ startTs: number; endTs: number; \}|当前时间的后十年|
21
+ |useUTC|是否使用 UTC 时间|boolean|false|
22
+ |rangeItemFormat|日期时间范围选择展示格式|string|-|
23
+ |formatter|各可选项展示的格式化方法,参数type为ItemTypes,参数value为当前行的值,返回展示的文字|(value: number, type: ItemType) =\> string|(value: number) => (value < 10 ? \`0${value}\` : String(value))|
24
+ |valueFilter|可选择行过滤方法,参数type为ItemType,参数value为当前行的值,返回true表示该行可选择|(type: ItemType, value: number) =\> boolean|() => true|
25
+ |columnsProcessor|选择器列表项干预,可插入自定义选项|(columns: PickerData\[\]\[\], currentDateObj: IDateObj) =\> PickerData\[\]\[\]|-|
26
+ |renderSeparator|自定义分隔符|() =\> ReactNode|-|
27
+ |renderLinkedContainer|将选择器的展现隐藏状态及选中值的展示与某个容器关联,传入后将同时渲染该容器和选择器组件,此时选择器组件的 visible 和 onHide 属性可不传,点击该容器会唤起选择器|(currentTs: number \| \[number, number\], itemTypes: ItemType\[\]) =\> ReactNode|-|
28
+ |visible|是否展示选择器|boolean|false|
29
+ |maskClosable|点击蒙层是否关闭菜单|boolean|false|
30
+ |needBottomOffset|从底部滑出的菜单内容是否适配ipx底部|boolean|false|
31
+ |translateZ|\[即将废弃\] 开启translateZ强制提升|boolean|false|
32
+ |maskTransitionTimeout|菜单蒙层动画时长|number \| \{ appear?: number; enter?: number; exit?: number; \}|{ enter: 450, exit: 240 }|
33
+ |contentTransitionTimeout|菜单内容动画时长|number \| \{ appear?: number; enter?: number; exit?: number; \}|{ enter: 450, exit: 240 }|
34
+ |contentTransitionType|内容过渡动画类名|string|\`slide-from-${props.direction}\`|
35
+ |className|自定义类名|string|-|
36
+ |maskClass|自定义蒙层类名|string|-|
37
+ |maskStyle|自定义蒙层样式|CSSProperties|-|
38
+ |contentClass|自定义内容类名|string|-|
39
+ |contentStyle|自定义内容样式|CSSProperties|-|
40
+ |maskTransitionType|蒙层过渡动画类名|string|"fade"|
41
+ |contentTransitionVarType|内容过渡动画类名变量标识|string|-|
42
+ |animatingClosable|执行进场动画时点击蒙层是否可关闭菜单|boolean|false|
43
+ |mountOnEnter|是否在打开菜单时再加载内容|boolean|true|
44
+ |unmountOnExit|是否在退出时卸载内容|boolean|true|
45
+ |preventBodyScroll|弹窗打开时是否禁止body的滚动|boolean|true|
46
+ |initialBodyOverflow|页面初始 overflow 状态,即关闭弹窗时 overflow 应该还原的状态|string|第一个全屏组件(弹窗、toast等)打开时页面overflow值|
47
+ |gestureOutOfControl|是否禁用滚动容器手势判断,禁用后交给业务方自己判断|boolean|true|
48
+ |onClose|关闭后回调(动画执行完毕)|(scene?: string) =\> void|-|
49
+ |onOpen|打开后回调(动画执行完毕)|() =\> void|-|
50
+ |onMaskClick|点击蒙层回调,maskClosable=false时也会触发|() =\> void|-|
51
+ |onTouchMove|弹窗的touchmove回调|(e: TouchEvent, prevented: boolean, direction: "x" \| "y") =\> void|-|
52
+ |onPreventTouchMove|非滚动区域或滚动到顶部及底部时的触摸事件回调|(e: TouchEvent, direction: "x" \| "y") =\> void|-|
53
+ |getContainer|获取挂载容器|() =\> HTMLElement|-|
54
+ |rows|行数(一列可选项的行数),必须是奇数,最小为3个|number|5|
55
+ |disabled|是否不可用|boolean|false|
56
+ |onHide|点击遮罩层或取消、确定按钮的隐藏回调|(scene?: string) =\> void|-|
57
+ |itemStyle|每列样式|CSSProperties|-|
58
+ |okText|弹窗确认已选值的文案|string|"确定"|
59
+ |dismissText|弹窗取消的文案|string|"取消"|
60
+ |onDismiss|点击取消时执行的回调|() =\> void|-|
61
+ |clickable|是否可通过点击操作选择内容|boolean|true|
62
+ |hideEmptyCols|是否隐藏无数据的空列,常用于级联选择|boolean|false|
63
+ |title|选择器标题|string|""|
64
+ |touchToStop|是否通过长按停止滑动,传入数字 x 表示触摸超过 x 毫秒算长按,传 true 表示 x=100,长按事件与 click 事件互斥|number \| boolean|false|
65
+ |renderExtraHeader|自定义头部扩展区域|() =\> ReactNode|-|
66
+
67
+ > 引用/Refs
68
+
69
+ |参数|描述|类型|
70
+ |----------|-------------|------|
71
+ |dom|最外层元素 DOM|HTMLDivElement|
72
+
73
+ > IDateObj
74
+
75
+ |参数|描述|类型|
76
+ |----------|-------------|------|
77
+ |year|年|number|
78
+ |month|月|number|
79
+ |date|日|number|
80
+ |hour|时|number|
81
+ |minute|分|number|
82
+ |second|秒|number|
83
+
84
+ > mode
85
+
86
+ ```
87
+ "date" | "time" | "datetime"
88
+ ```
89
+
90
+ > ItemType
91
+
92
+ ```
93
+ "date" | "year" | "month" | "hour" | "minute" | "second"
94
+ ```
95
+
96
+ > PickerData
97
+
98
+ |参数|描述|类型|
99
+ |----------|-------------|------|
100
+ |value|每一列展示的每项文案对应的值|ReactText|
101
+ |label|每一列展示的文案|ReactNode|
102
+ |children|级联状态下,该列对应的下一列数据|PickerData\[\]|
@@ -0,0 +1,545 @@
1
+ import React, {
2
+ useEffect,
3
+ useRef,
4
+ useState,
5
+ useMemo,
6
+ forwardRef,
7
+ Ref,
8
+ useImperativeHandle,
9
+ } from 'react';
10
+ import { cls, componentWrapper, formatDateNumber, isEmptyValue } from '@arco-design/mobile-utils';
11
+ import Picker, { PickerRef } from '../picker';
12
+ import { PickerData, ValueType } from '../picker-view';
13
+ import { ContextLayout } from '../context-provider';
14
+ import { convertTsToDateObj, oneOf, judgeObj, convertObjToTs } from './helper';
15
+ import { ItemType, IDateObj, DatePickerProps } from './type';
16
+
17
+ export * from './type';
18
+
19
+ const allTypes = ['year', 'month', 'date', 'hour', 'minute', 'second'] as ItemType[];
20
+
21
+ const defaultFormatter = formatDateNumber;
22
+
23
+ export const YEAR = 12 * 30 * 24 * 60 * 60 * 1000;
24
+
25
+ const initMinDate = Date.now() - 10 * YEAR;
26
+ const initMaxDate = Date.now() + 10 * YEAR;
27
+ const initDate = Date.now();
28
+
29
+ export interface DatePickerRef {
30
+ /**
31
+ * 最外层元素 DOM
32
+ * @en The outermost element DOM
33
+ */
34
+ dom: HTMLDivElement | null;
35
+ }
36
+
37
+ const DatePicker = forwardRef((props: DatePickerProps, ref: Ref<DatePickerRef>) => {
38
+ const {
39
+ currentTs: userSetCurrentTs = initDate,
40
+ className = '',
41
+ visible = false,
42
+ onOk,
43
+ onChange,
44
+ onValueChange,
45
+ mode = 'datetime',
46
+ typeArr = [],
47
+ minTs: userSetMinTs = initMinDate,
48
+ maxTs: userSetMaxTs = initMaxDate,
49
+ rangeItemFormat,
50
+ formatter = defaultFormatter,
51
+ valueFilter = () => true,
52
+ columnsProcessor,
53
+ touchToStop,
54
+ useUTC = false,
55
+ renderSeparator,
56
+ renderLinkedContainer,
57
+ ...otherProps
58
+ } = props;
59
+ const isRange = typeof userSetCurrentTs !== 'number';
60
+ const [leftTimeValue, setLeftTimeValue] = useState(userSetCurrentTs[0]);
61
+ const [rightTimeValue, setRightTimeValue] = useState(userSetCurrentTs[1]);
62
+ const [activeTabIndex, setActiveTabIndex] = useState<0 | 1>(0);
63
+ const [minTs, maxTs] = useMemo(() => {
64
+ return _updateTimeScope();
65
+ }, [userSetMinTs, userSetMaxTs, activeTabIndex]);
66
+ const [currentTs, setCurrentTs] = useState(
67
+ isRange
68
+ ? Math.min(maxTs, Math.max(minTs, userSetCurrentTs[0]))
69
+ : Math.min(maxTs, Math.max(minTs, userSetCurrentTs as number)),
70
+ );
71
+ const [data, setData] = useState<PickerData[][]>([[]]);
72
+ const [value, setValue] = useState<ValueType[]>([]);
73
+ const currentDateObjRef = useRef(_convertTsToDateObj(currentTs));
74
+ const minDateObjRef = useRef(_convertTsToDateObj(minTs));
75
+ const maxDateObjRef = useRef(_convertTsToDateObj(maxTs));
76
+ const keyOptions = useMemo(() => _getKeyOptions(), [mode, typeArr]);
77
+ const leftTimeString = useMemo(() => _getRangeItemValue(leftTimeValue), [leftTimeValue]);
78
+ const rightTimeString = useMemo(() => _getRangeItemValue(rightTimeValue), [rightTimeValue]);
79
+ const pickerRef = useRef<PickerRef | null>(null);
80
+
81
+ function _updateRangeValue(nowCurrentTs: number) {
82
+ const leftMinTs = typeof userSetMinTs !== 'number' ? userSetMinTs.startTs : userSetMinTs;
83
+ const rightMinTs = typeof userSetMinTs !== 'number' ? userSetMinTs.endTs : userSetMinTs;
84
+ const leftMaxTs = typeof userSetMaxTs !== 'number' ? userSetMaxTs.startTs : userSetMaxTs;
85
+ const rightMaxTs = typeof userSetMaxTs !== 'number' ? userSetMaxTs.endTs : userSetMaxTs;
86
+
87
+ if (isRange) {
88
+ let leftTime: number, rightTime: number;
89
+ if (activeTabIndex === 0) {
90
+ leftTime = nowCurrentTs;
91
+ rightTime = Math.min(
92
+ rightMaxTs,
93
+ Math.max(Math.max(leftTime, rightMinTs), rightTimeValue),
94
+ );
95
+ } else {
96
+ rightTime = nowCurrentTs;
97
+ leftTime = Math.min(leftMaxTs, Math.max(leftMinTs, leftTimeValue));
98
+ }
99
+ setLeftTimeValue(leftTime);
100
+ setRightTimeValue(rightTime);
101
+ }
102
+ }
103
+
104
+ useImperativeHandle(ref, () => ({
105
+ dom: pickerRef.current ? pickerRef.current.dom : null,
106
+ }));
107
+
108
+ function _getColumns() {
109
+ const dateObj = _getActualArray();
110
+ let columns = keyOptions.map(opt => dateObj[opt]);
111
+ if (columnsProcessor) {
112
+ columns = columnsProcessor(columns, currentDateObjRef.current);
113
+ }
114
+
115
+ return {
116
+ columns,
117
+ dateObj,
118
+ };
119
+ }
120
+
121
+ function _parseFormat(format: string, timeValue: IDateObj): string {
122
+ const { year, month, date, hour, minute, second } = timeValue;
123
+
124
+ const padZero = (num: number | string, targetLength = 2): string => {
125
+ let str = `${num}`;
126
+ while (str.length < targetLength) {
127
+ str = `0${str}`;
128
+ }
129
+ return str;
130
+ };
131
+
132
+ const replace = (formatArg: string, str: string, num: number) => {
133
+ if (formatArg.includes(str)) {
134
+ return str !== 'Y'
135
+ ? formatArg.replace(str.repeat(2), padZero(num)).replace(str, padZero(num))
136
+ : formatArg
137
+ .replace(str.repeat(4), padZero(num))
138
+ .replace(str.repeat(2), padZero(num))
139
+ .replace(str, padZero(num));
140
+ }
141
+ return formatArg;
142
+ };
143
+
144
+ return [
145
+ ['Y', year],
146
+ ['M', month],
147
+ ['D', date],
148
+ ['H', hour],
149
+ ['m', minute],
150
+ ['s', second],
151
+ ].reduce((current, item) => {
152
+ return replace(current, item[0] as string, item[1] as number);
153
+ }, format) as string;
154
+ }
155
+
156
+ function _getRangeItemValue(time: number) {
157
+ const timeValue = _convertTsToDateObj(time);
158
+
159
+ if (!isRange) {
160
+ return;
161
+ }
162
+
163
+ if (rangeItemFormat) {
164
+ return _parseFormat(rangeItemFormat, timeValue);
165
+ }
166
+
167
+ const format = (options: ItemType[], joinString: string) => {
168
+ return options
169
+ .filter(option => {
170
+ return keyOptions.includes(option);
171
+ })
172
+ .map(option => {
173
+ return timeValue[option] < 10
174
+ ? `0${timeValue[option]}`
175
+ : `${timeValue[option]}`;
176
+ })
177
+ .join(joinString);
178
+ };
179
+
180
+ const datePart = format(['year', 'month', 'date'] as ItemType[], '/');
181
+ const timePart = format(['hour', 'minute', 'second'] as ItemType[], ':');
182
+
183
+ return datePart + (datePart && timePart && ' ') + timePart;
184
+ }
185
+
186
+ function _getSelectValue(columns: PickerData[][]) {
187
+ const val = keyOptions.map((opt, index) => {
188
+ const curCol = columns[index] || [];
189
+ const selectIndex = curCol.findIndex(
190
+ col => col.value === currentDateObjRef.current[opt],
191
+ );
192
+
193
+ return curCol[Math.max(selectIndex, 0)]?.value;
194
+ });
195
+
196
+ return val;
197
+ }
198
+
199
+ function _initData() {
200
+ const { columns } = _getColumns();
201
+ const val = _getSelectValue(columns);
202
+
203
+ setData(() => columns);
204
+ setValue(() => val);
205
+ }
206
+
207
+ // 根据当前选中的日期动态改变其他列的options
208
+ // @en Dynamically change the options of other columns based on the currently selected date
209
+ function _getActualArray() {
210
+ const dateObj = {} as Record<ItemType, PickerData[]>;
211
+ // 当前时间对象
212
+ // @en current Date object
213
+ let currentDateObj = { ...currentDateObjRef.current };
214
+ allTypes.forEach(type => {
215
+ // 根据日期类型,计算出默认的日期范围
216
+ // @en According to the date type, calculate the default date range.
217
+ const normalRange = _getNormalRange(type, currentDateObj);
218
+ let range = [] as number[];
219
+ switch (type) {
220
+ case 'year':
221
+ // 默认使用minTs和maxTs年份区间
222
+ // @en Default use minTs and maxTs years.
223
+ range = [minDateObjRef.current.year, maxDateObjRef.current.year];
224
+ break;
225
+ default: {
226
+ // 除了年份外,其他日期类型都需要判断上一级日期是否相同
227
+ // @en In addition to the year, other date types need to check if the upper-level date is the same.
228
+ const checkKeys = allTypes.slice(0, allTypes.indexOf(type));
229
+ range = normalRange;
230
+ if (judgeObj(currentDateObj, minDateObjRef.current, checkKeys)) {
231
+ range[0] = minDateObjRef.current[type];
232
+ currentDateObj = {
233
+ ...currentDateObj,
234
+ // 取当前日期时间和minTs的最大值
235
+ // @en Take the maximum value between the current date and time and minTs.
236
+ [type]: Math.max(minDateObjRef.current[type], currentDateObj[type]),
237
+ };
238
+ }
239
+
240
+ if (judgeObj(currentDateObj, maxDateObjRef.current, checkKeys)) {
241
+ range[range.length - 1] = maxDateObjRef.current[type];
242
+ currentDateObj = {
243
+ ...currentDateObj,
244
+ // 取当前日期时间和maxTs的最小值
245
+ // @en Take the minimum value between the current date and time and maxTs.
246
+ [type]: Math.min(maxDateObjRef.current[type], currentDateObj[type]),
247
+ };
248
+ }
249
+ }
250
+ }
251
+ dateObj[type] = _convertRangeToArr(type, range);
252
+ });
253
+ return dateObj;
254
+ }
255
+
256
+ function _convertRangeToArr(type, range) {
257
+ const [start = 0, end = 0] = range;
258
+ const arr = [] as PickerData[];
259
+
260
+ for (let i = start; i <= end; i += 1) {
261
+ if (valueFilter(type, i)) {
262
+ const text = formatter(i, type);
263
+
264
+ arr.push({
265
+ label: text === void 0 ? defaultFormatter(i) : text,
266
+ value: i,
267
+ });
268
+ }
269
+ }
270
+ return arr;
271
+ }
272
+
273
+ function _getNormalRange(type: ItemType, nowDateObj: IDateObj) {
274
+ switch (type) {
275
+ case 'month':
276
+ return [1, 12];
277
+ case 'date':
278
+ if (nowDateObj.month === 2) {
279
+ // 闰年2月29天
280
+ // @en February 29th in leap year
281
+ return nowDateObj.year % 4 === 0 ? [1, 29] : [1, 28];
282
+ }
283
+ return oneOf(nowDateObj.month, [1, 3, 5, 7, 8, 10, 12]) ? [1, 31] : [1, 30];
284
+ case 'hour':
285
+ return [0, 23];
286
+ case 'minute':
287
+ case 'second':
288
+ return [0, 59];
289
+ default:
290
+ return [];
291
+ }
292
+ }
293
+
294
+ function _convertObjToTs(obj: IDateObj, defaultTs: number) {
295
+ return convertObjToTs(obj, defaultTs, useUTC);
296
+ }
297
+
298
+ function _convertTsToDateObj(ts: number) {
299
+ return convertTsToDateObj(ts, useUTC);
300
+ }
301
+
302
+ function _handlePickerChange(values: ValueType[], index: number) {
303
+ const type = keyOptions[index];
304
+ const nowDateObj = currentDateObjRef.current as IDateObj;
305
+ values.forEach((i, keyIndex) => {
306
+ nowDateObj[keyOptions[keyIndex]] = i as number;
307
+ });
308
+
309
+ if (~keyOptions.slice(0, keyOptions.length - 1).indexOf(type)) {
310
+ currentDateObjRef.current = nowDateObj;
311
+ const { columns, dateObj } = _getColumns();
312
+
313
+ // 校准选中日期,比如先选中2020-02-29 年份改为2019,则2月没有29日;需要校准
314
+ // @en Calibration selected date, For example, if you first select 2020-02-29 and change the year to 2019, there will be no 29th in February; calibration is required
315
+ keyOptions.forEach(key => {
316
+ if (dateObj[key].findIndex(item => item.value === nowDateObj[key]) < 0) {
317
+ nowDateObj[key] = dateObj[key][dateObj[key].length - 1].value as number;
318
+ }
319
+ });
320
+ const val = _getSelectValue(columns);
321
+
322
+ setData(columns);
323
+ setValue(val);
324
+ }
325
+
326
+ setCurrentTs(_convertObjToTs(nowDateObj, currentTs));
327
+
328
+ if (onValueChange) {
329
+ onValueChange(_convertObjToTs(nowDateObj, currentTs), nowDateObj, index);
330
+ }
331
+ }
332
+
333
+ function _handlePickerConfirm(values: ValueType[]) {
334
+ let nowDateObj;
335
+ let newTs;
336
+ if (isRange) {
337
+ const leftTimeObj = _convertTsToDateObj(leftTimeValue);
338
+ const rightTimeObj = _convertTsToDateObj(rightTimeValue);
339
+ nowDateObj = keyOptions.reduce(
340
+ (arr, key) => {
341
+ arr[0][key] = leftTimeObj[key];
342
+ arr[1][key] = rightTimeObj[key];
343
+ return arr;
344
+ },
345
+ [{} as IDateObj, {} as IDateObj],
346
+ );
347
+ newTs = [
348
+ _convertObjToTs(nowDateObj[0], currentTs),
349
+ _convertObjToTs(nowDateObj[1], currentTs),
350
+ ];
351
+ } else {
352
+ nowDateObj = {} as IDateObj;
353
+
354
+ values.forEach((index, keyIndex) => {
355
+ nowDateObj[keyOptions[keyIndex]] = index as number;
356
+ });
357
+ newTs = _convertObjToTs(nowDateObj, currentTs);
358
+ }
359
+
360
+ if (onOk) {
361
+ onOk(newTs, nowDateObj);
362
+ }
363
+
364
+ if (onChange) {
365
+ onChange(newTs, nowDateObj);
366
+ }
367
+ }
368
+
369
+ function _getKeyOptions() {
370
+ if (typeArr && typeArr.length) {
371
+ return typeArr;
372
+ }
373
+ let options = [] as ItemType[];
374
+
375
+ switch (mode) {
376
+ case 'date':
377
+ options = allTypes.slice(0, 3);
378
+ break;
379
+ case 'time':
380
+ options = allTypes.slice(3);
381
+ break;
382
+ default:
383
+ options = allTypes;
384
+ }
385
+ return options;
386
+ }
387
+
388
+ function _updateTimeScope(isLeft?: boolean): [number, number] {
389
+ let nowMaxTs: number, nowMinTs: number;
390
+ if (isLeft || activeTabIndex === 0) {
391
+ nowMaxTs = typeof userSetMaxTs === 'number' ? userSetMaxTs : userSetMaxTs.startTs;
392
+ nowMinTs = Math.min(
393
+ nowMaxTs,
394
+ typeof userSetMinTs === 'number' ? userSetMinTs : userSetMinTs.startTs,
395
+ );
396
+ } else {
397
+ nowMinTs = Math.max(
398
+ Math.min(
399
+ typeof userSetMaxTs === 'number' ? userSetMaxTs : userSetMaxTs.startTs,
400
+ leftTimeValue,
401
+ ),
402
+ typeof userSetMinTs === 'number' ? userSetMinTs : userSetMinTs.endTs,
403
+ );
404
+ nowMaxTs = Math.max(
405
+ nowMinTs,
406
+ typeof userSetMaxTs === 'number' ? userSetMaxTs : userSetMaxTs.endTs,
407
+ );
408
+ }
409
+ return [nowMinTs, nowMaxTs];
410
+ }
411
+
412
+ function _chooseTimeActive(index: 0 | 1) {
413
+ setActiveTabIndex(index);
414
+ }
415
+
416
+ useEffect(() => {
417
+ minDateObjRef.current = _convertTsToDateObj(minTs);
418
+ currentDateObjRef.current = _convertTsToDateObj(currentTs);
419
+ maxDateObjRef.current = _convertTsToDateObj(maxTs);
420
+
421
+ _initData();
422
+ }, [currentTs, minTs, maxTs, useUTC]);
423
+
424
+ useEffect(() => {
425
+ let nowCurrentTs;
426
+ if (isRange) {
427
+ nowCurrentTs = Math.min(
428
+ maxTs,
429
+ Math.max(minTs, activeTabIndex === 0 ? leftTimeValue : rightTimeValue),
430
+ );
431
+ if (currentTs === nowCurrentTs) {
432
+ _updateRangeValue(currentTs);
433
+ }
434
+ } else {
435
+ nowCurrentTs = Math.min(maxTs, Math.max(minTs, currentTs));
436
+ }
437
+ setCurrentTs(nowCurrentTs);
438
+ }, [minTs, maxTs]);
439
+
440
+ useEffect(() => {
441
+ _updateRangeValue(currentTs);
442
+ }, [currentTs]);
443
+
444
+ useEffect(() => {
445
+ if (visible) {
446
+ // 初始化当前时间
447
+ if (isRange) {
448
+ setActiveTabIndex(0);
449
+ setLeftTimeValue(userSetCurrentTs[0]);
450
+ setRightTimeValue(userSetCurrentTs[1]);
451
+ const [nowMinTs, nowMaxTs] = _updateTimeScope(true);
452
+ const nowCurrentTs = Math.min(nowMaxTs, Math.max(nowMinTs, userSetCurrentTs[0]));
453
+ setCurrentTs(nowCurrentTs);
454
+ if (currentTs === nowCurrentTs) {
455
+ _updateRangeValue(currentTs);
456
+ }
457
+ } else {
458
+ setCurrentTs(Math.min(maxTs, Math.max(minTs, userSetCurrentTs as number)));
459
+ }
460
+ _initData();
461
+ }
462
+ }, [visible]);
463
+
464
+ return (
465
+ <ContextLayout>
466
+ {({ prefixCls }) => (
467
+ <Picker
468
+ {...otherProps}
469
+ ref={pickerRef}
470
+ visible={visible}
471
+ className={cls(className, `${prefixCls}-date-picker`)}
472
+ cascade={false}
473
+ data={data}
474
+ value={value}
475
+ onPickerChange={_handlePickerChange}
476
+ onOk={_handlePickerConfirm}
477
+ touchToStop={touchToStop}
478
+ renderExtraHeader={
479
+ isRange
480
+ ? () => (
481
+ <div className={`${prefixCls}-date-picker-show`}>
482
+ <span
483
+ className={cls(
484
+ `${
485
+ activeTabIndex === 0
486
+ ? `${prefixCls}-date-picker-range-item-active`
487
+ : ''
488
+ }`,
489
+ `${prefixCls}-date-picker-range-item`,
490
+ )}
491
+ onClick={() => _chooseTimeActive(0)}
492
+ >
493
+ {leftTimeString}
494
+ </span>
495
+ {renderSeparator ? (
496
+ renderSeparator()
497
+ ) : (
498
+ <span
499
+ className={`${prefixCls}-date-picker-show-separate`}
500
+ >
501
+ ~
502
+ </span>
503
+ )}
504
+
505
+ <span
506
+ className={cls(
507
+ `${
508
+ activeTabIndex === 1
509
+ ? `${prefixCls}-date-picker-range-item-active`
510
+ : ''
511
+ }`,
512
+ `${prefixCls}-date-picker-range-item`,
513
+ )}
514
+ onClick={() => _chooseTimeActive(1)}
515
+ >
516
+ {rightTimeString}
517
+ </span>
518
+ </div>
519
+ )
520
+ : undefined
521
+ }
522
+ renderLinkedContainer={
523
+ renderLinkedContainer
524
+ ? () =>
525
+ renderLinkedContainer(
526
+ isEmptyValue(props.currentTs) ? undefined : currentTs,
527
+ keyOptions,
528
+ )
529
+ : undefined
530
+ }
531
+ />
532
+ )}
533
+ </ContextLayout>
534
+ );
535
+ });
536
+ /**
537
+ * 日期时间选择器,基于`Picker`组件扩展,支持指定范围,单位可精确到秒。
538
+ * @en Date picker, based on the `Picker` component, supports the specified range, the unit can be accurate to seconds.
539
+ * @type 数据录入
540
+ * @type_en Data Entry
541
+ * @name 日期时间选择器
542
+ * @name_en DatePicker
543
+ * @displayName DatePicker
544
+ */
545
+ export default componentWrapper(DatePicker, 'DatePicker');