time_record.tsx 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. import { View, Image } from "@tarojs/components";
  2. import './time_record.scss'
  3. import Taro, { useRouter, useShareAppMessage } from "@tarojs/taro";
  4. import { rpxToPx } from "@/utils/tools";
  5. import { MainColorType } from "@/context/themes/color";
  6. import NewButton, { NewButtonType } from "@/_health/base/new_button";
  7. import { useEffect, useState } from "react";
  8. import NewDateTimePicker from "@/_health/base/new_date_time_picker";
  9. import dayjs from "dayjs";
  10. import RingProgress from "../components/ring_progress";
  11. import NewDurationPicker, { DurationPickerType } from "@/_health/base/new_durationpicker";
  12. import { IconArrow, IconClose } from "@/components/basic/Icons";
  13. import { useSelector } from "react-redux";
  14. import { TimeFormatter } from "@/utils/time_format";
  15. import { addEvents } from "@/services/health";
  16. import Modal from "@/components/layout/Modal.weapp";
  17. import { getDurationArc, getStartArc } from "@/features/health/hooks/health_hooks";
  18. import ShareBtn from "@/components/basic/ShareBtn";
  19. import PickerCard from "../components/picker_card";
  20. let timer
  21. let useRoute;
  22. let useNavigation;
  23. if (process.env.TARO_ENV == 'rn') {
  24. useRoute = require("@react-navigation/native").useRoute
  25. useNavigation = require("@react-navigation/native").useNavigation
  26. }
  27. export default function TimeRecord() {
  28. const systemInfo: any = Taro.getWindowInfo ? Taro.getWindowInfo() : Taro.getSystemInfoSync();
  29. const navigationBarHeight = systemInfo.statusBarHeight + 44;
  30. const record = useSelector((state: any) => state.record);
  31. const [enterTime] = useState(new Date().getTime())
  32. const [showDatePicker, setShowDatePicker] = useState(false)
  33. const [showDurationPicker, setShowDurationPicker] = useState(false)
  34. const [showEndDatePicker, setShowEndDatePicker] = useState(false)
  35. const [count, setCount] = useState(0)
  36. const [status, setStatus] = useState('WFS')
  37. const [info, setInfo] = useState<any>(null)
  38. const [loaded, setLoaded] = useState(false)
  39. const [showHighlight, setShowHighlight] = useState(false)
  40. const [showShare, setShowShare] = useState(false)
  41. const [shareUrl, setShareUrl] = useState('')
  42. let router
  43. let navigation;
  44. if (useNavigation) {
  45. navigation = useNavigation()
  46. }
  47. if (process.env.TARO_ENV == 'rn') {
  48. router = useRoute()
  49. }
  50. else {
  51. router = useRouter()
  52. }
  53. const { scenario } = router.params
  54. if (process.env.TARO_ENV == 'weapp') {
  55. useShareAppMessage((e) => {
  56. return {
  57. title: '分享标题',
  58. path: 'pages/clock/Clock',
  59. imageUrl: shareUrl
  60. }
  61. })
  62. }
  63. useEffect(() => {
  64. const { events } = record
  65. events.map((item) => {
  66. if (item.scenario == scenario) {
  67. setInfo(item)
  68. setStatus(item.status)
  69. setLoaded(true)
  70. }
  71. })
  72. downloadFile()
  73. timer = setInterval(() => {
  74. if (showDatePicker || showEndDatePicker || showDurationPicker) return
  75. setCount(count => count + 1)
  76. }, 1000)
  77. return () => {
  78. clearInterval(timer)
  79. }
  80. }, [])
  81. function downloadFile() {
  82. Taro.downloadFile({
  83. url: 'https://background-pictures.oss-cn-beijing.aliyuncs.com/inapp/checkmark.png',
  84. success: (res) => {
  85. if (res.statusCode === 200) {
  86. global.checkImg = res.tempFilePath
  87. } else {
  88. }
  89. },
  90. fail: (err) => {
  91. }
  92. });
  93. }
  94. function tapClock() {
  95. if (status == 'WFS')
  96. setShowDurationPicker(true)
  97. }
  98. function start() {
  99. // var date = TimeFormatter.stringToDate(selDate, time)
  100. // date.setMilliseconds(new Date(enterTimestmap).getMilliseconds())
  101. var params: any = {
  102. scenario: scenario, //ACTIVITY
  103. type: 'INTERVAL',
  104. sub_type: scenario,
  105. time: {
  106. start_timestamp: new Date().getTime(),
  107. duration: info.time.duration
  108. }
  109. }
  110. if (router.params.join_id) {
  111. params.join_key = router.params.join_id
  112. }
  113. // if (event_id && event_id != 'undefined') {
  114. // params.event_id = event_id
  115. // }
  116. // if (is_temp) {
  117. // params.event = window == 'EAT' ? 'EAT_CUSTOM' : 'ACTIVE_CUSTOM'
  118. // }
  119. // params.op_page = window == 'EAT' ? 'HOME_EAT' : 'HOME_ACTIVE'
  120. params.extra = {
  121. set_time: global.set_time ? global.set_time : new Date().getTime(),
  122. confirm_time: new Date().getTime()
  123. }
  124. // console.log('打卡提交数据', params)
  125. // if (posting) return
  126. // setPosting(true)
  127. addEvents(params).then(res => {
  128. Taro.eventCenter.trigger('refreshClockIndex')
  129. setShowHighlight(true)
  130. setTimeout(() => {
  131. setShowHighlight(false)
  132. }, 3000)
  133. setInfo((res as any).data)
  134. setStatus((res as any).data.status)
  135. // Taro.showToast({
  136. // title: '成功',
  137. // icon: 'success'
  138. // })
  139. })
  140. }
  141. function end() {
  142. var params: any = {
  143. scenario: scenario, //ACTIVITY
  144. type: 'INTERVAL',
  145. sub_type: scenario,
  146. time: {
  147. end_timestamp: new Date().getTime()
  148. }
  149. }
  150. if (router.params.join_id) {
  151. params.join_key = router.params.join_id
  152. }
  153. params.extra = {
  154. set_time: global.set_time ? global.set_time : new Date().getTime(),
  155. confirm_time: new Date().getTime()
  156. }
  157. addEvents(params).then(res => {
  158. setShowHighlight(true)
  159. setTimeout(() => {
  160. setShowHighlight(false)
  161. }, 3000)
  162. Taro.eventCenter.trigger('refreshClockIndex')
  163. setInfo((res as any).data)
  164. setStatus((res as any).data.status)
  165. setShareUrl('')
  166. // Taro.showToast({
  167. // title: '成功',
  168. // icon: 'success'
  169. // })
  170. })
  171. }
  172. function update(params) {
  173. var data: any = {
  174. id: info.id,
  175. time: {
  176. ...params
  177. }
  178. }
  179. addEvents(data).then(res => {
  180. Taro.eventCenter.trigger('refreshClockIndex')
  181. setInfo((res as any).data)
  182. setShowDatePicker(false)
  183. setShowDurationPicker(false)
  184. setShowEndDatePicker(false)
  185. })
  186. }
  187. function tapStart() {
  188. setShowDatePicker(true)
  189. }
  190. function tapGoal() {
  191. setShowDurationPicker(true)
  192. }
  193. function ringExtra() {
  194. if (status == 'WFS') {
  195. const count = info.time.duration / 1000
  196. var str = TimeFormatter.formateDurationBySeconds(count)
  197. return {
  198. header: '',
  199. value: str,
  200. footer: 'Edit',
  201. color: MainColorType.orange
  202. }
  203. }
  204. var percent = 100 * (new Date().getTime() - info.time.start_timestamp) / info.time.duration
  205. percent = parseInt(percent + '')
  206. return {
  207. header: '',
  208. value: TimeFormatter.countdown(info.time.start_timestamp),
  209. footer: `ELAPSED ${percent}%`,
  210. color: MainColorType.g02
  211. }
  212. }
  213. function getBackground() {
  214. var time = record.time
  215. if (!time) return '#fff'
  216. const { background_colors } = time
  217. if (!background_colors) {
  218. return '#fff'
  219. }
  220. else if (background_colors.length == 1) {
  221. return background_colors[0]
  222. }
  223. return `linear-gradient(to bottom, ${background_colors[0]}, ${background_colors[1]})`
  224. }
  225. if (!loaded) {
  226. return <View style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
  227. <View className="main_bg" style={{ background: getBackground() }} />
  228. </View>
  229. }
  230. function doneComponent() {
  231. if (status == 'DONE') {
  232. return <View className="share_bg" style={{ justifyContent: 'flex-start' }}>
  233. {
  234. shareUrl.length == 0 && <View className="share_canvas"><RingProgress
  235. radius={125} canvasId="helloworld_share2"
  236. //scale={0.75}
  237. count={count}
  238. bgRing={{
  239. color: 'rgba(255,255,255,1)',
  240. width: 35
  241. }}
  242. real={{
  243. color: MainColorType.orange,
  244. width: 5,
  245. start: getStartArc(info.time.start_timestamp),
  246. duration: getDurationArc(info.time.start_timestamp, info.time.end_timestamp)
  247. }}
  248. extra={ringExtra()}
  249. isCompleted
  250. shareCover={
  251. url => {
  252. setShareUrl(url)
  253. }
  254. }
  255. /></View>
  256. }
  257. <View className="navi_bar" style={{ height: navigationBarHeight }}>
  258. <View style={{
  259. position: 'absolute',
  260. left: 0,
  261. right: 0,
  262. bottom: 0,
  263. height: 44,
  264. display: 'flex',
  265. alignItems: 'center',
  266. justifyContent: 'center'
  267. }}>
  268. <View style={{
  269. position: 'absolute',
  270. width: rpxToPx(92),
  271. height: rpxToPx(64),
  272. left: 22,
  273. top: 22 - rpxToPx(32)
  274. }}
  275. onClick={() => {
  276. Taro.navigateBack()
  277. }}>
  278. <IconClose color="#fff" width={rpxToPx(64)} height={rpxToPx(64)} />
  279. </View>
  280. </View>
  281. </View>
  282. <View className="share_card" style={{ background: MainColorType.orange, marginTop: rpxToPx(26) + navigationBarHeight }}>
  283. {
  284. shareUrl.length > 0 ? <Image src={shareUrl} style={{ width: rpxToPx(900), height: rpxToPx(720) }} /> :
  285. <View style={{ width: rpxToPx(900), height: rpxToPx(720), backgroundColor: MainColorType.g02 }} />
  286. }
  287. {
  288. <View className="operate_content" style={{ marginTop: rpxToPx(40) }}>
  289. <View className="operate_item" onClick={() => {
  290. setShowDatePicker(true)
  291. }}>
  292. <View className="g02 h24">STARTED</View>
  293. <View className="h44 bold" style={{ marginTop: rpxToPx(8), marginBottom: rpxToPx(8) }}>{TimeFormatter.dateTimeFormate(info.time.start_timestamp, true)}</View>
  294. <View className="h30 bold" style={{ color: MainColorType.white }}>Edit Start</View>
  295. </View>
  296. <View className="operate_item" onClick={() => {
  297. setShowEndDatePicker(true)
  298. }}>
  299. <View className="g02 h24">FINISHED</View>
  300. <View className="h44 bold" style={{ marginTop: rpxToPx(8), marginBottom: rpxToPx(8) }}>{TimeFormatter.dateTimeFormate(info.time.end_timestamp, true)}</View>
  301. <View className="h30 bold" style={{ color: MainColorType.white }}>Edit Finish</View>
  302. </View>
  303. </View>
  304. }
  305. </View>
  306. <ShareBtn>
  307. <NewButton
  308. type={NewButtonType.fill}
  309. color={MainColorType.success}
  310. width={rpxToPx(698)}
  311. height={rpxToPx(108)}
  312. title="Send to friends"
  313. />
  314. </ShareBtn>
  315. </View>
  316. }
  317. }
  318. function render() {
  319. return <View style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
  320. <View className="main_bg" style={{ background: getBackground() }} />
  321. <View className="navi_bar" style={{ height: navigationBarHeight }}>
  322. <View style={{
  323. position: 'absolute',
  324. left: 0,
  325. right: 0,
  326. bottom: 0,
  327. height: 44,
  328. display: 'flex',
  329. alignItems: 'center',
  330. justifyContent: 'center'
  331. }}>
  332. <Image src={require('@assets/_health/navi_back.png')} style={{
  333. position: 'absolute',
  334. width: rpxToPx(92),
  335. height: rpxToPx(64),
  336. left: 0,
  337. top: 22 - rpxToPx(32)
  338. }}
  339. onClick={() => {
  340. Taro.navigateBack()
  341. }}
  342. />
  343. <View className="h36 bold">upcoming fast</View>
  344. </View>
  345. </View>
  346. <View style={{ height: navigationBarHeight }} />
  347. <View className="progress_card">
  348. <View onClick={() => {
  349. tapClock()
  350. // setShowDurationPicker(true)
  351. }}>
  352. <RingProgress
  353. radius={125} canvasId="helloworld"
  354. //scale={0.75}
  355. count={count}
  356. bgRing={{
  357. color: 'rgba(255,255,255,0.25)',
  358. width: 35
  359. }}
  360. target={{
  361. color: 'rgba(255,255,255,0.5)',
  362. width: 35,
  363. start: status == 'WFS' ? getStartArc(new Date().getTime()) : getStartArc(info.time.start_timestamp),
  364. duration: status == 'WFS' ? getDurationArc(new Date().getTime(), new Date().getTime() + info.time.duration) : getDurationArc(info.time.start_timestamp, info.time.start_timestamp + info.time.duration)
  365. }}
  366. real={status == 'WFS' ? null : {
  367. color: MainColorType.orange,
  368. width: 35,
  369. start: getStartArc(info.time.start_timestamp),
  370. duration: getDurationArc(info.time.start_timestamp, new Date().getTime())
  371. }}
  372. extra={ringExtra()}
  373. />
  374. </View>
  375. {
  376. status == 'OG' && <View className="operate_content">
  377. <View className="operate_item" onClick={() => {
  378. setShowDatePicker(true)
  379. }}>
  380. <View className="g02 h24">STARTED</View>
  381. <View className="h44 bold" style={{ marginTop: rpxToPx(8), marginBottom: rpxToPx(8) }}>{TimeFormatter.dateTimeFormate(info.time.start_timestamp, true)}</View>
  382. <View className="h30 bold" style={{ color: MainColorType.orange }}>Edit Start</View>
  383. </View>
  384. <View className="operate_item" onClick={() => {
  385. setShowDurationPicker(true)
  386. }}>
  387. <View className="g02 h24">{TimeFormatter.formateDurationBySeconds(info.time.duration / 1000)} Goal</View>
  388. <View className="h44 bold" style={{ marginTop: rpxToPx(8), marginBottom: rpxToPx(8) }}>{TimeFormatter.dateTimeFormate(info.time.target_end_timestamp, true)}</View>
  389. <View className="h30 bold" style={{ color: MainColorType.orange }}>Edit Goal</View>
  390. </View>
  391. </View>
  392. }
  393. {
  394. status == 'WFS' && <NewButton
  395. type={NewButtonType.fill}
  396. title="Start fasting"
  397. width={rpxToPx(490)}
  398. height={rpxToPx(96)}
  399. color={MainColorType.orange}
  400. onClick={start}
  401. />
  402. }
  403. {
  404. status == 'OG' && <NewButton
  405. type={NewButtonType.fill}
  406. title="End fasting"
  407. width={rpxToPx(490)}
  408. height={rpxToPx(96)}
  409. color={MainColorType.orange}
  410. onClick={end}
  411. />
  412. }
  413. {
  414. status == 'OG' && <View className="share_icon">
  415. <Image onClick={() => {
  416. setShareUrl('')
  417. setShowShare(true)
  418. }} src={require('@assets/_health/wechat.png')} style={{
  419. width: rpxToPx(72),
  420. height: rpxToPx(72)
  421. }} />
  422. </View>
  423. }
  424. </View>
  425. {
  426. status == 'WFS' && <View className="eat_card" onClick={() => {
  427. Taro.redirectTo({
  428. url: `./log_record?scenario=${scenario == 'FAST' ? 'MEAL' : 'ACTIVITY'}`
  429. })
  430. }}>
  431. <View className="h30 bold">Or share your meals</View>
  432. <View className="h24 g02" style={{ marginTop: rpxToPx(12) }}>if you haven't started fasting yet</View>
  433. <View className="eat_card_arrow">
  434. <IconArrow width={rpxToPx(34)} color={MainColorType.g02} />
  435. </View>
  436. </View>
  437. }
  438. {
  439. status == 'OG' && <View className="eat_card" style={{ height: rpxToPx(120) }} onClick={() => {
  440. Taro.redirectTo({
  441. url: `./log_record?scenario=${scenario == 'FAST' ? 'MEAL' : 'ACTIVITY'}`
  442. })
  443. }}>
  444. <View className="h24 g02" style={{ marginTop: rpxToPx(12) }}>How are you feeling?</View>
  445. <View className="eat_card_arrow">
  446. <IconArrow width={rpxToPx(34)} color={MainColorType.g02} />
  447. </View>
  448. </View>
  449. }
  450. {/* {
  451. showDurationPicker && <Modal
  452. testInfo={null}
  453. dismiss={() => {
  454. setShowDurationPicker(false)
  455. }}
  456. confirm={() => { }}>
  457. {
  458. <NewDurationPicker type={DurationPickerType.normal} value={info.time.duration} onChange={(e) => {
  459. console.log(e)
  460. var obj = JSON.parse(JSON.stringify(info))
  461. obj.time.duration = e
  462. setInfo(obj)
  463. }} />
  464. }
  465. </Modal>
  466. } */}
  467. {
  468. showShare && <View className="share_bg">
  469. {
  470. shareUrl == '' && <View className="share_canvas">
  471. <RingProgress
  472. radius={125} canvasId="helloworld_share"
  473. //scale={0.75}
  474. count={count}
  475. bgRing={{
  476. color: 'rgba(255,255,255,0.25)',
  477. width: 35
  478. }}
  479. target={{
  480. color: 'rgba(255,255,255,0.5)',
  481. width: 35,
  482. start: status == 'WFS' ? getStartArc(new Date().getTime()) : getStartArc(info.time.start_timestamp),
  483. duration: status == 'WFS' ? getDurationArc(new Date().getTime(), new Date().getTime() + info.time.duration) : getDurationArc(info.time.start_timestamp, info.time.start_timestamp + info.time.duration)
  484. }}
  485. real={status == 'WFS' ? null : {
  486. color: MainColorType.orange,
  487. width: 35,
  488. start: getStartArc(info.time.start_timestamp),
  489. duration: getDurationArc(info.time.start_timestamp, new Date().getTime())
  490. }}
  491. extra={ringExtra()}
  492. shareBg={[record.time.background_colors[0], record.time.background_colors[1]]}
  493. shareCover={
  494. url => {
  495. setShareUrl(url)
  496. }
  497. }
  498. />
  499. </View>
  500. }
  501. <View className="navi_bar" style={{ height: navigationBarHeight }}>
  502. <View style={{
  503. position: 'absolute',
  504. left: 0,
  505. right: 0,
  506. bottom: 0,
  507. height: 44,
  508. display: 'flex',
  509. alignItems: 'center',
  510. justifyContent: 'center'
  511. }}>
  512. <View style={{
  513. position: 'absolute',
  514. width: rpxToPx(92),
  515. height: rpxToPx(64),
  516. left: 22,
  517. top: 22 - rpxToPx(32)
  518. }}
  519. onClick={() => {
  520. setShowShare(false)
  521. }}>
  522. <IconClose color="#fff" width={rpxToPx(64)} height={rpxToPx(64)} />
  523. </View>
  524. </View>
  525. </View>
  526. <View className="share_card" style={{ background: record.time.background_colors[1] }}>
  527. {
  528. shareUrl.length > 0 ? <Image src={shareUrl} style={{ width: rpxToPx(900), height: rpxToPx(720) }} /> :
  529. <View style={{ width: rpxToPx(900), height: rpxToPx(720), backgroundColor: MainColorType.g02 }} />
  530. }
  531. {
  532. status == 'OG' && <View className="operate_content" style={{ marginTop: rpxToPx(40) }}>
  533. <View className="operate_item">
  534. <View className="g02 h24">STARTED</View>
  535. <View className="h44 bold" style={{ marginTop: rpxToPx(8), marginBottom: rpxToPx(8) }}>{TimeFormatter.dateTimeFormate(info.time.start_timestamp, true)}</View>
  536. </View>
  537. <View className="operate_item">
  538. <View className="g02 h24">{TimeFormatter.formateDurationBySeconds(info.time.duration / 1000)} Goal</View>
  539. <View className="h44 bold" style={{ marginTop: rpxToPx(8), marginBottom: rpxToPx(8) }}>{TimeFormatter.dateTimeFormate(info.time.target_end_timestamp, true)}</View>
  540. </View>
  541. </View>
  542. }
  543. </View>
  544. <ShareBtn>
  545. <NewButton
  546. type={NewButtonType.fill}
  547. color={MainColorType.success}
  548. width={rpxToPx(698)}
  549. height={rpxToPx(108)}
  550. title="Send to friends"
  551. />
  552. </ShareBtn>
  553. </View>
  554. }
  555. </View>
  556. }
  557. return <View>
  558. {
  559. status == 'DONE' ? doneComponent() : render()
  560. }
  561. {
  562. showDatePicker && <PickerCard onClose={() => { setShowDatePicker(false) }}
  563. value={info.time.start_timestamp}
  564. type="datetime"
  565. onConfirm={(e) => {
  566. update({
  567. start_timestamp: e
  568. })
  569. console.log(e)
  570. // var obj = JSON.parse(JSON.stringify(info))
  571. // obj.time.duration = e
  572. // setInfo(obj)
  573. }}
  574. />
  575. }
  576. {
  577. showEndDatePicker && <PickerCard onClose={() => { setShowDatePicker(false) }}
  578. value={info.time.end_timestamp}
  579. type="datetime"
  580. onConfirm={(e) => {
  581. update({
  582. end_timestamp: e
  583. })
  584. console.log(e)
  585. // var obj = JSON.parse(JSON.stringify(info))
  586. // obj.time.duration = e
  587. // setInfo(obj)
  588. }}
  589. />
  590. }
  591. {
  592. showDurationPicker && <PickerCard onClose={() => { setShowDurationPicker(false) }}
  593. value={info.time.duration}
  594. type="duration"
  595. onConfirm={(e) => {
  596. var obj = JSON.parse(JSON.stringify(info))
  597. obj.time.duration = e
  598. setInfo(obj)
  599. if (status == 'WFS') return
  600. update({
  601. duration: e
  602. })
  603. }}
  604. />
  605. }
  606. </View>
  607. }