浏览代码

Merge branch 'v4' of http://git.ycjcjy.com/zhiyuxing/miniapp-v3 into v4

许静 5 年前
父节点
当前提交
51dc597f99
共有 5 个文件被更改,包括 512 次插入363 次删除
  1. 4
    1
      src/constants/api.js
  2. 432
    284
      src/pages/activity/detail/assemble.js
  3. 46
    77
      src/pages/activity/detail/assistance.js
  4. 8
    1
      src/services/activity.js
  5. 22
    0
      src/utils/tools.js

+ 4
- 1
src/constants/api.js 查看文件

@@ -149,4 +149,7 @@ export const API_HELP_DETAIL = resolvePath('helpActivity')
149 149
 export const API_HELP_CREATE = resolvePath('helpInitiateRecord')
150 150
 export const API_HELP_FRIEND = resolvePath('helpRecord')
151 151
 
152
-//
152
+// 拼团
153
+export const API_GROUP_DETAIL = resolvePath('taShareActivity')
154
+export const API_GROUP_CREATE = resolvePath('taShareRecord')
155
+export const API_GROUP_JOIN = resolvePath('taShareChildRecord')

+ 432
- 284
src/pages/activity/detail/assemble.js 查看文件

@@ -1,19 +1,18 @@
1 1
 import Taro, { Component } from '@tarojs/taro';
2 2
 import './index.scss'
3 3
 import Notice from '@components/Notice'
4
-import BackHomeBtn from '@components/BackHomeBtn'
5
-import Poster from './poster'
4
+// import BackHomeBtn from '@components/BackHomeBtn'
5
+import AchievePhone from '@components/achievePhone'
6
+import Poster from '@components/Poster'
6 7
 import dayjs from 'dayjs'
7
-import WxParse from '@components/wxParse/wxParse'
8
-import getUserPhone from '@utils/getUserPhone'
8
+// import WxParse from '@components/wxParse/wxParse'
9
+// import getUserPhone from '@utils/getUserPhone'
9 10
 import ready from '@utils/ready'
10
-import { getDownloadURL } from '@utils/tools'
11
+import { getDownloadURL, times, formateLeftTime } from '@utils/tools'
11 12
 import {
12
-  addActivityShareNum,
13
-  signupActivity,
14
-  favorActivity,
15
-  cancelFavorActivity,
16
-  queryActivityDetail
13
+  getGroupDetail,
14
+  createGroupActivity,
15
+  joinGroupBuy,
17 16
 } from '@services/activity'
