Activity.tsx 16 KB

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