parent
3c6cf034eb
commit
cddd25716d
Binary file not shown.
@ -0,0 +1 @@
|
||||
http://localhost:8000/static/index.html
|
@ -0,0 +1,30 @@
|
||||
body {
|
||||
font-size: .875rem;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
padding: 48px 0 0;
|
||||
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
.sidebar .nav-link {
|
||||
font-weight: 500;
|
||||
color: #adb5bd;
|
||||
}
|
||||
|
||||
.sidebar .nav-link.active {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.sidebar .nav-link:hover {
|
||||
color: rgba(255, 255, 255, .75);
|
||||
}
|
||||
|
||||
main {
|
||||
padding-top: 1.5rem;
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>知识库管理系统</title>
|
||||
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.bootcdn.net/ajax/libs/bootstrap-icons/1.10.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="css/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- 侧边栏 -->
|
||||
<div class="col-md-3 col-lg-2 d-md-block bg-dark sidebar collapse">
|
||||
<div class="position-sticky pt-3">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#kb-list" data-bs-toggle="tab">
|
||||
<i class="bi bi-book"></i> 知识库列表
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#file-list" data-bs-toggle="tab">
|
||||
<i class="bi bi-file-earmark"></i> 文件管理
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主内容区 -->
|
||||
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
||||
<div class="tab-content">
|
||||
<!-- 知识库管理 -->
|
||||
<div class="tab-pane fade show active" id="kb-list">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">知识库管理</h1>
|
||||
<button class="btn btn-primary" id="add-kb-btn">添加知识库</button>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover" id="kb-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>名称</th>
|
||||
<th>描述</th>
|
||||
<th>创建时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="kb-table-body"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 文件管理 -->
|
||||
<div class="tab-pane fade" id="file-list">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">文件管理</h1>
|
||||
<button class="btn btn-primary" id="upload-file-btn">上传文件</button>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<select class="form-select" id="kb-selector">
|
||||
<option value="">-- 选择知识库 --</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover" id="file-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>文件名</th>
|
||||
<th>大小</th>
|
||||
<th>类型</th>
|
||||
<th>状态</th>
|
||||
<th>上传时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="file-table-body"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模态框 -->
|
||||
<div class="modal fade" id="kb-modal" tabindex="-1" aria-hidden="true">
|
||||
<!-- 知识库添加/编辑模态框内容 -->
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="file-modal" tabindex="-1" aria-hidden="true">
|
||||
<!-- 文件上传模态框内容 -->
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.1/axios.min.js"></script>
|
||||
<script src="js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,171 @@
|
||||
// API基础URL
|
||||
const API_BASE_URL = 'http://localhost:8000';
|
||||
|
||||
// 初始化页面
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadKbList();
|
||||
setupEventListeners();
|
||||
});
|
||||
|
||||
// 设置事件监听器
|
||||
function setupEventListeners() {
|
||||
// 添加知识库按钮
|
||||
document.getElementById('add-kb-btn').addEventListener('click', showKbModal);
|
||||
|
||||
// 上传文件按钮
|
||||
document.getElementById('upload-file-btn').addEventListener('click', showFileModal);
|
||||
|
||||
// 知识库选择器变化
|
||||
document.getElementById('kb-selector').addEventListener('change', function() {
|
||||
loadFileList(this.value);
|
||||
});
|
||||
}
|
||||
|
||||
// 加载知识库列表
|
||||
async function loadKbList() {
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/kb`);
|
||||
const kbList = response.data;
|
||||
|
||||
const tbody = document.getElementById('kb-table-body');
|
||||
tbody.innerHTML = '';
|
||||
|
||||
const kbSelector = document.getElementById('kb-selector');
|
||||
kbSelector.innerHTML = '<option value="">-- 选择知识库 --</option>';
|
||||
|
||||
kbList.forEach(kb => {
|
||||
// 填充知识库表格
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${kb.id}</td>
|
||||
<td>${kb.name}</td>
|
||||
<td>${kb.description || '-'}</td>
|
||||
<td>${new Date(kb.create_time).toLocaleString()}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-primary edit-kb" data-id="${kb.id}">编辑</button>
|
||||
<button class="btn btn-sm btn-outline-danger delete-kb" data-id="${kb.id}">删除</button>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
|
||||
// 填充知识库选择器
|
||||
const option = document.createElement('option');
|
||||
option.value = kb.id;
|
||||
option.textContent = kb.name;
|
||||
kbSelector.appendChild(option);
|
||||
});
|
||||
|
||||
// 添加编辑和删除按钮的事件
|
||||
document.querySelectorAll('.edit-kb').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
showKbModal(this.getAttribute('data-id'));
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.delete-kb').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
deleteKb(this.getAttribute('data-id'));
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('加载知识库列表失败:', error);
|
||||
alert('加载知识库列表失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 加载文件列表
|
||||
async function loadFileList(kbId) {
|
||||
if (!kbId) return;
|
||||
|
||||
try {
|
||||
const response = await axios.get(`${API_BASE_URL}/kb_files?kb_id=${kbId}`);
|
||||
const fileList = response.data;
|
||||
|
||||
const tbody = document.getElementById('file-table-body');
|
||||
tbody.innerHTML = '';
|
||||
|
||||
fileList.forEach(file => {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${file.id}</td>
|
||||
<td>${file.file_name}</td>
|
||||
<td>${formatFileSize(file.file_size)}</td>
|
||||
<td>${file.file_type}</td>
|
||||
<td>${getFileStatusText(file.state)}</td>
|
||||
<td>${new Date(file.create_time).toLocaleString()}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-danger delete-file" data-id="${file.id}">删除</button>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
|
||||
// 添加删除按钮的事件
|
||||
document.querySelectorAll('.delete-file').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
deleteFile(this.getAttribute('data-id'));
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('加载文件列表失败:', error);
|
||||
alert('加载文件列表失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:格式化文件大小
|
||||
function formatFileSize(bytes) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
// 辅助函数:获取文件状态文本
|
||||
function getFileStatusText(state) {
|
||||
switch (state) {
|
||||
case 0: return '待处理';
|
||||
case 1: return '已处理';
|
||||
case 2: return '处理失败';
|
||||
default: return '未知状态';
|
||||
}
|
||||
}
|
||||
|
||||
// 显示知识库模态框
|
||||
function showKbModal(kbId = null) {
|
||||
// 实现知识库添加/编辑模态框逻辑
|
||||
}
|
||||
|
||||
// 显示文件上传模态框
|
||||
function showFileModal() {
|
||||
// 实现文件上传模态框逻辑
|
||||
}
|
||||
|
||||
// 删除知识库
|
||||
async function deleteKb(kbId) {
|
||||
if (!confirm('确定要删除这个知识库吗?')) return;
|
||||
|
||||
try {
|
||||
await axios.delete(`${API_BASE_URL}/kb/${kbId}`);
|
||||
alert('删除成功');
|
||||
loadKbList();
|
||||
} catch (error) {
|
||||
console.error('删除知识库失败:', error);
|
||||
alert('删除知识库失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
async function deleteFile(fileId) {
|
||||
if (!confirm('确定要删除这个文件吗?')) return;
|
||||
|
||||
try {
|
||||
await axios.delete(`${API_BASE_URL}/kb_files/${fileId}`);
|
||||
alert('删除成功');
|
||||
const kbId = document.getElementById('kb-selector').value;
|
||||
if (kbId) loadFileList(kbId);
|
||||
} catch (error) {
|
||||
console.error('删除文件失败:', error);
|
||||
alert('删除文件失败');
|
||||
}
|
||||
}
|
Loading…
Reference in new issue