Leon 2 vuotta sitten
vanhempi
commit
0eadcb7da5

+ 5 - 1
src/components/input/Slider.tsx

@@ -4,7 +4,7 @@ import { ColorType } from '@/context/themes/color'
 import { useState } from 'react';
 import { rpxToPx } from '@/utils/tools';
 
-export default function () {
+export default function (props: { onChanged?: Function }) {
     const colors = [
         '#00ffff', '#1cf2ff', '#39e6ff', '#56d9ff', '#73cdff', '#90c1ff', '#adb4ff', '#caa8ff', '#e79bff', '#ffaeff', '#ffffff',
         '#ffebe5',
@@ -51,6 +51,10 @@ export default function () {
 
     const handleTouchEnd = () => {
         setIsSliding(false);
+        if (props.onChanged){
+            props.onChanged(value);
+        }
+        
     };
 
     function getColor() {

+ 2 - 1
src/context/locales/zh.js

@@ -293,7 +293,8 @@ export default {
             album:'从相册选择',
             share_title:'我的饮食日记',
             prompt:'提示',
-            prompt_detail:'日记列表顺序发生变化,点击刷新'
+            prompt_detail:'日记列表顺序发生变化,点击刷新',
+            sence_desc:'拍摄食物,记录餐前饥饿感\n记录餐后饱足感'
         },
         track_something: {
             btn_record: '记录',

+ 35 - 0
src/features/food/FoodConsole.scss

@@ -6,6 +6,41 @@
     background-color: #00ffff;
 }
 
+.food_console_box{
+    background-color: #121212;
+    border-radius: 36px;
+    margin-left: 46px;
+    margin-right: 46px;
+    padding-top: 32px;
+    padding-bottom: 44px;
+    margin-bottom: 24px;
+}
+
+.food_console_title{
+    color: #fff;
+    font-size: 36px;
+    font-weight: bold;
+    margin-left: 40px;
+}
+
+.food_console_desc{
+    margin-top: 16px;
+    display: flex;
+    flex-direction: row;
+    color: #ffffff66;
+    font-size: 28px;
+    line-height: 48px;
+}
+
+.food_console_desc_point{
+    width: 12px;
+    height: 12px;
+    border-radius: 6px;
+    margin-right: 8px;
+    margin-left: 20px;
+    margin-top: 18px;
+}
+
 .demo1{
     width: 100px;
     height: 100px;

+ 65 - 32
src/features/food/FoodConsole.tsx

@@ -1,4 +1,4 @@
-import { View, Image, Text } from '@tarojs/components'
+import { View, Image, Text, Switch } from '@tarojs/components'
 import './FoodConsole.scss'
 import { rpxToPx } from '@/utils/tools'
 import Taro from '@tarojs/taro'
@@ -16,8 +16,11 @@ if (process.env.TARO_ENV == 'rn') {
     useNavigation = require("@react-navigation/native").useNavigation
 }
 
-export default function Component(props: { addItem: Function }) {
+export default function Component(props: { addItem: Function, firstItem: any }) {
     const user = useSelector((state: any) => state.user);
+    const [modeOn, setModeOn] = useState(false)
+    const [firstData, setFirstData] = useState(props.firstItem)
+    const [lastUnFinished, setLastUnFinished] = useState(false)
     const { t } = useTranslation()
     const [imgUrl, setImgUrl] = useState('')
     let navigation;
@@ -26,10 +29,23 @@ export default function Component(props: { addItem: Function }) {
     }
 
     useEffect(() => {
-        var str = Taro.getStorageSync('pic')
-        if (str && str.length > 0) {
-            setImgUrl(str)
+        setFirstData(props.firstItem)
+    }, [props.firstItem])
+
+    useEffect(() => {
+        if (firstData && firstData.status == 'ONGOING' &&
+            firstData.mindful_mode == 'AWARE' &&
+            (!firstData.feel.post_meal || !firstData.feel.pre_meal)) {
+            setLastUnFinished(true)
+            setModeOn(true)
         }
+    }, [firstData])
+
+    useEffect(() => {
+        // var str = Taro.getStorageSync('pic')
+        // if (str && str.length > 0) {
+        //     setImgUrl(str)
+        // }
     }, [])
 
     function choose(isAlbum = true) {
@@ -59,7 +75,7 @@ export default function Component(props: { addItem: Function }) {
                         console.log(savedFilePath)
                         setImgUrl(savedFilePath as any)
 
-                        uploadFile(savedFilePath,isAlbum ? 'album' : 'camera')
+                        uploadFile(savedFilePath, isAlbum ? 'album' : 'camera')
                     }
                 })
             }
@@ -105,7 +121,7 @@ export default function Component(props: { addItem: Function }) {
         )
     }
 
-    function uploadFile(path,source) {
+    function uploadFile(path, source) {
         Taro.showLoading({
             title: '加载中'
         })
@@ -123,10 +139,10 @@ export default function Component(props: { addItem: Function }) {
                 file_ext: fileExt
             },
             success: (rsp) => {
-                if (rsp.statusCode!=200){
+                if (rsp.statusCode != 200) {
                     Taro.showToast({
-                        title:'操作失败,请检查网络',
-                        icon:'none'
+                        title: '操作失败,请检查网络',
+                        icon: 'none'
                     })
                     return
                 }
@@ -137,7 +153,7 @@ export default function Component(props: { addItem: Function }) {
                     formData: rsp.data.fields,
                     success: rlt => {
                         console.log(rlt)
-                        createData(rsp.data.view_url,source)
+                        createData(rsp.data.view_url, source)
 
                         // uploadAvatar(rsp.data.view_url)
                         // _this.changeAvatar(rsp.data.view_url);
@@ -153,7 +169,7 @@ export default function Component(props: { addItem: Function }) {
         })
     }
 
-    function createData(url,source) {
+    function createData(url, source) {
         var date = new Date();
         var time = date.getTime()
         var strDate = (date.getFullYear() + '') + (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
@@ -162,12 +178,13 @@ export default function Component(props: { addItem: Function }) {
             media: [{
                 url,
                 type: url.indexOf('mp4') != -1 ? 'video' : 'image',
-                source:source
+                source: source
             }],
             start: {
                 timestamp: time,
                 date: strDate
-            }
+            },
+            mindful_mode: modeOn ? 'AWARE' : 'NORMAL'
 
         }).then(res => {
             props.addItem(res)
@@ -175,32 +192,48 @@ export default function Component(props: { addItem: Function }) {
             setImgUrl('')
             Taro.removeStorageSync('pic')
             Taro.hideLoading()
+            setFirstData(res)
+            // if (modeOn) {
+            //     setSwitchDisable(true)
+            // }
         }).catch(e => {
             Taro.hideLoading()
         })
     }
 
+    function modeChange(e) {
+        setModeOn(e.detail.value)
+    }
+
     return <View style={{ marginBottom: rpxToPx(60) }}>
-        <View style={{ display: 'flex', width: rpxToPx(750), alignItems: 'center', justifyContent: 'center', flexDirection: 'column' }}>
-            <View style={{ display: 'flex', flexDirection: 'column' }}>
-                {/* <Slider /> */}
-                {/* <View className='box11' onClick={()=>choose(true)}>{
-                    imgUrl && <Image style={{ width: '100%', height: '100%' }} src={imgUrl} mode="aspectFill" />
-                }
-                </View> */}
-                <View className='camera_bg' onClick={() => choose(false)}>
-                    <Image src={require('@assets/images/camera2.png')} className='camera_icon' />
-                    <Text className='camera_text'>{t('feature.food.camera')}</Text>
-                    <Text className='album_text'>{t('feature.food.album')}</Text>
-                    <View className='album_bottom' onClick={(e) => { choose(true); e.stopPropagation() }} />
-                </View>
-                {/* <Slider /> */}
+        <View className='food_console_box'>
+            <View style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
+                <Text className='food_console_title'>感知模式</Text>
+                <Switch disabled={lastUnFinished} checked={modeOn} color={ColorType.food} style={{ marginRight: rpxToPx(40), opacity: lastUnFinished ? 0.4 : 1 }} onChange={modeChange} />
+            </View>
+
+            <View className='food_console_desc'>
+                <View className='food_console_desc_point' style={{ backgroundColor: ColorType.food }} />
+                <Text>{t('feature.food.sence_desc')}</Text>
             </View>
-            {/* <IconShare color={ColorType.food} width={100} height={100} /> */}
-            {/* <View className='demo1' /> */}
-            {/* <Text style={{ color: '#fff',marginBottom:20 }} onClick={()=>choose(false)}>拍照</Text>
-            <Text style={{ color: '#fff' }} onClick={uploadFile}>上传</Text> */}
 
         </View>
+        {
+            !lastUnFinished && <View style={{ display: 'flex', width: rpxToPx(750), alignItems: 'center', justifyContent: 'center', flexDirection: 'column' }}>
+                <View style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
+                    <View className='camera_bg' onClick={() => choose(false)}>
+                        <Image src={require('@assets/images/camera2.png')} className='camera_icon' />
+                        <Text className='camera_text'>{t('feature.food.camera')}</Text>
+                        <Text className='album_text'>{t('feature.food.album')}</Text>
+                        <View className='album_bottom' onClick={(e) => { choose(true); e.stopPropagation() }} />
+                    </View>
+                    {
+                        modeOn && <View style={{ height: rpxToPx(60) }} />
+                    }
+                    {modeOn && <Slider />}
+                </View>
+            </View>
+        }
+
     </View>
 }

+ 11 - 5
src/features/food/FoodJournal.tsx

@@ -6,11 +6,11 @@ import FoodTimeline from "./FoodTimeline"
 import Layout from "@/components/layout/layout"
 import { NaviBarTitleShowType, TemplateType } from "@/utils/types"
 import { useEffect, useState } from "react"
-import { getFoodJournals, getFoodTags } from "@/services/foodJournal"
+import { getFoodJournals, getFoodScales, getFoodTags } from "@/services/foodJournal"
 import { usePullDownRefresh, useReachBottom, useReady } from "@tarojs/taro"
 import Taro from "@tarojs/taro"
 import { useDispatch, useSelector } from "react-redux"
-import { setMealTags } from "@/store/common"
+import { setFoodScales, setMealTags } from "@/store/common"
 import { getInfoSuccess } from "@/store/user"
 import './FoodJournal.scss'
 import { rpxToPx } from "@/utils/tools"
@@ -29,7 +29,7 @@ export default function Component() {
     const [showError, setShowError] = useState(false)
 
     useEffect(() => {
-        getTags()
+        getConfigs()
         if (user.isLogin) {
             getList(1)
         }
@@ -89,7 +89,7 @@ export default function Component() {
         setCount(count + 1)
     }
 
-    function getTags() {
+    function getConfigs() {
         getFoodTags({
             type: 'meal_tag'
         }).then(res => {
@@ -97,6 +97,12 @@ export default function Component() {
         }).catch(e => {
 
         })
+
+        getFoodScales({
+            type: 'hunger_fullness'
+        }).then(res => {
+            dispatch(setFoodScales((res as any).data))
+        }).catch(e => { })
     }
 
     async function getStorage(key: string) {
@@ -184,7 +190,7 @@ export default function Component() {
     function detail() {
         return <View style={{ position: 'relative', marginTop: rpxToPx(52) }}>
             {
-                <FoodConsole addItem={addItem} />
+                loaded && <FoodConsole addItem={addItem} firstItem={list.length > 0 ? list[0] : null} />
             }
             {
                 user.isLogin && list && <FoodTimeline array={list} refresh={() => refreshData()} forceRefresh={() => getList(1)} />

+ 61 - 38
src/features/food/FoodTimelineItem.tsx

@@ -12,6 +12,8 @@ import PickerViews from "@/components/input/PickerViews";
 import { IconShare } from "@/components/basic/Icons";
 import { TimeFormatter } from "@/utils/time_format";
 import { baseUrl } from "@/services/http/api";
+import Slider from "@/components/input/Slider";
+import { rpxToPx } from "@/utils/tools";
 
 export default function Component(props: {
     data: any, index: number,
@@ -212,6 +214,22 @@ export default function Component(props: {
         })
     }
 
+    function updateFeel(value, isPreMeal) {
+        var feel = isPreMeal ? { pre_meal: value } : { post_meal: value }
+        editFoodJournal({
+            feel: feel
+        }, detail.id).then(res => {
+            (res as any).showDate = props.data.showDate
+
+            setDetail(res)
+            setCount(count + 1)
+
+            props.update(res)
+        }).catch(e => {
+
+        })
+    }
+
     function updateTag(index) {
         var tag = common.meal_tags[index]
         editFoodJournal({
@@ -329,49 +347,55 @@ export default function Component(props: {
         }
     }
 
-    return <View className="food_timeline_item" onLongPress={showActionSheet}>
-        {/* <View className="thumb" style={{backgroundColor:'pink'}}/> */}
+    return <View>
+        {
+            detail.mindful_mode == 'AWARE' && detail.feel.pre_meal && !detail.feel.post_meal && <View style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: rpxToPx(60) }}>
+                <Slider onChanged={(value) => { updateFeel(value,false) }} />
+            </View>
+        }
+        <View className="food_timeline_item" onLongPress={showActionSheet}>
+            <View style={{ flex: 1 }}>
+                {
+                    <View className="tags">
+                        {detail.showDate && <Text className="food_timeline_item_day">{TimeFormatter.getMonthAndDayByDate(detail.start.date)}</Text>}
+                        {
+                            props.index == 0 && !detail.meal_tag && common.meal_tags.map((item, index) => {
+                                return index <= 2 ? <View className="tag-item" onClick={() => updateTag(index)}>
+                                    <Text style={{ color: ColorType.food }}>{item.label}</Text>
+                                </View> : <View />
 
-        <View style={{ flex: 1 }}>
-            {
-                <View className="tags">
-                    {detail.showDate && <Text className="food_timeline_item_day">{TimeFormatter.getMonthAndDayByDate(detail.start.date)}</Text>}
-                    {
-                        props.index == 0 && !detail.meal_tag && common.meal_tags.map((item, index) => {
-                            return index <= 2 ? <View className="tag-item" onClick={() => updateTag(index)}>
-                                <Text style={{ color: ColorType.food }}>{item.label}</Text>
-                            </View> : <View />
+                            })
+                        }
+                        {props.index == 0 && !detail.meal_tag && <View className="more_tag" onClick={() => { setShowTagModal(true) }}>更多标签</View>}
+                    </View>
+                }
 
-                        })
-                    }
-                    {props.index == 0 && !detail.meal_tag && <View className="more_tag" onClick={() => { setShowTagModal(true) }}>更多标签</View>}
+            </View>
+            <View className="thumb_bg">
+                <Image className="thumb" src={detail.media[0].url + '?x-oss-process=image/resize,w_300,limit_0'} mode="aspectFill" onClick={preview} />
+                <View className="food_desc" onClick={operateActionSheet}>
+                    <Text className="food_desc_text">{detail.meal_tag && detail.meal_tag.label}</Text>
+                    <Text className="food_desc_text">{detail.start && TimeFormatter.getTimeByTimestamp(detail.start.timestamp)}</Text>
+                    <Text className="food_desc_text">{detail.end.timestamp && '~' + TimeFormatter.getTimeByTimestamp(detail.end.timestamp)}</Text>
                 </View>
-            }
+            </View>
+            <View style={{ flex: 1 }}>
+                {
+                    props.index == 0 && <View className="food_share">
+                        <IconShare color={ColorType.food} width={20} height={17} />
+                        <Text className="food_share_text">分享</Text>
+                        <Button openType="share" className="food_share_btn" />
+                    </View>
+                }
+            </View>
+
 
         </View>
-        <View className="thumb_bg">
-            {/* <Image className="thumb" src={detail.cover.url} mode="aspectFill" onClick={preview} /> */}
-            <Image className="thumb" src={detail.media[0].url + '?x-oss-process=image/resize,w_300,limit_0'} mode="aspectFill" onClick={preview} />
-            <View className="food_desc" onClick={operateActionSheet}>
-                {/* <Text className="food_desc_text">{detail.start && TimeFormatter.getMonthAndDayByDate(detail.start.timestamp)}</Text> */}
-                <Text className="food_desc_text">{detail.meal_tag && detail.meal_tag.label}</Text>
-                <Text className="food_desc_text">{detail.start && TimeFormatter.getTimeByTimestamp(detail.start.timestamp)}</Text>
-                <Text className="food_desc_text">{detail.end.timestamp && '~' + TimeFormatter.getTimeByTimestamp(detail.end.timestamp)}</Text>
-                {/* {
-                    detail.end.timestamp && <Text>{'-' + getTime(detail.end.timestamp)}</Text>
-                } */}
+        {
+            detail.mindful_mode == 'AWARE' && !detail.feel.pre_meal && <View style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: rpxToPx(60) }}>
+                <Slider onChanged={(value) => {updateFeel(value,true) }} />
             </View>
-        </View>
-        {/* <Text className="food_item_date">{detail.start.date}</Text> */}
-        <View style={{ flex: 1 }}>
-            {
-                props.index == 0 && <View className="food_share">
-                    <IconShare color={ColorType.food} width={20} height={17} />
-                    <Text className="food_share_text">分享</Text>
-                    <Button openType="share" className="food_share_btn" />
-                </View>
-            }
-        </View>
+        }
         {
             showModal && <Modal dismiss={() => { setShowModal(false) }} confirm={() => { setShowModal(false) }}>
                 <View className='modal_content'>
@@ -399,6 +423,5 @@ export default function Component(props: {
                 />
             </Modal>
         }
-
     </View>
 }

+ 18 - 4
src/services/foodJournal.tsx

@@ -1,10 +1,24 @@
-import { API_FOOD, API_FOOD_TAGS } from './http/api';
+import { API_FOOD, API_FOOD_SCALE, API_FOOD_TAGS } from './http/api';
 import { request } from './http/request';
 
-export const getFoodTags = (params)=>{
+export const getFoodTags = (params) => {
     return new Promise((resolve, reject) => {
         request({
-            url: API_FOOD_TAGS, method: 'GET', data: {...params}
+            url: API_FOOD_TAGS, method: 'GET', data: { ...params }
+        }).then(res => {
+            resolve(res);
+            console.log(res);
+            // dispatch(loginSuccess(res));
+        }).catch(e => {
+            reject(e)
+        })
+    })
+}
+
+export const getFoodScales = (params) => {
+    return new Promise((resolve, reject) => {
+        request({
+            url: API_FOOD_SCALE, method: 'GET', data: {...params}
         }).then(res => {
             resolve(res);
             console.log(res);
@@ -42,7 +56,7 @@ export const createFoodJournal = (params) => {
     })
 }
 
-export const editFoodJournal = (params,id) => {
+export const editFoodJournal = (params, id) => {
     return new Promise((resolve, reject) => {
         request({
             url: API_FOOD + `/${id}`, method: 'POST', data: { ...params }

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

@@ -45,6 +45,7 @@ export const API_METRIC_FOLLOWS = `${baseUrl}/api/metric/follows`
 //food
 export const API_FOOD = `${baseUrl}/api/food/journals`
 export const API_FOOD_TAGS = `${baseUrl}/api/system/tags`
+export const API_FOOD_SCALE = `${baseUrl}/api/system/scales`
 
 //permissions
 export const API_WX_PUB_FOLLOWED = `${baseUrl}/api/fast/user/wx-pub-followed`

+ 6 - 1
src/store/common.tsx

@@ -3,6 +3,7 @@ import { createSlice } from "@reduxjs/toolkit";
 interface CommonState {
     resources: [] | null;
     meal_tags: [] | null;
+    food_scales: [] | null;
     configs: any | null;
     duration: {
         min: number;
@@ -16,6 +17,7 @@ interface CommonState {
 const initialState: CommonState = {
     resources: [],
     meal_tags: [],
+    food_scales: [],
     configs: null,
     duration: null,
     showTabbar: true,
@@ -33,6 +35,9 @@ const commonSlice = createSlice({
         setMealTags(state, action) {
             state.meal_tags = action.payload
         },
+        setFoodScales(state, action) {
+            state.food_scales = action.payload
+        },
         //是否disable并隐藏tabbar
         setTabbarStatus(state, action) {
             state.showTabbar = action.payload;
@@ -58,4 +63,4 @@ const commonSlice = createSlice({
 });
 
 export default commonSlice.reducer;
-export const { setResources, setMealTags, setConfigs, setTabbarStatus, changeTabbar } = commonSlice.actions;
+export const { setResources, setMealTags, setFoodScales, setConfigs, setTabbarStatus, changeTabbar } = commonSlice.actions;