Leon 1 gadu atpakaļ
vecāks
revīzija
ac5c91f055
36 mainītis faili ar 845 papildinājumiem un 367 dzēšanām
  1. 120 0
      src/_health/base/new_date_picker.tsx
  2. 31 6
      src/_health/components/add_label.tsx
  3. 1 1
      src/_health/components/fast_sleep_console.tsx
  4. 0 10
      src/_health/components/no_data.scss
  5. 28 7
      src/_health/components/no_data.tsx
  6. 10 0
      src/_health/components/no_record.scss
  7. 12 0
      src/_health/components/no_record.tsx
  8. 9 8
      src/_health/components/schedule_item.tsx
  9. 49 0
      src/_health/components/sticky_date_list.tsx
  10. 1 0
      src/_health/pages/fast_sleep.config.ts
  11. 71 56
      src/_health/pages/fast_sleep.tsx
  12. 27 11
      src/_health/pages/guide_active.tsx
  13. 8 0
      src/_health/pages/guide_begin.config.ts
  14. 54 0
      src/_health/pages/guide_begin.tsx
  15. 27 13
      src/_health/pages/guide_eat.tsx
  16. 1 0
      src/_health/pages/guide_fast.tsx
  17. 1 0
      src/_health/pages/guide_sleep.tsx
  18. 29 15
      src/_health/pages/log_time.tsx
  19. 1 0
      src/_health/pages/long_fast.config.ts
  20. 126 117
      src/_health/pages/long_fast.tsx
  21. 1 0
      src/_health/pages/post_result.config.ts
  22. 31 27
      src/_health/pages/post_result.tsx
  23. 12 5
      src/_health/pages/schedules.tsx
  24. 1 0
      src/_health/pages/timeline_detail.config.ts
  25. 1 0
      src/app.config.ts
  26. BIN
      src/assets/_health/guide_en.png
  27. BIN
      src/assets/_health/guide_zh.png
  28. 1 1
      src/components/input/PickerViews.tsx
  29. 7 10
      src/context/locales/en.js
  30. 6 10
      src/context/locales/zh.js
  31. 11 0
      src/features/health/MainConsole.scss
  32. 34 4
      src/features/health/MainConsole.tsx
  33. 88 26
      src/features/health/MainHistory.tsx
  34. 1 1
      src/pages/account/Album.tsx
  35. 1 0
      src/pages/clock/Clock.tsx
  36. 44 39
      src/pages/clock/ClockNew.tsx

+ 120 - 0
src/_health/base/new_date_picker.tsx

@@ -0,0 +1,120 @@
+import { rpxToPx } from "@/utils/tools";
+import { PickerView, PickerViewColumn, Text, View } from "@tarojs/components";
+import { useEffect, useState } from "react";
+import './new_timepicker.scss'
+import dayjs from "dayjs";
+import { MainColorType } from "@/context/themes/color";
+import { TimeFormatter } from "@/utils/time_format";
+
+export enum NewDatePickerType {
+    normal = 'normal',
+    date = 'date'
+}
+export default function NewDatePicker(props: { value?: any, onChange?: any, color?: string, type?: NewDatePickerType,isToday?:boolean }) {
+    const [items, setItems] = useState<any>([[0]])
+    const [values, setValues] = useState<any>([0])
+    const [loaded, setLoaded] = useState(false)
+    useEffect(() => {
+        switch (props.type) {
+            case NewDatePickerType.normal:
+                setItems(itemDatas())
+                setValues(itemValues())
+                break;
+            case NewDatePickerType.date:
+                setItems(longDatas())
+                setValues(longValues())
+                break;
+        }
+
+        setLoaded(true)
+    }, [])
+
+    function itemDatas() {
+        return [['Today','Yesterday']]
+    }
+
+    function itemValues() {
+        return [props.isToday?0:1]
+    }
+
+    function longDatas() {
+        var min = 1
+        var max = 99
+
+        var days: string[] = []
+
+        for (let i = min; i <= max; i++) {
+            days.push(i + '天')
+        }
+
+        var hours: string[] = []
+        for (var i = 0; i < 24; i++) {
+            hours.push(i + TimeFormatter.getHoursUnit(i))
+        }
+        return [days, hours]
+    }
+
+    function longValues() {
+        if (props.value){
+            var day = Math.floor(props.value/24)
+            var hour = props.value%24
+            return [day-1,hour]
+            
+
+        }
+        return [0, 0]
+    }
+
+    function onPickerChange(e) {
+        setValues(e.detail.value)
+        if (props.onChange) {
+            var list = e.detail.value
+            switch (props.type) {
+                case NewDatePickerType.normal:
+                    props.onChange(list[0])
+                    break
+                case NewDatePickerType.date:
+                    props.onChange(list[0]*24+list[1]+24)
+                    break
+                    break
+            }
+
+        }
+    }
+
+    function getColor(i, j) {
+        if (i == 0 && j == values[0]) {
+            return true
+        }
+        if (i == 1 && j == values[1]) {
+            return true
+        }
+        return false
+    }
+    if (!loaded) return <View />
+
+    const bgStyle = `background-color: ${props.color}1A !important;`
+    return <PickerView
+        value={values}
+        style={{ color: '#000', height: rpxToPx(340), width: rpxToPx(618) }}
+        onChange={onPickerChange}
+        indicatorClass="pick_sel_item"
+        indicatorStyle={bgStyle}//""
+        immediateChange={true}
+        className="picker"
+
+    >
+        {
+            items.map((item, index) => {
+                return <PickerViewColumn key={index}>
+                    {item.map((obj, j) => {
+                        return (
+                            <Text key={j} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', color: getColor(index, j) ? props.color ?? MainColorType.fast : '#000' }}>{obj}</Text>
+                        );
+                    })}
+                </PickerViewColumn>
+            })
+        }
+
+    </PickerView >
+}

+ 31 - 6
src/_health/components/add_label.tsx

