cankao-h5/src/pages/topNews/index.vue

537 lines
13 KiB
Vue

<template>
<view class="page-container">
<!-- 导航栏 start -->
<view class="custom-bav-bar">
<view class="left">
<u-icon name="arrow-left" color="#fff" size="36rpx" @click="handleBack" />
</view>
<view class="center"> 智能资讯榜 </view>
</view>
<!-- 导航栏 end -->
<!-- 24小时榜 start -->
<view class="radar-container">
<view class="title">24h AI追踪海外资讯</view>
<RadarChat />
<view
style="
display: flex;
align-items: center;
justify-content: flex-end;
margin-right: 15rpx;
font-size: 30rpx;
gap: 10rpx;
margin-top: 20rpx;
"
@click="showCalendar"
>
{{ chooseDate.startDate.split(" ")[0] }}
<u-icon name="calendar" size="26" style="margin-right: 10rpx"></u-icon>
</view>
</view>
<!-- 24小时榜 end -->
<view v-if="!loading" :class="['page-main ', { mask: !userStore.isLogin }]">
<view class="news-list-top">
<view
class="news-item"
v-for="(item, index) in newsListTop"
:key="item.news_id"
@click="goDetail(item)"
>
<view class="news-no"> {{ index + 1 }} </view>
<view class="news-info">
<view class="news-title">
<view class="title">{{ item.title }}</view>
<view class="score">{{ item.news_score }}</view>
</view>
<view class="news-cont">
{{ item.summary }}
</view>
<view class="source">
<view class="t-1">{{ item.source }}</view>
<view class="t-2">{{
dayjs(item.publish_time).format("YYYY-MM-DD hh:mm:ss")
}}</view>
</view>
</view>
</view>
</view>
<view class="news-list">
<view
class="news-item"
v-for="(item, index) in newsList"
:key="item.news_id"
@click="goDetail(item)"
>
<view class="news-no"> {{ index + 1 + topNum }} </view>
<view class="news-title">
{{ item.title }}
</view>
<view class="news-score">{{ item.news_score }}</view>
</view>
<view class="more-btn" v-if="!isExpAll" @click="handleShowAll">
<view class="text">查看更多</view>
</view>
</view>
<view class="more-loading" v-if="moreLoading">
<u-loading-icon
mode="circle"
text="AI正在实时计算剩余资讯"
textSize="26rpx"
textColor="#999999"
color="rgba(23, 119, 255, 1)"
size="28rpx"
></u-loading-icon>
</view>
</view>
<u-loading-icon
v-else
mode="circle"
text="加载中"
textSize="26rpx"
textColor="#999999"
color="rgba(23, 119, 255, 1)"
size="28rpx"
></u-loading-icon>
<!-- 日历 -->
<view v-if="calendarShow">
<u-calendar
:show="true"
:min-date="calendar.minDate"
:max-date="calendar.maxDate"
:monthNum="calendar.monthNum"
:default-date="chooseDate.startDate"
closeOnClickOverlay
@confirm="calendarConfirm"
@close="hideCalendar"
>
</u-calendar>
</view>
<!-- 登录弹窗 start -->
<LoginDialog
:show="LoginShow"
@onSuccess="handleLoginSuccess"
@onCancel="handleLoginCancel"
@onError="handleLoginError"
/>
<!-- 登录弹窗 end -->
</view>
</template>
<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch } from "vue";
import { getTopNews } from "@/api/newsInfo";
import dayjs from "dayjs";
import { useUserStore } from "@/stores/user";
import RadarChat from "@/components/charts/Radar.vue";
import LoginDialog from "@/pages/realtimeInfo/components/LoginPopup/index.vue";
const userStore = useUserStore(); // 登录弹框
const LoginShow = ref(false);
// 显示弹框
const handleShowLogin = () => {
LoginShow.value = true;
};
// 关闭弹框
const handleLoginCancel = () => {
LoginShow.value = false;
};
// 登录成功之后的回调
const handleLoginSuccess = () => {
LoginShow.value = false;
};
// 登录失败之后的回调
const handleLoginError = () => {
console.log("登录失败");
};
// 获取数据
const loading = ref(false);
const isExpAll = ref(false);
const topNum = 3; // 前置高量数
const lastNewsIndex = ref(10); // 控制 取前10条数据 和 取所有数据
const newsListAll = ref([]); // 全部新闻
const limit_num = ref(1000);
const moreLoading = ref(false);
// 获取前置数据
const newsListTop = computed(() => {
const _data = newsListAll.value.slice(0, topNum);
return _data;
});
// 获取剩余数据
const newsList = computed(() => {
const _data = newsListAll.value.slice(topNum, lastNewsIndex.value);
return _data;
});
// 获取更多数据
const handleShowAll = async () => {
isExpAll.value = true;
moreLoading.value = true;
// 模拟加载数据
await new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, 500);
}).then(() => {
moreLoading.value = false;
});
// 获取所有新闻
lastNewsIndex.value = newsListAll.value.length;
};
// 日期格式
const formatDateStart = "YYYY-MM-DD 00:00:00";
const formatDateEnd = "YYYY-MM-DD 23:59:59";
// 日历初始数据
const calendar = reactive({
minDate: "2025-01-01",
maxDate: dayjs().format(formatDateEnd),
monthNum: Math.ceil(dayjs().diff("2025-01-01", "month", true)),
});
// 选择的日期
const chooseDate = reactive({
startDate: dayjs().format(formatDateStart),
endDate: dayjs().format(formatDateEnd),
});
// 日历显示
const calendarShow = ref(false);
function showCalendar() {
if (!userStore.isLogin || !userStore.isUserType) return;
calendarShow.value = true;
}
// 隐藏日历
function hideCalendar() {
calendarShow.value = false;
}
function calendarConfirm(dateList: string[]) {
if (dateList && dateList.length > 0) {
chooseDate.startDate = dayjs(dateList[0]).format(formatDateStart);
chooseDate.endDate = dayjs(dateList[dateList.length - 1]).format(formatDateEnd);
}
getNewsList();
calendarShow.value = false;
isExpAll.value = false;
lastNewsIndex.value = 10;
}
async function getNewsList() {
const params = {
start_date: chooseDate.startDate,
end_date: chooseDate.endDate,
limit_num: limit_num.value,
};
loading.value = true;
try {
const result = await getTopNews(params);
newsListAll.value = result;
} catch (e) {
console.log(e);
} finally {
loading.value = false;
}
}
// 跳转详情
function goDetail(item: any) {
if (userStore.isLogin) {
uni.navigateTo({
url: `/pages/detail/indexNewsInfo?id=${item.news_id}`,
});
} else {
handleShowLogin();
}
}
// 导航栏路由返回
const handleBack = () => {
uni.navigateBack({
delta: 1,
});
};
onMounted(() => {
getNewsList();
});
</script>
<style scoped lang="scss">
.page-container {
width: 100%;
min-height: 100vh;
padding-bottom: 20rpx;
background-color: #f3f5f8;
background-image: url("@/assets/images/page/page6_pic@2x.png");
background-size: 100% auto;
background-repeat: no-repeat;
box-sizing: border-box;
}
.custom-bav-bar {
width: 100%;
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
position: relative;
.back_icon {
width: 36rpx;
height: 36rpx;
}
.logo_icon {
width: 168rpx;
height: 36rpx;
margin-right: 6rpx;
}
.left {
position: absolute;
top: 24rpx;
left: 32rpx;
}
.center {
display: flex;
align-items: center;
justify-content: center;
font-family: "PingFangSC, PingFang SC";
font-weight: 500;
font-size: 34rpx;
color: #ffffff;
line-height: 36rpx;
text-align: center;
}
}
.radar-container {
// min-height: 600rpx;
margin: 38rpx 20rpx 20rpx;
padding: 39rpx 0 30rpx;
background-image: linear-gradient(180deg, rgba(194, 214, 253, 0.96) 0%, #ffffff 50%);
box-shadow: inset 0px 1px 0px 0px #ffffff;
border-radius: 20px;
backdrop-filter: blur(10px);
box-sizing: border-box;
.title {
width: 329rpx;
padding: 14rpx 30rpx;
margin: 0 auto;
background: #ffffff;
border-radius: 32rpx;
border: 1px solid #e7e7e7;
font-family: "PingFangSC, PingFang SC";
font-weight: 500;
font-size: 26rpx;
color: #666666;
line-height: 38rpx;
text-align: center;
box-sizing: border-box;
}
}
.page-main {
&.mask {
filter: blur(5px);
}
.news-list-top {
margin: 0 20rpx;
.news-item {
display: flex;
padding: 30rpx;
margin-bottom: 20rpx;
background: #ffffff;
box-shadow: inset 0px 2rpx 0px 0px #ffffff;
border-radius: 20rpx;
.news-no {
flex: 0 0 35rpx;
height: 46rpx;
margin-right: 15rpx;
background-image: url("@/assets/images/page/icon_no1@2x.png");
background-repeat: no-repeat;
background-size: 35rpx 46rpx;
text-indent: -999em;
overflow: hidden;
}
&:nth-child(1) {
.news-no {
background-image: url("@/assets/images/page/icon_no1@2x.png");
}
}
&:nth-child(2) {
.news-no {
background-image: url("@/assets/images/page/icon_no2@2x.png");
}
}
&:nth-child(3) {
.news-no {
background-image: url("@/assets/images/page/icon_no3@2x.png");
}
}
}
.news-info {
.news-title {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 14rpx;
.title {
width: 505rpx;
font-family: "PingFangSC, PingFang SC";
font-weight: 500;
font-size: 30rpx;
color: #222222;
line-height: 42rpx;
text-align: left;
font-style: normal;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.score {
font-family: "AlimamaShuHeiTi, AlimamaShuHeiTi";
font-weight: bold;
font-size: 30rpx;
color: #3f80fa;
line-height: 42rpx;
text-align: right;
font-style: normal;
}
}
.news-cont {
margin-bottom: 16rpx;
font-family: "PingFangSC, PingFang SC";
font-weight: 400;
font-size: 24rpx;
color: #333333;
line-height: 33rpx;
text-align: justify;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.source {
display: flex;
align-items: center;
justify-content: space-between;
.t-1 {
font-family: "PingFangSC, PingFang SC";
font-weight: 400;
font-size: 24rpx;
color: #999999;
line-height: 33rpx;
margin-right: 4rpx;
color: #666666;
}
.t-2 {
font-family: "PingFangSC, PingFang SC";
font-weight: 400;
font-size: 24rpx;
color: #999999;
line-height: 33rpx;
}
}
}
}
.news-list {
padding-bottom: 20rpx;
margin: 0 20rpx;
background: #ffffff;
box-shadow: inset 0px 2rpx 0px 0px #ffffff;
border-radius: 20rpx;
.news-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx 0;
margin: 0 30rpx;
border-bottom: 2rpx solid #f3f3f5;
.news-no {
flex: 0 0 35rpx;
height: 42rpx;
margin-right: 15rpx;
font-family: "PingFangSC, PingFang SC";
font-weight: 500;
font-size: 30rpx;
color: #e98254;
line-height: 42rpx;
text-align: center;
}
.news-title {
width: 505rpx;
font-family: "PingFangSC, PingFang SC";
font-weight: 500;
font-size: 30rpx;
color: #222222;
line-height: 42rpx;
text-align: left;
font-style: normal;
}
.news-score {
font-family: "AlimamaShuHeiTi, AlimamaShuHeiTi";
font-weight: bold;
font-size: 30rpx;
color: #3f80fa;
line-height: 42rpx;
text-align: right;
font-style: normal;
}
}
}
.more-btn {
margin-top: 22rpx;
display: flex;
justify-content: center;
align-items: center;
.text {
padding-right: 31rpx;
background: url("@/assets/images/page/grey_down@2x.png") no-repeat right center;
background-size: 21rpx 11rpx;
font-family: "PingFangSC, PingFang SC";
font-weight: 400;
font-size: 28rpx;
color: #666666;
line-height: 40rpx;
text-align: center;
}
}
.more-loading {
padding: 30rpx 0;
}
}
</style>