Your Name 3 years ago
parent
commit
e6154de299

+ 72
- 0
src/components/Poster/Poster.jsx View File

1
+import React, { useEffect, useRef, useState } from 'react'
2
+import Taro from '@tarojs/taro'
3
+import { Canvas, View } from '@tarojs/components'
4
+import { getConfig } from './config'
5
+import posterSDKFactory from './sdk'
6
+
7
+export default (props) => {
8
+  const { dataSource, onStart, onEnd, onError } = props
9
+
10
+  const [sdk, setSDK] = useState()
11
+  const processing = useRef(false)
12
+
13
+  const config = useRef()
14
+  config.current = getConfig()
15
+
16
+  useEffect(() => {
17
+    Taro.nextTick(() => {
18
+      posterSDKFactory('#canvas-poster').then((res) => {
19
+        res.initCanvas({
20
+          ...config.current,
21
+        })
22
+        setSDK(res)
23
+      })
24
+    })
25
+  }, [])
26
+
27
+  useEffect(() => {
28
+    const { poster, miniCode, name, avatar, desc = '长按识别在线看房',  } = dataSource || {}
29
+    if (sdk && poster && !processing.current) {
30
+      onStart()
31
+      processing.current = true
32
+      const conf = config.current
33
+      
34
+      sdk.onError((err) => {
35
+        if (onError) {
36
+          onError(err)
37
+        } else {
38
+          console.error(err)
39
+        }
40
+      })
41
+
42
+      Promise.all([
43
+        sdk.getImage(poster),
44
+        sdk.getImage(miniCode),
45
+        sdk.getImage(avatar),
46
+      ]).then((res) => {
47
+        const [posterImg, miniCodeImg, avatarImg] = res
48
+
49
+        // 封面
50
+        sdk.drawImage(posterImg, conf.poster)
51
+        // 头像
52
+        sdk.drawImage(avatarImg, conf.avatar)
53
+        // 小程序码
54
+        sdk.drawImage(miniCodeImg, conf.miniCode)
55
+        // 名称
56
+        sdk.darwText(name, conf.name)
57
+        // 小程序码
58
+        sdk.darwText(desc, conf.desc)
59
+
60
+        //
61
+        const image = sdk.toDataURL()
62
+        onEnd(image, sdk)
63
+      }).catch(([e1, e2, e3]) => {
64
+        if (onError) {
65
+          onError([e1, e2, e3])
66
+        }
67
+      })
68
+    }
69
+  }, [sdk, dataSource, onStart, onEnd, onError])
70
+
71
+  return <View style={{width: 0, height: 0}}><Canvas type='2d' id='canvas-poster' /></View>
72
+}

+ 81
- 0
src/components/Poster/config.js View File

1
+import Taro, { preloadData } from '@tarojs/taro'
2
+
3
+/**
4
+ * 获取配置
5
+ * @returns 
6
+ */
7
+export function getConfig() {
8
+  // https://developers.weixin.qq.com/miniprogram/dev/api/base/system/wx.getSystemInfo.html
9
+  const systemInfo = Taro.getStorageSync('systemInfo')
10
+  const { windowWidth, pixelRatio: dpr } = systemInfo
11
+
12
+  // canvas
13
+  const canvas = {
14
+    width: windowWidth * dpr,
15
+    // 设计稿宽高比 2.16  = height / width
16
+    height: windowWidth * dpr * 2.16,
17
+  }
18
+
19
+  // 图片
20
+  const poster = {
21
+    width: canvas.width,
22
+    height: canvas.width * 16 / 9, // 图片宽高 9 : 16 占用 canvas 80%
23
+    x: 0,
24
+    y: 0,
25
+  }
26
+
27
+  const marign = 22.5 * dpr;
28
+  const innerMargin = 15 * dpr
29
+
30
+  // 头像
31
+  const avatar = {
32
+    arc: true,  // arc 代表裁剪为圆形
33
+    width: 66 * dpr,
34
+    height: 66 * dpr,
35
+    x: marign,
36
+    y: poster.height + (39 * dpr),
37
+  }
38
+
39
+  // 小程序码
40
+  const miniCode = {
41
+    arc: true,
42
+    width: 99 * dpr,
43
+    height: 99 * dpr,
44
+    x: canvas.width - (99 * dpr) - marign,  // 99 是宽度
45
+    y: poster.height + (20 * dpr),
46
+  }
47
+
48
+  // 姓名
49
+  const name = {
50
+    // https://developer.mozilla.org/zh-CN/docs/Web/CSS/font
51
+    font: `${15 * dpr}px serif`,
52
+    // https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/fillStyle
53
+    fillStyle: '#333333',
54
+
55
+    // 左右两边边距
56
+    // 左右两边文字边距
57
+    maxWidth: canvas.width - (marign * 2) - avatar.width - miniCode.width - (innerMargin * 2),
58
+
59
+    x: marign + avatar.width + innerMargin,
60
+    y: poster.height + (65 * dpr),
61
+  }
62
+
63
+  // 说明
64
+  const desc = {
65
+    font: `${10 * dpr}px serif`,
66
+    fillStyle: '#666666',
67
+    maxWidth: name.maxWidth,
68
+    x: name.x,
69
+    y: poster.height + (89.5 * dpr),
70
+  }
71
+
72
+  return {
73
+    systemInfo,
74
+    canvas,
75
+    poster,
76
+    miniCode,
77
+    avatar,
78
+    name,
79
+    desc,
80
+  }
81
+}

