Leon 2 vuotta sitten
vanhempi
commit
1d17567794
33 muutettua tiedostoa jossa 654 lisäystä ja 251 poistoa
  1. 2 0
      src/app.config.ts
  2. BIN
      src/assets/images/arrow.png
  3. 57 45
      src/components/basic/Buttons.scss
  4. 52 3
      src/components/basic/Buttons.tsx
  5. 6 2
      src/components/input/Stepper.scss
  6. 9 1
      src/components/layout/Box.scss
  7. 10 4
      src/components/layout/Box.tsx
  8. 23 0
      src/components/layout/Header.scss
  9. 9 0
      src/components/layout/Header.tsx
  10. 16 3
      src/components/layout/Modal.scss
  11. 16 11
      src/components/layout/Modal.tsx
  12. 1 1
      src/components/layout/layout.tsx
  13. 5 0
      src/context/locales/en.js
  14. 5 0
      src/context/locales/zh.js
  15. 19 2
      src/custom-tab-bar/index.scss
  16. 17 5
      src/custom-tab-bar/index.tsx
  17. 4 0
      src/features/common/RecordItem.scss
  18. 53 0
      src/features/common/RecordItem.tsx
  19. 24 0
      src/features/common/SpecBtns.tsx
  20. 37 19
      src/features/trackSomething/components/ActivityHistory.tsx
  21. 2 1
      src/features/trackSomething/components/Metric.scss
  22. 30 26
      src/features/trackSomething/components/Metric.tsx
  23. 0 2
      src/features/trackSomething/components/MetricHistory.scss
  24. 43 18
      src/features/trackSomething/components/MetricHistory.tsx
  25. 4 26
      src/features/trackTimeDuration/components/Console.tsx
  26. 26 0
      src/features/trackTimeDuration/components/Schedule.scss
  27. 137 65
      src/features/trackTimeDuration/components/Schedule.tsx
  28. 4 4
      src/features/trackTimeDuration/hooks/Console.tsx
  29. 2 8
      src/pages/clock/Clock.tsx
  30. 1 1
      src/pages/common/RecordsHistory.tsx
  31. 5 1
      src/pages/demo.tsx
  32. 26 0
      src/services/trackSomething.tsx
  33. 9 3
      src/utils/types.ts

+ 2 - 0
src/app.config.ts

