leon vor 1 Jahr
Ursprung
Commit
5862997005

+ 7 - 0
src/_health/pages/timeline_detail.tsx

@@ -739,10 +739,17 @@ export default function TimelineDetail() {
             return getThemeColor(detail.events[0].window)
         }
     }
+
+    function goHome(){
+        // jumpPage('/_moment/pages/message')
+        // jumpPage('/_moment/pages/home?uid='+(shareUser ? shareUser.id:detail.share_user ? detail.share_user.id : user.id))
+    }
+
     return <View style={{ display: 'flex', flex: 1, flexDirection: 'column', backgroundColor: '#fff', height: '101vh' }}>
         {
             !showEmpty && <View className="detail_header">
                 <Image className="detail_header_header"
+                onClick={goHome}
                     src={shareUser ? shareUser.avatar : detail.share_user ? detail.share_user.avatar : user.avatar}
                     mode="aspectFill"
                 />

+ 10 - 0
src/_moment/pages/home.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",
+})

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

@@ -0,0 +1,26 @@
+.home_top{
+    position: relative;
+}
+
+.cover{
+    width: 750px;
+    height: 680px;
+    background-color: #f0f0f0;
+}
+
+.home_avatar{
+    position: absolute;
+    width: 126px;
+    height: 126px;
+    border-radius: 63px;
+    right: 40px;
+    bottom: -20px;
+    background-color: pink;
+}
+
+.home_nickname{
+    position: absolute;
+    color: #000;
+    right: 186px;
+    bottom: 20px;
+}

+ 118 - 3
src/_moment/pages/home.tsx

@@ -1,5 +1,120 @@
-import { View } from "@tarojs/components";
+import { View, Text, Image } from "@tarojs/components";
+import './home.scss'
+import Taro, { useRouter } from "@tarojs/taro";
+import { useEffect, useState } from "react";
+import { followUser, getUserProfile, unfollowUser } from "@/services/friend";
+import { useSelector } from "react-redux";
+import NewButton, { NewButtonType } from "@/_health/base/new_button";
+import { rpxToPx } from "@/utils/tools";
+import { MainColorType } from "@/context/themes/color";
+import showActionSheet from "@/components/basic/ActionSheet";
 
