moment_main.tsx 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. import TabBar from "@/components/navigation/TabBar";
  2. import { rpxToPx } from "@/utils/tools";
  3. import { View, Text, Image, ScrollView, Button, Block } from "@tarojs/components";
  4. import Taro, { useDidShow, useRouter, useShareAppMessage } from "@tarojs/taro";
  5. import { useDispatch, useSelector } from "react-redux";
  6. import { useEffect, useRef, useState } from "react";
  7. import { followUser, getFriendMoments, getMyFriends, getUserDashBoard } from "@/services/friend";
  8. import FriendGuide from "./guide";
  9. import EmptyContent from "./empty_content";
  10. import MomentItem from "./moment_item";
  11. import { useTranslation } from "react-i18next";
  12. import { windows } from "@/services/health";
  13. import { setFastWithSleep, setFinishSetup, setLongFast, setRefreshs, setWindows } from "@/store/health";
  14. import { getInfoSuccess } from "@/store/user";
  15. import showActionSheet from "@/components/basic/ActionSheet";
  16. import { jumpPage } from "@/features/trackTimeDuration/hooks/Common";
  17. import './moment.scss'
  18. import ListFooter from "@/_health/components/list_footer";
  19. import { MainColorType } from "@/context/themes/color";
  20. import dayjs from "dayjs";
  21. import { IconClose, IconMenu } from "@/components/basic/Icons";
  22. import MomentShare from "./moment_share";
  23. import NoRecord from "@/_health/components/no_record";
  24. import ShareBtn from "@/components/basic/ShareBtn";
  25. import NewButton, { NewButtonType } from "@/_health/base/new_button";
  26. import MomentDetailShare from "./moment_detail_share";
  27. import { getThemeColor } from "@/features/health/hooks/health_hooks";
  28. import shareTitle from "./moment_unit";
  29. let useRoute;
  30. let useNavigation;
  31. if (process.env.TARO_ENV == 'rn') {
  32. useRoute = require("@react-navigation/native").useRoute
  33. useNavigation = require("@react-navigation/native").useNavigation
  34. }
  35. let timer;
  36. let myScrollTop = 0
  37. export default function MomentMain() {
  38. const user = useSelector((state: any) => state.user);
  39. const observerObjBottom = Taro.createIntersectionObserver().relativeToViewport({ bottom: 100 })
  40. const [loading, setLoading] = useState(false)
  41. const [noMore, setNoMore] = useState(false)
  42. const [friends, setFriends] = useState<any>([])
  43. const [count, setCount] = useState(0)
  44. const systemInfo: any = Taro.getWindowInfo ? Taro.getWindowInfo() : Taro.getSystemInfoSync();
  45. const navigationBarHeight = systemInfo.statusBarHeight + 44;
  46. const [itemLayouts, setItemLayouts] = useState<any>([])
  47. const [itemHeights, setItemHeights] = useState<any>([])
  48. const [isPulling, setIsPulling] = useState(false)
  49. const [pageTop, setPageTop] = useState(0)
  50. const scrollRef = useRef()
  51. let router
  52. let navigation;
  53. if (useNavigation) {
  54. navigation = useNavigation()
  55. }
  56. if (process.env.TARO_ENV == 'rn') {
  57. router = useRoute()
  58. }
  59. else {
  60. router = useRouter()
  61. }
  62. const [loaded, setLoaded] = useState(false)
  63. const [homeType, setHomeType] = useState('NO_FRIEND')
  64. const [dashBoard, setDashBoard] = useState<any>(null)
  65. const [moments, setMoments] = useState<any>([])
  66. const [page, setPage] = useState(1)
  67. const [endSignal, setEndSignal] = useState(0)
  68. const [closeGuide, setCloseGuide] = useState(false)
  69. const [showShareGuide, setShowShareGuide] = useState(false)
  70. const [shareInfo, setShareInfo] = useState<any>(null)
  71. const query = Taro.createSelectorQuery()
  72. const dispatch = useDispatch()
  73. const { t } = useTranslation()
  74. useEffect(() => {
  75. dayjs.locale(global.language == 'en' ? 'en' : 'zh-cn');
  76. require('moment/locale/en-gb')
  77. require('moment/locale/zh-cn')
  78. timer = setInterval(() => {
  79. setCount(count => count + 1)
  80. }, 1000)
  81. Taro.eventCenter.on('followUser', listenFollowUser)
  82. Taro.eventCenter.on('unfollowUser', listenUnfollowUser)
  83. Taro.eventCenter.on('refreshMoments', refreshMoments)
  84. Taro.eventCenter.on('moment_share', momentShare)
  85. return () => {
  86. Taro.eventCenter.off('followUser')
  87. Taro.eventCenter.off('unfollowUser')
  88. Taro.eventCenter.off('refreshMoments')
  89. Taro.eventCenter.off('moment_share')
  90. clearInterval(timer)
  91. }
  92. }, [])
  93. function listenFollowUser(e) {
  94. myFriends()
  95. }
  96. function listenUnfollowUser(e) {
  97. myFriends()
  98. }
  99. function refreshMoments(e) {
  100. myFriends()
  101. }
  102. function momentShare(e) {
  103. setShareInfo(e)
  104. setShowShareGuide(true)
  105. // var dt = scrollRef.current
  106. // query.select(`#myscrollview`).boundingClientRect().exec(res=>{
  107. // debugger
  108. // })
  109. }
  110. useEffect(() => {
  111. myFriends()
  112. if (router.params.type == 'share') {
  113. if (global.shareTicket) {
  114. Taro.getShareInfo({
  115. shareTicket: global.shareTicket,
  116. success(result) {
  117. updateRelation(result)
  118. },
  119. })
  120. }
  121. else {
  122. updateRelation(null)
  123. }
  124. }
  125. }, [user.isLogin])
  126. useEffect(() => {
  127. if (moments.length == 0) return
  128. setTimeout(() => {
  129. measureItemLayouts()
  130. }, 300)
  131. observerObjBottom.observe('#footer', (res) => {
  132. setEndSignal(endSignal => endSignal + 1)
  133. // if (moments.length==0) return
  134. // loadMore()
  135. })
  136. }, [moments])
  137. useEffect(() => {
  138. if (moments.length == 0) return
  139. loadMore()
  140. }, [endSignal])
  141. function measureItemLayouts() {
  142. if (moments.length <= 10) {
  143. moments.forEach((item, index) => {
  144. query.select(`#history2-${index}`).boundingClientRect()
  145. });
  146. query.exec((res) => {
  147. var layouts: any = []
  148. var heights: any = []
  149. res.forEach((rect, index) => {
  150. if (rect) {
  151. layouts[index] = rect.top + myScrollTop
  152. heights[index] = rect.height
  153. }
  154. });
  155. setItemLayouts(layouts)
  156. setItemHeights(heights)
  157. })
  158. }
  159. else {
  160. moments.forEach((item, index) => {
  161. if (index >= itemLayouts.length) {
  162. query.select(`#history2-${index}`).boundingClientRect()
  163. }
  164. });
  165. query.exec((res) => {
  166. var layouts: any = []
  167. var heights: any = []
  168. res.forEach((rect, index) => {
  169. if (rect) {
  170. layouts[index] = rect.top + myScrollTop
  171. heights[index] = rect.height
  172. }
  173. });
  174. setItemLayouts([...itemLayouts, ...layouts])
  175. setItemHeights([...itemHeights, ...heights])
  176. })
  177. }
  178. }
  179. function onScroll(e) {
  180. // var top = e.detail.scrollTop
  181. // myScrollTop = top
  182. var top = e.detail.scrollTop - e.detail.deltaY
  183. myScrollTop = e.detail.scrollTop
  184. setPageTop(top)
  185. }
  186. useDidShow(() => {
  187. getDashBoard()
  188. })
  189. function myFriends() {
  190. if (!user.isLogin) {
  191. setLoaded(true)
  192. Taro.hideLoading()
  193. return
  194. }
  195. setItemHeights([])
  196. setItemLayouts([])
  197. getDashBoard()
  198. getMoments(1)
  199. }
  200. function onRefresh() {
  201. setIsPulling(true)
  202. getMoments(1)
  203. getDashBoard()
  204. }
  205. function getMoments(index) {
  206. setPage(index)
  207. getFriendMoments({
  208. page: index,
  209. limit: 10
  210. }).then(res => {
  211. setIsPulling(false)
  212. if (index == 1) {
  213. setMoments((res as any).data)
  214. }
  215. else {
  216. setMoments([...moments, ...(res as any).data])
  217. }
  218. setLoading(false)
  219. if ((res as any).data.length == 0) {
  220. setNoMore(true)
  221. }
  222. else {
  223. setNoMore(false)
  224. }
  225. }).catch(e => {
  226. setIsPulling(false)
  227. setLoading(false)
  228. setLoaded(true)
  229. Taro.hideLoading()
  230. })
  231. }
  232. function getDashBoard() {
  233. getUserDashBoard().then(res => {
  234. setLoaded(true)
  235. setHomeType((res as any).homepage_type)
  236. setDashBoard(res)
  237. Taro.hideLoading()
  238. }).catch(e => {
  239. setLoaded(true)
  240. Taro.hideLoading()
  241. })
  242. }
  243. function updateRelation(obj) {
  244. if (!user.isLogin) {
  245. Taro.setStorageSync('share_uid', router.params.uid)
  246. Taro.setStorageSync('share_info', JSON.stringify(obj))
  247. return
  248. }
  249. if (user.id != router.params.uid) {
  250. var params: any = {
  251. follow_origin: obj ? 'WECHAT_GROUP_CHAT' : 'WECHAT_PRIVATE_CHAT',
  252. user_id: router.params.uid,
  253. }
  254. if (obj) {
  255. params.wechat = obj
  256. }
  257. followUser(params).then(res => {
  258. myFriends()
  259. })
  260. }
  261. }
  262. function loadMore() {
  263. if (loading) return;
  264. if (noMore) return;
  265. setLoading(true)
  266. var index = page;
  267. index++;
  268. setPage(index)
  269. getMoments(index)
  270. }
  271. function more() {
  272. showActionSheet({
  273. title: '',
  274. itemList: ['个人主页', '我的搭子', '消息通知'],
  275. success: (index) => {
  276. switch (index) {
  277. case 0:
  278. jumpPage('/_moment/pages/home?uid=' + user.id)
  279. break;
  280. case 1:
  281. jumpPage('/_moment/pages/relation')
  282. break
  283. case 2:
  284. jumpPage('/_moment/pages/message')
  285. break
  286. }
  287. }
  288. })
  289. }
  290. function friendGuide() {
  291. return <View style={{ position: 'fixed', left: 0, top: 0, width: rpxToPx(750), height: '100vh', zIndex: 100 }}>
  292. <View style={{ height: navigationBarHeight, width: rpxToPx(750), backgroundColor: '#fff' }} />
  293. {/* <View onClick={() => {
  294. setCloseGuide(true)
  295. }}>关闭</View> */}
  296. {
  297. user.isLogin && <View style={{
  298. position: 'absolute', left: 10, top: navigationBarHeight - 44, width: 44, height: 44,
  299. display: 'flex', alignItems: 'center', justifyContent: 'center'
  300. }}
  301. onClick={() => {
  302. setCloseGuide(true)
  303. }}
  304. >
  305. <IconClose color="#000" width={30} height={30} />
  306. </View>
  307. }
  308. <FriendGuide />
  309. {
  310. process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
  311. }</View>
  312. }
  313. function empty() {
  314. return <View style={{ position: 'fixed', left: 0, top: 0, width: rpxToPx(750), height: '100vh', zIndex: 100 }}>
  315. <View style={{ height: navigationBarHeight, width: rpxToPx(750), backgroundColor: '#fff' }} />
  316. {
  317. user.isLogin && <View style={{
  318. position: 'absolute', left: 10, top: navigationBarHeight - 44, width: 44, height: 44,
  319. display: 'flex', alignItems: 'center', justifyContent: 'center'
  320. }}
  321. onClick={() => {
  322. setCloseGuide(true)
  323. }}
  324. >
  325. <IconClose color="#000" width={30} height={30} />
  326. </View>
  327. }
  328. <EmptyContent friends={dashBoard.friends} />
  329. {
  330. process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
  331. }
  332. </View>
  333. }
  334. function shareGuideContent() {
  335. return <Block><View className="share_guide_bg" style={{ top: 0 }} onClick={(e) => {
  336. if (process.env.TARO_ENV == 'weapp') {
  337. e.stopPropagation()
  338. }
  339. setShowShareGuide(false)
  340. }}>
  341. <View className="share_guide_card" onClick={(e) => {
  342. if (process.env.TARO_ENV == 'weapp') {
  343. e.stopPropagation()
  344. }
  345. }}>
  346. <Image className="share_guide_avatar" mode="aspectFill" src={shareInfo.join.user.avatar} />
  347. <View className="h34 bold" style={{ marginTop: rpxToPx(60), marginBottom: rpxToPx(60) }}>{shareTitle(t, shareInfo.join.user)}</View>
  348. <ShareBtn onClick={() => {
  349. setShowShareGuide(false)
  350. }}>
  351. <NewButton
  352. title="分享给微信好友"
  353. type={NewButtonType.fill}
  354. width={rpxToPx(480)}
  355. height={rpxToPx(96)}
  356. color={MainColorType.success}
  357. onClick={() => {
  358. }}
  359. />
  360. </ShareBtn>
  361. </View>
  362. </View>
  363. </Block>
  364. }
  365. function listDetail() {
  366. return <View >
  367. <View style={{
  368. position: 'fixed',
  369. top: 0,
  370. left: 0,
  371. zIndex: 10,
  372. height: navigationBarHeight, width: rpxToPx(750), backgroundColor: '#f5f5f5', display: 'flex',
  373. flexDirection: 'column', justifyContent: 'flex-end'
  374. }}>
  375. <View style={{ height: 44, width: rpxToPx(750), position: 'relative', display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
  376. <View style={{ fontWeight: 'bold', }}>{t('health.moments')}</View>
  377. <View onClick={more} style={{ position: 'absolute', left: 10, top: 0, bottom: 0, width: 44, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
  378. <IconMenu color="#000" width={rpxToPx(40)} />
  379. </View>
  380. <View style={{ position: 'absolute', left: 54, top: 0, bottom: 0, width: 44, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
  381. <Image src={require('@assets/_health/wechat.png')} style={{ width: rpxToPx(48), height: rpxToPx(48) }} />
  382. <Button openType="share" style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0, opacity: 0 }} />
  383. </View>
  384. </View>
  385. </View>
  386. <ScrollView style={{
  387. marginTop: navigationBarHeight,
  388. height: '90vh'
  389. }}
  390. enableBackToTop
  391. ref={scrollRef}
  392. id="myscrollview"
  393. scrollY={showShareGuide ? false : true}
  394. refresherEnabled={true}
  395. upperThreshold={70}
  396. // scrollTop={showShareGuide ? pageTop : undefined}
  397. // lowerThreshold={140}
  398. refresherBackground={MainColorType.g05}
  399. onRefresherRefresh={onRefresh}
  400. refresherTriggered={isPulling}
  401. onScroll={onScroll}
  402. onScrollToUpper={() => {
  403. setPage(1)
  404. if (moments.length > 10) {
  405. setMoments(moments.slice(0, 10))
  406. setItemHeights(itemHeights.slice(0, 10))
  407. setItemLayouts(itemLayouts.slice(0, 10))
  408. }
  409. }}
  410. // onScrollToLower={props.loadMore}
  411. >
  412. <View style={{ backgroundColor: '#fff', minHeight: '100vh', paddingTop: rpxToPx(30), paddingBottom: 100 }}>
  413. {
  414. dashBoard && dashBoard.new_message && <View className="new_message_bg">
  415. <View className="new_message" onClick={() => {
  416. jumpPage('/_moment/pages/message')
  417. }}>
  418. {
  419. dashBoard.new_message.avatars.map((item, index) => {
  420. return <Image className="message_avatar" src={item} key={index} style={{ zIndex: 9 - index, marginLeft: index == 0 ? rpxToPx(8) : -15 }} />
  421. })
  422. }
  423. <View className="h26 bold" style={{ color: '#fff', minWidth: rpxToPx(260), textAlign: 'center' }}>{dashBoard.new_message.message_tip}</View>
  424. </View>
  425. </View>
  426. }
  427. {
  428. moments.map((item, index) => {
  429. if (itemLayouts.length >= index + 1 && pageTop > 0 && index > 5) {
  430. if (Math.abs(itemLayouts[index] - pageTop) > 2500) {
  431. return <View style={{ height: itemHeights[index] }} id={`history—temp-${index}`}>
  432. </View>
  433. }
  434. }
  435. return <View key={index} id={`history2-${index}`}>
  436. <MomentItem data={item} />
  437. </View>
  438. })
  439. }
  440. {
  441. moments.length == 0 && <NoRecord style={{ marginTop: rpxToPx(160) }} />
  442. }
  443. <ListFooter noMore={noMore} loading={loading} />
  444. <View id="footer" style={{ width: 1, height: 1 }}></View>
  445. </View>
  446. </ScrollView>
  447. <Block>
  448. {
  449. showShareGuide && <MomentDetailShare user={shareInfo.join.user} btnColor={getThemeColor(shareInfo.join.window)} />
  450. }
  451. </Block>
  452. <Block>
  453. {
  454. showShareGuide && shareGuideContent()
  455. }
  456. </Block>
  457. {
  458. process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
  459. }
  460. {
  461. homeType == 'NO_FRIEND' && !closeGuide && friendGuide()
  462. }
  463. {
  464. homeType == 'NO_MOMENT' && !closeGuide && empty()
  465. }
  466. </View>
  467. }
  468. function content() {
  469. if (!loaded) {
  470. return <View >
  471. {
  472. process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
  473. }
  474. </View>
  475. }
  476. if (!user.isLogin) {
  477. return friendGuide()
  478. }
  479. return listDetail()
  480. return <View >
  481. <View style={{
  482. position: 'fixed',
  483. top: 0,
  484. left: 0,
  485. zIndex: 10,
  486. height: navigationBarHeight, width: rpxToPx(750), backgroundColor: '#fff', display: 'flex',
  487. flexDirection: 'column', justifyContent: 'flex-end'
  488. }}>
  489. <View style={{ height: 44, width: rpxToPx(750), position: 'relative', display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
  490. <View>{t('health.moments')}</View>
  491. <View onClick={more} style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 80, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>More</View>
  492. </View>
  493. </View>
  494. <View style={{ backgroundColor: '#fff', minHeight: '100vh', paddingTop: navigationBarHeight, marginTop: rpxToPx(60), paddingBottom: 100 }}>
  495. {
  496. dashBoard && dashBoard.new_message && <View className="new_message_bg">
  497. <View className="new_message" onClick={() => {
  498. jumpPage('/_moment/pages/message')
  499. }}>
  500. {
  501. dashBoard.new_message.avatars.map((item, index) => {
  502. return <Image className="message_avatar" src={item} key={index} style={{ zIndex: 9 - index, marginLeft: index == 0 ? rpxToPx(8) : -15 }} />
  503. })
  504. }
  505. <View className="h26 bold" style={{ color: '#fff', minWidth: rpxToPx(260), textAlign: 'center' }}>{dashBoard.new_message.message_tip}</View>
  506. </View>
  507. </View>
  508. }
  509. {
  510. moments.map((item, index) => {
  511. if (itemLayouts.length >= index + 1 && pageTop > 0) {
  512. if (Math.abs(itemLayouts[index] - pageTop) > 2000) {
  513. return <View style={{ height: itemHeights[index] }} id={`history-${index}`}>
  514. </View>
  515. }
  516. // if (Math.abs(itemLayouts[index] - pageTop) > 1500) {
  517. // return <View style={{
  518. // height: itemHeights[index], display: 'flex',
  519. // paddingLeft: rpxToPx(40),
  520. // paddingRight: rpxToPx(40),
  521. // boxSizing: 'border-box',
  522. // flexDirection: 'row'
  523. // }} id={`history-${index}`}>
  524. // <TimelineDate timestamp={item.window_range.start_timestamp}
  525. // pre_timestamp={index > 0 ? list[index - 1].window_range.start_timestamp : null}
  526. // />
  527. // <View style={{
  528. // display: 'flex', flexDirection: 'column', flex: 1,
  529. // width: rpxToPx(552), height: itemHeights[index] - rpxToPx(60), backgroundColor: '#fafafa'
  530. // }}>
  531. // </View>
  532. // </View>
  533. // }
  534. }
  535. return <View key={index} id={`history-{index}`}>
  536. <MomentItem data={item} />
  537. </View>
  538. })
  539. }
  540. <ListFooter noMore={noMore} loading={loading} />
  541. </View>
  542. {
  543. process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
  544. }
  545. </View>
  546. }
  547. return <View>
  548. {
  549. content()
  550. }
  551. <MomentShare />
  552. </View>
  553. return <View>
  554. <ScrollView scrollY style={{ height: '100vh' }}>
  555. <Button openType="share">分享</Button>
  556. <View>好友数量{count}</View>
  557. {
  558. friends.map((item, index) => {
  559. return <View key={index}>
  560. <Image src={item.avatar} style={{ width: 70, height: 70 }} />
  561. <Text>{item.nickname}</Text>
  562. <Text>{item.relation}</Text>
  563. </View>
  564. })
  565. }
  566. <View style={{ height: '100vh', backgroundColor: 'pink', width: rpxToPx(750) }} id="a"></View>
  567. <View style={{ height: '100vh', backgroundColor: 'blue', width: rpxToPx(750) }} id="b"></View>
  568. <View style={{ height: '100vh', backgroundColor: 'yellow', width: rpxToPx(750) }} id="c"></View>
  569. <View style={{ height: '100vh', backgroundColor: 'green', width: rpxToPx(750) }} id="d"></View>
  570. <View style={{ height: '100vh', backgroundColor: 'red', width: rpxToPx(750) }} id="e"></View>
  571. </ScrollView>
  572. {
  573. process.env.TARO_ENV == 'weapp' && <TabBar index={4} />
  574. }
  575. </View>
  576. }