Browse Source

Merge branch 'hzj' into Xfy. Add video frame extraction functionality and fix video-only product share card issue.

pull/12/head
Trae AI 2 months ago
parent
commit
408ea92690
  1. 209
      pages/goods-detail/goods-detail.js
  2. 20
      pages/goods-detail/goods-detail.wxml

209
pages/goods-detail/goods-detail.js

@ -444,10 +444,36 @@ Page({
sharePath += `&region=${regionParam}`;
}
// 确定分享图片
let imageUrl = '/images/你有好蛋.png'; // 默认值
// 检查是否为纯视频商品
const mediaItems = goodsDetail.mediaItems || [];
const hasVideo = mediaItems.some(item => item.type === 'video');
const hasImage = mediaItems.some(item => item.type === 'image');
if (hasVideo && !hasImage) {
// 纯视频商品:使用提取的封面或默认图片
if (this.data.videoCoverUrl) {
imageUrl = this.data.videoCoverUrl;
console.log('使用提取的视频封面分享:', imageUrl);
} else {
console.log('视频封面尚未提取完成,使用默认图片');
// 尝试立即提取视频封面
const videoItems = mediaItems.filter(item => item.type === 'video');
if (videoItems.length > 0) {
this.extractVideoFirstFrame(videoItems[0].url);
}
}
} else {
// 有图片的商品:使用原有的图片选择逻辑
imageUrl = getShareImageUrl(goodsDetail);
}
return {
title: title,
path: sharePath,
imageUrl: getShareImageUrl(goodsDetail, this)
imageUrl: imageUrl
}
},
@ -481,10 +507,34 @@ Page({
const contactQuery = queryParams.join('&');
// 确定分享图片
let imageUrl = '/images/你有好蛋.png';
const mediaItems = goodsDetail.mediaItems || [];
const hasVideo = mediaItems.some(item => item.type === 'video');
const hasImage = mediaItems.some(item => item.type === 'image');
if (hasVideo && !hasImage) {
// 纯视频商品:使用提取的封面或默认图片
if (this.data.videoCoverUrl) {
imageUrl = this.data.videoCoverUrl;
console.log('使用提取的视频封面分享:', imageUrl);
} else {
console.log('视频封面尚未提取完成,使用默认图片');
// 尝试立即提取视频封面
const videoItems = mediaItems.filter(item => item.type === 'video');
if (videoItems.length > 0) {
this.extractVideoFirstFrame(videoItems[0].url);
}
}
} else {
imageUrl = getShareImageUrl(goodsDetail);
}
return {
title: title,
query: contactQuery,
imageUrl: getShareImageUrl(goodsDetail, this)
imageUrl: imageUrl
}
},
@ -561,9 +611,11 @@ Page({
favoriteGoods: [], // 收藏商品数据
loadingHome: false, // 首页数据加载状态
loadingFavorite: false, // 收藏数据加载状态
// 视频相关状态
videoCoverUrl: '', // 视频封面URL
videoSrc: '', // 视频源URL
// 新增以下字段:
videoCoverUrl: null, // 视频封面图片URL
isExtractingCover: false, // 是否正在提取封面
videoCoverCache: {}, // 视频封面缓存 {videoUrl: coverUrl}
videoSrcForSnapshot: '', // 用于截图的视频URL
},
// 点击对比价格列表中的商品,跳转到对应的商品详情页
@ -607,7 +659,7 @@ Page({
});
}
});
},
}
onLoad: function (options) {
console.log('商品详情页面加载,参数:', options);
@ -757,6 +809,143 @@ Page({
});
},
// ========== 新增:视频封面提取相关方法 ==========
/**
* 检查并提取视频封面
*/
async checkAndExtractVideoCover() {
const goodsDetail = this.data.goodsDetail;
const mediaItems = goodsDetail.mediaItems || [];
// 1. 检查是否为纯视频商品
const hasVideo = mediaItems.some(item => item.type === 'video');
const hasImage = mediaItems.some(item => item.type === 'image');
if (!hasVideo || hasImage) {
// 不是纯视频商品,不需要提取
return;
}
// 2. 获取第一个视频
const videoItems = mediaItems.filter(item => item.type === 'video');
if (videoItems.length === 0) return;
const firstVideo = videoItems[0];
const videoUrl = firstVideo.url;
// 3. 检查缓存
const cachedCover = this.data.videoCoverCache[videoUrl];
if (cachedCover) {
console.log('使用缓存的视频封面');
this.setData({
videoCoverUrl: cachedCover
});
return;
}
// 4. 开始提取
await this.extractVideoFirstFrame(videoUrl);
},
/**
* 提取视频第一帧
*/
async extractVideoFirstFrame(videoUrl) {
if (!videoUrl || this.data.isExtractingCover) {
return null;
}
console.log('开始提取视频封面:', videoUrl);
this.setData({ isExtractingCover: true });
try {
// 方法1:使用snapshot API(推荐)
const coverUrl = await this.captureVideoFrame(videoUrl);
if (coverUrl && coverUrl !== '/images/你有好蛋.png') {
// 更新缓存
const newCache = { ...this.data.videoCoverCache };
newCache[videoUrl] = coverUrl;
this.setData({
videoCoverUrl: coverUrl,
videoCoverCache: newCache,
isExtractingCover: false
});
console.log('视频封面提取成功:', coverUrl);
return coverUrl;
}
} catch (error) {
console.error('提取视频封面失败:', error);
}
// 降级到默认图片
this.setData({
videoCoverUrl: '/images/你有好蛋.png',
isExtractingCover: false
});
return '/images/你有好蛋.png';
},
/**
* 捕获视频帧从真实视频中提取帧
*/
captureVideoFrame(videoUrl) {
return new Promise((resolve, reject) => {
console.log('尝试从视频中提取真实帧:', videoUrl);
try {
// 检查当前环境是否为预览环境
const isPreview = __wxConfig.envVersion === 'develop' || __wxConfig.envVersion === 'trial';
console.log('当前环境:', isPreview ? '预览环境' : '生产环境');
// 检查视频URL是否来自阿里云OSS
// 如果是,可以使用阿里云OSS的视频处理参数来获取视频帧
if (videoUrl.includes('aliyuncs.com')) {
console.log('检测到阿里云OSS视频,使用URL参数获取视频帧');
// 构建带参数的URL,用于获取视频第一帧
// 添加阿里云OSS视频处理参数:x-oss-process=video/snapshot,t_0,f_jpg
// t_0表示获取第0秒的帧,f_jpg表示输出为jpg格式
const frameUrl = videoUrl + (videoUrl.includes('?') ? '&' : '?') + 'x-oss-process=video/snapshot,t_0,f_jpg';
console.log('构建的视频帧URL:', frameUrl);
// 使用wx.downloadFile下载视频帧
wx.downloadFile({
url: frameUrl,
success: (res) => {
console.log('视频帧下载响应:', res);
if (res.statusCode === 200) {
console.log('视频帧下载成功:', res.tempFilePath);
resolve(res.tempFilePath);
} else {
console.error('视频帧下载失败,状态码:', res.statusCode);
// 降级方案:使用默认图片
resolve('/images/你有好蛋.png');
}
},
fail: (err) => {
console.error('视频帧下载失败:', err);
// 降级方案:使用默认图片
resolve('/images/你有好蛋.png');
}
});
} else {
// 如果不是阿里云OSS视频,使用默认图片
console.log('非阿里云OSS视频,使用默认图片');
resolve('/images/你有好蛋.png');
}
} catch (error) {
console.error('提取视频帧异常:', error);
// 降级方案:使用默认图片
resolve('/images/你有好蛋.png');
}
});
},
loadGoodsDetail: function (productId, preloadedData = null, contactFromShare = null) {
// 首先显示预加载的数据,确保UI快速响应
if (preloadedData) {
@ -1105,9 +1294,15 @@ Page({
this.setData({
goodsDetail: formattedGoods,
displayRegion: displayRegion,
isFavorite: preloadedFavoriteStatus // 优先使用预加载数据中的收藏状态
isFavorite: preloadedFavoriteStatus, // 优先使用预加载数据中的收藏状态
videoCoverUrl: null // 重置封面URL
});
// 商品加载完成后检查并提取视频封面
setTimeout(() => {
this.checkAndExtractVideoCover();
}, 500);
// 只有当没有预加载的收藏状态时,才从服务器加载
if (!preloadedData || preloadedData.isFavorite === undefined) {
this.loadGoodsFavoriteStatus(productIdStr);

20
pages/goods-detail/goods-detail.wxml

@ -1,5 +1,25 @@
<!-- pages/goods-detail/goods-detail.wxml -->
<view class="goods-detail-page">
<!-- 在页面最顶部添加以下代码 -->
<!-- 隐藏的video组件,用于视频封面截图 -->
<video
id="videoSnapshotHelper"
src="{{videoSrcForSnapshot}}"
style="position: absolute; top: -9999px; width: 300px; height: 300px;"
autoplay="{{false}}"
muted="{{true}}"
show-center-play-btn="{{false}}"
show-play-btn="{{false}}"
object-fit="contain"
></video>
<!-- 隐藏的canvas组件,用于绘制视频帧 -->
<canvas
id="videoCanvas"
canvas-id="videoCanvas"
style="position: absolute; top: -9999px; width: 300px; height: 300px;"
></canvas>
<!-- 商品详情内容 -->
<view class="goods-detail-content">
<!-- 商品媒体轮播(支持图片和视频) -->

Loading…
Cancel
Save