@@ -22,6 +22,8 @@ export default function AddLabel(props: {
     color?: string,
     disMiss?: any,
     window?: string,
+    onlyCheck?: boolean,
+    schedules?: any,
     justLabel?: boolean, confirm?: any
 }) {
     const [showTimePicker, setShowTimePicker] = useState(false)
@@ -50,15 +52,28 @@ export default function AddLabel(props: {
         else {
             event = health.mode == 'EAT' ? 'EAT_CUSTOM' : 'ACTIVE_CUSTOM'
         }
-        createSchedule({
-
-            schedules: [{
+        var array: any = []
+        if (props.onlyCheck) {
+            array = [...props.schedules, {
+                event: event,
+                title: value,
+                time: strTime,
+                is_all_day: isFullday,
+                time_label: isFullday ? strTime : null
+            }]
+        }
+        else {
+            array = [{
                 event: event,
                 title: value,
                 time: strTime,
                 is_all_day: isFullday,
                 time_label: isFullday ? strTime : null
             }]
+        }
+        createSchedule({
+            only_check: props.onlyCheck,
+            schedules: array
         }).then(res => {
             if ((res as any).result) {
                 if (global.refreshWindow) {
@@ -71,16 +86,26 @@ export default function AddLabel(props: {
                     global.refreshSchedules2()
                 }
                 if (props.confirm) {
-                    props.confirm((res as any).schedules[0])
+                    props.confirm(res)
                 }
             }
             else {
+                if (props.onlyCheck) {
+                    if (props.confirm) {
+                        props.confirm(res)
+                    }
+                    setShowTimePicker(false)
+                    if (props.disMiss) {
+                        props.disMiss()
+                    }
+                    return;
+                }
                 showAlert({
                     title: '弹窗标题',
                     content: '冲突描述',
                     showCancel: false,
                     confirm: () => {
-                        jumpPage(`./schedules_conflict?schedules=${JSON.stringify((res as any).schedules)}&errors=${JSON.stringify((res as any).error_messages)}`)
+                        // jumpPage(`./schedules_conflict?schedules=${JSON.stringify((res as any).schedules)}&errors=${JSON.stringify((res as any).error_messages)}`)
                     }
                 })
             }
@@ -126,7 +151,7 @@ export default function AddLabel(props: {
                         // item.reminder = e.detail.value
                         // setList([...list])
                     }} />
-                <View className="border_footer_line"/>
+                <View className="border_footer_line" />
             </View>
             {
                 isFullday ? <View>

+ 1 - 1
src/_health/components/fast_sleep_console.tsx

@@ -170,7 +170,7 @@ export default function FastSleepConsole(props: { step: number, data: any, del:
         var title = actionList()[index]
         switch (title) {
             case t('health.finish_setup'):
-                jumpPage('/_health/pages/guide_fast')
+                jumpPage('/_health/pages/guide_begin')
                 break;
             case t('health.delete_current_record'):
                 delConfirm()

+ 0 - 10
src/_health/components/no_data.scss

@@ -1,10 +0,0 @@
-.no_more_bg{
-    background-color: #fff;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    box-sizing: border-box;
-    padding-top: 80px;
-    padding-bottom: 80px;
-    flex-shrink: 0;
-}

+ 28 - 7
src/_health/components/no_data.tsx

@@ -1,12 +1,33 @@
-import { View,Image } from "@tarojs/components";
+import { View, Text } from "@tarojs/components";
 import './no_data.scss'
+import { useTranslation } from "react-i18next";
+import NewButton, { NewButtonType } from "../base/new_button";
 import { rpxToPx } from "@/utils/tools";
 import { MainColorType } from "@/context/themes/color";
-
-export default function NoData(){
-    return <View className="no_more_bg">
-        <Image style={{width:rpxToPx(160),height:rpxToPx(160)}} src={require('@assets/_health/null.png')}/>
-        <View style={{height:rpxToPx(40)}}/>
-        <View className="h26" style={{color:MainColorType.g02}}>暂无数据</View>
+import { IconError } from "@/components/basic/Icons";
+export default function NoData(props: { refresh: Function }) {
+    const { t } = useTranslation()
+    return <View className="no_data_bg" style={{marginTop:rpxToPx(256)}}>
+        <View style={{
+            backgroundColor:MainColorType.g04,
+            width:rpxToPx(108),
+            height:rpxToPx(108),
+            borderRadius:rpxToPx(54),
+            display:'flex',
+            alignItems:'center',
+            justifyContent:'center'
+        }}>
+            <IconError width={rpxToPx(88)} color="#fff"/>
+        </View>
+        <Text className="h50 g01 bold" style={{marginTop:rpxToPx(24)}}>{t('feature.common.no_data.title')}</Text>
+        <View className="h30 g01" style={{marginBottom:rpxToPx(92),marginTop:rpxToPx(12)}}>check your network connection and try again</View>
+        <NewButton
+            onClick={props.refresh}
+            type={NewButtonType.alpha}
+            color={MainColorType.blue}
+            width={rpxToPx(240)}
+            height={rpxToPx(96)}
+            title={t('feature.common.no_data.retry_btn')}
+        />
     </View>
 }

+ 10 - 0
src/_health/components/no_record.scss

@@ -0,0 +1,10 @@
+.no_more_bg{
+    background-color: #fff;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    box-sizing: border-box;
+    padding-top: 80px;
+    padding-bottom: 80px;
+    flex-shrink: 0;
+}

+ 12 - 0
src/_health/components/no_record.tsx

@@ -0,0 +1,12 @@
+import { View,Image } from "@tarojs/components";
+import './no_record.scss'
+import { rpxToPx } from "@/utils/tools";
+import { MainColorType } from "@/context/themes/color";
+
+export default function NoRecord(){
+    return <View className="no_more_bg">
+        <Image style={{width:rpxToPx(160),height:rpxToPx(160)}} src={require('@assets/_health/null.png')}/>
+        <View style={{height:rpxToPx(40)}}/>
+        <View className="h26" style={{color:MainColorType.g02}}>暂无数据</View>
+    </View>
+}

+ 9 - 8
src/_health/components/schedule_item.tsx

@@ -17,12 +17,13 @@ export default function ScheduleItem(props: {
     obj: any,
     highlight?: boolean,
     disable?: boolean,
-    gray?:boolean,
-    days?:string,
+    gray?: boolean,
+    days?: string,
     showLine: boolean,
     errors: any,
     selMode: any,
-    onDelete?:Function,
+    hideReminderIcon?: boolean,
+    onDelete?: Function,
     onChange?: Function
 }) {
     const [showTimePicker, setShowTimePicker] = useState(false)
@@ -84,7 +85,7 @@ export default function ScheduleItem(props: {
                         console.log('cancel')
                     },
                     confirm: () => {
-                        if (props.onDelete){
+                        if (props.onDelete) {
                             props.onDelete()
                         }
                         // delItem(index, i)
@@ -111,14 +112,14 @@ export default function ScheduleItem(props: {
                     </StatusIndicator>
                     <View style={{ flex: 1 }} />
                     {
-                        props.days && <View className="h30" style={{color:MainColorType.g02}}>+{props.days} day</View>
+                        props.days && <View className="h30" style={{ color: MainColorType.g02 }}>+{props.days} day</View>
                     }
                     {
-                        !props.obj.is_all_day && !props.obj.reminder && <IconNotificationOff color={MainColorType.g03} width={rpxToPx(28)} />
+                        !props.hideReminderIcon && !props.obj.is_all_day && !props.obj.reminder && <IconNotificationOff color={MainColorType.g03} width={rpxToPx(28)} />
                     }
                     <View style={{ width: rpxToPx(12) }} />
                     {
-                        !props.disable&&!props.obj.is_all_day && <View className='edit_item_time' onClick={() => {
+                        !props.disable && !props.obj.is_all_day && <View className='edit_item_time' onClick={() => {
                             // setSelIndex(i)
                             // setSelItem(obj)
                             setTime(props.obj.time)
@@ -128,7 +129,7 @@ export default function ScheduleItem(props: {
                         }} style={itemStyle(props.obj)}>{props.obj.time}</View>
                     }
                     {
-                        props.disable && <View className="edit_item_time" style={{backgroundColor:'transparent',color:props.gray?MainColorType.g02:'#000'}}>{props.obj.time}</View>
+                        props.disable && <View className="edit_item_time" style={{ backgroundColor: 'transparent', color: props.gray ? MainColorType.g02 : '#000' }}>{props.obj.time}</View>
                     }
 
 

+ 49 - 0
src/_health/components/sticky_date_list.tsx

@@ -0,0 +1,49 @@
+import { MainColorType } from "@/context/themes/color";
+import { rpxToPx } from "@/utils/tools";
+import { ScrollView, View } from "@tarojs/components";
+
+export default function StickyDateList(props: {
+    header?: any, children: any, footer?: any,
+    onRefresherRefresh: any,
+    isPulling: boolean,
+    onScroll: any,
+    showDate: boolean,
+    date: string
+}) {
+    return <View style={{ position: 'relative' }}>
+        <View className="h26" style={{
+            position: 'absolute',
+            left: 0,
+            top: 0,
+            right: 0,
+            height: rpxToPx(84),
+            backgroundColor: '#f5f5f5',
+            paddingLeft: rpxToPx(40),
+            display: 'flex',
+            boxSizing: 'border-box',
+            flexDirection: 'row',
+            alignItems: 'center',
+            zIndex:1,
+            opacity: props.showDate ? 1 : 0,
+            color: MainColorType.g01
+        }}>{props.date}</View>
+        <ScrollView style='height:100vh'
+            scrollY
+            refresherEnabled
+            refresherBackground={MainColorType.g05}
+            onRefresherRefresh={props.onRefresherRefresh}
+            refresherTriggered={props.isPulling}
+            onScroll={props.onScroll}
+        >
+            {
+                props.header
+            }
+            {
+                props.children
+            }
+            {
+                props.footer
+            }
+        </ScrollView>
+    </View>
+}

+ 1 - 0
src/_health/pages/fast_sleep.config.ts

@@ -3,6 +3,7 @@ export default definePageConfig({
         // 'ec-canvas': '../../lib/ec-canvas/ec-canvas',
         // 'demo':'../../components/demo'
     },
+    "disableScroll": true,
     "navigationBarTitleText": "",
     "navigationBarBackgroundColor": "#f5f5f5"
 })

+ 71 - 56
src/_health/pages/fast_sleep.tsx

@@ -1,7 +1,7 @@
 import { View, Text, Image, Swiper, SwiperItem } from "@tarojs/components";
 import './fast_sleep.scss'
 import { useSelector } from "react-redux";
-import { useEffect, useState } from "react";
+import { useEffect, useRef, useState } from "react";
 import NewButton, { NewButtonType } from "../base/new_button";
 import { rpxToPx } from "@/utils/tools";
 import { getThemeColor } from "@/features/health/hooks/health_hooks";
@@ -16,6 +16,7 @@ import { fastWithSleep } from "@/services/health";
 import FastSleepCard from "../components/fast_sleep_card";
 import FastSleepDetailCard from "../components/fast_sleep_detail_card";
 import MainHistory from "@/features/health/MainHistory";
+import StickyDateList from "../components/sticky_date_list";
 
 export default function FastSleep() {
     const health = useSelector((state: any) => state.health);
@@ -25,6 +26,10 @@ export default function FastSleep() {
     const [loaded, setLoaded] = useState(false)
     const [data, setData] = useState<any>(null)
     const [current, setCurrent] = useState(0)
+    const [isPulling, setIsPulling] = useState(false)
+    const [showDate, setShowDate] = useState(false)
+    const [date, setDate] = useState('')
+    const historyRef = useRef()
 
     useEffect(() => {
 
@@ -70,59 +75,69 @@ export default function FastSleep() {
 
     if (!loaded) return <View />
 
-    return <View className="page_container">
-        <NewHeader type={health.fast_with_sleep.status != 'OG2_MISALIGNED'?NewHeaderType.left_subtitle:NewHeaderType.left}
-            title="Fast with Sleep"
-            subtitle={health.fast_with_sleep.status != 'OG2_MISALIGNED'?'Tune Into Your Circadian Rhythm ':''}
-        />
-        {
-            health.fast_with_sleep.status != 'OG2_MISALIGNED' && <Swiper indicatorColor='#59595933'
-                indicatorActiveColor='#59595999'
-                style={{ height: rpxToPx(460), marginBottom: rpxToPx(24), flexShrink: 0 }}
-                onChange={e => setCurrent(e.detail.current)}
-                current={current}
-                indicatorDots>
-                <SwiperItem>
-                    <Card>
-                        <FastSleepCard step={0} data={data} />
-
-                    </Card>
-                </SwiperItem>
-                <SwiperItem>
-                    <Card>
-                        <FastSleepCard step={1} data={data} />
-                    </Card>
-                </SwiperItem>
-                <SwiperItem>
-                    <Card>
-                        <FastSleepCard step={2} data={data} />
-                    </Card>
-                </SwiperItem>
-                <SwiperItem>
-                    <Card>
-                        <FastSleepCard step={3} data={data} />
-                    </Card>
-                </SwiperItem>
-            </Swiper>
-        }
-        {
-            health.fast_with_sleep.status != 'OG2_MISALIGNED' && <FastSleepDetailCard data={data} />
-        }
-
-
-
-        <FastSleepConsole step={current} data={data} del={()=>{
-            getDatas()
-        }}/>
-        <MainHistory type='FAST,SLEEP' />
-        {/* <NewButton type={NewButtonType.link} title="hello world" onClick={() => {
-
-        }} />
-        <NewButton type={NewButtonType.label} title="hello world" onClick={() => {
-
-        }} />
-        <NewButton type={NewButtonType.label} title="hello world" labelBorder onClick={() => {
-
-        }} /> */}
-    </View>
+    return <StickyDateList
+        isPulling={isPulling}
+        showDate={showDate}
+        date={date}
+        onRefresherRefresh={() => {
+            (historyRef.current as any).refresh()
+            setIsPulling(true)
+        }}
+        onScroll={e => {
+            if (historyRef) {
+                (historyRef.current as any).onScroll(e)
+            }
+        }}>
+        <View className="page_container">
+            <NewHeader type={health.fast_with_sleep.status != 'OG2_MISALIGNED' ? NewHeaderType.left_subtitle : NewHeaderType.left}
+                title="Fast with Sleep"
+                subtitle={health.fast_with_sleep.status != 'OG2_MISALIGNED' ? 'Tune Into Your Circadian Rhythm ' : ''}
+            />
+            {
+                health.fast_with_sleep.status != 'OG2_MISALIGNED' && <Swiper indicatorColor='#59595933'
+                    indicatorActiveColor='#59595999'
+                    style={{ height: rpxToPx(460), marginBottom: rpxToPx(24), flexShrink: 0 }}
+                    onChange={e => setCurrent(e.detail.current)}
+                    current={current}
+                    indicatorDots>
+                    <SwiperItem>
+                        <Card>
+                            <FastSleepCard step={0} data={data} />
+
+                        </Card>
+                    </SwiperItem>
+                    <SwiperItem>
+                        <Card>
+                            <FastSleepCard step={1} data={data} />
+                        </Card>
+                    </SwiperItem>
+                    <SwiperItem>
+                        <Card>
+                            <FastSleepCard step={2} data={data} />
+                        </Card>
+                    </SwiperItem>
+                    <SwiperItem>
+                        <Card>
+                            <FastSleepCard step={3} data={data} />
+                        </Card>
+                    </SwiperItem>
+                </Swiper>
+            }
+            {
+                health.fast_with_sleep.status != 'OG2_MISALIGNED' && <FastSleepDetailCard data={data} />
+            }
+
+
+
+            <FastSleepConsole step={current} data={data} del={() => {
+                getDatas()
+            }} />
+            <MainHistory type='FAST,SLEEP' ref={historyRef} updateDate={(e) => {
+                setShowDate(e.show)
+                setDate(e.date)
+            }} refreshSuccess={() => {
+                setIsPulling(false)
+            }} />
+        </View>
+    </StickyDateList>
 }

+ 27 - 11
src/_health/pages/guide_active.tsx

@@ -22,6 +22,7 @@ import OnBoard from "../components/onboard";
 import showAlert from "@/components/basic/Alert";
 import CellFooter, { CellFooterType } from "../base/cell_footer";
 import CellFooterText from "../base/cell_footer_text";
+import StatusIndicator, { StatusType } from "../base/status_indicator";
 
 let useRoute;
 let useNavigation;
@@ -124,9 +125,10 @@ export default function GuideActive() {
     function items() {
         var items = list.filter(item => item.window == 'ACTIVE')
         if (items.length == 0) {
+            if (labels.length == 0) return <View />
             return <Card>
-                <OnBoard title="title"
-                    desc="desc"
+                <OnBoard title={labels[0].title}
+                    desc={labels[0].time_label}
                     color={MainColorType.active}
                     btnTitle={t('health.create_my_active')}
                     onClick={() => {
@@ -146,13 +148,14 @@ export default function GuideActive() {
                     return <ScheduleItem
                         key={i * 100}
                         obj={obj}
-                        highlight={highlight?obj.window=='ACTIVE':false}
+                        highlight={highlight ? obj.window == 'ACTIVE' : false}
                         showLine={i < items.length - 1}
                         errors={errors}
                         selMode={selMode}
                         disable={isDisable(obj)}
                         gray={isDisable(obj)}
                         days={obj.plus_days != 0 ? obj.plus_days : null}
+                        hideReminderIcon={true}
                         onDelete={() => {
                             const scenario = getScenario(health.windows, 'ACTIVE')
                             if (scenario.access.min >= items.length) {
@@ -166,6 +169,7 @@ export default function GuideActive() {
                                 return
                             }
                             delSchedule(obj.id).then(res => {
+                                dispatch(setFooter((res as any).footer))
                                 var array = JSON.parse(JSON.stringify(list))
                                 for (var j = 0; j < array.length; j++) {
                                     if (array[j].id == obj.id) {
@@ -193,8 +197,8 @@ export default function GuideActive() {
             }
             <View className='item_add'
                 onClick={() => add()}>
-                <IconAdd color={MainColorType.eat} width={rpxToPx(34)} />
-                <View className='toolbar_btn' style={{ color: MainColorType.active }} >{t('health.add_active')}</View>
+                <StatusIndicator type={StatusType.normal} text={t('health.add_active')}
+                    color={MainColorType.active} fontColor={MainColorType.active} fontSize={rpxToPx(34)}/>
                 <View style={{ flex: 1 }} />
             </View>
         </Card>
@@ -215,6 +219,7 @@ export default function GuideActive() {
                         disable={isDisable(obj)}
                         gray={isDisable(obj)}
                         days={obj.plus_days != 0 ? obj.plus_days : null}
+                        hideReminderIcon={true}
                         onDelete={() => {
                             const scenario = getScenario(health.windows, 'ACTIVE')
                             if (scenario.access.min >= items.length) {
@@ -260,8 +265,8 @@ export default function GuideActive() {
             items()
         }
         <CellFooter type={CellFooterType.left}>
-            <View style={{display:'flex',flexDirection:'column'}}>
-                <CellFooterText text={footerTitle()} isBold/>
+            <View style={{ display: 'flex', flexDirection: 'column' }}>
+                <CellFooterText text={footerTitle()} isBold />
                 <CellFooterText text={footerDesc()} />
             </View>
         </CellFooter>
@@ -295,10 +300,21 @@ export default function GuideActive() {
                 <AddLabel labels={labels}
                     window='ACTIVE'
                     disMiss={() => setShowModal(false)}
-                    confirm={(e) => {
-                        var array = JSON.parse(JSON.stringify(list))
-                        array.push(e)
-                        setList(array)
+                    onlyCheck={true}
+                    schedules={list}
+                    confirm={(res) => {
+                        if ((res as any).result) {
+                            dispatch(setSchedules((res as any).schedules))
+                            dispatch(setFooter((res as any).footer))
+                            setList((res as any).schedules)
+                            setErrors([])
+                        }
+                        else {
+                            setList((res as any).schedules)
+                            dispatch(setFooter((res as any).footer))
+                            setErrors((res as any).error_messages ? (res as any).error_messages : [])
+                        }
+
                     }}
                     color={MainColorType.active} />
             </Modal>

+ 8 - 0
src/_health/pages/guide_begin.config.ts

@@ -0,0 +1,8 @@
+export default definePageConfig({
+    usingComponents: {
+        // 'ec-canvas': '../../lib/ec-canvas/ec-canvas',
+        // 'demo':'../../components/demo'
+    },
+    "navigationBarTitleText": "",
+    "navigationBarBackgroundColor": "#f5f5f5"
+})

+ 54 - 0
src/_health/pages/guide_begin.tsx

@@ -0,0 +1,54 @@
+import { View, Image } from "@tarojs/components";
+import NewButton, { NewButtonType } from "../base/new_button";
+import { MainColorType } from "@/context/themes/color";
+import { rpxToPx } from "@/utils/tools";
+import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
+import { useTranslation } from "react-i18next";
+import { useSelector } from "react-redux";
+import Taro from "@tarojs/taro";
+
+export default function GuideBegin() {
+    const user = useSelector((state: any) => state.user);
+
+    const { t } = useTranslation()
+    return <View style={{
+        display: 'flex',
+        flexDirection: 'column',
+        alignItems: 'center'
+    }}>
+        <Image src={user.avatar} mode="aspectFill" style={{
+            background: user.isLogin ? 'transparent' : '#fff',
+            width: rpxToPx(200),
+            height: rpxToPx(200),
+            marginTop: rpxToPx(108),
+            marginBottom: rpxToPx(48),
+            borderRadius:rpxToPx(100)
+        }} />
+        <View className="h50 bold">{t('health.guide_begin_title')}</View>
+        <View className="h30 g01" style={{ marginTop: rpxToPx(12), marginBottom: rpxToPx(72) }}>{t('health.guide_begin_desc')}</View>
+        <View style={{ width: rpxToPx(400), height: 1, backgroundColor: '#000', opacity: 0.1, marginBottom: rpxToPx(48) }} />
+        <Image style={{ width: rpxToPx(340), height: rpxToPx(352), marginBottom: rpxToPx(158) }} src={global.language == 'en' ? require('@assets/_health/guide_en.png') : require('@assets/_health/guide_zh.png')} />
+        <NewButton
+            type={NewButtonType.fill}
+            color={MainColorType.fast}
+            title={t('health.guide_begin_btn')}
+            width={rpxToPx(646)}
+            height={rpxToPx(96)}
+            onClick={() => {
+                jumpPage('./guide_fast')
+            }}
+        />
+        <View style={{ height: rpxToPx(56) }} />
+        <NewButton
+            type={NewButtonType.img}
+
+            width={rpxToPx(646)}
+            height={rpxToPx(96)}
+            onClick={() => {
+                Taro.navigateBack()
+            }}
+        >
+            <View className="g02">{t('health.guide_begin_later')}</View>
+        </NewButton>
+    </View>
+}

+ 27 - 13
src/_health/pages/guide_eat.tsx

@@ -21,6 +21,7 @@ import { useTranslation } from "react-i18next";
 import showAlert from "@/components/basic/Alert";
 import CellFooter, { CellFooterType } from "../base/cell_footer";
 import CellFooterText from "../base/cell_footer_text";
+import StatusIndicator, { StatusType } from "../base/status_indicator";
 
 let useRoute;
 let useNavigation;
@@ -136,19 +137,20 @@ export default function GuideEat() {
                     return <ScheduleItem
                         key={i * 100}
                         obj={obj}
-                        highlight={highlight?obj.window=='EAT':false}
+                        highlight={highlight ? obj.window == 'EAT' : false}
                         showLine={i < items.length - 1}
                         errors={errors}
                         selMode={selMode}
                         disable={isDisable(obj)}
                         gray={isDisable(obj)}
-                        days={obj.plus_days!=0?obj.plus_days:null}
+                        days={obj.plus_days != 0 ? obj.plus_days : null}
+                        hideReminderIcon={true}
                         onDelete={() => {
                             const scenario = getScenario(health.windows, 'EAT')
-                            if (scenario.access.min>=items.length){
+                            if (scenario.access.min >= items.length) {
                                 showAlert({
                                     title: '删除',
-                                    content: '最少保留'+items.length+'个',
+                                    content: '最少保留' + items.length + '个',
                                     showCancel: true,
                                     confirm: () => {
                                     }
@@ -156,6 +158,7 @@ export default function GuideEat() {
                                 return
                             }
                             delSchedule(obj.id).then(res => {
+                                dispatch(setFooter((res as any).footer))
                                 var array = JSON.parse(JSON.stringify(list))
                                 for (var j = 0; j < array.length; j++) {
                                     if (array[j].id == obj.id) {
@@ -183,8 +186,8 @@ export default function GuideEat() {
             }
             <View className='item_add'
                 onClick={() => add()}>
-                <IconAdd color={MainColorType.eat} width={rpxToPx(34)} />
-                <View className='toolbar_btn' style={{ color: MainColorType.eat }} >{t('health.add_meal')}</View>
+                <StatusIndicator type={StatusType.normal} text={t('health.add_meal')}
+                    color={MainColorType.eat} fontColor={MainColorType.eat} fontSize={rpxToPx(34)}/>
                 <View style={{ flex: 1 }} />
             </View>
         </Card>
@@ -204,7 +207,8 @@ export default function GuideEat() {
                         selMode={selMode}
                         disable={isDisable(obj)}
                         gray={isDisable(obj)}
-                        days={obj.plus_days!=0?obj.plus_days:null}
+                        days={obj.plus_days != 0 ? obj.plus_days : null}
+                        hideReminderIcon={true}
                         onDelete={() => {
                             var array = JSON.parse(JSON.stringify(list))
                             for (var j = 0; j < array.length; j++) {
@@ -239,8 +243,8 @@ export default function GuideEat() {
             items()
         }
         <CellFooter type={CellFooterType.left}>
-            <View style={{display:'flex',flexDirection:'column'}}>
-                <CellFooterText text={footerTitle()} isBold/>
+            <View style={{ display: 'flex', flexDirection: 'column' }}>
+                <CellFooterText text={footerTitle()} isBold />
                 <CellFooterText text={footerDesc()} />
             </View>
         </CellFooter>
@@ -272,10 +276,20 @@ export default function GuideEat() {
                 <AddLabel labels={labels}
                     window='EAT'
                     disMiss={() => setShowModal(false)}
-                    confirm={(e) => {
-                        var array = JSON.parse(JSON.stringify(list))
-                        array.push(e)
-                        setList(array)
+                    onlyCheck={true}
+                    schedules={list}
+                    confirm={(res) => {
+                        if ((res as any).result) {
+                            dispatch(setSchedules((res as any).schedules))
+                            dispatch(setFooter((res as any).footer))
+                            setList((res as any).schedules)
+                            setErrors([])
+                        }
+                        else {
+                            setList((res as any).schedules)
+                            dispatch(setFooter((res as any).footer))
+                            setErrors((res as any).error_messages ? (res as any).error_messages : [])
+                        }
                     }}
                     color={MainColorType.eat} />
             </Modal>

+ 1 - 0
src/_health/pages/guide_fast.tsx

@@ -124,6 +124,7 @@ export default function GuideFast() {
                         errors={errors}
                         selMode={selMode}
                         days={obj.plus_days != 0 ? obj.plus_days : null}
+                        hideReminderIcon={true}
                         // days="+1 day"
                         onChange={(time) => {
                             var array = JSON.parse(JSON.stringify(health.schedules))

+ 1 - 0
src/_health/pages/guide_sleep.tsx

@@ -99,6 +99,7 @@ export default function GuideSleep() {
                         disable={isDisable(obj)}
                         gray={isDisable(obj)}
                         days={obj.plus_days != 0 ? obj.plus_days : null}
+                        hideReminderIcon={true}
                         onChange={(time) => {
                             var array = JSON.parse(JSON.stringify(list))
                             array.map(item => {

+ 29 - 15
src/_health/pages/log_time.tsx

@@ -16,6 +16,7 @@ import Taro from "@tarojs/taro";
 import { clockTimes, fastWithSleep } from "@/services/health";
 import NewDurationPicker, { DurationPickerType } from "../base/new_durationpicker";
 import showAlert from "@/components/basic/Alert";
+import NewDatePicker, { NewDatePickerType } from "../base/new_date_picker";
 
 let useRoute;
 let useNavigation;
@@ -51,6 +52,7 @@ export default function LogTime() {
     const tapIndex = router.params.index ?? 0
 
     const [expandIndex, setExpandIndex] = useState(router.params.initIndex ? router.params.initIndex : tapIndex)
+    const [chooseDate, setChooseDate] = useState(false)
     const [array, setArray] = useState<any>([])
     const [errors, setErrors] = useState<any>([])
     const [showSuccess, setShowSuccess] = useState(false)
@@ -579,17 +581,20 @@ export default function LogTime() {
                     borderStyle: 'solid'
                 }}>
                     <NewButton
-                        type={NewButtonType.gray}
+                        type={(expandIndex == index && chooseDate) ? NewButtonType.alpha :NewButtonType.gray}
+                        color={iFast ? MainColorType.fast : MainColorType.sleep}
                         title={date}
                         fontSize={rpxToPx(34)}
                         width={rpxToPx(196)}
                         height={rpxToPx(84)}
                         disable={array[index].disable}
                         onClick={() => {
-                            var list = JSON.parse(JSON.stringify(array))
-                            list[index].today = !list[index].today
-                            list[index].extra.confirm_time = new Date().getTime()
-                            setArray(list)
+                            setChooseDate(true)
+                            setExpandIndex(index)
+                            // var list = JSON.parse(JSON.stringify(array))
+                            // list[index].today = !list[index].today
+                            // list[index].extra.confirm_time = new Date().getTime()
+                            // setArray(list)
                         }}
                     />
                 </View>
@@ -601,7 +606,7 @@ export default function LogTime() {
                     borderStyle: 'solid'
                 }}>
                     <NewButton
-                        type={expandIndex == index ? NewButtonType.alpha : NewButtonType.gray}
+                        type={(expandIndex == index && !chooseDate) ? NewButtonType.alpha : NewButtonType.gray}
                         color={iFast ? MainColorType.fast : MainColorType.sleep}
                         title={time}
                         fontSize={rpxToPx(34)}
@@ -609,6 +614,7 @@ export default function LogTime() {
                         height={rpxToPx(84)}
                         disable={array[index].disable}
                         onClick={() => {
+                            setChooseDate(false)
                             setExpandIndex(index)
                         }}
                     />
@@ -619,7 +625,22 @@ export default function LogTime() {
                 <View className='border_footer_line' style={{ left: rpxToPx(66) }} />
             </View>
             {
-                expandIndex == index && <View style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: rpxToPx(698) }}>
+                expandIndex == index && chooseDate && <View style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: rpxToPx(698) }}>
+                    <NewDatePicker
+                        type={NewDatePickerType.normal}
+                        isToday={array[index].today}
+                        onChange={(e) => {
+                            // console.log(e)
+                            var list = JSON.parse(JSON.stringify(array))
+                            list[index].today = e==0
+                            list[index].extra.confirm_time = new Date().getTime()
+                            setArray(list)
+                        }}
+                        color={iFast ? MainColorType.fast : MainColorType.sleep} />
+                </View>
+            }
+            {
+                expandIndex == index && !chooseDate && <View style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: rpxToPx(698) }}>
                     <NewTimePicker time={array[index].time} onChange={(e) => {
                         var list = JSON.parse(JSON.stringify(array))
                         list[index].time = e
@@ -628,15 +649,8 @@ export default function LogTime() {
                     }} color={iFast ? MainColorType.fast : MainColorType.sleep} />
                 </View>
             }
-
-            {/* {
-                expandIndex == index && <View className='card_footer' onClick={() => tapChangeTime(schedule_time, time, index)}>
-                    
-                    <Text style={{ color: '#5C7099', marginLeft: rpxToPx(12), fontSize: rpxToPx(26) }}>{changeTimeText(schedule_time, time)}</Text>
-                </View>
-            } */}
             {
-                expandIndex == index && <View className='card_footer'>
+                expandIndex == index && !chooseDate && <View className='card_footer'>
                     <NewButton type={NewButtonType.link}
                         title={changeTimeText(schedule_time, time)}
                         onClick={() => tapChangeTime(schedule_time, time, index)}

+ 1 - 0
src/_health/pages/long_fast.config.ts

@@ -3,6 +3,7 @@ export default definePageConfig({
         // 'ec-canvas': '../../lib/ec-canvas/ec-canvas',
         // 'demo':'../../components/demo'
     },
+    "disableScroll": true,
     "navigationBarTitleText": "",
     "navigationBarBackgroundColor": "#f5f5f5"
 })

+ 126 - 117
src/_health/pages/long_fast.tsx

@@ -12,7 +12,7 @@ import MainHistory from "@/features/health/MainHistory";
 import { useSelector } from "react-redux";
 import showAlert from "@/components/basic/Alert";
 import { clockTimes, delRecord, updateFast } from "@/services/health";
-import { useEffect, useState } from "react";
+import { useEffect, useRef, useState } from "react";
 import { TimeFormatter } from "@/utils/time_format";
 import dayjs from "dayjs";
 import showActionSheet from "@/components/basic/ActionSheet";
@@ -21,6 +21,7 @@ import NewDurationPicker, { DurationPickerType } from "../base/new_durationpicke
 import Taro from "@tarojs/taro";
 import { useTranslation } from "react-i18next";
 import NewTimePicker from "../base/new_timepicker";
+import StickyDateList from "../components/sticky_date_list";
 
 let useActionSheet;
 if (process.env.TARO_ENV == 'rn') {
@@ -36,6 +37,11 @@ export default function LongFast() {
     const [duration, setDuration] = useState(0)
     const [time, setTime] = useState(dayjs().format('HH:mm'))
     const { t } = useTranslation()
+    const [isPulling, setIsPulling] = useState(false)
+    const [showDate, setShowDate] = useState(false)
+    const [date, setDate] = useState('')
+    const historyRef = useRef()
+
     let showActionSheetWithOptions;
     if (process.env.TARO_ENV == 'rn') {
         showActionSheetWithOptions = useActionSheet()
@@ -213,137 +219,140 @@ export default function LongFast() {
         return <View />
     }
 
-    return <View className="page_container">
-        <NewHeader type={NewHeaderType.left_subtitle}
-            title="Long Fast "
-            subtitle="Prolonged Fasting beyond 24 hours"
-        />
-        <Card>
-            <View className="long_fast_card" >
-                <View style={{ height: rpxToPx(96) }} />
-                <View className="h50 bold" style={{ color: MainColorType.fast }}>{timeText()}</View>
-                <View className="h24" style={{ color: MainColorType.g02, marginTop: rpxToPx(12) }}>Goal {goal()}</View>
-                <View style={{ height: rpxToPx(44) }} />
-                {
-                    long_fast.status == 'WFS' ? <NewButton
-                        type={NewButtonType.fill}
-                        width={rpxToPx(538)}
-                        height={rpxToPx(96)}
-                        color={getThemeColor('FAST')}
-                        title="Start fast"
-                        onClick={() => {
-                            tapStart()
-                            // 
-                        }}
-                    /> :
-                        <NewButton
-                            type={NewButtonType.alpha}
+    return <StickyDateList
+        isPulling={isPulling}
+        showDate={showDate}
+        date={date}
+        onRefresherRefresh={() => {
+            (historyRef.current as any).refresh()
+            setIsPulling(true)
+        }}
+        onScroll={e => {
+            if (historyRef) {
+                (historyRef.current as any).onScroll(e)
+            }
+        }}><View className="page_container">
+            <NewHeader type={NewHeaderType.left_subtitle}
+                title="Long Fast "
+                subtitle="Prolonged Fasting beyond 24 hours"
+            />
+            <Card>
+                <View className="long_fast_card" >
+                    <View style={{ height: rpxToPx(96) }} />
+                    <View className="h50 bold" style={{ color: MainColorType.fast }}>{timeText()}</View>
+                    <View className="h24" style={{ color: MainColorType.g02, marginTop: rpxToPx(12) }}>Goal {goal()}</View>
+                    <View style={{ height: rpxToPx(44) }} />
+                    {
+                        long_fast.status == 'WFS' ? <NewButton
+                            type={NewButtonType.fill}
                             width={rpxToPx(538)}
                             height={rpxToPx(96)}
                             color={getThemeColor('FAST')}
-                            title="How are you feeling?"
+                            title="Start fast"
                             onClick={() => {
-                                tapLog()
+                                tapStart()
+                                // 
                             }}
-                        />
-                }
-                {
-                    moment()
-                }
+                        /> :
+                            <NewButton
+                                type={NewButtonType.alpha}
+                                width={rpxToPx(538)}
+                                height={rpxToPx(96)}
+                                color={getThemeColor('FAST')}
+                                title="How are you feeling?"
+                                onClick={() => {
+                                    tapLog()
+                                }}
+                            />
+                    }
+                    {
+                        moment()
+                    }
 
-            </View>
-        </Card>
-        {/* {
-            long_fast.status == 'OG' && <View style={{ position: 'relative', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
-                <NewButton
-                    type={NewButtonType.link}
-                    height={rpxToPx(96)}
-                    title='End fast'
-                    onClick={() => {
-                        tapEnd()
-                    }}
-                />
-            </View>
-        }
-        {
-            long_fast.status == 'OG' && <Text onClick={tapMore}>More</Text>
-        } */}
+                </View>
+            </Card>
 
-        <View className="long_fast_footer" style={{ backgroundColor: 'transparent', marginBottom: -rpxToPx(35) }}>
-            <View style={{ width: rpxToPx(316), height: rpxToPx(128), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
+            <View className="long_fast_footer" style={{ backgroundColor: 'transparent', marginBottom: -rpxToPx(35) }}>
+                <View style={{ width: rpxToPx(316), height: rpxToPx(128), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
+                    {
+                        long_fast.status == 'OG' ? <NewButton
+                            type={NewButtonType.link}
+                            title={'End longfast'}
+                            onClick={tapEnd}
+                        >
+                        </NewButton> : <NewButton
+                            type={NewButtonType.link}
+                            title={'See Guidelines'}
+                            onClick={() => { }}
+                        >
+                        </NewButton>
+                    }
+                </View>
                 {
-                    long_fast.status == 'OG' ? <NewButton
-                        type={NewButtonType.link}
-                        title={'End longfast'}
-                        onClick={tapEnd}
-                    >
-                    </NewButton> : <NewButton
-                        type={NewButtonType.link}
-                        title={'See Guidelines'}
-                        onClick={() => { }}
-                    >
-                    </NewButton>
+                    long_fast.status == 'OG' && <NewButton
+                        btnStyle={{
+                            position: 'absolute',
+                            top: rpxToPx(42),
+                            right: rpxToPx(26)
+                        }}
+                        type={NewButtonType.more}
+                        onClick={tapMore}
+                    />
                 }
-            </View>
-            {
-                long_fast.status == 'OG' && <NewButton
-                    btnStyle={{
-                        position: 'absolute',
-                        top: rpxToPx(42),
-                        right: rpxToPx(26)
-                    }}
-                    type={NewButtonType.more}
-                    onClick={tapMore}
-                />
-            }
-
 
-        </View>
 
+            </View>
 
 
-        <MainHistory type='FAST' fast_type="LF" />
 
-        {
-            editDuration && <NewModal
-                title='长断食时长'
-                dismiss={() => {
-                    setEditDuration(false)
-                }}
-                confirm={() => {
+            <MainHistory type='FAST' fast_type="LF" ref={historyRef} updateDate={(e) => {
+                setShowDate(e.show)
+                setDate(e.date)
+            }} refreshSuccess={() => {
+                setIsPulling(false)
+            }} />
 
-                    updateFast({ fast_type: 'LF', long_fast_goal: duration * 60 }).then(res => {
+            {
+                editDuration && <NewModal
+                    title='长断食时长'
+                    dismiss={() => {
                         setEditDuration(false)
-                        global.refreshWindow()
-                    })
-                }}
-                themeColor={getThemeColor(health.mode)}>
-                <View style={{ flexDirection: 'column', display: 'flex', alignItems: 'center', marginBottom: 20 }}>
-                    <NewDurationPicker type={DurationPickerType.long}
-                        color={MainColorType.fast}
-                        value={duration}
-                        onChange={e => setDuration(e)} />
-                </View>
-            </NewModal>
-        }
-        {
-            showPicker && <NewModal
-                title='结束长断食'
-                dismiss={() => {
-                    setShowPicker(false)
-                }}
-                confirm={() => {
+                    }}
+                    confirm={() => {
 
-                    save()
-                }}
-                themeColor={getThemeColor(health.mode)}>
-                <View style={{ flexDirection: 'column', display: 'flex', alignItems: 'center', marginBottom: 20 }}>
-                    <NewTimePicker
-                        color={MainColorType.fast}
-                        time={dayjs().format('HH:mm')}
-                        onChange={e => setTime(e)} />
-                </View>
-            </NewModal>
-        }
-    </View>
+                        updateFast({ fast_type: 'LF', long_fast_goal: duration * 60 }).then(res => {
+                            setEditDuration(false)
+                            global.refreshWindow()
+                        })
+                    }}
+                    themeColor={getThemeColor(health.mode)}>
+                    <View style={{ flexDirection: 'column', display: 'flex', alignItems: 'center', marginBottom: 20 }}>
+                        <NewDurationPicker type={DurationPickerType.long}
+                            color={MainColorType.fast}
+                            value={duration}
+                            onChange={e => setDuration(e)} />
+                    </View>
+                </NewModal>
+            }
+            {
+                showPicker && <NewModal
+                    title='结束长断食'
+                    dismiss={() => {
+                        setShowPicker(false)
+                    }}
+                    confirm={() => {
+
+                        save()
+                    }}
+                    themeColor={getThemeColor(health.mode)}>
+                    <View style={{ flexDirection: 'column', display: 'flex', alignItems: 'center', marginBottom: 20 }}>
+                        <NewTimePicker
+                            color={MainColorType.fast}
+                            time={dayjs().format('HH:mm')}
+                            onChange={e => setTime(e)} />
+                    </View>
+                </NewModal>
+            }
+        </View>
+    </StickyDateList>
 }

+ 1 - 0
src/_health/pages/post_result.config.ts

@@ -9,4 +9,5 @@ export default definePageConfig({
     //     }
     // },
     "navigationStyle":"custom",
+    "disableScroll":true
 })

+ 31 - 27
src/_health/pages/post_result.tsx

@@ -8,7 +8,7 @@ import { IconCheck, IconNotification, IconNotificationOff } from "@/components/b
 import { MainColorType } from "@/context/themes/color";
 import { useState } from "react";
 import dayjs from "dayjs";
-import { useDispatch } from "react-redux";
+import { useDispatch, useSelector } from "react-redux";
 import { setMode } from "@/store/health";
 import NewModal from "../base/new_modal";
 import Card from "../components/card";
@@ -23,6 +23,8 @@ if (process.env.TARO_ENV == 'rn') {
     useNavigation = require("@react-navigation/native").useNavigation
 }
 export default function PostResult() {
+    const user = useSelector((state: any) => state.user);
+
     let router
     let navigation;
     if (useNavigation) {
@@ -39,7 +41,7 @@ export default function PostResult() {
     const [data, setData] = useState(JSON.parse(router.params.data))
     const [showSetting, setShowSetting] = useState(false)
     const dispatch = useDispatch()
-    const {t} = useTranslation() 
+    const { t } = useTranslation()
 
     function getMainColor() {
         if (data.scenario == 'MOVE' && data.extra.move_status == 'SEDENTARY') {
@@ -50,24 +52,6 @@ export default function PostResult() {
 
     function nextTitle() {
         return data.next.content
-        // const today = dayjs();
-
-        // var timestamp = data.next.timestamp
-        // const dt = dayjs(timestamp);
-        // const yesterday = today.subtract(1, 'day');
-        // const tomorrow = today.subtract(-1, 'day');
-        // var date = ''
-        // var time = dt.format('HH:mm')
-        // if (dt.isSame(today, 'day')) {
-        //     date = '今天';
-        // } else if (dt.isSame(yesterday, 'day')) {
-        //     date = '昨天';
-        // } else if (dt.isSame(tomorrow, 'day')) {
-        //     date = '明天';
-        // } else {
-        //     date = dt.format('MM-DD');
-        // }
-        // return date + ' ' + time + ' ' + data.next.title
     }
 
     function showSwitchBtn() {
@@ -116,6 +100,26 @@ export default function PostResult() {
     }
 
     function headerIcon() {
+        if (data.current_window) {
+            return <View style={{
+                width: rpxToPx(128), height: rpxToPx(128), 
+                borderRadius: rpxToPx(64),
+                borderWidth: rpxToPx(4),
+                boxSizing:'border-box',
+                borderColor: getThemeColor(data.current_window),
+                borderStyle: 'solid',
+                display: 'flex',
+                alignItems: 'center',
+                justifyContent: 'center'
+            }}>
+                <Image src={user.avatar} mode="aspectFill" style={{
+                    background: user.isLogin ? 'transparent' : '#fff',
+                    width: rpxToPx(108),
+                    height: rpxToPx(108),
+                    borderRadius:rpxToPx(54)
+                }} />
+            </View>
+        }
         if (data.images && data.images.length > 0) {
             return <View className="result_icon_bg">
                 <Image className="result_icon_bg" mode="aspectFill" src={data.images[0]} />
@@ -148,13 +152,13 @@ export default function PostResult() {
     function statusText() {
         switch (data.current_window) {
             case 'FAST':
-                return t('health.guide_current_scenario',{scenario:t('health.fast')})
+                return t('health.guide_current_scenario', { scenario: t('health.fast') })
             case 'EAT':
-                return t('health.guide_current_scenario',{scenario:t('health.eat')})
+                return t('health.guide_current_scenario', { scenario: t('health.eat') })
             case 'SLEEP':
-                return t('health.guide_current_scenario',{scenario:t('health.sleep')})
+                return t('health.guide_current_scenario', { scenario: t('health.sleep') })
             case 'ACTIVE':
-                return t('health.guide_current_scenario',{scenario:t('health.active')})
+                return t('health.guide_current_scenario', { scenario: t('health.active') })
         }
         return ''
     }
@@ -164,7 +168,7 @@ export default function PostResult() {
             headerIcon()
         }
 
-        <View className="h50 bold" style={{ color: getMainColor(), marginTop: rpxToPx(30) }}>{data.title}</View>
+        <View className="h50 bold" style={{ color: data.current_window ? '#000' : getMainColor(), marginTop: rpxToPx(30) }}>{data.title}</View>
         <View className="h30" style={{ marginTop: rpxToPx(12) }}>{headerDesc()}</View>
         {
             data.next && <View className="result_next">
@@ -209,7 +213,7 @@ export default function PostResult() {
                 onClick={() => {
                     if (data.current_window) {
                         Taro.navigateBack({
-                            delta: 6
+                            delta: 7
                         })
                     }
                     else {
@@ -239,7 +243,7 @@ export default function PostResult() {
             >
 
                 <Card>
-                    <View style={{display:'flex',flexDirection:'row',alignItems:'center',paddingRight:rpxToPx(40)}}>
+                    <View style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', paddingRight: rpxToPx(40) }}>
                         <View className="setting_item" style={{ flex: 1 }}>
                             <View style={{ flex: 1 }}>
                                 <View className="h24" style={{ color: MainColorType.g01 }}>{data.next.time}</View>

+ 12 - 5
src/_health/pages/schedules.tsx

@@ -46,6 +46,7 @@ export default function Schedules() {
     }
     const [list, setList] = useState<any>([])
     const [labels, setLabels] = useState<any>([])
+    const [labels2, setLabels2] = useState<any>([])
     const [showAutoSave, setShowAutoSave] = useState(false)
     const [errors, setErrors] = useState<any>(router.params.errors ? JSON.parse(router.params.errors) : [])
     const [showTimePicker, setShowTimePicker] = useState(false)
@@ -57,6 +58,7 @@ export default function Schedules() {
     const [tempArray, setTempArray] = useState<any>([])
     const [btnEnable, setBtnEnable] = useState(true)
     const [selMode, setSleMode] = useState(router.params.mode);
+    const [isEat, setIsEat] = useState(false)
     const { t } = useTranslation()
 
     useEffect(() => {
@@ -116,9 +118,12 @@ export default function Schedules() {
 
         })
 
-        getLabelsEvent({ window: health.mode }).then(res => {
+        getLabelsEvent({ window: 'EAT' }).then(res => {
             setLabels((res as any).labels)
         })
+        getLabelsEvent({ window: 'ACTIVE' }).then(res => {
+            setLabels2((res as any).labels)
+        })
     }
 
     function getTitle() {
@@ -230,12 +235,14 @@ export default function Schedules() {
     function add() {
         var isMax = false
         if (selMode == 'FAST' || selMode == 'EAT') {
+            setIsEat(true)
             const countFastWindows = list.filter(item => item.window === 'EAT').length;
             if (countFastWindows >= 4) {
                 isMax = true
             }
         }
         else {
+            setIsEat(false)
             const countFastWindows = list.filter(item => item.window === 'ACTIVE').length;
             if (countFastWindows >= 4) {
                 isMax = true
@@ -327,7 +334,7 @@ export default function Schedules() {
                     jumpPage(url)
                 }
                 else if (res == 2) {
-                    jumpPage('/_health/pages/guide_fast')
+                    jumpPage('/_health/pages/guide_begin')
                 }
 
             }
@@ -483,7 +490,7 @@ export default function Schedules() {
                     <StatusIndicator type={StatusType.img}
                         fontColor={getAddColor()}
                         fontSize={rpxToPx(34)}
-                        text='添加' color={getAddColor()}>
+                        text={(selMode == 'FAST' || selMode == 'EAT')?t('health.add_meal'):t('health.add_active')} color={getAddColor()}>
                         <IconAdd color="#fff" width={rpxToPx(26)} />
                     </StatusIndicator>
                     {/* <IconAdd color={getAddColor()} width={rpxToPx(34)} />
@@ -538,7 +545,7 @@ export default function Schedules() {
                         width={rpxToPx(646)}
                         height={rpxToPx(96)}
                         onClick={() => {
-                            jumpPage('/_health/pages/guide_fast')
+                            jumpPage('/_health/pages/guide_begin')
                         }}
                     />
                 </View>
@@ -565,7 +572,7 @@ export default function Schedules() {
                         setShowModal(false)
                     }}
                     confirm={() => { }}>
-                    <AddLabel labels={labels} disMiss={() => setShowModal(false)} />
+                    <AddLabel labels={isEat ? labels : labels2} color={isEat ? MainColorType.eat : MainColorType.active} disMiss={() => setShowModal(false)} />
                 </Modal>
             }
         </View>

+ 1 - 0
src/_health/pages/timeline_detail.config.ts

@@ -4,4 +4,5 @@ export default definePageConfig({
         // 'demo':'../../components/demo'
     },
     "navigationBarTitleText": "详情",
+    "disableScroll":true
 })

+ 1 - 0
src/app.config.ts

@@ -69,6 +69,7 @@ const appConfig = defineAppConfig({
         'pages/post_result',
         'pages/streak_calendar',
         'pages/streak_weekly',
+        'pages/guide_begin',
         'pages/guide_fast',
         'pages/guide_eat',
         'pages/guide_sleep',

BIN
src/assets/_health/guide_en.png


BIN
src/assets/_health/guide_zh.png


+ 1 - 1
src/components/input/PickerViews.tsx

@@ -52,7 +52,7 @@ const Component = forwardRef((props: {
         }
         props.onChange(v)
     }
-
+ 
     useImperativeHandle(ref, () => ({
         getConfirmData: confirm
     }));

+ 7 - 10
src/context/locales/en.js

@@ -850,30 +850,27 @@ export default {
         }
     },
     health: {
+        guide_begin_title:'Getting Started',
+        guide_begin_desc:'Set Up My Daily Schedule',
+        guide_begin_btn:'Start with Fasting Schedule',
+        guide_begin_later:'Set Up Later',
+
         guide_0_title: 'My Fasting Schedule',
         guide_0_desc: 'Overnight Intermittent Fasting',
-        guide_0_footer_title: 'Fast Goal: {{hour}} hours',
-        guide_0_footer_desc: 'Current Schedule: {{target}} Intermittent Fasting',
         guide_1_title: 'While Fasting',
         guide_1_desc: 'My Sleep Schedule',
-        guide_1_footer_title: 'Sleep Goal: {{hour}} hours',
-        guide_1_footer_desc: 'Consisting of about {{count}} full sleep cycles',
         guide_2_title: 'After Fasting',
         guide_2_desc: 'My Eating Schedule',
-        guide_2_footer_title: '{{count}} Meals a Day',
-        guide_2_footer_desc: 'Planned within an {{count}} window from {{duration}}',
         guide_3_title: 'Stay Active',
         guide_3_desc: 'My Activity Schedule',
-        guide_3_footer_title: 'Daily Activities or Habits',
-        guide_3_footer_desc: 'Planned within a {{count}} window from {{time}}',
         guide_end_title: 'Almost Done!',
         guide_end_desc: 'Review My Daily Schedule',
-        guide_end_footer_title: 'My daily schedule for Eating, Fasting, and Sleep',
-        guide_end_footer_title2: 'My daily schedule for Eating, Fasting, Sleep, and Active',
         guide_done_title: 'You\'re all set!',
         guide_done_desc: 'Your daily schedule has gone live',
         guide_current_scenario: 'Live Now: {{scenario}} Schedule',
 
+        console_guide_tip:'Remember to finish setting up my schedule here 👆',
+
         add_meal: 'Add Meal',
         add_active: 'Add Activity',
         mark_done:'Mark Done',

+ 6 - 10
src/context/locales/zh.js

@@ -851,30 +851,26 @@ export default {
         }
     },
     health: {
+        guide_begin_title: '准备开始',
+        guide_begin_desc: '设置我的每日日程',
+        guide_begin_btn: '从断食日程开始',
+        guide_begin_later: '稍后设置',
         guide_0_title: '我的断食日程',
         guide_0_desc: '每日间歇性断食',
-        guide_0_footer_title: '断食目标:{{hour}} 小时',
-        guide_0_footer_desc: '当前日程:{{target}} 间歇性断食',
         guide_1_title: '断食期间',
         guide_1_desc: '我的睡眠日程',
-        guide_1_footer_title: '睡眠目标: {{hour}} 小时',
-        guide_1_footer_desc: '包含{{count}}个完整睡眠周期',
         guide_2_title: '断食结束后',
         guide_2_desc: '我的饮食日程',
-        guide_2_footer_title: '一日 {{count}} 餐',
-        guide_2_footer_desc: '计划在 {{duration}} 间的{{count}}小时内进餐',
         guide_3_title: '保持活跃',
         guide_3_desc: '我的活动日程',
-        guide_3_footer_title: '日常活动或习惯',
-        guide_3_footer_desc: '计划在 {{time}} 间的{{count}}内进行',
         guide_end_title: '即将完成!',
         guide_end_desc: '查看我的日程',
-        guide_end_footer_title: '我的饮食、断食和睡眠日程时间表',
-        guide_end_footer_title2: '我的饮食、断食、睡眠和活动日程时间表',
         guide_done_title: '一切就绪!',
         guide_done_desc: '你的日程已启动',
         guide_current_scenario: '当前正处于{{scenario}}日程内',
 
+        console_guide_tip:'完成我的日程设置,开启规律的健康生活 👆',
+
         add_meal: '添加餐次',
         add_active: '添加活动',
         mark_done: '标记完成',

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

@@ -229,6 +229,17 @@
   flex: 1;
 }
 
+.guide_tip{
+  height: 80px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background-color: #0080FF1A;
+  color: #0080FF;
+  width: 750px;
+  position: relative;
+}
+
 /*
 rn呼吸灯效果
 import React, { useEffect, useRef } from 'react';

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

@@ -14,7 +14,7 @@ import showActionSheet from "@/components/basic/ActionSheet";
 import { rpxToPx } from "@/utils/tools";
 import { setMode, setShowActionTip } from "@/store/health";
 import { getCountownTime, getDuration, getScenario, getThemeColor, getWindowStatus } from "./hooks/health_hooks";
-import { IconArrow, IconMore, IconNotification, IconNotificationOff, IconSwitch } from "@/components/basic/Icons";
+import { IconArrow, IconClose, IconMore, IconNotification, IconNotificationOff, IconSwitch } from "@/components/basic/Icons";
 import DurationPicker from "@/_health/components/duration_picker";
 import Taro from "@tarojs/taro";
 import { systemLocation } from "@/services/common";
@@ -42,6 +42,7 @@ export default function MainConsole(props: { type: WindowType }) {
     const [durationPicker, setDurationPicker] = useState(false)
     const [btnDisable, setBtnDisable] = useState(false)
     const [selItem, setSelItem] = useState<any>(null)
+    const [hideGuideTip, setHideGuideTip] = useState(false)
     const { t } = useTranslation()
     const dispatch = useDispatch()
 
@@ -437,7 +438,11 @@ export default function MainConsole(props: { type: WindowType }) {
                         list.push(t('health.finish_setup'))
                     }
                     list.push(t('health.add_active'))
-                    list.push(t('health.mark_done'))
+                    var scenario = getScenario(health.windows,'ACTIVE')
+                    if (scenario.status !='WFS'){
+                        list.push(t('health.mark_done'))
+                    }
+                    
 
                     if (health.finish_setup) {
                         list.push(t('health.edit_schedule'))
@@ -450,7 +455,10 @@ export default function MainConsole(props: { type: WindowType }) {
                         list.push(t('health.finish_setup'))
                     }
                     list.push(t('health.add_meal'))
-                    list.push(t('health.mark_done'))
+                    var scenario = getScenario(health.windows,'EAT')
+                    if (scenario.status !='WFS'){
+                        list.push(t('health.mark_done'))
+                    }
                     if (health.finish_setup) {
                         list.push(t('health.edit_schedule'))
                     }
@@ -573,7 +581,7 @@ export default function MainConsole(props: { type: WindowType }) {
     }
 
     function tapGuide() {
-        jumpPage('/_health/pages/guide_fast')
+        jumpPage('/_health/pages/guide_begin')
         // showAlert({
         //     title:'设置引导弹窗',
         //     content:'设置引导描述',
@@ -864,6 +872,7 @@ export default function MainConsole(props: { type: WindowType }) {
                     jumpPage('/_health/pages/active_plan?schedule=' + JSON.stringify(list.length > 0 ? list[0] : '{}'))
                 }}>测试</View>
             } */}
+
         </View>
         <View className="main_footer2">
             <View style={{ width: rpxToPx(316), height: rpxToPx(128), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
@@ -874,6 +883,7 @@ export default function MainConsole(props: { type: WindowType }) {
                 >
                 </NewButton>
             </View>
+
             {
                 showMoreBtn() && <NewButton
                     btnStyle={{
@@ -888,6 +898,25 @@ export default function MainConsole(props: { type: WindowType }) {
 
 
         </View>
+        {
+            !hideGuideTip && !health.finish_setup && <View className="guide_tip h26" onClick={()=>{
+                tapGuide();
+            }}>{t('health.console_guide_tip')}
+                <NewButton type={NewButtonType.img} btnStyle={{
+                    position: 'absolute',
+                    right: 0,
+                    top: 0,
+                    bottom: 0,
+                    width: rpxToPx(92)
+                }} onClick={() => {
+                    setHideGuideTip(true)
+                }}>
+                    <IconClose color={MainColorType.g01} width={rpxToPx(32)} height={rpxToPx(32)} />
+                </NewButton>
+
+            </View>
+        }
+
         {
             health.mode == 'ACTIVE' && <View>
                 <View className="main_column_space" />
@@ -958,6 +987,7 @@ export default function MainConsole(props: { type: WindowType }) {
                     </View>
                 </Cell>
 
+
             </View>
         }
         {

+ 88 - 26
src/features/health/MainHistory.tsx

@@ -1,5 +1,5 @@
 import { View, Text, Image } from "@tarojs/components";
-import { useEffect, useRef, useState } from "react";
+import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
 import { records } from "@/services/health";
 import './History.scss'
 import Calendar from "./calendar";
@@ -7,16 +7,17 @@ import { useSelector } from "react-redux";
 import HistoryItem from "./HistoryItem";
 import { rpxToPx } from "@/utils/tools";
 import { jumpPage } from "../trackTimeDuration/hooks/Common";
-import Taro from "@tarojs/taro";
+import Taro, { useReady } from "@tarojs/taro";
 import { getThemeColor } from "./hooks/health_hooks";
 import { TimeFormatter } from "@/utils/time_format";
 import dayjs from "dayjs";
 import { MainColorType } from "@/context/themes/color";
 import { IconArrow, IconCellArrow } from "@/components/basic/Icons";
-import NoData from "@/_health/components/no_data";
+import NoRecord from "@/_health/components/no_record";
 
 let lastMode = ''
-export default function MainHistory(props: { type?: string, fast_type?: string }) {
+export default forwardRef((props: { type?: string, fast_type?: string, updateDate?: any, refreshSuccess?: any }, ref) => {
+    const [itemLayouts, setItemLayouts] = useState<any>([])
     const [list, setList] = useState<any>([])
     const [page, setPage] = useState(1)
     const [total, setTotal] = useState(0)
@@ -26,12 +27,25 @@ export default function MainHistory(props: { type?: string, fast_type?: string }
     const user = useSelector((state: any) => state.user);
     const healthRef = useRef(health)
 
+    useImperativeHandle(ref, () => ({
+        onScroll: onScroll,
+        refresh: refresh
+    }))
 
-    useEffect(()=>{
-        if (!user.isLogin){
+    useEffect(() => {
+        if (list.length > 0) {
+            setTimeout(() => {
+                measureItemLayouts()
+            }, 300)
+        }
+    }, [list])
+
+
+    useEffect(() => {
+        if (!user.isLogin) {
             setList([])
         }
-    },[user.isLogin])
+    }, [user.isLogin])
 
     global.refreshHistory = () => {
         refresh()
@@ -52,6 +66,51 @@ export default function MainHistory(props: { type?: string, fast_type?: string }
 
     }, [health.mode])
 
+    function measureItemLayouts() {
+        const query = Taro.createSelectorQuery()
+        list.forEach((item, index) => {
+            query.select(`#history-${index}`).boundingClientRect()
+        });
+        query.exec((res) => {
+            var layouts: any = []
+            res.forEach((rect, index) => {
+                if (rect) {
+                    layouts[index] = rect.top
+                }
+            });
+            setItemLayouts(layouts)
+        })
+    }
+
+    function onScroll(e) {
+        var top = e.detail.scrollTop
+        if (itemLayouts.length > 0) {
+            var i = -1
+            var date = ''
+            list.forEach((item, index) => {
+                if (top >= itemLayouts[index] - 50) {
+                    i = index
+                    date = dayjs(item.window_range.start_timestamp).format('YYYY年M月')
+                }
+            })
+            if (props.updateDate) {
+                props.updateDate({
+                    show: i != -1,
+                    date: date
+                })
+            }
+        }
+        else {
+            if (props.updateDate) {
+                props.updateDate({
+                    show: false,
+                    date: ''
+                })
+            }
+
+        }
+    }
+
     function refresh() {
         loadData(1)
         setPage(1)
@@ -78,26 +137,29 @@ export default function MainHistory(props: { type?: string, fast_type?: string }
             if (index == 1) {
                 setList((res as any).data)
                 setTotal((res as any).total)
+                if (props.refreshSuccess) {
+                    props.refreshSuccess()
+                }
             }
             else {
                 setList([...list, ...(res as any).data])
             }
 
-            if ((res as any).data.length > 0) {
-                setTimeout(() => {
-                    // var array:any = [];
-                    // (res as any).data.map((item,index)=>{
-                    //     array.push('#history_id_'+index)
-                    // })
-                    // var ids = array.join(',')
-                    // console.log(array)
-                    // console.log(ids)
-                    const query = Taro.createSelectorQuery();
-                    query.selectAll('#history_id_0').boundingClientRect((rect) => {
-                        console.log(rect)
-                    }).exec();
-                }, 1000)
-            }
+            // if ((res as any).data.length > 0) {
+            //     setTimeout(() => {
+            //         // var array:any = [];
+            //         // (res as any).data.map((item,index)=>{
+            //         //     array.push('#history_id_'+index)
+            //         // })
+            //         // var ids = array.join(',')
+            //         // console.log(array)
+            //         // console.log(ids)
+            //         const query = Taro.createSelectorQuery();
+            //         query.selectAll('#history_id_0').boundingClientRect((rect) => {
+            //             console.log(rect)
+            //         }).exec();
+            //     }, 1000)
+            // }
 
         })
     }
@@ -181,7 +243,7 @@ export default function MainHistory(props: { type?: string, fast_type?: string }
                             return <Image src={item} key={index} className="archived_img" mode="aspectFill" />
                         })
                     }
-                    <IconArrow color={MainColorType.g03} width={rpxToPx(34)}/>
+                    <IconArrow color={MainColorType.g03} width={rpxToPx(34)} />
                     {/* <IconCellArrow color={MainColorType.g03} width={rpxToPx(34)} /> */}
                     {/* <Image src={require('@assets/_health/cell_arrow.png')} style={{
                         width: rpxToPx(24),
@@ -193,11 +255,11 @@ export default function MainHistory(props: { type?: string, fast_type?: string }
             </View>
         }
         {
-            list.length==0 && <NoData />
+            list.length == 0 && <NoRecord />
         }
         {
             list.map((item, index) => {
-                return <View ref={refDemo} id={'history_id_0'} key={index}>
+                return <View id={`history-${index}`} key={index}>
                     {
                         historyMonth(index, index - 1)
                     }
@@ -229,4 +291,4 @@ export default function MainHistory(props: { type?: string, fast_type?: string }
             (list.length > 0) && (total == list.length) && <Text className="no_more">没有更多了</Text>
         }
     </View>
-}
+})

+ 1 - 1
src/pages/account/Album.tsx

@@ -125,7 +125,7 @@ export default function Album() {
                     <View className="history_item2" >
 
                         <Text className="history_date">{(item.date + '').substring(6, 9)}</Text>
-                        <View className="border_footer_line">
+                        <View style={{display:'flex',flex:1}}>
                             <View className="media" style={{ marginRight: item.images.length == 4 ? 80 : 0 }}>
                                 {
                                     item.images.map((photo, i) => {

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

@@ -23,6 +23,7 @@ if (process.env.TARO_ENV == 'rn') {
 export default function Clock() {
     const dispatch = useDispatch();
     const [loaded, setLoaded] = useState(false)
+    
     const { t } = useTranslation()
     const health = useSelector((state: any) => state.health);
     const user = useSelector((state: any) => state.user);

+ 44 - 39
src/pages/clock/ClockNew.tsx

@@ -22,17 +22,24 @@ import NewButton, { NewButtonType } from "@/_health/base/new_button";
 import { getThemeColor } from "@/features/health/hooks/health_hooks";
 import StatusIndicator, { StatusType } from "@/_health/base/status_indicator";
 import { useTranslation } from "react-i18next";
+import StickyDateList from "@/_health/components/sticky_date_list";
+import NoData from "@/_health/components/no_data";
 
 export default function ClockNew() {
     const [count, setCount] = useState(0)
+    const [loaded, setLoaded] = useState(false)
+    const [showRetry, setShowRetry] = useState(false)
     const [scrollLeft, setScrollLeft] = useState(rpxToPx(750) * 0)
     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 [showSection, setShowSection] = useState(false)
+    const [showDate, setShowDate] = useState(false)
+    const [date, setDate] = useState('')
     const [isPulling, setIsPulling] = useState(false)
     const healthRef = useRef(health)
+    const historyRef = useRef()
     const dispatch = useDispatch();
     const { t } = useTranslation()
     global.dispatch = dispatch;
@@ -81,6 +88,8 @@ export default function ClockNew() {
 
     function getWindows() {
         windows().then(res => {
+            setLoaded(true)
+            setShowRetry(false)
             if (!(res as any).windows.night_day.night.target) {
                 var date = new Date()
                 var hour = date.getHours()
@@ -132,6 +141,8 @@ export default function ClockNew() {
             dispatch(setRefreshs((res as any).refresh_timestamps))
             dispatch(setFinishSetup((res as any).finish_setup))
             setIsPulling(false)
+        }).catch(e => {
+            setShowRetry(true)
         })
         archived()
     }
@@ -184,43 +195,51 @@ export default function ClockNew() {
         if (!health.windows) {
             return <View />
         }
-        return <ScrollView style='height:100vh'
-            refresherEnabled
-            refresherBackground={MainColorType.g05}
+        return <StickyDateList
+            isPulling={isPulling}
+            showDate={showDate}
+            date={date}
             onRefresherRefresh={() => {
                 global.refreshWindow()
                 setIsPulling(true)
             }}
-            refresherTriggered={isPulling}
-            scrollY onScroll={e => {
+            onScroll={e => {
                 if (e.detail.scrollTop > 240) {
                     dispatch(setTitle(pageTitle()))
                 }
                 else {
                     dispatch(setTitle(''))
                 }
-            }}>
-            <MainSwiper count={count} pageChanged={pageChanged} typeChanged={typeChanged} />
-            {/* <StatusIndicator type={StatusType.normal} color={MainColorType.fast} />
-            <StatusIndicator type={StatusType.normal} color={MainColorType.fast} text="hello world" />
-            <StatusIndicator type={StatusType.ing} color={MainColorType.fast} />
-            <StatusIndicator type={StatusType.ing} color={MainColorType.fast} text="hello world" />
-            <StatusIndicator type={StatusType.img} color={MainColorType.fast}>
-                <Image style={{ width: rpxToPx(20), height: rpxToPx(20) }} src={require('@assets/_health/checked.png')} />
-            </StatusIndicator>
-            <StatusIndicator type={StatusType.img} color={MainColorType.fast}  text="hello world">
-                <Image style={{ width: rpxToPx(20), height: rpxToPx(20) }} src={require('@assets/_health/checked.png')} />
-            </StatusIndicator> */}
-            <MainConsole type={type} />
+                if (historyRef) {
+                    (historyRef.current as any).onScroll(e)
+                }
+            }}
+        >
+            <View style={{ display: 'flex', flexDirection: 'column' }}>
+                <MainSwiper count={count} pageChanged={pageChanged} typeChanged={typeChanged} />
+                <MainConsole type={type} />
 
-            <MainHistory />
-            <View style={{ height: 200 }} />
-            {
-                (health.mode == 'DAY' || health.mode == 'NIGHT') && <View style={{ height: 150, flexShrink: 0 }} />
-            }
-        </ScrollView>
+                <MainHistory ref={historyRef} updateDate={(e) => {
+                    setShowDate(e.show)
+                    setDate(e.date)
+                }} />
+                <View style={{ height: 200 }} />
+                {
+                    (health.mode == 'DAY' || health.mode == 'NIGHT') && <View style={{ height: 150, flexShrink: 0 }} />
+                }
+            </View>
+        </StickyDateList>
     }
     //https://blog.csdn.net/weixin_43525284/article/details/130182218
+
+    if (!loaded && showRetry) return <NoData refresh={
+        () => {
+            getWindows();
+            if (global.refreshHistory) {
+                global.refreshHistory()
+            }
+        }
+    } />
     return <View style={{ flex: 1, position: 'relative' }}>
         {
             process.env.TARO_ENV == 'weapp' ? detail() : <ScrollView style={{ flex: 1, backgroundColor: MainColorType.bg }} onScroll={e => {
@@ -237,21 +256,7 @@ export default function ClockNew() {
 
             </ScrollView>
         }
-        <View className="h26" style={{
-            position: 'absolute',
-            left: 0,
-            top: 0,
-            right: 0,
-            height: rpxToPx(84),
-            backgroundColor: '#f5f5f5',
-            paddingLeft: rpxToPx(40),
-            display: 'flex',
-            boxSizing: 'border-box',
-            flexDirection: 'row',
-            alignItems: 'center',
-            opacity: showSection ? 1 : 0,
-            color: MainColorType.g01
-        }}>111</View>
+
         {
             process.env.TARO_ENV == 'weapp' && <TabBar index={0} />
         }