import { View, Text, Image } from "@tarojs/components"; import './move.scss' import { useDispatch, useSelector } from "react-redux"; import { getScenario, getThemeColor } from "@/features/health/hooks/health_hooks"; import { useEffect, useState } from "react"; import Taro, { useDidShow } from "@tarojs/taro"; import { checkStart, setResult } from "@/store/action_results"; import RequestType, { thirdPartRequest } from "@/services/thirdPartRequest"; import { setAuth } from "@/features/trackSomething/hooks/werun"; import { useTranslation } from "react-i18next"; import { getActiveMoves, getActiveMovesCurrent, uploadActiveMoves } from "@/services/health"; import dayjs from "dayjs"; import { TimeFormatter } from "@/utils/time_format"; import { jumpPage } from "@/features/trackTimeDuration/hooks/Common"; import { rpxToPx } from "@/utils/tools"; import { IconActive, IconMore, IconSit } from "@/components/basic/Icons"; import NewHeader, { NewHeaderType } from "../components/new_header"; import NewButton, { NewButtonType } from "../base/new_button"; import { MainColorType } from "@/context/themes/color"; import StatusIndicator, { StatusType } from "../base/status_indicator"; import showActionSheet from "@/components/basic/ActionSheet"; import ListFooter from "../components/list_footer"; import StickyDateList from "../components/sticky_date_list"; let timer let myScrollTop = 0 export default function Move() { const health = useSelector((state: any) => state.health); const [allowRun, setAllowRun] = useState(false) const [loaded, setLoaded] = useState(false) const [loadAuth, setLoadAuth] = useState(false) const [count, setCount] = useState(0) const [data, setData] = useState(null) const [list, setList] = useState([]) const [total, setTotal] = useState(0) const [index, setIndex] = useState(1) const [hideCurrentRecent, setHideCurrentRecent] = useState(false) const [moreActive, setMoreActive] = useState(false) const [hours, setHours] = useState([]) const [startDate, setStarteDate] = useState('') const [btnDisable,setBtnDisable] = useState(false) const [isPulling, setIsPulling] = useState(false) const [itemLayouts, setItemLayouts] = useState([]) const [showDate, setShowDate] = useState(false) const [date, setDate] = useState('') const [page, setPage] = useState(1) const [loading, setLoading] = useState(false) let navigation, showActionSheetWithOptions; const { t } = useTranslation() const dispatch = useDispatch() useEffect(() => { getMovesCurrent() getMovesHistory(1) checkAuth() timer = setInterval(() => { setCount((index) => index + 1) const date = new Date() if (date.getMinutes() == 10 && date.getSeconds() == 0) { getMovesCurrent() getMovesHistory(1) } }, 1000) return () => { myScrollTop = 0 clearInterval(timer) } }, []) useEffect(() => { if (list.length > 0) { setTimeout(() => { measureItemLayouts() }, 500) } }, [list]) function measureItemLayouts() { const query = Taro.createSelectorQuery() list.forEach((item, index) => { query.select(`#history-${index}`).boundingClientRect() }); query.exec((res) => { var layouts: any = [] res.forEach((rect, index) => { if (rect) { layouts[index] = rect.top + myScrollTop } }); setItemLayouts(layouts) }) } function checkAuth() { Taro.getSetting({ success: res => { //第一步,检测是否有授权 - 没有授权 if (!res.authSetting['scope.werun']) { setAllowRun(false) Taro.setStorage({ key: 'auth', data: false }) } else { setAllowRun(true) Taro.setStorage({ key: 'auth', data: true }) } setLoadAuth(true) } }) } useDidShow(() => { checkAuth() getMovesCurrent() getMovesHistory(1) }) global.updateMove = () => { getMovesCurrent() getMovesHistory(1) } function getMovesCurrent() { getActiveMovesCurrent().then(res => { setLoaded(true) setData(res) setStarteDate((res as any).start_date) var array = (res as any).hours var temps: any = [] for (var i = array.length - 1; i >= 0; i--) { var obj = array[i] if (obj.status != 'WFS') { temps.push(obj) } } setHours(temps) // setHours((res as any).hours.reverse()) }) } function getMovesHistory(page) { setIndex(page) // setIsPulling(true) setLoading(true) getActiveMoves({ page: page, limit: 10, } ).then(res => { if (page == 1) { setList((res as any).data) setTotal((res as any).total) } else { setList([...list, ...(res as any).data]) } setIsPulling(false) setLoading(false) }).catch(e => { setLoading(false) }) } function more() { if (loading) return; if (total == list.length) return; var index = page; index++; setPage(index) getMovesHistory(index) } function onScroll(e) { var top = e.detail.scrollTop myScrollTop = top if (e.detail.scrollTop > 70) { Taro.setNavigationBarTitle({ title:'Move Every Hour' }) } else { Taro.setNavigationBarTitle({ title:'' }) } if (itemLayouts.length > 0) { var i = -1 var date = '' list.forEach((item, index) => { if (top >= itemLayouts[index] - 50) { i = index var currentDate = (list[index].date + '').substring(0, 6) date = currentDate.substring(0, 4) + '年' + currentDate.substring(4, 6) + '月' } }) setShowDate(i != -1) setDate(date) } else { setShowDate(false) setDate('') } } function tapLog() { // if (getStatus() != 'open') { // return // } if (isExtra()) { return; } if (allowRun) { checkout() } else { setAuth(successAuth, refuseAuth, t) } } function successAuth() { Taro.setStorage({ key: 'auth', data: true }) setAllowRun(true) } function refuseAuth() { Taro.setStorage({ key: 'auth', data: false }) setAllowRun(false) } function checkout() { dispatch(checkStart()); getWeRunData(false) } function getWeRunData(autoCheck = false) { if (autoCheck) { return } else { dispatch(checkStart()); } // setTitle('打卡'); setAllowRun(true) let schedule_id = null const hour = currentHourPeriod() data.hours.map(item => { if (item.hour == hour) { schedule_id = item.schedule_id } }) if (btnDisable) return setBtnDisable(true) thirdPartRequest(RequestType.RequestTypeWXRunData).then(res => { console.log(res) uploadActiveMoves({ wechat_run: { encryptedData: (res as any).encryptedData, iv: (res as any).iv, }, start_date: startDate, date: dayjs().format('YYYYMMDD'), hour: hour, timestamp: new Date().getTime(), schedule_id: schedule_id }).then(res => { if ((res as any).error_code == 'WX_STEP_PARSE_FAIL') { retry(hour, schedule_id) return } // Taro.showToast({ // title: '上报成功', // icon: 'none' // }) // console.log(res) // console.log('move result') jumpPage('./post_result?data=' + JSON.stringify((res as any).post_result)) getMovesCurrent() getMovesHistory(1) setBtnDisable(false) }).catch(e=>{ setBtnDisable(false) }) }).catch(_ => { dispatch(setResult({ isSuccess: false }) as any) setBtnDisable(false) }) } function retry(hour, schedule_id) { Taro.login().then(res0 => { thirdPartRequest(RequestType.RequestTypeWXRunData).then(res => { uploadActiveMoves({ code: res0.code, wechat_run: { encryptedData: (res as any).encryptedData, iv: (res as any).iv, }, start_date: startDate, date: dayjs().format('YYYYMMDD'), hour: hour, timestamp: new Date().getTime(), schedule_id: schedule_id }).then(res => { if ((res as any).error_code == 'WX_STEP_PARSE_FAIL') { Taro.showToast({ title: '获取失败', icon: 'none' }) return } jumpPage('./post_result?data=' + JSON.stringify((res as any).post_result)) getMovesCurrent() getMovesHistory(1) }) }).catch(_ => { dispatch(setResult({ isSuccess: false }) as any) }) }) } function currentCheckHour() { let currentHour = new Date().getHours() const minute = new Date().getMinutes() if (minute < 10) { currentHour -= 1; if (currentHour < 0) { currentHour = 23 } } return currentHour } function currentHourChecked() { const currentHour = currentCheckHour() var isChecked = false data.hours.map((item) => { if (item.hour == currentHour && item.status != 'WFS') { isChecked = true } }) return isChecked; } function getStatus() { const minute = new Date().getMinutes() if (minute >= 50 || minute < 10) { var isChecked = currentHourChecked() if (isChecked) { return 'upcoming' } return 'open' } return 'upcoming' } function getDuration() { let now = new Date() let pre = new Date().getTime() if (now.getMinutes() < 10) { pre -= 3600 * 1000 } let next = pre + 3600 * 1000 if (currentHourChecked()) { pre = next next = pre + 3600 * 1000 } return dayjs(pre).format('HH:00') + '-' + dayjs(next).format('HH:00') } function getCurrentTarget() { let now = new Date() let pre = new Date().getTime() if (now.getMinutes() < 10) { pre -= 3600 * 1000 } if (currentHourChecked()) { pre += 3600 * 1000 } const hour = new Date(pre).getHours() for (var i = 0; i < data.hours.length; i++) { if (data.hours[i].hour == hour) { return `${data.hours[i].target_steps}`//`${data.hours[i].real_steps}/${data.hours[i].target_steps}` } } } function process() { return `${data.stat.active_hours} / ${data.stat.waking_hours}` } function currentHourPeriod() { const time = new Date() let hour = time.getHours() //假如00:09,则为23小时 if (time.getMinutes() < 10) { hour--; } if (hour < 0) { hour = 23 } return hour } function isExtra() { const hour = currentHourPeriod() var isFind = false data.hours.map((item) => { if (item.hour == hour) { isFind = true } }) return !isFind } function currentHistory(item) { var start = item.hour var isYesterday = start > new Date().getHours() var end = start + 1 start = (start + '').padStart(2, '0') end = (end + '').padStart(2, '0') return {start}:00-{end}:00 { item.is_extra && is Extra } {item.real_steps} / {item.target_steps} steps { item.status == 'MISSED' && Missed } { item.status == 'SEDENTARY' && } { item.status == 'ACTIVE' && } } function activeHour() { return Last {hours.length} Hour{hours.length == 1 ? '' : 's'} { !hideCurrentRecent && { hours.map((item, index) => { if (index >= 3 && !moreActive) return return { currentHistory(item) } }) } { hours.length > 3 && { setMoreActive(!moreActive) }} type={NewButtonType.link} fontSize={rpxToPx(24)} title={moreActive ? '收起' : `展开剩余${hours.length - 3}条`} btnStyle={{ minWidth: rpxToPx(170) }} /> } } { hours.length == 0 && No Active Hours Yet. } } function formatTimeInterval(startTimestamp, endTimestamp) { // 计算时间间隔(以秒为单位) const intervalSeconds = Math.floor((endTimestamp - startTimestamp) / 1000); // 处理负值的情况 if (intervalSeconds < 0) { throw new Error("End timestamp must be greater than start timestamp"); } // 如果时间间隔大于1小时 if (intervalSeconds >= 3600) { const hours = Math.floor(intervalSeconds / 3600); const minutes = Math.floor((intervalSeconds % 3600) / 60); const seconds = intervalSeconds % 60; return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; } else { // 如果时间间隔小于1小时 const minutes = Math.floor(intervalSeconds / 60); const seconds = intervalSeconds % 60; return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; } } function consoleFooter() { if (isExtra()) { var now = new Date() var target = new Date() target.setHours(data.hours[0].hour) target.setMinutes(50) target.setSeconds(0) target.setMilliseconds(0) var timestamp = target.getTime() if (now.getTime() > timestamp) { timestamp += 24 * 3600 * 1000 } return {formatTimeInterval(new Date().getTime(), timestamp)} } if (getStatus() == 'open') { if (new Date().getMinutes() < 10) { let time = new Date() time.setMinutes(10) time.setSeconds(0) time.setMilliseconds(0) // 获取总秒数 const totalSeconds = Math.floor((time.getTime() - new Date().getTime()) / 1000); // 计算小时、分钟和秒 // const hours = String(Math.floor(totalSeconds / 3600)).padStart(2, '0'); const minutes = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0'); const seconds = String(totalSeconds % 60).padStart(2, '0'); return Ending soon {minutes}:{seconds} } const pre = new Date().getTime() const next = new Date().getTime() + 3600 * 1000 return Check In available {dayjs(pre).format('HH:50')}-{dayjs(next).format('HH:10')} } const minute = new Date().getMinutes() var isChecked = currentHourChecked() if (isChecked && (minute < 10 || minute >= 50)) { debugger let time = new Date() time.setMinutes(50) time.setSeconds(0) time.setMilliseconds(0) // 获取总秒数 const totalSeconds = Math.floor((time.getTime() + 3600 * 1000 - new Date().getTime()) / 1000); // 计算小时、分钟和秒 // const hours = String(Math.floor(totalSeconds / 3600)).padStart(2, '0'); const minutes = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0'); const seconds = String(totalSeconds % 60).padStart(2, '0'); // return `${hours}:${minutes}:${seconds}`; return Opening soon {minutes}:{seconds} } let time = new Date() time.setMinutes(50) time.setSeconds(0) time.setMilliseconds(0) // 获取总秒数 const totalSeconds = Math.floor((time.getTime() - new Date().getTime()) / 1000); // 计算小时、分钟和秒 // const hours = String(Math.floor(totalSeconds / 3600)).padStart(2, '0'); const minutes = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0'); const seconds = String(totalSeconds % 60).padStart(2, '0'); return Opening soon {minutes}:{seconds} } function hourIndex() { const { time_slots } = data.period const str = getDuration() const hour = parseInt(str.substring(0, 2)) var selItem: any = null time_slots.map((item) => { if (item.hour == hour) { selItem = item; } }) return {/* */} {/* {selItem.type == 'SLEEP' ? 'SLEEP HOUR ' : 'WAKING HOUR '}{selItem.index} */} } function becomeTime() { var hour = new Date().getHours() var tHour = parseInt(getDuration().substring(0, 2)) if (isExtra()) { tHour = data.hours[0].hour } if (hour > tHour) { return `Check in begins at ${getDuration().substring(0, 2)}:50 tomorrow` } return `Check in begins at ${getDuration().substring(0, 2)}:50` } function consolePanel() { if (!allowRun) { return 你还没有开启步数授权 体验Move More需要您开启微信运动授权,点击下方按钮进行授权 去授权 } return {hourIndex()} {getDuration()} { isExtra() ? 'Sleep well.' : getStatus() == 'open' ? `Think you've hit ${getCurrentTarget()} steps this hour?` : `Hit ${getCurrentTarget()} steps within the hour` } { isExtra() ? : getStatus() == 'open' ? : // {becomeTime()} } { consoleFooter() } } function toolBtnText() { return `Upcoming (${data.hours.length - hours.length > 0 ? data.hours.length - hours.length : ''})` } function showMore() { showActionSheet({ showActionSheetWithOptions: showActionSheetWithOptions, title: t('health.more_actions'), itemList: [t('health.change_step_goal')], success: (res) => { if (res == 0) { jumpPage('./move_setting_time') } } }); } function tools() { return { jumpPage(`/_health/pages/move_schedule?hours=${JSON.stringify(data.hours)}`) }} > { showMore() }} /> } function summary() { return Summary { data.last_updated && 最近更新于 {dayjs(data.last_updated).format('HH:mm')} } Hours Sedentary {data.stat.sedentary_hours} / {data.stat.waking_hours} Hours Active {data.stat.active_hours} / {data.stat.waking_hours} Hours Missed {data.stat.missed_hours} / {data.stat.waking_hours} Total Steps {data.stat.real_steps} / {data.stat.target_steps} Total Calories {data.stat.real_calories} / {data.stat.target_calories} Total Distance {data.stat.real_distance} / {data.stat.target_distance} } function goDetail(item) { jumpPage('./move_detail?id=' + item.id) } function historyDate(item, index) { if (index == 0) { if (global.language == 'zh' && TimeFormatter.isToday(item.timestamp)) { return '今天' } if (global.language == 'zh' && TimeFormatter.isYesterday(item.timestamp)) { return '昨天' } return dayjs(item.timestamp).format('DD') } if (dayjs(item.timestamp).format('MM-DD') == dayjs(list[index - 1].timestamp).format('MM-DD')) { return '' } if (global.language == 'zh' && TimeFormatter.isToday(item.timestamp)) { return '今天' } if (global.language == 'zh' && TimeFormatter.isYesterday(item.timestamp)) { return '昨天' } return dayjs(item.timestamp).format('DD') } function historyMonth(item, index) { if (index == 0) { if (global.language == 'zh' && TimeFormatter.isToday(item.timestamp)) { return '' } if (global.language == 'zh' && TimeFormatter.isYesterday(item.timestamp)) { return '' } return dayjs(item.timestamp).format('MMM') } if (dayjs(item.timestamp).format('MM-DD') == dayjs(list[index - 1].timestamp).format('MM-DD')) { return '' } if (global.language == 'zh' && TimeFormatter.isToday(item.timestamp)) { return '' } if (global.language == 'zh' && TimeFormatter.isYesterday(item.timestamp)) { return '' } return dayjs(item.timestamp).format('MMM') } if (!loaded || !loadAuth) return return { setIsPulling(true) setPage(1) getMovesHistory(1) }} isPulling={isPulling} onScroll={onScroll} showDate={showDate} date={date} loadMore={more}> { consolePanel() } { tools() } { summary() } { activeHour() } { list.length > 0 && {t('health.recents')} { list.map((item, index) => { return goDetail(item)}> {/* {(item.date + '').substring(6, 8)} */} {historyDate(item,index)} {historyMonth(item,index)} Hours Active {item.active_hours} · Total Steps {item.stat.real_steps} {/* */} }) } } 0) && (total == list.length)} /> }