This commit is contained in:
amb
2026-09-01 13:57:34 +08:00
parent dfd38c99a0
commit 4db2d1a411
23 changed files with 2496 additions and 140 deletions
+81 -4
View File
@@ -1,10 +1,87 @@
<script setup lang="ts">
// Phase 14 完善仪表盘
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 */ }
})
</script>
<template>
<div class="dashboard-page">
<div>
<h1>仪表盘</h1>
<p>DashboardPhase 14 完善</p>
<el-row :gutter="20" style="margin-bottom: 20px">
<el-col :span="8">
<el-card>
<div class="stat-item">
<div class="stat-value">{{ stats.kb_count }}</div>
<div class="stat-label">知识库</div>
</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card>
<div class="stat-item">
<div class="stat-value">{{ stats.storage_used_mb }} MB</div>
<div class="stat-label">已用空间 / {{ stats.storage_quota_mb }} MB</div>
</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card>
<div class="stat-item">
<el-progress
:percentage="Math.min(100, Math.round(stats.storage_used_mb / stats.storage_quota_mb * 100))"
:stroke-width="20"
:text-inside="true"
/>
<div class="stat-label">存储用量</div>
</div>
</el-card>
</el-col>
</el-row>
<el-card>
<template #header>
<div style="display: flex; justify-content: space-between; align-items: center">
<span>快速开始</span>
</div>
</template>
<el-steps :active="0" direction="vertical">
<el-step title="创建知识库" description="点击左侧「知识库」菜单,创建你的第一个知识库" />
<el-step title="上传文档" description="支持 .docx 和 .pdf 文件" />
<el-step title="分享 AI 链接" description="复制知识库的 AI 专属链接,发送给任意 AI" />
</el-steps>
</el-card>
</div>
</template>
</template>
<style scoped>
.stat-item {
text-align: center;
padding: 10px 0;
}
.stat-value {
font-size: 28px;
font-weight: bold;
color: #409eff;
}
.stat-label {
color: #999;
margin-top: 8px;
}
</style>
+201 -6
View File
@@ -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({
+159 -5
View File
@@ -1,10 +1,164 @@
<script setup lang="ts">
// Phase 4 实现知识库详情
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 as string
const kb = ref<any>(null)
const docs = ref<any[]>([])
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: any) {
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: any) {
try {
await ElMessageBox.confirm(`确定删除文档「${doc.original_filename}」?`, '确认删除', { type: 'warning' })
await apiClient.delete(`/documents/${doc.id}`)
ElMessage.success('已删除。')
loadDocs()
} catch { /* ignore */ }
}
async function handleReprocess(doc: any) {
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: number) {
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: string) {
if (status === 'READY') return 'success'
if (status === 'FAILED') return 'danger'
return 'warning'
}
</script>
<template>
<div>
<h1>知识库详情</h1>
<p>知识库详情Phase 4 实现</p>
<div v-if="kb">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px">
<h1 style="margin: 0">{{ kb.name }}</h1>
<el-button type="primary" @click="handleCopyLink">复制 AI 链接</el-button>
</div>
<el-card style="margin-bottom: 20px">
<el-descriptions :column="2" border>
<el-descriptions-item label="描述">{{ kb.description || '无' }}</el-descriptions-item>
<el-descriptions-item label="状态">
<el-tag :type="kb.enabled ? 'success' : 'danger'">{{ kb.enabled ? '启用' : '禁用' }}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="AI 链接">
<div style="display: flex; align-items: center; gap: 8px">
<el-input :model-value="aiUrl" readonly size="small" style="flex: 1" />
<el-button size="small" @click="handleRegenerate">重新生成</el-button>
</div>
</el-descriptions-item>
<el-descriptions-item label="文档数">{{ docs.length }}</el-descriptions-item>
</el-descriptions>
</el-card>
<el-card>
<template #header>
<div style="display: flex; justify-content: space-between; align-items: center">
<span>文档列表</span>
<el-upload
:show-file-list="false"
:http-request="handleUpload"
accept=".docx,.pdf"
>
<el-button type="primary" :loading="uploading">上传文档</el-button>
</el-upload>
</div>
</template>
<el-table :data="docs" v-loading="loading" style="width: 100%">
<el-table-column prop="original_filename" label="文件名" min-width="200" show-overflow-tooltip />
<el-table-column label="状态" width="120" align="center">
<template #default="{ row }">
<el-tag :type="statusType(row.status)" size="small">{{ row.status }}</el-tag>
</template>
</el-table-column>
<el-table-column label="大小" width="100" align="center">
<template #default="{ row }">{{ formatSize(row.file_size) }}</template>
</el-table-column>
<el-table-column prop="title" label="标题" min-width="150" show-overflow-tooltip />
<el-table-column prop="keywords" label="关键词" min-width="150" show-overflow-tooltip />
<el-table-column label="操作" width="200" align="center">
<template #default="{ row }">
<el-button size="small" @click="handleReprocess(row)">重新解析</el-button>
<el-button size="small" type="danger" @click="handleDeleteDoc(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
</template>
+484 -4
View File
@@ -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({
+114 -4
View File
@@ -1,10 +1,120 @@
<script setup lang="ts">
// Phase 4 实现知识库列表
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<any[]>([])
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: any) {
try {
await ElMessageBox.confirm(`确定删除知识库「${kb.name}」?`, '确认删除', { type: 'warning' })
await apiClient.delete(`/knowledge-bases/${kb.id}`)
ElMessage.success('已删除。')
loadKbs()
} catch { /* ignore */ }
}
async function handleToggle(kb: any) {
const action = kb.enabled ? 'disable' : 'enable'
await apiClient.post(`/knowledge-bases/${kb.id}/${action}`)
ElMessage.success(kb.enabled ? '已禁用。' : '已启用。')
loadKbs()
}
async function handleCopyLink(kb: any) {
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 */ }
}
</script>
<template>
<div>
<h1>知识库</h1>
<p>知识库列表Phase 4 实现</p>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px">
<h1 style="margin: 0">知识库</h1>
<el-button type="primary" @click="showCreate = true">创建知识库</el-button>
</div>
<el-table :data="kbs" v-loading="loading" style="width: 100%">
<el-table-column prop="name" label="名称" min-width="200">
<template #default="{ row }">
<router-link :to="`/knowledge-bases/${row.id}`" style="color: #409eff; text-decoration: none">
{{ row.name }}
</router-link>
</template>
</el-table-column>
<el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip />
<el-table-column prop="document_count" label="文档数" width="100" align="center" />
<el-table-column label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.enabled ? 'success' : 'danger'" size="small">
{{ row.enabled ? '启用' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="300" align="center">
<template #default="{ row }">
<el-button size="small" @click="handleCopyLink(row)">复制链接</el-button>
<el-button size="small" @click="handleToggle(row)">
{{ row.enabled ? '禁用' : '启用' }}
</el-button>
<el-button size="small" type="danger" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 创建对话框 -->
<el-dialog v-model="showCreate" title="创建知识库" width="500px">
<el-form :model="createForm" label-position="top">
<el-form-item label="名称" required>
<el-input v-model="createForm.name" placeholder="例如:公司知识库" />
</el-form-item>
<el-form-item label="描述">
<el-input v-model="createForm.description" type="textarea" :rows="3" placeholder="可选描述" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="showCreate = false">取消</el-button>
<el-button type="primary" :loading="createLoading" @click="handleCreate">创建</el-button>
</template>
</el-dialog>
</div>
</template>
</template>
+416 -3
View File
@@ -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({
+44 -4
View File
@@ -1,14 +1,54 @@
<script setup lang="ts">
// Phase 3 实现登录逻辑
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
}
}
</script>
<template>
<div class="login-page">
<el-card class="login-card">
<template #header>
<h2>AI Knowledge Link</h2>
<h2 style="text-align: center; margin: 0">AI Knowledge Link</h2>
</template>
<p>登录页面Phase 3 实现</p>
<el-form :model="form" label-position="top" @submit.prevent="handleLogin">
<el-form-item label="用户名或邮箱">
<el-input v-model="form.username_or_email" placeholder="请输入用户名或邮箱" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password" type="password" placeholder="请输入密码" show-password />
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="loading" style="width: 100%" native-type="submit">
登录
</el-button>
</el-form-item>
</el-form>
<div style="text-align: center">
<router-link to="/register">没有账号立即注册</router-link>
</div>
</el-card>
</div>
</template>
@@ -24,4 +64,4 @@
.login-card {
width: 400px;
}
</style>
</style>
+140 -3
View File
@@ -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({
+62 -4
View File
@@ -1,14 +1,72 @@
<script setup lang="ts">
// Phase 3 实现注册逻辑
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'
</script>
<template>
<div class="register-page">
<el-card class="register-card">
<template #header>
<h2>注册</h2>
<h2 style="text-align: center; margin: 0">注册</h2>
</template>
<p>注册页面Phase 3 实现</p>
<el-form :model="form" label-position="top" @submit.prevent="handleRegister">
<el-form-item label="用户名">
<el-input v-model="form.username" placeholder="2-32 位字母、数字、下划线" />
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="form.email" placeholder="your@email.com" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password" type="password" placeholder="至少 8 位" show-password />
</el-form-item>
<el-form-item label="确认密码">
<el-input v-model="form.confirmPassword" type="password" placeholder="再次输入密码" show-password />
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="loading" style="width: 100%" native-type="submit">
注册
</el-button>
</el-form-item>
</el-form>
<div style="text-align: center">
<router-link to="/login">已有账号立即登录</router-link>
</div>
</el-card>
</div>
</template>
@@ -24,4 +82,4 @@
.register-card {
width: 400px;
}
</style>
</style>
+199 -3
View File
@@ -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({
+42 -3
View File
@@ -1,10 +1,49 @@
<script setup lang="ts">
// Phase 14 实现设置页
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
}
</script>
<template>
<div>
<h1>设置</h1>
<p>设置页面Phase 14 实现</p>
<el-card>
<template #header>修改密码</template>
<el-form :model="form" label-position="top" style="max-width: 400px">
<el-form-item label="新密码">
<el-input v-model="form.password" type="password" placeholder="至少 8 位" show-password />
</el-form-item>
<el-form-item label="确认新密码">
<el-input v-model="form.confirmPassword" type="password" placeholder="再次输入新密码" show-password />
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="loading" @click="handleChangePassword">修改密码</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
</template>
+136 -2
View File
@@ -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({