feat: 优化UI
This commit is contained in:
+115
-15
@@ -13,6 +13,7 @@ Page({
|
||||
activeContent: null,
|
||||
isPlaying: false,
|
||||
isVip: false,
|
||||
isLiked: false,
|
||||
currentTime: 0,
|
||||
duration: 0,
|
||||
currentTimeText: '00:00',
|
||||
@@ -20,16 +21,13 @@ Page({
|
||||
displayDate: '',
|
||||
playbackRate: 1.0,
|
||||
statusBarHeight: 0,
|
||||
showTranscript: false, // 封面 ⇔ 文案切换
|
||||
showSpeedSheet: false,
|
||||
speedItems: [
|
||||
{ label: '0.5x' },
|
||||
{ label: '0.75x' },
|
||||
{ label: '1.0x' },
|
||||
{ label: '1.25x' },
|
||||
{ label: '1.5x' },
|
||||
{ label: '2.0x' }
|
||||
]
|
||||
showTranscript: false,
|
||||
// 评论弹层
|
||||
showComments: false,
|
||||
commentList: [],
|
||||
commentText: '',
|
||||
commentLoading: false,
|
||||
submitting: false
|
||||
},
|
||||
|
||||
_isSeeking: false,
|
||||
@@ -65,6 +63,9 @@ Page({
|
||||
|
||||
app.on('playerStateChange', this._onPlayerChange)
|
||||
app.on('timeUpdate', this._onTimeUpdate)
|
||||
|
||||
// 查询当前节目点赞状态
|
||||
this._loadLikeStatus()
|
||||
},
|
||||
|
||||
onHide() {
|
||||
@@ -108,7 +109,7 @@ Page({
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取频道信息 — 从后端 API 获取
|
||||
* 获取频道信息
|
||||
*/
|
||||
_updateDomain() {
|
||||
const content = this.data.activeContent
|
||||
@@ -116,14 +117,12 @@ Page({
|
||||
|
||||
var channelId = content.channelId || (content.channel && content.channel.id)
|
||||
if (!channelId) {
|
||||
// 如果节目数据中直接包含 channel 信息
|
||||
if (content.channel) {
|
||||
this.setData({ domain: content.channel })
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 如果已经加载过且 channelId 没变,跳过
|
||||
if (this.data.domain && this.data.domain.id === channelId) return
|
||||
|
||||
var self = this
|
||||
@@ -136,6 +135,20 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 查询当前节目点赞状态
|
||||
*/
|
||||
_loadLikeStatus() {
|
||||
const content = this.data.activeContent
|
||||
if (!content) return
|
||||
var self = this
|
||||
api.getProgramDetail(content.id).then(function (res) {
|
||||
if (res.code === 200 && res.data) {
|
||||
self.setData({ isLiked: !!res.data.isLiked })
|
||||
}
|
||||
}).catch(function () { })
|
||||
},
|
||||
|
||||
/**
|
||||
* 播放/暂停
|
||||
*/
|
||||
@@ -251,13 +264,100 @@ Page({
|
||||
onLike() {
|
||||
const content = this.data.activeContent
|
||||
if (!content) return
|
||||
api.toggleLike({ contentId: content.id }).then(function (res) {
|
||||
wx.showToast({ title: res.code === 200 ? '已收藏 ♥' : '操作失败', icon: 'none' })
|
||||
const self = this
|
||||
const wasLiked = this.data.isLiked
|
||||
// 乐观更新
|
||||
this.setData({ isLiked: !wasLiked })
|
||||
api.toggleLike(content.id).then(function (res) {
|
||||
if (res.code !== 200) {
|
||||
// 回滚
|
||||
self.setData({ isLiked: wasLiked })
|
||||
wx.showToast({ title: res.msg || '操作失败', icon: 'none' })
|
||||
} else {
|
||||
wx.showToast({ title: wasLiked ? '已取消喜欢' : '已喜欢 ♥', icon: 'none' })
|
||||
}
|
||||
}).catch(function () {
|
||||
self.setData({ isLiked: wasLiked })
|
||||
wx.showToast({ title: '网络异常', icon: 'none' })
|
||||
})
|
||||
},
|
||||
|
||||
// ===== 评论弹层 =====
|
||||
|
||||
onOpenComments() {
|
||||
this.setData({ showComments: true })
|
||||
this._loadComments()
|
||||
},
|
||||
|
||||
onCloseComments() {
|
||||
this.setData({ showComments: false, commentText: '' })
|
||||
},
|
||||
|
||||
_loadComments() {
|
||||
const content = this.data.activeContent
|
||||
if (!content) return
|
||||
const self = this
|
||||
this.setData({ commentLoading: true })
|
||||
api.getCommentList(content.id, { current: 1, pageSize: 30 }).then(function (res) {
|
||||
if (res.code === 200 && res.data) {
|
||||
var list = (res.data.list || res.data || []).map(function (c) {
|
||||
return Object.assign({}, c, {
|
||||
_isOwn: c.userId === (getApp().globalData.userInfo && getApp().globalData.userInfo.id)
|
||||
})
|
||||
})
|
||||
self.setData({ commentList: list, commentLoading: false })
|
||||
} else {
|
||||
self.setData({ commentLoading: false })
|
||||
}
|
||||
}).catch(function () {
|
||||
self.setData({ commentLoading: false })
|
||||
})
|
||||
},
|
||||
|
||||
onCommentInput(e) {
|
||||
this.setData({ commentText: e.detail.value })
|
||||
},
|
||||
|
||||
onSubmitComment() {
|
||||
const text = (this.data.commentText || '').trim()
|
||||
if (!text) return
|
||||
const content = this.data.activeContent
|
||||
if (!content) return
|
||||
const self = this
|
||||
this.setData({ submitting: true })
|
||||
api.addComment(content.id, text).then(function (res) {
|
||||
self.setData({ submitting: false, commentText: '' })
|
||||
if (res.code === 200) {
|
||||
wx.showToast({ title: '发布成功', icon: 'none' })
|
||||
self._loadComments()
|
||||
} else {
|
||||
wx.showToast({ title: res.msg || '发布失败', icon: 'none' })
|
||||
}
|
||||
}).catch(function () {
|
||||
self.setData({ submitting: false })
|
||||
wx.showToast({ title: '网络异常', icon: 'none' })
|
||||
})
|
||||
},
|
||||
|
||||
onDeleteComment(e) {
|
||||
const id = e.currentTarget.dataset.id
|
||||
const self = this
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '确认删除该评论吗?',
|
||||
success(res) {
|
||||
if (!res.confirm) return
|
||||
api.deleteComment(id).then(function (r) {
|
||||
if (r.code === 200) {
|
||||
self._loadComments()
|
||||
} else {
|
||||
wx.showToast({ title: '删除失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onShare() {
|
||||
wx.showToast({ title: '分享功能开发中', icon: 'none' })
|
||||
},
|
||||
|
||||
+65
-14
@@ -2,7 +2,7 @@
|
||||
<page-meta page-style="overflow:hidden; background:#1A1208;" />
|
||||
<view class="player-page">
|
||||
|
||||
<!-- 状态栏占位(custom 导航模式必须手动留出状态栏高度) -->
|
||||
<!-- 状态栏占位 -->
|
||||
<view style="height: {{statusBarHeight}}px; flex-shrink: 0;"></view>
|
||||
|
||||
<!-- 环境光背景 -->
|
||||
@@ -10,7 +10,7 @@
|
||||
style="background: radial-gradient(ellipse at 50% -10%, {{domain.bgColor || '#FF9D42'}}44 0%, transparent 65%);">
|
||||
</view>
|
||||
|
||||
<!-- 顶部:返回 + 标题 + 分享 -->
|
||||
<!-- 顶部:返回 + 标题 + 评论 -->
|
||||
<view class="top-bar">
|
||||
<view class="top-btn tap-active" bindtap="goBack">
|
||||
<text class="top-back">‹</text>
|
||||
@@ -19,8 +19,8 @@
|
||||
<text class="top-label">正在播放</text>
|
||||
<text class="top-title">{{activeContent.title || '加载中...'}}</text>
|
||||
</view>
|
||||
<view class="top-btn tap-active" bindtap="onShare">
|
||||
<text class="top-share">↑</text>
|
||||
<view class="top-btn tap-active" bindtap="onOpenComments">
|
||||
<text class="top-comment-icon">💬</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<view class="ripple-ring" style="animation-delay: 1.4s;"></view>
|
||||
</view>
|
||||
|
||||
<!-- 大 emoji,无卡片背景 -->
|
||||
<!-- 大 emoji -->
|
||||
<text class="cover-emoji {{isPlaying ? 'emoji-active' : ''}}">📻</text>
|
||||
|
||||
<!-- 频道名 -->
|
||||
@@ -58,11 +58,11 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 日期 + like 同行,进度条上方 -->
|
||||
<!-- 日期 + like 同行 -->
|
||||
<view class="date-like-row">
|
||||
<text class="date-text">{{displayDate}}</text>
|
||||
<view class="like-btn-inline tap-active" bindtap="onLike">
|
||||
<text class="like-icon">♡</text>
|
||||
<text class="like-icon {{isLiked ? 'liked' : ''}}">{{isLiked ? '♥' : '♡'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -107,11 +107,62 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 倍速选择面板 -->
|
||||
<t-action-sheet
|
||||
visible="{{showSpeedSheet}}"
|
||||
items="{{speedItems}}"
|
||||
bind:selected="onSpeedSelect"
|
||||
bind:cancel="onSpeedCancel"
|
||||
/>
|
||||
<!-- 评论弹层 -->
|
||||
<view class="comment-mask" wx:if="{{showComments}}" bindtap="onCloseComments"></view>
|
||||
<view class="comment-sheet {{showComments ? 'sheet-up' : ''}}">
|
||||
<view class="sheet-handle"></view>
|
||||
<view class="sheet-header">
|
||||
<text class="sheet-title">评论 ({{commentList.length}})</text>
|
||||
<view class="sheet-close tap-active" bindtap="onCloseComments">
|
||||
<text class="sheet-close-icon">✕</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 输入区 -->
|
||||
<view class="comment-input-row">
|
||||
<input
|
||||
class="comment-input"
|
||||
placeholder="说点什么..."
|
||||
placeholder-style="color:rgba(255,200,120,0.3);"
|
||||
value="{{commentText}}"
|
||||
bindinput="onCommentInput"
|
||||
confirm-type="send"
|
||||
bindconfirm="onSubmitComment"
|
||||
maxlength="200"
|
||||
/>
|
||||
<view class="send-btn tap-active {{submitting ? 'sending' : ''}}" bindtap="onSubmitComment">
|
||||
<text class="send-text">发送</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 评论列表 -->
|
||||
<scroll-view scroll-y class="comment-list-scroll" enhanced show-scrollbar="{{false}}">
|
||||
<view wx:if="{{commentLoading}}" class="comment-loading">
|
||||
<text class="comment-loading-text">加载中...</text>
|
||||
</view>
|
||||
<view wx:elif="{{commentList.length === 0}}" class="comment-empty">
|
||||
<text class="comment-empty-icon">💬</text>
|
||||
<text class="comment-empty-text">还没有评论,来说第一句话</text>
|
||||
</view>
|
||||
<view
|
||||
wx:for="{{commentList}}"
|
||||
wx:key="id"
|
||||
class="comment-item"
|
||||
>
|
||||
<view class="comment-avatar">
|
||||
<text class="comment-avatar-text">{{item.userName ? item.userName[0] : '?'}}</text>
|
||||
</view>
|
||||
<view class="comment-body">
|
||||
<text class="comment-author">{{item.userName || '匿名'}}</text>
|
||||
<text class="comment-text">{{item.content}}</text>
|
||||
<text class="comment-time">{{item.createdAtStr || item.createdAt}}</text>
|
||||
</view>
|
||||
<view wx:if="{{item._isOwn}}" class="comment-del tap-active" bindtap="onDeleteComment" data-id="{{item.id}}">
|
||||
<text class="comment-del-icon">🗑</text>
|
||||
</view>
|
||||
</view>
|
||||
<view style="height: 40rpx;"></view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
@@ -320,3 +320,150 @@
|
||||
background: #FFF8EE;
|
||||
border-radius: 5rpx;
|
||||
}
|
||||
|
||||
/* ── like 状态 ── */
|
||||
.like-icon.liked {
|
||||
color: #FF4D6D;
|
||||
}
|
||||
.top-comment-icon {
|
||||
font-size: 38rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/* ── 评论弹层 ── */
|
||||
.comment-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 200;
|
||||
}
|
||||
.comment-sheet {
|
||||
position: fixed;
|
||||
bottom: -100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 70vh;
|
||||
background: #231808;
|
||||
border-radius: 40rpx 40rpx 0 0;
|
||||
z-index: 201;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 0 env(safe-area-inset-bottom);
|
||||
transition: bottom 0.3s cubic-bezier(0.32,0.72,0,1);
|
||||
}
|
||||
.comment-sheet.sheet-up {
|
||||
bottom: 0;
|
||||
}
|
||||
.sheet-handle {
|
||||
width: 72rpx;
|
||||
height: 6rpx;
|
||||
background: rgba(255,200,120,0.2);
|
||||
border-radius: 3rpx;
|
||||
margin: 20rpx auto 0;
|
||||
}
|
||||
.sheet-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 40rpx;
|
||||
border-bottom: 1rpx solid rgba(255,200,120,0.08);
|
||||
}
|
||||
.sheet-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: rgba(255,240,210,0.9);
|
||||
}
|
||||
.sheet-close-icon {
|
||||
font-size: 32rpx;
|
||||
color: rgba(255,200,120,0.4);
|
||||
}
|
||||
.comment-input-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
padding: 20rpx 32rpx;
|
||||
border-bottom: 1rpx solid rgba(255,200,120,0.08);
|
||||
}
|
||||
.comment-input {
|
||||
flex: 1;
|
||||
background: rgba(255,200,120,0.07);
|
||||
border-radius: 40rpx;
|
||||
padding: 16rpx 28rpx;
|
||||
font-size: 28rpx;
|
||||
color: rgba(255,240,210,0.9);
|
||||
min-height: 0;
|
||||
}
|
||||
.send-btn {
|
||||
background: #FF9D42;
|
||||
border-radius: 32rpx;
|
||||
padding: 14rpx 28rpx;
|
||||
}
|
||||
.send-btn.sending { opacity: 0.5; }
|
||||
.send-text {
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
color: #FFF;
|
||||
}
|
||||
.comment-list-scroll {
|
||||
flex: 1;
|
||||
padding: 8rpx 0;
|
||||
}
|
||||
.comment-loading, .comment-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80rpx 0;
|
||||
gap: 16rpx;
|
||||
}
|
||||
.comment-loading-text, .comment-empty-text {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255,200,120,0.3);
|
||||
}
|
||||
.comment-empty-icon { font-size: 60rpx; }
|
||||
.comment-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 20rpx;
|
||||
padding: 24rpx 32rpx;
|
||||
border-bottom: 1rpx solid rgba(255,200,120,0.05);
|
||||
}
|
||||
.comment-avatar {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255,157,66,0.25);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.comment-avatar-text {
|
||||
font-size: 28rpx;
|
||||
color: #FF9D42;
|
||||
font-weight: 700;
|
||||
}
|
||||
.comment-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
}
|
||||
.comment-author {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
color: rgba(255,200,120,0.6);
|
||||
}
|
||||
.comment-text {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255,240,210,0.85);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.comment-time {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255,200,120,0.3);
|
||||
}
|
||||
.comment-del {
|
||||
padding: 8rpx;
|
||||
}
|
||||
.comment-del-icon { font-size: 32rpx; }
|
||||
|
||||
Reference in New Issue
Block a user