Index.tsx 20 KB

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