@@ -2,6 +2,8 @@ const appConfig = defineAppConfig({
   pages: [
     'pages/clock/Clock',
     'pages/demo',
+    
+    
     'pages/index/index',
     'pages/account/Login',
     'pages/account/Auth',

BIN
src/assets/images/arrow.png


+ 57 - 45
src/components/basic/Buttons.scss

@@ -1,48 +1,60 @@
-@import '@/utils/common.scss';
-
-/* #ifdef weapp */ 
-.btn{
-    background-color: $themeColor;
-    border: none;
-    height: 90px;
-    border-radius: 45px;
+// @import '@/utils/common.scss';
+
+// /* #ifdef weapp */ 
+// .btn{
+//     background-color: $themeColor;
+//     border: none;
+//     height: 90px;
+//     border-radius: 45px;
+// }
+
+// .outline_btn{
+//     border: solid 4px $themeColor !important;
+//     background-color: transparent;
+//     color: $themeColor;
+//     border: none;
+//     height: 90px !important;
+//     border-radius: 45px !important;
+// }
+// /* #endif */ 
+
+
+// /* #ifdef rn */ 
+// .btn{
+//     background-color: $themeColor;
+//     height: 90px;
+//     border-radius: 45px;
+// }
+
+// .outline_btn{
+//     border-style: solid;
+//     border-width: 4px;
+//     border-color: $themeColor;
+//     background-color: transparent;
+//     color: $themeColor;
+//     height: 90px;
+//     border-radius: 45px;
+// }
+// /* #endif */ 
+
+// .btn::after{
+//     border: 0;
+// }
+
+
+
+// .outline_btn::after{
+//     border: none;
+// }
+
+
+.elevated{
+    display: flex;
+    align-items: center;
+    justify-content: center;
 }
 
-.outline_btn{
-    border: solid 4px $themeColor !important;
-    background-color: transparent;
-    color: $themeColor;
-    border: none;
-    height: 90px !important;
-    border-radius: 45px !important;
-}
-/* #endif */ 
-
-
-/* #ifdef rn */ 
-.btn{
-    background-color: $themeColor;
-    height: 90px;
-    border-radius: 45px;
-}
-
-.outline_btn{
-    border-style: solid;
-    border-width: 4px;
-    border-color: $themeColor;
-    background-color: transparent;
-    color: $themeColor;
-    height: 90px;
-    border-radius: 45px;
-}
-/* #endif */ 
-
-.btn::after{
-    border: 0;
-}
-
-
-
-.outline_btn::after{
-    border: none;
+.textClass{
+    height: '100%';
+    line-height: '100%';
 }

+ 52 - 3
src/components/basic/Buttons.tsx

@@ -1,11 +1,12 @@
-import { Button, View } from "@tarojs/components";
+import { Button, View, Text } from "@tarojs/components";
 import './Buttons.scss'
 import { ButtonType, ComponentStatus } from "../../utils/types";
 
-import {Button as RNButton} from 'react-native' ;
+import { Button as RNButton } from 'react-native';
 
 
 
+/*
 export default function Buttons(props: { title: string, type?: ButtonType, status?: ComponentStatus,onClick?:()=>void,style?:any }) {
     
     const myStyle = props.status == ComponentStatus.disable ? { opacity: 0.4 } : {}
@@ -15,4 +16,52 @@ export default function Buttons(props: { title: string, type?: ButtonType, statu
         </View>
 
     )
-}
+}*/
+
+export default function Buttons(props: {
+    title: string,
+    type?: ButtonType,
+    onClick: () => void,
+    disabled?: boolean,
+    lowLight?: boolean,
+    openType?: string,
+    btnStyle?: any,
+}) {
+
+    function onClick() {
+        if (props.disabled) return
+        props.onClick()
+    }
+
+
+    var mainClass = 'elevated'
+    var textClass = 'elevated_text'
+    if (props.type == ButtonType.outline) {
+        mainClass = 'outlined'
+        textClass = 'outlined_text'
+    }
+    else {
+        mainClass = 'puretext'
+        textClass = 'puretext_text'
+    }
+    return (
+        <View className={mainClass} style={{...props.btnStyle}}>
+            <Text
+                style={{
+                    color: props.btnStyle.color,
+                    fontSize: props.btnStyle.fontSize
+                }}>{props.title}</Text>
+        </View>
+        // <View  onClick={onClick}>
+        //     <Text 
+        //         style={{
+        //             height: props.btnStyle.height,
+        //             lineHeight: props.btnStyle.height,
+        //             color: props.btnStyle.color,
+        //             fontSize: props.btnStyle.fontSize
+        //         }}>{props.title}</Text>
+        // </View>
+    )
+}
+
+

+ 6 - 2
src/components/input/Stepper.scss

@@ -3,11 +3,15 @@
     flex-direction: row;
     align-items: center;
     background-color: #000;
+    height: 104px;
+    border-radius: 52px;
+    padding: 16px;
+    box-sizing: border-box;
 }
 
 .stepper_icon{
-    width: 30px;
-    height: 30px;
+    width: 40px;
+    height: 40px;
 }
 
 .stepper_item{

+ 9 - 1
src/components/layout/Box.scss

@@ -1,10 +1,18 @@
 .box-container{
     background-color: #1C1C1C;
     border-radius: 56px;
-    padding: 80px 40px 80px 40px;
+    padding: 40px;
     margin-left: 46px;
     margin-right: 46px;
     display: flex;
     flex-direction: column;
     position: relative;
+}
+
+.box-title{
+    font-size: 40px;
+    line-height: 40px;
+    color: #fff;
+    font-weight: 500;
+    margin-bottom: 40px;
 }

+ 10 - 4
src/components/layout/Box.tsx

@@ -1,8 +1,14 @@
-import { View } from "@tarojs/components";
+import { View,Text } from "@tarojs/components";
 import './Box.scss'
 
-export default function Component(props: { children: React.ReactNode }) {
-    return <View className="box-container">
-        {props.children}
+export default function Component(props: { children: React.ReactNode,title?:string, header?: React.ReactNode }) {
+    return <View>
+        {props.header ? props.header : null}
+        <View className="box-container">
+            {
+                props.title && <Text className="box-title">{props.title}</Text>
+            }
+            {props.children}
+        </View>
     </View>;
 }

+ 23 - 0
src/components/layout/Header.scss

@@ -0,0 +1,23 @@
+.header{
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    height: 96px;
+    align-items: center;
+    margin-left: 46px;
+    margin-right: 46px;
+}
+
+.header_title{
+    color: #fff;
+    font-size: 48px;
+    line-height: 48px;
+    font-weight: 500;
+}
+
+.header_action{
+    color: #AAFF00;
+    font-size: 32px;
+    line-height: 32px;
+    font-weight: 400;
+}

+ 9 - 0
src/components/layout/Header.tsx

@@ -0,0 +1,9 @@
+import { View, Text } from "@tarojs/components";
+import './Header.scss'
+
+export default function Component(props: { title: string, action?: Function }) {
+    return <View className="header">
+        <Text className="header_title">{props.title}</Text>
+        <Text className="header_action" onClick={() => { props.action!() }}>显示更多</Text>
+    </View>
+}

+ 16 - 3
src/components/layout/Modal.scss

@@ -4,8 +4,8 @@
     top: 0;
     left: 0;
     z-index: 100000;
-    width: 100%;
-    height: 100%;
+    right: 0;
+    bottom: 0;
     overflow: hidden;
     display: flex;
     flex-direction: column;
@@ -14,6 +14,8 @@
 
 
 
+
+
 /* #endif */ 
 
 
@@ -24,8 +26,19 @@
 
 /* #endif */ 
 
+.modal_center_container{
+    align-items: center;
+    justify-content: center;
+}
+
+.modal_center_content{
+    background-color: #1c1c1c;
+    border-radius: 36rpx;
+    width: 658px;
+}
+
 
-.modal_content{
+.modal_bottom_content{
     padding-bottom: 120px;
     width: 750px;
     background-color: #1c1c1c;

+ 16 - 11
src/components/layout/Modal.tsx

@@ -1,6 +1,7 @@
 import { View, Text } from '@tarojs/components'
 import './Modal.scss'
 import React from 'react';
+import { ModalType } from '@/utils/types';
 
 export default function Modal(props: {
     children: React.ReactNode,
@@ -8,20 +9,24 @@ export default function Modal(props: {
     title?: string, dismiss: Function,
     confirm: Function,
     themeColor?: string,
+    modalType?:ModalType
 }) {
-    var color = props.themeColor ? props.themeColor : '#ff0000'
 
-    function alphaToHex(alpha) {
-        var alphaValue = Math.round(alpha * 255); // 将透明度乘以255并四舍五入
-        var hexValue = alphaValue.toString(16); // 将整数转换为十六进制字符串
-        if (hexValue.length === 1) {
-            hexValue = "0" + hexValue; // 如果十六进制字符串只有一位,补零
-        }
-        return hexValue;
+    //阻止中间内容点击事件穿透
+    function click(e){
+        e.stopPropagation();
     }
 
-    var alpha = alphaToHex(0.4)
-
+    switch (props.modalType) {
+        case ModalType.center:
+            return <View className='modal modal_center_container' catchMove onClick={() => props.dismiss()}>
+                <View className='modal_center_content' onClick={click}>
+                    {
+                        props.children
+                    }
+                </View>
+            </View>
+    }
     return <View className='modal' catchMove>
 
         <View style={{ flex: 1 }} onClick={() => props.dismiss()}>
@@ -29,7 +34,7 @@ export default function Modal(props: {
                 props.testInfo ? props.testInfo : null
             }
         </View>
-        <View className='modal_content'>
+        <View className='modal_bottom_content'>
             {/* <Text className='modal_title' style={{ color: color }}>{props.title ? props.title : '测试标题 '}</Text> */}
             {
                 props.children

+ 1 - 1
src/components/layout/layout.tsx

@@ -27,7 +27,7 @@ export default function Layout(props: {
 
     function onScroll(e) {
         if (props.titleShowStyle == NaviBarTitleShowType.scrollToShow) {
-            if (e.detail.scrollTop > 80) {
+            if (e.detail.scrollTop > 70) {
                 setShowTitle(true)
             }
             else {

+ 5 - 0
src/context/locales/en.js

@@ -32,6 +32,11 @@ export default {
             title:'',
             btn_done:''
         },
+        clock:{
+            schedule:{
+                title:'Schedule',
+            }
+        },
         activity:{
             title:'Activity',
         },

+ 5 - 0
src/context/locales/zh.js

@@ -28,6 +28,11 @@ export default {
             sleep:'睡眠',
             fast_sleep:'断食睡眠',
         },
+        clock:{
+            schedule:{
+                title:'日程',
+            }
+        },
         activity:{
             title:'运动',
         },

+ 19 - 2
src/custom-tab-bar/index.scss

@@ -5,18 +5,35 @@
     bottom: 0;
     left: 0;
     right: 0;
-    height: 96px;
+    height: 104px;
     flex-direction: row;
     justify-content: space-around;
     background-color: #000;
+    // background-color: #000;
     // background-color: red;
     padding-bottom: constant(safe-area-inset-bottom);
     /* 兼容 iOS < 11.2 */
     padding-bottom: env(safe-area-inset-bottom);
+    border-top-color: rgba($color: #ffffff, $alpha: 0.2);
+    border-top-width: 1px;
+    border-top-style: solid;
     z-index: 100;
 }
 
+//未选中 18 40%
+//选中 20 100%
+
 .tabbar-item{
-    color: #fff;
+    color: rgba($color: #ffffff, $alpha: 0.4);
+    font-size: 36px;
     padding-top: 25px;
+    display: flex;
+    flex: 1;
+    align-items: center;
+    justify-content: center;
+}
+
+.tabbar-item-sel{
+    color: #ffffff;
+    font-size: 40px;
 }

+ 17 - 5
src/custom-tab-bar/index.tsx

@@ -1,14 +1,25 @@
-import { View,Text } from '@tarojs/components'
+import { View, Text } from '@tarojs/components'
 import './index.scss'
 import { useTranslation } from 'react-i18next'
 import Taro from '@tarojs/taro'
+import { useEffect, useState } from 'react'
 
 export default function TabBar() {
     const { t } = useTranslation()
+    const [selIndex, setSelIndex] = useState(0)
+
+    const pages = Taro.getCurrentPages();
+    const currentPage = pages[0];
+
+    useEffect(() => {
+        setSelIndex(global.index?global.index:0)
+      }, [global.index])
 
     function switchTab(index: number) {
+        global.index = index;
         switch (index) {
             case 0:
+
                 Taro.switchTab({
                     url: '/pages/clock/Clock'
                 })
@@ -19,6 +30,7 @@ export default function TabBar() {
                 })
                 break;
             case 2:
+
                 Taro.switchTab({
                     url: '/pages/activity/Activity'
                 })
@@ -32,18 +44,18 @@ export default function TabBar() {
     }
     return (
         <View className='tabbar'>
-            <View className='tabbar-item' onClick={()=>switchTab(0)}>
+            <View className={selIndex == 0 ? 'tabbar-item tabbar-item-sel' : 'tabbar-item'} onClick={() => switchTab(0)}>
                 <Text>{t('feature.tabbar.clock')}</Text>
             </View>
-            <View className='tabbar-item'  onClick={()=>switchTab(1)}>
+            <View className={selIndex == 1 ? 'tabbar-item tabbar-item-sel' : 'tabbar-item'} onClick={() => switchTab(1)}>
 
                 <Text>{t('feature.tabbar.metric')}</Text>
             </View>
-            <View className='tabbar-item' onClick={()=>switchTab(2)}>
+            <View className={selIndex == 2 ? 'tabbar-item tabbar-item-sel' : 'tabbar-item'} onClick={() => switchTab(2)}>
 
                 <Text>{t('feature.tabbar.activity')}</Text>
             </View>
-            <View className='tabbar-item' onClick={()=>switchTab(3)}>
+            <View className={selIndex == 3 ? 'tabbar-item tabbar-item-sel' : 'tabbar-item'} onClick={() => switchTab(3)}>
                 <Text>{t('feature.tabbar.profile')}</Text>
             </View>
         </View>

+ 4 - 0
src/features/common/RecordItem.scss

@@ -0,0 +1,4 @@
+
+.recordItem{
+    margin-top: 20px;
+}

+ 53 - 0
src/features/common/RecordItem.tsx

@@ -0,0 +1,53 @@
+import { View } from "@tarojs/components";
+import React from "react";
+import './RecordItem.scss'
+import Taro from "@tarojs/taro";
+
+
+export default function Component(props: { children: React.ReactNode,onClick?:Function, delete?: Function, canDel?: boolean }) {
+
+    function click(){
+        if (props.onClick) {
+            props.onClick();
+        }
+        else {
+            Taro.vibrateShort();
+        }
+    }
+    
+    function longPress() {
+        if (!props.delete) {
+            return;
+        }
+        Taro.showActionSheet({
+            itemList: ['删除']
+        })
+            .then(res => {
+                switch (res.tapIndex) {
+                    case 0:
+                        Taro.showModal({
+                            title: '删除',
+                            content: '确认要删除吗?',
+                            success: function (res) {
+                                if (res.confirm) {
+                                    console.log('delete')
+                                    props.delete!();
+                                }
+                            }
+                        })
+                        break;
+                    case 1:
+
+                        break;
+                }
+            })
+            .catch(err => {
+                console.log(err.errMsg)
+            })
+
+    }
+    //gesture  onClick onLongPress 有效
+    return <View className="recordItem" onLongPress={longPress} onClick={click}>
+        {props.children}
+    </View>
+}

+ 24 - 0
src/features/common/SpecBtns.tsx

@@ -0,0 +1,24 @@
+import Buttons from "@/components/basic/Buttons"
+import { ButtonType } from "@/utils/types"
+import { View,Text } from "@tarojs/components"
+
+export const StartFastBtn = (props: { onClick: Function }) => {
+    return (
+        <Buttons title="开始断食" type={ButtonType.elevated}
+            onClick={() => { props.onClick() }}
+            btnStyle={{
+                height: 50, 
+                borderRadius: 25,
+                backgroundColor: '#AAFF00',
+                paddingLeft: 40,
+                paddingRight: 40,
+                color:'black',
+                fontSize:20,
+                display:'flex',
+                alignItems:'center',
+                justifyContent:'center',
+                // lineHeight:20
+            }}
+        />
+    )
+}

+ 37 - 19
src/features/trackSomething/components/ActivityHistory.tsx

@@ -1,12 +1,19 @@
 import { View, Text } from "@tarojs/components";
 import './MetricHistory.scss'
+import RecordItem from "@/features/common/RecordItem";
+import { deleteActivityRecord } from "@/services/trackSomething";
+import { useEffect, useState } from "react";
 
 export default function Component(props: { records: any[] }) {
+    const [list, setList] = useState(props.records)
+    useEffect(()=>{
+        setList(props.records)
+    },[props.records])
     function formateDate(date: string) {
         //yyyyMMdd转换成日期,如果是今天,返回今天,如果是昨天,返回昨天,如果是昨天之前,返回日期
-        const dt = new Date(date.substring(0,4) + '/' + 
-        date.substring(4,6) + '/' +
-        date.substring(6));
+        const dt = new Date(date.substring(0, 4) + '/' +
+            date.substring(4, 6) + '/' +
+            date.substring(6));
 
         const now = new Date();
 
@@ -18,9 +25,9 @@ export default function Component(props: { records: any[] }) {
         } else if (diff < 2 * day) {
             return '昨天';
         } else {
-            return date.substring(0,4) + '-' + 
-            date.substring(4,6) + '-' +
-            date.substring(6)//dt.toISOString().slice(0, 10);
+            return date.substring(0, 4) + '-' +
+                date.substring(4, 6) + '-' +
+                date.substring(6)//dt.toISOString().slice(0, 10);
         }
     }
     function formateHourMinutes(timestamp: number) {
@@ -30,10 +37,19 @@ export default function Component(props: { records: any[] }) {
         return `${hour < 10 ? '0' + hour : hour}:${minutes < 10 ? '0' + minutes : minutes}`
     }
 
-    function clear(){
+    function clear() {
 
     }
-    
+
+    function deleteRecord(record: any) {
+
+        deleteActivityRecord({ id: record.id }).then(res => {
+            list.splice(list.findIndex(item => item.records[0].id == record.id), 1)
+            setList([...list])
+            global.refreshActivity()
+        })
+    }
+
     return <View style={{ display: 'flex', flexDirection: 'column' }}>
         {/* <View className="operate_view">
             <Text>时间倒序</Text>
@@ -42,21 +58,23 @@ export default function Component(props: { records: any[] }) {
             <View style={{flex:1}}/>
         </View> */}
         {
-            (props.records as any).map(item => {
+            (list as any).map(item => {
                 return <View style={{ display: 'flex', flexDirection: 'column' }}>
-                    <Text className="operate_day">{formateDate(item.date+'')}</Text>
+                    <Text className="operate_day">{formateDate(item.date + '')}</Text>
                     {
                         item.records.map(record => {
-                            return <View className="operate_item">
-                                <View className="status_bg">
-                                    <Text className="status_text">{record.type == 'total' ? '总计' : record.type == 'sync' ? '同步' : '打卡'}</Text>
+                            return <RecordItem delete={()=>deleteRecord(record)}>
+                                <View className="operate_item">
+                                    <View className="status_bg">
+                                        <Text className="status_text">{record.type == 'total' ? '总计' : record.type == 'sync' ? '同步' : '打卡'}</Text>
+                                    </View>
+                                    <View style={{ width: 12 }} />
+                                    <Text className="value">{record.items[0].value}</Text>
+                                    <Text className="unit">步</Text>
+                                    <View style={{ flex: 1 }} />
+                                    <Text className="time">{formateHourMinutes(record.timestamp)}</Text>
                                 </View>
-                                <View style={{width:12}}/>
-                                <Text className="value">{record.items[0].value}</Text>
-                                <Text className="unit">步</Text>
-                                <View style={{ flex: 1 }} />
-                                <Text className="time">{formateHourMinutes(record.timestamp)}</Text>
-                            </View>
+                            </RecordItem>
                         })
                     }
                 </View>

+ 2 - 1
src/features/trackSomething/components/Metric.scss

@@ -8,8 +8,9 @@
 .space_width{
     display: flex;
     width: 320px;
-    height: 100px;
+    height: 300px;
     flex-shrink: 0;
+    opacity: 0;
 }
 
 .change_time_bg{

+ 30 - 26
src/features/trackSomething/components/Metric.tsx

@@ -96,7 +96,7 @@ export default function Component(props: any) {
                 return
             }
             Taro.navigateTo({
-                url: '/pages/common/RecordsHistory?type=metric&refreshList=getCards&code=' + item.code+`&title=${item.name}`
+                url: '/pages/common/RecordsHistory?type=metric&refreshList=getCards&code=' + item.code + `&title=${item.name}`
             })
         }
         else {
@@ -281,31 +281,36 @@ export default function Component(props: any) {
     const limit = new Date().getTime() - 180 * 3600 * 1000 * 24;
 
     function detail() {
-        return <View className="metric_container">
-            {
-                list.map((item: any, index: number) => {
-                    var unit = ''
-                    var value = '无记录'
-                    var desc = '记录解锁趋势'
-                    if (item.latest_record) {
-                        unit = item.schemas[0].default_unit
-                        value = getValues(item.latest_record.items)
-                        desc = TimeFormatter.formatTimestamp(item.latest_record.timestamp)
-                    }
-                    return <MetricItem title={item.name}
-                        value={value}
-                        unit={unit}
-                        desc={desc}
-                        btnText='记录'
-                        isDisabled={false}
-                        themeColor={item.theme_color}
-                        onClickDetail={() => { goDetail(item) }}
-                        onClick={() => { record(item) }}
-                    />
-                })
-            }
-            <View className="space_width" />
+        return <View>
+
+
+            <View className="metric_container">
+                {
+                    list.map((item: any, index: number) => {
+                        var unit = ''
+                        var value = '无记录'
+                        var desc = '记录解锁趋势'
+                        if (item.latest_record) {
+                            unit = item.schemas[0].default_unit
+                            value = getValues(item.latest_record.items)
+                            desc = TimeFormatter.formatTimestamp(item.latest_record.timestamp)
+                        }
+                        return <MetricItem title={item.name}
+                            value={value}
+                            unit={unit}
+                            desc={desc}
+                            btnText='记录'
+                            isDisabled={false}
+                            themeColor={item.theme_color}
+                            onClickDetail={() => { goDetail(item) }}
+                            onClick={() => { record(item) }}
+                        />
+                    })
+                }
+
 
+            </View>
+            <View className="space_width" >11</View>
         </View>
     }
 
@@ -317,7 +322,6 @@ export default function Component(props: any) {
             type={TemplateType.grid}
             refresh={() => { getCards() }}
             triggered={triggered}
-            more={() => { getCards() }}
             titleShowStyle={NaviBarTitleShowType.scrollToShow}
         />
         {

+ 0 - 2
src/features/trackSomething/components/MetricHistory.scss

@@ -16,8 +16,6 @@
 }
 
 .operate_item{
-    // width: 658px;
-    margin-top: 20px;
     height: 136px;
     margin-left: 46px;
     margin-right: 46px;

+ 43 - 18
src/features/trackSomething/components/MetricHistory.tsx

@@ -1,7 +1,15 @@
 import { View, Text } from "@tarojs/components";
 import './MetricHistory.scss'
+import RecordItem from "@/features/common/RecordItem";
+import { deleteMetricRecord } from "@/services/trackSomething";
+import { useEffect, useState } from "react";
 
 export default function Component(props: { records: any[] }) {
+    const [list, setList] = useState(props.records)
+    useEffect(()=>{
+        setList(props.records)
+    },[props.records])
+    
     function formateDate(date: string) {
         //yyyyMMdd转换成日期,如果是今天,返回今天,如果是昨天,返回昨天,如果是昨天之前,返回日期
         const dt = new Date(date.substring(0, 4) + '/' +
@@ -31,36 +39,53 @@ export default function Component(props: { records: any[] }) {
         return `${hour < 10 ? '0' + hour : hour}:${minutes < 10 ? '0' + minutes : minutes}`
     }
 
+    function deleteRecord(record: any) {
+        deleteMetricRecord({ id: record.id }).then(res => {
+            list.map(item => {
+                item.records.splice(item.records.findIndex(item => item.id == record.id), 1)
+            })
+            for (let i=list.length;i>0;i--){
+                if(list[i-1].records.length==0){
+                    list.splice(i-1,1)
+                }
+            }
+            console.log(list)
+            global.refreshMetric()
+        })
+    }
+
     return <View style={{ display: 'flex', flexDirection: 'column' }}>
-        <View className="operate_view">
+        {/* <View className="operate_view">
             <Text>时间倒序</Text>
             <View style={{ marginLeft: 5, marginRight: 5, display: 'flex', height: '100%' }}>
                 <Text > | </Text>
             </View>
             <Text>时间正序</Text>
-        </View>
+        </View> */}
         {
-            (props.records as any).map(item => {
+            (list as any).map(item => {
                 return <View style={{ display: 'flex', flexDirection: 'column' }}>
                     <Text className="operate_day">{formateDate(item.date + '')}</Text>
                     {
                         item.records.map(record => {
-                            return <View className="operate_item">
-                                <View className="status_bg">
-                                    {/* <Text className="status_text">{record.type == 'total' ? '总计' : record.type == 'sync' ? '同步' : '打卡'}</Text> */}
+                            return <RecordItem delete={() => deleteRecord(record)}>
+                                <View className="operate_item">
+                                    <View className="status_bg">
+                                        {/* <Text className="status_text">{record.type == 'total' ? '总计' : record.type == 'sync' ? '同步' : '打卡'}</Text> */}
+                                    </View>
+                                    <View style={{ width: 12 }} />
+                                    <Text className="value">{record.items[0].value}</Text>
+                                    {
+                                        record.items.length > 1 && <Text className="value">/{record.items[1].value}</Text>
+                                    }
+                                    {
+                                        record.items.length > 2 && <Text className="value">/{record.items[2].value}</Text>
+                                    }
+                                    <Text className="unit">{record.items[0].unit}</Text>
+                                    <View style={{ flex: 1 }} />
+                                    <Text className="time">{formateHourMinutes(record.timestamp)}</Text>
                                 </View>
-                                <View style={{width:12}}/>
-                                <Text className="value">{record.items[0].value}</Text>
-                                {
-                                    record.items.length>1 && <Text className="value">/{record.items[1].value}</Text>
-                                }
-                                {
-                                    record.items.length>2 && <Text className="value">/{record.items[2].value}</Text>
-                                }
-                                <Text className="unit">{record.items[0].unit}</Text>
-                                <View style={{ flex: 1 }} />
-                                <Text className="time">{formateHourMinutes(record.timestamp)}</Text>
-                            </View>
+                            </RecordItem>
                         })
                     }
                 </View>

+ 4 - 26
src/features/trackTimeDuration/components/Console.tsx

@@ -12,6 +12,7 @@ import { durationDatas, durationIndex, pickerDurations } from "../hooks/Console"
 import PickerViews from "@/components/input/PickerViews";
 import Modal from "@/components/layout/Modal";
 import Stepper from "@/components/input/Stepper";
+import { StartFastBtn } from "@/features/common/SpecBtns";
 
 export default function Component() {
     const scenario = useSelector((state: any) => state.scenario);
@@ -238,10 +239,11 @@ export default function Component() {
     }
 
     function mixedBtns() {
-        return <View>
+        return <View style={{display:'flex'}}>
             {
                 (value == 'WAIT_FOR_START' || value == 'DONE') &&
-                <Text style={{ color: '#AAFF00' }} onClick={showPicker}>Start Fast</Text>
+                <StartFastBtn onClick={showPicker} />
+                // <Text style={{ color: '#AAFF00' }} onClick={showPicker}>Start Fast</Text>
             }
             {
                 (value == 'ONGOING'/* ||value == 'ONGOING1' || value == 'ONGOING2'*/ || value == 'ONGOING3') &&
@@ -453,30 +455,6 @@ export default function Component() {
                 }} />
             }
 
-            {/* {
-                showModal && <AtFloatLayout
-                    isOpened={isOpen}
-                    onClose={() => {
-                        setIsOpen(false)
-                        setShowModal(false)
-                    }}
-                    title="">
-                    {
-                        layoutContent()
-                    }
-                </AtFloatLayout>
-            }
-            <AtFloatLayout
-                isOpened={isOpenDurationPicker}
-                onClose={() => {
-                    setIsOpenDurationPicker(false)
-                }}
-                title="">
-                {
-                    durationPickerContent()
-                }
-            </AtFloatLayout> */}
-
         </View>
     )
 }

+ 26 - 0
src/features/trackTimeDuration/components/Schedule.scss

@@ -0,0 +1,26 @@
+.duration_bg{
+    margin-left: 50px;
+    display: flex;
+    flex-direction: column;
+    flex: 1;
+}
+
+.duration_title{
+    font-size: 32px;
+    line-height: 32px;
+    color: #fff;
+    opacity: 0.6;
+    font-weight: 400;
+}
+
+.duration_value{
+    font-size: 36px;
+    line-height: 36px;
+    font-weight: 500;
+    margin-bottom: 12px;
+}
+
+.arrow1{
+    width: 48px;
+    height: 48px;
+}

+ 137 - 65
src/features/trackTimeDuration/components/Schedule.tsx

@@ -1,4 +1,4 @@
-import { View, Text } from "@tarojs/components";
+import { View, Text, Image } from "@tarojs/components";
 import trackTimeService, { machine } from "@/store/trackTimeMachine"
 import { useEffect, useState } from "react";
 import Taro from "@tarojs/taro";
@@ -9,19 +9,22 @@ import Modal from "@/components/layout/Modal";
 import Rings, { BgRing, CurrentDot, RealRing, RingCommon } from './Rings';
 import { getBgRing, getCommon, getDot, getReal, getTarget } from "../hooks/RingData";
 import Timeline from "@/components/view/Timeline";
+import RecordItem from "@/features/common/RecordItem";
+import Box from "@/components/layout/Box";
+import './Schedule.scss'
+import { ModalType } from "@/utils/types";
+import Header from "@/components/layout/Header";
+import { useTranslation } from "react-i18next";
 
 
 export default function Component(props: { type?: string, data?: any, delSuccess?: Function }) {
     const [checkData, setCheckData] = useState(null)
-
+    const { t } = useTranslation()
     const [key, setKey] = useState('');
     const [value, setValue] = useState('');
     const [isOpen, setIsOpen] = useState(false);
     const [isLatest, setIsLatest] = useState(props.type == 'latest');
-
-    const [timerId, setTimerId] = useState(null)
-    const [counter, setCounter] = useState(0)
-
+    const [showDetailModal, setShowDetailModal] = useState(false)
     const canvasId = props.type == 'latest' ? 'latest' : props.type == 'record' ? props.data.id : 'current'
 
     useEffect(() => {
@@ -372,21 +375,14 @@ export default function Component(props: { type?: string, data?: any, delSuccess
     }
 
     function del() {
-        Taro.showModal({
-            title: '删除记录',
-            content: '确定删除该记录吗?',
-            success: res => {
-                if (res.confirm) {
-                    delRecord(props.data.id
-                    ).then(res => {
-                        Taro.showToast({
-                            title: '删除成功'
-                        })
-                        props.delSuccess && props.delSuccess(props.data)
-                        // Taro.navigateBack()
-                    })
-                }
-            }
+        var id = props.type == 'record' ? props.data.id : (checkData as any).latest_record.id
+        delRecord(id
+        ).then(res => {
+            Taro.showToast({
+                title: '删除成功'
+            })
+            props.delSuccess && props.delSuccess(props.data)
+            // Taro.navigateBack()
         })
     }
 
@@ -556,68 +552,144 @@ export default function Component(props: { type?: string, data?: any, delSuccess
         return null
     }
 
-    return <View style={{ flexDirection: 'column', display: 'flex', alignItems: 'center', position: 'relative' }} onClick={all}>
-        {
-            (props.type == 'latest' || props.type == 'record') &&
-            <View style={{ position: 'relative', zIndex: 1 }}>
+    function rings() {
+        return <View style={{ position: 'relative', zIndex: 1 }}>
+            {
+                bigRing()
+            }
+            <View style={{ display: 'flex', position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, alignItems: 'center', justifyContent: 'center' }}>
                 {
-                    bigRing()
+                    smallRing()
                 }
-                <View style={{ display: 'flex', position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, alignItems: 'center', justifyContent: 'center' }}>
-                    {
-                        smallRing()
-                    }
-                </View>
             </View>
-        }
+        </View>
+    }
 
-        {
-            props.type == 'latest' ? <Text style={{ color: 'red' }}>Latest</Text> :
-                <Text>{value == 'WAIT_FOR_START' ? 'Schedule' : 'Log in Progress'}</Text>
-        }
-        {
-            scheduleItems(props.type == 'record' ? props.data : checkData)
-        }
+    function schedules() {
+        return scheduleItems(props.type == 'record' ? props.data : checkData)
+    }
 
-        {
-            (props.type != 'record' && value == 'WAIT_FOR_START') && <Text onClick={editSchedule}>调整日程</Text>
+    function detail() {
+        return <View style={{ flexDirection: 'column', display: 'flex', alignItems: 'center', position: 'relative' }} onClick={all}>
+            {
+                (props.type == 'latest' || props.type == 'record') && rings()
+            }
+            {
+                schedules()
+            }
+            {/* {
+                (props.type != 'record' && value == 'WAIT_FOR_START') && <Text onClick={editSchedule}>调整日程</Text>
+            } */}
+            {
+                ((props.type == 'record' && props.data.scenario == 'FAST_SLEEP') || (props.type == 'latest' && key == 'FAST_SLEEP')) && <Text onClick={showLatest}>Durations by stage</Text>
+            }
+            {
+                props.type != 'record' && props.type != 'latest' && key == 'FAST_SLEEP' && (value == 'WAIT_FOR_START' ? <Text onClick={showStage}>Duration goals by stage</Text> : <Text onClick={showStage}>Current stage</Text>)
+            }
+            {
+                key == 'FAST_SLEEP' && isOpen && props.type != 'record' && checkData && <Modal children={layoutContent()} dismiss={() => setIsOpen(false)} confirm={() => { }} />
+            }
+            {
+                key == 'FAST_SLEEP' && isOpen && props.type == 'record' && props.data.scenario == 'FAST_SLEEP' && <Modal children={layoutContent()} dismiss={() => setIsOpen(false)} confirm={() => { }} />
+            }
+
+            {
+                props.type == 'record' && <Text style={{ position: 'absolute', right: 20, top: 20 }} onClick={more}>More</Text>
+            }
+
+
+        </View >
+    }
+
+    function getDuration(obj) {
+        if (!obj) {
+            debugger
         }
-        {
-            ((props.type == 'record' && props.data.scenario == 'FAST_SLEEP') || (props.type == 'latest' && key == 'FAST_SLEEP')) && <Text onClick={showLatest}>Durations by stage</Text>
+        if (obj.status == 'NOT_STARTED' || obj.status == 'NOT_COMPLETED') {
+            return ''
         }
-        {
-            props.type != 'record' && props.type != 'latest' && key == 'FAST_SLEEP' && (value == 'WAIT_FOR_START' ? <Text onClick={showStage}>Duration goals by stage</Text> : <Text onClick={showStage}>Current stage</Text>)
+        var start = obj.real_start_time
+        var end = obj.real_end_time
+        if (!end) {
+            end = (new Date()).getTime()
         }
-        {
-            key == 'FAST_SLEEP' && isOpen && props.type != 'record' && checkData && <Modal children={layoutContent()} dismiss={() => setIsOpen(false)} confirm={() => { }} />
+        return TimeFormatter.calculateTimeDifference(start, end)
+    }
+
+    function showDetail(record) {
+        setShowDetailModal(true)
+    }
+
+    function recordDetail() {
+        var record = getRecord()
+        var fastDuration = ''
+        var sleepDuration = ''
+        if (record.scenario == 'FAST_SLEEP') {
+            fastDuration = getDuration(record.fast)
+            sleepDuration = getDuration(record.sleep)
         }
-        {
-            key == 'FAST_SLEEP' && isOpen && props.type == 'record' && props.data.scenario == 'FAST_SLEEP' && <Modal children={layoutContent()} dismiss={() => setIsOpen(false)} confirm={() => { }} />
+        else if (record.scenario == 'FAST') {
+            fastDuration = getDuration(record.fast)
         }
-
-        {/* {
-            key == 'FAST_SLEEP' && <AtFloatLayout
-                isOpened={isOpen}
-                onClose={() => {
-                    // stopTimer()
-                    setIsOpen(false)
-                }}
-                title="这是个标题">
+        else {
+            sleepDuration = getDuration(record.sleep)
+        }
+        return <View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
+            {
+                rings()
+            }
+            <View className="duration_bg">
+                {
+                    fastDuration.length > 0 && <Text className="duration_title">断食</Text>
+                }
+                {
+                    fastDuration.length > 0 && <Text className="duration_value" style={{ color: '#AAFF00' }}>{fastDuration}</Text>
+                }
                 {
-                    props.type != 'record'&&checkData && layoutContent()
+                    sleepDuration.length > 0 && <Text className="duration_title">睡眠</Text>
                 }
                 {
-                    props.type == 'record' && props.data.scenario=='FAST_SLEEP' && layoutContent()
+                    sleepDuration.length > 0 && <Text className="duration_value" style={{ color: '#00FFFF' }}>{sleepDuration}</Text>
                 }
+            </View>
+            <Image className="arrow1" src={require('@/assets/images/arrow.png')} />
+        </View>
+    }
 
+    function header() {
+        if (props.type == 'latest') {
+            return <Header title="最近记录" action={() => {
+                Taro.navigateTo({
+                    url: '/pages/common/RecordsHistory?type=time&title=time'
+                })
+            }} />
+        }
+        return null
+    }
 
-            </AtFloatLayout>
-        } */}
+    if (props.type == 'record' || props.type == 'latest') {
+        var record = getRecord()
+        if (!record) return <View />
+        return <Box header={header()}>
+            <RecordItem canDel={record.status == 'COMPLETED'} delete={del}
+                onClick={() => { showDetail(record) }}
+            >{recordDetail()}
+            </RecordItem>
+            {
+                showDetailModal && <Modal children={schedules()}
+                    modalType={ModalType.center}
+                    dismiss={() => setShowDetailModal(false)}
+                    confirm={() => { }} />
+            }
+        </Box>
+        // return <RecordItem canDel={record.status == 'COMPLETED'} delete={del}>{detail()}</RecordItem>
+    }
 
+    return <Box title={t('page.clock.schedule.title')}>
         {
-            props.type == 'record' && <Text style={{ position: 'absolute', right: 20, top: 20 }} onClick={more}>More</Text>
+            detail()
         }
-        <Text style={{ opacity: 0 }}>{counter}</Text>
+    </Box>
+
 
-    </View >
 }

+ 4 - 4
src/features/trackTimeDuration/hooks/Console.tsx

@@ -26,13 +26,13 @@ export const durationDatas = (common: any) => {
         max = common.duration.max
         step = common.duration.step
     }
-    var minutes: number[] = []
+    var minutes: string[] = []
     for (let i = 0; i < 60; i += step) {
-        minutes.push(i)
+        minutes.push(i+'分钟')
     }
-    var hours: number[] = []
+    var hours: string[] = []
     for (let i = min; i <= max; i++) {
-        hours.push(i)
+        hours.push(i+'小时')
     }
     return [hours, minutes]
 }

+ 2 - 8
src/pages/clock/Clock.tsx

@@ -291,20 +291,14 @@ export default function IndexPage() {
       {
         !permission.wxPubFollow && user.isLogin && <Text style={{ textAlign: 'center', width: '100%' }} onClick={() => followWxPub()}>去关注公众号</Text>
       }
-      {
-        user.isLogin && <Text onClick={() => {
-          Taro.navigateTo({
-            url: '/pages/common/RecordsHistory?type=time&title=time'
-          })
-        }}>查看全部记录</Text>
-      }
+ 
       {
         checkData && schedule()
       }
 
 
       {
-        checkData && (checkData as any).latest_record && <Schedule type='latest' />
+        checkData && (checkData as any).latest_record && <Schedule type='latest' delSuccess={getCheckData}/>
       }
       {/* <Picker mode="time" start="07:00" end="20:00">
         <Text style="color: #fff;">test picker</Text>

+ 1 - 1
src/pages/common/RecordsHistory.tsx

@@ -78,7 +78,7 @@ export default function Page() {
             getClockRecords({
                 page: page,
                 limit: pageSize,
-                only_finished: false
+                only_finished: true
             }).then(res => {
                 setTriggered(false)
                 if (page == 1) {

+ 5 - 1
src/pages/demo.tsx

@@ -1,7 +1,8 @@
 import Taro from '@tarojs/taro';
-import { Canvas, View } from '@tarojs/components';
+import { Canvas, View,Text } from '@tarojs/components';
 import { useEffect, useRef } from 'react';
 import Timeline from '@/components/view/Timeline';
+import RecordItem from '@/features/common/RecordItem';
 
 export default function Demo() {
   const canvasRef = useRef<any>(null);
@@ -269,6 +270,9 @@ export default function Demo() {
       onTouchStart={handleClick}
       ref={canvasRef} />
     <Timeline items={timelineItems} />
+    <RecordItem>
+      <Text>sldifjgsdgpsg</Text>
+    </RecordItem>
 
   </View>
 }

+ 26 - 0
src/services/trackSomething.tsx

@@ -62,6 +62,32 @@ export const clearMetricRecords = (params) => {
     })
 
 
+}
+
+export const deleteMetricRecord = (params) => {
+    return new Promise((resolve) => {
+        request({
+            url: API_METRIC_RECORDS + '/' + params.id, method: 'DELETE', data: { }
+        }).then(res => {
+            resolve(res);
+            // dispatch(loginSuccess(res));
+        })
+    })
+
+
+}
+
+export const deleteActivityRecord = (params) => {
+    return new Promise((resolve) => {
+        request({
+            url: API_ACTIVITY_RECORDS + '/' + params.id, method: 'DELETE', data: { }
+        }).then(res => {
+            resolve(res);
+            // dispatch(loginSuccess(res));
+        })
+    })
+
+
 }
 
 export const uploadMetric = (params) => {

+ 9 - 3
src/utils/types.ts

@@ -1,7 +1,8 @@
 export enum ButtonType {
-    primary = 'primary',
-    outline = 'outline',
-    more = 'more',
+    elevated = 'elevated', //实心bg+文字
+    outline = 'outline',    //描边跟按钮文字一致
+    text = 'text',          //纯文字
+    
 } 
 
 export enum TextType{
@@ -32,4 +33,9 @@ export enum NaviBarTitleShowType{
     alwayShow = 'alwayShow',
     alwayHide = 'alwayHide',
     scrollToShow = 'scrollToShow',
+}
+
+export enum ModalType{
+    center = 'center',
+    bottom = 'bottom',
 }