新增知识库管理功能,包括知识库和文档的增删改查,优化文档上传和状态管理,更新相关API接口和前端页面,添加知识库和文档的视图组件。

This commit is contained in:
Chuck1sn
2025-06-27 16:51:48 +08:00
parent 2fb08968ee
commit 8ed0b795f3
25 changed files with 1578 additions and 46 deletions

View File

@@ -21,25 +21,25 @@
<script setup lang="ts">
defineProps({
href: {
type: String,
required: true
},
imageSrc: {
type: String,
required: true
},
imageAlt: {
type: String,
default: 'promotion'
},
label: {
type: String,
default: '官方教程'
},
text: {
type: String,
required: true
}
href: {
type: String,
required: true,
},
imageSrc: {
type: String,
required: true,
},
imageAlt: {
type: String,
default: "promotion",
},
label: {
type: String,
default: "官方教程",
},
text: {
type: String,
required: true,
},
});
</script>

View File

@@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-book-icon">
<path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20" />
<path d="m9 10 2 2 4-4" />
</svg>
</template>

View File

@@ -11,3 +11,4 @@ export { default as RoleIcon } from "./RoleIcon.vue";
export { default as SettingsIcon } from "./SettingsIcon.vue";
export { default as UsersIcon } from "./UsersIcon.vue";
export { default as PermissionIcon } from "./PermissionIcon.vue";
export { default as KnowledgeIcon } from "./KnowledgeIcon.vue";

View File

@@ -35,6 +35,7 @@ import { RouterLink, useRoute } from "vue-router";
import {
DepartmentIcon,
KnowledgeIcon,
LlmConfigIcon,
PermissionIcon,
PositionIcon,
@@ -113,6 +114,11 @@ const menuItems = [
path: Routes.LLMCONFIGVIEW.fullPath(),
icon: LlmConfigIcon,
},
{
title: "知识库管理",
path: Routes.KNOWLEDGEVIEW.fullPath(),
icon: KnowledgeIcon,
},
];
const route = useRoute();

View File

@@ -0,0 +1,93 @@
<template>
<BaseDialog :id="id" title="知识库管理" size="md" :closeModal="closeModal">
<!-- Modal body -->
<div class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-1">
<div class="col-span-full">
<label for="name" class="block mb-2 text-sm font-medium text-gray-900">知识库名称</label>
<input type="text" id="name" v-model="formData.name"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
required />
</div>
<div class="col-span-full">
<label for="description" class="block mb-2 text-sm font-medium text-gray-900">知识库描述</label>
<textarea id="description" v-model="formData.description" rows="3"
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"></textarea>
</div>
</div>
<button type="submit" @click="handleSubmit"
class="w-auto text-sm px-4 py-2 text-white flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-center self-start mt-5">
保存
</button>
</div>
</BaseDialog>
</template>
<script setup lang="ts">
import useAlertStore from "@/composables/store/useAlertStore";
import type { Library } from "@/types/KnowledgeTypes";
import type { LibraryUpsertModel } from "@/types/KnowledgeTypes";
import { ref, watch } from "vue";
import { z } from "zod";
import BaseDialog from "./BaseDialog.vue";
const alertStore = useAlertStore();
const { library, closeModal, onSubmit, id } = defineProps<{
library?: Library;
closeModal: () => void;
onSubmit: (data: LibraryUpsertModel) => Promise<void>;
id: string;
}>();
const formData = ref<LibraryUpsertModel>({
name: "",
description: "",
});
const updateFormData = (newLibrary: typeof library) => {
if (!newLibrary) {
formData.value = {
name: "",
description: "",
};
return;
}
formData.value = {
id: newLibrary.id,
name: newLibrary.name ?? "",
description: newLibrary.description ?? "",
};
};
watch(() => library, updateFormData, { immediate: true });
const handleSubmit = async () => {
const schema = z.object({
name: z.string().min(1, "知识库名称不能为空"),
description: z.string().optional(),
});
try {
const validatedData = schema.parse(formData.value);
await onSubmit({
...formData.value,
name: validatedData.name,
description: validatedData.description,
});
} catch (error) {
if (error instanceof z.ZodError) {
alertStore.showAlert({
type: "error",
message: error.errors[0].message,
});
} else {
console.error("表单提交错误:", error);
alertStore.showAlert({
type: "error",
message: "表单提交失败,请重试",
});
}
}
};
</script>

View File

@@ -116,10 +116,9 @@ const handleFileChange = (event: Event) => {
throw err;
},
});
} catch (error) {
} finally {
(event.target as HTMLInputElement).value = "";
uploadLoading.value = false;
throw error;
}
};