WorkoutStopWatch.tsx 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. import { ColorType } from "@/context/themes/color";
  2. import { TimeFormatter } from "@/utils/time_format";
  3. import { View, Text } from "@tarojs/components";
  4. import { useEffect, useState } from "react";
  5. import { ChooseScenarioBtn, WorkoutEndBtn } from "../common/SpecBtns";
  6. import Taro, { useRouter } from "@tarojs/taro";
  7. import { WorkoutType } from "@/utils/types";
  8. import Modal from "@/components/layout/Modal";
  9. import PickerViews from "@/components/input/PickerViews";
  10. import { useDispatch, useSelector } from "react-redux";
  11. import { endSuccess, startSuccess } from "@/store/workout";
  12. import { uploadWorkout } from "@/services/workout";
  13. import './WorkoutStopWatch.scss'
  14. import Box from "@/components/layout/Box";
  15. import { rpxToPx } from "@/utils/tools";
  16. import MultiText from "@/components/view/MultiText";
  17. import { values } from "lodash";
  18. import { IconRadioCross, IconX } from "@/components/basic/Icons";
  19. var timer
  20. var lastStrTime
  21. var lastTimestamp
  22. export default function Component(props: { targetCount: any, end: Function }) {
  23. const router = useRouter();
  24. const workout = useSelector((state: any) => state.workout);
  25. const [index, setIndex] = useState(1)
  26. const [count, setCount] = useState(0)
  27. const [startTime, setStartTime] = useState(new Date().getTime())
  28. const [tempTime, setTempTime] = useState(0)
  29. // const [lastStrTime, setLastStrTime] = useState('')
  30. const [groups, setGroups] = useState<any[]>([])
  31. const [isDoing, setIsDoing] = useState(true)
  32. const [showModal, setShowModal] = useState(false)
  33. const [needTerminal, setNeedTerminal] = useState(false)
  34. const [isPaused, setIsPaused] = useState(false);
  35. const [isPosting, setIsPosting] = useState(false)
  36. const dispatch = useDispatch();
  37. const [pickerItems, setPickerItems] = useState<any[]>([])
  38. const [pickerValue, setPickerValue] = useState<any[]>([])
  39. const [lastPickerValue,setLastPickerValue] = useState<any[]>([])
  40. const [isEdit, setIsEdit] = useState(false)
  41. const [editIndex, setEditIdex] = useState(-1)
  42. useEffect(() => {
  43. if (router.params.restore) {
  44. Taro.getStorage({
  45. key: 'lastWorkout', success: function (res) {
  46. var workouts = JSON.parse(res.data)
  47. setGroups(workouts)
  48. var workObj = workouts[workouts.length - 1]
  49. setIndex(workObj.index)
  50. setStartTime(workObj.time)
  51. if (workObj.type == 'REST') {
  52. setIsDoing(false)
  53. }
  54. }, fail: function (err) {
  55. console.log(err, 'no cache')
  56. }
  57. })
  58. }
  59. else {
  60. var array = [{
  61. code: workout.item.code,
  62. index: index,
  63. time: startTime,
  64. duration: props.targetCount,
  65. type: 'WORK'
  66. }]
  67. setGroups(array)
  68. saveCache(array)
  69. dispatch(startSuccess({
  70. start: startTime,
  71. code: workout.item.code,
  72. duration: props.targetCount
  73. }))
  74. }
  75. var item = workout.item
  76. var items: any = []
  77. var selects: any = []
  78. item.schemas[0].values.map(obj => {
  79. var list: any = []
  80. var min = parseInt(obj.min + '')
  81. var max = parseInt(obj.max + '')
  82. var step = parseInt(obj.step + '')
  83. var defaultV = parseInt(obj.default_value)
  84. for (var i = min; i <= max; i = i + step) {
  85. list.push(i + obj.unit)
  86. }
  87. items.push(list)
  88. for (var i = 0; i < list.length; i++) {
  89. if (parseInt(list[i] + '') == defaultV) {
  90. selects.push(i)
  91. }
  92. }
  93. })
  94. setLastPickerValue(selects)
  95. setPickerValue(selects)
  96. setPickerItems(items)
  97. setLatestPicker()
  98. // setTimeout(()=>{
  99. // Taro.pageScrollTo({
  100. // scrollTop:100000,
  101. // duration:0
  102. // })
  103. // },100)
  104. }, [])
  105. useEffect(() => {
  106. if (!isPaused) {
  107. timer = setInterval(() => {
  108. setCount((count) => count + 1)
  109. }, 1000)
  110. }
  111. return () => clearInterval(timer)
  112. }, [isPaused])
  113. function resume() {
  114. if (timer) {
  115. clearInterval(timer)
  116. timer = null
  117. }
  118. timer = setInterval(() => {
  119. setCount((count) => count + 1)
  120. }, 1000)
  121. }
  122. function planTime() {
  123. var minutes = props.targetCount / 60
  124. return minutes + '分钟'
  125. }
  126. function durationTime() {
  127. var str = TimeFormatter.formateTimeNow(startTime)
  128. lastStrTime = str
  129. return str
  130. }
  131. function twoTimeDuration(start, end) {
  132. var time = Math.floor((end - start) / 1000);
  133. const hours = Math.floor(time / 3600);
  134. const minutes = Math.floor((time % 3600) / 60);
  135. const seconds = Math.floor(time % 60);
  136. var strDuration = ''
  137. if (hours > 0) {
  138. strDuration = `${hours}小时`
  139. }
  140. if (minutes > 0) {
  141. strDuration += `${minutes}分钟`
  142. }
  143. if (seconds > 0) {
  144. strDuration += `${seconds}秒`
  145. }
  146. return strDuration.length == 0 ? '1秒' : strDuration
  147. }
  148. function twoTimeFormateList(start, end) {
  149. var time = Math.floor((end - start) / 1000);
  150. if (time<1){
  151. time = 1
  152. }
  153. return TimeFormatter.workoutTimeAndUnitList(time)
  154. }
  155. function setLatestPicker(){
  156. if (lastPickerValue){
  157. setPickerValue(lastPickerValue)
  158. }
  159. for (var i=groups.length-1;i>=0;i--){
  160. var obj = groups[i]
  161. if (obj.pickerValue){
  162. setLastPickerValue(obj.pickerValue)
  163. setPickerValue(obj.pickerValue)
  164. return
  165. }
  166. }
  167. }
  168. function finish() {
  169. setTempTime(new Date().getTime())
  170. var schema = workout.item.schemas[0]
  171. if (workout.item.schemas[0].values.length > 0 && schema.format != 'TIME_SECONDS') {
  172. setLatestPicker()
  173. // if (groups[groups.length])
  174. clearInterval(timer)
  175. setShowModal(true)
  176. return
  177. }
  178. clearInterval(timer)
  179. timer = null
  180. resume()
  181. var array = groups;
  182. var time = new Date().getTime()
  183. array.push({
  184. code: workout.item.code,
  185. index: index,
  186. time: time,
  187. type: 'REST'
  188. })
  189. setIsDoing(false)
  190. setStartTime(time)
  191. setGroups(array)
  192. saveCache(array)
  193. }
  194. function start() {
  195. clearInterval(timer)
  196. timer = null
  197. resume()
  198. var array = groups;
  199. var time = new Date().getTime()
  200. array.push({
  201. code: workout.item.code,
  202. index: index + 1,
  203. time: time,
  204. type: 'WORK'
  205. })
  206. setStartTime(time)
  207. setIndex(index + 1)
  208. setIsDoing(true)
  209. setGroups(array)
  210. saveCache(array)
  211. }
  212. function saveCache(array) {
  213. Taro.setStorage({
  214. key: 'lastWorkout',
  215. data: JSON.stringify(array)
  216. })
  217. }
  218. function clearCache() {
  219. Taro.removeStorage({ key: 'lastWorkout' })
  220. }
  221. function formateDate(date) {
  222. return (date.getFullYear() + '') + (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
  223. }
  224. function getValue(str, unit) {
  225. var i = str.indexOf(unit)
  226. return str.substring(0, i)
  227. }
  228. function getUnit() {
  229. var schema = workout.item.schemas[0]
  230. var units = schema.values
  231. if (schema.format == 'TIME_SECONDS') {
  232. return units[units.length - 1].unit
  233. }
  234. else {
  235. return units.map(obj => obj.unit).join('·')
  236. }
  237. }
  238. function totalValue() {
  239. var count = 0
  240. var schema = workout.item.schemas[0]
  241. if (schema.format == 'TIME_SECONDS') {
  242. groups.map(item => {
  243. if (item.type == 'WORK') {
  244. var t = Math.floor((item.end - item.start) / 1000)
  245. t = t < 1 ? 1 : t
  246. console.log(t)
  247. count += t
  248. }
  249. })
  250. return count
  251. }
  252. for (var i = 0; i < groups.length; i++) {
  253. var obj = groups[i]
  254. if (obj.type == 'WORK') {
  255. var temp = 0
  256. if (schema.format == 'TIME_SECONDS') {
  257. temp = parseInt(obj.value + '') * 3600 + parseInt(obj.value2 + '') * 60 + parseInt(obj.value3 + '')
  258. }
  259. else {
  260. if (obj.value) {
  261. temp = parseInt(obj.value + '')
  262. }
  263. if (obj.value2) {
  264. temp *= parseInt(obj.value2 + '')
  265. }
  266. if (obj.value3) {
  267. temp *= parseInt(obj.value3 + '')
  268. }
  269. }
  270. count += temp
  271. }
  272. }
  273. return count
  274. }
  275. function postData() {
  276. setIsPosting(true)
  277. var date = new Date()
  278. var strDate = formateDate(date)
  279. var records: any = []
  280. for (var i = 0; i < groups.length; i++) {
  281. var obj = groups[i]
  282. if (obj.type == 'WORK') {
  283. obj.start = obj.time
  284. obj.end = groups[i + 1].time
  285. obj.value = groups[i + 1].value
  286. obj.value2 = groups[i + 1].value2
  287. obj.value3 = groups[i + 1].value3
  288. }
  289. else {
  290. if (i != groups.length - 1) {
  291. obj.start = obj.time
  292. obj.end = groups[i + 1].time
  293. }
  294. }
  295. }
  296. for (var i = groups.length - 1; i >= 0; i--) {
  297. var obj = groups[i]
  298. if (obj.type == 'REST') {
  299. groups.splice(i, 1)
  300. }
  301. else {
  302. break;
  303. }
  304. }
  305. var units = workout.item.schemas[0].values
  306. for (var i = 0; i < groups.length; i++) {
  307. var obj = groups[i]
  308. var values: any = []
  309. if (obj.type == 'WORK') {
  310. if (obj.value) {
  311. if (units) {
  312. values.push({
  313. value: getValue(obj.value, units[0].unit),
  314. unit: units[0].unit
  315. })
  316. }
  317. else {
  318. values.push({
  319. value: obj.value
  320. })
  321. }
  322. }
  323. if (obj.value2) {
  324. values.push({
  325. value: getValue(obj.value2, units[1].unit),
  326. unit: units[1].unit
  327. })
  328. }
  329. if (obj.value3) {
  330. values.push({
  331. value: getValue(obj.value3, units[2].unit),
  332. unit: units[2].unit
  333. })
  334. }
  335. }
  336. records.push({
  337. type: obj.type,
  338. start: {
  339. date: formateDate(new Date(obj.start)),
  340. timestamp: obj.start
  341. },
  342. end: {
  343. date: formateDate(new Date(obj.end)),
  344. timestamp: obj.end
  345. },
  346. values: values
  347. })
  348. }
  349. var params = {
  350. date: strDate,
  351. timestamp: date.getTime(),
  352. code: workout.item.code,
  353. items: [
  354. {
  355. code: workout.item.code,
  356. duration: props.targetCount * 1000,
  357. summary_stats: [
  358. {
  359. unit: getUnit(),
  360. value: totalValue()
  361. }
  362. ],
  363. groups: records
  364. }
  365. ]
  366. }
  367. uploadWorkout(params).then(res => {
  368. clearCache()
  369. dispatch(endSuccess())
  370. setTimeout(() => {
  371. Taro.redirectTo({
  372. url: '/pages/workout/WorkoutDetail?detail=' + JSON.stringify((res as any).latest_record) + '&title=' + workout.item.name + '&themeColor=' + workout.item.theme_color
  373. })
  374. }, 0)
  375. props.end()
  376. global.refreshWorkout()
  377. }).catch(e => {
  378. setIsPosting(false)
  379. resume()
  380. })
  381. }
  382. function checkEnd() {
  383. if (groups[groups.length - 1].type == 'REST') {
  384. postData()
  385. return
  386. }
  387. setLatestPicker()
  388. setIsPosting(true)
  389. setNeedTerminal(true)
  390. setShowModal(true)
  391. }
  392. function terminal() {
  393. clearInterval(timer)
  394. var tempTimestamp = new Date().getTime()
  395. setTempTime(tempTimestamp)
  396. lastTimestamp = tempTimestamp
  397. Taro.showModal({
  398. title: '提示',
  399. content: '确认结束?',
  400. success: function (res) {
  401. if (res.confirm) {
  402. var schema = workout.item.schemas[0]
  403. if (workout.item.schemas[0].values.length > 0 && schema.format != 'TIME_SECONDS') {
  404. checkEnd()
  405. return;
  406. }
  407. var array = groups;
  408. // var time = new Date().getTime()
  409. array.push({
  410. index: index,
  411. time: tempTimestamp,
  412. type: 'REST'
  413. })
  414. // setIsDoing(false)
  415. setGroups(array)
  416. postData()
  417. } else if (res.cancel) {
  418. resume()
  419. console.log('用户点击取消')
  420. }
  421. }
  422. })
  423. }
  424. function numChange(e) {
  425. if (isEdit) {
  426. var array = groups
  427. var obj = array[editIndex]
  428. obj.value = e.length > 0 ? pickerItems[0][e[0]] : pickerItems[e[0]]
  429. obj.value2 = e.length > 1 ? pickerItems[1][e[1]] : null
  430. obj.value3 = e.length > 2 ? pickerItems[2][e[2]] : null
  431. obj.pickerValue = e
  432. saveCache(array)
  433. setGroups(array)
  434. setIsEdit(false)
  435. setEditIdex(-1)
  436. setPickerValue(e)
  437. setShowModal(false)
  438. resume()
  439. return
  440. }
  441. setLastPickerValue(e)
  442. setPickerValue(e)
  443. setShowModal(false)
  444. var array = groups;
  445. array.push({
  446. index: index,
  447. time: tempTime,
  448. pickerValue:e,
  449. value: e.length > 0 ? pickerItems[0][e[0]] : pickerItems[e[0]],
  450. value2: e.length > 1 ? pickerItems[1][e[1]] : null,
  451. value3: e.length > 2 ? pickerItems[2][e[2]] : null,
  452. type: 'REST'
  453. })
  454. if (needTerminal) {
  455. postData()
  456. return;
  457. }
  458. setIsDoing(false)
  459. saveCache(array)
  460. setStartTime(tempTime)
  461. setGroups(array)
  462. resume()
  463. }
  464. function needShowPicker() {
  465. var schema = workout.item.schemas[0]
  466. if (schema.format == 'TIME_SECONDS') {
  467. return false;
  468. }
  469. if (schema.values.length == 0) {
  470. return false;
  471. }
  472. return true;
  473. }
  474. function pickerContent() {
  475. var color = workout.item.theme_color
  476. var title = isEdit?`第${groups[editIndex].index}组`:`第${index}组`
  477. return <View style={{ color: '#fff', backgroundColor: 'transparent' }}>
  478. <PickerViews
  479. onChange={numChange}
  480. items={pickerItems}
  481. value={pickerValue}
  482. themeColor={color}
  483. title={title}
  484. showBtns={true}
  485. onCancel={() => {
  486. resume()
  487. setIsPosting(false)
  488. setNeedTerminal(false)
  489. setShowModal(false)
  490. }} />
  491. </View>
  492. }
  493. function totalSummary() {
  494. var multiValues: any = []
  495. var multiUnits: any = []
  496. var schema = workout.item.schemas[0]
  497. if (schema.format == 'TIME_SECONDS') {
  498. var count = 0
  499. for (var i = 0; i < groups.length; i++) {
  500. var obj = groups[i]
  501. if (obj.type == 'REST') {
  502. count += Math.floor((obj.time - groups[i - 1].time) / 1000)
  503. }
  504. }
  505. if (!count) {
  506. multiValues.push(0)
  507. multiValues.push(0)
  508. multiValues.push(0)
  509. multiUnits.push('小时')
  510. multiUnits.push('分钟')
  511. multiUnits.push('秒')
  512. }
  513. else {
  514. var obj = TimeFormatter.workoutTimeAndUnitList(count) as any
  515. multiValues = obj.values
  516. multiUnits = obj.units
  517. }
  518. }
  519. else {
  520. var count = 0
  521. for (var i = 0; i < groups.length; i++) {
  522. var obj = groups[i]
  523. if (obj.type == 'REST') {
  524. var temp = 0
  525. if (obj.value) {
  526. temp = parseInt(obj.value + '')
  527. }
  528. if (obj.value2) {
  529. temp *= parseInt(obj.value2 + '')
  530. }
  531. if (obj.value3) {
  532. temp *= parseInt(obj.value3 + '')
  533. }
  534. count += temp
  535. }
  536. }
  537. var array = workout.item.schemas[0].values
  538. var unit = array.map(obj => obj.unit).join('·')
  539. multiUnits = [unit]
  540. multiValues = [count]
  541. }
  542. return <MultiText values={multiValues} units={multiUnits} color={workout.item.theme_color} valueSize={rpxToPx(48)} unitSize={rpxToPx(32)} />
  543. }
  544. function edit(e, index) {
  545. if (process.env.TARO_ENV == 'weapp') {
  546. e.stopPropagation()
  547. }
  548. if (groups[index].pickerValue){
  549. setPickerValue(groups[index].pickerValue)
  550. }
  551. clearInterval(timer)
  552. setIsEdit(true)
  553. setEditIdex(index)
  554. setShowModal(true)
  555. }
  556. return <View style={{ color: workout.item.theme_color, flexDirection: 'column', display: 'flex' }}>
  557. <Text className="working_title" style={{ fontSize: rpxToPx(56) }}>{workout.item.name}</Text>
  558. <Text className="working_subtitle">计时训练</Text>
  559. {
  560. groups.length > 1 && groups.map((item, index) => {
  561. if (index == 0) {
  562. return <View />
  563. }
  564. return <View style={{ position: 'relative' }}>
  565. <Box key={index} >
  566. <View>
  567. <Text className="working_index">{item.type == 'REST' ? `第${item.index}组` : '组间休息'}</Text>
  568. {
  569. 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>
  570. }
  571. <View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', marginTop: item.type == 'REST' ? rpxToPx(60) : 0, marginBottom: item.type == 'REST' ? rpxToPx(0) : 0 }}>
  572. {item.type == 'REST' && workout.item.schemas[0].format != 'TIME_SECONDS' &&
  573. <View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
  574. {
  575. <MultiText values={[parseInt(item.value)]} units={[workout.item.schemas[0].values[0].unit]} color={workout.item.theme_color} valueSize={rpxToPx(48)} unitSize={rpxToPx(32)} />
  576. }
  577. {
  578. item.value2 && <IconX width={rpxToPx(32)} color={workout.item.theme_color} />
  579. }
  580. {
  581. item.value2 && <View style={{ width: 1 }} />
  582. }
  583. {
  584. 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)} />
  585. }
  586. {
  587. 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)} />
  588. }
  589. </View>
  590. // <Text className="working_group_value" style={{ color: workout.item.theme_color }}>{getGroupValue(item)}</Text>
  591. }
  592. {
  593. item.type == 'REST' && workout.item.schemas[0].format == 'TIME_SECONDS' &&
  594. <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)} />
  595. }
  596. <View style={{ flex: 1 }} />
  597. <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>
  598. </View>
  599. </View>
  600. </Box>
  601. </View>
  602. })
  603. }
  604. <View style={{ position: 'relative' }}>
  605. <Box>
  606. {
  607. isDoing ? <View style={{ display: 'flex', flexDirection: 'column', width: '100%' }}>
  608. <Text className="working_index">第{index}组</Text>
  609. <Text className="working_duration">{isPosting ? lastStrTime : durationTime()}</Text>
  610. <View style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
  611. <WorkoutEndBtn onClick={finish} disable={isPosting} title={needShowPicker() ? "完成本组, 去记录" : "完成本组"} background={workout.item.theme_color} />
  612. </View>
  613. </View> :
  614. <View style={{ display: 'flex', flexDirection: 'column', width: '100%' }}>
  615. <Text className="working_index">组间休息</Text>
  616. <Text className="working_duration" >{isPosting ? lastStrTime : durationTime()}</Text>
  617. <View style={{ width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
  618. <ChooseScenarioBtn onClick={start} disable={isPosting} title="开始下一组" background={workout.item.theme_color} />
  619. </View>
  620. </View>
  621. }
  622. </Box>
  623. </View>
  624. <Text className="working_end" onClick={terminal}>结束训练</Text>
  625. <View style={{ height: 50 }} />
  626. <View style={{ display: 'flex', flexDirection: 'column', color: '#fff', marginLeft: rpxToPx(46) }}>
  627. <Text style={{ fontSize: rpxToPx(40), fontWeight: 'bold', marginBottom: rpxToPx(6) }}>训练统计</Text>
  628. <Text className="train_summary_title">总量</Text>
  629. {
  630. totalSummary()
  631. }
  632. {/* <Text className="train_summary_value" style={{ color: workout.item.theme_color }}></Text> */}
  633. <Text className="train_summary_title">已进行</Text>
  634. <Text className="train_summary_value" style={{ color: workout.item.theme_color }}>{groups.length > 0 &&
  635. (isPosting ? TimeFormatter.formateTimeNow(groups[0].time, lastTimestamp) :
  636. TimeFormatter.formateTimeNow(groups[0].time))}</Text>
  637. <Text className="train_summary_title">{groups.length > 0 && new Date().getTime() > groups[0].time + props.targetCount * 1000 ? '已超时' : '距结束'}</Text>
  638. <Text className="train_summary_value" style={{ color: workout.item.theme_color }}>{groups.length > 0 &&
  639. (isPosting ? TimeFormatter.countdown(groups[0].time + props.targetCount * 1000, lastTimestamp) :
  640. TimeFormatter.countdown(groups[0].time + props.targetCount * 1000))}</Text>
  641. </View>
  642. {
  643. showModal && <Modal dismiss={() => {
  644. setShowModal(false)
  645. resume()
  646. }}>
  647. {
  648. pickerContent()
  649. }
  650. </Modal>
  651. }
  652. </View>
  653. }