+ 92
- 63
src/components/Poster/index.jsx View File

1
-import React, { useEffect, useState } from 'react'
1
+import React, { useRef, useState } from 'react'
2
 import Taro from '@tarojs/taro'
2
 import Taro from '@tarojs/taro'
3
-import { Canvas, View } from '@tarojs/components'
4
-import rtLog from '@/utils/rtLog'
5
-import { getConfig, getCanvas } from './sdk'
3
+import Modal from '@/components/Modal'
4
+import { authorize } from '@/utils/wxAuth'
5
+import { View, Image, Button } from '@tarojs/components'
6
+import Spin2 from '@/components/Spin/Spin2'
7
+import Poster from './Poster'
8
+import './style.scss'
6
 
9
 
7
 export default (props) => {
10
 export default (props) => {
8
-  const { poster, miniCode, name, desc = '长按识别在线看房', onStart, onEnd } = props
11
+  const {
12
+    show,
13
+    dataSource,
14
+    onClose,
15
+    onSuccess,
16
+    title = '保存后分享图片',
17
+    btnText = '保存海报至相册',
18
+  } = props
9
 
19
 
10
-  const [posterData, setPosterData] = useState()
11
-  const [codeData, setCodeData] = useState()
12
-  const [canvas, setCanvas] = useState()
20
+  const [img, setImg] = useState()
21
+  const [processing, setProcessing] = useState(false)
22
+  const [loading, setLoading] = useState(false)
23
+  const sdkRef = useRef()
13
 
24
 
14
-  useEffect(() => {
15
-    Taro.nextTick(() => {
16
-      getCanvas('#canvas-poster').then(setCanvas)
17
-    })
18
-  }, [])
25
+  const handlePoster = (url, sdk) => {
26
+    setImg(url)
27
+    setProcessing(false)
28
+    sdkRef.current = sdk
29
+  }
19
 
30
 
20
-  useEffect(() => {
21
-    if (poster) {
22
-      Taro.downloadFile({
23
-        url: poster,
24
-        success: (res) => {
25
-          if (res.statusCode === 200) {
26
-            setPosterData(res.tempFilePath)
27
-          }
28
-        },
29
-        fail: (err) => {
30
-          rtLog.error(err)
31
-          Taro.showToast({
32
-            title: '下载海报图出错',
33
-            icon: 'none',
34
-          })
35
-        }
36
-      })
37
-    }
38
-  }, [poster])
39
-  
40
-  useEffect(() => {
41
-    if (miniCode) {
42
-      Taro.downloadFile({
43
-        url: miniCode,
44
-        success: (res) => {
45
-          if (res.statusCode === 200) {
46
-            setCodeData(res.tempFilePath)
47
-          }
48
-        },
49
-        fail: (err) => {
50
-          rtLog.error(err)
51
-          Taro.showToast({
52
-            title: '下载海报二维码出错',
53
-            icon: 'none',
54
-          })
55
-        }
31
+  const handleSave = () => {
32
+    if (!img) {
33
+      Taro.showToast({
34
+        title: '海报未生成, 请稍后',
35
+        icon: 'none',
56
       })
36
       })
37
+      return
57
     }
38
     }
58
-  }, [miniCode])
59
 
39
 
60
-  useEffect(() => {
61
-    if (canvas && posterData && codeData) {
62
-      onStart()
63
-      const config = getConfig()
64
-      const dpr = config.systemInfo.pixelRatio
65
-      const ctx = canvas.getContext('2d')
66
-      canvas.width = config.canvas.width
67
-      canvas.height = config.canvas.height
68
-      ctx.scale(dpr, dpr)
40
+    authorize('scope.writePhotosAlbum').then(() => {
41
+      setLoading(true)
69
 
42
 
70
-      //
71
-    }
72
-  }, [canvas, posterData, codeData, onStart, onEnd])
43
+      // 先生成到临时位置
44
+      sdkRef.current.download().then((tempPath) => {
45
+        // 再保存到相册
46
+        Taro.saveImageToPhotosAlbum({
47
+          filePath: tempPath,
48
+          success: () => {
49
+            Taro.showToast({
50
+              title: '保存成功',
51
+              icon: 'none',
52
+              duration: 3000,
53
+            })
54
+            onSuccess()
55
+          },
56
+          fail: (err) => {
57
+            console.error(err)
58
+            const message = err.errMsg || err.message || err
59
+            Taro.showToast({
60
+              title: message,
61
+              icon: 'none',
62
+            })
63
+          },
64
+          complete: () => {
65
+            setLoading(false)
66
+          }
67
+        })
68
+      }).catch((err) => {
69
+        setLoading(false)
70
+        console.error(err)
71
+        const message = err.errMsg || err.message || err
72
+        Taro.showToast({
73
+          title: message,
74
+          icon: 'none',
75
+        })
76
+      })
77
+    }).catch((err) => {
78
+      console.error(err)
79
+      const message = err.errMsg || err.message || err
80
+      Taro.showToast({
81
+        title: message,
82
+        icon: 'none',
83
+      })
84
+    })
85
+  }
73
 
86
 
74
-  return <View style={{width: 0, height: 0}}><Canvas type='2d' id='canvas-poster' /></View>
87
+  return (
88
+    <Modal title={title} visible={show} onClose={onClose}>
89
+      <View className='modal-poster'>
90
+        <View className='modal-poster-img-box'>
91
+        {
92
+          !processing
93
+            ? <Image src={img} mode='scaleToFill' onClick={() => Taro.previewImage({ current: img, urls: [img] })} />
94
+            : <Spin2 spinning={processing} size={32} />
95
+        }
96
+        </View>
97
+        <Button className='modal-poster-action' onClick={handleSave} disabled={!img} loading={loading}>
98
+          {btnText}
99
+        </Button>
100
+      </View>
101
+      <Poster dataSource={dataSource} onStart={() => setProcessing(true)} onEnd={handlePoster} />
102
+    </Modal>
103
+  )
75
 }
104
 }

