feat(文档管理): 添加文档状态更新和向量生成功能

refactor(话术管理): 重构话术列表和编辑界面,调整API路径

fix(请求拦截器): 移除调试日志并优化错误处理

style(分页组件): 格式化代码并添加初始化标记

feat(知识库): 实现文档状态切换和向量生成功能
This commit is contained in:
2026-04-11 16:11:00 +08:00
parent c80f67d2ab
commit 4c91dd6fd5
8 changed files with 1199 additions and 563 deletions

View File

@@ -3,7 +3,7 @@ import request from '/@/utils/request';
//获取话术列表 //获取话术列表
export function getscriptList(data: object) { export function getscriptList(data: object) {
return request({ return request({
url: '/customer-server/speechcraft/list', url: '/customer-server/scripted/speech/list',
method: 'get', method: 'get',
params: data, params: data,
}); });
@@ -12,7 +12,7 @@ export function getscriptList(data: object) {
//增加话术 //增加话术
export function addScript(data: object) { export function addScript(data: object) {
return request({ return request({
url: '/customer-server/speechcraft/add', url: '/customer-server/scripted/speech/add',
method: 'post', method: 'post',
data: data, data: data,
}); });
@@ -21,7 +21,7 @@ export function addScript(data: object) {
//删除话术列表 //删除话术列表
export function deleteScript(data: object) { export function deleteScript(data: object) {
return request({ return request({
url: '/customer-server/speechcraft/delete', url: '/customer-server/scripted/speech/delete',
method: 'post', method: 'post',
data: data, data: data,
}); });
@@ -30,8 +30,17 @@ export function deleteScript(data: object) {
//更新话术列表 //更新话术列表
export function updateScript(data: object) { export function updateScript(data: object) {
return request({ return request({
url: '/customer-server/speechcraft/update', url: '/customer-server/scripted/speech/update',
method: 'post', method: 'post',
data: data, data: data,
}); });
} }
//获取话术详情
export function getScriptDetail(data: object) {
return request({
url: '/customer-server/scripted/speech/getOne',
method: 'get',
params: data,
});
}

View File

@@ -29,6 +29,7 @@ export interface UpdateDocumentParams {
fileSize?: number; fileSize?: number;
format?: string; format?: string;
title?: string; title?: string;
status?: number;
} }
// 文档分段查询参数 // 文档分段查询参数
@@ -184,3 +185,12 @@ export function getDocumentProcess(id: string) {
params: { id }, params: { id },
}); });
} }
// 生成向量
export function generateVector(id: string, datasetId: string) {
return request({
url: '/rag/document/vectorization',
method: 'post',
data: { id, datasetId },
});
}

View File

@@ -1,100 +1,113 @@
<template> <template>
<div :class="{'hidden':hidden}" class="pagination-container"> <div :class="{ hidden: hidden }" class="pagination-container">
<el-pagination <el-pagination
:background="background" :background="background"
v-model:current-page="currentPage" v-model:current-page="currentPage"
v-model:page-size="pageSize" v-model:page-size="pageSize"
:layout="layout" :layout="layout"
:page-sizes="pageSizes" :page-sizes="pageSizes"
:pager-count="pagerCount" :pager-count="pagerCount"
:total="total" :total="total"
@size-change="handleSizeChange" @size-change="handleSizeChange"
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
/> />
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { toRefs, defineComponent,computed } from 'vue'; import { toRefs, defineComponent, computed, ref, onMounted } from 'vue';
const props = { const props = {
total: { total: {
required: true, required: true,
type: Number type: Number,
}, },
page: { page: {
type: Number, type: Number,
default: 1 default: 1,
}, },
limit: { limit: {
type: Number, type: Number,
default: 20 default: 20,
}, },
pageSizes: { pageSizes: {
type: Array, type: Array,
default() { default() {
return [10, 20, 30, 50] return [10, 20, 30, 50];
} },
}, },
// 移动端页码按钮的数量端默认值5 // 移动端页码按钮的数量端默认值5
pagerCount: { pagerCount: {
type: Number, type: Number,
default: document.body.clientWidth < 992 ? 5 : 7 default: document.body.clientWidth < 992 ? 5 : 7,
}, },
layout: { layout: {
type: String, type: String,
default: 'total, sizes, prev, pager, next, jumper' default: 'total, sizes, prev, pager, next, jumper',
}, },
background: { background: {
type: Boolean, type: Boolean,
default: true default: true,
}, },
hidden: { hidden: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}; };
export default defineComponent({ export default defineComponent({
name: 'pagination', name: 'pagination',
props: props, props: props,
setup(props,{emit}){ setup(props, { emit }) {
const { page,limit,pageSizes } = toRefs(props); const { page, limit } = toRefs(props);
const currentPage = computed({ const isInitialized = ref(false);
get() {
return page.value; const currentPage = computed({
}, get() {
set(val) { return page.value;
emit('update:page', val) },
} set(val) {
}); emit('update:page', val);
const pageSize = computed({ },
get() { });
return limit.value const pageSize = computed({
}, get() {
set(val) { return limit.value;
emit('update:limit', val) },
} set(val) {
}); emit('update:limit', val);
const handleSizeChange = (val:number) => { },
emit('pagination', { page: currentPage.value, limit: val }) });
};
const handleCurrentChange=(val:number) => { const handleSizeChange = (val: number) => {
emit('pagination', { page: val, limit: pageSizes.value }) if (isInitialized.value) {
} emit('pagination', { page: currentPage.value, limit: val });
return { }
currentPage, };
pageSize, const handleCurrentChange = (val: number) => {
handleSizeChange, if (isInitialized.value) {
handleCurrentChange emit('pagination', { page: val, limit: pageSize.value });
} }
} };
// 组件挂载后标记为已初始化
onMounted(() => {
isInitialized.value = true;
});
return {
currentPage,
pageSize,
handleSizeChange,
handleCurrentChange,
};
},
}); });
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.pagination-container { .pagination-container {
padding: 32px 16px; padding: 32px 16px;
} }
.pagination-container.hidden { .pagination-container.hidden {
display: none; display: none;
} }
</style> </style>

View File

@@ -108,8 +108,6 @@ const requestInterceptor = (config: InternalAxiosRequestConfig) => {
// 没有变化,只传递 id // 没有变化,只传递 id
config.data = { id: idField }; config.data = { id: idField };
} }
console.log('[最小化传参] 原始字段数:', Object.keys(currentData).length, '-> 传递字段数:', Object.keys(config.data).length);
} }
} }
@@ -155,7 +153,6 @@ const responseInterceptor = (response: AxiosResponse) => {
if (code === 402 && !requestUrl.includes('/assets/asset/sku/')) { if (code === 402 && !requestUrl.includes('/assets/asset/sku/')) {
// 获取当前路由路径 // 获取当前路由路径
const currentPath = window.location.hash.replace('#', '') || window.location.pathname; const currentPath = window.location.hash.replace('#', '') || window.location.pathname;
console.log('[request.ts] 检测到403错误当前路径:', currentPath);
handleModuleNotEnabled(currentPath); handleModuleNotEnabled(currentPath);
// 直接返回,不再显示错误消息 // 直接返回,不再显示错误消息
return Promise.reject(new Error('模块未开通')); return Promise.reject(new Error('模块未开通'));
@@ -173,8 +170,6 @@ const responseInterceptor = (response: AxiosResponse) => {
// 响应错误拦截器 // 响应错误拦截器
const responseErrorHandler = (error: any) => { const responseErrorHandler = (error: any) => {
console.error('API请求错误:', error);
if (error.code === 'ECONNABORTED' && error.message.includes('timeout')) { if (error.code === 'ECONNABORTED' && error.message.includes('timeout')) {
showErrorMessage('请求超时,请检查网络连接'); showErrorMessage('请求超时,请检查网络连接');
return Promise.reject(new Error('请求超时')); return Promise.reject(new Error('请求超时'));
@@ -206,13 +201,11 @@ const responseErrorHandler = (error: any) => {
const lastSubscribeTime = sessionStorage.getItem('lastSubscribeTime'); const lastSubscribeTime = sessionStorage.getItem('lastSubscribeTime');
const now = Date.now(); const now = Date.now();
if (lastSubscribeTime && now - parseInt(lastSubscribeTime) < 5000) { if (lastSubscribeTime && now - parseInt(lastSubscribeTime) < 5000) {
console.log('[responseErrorHandler] 刚完成开通跳过402处理');
showErrorMessage(responseMessage || '服务开通中,请稍后刷新页面'); showErrorMessage(responseMessage || '服务开通中,请稍后刷新页面');
return Promise.reject(new Error('模块开通中')); return Promise.reject(new Error('模块开通中'));
} }
const currentPath = window.location.hash.replace('#', '') || window.location.pathname; const currentPath = window.location.hash.replace('#', '') || window.location.pathname;
console.log('[responseErrorHandler] 检测到HTTP 402错误当前路径:', currentPath);
handleModuleNotEnabled(currentPath); handleModuleNotEnabled(currentPath);
return Promise.reject(new Error('模块未开通')); return Promise.reject(new Error('模块未开通'));
} }

File diff suppressed because it is too large Load Diff

View File

@@ -4,14 +4,18 @@
<el-form ref="formRef" :model="formData" :rules="rules" size="default" label-width="90px"> <el-form ref="formRef" :model="formData" :rules="rules" size="default" label-width="90px">
<el-row :gutter="35"> <el-row :gutter="35">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20"> <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="标签" prop="tag"> <el-form-item label="数据集">
<el-input v-model="formData.tag" placeholder="请输入标签" clearable /> <el-input v-model="formData.datasetName" placeholder="数据集" disabled />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
<el-form-item label="场景类型">
<el-input v-model="formData.sceneType" placeholder="场景类型" disabled />
</el-form-item> </el-form-item>
</el-col> </el-col>
<!-- 富文本编辑器 -->
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="话术" prop="content"> <el-form-item label="话术内容" prop="questionContent">
<Editor v-model="formData.content" height="400px" :key="editorKey" placeholder="请输入产品详情" :disableExceptEmotion="true" /> <Editor v-model="formData.questionContent" height="400px" :key="editorKey" placeholder="请输入话术内容" :disableExceptEmotion="true" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -29,18 +33,19 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, toRefs, nextTick } from 'vue'; import { ref, reactive, toRefs, nextTick, onMounted } from 'vue';
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'; import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
import Editor from '/@/components/editor/index.vue'; import Editor from '/@/components/editor/index.vue';
import { addScript, updateScript } from '/@/api/customerService/script'; import { addScript, updateScript, getScriptDetail } from '/@/api/customerService/script';
import { listknowledges } from '/@/api/knowledge/dataset';
// 定义类型接口 // 定义类型接口
interface DialogRow { interface DialogRow {
id?: number | string; id?: number;
tag: string; datasetId: string | number;
creator: string; datasetName?: string;
content: string; sceneType: number;
modifier: string; questionContent: string;
} }
// 定义事件 // 定义事件
@@ -48,30 +53,30 @@ const emit = defineEmits<{
(e: 'refresh'): void; (e: 'refresh'): void;
}>(); }>();
// 定义数据集选项类型
interface DatasetOption {
label: string;
value: string;
}
// 响应式数据 // 响应式数据
const state = reactive({ const state = reactive({
loading: false, loading: false,
isShowDialog: false, isShowDialog: false,
datasets: [] as DatasetOption[], // 数据集列表
editorKey: 0, // 用于强制重新渲染编辑器 editorKey: 0, // 用于强制重新渲染编辑器
formData: { formData: {
id: 0, id: 0,
tag: '', datasetId: 0,
content: '', datasetName: '',
creator: '', sceneType: 0,
modifier: '', questionContent: '',
} as DialogRow, } as DialogRow,
}); });
// 表单验证规则 // 表单验证规则
const rules: FormRules = { const rules: FormRules = {
tag: [ questionContent: [{ required: true, message: '话术内容不能为空', trigger: 'blur' }],
{ required: true, message: '标签名称不能为空', trigger: 'blur' },
{ max: 64, message: '标签长度最多 64 个字符', trigger: 'blur' },
],
content: [
{ required: true, message: '产品详情不能为空', trigger: 'blur' },
{ max: 8126, message: '产品名称长度最多 8126 个字符', trigger: 'blur' },
],
}; };
// 模板引用 // 模板引用
@@ -80,28 +85,74 @@ const formRef = ref<FormInstance>();
// 解构状态数据 // 解构状态数据
const { loading, isShowDialog, formData, editorKey } = toRefs(state); const { loading, isShowDialog, formData, editorKey } = toRefs(state);
/**
* 加载数据集列表
*/
const loadDatasets = async () => {
try {
const response = await listknowledges({ pageNum: 1, pageSize: 100 });
if (response.data && response.data.list) {
state.datasets = response.data.list.map((item: any) => ({
label: item.name,
value: item.id,
}));
}
} catch (error) {
ElMessage.error('加载数据集列表失败');
}
};
// 生命周期
onMounted(() => {
loadDatasets();
});
/** /**
* 打开对话框 * 打开对话框
* @param row - 可选的编辑数据 * @param row - 可选的编辑数据
*/ */
const openDialog = (row?: DialogRow) => { const openDialog = async (row?: DialogRow) => {
resetForm(); resetForm();
if (row) { // 重新加载数据集列表,确保数据是最新的
// 深拷贝数据,避免引用问题 await loadDatasets();
state.formData = { ...row };
if (row && row.id) {
try {
// 加载话术详情
const response = await getScriptDetail({ id: row.id });
if (response.data) {
// 确保datasetId是字符串类型与datasets选项的value类型一致
const detailData = {
...response.data,
datasetId: String(response.data.datasetId),
datasetName: '',
};
// 查找对应的数据集名称
const dataset = state.datasets.find((d) => d.value === detailData.datasetId);
if (dataset) {
detailData.datasetName = dataset.label;
}
state.formData = detailData;
}
} catch (error) {
ElMessage.error('获取话术详情失败');
return;
}
} else { } else {
// 新增模式,确保清空数据 // 新增模式,确保清空数据
state.formData = { state.formData = {
id: 0, id: 0,
tag: '', datasetId: 0,
content: '', datasetName: '',
creator: '', sceneType: 0,
modifier: '', questionContent: '',
}; };
} }
// 更新编辑器 key 强制重新渲染 // 强制重新渲染编辑器
state.editorKey++; state.editorKey++;
state.isShowDialog = true; state.isShowDialog = true;
@@ -139,21 +190,22 @@ const onSubmit = async () => {
const valid = await formRef.value.validate(); const valid = await formRef.value.validate();
if (!valid) return; if (!valid) return;
// 额外验证话术内容 // 确保数据类型正确
if (!state.formData.content || state.formData.content === '<p><br></p>' || state.formData.content.trim() === '<p><br></p>') { const submitData = {
ElMessage.warning('话术内容不能为空'); ...state.formData,
return; datasetId: String(state.formData.datasetId),
} sceneType: Number(state.formData.sceneType),
};
state.loading = true; state.loading = true;
if (state.formData.id === 0) { if (state.formData.id === 0) {
// 新增模式 // 新增模式
await addScript(state.formData); await addScript(submitData);
ElMessage.success('添加成功'); ElMessage.success('添加成功');
} else { } else {
// 编辑模式 // 编辑模式
await updateScript(state.formData); await updateScript(submitData);
ElMessage.success('修改成功'); ElMessage.success('修改成功');
} }
@@ -161,7 +213,6 @@ const onSubmit = async () => {
state.isShowDialog = false; state.isShowDialog = false;
emit('refresh'); emit('refresh');
} catch (error) { } catch (error) {
console.error('提交失败:', error);
// 错误已由请求拦截器统一处理 // 错误已由请求拦截器统一处理
} finally { } finally {
state.loading = false; state.loading = false;
@@ -174,10 +225,10 @@ const onSubmit = async () => {
const resetForm = () => { const resetForm = () => {
state.formData = { state.formData = {
id: 0, id: 0,
tag: '', datasetId: 0,
content: '', datasetName: '',
creator: '', sceneType: 0,
modifier: '', questionContent: '',
}; };
// 重置表单验证状态 // 重置表单验证状态

View File

@@ -20,7 +20,7 @@
</el-icon> </el-icon>
重置 重置
</el-button> </el-button>
<el-button size="default" type="success" @click="handleAdd"> <el-button size="default" type="success" @click="handleAdd">
<el-icon><FolderAdd /></el-icon> <el-icon><FolderAdd /></el-icon>
新增话术 新增话术
</el-button> </el-button>
@@ -31,9 +31,10 @@
<!-- 数据表格 --> <!-- 数据表格 -->
<el-table :data="tableData.data" v-loading="tableData.loading" style="width: 100%"> <el-table :data="tableData.data" v-loading="tableData.loading" style="width: 100%">
<el-table-column type="index" label="序号" width="60" align="center" /> <el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="tag" label="标签" show-overflow-tooltip min-width="120" /> <el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="creator" label="创建人" show-overflow-tooltip min-width="100" /> <el-table-column prop="datasetId" label="数据集ID" width="120" align="center" />
<el-table-column prop="updater" label="修改人" show-overflow-tooltip min-width="100" /> <el-table-column prop="sceneType" label="场景类型" width="120" align="center" />
<el-table-column prop="questionContent" label="问题内容" show-overflow-tooltip min-width="200" />
<el-table-column prop="createdAt" label="创建时间" show-overflow-tooltip min-width="140"> <el-table-column prop="createdAt" label="创建时间" show-overflow-tooltip min-width="140">
<template #default="{ row }"> <template #default="{ row }">
{{ formatTime(row.createdAt) }} {{ formatTime(row.createdAt) }}
@@ -81,13 +82,12 @@ import { getscriptList, deleteScript } from '/@/api/customerService/script';
// ==================== 类型定义 ==================== // ==================== 类型定义 ====================
interface ScriptItem { interface ScriptItem {
id: string; id: number;
tag: string; datasetId: number;
creator: string; sceneType: number;
modifier: string; questionContent: string;
createdAt: string; // 保持原字段不变 createdAt: string;
updatedAt: string; // 保持原字段不变 updatedAt: string;
content?: string;
} }
interface TableParams { interface TableParams {
@@ -176,7 +176,6 @@ const formatTime = (time: string | number | Date): string => {
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
} catch (error) { } catch (error) {
console.error('时间格式化错误:', error);
return String(time); return String(time);
} }
}; };
@@ -196,8 +195,6 @@ const loadTableData = async () => {
tableData.data = list; tableData.data = list;
tableData.total = total; tableData.total = total;
} catch (error) { } catch (error) {
console.error('加载数据失败:', error);
// 错误已由请求拦截器统一处理
tableData.data = []; tableData.data = [];
tableData.total = 0; tableData.total = 0;
} finally { } finally {
@@ -215,8 +212,8 @@ const handleAdd = () => {
/** /**
* 编辑话术 * 编辑话术
*/ */
const handleEdit = (row: ScriptItem) => { const handleEdit = async (row: ScriptItem) => {
editRoleRef.value?.openDialog(row as any); await editRoleRef.value?.openDialog(row as any);
}; };
/** /**
@@ -224,7 +221,7 @@ const handleEdit = (row: ScriptItem) => {
*/ */
const handleDelete = async (row: ScriptItem) => { const handleDelete = async (row: ScriptItem) => {
try { try {
await ElMessageBox.confirm(`确定要删除话术「${row.tag}」吗?此操作不可恢复。`, '提示', { await ElMessageBox.confirm(`确定要删除话术「${row.questionContent}」吗?此操作不可恢复。`, '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
@@ -237,19 +234,11 @@ const handleDelete = async (row: ScriptItem) => {
await loadTableData(); await loadTableData();
} catch (error) { } catch (error) {
if (error !== 'cancel') { if (error !== 'cancel') {
console.error('删除失败:', error);
// 错误已由请求拦截器统一处理 // 错误已由请求拦截器统一处理
} }
} }
}; };
/**
* 操作成功回调
*/
const handleSuccess = () => {
loadTableData();
};
// ==================== 生命周期 ==================== // ==================== 生命周期 ====================
onMounted(() => { onMounted(() => {
loadTableData(); loadTableData();

View File

@@ -127,32 +127,37 @@
</div> </div>
<div class="file-table" v-loading="fileLoading"> <div class="file-table" v-loading="fileLoading">
<el-table :data="fileList" style="width: 100%" row-key="id" border> <el-table :data="fileList" style="width: 100%" row-key="id" border>
<el-table-column prop="Title" label="名称" min-width="200"> <el-table-column prop="title" label="名称" min-width="200">
<template #default="scope"> <template #default="scope">
<span class="file-link" @click="onViewDocumentDetail(scope.row)" style="cursor: pointer; color: #409eff">{{ <span class="file-link" @click="onViewDocumentDetail(scope.row)" style="cursor: pointer; color: #409eff">{{
scope.row.Title scope.row.title
}}</span> }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="chunkCount" label="分块数" width="80" align="center" /> <el-table-column prop="chunkCount" label="分块数" width="80" align="center" />
<el-table-column prop="status" label="状态" width="90" align="center"> <el-table-column prop="status" label="状态" width="90" align="center">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'" size="small"> <el-switch
{{ scope.row.status === 1 ? '正常' : '禁用' }} v-model="scope.row.statusEnabled"
</el-tag> inline-prompt
active-text=""
inactive-text=""
@change="onFileStatusChange(scope.row)"
/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="vectorStatus" label="向量化" width="100" align="center"> <el-table-column prop="vectorStatus" label="向量化" width="100" align="center">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.vectorStatus === 'done' ? 'success' : 'warning'" size="small"> <el-tag :type="scope.row.vectorStatus === 2 ? 'success' : 'warning'" size="small">
{{ scope.row.vectorStatus || '未处理' }} {{ scope.row.vectorStatus === 2 ? '已完成' : '未完成' }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="createdAt" label="上传日期" width="180" /> <el-table-column prop="createdAt" label="上传日期" width="180" />
<el-table-column label="动作" width="120" align="center"> <el-table-column label="动作" width="180" align="center">
<template #default="scope"> <template #default="scope">
<el-button text size="small" @click="onPreviewFile(scope.row)">预览</el-button> <el-button text size="small" @click="onPreviewFile(scope.row)">预览</el-button>
<el-button text size="small" type="primary" @click="onGenerateVector(scope.row)">生成向量</el-button>
<el-button text size="small" type="danger" @click="onDeleteFile(scope.row)">删除</el-button> <el-button text size="small" type="danger" @click="onDeleteFile(scope.row)">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
@@ -286,7 +291,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
import type { FormInstance, FormRules, UploadFile } from 'element-plus'; import type { FormInstance, FormRules, UploadFile } from 'element-plus';
import DocumentDetailDialog from './component/documentDetailDialog.vue'; import DocumentDetailDialog from './component/documentDetailDialog.vue';
import { listknowledges, createknowledge, updateknowledge, deleteknowledge } from '/@/api/knowledge/dataset'; import { listknowledges, createknowledge, updateknowledge, deleteknowledge } from '/@/api/knowledge/dataset';
import { listDocuments, uploadFile, createDocument, deleteDocument } from '/@/api/knowledge/document'; import { listDocuments, uploadFile, createDocument, deleteDocument, updateDocument, generateVector, getDocument } from '/@/api/knowledge/document';
// 数据集相关 // 数据集相关
const knowledgeLoading = ref(false); const knowledgeLoading = ref(false);
@@ -497,7 +502,10 @@ const getFileList = async () => {
pageNum: 1, pageNum: 1,
pageSize: 100, pageSize: 100,
}); });
fileList.value = response.data?.list || []; fileList.value = (response.data?.list || []).map((item: any) => ({
...item,
statusEnabled: item.status === 1,
}));
} catch (_error) { } catch (_error) {
ElMessage.error('获取文件列表失败'); ElMessage.error('获取文件列表失败');
} finally { } finally {
@@ -578,14 +586,47 @@ const onConfirmUpload = async () => {
}; };
// 文件状态变化 // 文件状态变化
const _onFileStatusChange = (row: any) => { const onFileStatusChange = async (row: any) => {
ElMessage.success(row.enabled ? '已启用' : '已禁用'); const newStatus = row.statusEnabled ? 1 : 0;
try {
// 调用后端API来更新文件状态
await updateDocument({
id: row.id,
status: newStatus,
});
ElMessage.success(row.statusEnabled ? '已启用' : '已禁用');
} catch (error) {
// 失败时恢复原状态
row.statusEnabled = !row.statusEnabled;
ElMessage.error('状态更新失败');
}
};
// 生成向量
const onGenerateVector = async (row: any) => {
try {
// 调用后端API来生成向量传递id和datasetId
await generateVector(row.id, currentknowledge.value.id);
ElMessage.success('生成向量任务已提交');
// 模拟更新状态
setTimeout(() => {
getFileList();
}, 1000);
} catch (error) {
ElMessage.error('生成向量失败');
}
}; };
// 查看文档详情 // 查看文档详情
const onViewDocumentDetail = (row: any) => { const onViewDocumentDetail = async (row: any) => {
currentDocument.value = row; try {
showDocumentDetailDialog.value = true; // 调用getDocument接口获取最新的文件详情
const response = await getDocument(row.id);
currentDocument.value = response.data;
showDocumentDetailDialog.value = true;
} catch (error) {
ElMessage.error('获取文件详情失败');
}
}; };
// 预览文件 // 预览文件