Metric.tsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. import { View, Text, ScrollView, 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 Modal from "@/components/layout/Modal";
  10. import LimitPickers from "@/components/input/LimitPickers";
  11. import SlidngScale from "@/components/input/SlidngScale";
  12. import NoData from "@/components/view/NoData";
  13. import { alphaToHex } from "@/utils/tools";
  14. import Layout from "@/components/layout/layout";
  15. import { MetricModalType, ModalType, NaviBarTitleShowType, TemplateType } 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 { setTabbarStatus } from "@/store/common";
  20. import MetricModalChoose from "./MetricModalChoose";
  21. import MetricModalOrder from './MetricModalOrder';
  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 [isModalOpen, setIsModalOpen] = useState(false);
  31. const [isTimePickerOpen, setIsTimePickerOpen] = useState(false);
  32. const [pickerValue, setPickerValue] = useState([]);
  33. const [pickerItems, setPickerItems] = useState([]);
  34. const [isPoint, setIsPoint] = useState(false)
  35. const [metricItem, setMetricItem] = useState({})
  36. const [strTime, setStrTime] = useState('')
  37. const [time, setTime] = useState(0)
  38. const [showErrorPage, setErrorPage] = useState(false)
  39. const [setupTime, setSetupTime] = useState(0)
  40. const [triggered, setTriggered] = useState(true)
  41. const limitPickerRef = useRef<any>(null);
  42. const [count, setCount] = useState(0)
  43. const [showPageContainer, setShowPageContainer] = useState(false)
  44. const [modalType, setModalType] = useState(MetricModalType.none)
  45. const [themeColor, setThemeColor] = useState('#00ffff')
  46. const [groups, setGroups] = useState([])
  47. const [limits, setLimits] = useState(null)
  48. const [orders, setOrders] = useState([])
  49. const dispatch = useDispatch();
  50. let navigation;
  51. if (useNavigation) {
  52. navigation = useNavigation()
  53. }
  54. //未登录<->已登录 状态切换时,执行一次授权检查
  55. useEffect(() => {
  56. getCards();
  57. getGroups();
  58. const now = new Date();
  59. const nextMidnight = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0);
  60. const timeUntilMidnight = nextMidnight.getTime() - now.getTime();
  61. setTimeout(() => {
  62. setCount(count + 1)
  63. }, timeUntilMidnight);
  64. }, [user.isLogin])
  65. const openModal = () => {
  66. setSetupTime(new Date().getTime())
  67. setIsModalOpen(true);
  68. };
  69. const closeModal = () => {
  70. setIsModalOpen(false);
  71. };
  72. global.refreshMetric = () => {
  73. getCards()
  74. }
  75. function getCards() {
  76. setTriggered(true)
  77. metricCards().then(res => {
  78. Taro.stopPullDownRefresh()
  79. setErrorPage(false)
  80. setList((res as any).cards)
  81. setTriggered(false)
  82. if ((res as any).cards.length > 0) {
  83. var obj = (res as any).cards[0]
  84. setThemeColor(obj.theme_color)
  85. }
  86. var list: any = [];
  87. (res as any).cards.map(item => {
  88. list.push({
  89. name: item.name,
  90. code: item.code
  91. })
  92. })
  93. setOrders(list)
  94. }).catch(e => {
  95. Taro.stopPullDownRefresh()
  96. if (list.length == 0) {
  97. setErrorPage(true)
  98. }
  99. setTriggered(false)
  100. })
  101. }
  102. function getGroups() {
  103. metricGroups().then(res => {
  104. setGroups((res as any).groups)
  105. setLimits((res as any).num_options_limit)
  106. })
  107. }
  108. //ts 把数组items: [{code: "_walk", value: 2180},{code: "_walk", value: 4444}]中的value取出来,/分割,组成字符串,如2180/4444
  109. function getValues(items) {
  110. var values = ''
  111. items.map((item, index) => {
  112. if (index == 0) {
  113. values = item.value
  114. }
  115. else {
  116. values = values + '/' + item.value
  117. }
  118. })
  119. return values
  120. }
  121. function goDetail(item) {
  122. if (user.isLogin) {
  123. if (!item.latest_record) {
  124. return
  125. }
  126. jumpPage('/pages/common/RecordsHistory?type=metric&refreshList=getCards&code=' + item.code + `&title=${item.name}` + '&themeColor=' + item.theme_color)
  127. }
  128. else {
  129. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  130. }
  131. }
  132. function record(item: any) {
  133. if (user.isLogin) {
  134. var now = new Date();
  135. var t = (now.getHours() < 10 ? '0' + now.getHours() : now.getHours()) + ":" + (now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes());
  136. // setStrTime(t)
  137. setStrTime(TimeFormatter.dateTimeFormate(now.getTime()))
  138. setTime(now.getTime())
  139. setMetricItem(item)
  140. openModal()
  141. }
  142. else {
  143. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
  144. }
  145. }
  146. function showTimePicker() {
  147. setIsTimePickerOpen(true)
  148. }
  149. function chooseTime(e) {
  150. setTime(e);
  151. setStrTime(TimeFormatter.dateTimeFormate(e))
  152. setIsTimePickerOpen(false)
  153. }
  154. function cancelModal() {
  155. (metricItem as any).schemas.map((item, index) => {
  156. item.tempValue = ''
  157. })
  158. closeModal()
  159. }
  160. function confirmModal() {
  161. closeModal()
  162. var date = new Date(time)
  163. var strDate = (date.getFullYear() + '') + (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
  164. var array: any[] = [];
  165. (metricItem as any).schemas.map((item, index) => {
  166. array.push({
  167. code: item.code,
  168. value: item.tempValue && item.tempValue > 0 ? item.tempValue : item.default_value
  169. })
  170. })
  171. var params = {
  172. code: (metricItem as any).code,
  173. timestamp: time,
  174. date: strDate,
  175. items: array,
  176. extra: {
  177. set_time: setupTime,
  178. confirm_time: new Date().getTime()
  179. }
  180. }
  181. global.postBtnUpdateStatus('normal');
  182. uploadMetric(params).then(res => {
  183. // getCards();
  184. (metricItem as any).schemas.map((item, index) => {
  185. item.tempValue = ''
  186. })
  187. list.map((item, index) => {
  188. if ((item as any).code == (res as any).code) {
  189. (item as any).latest_record = (res as any).latest_record;
  190. (item as any).schemas = (res as any).schemas;
  191. }
  192. })
  193. setList(JSON.parse(JSON.stringify(list)))
  194. global.postBtnUpdateStatus('idle');
  195. setTimeout(() => {
  196. setCount(count + 1)
  197. }, 31000)
  198. })
  199. }
  200. const limitDay = 500
  201. const limit = new Date().getTime() - limitDay * 3600 * 1000 * 24;
  202. function detail() {
  203. return <View>
  204. <View className="metric_container">
  205. {
  206. list.map((item: any, index: number) => {
  207. var unit = ''
  208. var value = t('feature.track_something.metric.no_record')
  209. var desc = t('feature.track_something.metric.check_unlock_data')
  210. var showDetail = false;
  211. if (item.latest_record) {
  212. unit = item.schemas[0].default_unit
  213. value = getValues(item.latest_record.items)
  214. desc = TimeFormatter.dateDescription(item.latest_record.timestamp, true)
  215. showDetail = true
  216. }
  217. if (!user.isLogin) {
  218. value = t('feature.track_something.metric.un_login')
  219. desc = t('feature.track_something.metric.login_can_check')
  220. }
  221. return <MetricItem title={item.name}
  222. value={value}
  223. unit={unit}
  224. desc={desc}
  225. btnText={t('feature.track_something.btn_record')}
  226. isDisabled={false}
  227. showDetail={showDetail}
  228. themeColor={item.theme_color}
  229. onClickDetail={() => { goDetail(item) }}
  230. onClick={() => { record(item) }}
  231. />
  232. })
  233. }
  234. </View>
  235. <View className="space_width" ></View>
  236. </View>
  237. }
  238. function detailContent() {
  239. // if (process.env.TARO_ENV=='rn'){
  240. // return <ScrollView>
  241. // {
  242. // detail()
  243. // }
  244. // <View style={{height:150}}/>
  245. // </ScrollView>
  246. // }
  247. return detail()
  248. }
  249. function addBtnClick() {
  250. Taro.showActionSheet({
  251. itemList: [t('feature.track_something.metric.choose_metric'),
  252. t('feature.track_something.metric.order')]
  253. })
  254. .then(res => {
  255. switch (res.tapIndex) {
  256. case 0:
  257. global.metricAdd = true
  258. setModalType(MetricModalType.choose)
  259. dispatch(setTabbarStatus(false))
  260. setShowPageContainer(true)
  261. break;
  262. case 1:
  263. global.metricAdd = false
  264. setModalType(MetricModalType.order)
  265. dispatch(setTabbarStatus(false))
  266. setShowPageContainer(true)
  267. break;
  268. }
  269. })
  270. .catch(err => {
  271. console.log(err.errMsg)
  272. })
  273. }
  274. function headerView() {
  275. return <TitleView title={t('page.metric.title')} showAddBtn={true} onClick={addBtnClick}>
  276. </TitleView>
  277. }
  278. function metricModalContent() {
  279. switch (modalType) {
  280. case MetricModalType.choose:
  281. return <MetricModalChoose
  282. themeColor={themeColor}
  283. cancel={modalCancel}
  284. confirm={modalConfirm}
  285. array={groups}
  286. orders={orders}
  287. limit={limits}
  288. />
  289. case MetricModalType.order:
  290. return <MetricModalOrder themeColor={themeColor} cancel={modalOrderCancel} confirm={modalOrderConfirm} array={orders} />
  291. }
  292. return <View />
  293. }
  294. function modalCancel() {
  295. setShowPageContainer(false)
  296. }
  297. function modalConfirm(datas) {
  298. var array: any = []
  299. datas.map(item => {
  300. array.push(item.code)
  301. })
  302. metricFollows({ codes: array }).then(res => {
  303. getCards()
  304. getGroups()
  305. })
  306. setShowPageContainer(false)
  307. setTimeout(() => {
  308. dispatch(setTabbarStatus(false))
  309. setModalType(MetricModalType.order)
  310. setShowPageContainer(true)
  311. }, 500)
  312. }
  313. function modalOrderCancel() {
  314. global.metricAdd ? modalCancel() : modalCancel()
  315. if (global.metricAdd) {
  316. setShowPageContainer(false)
  317. setTimeout(() => {
  318. dispatch(setTabbarStatus(false))
  319. setModalType(MetricModalType.choose)
  320. setShowPageContainer(true)
  321. }, 500)
  322. }
  323. else {
  324. setShowPageContainer(false)
  325. }
  326. }
  327. function modalOrderConfirm() {
  328. setShowPageContainer(false)
  329. }
  330. return <View style={{ position: 'relative' }}>
  331. <Layout children={showErrorPage ? <NoData refresh={() => { getCards() }} /> : detailContent()}
  332. title={t('page.metric.title')}
  333. type={TemplateType.customHeader}
  334. header={headerView()}
  335. refresh={() => { getCards() }}
  336. triggered={triggered}
  337. titleShowStyle={NaviBarTitleShowType.scrollToShow}
  338. />
  339. <PageContainer style={{ backgroundColor: '#1c1c1c' }}
  340. overlayStyle='background-color:rgba(0,0,0,0.9)'
  341. custom-style='background-color:#1c1c1c'
  342. closeOnSlideDown={false}
  343. show={showPageContainer} round={true} overlay={true} position='bottom'
  344. onBeforeLeave={() => { dispatch(setTabbarStatus(true)) }}
  345. onAfterLeave={() => { setShowPageContainer(false); }}>
  346. {
  347. metricModalContent()
  348. }
  349. </PageContainer>
  350. {
  351. isModalOpen && <Modal dismiss={closeModal} title={(metricItem as any).name}
  352. themeColor={(metricItem as any).theme_color}
  353. confirm={confirmModal}>
  354. <View style={{
  355. display: 'flex', flexDirection: 'column',
  356. width: '100%', color: '#000'
  357. }}>
  358. <Text className='modal_title' style={{ color: (metricItem as any).theme_color }}>{(metricItem as any).name ? (metricItem as any).name : ''}</Text>
  359. <View style={{ position: 'relative' }}>
  360. {
  361. (metricItem as any).schemas.map((item, index) => {
  362. return <View key={index}>
  363. {
  364. (metricItem as any).schemas.length > 1 && <Text style={{
  365. textAlign: 'center', width: '100%', display: 'flex',
  366. justifyContent: 'center', color: (metricItem as any).theme_color
  367. }}>{item.name}</Text>
  368. }
  369. <SlidngScale step={item.step} min={item.min} max={item.max} default_value={item.default_value}
  370. unit={item.default_unit}
  371. themeColor={(metricItem as any).theme_color}
  372. changed={(e) => { item.tempValue = e }} />
  373. </View>
  374. })
  375. }
  376. </View>
  377. <View className="change_time_bg ">
  378. <View className="gray1 time_bg" onClick={showTimePicker}>
  379. <Text className="time" >{strTime}</Text>
  380. </View>
  381. </View>
  382. <View className='modal_operate'>
  383. <View className='modal_btn' style={{ backgroundColor: (metricItem as any).theme_color + alphaToHex(0.4) }} onClick={cancelModal}>
  384. <Text className='modal_cancel_text' style={{ color: (metricItem as any).theme_color }}>{
  385. t('feature.common.picker_cancel_btn')
  386. }</Text>
  387. </View>
  388. <View className='btn_space' />
  389. <View className='modal_btn' style={{ backgroundColor: (metricItem as any).theme_color }} onClick={confirmModal}>
  390. <Text className='modal_confirm_text' style={{ color: '#000' }}>{
  391. t('feature.common.picker_confirm_btn')
  392. }</Text>
  393. </View>
  394. </View>
  395. {/* <View style={{ marginBottom: 20, marginTop: 20, display: 'flex', flexDirection: 'row', width: '100%' }}>
  396. <Text style={{ flex: 1, textAlign: 'center', height: 50 }} onClick={cancelModal}>取消</Text>
  397. <Text style={{ flex: 1, textAlign: 'center', height: 50 }} onClick={confirmModal}>确认</Text>
  398. </View> */}
  399. </View>
  400. </Modal>
  401. }
  402. {
  403. isTimePickerOpen && <Modal
  404. themeColor={(metricItem as any).theme_color}
  405. dismiss={() => setIsTimePickerOpen(false)} confirm={() => {
  406. var picker = limitPickerRef.current;
  407. chooseTime((picker as any).getConfirmData());
  408. setIsTimePickerOpen(false);
  409. }}>
  410. <LimitPickers ref={limitPickerRef}
  411. isRealTime={true} time={time} limit={limit}
  412. title={t('feature.track_something.picker_datetime')}
  413. themeColor={(metricItem as any).theme_color}
  414. limitDay={limitDay} onCancel={() => { setIsTimePickerOpen(false) }}
  415. onChange={(e) => {
  416. chooseTime(e)
  417. // pickerConfirm(e)
  418. // hidePicker()
  419. }} />
  420. </Modal>
  421. }
  422. </View>
  423. }