WeekCalendar.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. import { View, ScrollView, Text, Swiper, SwiperItem } from "@tarojs/components";
  2. import './WeekCalendar.scss'
  3. import { useEffect, useState, useMemo, memo, useRef } from "react";
  4. import { ColorType } from "@/context/themes/color";
  5. import WeekCalendarItem from "./WeekCalendarItem";
  6. import { rpxToPx } from "@/utils/tools";
  7. import { TimeFormatter } from "@/utils/time_format";
  8. import { clockSummaryStats } from "@/services/trackTimeDuration";
  9. import { useTranslation } from "react-i18next";
  10. import { IconBigArrow } from "@/components/basic/Icons";
  11. import dayjs from "dayjs";
  12. let pageIndex = 0
  13. let lastFastValue = 0;
  14. let lastSleepValue = 0;
  15. let lastOffset;
  16. let LinearGradient;
  17. if (process.env.TARO_ENV == 'rn') {
  18. LinearGradient = require('react-native-linear-gradient').default
  19. }
  20. const WeekCalendar = memo((props: { isFastSleep: boolean }) => {
  21. const [calendars, setCalendars] = useState<any>([])
  22. const [current, setCurrent] = useState(0)
  23. const [summary, setSummary] = useState<any>(null)
  24. const [calendarData, setCalendarData] = useState<any>(null)
  25. const [minTime, setMinTime] = useState(0)
  26. const [left, setLeft] = useState(0)
  27. const [isLoading, setIsLoading] = useState(false)
  28. const { t } = useTranslation()
  29. const ref = useRef(null)
  30. const pageSize = 40
  31. console.log('aaaaa')
  32. useEffect(() => {
  33. // pageIndex = -1
  34. getRecords()
  35. }, [])
  36. global.refrehWeekly = () => {
  37. // getRecords()
  38. if (isLoading) return
  39. pageIndex = 0;
  40. setIsLoading(true)
  41. var timestamp = TimeFormatter.getMondayTimestamp()
  42. var now = new Date()
  43. if (now.getDay() == 0 && now.getHours() >= 0 && now.getHours() < 12) {
  44. timestamp -= 24 * 3600 * 1000 * 7
  45. }
  46. var list: any = []
  47. var offset = 12 * 3600 * 1000 + pageIndex * pageSize * 24 * 3600 * 1000
  48. if (!props.isFastSleep){
  49. offset = pageIndex * pageSize * 24 * 3600 * 1000
  50. }
  51. for (var i = 0; i < pageSize; i++) {
  52. list.push(`${i + pageIndex * pageSize},${timestamp - 7 * 24 * 3600 * 1000 * i - offset},${timestamp - 7 * 24 * 3600 * 1000 * i + 7 * 24 * 3600 * 1000 - offset}`)
  53. }
  54. clockSummaryStats({ times: list.join(';') }).then(res => {
  55. var list = (res as any).data.reverse()
  56. if (pageIndex == 0) {
  57. setCalendars(list)
  58. setSummary(list[current].summary_stats ? list[current].summary_stats : null)
  59. setCalendarData(list[current])
  60. setIsLoading(false)
  61. }
  62. })
  63. }
  64. function getRecords() {
  65. if (isLoading) return
  66. pageIndex = 0;
  67. setIsLoading(true)
  68. var timestamp = TimeFormatter.getMondayTimestamp()
  69. var now = new Date()
  70. if (now.getDay() == 0 && now.getHours() >= 0 && now.getHours() < 12) {
  71. timestamp -= 24 * 3600 * 1000 * 7
  72. }
  73. var list: any = []
  74. var offset = 12 * 3600 * 1000 + pageIndex * pageSize * 24 * 3600 * 1000
  75. if (!props.isFastSleep){
  76. offset = pageIndex * pageSize * 24 * 3600 * 1000
  77. }
  78. for (var i = 0; i < pageSize; i++) {
  79. list.push(`${i + pageIndex * pageSize},${timestamp - 7 * 24 * 3600 * 1000 * i - offset},${timestamp - 7 * 24 * 3600 * 1000 * i + 7 * 24 * 3600 * 1000 - offset}`)
  80. }
  81. clockSummaryStats({ times: list.join(';') }).then(res => {
  82. var list = (res as any).data.reverse()
  83. if (list.length > 1) {
  84. lastFastValue = list[list.length - 2].summary_stats.fast.avg
  85. lastSleepValue = list[list.length - 2].summary_stats.sleep.avg
  86. }
  87. if (pageIndex == 0) {
  88. setCalendars(list)
  89. setCurrent(list.length - 1)
  90. setSummary(list[list.length - 1].summary_stats ? list[list.length - 1].summary_stats : null)
  91. setCalendarData(list[list.length - 1])
  92. setMinTime((res as any).extra.real_start_time_min)
  93. setLeft((list.length - 1) * parseInt(rpxToPx(658) + ''))
  94. setIsLoading(false);
  95. if (ref.current) {
  96. (ref.current as any).scrollToOffset((list.length - 1) * parseInt(rpxToPx(658) + ''), false);
  97. setTimeout(() => {
  98. (ref.current as any).scrollToOffset((list.length - 1) * parseInt(rpxToPx(658) + ''), false);
  99. }, 500)
  100. }
  101. }
  102. else {
  103. }
  104. })
  105. // clockSummaryStats({start:new Date().getTime()-7*24*3600*1000,end:new Date().getTime()}).then(res => { })
  106. }
  107. function dragStart(e) {
  108. // fingerDrag = true
  109. }
  110. function dragEnd(e) {
  111. // fingerDrag = false
  112. }
  113. function onScroll(e) {
  114. // if (!fingerDrag && process.env.TARO_ENV == 'weapp') return
  115. if (lastOffset && Math.abs(lastOffset - e.detail.scrollLeft) > 300) {
  116. setLeft(lastOffset)
  117. return
  118. }
  119. // isScrolling = true
  120. var x = e.detail.scrollLeft + 5
  121. lastOffset = e.detail.scrollLeft
  122. // var page = parseInt(x / parseInt(rpxToPx(658) + '') + '')
  123. var page = Math.round(x / parseInt(rpxToPx(658) + ''))
  124. console.log(page, x)
  125. if (current != page && page < calendars.length && page >= 0) {
  126. lastFastValue = calendars[current].summary_stats.fast.avg
  127. lastSleepValue = calendars[current].summary_stats.sleep.avg
  128. setCurrent(page)
  129. setSummary(calendars[page].summary_stats ? calendars[page].summary_stats : null)
  130. setCalendarData(calendars[page])
  131. // if (page <= 0) {
  132. // getRecords();
  133. // }
  134. }
  135. // if (scrollTimer)
  136. // clearTimeout(scrollTimer);
  137. // scrollTimer = setTimeout(() => {
  138. // isScrolling = false
  139. // fingerDrag = false;
  140. // }, 300) as any
  141. }
  142. function onChange(e) {
  143. var page = e.detail.current
  144. lastFastValue = calendars[current].summary_stats.fast.avg
  145. lastSleepValue = calendars[current].summary_stats.sleep.avg
  146. setCurrent(page)
  147. setSummary(calendars[page].summary_stats ? calendars[page].summary_stats : null)
  148. setCalendarData(calendars[page])
  149. }
  150. function getDate(timestamp) {
  151. var date = new Date(timestamp)
  152. if (global.language == 'en') {
  153. return dayjs(timestamp).format('MMM D')
  154. }
  155. return `${date.getMonth() + 1}月${date.getDate()}日`
  156. }
  157. function getWeekDuration() {
  158. if (global.language == 'en') {
  159. if (!props.isFastSleep) {
  160. return `${t('feature.common.day_of_week_full.mon')}, ${getDate(calendarData.start)} - ${t('feature.common.day_of_week_full.mon')}, ${getDate(calendarData.end)}`
  161. }
  162. return `${t('feature.common.day_of_week_full.sun')} ${t('feature.common.time_desc.afternoon')}, ${getDate(calendarData.start)} - ${t('feature.common.day_of_week_full.sun')} ${t('feature.common.time_desc.morning')}, ${getDate(calendarData.end)}`
  163. }
  164. if (!props.isFastSleep) {
  165. return `${getDate(calendarData.start)} ${t('feature.common.day_of_week_full.mon')} - ${getDate(calendarData.end)} ${t('feature.common.day_of_week_full.mon')}`
  166. }
  167. return `${getDate(calendarData.start)} ${t('feature.common.day_of_week_full.sun')}${t('feature.common.time_desc.afternoon')} - ${getDate(calendarData.end)} ${t('feature.common.day_of_week_full.sun')}${t('feature.common.time_desc.morning')}`
  168. }
  169. function getWeekIndex() {
  170. // style={{ opacity: current == calendars.length - 1 ? 1 : 0 }}
  171. if (current == calendars.length - 1) {
  172. return t('feature.common.week_desc.current_week')
  173. }
  174. else if (current == calendars.length - 2) {
  175. return t('feature.common.week_desc.last_week')
  176. }
  177. else {
  178. return t('feature.common.week_desc.weeks_ago', { index: calendars.length - current - 1 })
  179. }
  180. }
  181. function showWeeklyItem(index) {
  182. if (process.env.TARO_ENV == 'weapp') {
  183. if (index >= current - 1 && index <= current + 1) {
  184. return true
  185. }
  186. return false
  187. }
  188. if (index >= current - 2 && index <= current + 2) {
  189. return true
  190. }
  191. return false
  192. }
  193. if (!calendarData)
  194. return <View />
  195. return <View style={{ display: 'flex', flexDirection: 'column' }}>
  196. <View className="calendar_summary_top">
  197. <View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', flex: 1 }}>
  198. {
  199. !summary || summary.fast.avg == 0 ? <View className="calendar-empty-bg" style={{ borderColor: props.isFastSleep ? ColorType.fast : ColorType.food }}>
  200. <View className="calendar-empty-line" style={{ backgroundColor: props.isFastSleep ? ColorType.fast : ColorType.food }} />
  201. </View> :
  202. <View className={lastFastValue > summary.fast.avg ? 'calendar-arrow-bg-down' : 'calendar-arrow-bg'} style={{ backgroundColor: props.isFastSleep ? ColorType.fast : ColorType.food }}>
  203. <IconBigArrow color="#fff" width={rpxToPx(32)} />
  204. </View>
  205. }
  206. <View className="calendar_summary_item">
  207. <Text className="calendar_summary_title">{props.isFastSleep ? t('feature.track_time_duration.weekly.fast_average') : t('feature.track_time_duration.weekly.eat_average')}</Text>
  208. <Text className="calendar_summary_value" style={{ color: props.isFastSleep ? ColorType.fast : ColorType.food }}>{!summary || summary.fast.avg == 0 ? t('feature.track_time_duration.record_fast_sleep.none') : TimeFormatter.calculateTimeDifference(new Date().getTime(), new Date().getTime() + summary.fast.avg)}</Text>
  209. </View>
  210. </View>
  211. <View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', flex: 1 }}>
  212. {
  213. !summary || summary.sleep.avg == 0 ? <View className="calendar-empty-bg" style={{ borderColor: props.isFastSleep ? ColorType.sleep : ColorType.activity }}>
  214. <View className="calendar-empty-line" style={{ backgroundColor: props.isFastSleep ? ColorType.sleep : ColorType.activity }} />
  215. </View> :
  216. <View className={lastSleepValue > summary.sleep.avg ? 'calendar-arrow-bg-down' : 'calendar-arrow-bg'} style={{ backgroundColor: props.isFastSleep ? ColorType.sleep : ColorType.activity }}>
  217. <IconBigArrow color="#fff" width={rpxToPx(32)} />
  218. </View>
  219. }
  220. <View className="calendar_summary_item">
  221. <Text className="calendar_summary_title">{props.isFastSleep ? t('feature.track_time_duration.weekly.sleep_average') : t('feature.track_time_duration.weekly.wake_average')}</Text>
  222. <Text className="calendar_summary_value" style={{ color: props.isFastSleep ? ColorType.sleep : ColorType.activity }}>{!summary || summary.sleep.avg == 0 ? t('feature.track_time_duration.record_fast_sleep.none') : TimeFormatter.calculateTimeDifference(new Date().getTime(), new Date().getTime() + summary.sleep.avg)}</Text>
  223. </View>
  224. </View>
  225. </View>
  226. <View style={{ display: 'flex', flexDirection: 'row', marginBottom: rpxToPx(16), alignItems: 'center' }}>
  227. <View className="calendar_this_week" >{getWeekIndex()}</View>
  228. <Text className="calendar_summary_desc">{getWeekDuration()}</Text>
  229. </View>
  230. <View className="chart_bg">
  231. <View className="chart_bg">
  232. {
  233. process.env.TARO_ENV == 'weapp' ? <View className="chart_content_bg" style={{
  234. left: parseInt(rpxToPx(46) + ''),
  235. right: parseInt(rpxToPx(46) + ''),
  236. top: parseInt(rpxToPx(60) + ''),
  237. bottom: parseInt(rpxToPx(60) + ''),
  238. width: parseInt(rpxToPx(658) + ''),
  239. }} /> :
  240. <LinearGradient style={{
  241. position: 'absolute',
  242. left: parseInt(rpxToPx(46) + ''),
  243. right: parseInt(rpxToPx(46) + ''),
  244. top: parseInt(rpxToPx(60) + ''),
  245. bottom: parseInt(rpxToPx(60) + ''),
  246. width: parseInt(rpxToPx(658) + ''),
  247. zIndex: -1
  248. }}
  249. colors={['#1C1C1C', '#000000', '#1C1C1C']}
  250. start={{ x: 0, y: 0 }}
  251. end={{ x: 0, y: 1 }} />
  252. }
  253. <View>
  254. <Swiper
  255. current={current}
  256. onChange={onChange}
  257. style={{
  258. marginLeft: parseInt(rpxToPx(46) + ''),
  259. width: parseInt(rpxToPx(658) + ''),
  260. height: parseInt(rpxToPx(520) + ''),
  261. flexDirection: 'row', display: 'flex',
  262. }}>
  263. {
  264. calendars.map((item, index) => {
  265. return <SwiperItem key={index}>
  266. {
  267. showWeeklyItem(index) ?
  268. <WeekCalendarItem data={item} isCurrentWeek={index == calendars.length - 1} isFastSleep={props.isFastSleep} /> :
  269. <View style={{ width: parseInt(rpxToPx(658) + ''), flexShrink: 0 }} />
  270. }
  271. </SwiperItem>
  272. })
  273. }
  274. </Swiper>
  275. </View>
  276. {
  277. props.isFastSleep ? <View className="chart_times" style={{ marginTop: parseInt(rpxToPx(60) + ''), marginBottom: parseInt(rpxToPx(60) + '') }}>
  278. <Text className="chart_times_txt" style={{ left: 0, top: 0 }}>12:00</Text>
  279. <Text className="chart_times_txt" style={{ left: 0, top: parseInt(rpxToPx(100 - 7) + '') }}>18:00</Text>
  280. <Text className="chart_times_txt" style={{ left: 0, top: parseInt(rpxToPx(200 - 5) + '') }}>24:00</Text>
  281. <Text className="chart_times_txt" style={{ left: 0, top: parseInt(rpxToPx(300 - 5) + '') }}>06:00</Text>
  282. <Text className="chart_times_txt" style={{ left: 0, bottom: 0 }}>12:00</Text>
  283. </View> :
  284. <View className="chart_times" style={{ marginTop: parseInt(rpxToPx(60) + ''), marginBottom: parseInt(rpxToPx(60) + '') }}>
  285. <Text className="chart_times_txt" style={{ left: 0, top: 0 }}>00:00</Text>
  286. <Text className="chart_times_txt" style={{ left: 0, top: parseInt(rpxToPx(100 - 7) + '') }}>06:00</Text>
  287. <Text className="chart_times_txt" style={{ left: 0, top: parseInt(rpxToPx(200 - 5) + '') }}>12:00</Text>
  288. <Text className="chart_times_txt" style={{ left: 0, top: parseInt(rpxToPx(300 - 5) + '') }}>18:00</Text>
  289. <Text className="chart_times_txt" style={{ left: 0, bottom: 0 }}>24:00</Text>
  290. </View>
  291. }
  292. </View>
  293. </View>
  294. </View>
  295. })
  296. export default WeekCalendar;