|
@@ -1,48 +1,76 @@
|
|
|
<template>
|
|
|
<el-container style="height: 100vh; padding: 20px;">
|
|
|
- <!-- Header: Knowledge Base title + Create button -->
|
|
|
+ <!-- Header -->
|
|
|
<el-header style="display: flex; justify-content: space-between; align-items: center; padding: 20px;">
|
|
|
<div style="font-size: 28px; font-weight: bold; color: #333;">知识库</div>
|
|
|
- <el-button type="primary" @click="showCreateModal" style="border-radius: 20px;">创建知识库</el-button>
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ @click="showCreateModal"
|
|
|
+ style="border-radius: 20px;"
|
|
|
+ :loading="loading.create"
|
|
|
+ >
|
|
|
+ 创建知识库
|
|
|
+ </el-button>
|
|
|
</el-header>
|
|
|
|
|
|
- <!-- Content Area: Display Knowledge Base List -->
|
|
|
+ <!-- Content Area -->
|
|
|
<el-main style="padding: 20px;">
|
|
|
<div class="knowledge-base-grid">
|
|
|
<el-card
|
|
|
v-for="item in knowledgeBaseList"
|
|
|
:key="item.dataset_id"
|
|
|
- :body-style="{ padding: '20px', borderRadius: '12px' }"
|
|
|
+ :body-style="{ padding: '20px', borderRadius: '12px', position: 'relative' }"
|
|
|
class="box-card"
|
|
|
- @click="goToDetailPage(item.dataset_id, item.name)"
|
|
|
>
|
|
|
- <div style="font-size: 18px; font-weight: bold; margin-bottom: 10px; color: #2c3e50;">
|
|
|
- {{ item.name }}
|
|
|
+ <!-- 美观的删除按钮 -->
|
|
|
+ <el-button
|
|
|
+ circle
|
|
|
+ size="small"
|
|
|
+ style="position: absolute; top: 10px; right: 10px; width: 28px; height: 28px;"
|
|
|
+ @click.stop="confirmDelete(item.dataset_id, item.name)"
|
|
|
+ >
|
|
|
+ <el-icon><CloseBold /></el-icon>
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+ <!-- 点击卡片跳转详情 -->
|
|
|
+ <div
|
|
|
+ style="cursor: pointer"
|
|
|
+ @click="goToDetailPage(item.dataset_id, item.name)"
|
|
|
+ >
|
|
|
+ <div style="font-size: 18px; font-weight: bold; margin-bottom: 10px; color: #2c3e50;">
|
|
|
+ {{ item.name }}
|
|
|
+ </div>
|
|
|
+ <div style="color: #7f8c8d;">文档数量:{{ item.count }}</div>
|
|
|
+ <div style="color: #7f8c8d;">创建时间:{{ item.created_at }}</div>
|
|
|
</div>
|
|
|
- <div style="color: #7f8c8d;">文档数量:{{ item.count }}</div>
|
|
|
- <div style="color: #7f8c8d;">创建时间:{{ item.created_at }}</div>
|
|
|
</el-card>
|
|
|
+
|
|
|
+
|
|
|
</div>
|
|
|
</el-main>
|
|
|
|
|
|
- <!-- Modal for Creating Knowledge Base -->
|
|
|
+ <!-- 创建知识库弹窗 -->
|
|
|
<el-dialog v-model="createModalVisible" title="创建知识库" width="400px" style="border-radius: 12px;">
|
|
|
<el-input
|
|
|
v-model="newKnowledgeBaseTitle"
|
|
|
placeholder="请输入知识库名称"
|
|
|
maxlength="64"
|
|
|
style="border-radius: 10px; padding: 10px;"
|
|
|
+ :disabled="loading.create"
|
|
|
/>
|
|
|
- <!-- 显示已输入字符数/最大字符数 -->
|
|
|
<div style="text-align: right; margin-top: 5px; font-size: 12px; color: #999;">
|
|
|
{{ newKnowledgeBaseTitle.length }}/64
|
|
|
</div>
|
|
|
<template #footer>
|
|
|
- <el-button @click="createModalVisible = false" style="border-radius: 20px;">取消</el-button>
|
|
|
+ <el-button @click="createModalVisible = false" style="border-radius: 20px;" :disabled="loading.create">
|
|
|
+ 取消
|
|
|
+ </el-button>
|
|
|
<el-button
|
|
|
type="primary"
|
|
|
@click="createKnowledgeBase"
|
|
|
- style="border-radius: 20px; background-color: #409EFF; border-color: #409EFF;">
|
|
|
+ style="border-radius: 20px; background-color: #409EFF; border-color: #409EFF;"
|
|
|
+ :loading="loading.create"
|
|
|
+ >
|
|
|
创建
|
|
|
</el-button>
|
|
|
</template>
|
|
@@ -51,76 +79,120 @@
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts">
|
|
|
-import {defineComponent, ref} from 'vue';
|
|
|
+import {defineComponent, ref, reactive} from 'vue';
|
|
|
import axios from 'axios';
|
|
|
-import {ElMessage} from 'element-plus';
|
|
|
-import {useRouter} from 'vue-router'; // 导入 useRouter
|
|
|
+import {ElMessage, ElMessageBox} from 'element-plus';
|
|
|
+import { CloseBold } from '@element-plus/icons-vue';
|
|
|
+import {useRouter} from 'vue-router';
|
|
|
|
|
|
interface KnowledgeBaseItem {
|
|
|
dataset_id: number;
|
|
|
name: string;
|
|
|
count: number;
|
|
|
- create_at: string;
|
|
|
+ created_at: string;
|
|
|
}
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: 'KnowledgeBase',
|
|
|
+ components: {CloseBold},
|
|
|
+ // components: { CloseBold },
|
|
|
setup() {
|
|
|
- const router = useRouter(); // 获取 router 实例
|
|
|
+ const router = useRouter();
|
|
|
const knowledgeBaseList = ref<KnowledgeBaseItem[]>([]);
|
|
|
const newKnowledgeBaseTitle = ref('');
|
|
|
const createModalVisible = ref(false);
|
|
|
|
|
|
- // 获取知识库列表
|
|
|
+ // loading 状态
|
|
|
+ const loading = reactive({
|
|
|
+ create: false,
|
|
|
+ delete: {} as Record<number, boolean>
|
|
|
+ });
|
|
|
+
|
|
|
const fetchKnowledgeBaseList = async () => {
|
|
|
try {
|
|
|
- const response = await axios.get('http://127.0.0.1:8001/api/dataset/list');
|
|
|
- knowledgeBaseList.value = response.data.data;
|
|
|
+ const res = await axios.get('http://61.48.133.26:8001/api/dataset/list');
|
|
|
+ knowledgeBaseList.value = res.data.data;
|
|
|
} catch (error) {
|
|
|
ElMessage.error('获取知识库列表失败');
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- // 显示创建知识库的弹窗
|
|
|
const showCreateModal = () => {
|
|
|
createModalVisible.value = true;
|
|
|
};
|
|
|
|
|
|
- // 创建新的知识库
|
|
|
const createKnowledgeBase = async () => {
|
|
|
if (!newKnowledgeBaseTitle.value.trim()) {
|
|
|
ElMessage.warning('请输入知识库名称');
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
+ loading.create = true;
|
|
|
try {
|
|
|
- await axios.post('http://127.0.0.1:8001/api/dataset/add', {
|
|
|
+ await axios.post('http://61.48.133.26:8001/api/dataset/add', {
|
|
|
name: newKnowledgeBaseTitle.value
|
|
|
});
|
|
|
ElMessage.success('知识库创建成功');
|
|
|
createModalVisible.value = false;
|
|
|
- newKnowledgeBaseTitle.value = ''; // 清空输入框
|
|
|
- fetchKnowledgeBaseList(); // 重新获取知识库列表
|
|
|
- } catch (error) {
|
|
|
- ElMessage.error('创建知识库失败');
|
|
|
+ newKnowledgeBaseTitle.value = '';
|
|
|
+ await fetchKnowledgeBaseList();
|
|
|
+ } catch (error: any) {
|
|
|
+ ElMessage.error(error?.response?.data?.detail || '创建知识库失败');
|
|
|
+ } finally {
|
|
|
+ loading.create = false;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const confirmDelete = async (datasetId: number, datasetName: string) => {
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm(
|
|
|
+ `确定要删除知识库 "${datasetName}" 吗?`,
|
|
|
+ '删除确认',
|
|
|
+ {
|
|
|
+ confirmButtonText: '删除',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning',
|
|
|
+ }
|
|
|
+ );
|
|
|
+ await deleteKnowledgeBase(datasetId);
|
|
|
+ } catch {
|
|
|
+ // 用户取消,不做任何操作
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const deleteKnowledgeBase = async (datasetId: number) => {
|
|
|
+ loading.delete[datasetId] = true;
|
|
|
+ try {
|
|
|
+ await axios.post('http://192.168.100.31:8001/api/delete', {
|
|
|
+ level: 'dataset',
|
|
|
+ params: {dataset_id: datasetId}
|
|
|
+ });
|
|
|
+ ElMessage.success('知识库删除成功');
|
|
|
+ await fetchKnowledgeBaseList();
|
|
|
+ } catch (error: any) {
|
|
|
+ ElMessage.error(error?.response?.data?.detail || '删除知识库失败');
|
|
|
+ } finally {
|
|
|
+ loading.delete[datasetId] = false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- // 跳转到知识库详情页面
|
|
|
const goToDetailPage = (datasetId: number, datasetName: string) => {
|
|
|
- console.log(`跳转到知识库 ${datasetId} 的详情页`);
|
|
|
- router.push({path: `/knowledge/content`, query: {datasetId: datasetId.toString(), datasetName: datasetName}});
|
|
|
+ router.push({
|
|
|
+ path: '/knowledge/content',
|
|
|
+ query: {datasetId: datasetId.toString(), datasetName}
|
|
|
+ });
|
|
|
};
|
|
|
|
|
|
- // 初始化加载知识库列表
|
|
|
+ // 初始化加载
|
|
|
fetchKnowledgeBaseList();
|
|
|
|
|
|
return {
|
|
|
knowledgeBaseList,
|
|
|
newKnowledgeBaseTitle,
|
|
|
createModalVisible,
|
|
|
+ loading,
|
|
|
showCreateModal,
|
|
|
createKnowledgeBase,
|
|
|
+ confirmDelete,
|
|
|
goToDetailPage,
|
|
|
};
|
|
|
}
|
|
@@ -131,50 +203,46 @@ export default defineComponent({
|
|
|
.el-card {
|
|
|
cursor: pointer;
|
|
|
transition: transform 0.3s ease;
|
|
|
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
|
|
|
- border-radius: 12px; /* 添加圆角 */
|
|
|
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
|
|
+ border-radius: 12px;
|
|
|
background-color: #fff;
|
|
|
- width: 250px; /* 设置卡片的固定宽度 */
|
|
|
+ width: 250px;
|
|
|
+ margin-top: 20px;
|
|
|
}
|
|
|
|
|
|
.el-card:hover {
|
|
|
- transform: translateY(-10px); /* 鼠标悬停时,卡片上升 */
|
|
|
+ transform: translateY(-10px);
|
|
|
}
|
|
|
|
|
|
.el-dialog {
|
|
|
z-index: 9999;
|
|
|
- border-radius: 12px; /* 弹窗圆角 */
|
|
|
+ border-radius: 12px;
|
|
|
}
|
|
|
|
|
|
.el-button {
|
|
|
- border-radius: 20px; /* 按钮圆角 */
|
|
|
+ border-radius: 20px;
|
|
|
}
|
|
|
|
|
|
.el-input {
|
|
|
- border-radius: 10px; /* 输入框圆角 */
|
|
|
+ border-radius: 10px;
|
|
|
}
|
|
|
|
|
|
.knowledge-base-grid {
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
- gap: 20px; /* 设置每个卡片之间的间距 */
|
|
|
- justify-content: flex-start; /* 默认从左侧对齐 */
|
|
|
-}
|
|
|
-
|
|
|
-.el-card {
|
|
|
- margin-top: 20px; /* 设置上边距为20px */
|
|
|
+ gap: 20px;
|
|
|
+ justify-content: flex-start;
|
|
|
}
|
|
|
|
|
|
-/* 适配小屏幕 */
|
|
|
@media (max-width: 768px) {
|
|
|
.el-card {
|
|
|
- width: 230px; /* 在小屏幕下调整卡片宽度 */
|
|
|
+ width: 230px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@media (max-width: 480px) {
|
|
|
.el-card {
|
|
|
- width: 100%; /* 屏幕宽度小于480px时,每行展示1个卡片 */
|
|
|
+ width: 100%;
|
|
|
}
|
|
|
}
|
|
|
</style>
|