This commit is contained in:
zoujiandong 2025-12-03 09:58:56 +08:00
parent 51367c48c9
commit da3659412d
4 changed files with 2314 additions and 2225 deletions

View File

@ -9,16 +9,16 @@
}
},
"pages": [
// {
// "path": "pages/loading/loading",
// "style": {
// "navigationBarTitleText": "",
// "navigationStyle": "custom",
// "app": {
// "bounce": "none"
// }
// }
// },
{
"path": "pages/loading/loading",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"app": {
"bounce": "none"
}
}
},
{
"path": "pages/index/index",
"style": {

View File

@ -15,11 +15,7 @@
<image class="img-icon" :src="searchImg" mode="aspectFill" />
</view>
<view class="collect-img" @click="goMeet">
<image
class="img-icon"
:src="meetImg"
mode="aspectFill"
/>
<image class="img-icon" :src="meetImg" mode="aspectFill" />
</view>
</view>
</template>
@ -31,12 +27,17 @@
<!-- Fixed Banner Swiper -->
<view class="banner-container">
<view class="swipemask">
<view class="banner-subtitle" v-if="bannerList.length>0">{{bannerList[currentBannerIndex].name}}</view>
<view class="banner-subtitle" v-if="bannerList.length > 0">{{
bannerList[currentBannerIndex].name
}}</view>
<view class="dotbox">
<view class="circle" :class="{active:currentBannerIndex==index} "v-for="(banner, index) in bannerList"
:key="banner.id"></view>
<view
class="circle"
:class="{ active: currentBannerIndex == index }"
v-for="(banner, index) in bannerList"
:key="banner.id"
></view>
</view>
</view>
<swiper
@ -50,7 +51,6 @@
circular
@change="onSwiperChange"
>
<swiper-item
v-for="(banner, index) in bannerList"
:key="banner.id"
@ -68,13 +68,20 @@
height="400rpx"
>
<template #error>
<image :src="lazyVideoImg" class="banner-image" mode="aspectFill"></image>
<image
:src="lazyVideoImg"
class="banner-image"
mode="aspectFill"
></image>
</template>
<template #loading>
<image :src="lazyVideoImg" class="banner-image" mode="aspectFill"></image>
<image
:src="lazyVideoImg"
class="banner-image"
mode="aspectFill"
></image>
</template>
</up-image>
</view>
</swiper-item>
</swiper>
@ -83,32 +90,45 @@
<!-- Fixed Filter Tabs -->
<view class="filter-tabs-container">
<view class="filter-tabs">
<view
class="tab-item"
@click="showAllVideoPopup=!showAllVideoPopup"
>
<up-image :src="isAllActive?allOnImg:allImg" width="30rpx" height="30rpx" ></up-image>
<text class="tab-text" :class="{active:isAllActive}">{{typeName}}</text>
<up-image :src="isAllActive?selectOnImg:selectImg" width="30rpx" height="30rpx" ></up-image>
<view class="tab-item" @click="showAllVideoPopup = !showAllVideoPopup">
<up-image
:src="isAllActive ? allOnImg : allImg"
width="30rpx"
height="30rpx"
></up-image>
<text class="tab-text" :class="{ active: isAllActive }">{{
typeName
}}</text>
<up-image
:src="isAllActive ? selectOnImg : selectImg"
width="30rpx"
height="30rpx"
></up-image>
</view>
<view class="right">
<view
class="tab-item"
@click="toggleSort"
>
<text class="tab-text active">{{sort==2?'最新':'最热'}}</text>
<view class="tab-item" @click="toggleSort">
<text class="tab-text active">{{
sort == 2 ? "最新" : "最热"
}}</text>
<view class="newbox">
<up-image :src="sort==2?upImg:downImg" width="20rpx" height="26rpx" ></up-image>
<up-image
:src="sort == 2 ? upImg : downImg"
width="20rpx"
height="26rpx"
></up-image>
</view>
</view>
<view class="bar"></view>
<view
class="tab-item"
@click="showFilterPopup"
<view class="tab-item" @click="showFilterPopup">
<text class="tab-text" :class="{ active: isFilterActive }"
>筛选</text
>
<text class="tab-text " :class="{active:isFilterActive}">筛选</text>
<view class="filterbox">
<up-image :src="isFilterActive ? filterOn : filter" width="30rpx" height="30rpx" ></up-image>
<up-image
:src="isFilterActive ? filterOn : filter"
width="30rpx"
height="30rpx"
></up-image>
</view>
</view>
</view>
@ -125,7 +145,6 @@
@scrolltolower="onLoadMore"
lower-threshold="100"
>
<!-- Video List -->
<view class="video-list">
<view
@ -144,16 +163,22 @@
:lazy-load="true"
width="100%"
height="220rpx"
>
<template #error>
<image :src="lazyImg" class="poster-image" mode="aspectFill"></image>
<image
:src="lazyImg"
class="poster-image"
mode="aspectFill"
></image>
</template>
<template #loading>
<image :src="lazyImg" class="poster-image" mode="aspectFill"></image>
<image
:src="lazyImg"
class="poster-image"
mode="aspectFill"
></image>
</template>
</up-image>
</view>
<view class="video-info">
<view class="video-title">{{ video.title || video.name }}</view>
@ -161,10 +186,11 @@
<text class="author">{{ video.public_name }}</text>
<view class="stats">
<uni-icons type="eye" size="14" color="#999"></uni-icons>
<text class="view-count">{{formatNumber(video.readnum)}}</text>
<text class="view-count">{{
formatNumber(video.readnum)
}}</text>
</view>
</view>
</view>
</view>
</view>
@ -176,7 +202,7 @@
:content-text="{
contentdown: '上拉加载更多',
contentrefresh: '正在加载...',
contentnomore: '没有更多数据了'
contentnomore: '没有更多数据了',
}"
></uni-load-more>
@ -189,7 +215,6 @@
<view class="btnbox" @click="goPatientVideo">
<up-image :src="videoImg" width="44rpx" height="44rpx"></up-image>
患教视频
</view>
<!-- 筛选弹窗 -->
<view class="filter-popup" v-if="showFilter" @click="hideFilterPopup">
@ -215,11 +240,13 @@
</view>
</view>
<!-- 全部视频弹窗 -->
<view class="all-video-popup" v-if="showAllVideoPopup" @click="closeAllVideoPopup">
<view
class="all-video-popup"
v-if="showAllVideoPopup"
@click="closeAllVideoPopup"
>
<view class="popup-content" @click.stop>
<view class="popup-body">
<view class="category-sidebar">
<view
@ -230,18 +257,18 @@
@click="selectCategory(category.value)"
>
<view class="category-label">{{ category.label }}</view>
<view class="category-date" v-if="category.value !== '全部' && category.originalDate">
<view
class="category-date"
v-if="category.value !== '全部' && category.originalDate"
>
{{ formatDate(category.originalDate) }}
</view>
</view>
</view>
<view class="content-area">
<view class="content-list">
<view
class="content-item"
v-for="item in filteredContent"
:key="item.uuid"
:class="{ active: selectYearContent.uuid == item.uuid }"
@ -261,102 +288,119 @@
</template>
<script setup>
import { ref, onMounted, computed,reactive } from 'vue';
import { onShow } 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 videoImg from "@/static/patient_video.png"
import docUrl from '@/utils/docUrl';
import navTo from '@/utils/navTo';
import searchImg from "@/static/search.png"
import lazyImg from "@/static/default_video.png"
import { ref, onMounted, computed, reactive } from "vue";
import { onShow,onBackPress} 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 videoImg from "@/static/patient_video.png";
import docUrl from "@/utils/docUrl";
import navTo from "@/utils/navTo";
import searchImg from "@/static/search.png";
import lazyImg from "@/static/default_video.png";
import lazyVideoImg from "@/static/videoPlaceholder.png";
import meetImg from "@/static/videoIcon.png"
import formatNumber from '@/utils/formatNumber.js';
import navBar from '@/components/navBar/navBar.vue';
const isAllActive=ref(false)
import meetImg from "@/static/videoIcon.png";
import formatNumber from "@/utils/formatNumber.js";
import navBar from "@/components/navBar/navBar.vue";
const isAllActive = ref(false);
//
const videoList = ref([]);
const bannerVideo = ref(null);
const activeTab = ref(1); // ""
const loading = ref(false);
const refreshing = ref(false);
const loadMoreStatus = ref('more'); // more, loading, noMore
const loadMoreStatus = ref("more"); // more, loading, noMore
const currentPage = ref(1);
const pageSize = ref(10);
const hasMoreData = ref(true);
const filteredContent=ref([])
const filteredContent = ref([]);
const sort = ref(2);
const keywords=ref('');
const typeUuid=ref('');
const typeName=ref('全部视频')
const keywords = ref("");
const typeUuid = ref("");
const typeName = ref("全部视频");
// Banner
const bannerList = ref([]);
const currentBannerIndex = ref(0);
const isFilterActive=ref(false)
const isFilterActive = ref(false);
const showFilter = ref(false);
const yearList = ref([]);
const selectYearContent=reactive({})
const goSearch=()=>{
uni.sendNativeEvent('goHomeSearch', {
msg: 'goHomeSearch'
},ret => {
const selectYearContent = reactive({});
onBackPress(() => {
try {
uni.sendNativeEvent(
"goTabbarPage",
{
msg: "home",
},
(ret) => {
console.log(ret);
})
}
);
} catch (e) {
console.log(e);
}
plus.runtime.quit();
return true;
});
const goSearch = () => {
uni.sendNativeEvent(
"goHomeSearch",
{
msg: "goHomeSearch",
},
(ret) => {
console.log(ret);
}
);
};
const goMeet = () => {
uni.navigateTo({
url: '/pages_app/liveReplay/liveReplay?from=video'
url: "/pages_app/liveReplay/liveReplay?from=video",
});
}
};
//
const filterTags = ref([
{ name: '指南解读', selected: false },
{ name: '病例分析', selected: false },
{ name: '学术讲座', selected: false },
{ name: '手术视频', selected: false },
{ name: '研究进展', selected: false },
{ name: '肝病治疗', selected: false },
{ name: '肝癌诊断', selected: false },
{ name: '肝移植', selected: false },
{ name: '微创手术', selected: false },
{ name: '免疫治疗', selected: false },
{ name: '靶向治疗', selected: false },
{ name: '化疗方案', selected: false }
{ name: "指南解读", selected: false },
{ name: "病例分析", selected: false },
{ name: "学术讲座", selected: false },
{ name: "手术视频", selected: false },
{ name: "研究进展", selected: false },
{ name: "肝病治疗", selected: false },
{ name: "肝癌诊断", selected: false },
{ name: "肝移植", selected: false },
{ name: "微创手术", selected: false },
{ name: "免疫治疗", selected: false },
{ name: "靶向治疗", selected: false },
{ name: "化疗方案", selected: false },
]);
//
const showAllVideoPopup = ref(false);
const selectedCategory = ref('全部');
const categoryList = ref([
{ value: 'all', label: '全部' }
]);
const selectedCategory = ref("全部");
const categoryList = ref([{ value: "all", label: "全部" }]);
// - API
const contentByCategory = ref({
all: []
all: [],
});
// API
const videoTypesData = ref([]);
//
onMounted(() => {
});
onMounted(() => {});
const formatName = (name) => {
let index=name.lastIndexOf('-');
let index = name.lastIndexOf("-");
if (index > -1) {
return name.substring(index + 1, name.length);
}
return name;
}
};
onShow(() => {
// API
currentPage.value = 1;
@ -368,7 +412,7 @@
// ""
setTimeout(() => {
loadCategoryVideos('all');
loadCategoryVideos("all");
}, 500);
});
@ -376,13 +420,11 @@
const loadBannerData = async () => {
try {
const response = await api.videoRoll({});
console.log('轮播API原始响应:', response);
console.log("轮播API原始响应:", response);
bannerList.value = response.data;
} catch (error) {
console.error('加载轮播数据失败:', error);
console.error("加载轮播数据失败:", error);
// 使
}
};
@ -390,82 +432,84 @@
const loadVideoTags = async () => {
try {
const response = await api.videoTagList({
type:2
type: 2,
});
console.log('标签API原始响应:', response);
console.log("标签API原始响应:", response);
if (response.code == 200) {
filterTags.value = response.data;
console.log(22222)
console.log(filterTags.value)
console.log(22222);
console.log(filterTags.value);
}
} catch (error) {
console.error('加载视频标签失败:', error);
console.error("加载视频标签失败:", error);
}
};
//
const loadVideoTypes = async () => {
try {
const response = await api.expertVideoTypeList({
});
console.log('类型API原始响应:', response);
const response = await api.expertVideoTypeList({});
console.log("类型API原始响应:", response);
if (response.code == 200) {
yearList.value = response.data;
let all=[{uuid:'',name:'全部视频'}];
filteredContent.value=all.concat((response.data[0]).list);
console.log(33)
let arr=response.data.map(item=>{
let all = [{ uuid: "", name: "全部视频" }];
filteredContent.value = all.concat(response.data[0].list);
console.log(33);
let arr = response.data.map((item) => {
return {
value: item.name,
label:item.name
label: item.name,
};
});
categoryList.value = arr;
}
})
categoryList.value=arr
}
console.log(2222)
console.log(categoryList.value)
console.log(2222);
console.log(categoryList.value);
} catch (error) {
console.error('加载视频类型失败:', error);
console.error("加载视频类型失败:", error);
}
};
//
const loadCategoryVideos = async (categoryValue) => {
try {
console.log('加载分类视频:', categoryValue);
console.log("加载分类视频:", categoryValue);
let response;
if (categoryValue === '全部') {
if (categoryValue === "全部") {
//
response = await api.videoByKeyWordsNew({
page: 1,
pageSize: 20,
keywords: '',
keywords: "",
sort: 0,
typeUuid: '',
tags: ''
typeUuid: "",
tags: "",
});
} else {
//
//
const typesForDate = videoTypesData.value.filter(type => type.create_date === categoryValue);
const typesForDate = videoTypesData.value.filter(
(type) => type.create_date === categoryValue
);
console.log(`日期 ${categoryValue} 对应的视频类型:`, typesForDate);
if (typesForDate.length > 0) {
// UUID
const typeUuids = typesForDate.map(type => type.id || type.uuid || type.value).join(',');
console.log('类型UUID列表:', typeUuids);
const typeUuids = typesForDate
.map((type) => type.id || type.uuid || type.value)
.join(",");
console.log("类型UUID列表:", typeUuids);
//
response = await api.videoByKeyWordsNew({
page: 1,
pageSize: 20,
keywords: '',
keywords: "",
sort: 0,
typeUuid: typeUuids,
tags: ''
tags: "",
});
} else {
console.warn(`未找到日期 ${categoryValue} 对应的视频类型`);
@ -474,7 +518,7 @@
}
}
console.log('分类视频API响应:', response);
console.log("分类视频API响应:", response);
//
let videoData = {};
@ -488,21 +532,24 @@
videoData = response.data || {};
}
console.log('解析后的分类视频数据:', videoData);
console.log("解析后的分类视频数据:", videoData);
if (videoData && videoData.list) {
const { list } = videoData;
//
contentByCategory.value[categoryValue] = list.map(video => ({
contentByCategory.value[categoryValue] = list.map((video) => ({
id: video.id || video.uuid,
title: video.title || video.name,
name: video.name || video.title
name: video.name || video.title,
}));
console.log(`分类 ${categoryValue} 的内容:`, contentByCategory.value[categoryValue]);
console.log(
`分类 ${categoryValue} 的内容:`,
contentByCategory.value[categoryValue]
);
}
} catch (error) {
console.error('加载分类视频失败:', error);
console.error("加载分类视频失败:", error);
}
};
@ -515,13 +562,13 @@
try {
// API
//const selectedTags = filterTags.value.filter(tag => tag.selected).map(tag => tag.id).join(',');
console.log('请求参数:', {
console.log("请求参数:", {
page: currentPage.value,
pageSize: pageSize.value,
keywords: keywords.value,
sort: sort.value,
typeUuid: typeUuid.value,
tags: keywords.value
tags: keywords.value,
});
const response = await api.videoByKeyWordsNew({
@ -532,7 +579,7 @@
typeUuid: typeUuid.value,
});
console.log('视频列表API原始响应:', response);
console.log("视频列表API原始响应:", response);
//
let videoData = {};
@ -546,11 +593,11 @@
videoData = response.data || {};
}
console.log('解析后的视频数据:', videoData);
console.log("解析后的视频数据:", videoData);
if (videoData && videoData.list) {
const { list, pageNumber, totalPage } = videoData;
console.log('视频列表数据:', list);
console.log("视频列表数据:", list);
if (isRefresh) {
videoList.value = list || [];
@ -561,14 +608,12 @@
//const { list, pageNumber,totalPage } = videoData;
hasMoreData.value = totalPage > pageNumber;
loadMoreStatus.value = hasMoreData.value ? 'more' : 'noMore';
loadMoreStatus.value = hasMoreData.value ? "more" : "noMore";
} else {
throw new Error(response?.message || '获取数据失败');
throw new Error(response?.message || "获取数据失败");
}
} catch (error) {
console.error('加载视频失败:', error);
console.error("加载视频失败:", error);
} finally {
loading.value = false;
refreshing.value = false;
@ -588,7 +633,7 @@
videoList.value = [...videoList.value, ...mockData.list];
}
hasMoreData.value = mockData.hasMore;
loadMoreStatus.value = hasMoreData.value ? 'more' : 'noMore';
loadMoreStatus.value = hasMoreData.value ? "more" : "noMore";
} finally {
loading.value = false;
refreshing.value = false;
@ -607,7 +652,7 @@
const onLoadMore = () => {
if (!hasMoreData.value || loading.value) return;
loadMoreStatus.value = 'loading';
loadMoreStatus.value = "loading";
currentPage.value++;
loadVideoData();
};
@ -626,12 +671,10 @@
const videoId = video.id || video.uuid;
navTo({
url: `/pages_app/videoDetail/videoDetail?id=${videoId}`
url: `/pages_app/videoDetail/videoDetail?id=${videoId}`,
});
};
//
// const goSearch = () => {
// uni.navigateTo({
@ -642,26 +685,26 @@
//
const goPatientVideo = () => {
navTo({
url: '/pages_app/patientVideo/patientVideo'
url: "/pages_app/patientVideo/patientVideo",
});
};
//
const searchVideos = async (keywords) => {
if (!keywords || keywords.trim() === '') {
if (!keywords || keywords.trim() === "") {
loadVideoData(true);
return;
}
try {
console.log('搜索关键词:', keywords.trim());
console.log("搜索关键词:", keywords.trim());
const response = await api.videoByKeyWordsNew({
keywords: keywords.trim(),
page: 1,
pageSize: pageSize.value
pageSize: pageSize.value,
});
console.log('搜索API原始响应:', response);
console.log("搜索API原始响应:", response);
//
let searchData = {};
@ -675,26 +718,25 @@
searchData = response.data || {};
}
console.log('解析后的搜索数据:', searchData);
console.log("解析后的搜索数据:", searchData);
if (searchData && searchData.list) {
const { list, totalPage, pageNumber } = searchData;
videoList.value = list || [];
hasMoreData.value = totalPage > pageNumber;
console.log('hasMoreData:'+hasMoreData.value)
loadMoreStatus.value = hasMoreData.value ? 'more' : 'noMore';
console.log("hasMoreData:" + hasMoreData.value);
loadMoreStatus.value = hasMoreData.value ? "more" : "noMore";
currentPage.value = 1;
}
} catch (error) {
console.error('搜索视频失败:', error);
console.error("搜索视频失败:", error);
uni.showToast({
title: '搜索失败,请重试',
icon: 'none'
title: "搜索失败,请重试",
icon: "none",
});
}
};
const onSwiperChange = (e) => {
currentBannerIndex.value = e.detail.current;
};
@ -703,7 +745,7 @@
const videoId = banner.id || banner.uuid;
navTo({
url: `/pages_app/videoDetail/videoDetail?id=${videoId}`
url: `/pages_app/videoDetail/videoDetail?id=${videoId}`,
});
};
@ -717,15 +759,17 @@
};
const selectCategory = async (categoryValue) => {
selectedCategory.value = categoryValue;
console.log(yearList.value)
console.log('选择分类:', categoryValue);
let all=[{uuid:'',name:'全部视频'}];
console.log(yearList.value);
console.log("选择分类:", categoryValue);
let all = [{ uuid: "", name: "全部视频" }];
for (var i = 0; i < yearList.value.length; i++) {
if (categoryValue == yearList.value[i].name) {
console.log(yearList.value[i]);
filteredContent.value=categoryValue=='全部'?all.concat(yearList.value[i].list):yearList.value[i].list;
console.log(filteredContent.value)
filteredContent.value =
categoryValue == "全部"
? all.concat(yearList.value[i].list)
: yearList.value[i].list;
console.log(filteredContent.value);
break;
}
}
@ -733,7 +777,7 @@
const selectContent = (content) => {
//
console.log('选中内容:', content);
console.log("选中内容:", content);
closeAllVideoPopup();
Object.assign(selectYearContent, content);
typeUuid.value = content.uuid;
@ -754,16 +798,16 @@
const toggleTag = (index) => {
filterTags.value[index].selected = !filterTags.value[index].selected;
isFilterActive.value = filterTags.value.some(tag => tag.selected);
isFilterActive.value = filterTags.value.some((tag) => tag.selected);
};
const resetFilter = () => {
//
filterTags.value.forEach(tag => tag.selected = false);
filterTags.value.forEach((tag) => (tag.selected = false));
//
isFilterActive.value = false;
//
keywords.value = '';
keywords.value = "";
//
currentPage.value = 1;
hasMoreData.value = true;
@ -771,21 +815,18 @@
};
const confirmFilter = () => {
let str='';
const selectedTags = filterTags.value.filter(tag => tag.selected);
console.log('选中的筛选标签:', selectedTags);
let str = "";
const selectedTags = filterTags.value.filter((tag) => tag.selected);
console.log("选中的筛选标签:", selectedTags);
for (var i = 0; i < selectedTags.length; i++) {
if (str) {
str+=","+selectedTags[i].NAME
str += "," + selectedTags[i].NAME;
} else {
str=selectedTags[i].NAME
str = selectedTags[i].NAME;
}
}
keywords.value = str;
console.log('keywords:'+keywords.value)
console.log("keywords:" + keywords.value);
isFilterActive.value = true;
hideFilterPopup();
//
@ -805,22 +846,31 @@
const index = startIndex + i;
mockList.push({
id: `video_${index}`,
title: index === 0 ? '《2025年版慢加急性肝衰竭指南》解读' :
index % 4 === 1 ? '自身免疫性肝病专栏免疫治疗的双刃剑——1例自…' :
index % 4 === 2 ? '徐医感染:硬化出血发热路,关关难过关关过' :
index % 4 === 3 ? '徐医感染:一场呼吸的迷局' :
'南京市第二医院疑难肝病病理读片会暨疑难肝病MDT',
thumbnail: '/static/video-thumb-' + (index % 4 + 1) + '.png',
author: index % 3 === 0 ? '首都医…' :
index % 3 === 1 ? '徐州医…' : '南京市…',
title:
index === 0
? "《2025年版慢加急性肝衰竭指南》解读"
: index % 4 === 1
? "自身免疫性肝病专栏免疫治疗的双刃剑——1例自…"
: index % 4 === 2
? "徐医感染:硬化出血发热路,关关难过关关过"
: index % 4 === 3
? "徐医感染:一场呼吸的迷局"
: "南京市第二医院疑难肝病病理读片会暨疑难肝病MDT",
thumbnail: "/static/video-thumb-" + ((index % 4) + 1) + ".png",
author:
index % 3 === 0
? "首都医…"
: index % 3 === 1
? "徐州医…"
: "南京市…",
viewCount: Math.floor(Math.random() * 2000) + 100,
duration: '15:30'
duration: "15:30",
});
}
resolve({
list: mockList,
hasMore: page <2 // 模拟5页数据
hasMore: page < 2, // 5
});
}, 1000);
});
@ -830,23 +880,22 @@
uni.navigateBack({
fail() {
uni.redirectTo({
url: '/pages/index/index'
url: "/pages/index/index",
});
}
},
});
}
};
const toggleSort = () => {
sort.value = sort.value === 1 ? 2 : 1; // 1=, 2=
currentPage.value = 1;
hasMoreData.value = true;
loadVideoData(true);
};
</script>
<style scoped lang="scss">
$primary-color: #ff6b6b;
$theme-color: #8B2316;
$theme-color: #8b2316;
$white: #fff;
$gray-bg: #f5f5f5;
$gray-light: #eee;
@ -902,7 +951,8 @@
z-index: 100;
}
.header-left, .header-right {
.header-left,
.header-right {
display: flex;
align-items: center;
}
@ -910,17 +960,21 @@
.header-title {
font-size: 36rpx;
font-weight: 600;
color: #8B4513;
color: #8b4513;
}
/* Scroll View */
.scroll-view {
position: fixed;
bottom: 0rpx;
height: calc(100vh - var(--status-bar-height) - 54px - 430rpx); /* 固定高度减去固定的banner和Filter Tabs空间 */
height: calc(
100vh - var(--status-bar-height) - 54px - 430rpx
); /* 固定高度减去固定的banner和Filter Tabs空间 */
background-color: #f5f5f5;
margin-bottom: 200rpx;
top: calc(var(--status-bar-height) + 54px + 400rpx); /* 为固定的banner和Filter Tabs留出空间 */
top: calc(
var(--status-bar-height) + 54px + 400rpx
); /* 为固定的banner和Filter Tabs留出空间 */
}
/* Banner Styles */
@ -981,7 +1035,7 @@
}
.tab-item.active .tab-text {
color: #E74C3C;
color: #e74c3c;
font-weight: 600;
}
@ -998,8 +1052,7 @@
white-space: nowrap;
}
.tab-item .tab-text.active {
color: #8B2316;
color: #8b2316;
}
/* Fixed Banner Container */
.banner-container {
@ -1033,7 +1086,7 @@
border-radius: 50%;
}
.circle.active {
background-color: #8B2316;
background-color: #8b2316;
}
}
}
@ -1042,7 +1095,9 @@
/* Fixed Filter Tabs Container */
.filter-tabs-container {
position: fixed;
top: calc(var(--status-bar-height) + 44px + 400rpx); /* banner-container top + banner height */
top: calc(
var(--status-bar-height) + 44px + 400rpx
); /* banner-container top + banner height */
left: 0;
right: 0;
z-index: 40;
@ -1143,8 +1198,6 @@
height: 100%;
}
.video-duration {
margin-top: 8rpx;
}
@ -1232,7 +1285,6 @@
z-index: 1000;
display: flex;
}
.popup-content {
@ -1242,7 +1294,6 @@
background-color: #fff;
overflow: scroll;
}
.popup-header {
@ -1292,8 +1343,7 @@
.category-item.active {
background-color: #fff;
color: #8B2316;
color: #8b2316;
}
.category-label {
@ -1330,11 +1380,8 @@
border: 2rpx solid transparent;
}
.content-item.active {
color: #8B2316;
color: #8b2316;
}
.empty-content {

View File

@ -40,11 +40,13 @@
class="player-wrapper"
:src="videoSrc"
:videoHeight="220"
:videoWidth="videoWidth"
:seekTime="0"
@fullscreenchange="onFullscreenChange"
/>
<!-- 标签切换 -->
<cover-view class="tabs" v-if="from != 'download'" :style="{ opacity: isFullScreen ? 0: 1 }">
<cover-view class="tabs" v-if="from != 'download'" :style="{ opacity:isFullScreen?0:1, width: videoWidth + 'px' }" >
<cover-view
class="tab"
:class="{ active: activeTab === 'info' }"
@ -958,7 +960,6 @@ $theme-color: #8b2316;
position: relative;
top: calc(var(--status-bar-height) + 44px);
z-index: 0;
overflow: hidden;
}
.share-img {
@ -1034,7 +1035,7 @@ $theme-color: #8b2316;
}
.intro {
// background: #fff;
padding: 30rpx 28rpx 100rpx;
padding: 40rpx 28rpx 100rpx;
// margin-top: calc(var(--status-bar-height) + 44px + 220px + 88rpx);
// height: calc(100vh - var(--status-bar-height) - 44px - 220px - 88rpx);
// overflow-y: scroll;
@ -1056,9 +1057,7 @@ $theme-color: #8b2316;
.video-author {
font-size: 26rpx;
color: #666;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}

View File

@ -13,7 +13,6 @@
<view class="zhinan-page" v-if="tab == 'zhinan'">
<!-- 导航栏 -->
<!-- 固定搜索栏 -->
<view class="search-container-fixed filter-bar">
<view class="search-box" @click="goSearch">
@ -24,7 +23,11 @@
<view class="divider"></view>
<view class="filter-item" @click="showFilterPopup">
<text>筛选</text>
<up-image :src="isFilterActive ? filterOn : filter" width="30rpx" height="30rpx" ></up-image>
<up-image
:src="isFilterActive ? filterOn : filter"
width="30rpx"
height="30rpx"
></up-image>
</view>
</view>
@ -37,7 +40,11 @@
@click="enterCategory(item)"
>
<view class="item-image">
<image :src="docUrl+item.imgs" mode="widthFix" class="category-icon"></image>
<image
:src="docUrl + item.imgs"
mode="widthFix"
class="category-icon"
></image>
</view>
<view class="item-content">
<text class="category-title">{{ item.name }}</text>
@ -50,12 +57,10 @@
<view class="count"> {{ total }}份文献</view>
<up-image :src="star2" width="85rpx" height="9rpx"></up-image>
</view>
</view>
<view class="qikan-page" v-else-if="tab == 'qikan'">
<!-- 导航头部 -->
<!-- 主要内容区域 -->
<view class="main-content">
<!-- 标签切换区域 -->
@ -68,7 +73,12 @@
>
<text class="tab-text">代查文献</text>
<view class="tab-underline">
<up-image :src="activeImg" width="48rpx" height="18rpx" v-if="activeTab === 'daichawenxian'"></up-image>
<up-image
:src="activeImg"
width="48rpx"
height="18rpx"
v-if="activeTab === 'daichawenxian'"
></up-image>
</view>
</view>
<view
@ -78,7 +88,12 @@
>
<text class="tab-text">英文文献</text>
<view class="tab-underline">
<up-image :src="activeImg" width="48rpx" height="18rpx" v-if="activeTab === 'yingwenwenxian'"></up-image>
<up-image
:src="activeImg"
width="48rpx"
height="18rpx"
v-if="activeTab === 'yingwenwenxian'"
></up-image>
</view>
</view>
</view>
@ -168,12 +183,19 @@
</view>
<!-- 删除按钮 -->
<view class="delbox" v-if="literatureList.length > 1" @click="removeLiterature(index)">
<view
class="delbox"
v-if="literatureList.length > 1"
@click="removeLiterature(index)"
>
<up-image :src="delImg" width="40rpx" height="52rpx"></up-image>
</view>
<!-- 文献分隔线 -->
<view class="literature-divider" v-if="index < literatureList.length - 1"></view>
<view
class="literature-divider"
v-if="index < literatureList.length - 1"
></view>
</view>
<!-- 添加代查文献按钮 -->
<view class="add-literature-section" v-if="literatureList.length < 5">
@ -183,17 +205,27 @@
</view>
<view class="limit-tip">
<view class="imgbox">
<up-image :src="countImg" width="186rpx" height="74rpx"></up-image>
<up-image
:src="countImg"
width="186rpx"
height="74rpx"
></up-image>
</view>
<view class="count">还可添加{{ 5 - literatureList.length }}</view>
<view class="count"
>还可添加{{ 5 - literatureList.length }}</view
>
</view>
</view>
</view>
<!-- 常见问题 -->
<view class="faq-section">
<up-image :src="questionImg" width="100%" mode="widtFix" height="540rpx"></up-image>
<up-image
:src="questionImg"
width="100%"
mode="widtFix"
height="540rpx"
></up-image>
</view>
<view class="tips">
<view class="title">注意</view>
@ -202,8 +234,12 @@
<view class="row">不支持模糊代查请尽可能详细提供所需文献信息</view>
</view>
<view class="btnbox">
<up-image :src="submitImg" width="100%" height="160rpx" mode="widtFix"></up-image>
<up-image
:src="submitImg"
width="100%"
height="160rpx"
mode="widtFix"
></up-image>
</view>
</view>
@ -215,12 +251,8 @@
</view>
</view>
</view>
</view>
<!-- 筛选弹窗 -->
<view class="filter-popup" v-if="showFilter" @click="hideFilterPopup">
<view class="filter-content" @click.stop>
@ -247,35 +279,52 @@
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { onShow } from "@dcloudio/uni-app";
import upImg from "@/static/cb_up.png"
import downImg from "@/static/cb_up.png"
import filter from "@/static/cb_screen_no.png"
import filterOn from "@/static/cb_screen_yes.png"
import star1 from "@/static/xingxing1.png"
import star2 from "@/static/xingxing2.png"
import paperImg from "@/static/paper_bg.png"
import activeImg from "@/static/route.png"
import emailImg from "@/static/email_bg.png"
import countImg from "@/static/sheng_bg.png"
import questionImg from "@/static/paper_question.png"
import submitImg from "@/static/paper_submit.png"
import delImg from "@/static/delete_paper.png"
import api from '@/api/api.js'
import docUrl from "@/utils/docUrl.js"
import navTo from '@/utils/navTo.js';
import navBar from "@/components/navBar/navBar.vue"
import { ref, onMounted } from "vue";
import { onShow, onBackPress } from "@dcloudio/uni-app";
import upImg from "@/static/cb_up.png";
import downImg from "@/static/cb_up.png";
import filter from "@/static/cb_screen_no.png";
import filterOn from "@/static/cb_screen_yes.png";
import star1 from "@/static/xingxing1.png";
import star2 from "@/static/xingxing2.png";
import paperImg from "@/static/paper_bg.png";
import activeImg from "@/static/route.png";
import emailImg from "@/static/email_bg.png";
import countImg from "@/static/sheng_bg.png";
import questionImg from "@/static/paper_question.png";
import submitImg from "@/static/paper_submit.png";
import delImg from "@/static/delete_paper.png";
import api from "@/api/api.js";
import docUrl from "@/utils/docUrl.js";
import navTo from "@/utils/navTo.js";
import navBar from "@/components/navBar/navBar.vue";
const total = ref(0);
const tab=ref('zhinan')
const tab = ref("zhinan");
//
const searchText = ref('');
const searchText = ref("");
const guidelineCategories = ref([]);
const isFilterActive=ref(false)
const isFilterActive = ref(false);
// 使
const searchLibraryList = ref([]);
const filterTags = ref([]);
const keywords = ref('');
const keywords = ref("");
onBackPress(() => {
try {
uni.sendNativeEvent(
"goTabbarPage",
{
msg: "home",
},
(ret) => {
console.log(ret);
}
);
} catch (e) {
console.log(e);
}
plus.runtime.quit();
return true;
});
//
onMounted(() => {
loadGuideTypes();
@ -288,28 +337,32 @@
showFilter.value = true;
};
const goSearch = () => {
uni.sendNativeEvent('goHomeSearch', {
msg: 'goHomeSearch'
},ret => {
uni.sendNativeEvent(
"goHomeSearch",
{
msg: "goHomeSearch",
},
(ret) => {
console.log(ret);
})
}
);
};
const hideFilterPopup = () => {
showFilter.value = false;
};
const toggleTag = (index) => {
filterTags.value[index].selected = !filterTags.value[index].selected;
isFilterActive.value = filterTags.value.some(tag => tag.selected);
isFilterActive.value = filterTags.value.some((tag) => tag.selected);
};
const resetFilter = () => {
//
filterTags.value.forEach(tag => tag.selected = false);
filterTags.value.forEach((tag) => (tag.selected = false));
//
isFilterActive.value = false;
//
keywords.value = '';
keywords.value = "";
//
// currentPage.value = 1;
// hasMoreData.value = true;
@ -317,24 +370,22 @@
};
const confirmFilter = () => {
const selectedTags = filterTags.value.filter(tag => tag.selected);
console.log('选中的筛选标签:', selectedTags);
const selectedTags = filterTags.value.filter((tag) => tag.selected);
console.log("选中的筛选标签:", selectedTags);
for (var i = 0; i < selectedTags.length; i++) {
if (keywords.value) {
keywords.value+=","+selectedTags[i].NAME
keywords.value += "," + selectedTags[i].NAME;
} else {
keywords.value=selectedTags[i].NAME
keywords.value = selectedTags[i].NAME;
}
navTo({
url:'/pages_app/hot/hot?keywords='+encodeURIComponent(keywords.value)
})
url: "/pages_app/hot/hot?keywords=" + encodeURIComponent(keywords.value),
});
}
isFilterActive.value = true;
hideFilterPopup();
//
};
onShow(() => {
@ -348,11 +399,10 @@
const res = await api.guideType({});
guidelineCategories.value = res.data;
for (var i = 0; i < res.data.length; i++) {
total.value=total.value+res.data[i].total
total.value = total.value + res.data[i].total;
}
} catch (e) {
console.error('加载指南分类失败:', e);
console.error("加载指南分类失败:", e);
}
};
@ -363,14 +413,13 @@
page: 1,
pageSize: 20,
type: 1,
keywords:'',
keywords: "",
});
if (res && res.code === 200) {
searchLibraryList.value = res.data
searchLibraryList.value = res.data;
}
} catch (e) {
console.error('加载指南库失败:', e);
console.error("加载指南库失败:", e);
}
};
@ -378,38 +427,38 @@
const loadGuideTags = async () => {
try {
const res = await api.guideTag({
type:3
type: 3,
});
console.log('指南标签API响应:', res);
console.log("指南标签API响应:", res);
if (res && res.code === 200 && res.data) {
// API
filterTags.value = res.data.map(tag => ({
filterTags.value = res.data.map((tag) => ({
...tag,
selected: false
selected: false,
}));
console.log('指南标签加载成功:', filterTags.value);
console.log("指南标签加载成功:", filterTags.value);
}
} catch (e) {
console.error('加载指南标签失败:', e);
console.error("加载指南标签失败:", e);
}
};
//
const enterCategory = (item) => {
navTo({
url: `/pages_app/zhinanList/zhinanList?typeUuid=${item.uuid}&title=${item.name}`
url: `/pages_app/zhinanList/zhinanList?typeUuid=${item.uuid}&title=${item.name}`,
});
};
//
const showFilterDialog = () => {
console.log('显示筛选');
console.log("显示筛选");
//
};
//
const switchTab = (tabName) => {
console.log('切换到:', tabName);
console.log("切换到:", tabName);
tab.value = tabName;
};
@ -418,49 +467,50 @@
uni.navigateBack({
fail() {
uni.redirectTo({
url: '/pages/index/index'
url: "/pages/index/index",
});
}
},
});
};
//
const activeTab = ref('daichawenxian');
const activeTab = ref("daichawenxian");
//
const formData = ref({
email: '',
literatureName: '',
author: '',
journalName: ''
email: "",
literatureName: "",
author: "",
journalName: "",
});
//
const literatureList = ref([
{
id: 1,
literatureName: '',
author: '',
journalName: ''
}
literatureName: "",
author: "",
journalName: "",
},
]);
//
const faqList = ref([
{
question: '如何查找文献?',
answer: '请提供准确的文献标题、作者和期刊信息,我们将为您查找并发送到指定邮箱。',
expanded: false
question: "如何查找文献?",
answer:
"请提供准确的文献标题、作者和期刊信息,我们将为您查找并发送到指定邮箱。",
expanded: false,
},
{
question: '查找需要多长时间?',
answer: '通常在1-3个工作日内完成文献查找并发送到您的邮箱。',
expanded: false
question: "查找需要多长时间?",
answer: "通常在1-3个工作日内完成文献查找并发送到您的邮箱。",
expanded: false,
},
{
question: '支持哪些文献类型?',
answer: '支持国内外期刊论文、会议论文、学位论文等多种文献类型。',
expanded: false
}
question: "支持哪些文献类型?",
answer: "支持国内外期刊论文、会议论文、学位论文等多种文献类型。",
expanded: false,
},
]);
//
@ -470,14 +520,14 @@
//
const switchBottomTab = (tab) => {
if (tab === 'zhinan') {
if (tab === "zhinan") {
uni.navigateTo({
url: '/pages_app/zhinan/zhinan'
url: "/pages_app/zhinan/zhinan",
});
} else if (tab === 'tools') {
} else if (tab === "tools") {
uni.showToast({
title: '功能开发中',
icon: 'none'
title: "功能开发中",
icon: "none",
});
}
};
@ -486,24 +536,24 @@
const addLiterature = () => {
if (literatureList.value.length >= 5) {
uni.showToast({
title: '最多只能添加5篇文献',
icon: 'none'
title: "最多只能添加5篇文献",
icon: "none",
});
return;
}
const newLiterature = {
id: Date.now(), // 使ID
literatureName: '',
author: '',
journalName: ''
literatureName: "",
author: "",
journalName: "",
};
literatureList.value.push(newLiterature);
uni.showToast({
title: '添加成功',
icon: 'none'
title: "添加成功",
icon: "none",
});
};
@ -511,8 +561,8 @@
const removeLiterature = (index) => {
if (literatureList.value.length <= 1) {
uni.showToast({
title: '至少保留一篇文献',
icon: 'none'
title: "至少保留一篇文献",
icon: "none",
});
return;
}
@ -520,8 +570,8 @@
literatureList.value.splice(index, 1);
uni.showToast({
title: '删除成功',
icon: 'none'
title: "删除成功",
icon: "none",
});
};
@ -533,14 +583,14 @@
<style lang="scss" scoped>
// SCSS Variables
$primary-color: #8B2316;
$primary-color: #8b2316;
$bg-color: #f5f5f5;
$white: #fff;
$text-primary: #333;
$text-secondary: #666;
$text-light: #999;
$primary-color: #ff6b6b;
$theme-color: #8B2316;
$theme-color: #8b2316;
$white: #fff;
$gray-bg: #f5f5f5;
$gray-light: #eee;
@ -554,7 +604,7 @@ $border-radius: 8px;
$border-radius-small: 6px;
$padding: 15px;
$padding-small: 10px;
$accent-color: #4A90E2;
$accent-color: #4a90e2;
.zhinan-page {
background-color: $bg-color;
min-height: 100vh;
@ -621,7 +671,9 @@ $accent-color: #4A90E2;
padding: 30rpx;
margin: 0 30rpx;
margin-top: calc(var(--status-bar-height) + 44px + 106rpx); // (80rpx + )
margin-top: calc(
var(--status-bar-height) + 44px + 106rpx
); // (80rpx + )
.guideline-item {
margin-top: 20rpx;
@ -694,7 +746,7 @@ $accent-color: #4A90E2;
gap: 8rpx;
&.active {
color: #fff;
background-color: #8B2316;
background-color: #8b2316;
}
.tab-icon {
width: 44rpx;
@ -706,7 +758,6 @@ $accent-color: #4A90E2;
color: $text-secondary;
&.active {
color: #fff;
}
}
}
@ -755,7 +806,6 @@ $accent-color: #4A90E2;
background-color: #a5d9fe;
padding: 0 30rpx;
.tab-container {
display: flex;
align-items: center;
@ -786,8 +836,6 @@ $accent-color: #4A90E2;
right: 0;
transform: translateX(-50%);
height: 18rpx;
}
}
}
@ -802,7 +850,7 @@ $accent-color: #4A90E2;
//
.header-banner {
background: linear-gradient(135deg, #87CEEB, #B0E0E6);
background: linear-gradient(135deg, #87ceeb, #b0e0e6);
margin: 20rpx 30rpx;
border-radius: 20rpx;
padding: 40rpx 30rpx;
@ -844,14 +892,12 @@ $accent-color: #4A90E2;
//
.form-section {
margin: -156rpx 30rpx 20rpx;
border-radius: 20rpx;
padding: 0rpx 0rpx;
.wenxian {
margin-top: 40rpx;
overflow: hidden;
}
.from-cell {
@ -889,7 +935,6 @@ $accent-color: #4A90E2;
}
.form-group {
margin-bottom: 40rpx;
display: flex;
@ -915,7 +960,8 @@ $accent-color: #4A90E2;
.input-container {
flex: 1;
.form-input,.form-textarea{
.form-input,
.form-textarea {
width: 100%;
height: 80rpx;
padding: 0 20rpx;
@ -958,7 +1004,6 @@ $accent-color: #4A90E2;
.formbox .form-group:nth-child(1) {
margin-bottom: 40rpx;
}
}
//
@ -1019,7 +1064,6 @@ $accent-color: #4A90E2;
background-color: $white;
border-radius: 20rpx;
padding: 1rpx 1rpx;
}
.tips {
font-size: 24rpx;
@ -1127,5 +1171,4 @@ $accent-color: #4A90E2;
}
}
}
</style>