log_time.tsx 46 KB

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