MainConsole.tsx 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187
  1. import { WindowStatusType, WindowType } from "@/utils/types";
  2. import { View, Text, Image, Swiper, SwiperItem } from "@tarojs/components";
  3. import dayjs from "dayjs";
  4. import { useEffect, useRef, useState } from "react";
  5. import { useDispatch, useSelector } from "react-redux";
  6. import './MainConsole.scss'
  7. import { jumpPage } from "../trackTimeDuration/hooks/Common";
  8. import Modal from "@/components/layout/Modal.weapp";
  9. import { MainColorType } from "@/context/themes/color";
  10. import ConsolePicker from "../trackTimeDuration/components/ConsolePicker";
  11. import { clockTimes, delRecord, getLabelsEvent, makeDone, updateEventDuration, updateFast, updateSchedule, updateTarget } from "@/services/health";
  12. import TimePicker from "../common/TimePicker";
  13. import showActionSheet from "@/components/basic/ActionSheet";
  14. import { rpxToPx } from "@/utils/tools";
  15. import { setMode, setShowActionTip } from "@/store/health";
  16. import { durationTime, getCountownTime, getDuration, getScenario, getThemeColor, getWindowStatus } from "./hooks/health_hooks";
  17. import { IconActive, IconArrow, IconCircle, IconClose, IconMiss, IconMore, IconNotification, IconNotificationOff, IconSwitch } from "@/components/basic/Icons";
  18. import DurationPicker from "@/_health/components/duration_picker";
  19. import Taro from "@tarojs/taro";
  20. import { systemLocation } from "@/services/common";
  21. import { TimeFormatter } from "@/utils/time_format";
  22. import { clearLocation } from "@/services/user";
  23. import OnBoard from "@/_health/components/onboard";
  24. import NewButton, { NewButtonType } from "@/_health/base/new_button";
  25. import showAlert from "@/components/basic/Alert";
  26. import { useTranslation } from "react-i18next";
  27. import Cell from "@/_health/base/cell";
  28. import ConsoleCell from "@/_health/components/console_cell";
  29. import IconTitleCell from "@/_health/components/icon_title_cell";
  30. import StatusIndicator, { StatusType } from "@/_health/base/status_indicator";
  31. import AddLabel from "@/_health/components/add_label";
  32. let useNavigation;
  33. let min = 0
  34. let max = 0
  35. let defaultTimestamp = 0
  36. let guideIndex = 0
  37. let lastFastSleepStatus = ''
  38. if (process.env.TARO_ENV == 'rn') {
  39. useNavigation = require("@react-navigation/native").useNavigation
  40. }
  41. export default function MainConsole(props: { type: WindowType }) {
  42. const health = useSelector((state: any) => state.health);
  43. const user = useSelector((state: any) => state.user);
  44. const [durationPicker, setDurationPicker] = useState(false)
  45. const [btnDisable, setBtnDisable] = useState(false)
  46. const [selItem, setSelItem] = useState<any>(null)
  47. const [hideGuideTip, setHideGuideTip] = useState(false)
  48. const [hideErrorTip, setHideErrorTip] = useState(false)
  49. const [labels, setLabels] = useState<any>([])
  50. const [showModal, setShowModal] = useState(false)
  51. const [hideEatArchiveTip, setHideEatArchiveTip] = useState(false)
  52. const [hideActiveArchiveTip, setHideActiveArchiveTip] = useState(false)
  53. const [hideFastTip, setHideFastTip] = useState(false)
  54. const [hideSleepTip, setHideSleepTip] = useState(false)
  55. const { t } = useTranslation()
  56. const dispatch = useDispatch()
  57. const scale = '?x-oss-process=image/format,webp/resize,w_200'//'?x-oss-process=image/resize,webp,w_200,limit_0'
  58. let navigation, showActionSheetWithOptions;
  59. if (useNavigation) {
  60. navigation = useNavigation()
  61. }
  62. useEffect(() => {
  63. if (user.isLogin) {
  64. refreshLabels()
  65. }
  66. }, [user.isLogin])
  67. function refreshLabels() {
  68. getLabelsEvent({ window: 'ACTIVE' }).then(res => {
  69. setLabels((res as any).labels)
  70. })
  71. }
  72. useEffect(() => {
  73. if (health.fast_with_sleep.status == 'OG2_MISALIGNED' || health.fast_with_sleep.status == 'OG2_NO1') {
  74. if (lastFastSleepStatus != health.fast_with_sleep.status) {
  75. setHideErrorTip(false)
  76. }
  77. }
  78. lastFastSleepStatus = health.fast_with_sleep.status
  79. }, [health.fast_with_sleep.status])
  80. global.chooseLocation = () => {
  81. chooseLocation()
  82. }
  83. global.postMomentSuccess = () => {
  84. if (health.mode == 'ACTIVE') {
  85. setHideActiveArchiveTip(false)
  86. global.hideActiveArchiveTip = false
  87. }
  88. else {
  89. setHideEatArchiveTip(false)
  90. global.hideEatArchiveTip = false
  91. }
  92. }
  93. global.postFastBeginSuccess = () => {
  94. setHideFastTip(false)
  95. global.hideFastTip = false
  96. }
  97. global.postSleepBeginSuccess = () => {
  98. setHideSleepTip(false)
  99. global.hideSleepTip = false
  100. }
  101. function edit(item) {
  102. if (item.scenario != 'FAST' && item.scenario != 'SLEEP') {
  103. return
  104. }
  105. if (item.action == 'NA' || item.action == 'POST_MOMENT' || 'SLEEP_WAKE_UP' == item.action) {
  106. return;
  107. }
  108. if (!user.isLogin) {
  109. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  110. return
  111. }
  112. console.log(item)
  113. setSelItem(item)
  114. }
  115. function record(item) {
  116. if (!user.isLogin) {
  117. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  118. return
  119. }
  120. if ((item.event == 'FAST_START' || item.event == 'FAST_END') && health.long_fast.status == 'OG') {
  121. showAlert({
  122. title: t('health.lf_progress_title'),
  123. content: t('health.lf_progress_desc'),
  124. showCancel: true,
  125. cancelText: t('health.cancel'),
  126. confirmText: t('health.switch'),
  127. confirm: () => {
  128. changeToIF();
  129. },
  130. cancel: () => {
  131. // Taro.showToast({
  132. // title: '已保存到发现页“长断食”',
  133. // icon: 'success'
  134. // })
  135. }
  136. })
  137. return
  138. }
  139. setSelItem(item)
  140. switch (item.action) {
  141. case 'START':
  142. {
  143. jumpPage(`/_health/pages/log_time?index=${health.mode == 'FAST' ? 0 : 1}&single=1&is_start=1&window=${health.mode}&op_page=${health.mode == 'FAST' ? 'HOME_FAST' : 'HOME_SLEEP'}`)
  144. }
  145. return;
  146. case 'END':
  147. {
  148. var sceniaro = getScenario(health.windows, health.mode)
  149. jumpPage(`/_health/pages/log_time?type=home&index=${health.mode == 'FAST' ? 3 : 2}&single=${sceniaro.status == 'OG' ? 1 : 0}&is_start=0&window=${health.mode}&op_page=${health.mode == 'FAST' ? 'HOME_FAST' : 'HOME_SLEEP'}`)
  150. }
  151. return;
  152. case 'MARK_DONE':
  153. {
  154. setBtnDisable(true)
  155. clockTimes('', {
  156. check_items: [{
  157. schedule_id: item.schedule_id,
  158. date: dayjs().format('YYYYMMDD'),
  159. timestamp: new Date().getTime()
  160. }]
  161. }).then(res => {
  162. Taro.showToast({
  163. title: '操作成功',
  164. icon: 'success'
  165. })
  166. global.refreshWindow()
  167. global.refreshHistory()
  168. }).catch(e => {
  169. })
  170. }
  171. return;
  172. }
  173. jumpPage(`/_health/pages/add_moment?moment=${JSON.stringify(item)}&title=${item.title}&schedule_id=${item.schedule_id}&event_id=${item.event_id}`)
  174. }
  175. function operateTitle(item) {
  176. return t('health.log')
  177. // switch (item.action) {
  178. // case 'START':
  179. // case 'END':
  180. // return '打卡'
  181. // case 'MARK_DONE':
  182. // return 'Action'
  183. // }
  184. // return '记录'
  185. }
  186. function itemTitle(item: any) {
  187. // if (health.mode == 'DAY' || health.mode == 'NIGHT') {
  188. // return item.title
  189. // }
  190. if (item.real) {
  191. return TimeFormatter.dayjsFormat(item.real.timestamp)
  192. // return dayjs(item.real.timestamp).format('MM-DD HH:mm')
  193. }
  194. if (!item.target || !item.target.timestamp) {
  195. return item.time_label
  196. }
  197. return TimeFormatter.dayjsFormat(item.target.timestamp)
  198. // return dayjs(item.target.timestamp).format('MM-DD HH:mm')
  199. }
  200. function itemValue(item: any) {
  201. let themeColor: any = getThemeColor(health.mode)
  202. // const scenario = getScenario(health.windows, health.mode)
  203. // if (item.action == 'END' && !scenario.real) {
  204. // themeColor = MainColorType.g01
  205. // }
  206. if (item.target && item.target.timestamp >= new Date().getTime()) {
  207. themeColor = MainColorType.g02
  208. }
  209. if (health.mode == 'DAY' || health.mode == 'NIGHT') {
  210. return null
  211. }
  212. if (item.action && item.action != 'NA') {
  213. if (health.mode == 'FAST' || health.mode == 'SLEEP') {
  214. if (item.action == 'POST_MOMENT') {
  215. return <IconArrow width={rpxToPx(34)} color={MainColorType.g02} />
  216. }
  217. }
  218. // else if (health.mode == 'ACTIVE' && item.action == 'POST_MOMENT') {
  219. // return <NewButton
  220. // color={themeColor}
  221. // type={NewButtonType.border}
  222. // title={operateTitle(item)}
  223. // width={rpxToPx(128)}
  224. // height={rpxToPx(72)}
  225. // bold={true}
  226. // onClick={() => record(item)} />
  227. // }
  228. return <NewButton
  229. color={themeColor}
  230. type={item.target && item.target.timestamp >= new Date().getTime() ? NewButtonType.alpha2 : NewButtonType.alpha}
  231. title={operateTitle(item)}
  232. width={rpxToPx(128)}
  233. height={rpxToPx(72)}
  234. bold={true}
  235. onClick={() => record(item)} />
  236. }
  237. if (item.action && item.action == 'NA') {
  238. // if (health.mode == 'FAST' || health.mode == 'SLEEP') {
  239. if (item.moment && item.moment.media && item.moment.media.length > 0) {
  240. return <Image
  241. src={item.moment.media[0].url+scale}
  242. mode="aspectFill"
  243. className="console_item_img gray_bg" />
  244. }
  245. else {
  246. return <IconArrow width={rpxToPx(34)} color={MainColorType.g02} />
  247. }
  248. // }
  249. }
  250. return <View />
  251. }
  252. function canTap(item) {
  253. if (health.mode == 'DAY' || health.mode == 'NIGHT') {
  254. return false;
  255. }
  256. if (!user.isLogin) {
  257. return false
  258. }
  259. if (!item.event_id) {
  260. return false
  261. }
  262. return true
  263. }
  264. function tapTimeline(item, inex) {
  265. if (health.mode == 'DAY' || health.mode == 'NIGHT') {
  266. return;
  267. }
  268. if (!user.isLogin) {
  269. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  270. return
  271. }
  272. if (!item.event_id) {
  273. return
  274. }
  275. var scenario = getScenario(health.windows, health.mode)
  276. var window_id = scenario.window_id
  277. var op_page = 'HOME_FAST'
  278. switch (health.mode) {
  279. case 'FAST':
  280. op_page = 'HOME_FAST'
  281. break
  282. case 'EAT':
  283. op_page = 'HOME_EAT'
  284. break
  285. case 'SLEEP':
  286. op_page = 'HOME_SLEEP'
  287. break
  288. case 'ACTIVE':
  289. op_page = 'HOME_ACTIVE'
  290. break
  291. }
  292. jumpPage(`/_health/pages/timeline_detail?event_id=${item.event_id}&schedule_id=${item.schedule_id}&op_page=${op_page}&window_id=${window_id}`)
  293. }
  294. function processIcon(index) {
  295. const time = new Date().getTime()
  296. const scenario = getScenario(health.windows, health.mode)
  297. const timeline = scenario.timeline[index]
  298. if (health.mode == 'DAY' || health.mode == 'NIGHT') {
  299. if (time > timeline.target.timestamp) {
  300. return <Image style={{ width: rpxToPx(24), height: rpxToPx(24) }} src={require('@assets/_health/checked.png')} />
  301. }
  302. return <IconCircle width={rpxToPx(32)} color={MainColorType.g02} />
  303. // return <View style={{width:rpxToPx(26),height:rpxToPx(26),borderRadius:rpxToPx(13),backgroundColor:'#fff'}}/>
  304. }
  305. // if (timeline.target.timestamp < new Date().getTime()) {
  306. // return <IconMiss color="#fff" width={rpxToPx(24)} />
  307. // }
  308. if (timeline.real) {
  309. return <Image style={{ width: rpxToPx(24), height: rpxToPx(24) }} src={require('@assets/_health/checked.png')} />
  310. }
  311. return <View style={{ width: rpxToPx(26), height: rpxToPx(26), borderRadius: rpxToPx(13), backgroundColor: '#fff' }} />
  312. // return timeline.reminder ? <IconNotification color="#fff" width={rpxToPx(24)} /> : <IconNotificationOff color="#fff" width={rpxToPx(24)} />
  313. }
  314. function timelineItem(item: any, index: number, count: number) {
  315. var strColor = ''
  316. if (item.real) {
  317. strColor = getThemeColor(health.mode)
  318. }
  319. else if (health.mode == 'DAY' || health.mode == 'NIGHT') {
  320. const time = new Date().getTime()
  321. const scenario = getScenario(health.windows, health.mode)
  322. const timeline = scenario.timeline[index]
  323. if (time > timeline.target.timestamp) {
  324. strColor = getThemeColor(health.mode)
  325. }
  326. else {
  327. strColor = 'transparent'
  328. }
  329. }
  330. else {
  331. strColor = 'transparent'
  332. }
  333. function statusView() {
  334. return <StatusIndicator type={StatusType.console}
  335. color={strColor}
  336. fontColor={item.real ? getThemeColor(health.mode) : MainColorType.g01}
  337. bold={item.real ? true : false}
  338. // color={new Date().getTime()<item.target.timestamp?MainColorType.g02:getThemeColor(health.mode)}
  339. text={itemTitle(item)}
  340. fontSize={rpxToPx(24)}
  341. >{
  342. (item.real || (health.mode == 'DAY' || health.mode == 'NIGHT')) ? processIcon(index) : <IconCircle width={rpxToPx(32)} color={MainColorType.g02} />
  343. }</StatusIndicator>
  344. }
  345. return <ConsoleCell
  346. status={statusView()}
  347. title={(item.moment && item.moment.title) ? item.moment.title : item.title}
  348. description={item.moment ? item.moment.description : null}
  349. right={itemValue(item)}
  350. disable={!canTap(item)}
  351. onClick={() => tapTimeline(item, index)}
  352. showLine={true}
  353. fullLine={count - 1 == index}
  354. />
  355. }
  356. function changeToIF() {
  357. updateFast({ fast_type: 'IF' }).then(res => {
  358. global.refreshWindow()
  359. })
  360. }
  361. function actionList() {
  362. var list: any = []
  363. switch (health.mode) {
  364. case 'ACTIVE':
  365. {
  366. if (!health.finish_setup) {
  367. list.push(t('health.finish_setup'))
  368. }
  369. list.push(t('health.log_more'))
  370. var scenario = getScenario(health.windows, 'ACTIVE')
  371. if (scenario.status != 'WFS') {
  372. list.push(t('health.mark_done'))
  373. }
  374. if (health.finish_setup) {
  375. list.push(t('health.edit_schedule'))
  376. }
  377. }
  378. break;
  379. case 'EAT':
  380. {
  381. if (!health.finish_setup) {
  382. list.push(t('health.finish_setup'))
  383. }
  384. list.push(t('health.log_more'))
  385. var scenario = getScenario(health.windows, 'EAT')
  386. if (scenario.status != 'WFS') {
  387. list.push(t('health.mark_done'))
  388. }
  389. if (health.finish_setup) {
  390. list.push(t('health.edit_schedule'))
  391. }
  392. }
  393. break;
  394. case 'FAST':
  395. case 'SLEEP':
  396. {
  397. if (!health.finish_setup) {
  398. list.push(t('health.finish_setup'))
  399. }
  400. const obj = getScenario(health.windows, health.mode)
  401. if (obj.window_id) {
  402. list.push(t('health.delete_log'))
  403. }
  404. if (health.finish_setup) {
  405. list.push(t('health.edit_schedule'))
  406. }
  407. }
  408. break;
  409. case 'DAY':
  410. case 'NIGHT':
  411. {
  412. list = [t('health.change_location'), t('health.clear_location')]
  413. }
  414. break;
  415. }
  416. return list;
  417. }
  418. function more() {
  419. if (!user.isLogin) {
  420. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  421. return
  422. }
  423. var strTitle = ''
  424. if (health.mode == 'DAY' || health.mode == 'NIGHT') {
  425. strTitle = getLocation()
  426. }
  427. else {
  428. const scenario = getScenario(health.windows, health.mode)
  429. if (scenario.status == 'WFS') {
  430. strTitle = durationTime(scenario.target.start_timestamp, scenario.target.end_timestamp)
  431. // var time = scenario.period.start_time+'-'+scenario.period.end_time
  432. // strTitle = t('health.my_period',{start:scenario.period.start_time,end:scenario.period.end_time})
  433. // strTitle = health.mode == 'FAST' ? t('health.my_fast_period',{time:time}) :
  434. // health.mode == 'EAT' ? t('health.my_eating_period',{time:time}) :
  435. // health.mode == 'SLEEP' ? t('health.my_sleep_period',{time:time}) :
  436. // t('health.my_activity_period',{time:time})
  437. }
  438. else {
  439. strTitle = t('health.log_progress')
  440. // strTitle = health.mode == 'FAST' ? t('health.fasting_progress') :
  441. // health.mode == 'EAT' ? t('health.meal_progress') :
  442. // health.mode == 'SLEEP' ? t('health.sleep_progress') :
  443. // t('health.activity_progress')
  444. }
  445. }
  446. showActionSheet({
  447. showActionSheetWithOptions: showActionSheetWithOptions,
  448. title: strTitle,
  449. itemList: actionList(),
  450. success: (res) => {
  451. tapActionSheet(res)
  452. }
  453. });
  454. }
  455. function getLocation() {
  456. var scenario = getScenario(health.windows, health.mode)
  457. if (!scenario.extra.choose_location) {
  458. return t('health.more_actions')
  459. }
  460. return `${getCity()}${Math.abs(parseInt(scenario.extra.lat))}°${parseInt(scenario.extra.lat) < 0 ? 'S' : 'N'} ${Math.abs(parseInt(scenario.extra.lng))}°${parseInt(scenario.extra.lng) < 0 ? 'W' : 'E'}`
  461. }
  462. function getCity() {
  463. var city = ''
  464. var scenario = getScenario(health.windows, health.mode)
  465. if (scenario.extra.address) {
  466. if (scenario.extra.address.city.length > 0) {
  467. city = scenario.extra.address.city
  468. }
  469. else if (scenario.extra.address.province.length > 0) {
  470. city = scenario.extra.address.province
  471. }
  472. else if (scenario.extra.address.country.length > 0) {
  473. city = scenario.extra.address.country
  474. }
  475. else {
  476. return ''
  477. // city = t('feature.track_time_duration.third_ring.unknown')
  478. }
  479. }
  480. else {
  481. return ''
  482. // city = t('feature.track_time_duration.third_ring.unknown')
  483. }
  484. return city + ' | '
  485. }
  486. function tapActionSheet(index) {
  487. var title = actionList()[index]
  488. switch (title) {
  489. case t('health.finish_setup'):
  490. tapGuide();
  491. break;
  492. case t('health.log_more'):
  493. if (health.mode == 'EAT') {
  494. jumpPage(`/_health/pages/add_moment?title=&is_temp=${true}`)
  495. }
  496. else {
  497. jumpPage(`/_health/pages/add_moment?title=&is_temp=${true}`)
  498. }
  499. break;
  500. case t('health.mark_done'):
  501. tapMakeDone()
  502. break
  503. case t('health.edit_schedule'):
  504. jumpPage('/_health/pages/schedules?mode=' + health.mode)
  505. break
  506. case t('health.delete_log'):
  507. {
  508. const obj = getScenario(health.windows, health.mode)
  509. showAlert({
  510. title: t('health.del_title'),
  511. content: '',
  512. cancelText: t('health.del_cancel'),
  513. confirmText: t('health.del_confirm'),
  514. showCancel: true,
  515. confirm: () => {
  516. delRecord({ ids: [obj.window_id] }).then(res => {
  517. global.refreshWindow()
  518. if ((res as any).status_change) {
  519. if ((res as any).status_change.previous != (res as any).status_change.current) {
  520. //灵动岛弹窗
  521. setTimeout(() => {
  522. dispatch(setShowActionTip({
  523. isShow: true,
  524. isCompleted: false
  525. }))
  526. }, 1000)
  527. }
  528. }
  529. })
  530. }
  531. })
  532. }
  533. break;
  534. case t('health.change_location'):
  535. chooseLocation()
  536. break
  537. case t('health.clear_location'):
  538. tapClearLocation()
  539. break
  540. }
  541. }
  542. function tapGuide() {
  543. jumpPage('/_health/pages/guide_begin')
  544. // showAlert({
  545. // title:'设置引导弹窗',
  546. // content:'设置引导描述',
  547. // showCancel:true,
  548. // cancelText:'稍后',
  549. // confirmText:'设置',
  550. // cancel:()=>{
  551. // },
  552. // confirm:()=>{
  553. // jumpPage('/_health/pages/guide_fast')
  554. // }
  555. // })
  556. }
  557. function tapMakeDone() {
  558. makeDone(getScenario(health.windows, health.mode).window_id).then(res => {
  559. global.refreshWindow()
  560. global.refreshHistory()
  561. if ((res as any).status_change) {
  562. if ((res as any).status_change.previous != (res as any).status_change.current) {
  563. //灵动岛弹窗
  564. setTimeout(() => {
  565. dispatch(setShowActionTip({
  566. isShow: true,
  567. isCompleted: false
  568. }))
  569. }, 1000)
  570. }
  571. }
  572. })
  573. }
  574. function detail() {
  575. const { day, night } = health.windows.night_day
  576. const { fast, eat } = health.windows.fast_eat
  577. const { sleep, active } = health.windows.sleep_active
  578. let list: any = []
  579. switch (health.mode) {
  580. case 'DAY':
  581. list = day.timeline
  582. if (day.extra.choose_location == false) {
  583. return <OnBoard title={t('health.sunrise_to_sunset')}
  584. desc={t('health.rise_to_set_desc')}
  585. btnTitle={t('health.choose_location')}
  586. onClick={chooseLocation}
  587. />
  588. }
  589. break;
  590. case 'NIGHT':
  591. list = night.timeline
  592. if (night.extra.choose_location == false) {
  593. return <OnBoard title={t('health.sunset_to_sunrise')}
  594. desc={t('health.set_to_rise_desc')}
  595. btnTitle={t('health.choose_location')}
  596. onClick={chooseLocation}
  597. />
  598. }
  599. break;
  600. case 'FAST':
  601. list = fast.timeline
  602. break;
  603. case 'EAT':
  604. list = eat.timeline
  605. break;
  606. case 'SLEEP':
  607. list = sleep.timeline
  608. break;
  609. case 'ACTIVE':
  610. list = active.timeline
  611. if (active.onboard == false && active.status == 'WFS') {
  612. var seconds = new Date().getSeconds()
  613. if (seconds % 1 == 0) {
  614. guideIndex++;
  615. if (guideIndex >= list.length) {
  616. guideIndex = 0
  617. }
  618. }
  619. // return <Swiper autoplay>
  620. // {
  621. // list.map((item, index) => {
  622. // return <SwiperItem key={index}>
  623. // <OnBoard title={item.title}
  624. // desc={item.time_label}
  625. // btnTitle="Action"
  626. // onClick={() => {
  627. // if (!user.isLogin) {
  628. // jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  629. // return
  630. // }
  631. // jumpPage('/_health/pages/active_plan?schedule=' + JSON.stringify(item))
  632. // }}
  633. // />
  634. // </SwiperItem>
  635. // })
  636. // }
  637. // </Swiper>
  638. return <OnBoard title={list[guideIndex].title}
  639. desc={list[guideIndex].time_label}
  640. btnTitle={t('health.add_my_first_activity')}
  641. onClick={() => {
  642. if (!user.isLogin) {
  643. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  644. return
  645. }
  646. // if (!health.finish_setup) {
  647. // showAlert({
  648. // title: '',
  649. // content: '在整个日程中,创建您的活动安排',
  650. // showCancel: true,
  651. // cancelText: '稍后',
  652. // confirmText: '立即设置',
  653. // cancel: () => {
  654. // global.showIndexAddActive(labels)
  655. // },
  656. // confirm: () => {
  657. // tapGuide()
  658. // }
  659. // })
  660. // return
  661. // }
  662. global.showIndexAddActive(labels)
  663. // setShowModal(true)
  664. // jumpPage('/_health/pages/active_plan?schedule=' + JSON.stringify(list.length > 0 ? list[0] : '{}'))
  665. }}
  666. />
  667. }
  668. break;
  669. }
  670. return <View>
  671. {
  672. list.map((item, index) => {
  673. return timelineItem(item, index, list.length)
  674. })
  675. }
  676. </View>
  677. }
  678. function switchText() {
  679. switch (health.mode) {
  680. case 'FAST':
  681. return t('health.switch_to', { scenario: t('health.eat') })
  682. case 'EAT':
  683. return t('health.switch_to', { scenario: t('health.fast') })
  684. case 'DAY':
  685. return t('health.switch_to', { scenario: t('health.night') })
  686. case 'NIGHT':
  687. return t('health.switch_to', { scenario: global.language == 'en' ? 'Day' : '白天' })//'Switch to Daylight'
  688. case 'SLEEP':
  689. return t('health.switch_to', { scenario: t('health.active') })
  690. case 'ACTIVE':
  691. return t('health.switch_to', { scenario: t('health.sleep') })
  692. }
  693. return ''
  694. }
  695. function tapSwitchBtn() {
  696. switch (health.mode) {
  697. case 'FAST':
  698. dispatch(setMode('EAT'));
  699. break
  700. case 'EAT':
  701. dispatch(setMode('FAST'));
  702. break
  703. case 'DAY':
  704. dispatch(setMode('NIGHT'));
  705. break
  706. case 'NIGHT':
  707. dispatch(setMode('DAY'));
  708. break
  709. case 'SLEEP':
  710. dispatch(setMode('ACTIVE'));
  711. break
  712. case 'ACTIVE':
  713. dispatch(setMode('SLEEP'));
  714. break
  715. }
  716. }
  717. function tapClearLocation() {
  718. Taro.showModal({
  719. title: t('feature.location.clear_alert_title'),
  720. content: t('feature.location.clear_alert_content'),
  721. success: function (res) {
  722. if (res.confirm) {
  723. clearLocation().then(res => {
  724. global.refreshWindow()
  725. })
  726. } else if (res.cancel) {
  727. console.log('用户点击取消')
  728. }
  729. }
  730. })
  731. }
  732. function chooseLocation() {
  733. if (!user.isLogin) {
  734. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  735. return
  736. }
  737. var scenario = getScenario(health.windows, health.mode)
  738. Taro.chooseLocation({
  739. latitude: scenario.extra.choose_location ? parseFloat(scenario.extra.lat + '') : undefined,
  740. longitude: scenario.extra.choose_location ? parseFloat(scenario.extra.lng + '') : undefined,
  741. success: function (res) {
  742. uploadLocation(res)
  743. },
  744. fail(res) {
  745. Taro.showToast({
  746. title: '位置修改失败!\n请重新选择就近位置',
  747. icon: 'none'
  748. })
  749. },
  750. complete(res) {
  751. }
  752. })
  753. }
  754. function uploadLocation(res) {
  755. var today = new Date()
  756. var yesterday = new Date(today.getTime() - 24 * 3600 * 1000)
  757. var tomorrow = new Date(today.getTime() + 24 * 3600 * 1000 * 5)
  758. var strYesterday = `${yesterday.getFullYear()}-${TimeFormatter.padZero(yesterday.getMonth() + 1)}-${TimeFormatter.padZero(yesterday.getDate())}`
  759. var strTomorrow = `${tomorrow.getFullYear()}-${TimeFormatter.padZero(tomorrow.getMonth() + 1)}-${TimeFormatter.padZero(tomorrow.getDate())}`
  760. Taro.showLoading({
  761. title: global.language == 'en' ? 'Loading' : '加载中'
  762. })
  763. systemLocation({
  764. lat: res.latitude,
  765. lng: res.longitude,
  766. name: res.name,
  767. address: res.address,
  768. date_start: strYesterday,
  769. date_end: strTomorrow,
  770. coordinate_system_standard: process.env.TARO_ENV == 'weapp' ? 'GCJ-02' : 'WGS-84'
  771. }).then(data => {
  772. global.refreshWindow()
  773. Taro.hideLoading()
  774. }).catch((e) => {
  775. Taro.hideLoading()
  776. })
  777. }
  778. function updateDuration(duration) {
  779. setDurationPicker(false)
  780. const scenario = getScenario(health.windows, health.mode)
  781. updateEventDuration(scenario.timeline[0].event_id, duration).then(res => {
  782. global.refreshWindow()
  783. })
  784. }
  785. function timePointClass() {
  786. if (getWindowStatus(health.windows, health.mode) == WindowStatusType.process) {
  787. return 'time_point time_point_animation'
  788. }
  789. return 'time_point'
  790. }
  791. function showMoreBtn() {
  792. if (health.mode == 'DAY' || health.mode == 'NIGHT') {
  793. if (!getScenario(health.windows, health.mode).extra.choose_location) {
  794. return false
  795. }
  796. }
  797. return true;
  798. }
  799. function getTitleColor() {
  800. if (getWindowStatus(health.windows, health.mode) == WindowStatusType.upcoming) {
  801. return MainColorType.g01
  802. }
  803. const scenario = getScenario(health.windows, health.mode)
  804. if (scenario.status == 'OG') {
  805. return getThemeColor(health.mode)
  806. }
  807. return '#000'
  808. }
  809. function polarCheck() {
  810. const scenario = getScenario(health.windows, health.mode)
  811. if (health.mode == 'DAY' && scenario.extra && scenario.extra.is_polar_day) {
  812. return <View className="console_tag_bg" style={{ backgroundColor: getThemeColor(health.mode) }}>
  813. <Image src={global.language == 'en' ? require('@assets/_health/tag_polar.png') : require('@assets/_health/tag_polar_day.png')} className="console_tag_img" />
  814. </View>
  815. }
  816. if (health.mode == 'NIGHT' && scenario.extra && scenario.extra.is_polar_night) {
  817. return <View className="console_tag_bg" style={{ backgroundColor: getThemeColor(health.mode) }}>
  818. <Image src={global.language == 'en' ? require('@assets/_health/tag_polar.png') : require('@assets/_health/tag_polar_night.png')} className="console_tag_img" />
  819. </View>
  820. }
  821. }
  822. function ogTime() {
  823. return <View className="time_count h30 bold" style={{
  824. backgroundColor: getThemeColor(health.mode)
  825. }}>
  826. {/* <View className="console_tag_bg" style={{backgroundColor:getThemeColor(health.mode)}}>
  827. <Image src={global.language=='en'?require('@assets/_health/tag_log.png'):require('@assets/_health/tag_record.png')} className="console_tag_img"/>
  828. </View> */}
  829. {
  830. getCountownTime(health.windows, health.mode)
  831. }
  832. </View>
  833. }
  834. function markDoneTip() {
  835. if (health.mode == 'DAY' && health.mode != 'NIGHT') return
  836. var scenario = getScenario(health.windows, health.mode)
  837. if (scenario.status != 'OG') return
  838. if (health.mode == 'EAT' && hideEatArchiveTip) return
  839. if (health.mode == 'ACTIVE' && hideActiveArchiveTip) return
  840. if (health.mode == 'FAST' && hideFastTip) return
  841. if (health.mode == 'SLEEP' && hideSleepTip) return
  842. function tipContent() {
  843. var strTime = ''
  844. var today = new Date().getDate()
  845. var date = new Date(scenario.archive_timestamp).getDate()
  846. if (today == date) {
  847. strTime = t('health.today_at', { time: dayjs(scenario.archive_timestamp).format('HH:mm') })
  848. }
  849. else {
  850. strTime = t('health.tomorrow_at', { time: dayjs(scenario.archive_timestamp).format('HH:mm') })
  851. }
  852. switch (health.mode) {
  853. case 'FAST':
  854. if (global.language == 'en') {
  855. return <Text className="h28">After you log <Text className="italic">End Fast</Text>,{'\n'}
  856. Your moments <Text className="bold">today</Text> will appear in <Text className="bold">Recents</Text>.</Text>
  857. }
  858. return <Text className="h28">在您记录完 <Text className="italic">结束断食</Text> 之后,{'\n'}
  859. 您<Text className="bold">今天</Text>的时刻将出现在<Text className="bold">最近</Text>中。</Text>
  860. case 'SLEEP':
  861. if (global.language == 'en') {
  862. return <Text className="h28">After you log <Text className="italic">Wake Up</Text>,{'\n'}
  863. Your moments <Text className="bold">today</Text> will appear in <Text className="bold">Recents</Text>.</Text>
  864. }
  865. return <Text className="h28">在您记录完 <Text className="italic">起床</Text> 之后,{'\n'}
  866. 您<Text className="bold">今天</Text>的时刻将出现在<Text className="bold">最近</Text>中。</Text>
  867. case 'EAT':
  868. if (global.language == 'en') {
  869. return <Text className="h28"><Text style={{ color: MainColorType.eat }}>{strTime}</Text> or after you <Text className="italic">Mark Done</Text>,{'\n'}
  870. Your moments <Text className="bold">today</Text> will appear in <Text className="bold">Recents</Text>.</Text>
  871. }
  872. return <Text className="h28"><Text style={{ color: MainColorType.eat }}>{strTime}</Text> 或在您 <Text className="italic">标记完成</Text> 之后,{'\n'}
  873. 您<Text className="bold">今天</Text>的时刻将出现在<Text className="bold">最近</Text>中。</Text>
  874. case 'ACTIVE':
  875. if (global.language == 'en') {
  876. return <Text className="h28"><Text style={{ color: MainColorType.active }}>{strTime}</Text> or after you <Text className="italic">Mark Done</Text>,{'\n'}
  877. Your moments <Text className="bold">today</Text> will appear in <Text className="bold">Recents</Text>.</Text>
  878. }
  879. return <Text className="h28"><Text style={{ color: MainColorType.active }}>{strTime}</Text> 或在您 <Text className="italic">标记完成</Text> 之后,{'\n'}
  880. 您<Text className="bold">今天</Text>的时刻将出现在<Text className="bold">最近</Text>中。</Text>
  881. }
  882. return <Text className="h28">1</Text>
  883. }
  884. return <View className="mark_done_tip" style={{
  885. backgroundColor: getThemeColor(health.mode) + '1A'
  886. }}>
  887. <View style={{ display: 'flex', flexDirection: 'column', flex: 1 }}>
  888. {
  889. tipContent()
  890. }
  891. </View>
  892. <NewButton type={NewButtonType.img} btnStyle={{
  893. height: rpxToPx(32),
  894. width: rpxToPx(32)
  895. }} onClick={() => {
  896. switch (health.mode) {
  897. case 'FAST':
  898. setHideFastTip(true)
  899. break;
  900. case 'EAT':
  901. setHideEatArchiveTip(true)
  902. break;
  903. case 'SLEEP':
  904. setHideSleepTip(true)
  905. break
  906. case 'ACTIVE':
  907. setHideActiveArchiveTip(true)
  908. break
  909. }
  910. }}>
  911. <IconClose color={MainColorType.g03} width={rpxToPx(32)} height={rpxToPx(32)} />
  912. </NewButton>
  913. </View>
  914. }
  915. if (health.mode == '') return <View />
  916. return <View className="main-console-bg">
  917. <Image className="main_arrow" src={require('@assets/images/center_arrow.png')} />
  918. <View className="main_summary">
  919. <View className="main_summary_time h30 bold" style={{
  920. marginTop: rpxToPx(14),
  921. }} >
  922. {polarCheck()}
  923. {getScenario(health.windows, health.mode).status == 'OG' ? ogTime() : getDuration(health.windows, health.mode)}
  924. </View>
  925. <Text className="main_summary_duration g01"
  926. style={{
  927. marginBottom: rpxToPx(30)
  928. }}>{getScenario(health.windows, health.mode).status == 'OG' ? getDuration(health.windows, health.mode) : getCountownTime(health.windows, health.mode)}
  929. </Text>
  930. <View className="border_footer_line" />
  931. </View>
  932. <View style={{ backgroundColor: '#fff', width: rpxToPx(750) }}>
  933. {
  934. detail()
  935. }
  936. </View>
  937. <View className="main_footer2">
  938. <View style={{ width: rpxToPx(316), height: rpxToPx(128), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
  939. <NewButton
  940. type={NewButtonType.link}
  941. title={switchText()}
  942. onClick={() => {
  943. tapSwitchBtn()
  944. }}
  945. >
  946. </NewButton>
  947. </View>
  948. {
  949. showMoreBtn() && <NewButton
  950. btnStyle={{
  951. position: 'absolute',
  952. top: rpxToPx(42),
  953. right: rpxToPx(40)
  954. }}
  955. type={NewButtonType.more}
  956. onClick={more}
  957. />
  958. }
  959. </View>
  960. {
  961. user.isLogin && (health.mode != 'DAY' && health.mode != 'NIGHT') && !hideGuideTip && !health.finish_setup && <View className="guide_tip h26" onClick={() => {
  962. tapGuide();
  963. setHideGuideTip(true)
  964. }}>{t('health.console_guide_tip')}
  965. <NewButton type={NewButtonType.img} btnStyle={{
  966. position: 'absolute',
  967. right: 0,
  968. top: 0,
  969. bottom: 0,
  970. width: rpxToPx(92)
  971. }} onClick={() => {
  972. setHideGuideTip(true)
  973. }}>
  974. <IconClose color={MainColorType.g03} width={rpxToPx(32)} height={rpxToPx(32)} />
  975. </NewButton>
  976. </View>
  977. }
  978. {/* {
  979. markDoneTip()
  980. } */}
  981. {/* {
  982. health.mode == 'ACTIVE' && <View>
  983. <View className="main_column_space" /><IconTitleCell
  984. icon={<IconActive width={rpxToPx(32)} color={MainColorType.active} />}
  985. title={t('health.move_more')}
  986. onClick={() => {
  987. jumpPage('/_health/pages/move')
  988. }}
  989. /></View>
  990. } */}
  991. {/* {
  992. (health.mode == 'FAST' || health.mode == 'SLEEP') && <View >
  993. <View className="main_column_space" />
  994. <IconTitleCell
  995. onClick={() => {
  996. if (health.long_fast.status == 'OG') {
  997. showAlert({
  998. title: '长断食进行中',
  999. content: '当前有一个正在进行的长断食记录,要转换为间歇性断食吗?',
  1000. showCancel: true,
  1001. cancelText: '取消',
  1002. confirmText: '确定',
  1003. confirm: () => {
  1004. updateFast({ fast_type: 'IF' }).then(res => {
  1005. global.refreshWindow()
  1006. jumpPage('/_health/pages/fast_sleep')
  1007. })
  1008. }
  1009. })
  1010. return
  1011. }
  1012. setTimeout(() => {
  1013. setHideErrorTip(true)
  1014. }, 1000)
  1015. jumpPage('/_health/pages/fast_sleep')
  1016. }}
  1017. showLine={health.mode == 'FAST'}
  1018. icon={<Image className="active_icon" src={require('@assets/_health/fast.png')} />}
  1019. title={t('health.fast_with_sleep')}
  1020. desc={<View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
  1021. {
  1022. fastWithSleepStatus()
  1023. }
  1024. {
  1025. !hideErrorTip && (health.fast_with_sleep.status == 'OG2_MISALIGNED' || health.fast_with_sleep.status == 'OG2_NO1') && <View style={{
  1026. backgroundColor: MainColorType.error,
  1027. width: rpxToPx(12),
  1028. height: rpxToPx(12),
  1029. borderRadius: rpxToPx(6),
  1030. marginLeft: rpxToPx(12),
  1031. marginRight: rpxToPx(0)
  1032. }} />
  1033. }
  1034. </View>}
  1035. />
  1036. </View>
  1037. } */}
  1038. {/* {
  1039. health.mode == 'FAST' && <IconTitleCell
  1040. onClick={() => {
  1041. jumpPage('/_health/pages/long_fast')
  1042. }}
  1043. icon={<Image className="active_icon" src={require('@assets/_health/fast.png')} />}
  1044. title={t('health.long_fast')}
  1045. desc={
  1046. longFastStatus()
  1047. }
  1048. />
  1049. } */}
  1050. <View className="circle" />
  1051. {
  1052. durationPicker && <DurationPicker
  1053. done={(time) => {
  1054. updateDuration(time)
  1055. }}
  1056. dismiss={() => {
  1057. setDurationPicker(false)
  1058. }} time={getScenario(health.windows, health.mode).target.duration} />
  1059. }
  1060. {
  1061. showModal && <AddLabel labels={labels}
  1062. window='ACTIVE'
  1063. disMiss={() => setShowModal(false)}
  1064. op_page='SCHEDULE_ACTIVE_SLEEP'
  1065. // onlyCheck={true}
  1066. // schedules={[]}
  1067. confirm={(res) => {
  1068. setShowModal(false)
  1069. if ((res as any).result) {
  1070. global.refreshWindow()
  1071. // dispatch(setSchedules((res as any).schedules))
  1072. // dispatch(setFooter((res as any).footer))
  1073. // setList((res as any).schedules)
  1074. // setErrors([])
  1075. }
  1076. else {
  1077. jumpPage('/_health/pages/schedules?mode=' + health.mode + '&error=' + JSON.stringify(res))
  1078. // setList((res as any).schedules)
  1079. // dispatch(setFooter((res as any).footer))
  1080. // setErrors((res as any).error_messages ? (res as any).error_messages : [])
  1081. }
  1082. }}
  1083. color={MainColorType.active} />
  1084. }
  1085. </View >
  1086. }