log_time.tsx 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096
  1. import { View, Text, Image } from "@tarojs/components";
  2. import './log_time.scss'
  3. import './fast_sleep.scss'
  4. import { useSelector } from "react-redux";
  5. import { useEffect, useRef, useState } from "react";
  6. import NewButton, { NewButtonType } from "../base/new_button";
  7. import { rpxToPx } from "@/utils/tools";
  8. import { getScenario, getThemeColor } from "@/features/health/hooks/health_hooks";
  9. import NewTimePicker from "../base/new_timepicker";
  10. import { IconCalendar, IconError } from "@/components/basic/Icons";
  11. import dayjs from "dayjs";
  12. import { useRouter } from "@tarojs/taro";
  13. import Card from "../components/card";
  14. import { MainColorType } from "@/context/themes/color";
  15. import Taro from "@tarojs/taro";
  16. import { clockTimes, fastWithSleep } from "@/services/health";
  17. import NewDurationPicker, { DurationPickerType } from "../base/new_durationpicker";
  18. import showAlert from "@/components/basic/Alert";
  19. import NewDatePicker, { NewDatePickerType } from "../base/new_date_picker";
  20. import ChooseDateTime from "../components/choose_date_time";
  21. import { TimeFormatter } from "@/utils/time_format";
  22. import StatusIndicator, { StatusType } from "../base/status_indicator";
  23. import { t } from "i18next";
  24. let useRoute;
  25. let useNavigation;
  26. let scenario = '';
  27. let AppState;
  28. if (process.env.TARO_ENV == 'rn') {
  29. useRoute = require("@react-navigation/native").useRoute
  30. useNavigation = require("@react-navigation/native").useNavigation
  31. AppState = require("react-native").AppState
  32. }
  33. export default function LogTime() {
  34. let router
  35. let navigation;
  36. if (useNavigation) {
  37. navigation = useNavigation()
  38. }
  39. if (process.env.TARO_ENV == 'rn') {
  40. router = useRoute()
  41. }
  42. else {
  43. router = useRouter()
  44. }
  45. const [enterTime, setEnterTime] = useState(new Date().getTime())
  46. const [enter_timestamp] = useState(new Date().getTime())
  47. const isSingle = router.params.single == '1'
  48. const isFast = router.params.window == 'FAST'
  49. const isStart = router.params.is_start == '1'
  50. const isFastWithSleep = router.params.is_fast_with_sleep == '1'
  51. const type = router.params.type
  52. const [data, setData] = useState<any>(null)
  53. const health = useSelector((state: any) => state.health);
  54. const [showGoal, setShowGoal] = useState(router.params.longfast)
  55. const tapIndex = router.params.index ?? 0
  56. const [longDuration, setLongDuration] = useState(24)
  57. const [expandIndex, setExpandIndex] = useState(router.params.initIndex ? router.params.initIndex : tapIndex)
  58. const [chooseDate, setChooseDate] = useState(false)
  59. const [array, setArray] = useState<any>([])
  60. const [errors, setErrors] = useState<any>([])
  61. const [showSuccess, setShowSuccess] = useState(false)
  62. const [conflicts, setConflicts] = useState<any>([])
  63. const [loaded, setLoaded] = useState(false)
  64. const [autoCheck, setAutoCheck] = useState(false)
  65. const [initCheck, setInitCheck] = useState(router.params.initCheck == '1')
  66. const [count, setCount] = useState(0)
  67. const [ignoreCheck, setIgnoreCheck] = useState(false)
  68. const [posting, setPosting] = useState(false)
  69. useEffect(() => {
  70. // if (isSingle) {
  71. // }
  72. loadData()
  73. var now = new Date()
  74. var t = now.getTime()
  75. now.setHours(0)
  76. now.setMilliseconds(0)
  77. now.setSeconds(0)
  78. now.setMinutes(0)
  79. var t2 = now.getTime()
  80. t2 += 24 * 3600 * 1000
  81. var left = t2 - t + 500
  82. //前端待处理,日期更新
  83. setTimeout(() => {
  84. setCount(count => count + 1)
  85. setArray(array => {
  86. array.map((item) => {
  87. item.today = false
  88. })
  89. return array;
  90. })
  91. }, left)
  92. if (process.env.TARO_ENV == 'rn') {
  93. AppState.addEventListener('change', handleAppStateChange);
  94. }
  95. Taro.onAppShow(() => {
  96. setCount(count => count + 1)
  97. })
  98. }, [])
  99. const handleAppStateChange = (nextAppState) => {
  100. if (nextAppState != 'active') {
  101. return
  102. }
  103. if (nextAppState == 'active') {
  104. setCount(count => count + 1)
  105. }
  106. };
  107. useEffect(() => {
  108. if (autoCheck) {
  109. if (ignoreCheck) {
  110. setIgnoreCheck(false)
  111. }
  112. else {
  113. tapCommit(true)
  114. }
  115. }
  116. if (initCheck && array.length > 0) {
  117. tapCommit(true, true)
  118. setInitCheck(false)
  119. }
  120. }, [array])
  121. function loadData() {
  122. fastWithSleep().then(res => {
  123. setData(res)
  124. initDatas(res)
  125. })
  126. }
  127. function getLongDuration() {
  128. var day = Math.floor(longDuration / 24)
  129. var hour = longDuration % 24
  130. var str = ''
  131. if (day > 0)
  132. str = day + '天'
  133. if (hour > 0)
  134. str += hour + '小时'
  135. return str
  136. }
  137. function initDatas(res = data) {
  138. const { fast, sleep, status } = res
  139. var list: any = []
  140. if (isSingle) {
  141. var timeline: any;
  142. var time = dayjs().format('HH:mm')
  143. var date = dayjs().format('YYYY-MM-DD')
  144. if (isFast) {
  145. timeline = isStart ? fast.timeline[0] : fast.timeline[1]
  146. Taro.setNavigationBarTitle({
  147. title: isStart ? fast.timeline[0].title : fast.timeline[1].title
  148. });
  149. //特殊处理单场景下,结束,超过24小时,picker设置为target_end_time
  150. if (!isStart && new Date().getTime() - fast.timeline[0].target.timestamp>=24*3600*1000) {
  151. time = dayjs(fast.timeline[1].target.timestamp).format('HH:mm')
  152. date = dayjs(fast.timeline[1].target.timestamp).format('YYYY-MM-DD')
  153. }
  154. }
  155. else {
  156. timeline = isStart ? sleep.timeline[0] : sleep.timeline[1]
  157. Taro.setNavigationBarTitle({
  158. title: isStart ? sleep.timeline[0].title : sleep.timeline[1].title
  159. });
  160. //特殊处理单场景下,结束,超过24小时,picker设置为target_end_time
  161. if (!isStart && new Date().getTime() - sleep.timeline[0].target.timestamp>=24*3600*1000) {
  162. time = dayjs(sleep.timeline[1].target.timestamp).format('HH:mm')
  163. date = dayjs(sleep.timeline[1].target.timestamp).format('YYYY-MM-DD')
  164. }
  165. }
  166. if (router.params.longfast) {
  167. Taro.setNavigationBarTitle({
  168. title: t('health.long_fast')
  169. })
  170. }
  171. list.push({
  172. event_id: timeline.event_id,
  173. schedule_id: timeline.schedule_id,
  174. time: time,
  175. date: date,
  176. extra: {
  177. set_time: enterTime,
  178. confirm_time: enterTime
  179. }
  180. })
  181. setExpandIndex(0)
  182. }
  183. else {
  184. for (var i = 0; i <= tapIndex; i++) {
  185. // if (type == 'home'){
  186. // if (tapIndex == 2){
  187. // if (i == 0 || i==3){
  188. // continue;
  189. // }
  190. // }
  191. // else if (tapIndex ==3){
  192. // if (i==1||i==2){
  193. // continue;
  194. // }
  195. // }
  196. // }
  197. var timeline: any;
  198. if (i == 0 || i == 3) {
  199. timeline = i == 0 ? fast.timeline[0] : fast.timeline[1]
  200. Taro.setNavigationBarTitle({
  201. title: i == 0 ? fast.timeline[0].title : fast.timeline[1].title
  202. });
  203. }
  204. else {
  205. timeline = i == 1 ? sleep.timeline[0] : sleep.timeline[1]
  206. Taro.setNavigationBarTitle({
  207. title: i == 1 ? sleep.timeline[0].title : sleep.timeline[1].title
  208. });
  209. }
  210. list.push({
  211. event_id: timeline.event_id,
  212. schedule_id: timeline.schedule_id,
  213. time: dayjs().format('HH:mm'),
  214. date: dayjs().format('YYYY-MM-DD'),
  215. extra: {
  216. set_time: enterTime,
  217. confirm_time: enterTime
  218. }
  219. })
  220. }
  221. //逆推初始化时间
  222. var fastStartTime = new Date().getTime()
  223. var fastEndTime = new Date().getTime()
  224. var sleepStartTime = new Date().getTime()
  225. var sleepEndTime = new Date().getTime()
  226. fastStartTime = fastEndTime - fast.target.duration
  227. var fastEndtoWakeDuration = 0
  228. var time1 = fast.period.end_time
  229. var time2 = sleep.period.end_time
  230. var t1 = parseInt(time1.split(':')[0]) * 60 + parseInt(time1.split(':')[1])
  231. var t2 = parseInt(time2.split(':')[0]) * 60 + parseInt(time2.split(':')[1])
  232. fastEndtoWakeDuration = t1 - t2 > 0 ? (t1 - t2) * 60 * 1000 : (t1 - t2) * 60 * 1000 + 24 * 3600 * 1000
  233. sleepEndTime = fastEndTime - fastEndtoWakeDuration//(fast.target.end_timestamp-sleep.target.end_timestamp)
  234. sleepStartTime = sleepEndTime - sleep.target.duration
  235. var isConflict = false;
  236. if (fast.real && fast.real.start_timestamp && fast.real.start_timestamp > fastStartTime) {
  237. isConflict = true;
  238. }
  239. else if (sleep.real && sleep.real.start_timestamp && sleep.real.start_timestamp > sleepStartTime) {
  240. isConflict = true;
  241. }
  242. else if (sleep.real && sleep.real.end_timestamp && sleep.real.end_timestamp > sleepEndTime) {
  243. isConflict = true;
  244. }
  245. if (!isConflict) {
  246. list[0].date = dayjs(fastStartTime).format('YYYY-MM-DD')
  247. list[0].time = dayjs(fastStartTime).format('HH:mm')
  248. list[1].date = dayjs(sleepStartTime).format('YYYY-MM-DD')
  249. list[1].time = dayjs(sleepStartTime).format('HH:mm')
  250. if (list.length > 2) {
  251. list[2].date = dayjs(sleepEndTime).format('YYYY-MM-DD')
  252. list[2].time = dayjs(sleepEndTime).format('HH:mm')
  253. }
  254. }
  255. if (fast.real && fast.real.start_timestamp) {
  256. list[0].date = dayjs(fast.real.start_timestamp).format('YYYY-MM-DD')
  257. list[0].disable = true
  258. list[0].time = dayjs(fast.real.start_timestamp).format('HH:mm')
  259. }
  260. if (sleep.real && sleep.real.start_timestamp) {
  261. list[1].date = dayjs(sleep.real.start_timestamp).format('YYYY-MM-DD')
  262. list[1].disable = true
  263. list[1].time = dayjs(sleep.real.start_timestamp).format('HH:mm')
  264. }
  265. if (list.length > 2 && sleep.real && sleep.real.end_timestamp) {
  266. list[2].date = dayjs(sleep.real.end_timestamp).format('YYYY-MM-DD')
  267. list[2].disable = true
  268. list[2].time = dayjs(sleep.real.end_timestamp).format('HH:mm')
  269. }
  270. }
  271. if (status == 'OG2_NO1' && isFastWithSleep) {
  272. list[0].time = ''
  273. list[0].date = ''
  274. }
  275. setArray(list)
  276. setLoaded(true)
  277. }
  278. function footerBtnColor() {
  279. if (isSingle) {
  280. return isFast ? MainColorType.fast : MainColorType.sleep
  281. }
  282. else {
  283. if (tapIndex == '1' || tapIndex == '2') return MainColorType.sleep
  284. }
  285. return MainColorType.fast
  286. }
  287. function getTimestamp(obj) {
  288. var time = obj.time
  289. // var hour = parseInt(time.split(':')[0])
  290. // var minute = parseInt(time.split(':')[1])
  291. // var date = obj.date
  292. var now = new Date(obj.date + 'T' + time + ':' + dayjs(enter_timestamp).format('ss'))
  293. now.setMilliseconds(new Date(enter_timestamp).getMilliseconds())
  294. // now.setHours(hour)
  295. // now.setMinutes(minute)
  296. // now.setSeconds(0)
  297. // now.setMilliseconds(0)
  298. var timestamp = now.getTime()
  299. return timestamp
  300. }
  301. function tapDone() {
  302. var findError = false
  303. for (var i = 0; i < array.length; i++) {
  304. var obj = array[i]
  305. var str = dayjs().format('HH:mm')
  306. var date = new Date(obj.date + ' ' + obj.time + ':00')
  307. var now = new Date()
  308. if (date.getTime() > now.getTime()) {
  309. // setTime(str)
  310. array[i].time = str
  311. console.log(str)
  312. setArray(array)
  313. setCount(count => count + 1)
  314. findError = true
  315. }
  316. }
  317. if (findError) {
  318. Taro.showToast({
  319. title: '不能超过当前时间',
  320. icon: 'none'
  321. })
  322. return
  323. }
  324. tapCommit(false)
  325. }
  326. function tapCommit(onlyCheck, firstCheck = false, save_confirm = null) {
  327. for (var i = 0; i < array.length; i++) {
  328. var obj = array[i]
  329. if (obj.time == '' || obj.date == '') {
  330. Taro.showToast({
  331. title: t('health.missing_date_time'),
  332. icon: 'none'
  333. })
  334. return;
  335. }
  336. }
  337. var list: any = []
  338. if (isSingle) {
  339. var obj = array[0]
  340. var timestamp = getTimestamp(obj)
  341. var params: any = {
  342. schedule_id: obj.schedule_id,
  343. event_id: obj.event_id ? obj.event_id : null,
  344. extra: obj.extra,
  345. date: dayjs(timestamp).format('YYYYMMDD'),
  346. timestamp: timestamp,
  347. }
  348. if (isStart) {
  349. params.duration = isFast ? data.fast.target.duration : data.sleep.target.duration
  350. }
  351. list.push(params)
  352. if (router.params.longfast && isStart) {
  353. list = [{
  354. schedule_id: health.long_fast.timeline[0].schedule_id,
  355. date: dayjs(timestamp).format('YYYYMMDD'),
  356. timestamp: timestamp,
  357. extra: {
  358. long_fast_goal: longDuration * 60,
  359. set_time: global.set_time ? global.set_time : new Date().getTime(),
  360. confirm_time: new Date().getTime()
  361. }
  362. }]
  363. }
  364. }
  365. else {
  366. if (type == 'home') {
  367. if (parseInt(tapIndex + '') == 2) {
  368. var obj = array[1]
  369. var timestamp = getTimestamp(obj)
  370. list.push({
  371. schedule_id: obj.schedule_id,
  372. event_id: obj.event_id ? obj.event_id : null,
  373. extra: obj.extra,
  374. date: dayjs(timestamp).format('YYYYMMDD'),
  375. timestamp: timestamp,
  376. })
  377. var obj2 = array[2]
  378. var timestamp2 = getTimestamp(obj2)
  379. list.push({
  380. schedule_id: obj2.schedule_id,
  381. event_id: obj.event_id ? obj.event_id : null,
  382. extra: obj2.extra,
  383. date: dayjs(timestamp2).format('YYYYMMDD'),
  384. timestamp: timestamp2,
  385. })
  386. }
  387. if (parseInt(tapIndex + '') == 3) {
  388. var obj = array[0]
  389. var timestamp = getTimestamp(obj)
  390. list.push({
  391. schedule_id: obj.schedule_id,
  392. event_id: obj.event_id ? obj.event_id : null,
  393. extra: obj.extra,
  394. date: dayjs(timestamp).format('YYYYMMDD'),
  395. timestamp: timestamp,
  396. })
  397. var obj2 = array[3]
  398. var timestamp2 = getTimestamp(obj2)
  399. list.push({
  400. schedule_id: obj2.schedule_id,
  401. event_id: obj.event_id ? obj.event_id : null,
  402. extra: obj2.extra,
  403. date: dayjs(timestamp2).format('YYYYMMDD'),
  404. timestamp: timestamp2,
  405. })
  406. }
  407. }
  408. else {
  409. // const { status } = data
  410. for (var i = 0; i <= tapIndex; i++) {
  411. if (firstCheck && i > 1) {
  412. }
  413. else {
  414. var obj = array[i]
  415. var timestamp = getTimestamp(obj)
  416. list.push({
  417. schedule_id: obj.schedule_id,
  418. event_id: obj.event_id ? obj.event_id : null,
  419. extra: obj.extra,
  420. date: dayjs(timestamp).format('YYYYMMDD'),
  421. timestamp: timestamp,
  422. })
  423. }
  424. }
  425. }
  426. }
  427. if (firstCheck && parseInt(router.params.initIndex) == 1) {
  428. var temps = [list[1], list[0]]
  429. commit(temps, onlyCheck, save_confirm)
  430. }
  431. else {
  432. commit(list, onlyCheck, save_confirm)
  433. }
  434. }
  435. function getLogMethod(list) {
  436. // if (isSingle) return 'LOG_ONCE'
  437. if (list.length == 1) return 'LOG_ONCE'
  438. const { status } = data
  439. if (status == 'OG2_MISALIGNED') return 'LOG_MULTIPLE'
  440. if (status == 'OG2_NO1') return 'LOG_MULTIPLE'
  441. if (status == 'WFS' && list.length > 1) return 'LOG_MULTIPLE'
  442. if (status == 'OG1' && list.length > 2) return 'LOG_MULTIPLE'
  443. if (status == 'OG2' && list.length > 3) return 'LOG_MULTIPLE'
  444. return 'LOG_ONCE'
  445. }
  446. function commit(list, onlyCheck, save_confirm) {
  447. const sortedData = list.sort((a, b) => {
  448. return b.extra.confirm_time - a.extra.confirm_time; // 降序
  449. });
  450. var params: any = {
  451. check_items: sortedData,
  452. op_page: isFastWithSleep ? 'FAST_WITH_SLEEP' : null,
  453. only_check: onlyCheck,
  454. log_method: getLogMethod(list),
  455. extra: {
  456. set_time: enterTime,
  457. confirm_time: new Date().getTime()
  458. }
  459. }
  460. if (save_confirm) {
  461. params.save_confirm = save_confirm
  462. }
  463. // console.log(new Date().getTime())
  464. // console.log(params)
  465. // return
  466. if (posting) return
  467. setPosting(true)
  468. clockTimes(params).then(res => {
  469. setPosting(false)
  470. if ((res as any).result) {
  471. setErrors([])
  472. setConflicts([])
  473. if (!onlyCheck) {
  474. global.refreshWindow()
  475. if (global.refreshHistory)
  476. global.refreshHistory()
  477. if (global.refreshOtherHistory)
  478. global.refreshOtherHistory()
  479. if (global.refreshFastSleep)
  480. global.refreshFastSleep()
  481. if (global.refreshLongFast) {
  482. global.refreshLongFast()
  483. }
  484. Taro.redirectTo({
  485. url: './post_result?data=' + JSON.stringify(res)
  486. })
  487. }
  488. }
  489. else {
  490. if ((res as any).warn_code == 'SAVE_AS_LF') {
  491. showAlert({
  492. title: 'Saving as Long Fast',
  493. content: 'Fasting that lasts more than 24 hours will be saved as Long Fast. ',
  494. showCancel: true,
  495. cancelText: '取消',
  496. confirmText: '保存',
  497. cancel: () => {
  498. },
  499. confirm: () => {
  500. tapCommit(false, false, (res as any).warn_code)
  501. }
  502. })
  503. return
  504. }
  505. if ((res as any).warn_code == 'SAVE_AS_IF') {
  506. showAlert({
  507. title: 'Saving as Intermittent Fasting',
  508. content: 'Fasting that lasts fewer than 24 hours will be saved as Intermittent Fasting.',
  509. showCancel: true,
  510. cancelText: '取消',
  511. confirmText: '保存',
  512. cancel: () => {
  513. },
  514. confirm: () => {
  515. tapCommit(false, false, (res as any).warn_code)
  516. }
  517. })
  518. return
  519. }
  520. setErrors((res as any).error_messages)
  521. setConflicts((res as any).conflict_schedule_ids)
  522. setShowSuccess(true)
  523. setAutoCheck(true)
  524. var tempList = JSON.parse(JSON.stringify(array))
  525. tempList.map(item => {
  526. if ((res as any).conflict_schedule_ids.includes(item.schedule_id)) {
  527. item.disable = false
  528. }
  529. })
  530. setIgnoreCheck(true)
  531. setArray(tempList)
  532. }
  533. // Taro.navigateBack({
  534. // delta: 1
  535. // })
  536. }).catch(e => {
  537. setPosting(false)
  538. })
  539. }
  540. function changeToScheduleTime(schedule_time, index) {
  541. var nowTime = parseInt(dayjs().format('HHmm'))
  542. var scheduleTime = parseInt(schedule_time.replace(':', ''))
  543. var date = dayjs().format('YYYY-MM-DD')
  544. if (scheduleTime > nowTime) {
  545. date = dayjs(new Date().getTime() - 24 * 3600 * 1000).format('YYYY-MM-DD')
  546. }
  547. var list = JSON.parse(JSON.stringify(array))
  548. list[index].date = date
  549. list[index].time = schedule_time
  550. list[index].extra.confirm_time = new Date().getTime()
  551. setArray(list)
  552. }
  553. function durationTime() {
  554. const { fast, sleep } = data
  555. var seconds = isFast ? fast.target.duration / 1000 : sleep.target.duration / 1000
  556. var hour = Math.floor(seconds / 3600)
  557. var minutes = Math.floor((seconds % 3600) / 60)
  558. var str = ''
  559. if (hour > 0) {
  560. str = hour + TimeFormatter.getHoursUnit(hour)
  561. }
  562. if (minutes > 0) {
  563. str += minutes + TimeFormatter.getMinutesUnit(minutes)
  564. }
  565. if (hour == 0 && minutes == 0) {
  566. str = 0 + TimeFormatter.getMinutesUnit(0)
  567. }
  568. return str
  569. }
  570. function changeTimeText(schedule_time, time) {
  571. if (time == schedule_time) {
  572. return `Check in:Today ${dayjs(enterTime).format('HH:mm')}`
  573. }
  574. return `Scheduled for ${schedule_time}`
  575. }
  576. function tapChangeTime(schedule_time, time, index) {
  577. if (time == schedule_time) {
  578. changeToScheduleTime(dayjs(enterTime).format('HH:mm'), index)
  579. }
  580. else {
  581. changeToScheduleTime(schedule_time, index)
  582. }
  583. }
  584. function expectText() {
  585. var obj = array[0]
  586. var timestamp = getTimestamp(obj)
  587. var duration = isFast ? data.fast.target.duration : data.sleep.target.duration
  588. if (router.params.longfast) {
  589. duration = longDuration * 1000 * 3600
  590. }
  591. var time2 = timestamp + duration
  592. if (router.params.longfast) {
  593. return 'Expect to end fast at ' + dayjs(time2).format('MM-DD HH:mm')
  594. }
  595. var strTime = TimeFormatter.dayjsFormat(time2, false)
  596. if (isFast) {
  597. return 'Expect to end fast at ' + strTime
  598. }
  599. else {
  600. return 'Expect to wake up at ' + strTime
  601. }
  602. }
  603. function logItem(index: number, iFast: boolean, iStart: boolean, showLine: boolean) {
  604. const { fast, sleep, status } = data
  605. var schedule_time = ''
  606. var title = ''
  607. var date = array[index].date//array[index].today ? "Today" : "Yesterday"
  608. var time = array[index].time
  609. var min = enter_timestamp
  610. var max = new Date().getTime()
  611. if (iFast) {
  612. var timeline = index == 0 ? fast.timeline[0] : fast.timeline[1]
  613. if (!isFastWithSleep) {
  614. //首页单场景进入时时间限制处理逻辑
  615. var fastScenario = getScenario(health.windows, 'FAST')
  616. timeline = iStart ? fastScenario.timeline[0] : fastScenario.timeline[1]
  617. if (fastScenario.status == 'WFS') {
  618. min = enter_timestamp - 24 * 3600 * 1000
  619. max = new Date().getTime()
  620. }
  621. else {
  622. min = timeline.picker.min_timestamp
  623. max = timeline.picker.max_timestamp ?? new Date().getTime()
  624. }
  625. }
  626. else {
  627. //fast_sleep 进入时,除了wfs情况前端处理,其他case后端处理
  628. if (status == 'WFS') {
  629. min = enter_timestamp - 24 * 3600 * 1000
  630. max = new Date().getTime()
  631. }
  632. else if (status == 'OG2_MISALIGNED') {
  633. if (index == 0) {
  634. min = sleep.real.start_timestamp - 24 * 3600 * 1000
  635. max = sleep.real.start_timestamp
  636. }
  637. else {
  638. min = fast.real.start_timestamp
  639. max = new Date().getTime()
  640. }
  641. }
  642. else {
  643. min = timeline.picker.min_timestamp
  644. max = timeline.picker.max_timestamp ?? new Date().getTime()
  645. }
  646. }
  647. }
  648. else {
  649. var timeline = index == 1 ? sleep.timeline[0] : sleep.timeline[1]
  650. if (status == 'WFS') {
  651. min = enter_timestamp - 24 * 3600 * 1000
  652. max = new Date().getTime()
  653. }
  654. else if (status == 'OG2_MISALIGNED') {
  655. if (index == 1) {
  656. min = fast.real.start_timestamp
  657. }
  658. else {
  659. min = sleep.real.start_timestamp
  660. }
  661. max = new Date().getTime()
  662. }
  663. else {
  664. min = timeline.picker.min_timestamp
  665. max = timeline.picker.max_timestamp ?? new Date().getTime()
  666. }
  667. }
  668. const today = dayjs();
  669. var schedule_id = ''
  670. if (iFast) {
  671. schedule_time = iStart ? fast.period.start_time : fast.period.end_time
  672. schedule_id = iStart ? fast.timeline[0].schedule_id : fast.timeline[1].schedule_id
  673. if (!iStart && fast.status == 'OG') {
  674. schedule_time = dayjs(fast.target.end_timestamp).format('HH:mm')
  675. }
  676. title = iStart ? fast.timeline[0].title : fast.timeline[1].title
  677. if (array[index].disable) {
  678. var timestamp = iStart ? fast.real.start_timestamp : fast.real.end_timestamp
  679. date = dayjs(timestamp).format('YYYY-MM-DD')
  680. // const dt = dayjs(timestamp);
  681. // const yesterday = today.subtract(1, 'day');
  682. // time = dayjs(timestamp).format('HH:mm')
  683. // if (dt.isSame(today, 'day')) {
  684. // date = global.language == 'en' ? 'Today' : '今天';
  685. // } else if (dt.isSame(yesterday, 'day')) {
  686. // date = global.language == 'en' ? 'Yesterday' : '昨天';
  687. // } else {
  688. // date = global.language == 'en' ? dt.format('MMM D') : dt.format('MMMD日');
  689. // }
  690. }
  691. }
  692. else {
  693. schedule_time = iStart ? sleep.period.start_time : sleep.period.end_time
  694. schedule_id = iStart ? sleep.timeline[0].schedule_id : sleep.timeline[1].schedule_id
  695. if (!iStart && sleep.status == 'OG') {
  696. schedule_time = dayjs(sleep.target.end_timestamp).format('HH:mm')
  697. }
  698. title = iStart ? sleep.timeline[0].title : sleep.timeline[1].title
  699. if (array[index].disable) {
  700. var timestamp = iStart ? sleep.real.start_timestamp : sleep.real.end_timestamp
  701. date = dayjs(timestamp).format('YYYY-MM-DD')
  702. // const dt = dayjs(timestamp);
  703. // const yesterday = today.subtract(1, 'day');
  704. // time = dayjs(timestamp).format('HH:mm')
  705. // if (dt.isSame(today, 'day')) {
  706. // date = global.language == 'en' ? 'Today' : '今天';
  707. // } else if (dt.isSame(yesterday, 'day')) {
  708. // date = global.language == 'en' ? 'Yesterday' : '昨天';
  709. // } else {
  710. // date = global.language == 'en' ? dt.format('MMM D') : dt.format('MMMD日');
  711. // }
  712. }
  713. }
  714. var showError = false;
  715. if (conflicts.includes(schedule_id)) {
  716. showError = true
  717. }
  718. return <ChooseDateTime
  719. title={isSingle ? null : <StatusIndicator
  720. type={showError ? StatusType.img : StatusType.normal}
  721. color={showError ? MainColorType.error : iFast ? MainColorType.fast : MainColorType.sleep}
  722. fontColor="#000"
  723. fontSize={rpxToPx(34)}
  724. text={title}
  725. defaultSpace
  726. >
  727. {
  728. showError && <IconError color="#fff" width={rpxToPx(26)} />
  729. }
  730. </StatusIndicator>}
  731. disable={array[index].disable}
  732. showError={showError}
  733. showLine={showLine}
  734. footerTitle={changeTimeText(schedule_time, time)}
  735. tapFooter={() => tapChangeTime(schedule_time, time, index)}
  736. color={iFast ? MainColorType.fast : MainColorType.sleep}
  737. minTimestamp={min}
  738. maxTimestamp={max}
  739. date={date}
  740. time={time}
  741. count={count}
  742. expand={expandIndex == index}
  743. choose={() => {
  744. setExpandIndex(index)
  745. }}
  746. dateChange={(e) => {
  747. var list = JSON.parse(JSON.stringify(array))
  748. list[index].date = e
  749. list[index].extra.confirm_time = new Date().getTime()
  750. setArray(list)
  751. }}
  752. timeChange={(e) => {
  753. var list = JSON.parse(JSON.stringify(array))
  754. list[index].time = e
  755. list[index].extra.confirm_time = new Date().getTime()
  756. setArray(list)
  757. }}
  758. />
  759. }
  760. function multiContent() {
  761. if (type == 'home') {
  762. switch (parseInt(tapIndex + '')) {
  763. case 2:
  764. return <View style={{ position: 'relative' }}>
  765. {
  766. logItem(1, false, true, false)
  767. }
  768. {
  769. logItem(2, false, false, false)
  770. }
  771. </View>
  772. case 3:
  773. return <View style={{ position: 'relative' }}>
  774. {
  775. logItem(0, true, true, false)
  776. }
  777. {
  778. logItem(3, true, false, false)
  779. }
  780. </View>
  781. }
  782. }
  783. const { status } = data
  784. switch (parseInt(tapIndex + '')) {
  785. case 1:
  786. return <View style={{ position: 'relative' }}>
  787. {
  788. logItem(0, true, true, true)
  789. }
  790. {
  791. logItem(1, false, true, false)
  792. }
  793. </View>
  794. case 2:
  795. return <View style={{ position: 'relative' }}>
  796. {
  797. logItem(0, true, true, true)
  798. }
  799. {
  800. logItem(1, false, true, true)
  801. }
  802. {
  803. logItem(2, false, false, false)
  804. }
  805. </View>
  806. case 3:
  807. return <View style={{ position: 'relative' }}>
  808. {
  809. logItem(0, true, true, true)
  810. }
  811. {
  812. logItem(1, false, true, true)
  813. }
  814. {
  815. logItem(2, false, false, true)
  816. }
  817. {
  818. logItem(3, true, false, false)
  819. }
  820. </View>
  821. }
  822. return <View style={{ position: 'relative' }}></View>
  823. }
  824. function goalCard() {
  825. if (isSingle && isStart && showGoal) {
  826. if (router.params.longfast) {
  827. return <Card>
  828. <View style={{ position: 'relative' }}>
  829. <View className="card_header" style={{ justifyContent: 'space-between' }}>
  830. <View className="h34" style={{ marginLeft: rpxToPx(12) }}>LongFast Goal</View>
  831. <NewButton
  832. type={expandIndex == -1 ? NewButtonType.alpha : NewButtonType.gray}
  833. color={isFast ? MainColorType.fast : MainColorType.sleep}
  834. height={rpxToPx(84)}
  835. title={getLongDuration()}
  836. fontNormal
  837. onClick={() => { setExpandIndex(-1) }}
  838. />
  839. {/* </View> */}
  840. </View>
  841. {
  842. expandIndex == -1 && <View style={{
  843. display: 'flex',
  844. flexDirection: 'column',
  845. alignItems: 'center'
  846. }}>
  847. <NewDurationPicker color={MainColorType.fast}
  848. type={DurationPickerType.long}
  849. value={longDuration}
  850. onChange={(e) => {
  851. setLongDuration(e)
  852. }}
  853. />
  854. </View>
  855. }
  856. </View>
  857. </Card>
  858. }
  859. else {
  860. return <Card>
  861. <View style={{ position: 'relative' }}>
  862. <View className="card_header" style={{ justifyContent: 'space-between' }}>
  863. <View className="h34" style={{ marginLeft: rpxToPx(12) }}>{isFast ? 'Fast Goal' : 'Sleep Goal'}</View>
  864. {/* <View style={{
  865. borderColor: expandIndex == -1 ? isFast ? MainColorType.fast : MainColorType.sleep : 'transparent',
  866. borderWidth: rpxToPx(2),
  867. borderRadius: rpxToPx(88 / 4),
  868. borderStyle: 'solid'
  869. }}> */}
  870. <NewButton
  871. type={expandIndex == -1 ? NewButtonType.alpha : NewButtonType.gray}
  872. color={isFast ? MainColorType.fast : MainColorType.sleep}
  873. height={rpxToPx(84)}
  874. width={rpxToPx(218)}
  875. title={durationTime()}
  876. fontNormal
  877. onClick={() => { setExpandIndex(-1) }}
  878. />
  879. {/* </View> */}
  880. </View>
  881. {
  882. expandIndex == -1 && <View style={{
  883. display: 'flex',
  884. flexDirection: 'column',
  885. alignItems: 'center'
  886. }}>
  887. <NewDurationPicker
  888. type={DurationPickerType.normal}
  889. value={isFast ? data.fast.target.duration : data.sleep.target.duration}
  890. onChange={e => {
  891. var temp = JSON.parse(JSON.stringify(data))
  892. if (isFast) {
  893. temp.fast.target.duration = e
  894. }
  895. else {
  896. temp.sleep.target.duration = e
  897. }
  898. setData(temp)
  899. }}
  900. color={isFast ? MainColorType.fast : MainColorType.sleep} />
  901. </View>
  902. }
  903. </View>
  904. </Card>
  905. }
  906. }
  907. return <View />
  908. }
  909. if (!loaded) return <View />
  910. return <View className="page_container">
  911. <View style={{ height: rpxToPx(36) }} />
  912. <Card>
  913. <View style={{ display: 'flex', flexDirection: 'column' }}>
  914. {
  915. errors.map((item, index) => {
  916. return <View className="error_bg" key={index}>
  917. <View className="error_icon_bg">
  918. <IconError color="#fff" width={rpxToPx(26)} />
  919. </View>
  920. <Text className="h24" style={{ lineHeight: rpxToPx(36) + 'px' }}>{item}</Text>
  921. </View>
  922. })
  923. }
  924. {
  925. autoCheck && showSuccess && errors.length == 0 && <View className="error_bg" style={{ backgroundColor: MainColorType.success + '1A' }}>
  926. <View className="error_icon_bg" style={{ backgroundColor: MainColorType.success }}>
  927. <Image src={require('@assets/_health/tip_check.png')} style={{ width: rpxToPx(26), height: rpxToPx(26) }} />
  928. </View>
  929. <Text className="h24" style={{ lineHeight: rpxToPx(36) + 'px' }}>成功提示</Text>
  930. </View>
  931. }
  932. {
  933. isSingle ? <View style={{ position: 'relative' }}>
  934. {
  935. logItem(0, isFast, isStart, false)
  936. }
  937. </View> : multiContent()
  938. }
  939. </View>
  940. </Card>
  941. <View style={{ height: rpxToPx(36) }} />
  942. {
  943. isSingle && isStart && !showGoal && <View style={{ height: rpxToPx(72), marginTop: rpxToPx(18) }}>
  944. <NewButton
  945. type={NewButtonType.link}
  946. title="Show More"
  947. onClick={() => {
  948. setShowGoal(true)
  949. }}
  950. />
  951. </View>
  952. }
  953. {
  954. goalCard()
  955. }
  956. {
  957. isSingle && isStart && showGoal && <View className="h24 g02" style={{
  958. width: rpxToPx(750), height: rpxToPx(84),
  959. display: 'flex',
  960. alignItems: 'center',
  961. justifyContent: 'center'
  962. }}>{expectText()}</View>
  963. }
  964. <View style={{ flex: 1 }} />
  965. {/* <View style={{ marginBottom: rpxToPx(128), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
  966. <NewButton
  967. color={footerBtnColor()}
  968. type={NewButtonType.fill}
  969. title={'Log'}
  970. width={rpxToPx(646)}
  971. height={rpxToPx(96)}
  972. disable={errors.length > 0}
  973. bold={true}
  974. onClick={() => tapCommit(false)} />
  975. </View> */}
  976. <View className="main_footer">
  977. <NewButton
  978. color={footerBtnColor()}
  979. type={NewButtonType.fill}
  980. title={t('health.log')}
  981. width={rpxToPx(646)}
  982. height={rpxToPx(96)}
  983. disable={errors.length > 0}
  984. bold={true}
  985. onClick={() => tapDone()} />
  986. </View>
  987. </View>
  988. }