diff --git a/.gitignore b/.gitignore index 91a3710..92a07e3 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,4 @@ Thumbs.db .idea/ .vscode/ *.swp -*.swo \ No newline at end of file +*.swoclient/src/.share-done diff --git a/client/src/App.vue b/client/src/App.vue index 52908e9..91a03f3 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -81,7 +81,7 @@ page, .theme-light { /* 卡片 — 纯白微阴影 */ --glass-bg: #ffffff; - --glass-border: rgba(0, 0, 0, 0.06); + --glass-border: rgba(0, 0, 0, 0.08); --glass-hover: #f8f8ff; --glass-hover-border: rgba(99, 102, 241, 0.15); --glass-strong: #ffffff; @@ -89,8 +89,8 @@ page, .theme-light { /* 文字 — 清晰深色 */ --text-primary: #0d0d1a; - --text-secondary: rgba(13, 13, 26, 0.6); - --text-tertiary: rgba(13, 13, 26, 0.4); + --text-secondary: rgba(13, 13, 26, 0.68); + --text-tertiary: rgba(13, 13, 26, 0.48); --text-muted: rgba(13, 13, 26, 0.25); --text-disabled: rgba(13, 13, 26, 0.15); diff --git a/client/src/manifest.json b/client/src/manifest.json index ee62fec..afc376d 100644 --- a/client/src/manifest.json +++ b/client/src/manifest.json @@ -1,7 +1,7 @@ { "name": "宇之然AI维度", "appid": "wxdad62baf4ccd09e3", - "versionName": "1.1.5", + "versionName": "1.2.7", "versionCode": "100", "description": "AI 知识探索社区 — 从5个维度系统理解人工智能", "uni-app": { diff --git a/client/src/pages.json b/client/src/pages.json index bd8c84c..60619f4 100644 --- a/client/src/pages.json +++ b/client/src/pages.json @@ -124,6 +124,18 @@ "navigationBarTitleText": "协议", "navigationStyle": "custom" } + }, + { + "path": "pages/map/map", + "style": { + "navigationBarTitleText": "AI 知识地图" + } + }, + { + "path": "pages/map/quiz", + "style": { + "navigationBarTitleText": "知识闯关" + } } ], "globalStyle": { diff --git a/client/src/pages/map/map.vue b/client/src/pages/map/map.vue new file mode 100644 index 0000000..d6c85fe --- /dev/null +++ b/client/src/pages/map/map.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/client/src/pages/map/quiz.vue b/client/src/pages/map/quiz.vue new file mode 100644 index 0000000..44e54bc --- /dev/null +++ b/client/src/pages/map/quiz.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/server/src/index.js b/server/src/index.js index c1b9593..5df959f 100755 --- a/server/src/index.js +++ b/server/src/index.js @@ -1,105 +1,109 @@ -require('dotenv').config() - -const express = require('express') -const cors = require('cors') -const helmet = require('helmet') -const compression = require('compression') -const morgan = require('morgan') -const rateLimit = require('express-rate-limit') - -const connectDB = require('./config/database') -const initRoutes = require('./routes') -const logger = require('./utils/logger') - -// 创建 Express 应用 -const app = express() - -// 数据库连接 -connectDB() - -// 中间件配置 -app.use(helmet()) // 安全头部 -app.use(cors()) // 跨域支持 -app.use(compression()) // Gzip 压缩 -app.use(express.json({ limit: '10mb' })) // JSON 解析 -app.use(express.urlencoded({ extended: true, limit: '10mb' })) // URL 编码解析 - -// 日志中间件 -if (process.env.NODE_ENV === 'development') { - app.use(morgan('dev')) -} else { - app.use(morgan('combined')) -} - -// 速率限制 -const limiter = rateLimit({ - windowMs: 15 * 60 * 1000, // 15 分钟 - max: 1000, // 每个 IP 最多 1000 次请求 - message: { - success: false, - error: '请求过于频繁,请稍后再试' - } -}) -app.use('/api/', limiter) - -// 健康检查 -app.get('/health', (req, res) => { - res.status(200).json({ - status: 'ok', - timestamp: new Date().toISOString(), - uptime: process.uptime() - }) -}) - -// API 路由 -initRoutes(app) - -// 404 处理 -app.use((req, res) => { - res.status(404).json({ - success: false, - error: '接口不存在', - path: req.path - }) -}) - -// 全局错误处理 -app.use((err, req, res, next) => { - logger.error('服务器错误:', err) - - res.status(err.status || 500).json({ - success: false, - error: process.env.NODE_ENV === 'production' - ? '服务器内部错误' - : err.message, - stack: process.env.NODE_ENV === 'development' ? err.stack : undefined - }) -}) - -// 启动服务器(仅在直接运行时启动,被测试 import 时不启动) -const PORT = process.env.PORT || 3000 -let server = null - -if (require.main === module) { - server = app.listen(PORT, () => { - logger.info(`🚀 服务器启动成功`) - logger.info(`📍 端口: ${PORT}`) - logger.info(`🌐 环境: ${process.env.NODE_ENV || 'development'}`) - logger.info(`📊 健康检查: http://localhost:${PORT}/health`) - }) -} - -// 优雅关闭 -process.on('SIGTERM', () => { - logger.info('📴 接收到 SIGTERM 信号,正在关闭服务器...') - if (server) { - server.close(() => { - logger.info('✅ 服务器已关闭') - process.exit(0) - }) - } else { - process.exit(0) - } -}) - -module.exports = app +require('dotenv').config() + +const express = require('express') +const cors = require('cors') +const helmet = require('helmet') +const compression = require('compression') +const morgan = require('morgan') +const rateLimit = require('express-rate-limit') + +const connectDB = require('./config/database') +const initRoutes = require('./routes') +const seoRoutes = require('./routes/seo') +const logger = require('./utils/logger') + +// 创建 Express 应用 +const app = express() + +// 数据库连接 +connectDB() + +// SEO/GEO 路由(robots/sitemap/llms/about) +app.use('/', seoRoutes) + +// 中间件配置 +app.use(helmet()) // 安全头部 +app.use(cors()) // 跨域支持 +app.use(compression()) // Gzip 压缩 +app.use(express.json({ limit: '10mb' })) // JSON 解析 +app.use(express.urlencoded({ extended: true, limit: '10mb' })) // URL 编码解析 + +// 日志中间件 +if (process.env.NODE_ENV === 'development') { + app.use(morgan('dev')) +} else { + app.use(morgan('combined')) +} + +// 速率限制 +const limiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 分钟 + max: 1000, // 每个 IP 最多 1000 次请求 + message: { + success: false, + error: '请求过于频繁,请稍后再试' + } +}) +app.use('/api/', limiter) + +// 健康检查 +app.get('/health', (req, res) => { + res.status(200).json({ + status: 'ok', + timestamp: new Date().toISOString(), + uptime: process.uptime() + }) +}) + +// API 路由 +initRoutes(app) + +// 404 处理 +app.use((req, res) => { + res.status(404).json({ + success: false, + error: '接口不存在', + path: req.path + }) +}) + +// 全局错误处理 +app.use((err, req, res, next) => { + logger.error('服务器错误:', err) + + res.status(err.status || 500).json({ + success: false, + error: process.env.NODE_ENV === 'production' + ? '服务器内部错误' + : err.message, + stack: process.env.NODE_ENV === 'development' ? err.stack : undefined + }) +}) + +// 启动服务器(仅在直接运行时启动,被测试 import 时不启动) +const PORT = process.env.PORT || 3000 +let server = null + +if (require.main === module) { + server = app.listen(PORT, () => { + logger.info(`🚀 服务器启动成功`) + logger.info(`📍 端口: ${PORT}`) + logger.info(`🌐 环境: ${process.env.NODE_ENV || 'development'}`) + logger.info(`📊 健康检查: http://localhost:${PORT}/health`) + }) +} + +// 优雅关闭 +process.on('SIGTERM', () => { + logger.info('📴 接收到 SIGTERM 信号,正在关闭服务器...') + if (server) { + server.close(() => { + logger.info('✅ 服务器已关闭') + process.exit(0) + }) + } else { + process.exit(0) + } +}) + +module.exports = app