-
知识库详情
-
知识库详情(Phase 4 实现)
+
+
+
{{ kb.name }}
+ 复制 AI 链接
+
+
+
+
+ {{ kb.description || '无' }}
+
+ {{ kb.enabled ? '启用' : '禁用' }}
+
+
+
+
+ 重新生成
+
+
+ {{ docs.length }}
+
+
+
+
+
+
+ 文档列表
+
+ 上传文档
+
+
+
+
+
+
+
+
+ {{ row.status }}
+
+
+
+ {{ formatSize(row.file_size) }}
+
+
+
+
+
+ 重新解析
+ 删除
+
+
+
+
-
\ No newline at end of file
+
diff --git a/frontend/src/views/KbDetail.vue.js b/frontend/src/views/KbDetail.vue.js
index 09e44bb..9bcbd81 100644
--- a/frontend/src/views/KbDetail.vue.js
+++ b/frontend/src/views/KbDetail.vue.js
@@ -1,14 +1,494 @@
+import { ref, onMounted } from 'vue';
+import { useRoute } from 'vue-router';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import apiClient from '@/api/client';
+const route = useRoute();
+const kbId = route.params.id;
+const kb = ref(null);
+const docs = ref([]);
+const loading = ref(false);
+const uploading = ref(false);
+const aiUrl = ref('');
+onMounted(async () => {
+ await loadKb();
+ await loadDocs();
+ await loadLink();
+});
+async function loadKb() {
+ try {
+ const { data } = await apiClient.get(`/knowledge-bases/${kbId}`);
+ kb.value = data;
+ }
+ catch { /* ignore */ }
+}
+async function loadDocs() {
+ loading.value = true;
+ try {
+ const { data } = await apiClient.get(`/documents?kb_id=${kbId}`);
+ docs.value = data.items;
+ }
+ catch { /* ignore */ }
+ loading.value = false;
+}
+async function loadLink() {
+ try {
+ const { data } = await apiClient.get(`/knowledge-bases/${kbId}/link`);
+ aiUrl.value = `${window.location.origin}/k/${data.token}`;
+ }
+ catch { /* ignore */ }
+}
+async function handleUpload(options) {
+ uploading.value = true;
+ try {
+ const formData = new FormData();
+ formData.append('kb_id', kbId);
+ formData.append('file', options.file);
+ await apiClient.post('/documents/upload', formData, {
+ headers: { 'Content-Type': 'multipart/form-data' },
+ });
+ ElMessage.success('文档上传成功!');
+ loadDocs();
+ }
+ catch { /* ignore */ }
+ uploading.value = false;
+}
+async function handleDeleteDoc(doc) {
+ try {
+ await ElMessageBox.confirm(`确定删除文档「${doc.original_filename}」?`, '确认删除', { type: 'warning' });
+ await apiClient.delete(`/documents/${doc.id}`);
+ ElMessage.success('已删除。');
+ loadDocs();
+ }
+ catch { /* ignore */ }
+}
+async function handleReprocess(doc) {
+ try {
+ await apiClient.post(`/documents/${doc.id}/reprocess`);
+ ElMessage.success('重新解析已提交。');
+ loadDocs();
+ }
+ catch { /* ignore */ }
+}
+async function handleCopyLink() {
+ try {
+ await navigator.clipboard.writeText(aiUrl.value);
+ ElMessage.success('AI 链接已复制!');
+ }
+ catch { /* ignore */ }
+}
+async function handleRegenerate() {
+ try {
+ await ElMessageBox.confirm('重新生成链接后,旧链接将立即失效。确定继续?', '确认', { type: 'warning' });
+ const { data } = await apiClient.post(`/knowledge-bases/${kbId}/regenerate-token`);
+ aiUrl.value = `${window.location.origin}/k/${data.token}`;
+ ElMessage.success('链接已重新生成。');
+ }
+ catch { /* ignore */ }
+}
+function formatSize(bytes) {
+ if (bytes < 1024)
+ return bytes + ' B';
+ if (bytes < 1024 * 1024)
+ return (bytes / 1024).toFixed(1) + ' KB';
+ return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
+}
+function statusType(status) {
+ if (status === 'READY')
+ return 'success';
+ if (status === 'FAILED')
+ return 'danger';
+ return 'warning';
+}
debugger; /* PartiallyEnd: #3632/scriptSetup.vue */
const __VLS_ctx = {};
let __VLS_components;
let __VLS_directives;
-__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({});
-__VLS_asFunctionalElement(__VLS_intrinsicElements.h1, __VLS_intrinsicElements.h1)({});
-__VLS_asFunctionalElement(__VLS_intrinsicElements.p, __VLS_intrinsicElements.p)({});
+if (__VLS_ctx.kb) {
+ __VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({});
+ __VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
+ ...{ style: {} },
+ });
+ __VLS_asFunctionalElement(__VLS_intrinsicElements.h1, __VLS_intrinsicElements.h1)({
+ ...{ style: {} },
+ });
+ (__VLS_ctx.kb.name);
+ const __VLS_0 = {}.ElButton;
+ /** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+ // @ts-ignore
+ const __VLS_1 = __VLS_asFunctionalComponent(__VLS_0, new __VLS_0({
+ ...{ 'onClick': {} },
+ type: "primary",
+ }));
+ const __VLS_2 = __VLS_1({
+ ...{ 'onClick': {} },
+ type: "primary",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_1));
+ let __VLS_4;
+ let __VLS_5;
+ let __VLS_6;
+ const __VLS_7 = {
+ onClick: (__VLS_ctx.handleCopyLink)
+ };
+ __VLS_3.slots.default;
+ var __VLS_3;
+ const __VLS_8 = {}.ElCard;
+ /** @type {[typeof __VLS_components.ElCard, typeof __VLS_components.elCard, typeof __VLS_components.ElCard, typeof __VLS_components.elCard, ]} */ ;
+ // @ts-ignore
+ const __VLS_9 = __VLS_asFunctionalComponent(__VLS_8, new __VLS_8({
+ ...{ style: {} },
+ }));
+ const __VLS_10 = __VLS_9({
+ ...{ style: {} },
+ }, ...__VLS_functionalComponentArgsRest(__VLS_9));
+ __VLS_11.slots.default;
+ const __VLS_12 = {}.ElDescriptions;
+ /** @type {[typeof __VLS_components.ElDescriptions, typeof __VLS_components.elDescriptions, typeof __VLS_components.ElDescriptions, typeof __VLS_components.elDescriptions, ]} */ ;
+ // @ts-ignore
+ const __VLS_13 = __VLS_asFunctionalComponent(__VLS_12, new __VLS_12({
+ column: (2),
+ border: true,
+ }));
+ const __VLS_14 = __VLS_13({
+ column: (2),
+ border: true,
+ }, ...__VLS_functionalComponentArgsRest(__VLS_13));
+ __VLS_15.slots.default;
+ const __VLS_16 = {}.ElDescriptionsItem;
+ /** @type {[typeof __VLS_components.ElDescriptionsItem, typeof __VLS_components.elDescriptionsItem, typeof __VLS_components.ElDescriptionsItem, typeof __VLS_components.elDescriptionsItem, ]} */ ;
+ // @ts-ignore
+ const __VLS_17 = __VLS_asFunctionalComponent(__VLS_16, new __VLS_16({
+ label: "描述",
+ }));
+ const __VLS_18 = __VLS_17({
+ label: "描述",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_17));
+ __VLS_19.slots.default;
+ (__VLS_ctx.kb.description || '无');
+ var __VLS_19;
+ const __VLS_20 = {}.ElDescriptionsItem;
+ /** @type {[typeof __VLS_components.ElDescriptionsItem, typeof __VLS_components.elDescriptionsItem, typeof __VLS_components.ElDescriptionsItem, typeof __VLS_components.elDescriptionsItem, ]} */ ;
+ // @ts-ignore
+ const __VLS_21 = __VLS_asFunctionalComponent(__VLS_20, new __VLS_20({
+ label: "状态",
+ }));
+ const __VLS_22 = __VLS_21({
+ label: "状态",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_21));
+ __VLS_23.slots.default;
+ const __VLS_24 = {}.ElTag;
+ /** @type {[typeof __VLS_components.ElTag, typeof __VLS_components.elTag, typeof __VLS_components.ElTag, typeof __VLS_components.elTag, ]} */ ;
+ // @ts-ignore
+ const __VLS_25 = __VLS_asFunctionalComponent(__VLS_24, new __VLS_24({
+ type: (__VLS_ctx.kb.enabled ? 'success' : 'danger'),
+ }));
+ const __VLS_26 = __VLS_25({
+ type: (__VLS_ctx.kb.enabled ? 'success' : 'danger'),
+ }, ...__VLS_functionalComponentArgsRest(__VLS_25));
+ __VLS_27.slots.default;
+ (__VLS_ctx.kb.enabled ? '启用' : '禁用');
+ var __VLS_27;
+ var __VLS_23;
+ const __VLS_28 = {}.ElDescriptionsItem;
+ /** @type {[typeof __VLS_components.ElDescriptionsItem, typeof __VLS_components.elDescriptionsItem, typeof __VLS_components.ElDescriptionsItem, typeof __VLS_components.elDescriptionsItem, ]} */ ;
+ // @ts-ignore
+ const __VLS_29 = __VLS_asFunctionalComponent(__VLS_28, new __VLS_28({
+ label: "AI 链接",
+ }));
+ const __VLS_30 = __VLS_29({
+ label: "AI 链接",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_29));
+ __VLS_31.slots.default;
+ __VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
+ ...{ style: {} },
+ });
+ const __VLS_32 = {}.ElInput;
+ /** @type {[typeof __VLS_components.ElInput, typeof __VLS_components.elInput, ]} */ ;
+ // @ts-ignore
+ const __VLS_33 = __VLS_asFunctionalComponent(__VLS_32, new __VLS_32({
+ modelValue: (__VLS_ctx.aiUrl),
+ readonly: true,
+ size: "small",
+ ...{ style: {} },
+ }));
+ const __VLS_34 = __VLS_33({
+ modelValue: (__VLS_ctx.aiUrl),
+ readonly: true,
+ size: "small",
+ ...{ style: {} },
+ }, ...__VLS_functionalComponentArgsRest(__VLS_33));
+ const __VLS_36 = {}.ElButton;
+ /** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+ // @ts-ignore
+ const __VLS_37 = __VLS_asFunctionalComponent(__VLS_36, new __VLS_36({
+ ...{ 'onClick': {} },
+ size: "small",
+ }));
+ const __VLS_38 = __VLS_37({
+ ...{ 'onClick': {} },
+ size: "small",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_37));
+ let __VLS_40;
+ let __VLS_41;
+ let __VLS_42;
+ const __VLS_43 = {
+ onClick: (__VLS_ctx.handleRegenerate)
+ };
+ __VLS_39.slots.default;
+ var __VLS_39;
+ var __VLS_31;
+ const __VLS_44 = {}.ElDescriptionsItem;
+ /** @type {[typeof __VLS_components.ElDescriptionsItem, typeof __VLS_components.elDescriptionsItem, typeof __VLS_components.ElDescriptionsItem, typeof __VLS_components.elDescriptionsItem, ]} */ ;
+ // @ts-ignore
+ const __VLS_45 = __VLS_asFunctionalComponent(__VLS_44, new __VLS_44({
+ label: "文档数",
+ }));
+ const __VLS_46 = __VLS_45({
+ label: "文档数",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_45));
+ __VLS_47.slots.default;
+ (__VLS_ctx.docs.length);
+ var __VLS_47;
+ var __VLS_15;
+ var __VLS_11;
+ const __VLS_48 = {}.ElCard;
+ /** @type {[typeof __VLS_components.ElCard, typeof __VLS_components.elCard, typeof __VLS_components.ElCard, typeof __VLS_components.elCard, ]} */ ;
+ // @ts-ignore
+ const __VLS_49 = __VLS_asFunctionalComponent(__VLS_48, new __VLS_48({}));
+ const __VLS_50 = __VLS_49({}, ...__VLS_functionalComponentArgsRest(__VLS_49));
+ __VLS_51.slots.default;
+ {
+ const { header: __VLS_thisSlot } = __VLS_51.slots;
+ __VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
+ ...{ style: {} },
+ });
+ __VLS_asFunctionalElement(__VLS_intrinsicElements.span, __VLS_intrinsicElements.span)({});
+ const __VLS_52 = {}.ElUpload;
+ /** @type {[typeof __VLS_components.ElUpload, typeof __VLS_components.elUpload, typeof __VLS_components.ElUpload, typeof __VLS_components.elUpload, ]} */ ;
+ // @ts-ignore
+ const __VLS_53 = __VLS_asFunctionalComponent(__VLS_52, new __VLS_52({
+ showFileList: (false),
+ httpRequest: (__VLS_ctx.handleUpload),
+ accept: ".docx,.pdf",
+ }));
+ const __VLS_54 = __VLS_53({
+ showFileList: (false),
+ httpRequest: (__VLS_ctx.handleUpload),
+ accept: ".docx,.pdf",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_53));
+ __VLS_55.slots.default;
+ const __VLS_56 = {}.ElButton;
+ /** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+ // @ts-ignore
+ const __VLS_57 = __VLS_asFunctionalComponent(__VLS_56, new __VLS_56({
+ type: "primary",
+ loading: (__VLS_ctx.uploading),
+ }));
+ const __VLS_58 = __VLS_57({
+ type: "primary",
+ loading: (__VLS_ctx.uploading),
+ }, ...__VLS_functionalComponentArgsRest(__VLS_57));
+ __VLS_59.slots.default;
+ var __VLS_59;
+ var __VLS_55;
+ }
+ const __VLS_60 = {}.ElTable;
+ /** @type {[typeof __VLS_components.ElTable, typeof __VLS_components.elTable, typeof __VLS_components.ElTable, typeof __VLS_components.elTable, ]} */ ;
+ // @ts-ignore
+ const __VLS_61 = __VLS_asFunctionalComponent(__VLS_60, new __VLS_60({
+ data: (__VLS_ctx.docs),
+ ...{ style: {} },
+ }));
+ const __VLS_62 = __VLS_61({
+ data: (__VLS_ctx.docs),
+ ...{ style: {} },
+ }, ...__VLS_functionalComponentArgsRest(__VLS_61));
+ __VLS_asFunctionalDirective(__VLS_directives.vLoading)(null, { ...__VLS_directiveBindingRestFields, value: (__VLS_ctx.loading) }, null, null);
+ __VLS_63.slots.default;
+ const __VLS_64 = {}.ElTableColumn;
+ /** @type {[typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, ]} */ ;
+ // @ts-ignore
+ const __VLS_65 = __VLS_asFunctionalComponent(__VLS_64, new __VLS_64({
+ prop: "original_filename",
+ label: "文件名",
+ minWidth: "200",
+ showOverflowTooltip: true,
+ }));
+ const __VLS_66 = __VLS_65({
+ prop: "original_filename",
+ label: "文件名",
+ minWidth: "200",
+ showOverflowTooltip: true,
+ }, ...__VLS_functionalComponentArgsRest(__VLS_65));
+ const __VLS_68 = {}.ElTableColumn;
+ /** @type {[typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, ]} */ ;
+ // @ts-ignore
+ const __VLS_69 = __VLS_asFunctionalComponent(__VLS_68, new __VLS_68({
+ label: "状态",
+ width: "120",
+ align: "center",
+ }));
+ const __VLS_70 = __VLS_69({
+ label: "状态",
+ width: "120",
+ align: "center",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_69));
+ __VLS_71.slots.default;
+ {
+ const { default: __VLS_thisSlot } = __VLS_71.slots;
+ const [{ row }] = __VLS_getSlotParams(__VLS_thisSlot);
+ const __VLS_72 = {}.ElTag;
+ /** @type {[typeof __VLS_components.ElTag, typeof __VLS_components.elTag, typeof __VLS_components.ElTag, typeof __VLS_components.elTag, ]} */ ;
+ // @ts-ignore
+ const __VLS_73 = __VLS_asFunctionalComponent(__VLS_72, new __VLS_72({
+ type: (__VLS_ctx.statusType(row.status)),
+ size: "small",
+ }));
+ const __VLS_74 = __VLS_73({
+ type: (__VLS_ctx.statusType(row.status)),
+ size: "small",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_73));
+ __VLS_75.slots.default;
+ (row.status);
+ var __VLS_75;
+ }
+ var __VLS_71;
+ const __VLS_76 = {}.ElTableColumn;
+ /** @type {[typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, ]} */ ;
+ // @ts-ignore
+ const __VLS_77 = __VLS_asFunctionalComponent(__VLS_76, new __VLS_76({
+ label: "大小",
+ width: "100",
+ align: "center",
+ }));
+ const __VLS_78 = __VLS_77({
+ label: "大小",
+ width: "100",
+ align: "center",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_77));
+ __VLS_79.slots.default;
+ {
+ const { default: __VLS_thisSlot } = __VLS_79.slots;
+ const [{ row }] = __VLS_getSlotParams(__VLS_thisSlot);
+ (__VLS_ctx.formatSize(row.file_size));
+ }
+ var __VLS_79;
+ const __VLS_80 = {}.ElTableColumn;
+ /** @type {[typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, ]} */ ;
+ // @ts-ignore
+ const __VLS_81 = __VLS_asFunctionalComponent(__VLS_80, new __VLS_80({
+ prop: "title",
+ label: "标题",
+ minWidth: "150",
+ showOverflowTooltip: true,
+ }));
+ const __VLS_82 = __VLS_81({
+ prop: "title",
+ label: "标题",
+ minWidth: "150",
+ showOverflowTooltip: true,
+ }, ...__VLS_functionalComponentArgsRest(__VLS_81));
+ const __VLS_84 = {}.ElTableColumn;
+ /** @type {[typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, ]} */ ;
+ // @ts-ignore
+ const __VLS_85 = __VLS_asFunctionalComponent(__VLS_84, new __VLS_84({
+ prop: "keywords",
+ label: "关键词",
+ minWidth: "150",
+ showOverflowTooltip: true,
+ }));
+ const __VLS_86 = __VLS_85({
+ prop: "keywords",
+ label: "关键词",
+ minWidth: "150",
+ showOverflowTooltip: true,
+ }, ...__VLS_functionalComponentArgsRest(__VLS_85));
+ const __VLS_88 = {}.ElTableColumn;
+ /** @type {[typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, ]} */ ;
+ // @ts-ignore
+ const __VLS_89 = __VLS_asFunctionalComponent(__VLS_88, new __VLS_88({
+ label: "操作",
+ width: "200",
+ align: "center",
+ }));
+ const __VLS_90 = __VLS_89({
+ label: "操作",
+ width: "200",
+ align: "center",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_89));
+ __VLS_91.slots.default;
+ {
+ const { default: __VLS_thisSlot } = __VLS_91.slots;
+ const [{ row }] = __VLS_getSlotParams(__VLS_thisSlot);
+ const __VLS_92 = {}.ElButton;
+ /** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+ // @ts-ignore
+ const __VLS_93 = __VLS_asFunctionalComponent(__VLS_92, new __VLS_92({
+ ...{ 'onClick': {} },
+ size: "small",
+ }));
+ const __VLS_94 = __VLS_93({
+ ...{ 'onClick': {} },
+ size: "small",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_93));
+ let __VLS_96;
+ let __VLS_97;
+ let __VLS_98;
+ const __VLS_99 = {
+ onClick: (...[$event]) => {
+ if (!(__VLS_ctx.kb))
+ return;
+ __VLS_ctx.handleReprocess(row);
+ }
+ };
+ __VLS_95.slots.default;
+ var __VLS_95;
+ const __VLS_100 = {}.ElButton;
+ /** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+ // @ts-ignore
+ const __VLS_101 = __VLS_asFunctionalComponent(__VLS_100, new __VLS_100({
+ ...{ 'onClick': {} },
+ size: "small",
+ type: "danger",
+ }));
+ const __VLS_102 = __VLS_101({
+ ...{ 'onClick': {} },
+ size: "small",
+ type: "danger",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_101));
+ let __VLS_104;
+ let __VLS_105;
+ let __VLS_106;
+ const __VLS_107 = {
+ onClick: (...[$event]) => {
+ if (!(__VLS_ctx.kb))
+ return;
+ __VLS_ctx.handleDeleteDoc(row);
+ }
+ };
+ __VLS_103.slots.default;
+ var __VLS_103;
+ }
+ var __VLS_91;
+ var __VLS_63;
+ var __VLS_51;
+}
var __VLS_dollars;
const __VLS_self = (await import('vue')).defineComponent({
setup() {
- return {};
+ return {
+ kb: kb,
+ docs: docs,
+ loading: loading,
+ uploading: uploading,
+ aiUrl: aiUrl,
+ handleUpload: handleUpload,
+ handleDeleteDoc: handleDeleteDoc,
+ handleReprocess: handleReprocess,
+ handleCopyLink: handleCopyLink,
+ handleRegenerate: handleRegenerate,
+ formatSize: formatSize,
+ statusType: statusType,
+ };
},
});
export default (await import('vue')).defineComponent({
diff --git a/frontend/src/views/KnowledgeBases.vue b/frontend/src/views/KnowledgeBases.vue
index 70c30d9..404f5a7 100644
--- a/frontend/src/views/KnowledgeBases.vue
+++ b/frontend/src/views/KnowledgeBases.vue
@@ -1,10 +1,120 @@
-
知识库
-
知识库列表(Phase 4 实现)
+
+
知识库
+ 创建知识库
+
+
+
+
+
+
+ {{ row.name }}
+
+
+
+
+
+
+
+
+ {{ row.enabled ? '启用' : '禁用' }}
+
+
+
+
+
+ 复制链接
+
+ {{ row.enabled ? '禁用' : '启用' }}
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 创建
+
+
-
\ No newline at end of file
+
diff --git a/frontend/src/views/KnowledgeBases.vue.js b/frontend/src/views/KnowledgeBases.vue.js
index 09e44bb..8d1c32e 100644
--- a/frontend/src/views/KnowledgeBases.vue.js
+++ b/frontend/src/views/KnowledgeBases.vue.js
@@ -1,14 +1,427 @@
+import { ref, onMounted } from 'vue';
+import { useRouter } from 'vue-router';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import apiClient from '@/api/client';
+const router = useRouter();
+const kbs = ref([]);
+const loading = ref(false);
+const showCreate = ref(false);
+const createForm = ref({ name: '', description: '' });
+const createLoading = ref(false);
+onMounted(() => {
+ loadKbs();
+});
+async function loadKbs() {
+ loading.value = true;
+ try {
+ const { data } = await apiClient.get('/knowledge-bases');
+ kbs.value = data.items;
+ }
+ catch { /* ignore */ }
+ loading.value = false;
+}
+async function handleCreate() {
+ if (!createForm.value.name.trim()) {
+ ElMessage.warning('请输入知识库名称。');
+ return;
+ }
+ createLoading.value = true;
+ try {
+ const { data } = await apiClient.post('/knowledge-bases', createForm.value);
+ ElMessage.success('知识库创建成功!');
+ showCreate.value = false;
+ createForm.value = { name: '', description: '' };
+ router.push(`/knowledge-bases/${data.id}`);
+ }
+ catch { /* ignore */ }
+ createLoading.value = false;
+}
+async function handleDelete(kb) {
+ try {
+ await ElMessageBox.confirm(`确定删除知识库「${kb.name}」?`, '确认删除', { type: 'warning' });
+ await apiClient.delete(`/knowledge-bases/${kb.id}`);
+ ElMessage.success('已删除。');
+ loadKbs();
+ }
+ catch { /* ignore */ }
+}
+async function handleToggle(kb) {
+ const action = kb.enabled ? 'disable' : 'enable';
+ await apiClient.post(`/knowledge-bases/${kb.id}/${action}`);
+ ElMessage.success(kb.enabled ? '已禁用。' : '已启用。');
+ loadKbs();
+}
+async function handleCopyLink(kb) {
+ try {
+ const { data } = await apiClient.get(`/knowledge-bases/${kb.id}/link`);
+ const url = `${window.location.origin}${data.ai_url}`;
+ await navigator.clipboard.writeText(url);
+ ElMessage.success('AI 链接已复制到剪贴板!');
+ }
+ catch { /* ignore */ }
+}
debugger; /* PartiallyEnd: #3632/scriptSetup.vue */
const __VLS_ctx = {};
let __VLS_components;
let __VLS_directives;
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({});
-__VLS_asFunctionalElement(__VLS_intrinsicElements.h1, __VLS_intrinsicElements.h1)({});
-__VLS_asFunctionalElement(__VLS_intrinsicElements.p, __VLS_intrinsicElements.p)({});
+__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
+ ...{ style: {} },
+});
+__VLS_asFunctionalElement(__VLS_intrinsicElements.h1, __VLS_intrinsicElements.h1)({
+ ...{ style: {} },
+});
+const __VLS_0 = {}.ElButton;
+/** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+// @ts-ignore
+const __VLS_1 = __VLS_asFunctionalComponent(__VLS_0, new __VLS_0({
+ ...{ 'onClick': {} },
+ type: "primary",
+}));
+const __VLS_2 = __VLS_1({
+ ...{ 'onClick': {} },
+ type: "primary",
+}, ...__VLS_functionalComponentArgsRest(__VLS_1));
+let __VLS_4;
+let __VLS_5;
+let __VLS_6;
+const __VLS_7 = {
+ onClick: (...[$event]) => {
+ __VLS_ctx.showCreate = true;
+ }
+};
+__VLS_3.slots.default;
+var __VLS_3;
+const __VLS_8 = {}.ElTable;
+/** @type {[typeof __VLS_components.ElTable, typeof __VLS_components.elTable, typeof __VLS_components.ElTable, typeof __VLS_components.elTable, ]} */ ;
+// @ts-ignore
+const __VLS_9 = __VLS_asFunctionalComponent(__VLS_8, new __VLS_8({
+ data: (__VLS_ctx.kbs),
+ ...{ style: {} },
+}));
+const __VLS_10 = __VLS_9({
+ data: (__VLS_ctx.kbs),
+ ...{ style: {} },
+}, ...__VLS_functionalComponentArgsRest(__VLS_9));
+__VLS_asFunctionalDirective(__VLS_directives.vLoading)(null, { ...__VLS_directiveBindingRestFields, value: (__VLS_ctx.loading) }, null, null);
+__VLS_11.slots.default;
+const __VLS_12 = {}.ElTableColumn;
+/** @type {[typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, ]} */ ;
+// @ts-ignore
+const __VLS_13 = __VLS_asFunctionalComponent(__VLS_12, new __VLS_12({
+ prop: "name",
+ label: "名称",
+ minWidth: "200",
+}));
+const __VLS_14 = __VLS_13({
+ prop: "name",
+ label: "名称",
+ minWidth: "200",
+}, ...__VLS_functionalComponentArgsRest(__VLS_13));
+__VLS_15.slots.default;
+{
+ const { default: __VLS_thisSlot } = __VLS_15.slots;
+ const [{ row }] = __VLS_getSlotParams(__VLS_thisSlot);
+ const __VLS_16 = {}.RouterLink;
+ /** @type {[typeof __VLS_components.RouterLink, typeof __VLS_components.routerLink, typeof __VLS_components.RouterLink, typeof __VLS_components.routerLink, ]} */ ;
+ // @ts-ignore
+ const __VLS_17 = __VLS_asFunctionalComponent(__VLS_16, new __VLS_16({
+ to: (`/knowledge-bases/${row.id}`),
+ ...{ style: {} },
+ }));
+ const __VLS_18 = __VLS_17({
+ to: (`/knowledge-bases/${row.id}`),
+ ...{ style: {} },
+ }, ...__VLS_functionalComponentArgsRest(__VLS_17));
+ __VLS_19.slots.default;
+ (row.name);
+ var __VLS_19;
+}
+var __VLS_15;
+const __VLS_20 = {}.ElTableColumn;
+/** @type {[typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, ]} */ ;
+// @ts-ignore
+const __VLS_21 = __VLS_asFunctionalComponent(__VLS_20, new __VLS_20({
+ prop: "description",
+ label: "描述",
+ minWidth: "200",
+ showOverflowTooltip: true,
+}));
+const __VLS_22 = __VLS_21({
+ prop: "description",
+ label: "描述",
+ minWidth: "200",
+ showOverflowTooltip: true,
+}, ...__VLS_functionalComponentArgsRest(__VLS_21));
+const __VLS_24 = {}.ElTableColumn;
+/** @type {[typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, ]} */ ;
+// @ts-ignore
+const __VLS_25 = __VLS_asFunctionalComponent(__VLS_24, new __VLS_24({
+ prop: "document_count",
+ label: "文档数",
+ width: "100",
+ align: "center",
+}));
+const __VLS_26 = __VLS_25({
+ prop: "document_count",
+ label: "文档数",
+ width: "100",
+ align: "center",
+}, ...__VLS_functionalComponentArgsRest(__VLS_25));
+const __VLS_28 = {}.ElTableColumn;
+/** @type {[typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, ]} */ ;
+// @ts-ignore
+const __VLS_29 = __VLS_asFunctionalComponent(__VLS_28, new __VLS_28({
+ label: "状态",
+ width: "100",
+ align: "center",
+}));
+const __VLS_30 = __VLS_29({
+ label: "状态",
+ width: "100",
+ align: "center",
+}, ...__VLS_functionalComponentArgsRest(__VLS_29));
+__VLS_31.slots.default;
+{
+ const { default: __VLS_thisSlot } = __VLS_31.slots;
+ const [{ row }] = __VLS_getSlotParams(__VLS_thisSlot);
+ const __VLS_32 = {}.ElTag;
+ /** @type {[typeof __VLS_components.ElTag, typeof __VLS_components.elTag, typeof __VLS_components.ElTag, typeof __VLS_components.elTag, ]} */ ;
+ // @ts-ignore
+ const __VLS_33 = __VLS_asFunctionalComponent(__VLS_32, new __VLS_32({
+ type: (row.enabled ? 'success' : 'danger'),
+ size: "small",
+ }));
+ const __VLS_34 = __VLS_33({
+ type: (row.enabled ? 'success' : 'danger'),
+ size: "small",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_33));
+ __VLS_35.slots.default;
+ (row.enabled ? '启用' : '禁用');
+ var __VLS_35;
+}
+var __VLS_31;
+const __VLS_36 = {}.ElTableColumn;
+/** @type {[typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, typeof __VLS_components.ElTableColumn, typeof __VLS_components.elTableColumn, ]} */ ;
+// @ts-ignore
+const __VLS_37 = __VLS_asFunctionalComponent(__VLS_36, new __VLS_36({
+ label: "操作",
+ width: "300",
+ align: "center",
+}));
+const __VLS_38 = __VLS_37({
+ label: "操作",
+ width: "300",
+ align: "center",
+}, ...__VLS_functionalComponentArgsRest(__VLS_37));
+__VLS_39.slots.default;
+{
+ const { default: __VLS_thisSlot } = __VLS_39.slots;
+ const [{ row }] = __VLS_getSlotParams(__VLS_thisSlot);
+ const __VLS_40 = {}.ElButton;
+ /** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+ // @ts-ignore
+ const __VLS_41 = __VLS_asFunctionalComponent(__VLS_40, new __VLS_40({
+ ...{ 'onClick': {} },
+ size: "small",
+ }));
+ const __VLS_42 = __VLS_41({
+ ...{ 'onClick': {} },
+ size: "small",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_41));
+ let __VLS_44;
+ let __VLS_45;
+ let __VLS_46;
+ const __VLS_47 = {
+ onClick: (...[$event]) => {
+ __VLS_ctx.handleCopyLink(row);
+ }
+ };
+ __VLS_43.slots.default;
+ var __VLS_43;
+ const __VLS_48 = {}.ElButton;
+ /** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+ // @ts-ignore
+ const __VLS_49 = __VLS_asFunctionalComponent(__VLS_48, new __VLS_48({
+ ...{ 'onClick': {} },
+ size: "small",
+ }));
+ const __VLS_50 = __VLS_49({
+ ...{ 'onClick': {} },
+ size: "small",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_49));
+ let __VLS_52;
+ let __VLS_53;
+ let __VLS_54;
+ const __VLS_55 = {
+ onClick: (...[$event]) => {
+ __VLS_ctx.handleToggle(row);
+ }
+ };
+ __VLS_51.slots.default;
+ (row.enabled ? '禁用' : '启用');
+ var __VLS_51;
+ const __VLS_56 = {}.ElButton;
+ /** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+ // @ts-ignore
+ const __VLS_57 = __VLS_asFunctionalComponent(__VLS_56, new __VLS_56({
+ ...{ 'onClick': {} },
+ size: "small",
+ type: "danger",
+ }));
+ const __VLS_58 = __VLS_57({
+ ...{ 'onClick': {} },
+ size: "small",
+ type: "danger",
+ }, ...__VLS_functionalComponentArgsRest(__VLS_57));
+ let __VLS_60;
+ let __VLS_61;
+ let __VLS_62;
+ const __VLS_63 = {
+ onClick: (...[$event]) => {
+ __VLS_ctx.handleDelete(row);
+ }
+ };
+ __VLS_59.slots.default;
+ var __VLS_59;
+}
+var __VLS_39;
+var __VLS_11;
+const __VLS_64 = {}.ElDialog;
+/** @type {[typeof __VLS_components.ElDialog, typeof __VLS_components.elDialog, typeof __VLS_components.ElDialog, typeof __VLS_components.elDialog, ]} */ ;
+// @ts-ignore
+const __VLS_65 = __VLS_asFunctionalComponent(__VLS_64, new __VLS_64({
+ modelValue: (__VLS_ctx.showCreate),
+ title: "创建知识库",
+ width: "500px",
+}));
+const __VLS_66 = __VLS_65({
+ modelValue: (__VLS_ctx.showCreate),
+ title: "创建知识库",
+ width: "500px",
+}, ...__VLS_functionalComponentArgsRest(__VLS_65));
+__VLS_67.slots.default;
+const __VLS_68 = {}.ElForm;
+/** @type {[typeof __VLS_components.ElForm, typeof __VLS_components.elForm, typeof __VLS_components.ElForm, typeof __VLS_components.elForm, ]} */ ;
+// @ts-ignore
+const __VLS_69 = __VLS_asFunctionalComponent(__VLS_68, new __VLS_68({
+ model: (__VLS_ctx.createForm),
+ labelPosition: "top",
+}));
+const __VLS_70 = __VLS_69({
+ model: (__VLS_ctx.createForm),
+ labelPosition: "top",
+}, ...__VLS_functionalComponentArgsRest(__VLS_69));
+__VLS_71.slots.default;
+const __VLS_72 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_73 = __VLS_asFunctionalComponent(__VLS_72, new __VLS_72({
+ label: "名称",
+ required: true,
+}));
+const __VLS_74 = __VLS_73({
+ label: "名称",
+ required: true,
+}, ...__VLS_functionalComponentArgsRest(__VLS_73));
+__VLS_75.slots.default;
+const __VLS_76 = {}.ElInput;
+/** @type {[typeof __VLS_components.ElInput, typeof __VLS_components.elInput, ]} */ ;
+// @ts-ignore
+const __VLS_77 = __VLS_asFunctionalComponent(__VLS_76, new __VLS_76({
+ modelValue: (__VLS_ctx.createForm.name),
+ placeholder: "例如:公司知识库",
+}));
+const __VLS_78 = __VLS_77({
+ modelValue: (__VLS_ctx.createForm.name),
+ placeholder: "例如:公司知识库",
+}, ...__VLS_functionalComponentArgsRest(__VLS_77));
+var __VLS_75;
+const __VLS_80 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_81 = __VLS_asFunctionalComponent(__VLS_80, new __VLS_80({
+ label: "描述",
+}));
+const __VLS_82 = __VLS_81({
+ label: "描述",
+}, ...__VLS_functionalComponentArgsRest(__VLS_81));
+__VLS_83.slots.default;
+const __VLS_84 = {}.ElInput;
+/** @type {[typeof __VLS_components.ElInput, typeof __VLS_components.elInput, ]} */ ;
+// @ts-ignore
+const __VLS_85 = __VLS_asFunctionalComponent(__VLS_84, new __VLS_84({
+ modelValue: (__VLS_ctx.createForm.description),
+ type: "textarea",
+ rows: (3),
+ placeholder: "可选描述",
+}));
+const __VLS_86 = __VLS_85({
+ modelValue: (__VLS_ctx.createForm.description),
+ type: "textarea",
+ rows: (3),
+ placeholder: "可选描述",
+}, ...__VLS_functionalComponentArgsRest(__VLS_85));
+var __VLS_83;
+var __VLS_71;
+{
+ const { footer: __VLS_thisSlot } = __VLS_67.slots;
+ const __VLS_88 = {}.ElButton;
+ /** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+ // @ts-ignore
+ const __VLS_89 = __VLS_asFunctionalComponent(__VLS_88, new __VLS_88({
+ ...{ 'onClick': {} },
+ }));
+ const __VLS_90 = __VLS_89({
+ ...{ 'onClick': {} },
+ }, ...__VLS_functionalComponentArgsRest(__VLS_89));
+ let __VLS_92;
+ let __VLS_93;
+ let __VLS_94;
+ const __VLS_95 = {
+ onClick: (...[$event]) => {
+ __VLS_ctx.showCreate = false;
+ }
+ };
+ __VLS_91.slots.default;
+ var __VLS_91;
+ const __VLS_96 = {}.ElButton;
+ /** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+ // @ts-ignore
+ const __VLS_97 = __VLS_asFunctionalComponent(__VLS_96, new __VLS_96({
+ ...{ 'onClick': {} },
+ type: "primary",
+ loading: (__VLS_ctx.createLoading),
+ }));
+ const __VLS_98 = __VLS_97({
+ ...{ 'onClick': {} },
+ type: "primary",
+ loading: (__VLS_ctx.createLoading),
+ }, ...__VLS_functionalComponentArgsRest(__VLS_97));
+ let __VLS_100;
+ let __VLS_101;
+ let __VLS_102;
+ const __VLS_103 = {
+ onClick: (__VLS_ctx.handleCreate)
+ };
+ __VLS_99.slots.default;
+ var __VLS_99;
+}
+var __VLS_67;
var __VLS_dollars;
const __VLS_self = (await import('vue')).defineComponent({
setup() {
- return {};
+ return {
+ kbs: kbs,
+ loading: loading,
+ showCreate: showCreate,
+ createForm: createForm,
+ createLoading: createLoading,
+ handleCreate: handleCreate,
+ handleDelete: handleDelete,
+ handleToggle: handleToggle,
+ handleCopyLink: handleCopyLink,
+ };
},
});
export default (await import('vue')).defineComponent({
diff --git a/frontend/src/views/Login.vue b/frontend/src/views/Login.vue
index 317d47a..d87ebe9 100644
--- a/frontend/src/views/Login.vue
+++ b/frontend/src/views/Login.vue
@@ -1,14 +1,54 @@
- AI Knowledge Link
+ AI Knowledge Link
- 登录页面(Phase 3 实现)
+
+
+
+
+
+
+
+
+
+ 登录
+
+
+
+
+ 没有账号?立即注册
+
@@ -24,4 +64,4 @@
.login-card {
width: 400px;
}
-
\ No newline at end of file
+
diff --git a/frontend/src/views/Login.vue.js b/frontend/src/views/Login.vue.js
index b9d6ec6..d99d52a 100644
--- a/frontend/src/views/Login.vue.js
+++ b/frontend/src/views/Login.vue.js
@@ -1,3 +1,28 @@
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { useUserStore } from '@/stores/user';
+import apiClient from '@/api/client';
+const router = useRouter();
+const userStore = useUserStore();
+const form = ref({
+ username_or_email: '',
+ password: '',
+});
+const loading = ref(false);
+async function handleLogin() {
+ loading.value = true;
+ try {
+ const { data } = await apiClient.post('/auth/login', form.value);
+ userStore.setUser(data);
+ router.push('/');
+ }
+ catch {
+ // 错误由拦截器处理
+ }
+ finally {
+ loading.value = false;
+ }
+}
debugger; /* PartiallyEnd: #3632/scriptSetup.vue */
const __VLS_ctx = {};
let __VLS_components;
@@ -19,16 +44,128 @@ const __VLS_2 = __VLS_1({
__VLS_3.slots.default;
{
const { header: __VLS_thisSlot } = __VLS_3.slots;
- __VLS_asFunctionalElement(__VLS_intrinsicElements.h2, __VLS_intrinsicElements.h2)({});
+ __VLS_asFunctionalElement(__VLS_intrinsicElements.h2, __VLS_intrinsicElements.h2)({
+ ...{ style: {} },
+ });
}
-__VLS_asFunctionalElement(__VLS_intrinsicElements.p, __VLS_intrinsicElements.p)({});
+const __VLS_4 = {}.ElForm;
+/** @type {[typeof __VLS_components.ElForm, typeof __VLS_components.elForm, typeof __VLS_components.ElForm, typeof __VLS_components.elForm, ]} */ ;
+// @ts-ignore
+const __VLS_5 = __VLS_asFunctionalComponent(__VLS_4, new __VLS_4({
+ ...{ 'onSubmit': {} },
+ model: (__VLS_ctx.form),
+ labelPosition: "top",
+}));
+const __VLS_6 = __VLS_5({
+ ...{ 'onSubmit': {} },
+ model: (__VLS_ctx.form),
+ labelPosition: "top",
+}, ...__VLS_functionalComponentArgsRest(__VLS_5));
+let __VLS_8;
+let __VLS_9;
+let __VLS_10;
+const __VLS_11 = {
+ onSubmit: (__VLS_ctx.handleLogin)
+};
+__VLS_7.slots.default;
+const __VLS_12 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_13 = __VLS_asFunctionalComponent(__VLS_12, new __VLS_12({
+ label: "用户名或邮箱",
+}));
+const __VLS_14 = __VLS_13({
+ label: "用户名或邮箱",
+}, ...__VLS_functionalComponentArgsRest(__VLS_13));
+__VLS_15.slots.default;
+const __VLS_16 = {}.ElInput;
+/** @type {[typeof __VLS_components.ElInput, typeof __VLS_components.elInput, ]} */ ;
+// @ts-ignore
+const __VLS_17 = __VLS_asFunctionalComponent(__VLS_16, new __VLS_16({
+ modelValue: (__VLS_ctx.form.username_or_email),
+ placeholder: "请输入用户名或邮箱",
+}));
+const __VLS_18 = __VLS_17({
+ modelValue: (__VLS_ctx.form.username_or_email),
+ placeholder: "请输入用户名或邮箱",
+}, ...__VLS_functionalComponentArgsRest(__VLS_17));
+var __VLS_15;
+const __VLS_20 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_21 = __VLS_asFunctionalComponent(__VLS_20, new __VLS_20({
+ label: "密码",
+}));
+const __VLS_22 = __VLS_21({
+ label: "密码",
+}, ...__VLS_functionalComponentArgsRest(__VLS_21));
+__VLS_23.slots.default;
+const __VLS_24 = {}.ElInput;
+/** @type {[typeof __VLS_components.ElInput, typeof __VLS_components.elInput, ]} */ ;
+// @ts-ignore
+const __VLS_25 = __VLS_asFunctionalComponent(__VLS_24, new __VLS_24({
+ modelValue: (__VLS_ctx.form.password),
+ type: "password",
+ placeholder: "请输入密码",
+ showPassword: true,
+}));
+const __VLS_26 = __VLS_25({
+ modelValue: (__VLS_ctx.form.password),
+ type: "password",
+ placeholder: "请输入密码",
+ showPassword: true,
+}, ...__VLS_functionalComponentArgsRest(__VLS_25));
+var __VLS_23;
+const __VLS_28 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_29 = __VLS_asFunctionalComponent(__VLS_28, new __VLS_28({}));
+const __VLS_30 = __VLS_29({}, ...__VLS_functionalComponentArgsRest(__VLS_29));
+__VLS_31.slots.default;
+const __VLS_32 = {}.ElButton;
+/** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+// @ts-ignore
+const __VLS_33 = __VLS_asFunctionalComponent(__VLS_32, new __VLS_32({
+ type: "primary",
+ loading: (__VLS_ctx.loading),
+ ...{ style: {} },
+ nativeType: "submit",
+}));
+const __VLS_34 = __VLS_33({
+ type: "primary",
+ loading: (__VLS_ctx.loading),
+ ...{ style: {} },
+ nativeType: "submit",
+}, ...__VLS_functionalComponentArgsRest(__VLS_33));
+__VLS_35.slots.default;
+var __VLS_35;
+var __VLS_31;
+var __VLS_7;
+__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
+ ...{ style: {} },
+});
+const __VLS_36 = {}.RouterLink;
+/** @type {[typeof __VLS_components.RouterLink, typeof __VLS_components.routerLink, typeof __VLS_components.RouterLink, typeof __VLS_components.routerLink, ]} */ ;
+// @ts-ignore
+const __VLS_37 = __VLS_asFunctionalComponent(__VLS_36, new __VLS_36({
+ to: "/register",
+}));
+const __VLS_38 = __VLS_37({
+ to: "/register",
+}, ...__VLS_functionalComponentArgsRest(__VLS_37));
+__VLS_39.slots.default;
+var __VLS_39;
var __VLS_3;
/** @type {__VLS_StyleScopedClasses['login-page']} */ ;
/** @type {__VLS_StyleScopedClasses['login-card']} */ ;
var __VLS_dollars;
const __VLS_self = (await import('vue')).defineComponent({
setup() {
- return {};
+ return {
+ form: form,
+ loading: loading,
+ handleLogin: handleLogin,
+ };
},
});
export default (await import('vue')).defineComponent({
diff --git a/frontend/src/views/Register.vue b/frontend/src/views/Register.vue
index efd240e..940d46a 100644
--- a/frontend/src/views/Register.vue
+++ b/frontend/src/views/Register.vue
@@ -1,14 +1,72 @@
- 注册
+ 注册
- 注册页面(Phase 3 实现)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 注册
+
+
+
+
+ 已有账号?立即登录
+
@@ -24,4 +82,4 @@
.register-card {
width: 400px;
}
-
\ No newline at end of file
+
diff --git a/frontend/src/views/Register.vue.js b/frontend/src/views/Register.vue.js
index 76db03e..29d426b 100644
--- a/frontend/src/views/Register.vue.js
+++ b/frontend/src/views/Register.vue.js
@@ -1,3 +1,39 @@
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+import { useUserStore } from '@/stores/user';
+import apiClient from '@/api/client';
+const router = useRouter();
+const userStore = useUserStore();
+const form = ref({
+ username: '',
+ email: '',
+ password: '',
+ confirmPassword: '',
+});
+const loading = ref(false);
+async function handleRegister() {
+ if (form.value.password !== form.value.confirmPassword) {
+ ElMessage.error('两次输入的密码不一致。');
+ return;
+ }
+ loading.value = true;
+ try {
+ const { data } = await apiClient.post('/auth/register', {
+ username: form.value.username,
+ email: form.value.email,
+ password: form.value.password,
+ });
+ userStore.setUser(data);
+ router.push('/');
+ }
+ catch {
+ // 错误由拦截器处理
+ }
+ finally {
+ loading.value = false;
+ }
+}
+import { ElMessage } from 'element-plus';
debugger; /* PartiallyEnd: #3632/scriptSetup.vue */
const __VLS_ctx = {};
let __VLS_components;
@@ -19,16 +55,176 @@ const __VLS_2 = __VLS_1({
__VLS_3.slots.default;
{
const { header: __VLS_thisSlot } = __VLS_3.slots;
- __VLS_asFunctionalElement(__VLS_intrinsicElements.h2, __VLS_intrinsicElements.h2)({});
+ __VLS_asFunctionalElement(__VLS_intrinsicElements.h2, __VLS_intrinsicElements.h2)({
+ ...{ style: {} },
+ });
}
-__VLS_asFunctionalElement(__VLS_intrinsicElements.p, __VLS_intrinsicElements.p)({});
+const __VLS_4 = {}.ElForm;
+/** @type {[typeof __VLS_components.ElForm, typeof __VLS_components.elForm, typeof __VLS_components.ElForm, typeof __VLS_components.elForm, ]} */ ;
+// @ts-ignore
+const __VLS_5 = __VLS_asFunctionalComponent(__VLS_4, new __VLS_4({
+ ...{ 'onSubmit': {} },
+ model: (__VLS_ctx.form),
+ labelPosition: "top",
+}));
+const __VLS_6 = __VLS_5({
+ ...{ 'onSubmit': {} },
+ model: (__VLS_ctx.form),
+ labelPosition: "top",
+}, ...__VLS_functionalComponentArgsRest(__VLS_5));
+let __VLS_8;
+let __VLS_9;
+let __VLS_10;
+const __VLS_11 = {
+ onSubmit: (__VLS_ctx.handleRegister)
+};
+__VLS_7.slots.default;
+const __VLS_12 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_13 = __VLS_asFunctionalComponent(__VLS_12, new __VLS_12({
+ label: "用户名",
+}));
+const __VLS_14 = __VLS_13({
+ label: "用户名",
+}, ...__VLS_functionalComponentArgsRest(__VLS_13));
+__VLS_15.slots.default;
+const __VLS_16 = {}.ElInput;
+/** @type {[typeof __VLS_components.ElInput, typeof __VLS_components.elInput, ]} */ ;
+// @ts-ignore
+const __VLS_17 = __VLS_asFunctionalComponent(__VLS_16, new __VLS_16({
+ modelValue: (__VLS_ctx.form.username),
+ placeholder: "2-32 位字母、数字、下划线",
+}));
+const __VLS_18 = __VLS_17({
+ modelValue: (__VLS_ctx.form.username),
+ placeholder: "2-32 位字母、数字、下划线",
+}, ...__VLS_functionalComponentArgsRest(__VLS_17));
+var __VLS_15;
+const __VLS_20 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_21 = __VLS_asFunctionalComponent(__VLS_20, new __VLS_20({
+ label: "邮箱",
+}));
+const __VLS_22 = __VLS_21({
+ label: "邮箱",
+}, ...__VLS_functionalComponentArgsRest(__VLS_21));
+__VLS_23.slots.default;
+const __VLS_24 = {}.ElInput;
+/** @type {[typeof __VLS_components.ElInput, typeof __VLS_components.elInput, ]} */ ;
+// @ts-ignore
+const __VLS_25 = __VLS_asFunctionalComponent(__VLS_24, new __VLS_24({
+ modelValue: (__VLS_ctx.form.email),
+ placeholder: "your@email.com",
+}));
+const __VLS_26 = __VLS_25({
+ modelValue: (__VLS_ctx.form.email),
+ placeholder: "your@email.com",
+}, ...__VLS_functionalComponentArgsRest(__VLS_25));
+var __VLS_23;
+const __VLS_28 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_29 = __VLS_asFunctionalComponent(__VLS_28, new __VLS_28({
+ label: "密码",
+}));
+const __VLS_30 = __VLS_29({
+ label: "密码",
+}, ...__VLS_functionalComponentArgsRest(__VLS_29));
+__VLS_31.slots.default;
+const __VLS_32 = {}.ElInput;
+/** @type {[typeof __VLS_components.ElInput, typeof __VLS_components.elInput, ]} */ ;
+// @ts-ignore
+const __VLS_33 = __VLS_asFunctionalComponent(__VLS_32, new __VLS_32({
+ modelValue: (__VLS_ctx.form.password),
+ type: "password",
+ placeholder: "至少 8 位",
+ showPassword: true,
+}));
+const __VLS_34 = __VLS_33({
+ modelValue: (__VLS_ctx.form.password),
+ type: "password",
+ placeholder: "至少 8 位",
+ showPassword: true,
+}, ...__VLS_functionalComponentArgsRest(__VLS_33));
+var __VLS_31;
+const __VLS_36 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_37 = __VLS_asFunctionalComponent(__VLS_36, new __VLS_36({
+ label: "确认密码",
+}));
+const __VLS_38 = __VLS_37({
+ label: "确认密码",
+}, ...__VLS_functionalComponentArgsRest(__VLS_37));
+__VLS_39.slots.default;
+const __VLS_40 = {}.ElInput;
+/** @type {[typeof __VLS_components.ElInput, typeof __VLS_components.elInput, ]} */ ;
+// @ts-ignore
+const __VLS_41 = __VLS_asFunctionalComponent(__VLS_40, new __VLS_40({
+ modelValue: (__VLS_ctx.form.confirmPassword),
+ type: "password",
+ placeholder: "再次输入密码",
+ showPassword: true,
+}));
+const __VLS_42 = __VLS_41({
+ modelValue: (__VLS_ctx.form.confirmPassword),
+ type: "password",
+ placeholder: "再次输入密码",
+ showPassword: true,
+}, ...__VLS_functionalComponentArgsRest(__VLS_41));
+var __VLS_39;
+const __VLS_44 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_45 = __VLS_asFunctionalComponent(__VLS_44, new __VLS_44({}));
+const __VLS_46 = __VLS_45({}, ...__VLS_functionalComponentArgsRest(__VLS_45));
+__VLS_47.slots.default;
+const __VLS_48 = {}.ElButton;
+/** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+// @ts-ignore
+const __VLS_49 = __VLS_asFunctionalComponent(__VLS_48, new __VLS_48({
+ type: "primary",
+ loading: (__VLS_ctx.loading),
+ ...{ style: {} },
+ nativeType: "submit",
+}));
+const __VLS_50 = __VLS_49({
+ type: "primary",
+ loading: (__VLS_ctx.loading),
+ ...{ style: {} },
+ nativeType: "submit",
+}, ...__VLS_functionalComponentArgsRest(__VLS_49));
+__VLS_51.slots.default;
+var __VLS_51;
+var __VLS_47;
+var __VLS_7;
+__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({
+ ...{ style: {} },
+});
+const __VLS_52 = {}.RouterLink;
+/** @type {[typeof __VLS_components.RouterLink, typeof __VLS_components.routerLink, typeof __VLS_components.RouterLink, typeof __VLS_components.routerLink, ]} */ ;
+// @ts-ignore
+const __VLS_53 = __VLS_asFunctionalComponent(__VLS_52, new __VLS_52({
+ to: "/login",
+}));
+const __VLS_54 = __VLS_53({
+ to: "/login",
+}, ...__VLS_functionalComponentArgsRest(__VLS_53));
+__VLS_55.slots.default;
+var __VLS_55;
var __VLS_3;
/** @type {__VLS_StyleScopedClasses['register-page']} */ ;
/** @type {__VLS_StyleScopedClasses['register-card']} */ ;
var __VLS_dollars;
const __VLS_self = (await import('vue')).defineComponent({
setup() {
- return {};
+ return {
+ form: form,
+ loading: loading,
+ handleRegister: handleRegister,
+ };
},
});
export default (await import('vue')).defineComponent({
diff --git a/frontend/src/views/Settings.vue b/frontend/src/views/Settings.vue
index 218e374..1e9d1fb 100644
--- a/frontend/src/views/Settings.vue
+++ b/frontend/src/views/Settings.vue
@@ -1,10 +1,49 @@
设置
-
设置页面(Phase 14 实现)
+
+ 修改密码
+
+
+
+
+
+
+
+
+ 修改密码
+
+
+
-
\ No newline at end of file
+
diff --git a/frontend/src/views/Settings.vue.js b/frontend/src/views/Settings.vue.js
index 09e44bb..95d6313 100644
--- a/frontend/src/views/Settings.vue.js
+++ b/frontend/src/views/Settings.vue.js
@@ -1,14 +1,148 @@
+import { ref } from 'vue';
+import { ElMessage } from 'element-plus';
+import apiClient from '@/api/client';
+const form = ref({
+ password: '',
+ confirmPassword: '',
+});
+const loading = ref(false);
+async function handleChangePassword() {
+ if (form.value.password !== form.value.confirmPassword) {
+ ElMessage.error('两次输入的密码不一致。');
+ return;
+ }
+ if (form.value.password.length < 8) {
+ ElMessage.error('密码长度不能少于 8 位。');
+ return;
+ }
+ loading.value = true;
+ try {
+ await apiClient.patch('/auth/me', { password: form.value.password });
+ ElMessage.success('密码修改成功。');
+ form.value = { password: '', confirmPassword: '' };
+ }
+ catch { /* ignore */ }
+ loading.value = false;
+}
debugger; /* PartiallyEnd: #3632/scriptSetup.vue */
const __VLS_ctx = {};
let __VLS_components;
let __VLS_directives;
__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({});
__VLS_asFunctionalElement(__VLS_intrinsicElements.h1, __VLS_intrinsicElements.h1)({});
-__VLS_asFunctionalElement(__VLS_intrinsicElements.p, __VLS_intrinsicElements.p)({});
+const __VLS_0 = {}.ElCard;
+/** @type {[typeof __VLS_components.ElCard, typeof __VLS_components.elCard, typeof __VLS_components.ElCard, typeof __VLS_components.elCard, ]} */ ;
+// @ts-ignore
+const __VLS_1 = __VLS_asFunctionalComponent(__VLS_0, new __VLS_0({}));
+const __VLS_2 = __VLS_1({}, ...__VLS_functionalComponentArgsRest(__VLS_1));
+__VLS_3.slots.default;
+{
+ const { header: __VLS_thisSlot } = __VLS_3.slots;
+}
+const __VLS_4 = {}.ElForm;
+/** @type {[typeof __VLS_components.ElForm, typeof __VLS_components.elForm, typeof __VLS_components.ElForm, typeof __VLS_components.elForm, ]} */ ;
+// @ts-ignore
+const __VLS_5 = __VLS_asFunctionalComponent(__VLS_4, new __VLS_4({
+ model: (__VLS_ctx.form),
+ labelPosition: "top",
+ ...{ style: {} },
+}));
+const __VLS_6 = __VLS_5({
+ model: (__VLS_ctx.form),
+ labelPosition: "top",
+ ...{ style: {} },
+}, ...__VLS_functionalComponentArgsRest(__VLS_5));
+__VLS_7.slots.default;
+const __VLS_8 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_9 = __VLS_asFunctionalComponent(__VLS_8, new __VLS_8({
+ label: "新密码",
+}));
+const __VLS_10 = __VLS_9({
+ label: "新密码",
+}, ...__VLS_functionalComponentArgsRest(__VLS_9));
+__VLS_11.slots.default;
+const __VLS_12 = {}.ElInput;
+/** @type {[typeof __VLS_components.ElInput, typeof __VLS_components.elInput, ]} */ ;
+// @ts-ignore
+const __VLS_13 = __VLS_asFunctionalComponent(__VLS_12, new __VLS_12({
+ modelValue: (__VLS_ctx.form.password),
+ type: "password",
+ placeholder: "至少 8 位",
+ showPassword: true,
+}));
+const __VLS_14 = __VLS_13({
+ modelValue: (__VLS_ctx.form.password),
+ type: "password",
+ placeholder: "至少 8 位",
+ showPassword: true,
+}, ...__VLS_functionalComponentArgsRest(__VLS_13));
+var __VLS_11;
+const __VLS_16 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_17 = __VLS_asFunctionalComponent(__VLS_16, new __VLS_16({
+ label: "确认新密码",
+}));
+const __VLS_18 = __VLS_17({
+ label: "确认新密码",
+}, ...__VLS_functionalComponentArgsRest(__VLS_17));
+__VLS_19.slots.default;
+const __VLS_20 = {}.ElInput;
+/** @type {[typeof __VLS_components.ElInput, typeof __VLS_components.elInput, ]} */ ;
+// @ts-ignore
+const __VLS_21 = __VLS_asFunctionalComponent(__VLS_20, new __VLS_20({
+ modelValue: (__VLS_ctx.form.confirmPassword),
+ type: "password",
+ placeholder: "再次输入新密码",
+ showPassword: true,
+}));
+const __VLS_22 = __VLS_21({
+ modelValue: (__VLS_ctx.form.confirmPassword),
+ type: "password",
+ placeholder: "再次输入新密码",
+ showPassword: true,
+}, ...__VLS_functionalComponentArgsRest(__VLS_21));
+var __VLS_19;
+const __VLS_24 = {}.ElFormItem;
+/** @type {[typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, typeof __VLS_components.ElFormItem, typeof __VLS_components.elFormItem, ]} */ ;
+// @ts-ignore
+const __VLS_25 = __VLS_asFunctionalComponent(__VLS_24, new __VLS_24({}));
+const __VLS_26 = __VLS_25({}, ...__VLS_functionalComponentArgsRest(__VLS_25));
+__VLS_27.slots.default;
+const __VLS_28 = {}.ElButton;
+/** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ;
+// @ts-ignore
+const __VLS_29 = __VLS_asFunctionalComponent(__VLS_28, new __VLS_28({
+ ...{ 'onClick': {} },
+ type: "primary",
+ loading: (__VLS_ctx.loading),
+}));
+const __VLS_30 = __VLS_29({
+ ...{ 'onClick': {} },
+ type: "primary",
+ loading: (__VLS_ctx.loading),
+}, ...__VLS_functionalComponentArgsRest(__VLS_29));
+let __VLS_32;
+let __VLS_33;
+let __VLS_34;
+const __VLS_35 = {
+ onClick: (__VLS_ctx.handleChangePassword)
+};
+__VLS_31.slots.default;
+var __VLS_31;
+var __VLS_27;
+var __VLS_7;
+var __VLS_3;
var __VLS_dollars;
const __VLS_self = (await import('vue')).defineComponent({
setup() {
- return {};
+ return {
+ form: form,
+ loading: loading,
+ handleChangePassword: handleChangePassword,
+ };
},
});
export default (await import('vue')).defineComponent({
diff --git a/frontend/tsconfig.tsbuildinfo b/frontend/tsconfig.tsbuildinfo
index 5fb6763..9a19fb0 100644
--- a/frontend/tsconfig.tsbuildinfo
+++ b/frontend/tsconfig.tsbuildinfo
@@ -1 +1 @@
-{"root":["./src/env.d.ts","./src/main.ts","./src/api/client.ts","./src/router/index.ts","./src/stores/user.ts","./src/app.vue","./src/views/dashboard.vue","./src/views/kbdetail.vue","./src/views/knowledgebases.vue","./src/views/login.vue","./src/views/register.vue","./src/views/settings.vue"],"version":"5.9.3"}
\ No newline at end of file
+{"root":["./src/env.d.ts","./src/main.ts","./src/api/client.ts","./src/router/index.ts","./src/stores/user.ts","./src/app.vue","./src/layouts/defaultlayout.vue","./src/views/dashboard.vue","./src/views/kbdetail.vue","./src/views/knowledgebases.vue","./src/views/login.vue","./src/views/register.vue","./src/views/settings.vue"],"version":"5.9.3"}
\ No newline at end of file