refactor: 项目架构重构 - 目录标准化 + 清理冗余
- 目录重命名: backend/wdkj-server/ → server/, frontend/ai-dimension/ → client/ - 删除 20+ 冗余文件(WDKJ 旧脚本、Windows 脚本、过时文档、设计稿) - 更新 package.json 元数据(移除 wdkj 命名) - 完善三级 .gitignore(根 + server + client) - 重写 README.md 和 CHANGELOG.md - 工具脚本移至 scripts/
This commit is contained in:
@@ -0,0 +1,376 @@
|
||||
<template>
|
||||
<view class="page-home">
|
||||
<!-- 状态栏占位 -->
|
||||
<view class="status-bar-placeholder"></view>
|
||||
|
||||
<!-- 顶部导航 -->
|
||||
<view class="header">
|
||||
<view class="brand">
|
||||
<view class="brand-icon">✦</view>
|
||||
<view class="brand-text">
|
||||
<text class="title">AI 维度</text>
|
||||
<text class="subtitle">宇之然 · 探索</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="header-actions">
|
||||
<view class="icon-btn" @tap="onNotify">
|
||||
<text>🔔</text>
|
||||
</view>
|
||||
<view class="icon-btn" @tap="goProfile">
|
||||
<text>👤</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 问候语 -->
|
||||
<view class="greeting">
|
||||
<text class="greeting-title">探索 </text>
|
||||
<text class="greeting-highlight">人工智能</text>
|
||||
<text class="greeting-desc">从 5 个维度,系统理解 AI 的过去、现在与未来</text>
|
||||
</view>
|
||||
|
||||
<!-- 搜索栏 -->
|
||||
<view class="search-bar" @tap="onSearch">
|
||||
<text class="search-icon">🔍</text>
|
||||
<text class="search-placeholder">搜搜你想了解的 AI 知识...</text>
|
||||
</view>
|
||||
|
||||
<!-- 五维度网格 -->
|
||||
<view class="section-header">
|
||||
<text class="section-title">✦ 五个维度</text>
|
||||
</view>
|
||||
<view class="dim-grid">
|
||||
<view
|
||||
v-for="dim in dimensions"
|
||||
:key="dim.id"
|
||||
class="dim-card"
|
||||
:class="{ 'dim-full': dim.isFull }"
|
||||
:style="{ background: dim.bg }"
|
||||
@tap="goDimension(dim)"
|
||||
>
|
||||
<view class="dim-icon" :style="{ background: dim.iconBg, color: dim.color }">
|
||||
<text>{{ dim.icon }}</text>
|
||||
</view>
|
||||
<text class="dim-name" :style="{ color: dim.color }">{{ dim.name }}</text>
|
||||
<text class="dim-desc">{{ dim.desc }}</text>
|
||||
<text class="dim-count">
|
||||
{{ dim.isFull ? '今日已更新 8 条' : `${dim.articleCount} 篇 · ${dim.quizCount} 个问答` }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 今日快讯 -->
|
||||
<view class="section-header">
|
||||
<text class="section-title">📡 今日快讯</text>
|
||||
<text class="section-more" @tap="goTrend">查看全部 →</text>
|
||||
</view>
|
||||
<view
|
||||
v-for="(item, idx) in newsList"
|
||||
:key="idx"
|
||||
class="news-card"
|
||||
@tap="goNewsDetail(item)"
|
||||
>
|
||||
<view class="news-tag" :class="item.tagClass">{{ item.tag }}</view>
|
||||
<text class="news-title">{{ item.title }}</text>
|
||||
<view class="news-meta">
|
||||
<text>{{ item.source }}</text>
|
||||
<text>{{ item.time }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bottom-spacer"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { DIMENSIONS } from '@/utils/dimensions'
|
||||
import { trendApi } from '@/utils/api'
|
||||
|
||||
const dimensions = ref(DIMENSIONS)
|
||||
|
||||
const newsList = ref([])
|
||||
const loading = ref(true)
|
||||
|
||||
onMounted(() => {
|
||||
fetchNews()
|
||||
})
|
||||
|
||||
async function fetchNews() {
|
||||
try {
|
||||
const data = await trendApi.list({ limit: 5 })
|
||||
newsList.value = data.list.map(item => ({
|
||||
tag: item.hot ? '🔥 热门' : item.picked ? '📌 精选' : '🚀 最新',
|
||||
tagClass: item.hot ? 'hot' : item.picked ? 'pick' : 'new',
|
||||
title: item.title,
|
||||
source: item.source,
|
||||
time: formatTime(item.newsDate),
|
||||
_id: item._id
|
||||
}))
|
||||
} catch (e) {
|
||||
// 降级:本地数据
|
||||
newsList.value = [
|
||||
{ tag: '🔥 热门', tagClass: 'hot', title: 'DeepSeek 被曝自研推理芯片', source: '量子位', time: '2 小时前' },
|
||||
{ tag: '🚀 最新', tagClass: 'new', title: '蚂蚁灵波开源 LingBot-World 2.0', source: '量子位', time: '4 小时前' },
|
||||
{ tag: '📌 精选', tagClass: 'pick', title: '阿里获 ACL 2026 最佳资源论文奖', source: '机器之心', time: '6 小时前' }
|
||||
]
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function formatTime(dateStr) {
|
||||
const diff = Date.now() - new Date(dateStr).getTime()
|
||||
const hours = Math.floor(diff / 3600000)
|
||||
if (hours < 1) return '刚刚'
|
||||
if (hours < 24) return `${hours} 小时前`
|
||||
return `${Math.floor(hours / 24)} 天前`
|
||||
}
|
||||
|
||||
function goDimension(dim) {
|
||||
uni.navigateTo({ url: `/pages/dimension/dimension?id=${dim.id}&name=${dim.name}` })
|
||||
}
|
||||
|
||||
function goTrend() {
|
||||
uni.switchTab({ url: '/pages/trend/trend' })
|
||||
}
|
||||
|
||||
function goProfile() {
|
||||
uni.switchTab({ url: '/pages/profile/profile' })
|
||||
}
|
||||
|
||||
function onSearch() {
|
||||
uni.navigateTo({ url: '/pages/search/search' })
|
||||
}
|
||||
|
||||
function onNotify() {
|
||||
uni.showToast({ title: '暂无新消息', icon: 'none' })
|
||||
}
|
||||
|
||||
function goNewsDetail(item) {
|
||||
uni.switchTab({ url: '/pages/trend/trend' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-home {
|
||||
min-height: 100vh;
|
||||
padding: 0 20px;
|
||||
background: var(--bg-primary);
|
||||
}
|
||||
|
||||
.status-bar-placeholder {
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 6px 0 20px;
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.brand-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(135deg, rgba(124,77,255,0.3), rgba(0,188,212,0.2));
|
||||
border: 1px solid rgba(124,77,255,0.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
box-shadow: 0 0 20px rgba(124,77,255,0.1);
|
||||
}
|
||||
|
||||
.brand-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.brand-text .title {
|
||||
font-size: 20px;
|
||||
color: var(--text-primary);
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.brand-text .subtitle {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
.icon-btn {
|
||||
width: 36px; height: 36px;
|
||||
border-radius: 50%;
|
||||
background: var(--glass-bg);
|
||||
border: 1px solid var(--glass-border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.greeting {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.greeting-title {
|
||||
font-size: 26px;
|
||||
color: var(--text-primary);
|
||||
font-weight: 700;
|
||||
}
|
||||
.greeting-highlight {
|
||||
font-size: 26px;
|
||||
font-weight: 700;
|
||||
background: linear-gradient(135deg, #b388ff, #7c4dff);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
.greeting-desc {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
color: var(--text-tertiary);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
background: var(--glass-bg);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 14px;
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 24px;
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
}
|
||||
.search-icon { color: var(--text-muted); }
|
||||
.search-placeholder { color: var(--text-muted); font-size: 14px; }
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 17px;
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.section-more {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.dim-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.dim-card {
|
||||
border-radius: 18px;
|
||||
padding: 20px 16px;
|
||||
border: 1px solid var(--glass-border);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
}
|
||||
.dim-full {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.dim-icon {
|
||||
width: 42px; height: 42px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.dim-name {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 4px;
|
||||
letter-spacing: 0.5px;
|
||||
display: block;
|
||||
}
|
||||
.dim-desc {
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
line-height: 1.5;
|
||||
display: block;
|
||||
}
|
||||
.dim-count {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
margin-top: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.news-card {
|
||||
border-radius: 14px;
|
||||
padding: 14px 16px;
|
||||
margin-bottom: 10px;
|
||||
background: var(--glass-bg);
|
||||
border: 1px solid var(--glass-border);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.news-tag {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
padding: 2px 10px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.news-tag.hot {
|
||||
background: rgba(239,83,80,0.12);
|
||||
color: #ef5350;
|
||||
}
|
||||
.news-tag.new {
|
||||
background: rgba(0,188,212,0.12);
|
||||
color: #4dd0e1;
|
||||
}
|
||||
.news-tag.pick {
|
||||
background: rgba(124,77,255,0.12);
|
||||
color: #b388ff;
|
||||
}
|
||||
|
||||
.news-title {
|
||||
font-size: 14px;
|
||||
color: var(--text-primary);
|
||||
line-height: 1.5;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.news-meta {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.bottom-spacer {
|
||||
height: 40px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user