Files
schoolNews/schoolNewsWeb/src/views/admin/manage/ai/KnowledgeManagementView.vue
2025-11-07 16:09:00 +08:00

360 lines
8.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<AdminLayout title="知识管理" subtitle="知识管理">
<!-- 3个div在同一个位置, 后2个通过zindex遮盖前一个 -->
<div class="knowledge-management-container">
<!-- 层级1: 知识库列表 -->
<div class="knowledge-list-container" v-loading="loading">
<div class="list-header">
<h3 class="list-title">知识库列表</h3>
<el-button type="primary" @click="handleCreate">
+ 新建知识库
</el-button>
</div>
<div class="knowledge-list-content">
<div class="knowledge-grid">
<KnowledgeCard class="knowledge-card"
v-for="knowledge in knowledgeCards"
:key="knowledge.id"
:knowledge="knowledge"
@click="handleKnowledgeClick"
@edit="handleEdit"
@delete="handleDelete"
/>
</div>
</div>
<el-empty v-if="!loading && knowledgeCards.length === 0" description="暂无知识库" />
<el-pagination
v-if="total >= 0"
:current-page="pageParam.pageNumber"
:page-size="pageParam.pageSize"
:total="total"
:page-sizes="[9, 18, 36]"
layout="total, sizes, prev, pager, next, jumper"
@current-change="handlePageChange"
@size-change="handleSizeChange"
/>
</div>
<!-- 层级2: 知识库详情覆盖在列表上方 -->
<transition name="slide-left">
<KnowledgeInfo
v-if="selectedKnowledge"
:knowledge="selectedKnowledge"
@close="handleCloseInfo"
@refresh="loadKnowledges"
@edit="handleEditFromInfo"
/>
</transition>
</div>
<!-- 新增/编辑对话框 -->
<el-dialog
v-model="basicDialogVisible"
:title="basicType === 'add' ? '新建知识库' : '编辑知识库'"
width="800px"
:close-on-click-modal="false"
destroy-on-close
>
<KnowledgeBasic
:type="basicType"
:knowledge="editKnowledge"
@success="handleBasicSuccess"
@cancel="basicDialogVisible = false"
/>
</el-dialog>
</AdminLayout>
</template>
<script setup lang="ts">
import { AdminLayout } from '@/views/admin';
import { KnowledgeCard, KnowledgeInfo, KnowledgeBasic } from './components';
import { ref, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import type { AiKnowledge } from '@/types/ai';
import type { PageParam } from '@/types';
import { knowledgeApi } from '@/apis/ai';
defineOptions({
name: 'KnowledgeManagementView'
});
const knowledgeCards = ref<AiKnowledge[]>([]);
const selectedKnowledge = ref<AiKnowledge | null>(null);
const editKnowledge = ref<AiKnowledge | null>(null);
const basicDialogVisible = ref(false);
const basicType = ref<'view' | 'add' | 'edit'>('view');
const loading = ref(false);
const total = ref(0);
const pageParam = ref<PageParam>({
pageNumber: 1,
pageSize: 12
});
// 加载知识库列表
onMounted(() => {
loadKnowledges();
});
async function loadKnowledges() {
try {
loading.value = true;
const result = await knowledgeApi.pageKnowledges({}, pageParam.value);
if (result.success) {
knowledgeCards.value = result.dataList || [];
total.value = result.pageParam?.totalElements || 0;
}
} catch (error: any) {
console.error('加载知识库失败:', error);
ElMessage.error('加载知识库失败');
} finally {
loading.value = false;
}
}
// 选中知识库
function handleKnowledgeClick(knowledge: AiKnowledge) {
selectedKnowledge.value = knowledge;
}
// 关闭知识库详情
function handleCloseInfo() {
selectedKnowledge.value = null;
}
// 新建知识库
function handleCreate() {
basicType.value = 'add';
editKnowledge.value = null;
basicDialogVisible.value = true;
}
// 编辑知识库(从卡片)
function handleEdit(knowledge: AiKnowledge) {
basicType.value = 'edit';
editKnowledge.value = knowledge;
basicDialogVisible.value = true;
}
// 编辑知识库(从详情页)
function handleEditFromInfo(knowledge: AiKnowledge) {
basicType.value = 'edit';
editKnowledge.value = knowledge;
basicDialogVisible.value = true;
selectedKnowledge.value = null; // 关闭详情页
}
// 基本信息操作成功
function handleBasicSuccess(knowledge: AiKnowledge) {
basicDialogVisible.value = false;
loadKnowledges();
if (basicType.value === 'add') {
ElMessage.success('知识库创建成功');
} else {
ElMessage.success('知识库更新成功');
// 如果当前选中的知识库就是被编辑的,更新它
if (selectedKnowledge.value?.id === knowledge.id) {
selectedKnowledge.value = knowledge;
}
}
}
// 删除知识库
async function handleDelete(knowledge: AiKnowledge) {
try {
await ElMessageBox.confirm(
`确定要删除知识库"${knowledge.title}"吗?此操作不可恢复。`,
'警告',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
);
if (knowledge.id) {
const result = await knowledgeApi.deleteKnowledge(knowledge.id);
if (result.success) {
ElMessage.success('删除成功');
loadKnowledges();
} else {
ElMessage.error(result.message || '删除失败');
}
}
} catch (error: any) {
if (error !== 'cancel') {
console.error('删除知识库失败:', error);
ElMessage.error('删除失败');
}
}
}
// 分页改变
function handlePageChange(page: number) {
pageParam.value.pageNumber = page;
loadKnowledges();
}
function handleSizeChange(size: number) {
pageParam.value.pageSize = size;
pageParam.value.pageNumber = 1;
loadKnowledges();
}
</script>
<style scoped lang="scss">
.knowledge-management-container {
position: relative;
// padding: 24px;
background: #F5F5F7;
height: calc(100vh - 40px - 44px - 24px - 110px);
}
.knowledge-list-container {
background: #FFFFFF;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 14px;
padding: 24px;
height: 100%;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: flex-end;
}
.list-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
width: 100%;
.list-title {
font-size: 18px;
font-weight: 500;
color: #101828;
margin: 0;
letter-spacing: -0.02em;
}
:deep(.el-button) {
border-radius: 8px;
font-weight: 500;
letter-spacing: -0.01em;
&.el-button--primary {
background: #E7000B;
border-color: #E7000B;
&:hover {
background: #C90009;
}
}
}
}
.knowledge-list-content{
width: 100%;
overflow-y: auto;
height: 100%;
// 自定义滚动条样式
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: transparent;
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #D1D5DB;
border-radius: 3px;
&:hover {
background: #9CA3AF;
}
}
}
.knowledge-grid {
display: flex;
width: 100%;
gap: 20px;
margin-top: 12px;
.knowledge-card {
width: 33%;
}
}
:deep(.el-pagination) {
display: flex;
justify-content: flex-end;
padding-top: 24px;
border-top: 1px solid #F3F3F5;
margin-top: auto; // 推到容器底部
width: 100%;
.el-pager li {
&.is-active {
background: #E7000B;
color: #FFFFFF;
}
}
.btn-prev,
.btn-next {
&:hover:not(.disabled) {
color: #E7000B;
}
}
}
:deep(.el-empty) {
padding: 60px 0;
}
:deep(.el-dialog) {
border-radius: 12px;
.el-dialog__header {
border-bottom: 1px solid #F3F3F5;
padding: 20px 24px;
}
.el-dialog__body {
padding: 0;
}
}
// 过渡动画
.slide-left-enter-active,
.slide-left-leave-active {
transition: transform 0.3s ease-in-out, opacity 0.3s;
}
.slide-left-enter-from {
transform: translateX(100%);
opacity: 0;
}
.slide-left-leave-to {
transform: translateX(100%);
opacity: 0;
}
.slide-left-enter-to,
.slide-left-leave-from {
transform: translateX(0);
opacity: 1;
}
</style>