import { View, Text, Image } from "@tarojs/components"; import './MainCard.scss' import { useEffect, useRef, useState } from "react"; import Modal from "@/components/layout/Modal.weapp"; import { rpxToPx } from "@/utils/tools"; import Rings, { RingCommon, BgRing, TargetRing, CurrentDot } from "@/features/trackTimeDuration/components/Rings"; import dayjs from "dayjs"; import moment from 'moment-timezone' import { MainColorType } from "@/context/themes/color"; import { fastWindow, setSchedule, updateRecord } from "@/services/trackTimeDuration"; import { useDispatch, useSelector } from "react-redux"; import { jumpPage } from "../trackTimeDuration/hooks/Common"; import ConsolePicker from "../trackTimeDuration/components/ConsolePicker"; import { endFast, startFast } from "../trackTimeDuration/actions/TrackTimeActions"; import formatMilliseconds from "@/utils/format_time"; import TimePicker from "@/features/common/TimePicker"; import showAlert from "@/components/basic/Alert"; import showActionSheet from "@/components/basic/ActionSheet"; import { records } from "@/services/health"; import MainHistory from "./MainHistory"; import { WindowStatusType, WindowType } from "@/utils/types"; import { durationArc, isCurrentTimeInRange, startArc } from "./util"; import { setMode } from "@/store/health"; import { IconSwitch1, IconSwitch2 } from "@/components/basic/Icons"; import { getDurationArc, getScenario, getStartArc, getWindowStatus } from "./hooks/health_hooks"; let useNavigation; let checkNotification; let min = 0 let max = 0 let defaultTimestamp = 0 let useActionSheet; if (process.env.TARO_ENV == 'rn') { useNavigation = require("@react-navigation/native").useNavigation checkNotification = require('@/utils/native_permission_check').checkNotification; useActionSheet = require('@expo/react-native-action-sheet').useActionSheet } export default function MainFastEatCard(props: { count: any, typeChanged: Function, id: number, onClick: Function, scale: number }) { const [showModal, setShowModal] = useState(false) const [showTimePicker, setShowTimePicker] = useState(false); const limitPickerRef = useRef(null) const [operateType, setOperateType] = useState('startFast') const [btnDisable, setBtnDisable] = useState(false) const [logEvent, setLogEvent] = useState('LOG_ONCE'); const [eatData, setEatData] = useState(null) const [fastData, setFastData] = useState(null) const [status, setStatus] = useState('upcoming') const [showPicker, setShowPicker] = useState(false) const [isStart, setIsStart] = useState(true) const user = useSelector((state: any) => state.user); const health = useSelector((state: any) => state.health); const dispatch = useDispatch() const { fast, eat } = health.windows.fast_eat const t = new Date().getTime() const isTempFast = (fast.status == 'WAIT_FOR_END' || fast.target.start_time <= t && fast.target.end_time >= t) || isCurrentTimeInRange(fast.period.start_time, fast.period.end_time) const [isFastMode, setIsFastMode] = useState(isTempFast) useEffect(() => { if (health.mode == 'FAST') { setIsFastMode(true) } else if (health.mode == 'EAT') { setIsFastMode(false) } }, [health.mode]) useEffect(() => { const { fast, eat } = health.windows.fast_eat var now = new Date().getTime() if ((fast.status == 'WAIT_FOR_END' || fast.target.start_time <= now && fast.target.end_time >= now) || isCurrentTimeInRange(fast.period.start_time, fast.period.end_time)) { setIsFastMode(true) dispatch(setMode('FAST')) } else { setIsFastMode(false) dispatch(setMode('EAT')) } setEatData(eat) setFastData(fast) update(fast) }, []) useEffect(() => { if (fastData) { update(fastData) } }, [props.count]) useEffect(() => { if (health.selTab == 1) { dispatch(setMode(isFastMode ? 'FAST' : 'EAT')) } }, [health.selTab, isFastMode]) function update(fast) { var now = new Date().getTime() if (fast.status == 'WAIT_FOR_END') { setStatus('process') } else if ((fast.target.start_timestamp <= now && fast.target.end_timestamp >= now) || isCurrentTimeInRange(fast.period.start_time, fast.period.end_time)) { // setStartTime(fast.period.start_time) setStatus('new') } else { setStatus('upcoming') } } const common: RingCommon = { useCase: 'ChooseScenario', radius: 23.5, lineWidth: 13, isFast: true, status: 'WAIT_FOR_START' } const bgRing: BgRing = { color: MainColorType.ringBg } function targetRing() { const { fast, eat } = health.windows.fast_eat var starts: any = fast.period.start_time.split(':') var ends: any = fast.period.end_time.split(':') const startSeconds: any = parseInt(starts[0] + '') * 60 + parseInt(starts[1] + '') const endSeconds: any = parseInt(ends[0] + '') * 60 + parseInt(ends[1] + '') const color = isFastMode ? MainColorType.fastLight : MainColorType.eatLight const startArc = isFastMode ? startSeconds / 1440 * 2 * Math.PI - Math.PI / 2 : endSeconds / 1440 * 2 * Math.PI - Math.PI / 2 const fastCount = endSeconds - startSeconds > 0 ? endSeconds - startSeconds : endSeconds - startSeconds + 1440 const eatCount = 1440 - fastCount const durationArc = isFastMode ? fastCount / 1440 * 2 * Math.PI : eatCount / 1440 * 2 * Math.PI if (isFastMode && getWindowStatus(health.windows, 'FAST') == WindowStatusType.process) { const scenario = getScenario(health.windows, 'FAST') return { color, startArc: getStartArc(scenario.target.start_timestamp), durationArc: getDurationArc(scenario.target.start_timestamp, scenario.target.end_timestamp) } } if (!isFastMode && getScenario(health.windows, 'EAT').real) { const scenario = getScenario(health.windows, 'EAT') return { color, startArc: getStartArc(scenario.target.start_timestamp), durationArc: getDurationArc(scenario.target.start_timestamp, scenario.target.end_timestamp) } } return { color, startArc, durationArc } } function realRing() { const status = getWindowStatus(health.windows, isFastMode ? 'FAST' : 'EAT') const scenario = getScenario(health.windows, isFastMode ? 'FAST' : 'EAT') if (status == WindowStatusType.upcoming) { return null // return { // color: '#cccccc', // startArc: getStartArc(new Date().getTime()), // durationArc: getDurationArc(new Date().getTime(), scenario.target.start_timestamp), // } } return { color: isFastMode ? MainColorType.fast : MainColorType.eat, startArc: getStartArc(scenario.target.start_timestamp), durationArc: getDurationArc(scenario.target.start_timestamp, new Date().getTime()) } } function currentDot() { if (health.mode == 'FAST' || health.mode == 'EAT') { const status = getWindowStatus(health.windows, isFastMode ? 'FAST' : 'EAT') return { color: status == WindowStatusType.upcoming ? '#B2B2B2' : isFastMode ? MainColorType.fast : MainColorType.eat, lineWidth: 2, borderColor: '#F5F5F5', offset: 0 } } return null; } function ring() { return } function modalContent() { global.set_time = new Date().getTime() return { setShowTimePicker(false) }} confirm={() => { }}> { timePickerContent() } } function timeContent() { return { setShowPicker(false) }} confirm={() => { }}> { pickerContent() } } function timePickerContent() { var title = operateType == 'endFast' ? '结束断食' : '开始断食' var color = MainColorType.fast var endTimestamp = 0 if (operateType == 'endFast') { endTimestamp = fastData.target.end_time } var duration = fastData.target.duration return { setShowTimePicker(false) }} min={min} max={max} current={defaultTimestamp} duration={duration} endTimestamp={endTimestamp} isFast={true} isEnd={operateType == 'endFast'} isTimeout={false} isLoading={btnDisable} onChange={(e) => { pickerConfirm(e, null) global.pauseIndexTimer = false }} /> } function pickerContent() { const timestamp = isStart ? fastData.target.start_time : fastData.target.end_time const strTime = dayjs(timestamp).format('HH:mm') return { confirmPickerTime(e) }} cancel={() => { setShowPicker(false) }} /> } function confirmPickerTime(strTime) { if (status != 'process') { setSchedule({ code: isStart ? 'FAST_START' : 'FAST_END', time: strTime }).then(res => { setShowPicker(false) }) } else { var startTime = dayjs(fastData.target.start_time).format('HH:mm:ss') var endTime = strTime + ':00' console.log(startTime, endTime) if (startTime == endTime) { showAlert({ title: '', content: '开始时间不能与结束时间相同' }) return; } updateRecord({ fast: { target_duration: getIntervalSeconds(startTime, endTime) * 1000 } }, fastData.id).then(res => { setShowPicker(false) }) } } function getIntervalSeconds(time1, time2) { // 将时间字符串转换为 Date 对象 const date1 = new Date(`2000-01-01T${time1}Z`); const date2 = new Date(`2000-01-01T${time2}Z`); // 计算两个 Date 对象之间的时间差 let intervalMs = date2.getTime() - date1.getTime(); // 如果 time2 比 time1 小, 说明跨天了, 需要加上一天的毫秒数 if (date2 < date1) { intervalMs += 24 * 60 * 60 * 1000; } // 返回间隔秒数 return Math.floor(intervalMs / 1000); } function pickerConfirm(t1: number, event: any) { if (btnDisable) { return } global.scenario = 'FAST' setBtnDisable(true) var date = new Date(t1) var setDate = new Date(global.set_time); date.setMilliseconds(setDate.getMilliseconds()); date.setSeconds(setDate.getSeconds()); t1 = date.getTime(); if (operateType == 'startFast') { startFast(t1, fastData.target_duration, event ? event : logEvent).then(res => { setBtnDisable(false) setShowTimePicker(false) }).catch(e => { setBtnDisable(false) }) } else { endFast(t1, event ? event : logEvent).then(res => { setBtnDisable(false) setShowTimePicker(false) }).catch(e => { setBtnDisable(false) }) } } if (!fastData) return return props.onClick()}> { ring() } {isFastMode ? 'Fast' : 'Eat'} { showModal && setShowModal(false)}> {props.count} } { showTimePicker && modalContent() } { showPicker && timeContent() } }