Files
st/docs/Vue重构方案.md

649 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# web-app Vue 3 重构方案
## 📋 方案概述
将 web-app 从传统的 jQuery 项目重构为 Vue 3 现代化单页应用SPA
## 🎯 重构目标
### 技术目标
- ✅ 使用 Vue 3 + Vite + TypeScript
- ✅ 组件化、模块化开发
- ✅ 统一前后端技术栈(与管理后台一致)
- ✅ 优化性能和用户体验
- ✅ 便于维护和扩展
### 业务目标
- ✅ 保留所有原有功能
- ✅ 改善 UI/UX 设计
- ✅ 适配移动端
- ✅ 支持主题切换
- ✅ 国际化支持
## 🏗️ 技术栈选择
### 核心技术
```json
{
"框架": "Vue 3 (Composition API)",
"构建工具": "Vite 5",
"语言": "TypeScript",
"状态管理": "Pinia",
"路由": "Vue Router 4",
"HTTP": "Axios",
"WebSocket": "原生 WebSocket / Socket.io-client"
}
```
### UI 框架选择
#### 方案一Element Plus推荐
```bash
# 优点
✅ 与管理后台统一web/ 使用的就是 Element Plus
✅ 组件丰富,开箱即用
✅ 中文文档完善
✅ 支持深色主题
✅ TypeScript 支持好
# 缺点
⚠️ 组件较重(如果只需要简单 UI可能过度设计
```
#### 方案二Naive UI
```bash
# 优点
✅ 轻量级,性能好
✅ TypeScript 原生支持
✅ 组件设计现代
✅ 支持深色主题
# 缺点
⚠️ 与管理后台不统一
```
#### 方案三:自定义 UI参考 auth.html
```bash
# 优点
✅ 完全自定义,独特设计
✅ 轻量级
✅ 可以复用已有的 auth.css 样式
# 缺点
⚠️ 需要自己实现所有组件
⚠️ 开发时间较长
```
**推荐Element Plus + 自定义样式**
- 使用 Element Plus 的基础组件(表单、按钮、对话框等)
- 自定义主题和关键页面样式
- 兼顾开发效率和设计独特性
## 📂 项目结构
### 新项目结构(推荐)
```
web-app-vue/ # 新建的 Vue 项目
├── public/
│ ├── favicon.ico
│ └── img/ # 静态图片资源
├── src/
│ ├── api/ # API 接口
│ │ ├── auth.ts # 认证接口
│ │ ├── character.ts # 角色接口
│ │ ├── chat.ts # 对话接口
│ │ └── index.ts # axios 配置
│ ├── assets/ # 资源文件
│ │ ├── styles/ # 全局样式
│ │ │ ├── index.scss
│ │ │ ├── variables.scss
│ │ │ └── dark-theme.scss
│ │ └── images/
│ ├── components/ # 通用组件
│ │ ├── common/ # 基础组件
│ │ │ ├── AppHeader.vue
│ │ │ ├── AppSidebar.vue
│ │ │ └── Loading.vue
│ │ ├── chat/ # 对话组件
│ │ │ ├── ChatMessage.vue
│ │ │ ├── ChatInput.vue
│ │ │ ├── MessageSwipe.vue
│ │ │ └── VoiceInput.vue
│ │ ├── character/ # 角色组件
│ │ │ ├── CharacterCard.vue
│ │ │ ├── CharacterList.vue
│ │ │ ├── CharacterEditor.vue
│ │ │ └── CharacterImport.vue
│ │ └── settings/ # 设置组件
│ │ ├── AIConfig.vue
│ │ ├── ThemeConfig.vue
│ │ └── UserProfile.vue
│ ├── composables/ # 组合式函数
│ │ ├── useAuth.ts # 认证相关
│ │ ├── useChat.ts # 对话相关
│ │ ├── useCharacter.ts # 角色相关
│ │ └── useWebSocket.ts # WebSocket
│ ├── layouts/ # 布局组件
│ │ ├── DefaultLayout.vue # 默认布局
│ │ ├── AuthLayout.vue # 认证页布局
│ │ └── ChatLayout.vue # 对话页布局
│ ├── router/ # 路由配置
│ │ ├── index.ts
│ │ └── guards.ts # 路由守卫
│ ├── stores/ # Pinia 状态管理
│ │ ├── auth.ts # 用户认证
│ │ ├── chat.ts # 对话状态
│ │ ├── character.ts # 角色管理
│ │ ├── settings.ts # 设置
│ │ └── index.ts
│ ├── types/ # TypeScript 类型
│ │ ├── api.d.ts
│ │ ├── character.d.ts
│ │ ├── chat.d.ts
│ │ └── user.d.ts
│ ├── utils/ # 工具函数
│ │ ├── request.ts # HTTP 请求封装
│ │ ├── storage.ts # 本地存储
│ │ ├── websocket.ts # WebSocket 封装
│ │ ├── format.ts # 格式化
│ │ └── validate.ts # 验证
│ ├── views/ # 页面视图
│ │ ├── auth/ # 认证页
│ │ │ ├── Login.vue
│ │ │ └── Register.vue
│ │ ├── home/ # 主页
│ │ │ └── Index.vue
│ │ ├── character/ # 角色页
│ │ │ ├── List.vue
│ │ │ ├── Detail.vue
│ │ │ └── Create.vue
│ │ ├── chat/ # 对话页
│ │ │ └── Index.vue
│ │ ├── settings/ # 设置页
│ │ │ └── Index.vue
│ │ └── user/ # 用户中心
│ │ └── Profile.vue
│ ├── App.vue # 根组件
│ └── main.ts # 入口文件
├── .env.development # 开发环境配置
├── .env.production # 生产环境配置
├── index.html
├── package.json
├── tsconfig.json
├── vite.config.ts
└── README.md
```
### 与现有项目的关系
```
st/
├── server/ # Go 后端(不变)
├── web/ # Vue 管理后台(不变)
├── web-app/ # 旧项目(保留备份)
└── web-app-vue/ # 新的 Vue 前台(新建)
└── ...
```
## 🚀 实施步骤
### 阶段一项目初始化1-2 天)
#### 1.1 创建 Vue 项目
```bash
# 使用 Vite 创建项目
npm create vite@latest web-app-vue -- --template vue-ts
cd web-app-vue
npm install
```
#### 1.2 安装依赖
```bash
# UI 框架
npm install element-plus
# 路由和状态管理
npm install vue-router@4 pinia
# HTTP 和工具
npm install axios
npm install @vueuse/core # Vue 常用组合式函数
# 开发依赖
npm install -D sass
npm install -D unplugin-vue-components unplugin-auto-import
```
#### 1.3 配置 Vite
```typescript
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
imports: ['vue', 'vue-router', 'pinia'],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
server: {
port: 3000,
proxy: {
'/app': {
target: 'http://localhost:8888',
changeOrigin: true,
},
},
},
})
```
#### 1.4 基础配置
```typescript
// src/main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import router from './router'
import App from './App.vue'
import './assets/styles/index.scss'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
app.use(router)
app.use(ElementPlus)
app.mount('#app')
```
### 阶段二核心功能开发5-7 天)
#### 2.1 认证模块1 天)
- [x] 登录页面
- [x] 注册页面
- [x] Token 管理
- [x] 路由守卫
#### 2.2 角色管理2 天)
- [ ] 角色列表
- [ ] 角色详情
- [ ] 角色创建/编辑
- [ ] 角色导入/导出
- [ ] 收藏功能
#### 2.3 对话功能3 天)
- [ ] 对话界面
- [ ] 消息发送
- [ ] 消息渲染
- [ ] Swipe 功能
- [ ] WebSocket 实时通信
- [ ] 流式输出
#### 2.4 设置页面1 天)
- [ ] AI 配置
- [ ] 主题设置
- [ ] 用户偏好
### 阶段三高级功能3-5 天)
#### 3.1 AI 功能
- [ ] 多模型支持
- [ ] Prompt 管理
- [ ] World Info
- [ ] 向量记忆
#### 3.2 UI/UX 优化
- [ ] 响应式布局
- [ ] 移动端适配
- [ ] 主题切换
- [ ] 动画效果
#### 3.3 文件管理
- [ ] 头像上传
- [ ] 文件管理
- [ ] 图片预览
### 阶段四测试和优化2-3 天)
- [ ] 单元测试
- [ ] E2E 测试
- [ ] 性能优化
- [ ] 打包优化
- [ ] 部署配置
## 📦 关键组件示例
### 1. 认证 Store
```typescript
// src/stores/auth.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { login, register, getUserInfo } from '@/api/auth'
import type { LoginRequest, User } from '@/types/user'
export const useAuthStore = defineStore('auth', () => {
const token = ref<string>(localStorage.getItem('st_access_token') || '')
const user = ref<User | null>(null)
const isLoggedIn = computed(() => !!token.value)
async function handleLogin(data: LoginRequest) {
const res = await login(data)
token.value = res.data.token
user.value = res.data.user
localStorage.setItem('st_access_token', res.data.token)
localStorage.setItem('st_user_info', JSON.stringify(res.data.user))
}
async function handleLogout() {
token.value = ''
user.value = null
localStorage.removeItem('st_access_token')
localStorage.removeItem('st_user_info')
}
async function fetchUserInfo() {
const res = await getUserInfo()
user.value = res.data
}
return {
token,
user,
isLoggedIn,
handleLogin,
handleLogout,
fetchUserInfo,
}
})
```
### 2. HTTP 请求封装
```typescript
// src/utils/request.ts
import axios from 'axios'
import { ElMessage } from 'element-plus'
import { useAuthStore } from '@/stores/auth'
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:8888',
timeout: 10000,
})
// 请求拦截器
request.interceptors.request.use(
(config) => {
const authStore = useAuthStore()
if (authStore.token) {
config.headers['x-token'] = authStore.token
}
return config
},
(error) => {
return Promise.reject(error)
}
)
// 响应拦截器
request.interceptors.response.use(
(response) => {
const res = response.data
if (res.code !== 0) {
ElMessage.error(res.msg || '请求失败')
return Promise.reject(new Error(res.msg || '请求失败'))
}
return res
},
(error) => {
ElMessage.error(error.message || '网络错误')
return Promise.reject(error)
}
)
export default request
```
### 3. 角色卡片组件
```vue
<!-- src/components/character/CharacterCard.vue -->
<template>
<div class="character-card" @click="handleClick">
<div class="card-header">
<img :src="character.avatar" :alt="character.name" class="avatar" />
<el-icon v-if="isFavorite" class="favorite-icon">
<Star />
</el-icon>
</div>
<div class="card-body">
<h3 class="character-name">{{ character.name }}</h3>
<p class="character-description">{{ character.description }}</p>
</div>
<div class="card-footer">
<el-tag v-for="tag in character.tags" :key="tag" size="small">
{{ tag }}
</el-tag>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { Character } from '@/types/character'
interface Props {
character: Character
}
const props = defineProps<Props>()
const emit = defineEmits<{
click: [character: Character]
}>()
const isFavorite = computed(() => props.character.isFavorite)
function handleClick() {
emit('click', props.character)
}
</script>
<style scoped lang="scss">
.character-card {
border-radius: 12px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s;
background: var(--el-bg-color);
&:hover {
transform: translateY(-4px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}
.card-header {
position: relative;
.avatar {
width: 100%;
height: 200px;
object-fit: cover;
}
.favorite-icon {
position: absolute;
top: 12px;
right: 12px;
color: #f59e0b;
font-size: 24px;
}
}
.card-body {
padding: 16px;
.character-name {
font-size: 18px;
font-weight: bold;
margin-bottom: 8px;
}
.character-description {
color: var(--el-text-color-secondary);
font-size: 14px;
line-height: 1.6;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
}
.card-footer {
padding: 0 16px 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
}
</style>
```
## 🔄 迁移策略
### 渐进式迁移(推荐)
1. **Phase 1: 新功能使用 Vue**
- 保留旧 web-app用于稳定运行
- 新功能在 web-app-vue 开发
- 通过路由切换新旧页面
2. **Phase 2: 逐步迁移**
- 按模块迁移(认证 → 角色 → 对话 → 设置)
- 每个模块迁移后充分测试
- 确保功能完整
3. **Phase 3: 完全替换**
- 所有功能迁移完成
- 彻底删除旧代码
- web-app-vue 改名为 web-app
### 一次性重写(不推荐,风险高)
除非你有充足的时间和人力,否则不建议一次性重写整个项目。
## 📊 与现有项目的集成
### Go 后端配置
```go
// server/initialize/router.go
// 前台 Vue 应用静态文件
webAppVuePath := "../web-app-vue/dist"
if _, err := os.Stat(webAppVuePath); err == nil {
Router.Static("/assets", webAppVuePath+"/assets")
Router.StaticFile("/", webAppVuePath+"/index.html")
global.GVA_LOG.Info("前台 Vue 应用已启动: " + webAppVuePath)
}
```
### 环境配置
```bash
# .env.development
VITE_API_BASE_URL=http://localhost:8888
VITE_WS_URL=ws://localhost:8888
# .env.production
VITE_API_BASE_URL=https://your-domain.com
VITE_WS_URL=wss://your-domain.com
```
## 🎯 开发优先级
### P0必须
1. ✅ 用户认证(登录/注册)
2. ✅ 角色列表和详情
3. ✅ 基本对话功能
4. ✅ AI 配置
### P1重要
5. ⚪ 角色编辑和创建
6. ⚪ 消息 Swipe
7. ⚪ 文件上传
8. ⚪ 设置页面
### P2可选
9. ⚪ World Info
10. ⚪ 向量记忆
11. ⚪ 高级 AI 功能
12. ⚪ 主题切换
## 📝 注意事项
### 1. 保持功能一致性
- 确保所有原有功能都能在 Vue 版本中实现
- 参考旧版的交互逻辑
- 不要遗漏边界情况
### 2. 性能优化
- 使用虚拟滚动(角色列表、消息列表)
- 图片懒加载
- 路由懒加载
- 打包分析和优化
### 3. 移动端适配
- 响应式设计
- 触摸手势支持
- 移动端专用布局
### 4. 国际化
- 使用 vue-i18n
- 支持多语言切换
- 本地化日期和数字
## 📚 学习资源
- Vue 3 官方文档: https://cn.vuejs.org/
- Vite 文档: https://cn.vitejs.dev/
- Element Plus: https://element-plus.org/zh-CN/
- Pinia 文档: https://pinia.vuejs.org/zh/
- TypeScript 文档: https://www.typescriptlang.org/zh/
## 🎉 总结
### 为什么要重构?
1.**代码质量**:从混乱的 jQuery 代码到清晰的组件化代码
2.**开发效率**热更新、TypeScript、自动导入
3.**性能提升**Vite 构建、按需加载、虚拟滚动
4.**易于维护**:模块化、类型安全、单一职责
5.**技术统一**:与管理后台使用相同技术栈
6.**未来发展**:易于扩展新功能
### 建议的时间线
- **快速原型**1 周):核心功能,可以开始使用
- **MVP 版本**2-3 周):主要功能完成
- **完整版本**4-6 周):所有功能迁移完成
- **优化打磨**持续性能优化、bug 修复
---
**更新日期**: 2026-02-10
**版本**: v1.0.0