leon 1 anno fa
parent
commit
ffb313a4ca

+ 1 - 1
src/app.config.ts

@@ -6,7 +6,7 @@ const appConfig = defineAppConfig({
     'pages/clock/Clock',
     // 'pages/clock/Suggest',
     // 'pages/clock/SetGoal',
-    'pages/clock/AddEat',
+    'pages/clock/AddMoment',
     // 'pages/demo',
     // 'pages/food/Food',
     'pages/account/Login',

File diff suppressed because it is too large
+ 17 - 0
src/components/basic/Icons.tsx


+ 41 - 13
src/features/health/MainCard.scss

@@ -48,8 +48,8 @@
     color: #CACACA;
 }
 
-.fast_log_eat_btn{
-    color:#FE810C;
+.fast_log_eat_btn {
+    color: #FE810C;
     background-color: rgba(254, 129, 12, 0.2);
 }
 
@@ -69,8 +69,8 @@
     font-size: 40px;
 }
 
-.sticky{
-    position: sticky;
+.sticky {
+    // position: sticky;
     width: 750px;
     height: 50px;
     background-color: red;
@@ -80,17 +80,45 @@
 
 .scroll-view {
     height: 100vh; // 使 ScrollView 填满整个视口
-  }
-  
-  .content {
-  }
-  
-  .sticky-view {
-    position: -webkit-sticky; /* Safari */
-    position: sticky;
+}
+
+.content {}
+
+.sticky-view {
+    // position: -webkit-sticky;
+    /* Safari */
+    // position: sticky;
     top: 0;
     background-color: white;
     padding: 10px;
     box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
     z-index: 10; // 确保在其他内容之上
-  }
+}
+
+.switch_btn {
+    margin-top: 20px;
+    margin-bottom: 20px;
+    width: 72px;
+    height: 72px;
+    border-radius: 36px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.3);
+}
+
+.tabs{
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: center;
+    width: 750px;
+}
+
+.tab_item {
+    width: 72px;
+    height: 72px;
+    border-radius: 36px;
+    align-items: center;
+    justify-content: center;
+}

+ 32 - 0
src/features/health/MainConsole.scss

@@ -0,0 +1,32 @@
+.timeline_item{
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
+    padding-left: 40px;
+    padding-right: 40px;
+    padding-bottom: 28px;
+}
+
+.timeline_left{
+    display: flex;
+    flex-direction: column;
+
+}
+
+.timeline_title{
+    font-size: 28px;
+    line-height: 34px;
+    color: #808080;
+
+}
+
+.timeline_time{
+    font-size: 48px;
+    line-height: 56px;
+    color: #4D4D4D;
+}
+
+.timeline_operate{
+
+}

+ 34 - 24
src/features/health/MainConsole.tsx

@@ -3,14 +3,42 @@ import { View, Text } from "@tarojs/components";
 import dayjs from "dayjs";
 import { useEffect } from "react";
 import { useSelector } from "react-redux";
+import './MainConsole.scss'
+import { jumpPage } from "../trackTimeDuration/hooks/Common";
+
+let useNavigation;
+if (process.env.TARO_ENV == 'rn') {
+    useNavigation = require("@react-navigation/native").useNavigation
+}
 
 export default function MainConsole(props: { type: WindowType }) {
     const health = useSelector((state: any) => state.health);
 
+    let navigation, showActionSheetWithOptions;
+    if (useNavigation) {
+        navigation = useNavigation()
+    }
+
+
     useEffect(() => {
 
     }, [props.type])
 
+
+    function record(item) {
+        jumpPage('/pages/clock/AddMoment?moment=' + JSON.stringify(item))
+    }
+
+    function timelineItem(item: any, index: number) {
+        return <View key={index} className="timeline_item" onClick={() => record(item)}>
+            <View className="timeline_left">
+                <Text className="timeline_title">{item.title}</Text>
+                <Text className="timeline_time">{dayjs(item.target.timestamp).format('HH:mm')}</Text>
+            </View>
+            <View className="timeline_operate">记录</View>
+        </View>
+    }
+
     function detail() {
         const { day, night } = health.windows.night_day
         const { fast, eat } = health.windows.fast_eat
@@ -20,10 +48,7 @@ export default function MainConsole(props: { type: WindowType }) {
                 return <View>
                     {
                         day.timeline.map((item, index) => {
-                            return <View key={index}>
-                                <Text>{item.title}</Text>
-                                <Text>{dayjs(item.target.timestamp).format('HH:mm')}</Text>
-                            </View>
+                            return timelineItem(item, index)
                         })
                     }
                 </View>
@@ -31,10 +56,7 @@ export default function MainConsole(props: { type: WindowType }) {
                 return <View>
                     {
                         night.timeline.map((item, index) => {
-                            return <View key={index}>
-                                <Text>{item.title}</Text>
-                                <Text>{dayjs(item.target.timestamp).format('HH:mm')}</Text>
-                            </View>
+                            return timelineItem(item, index)
                         })
                     }
                 </View>
@@ -42,10 +64,7 @@ export default function MainConsole(props: { type: WindowType }) {
                 return <View>
                     {
                         fast.timeline.map((item, index) => {
-                            return <View key={index}>
-                                <Text>{item.title}</Text>
-                                <Text>{dayjs(item.target.timestamp).format('HH:mm')}</Text>
-                            </View>
+                            return timelineItem(item, index)
                         })
                     }
                 </View>
@@ -53,10 +72,7 @@ export default function MainConsole(props: { type: WindowType }) {
                 return <View>
                     {
                         eat.timeline.map((item, index) => {
-                            return <View key={index}>
-                                <Text>{item.title}</Text>
-                                <Text>{dayjs(item.target.timestamp).format('HH:mm')}</Text>
-                            </View>
+                            return timelineItem(item, index)
                         })
                     }
                 </View>
@@ -64,10 +80,7 @@ export default function MainConsole(props: { type: WindowType }) {
                 return <View>
                     {
                         sleep.timeline.map((item, index) => {
-                            return <View key={index}>
-                                <Text>{item.title}</Text>
-                                <Text>{dayjs(item.target.timestamp).format('HH:mm')}</Text>
-                            </View>
+                            return timelineItem(item, index)
                         })
                     }
                 </View>
@@ -75,10 +88,7 @@ export default function MainConsole(props: { type: WindowType }) {
                 return <View>
                     {
                         active.timeline && active.timeline.map((item, index) => {
-                            return <View key={index}>
-                                <Text>{item.title}</Text>
-                                <Text>{dayjs(item.target.timestamp).format('HH:mm')}</Text>
-                            </View>
+                            return timelineItem(item, index)
                         })
                     }
                 </View>

+ 45 - 3
src/features/health/MainDayNightCard.tsx

@@ -14,6 +14,7 @@ import Calendar from "@/features/health/calendar";
 import { WindowType } from "@/utils/types";
 import { durationArc, isCurrentTimeInRange, startArc } from "./util";
 import { setMode } from "@/store/health";
+import { IconSwitch1, IconSwitch2 } from "@/components/basic/Icons";
 
 export default function MainDayNightCard(props: { count: number, typeChanged: Function }) {
     const [isDay, setIsDay] = useState(true)
@@ -38,7 +39,7 @@ export default function MainDayNightCard(props: { count: number, typeChanged: Fu
         if (health.selTab == 0) {
             dispatch(setMode(isDayMode ? 'DAY' : 'NIGHT'))
         }
-    }, [health.selTab,isDayMode])
+    }, [health.selTab, isDayMode])
 
     useEffect(() => {
         dayjs.locale(global.language == 'en' ? 'en' : 'zh-cn');
@@ -158,6 +159,45 @@ export default function MainDayNightCard(props: { count: number, typeChanged: Fu
         return 'Coming up'
     }
 
+    function switchIcon() {
+        if (isDayMode) {
+            if (isDay) {
+                return <IconSwitch1 color="#000" width={15} />
+            }
+            return <IconSwitch2 color="#fff" width={15} />
+        }
+        if (isDay) {
+            return <IconSwitch2 color="#fff" width={15} />
+        }
+        return <IconSwitch1 color="#000" width={15} />
+    }
+
+    function switchBtn() {
+        var bgColor = ''
+        if (isDayMode) {
+            if (isDay) {
+                bgColor = '#fff'
+            }
+            else {
+                bgColor = '#000'
+            }
+
+        }
+        else {
+            if (isDay) {
+                bgColor = MainColorType.day
+            }
+            else {
+                bgColor = '#fff'
+            }
+        }
+        return <View className="switch_btn" style={{ backgroundColor: bgColor }} onClick={switchMode}>
+            {
+                switchIcon()
+            }
+        </View>
+    }
+
     return <View style={{ width: rpxToPx(750), display: 'flex', flexShrink: 0, flexDirection: 'column', alignItems: 'center', position: 'relative' }}>
         {/* <Calendar year={2024} month={8}/> */}
         <View style={{ position: 'relative' }}>
@@ -171,8 +211,10 @@ export default function MainDayNightCard(props: { count: number, typeChanged: Fu
                 <Text className="date1">{global.language == 'en' ? formatTime('dddd, MMM D') : formatTime('MMMD日 dddd')}</Text>
             </View>
         </View>
-        <Text onClick={switchMode}>Switch</Text>
+
+        {switchBtn()}
+        {/* <Text onClick={switchMode}>Switch</Text> */}
         <View className="sticky"></View>
-        <View style={{ height: 200 }} />
+        {/* <View style={{ height: 200 }} /> */}
     </View>
 }

+ 44 - 2
src/features/health/MainFastEatCard.tsx

@@ -21,6 +21,7 @@ import MainHistory from "./MainHistory";
 import { WindowType } from "@/utils/types";
 import { isCurrentTimeInRange } from "./util";
 import { setMode } from "@/store/health";
+import { IconSwitch1, IconSwitch2 } from "@/components/basic/Icons";
 let useNavigation;
 
 let Linking, PushNotification;
@@ -604,6 +605,45 @@ export default function MainFastEatCard(props: { count: any, typeChanged: Functi
         });
     }
 
+    function switchIcon() {
+        if (isFastMode) {
+            if (status!='upcoming') {
+                return <IconSwitch1 color="#000" width={15} />
+            }
+            return <IconSwitch2 color="#fff" width={15} />
+        }
+        if (status!='upcoming') {
+            return <IconSwitch2 color="#fff" width={15} />
+        }
+        return <IconSwitch1 color="#000" width={15} />
+    }
+
+    function switchBtn() {
+        var bgColor = ''
+        if (isFastMode) {
+            if (status!='upcoming') {
+                bgColor = '#fff'
+            }
+            else {
+                bgColor = MainColorType.eat
+            }
+
+        }
+        else {
+            if (status!='upcoming') {
+                bgColor = MainColorType.fast
+            }
+            else {
+                bgColor = '#fff'
+            }
+        }
+        return <View className="switch_btn" style={{ backgroundColor: bgColor }} onClick={switchMode}>
+            {
+                switchIcon()
+            }
+        </View>
+    }
+
     if (!fastData)
         return <View />
 
@@ -622,7 +662,7 @@ export default function MainFastEatCard(props: { count: any, typeChanged: Functi
                 <Text className="date1">{global.language == 'en' ? formatTime('dddd, MMM D') : formatTime('MMMD日 dddd')}</Text>
             </View>
         </View>
-        <View>{isFastMode ? formatMilliseconds(fastData.target.duration) : formatMilliseconds(eatData.target.end_time - eatData.target.start_time)}</View>
+        <View>{isFastMode ? formatMilliseconds(fastData.target.duration) : formatMilliseconds(eatData.target.end_timestamp - eatData.target.start_timestamp)}</View>
         {/* {
             isFastMode && <View>
                 <View className="log_row">
@@ -684,7 +724,9 @@ export default function MainFastEatCard(props: { count: any, typeChanged: Functi
 
 
 
-        <Text onClick={switchMode}>Switch</Text>
+        {
+            switchBtn()
+        }
         {
             !isFastMode && <Text onClick={more}>更多</Text>
         }

+ 18 - 5
src/features/health/MainHistory.tsx

@@ -9,6 +9,7 @@ import './History.scss'
 import Calendar from "./calendar";
 import { useSelector } from "react-redux";
 
+let lastMode = ''
 export default function MainHistory(props: { type: string }) {
     const [list, setList] = useState<any>([])
     const [page, setPage] = useState(1)
@@ -17,12 +18,17 @@ export default function MainHistory(props: { type: string }) {
 
     const health = useSelector((state: any) => state.health);
 
-    
+
 
 
 
     useEffect(() => {
-        loadData(1)
+        if (lastMode !=health.mode){
+            lastMode = health.mode
+            loadData(1)
+        }
+        // console.log(health.mode)
+        
     }, [health.mode])
 
     function refresh() {
@@ -39,7 +45,7 @@ export default function MainHistory(props: { type: string }) {
 
     function loadData(index: number) {
         records({
-            code: health.mode,
+            window: health.mode,
             limit: 10,
             page: index
         }).then(res => {
@@ -58,8 +64,15 @@ export default function MainHistory(props: { type: string }) {
     if (!loaded)
         return <View />
 
-    return <View style={{display:'flex',flexDirection:'column'}}>
+    return <>
         {/* <Calendar year={2024} month={8}/> */}
+        <View style={{
+            // position: 'sticky',
+            top: 0,
+            height: 50,
+            backgroundColor: 'blue',
+            zIndex: 100
+        }} />
         {
             list.map((item, index) => {
                 return <View key={index}>
@@ -81,5 +94,5 @@ export default function MainHistory(props: { type: string }) {
         {
             (total == list.length) && <Text className="no_more">没有更多了</Text>
         }
-    </View>
+    </>
 }

+ 51 - 7
src/features/health/MainSleepActiveCard.tsx

@@ -11,6 +11,7 @@ import { sleepWindow } from "@/services/trackTimeDuration";
 import { WindowType } from "@/utils/types";
 import { durationArc, isCurrentTimeInRange, startArc } from "./util";
 import { setMode } from "@/store/health";
+import { IconSwitch1, IconSwitch2 } from "@/components/basic/Icons";
 
 export default function MainSleepActiveCard(props: { count: any, typeChanged: Function }) {
     const [isSleepMode, setIsSleepMode] = useState(true)
@@ -40,7 +41,7 @@ export default function MainSleepActiveCard(props: { count: any, typeChanged: Fu
         if (health.selTab == 2) {
             dispatch(setMode(isSleepMode ? 'SLEEP' : 'ACTIVE'))
         }
-    }, [health.selTab,isSleepMode])
+    }, [health.selTab, isSleepMode])
 
     function formatTime(format: string, timestamp?: number) {
 
@@ -102,15 +103,15 @@ export default function MainSleepActiveCard(props: { count: any, typeChanged: Fu
     }
 
     function realRing() {
-        const color = isSleepMode?MainColorType.sleep:MainColorType.active
-        const { sleep,active } = health.windows.sleep_active
-        if (isSleepMode){
-            if (!isCurrentTimeInRange(sleep.schedule.start_time, sleep.schedule.end_time)){
+        const color = isSleepMode ? MainColorType.sleep : MainColorType.active
+        const { sleep, active } = health.windows.sleep_active
+        if (isSleepMode) {
+            if (!isCurrentTimeInRange(sleep.schedule.start_time, sleep.schedule.end_time)) {
                 return null
             }
         }
         else {
-            if (!isCurrentTimeInRange(active.schedule.start_time, active.schedule.end_time)){
+            if (!isCurrentTimeInRange(active.schedule.start_time, active.schedule.end_time)) {
                 return null
             }
         }
@@ -180,6 +181,47 @@ export default function MainSleepActiveCard(props: { count: any, typeChanged: Fu
         return <Rings common={common} bgRing={bgRing} targetRing={targetRing()} realRing={realRing()} currentDot={currentDot} canvasId={'smal11lee'} />
     }
 
+    function switchIcon() {
+        const { sleep } = health.windows.sleep_active
+        if (isSleepMode) {
+            if (isCurrentTimeInRange(sleep.schedule.start_time, sleep.schedule.end_time)) {
+                return <IconSwitch1 color="#000" width={15} />
+            }
+            return <IconSwitch2 color="#fff" width={15} />
+        }
+        if (isCurrentTimeInRange(sleep.schedule.start_time, sleep.schedule.end_time)) {
+            return <IconSwitch2 color="#fff" width={15} />
+        }
+        return <IconSwitch1 color="#000" width={15} />
+    }
+
+    function switchBtn() {
+        var bgColor = ''
+        const { sleep } = health.windows.sleep_active
+        if (isSleepMode) {
+            if (isCurrentTimeInRange(sleep.schedule.start_time, sleep.schedule.end_time)) {
+                bgColor = '#fff'
+            }
+            else {
+                bgColor = MainColorType.active
+            }
+
+        }
+        else {
+            if (isCurrentTimeInRange(sleep.schedule.start_time, sleep.schedule.end_time)) {
+                bgColor = MainColorType.sleep
+            }
+            else {
+                bgColor = '#fff'
+            }
+        }
+        return <View className="switch_btn" style={{ backgroundColor: bgColor }} onClick={switchMode}>
+            {
+                switchIcon()
+            }
+        </View>
+    }
+
     return <View style={{ width: rpxToPx(750), display: 'flex', flexShrink: 0, flexDirection: 'column', alignItems: 'center' }}>
         <View style={{ position: 'relative', }}>
             {
@@ -191,6 +233,8 @@ export default function MainSleepActiveCard(props: { count: any, typeChanged: Fu
             </View>
         </View>
 
-        <Text onClick={switchMode}>Switch</Text>
+        {
+            switchBtn()
+        }
     </View>
 }

+ 27 - 9
src/features/health/MainSwiper.tsx

@@ -5,13 +5,15 @@ import MainFastEatCard from "./MainFastEatCard";
 import MainSleepActiveCard from "./MainSleepActiveCard";
 import { useState } from "react";
 import { WindowType } from "@/utils/types";
-import { useDispatch } from "react-redux";
+import { useDispatch, useSelector } from "react-redux";
 import { setTab } from "@/store/health";
+import { MainColorType } from "@/context/themes/color";
+import { rpxToPx } from "@/utils/tools";
 
 export default function MainSwiper(props: { count: number, pageChanged: Function, typeChanged: Function }) {
     const [current, setCurrent] = useState(0)
-    const [type,setType] = useState(WindowType.day)
-
+    const [type, setType] = useState(WindowType.day)
+    const health = useSelector((state: any) => state.health);
     const dispatch = useDispatch()
 
     function tapScroll(index) {
@@ -20,13 +22,15 @@ export default function MainSwiper(props: { count: number, pageChanged: Function
 
     function pageChanged(e) {
         const page = e.detail.current
+
+        setCurrent(page)
         props.pageChanged(page)
 
         var strType = WindowType.day
-        if (page == 0){
+        if (page == 0) {
             strType = WindowType.day
         }
-        else if (page == 1){
+        else if (page == 1) {
             strType = WindowType.fast
         }
         else {
@@ -37,16 +41,30 @@ export default function MainSwiper(props: { count: number, pageChanged: Function
         dispatch(setTab(page))
     }
 
-    function typeChanged(e){
+    function typeChanged(e) {
         setType(e)
         props.typeChanged(e)
     }
 
+    function isDay() {
+        return health.mode == 'DAY'
+    }
+
+    function isFast() {
+        return health.mode == 'FAST'
+    }
+
+    function isSleep() {
+        return health.mode == 'SLEEP'
+    }
+
     return <View>
         <View className="tabs">
-            <View className="item" onClick={() => tapScroll(0)} > tab 0</View>
-            <View className="item" onClick={() => tapScroll(1)}>tab 1</View>
-            <View className="item" onClick={() => tapScroll(2)}>tab 2</View>
+            <View className="tab_item" style={{ backgroundColor: current != 0 ? '#B2B2B2' : isDay() ? MainColorType.day : MainColorType.night }} onClick={() => tapScroll(0)}></View>
+            <View style={{ width: rpxToPx(40) }} />
+            <View className="tab_item" style={{ backgroundColor: current != 1 ? '#B2B2B2' : isFast() ? MainColorType.fast : MainColorType.eat }} onClick={() => tapScroll(1)}></View>
+            <View style={{ width: rpxToPx(40) }} />
+            <View className="tab_item" style={{ backgroundColor: current != 2 ? '#B2B2B2' : isSleep() ? MainColorType.sleep : MainColorType.active }} onClick={() => tapScroll(2)}></View>
         </View>
         <Swiper style={{ height: 400 }} onChange={pageChanged} current={current}>
             <SwiperItem>

+ 183 - 0
src/features/health/Streak.scss

@@ -0,0 +1,183 @@
+/* #ifdef weapp */
+.modal1 {
+    position: fixed;
+    top: -2px;
+    left: 0;
+    z-index: 100000;
+    right: 0;
+    bottom: 0;
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+    background-color: rgba($color: #000000, $alpha: 0);
+    animation: modalBgAnim1 0.2s linear forwards;
+}
+
+.rn_modal1{
+    position: fixed;
+    top: -2px;
+    left: 0;
+    z-index: 100000;
+    right: 0;
+    bottom: 0;
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+    background-color: rgba($color: #000000, $alpha: 0);
+}
+
+@keyframes modalBgAnim1 {
+
+    100% {
+        background-color: rgba($color: #000000, $alpha: 0.15);
+    }
+}
+
+.modal_dismiss1 {
+    background-color: rgba($color: #000000, $alpha: 0.15);
+    animation: modalBgHideAnim1 0.2s linear forwards;
+}
+
+@keyframes modalBgHideAnim1 {
+    100% {
+        background-color: rgba($color: #000000, $alpha: 0);
+    }
+}
+
+
+.modal_center_container1 {
+    align-items: center;
+    justify-content: center;
+    // margin-bottom: 560px;
+}
+
+.center_modal_detail1 {
+    margin-bottom: 192px;
+}
+
+.modal_center_content1 {
+    // background-color: #1c1c1c;
+    // border-radius: 36rpx;
+    width: 658px;
+
+}
+
+
+.modal_bottom_content1 {
+    // padding-bottom: 120px;
+    width: 750px;
+    background-color: #ffffff;
+    border-bottom-left-radius: 36px;
+    border-bottom-right-radius: 36px;
+    display: flex;
+    flex-shrink: 0;
+    flex-direction: column;
+    z-index: 1000000;
+    margin-top: -1000px;
+    animation: modalAnim1 0.2s linear forwards;
+}
+
+.modal_bottom_dismiss1 {
+    margin-top: 0px;
+    animation: modalHideAnim1 0.2s linear forwards;
+}
+
+@keyframes modalAnim1 {
+    0% {
+        margin-top: -1000px;
+    }
+
+    100% {
+        margin-top: 0;
+    }
+}
+
+@keyframes modalHideAnim1 {
+    100% {
+        margin-top: -1000px;
+    }
+}
+
+/* #endif */
+
+/* #ifdef rn */
+
+.modal1 {
+    position: absolute;
+    top: -2px;
+    left: 0;
+    z-index: 100000;
+    right: 0;
+    height: 700;
+    // bottom: 0;
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+    background-color: rgba(0,0,0,0.95);
+    // background-color: rgba($color: #000000, $alpha: 0);
+    // animation: modalBgAnim 0.2s linear forwards;
+}
+
+.modal_bottom_content1 {
+    // padding-bottom: 120px;
+    width: 750px;
+    background-color: #fff;
+    border-bottom-left-radius: 36px;
+    border-bottom-right-radius: 36px;
+    display: flex;
+    flex-shrink: 0;
+    flex-direction: column;
+    z-index: 1000000;
+    margin-top: 0;
+    // height: 400;
+    // margin-bottom: -1000px;
+    // animation: modalAnim 0.2s linear forwards;
+}
+
+/* #endif */
+
+
+
+
+
+.modal_title1 {
+    font-size: 36px;
+    line-height: 120px;
+    height: 120px;
+    font-weight: 500;
+    width: 750px;
+    text-align: center;
+}
+
+.modal_operate1 {
+    display: flex;
+    flex-direction: row;
+    width: 750px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin-top: 36px;
+}
+
+.modal_btn1 {
+    width: 260px;
+    height: 84px;
+    border-radius: 42px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+.btn_space {
+
+    width: 90px;
+}
+
+.modal_cancel_text {
+    font-weight: 500;
+}
+
+
+.modal_confirm_text {
+    font-weight: 500;
+}

+ 147 - 0
src/features/health/Streak.tsx

@@ -0,0 +1,147 @@
+import { View, Text, ScrollView } from '@tarojs/components'
+import './Streak.scss'
+import React, { useEffect, useRef, useState } from 'react';
+import { ModalType } from '@/utils/types';
+import Taro from '@tarojs/taro';
+import { vibrate } from '@/utils/tools';
+
+
+let ModalRN, Animated
+
+if (process.env.TARO_ENV == 'rn') {
+    ModalRN = require("react-native").Modal
+    Animated = require("react-native").Animated
+}
+
+export default function Streak(props: {
+    children: React.ReactNode,
+    testInfo?: React.ReactNode,
+    title?: string,
+    dismiss: Function,
+    confirm?: Function,
+    themeColor?: string,
+    modalType?: ModalType,
+    cancelCatchMove?: boolean,
+    themeIsWhite?: boolean
+}) {
+
+    const [isDismiss, setIsDismiss] = useState(false)
+    let animation, animatedStyle;
+    if (process.env.TARO_ENV == 'rn') {
+        animation = useRef(new Animated.Value(0)).current;
+        animatedStyle = {
+            transform: [
+                {
+                    translateY: animation.interpolate({
+                        inputRange: [0, 1],
+                        outputRange: [-300, 0],
+                    }),
+                },
+            ],
+        };
+    }
+
+    useEffect(() => {
+        if (process.env.TARO_ENV == 'rn') {
+            startAnimation()
+        }
+    }, [])
+
+    const startAnimation = () => {
+        Animated.spring(animation, {
+            toValue: 1,
+            duration: 50,
+            useNativeDriver: true,
+        }).start();
+    };
+
+    const endAnimation = () => {
+        Animated.spring(animation, {
+            toValue: 0,
+            duration: 50,
+            useNativeDriver: true,
+        }).start();
+        console.log('end')
+    };
+
+    //阻止中间内容点击事件穿透
+    function click(e) {
+        if (process.env.TARO_ENV == 'weapp') {
+            e.stopPropagation()
+        }
+        vibrate()
+    }
+
+    function onClick() {
+    }
+
+    function longPress(e) {
+        if (process.env.TARO_ENV == 'weapp') {
+            e.stopPropagation()
+        }
+    }
+
+    function dismiss() {
+        if (props.modalType == ModalType.center) {
+            props.dismiss()
+            return
+        }
+        setIsDismiss(true)
+        setTimeout(() => {
+            props.dismiss()
+        }, 250)
+    }
+
+    function rndismiss() {
+        if (props.modalType == ModalType.center) {
+            props.dismiss()
+            return
+        }
+        endAnimation()
+        setTimeout(() => {
+            props.dismiss()
+        }, 250)
+    }
+
+    global.dismissModal = dismiss;
+
+    if (process.env.TARO_ENV == 'rn') {
+        return <View style={{position:'absolute',left:0,right:0,top:0,bottom:0}}
+        >
+            <View style={{ flex: 1, backgroundColor: '#ffffff90' }}>
+
+                <Animated.View className={isDismiss ? 'modal_bottom_content1 modal_bottom_dismiss1' : 'modal_bottom_content1'}
+                    style={[{ flexShrink: 0 }, animatedStyle]} onClick={onClick}>
+                    {
+                        props.children
+                    }
+
+                </Animated.View>
+                <View style={{ flex: 1, backgroundColor: 'transparent' }} onClick={(e) => {
+                    rndismiss()
+                }}></View>
+            </View>
+        </View>
+    }
+
+
+    return <View className={isDismiss ? 'modal1 modal_dismiss1' : 'modal1'} catchMove onLongPress={longPress}>
+
+        <View className={isDismiss ? 'modal_bottom_content1 modal_bottom_dismiss1' : 'modal_bottom_content1'} style={{ flexShrink: 0 }} onClick={onClick}>
+            {
+                props.children
+            }
+
+        </View>
+        <View style={{ flex: 1, width: 375, flexShrink: 0 }} onClick={(e) => {
+            if (process.env.TARO_ENV == 'weapp') {
+                e.stopPropagation()
+            }; dismiss()
+        }}>
+            {
+                props.testInfo ? props.testInfo : null
+            }
+        </View>
+
+    </View>
+}

+ 3 - 1
src/features/health/calendar.tsx

@@ -4,12 +4,14 @@ import dayjs from "dayjs";
 import { useEffect, useState } from "react";
 import { rpxToPx } from "@/utils/tools";
 import { streaks } from "@/services/health";
+import { useSelector } from "react-redux";
 
 export default function Calendar(props: { year: number, month: number }) {
     const weeks = ['日', '一', '二', '三', '四', '五', '六']
     const indexBeginWeek = 0;
     const [spaces, setSpaces] = useState<any>([])
     const [days, setDays] = useState<any>([])
+    const health = useSelector((state: any) => state.health);
 
     useEffect(() => {
         loadData()
@@ -51,7 +53,7 @@ export default function Calendar(props: { year: number, month: number }) {
 
 
         streaks({
-            category:'EAT',
+            window:health.mode,
             month:202408
         }).then(res=>{
             const array = (res as any).streaks

+ 0 - 0
src/pages/clock/AddEat.scss → src/pages/clock/AddMoment.scss


+ 39 - 33
src/pages/clock/AddEat.tsx → src/pages/clock/AddMoment.tsx

@@ -1,7 +1,7 @@
 import { View, Text, Textarea,Image } from "@tarojs/components";
 import Taro, { useRouter } from "@tarojs/taro";
 import { useTranslation } from "react-i18next";
-import './AddEat.scss'
+import './AddMoment.scss'
 import { useEffect, useState } from "react";
 import { saveFoodCache } from "@/features/food/hooks/ExtraData";
 import { baseUrl } from "@/services/http/api";
@@ -11,6 +11,7 @@ import Modal from "@/components/layout/Modal.weapp";
 import dayjs from "dayjs";
 import TimePicker from "@/features/common/TimePicker";
 import { MainColorType } from "@/context/themes/color";
+import { createMoment } from "@/services/health";
 
 
 let useRoute;
@@ -21,7 +22,7 @@ if (process.env.TARO_ENV == 'rn') {
     useNavigation = require("@react-navigation/native").useNavigation
 }
 
-export default function AddEat() {
+export default function AddMoment() {
     const [desc, setDesc] = useState('')
     const { t } = useTranslation()
     const [imgUrl, setImgUrl] = useState('')
@@ -45,12 +46,13 @@ export default function AddEat() {
         router = useRouter()
     }
 
-    const [meal,setMeal] = useState(JSON.parse(router.params.meal))
+    const [moment,setMoment] = useState(JSON.parse(router.params.moment))
 
     useEffect(() => {
-        var obj = JSON.parse(router.params.meal)
-        setStartTime(obj.target_start_time)
-        setEndTime(obj.target_end_time)
+        // var obj = JSON.parse(router.params.moment)
+        // var start = dayjs(obj.target.timestamp).format('HH:mm')
+        // setStartTime(start)
+        // setEndTime(obj.target_end_time)
      }, [])
 
     function getIntervalHoursAndMinutes(time1, time2) {
@@ -74,17 +76,17 @@ export default function AddEat() {
         return { hours, minutes };
     }
 
-    function duration() {
-        const { hours, minutes } = getIntervalHoursAndMinutes(meal.schedule_end_time, meal.schedule_start_time)
-        var time = ''
-        if (hours > 0) {
-            time = hours + '小时'
-        }
-        if (minutes > 0) {
-            time = minutes + '分钟'
-        }
-        return time
-    }
+    // function duration() {
+    //     const { hours, minutes } = getIntervalHoursAndMinutes(meal.schedule_end_time, meal.schedule_start_time)
+    //     var time = ''
+    //     if (hours > 0) {
+    //         time = hours + '小时'
+    //     }
+    //     if (minutes > 0) {
+    //         time = minutes + '分钟'
+    //     }
+    //     return time
+    // }
 
     function tapTime() {
         setShowPicker(true)
@@ -110,11 +112,15 @@ export default function AddEat() {
     }
 
     function save() {
-        eatMeals({
-            code: meal.code,
+        createMoment({
+            schedule_id: moment.schedule_id,
+            title:moment.title,
             description: desc,
-            real_start_time: meal.target_start_time,
-            real_end_time: meal.target_end_time,
+            start: {
+                date:dayjs(moment.target.timestamp).format('YYYYMMDD'),
+                timestamp:moment.target.timestamp
+            },
+            // real_end_time: meal.target_end_time,
             media: [{
                 url:imgUrl,
                 type: imgUrl.indexOf('mp4') != -1 ? 'video' : 'image',
@@ -125,7 +131,7 @@ export default function AddEat() {
                 Taro.navigateBack();
             }
 
-            global.refreshFastEat()
+            global.refreshWindow()
         })
     }
 
@@ -210,11 +216,11 @@ export default function AddEat() {
     }
 
     function pickerContent(){
-        const timestamp = meal.target_start_time
+        const timestamp = moment.target.timestamp
         const strTime = dayjs(timestamp).format('HH:mm')
         return <TimePicker time={strTime}
             color={MainColorType.eat}
-            title={meal.name}
+            title={moment.title}
             confirm={(e) => {
                 confirmPickerTime(e)
             }}
@@ -229,14 +235,14 @@ export default function AddEat() {
         date.setHours(list[0])
         date.setMinutes(list[1])
         
-        const duration = meal.target_end_time-meal.target_start_time
-        const endDate = date.getTime()+duration;
-        var data = JSON.parse(JSON.stringify(meal))
-        data.schedule_start_time = e
-        data.schedule_end_time = dayjs(endDate).format('HH:mm')
+        // const duration = meal.target_end_time-meal.target_start_time
+        // const endDate = date.getTime()+duration;
+        var data = JSON.parse(JSON.stringify(moment))
+        data.target.timestamp = e
+        // data.schedule_end_time = dayjs(endDate).format('HH:mm')
         data.target_start_time = date.getTime()
-        data.target_end_time = date.getTime()+duration
-        setMeal(data)
+        // data.target_end_time = date.getTime()+duration
+        setMoment(data)
         setShowPicker(false)
     }
 
@@ -247,8 +253,8 @@ export default function AddEat() {
 
     return <View>
         <View className="header">
-            <Text className="time1" onClick={tapTime}>{meal.schedule_start_time}</Text>
-            <Text className="time1" onClick={tapDuration}>{duration()}</Text>
+            <Text className="time1" onClick={tapTime}>{dayjs(moment.target.timestamp).format('HH:mm')}</Text>
+            {/* <Text className="time1" onClick={tapDuration}>{duration()}</Text> */}
         </View>
         <View>
             <Textarea placeholder="简单描述(选填)" className="textarea" onInput={e => {

+ 1 - 1
src/pages/clock/Clock.tsx

@@ -88,7 +88,7 @@ export default function Clock() {
     if (!loaded)
         return <View />
     
-    return <View>
+    return <View style={{flex:1}}>
         <ClockNew />
     </View>
 }

+ 36 - 4
src/pages/clock/ClockNew.tsx

@@ -12,7 +12,11 @@ import MainHistory from "@/features/health/MainHistory";
 import { WindowType } from "@/utils/types";
 import { windows } from "@/services/health";
 import { useDispatch, useSelector } from "react-redux";
-import health, { setWindows } from "@/store/health";
+import health, { setRefreshs, setWindows } from "@/store/health";
+import dayjs from "dayjs";
+import Modal from "@/components/layout/Modal.weapp";
+import Streak from "@/features/health/Streak";
+import Calendar from "@/features/health/calendar";
 
 export default function ClockNew() {
     const [count, setCount] = useState(0)
@@ -20,12 +24,20 @@ export default function ClockNew() {
     const user = useSelector((state: any) => state.user);
     const health = useSelector((state: any) => state.health);
     const [type, setType] = useState(WindowType.day)
+    const [showCalendar, setShowCalendar] = useState(false)
     const dispatch = useDispatch()
 
 
     useEffect(() => {
         setInterval(() => {
             setCount(index => index + 1)
+            health.refreshs.map((item) => {
+                const strTime = dayjs(item).format('YYYY-MM-DDTHH:mm:ss')
+                const now = dayjs().format('YYYY-MM-DDTHH:mm:ss')
+                if (strTime == now) {
+                    getWindows()
+                }
+            })
         }, 1000)
 
 
@@ -35,9 +47,14 @@ export default function ClockNew() {
         getWindows();
     }, [user.isLogin])
 
+    global.refreshWindow = () => {
+        getWindows();
+    }
+
     function getWindows() {
         windows().then(res => {
             dispatch(setWindows((res as any).windows))
+            dispatch(setRefreshs((res as any).refresh_timestamps))
         })
     }
 
@@ -58,14 +75,18 @@ export default function ClockNew() {
     }
 
     function detail() {
-        if (!health.windows){
+
+        if (!health.windows) {
             return <View />
         }
-        return <View>
+        return <View >
             <MainSwiper count={count} pageChanged={pageChanged} typeChanged={typeChanged} />
             <MainConsole type={type} />
+            <View onClick={() => {
+                setShowCalendar(true)
+            }}>Show Calendar</View>
             <MainHistory type={type} />
-            <View style={{ height: 200 }} />
+            <View style={{ height: 2200 }} />
         </View>
     }
     //https://blog.csdn.net/weixin_43525284/article/details/130182218
@@ -105,6 +126,17 @@ export default function ClockNew() {
 
 
         </ScrollView> */}
+        {
+            showCalendar && <Streak testInfo={null}
+                dismiss={() => {
+                    setShowCalendar(false)
+                }}
+                confirm={() => { }}>
+                <View>
+                    <Calendar year={2024} month={9} />
+                </View>
+            </Streak>
+        }
         <TabBar index={0} />
     </View>
 }

+ 2 - 2
src/pages/rn/RNMain.tsx

@@ -125,12 +125,12 @@ export default function RNMain() {
 
         screenOptions={({ route }) => ({
           headerStyle: {
-            backgroundColor: 'black',
+            backgroundColor: 'white',
             // borderBottomColor:'#ffffff33',
             // borderBottomWidth: 1, // 隐藏导航条底部边框
           },
           headerTintColor: 'white',
-          tabBarStyle: { backgroundColor: 'black', borderTopColor: '#ffffff22', borderTopWidth: 1 / PixelRatio.get() }, // tabbar的背景色
+          tabBarStyle: { backgroundColor: 'white', borderTopColor: '#ffffff22', borderTopWidth: 1 / PixelRatio.get() }, // tabbar的背景色
           tabBarActiveTintColor: 'white', // 活动标签的颜色
           tabBarInactiveTintColor: 'gray', // 非活动标签的颜色
         })}>

+ 12 - 1
src/services/health.tsx

@@ -1,4 +1,4 @@
-import { API_HEALTH_LABELS, API_HEALTH_RECORD, API_HEALTH_SCHEDULES, API_HEALTH_STREAKS, API_HEALTH_WINDOWS } from "./http/api";
+import { API_HEALTH_LABELS, API_HEALTH_MOMENT, API_HEALTH_RECORD, API_HEALTH_SCHEDULES, API_HEALTH_STREAKS, API_HEALTH_WINDOWS } from "./http/api";
 import { request } from "./http/request";
 
 export const getLabels = (params) => {
@@ -103,4 +103,15 @@ export const windows = ()=>{
             reject(e)
         })
     })
+}
+
+export const createMoment = (params) =>{
+    return new Promise((resolve) => {
+        request({
+            url: API_HEALTH_MOMENT, method: 'POST', data: { ...params }
+        }).then(res => {
+            resolve(res);
+            // dispatch(loginSuccess(res));
+        })
+    })
 }

+ 2 - 2
src/services/http/api.js

@@ -1,4 +1,4 @@
-const online = process.env.TARO_ENV == 'weapp' ? false : true;
+const online = process.env.TARO_ENV == 'weapp' ? false : false;
 
 import { WX_VERSION as _WX_VERSION, APP_VERSION as _APP_VERSION, ANDROID_VERSION as _ANDROID_VERSION } from "../../../config/env";
 
@@ -95,7 +95,7 @@ export const API_ORDER_CHECK = `${baseUrl}/api/payment/member/orders/`
 
 //health
 export const API_SET_SCHEDULE = `${baseUrl}/api/fast/schedules`
-export const API_EAT_MEALS = `${baseUrl}/api/eat/meals`
+export const API_HEALTH_MOMENT = `${baseUrl}/api/health/moments`
 export const API_HEALTH_SCHEDULES = `${baseUrl}/api/health/schedules`
 export const API_HEALTH_LABELS = `${baseUrl}/api/health/labels`
 export const API_HEALTH_RECORD = `${baseUrl}/api/health/records`

+ 1 - 10
src/services/trackSomething.tsx

@@ -173,13 +173,4 @@ export const metricFollows = (params) => {
     })
 }
 
-export const eatMeals = (params) =>{
-    return new Promise((resolve) => {
-        request({
-            url: API_EAT_MEALS, method: 'POST', data: { ...params }
-        }).then(res => {
-            resolve(res);
-            // dispatch(loginSuccess(res));
-        })
-    })
-}
+

+ 9 - 4
src/store/health.tsx

@@ -3,13 +3,15 @@ import { createSlice } from "@reduxjs/toolkit";
 interface HealthState {
     windows: any;
     mode: string;
-    selTab:number;
+    selTab: number;
+    refreshs: any; //刷新数据时间点
 }
 
 const initialState: HealthState = {
     windows: null,
     mode: 'DAY',
-    selTab:0
+    selTab: 0,
+    refreshs: []
 }
 
 const healthSlice = createSlice({
@@ -23,8 +25,11 @@ const healthSlice = createSlice({
         setMode(state, action) {
             state.mode = action.payload
         },
-        setTab(state,action){
+        setTab(state, action) {
             state.selTab = action.payload
+        },
+        setRefreshs(state, action) {
+            state.refreshs = action.payload
         }
 
     }
@@ -33,5 +38,5 @@ const healthSlice = createSlice({
 
 
 
-export const { setWindows, setMode,setTab } = healthSlice.actions;
+export const { setWindows, setMode, setTab, setRefreshs } = healthSlice.actions;
 export default healthSlice.reducer;

Some files were not shown because too many files changed in this diff