feat: 增强情绪博物馆项目功能 - 新增用户评论和帖子功能,优化前端架构和WebSocket通信 - 更新文档和部署配置

This commit is contained in:
2025-07-29 07:38:47 +08:00
parent cc886cd4d5
commit 2f3d39fb00
142 changed files with 45645 additions and 0 deletions
+517
View File
@@ -0,0 +1,517 @@
# 情绪博物馆前端环境配置梳理
## 1. 项目概述
情绪博物馆前端基于Vue3 + TypeScript + Vite开发,采用现代化的前端技术栈,支持多环境部署。
### 技术栈
- **框架**: Vue 3.4.0
- **构建工具**: Vite 5.0.8
- **语言**: TypeScript 5.3.3
- **UI框架**: Element Plus 2.4.4
- **状态管理**: Pinia 2.1.7
- **路由**: Vue Router 4.2.5
- **样式**: Tailwind CSS 3.4.0
- **HTTP客户端**: Axios 1.6.2
- **WebSocket**: Socket.io-client 4.7.4, @stomp/stompjs 7.1.1
- **图表**: ECharts 5.4.3
- **工具库**: Day.js, Lodash-es, Zod
## 2. 环境配置文件
### 2.1 环境变量类型定义 (`src/types/env.d.ts`)
```typescript
interface ImportMetaEnv {
readonly VITE_APP_ENV: string // 应用环境
readonly VITE_APP_TITLE: string // 应用标题
readonly VITE_APP_VERSION: string // 应用版本
readonly VITE_API_BASE_URL: string // API基础URL
readonly VITE_WS_BASE_URL: string // WebSocket基础URL
readonly VITE_UPLOAD_URL: string // 文件上传URL
readonly VITE_DEBUG: string // 调试模式
readonly VITE_MOCK: string // Mock模式
readonly VITE_APP_DESCRIPTION: string // 应用描述
}
```
### 2.2 环境配置管理 (`src/config/env.ts`)
环境配置支持四种环境:
- **local**: 本地开发环境
- **dev**: 开发环境
- **test**: 测试环境
- **prod**: 生产环境
#### 环境配置接口
```typescript
interface EnvConfig {
name: string // 环境名称
apiBaseUrl: string // API基础URL
wsBaseUrl: string // WebSocket URL
uploadUrl: string // 文件上传URL
debug: boolean // 调试模式
mock: boolean // Mock模式
appTitle: string // 应用标题
appVersion: string // 应用版本
}
```
#### 各环境配置详情
**本地环境 (local)**
```typescript
{
name: '本地环境',
apiBaseUrl: 'http://localhost:19089/api',
wsBaseUrl: 'ws://localhost:19089/api',
uploadUrl: 'http://localhost:19089/api/upload',
debug: true,
mock: false,
appTitle: '情绪博物馆 - 本地',
appVersion: '1.0.0'
}
```
**开发环境 (dev)**
```typescript
{
name: '开发环境',
apiBaseUrl: 'http://localhost:19089/api',
wsBaseUrl: 'ws://localhost:19089/api',
uploadUrl: 'http://localhost:19089/api/upload',
debug: true,
mock: false,
appTitle: '情绪博物馆 - 开发',
appVersion: '1.0.0'
}
```
**测试环境 (test)**
```typescript
{
name: '测试环境',
apiBaseUrl: 'http://test.emotion-museum.com/api',
wsBaseUrl: 'ws://test.emotion-museum.com',
uploadUrl: 'http://test.emotion-museum.com/api/upload',
debug: false,
mock: false,
appTitle: '情绪博物馆 - 测试',
appVersion: '1.0.0'
}
```
**生产环境 (prod)**
```typescript
{
name: '生产环境',
apiBaseUrl: 'https://api.emotion-museum.com/api',
wsBaseUrl: 'wss://api.emotion-museum.com',
uploadUrl: 'https://api.emotion-museum.com/api/upload',
debug: false,
mock: false,
appTitle: '情绪博物馆',
appVersion: '1.0.0'
}
```
## 3. 构建配置
### 3.1 Vite配置 (`vite.config.ts`)
```typescript
export default defineConfig({
base: '/emotion-museum/', // 部署基础路径
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src'), // 路径别名
},
},
define: {
global: 'globalThis', // 全局变量定义
},
server: {
port: 5173, // 开发服务器端口
open: true, // 自动打开浏览器
proxy: { // 代理配置
'/api': {
target: 'http://localhost:19089',
changeOrigin: true,
secure: false,
}
}
},
build: {
outDir: 'dist', // 输出目录
sourcemap: false, // 不生成sourcemap
rollupOptions: {
external: (id) => { // 外部依赖处理
if (id.includes('echarts') && id.includes('extension')) {
return true
}
return false
},
output: {
manualChunks: { // 代码分割
vendor: ['vue', 'vue-router', 'pinia'],
elementPlus: ['element-plus'],
},
},
},
},
})
```
### 3.2 TypeScript配置 (`tsconfig.json`)
```json
{
"compilerOptions": {
"target": "ES2020", // 目标版本
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler", // 模块解析策略
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
"strict": true, // 严格模式
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": { // 路径映射
"@/*": ["src/*"]
},
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"types": ["node"]
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue",
"src/types/global.d.ts"
],
"references": [{ "path": "./tsconfig.node.json" }]
}
```
### 3.3 Tailwind CSS配置 (`tailwind.config.js`)
```javascript
export default {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
primary: { // 主色调
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
},
emotion: { // 情绪色彩
happy: '#fbbf24',
sad: '#3b82f6',
angry: '#ef4444',
calm: '#10b981',
excited: '#f97316',
anxious: '#8b5cf6',
},
// 设计系统颜色
'tech-blue': '#4A90E2',
'warm-orange': '#F5A623',
'light-gray': '#F7F8FA',
'text-dark': '#333333',
'text-medium': '#888888',
},
fontFamily: {
sans: ['Noto Sans SC', 'Inter', 'system-ui', 'sans-serif'],
},
animation: { // 自定义动画
'fade-in': 'fadeIn 0.5s ease-in-out',
'slide-up': 'slideUp 0.3s ease-out',
'bounce-gentle': 'bounceGentle 2s infinite',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
slideUp: {
'0%': { transform: 'translateY(20px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
bounceGentle: {
'0%, 100%': { transform: 'translateY(0)' },
'50%': { transform: 'translateY(-5px)' },
},
},
},
},
plugins: [],
}
```
### 3.4 PostCSS配置 (`postcss.config.js`)
```javascript
export default {
plugins: {
tailwindcss: {}, // Tailwind CSS
autoprefixer: {}, // 自动添加CSS前缀
},
}
```
## 4. 代码规范配置
### 4.1 ESLint配置 (`.eslintrc.cjs`)
```javascript
module.exports = {
root: true,
extends: [
'plugin:vue/vue3-essential', // Vue3基础规则
'eslint:recommended', // ESLint推荐规则
'@vue/eslint-config-typescript', // TypeScript规则
'@vue/eslint-config-prettier/skip-formatting' // Prettier集成
],
parserOptions: {
ecmaVersion: 'latest'
},
rules: {
'vue/multi-word-component-names': 'off', // 允许单词组件名
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], // 忽略下划线参数
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 生产环境警告console
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off' // 生产环境警告debugger
}
}
```
### 4.2 Prettier配置 (`.prettierrc`)
```json
{
"semi": false, // 不使用分号
"singleQuote": true, // 使用单引号
"tabWidth": 2, // 缩进2个空格
"trailingComma": "es5", // ES5兼容的尾随逗号
"printWidth": 100, // 行宽100字符
"bracketSpacing": true, // 对象字面量括号内空格
"arrowParens": "avoid" // 箭头函数参数避免括号
}
```
## 5. HTTP请求配置
### 5.1 请求工具配置 (`src/utils/request.ts`)
#### 基础配置
```typescript
const instance = axios.create({
baseURL: envConfig.apiBaseUrl, // 从环境配置获取基础URL
timeout: 30000, // 30秒超时
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
```
#### 请求拦截器
- 自动添加Authorization头(Bearer Token
- 生成请求ID用于追踪
- 调试模式下打印请求日志
#### 响应拦截器
- 统一处理业务状态码
- 特殊错误码处理(401、403、404、500等)
- 自动处理未授权情况
- 调试模式下打印响应日志
#### 错误处理
- 网络错误处理
- 服务器错误处理
- 业务错误处理
- 401未授权自动跳转登录
## 6. 部署配置
### 6.1 构建脚本 (`package.json`)
```json
{
"scripts": {
"dev": "vite", // 开发环境
"build": "vite build", // 生产构建
"build:check": "vue-tsc && vite build", // 类型检查+构建
"preview": "vite preview", // 预览构建结果
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"type-check": "vue-tsc --noEmit", // TypeScript类型检查
"test": "vitest", // 单元测试
"test:e2e": "cypress run" // E2E测试
}
}
```
### 6.2 Linux部署脚本 (`deploy.sh`)
```bash
#!/bin/bash
# 部署脚本 - 将构建好的文件上传到服务器
SERVER_IP="47.111.10.27"
USERNAME="root"
REMOTE_PATH="/data/www/emotion-museum"
# 检查dist目录是否存在
if [ ! -d "dist" ]; then
echo "错误: dist目录不存在,请先运行 npm run build"
exit 1
fi
# 上传文件到服务器
scp dist/index.html "${USERNAME}@${SERVER_IP}:${REMOTE_PATH}/"
scp -r dist/assets "${USERNAME}@${SERVER_IP}:${REMOTE_PATH}/"
scp dist/test-*.html "${USERNAME}@${SERVER_IP}:${REMOTE_PATH}/"
```
### 6.3 Windows部署脚本 (`deploy.ps1`)
```powershell
# 部署脚本 - PowerShell版本
param(
[string]$ServerIP = "47.111.10.27",
[string]$Username = "root",
[string]$RemotePath = "/data/www/emotion-museum"
)
# 检查dist目录
if (-not (Test-Path "dist")) {
Write-Host "错误: dist目录不存在,请先运行 npm run build" -ForegroundColor Red
exit 1
}
# 上传文件到服务器
scp "dist/index.html" "${Username}@${ServerIP}:${RemotePath}/"
scp -r "dist/assets" "${Username}@${ServerIP}:${RemotePath}/"
scp "dist/test-*.html" "${Username}@${ServerIP}:${RemotePath}/"
```
## 7. 环境变量使用
### 7.1 环境变量获取方式
```typescript
// 在组件中使用环境变量
const apiUrl = import.meta.env.VITE_API_BASE_URL
const isDebug = import.meta.env.VITE_DEBUG === 'true'
const appTitle = import.meta.env.VITE_APP_TITLE
```
### 7.2 环境变量设置
开发时可以通过以下方式设置环境变量:
**Linux/Mac:**
```bash
export VITE_APP_ENV=dev
export VITE_API_BASE_URL=http://localhost:19089/api
npm run dev
```
**Windows:**
```cmd
set VITE_APP_ENV=dev
set VITE_API_BASE_URL=http://localhost:19089/api
npm run dev
```
**或者创建.env文件:**
```env
VITE_APP_ENV=dev
VITE_API_BASE_URL=http://localhost:19089/api
VITE_WS_BASE_URL=ws://localhost:19089/api
VITE_DEBUG=true
VITE_MOCK=false
```
## 8. 开发环境配置
### 8.1 开发服务器配置
- **端口**: 5173
- **自动打开**: 是
- **代理**: `/api` -> `http://localhost:19089`
- **热更新**: 启用
### 8.2 调试配置
- **Vue DevTools**: 支持
- **TypeScript**: 严格模式
- **ESLint**: 实时检查
- **Prettier**: 自动格式化
### 8.3 构建优化
- **代码分割**: 按模块分割
- **Tree Shaking**: 自动移除未使用代码
- **压缩**: 生产环境自动压缩
- **缓存**: 文件名包含哈希值
## 9. 生产环境配置
### 9.1 构建优化
- **Source Map**: 禁用
- **压缩**: 启用
- **代码分割**: 启用
- **CDN**: 支持
### 9.2 部署路径
- **基础路径**: `/emotion-museum/`
- **静态资源**: 自动添加哈希值
- **缓存策略**: 长期缓存静态资源
### 9.3 性能优化
- **懒加载**: 路由级别懒加载
- **预加载**: 关键资源预加载
- **压缩**: Gzip/Brotli压缩
- **缓存**: 浏览器缓存优化
## 10. 注意事项
1. **环境变量**: 必须以`VITE_`开头才能在客户端使用
2. **API代理**: 开发环境使用代理,生产环境使用真实域名
3. **WebSocket**: 开发环境使用ws协议,生产环境使用wss协议
4. **构建路径**: 确保部署路径与`vite.config.ts`中的`base`配置一致
5. **类型检查**: 构建前建议运行`npm run type-check`确保类型安全
6. **代码规范**: 提交前运行`npm run lint`确保代码质量
## 11. 故障排除
### 常见问题
1. **构建失败**: 检查TypeScript类型错误
2. **代理不生效**: 检查vite.config.ts中的proxy配置
3. **环境变量未生效**: 确保变量名以`VITE_`开头
4. **部署404**: 检查nginx配置和base路径设置
5. **WebSocket连接失败**: 检查协议和端口配置
### 调试技巧
1. 使用浏览器开发者工具查看网络请求
2. 检查控制台错误信息
3. 使用Vue DevTools调试组件状态
4. 查看构建日志定位问题