vhall-mini-sdk 0.4.1 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/components/gift/gift-display/gift-display.js +118 -0
  2. package/dist/components/gift/gift-display/gift-display.json +3 -0
  3. package/dist/components/gift/gift-display/gift-display.wxml +16 -0
  4. package/dist/components/gift/gift-display/gift-display.wxss +1 -0
  5. package/dist/components/gift/gift-sender/gift-sender.js +63 -0
  6. package/dist/components/gift/gift-sender/gift-sender.json +6 -0
  7. package/dist/components/gift/gift-sender/gift-sender.wxml +19 -0
  8. package/dist/components/gift/gift-sender/gift-sender.wxss +1 -0
  9. package/dist/components/lottery/lottery-accept/index.js +249 -0
  10. package/dist/components/lottery/lottery-accept/index.json +4 -0
  11. package/dist/components/lottery/lottery-accept/index.wxml +49 -0
  12. package/dist/components/lottery/lottery-accept/index.wxss +1 -0
  13. package/dist/components/lottery/lottery-history/index.js +36 -0
  14. package/dist/components/lottery/lottery-history/index.json +3 -0
  15. package/dist/components/lottery/lottery-history/index.wxml +28 -0
  16. package/dist/components/lottery/lottery-history/index.wxss +1 -0
  17. package/dist/components/lottery/lottery-shake/lottery-shake.js +328 -0
  18. package/dist/components/lottery/lottery-shake/lottery-shake.json +1 -0
  19. package/dist/components/lottery/lottery-shake/lottery-shake.wxml +52 -0
  20. package/dist/components/lottery/lottery-shake/lottery-shake.wxss +1 -0
  21. package/dist/components/lottery/lottery-slot/lottery-slot.js +230 -0
  22. package/dist/components/lottery/lottery-slot/lottery-slot.json +1 -0
  23. package/dist/components/lottery/lottery-slot/lottery-slot.wxml +62 -0
  24. package/dist/components/lottery/lottery-slot/lottery-slot.wxss +1 -0
  25. package/dist/components/lottery/lottery-wheel/lottery-wheel.js +153 -0
  26. package/dist/components/lottery/lottery-wheel/lottery-wheel.json +4 -0
  27. package/dist/components/lottery/lottery-wheel/lottery-wheel.wxml +91 -0
  28. package/dist/components/lottery/lottery-wheel/lottery-wheel.wxss +1 -0
  29. package/dist/components/lottery/lottery-winners/index.js +101 -0
  30. package/dist/components/lottery/lottery-winners/index.json +4 -0
  31. package/dist/components/lottery/lottery-winners/index.wxml +39 -0
  32. package/dist/components/lottery/lottery-winners/index.wxss +1 -0
  33. package/dist/components/lottery/lottery.js +388 -0
  34. package/dist/components/lottery/lottery.json +11 -0
  35. package/dist/components/lottery/lottery.wxml +78 -0
  36. package/dist/components/lottery/lottery.wxss +1 -0
  37. package/dist/components/lottery/wheel.json +49 -0
  38. package/dist/components/mall-reward/common/reward-card.wxss +0 -0
  39. package/dist/components/mall-reward/duration-icon/index.js +101 -0
  40. package/dist/components/mall-reward/duration-icon/index.json +3 -0
  41. package/dist/components/mall-reward/duration-icon/index.wxml +7 -0
  42. package/dist/components/mall-reward/duration-icon/index.wxss +1 -0
  43. package/dist/components/mall-reward/f-count-down/index.js +61 -0
  44. package/dist/components/mall-reward/f-count-down/index.json +3 -0
  45. package/dist/components/mall-reward/f-count-down/index.wxml +9 -0
  46. package/dist/components/mall-reward/f-count-down/index.wxss +1 -0
  47. package/dist/components/mall-reward/f-empty/index.js +11 -0
  48. package/dist/components/mall-reward/f-empty/index.json +3 -0
  49. package/dist/components/mall-reward/f-empty/index.wxml +8 -0
  50. package/dist/components/mall-reward/f-empty/index.wxss +1 -0
  51. package/dist/components/mall-reward/f-history/index.js +84 -0
  52. package/dist/components/mall-reward/f-history/index.json +4 -0
  53. package/dist/components/mall-reward/f-history/index.wxml +38 -0
  54. package/dist/components/mall-reward/f-history/index.wxss +1 -0
  55. package/dist/components/mall-reward/f-open/index.js +36 -0
  56. package/dist/components/mall-reward/f-open/index.json +3 -0
  57. package/dist/components/mall-reward/f-open/index.wxml +10 -0
  58. package/dist/components/mall-reward/f-open/index.wxss +1 -0
  59. package/dist/components/mall-reward/f-receive/index.js +36 -0
  60. package/dist/components/mall-reward/f-receive/index.json +3 -0
  61. package/dist/components/mall-reward/f-receive/index.wxml +9 -0
  62. package/dist/components/mall-reward/f-receive/index.wxss +1 -0
  63. package/dist/components/mall-reward/index.js +374 -0
  64. package/dist/components/mall-reward/index.json +8 -0
  65. package/dist/components/mall-reward/index.wxml +4 -0
  66. package/dist/components/mall-reward/index.wxss +0 -0
  67. package/dist/components/mall-reward/main-popup/index.js +46 -0
  68. package/dist/components/mall-reward/main-popup/index.json +12 -0
  69. package/dist/components/mall-reward/main-popup/index.wxml +16 -0
  70. package/dist/components/mall-reward/main-popup/index.wxss +1 -0
  71. package/dist/components/praise/praise.js +150 -0
  72. package/dist/components/praise/praise.json +5 -0
  73. package/dist/components/praise/praise.wxml +17 -0
  74. package/dist/components/praise/praise.wxss +1 -0
  75. package/dist/components/product/product-card/product-card.js +109 -0
  76. package/dist/components/product/product-card/product-card.json +3 -0
  77. package/dist/components/product/product-card/product-card.wxml +47 -0
  78. package/dist/components/product/product-card/product-card.wxss +1 -0
  79. package/dist/components/product/product-detail/product-detail.js +127 -0
  80. package/dist/components/product/product-detail/product-detail.json +3 -0
  81. package/dist/components/product/product-detail/product-detail.wxml +57 -0
  82. package/dist/components/product/product-detail/product-detail.wxss +1 -0
  83. package/dist/components/product/product-item/product-item.js +56 -0
  84. package/dist/components/product/product-item/product-item.json +3 -0
  85. package/dist/components/product/product-item/product-item.wxml +35 -0
  86. package/dist/components/product/product-item/product-item.wxss +1 -0
  87. package/dist/components/product/product-list/product-list.js +67 -0
  88. package/dist/components/product/product-list/product-list.json +6 -0
  89. package/dist/components/product/product-list/product-list.wxml +16 -0
  90. package/dist/components/product/product-list/product-list.wxss +1 -0
  91. package/dist/components/product/product-order/product-order.js +394 -0
  92. package/dist/components/product/product-order/product-order.json +3 -0
  93. package/dist/components/product/product-order/product-order.wxml +75 -0
  94. package/dist/components/product/product-order/product-order.wxss +1 -0
  95. package/dist/pubComponents/popup/popup.wxss +1 -0
  96. package/dist/sdk/config/index.js +1 -0
  97. package/dist/sdk/plugins/InteractServer.js +1 -0
  98. package/dist/sdk/plugins/LotteryServer.js +1 -0
  99. package/dist/sdk/plugins/MallRewardServer.js +1 -0
  100. package/dist/sdk/plugins/ProductServer.js +1 -0
  101. package/lib/components/live-landscape/live-landscape.js +2 -2
  102. package/lib/components/live-portrait/live-portrait.js +2 -2
  103. package/lib/components/player/components/controls/controls.wxml +6 -3
  104. package/lib/components/player/components/controls/controls.wxss +1 -1
  105. package/lib/components/player/player.wxml +26 -24
  106. package/lib/components/player/player.wxss +1 -1
  107. package/lib/components/product/product-card/product-card.wxml +1 -1
  108. package/lib/sdk/main/index.js +2 -2
  109. package/lib/shared/mpUtils.js +1 -1
  110. package/package.json +1 -1