-export default function UserHome(){
-    return <View></View>
+let useRoute;
+let useNavigation;
+let scenario = '';
+if (process.env.TARO_ENV == 'rn') {
+    useRoute = require("@react-navigation/native").useRoute
+    useNavigation = require("@react-navigation/native").useNavigation
+}
+
+export default function UserHome() {
+    const user = useSelector((state: any) => state.user);
+    const [profile, setProfile] = useState<any>(null)
+    const [loaded, setLoaded] = useState(false)
+    const systemInfo: any = Taro.getWindowInfo ? Taro.getWindowInfo() : Taro.getSystemInfoSync();
+    const navigationBarHeight = systemInfo.statusBarHeight + 44;
+
+
+    let router
+    let navigation;
+    if (useNavigation) {
+        navigation = useNavigation()
+    }
+
+    if (process.env.TARO_ENV == 'rn') {
+        router = useRoute()
+    }
+    else {
+        router = useRouter()
+    }
+
+    useEffect(() => {
+        getProfile()
+    }, [])
+
+    function getProfile() {
+        getUserProfile({ user_id: router.params.uid }).then(res => {
+            setProfile(res)
+            setLoaded(true)
+        })
+    }
+
+    function tapFollow() {
+        var params: any = {
+            follow_origin: 'WECHAT_PRIVATE_CHAT',
+            user_id: router.params.uid,
+        }
+        followUser(params).then(res => {
+            getProfile()
+            Taro.eventCenter.trigger('followUser', router.params.uid)
+        })
+    }
+
+    function tapFollowing() {
+        showActionSheet({
+            title: `不再关注“${profile.nickname}”,他的动态将不出现在搭子圈`,
+            itemList: ['不再关注'],
+            success: (res) => {
+                if (res == 0) {
+                    unfollowUser(profile.id).then(res => {
+                        Taro.eventCenter.trigger('unfollowUser', router.params.uid)
+                        getProfile()
+                    })
+                }
+            }
+        })
+    }
+
+    if (!loaded) return <View />
+
+    return <View>
+        <View className="home_top">
+            <View className="cover" />
+            <Image className="home_avatar" src={profile.avatar} />
+            <View className="home_nickname">{profile.nickname}</View>
+            <View style={{
+                position: 'absolute',
+                top:0,
+                left: 0,
+                zIndex: 10,
+                height: navigationBarHeight, width: rpxToPx(750), backgroundColor: 'transparent', display: 'flex',
+                flexDirection: 'column', justifyContent: 'flex-end'
+            }}>
+                <View style={{ height: 44, width: rpxToPx(750), position: 'relative', display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
+                    <View onClick={()=>{
+                        Taro.navigateBack()
+                    }} style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 80, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>Back</View>
+                </View>
+            </View>
+        </View>
+        {
+            router.params.uid != user.id && <View style={{ marginTop: rpxToPx(62), marginLeft: rpxToPx(45) }}>
+                {
+                    profile.relation == 'FRIEND' || profile.relation == 'FOLLOWING' ? <NewButton type={NewButtonType.fill}
+                        width={rpxToPx(665)}
+                        height={rpxToPx(72)}
+                        title="following"
+                        color={MainColorType.g02}
+                        onClick={tapFollowing}
+                    /> : <NewButton type={NewButtonType.fill}
+                        width={rpxToPx(665)}
+                        height={rpxToPx(72)}
+                        title="follow"
+                        color={MainColorType.blue}
+                        onClick={tapFollow}
+                    />
+                }
+            </View>
+        }
+    </View>
 }

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

@@ -0,0 +1,85 @@
+.grid-wrapper {
+    width: 100%;
+    position: relative;
+    background-color: #f5f5f5;
+  }
+  
+  .grid-container {
+    width: 100%;
+    height: 100%;
+    position: relative;
+    overflow: hidden;
+  }
+  
+  .grid-item {
+    width: 33.33%;
+    height: 33.33vw;
+    position: absolute;
+    will-change: transform;
+    
+    &.active {
+      z-index: 100;
+      
+      .grid-image {
+        transform: scale(1.05);
+        opacity: 0.8;
+      }
+    }
+  }
+  
+  .grid-image {
+    width: 100%;
+    height: 100%;
+    padding: 4px;
+    box-sizing: border-box;
+    transition: all 0.2s ease;
+  }
+  
+  .delete-btn {
+    position: absolute;
+    right: 4px;
+    top: 4px;
+    width: 20px;
+    height: 20px;
+    background-color: rgba(0, 0, 0, 0.5);
+    border-radius: 50%;
+    z-index: 1;
+    
+    &::before,
+    &::after {
+      content: '';
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      width: 12px;
+      height: 2px;
+      background-color: #fff;
+      transform: translate(-50%, -50%) rotate(45deg);
+    }
+    
+    &::after {
+      transform: translate(-50%, -50%) rotate(-45deg);
+    }
+  }
+  
+  .upload-item {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background-color: #fff;
+    border: 1px dashed #ddd;
+    box-sizing: border-box;
+    position: absolute;
+    margin: 4px;
+    width: calc(33.33% - 8px);
+    height: calc(33.33vw - 8px);
+    will-change: transform;
+  }
+  
+  .upload-icon {
+    font-size: 32px;
+    color: #999;
+    font-weight: lighter;
+  }
+  
+  

+ 259 - 0
src/_moment/pages/message copy.tsx

@@ -0,0 +1,259 @@
+import { useState, useRef, useEffect } from 'react'
+import { View, MovableArea, MovableView, Image } from '@tarojs/components'
+import { createSelectorQuery, chooseImage, showToast } from '@tarojs/taro'
+import './message.scss'
+
+interface ImageItem {
+  id: string
+  url: string
+}
+
+interface Position {
+  x: number
+  y: number
+}
+
+interface Props {
+  maxCount?: number
+  value?: ImageItem[]
+  onChange?: (images: ImageItem[]) => void
+}
+
+export default function SortableGrid({ 
+  maxCount = 9,
+  value = [],
+  onChange
+}: Props) {
+  const [images, setImages] = useState<ImageItem[]>(value)
+  const [currentItem, setCurrentItem] = useState<ImageItem | null>(null)
+  const [positions, setPositions] = useState<{[key: string]: Position}>({})
+  const [itemSize, setItemSize] = useState({ width: 0, height: 0 })
+  const [isDragging, setIsDragging] = useState(false)
+  const [draggedIndex, setDraggedIndex] = useState<number>(-1)
+  const [targetIndex, setTargetIndex] = useState<number>(-1)
+  const gridRef = useRef<any>(null)
+
+  // 更新图片列表
+  const updateImages = (newImages: ImageItem[]) => {
+    setImages(newImages)
+    onChange?.(newImages)
+  }
+
+  // 处理图片上传
+  const handleUpload = async () => {
+    if (images.length >= maxCount) {
+      showToast({
+        title: `最多只能上传${maxCount}张图片`,
+        icon: 'none'
+      })
+      return
+    }
+
+    try {
+      const res = await chooseImage({
+        count: maxCount - images.length,
+        sizeType: ['compressed'],
+        sourceType: ['album', 'camera']
+      })
+
+      const newImages = [
+        ...images,
+        ...res.tempFilePaths.map((url, index) => ({
+          id: Date.now() + index + '',
+          url
+        }))
+      ]
+
+      updateImages(newImages)
+    } catch (error) {
+      console.error('选择图片失败:', error)
+    }
+  }
+
+  // 删除图片
+  const handleDelete = (item: ImageItem) => {
+    const newImages = images.filter(img => img.id !== item.id)
+    updateImages(newImages)
+  }
+
+  // 计算网格项尺寸和位置
+  const calculateLayout = () => {
+    return new Promise<void>((resolve) => {
+      const query = createSelectorQuery()
+      query.select('.grid-container').boundingClientRect((rect: any) => {
+        if (rect) {
+          const width = rect.width / 3
+          setItemSize({ width, height: width })
+          
+          const newPositions: {[key: string]: Position} = {}
+          const totalItems = images.length + (images.length < maxCount ? 1 : 0)
+          
+          for (let i = 0; i < totalItems; i++) {
+            const row = Math.floor(i / 3)
+            const col = i % 3
+            newPositions[i] = {
+              x: col * width,
+              y: row * width
+            }
+          }
+          
+          setPositions(newPositions)
+          resolve()
+        }
+      }).exec()
+    })
+  }
+
+  // 获取目标索引
+  const getTargetIndex = (x: number, y: number): number => {
+    if (!itemSize.width) return -1
+    
+    const col = Math.floor((x + itemSize.width / 2) / itemSize.width)
+    const row = Math.floor((y + itemSize.height / 2) / itemSize.height)
+    
+    if (col < 0 || col >= 3 || row < 0) return -1
+    const index = row * 3 + col
+    return index >= images.length ? -1 : index
+  }
+
+  // 长按开始拖动
+  const handleLongPress = (index: number) => {
+    setIsDragging(true)
+    setDraggedIndex(index)
+    setCurrentItem(images[index])
+  }
+
+  // 拖动中
+  const handleMove = (e: any) => {
+    if (!isDragging || draggedIndex === -1) return
+
+    const { x, y } = e.detail
+    const newTargetIndex = getTargetIndex(x, y)
+    
+    if (newTargetIndex !== -1 && newTargetIndex !== draggedIndex && newTargetIndex < images.length) {
+      setTargetIndex(newTargetIndex)
+    } else {
+      setTargetIndex(-1)
+    }
+  }
+
+  // 拖动结束
+  const handleTouchEnd = () => {
+    if (isDragging && targetIndex !== -1 && draggedIndex !== -1) {
+      const newImages = [...images]
+      const [draggedItem] = newImages.splice(draggedIndex, 1)
+      newImages.splice(targetIndex, 0, draggedItem)
+      updateImages(newImages)
+    }
+    
+    setIsDragging(false)
+    setDraggedIndex(-1)
+    setTargetIndex(-1)
+    setCurrentItem(null)
+  }
+
+  // 获取元素样式
+  const getItemStyle = (index: number) => {
+    if (!positions[index]) return {}
+    
+    const baseStyle = {
+      transform: `translate3d(${positions[index].x}px, ${positions[index].y}px, 0)`,
+      transition: isDragging ? 'transform 0.3s ease' : 'transform 0.3s ease'
+    }
+
+    if (index === draggedIndex) {
+      return {
+        ...baseStyle,
+        transition: 'none',
+        zIndex: 100
+      }
+    }
+
+    if (targetIndex !== -1) {
+      if (index === targetIndex) {
+        const targetPos = positions[draggedIndex]
+        return {
+          ...baseStyle,
+          transform: `translate3d(${targetPos.x}px, ${targetPos.y}px, 0)`
+        }
+      }
+      
+      if (index > targetIndex && index <= draggedIndex) {
+        const nextPos = positions[index - 1]
+        return {
+          ...baseStyle,
+          transform: `translate3d(${nextPos.x}px, ${nextPos.y}px, 0)`
+        }
+      }
+      
+      if (index < targetIndex && index >= draggedIndex) {
+        const prevPos = positions[index + 1]
+        return {
+          ...baseStyle,
+          transform: `translate3d(${prevPos.x}px, ${prevPos.y}px, 0)`
+        }
+      }
+    }
+
+    return baseStyle
+  }
+
+  // 计算容器高度
+  const getContainerHeight = () => {
+    const totalItems = images.length + (images.length < maxCount ? 1 : 0)
+    const rows = Math.ceil(totalItems / 3)
+    return `${rows * 33.33}vw`
+  }
+
+  useEffect(() => {
+    calculateLayout()
+  }, [images.length])
+
+  return (
+    <View className="grid-wrapper" style={{ height: getContainerHeight() }}>
+      <MovableArea className="grid-container" ref={gridRef}>
+        {images.map((item, index) => (
+          <MovableView
+            key={item.id}
+            className={`grid-item ${draggedIndex === index ? 'active' : ''}`}
+            direction="all"
+            x={positions[index]?.x || 0}
+            y={positions[index]?.y || 0}
+            onLongPress={() => handleLongPress(index)}
+            onChange={handleMove}
+            onTouchEnd={handleTouchEnd}
+            damping={50}
+            friction={2}
+          >
+            <Image
+              className="grid-image"
+              src={item.url}
+              mode="aspectFill"
+            />
+            <View 
+              className="delete-btn"
+              onClick={(e) => {
+                e.stopPropagation()
+                handleDelete(item)
+              }}
+            />
+          </MovableView>
+        ))}
+        
+        {images.length < maxCount && (
+          <View 
+            className="grid-item upload-item" 
+            onClick={handleUpload}
+            style={{
+              transform: `translate3d(${positions[images.length]?.x}px, ${positions[images.length]?.y}px, 0)`,
+              transition: 'transform 0.3s ease'
+            }}
+          >
+            <View className="upload-icon">+</View>
+          </View>
+        )}
+      </MovableArea>
+    </View>
+  )
+}
+

+ 17 - 85
src/_moment/pages/message.scss

@@ -1,85 +1,17 @@
-.grid-wrapper {
-    width: 100%;
-    position: relative;
-    background-color: #f5f5f5;
-  }
-  
-  .grid-container {
-    width: 100%;
-    height: 100%;
-    position: relative;
-    overflow: hidden;
-  }
-  
-  .grid-item {
-    width: 33.33%;
-    height: 33.33vw;
-    position: absolute;
-    will-change: transform;
-    
-    &.active {
-      z-index: 100;
-      
-      .grid-image {
-        transform: scale(1.05);
-        opacity: 0.8;
-      }
-    }
-  }
-  
-  .grid-image {
-    width: 100%;
-    height: 100%;
-    padding: 4px;
-    box-sizing: border-box;
-    transition: all 0.2s ease;
-  }
-  
-  .delete-btn {
-    position: absolute;
-    right: 4px;
-    top: 4px;
-    width: 20px;
-    height: 20px;
-    background-color: rgba(0, 0, 0, 0.5);
-    border-radius: 50%;
-    z-index: 1;
-    
-    &::before,
-    &::after {
-      content: '';
-      position: absolute;
-      top: 50%;
-      left: 50%;
-      width: 12px;
-      height: 2px;
-      background-color: #fff;
-      transform: translate(-50%, -50%) rotate(45deg);
-    }
-    
-    &::after {
-      transform: translate(-50%, -50%) rotate(-45deg);
-    }
-  }
-  
-  .upload-item {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    background-color: #fff;
-    border: 1px dashed #ddd;
-    box-sizing: border-box;
-    position: absolute;
-    margin: 4px;
-    width: calc(33.33% - 8px);
-    height: calc(33.33vw - 8px);
-    will-change: transform;
-  }
-  
-  .upload-icon {
-    font-size: 32px;
-    color: #999;
-    font-weight: lighter;
-  }
-  
-  
+.message_item{
+  height: 138px;
+  width: 750px;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  box-sizing: border-box;
+  padding: 0 40px;
+}
+
+.message_item_avatar{
+  width: 86px;
+  height: 86px;
+  border-radius: 43px;
+  margin-right: 24px;
+  flex-shrink: 0;
+}

+ 70 - 237
src/_moment/pages/message.tsx

@@ -1,259 +1,92 @@
 import { useState, useRef, useEffect } from 'react'
-import { View, MovableArea, MovableView, Image } from '@tarojs/components'
+import { View, MovableArea, MovableView, Image, Text } from '@tarojs/components'
 import { createSelectorQuery, chooseImage, showToast } from '@tarojs/taro'
 import './message.scss'
+import { followUser, getMessages } from '@/services/friend'
+import { MainColorType } from '@/context/themes/color'
+import { jumpPage } from '@/features/trackTimeDuration/hooks/Common'
+import dayjs from 'dayjs'
+import { rpxToPx } from '@/utils/tools'
+import NewButton, { NewButtonType } from '@/_health/base/new_button'
+import Taro from '@tarojs/taro'
 
-interface ImageItem {
-  id: string
-  url: string
-}
-
-interface Position {
-  x: number
-  y: number
-}
-
-interface Props {
-  maxCount?: number
-  value?: ImageItem[]
-  onChange?: (images: ImageItem[]) => void
-}
-
-export default function SortableGrid({ 
-  maxCount = 9,
-  value = [],
-  onChange
-}: Props) {
-  const [images, setImages] = useState<ImageItem[]>(value)
-  const [currentItem, setCurrentItem] = useState<ImageItem | null>(null)
-  const [positions, setPositions] = useState<{[key: string]: Position}>({})
-  const [itemSize, setItemSize] = useState({ width: 0, height: 0 })
-  const [isDragging, setIsDragging] = useState(false)
-  const [draggedIndex, setDraggedIndex] = useState<number>(-1)
-  const [targetIndex, setTargetIndex] = useState<number>(-1)
-  const gridRef = useRef<any>(null)
-
-  // 更新图片列表
-  const updateImages = (newImages: ImageItem[]) => {
-    setImages(newImages)
-    onChange?.(newImages)
-  }
-
-  // 处理图片上传
-  const handleUpload = async () => {
-    if (images.length >= maxCount) {
-      showToast({
-        title: `最多只能上传${maxCount}张图片`,
-        icon: 'none'
-      })
-      return
-    }
 
-    try {
-      const res = await chooseImage({
-        count: maxCount - images.length,
-        sizeType: ['compressed'],
-        sourceType: ['album', 'camera']
-      })
+export default function Message() {
+  const [list, setList] = useState<any>([])
+  useEffect(() => {
+    Taro.setNavigationBarTitle({
+      title: '消息'
+    })
+    getMessageData()
 
-      const newImages = [
-        ...images,
-        ...res.tempFilePaths.map((url, index) => ({
-          id: Date.now() + index + '',
-          url
-        }))
-      ]
+    Taro.eventCenter.on('followUser', listenFollowUser)
+    Taro.eventCenter.on('unfollowUser', listenUnfollowUser)
+  }, [])
 
-      updateImages(newImages)
-    } catch (error) {
-      console.error('选择图片失败:', error)
-    }
+  function listenFollowUser(e) {
+    getMessageData()
   }
 
-  // 删除图片
-  const handleDelete = (item: ImageItem) => {
-    const newImages = images.filter(img => img.id !== item.id)
-    updateImages(newImages)
+  function listenUnfollowUser(e) {
+    getMessageData()
   }
 
-  // 计算网格项尺寸和位置
-  const calculateLayout = () => {
-    return new Promise<void>((resolve) => {
-      const query = createSelectorQuery()
-      query.select('.grid-container').boundingClientRect((rect: any) => {
-        if (rect) {
-          const width = rect.width / 3
-          setItemSize({ width, height: width })
-          
-          const newPositions: {[key: string]: Position} = {}
-          const totalItems = images.length + (images.length < maxCount ? 1 : 0)
-          
-          for (let i = 0; i < totalItems; i++) {
-            const row = Math.floor(i / 3)
-            const col = i % 3
-            newPositions[i] = {
-              x: col * width,
-              y: row * width
-            }
-          }
-          
-          setPositions(newPositions)
-          resolve()
-        }
-      }).exec()
+  function getMessageData() {
+    getMessages({ page: 1, limit: 20 }).then(res => {
+      setList((res as any).data)
     })
   }
 
-  // 获取目标索引
-  const getTargetIndex = (x: number, y: number): number => {
-    if (!itemSize.width) return -1
-    
-    const col = Math.floor((x + itemSize.width / 2) / itemSize.width)
-    const row = Math.floor((y + itemSize.height / 2) / itemSize.height)
-    
-    if (col < 0 || col >= 3 || row < 0) return -1
-    const index = row * 3 + col
-    return index >= images.length ? -1 : index
-  }
-
-  // 长按开始拖动
-  const handleLongPress = (index: number) => {
-    setIsDragging(true)
-    setDraggedIndex(index)
-    setCurrentItem(images[index])
-  }
-
-  // 拖动中
-  const handleMove = (e: any) => {
-    if (!isDragging || draggedIndex === -1) return
-
-    const { x, y } = e.detail
-    const newTargetIndex = getTargetIndex(x, y)
-    
-    if (newTargetIndex !== -1 && newTargetIndex !== draggedIndex && newTargetIndex < images.length) {
-      setTargetIndex(newTargetIndex)
-    } else {
-      setTargetIndex(-1)
+  function tapFollow(item) {
+    var params: any = {
+      follow_origin: 'WECHAT_PRIVATE_CHAT',
+      user_id: item.user.id,
     }
+    followUser(params).then(res => {
+      item.relation = 'FRIEND'
+      setList(JSON.parse(JSON.stringify(list)))
+      Taro.eventCenter.trigger('followUser', item.user.id)
+    })
   }
 
-  // 拖动结束
-  const handleTouchEnd = () => {
-    if (isDragging && targetIndex !== -1 && draggedIndex !== -1) {
-      const newImages = [...images]
-      const [draggedItem] = newImages.splice(draggedIndex, 1)
-      newImages.splice(targetIndex, 0, draggedItem)
-      updateImages(newImages)
-    }
-    
-    setIsDragging(false)
-    setDraggedIndex(-1)
-    setTargetIndex(-1)
-    setCurrentItem(null)
-  }
-
-  // 获取元素样式
-  const getItemStyle = (index: number) => {
-    if (!positions[index]) return {}
-    
-    const baseStyle = {
-      transform: `translate3d(${positions[index].x}px, ${positions[index].y}px, 0)`,
-      transition: isDragging ? 'transform 0.3s ease' : 'transform 0.3s ease'
-    }
-
-    if (index === draggedIndex) {
-      return {
-        ...baseStyle,
-        transition: 'none',
-        zIndex: 100
-      }
-    }
-
-    if (targetIndex !== -1) {
-      if (index === targetIndex) {
-        const targetPos = positions[draggedIndex]
-        return {
-          ...baseStyle,
-          transform: `translate3d(${targetPos.x}px, ${targetPos.y}px, 0)`
-        }
-      }
-      
-      if (index > targetIndex && index <= draggedIndex) {
-        const nextPos = positions[index - 1]
-        return {
-          ...baseStyle,
-          transform: `translate3d(${nextPos.x}px, ${nextPos.y}px, 0)`
-        }
-      }
-      
-      if (index < targetIndex && index >= draggedIndex) {
-        const prevPos = positions[index + 1]
-        return {
-          ...baseStyle,
-          transform: `translate3d(${prevPos.x}px, ${prevPos.y}px, 0)`
-        }
+  function messageItem(item, index) {
+    return <View key={index} className='message_item' >
+      <Image className='message_item_avatar' src={item.user.avatar} />
+      <View style={{ display: 'flex', flexDirection: 'column', flex: 1 }}>
+        <Text className='h28 g02'>
+          <Text onClick={() => {
+            jumpPage('./home?uid=' + item.user.id)
+          }} className='h28 bold link' style={{ color: MainColorType.link }}>{item.user.nickname} </Text>
+          关注了我
+        </Text>
+        <Text className='h22 g02' style={{ marginTop: rpxToPx(12) }}>{dayjs(item.timestamp).format('MM-DD HH:mm')}</Text>
+
+      </View>
+      {
+        item.relation == 'FOLLOWER' || item.relation == 'NA' ? <NewButton
+          type={NewButtonType.fill}
+          height={rpxToPx(72)}
+          color={MainColorType.blue}
+          title='Follow back'
+          onClick={() => tapFollow(item)}
+        /> :
+          <NewButton
+            type={NewButtonType.fill}
+            height={rpxToPx(72)}
+            color={MainColorType.g02}
+            title='Following'
+            onClick={() => { }}
+          />
       }
-    }
-
-    return baseStyle
-  }
-
-  // 计算容器高度
-  const getContainerHeight = () => {
-    const totalItems = images.length + (images.length < maxCount ? 1 : 0)
-    const rows = Math.ceil(totalItems / 3)
-    return `${rows * 33.33}vw`
+    </View>
   }
 
-  useEffect(() => {
-    calculateLayout()
-  }, [images.length])
-
-  return (
-    <View className="grid-wrapper" style={{ height: getContainerHeight() }}>
-      <MovableArea className="grid-container" ref={gridRef}>
-        {images.map((item, index) => (
-          <MovableView
-            key={item.id}
-            className={`grid-item ${draggedIndex === index ? 'active' : ''}`}
-            direction="all"
-            x={positions[index]?.x || 0}
-            y={positions[index]?.y || 0}
-            onLongPress={() => handleLongPress(index)}
-            onChange={handleMove}
-            onTouchEnd={handleTouchEnd}
-            damping={50}
-            friction={2}
-          >
-            <Image
-              className="grid-image"
-              src={item.url}
-              mode="aspectFill"
-            />
-            <View 
-              className="delete-btn"
-              onClick={(e) => {
-                e.stopPropagation()
-                handleDelete(item)
-              }}
-            />
-          </MovableView>
-        ))}
-        
-        {images.length < maxCount && (
-          <View 
-            className="grid-item upload-item" 
-            onClick={handleUpload}
-            style={{
-              transform: `translate3d(${positions[images.length]?.x}px, ${positions[images.length]?.y}px, 0)`,
-              transition: 'transform 0.3s ease'
-            }}
-          >
-            <View className="upload-icon">+</View>
-          </View>
-        )}
-      </MovableArea>
-    </View>
-  )
+  return <View style={{ minHeight: '100vh', backgroundColor: '#fff' }}>
+    {
+      list.map((item, index) => {
+        return messageItem(item, index)
+      })
+    }
+  </View>
 }
 

+ 42 - 7
src/_moment/pages/relation.tsx

@@ -1,5 +1,5 @@
 import { MainColorType } from "@/context/themes/color";
-import { getMyFollowers, getMyFollowings, getMyFriends } from "@/services/friend";
+import { followUser, getMyFollowers, getMyFollowings, getMyFriends } from "@/services/friend";
 import { View, Image, Text } from "@tarojs/components";
 import { useEffect, useState } from "react";
 import './relation.scss'
@@ -7,6 +7,7 @@ import NewButton, { NewButtonType } from "@/_health/base/new_button";
 import { rpxToPx } from "@/utils/tools";
 import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
 import { IconArrow } from "@/components/basic/Icons";
+import Taro from "@tarojs/taro";
 
 export default function Relation() {
     const [count, setCount] = useState(0)
@@ -21,14 +22,35 @@ export default function Relation() {
         getRelation()
         getFollowers()
         getFollowings()
+
+        Taro.eventCenter.on('followUser',listenFollowUser)
+        Taro.eventCenter.on('unfollowUser',listenUnfollowUser)
+
+        return ()=>{
+            // Taro.eventCenter.off('followUser')
+            // Taro.eventCenter.off('unfollowUser')
+        }
     }, [])
 
+    function listenFollowUser(e){
+        console.log('follow user',e)
+        getRelation()
+        getFollowers()
+        getFollowings()
+    }
+
+    function listenUnfollowUser(e){
+        console.log('unfollow user',e)
+        getRelation()
+        getFollowers()
+        getFollowings()
+    }
+
     function getRelation() {
         getMyFriends({
             page: 1,
             limit: 20
         }).then(res => {
-            console.log(res)
             setCount((res as any).total)
             setFriends((res as any).data)
         })
@@ -38,7 +60,6 @@ export default function Relation() {
             page: 1,
             limit: 20
         }).then(res => {
-            console.log(res)
             setCount2((res as any).total)
             setFollowers((res as any).data)
         })
@@ -48,7 +69,6 @@ export default function Relation() {
             page: 1,
             limit: 20
         }).then(res => {
-            console.log(res)
             setCount3((res as any).total)
             setFollowings((res as any).data)
         })
@@ -87,9 +107,21 @@ export default function Relation() {
         </View>
     }
 
+    function tapFollow(item) {
+        var params: any = {
+            follow_origin: 'WECHAT_PRIVATE_CHAT',
+            user_id: item.id,
+        }
+        followUser(params).then(res => {
+            // getProfile()
+            Taro.eventCenter.trigger('followUser', item.id)
+            debugger
+        })
+    }
+
     function followItem(item, index) {
-        return <View key={index} className="relation_item" onClick={()=>{
-            jumpPage('./home')
+        return <View key={index} className="relation_item" onClick={() => {
+            jumpPage('./home?uid='+item.id)
         }}>
             <Image src={item.avatar} className="relation_avatar" />
             <Text className="h34" style={{ color: MainColorType.link, flex: 1 }}>{item.nickname}</Text>
@@ -101,12 +133,15 @@ export default function Relation() {
                 item.relation == 'FOLLOWING' && <Text className="h30 g02">Following</Text>
             }
             {
-                item.relation == 'FOLLOWER' && <NewButton 
+                item.relation == 'FOLLOWER' && <NewButton
                     title="Follow"
                     type={NewButtonType.alpha}
                     color={MainColorType.blue}
                     width={rpxToPx(136)}
                     height={rpxToPx(72)}
+                    onClick={() => {
+                        tapFollow(item)
+                    }}
                 />
             }
             <IconArrow width={rpxToPx(34)} color={MainColorType.g02} />

+ 0 - 1
src/features/health/MainHistory.tsx

@@ -803,7 +803,6 @@ export default forwardRef((props: { type?: string, fast_type?: string, updateDat
             </View>
         }
 
-
         {/* <View style={{ height: rpxToPx(40), flexShrink: 0, backgroundColor: '#fff' }} /> */}
         <ListFooter noMore={(list.length > 0) && (total == list.length)} loading={loading} />
     </View>

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

@@ -83,7 +83,8 @@ export default function Clock() {
         globalSetting({
             keys: 'mp_status'
         }).then(res => {
-            if ((res as any).data && (res as any).data[0].value.status == 'PENDING') {
+            debugger
+            if ((res as any).data && (res as any).data.length > 0 && (res as any).data[0].value.status == 'PENDING') {
                 global.allowShare = false
             }
             else {

+ 22 - 0
src/pages/friend/friend.scss

@@ -0,0 +1,22 @@
+.new_message_bg{
+    margin-bottom: 60px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+.new_message{
+    background-color: #000;
+    height: 72px;
+    border-radius: 36px;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    
+}
+
+.message_avatar{
+    width: 56px;
+    height: 56px;
+    border-radius: 28rpx;
+}

+ 21 - 1
src/pages/friend/friend.tsx

@@ -6,7 +6,7 @@ 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, getFriendDashBoard, getFriendMoments, getMyFriends, getUserHome } from "@/services/friend";
+import { followUser, getFriendDashBoard, getFriendMoments, getMyFriends } from "@/services/friend";
 import FriendGuide from "./guide";
 import EmptyContent from "./empty_content";
 import MomentItem from "./moment_item";
@@ -35,6 +35,26 @@ export default function Friend() {
         getWindows()
     }, [user.isLogin])
 
+    if (process.env.TARO_ENV == 'weapp' /*&& global.allowShare*/) {
+        Taro.updateShareMenu({
+            withShareTicket: true,
+            success() { }
+        })
+
+        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 ',
+                path: '/pages/friend/friend?type=share&uid=' + user.id,
+                // imageUrl: imageUrl
+            }
+        })
+    }
+
     function getWindows() {
         windows().then(res => {
             dispatch(setFastWithSleep((res as any).fast_with_sleep))

+ 308 - 67
src/pages/friend/friend_main.tsx

@@ -3,10 +3,10 @@
 import TabBar from "@/components/navigation/TabBar";
 import { rpxToPx } from "@/utils/tools";
 import { View, Text, Image, ScrollView, Button } from "@tarojs/components";
-import Taro, { useRouter, useShareAppMessage } from "@tarojs/taro";
+import Taro, { useDidShow, useRouter, useShareAppMessage } from "@tarojs/taro";
 import { useDispatch, useSelector } from "react-redux";
 import { useEffect, useState } from "react";
-import { followUser, getFriendDashBoard, getFriendMoments, getMyFriends, getUserHome } from "@/services/friend";
+import { followUser, getFriendMoments, getMyFriends, getUserDashBoard } from "@/services/friend";
 import FriendGuide from "./guide";
 import EmptyContent from "./empty_content";
 import MomentItem from "./moment_item";
@@ -16,6 +16,8 @@ import { setFastWithSleep, setFinishSetup, setLongFast, setRefreshs, setWindows
 import { getInfoSuccess } from "@/store/user";
 import showActionSheet from "@/components/basic/ActionSheet";
 import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
+import './friend.scss'
+import ListFooter from "@/_health/components/list_footer";
 
 let useRoute;
 let useNavigation;
@@ -25,18 +27,27 @@ if (process.env.TARO_ENV == 'rn') {
 }
 
 let timer;
+
+let myScrollTop = 0
+
 export default function FriendMain() {
     const user = useSelector((state: any) => state.user);
     const launchObj = Taro.getLaunchOptionsSync()
 
     const observerObjBottom = Taro.createIntersectionObserver().relativeToViewport({ bottom: 100 })
-
+    const [loading, setLoading] = useState(false)
+    const [noMore, setNoMore] = useState(false)
     const [friends, setFriends] = useState<any>([])
     const [count, setCount] = useState(0)
 
     const systemInfo: any = Taro.getWindowInfo ? Taro.getWindowInfo() : Taro.getSystemInfoSync();
     const navigationBarHeight = systemInfo.statusBarHeight + 44;
 
+    const [itemLayouts, setItemLayouts] = useState<any>([])
+    const [itemHeights, setItemHeights] = useState<any>([])
+    const [pageTop, setPageTop] = useState(0)
+
+
     let router
     let navigation;
     if (useNavigation) {
@@ -54,30 +65,39 @@ export default function FriendMain() {
     const [homeType, setHomeType] = useState('NO_FRIEND')
     const [dashBoard, setDashBoard] = useState<any>(null)
     const [moments, setMoments] = useState<any>([])
+    const [page, setPage] = useState(1)
+    const [endSignal, setEndSignal] = useState(0)
+    const query = Taro.createSelectorQuery()
+
     const dispatch = useDispatch()
     const { t } = useTranslation()
 
     useEffect(() => {
-        loadData()
         timer = setInterval(() => {
             setCount(count => count + 1)
         }, 1000)
+
+        Taro.eventCenter.on('followUser', listenFollowUser)
+        Taro.eventCenter.on('unfollowUser', listenUnfollowUser)
         return () => {
+            Taro.eventCenter.off('followUser')
+            Taro.eventCenter.off('unfollowUser')
             clearInterval(timer)
         }
 
 
     }, [])
 
-    function loadData() {
-        var userData = Taro.getStorageSync('userData')
-        if (userData) {
-            console.log('load user cache')
-            dispatch(getInfoSuccess(JSON.parse(userData)));
-        }
+    function listenFollowUser(e) {
+        console.log('home follow user', e)
+        myFriends()
+    }
+
+    function listenUnfollowUser(e) {
+        console.log('home unfollow user', e)
+        myFriends()
     }
 
-    
 
 
     useEffect(() => {
@@ -98,25 +118,130 @@ export default function FriendMain() {
         }
     }, [user.isLogin])
 
+    useEffect(() => {
+        if (moments.length == 0) return
+
+        setTimeout(() => {
+            measureItemLayouts()
+        }, 300)
+
+        observerObjBottom.observe('#footer', (res) => {
+            setEndSignal(endSignal => endSignal + 1)
+            // console.log(moments.length)
+            // if (moments.length==0) return
+            // loadMore()
+        })
+    }, [moments])
+
+    useEffect(() => {
+        if (moments.length == 0) return
+        loadMore()
+    }, [endSignal])
+
+    function measureItemLayouts() {
+
+        console.log('开始计算位置', new Date().getTime(), moments.length)
+        if (moments.length <= 10) {
+            moments.forEach((item, index) => {
+                query.select(`#history2-${index}`).boundingClientRect()
+            });
+            query.exec((res) => {
+                debugger
+                var layouts: any = []
+                var heights: any = []
+                res.forEach((rect, index) => {
+                    if (rect) {
+                        layouts[index] = rect.top + myScrollTop
+                        heights[index] = rect.height
+                    }
+                });
+                setItemLayouts(layouts)
+                setItemHeights(heights)
+                console.log('结束计算位置', new Date().getTime())
+            })
+        }
+        else {
+            moments.forEach((item, index) => {
+                if (index >= itemLayouts.length) {
+                    query.select(`#history2-${index}`).boundingClientRect()
+                }
+            });
+            query.exec((res) => {
+                var layouts: any = []
+                var heights: any = []
+                // console.log(res)
+                res.forEach((rect, index) => {
+
+                    if (rect) {
+                        layouts[index] = rect.top + myScrollTop
+                        heights[index] = rect.height
+                    }
+                });
+                setItemLayouts([...itemLayouts, ...layouts])
+                setItemHeights([...itemHeights, ...heights])
+                console.log('结束计算位置', new Date().getTime())
+            })
+
+        }
+    }
+
+    function onScroll(e) {
+        // var top = e.detail.scrollTop
+        // myScrollTop = top
+        var top = e.detail.scrollTop - e.detail.deltaY
+        myScrollTop = e.detail.scrollTop
+        setPageTop(top)
+    }
+
+    useDidShow(() => {
+        getDashBoard()
+    })
+
     function myFriends() {
         if (!user.isLogin) {
             setLoaded(true)
 
             return
         }
-        
 
-        getFriendDashBoard().then(res => {
-            setLoaded(true)
-            setHomeType((res as any).homepage_type)
-            setDashBoard(res)
-        })
 
+        getDashBoard()
+
+        getMoments(1)
+    }
+
+    function getMoments(index) {
+        setPage(index)
         getFriendMoments({
-            page: 1,
+            page: index,
             limit: 10
         }).then(res => {
-            setMoments((res as any).data)
+            console.log(index)
+            if (index == 1) {
+                console.log('ss')
+                setMoments((res as any).data)
+            }
+            else {
+                console.log('ooo')
+                setMoments([...moments, ...(res as any).data])
+            }
+            setLoading(false)
+
+            if ((res as any).data.length == 0) {
+                setNoMore(true)
+            }
+            else {
+                setNoMore(false)
+            }
+
+        })
+    }
+
+    function getDashBoard() {
+        getUserDashBoard().then(res => {
+            setLoaded(true)
+            setHomeType((res as any).homepage_type)
+            setDashBoard(res)
         })
     }
 
@@ -126,67 +251,42 @@ export default function FriendMain() {
             Taro.setStorageSync('share_info', JSON.stringify(obj))
             return
         }
-        console.log('user login')
         if (user.id != router.params.uid) {
             var params: any = {
-                follow_origin: obj ? 'WECHAT_GROUP_CHAT' : 'WECHAT_PRIVATE_CHAT'
+                follow_origin: obj ? 'WECHAT_GROUP_CHAT' : 'WECHAT_PRIVATE_CHAT',
+                user_id: router.params.uid,
             }
             if (obj) {
                 params.wechat = obj
             }
-            followUser(router.params.uid, params).then(res => {
+            followUser(params).then(res => {
                 myFriends()
             })
         }
     }
 
 
-    useEffect(() => {
-        // observerObjBottom.observe('#a', (res) => {
-        //     console.log('a')
-        // })
-        // observerObjBottom.observe('#b', (res) => {
-        //     console.log('b')
-        // })
-        // observerObjBottom.observe('#c', (res) => {
-        //     console.log('c')
-        // })
-        // observerObjBottom.observe('#d', (res) => {
-        //     console.log('d')
-        // })
-        observerObjBottom.observe('#e', (res) => {
-            console.log('e')
-        })
-    }, [])
 
-    if (process.env.TARO_ENV == 'weapp' /*&& global.allowShare*/) {
-        Taro.updateShareMenu({
-            withShareTicket: true,
-            success() { }
-        })
 
-        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 ',
-                path: '/pages/friend/friend?type=share&uid=' + user.id,
-                // imageUrl: imageUrl
-            }
-        })
+    function loadMore() {
+        if (loading) return;
+        if (noMore) return;
+        setLoading(true)
+        console.log(page)
+        var index = page;
+        index++;
+        setPage(index)
+        getMoments(index)
     }
 
-    function more(){
+    function more() {
         showActionSheet({
-            title:'',
-            itemList:['个人主页','我的搭子','消息通知'],
-            success:(index)=>{
-                switch(index){
+            title: '',
+            itemList: ['个人主页', '我的搭子', '消息通知'],
+            success: (index) => {
+                switch (index) {
                     case 0:
-                        jumpPage('/_moment/pages/home')
+                        jumpPage('/_moment/pages/home?uid=' + user.id)
                         break;
                     case 1:
                         jumpPage('/_moment/pages/relation')
@@ -202,6 +302,9 @@ export default function FriendMain() {
     function friendGuide() {
         return <View>
             <View style={{ height: navigationBarHeight, width: rpxToPx(750), backgroundColor: '#fff' }} />
+            <View onClick={() => {
+                jumpPage('/_moment/pages/message')
+            }}>My Message</View>
             <FriendGuide />
             {
                 process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
@@ -218,6 +321,89 @@ export default function FriendMain() {
         </View>
     }
 
+    // console.log(pageTop, itemLayouts)
+
+    function listDetail() {
+        return <View >
+            <View style={{
+                position: 'fixed',
+                top: 0,
+                left: 0,
+                zIndex: 10,
+                height: navigationBarHeight, width: rpxToPx(750), backgroundColor: '#fff', display: 'flex',
+                flexDirection: 'column', justifyContent: 'flex-end'
+            }}>
+                <View style={{ height: 44, width: rpxToPx(750), position: 'relative', display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
+                    <View>{t('health.moments')}</View>
+                    <View onClick={more} style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 80, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>More</View>
+                </View>
+            </View>
+            <ScrollView style='height:100vh'
+                enableBackToTop
+                scrollY={true}
+                // refresherEnabled={props.onRefresherRefresh}
+                // upperThreshold={70}
+                // lowerThreshold={140}
+                // refresherBackground={MainColorType.g05}
+                // onRefresherRefresh={props.onRefresherRefresh}
+                // refresherTriggered={props.isPulling}
+                onScroll={onScroll}
+                onScrollToUpper={() => {
+                    setPage(1)
+                    if (moments.length > 10) {
+                        setMoments(moments.slice(0, 10))
+                        setItemHeights(itemHeights.slice(0, 10))
+                        setItemLayouts(itemLayouts.slice(0, 10))
+                    }
+
+                }}
+            // onScrollToLower={props.loadMore}
+            >
+                <View style={{ backgroundColor: '#fff', minHeight: '100vh', paddingTop: navigationBarHeight, marginTop: rpxToPx(60), paddingBottom: 100 }}>
+                    {
+                        dashBoard && dashBoard.new_message && <View className="new_message_bg">
+
+                            <View className="new_message" onClick={() => {
+                                jumpPage('/_moment/pages/message')
+                            }}>
+                                {
+                                    dashBoard.new_message.avatars.map((item, index) => {
+                                        return <Image className="message_avatar" src={item} key={index} style={{ zIndex: 9 - index, marginLeft: index == 0 ? rpxToPx(8) : -15 }} />
+                                    })
+                                }
+                                <View className="h26 bold" style={{ color: '#fff', minWidth: rpxToPx(260), textAlign: 'center' }}>{dashBoard.new_message.message_tip}</View>
+                            </View>
+                        </View>
+                    }
+                    {
+                        moments.map((item, index) => {
+                            if (itemLayouts.length >= index + 1 && pageTop > 0 && index > 5) {
+                                if (Math.abs(itemLayouts[index] - pageTop) > 2500) {
+                                    return <View style={{ height: itemHeights[index] }} id={`history—temp-${index}`}>
+                                    </View>
+                                }
+
+                            }
+                            return <View key={index} id={`history2-${index}`}>
+                                <MomentItem data={item} />
+                            </View>
+                        })
+                    }
+
+                    <ListFooter noMore={noMore} loading={loading} />
+                    <View id="footer" style={{ width: 1, height: 1 }}></View>
+
+                </View>
+            </ScrollView>
+
+
+            {
+                process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
+            }
+        </View>
+
+    }
+
     function content() {
         if (!loaded) {
             return <View >
@@ -236,33 +422,88 @@ export default function FriendMain() {
                 return empty()
 
         }
+
+        return listDetail()
         return <View >
             <View style={{
+                position: 'fixed',
+                top: 0,
+                left: 0,
+                zIndex: 10,
                 height: navigationBarHeight, width: rpxToPx(750), backgroundColor: '#fff', display: 'flex',
                 flexDirection: 'column', justifyContent: 'flex-end'
             }}>
-                <View style={{ height: 44, width: rpxToPx(750),position:'relative', display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
+                <View style={{ height: 44, width: rpxToPx(750), position: 'relative', display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
                     <View>{t('health.moments')}</View>
-                    <View onClick={more} style={{position:'absolute',left:0,top:0,bottom:0,width:80,display:'flex',alignItems:'center',justifyContent:'center'}}>More</View>
+                    <View onClick={more} style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 80, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>More</View>
                 </View>
             </View>
-            <View style={{ backgroundColor: '#fff', minHeight: '100vh' }}>
+            <View style={{ backgroundColor: '#fff', minHeight: '100vh', paddingTop: navigationBarHeight, marginTop: rpxToPx(60), paddingBottom: 100 }}>
+                {
+                    dashBoard && dashBoard.new_message && <View className="new_message_bg">
+
+                        <View className="new_message" onClick={() => {
+                            jumpPage('/_moment/pages/message')
+                        }}>
+                            {
+                                dashBoard.new_message.avatars.map((item, index) => {
+                                    return <Image className="message_avatar" src={item} key={index} style={{ zIndex: 9 - index, marginLeft: index == 0 ? rpxToPx(8) : -15 }} />
+                                })
+                            }
+                            <View className="h26 bold" style={{ color: '#fff', minWidth: rpxToPx(260), textAlign: 'center' }}>{dashBoard.new_message.message_tip}</View>
+                        </View>
+                    </View>
+                }
                 {
                     moments.map((item, index) => {
-                        return <View key={index}>
+                        if (itemLayouts.length >= index + 1 && pageTop > 0) {
+                            if (Math.abs(itemLayouts[index] - pageTop) > 2000) {
+                                return <View style={{ height: itemHeights[index] }} id={`history-${index}`}>
+                                </View>
+                            }
+                            // if (Math.abs(itemLayouts[index] - pageTop) > 1500) {
+                            //     return <View style={{
+                            //         height: itemHeights[index], display: 'flex',
+                            //         paddingLeft: rpxToPx(40),
+                            //         paddingRight: rpxToPx(40),
+                            //         boxSizing: 'border-box',
+                            //         flexDirection: 'row'
+                            //     }} id={`history-${index}`}>
+                            //         <TimelineDate timestamp={item.window_range.start_timestamp}
+                            //             pre_timestamp={index > 0 ? list[index - 1].window_range.start_timestamp : null}
+                            //         />
+                            //         <View style={{
+                            //             display: 'flex', flexDirection: 'column', flex: 1,
+                            //             width: rpxToPx(552), height: itemHeights[index] - rpxToPx(60), backgroundColor: '#fafafa'
+                            //         }}>
+                            //         </View>
+                            //     </View>
+                            // }
+
+                        }
+                        return <View key={index} id={`history-{index}`}>
                             <MomentItem data={item} />
                         </View>
                     })
                 }
+
+                <ListFooter noMore={noMore} loading={loading} />
+
             </View>
 
+
             {
                 process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
             }
         </View>
     }
 
-    return content()
+    return <View>
+        {
+            content()
+        }
+
+    </View>
 
 
     return <View>

+ 2 - 2
src/pages/friend/moment_item.scss

@@ -2,8 +2,8 @@
     display: flex;
     flex-direction: row;
     padding-bottom: 60px;
-    padding-left: 60px;
-    padding-right: 60px;
+    padding-left: 40px;
+    padding-right: 40px;
 }
 
 .moment_avatar {

+ 5 - 2
src/pages/friend/moment_item.tsx

@@ -44,7 +44,10 @@ export default function MomentItem(props: { data: any }) {
         return list.map(obj => obj.url);
     }
 
-    function goProfile() {
+    function goProfile(e) {
+        if (process.env.TARO_ENV=='weapp'){
+            e.stopPropagation()
+        }
         jumpPage(`/_moment/pages/home?uid=${user.id}`)
     }
 
@@ -55,7 +58,7 @@ export default function MomentItem(props: { data: any }) {
     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>
+            <View className="h34 bold" style={{ color: MainColorType.link, marginBottom: rpxToPx(6) }} onClick={goProfile}>{user.nickname}</View>
             {
                 (moment.title || moment.description) && <TimeTitleDesc time="" title={moment.title} desc={moment.description} />
             }

+ 43 - 14
src/services/friend.tsx

@@ -1,10 +1,39 @@
-import { API_FOLLOW_USER, API_FRIEND_DASHBOARD, API_FRIEND_MOMENTS, API_MY_FOLLOWERS, API_MY_FOLLOWINGS, API_MY_FRIENDS, API_USER_HOME } from "./http/api";
+import { API_FOLLOW_USER, API_USER_MESSAGES, API_FRIEND_MOMENTS, API_MY_FOLLOWINGS, API_MY_FRIENDS, API_USER_DASHBOARD, API_USER_PROFILE } from "./http/api";
 import { request } from "./http/request";
 
-export const followUser = (id,params) => {
+//关注
+export const followUser = (params) => {
     return new Promise((resolve, reject) => {
         request({
-            url: API_FOLLOW_USER+'/'+id+'/followers', method: 'POST', data: {...params}
+            url: API_FOLLOW_USER, method: 'POST', data: { ...params }
+        }).then(res => {
+            resolve(res);
+            // dispatch(loginSuccess(res));
+        }).catch(e => {
+            reject(e)
+        })
+    })
+}
+
+//取消关注
+export const unfollowUser = (id) => {
+    return new Promise((resolve, reject) => {
+        request({
+            url: API_MY_FOLLOWINGS + '/' + id, method: 'DELETE', data: {}
+        }).then(res => {
+            resolve(res);
+            // dispatch(loginSuccess(res));
+        }).catch(e => {
+            reject(e)
+        })
+    })
+}
+
+//获取消息列表
+export const getMessages = (params) => {
+    return new Promise((resolve, reject) => {
+        request({
+            url: API_USER_MESSAGES, method: 'GET', data: { ...params }
         }).then(res => {
             resolve(res);
             // dispatch(loginSuccess(res));
@@ -17,7 +46,7 @@ export const followUser = (id,params) => {
 export const getMyFriends = (params) => {
     return new Promise((resolve, reject) => {
         request({
-            url: API_MY_FRIENDS, method: 'GET', data: {...params}
+            url: API_MY_FRIENDS, method: 'GET', data: { ...params }
         }).then(res => {
             resolve(res);
             // dispatch(loginSuccess(res));
@@ -27,10 +56,10 @@ export const getMyFriends = (params) => {
     })
 }
 
-export const getMyFollowings = (params) =>{
+export const getMyFollowings = (params) => {
     return new Promise((resolve, reject) => {
         request({
-            url: API_MY_FOLLOWINGS, method: 'GET', data: {...params}
+            url: API_MY_FOLLOWINGS, method: 'GET', data: { ...params }
         }).then(res => {
             resolve(res);
             // dispatch(loginSuccess(res));
@@ -40,10 +69,10 @@ export const getMyFollowings = (params) =>{
     })
 }
 
-export const getMyFollowers = (params) =>{
+export const getMyFollowers = (params) => {
     return new Promise((resolve, reject) => {
         request({
-            url: API_MY_FOLLOWERS, method: 'GET', data: {...params}
+            url: API_FOLLOW_USER, method: 'GET', data: { ...params }
         }).then(res => {
             resolve(res);
             // dispatch(loginSuccess(res));
@@ -53,10 +82,10 @@ export const getMyFollowers = (params) =>{
     })
 }
 
-export const getFriendDashBoard = ()=>{
+export const getUserDashBoard = () => {
     return new Promise((resolve, reject) => {
         request({
-            url: API_FRIEND_DASHBOARD, method: 'GET', data: {}
+            url: API_USER_DASHBOARD, method: 'GET', data: {}
         }).then(res => {
             resolve(res);
             // dispatch(loginSuccess(res));
@@ -66,10 +95,10 @@ export const getFriendDashBoard = ()=>{
     })
 }
 
-export const getUserHome = ()=>{
+export const getUserProfile = (params) => {
     return new Promise((resolve, reject) => {
         request({
-            url: API_USER_HOME, method: 'GET', data: {}
+            url: API_USER_PROFILE, method: 'GET', data: { ...params }
         }).then(res => {
             resolve(res);
             // dispatch(loginSuccess(res));
@@ -79,10 +108,10 @@ export const getUserHome = ()=>{
     })
 }
 
-export const getFriendMoments = (params)=>{
+export const getFriendMoments = (params) => {
     return new Promise((resolve, reject) => {
         request({
-            url: API_FRIEND_MOMENTS, method: 'GET', data: {...params}
+            url: API_FRIEND_MOMENTS, method: 'GET', data: { ...params }
         }).then(res => {
             resolve(res);
             // dispatch(loginSuccess(res));

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

@@ -122,10 +122,10 @@ export const API_LASTEST_JOURNAL = `${baseUrl}/api/health/journals/latest/genera
 export const API_RESET_TESTINFO = `${baseUrl}/api/user/test-resets`
 
 //friend
-export const API_FOLLOW_USER = `${baseUrl}/api/users`
+export const API_FOLLOW_USER = `${baseUrl}/api/user/followers`
 export const API_MY_FRIENDS = `${baseUrl}/api/user/friends`
 export const API_MY_FOLLOWINGS = `${baseUrl}/api/user/followings`
-export const API_MY_FOLLOWERS = `${baseUrl}/api/user/followers`
-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`
+export const API_USER_DASHBOARD = `${baseUrl}/api/user/dashboard`
+export const API_FRIEND_MOMENTS = `${baseUrl}/api/user/feeds`
+export const API_USER_PROFILE = `${baseUrl}/api/user/profile`
+export const API_USER_MESSAGES = `${baseUrl}/api/user/messages`