vr-shopxo-uniapp/pages/plugins/video/detail/detail.vue

1995 lines
90 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="content pr">
<template v-if="display_video_list.length > 0">
<!-- 搜索框 -->
<view v-if="!show_comment_modal" class="header-top" :style="top_content_style + menu_button_info">
<view id="search-height" class="flex-row align-c">
<!-- 支付宝小程序自带返回按钮,这里就不给返回按钮了,这里给留出一点空间就行 -->
<!-- #ifndef MP-ALIPAY -->
<view class="cp" @tap="handle_back">
<iconfont name="icon-arrow-left " size="36rpx" color="#333" class="mr-10"></iconfont>
</view>
<!-- #endif -->
<view class="wh-auto ht-auto" :style="header_padding_left">
<search-component propIsDisabled @disabledSearch="handle_search" />
</view>
</view>
</view>
<!-- 视频列表 -->
<swiper class="swiper-container" :key="'top-or-buttom-' + swiper_key" :style="swiperStyle" :duration="500" :vertical="true" :circular="close_circular ? false : true" :skip-hidden-item-layout="true" :current="current_index" easing-function="linear" @transition="on_transition" @change="handle_swiper_change">
<swiper-item v-for="(video_item, index) in display_video_list" :key="video_item.id">
<view class="video-container pr" @tap.stop="toggle_play_pause">
<view class="video-bg" :style="!isEmpty(video_item.poster_url) ? 'background-image: url(' + video_item.poster_url + ')' : ''"></view>
<video class="video" :src="video_item.video_url" :poster="video_item.poster_url" :id="`video_${index}`" :loop="true" :show-fullscreen-btn="false" :show-center-play-btn="false" :show-play-btn="false" :controls="false" :show-mute-btn="true" object-fit="contain" @timeupdate="handle_time_update" @play="handle_play"></video>
<view v-if="paused && current_index == index" class="play-icon">
<view class="pr">
<view class="play-icon-bg"></view>
<view class="pa z-i play-icon-iconfont">
<iconfont name="icon-bofang" size="120rpx" propClass="" color="#4F3E35"></iconfont>
</view>
</view>
</view>
<template v-if="!show_comment_modal">
<!-- Right Action Bar -->
<view class="right-actions">
<view v-if="base_config_data && base_config_data.is_video_give_thumbs && base_config_data.is_video_give_thumbs == 1" class="action-item" :data-value="video_item" @tap.stop="handle_like">
<iconfont name="icon-givealike" :color="video_item.is_give_thumbs == 0 ? '#fff' : '#F4B73F'" size="60rpx" />
<text class="action-text">{{ video_item.give_thumbs_count }}</text>
</view>
<view v-if="base_config_data && base_config_data.is_video_comments_show && base_config_data.is_video_comments_show == 1" class="action-item" :data-value="video_item" @tap.stop="handle_comment">
<iconfont name="icon-comment" color="#fff" size="60rpx" />
<text class="action-text">{{ video_item.comments_count }}</text>
</view>
<view class="action-item" @tap.stop="handle_share">
<iconfont name="icon-share-solid" color="#fff" size="60rpx"></iconfont>
<text class="action-text">分享</text>
</view>
</view>
<view v-if="!isEmpty(video_item.goods) && base_config_data && base_config_data.is_video_detail_show_goods && base_config_data.is_video_detail_show_goods == 1" class="product-card">
<view class="flex-col gap-10">
<view v-if="video_item.show_goods" class="flex-row align-c gap-10 product-card-item" :data-id="video_item.id" @tap.stop="handle_product_card_item">
<view class="product-image">
<image :src="video_item.goods.images" mode="aspectFill" class="product-image"></image>
</view>
<view class="flex-1 flex-col align-sb jc-c gap-10">
<text class="product-name text-line-1">{{ video_item.goods.title }}</text>
<text class="product-price">¥{{ video_item.goods.price }}</text>
</view>
<view class="product-close" :data-id="video_item.id" @tap.stop="product_close_event">
<iconfont name="icon-close" color="#999" size="30rpx"></iconfont>
</view>
</view>
<view class="product-button" :data-id="video_item.id" @tap.stop="handle_product_button">
<view class="product-button-left flex-row align-c gap-10">
<iconfont name="icon-cart-have" color="#F5C366" size="30rpx"></iconfont>
<text class="size-14 cr-f">购买商品</text>
</view>
<iconfont name="icon-angle-right" color="#fff" size="30rpx"></iconfont>
</view>
</view>
</view>
<!-- Progress Bar -->
<view class="progress-bar-container" v-if="current_index == index">
<slider class="progress-slider" :value="current_video_progress" :max="current_video_duration" @change.stop="handle_slider_change" @changing="handle_slider_changing" @tap.stop="handle_slider_change" block-size="14" activeColor="#FFFFFF" backgroundColor="rgba(255, 255, 255, 0.4)" />
<text class="time-display">{{ format_time(current_video_progress) }} / {{ format_time(current_video_duration) }}</text>
</view>
</template>
</view>
</swiper-item>
</swiper>
</template>
<template v-else>
<component-no-data :propStatus="data_list_loding_status" :propMsg="data_list_loding_msg"></component-no-data>
</template>
<!-- 评论弹窗 -->
<view v-if="show_comment_modal" class="comment-modal" @tap="close_comment_modal">
<view class="comment-content bottom-line-exclude-bottom" :style="commentContentStyle" @tap.stop @touchstart="handle_comment_touch_start" @touchmove="handle_comment_touch_move" @touchend="handle_comment_touch_end">
<view class="comment-header">
<text class="comment-count">评论</text>
<view class="close-btn" @tap="close_comment_modal">✕</view>
</view>
<!-- 评论内容区域 -->
<scroll-view class="comment-list" scroll-y :scroll-top="comment_scroll_top" show-scrollbar="false" scroll-with-animation @scrolltolower="handle_comment_to_lower_scroll" @scroll="handle_comment_scroll">
<view class="comment-scroll">
<template v-if="active_comments.length > 0">
<view class="comment-item flex-col" v-for="(comment_item, index) in active_comments" :key="index">
<commentInfoComponent class="wh-auto ht-auto" :propComment="comment_item" :propId="comment_item.id" :propDropDownVisible="active_dropdown_id == comment_item.id" @comment_reply="comment_reply" @comment_like="comment_like" @toggle_dropdown="handle_toggle_dropdown" @dropdown_item_click="handle_dropdown_item_click"></commentInfoComponent>
<!-- 子评论 -->
<view class="sub-comment flex-col jc-c gap-10 mt-10">
<view v-if="comment_item.sub_comments && comment_item.sub_comments.length > 0 && comment_item.show_sub_comment" class="sub-comment-list flex-col jc-c">
<view class="sub-comment-item flex-row align-s gap-10" v-for="(sub_comment_item, sub_comment_index) in comment_item.sub_comments" :key="sub_comment_index">
<commentInfoComponent class="wh-auto ht-auto" :propComment="sub_comment_item" :propId="sub_comment_item.id" :propDropDownVisible="active_dropdown_id == sub_comment_item.id" @comment_reply="comment_reply" @comment_like="comment_like" @toggle_dropdown="handle_toggle_dropdown" @dropdown_item_click="handle_dropdown_item_click"></commentInfoComponent>
</view>
</view>
<template v-if="comment_item.comments_count > 0">
<template v-if="!comment_item.show_sub_comment">
<commentMoreComponent :propId="comment_item.id" :propIsLevel="1" :propText="'—— 展开' + (comment_item.comments_count ? comment_item.comments_count || 0 : 0) + '条回复'" @comment_more_event="open_sub_comment"></commentMoreComponent>
</template>
<template v-else>
<template v-if="comment_item.show_sub_comment_loading">
<loading-component></loading-component>
</template>
<view v-else class="sub-comment-more flex-row align-c gap-10">
<view v-if="comment_item.page && comment_item.page < comment_item.page_total">
<commentMoreComponent :propId="comment_item.id" :propIsLevel="2" propText="展开" @comment_more_event="open_sub_comment"></commentMoreComponent>
</view>
<commentMoreComponent :propId="comment_item.id" propText="收起" propIconName="icon-arrow-top" @comment_more_event="close_sub_comment"></commentMoreComponent>
</view>
</template>
</template>
</view>
</view>
<template v-if="comment_item_loading">
<loading-component></loading-component>
</template>
<template v-else>
<!-- 结尾 -->
<component-bottom-line :propStatus="goods_bottom_line_status"></component-bottom-line>
</template>
</template>
<template v-else>
<component-no-data propMsg="暂无评论"></component-no-data>
</template>
</view>
</scroll-view>
<view v-if="base_config_data && base_config_data.is_video_comments_add && base_config_data.is_video_comments_add == 1" class="comment-input-container">
<view class="comment-input-content flex-col jc-c">
<view v-if="!isEmpty(comments_data)" class="comment-reply-content flex-row align-c jc-sb gap-10">
<text class="size-12 cr-f text-line-1">@{{ comments_data.user.user_name_view }}:{{ comments_data.content }}</text>
<view data-type="image" @tap="comment_data_delete">
<iconfont name="icon-close-line" size="24rpx" color="#fff"></iconfont>
</view>
</view>
<view class="flex-row align-c gap-10 wh-auto ht-auto pr-16 box-border-box">
<input :value="comment_input_value" class="comment-input" type="text" confirm-type="send" :adjust-position="false" :placeholder="input_placeholder" @focus="add_comment" @input="comment_input_event" @confirm="send_comment" />
<view data-type="image" @tap="comment_input_change">
<iconfont name="icon-layout-module-single-images" size="32rpx" color="#999"></iconfont>
</view>
</view>
<view v-if="form_images_list.length > 0" class="pr w h comment-input-img-container">
<view v-for="(item, index) in form_images_list" :key="index" class="comment-input-img pr">
<iconfont name="icon-close" size="10" color="#000" class="comment-input-img-close" :data-index="index" @tap="comment_input_img_close"></iconfont>
<image :src="item.url" :data-index="index" @tap="upload_show_event" mode="aspectFill" class="wh-auto ht-auto"></image>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 举报弹窗 -->
<component-popup :propShow="popup_report_status" propPosition="bottom" @onclose="popup_close_event">
<view class="report-content">
<!-- 顶部按钮区域 -->
<view class="report-header flex-row align-c jc-sb">
<view class="report-btn cr-6" @tap="popup_close_event">取消</view>
<view class="report-title flex-1">举报原因</view>
<view class="report-btn cr-blue" @tap="submit_report">确定</view>
</view>
<!-- 主要内容区域 -->
<view class="report-body">
<!-- 第一层:举报原因选择 -->
<view v-if="report_type_list.length > 0" class="report-section">
<view class="report-label">举报原因<text class="ml-10">*</text></view>
<view class="flex-row align-c gap-10 flex-wrap">
<view v-for="(mainItem, main_index) in report_type_list" :key="main_index" class="flex-row align-c" :data-index="main_index" @tap="select_main_reason">
<view class="flex-row align-c">
<radio :value="main_index.toString()" :checked="current_main_index === main_index" style="transform:scale(0.7)" />
<view class="flex-row align-c">{{mainItem.name}}</view>
</view>
</view>
</view>
</view>
<!-- 第二层:具体类型选择(当有主类别选中时显示) -->
<view class="report-section mt-20" v-if="current_main_index >= 0 && report_type_list[current_main_index]">
<view class="report-label">请选择具体的类型<text class="ml-10">*</text></view>
<view class="flex-row align-c gap-10 flex-wrap">
<view v-for="(subItem, sub_index) in report_type_list[current_main_index].data" :key="sub_index" class="flex-row align-c" :data-index="sub_index" @tap="select_sub_reason">
<view class="flex-row align-c">
<radio :value="sub_index.toString()" :checked="current_sub_index === sub_index" style="transform:scale(0.7)" />
<view class="flex-row align-c">{{subItem}}</view>
</view>
</view>
</view>
</view>
</view>
</view>
</component-popup>
<!-- 添加评论弹出框 -->
<view v-if="is_add_comment" class="keyboard-input br-top-shadow" :style="'width:100%;bottom:' + listener_height + 'px;'">
<view class="comment-input-content flex-col jc-c">
<view v-if="!isEmpty(comments_data)" class="comment-reply-content flex-row align-c jc-sb gap-10">
<text class="size-12 cr-f text-line-1">@{{ comments_data.user.user_name_view }}:{{ comments_data.content }}</text>
<view data-type="image" @tap="comment_data_delete">
<iconfont name="icon-close-line" size="24rpx" color="#fff"></iconfont>
</view>
</view>
<view class="flex-row align-c gap-10 wh-auto ht-auto pr-16 box-border-box">
<input :value="comment_input_value" :focus="is_add_comment" class="comment-input" type="text" confirm-type="done" :adjust-position="false" :auto-blur="true" :placeholder="input_placeholder" @input="comment_input_event" @blur="() => is_add_comment = false" @confirm="send_comment" />
<view data-type="image" @tap="comment_input_change">
<iconfont name="icon-layout-module-single-images" size="32rpx" color="#999"></iconfont>
</view>
</view>
<view v-if="form_images_list.length > 0" class="pr w h comment-input-img-container">
<view v-for="(item, index) in form_images_list" :key="index" class="comment-input-img pr">
<iconfont name="icon-close" size="10" color="#000" class="comment-input-img-close" :data-index="index" @tap="comment_input_img_close"></iconfont>
<image :src="item.url" :data-index="index" @tap="upload_show_event" mode="aspectFill" class="wh-auto ht-auto"></image>
</view>
</view>
</view>
</view>
<!-- 分享弹窗 -->
<component-share-popup ref="share"></component-share-popup>
</view>
</template>
<script>
const app = getApp();
import { get_math, isEmpty, video_get_top_left_padding } from '@/common/js/common/common.js';
import commentInfoComponent from '@/pages/plugins/video/components/comment-info.vue';
import loadingComponent from '@/pages/plugins/video/components/loading.vue';
import commentMoreComponent from '@/pages/plugins/video/components/comment-more.vue';
import searchComponent from '@/pages/plugins/video/components/search.vue';
import componentSharePopup from '@/components/share-popup/share-popup';
import componentNoData from '@/components/no-data/no-data';
import componentBottomLine from '@/components/bottom-line/bottom-line';
import componentPopup from '@/components/popup/popup';
// 状态栏高度
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
// #ifdef MP-TOUTIAO || H5
bar_height = 0;
// #endif
export default {
components: {
commentInfoComponent,
commentMoreComponent,
searchComponent,
componentSharePopup,
componentNoData,
componentBottomLine,
componentPopup,
loadingComponent
},
data() {
return {
// 5,7,0 是误差,, 10 是下边距66是高度bar_height是不同小程序下的导航栏距离顶部的高度
// #ifdef MP
top_content_style: 'padding-top:' + (bar_height + 5) + 'px;padding-bottom:10px;',
// #endif
// #ifdef H5 || MP-TOUTIAO
top_content_style: 'padding-top:' + (bar_height + 7) + 'px;padding-bottom:10px;',
// #endif
// #ifdef APP
top_content_style: 'padding-top:' + bar_height + 'px;padding-bottom:10px;',
// #endif
data_list_loding_status: 1,
data_list_loding_msg: '',
video_data_list: [],
display_video_list: [],
current_index: 0,
video_contexts: [], // 原生的video视频
create_video_contexts: [], // 使用uni.createVideoContext创建的视频上下文
paused: false,
current_video_progress: 0,
current_video_duration: 1,
is_seeking: false,
show_comment_modal: false,
active_comments: {},
comments_page: 1, // 当前评论页
comments_page_total: 5, // 评论总页数
goods_bottom_line_status: false, //评论页是否显示底部线
comment_item_loading: false,
comment_start_y: 0, // 评论开始拖拽位置
comment_current_y: 0, // 评论当前拖拽位置
move_distance: 0, // 评论拖拽距离
current_video_id: '', // 当前播放视频的ID
is_slide_start: false,
swiper_key: get_math(),
comment_scroll_top: 0, // 评论滚动距离顶部的距离
input_placeholder: '请输入您的精彩评论',
comment_input_value: '',
propMaxNum: 1,
form_images_list: [],
share_info: {},
menu_button_info: '',
direction: 'direction',
base_config_data: {},
video_switch_debounce_timer: null, // 视频切换防抖定时器
video_cleanup_timer: null, // 视频清理定时器
// 添加下拉菜单状态管理
active_dropdown_id: null, // 当前显示下拉菜单的评论ID
params: {},
header_padding_left: '',
report_type_list: [], // 举报类型列表
popup_report_status: false, // 举报弹窗状态
current_main_index: 0, // 默认选中第一个举报原因
current_sub_index: 0, // 默认选中第一个具体类型
report_comment_id: '', // 举报的评论id
comment_scroll_top: 0,
comment_value: '',
is_add_comment: false,
// 监听键盘高度变化事件
listener_height: 0,
comments_data: {}
};
},
computed: {
swiperStyle() {
return this.show_comment_modal ? (this.move_distance > 0 ? `height: calc(30% + ${this.move_distance}px);` : 'height: 30%;') : 'height: 100%;';
},
commentContentStyle() {
return this.show_comment_modal && this.move_distance > 0 ? `transform: translateY(3px); height: calc(70% - ${this.move_distance}px);` : `transform: translateY(0); height: 70%;`;
},
current_video_index() {
return this.video_data_list.findIndex(item => item.id == this.current_video_id);
},
// 如果是第一个或者最后一个的情况下,取消无限轮播
close_circular() {
if (this.video_data_list.length > 0) {
return this.video_data_list[0].id == this.current_video_id || this.video_data_list[this.video_data_list.length - 1].id == this.current_video_id;
} else {
return true
}
}
},
onLoad(params) {
// 调用公共事件方法
app.globalData.page_event_onload_handle(params);
// 设置参数
this.setData({
params: app.globalData.launch_params_handle(params),
});
},
onShow() {
this.init();
},
mounted() {
// #ifdef H5
// 添加全局点击事件监听
document.addEventListener('click', this.handle_global_click);
// 添加触摸事件监听(移动端兼容)
document.addEventListener('touchstart', this.handle_global_click);
//#endif
// 创建监听事件
this.bind_keyboard_listener();
},
beforeDestroy() {
// 清理定时器
if (this.video_switch_debounce_timer) {
clearTimeout(this.video_switch_debounce_timer);
}
if (this.video_cleanup_timer) {
clearTimeout(this.video_cleanup_timer);
}
// 清理所有视频资源
this.cleanup_all_videos();
// 移除键盘事件监听器
// #ifdef H5
if (typeof document !== 'undefined') {
document.removeEventListener('keydown', this.handle_keydown);
}
// 移除全局事件监听器
document.removeEventListener('click', this.handle_global_click);
document.removeEventListener('touchstart', this.handle_global_click);
// #endif
this.unbind_keyboard_listener();
},
methods: {
isEmpty,
init() {
// 小程序下,获取小程序胶囊的宽度
let menu_button_info = 'max-width:100%';
// #ifndef MP-TOUTIAO
// #ifdef MP
// 判断是否有胶囊
const is_current_single_page = app.globalData.is_current_single_page();
// 如果有胶囊的时候,做处理
if (is_current_single_page == 0) {
const custom = uni.getMenuButtonBoundingClientRect();
menu_button_info = `max-width:calc(100% - ${custom.width + 10}px);`;
}
// #endif
// #endif
// 视频详情页需要添加padding-left
let padding_left = '';
// #ifdef MP-ALIPAY
padding_left = video_get_top_left_padding();
// #endif
this.setData({
header_padding_left: padding_left,
menu_button_info: menu_button_info,
current_video_id: this.params.id,
});
this.get_video_detail(this.params.id);
},
// 获取视频详情
get_video_detail(id) {
// 获取数据
uni.request({
url: app.globalData.get_request_url("detail", "index", "video"),
method: 'POST',
data: {
id: id
},
dataType: 'json',
success: res => {
const data = res.data;
if (data.code == 0) {
// const list = data.data.video;
const new_data = data.data;
this.setData({
video_data_list: [new_data.data],
report_type_list: new_data.report_type_list,
base_config_data: new_data.base_config_data,
});
this.get_last_or_next_data_list(this.params.id, 1, 1);
} else {
this.setData({
data_list_loding_status: 2,
data_tabs_loding_msg: data.msg,
});
}
},
fail: (err) => {
this.setData({
data_list_loding_status: 2,
data_list_loding_msg: this.$t('common.internet_error_tips'),
});
}
});
},
// 获取视频列表
get_last_or_next_data_list(id, is_last = 0, is_next = 0) {
// 获取数据
uni.request({
url: app.globalData.get_request_url("lastnextdata", "index", "video"),
method: 'POST',
data: {
id: id,
is_last: is_last,
is_next: is_next,
},
dataType: 'json',
success: res => {
const data = res.data;
if (data.code == 0) {
const new_data = data.data;
// 第一次的数据
let data_list = JSON.parse(JSON.stringify(this.video_data_list));
// 创建现有数据的ID映射表用于快速去重
const existing_ids = new Map();
data_list.forEach(item => {
existing_ids.set(item.id, true);
});
if (is_last == 1 && is_next == 1) {
// 上一批数据 - 去重处理
if (new_data.last.length > 0) {
const unique_last = new_data.last.filter(item => !existing_ids.has(item.id));
if (unique_last.length > 0) {
data_list.unshift(...unique_last);
// 更新ID映射表
unique_last.forEach(item => existing_ids.set(item.id, true));
}
}
// 下一批数据 - 去重处理
if (new_data.next.length > 0) {
const unique_next = new_data.next.filter(item => !existing_ids.has(item.id));
if (unique_next.length > 0) {
data_list.push(...unique_next);
}
}
} else if (is_last == 1 && new_data.last.length > 0) { // 上一页数据 - 去重处理
const unique_last = new_data.last.filter(item => !existing_ids.has(item.id));
if (unique_last.length > 0) {
data_list.unshift(...unique_last);
}
} else if (is_next == 1 && new_data.next.length > 0) { // 下一页数据 - 去重处理
const unique_next = new_data.next.filter(item => !existing_ids.has(item.id));
if (unique_next.length > 0) {
data_list.push(...unique_next);
}
}
// 更新当前视频商品信息
const new_index = data_list.findIndex(item => item.id == this.params.id);
data_list.forEach((item) => {
if (isEmpty(item.show_goods)) {
if (this.base_config_data && this.base_config_data.is_video_detail_show_goods_modal && this.base_config_data.is_video_detail_show_goods_modal == 1) {
item.show_goods = true;
} else {
item.show_goods = false;
}
}
});
this.setData({
video_data_list: data_list,
current_index: is_last == 1 && is_next == 1 ? (new_index == data_list.length - 1 ? 2 : (new_index == data_list.length - 2 ? 1 : 0)) : this.current_index,
});
if (is_last == 1 && is_next == 1) {
// 更新数据信息
this.update_display_data();
setTimeout(() => {
// // 更新分享信息
this.update_share_info(this.display_video_list[0]);
this.display_video_list.forEach((item, index) => {
this.create_video_contexts[index] = uni.createVideoContext(`video_${index}`, this);
//#ifdef H5
this.video_contexts[index] = document.getElementById(`video_${index}`).querySelector('video');
//#endif
});
setTimeout(() => {
//#ifdef H5
if (this.video_contexts[0]) { // 当前播放的视频索引为0
this.video_play_event(this.video_contexts[0], true);
}
//#endif
//#ifndef H5
if (this.create_video_contexts[0]) { // 当前播放的视频索引为0
this.video_play_event(this.create_video_contexts[0], true);
}
//#endif
}, 200);
}, 0);
}
} else {
this.setData({
data_list_loding_status: 2,
data_tabs_loding_msg: data.msg,
});
}
},
fail: (err) => {
this.setData({
data_list_loding_status: 2,
data_list_loding_msg: this.$t('common.internet_error_tips'),
});
}
});
},
// 视频滚动处理逻辑(带防抖)
handle_swiper_change(event) {
const { current } = event.detail;
// 防抖处理,避免快速切换时的重复操作
if (this.video_switch_debounce_timer) {
clearTimeout(this.video_switch_debounce_timer);
}
this.video_switch_debounce_timer = setTimeout(() => {
this.process_swiper_change(current);
}, 50); // 50ms防抖延迟
},
// 实际的swiper切换处理逻辑
process_swiper_change(current) {
// 先暂停所有视频,确保不会有后台播放
this.pause_all_videos_except(current);
const id = this.display_video_list[current].id;
// 更新状态
this.setData({
current_index: current,
paused: false,
current_video_progress: 0,
current_video_duration: 1,
is_seeking: false,
current_video_id: id, // 更新当前播放视频的ID
});
const index = this.video_data_list.findIndex(item => item.id == id);
// 数据预加载逻辑
if (index < 2 && this.direction == 'prev') {
this.get_last_or_next_data_list(this.video_data_list[0].id, 1, 0);
} else if (index < this.video_data_list.length - 3 && this.direction == 'next') {
this.get_last_or_next_data_list(this.video_data_list[this.video_data_list.length - 1].id, 0, 1);
}
// 获取视频详细信息
this.get_video_data_detail(id);
// 边界处理逻辑
if (this.current_video_index == 0 && this.is_slide_start) {
const list = [
this.get_video_by_index(0),
this.get_video_by_index(1),
this.get_video_by_index(2)
];
this.setData({
is_slide_start: false,
current_index: 0,
display_video_list: list,
swiper_key: get_math()
});
} else if (this.current_video_index == this.video_data_list.length - 1) {
const list = [
this.get_video_by_index(this.current_video_index - 2),
this.get_video_by_index(this.current_video_index - 1),
this.get_video_by_index(this.current_video_index),
];
this.setData({
current_index: 2,
display_video_list: list,
swiper_key: get_math()
});
} else {
this.setData({
is_slide_start: true,
swiper_key: get_math()
});
this.update_display_data();
}
// 更新分享信息
this.update_share_info(this.display_video_list[current]);
// 延迟播放当前视频确保DOM更新完成
setTimeout(() => {
this.play_current_video_safely(this.current_index);
}, 150);
},
// 批量暂停除指定索引外的所有视频
pause_all_videos_except(exceptIndex) {
// 暂停 uni.createVideoContext 创建的视频
this.create_video_contexts.forEach((context, index) => {
if (index !== exceptIndex && context) {
try {
context.pause();
} catch (error) {
console.warn(`暂停视频 ${index} 失败:`, error);
}
}
});
},
// 安全播放当前视频
play_current_video_safely(index) {
// 优先使用 uni.createVideoContext
if (this.create_video_contexts[index]) {
this.video_play_event(this.create_video_contexts[index], false);
return;
}
},
// 切换播放暂停
toggle_play_pause() {
const currentIndex = this.current_index;
// 检查视频上下文是否存在
const videoContext = this.create_video_contexts[currentIndex] || this.video_contexts[currentIndex];
if (!videoContext) {
console.warn(`当前索引 ${currentIndex} 无可用视频上下文`);
return;
}
this.setData({
paused: !this.paused
});
if (this.paused) {
// 暂停当前视频
try {
videoContext.pause();
} catch (error) {
console.warn('暂停视频失败:', error);
}
} else {
// 播放当前视频
this.video_play_event(videoContext, false);
}
},
update_share_info(data) {
const info = {
title: data.title || '',
desc: data.desc || '',
path: '/pages/plugins/video/detail/detail',
query: app.globalData.json_to_url_params(this.params),
img: data.poster_url || ''
}
this.setData({
share_info: info,
});
// 分享菜单处理
app.globalData.page_share_handle(info);
},
// 安全的视频播放事件处理
video_play_event(videoContext, is_first_play = false) {
if (!videoContext) {
this.setData({ paused: true });
return;
}
try {
if (is_first_play) {
//#ifdef H5
videoContext.play().catch((error) => {
this.setData({ paused: true });
});
//#endif
//#ifndef H5
videoContext.play();
//#endif
} else {
videoContext.play();
}
} catch (error) {
console.error('视频播放异常:', error);
this.setData({ paused: true });
}
},
// 安全获取视频数据的方法,处理索引超限情况
get_video_by_index(index) {
// 处理负数索引
if (index < 0) {
// 循环到数组末尾
const actualIndex = this.video_data_list.length + (index % this.video_data_list.length);
return this.video_data_list[actualIndex];
}
// 处理超出数组长度的索引
if (index >= this.video_data_list.length) {
// 循环到数组开头
const actualIndex = index % this.video_data_list.length;
return this.video_data_list[actualIndex];
}
// 正常情况直接返回
return this.video_data_list[index];
},
// 更新显示数据
update_display_data() {
let list = [];
// 如果当前索引为0只显示当前元素和下一个元素
if (this.current_index == 0) {
list = [
this.get_video_by_index(this.current_video_index),
this.get_video_by_index(this.current_video_index + 1), // 下一个元素
this.get_video_by_index(this.current_video_index - 1) // 上一个元素,
];
} else if (this.current_index == 1) { // 索引为1时为确保无限轮播正常需要改变数据插入顺序
list = [
this.get_video_by_index(this.current_video_index - 1),
this.get_video_by_index(this.current_video_index),
this.get_video_by_index(this.current_video_index + 1)
];
} else {
list = [
this.get_video_by_index(this.current_video_index + 1),
this.get_video_by_index(this.current_video_index - 1),
this.get_video_by_index(this.current_video_index),
];
}
this.setData({
display_video_list: list
})
},
// 评论输入框事件
comment_input_event(e) {
this.comment_input_value = e.detail.value;
},
comment_input_change(e) {
const { type } = e.currentTarget.dataset;
if (type == 'image') {
var self = this;
uni.chooseImage({
count: self.propMaxNum,
success(res) {
var success = 0;
var fail = 0;
var length = res.tempFilePaths.length;
var count = 0;
self.upload_one_by_one(res.tempFilePaths, success, fail, count, length, 'uploadimage');
},
});
}
},
// 采用递归的方式上传多张
upload_one_by_one(img_paths, success, fail, count, length, action) {
var self = this;
if (self.form_images_list.length <= this.propMaxNum) {
uni.uploadFile({
url: app.globalData.get_request_url('index', 'ueditor'),
filePath: img_paths[count],
name: 'upfile',
formData: {
action: action,
path_type: self.propPathType,
},
success: function (res) {
success++;
if (res.statusCode == 200) {
var data = typeof res.data == 'object' ? res.data : JSON.parse(res.data);
if (data.code == 0 && (data.data.url || null) != null) {
var list = self.form_images_list;
list.push({
url: data.data.url,
name: data.data.original,
size: data.data.size,
});
self.setData({
form_images_list: list,
});
self.$emit('call-back', self.form_images_list, self.propCallData);
} else {
app.globalData.showToast(data.msg);
}
}
},
fail: function (e) {
console.log(e);
fail++;
},
complete: function (e) {
count++;
// 下一张
if (count >= length) {
// 上传完毕,作一下提示
//app.showToast('上传成功' + success +'张', 'success');
} else {
// 递归调用,上传下一张
self.upload_one_by_one(img_paths, success, fail, count, length, action);
}
},
});
}
},
// 上传图片预览
upload_show_event(e) {
uni.previewImage({
current: this.form_images_list[e.currentTarget.dataset.index].url,
urls: this.form_images_list.map(item => item.url),
});
},
// 评论输入图片删除
comment_input_img_close(e) {
const index = e?.currentTarget?.dataset?.index || 0;
var list = this.form_images_list;
list.splice(index, 1);
this.setData({
form_images_list: list,
});
},
on_transition(e) {
const dy = e.detail.dy;
let status = 'direction'
if (dy > 0) {
status = 'next'
} else if (dy < 0) {
status = 'prev'
}
// 如果历史的是向下滑动,这次也是向下滑动,就不更新数据
if (this.direction != status) {
this.setData({
direction: status,
})
}
},
// 切换播放暂停
toggle_play_pause() {
if (this.create_video_contexts[this.current_index] == null) return; // 当前播放的视频索引为1
this.setData({
paused: !this.paused
});
// 判断是否暂停
if (this.paused) {
this.create_video_contexts[this.current_index].pause(); // 暂停中间的视频
} else {
this.video_play_event(this.create_video_contexts[this.current_index], false); // 播放中间的视频
}
},
handle_play() {
this.setData({ paused: false });
},
// 收藏
handle_like(e) {
if (!app.globalData.is_single_page_check()) {
return false;
}
var user = app.globalData.get_user_info(this, 'handle_like', e);
if (user != false) {
const value = e?.currentTarget?.dataset?.value || {};
this.set_givethumbs_num(value.id);
}
},
// 打开评论区
handle_comment(e) {
const old_data = e?.currentTarget?.dataset?.value || '';
// 初始化评论数据
const new_data = old_data.comments_list.map(item1 => ({
...item1,
show_sub_comment: false,
show_sub_comment_loading: false,
page: 0,
sub_comments: [],
}));
this.setData({
active_comments: new_data,
comments_page: 1,
comments_page_total: 5,
comment_item_loading: false,
show_comment_modal: true,
move_distance: 0,
})
},
// 关闭评论区
close_comment_modal() {
this.setData({
active_dropdown_id: null,
show_comment_modal: false,
move_distance: 0,
})
},
// 评论滚动事件, 记录滚动位置
handle_comment_scroll(e) {
this.comment_scroll_top = e.detail.scrollTop;
},
// 评论滚动到底部事件
handle_comment_to_lower_scroll() {
if (this.goods_bottom_line_status) {
return;
}
this.comment_item_loading = true;
// 获取数据
uni.request({
url: app.globalData.get_request_url("commentsreplylist", "index", "video"),
method: 'POST',
data: {
video_id: this.current_video_id,
page: this.comments_page + 1,
video_comments_id: 0
},
dataType: 'json',
success: res => {
const data = res.data;
if (data.code == 0) {
const new_data = data.data;
if (new_data.data.length > 0) {
// 初始化评论数据
const comment_data = new_data.data.map(item1 => ({
...item1,
show_sub_comment: false,
show_sub_comment_loading: false,
page: 0,
sub_comments: [],
}));
this.active_comments.push(...comment_data);
}
// 是否显示没有更多数据
if (new_data.page >= new_data.page_total) {
// 没有更多数据了
this.setData({
goods_bottom_line_status: true,
})
}
this.comments_page = new_data.page;
this.comments_page_total = new_data.page_total
}
},
complete: () => {
this.comment_item_loading = false;
}
});
},
// 评论拖拽开始
handle_comment_touch_start(e) {
// 只有滚动到顶部时才允许拖拽
if (this.comment_scroll_top <= 5) {
this.comment_start_y = e.touches[0].pageY;
this.comment_current_y = this.comment_start_y;
this.move_distance = 0;
}
},
// 评论拖拽中
handle_comment_touch_move(e) {
// 只有滚动到顶部时才允许拖拽
if (this.comment_scroll_top <= 5) {
this.comment_current_y = e.touches[0].pageY;
this.move_distance = this.comment_current_y - this.comment_start_y;
}
},
// 评论拖拽结束
handle_comment_touch_end(e) {
// 只有滚动到顶部时才允许拖拽
if (this.comment_scroll_top <= 5) {
const move_distance = this.comment_current_y - this.comment_start_y;
// 如果拖拽距离足够大,关闭评论弹窗
if (move_distance > 150) {
this.close_comment_modal();
} else {
this.move_distance = 0;
}
}
},
send_comment() {
let comment_text = this.comment_input_value;
if (!comment_text.trim()) return;
// video_id 视频id video_comments_id 父级评论id id 当前评论id
let new_video_comments_id = 0;
let reply_comments_id = 0
if (!isEmpty(this.comments_data)) {
const { video_comments_id, id } = this.comments_data;
new_video_comments_id = video_comments_id == 0 ? id : video_comments_id;
reply_comments_id = video_comments_id == 0 ? 0 : id;
}
uni.request({
url: app.globalData.get_request_url("comments", "index", "video"),
method: 'POST',
data: {
video_id: this.current_video_id,
video_comments_id: new_video_comments_id, // 如果父级评论id为0说明没有父级id所以取当前id
reply_comments_id: reply_comments_id, // 如果父级评论id为0说明没有父级id所以回复id为0
content: comment_text,
images: this.form_images_list.length > 0 ? this.form_images_list[0].url : '',
},
dataType: 'json',
success: res => {
const data = res.data;
if (data.code == 0) {
const new_data = data.data;
// 没有回复时的评论
if (new_video_comments_id == 0) {
this.active_comments.unshift({
...new_data,
show_sub_comment: false,
show_sub_comment_loading: false,
page: 0,
sub_comments: [],
})
this.video_data_list.forEach(item => {
if (item.id == this.current_video_id) {
item.comments_count++;
}
})
this.setData({
video_data_list: this.video_data_list,
comment_scroll_top: 0 + Math.random() // 添加主评论时滚动到最顶部
})
} else {
this.active_comments.forEach(item => {
if (item.id == new_video_comments_id) {
item.sub_comments.unshift(new_data);
item.comments_count++;
}
})
}
// 清空输入框, 更新数据内容
this.setData({
active_comments: this.active_comments,
form_images_list: [],
comment_input_value: '',
comments_data: {},
input_placeholder: '请输入您的精彩评论',
});
} else {
if (app.globalData.is_login_check(res.data)) {
app.globalData.showToast(res.data.msg);
} else {
app.globalData.showToast(this.$t('common.sub_error_retry_tips'));
}
}
}
});
},
// 展开子评论
open_sub_comment(id, is_level) {
const comment = this.active_comments.find(item => item.id == id);
if (comment) {
comment.show_sub_comment = true;
comment.show_sub_comment_loading = true;
// 如果是一级,并且有子评论数据,不需要调用接口,直接渲染评论信息
if (is_level == 1 && !isEmpty(comment.sub_comments)) {
comment.show_sub_comment_loading = false;
return;
}
uni.request({
url: app.globalData.get_request_url("commentsreplylist", "index", "video"),
method: 'POST',
data: {
video_id: this.current_video_id,
video_comments_id: id,
page: comment.page + 1,
},
dataType: 'json',
success: res => {
const data = res.data;
if (data.code == 0) {
const new_data = data.data;
if (new_data.data.length > 0) {
comment.sub_comments.push(...new_data.data);
}
comment.page = new_data.page;
comment.page_total = new_data.page_total
}
},
complete: () => {
comment.show_sub_comment_loading = false;
}
});
}
},
// 收起子评论
close_sub_comment(id) {
const comment = this.active_comments.find(item => item.id == id);
if (comment) {
comment.show_sub_comment = false;
}
},
handle_share() {
if ((this.$refs.share || null) != null) {
this.$refs.share.init({
status: true,
share_info: this.share_info,
});
}
},
// 更新视频数据信息
get_video_data_detail(id) {
uni.request({
url: app.globalData.get_request_url("data", "index", "video"),
method: 'POST',
data: {
id: id,
},
dataType: 'json',
success: res => {
const data = res.data;
if (data.code == 0) {
const new_data = data.data;
// 更新视频数据
this.video_data_list.forEach(item => {
if (item.id == id) {
const new_item = {
...item,
...new_data,
};
item = new_item;
}
});
this.setData({
video_data_list: this.video_data_list
})
}
}
});
},
// 更新点赞数量
set_givethumbs_num(id, comments_id) {
uni.request({
url: app.globalData.get_request_url("givethumbs", "index", "video"),
method: 'POST',
data: {
video_id: id,
...(isEmpty(comments_id) ? {} : {video_comments_id: comments_id}),
},
dataType: 'json',
success: res => {
const data = res.data;
if (data.code == 0) {
const new_data = data.data;
// 提取更新点赞状态的公共函数
const updateThumbsStatus = (target, new_data) => {
target.give_thumbs_count = new_data.count;
target.is_give_thumbs = new_data.is_active;
};
// 优化后的遍历逻辑
for (let i = 0; i < this.video_data_list.length; i++) {
const item = this.video_data_list[i];
if (item.id == id) {
if (!isEmpty(comments_id)) {
// 安全检查comments数组是否存在
if (this.active_comments && Array.isArray(this.active_comments)) {
for (let j = 0; j < this.active_comments.length; j++) {
const comment = this.active_comments[j];
if (comment.id == comments_id) {
updateThumbsStatus(comment, new_data);
return; // 找到后直接返回
} else {
// 安全检查sub_comments数组是否存在
if (comment.sub_comments && Array.isArray(comment.sub_comments)) {
for (let k = 0; k < comment.sub_comments.length; k++) {
const sub_comment = comment.sub_comments[k];
if (sub_comment.id == comments_id) {
updateThumbsStatus(sub_comment, new_data);
return; // 找到后直接返回
}
}
}
}
}
}
} else {
updateThumbsStatus(item, new_data);
}
break; // 处理完当前item后跳出外层循环
}
}
this.setData({
video_data_list: this.video_data_list
})
} else {
if (app.globalData.is_login_check(res.data)) {
app.globalData.showToast(res.data.msg);
} else {
app.globalData.showToast(this.$t('common.sub_error_retry_tips'));
}
}
}
});
},
handle_time_update(e) {
if (this.is_seeking) return;
let duration = this.current_video_duration;
// #ifdef MP-ALIPAY
if (e.detail.videoDuration > 0) {
duration = e.detail.videoDuration;
}
// #endif
// #ifndef MP-ALIPAY
if (e.detail.duration > 0) {
duration = e.detail.duration;
}
// #endif
this.setData({
current_video_duration: duration,
current_video_progress: e.detail.currentTime,
});
},
handle_slider_changing() {
this.is_seeking = true;
},
// 主评论回复
comment_reply(comments) {
this.active_dropdown_id = null;
if (!isEmpty(comments)) {
this.setData({
comments_data: comments,
});
}
},
comment_data_delete() {
this.setData({
comments_data: {},
});
},
// 评论点赞
comment_like(id) {
this.active_dropdown_id = null;
this.set_givethumbs_num(this.current_video_id, id);
},
handle_slider_change(e) {
const seek_time = e.detail.value;
if (this.create_video_contexts[this.current_index]) {
this.create_video_contexts[this.current_index].seek(seek_time);
this.setData({
current_video_progress: seek_time,
})
}
setTimeout(() => {
this.is_seeking = false;
}, 100);
},
format_time(seconds) {
if (isNaN(seconds) || seconds < 0) {
return '00:00';
}
const min = Math.floor(seconds / 60);
const sec = Math.floor(seconds % 60);
return `${min < 10 ? '0' : ''}${min}:${sec < 10 ? '0' : ''}${sec}`;
},
handle_back() {
app.globalData.page_back_prev_event();
},
handle_search() {
// 跳转到搜索记录页面
app.globalData.url_open(`/pages/plugins/video/search/search-record`, false);
},
// 关闭推荐商品
product_close_event(e) {
const id = e?.currentTarget?.dataset?.id || '';
this.video_data_list.forEach((item) => {
if (item.id == id) {
item.show_goods = false;
}
});
this.setData({
video_data_list: this.video_data_list
})
},
handle_product_card_item(e) {
const id = e?.currentTarget?.dataset?.id || '';
const data = this.video_data_list.find(item => item.id == id);
if (!isEmpty(data) && !isEmpty(data.goods)) {
app.globalData.url_open(data.goods.goods_url);
}
},
handle_product_button(e) {
const id = e.currentTarget.dataset.id;
this.video_data_list.forEach((item, index) => {
if (item.id == id) {
if (item.show_goods && !isEmpty(item.goods)) {
app.globalData.url_open(item.goods.goods_url);
} else {
item.show_goods = true;
}
}
});
this.setData({
video_data_list: this.video_data_list
})
},
// 清理所有视频资源
cleanup_all_videos() {
try {
// 暂停所有视频
this.pause_all_videos_except(-1);
// 清空视频上下文数组
this.create_video_contexts = [];
this.video_contexts = [];
console.log('视频资源清理完成');
} catch (error) {
console.error('清理视频资源时出错:', error);
}
},
// 处理下拉菜单切换
handle_toggle_dropdown(comment_id) {
// 如果点击的是同一个组件,则切换状态;否则关闭其他组件并打开当前组件
if (this.active_dropdown_id == comment_id) {
this.active_dropdown_id = null;
} else {
this.active_dropdown_id = comment_id;
}
},
// 关闭下拉菜单
handle_dropdown_item_click(comment_id, obj) {
if (this.active_dropdown_id == comment_id) {
this.active_dropdown_id = null;
}
// 处理不同操作
if (obj.type == 'delete') {
// 确认删除
uni.showModal({
title: '确认删除',
content: '确定删除此评论吗?',
success: (res) => {
if (res.confirm) {
// 调用删除接口
this.delete_comment(comment_id);
}
}
});
} else if (obj.type == 'report') {
// 举报评论
this.popup_report_status = true;
this.report_comment_id = comment_id;
}
},
// 删除评论
delete_comment(comment_id) {
uni.request({
url: app.globalData.get_request_url("delete", "index", "video"),
method: 'POST',
data: {
ids: comment_id,
},
dataType: 'json',
success: res => {
const data = res.data;
if (data.code == 0) {
// 删除评论数据
this.delete_comment_handle(comment_id);
// 显示删除成功提示
app.globalData.showToast(this.$t('common.del_success'));
} else {
if (app.globalData.is_login_check(res.data)) {
app.globalData.showToast(res.data.msg);
} else {
app.globalData.showToast(this.$t('common.sub_error_retry_tips'));
}
}
}
});
},
delete_comment_handle(comment_id) {
// 删除成功从active_comments中移除对应数据
if (this.active_comments && Array.isArray(this.active_comments)) {
// 创建新的数组来存储过滤后的结果
const filteredComments = [];
// 遍历所有评论
for (let i = 0; i < this.active_comments.length; i++) {
const comment = this.active_comments[i];
// 如果是父级评论且id匹配跳过整个评论包括子评论
if (comment.id == comment_id) {
continue;
}
// 检查是否有子评论需要删除
if (comment.sub_comments && Array.isArray(comment.sub_comments)) {
// 过滤掉匹配的子评论
const filteredSubComments = comment.sub_comments.filter(
subComment => subComment.id != comment_id
);
// 如果还有子评论或者本身就是有效的父级评论,则保留
if (filteredSubComments.length > 0 || comment.content) {
// 更新子评论数组
comment.sub_comments = filteredSubComments;
filteredComments.push(comment);
}
// 更新显示的评论数
comment.comments_count = filteredSubComments.length;
} else {
// 没有子评论的情况,直接保留父级评论
filteredComments.push(comment);
}
}
// 删除之后更新评论数据
this.video_data_list.forEach(item => {
if (item.id == this.current_video_id) {
item.comments_count = filteredComments.length;
}
})
// 更新数据
this.setData({
active_comments: filteredComments,
video_data_list: this.video_data_list
})
}
},
// 处理全局点击事件
handle_global_click(e) {
// 检查点击目标是否在下拉菜单相关元素内
const target = e.target || e.srcElement;
// 查找点击元素是否在comment-option或dropdown-menu内
let isInDropdown = false;
let currentElement = target;
while (currentElement && currentElement !== document) {
// 检查是否点击了下拉菜单触发器或菜单本身
if (currentElement.classList &&
(currentElement.classList.contains('comment-option') ||
currentElement.classList.contains('dropdown-menu') ||
currentElement.closest('.comment-option') ||
currentElement.closest('.dropdown-menu'))) {
isInDropdown = true;
break;
}
currentElement = currentElement.parentNode;
}
// 如果点击的不是下拉菜单相关元素,则关闭所有下拉菜单
if (!isInDropdown && this.active_dropdown_id !== null) {
this.active_dropdown_id = null;
}
},
// 关闭举报弹窗
popup_close_event() {
this.setData({
popup_report_status: false,
current_main_index: 0,
current_sub_index: 0,
});
},
// 新的举报弹窗相关方法
onMain_reasonChange(e) {
const value = parseInt(e.detail.value);
this.setData({
current_main_index: value,
current_sub_index: -1,
});
},
onSub_reasonChange(e) {
const value = parseInt(e.detail.value);
if (this.current_main_index >= 0) {
this.setData({
current_sub_index: value,
});
}
},
// 直接选择主原因(用于一行显示的点击)
select_main_reason(e) {
const index = e?.currentTarget?.dataset?.index || 0;
const main_index = parseInt(index);
if (main_index !== this.current_main_index) {
this.setData({
current_main_index: main_index,
current_sub_index: 0, // 默认选中第一个子类型
});
}
},
// 直接选择子类型(用于一行显示的点击)
select_sub_reason(e) {
const index = e?.currentTarget?.dataset?.index || 0;
const sub_index = parseInt(index);
if (sub_index !== this.current_sub_index) {
this.setData({
current_sub_index: sub_index,
});
}
},
submit_report() {
// 获取选中的举报原因和具体类型
const main_reason = this.report_type_list[this.current_main_index];
const sub_reason = main_reason.data[this.current_sub_index];
// 调用举报接口
uni.request({
url: app.globalData.get_request_url("report", "index", "video"),
method: 'POST',
data: {
id: this.report_comment_id,
reason: main_reason.name,
type: sub_reason
},
dataType: 'json',
success: res => {
const data = res.data;
if (data.code == 0) {
// 显示删除成功提示
app.globalData.showToast('举报成功');
// 关闭弹窗
this.close_report_popup();
} else {
if (app.globalData.is_login_check(res.data)) {
app.globalData.showToast(res.data.msg);
} else {
app.globalData.showToast(this.$t('common.sub_error_retry_tips'));
}
}
}
});
},
add_comment() {
//#ifndef H5
this.is_add_comment = true;
this.active_dropdown_id = null;
//#endif
},
/**
* 键盘高度变化监听处理
* @param {Object} res - 键盘高度变化事件对象
*/
listener(res) {
console.log(res);
// 减1是为了兼容避免跟键盘之间会不连贯
if (res.height > 0) {
this.listener_height = res.height - 1;
} else {
this.listener_height = 0;
}
},
/**
* 绑定键盘高度变化监听事件
*/
bind_keyboard_listener() {
uni.onKeyboardHeightChange(this.listener);
},
/**
* 解绑键盘高度变化监听事件
*/
unbind_keyboard_listener() {
uni.offKeyboardHeightChange(this.listener);
},
}
};
</script>
<style lang="scss" scoped>
.mt-10 {
margin-top: 20rpx;
}
.ml-10 {
margin-left: 20rpx;
}
.content,
.swiper-container {
width: 100%;
height: 100vh;
}
.video {
width: 100%;
height: 100%;
}
.video-container {
position: relative;
width: 100%;
height: 100%;
}
.play-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
.play-icon-bg {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #fff;
width: 60rpx;
height: 60rpx;
z-index: 0;
}
.play-icon-iconfont {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
.right-actions {
position: absolute;
right: 20rpx;
bottom: 200rpx;
display: flex;
flex-direction: column;
align-items: center;
color: #fff;
z-index: 10;
}
.action-item {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 40rpx;
}
.user-avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
border: 4rpx solid #fff;
}
.icon {
width: 70rpx;
height: 70rpx;
}
.action-text {
font-size: 28rpx;
margin-top: 10rpx;
}
.product-card {
position: absolute;
width: 440rpx;
bottom: 180rpx;
left: 30rpx;
color: #fff;
z-index: 99;
.product-card-item {
background: #DDDDDD;
padding: 16rpx;
border-radius: 8rpx;
}
.product-image {
width: 100rpx;
height: 100rpx;
}
.product-name {
font-weight: 500;
font-size: 28rpx;
color: #333333;
line-height: 40rpx;
}
.product-price {
font-weight: 500;
font-size: 32rpx;
color: #FF1919;
line-height: 44rpx;
}
.product-close {
position: absolute;
right: -10rpx;
top: -14rpx;
}
.product-button {
display: flex;
align-items: center;
justify-content: space-between;
width: 300rpx;
height: 88rpx;
padding: 0 20rpx;
background: rgba(40, 40, 40, 0.45);
border-radius: 88rpx;
border: 2rpx solid rgba(151, 151, 151, 0.53);
cursor: pointer;
}
}
.author {
font-size: 36rpx;
font-weight: bold;
}
::v-deep .uni-video-container {
background: transparent;
}
.video-bg {
position: absolute;
top: 0;
left: 0;
z-index: -1;
width: 100%;
height: 100%;
background: #000;
background-size: cover;
background-position: center;
transform: scale(3);
filter: blur(100rpx);
opacity: 0.7;
}
.video-mask {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
background: transparent;
}
.video-content {
display: block;
font-size: 30rpx;
margin-top: 16rpx;
max-width: 70%;
}
.progress-bar-container {
position: absolute;
bottom: 60rpx;
left: 20rpx;
right: 20rpx;
display: flex;
align-items: center;
z-index: 11;
}
.progress-slider {
flex: 1;
margin: 0 20rpx;
}
.time-display {
color: #fff;
font-size: 24rpx;
text-shadow: 2rpx 2rpx 2rpx rgba(0, 0, 0, 0.6);
width: 180rpx;
text-align: right;
}
/* 评论弹窗样式 */
.comment-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 99;
display: flex;
justify-content: center;
align-items: flex-end;
}
.comment-content {
width: 100%;
height: 70%;
background-color: #fff;
border-top-left-radius: 30rpx;
border-top-right-radius: 30rpx;
display: flex;
flex-direction: column;
transition: transform 0.3s ease;
}
.comment-header {
padding: 30rpx;
box-sizing: border-box;
border-bottom: 2rpx solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
}
.comment-count {
font-weight: bold;
font-size: 32rpx;
}
.close-btn {
font-size: 40rpx;
color: #999;
}
.comment-list {
flex: 1;
overflow: hidden;
.comment-scroll {
width: 100%;
height: 100%;
padding: 30rpx;
box-sizing: border-box;
}
}
.comment-item {
margin-bottom: 30rpx;
}
.sub-comment {
margin-left: 100rpx;
}
.sub-comment-list {
gap: 40rpx;
}
.comment-input-container {
display: flex;
padding: 20rpx;
border-top: 2rpx solid #eee;
}
.comment-input {
flex: 1;
font-size: 28rpx;
height: 50rpx;
padding: 16rpx;
box-sizing: content-box;
}
.comment-input-content {
flex: 1;
border: 2rpx solid #eee;
border-radius: 16rpx;
// padding-right: 16rpx;
font-size: 28rpx;
}
.pr-16 {
padding-right: 16rpx;
}
.comment-input-img-container {
padding: 10rpx 16rpx 16rpx 16rpx;
}
.comment-input-img-close {
position: absolute;
right: -15rpx;
top: -15rpx;
z-index: 2;
}
.comment-input-img {
width: 50rpx;
height: 50rpx;
}
/* 新的举报弹窗样式 */
.report-content {
width: 100%;
max-width: 750rpx;
background-color: #fff;
border-radius: 20rpx;
}
.report-header {
padding: 30rpx 40rpx;
border-bottom: 1rpx solid #ddd;
background-color: #fff;
}
.report-btn {
font-size: 32rpx;
color: #333;
}
.report-title {
font-size: 36rpx;
font-weight: bold;
text-align: center;
color: #333;
}
.report-body {
padding: 30rpx 40rpx;
}
.report-section {
margin-bottom: 30rpx;
}
.report-label {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 20rpx;
color: #333;
}
.report-label text {
color: #e74c3c;
font-size: 30rpx;
vertical-align: middle;
}
// 搜索
.header-top {
padding-left: 12px;
box-sizing: border-box;
position: absolute;
top: 0;
left: 0;
z-index: 9;
width: 100%;
}
.header-top {
::v-deep .search-bar {
background:#D8D8D8;
opacity: 0.27;
border-color: transparent;
}
}
.keyboard-input {
position: fixed;
left: 0;
z-index: 99;
background: #fff;
padding: 20rpx;
box-sizing: border-box;
}
.keyboard-input-border {
border: 2rpx solid #ddd;
border-radius: 16rpx;
}
.keyboard-input-content {
padding: 16rpx 22rpx;
}
.comment-reply-content {
background-color: rgba(0, 0, 0, 0.6);
padding: 10rpx;
border-radius: 16rpx;
color: #fff;
}
</style>