1374 lines
32 KiB
Vue
1374 lines
32 KiB
Vue
<template>
|
||
<view class="video-container" @touchstart="onTouchStart" @touchend="onTouchEnd">
|
||
<video
|
||
id="video-element"
|
||
class="video-player"
|
||
:src="videoUrl"
|
||
:autoplay="autoplay"
|
||
:muted="muted"
|
||
:controls="false"
|
||
loop
|
||
object-fit="cover"
|
||
@play="onVideoPlay"
|
||
@pause="onVideoPause"
|
||
@ended="onVideoEnd"
|
||
@timeupdate="onTimeUpdate"
|
||
@loadedmetadata="onVideoReady"
|
||
@click="onVideoTap"
|
||
></video>
|
||
|
||
<!-- 顶部控制栏 -->
|
||
<view class="top-controls" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||
<view class="left-controls">
|
||
<view class="back-btn" @click="onBack">
|
||
<text class="icon-back">‹</text>
|
||
</view>
|
||
<text class="time-display">{{ currentTime }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 视频内容区域 -->
|
||
<view class="video-content" @click="onPlayPause">
|
||
<view :class="['play-indicator', isPlaying ? 'hide' : 'show']">
|
||
<text class="play-icon">▶</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部信息区域 -->
|
||
<view class="bottom-info">
|
||
<!-- 文章加载状态 -->
|
||
<view class="article-status" v-if="isLoadingArticle || articleError">
|
||
<view class="loading-indicator" v-if="isLoadingArticle">
|
||
<text class="loading-text">正在加载文章详情...</text>
|
||
</view>
|
||
<view class="error-message" v-if="articleError">
|
||
<text class="error-text">{{ articleError }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 创作者信息 -->
|
||
<view class="creator-info">
|
||
<image class="creator-avatar" :src="creatorAvatar" @click="onCreatorTap" />
|
||
<view class="creator-details">
|
||
<text class="creator-name">{{ creatorName }}</text>
|
||
<view :class="['follow-btn', isFollowing ? 'following' : '']" @click="onFollow">
|
||
{{ isFollowing ? '已关注' : '关注' }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 视频描述 -->
|
||
<view class="video-info" v-if="videoDescription">
|
||
<view :class="['video-description', isDescriptionExpanded ? 'expanded' : '']" @click="onToggleDescription">
|
||
{{ videoDescription }}
|
||
</view>
|
||
<view class="expand-toggle" @click="onToggleDescription" v-if="videoDescription.length > 50">
|
||
<text class="iconfont" :class="isDescriptionExpanded ? 'icon-xiangshang' : 'icon-xiangxia'"></text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 互动区域 -->
|
||
<view class="interaction-area">
|
||
<view class="like-section">
|
||
<view :class="['like-btn', isLiked ? 'liked' : '']" @click="onLike">
|
||
<text class="heart-icon">{{ isLiked ? '❤️' : '🤍' }}</text>
|
||
</view>
|
||
<text class="like-count">{{ likeCount }}</text>
|
||
</view>
|
||
<view class="action-buttons">
|
||
<view class="consult-btn" @click="onConsult">立即咨询</view>
|
||
<view class="action-btn" @click="onCreateSimilar">做同款</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- AI生成内容标识 -->
|
||
<view class="ai-notice">
|
||
<text class="ai-notice-text">内容由AI生成</text>
|
||
</view>
|
||
|
||
<!-- 进度条 -->
|
||
<view class="progress-bar">
|
||
<view class="progress-track">
|
||
<view class="progress-fill" :style="{ width: progress + '%' }"></view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 悬浮操作按钮 -->
|
||
<view class="floating-actions">
|
||
<view class="floating-btn download-btn" @click="onDownload">
|
||
<text class="floating-label">下载</text>
|
||
</view>
|
||
<view class="floating-btn share-btn" @click="onShare">
|
||
<text class="floating-label">分享</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import api from '@/api/models-api.js';
|
||
import { mapGetters } from 'vuex';
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
videoUrl: 'https://jxz.uj345.cc/videos/video1.mp4',
|
||
currentTime: '00:25',
|
||
progress: 45,
|
||
isPlaying: false,
|
||
autoplay: false,
|
||
muted: false,
|
||
creatorName: '开心海浪',
|
||
creatorAvatar: '/static/images/creator-avatar.png',
|
||
isFollowing: false,
|
||
videoDescription: '女孩自然的姿势贴地快速飞行,飞向湖面,镜头跟随其后,女孩自然的姿势贴地快速飞行,飞向湖面,镜头跟随其后,女孩自然的姿势贴地快速飞行,飞向湖面,镜头跟随其后',
|
||
isDescriptionExpanded: false,
|
||
isLiked: false,
|
||
likeCount: 2778,
|
||
videoContext: null,
|
||
isVideoReady: false,
|
||
playPromise: null,
|
||
articleData: null,
|
||
isLoadingArticle: false,
|
||
articleError: null,
|
||
currentArticleId: null,
|
||
touchStartY: 0,
|
||
touchEndY: 0,
|
||
isSwipeEnabled: true,
|
||
statusBarHeight: 0,
|
||
};
|
||
},
|
||
computed: mapGetters(['chatUrl']),
|
||
onLoad(options) {
|
||
const articleId = options.id;
|
||
this.setData({
|
||
currentArticleId: articleId,
|
||
});
|
||
const sys = uni.getSystemInfoSync();
|
||
const sbh = sys.statusBarHeight;
|
||
this.statusBarHeight = (sbh && sbh > 0) ? sbh : (sys.platform === 'ios' ? 44 : 24);
|
||
if (articleId) {
|
||
console.log('开始加载文章详情,ID:', articleId);
|
||
this.loadArticleDetail(articleId);
|
||
} else {
|
||
console.log('未提供文章ID,跳过文章详情加载');
|
||
}
|
||
setTimeout(() => {
|
||
this.videoContext = uni.createVideoContext('video-element', this);
|
||
this.setData({
|
||
isVideoReady: true,
|
||
});
|
||
}, 1000);
|
||
},
|
||
onShow() {
|
||
setTimeout(() => {
|
||
if (this.videoContext && this.isVideoReady) {
|
||
this.safePlay();
|
||
}
|
||
}, 300);
|
||
},
|
||
onHide() {
|
||
if (this.videoContext && this.isVideoReady) {
|
||
this.safePause();
|
||
}
|
||
},
|
||
methods: {
|
||
sanitizeText(str) {
|
||
if (!str || typeof str !== 'string') return '';
|
||
try {
|
||
// 去除所有 HTML 标签,避免 WXML 解析原始 `<` `>` 造成语法错误
|
||
const noTags = str.replace(/<[^>]*>/g, '');
|
||
// 保险处理:将残留的尖括号转义为实体
|
||
return noTags.replace(/</g, '<').replace(/>/g, '>');
|
||
} catch (e) {
|
||
return String(str);
|
||
}
|
||
},
|
||
// 处理头像URL,添加前缀
|
||
getAvatarUrl(avatarUrl) {
|
||
if (!avatarUrl || avatarUrl === '/static/images/avatar-default.png') {
|
||
return '/static/images/avatar-default.png';
|
||
}
|
||
// 如果已经是完整URL,直接返回
|
||
if (avatarUrl.startsWith('http://') || avatarUrl.startsWith('https://')) {
|
||
return avatarUrl;
|
||
}
|
||
// 如果是相对路径,添加前缀
|
||
const prefix = 'https://uthink2025.oss-cn-shanghai.aliyuncs.com/';
|
||
// 如果URL已经以/开头,去掉开头的/
|
||
const cleanUrl = avatarUrl.startsWith('/') ? avatarUrl.substring(1) : avatarUrl;
|
||
return prefix + cleanUrl;
|
||
},
|
||
loadVideoData() {
|
||
setTimeout(() => {
|
||
this.setData({
|
||
videoUrl: '/videos/sample-video.mp4',
|
||
});
|
||
}, 500);
|
||
},
|
||
loadArticleDetail(articleId) {
|
||
console.log('loadArticleDetail 被调用,参数:', articleId);
|
||
this.setData({
|
||
isLoadingArticle: true,
|
||
articleError: null,
|
||
});
|
||
console.log('设置加载状态为 true');
|
||
api.getArticleById(articleId).then(response => {
|
||
console.log('API响应原始数据:', response);
|
||
const data = response.data || response;
|
||
console.log('文章详情数据:', data);
|
||
const rawDesc = data.prompt || data.content || data.title || data.synopsis || this.videoDescription;
|
||
const safeDesc = this.sanitizeText(rawDesc);
|
||
|
||
// 获取作者头像
|
||
const authorAvatar = this.getAvatarUrl(data.authorAvatar || data.avatar || '');
|
||
|
||
// 获取作者名称
|
||
const authorName = data.authorName || data.author || this.creatorName;
|
||
|
||
// 获取点赞数
|
||
const likeCount = data.likeCount || data.visit || this.likeCount;
|
||
|
||
this.setData({
|
||
articleData: data,
|
||
isLoadingArticle: false,
|
||
videoDescription: safeDesc,
|
||
creatorName: authorName,
|
||
creatorAvatar: authorAvatar,
|
||
videoUrl: data.videoUrl || this.videoUrl,
|
||
likeCount: likeCount,
|
||
});
|
||
console.log('页面数据更新完成,当前 articleData:', this.articleData);
|
||
console.log('当前 isLoadingArticle:', this.isLoadingArticle);
|
||
console.log('作者头像:', authorAvatar);
|
||
}).catch(error => {
|
||
console.error('文章详情获取失败:', error);
|
||
this.setData({
|
||
articleError: error.message || '获取文章详情失败',
|
||
isLoadingArticle: false,
|
||
});
|
||
console.log('错误状态设置完成,articleError:', this.articleError);
|
||
uni.showToast({
|
||
title: '获取文章详情失败',
|
||
icon: 'none',
|
||
duration: 2000,
|
||
});
|
||
});
|
||
},
|
||
onBack() {
|
||
uni.navigateBack();
|
||
},
|
||
// 下载视频
|
||
onDownload() {
|
||
if (!this.videoUrl) {
|
||
uni.showToast({
|
||
title: '视频地址不存在',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
uni.showLoading({
|
||
title: '下载中...',
|
||
mask: true
|
||
});
|
||
|
||
// 下载视频文件
|
||
uni.downloadFile({
|
||
url: this.videoUrl,
|
||
success: (res) => {
|
||
if (res.statusCode === 200) {
|
||
// 保存到相册
|
||
uni.saveVideoToPhotosAlbum({
|
||
filePath: res.tempFilePath,
|
||
success: () => {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '已保存到相册',
|
||
icon: 'success',
|
||
duration: 2000
|
||
});
|
||
},
|
||
fail: (error) => {
|
||
uni.hideLoading();
|
||
console.error('保存到相册失败:', error);
|
||
|
||
// 如果是权限问题,提示用户开启权限
|
||
if (error.errMsg.includes('auth')) {
|
||
uni.showModal({
|
||
title: '需要相册权限',
|
||
content: '请在设置中开启相册权限',
|
||
confirmText: '去设置',
|
||
success: (modalRes) => {
|
||
if (modalRes.confirm) {
|
||
uni.openSetting();
|
||
}
|
||
}
|
||
});
|
||
} else {
|
||
uni.showToast({
|
||
title: '保存失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
}
|
||
});
|
||
} else {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '下载失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
},
|
||
fail: (error) => {
|
||
uni.hideLoading();
|
||
console.error('下载失败:', error);
|
||
uni.showToast({
|
||
title: '下载失败,请重试',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
});
|
||
},
|
||
// 分享视频
|
||
onShare() {
|
||
uni.showActionSheet({
|
||
itemList: ['分享到微信', '分享到朋友圈', '复制链接'],
|
||
success: (res) => {
|
||
if (res.tapIndex === 0) {
|
||
// 分享到微信好友
|
||
this.shareToWechat();
|
||
} else if (res.tapIndex === 1) {
|
||
// 分享到朋友圈
|
||
this.shareToMoments();
|
||
} else if (res.tapIndex === 2) {
|
||
// 复制链接
|
||
this.copyLink();
|
||
}
|
||
}
|
||
});
|
||
},
|
||
// 分享到微信好友
|
||
shareToWechat() {
|
||
// #ifdef MP-WEIXIN
|
||
// 小程序中使用按钮的 open-type="share"
|
||
uni.showToast({
|
||
title: '请使用右上角分享',
|
||
icon: 'none'
|
||
});
|
||
// #endif
|
||
|
||
// #ifdef H5
|
||
uni.showToast({
|
||
title: '请使用浏览器分享功能',
|
||
icon: 'none'
|
||
});
|
||
// #endif
|
||
|
||
// #ifdef APP-PLUS
|
||
// App中可以调用原生分享
|
||
uni.share({
|
||
provider: 'weixin',
|
||
scene: 'WXSceneSession',
|
||
type: 2,
|
||
title: this.videoDescription || '精彩视频分享',
|
||
summary: `来自 ${this.creatorName} 的视频`,
|
||
href: this.videoUrl,
|
||
imageUrl: this.articleData?.imageInput || '',
|
||
success: () => {
|
||
uni.showToast({
|
||
title: '分享成功',
|
||
icon: 'success'
|
||
});
|
||
},
|
||
fail: (err) => {
|
||
console.error('分享失败:', err);
|
||
uni.showToast({
|
||
title: '分享失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
});
|
||
// #endif
|
||
},
|
||
// 分享到朋友圈
|
||
shareToMoments() {
|
||
// #ifdef MP-WEIXIN
|
||
uni.showToast({
|
||
title: '请使用右上角分享到朋友圈',
|
||
icon: 'none'
|
||
});
|
||
// #endif
|
||
|
||
// #ifdef H5
|
||
uni.showToast({
|
||
title: '请使用浏览器分享功能',
|
||
icon: 'none'
|
||
});
|
||
// #endif
|
||
|
||
// #ifdef APP-PLUS
|
||
uni.share({
|
||
provider: 'weixin',
|
||
scene: 'WXSceneTimeline',
|
||
type: 2,
|
||
title: this.videoDescription || '精彩视频分享',
|
||
summary: `来自 ${this.creatorName} 的视频`,
|
||
href: this.videoUrl,
|
||
imageUrl: this.articleData?.imageInput || '',
|
||
success: () => {
|
||
uni.showToast({
|
||
title: '分享成功',
|
||
icon: 'success'
|
||
});
|
||
},
|
||
fail: (err) => {
|
||
console.error('分享失败:', err);
|
||
uni.showToast({
|
||
title: '分享失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
});
|
||
// #endif
|
||
},
|
||
// 复制链接
|
||
copyLink() {
|
||
const shareUrl = this.currentArticleId
|
||
? `https://yourapp.com/pages/ai-generate/video?id=${this.currentArticleId}`
|
||
: 'https://yourapp.com/pages/ai-generate/video';
|
||
|
||
uni.setClipboardData({
|
||
data: shareUrl,
|
||
success: () => {
|
||
uni.showToast({
|
||
title: '链接已复制',
|
||
icon: 'success'
|
||
});
|
||
},
|
||
fail: () => {
|
||
uni.showToast({
|
||
title: '复制失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
});
|
||
},
|
||
onVideoTap(e) {
|
||
if (e && e.stopPropagation) {
|
||
e.stopPropagation();
|
||
}
|
||
this.onPlayPause();
|
||
},
|
||
onVideoLongPress(e) {
|
||
if (e && e.stopPropagation) {
|
||
e.stopPropagation();
|
||
}
|
||
uni.showActionSheet({
|
||
itemList: ['举报', '不感兴趣', '保存到相册'],
|
||
success: res => {
|
||
const actions = ['举报', '不感兴趣', '保存到相册'];
|
||
uni.showToast({
|
||
title: actions[res.tapIndex],
|
||
icon: 'none',
|
||
});
|
||
},
|
||
});
|
||
},
|
||
onPlayPause(e) {
|
||
if (e && e.stopPropagation) {
|
||
e.stopPropagation();
|
||
}
|
||
if (!this.videoContext || !this.isVideoReady) {
|
||
console.warn('视频上下文未准备就绪');
|
||
return;
|
||
}
|
||
if (this.isPlaying) {
|
||
this.safePause();
|
||
} else {
|
||
this.safePlay();
|
||
}
|
||
},
|
||
safePlay() {
|
||
if (!this.videoContext || !this.isVideoReady) {
|
||
return;
|
||
}
|
||
if (this.isPlaying) {
|
||
return;
|
||
}
|
||
try {
|
||
this.videoContext.play();
|
||
} catch (error) {
|
||
console.error('播放失败:', error);
|
||
}
|
||
},
|
||
safePause() {
|
||
if (!this.videoContext || !this.isVideoReady) {
|
||
return;
|
||
}
|
||
if (!this.isPlaying) {
|
||
return;
|
||
}
|
||
try {
|
||
this.videoContext.pause();
|
||
} catch (error) {
|
||
console.error('暂停失败:', error);
|
||
}
|
||
},
|
||
onVideoReady() {
|
||
console.log('视频元数据加载完成');
|
||
this.setData({
|
||
isVideoReady: true,
|
||
});
|
||
},
|
||
onVideoPlay() {
|
||
console.log('视频开始播放');
|
||
this.setData({
|
||
isPlaying: true,
|
||
});
|
||
},
|
||
onVideoPause() {
|
||
console.log('视频暂停');
|
||
this.setData({
|
||
isPlaying: false,
|
||
});
|
||
},
|
||
onTimeUpdate(e) {
|
||
const { currentTime, duration } = e.detail;
|
||
const progress = (currentTime / duration) * 100;
|
||
const minutes = Math.floor(currentTime / 60);
|
||
const seconds = Math.floor(currentTime % 60);
|
||
const timeStr = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
||
this.setData({
|
||
currentTime: timeStr,
|
||
progress: progress,
|
||
});
|
||
},
|
||
onVideoEnd() {
|
||
this.setData({
|
||
isPlaying: false,
|
||
progress: 0,
|
||
});
|
||
},
|
||
onCreatorTap() {
|
||
uni.showToast({
|
||
title: `查看${this.creatorName}的主页`,
|
||
icon: 'none',
|
||
});
|
||
},
|
||
onFollow() {
|
||
const isFollowing = !this.isFollowing;
|
||
this.setData({
|
||
isFollowing: isFollowing,
|
||
});
|
||
uni.showToast({
|
||
title: isFollowing ? '关注成功' : '取消关注',
|
||
icon: 'success',
|
||
});
|
||
},
|
||
onLike() {
|
||
const isLiked = !this.isLiked;
|
||
const likeCount = isLiked ? this.likeCount + 1 : this.likeCount - 1;
|
||
this.setData({
|
||
isLiked: isLiked,
|
||
likeCount: likeCount,
|
||
});
|
||
if (isLiked) {
|
||
uni.vibrateShort();
|
||
}
|
||
},
|
||
onCreateSimilar() {
|
||
const description = this.videoDescription;
|
||
const encodedDescription = encodeURIComponent(description);
|
||
uni.navigateTo({
|
||
url: `/pages/ai-generate/oneclick?description=${encodedDescription}&from=video`,
|
||
});
|
||
},
|
||
onConsult() {
|
||
const url = this.chatUrl;
|
||
if (!url) {
|
||
uni.showToast({ title: '暂无客服链接', icon: 'none' });
|
||
return;
|
||
}
|
||
// 统一跳转到内置网页容器
|
||
uni.navigateTo({
|
||
url: `/pages/users/web_page/index?webUel=${encodeURIComponent(url)}&title=客服`
|
||
});
|
||
},
|
||
onViewHistory() {
|
||
uni.navigateTo({
|
||
url: '/pages/ai-generate/assets',
|
||
});
|
||
},
|
||
onTouchStart(e) {
|
||
if (!this.isSwipeEnabled || this.isLoadingArticle) return;
|
||
this.setData({
|
||
touchStartY: e.touches[0].clientY,
|
||
});
|
||
},
|
||
onTouchEnd(e) {
|
||
if (!this.isSwipeEnabled || this.isLoadingArticle) return;
|
||
const touchEndY = e.changedTouches[0].clientY;
|
||
const deltaY = touchEndY - this.touchStartY;
|
||
const minSwipeDistance = 50;
|
||
this.setData({
|
||
touchEndY: touchEndY,
|
||
});
|
||
if (Math.abs(deltaY) > minSwipeDistance) {
|
||
if (deltaY > 0) {
|
||
this.loadPreviousArticle();
|
||
} else {
|
||
this.loadNextArticle();
|
||
}
|
||
}
|
||
},
|
||
loadPreviousArticle() {
|
||
const currentId = parseInt(this.currentArticleId);
|
||
if (currentId && currentId > 1) {
|
||
const previousId = currentId - 1;
|
||
console.log('加载上一篇文章,ID:', previousId);
|
||
this.loadArticleDetail(previousId);
|
||
this.setData({
|
||
currentArticleId: previousId.toString(),
|
||
});
|
||
} else {
|
||
uni.showToast({
|
||
title: '已经是第一篇了',
|
||
icon: 'none',
|
||
});
|
||
}
|
||
},
|
||
loadNextArticle() {
|
||
const currentId = parseInt(this.currentArticleId);
|
||
if (currentId) {
|
||
const nextId = currentId + 1;
|
||
console.log('加载下一篇文章,ID:', nextId);
|
||
this.loadArticleDetail(nextId);
|
||
this.setData({
|
||
currentArticleId: nextId.toString(),
|
||
});
|
||
}
|
||
},
|
||
onToggleDescription() {
|
||
this.setData({
|
||
isDescriptionExpanded: !this.isDescriptionExpanded,
|
||
});
|
||
},
|
||
onShareAppMessage() {
|
||
try {
|
||
// 获取分享标题,优先使用articleData.title
|
||
let shareTitle = '精彩视频分享'; // 默认标题
|
||
if (this.articleData && this.articleData.title) {
|
||
shareTitle = this.articleData.title;
|
||
// 限制标题长度,微信建议不超过28个字符
|
||
if (shareTitle.length > 28) {
|
||
shareTitle = shareTitle.substring(0, 25) + '...';
|
||
}
|
||
} else if (this.creatorName) {
|
||
shareTitle = `${this.creatorName}的作品`;
|
||
}
|
||
|
||
// 获取分享缩略图,优先使用articleData.imageInput
|
||
let shareImageUrl = '/static/images/video-share.png'; // 默认缩略图
|
||
if (this.articleData && this.articleData.imageInput) {
|
||
shareImageUrl = this.articleData.imageInput;
|
||
}
|
||
|
||
// 构建分享路径,包含当前文章ID
|
||
const sharePath = this.currentArticleId
|
||
? `/pages/ai-generate/video?id=${this.currentArticleId}`
|
||
: '/pages/ai-generate/assets';
|
||
|
||
console.log('分享配置:', {
|
||
title: shareTitle,
|
||
path: sharePath,
|
||
imageUrl: shareImageUrl
|
||
});
|
||
|
||
return {
|
||
title: shareTitle,
|
||
path: sharePath,
|
||
imageUrl: shareImageUrl,
|
||
};
|
||
} catch (error) {
|
||
console.error('分享配置失败:', error);
|
||
// 发生错误时返回默认配置
|
||
return {
|
||
title: '精彩视频分享',
|
||
path: '/pages/ai-generate/video',
|
||
imageUrl: '/static/images/video-share.png',
|
||
};
|
||
}
|
||
},
|
||
onShareTimeline() {
|
||
try {
|
||
// 获取分享标题,优先使用articleData.title
|
||
let shareTitle = '精彩视频分享'; // 默认标题
|
||
if (this.articleData && this.articleData.title) {
|
||
shareTitle = this.articleData.title;
|
||
// 朋友圈分享标题建议更简洁,限制在20个字符内
|
||
if (shareTitle.length > 20) {
|
||
shareTitle = shareTitle.substring(0, 17) + '...';
|
||
}
|
||
} else if (this.creatorName) {
|
||
shareTitle = `${this.creatorName}的作品`;
|
||
}
|
||
|
||
// 获取分享缩略图,优先使用articleData.imageInput
|
||
let shareImageUrl = '/static/images/video-share.png'; // 默认缩略图
|
||
if (this.articleData && this.articleData.imageInput) {
|
||
shareImageUrl = this.articleData.imageInput;
|
||
}
|
||
|
||
console.log('朋友圈分享配置:', {
|
||
title: shareTitle,
|
||
imageUrl: shareImageUrl
|
||
});
|
||
|
||
return {
|
||
title: shareTitle,
|
||
imageUrl: shareImageUrl,
|
||
};
|
||
} catch (error) {
|
||
console.error('朋友圈分享配置失败:', error);
|
||
// 发生错误时返回默认配置
|
||
return {
|
||
title: '精彩视频分享',
|
||
imageUrl: '/static/images/video-share.png',
|
||
};
|
||
}
|
||
},
|
||
onPullDownRefresh() {
|
||
this.loadVideoData();
|
||
setTimeout(() => {
|
||
uni.stopPullDownRefresh();
|
||
}, 1000);
|
||
},
|
||
setData(data) {
|
||
let that = this;
|
||
Object.keys(data).forEach(key => {
|
||
that[key] = data[key];
|
||
});
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style>
|
||
/* 视频播放页面样式 */
|
||
.video-container {
|
||
width: 100vw;
|
||
height: 100vh;
|
||
background: #000000; margin-top: 80rpx;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* AI生成内容标识 */
|
||
.ai-notice {
|
||
position: fixed;
|
||
right: 12px;width: 100px;
|
||
height: 30px; top: 92px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8rpx;
|
||
padding: 12rpx 24rpx;
|
||
background: rgba(0, 0, 0, 0.3);
|
||
border: 1rpx solid rgba(66, 202, 77, 0.5);
|
||
border-radius: 40rpx;
|
||
backdrop-filter: blur(10rpx);
|
||
z-index: 100;
|
||
}
|
||
|
||
.ai-notice-icon {
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.ai-notice-text {
|
||
font-size: 20rpx;
|
||
color: #42ca4d;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.video-player {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 顶部控制栏 */
|
||
.top-controls {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 48px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-end;
|
||
padding: 0 16px 16px;
|
||
background: linear-gradient(180deg, rgba(0,0,0,0.6) 0%, transparent 100%);
|
||
z-index: 10;
|
||
}
|
||
|
||
.left-controls {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.back-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 12px;
|
||
}
|
||
|
||
.icon-back {
|
||
font-size: 24px;
|
||
color: #ffffff;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* 文章详情样式 */
|
||
.article-status {
|
||
margin-bottom: 16px;
|
||
padding: 12px 16px;
|
||
background: rgba(0, 0, 0, 0.6);
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.loading-indicator {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.loading-text {
|
||
color: #ffffff;
|
||
font-size: 14px;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.error-message {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.error-text {
|
||
color: #ff6b6b;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.article-detail {
|
||
margin-bottom: 16px;
|
||
padding: 16px;
|
||
background: rgba(0, 0, 0, 0.6);
|
||
border-radius: 12px;
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
.article-header {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.article-title {
|
||
color: #ffffff;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.article-meta {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
gap: 12px;
|
||
}
|
||
|
||
.publish-time {
|
||
color: #ffffff;
|
||
font-size: 12px;
|
||
opacity: 0.7;
|
||
}
|
||
|
||
.article-category {
|
||
color: #4CAF50;
|
||
font-size: 12px;
|
||
background: rgba(76, 175, 80, 0.2);
|
||
padding: 2px 8px;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.article-content {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.content-text {
|
||
color: #ffffff;
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.article-tags {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.tag-item {
|
||
color: #2196F3;
|
||
font-size: 12px;
|
||
background: rgba(33, 150, 243, 0.2);
|
||
padding: 4px 8px;
|
||
border-radius: 12px;
|
||
}
|
||
|
||
.time-display {
|
||
font-size: 14px;
|
||
color: #ffffff;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.right-controls {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.signal-icons {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-right: 12px;
|
||
}
|
||
|
||
.signal, .wifi, .battery {
|
||
font-size: 14px;
|
||
color: #ffffff;
|
||
margin-left: 4px;
|
||
}
|
||
|
||
.share-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.icon-share {
|
||
font-size: 18px;
|
||
color: #ffffff;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* 视频内容区域 */
|
||
.video-content {
|
||
flex: 1;
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.video-element {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.play-indicator {
|
||
position: absolute;
|
||
width: 80px;
|
||
height: 80px;
|
||
background: rgba(0, 0, 0, 0.6);
|
||
border-radius: 40px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: opacity 0.3s ease;
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
.play-indicator.hide {
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.play-indicator.show {
|
||
opacity: 1;
|
||
}
|
||
|
||
.play-icon {
|
||
font-size: 32px;
|
||
color: #ffffff;
|
||
margin-left: 4px;
|
||
}
|
||
|
||
/* 底部信息区域 */
|
||
.bottom-info {
|
||
position: absolute;
|
||
bottom: 60rpx;
|
||
left: 0;
|
||
right: 0;
|
||
padding: 11px;
|
||
background: linear-gradient(0deg, rgba(0,0,0,0.8) 0%, transparent 100%);
|
||
z-index: 10;
|
||
}
|
||
|
||
/* 创作者信息 */
|
||
.creator-info {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.creator-avatar {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 20px;
|
||
margin-right: 12px;
|
||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||
}
|
||
|
||
.creator-details {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.creator-name {
|
||
font-size: 16px;
|
||
color: #ffffff;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.follow-btn {
|
||
padding: 6px 16px;
|
||
background: #ffffff;
|
||
color: #333333;
|
||
border-radius: 16px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.follow-btn.following {
|
||
background: rgba(255, 255, 255, 0.3);
|
||
color: #ffffff;
|
||
}
|
||
|
||
/* 视频描述信息 */
|
||
.video-info {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.info-tags {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.tag {
|
||
padding: 4px 8px;
|
||
border-radius: 12px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.tag-info {
|
||
background: rgba(79, 172, 254, 0.8);
|
||
color: #ffffff;
|
||
}
|
||
|
||
.tag-ai {
|
||
background: rgba(118, 75, 162, 0.8);
|
||
color: #ffffff;
|
||
}
|
||
|
||
.video-description {
|
||
font-size: 14px;
|
||
color: #ffffff;
|
||
line-height: 1.4;
|
||
opacity: 0.9;
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 2;
|
||
line-clamp: 2;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
word-break: break-all;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.video-description.expanded {
|
||
-webkit-line-clamp: unset;
|
||
line-clamp: unset;
|
||
overflow: visible;
|
||
}
|
||
|
||
/* 展开/收起切换按钮 */
|
||
.expand-toggle {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
margin-top: 8px;
|
||
padding: 4px 0;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.expand-toggle .iconfont {
|
||
font-size: 16px;
|
||
color: rgba(255, 255, 255, 0.7);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.expand-toggle:active .iconfont {
|
||
color: rgba(255, 255, 255, 1);
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
/* 互动操作区 */
|
||
.interaction-area {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.like-section {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.like-btn {
|
||
width: 44px;
|
||
height: 44px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 8px;
|
||
transition: transform 0.2s ease;
|
||
}
|
||
|
||
.like-btn:active {
|
||
transform: scale(1.2);
|
||
}
|
||
|
||
.heart-icon {
|
||
font-size: 24px;
|
||
}
|
||
|
||
.like-count {
|
||
font-size: 16px;
|
||
color: #ffffff;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.action-buttons {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
|
||
/* 悬浮操作按钮 */
|
||
.floating-actions {
|
||
position: fixed;
|
||
right: 16px;
|
||
bottom: 35%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 20px;
|
||
z-index: 100;
|
||
}
|
||
|
||
.floating-btn {
|
||
width: 42px;
|
||
height: 42px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
background: linear-gradient(135deg, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0.25) 100%);
|
||
border: 2px solid rgba(255, 255, 255, 0.15);
|
||
border-radius: 50%;
|
||
backdrop-filter: blur(20px);
|
||
transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4),
|
||
0 4px 8px rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
.floating-btn:active {
|
||
transform: scale(0.92);
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3),
|
||
0 2px 4px rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
/* 下载按钮 */
|
||
.download-btn {
|
||
background: linear-gradient(135deg, rgba(76, 175, 80, 0.2) 0%, rgba(56, 142, 60, 0.4) 100%);
|
||
border-color: rgba(139, 195, 74, 0.3);
|
||
}
|
||
|
||
.download-btn:active {
|
||
background: linear-gradient(135deg, rgba(76, 175, 80, 1) 0%, rgba(56, 142, 60, 0.9) 100%);
|
||
}
|
||
|
||
/* 分享按钮 */
|
||
.share-btn {
|
||
background: linear-gradient(135deg, rgba(33, 150, 243, 0.2) 0%, rgba(25, 118, 210, 0.4) 100%);
|
||
border-color: rgba(100, 181, 246, 0.3);
|
||
}
|
||
|
||
.share-btn:active {
|
||
background: linear-gradient(135deg, rgba(33, 150, 243, 1) 0%, rgba(25, 118, 210, 0.9) 100%);
|
||
}
|
||
|
||
/* CSS绘制的下载图标 */
|
||
.icon-download {
|
||
width: 20px;
|
||
height: 20px;
|
||
position: relative;
|
||
}
|
||
|
||
.icon-download::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 0;
|
||
width: 3px;
|
||
height: 14px;
|
||
background: #ffffff;
|
||
transform: translateX(-50%);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.icon-download::after {
|
||
content: '';
|
||
position: absolute;
|
||
left: 50%;
|
||
bottom: 0;
|
||
width: 0;
|
||
height: 0;
|
||
border-left: 5px solid transparent;
|
||
border-right: 5px solid transparent;
|
||
border-top: 6px solid #ffffff;
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
/* CSS绘制的分享图标 */
|
||
.icon-share {
|
||
width: 20px;
|
||
height: 20px;
|
||
position: relative;
|
||
}
|
||
|
||
.icon-share::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 50%;
|
||
bottom: 0;
|
||
width: 3px;
|
||
height: 14px;
|
||
background: #ffffff;
|
||
transform: translateX(-50%);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.icon-share::after {
|
||
content: '';
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 0;
|
||
width: 0;
|
||
height: 0;
|
||
border-left: 5px solid transparent;
|
||
border-right: 5px solid transparent;
|
||
border-bottom: 6px solid #ffffff;
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
.floating-label {
|
||
font-size: 12px;
|
||
color: #ffffff;
|
||
font-weight: 500;
|
||
letter-spacing: 0.3px;
|
||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||
}
|
||
|
||
.consult-btn {
|
||
padding: 12px 24px;
|
||
background: rgba(255, 255, 255, 0.15);
|
||
color: #ffffff;
|
||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||
border-radius: 24px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
transition: transform 0.2s ease, background 0.2s ease;
|
||
}
|
||
|
||
.consult-btn:active {
|
||
transform: scale(0.95);
|
||
background: rgba(255, 255, 255, 0.25);
|
||
}
|
||
|
||
.action-btn {
|
||
padding: 12px 24px;
|
||
background: #ffffff;
|
||
color: #333333;
|
||
border-radius: 24px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
transition: transform 0.2s ease;
|
||
}
|
||
|
||
.action-btn:active {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
/* 进度条 */
|
||
.progress-bar {
|
||
width: 100%;
|
||
}
|
||
|
||
.progress-track {
|
||
width: 100%;
|
||
height: 2px;
|
||
background: rgba(255, 255, 255, 0.3);
|
||
border-radius: 1px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.progress-fill {
|
||
height: 100%;
|
||
background: #ffffff;
|
||
border-radius: 1px;
|
||
transition: width 0.1s ease;
|
||
}
|
||
|
||
/* 点赞动画 */
|
||
@keyframes likeAnimation {
|
||
0% {
|
||
transform: scale(1);
|
||
}
|
||
50% {
|
||
transform: scale(1.3);
|
||
}
|
||
100% {
|
||
transform: scale(1);
|
||
}
|
||
}
|
||
|
||
.like-btn.liked .heart-icon {
|
||
animation: likeAnimation 0.6s ease;
|
||
}
|
||
</style> |