feat: 初始化考培练系统项目
- 从服务器拉取完整代码 - 按框架规范整理项目结构 - 配置 Drone CI 测试环境部署 - 包含后端(FastAPI)、前端(Vue3)、管理端 技术栈: Vue3 + TypeScript + FastAPI + MySQL
This commit is contained in:
9
frontend/src/types/broadcast.ts
Normal file
9
frontend/src/types/broadcast.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export interface BroadcastInfo {
|
||||
has_broadcast: boolean
|
||||
mp3_url?: string
|
||||
generated_at?: string
|
||||
}
|
||||
|
||||
export interface GenerateBroadcastResponse {
|
||||
message: string
|
||||
}
|
||||
129
frontend/src/types/material.ts
Normal file
129
frontend/src/types/material.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 课程资料相关类型定义
|
||||
*/
|
||||
|
||||
/**
|
||||
* 课程资料信息
|
||||
*/
|
||||
export interface Material {
|
||||
id: number
|
||||
course_id: number
|
||||
name: string
|
||||
description?: string
|
||||
file_url: string
|
||||
file_type: string
|
||||
file_size: number
|
||||
created_at: string
|
||||
updated_at?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* 预览类型
|
||||
* 支持格式:TXT、Markdown、MDX、PDF、HTML、Excel、Word、CSV、VTT、Properties、视频、音频、图片
|
||||
*/
|
||||
export type PreviewType = 'pdf' | 'text' | 'html' | 'download' | 'video' | 'audio' | 'image'
|
||||
|
||||
/**
|
||||
* 预览信息
|
||||
*/
|
||||
export interface PreviewInfo {
|
||||
preview_type: PreviewType
|
||||
preview_url?: string
|
||||
content?: string // 文本内容(仅text类型)
|
||||
file_name: string
|
||||
original_url: string
|
||||
file_size: number
|
||||
is_converted?: boolean // 是否经过转换(Office文档)
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件类型图标映射
|
||||
* 支持格式:TXT、Markdown、MDX、PDF、HTML、Excel、Word、CSV、VTT、Properties
|
||||
*/
|
||||
export const FILE_TYPE_ICONS: Record<string, string> = {
|
||||
// PDF
|
||||
pdf: 'document',
|
||||
|
||||
// Office文档
|
||||
doc: 'document',
|
||||
docx: 'document',
|
||||
xls: 'document',
|
||||
xlsx: 'document',
|
||||
|
||||
// 文本
|
||||
txt: 'document',
|
||||
md: 'document',
|
||||
mdx: 'document',
|
||||
csv: 'tickets',
|
||||
vtt: 'document',
|
||||
properties: 'setting',
|
||||
|
||||
// HTML
|
||||
html: 'document',
|
||||
htm: 'document',
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类型图标
|
||||
*/
|
||||
export function getFileTypeIcon(fileName: string): string {
|
||||
const ext = fileName.split('.').pop()?.toLowerCase() || ''
|
||||
return FILE_TYPE_ICONS[ext] || 'document'
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文件大小
|
||||
*/
|
||||
export function formatFileSize(bytes: number): string {
|
||||
if (bytes === 0) return '0 B'
|
||||
const k = 1024
|
||||
const sizes = ['B', 'KB', 'MB', 'GB']
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||||
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件扩展名
|
||||
*/
|
||||
export function getFileExtension(fileName: string): string {
|
||||
return fileName.split('.').pop()?.toLowerCase() || ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断文件类型
|
||||
* 支持格式:TXT、Markdown、MDX、PDF、HTML、Excel、Word、CSV、VTT、Properties、视频、音频、图片
|
||||
*/
|
||||
export function getFileCategory(fileName: string): 'document' | 'text' | 'video' | 'audio' | 'image' | 'other' {
|
||||
const ext = getFileExtension(fileName)
|
||||
|
||||
// 视频格式
|
||||
const videoFormats = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv']
|
||||
if (videoFormats.includes(ext)) {
|
||||
return 'video'
|
||||
}
|
||||
|
||||
// 音频格式
|
||||
const audioFormats = ['mp3', 'wav', 'ogg', 'aac', 'flac', 'm4a']
|
||||
if (audioFormats.includes(ext)) {
|
||||
return 'audio'
|
||||
}
|
||||
|
||||
// 图片格式
|
||||
const imageFormats = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp']
|
||||
if (imageFormats.includes(ext)) {
|
||||
return 'image'
|
||||
}
|
||||
|
||||
// 文档格式
|
||||
const documentFormats = [
|
||||
'pdf', 'doc', 'docx', 'xls', 'xlsx',
|
||||
'txt', 'md', 'mdx', 'csv', 'vtt', 'properties',
|
||||
'html', 'htm'
|
||||
]
|
||||
if (documentFormats.includes(ext)) {
|
||||
return 'document'
|
||||
}
|
||||
|
||||
return 'other'
|
||||
}
|
||||
|
||||
149
frontend/src/types/practice.ts
Normal file
149
frontend/src/types/practice.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* 陪练功能类型定义
|
||||
*/
|
||||
|
||||
// ==================== 枚举类型 ====================
|
||||
|
||||
/** 场景类型 */
|
||||
export type SceneType = 'phone' | 'face' | 'complaint' | 'after-sales' | 'product-intro'
|
||||
|
||||
/** 难度等级 */
|
||||
export type Difficulty = 'beginner' | 'junior' | 'intermediate' | 'senior' | 'expert'
|
||||
|
||||
/** 场景状态 */
|
||||
export type SceneStatus = 'active' | 'inactive'
|
||||
|
||||
/** 聊天模式 */
|
||||
export enum ChatModel {
|
||||
TEXT = 'text',
|
||||
VOICE = 'voice'
|
||||
}
|
||||
|
||||
/** 连接状态 */
|
||||
export enum ConnectionStatus {
|
||||
UNCONNECTED = 'unconnected',
|
||||
CONNECTING = 'connecting',
|
||||
CONNECTED = 'connected',
|
||||
DISCONNECTED = 'disconnected',
|
||||
ERROR = 'error',
|
||||
WAITING = 'waiting',
|
||||
LISTENING = 'listening'
|
||||
}
|
||||
|
||||
// ==================== 数据模型 ====================
|
||||
|
||||
/** 陪练场景 */
|
||||
export interface PracticeScene {
|
||||
id: number
|
||||
name: string
|
||||
description?: string
|
||||
type: SceneType
|
||||
difficulty: Difficulty
|
||||
status: SceneStatus
|
||||
background: string
|
||||
ai_role: string
|
||||
objectives: string[]
|
||||
keywords?: string[]
|
||||
duration: number
|
||||
usage_count: number
|
||||
rating: number
|
||||
created_by?: number
|
||||
updated_by?: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
/** 消息对象 */
|
||||
export interface Message {
|
||||
id: string
|
||||
role: 'user' | 'assistant'
|
||||
content: string
|
||||
timestamp: number
|
||||
loading?: boolean
|
||||
prologue?: boolean
|
||||
}
|
||||
|
||||
/** Bot信息 */
|
||||
export interface BotInfo {
|
||||
bot_id: string
|
||||
name: string
|
||||
description: string
|
||||
icon_url: string
|
||||
onboarding_info?: {
|
||||
prologue: string
|
||||
suggested_questions: string[]
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 请求/响应 ====================
|
||||
|
||||
/** 获取场景列表请求参数 */
|
||||
export interface GetScenesParams {
|
||||
page?: number
|
||||
size?: number
|
||||
type?: SceneType
|
||||
difficulty?: Difficulty
|
||||
search?: string
|
||||
}
|
||||
|
||||
/** 开始陪练请求参数 */
|
||||
export interface StartPracticeParams {
|
||||
scene_id?: number
|
||||
scene_name?: string
|
||||
scene_description?: string
|
||||
scene_background?: string
|
||||
scene_ai_role?: string
|
||||
scene_objectives?: string[]
|
||||
scene_keywords?: string[]
|
||||
user_message: string
|
||||
conversation_id?: string
|
||||
is_first: boolean
|
||||
}
|
||||
|
||||
/** 中断对话请求参数 */
|
||||
export interface InterruptPracticeParams {
|
||||
conversation_id: string
|
||||
chat_id: string
|
||||
}
|
||||
|
||||
/** 分页响应 */
|
||||
export interface PaginatedResponse<T> {
|
||||
items: T[]
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
pages: number
|
||||
}
|
||||
|
||||
/** 统一响应格式 */
|
||||
export interface ResponseModel<T = any> {
|
||||
code: number
|
||||
message: string
|
||||
data: T
|
||||
request_id?: string
|
||||
}
|
||||
|
||||
// ==================== SSE事件 ====================
|
||||
|
||||
/** SSE事件类型 */
|
||||
export type SSEEventType =
|
||||
| 'conversation.chat.created'
|
||||
| 'message.delta'
|
||||
| 'message.completed'
|
||||
| 'conversation.completed'
|
||||
| 'error'
|
||||
| 'done'
|
||||
|
||||
/** SSE事件数据 */
|
||||
export interface SSEEventData {
|
||||
conversation_id?: string
|
||||
chat_id?: string
|
||||
content?: string
|
||||
token_count?: number
|
||||
input_count?: number
|
||||
output_count?: number
|
||||
error?: string
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user