308 lines
6.2 KiB
Vue
308 lines
6.2 KiB
Vue
<template>
|
||
<view class="video-search-page">
|
||
<!-- 头部导航栏 -->
|
||
<uni-nav-bar
|
||
left-icon="left"
|
||
:title="title"
|
||
@clickLeft="goBack"
|
||
fixed
|
||
color="#8B2316"
|
||
height="180rpx"
|
||
:border="false"
|
||
backgroundColor="#eeeeee"
|
||
/>
|
||
|
||
<!-- 顶部排序标签 -->
|
||
<view class="tabs">
|
||
<view
|
||
class="tab"
|
||
:class="{ active: activeTab === 0 }"
|
||
@click="switchTab(0)"
|
||
>
|
||
<text class="tab-text">上传时间</text>
|
||
</view>
|
||
<view
|
||
class="tab"
|
||
:class="{ active: activeTab === 1 }"
|
||
@click="switchTab(1)"
|
||
>
|
||
<text class="tab-text">点播量</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 列表区域 -->
|
||
<scroll-view
|
||
class="list-scroll"
|
||
scroll-y
|
||
:show-scrollbar="false"
|
||
@scrolltolower="onReachBottom"
|
||
:refresher-enabled="true"
|
||
:refresher-triggered="isRefreshing"
|
||
@refresherrefresh="onRefresh"
|
||
>
|
||
<view class="video-list">
|
||
<view class="video-item" v-for="(item, idx) in videoList" :key="idx" @click="openDetail(item)">
|
||
<view class="item-title">{{ item.name }}</view>
|
||
<view class="item-meta">
|
||
<text class="item-tag">{{ item.public_name }}</text>
|
||
</view>
|
||
<view class="item-date-views">
|
||
<text class="item-date">{{ formatDate(item.create_date) }}</text>
|
||
<view class="item-views">
|
||
<uni-icons type="eye" size="20" color="#999"></uni-icons>
|
||
<text class="views-text">{{ item.readnum }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="item-footer">
|
||
<text class="item-source">{{ item.video_type_name }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref } from 'vue'
|
||
import { onLoad,onShow } from '@dcloudio/uni-app'
|
||
import api from '@/api/api.js'
|
||
import navTo from '@/utils/navTo.js'
|
||
const keywords=ref('')
|
||
const title = ref('肝胆视频')
|
||
const activeTab = ref(0)
|
||
const page = ref(1)
|
||
const pageSize = ref(10)
|
||
const hasMore = ref(true)
|
||
const isRefreshing = ref(false)
|
||
const videoList = ref([])
|
||
const sort = ref('2')
|
||
const from=ref('');
|
||
const loadListHuanJiao=async (reset = false) => {
|
||
if (reset) {
|
||
page.value = 1
|
||
hasMore.value = true
|
||
videoList.value = []
|
||
}
|
||
if (!hasMore.value) return
|
||
const res = await api.videoBySearchNew({
|
||
name: keywords.value,
|
||
page: page.value,
|
||
pageSize: pageSize.value,
|
||
sort: sort.value,
|
||
|
||
})
|
||
if (res.code === 200 && res.data) {
|
||
const list = res.data.list || []
|
||
videoList.value = [...videoList.value, ...list]
|
||
if (list.length < pageSize.value) {
|
||
hasMore.value = false
|
||
} else {
|
||
page.value += 1
|
||
}
|
||
} else {
|
||
hasMore.value = false
|
||
}
|
||
}
|
||
|
||
const loadList = async (reset = false) => {
|
||
if (reset) {
|
||
page.value = 1
|
||
hasMore.value = true
|
||
videoList.value = []
|
||
}
|
||
if (!hasMore.value) return
|
||
const res = await api.videoBySearchNew({
|
||
name: keywords.value,
|
||
page: page.value,
|
||
pageSize: pageSize.value,
|
||
sort: sort.value,
|
||
|
||
})
|
||
if (res.code === 200 && res.data) {
|
||
const list = res.data.list || []
|
||
videoList.value = [...videoList.value, ...list]
|
||
if (list.length < pageSize.value) {
|
||
hasMore.value = false
|
||
} else {
|
||
page.value += 1
|
||
}
|
||
} else {
|
||
hasMore.value = false
|
||
}
|
||
}
|
||
|
||
onShow(() => {
|
||
if(from.value){
|
||
loadListHuanJiao(true)
|
||
}else{
|
||
loadList(true)
|
||
}
|
||
})
|
||
|
||
const onReachBottom = () => {
|
||
if(from.value){
|
||
loadListHuanJiao(false)
|
||
}else{
|
||
loadList(false)
|
||
}
|
||
}
|
||
|
||
const onRefresh = async () => {
|
||
isRefreshing.value = true
|
||
if(from.value){
|
||
await loadListHuanJiao(true)
|
||
}else{
|
||
await loadList(true)
|
||
}
|
||
isRefreshing.value = false
|
||
}
|
||
|
||
onLoad((options) => {
|
||
if (options.keywords) {
|
||
keywords.value = options.keywords
|
||
}
|
||
if(options.from){
|
||
from.value = options.from
|
||
title.value = '患教视频'
|
||
}
|
||
})
|
||
|
||
|
||
|
||
|
||
|
||
|
||
const switchTab = (index) => {
|
||
activeTab.value = index;
|
||
if(index==0){
|
||
sort.value='2'
|
||
}else{
|
||
sort.value='1'
|
||
}
|
||
loadList(true)
|
||
// 在此触发排序加载逻辑
|
||
}
|
||
|
||
|
||
|
||
const openDetail = (item) => {
|
||
// 打开视频详情/播放页
|
||
navTo({
|
||
url: `/pages_app/videoDetail/videoDetail?id=${item.uuid}`
|
||
})
|
||
}
|
||
|
||
const goBack = () => {
|
||
uni.navigateBack()
|
||
}
|
||
|
||
const formatDate = (val) => {
|
||
if (!val) return ''
|
||
try {
|
||
const d = new Date(val)
|
||
const y = d.getFullYear()
|
||
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||
const day = String(d.getDate()).padStart(2, '0')
|
||
return `${y}-${m}-${day}`
|
||
} catch (e) {
|
||
return val
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
$primary: #8B2316;
|
||
$text-primary: #333;
|
||
$text-secondary: #666;
|
||
$text-light: #999;
|
||
$bg: #f6f6f6;
|
||
$white: #ffffff;
|
||
|
||
.video-search-page {
|
||
background: $bg;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
.tabs {
|
||
position: fixed;
|
||
top: 180rpx;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 90;
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
background: $white;
|
||
border-bottom: 2rpx solid #eee;
|
||
.tab {
|
||
padding: 28rpx 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
.tab-text { color: $text-secondary; font-size: 30rpx; }
|
||
&.active {
|
||
.tab-text { color: $primary; font-weight: 600; }
|
||
position: relative;
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
.list-scroll {
|
||
position: fixed;
|
||
top: 215rpx; // 140rpx 导航 + 100rpx tabs
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: $bg;
|
||
}
|
||
|
||
.video-list {
|
||
padding: 20rpx 0;
|
||
|
||
.video-item {
|
||
background: $white;
|
||
padding: 28rpx 32rpx;
|
||
margin: 20rpx 30rpx 0; // 上 20rpx,左右 30rpx
|
||
// 去底部分隔线
|
||
|
||
.item-title {
|
||
font-size: 34rpx;
|
||
color: $primary;
|
||
line-height: 1.5;
|
||
margin-bottom: 18rpx;
|
||
}
|
||
|
||
.item-meta {
|
||
margin-bottom: 12rpx;
|
||
.item-tag { color: $text-secondary; font-size: 28rpx; }
|
||
}
|
||
|
||
.item-date-views {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between; // 两端分布
|
||
width: 100%;
|
||
margin-bottom: 16rpx;
|
||
padding-bottom: 16rpx;
|
||
border-bottom: 2rpx solid #efefef;
|
||
.item-date { color: $text-secondary; font-size: 28rpx; }
|
||
.item-views { display: flex; align-items: center; gap: 10rpx; white-space: nowrap; }
|
||
.views-text { color: $text-secondary; font-size: 28rpx; }
|
||
}
|
||
|
||
.item-footer {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
.item-source {
|
||
font-size: 28rpx;
|
||
color: $text-secondary;
|
||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
</style>
|
||
|