Metric.tsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. import { View, Text, Image, PageContainer } from "@tarojs/components";
  2. import './Metric.scss'
  3. import { useDispatch, useSelector } from "react-redux";
  4. import { useEffect, useRef, useState } from "react";
  5. import Taro from "@tarojs/taro";
  6. import { metricCards, metricFollows, metricGroups, uploadMetric, uploadSteps } from "@/services/trackSomething";
  7. import { TimeFormatter } from "@/utils/time_format";
  8. import MetricItem from "./MetricItem";
  9. import NoData from "@/components/view/NoData";
  10. import Layout from "@/components/layout/layout";
  11. import { MetricModalType, ModalType, NaviBarTitleShowType, TemplateType } from "@/utils/types";
  12. import { useTranslation } from "react-i18next";
  13. import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
  14. import TitleView from "@/features/trackTimeDuration/components/TitleView";
  15. import { setTabbarStatus } from "@/store/common";
  16. import MetricModalChoose from "./MetricModalChoose";
  17. import MetricModalOrder from './MetricModalOrder';
  18. import MetricModalAdd from "./MetricModalAdd";
  19. import MetricModalTime from "./MetricModalTime";
  20. import Modal from "@/components/layout/Modal";
  21. import { rpxToPx } from "@/utils/tools";
  22. let useNavigation;
  23. if (process.env.TARO_ENV == 'rn') {
  24. useNavigation = require("@react-navigation/native").useNavigation
  25. }
  26. export default function Component(props: any) {
  27. const { t } = useTranslation()
  28. const user = useSelector((state: any) => state.user);
  29. const [list, setList] = useState([])
  30. const [metricItem, setMetricItem] = useState({})
  31. const [strTime, setStrTime] = useState('')
  32. const [time, setTime] = useState(0)
  33. const [showErrorPage, setErrorPage] = useState(false)
  34. const [setupTime, setSetupTime] = useState(0)
  35. const [triggered, setTriggered] = useState(true)
  36. const [count, setCount] = useState(0)
  37. const [showPageContainer, setShowPageContainer] = useState(false)
  38. const [modalType, setModalType] = useState(MetricModalType.none)
  39. const [themeColor, setThemeColor] = useState('#00ffff')
  40. const [groups, setGroups] = useState([])
  41. const [orignalGroups, setOrignalGroups] = useState([])
  42. const [limits, setLimits] = useState(null)
  43. const [orders, setOrders] = useState([])
  44. const [newOrders, setNewOrders] = useState([])
  45. const [resultOrders, setResultOrders] = useState([])
  46. const [tempMetricItem, setTempMetricItem] = useState(null)
  47. const [loaded, setLoaded] = useState(false)
  48. const dispatch = useDispatch();
  49. let navigation;
  50. if (useNavigation) {
  51. navigation = useNavigation()
  52. }
  53. //未登录<->已登录 状态切换时,执行一次授权检查
  54. useEffect(() => {
  55. getCards();
  56. getGroups();
  57. const now = new Date();
  58. const nextMidnight = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0);
  59. const timeUntilMidnight = nextMidnight.getTime() - now.getTime();
  60. setTimeout(() => {
  61. setCount(count + 1)
  62. }, timeUntilMidnight);
  63. }, [user.isLogin])
  64. const openModal = () => {
  65. setSetupTime(new Date().getTime())
  66. setModalType(MetricModalType.add)
  67. setShowPageContainer(true)
  68. };
  69. global.refreshMetric = () => {
  70. getCards()
  71. }
  72. function getCards() {
  73. setTriggered(true)
  74. metricCards().then(res => {
  75. Taro.stopPullDownRefresh()
  76. setErrorPage(false)
  77. setList((res as any).cards)
  78. setTriggered(false)
  79. if ((res as any).cards.length > 0) {
  80. var obj = (res as any).cards[0]
  81. setThemeColor(obj.theme_color)
  82. }
  83. var list: any = [];
  84. (res as any).cards.map(item => {
  85. list.push({
  86. name: item.name,
  87. code: item.code,
  88. is_following: true
  89. })
  90. })
  91. setOrders(list)
  92. setResultOrders(list)
  93. setLoaded(true)
  94. }).catch(e => {
  95. Taro.stopPullDownRefresh()
  96. if (list.length == 0) {
  97. setErrorPage(true)
  98. }
  99. setTriggered(false)
  100. setLoaded(false)
  101. })
  102. }
  103. function getGroups() {
  104. metricGroups().then(res => {
  105. var array = (res as any).groups
  106. setOrignalGroups(JSON.parse(JSON.stringify(array)))
  107. setGroups(array)
  108. setLimits((res as any).num_options_limit)
  109. setNewOrders([])
  110. })
  111. }
  112. //ts 把数组items: [{code: "_walk", value: 2180},{code: "_walk", value: 4444}]中的value取出来,/分割,组成字符串,如2180/4444
  113. function getValues(items) {
  114. var values = ''
  115. items.map((item, index) => {
  116. if (index == 0) {
  117. values = item.value
  118. }
  119. else {
  120. values = values + '/' + item.value
  121. }
  122. })
  123. return values
  124. }
  125. function goDetail(item) {
  126. if (user.isLogin) {
  127. if (!item.latest_record) {
  128. return
  129. }
  130. global.selMetricItem = item
  131. jumpPage('/pages/common/RecordsHistory?type=metric&refreshList=getCards&code='
  132. + item.code + `&title=${item.name}` + '&themeColor=' + item.theme_color, 'RecordsHistory', navigation, {
  133. type: 'metric',
  134. refreshList: 'getCards',
  135. code: item.code,
  136. title: item.name,
  137. themeColor: item.theme_color
  138. })
  139. }
  140. else {
  141. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  142. }
  143. }
  144. function record(item: any) {
  145. if (user.isLogin) {
  146. var now = new Date();
  147. var t = (now.getHours() < 10 ? '0' + now.getHours() : now.getHours()) + ":" + (now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes());
  148. // setStrTime(t)
  149. setStrTime(TimeFormatter.dateTimeFormate(now.getTime()))
  150. setTime(now.getTime())
  151. setMetricItem(item)
  152. openModal()
  153. }
  154. else {
  155. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  156. }
  157. }
  158. function chooseTime(e) {
  159. setTime(e);
  160. setStrTime(TimeFormatter.dateTimeFormate(e))
  161. }
  162. const limitDay = 500
  163. const limit = new Date().getTime() - limitDay * 3600 * 1000 * 24;
  164. //获取参考值
  165. function getTargetValue(item) {
  166. for (var i = 0; i < item.references.length; i++) {
  167. for (var j = 0; j < item.references[i].categories.length; j++) {
  168. if (item.references[i].categories[j].is_default) {
  169. return item.references[i].categories[j].value_range
  170. }
  171. }
  172. }
  173. return null
  174. }
  175. function detail() {
  176. return <View>
  177. <View className="metric_container">
  178. {
  179. list.map((item: any, index: number) => {
  180. var unit = ''
  181. var value = t('feature.track_something.metric.no_record')
  182. var desc = t('feature.track_something.metric.check_unlock_data')
  183. var showDetail = false;
  184. if (item.latest_record) {
  185. if (item.type == 'composite') {
  186. unit = item.latest_record.unit ? item.latest_record.unit : ''
  187. value = item.latest_record.value
  188. }
  189. else {
  190. unit = item.schemas[0].default_unit
  191. value = getValues(item.latest_record.items)
  192. }
  193. desc = TimeFormatter.dateDescription(item.latest_record.timestamp, true)
  194. showDetail = true
  195. }
  196. if (!user.isLogin) {
  197. value = t('feature.track_something.metric.un_login')
  198. desc = t('feature.track_something.metric.login_can_check')
  199. }
  200. if (getTargetValue(item)) {
  201. desc = getTargetValue(item)
  202. }
  203. // desc = '90~140/60~90 mmHg'
  204. return <MetricItem title={item.name}
  205. value={value}
  206. unit={unit}
  207. desc={desc}
  208. btnText={t('feature.track_something.btn_record')}
  209. isDisabled={false}
  210. showDetail={showDetail}
  211. themeColor={item.theme_color}
  212. onClickDetail={() => { goDetail(item) }}
  213. onClick={() => { record(item) }}
  214. showTag={item.type == 'composite'}
  215. tagName={t('feature.track_something.metric.composite')}
  216. />
  217. })
  218. }
  219. {
  220. user.isLogin && list.length > 0 && <View className="add_more" onClick={chooseMore}>
  221. <Image style={{ width: rpxToPx(48), height: rpxToPx(48) }} src={require('@assets/images/add2.png')} />
  222. <Text className="add_more_text">{t('feature.workout.add_more')}</Text>
  223. </View>
  224. }
  225. </View>
  226. <View className="space_width" ></View>
  227. </View>
  228. }
  229. function addBtnClick() {
  230. Taro.showActionSheet({
  231. itemList: [t('feature.track_something.metric.choose_metric'),
  232. t('feature.track_something.metric.order')]
  233. })
  234. .then(res => {
  235. switch (res.tapIndex) {
  236. case 0:
  237. chooseMore()
  238. break;
  239. case 1:
  240. global.metricAdd = false
  241. setModalType(MetricModalType.order)
  242. setShowPageContainer(true)
  243. break;
  244. }
  245. })
  246. .catch(err => {
  247. console.log(err.errMsg)
  248. })
  249. }
  250. function chooseMore() {
  251. global.metricAdd = true
  252. setModalType(MetricModalType.choose)
  253. setShowPageContainer(true)
  254. }
  255. function headerView() {
  256. return <TitleView title={t('page.metric.title')} showAddBtn={loaded && !showErrorPage ? true : false} onClick={addBtnClick}>
  257. </TitleView>
  258. }
  259. function metricModalContent() {
  260. switch (modalType) {
  261. case MetricModalType.choose:
  262. return <MetricModalChoose
  263. themeColor={themeColor}
  264. cancel={modalCancel}
  265. confirm={modalConfirm}
  266. array={groups}
  267. orders={orders}
  268. newOrders={newOrders}
  269. limit={limits}
  270. />
  271. case MetricModalType.order:
  272. return <MetricModalOrder
  273. themeColor={themeColor}
  274. cancel={modalOrderCancel}
  275. confirm={modalOrderConfirm}
  276. array={resultOrders} />
  277. case MetricModalType.add:
  278. return <MetricModalAdd
  279. item={tempMetricItem ? tempMetricItem : metricItem}
  280. strTime={strTime}
  281. showPicker={(tempItem) => {
  282. var temp = JSON.parse(JSON.stringify(tempItem))
  283. temp.schemas.map(item => {
  284. if (item.tempValue) {
  285. item.default_value = item.tempValue
  286. }
  287. })
  288. setTempMetricItem(temp)
  289. setModalType(MetricModalType.time)
  290. }}
  291. cancel={modalAddCancel}
  292. confirm={modalAddConfirm} />
  293. case MetricModalType.time:
  294. return <MetricModalTime
  295. item={metricItem}
  296. time={time}
  297. limit={limit}
  298. limitDay={limitDay}
  299. cancel={() => {
  300. setModalType(MetricModalType.add)
  301. }}
  302. confirm={(e) => {
  303. chooseTime(e)
  304. setModalType(MetricModalType.add)
  305. }}
  306. />
  307. }
  308. return <View />
  309. }
  310. function modalCancel() {
  311. setShowPageContainer(false)
  312. onPageContainerCancel()
  313. }
  314. function modalConfirm(datas, newOrders, resultOrders, groups) {
  315. setOrders(datas)
  316. setGroups(groups)
  317. setNewOrders(newOrders)
  318. setResultOrders(resultOrders)
  319. setModalType(MetricModalType.order)
  320. }
  321. function modalOrderCancel() {
  322. if (global.metricAdd) {
  323. setModalType(MetricModalType.choose)
  324. }
  325. else {
  326. setShowPageContainer(false)
  327. onPageContainerCancel()
  328. }
  329. }
  330. function modalOrderConfirm(datas) {
  331. var array: any = []
  332. datas.map(item => {
  333. array.push(item.code)
  334. })
  335. metricFollows({ codes: array }).then(res => {
  336. getCards()
  337. getGroups()
  338. setList((res as any).cards)
  339. // setOrignalGroups(groups)
  340. })
  341. setShowPageContainer(false)
  342. }
  343. function modalAddCancel() {
  344. setShowPageContainer(false)
  345. onPageContainerCancel()
  346. }
  347. function modalAddConfirm(result) {
  348. setShowPageContainer(false)
  349. var date = new Date(time)
  350. var strDate = (date.getFullYear() + '') + (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
  351. var array: any[] = [];
  352. result.schemas.map((item, index) => {
  353. array.push({
  354. code: item.code,
  355. value: item.tempValue && item.tempValue > 0 ? item.tempValue : item.default_value
  356. })
  357. })
  358. var params = {
  359. code: result.code,
  360. timestamp: time,
  361. date: strDate,
  362. items: array,
  363. extra: {
  364. set_time: setupTime,
  365. confirm_time: new Date().getTime()
  366. }
  367. }
  368. global.postBtnUpdateStatus('normal');
  369. uploadMetric(params).then(res => {
  370. // getCards();
  371. result.schemas.map((item, index) => {
  372. item.tempValue = ''
  373. })
  374. list.map((item, index) => {
  375. if ((item as any).code == (res as any).code) {
  376. (item as any).latest_record = (res as any).latest_record;
  377. (item as any).schemas = (res as any).schemas;
  378. }
  379. })
  380. setList(JSON.parse(JSON.stringify(list)))
  381. global.postBtnUpdateStatus('idle');
  382. setTimeout(() => {
  383. setCount(count + 1)
  384. }, 31000)
  385. getCards()
  386. })
  387. }
  388. function onPageContainerCancel() {
  389. if (modalType == MetricModalType.choose || modalType == MetricModalType.order) {
  390. var array: any = [];
  391. list.map(item => {
  392. array.push({
  393. name: (item as any).name,
  394. code: (item as any).code,
  395. is_following: true
  396. })
  397. })
  398. setOrders(array)
  399. setNewOrders([])
  400. setGroups(JSON.parse(JSON.stringify(orignalGroups)))
  401. // setGroups(orignalGroups)
  402. }
  403. else {
  404. setTempMetricItem(null)
  405. }
  406. }
  407. function modalContent() {
  408. if (showPageContainer) {
  409. if (process.env.TARO_ENV == 'weapp') {
  410. return <Modal dismiss={() => {
  411. onPageContainerCancel()
  412. setShowPageContainer(false)
  413. }} confirm={() => { }}>
  414. {
  415. metricModalContent()
  416. }
  417. </Modal>
  418. }
  419. else if (process.env.TARO_ENV == 'rn') {
  420. return <PageContainer style={{ backgroundColor: '#1c1c1c' }}
  421. overlayStyle={{ backgroundColor: 'rgba(0,0,0,0.9)' }}
  422. customStyle={{ backgroundColor: '#1c1c1c' }}
  423. closeOnSlideDown={false}
  424. show={showPageContainer} round={true} overlay={true} position='bottom'
  425. onClickOverlay={onPageContainerCancel}
  426. onAfterLeave={() => { setShowPageContainer(false); setModalType(MetricModalType.none) }}
  427. onBeforeEnter={() => { dispatch(setTabbarStatus(false)); Taro.hideTabBar() }}
  428. onBeforeLeave={() => { dispatch(setTabbarStatus(true)); Taro.showTabBar() }}
  429. >
  430. {
  431. metricModalContent()
  432. }
  433. </PageContainer>
  434. }
  435. }
  436. return <View />
  437. }
  438. return <View style={{ position: 'relative' }}>
  439. <Layout children={showErrorPage ? <NoData refresh={() => { getCards() }} /> : detail()}
  440. title={t('page.metric.title')}
  441. type={TemplateType.customHeader}
  442. header={headerView()}
  443. refresh={() => { getCards() }}
  444. triggered={triggered}
  445. titleShowStyle={NaviBarTitleShowType.scrollToShow}
  446. />
  447. {
  448. modalContent()
  449. }
  450. </View>
  451. }