feat: 更新多个组件和API,优化用户体验和错误处理
This commit is contained in:
parent
52f7abf50e
commit
20268d6400
@ -17,7 +17,6 @@
|
||||
- 系统层面添加 apikey,在智能体、知识库调用中支持 apikey 以支持外部调用
|
||||
- 支持更多类型的文档源的导入功能(支持后端配置的白名单的 URL 导入)
|
||||
- 部分场景应该使用默认模型作为默认值而不是空值
|
||||
- CommonRAG 添加更多检索类型,比如 BM25,关键词,grep 等
|
||||
- 文件上传解析后,如何提示用户需要入库
|
||||
- 检索测试中,添加问答
|
||||
- 丰富当前智能体的 Prompt,最好支持从 markdown 解析
|
||||
|
||||
@ -101,7 +101,7 @@ export async function apiRequest(url, options = {}, requiresAuth = true, respons
|
||||
} else if (response.status === 403) {
|
||||
throw new Error('没有权限执行此操作')
|
||||
} else if (response.status === 500) {
|
||||
throw new Error('Server 500 Error, please check the log use `docker logs api-dev`')
|
||||
throw new Error('服务器内部错误,请使用 docker logs api-dev 查看详细日志')
|
||||
}
|
||||
|
||||
throw new Error(errorMessage)
|
||||
|
||||
@ -1278,7 +1278,7 @@ watch(
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
flex-grow: 1;
|
||||
padding: 1rem;
|
||||
padding: 1rem 1.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<a-drawer :open="isOpen" :width="620" title="任务中心" placement="right" @close="handleClose">
|
||||
<p>提醒:任务执行成功,只代表任务已执行完成,但是任务内部可能有问题已捕获,请注意观察日志。</p>
|
||||
<div class="task-center">
|
||||
<div class="task-toolbar">
|
||||
<div class="task-filter-group">
|
||||
|
||||
@ -8,14 +8,15 @@ export const useInfoStore = defineStore('info', () => {
|
||||
const isLoading = ref(false)
|
||||
const isLoaded = ref(false)
|
||||
const debugMode = ref(false)
|
||||
const error = ref(null) // 错误信息
|
||||
|
||||
// 计算属性 - 组织信息
|
||||
const organization = computed(
|
||||
() =>
|
||||
infoConfig.value.organization || {
|
||||
name: '江南语析',
|
||||
logo: '/favicon.svg',
|
||||
avatar: '/avatar.jpg'
|
||||
name: '',
|
||||
logo: '',
|
||||
avatar: ''
|
||||
}
|
||||
)
|
||||
|
||||
@ -23,75 +24,22 @@ export const useInfoStore = defineStore('info', () => {
|
||||
const branding = computed(
|
||||
() =>
|
||||
infoConfig.value.branding || {
|
||||
name: 'Yuxi-Know',
|
||||
title: 'Yuxi-Know',
|
||||
subtitle: '大模型驱动的知识库管理工具',
|
||||
description: '结合知识库与知识图谱,提供更准确、更全面的回答'
|
||||
name: '',
|
||||
title: '',
|
||||
subtitle: ''
|
||||
}
|
||||
)
|
||||
|
||||
// 计算属性 - 功能特性
|
||||
const features = computed(
|
||||
() =>
|
||||
infoConfig.value.features || [
|
||||
{
|
||||
label: 'GitHub Stars',
|
||||
value: '3200+',
|
||||
description: '开发者社区的认可与支持',
|
||||
icon: 'stars'
|
||||
},
|
||||
{
|
||||
label: '已解决 Issues',
|
||||
value: '250+',
|
||||
description: '持续改进和问题解决能力',
|
||||
icon: 'issues'
|
||||
},
|
||||
{
|
||||
label: '累计 Commits',
|
||||
value: '1200+',
|
||||
description: '活跃的开发迭代和功能更新',
|
||||
icon: 'commits'
|
||||
},
|
||||
{
|
||||
label: '开源协议',
|
||||
value: 'MIT 协议',
|
||||
description: '完全免费,支持商业使用',
|
||||
icon: 'license'
|
||||
}
|
||||
]
|
||||
)
|
||||
const features = computed(() => infoConfig.value.features || [])
|
||||
|
||||
const actions = computed(
|
||||
() =>
|
||||
infoConfig.value.actions || [
|
||||
{
|
||||
name: '演示视频',
|
||||
icon: 'video',
|
||||
url: 'https://www.bilibili.com/video/BV1DF14BTETq'
|
||||
},
|
||||
{
|
||||
name: '文档中心',
|
||||
icon: 'docs',
|
||||
url: 'https://xerrors.github.io/Yuxi-Know/'
|
||||
},
|
||||
{
|
||||
name: '提交 Issue',
|
||||
icon: 'issue',
|
||||
url: 'https://github.com/xerrors/Yuxi-Know/issues/new/choose'
|
||||
},
|
||||
{
|
||||
name: '开发路线图',
|
||||
icon: 'roadmap',
|
||||
url: 'https://github.com/xerrors/Yuxi-Know#roadmap'
|
||||
}
|
||||
]
|
||||
)
|
||||
const actions = computed(() => infoConfig.value.actions || [])
|
||||
|
||||
// 计算属性 - 页脚信息
|
||||
const footer = computed(
|
||||
() =>
|
||||
infoConfig.value.footer || {
|
||||
copyright: '© 江南语析 2025 [WIP] v0.12.138'
|
||||
copyright: ''
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@ -630,7 +630,6 @@ const goToDatabasePage = () => {
|
||||
.db-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 20px;
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
@ -767,7 +766,7 @@ const goToDatabasePage = () => {
|
||||
}
|
||||
|
||||
:deep(.ant-input) {
|
||||
padding: 2px 10px;
|
||||
padding: 2px 0px;
|
||||
}
|
||||
|
||||
button {
|
||||
|
||||
@ -1,6 +1,27 @@
|
||||
<template>
|
||||
<div class="home-container">
|
||||
<div class="hero-section">
|
||||
<!-- 加载中状态 -->
|
||||
<div v-if="isLoading" class="loading-container">
|
||||
<a-spin size="large" />
|
||||
<p class="loading-text">正在连接服务...</p>
|
||||
</div>
|
||||
|
||||
<!-- 错误状态 -->
|
||||
<div v-else-if="error" class="error-container">
|
||||
<a-result
|
||||
status="error"
|
||||
:title="error.title"
|
||||
:sub-title="error.message"
|
||||
>
|
||||
<template #extra>
|
||||
<a-button type="primary" @click="retryLoad">重试</a-button>
|
||||
</template>
|
||||
</a-result>
|
||||
</div>
|
||||
|
||||
<!-- 正常内容 -->
|
||||
<template v-else>
|
||||
<div class="hero-section">
|
||||
<div class="glass-header">
|
||||
<div class="logo">
|
||||
<img
|
||||
@ -106,16 +127,19 @@
|
||||
<p class="copyright">{{ infoStore.footer?.copyright || '© 2025 All rights reserved' }}</p>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useInfoStore } from '@/stores/info'
|
||||
import { useAgentStore } from '@/stores/agent'
|
||||
import { useThemeStore } from '@/stores/theme'
|
||||
import { healthApi } from '@/apis/system_api'
|
||||
import { Result, Button } from 'ant-design-vue'
|
||||
import UserInfoComponent from '@/components/UserInfoComponent.vue'
|
||||
import ProjectOverview from '@/components/ProjectOverview.vue'
|
||||
import {
|
||||
@ -130,12 +154,54 @@ import {
|
||||
ShieldCheck
|
||||
} from 'lucide-vue-next'
|
||||
|
||||
const AResult = Result
|
||||
const AButton = Button
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
const infoStore = useInfoStore()
|
||||
const agentStore = useAgentStore()
|
||||
const themeStore = useThemeStore()
|
||||
|
||||
// 加载状态
|
||||
const isLoading = ref(true)
|
||||
const error = ref(null)
|
||||
|
||||
const checkHealth = async () => {
|
||||
try {
|
||||
const response = await healthApi.checkHealth()
|
||||
if (response.status !== 'ok') {
|
||||
throw new Error('服务不可用')
|
||||
}
|
||||
} catch (e) {
|
||||
error.value = {
|
||||
title: '服务连接失败',
|
||||
message: '后端服务无法响应,请检查服务是否正常运行'
|
||||
}
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
const loadData = async () => {
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
// 先检查健康状态
|
||||
await checkHealth()
|
||||
// 健康检查通过后加载配置
|
||||
await infoStore.loadInfoConfig()
|
||||
} catch (e) {
|
||||
console.error('加载失败:', e)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const retryLoad = () => {
|
||||
loadData()
|
||||
}
|
||||
|
||||
const goToChat = async () => {
|
||||
// 检查用户是否登录
|
||||
if (!userStore.isLoggedIn) {
|
||||
@ -167,9 +233,9 @@ const goToChat = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// 加载信息配置
|
||||
await infoStore.loadInfoConfig()
|
||||
onMounted(() => {
|
||||
// 加载数据
|
||||
loadData()
|
||||
})
|
||||
|
||||
const iconKey = (value) => (typeof value === 'string' ? value.toLowerCase() : '')
|
||||
@ -252,6 +318,30 @@ const actionLinks = computed(() => {
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
// 加载中状态
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
gap: 1rem;
|
||||
|
||||
.loading-text {
|
||||
color: var(--gray-600);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
}
|
||||
|
||||
// 错误状态
|
||||
.error-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
padding: 2rem;
|
||||
}
|
||||
.glass-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@ -18,7 +18,11 @@
|
||||
<nav class="login-navbar">
|
||||
<div class="navbar-content">
|
||||
<div class="brand-container">
|
||||
<h1 class="brand-text">{{ brandName }}</h1>
|
||||
<h1 class="brand-text">
|
||||
<span v-if="brandOrgName" class="brand-org">{{ brandOrgName }}</span>
|
||||
<span v-if="brandOrgName && brandName !== brandOrgName" class="brand-separator"></span>
|
||||
<span class="brand-main">{{ brandName }}</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="login-top-action">
|
||||
<a-button type="text" size="small" class="back-home-btn" @click="goHome">
|
||||
@ -255,12 +259,15 @@ const agentStore = useAgentStore()
|
||||
const loginBgImage = computed(() => {
|
||||
return infoStore.organization?.login_bg || '/login-bg.jpg'
|
||||
})
|
||||
const brandOrgName = computed(() => {
|
||||
return infoStore.organization?.name?.trim() || ''
|
||||
})
|
||||
const brandName = computed(() => {
|
||||
const orgName = infoStore.organization?.name?.trim()
|
||||
const orgName = brandOrgName.value
|
||||
const brandNameRaw = infoStore.branding?.name?.trim() || 'Yuxi-Know'
|
||||
|
||||
if (orgName && brandNameRaw && orgName !== brandNameRaw) {
|
||||
return `${orgName} | ${brandNameRaw}`
|
||||
return brandNameRaw
|
||||
}
|
||||
|
||||
return orgName || brandNameRaw
|
||||
@ -584,8 +591,28 @@ onUnmounted(() => {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--main-color);
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.brand-org {
|
||||
color: var(--gray-700);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.brand-separator {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background-color: var(--gray-400);
|
||||
border-radius: 50%;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.brand-main {
|
||||
color: var(--main-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.back-home-btn {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user