Files
AIProd/pages/Launches/Detail/index.vue

460 lines
11 KiB
Vue
Raw Permalink 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>
<div id="normal-container">
<IntegratedLayout>
<div class="content">
<div class="bread-menu">
<span>AI Launches</span>
<i class="el-icon-arrow-right"></i>
<span class="crumbs gradient-color">{{newsDetail.title || ''}}</span>
</div>
<div class="title-text">{{ newsDetail.title || '' }}</div>
<div class="flex mt-24">
<div class="flex-1">
<div class="terms-item">
<div class="item-title">
<img src="/ToolDetail/icon_star.png" alt="">
<span>Score: </span>
<div class="score color-01">{{ (newsDetail.rating || 0).toFixed(1) }}</div>
</div>
</div>
<div class="terms-item">
<div class="item-title">
<img src="/ToolDetail/icon_note.png" alt="">
<span>Introduction: </span>
</div>
<div class="item-content">
{{ newsDetail.summary || '' }}
</div>
</div>
<div class="terms-item">
<div class="item-title">
<img src="/ToolDetail/icon_clock.png" alt="">
<span>Data update: </span>
</div>
<div class="item-content">{{ formatPublishTime(newsDetail.publishTime || '') }}</div>
</div>
<div class="tags">
<div class="tag-item" v-for="(it, index) in tagList" :key="index">{{ it }}</div>
</div>
</div>
<div class="flex gap-20">
<ThumbBtn :like-count="newsDetail.likeCount || 0" :id="newsDetail.id || 0" type="article" @like-success="refreshToolDetail" />
<CommentBtn :comment-count="commentCount" />
</div>
</div>
<div class="diver"></div>
<div class="container flex">
<div class="left-content flex-1 flex flex-col">
<div class="card flex-1">
<div class="article-content">
<div v-html="newsDetail.content || ''"></div>
</div>
</div>
</div>
<div class="right-content">
<div class="card">
<div class="flex items-center mt-20">
<img alt="" src="/launches/detail/icon_hourse.png" class="icon" />
<div class="content-title">Company Information</div>
</div>
<div class="diver-line"></div>
<div v-if="newsDetail.extra && Array.isArray(newsDetail.extra.socialLinks)" class="mt-30">
<ProjectItem v-for="(item, index) in newsDetail.extra.socialLinks" :key="index" :item="item" />
</div>
<!--<div class="more flex items-center justify-between mt-20">-->
<!-- <div>A total of 8 projects were released</div>-->
<!-- <img src="/launches/detail/icon_arrow.png" alt="" />-->
<!--</div>-->
</div>
<div class="card mt-20">
<div class="flex items-center mt-20">
<img alt="" src="/launches/detail/icon_finance.png" class="icon" />
<div class="content-title">Special Financing</div>
</div>
<div class="diver-line"></div>
<div class="scroll">
<div v-if="newsDetail.extra && Array.isArray(newsDetail.extra.financing)">
<FinanceItem v-for="(item, index) in newsDetail.extra.financing" :key="index" :item="item" :slug="news_slug" />
</div>
</div>
<div class="flex justify-end mt-30">
<div class="more flex items-center justify-between gap-14" @click="goToFinanceDetail">
<div>View more</div>
<img src="/launches/detail/icon_arrow.png" alt="" />
</div>
</div>
</div>
</div>
</div>
<div class="related">
<div class="related-title flex justify-between items-center">
<div class="title">Related Products</div>
<div @click="goToViewMore" class="more pointer">
View more<i class="el-icon-arrow-right"></i>
</div>
</div>
<div class="card">
<div class="list">
<div class="item" v-for="(item, index) in otherList" :key="index">
<RelatedTool :item="item" />
</div>
</div>
</div>
</div>
<Comment comment-type="article" :id="newsDetail.id" @update:commentCount="handleCommentCountUpdate" />
</div>
</IntegratedLayout>
</div>
</template>
<script>
import CommentBtn from "@/pages/ToolDetail/components/CommentBtn.vue";
import Comment from "@/pages/ToolDetail/Comment/index.vue";
import RelatedTool from "@/pages/Launches/Detail/RelatedTool.vue";
import ProjectItem from "@/pages/Launches/Detail/ProjectItem.vue";
import FinanceItem from "@/pages/Launches/Detail/FinanceItem.vue";
import ThumbBtn from "@/pages/ToolDetail/components/ThumbBtn.vue";
export default {
components: {ThumbBtn, FinanceItem, ProjectItem, RelatedTool, CommentBtn, Comment},
data() {
return {
newsDetail: {},
commentCount: 0,
news_slug: '',
otherList: [],
}
},
methods: {
// 刷新工具详情数据
refreshToolDetail() {
if (this.news_slug) {
this.getNewsDetail(this.news_slug);
}
},
// 获取新闻详情
async getNewsDetail(newsSlug) {
const {data: res} = await this.$api.article.getArticleDetail(newsSlug);
const {code, data} = res;
if (code === 0 && data) {
this.newsDetail = {...data, extra: this.stringJsonToObject(data.extra || '[]')};
// 处理socialLinks
if (this.newsDetail.extra && Array.isArray(this.newsDetail.extra.socialLinks)) {
const socialLinks = this.newsDetail.extra.socialLinks;
// 查找Website选项的索引
const websiteIndex = socialLinks.findIndex(item => item && item.key === 'Website');
// 如果找到Website选项且不在第一个位置则移到第一个位置
if (websiteIndex !== -1 && websiteIndex !== 0) {
const websiteItem = socialLinks.splice(websiteIndex, 1)[0];
socialLinks.unshift(websiteItem);
}
}
}
},
formatPublishTime(timeString) {
if (!timeString) return '';
const date = new Date(timeString);
const months = [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
];
const month = months[date.getMonth()];
const day = String(date.getDate()).padStart(2, '0');
const year = date.getFullYear();
return `${month} ${day} ${year}`;
},
stringJsonToObject(str) {
// 将json字符串转为对象捕获错误当str为空或者转对象失败时默认返回空数组
try {
return JSON.parse(str);
} catch (e) {
console.error('Error parsing JSON string:', e);
return [];
}
},
goToViewMore() {
// 返回上一页
this.$router.push('/launches');
},
handleCommentCountUpdate(count) {
this.commentCount = count;
},
goToFinanceDetail() {
if (!this.news_slug) {
return false;
}
this.$router.push('/finance-detail?news_slug=' + this.news_slug)
},
async getArticleListData() {
const params = {page: 1, limit: 4, articleType: 'launches'};
const {data: res} = await this.$api.article.getArticleList(params);
const {code, data} = res;
if (code === 0 && data.list && Array.isArray(data.list)) {
let processedList = [...data.list];
// 判断列表中是否有与当前详情id一致的项
if (this.newsDetail && this.newsDetail.id) {
const currentIdIndex = processedList.findIndex(item => item && item.id === this.newsDetail.id);
if (currentIdIndex !== -1) {
// 有一致的id删除该项
processedList.splice(currentIdIndex, 1);
} else if (processedList.length > 0) {
// 没有一致的id删除最后一个项
processedList = processedList.slice(0, -1);
}
}
this.otherList = processedList;
}
},
async onLoad() {
this.news_slug = this.$route.query.news_slug;
if (this.news_slug) {
await this.getNewsDetail(this.news_slug);
await this.getArticleListData();
}
}
},
watch: {
'$route'(to, from) {
// 当路由参数发生变化时重新加载数据
if (to.query.news_slug !== from.query.news_slug) {
this.onLoad();
}
}
},
mounted() {
this.onLoad();
},
computed: {
tagList() {
if (!this.newsDetail.tags) {
return [];
}
return this.stringJsonToObject(this.newsDetail.tags || '[]');
}
},
}
</script>
<style scoped lang="scss">
.mt-24 {
margin-top: 24px;
}
.color-01 {
color: #7B61FF;
}
.mt-20 {
margin-top: 20px;
}
.mt-30 {
margin-top: 30px;
}
.card {
padding: 20px;
background-color: #FFFFFF;
border-radius: 12px;
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.08);
}
.scroll {
max-height: 500px; overflow-y: auto; overflow-x: hidden;
}
.content {
padding-top: 25px;
padding-bottom: 100px;
.bread-menu {
font-size: $mid-font-size;
font-family: 'Poppins-Medium';
margin-bottom: 25px;
.crumbs {
font-family: 'Poppins-SemiBold';
font-weight: 600;
}
}
.diver {
margin-top: 30px;
border-top: 4px solid #E2E8F0;
margin-bottom: 30px;
}
.title-text {
font-size: 34px;
color: #1E293B;
font-family: 'Poppins-SemiBold';
font-weight: 600;
}
.rate-box {
margin-top: 20px;
display: flex;
align-items: center;
justify-content: space-between;
.btn-wrapper {
display: flex;
align-items: center;
gap: 20px;
}
}
.terms-item {
margin-bottom: 30px;
display: flex;
align-items: flex-start;
gap: 7px;
.item-title {
display: flex;
align-items: center;
gap: 8px;
color: #1E293B;
font-family: 'Poppins-Medium';
img {
width: 24px;
height: 24px;
}
}
.item-content {
font-family: 'Poppins-Regular';
color: #64748B;
}
}
.tags {
display: flex;
overflow-x: auto;
gap: 12px;
scrollbar-width: none;
-ms-overflow-style: none;
user-select: none;
flex-wrap: wrap;
width: 80%;
.tag-item {
font-family: 'Poppins-Medium';
flex-shrink: 0;
padding: 4px 12px;
border-radius: 12px;
@include gradient-border($linear-gradient-start, $linear-gradient-end);
}
}
.container {
gap: 20px;
.right-content {
width: 372px;
.diver-line {
margin-top: 20px;
border-top: 2px solid #E2E8F0;
}
.content-title {
margin-left: 6px;
font-family: 'Poppins-SemiBold';
font-size: 24px;
color: #1E293B;
font-weight: 600;
}
.icon {
width: 24px;
height: 24px;
}
.more {
cursor: pointer;
border-radius: 6px;
padding: 8px 15px;
border: 1px solid #e2e8f0;
font-family: 'Poppins-Regular';
color: #64748B;
&:active {
opacity: 0.8;
}
img {
width: 16px;
height: 16px;
}
}
}
.left-content {
.sketch {
padding: 22px;
background-color: #F5F4FF;
border-radius: 12px;
.text {
font-family: 'Poppins-Regular';
color: #64748B;
font-size: 18px;
}
.more {
cursor: pointer;
border-radius: 6px;
padding: 8px 15px;
border: 1px solid #e2e8f0;
font-family: 'Poppins-Regular';
color: #64748B;
img {
width: 16px;
height: 16px;
}
}
}
}
}
.related {
margin-top: 40px;
.related-title {
.title {
margin-bottom: 20px;
font-size: 30px;
color: #1E293B;
font-family: 'Poppins-SemiBold';
font-weight: 600;
&::before {
content: '';
display: inline-block;
width: 6px;
height: 26px;
background: $header-backgroungd;
margin-right: 8px;
border-radius: 0 6px 6px 0;
}
}
.more {
display: block;
text-align: right;
color: $grey-color;
font-size: $mid-font-size;
font-family: 'Poppins-Regular';
}
}
.list {
gap: 60px;
margin: 40px 10px 40px 10px;
display: grid;
grid-template-columns: repeat(3, 1fr);
.item {
width: 100%;
overflow: hidden;
min-height: 110px;
}
}
}
}
</style>