feat: 添加双人对练功能
Some checks failed
continuous-integration/drone/push Build is failing

- 新增数据库迁移脚本 (practice_rooms, practice_room_messages)
- 新增后端 API: 房间创建/加入/消息同步/报告生成
- 新增前端页面: 入口页/对练房间/报告页
- 新增 AI 双人评估服务和提示词
This commit is contained in:
yuliang_guo
2026-01-28 15:20:03 +08:00
parent fc299ed7b7
commit b6aea2e23d
14 changed files with 4195 additions and 0 deletions

View File

@@ -0,0 +1,187 @@
/**
* 双人对练 API
*/
import request from '@/api/request'
// ==================== 类型定义 ====================
export interface CreateRoomRequest {
scene_id?: number
scene_name?: string
scene_type?: string
scene_background?: string
role_a_name?: string
role_b_name?: string
role_a_description?: string
role_b_description?: string
host_role?: 'A' | 'B'
room_name?: string
}
export interface CreateRoomResponse {
room_code: string
room_id: number
room_name: string
my_role: string
my_role_name: string
}
export interface JoinRoomResponse {
room_code: string
room_id: number
room_name: string
status: string
my_role: string
my_role_name: string
}
export interface RoomUser {
id: number
username: string
full_name: string
avatar_url?: string
}
export interface RoomInfo {
id: number
room_code: string
room_name?: string
scene_id?: number
scene_name?: string
scene_type?: string
scene_background?: string
role_a_name: string
role_b_name: string
role_a_description?: string
role_b_description?: string
host_role: string
status: string
created_at?: string
started_at?: string
ended_at?: string
duration_seconds: number
total_turns: number
role_a_turns: number
role_b_turns: number
}
export interface RoomDetailResponse {
room: RoomInfo
host_user?: RoomUser
guest_user?: RoomUser
host_role_name?: string
guest_role_name?: string
my_role?: string
my_role_name?: string
is_host: boolean
}
export interface RoomMessage {
id: number
room_id: number
user_id?: number
message_type: 'chat' | 'system' | 'join' | 'leave' | 'start' | 'end'
content?: string
role_name?: string
sequence: number
created_at: string
}
export interface MessagesResponse {
messages: RoomMessage[]
room_status: string
last_sequence: number
}
export interface RoomListItem {
id: number
room_code: string
room_name?: string
scene_name?: string
status: string
is_host: boolean
created_at?: string
duration_seconds: number
total_turns: number
}
// ==================== API 函数 ====================
/**
* 创建房间
*/
export function createRoom(data: CreateRoomRequest) {
return request.post<CreateRoomResponse>('/api/v1/practice/rooms', data)
}
/**
* 加入房间
*/
export function joinRoom(roomCode: string) {
return request.post<JoinRoomResponse>('/api/v1/practice/rooms/join', {
room_code: roomCode
})
}
/**
* 获取房间详情
*/
export function getRoomDetail(roomCode: string) {
return request.get<RoomDetailResponse>(`/api/v1/practice/rooms/${roomCode}`)
}
/**
* 开始对练
*/
export function startPractice(roomCode: string) {
return request.post(`/api/v1/practice/rooms/${roomCode}/start`)
}
/**
* 结束对练
*/
export function endPractice(roomCode: string) {
return request.post(`/api/v1/practice/rooms/${roomCode}/end`)
}
/**
* 离开房间
*/
export function leaveRoom(roomCode: string) {
return request.post(`/api/v1/practice/rooms/${roomCode}/leave`)
}
/**
* 发送消息
*/
export function sendMessage(roomCode: string, content: string) {
return request.post<RoomMessage>(`/api/v1/practice/rooms/${roomCode}/message`, {
content
})
}
/**
* 获取消息列表
*/
export function getMessages(roomCode: string, sinceSequence: number = 0) {
return request.get<MessagesResponse>(`/api/v1/practice/rooms/${roomCode}/messages`, {
params: { since_sequence: sinceSequence }
})
}
/**
* 获取我的房间列表
*/
export function getMyRooms(status?: string, limit: number = 20) {
return request.get<{ rooms: RoomListItem[] }>('/api/v1/practice/rooms', {
params: { status, limit }
})
}
/**
* 生成分享链接
*/
export function generateShareLink(roomCode: string): string {
const baseUrl = window.location.origin
return `${baseUrl}/trainee/duo-practice/join/${roomCode}`
}