| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738 |
- import { ColorType } from "@/context/themes/color";
- import { TimeFormatter } from "@/utils/time_format";
- import { View, Text } from "@tarojs/components";
- import { useEffect, useState } from "react";
- import { ChooseScenarioBtn, WorkoutEndBtn } from "../common/SpecBtns";
- import Taro, { useRouter } from "@tarojs/taro";
- import { WorkoutType } from "@/utils/types";
- import Modal from "@/components/layout/Modal";
- import PickerViews from "@/components/input/PickerViews";
- import { useDispatch, useSelector } from "react-redux";
- import { endSuccess, startSuccess } from "@/store/workout";
- import { uploadWorkout } from "@/services/workout";
- import './WorkoutStopWatch.scss'
- import Box from "@/components/layout/Box";
- import { rpxToPx } from "@/utils/tools";
- import MultiText from "@/components/view/MultiText";
- import { values } from "lodash";
- import { IconRadioCross, IconX } from "@/components/basic/Icons";
- var timer
- var lastStrTime
- var lastTimestamp
- export default function Component(props: { targetCount: any, end: Function }) {
- const router = useRouter();
- const workout = useSelector((state: any) => state.workout);
- const [index, setIndex] = useState(1)
- const [count, setCount] = useState(0)
- const [startTime, setStartTime] = useState(new Date().getTime())
- const [tempTime, setTempTime] = useState(0)
- // const [lastStrTime, setLastStrTime] = useState('')
- const [groups, setGroups] = useState<any[]>([])
- const [isDoing, setIsDoing] = useState(true)
- const [showModal, setShowModal] = useState(false)
- const [needTerminal, setNeedTerminal] = useState(false)
- const [isPaused, setIsPaused] = useState(false);
- const [isPosting, setIsPosting] = useState(false)
- const dispatch = useDispatch();
- const [pickerItems, setPickerItems] = useState<any[]>([])
- const [pickerValue, setPickerValue] = useState<any[]>([])
- const [lastPickerValue,setLastPickerValue] = useState<any[]>([])
- const [isEdit, setIsEdit] = useState(false)
- const [editIndex, setEditIdex] = useState(-1)
- useEffect(() => {
- if (router.params.restore) {
- Taro.getStorage({
- key: 'lastWorkout', success: function (res) {
- var workouts = JSON.parse(res.data)
- setGroups(workouts)
- var workObj = workouts[workouts.length - 1]
- setIndex(workObj.index)
- setStartTime(workObj.time)
- if (workObj.type == 'REST') {
- setIsDoing(false)
- }
- }, fail: function (err) {
- console.log(err, 'no cache')
- }
- })
- }
- else {
- var array = [{
- code: workout.item.code,
- index: index,
- time: startTime,
- duration: props.targetCount,
- type: 'WORK'
- }]
- setGroups(array)
- saveCache(array)
- dispatch(startSuccess({
- start: startTime,
- code: workout.item.code,
- duration: props.targetCount
- }))
- }
- var item = workout.item
- var items: any = []
- var selects: any = []
- item.schemas[0].values.map(obj => {
- var list: any = []
- var min = parseInt(obj.min + '')
- var max = parseInt(obj.max + '')
- var step = parseInt(obj.step + '')
- var defaultV = parseInt(obj.default_value)
- for (var i = min; i <= max; i = i + step) {
- list.push(i + obj.unit)
- }
- items.push(list)
- for (var i = 0; i < list.length; i++) {
- if (parseInt(list[i] + '') == defaultV) {
- selects.push(i)
- }
- }
- })
- setLastPickerValue(selects)
- setPickerValue(selects)
- setPickerItems(items)
- setLatestPicker()
- // setTimeout(()=>{
- // Taro.pageScrollTo({
- // scrollTop:100000,
- // duration:0
- // })
- // },100)
-
- }, [])
- useEffect(() => {
- if (!isPaused) {
- timer = setInterval(() => {
- setCount((count) => count + 1)
- }, 1000)
- }
- return () => clearInterval(timer)
- }, [isPaused])
- function resume() {
- if (timer) {
- clearInterval(timer)
- timer = null
- }
- timer = setInterval(() => {
- setCount((count) => count + 1)
- }, 1000)
- }
- function planTime() {
- var minutes = props.targetCount / 60
- return minutes + '分钟'
- }
- function durationTime() {
- var str = TimeFormatter.formateTimeNow(startTime)
- lastStrTime = str
- return str
- }
- function twoTimeDuration(start, end) {
- var time = Math.floor((end - start) / 1000);
- const hours = Math.floor(time / 3600);
- const minutes = Math.floor((time % 3600) / 60);
- const seconds = Math.floor(time % 60);
- var strDuration = ''
- if (hours > 0) {
- strDuration = `${hours}小时`
- }
- if (minutes > 0) {
- strDuration += `${minutes}分钟`
- }
- if (seconds > 0) {
- strDuration += `${seconds}秒`
- }
- return strDuration.length == 0 ? '1秒' : strDuration
- }
- function twoTimeFormateList(start, end) {
- var time = Math.floor((end - start) / 1000);
- if (time<1){
- time = 1
- }
- return TimeFormatter.workoutTimeAndUnitList(time)
- }
- function setLatestPicker(){
- if (lastPickerValue){
- setPickerValue(lastPickerValue)
- }
- for (var i=groups.length-1;i>=0;i--){
- var obj = groups[i]
- if (obj.pickerValue){
- setLastPickerValue(obj.pickerValue)
- setPickerValue(obj.pickerValue)
- return
- }
- }
-
-
- }
- function finish() {
- setTempTime(new Date().getTime())
- var schema = workout.item.schemas[0]
- if (workout.item.schemas[0].values.length > 0 && schema.format != 'TIME_SECONDS') {
- setLatestPicker()
- // if (groups[groups.length])
- clearInterval(timer)
- setShowModal(true)
- return
- }
- clearInterval(timer)
- timer = null
- resume()
- var array = groups;
- var time = new Date().getTime()
- array.push({
- code: workout.item.code,
- index: index,
- time: time,
- type: 'REST'
- })
- setIsDoing(false)
- setStartTime(time)
- setGroups(array)
- saveCache(array)
- }
- function start() {
- clearInterval(timer)
- timer = null
- resume()
- var array = groups;
- var time = new Date().getTime()
- array.push({
- code: workout.item.code,
- index: index + 1,
- time: time,
- type: 'WORK'
- })
- setStartTime(time)
- setIndex(index + 1)
- setIsDoing(true)
- setGroups(array)
- saveCache(array)
- }
- function saveCache(array) {
- Taro.setStorage({
- key: 'lastWorkout',
- data: JSON.stringify(array)
- })
- }
- function clearCache() {
- Taro.removeStorage({ key: 'lastWorkout' })
- }
- function formateDate(date) {
- return (date.getFullYear() + '') + (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
- }
- function getValue(str, unit) {
- var i = str.indexOf(unit)
- return str.substring(0, i)
- }
- function getUnit() {
- var schema = workout.item.schemas[0]
- var units = schema.values
- if (schema.format == 'TIME_SECONDS') {
- return units[units.length - 1].unit
- }
- else {
- return units.map(obj => obj.unit).join('·')
- }
- }
- function totalValue() {
- var count = 0
- var schema = workout.item.schemas[0]
- if (schema.format == 'TIME_SECONDS') {
- groups.map(item => {
- if (item.type == 'WORK') {
- var t = Math.floor((item.end - item.start) / 1000)
- t = t < 1 ? 1 : t
- console.log(t)
- count += t
- }
- })
- return count
- }
- for (var i = 0; i < groups.length; i++) {
- var obj = groups[i]
- if (obj.type == 'WORK') {
- var temp = 0
- if (schema.format == 'TIME_SECONDS') {
- temp = parseInt(obj.value + '') * 3600 + parseInt(obj.value2 + '') * 60 + parseInt(obj.value3 + '')
- }
- else {
- if (obj.value) {
- temp = parseInt(obj.value + '')
- }
- if (obj.value2) {
- temp *= parseInt(obj.value2 + '')
- }
- if (obj.value3) {
- temp *= parseInt(obj.value3 + '')
- }
- }
- count += temp
- }
- }
- return count
- }
- function postData() {
- setIsPosting(true)
- var date = new Date()
- var strDate = formateDate(date)
- var records: any = []
- for (var i = 0; i < groups.length; i++) {
- var obj = groups[i]
- if (obj.type == 'WORK') {
- obj.start = obj.time
- obj.end = groups[i + 1].time
- obj.value = groups[i + 1].value
- obj.value2 = groups[i + 1].value2
- obj.value3 = groups[i + 1].value3
- }
- else {
- if (i != groups.length - 1) {
- obj.start = obj.time
- obj.end = groups[i + 1].time
- }
- }
- }
- for (var i = groups.length - 1; i >= 0; i--) {
- var obj = groups[i]
- if (obj.type == 'REST') {
- groups.splice(i, 1)
- }
- else {
- break;
- }
- }
- var units = workout.item.schemas[0].values
- for (var i = 0; i < groups.length; i++) {
- var obj = groups[i]
- var values: any = []
- if (obj.type == 'WORK') {
- if (obj.value) {
- if (units) {
- values.push({
- value: getValue(obj.value, units[0].unit),
- unit: units[0].unit
- })
- }
- else {
- values.push({
- value: obj.value
- })
- }
- }
- if (obj.value2) {
- values.push({
- value: getValue(obj.value2, units[1].unit),
- unit: units[1].unit
- })
- }
- if (obj.value3) {
- values.push({
- value: getValue(obj.value3, units[2].unit),
- unit: units[2].unit
- })
- }
- }
- records.push({
- type: obj.type,
- start: {
- date: formateDate(new Date(obj.start)),
- timestamp: obj.start
- },
- end: {
- date: formateDate(new Date(obj.end)),
- timestamp: obj.end
- },
- values: values
- })
- }
- var params = {
- date: strDate,
- timestamp: date.getTime(),
- code: workout.item.code,
- items: [
- {
- code: workout.item.code,
- duration: props.targetCount * 1000,
- summary_stats: [
- {
- unit: getUnit(),
- value: totalValue()
- }
- ],
- groups: records
- }
- ]
- }
- uploadWorkout(params).then(res => {
- clearCache()
- dispatch(endSuccess())
- setTimeout(() => {
- Taro.redirectTo({
- url: '/pages/workout/WorkoutDetail?detail=' + JSON.stringify((res as any).latest_record) + '&title=' + workout.item.name + '&themeColor=' + workout.item.theme_color
- })
- }, 0)
- props.end()
- global.refreshWorkout()
- }).catch(e => {
- setIsPosting(false)
- resume()
- })
- }
- function checkEnd() {
- if (groups[groups.length - 1].type == 'REST') {
- postData()
- return
- }
- setLatestPicker()
- setIsPosting(true)
- setNeedTerminal(true)
- setShowModal(true)
- }
- function terminal() {
- clearInterval(timer)
- var tempTimestamp = new Date().getTime()
- setTempTime(tempTimestamp)
- lastTimestamp = tempTimestamp
- Taro.showModal({
- title: '提示',
- content: '确认结束?',
- success: function (res) {
- if (res.confirm) {
- var schema = workout.item.schemas[0]
- if (workout.item.schemas[0].values.length > 0 && schema.format != 'TIME_SECONDS') {
- checkEnd()
- return;
- }
- var array = groups;
- // var time = new Date().getTime()
- array.push({
- index: index,
- time: tempTimestamp,
- type: 'REST'
- })
- // setIsDoing(false)
- setGroups(array)
- postData()
- } else if (res.cancel) {
- resume()
- console.log('用户点击取消')
- }
- }
- })
- }
- function numChange(e) {
- if (isEdit) {
- var array = groups
- var obj = array[editIndex]
- obj.value = e.length > 0 ? pickerItems[0][e[0]] : pickerItems[e[0]]
- obj.value2 = e.length > 1 ? pickerItems[1][e[1]] : null
- obj.value3 = e.length > 2 ? pickerItems[2][e[2]] : null
- obj.pickerValue = e
- saveCache(array)
- setGroups(array)
- setIsEdit(false)
- setEditIdex(-1)
- setPickerValue(e)
- setShowModal(false)
- resume()
- return
- }
- setLastPickerValue(e)
- setPickerValue(e)
- setShowModal(false)
- var array = groups;
- array.push({
- index: index,
- time: tempTime,
- pickerValue:e,
- value: e.length > 0 ? pickerItems[0][e[0]] : pickerItems[e[0]],
- value2: e.length > 1 ? pickerItems[1][e[1]] : null,
- value3: e.length > 2 ? pickerItems[2][e[2]] : null,
- type: 'REST'
- })
- if (needTerminal) {
- postData()
- return;
- }
- setIsDoing(false)
- saveCache(array)
- setStartTime(tempTime)
- setGroups(array)
- resume()
- }
- function needShowPicker() {
- var schema = workout.item.schemas[0]
- if (schema.format == 'TIME_SECONDS') {
- return false;
- }
- if (schema.values.length == 0) {
- return false;
- }
- return true;
- }
- function pickerContent() {
- var color = workout.item.theme_color
- var title = isEdit?`第${groups[editIndex].index}组`:`第${index}组`
- return <View style={{ color: '#fff', backgroundColor: 'transparent' }}>
- <PickerViews
- onChange={numChange}
- items={pickerItems}
- value={pickerValue}
- themeColor={color}
- title={title}
- showBtns={true}
- onCancel={() => {
- resume()
- setIsPosting(false)
- setNeedTerminal(false)
- setShowModal(false)
- }} />
- </View>
- }
- function totalSummary() {
- var multiValues: any = []
- var multiUnits: any = []
- var schema = workout.item.schemas[0]
- if (schema.format == 'TIME_SECONDS') {
- var count = 0
- for (var i = 0; i < groups.length; i++) {
- var obj = groups[i]
- if (obj.type == 'REST') {
- count += Math.floor((obj.time - groups[i - 1].time) / 1000)
- }
- }
- if (!count) {
- multiValues.push(0)
- multiValues.push(0)
- multiValues.push(0)
- multiUnits.push('小时')
- multiUnits.push('分钟')
- multiUnits.push('秒')
- }
- else {
- var obj = TimeFormatter.workoutTimeAndUnitList(count) as any
- multiValues = obj.values
- multiUnits = obj.units
- }
- }
- else {
- var count = 0
- for (var i = 0; i < groups.length; i++) {
- var obj = groups[i]
- if (obj.type == 'REST') {
- var temp = 0
- if (obj.value) {
- temp = parseInt(obj.value + '')
- }
- if (obj.value2) {
- temp *= parseInt(obj.value2 + '')
- }
- if (obj.value3) {
- temp *= parseInt(obj.value3 + '')
- }
- count += temp
- }
- }
- var array = workout.item.schemas[0].values
- var unit = array.map(obj => obj.unit).join('·')
- multiUnits = [unit]
- multiValues = [count]
- }
- return <MultiText values={multiValues} units={multiUnits} color={workout.item.theme_color} valueSize={rpxToPx(48)} unitSize={rpxToPx(32)} />
- }
- function edit(e, index) {
- if (process.env.TARO_ENV == 'weapp') {
- e.stopPropagation()
- }
- if (groups[index].pickerValue){
- setPickerValue(groups[index].pickerValue)
- }
- clearInterval(timer)
- setIsEdit(true)
- setEditIdex(index)
- setShowModal(true)
- }
- return <View style={{ color: workout.item.theme_color, flexDirection: 'column', display: 'flex' }}>
- <Text className="working_title" style={{ fontSize: rpxToPx(56) }}>{workout.item.name}</Text>
- <Text className="working_subtitle">计时训练</Text>
- {
- groups.length > 1 && groups.map((item, index) => {
- if (index == 0) {
- return <View />
- }
- return <View style={{ position: 'relative' }}>
- <Box key={index} >
- <View>
- <Text className="working_index">{item.type == 'REST' ? `第${item.index}组` : '组间休息'}</Text>
- {
- item.type == 'REST' &&workout.item.schemas[0].format != 'TIME_SECONDS' && <Text className="workout_edit" style={{ color: workout.item.theme_color }} onClick={(e) => edit(e, index)}>编辑</Text>
- }
- <View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', marginTop: item.type == 'REST' ? rpxToPx(60) : 0, marginBottom: item.type == 'REST' ? rpxToPx(0) : 0 }}>
- {item.type == 'REST' && workout.item.schemas[0].format != 'TIME_SECONDS' &&
- <View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
- {
- <MultiText values={[parseInt(item.value)]} units={[workout.item.schemas[0].values[0].unit]} color={workout.item.theme_color} valueSize={rpxToPx(48)} unitSize={rpxToPx(32)} />
- }
- {
- item.value2 && <IconX width={rpxToPx(32)} color={workout.item.theme_color} />
- }
- {
- item.value2 && <View style={{ width: 1 }} />
- }
- {
- item.value2 && <MultiText values={[parseInt(item.value2)]} units={[workout.item.schemas[0].values[1].unit]} color={workout.item.theme_color} valueSize={rpxToPx(48)} unitSize={rpxToPx(32)} />
- }
- {
- item.value3 && <MultiText values={[parseInt(item.value3)]} units={[workout.item.schemas[0].values[2].unit]} color={workout.item.theme_color} valueSize={rpxToPx(48)} unitSize={rpxToPx(32)} />
- }
- </View>
- // <Text className="working_group_value" style={{ color: workout.item.theme_color }}>{getGroupValue(item)}</Text>
- }
- {
- item.type == 'REST' && workout.item.schemas[0].format == 'TIME_SECONDS' &&
- <MultiText values={twoTimeFormateList(groups[index - 1].time, item.time).values} units={twoTimeFormateList(groups[index - 1].time, item.time).units} color={workout.item.theme_color} valueSize={rpxToPx(48)} unitSize={rpxToPx(32)} />
- }
- <View style={{ flex: 1 }} />
- <Text className="working_group_duration" style={{ opacity: item.type != 'REST' || workout.item.schemas[0].format != 'TIME_SECONDS' ? 0.4 : 0 }}>{twoTimeDuration(groups[index - 1].time, item.time)}</Text>
- </View>
- </View>
- </Box>
- </View>
- })
- }
- <View style={{ position: 'relative' }}>
- <Box>
- {
- isDoing ? <View style={{ display: 'flex', flexDirection: 'column', width: '100%' }}>
- <Text className="working_index">第{index}组</Text>
- <Text className="working_duration">{isPosting ? lastStrTime : durationTime()}</Text>
- <View style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
- <WorkoutEndBtn onClick={finish} disable={isPosting} title={needShowPicker() ? "完成本组, 去记录" : "完成本组"} background={workout.item.theme_color} />
- </View>
- </View> :
- <View style={{ display: 'flex', flexDirection: 'column', width: '100%' }}>
- <Text className="working_index">组间休息</Text>
- <Text className="working_duration" >{isPosting ? lastStrTime : durationTime()}</Text>
- <View style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
- <ChooseScenarioBtn onClick={start} disable={isPosting} title="开始下一组" background={workout.item.theme_color} />
- </View>
- </View>
- }
- </Box>
- </View>
- <Text className="working_end" onClick={terminal}>结束训练</Text>
- <View style={{ height: 50 }} />
- <View style={{ display: 'flex', flexDirection: 'column', color: '#fff', marginLeft: rpxToPx(46) }}>
- <Text style={{ fontSize: rpxToPx(40), fontWeight: 'bold', marginBottom: rpxToPx(6) }}>训练统计</Text>
- <Text className="train_summary_title">总量</Text>
- {
- totalSummary()
- }
- {/* <Text className="train_summary_value" style={{ color: workout.item.theme_color }}></Text> */}
- <Text className="train_summary_title">已进行</Text>
- <Text className="train_summary_value" style={{ color: workout.item.theme_color }}>{groups.length > 0 &&
- (isPosting ? TimeFormatter.formateTimeNow(groups[0].time, lastTimestamp) :
- TimeFormatter.formateTimeNow(groups[0].time))}</Text>
- <Text className="train_summary_title">{groups.length > 0 && new Date().getTime() > groups[0].time + props.targetCount * 1000 ? '已超时' : '距结束'}</Text>
- <Text className="train_summary_value" style={{ color: workout.item.theme_color }}>{groups.length > 0 &&
- (isPosting ? TimeFormatter.countdown(groups[0].time + props.targetCount * 1000, lastTimestamp) :
- TimeFormatter.countdown(groups[0].time + props.targetCount * 1000))}</Text>
- </View>
- {
- showModal && <Modal dismiss={() => {
- setShowModal(false)
- resume()
- }}>
- {
- pickerContent()
- }
- </Modal>
- }
- </View>
- }
|