vhall-mini-sdk 0.4.0 → 0.4.3

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/CHANGELOG.md +4 -0
  2. package/dist/components/gift/gift-display/gift-display.js +118 -0
  3. package/dist/components/gift/gift-display/gift-display.json +3 -0
  4. package/dist/components/gift/gift-display/gift-display.wxml +16 -0
  5. package/dist/components/gift/gift-display/gift-display.wxss +1 -0
  6. package/dist/components/gift/gift-sender/gift-sender.js +63 -0
  7. package/dist/components/gift/gift-sender/gift-sender.json +6 -0
  8. package/dist/components/gift/gift-sender/gift-sender.wxml +19 -0
  9. package/dist/components/gift/gift-sender/gift-sender.wxss +1 -0
  10. package/dist/components/lottery/lottery-accept/index.js +249 -0
  11. package/dist/components/lottery/lottery-accept/index.json +4 -0
  12. package/dist/components/lottery/lottery-accept/index.wxml +49 -0
  13. package/dist/components/lottery/lottery-accept/index.wxss +1 -0
  14. package/dist/components/lottery/lottery-history/index.js +36 -0
  15. package/dist/components/lottery/lottery-history/index.json +3 -0
  16. package/dist/components/lottery/lottery-history/index.wxml +28 -0
  17. package/dist/components/lottery/lottery-history/index.wxss +1 -0
  18. package/dist/components/lottery/lottery-shake/lottery-shake.js +328 -0
  19. package/dist/components/lottery/lottery-shake/lottery-shake.json +1 -0
  20. package/dist/components/lottery/lottery-shake/lottery-shake.wxml +52 -0
  21. package/dist/components/lottery/lottery-shake/lottery-shake.wxss +1 -0
  22. package/dist/components/lottery/lottery-slot/lottery-slot.js +230 -0
  23. package/dist/components/lottery/lottery-slot/lottery-slot.json +1 -0
  24. package/dist/components/lottery/lottery-slot/lottery-slot.wxml +62 -0
  25. package/dist/components/lottery/lottery-slot/lottery-slot.wxss +1 -0
  26. package/dist/components/lottery/lottery-wheel/lottery-wheel.js +153 -0
  27. package/dist/components/lottery/lottery-wheel/lottery-wheel.json +4 -0
  28. package/dist/components/lottery/lottery-wheel/lottery-wheel.wxml +91 -0
  29. package/dist/components/lottery/lottery-wheel/lottery-wheel.wxss +1 -0
  30. package/dist/components/lottery/lottery-winners/index.js +101 -0
  31. package/dist/components/lottery/lottery-winners/index.json +4 -0
  32. package/dist/components/lottery/lottery-winners/index.wxml +39 -0
  33. package/dist/components/lottery/lottery-winners/index.wxss +1 -0
  34. package/dist/components/lottery/lottery.js +388 -0
  35. package/dist/components/lottery/lottery.json +11 -0
  36. package/dist/components/lottery/lottery.wxml +78 -0
  37. package/dist/components/lottery/lottery.wxss +1 -0
  38. package/dist/components/lottery/wheel.json +49 -0
  39. package/dist/components/mall-reward/common/reward-card.wxss +0 -0
  40. package/dist/components/mall-reward/duration-icon/index.js +101 -0
  41. package/dist/components/mall-reward/duration-icon/index.json +3 -0
  42. package/dist/components/mall-reward/duration-icon/index.wxml +7 -0
  43. package/dist/components/mall-reward/duration-icon/index.wxss +1 -0
  44. package/dist/components/mall-reward/f-count-down/index.js +61 -0
  45. package/dist/components/mall-reward/f-count-down/index.json +3 -0
  46. package/dist/components/mall-reward/f-count-down/index.wxml +9 -0
  47. package/dist/components/mall-reward/f-count-down/index.wxss +1 -0
  48. package/dist/components/mall-reward/f-empty/index.js +11 -0
  49. package/dist/components/mall-reward/f-empty/index.json +3 -0
  50. package/dist/components/mall-reward/f-empty/index.wxml +8 -0
  51. package/dist/components/mall-reward/f-empty/index.wxss +1 -0
  52. package/dist/components/mall-reward/f-history/index.js +84 -0
  53. package/dist/components/mall-reward/f-history/index.json +4 -0
  54. package/dist/components/mall-reward/f-history/index.wxml +38 -0
  55. package/dist/components/mall-reward/f-history/index.wxss +1 -0
  56. package/dist/components/mall-reward/f-open/index.js +36 -0
  57. package/dist/components/mall-reward/f-open/index.json +3 -0
  58. package/dist/components/mall-reward/f-open/index.wxml +10 -0
  59. package/dist/components/mall-reward/f-open/index.wxss +1 -0
  60. package/dist/components/mall-reward/f-receive/index.js +36 -0
  61. package/dist/components/mall-reward/f-receive/index.json +3 -0
  62. package/dist/components/mall-reward/f-receive/index.wxml +9 -0
  63. package/dist/components/mall-reward/f-receive/index.wxss +1 -0
  64. package/dist/components/mall-reward/index.js +374 -0
  65. package/dist/components/mall-reward/index.json +8 -0
  66. package/dist/components/mall-reward/index.wxml +4 -0
  67. package/dist/components/mall-reward/index.wxss +0 -0
  68. package/dist/components/mall-reward/main-popup/index.js +46 -0
  69. package/dist/components/mall-reward/main-popup/index.json +12 -0
  70. package/dist/components/mall-reward/main-popup/index.wxml +16 -0
  71. package/dist/components/mall-reward/main-popup/index.wxss +1 -0
  72. package/dist/components/praise/praise.js +150 -0
  73. package/dist/components/praise/praise.json +5 -0
  74. package/dist/components/praise/praise.wxml +17 -0
  75. package/dist/components/praise/praise.wxss +1 -0
  76. package/dist/components/product/product-card/product-card.js +109 -0
  77. package/dist/components/product/product-card/product-card.json +3 -0
  78. package/dist/components/product/product-card/product-card.wxml +47 -0
  79. package/dist/components/product/product-card/product-card.wxss +1 -0
  80. package/dist/components/product/product-detail/product-detail.js +127 -0
  81. package/dist/components/product/product-detail/product-detail.json +3 -0
  82. package/dist/components/product/product-detail/product-detail.wxml +57 -0
  83. package/dist/components/product/product-detail/product-detail.wxss +1 -0
  84. package/dist/components/product/product-item/product-item.js +56 -0
  85. package/dist/components/product/product-item/product-item.json +3 -0
  86. package/dist/components/product/product-item/product-item.wxml +35 -0
  87. package/dist/components/product/product-item/product-item.wxss +1 -0
  88. package/dist/components/product/product-list/product-list.js +67 -0
  89. package/dist/components/product/product-list/product-list.json +6 -0
  90. package/dist/components/product/product-list/product-list.wxml +16 -0
  91. package/dist/components/product/product-list/product-list.wxss +1 -0
  92. package/dist/components/product/product-order/product-order.js +394 -0
  93. package/dist/components/product/product-order/product-order.json +3 -0
  94. package/dist/components/product/product-order/product-order.wxml +75 -0
  95. package/dist/components/product/product-order/product-order.wxss +1 -0
  96. package/dist/pubComponents/popup/popup.wxss +1 -0
  97. package/dist/sdk/config/index.js +1 -0
  98. package/dist/sdk/plugins/InteractServer.js +1 -0
  99. package/dist/sdk/plugins/LotteryServer.js +1 -0
  100. package/dist/sdk/plugins/MallRewardServer.js +1 -0
  101. package/dist/sdk/plugins/ProductServer.js +1 -0
  102. package/lib/components/announcement/announ-banner/index.wxml +1 -1
  103. package/lib/components/chat-recommend/index.wxml +1 -1
  104. package/lib/components/player/components/controls/controls.wxml +6 -3
  105. package/lib/components/player/components/controls/controls.wxss +1 -1
  106. package/lib/components/player/player.wxml +26 -24
  107. package/lib/components/player/player.wxss +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,62 @@
