feat(新闻详情): 添加摘要图标和AI关联标的展示

- 在新闻摘要前添加摘要图标
- 新增AI关联标的展示区域
- 为ETF列表项添加点击跳转功能
- 优化样式细节和代码格式
This commit is contained in:
34701892@qq.com 2025-11-20 14:08:28 +08:00
parent 6a0db7df63
commit 2b20a82484
5 changed files with 160 additions and 71 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -1,8 +1,8 @@
<template>
<view class="main">
<view class="title" :class="{ 'mohu': !isLogin }">{{ props.data.title }}</view>
<view class="title" :class="{ mohu: !isLogin }">{{ props.data.title }}</view>
<view class="author">
<view class="name" :class="{ 'mohu': !isLogin }">
<view class="name" :class="{ mohu: !isLogin }">
<text class="text">来源:</text>
<text class="text">{{ props.data.tag }}</text>
</view>
@ -11,40 +11,57 @@
<text class="text">编辑:</text>
<text class="text">{{ props.data.editor }}</text>
</view>
<view class="time" :class="{ 'mohu': !isLogin }">{{ props.data.publishTime }}</view>
<view class="time" :class="{ mohu: !isLogin }">{{ props.data.publishTime }}</view>
</view>
<!-- 两个标签 start -->
<view class="r_r_tags" :class="{ 'mohu': !isLogin }">
<view class="r_r_tags" :class="{ mohu: !isLogin }">
<view style="display: flex; margin-top: 20rpx; overflow-x: auto; width: 95vw">
<view class="r_tags">
<view class="tag" style="background-color: #fff9ec; color: #ffb100"
v-for="(item, index) in props.data.conceptLabels" :key="index">{{ item }}</view>
<view
class="tag"
style="background-color: #fff9ec; color: #ffb100"
v-for="(item, index) in props.data.conceptLabels"
:key="index"
>{{ item }}</view
>
</view>
</view>
<view style="display: flex; margin-top: 20rpx; overflow-x: auto; width: 100vw">
<view class="r_tags">
<view class="tag" style="background-color: #f5f8fe; color: #007aff"
v-for="(item, index) in props.data.industryLabels" :key="index">{{ item }}</view>
<view
class="tag"
style="background-color: #f5f8fe; color: #007aff"
v-for="(item, index) in props.data.industryLabels"
:key="index"
>{{ item }}</view
>
</view>
</view>
</view>
<!-- 两个标签 end -->
<!-- 摘要 -->
<view class="desc" v-if="props.data.summary" :class="{ 'mohu': !isLogin }">
<view class="desc" v-if="props.data.summary" :class="{ mohu: !isLogin }">
<!-- <view class="bill_icon"></view> -->
<image :src="zhaiyaoImg" mode="scaleToFill" class="zhaiyao_icon" />
<view>
{{ props.data.summary }}
</view>
</view>
<view class="thumbnail" v-if="props.data.picture">
<image :src="props.data.picture" mode="widthFix" />
</view>
<view style="padding: 35rpx;" :class="{ 'mohu': !isLogin }">
<text class="articleDes" :class="props?.data?.needpay && 'needpay'" style="white-space: pre-wrap;"
v-html="props.data.content">
<view style="padding: 35rpx" :class="{ mohu: !isLogin }">
<text
class="articleDes"
:class="props?.data?.needpay && 'needpay'"
style="white-space: pre-wrap"
v-html="props.data.content"
>
</text>
</view>
@ -55,30 +72,37 @@
>
</view> -->
<view class="r_etf">
<text class="etf_title">AI关联标的</text>
<view class="etfs">
<view v-for="item in data.etfs" class="etf_item">
{{ item.name }}
</view>
</view>
</view>
<LoginPopup :show="LoginShow" @handlePopupClose="handlePopupClose"
@handlePopupSuccessCallback="handlePopupSuccessCallback" @handlePopupErrorCallback="handlePopupErrorCallback" />
<LoginPopup
:show="LoginShow"
@handlePopupClose="handlePopupClose"
@handlePopupSuccessCallback="handlePopupSuccessCallback"
@handlePopupErrorCallback="handlePopupErrorCallback"
/>
</view>
</template>
<script setup lang="ts">
import { ref } from "vue";
import {
onLaunch,
onShow,
onLoad,
onShareAppMessage,
onShareTimeline,
} from "@dcloudio/uni-app";
import { onLaunch, onShow, onLoad, onShareAppMessage, onShareTimeline } from "@dcloudio/uni-app";
import articleMock from "@/mock/article.js";
import LoginPopup from "@/components/loginPopup/index.vue";
import { Session } from "@/utils/storage";
import zhaiyaoImg from "../../assets/zixun/zhaiyao_icon.png";
const isLogin = ref(Session.get('token'))
const isLogin = ref(Session.get("token"));
const props = defineProps({
data: {
type: Object,
default: () => { },
default: () => {},
},
});
const tagList1 = ref([
@ -96,15 +120,14 @@ const LoginShow = ref(false);
//
const handlePopupClose = () => {
LoginShow.value = false;
isLogin.value = Session.get('token');
isLogin.value = Session.get("token");
};
//
const handlePopupSuccessCallback = () => {
isLogin.value = Session.get('token');
console.log("🚀 ~ handlePopupSuccessCallback ~ isLogin.value:", isLogin.value)
isLogin.value = Session.get("token");
console.log("🚀 ~ handlePopupSuccessCallback ~ isLogin.value:", isLogin.value);
};
const tagList2 = ref([
{
name: "医药生物-生物制药",
@ -184,6 +207,7 @@ const handleSub = () => {
.main {
position: relative;
background-color: #fff;
padding-bottom: 120rpx;
.title {
padding-top: 16rpx;
@ -224,15 +248,16 @@ const handleSub = () => {
.desc {
padding: 12rpx;
box-sizing: border-box;
background-color: #f5f5f5;
background-color: #f2f4fa;
width: 700rpx;
margin: 30rpx auto;
color: rgba(51, 51, 51, 0.6);
color: #666666;
// font-size: 28rpx;
font-size: var(--h2-font-size);
// text-indent: 0.5em;
white-space: pre-wrap;
overflow-wrap: break-word;
line-height: 40rpx;
/* 在必要时单词内部断行 */
.bill_icon {
@ -311,4 +336,54 @@ const handleSub = () => {
.mohu {
filter: blur(4px);
}
.zhaiyao_icon {
width: 72rpx;
height: 51rpx;
margin-top: 10rpx;
margin-bottom: 10rpx;
}
.r_etf {
display: flex;
flex-direction: column;
padding: 0 30rpx;
.etfs {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
margin-top: 20rpx;
}
.etf_title {
font-family: PingFangSC, PingFang SC;
font-weight: bold;
font-size: 30rpx;
color: #222222;
line-height: 42rpx;
text-align: left;
font-style: normal;
}
.etf_item {
width: calc(50vw - 80rpx);
height: 64rpx;
background: #edf1f5;
border-radius: 8rpx;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 24rpx;
color: #666666;
line-height: 44rpx;
text-align: left;
font-style: normal;
display: flex;
align-items: center;
justify-content: center;
padding: 5rpx 20rpx;
}
}
</style>

View File

@ -1,11 +1,15 @@
<template>
<view class="comment">
<view class="comment-count">
<view class="count" @click="handleClickLike">
<image
:src="props.data.isLike ? 'https://cankao.obs.cn-east-3.myhuaweicloud.com/mini/newmini/zan_like_fill%402x.png' : 'https://cankao.obs.cn-east-3.myhuaweicloud.com/mini/newmini/zan_like_normal%402x.png'"
class="icon" />
:src="
props.data.isLike
? 'https://cankao.obs.cn-east-3.myhuaweicloud.com/mini/newmini/zan_like_fill%402x.png'
: 'https://cankao.obs.cn-east-3.myhuaweicloud.com/mini/newmini/zan_like_normal%402x.png'
"
class="icon"
/>
<text class="num">点赞</text>
</view>
<!-- <view class="count" @click="handleClickStar">
@ -30,7 +34,7 @@ const messageShow = ref(false);
const props = defineProps({
data: {
type: Object,
default: () => { },
default: () => {},
},
});
@ -40,7 +44,6 @@ const comment = ref("");
//
const handleClickLike = () => {
emit("handleClickLike");
};
//
@ -98,7 +101,6 @@ const handleSubmit = () => {
display: flex;
width: 100vw;
.count {
display: flex;
text-align: center;
@ -122,7 +124,6 @@ const handleSubmit = () => {
}
}
button::after {
border: 0;
}

View File

@ -12,6 +12,7 @@
<!-- 文章正文 start -->
<Article :data="data" />
<!-- 分割 -->
<view class="line"></view>
<!-- 推荐栏目 -->
@ -31,11 +32,7 @@
import { onMounted, ref } from "vue";
import { onLoad, onShow } from "@dcloudio/uni-app";
import { onReachBottom } from "@dcloudio/uni-app";
import {
fetchArticleDetail,
fetchArticleLike,
fetchArticleFavorate,
} from "@/api/detail";
import { fetchArticleDetail, fetchArticleLike, fetchArticleFavorate } from "@/api/detail";
import { getNewsList } from "@/api";
import Article from "@/components/article/indexNewsInfo.vue";
import Column from "@/components/column/index.vue";
@ -66,7 +63,7 @@ onLoad(async (option: any) => {
if (res.code === 200) {
data.value = res.data;
res.data.content = res.data.content.replace(/\n{3,}/g, '\n');
res.data.content = res.data.content.replace(/\n{3,}/g, "\n");
columnName.value = res.data.columnName1;
newList(res.data.columnId1);
@ -90,25 +87,32 @@ const newList = async (columnId: number) => {
//
const handleClickLike = async () => {
console.log("🚀 ~ handleClickLike ~ data.value.isLike:", data.value.isLike)
console.log("🚀 ~ handleClickLike ~ data.value.isLike:", data.value.isLike);
if (data.value.isLike == 1) {
//
aplus_queue.push({
action: 'aplus.record',
arguments: ['canncelLike', 'CLK', {
action: "aplus.record",
arguments: [
"canncelLike",
"CLK",
{
param1: data.value.id,
param2: data.value.title,
}]
},
],
});
} else {
//
aplus_queue.push({
action: 'aplus.record',
arguments: ['doLike', 'CLK', {
action: "aplus.record",
arguments: [
"doLike",
"CLK",
{
param1: data.value.id,
param2: data.value.title,
}]
},
],
});
}
@ -119,9 +123,7 @@ const handleClickLike = async () => {
});
if (res.code === 200) {
data.value.isLike = data.value.isLike ? 0 : 1;
data.value.likeNums = data.value.isLike
? data.value.likeNums + 1
: data.value.likeNums - 1;
data.value.likeNums = data.value.isLike ? data.value.likeNums + 1 : data.value.likeNums - 1;
}
};
@ -133,9 +135,7 @@ const handleClickStar = async () => {
});
if (res.code === 200) {
data.value.isFav = data.value.isFav ? 0 : 1;
data.value.favNums = data.value.isFav
? data.value.favNums + 1
: data.value.favNums - 1;
data.value.favNums = data.value.isFav ? data.value.favNums + 1 : data.value.favNums - 1;
}
};
@ -197,19 +197,22 @@ const { aplus_queue } = window;
onMounted(() => {
aplus_queue.push({
action: 'aplus.sendPV',
arguments: [{ is_auto: false }] //
action: "aplus.sendPV",
arguments: [{ is_auto: false }], //
});
//demo
aplus_queue.push({
action: 'aplus.record',
arguments: ['goDetail', 'CLK', {
action: "aplus.record",
arguments: [
"goDetail",
"CLK",
{
id: data.value.id,
title: data.value.title,
}]
},
],
});
})
});
//
const jumpDetail = (item: any) => {

View File

@ -43,7 +43,7 @@
<view class="left_line"></view>
</view>
<view class="card_right">
<view v-for="item in item.list" :key="item.time">
<view v-for="item in item.list" :key="item.time" @click="goDetail(item)">
<view class="item_time">
<text>{{ item.timeStr }}</text>
<text class="item_source_title">来自 <text class="item_source">中国证券报</text></text>
@ -163,6 +163,16 @@ onReachBottom(() => {
getData();
});
function goDetail(item, index) {
if (Session.get("token")) {
uni.navigateTo({
url: `/pages/detail/indexNewsInfo?id=${item.id}`,
});
} else {
LoginShow.value = true;
}
}
function onSreach() {
if (Session.get("token")) {
form.value.page = 1;