2025-11-28 10:43:13 +08:00

644 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="navbox">
<view class="status_bar"></view>
<uni-nav-bar left-icon="left"
@clickLeft="goBack" :title="name" color="#8B2316" :border="false" backgroundColor="#eeeeee">
<template #right>
<view class="nav-right" @click="goSelect">
精选
</view>
</template>
</uni-nav-bar>
</view>
<view class="video-page">
<!-- Header -->
<!-- Main Content -->
<scroll-view
class="scroll-view"
scroll-y="true"
refresher-enabled="true"
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
@scrolltolower="onLoadMore"
lower-threshold="100"
>
<!-- Video List -->
<view class="video-list">
<view
class="video-item"
v-for="(video, index) in videoList"
:key="video.id || video.uuid"
@click="playVideo(video)"
>
<view class="video-thumbnail">
<up-image :src="docUrl + video.imgpath" mode="aspectFill" :loadingIcon="lazyImg" :errorIcon="lazyImg" height="200rpx" width="100%" :lazy-load="true">
<template #error>
<image :src="lazyImg" mode="aspectFill" height="200rpx" width="100%"></image>
</template>
<template #loading>
<image :src="lazyImg" mode="aspectFill" height="200rpx" width="100%"></image>
</template>
</up-image>
</view>
<view class="video-info">
<view class="video-title">{{video.title || video.name}}</view>
<view class="video-meta">
<text class="author">{{video.public_name}}</text>
<view class="stats">
<uni-icons type="eye" size="14" color="#999"></uni-icons>
<text class="view-count">{{video.readnum}}</text>
</view>
</view>
</view>
</view>
</view>
<!-- Loading More -->
<uni-load-more
v-if="videoList.length > 0"
:status="loadMoreStatus"
:content-text="{
contentdown: '上拉加载更多',
contentrefresh: '正在加载...',
contentnomore: '没有更多数据了'
}"
></uni-load-more>
<!-- Empty State -->
<view class="empty-state" v-if="videoList.length === 0 && !loading">
<empty></empty>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref, onMounted, computed,reactive } from 'vue';
import { onShow,onLoad } from "@dcloudio/uni-app";
import api from '@/api/api.js';
import allImg from "@/static/video_all.png"
import allOnImg from "@/static/video_select.png"
import selectImg from "@/static/all_video.png"
import selectOnImg from "@/static/select_video.png"
import filter from "@/static/cb_screen_no.png"
import filterOn from "@/static/cb_screen_yes.png"
import upImg from "@/static/cb_up.png"
import downImg from "@/static/cb_down.png"
import docUrl from '@/utils/docUrl';
import navTo from '@/utils/navTo';
import empty from '@/components/empty/empty.vue';
import lazyImg from '@/static/default_video.png';
const isAllActive=ref(false)
// 响应式数据
const videoList = ref([]);
const activeTab = ref(1); // 默认选中"最新"
const loading = ref(false);
const refreshing = ref(false);
const loadMoreStatus = ref('more'); // more, loading, noMore
const currentPage = ref(1);
const pageSize = ref(10);
const hasMoreData = ref(true);
const filteredContent=ref([])
const sort =ref(2);
const keywords=ref('');
const typeUuid=ref('');
const typeName=ref('乙肝')
const isFilterActive=ref(false)
const showFilter = ref(false);
const yearList=ref([]);
const selectYearContent=reactive({});
const name=ref('');
// 筛选弹窗相关数据
const filterTags = ref([]);
onLoad((options)=>{
if(options.name){
name.value=decodeURIComponent(options.name);
}
getVideoType();
})
const goSelect=()=>{
navTo({
url: `/pages_app/replayText/replayText?name=${name.value}`
});
};
const getVideoType=async () => {
const response = await api.getTypeUuidByName({
name: name.value,
});
if(response.code === 200 && response.data){
typeUuid.value = response.data;
loadVideoData();
}
}
// 加载轮播数据
// 加载视频数据
const loadVideoData = async (isRefresh = false) => {
if (loading.value && !isRefresh) return;
loading.value = true;
try {
const response = await api.videoByTypeNew({
page: currentPage.value,
pageSize: pageSize.value,
typeUuid:typeUuid.value,
});
console.log('视频列表API原始响应:', response);
// 检查响应结构
let videoData = {};
if (response && response.data) {
if (response.data.code === 200) {
videoData = response.data.data || {};
} else if (response.code === 200) {
videoData = response.data || {};
}
} else if (response && response.code === 200) {
videoData = response.data || {};
}
console.log('解析后的视频数据:', videoData);
if (videoData && videoData.list) {
const { list, totalPage,pageNumber } = videoData;
console.log('视频列表数据:', list);
if (isRefresh) {
videoList.value = list || [];
currentPage.value = 1;
} else {
videoList.value = [...videoList.value, ...(list || [])];
}
hasMoreData.value = totalPage>pageNumber;
loadMoreStatus.value = hasMoreData.value ? 'more' : 'noMore';
} else {
throw new Error(response?.message || '获取数据失败');
}
} catch (error) {
console.error('加载视频失败:', error);
} finally {
loading.value = false;
refreshing.value = false;
}
};
// 下拉刷新
const onRefresh = () => {
refreshing.value = true;
currentPage.value = 1;
hasMoreData.value = true;
loadVideoData(true);
};
// 上拉加载更多
const onLoadMore = () => {
if (!hasMoreData.value || loading.value) return;
loadMoreStatus.value = 'loading';
currentPage.value++;
loadVideoData();
};
// 播放视频
const playVideo = (video) => {
console.log(video);
const videoId = video.id || video.uuid;
navTo({
url: `/pages_app/videoDetail/videoDetail?id=${videoId}`
});
};
// 返回
const goBack = () => {
uni.navigateBack({
fail() {
uni.redirectTo({
url: '/pages/index/index'
});
}
});
}
</script>
<style scoped lang="scss">
$primary-color: #ff6b6b;
$theme-color: #8B2316;
$white: #fff;
$gray-bg: #f5f5f5;
$gray-light: #eee;
$gray-medium: #999;
$gray-dark: #666;
$text-color: #333;
// 尺寸变量
$border-radius: 8px;
$border-radius-small: 6px;
$padding: 15px;
$padding-small: 10px;
.nav-right {
// margin-top:50rpx;
font-size: 32rpx;
color: #8b2316;
font-weight: 500;
}
.video-page {
background-color: #f5f5f5;
height: 100vh;
display: flex;
overflow: hidden;
flex-direction: column;
}
/* Header Styles */
.header {
background-color: #fff;
height: 88rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30rpx;
box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.1);
position: relative;
z-index: 100;
}
.header-left, .header-right {
display: flex;
align-items: center;
}
.header-title {
font-size: 36rpx;
font-weight: 600;
color: #8B4513;
}
/* Scroll View */
.scroll-view {
position: fixed;
bottom: 0rpx;
height:calc(100vh - var(--status-bar-height) - 44px);
background-color: #f5f5f5;
top: calc(var(--status-bar-height) + 44px); /* 为导航栏留出空间 */
}
/* Filter Tabs */
.filter-tabs {
background-color: #fff;
display: flex;
justify-content: space-between;
padding: 30rpx 30rpx;
}
.tab-item {
display: flex;
align-items: center;
margin-right: 60rpx;
padding: 10rpx 0;
}
.tab-item:last-child{
margin-right: 0;
}
.right{
display: flex;
}
.tab-item.active .tab-text {
color: #E74C3C;
font-weight: 600;
}
.tab-text {
margin: 0 8rpx;
font-size: 28rpx;
color: #666;
}
.tab-item:first-child .tab-text{
max-width:295rpx;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tab-item .tab-text.active {
color: #8B2316;
}
/* Fixed Filter Tabs Container */
.filter-tabs-container {
position: fixed;
top: 180rpx; /* uni-nav-bar height */
left: 0;
right: 0;
z-index: 40;
background-color: #fff;
border-bottom: 1rpx solid #f0f0f0;
}
.doctor-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 20rpx;
overflow: hidden;
}
.doctor-avatar image {
width: 100%;
height: 100%;
}
/* Video List */
.video-list {
padding: 0 20rpx;
margin-top: 20rpx; /* 为固定的Filter Tabs留出空间 */
display: grid;
grid-template-columns: repeat(2, 1fr); /* 每行两个 */
gap: 16rpx; /* 卡片间距 */
}
.video-item {
background-color: #fff;
border-radius: 16rpx;
margin-bottom: 0;
overflow: hidden;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
width: 100%;
}
.video-thumbnail {
position: relative;
height: 200rpx;
}
.video-thumbnail image {
width: 100%;
height: 100%;
}
.video-duration {
margin-top: 8rpx;
}
.video-duration text {
font-size: 22rpx;
color: #999;
}
.video-info {
padding: 24rpx;
}
.video-title {
font-size: 28rpx;
font-weight: 400;
color: #333;
line-height: 1.4;
margin-bottom: 16rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
overflow: hidden;
height: 2.8em; /* 固定2行高度1.4 * 2 = 2.8em */
}
.video-meta {
display: flex;
justify-content: space-between;
align-items: center;
}
.author {
font-size: 24rpx;
color: #999;
}
.stats {
display: flex;
align-items: center;
}
.view-count {
font-size: 24rpx;
color: #999;
margin-left: 8rpx;
}
/* Empty State */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
}
.empty-state image {
width: 200rpx;
height: 200rpx;
margin-bottom: 30rpx;
opacity: 0.5;
}
.empty-state text {
color: #999;
font-size: 28rpx;
}
.newbox{
margin-top: -12rpx;
}
/* 全部视频弹窗样式 */
.all-video-popup {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
display: flex;
align-items: flex-end;
}
.popup-content {
width: 100%;
background-color: #fff;
height:calc(100vh - 272rpx);
overflow-y: scroll;
}
.popup-header {
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
background-color: #fff;
}
.popup-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.popup-body {
height:100%;
}
.category-item {
padding: 30rpx;
font-size: 28rpx;
color: #333;
border-bottom: 1rpx solid #f0f0f0;
background-color: #fff;
transition: background-color 0.2s ease;
}
.category-item:last-child {
border-bottom: none;
}
.category-item.active {
background-color: #f8f8f8;
color: #8B2316;
}
.category-item:active {
background-color: #e8f4fd;
}
.empty-content {
display: flex;
justify-content: center;
align-items: center;
height: 200rpx;
color: #999;
font-size: 28rpx;
}
// 筛选弹窗样式
.filter-popup {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
// background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
z-index: 9999;
.filter-content {
margin-top:272rpx;
overflow-y:scroll;
background-color: $white;
// border-radius: 20rpx 20rpx 0 0;
padding: 20rpx 30rpx 60rpx;
width: 100%;
height: calc(100vh - 272rpx);
.filter-tags {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
margin-bottom: 60rpx;
max-height: 65vh;
overflow-y: auto;
.tag-item {
background-color: #f8f8f8;
color: $gray-dark;
padding: 8rpx 0; /* 去掉左右padding仅保留上下 */
border-radius: 30rpx;
font-size: 26rpx;
border: 2rpx solid #efefef;
transition: all 0.3s ease;
width: 152rpx; /* 固定宽度 */
text-align: center; /* 文本居中 */
white-space: nowrap; /* 单行显示 */
overflow: hidden; /* 隐藏溢出 */
text-overflow: ellipsis; /* 超出显示省略号 */
&.active {
background-color: #fff;
color: $theme-color;
border-color: $theme-color;
}
}
}
.filter-buttons {
display: flex;
gap: 20rpx;
position: fixed;
bottom: 30rpx;
left: 30rpx;
right: 30rpx;
background-color: #fff; /* 背景色为白色 */
.btn-reset,
.btn-confirm {
flex: 1;
height: 70rpx;
border-radius: 14rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
font-weight: 500;
}
.btn-reset {
background-color: $white;
color: $theme-color;
border: 2rpx solid $theme-color;
}
.btn-confirm {
border: 2rpx solid $theme-color;
background-color: $theme-color;
color: $white;
}
}
}
}
</style>