+ 121
- 92
src/components/Poster/sdk.js View File

1
 import Taro from '@tarojs/taro'
1
 import Taro from '@tarojs/taro'
2
 
2
 
3
-/**
4
- * 获取配置
5
- * @returns 
6
- */
7
-export function getConfig() {
8
-  // https://developers.weixin.qq.com/miniprogram/dev/api/base/system/wx.getSystemInfo.html
9
-  const systemInfo = Taro.getStorageSync('systemInfo')
10
-  const { windowWidth, pixelRatio } = systemInfo
3
+export default function factory(selector) {
4
+  return new Promise((resolve) => {
5
+    const query = Taro.createSelectorQuery()
6
+    query.select(selector)
7
+      .node((res) => {
8
+        const canvas = res.node
9
+        resolve(posterSDK(canvas))
10
+      })
11
+      .exec()
12
+  })
13
+}
11
 
14
 
12
-  // canvas
13
-  const canvas = {
14
-    width: windowWidth * pixelRatio,
15
-    // 设计稿宽高比 2.16  = height / width
16
-    height: windowWidth * pixelRatio * 2.16,
17
-  }
15
+export function posterSDK(canvas) {
16
+  let onError = (err) => console.error(err);
17
+  const ctx = canvas.getContext('2d')
18
+
19
+  /**
20
+   * 初始化 canvas
21
+   * @param {*} config 
22
+   */
23
+  function initCanvas(config) {
24
+    canvas.width = config.canvas.width
25
+    canvas.height = config.canvas.height
18
 
26
 
19
-  // 图片
20
-  const image = {
21
-    width: canvas.width,
22
-    height: canvas.width * 16 / 9, // 图片宽高 9 : 16
23
-    x: 0,
24
-    y: 0,
27
+    // 默认白色背景
28
+    ctx.fillStyle="#FFFFFF";
29
+    ctx.fillRect(0, 0, canvas.width, canvas.height)
30
+    ctx.save()
25
   }
31
   }
26
 
32
 
27
-  // 头像
28
-  const avatar = {
29
-    width: 88,
30
-    height: 88,
31
-    x: 30,
32
-    y: image.height + 50,
33
+  /**
34
+   * 生成 canvas 可用 image
35
+   * @param {*} canvas 
36
+   * @param {*} url 
37
+   * @returns 
38
+   */
39
+  function getImage(url) {
40
+    return new Promise((resolve, reject) => {
41
+      Taro.downloadFile({
42
+        url,
43
+        success: (res) => {
44
+          if (res.statusCode === 200) {
45
+            const image = canvas.createImage()
46
+            image.onload = () => resolve(image)
47
+            image.onerror = (err) => {
48
+              onError('importImage', err)
49
+              reject(err)
50
+            }
51
+            image.src = res.tempFilePath
52
+          }
53
+        },
54
+        fail: (err) => {
55
+          onError('downloadImage', err)
56
+          reject(err)
57
+        }
58
+      })
59
+    })
33
   }
60
   }
34
 
61
 
35
-  // 小程序码
36
-  const miniCode = {
37
-    width: 132,
38
-    height: 132,
39
-    x: canvas.width - 132 - 30,  // 128 是宽度, 30 是右边距
40
-    y: image.height + 50,
62
+  /**
63
+   * 绘制图像
64
+   * @param {*} ctx 
65
+   * @param {*} image 
66
+   * @param {*} conf 
67
+   */
68
+  function drawImage(image, conf) {
69
+    ctx.save()
70
+    if (conf.arc) {
71
+      // 圆心
72
+      const x = conf.x + conf.width / 2
73
+      const y = conf.y + conf.height / 2
74
+      const r = conf.width / 2
75
+      ctx.arc(x, y, r, 0, 2 * Math.PI)
76
+      ctx.clip()
77
+    }
78
+    
79
+    ctx.drawImage(image, conf.x, conf.y, conf.width, conf.height)
80
+    ctx.restore()
41
   }
81
   }
42
 
82
 
43
-  // 姓名
44
-  const name = {
45
-    // https://developer.mozilla.org/zh-CN/docs/Web/CSS/font
46
-    font: '28px',
47
-    // https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/fillStyle
48
-    fillStyle: '#333333',
83
+  /**
84
+   * 绘制文字
85
+   * @param {*} ctx 
86
+   * @param {*} text 
87
+   * @param {*} conf 
88
+   */
89
+  function darwText(text, conf) {
90
+    ctx.fillStyle = conf.fillStyle
91
+    ctx.font = conf.font
92
+    ctx.fillText(text, conf.x, conf.y, conf.maxWidth)
93
+  }
49
 
94
 
50
-    // 60 是头像左边距 + 小程序码右边距
51
-    // 40 是文字距离头像的左边距 20 + 距离小程序码的右边距 20
52
-    maxWidth: canvas.width - 60 - avatar.width - miniCode.width - 40,
95
+  /**
96
+   * canvas 转为图片
97
+   * @param {*} type 
98
+   * @param {*} encoderOptions 
99
+   * @returns 
100
+   */
101
+  function toDataURL(type = 'image/jpeg', encoderOptions = 0.8) {
102
+    return canvas.toDataURL(type, encoderOptions)
103
+  }
53
 
104
 
54
-    x: image.height + 66,
55
-    // 30 是头像左边距, 20 文字距离头像的左边距
56
-    y: 30 + avatar.width + 20,
105
+  /**
106
+   * 下载到本地
107
+   * @param {*} options 
108
+   * @returns 
109
+   */
110
+  function download(options) {
111
+    return new Promise((resovle, reject) => {
112
+      Taro.canvasToTempFilePath({
113
+        canvas,
114
+        fileType: 'jpg',
115
+        quality: 0.8,
116
+        ...(options || {}),
117
+        success: (res) => resovle(res.tempFilePath),
118
+        fail: (err) => {
119
+          onError('exportImage', err)
120
+          reject(err)
121
+        },
122
+      })
123
+    })
57
   }
124
   }
58
 
125
 
59
-  // 说明
60
-  const desc = {
61
-    font: '20px',
62
-    fillStyle: '#666666',
63
-    maxWidth: name.maxWidth,
64
-    x: name.x,
65
-    y: image.height + 106,
126
+  function listenError(callback) {
127
+    onError = callback
66
   }
128
   }
67
 
129
 
68
   return {
130
   return {
69
-    systemInfo,
70
     canvas,
131
     canvas,
71
-    image,
72
-    miniCode,
73
-    name,
74
-    desc,
132
+    ctx,
133
+    initCanvas,
134
+    download,
135
+    getImage,
136
+    drawImage,
137
+    darwText,
138
+    toDataURL,
139
+    onError: listenError,
75
   }
140
   }
76
 }
141
 }
