leon 1 год назад
Родитель
Сommit
6ae6ead923

+ 10 - 0
src/_health/base/cell.scss

@@ -0,0 +1,10 @@
+.common_cell_bg{
+    background-color: #fff;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+}
+
+.cell_hover{
+    background-color: #E5E5E5;
+}

+ 13 - 0
src/_health/base/cell.tsx

@@ -0,0 +1,13 @@
+import { View } from "@tarojs/components";
+import './cell.scss'
+
+export default function Cell(props: { disable?: boolean, className?: any, onClick?: any, children: any }) {
+
+    var name = `common_cell_bg ${props.className}`
+    
+    return <View className={name} hoverClass={props.disable ? '' : 'cell_hover'} onClick={props.onClick}>
+        {
+            props.children
+        }
+    </View>
+}

+ 190 - 0
src/_health/base/new_modal.scss

@@ -0,0 +1,190 @@
+/* #ifdef weapp */
+.modal {
+    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: modalBgAnim 0.2s linear forwards;
+}
+
+.rn_modal{
+    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 modalBgAnim {
+
+    100% {
+        background-color: rgba($color: #000000, $alpha: 0.15);
+    }
+}
+
+.modal_dismiss {
+    background-color: rgba($color: #000000, $alpha: 0.15);
+    animation: modalBgHideAnim 0.2s linear forwards;
+}
+
+@keyframes modalBgHideAnim {
+    100% {
+        background-color: rgba($color: #000000, $alpha: 0);
+    }
+}
+
+
+.modal_center_container {
+    align-items: center;
+    justify-content: center;
+    // margin-bottom: 560px;
+}
+
+.center_modal_detail {
+    margin-bottom: 192px;
+}
+
+.modal_center_content {
+    // background-color: #1c1c1c;
+    // border-radius: 36rpx;
+    width: 658px;
+
+}
+
+
+.modal_bottom_content {
+    // padding-bottom: 120px;
+    width: 750px;
+    background-color: #f5f5f5;
+    border-top-left-radius: 36px;
+    border-top-right-radius: 36px;
+    position: relative;
+    display: flex;
+    flex-shrink: 0;
+    flex-direction: column;
+    z-index: 1000000;
+    margin-bottom: -1000px;
+    animation: modalAnim 0.2s linear forwards;
+}
+
+.modal_bottom_dismiss {
+    margin-bottom: 0px;
+    animation: modalHideAnim 0.2s linear forwards;
+}
+
+@keyframes modalAnim {
+    0% {
+        margin-bottom: -1000px;
+    }
+
+    100% {
+        margin-bottom: 0;
+    }
+}
+
+@keyframes modalHideAnim {
+    100% {
+        margin-bottom: -1000px;
+    }
+}
+
+/* #endif */
+
+/* #ifdef rn */
+
+.modal {
+    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_content {
+    // padding-bottom: 120px;
+    width: 750px;
+    background-color: #1c1c1c;
+    border-top-left-radius: 36px;
+    border-top-right-radius: 36px;
+    display: flex;
+    flex-shrink: 0;
+    flex-direction: column;
+    z-index: 1000000;
+    margin-bottom: 0;
+    // height: 400;
+    // margin-bottom: -1000px;
+    // animation: modalAnim 0.2s linear forwards;
+}
+
+/* #endif */
+
+
+
+
+
+.modal_title {
+    font-size: 34px;
+    height: 128px;
+    font-weight: 500;
+    width: 750px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    position: relative;
+}
+
+.modal_footer{
+    
+}
+
+.modal_operate {
+    display: flex;
+    flex-direction: row;
+    width: 750px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin-top: 36px;
+}
+
+.modal_btn {
+    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;
+}

+ 136 - 0
src/_health/base/new_modal.tsx

@@ -0,0 +1,136 @@
+import { View, Text, ScrollView } from '@tarojs/components'
+import './new_modal.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 NewModal(props: {
+    children: React.ReactNode,
+    title?: string,
+    dismiss: Function,
+    confirm?: Function,
+    themeColor?: string,
+    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() {
+        setIsDismiss(true)
+        setTimeout(() => {
+            props.dismiss()
+        }, 250)
+    }
+
+    function rndismiss() {
+        endAnimation()
+        setTimeout(() => {
+            props.dismiss()
+        }, 250)
+    }
+
+    global.dismissModal = dismiss;
+
+    if (process.env.TARO_ENV == 'rn') {
+        return <ModalRN transparent
+        // animationType="slide"
+        // style={{backgroundColor:'red'}}
+        >
+            <View style={{ flex: 1, backgroundColor: props.themeIsWhite?'#ffffff90':'#000000cc' }}>
+                <View style={{ flex: 1, backgroundColor: 'transparent' }} onClick={(e) => {
+                    rndismiss()
+                }}></View>
+                <Animated.View className={isDismiss ? 'modal_bottom_content modal_bottom_dismiss' : 'modal_bottom_content'}
+                    style={[{ flexShrink: 0 }, animatedStyle]} onClick={onClick}>
+                    {
+                        props.children
+                    }
+
+                </Animated.View>
+            </View>
+        </ModalRN>
+    }
+
+
+    return <View className={isDismiss ? 'modal modal_dismiss' : 'modal'} catchMove onLongPress={longPress}>
+        <View style={{ flex: 1, width: 375, flexShrink: 0 }} onClick={(e) => {
+            if (process.env.TARO_ENV == 'weapp') {
+                e.stopPropagation()
+            }; dismiss()
+        }}>
+        </View>
+        <View className={isDismiss ? 'modal_bottom_content modal_bottom_dismiss' : 'modal_bottom_content'} style={{ flexShrink: 0 }} onClick={onClick}>
+            <View className='modal_title'>{props.title}</View>
+            {
+                props.children
+            }
+            <View className='modal_footer'></View>
+
+        </View>
+
+    </View>
+}

+ 7 - 0
src/_health/base/new_timepicker.scss

@@ -0,0 +1,7 @@
+.pick_sel_item{
+    height: 80px !important;
+    background-color: #FF2E661A !important;
+    border: solid 1px #ffffff00 !important;
+    border-radius: 40px !important;
+    color: aqua !important;
+}

+ 59 - 0
src/_health/base/new_timepicker.tsx

@@ -0,0 +1,59 @@
+import { rpxToPx } from "@/utils/tools";
+import { PickerView, PickerViewColumn,Text } from "@tarojs/components";
+import { useEffect, useState } from "react";
+import './new_timepicker.scss'
+
+export default function NewTimePicker() {
+    const [items,setItems] = useState<any>([[0],[0]])
+    const [values,setValues] = useState<any>([0,0])
+    useEffect(()=>{
+        var hours:any = []
+        for (var i = 0;i<=23;i++){
+            hours.push(i)
+        }
+        var minutes:any = []
+        for (var i = 0;i<=59;i++){
+            minutes.push(i)
+        }
+        setItems([hours,minutes])
+    },[])
+
+    function onPickerChange(e){
+        setValues(e.detail.value)
+        console.log(e)
+    }
+
+    function getColor(i,j){
+        if (i == 0 && j == values[0]){
+            return true
+        }
+        if (i == 1 && j == values[1]){
+            return true
+        }
+        return false
+    }
+    return <PickerView
+        value={values}
+        // itemStyle={{ color: '#000' }}
+        style={{ color: '#000', height: rpxToPx(340),width:rpxToPx(670) }}
+        onChange={onPickerChange}
+        indicatorClass="pick_sel_item"
+        indicatorStyle="background-color: #FF2E661A !important;"
+        immediateChange={true}
+        className="picker"
+    // maskClass={props.hideTitle?"picker-mask-small":"picker-mask"}
+    >
+        {
+            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)?'#FF2E66':'#000' }}>{obj}</Text>
+                        );
+                    })}
+                </PickerViewColumn>
+            })
+        }
+
+    </PickerView >
+}

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

