🎨 重构用户端前端为vue开发,完善基础类和角色相关接口

This commit is contained in:
2026-02-10 21:55:45 +08:00
parent db934ebed7
commit 56e821b222
92 changed files with 18377 additions and 21 deletions

648
docs/Vue重构方案.md Normal file
View File

@@ -0,0 +1,648 @@
# 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

View File

@@ -0,0 +1,382 @@
# 用户认证 API 文档
## 📋 概述
本文档描述云酒馆项目前台用户认证系统的所有 API 接口。
## 🔗 基础信息
- **Base URL**: `http://localhost:8888/app`(开发环境)
- **认证方式**: JWT Bearer Token
- **Content-Type**: `application/json`
## 📌 API 接口列表
### 1. 用户注册
**接口**: `POST /app/auth/register`
**描述**: 新用户注册
**请求头**: 无需认证
**请求体**:
```json
{
"username": "testuser",
"password": "123456",
"nickName": "测试用户",
"email": "test@example.com",
"phone": "13800138000"
}
```
**字段说明**:
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| username | string | 是 | 用户名3-32字符 |
| password | string | 是 | 密码6-32字符 |
| nickName | string | 否 | 昵称最多50字符 |
| email | string | 否 | 邮箱地址 |
| phone | string | 否 | 手机号 |
**成功响应**:
```json
{
"code": 0,
"msg": "注册成功"
}
```
**错误响应**:
```json
{
"code": 7,
"msg": "用户名已存在"
}
```
---
### 2. 用户登录
**接口**: `POST /app/auth/login`
**描述**: 用户登录获取 Token
**请求头**: 无需认证
**请求体**:
```json
{
"username": "testuser",
"password": "123456"
}
```
**成功响应**:
```json
{
"code": 0,
"data": {
"user": {
"id": 1,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"username": "testuser",
"nickName": "测试用户",
"email": "test@example.com",
"phone": "13800138000",
"avatar": "",
"status": "active",
"enable": true,
"lastLoginAt": "2026-02-10T09:00:00Z",
"chatCount": 0,
"messageCount": 0,
"aiSettings": null,
"preferences": null,
"createdAt": "2026-02-10T08:00:00Z"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresAt": 1707552000
},
"msg": "登录成功"
}
```
**错误响应**:
```json
{
"code": 7,
"msg": "用户名或密码错误"
}
```
---
### 3. 刷新 Token
**接口**: `POST /app/auth/refresh`
**描述**: 使用 RefreshToken 获取新的 Token
**请求头**: 无需认证
**请求体**:
```json
{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```
**成功响应**: 同登录接口
---
### 4. 用户登出
**接口**: `POST /app/auth/logout`
**描述**: 用户登出(清除会话)
**请求头**:
```
x-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
```
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**请求体**: 无
**成功响应**:
```json
{
"code": 0,
"msg": "登出成功"
}
```
---
### 5. 获取用户信息
**接口**: `GET /app/auth/userinfo`
**描述**: 获取当前登录用户信息
**请求头**: 需要认证JWT Token
**成功响应**:
```json
{
"code": 0,
"data": {
"id": 1,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"username": "testuser",
"nickName": "测试用户",
"email": "test@example.com",
"phone": "13800138000",
"avatar": "",
"status": "active",
"enable": true,
"lastLoginAt": "2026-02-10T09:00:00Z",
"chatCount": 5,
"messageCount": 120,
"aiSettings": {},
"preferences": {},
"createdAt": "2026-02-10T08:00:00Z"
}
}
```
---
### 6. 更新用户信息
**接口**: `PUT /app/user/profile`
**描述**: 更新当前用户的个人信息
**请求头**: 需要认证JWT Token
**请求体**:
```json
{
"nickName": "新昵称",
"email": "newemail@example.com",
"phone": "13900139000",
"avatar": "https://example.com/avatar.jpg",
"preferences": "{\"theme\":\"dark\"}",
"aiSettings": "{\"defaultModel\":\"gpt-4\"}"
}
```
**字段说明**: 所有字段均为可选
**成功响应**:
```json
{
"code": 0,
"msg": "更新成功"
}
```
---
### 7. 修改密码
**接口**: `POST /app/user/change-password`
**描述**: 修改当前用户密码
**请求头**: 需要认证JWT Token
**请求体**:
```json
{
"oldPassword": "123456",
"newPassword": "new123456"
}
```
**成功响应**:
```json
{
"code": 0,
"msg": "修改成功"
}
```
**错误响应**:
```json
{
"code": 7,
"msg": "原密码错误"
}
```
---
## 🔐 认证说明
### Token 使用方式
认证接口需要在请求头中携带 Token支持两种方式
**方式 1**: `x-token`
```http
x-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**方式 2**: `Authorization`Bearer Token
```http
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**方式 3**: Query 参数(不推荐,仅用于特殊场景)
```http
GET /app/auth/userinfo?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
### Token 有效期
- **Access Token**: 配置文件中的 `jwt.expiresTime` 设置(默认 7200 秒 = 2 小时)
- **Refresh Token**: 固定 7 天
### Token 刷新流程
1. Access Token 过期后,使用 Refresh Token 调用 `/app/auth/refresh` 接口
2. 获取新的 Access Token 和 Refresh Token
3. 使用新的 Token 继续访问 API
---
## 🧪 测试用例
### 使用 curl 测试
**1. 注册新用户**:
```bash
curl -X POST http://localhost:8888/app/auth/register \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"password": "123456",
"nickName": "测试用户"
}'
```
**2. 登录**:
```bash
curl -X POST http://localhost:8888/app/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"password": "123456"
}'
```
**3. 获取用户信息**(需替换 TOKEN:
```bash
TOKEN="your_token_here"
curl -X GET http://localhost:8888/app/auth/userinfo \
-H "x-token: $TOKEN"
```
**4. 更新用户信息**:
```bash
curl -X PUT http://localhost:8888/app/user/profile \
-H "x-token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"nickName": "新昵称",
"avatar": "https://example.com/avatar.jpg"
}'
```
**5. 修改密码**:
```bash
curl -X POST http://localhost:8888/app/user/change-password \
-H "x-token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"oldPassword": "123456",
"newPassword": "new123456"
}'
```
---
## ❗ 常见错误码
| 错误码 | 说明 |
|-------|------|
| 0 | 成功 |
| 7 | 业务错误(如用户名已存在、密码错误等) |
| 401 | 未认证或 Token 无效 |
| 403 | 账户被禁用或状态异常 |
| 500 | 服务器内部错误 |
---
## 📝 注意事项
1. **密码安全**: 所有密码均使用 bcrypt 加密存储,不可逆
2. **用户状态**: 只有 `status=active``enable=true` 的用户才能登录
3. **用户名唯一性**: 用户名和邮箱必须唯一
4. **会话管理**: 登出后会删除对应的会话记录,但 Token 在过期前仍然有效
5. **跨域配置**: 如需前端调用,请在 `initialize/router.go` 中启用 CORS 中间件
---
## 🔄 下一步开发
- [ ] 邮箱验证
- [ ] 手机号验证
- [ ] 找回密码
- [ ] 第三方登录OAuth
- [ ] 多设备登录管理
- [ ] 用户在线状态

3077
docs/重构实施方案.md Normal file

File diff suppressed because it is too large Load Diff

1986
docs/重构进度管理.md Normal file

File diff suppressed because it is too large Load Diff