Files
ai-dimension/client/src/pages/trend/trend.vue
T

367 lines
8.1 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="page-trend page-layout">
<view class="status-bar-placeholder"></view>
<!-- 顶部 -->
<view class="trend-header">
<text class="header-title">AI 趋势</text>
<text class="header-desc">每天精选 AI 行业最新动态</text>
</view>
<!-- 分类筛选 -->
<view class="filter-bar">
<view
class="filter-item"
:class="{ active: activeFilter === idx }"
v-for="(tag, idx) in filters"
:key="idx"
@click="activeFilter = idx"
>
<text>{{ tag }}</text>
</view>
</view>
<!-- 新闻列表 -->
<view class="trend-list">
<view v-for="(item, idx) in displayItems" :key="idx" class="trend-card" @click="goDetail(item)">
<!-- 头部标签 -->
<view class="card-header">
<text class="card-tag" :class="getTagClass(item)">
{{ getTagText(item) }}
</text>
<text class="card-source">{{ item.source }}</text>
</view>
<!-- 标题 -->
<text class="card-title">{{ item.title }}</text>
<!-- 摘要 -->
<text class="card-summary" v-if="item.summary">
{{ item.summary }}
</text>
<!-- 底部信息 -->
<view class="card-footer">
<text class="card-date">{{ formatDate(item.newsDate) }}</text>
<view class="card-stats">
<text class="stat-item" v-if="item.hot">🔥 {{ item.hotCount }}</text>
<text class="stat-item">👁 {{ item.viewCount || 0 }}</text>
</view>
</view>
</view>
<!-- 加载状态 -->
<view v-if="loading" class="loading-state">
<text>加载中...</text>
</view>
<view v-else-if="displayItems.length === 0" class="empty-state">
<text class="empty-icon">📡</text>
<text class="empty-text">暂无趋势资讯</text>
<text class="empty-sub">稍后再来看最新 AI 动态</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { trendApi } from '@/utils/api'
const filters = ref(['全部', '🚀 产品', '📄 论文', '🔧 工具', '🏢 公司'])
const activeFilter = ref(0)
const items = ref([])
const loading = ref(false)
onMounted(() => {
fetchTrends()
})
const displayItems = computed(() => {
if (activeFilter.value === 0) return items.value
const categoryMap = { 1: 'product', 2: 'paper', 3: 'tool', 4: 'company' }
const category = categoryMap[activeFilter.value]
if (!category) return items.value
return items.value.filter(item => item.category === category)
})
async function fetchTrends() {
loading.value = true
try {
const data = await trendApi.list({ limit: 20 })
items.value = data.list || data.items || []
} catch (err) {
console.error('获取趋势失败:', err)
// 降级:本地示例
items.value = getSampleData()
} finally {
loading.value = false
}
}
function getTagText(item) {
if (item.hot) return '🔥 热门'
if (item.picked) return '📌 精选'
if (item.category === 'product') return '🚀 产品'
if (item.category === 'paper') return '📄 论文'
if (item.category === 'tool') return '🔧 工具'
if (item.category === 'company') return '🏢 公司'
return '📰 资讯'
}
function getTagClass(item) {
if (item.hot) return 'hot'
if (item.picked) return 'pick'
if (item.category === 'product') return 'product'
if (item.category === 'paper') return 'paper'
if (item.category === 'tool') return 'tool'
return ''
}
function formatDate(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
const now = new Date()
const diff = now - date
const hours = Math.floor(diff / 3600000)
if (hours < 1) return '刚刚'
if (hours < 24) return `${hours} 小时前`
return `${Math.floor(hours / 24)} 天前`
}
function goDetail(item) {
// 如果有原文链接,跳转外部
if (item.link) {
// 微信小程序不支持直接打开外部链接,复制链接提示
uni.setClipboardData({
data: item.link,
success: () => {
uni.showModal({
title: '打开链接',
content: '链接已复制,请在浏览器中打开',
showCancel: false
})
}
})
return
}
uni.setStorageSync('__news_item__', JSON.stringify(item))
uni.navigateTo({ url: '/pages/news/news' })
}
function getSampleData() {
return [
{
title: 'DeepSeek 发布 R1 推理模型',
summary: 'DeepSeek R1 在多项基准测试中超越 GPT-4o,引发全球关注',
source: '量子位',
newsDate: new Date(Date.now() - 2 * 3600000).toISOString(),
category: 'product',
hot: true,
hotCount: 2000,
viewCount: 15000
},
{
title: 'Google Gemini 1.5 Pro 发布',
summary: '支持 200 万 token 上下文窗口,多模态能力大幅提升',
source: '机器之心',
newsDate: new Date(Date.now() - 6 * 3600000).toISOString(),
category: 'product',
viewCount: 8000
},
{
title: 'Transformer 论文作者新方向',
summary: '从注意力机制到状态空间模型,作者分享最新研究进展',
source: 'PaperWeekly',
newsDate: new Date(Date.now() - 12 * 3600000).toISOString(),
category: 'paper',
picked: true,
viewCount: 5000
}
]
}
</script>
<style lang="scss" scoped>
.page-trend {
height: 100vh;
display: flex;
flex-direction: column;
background: var(--bg-primary);
}
.status-bar-placeholder { height: 44px; }
// 头部
.trend-header {
padding: 10px 20px 16px;
}
.header-title {
font-size: 24px;
font-weight: 700;
color: var(--text-primary);
display: block;
}
.header-desc {
font-size: 12px;
color: var(--text-tertiary);
margin-top: 4px;
display: block;
}
// 筛选栏
.filter-bar {
padding: 0 20px 12px;
white-space: nowrap;
}
.filter-item {
display: inline-block;
padding: 6px 14px;
margin-right: 8px;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 16px;
font-size: 13px;
color: var(--text-secondary);
}
.filter-item.active {
background: rgba(124, 77, 255, 0.15);
border-color: rgba(124, 77, 255, 0.3);
color: var(--dim1-color);
}
// 列表
.trend-list {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
padding: 0 16px 16px;
}
.trend-card {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 14px;
padding: 16px;
margin-bottom: 12px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.card-tag {
font-size: 11px;
padding: 2px 10px;
border-radius: 10px;
font-weight: 500;
}
.card-tag.hot {
background: rgba(239, 83, 80, 0.12);
color: #ef5350;
}
.card-tag.pick {
background: rgba(124, 77, 255, 0.12);
color: #b388ff;
}
.card-tag.product {
background: rgba(0, 188, 212, 0.12);
color: #4dd0e1;
}
.card-tag.paper {
background: rgba(179, 136, 255, 0.12);
color: #b388ff;
}
.card-tag.tool {
background: rgba(77, 182, 172, 0.12);
color: #4db6ac;
}
.card-source {
font-size: 11px;
color: var(--text-muted);
}
.card-title {
font-size: 14px;
font-weight: 600;
color: var(--text-primary);
line-height: 1.5;
margin-bottom: 8px;
display: block;
}
.card-summary {
font-size: 12px;
color: var(--text-tertiary);
line-height: 1.6;
margin-bottom: 10px;
display: block;
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.card-date {
font-size: 11px;
color: var(--text-muted);
}
.card-stats {
display: flex;
gap: 12px;
font-size: 11px;
color: var(--text-muted);
}
.stat-item {
color: var(--text-tertiary);
}
// 加载/空状态
.loading-state,
.empty-state {
text-align: center;
padding: 40px 0;
}
.loading-state text {
color: var(--text-muted);
font-size: 13px;
}
.empty-icon {
font-size: 48px;
display: block;
margin-bottom: 16px;
}
.empty-text {
font-size: 15px;
color: var(--text-tertiary);
display: block;
}
.empty-sub {
font-size: 12px;
color: var(--text-muted);
margin-top: 6px;
display: block;
}
</style>