feat: 增强情绪博物馆项目功能 - 新增用户评论和帖子功能,优化前端架构和WebSocket通信 - 更新文档和部署配置
This commit is contained in:
@@ -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. 查看构建日志定位问题
|
||||
Reference in New Issue
Block a user