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:
Yuzhiran Dev
2026-07-11 12:45:37 +08:00
parent 66ac576082
commit c1d6dd3b29
106 changed files with 17436 additions and 2311 deletions
+376
View File
@@ -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>