Metric.tsx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  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. jumpPage('/pages/common/RecordsHistory?type=metric&refreshList=getCards&code='
  131. + item.code + `&title=${item.name}` + '&themeColor=' + item.theme_color, 'RecordsHistory', navigation, {
  132. type: 'metric',
  133. refreshList: 'getCards',
  134. code: item.code,
  135. title: item.name,
  136. themeColor: item.theme_color
  137. })
  138. }
  139. else {
  140. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  141. }
  142. }
  143. function record(item: any) {
  144. if (user.isLogin) {
  145. var now = new Date();
  146. var t = (now.getHours() < 10 ? '0' + now.getHours() : now.getHours()) + ":" + (now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes());
  147. // setStrTime(t)
  148. setStrTime(TimeFormatter.dateTimeFormate(now.getTime()))
  149. setTime(now.getTime())
  150. setMetricItem(item)
  151. openModal()
  152. }
  153. else {
  154. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  155. }
  156. }
  157. function chooseTime(e) {
  158. setTime(e);
  159. setStrTime(TimeFormatter.dateTimeFormate(e))
  160. }
  161. const limitDay = 500
  162. const limit = new Date().getTime() - limitDay * 3600 * 1000 * 24;
  163. function detail() {
  164. return <View>
  165. <View className="metric_container">
  166. {
  167. list.map((item: any, index: number) => {
  168. var unit = ''
  169. var value = t('feature.track_something.metric.no_record')
  170. var desc = t('feature.track_something.metric.check_unlock_data')
  171. var showDetail = false;
  172. if (item.latest_record) {
  173. unit = item.schemas[0].default_unit
  174. value = getValues(item.latest_record.items)
  175. desc = TimeFormatter.dateDescription(item.latest_record.timestamp, true)
  176. showDetail = true
  177. }
  178. if (!user.isLogin) {
  179. value = t('feature.track_something.metric.un_login')
  180. desc = t('feature.track_something.metric.login_can_check')
  181. }
  182. return <MetricItem title={item.name}
  183. value={value}
  184. unit={unit}
  185. desc={desc}
  186. btnText={t('feature.track_something.btn_record')}
  187. isDisabled={false}
  188. showDetail={showDetail}
  189. themeColor={item.theme_color}
  190. onClickDetail={() => { goDetail(item) }}
  191. onClick={() => { record(item) }}
  192. />
  193. })
  194. }
  195. {
  196. user.isLogin && list.length > 0 && <View className="add_more" onClick={chooseMore}>
  197. <Image style={{ width: rpxToPx(48), height: rpxToPx(48) }} src={require('@assets/images/add2.png')} />
  198. <Text className="add_more_text">添加更多</Text>
  199. </View>
  200. }
  201. </View>
  202. <View className="space_width" ></View>
  203. </View>
  204. }
  205. function addBtnClick() {
  206. Taro.showActionSheet({
  207. itemList: [t('feature.track_something.metric.choose_metric'),
  208. t('feature.track_something.metric.order')]
  209. })
  210. .then(res => {
  211. switch (res.tapIndex) {
  212. case 0:
  213. chooseMore()
  214. break;
  215. case 1:
  216. global.metricAdd = false
  217. setModalType(MetricModalType.order)
  218. setShowPageContainer(true)
  219. break;
  220. }
  221. })
  222. .catch(err => {
  223. console.log(err.errMsg)
  224. })
  225. }
  226. function chooseMore() {
  227. global.metricAdd = true
  228. setModalType(MetricModalType.choose)
  229. setShowPageContainer(true)
  230. }
  231. function headerView() {
  232. return <TitleView title={t('page.metric.title')} showAddBtn={loaded && !showErrorPage ? true : false} onClick={addBtnClick}>
  233. </TitleView>
  234. }
  235. function metricModalContent() {
  236. switch (modalType) {
  237. case MetricModalType.choose:
  238. return <MetricModalChoose
  239. themeColor={themeColor}
  240. cancel={modalCancel}
  241. confirm={modalConfirm}
  242. array={groups}
  243. orders={orders}
  244. newOrders={newOrders}
  245. limit={limits}
  246. />
  247. case MetricModalType.order:
  248. return <MetricModalOrder
  249. themeColor={themeColor}
  250. cancel={modalOrderCancel}
  251. confirm={modalOrderConfirm}
  252. array={resultOrders} />
  253. case MetricModalType.add:
  254. return <MetricModalAdd
  255. item={tempMetricItem ? tempMetricItem : metricItem}
  256. strTime={strTime}
  257. showPicker={(tempItem) => {
  258. var temp = JSON.parse(JSON.stringify(tempItem))
  259. temp.schemas.map(item => {
  260. if (item.tempValue) {
  261. item.default_value = item.tempValue
  262. }
  263. })
  264. setTempMetricItem(temp)
  265. setModalType(MetricModalType.time)
  266. }}
  267. cancel={modalAddCancel}
  268. confirm={modalAddConfirm} />
  269. case MetricModalType.time:
  270. return <MetricModalTime
  271. item={metricItem}
  272. time={time}
  273. limit={limit}
  274. limitDay={limitDay}
  275. cancel={() => {
  276. setModalType(MetricModalType.add)
  277. }}
  278. confirm={(e) => {
  279. chooseTime(e)
  280. setModalType(MetricModalType.add)
  281. }}
  282. />
  283. }
  284. return <View />
  285. }
  286. function modalCancel() {
  287. setShowPageContainer(false)
  288. onPageContainerCancel()
  289. }
  290. function modalConfirm(datas, newOrders, resultOrders, groups) {
  291. setOrders(datas)
  292. setGroups(groups)
  293. setNewOrders(newOrders)
  294. setResultOrders(resultOrders)
  295. setModalType(MetricModalType.order)
  296. }
  297. function modalOrderCancel() {
  298. if (global.metricAdd) {
  299. setModalType(MetricModalType.choose)
  300. }
  301. else {
  302. setShowPageContainer(false)
  303. onPageContainerCancel()
  304. }
  305. }
  306. function modalOrderConfirm(datas) {
  307. var array: any = []
  308. datas.map(item => {
  309. array.push(item.code)
  310. })
  311. metricFollows({ codes: array }).then(res => {
  312. getCards()
  313. getGroups()
  314. setList((res as any).cards)
  315. // setOrignalGroups(groups)
  316. })
  317. setShowPageContainer(false)
  318. }
  319. function modalAddCancel() {
  320. setShowPageContainer(false)
  321. onPageContainerCancel()
  322. }
  323. function modalAddConfirm(result) {
  324. setShowPageContainer(false)
  325. var date = new Date(time)
  326. var strDate = (date.getFullYear() + '') + (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
  327. var array: any[] = [];
  328. result.schemas.map((item, index) => {
  329. array.push({
  330. code: item.code,
  331. value: item.tempValue && item.tempValue > 0 ? item.tempValue : item.default_value
  332. })
  333. })
  334. var params = {
  335. code: result.code,
  336. timestamp: time,
  337. date: strDate,
  338. items: array,
  339. extra: {
  340. set_time: setupTime,
  341. confirm_time: new Date().getTime()
  342. }
  343. }
  344. global.postBtnUpdateStatus('normal');
  345. uploadMetric(params).then(res => {
  346. // getCards();
  347. result.schemas.map((item, index) => {
  348. item.tempValue = ''
  349. })
  350. list.map((item, index) => {
  351. if ((item as any).code == (res as any).code) {
  352. (item as any).latest_record = (res as any).latest_record;
  353. (item as any).schemas = (res as any).schemas;
  354. }
  355. })
  356. setList(JSON.parse(JSON.stringify(list)))
  357. global.postBtnUpdateStatus('idle');
  358. setTimeout(() => {
  359. setCount(count + 1)
  360. }, 31000)
  361. })
  362. }
  363. function onPageContainerCancel() {
  364. if (modalType == MetricModalType.choose || modalType == MetricModalType.order) {
  365. var array: any = [];
  366. list.map(item => {
  367. array.push({
  368. name: (item as any).name,
  369. code: (item as any).code,
  370. is_following: true
  371. })
  372. })
  373. setOrders(array)
  374. setNewOrders([])
  375. setGroups(JSON.parse(JSON.stringify(orignalGroups)))
  376. // setGroups(orignalGroups)
  377. }
  378. else {
  379. setTempMetricItem(null)
  380. }
  381. }
  382. function modalContent() {
  383. if (showPageContainer) {
  384. if (process.env.TARO_ENV == 'weapp') {
  385. return <Modal dismiss={() => {
  386. onPageContainerCancel()
  387. setShowPageContainer(false)
  388. }} confirm={() => { }}>
  389. {
  390. metricModalContent()
  391. }
  392. </Modal>
  393. }
  394. else if (process.env.TARO_ENV == 'rn') {
  395. return <PageContainer style={{ backgroundColor: '#1c1c1c' }}
  396. overlayStyle={{ backgroundColor: 'rgba(0,0,0,0.9)' }}
  397. customStyle={{ backgroundColor: '#1c1c1c' }}
  398. closeOnSlideDown={false}
  399. show={showPageContainer} round={true} overlay={true} position='bottom'
  400. onClickOverlay={onPageContainerCancel}
  401. onAfterLeave={() => { setShowPageContainer(false); setModalType(MetricModalType.none) }}
  402. onBeforeEnter={() => { dispatch(setTabbarStatus(false)); Taro.hideTabBar() }}
  403. onBeforeLeave={() => { dispatch(setTabbarStatus(true)); Taro.showTabBar() }}
  404. >
  405. {
  406. metricModalContent()
  407. }
  408. </PageContainer>
  409. }
  410. }
  411. return <View />
  412. }
  413. return <View style={{ position: 'relative' }}>
  414. <Layout children={showErrorPage ? <NoData refresh={() => { getCards() }} /> : detail()}
  415. title={t('page.metric.title')}
  416. type={TemplateType.customHeader}
  417. header={headerView()}
  418. refresh={() => { getCards() }}
  419. triggered={triggered}
  420. titleShowStyle={NaviBarTitleShowType.scrollToShow}
  421. />
  422. {
  423. modalContent()
  424. }
  425. </View>
  426. }