Index.tsx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. import { View, Text, Image, ScrollView, PageContainer, Swiper, SwiperItem, Switch } from "@tarojs/components";
  2. import Tabbar from "@/components/navigation/TabBar";
  3. import IndexItem from '@/features/trackTimeDuration/components/IndexItem';
  4. import Rings from "@/features/trackTimeDuration/components/Rings";
  5. import './Index.scss'
  6. import { useDispatch, useSelector } from "react-redux";
  7. import { useDidShow, useReady } from "@tarojs/taro";
  8. import Taro from "@tarojs/taro";
  9. import { getInfoSuccess } from "@/store/user";
  10. import { clockHome, clockSummaryRecords, clockSummaryStats, getClockRecords, getClocks } from "@/services/trackTimeDuration";
  11. import { updateScenario } from "@/store/time";
  12. import { setConfigs } from "@/store/common";
  13. import { setScenario } from "@/store/scenario";
  14. import { useEffect, useState } from "react";
  15. import { IconPlus, IconRadioCheck, IconRadioCross } from "@/components/basic/Icons";
  16. import { ColorType } from "@/context/themes/color";
  17. import { getBgRing, getCommon, getDot, getSchedule } from "@/features/trackTimeDuration/hooks/RingData";
  18. import { RealRing, CurrentDot } from "@/features/trackTimeDuration/components/Rings";
  19. import IndexConsole from "@/features/trackTimeDuration/components/IndexConsole";
  20. import Modal from '@/components/layout/Modal'
  21. import { rpxToPx } from "@/utils/tools";
  22. import RecordFastSleep from "@/features/trackTimeDuration/components/RecordFastSleep";
  23. import DayLight from "@/features/trackTimeDuration/components/DayLight";
  24. import { getInfo } from "@/services/user";
  25. import { TimeFormatter } from "@/utils/time_format";
  26. import WeekCalendar from "@/features/trackTimeDuration/components/WeekCalendar";
  27. import { useTranslation } from "react-i18next";
  28. import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
  29. let GradientText
  30. let useNavigation;
  31. if (process.env.TARO_ENV == 'rn') {
  32. GradientText = require('@/components/basic/GradientText').default
  33. useNavigation = require("@react-navigation/native").useNavigation
  34. }
  35. export default function Page() {
  36. const dispatch = useDispatch();
  37. global.dispatch = dispatch;
  38. let navigation;
  39. if (useNavigation) {
  40. navigation = useNavigation()
  41. }
  42. const { t } = useTranslation()
  43. const user = useSelector((state: any) => state.user);
  44. const time = useSelector((state: any) => state.time);
  45. const [showErrorPage, setErrorPage] = useState(false)
  46. const [data, setData] = useState(null)
  47. const [count, setCount] = useState(0)
  48. const [homeData, setHomeData] = useState(null)
  49. const [selIndex, setSelIndex] = useState(0)
  50. const [showModal, setShowModal] = useState(false)
  51. const [modalDetail, setModalDetail] = useState<any>(null)
  52. const [showModal2, setShowModal2] = useState(false)
  53. const [modalDetail2, setModalDetail2] = useState<any>(null)
  54. const [isModal1, setIsModal1] = useState(false)
  55. const [debugInfo, setDebugInfo] = useState(null)
  56. const [isMulti, setIsMulti] = useState(false)
  57. const [records, setRecords] = useState([])
  58. const [calendars, setCalendars] = useState([])
  59. const [multiData, setMultiData] = useState([
  60. {
  61. title: '睡前断食',
  62. checked: false
  63. },
  64. {
  65. title: '睡眠中断食',
  66. checked: false
  67. },
  68. {
  69. title: '起床后断食',
  70. checked: false
  71. },
  72. ])
  73. useEffect(() => {
  74. global.showNightRing = false;
  75. setInterval(() => {
  76. setCount((prevCounter) => prevCounter + 1)
  77. }, 1000)
  78. }, [])
  79. useEffect(() => {
  80. // if (user.isLogin) {
  81. getCheckData()
  82. // }
  83. if (user.isLogin) {
  84. getRecords()
  85. }
  86. }, [user.isLogin, time.status])
  87. useReady(async () => {
  88. const userData = await getStorage('userData');
  89. if (userData) {
  90. dispatch(getInfoSuccess(JSON.parse(userData as string)) as any);
  91. // setTimeout(() => {
  92. // // checkWXPubFollow()
  93. // getCheckData()
  94. // }, 200)
  95. getHistory()
  96. }
  97. })
  98. useDidShow(() => {
  99. if (user.isLogin)
  100. refresh()
  101. })
  102. global.refreshIndex = () => {
  103. setCount((prevCounter) => prevCounter + 1)
  104. }
  105. function refresh() {
  106. getInfo().then(res => {
  107. dispatch(getInfoSuccess(res))
  108. }).catch(e => {
  109. })
  110. }
  111. function getCheckData() {
  112. clockHome().then(res => {
  113. setHomeData(res as any)
  114. global.homeData = res
  115. })
  116. getHistory()
  117. }
  118. function getRecords() {
  119. var timestamp = TimeFormatter.getMondayTimestamp()
  120. var list: any = []
  121. var offset = 12 * 3600 * 1000
  122. for (var i = 0; i < 7; i++) {
  123. list.push(`${i},${timestamp - 7 * 24 * 3600 * 1000 * i - offset},${timestamp - 7 * 24 * 3600 * 1000 * i + 7 * 24 * 3600 * 1000 - offset}`)
  124. // list.push({
  125. // start:timestamp-7*24*3600*1000*i,
  126. // end:timestamp-7*24*3600*1000*i+24*3600*100,
  127. // index:i
  128. // })
  129. }
  130. clockSummaryStats({ times: list.join(';') }).then(res => {
  131. setCalendars((res as any).data.reverse())
  132. })
  133. // clockSummaryStats({start:new Date().getTime()-7*24*3600*1000,end:new Date().getTime()}).then(res => { })
  134. }
  135. function getHistory() {
  136. if (user.isLogin)
  137. getClockRecords({
  138. page: 1,
  139. limit: 1,
  140. completed: true
  141. }).then(res => {
  142. setRecords((res as any).data)
  143. })
  144. }
  145. const startArc = (time: number) => {
  146. var date = new Date(time);
  147. var hour = date.getHours();
  148. var minute = date.getMinutes();
  149. var second = date.getSeconds();
  150. return (hour * 3600 + minute * 60 + second) / (24 * 3600) * 2 * Math.PI - Math.PI / 2.0;
  151. }
  152. const durationArc = (start_time: number, end_time: number) => {
  153. var duration = (end_time - start_time) / 1000;
  154. return duration / (24 * 3600) * 2 * Math.PI;
  155. }
  156. function bigRing() {
  157. var currentRecord = (homeData as any).fast_sleep.current_record
  158. var common = getCommon(null, true)
  159. common.radius = 42;
  160. common.lineWidth = 9;
  161. var bgRing = getBgRing()
  162. var realRing1 = getSchedule(currentRecord, true, true)
  163. realRing1.color = ColorType.fast + '66'
  164. var list: any = []
  165. if (multiData[0].checked) {
  166. const realRingBig: RealRing = {
  167. color: global.fastColor ? global.fastColor : ColorType.fast,
  168. startArc: startArc(currentRecord.fast.target_start_time),
  169. durationArc: durationArc(currentRecord.fast.target_start_time, currentRecord.sleep.target_start_time)
  170. }
  171. list.push(realRingBig)
  172. }
  173. if (multiData[1].checked) {
  174. const realRingBig: RealRing = {
  175. color: global.fastColor ? global.fastColor : ColorType.fast,
  176. startArc: startArc(currentRecord.sleep.target_start_time),
  177. durationArc: durationArc(currentRecord.sleep.target_start_time, currentRecord.sleep.target_end_time)
  178. }
  179. list.push(realRingBig)
  180. }
  181. if (multiData[2].checked) {
  182. const realRingBig: RealRing = {
  183. color: global.fastColor ? global.fastColor : ColorType.fast,
  184. startArc: startArc(currentRecord.sleep.target_end_time),
  185. durationArc: durationArc(currentRecord.sleep.target_end_time, currentRecord.fast.target_end_time)
  186. }
  187. list.push(realRingBig)
  188. }
  189. var points: any = []
  190. for (var i = 0; i < 12; i++) {
  191. var dot: CurrentDot = {
  192. color: 'red',
  193. lineWidth: 8,
  194. borderColor: 'black',
  195. timestamp: new Date().getTime() + i * 3600 * 1000 * 2
  196. }
  197. points.push(dot)
  198. }
  199. return <Rings common={common} bgRing={bgRing} realRing={realRing1} stageList={list} dotList={points} canvasId={'testA'} />
  200. }
  201. function smallRing() {
  202. var common = getCommon(null, true)
  203. common.radius = 28;
  204. common.lineWidth = 9;
  205. var bgRing = getBgRing()
  206. var realRing1 = getSchedule((homeData as any).fast_sleep.current_record, false, false)
  207. return <Rings common={common} bgRing={bgRing} realRing={realRing1} canvasId={'testB'} />
  208. }
  209. function rings() {
  210. return <View style={{ display: 'flex', flexDirection: 'row', marginLeft: 100, marginBottom: 30 }}>
  211. <View style={{ position: 'relative', zIndex: 1 }}>
  212. {
  213. bigRing()
  214. }
  215. {
  216. <View style={{ display: 'flex', position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, alignItems: 'center', justifyContent: 'center' }}>
  217. {
  218. smallRing()
  219. }
  220. </View>
  221. }
  222. </View>
  223. </View>
  224. }
  225. global.indexPageRefresh = () => {
  226. getCheckData()
  227. }
  228. global.showIndexModal = (isShow: boolean, detail: any, debugNode?: any) => {
  229. global.showModal = isShow
  230. setIsModal1(true)
  231. setDebugInfo(debugNode)
  232. setShowModal(isShow)
  233. setModalDetail(detail)
  234. }
  235. global.showIndexModal2 = (isShow: boolean, detail: any) => {
  236. setDebugInfo(null)
  237. global.showModal = isShow
  238. setIsModal1(false)
  239. setShowModal2(isShow)
  240. setModalDetail2(detail)
  241. }
  242. function modalContent() {
  243. if (showModal || showModal2) {
  244. if (process.env.TARO_ENV == 'weapp') {
  245. return <Modal
  246. testInfo={debugInfo}
  247. dismiss={() => {
  248. setDebugInfo(null)
  249. setShowModal(false); setShowModal2(false)
  250. }}
  251. confirm={() => { }}>
  252. {
  253. isModal1 ? modalDetail : modalDetail2
  254. }
  255. </Modal>
  256. }
  257. else if (process.env.TARO_ENV == 'rn') {
  258. return <PageContainer style={{ backgroundColor: '#1c1c1c' }}
  259. // overlayStyle='background-color:rgba(0,0,0,0.9)'
  260. // custom-style='background-color:#1c1c1c'
  261. overlayStyle={{ backgroundColor: 'rgba(0,0,0,0.9)' }}
  262. customStyle={{ backgroundColor: '#1c1c1c' }}
  263. closeOnSlideDown={false}
  264. onBeforeEnter={() => {
  265. Taro.hideTabBar();
  266. }}
  267. onBeforeLeave={() => {
  268. Taro.showTabBar();
  269. }}
  270. onClick={() => { alert('b') }}
  271. onClickOverlay={() => { alert('a') }}
  272. onAfterLeave={() => { setShowModal(false); setShowModal2(false) }}
  273. show={showModal || showModal2} round={true} overlay={true} position='bottom'
  274. >
  275. {
  276. isModal1 ? modalDetail : modalDetail2
  277. }
  278. </PageContainer>
  279. }
  280. }
  281. return <View />
  282. }
  283. async function getStorage(key: string) {
  284. try {
  285. const res = await Taro.getStorage({ key });
  286. return res.data;
  287. } catch {
  288. return '';
  289. }
  290. }
  291. if (!homeData) {
  292. return <View>
  293. <Tabbar index={0} />
  294. </View>
  295. }
  296. function more() {
  297. jumpPage('/pages/common/RecordsHistory?type=time&title=time', 'RecordsHistory', navigation, {
  298. type: 'time',
  299. title: 'time'
  300. })
  301. }
  302. var timestamp = new Date().getTime()
  303. function render() {
  304. return <View className="index_container">
  305. <Text className="count">{count}</Text>
  306. <IndexItem type="FAST" data={(homeData as any).fast} time={timestamp} />
  307. <IndexItem type='SLEEP' data={(homeData as any).sleep} time={timestamp} />
  308. <Text className="discovery">探索</Text>
  309. <IndexItem type="FAST_SLEEP" data={(homeData as any).fast_sleep} time={timestamp} />
  310. <Swiper className='swiper1' indicatorColor='#333'
  311. indicatorActiveColor='#999'
  312. current={0}
  313. autoplay={false}
  314. duration={300}
  315. interval={300}
  316. indicator-offset={[0, -30]}
  317. indicator-height={30}
  318. indicatorDots={(homeData as any).fast_sleep.current_record.status == 'WAIT_FOR_START'}
  319. onChange={(e) => {
  320. var pageIndex = e.detail.current
  321. global.changeMixIndex(pageIndex)
  322. }}
  323. >
  324. <SwiperItem className='swiperItem'>
  325. <IndexConsole record={(homeData as any).fast_sleep} />
  326. </SwiperItem>
  327. {
  328. (homeData as any).fast_sleep.current_record.status == 'WAIT_FOR_START' &&
  329. <SwiperItem className='swiperItem'>
  330. <View>
  331. {
  332. isMulti ? <View>
  333. {
  334. multiData.map((item, index) => {
  335. return <View className={item.checked ? "single_check_sel" : "single_check_nor"} onClick={() => {
  336. item.checked = !item.checked
  337. global.updateMixItem([multiData[0].checked, multiData[1].checked, multiData[2].checked])
  338. setMultiData(JSON.parse(JSON.stringify(multiData)))
  339. setCount((prevCounter) => prevCounter + 1)
  340. }}>
  341. <Text className={item.checked ? "single_check_text_sel" : "single_check_text_nor"}>{item.title}</Text>
  342. {
  343. item.checked ? <Image src={require('@assets/images/check_black.png')} className="single_checked" /> :
  344. <IconPlus color={ColorType.fast} />
  345. }
  346. </View>
  347. })
  348. }
  349. </View> : <View>
  350. <View className={selIndex == 0 ? "single_check_sel" : "single_check_nor"} onClick={() => { setSelIndex(0); global.updateMixItem([true, false, false]); setCount((prevCounter) => prevCounter + 1) }}>
  351. <Text className={selIndex == 0 ? "single_check_text_sel" : "single_check_text_nor"}>睡前断食</Text>
  352. {
  353. selIndex == 0 && <Image src={require('@assets/images/check_black.png')} className="single_checked" />
  354. }
  355. </View>
  356. <View className={selIndex == 1 ? "single_check_sel" : "single_check_nor"} onClick={() => { setSelIndex(1); global.updateMixItem([false, true, false]); setCount((prevCounter) => prevCounter + 1) }}>
  357. <Text className={selIndex == 1 ? "single_check_text_sel" : "single_check_text_nor"}>睡眠中断食</Text>
  358. {
  359. selIndex == 1 && <Image src={require('@assets/images/check_black.png')} className="single_checked" />
  360. }
  361. </View>
  362. <View className={selIndex == 2 ? "single_check_sel" : "single_check_nor"} onClick={() => { setSelIndex(2); global.updateMixItem([false, false, true]); setCount((prevCounter) => prevCounter + 1) }}>
  363. <Text className={selIndex == 2 ? "single_check_text_sel" : "single_check_text_nor"}>起床后断食</Text>
  364. {
  365. selIndex == 2 && <Image src={require('@assets/images/check_black.png')} className="single_checked" />
  366. }
  367. </View>
  368. </View>
  369. }
  370. <View style={{ display: 'flex', alignItems: 'center', flexDirection: 'row', paddingRight: rpxToPx(46), width: rpxToPx(750), boxSizing: 'border-box' }}>
  371. <View style={{ flex: 1 }} />
  372. <Text style={{ marginRight: 10 }}>多选</Text>
  373. <Switch color={ColorType.fast} onChange={(e) => {
  374. setIsMulti(e.detail.value)
  375. if (e.detail.value) {
  376. global.updateMixItem([multiData[0].checked, multiData[1].checked, multiData[2].checked])
  377. }
  378. else {
  379. global.updateMixItem([selIndex == 0, selIndex == 1, selIndex == 2])
  380. }
  381. setCount((prevCounter) => prevCounter + 1)
  382. }} />
  383. </View>
  384. </View>
  385. </SwiperItem>
  386. }
  387. </Swiper>
  388. {
  389. user.isLogin && <DayLight />
  390. }
  391. {
  392. user.isLogin && records.length > 0 && <View style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between' }}>
  393. {
  394. <Text className="discovery">最近</Text>
  395. }
  396. {
  397. process.env.TARO_ENV == 'weapp' && <Text className="fast_sleep_more index_more" onClick={more}>{t('feature.track_time_duration.record_fast_sleep.header.btn_show_all')}</Text>
  398. }
  399. {
  400. process.env.TARO_ENV == 'rn' && <GradientText onClick={more} style={{ fontSize: rpxToPx(32), fontWeight: 'bold' }}>{t('feature.track_time_duration.record_fast_sleep.header.btn_show_all')}</GradientText>
  401. //<Text className="header_action fast_sleep_text" onClick={() => { props.action!() }}>{t('feature.track_time_duration.record_fast_sleep.header.btn_show_all')}</Text>
  402. }
  403. </View>
  404. }
  405. {
  406. records.length > 0 && <View className="fast_sleep_item_bg">
  407. <RecordFastSleep data={records[0]} type='record' delSuccess={() => { }} index={-20000}/>
  408. </View>
  409. }
  410. {
  411. user.isLogin && calendars.length > 0 && <View>
  412. <Text className="discovery">周统计</Text>
  413. <WeekCalendar calendars={calendars} />
  414. </View>
  415. }
  416. {/*
  417. <View style={{ marginTop: 50 }}>
  418. <Text>Multi Sel</Text>
  419. {
  420. rings()
  421. }
  422. </View> */}
  423. <View style={{ height: 100 }} />
  424. {
  425. modalContent()
  426. }
  427. <Tabbar index={0} />
  428. </View>
  429. }
  430. if (process.env.TARO_ENV == 'rn') {
  431. return <ScrollView>
  432. {
  433. render()
  434. }
  435. </ScrollView>
  436. }
  437. return render()
  438. }