2114 lines
112 KiB
Plaintext
2114 lines
112 KiB
Plaintext
<template>
|
||
<view :class="theme_view" :style="width_height_style">
|
||
<view v-if="display_video_list && display_video_list.length > 0" class="content pr" :style="width_height_style">
|
||
<!-- 视频列表 -->
|
||
<swiper class="swiper-container" :key="'top-or-buttom-' + swiper_key" :style="width_height_style + swiperStyle" :duration="300" :vertical="true" :circular="false" :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" :style="width_height_style">
|
||
<view class="pr" @tap.stop="toggle_play_pause" :style="width_height_style" @touchstart.prevent="handle_swiper_touch_start" @touchmove.prevent="handle_swiper_touch_move" @touchend="handle_swiper_touch_end">
|
||
<view class="video-bg" :style="(!isEmpty(video_item.cover) ? 'background-image: url(' + video_item.cover + ')' : '') + width_height_style"></view>
|
||
|
||
<video class="video" :style="width_height_style + swiperStyle" :src="video_item.video_url" :poster="video_item.cover" :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" @tap.stop="toggle_play_pause"></video>
|
||
|
||
<view v-if="paused && current_index == index" class="play-icon" :style="width_height_style + swiperStyle">
|
||
<view class="flex-1 pr flex-row align-c jc-c">
|
||
<view class="play-icon-bg"></view>
|
||
<view class="pa z-i">
|
||
<u-icon propName="bofang" propSize="120rpx" propColor="#4F3E35"></u-icon>
|
||
</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-id="video_item.id" @tap.stop="handle_like">
|
||
<u-icon propName="givealike" propSize="60rpx" :propColor="video_item.is_give_thumbs == 0 ? '#fff' : '#F4B73F'"></u-icon>
|
||
<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-id="video_item.id" @tap.stop="handle_comment">
|
||
<u-icon propName="comment" propSize="60rpx" propColor="#fff"></u-icon>
|
||
<text class="action-text">{{ video_item.comments_count }}</text>
|
||
</view>
|
||
<view class="action-item" @tap.stop="handle_share">
|
||
<u-icon propName="share-solid" propSize="60rpx" propColor="#fff"></u-icon>
|
||
<text class="action-text">{{$t('common.share')}}</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">
|
||
<view v-if="video_item.show_goods" class="flex-row align-c product-card-item" style="margin-bottom: 20rpx;" :data-id="video_item.id" @tap.stop="handle_product_card_item">
|
||
<view style="width: 100rpx;height:100rpx;">
|
||
<image :src="video_item.goods.images" mode="aspectFill" style="width: 100rpx;height:100rpx;"></image>
|
||
</view>
|
||
<view class="flex-1 flex-col align-sb jc-c" style="margin-left: 20rpx;">
|
||
<text class="product-name text-line-1" style="margin-bottom: 20rpx;">{{ 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">
|
||
<u-icon propName="close" propSize="50rpx" propColor="#999"></u-icon>
|
||
</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">
|
||
<u-icon propName="cart-have" propSize="30rpx" propColor="#F5C366"></u-icon>
|
||
<text class="size-14 cr-f" style="margin-left: 20rpx;">{{$t('common.buy')}} {{$t('common.goods')}}</text>
|
||
</view>
|
||
<u-icon propName="angle-right" propSize="30rpx" propColor="#fff"></u-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- Progress Bar -->
|
||
<view class="progress-bar-container" v-if="current_index == index" :style="'width: ' + (windowWidth - 20) + 'px'">
|
||
<slider class="flex-1 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>
|
||
<!-- 搜索框 -->
|
||
<view v-if="!show_comment_modal" class="header-top" :style="top_content_style + menu_button_info + ' width: ' + windowWidth + 'px;'">
|
||
<view id="search-height" class="flex-row align-c">
|
||
<!-- 支付宝小程序自带返回按钮,这里就不给返回按钮了,这里给留出一点空间就行 -->
|
||
<!-- #ifndef MP-ALIPAY -->
|
||
<view class="cp" @tap="handle_back">
|
||
<u-icon propName="arrow-left" propSize="36rpx" propColor="#333" class="mr-10"></u-icon>
|
||
</view>
|
||
<!-- #endif -->
|
||
<view class="flex-1" :style="header_padding_left">
|
||
<search-component propIsDisabled @disabledSearch="handle_search" :propsWidth="windowWidth" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<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" :style="width_height_style">
|
||
<view class="comment-content bottom-line-exclude-bottom" @tap.stop :style="commentContentStyle">
|
||
<view class="comment-header" data-type="header" @tap.stop @touchstart.prevent="handle_comment_touch_start" @touchmove.prevent="handle_comment_touch_move" @touchend="handle_comment_touch_end">
|
||
<text class="comment-count">{{$t('common.comment')}}</text>
|
||
<view class="close-btn" @tap="close_comment_modal">✕</view>
|
||
</view>
|
||
<view class="flex-1 flex-row oh" :style="'width:' + windowWidth + 'px;'" data-type="scroll" @tap.stop @touchstart.prevent="handle_comment_touch_start" @touchmove.prevent="handle_comment_touch_move" @touchend="handle_comment_touch_end">
|
||
<!-- 评论内容区域 -->
|
||
<!-- <scroll-view class="flex-1 comment-list flex-row" scroll-y :scroll-top="comment_scroll_top" show-scrollbar="false" scroll-with-animation :scroll-with-touch="!is_dragging" @scrolltolower="handle_comment_to_lower_scroll" @scroll="handle_comment_scroll"> -->
|
||
<list class="comment-list comment-scroll" :show-scrollbar="false" :scrollable="!is_dragging" loadmoreoffset="100" @scroll="handle_comment_scroll" @loadmore="handle_comment_to_lower_scroll">
|
||
<template v-if="active_comments && active_comments.length > 0">
|
||
<cell v-for="(comment_item, index) in active_comments" :key="comment_item.id">
|
||
<view class="comment-item flex-col">
|
||
<commentInfoComponent :style="window_more_style" :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 mt-10">
|
||
<view v-if="comment_item.sub_comments && Array.isArray(comment_item.sub_comments) && comment_item.sub_comments.length > 0 && comment_item.show_sub_comment" style="margin-buttom: 20rpx;" class="sub-comment-list flex-col jc-c">
|
||
<view v-for="(sub_comment_item, sub_comment_index) in comment_item.sub_comments" :key="sub_comment_index" class="sub-comment-item flex-row align-s" style="margin-bottom: 20rpx;">
|
||
<commentInfoComponent :style="window_sub_more_style" :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 :style="window_more_style" :propId="comment_item.id" :propIsLevel="1" :propText="'—— '+ $t('common.expand') + (comment_item.comments_count ? comment_item.comments_count || 0 : 0) + $t('ask-comments.ask-comments.ymmd24')" @comment_more_event="open_sub_comment"></commentMoreComponent>
|
||
</template>
|
||
<template v-else>
|
||
<template v-if="comment_item.show_sub_comment_loading">
|
||
<loading-component :style="window_more_style"></loading-component>
|
||
</template>
|
||
<view v-else class="sub-comment-more flex-row align-c gap-10">
|
||
<template v-if="comment_item.page != null && comment_item.page < comment_item.page_total">
|
||
<commentMoreComponent :style="window_more_style" :propId="comment_item.id" :propIsLevel="2" :propText="$t('common.expand')" @comment_more_event="open_sub_comment"></commentMoreComponent>
|
||
</template>
|
||
<commentMoreComponent :style="window_more_style" :propId="comment_item.id" :propText="$t('common.retract')" propIconName="arrow-top" @comment_more_event="close_sub_comment"></commentMoreComponent>
|
||
</view>
|
||
</template>
|
||
</template>
|
||
</view>
|
||
</view>
|
||
</cell>
|
||
<template v-if="comment_item_loading">
|
||
<cell>
|
||
<view class="flex-row align-c jc-c" :style="window_more_style">
|
||
<loading-component></loading-component>
|
||
</view>
|
||
</cell>
|
||
</template>
|
||
<template v-else>
|
||
<cell>
|
||
<!-- 结尾 -->
|
||
<component-bottom-line :propStatus="goods_bottom_line_status"></component-bottom-line>
|
||
</cell>
|
||
</template>
|
||
</template>
|
||
<template v-else>
|
||
<cell>
|
||
<component-no-data :propMsg="$t('common.no_data')"></component-no-data>
|
||
</cell>
|
||
</template>
|
||
<!-- </view> -->
|
||
</list>
|
||
</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_reply_data)" class="comment-reply-content flex-row align-c jc-sb gap-10">
|
||
<text class="size-12 cr-f text-line-1">@{{ isEmpty(comments_reply_data.user) ? '' : comments_reply_data.user.user_name_view }}:{{ comments_reply_data.content }}</text>
|
||
<view data-type="image" @tap="comment_data_delete">
|
||
<u-icon propName="close-line" propSize="24rpx" propColor="#fff"></u-icon>
|
||
</view>
|
||
</view>
|
||
<view class="flex-row align-c wh-auto ht-auto pr-16 box-border-box" :style="window_more_style">
|
||
<input :value="comment_input_value" class="comment-input" style="margin-right: 20rpx;" type="text" confirm-type="send" :adjust-position="false" :placeholder="$t('video-detail.video-detail.98yyuf')" @focus="add_comment" @input="comment_input_event" @confirm="send_comment" />
|
||
<component-upload :propMaxNum="1" :propPathType="editor_path_type" propSlot propSingleCall propIsAllInfo @call-back="upload_images_event">
|
||
<u-icon propName="layout-module-single-images" propSize="32rpx" propColor="#999"></u-icon>
|
||
</component-upload>
|
||
</view>
|
||
<view v-if="form_images_list && 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">
|
||
<u-icon propName="close" propSize="10" propColor="#000" class="comment-input-img-close" :data-index="index" @tap="comment_input_img_close"></u-icon>
|
||
<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>
|
||
|
||
<!-- 举报弹窗 -->
|
||
<u-popup ref="popupReportRef" propMode="bottom" propCloseType="text" :propWidth="'width:' + windowWidth + 'px;'" propTitleBorder class="pointer-events-auto" :propTitle="$t('video-detail.video-detail.rfsdfg')" :propCloseable="true" @close="popup_report_close_event" @callBack="submit_report">
|
||
<view class="report-content">
|
||
<!-- 主要内容区域 -->
|
||
<view class="report-body">
|
||
<!-- 第一层:举报原因选择 -->
|
||
<view v-if="report_type_list && report_type_list.length > 0" class="report-section">
|
||
<view class="report-label flex-row align-c">{{$t('video-detail.video-detail.rfsdfg')}}<text class="ml-10 report-required">*</text></view>
|
||
<view class="flex-row align-c flex-wrap">
|
||
<radio-group class="flex-row align-c flex-wrap" :style="window_more_style">
|
||
<view v-for="(mainItem, main_index) in report_type_list" :key="main_index" class="flex-row align-c" style="margin-right: 20rpx;" :data-index="main_index" @tap.stop="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)" />
|
||
<text class="flex-row align-c">{{mainItem.name}}</text>
|
||
</view>
|
||
</view>
|
||
</radio-group>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 第二层:具体类型选择(当有主类别选中时显示) -->
|
||
<view class="report-section mt-20" v-if="current_main_index >= 0 && report_type_list[current_main_index] && report_type_list[current_main_index].data">
|
||
<view class="report-label flex-row align-c">{{$t('video-detail.video-detail.fsdf33')}}<text class="ml-10 report-required">*</text></view>
|
||
<view class="flex-row align-c flex-wrap">
|
||
<radio-group class="flex-row align-c flex-wrap" :style="window_more_style">
|
||
<view v-for="(subItem, sub_index) in report_type_list[current_main_index].data" :key="sub_index" class="flex-row align-c" style="margin-right: 20rpx;" :data-index="sub_index" @tap.stop="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>
|
||
</radio-group>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-popup>
|
||
<!-- 添加评论弹出框 -->
|
||
<view v-if="is_add_comment" class="keyboard-input br-top-shadow" :style="'width:'+ windowWidth +'px;bottom:' + listener_height + 'px;'">
|
||
<view class="comment-input-content flex-col jc-c">
|
||
<view v-if="!isEmpty(comments_reply_data)" class="comment-reply-content flex-row align-c jc-sb gap-10">
|
||
<text class="size-12 cr-f text-line-1">@{{ comments_reply_data.user.user_name_view }}:{{ comments_reply_data.content }}</text>
|
||
<view data-type="image" @tap="comment_data_delete">
|
||
<u-icon propName="close-line" propSize="24rpx" propColor="#fff"></u-icon>
|
||
</view>
|
||
</view>
|
||
<view class="flex-row align-c wh-auto ht-auto pr-16 box-border-box" :style="window_more_style">
|
||
<input :value="comment_input_value" :focus="is_add_comment" class="comment-input" style="margin-right: 20rpx;" 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" />
|
||
<component-upload :propMaxNum="1" :propPathType="editor_path_type" propSlot propSingleCall propIsAllInfo @call-back="upload_images_event">
|
||
<u-icon propName="layout-module-single-images" propSize="48rpx" propColor="#999"></u-icon>
|
||
</component-upload>
|
||
</view>
|
||
<view v-if="form_images_list && 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">
|
||
<u-icon propName="close" propSize="10" propColor="#000" class="comment-input-img-close" :data-index="index" @tap="comment_input_img_close"></u-icon>
|
||
<image :src="item.url" :data-index="index" @tap="upload_show_event" mode="aspectFill" class="wh-auto ht-auto"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 分享弹窗 -->
|
||
<u-share-popup ref="share" class="pointer-events-auto"></u-share-popup>
|
||
|
||
<!-- 公共 -->
|
||
<!-- <component-common ref="common"></component-common> -->
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
const app = getApp();
|
||
import { get_math, isEmpty, video_get_top_left_padding, showToast } 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 componentNoData from '@/components/no-data/no-data';
|
||
import componentBottomLine from '@/components/bottom-line/bottom-line';
|
||
import componentPopup from '@/components/popup/popup';
|
||
import componentUpload from '@/components/upload/upload';
|
||
import componentCommon from '@/components/common/common';
|
||
// 多语言
|
||
//#ifdef APP-NVUE
|
||
import i18n from '@/locale/index.js';
|
||
// nvue页面在方法中使用时的处理
|
||
import { initVueI18n } from '@dcloudio/uni-i18n';
|
||
import indexNvue from '@/locale/index-nvue.js';
|
||
const { t } = initVueI18n(indexNvue)
|
||
//#endif
|
||
// 状态栏高度
|
||
var bar_height = parseInt(app.globalData.get_system_info('statusBarHeight', 0));
|
||
// #ifdef MP-TOUTIAO || H5
|
||
bar_height = 0;
|
||
// #endif
|
||
export default {
|
||
//#ifdef APP-NVUE
|
||
i18n,
|
||
//#endif
|
||
data() {
|
||
return {
|
||
theme_view: app.globalData.get_theme_value_view(),
|
||
top_content_style: 'padding-top:' + bar_height + 'px;padding-bottom:10px;',
|
||
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, // 评论拖拽距离
|
||
is_dragging: false, // 是否正在拖拽中
|
||
current_video_id: '', // 当前播放视频的 ID
|
||
is_slide_start: false,
|
||
swiper_key: get_math(),
|
||
comment_scroll_top: 0, // 评论滚动距离顶部的距离
|
||
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, // 视频清理定时器
|
||
comment_scroll_debounce_timer: null, // 评论滚动防抖定时器
|
||
comment_move_throttle_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_value: '',
|
||
is_add_comment: false,
|
||
|
||
// 监听键盘高度变化事件
|
||
listener_height: 0,
|
||
comments_reply_data: {},
|
||
editor_path_type: 'video',
|
||
is_manual_pause: false, // 是否手动暂停
|
||
windowWidth: 0,
|
||
windowHeight: 0,
|
||
padding_width: 0,
|
||
sub_comment_padding_left: 0,
|
||
// 视频滚动
|
||
swiper_start_y: 0,
|
||
swiper_current_y: 0,
|
||
swiper_move_distance: 0,
|
||
swiper_move_throttle_timer: null,
|
||
};
|
||
},
|
||
components: {
|
||
commentInfoComponent,
|
||
commentMoreComponent,
|
||
searchComponent,
|
||
componentNoData,
|
||
componentBottomLine,
|
||
componentPopup,
|
||
loadingComponent,
|
||
componentUpload,
|
||
componentCommon
|
||
},
|
||
computed: {
|
||
// 视频列表高度
|
||
swiperStyle() {
|
||
return this.show_comment_modal ? (this.move_distance > 0 ? `height: ${Math.round(this.windowHeight * 0.3) + this.move_distance}px;` : `height: ${Math.round(this.windowHeight * 0.3)}px;`) : `height: ${this.windowHeight}px;`;
|
||
},
|
||
// 评论内容区域高度
|
||
commentContentStyle() {
|
||
const baseHeight = Math.round(this.windowHeight * 0.7);
|
||
return this.show_comment_modal && this.move_distance > 0
|
||
? `transform: translateY(3px); width:${this.windowWidth}px; height: ${baseHeight - 10 - this.move_distance}px;`
|
||
: `transform: translateY(0); width:${this.windowWidth}px; height: ${baseHeight + 10}px;`;
|
||
},
|
||
// 当前播放视频的索引
|
||
current_video_index() {
|
||
if (this.video_data_list && this.video_data_list.length > 0) {
|
||
return this.video_data_list.findIndex(item => item.id == this.current_video_id);
|
||
} else {
|
||
return -1;
|
||
}
|
||
},
|
||
close_circular() {
|
||
try {
|
||
if (this.video_data_list && 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
|
||
}
|
||
} catch {
|
||
console.log('close_circular');
|
||
}
|
||
},
|
||
width_height_style() {
|
||
return `width: ${ this.windowWidth }px;height: ${ this.windowHeight }px;`;
|
||
},
|
||
window_more_style() {
|
||
return `width: ${ this.windowWidth - this.padding_width }px;`
|
||
},
|
||
window_sub_more_style() {
|
||
return `width: ${ this.windowWidth - this.sub_comment_padding_left }px;`
|
||
}
|
||
},
|
||
onLoad(params) {
|
||
try {
|
||
// 调用公共事件方法
|
||
app.globalData.page_event_onload_handle(params);
|
||
|
||
// 设置参数
|
||
this.params = app.globalData.launch_params_handle(params);
|
||
} catch {
|
||
console.log('close_circular');
|
||
}
|
||
},
|
||
|
||
onShow() {
|
||
try {
|
||
const data = uni.getWindowInfo();
|
||
this.windowWidth = data.windowWidth > 800 ? 800 : data.windowWidth;
|
||
this.windowHeight = data.windowHeight;
|
||
// 调用公共事件方法
|
||
app.globalData.page_event_onshow_handle();
|
||
|
||
// 视频播放
|
||
if (!this.is_manual_pause && this.create_video_contexts && this.create_video_contexts[this.current_index]) {
|
||
this.video_play_event(this.create_video_contexts[this.current_index]);
|
||
}
|
||
|
||
// 公共onshow事件
|
||
if ((this.$refs.common || null) != null) {
|
||
this.$refs.common.on_show();
|
||
}
|
||
|
||
// 分享菜单处理
|
||
app.globalData.page_share_handle();
|
||
} catch {
|
||
console.log('close_circular');
|
||
}
|
||
},
|
||
|
||
onHide() {
|
||
// 清理定时器
|
||
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();
|
||
},
|
||
mounted() {
|
||
try {
|
||
// 初始化
|
||
this.init();
|
||
|
||
// #ifdef H5
|
||
// 添加全局点击事件监听
|
||
document.addEventListener('click', this.handle_global_click);
|
||
// 添加触摸事件监听(移动端兼容)
|
||
document.addEventListener('touchstart', this.handle_global_click);
|
||
//#endif
|
||
|
||
// 创建监听事件
|
||
this.bind_keyboard_listener();
|
||
} catch {
|
||
console.log('close_circular');
|
||
}
|
||
},
|
||
beforeDestroy() {
|
||
// 清理定时器
|
||
if (this.video_switch_debounce_timer) {
|
||
clearTimeout(this.video_switch_debounce_timer);
|
||
}
|
||
if (this.video_cleanup_timer) {
|
||
clearTimeout(this.video_cleanup_timer);
|
||
}
|
||
if (this.comment_scroll_debounce_timer) {
|
||
clearTimeout(this.comment_scroll_debounce_timer);
|
||
}
|
||
if (this.comment_move_throttle_timer) {
|
||
clearTimeout(this.comment_move_throttle_timer);
|
||
}
|
||
if (this.video_move_throttle_timer) {
|
||
clearTimeout(this.video_move_throttle_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() {
|
||
try {
|
||
// 小程序下,获取小程序胶囊的宽度
|
||
let menu_button_info = `max-width:${ this.windowWidth }px;`;
|
||
// #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(${ this.windowWidth } - ${custom.width + 10}px);`;
|
||
}
|
||
// #endif
|
||
// #endif
|
||
// 视频详情页,需要添加 padding-left
|
||
let padding_left = '';
|
||
// #ifdef MP-ALIPAY
|
||
padding_left = video_get_top_left_padding();
|
||
// #endif
|
||
this.padding_width = app.globalData.rpx_to_px(30);
|
||
this.sub_comment_padding_left = app.globalData.rpx_to_px(80);
|
||
|
||
this.header_padding_left = padding_left;
|
||
this.menu_button_info = menu_button_info;
|
||
this.current_video_id = isEmpty(this.current_video_id) ? this.params.id : this.current_video_id;
|
||
|
||
this.get_video_detail(this.current_video_id);
|
||
} catch (error) {
|
||
console.error('init error:', error);
|
||
}
|
||
},
|
||
/*
|
||
* 获取视频详情
|
||
* @param {*} id 视频 id
|
||
*/
|
||
get_video_detail(id) {
|
||
try {
|
||
// 获取数据
|
||
uni.request({
|
||
url: app.globalData.get_request_url("detail", "index", "video"),
|
||
method: 'POST',
|
||
data: {
|
||
id: id
|
||
},
|
||
dataType: 'json',
|
||
success: res => {
|
||
try {
|
||
const data = res.data;
|
||
if (data.code == 0) {
|
||
const new_data = data.data;
|
||
// 数据更新
|
||
this.data_list_loding_status = 3;
|
||
this.video_data_list = [new_data.data];
|
||
this.report_type_list = new_data.report_type_list;
|
||
this.base_config_data = new_data.base_config_data;
|
||
this.editor_path_type = new_data.editor_path_type;
|
||
|
||
this.get_last_or_next_data_list(this.params.id, 1, 1);
|
||
} else {
|
||
this.data_list_loding_status = 0;
|
||
this.data_tabs_loding_msg = data.msg;
|
||
}
|
||
} catch {
|
||
console.error('get_video_detail error:', error);
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
this.data_list_loding_status = 2;
|
||
this.data_list_loding_msg = t('common_internet_error_tips');
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('get_video_detail error:', error);
|
||
}
|
||
},
|
||
/*
|
||
* 获取视频列表
|
||
* @param {*} id 视频 id
|
||
* @param {*} is_last 是否获取上一批数据
|
||
* @param {*} is_next 是否获取下一批数据
|
||
*/
|
||
get_last_or_next_data_list(id, is_last = 0, is_next = 0) {
|
||
try {
|
||
// 获取数据
|
||
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();
|
||
this.video_data_list.forEach(item => {
|
||
existing_ids.set(item.id, true);
|
||
});
|
||
|
||
if (is_last == 1 && is_next == 1) {
|
||
// 上一批数据 - 去重处理
|
||
if (new_data.last && new_data.last.length > 0) {
|
||
const unique_last = new_data.last.filter(item => !existing_ids.has(item.id));
|
||
if (unique_last.length > 0) {
|
||
this.video_data_list.unshift(...unique_last);
|
||
// 更新 ID 映射表
|
||
unique_last.forEach(item => existing_ids.set(item.id, true));
|
||
}
|
||
}
|
||
// 下一批数据 - 去重处理
|
||
if (new_data.next && new_data.next.length > 0) {
|
||
const unique_next = new_data.next.filter(item => !existing_ids.has(item.id));
|
||
if (unique_next.length > 0) {
|
||
this.video_data_list.push(...unique_next);
|
||
}
|
||
}
|
||
} else if (is_last == 1 && new_data.last && new_data.last.length > 0) { // 上一页数据 - 去重处理
|
||
const unique_last = new_data.last.filter(item => !existing_ids.has(item.id));
|
||
if (unique_last.length > 0) {
|
||
this.video_data_list.unshift(...unique_last);
|
||
}
|
||
} else if (is_next == 1 && new_data.next && new_data.next.length > 0) { // 下一页数据 - 去重处理
|
||
const unique_next = new_data.next.filter(item => !existing_ids.has(item.id));
|
||
if (unique_next.length > 0) {
|
||
this.video_data_list.push(...unique_next);
|
||
}
|
||
}
|
||
// 更新当前视频商品信息
|
||
const new_index = this.video_data_list.findIndex(item => item.id == this.params.id);
|
||
// 处理当前视频商品信息
|
||
this.video_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.video_data_list = this.video_data_list;
|
||
this.$set(this, 'video_data_list', this.video_data_list);
|
||
// 逻辑说明:当是最后一个视频且需要播放下一个时,根据数组长度和新索引计算新的当前索引
|
||
// - 数组长度 > 2 时:新索引是最后一个元素则返回 2,是倒数第二个则返回 1,否则返回 0
|
||
// - 数组长度 <= 2 时:返回 length - 1
|
||
this.current_index = is_last == 1 && is_next == 1 ? this.calculate_new_index(this.video_data_list.length, new_index) : this.current_index;
|
||
|
||
if (is_last == 1 && is_next == 1) {
|
||
setTimeout(() => {
|
||
// 更新显示数据数据信息
|
||
this.update_display_data();
|
||
|
||
setTimeout(() => {
|
||
|
||
if (this.display_video_list && this.display_video_list.length > 0) {
|
||
// 更新分享信息
|
||
this.update_share_info(this.display_video_list[this.current_index]);
|
||
console.log(this.display_video_list.length);
|
||
this.display_video_list.forEach((item, index) => {
|
||
// this.create_video_contexts[index] = uni.createVideoContext(`video_${index}`, this);
|
||
this.$set(this.create_video_contexts, index, uni.createVideoContext(`video_${index}`, this));
|
||
//#ifdef H5
|
||
if (document.getElementById(`video_${index}`) != null && this.video_contexts) {
|
||
// this.video_contexts[index] = document.getElementById(`video_${index}`).querySelector('video');
|
||
this.$set(this.video_contexts, index, document.getElementById(`video_${index}`).querySelector('video'));
|
||
}
|
||
//#endif
|
||
});
|
||
}
|
||
|
||
//#ifdef H5
|
||
if (this.video_contexts && this.video_contexts[this.current_index]) { // 当前播放的视频索引为 0
|
||
this.video_play_event(this.video_contexts[this.current_index], true);
|
||
}
|
||
//#endif
|
||
//#ifndef H5
|
||
if (this.create_video_contexts && this.create_video_contexts[this.current_index]) { // 当前播放的视频索引为 0
|
||
this.video_play_event(this.create_video_contexts[this.current_index], true);
|
||
}
|
||
//#endif
|
||
}, 200);
|
||
}, 100);
|
||
}
|
||
}
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('get_last_or_next_data_list error:', error);
|
||
}
|
||
},
|
||
/**
|
||
* 计算新的视频索引
|
||
* 当是最后一个视频且需要播放下一个时,根据数组长度和新索引计算新的当前索引
|
||
* @param {number} listLength - 视频列表长度
|
||
* @param {number} newIndex - 新视频在列表中的索引
|
||
* @returns {number} 计算后的新索引
|
||
*/
|
||
calculate_new_index(listLength, newIndex) {
|
||
try {
|
||
// 边界处理:空数组
|
||
if (listLength === 0) {
|
||
return 0;
|
||
}
|
||
|
||
// 数组长度 <= 2 时,返回最后一个索引
|
||
if (listLength <= 2) {
|
||
return listLength - 1;
|
||
}
|
||
|
||
// 数组长度 > 2 时,根据新索引位置返回对应值
|
||
// 新索引是最后一个元素 -> 返回 2
|
||
if (newIndex === listLength - 1) {
|
||
return 2;
|
||
}
|
||
// 新索引是倒数第二个元素 -> 返回 1
|
||
if (newIndex === listLength - 2) {
|
||
return 1;
|
||
}
|
||
// 其他情况 -> 返回 0
|
||
return 0;
|
||
} catch (error) {
|
||
console.error('calculate_new_index error:', error);
|
||
}
|
||
},
|
||
// 视频拖拽开始
|
||
handle_swiper_touch_start(e) {
|
||
try {
|
||
// 如果是滚动区域内滚动到顶部才可以拖拽,如果是头部拖拽的话,一直都可以
|
||
this.swiper_start_y = e?.touches[0]?.pageY || 0;
|
||
this.swiper_current_y = this.swiper_start_y;
|
||
this.swiper_move_distance = 0;
|
||
} catch (error) {
|
||
console.error('handle_swiper_touch_start error:', error);
|
||
}
|
||
},
|
||
// 视频拖拽中
|
||
handle_swiper_touch_move(e) {
|
||
try {
|
||
// 阻止默认行为,防止页面滚动干扰
|
||
if (e.preventDefault) {
|
||
e.preventDefault();
|
||
}
|
||
|
||
const current_y = e?.touches[0]?.pageY || 0;
|
||
const distance = current_y - this.swiper_start_y;
|
||
|
||
// 只有向下移动且距离超过阈值(10px)才开始拖拽,避免误触和抖动
|
||
if (Math.abs(distance) > 10) {
|
||
this.swiper_current_y = current_y;
|
||
|
||
// 使用节流控制 move_distance 的更新频率,避免计算属性频繁触发导致抖动
|
||
if (this.swiper_move_throttle_timer) {
|
||
return;
|
||
}
|
||
|
||
this.move_distance = distance;
|
||
|
||
// 设置节流定时器,16ms 约等于 60fps,保证流畅度同时避免过度更新
|
||
this.swiper_move_throttle_timer = setTimeout(() => {
|
||
this.swiper_move_throttle_timer = null;
|
||
}, 80);
|
||
}
|
||
} catch(error) {
|
||
console.error('handle_swiper_touch_move error:', error);
|
||
}
|
||
},
|
||
// 视频拖拽结束
|
||
handle_swiper_touch_end(e) {
|
||
try {
|
||
const move_distance = this.swiper_current_y - this.swiper_start_y;
|
||
// 判断滑动方向:向下为正,向上为负
|
||
if (Math.abs(move_distance) > (this.windowHeight * 0.3)) {
|
||
// 只有滑动距离超过屏幕高度的 15% 才触发切换
|
||
if (move_distance > 0) {
|
||
// 向下滑动,切换到上一个视频
|
||
this.handle_swiper_change_by_direction('prev');
|
||
} else {
|
||
// 向上滑动,切换到下一个视频
|
||
this.handle_swiper_change_by_direction('next');
|
||
}
|
||
} else {
|
||
// 滑动距离不够,重置位置
|
||
this.swiper_move_distance = 0;
|
||
}
|
||
|
||
// 清理节流定时器
|
||
if (this.swiper_move_throttle_timer) {
|
||
clearTimeout(this.swiper_move_throttle_timer);
|
||
this.swiper_move_throttle_timer = null;
|
||
}
|
||
|
||
// 重置拖拽状态
|
||
this.swiper_start_y = 0;
|
||
this.swiper_current_y = 0;
|
||
} catch (error) {
|
||
console.error('handle_swiper_touch_end error:', error);
|
||
}
|
||
},
|
||
|
||
// 根据滑动方向切换视频
|
||
handle_swiper_change_by_direction(direction) {
|
||
try {
|
||
let new_index = this.current_index;
|
||
if (direction === 'prev') {
|
||
// 向下滑动,切换到上一个
|
||
if (this.current_video_index <= 0) {
|
||
app.globalData.showToast('已经是第一个视频了');
|
||
return;
|
||
} else {
|
||
new_index = this.current_index - 1 < 0 ? 2 : (this.current_index - 1);
|
||
}
|
||
} else if (direction === 'next') {
|
||
// 向上滑动,切换到下一个
|
||
if (this.current_video_index >= this.video_data_list.length - 1) {
|
||
app.globalData.showToast('已经是最后一个视频了');
|
||
return;
|
||
} else {
|
||
console.log('new_index', this.current_index);
|
||
new_index = this.current_index + 1 > 2 ? 0 : (this.current_index + 1);
|
||
}
|
||
}
|
||
console.log('new_index', new_index);
|
||
// 创建模拟的 event 对象
|
||
const mockEvent = {
|
||
detail: {
|
||
current: new_index
|
||
}
|
||
};
|
||
|
||
// 调用原有的处理逻辑
|
||
this.handle_swiper_change(mockEvent);
|
||
} catch (error) {
|
||
console.error('handle_swiper_change_by_direction error:', error);
|
||
}
|
||
},
|
||
// 视频滚动处理逻辑(带防抖)
|
||
handle_swiper_change(event) {
|
||
try {
|
||
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);
|
||
}, 100); // 100ms 防抖延迟
|
||
} catch (error) {
|
||
console.error('handle_swiper_change error:', error);
|
||
}
|
||
},
|
||
|
||
// 实际的 swiper 切换处理逻辑
|
||
process_swiper_change(current) {
|
||
try {
|
||
// 先暂停所有视频,确保不会有后台播放
|
||
this.pause_all_videos_except(current);
|
||
|
||
const id = this?.display_video_list[current]?.id || '';
|
||
// 更新状态
|
||
this.current_index = current;
|
||
this.paused = false;
|
||
this.is_manual_pause = false;
|
||
this.current_video_progress = 0;
|
||
this.current_video_duration = 1;
|
||
this.is_seeking = false;
|
||
this.current_video_id = id; // 更新当前播放视频的ID
|
||
|
||
//#ifdef H5
|
||
// 使用URLSearchParams处理当前查询参数
|
||
const url = new URL(location.href);
|
||
url.searchParams.set('id', id);
|
||
// 替换URL路径,保持查询参数不变
|
||
const pathname = location.href?.split('?')[0] || '';
|
||
history.replaceState(null, '', pathname + url.search);
|
||
//#endif
|
||
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.update_video_list([0, 1, 2]);
|
||
|
||
this.is_slide_start = false;
|
||
this.current_index = 0;
|
||
// this.swiper_key = get_math();
|
||
// 刷新数据
|
||
this.update_display_video_list(list);
|
||
} else if (this.current_video_index == this.video_data_list.length - 1) {
|
||
const list = this.update_video_list([-2, -1, 0]);
|
||
this.current_index = list.length - 1;
|
||
// this.swiper_key = get_math();
|
||
// 刷新数据
|
||
this.update_display_video_list(list);
|
||
} else {
|
||
this.is_slide_start = true;
|
||
// this.swiper_key = get_math();
|
||
this.update_display_data();
|
||
}
|
||
// 更新分享信息
|
||
this.update_share_info(this.display_video_list[current]);
|
||
this.swiper_key = get_math();
|
||
// 延迟播放当前视频,确保DOM更新完成
|
||
setTimeout(() => {
|
||
this.play_current_video_safely(this.current_index);
|
||
}, 150);
|
||
} catch (error) {
|
||
console.error('process_swiper_change error:', error);
|
||
}
|
||
},
|
||
update_video_list(offsets) {
|
||
try {
|
||
let list = [];
|
||
for (let i = 0; i < offsets.length; i++) {
|
||
const targetIndex = this.current_video_index + offsets[i];
|
||
if (targetIndex >= 0 && targetIndex < this.video_data_list.length) {
|
||
list.push(this.get_video_by_index(targetIndex));
|
||
}
|
||
}
|
||
return list;
|
||
} catch (error) {
|
||
console.error('update_video_list error:', error);
|
||
}
|
||
},
|
||
|
||
// 批量暂停除指定索引外的所有视频
|
||
pause_all_videos_except(exceptIndex) {
|
||
try {
|
||
if (this.create_video_contexts && this.create_video_contexts.length > 0) {
|
||
// 暂停 uni.createVideoContext 创建的视频
|
||
this.create_video_contexts.forEach((context, index) => {
|
||
if (index !== exceptIndex && context) {
|
||
try {
|
||
context.pause();
|
||
} catch (error) {
|
||
console.warn(`暂停视频 ${index} 失败:`, error);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('pause_all_videos_except error:', error);
|
||
}
|
||
},
|
||
|
||
// 安全播放当前视频
|
||
play_current_video_safely(index) {
|
||
try {
|
||
// 优先使用 uni.createVideoContext
|
||
if (this.create_video_contexts && this.create_video_contexts[index]) {
|
||
this.video_play_event(this.create_video_contexts[index]);
|
||
return;
|
||
}
|
||
} catch (error) {
|
||
console.error('play_current_video_safely error:', error);
|
||
}
|
||
},
|
||
|
||
// 切换播放暂停
|
||
toggle_play_pause(e) {
|
||
try {
|
||
const currentIndex = this.current_index;
|
||
// 检查视频上下文是否存在
|
||
const videoContext = this.create_video_contexts[currentIndex] || this.video_contexts[currentIndex];
|
||
if (!videoContext) {
|
||
console.warn(`当前索引 ${currentIndex} 无可用视频上下文`);
|
||
e.stopPropagation();
|
||
return;
|
||
}
|
||
|
||
this.paused = !this.paused;
|
||
this.is_manual_pause = !this.paused;
|
||
|
||
if (this.paused) {
|
||
// 暂停当前视频
|
||
try {
|
||
videoContext.pause();
|
||
} catch (error) {
|
||
e.stopPropagation();
|
||
console.warn('暂停视频失败:', error);
|
||
}
|
||
} else {
|
||
// 播放当前视频
|
||
this.video_play_event(videoContext);
|
||
}
|
||
e.stopPropagation();
|
||
} catch (error) {
|
||
console.error('toggle_play_pause error:', error);
|
||
}
|
||
},
|
||
// 播放数组更新
|
||
update_display_video_list(list) {
|
||
try {
|
||
// 不理解为什么这里时undefined的
|
||
// 根据 weex 的通用做法,需要同时改变“引用”和“长度”两个维度才能被识别数组更新。
|
||
// 1. 先清空原数组(触发长度变化)
|
||
if (this.display_video_list && this.display_video_list.length > 0) {
|
||
this.display_video_list.splice(0, this.display_video_list.length)
|
||
} else {
|
||
this.display_video_list = [];
|
||
}
|
||
// this.display_video_list.splice(0, this.display_video_list.length, ...list);
|
||
|
||
// this.$nextTick(() => {
|
||
// setTimeout(() => {
|
||
// 2. 再把新数据 push 进去(触发内容变化)
|
||
list.forEach(item => this.display_video_list.push(item))
|
||
// }, 0);
|
||
// });
|
||
} catch (e) {
|
||
console.log('update_display_video_list', e);
|
||
}
|
||
},
|
||
|
||
// 更新分享信息
|
||
update_share_info(data) {
|
||
try {
|
||
const info = {
|
||
title: data?.title || '',
|
||
desc: data?.desc || '',
|
||
path: '/pages/plugins/video/detail/detail',
|
||
query: 'id=' + this.current_video_id,
|
||
img: data.cover || ''
|
||
}
|
||
this.share_info = info;
|
||
// 分享菜单处理
|
||
app.globalData.page_share_handle(info);
|
||
|
||
// 更新页面标题
|
||
uni.setNavigationBarTitle({title: data.title});
|
||
} catch (error) {
|
||
console.error('update_share_info error:', error);
|
||
}
|
||
},
|
||
|
||
// 安全的视频播放事件处理
|
||
video_play_event(videoContext, is_first_play = false) {
|
||
try {
|
||
if (!videoContext) {
|
||
this.paused = true;
|
||
this.is_manual_pause = false;
|
||
return;
|
||
}
|
||
|
||
try {
|
||
if (is_first_play) {
|
||
//#ifdef H5
|
||
videoContext.play().catch((error) => {
|
||
this.paused = true;
|
||
this.is_manual_pause = false;
|
||
});
|
||
//#endif
|
||
//#ifndef H5
|
||
videoContext.play();
|
||
//#endif
|
||
} else {
|
||
videoContext.play();
|
||
}
|
||
} catch (error) {
|
||
console.error('视频播放异常:', error);
|
||
this.paused = true;
|
||
this.is_manual_pause = false;
|
||
}
|
||
} catch (error) {
|
||
console.error('video_play_event error:', error);
|
||
}
|
||
},
|
||
// 安全获取视频数据的方法,处理索引超限情况
|
||
get_video_by_index(index) {
|
||
try {
|
||
// 处理负数索引
|
||
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];
|
||
} catch (error) {
|
||
console.error('get_video_by_index error:', error);
|
||
}
|
||
},
|
||
|
||
/*
|
||
* 更新显示的视频数据
|
||
*/
|
||
update_display_data() {
|
||
try {
|
||
let list = [];
|
||
// 如果当前索引为0,只显示当前元素和下一个元素
|
||
if (this.current_index == 0) {
|
||
if (this.current_video_index == 0) {
|
||
list = this.update_video_list([0, 1, 2]);
|
||
} else {
|
||
list = this.update_video_list([0, 1, -1]);
|
||
}
|
||
} else if (this.current_index == 1) { // 索引为1时,为确保无限轮播正常,需要改变数据插入顺序
|
||
list = this.update_video_list([-1, 0, 1]);
|
||
} else {
|
||
if (this.current_video_index == this.video_data_list.length - 1) {
|
||
list = this.update_video_list([-2, -1, 0]);
|
||
} else {
|
||
list = this.update_video_list([1, -1, 0]);
|
||
}
|
||
}
|
||
// 刷新数据
|
||
this.update_display_video_list(list);
|
||
} catch (error) {
|
||
console.error('update_display_data error:', error);
|
||
}
|
||
},
|
||
|
||
// 评论输入框事件
|
||
comment_input_event(e) {
|
||
try {
|
||
this.comment_input_value = e.detail.value;
|
||
} catch (error) {
|
||
console.error('comment_input_event error:', error);
|
||
}
|
||
},
|
||
|
||
// 图片上传回调
|
||
upload_images_event(res) {
|
||
try {
|
||
if((res || null) != null) {
|
||
// 存储上传图片内容
|
||
this.form_images_list.push({
|
||
url: res.url,
|
||
name: res.name,
|
||
size: res.size,
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('upload_images_event error:', error);
|
||
}
|
||
},
|
||
|
||
// 上传图片预览
|
||
upload_show_event(e) {
|
||
try {
|
||
const index = e?.currentTarget?.dataset?.index || 0;
|
||
uni.previewImage({
|
||
current: this?.form_images_list[index]?.url || '',
|
||
urls: this.form_images_list.map(item => item.url),
|
||
});
|
||
} catch (error) {
|
||
console.error('upload_show_event error:', error);
|
||
}
|
||
},
|
||
|
||
// 评论输入图片删除
|
||
comment_input_img_close(e) {
|
||
try {
|
||
const index = e?.currentTarget?.dataset?.index || 0;
|
||
var list = this.form_images_list;
|
||
list.splice(index, 1);
|
||
// 图片赋值
|
||
this.form_images_list = list;
|
||
} catch (error) {
|
||
console.error('comment_input_img_close error:', error);
|
||
}
|
||
},
|
||
|
||
// swiper-item 的位置发生改变时
|
||
on_transition(e) {
|
||
try {
|
||
const dy = e.detail.dy;
|
||
let status = 'direction';
|
||
if (dy > 0) {
|
||
status = 'next';
|
||
} else if (dy < 0) {
|
||
status = 'prev';
|
||
}
|
||
// 如果历史的是向下滑动,这次也是向下滑动,就不更新数据
|
||
if (this.direction != status) {
|
||
this.direction = status;
|
||
}
|
||
} catch (error) {
|
||
console.error('on_transition error:', error);
|
||
}
|
||
},
|
||
|
||
// 播放
|
||
handle_play() {
|
||
try {
|
||
this.paused = false;
|
||
this.is_manual_pause = false;
|
||
} catch (error) {
|
||
console.error('handle_play error:', error);
|
||
}
|
||
},
|
||
|
||
// 收藏
|
||
handle_like(e) {
|
||
try {
|
||
if (!app.globalData.is_single_page_check()) {
|
||
return false;
|
||
}
|
||
var user = app.globalData.get_user_info(this, 'handle_like', e);
|
||
if (user != false) {
|
||
// const id = e?.currentTarget?.dataset?.id || '';
|
||
this.set_givethumbs_num(this.current_video_id);
|
||
}
|
||
} catch (error) {
|
||
console.error('handle_like error:', error);
|
||
}
|
||
},
|
||
// 打开评论区
|
||
handle_comment(e) {
|
||
try {
|
||
e.stopPropagation();
|
||
// const id = this.current_video_id;
|
||
const old_data = this.video_data_list.find(item => item.id == this.current_video_id);
|
||
if (old_data && old_data.comments_list) {
|
||
// 初始化评论数据
|
||
const new_data = old_data.comments_list.map(item1 => ({
|
||
...item1,
|
||
show_sub_comment: false,
|
||
show_sub_comment_loading: false,
|
||
page: 0,
|
||
sub_comments: [],
|
||
}));
|
||
this.active_comments = new_data;
|
||
this.comments_page = 1;
|
||
this.comments_page_total = 5;
|
||
this.comment_item_loading = false;
|
||
this.show_comment_modal = true;
|
||
this.move_distance = 0;
|
||
this.is_dragging = false; // 重置拖拽状态
|
||
this.comment_start_y = 0; // 重置起始位置
|
||
this.comment_current_y = 0; // 重置当前位置
|
||
this.comment_scroll_top = 0 + Math.random(); // 滚动到最顶部
|
||
}
|
||
} catch (error) {
|
||
console.error('handle_comment error:', error);
|
||
}
|
||
},
|
||
// 关闭评论区
|
||
close_comment_modal(e) {
|
||
try {
|
||
this.active_dropdown_id = null;
|
||
this.show_comment_modal = false;
|
||
this.comment_scroll_top = 0 + Math.random(); // 关闭评论时滚动到最顶部
|
||
this.comments_reply_data = {}; // 清空回复评论数据
|
||
this.form_images_list = []; // 清空上传图片
|
||
this.comment_input_value = ''; // 清空输入框内容
|
||
this.move_distance = 0;
|
||
this.is_dragging = false; // 重置拖拽状态
|
||
this.comment_start_y = 0; // 重置起始位置
|
||
this.comment_current_y = 0; // 重置当前位置
|
||
|
||
// 清理节流定时器
|
||
if (this.comment_move_throttle_timer) {
|
||
clearTimeout(this.comment_move_throttle_timer);
|
||
this.comment_move_throttle_timer = null;
|
||
}
|
||
} catch (error) {
|
||
console.error('close_comment_modal error:', error);
|
||
}
|
||
},
|
||
// 评论滚动事件,记录滚动位置(带防抖)
|
||
handle_comment_scroll(e) {
|
||
try {
|
||
// 清除之前的防抖定时器
|
||
if (this.comment_scroll_debounce_timer) {
|
||
clearTimeout(this.comment_scroll_debounce_timer);
|
||
}
|
||
// 设置新的防抖定时器
|
||
this.comment_scroll_debounce_timer = setTimeout(() => {
|
||
this.comment_scroll_top = Math.abs(e.contentOffset.y);
|
||
}, 100); // 100ms防抖延迟
|
||
} catch (error) {
|
||
console.error('handle_comment_scroll error:', error);
|
||
}
|
||
},
|
||
// 评论滚动到底部事件
|
||
handle_comment_to_lower_scroll() {
|
||
try {
|
||
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.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;
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('handle_comment_to_lower_scroll error:', error);
|
||
}
|
||
},
|
||
// 评论拖拽开始
|
||
handle_comment_touch_start(e) {
|
||
try {
|
||
const type = e?.target?.dataset?.type || 'header';
|
||
// 如果是滚动区域内滚动到顶部才可以拖拽,如果是头部拖拽的话,一直都可以
|
||
if ((this.comment_scroll_top <= 5 && type == 'scroll') || type == 'header') {
|
||
this.comment_start_y = e?.touches[0]?.pageY || 0;
|
||
this.comment_current_y = this.comment_start_y;
|
||
this.move_distance = 0;
|
||
this.is_dragging = false; // 开始时不设置为拖拽状态,需要移动一定距离后才算拖拽
|
||
}
|
||
} catch (error) {
|
||
console.error('handle_comment_touch_start error:', error);
|
||
}
|
||
},
|
||
// 评论拖拽中
|
||
handle_comment_touch_move(e) {
|
||
try {
|
||
const type = e?.target?.dataset?.type || 'header';
|
||
// 如果是滚动区域内滚动到顶部才可以拖拽,如果是头部拖拽的话,一直都可以
|
||
if ((this.comment_scroll_top <= 5 && type == 'scroll') || type == 'header') {
|
||
// 阻止默认行为,防止页面滚动干扰
|
||
if (e.preventDefault) {
|
||
e.preventDefault();
|
||
}
|
||
|
||
const current_y = e?.touches[0]?.pageY || 0;
|
||
const distance = current_y - this.comment_start_y;
|
||
|
||
// 只有向下移动且距离超过阈值(30px)才开始拖拽,避免误触和抖动
|
||
if (distance > 10) {
|
||
this.is_dragging = true;
|
||
this.comment_current_y = current_y;
|
||
|
||
// 使用节流控制 move_distance 的更新频率,避免计算属性频繁触发导致抖动
|
||
if (this.comment_move_throttle_timer) {
|
||
return;
|
||
}
|
||
|
||
this.move_distance = distance;
|
||
|
||
// 设置节流定时器,16ms 约等于 60fps,保证流畅度同时避免过度更新
|
||
this.comment_move_throttle_timer = setTimeout(() => {
|
||
this.comment_move_throttle_timer = null;
|
||
}, 80);
|
||
}
|
||
}
|
||
} catch(error) {
|
||
console.error('handle_comment_touch_move error:', error);
|
||
}
|
||
},
|
||
// 评论拖拽结束
|
||
handle_comment_touch_end(e) {
|
||
try {
|
||
const type = e?.target?.dataset?.type || 'header';
|
||
// 如果是滚动区域内滚动到顶部才可以拖拽,如果是头部拖拽的话,一直都可以
|
||
if ((this.comment_scroll_top <= 5 && type == 'scroll') || type == 'header') {
|
||
const move_distance = this.comment_current_y - this.comment_start_y;
|
||
// 如果拖拽距离足够大,关闭评论弹窗
|
||
if (move_distance > 150) {
|
||
this.close_comment_modal();
|
||
} else {
|
||
this.move_distance = 0;
|
||
}
|
||
this.is_dragging = false; // 拖拽结束,重置状态
|
||
|
||
// 清理节流定时器
|
||
if (this.comment_move_throttle_timer) {
|
||
clearTimeout(this.comment_move_throttle_timer);
|
||
this.comment_move_throttle_timer= null;
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('handle_comment_touch_end error:', error);
|
||
}
|
||
},
|
||
// 评论
|
||
send_comment() {
|
||
try {
|
||
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_reply_data)) {
|
||
const { video_comments_id, id } = this.comments_reply_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.video_data_list = this.video_data_list;
|
||
this.$set(this, 'video_data_list', this.video_data_list)
|
||
this.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++;
|
||
if (!item.show_sub_comment) {
|
||
item.show_sub_comment = true;
|
||
// 如果回复总数跟当前显示的数量对得上,就不显示展开. 如果之前没有页面时,设置页数和分页都为1, 否则保持之前的分页
|
||
item.page = item.comments_count == item.sub_comments.length ? (!isEmpty(item.page) && item.page > 0 ? item.page : 1) : 0;
|
||
// 如果之前没有数据时,设置总页数为1
|
||
item.page_total = !isEmpty(item.page_total) ? item.page_total : 1;
|
||
}
|
||
}
|
||
})
|
||
}
|
||
// 清空输入框,更新数据内容
|
||
this.active_comments = this.active_comments;
|
||
this.form_images_list = [];
|
||
this.comment_input_value = '';
|
||
this.comments_reply_data = {};
|
||
} else {
|
||
if (app.globalData.is_login_check(res.data)) {
|
||
app.globalData.showToast(res.data.msg);
|
||
} else {
|
||
app.globalData.showToast(t('common_sub_error_retry_tips'));
|
||
}
|
||
}
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('send_comment error:', error);
|
||
}
|
||
},
|
||
// 展开子评论
|
||
open_sub_comment(id, is_level) {
|
||
try {
|
||
console.log(id);
|
||
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 (comment.page == 0) {
|
||
comment.sub_comments = new_data.data;
|
||
} else 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;
|
||
}
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('open_sub_comment error:', error);
|
||
}
|
||
},
|
||
|
||
// 收起子评论
|
||
close_sub_comment(id) {
|
||
try {
|
||
const comment = this.active_comments.find(item => item.id == id);
|
||
if (comment) {
|
||
comment.show_sub_comment = false;
|
||
}
|
||
} catch (error) {
|
||
console.error('close_sub_comment error:', error);
|
||
}
|
||
},
|
||
|
||
// 分享事件
|
||
handle_share() {
|
||
try {
|
||
if ((this.$refs.share || null) != null) {
|
||
this.$refs.share.init({
|
||
status: true,
|
||
share_info: this.share_info,
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('handle_share error:', error);
|
||
}
|
||
},
|
||
// 更新视频数据信息
|
||
get_video_data_detail(id) {
|
||
try {
|
||
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;
|
||
// 更新视频数据
|
||
const index = this.video_data_list.findIndex(item => item.id == id);
|
||
if (index !== -1) {
|
||
// 使用Object.assign更新原对象,保持引用不变
|
||
Object.assign(this.video_data_list[index], {
|
||
...this.video_data_list[index],
|
||
...new_data.data
|
||
});
|
||
}
|
||
}
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('get_video_data_detail error:', error);
|
||
}
|
||
},
|
||
|
||
// 更新点赞数量
|
||
set_givethumbs_num(id, comments_id) {
|
||
try {
|
||
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.video_data_list = this.video_data_list;
|
||
this.$set(this, '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(t('common_sub_error_retry_tips'));
|
||
}
|
||
}
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('set_givethumbs_num error:', error);
|
||
}
|
||
},
|
||
// 主评论回复
|
||
comment_reply(comments) {
|
||
try {
|
||
this.active_dropdown_id = null;
|
||
if (!isEmpty(comments)) {
|
||
this.comments_reply_data = comments;
|
||
}
|
||
} catch (error) {
|
||
console.error('comment_reply error:', error);
|
||
}
|
||
},
|
||
// 删除回复评论数据
|
||
comment_data_delete() {
|
||
try {
|
||
this.comments_reply_data = {};
|
||
} catch (error) {
|
||
console.error('comment_data_delete error:', error);
|
||
}
|
||
},
|
||
// 播放进度变化时触发
|
||
handle_time_update(e) {
|
||
try {
|
||
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.$nextTick(() => {
|
||
// this.current_video_duration = duration;
|
||
// this.current_video_progress = e.detail.currentTime;
|
||
// })
|
||
this.$set(this, 'current_video_duration', duration);
|
||
this.$set(this, 'current_video_progress', e.detail.currentTime)
|
||
} catch (error) {
|
||
console.error('handle_time_update error:', error);
|
||
}
|
||
},
|
||
// 视频进度条拖动时触发事件
|
||
handle_slider_changing() {
|
||
try {
|
||
this.is_seeking = true;
|
||
e.stopPropagation();
|
||
} catch (error) {
|
||
console.error('handle_slider_changing error:', error);
|
||
}
|
||
},
|
||
// 评论点赞
|
||
comment_like(id) {
|
||
try {
|
||
this.active_dropdown_id = null;
|
||
this.set_givethumbs_num(this.current_video_id, id);
|
||
} catch (error) {
|
||
console.error('comment_like error:', error);
|
||
}
|
||
},
|
||
// 视频进度条拖动完成触发事件
|
||
handle_slider_change(e) {
|
||
try {
|
||
const seek_time = e.detail.value;
|
||
if (this.create_video_contexts && this.create_video_contexts[this.current_index]) {
|
||
this.create_video_contexts[this.current_index].seek(seek_time);
|
||
this.current_video_progress = seek_time;
|
||
}
|
||
setTimeout(() => {
|
||
this.is_seeking = false;
|
||
}, 100);
|
||
e.stopPropagation();
|
||
} catch (error) {
|
||
console.error('handle_slider_change error:', error);
|
||
}
|
||
},
|
||
// 视频进度条时间显示
|
||
format_time(seconds) {
|
||
try {
|
||
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}`;
|
||
} catch (error) {
|
||
console.error('format_time error:', error);
|
||
}
|
||
},
|
||
// 返回上一页
|
||
handle_back() {
|
||
try {
|
||
app.globalData.page_back_prev_event();
|
||
} catch (error) {
|
||
console.error('handle_back error:', error);
|
||
}
|
||
},
|
||
// 跳转搜索记录页面
|
||
handle_search() {
|
||
try {
|
||
// 跳转到搜索记录页面
|
||
app.globalData.url_open(`/pages/plugins/video/search-record/search-record`, false);
|
||
} catch (error) {
|
||
console.error('handle_search error:', error);
|
||
}
|
||
},
|
||
// 关闭推荐商品
|
||
product_close_event(e) {
|
||
try {
|
||
this.video_data_list.forEach((item) => {
|
||
if (item.id == this.current_video_id) {
|
||
item.show_goods = false;
|
||
}
|
||
});
|
||
// this.video_data_list = this.video_data_list;
|
||
this.$set(this, 'video_data_list', this.video_data_list);
|
||
e.stopPropagation();
|
||
} catch (error) {
|
||
console.error('product_close_event error:', error);
|
||
}
|
||
},
|
||
// 点击商品卡片触发事件
|
||
handle_product_card_item(e) {
|
||
try {
|
||
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);
|
||
}
|
||
e.stopPropagation();
|
||
} catch (error) {
|
||
console.error('handle_product_card_item error:', error);
|
||
}
|
||
},
|
||
// 点击购买商品按钮触发事件
|
||
handle_product_button(e) {
|
||
try {
|
||
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.video_data_list = this.video_data_list;
|
||
this.$set(this, 'video_data_list', this.video_data_list);
|
||
e.stopPropagation();
|
||
} catch (error) {
|
||
console.error('handle_product_button error:', error);
|
||
}
|
||
},
|
||
// 清理所有视频资源
|
||
cleanup_all_videos() {
|
||
try {
|
||
// 暂停所有视频
|
||
this.pause_all_videos_except(-1);
|
||
} catch (error) {
|
||
console.error('清理视频资源时出错:', error);
|
||
}
|
||
},
|
||
// 处理下拉菜单切换
|
||
handle_toggle_dropdown(comment_id) {
|
||
try {
|
||
if (this.active_dropdown_id == comment_id) {
|
||
this.active_dropdown_id = null;
|
||
} else {
|
||
this.active_dropdown_id = comment_id;
|
||
}
|
||
console.log(this.active_dropdown_id);
|
||
} catch (error) {
|
||
console.error('handle_toggle_dropdown error:', error);
|
||
}
|
||
},
|
||
|
||
// 关闭下拉菜单
|
||
handle_dropdown_item_click(comment_id, obj) {
|
||
try {
|
||
if (this.active_dropdown_id == comment_id) {
|
||
this.active_dropdown_id = null;
|
||
}
|
||
// 处理不同操作
|
||
if (obj.type == 'delete') {
|
||
// 确认删除
|
||
uni.showModal({
|
||
title: t('common_warm_tips'),
|
||
content: t('common_delete_confirm_tips'),
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
// 调用删除接口
|
||
this.delete_comment(comment_id);
|
||
}
|
||
}
|
||
});
|
||
} else if (obj.type == 'report') {
|
||
// 举报评论
|
||
this.$refs.popupReportRef.open();
|
||
this.report_comment_id = comment_id;
|
||
}
|
||
} catch (error) {
|
||
console.error('handle_dropdown_item_click error:', error);
|
||
}
|
||
},
|
||
// 删除评论
|
||
delete_comment(comment_id) {
|
||
try {
|
||
uni.request({
|
||
url: app.globalData.get_request_url("delete", "index", "video"),
|
||
method: 'POST',
|
||
data: {
|
||
ids: comment_id,
|
||
},
|
||
dataType: 'json',
|
||
success: res => {
|
||
if (res.data.code == 0) {
|
||
// 删除评论数据
|
||
this.delete_comment_handle(comment_id);
|
||
// 显示删除成功提示
|
||
app.globalData.showToast(res.data.msg, 'success');
|
||
} else {
|
||
if (app.globalData.is_login_check(res.data)) {
|
||
app.globalData.showToast(res.data.msg);
|
||
} else {
|
||
app.globalData.showToast(t('common_sub_error_retry_tips'));
|
||
}
|
||
}
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('send_comment error:', error);
|
||
}
|
||
},
|
||
// 删除评论数据处理
|
||
delete_comment_handle(comment_id) {
|
||
try {
|
||
// 删除成功,从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];
|
||
|
||
// 清空回复评论数据(仅当匹配时)
|
||
if (comment.id === this.comments_reply_data.id || (comment.sub_comments && Array.isArray(comment.sub_comments) && comment.sub_comments.some(subComment => subComment.id === this.comments_reply_data.id))) {
|
||
this.comments_reply_data = {};
|
||
}
|
||
|
||
// 如果是父级评论且 id 匹配,跳过整个评论(包括子评论)
|
||
if (comment.id === comment_id) {
|
||
continue;
|
||
}
|
||
|
||
// 处理子评论
|
||
if (comment.sub_comments && Array.isArray(comment.sub_comments)) {
|
||
// 查找并移除匹配的子评论
|
||
const targetSubCommentIndex = comment.sub_comments.findIndex(subComment => subComment.id === comment_id);
|
||
if (targetSubCommentIndex !== -1) {
|
||
// 移除目标子评论
|
||
comment.sub_comments.splice(targetSubCommentIndex, 1);
|
||
// 更新显示状态和评论数
|
||
if (comment.sub_comments.length === 0) {
|
||
comment.show_sub_comment = false;
|
||
}
|
||
comment.comments_count -= 1;
|
||
}
|
||
}
|
||
|
||
// 保留当前评论
|
||
filteredComments.push(comment);
|
||
}
|
||
// 删除之后更新评论数据
|
||
this.video_data_list.forEach(item => {
|
||
if (item.id == this.current_video_id) {
|
||
item.comments_count = filteredComments.length;
|
||
}
|
||
})
|
||
// 更新数据
|
||
this.active_comments = filteredComments;
|
||
// this.video_data_list = this.video_data_list;
|
||
this.$set(this, 'video_data_list', this.video_data_list)
|
||
}
|
||
} catch (error) {
|
||
console.error('delete_comment_handle error:', error);
|
||
}
|
||
},
|
||
// 处理全局点击事件
|
||
handle_global_click(e) {
|
||
try {
|
||
// 检查点击目标是否在下拉菜单相关元素内
|
||
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;
|
||
}
|
||
} catch (error) {
|
||
console.error('handle_global_click error:', error);
|
||
}
|
||
},
|
||
// 关闭举报弹窗
|
||
popup_report_close_event() {
|
||
try {
|
||
// this.$refs.popupReportRef.close();
|
||
this.current_main_index = 0;
|
||
this.current_sub_index = 0;
|
||
} catch (error) {
|
||
console.error('popup_report_close_event error:', error);
|
||
}
|
||
},
|
||
|
||
// 直接选择主原因(用于一行显示的点击)
|
||
select_main_reason(e) {
|
||
try {
|
||
const index = e?.currentTarget?.dataset?.index || 0;
|
||
console.log(index);
|
||
const main_index = parseInt(index);
|
||
if (main_index !== this.current_main_index) {
|
||
this.current_main_index = main_index;
|
||
this.current_sub_index = 0; // 默认选中第一个子类型
|
||
}
|
||
} catch (error) {
|
||
console.error('select_main_reason error:', error);
|
||
}
|
||
},
|
||
|
||
// 直接选择子类型(用于一行显示的点击)
|
||
select_sub_reason(e) {
|
||
try {
|
||
const index = e?.currentTarget?.dataset?.index || 0;
|
||
const sub_index = parseInt(index);
|
||
if (sub_index !== this.current_sub_index) {
|
||
this.current_sub_index = sub_index;
|
||
}
|
||
} catch (error) {
|
||
console.error('select_sub_reason error:', error);
|
||
}
|
||
},
|
||
/*
|
||
* 提交举报
|
||
*/
|
||
submit_report() {
|
||
try {
|
||
// 获取选中的举报原因和具体类型
|
||
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 => {
|
||
if (res.data.code == 0) {
|
||
// 显示删除成功提示
|
||
app.globalData.showToast(res.data.msg, 'success');
|
||
// 关闭弹窗
|
||
this.popup_report_close_event();
|
||
} else {
|
||
if (app.globalData.is_login_check(res.data)) {
|
||
app.globalData.showToast(res.data.msg);
|
||
} else {
|
||
app.globalData.showToast(t('common_sub_error_retry_tips'));
|
||
}
|
||
}
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('submit_report error:', error);
|
||
}
|
||
},
|
||
// 键盘显示时,切换输入框
|
||
add_comment() {
|
||
try {
|
||
//#ifndef H5
|
||
this.is_add_comment = true;
|
||
this.active_dropdown_id = null;
|
||
//#endif
|
||
} catch (error) {
|
||
console.error('add_comment error:', error);
|
||
}
|
||
},
|
||
/**
|
||
* 键盘高度变化监听处理
|
||
* @param {Object} res - 键盘高度变化事件对象
|
||
*/
|
||
listener(res) {
|
||
try {
|
||
if (res.height > 0) {
|
||
this.listener_height = res.height - 1;
|
||
} else {
|
||
this.listener_height = 0;
|
||
}
|
||
} catch (error) {
|
||
console.error('listener error:', error);
|
||
}
|
||
},
|
||
/**
|
||
* 绑定键盘高度变化监听事件
|
||
*/
|
||
bind_keyboard_listener() {
|
||
try {
|
||
uni.onKeyboardHeightChange(this.listener);
|
||
} catch (error) {
|
||
console.error('bind_keyboard_listener error:', error);
|
||
}
|
||
},
|
||
/**
|
||
* 解绑键盘高度变化监听事件
|
||
*/
|
||
unbind_keyboard_listener() {
|
||
try {
|
||
uni.offKeyboardHeightChange(this.listener);
|
||
} catch (error) {
|
||
console.error('unbind_keyboard_listener error:', error);
|
||
}
|
||
},
|
||
}
|
||
};
|
||
</script>
|
||
<style lang="scss" scoped>
|
||
@import './detail.css';
|
||
</style> |