From 4db2d1a41192dc25768e37acea71d52e5389d745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E7=BB=AB?= <486494914@qq.com> Date: Tue, 1 Sep 2026 13:57:34 +0800 Subject: [PATCH] 4 --- backend/app/public/routes.py | 6 +- backend/app/services/kb_public_service.py | 4 +- backend/requirements.txt | 4 +- docs/requirements.md | 2 +- frontend/package-lock.json | 53 +-- frontend/package.json | 26 +- frontend/src/layouts/DefaultLayout.vue | 71 ++++ frontend/src/layouts/DefaultLayout.vue.js | 263 ++++++++++++ frontend/src/router/index.js | 40 +- frontend/src/router/index.ts | 42 +- frontend/src/views/Dashboard.vue | 85 +++- frontend/src/views/Dashboard.vue.js | 207 ++++++++- frontend/src/views/KbDetail.vue | 164 +++++++- frontend/src/views/KbDetail.vue.js | 488 +++++++++++++++++++++- frontend/src/views/KnowledgeBases.vue | 118 +++++- frontend/src/views/KnowledgeBases.vue.js | 419 ++++++++++++++++++- frontend/src/views/Login.vue | 48 ++- frontend/src/views/Login.vue.js | 143 ++++++- frontend/src/views/Register.vue | 66 ++- frontend/src/views/Register.vue.js | 202 ++++++++- frontend/src/views/Settings.vue | 45 +- frontend/src/views/Settings.vue.js | 138 +++++- frontend/tsconfig.tsbuildinfo | 2 +- 23 files changed, 2496 insertions(+), 140 deletions(-) create mode 100644 frontend/src/layouts/DefaultLayout.vue create mode 100644 frontend/src/layouts/DefaultLayout.vue.js diff --git a/backend/app/public/routes.py b/backend/app/public/routes.py index d7c9d5f..28e81d5 100644 --- a/backend/app/public/routes.py +++ b/backend/app/public/routes.py @@ -163,9 +163,12 @@ def kb_index_html( doc_url = f"/k/{token}/doc/{decrypt_token(doc.doc_token_encrypted) if doc.doc_token_encrypted else ''}" keywords_html = f'关键词:{doc.keywords}' if doc.keywords else "" summary_html = f'

{doc.content_summary or ""}

' if doc.content_summary else "" + status_badge = "" + if doc.status != "READY": + status_badge = f' [{doc.status}]' doc_rows += f"""
-

{doc.title or doc.original_filename}

+

{doc.title or doc.original_filename}{status_badge}

类型:{doc.file_ext} | 更新:{doc.updated_at}

{summary_html} {keywords_html} @@ -195,6 +198,7 @@ def kb_index_html( .summary {{ color: #444; font-size: 0.95em; margin: 5px 0; }} .keywords {{ color: #888; font-size: 0.85em; }} .pagination {{ color: #666; font-size: 0.9em; text-align: center; }} + .status-badge {{ color: #e67e22; font-size: 0.8em; font-weight: normal; }} .footer {{ margin-top: 30px; padding-top: 15px; border-top: 1px solid #eee; color: #999; font-size: 0.85em; }} diff --git a/backend/app/services/kb_public_service.py b/backend/app/services/kb_public_service.py index 90b2766..1dd3a6c 100644 --- a/backend/app/services/kb_public_service.py +++ b/backend/app/services/kb_public_service.py @@ -29,9 +29,9 @@ class KbPublicService: def list_documents( self, kb: KnowledgeBase, *, page: int = 1, page_size: int = 50 ) -> tuple[list[Document], int]: - """获取知识库的文档列表(仅 READY 状态)。""" + """获取知识库的文档列表(排除 DELETED)。""" return self._doc_repo.list_by_knowledge_base( - kb.id, page=page, page_size=page_size, status="READY" + kb.id, page=page, page_size=page_size ) def get_document_by_token(self, kb: KnowledgeBase, doc_token: str) -> Document: diff --git a/backend/requirements.txt b/backend/requirements.txt index 0a6ee10..b837129 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -20,8 +20,8 @@ python-multipart>=0.0.7 # --- 文档解析 --- # MIME 嗅探:纯 Python,Windows 无需 libmagic DLL filetype>=1.2 -# MarkItDown(MIT) -markitdown>=0.1.0 +# MarkItDown(MIT)—— 含 docx/pdf 支持 +markitdown[docx,pdf]>=0.1.0 # PDF fallback: PyMuPDF(AGPL-3.0) # TODO: 商品化前替换为 pypdfium2(Apache-2.0/BSD),见 docs/technical-review.md R3 PyMuPDF>=1.24.0 diff --git a/docs/requirements.md b/docs/requirements.md index 33b4215..47af7e1 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -23,7 +23,7 @@ | 11 | Markdown/TXT/JSON 输出 | ✅ 完成 | | 12 | 搜索 | ✅ 完成(LIKE 搜索,可升级 FTS5) | | 13 | 安全 | 🔄 已实现:IDOR 防护、限流、XSS 防护、路径穿越防护、Session 安全 | -| 14 | 前端完善 | ⬜ | +| 14 | 前端完善 | ✅ 完成 | | 15 | 测试 | 🔄 后端 51/51 通过;前端测试待 Phase 14 | | 16 | Docker | 🔄 compose/Dockerfile 已写(Phase 1),待 Docker 环境验证 | | 17 | Ubuntu 部署文档 | ⬜ | diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 618465c..e37d6d7 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "dependencies": { "@element-plus/icons-vue": "^2.3", - "axios": "^1.7", + "axios": "^1.7.9", "element-plus": "^2.9", "pinia": "^2.2", "vue": "^3.5", @@ -1809,18 +1809,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/ajv": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", @@ -1881,15 +1869,14 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", - "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.16.0", - "form-data": "^4.0.6", - "https-proxy-agent": "^5.0.1", - "proxy-from-env": "^2.1.0" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/balanced-match": { @@ -2052,6 +2039,7 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2784,19 +2772,6 @@ "he": "bin/he" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/ignore": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz", @@ -3043,6 +3018,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, "node_modules/muggle-string": { @@ -3296,13 +3272,10 @@ } }, "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" }, "node_modules/punycode": { "version": "2.3.1", diff --git a/frontend/package.json b/frontend/package.json index 02c8f13..78a75c7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,23 +11,23 @@ "format": "prettier --write src/" }, "dependencies": { - "vue": "^3.5", - "vue-router": "^4.4", - "pinia": "^2.2", + "@element-plus/icons-vue": "^2.3", + "axios": "^1.7.9", "element-plus": "^2.9", - "axios": "^1.7", - "@element-plus/icons-vue": "^2.3" + "pinia": "^2.2", + "vue": "^3.5", + "vue-router": "^4.4" }, "devDependencies": { - "@vitejs/plugin-vue": "^5.2", - "vite": "^6.1", - "typescript": "^5.7", - "vue-tsc": "^2.2", "@types/node": "^22.0", - "eslint": "^9.0", - "eslint-plugin-vue": "^9.28", "@typescript-eslint/eslint-plugin": "^8.0", "@typescript-eslint/parser": "^8.0", - "prettier": "^3.4" + "@vitejs/plugin-vue": "^5.2", + "eslint": "^9.0", + "eslint-plugin-vue": "^9.28", + "prettier": "^3.4", + "typescript": "^5.7", + "vite": "^6.1", + "vue-tsc": "^2.2" } -} \ No newline at end of file +} diff --git a/frontend/src/layouts/DefaultLayout.vue b/frontend/src/layouts/DefaultLayout.vue new file mode 100644 index 0000000..479f5da --- /dev/null +++ b/frontend/src/layouts/DefaultLayout.vue @@ -0,0 +1,71 @@ + + + diff --git a/frontend/src/layouts/DefaultLayout.vue.js b/frontend/src/layouts/DefaultLayout.vue.js new file mode 100644 index 0000000..49ef2b8 --- /dev/null +++ b/frontend/src/layouts/DefaultLayout.vue.js @@ -0,0 +1,263 @@ +import { ref, onMounted } from 'vue'; +import { useRouter } from 'vue-router'; +import { useUserStore } from '@/stores/user'; +import apiClient from '@/api/client'; +const router = useRouter(); +const userStore = useUserStore(); +const isCollapsed = ref(false); +onMounted(async () => { + try { + const { data } = await apiClient.get('/auth/me'); + userStore.setUser(data); + } + catch { + // 未登录,跳转登录页 + if (router.currentRoute.value.path !== '/login' && router.currentRoute.value.path !== '/register') { + router.push('/login'); + } + } +}); +async function handleLogout() { + try { + await apiClient.post('/auth/logout'); + } + catch { /* ignore */ } + userStore.clearUser(); + router.push('/login'); +} +debugger; /* PartiallyEnd: #3632/scriptSetup.vue */ +const __VLS_ctx = {}; +let __VLS_components; +let __VLS_directives; +const __VLS_0 = {}.ElContainer; +/** @type {[typeof __VLS_components.ElContainer, typeof __VLS_components.elContainer, typeof __VLS_components.ElContainer, typeof __VLS_components.elContainer, ]} */ ; +// @ts-ignore +const __VLS_1 = __VLS_asFunctionalComponent(__VLS_0, new __VLS_0({ + ...{ style: {} }, +})); +const __VLS_2 = __VLS_1({ + ...{ style: {} }, +}, ...__VLS_functionalComponentArgsRest(__VLS_1)); +var __VLS_4 = {}; +__VLS_3.slots.default; +const __VLS_5 = {}.ElAside; +/** @type {[typeof __VLS_components.ElAside, typeof __VLS_components.elAside, typeof __VLS_components.ElAside, typeof __VLS_components.elAside, ]} */ ; +// @ts-ignore +const __VLS_6 = __VLS_asFunctionalComponent(__VLS_5, new __VLS_5({ + width: (__VLS_ctx.isCollapsed ? '64px' : '220px'), + ...{ style: {} }, +})); +const __VLS_7 = __VLS_6({ + width: (__VLS_ctx.isCollapsed ? '64px' : '220px'), + ...{ style: {} }, +}, ...__VLS_functionalComponentArgsRest(__VLS_6)); +__VLS_8.slots.default; +__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ + ...{ style: {} }, +}); +if (!__VLS_ctx.isCollapsed) { + __VLS_asFunctionalElement(__VLS_intrinsicElements.span, __VLS_intrinsicElements.span)({}); +} +else { + __VLS_asFunctionalElement(__VLS_intrinsicElements.span, __VLS_intrinsicElements.span)({}); +} +const __VLS_9 = {}.ElMenu; +/** @type {[typeof __VLS_components.ElMenu, typeof __VLS_components.elMenu, typeof __VLS_components.ElMenu, typeof __VLS_components.elMenu, ]} */ ; +// @ts-ignore +const __VLS_10 = __VLS_asFunctionalComponent(__VLS_9, new __VLS_9({ + defaultActive: (__VLS_ctx.router.currentRoute.value.path), + collapse: (__VLS_ctx.isCollapsed), + router: true, +})); +const __VLS_11 = __VLS_10({ + defaultActive: (__VLS_ctx.router.currentRoute.value.path), + collapse: (__VLS_ctx.isCollapsed), + router: true, +}, ...__VLS_functionalComponentArgsRest(__VLS_10)); +__VLS_12.slots.default; +const __VLS_13 = {}.ElMenuItem; +/** @type {[typeof __VLS_components.ElMenuItem, typeof __VLS_components.elMenuItem, typeof __VLS_components.ElMenuItem, typeof __VLS_components.elMenuItem, ]} */ ; +// @ts-ignore +const __VLS_14 = __VLS_asFunctionalComponent(__VLS_13, new __VLS_13({ + index: "/", +})); +const __VLS_15 = __VLS_14({ + index: "/", +}, ...__VLS_functionalComponentArgsRest(__VLS_14)); +__VLS_16.slots.default; +const __VLS_17 = {}.ElIcon; +/** @type {[typeof __VLS_components.ElIcon, typeof __VLS_components.elIcon, typeof __VLS_components.ElIcon, typeof __VLS_components.elIcon, ]} */ ; +// @ts-ignore +const __VLS_18 = __VLS_asFunctionalComponent(__VLS_17, new __VLS_17({})); +const __VLS_19 = __VLS_18({}, ...__VLS_functionalComponentArgsRest(__VLS_18)); +__VLS_20.slots.default; +__VLS_asFunctionalElement(__VLS_intrinsicElements.svg, __VLS_intrinsicElements.svg)({ + viewBox: "0 0 24 24", + fill: "currentColor", +}); +__VLS_asFunctionalElement(__VLS_intrinsicElements.path)({ + d: "M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z", +}); +var __VLS_20; +{ + const { title: __VLS_thisSlot } = __VLS_16.slots; +} +var __VLS_16; +const __VLS_21 = {}.ElMenuItem; +/** @type {[typeof __VLS_components.ElMenuItem, typeof __VLS_components.elMenuItem, typeof __VLS_components.ElMenuItem, typeof __VLS_components.elMenuItem, ]} */ ; +// @ts-ignore +const __VLS_22 = __VLS_asFunctionalComponent(__VLS_21, new __VLS_21({ + index: "/knowledge-bases", +})); +const __VLS_23 = __VLS_22({ + index: "/knowledge-bases", +}, ...__VLS_functionalComponentArgsRest(__VLS_22)); +__VLS_24.slots.default; +const __VLS_25 = {}.ElIcon; +/** @type {[typeof __VLS_components.ElIcon, typeof __VLS_components.elIcon, typeof __VLS_components.ElIcon, typeof __VLS_components.elIcon, ]} */ ; +// @ts-ignore +const __VLS_26 = __VLS_asFunctionalComponent(__VLS_25, new __VLS_25({})); +const __VLS_27 = __VLS_26({}, ...__VLS_functionalComponentArgsRest(__VLS_26)); +__VLS_28.slots.default; +__VLS_asFunctionalElement(__VLS_intrinsicElements.svg, __VLS_intrinsicElements.svg)({ + viewBox: "0 0 24 24", + fill: "currentColor", +}); +__VLS_asFunctionalElement(__VLS_intrinsicElements.path)({ + d: "M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm16-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-1 9H9V9h10v2zm-4 4H9v-2h6v2zm4-8H9V5h10v2z", +}); +var __VLS_28; +{ + const { title: __VLS_thisSlot } = __VLS_24.slots; +} +var __VLS_24; +const __VLS_29 = {}.ElMenuItem; +/** @type {[typeof __VLS_components.ElMenuItem, typeof __VLS_components.elMenuItem, typeof __VLS_components.ElMenuItem, typeof __VLS_components.elMenuItem, ]} */ ; +// @ts-ignore +const __VLS_30 = __VLS_asFunctionalComponent(__VLS_29, new __VLS_29({ + index: "/settings", +})); +const __VLS_31 = __VLS_30({ + index: "/settings", +}, ...__VLS_functionalComponentArgsRest(__VLS_30)); +__VLS_32.slots.default; +const __VLS_33 = {}.ElIcon; +/** @type {[typeof __VLS_components.ElIcon, typeof __VLS_components.elIcon, typeof __VLS_components.ElIcon, typeof __VLS_components.elIcon, ]} */ ; +// @ts-ignore +const __VLS_34 = __VLS_asFunctionalComponent(__VLS_33, new __VLS_33({})); +const __VLS_35 = __VLS_34({}, ...__VLS_functionalComponentArgsRest(__VLS_34)); +__VLS_36.slots.default; +__VLS_asFunctionalElement(__VLS_intrinsicElements.svg, __VLS_intrinsicElements.svg)({ + viewBox: "0 0 24 24", + fill: "currentColor", +}); +__VLS_asFunctionalElement(__VLS_intrinsicElements.path)({ + d: "M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.07.62-.07.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z", +}); +var __VLS_36; +{ + const { title: __VLS_thisSlot } = __VLS_32.slots; +} +var __VLS_32; +var __VLS_12; +var __VLS_8; +const __VLS_37 = {}.ElContainer; +/** @type {[typeof __VLS_components.ElContainer, typeof __VLS_components.elContainer, typeof __VLS_components.ElContainer, typeof __VLS_components.elContainer, ]} */ ; +// @ts-ignore +const __VLS_38 = __VLS_asFunctionalComponent(__VLS_37, new __VLS_37({})); +const __VLS_39 = __VLS_38({}, ...__VLS_functionalComponentArgsRest(__VLS_38)); +__VLS_40.slots.default; +const __VLS_41 = {}.ElHeader; +/** @type {[typeof __VLS_components.ElHeader, typeof __VLS_components.elHeader, typeof __VLS_components.ElHeader, typeof __VLS_components.elHeader, ]} */ ; +// @ts-ignore +const __VLS_42 = __VLS_asFunctionalComponent(__VLS_41, new __VLS_41({ + ...{ style: {} }, +})); +const __VLS_43 = __VLS_42({ + ...{ style: {} }, +}, ...__VLS_functionalComponentArgsRest(__VLS_42)); +__VLS_44.slots.default; +const __VLS_45 = {}.ElButton; +/** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ; +// @ts-ignore +const __VLS_46 = __VLS_asFunctionalComponent(__VLS_45, new __VLS_45({ + ...{ 'onClick': {} }, + icon: (__VLS_ctx.isCollapsed ? 'Expand' : 'Fold'), + text: true, +})); +const __VLS_47 = __VLS_46({ + ...{ 'onClick': {} }, + icon: (__VLS_ctx.isCollapsed ? 'Expand' : 'Fold'), + text: true, +}, ...__VLS_functionalComponentArgsRest(__VLS_46)); +let __VLS_49; +let __VLS_50; +let __VLS_51; +const __VLS_52 = { + onClick: (...[$event]) => { + __VLS_ctx.isCollapsed = !__VLS_ctx.isCollapsed; + } +}; +var __VLS_48; +__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ + ...{ style: {} }, +}); +__VLS_asFunctionalElement(__VLS_intrinsicElements.span, __VLS_intrinsicElements.span)({}); +(__VLS_ctx.userStore.username); +const __VLS_53 = {}.ElButton; +/** @type {[typeof __VLS_components.ElButton, typeof __VLS_components.elButton, typeof __VLS_components.ElButton, typeof __VLS_components.elButton, ]} */ ; +// @ts-ignore +const __VLS_54 = __VLS_asFunctionalComponent(__VLS_53, new __VLS_53({ + ...{ 'onClick': {} }, + type: "danger", + text: true, +})); +const __VLS_55 = __VLS_54({ + ...{ 'onClick': {} }, + type: "danger", + text: true, +}, ...__VLS_functionalComponentArgsRest(__VLS_54)); +let __VLS_57; +let __VLS_58; +let __VLS_59; +const __VLS_60 = { + onClick: (__VLS_ctx.handleLogout) +}; +__VLS_56.slots.default; +var __VLS_56; +var __VLS_44; +const __VLS_61 = {}.ElMain; +/** @type {[typeof __VLS_components.ElMain, typeof __VLS_components.elMain, typeof __VLS_components.ElMain, typeof __VLS_components.elMain, ]} */ ; +// @ts-ignore +const __VLS_62 = __VLS_asFunctionalComponent(__VLS_61, new __VLS_61({ + ...{ style: {} }, +})); +const __VLS_63 = __VLS_62({ + ...{ style: {} }, +}, ...__VLS_functionalComponentArgsRest(__VLS_62)); +__VLS_64.slots.default; +const __VLS_65 = {}.RouterView; +/** @type {[typeof __VLS_components.RouterView, typeof __VLS_components.routerView, ]} */ ; +// @ts-ignore +const __VLS_66 = __VLS_asFunctionalComponent(__VLS_65, new __VLS_65({})); +const __VLS_67 = __VLS_66({}, ...__VLS_functionalComponentArgsRest(__VLS_66)); +var __VLS_64; +var __VLS_40; +var __VLS_3; +var __VLS_dollars; +const __VLS_self = (await import('vue')).defineComponent({ + setup() { + return { + router: router, + userStore: userStore, + isCollapsed: isCollapsed, + handleLogout: handleLogout, + }; + }, +}); +export default (await import('vue')).defineComponent({ + setup() { + return {}; + }, +}); +; /* PartiallyEnd: #4569/main.vue */ diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index 7466b3d..9719bf1 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -14,23 +14,29 @@ const router = createRouter({ }, { path: '/', - name: 'Dashboard', - component: () => import('@/views/Dashboard.vue'), - }, - { - path: '/knowledge-bases', - name: 'KnowledgeBases', - component: () => import('@/views/KnowledgeBases.vue'), - }, - { - path: '/knowledge-bases/:id', - name: 'KbDetail', - component: () => import('@/views/KbDetail.vue'), - }, - { - path: '/settings', - name: 'Settings', - component: () => import('@/views/Settings.vue'), + component: () => import('@/layouts/DefaultLayout.vue'), + children: [ + { + path: '', + name: 'Dashboard', + component: () => import('@/views/Dashboard.vue'), + }, + { + path: 'knowledge-bases', + name: 'KnowledgeBases', + component: () => import('@/views/KnowledgeBases.vue'), + }, + { + path: 'knowledge-bases/:id', + name: 'KbDetail', + component: () => import('@/views/KbDetail.vue'), + }, + { + path: 'settings', + name: 'Settings', + component: () => import('@/views/Settings.vue'), + }, + ], }, ], }); diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index fb9fef2..37c8b92 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -15,25 +15,31 @@ const router = createRouter({ }, { path: '/', - name: 'Dashboard', - component: () => import('@/views/Dashboard.vue'), - }, - { - path: '/knowledge-bases', - name: 'KnowledgeBases', - component: () => import('@/views/KnowledgeBases.vue'), - }, - { - path: '/knowledge-bases/:id', - name: 'KbDetail', - component: () => import('@/views/KbDetail.vue'), - }, - { - path: '/settings', - name: 'Settings', - component: () => import('@/views/Settings.vue'), + component: () => import('@/layouts/DefaultLayout.vue'), + children: [ + { + path: '', + name: 'Dashboard', + component: () => import('@/views/Dashboard.vue'), + }, + { + path: 'knowledge-bases', + name: 'KnowledgeBases', + component: () => import('@/views/KnowledgeBases.vue'), + }, + { + path: 'knowledge-bases/:id', + name: 'KbDetail', + component: () => import('@/views/KbDetail.vue'), + }, + { + path: 'settings', + name: 'Settings', + component: () => import('@/views/Settings.vue'), + }, + ], }, ], }) -export default router \ No newline at end of file +export default router diff --git a/frontend/src/views/Dashboard.vue b/frontend/src/views/Dashboard.vue index c5818c3..886e81a 100644 --- a/frontend/src/views/Dashboard.vue +++ b/frontend/src/views/Dashboard.vue @@ -1,10 +1,87 @@ \ No newline at end of file + + + diff --git a/frontend/src/views/Dashboard.vue.js b/frontend/src/views/Dashboard.vue.js index e30bddd..d0d8f1c 100644 --- a/frontend/src/views/Dashboard.vue.js +++ b/frontend/src/views/Dashboard.vue.js @@ -1,17 +1,212 @@ +import { ref, onMounted } from 'vue'; +import apiClient from '@/api/client'; +const stats = ref({ + kb_count: 0, + doc_count: 0, + storage_used_mb: 0, + storage_quota_mb: 100, +}); +onMounted(async () => { + try { + const [kbRes, storageRes] = await Promise.all([ + apiClient.get('/knowledge-bases'), + apiClient.get('/auth/storage'), + ]); + stats.value.kb_count = kbRes.data.total; + stats.value.storage_used_mb = storageRes.data.storage_used_mb; + stats.value.storage_quota_mb = storageRes.data.storage_quota_mb; + } + catch { /* ignore */ } +}); debugger; /* PartiallyEnd: #3632/scriptSetup.vue */ const __VLS_ctx = {}; let __VLS_components; let __VLS_directives; -__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ - ...{ class: "dashboard-page" }, -}); +// CSS variable injection +// CSS variable injection end +__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({}); __VLS_asFunctionalElement(__VLS_intrinsicElements.h1, __VLS_intrinsicElements.h1)({}); -__VLS_asFunctionalElement(__VLS_intrinsicElements.p, __VLS_intrinsicElements.p)({}); -/** @type {__VLS_StyleScopedClasses['dashboard-page']} */ ; +const __VLS_0 = {}.ElRow; +/** @type {[typeof __VLS_components.ElRow, typeof __VLS_components.elRow, typeof __VLS_components.ElRow, typeof __VLS_components.elRow, ]} */ ; +// @ts-ignore +const __VLS_1 = __VLS_asFunctionalComponent(__VLS_0, new __VLS_0({ + gutter: (20), + ...{ style: {} }, +})); +const __VLS_2 = __VLS_1({ + gutter: (20), + ...{ style: {} }, +}, ...__VLS_functionalComponentArgsRest(__VLS_1)); +__VLS_3.slots.default; +const __VLS_4 = {}.ElCol; +/** @type {[typeof __VLS_components.ElCol, typeof __VLS_components.elCol, typeof __VLS_components.ElCol, typeof __VLS_components.elCol, ]} */ ; +// @ts-ignore +const __VLS_5 = __VLS_asFunctionalComponent(__VLS_4, new __VLS_4({ + span: (8), +})); +const __VLS_6 = __VLS_5({ + span: (8), +}, ...__VLS_functionalComponentArgsRest(__VLS_5)); +__VLS_7.slots.default; +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({})); +const __VLS_10 = __VLS_9({}, ...__VLS_functionalComponentArgsRest(__VLS_9)); +__VLS_11.slots.default; +__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ + ...{ class: "stat-item" }, +}); +__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ + ...{ class: "stat-value" }, +}); +(__VLS_ctx.stats.kb_count); +__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ + ...{ class: "stat-label" }, +}); +var __VLS_11; +var __VLS_7; +const __VLS_12 = {}.ElCol; +/** @type {[typeof __VLS_components.ElCol, typeof __VLS_components.elCol, typeof __VLS_components.ElCol, typeof __VLS_components.elCol, ]} */ ; +// @ts-ignore +const __VLS_13 = __VLS_asFunctionalComponent(__VLS_12, new __VLS_12({ + span: (8), +})); +const __VLS_14 = __VLS_13({ + span: (8), +}, ...__VLS_functionalComponentArgsRest(__VLS_13)); +__VLS_15.slots.default; +const __VLS_16 = {}.ElCard; +/** @type {[typeof __VLS_components.ElCard, typeof __VLS_components.elCard, typeof __VLS_components.ElCard, typeof __VLS_components.elCard, ]} */ ; +// @ts-ignore +const __VLS_17 = __VLS_asFunctionalComponent(__VLS_16, new __VLS_16({})); +const __VLS_18 = __VLS_17({}, ...__VLS_functionalComponentArgsRest(__VLS_17)); +__VLS_19.slots.default; +__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ + ...{ class: "stat-item" }, +}); +__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ + ...{ class: "stat-value" }, +}); +(__VLS_ctx.stats.storage_used_mb); +__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ + ...{ class: "stat-label" }, +}); +(__VLS_ctx.stats.storage_quota_mb); +var __VLS_19; +var __VLS_15; +const __VLS_20 = {}.ElCol; +/** @type {[typeof __VLS_components.ElCol, typeof __VLS_components.elCol, typeof __VLS_components.ElCol, typeof __VLS_components.elCol, ]} */ ; +// @ts-ignore +const __VLS_21 = __VLS_asFunctionalComponent(__VLS_20, new __VLS_20({ + span: (8), +})); +const __VLS_22 = __VLS_21({ + span: (8), +}, ...__VLS_functionalComponentArgsRest(__VLS_21)); +__VLS_23.slots.default; +const __VLS_24 = {}.ElCard; +/** @type {[typeof __VLS_components.ElCard, typeof __VLS_components.elCard, typeof __VLS_components.ElCard, typeof __VLS_components.elCard, ]} */ ; +// @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; +__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ + ...{ class: "stat-item" }, +}); +const __VLS_28 = {}.ElProgress; +/** @type {[typeof __VLS_components.ElProgress, typeof __VLS_components.elProgress, ]} */ ; +// @ts-ignore +const __VLS_29 = __VLS_asFunctionalComponent(__VLS_28, new __VLS_28({ + percentage: (Math.min(100, Math.round(__VLS_ctx.stats.storage_used_mb / __VLS_ctx.stats.storage_quota_mb * 100))), + strokeWidth: (20), + textInside: (true), +})); +const __VLS_30 = __VLS_29({ + percentage: (Math.min(100, Math.round(__VLS_ctx.stats.storage_used_mb / __VLS_ctx.stats.storage_quota_mb * 100))), + strokeWidth: (20), + textInside: (true), +}, ...__VLS_functionalComponentArgsRest(__VLS_29)); +__VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ + ...{ class: "stat-label" }, +}); +var __VLS_27; +var __VLS_23; +var __VLS_3; +const __VLS_32 = {}.ElCard; +/** @type {[typeof __VLS_components.ElCard, typeof __VLS_components.elCard, typeof __VLS_components.ElCard, typeof __VLS_components.elCard, ]} */ ; +// @ts-ignore +const __VLS_33 = __VLS_asFunctionalComponent(__VLS_32, new __VLS_32({})); +const __VLS_34 = __VLS_33({}, ...__VLS_functionalComponentArgsRest(__VLS_33)); +__VLS_35.slots.default; +{ + const { header: __VLS_thisSlot } = __VLS_35.slots; + __VLS_asFunctionalElement(__VLS_intrinsicElements.div, __VLS_intrinsicElements.div)({ + ...{ style: {} }, + }); + __VLS_asFunctionalElement(__VLS_intrinsicElements.span, __VLS_intrinsicElements.span)({}); +} +const __VLS_36 = {}.ElSteps; +/** @type {[typeof __VLS_components.ElSteps, typeof __VLS_components.elSteps, typeof __VLS_components.ElSteps, typeof __VLS_components.elSteps, ]} */ ; +// @ts-ignore +const __VLS_37 = __VLS_asFunctionalComponent(__VLS_36, new __VLS_36({ + active: (0), + direction: "vertical", +})); +const __VLS_38 = __VLS_37({ + active: (0), + direction: "vertical", +}, ...__VLS_functionalComponentArgsRest(__VLS_37)); +__VLS_39.slots.default; +const __VLS_40 = {}.ElStep; +/** @type {[typeof __VLS_components.ElStep, typeof __VLS_components.elStep, ]} */ ; +// @ts-ignore +const __VLS_41 = __VLS_asFunctionalComponent(__VLS_40, new __VLS_40({ + title: "创建知识库", + description: "点击左侧「知识库」菜单,创建你的第一个知识库", +})); +const __VLS_42 = __VLS_41({ + title: "创建知识库", + description: "点击左侧「知识库」菜单,创建你的第一个知识库", +}, ...__VLS_functionalComponentArgsRest(__VLS_41)); +const __VLS_44 = {}.ElStep; +/** @type {[typeof __VLS_components.ElStep, typeof __VLS_components.elStep, ]} */ ; +// @ts-ignore +const __VLS_45 = __VLS_asFunctionalComponent(__VLS_44, new __VLS_44({ + title: "上传文档", + description: "支持 .docx 和 .pdf 文件", +})); +const __VLS_46 = __VLS_45({ + title: "上传文档", + description: "支持 .docx 和 .pdf 文件", +}, ...__VLS_functionalComponentArgsRest(__VLS_45)); +const __VLS_48 = {}.ElStep; +/** @type {[typeof __VLS_components.ElStep, typeof __VLS_components.elStep, ]} */ ; +// @ts-ignore +const __VLS_49 = __VLS_asFunctionalComponent(__VLS_48, new __VLS_48({ + title: "分享 AI 链接", + description: "复制知识库的 AI 专属链接,发送给任意 AI", +})); +const __VLS_50 = __VLS_49({ + title: "分享 AI 链接", + description: "复制知识库的 AI 专属链接,发送给任意 AI", +}, ...__VLS_functionalComponentArgsRest(__VLS_49)); +var __VLS_39; +var __VLS_35; +/** @type {__VLS_StyleScopedClasses['stat-item']} */ ; +/** @type {__VLS_StyleScopedClasses['stat-value']} */ ; +/** @type {__VLS_StyleScopedClasses['stat-label']} */ ; +/** @type {__VLS_StyleScopedClasses['stat-item']} */ ; +/** @type {__VLS_StyleScopedClasses['stat-value']} */ ; +/** @type {__VLS_StyleScopedClasses['stat-label']} */ ; +/** @type {__VLS_StyleScopedClasses['stat-item']} */ ; +/** @type {__VLS_StyleScopedClasses['stat-label']} */ ; var __VLS_dollars; const __VLS_self = (await import('vue')).defineComponent({ setup() { - return {}; + return { + stats: stats, + }; }, }); export default (await import('vue')).defineComponent({ diff --git a/frontend/src/views/KbDetail.vue b/frontend/src/views/KbDetail.vue index 868d1ef..0544000 100644 --- a/frontend/src/views/KbDetail.vue +++ b/frontend/src/views/KbDetail.vue @@ -1,10 +1,164 @@ \ 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 @@ \ 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 @@ @@ -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 @@ @@ -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 @@ \ 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