77
-
78
-/**
79
- * 绘制图像
80
- * @param {*} ctx 
81
- * @param {*} image 
82
- * @param {*} config 
83
- */
84
-export function drawImage(ctx, image, config) {
85
-  ctx.drawImage(image, config.x, config.y, config.width, config.height)
86
-}
87
-
88
-/**
89
- * 绘制文字
90
- * @param {*} ctx 
91
- * @param {*} text 
92
- * @param {*} config 
93
- */
94
-export function darwText(ctx, text, config) {
95
-  ctx.setFillStyle(config.fillStyle)
96
-  ctx.font = config.font
97
-  ctx.fillText(text, config.x, config.y, config.maxWidth)
98
-}
99
-
100
-/**
101
- * 获取 canvas
102
- * @param {*} selector 
103
- * @returns 
104
- */
105
-export function getCanvas(selector) {
106
-  return new Promise((resolve) => {
107
-    const query = Taro.createSelectorQuery()
108
-    query.select(selector)
109
-      .node((res) => resolve(res.node))
110
-      .exec()
111
-  })
112
-}

+ 34
- 0
src/components/Poster/style.scss View File

1
+.modal-poster {
2
+  width: 100vw;
3
+  height: calc(100vh - 62rpx);
4
+  box-sizing: border-box;
5
+  padding: 40rpx;
6
+
7
+  &-img-box {
8
+    flex: auto;
9
+    width: 70%;
10
+    height: calc(100% - 92rpx - 40rpx);
11
+    margin: 0 auto;
12
+    background: #fff;
13
+    box-shadow: 0 14rpx 24rpx 0 rgba(0, 0, 0, 0.2);
14
+    position: relative;
15
+
16
+    image {
17
+      width: 100%;
18
+      height: 100%;
19
+    }
20
+  }
21
+
22
+  &-action {
23
+    margin-top: 40rpx;
24
+    width: 100%;
25
+    height: 92rpx;
26
+    background: #193C83;
27
+    border-radius: 46rpx;
28
+    text-align: center;
29
+    color: #fff;
30
+    font-size: 30rpx;
31
+    font-weight: 600;
32
+    line-height: 90rpx;
33
+  }
34
+}

