feat: 添加热门行业组件,优化推荐列表和搜索功能

This commit is contained in:
傅光孟 2026-02-08 16:33:14 +08:00
parent d09945c70c
commit d3cfb99c62
6 changed files with 183 additions and 172 deletions

View File

@ -2,10 +2,10 @@
ENV = development ENV = development
# 本地环境接口地址 # 本地环境接口地址
# VITE_API_URL = http://123.60.153.169:8040/apih5 VITE_API_URL = http://123.60.153.169:8040/apih5
# VITE_API_URL = http://4155gf93ll13.vicp.fun/apih5 # VITE_API_URL = http://4155gf93ll13.vicp.fun/apih5
# VITE_API_URL = http://123.60.79.143:8041/apih5 # VITE_API_URL = http://123.60.79.143:8041/apih5
# VITE_API_URL =http://192.168.0.135:8040/apih5 # VITE_API_URL =http://192.168.0.135:8040/apih5
VITE_API_URL = https://cankao.cs.com.cn/apih5 # VITE_API_URL = https://cankao.cs.com.cn/apih5
VITE_API_DATAV_URL = https://cankao.cs.com.cn/zzck_datav VITE_API_DATAV_URL = https://cankao.cs.com.cn/zzck_datav

View File

@ -91,7 +91,6 @@ export const fetchEtfDetail = (data: any) => {
return Request.post("/news/etfList", data); return Request.post("/news/etfList", data);
}; };
// 海外先机 // 海外先机
export const getForeignList = (data: any) => { export const getForeignList = (data: any) => {
return Request.get("/news/exclusiveList", data); return Request.get("/news/exclusiveList", data);
@ -99,5 +98,11 @@ export const getForeignList = (data: any) => {
// 编辑精选 // 编辑精选
export const getRecommendList = (data: any) => { export const getRecommendList = (data: any) => {
return Request.get("/news/curatedList", data); return Request.get("/news/curatedList", { params: data });
}; };
// 宏观知微
export const getMacroList = (data: any) => {
return Request.get("/news/globalMacroList", { params: data });
};

View File

@ -16,72 +16,117 @@
<!-- 标题 end --> <!-- 标题 end -->
<view class="page-main"> <view class="page-main">
<view class="news-list"> <u-loading-icon v-if="loading"></u-loading-icon>
<view class="news-item"> <view class="news-list" v-else-if="data?.length > 0">
<template v-for="(item, index) in data" :key="index">
<view
:class="['news-item', { mask: !userStore.isLogin }]"
v-for="news in item.list"
:key="news.id"
@click="goDetail(news)"
>
<view class="title"> <view class="title">
<view class="icon">宏观</view> <view class="icon">宏观</view>
<view class="name"> <view class="name">
行业龙头最新财报行业龙头最新财报行业龙头最新财报行业龙头最新财报 {{ news.title }}
</view> </view>
</view> </view>
<view class="content"> <view :class="['content', { mask: isMask }]">
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元 {{ news.summary }}
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元
</view> </view>
<view class="source"> <view :class="['source', { mask: isMask }]">
<view>中国证券报</view> <view>{{ news.source }}</view>
<view>2025-06-23 10:00</view> <view>{{ news.timeStr }}</view>
</view>
</view>
<view class="news-item">
<view class="title">
<view class="icon">宏观</view>
<view class="name">
行业龙头最新财报行业龙头最新财报行业龙头最新财报行业龙头最新财报
</view>
</view>
<view class="content">
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元
</view>
<view class="source">
<view>中国证券报</view>
<view>2025-06-23 10:00</view>
</view>
</view>
<view class="news-item">
<view class="title">
<view class="icon">宏观</view>
<view class="name">
行业龙头最新财报行业龙头最新财报行业龙头最新财报行业龙头最新财报
</view>
</view>
<view class="content">
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元
</view>
<view class="source">
<view>中国证券报</view>
<view>2025-06-23 10:00</view>
</view> </view>
</view> </view>
</template>
</view> </view>
<u-empty v-else />
</view> </view>
<!-- 登录弹窗 start -->
<LoginDialog
:show="LoginShow"
@onSuccess="handleLoginSuccess"
@onCancel="handleLoginCancel"
@onError="handleLoginError"
/>
<!-- 登录弹窗 end -->
</view> </view>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { getMacroList } from "@/api";
import { useUserStore } from "@/stores/user";
import { computed, onMounted, ref } from "vue";
import LoginDialog from "@/components/loginPopup/index.vue";
// //
const handleBack = () => { const handleBack = () => {
uni.navigateBack({ uni.navigateBack({
delta: 1, delta: 1,
}); });
}; };
const userStore = useUserStore();
// |
const isMask = computed(() => {
return !userStore.isUserType;
});
const LoginShow = ref(false);
//
const handleShowLogin = () => {
LoginShow.value = true;
};
//
const handleLoginCancel = () => {
LoginShow.value = false;
};
//
const handleLoginSuccess = () => {
LoginShow.value = false;
};
//
const handleLoginError = () => {
console.log("登录失败");
};
//
function goDetail(item: any) {
if (!userStore.isLogin) {
handleShowLogin();
return;
}
//
if (!userStore.isUserType) {
return;
}
uni.navigateTo({
url: `/pages/detail/indexNewsInfo?id=${item.id}`,
});
}
const data = ref([]);
const loading = ref(false);
const getList = async () => {
loading.value = true;
const result = await getMacroList({});
loading.value = false;
if (result.code === 200) {
const { list, total } = result.data;
data.value = list;
} else {
data.value = [];
}
};
onMounted(async () => {
if (!userStore.isLogin) {
handleShowLogin();
}
getList();
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@ -151,6 +196,10 @@ const handleBack = () => {
overflow: hidden; overflow: hidden;
box-sizing: border-box; box-sizing: border-box;
.mask {
filter: blur(5px);
}
.news-item { .news-item {
width: 100%; width: 100%;
margin-bottom: 30rpx; margin-bottom: 30rpx;

View File

@ -14,7 +14,7 @@
<!-- 资讯榜 end --> <!-- 资讯榜 end -->
<!-- 热门行业 start --> <!-- 热门行业 start -->
<HotNewsView @on-show="handleShowLogin" /> <IndustryNewsView @on-show="handleShowLogin" />
<!-- 热门行业 end --> <!-- 热门行业 end -->
<!-- 风口概念 start --> <!-- 风口概念 start -->
@ -45,7 +45,7 @@ import { ref, onMounted, onUnmounted, reactive } from "vue";
import HeaderView from "./components/HeaderView/index.vue"; import HeaderView from "./components/HeaderView/index.vue";
import BannerNewsView from "./components/BannerNewsView/index.vue"; import BannerNewsView from "./components/BannerNewsView/index.vue";
import TopNewsView from "./components/TopNewsView/index.vue"; import TopNewsView from "./components/TopNewsView/index.vue";
import HotNewsView from "./components/HotNewsView/index.vue"; import IndustryNewsView from "./components/IndustryNewsView/index.vue";
import ConceptNewsView from "./components/ConceptNewsView/index.vue"; import ConceptNewsView from "./components/ConceptNewsView/index.vue";
import TodayNewsView from "./components/TodayNewsView/index.vue"; import TodayNewsView from "./components/TodayNewsView/index.vue";
import FooterView from "./components/FooterView/index.vue"; import FooterView from "./components/FooterView/index.vue";

View File

@ -20,7 +20,7 @@
<!-- 搜索 start --> <!-- 搜索 start -->
<view class="page-search"> <view class="page-search">
<u-input <u-input
v-model="input" v-model="keyword"
type="text" type="text"
placeholder="搜索资讯" placeholder="搜索资讯"
prefixIcon="search" prefixIcon="search"
@ -30,140 +30,76 @@
borderRadius: '36rpx', borderRadius: '36rpx',
background: '#F3F5F8', background: '#F3F5F8',
}" }"
@confirm="handleSearch"
/> />
</view> </view>
<!-- 时间轴 start --> <!-- 时间轴 start -->
<view class="page-timeline"> <view class="page-timeline">
<view class="timeline"> <view
:class="['timeline', { mask: !userStore.isLogin }]"
v-for="item in data"
:key="item.day"
>
<view class="line"></view> <view class="line"></view>
<view class="content"> <view class="content">
<view class="date">2025/11/26</view> <view class="date">{{ item.day }}</view>
<view class="news-list"> <view class="news-list">
<view class="news"> <view
class="news"
v-for="news in item.list"
:key="news.id"
@click="goDetail(news)"
>
<view class="news-top"> <view class="news-top">
<view class="time">09:30:00</view> <view class="time">{{ news.timeStr }}</view>
<view class="source"> <view class="source" v-if="news.source">
<view class="star" :style="{ width: `${4 * 20}rpx` }"></view> <!-- <view class="star" :style="{ width: `${4 * 20}rpx` }"></view> -->
<view class="t-1">来自</view> <view class="t-1">来自</view>
<view class="t-2">中国证券报</view> <view class="t-2">{{ news.source }}</view>
</view> </view>
</view> </view>
<view class="news-title"> <view class="news-title">
<view class="name"> <view class="name">
<text class="text" <text class="text">{{ news.title }}</text>
>行业龙头最新财报行业龙头最新财报行业龙头最新财报行业龙头最新财报</text </view>
</view>
<view :class="['news-content', { mask: isMask }]">
{{ news.summary }}
</view>
<view :class="['tags', { mask: isMask }]">
<text class="tag">{{ news.companyName }}</text>
</view>
<view
:class="['events-collapse']"
v-if="news.furtherReadings?.length > 0"
> >
</view>
</view>
<view class="news-content">
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元
</view>
<view class="tags">
<text class="tag">#苹果产业链</text>
<text class="tag">#苹果产业链</text>
</view>
<view class="events-collapse">
<view class="events-collapse-top active"> <view class="events-collapse-top active">
<view class="t-1">事件梳理</view> <view class="t-1">事件梳理</view>
<view class="t-2">收起</view> <view
</view> v-if="!selectKeys.includes(news.id)"
<view v-show="a" class="events-list"> class="t-2"
<view class="events-item"> @click="handleOpenEvents(news.id)"
<view class="events-item-line"></view> >展开</view
<view class="events-item-content"> >
<view class="events-content-date">11/24</view> <view v-else class="t-2" @click="handleCloseEvents(news.id)"
<view class="events-content-text"> >收起</view
特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳
</view>
</view>
</view>
<view class="events-item">
<view class="events-item-line"></view>
<view class="events-item-content">
<view class="events-content-date">11/24</view>
<view class="events-content-text">
特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳
</view>
</view>
</view>
<view class="events-item">
<view class="events-item-line"></view>
<view class="events-item-content">
<view class="events-content-date">11/24</view>
<view class="events-content-text">
特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="timeline">
<view class="line"></view>
<view class="content">
<view class="date">2025/11/26</view>
<view class="news-list">
<view class="news">
<view class="news-top">
<view class="time">09:30:00</view>
<view class="source">
<view class="star" :style="{ width: `${4 * 20}rpx` }"></view>
<view class="t-1">来自</view>
<view class="t-2">中国证券报</view>
</view>
</view>
<view class="news-title">
<view class="name">
<text class="text"
>行业龙头最新财报行业龙头最新财报行业龙头最新财报行业龙头最新财报</text
> >
</view> </view>
</view> <view
<view class="news-content"> v-show="selectKeys.includes(news.id)"
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元 :class="['events-list', { mask: isMask }]"
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元 >
英伟达发布2026财年三季度业绩及四季度指引均超市场预期收入方场预期收入方面三亿美元 <view
</view> class="events-item"
<view class="tags"> v-for="further in news.furtherReadings"
<text class="tag">#苹果产业链</text> :key="further.id"
<text class="tag">#苹果产业链</text> >
</view>
<view class="events-collapse">
<view class="events-collapse-top">
<view class="t-1">事件梳理</view>
<view class="t-2">展开</view>
</view>
<view v-show="!a" class="events-list">
<view class="events-item">
<view class="events-item-line"></view> <view class="events-item-line"></view>
<view class="events-item-content"> <view class="events-item-content">
<view class="events-content-date">11/24</view> <view class="events-content-date">{{ further.timeStr }}</view>
<view class="events-content-text"> <view class="events-content-text">
特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳 {{ further.title }}
</view>
</view>
</view>
<view class="events-item">
<view class="events-item-line"></view>
<view class="events-item-content">
<view class="events-content-date">11/24</view>
<view class="events-content-text">
特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳
</view>
</view>
</view>
<view class="events-item">
<view class="events-item-line"></view>
<view class="events-item-content">
<view class="events-content-date">11/24</view>
<view class="events-content-text">
特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳特斯拉Optimus行走视频流出步态稳
</view> </view>
</view> </view>
</view> </view>
@ -193,7 +129,6 @@ import { getRecommendList } from "@/api";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import { computed, onMounted, ref } from "vue"; import { computed, onMounted, ref } from "vue";
import LoginDialog from "@/components/loginPopup/index.vue"; import LoginDialog from "@/components/loginPopup/index.vue";
const input = ref("");
// //
const handleBack = () => { const handleBack = () => {
uni.navigateBack({ uni.navigateBack({
@ -201,10 +136,19 @@ const handleBack = () => {
}); });
}; };
const selectKeys = ref([]);
const handleOpenEvents = (id: string) => {
selectKeys.value.push(id);
};
const handleCloseEvents = (id: string) => {
selectKeys.value = selectKeys.value.filter((item) => item !== id);
};
const userStore = useUserStore(); const userStore = useUserStore();
// | // |
const isMask = computed(() => { const isMask = computed(() => {
return !userStore.isLogin || !userStore.isUserType; return !userStore.isUserType;
}); });
const LoginShow = ref(false); const LoginShow = ref(false);
@ -244,7 +188,9 @@ function goDetail(item: any) {
const data = ref([]); const data = ref([]);
const getList = async () => { const getList = async () => {
const result = await getRecommendList({}); const result = await getRecommendList({
keyword: keyword.value,
});
if (result.code === 200) { if (result.code === 200) {
const { list, total } = result.data; const { list, total } = result.data;
data.value = list; data.value = list;
@ -253,6 +199,11 @@ const getList = async () => {
} }
}; };
const keyword = ref("");
const handleSearch = () => {
getList();
};
onMounted(async () => { onMounted(async () => {
if (!userStore.isLogin) { if (!userStore.isLogin) {
handleShowLogin(); handleShowLogin();
@ -335,6 +286,7 @@ onMounted(async () => {
.page-main { .page-main {
position: relative; position: relative;
width: 100%; width: 100%;
min-height: calc(100vh - 400rpx);
padding: 30rpx 30rpx 0; padding: 30rpx 30rpx 0;
background: #f3f5f8; background: #f3f5f8;
border-radius: 24rpx 24rpx 0px 0px; border-radius: 24rpx 24rpx 0px 0px;
@ -363,9 +315,14 @@ onMounted(async () => {
position: relative; position: relative;
z-index: 3; z-index: 3;
.mask {
filter: blur(5px);
}
.timeline { .timeline {
z-index: 2; z-index: 2;
display: flex; display: flex;
.line { .line {
position: relative; position: relative;
top: 12rpx; top: 12rpx;