Your Name 3 vuotta sitten
vanhempi
commit
9338741d48

+ 1
- 0
config/index.js Näytä tiedosto

@@ -28,6 +28,7 @@ const config = {
28 28
   },
29 29
   copy: {
30 30
     patterns: [
31
+      { from: 'src/native/', to: 'dist/native/' },
31 32
     ],
32 33
     options: {
33 34
     }

+ 8
- 1
src/app.jsx Näytä tiedosto

@@ -5,19 +5,26 @@ import { getLocation, getRouterParams } from '@/utils/tools'
5 5
 import login from '@/utils/login'
6 6
 import im from '@/utils/im'
7 7
 import store from './store'
8
+import trackUserSource from '@/utils/tracking/userSource'
8 9
 
9 10
 import './app.scss'
10 11
 
11 12
 class App extends Component {
13
+  // 更新埋点
14
+  updateTracking;
12 15
 
13 16
   componentDidMount () {}
14 17
 
15 18
   componentDidShow (options) {
16 19
     // 保留初始场景
17 20
     Taro.setStorage({ key: 'scene', data: options.scene })
21
+    // 埋点
22
+    trackUserSource(options).then((res) => (this.updateTracking = res))
18 23
   }
19 24
 
20
-  componentDidHide () {}
25
+  componentDidHide () {
26
+    this.updateTracking()
27
+  }
21 28
 
22 29
   componentDidCatchError () {}
23 30
 

+ 1
- 1
src/assets/css/iconfont.json Näytä tiedosto

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "id": "2603904",
3
-  "name": "新联",
3
+  "name": "新联",
4 4
   "font_family": "iconfont",
5 5
   "css_prefix_text": "icon-",
6 6
   "description": "",

+ 5
- 3
src/components/Poster/index.jsx Näytä tiedosto

@@ -85,8 +85,10 @@ export default (props) => {
85 85
   }
86 86
 
87 87
   return (
88
-    <Modal title={title} visible={show} onClose={onClose}>
89
-      <View className='modal-poster'>
88
+    // <Modal title={title} visible={show} onClose={onClose}>
89
+    // eslint-disable-next-line react/jsx-no-undef
90
+    <page-container show={show} position='bottom' onClickOverlay={onClose}>
91
+      <View className='modal-poster' onClick={onClose}>
90 92
         <View className='modal-poster-img-box'>
91 93
         {
92 94
           !processing
@@ -99,6 +101,6 @@ export default (props) => {
99 101
         </Button>
100 102
       </View>
101 103
       <Poster dataSource={dataSource} onStart={() => setProcessing(true)} onEnd={handlePoster} />
102
-    </Modal>
104
+    </page-container>
103 105
   )
104 106
 }

+ 8
- 2
src/components/Poster/style.scss Näytä tiedosto

@@ -1,6 +1,7 @@
1 1
 .modal-poster {
2 2
   width: 100vw;
3
-  height: calc(100vh - 62rpx);
3
+  height: 100vh;
4
+  // height: calc(100vh - 62rpx);
4 5
   box-sizing: border-box;
5 6
   padding: 40rpx;
6 7
 
@@ -31,4 +32,9 @@
31 32
     font-weight: 600;
32 33
     line-height: 90rpx;
33 34
   }
34
-}
35
+}
36
+
37
+page-container {
38
+  position: fixed;
39
+  z-index: 1000;
40
+}

+ 66
- 0
src/native/PageContainer/index.js Näytä tiedosto

@@ -0,0 +1,66 @@
1
+Component({
2
+  properties: {
3
+    show: {
4
+      type: Boolean,
5
+      value: false,
6
+    },
7
+    position: {
8
+      type: String,
9
+      value: 'right',
10
+    },
11
+    duration: {
12
+      type: Number,
13
+      value: 300,
14
+    },
15
+    round: {
16
+      type: Boolean,
17
+      value: false,
18
+    },
19
+    overlay: {
20
+      type: Boolean,
21
+      value: true,
22
+    },
23
+    height: {
24
+      type: String,
25
+      value: '100%',
26
+      observer: function(val) {
27
+        const h = val || '100%'
28
+        const customStyle = 'height: '+ h +';'
29
+        this.setData({ customStyle })
30
+      }
31
+    },
32
+    overlayColor: {
33
+      type: String,
34
+      value: 'black',
35
+      observer: function(val) {
36
+        let overlayStyle = ''
37
+        switch(val) {
38
+          case 'white':
39
+            overlayStyle = 'background-color: rgba(255, 255, 255, 0.7)'
40
+            break
41
+          case 'blur':
42
+            overlayStyle = 'background-color: rgba(0, 0, 0, 0.7); filter: blur(4px);'
43
+            break
44
+          default:
45
+            overlayStyle = 'background-color: rgba(0, 0, 0, 0.7)'
46
+        }
47
+        this.setData({ overlayStyle })
48
+      }
49
+    }
50
+  },
51
+  data: {
52
+    customStyle: '',
53
+    overlayStyle: ''
54
+  },
55
+  methods: {
56
+    onBeforeEnter(e) {},
57
+    onEnter(e) {},
58
+    onAfterEnter(e) {},
59
+    onBeforeLeave(e) {},
60
+    onLeave(e) {},
61
+    onAfterLeave(e) {},
62
+    onClickOverlay(e) {
63
+      this.triggerEvent('clickOverlay', e)
64
+    }
65
+  }
66
+})

+ 3
- 0
src/native/PageContainer/index.json Näytä tiedosto

@@ -0,0 +1,3 @@
1
+{
2
+  "usingComponents": {}
3
+}

+ 19
- 0
src/native/PageContainer/index.wxml Näytä tiedosto

@@ -0,0 +1,19 @@
1
+<page-container 
2
+  show="{{show}}"
3
+  round="{{round}}"
4
+  overlay="{{overlay}}"
5
+  duration="{{duration}}"
6
+  position="{{position}}"
7
+  close-on-slide-down="{{false}}"
8
+  bindbeforeenter="onBeforeEnter"
9
+  bindenter="onEnter"
10
+  bindafterenter="onAfterEnter"
11
+  bindbeforeleave="onBeforeLeave"
12
+  bindleave="onLeave"
13
+  bindafterleave="onAfterLeave"
14
+  bindclickoverlay="onClickOverlay"
15
+  custom-style="{{customStyle}}"
16
+  overlay-style="{{overlayStyle}}"
17
+>
18
+  <slot></slot>
19
+</page-container>

+ 0
- 0
src/native/PageContainer/index.wxss Näytä tiedosto


+ 3
- 3
src/pages/index/buildingDetail/components/Banner/index.jsx Näytä tiedosto

@@ -4,14 +4,14 @@ import { getImgURL } from '@/utils/image'
4 4
 import './index.scss'
5 5
 
6 6
 export default function Banner (props) {
7
-  const { List = [] } = props
7
+  const { List, onClick } = props
8 8
   return (
9 9
     <view className='components Banner'>
10 10
       <Swiper autoplay interval={2000} indicator-dots>
11 11
         {
12
-          List.map((item, index) => (
12
+          (List||[]).map((item, index) => (
13 13
             <SwiperItem key={`Banner-${index}`}>
14
-              <view className='swiper-item'>
14
+              <view className='swiper-item' onClick={() => onClick(item, List)}>
15 15
                 <Image mode='aspectFill' className='centerLabel' src={getImgURL(item.image || item.coverImg || item.url || item.img)} />
16 16
               </view>
17 17
             </SwiperItem>

+ 61
- 27
src/pages/index/buildingDetail/components/BuildingDetailBanner/index.jsx Näytä tiedosto

@@ -1,10 +1,24 @@
1 1
 import { useState } from 'react'
2
-import { Swiper, SwiperItem, Image } from '@tarojs/components'
2
+import Taro from '@tarojs/taro'
3
+import { Video } from '@tarojs/components'
3 4
 import { getImgURL } from '@/utils/image'
5
+import Banner from '../Banner'
4 6
 import './index.scss'
5 7
 
8
+const getImage = item => getImgURL(item.image || item.coverImg || item.url || item.img)
9
+
6 10
 export default function BuildingDetailBanner (props) {
7
-  const { PictureList = [{}, {}, {}] } = props
11
+  const { Info } = props
12
+  const { buildingImg, panoramaList, videoUrl, videoImage } = Info || {}
13
+  const videoPoster = videoImage ? videoImage[0] : undefined
14
+
15
+  const showPicBtn = buildingImg && buildingImg.length > 0
16
+  const showVRBtn = panoramaList && panoramaList.length > 0
17
+  const shwoVideoBtn = !!videoUrl
18
+
19
+  // JS 中 true + true = 2
20
+  const showBtns = (showPicBtn + showVRBtn + shwoVideoBtn) > 1
21
+
8 22
   const [NavList] = useState([
9 23
     { name: 'VR', id: 1 },
10 24
     { name: '视频', id: 2 },
@@ -18,33 +32,63 @@ export default function BuildingDetailBanner (props) {
18 32
     }
19 33
   }
20 34
 
35
+  const handlePreview = (item, all) => {
36
+    const img = getImage(item)
37
+    if (!img) return
38
+
39
+    Taro.previewImage({
40
+      current: img,
41
+      urls: all.map(getImage),
42
+    })
43
+  }
44
+
45
+  const handleVR = (item) => {
46
+    const url = (item || {}).panoramaLink
47
+    if (!url) return
48
+
49
+    Taro.navigateTo({
50
+      url: `/pages/index/webview/index?url=${encodeURIComponent(url)}`
51
+    })
52
+  }
53
+
21 54
   return (
22 55
     <view className='components buildingDetailBanner'>
23 56
 
24 57
       {/* 切换 */}
25
-      <view className='CutPoint'>
26
-        <view>
27
-          {
28
-            NavList.map((item, index) => (
29
-              <text key={`NavItem-${index}`} className={CurrentNavId === item.id ? 'active' : ''} onClick={CutNavId(item.id)}>{item.name}</text>
30
-            ))
31
-          }
32
-        </view>
33
-      </view>
58
+      {
59
+        showBtns && (
60
+          <view className='CutPoint'>
61
+            <view>
62
+              {
63
+                NavList.map((item, index) => (
64
+                  <text key={`NavItem-${index}`} className={CurrentNavId === item.id ? 'active' : ''} onClick={CutNavId(item.id)}>{item.name}</text>
65
+                ))
66
+              }
67
+            </view>
68
+          </view>
69
+        )
70
+      }
34 71
 
35 72
       {/* VR */}
36 73
       {
37
-        CurrentNavId === 1 &&
38
-        <view className='Vr'>
39
-
40
-        </view>
74
+        CurrentNavId === 1 && (
75
+          <view className='Vr'>
76
+            <Banner List={panoramaList} onClick={handleVR} />
77
+          </view>
78
+        )
41 79
       }
42 80
 
43 81
       {/* 视频 */}
44 82
       {
45 83
         CurrentNavId === 2 &&
46 84
         <view className='Video'>
47
-
85
+          <Video
86
+            controls
87
+            showMuteBtn
88
+            src={videoUrl}
89
+            poster={getImgURL(videoPoster)}
90
+            style={{ height: '600rpx', width: '750rpx' }}
91
+          />
48 92
         </view>
49 93
       }
50 94
 
@@ -52,17 +96,7 @@ export default function BuildingDetailBanner (props) {
52 96
       {
53 97
         CurrentNavId === 3 &&
54 98
         <view className='Picture'>
55
-          <Swiper autoplay interval={2000} indicator-dots>
56
-            {
57
-              PictureList.map((item, index) => (
58
-                <SwiperItem key={`Banner-${index}`}>
59
-                  <view className='swiper-item'>
60
-                    <Image mode='aspectFill' className='centerLabel' src={getImgURL(item.image || item.coverImg || item.url || item.img) || null} />
61
-                  </view>
62
-                </SwiperItem>
63
-              ))
64
-            }
65
-          </Swiper>
99
+          <Banner List={buildingImg} onClick={handlePreview} />
66 100
         </view>
67 101
       }
68 102
 

+ 6
- 6
src/pages/index/buildingDetail/components/DetailBottom/index.jsx Näytä tiedosto

@@ -3,17 +3,17 @@ import Taro from '@tarojs/taro'
3 3
 import { useSelector } from 'react-redux'
4 4
 import { Image } from '@tarojs/components'
5 5
 import AuthRole from '@/components/auth/AuthRole'
6
-import Poster from '@/components/Poster'
6
+// import Poster from '@/components/Poster'
7 7
 import { queryActivityList } from '@/services/activity'
8 8
 import { ROLE_CODE } from '@/constants/user'
9 9
 import './index.scss'
10 10
 
11 11
 export default function DetailBottom (props) {
12
-  const { Info = {}, poster } = props
12
+  const { Info = {}, onPoster } = props
13 13
 
14 14
   // 当前推荐置业
15 15
   const { consultant } = useSelector(s => s.system)
16
-  const [showPoster, setShowPoster] = useState(false)
16
+  // const [showPoster, setShowPoster] = useState(false)
17 17
   const [actList, setActList] = useState([])
18 18
 
19 19
   const handleCall = () => {
@@ -71,7 +71,7 @@ export default function DetailBottom (props) {
71 71
     <view>
72 72
       <view className='components DetailBottom flex-h'>
73 73
         <view className='flex-item'>
74
-          <view className='Item' onClick={() => setShowPoster(true)}>
74
+          <view className='Item' onClick={onPoster}>
75 75
             <Image mode='heightFix' src={require('@/assets/buildingDetail-icon3.png')}></Image>
76 76
             <text>一键海报</text>
77 77
           </view>
@@ -106,12 +106,12 @@ export default function DetailBottom (props) {
106 106
         </view>
107 107
       </view>
108 108
 
109
-      <Poster
109
+      {/* <Poster
110 110
         show={showPoster}
111 111
         dataSource={poster}
112 112
         onClose={() => setShowPoster(false)}
113 113
         onSuccess={() => setShowPoster(false)}
114
-      />
114
+      /> */}
115 115
     </view>
116 116
   )
117 117
 }

+ 14
- 12
src/pages/index/buildingDetail/hooks/useBuildingPoster.js Näytä tiedosto

@@ -1,23 +1,25 @@
1 1
 import { useEffect, useState } from 'react'
2 2
 import { getMiniQrcode } from '@/services/common'
3 3
 
4
-export default function useBuildingPoster(person, router, poster, paramsRef) {
4
+export default function useBuildingPoster(person, building, router, paramsRef) {
5 5
   const [posterData, setPosterData] = useState()
6 6
 
7 7
   useEffect(() => {
8
-    const page = router.path
9
-    const scene = paramsRef.current
10
-
11
-    getMiniQrcode({ page, scene }).then((miniCode) => {
12
-      setPosterData({
13
-        poster,
14
-        miniCode,
15
-        name: person.name || person.nickname,
16
-        avatar: person.avatarurl,
8
+    if (building?.buildingId) {
9
+      const page = router.path
10
+      const scene = paramsRef.current
11
+  
12
+      getMiniQrcode({ page, scene }).then((miniCode) => {
13
+        setPosterData({
14
+          poster: building?.poster,
15
+          miniCode,
16
+          name: person.name || person.nickname,
17
+          avatar: person.avatarurl,
18
+        })
17 19
       })
18
-    })
20
+    }
19 21
   // eslint-disable-next-line react-hooks/exhaustive-deps
20
-  }, [router.path, poster])
22
+  }, [building?.buildingId, router.path, building?.poster])
21 23
 
22 24
   return posterData
23 25
 }

+ 3
- 0
src/pages/index/buildingDetail/index.config.js Näytä tiedosto

@@ -1,4 +1,7 @@
1 1
 export default {
2 2
   navigationBarTitleText: '楼盘详情',
3 3
   enableShareAppMessage: true,
4
+  usingComponents: {
5
+    'page-container': '/native/PageContainer/index'
6
+  }
4 7
 }

+ 12
- 4
src/pages/index/buildingDetail/index.jsx Näytä tiedosto

@@ -2,9 +2,9 @@ import { useState, useEffect, useMemo, useRef } from 'react'
2 2
 import withLayout from '@/layout'
3 3
 import { ScrollView } from '@tarojs/components'
4 4
 import Disclaimer from '@/components/Disclaimer'
5
+import Poster from '@/components/Poster'
5 6
 import { fetch } from '@/utils/request'
6 7
 import { API_ITEMS_DETAIL, API_NEWS_LIST } from '@/constants/api'
7
-import useConsultant from '@/utils/hooks/useConsultant'
8 8
 import DetailBottom from './components/DetailBottom/index'
9 9
 import BuildingDetailBanner from './components/BuildingDetailBanner/index'
10 10
 import BasicInfo from './components/BasicInfo/index'
@@ -27,6 +27,7 @@ export default withLayout((props) => {
27 27
   const { router, person } = props
28 28
   const { id } = router.params
29 29
 
30
+  const [showPoster, setShowPoster] = useState(false)
30 31
   const [DetailInfo, setDetailInfo] = useState({})
31 32
   const [PictureList, setPictureList] = useState([])
32 33
   const [NewsList, setNewsList] = useState([])
@@ -38,7 +39,7 @@ export default withLayout((props) => {
38 39
   useBuildingShare(person, DetailInfo, router, paramsRef)
39 40
 
40 41
   // 海报
41
-  const posterData = useBuildingPoster(person, router, DetailInfo?.poster, paramsRef)
42
+  const posterData = useBuildingPoster(person, DetailInfo, router, paramsRef)
42 43
 
43 44
   useEffect(() => {
44 45
     // 获取楼盘信息
@@ -71,7 +72,7 @@ export default withLayout((props) => {
71 72
               <view className='BannerContainer'>
72 73
                 <view>
73 74
                   <view>
74
-                    <BuildingDetailBanner></BuildingDetailBanner>
75
+                    <BuildingDetailBanner Info={DetailInfo}></BuildingDetailBanner>
75 76
                   </view>
76 77
                 </view>
77 78
               </view>
@@ -139,8 +140,15 @@ export default withLayout((props) => {
139 140
       </view>
140 141
 
141 142
       <view className='PageBottom'>
142
-        <DetailBottom Info={DetailInfo} poster={posterData}></DetailBottom>
143
+        <DetailBottom Info={DetailInfo} onPoster={() => setShowPoster(true)}></DetailBottom>
143 144
       </view>
145
+
146
+      <Poster
147
+        show={showPoster}
148
+        dataSource={posterData}
149
+        onClose={() => setShowPoster(false)}
150
+        onSuccess={() => setShowPoster(false)}
151
+      />
144 152
     </view>
145 153
   )
146 154
 })

+ 1
- 1
src/pages/index/index.config.js Näytä tiedosto

@@ -1,3 +1,3 @@
1 1
 export default {
2
-  navigationBarTitleText: '新联'
2
+  navigationBarTitleText: '新联'
3 3
 }

+ 3
- 0
src/pages/index/webview/index.config.js Näytä tiedosto

@@ -0,0 +1,3 @@
1
+export default {
2
+  navigationBarTitleText: '新联家全景'
3
+}

+ 19
- 0
src/pages/index/webview/index.jsx Näytä tiedosto

@@ -0,0 +1,19 @@
1
+import React, { useEffect } from 'react'
2
+import Taro from '@tarojs/taro'
3
+import withLayout from '@/layout'
4
+import { WebView } from '@tarojs/components'
5
+
6
+export default withLayout((props) => {
7
+  const { router } = props
8
+  const { url, title } = router.params
9
+
10
+  useEffect(() => {
11
+    if (title) {
12
+      Taro.setNavigationBarTitle({ title: decodeURIComponent(title) })
13
+    }
14
+  }, [title])
15
+
16
+  return (
17
+    <WebView url={decodeURIComponent(url)} />
18
+  )
19
+})

+ 6
- 0
src/routes.js Näytä tiedosto

@@ -357,6 +357,12 @@ const routes = [
357 357
     pkg: 'main',
358 358
     type: 'mine',
359 359
   },
360
+  {
361
+    name: '全景图',
362
+    page: 'pages/index/webview/index',
363
+    pkg: 'main',
364
+    type: 'other',
365
+  },
360 366
 
361 367
 ]
362 368
 

+ 1
- 1
src/utils/hooks/useShare.js Näytä tiedosto

@@ -1,6 +1,6 @@
1 1
 import React, { useState } from 'react'
2 2
 import Taro, { useShareAppMessage } from '@tarojs/taro'
3
-import { shareTracking } from '@/utils/tracking'
3
+import shareTracking from '@/utils/tracking/share'
4 4
 
5 5
 export default function useShare(shareRef, trackRef) {
6 6
   useShareAppMessage((res) => {

+ 31
- 0
src/utils/tracking/share.js Näytä tiedosto

@@ -0,0 +1,31 @@
1
+import Taro from '@tarojs/taro'
2
+import { savePoint } from '@/services/common'
3
+import addNum from './addNum'
4
+
5
+export default (options) => {
6
+  const page = Taro.getStorageSync('page')
7
+  if (!page) return;
8
+
9
+  const { name: propertyName, type: eventType } = page
10
+  const {
11
+    event = 'share',
12
+    // eventType = '',
13
+    // propertyName = '',
14
+    consultantId = '',
15
+    sharePersonId = '',
16
+    targetId = '',
17
+    buildingId = '',
18
+  } = options
19
+
20
+  addNum({ eventType, targetId })
21
+  savePoint({
22
+    event,
23
+    eventType,
24
+    propertyName,
25
+    consultantId,
26
+    sharePersonId,
27
+    targetId,
28
+    buildingId,
29
+    data: '{}',
30
+  })
31
+}

+ 29
- 0
src/utils/tracking/userSource.js Näytä tiedosto

@@ -0,0 +1,29 @@
1
+import { savePoint, updatePoint } from '@/services/common'
2
+import { routes } from '../../routes'
3
+
4
+export default async (router) => {
5
+  const { path, query, scene } = router || {}
6
+  const { id, buildingId, recommender } = query || {}
7
+
8
+  const pageInfo = routes.filter(x => path.indexOf(x.page) > -1)[0] || { type: 'other', name: '其他' }
9
+
10
+  const trackPayload = {
11
+    event: 'start',
12
+    eventType: pageInfo.type,
13
+    propertyName: pageInfo.name,
14
+    data: '{}',
15
+    id,
16
+    buildingId,
17
+    realScene: scene,
18
+    sceneId: scene,
19
+    sharePersonId: recommender,
20
+  }
21
+
22
+  try {
23
+    const { recordId } = await savePoint(trackPayload)
24
+    return function () { updatePoint(recordId); }
25
+  } catch (e) {
26
+    console.error('进入小程序埋点出错:', e);
27
+    return function () { }
28
+  }
29
+}