4
This commit is contained in:
@@ -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>Dashboard(Phase 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>
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user