leon 1 سال پیش
والد
کامیت
1db09633a4

+ 9 - 4
src/_health/components/target_progress.tsx

@@ -5,6 +5,7 @@ import { MainColorType } from '@/context/themes/color';
 import { durationArc, durationProgress, startArc, startDegree } from '@/utils/ring_utils';
 import { rpxToPx } from '@/utils/tools';
 import CircleRing from '@/components/basic/CircleRing';
+import { TimeFormatter } from '@/utils/time_format';
 
 export default function TargetProgress(props: {
     showLine?: boolean,
@@ -15,6 +16,7 @@ export default function TargetProgress(props: {
     showRing: boolean,
     icon?: any,
     desc?: string,
+    og?: boolean,
 
     //双环
     doubleRing?: boolean,
@@ -23,8 +25,8 @@ export default function TargetProgress(props: {
     onClick?: any
 }) {
 
-    function ring(){
-        return <CircleRing 
+    function ring() {
+        return <CircleRing
             size={26}
             thickness={4.5}
             color={props.color ?? MainColorType.fast}
@@ -59,7 +61,7 @@ export default function TargetProgress(props: {
     }
 
     function ring1() {
-        return <CircleRing 
+        return <CircleRing
             size={28}
             thickness={4}
             color={MainColorType.fast}
@@ -90,7 +92,7 @@ export default function TargetProgress(props: {
     }
 
     function ring2() {
-        return <CircleRing 
+        return <CircleRing
             size={14}
             thickness={4}
             color={MainColorType.sleep}
@@ -173,6 +175,9 @@ export default function TargetProgress(props: {
         {
             props.desc && <View className='history_item_duration h32'>{props.desc}</View>
         }
+        {
+            props.og && <View className='history_item_duration h32'>{TimeFormatter.formateTimeDifference(props.startTimestamp!,props.endTimerstamp!)}</View>
+        }
         {
             props.doubleRing && <View className='history_item_duration h32' style={{
                 display: 'flex',

+ 0 - 0
src/_moment/pages/home.config.ts


+ 0 - 0
src/_moment/pages/home.scss


+ 5 - 0
src/_moment/pages/home.tsx

@@ -0,0 +1,5 @@
+import { View } from "@tarojs/components";
+
+export default function UserHome(){
+    return <View></View>
+}

+ 0 - 0
src/_moment/pages/message.config.ts


+ 0 - 0
src/_moment/pages/message.scss


+ 5 - 0
src/_moment/pages/message.tsx

@@ -0,0 +1,5 @@
+import { View } from "@tarojs/components";
+
+export default function Message(){
+    return <View></View>
+}

+ 0 - 0
src/_moment/pages/relation.config.ts


+ 0 - 0
src/_moment/pages/relation.scss


+ 5 - 0
src/_moment/pages/relation.tsx

@@ -0,0 +1,5 @@
+import { View } from "@tarojs/components";
+
+export default function Relation(){
+    return <View></View>
+}

+ 8 - 0
src/app.config.ts

@@ -68,6 +68,14 @@ const appConfig = defineAppConfig({
         'pages/Album',
         'pages/PhotoWall',
       ]
+    },
+    {
+      root: '_moment',
+      pages: [
+        'pages/home',
+        'pages/message',
+        'pages/relation'
+      ]
     }
   ],
   usingComponents: {

+ 20 - 0
src/components/basic/ShareBtn.tsx

@@ -0,0 +1,20 @@
+import { Button, View } from "@tarojs/components";
+
+export default function ShareBtn(props: { children: any, onClick?: any }) {
+    return <View style={{ position: 'relative' }}>
+        {
+            props.children
+        }
+        <Button openType="share" style={{
+            position: 'absolute',
+            left: 0,
+            right: 0,
+            top: 0,
+            bottom: 0
+        }} onClick={() => {
+            if (props.onClick) {
+                props.onClick()
+            }
+        }} />
+    </View>
+}

+ 4 - 0
src/components/navigation/TabBar.tsx

@@ -11,6 +11,10 @@ export default function Component(props: { index: number }) {
     const common = useSelector((state: any) => state.common);
     const [selIndex] = useState(props.index)
     const { t } = useTranslation()
+
+    global.switchTab = (index)=>{
+        switchTab(index)
+    }
     function switchTab(index: number) {
         switch (index) {
             case 0:

+ 2 - 1
src/pages/clock/ClockNew.tsx

@@ -153,7 +153,7 @@ export default function ClockNew(props: { children: any, onScroll: any }) {
 
     useEffect(() => {
         setTimeout(() => {
-            if (userRef.current.isLogin) {
+            if (userRef.current.isLogin && !healthRef.current.finish_setup) {
                 checkVersionUpdate()
             }
         }, 1000)
@@ -308,6 +308,7 @@ export default function ClockNew(props: { children: any, onScroll: any }) {
         // }
 
 
+
         const showAlert1 = await getStorage('149alert') || false;
         Taro.setStorage({ key: '149alert', data: true })
 

+ 24 - 0
src/pages/friend/empty_content.scss

@@ -0,0 +1,24 @@
+.empty_content {
+    background-color: #fff;
+    height: 100vh;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    box-sizing: border-box;
+    padding-top: 196px;
+}
+
+.friends_avatars {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    margin-bottom: 36px;
+}
+
+.avatar_border {
+    width: 92px;
+    height: 92px;
+    border-radius: 46px;
+    border: solid 6px #fff;
+    box-sizing: border-box;
+}

+ 34 - 0
src/pages/friend/empty_content.tsx

@@ -0,0 +1,34 @@
+import NewButton, { NewButtonType } from "@/_health/base/new_button";
+import { MainColorType } from "@/context/themes/color";
+import { rpxToPx } from "@/utils/tools";
+import { View,Image } from "@tarojs/components";
+import './empty_content.scss'
+import { useSelector } from "react-redux";
+
+export default function EmptyContent(props: { friends: any }) {
+    const user = useSelector((state: any) => state.user);
+    function goHome() {
+        global.switchTab(0)
+    }
+    return <View className="empty_content">
+        <View className="friends_avatars">
+            <Image className="avatar_border" style={{zIndex:100}} mode="aspectFill" src={user.avatar}/>
+            {
+                props.friends.map((item,index)=>{
+                    return <Image className="avatar_border" mode="aspectFill" style={{zIndex:99-index,marginLeft:-rpxToPx(40)}} key={index} src={item.avatar}/>
+                })
+            }
+        </View>
+        <View className="h50 bold">你和搭子还没有</View>
+        <View className="h50 bold">记录过任何时刻哦</View>
+        <View className="h26 g02" style={{ marginBottom: rpxToPx(120), marginTop: rpxToPx(24) }}>打卡后,你们在搭子圈中可以看到彼此的动态</View>
+        <NewButton
+            title="前往首页记录"
+            type={NewButtonType.fill}
+            color={MainColorType.blue}
+            width={rpxToPx(400)}
+            height={rpxToPx(96)}
+            onClick={goHome}
+        />
+    </View>
+}

+ 10 - 0
src/pages/friend/friend.config.ts

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

+ 97 - 3
src/pages/friend/friend.tsx

@@ -6,7 +6,10 @@ import { View, Text, Image, ScrollView, Button } from "@tarojs/components";
 import Taro, { useRouter, useShareAppMessage } from "@tarojs/taro";
 import { useDispatch, useSelector } from "react-redux";
 import { useEffect, useState } from "react";
-import { followUser, getMyFriends } from "@/services/friend";
+import { followUser, getFriendDashBoard, getFriendMoments, getMyFriends, getUserHome } from "@/services/friend";
+import FriendGuide from "./guide";
+import EmptyContent from "./empty_content";
+import MomentItem from "./moment_item";
 
 let useRoute;
 let useNavigation;
@@ -15,7 +18,7 @@ if (process.env.TARO_ENV == 'rn') {
     useNavigation = require("@react-navigation/native").useNavigation
 }
 
-
+let timer;
 export default function Friend() {
     const user = useSelector((state: any) => state.user);
     const launchObj = Taro.getLaunchOptionsSync()
@@ -25,6 +28,9 @@ export default function Friend() {
     const [friends, setFriends] = useState<any>([])
     const [count, setCount] = useState(0)
 
+    const systemInfo: any = Taro.getWindowInfo ? Taro.getWindowInfo() : Taro.getSystemInfoSync();
+    const navigationBarHeight = systemInfo.statusBarHeight + 44;
+
     let router
     let navigation;
     if (useNavigation) {
@@ -38,7 +44,19 @@ export default function Friend() {
         router = useRouter()
     }
 
+    const [loaded, setLoaded] = useState(false)
+    const [homeType, setHomeType] = useState('NO_FRIEND')
+    const [dashBoard, setDashBoard] = useState<any>(null)
+    const [moments, setMoments] = useState<any>([])
 
+    useEffect(() => {
+        timer = setInterval(() => {
+            setCount(count => count + 1)
+        }, 1000)
+        return () => {
+            clearInterval(timer)
+        }
+    }, [])
 
 
     useEffect(() => {
@@ -62,7 +80,10 @@ export default function Friend() {
     }, [user.isLogin])
 
     function myFriends() {
-        if (!user.isLogin) return
+        if (!user.isLogin) {
+            setLoaded(true)
+            return
+        }
         getMyFriends({
             page: 1,
             limit: 10
@@ -71,6 +92,19 @@ export default function Friend() {
             setCount((res as any).total)
             setFriends((res as any).data)
         })
+
+        getFriendDashBoard().then(res => {
+            setLoaded(true)
+            setHomeType((res as any).homepage_type)
+            setDashBoard(res)
+        })
+
+        getFriendMoments({
+            page: 1,
+            limit: 50
+        }).then(res => {
+            setMoments((res as any).data)
+        })
     }
 
     function updateRelation(obj) {
@@ -120,6 +154,9 @@ export default function Friend() {
 
         useShareAppMessage((e) => {
             var sharePath = ``
+            if (global.shareData) {
+                console.log(global.shareData)
+            }
             console.log('share_url', '/pages/friend/friend?type=share&uid=' + user.id)
             return {
                 title: 'Friends ',
@@ -129,6 +166,63 @@ export default function Friend() {
         })
     }
 
+    function friendGuide() {
+        return <View>
+            <View style={{ height: navigationBarHeight, width: rpxToPx(750), backgroundColor: '#fff' }} />
+            <FriendGuide />
+            {
+                process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
+            }</View>
+    }
+
+    function empty() {
+        return <View>
+            <View style={{ height: navigationBarHeight, width: rpxToPx(750), backgroundColor: '#fff' }} />
+            <EmptyContent friends={dashBoard.friends} />
+            {
+                process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
+            }
+        </View>
+    }
+
+    function content() {
+        if (!loaded) {
+            return <View >
+                {
+                    process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
+                }
+            </View>
+        }
+        if (!user.isLogin) {
+            return friendGuide()
+        }
+        switch (homeType) {
+            case 'NO_FRIEND':
+                return friendGuide()
+            case 'NO_MOMENT':
+                return empty()
+
+        }
+        return <View >
+            <View style={{ height: navigationBarHeight, width: rpxToPx(750), backgroundColor: '#fff' }} />
+            <View style={{ backgroundColor: '#fff', minHeight: '100vh' }}>
+                {
+                    moments.map((item, index) => {
+                        return <View key={index}>
+                            <MomentItem data={item} />
+                        </View>
+                    })
+                }
+            </View>
+
+            {
+                process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
+            }
+        </View>
+    }
+
+    return content()
+
 
     return <View>
         <ScrollView scrollY style={{ height: '100vh' }}>

+ 43 - 0
src/pages/friend/guide.scss

@@ -0,0 +1,43 @@
+.friend_guide_content{
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    height: 100vh;
+    background-color: #fff;
+}
+
+.friend_share_btn_bg {
+    position: relative;
+    width: 400px;
+    height: 96px;
+}
+
+.friend_body{
+    height: 500px;
+}
+
+.friend_share_btn {
+    position: absolute;
+    left: 0;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    opacity: 0;
+}
+
+.share_btn_tip {
+    margin-top: 28px;
+}
+
+.avatar_bg{
+    width: 200px;
+    height: 200px;
+    border-radius: 100px;
+    margin-bottom: 24px;
+}
+
+.avatar{
+    width: 200px;
+    height: 200px;
+    border-radius: 100px;
+}

+ 51 - 0
src/pages/friend/guide.tsx

@@ -0,0 +1,51 @@
+import NewButton, { NewButtonType } from "@/_health/base/new_button";
+import { MainColorType } from "@/context/themes/color";
+import { rpxToPx } from "@/utils/tools";
+import { Button, View, Image } from "@tarojs/components";
+import './guide.scss'
+import { useSelector } from "react-redux";
+import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
+
+export default function FriendGuide() {
+    const user = useSelector((state: any) => state.user);
+
+    function goLogin() {
+        jumpPage('/_account/pages/ChooseAuth')
+    }
+
+    function tapAvatar() {
+        if (user.isLogin) {
+            jumpPage(`/_account/pages/ProfileSetting?newuser=${user.is_new_user?'1':'0'}`)
+        }
+        else {
+            goLogin()
+        }
+    }
+    return <View className="friend_guide_content">
+        <View className="avatar_bg" onClick={tapAvatar}>
+            {
+                user.isLogin ? <Image className='avatar gray_bg' src={user.avatar} mode="aspectFill"/> : <View className="avatar gray_bg" />
+            }
+        </View>
+
+        <View className="h50 bold">和搭子们</View>
+        <View className="h50 bold">分享彼此的日常生活</View>
+        <View className="friend_body" />
+        <View className="friend_share_btn_bg">
+            <NewButton
+                onClick={goLogin}
+                title="立即邀请搭子"
+                type={NewButtonType.fill}
+                color={MainColorType.blue}
+                width={rpxToPx(400)}
+                height={rpxToPx(96)}
+            />
+            {
+                user.isLogin && <Button openType="share" className="friend_share_btn" />
+            }
+
+        </View>
+
+        <View className="share_btn_tip h26 g02">搭子加入时,搭子圈立即解锁</View>
+    </View>
+}

+ 21 - 0
src/pages/friend/moment_item.scss

@@ -0,0 +1,21 @@
+.moment_item {
+    display: flex;
+    flex-direction: row;
+    padding-bottom: 60px;
+    padding-left: 60px;
+    padding-right: 60px;
+}
+
+.moment_avatar {
+    width: 74px;
+    height: 74px;
+    border-radius: 37px;
+    margin-right: 24px;
+    flex-shrink: 0;
+}
+
+.moment_detail{
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+}

+ 85 - 0
src/pages/friend/moment_item.tsx

@@ -0,0 +1,85 @@
+import { View, Image, Button } from "@tarojs/components";
+import './moment_item.scss'
+import { MainColorType } from "@/context/themes/color";
+import TimeTitleDesc from "@/_health/components/time_title_desc";
+import dayjs from 'dayjs';
+import relativeTime from 'dayjs/plugin/relativeTime';
+import isToday from 'dayjs/plugin/isToday';
+import isTomorrow from 'dayjs/plugin/isTomorrow'
+import isYesterday from 'dayjs/plugin/isYesterday'
+import TargetProgress from "@/_health/components/target_progress";
+import { rpxToPx } from "@/utils/tools";
+import { getThemeColor } from "@/features/health/hooks/health_hooks";
+import CoverList from "@/_health/components/cover_list";
+import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
+
+dayjs.extend(relativeTime);
+dayjs.extend(isToday);
+dayjs.extend(isTomorrow);
+dayjs.extend(isYesterday);
+
+
+export default function MomentItem(props: { data: any }) {
+    const { link, moment, user } = props.data
+
+    const formatTime = (timestamp) => {
+        const now = dayjs();
+        const time = dayjs(timestamp);
+
+        if (time.isToday()) {
+            return time.format('HH:mm'); // 今天的时间
+        }
+
+        const diffInMinutes = now.diff(time, 'minute');
+
+        if (diffInMinutes < 60) {
+            return `${diffInMinutes} min ago`; // xx分钟之前
+        } else {
+            return time.format('YYYY-MM-DD'); // 显示完整日期
+        }
+    };
+
+    const formatImages = (list) => {
+        return list.map(obj => obj.url);
+    }
+
+    function goProfile(){
+        jumpPage(`/_moment/pages/home?uid=${user.id}`)
+    }
+
+    function goDetail(){
+        jumpPage(`/_health/pages/timeline_detail?disable_edit=1&window_id=${link.window_id}`)
+    }
+
+    return <View className="moment_item">
+        <Image className="moment_avatar" src={user.avatar} mode="aspectFill" onClick={goProfile}/>
+        <View className="moment_detail" onClick={goDetail}>
+            <View className="h34 bold" style={{ color: MainColorType.link, marginBottom: rpxToPx(6) }}>{user.nickname}</View>
+            {
+                (moment.title || moment.description) && <TimeTitleDesc time="" title={moment.title} desc={moment.description} />
+            }
+            <View style={{ height: rpxToPx(12) }} />
+            {
+                moment.media.length > 0 && <CoverList imgs={formatImages(moment.media)} count={moment.media.length} />
+            }
+            {
+                link && <View style={{ marginTop: rpxToPx(24) }}>
+                    <TargetProgress
+                        color={getThemeColor(link.window)}
+                        showRing={true}
+                        desc={link.ring.description}
+                        og={link.status == 'OG'}
+                        startTimestamp={link.ring.start_timestamp}
+                        endTimerstamp={link.ring.end_timestamp ?? new Date().getTime()}
+                    />
+                </View>
+            }
+            <View style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', marginTop: rpxToPx(24) }}>
+                <View className="h26 g02">{formatTime(moment.timestamp)}</View>
+                <View style={{ position: 'relative' }}>
+                    <Button className="item_share" openType="share" onClick={() => { global.shareData = '9527'; console.log('sgareeeeeee') }}></Button>
+                </View>
+            </View>
+        </View>
+    </View>
+}

+ 40 - 1
src/services/friend.tsx

@@ -1,4 +1,4 @@
-import { API_FOLLOW_USER, API_MY_FRIENDS } from "./http/api";
+import { API_FOLLOW_USER, API_FRIEND_DASHBOARD, API_FRIEND_MOMENTS, API_MY_FRIENDS, API_USER_HOME } from "./http/api";
 import { request } from "./http/request";
 
 export const followUser = (id,params) => {
@@ -27,3 +27,42 @@ export const getMyFriends = (params) => {
     })
 }
 
+export const getFriendDashBoard = ()=>{
+    return new Promise((resolve, reject) => {
+        request({
+            url: API_FRIEND_DASHBOARD, method: 'GET', data: {}
+        }).then(res => {
+            resolve(res);
+            // dispatch(loginSuccess(res));
+        }).catch(e => {
+            reject(e)
+        })
+    })
+}
+
+export const getUserHome = ()=>{
+    return new Promise((resolve, reject) => {
+        request({
+            url: API_USER_HOME, method: 'GET', data: {}
+        }).then(res => {
+            resolve(res);
+            // dispatch(loginSuccess(res));
+        }).catch(e => {
+            reject(e)
+        })
+    })
+}
+
+export const getFriendMoments = (params)=>{
+    return new Promise((resolve, reject) => {
+        request({
+            url: API_FRIEND_MOMENTS, method: 'GET', data: {...params}
+        }).then(res => {
+            resolve(res);
+            // dispatch(loginSuccess(res));
+        }).catch(e => {
+            reject(e)
+        })
+    })
+}
+

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

@@ -123,4 +123,7 @@ export const API_RESET_TESTINFO = `${baseUrl}/api/user/test-resets`
 
 //friend
 export const API_FOLLOW_USER = `${baseUrl}/api/users`
-export const API_MY_FRIENDS = `${baseUrl}/api/user/friends`
+export const API_MY_FRIENDS = `${baseUrl}/api/user/friends`
+export const API_FRIEND_DASHBOARD = `${baseUrl}/api/user/friend/dashboard`
+export const API_USER_HOME = `${baseUrl}/api/user/home`
+export const API_FRIEND_MOMENTS = `${baseUrl}/api/user/friend-moments`