2025-09-23 19:00:32 +08:00

715 lines
17 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="zhinan-list-page">
<!-- 头部导航栏 -->
<uni-nav-bar
left-icon="left"
:title="title"
@clickLeft="goBack"
fixed
color="#8B2316"
height="140rpx"
:border="false"
backgroundColor="#eeeeee"
>
<template v-slot:right>
<view class="nav-right" @click="goGot">
<up-image :src="hotImg" width="40rpx" height="40rpx" ></up-image>
</view>
</template>
</uni-nav-bar>
<!-- 固定搜索栏 -->
<view class="search-container-fixed filter-bar">
<view class="search-box" @click="goToSearch">
<uni-icons type="search" size="16" color="#999"></uni-icons>
<text class="search-text">搜索</text>
</view>
<view class="divider"></view>
<view class="current-sort" @click="toggleInnerSort">
<text class="sort-text">{{ innerSortTitle }}</text>
<view class="imgbox">
<up-image :src="upImg" width="26rpx" height="26rpx" ></up-image>
</view>
</view>
</view>
<!-- 使用scroll-view实现列表 -->
<scroll-view
class="guidelines-scroll-view"
scroll-y="true"
:refresher-enabled="true"
:refresher-triggered="isRefreshing"
@refresherrefresh="onRefresh"
@scrolltolower="onScrollToLower"
:show-scrollbar="false"
>
<!-- 指南列表 -->
<view class="guidelines-list">
<view
class="guideline-item"
v-for="(item, index) in guidelinesList"
:key="item.uuid || index"
@click="viewGuideline(item)"
>
<!-- 指南信息 -->
<view class="item-content">
<view class="item-title">{{ item.title }}</view>
<view class="item-bottom">
<view class="item-date">{{ formatDate(item.releaseTime) }}</view>
<!-- 操作按钮 -->
<view class="item-action">
<view
class="download-btn"
@click.stop="viewGuideline(item)"
>
<up-icon name="download" color="#8D2316" size="28"></up-icon>
</view>
<!-- <view
v-else
class="view-btn"
@click.stop="viewGuideline(item)"
>
查看
</view> -->
</view>
</view>
</view>
</view>
</view>
<!-- 加载更多状态 -->
<view class="load-more-status">
<view v-if="loadMoreStatus === 'loading'" class="loading">
<uni-icons type="spinner-cycle" size="20" color="#999"></uni-icons>
<text>加载中...</text>
</view>
<view v-else-if="loadMoreStatus === 'more'" class="more">
<text>上拉加载更多</text>
</view>
<view v-else-if="loadMoreStatus === 'noMore'" class="no-more">
<text>没有更多数据了</text>
</view>
</view>
<!-- 无数据提示 -->
<view class="no-data" v-if="guidelinesList.length === 0 && !isLoading">
<uni-icons type="info" size="60" color="#999"></uni-icons>
<text>暂无诊疗指南数据</text>
</view>
</scroll-view>
</view>
<!-- 组内排序弹窗 -->
<view v-if="showInnerSort" class="popup-panel">
<view class="popup-item" :class="{ active:sort==1 }" @click.stop="chooseInnerSort(1)">
<text class="item-text">下载量</text>
<uni-icons v-if="sort==1" type="checkmarkempty" color="#8B2316" size="22"></uni-icons>
</view>
<view class="popup-divider"></view>
<view class="popup-item" :class="{ active:sort==2 }" @click.stop="chooseInnerSort(2)">
<text class="item-text">上传时间</text>
<uni-icons v-if="sort==2" type="checkmarkempty" color="#8B2316" size="22"></uni-icons>
</view>
<view class="popup-divider"></view>
<view class="popup-item" :class="{ active:sort==3 }" @click.stop="chooseInnerSort(3)">
<text class="item-text">标题</text>
<uni-icons v-if="sort==3" type="checkmarkempty" color="#8B2316" size="22"></uni-icons>
</view>
</view>
</template>
<script setup>
import { ref, onMounted} from 'vue'
import api from '@/api/api.js'
import { onShow,onLoad } from "@dcloudio/uni-app";
import docUrl from "@/utils/docUrl.js"
import navTo from "@/utils/navTo.js"
import hotImg from "@/static/hot_booklist.png"
// 响应式数据
const guidelinesList = ref([])
const isLoading = ref(false)
const hasMoreData = ref(true)
const currentPage = ref(1)
const pageSize = ref(10)
const isRefreshing = ref(false)
const keywords=ref('');
import upImg from "@/static/triangle_green_theme.png"
import downImg from "@/static/triangle_normal.png"
const loadMoreStatus = ref('more') // 'loading', 'more', 'noMore'
const typeUuid=ref('');
const title=ref('');
const sort=ref(2);
const showInnerSort=ref(false);
const innerSortTitle=ref('上传时间');
const chooseInnerSort=(index)=>{
sort.value=index;
if(index==1){
innerSortTitle.value='下载量';
}else if(index==2){
innerSortTitle.value='上传时间';
}else if(index==3){
innerSortTitle.value='标题';
}
showInnerSort.value=false;
loadGuidelinesList(true);
}
onLoad((options)=>{
console.log(options)
if(options.typeUuid){
typeUuid.value=options.typeUuid;
}
if(options.title){
title.value=options.title;
}
if(options.keywords){
keywords.value=decodeURIComponent(options.keywords);
title.value=decodeURIComponent(options.title);
}
})
const goGot=()=>{
navTo({
url:'/pages_app/hot/hot?from=hot&typeUuid='+typeUuid.value
})
}
const toggleInnerSort=()=>{
showInnerSort.value=!showInnerSort.value;
}
onShow(() => {
// 页面显示时,如果列表为空则加载数据
if (guidelinesList.value.length === 0) {
loadGuidelinesList(true)
}
})
// 跳转到搜索页
const goToSearch = () => {
const q = keywords.value ? encodeURIComponent(keywords.value) : ''
const t = title.value ? encodeURIComponent(title.value) : ''
const type = typeUuid.value ? `&typeUuid=${encodeURIComponent(typeUuid.value)}` : ''
uni.navigateTo({
url: `/pages_app/search/search?keywords=${q}&title=${t}${type}`
})
}
// scroll-view 下拉刷新
const onRefresh = async () => {
console.log('scroll-view 下拉刷新触发');
isRefreshing.value = true;
await refreshData();
isRefreshing.value = false;
};
// scroll-view 滚动到底部
const onScrollToLower = () => {
console.log('=== onScrollToLower 触发 ===');
console.log('当前状态:', {
loadMoreStatus: loadMoreStatus.value,
isRefreshing: isRefreshing.value,
currentPage: currentPage.value,
listLength: guidelinesList.value.length,
hasMoreData: hasMoreData.value,
isLoading: isLoading.value
});
if (loadMoreStatus.value === 'more' && !isRefreshing.value && !isLoading.value) {
console.log('条件满足,开始加载更多数据');
loadMoreData();
} else {
console.log('条件不满足,跳过加载:', {
loadMoreStatus: loadMoreStatus.value,
isRefreshing: isRefreshing.value,
isLoading: isLoading.value
});
}
};
// 刷新数据
const refreshData = async () => {
try {
currentPage.value = 1
hasMoreData.value = true
loadMoreStatus.value = 'more'
await loadGuidelinesList(true)
uni.showToast({
title: '刷新成功',
icon: 'none'
})
} catch (error) {
console.error('刷新失败:', error)
uni.showToast({
title: '刷新失败',
icon: 'none'
})
}
}
// 加载指南列表
const loadGuidelinesList = async (isRefresh = false) => {
console.log('=== loadGuidelinesList 开始 ===');
console.log('当前参数:', { isRefresh, page: currentPage.value, keywords: keywords.value });
if (isLoading.value) return
try {
isLoading.value = true
loadMoreStatus.value = 'loading'
const params = {
page: currentPage.value,
pageSize: pageSize.value,
type: 1, // 诊疗指南类型
sort:2,
typeUuid:typeUuid.value,
keywords:keywords.value
}
const res = await api.searchLibraryU(params)
console.log('指南列表响应:', res)
if (res.code === 200 && res.data) {
const newData = res.data.list || res.data
if (isRefresh) {
guidelinesList.value = newData
console.log('刷新模式:替换列表数据');
} else {
guidelinesList.value = [...guidelinesList.value, ...newData]
console.log('加载更多:追加数据到列表');
}
// 判断是否还有更多数据
if (newData.length < pageSize.value) {
loadMoreStatus.value = 'noMore'
hasMoreData.value = false
console.log('没有更多数据了');
} else {
loadMoreStatus.value = 'more'
hasMoreData.value = true
// 只有在加载更多模式下才递增页码
if (!isRefresh) {
currentPage.value++
console.log(`还有更多数据,下一页: ${currentPage.value}`);
}
}
} else {
console.error('加载指南列表失败:', res.message)
loadMoreStatus.value = 'noMore'
uni.showToast({
title: res.message || '加载失败',
icon: 'none'
})
}
} catch (error) {
console.error('加载指南列表异常:', error)
loadMoreStatus.value = 'noMore'
uni.showToast({
title: '网络异常,请重试',
icon: 'none'
})
} finally {
isLoading.value = false
console.log('=== loadGuidelinesList 结束 ===');
console.log('最终状态:', {
loadMoreStatus: loadMoreStatus.value,
page: currentPage.value,
listLength: guidelinesList.value.length
});
}
}
// 加载更多数据
const loadMoreData = () => {
console.log('=== loadMoreData 被调用 ===');
console.log('检查条件:', {
hasMoreData: hasMoreData.value,
isLoading: isLoading.value,
currentPage: currentPage.value
});
if (hasMoreData.value && !isLoading.value) {
console.log('条件满足,开始加载更多数据');
loadGuidelinesList(false);
} else {
console.log('条件不满足,跳过加载更多');
}
}
// 下载指南
const downloadGuideline = (item) => {
console.log('下载指南:', item)
uni.showToast({
title: '开始下载...',
icon: 'none'
})
// 这里可以调用下载API
// 示例下载PDF文件
if (item.file_path) {
uni.downloadFile({
url: item.file_path,
success: (res) => {
if (res.statusCode === 200) {
uni.showToast({
title: '下载成功',
icon: 'none'
})
}
},
fail: (err) => {
console.error('下载失败:', err)
uni.showToast({
title: '下载失败',
icon: 'none'
})
}
})
}
}
// 查看指南支持常用文档直链pdf/doc/docx/xls/xlsx/ppt/pptx/txt
const viewGuideline = (item) => {
const url = docUrl+item.path
if (url) {
const isPDF = /\.(pdf)(\?|$)/i.test(url)
const isOffice = /\.(docx?|xlsx?|pptx?)(\?|$)/i.test(url)
const isText = /\.(txt)(\?|$)/i.test(url)
// H5 端
// #ifdef H5
if (isPDF) {
try { window.open(url, '_blank') } catch (e) {
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
}
return
}
if (isOffice) {
const officeUrl = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)}`
try { window.open(officeUrl, '_blank') } catch (e) {
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(officeUrl)}` })
}
return
}
if (isText) {
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
return
}
// 其他格式统一用 webview 打开
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
return
// #endif
// 非 H5 端:下载后尝试用 openDocument失败回退 webview
// #ifndef H5
uni.showToast({ title: '正在打开...', icon: 'none' })
uni.downloadFile({
url,
success: (res) => {
if (res.statusCode === 200 && res.tempFilePath) {
uni.openDocument({
filePath: res.tempFilePath,
showMenu: true,
success: () => {},
fail: () => {
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
}
})
} else {
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
}
},
fail: () => {
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
}
})
return
// #endif
}
// 无直链,回退到详情页
}
// 返回上一页
const goBack = () => {
uni.navigateBack()
}
// 测试加载更多功能
const testLoadMore = () => {
console.log('=== 手动测试加载更多 ===');
console.log('当前状态:', {
loadMoreStatus: loadMoreStatus.value,
hasMoreData: hasMoreData.value,
isLoading: isLoading.value,
currentPage: currentPage.value,
listLength: guidelinesList.value.length
});
if (loadMoreStatus.value === 'more' && !isLoading.value) {
loadMoreData();
} else {
uni.showToast({
title: `状态: ${loadMoreStatus.value}, 加载中: ${isLoading.value}`,
icon: 'none',
duration: 2000
});
}
}
// 格式化日期
const formatDate = (dateString) => {
if (!dateString) return ''
try {
const date = new Date(dateString)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
} catch (error) {
return dateString
}
}
</script>
<style lang="scss" scoped>
// 颜色变量
$primary-color: #ff4757;
$text-primary: #333;
$text-secondary: #666;
$text-light: #999;
$border-color: #e0e0e0;
$bg-color: #f6f6f6;
$white: #ffffff;
.imgbox{
width: 32rpx;
margin-top: -10rpx;
}
.popup-panel {
position: fixed;
top: 256rpx; /* 紧贴筛选栏 */
left: 0;
right: 0;
background: #fff;
z-index: 100;
box-shadow: 0 6rpx 20rpx rgba(0,0,0,0.08);
}
.popup-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 28rpx 30rpx;
font-size: 30rpx;
color: #333;
}
.popup-divider {
height: 2rpx;
background: #eaeaea;
}
.popup-item.active .item-text {
color: #8B2316;
}
.current-sort {
display: flex;
align-items: center;
gap: 10rpx;
.sort-text {
font-size: 28rpx;
color: #333;
}
.sort-icon.up {
width: 0;
height: 0;
border-left: 8rpx solid transparent;
border-right: 8rpx solid transparent;
border-bottom: 12rpx solid #999;
&.active {
border-bottom-color: #ff0000;
}
}
}
.zhinan-list-page {
background-color: $bg-color;
height: 100vh;
}
.guidelines-scroll-view {
position: fixed;
top: 242rpx;
left: 0;
right: 0;
bottom: 0;
z-index: 99;
height: calc(100vh - 140rpx);
background-color: $bg-color;
}
// 固定搜索容器
.search-container-fixed {
position: fixed;
top: 140rpx; // 导航栏高度
left: 0;
right: 0;
z-index: 90;
display: flex;
align-items: center;
justify-content: center;
padding: 30rpx 30rpx;
background-color: $white;
gap: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
// 筛选栏
.filter-bar {
background-color: $white;
display: flex;
align-items: center;
border-bottom: 2px solid #eee;
.search-box {
display: flex;
justify-content: center;
align-items: center;
gap: 5px;
.search-text {
font-size: 14px;
color:#999;
}
}
.divider {
width: 1px;
height: 16px;
background-color: #999;
margin: 0 60rpx;
}
.filter-item {
flex:1;
display: flex;
align-items: center;
justify-content: center;
gap: 3px;
font-size: 14px;
color: #999;
}
}
// 指南列表
.guidelines-list {
padding: 20rpx 30rpx;
.guideline-item {
background-color: $white;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
.item-content {
flex: 1;
margin-right: 30rpx;
.item-title {
font-size: 32rpx;
color: $text-primary;
line-height: 1.5;
margin-bottom: 16rpx;
font-weight: 500;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
.item-bottom {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10rpx;
.item-date {
font-size: 26rpx;
color: $text-secondary;
}
.item-action {
display: flex;
align-items: center;
.download-btn {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: rgba(255, 71, 87, 0.1);
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
background-color: rgba(255, 71, 87, 0.2);
}
}
.view-btn {
color:#8B2316;
font-size: 28rpx;
font-weight: 500;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
background-color: darken($primary-color, 10%);
}
}
}
}
}
}
}
// 加载更多状态
.load-more-status {
padding: 20rpx 0;
text-align: center;
.loading, .more, .no-more {
display: flex;
align-items: center;
justify-content: center;
gap: 10rpx;
padding: 20rpx 0;
font-size: 26rpx;
color: $text-light;
}
}
// 无数据提示
.no-data {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 120rpx 0;
text {
margin-top: 30rpx;
font-size: 28rpx;
color: $text-light;
}
}
</style>