feat: 添加防抖指令和任务管理功能

feat(anchor): 新增主播管理模块

feat(account): 完善客服账号管理功能

feat(knowledge): 添加任务列表查看和重新执行功能

feat(router): 增强路由组件动态导入逻辑

refactor: 优化多个视图的按钮防抖处理

style: 统一代码格式和样式

fix: 修复客服账号状态切换逻辑
This commit is contained in:
2026-04-20 10:20:45 +08:00
parent 4f547b5bff
commit c4bdfe2bb3
15 changed files with 1035 additions and 134 deletions

View File

@@ -8,11 +8,11 @@
<span class="header-title">知识库</span>
</div>
<div class="header-actions">
<el-button type="primary" @click="onAddknowledge">
<el-button type="primary" v-debounce @click="onAddknowledge">
<el-icon><ele-Plus /></el-icon>
新建知识库
</el-button>
<el-button type="success" @click="onOpenModelConfig">
<el-button type="success" v-debounce @click="onOpenModelConfig">
<el-icon><ele-Setting /></el-icon>
模型配置
</el-button>
@@ -39,12 +39,12 @@
<!-- 悬停操作按钮 -->
<div class="card-actions" @click.stop>
<el-tooltip content="重命名" placement="top">
<el-button text size="small" @click="onRenameknowledge(item)">
<el-button text size="small" v-debounce @click="onRenameknowledge(item)">
<el-icon><ele-Edit /></el-icon>
</el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button text size="small" type="danger" @click="onDeleteknowledge(item)">
<el-button text size="small" type="danger" v-debounce @click="onDeleteknowledge(item)">
<el-icon><ele-Delete /></el-icon>
</el-button>
</el-tooltip>
@@ -125,7 +125,7 @@
<el-icon><ele-Search /></el-icon>
</template>
</el-input>
<el-button type="primary" @click="onUploadFile">
<el-button type="primary" v-debounce @click="onUploadFile">
<el-icon><ele-Plus /></el-icon>
新增文件
</el-button>
@@ -146,17 +146,20 @@
</el-table-column>
<el-table-column prop="vectorStatus" label="向量化" width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.vectorStatus === 2 ? 'success' : 'warning'" size="small">
{{ row.vectorStatus === 2 ? '已完成' : '未完成' }}
<el-tag :type="getVectorStatusType(row.vectorStatus)" size="small">
{{ getVectorStatusText(row.vectorStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createdAt" label="上传日期" width="180" />
<el-table-column label="动作" width="180" align="center">
<template #default="{ row }">
<el-button text size="small" @click="onPreviewFile(row)">预览</el-button>
<el-button text size="small" type="primary" @click="onGenerateVector(row)">生成向量</el-button>
<el-button text size="small" type="danger" @click="onDeleteFile(row)">删除</el-button>
<el-button text size="small" v-debounce @click="onPreviewFile(row)">预览</el-button>
<el-button v-if="row.vectorStatus === 1" text size="small" type="primary" v-debounce @click="onGenerateVector(row)"
>生成向量</el-button
>
<el-button v-else text size="small" type="primary" v-debounce @click="onViewTaskList(row)">查看任务</el-button>
<el-button text size="small" type="danger" v-debounce @click="onDeleteFile(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
@@ -169,7 +172,7 @@
<div class="panel-card">
<h3>检索测试</h3>
<el-input v-model="searchQuery" type="textarea" :rows="3" placeholder="输入问题进行检索测试..." />
<el-button type="primary" class="mt15" @click="onSearchTest">测试检索</el-button>
<el-button type="primary" class="mt15" v-debounce @click="onSearchTest">测试检索</el-button>
<div class="search-results mt15" v-if="searchResults.length > 0">
<h4>检索结果</h4>
<div class="result-item" v-for="(item, index) in searchResults" :key="index">
@@ -215,7 +218,7 @@
<el-input-number v-model="settingsForm.chunkOverlap" :min="0" :max="500" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSaveSettings">保存配置</el-button>
<el-button type="primary" v-debounce @click="onSaveSettings">保存配置</el-button>
</el-form-item>
</el-form>
</div>
@@ -236,7 +239,7 @@
</el-form>
<template #footer>
<el-button @click="showknowledgeDialog = false">取消</el-button>
<el-button type="primary" @click="onSaveknowledge" :loading="knowledgeSaving">确定</el-button>
<el-button type="primary" v-debounce @click="onSaveknowledge" :loading="knowledgeSaving">确定</el-button>
</template>
</el-dialog>
@@ -261,7 +264,7 @@
</el-upload>
<template #footer>
<el-button @click="showUploadDialog = false">取消</el-button>
<el-button type="primary" @click="onConfirmUpload" :loading="uploading" :disabled="uploadFileList.length === 0">
<el-button type="primary" v-debounce @click="onConfirmUpload" :loading="uploading" :disabled="uploadFileList.length === 0">
上传 ({{ uploadFileList.length }} 个文件)
</el-button>
</template>
@@ -278,7 +281,7 @@
<!-- 模型配置弹窗 -->
<el-dialog title="模型配置" v-model="showModelConfigDialog" width="1000px" :close-on-click-modal="false">
<div class="model-config-list" v-loading="modelConfigLoading">
<el-button type="primary" style="margin-bottom: 16px" @click="onCreateModelConfig">
<el-button type="primary" style="margin-bottom: 16px" v-debounce @click="onCreateModelConfig">
<el-icon><ele-Plus /></el-icon>
创建模型配置
</el-button>
@@ -299,7 +302,7 @@
</el-table-column>
<el-table-column label="操作" width="80" align="center">
<template #default="{ row }">
<el-button text size="small" type="primary" @click="onEditModelConfig(row)">编辑</el-button>
<el-button text size="small" type="primary" v-debounce @click="onEditModelConfig(row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
@@ -310,6 +313,53 @@
</template>
</el-dialog>
<!-- 任务列表弹窗 -->
<el-dialog title="任务列表" v-model="showTaskListDialog" width="900px" :close-on-click-modal="false">
<el-table :data="taskList" style="width: 100%" border v-loading="taskListLoading">
<el-table-column prop="taskType" label="任务类型" width="150">
<template #default="{ row }">
{{ getTaskTypeText(row.taskType) }}
</template>
</el-table-column>
<el-table-column prop="status" label="任务状态" width="120">
<template #default="{ row }">
<el-tag :type="getTaskStatusType(row.status)" size="small">
{{ getTaskStatusText(row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="200" />
<el-table-column prop="startTime" label="开始时间" width="180">
<template #default="{ row }">
{{ row.startTime ? formatDateTime(row.startTime) : '-' }}
</template>
</el-table-column>
<el-table-column prop="endTime" label="结束时间" width="180">
<template #default="{ row }">
{{ row.endTime ? formatDateTime(row.endTime) : '-' }}
</template>
</el-table-column>
<el-table-column label="操作" width="120" align="center">
<template #default="{ row }">
<el-button
v-if="row.status === 'FAILED' || row.status === 'COMPLETED'"
text
size="small"
type="primary"
v-debounce
@click="onReexecuteTask(row)"
>重新执行</el-button
>
<el-button v-else text size="small" type="info" disabled>执行中</el-button>
</template>
</el-table-column>
</el-table>
<el-empty v-if="taskList.length === 0 && !taskListLoading" description="暂无任务" :image-size="60" />
<template #footer>
<el-button @click="showTaskListDialog = false">关闭</el-button>
</template>
</el-dialog>
<!-- 创建/编辑模型配置弹窗 -->
<el-dialog :title="isEditMode ? '编辑模型配置' : '创建模型配置'" v-model="showCreateModelDialog" width="600px" :close-on-click-modal="false">
<div v-loading="modelEnumsLoading || modelFormLoading">
@@ -356,7 +406,7 @@
</div>
<template #footer>
<el-button @click="showCreateModelDialog = false">取消</el-button>
<el-button type="primary" @click="onSaveModelConfig()" :disabled="!selectedModelType || !selectedConfigType"> 保存 </el-button>
<el-button type="primary" v-debounce @click="onSaveModelConfig" :disabled="!selectedModelType || !selectedConfigType"> 保存 </el-button>
</template>
</el-dialog>
</div>
@@ -374,7 +424,17 @@ import { ElMessage, ElMessageBox } from 'element-plus';
import type { FormInstance, FormRules, UploadFile } from 'element-plus';
import DocumentDetailDialog from './component/documentDetailDialog.vue';
import { listknowledges, createknowledge, updateknowledge, deleteknowledge } from '/@/api/knowledge/dataset';
import { listDocuments, uploadFile, createDocument, deleteDocument, updateDocument, generateVector, getDocument } from '/@/api/knowledge/document';
import {
listDocuments,
uploadFile,
createDocument,
deleteDocument,
updateDocument,
generateVector,
getDocument,
listTasks,
reexecuteTask,
} from '/@/api/knowledge/document';
import { listModelConfigs, createModelConfig, updateModelConfig, getModelConfig, getAllModelEnums, getModelFormField } from '/@/api/knowledge/model';
// 数据集相关
@@ -389,6 +449,11 @@ const showModelConfigDialog = ref(false);
const modelConfigList = ref<any[]>([]);
const modelConfigLoading = ref(false);
// 任务列表相关
const showTaskListDialog = ref(false);
const taskList = ref<any[]>([]);
const taskListLoading = ref(false);
// 创建模型配置相关
const showCreateModelDialog = ref(false);
const modelEnums = ref<any[]>([]);
@@ -995,6 +1060,101 @@ const formatDateTime = (dateTime: string) => {
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
// 获取向量状态文本
const getVectorStatusText = (status: number) => {
const statusMap: Record<number, string> = {
1: '待处理',
2: '处理中',
3: '已完成',
4: '失败',
};
return statusMap[status] || '未知';
};
// 获取向量状态标签类型
const getVectorStatusType = (status: number) => {
const typeMap: Record<number, any> = {
1: 'warning',
2: 'primary',
3: 'success',
4: 'danger',
};
return typeMap[status] || 'info';
};
// 获取任务类型文本
const getTaskTypeText = (taskType: string) => {
const typeMap: Record<string, string> = {
EXTRACT_KEYWORDS: '提取关键词',
GENERATE_VECTOR: '生成向量',
FULL_TEXT_SEARCH: '全文检索',
DOC_PARSE: '文档解析',
};
return typeMap[taskType] || taskType;
};
// 获取任务状态文本
const getTaskStatusText = (status: string) => {
const statusMap: Record<string, string> = {
PENDING: '待执行',
RUNNING: '执行中',
COMPLETED: '已完成',
FAILED: '执行失败',
};
return statusMap[status] || status;
};
// 获取任务状态标签类型
const getTaskStatusType = (status: string) => {
const typeMap: Record<string, any> = {
PENDING: 'warning',
RUNNING: 'primary',
COMPLETED: 'success',
FAILED: 'danger',
};
return typeMap[status] || 'info';
};
// 查看任务列表
const onViewTaskList = async (row: any) => {
showTaskListDialog.value = true;
await getTaskList();
};
// 获取任务列表
const getTaskList = async () => {
taskListLoading.value = true;
try {
const response = await listTasks();
taskList.value = response.data?.list || [];
} catch (error) {
ElMessage.error('获取任务列表失败');
taskList.value = [];
} finally {
taskListLoading.value = false;
}
};
// 重新执行任务
const onReexecuteTask = async (task: any) => {
ElMessageBox.confirm(`确定要重新执行任务【${getTaskTypeText(task.taskType)}】吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
try {
await reexecuteTask(task.id);
ElMessage.success('重新执行任务成功');
// 重新获取任务列表
await getTaskList();
} catch (error) {
ElMessage.error('重新执行任务失败,请重试');
}
})
.catch(() => {});
};
// 页面加载
onMounted(() => {
getknowledgeList();