vhall-mini-sdk 0.2.1 → 0.3.1
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.
- package/CHANGELOG.md +44 -0
- package/lib/components/announcement/announ-banner/index.js +40 -0
- package/lib/components/announcement/announ-banner/index.json +4 -0
- package/lib/components/announcement/announ-banner/index.wxml +13 -0
- package/lib/components/announcement/announ-banner/index.wxss +1 -0
- package/lib/components/announcement/announ-icon/index.js +69 -0
- package/lib/components/announcement/announ-icon/index.json +3 -0
- package/lib/components/announcement/announ-icon/index.wxml +10 -0
- package/lib/components/announcement/announ-icon/index.wxss +1 -0
- package/lib/components/announcement/announ-popup/index.js +44 -0
- package/lib/components/announcement/announ-popup/index.json +7 -0
- package/lib/components/announcement/announ-popup/index.wxml +39 -0
- package/lib/components/announcement/announ-popup/index.wxss +1 -0
- package/lib/components/announcement/index.js +223 -0
- package/lib/components/announcement/index.json +9 -0
- package/lib/components/announcement/index.wxml +6 -0
- package/lib/components/announcement/index.wxss +0 -0
- package/lib/components/live-landscape/live-landscape.js +7 -1
- package/lib/components/live-landscape/live-landscape.json +2 -0
- package/lib/components/live-landscape/live-landscape.wxml +7 -4
- package/lib/components/live-portrait/live-portrait.js +10 -2
- package/lib/components/live-portrait/live-portrait.json +3 -1
- package/lib/components/live-portrait/live-portrait.wxml +8 -4
- package/lib/components/mall-reward/index.js +47 -29
- package/lib/components/product/product-card/product-card.js +5 -6
- package/lib/components/product/product-detail/product-detail.js +6 -6
- package/lib/components/product/product-list/product-list.js +2 -3
- package/lib/sdk/main/index.js +2 -2
- package/lib/sdk/plugins/MallRewardServer.js +1 -1
- package/package.json +8 -11
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
本项目所有重要变更均记录于此文件。
|
|
4
|
+
|
|
5
|
+
格式遵循 [Keep a Changelog](https://keepachangelog.com/),版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
6
|
+
|
|
7
|
+
## [0.3.1] - 2026-08-13
|
|
8
|
+
|
|
9
|
+
### 修复
|
|
10
|
+
|
|
11
|
+
- 修复公告关闭事件定义重复问题。
|
|
12
|
+
|
|
13
|
+
## [0.3.0] - 2026-08-13
|
|
14
|
+
|
|
15
|
+
### 新增
|
|
16
|
+
|
|
17
|
+
- 直播和回放场景下新增 <span style="color:red">公告</span> 能力。
|
|
18
|
+
|
|
19
|
+
- VhallMiniSdk增加 <span style="color:red">VERSION</span> 属性,实例增加 <span style="color:red">version</span> 属性, 方便获取当前SDK版本号。
|
|
20
|
+
|
|
21
|
+
### 变更
|
|
22
|
+
|
|
23
|
+
- SDK 错误页支持直播模式(mode,0:竖屏,1:横屏)初始0或1,不用空值,业务侧无需额外调用 setData 即可正常展示。
|
|
24
|
+
|
|
25
|
+
### 修复
|
|
26
|
+
|
|
27
|
+
- 修复某些场景下商城奖励计时不动以及计时不准确的问题。
|
|
28
|
+
|
|
29
|
+
## [0.2.1] - 2026-08-06
|
|
30
|
+
|
|
31
|
+
### 变更
|
|
32
|
+
|
|
33
|
+
- SDK和几个插件都去掉了具名导出,避免默认导出和具名导出混用带来的问题。
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
// 旧
|
|
37
|
+
import { MallRewardServer } from ...
|
|
38
|
+
// 新
|
|
39
|
+
import MallRewardServer from ...
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 修复
|
|
43
|
+
|
|
44
|
+
- 修复某些场景下收不到消息的问题。
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Component({
|
|
2
|
+
properties: {
|
|
3
|
+
text: {
|
|
4
|
+
type: String,
|
|
5
|
+
value: '',
|
|
6
|
+
},
|
|
7
|
+
show: {
|
|
8
|
+
type: Boolean,
|
|
9
|
+
value: false,
|
|
10
|
+
},
|
|
11
|
+
static: {
|
|
12
|
+
type: Boolean,
|
|
13
|
+
value: false,
|
|
14
|
+
},
|
|
15
|
+
// 直播间模式:0=竖屏,1=横屏(样式区分)
|
|
16
|
+
mode: {
|
|
17
|
+
type: Number,
|
|
18
|
+
value: 0,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
data: {
|
|
23
|
+
duration: 6, // 滚动动画时长(秒),按文字长度动态计算
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
observers: {
|
|
27
|
+
// 文字越长滚动时长越大,保持匀速观感
|
|
28
|
+
text(val) {
|
|
29
|
+
const len = (val || '').length;
|
|
30
|
+
const duration = Math.max(4, Math.ceil(len * 0.2));
|
|
31
|
+
this.setData({ duration });
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
methods: {
|
|
36
|
+
onClose() {
|
|
37
|
+
this.triggerEvent('close');
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<view wx:if="{{show }}" class="announ-banner {{static ? 'announ-banner--static' : ''}} mode-{{mode}}">
|
|
2
|
+
<view class="announ-banner-icon">
|
|
3
|
+
<view class="announ-banner-icon__box"></view>
|
|
4
|
+
<view class="announ-banner-icon__body"></view>
|
|
5
|
+
<view class="announ-banner-icon__wave announ-banner-icon__wave--top"></view>
|
|
6
|
+
<view class="announ-banner-icon__wave announ-banner-icon__wave--mid"></view>
|
|
7
|
+
<view class="announ-banner-icon__wave announ-banner-icon__wave--bottom"></view>
|
|
8
|
+
</view>
|
|
9
|
+
<view class="announ-banner-text-wrap">
|
|
10
|
+
<view class="announ-banner-text" style="animation-duration:{{duration}}s">{{text}}</view>
|
|
11
|
+
</view>
|
|
12
|
+
<view class="announ-banner-close" catchtap="onClose">✕</view>
|
|
13
|
+
</view>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.announ-banner{align-items:center;background:rgba(0,0,0,.5);border-radius:40rpx;box-sizing:border-box;color:#fff;display:flex;font-size:24rpx;left:12rpx;padding:0 12rpx;position:fixed;right:12rpx;top:180rpx;z-index:99}.announ-banner-icon{color:#fff;flex-shrink:0;height:32rpx;margin-right:16rpx;position:relative;width:34rpx}.mode-1 .announ-banner-icon{color:#fb3a32}.announ-banner-icon__box{background:currentColor;border-bottom-left-radius:4rpx;border-top-left-radius:4rpx;height:14rpx;left:3rpx;position:absolute;top:9rpx;width:7rpx;z-index:2}.announ-banner-icon__body{background:currentColor;border-radius:4rpx 6rpx 6rpx 4rpx;-webkit-clip-path:polygon(0 20%,0 80%,78% 100%,78% 0);clip-path:polygon(0 20%,0 80%,78% 100%,78% 0);height:28rpx;left:8rpx;position:absolute;top:2rpx;width:15rpx}.announ-banner-icon__wave{background:currentColor;border-radius:4rpx;position:absolute}.announ-banner-icon__wave--top{height:4rpx;right:4rpx;top:5rpx;transform:rotate(-32deg);width:9rpx}.announ-banner-icon__wave--mid{height:4rpx;right:1rpx;top:14rpx;width:11rpx}.announ-banner-icon__wave--bottom{bottom:5rpx;height:4rpx;right:4rpx;transform:rotate(32deg);width:9rpx}.announ-banner-text-wrap{align-items:center;display:flex;flex:1;height:100%;overflow:hidden;padding:6rpx 0}.announ-banner-text{animation:announ-banner-scroll linear infinite;display:inline-block;padding-left:100%;white-space:nowrap}.announ-banner--static .announ-banner-text{animation:none;padding-left:0}.announ-banner-close{flex-shrink:0;font-size:32rpx;margin-left:16rpx}.announ-banner.mode-1{background:linear-gradient(59.32deg,#ffebe9,#edecff 107.06%);border-radius:0;color:#262626;font-size:28rpx;left:0;max-width:none;padding:16rpx 12rpx;right:0;top:calc(56.25vw + 85rpx);transform:none;width:100%}@keyframes announ-banner-scroll{0%{transform:translateX(0)}to{transform:translateX(-100%)}}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Component({
|
|
2
|
+
properties: {
|
|
3
|
+
// 是否显示公告图标
|
|
4
|
+
showIcon: {
|
|
5
|
+
type: Boolean,
|
|
6
|
+
value: false,
|
|
7
|
+
},
|
|
8
|
+
// 未读角标数字
|
|
9
|
+
badge: {
|
|
10
|
+
type: Number,
|
|
11
|
+
value: 0,
|
|
12
|
+
},
|
|
13
|
+
// 直播间模式:0=竖屏,1=横屏(样式区分)
|
|
14
|
+
mode: {
|
|
15
|
+
type: Number,
|
|
16
|
+
value: 0,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
data: {
|
|
20
|
+
x: 20,
|
|
21
|
+
y: 40,
|
|
22
|
+
startX: 0,
|
|
23
|
+
startY: 0,
|
|
24
|
+
hasMoved: false,
|
|
25
|
+
},
|
|
26
|
+
lifetimes: {
|
|
27
|
+
attached() {
|
|
28
|
+
// 初始定位:竖屏在左上角;横屏 70rpx≈35px,在右下角抽奖历史图标上方
|
|
29
|
+
try {
|
|
30
|
+
const info = wx.getSystemInfoSync();
|
|
31
|
+
const iconSize = this.data.mode === 1 ? 35 : 42;
|
|
32
|
+
if (this.data.mode === 1) {
|
|
33
|
+
// 横屏:距右 40rpx≈20px;历史图标 bottom:200rpx + 高 70rpx + 间隔 36rpx ≈ 306rpx
|
|
34
|
+
const rightGap = 20;
|
|
35
|
+
const bottomGap = 160;
|
|
36
|
+
const x = Math.max(0, info.windowWidth - iconSize - rightGap);
|
|
37
|
+
const y = Math.max(0, info.windowHeight - iconSize - bottomGap);
|
|
38
|
+
this.setData({ x, y });
|
|
39
|
+
} else {
|
|
40
|
+
// 竖屏:左上角,留 12rpx≈6px 边距
|
|
41
|
+
const x = 6;
|
|
42
|
+
const y = 40;
|
|
43
|
+
this.setData({ x, y });
|
|
44
|
+
}
|
|
45
|
+
} catch (e) {
|
|
46
|
+
// 获取失败则保持默认左上角
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
methods: {
|
|
51
|
+
onTouchStart(e) {
|
|
52
|
+
this.setData({ hasMoved: false });
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
onTouchEnd(e) {
|
|
56
|
+
this.data.hasMoved = false;
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
onDragChange(e) {
|
|
60
|
+
const { x, y } = e.detail;
|
|
61
|
+
this.setData({ x, y, hasMoved: true });
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
onTapIcon() {
|
|
65
|
+
if (this.data.hasMoved) return;
|
|
66
|
+
this.triggerEvent('onTapIcon');
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<movable-area class="drag-area">
|
|
2
|
+
<movable-view wx:if="{{showIcon}}" class="drag-view" direction="all" x="{{x}}" y="{{y}}" damping="{{40}}" out-of-bounds="{{false}}" bindchange="onDragChange" bindtouchstart="onTouchStart" bindtouchend="onTouchEnd">
|
|
3
|
+
<view class="announ-icon mode-{{mode}}" bindtap="onTapIcon">
|
|
4
|
+
<image wx:if="{{mode === 1}}" class="announ-icon-img" src="https://t-alistatic01.e.vhall.com/common-static/saas-wap/static/img/notice-icon.a86f1993.png" mode="aspectFit" />
|
|
5
|
+
<image wx:else class="announ-icon-img" src="https://t-alistatic01.e.vhall.com/common-static/images/mp/announ_icon.png" mode="aspectFit" />
|
|
6
|
+
<text wx:if="{{mode !== 1}}" class="announ-icon-text">公告</text>
|
|
7
|
+
<view wx:if="{{badge > 0}}" class="announ-icon-badge">{{badge > 99 ? '99+' : badge}}</view>
|
|
8
|
+
</view>
|
|
9
|
+
</movable-view>
|
|
10
|
+
</movable-area>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.drag-area{height:100vh;left:0;pointer-events:none;position:fixed;top:0;width:100vw;z-index:100}.drag-view{height:96rpx;pointer-events:auto;top:10rpx;width:96rpx}.announ-icon{align-items:center;background:rgba(0,0,0,.4);border-radius:50%;display:flex;flex-direction:column;height:84rpx;justify-content:center;position:relative;width:84rpx}.announ-icon.mode-1{height:70rpx;width:70rpx}.announ-icon-img{height:64rpx;width:64rpx}.mode-1 .announ-icon-img{height:70rpx;width:70rpx}.announ-icon-text{color:#fff;font-size:24rpx;margin-top:-20rpx}.announ-icon-badge{align-items:center;background:#ff3b30;border:2rpx solid #fff;border-radius:16rpx;box-sizing:border-box;color:#fff;display:flex;font-size:20rpx;font-weight:700;height:32rpx;justify-content:center;min-width:32rpx;padding:0 8rpx;position:absolute;right:-8rpx;top:-8rpx}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Component({
|
|
2
|
+
properties: {
|
|
3
|
+
show: { type: Boolean, value: false },
|
|
4
|
+
// 公告信息(store.announcement)
|
|
5
|
+
info: { type: Object, value: null },
|
|
6
|
+
},
|
|
7
|
+
|
|
8
|
+
data: {
|
|
9
|
+
list: [],
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
observers: {
|
|
13
|
+
info: function (info) {
|
|
14
|
+
const rawList = info?.list || [];
|
|
15
|
+
this.setData({
|
|
16
|
+
list: rawList.map((item) => ({
|
|
17
|
+
...item,
|
|
18
|
+
_text: this.getContentText(item.content),
|
|
19
|
+
_time: this.formatTime(item.created_at),
|
|
20
|
+
})),
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
methods: {
|
|
26
|
+
getContentText(content) {
|
|
27
|
+
if (!content) return '';
|
|
28
|
+
if (typeof content === 'string') return content;
|
|
29
|
+
return content.content || content.text || '';
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
formatTime(time) {
|
|
33
|
+
if (!time) return '';
|
|
34
|
+
if (typeof time !== 'string') return '';
|
|
35
|
+
// 将 "2026-08-07 16:47:13" 截断为 "08-07 16:47"
|
|
36
|
+
const matched = time.match(/\d{4}-(\d{2}-\d{2})\s+(\d{2}:\d{2}):\d{2}/);
|
|
37
|
+
return matched ? `${matched[1]} ${matched[2]}` : time;
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
onClose() {
|
|
41
|
+
this.triggerEvent('close');
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<vh-popup
|
|
2
|
+
wx:if="{{show}}"
|
|
3
|
+
visible="{{show}}"
|
|
4
|
+
showClose="{{true}}"
|
|
5
|
+
mode="bottom"
|
|
6
|
+
hasMask="{{true}}"
|
|
7
|
+
maskClosable="{{true}}"
|
|
8
|
+
bgColor="#f7f7f7"
|
|
9
|
+
bind:close="onClose"
|
|
10
|
+
>
|
|
11
|
+
<view class="announ-popup">
|
|
12
|
+
<view class="announ-popup-header">
|
|
13
|
+
<text class="announ-popup-star left">✦</text>
|
|
14
|
+
<text class="announ-popup-title">公告</text>
|
|
15
|
+
<text class="announ-popup-star right">✦</text>
|
|
16
|
+
</view>
|
|
17
|
+
<scroll-view class="announ-popup-list" scroll-y>
|
|
18
|
+
<view class="announ-items">
|
|
19
|
+
<view
|
|
20
|
+
wx:for="{{list}}"
|
|
21
|
+
wx:key="id"
|
|
22
|
+
class="announ-item {{index === list.length - 1 ? 'last' : ''}} {{index === 0 ? 'first' : ''}}"
|
|
23
|
+
>
|
|
24
|
+
<view class="announ-item-timeline">
|
|
25
|
+
<view class="announ-item-line announ-item-line-top"></view>
|
|
26
|
+
<view class="announ-item-dot-outer">
|
|
27
|
+
<view class="announ-item-dot-inner"></view>
|
|
28
|
+
</view>
|
|
29
|
+
<view class="announ-item-line announ-item-line-bottom"></view>
|
|
30
|
+
</view>
|
|
31
|
+
<view class="announ-item-content">
|
|
32
|
+
<view class="announ-item-text">{{item._text}}</view>
|
|
33
|
+
<view class="announ-item-time">{{item._time}}</view>
|
|
34
|
+
</view>
|
|
35
|
+
</view>
|
|
36
|
+
</view>
|
|
37
|
+
</scroll-view>
|
|
38
|
+
</view>
|
|
39
|
+
</vh-popup>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.popup-body{display:flex}.announ-popup{background:#f7f7f7;box-sizing:border-box;display:flex;flex-direction:column;height:50vh;width:100%}.announ-popup-header{align-items:center;display:flex;justify-content:center;margin-bottom:32rpx;position:relative}.announ-popup-title{color:#1a1a1a;font-size:36rpx;font-weight:600;position:relative}.announ-popup-title:after{background:#ff4d4f;border-radius:4rpx;bottom:-4rpx;content:"";height:8rpx;left:50%;opacity:.6;position:absolute;transform:translateX(-50%);width:60%}.announ-popup-star{color:#ffcd00;font-size:24rpx;margin:0 12rpx}.announ-popup-star.left{transform:rotate(-15deg)}.announ-popup-star.right{transform:rotate(15deg)}.announ-popup-list{box-sizing:border-box;flex:1;min-height:0;overflow:hidden}.announ-popup-items{position:relative}.announ-popup-line{border-left:1rpx dashed #bfbfbf;left:50%;position:absolute;transform:translateX(-50%);width:0}.announ-item{display:flex;padding-bottom:32rpx;padding-left:48rpx;position:relative}.announ-item-timeline{border-left:1rpx dashed #bfbfbf;bottom:0;left:16rpx;position:absolute;top:0;width:24rpx}.announ-item-dot-outer{align-items:center;background:#fff;border:3rpx solid #ccc;border-radius:50%;box-sizing:border-box;display:flex;flex-shrink:0;height:28rpx;justify-content:center;left:-14rpx;position:absolute;top:0;width:28rpx;z-index:1}.announ-item-dot-inner{background:#ccc;border-radius:50%;box-sizing:border-box;height:12rpx;width:12rpx}.announ-item.first .announ-item-dot-outer{background:#fff;border-color:#fb2626}.announ-item.first .announ-item-dot-inner{background:#fb2626}.announ-item.last{padding-bottom:0}.announ-item.last .announ-item-timeline{border:none}.announ-item-content{background:#fff;border-radius:12rpx;flex:1;padding:20rpx 24rpx}.announ-item-text{color:#1a1a1a;font-size:28rpx;line-height:1.5;margin-bottom:12rpx;word-break:break-all}.announ-item-time{color:#999;font-size:24rpx}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
Component({
|
|
2
|
+
properties: {
|
|
3
|
+
sdkInstance: {
|
|
4
|
+
type: Object,
|
|
5
|
+
value: null,
|
|
6
|
+
},
|
|
7
|
+
// 直播间模式:0=竖屏,1=横屏(样式区分)
|
|
8
|
+
mode: {
|
|
9
|
+
type: Number,
|
|
10
|
+
value: 0,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
data: {
|
|
15
|
+
announInfo: null, // 公告信息
|
|
16
|
+
showIcon: false, // 是否显示公告小图标
|
|
17
|
+
showPopup: false, // 是否显示公告弹窗
|
|
18
|
+
showBanner: false, // 是否显示公告banner
|
|
19
|
+
bannerText: '', // 公告banner文本
|
|
20
|
+
isStatic: false, // 公告banner内容是否静止不滚动(display_type==1)
|
|
21
|
+
curNoticeId: '', // 当前展示的公告 id
|
|
22
|
+
badge: 0, // 公告未读角标数字(收到推送 +1,打开弹窗清零)
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
observers: {
|
|
26
|
+
sdkInstance: function sdkInstance(_sdkInstance) {
|
|
27
|
+
if (!_sdkInstance) return;
|
|
28
|
+
this.sdkInstance = _sdkInstance;
|
|
29
|
+
|
|
30
|
+
this.unsub = this.sdkInstance.store.get({
|
|
31
|
+
announcement: (val) => {
|
|
32
|
+
// 初始化 / 配置刷新时,按公告数据统一处理展示逻辑
|
|
33
|
+
const watchInitData = this.sdkInstance.store.get('watchInitData');
|
|
34
|
+
const webinarType = watchInitData?.webinar?.type;
|
|
35
|
+
// 不是直播也不是回放,不处理
|
|
36
|
+
if (webinarType != 1 && webinarType != 5) return;
|
|
37
|
+
|
|
38
|
+
this.applyAnnouncement(val);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
this.initEventListener();
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
lifetimes: {
|
|
47
|
+
detached() {
|
|
48
|
+
this.unsub && this.unsub();
|
|
49
|
+
this.unlistener?.();
|
|
50
|
+
this.clearTimer();
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
methods: {
|
|
55
|
+
initEventListener() {
|
|
56
|
+
this.unlistener?.();
|
|
57
|
+
const EVENT = this.sdkInstance.EVENT;
|
|
58
|
+
const obj = {};
|
|
59
|
+
// 推送公告:把消息字段转成与接口列表一致的格式,插入到列表首位(去重同 id),保留已有公告
|
|
60
|
+
obj[EVENT.ROOM_ANNOUNCEMENT] = (msg) => {
|
|
61
|
+
const data = msg?.data || msg;
|
|
62
|
+
if (!data) return;
|
|
63
|
+
// display_type: 0
|
|
64
|
+
// duration: 600
|
|
65
|
+
// event_type: "room_announcement"
|
|
66
|
+
// id: "364"
|
|
67
|
+
// push_time: "2026-08-10 16:39:55"
|
|
68
|
+
// record_display: 1
|
|
69
|
+
// room_announcement_text: "zxcfzxcxzc"
|
|
70
|
+
// room_id: "lss_1d63a879"
|
|
71
|
+
// room_join_id: "101643"
|
|
72
|
+
// set_type: 1
|
|
73
|
+
// type: "room_announcement"
|
|
74
|
+
|
|
75
|
+
const item = {
|
|
76
|
+
id: data.id,
|
|
77
|
+
content: data.room_announcement_text ? { content: data.room_announcement_text } : data.content || '',
|
|
78
|
+
duration: data.duration,
|
|
79
|
+
display_type: data.display_type,
|
|
80
|
+
create_at: data.push_time,
|
|
81
|
+
record_display: data.record_display,
|
|
82
|
+
set_type: data.set_type
|
|
83
|
+
};
|
|
84
|
+
const prev = this.sdkInstance.store.get('announcement') || {};
|
|
85
|
+
const list = (prev.list || []).filter((it) => it.id !== item.id);
|
|
86
|
+
list.unshift(item);
|
|
87
|
+
|
|
88
|
+
this.sdkInstance.store.set('announcement', { list, total: list.length });
|
|
89
|
+
// 收到推送公告,未读角标 +1
|
|
90
|
+
this.setData({ badge: this.data.badge + 1 });
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// 公告删除:从列表中移除该公告,store 变化会自动触发 applyAnnouncement 重新渲染并关闭 banner
|
|
94
|
+
obj[EVENT.DEL_ROOM_ANNOUNCEMENT] = (msg) => {
|
|
95
|
+
const delId = msg?.data?.id ?? msg?.id;
|
|
96
|
+
if (!delId) return;
|
|
97
|
+
const prev = this.sdkInstance.store.get('announcement') || {};
|
|
98
|
+
const list = (prev.list || []).filter((it) => it.id !== delId);
|
|
99
|
+
this.sdkInstance.store.set('announcement', { list, total: list.length });
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// 直播结束:自动关闭公告
|
|
103
|
+
obj[EVENT.LIVE_END] = () => {
|
|
104
|
+
this.closeAnnouncement();
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
this.unlistener = this.sdkInstance.on(obj);
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 根据公告数据统一处理展示逻辑(store / common-config 回调)
|
|
112
|
+
* - 列表为空:关闭 banner
|
|
113
|
+
* - 否则取第一条公告 item 交给统一调度
|
|
114
|
+
*/
|
|
115
|
+
applyAnnouncement(announ) {
|
|
116
|
+
this.setData({ announInfo: announ });
|
|
117
|
+
|
|
118
|
+
const list = announ?.list || [];
|
|
119
|
+
const total = announ?.total || 0;
|
|
120
|
+
|
|
121
|
+
if (total < 1) {
|
|
122
|
+
this.clearTimer();
|
|
123
|
+
this.setData({
|
|
124
|
+
showIcon: false,
|
|
125
|
+
showBanner: false,
|
|
126
|
+
isStatic: false,
|
|
127
|
+
curNoticeId: '',
|
|
128
|
+
bannerText: '',
|
|
129
|
+
});
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 取第一条公告 item 交给统一调度
|
|
134
|
+
this.scheduleBanner(list[0] || {});
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 统一调度 banner 展示与定时关闭
|
|
139
|
+
* - content: {content: "sdfdsfsdfsdfdsfdsfdsf"}
|
|
140
|
+
* - created_at: "2026-08-10 16:22:52" // 公告创建四时间
|
|
141
|
+
* - display_type:0 // 0 滚动, 1:不滚动
|
|
142
|
+
* - duration: 300 剩余时长,0:永久展示 ; >0 按剩余时长展示,超时自动关闭
|
|
143
|
+
* - id: "363" //公告id
|
|
144
|
+
* - set_type: 1
|
|
145
|
+
*/
|
|
146
|
+
scheduleBanner(item = {}) {
|
|
147
|
+
const id = item.id;
|
|
148
|
+
const duration = Number(item.duration) || 0;
|
|
149
|
+
const displayType = Number(item.display_type);
|
|
150
|
+
const createAt = item.created_at;
|
|
151
|
+
const text = typeof item.content === 'string' ? item.content : item.content?.content || item.content?.text || '';
|
|
152
|
+
|
|
153
|
+
this.clearTimer();
|
|
154
|
+
|
|
155
|
+
this.setData({
|
|
156
|
+
showIcon: true,
|
|
157
|
+
isStatic: displayType === 1,
|
|
158
|
+
curNoticeId: id,
|
|
159
|
+
bannerText: text,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// duration < 1:永久展示
|
|
163
|
+
if (duration < 1) {
|
|
164
|
+
this.setData({ showBanner: true });
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 计算剩余展示时长
|
|
169
|
+
const now = Date.now();
|
|
170
|
+
const createTs = this.parseTime(createAt);
|
|
171
|
+
// pushTime 解析失败则视为从当前时刻开始计时,避免 NaN 导致不展示
|
|
172
|
+
const remain = isNaN(createTs) ? duration * 1000 : duration * 1000 - (now - createTs);
|
|
173
|
+
|
|
174
|
+
if (remain > 0) {
|
|
175
|
+
this.setData({ showBanner: true });
|
|
176
|
+
this.announTimer = setTimeout(() => {
|
|
177
|
+
this.setData({ showBanner: false });
|
|
178
|
+
this.announTimer = null;
|
|
179
|
+
}, remain);
|
|
180
|
+
} else {
|
|
181
|
+
this.setData({ showBanner: false });
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
// 解析时间字符串为时间戳(兼容 iOS:将 "2026-08-07 16:47:13" 转为 "2026/08/07 16:47:13")
|
|
186
|
+
parseTime(str) {
|
|
187
|
+
if (!str) return NaN;
|
|
188
|
+
const s = String(str).replace(/-/g, '/');
|
|
189
|
+
const t = new Date(s).getTime();
|
|
190
|
+
return isNaN(t) ? NaN : t;
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
// 清除展示定时器
|
|
194
|
+
clearTimer() {
|
|
195
|
+
if (this.announTimer) {
|
|
196
|
+
clearTimeout(this.announTimer);
|
|
197
|
+
this.announTimer = null;
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
// 被动关闭(删除/直播结束):关闭当前 banner
|
|
202
|
+
closeAnnouncement() {
|
|
203
|
+
this.clearTimer();
|
|
204
|
+
this.setData({ showBanner: false });
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
// 用户手动关闭当前 banner
|
|
208
|
+
handleBannerClose() {
|
|
209
|
+
this.clearTimer();
|
|
210
|
+
this.setData({ showBanner: false });
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
// 点击公告图标:打开弹窗并清零未读角标
|
|
214
|
+
handleIconClick() {
|
|
215
|
+
this.setData({ showPopup: true, badge: 0 });
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
// 关闭公告弹窗
|
|
219
|
+
handlePopupClose() {
|
|
220
|
+
this.setData({ showPopup: false });
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<!-- 公告顶部滚动条 -->
|
|
2
|
+
<announ-banner show="{{showBanner}}" text="{{bannerText}}" static="{{isStatic}}" mode="{{mode}}" bind:close="handleBannerClose" />
|
|
3
|
+
<!-- 公告浮动小图标 -->
|
|
4
|
+
<announ-icon wx:if="{{showIcon}}" showIcon="{{showIcon}}" badge="{{badge}}" mode="{{mode}}" bind:onTapIcon="handleIconClick" />
|
|
5
|
+
<!-- 公告弹窗 -->
|
|
6
|
+
<announ-popup show="{{showPopup}}" info="{{announInfo}}" bind:close="handlePopupClose" />
|
|
File without changes
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { reloadCurrentPage } from '../../shared/mpUtils.js';
|
|
2
|
+
|
|
1
3
|
Component({
|
|
2
4
|
properties: {
|
|
3
5
|
sdkInstance: {
|
|
@@ -9,6 +11,7 @@ Component({
|
|
|
9
11
|
tabList: [],
|
|
10
12
|
activeTab: 0,
|
|
11
13
|
liveInfo: null,
|
|
14
|
+
isReady: false, // SDK 是否已初始化完成
|
|
12
15
|
showStartDialog: false, // 是否显示开始直播弹窗
|
|
13
16
|
|
|
14
17
|
showRecordWatchExpireDialog: false, // 是否显示回放视频已过观看有效期提示框
|
|
@@ -31,6 +34,9 @@ Component({
|
|
|
31
34
|
liveInfo: val,
|
|
32
35
|
});
|
|
33
36
|
},
|
|
37
|
+
isReady: (val) => {
|
|
38
|
+
this.setData({ isReady: !!val });
|
|
39
|
+
},
|
|
34
40
|
webinarStatus: (val) => {
|
|
35
41
|
this.setData({
|
|
36
42
|
webinarStatus: val,
|
|
@@ -124,7 +130,7 @@ Component({
|
|
|
124
130
|
this.setData({
|
|
125
131
|
showStartDialog: false,
|
|
126
132
|
});
|
|
127
|
-
|
|
133
|
+
reloadCurrentPage();
|
|
128
134
|
},
|
|
129
135
|
handleExprie() {
|
|
130
136
|
this.sdkInstance._handleBizErrorCode(512912)
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"vhall-product-order": "../product/product-order/product-order",
|
|
14
14
|
"vhall-lottery": "../lottery/lottery",
|
|
15
15
|
"vhall-mall-reward":"../mall-reward/index",
|
|
16
|
+
"vhall-announcement":"../announcement/index",
|
|
16
17
|
"start-countdown": "../../pubComponents/countdown/countdown",
|
|
17
18
|
"signin-dialog": "../signin/signin-dialog",
|
|
18
19
|
"my-invite-detail": "../invite-rank/my-invite-detail",
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
"vhall-gift-sender": "view",
|
|
32
33
|
"vhall-lottery": "view",
|
|
33
34
|
"vhall-mall-reward":"view",
|
|
35
|
+
"vhall-announcement":"view",
|
|
34
36
|
"vhall-invite-rank": "view"
|
|
35
37
|
},
|
|
36
38
|
"permissiion": {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
<
|
|
1
|
+
<error-page wx:if="{{errorResp && errorResp.code}}" errorResp="{{errorResp}}"></error-page>
|
|
2
|
+
<view class="live_landscape" wx:elif="{{isReady}}">
|
|
2
3
|
<view class="live_landscape_player">
|
|
3
4
|
<vhall-player sdkInstance="{{sdkInstance}}"></vhall-player>
|
|
4
5
|
</view>
|
|
@@ -66,8 +67,10 @@
|
|
|
66
67
|
<vh-popup visible="{{showOrder}}" mode="bottom" maskClosable="true" bind:close="closeOrder">
|
|
67
68
|
<vhall-product-order show="{{showOrder}}" product="{{selectedProduct}}" sdkInstance="{{sdkInstance}}" bind:close="closeOrder" bind:paySuccess="onPaySuccess" />
|
|
68
69
|
</vh-popup>
|
|
69
|
-
|
|
70
|
+
<!-- 抽奖组件 -->
|
|
71
|
+
<vhall-lottery wx:if="{{webinarStatus==1}}" sdkInstance="{{sdkInstance}}" />
|
|
70
72
|
<!-- 商城奖励 -->
|
|
71
|
-
<vhall-mall-reward sdkInstance="{{sdkInstance}}" />
|
|
73
|
+
<vhall-mall-reward wx:if="{{webinarStatus==1||webinarStatus==5}}" sdkInstance="{{sdkInstance}}" />
|
|
74
|
+
<!-- 公告组件 -->
|
|
75
|
+
<vhall-announcement wx:if="{{webinarStatus==1||webinarStatus==5}}" sdkInstance="{{sdkInstance}}" mode="{{1}}" />
|
|
72
76
|
</view>
|
|
73
|
-
<error-page wx:else errorResp="{{errorResp}}"></error-page>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { reloadCurrentPage } from '../../shared/mpUtils.js';
|
|
2
|
+
|
|
1
3
|
Component({
|
|
2
4
|
properties: {
|
|
3
5
|
sdkInstance: {
|
|
@@ -9,6 +11,7 @@ Component({
|
|
|
9
11
|
tabList: [],
|
|
10
12
|
activeTab: 0,
|
|
11
13
|
liveInfo: null,
|
|
14
|
+
isReady: false, // SDK 是否已初始化完成
|
|
12
15
|
showStartDialog: false, // 是否显示开始直播弹窗
|
|
13
16
|
|
|
14
17
|
showRecordWatchExpireDialog: false, // 是否显示回放视频已过观看有效期提示框
|
|
@@ -42,6 +45,9 @@ Component({
|
|
|
42
45
|
liveInfo: val,
|
|
43
46
|
});
|
|
44
47
|
},
|
|
48
|
+
isReady: (val) => {
|
|
49
|
+
this.setData({ isReady: !!val });
|
|
50
|
+
},
|
|
45
51
|
webinarStatus: (val) => {
|
|
46
52
|
this.setData({
|
|
47
53
|
webinarStatus: val,
|
|
@@ -148,7 +154,8 @@ Component({
|
|
|
148
154
|
this.setData({
|
|
149
155
|
showStartDialog: false,
|
|
150
156
|
});
|
|
151
|
-
|
|
157
|
+
reloadCurrentPage();
|
|
158
|
+
|
|
152
159
|
},
|
|
153
160
|
handleExprie() {
|
|
154
161
|
this.sdkInstance._handleBizErrorCode(512912)
|
|
@@ -279,4 +286,5 @@ Component({
|
|
|
279
286
|
// 支付成功后的处理
|
|
280
287
|
},
|
|
281
288
|
},
|
|
282
|
-
});
|
|
289
|
+
});
|
|
290
|
+
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"vhall-product-order": "../product/product-order/product-order",
|
|
14
14
|
"vhall-lottery": "../lottery/lottery",
|
|
15
15
|
"vhall-mall-reward": "../mall-reward/index",
|
|
16
|
+
"vhall-announcement": "../announcement/index",
|
|
16
17
|
"product-detail": "../product/product-detail/product-detail",
|
|
17
18
|
"start-countdown": "../../pubComponents/countdown/countdown",
|
|
18
19
|
"signin-dialog": "../signin/signin-dialog",
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
"signin-dialog": "view",
|
|
34
35
|
"vhall-gift-sender": "view",
|
|
35
36
|
"vhall-lottery": "view",
|
|
36
|
-
"vhall-invite-rank": "view"
|
|
37
|
+
"vhall-invite-rank": "view",
|
|
38
|
+
"vhall-announcement": "view"
|
|
37
39
|
}
|
|
38
40
|
}
|