+ 2
- 2
src/components/Spin/style.scss View File

123
 
123
 
124
   .spin2 {
124
   .spin2 {
125
     display: inline-block;
125
     display: inline-block;
126
-    margin: auto;
127
     position: absolute;
126
     position: absolute;
127
+    left: 50%;
128
     top: 50%;
128
     top: 50%;
129
-    transform: translateY(-50%);
129
+    transform: translate(-50%, -50%);
130
   }
130
   }
131
 }
131
 }

+ 11
- 4
src/pages/index/buildingDetail/components/DetailBottom/index.jsx View File

1
-import React from 'react'
1
+import React, { useState } from 'react'
2
 import Taro from '@tarojs/taro'
2
 import Taro from '@tarojs/taro'
3
 import { useSelector } from 'react-redux'
3
 import { useSelector } from 'react-redux'
4
 import { Image } from '@tarojs/components'
4
 import { Image } from '@tarojs/components'
8
 import './index.scss'
8
 import './index.scss'
9
 
9
 
10
 export default function DetailBottom (props) {
10
 export default function DetailBottom (props) {
11
-  const { Info = {} } = props
11
+  const { Info = {}, poster } = props
12
 
12
 
13
   // 当前推荐置业
13
   // 当前推荐置业
14
   const { consultant } = useSelector(s => s.system)
14
   const { consultant } = useSelector(s => s.system)
15
+  const [showPoster, setShowPoster] = useState(false)
15
 
16
 
16
   const handleCall = () => {
17
   const handleCall = () => {
17
     if (Info.tel) {
18
     if (Info.tel) {
47
   return (
48
   return (
48
     <view>
49
     <view>
49
       <view className='components DetailBottom flex-h'>
50
       <view className='components DetailBottom flex-h'>
50
-        <view className='Item'>
51
+        <view className='Item' onClick={() => setShowPoster(true)}>
51
           <Image mode='heightFix' src={require('@/assets/buildingDetail-icon3.png')}></Image>
52
           <Image mode='heightFix' src={require('@/assets/buildingDetail-icon3.png')}></Image>
52
           <text>一键海报</text>
53
           <text>一键海报</text>
53
         </view>
54
         </view>
67
           <text className='active' onClick={handleCall}>一键电话</text>
68
           <text className='active' onClick={handleCall}>一键电话</text>
68
         </view>
69
         </view>
69
       </view>
70
       </view>
70
-      <Poster />
71
+
72
+      <Poster
73
+        show={showPoster}
74
+        dataSource={poster}
75
+        onClose={() => setShowPoster(false)}
76
+        onSuccess={() => setShowPoster(false)}
77
+      />
71
     </view>
78
     </view>
72
   )
79
   )
73
 }
80
 }

+ 18
- 4
src/pages/index/buildingDetail/index.jsx View File

1
-import { useState, useEffect } from 'react'
1
+import { useState, useEffect, useMemo } from 'react'
2
 import withLayout from '@/layout'
2
 import withLayout from '@/layout'
3
 import { ScrollView } from '@tarojs/components'
3
 import { ScrollView } from '@tarojs/components'
4
 import Disclaimer from '@/components/Disclaimer'
4
 import Disclaimer from '@/components/Disclaimer'
20
 import './index.scss'
20
 import './index.scss'
21
 
21
 
22
 export default withLayout((props) => {
22
 export default withLayout((props) => {
23
-  const { id } = props.router.params
23
+  const { router, person } = props
24
+  const { id } = router.params
24
 
25
 
25
   const [DetailInfo, setDetailInfo] = useState({})
26
   const [DetailInfo, setDetailInfo] = useState({})
26
   const [PictureList, setPictureList] = useState([])
27
   const [PictureList, setPictureList] = useState([])
29
   const [IsPull, setPull] = useState(false)
30
   const [IsPull, setPull] = useState(false)
30
   const [PullTimer, setPullTimer] = useState(null)
31
   const [PullTimer, setPullTimer] = useState(null)
31
 
32
 
33
+  const posterData = useMemo(() => {
34
+    if (!DetailInfo?.poster) {
35
+      return undefined
36
+    }
37
+
38
+    return {
39
+      name: person.name || person.nickname,
40
+      avatar: person.avatarurl,
41
+      poster: DetailInfo?.poster,
42
+      miniCode: DetailInfo?.poster,
43
+    }
44
+
45
+  }, [DetailInfo?.poster, person.avatarurl, person.name, person.nickname])
46
+
32
   useEffect(() => {
47
   useEffect(() => {
33
     // 获取楼盘信息
48
     // 获取楼盘信息
34
     fetch({ url: `${API_ITEMS_DETAIL}/${id}`, spin: true }).then((res) => {
49
     fetch({ url: `${API_ITEMS_DETAIL}/${id}`, spin: true }).then((res) => {
140
       </view>
155
       </view>
141
 
156
 
142
       <view className='PageBottom'>
157
       <view className='PageBottom'>
143
-        <DetailBottom Info={DetailInfo}></DetailBottom>
158
+        <DetailBottom Info={DetailInfo} poster={posterData}></DetailBottom>
144
       </view>
159
       </view>
145
-
146
     </view>
160
     </view>
147
   )
161
   )
148
 })
162
 })

+ 1
- 0
src/routes.js View File

66
     page: 'pages/index/buildingDetail/index',
66
     page: 'pages/index/buildingDetail/index',
67
     pkg: 'main',
67
     pkg: 'main',
68
     type: 'building',
68
     type: 'building',
69
+    auth: ['phone', 'avatar'],
69
   },
70
   },
70
   {
71
   {
71
     name: '楼盘信息',
72
     name: '楼盘信息',

+ 25
- 0
src/utils/wxAuth.js View File

1
+import Taro from '@tarojs/taro'
2
+
3
+// https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/authorize.html
4
+/**
5
+ * 微信授权
6
+ * @param {*} scope 
7
+ */
8
+export function authorize(scope) {
9
+  return new Promise((resolve, reject) => {
10
+    Taro.getSetting({
11
+      success: function (res) {
12
+        if (!res.authSetting[scope]) {
13
+          Taro.authorize({
14
+            scope,
15
+            success: resolve,
16
+            fail: reject,
17
+          })
18
+        } else {
19
+          resolve()
20
+        }
21
+      },
22
+      fail: reject,
23
+    })
24
+  })
25
+}