@@ -68,7 +68,7 @@ export default function AddLabel(props: { labels: any }) {
             <View className="label_bg">
                 {
                     props.labels.map((item, index) => {
-                        return <View className="label" key={index} onClick={() => setValue(item.label)}>{item.label}</View>
+                        return <View className="label" key={index} onClick={() => setValue(item.title)}>{item.title}</View>
                     })
                 }
             </View>

+ 0 - 0
src/_health/pages/edit_schedule.ts.config → src/_health/pages/edit_schedule.config.ts


+ 3 - 3
src/_health/pages/move.tsx

@@ -74,7 +74,7 @@ export default function Move() {
             var temps: any = []
             for (var i = array.length - 1; i >= 0; i--) {
                 var obj = array[i]
-                if (obj.status != 'NOT_CHECK') {
+                if (obj.status != 'WFS') {
                     temps.push(obj)
                 }
             }
@@ -390,10 +390,10 @@ export default function Move() {
                 item.status == 'MISSED' && <Text className="missed">Missed</Text>
             }
             {
-                item.status == 'CHECKED' && item.real_steps == 0 && <Image className="history_item_detail_icon" src={require('@assets/_health/sit.png')} />
+                item.status == 'SEDENTARY'  && <Image className="history_item_detail_icon" src={require('@assets/_health/sit.png')} />
             }
             {
-                item.status == 'CHECKED' && item.real_steps > 0 && <Image className="history_item_detail_icon" src={require('@assets/_health/walk.png')} />
+                item.status == 'ACTIVE' && <Image className="history_item_detail_icon" src={require('@assets/_health/walk.png')} />
             }
             <View className="border_footer_line" />
         </View>

+ 25 - 17
src/_health/pages/move_schedule.tsx

@@ -1,6 +1,9 @@
-import { View, Text,Image } from "@tarojs/components";
+import { View, Text,Image, Switch } from "@tarojs/components";
 import './move_schedule.scss'
 import { useRouter } from "@tarojs/taro";
+import { useEffect, useState } from "react";
+import { getMoveSchedules } from "@/services/health";
+import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
 
 let useRoute;
 let useNavigation;
@@ -28,9 +31,19 @@ export default function MoveSchedule() {
         router = useRouter()
     }
 
-    const hours = JSON.parse(router.params.hours)
+    const [hours,setHours] = useState(JSON.parse(router.params.hours))
+    const [loaded,setLoaded] = useState(false)
+
+    
+    useEffect(()=>{
+        getMoveSchedules().then(res => {
+            console.log(hours)
+            setLoaded(true)
+        })
+    },[])
 
     // console.log(JSON.parse(router.params.hours))
+    if (!loaded) return <View />
 
     return <View style={{ display: 'flex', flexDirection: 'column' }}>
         {
@@ -42,25 +55,18 @@ export default function MoveSchedule() {
                 end = (end + '').padStart(2, '0')
                 
                 open = (open + '').padStart(2, '0')
-                if (item.status!='NOT_CHECK') return <View key={index}/>
+                if (item.status!='WFS') return <View key={index}/>
                 return <View key={index} className="schedule_item">
                     <View className="schedule_item_left">
+                        <View>{open}:50</View>
                         <View className="schedule_item_time">{parseInt(start)<new Date().getHours()?'明天':''}{start}:00-{end}:00</View>
-                        <Text className="schedule_item_target">{item.real_steps}/{item.target_steps} steps</Text>
+                        {/* <Text className="schedule_item_target">{item.real_steps}/{item.target_steps} steps</Text> */}
                     </View>
                     <View style={{ flex: 1 }} />
-                    {
-                        item.status == 'MISSED' && <Text className="missed">Missed</Text>
-                    }
-                    {
-                        item.status == 'CHECKED' && item.real_steps == 0 && <Image className="history_item_detail_icon" src={require('@assets/_health/sit.png')} />
-                    }
-                    {
-                        item.status == 'CHECKED' && item.real_steps > 0 && <Image className="history_item_detail_icon" src={require('@assets/_health/walk.png')} />
-                    }
-                    {
-                        item.status == 'NOT_CHECK' && <Text className="schedule_item_open">{open}:50开放</Text>
-                    }
+                    <Switch checked={item.reminder}/>
+                    {/* {
+                        item.status == 'WFS' && <Text className="schedule_item_open">{open}:50开放</Text>
+                    } */}
                     
                     {
                         index < hours.length - 1 && <View className="schedule_item_line" />
@@ -68,6 +74,8 @@ export default function MoveSchedule() {
                 </View>
             })
         }
-        <Text className="no_more">没有更多了</Text>
+        <Text className="no_more" onClick={()=>{
+            jumpPage('./move_setting_reminder')
+        }}>Full schedules</Text>
     </View>
 }

+ 4 - 1
src/_health/pages/move_setting.tsx

@@ -6,6 +6,7 @@ import { useEffect, useState } from "react";
 import { getThemeColor } from "@/features/health/hooks/health_hooks";
 import { getMoveSchedules, setMoveSchedules } from "@/services/health";
 import Taro from "@tarojs/taro";
+import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
 
 export default function MoveSetting() {
     const [selIndex, setSelIndex] = useState(-1)
@@ -33,7 +34,9 @@ export default function MoveSetting() {
         })
     }
     return <View className="setting_container">
-        <View className="setting_cell" hoverClass='cell_hover' hoverStayTime={50} onClick={() => { }}>
+        <View className="setting_cell" hoverClass='cell_hover' hoverStayTime={50} onClick={() => {
+            jumpPage('./move_setting_time')
+        }}>
             <Text className="setting_title">打卡提醒</Text>
             <Text className="placeholder">设置</Text>
             <IconCellArrow width={18} color="#B2B2B2" />

+ 0 - 0
src/_health/pages/move_setting_reminder.config.ts


+ 0 - 0
src/_health/pages/move_setting_reminder.scss


+ 42 - 0
src/_health/pages/move_setting_reminder.tsx

@@ -0,0 +1,42 @@
+import { View, Text, Switch } from "@tarojs/components";
+import './move_setting_reminder.scss'
+import Cell from "../base/cell";
+import { useEffect, useState } from "react";
+import { getMoveSchedules } from "@/services/health";
+
+export default function MoveSettingReminder() {
+    const [selIndex, setSelIndex] = useState(-1)
+    const [hours, setHours] = useState('')
+    const [total, setTotal] = useState('')
+    const [detail, setDetail] = useState<any>(null)
+
+    useEffect(() => {
+        getMoveSchedules().then(res => {
+            setDetail(res)
+            setHours((res as any).goal.hour)
+            setTotal((res as any).goal.day)
+        })
+    }, [])
+
+    if (!detail) return <View />
+
+    return <View>
+        <Text>打卡时刻表</Text>
+        {
+            detail.schedules.map((item, index) => {
+                return <View key={index}>
+                    <Cell className='demoCell' disable>
+                        <View style={{ display: 'flex', flexDirection: 'column' }}>
+                            <Text>{item.reminder_time}</Text>
+                            <View>
+                                <Text style={{ flex: 1 }}>check in for {item.time}-{item.end_time}</Text>
+                                <Switch checked={item.reminder} />
+                            </View>
+                        </View>
+                    </Cell>
+                </View>
+            })
+        }
+
+    </View>
+}

+ 0 - 0
src/_health/pages/move_setting_time.config.ts


+ 3 - 0
src/_health/pages/move_setting_time.scss

@@ -0,0 +1,3 @@
+.demoCell{
+    height: 120px;
+}

+ 45 - 0
src/_health/pages/move_setting_time.tsx

@@ -0,0 +1,45 @@
+import { View, Text } from "@tarojs/components";
+import './move_setting_time.scss'
+import Cell from "../base/cell";
+import { useEffect, useState } from "react";
+import { getMoveSchedules } from "@/services/health";
+
+export default function MoveSettingTime() {
+    const [selIndex, setSelIndex] = useState(-1)
+    const [hours, setHours] = useState('')
+    const [total, setTotal] = useState('')
+    const [detail, setDetail] = useState<any>(null)
+
+    useEffect(() => {
+        getMoveSchedules().then(res => {
+            setDetail(res)
+            setHours((res as any).goal.hour)
+            setTotal((res as any).goal.day)
+        })
+    }, [])
+
+    if (!detail) return <View />
+
+    return <View>
+        <Text>每小时步数目标</Text>
+        <Text>平均 {hours} 步,全天 {total} 步</Text>
+        {
+            detail.schedules.map((item, index) => {
+                return <View key={index}>
+                    <Cell className='demoCell' disable>
+                        <View style={{display:'flex',flexDirection:'column'}}>
+                            <Text>{item.time}-{item.end_time}</Text>
+                            <View>
+                                <Text style={{flex:1}}>200<Text>Steps</Text></Text>
+                                <Text onClick={()=>{
+                                    setSelIndex(index)
+                                }}>更改目标</Text>
+                            </View>
+                        </View>
+                    </Cell>
+                </View>
+            })
+        }
+
+    </View>
+}

+ 11 - 0
src/_health/pages/timeline_detail.scss

@@ -92,4 +92,15 @@
     border-radius: 18px;
     align-items: center;
     justify-content: center;
+}
+
+.detail_time{
+    color: #5C7099;
+    margin-top: 10px;
+}
+
+.publish_time{
+    margin-top: 122px;
+    color: #B2B2B2;
+    font-size: 24px;
 }

+ 20 - 14
src/_health/pages/timeline_detail.tsx

@@ -197,29 +197,35 @@ export default function TimelineDetail() {
                 <Text className="detail_nickname">{user.nickname}</Text>
                 {
                     list.map((item, index) => {
-                        return <View key={index} style={{flexDirection:'column',display:'flex'}}>
-                            <Text>{dayjs(item.time.timestamp).format('HH:mm')}</Text>
-                            {
-                                item.title && <Text>{item.title}</Text>
-                            }
-                            {
-                                item.description && <Text>{item.description}</Text>
-                            }
+                        return <View key={index} style={{ flexDirection: 'column', display: 'flex' }}>
+
+                            <Text className="detail_time">{dayjs(item.time.timestamp).format('HH:mm')}
+                                {
+                                    item.title && <Text> {item.title}</Text>
+                                }
+                                {
+                                    item.description && <Text style={{ color: '#000' }}> {item.description}</Text>
+                                }
+                            </Text>
+
                             {
-                                item.media && <Image src={item.media[0].url} style={{width:60,height:60}}/>
+                                item.media && item.media.length > 0 && <Image mode="aspectFill" src={item.media[0].url} style={{ width: 60, height: 60, marginTop: 5 }} />
                             }
                         </View>
                     })
                 }
                 {
-                    publish && <Text>发布于{dayjs(publish.timestamp).format('MM-DD HH:mm')}</Text>
+                    publish && <Text className="publish_time">发布于{dayjs(publish.timestamp).format('MM-DD HH:mm')}</Text>
                 }
             </View>
         </View>
-        <View className="add_note" onClick={() => {
-            timestamp = new Date().getTime()
-            setShowPop(true)
-        }}>写个笔记</View>
+        {
+            health.mode != 'ACTIVE' && health.mode != 'EAT' && <View className="add_note" onClick={() => {
+                timestamp = new Date().getTime()
+                setShowPop(true)
+            }}>写个笔记</View>
+        }
+
         {
             showPop && <View className="publish_bg">
                 <View style={{

+ 3 - 1
src/app.config.ts

@@ -63,7 +63,9 @@ const appConfig = defineAppConfig({
         'pages/archive',
         'pages/move',
         'pages/move_schedule',
-        'pages/move_setting'
+        'pages/move_setting',
+        'pages/move_setting_reminder',
+        'pages/move_setting_time'
       ]
     }
   ],

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/components/basic/Icons.tsx


+ 26 - 2
src/features/health/HeaderCircadian.tsx

@@ -34,13 +34,36 @@ export default function HeaderCircadian() {
         if (health && health.windows) {
             // lauchShow = true
             const scenario = getScenario(health.windows, health.mode)
-            if (scenario.real) {
+            if (scenario.real || scenario.status == 'OG') {
                 dispatch(setShowActionTip({
-                    isShow: true,
+                    isShow: false,
                     isCompleted: false
                 }))
+
+                setTimeout(() => {
+                    dispatch(setShowActionTip({
+                        isShow: true,
+                        isCompleted: false
+                    }))
+                }, 50)
+
                 return;
             }
+            else if (scenario.status == 'DONE') {
+                dispatch(setShowActionTip({
+                    isShow: false,
+                    isCompleted: false
+                }))
+
+                setTimeout(() => {
+                    dispatch(setShowActionTip({
+                        isShow: true,
+                        isCompleted: true
+                    }))
+                }, 50)
+
+                return
+            }
             else {
                 if (new Date().getTime() >= scenario.target.start_timestamp && new Date().getTime() < scenario.target.end_timestamp) {
                     setDesc('ON')
@@ -133,6 +156,7 @@ export default function HeaderCircadian() {
                     }
                     break;
                 case 'ACTIVE':
+                    debugger
                     {
                         setIcon(require('@assets/_health/active.png'))
                         setTitle('Activity logging')

+ 2 - 2
src/features/health/HistoryItem.tsx

@@ -92,7 +92,7 @@ export default function HistoryItem(props: { data: any, preData: any, index: num
         return dayjs(props.data.window_range.start_timestamp).format('D')
     }
 
-    return <View className="history_item" onClick={() => props.onClick()}>
+    return <View className="history_item">
         <View className="history_date">{historyDate()}</View>
         <View className="history_content">
 
@@ -100,7 +100,7 @@ export default function HistoryItem(props: { data: any, preData: any, index: num
                 {
                     props.data.events.map((item, index) => {
                         return <Text key={index}>
-                            <Text className="history_item_title">{dayjs(item.real.start_timestamp).format('HH:mm')} {getTitle(item)} </Text>
+                            <Text className="history_item_title">{item.real && dayjs(item.real.start_timestamp).format('HH:mm')} {getTitle(item)} </Text>
                             {
                                 item.moment && item.moment.description && <Text className="history_item_desc">{item.moment.description}</Text>
                             }

+ 13 - 2
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 { IconMore } from "@/components/basic/Icons";
+import { IconCellArrow, IconMore } from "@/components/basic/Icons";
 import DurationPicker from "@/_health/components/duration_picker";
 import Taro from "@tarojs/taro";
 import { systemLocation } from "@/services/common";
@@ -156,8 +156,19 @@ export default function MainConsole(props: { type: WindowType }) {
         if (health.mode == 'DAY' || health.mode == 'NIGHT') {
             return null
         }
-        if (item.action && item.action != 'NA')
+        if (item.action && item.action != 'NA'){
+            if (health.mode == 'FAST'|| health.mode == 'SLEEP'){
+                if (item.action == 'POST_MOMENT'){
+                    return <IconCellArrow color='#B2B2B2' width={rpxToPx(34)}/>
+                }
+                
+            }
+            else if (health.mode == 'ACTIVE' && item.action == 'POST_MOMENT'){
+                return <View className="timeline_operate" style={{ color: themeColor, backgroundColor: '#fff',borderColor:themeColor,borderWidth:1,borderStyle:'solid' }} onClick={() => record(item)}>{operateTitle(item)}</View>
+            }
             return <View className="timeline_operate" style={{ color: themeColor, backgroundColor: themeColor + '1A' }} onClick={() => record(item)}>{operateTitle(item)}</View>
+        }
+            
         return <View />
     }
 

+ 36 - 12
src/pages/account/Album.tsx

@@ -1,48 +1,72 @@
 import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
-import { getAlbums } from "@/services/health";
-import { View, Text,Image } from "@tarojs/components";
+import { getAlbums, getAlbumsStat } from "@/services/health";
+import { View, Text, Image } from "@tarojs/components";
 import { useEffect, useState } from "react";
 import './Album.scss'
 
 export default function Album() {
 
     const [medias, setMedias] = useState<any>([])
+    const [window, setWindow] = useState('')
+    const [stat, setStat] = useState<any>(null)
 
     useEffect(() => {
-        getAlbumsData()
+        getAlbumsData('')
     }, [])
 
-    function getAlbumsData() {
+    function getAlbumsData(str) {
         getAlbums({
             page: 1,
-            limit: 50
+            limit: 50,
+            window: str
         }).then(res => {
             setMedias((res as any).data)
         })
+
+        getAlbumsStat().then(res => {
+            setStat(res)
+        })
     }
 
 
     return <View style={{ display: 'flex', flexDirection: 'column' }}>
+        {
+            stat && <View style={{ flexDirection: 'row', alignItems: 'center', display: 'flex' }}>
+                <View onClick={() => {
+                    setWindow('')
+                    getAlbumsData('')
+                }}>全部{stat.total}</View>
+                {
+                    stat.items.map((item, index) => {
+                        return <View key={index} onClick={() => {
+                            setWindow(item.window)
+                            getAlbumsData(item.window)
+                        }}>{item.window}{item.image_count}</View>
+                    })
+                }
+            </View>
+        }
+
         <View className="photo_wall" onClick={() => {
             jumpPage('/pages/account/PhotoWall')
         }}>
-            <View style={{flex:1}}/>
+            <View style={{ flex: 1 }} />
             <Text className="photo_wall_text">Photo Wall</Text>
-            <Image className="photo_wall_arrow" src={require('@assets/_health/arrow2.png')}/>
+            <Image className="photo_wall_arrow" src={require('@assets/_health/arrow2.png')} />
             <View className="album_line" />
         </View>
         {
-            medias.map((item,index)=>{
+            medias.map((item, index) => {
                 return <View className="album_item" key={index}>
-                    <Text className="album_date">{(item.date+'').substring(6,9)}</Text>
+                    <Text className="album_date">{(item.date + '').substring(6, 9)}</Text>
                     <View className="album_container">
                         {
-                            item.images.map((photo,i)=>{
-                                return <Image mode="aspectFill" src={photo} key={i*900} className="album_phone"/>
+                            item.images.map((photo, i) => {
+                                return <Image mode="aspectFill" src={photo} key={i * 900} className="album_phone" />
                             })
                         }
                     </View>
-                    <View className="album_line"/>
+                    <View className="album_line" />
                 </View>
             })
         }

+ 45 - 0
src/pages/account/JournalDetail.scss

@@ -0,0 +1,45 @@
+.journal_detail {
+    display: flex;
+    flex-direction: row;
+    background-color: #fff;
+    padding-left: 40px;
+    padding-right: 40px;
+    padding-bottom: 40px;
+    padding-top: 40px;
+}
+
+.header_avatar {
+    width: 74px;
+    height: 74px;
+    border-radius: 8px;
+    margin-right: 24px;
+}
+
+.jounal_content {
+    flex: 1;
+    flex-direction: column;
+    display: flex;
+}
+
+.journal_nickname {
+    display: flex;
+    font-size: 34px;
+    font-weight: bold;
+    color: #5C7099;
+    font-weight: bold;
+}
+
+.img_container{
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    margin-top: 24px;
+    margin-bottom: 16px;
+}
+
+.journal_img{
+    width: 155px;
+    height: 155px;
+    margin-right: 4px;
+    margin-bottom: 4px;
+}

+ 78 - 4
src/pages/account/JournalDetail.tsx

@@ -1,6 +1,11 @@
-import { View } from "@tarojs/components";
+import { View, Image, Text } from "@tarojs/components";
 import { useRouter } from "@tarojs/taro";
-import { useState } from "react";
+import { useEffect, useState } from "react";
+import { useSelector } from "react-redux";
+import './JournalDetail.scss'
+import Taro from "@tarojs/taro";
+import dayjs from "dayjs";
+import { rpxToPx } from "@/utils/tools";
 
 let useRoute;
 let useNavigation;
@@ -11,7 +16,10 @@ if (process.env.TARO_ENV == 'rn') {
 }
 
 export default function JournalDetail() {
-
+    const health = useSelector((state: any) => state.health);
+    const user = useSelector((state: any) => state.user);
+    const [imgs, setImgs] = useState<any>([])
+    const [events, setEvents] = useState<any>([])
     let router
     let navigation;
     if (useNavigation) {
@@ -25,10 +33,76 @@ export default function JournalDetail() {
         router = useRouter()
     }
 
-    const [detail,setDetail] = useState(JSON.parse(router.params.detail))
+    const [detail, setDetail] = useState(JSON.parse(router.params.detail))
+
+    useEffect(() => {
+        let obj = JSON.parse(router.params.detail)
+
+        console.log(obj)
+
+        var array: any = []
+
+        obj.windows.map(item => {
+            item.events.map(tem => {
+                array.push(tem)
+            })
+        })
+        const sortedArray = array.sort((a, b) => {
+            return a.real.start_timestamp - b.real.start_timestamp;
+        });
+
+        // 返回一个新数组
+        const newArray = [...sortedArray];
+        setImgs(obj.imgs)
+        setEvents(newArray)
+    }, [])
+
+
+    function preview(url) {
+
+        Taro.previewImage({
+            current: url,
+            urls: imgs
+        })
+    }
 
 
     return <View>
+        <View className="journal_detail">
+            <Image className="header_avatar" src={user.avatar} mode="aspectFill" />
+            <View className="jounal_content">
+                <Text className="journal_nickname">{user.nickname}</Text>
+                <View style={{ flexDirection: 'column', display: 'flex',marginTop:rpxToPx(16) }}>
+                    {
+                        events.map((item, index) => {
+                            return <View key={index} style={{marginBottom:index<events.length-1?rpxToPx(48):0,display:'flex',flexDirection:'column'}}>
+                                <Text >
+                                {
+                                    item.real && <Text style={{color:'#5C7099'}}>{dayjs(item.real.start_timestamp).format('HH:mm')} </Text>
+                                }
+                                {
+                                    item.moment && item.moment.title && <Text> {item.moment.title} </Text>
+                                }
+                                {
+                                    item.moment && item.moment.description && <Text> {item.moment.description} </Text>
+                                }
+
+                            </Text>
+                            </View>
+                        })
+                    }
+                </View>
 
+                <View className="img_container">
+                    {
+                        imgs.map((item, index) => {
+                            return <Image key={index} src={item} className="journal_img" mode="aspectFill" onClick={() => {
+                                preview(item)
+                            }} />
+                        })
+                    }
+                </View>
+            </View>
+        </View>
     </View>
 }

+ 5 - 1
src/pages/account/PhotoWall.tsx

@@ -2,13 +2,16 @@ import { View } from "@tarojs/components";
 import './PhotoWall.scss'
 import Taro from "@tarojs/taro";
 import { useState } from "react";
+import NewTimePicker from "@/_health/base/new_timepicker";
 
 export default function PhotoWall() {
     const screenWidth = Taro.getSystemInfoSync().screenWidth
     const space = 2
     const itemWidth = (screenWidth-space*2)/3.0
     const [list, setList] = useState(new Array(10).fill("aaa"))
-    return <View className="photo_wall">
+    return <View style={{display:'flex',flexDirection:'column'}}>
+        <NewTimePicker />
+        <View className="photo_wall">
         {
             list.map((item, index) => {
                 return <View key={index} style={{ width: itemWidth, height: itemWidth, backgroundColor: 'pink',marginBottom:space }}></View>
@@ -17,4 +20,5 @@ export default function PhotoWall() {
         <View style={{ width: itemWidth, height: itemWidth }} />
         <View style={{ width: itemWidth, height: itemWidth }} />
     </View>
+    </View>
 }

+ 13 - 1
src/services/health.tsx

@@ -1,4 +1,4 @@
-import { API_ACTIVE_MOVES, API_ACTIVE_MOVES_CURRENT, API_ACTIVE_MOVES_SCHEDULES, API_HEALTH_ARCHIVED, API_HEALTH_CLOCK, API_HEALTH_EVENTS, API_HEALTH_LABELS, API_HEALTH_MOMENT, API_HEALTH_RECORD, API_HEALTH_SCHEDULES, API_HEALTH_STREAKS, API_HEALTH_TARGET, API_HEALTH_WINDOWS, API_ME_ALBUMS, API_ME_JOURNALS } from "./http/api";
+import { API_ACTIVE_MOVES, API_ACTIVE_MOVES_CURRENT, API_ACTIVE_MOVES_SCHEDULES, API_HEALTH_ARCHIVED, API_HEALTH_CLOCK, API_HEALTH_EVENTS, API_HEALTH_LABELS, API_HEALTH_MOMENT, API_HEALTH_RECORD, API_HEALTH_SCHEDULES, API_HEALTH_STREAKS, API_HEALTH_TARGET, API_HEALTH_WINDOWS, API_ME_ALBUMS, API_ME_ALBUMS_STAT, API_ME_JOURNALS } from "./http/api";
 import { request } from "./http/request";
 
 export const getLabels = (params) => {
@@ -255,6 +255,18 @@ export const getAlbums = (params) =>{
     })
 }
 
+export const getAlbumsStat = () =>{
+    return new Promise((resolve) => {
+        request({
+            url: API_ME_ALBUMS_STAT, method: 'GET', data: { }
+        }).then(res => {
+            resolve(res);
+            // dispatch(loginSuccess(res));
+        })
+    })
+}
+
+
 export const getMoveSchedules = ()=>{
     return new Promise((resolve) => {
         request({

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

@@ -111,4 +111,5 @@ export const API_ACTIVE_MOVES_CURRENT = `${baseUrl}/api/health/active/moves/curr
 export const API_ACTIVE_MOVES_SCHEDULES = `${baseUrl}/api/health/schedules/active/move`
 export const API_ACTIVE_MOVES= `${baseUrl}/api/health/active/moves`
 export const API_ME_JOURNALS = `${baseUrl}/api/health/wo/journals`
-export const API_ME_ALBUMS = `${baseUrl}/api/health/wo/albums`
+export const API_ME_ALBUMS = `${baseUrl}/api/health/wo/albums`
+export const API_ME_ALBUMS_STAT = `${baseUrl}/api/health/wo/albums-stat`

Некоторые файлы не были показаны из-за большого количества измененных файлов