|
|
@@ -0,0 +1,493 @@
|
|
|
+import { View, Text, ScrollView, PageContainer } from "@tarojs/components";
|
|
|
+import './Metric.scss'
|
|
|
+import { useDispatch, useSelector } from "react-redux";
|
|
|
+import { useEffect, useRef, useState } from "react";
|
|
|
+import Taro from "@tarojs/taro";
|
|
|
+import { metricCards, metricFollows, metricGroups, uploadMetric, uploadSteps } from "@/services/trackSomething";
|
|
|
+import { TimeFormatter } from "@/utils/time_format";
|
|
|
+import MetricItem from "./MetricItem";
|
|
|
+import Modal from "@/components/layout/Modal";
|
|
|
+import LimitPickers from "@/components/input/LimitPickers";
|
|
|
+import SlidngScale from "@/components/input/SlidngScale";
|
|
|
+import NoData from "@/components/view/NoData";
|
|
|
+import { alphaToHex } from "@/utils/tools";
|
|
|
+import Layout from "@/components/layout/layout";
|
|
|
+import { MetricModalType, ModalType, NaviBarTitleShowType, TemplateType } from "@/utils/types";
|
|
|
+import { useTranslation } from "react-i18next";
|
|
|
+import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
|
|
|
+import TitleView from "@/features/trackTimeDuration/components/TitleView";
|
|
|
+import { setTabbarStatus } from "@/store/common";
|
|
|
+import MetricModalChoose from "./MetricModalChoose";
|
|
|
+import MetricModalOrder from './MetricModalOrder';
|
|
|
+
|
|
|
+let useNavigation;
|
|
|
+if (process.env.TARO_ENV == 'rn') {
|
|
|
+ useNavigation = require("@react-navigation/native").useNavigation
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+export default function Component(props: any) {
|
|
|
+ const { t } = useTranslation()
|
|
|
+ const user = useSelector((state: any) => state.user);
|
|
|
+ const [list, setList] = useState([])
|
|
|
+
|
|
|
+ const [isModalOpen, setIsModalOpen] = useState(false);
|
|
|
+ const [isTimePickerOpen, setIsTimePickerOpen] = useState(false);
|
|
|
+ const [pickerValue, setPickerValue] = useState([]);
|
|
|
+ const [pickerItems, setPickerItems] = useState([]);
|
|
|
+ const [isPoint, setIsPoint] = useState(false)
|
|
|
+
|
|
|
+ const [metricItem, setMetricItem] = useState({})
|
|
|
+
|
|
|
+ const [strTime, setStrTime] = useState('')
|
|
|
+ const [time, setTime] = useState(0)
|
|
|
+
|
|
|
+ const [showErrorPage, setErrorPage] = useState(false)
|
|
|
+
|
|
|
+ const [setupTime, setSetupTime] = useState(0)
|
|
|
+ const [triggered, setTriggered] = useState(true)
|
|
|
+ const limitPickerRef = useRef<any>(null);
|
|
|
+ const [count, setCount] = useState(0)
|
|
|
+ const [showPageContainer, setShowPageContainer] = useState(false)
|
|
|
+ const [modalType, setModalType] = useState(MetricModalType.none)
|
|
|
+ const [themeColor, setThemeColor] = useState('#00ffff')
|
|
|
+ const [groups, setGroups] = useState([])
|
|
|
+ const [orignalGroups,setOrignalGroups] = useState([])
|
|
|
+ const [limits, setLimits] = useState(null)
|
|
|
+ const [orders, setOrders] = useState([])
|
|
|
+ const dispatch = useDispatch();
|
|
|
+ let navigation;
|
|
|
+ if (useNavigation) {
|
|
|
+ navigation = useNavigation()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //未登录<->已登录 状态切换时,执行一次授权检查
|
|
|
+ useEffect(() => {
|
|
|
+ getCards();
|
|
|
+ getGroups();
|
|
|
+ const now = new Date();
|
|
|
+ const nextMidnight = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0);
|
|
|
+ const timeUntilMidnight = nextMidnight.getTime() - now.getTime();
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ setCount(count + 1)
|
|
|
+ }, timeUntilMidnight);
|
|
|
+ }, [user.isLogin])
|
|
|
+
|
|
|
+ const openModal = () => {
|
|
|
+ setSetupTime(new Date().getTime())
|
|
|
+ setIsModalOpen(true);
|
|
|
+ };
|
|
|
+
|
|
|
+ const closeModal = () => {
|
|
|
+ setIsModalOpen(false);
|
|
|
+ };
|
|
|
+
|
|
|
+ global.refreshMetric = () => {
|
|
|
+ getCards()
|
|
|
+ }
|
|
|
+
|
|
|
+ function getCards() {
|
|
|
+ setTriggered(true)
|
|
|
+ metricCards().then(res => {
|
|
|
+ Taro.stopPullDownRefresh()
|
|
|
+ setErrorPage(false)
|
|
|
+ setList((res as any).cards)
|
|
|
+ setTriggered(false)
|
|
|
+ if ((res as any).cards.length > 0) {
|
|
|
+ var obj = (res as any).cards[0]
|
|
|
+ setThemeColor(obj.theme_color)
|
|
|
+ }
|
|
|
+ var list: any = [];
|
|
|
+ (res as any).cards.map(item => {
|
|
|
+ list.push({
|
|
|
+ name: item.name,
|
|
|
+ code: item.code
|
|
|
+ })
|
|
|
+ })
|
|
|
+ setOrders(list)
|
|
|
+
|
|
|
+ }).catch(e => {
|
|
|
+ Taro.stopPullDownRefresh()
|
|
|
+ if (list.length == 0) {
|
|
|
+ setErrorPage(true)
|
|
|
+ }
|
|
|
+ setTriggered(false)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ function getGroups() {
|
|
|
+ metricGroups().then(res => {
|
|
|
+ var array = (res as any).groups
|
|
|
+ setOrignalGroups(JSON.parse(JSON.stringify(array)))
|
|
|
+ setGroups(array)
|
|
|
+ setLimits((res as any).num_options_limit)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //ts 把数组items: [{code: "_walk", value: 2180},{code: "_walk", value: 4444}]中的value取出来,/分割,组成字符串,如2180/4444
|
|
|
+ function getValues(items) {
|
|
|
+ var values = ''
|
|
|
+ items.map((item, index) => {
|
|
|
+ if (index == 0) {
|
|
|
+ values = item.value
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ values = values + '/' + item.value
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return values
|
|
|
+ }
|
|
|
+ function goDetail(item) {
|
|
|
+ if (user.isLogin) {
|
|
|
+ if (!item.latest_record) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ jumpPage('/pages/common/RecordsHistory?type=metric&refreshList=getCards&code=' + item.code + `&title=${item.name}` + '&themeColor=' + item.theme_color)
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function record(item: any) {
|
|
|
+
|
|
|
+ if (user.isLogin) {
|
|
|
+ var now = new Date();
|
|
|
+ var t = (now.getHours() < 10 ? '0' + now.getHours() : now.getHours()) + ":" + (now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes());
|
|
|
+ // setStrTime(t)
|
|
|
+ setStrTime(TimeFormatter.dateTimeFormate(now.getTime()))
|
|
|
+ setTime(now.getTime())
|
|
|
+ setMetricItem(item)
|
|
|
+ openModal()
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ jumpPage('/pages/account/ChooseAuth', 'ChooseAuth', navigation)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function showTimePicker() {
|
|
|
+
|
|
|
+ setIsTimePickerOpen(true)
|
|
|
+ }
|
|
|
+
|
|
|
+ function chooseTime(e) {
|
|
|
+ setTime(e);
|
|
|
+ setStrTime(TimeFormatter.dateTimeFormate(e))
|
|
|
+ setIsTimePickerOpen(false)
|
|
|
+ }
|
|
|
+
|
|
|
+ function cancelModal() {
|
|
|
+ (metricItem as any).schemas.map((item, index) => {
|
|
|
+ item.tempValue = ''
|
|
|
+ })
|
|
|
+ closeModal()
|
|
|
+ }
|
|
|
+
|
|
|
+ function confirmModal() {
|
|
|
+ closeModal()
|
|
|
+ var date = new Date(time)
|
|
|
+ var strDate = (date.getFullYear() + '') + (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
|
|
|
+
|
|
|
+ var array: any[] = [];
|
|
|
+ (metricItem as any).schemas.map((item, index) => {
|
|
|
+ array.push({
|
|
|
+ code: item.code,
|
|
|
+ value: item.tempValue && item.tempValue > 0 ? item.tempValue : item.default_value
|
|
|
+ })
|
|
|
+ })
|
|
|
+ var params = {
|
|
|
+ code: (metricItem as any).code,
|
|
|
+ timestamp: time,
|
|
|
+ date: strDate,
|
|
|
+ items: array,
|
|
|
+ extra: {
|
|
|
+ set_time: setupTime,
|
|
|
+ confirm_time: new Date().getTime()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ global.postBtnUpdateStatus('normal');
|
|
|
+ uploadMetric(params).then(res => {
|
|
|
+ // getCards();
|
|
|
+ (metricItem as any).schemas.map((item, index) => {
|
|
|
+ item.tempValue = ''
|
|
|
+ })
|
|
|
+
|
|
|
+ list.map((item, index) => {
|
|
|
+ if ((item as any).code == (res as any).code) {
|
|
|
+ (item as any).latest_record = (res as any).latest_record;
|
|
|
+ (item as any).schemas = (res as any).schemas;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ setList(JSON.parse(JSON.stringify(list)))
|
|
|
+
|
|
|
+ global.postBtnUpdateStatus('idle');
|
|
|
+ setTimeout(() => {
|
|
|
+ setCount(count + 1)
|
|
|
+ }, 31000)
|
|
|
+
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ const limitDay = 500
|
|
|
+
|
|
|
+ const limit = new Date().getTime() - limitDay * 3600 * 1000 * 24;
|
|
|
+
|
|
|
+ function detail() {
|
|
|
+ return <View>
|
|
|
+
|
|
|
+
|
|
|
+ <View className="metric_container">
|
|
|
+ {
|
|
|
+ list.map((item: any, index: number) => {
|
|
|
+ var unit = ''
|
|
|
+ var value = t('feature.track_something.metric.no_record')
|
|
|
+ var desc = t('feature.track_something.metric.check_unlock_data')
|
|
|
+ var showDetail = false;
|
|
|
+ if (item.latest_record) {
|
|
|
+ unit = item.schemas[0].default_unit
|
|
|
+ value = getValues(item.latest_record.items)
|
|
|
+ desc = TimeFormatter.dateDescription(item.latest_record.timestamp, true)
|
|
|
+ showDetail = true
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!user.isLogin) {
|
|
|
+ value = t('feature.track_something.metric.un_login')
|
|
|
+ desc = t('feature.track_something.metric.login_can_check')
|
|
|
+ }
|
|
|
+ return <MetricItem title={item.name}
|
|
|
+ value={value}
|
|
|
+ unit={unit}
|
|
|
+ desc={desc}
|
|
|
+ btnText={t('feature.track_something.btn_record')}
|
|
|
+ isDisabled={false}
|
|
|
+ showDetail={showDetail}
|
|
|
+ themeColor={item.theme_color}
|
|
|
+ onClickDetail={() => { goDetail(item) }}
|
|
|
+ onClick={() => { record(item) }}
|
|
|
+ />
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ </View>
|
|
|
+ <View className="space_width" ></View>
|
|
|
+ </View>
|
|
|
+ }
|
|
|
+
|
|
|
+ function detailContent() {
|
|
|
+ // if (process.env.TARO_ENV=='rn'){
|
|
|
+ // return <ScrollView>
|
|
|
+ // {
|
|
|
+ // detail()
|
|
|
+ // }
|
|
|
+ // <View style={{height:150}}/>
|
|
|
+ // </ScrollView>
|
|
|
+ // }
|
|
|
+ return detail()
|
|
|
+ }
|
|
|
+
|
|
|
+ function addBtnClick() {
|
|
|
+ Taro.showActionSheet({
|
|
|
+ itemList: [t('feature.track_something.metric.choose_metric'),
|
|
|
+ t('feature.track_something.metric.order')]
|
|
|
+ })
|
|
|
+ .then(res => {
|
|
|
+ switch (res.tapIndex) {
|
|
|
+ case 0:
|
|
|
+ global.metricAdd = true
|
|
|
+ setModalType(MetricModalType.choose)
|
|
|
+ dispatch(setTabbarStatus(false))
|
|
|
+ setShowPageContainer(true)
|
|
|
+
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ global.metricAdd = false
|
|
|
+ setModalType(MetricModalType.order)
|
|
|
+ dispatch(setTabbarStatus(false))
|
|
|
+ setShowPageContainer(true)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ console.log(err.errMsg)
|
|
|
+ })
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function headerView() {
|
|
|
+ return <TitleView title={t('page.metric.title')} showAddBtn={true} onClick={addBtnClick}>
|
|
|
+ </TitleView>
|
|
|
+ }
|
|
|
+
|
|
|
+ function metricModalContent() {
|
|
|
+ switch (modalType) {
|
|
|
+ case MetricModalType.choose:
|
|
|
+ return <MetricModalChoose
|
|
|
+ themeColor={themeColor}
|
|
|
+ cancel={modalCancel}
|
|
|
+ confirm={modalConfirm}
|
|
|
+ array={groups}
|
|
|
+ orders={orders}
|
|
|
+ limit={limits}
|
|
|
+ />
|
|
|
+ case MetricModalType.order:
|
|
|
+ return <MetricModalOrder
|
|
|
+ themeColor={themeColor}
|
|
|
+ cancel={modalOrderCancel}
|
|
|
+ confirm={modalOrderConfirm}
|
|
|
+ array={orders} />
|
|
|
+ }
|
|
|
+ return <View />
|
|
|
+ }
|
|
|
+
|
|
|
+ function modalCancel() {
|
|
|
+ dispatch(setTabbarStatus(true))
|
|
|
+ setShowPageContainer(false)
|
|
|
+ onPageContainerCancel()
|
|
|
+ }
|
|
|
+
|
|
|
+ function modalConfirm(datas) {
|
|
|
+ setOrders(datas)
|
|
|
+ setModalType(MetricModalType.order)
|
|
|
+ }
|
|
|
+
|
|
|
+ function modalOrderCancel() {
|
|
|
+ if (global.metricAdd) {
|
|
|
+ setModalType(MetricModalType.choose)
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ dispatch(setTabbarStatus(true))
|
|
|
+ setShowPageContainer(false)
|
|
|
+ onPageContainerCancel()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function modalOrderConfirm(datas) {
|
|
|
+ var array: any = []
|
|
|
+ datas.map(item => {
|
|
|
+ array.push(item.code)
|
|
|
+ })
|
|
|
+ metricFollows({ codes: array }).then(res => {
|
|
|
+ getCards()
|
|
|
+ getGroups()
|
|
|
+ })
|
|
|
+ dispatch(setTabbarStatus(true))
|
|
|
+ setShowPageContainer(false)
|
|
|
+ }
|
|
|
+
|
|
|
+ function onPageContainerCancel() {
|
|
|
+ if (modalType == MetricModalType.choose || modalType == MetricModalType.order) {
|
|
|
+ var array: any = [];
|
|
|
+ list.map(item => {
|
|
|
+ array.push({
|
|
|
+ name: (item as any).name,
|
|
|
+ code: (item as any).code
|
|
|
+ })
|
|
|
+ })
|
|
|
+ // debugger
|
|
|
+ setOrders(array)
|
|
|
+ setGroups(JSON.parse(JSON.stringify(orignalGroups)))
|
|
|
+ // setGroups(orignalGroups)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return <View style={{ position: 'relative' }}>
|
|
|
+ <Layout children={showErrorPage ? <NoData refresh={() => { getCards() }} /> : detailContent()}
|
|
|
+ title={t('page.metric.title')}
|
|
|
+ type={TemplateType.customHeader}
|
|
|
+ header={headerView()}
|
|
|
+ refresh={() => { getCards() }}
|
|
|
+ triggered={triggered}
|
|
|
+ titleShowStyle={NaviBarTitleShowType.scrollToShow}
|
|
|
+ />
|
|
|
+ <PageContainer style={{ backgroundColor: '#1c1c1c' }}
|
|
|
+ overlayStyle='background-color:rgba(0,0,0,0.9)'
|
|
|
+ custom-style='background-color:#1c1c1c'
|
|
|
+ closeOnSlideDown={false}
|
|
|
+ show={showPageContainer} round={true} overlay={true} position='bottom'
|
|
|
+ onClickOverlay={onPageContainerCancel}
|
|
|
+ onAfterLeave={() => { setShowPageContainer(false);setModalType(MetricModalType.none) }}
|
|
|
+ onBeforeLeave={() => { dispatch(setTabbarStatus(true)) }}
|
|
|
+ >
|
|
|
+ {
|
|
|
+ metricModalContent()
|
|
|
+ }
|
|
|
+ </PageContainer>
|
|
|
+ {
|
|
|
+ isModalOpen && <Modal dismiss={closeModal} title={(metricItem as any).name}
|
|
|
+ themeColor={(metricItem as any).theme_color}
|
|
|
+ confirm={confirmModal}>
|
|
|
+ <View style={{
|
|
|
+ display: 'flex', flexDirection: 'column',
|
|
|
+ width: '100%', color: '#000'
|
|
|
+ }}>
|
|
|
+ <Text className='modal_title' style={{ color: (metricItem as any).theme_color }}>{(metricItem as any).name ? (metricItem as any).name : ''}</Text>
|
|
|
+ <View style={{ position: 'relative' }}>
|
|
|
+ {
|
|
|
+ (metricItem as any).schemas.map((item, index) => {
|
|
|
+ return <View key={index}>
|
|
|
+ {
|
|
|
+ (metricItem as any).schemas.length > 1 && <Text style={{
|
|
|
+ textAlign: 'center', width: '100%', display: 'flex',
|
|
|
+ justifyContent: 'center', color: (metricItem as any).theme_color
|
|
|
+ }}>{item.name}</Text>
|
|
|
+ }
|
|
|
+ <SlidngScale step={item.step} min={item.min} max={item.max} default_value={item.default_value}
|
|
|
+ unit={item.default_unit}
|
|
|
+ themeColor={(metricItem as any).theme_color}
|
|
|
+ changed={(e) => { item.tempValue = e }} />
|
|
|
+ </View>
|
|
|
+ })
|
|
|
+ }
|
|
|
+ </View>
|
|
|
+ <View className="change_time_bg ">
|
|
|
+ <View className="gray1 time_bg" onClick={showTimePicker}>
|
|
|
+ <Text className="time" >{strTime}</Text>
|
|
|
+ </View>
|
|
|
+
|
|
|
+ </View>
|
|
|
+ <View className='modal_operate'>
|
|
|
+ <View className='modal_btn' style={{ backgroundColor: (metricItem as any).theme_color + alphaToHex(0.4) }} onClick={cancelModal}>
|
|
|
+ <Text className='modal_cancel_text' style={{ color: (metricItem as any).theme_color }}>{
|
|
|
+ t('feature.common.picker_cancel_btn')
|
|
|
+ }</Text>
|
|
|
+ </View>
|
|
|
+ <View className='btn_space' />
|
|
|
+ <View className='modal_btn' style={{ backgroundColor: (metricItem as any).theme_color }} onClick={confirmModal}>
|
|
|
+ <Text className='modal_confirm_text' style={{ color: '#000' }}>{
|
|
|
+ t('feature.common.picker_confirm_btn')
|
|
|
+ }</Text>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </Modal>
|
|
|
+ }
|
|
|
+ {
|
|
|
+
|
|
|
+ isTimePickerOpen && <Modal
|
|
|
+ themeColor={(metricItem as any).theme_color}
|
|
|
+ dismiss={() => setIsTimePickerOpen(false)} confirm={() => {
|
|
|
+ var picker = limitPickerRef.current;
|
|
|
+ chooseTime((picker as any).getConfirmData());
|
|
|
+ setIsTimePickerOpen(false);
|
|
|
+ }}>
|
|
|
+ <LimitPickers ref={limitPickerRef}
|
|
|
+ isRealTime={true} time={time} limit={limit}
|
|
|
+ title={t('feature.track_something.picker_datetime')}
|
|
|
+ themeColor={(metricItem as any).theme_color}
|
|
|
+ limitDay={limitDay} onCancel={() => { setIsTimePickerOpen(false) }}
|
|
|
+ onChange={(e) => {
|
|
|
+ chooseTime(e)
|
|
|
+ // pickerConfirm(e)
|
|
|
+ // hidePicker()
|
|
|
+ }} />
|
|
|
+ </Modal>
|
|
|
+ }
|
|
|
+ </View>
|
|
|
+
|
|
|
+}
|