ClockIndex.tsx 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
  2. import { View, Image, ScrollView, Swiper, SwiperItem, Block } from "@tarojs/components";
  3. import './ClockIndex.scss'
  4. import TabBar from "@/components/navigation/TabBar";
  5. import { IconClose, IconNext } from "@/components/basic/Icons";
  6. import { rpxToPx } from "@/utils/tools";
  7. import { useDispatch, useSelector } from "react-redux";
  8. import { useEffect, useRef, useState } from "react";
  9. import { homeInfo, windows } from "@/services/health";
  10. import dayjs from "dayjs";
  11. import 'dayjs/locale/zh-cn';
  12. import 'dayjs/locale/en';
  13. import { setActions, setEvents, setTimeData } from "@/store/record";
  14. import { TimeFormatter } from "@/utils/time_format";
  15. import { getInfo } from "@/services/user";
  16. import Taro from "@tarojs/taro";
  17. import ChooseActions from "./components/choose_actions";
  18. import NewButton, { NewButtonType } from "@/_health/base/new_button";
  19. import { BASE_IMG_URL } from "@/services/http/api";
  20. import { useTranslation } from "react-i18next";
  21. import NoData from "@/_health/components/no_data";
  22. import IndexTab from "./components/index_tab";
  23. import TimeRecord from "@/_record/pages/time_record";
  24. import RecordTime from "./components/record_time";
  25. import RecordLog from "./components/record_log";
  26. import PickerCard from "@/_record/components/picker_card";
  27. import LogPublish from "./components/log_publish";
  28. import RecordTimeResult from "./components/record_time_result";
  29. import { setFastWithSleep, setWindows } from "@/store/health";
  30. var timer
  31. let useNavigation, LinearGradient;
  32. let pickerConfirm;
  33. if (process.env.TARO_ENV == 'rn') {
  34. useNavigation = require("@react-navigation/native").useNavigation
  35. LinearGradient = require('react-native-linear-gradient').default
  36. }
  37. export default function ClockIndex() {
  38. const systemInfo: any = Taro.getWindowInfo ? Taro.getWindowInfo() : Taro.getSystemInfoSync();
  39. const navigationBarHeight = systemInfo.statusBarHeight + 44;
  40. const screenHeight = systemInfo.screenHeight
  41. const safeAreaInsets = systemInfo.safeArea; // 获取安全区域信息
  42. // 计算底部安全区域的高度
  43. const bottomSafeAreaHeight = systemInfo.windowHeight - safeAreaInsets.bottom;
  44. const user = useSelector((state: any) => state.user);
  45. const record = useSelector((state: any) => state.record);
  46. const [loaded, setLoaded] = useState(false)
  47. const [showRetry, setShowRetry] = useState(false)
  48. const [home, setHome] = useState<any>(null)
  49. const [count, setCount] = useState(0)
  50. const [currentTimeData, setCurrentTimeData] = useState<any>(null)
  51. const [showChoose, setShowChoose] = useState(false)
  52. const [selScenario, setSelScenario] = useState('')
  53. const [selTag, setSelTag] = useState<any>(null)
  54. const [scenarios, setScenarios] = useState<any>([])
  55. const [tabs, setTabs] = useState<any>([])
  56. const dispatch = useDispatch();
  57. const { t } = useTranslation()
  58. global.dispatch = dispatch;
  59. const [showDatePicker, setShowDatePicker] = useState(false)
  60. const [showDurationPicker, setShowDurationPicker] = useState(false)
  61. const [showEndDatePicker, setShowEndDatePicker] = useState(false)
  62. const [pickerTitle, setPickerTitle] = useState('')
  63. const [pickerValue, setPickerValue] = useState<any>(null)
  64. const [showLogPublish, setShowLogPublish] = useState(false)
  65. const startPickerRef = useRef(showDatePicker)
  66. const endPickerRef = useRef(showEndDatePicker)
  67. const durationPickerRef = useRef(showDurationPicker)
  68. const [tags, setTags] = useState<any>([])
  69. const [addTag, setAddTag] = useState(false)
  70. const [showTimeResult, setShowTimeResult] = useState(false)
  71. const [timeResult, setTimeResult] = useState<any>(null)
  72. const [current, setCurrent] = useState(0)
  73. dayjs.locale(global.language == 'en' ? 'en' : 'zh-cn');
  74. let navigation;
  75. if (useNavigation) {
  76. navigation = useNavigation()
  77. }
  78. useEffect(() => {
  79. getHomeData()
  80. }, [user.isLogin])
  81. useEffect(() => {
  82. startPickerRef.current = showDatePicker
  83. endPickerRef.current = showEndDatePicker
  84. durationPickerRef.current = showDurationPicker
  85. }, [showDatePicker, showDurationPicker, showEndDatePicker])
  86. function getHomeData() {
  87. getWindows()
  88. homeInfo().then(res => {
  89. setLoaded(true)
  90. setHome(res)
  91. setCount(1)
  92. dispatch(setEvents((res as any).events))
  93. dispatch(setActions((res as any).actions))
  94. if ((res as any).scenarios) {
  95. setScenarios((res as any).scenarios)
  96. var active_scenario = (res as any).active_scenario
  97. setTabs((res as any).scenarios.map(((item, index) => {
  98. if (item.scenario == active_scenario) {
  99. setCurrent(index)
  100. }
  101. return item.title
  102. })))
  103. }
  104. setShowRetry(false)
  105. }).catch(e => {
  106. setShowRetry(true)
  107. })
  108. }
  109. function getWindows() {
  110. windows().then(res => {
  111. // setLoaded(true)
  112. // setShowRetry(false)
  113. // if (!(res as any).windows.night_day.night.target) {
  114. // var date = new Date()
  115. // var hour = date.getHours()
  116. // if (hour >= 6 && hour < 18) {
  117. // var date1 = new Date()
  118. // date1.setHours(6)
  119. // date1.setMinutes(0)
  120. // date1.setSeconds(0)
  121. // var date2 = new Date()
  122. // date2.setHours(18)
  123. // date2.setMinutes(0)
  124. // date2.setSeconds(0);
  125. // (res as any).windows.night_day.day.target = {
  126. // start_timestamp: date1.getTime(),
  127. // end_timestamp: date2.getTime(),
  128. // duration: 12 * 60 * 60 * 1000
  129. // };
  130. // (res as any).windows.night_day.night.target = {
  131. // start_timestamp: date2.getTime(),
  132. // end_timestamp: date2.getTime() + 12 * 60 * 60 * 1000,
  133. // duration: 12 * 60 * 60 * 1000
  134. // }
  135. // }
  136. // else {
  137. // var date1 = new Date()
  138. // date1.setHours(18)
  139. // date1.setMinutes(0)
  140. // date1.setSeconds(0);
  141. // (res as any).windows.night_day.day.target = {
  142. // start_timestamp: date1.getTime(),
  143. // end_timestamp: date1.getTime() + 12 * 60 * 60 * 1000,
  144. // duration: 12 * 60 * 60 * 1000
  145. // };
  146. // (res as any).windows.night_day.night.target = {
  147. // start_timestamp: date1.getTime() + 12 * 60 * 60 * 1000,
  148. // end_timestamp: date1.getTime() + 12 * 60 * 60 * 1000 + 12 * 60 * 60 * 1000,
  149. // duration: 12 * 60 * 60 * 1000
  150. // }
  151. // }
  152. // }
  153. dispatch(setFastWithSleep((res as any).fast_with_sleep))
  154. dispatch(setWindows((res as any).windows))
  155. // dispatch(setLongFast((res as any).long_fast))
  156. // dispatch(setRefreshs((res as any).refresh_timestamps))
  157. // dispatch(setFinishSetup((res as any).finish_setup))
  158. }).catch(e => {
  159. })
  160. }
  161. useEffect(() => {
  162. getInfo()
  163. Taro.eventCenter.on('refreshClockIndex', getHomeData)
  164. timer = setInterval(() => {
  165. if (startPickerRef.current || endPickerRef.current || durationPickerRef.current) {
  166. return
  167. }
  168. // console.log(showDatePicker , showDurationPicker , showEndDatePicker)
  169. setCount(pre => pre + 1)
  170. }, 1000)
  171. return () => {
  172. clearInterval(timer)
  173. Taro.eventCenter.off('refreshClockIndex')
  174. }
  175. }, [])
  176. useEffect(() => {
  177. Taro.eventCenter.trigger('hideTab', showChoose)
  178. }, [showChoose])
  179. useEffect(() => {
  180. getTime()
  181. }, [count])
  182. useEffect(() => {
  183. if (currentTimeData) {
  184. dispatch(setTimeData(currentTimeData))
  185. }
  186. }, [currentTimeData])
  187. function tapItem(index) {
  188. if (!user.isLogin) {
  189. jumpPage('/_account/pages/ChooseAuth', 'ChooseAuth', navigation)
  190. return
  191. }
  192. var scenarioObj = scenarios[index]
  193. switch (scenarioObj.scenario) {
  194. case 'MEAL':
  195. setShowChoose(true)
  196. setSelScenario('MEAL')
  197. break;
  198. case 'ACTIVITY':
  199. setShowChoose(true)
  200. setSelScenario('ACTIVITY')
  201. break;
  202. case 'FAST':
  203. jumpPage(`/_record/pages/time_record?scenario=FAST`, 'TimeRecord', navigation, {
  204. scenario: 'FAST'
  205. })
  206. break
  207. case 'SLEEP':
  208. jumpPage(`/_record/pages/time_record?scenario=SLEEP`, 'TimeRecord', navigation, {
  209. scenario: 'SLEEP'
  210. })
  211. break
  212. case 'METRIC':
  213. jumpPage('/pages/metric/Metric')
  214. break
  215. case 'MOVE':
  216. jumpPage('/_health/pages/move')
  217. break;
  218. }
  219. }
  220. function getTime() {
  221. if (!home) return
  222. var now = dayjs().format('HH:mm')
  223. for (var i = 0; i < home.time_messages.length; i++) {
  224. var obj = home.time_messages[i]
  225. if (now >= obj.start_time && now < obj.end_time) {
  226. setCurrentTimeData(obj)
  227. return
  228. }
  229. }
  230. setCurrentTimeData(home.time_messages[home.time_messages.length - 1])
  231. }
  232. function getBackground() {
  233. var time = record.time
  234. if (!time) return '#fff'
  235. const { background_colors } = time
  236. if (!background_colors) {
  237. return '#fff'
  238. }
  239. else if (background_colors.length == 1) {
  240. return background_colors[0]
  241. }
  242. return `linear-gradient(to bottom, ${background_colors[0]}, ${background_colors[1]})`
  243. }
  244. function itemTime(item) {
  245. if (item.event && item.event.status == 'OG') {
  246. return TimeFormatter.countdown(item.event.time.start_timestamp)
  247. }
  248. return ''
  249. }
  250. function showPicker(type, title, value, confirm) {
  251. setPickerTitle(title)
  252. setPickerValue(value)
  253. // setPickerFunc(confirm)
  254. pickerConfirm = confirm
  255. switch (type) {
  256. case 'duration':
  257. setShowDurationPicker(true)
  258. break
  259. case 'start':
  260. setShowDatePicker(true)
  261. break
  262. case 'end':
  263. setShowEndDatePicker(true)
  264. break
  265. }
  266. }
  267. function hidePicker() {
  268. setShowDatePicker(false)
  269. setShowEndDatePicker(false)
  270. setShowDurationPicker(false)
  271. }
  272. const array = global.language == 'en' ? ['Eat', 'Workout', 'Fast', 'Sleep'] : ['饮食', '运动', '断食', '睡眠']
  273. if (!loaded && showRetry) return <View style={{ position: 'relative' }}>
  274. <View style={{ height: navigationBarHeight }} />
  275. <IndexTab items={array} current={current} onChanged={(index) => {
  276. setCurrent(index)
  277. }} />
  278. <NoData refresh={
  279. () => {
  280. getHomeData()
  281. }
  282. } />
  283. </View>
  284. function bgView() {
  285. if (process.env.TARO_ENV == 'weapp') {
  286. return <View className="main_bg" style={{ background: getBackground() }} />
  287. }
  288. var time = record.time
  289. if (!time) return <View />
  290. const { background_colors } = time
  291. if (!background_colors) {
  292. return <View />
  293. }
  294. else if (background_colors.length == 1) {
  295. return <View />
  296. }
  297. return <LinearGradient style={{
  298. position: 'absolute',
  299. left: 0,
  300. top: 0,
  301. width: rpxToPx(750),
  302. height: screenHeight,
  303. zIndex: 0,
  304. pointerEvents: 'none'
  305. }}
  306. colors={[background_colors[0], background_colors[1]]}
  307. start={{ x: 0, y: 0 }}
  308. end={{ x: 0, y: 1 }} pointerEvents="none" />
  309. }
  310. function swiperHeight() {
  311. return screenHeight - navigationBarHeight - rpxToPx(94) - rpxToPx(112) - bottomSafeAreaHeight + 4
  312. }
  313. if (!loaded) return <View />
  314. return <View style={{ position: 'relative' }}>
  315. {
  316. bgView()
  317. }
  318. <View style={{ height: navigationBarHeight }} />
  319. <IndexTab items={tabs} current={current} onChanged={(index) => {
  320. setCurrent(index)
  321. }} />
  322. <Swiper style={{ height: swiperHeight(), width: rpxToPx(750) }} current={current} onChange={e => {
  323. setCurrent(e.detail.current)
  324. }}>
  325. {
  326. scenarios.map((item, index) => {
  327. return <SwiperItem key={index}>
  328. {
  329. item.scenario == 'FAST' && <RecordTime scenario="FAST"
  330. event={item.event}
  331. theme_color={item.theme_color}
  332. contentHeight={swiperHeight()}
  333. showPicker={showPicker}
  334. hidePicker={hidePicker}
  335. complete={info => {
  336. setTimeResult(info)
  337. setSelScenario('FAST')
  338. setShowTimeResult(true)
  339. }}
  340. count={count} />
  341. }
  342. {
  343. item.scenario == 'SLEEP' && <RecordTime scenario="SLEEP"
  344. event={item.event}
  345. theme_color={item.theme_color}
  346. contentHeight={swiperHeight()}
  347. showPicker={showPicker} hidePicker={hidePicker}
  348. complete={info => {
  349. setTimeResult(info)
  350. setSelScenario('SLEEP')
  351. setShowTimeResult(true)
  352. }}
  353. count={count} />
  354. }
  355. {
  356. item.scenario == 'MEAL' && <RecordLog scenario="MEAL"
  357. tags={item.tags}
  358. contentHeight={swiperHeight()}
  359. showPublish={(scenario, tag, tags, addTag) => {
  360. setAddTag(addTag)
  361. setShowLogPublish(true)
  362. setSelScenario(scenario)
  363. setSelTag(tag)
  364. setTags(tags)
  365. }} />
  366. }
  367. {
  368. item.scenario == 'ACTIVITY' && <RecordLog
  369. tags={item.tags}
  370. scenario="ACTIVITY"
  371. contentHeight={swiperHeight()}
  372. showPublish={(scenario, tag, tags, addTag) => {
  373. setAddTag(addTag)
  374. setShowLogPublish(true)
  375. setSelScenario(scenario)
  376. setSelTag(tag)
  377. setTags(tags)
  378. }} />
  379. }
  380. </SwiperItem>
  381. })
  382. }
  383. {/* <SwiperItem>
  384. <RecordTime scenario="FAST"
  385. contentHeight={swiperHeight()}
  386. showPicker={showPicker}
  387. hidePicker={hidePicker}
  388. complete={info => {
  389. setTimeResult(info)
  390. setScenarios('FAST')
  391. setShowTimeResult(true)
  392. }}
  393. count={count} />
  394. </SwiperItem>
  395. <SwiperItem>
  396. <RecordTime scenario="SLEEP"
  397. contentHeight={swiperHeight()}
  398. showPicker={showPicker} hidePicker={hidePicker}
  399. complete={info => {
  400. setTimeResult(info)
  401. setScenarios('SLEEP')
  402. setShowTimeResult(true)
  403. }}
  404. count={count} />
  405. </SwiperItem>
  406. <SwiperItem>
  407. <RecordLog scenario="MEAL" contentHeight={swiperHeight()} showPublish={(scenario, tag, tags, addTag) => {
  408. setAddTag(addTag)
  409. setShowLogPublish(true)
  410. setSelScenario(scenario)
  411. setSelTag(tag)
  412. setTags(tags)
  413. }} />
  414. </SwiperItem>
  415. <SwiperItem>
  416. <RecordLog scenario="ACTIVITY" contentHeight={swiperHeight()} showPublish={(scenario, tag, tags, addTag) => {
  417. setAddTag(addTag)
  418. setShowLogPublish(true)
  419. setSelScenario(scenario)
  420. setSelTag(tag)
  421. setTags(tags)
  422. }} />
  423. </SwiperItem> */}
  424. </Swiper>
  425. {
  426. showChoose && <ChooseActions
  427. close={() => {
  428. setShowChoose(false)
  429. }}
  430. quick={() => {
  431. jumpPage(`/_record/pages/log_record?scenario=${selScenario}&quick=1`, 'LogRecord', navigation, {
  432. scenario: selScenario,
  433. quick: 1
  434. })
  435. }}
  436. chooseImg={(array) => {
  437. jumpPage(`/_record/pages/log_record?scenario=${selScenario}&imgs=${JSON.stringify(array)}`, 'LogRecord', navigation, {
  438. scenario: selScenario,
  439. imgs: JSON.stringify(array)
  440. })
  441. }}
  442. chooseText={() => {
  443. jumpPage(`/_record/pages/log_record?scenario=${selScenario}&only_text=1`, 'LogRecord', navigation, {
  444. scenario: selScenario,
  445. only_text: 1
  446. })
  447. }}
  448. />
  449. }
  450. <Block>
  451. {
  452. showDurationPicker && <PickerCard onClose={() => { setShowDurationPicker(false) }}
  453. value={pickerValue}
  454. type="duration"
  455. title={pickerTitle}
  456. onConfirm={(e) => {
  457. // pickerFunc(e)
  458. pickerConfirm(e)
  459. }}
  460. />
  461. }
  462. </Block>
  463. <Block>
  464. {
  465. showDatePicker && <PickerCard onClose={() => { setShowDatePicker(false) }}
  466. value={pickerValue}
  467. type="datetime"
  468. title={pickerTitle}
  469. onConfirm={(e) => {
  470. // pickerFunc(e)
  471. pickerConfirm(e)
  472. }}
  473. />
  474. }
  475. </Block>
  476. <Block>
  477. {
  478. showEndDatePicker && <PickerCard onClose={() => { setShowEndDatePicker(false) }}
  479. value={pickerValue}
  480. type="datetime"
  481. title={pickerTitle}
  482. onConfirm={(e) => {
  483. // pickerFunc(e)
  484. pickerConfirm(e)
  485. }}
  486. />
  487. }
  488. </Block>
  489. <Block>
  490. {
  491. showLogPublish && <LogPublish scenario={selScenario}
  492. tags={tags}
  493. tag={selTag}
  494. addTag={addTag}
  495. onClose={() => {
  496. setShowLogPublish(false)
  497. }} />
  498. }
  499. </Block>
  500. <Block>
  501. {
  502. showTimeResult && <RecordTimeResult
  503. showPicker={showPicker}
  504. hidePicker={hidePicker}
  505. onClose={() => setShowTimeResult(false)}
  506. scenario={selScenario}
  507. info={timeResult}
  508. goEat={() => {
  509. setCurrent(0)
  510. setShowTimeResult(false)
  511. }}
  512. />
  513. }
  514. </Block>
  515. {
  516. process.env.TARO_ENV == 'weapp' && <TabBar index={0} />
  517. }
  518. </View>
  519. }