@@ -0,0 +1,374 @@
1
+ import { isEmpty, safeJsonParse, sleep, genRandom } from '../../shared/utils.js';
2
+ import createLogger from '../../shared/logger.js';
3
+
4
+ const log = createLogger('mall-reward');
5
+ Component({
6
+ properties: {
7
+ sdkInstance: {
8
+ type: Object,
9
+ value: null,
10
+ },
11
+ },
12
+
13
+ /**
14
+ * 组件的初始数据
15
+ */
16
+ data: {
17
+ initTime: 0,
18
+
19
+ mallRewardInfo: null,
20
+
21
+ activeMallReward: null, // 时间最近的未领取的奖励项
22
+ oriOnlineDuration: 0, // 最初始的在线时长(=mallRewardInfo?.online_duration || 0)
23
+
24
+ onlineDuration: 0, // 当前在线时长(倒计时会持续变化)
25
+
26
+ showIcon: false, // 是否显示小图标
27
+
28
+ showPopup: false, // 是否显示弹窗
29
+ filler: '', // 当前填充器
30
+ currentInfo: null, // 预处理后的当前福利信息,直接传给子组件渲染
31
+ isBubble: false, // 是否气泡显示, 因为气泡模式区域太小承载内容有限,且无遮罩,与产品沟通后调整为只有‘无条件+未领取’状态生效
32
+ },
33
+ observers: {
34
+ sdkInstance: function sdkInstance(_sdkInstance) {
35
+ if (!_sdkInstance) return;
36
+ log.info('mall-reward sdkInstance');
37
+ this.sdkInstance = _sdkInstance;
38
+ this.setData({
39
+ initTime: Date.now(),
40
+ });
41
+ this.initEventListener();
42
+
43
+ this.checkAndFetchMallRewardInfo('refresh');
44
+ },
45
+ },
46
+ lifetimes: {
47
+ attached() {
48
+ log.info('mall-reward component attached');
49
+ },
50
+ detached() {
51
+ this.unlistener?.();
52
+ },
53
+ },
54
+
55
+ methods: {
56
+ // 初始化事件监听
57
+ initEventListener() {
58
+ this.unlistener?.();
59
+ const obj = {};
60
+
61
+ // 推送商城奖励
62
+ obj[this.sdkInstance.EVENT.MALL_REWARD_PUSH] = (msg) => {
63
+ log.info('mallReward open msg:', JSON.stringify(msg));
64
+ const watchInitData = this.sdkInstance.store.get('watchInitData');
65
+ const webinarType = watchInitData?.webinar?.type;
66
+ if (!this.webinarType != 1) {
67
+ return;
68
+ }
69
+ this.checkAndFetchMallRewardInfo('push', { reward_id: msg.data?.id });
70
+ // 消息推送
71
+ // const data = {
72
+ // roleName: msg.data.role_name,
73
+ // nickname: msg.data.pusher_name,
74
+ // avatar: '//cnstatic01.e.vhall.com/static/images/watch/system.png',
75
+ // content: {
76
+ // text_content: `${this.$t('chat.chat_1108')}`,
77
+ // },
78
+ // type: msg.data.type,
79
+ // interactStatus: true,
80
+ // };
81
+ // useChatServer().addChatToList(data);
82
+ };
83
+
84
+ // 收到商城奖励结束消息
85
+ obj[this.sdkInstance.EVENT.MALL_REWARD_END] = (msg) => {
86
+ log.info('mallReward ------handleMsgMallRewardEnd-msg:', msg);
87
+ this.updateInfo(msg.data.id, { status: 2 });
88
+ if (
89
+ ['COUNTDOWN', 'OPEN'].includes(this.data.filler) &&
90
+ this.data.currentInfo?.reward_id === msg.data.id
91
+ ) {
92
+ this.changeMainFiller('');
93
+ }
94
+ };
95
+
96
+ // 直播结束
97
+ obj[this.sdkInstance.EVENT.LIVE_END] = (msg) => {
98
+ log.info('mallReward ------handleMsgMallRewardEnd-msg:', msg);
99
+ this.destroyTimer(); // 清除计时器
100
+ this.setData({
101
+ mallRewardInfo: null,
102
+ activeMallReward: null,
103
+ oriOnlineDuration: 0,
104
+ onlineDuration: 0,
105
+ showIcon: false,
106
+ showPopup: false,
107
+ filler: '',
108
+ currentInfo: null,
109
+ });
110
+ };
111
+
112
+ // 上线消息
113
+ obj[this.sdkInstance.EVENT.JOIN_MSG] = (msg) => {
114
+ log.info('mallReward ------handleMsgJoin-msg:', msg);
115
+ // 监听上线消息,刷新商城奖励数据条件:
116
+ //(1)上线的人是自己;( 支持多端上线)
117
+ //(2)间隔初始化请求时间超过3s(否则每次刷新调用两次请求;是否可以仅使用JOIN消息请求?不行,因为join消息不可靠,有时候收不到)
118
+ if (!this.sdkInstance) return;
119
+ const watchInitData = this.sdkInstance.store.get('watchInitData');
120
+ const thirdPartyUserId = watchInitData?.join_info?.third_party_user_id;
121
+ /* prettier-ignore */
122
+ if (thirdPartyUserId && msg.sender_id == thirdPartyUserId && Date.now() - this.data.initTime > 3000) {
123
+ this.checkAndFetchMallRewardInfo('refresh');
124
+ }
125
+ };
126
+
127
+ // 下线消息
128
+ obj[this.sdkInstance.EVENT.LEAVE_MSG] = (msg) => {
129
+ log.info('mallReward ------handleMsgLeave-msg:', msg);
130
+ if (!this.sdkInstance) return;
131
+ const watchInitData = this.sdkInstance.store.get('watchInitData');
132
+ const localKickMark = this.sdkInstance.store.get('kickMark');
133
+ const localKickID = watchInitData?.sso?.kick_id;
134
+ const msgContex = safeJsonParse(msg?.context);
135
+ /* prettier-ignore */ // 自己下线了,计时器暂停
136
+ if (localKickMark && localKickID && msgContex.kick_id === localKickID && msgContex.kick_mark === localKickMark) {
137
+ console.log('mallReward 倒计时暂停');
138
+ this.destroyTimer();
139
+ }
140
+ };
141
+
142
+ this.unlistener = this.sdkInstance.on(obj);
143
+ },
144
+ async checkAndFetchMallRewardInfo(from, extra) {
145
+ log.info('mall-reward checkAndFetchMallRewardInfo start');
146
+ const mallRewardServer = this.sdkInstance.get('mallRewardServer');
147
+ if (!mallRewardServer) return;
148
+
149
+ const watchInitData = this.sdkInstance.store.get('watchInitData');
150
+ const webinarType = watchInitData?.webinar?.type;
151
+
152
+ if (webinarType != 1 && webinarType != 5) return;
153
+
154
+ if (from === 'refresh') {
155
+ this.destroyTimer();
156
+ this.changeMainFiller('');
157
+ }
158
+
159
+ if (from === 'push') {
160
+ // 延迟随机3s以内,再去调用接口,减少大并发
161
+ const rnd = genRandom(0, 3000);
162
+ await sleep(rnd);
163
+ }
164
+ const mallRewardInfo = await mallRewardServer.getValidList();
165
+ const activeMallReward = mallRewardServer.updateActiveMallReward();
166
+ this.setData({
167
+ mallRewardInfo: mallRewardInfo,
168
+ activeMallReward: activeMallReward,
169
+ oriOnlineDuration: mallRewardInfo?.online_duration || 0,
170
+ onlineDuration: mallRewardInfo?.online_duration || 0,
171
+ });
172
+ this.setData({
173
+ /* prettier-ignore */
174
+ showIcon: (webinarType == 1 || webinarType == 5) && (mallRewardInfo?.is_received == 1 || mallRewardInfo?.list?.length > 0),
175
+ });
176
+ if (webinarType == 1 || webinarType == 5) {
177
+ this.createTimer(); // 创建计时器
178
+ }
179
+
180
+ // 检查并弹窗
181
+ if (from === 'push' && extra?.reward_id && Array.isArray(mallRewardInfo?.list)) {
182
+ extra = mallRewardInfo.list.find((item) => item.reward_id == extra.reward_id);
183
+ }
184
+ this.checkAndOpenPopup(from, extra);
185
+ },
186
+ /**
187
+ * 创建定时器
188
+ */
189
+ createTimer() {
190
+ this.destroyTimer();
191
+
192
+ this.timer = setInterval(() => {
193
+ const currentTime = Date.now();
194
+ if (!this.startTime) {
195
+ // 如果还没记录开始时间,说明是刚启动定时器,记录当前时间作为开始时间
196
+ this.startTime = currentTime;
197
+ }
198
+ // 计时,延时问题处理
199
+ this.setData({
200
+ onlineDuration:
201
+ this.data.oriOnlineDuration + parseInt((Date.now() - this.startTime) / 1000),
202
+ });
203
+ }, 1000);
204
+ },
205
+ /**
206
+ * 销毁定时器
207
+ */
208
+ destroyTimer() {
209
+ if (this.timer) {
210
+ clearInterval(this.timer);
211
+ this.timer = 0;
212
+ }
213
+ this.startTime = undefined;
214
+ },
215
+ // 关闭弹窗
216
+ handlePopupClose() {
217
+ this.setData({
218
+ showPopup: false,
219
+ filler: '',
220
+ });
221
+ },
222
+ // 点击icon图标
223
+ handleIconClick() {
224
+ this.checkAndOpenPopup('icon_click');
225
+ },
226
+ // 切换对话框视图
227
+ async changeMainFiller(filler, payload) {
228
+ this.setData({
229
+ showPopup: false,
230
+ filler: '',
231
+ currentInfo: null,
232
+ isBubble: false,
233
+ });
234
+ await sleep(20);
235
+ if (filler) {
236
+ const currentInfo = payload
237
+ ? { ...payload, tip_setting: safeJsonParse(payload.tip_setting) }
238
+ : { ...this.data.activeMallReward };
239
+ this.setData({
240
+ showPopup: true,
241
+ filler,
242
+ currentInfo,
243
+ isBubble:
244
+ filler === 'OPEN' &&
245
+ currentInfo?.viewing_minutes === 0 &&
246
+ currentInfo?.display_of_results === 1,
247
+ });
248
+ }
249
+ },
250
+ // 检测并打开对应的弹窗
251
+ async checkAndOpenPopup(action, payload) {
252
+ console.log('checkAndOpenPopup called with:', { action, payload });
253
+ const mallRewardInfo = this.sdkInstance.store.get('mallRewardInfo');
254
+ if (isEmpty(mallRewardInfo)) return;
255
+ switch (action) {
256
+ // 点击icon
257
+ case 'icon_click':
258
+ if (this.data.mallRewardInfo.list?.length === 1) {
259
+ // 列表中只有一条数据
260
+ const mrInfo = this.data.mallRewardInfo.list[0];
261
+ if (mrInfo.claim_status === 1) {
262
+ // 已领取(无论是无条件还是定时奖励),都直接打开“开下收下”弹窗
263
+ this.changeMainFiller('RECEIVE', mrInfo);
264
+ } else if (
265
+ mrInfo.viewing_minutes === 0 &&
266
+ mrInfo.status === 1 &&
267
+ mrInfo.remaining_quota > 0
268
+ ) {
269
+ // (未领取)+ 无条件 + 推送中 + 有数量 可以拆商城奖励
270
+ this.changeMainFiller('OPEN', mrInfo);
271
+ } else if (
272
+ mrInfo.viewing_minutes > 0 &&
273
+ mrInfo.status === 0 &&
274
+ mrInfo.remaining_quota > 0
275
+ ) {
276
+ // (未领取)+ 定时奖励 + 推送中 + 有数量
277
+ if (this.data.onlineDuration <= mrInfo.viewing_minutes * 60) {
278
+ this.changeMainFiller('COUNTDOWN', mrInfo);
279
+ } else {
280
+ this.changeMainFiller('OPEN', mrInfo);
281
+ }
282
+ } else {
283
+ this.changeMainFiller('EMPTY');
284
+ }
285
+ } else if (this.data.mallRewardInfo.list?.length > 1) {
286
+ // 列表中有多条数据
287
+ this.changeMainFiller('HISTORY');
288
+ }
289
+ break;
290
+
291
+ // 推送触发
292
+ case 'push':
293
+ // 如果开了某些弹窗,则不操作
294
+ if (['OPEN', 'RECEIVE', 'EMPTY'].includes(this.data.filler)) return;
295
+ // 打开“立即领取”弹窗
296
+ this.changeMainFiller('OPEN', payload);
297
+ break;
298
+ }
299
+ },
300
+ // 更新某个奖励的属性
301
+ updateInfo(mallRewardId, attrs) {
302
+ if (this.data.mallRewardInfo) {
303
+ if (this.data.mallRewardInfo.list?.length > 0) {
304
+ for (let item of this.data.mallRewardInfo.list) {
305
+ if (item.reward_id === mallRewardId) {
306
+ Object.keys(attrs).forEach((k) => {
307
+ item[k] = attrs[k];
308
+ });
309
+ break;
310
+ }
311
+ }
312
+ }
313
+ if (attrs?.['claim_status'] == 1) {
314
+ this.data.mallRewardInfo.is_received = 1;
315
+ }
316
+ this.sdkInstance.store.set('mallRewardInfo', this.data.mallRewardInfo);
317
+ const mallRewardServer = this.sdkInstance.get('mallRewardServer');
318
+ const activeMallReward = mallRewardServer.updateActiveMallReward();
319
+ this.setData({
320
+ mallRewardInfo: this.data.mallRewardInfo,
321
+ activeMallReward: activeMallReward,
322
+ });
323
+ }
324
+ },
325
+
326
+ /**
327
+ * 立即领取福利
328
+ * @param {*} from 来源
329
+ * 1. claim_now 用户点击“立即领取”(默认).
330
+ * 2. countdown_end 倒计时结束自动立即领取
331
+ * @param {*} theInfo
332
+ * @returns
333
+ */
334
+ async claimNowHandler(from = 'claim_now', theInfo) {
335
+ console.log('claimNowHandler called with:', { from, theInfo });
336
+ const mallRewardServer = this.sdkInstance.get('mallRewardServer');
337
+ if (!mallRewardServer) return;
338
+
339
+ const rewardId = theInfo?.reward_id;
340
+ if (!rewardId) return;
341
+
342
+ const res = await mallRewardServer.claimMallReward(rewardId);
343
+ console.log('mallreward claim result:', res);
344
+ if (res?.code === 520099) {
345
+ // 已领光
346
+ this.updateInfo(rewardId, { remaining_quota: 0 });
347
+ this.changeMainFiller('EMPTY');
348
+ } else if (res?.code === 200 || res?.code === 520008) {
349
+ // 领取成功 || 已领取过
350
+ this.updateInfo(rewardId, { claim_status: 1 });
351
+ this.changeMainFiller('RECEIVE', { ...theInfo, claim_status: 1 });
352
+ } else {
353
+ // 其它错误,如果是手动点击的“立即领取”,有错误提示
354
+ if (from === 'claim_now') {
355
+ wx.showToast({
356
+ title: res?.msg || '领取失败',
357
+ icon: 'none',
358
+ duration: 2000,
359
+ });
360
+ } else {
361
+ this.changeMainFiller('OPEN', theInfo);
362
+ }
363
+ }
364
+ },
365
+ // 立即领取
366
+ onPopupClaim(e) {
367
+ this.claimNowHandler('claim_now', e.detail);
368
+ },
369
+ // 倒计时结束,自动领取福利
370
+ onCountdownEnd(e) {
371
+ this.claimNowHandler('countdown_end', e.detail);
372
+ },
373
+ },
374
+ });
@@ -0,0 +1,8 @@
1
+ {
2
+ "component": true,
3
+ "styleIsolation": "shared",
4
+ "usingComponents": {
5
+ "duration-icon": "./duration-icon/index",
6
+ "main-popup": "./main-popup/index"
7
+ }
8
+ }
@@ -0,0 +1,4 @@
1
+ <!-- 商城奖励浮动小图标 -->
2
+ <duration-icon wx:if="{{showIcon}}" mallRewardInfo="{{mallRewardInfo}}" activeMallReward="{{activeMallReward}}" onlineDuration="{{onlineDuration}}" bind:onTapIcon="handleIconClick" bind:countdownEnd="onCountdownEnd"></duration-icon>
3
+ <!-- 主弹窗组件 -->
4
+ <main-popup show="{{showPopup}}" filler="{{filler}}" currentInfo="{{currentInfo}}" mallRewardInfo="{{mallRewardInfo}}" onlineDuration="{{onlineDuration}}" hasMask="{{true}}" isBubble="{{isBubble}}" bind:close="handlePopupClose" bind:claim="onPopupClaim"></main-popup>
File without changes
@@ -0,0 +1,46 @@
1
+ Component({
2
+ properties: {
3
+ show: { type: Boolean, value: false },
4
+ mallRewardInfo: { type: Object, value: null },
5
+ filler: { type: String, value: '' },
6
+ currentInfo: { type: Object, value: null },
7
+ onlineDuration: { type: Number, value: 0 },
8
+ isBubble: { type: Boolean, value: false }, //气泡模式
9
+ },
10
+
11
+ data: {
12
+ historyList: [],
13
+ tipMode: 1,
14
+ position: 'center', // 弹窗位置
15
+ showFooterCloseBtn: true,
16
+ },
17
+
18
+ observers: {
19
+ mallRewardInfo: function (newValue) {
20
+ if (newValue) {
21
+ this.setData({ historyList: newValue?.list || [] });
22
+ }
23
+ },
24
+ filler: function (filler) {
25
+ if (filler) {
26
+ const position = ['HISTORY'].includes(filler)
27
+ ? 'bottom'
28
+ : this.properties.isBubble
29
+ ? 'bottom-right'
30
+ : 'center';
31
+
32
+ this.setData({
33
+ tipMode: this.properties.currentInfo?.tip_mode || 1,
34
+ position: position,
35
+ showFooterCloseBtn: position === 'center',
36
+ });
37
+ }
38
+ },
39
+ },
40
+
41
+ methods: {
42
+ onClose() {
43
+ this.triggerEvent('close');
44
+ },
45
+ },
46
+ });
@@ -0,0 +1,12 @@
1
+ {
2
+ "component": true,
3
+ "styleIsolation": "shared",
4
+ "usingComponents": {
5
+ "vh-popup": "../../../pubComponents/popup/popup",
6
+ "f-open": "../f-open/index",
7
+ "f-count-down": "../f-count-down/index",
8
+ "f-history": "../f-history/index",
9
+ "f-empty": "../f-empty/index",
10
+ "f-receive": "../f-receive/index"
11
+ }
12
+ }
@@ -0,0 +1,16 @@
1
+ <vh-popup wx:if="{{show}}" visible="{{show}}" showClose="{{false}}" mode="{{position}}" hasMask="{{!isBubble}}" maskClosable="{{false}}" hasGap="{{false}}" bgColor="transparent" bind:close="onClose">
2
+ <view class="mall-reward-pupup-content">
3
+ <!-- 福利领取未到时长,显示倒计时 -->
4
+ <f-count-down wx:if="{{filler==='COUNTDOWN'}}" tip-mode="{{tipMode}}" info="{{currentInfo}}" onlineDuration="{{onlineDuration}}" />
5
+ <!-- 拆福利(立即领取) -->
6
+ <f-open wx:if="{{filler==='OPEN'}}" isBubble="{{isBubble}}" tip-mode="{{tipMode}}" info="{{currentInfo}}" onlineDuration="{{onlineDuration}}" />
7
+ <!-- 开心收下 -->
8
+ <f-receive wx:if="{{filler==='RECEIVE'}}" tip-mode="{{tipMode}}" info="{{currentInfo}}" />
9
+ <!-- 福利已领完 -->
10
+ <f-empty wx:if="{{filler==='EMPTY'}}" />
11
+ <!-- 福利记录 -->
12
+ <f-history wx:if="{{filler==='HISTORY'}}" dataList="{{historyList}}" onlineDuration="{{onlineDuration}}" />
13
+ <!-- 是否显示关闭按钮 -->
14
+ <view wx:if="{{showFooterCloseBtn}}" class="close-btn" bindtap="onClose">✕</view>
15
+ </view>
16
+ </vh-popup>
@@ -0,0 +1 @@
1
+ .mall-reward-pupup-content{display:flex;flex-direction:column}.mall-reward-pupup-content .close-btn{align-items:center;border:5rpx solid hsla(0,0%,100%,.6);border-radius:50%;color:hsla(0,0%,100%,.8);display:flex;font-size:1.29rem;height:48rpx;justify-content:center;line-height:1;margin:24rpx auto 0;width:48rpx}
@@ -0,0 +1,150 @@
1
+ Component({
2
+ properties: {
3
+ sdkInstance: {
4
+ type: Object,
5
+ value: null,
6
+ },
7
+ },
8
+ data: {
9
+ likeCount: 0, // 点赞数
10
+ eleList: [], // 动画元素列表
11
+ },
12
+ observers: {
13
+ sdkInstance: function sdkInstance(_sdkInstance) {
14
+ if (!_sdkInstance) return;
15
+ this.sdkInstance = _sdkInstance;
16
+ this.initStoreListener();
17
+ },
18
+ },
19
+ lifetimes: {
20
+ detached() {
21
+ // 组件销毁时清除监听
22
+ this.unsub && this.unsub();
23
+ },
24
+ },
25
+ methods: {
26
+ // 初始化 store 监听
27
+ initStoreListener() {
28
+ this.unsub = this.sdkInstance.store.get({
29
+ likeCount: (val) => {
30
+ if (val !== undefined) {
31
+ let num = Number(val)
32
+ if (num >= 10000) {
33
+ const n = Math.floor((num / 10000) * 10) / 10;
34
+ if (n > 9999.9) {
35
+ num = '9999.9+w';
36
+ } else {
37
+ num = n + 'w';
38
+ }
39
+ }
40
+
41
+ this.setData({
42
+ likeCount: num
43
+ });
44
+ }
45
+ },
46
+ });
47
+ },
48
+ // 处理点赞点击
49
+ handleLike() {
50
+ if (!this.properties.sdkInstance) return;
51
+ const interactServer = this.properties.sdkInstance.get('interactServer');
52
+ if (interactServer) {
53
+ interactServer.like();
54
+ }
55
+ // 触发点赞动画
56
+ this.giveParise();
57
+ },
58
+ // 随机算法闭包生成封装
59
+ randomAlgorithmFactory(array) {
60
+ const randomBase = Math.ceil(array.length / 2); // 随机选择前半边的元素
61
+ return function () {
62
+ const idx = Math.floor(randomBase * Math.random());
63
+ const eleArr = array.splice(idx, 1); // 选中的元素摘除
64
+ const ele = eleArr[0];
65
+ array.push(ele); // 塞到队尾
66
+ return ele;
67
+ };
68
+ },
69
+ // 单次渲染一个元素的动画
70
+ renderParise() {
71
+ const iconList = [
72
+ {
73
+ name: 'happy',
74
+ url: 'happy.png'
75
+ },
76
+ {
77
+ name: 'balloon',
78
+ url: 'balloon.png'
79
+ },
80
+ {
81
+ name: 'quitegood',
82
+ url: 'quitegood.png'
83
+ },
84
+ {
85
+ name: 'star',
86
+ url: 'star.png'
87
+ },
88
+ {
89
+ name: 'microphone',
90
+ url: 'microphone.png'
91
+ },
92
+ {
93
+ name: 'love',
94
+ url: 'love.png'
95
+ },
96
+ {
97
+ name: 'likes2',
98
+ url: 'likes2.png'
99
+ },
100
+ {
101
+ name: 'likes',
102
+ url: 'likes.png'
103
+ }
104
+ ];
105
+ const toTopAnimations = [
106
+ 'zan-animation-01',
107
+ 'zan-animation-02',
108
+ 'zan-animation-03',
109
+ 'zan-animation-04'
110
+ ];
111
+ const shakeAnimations = [
112
+ 'shake-animation-01',
113
+ 'shake-animation-02',
114
+ 'shake-animation-03',
115
+ 'shake-animation-04'
116
+ ];
117
+
118
+ const pickIcon = this.randomAlgorithmFactory([...iconList]); // 挑选图标
119
+ const pick2TopAnimations = this.randomAlgorithmFactory([...toTopAnimations]); // 挑选向上动画
120
+ const pickShakeTopAnimations = this.randomAlgorithmFactory([...shakeAnimations]); // 挑选左右摇摆动画
121
+
122
+ const selectedIcon = pickIcon();
123
+ const uuid = Date.now() + Math.random(); // 唯一id
124
+ const newItem = {
125
+ uuid,
126
+ icon: selectedIcon.name,
127
+ iconUrl: `https://cnstatic01.e.vhall.com/common-static/weapp/praise/img/${selectedIcon.url}`,
128
+ toTopAnimation: pick2TopAnimations(),
129
+ shakeTopAnimations: pickShakeTopAnimations()
130
+ };
131
+
132
+ const eleList = this.data.eleList.concat(newItem);
133
+ this.setData({ eleList });
134
+
135
+ // 及时删除第一个被占位的元素
136
+ setTimeout(() => {
137
+ const newEleList = this.data.eleList.filter(item => item.uuid !== uuid);
138
+ this.setData({ eleList: newEleList });
139
+ }, 2000);
140
+ },
141
+ // 对外暴露的点赞函数
142
+ giveParise() {
143
+ const maxCount = 2; // 一次点赞最大渲染元素次数
144
+ const count = Math.ceil(Math.random() * maxCount);
145
+ for (let i = 0; i < count; i++) {
146
+ this.renderParise();
147
+ }
148
+ },
149
+ },
150
+ });
@@ -0,0 +1,5 @@
1
+ {
2
+ "component": true,
3
+ "styleIsolation": "shared",
4
+ "usingComponents": {}
5
+ }
@@ -0,0 +1,17 @@
1
+ <view class="praise-container">
2
+ <view class="praise-button" bindtap="handleLike">
3
+ <image class="praise-icon" src="https://cnstatic01.e.vhall.com/common-static/saas-wap/static/img/icon_like0.866359fe.png" mode="aspectFit"></image>
4
+ <view class="praise-count" wx:if="{{likeCount>0}}">{{likeCount}}</view>
5
+ </view>
6
+
7
+ <!-- 点赞动画区域 -->
8
+ <view class="zan-zone">
9
+ <view
10
+ wx:for="{{eleList}}"
11
+ wx:key="uuid"
12
+ class="zan-icon-wrapper {{item.toTopAnimation}}"
13
+ >
14
+ <image class="zan-icon {{item.shakeTopAnimations}}" src="{{item.iconUrl}}" mode="aspectFit"></image>
15
+ </view>
16
+ </view>
17
+ </view>
@@ -0,0 +1 @@
1
+ .praise-button,.praise-container{position:relative}.praise-button{align-items:center;background:rgba(6,6,6,.25);border-radius:50%;display:flex;height:2rem;justify-content:center;width:2rem}.praise-button:active{transform:scale(.9)}.praise-icon{height:100%;width:100%}.praise-count{align-items:center;background-color:#ff4d4f;border:2rpx solid #fff;border-radius:16rpx;box-shadow:0 2rpx 8rpx rgba(255,77,79,.2);color:#fff;display:flex;font-size:.71rem;font-weight:700;height:32rpx;justify-content:center;min-width:32rpx;padding:0 8rpx;position:absolute;right:-8rpx;top:-8rpx}.zan-zone{bottom:100rpx;display:block;height:500rpx;pointer-events:none;position:fixed;right:0;width:100rpx;z-index:1000}.zan-icon-wrapper{bottom:0;display:block;left:0;opacity:0;position:absolute}.zan-icon{display:inline-block;height:70rpx;left:0;position:relative;width:70rpx}.zan-animation-01{animation:toTop 2s linear 0s}.zan-animation-02{animation:toTop 1.8s linear 0s}.zan-animation-03{animation:toTop 1.6s linear 0s}.zan-animation-04{animation:toTop 1.4s linear 0s}.zan-icon.shake-animation-01{animation:shake1 2s linear 0s}.zan-icon.shake-animation-02{animation:shake2 2s linear 0s}.zan-icon.shake-animation-03{animation:shake3 2s linear 0s}.zan-icon.shake-animation-04{animation:shake4 2s linear 0s}@keyframes toTop{0%{bottom:-40rpx;opacity:1;transform:scale(0)}10%{bottom:-20rpx;opacity:1;transform:scale(1)}50%{bottom:300rpx}60%{bottom:360rpx;opacity:.8}70%{bottom:420rpx}80%{bottom:480rpx}90%{bottom:600rpx}to{bottom:660rpx;opacity:0}}@keyframes shake1{0%{left:0}25%{left:-20rpx}50%{left:0}75%{left:-20rpx}to{left:0}}@keyframes shake2{0%{left:0}80%{left:-80rpx}to{left:-40rpx}}@keyframes shake3{0%{left:0}65%{left:-20rpx}to{left:30rpx}}@keyframes shake4{0%{left:0}20%{left:-30rpx}70%{left:40rpx}to{left:10rpx}}