Activity.tsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. import { View, Text, ScrollView } from "@tarojs/components";
  2. import './Metric.scss'
  3. import { setAuth } from "../hooks/werun";
  4. import { useDidShow, useReady } from "@tarojs/taro";
  5. import { useDispatch, useSelector } from "react-redux";
  6. import { useEffect, useState } from "react";
  7. import Taro from "@tarojs/taro";
  8. import { activityCards, uploadSteps } from "@/services/trackSomething";
  9. import { TimeFormatter } from "@/utils/time_format";
  10. import MetricItem from "./MetricItem";
  11. import Layout from '@/components/layout/layout'
  12. import NoData from "@/components/view/NoData";
  13. import { ResultType, checkFail, checkRetry, checkStart, checkSuccess, resetStatus, setResult } from "@/store/action_results";
  14. import RequestType, { thirdPartRequest } from "@/services/thirdPartRequest";
  15. import { ModalType, NaviBarTitleShowType, TemplateType, WorkoutType } from "@/utils/types";
  16. import { useTranslation } from "react-i18next";
  17. import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
  18. import TitleView from "@/features/trackTimeDuration/components/TitleView";
  19. import './Activity.scss'
  20. import Modal from "@/components/layout/Modal";
  21. import MoveList from "./MoveList";
  22. import { ColorType } from "@/context/themes/color";
  23. import SetGoal from "@/features/workout/SetGoal";
  24. import Working from "@/features/workout/WorkoutStopWatch";
  25. import { startSuccess } from "@/store/workout";
  26. import { workoutGroups } from "@/services/workout";
  27. // import { useNavigation } from "@react-navigation/native";
  28. let useNavigation;
  29. if (process.env.TARO_ENV == 'rn') {
  30. useNavigation = require("@react-navigation/native").useNavigation
  31. }
  32. //
  33. let timer
  34. export default function Component(props: any) {
  35. const { t } = useTranslation()
  36. const user = useSelector((state: any) => state.user);
  37. const checkResult = useSelector((state: any) => state.checkResult);
  38. const workout = useSelector((state: any) => state.workout);
  39. const [allowRun, setAllowRun] = useState(false)
  40. const [stepInfo, setStepInfo] = useState(null)
  41. const [lastTime, setLastTime] = useState(new Date().getTime())
  42. const [list, setList] = useState([])
  43. const dispatch = useDispatch();
  44. const [showErrorBadge, setShowErrorBadge] = useState(false)
  45. const [latestRecord, setLatestRecord] = useState(null)
  46. const [triggered, setTriggered] = useState(true)
  47. const [showErrorPage, setErrorPage] = useState(false)
  48. const [showModal, setShowModal] = useState(false)
  49. const [loaded, setLoaded] = useState(false)
  50. const [count, setCount] = useState(0)
  51. const [isStart, setIsStart] = useState(false)
  52. const [targetTime, setTargetTime] = useState(0)
  53. let navigation;
  54. if (useNavigation) {
  55. navigation = useNavigation()
  56. }
  57. // const navigation = useNavigation();
  58. // const [title, setTitle] = useState('打卡')
  59. //未登录<->已登录 状态切换时,重新拉取一次列表数据
  60. useEffect(() => {
  61. if (user.isLogin) {
  62. loadWorkoutCache()
  63. }
  64. dispatch(resetStatus())
  65. getCards();
  66. const now = new Date();
  67. const nextMidnight = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0);
  68. const timeUntilMidnight = nextMidnight.getTime() - now.getTime();
  69. setTimeout(() => {
  70. setCount(count + 1)
  71. }, timeUntilMidnight);
  72. }, [user.isLogin])
  73. // useEffect(() => {
  74. // Taro.setStorage({key:'auth',data:allowRun})
  75. // },[allowRun])
  76. useEffect(() => {
  77. Taro.getStorage({
  78. key: 'auth', success: function (res) {
  79. setAllowRun(res.data ? res.data : false)
  80. }
  81. });
  82. }, [])
  83. //页面渲染完成后执行一次授权检查
  84. useReady(() => {
  85. })
  86. useDidShow(() => {
  87. if (list.length > 0) {
  88. checkAuth()
  89. }
  90. })
  91. function loadWorkoutCache() {
  92. Taro.getStorage({
  93. key: 'lastWorkout', success: function (res) {
  94. var workouts = JSON.parse(res.data)
  95. if (workouts && workouts.length>0){
  96. var workoutObj = workouts[0]
  97. dispatch(startSuccess({
  98. start:workoutObj.time,
  99. id:1
  100. }));
  101. timer = setInterval(()=>{
  102. setCount(count=>count+1)
  103. },1000)
  104. }
  105. },fail:function(err){
  106. console.log(err,'no cache')
  107. }
  108. })
  109. }
  110. global.refreshActivity = () => {
  111. getCards()
  112. }
  113. function getCards() {
  114. setTriggered(true)
  115. activityCards().then(res => {
  116. setErrorPage(false)
  117. setTriggered(false)
  118. checkAuth()
  119. setList((res as any).cards)
  120. for (var i = 0; i < (res as any).cards.length; i++) {
  121. var obj = (res as any).cards[i];
  122. if (obj.code == '_walk') {
  123. setLatestRecord(obj.latest_record)
  124. }
  125. }
  126. setLoaded(true)
  127. }).catch(e => {
  128. setTriggered(false)
  129. if (list.length == 0) {
  130. setErrorPage(true)
  131. }
  132. setLoaded(true)
  133. })
  134. workoutGroups().then(res=>{
  135. })
  136. }
  137. global.activityCardsFunc = getCards
  138. function checkAuth() {
  139. if (user.isLogin) {
  140. Taro.getSetting({
  141. success: res => {
  142. //第一步,检测是否有授权 - 没有授权
  143. if (!res.authSetting['scope.werun']) {
  144. setAllowRun(false)
  145. Taro.setStorage({ key: 'auth', data: false })
  146. }
  147. else {
  148. setAllowRun(true)
  149. Taro.setStorage({ key: 'auth', data: true })
  150. }
  151. }
  152. })
  153. }
  154. else {
  155. setAllowRun(false)
  156. Taro.setStorage({ key: 'auth', data: false })
  157. }
  158. }
  159. function tapBtn() {
  160. if (user.isLogin) {
  161. if (allowRun) {
  162. checkout()
  163. }
  164. else {
  165. setAuth(successAuth, refuseAuth, t)
  166. }
  167. }
  168. else {
  169. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  170. }
  171. }
  172. function successAuth() {
  173. Taro.setStorage({ key: 'auth', data: true })
  174. setAllowRun(true)
  175. }
  176. function refuseAuth() {
  177. // setTitle('开启');
  178. Taro.setStorage({ key: 'auth', data: false })
  179. setAllowRun(false)
  180. }
  181. function checkout() {
  182. dispatch(checkStart());
  183. getWeRunData(false)
  184. }
  185. function getWeRunData(autoCheck = false) {
  186. if (autoCheck) {
  187. return
  188. }
  189. else {
  190. dispatch(checkStart());
  191. }
  192. // setTitle('打卡');
  193. setAllowRun(true)
  194. var date = new Date();
  195. var time = date.getTime()
  196. var strDate = (date.getFullYear() + '') + (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
  197. thirdPartRequest(RequestType.RequestTypeWXRunData).then(res => {
  198. var params = {
  199. is_manual: autoCheck ? 0 : 1,
  200. timestamp: time,
  201. encryptedData: (res as any).encryptedData,
  202. iv: (res as any).iv,
  203. date: strDate,
  204. cloudID: (res as any).cloudID,
  205. }
  206. uploadSteps(params).then(res => {
  207. if ((res as any).error_code == 'WX_STEP_PARSE_FAIL') {
  208. retry(params, autoCheck, time)
  209. dispatch(checkRetry())
  210. }
  211. else {
  212. setShowErrorBadge(false)
  213. uploadSuccess(res, autoCheck, time)
  214. setTimeout(() => {
  215. setCount(count + 1)
  216. }, 31000)
  217. }
  218. }).catch(e => {
  219. retry(params, autoCheck, time)
  220. });
  221. }).catch(_ => {
  222. dispatch(setResult({ isSuccess: false }) as any)
  223. })
  224. }
  225. function retry(params, autoCheck, time) {
  226. Taro.login().then(res => {
  227. Taro.getWeRunData({
  228. success: res2 => {
  229. params.code = res.code;
  230. params.encryptedData = res2.encryptedData
  231. params.iv = res2.iv
  232. params.cloudID = res2.cloudID
  233. uploadSteps(params).then(res => {
  234. if ((res as any).error_code == 'WX_STEP_PARSE_FAIL') {
  235. if (!autoCheck) {
  236. dispatch(setResult({ isSuccess: false }) as any);
  237. setShowErrorBadge(true)
  238. }
  239. }
  240. else {
  241. setShowErrorBadge(false)
  242. uploadSuccess(res, autoCheck, time)
  243. setTimeout(() => {
  244. setCount(count + 1)
  245. }, 31000)
  246. }
  247. }).catch(e => {
  248. if (!autoCheck) {
  249. dispatch(setResult({ isSuccess: false }) as any);
  250. setShowErrorBadge(true)
  251. }
  252. })
  253. }
  254. })
  255. })
  256. }
  257. function uploadSuccess(res, autoCheck, time) {
  258. Taro.setStorageSync('lastUploadStepsTime', time)
  259. if (!autoCheck)
  260. dispatch(setResult({ isSuccess: true }) as any)
  261. setStepInfo((res as any)[(res as any).length - 1])
  262. setLastTime(time)
  263. for (var i = 0; i < list.length; i++) {
  264. var obj = list[i];
  265. if ((obj as any).code == '_walk') {
  266. (obj as any).latest_record = res.latest_record
  267. }
  268. }
  269. // getCards();
  270. }
  271. function goDetail(item) {
  272. if (user.isLogin) {
  273. if (!allowRun) {
  274. return;
  275. }
  276. jumpPage('/pages/common/RecordsHistory?type=activity&refreshList=getCards&title=' + item.name + '&themeColor=' + item.theme_color)
  277. }
  278. else {
  279. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  280. }
  281. }
  282. // checkResult.type == 'ing' && setStrBtnTitle('打卡中...')
  283. var btnTitle = '';
  284. var isEnable = true;
  285. if (allowRun) {
  286. switch (checkResult.type) {
  287. case ResultType.idle:
  288. {
  289. btnTitle = t('feature.track_something.activity.btn_status.idle')
  290. isEnable = true
  291. }
  292. break;
  293. case ResultType.ing:
  294. {
  295. btnTitle = t('feature.track_something.activity.btn_status.ing')
  296. isEnable = false
  297. }
  298. break;
  299. case ResultType.retry:
  300. {
  301. btnTitle = t('feature.track_something.activity.btn_status.retry')
  302. isEnable = false
  303. }
  304. break;
  305. case ResultType.success:
  306. {
  307. btnTitle = t('feature.track_something.activity.btn_status.success')
  308. isEnable = false
  309. }
  310. break;
  311. case ResultType.fail:
  312. {
  313. btnTitle = t('feature.track_something.activity.btn_status.fail')
  314. isEnable = false
  315. }
  316. break;
  317. case ResultType.countdown:
  318. {
  319. btnTitle = checkResult.title + 's'
  320. isEnable = false
  321. }
  322. break;
  323. default:
  324. break;
  325. }
  326. }
  327. else {
  328. btnTitle = t('feature.track_something.activity.open');
  329. isEnable = true;
  330. }
  331. function headerView() {
  332. return <TitleView title={t('page.activity.title')} showAddBtn={false}>
  333. </TitleView>
  334. }
  335. function workoutStart() {
  336. setShowModal(true)
  337. }
  338. function detail() {
  339. return <View className="activity_container">
  340. {
  341. list.map((item: any, index) => {
  342. var value = '0'
  343. var desc = ''
  344. var unit = ''
  345. var showDetail = false;
  346. if (item.latest_record) {
  347. showDetail = true
  348. value = item.latest_record.items[0].value
  349. if (item.latest_record.timestamp == 0) {
  350. desc = t('feature.track_something.activity.today_un_check')
  351. }
  352. else {
  353. desc = TimeFormatter.datetimeDescription(item.latest_record.timestamp)
  354. }
  355. }
  356. else {
  357. desc = t('feature.track_something.activity.today_un_check')
  358. }
  359. if (!user.isLogin) {
  360. value = t('feature.track_something.activity.un_login')
  361. desc = t('feature.track_something.activity.login_then_check')//登录后可开启打卡'
  362. }
  363. else {
  364. if (!allowRun) {
  365. value = t('feature.track_something.activity.un_open')
  366. desc = t('feature.track_something.activity.open_then_check')
  367. }
  368. else {
  369. // unit = '步'
  370. showDetail = true
  371. if (item.latest_record) {
  372. value = item.latest_record.items[0].value
  373. desc = TimeFormatter.datetimeDescription(item.latest_record.timestamp)
  374. unit = '步'
  375. }
  376. else {
  377. value = t('feature.track_something.activity.today_un_check')
  378. desc = t('feature.track_something.activity.check_history')//'查看历史记录'
  379. }
  380. }
  381. }
  382. return <MetricItem title={item.name}
  383. // value={allowRun ? stepInfo ? (stepInfo as any).step : '' : '未开启'}
  384. value={value}
  385. unit={unit}
  386. desc={desc}
  387. btnText={btnTitle}
  388. isDisabled={!isEnable}
  389. themeColor={item.theme_color}
  390. onClickDetail={() => { goDetail(item) }}
  391. showBadge={showErrorBadge && checkResult.type == 'idle'}
  392. showDetail={showDetail}
  393. onClick={() => {
  394. tapBtn()
  395. }}
  396. />
  397. })
  398. }
  399. <MetricItem title='平板支撑'
  400. // value={allowRun ? stepInfo ? (stepInfo as any).step : '' : '未开启'}
  401. value={10}
  402. unit={'分钟'}
  403. desc={'昨天'}
  404. btnText={'计时训练'}
  405. isDisabled={false}
  406. themeColor={ColorType.workout}
  407. onClickDetail={() => {
  408. Taro.navigateTo({
  409. url: '/pages/workout/History'
  410. })
  411. }}
  412. showBadge={showErrorBadge && checkResult.type == 'idle'}
  413. showDetail={false}
  414. onClick={() => {
  415. workoutStart()
  416. }}
  417. />
  418. </View>
  419. }
  420. return <View style={{ position: 'relative' }}>
  421. <Layout type={TemplateType.customHeader} header={headerView()} children={showErrorPage ? <NoData refresh={() => { getCards() }} /> : detail()}
  422. title={t('page.activity.title')}
  423. // type={process.env.TARO_ENV == 'rn' ? TemplateType.flex : TemplateType.grid}
  424. refresh={() => { getCards() }}
  425. triggered={triggered}
  426. titleShowStyle={NaviBarTitleShowType.scrollToShow}
  427. />
  428. {
  429. showModal && <Modal dismiss={() => {
  430. setIsStart(false)
  431. setShowModal(false)
  432. }} confirm={() => { }} modalType={ModalType.center}>
  433. {
  434. !isStart && <SetGoal start={(count) => { setTargetTime(count); setShowModal(false); Taro.navigateTo({ url: '/pages/workout/Working?count=' + count }) }} />
  435. }
  436. {
  437. isStart && <Working targetCount={targetTime} type={WorkoutType.multi} end={() => {
  438. setIsStart(false)
  439. setShowModal(false)
  440. }} />
  441. }
  442. </Modal>
  443. }
  444. </View>
  445. }