1
+ <view class="slot-machine">
2
+ <!-- 顶部横幅:抽奖进行中,文字跑马灯,常显 -->
3
+ <view class="slot-banner">
4
+ <view class="slot-banner-inner">
5
+ <text class="slot-banner-text">{{remark}}</text>
6
+ </view>
7
+ </view>
8
+
9
+ <!-- 机器主体 -->
10
+ <view class="slot-body">
11
+ <!-- 顶部装饰灯条 -->
12
+ <view class="slot-top-lights">
13
+ <view wx:for="{{12}}" wx:key="index" class="slot-light-bulb {{index % 2 === 0 ? 'on' : ''}}"></view>
14
+ </view>
15
+
16
+ <!-- 滚轴区域 -->
17
+ <view class="slot-reels-container">
18
+ <!-- 滚轴窗口 -->
19
+ <view class="slot-reels-window">
20
+ <!-- 滚轴1 -->
21
+ <view class="slot-reel-wrap">
22
+ <view class="slot-reel {{stopped1 ? 'stopped' : ''}}" style="transform: translateY({{offset1}}rpx);">
23
+ <view wx:for="{{reelList}}" wx:key="index" class="slot-item">
24
+ <text class="slot-emoji">{{item.emoji}}</text>
25
+ <text class="slot-label">{{item.label}}</text>
26
+ </view>
27
+ </view>
28
+ </view>
29
+ <!-- 滚轴2 -->
30
+ <view class="slot-reel-wrap">
31
+ <view class="slot-reel {{stopped2 ? 'stopped' : ''}}" style="transform: translateY({{offset2}}rpx);">
32
+ <view wx:for="{{reelList}}" wx:key="index" class="slot-item">
33
+ <text class="slot-emoji">{{item.emoji}}</text>
34
+ <text class="slot-label">{{item.label}}</text>
35
+ </view>
36
+ </view>
37
+ </view>
38
+ <!-- 滚轴3 -->
39
+ <view class="slot-reel-wrap">
40
+ <view class="slot-reel {{stopped3 ? 'stopped' : ''}}" style="transform: translateY({{offset3}}rpx);">
41
+ <view wx:for="{{reelList}}" wx:key="index" class="slot-item">
42
+ <text class="slot-emoji">{{item.emoji}}</text>
43
+ <text class="slot-label">{{item.label}}</text>
44
+ </view>
45
+ </view>
46
+ </view>
47
+ </view>
48
+ </view>
49
+
50
+ <!-- 底部操作区 -->
51
+ <view class="slot-bottom-area">
52
+ <!-- 装饰小圆点 -->
53
+ <view class="slot-dots">
54
+ <view class="slot-dot" wx:for="{{7}}" wx:key="i"></view>
55
+ </view>
56
+ <!-- 抽奖按钮 -->
57
+ <view class="slot-draw-btn" bindtap="onDrawTap">
58
+ <text class="slot-btn-text">点我抽奖</text>
59
+ </view>
60
+ </view>
61
+ </view>
62
+ </view>
@@ -0,0 +1 @@
1
+ .slot-machine{align-items:center;display:flex;flex-direction:column;width:500rpx}.slot-banner{margin-bottom:-20rpx;overflow:hidden;position:relative;width:100%;z-index:5}.slot-banner-inner{align-items:center;background:linear-gradient(90deg,#ff6b6b,#ee5a5a 50%,#ff6b6b);border:4rpx solid rgba(255,220,180,.8);border-bottom:none;border-radius:40rpx 40rpx 0 0;box-shadow:inset 0 2rpx 8rpx hsla(0,0%,100%,.3),0 -4rpx 12rpx rgba(200,50,30,.3);display:flex;overflow:hidden;padding:12rpx 30rpx;white-space:nowrap}.slot-banner-text{animation:slot-marquee 3s linear infinite;color:#fff;display:inline-block;font-size:28rpx;font-weight:700;letter-spacing:4rpx;line-height:1.2;padding-left:100%;text-shadow:0 2rpx 4rpx rgba(150,30,10,.5);white-space:nowrap}@keyframes slot-marquee{0%{transform:translateX(0)}to{transform:translateX(-100%)}}.slot-body{background:linear-gradient(180deg,#ff8c42,#ff6b35 25%,#e85d24 60%,#d14d18);border:4rpx solid rgba(255,200,140,.7);border-radius:16rpx;box-shadow:0 12rpx 40rpx rgba(200,70,20,.45),inset 0 2rpx 8rpx rgba(255,220,160,.25);padding:24rpx 20rpx 32rpx;position:relative;width:100%;z-index:3}.slot-top-lights{display:flex;gap:12rpx;justify-content:center;margin-bottom:20rpx;padding:0 10rpx}.slot-light-bulb{background:#c42;border-radius:50%;box-shadow:inset 0 -2rpx 4rpx rgba(0,0,0,.4);height:16rpx;width:16rpx}.slot-light-bulb.on{animation:slot-blink .6s ease-in-out infinite alternate;background:radial-gradient(circle at 35% 35%,#fff 0,#ffd93d 50%,#fa0 100%);box-shadow:0 0 10rpx 4rpx rgba(255,217,61,.7),inset 0 -2rpx 4rpx rgba(0,0,0,.15)}@keyframes slot-blink{0%{opacity:.6}to{opacity:1}}.slot-reels-container{align-items:stretch;display:flex;gap:0}.slot-reels-window{align-items:stretch;background:linear-gradient(180deg,#d9531e,#b8430f);border:12rpx solid #ffd93d;border-radius:16rpx;box-shadow:inset 0 0 0 5rpx rgba(120,45,10,.75),inset 0 5rpx 12rpx rgba(255,224,160,.45),inset 0 -10rpx 20rpx rgba(80,25,0,.5),0 0 0 4rpx rgba(255,217,61,.25),0 10rpx 32rpx rgba(120,40,10,.55);display:flex;flex:1;justify-content:space-evenly;overflow:hidden}.slot-reel-wrap{flex-shrink:0;height:240rpx;overflow:hidden;position:relative;width:140rpx}.slot-reel{display:flex;flex-direction:column;gap:4rpx;transition:none}.slot-reel.stopped{transition:transform .8s cubic-bezier(.17,.67,.12,.99)}.slot-item{align-items:center;background:linear-gradient(180deg,#fffdf8,#fff2dc);border:2rpx solid rgba(230,130,60,.4);border-radius:12rpx;box-shadow:inset 0 2rpx 4rpx hsla(0,0%,100%,.7),0 1rpx 3rpx rgba(180,100,40,.12);box-sizing:border-box;display:flex;flex-direction:column;flex-shrink:0;gap:4rpx;height:130rpx;justify-content:center;margin:0;width:140rpx}.slot-emoji{font-size:44rpx;line-height:1}.slot-label{color:#8b6914;font-size:20rpx;font-weight:500;line-height:1.2;white-space:nowrap}.slot-divider{background:linear-gradient(180deg,transparent,rgba(210,130,50,.4) 20%,rgba(210,130,50,.6) 50%,rgba(210,130,50,.4) 80%,transparent);flex-shrink:0;width:3rpx}.slot-bottom-area{align-items:center;flex-direction:column;margin-top:24rpx}.slot-bottom-area,.slot-dots{display:flex;gap:16rpx}.slot-dot{background:rgba(255,200,120,.6);border-radius:50%;box-shadow:inset 0 -1rpx 2rpx rgba(180,80,20,.3);height:12rpx;width:12rpx}.slot-draw-btn{animation:slot-btn-pulse 1.5s ease-in-out infinite;background:linear-gradient(180deg,#ffe066,#ffb830 40%,#f5a000);border:3rpx solid #e89400;border-radius:48rpx;box-shadow:0 6rpx 20rpx rgba(200,100,0,.4),inset 0 2rpx 4rpx rgba(255,255,220,.6),inset 0 -2rpx 4rpx rgba(180,80,0,.2);padding:18rpx 72rpx}@keyframes slot-btn-pulse{0%,to{box-shadow:0 6rpx 20rpx rgba(200,100,0,.4),inset 0 2rpx 4rpx rgba(255,255,220,.6),inset 0 -2rpx 4rpx rgba(180,80,0,.2);transform:scale(1)}50%{box-shadow:0 10rpx 30rpx rgba(200,100,0,.55),inset 0 2rpx 4rpx rgba(255,255,220,.7),inset 0 -2rpx 4rpx rgba(180,80,0,.2);transform:scale(1.04)}}.slot-btn-text{color:#8b4513;font-size:32rpx;font-weight:700;letter-spacing:6rpx;text-shadow:0 1rpx 2rpx rgba(255,250,230,.8)}
@@ -0,0 +1,153 @@
1
+ Component({
2
+ properties: {
3
+ type: {
4
+ type: String,
5
+ value: 1,
6
+ },
7
+ // 抽奖 ID:用于区分不同抽奖的缓存 key
8
+ lotteryId: {
9
+ type: String,
10
+ value: '',
11
+ },
12
+ width: {
13
+ type: String,
14
+ value: '100%',
15
+ },
16
+ height: {
17
+ type: String,
18
+ value: '100%',
19
+ },
20
+ remark: {
21
+ type: String,
22
+ value: '抽奖进行中...',
23
+ },
24
+ // 兼容原 lottie 版的属性透传,避免未知属性告警
25
+ autoplay: {
26
+ type: Boolean,
27
+ value: false,
28
+ },
29
+ loop: {
30
+ type: Boolean,
31
+ value: false,
32
+ },
33
+ // 外部"消息"控制:true 开始无限转,false 平滑停止
34
+ running: {
35
+ type: Boolean,
36
+ value: false,
37
+ observer(val) {
38
+ if (val) {
39
+ this.playSegment();
40
+ } else {
41
+ this.stop();
42
+ }
43
+ },
44
+ },
45
+ },
46
+
47
+ data: {
48
+ spinning: false, // 是否处于无限旋转状态
49
+ stopping: false, // 是否处于减速停止过渡
50
+ angle: 0, // 当前旋转角度(deg),由 JS 驱动
51
+ },
52
+
53
+ lifetimes: {
54
+ attached() {
55
+ if (this.data.running) {
56
+ // running 初始为 true 时直接开始
57
+ this.playSegment();
58
+ } else if (this._hasSpinCache()) {
59
+ // 刷新前抽奖仍在进行(有缓存),进入页面后自动恢复旋转动画
60
+ this.playSegment();
61
+ }
62
+ },
63
+ detached() {
64
+ // 注意:不在此清除缓存,保证刷新后仍能恢复动画
65
+ this._clearTimer();
66
+ },
67
+ },
68
+
69
+ methods: {
70
+ _clearTimer() {
71
+ if (this._timer) {
72
+ clearInterval(this._timer);
73
+ this._timer = null;
74
+ }
75
+ if (this._stopTimer) {
76
+ clearTimeout(this._stopTimer);
77
+ this._stopTimer = null;
78
+ }
79
+ },
80
+
81
+ // 缓存 key:lottery_<lotteryId>_cache,标记"该抽奖仍在旋转/进行中"
82
+ _cacheKey() {
83
+ return `lottery_${this.data.lotteryId}_cache`;
84
+ },
85
+ _hasSpinCache() {
86
+ return !!wx.getStorageSync(this._cacheKey());
87
+ },
88
+ _setSpinCache() {
89
+ wx.setStorageSync(this._cacheKey(), true);
90
+ },
91
+ _clearSpinCache() {
92
+ wx.removeStorageSync(this._cacheKey());
93
+ },
94
+
95
+ // 点击中心按钮:开始无限循环旋转,并通知父组件"用户发起抽奖"
96
+ playSegment() {
97
+ // 进行中或减速过渡阶段,忽略重复点击,避免动画重复执行 / 重复上报抽奖
98
+ if (this.data.spinning || this.data.stopping) return;
99
+ this._clearTimer();
100
+ this.setData({ spinning: true, stopping: false });
101
+ // 记录缓存:抽奖进行中,刷新后可据此恢复动画
102
+ this._setSpinCache();
103
+ // 每帧递增角度,约 360deg/s,纯 CSS 旋转由 transform 驱动
104
+ this._timer = setInterval(() => {
105
+ this.data.angle += 6;
106
+ this.setData({ angle: this.data.angle });
107
+ }, 16);
108
+ // 透传给父组件,便于其触发服务端抽奖
109
+ this.triggerEvent('draw');
110
+ },
111
+
112
+ // 兼容旧接口:开始旋转
113
+ play() {
114
+ this.playSegment();
115
+ },
116
+
117
+ // 平滑停止。resultIndex 可选:停到该扇区中心(指针在正上方)
118
+ // 返回 true 表示确实触发了减速停止;false 表示当前并未在转(无需等待)
119
+ stop(resultIndex) {
120
+ if (!this.data.spinning && !this.data.stopping) return false;
121
+ this._clearTimer();
122
+ // 抽奖已结束(服务端已返回结果),清除进行中缓存
123
+ this._clearSpinCache();
124
+ const current = this.data.angle;
125
+ let finalAngle = current + 360 * 5; // 默认再转 5 圈后停在当前相对位置
126
+ if (typeof resultIndex === 'number') {
127
+ // 扇区 i 中心角度(顺时针、自正上方起) = i*45 + 22.5
128
+ const center = (resultIndex % 8) * 45 + 22.5;
129
+ // 旋转后使该扇区中心对齐到正上方(0deg):R ≡ -center (mod 360)
130
+ const land = (360 - center) % 360;
131
+ const base = current - (current % 360);
132
+ finalAngle = base + 360 * 5 + land;
133
+ // 保证比当前角度更大(始终向前转)
134
+ if (finalAngle < current + 360) finalAngle += 360;
135
+ }
136
+ // 先切到 stopping(带 transition),再写入最终角度触发平滑减速
137
+ this.setData({ spinning: false, stopping: true }, () => {
138
+ this.setData({ angle: finalAngle });
139
+ });
140
+ // 减速过渡结束后复位 stopping 状态,并通知父组件"已停止"
141
+ this._stopTimer = setTimeout(() => {
142
+ this.setData({ stopping: false });
143
+ this.triggerEvent('stopped', { angle: finalAngle, resultIndex });
144
+ }, 4000);
145
+ return true;
146
+ },
147
+
148
+ // 兼容旧接口:暂停(不带落点)
149
+ pause() {
150
+ this.stop();
151
+ },
152
+ },
153
+ });
@@ -0,0 +1,4 @@
1
+ {
2
+ "component": true,
3
+ "usingComponents": {}
4
+ }
@@ -0,0 +1,91 @@
1
+ <view class="lottery-wheel-container lottery-wheel-{{type}}">
2
+ <view class="lottery-wheel-wrapper">
3
+ <!-- 底座 -->
4
+ <view class="lottery-base"></view>
5
+
6
+ <!-- 转盘主体(angle 由 JS 驱动,stopping 触发减速过渡) -->
7
+ <view class="lottery-wheel-disc {{stopping ? 'stopping' : ''}}" style="transform: rotate({{angle}}deg);">
8
+ <!-- 8 个扇区(含文字+emoji) -->
9
+ <view class="lottery-segment lottery-segment-even" style="--i:0; --rot:0deg;">
10
+ <view class="lottery-segment-content">
11
+ <text class="lottery-segment-text">恭喜中奖</text>
12
+ <text class="lottery-segment-emoji">🎁</text>
13
+ </view>
14
+ </view>
15
+ <view class="lottery-segment lottery-segment-odd" style="--i:1; --rot:45deg;">
16
+ <view class="lottery-segment-content">
17
+ <text class="lottery-segment-text">谢谢参与</text>
18
+ <text class="lottery-segment-emoji">😊</text>
19
+ </view>
20
+ </view>
21
+ <view class="lottery-segment lottery-segment-even" style="--i:2; --rot:90deg;">
22
+ <view class="lottery-segment-content">
23
+ <text class="lottery-segment-text">恭喜中奖</text>
24
+ <text class="lottery-segment-emoji">🎁</text>
25
+ </view>
26
+ </view>
27
+ <view class="lottery-segment lottery-segment-odd" style="--i:3; --rot:135deg;">
28
+ <view class="lottery-segment-content">
29
+ <text class="lottery-segment-text">谢谢参与</text>
30
+ <text class="lottery-segment-emoji">😊</text>
31
+ </view>
32
+ </view>
33
+ <view class="lottery-segment lottery-segment-even" style="--i:4; --rot:180deg;">
34
+ <view class="lottery-segment-content">
35
+ <text class="lottery-segment-text">恭喜中奖</text>
36
+ <text class="lottery-segment-emoji">🎁</text>
37
+ </view>
38
+ </view>
39
+ <view class="lottery-segment lottery-segment-odd" style="--i:5; --rot:225deg;">
40
+ <view class="lottery-segment-content">
41
+ <text class="lottery-segment-text">谢谢参与</text>
42
+ <text class="lottery-segment-emoji">😊</text>
43
+ </view>
44
+ </view>
45
+ <view class="lottery-segment lottery-segment-even" style="--i:6; --rot:270deg;">
46
+ <view class="lottery-segment-content">
47
+ <text class="lottery-segment-text">恭喜中奖</text>
48
+ <text class="lottery-segment-emoji">🎁</text>
49
+ </view>
50
+ </view>
51
+ <view class="lottery-segment lottery-segment-odd" style="--i:7; --rot:315deg;">
52
+ <view class="lottery-segment-content">
53
+ <text class="lottery-segment-text">谢谢参与</text>
54
+ <text class="lottery-segment-emoji">😊</text>
55
+ </view>
56
+ </view>
57
+ </view>
58
+
59
+ <!-- 外圈灯泡装饰(兄弟节点,避免被盘面圆形裁剪;与盘面同步旋转) -->
60
+ <view class="lottery-lights {{stopping ? 'stopping' : ''}}" style="transform: rotate({{angle}}deg);">
61
+ <view class="lottery-light"></view>
62
+ <view class="lottery-light"></view>
63
+ <view class="lottery-light"></view>
64
+ <view class="lottery-light"></view>
65
+ <view class="lottery-light"></view>
66
+ <view class="lottery-light"></view>
67
+ <view class="lottery-light"></view>
68
+ <view class="lottery-light"></view>
69
+ <view class="lottery-light"></view>
70
+ <view class="lottery-light"></view>
71
+ <view class="lottery-light"></view>
72
+ <view class="lottery-light"></view>
73
+ </view>
74
+
75
+ <!-- 顶部抽奖指针(向上,底部贴着中心按钮) -->
76
+ <view class="lottery-pointer">
77
+ <view class="lottery-pointer-inner"></view>
78
+ </view>
79
+
80
+ <!-- 中心按钮:点我抽奖(不随盘面旋转,独立无限缩放) -->
81
+ <view class="lottery-center-btn" bindtap="playSegment">
82
+ <text class="lottery-center-btn-text">点我</text>
83
+ <text class="lottery-center-btn-text">抽奖</text>
84
+ </view>
85
+
86
+ <!-- 状态文案:常显 -->
87
+ <view class="lotterying">
88
+ <view class="lotterying-text">{{remark}}</view>
89
+ </view>
90
+ </view>
91
+ </view>
@@ -0,0 +1 @@
1
+ .lottery-wheel-container{align-items:center;display:flex;flex-direction:column;justify-content:center}.lottery-wheel-wrapper{height:720rpx;position:relative;width:750rpx}.lottery-base{background:linear-gradient(180deg,#e63e30,#c41a0d);border-radius:20rpx 20rpx 60rpx 60rpx;bottom:0;box-shadow:0 10rpx 30rpx rgba(198,26,13,.5),inset 0 4rpx 0 hsla(0,0%,100%,.2);height:120rpx;width:360rpx;z-index:16}.lottery-base,.lottery-base:after{left:50%;position:absolute;transform:translateX(-50%)}.lottery-base:after{background:rgba(0,0,0,.15);border-radius:20rpx;content:"";height:40rpx;top:20rpx;width:320rpx}.lottery-wheel-disc{background:transparent;border-radius:50%;box-shadow:0 8rpx 30rpx rgba(0,0,0,.25);height:440rpx;left:50%;margin-left:-220rpx;margin-top:-200rpx;overflow:hidden;position:absolute;top:50%;width:440rpx;z-index:10}.lottery-wheel-disc:after{border:8rpx solid rgba(230,62,48,.7);border-radius:50%;z-index:6}.lottery-wheel-disc:after,.lottery-wheel-disc:before{content:"";inset:0;pointer-events:none;position:absolute}.lottery-wheel-disc:before{background:repeating-conic-gradient(from 22.5deg,transparent 0deg 44deg,rgba(200,60,40,.45) 44deg 45deg);border-radius:50%;z-index:5}.lottery-wheel-disc.stopping{transition:transform 4s cubic-bezier(.17,.67,.12,.99)}.lottery-segment{height:100%;left:0;position:absolute;top:0;transform:rotate(calc(var(--rot)));transform-origin:center center;width:100%}.lottery-segment .lottery-segment-content{align-items:center;display:flex;flex-direction:column;justify-content:center;left:50%;position:absolute;text-align:center;top:50%;transform:translate(-50%,-50%) translateY(-145rpx);width:150rpx}.lottery-segment .lottery-segment-text{font-size:24rpx;font-weight:700;white-space:nowrap}.lottery-segment .lottery-segment-emoji{font-size:36rpx;line-height:1.2}.lottery-segment-even{background:conic-gradient(from -22.5deg,#ff8c42 0deg 45deg,transparent 45deg 1turn)}.lottery-segment-even .lottery-segment-text{color:#fff;text-shadow:0 2rpx 4rpx rgba(0,0,0,.25)}.lottery-segment-odd{background:conic-gradient(from -22.5deg,#fff1d6 0deg 45deg,transparent 45deg 1turn)}.lottery-segment-odd .lottery-segment-text{color:#c41a0d}.lottery-lights{border-radius:50%;height:440rpx;left:50%;margin-left:-220rpx;margin-top:-200rpx;pointer-events:none;position:absolute;top:50%;width:440rpx;z-index:15}.lottery-lights.stopping{transition:transform 4s cubic-bezier(.17,.67,.12,.99)}.lottery-lights .lottery-light{animation:lottery-light-blink .8s ease-in-out infinite alternate;background:radial-gradient(circle at 35% 35%,#fff 0,#ffd93d 50%,#fa0 100%);border-radius:50%;box-shadow:0 0 12rpx 4rpx rgba(255,217,61,.8);height:20rpx;left:50%;margin-left:-10rpx;margin-top:-10rpx;position:absolute;top:50%;transform-origin:center;width:20rpx}.lottery-lights .lottery-light:first-child{transform:rotate(0deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(2){transform:rotate(30deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(3){transform:rotate(60deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(4){transform:rotate(90deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(5){transform:rotate(120deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(6){transform:rotate(150deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(7){transform:rotate(180deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(8){transform:rotate(210deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(9){transform:rotate(240deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(10){transform:rotate(270deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(11){transform:rotate(300deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(12){transform:rotate(330deg) translateX(235rpx)}.lottery-lights .lottery-light:nth-child(2n){animation-delay:.4s}@keyframes lottery-light-blink{0%{box-shadow:0 0 12rpx 4rpx rgba(255,217,61,.9);opacity:1}to{box-shadow:0 0 6rpx 2rpx rgba(255,217,61,.4);opacity:.5}}.lottery-center-btn{align-items:center;animation:lottery-btn-zoom .8s ease-in-out infinite alternate;background:linear-gradient(145deg,#ff6b5b,#e63e30);border:3rpx solid #ffd93d;border-radius:50%;box-shadow:0 4rpx 16rpx rgba(198,26,13,.5),inset 0 2rpx 4rpx hsla(0,0%,100%,.3);color:#fff;display:flex;flex-direction:column;height:100rpx;justify-content:center;left:50%;margin-left:-50rpx;margin-top:-30rpx;position:absolute;top:50%;width:100rpx;z-index:20}.lottery-center-btn:active{opacity:.85}.lottery-center-btn .lottery-center-btn-text{font-size:20rpx;font-weight:700;line-height:1.2;text-shadow:0 2rpx 4rpx rgba(0,0,0,.2)}.lottery-pointer{background:#ffd93d;-webkit-filter:drop-shadow(0 3rpx 6rpx rgba(0,0,0,.25));filter:drop-shadow(0 3rpx 6rpx rgba(0,0,0,.25));height:40rpx;left:50%;top:290rpx;transform:translateX(-50%);width:44rpx;z-index:18}.lottery-pointer,.lottery-pointer-inner{-webkit-clip-path:polygon(50% 0,0 100%,100% 100%);clip-path:polygon(50% 0,0 100%,100% 100%);position:absolute}.lottery-pointer-inner{background:linear-gradient(90deg,#ff7a6a,#ff7a6a 50%,#d62f23 0,#d62f23);bottom:0;left:4rpx;right:4rpx;top:4rpx}@keyframes lottery-btn-zoom{0%{transform:scale(1)}to{transform:scale(1.12)}}.lotterying{bottom:60rpx;color:#fff;font-size:28rpx;left:50%;margin-left:-150rpx;overflow:hidden;position:absolute;width:300rpx;z-index:999}.lotterying .lotterying-text{animation:marquee 3s linear infinite;display:inline-block;padding-left:100%;white-space:nowrap}@keyframes marquee{0%{transform:translateX(0)}to{transform:translateX(-100%)}}
@@ -0,0 +1,101 @@
1
+ Component({
2
+ properties: {
3
+ visible: {
4
+ type: Boolean,
5
+ value: false,
6
+ },
7
+ lotteryId: {
8
+ type: String,
9
+ value: '',
10
+ },
11
+ sdkInstance: {
12
+ type: Object,
13
+ value: null,
14
+ },
15
+ },
16
+
17
+ data: {
18
+ winnersList: [],
19
+ total: 0,
20
+ pos: 0,
21
+ limit: 20,
22
+ loading: false,
23
+ hasMore: true,
24
+ },
25
+
26
+ observers: {
27
+ visible: function (visible) {
28
+ if (visible) {
29
+ this.initWinnersList();
30
+ } else {
31
+ this.setData({
32
+ winnersList: [],
33
+ pos: 0,
34
+ hasMore: true,
35
+ });
36
+ }
37
+ },
38
+ },
39
+
40
+ methods: {
41
+ async initWinnersList() {
42
+ this.setData({
43
+ winnersList: [],
44
+ pos: 0,
45
+ hasMore: true,
46
+ loading: true,
47
+ });
48
+ await this.loadWinnersList();
49
+ },
50
+
51
+ async loadWinnersList() {
52
+ if (!this.properties.lotteryId || !this.properties.sdkInstance) return;
53
+
54
+ const { lotteryId, sdkInstance } = this.properties;
55
+ const { pos, limit } = this.data;
56
+
57
+ try {
58
+ const lotteryServer = sdkInstance.get('lotteryServer');
59
+ if (!lotteryServer) return;
60
+ const res = await lotteryServer.getWinnerList({
61
+ lottery_id: lotteryId,
62
+ pos,
63
+ limit,
64
+ });
65
+
66
+ if (res && res.code === 200 && res.data) {
67
+ const newList = res.data.list || [];
68
+ const total = res.data.total || 0;
69
+
70
+ this.setData({
71
+ winnersList: pos === 0 ? newList : [...this.data.winnersList, ...newList],
72
+ total,
73
+ hasMore: pos + newList.length < total,
74
+ loading: false,
75
+ });
76
+ } else {
77
+ this.setData({ loading: false });
78
+ }
79
+ } catch (err) {
80
+ console.error('获取中奖名单失败:', err);
81
+ this.setData({ loading: false });
82
+ }
83
+ },
84
+
85
+ onScrollToLower() {
86
+ if (this.data.loading || !this.data.hasMore) return;
87
+
88
+ this.setData({
89
+ pos: this.data.pos + this.data.limit,
90
+ loading: true,
91
+ });
92
+
93
+ this.loadWinnersList();
94
+ },
95
+
96
+ close() {
97
+ this.setData({ visible: false });
98
+ this.triggerEvent('close');
99
+ },
100
+ },
101
+ });
@@ -0,0 +1,4 @@
1
+ {
2
+ "component": true,
3
+ "usingComponents": {}
4
+ }
@@ -0,0 +1,39 @@
1
+ <view wx:if="{{visible}}" class="lottery-winners-modal">
2
+ <view class="lottery-winners-mask" bindtap="close"></view>
3
+ <view class="lottery-winners-content">
4
+ <view class="lottery-winners-header">
5
+ <text class="lottery-winners-title">中奖名单</text>
6
+ <view class="lottery-winners-close" bindtap="close">
7
+ <icon type="cancel" size="24" color="#ffb029;" />
8
+ </view>
9
+ </view>
10
+ <view class="lottery-winners-body">
11
+ <scroll-view class="lottery-winners-list" scroll-y bindscrolltolower="onScrollToLower">
12
+ <view class="lottery-winners-list-inner">
13
+ <view wx:for="{{winnersList}}" wx:key="lottery_user_id" class="lottery-winners-item" wx:class="{ isSelf: item.win }">
14
+ <view class="lottery-winners-rank">
15
+ {{index < 9 ? '0' + (index + 1) : (index + 1)}}
16
+ </view>
17
+ <image class="lottery-winners-avatar" src="{{item.lottery_user_avatar || 'https://cnstatic01.e.vhall.com/common-static/images/default_avatar.png'}}" mode="aspectFill" />
18
+ <view class="lottery-winners-nickname">
19
+ {{item.lottery_user_nickname }}
20
+ </view>
21
+ <view class="lottery-winners-prize">
22
+ 获得"{{item.lottery_award_name || ''}}"
23
+ </view>
24
+ </view>
25
+ </view>
26
+ <view wx:if="{{loading}}" class="lottery-winners-loading">
27
+ <text>加载中...</text>
28
+ </view>
29
+ <view wx:if="{{!loading && !hasMore && winnersList.length > 0}}" class="lottery-winners-end">
30
+ <text>没有更多了</text>
31
+ </view>
32
+ <view wx:if="{{!loading && winnersList.length == 0}}" class="lottery-winners-empty">
33
+ <text class="empty-emoji">🙁</text>
34
+ <text class="empty-text">当前无中奖用户</text>
35
+ </view>
36
+ </scroll-view>
37
+ </view>
38
+ </view>
39
+ </view>
@@ -0,0 +1 @@
1
+ .lottery-winners-modal{align-items:flex-end;bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:2000}.lottery-winners-mask{background:rgba(0,0,0,.5);bottom:0;left:0;position:absolute;right:0;top:0}.lottery-winners-content{background:linear-gradient(37.94deg,#fffbe8 3.86%,#fbf0e6 84.36%);border-radius:32rpx 32rpx 0 0;display:flex;flex-direction:column;max-height:70vh;position:relative;width:100%}.lottery-winners-header{align-items:center;display:flex;justify-content:center;padding:30rpx;position:relative}.lottery-winners-title{color:#ad2000;font-size:1.29rem}.lottery-winners-close{align-items:center;display:flex;height:48rpx;justify-content:center;position:absolute;right:30rpx;top:50%;transform:translateY(-50%);width:48rpx}.lottery-winners-body{flex:1;overflow:hidden;padding:0 30rpx 30rpx}.lottery-winners-list{height:55vh}.lottery-winners-list-inner{background:#fff;border-radius:24rpx;overflow:hidden}.lottery-winners-item{align-items:center;border-bottom:1rpx solid #f5f5f5;color:#333;display:flex;padding:30rpx}.lottery-winners-item:last-child{border-bottom:none}.lottery-winners-item.isSelf .lottery-winners-nickname,.lottery-winners-item.isSelf .lottery-winners-prize,.lottery-winners-item.isSelf .lottery-winners-rank{color:#fb2626}.lottery-winners-rank{color:#333;font-size:1.14rem;font-weight:700;margin-right:24rpx;width:60rpx}.lottery-winners-avatar{background:#f5f5f5;border-radius:50%;height:80rpx;margin-right:24rpx;width:80rpx}.lottery-winners-nickname{color:#333;flex:1;font-size:1.14rem}.lottery-winners-prize{color:#333;font-size:1rem}.lottery-winners-end,.lottery-winners-loading{color:#999;font-size:.93rem;padding:30rpx;text-align:center}.lottery-winners-empty{align-items:center;background:#fff;border-radius:24rpx;display:flex;flex-direction:column;height:100%;justify-content:center}.lottery-winners-empty .empty-emoji{font-size:4.29rem;margin-bottom:30rpx}.lottery-winners-empty .empty-text{color:#999;font-size:1.07rem}