import { WindowStatusType, WindowType } from "@/utils/types"; import { View, Text, Image, Swiper, SwiperItem } from "@tarojs/components"; import dayjs from "dayjs"; import { useEffect, useRef, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import './MainConsole.scss' import { jumpPage } from "../trackTimeDuration/hooks/Common"; import Modal from "@/components/layout/Modal.weapp"; import { MainColorType } from "@/context/themes/color"; import ConsolePicker from "../trackTimeDuration/components/ConsolePicker"; import { clockTimes, delRecord, makeDone, updateEventDuration, updateFast, updateSchedule, updateTarget } from "@/services/health"; import TimePicker from "../common/TimePicker"; import showActionSheet from "@/components/basic/ActionSheet"; import { rpxToPx } from "@/utils/tools"; import { setMode, setShowActionTip } from "@/store/health"; import { getCountownTime, getDuration, getScenario, getThemeColor, getWindowStatus } from "./hooks/health_hooks"; import { IconActive, IconArrow, IconCircle, IconClose, IconMiss, IconMore, IconNotification, IconNotificationOff, IconSwitch } from "@/components/basic/Icons"; import DurationPicker from "@/_health/components/duration_picker"; import Taro from "@tarojs/taro"; import { systemLocation } from "@/services/common"; import { TimeFormatter } from "@/utils/time_format"; import { clearLocation } from "@/services/user"; import OnBoard from "@/_health/components/onboard"; import NewButton, { NewButtonType } from "@/_health/base/new_button"; import showAlert from "@/components/basic/Alert"; import { useTranslation } from "react-i18next"; import Cell from "@/_health/base/cell"; import ConsoleCell from "@/_health/components/console_cell"; import IconTitleCell from "@/_health/components/icon_title_cell"; import StatusIndicator, { StatusType } from "@/_health/base/status_indicator"; let useNavigation; let min = 0 let max = 0 let defaultTimestamp = 0 let lastFastSleepStatus = '' if (process.env.TARO_ENV == 'rn') { useNavigation = require("@react-navigation/native").useNavigation } export default function MainConsole(props: { type: WindowType }) { const health = useSelector((state: any) => state.health); const user = useSelector((state: any) => state.user); const [durationPicker, setDurationPicker] = useState(false) const [btnDisable, setBtnDisable] = useState(false) const [selItem, setSelItem] = useState(null) const [hideGuideTip, setHideGuideTip] = useState(false) const [hideErrorTip, setHideErrorTip] = useState(false) const { t } = useTranslation() const dispatch = useDispatch() let navigation, showActionSheetWithOptions; if (useNavigation) { navigation = useNavigation() } useEffect(() => { }, [props.type]) // useEffect(() => { if (health.fast_with_sleep.status == 'OG2_MISALIGNED' || health.fast_with_sleep.status == 'OG2_NO1') { if (lastFastSleepStatus != health.fast_with_sleep.status) { setHideErrorTip(false) } } lastFastSleepStatus = health.fast_with_sleep.status }, [health.fast_with_sleep.status]) global.chooseLocation = () => { chooseLocation() } function edit(item) { if (item.scenario != 'FAST' && item.scenario != 'SLEEP') { return } if (item.action == 'NA' || item.action == 'POST_MOMENT' || 'SLEEP_WAKE_UP' == item.action) { return; } if (!user.isLogin) { jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation) return } console.log(item) setSelItem(item) } function record(item) { if (!user.isLogin) { jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation) return } if (item.event == 'FAST_START' && health.long_fast.status == 'OG') { showAlert({ title: '长断食进行中', content: '当前有一个正在进行的长断食记录,要转换为间歇性断食吗?', showCancel: true, cancelText: '取消', confirmText: '确定', confirm: () => { changeToIF(); } }) return } setSelItem(item) switch (item.action) { case 'START': { jumpPage(`/_health/pages/log_time?index=${health.mode == 'FAST' ? 0 : 1}&single=1&is_start=1&window=${health.mode}`) } return; case 'END': { var sceniaro = getScenario(health.windows, health.mode) 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}`) } return; case 'MARK_DONE': { setBtnDisable(true) clockTimes({ check_items: [{ schedule_id: item.schedule_id, date: dayjs().format('YYYYMMDD'), timestamp: new Date().getTime() }] }).then(res => { Taro.showToast({ title: '操作成功', icon: 'success' }) global.refreshWindow() global.refreshHistory() }).catch(e => { }) } return; } jumpPage(`/_health/pages/add_moment?moment=${JSON.stringify(item)}&title=${item.title}&schedule_id=${item.schedule_id}&event_id=${item.event_id}`) } function operateTitle(item) { return t('health.log') // switch (item.action) { // case 'START': // case 'END': // return '打卡' // case 'MARK_DONE': // return 'Action' // } // return '记录' } function itemTitle(item: any) { // if (health.mode == 'DAY' || health.mode == 'NIGHT') { // return item.title // } if (item.real) { return TimeFormatter.dayjsFormat(item.real.timestamp) // return dayjs(item.real.timestamp).format('MM-DD HH:mm') } if (!item.target || !item.target.timestamp) { return item.time_label } return TimeFormatter.dayjsFormat(item.target.timestamp) // return dayjs(item.target.timestamp).format('MM-DD HH:mm') } function itemValue(item: any) { let themeColor: any = getThemeColor(health.mode) // const scenario = getScenario(health.windows, health.mode) // if (item.action == 'END' && !scenario.real) { // themeColor = MainColorType.g01 // } if (item.target && item.target.timestamp >= new Date().getTime()) { themeColor = MainColorType.g02 } if (health.mode == 'DAY' || health.mode == 'NIGHT') { return null } if (item.action && item.action != 'NA') { if (health.mode == 'FAST' || health.mode == 'SLEEP') { if (item.action == 'POST_MOMENT') { return } } // else if (health.mode == 'ACTIVE' && item.action == 'POST_MOMENT') { // return record(item)} /> // } return = new Date().getTime() ? NewButtonType.alpha2 : NewButtonType.alpha} title={operateTitle(item)} width={rpxToPx(128)} height={rpxToPx(72)} bold={true} onClick={() => record(item)} /> } if (item.action && item.action == 'NA') { // if (health.mode == 'FAST' || health.mode == 'SLEEP') { if (item.moment && item.moment.media && item.moment.media.length > 0) { return } else { return } // } } return } function canTap(item) { if (health.mode == 'DAY' || health.mode == 'NIGHT') { return false; } if (!user.isLogin) { return false } if (!item.event_id) { return false } return true } function tapTimeline(item, inex) { if (health.mode == 'DAY' || health.mode == 'NIGHT') { return; } if (!user.isLogin) { jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation) return } if (!item.event_id) { return } jumpPage(`/_health/pages/timeline_detail?event_id=${item.event_id}&schedule_id=${item.schedule_id}`) } function getIconColor(index) { var color = getThemeColor(health.mode) const time = new Date().getTime() const scenario = getScenario(health.windows, health.mode) const timeline = scenario.timeline[index] if (health.mode == 'DAY' || health.mode == 'NIGHT') { if (time > timeline.target.timestamp) { return MainColorType.g03 } } if (timeline.real) { return MainColorType.g03 } if (timeline.target.timestamp < new Date().getTime()) { return MainColorType.error } return color } function processIcon(index) { const time = new Date().getTime() const scenario = getScenario(health.windows, health.mode) const timeline = scenario.timeline[index] if (health.mode == 'DAY' || health.mode == 'NIGHT') { if (time > timeline.target.timestamp) { return } return // return } // if (timeline.target.timestamp < new Date().getTime()) { // return // } if (timeline.real) { return } return // return timeline.reminder ? : } function timelineItem(item: any, index: number, count: number) { var strColor = '' if (item.real) { strColor = getThemeColor(health.mode) } else if (health.mode == 'DAY' || health.mode == 'NIGHT') { const time = new Date().getTime() const scenario = getScenario(health.windows, health.mode) const timeline = scenario.timeline[index] if (time > timeline.target.timestamp) { strColor = getThemeColor(health.mode) } else { strColor = 'transparent' } } else { strColor = 'transparent' } function statusView() { return { (item.real || (health.mode == 'DAY' || health.mode == 'NIGHT')) ? processIcon(index) : } } return tapTimeline(item, index)} showLine={true} fullLine={count - 1 == index} /> } function changeToIF() { updateFast({ fast_type: 'IF' }).then(res => { global.refreshWindow() }) } function actionList() { var list: any = [] switch (health.mode) { case 'ACTIVE': { if (!health.finish_setup) { list.push(t('health.finish_setup')) } list.push(t('health.log_extra_activity')) var scenario = getScenario(health.windows, 'ACTIVE') if (scenario.status != 'WFS') { list.push(t('health.mark_done')) } if (health.finish_setup) { list.push(t('health.edit_schedule')) } } break; case 'EAT': { if (!health.finish_setup) { list.push(t('health.finish_setup')) } list.push(t('health.log_extra_meal')) var scenario = getScenario(health.windows, 'EAT') if (scenario.status != 'WFS') { list.push(t('health.mark_done')) } if (health.finish_setup) { list.push(t('health.edit_schedule')) } } break; case 'FAST': case 'SLEEP': { if (!health.finish_setup) { list.push(t('health.finish_setup')) } const obj = getScenario(health.windows, health.mode) if (obj.window_id) { list.push(t('health.delete_current_record')) } if (health.finish_setup) { list.push(t('health.edit_schedule')) } } break; case 'DAY': case 'NIGHT': { list = [t('health.change_location'), t('health.clear_location')] } break; } return list; } function more() { if (!user.isLogin) { jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation) return } var strTitle = '' if (health.mode == 'DAY' || health.mode == 'NIGHT') { strTitle = getLocation() } else if (health.mode == 'EAT' || health.mode == 'ACTIVE') { const scenario = getScenario(health.windows, health.mode) if (scenario.archive_timestamp) { /*"Today's logs will be archived at 23:59." "Today's logs will be archived at 03:10 tomorrow." "今日记录将于 23:59 归档" "今日记录将于明天 23:59 归档"*/ var today = new Date().getDate() var date = new Date(scenario.archive_timestamp).getDate() strTitle = `今日记录将于${today == date ? '' : '明天'} ${dayjs(scenario.archive_timestamp).format('HH:mm')} 归档` } else { strTitle = t('health.more_actions') } } else { strTitle = t('health.more_actions') } showActionSheet({ showActionSheetWithOptions: showActionSheetWithOptions, title: strTitle, itemList: actionList(), success: (res) => { tapActionSheet(res) } }); } function getLocation() { var scenario = getScenario(health.windows, health.mode) if (!scenario.extra.choose_location) { return t('health.more_actions') } 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'}` } function getCity() { var city = '' var scenario = getScenario(health.windows, health.mode) if (scenario.extra.address) { if (scenario.extra.address.city.length > 0) { city = scenario.extra.address.city } else if (scenario.extra.address.province.length > 0) { city = scenario.extra.address.province } else if (scenario.extra.address.country.length > 0) { city = scenario.extra.address.country } else { city = t('feature.track_time_duration.third_ring.unknown') } } else { city = t('feature.track_time_duration.third_ring.unknown') } return city } function tapActionSheet(index) { var title = actionList()[index] switch (title) { case t('health.finish_setup'): tapGuide(); break; case t('health.log_extra_activity'): jumpPage(`/_health/pages/add_moment?title=&is_temp=${true}`) break; case t('health.log_extra_meal'): jumpPage(`/_health/pages/add_moment?title=加餐&is_temp=${true}`) break; case t('health.mark_done'): tapMakeDone() break case t('health.edit_schedule'): jumpPage('/_health/pages/schedules?mode=' + health.mode) break case t('health.delete_current_record'): { const obj = getScenario(health.windows, health.mode) showAlert({ title: 'del', content: '确认删除此记录?', showCancel: true, confirm: () => { delRecord(obj.window_id).then(res => { global.refreshWindow() }) } }) } break; case t('health.change_location'): chooseLocation() break case t('health.clear_location'): tapClearLocation() break } } function tapGuide() { jumpPage('/_health/pages/guide_begin') // showAlert({ // title:'设置引导弹窗', // content:'设置引导描述', // showCancel:true, // cancelText:'稍后', // confirmText:'设置', // cancel:()=>{ // }, // confirm:()=>{ // jumpPage('/_health/pages/guide_fast') // } // }) } function tapMakeDone() { makeDone(getScenario(health.windows, health.mode).window_id).then(res => { global.refreshWindow() global.refreshHistory() }) } function detail() { const { day, night } = health.windows.night_day const { fast, eat } = health.windows.fast_eat const { sleep, active } = health.windows.sleep_active let list: any = [] switch (health.mode) { case 'DAY': list = day.timeline if (day.extra.choose_location == false) { return } break; case 'NIGHT': list = night.timeline if (night.extra.choose_location == false) { return } break; case 'FAST': list = fast.timeline break; case 'EAT': list = eat.timeline break; case 'SLEEP': list = sleep.timeline break; case 'ACTIVE': list = active.timeline if (active.onboard == false) { var seconds = new Date().getSeconds() // return // { // list.map((item, index) => { // return // { // if (!user.isLogin) { // jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation) // return // } // jumpPage('/_health/pages/active_plan?schedule=' + JSON.stringify(item)) // }} // /> // // }) // } // return { if (!user.isLogin) { jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation) return } jumpPage('/_health/pages/active_plan?schedule=' + JSON.stringify(list.length > 0 ? list[0] : '{}')) }} /> } break; } return { list.map((item, index) => { return timelineItem(item, index, list.length) }) } } function switchText() { switch (health.mode) { case 'FAST': return t('health.switch_to', { scenario: t('health.eat') }) case 'EAT': return t('health.switch_to', { scenario: t('health.fast') }) case 'DAY': return t('health.switch_to', { scenario: t('health.night') }) case 'NIGHT': return t('health.switch_to', { scenario: global.language == 'en' ? 'Daylight' : '白天' })//'Switch to Daylight' case 'SLEEP': return t('health.switch_to', { scenario: t('health.active') }) case 'ACTIVE': return t('health.switch_to', { scenario: t('health.sleep') }) } return '' } function tapSwitchBtn() { switch (health.mode) { case 'FAST': dispatch(setMode('EAT')); break case 'EAT': dispatch(setMode('FAST')); break case 'DAY': dispatch(setMode('NIGHT')); break case 'NIGHT': dispatch(setMode('DAY')); break case 'SLEEP': dispatch(setMode('ACTIVE')); break case 'ACTIVE': dispatch(setMode('SLEEP')); break } } function tapClearLocation() { Taro.showModal({ title: '提示', content: '确认清除位置数据?', success: function (res) { if (res.confirm) { clearLocation().then(res => { global.refreshWindow() }) } else if (res.cancel) { console.log('用户点击取消') } } }) } function chooseLocation() { if (!user.isLogin) { jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation) return } var scenario = getScenario(health.windows, health.mode) Taro.chooseLocation({ latitude: scenario.extra.choose_location ? parseFloat(scenario.extra.lat + '') : undefined, longitude: scenario.extra.choose_location ? parseFloat(scenario.extra.lng + '') : undefined, success: function (res) { uploadLocation(res) }, fail(res) { Taro.showToast({ title: '位置修改失败!\n请重新选择就近位置', icon: 'none' }) }, complete(res) { } }) } function uploadLocation(res) { var today = new Date() var yesterday = new Date(today.getTime() - 24 * 3600 * 1000) var tomorrow = new Date(today.getTime() + 24 * 3600 * 1000 * 5) var strYesterday = `${yesterday.getFullYear()}-${TimeFormatter.padZero(yesterday.getMonth() + 1)}-${TimeFormatter.padZero(yesterday.getDate())}` var strTomorrow = `${tomorrow.getFullYear()}-${TimeFormatter.padZero(tomorrow.getMonth() + 1)}-${TimeFormatter.padZero(tomorrow.getDate())}` systemLocation({ lat: res.latitude, lng: res.longitude, name: res.name, address: res.address, date_start: strYesterday, date_end: strTomorrow, coordinate_system_standard: process.env.TARO_ENV == 'weapp' ? 'GCJ-02' : 'WGS-84' }).then(data => { global.refreshWindow() }) } function updateDuration(duration) { setDurationPicker(false) const scenario = getScenario(health.windows, health.mode) updateEventDuration(scenario.timeline[0].event_id, duration).then(res => { global.refreshWindow() }) } function timePointClass() { if (getWindowStatus(health.windows, health.mode) == WindowStatusType.process) { return 'time_point time_point_animation' } return 'time_point' } function fastWithSleepStatus() { const { status } = health.fast_with_sleep var str = '' switch (status) { case 'OG1': str = t('health.fast_before_bed') break; case 'OG2_NO1': str = t('health.fast_missing') break; case 'OG2': str = t('health.fast_while_sleep') break; case 'OG2_MISALIGNED': str = t('health.misaligned') break; case 'OG3': str = t('health.fast_after_sleep') break } return {str} } function longFastStatus() { const { status } = health.long_fast return {status == 'OG' ? 'In progress' : ''} } function showMoreBtn() { if (health.mode == 'DAY' || health.mode == 'NIGHT') { if (!getScenario(health.windows, health.mode).extra.choose_location) { return false } } return true; } function getTitleColor() { if (getWindowStatus(health.windows, health.mode) == WindowStatusType.upcoming) { return MainColorType.g01 } const scenario = getScenario(health.windows, health.mode) if (scenario.status == 'OG') { return getThemeColor(health.mode) } return '#000' } function polarCheck() { const scenario = getScenario(health.windows, health.mode) if (health.mode == 'DAY' && scenario.extra && scenario.extra.is_polar_day) { return } if (health.mode == 'NIGHT' && scenario.extra && scenario.extra.is_polar_night) { return } } function ogTime() { return {/* */} { getCountownTime(health.windows, health.mode) } } return {polarCheck()} {getScenario(health.windows, health.mode).status == 'OG' ? ogTime() : getDuration(health.windows, health.mode)} {getScenario(health.windows, health.mode).status == 'OG' ? getDuration(health.windows, health.mode) : getCountownTime(health.windows, health.mode)} { detail() } { showMoreBtn() && } { user.isLogin && !hideGuideTip && !health.finish_setup && { tapGuide(); setHideGuideTip(true) }}>{t('health.console_guide_tip')} { setHideGuideTip(true) }}> } { health.mode == 'ACTIVE' && } title={t('health.move_more')} onClick={() => { jumpPage('/_health/pages/move') }} /> } { (health.mode == 'FAST' || health.mode == 'SLEEP') && { if (health.long_fast.status == 'OG') { showAlert({ title: '长断食进行中', content: '当前有一个正在进行的长断食记录,要转换为间歇性断食吗?', showCancel: true, cancelText: '取消', confirmText: '确定', confirm: () => { updateFast({ fast_type: 'IF' }).then(res => { global.refreshWindow() jumpPage('/_health/pages/fast_sleep') }) } }) return } setTimeout(() => { setHideErrorTip(true) }, 1000) jumpPage('/_health/pages/fast_sleep') }} showLine={health.mode == 'FAST'} icon={} title={t('health.fast_with_sleep')} desc={ { fastWithSleepStatus() } { !hideErrorTip && (health.fast_with_sleep.status == 'OG2_MISALIGNED' || health.fast_with_sleep.status == 'OG2_NO1') && } } /> } { health.mode == 'FAST' && { jumpPage('/_health/pages/long_fast') }} icon={} title={t('health.long_fast')} desc={ longFastStatus() } /> } { durationPicker && { updateDuration(time) }} dismiss={() => { setDurationPicker(false) }} time={getScenario(health.windows, health.mode).target.duration} /> } }