Activity.tsx 17 KB

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