ConsolePicker.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import { View, Text, PickerView, PickerViewColumn } from "@tarojs/components";
  2. import Taro from "@tarojs/taro";
  3. import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
  4. import { useTranslation } from "react-i18next";
  5. import '@components/input/LimitPickers.scss'
  6. import { TimeFormatter } from "@/utils/time_format";
  7. import React from "react";
  8. let currentValueList;
  9. const Component = forwardRef((props: {
  10. themeColor?: string, title?: string,
  11. min: number,
  12. max: number,
  13. current: number,
  14. onChange: Function,
  15. onCancel: Function,
  16. duration?: number,
  17. isFast?: boolean,
  18. isEnd?: boolean,
  19. endTimestamp?: number,
  20. isTimeout?: boolean
  21. }, ref) => {
  22. const today = new Date();
  23. const [loaded, setLoaded] = useState(false)
  24. const [values, setValues] = useState([0, today.getHours(), today.getMinutes()])
  25. const [days, setDays] = useState(['0'])
  26. const [todayIndex, setTodayIndex] = useState(0)
  27. const { t } = useTranslation()
  28. const hours: number[] = [];
  29. var color = props.themeColor ? props.themeColor : '#ff0000'
  30. var alpha = alphaToHex(0.4)
  31. for (let i = 0; i <= 23; i++) {
  32. hours.push(i);
  33. }
  34. const minutes: number[] = [];
  35. for (let i = 0; i <= 59; i++) {
  36. minutes.push(i);
  37. }
  38. function resetPickerData() {
  39. debugger
  40. if (currentValueList) {
  41. setValues(currentValueList)
  42. }
  43. }
  44. useImperativeHandle(ref, () => ({
  45. resetPickerData: resetPickerData
  46. }));
  47. useEffect(() => {
  48. var minDate = new Date(props.min)
  49. var maxDate = new Date(props.max)
  50. var currentDate = new Date(props.current)
  51. minDate.setHours(0)
  52. minDate.setMinutes(0)
  53. minDate.setSeconds(0)
  54. minDate.setMilliseconds(0)
  55. maxDate.setHours(0)
  56. maxDate.setMinutes(0)
  57. maxDate.setSeconds(0)
  58. maxDate.setMilliseconds(0)
  59. // 计算两个日期的时间戳差异(以毫秒为单位)
  60. const timeDifference = Math.abs(maxDate.getTime() - minDate.getTime());
  61. // 将时间戳差异转换为天数
  62. const count = Math.ceil(timeDifference / (1000 * 3600 * 24));
  63. var list: any = [];
  64. var selIndex = 0;
  65. for (var i = 0; i <= count; i++) {
  66. var dt = new Date(props.min + i * 24 * 3600 * 1000)
  67. const month = dt.getMonth() + 1;
  68. const day = dt.getDate();
  69. // const weekday = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][date.getDay()];
  70. const weekday = TimeFormatter.getDayOfWeek(dt.getDay(), true);
  71. const formattedDate = global.language == 'en' ? `${weekday} ${TimeFormatter.getMonth(month)} ${day}` : `${TimeFormatter.getMonth(month)}${day}日 ${weekday}`;
  72. var today1 = new Date();
  73. var yesterday = new Date(today1.getTime() - 24 * 3600 * 1000)
  74. if (dt.getMonth() == currentDate.getMonth() && dt.getDate() == currentDate.getDate()) {
  75. selIndex = i
  76. }
  77. if (dt.getMonth() == today1.getMonth() && dt.getDate() == today1.getDate()) {
  78. list.push(TimeFormatter.getTodayUnit());
  79. setTodayIndex(i)
  80. }
  81. else if (dt.getMonth() == yesterday.getMonth() && dt.getDate() == yesterday.getDate()) {
  82. list.push(TimeFormatter.getYesterdayUnit());
  83. }
  84. else {
  85. list.push(formattedDate);
  86. }
  87. }
  88. setDays(list)
  89. currentValueList = [selIndex, currentDate.getHours(), currentDate.getMinutes()]
  90. setValues([selIndex, currentDate.getHours(), currentDate.getMinutes()])
  91. setTimeout(() => {
  92. setValues([selIndex, currentDate.getHours(), currentDate.getMinutes()])
  93. }, 50)
  94. setLoaded(true)
  95. }, [])
  96. function alphaToHex(alpha) {
  97. var alphaValue = Math.round(alpha * 255); // 将透明度乘以255并四舍五入
  98. var hexValue = alphaValue.toString(16); // 将整数转换为十六进制字符串
  99. if (hexValue.length === 1) {
  100. hexValue = "0" + hexValue; // 如果十六进制字符串只有一位,补零
  101. }
  102. return hexValue;
  103. }
  104. function cancel(e) {
  105. if (process.env.TARO_ENV == 'weapp') {
  106. e.stopPropagation()
  107. }
  108. props.onCancel()
  109. }
  110. function confirm(e) {
  111. if (process.env.TARO_ENV == 'weapp') {
  112. e.stopPropagation()
  113. }
  114. var date = new Date();
  115. date.setDate(new Date(props.max).getDate() - (days.length - values[0] - 1));
  116. const year = date.getFullYear();
  117. const month = date.getMonth() + 1;
  118. const day = date.getDate();
  119. const time = `${year}-${expandZero(month)}-${expandZero(day)}T${expandZero(hours[values[1]])}:${expandZero(minutes[values[2]])}:${expandZero((new Date(global.set_time)).getSeconds())}`;
  120. if (getTimestamp(time) > global.set_time) {
  121. setValues([todayIndex, (new Date(global.set_time)).getHours(), (new Date(global.set_time)).getMinutes()])
  122. setTimeout(() => {
  123. setValues([todayIndex, (new Date(global.set_time)).getHours(), (new Date(global.set_time)).getMinutes()])
  124. }, 300);
  125. Taro.showToast({
  126. icon: 'none',
  127. title: t('feature.common.toast.min_time_value'),
  128. })
  129. return
  130. }
  131. props.onChange(new Date(time).getTime())
  132. }
  133. function expandZero(num: number): string {
  134. return num < 10 ? `0${num}` : `${num}`;
  135. }
  136. function getTimestamp(dateTimeString: string): number {
  137. const timestamp = Date.parse(dateTimeString);
  138. return timestamp;
  139. }
  140. function onPickerChange(e) {
  141. setValues(e.detail.value)
  142. }
  143. function getEndTime() {
  144. var date = new Date(props.max);
  145. date.setDate(date.getDate() - (days.length - values[0] - 1));
  146. date.setHours(values[1])
  147. date.setMinutes(values[2])
  148. var newDate = new Date(date.getTime() + props.duration!).getTime()
  149. if (global.language == 'en') {
  150. return TimeFormatter.dateDescription(newDate, true) + ' at ' + TimeFormatter.timeDescription(newDate)
  151. }
  152. return TimeFormatter.dateDescription(newDate, true) + ' ' + TimeFormatter.timeDescription(newDate)
  153. }
  154. function getEndTimestamp(timestamp) {
  155. if (global.language == 'en') {
  156. return TimeFormatter.dateDescription(timestamp, true) + ' at ' + TimeFormatter.timeDescription(timestamp)
  157. }
  158. return TimeFormatter.dateDescription(timestamp, true) + ' ' + TimeFormatter.timeDescription(timestamp)
  159. }
  160. function pickerTimeText() {
  161. if (props.isTimeout) {
  162. if (props.isFast) {
  163. return t('feature.track_time_duration.console.real_fast_end_tip',{time:getEndTimestamp(props.endTimestamp!)})
  164. }
  165. else {
  166. return t('feature.track_time_duration.console.real_sleep_end_tip',{time:getEndTimestamp(props.endTimestamp!)})
  167. }
  168. }
  169. if (props.isFast) {
  170. if (props.isEnd) {
  171. return t('feature.track_time_duration.console.real_fast_end_tip',{time:getEndTimestamp(props.endTimestamp!)})
  172. }
  173. return t('feature.track_time_duration.console.real_fast_start_tip',{time:getEndTime()})
  174. }
  175. else {
  176. if (props.isEnd) {
  177. return t('feature.track_time_duration.console.real_sleep_end_tip',{time:getEndTimestamp(props.endTimestamp!)})
  178. }
  179. return t('feature.track_time_duration.console.real_sleep_start_tip',{time:getEndTime()})
  180. }
  181. }
  182. function pickerDetail() {
  183. return <View style={{ display: 'flex', flexDirection: 'column', opacity: loaded ? 1 : 0 }}>
  184. <Text className='modal_title' style={{ color: color }}>{props.title ? props.title : '测试标题 '}</Text>
  185. <View style={{ backgroundColor: 'transparent', position: 'relative' }}>
  186. <PickerView
  187. itemStyle={{ color: '#fff', margin: 0, padding: 0 }}
  188. value={values}
  189. className="picker"
  190. maskClass="picker-mask"
  191. style={{ color: '#fff' }}
  192. onChange={onPickerChange}
  193. immediateChange={true}
  194. indicatorStyle='height: 50px;color:red;'>
  195. <PickerViewColumn style='flex:0 0 45%'>
  196. {days.map(item => {
  197. return (
  198. <View style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>{item}</View>
  199. );
  200. })}
  201. </PickerViewColumn>
  202. <PickerViewColumn>
  203. {hours.map(item => {
  204. return (
  205. <View style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>{item < 10 ? `0${item}` : item}</View>
  206. );
  207. })}
  208. </PickerViewColumn>
  209. <PickerViewColumn>
  210. {minutes.map(item => {
  211. return (
  212. <View style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>{item < 10 ? `0${item}` : item}</View>
  213. );
  214. })}
  215. </PickerViewColumn>
  216. </PickerView>
  217. </View>
  218. <Text className="pickerEndTime" style={{ color: props.isTimeout ? 'red' : '#ffffff' }}>{pickerTimeText()}</Text>
  219. <View className='modal_operate'>
  220. <View className='modal_btn' style={{ backgroundColor: color + alpha }} onClick={cancel}>
  221. <Text className='modal_cancel_text' style={{ color: color, fontWeight: 'bold' }}>{t('feature.common.picker_cancel_btn')}</Text>
  222. </View>
  223. <View className='btn_space' />
  224. <View className='modal_btn' style={{ backgroundColor: color }} onClick={confirm}>
  225. <Text className='modal_confirm_text' style={{ color: '#000', fontWeight: 'bold' }}>{t('feature.common.picker_confirm_btn')}</Text>
  226. </View>
  227. </View>
  228. </View>
  229. }
  230. return pickerDetail()
  231. })
  232. export default React.memo(Component);