18 17
 import {
19 18
   getMiniQrcode,
@@ -22,6 +21,16 @@ import {
22 21
 } from '@services/common'
23 22
 import { connect } from '@tarojs/redux'
24 23
 
24
+// 活动状态
25
+const ActBeforeStart = 0;
26
+const ActInProcess = 1;
27
+const ActFinished = 2;
28
+
29
+// 发起的拼团状态
30
+const GroupInProcess = 1;
31
+const GroupSuccess = 0;
32
+const GroupFailure = 2;
33
+
25 34
 @connect(state => state.user)
26 35
 export default class Detail extends Component {
27 36
   config = {
@@ -29,364 +38,503 @@ export default class Detail extends Component {
29 38
   }
30 39
 
31 40
   state = {
32
-    id: null,
41
+    id: null, // 活动ID
42
+    recordId: undefined,  // 发起拼团ID
33 43
     loaded: false,
34
-    detail: {},
35
-    recordId: null,
36
-    isSaved: false,
37
-    isSign: false,
38
-    posterShow: false,
39
-    posterData: {},
40
-    posterVisible: false,
41
-    selector: ['1', '2', '3'],
42
-    selectorChecked: '1',
43
-    canChoose: 'none',
44
-    inputName: ''
44
+    detail: {}, // 活动详情
45
+    recordDetail: {}, // 发团记录
46
+    memberList: [], // 团员记录
47
+    shares: [], // 分享设置
48
+    posters: [], // 海报模板
49
+    leftTime: 0,  // 剩余时间
50
+    ltTicker: undefined,  // 剩余时间计时器
51
+    actState: ActBeforeStart,  // 活动本身状态
52
+    groupState: GroupInProcess, // 发起拼团活动的状态
53
+    isStarter: true, // 是否发起人
54
+    submitting: false, // 是否提交中
55
+    actionSheetVisible: false, // 底部分享好友
56
+    posterVisible: false, // 海报分享
57
+    grantPhoneVisible: false, // 授权电话
58
+    grantAvatarVisible: false, // 授权头像
45 59
   }
46 60
 
47 61
   componentWillMount() {
48 62
     ready.queue(() => {
49
-      const router = Taro.getStorageSync('router')
50
-      const id = this.$router.params.id || router.query.id || '2fe920719b8b0db50011441462e647ad'
51
-      this.setState({ id }, () => {
52
-        this.loadDetail()
53
-      })
63
+      // 必须授权电话
64
+      if (this.toggleGrantPhone()) {
65
+        this.initPageData()
66
+      }
54 67
     })
55 68
   }
69
+
56 70
   componentWillUnmount() {
57
-    const { recordId } = this.state
58
-    recordId && updatePoint(recordId)
71
+    this.clearTicker()
59 72
   }
60 73
 
61
-  loadDetail() {
62
-    const { id } = this.state
63
-    Taro.showLoading()
64
-    queryActivityDetail(id).then(res => {
65
-      Taro.hideLoading()
66
-      const { isSaved, isSign } = res
67
-      this.setState({
68
-        detail: res,
69
-        isSaved,
70
-        isSign,
71
-        loaded: true
72
-      }, () => {
73
-        const { detail } = this.state
74
-        if (detail.posters[0].posterImg) {
75
-          this.setState({
76
-            posterShow: true
77
-          })
78
-        }
79
-      })
80
-      WxParse.wxParse('article', 'html', res.desc, this.$scope, 0)
81
-
82
-      savePoint({
83
-        event: 'detail',
84
-        eventType: 'activity',
85
-        propertyName: '活动详情',
86
-        buildingId: res.buildingId,
87
-        targetId: res.dynamicId,
88
-        data: '{}'
89
-      }).then(res1 => {
90
-        this.setState({
91
-          recordId: res1.recordId
92
-        })
93
-        console.log('活动详情')
74
+  // 初始化页面数据
75
+  initPageData = () => {
76
+    if (!this.state.detail.groupActivityId) {
77
+      const router = Taro.getStorageSync('router')
78
+      const id = this.$router.params.id || router.query.id
79
+      const recordId = this.$router.params.recordId || router.query.recordId
80
+
81
+      this.setState({ id, recordId }, () => {
82
+        this.loadDetail()
94 83
       })
95
-    })
84
+    }
96 85
   }
97
-  onShareAppMessage = () => {
98
-    const { detail: { shareContents, title, dynamicId, url } } = this.state
99
-    const { userInfo: { person: { personId } } } = this.props
100
-
101
-    addActivityShareNum(dynamicId)
102 86
 
103
-    savePoint({
104
-      event: 'share',
105
-      eventType: 'activity',
106
-      propertyName: '活动详情分享',
107
-      data: '{}'
108
-    }).then(res => {
109
-      console.log('活动详情分享')
110
-    })
111
-    return {
112
-      title: shareContents[0].shareContentTitle,
113
-      path: `/pages/activity/detail/index?id=${dynamicId}&from=dynamic_share&recommender=${personId}`,//分享地址
114
-      imageUrl: shareContents[0].shareContentImg
87
+  // 清除 ticker
88
+  clearTicker() {
89
+    if (this.state.ltTicker) {
90
+      clearInterval(this.state.ltTicker)
91
+      this.setState({ ltTicker: undefined })
115 92
     }
116 93
   }
117 94
 
118
-  handleSignup() {
119
-    const { detail: { buildingId, dynamicId }, isSign } = this.state
120
-    const { userInfo: { person: { phone, name, nickname } } } = this.props
95
+  // 调起授权电话
96
+  toggleGrantPhone = () => {
97
+    const { userInfo: { person: { phone } } } = this.props
98
+    if (!phone) {
99
+      this.setState({ grantPhoneVisible: true })
100
+      return false
101
+    }
121 102
 
122
-    if (isSign) {
123
-      Taro.showToast({
124
-        icon: 'none',
125
-        title: '你已报名成功'
126
-      })
127
-      return
103
+    return true
104
+  }
105
+
106
+  // 调起授权头像
107
+  toggleGrantAvatar = () => {
108
+    const { userInfo: { person: { avatarurl } } } = this.props
109
+    if (!avatarurl) {
110
+      this.setState({ grantAvatarVisible: true })
111
+      return false
128 112
     }
129 113
 
114
+    return true
115
+  }
116
+  
117
+  // 打开关闭 ActionSheet 面板
118
+  toggleActionVisible = () => {
130 119
     this.setState({
131
-      canChoose: 'block'
120
+      actionSheetVisible: !this.state.actionSheetVisible
132 121
     })
133 122
   }
134 123
 
135
-  handleFavor() {
136
-    const { detail: { dynamicId }, isSaved } = this.state
137
-    if (isSaved) {
138
-      cancelFavorActivity(dynamicId).then(res => {
139
-        Taro.showToast({
140
-          title: '已取消收藏'
141
-        })
142
-        this.setState({
143
-          isSaved: false
144
-        })
145
-      })
124
+  // 打开关闭海报面板
125
+  togglePosterVisible = () => {
126
+    this.setState({
127
+      posterVisible: !this.state.posterVisible,
128
+      actionSheetVisible: false
129
+    })
130
+  }
131
+
132
+  compActState = (startDate, endDate) => {
133
+    const st = dayjs(startDate).valueOf()
134
+    const ed = dayjs(endDate).valueOf()
135
+    const nw = dayjs().valueOf()
136
+
137
+    if (st > nw) {
138
+      // 活动未开始
139
+      return [ActBeforeStart, st - nw]
140
+    } else if (ed > nw) {
141
+      // 活动进行中
142
+      return [ActInProcess, ed - nw]
146 143
     } else {
147
-      favorActivity(dynamicId).then(res => {
148
-        Taro.showToast({
149
-          title: '收藏成功'
150
-        })
151
-        this.setState({
152
-          isSaved: true
153
-        })
154
-      })
144
+      // 活动已结束
145
+      return [ActFinished, 0]
155 146
     }
156
-    savePoint({
157
-      event: 'save',
158
-      eventType: 'activity',
159
-      propertyName: '活动详情收藏',
160
-      data: '{}'
161
-    }).then(res => {
162
-      console.log('活动详情收藏')
163
-    })
164 147
   }
165 148
 
166
-  handleGetPhone(e) {
167
-    getUserPhone(e, (phoneNumber) => {
168
-      if (phoneNumber) {
169
-        this.handleSignup()
170
-      } else {
171
-        Taro.showToast({
172
-          title: '报名失败',
173
-          icon: 'none'
174
-        })
175
-      }
149
+  // 计时器更新剩余时间
150
+  updateLeftTime(startDate, endDate) {
151
+    this.setState({
152
+      ltTicker: setInterval(() => {
153
+        const [actState, leftTime] = this.compActState(startDate, endDate)
154
+        this.setState({actState, leftTime})
155
+
156
+        if (actState === ActFinished) {
157
+          this.clearTicker()
158
+        }
159
+      }, 1000)
176 160
     })
177 161
   }
178
-  getPosterData = () => {
179
-    return new Promise(resolve => {
180
-      const { posterData } = this.state
181
-      if (posterData.qrcode) {
182
-        resolve(posterData)
183
-        return
184
-      }
185 162
 
186
-      const { userInfo: { person } } = this.props
187
-      const { avatarurl, nickname, personId } = person
188
-      const { detail: { dynamicId, posters, createDate } } = this.state
189
-      const payload = {
190
-        "scene": `id=${dynamicId}&from=dynamic_share&recommender=${personId}`,
191
-        "page": 'pages/activity/detail/index',
163
+  loadDetail() {
164
+    const { id, recordId } = this.state
165
+    const { userInfo } = this.props
166
+
167
+    Taro.showLoading()
168
+    getGroupDetail(id, recordId).then(res => {
169
+      this.clearTicker()
170
+
171
+      const recordDetail = res.taShareRecord || {}
172
+      let [actState, leftTime] = this.compActState(res.taShareActivity.startTime, res.taShareActivity.endTime)
173
+
174
+      if (res.taShareActivity.status != 1) {
175
+        actState = ActFinished
192 176
       }
193
-      debugger
194
-      const _avatarurl = getDownloadURL(avatarurl, 'avatar');
195
-      getMiniQrcode(payload).then(qrcode => {
196
-        let data = {
197
-          qrcode,//小程序二维码
198
-          nickname,//访问者名字
199
-          avatarurl: _avatarurl,//访问者头像
200
-          poster: posters[0].posterImg,
201
-          title: posters[0].posterTitle,//海报标题
202
-          createDate: createDate,//时间
203
-        }
204
-        resolve(data)
177
+
178
+      Taro.hideLoading()
179
+      this.setState({
180
+        detail: res.taShareActivity,
181
+        recordDetail,
182
+        recordId: recordDetail.recordId,
183
+        groupState: recordDetail.status === undefined ? GroupInProcess : recordDetail.status,
184
+        shares: res.shareContentList || [],
185
+        posters: res.postList || [],
186
+        posterTpls: res.posterTemplateList || [],
187
+        memberList: res.shareChildRecordList || [],
188
+        loaded: true,
189
+        isStarter: !recordDetail.personId || userInfo.person.personId === recordDetail.personId,
190
+        actState,
191
+        leftTime,
205 192
       })
193
+
194
+      if (actState != ActFinished) {
195
+        this.updateLeftTime(res.taShareActivity.startTime, res.taShareActivity.endTime)
196
+      }
197
+
198
+      // WxParse.wxParse('article', 'html', res.desc, this.$scope, 0)
199
+
200
+      // savePoint({
201
+      //   event: 'detail',
202
+      //   eventType: 'group',
203
+      //   propertyName: '拼团详情',
204
+      //   buildingId: res.buildingId,
205
+      //   targetId: res.groupActivityId,
206
+      //   data: '{}'
207
+      // }).then(res1 => {
208
+      //   this.setState({
209
+      //     recordId: res1.recordId
210
+      //   })
211
+      // })
206 212
     })
207 213
   }
208
-  // 开始生成海报
209
-  togglePosterStatus = (flag) => {
210
-    if (flag) {
211
-      this.getPosterData().then(posterData => {
212
-        this.setState({
213
-          posterVisible: !!flag,
214
-          posterData
215
-        })
216
-      })
217
-      // App.zhuge.track('生成活动详情海报')
218
-    } else {
219
-      this.setState({
220
-        posterVisible: !!flag
221
-      })
214
+
215
+  currentPageAndParams() {
216
+    const { id, recordId } = this.state
217
+    const { userInfo: { person: { personId } } } = this.props
218
+
219
+    let queryParams = [
220
+      `id=${id}`,
221
+      `from=group_share`,
222
+      `recommender=${personId}`
223
+    ]
224
+    if (recordId) {
225
+      queryParams.push(`recordId=${recordId}`)
222 226
     }
227
+
228
+    const res = [
229
+      'pages/activity/detail/assemble',
230
+      queryParams.join('&'),
231
+    ]
232
+
233
+    console.log('--page-params->', res)
234
+    return res
235
+  }
236
+
237
+
238
+  onShareAppMessage = () => {
239
+    const { shares } = this.state
240
+    const currentPage = this.currentPageAndParams().join('?')
241
+
223 242
     savePoint({
224
-      event: 'poster',
225
-      eventType: 'activity',
226
-      propertyName: '生成活动详情海报',
243
+      event: 'share',
244
+      eventType: 'group',
245
+      propertyName: '拼团详情分享',
227 246
       data: '{}'
228
-    }).then(res => {
229
-      console.log('生成活动详情海报')
230 247
     })
231
-  }
232 248
 
233
-  handleMoreClick() {
234
-    // App.zhuge.track('查看置业顾问列表')
235
-    console.log()
236
-    Taro.navigateTo({
237
-      url: `/pages/card/list/index?buildingId=${this.$router.params.buildingId}`
238
-    })
239
-  }
249
+    if (!shares || !shares.length) {
250
+      return {
251
+        title: this.state.detail.activityName,
252
+        path: currentPage,//分享地址
253
+        imageUrl: this.state.detail.mainImg
254
+      }
255
+    }
240 256
 
241
-  onChange = e => {
242
-    this.setState({
243
-      selectorChecked: this.state.selector[e.detail.value]
244
-    })
257
+    return {
258
+      title: shares[0].shareContentTitle,
259
+      path: currentPage,//分享地址
260
+      imageUrl: shares[0].shareContentImg
261
+    }
245 262
   }
263
+  
264
+  // 立即参团
265
+  joinGroup = () => {
266
+    if (this.state.submitting) return
246 267
 
247
-  onInputText = e => {
248
-    this.setState({
249
-      inputName: e.detail.value
268
+    Taro.showLoading()
269
+    this.setState({ submitting: true }, () => {
270
+      const { detail, recordDetail } = this.state
271
+      const person = this.props.userInfo.person
272
+
273
+      joinGroupBuy({
274
+        recordId: recordDetail.recordId,
275
+        groupActivityId: detail.groupActivityId,
276
+        personId: person.personId,
277
+        nickname: person.name || person.nickname,
278
+        phone: person.tel || person.phone,
279
+        avatarurl: person.avatarurl,
280
+      }).then((res) => {
281
+        Taro.hideLoading()
282
+        const memberList = this.state.memberList || []
283
+        memberList.push(res.taShareChildRecord)
284
+
285
+        this.setState({
286
+          submitting: false,
287
+          memberList,
288
+          recordDetail: res.taShareRecord,          
289
+          recordId: res.taShareRecord.recordId,
290
+          groupState: res.taShareRecord.status === undefined ? GroupInProcess : res.taShareRecord.status,
291
+        })
292
+
293
+        Taro.showToast({
294
+          title: '参团成功',
295
+          icon: 'success'
296
+        })
297
+      }).catch(err => {
298
+        console.log('err:', err)
299
+        Taro.hideLoading()
300
+        this.setState({ submitting: false })
301
+      })
250 302
     })
251 303
   }
252 304
 
253
-  comfire = e => {
305
+  // 发起我的拼团
306
+  startMine = () => {
307
+    // 必须授权头像
308
+    if (this.toggleGrantAvatar()) {
309
+      const detail = this.state.detail
310
+      const person = this.props.userInfo.person
254 311
 
255
-    const { detail: { buildingId, dynamicId }, isSign, selectorChecked, inputName } = this.state
256
-    const { userInfo: { person: { phone, name, nickname, tel } } } = this.props
257
-
258
-    if (inputName == '') {
259
-      Taro.showToast({
260
-        title: '请输入姓名',
261
-        icon: 'none'
312
+      return new Promise((resolve, reject) => {
313
+        createGroupActivity({
314
+          groupActivityId: detail.groupActivityId,
315
+          personId: person.personId,
316
+          nickname: person.name || person.nickname,
317
+          phone: person.tel || person.phone,
318
+          avatarurl: person.avatarurl,
319
+        }).then(res => {
320
+          this.setState({
321
+            recordDetail: res,
322
+            recordId: res.recordId,
323
+            memberList: [],
324
+            isStarter: true,
325
+            groupState: GroupInProcess,
326
+          }, resolve)
327
+        }).catch(err => {
328
+          console.log('err:', err)
329
+          Taro.showToast({
330
+            title: '发起失败: ' + err.message,
331
+            icon: 'none'
332
+          })
333
+          reject()
334
+        })
262 335
       })
263
-      return
264 336
     }
265 337
 
266
-    const payload = {
267
-      buildingId,
268
-      dynamicId,
269
-      name: inputName,
270
-      phone: phone ? phone : tel,
271
-      attendNum: selectorChecked
338
+    return Promise.reject()
339
+  }
340
+  
341
+  // 请求好友参团
342
+  groupBuyInvite = () => {
343
+    // 必须授权头像
344
+    if (this.toggleGrantAvatar()) {
345
+      const recordDetail = this.state.recordDetail
346
+      if (!recordDetail.recordId) {
347
+        // 如果是未发起的拼团, 先以当前人身份发起
348
+        this.startMine().then(() => {
349
+          this.toggleActionVisible()
350
+        })
351
+      } else {
352
+        this.toggleActionVisible()
353
+      }
272 354
     }
355
+  }
273 356
 
274
-    signupActivity(payload).then(res => {
275
-      Taro.showToast({
276
-        title: '报名成功'
277
-      })
278
-      this.setState({
279
-        isSign: true,
280
-        canChoose: 'none'
281
-      })
282
-    })
283
-
284
-    savePoint({
285
-      event: 'enlist',
286
-      eventType: 'activity',
287
-      propertyName: '活动详情报名',
288
-      data: '{}'
289
-    }).then(res => {
290
-      console.log('活动详情报名 ')
357
+  getQRCode() {
358
+    const [page, scene] = this.currentPageAndParams()
359
+    const payload = { page, scene }
360
+  
361
+    getMiniQrcode(payload).then(qrCode => {
362
+      this.setState({ qrCode, posterVisible: true })
291 363
     })
292 364
   }
293 365
 
294
-  hideModal() {
295
-    this.setState({
296
-      canChoose: 'none'
297
-    })
366
+  // 发送朋友圈
367
+  shareMoments = () => {
368
+    this.getQRCode().then(() => {
369
+      this.togglePosterVisible()
370
+    })    
298 371
   }
299 372
 
300 373
   render() {
301
-    const { detail, loaded, isSaved, isSign, posterVisible, posterData, posterShow } = this.state
302
-    const { userInfo: { person: { phone } } } = this.props
374
+    const {
375
+      recordId,
376
+      recordDetail,
377
+      detail,
378
+      loaded,
379
+      actState,
380
+      posterVisible,
381
+      isStarter,
382
+      memberList,
383
+      groupState,
384
+      actionSheetVisible,
385
+      grantPhoneVisible,
386
+      posterTpls,
387
+      posters,
388
+      qrCode,
389
+      leftTime,
390
+    } = this.state
391
+
392
+    const { userInfo } = this.props
393
+    const posterData = {
394
+      title: posters[0] ? posters[0].posterTitle : '',
395
+      desc: posters[0] ? posters[0].posterDescription : '',
396
+      poster: posters[0] ? posters[0].posterImg : '',
397
+      name: userInfo.person.name || userInfo.person.nickname,
398
+      qrcode: qrCode,
399
+      avatarurl: getDownloadURL(userInfo.person.avatarurl, 'avatar') || '',
400
+    }
401
+
402
+    // 团长显示团长核销码, 参团的显示参团核销码
403
+    const verificationCode = isStarter ? recordDetail.verificationCode : (memberList.filter(x => x.personId === userInfo.person.personId)[0] || {}).verificationCode
404
+
405
+    const joinedNum = detail.groupBuyPeople - (recordDetail.recordId ? 1 : 0) - memberList.length
406
+
303 407
     return (
304 408
       <Block>
305 409
         {/* 生成海报 */}
306
-        {posterVisible && (<Poster data={posterData} toggle={this.togglePosterStatus}></Poster>)}
410
+        {posterVisible && (<Poster tpls={posterTpls} params={posterData} onCancel={this.togglePosterVisible} onFinish={this.togglePosterVisible}></Poster>)}
411
+        
412
+        {
413
+          grantPhoneVisible &&
414
+          <AchievePhone user={userInfo.person} onSuccess={this.initPageData}></AchievePhone>
415
+        }
307 416
 
308 417
         {
309 418
           loaded && (
310 419
             <View>
311 420
               <Notice></Notice>
312 421
               <View className="detail-banner">
313
-                <Image mode="widthFix" src={detail.imgUrl} className="detail-banner__img"></Image>
314
-                <View className="rest-time">
315
-                  <Text className="row-label">活动剩余时间:</Text>
316
-                  <Text className="row-content">{dayjs(detail.enlistEnd).format('YYYY-MM-DD hh:mm:ss')}</Text>
317
-                </View>
422
+                <Image mode="widthFix" src={detail.mainImg} className="detail-banner__img"></Image>
423
+                {
424
+                  groupState === GroupInProcess && actState != ActFinished &&
425
+                  (
426
+                    <View className="rest-time">
427
+                      <Text className="row-label">{actState === ActBeforeStart ? '距活动开始 :' : (actState === ActInProcess ? '活动剩余时间 :' : '活动已结束')} </Text>
428
+                      <Text className="row-content">{actState != ActFinished ? formateLeftTime(leftTime) : ''}</Text>
429
+                    </View>
430
+                  )
431
+                }
318 432
               </View>
319 433
               <ScrollView
320 434
                 scrollY
321 435
                 className="detail-wrap">
322 436
                 <View className="detail">
323
-                  <View class="detail-title">{detail.title}</View>
437
+                  <View class="detail-title">{detail.activityName}</View>
438
+                  {
439
+                    groupState === GroupSuccess &&
440
+                    (
441
+                      <Block>
442
+                        <Image className="status__img" src={"TODO:"}></Image>
443
+                        <View className="hexiaoma">核销码: {verificationCode}</View>
444
+                      </Block>
445
+                    )
446
+                  }
447
+                  
448
+                  {
449
+                    groupState === GroupFailure &&
450
+                    (
451
+                      <View>
452
+                        <Image className="status__img" src={"TODO:"}></Image>
453
+                        <View className="fail-text">活动已超时,拼团失败!</View>
454
+                      </View>
455
+                    )
456
+                  }
457
+
324 458
                   <View className="detail-info">
325
-                    <View style="margin-right:30px">所需<Text style="color:#FF245A">300</Text>积分</View>
326
-                    <Image style="width:20px;height:20px;margin-right:2px" src={require('@assets/mine/regiment.png')} ></Image>
327
-                    <Text >5人团</Text>
459
+                    <View style="margin-right:30px">所需<Text style="color:#FF245A">{detail.integral}</Text>积分</View>
460
+                    <Image style="width:20px;height:20px;margin-right:2px" src={"TODO:"} ></Image>
461
+                    <Text >{detail.groupBuyPeople}人团</Text>
328 462
                   </View>
329 463
 
330
-                  <Image src={require('@assets/shop/banner1.jpg')} className="my__img"></Image>
464
+                  <Image src={"TODO:"} className="my__img"></Image>
331 465
 
332 466
                   <View className='tools-main'>
333
-                    <View className='tools-item'>
334
-                      <Image src={require('@assets/shop/banner1.jpg')} className='tools-item-img'></Image>
335
-                      <Text className='tools-item-txt'>等待拼团</Text>
336
-                    </View>
337
-                    <View className='tools-item'>
338
-                      <Image src={require('@assets/shop/banner1.jpg')} className='tools-item-img'></Image>
339
-                      <Text className='tools-item-txt'>等待拼团</Text>
340
-                    </View>
341
-                    <View className='tools-item'>
342
-                      <Image src={require('@assets/shop/banner1.jpg')} className='tools-item-img'></Image>
343
-                      <Text className='tools-item-txt'>等待拼团</Text>
344
-                    </View>
345
-                    <View className='tools-item'>
346
-                      <Image src={require('@assets/shop/banner1.jpg')} className='tools-item-img'></Image>
347
-                      <Text className='tools-item-txt'>等待拼团</Text>
348
-                    </View>
349
-                    <View className='tools-item'>
350
-                      <Image src={require('@assets/shop/banner1.jpg')} className='tools-item-img'></Image>
351
-                      <Text className='tools-item-txt'>等待拼团</Text>
352
-                    </View>
353
-                    <View className='tools-item'>
354
-                      <Image src={require('@assets/shop/banner1.jpg')} className='tools-item-img'></Image>
355
-                      <Text className='tools-item-txt'>等待拼团</Text>
356
-                    </View>
357
-                    <View className='tools-item'>
358
-                      <Image src={require('@assets/shop/banner1.jpg')} className='tools-item-img'></Image>
359
-                      <Text className='tools-item-txt'>等待拼团</Text>
360
-                    </View>
361
-                    <View className='tools-item'>
362
-                      <Image src={require('@assets/shop/banner1.jpg')} className='tools-item-img'></Image>
363
-                      <Text className='tools-item-txt'>等待拼团</Text>
364
-                    </View>
365
-                    <View className='tools-item'>
366
-                      <Image src={require('@assets/shop/banner1.jpg')} className='tools-item-img'></Image>
367
-                      <Text className='tools-item-txt'>等待拼团</Text>
368
-                    </View>
369
-                    <View className='tools-item'>
370
-                      <Image src={require('@assets/shop/banner1.jpg')} className='tools-item-img'></Image>
371
-                      <Text className='tools-item-txt'>等待拼团</Text>
372
-                    </View>
467
+                    {
468
+                      recordDetail.recordId &&
469
+                      (
470
+                        <View className='tools-item'>
471
+                          <Image src={recordDetail.avatarurl} className='tools-item-img'></Image>
472
+                          <Image src={"TODO: 团长标志"} className='tools-item-img'></Image>
473
+                          <Text className='tools-item-txt'>recordDetail.nickname</Text>
474
+                        </View>
475
+                      )
476
+                    }
477
+                    {
478
+                      memberList.map((it, inx) => {
479
+                        return (
480
+                          <View className='tools-item' key={`group-${inx}`}>
481
+                            <Image src={it.avatarurl} className='tools-item-img'></Image>
482
+                            <Text className='tools-item-txt'>{it.nickname}</Text>
483
+                          </View>
484
+                        )
485
+                      })
486
+                    }
487
+                    {
488
+                      times(joinedNum).map((_, inx) => {
489
+                        return (
490
+                          <View className='tools-item' key={`un-${inx}`}>
491
+                            <Image src={"TODO:"} className='tools-item-img'></Image>
492
+                            <Text className='tools-item-txt'>等待拼团</Text>
493
+                          </View>
494
+                        )
495
+                      })
496
+                    }
373 497
                   </View>
374 498
                 </View>
375 499
 
376
-                <View className="assistance-text">活动说明</View>
377
-                <Image src={require('@assets/shop/banner1.jpg')}style="width:100%"></Image>
378
-                <Button className={true ? "assistance-btn" : "nostart-btn"}>{true ? "邀请好友拼团" : "未开始"}</Button>
379
-              </ScrollView>
500
+                <View className="assistance-text"><Text style="color:#dcdcdc">————————</Text><Text className="acitivty-desc">活动说明</Text><Text style="color:#dcdcdc">————————</Text></View>
501
+                <Image src={detail.descImg} style="width:100%;margin-bottom:20px"></Image>
380 502
 
503
+                {
504
+                  actState === ActBeforeStart &&
505
+                  (<Button className="nostart-btn">未开始</Button>)
506
+                }
507
+                {
508
+                  isStarter && actState === ActInProcess && groupState === GroupInProcess &&
509
+                  (<Button className="assistance-btn" onClick={this.groupBuyInvite}>邀请好友拼团</Button>)
510
+                }
511
+                {
512
+                  !isStarter && actState === ActInProcess &&
513
+                  (
514
+                    <Block>
515
+                      {
516
+                        groupState === GroupInProcess &&
517
+                        (<Button className="assistance-btn" onClick={this.joinGroup}>立即参团</Button>)
518
+                      }
519
+                      <Button className={groupState === GroupInProcess ? "set-btn" : "assistance-btn"} onClick={this.startMine}>发起我的拼团</Button>
520
+                    </Block>
521
+                  )
522
+                }
523
+              </ScrollView>
381 524
 
382
-              <View className="chat-entrance" onClick={this.handleMoreClick}>
383
-                <Text className="iconfont icon-chat"></Text>
384
-              </View>
385
-              <BackHomeBtn></BackHomeBtn>
525
+              <action-sheet hidden={!actionSheetVisible} bindchange={this.toggleActionVisible}>
526
+                <action-sheet-item open-type="share">
527
+                  <Button open-type="share" className='share__friend' onClick={this.toggleActionVisible}>分享给好友</Button>
528
+                </action-sheet-item>
529
+                <action-sheet-item>
530
+                  <Button className='creat__img' onClick={this.shareMoments}>发送朋友圈</Button>
531
+                </action-sheet-item>
532
+                <action-sheet-cancel onClick={this.toggleActionVisible}>取消</action-sheet-cancel>
533
+              </action-sheet>
386 534
             </View>
387 535
           )
388 536
         }
389 537
       </Block>
390 538
     )
391 539
   }
392
-}
540
+}

+ 46
- 77
src/pages/activity/detail/assistance.js 查看文件

@@ -1,14 +1,14 @@
1 1
 import Taro, { Component } from '@tarojs/taro';
2 2
 import './index.scss'
3 3
 import Notice from '@components/Notice'
4
-import BackHomeBtn from '@components/BackHomeBtn'
4
+// import BackHomeBtn from '@components/BackHomeBtn'
5 5
 import AchievePhone from '@components/achievePhone'
6 6
 import Poster from '@components/Poster'
7 7
 import dayjs from 'dayjs'
8 8
 // import WxParse from '@components/wxParse/wxParse'
9
-import getUserPhone from '@utils/getUserPhone'
9
+// import getUserPhone from '@utils/getUserPhone'
10 10
 import ready from '@utils/ready'
11
-import { getDownloadURL } from '@utils/tools'
11
+import { getDownloadURL, times, formateLeftTime } from '@utils/tools'
12 12
 import {
13 13
   getHelpDetail,
14 14
   createHelpActivity,
@@ -20,12 +20,11 @@ import {
20 20
   updatePoint
21 21
 } from '@services/common'
22 22
 import { connect } from '@tarojs/redux'
23
+
23 24
 const successImg = 'https://estateagents.oss-cn-shanghai.aliyuncs.com/miniapp/images/helpgroup/help/success2.png'
24 25
 const failImg = 'https://estateagents.oss-cn-shanghai.aliyuncs.com/miniapp/images/helpgroup/help/help%20failure.png'
25 26
 const waitImg = 'https://estateagents.oss-cn-shanghai.aliyuncs.com/miniapp/images/helpgroup/waiting%20for%20help.png'
26 27
 
27
-const times = n => n > 0 ? '*'.repeat(n - 1).split('*') : []
28
-
29 28
 // 活动状态
30 29
 const ActBeforeStart = 0;
31 30
 const ActInProcess = 1;
@@ -135,54 +134,37 @@ export default class Detail extends Component {
135 134
     })
136 135
   }
137 136
 
138
-  // 计时器更新剩余时间
139
-  updateLeftTime(startDate, endDate) {
137
+  compActState = (startDate, endDate) => {
140 138
     const st = dayjs(startDate).valueOf()
141 139
     const ed = dayjs(endDate).valueOf()
140
+    const nw = dayjs().valueOf()
141
+
142
+    if (st > nw) {
143
+      // 活动未开始
144
+      return [ActBeforeStart, st - nw]
145
+    } else if (ed > nw) {
146
+      // 活动进行中
147
+      return [ActInProcess, ed - nw]
148
+    } else {
149
+      // 活动已结束
150
+      return [ActFinished, 0]
151
+    }
152
+  }
142 153
 
154
+  // 计时器更新剩余时间
155
+  updateLeftTime(startDate, endDate) {
143 156
     this.setState({
144 157
       ltTicker: setInterval(() => {
145
-        const nw = dayjs().valueOf()
158
+        const [actState, leftTime] = this.compActState(startDate, endDate)
159
+        this.setState({actState, leftTime})
146 160
 
147
-        if (st > nw) {
148
-          // 活动未开始
149
-          this.setState({
150
-            leftTime: st - nw,
151
-            actState: ActBeforeStart,
152
-          })
153
-        } else if (ed > nw) {
154
-          // 活动未结束
155
-          this.setState({
156
-            leftTime: ed - nw,
157
-            actState: ActInProcess,
158
-          })
159
-        } else {
160
-          // 活动已结束
161
+        if (actState === ActFinished) {
161 162
           this.clearTicker()
162
-          this.setState({
163
-            leftTime: 0,
164
-            actState: ActFinished,
165
-          })
166 163
         }
167 164
       }, 1000)
168 165
     })
169 166
   }
170 167
 
171
-  // 格式化剩余时间
172
-  formateLeftTime = () => {
173
-    const nd = 1000 * 24 * 60 * 60;
174
-    const nh = 1000 * 60 * 60;
175
-    const nm = 1000 * 60;
176
-    const ns = 1000;
177
-
178
-    const day = Math.floor(this.state.leftTime / nd);
179
-    const hour = Math.floor(this.state.leftTime % nd / nh);
180
-    const min = Math.floor(this.state.leftTime % nd % nh / nm);
181
-    const sec = Math.floor(this.state.leftTime % nd % nh % nm / ns);
182
-
183
-    return `${day}天${hour}小时${min}分${sec}秒`
184
-  }
185
-
186 168
   // 请求详情
187 169
   loadDetail() {
188 170
     const { id, initiateId } = this.state
@@ -193,6 +175,11 @@ export default class Detail extends Component {
193 175
       this.clearTicker()
194 176
 
195 177
       const initiateDetail = res.helpInitiateRecord || {}
178
+      let [actState, leftTime] = this.compActState(res.helpActivity.startDate, res.helpActivity.endDate)
179
+
180
+      if (res.helpActivity.status != 1) {
181
+        actState = ActFinished
182
+      }
196 183
 
197 184
       Taro.hideLoading()
198 185
       this.setState({
@@ -206,9 +193,14 @@ export default class Detail extends Component {
206 193
         helpList: res.helpRecordList || [],
207 194
         loaded: true,
208 195
         isStarter: !initiateDetail.personId || userInfo.person.personId === initiateDetail.personId,
196
+        actState,
197
+        leftTime,
209 198
       })
210 199
 
211
-      this.updateLeftTime(res.helpActivity.startDate, res.helpActivity.endDate)
200
+      if (actState != ActFinished) {
201
+        this.updateLeftTime(res.helpActivity.startDate, res.helpActivity.endDate)
202
+      }
203
+
212 204
       // WxParse.wxParse('article', 'html', res.desc, this.$scope, 0)
213 205
 
214 206
       // savePoint({
@@ -250,11 +242,7 @@ export default class Detail extends Component {
250 242
 
251 243
   onShareAppMessage = () => {
252 244
     const { shares } = this.state
253
-
254
-    if (!shares || !shares.length) {
255
-      Taro.hideShareMenu()
256
-      return {}
257
-    }
245
+    const currentPage = this.currentPageAndParams().join('?')
258 246
 
259 247
     savePoint({
260 248
       event: 'share',
@@ -262,8 +250,15 @@ export default class Detail extends Component {
262 250
       propertyName: '助力详情分享',
263 251
       data: '{}'
264 252
     })
253
+    
254
+    if (!shares || !shares.length) {
255
+      return {
256
+        title: this.state.detail.title,
257
+        path: currentPage,//分享地址
258
+        imageUrl: this.state.detail.img
259
+      }
260
+    }
265 261
 
266
-    const currentPage = this.currentPageAndParams().join('?')
267 262
     return {
268 263
       title: shares[0].shareContentTitle,
269 264
       path: currentPage,//分享地址
@@ -355,6 +350,7 @@ export default class Detail extends Component {
355 350
     // 必须授权头像
356 351
     if (this.toggleGrantAvatar()) {
357 352
       const initiateDetail = this.state.initiateDetail
353
+      debugger
358 354
       if (!initiateDetail.helpRecordInitiateId) {
359 355
         // 如果是未发起的助力, 先以当前人身份发起
360 356
         this.startMine().then(() => {
@@ -382,32 +378,6 @@ export default class Detail extends Component {
382 378
     })    
383 379
   }
384 380
 
385
-  // // 开始生成海报
386
-  // togglePosterStatus = (flag) => {
387
-  //   if (flag) {
388
-  //     this.getPosterData().then(posterData => {
389
-  //       this.setState({
390
-  //         posterVisible: !!flag,
391
-  //         posterData
392
-  //       })
393
-  //     })
394
-  //     // App.zhuge.track('生成助力详情海报')
395
-  //   } else {
396
-  //     this.setState({
397
-  //       posterVisible: !!flag
398
-  //     })
399
-  //   }
400
-
401
-  //   savePoint({
402
-  //     event: 'poster',
403
-  //     eventType: 'help',
404
-  //     propertyName: '生成助力详情海报',
405
-  //     data: '{}',
406
-  //   }).then(res => {
407
-  //     console.log('生成助力详情海报')
408
-  //   })
409
-  // }
410
-
411 381
   render() {
412 382
     const {
413 383
       initiateId,
@@ -424,6 +394,7 @@ export default class Detail extends Component {
424 394
       posterTpls,
425 395
       posters,
426 396
       qrCode,
397
+      leftTime,
427 398
     } = this.state
428 399
 
429 400
     const { userInfo } = this.props
@@ -458,7 +429,7 @@ export default class Detail extends Component {
458 429
                   (
459 430
                     <View className="rest-time">
460 431
                       <Text className="row-label">{actState === ActBeforeStart ? '距活动开始 :' : (actState === ActInProcess ? '活动剩余时间 :' : '活动已结束')} </Text>
461
-                      <Text className="row-content">{actState != ActFinished ? this.formateLeftTime() : ''}</Text>
432
+                      <Text className="row-content">{actState != ActFinished ? formateLeftTime(leftTime) : ''}</Text>
462 433
                     </View>
463 434
                   )
464 435
                 }
@@ -553,8 +524,6 @@ export default class Detail extends Component {
553 524
                 </action-sheet-item>
554 525
                 <action-sheet-cancel onClick={this.toggleActionVisible}>取消</action-sheet-cancel>
555 526
               </action-sheet>
556
-
557
-              <BackHomeBtn></BackHomeBtn>
558 527
             </View>
559 528
           )
560 529
         }

+ 8
- 1
src/services/activity.js 查看文件

@@ -12,7 +12,10 @@ import {
12 12
   API_HELP_CREATE,
13 13
   API_HELP_FRIEND,
14 14
   API_HELP_LIST,
15
-  API_GROUP_LIST
15
+  API_GROUP_LIST,
16
+  API_GROUP_DETAIL,
17
+  API_GROUP_JOIN,
18
+  API_GROUP_CREATE,
16 19
 } from '@constants/api'
17 20
 
18 21
 /**
@@ -85,3 +88,7 @@ export const getActNewList = payload => fetch({ url: API_ACTNEW_LIST, payload })
85 88
 export const getHelpDetail = (id, initiateId) => fetch({ url: `${API_HELP_DETAIL}/${id}${ initiateId ? '?initiateId=' + initiateId : ''}`, method:'GET' })
86 89
 export const createHelpActivity = payload => fetch({ url: API_HELP_CREATE, method:'POST', payload })
87 90
 export const giveFriendHelp = payload => fetch({ url: API_HELP_FRIEND, method:'POST', payload })
91
+
92
+export const getGroupDetail = (id, recordId) => fetch({ url: `${API_GROUP_DETAIL}/${id}${ recordId ? '?recordId=' + recordId : ''}`, method:'GET' })
93
+export const createGroupActivity = payload => fetch({ url: API_GROUP_CREATE, method:'POST', payload })
94
+export const joinGroupBuy = payload => fetch({ url: API_GROUP_JOIN, method:'POST', payload })

+ 22
- 0
src/utils/tools.js 查看文件

@@ -1,5 +1,27 @@
1 1
 import Taro from '@tarojs/taro';
2 2
 
3
+export function times(n) {
4
+  return n > 0 ? '*'.repeat(n - 1).split('*') : []
5
+}
6
+
7
+/**
8
+ * 格式化剩余时间为 xx天xx小时xx分xx秒
9
+ * @param {int} leftTime 时间毫秒数
10
+ */
11
+export function formateLeftTime(leftTime) {
12
+  const nd = 1000 * 24 * 60 * 60;
13
+  const nh = 1000 * 60 * 60;
14
+  const nm = 1000 * 60;
15
+  const ns = 1000;
16
+
17
+  const day = Math.floor(leftTime / nd);
18
+  const hour = Math.floor(leftTime % nd / nh);
19
+  const min = Math.floor(leftTime % nd % nh / nm);
20
+  const sec = Math.floor(leftTime % nd % nh % nm / ns);
21
+
22
+  return `${day}天${hour}小时${min}分${sec}秒`
23
+}
24
+
3 25
 export function getDownloadURL(url, type) {
4 26
   switch (type) {
5 27
     case 'avatar':