mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
refactor(web): i18n
This commit is contained in:
@@ -76,33 +76,20 @@ const curSelectSlide = (cur: string) => computed(() => {
|
||||
})
|
||||
const sidebarInfo = computed(() => [
|
||||
{
|
||||
title: t('slidebar.chat'),
|
||||
title: t('sidebar.chat'),
|
||||
name: 'chat',
|
||||
icon: ['far', 'comments']
|
||||
icon: ['far', 'comments'],
|
||||
},
|
||||
// {
|
||||
// title: t('slidebar.home'),
|
||||
// name: 'home',
|
||||
// icon: mdiHome
|
||||
// },
|
||||
{
|
||||
title: t('slidebar.model_setting'),
|
||||
title: t('sidebar.models'),
|
||||
name: 'models',
|
||||
icon: ['fas', 'robot']
|
||||
}, {
|
||||
title: t('slidebar.setting'),
|
||||
name: 'settings',
|
||||
icon: ['fas', 'gear']
|
||||
icon: ['fas', 'robot'],
|
||||
},
|
||||
{
|
||||
title: t('sidebar.settings'),
|
||||
name: 'settings',
|
||||
icon: ['fas', 'gear'],
|
||||
},
|
||||
// {
|
||||
// title: 'MCP',
|
||||
// name: 'mcp',
|
||||
// icon: mdiListBox
|
||||
// }, {
|
||||
// title: t('slidebar.platform'),
|
||||
// name: 'platform',
|
||||
// icon: mdiBookArrowDown
|
||||
// }
|
||||
])
|
||||
|
||||
</script>
|
||||
@@ -6,15 +6,15 @@
|
||||
variant="default"
|
||||
class="ml-auto my-4"
|
||||
>
|
||||
添加平台
|
||||
{{ $t('platform.addTitle') }}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent class="sm:max-w-106.25">
|
||||
<form @submit="addPlatform">
|
||||
<DialogHeader>
|
||||
<DialogTitle>添加平台</DialogTitle>
|
||||
<DialogTitle>{{ $t('platform.addTitle') }}</DialogTitle>
|
||||
<DialogDescription class="mb-4">
|
||||
为模型添加使用平台
|
||||
{{ $t('platform.addDescription') }}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
>
|
||||
<FormItem>
|
||||
<FormLabel class="mb-2">
|
||||
Name
|
||||
{{ $t('platform.name') }}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="请输入Name"
|
||||
:placeholder="$t('platform.namePlaceholder')"
|
||||
v-bind="componentField"
|
||||
autocomplete="name"
|
||||
/>
|
||||
@@ -49,7 +49,7 @@
|
||||
>
|
||||
<FormItem>
|
||||
<FormLabel class="mb-2">
|
||||
Config
|
||||
{{ $t('platform.config') }}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<TagsInput
|
||||
@@ -67,7 +67,7 @@
|
||||
<TagsInputItemDelete />
|
||||
</TagsInputItem>
|
||||
<TagsInputInput
|
||||
placeholder="key:value 格式"
|
||||
:placeholder="$t('platform.configPlaceholder')"
|
||||
class="w-full py-1"
|
||||
/>
|
||||
</TagsInput>
|
||||
@@ -85,7 +85,7 @@
|
||||
>
|
||||
<FormItem>
|
||||
<FormLabel class="mb-2">
|
||||
是否立即使用
|
||||
{{ $t('platform.active') }}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Switch
|
||||
@@ -103,11 +103,11 @@
|
||||
<DialogFooter class="mt-4">
|
||||
<DialogClose as-child>
|
||||
<Button variant="outline">
|
||||
取消
|
||||
{{ $t('common.cancel') }}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<Button type="submit">
|
||||
添加平台
|
||||
{{ $t('platform.addTitle') }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
|
||||
@@ -9,19 +9,18 @@
|
||||
<FontAwesomeIcon
|
||||
:icon="['fas', 'plus']"
|
||||
class="mr-1"
|
||||
/> 添加
|
||||
/> {{ $t('provider.addBtn') }}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent class="sm:max-w-106.25">
|
||||
<form @submit="createProvider">
|
||||
<DialogHeader>
|
||||
<DialogTitle>添加提供商</DialogTitle>
|
||||
<DialogTitle>{{ $t('provider.add') }}</DialogTitle>
|
||||
<DialogDescription>
|
||||
<Separator class="my-4" />
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
|
||||
|
||||
<div class="flex-col gap-3 flex">
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
@@ -29,12 +28,12 @@
|
||||
>
|
||||
<FormItem>
|
||||
<Label class="mb-2">
|
||||
Name
|
||||
{{ $t('provider.name') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="请输入Name"
|
||||
:placeholder="$t('provider.namePlaceholder')"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -46,12 +45,12 @@
|
||||
>
|
||||
<FormItem>
|
||||
<Label class="mb-2">
|
||||
API 密钥
|
||||
{{ $t('provider.apiKey') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="请输入Api Key"
|
||||
:placeholder="$t('provider.apiKeyPlaceholder')"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -63,15 +62,15 @@
|
||||
>
|
||||
<FormItem>
|
||||
<Label class="mb-2">
|
||||
URL
|
||||
{{ $t('provider.url') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="请输入URL"
|
||||
:placeholder="$t('provider.urlPlaceholder')"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
<FormField
|
||||
@@ -80,12 +79,12 @@
|
||||
>
|
||||
<FormItem>
|
||||
<Label class="mb-2">
|
||||
Type
|
||||
{{ $t('provider.type') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Select v-bind="componentField">
|
||||
<SelectTrigger class="w-full">
|
||||
<SelectValue :placeholder="$t('prompt.select', { msg: 'Type' })" />
|
||||
<SelectValue :placeholder="$t('provider.typePlaceholder')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
@@ -106,7 +105,7 @@
|
||||
<DialogFooter class="mt-8">
|
||||
<DialogClose as-child>
|
||||
<Button variant="outline">
|
||||
Cancel
|
||||
{{ $t('common.cancel') }}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<Button
|
||||
@@ -117,7 +116,7 @@
|
||||
v-if="isLoading"
|
||||
class="mr-1"
|
||||
/>
|
||||
添加MCP
|
||||
{{ $t('provider.add') }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
@@ -130,7 +129,7 @@ import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
@@ -148,7 +147,7 @@ import {
|
||||
SelectItem,
|
||||
Separator,
|
||||
Label,
|
||||
Spinner
|
||||
Spinner,
|
||||
} from '@memoh/ui'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import z from 'zod'
|
||||
@@ -182,5 +181,4 @@ const createProvider = form.handleSubmit(async (value) => {
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
variant="outline"
|
||||
@click="close"
|
||||
>
|
||||
{{ cancelText }}
|
||||
{{ cancelText || $t('common.cancel') }}
|
||||
</Button>
|
||||
<Button
|
||||
:disabled="loading"
|
||||
@click="$emit('confirm'); close()"
|
||||
>
|
||||
<Spinner v-if="loading" />
|
||||
{{ confirmText }}
|
||||
{{ confirmText || $t('common.confirm') }}
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
@@ -43,8 +43,8 @@ withDefaults(defineProps<{
|
||||
cancelText?: string
|
||||
loading?: boolean
|
||||
}>(), {
|
||||
confirmText: '确定',
|
||||
cancelText: '取消',
|
||||
confirmText: '',
|
||||
cancelText: '',
|
||||
loading: false,
|
||||
})
|
||||
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
variant="default"
|
||||
class="ml-auto my-4"
|
||||
>
|
||||
{{ $t("button.add", { msg: "MCP" }) }}
|
||||
{{ $t('mcp.addTitle') }}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent class="sm:max-w-106.25">
|
||||
<form @submit="createMCP">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ $t("button.add", { msg: "MCP" }) }}</DialogTitle>
|
||||
<DialogTitle>{{ $t('mcp.addTitle') }}</DialogTitle>
|
||||
<DialogDescription class="mb-4">
|
||||
添加MCP完成操作
|
||||
{{ $t('mcp.addDescription') }}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
>
|
||||
<FormItem>
|
||||
<FormLabel class="mb-2">
|
||||
Name
|
||||
{{ $t('mcp.name') }}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
:placeholder="$t('prompt.enter', { msg: 'Name' })"
|
||||
:placeholder="$t('mcp.namePlaceholder')"
|
||||
v-bind="componentField"
|
||||
autocomplete="name"
|
||||
/>
|
||||
@@ -49,12 +49,12 @@
|
||||
>
|
||||
<FormItem>
|
||||
<FormLabel class="mb-2">
|
||||
Type
|
||||
{{ $t('mcp.type') }}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Select v-bind="componentField">
|
||||
<SelectTrigger class="w-full">
|
||||
<SelectValue :placeholder="$t('prompt.select', { msg: 'Type' })" />
|
||||
<SelectValue :placeholder="$t('mcp.typePlaceholder')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
@@ -78,12 +78,12 @@
|
||||
>
|
||||
<FormItem>
|
||||
<FormLabel class="mb-2">
|
||||
Cwd
|
||||
{{ $t('mcp.cwd') }}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
:placeholder="$t('prompt.enter', { msg: 'cwd' })"
|
||||
:placeholder="$t('mcp.cwdPlaceholder')"
|
||||
v-bind="componentField"
|
||||
autocomplete="cwd"
|
||||
/>
|
||||
@@ -101,11 +101,11 @@
|
||||
>
|
||||
<FormItem>
|
||||
<FormLabel class="mb-2">
|
||||
Command
|
||||
{{ $t('mcp.command') }}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
:placeholder="$t('prompt.enter', { msg: 'Command' })"
|
||||
:placeholder="$t('mcp.commandPlaceholder')"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -122,7 +122,7 @@
|
||||
>
|
||||
<FormItem>
|
||||
<FormLabel class="mb-2">
|
||||
Arguments
|
||||
{{ $t('mcp.arguments') }}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<TagsInput
|
||||
@@ -140,7 +140,7 @@
|
||||
<TagsInputItemDelete />
|
||||
</TagsInputItem>
|
||||
<TagsInputInput
|
||||
:placeholder="$t('prompt.enter', { msg: 'Arguments' })"
|
||||
:placeholder="$t('mcp.argumentsPlaceholder')"
|
||||
class="w-full py-1"
|
||||
/>
|
||||
</TagsInput>
|
||||
@@ -158,7 +158,7 @@
|
||||
>
|
||||
<FormItem>
|
||||
<FormLabel class="mb-2">
|
||||
Env
|
||||
{{ $t('mcp.env') }}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<TagsInput
|
||||
@@ -176,7 +176,7 @@
|
||||
<TagsInputItemDelete />
|
||||
</TagsInputItem>
|
||||
<TagsInputInput
|
||||
:placeholder="$t('prompt.enter', { msg: 'Env' })"
|
||||
:placeholder="$t('mcp.envPlaceholder')"
|
||||
class="w-full py-1"
|
||||
/>
|
||||
</TagsInput>
|
||||
@@ -195,7 +195,7 @@
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<section class="flex gap-4">
|
||||
<Label>{{ $t('state.open') }}</Label>
|
||||
<Label>{{ $t('mcp.active') }}</Label>
|
||||
<Switch
|
||||
:model-value="componentField.modelValue"
|
||||
@update:model-value="componentField['onUpdate:modelValue']"
|
||||
@@ -212,11 +212,11 @@
|
||||
<DialogFooter class="mt-4">
|
||||
<DialogClose as-child>
|
||||
<Button variant="outline">
|
||||
Cancel
|
||||
{{ $t('common.cancel') }}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<Button type="submit">
|
||||
{{ $t("button.add", { msg: "MCP" }) }}
|
||||
{{ $t('mcp.addTitle') }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
|
||||
@@ -3,33 +3,33 @@
|
||||
<Dialog v-model:open="open">
|
||||
<DialogTrigger as-child>
|
||||
<Button variant="default">
|
||||
{{ $t("button.add", { msg: "Model" }) }}
|
||||
{{ $t('models.addModel') }}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent class="sm:max-w-106.25">
|
||||
<form @submit="addModel">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{{ title === 'edit' ? '编辑Model' : '添加Model' }}
|
||||
{{ title === 'edit' ? $t('models.editModel') : $t('models.addModel') }}
|
||||
</DialogTitle>
|
||||
<DialogDescription class="mb-4">
|
||||
<Separator class="my-4" />
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div class="flex flex-col gap-3">
|
||||
<!-- 1. Type(先选类型) -->
|
||||
<!-- Type -->
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
name="type"
|
||||
>
|
||||
<FormItem>
|
||||
<Label class="mb-2">
|
||||
Type
|
||||
{{ $t('models.type') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Select v-bind="componentField">
|
||||
<SelectTrigger class="w-full">
|
||||
<SelectValue placeholder="选择模型类型" />
|
||||
<SelectValue :placeholder="$t('models.typePlaceholder')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
@@ -46,46 +46,46 @@
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- 2. Model(原 Model ID) -->
|
||||
<!-- Model -->
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
name="model_id"
|
||||
>
|
||||
<FormItem>
|
||||
<Label class="mb-2">
|
||||
Model
|
||||
{{ $t('models.model') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="e.g. gpt-4o"
|
||||
:placeholder="$t('models.modelPlaceholder')"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- 3. Display Name(可选) -->
|
||||
<!-- Display Name -->
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
name="name"
|
||||
>
|
||||
<FormItem>
|
||||
<Label class="mb-2">
|
||||
Display Name
|
||||
<span class="text-muted-foreground text-xs ml-1">(optional)</span>
|
||||
{{ $t('models.displayName') }}
|
||||
<span class="text-muted-foreground text-xs ml-1">({{ $t('common.optional') }})</span>
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="自定义显示名称"
|
||||
:placeholder="$t('models.displayNamePlaceholder')"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- 4. Dimensions(仅 embedding 时显示) -->
|
||||
<!-- Dimensions (embedding only) -->
|
||||
<FormField
|
||||
v-if="selectedType === 'embedding'"
|
||||
v-slot="{ componentField }"
|
||||
@@ -93,19 +93,19 @@
|
||||
>
|
||||
<FormItem>
|
||||
<Label class="mb-2">
|
||||
Dimensions
|
||||
{{ $t('models.dimensions') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="e.g. 1536"
|
||||
:placeholder="$t('models.dimensionsPlaceholder')"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- 5. 多模态(仅 chat 时显示) -->
|
||||
<!-- Multimodal (chat only) -->
|
||||
<FormField
|
||||
v-if="selectedType === 'chat'"
|
||||
v-slot="{ componentField }"
|
||||
@@ -113,7 +113,7 @@
|
||||
>
|
||||
<FormItem class="flex items-center justify-between">
|
||||
<Label>
|
||||
是否开启多模态
|
||||
{{ $t('models.multimodal') }}
|
||||
</Label>
|
||||
<Switch
|
||||
v-model="componentField.modelValue"
|
||||
@@ -125,7 +125,7 @@
|
||||
<DialogFooter class="mt-4">
|
||||
<DialogClose as-child>
|
||||
<Button variant="outline">
|
||||
Cancel
|
||||
{{ $t('common.cancel') }}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<Button
|
||||
@@ -133,7 +133,7 @@
|
||||
:disabled="!form.meta.value.valid"
|
||||
>
|
||||
<Spinner v-if="isLoading" />
|
||||
{{ title === 'edit' ? '保存' : $t("button.add", { msg: "Model" }) }}
|
||||
{{ title === 'edit' ? $t('common.save') : $t('models.addModel') }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
@@ -176,7 +176,7 @@ import { type ModelInfo } from '@memoh/shared'
|
||||
import { useCreateModel } from '@/composables/api/useModels'
|
||||
|
||||
const formSchema = toTypedSchema(z.object({
|
||||
type: z.string().min(1, '请选择模型类型'),
|
||||
type: z.string().min(1),
|
||||
model_id: z.string().min(1),
|
||||
name: z.string().optional(),
|
||||
dimensions: z.coerce.number().min(1).optional(),
|
||||
|
||||
@@ -1,39 +1,121 @@
|
||||
{
|
||||
"login": {
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"login": "Login",
|
||||
"register": "Register",
|
||||
"forget": "Forgot your password?",
|
||||
"exit": "Sign Out"
|
||||
},
|
||||
"prompt": {
|
||||
"enter": "Please enter {msg}",
|
||||
"select": "Please select {msg}"
|
||||
},
|
||||
"slidebar": {
|
||||
"setting": "Settings",
|
||||
"platform": "Platform",
|
||||
"chat": "Create Chat",
|
||||
"model_setting": "Model Settings",
|
||||
"home": "Home"
|
||||
},
|
||||
"desc": {
|
||||
"question": "your question"
|
||||
},
|
||||
"chat": {
|
||||
"send": "Send",
|
||||
"chat": "Chat"
|
||||
},
|
||||
"breadcrumb": {
|
||||
"main": "Main"
|
||||
},
|
||||
"button": {
|
||||
"common": {
|
||||
"confirm": "Confirm",
|
||||
"cancel": "Cancel",
|
||||
"save": "Save",
|
||||
"add": "Add",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"add": "Add {msg}"
|
||||
"search": "Search",
|
||||
"loading": "Loading...",
|
||||
"operation": "Actions",
|
||||
"enable": "Enable",
|
||||
"optional": "optional"
|
||||
},
|
||||
"state":{
|
||||
"open":"Open"
|
||||
"auth": {
|
||||
"welcome": "Welcome Back",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"login": "Sign In",
|
||||
"register": "Sign Up",
|
||||
"forgotPassword": "Forgot password?",
|
||||
"logout": "Sign Out",
|
||||
"logoutConfirm": "Are you sure you want to sign out?",
|
||||
"loginFailed": "Login failed",
|
||||
"invalidCredentials": "Invalid username or password",
|
||||
"retryHint": "Please check and try again"
|
||||
},
|
||||
"sidebar": {
|
||||
"chat": "Chat",
|
||||
"models": "Models",
|
||||
"settings": "Settings",
|
||||
"home": "Home",
|
||||
"platform": "Platform",
|
||||
"mcp": "MCP"
|
||||
},
|
||||
"breadcrumb": {
|
||||
"main": "Home"
|
||||
},
|
||||
"settings": {
|
||||
"display": "Display Settings",
|
||||
"language": "Language",
|
||||
"languagePlaceholder": "Select language",
|
||||
"theme": "Theme",
|
||||
"themePlaceholder": "Select theme",
|
||||
"themeLight": "Light",
|
||||
"themeDark": "Dark",
|
||||
"langZh": "中文",
|
||||
"langEn": "English"
|
||||
},
|
||||
"chat": {
|
||||
"greeting": "Hi! How can I help you today?",
|
||||
"inputPlaceholder": "Type your question…",
|
||||
"send": "Send"
|
||||
},
|
||||
"models": {
|
||||
"title": "Models",
|
||||
"searchPlaceholder": "Search providers…",
|
||||
"addModel": "Add Model",
|
||||
"editModel": "Edit Model",
|
||||
"deleteModelConfirm": "Are you sure you want to delete this model?",
|
||||
"emptyTitle": "No Models",
|
||||
"emptyDescription": "Click the button above to add a model for this provider",
|
||||
"type": "Type",
|
||||
"typePlaceholder": "Select model type",
|
||||
"model": "Model ID",
|
||||
"modelPlaceholder": "e.g. gpt-4o",
|
||||
"displayName": "Display Name",
|
||||
"displayNamePlaceholder": "Custom display name",
|
||||
"dimensions": "Dimensions",
|
||||
"dimensionsPlaceholder": "e.g. 1536",
|
||||
"multimodal": "Multimodal"
|
||||
},
|
||||
"provider": {
|
||||
"add": "Add Provider",
|
||||
"addBtn": "Add",
|
||||
"name": "Name",
|
||||
"namePlaceholder": "Enter provider name",
|
||||
"apiKey": "API Key",
|
||||
"apiKeyPlaceholder": "Enter API key",
|
||||
"url": "Base URL",
|
||||
"urlPlaceholder": "Enter base URL",
|
||||
"type": "Type",
|
||||
"typePlaceholder": "Select type",
|
||||
"deleteConfirm": "Are you sure you want to delete this provider?",
|
||||
"saveChanges": "Save Changes",
|
||||
"emptyTitle": "No Providers",
|
||||
"emptyDescription": "Add a model provider first to configure models"
|
||||
},
|
||||
"mcp": {
|
||||
"addTitle": "Add MCP",
|
||||
"addDescription": "Configure MCP server connection",
|
||||
"name": "Name",
|
||||
"namePlaceholder": "Enter name",
|
||||
"type": "Type",
|
||||
"typePlaceholder": "Select type",
|
||||
"command": "Command",
|
||||
"commandPlaceholder": "Enter start command",
|
||||
"arguments": "Arguments",
|
||||
"argumentsPlaceholder": "Enter arguments",
|
||||
"cwd": "Working Directory",
|
||||
"cwdPlaceholder": "Enter working directory path",
|
||||
"env": "Environment",
|
||||
"envPlaceholder": "Format: KEY:VALUE",
|
||||
"active": "Enable Now"
|
||||
},
|
||||
"platform": {
|
||||
"addTitle": "Add Platform",
|
||||
"addDescription": "Configure a platform for model access",
|
||||
"name": "Name",
|
||||
"namePlaceholder": "Enter platform name",
|
||||
"config": "Config",
|
||||
"configPlaceholder": "Format: key:value",
|
||||
"active": "Enable Now",
|
||||
"running": "Running",
|
||||
"platformLabel": "Platform",
|
||||
"deleteConfirm": "Are you sure you want to delete this platform?"
|
||||
},
|
||||
"home": {
|
||||
"title": "Home"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,121 @@
|
||||
{
|
||||
"login": {
|
||||
"common": {
|
||||
"confirm": "确认",
|
||||
"cancel": "取消",
|
||||
"save": "保存",
|
||||
"add": "添加",
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"search": "搜索",
|
||||
"loading": "加载中...",
|
||||
"operation": "操作",
|
||||
"enable": "启用",
|
||||
"optional": "可选"
|
||||
},
|
||||
"auth": {
|
||||
"welcome": "欢迎回来",
|
||||
"username": "用户名",
|
||||
"password": "密码",
|
||||
"login": "登录",
|
||||
"register": "注册",
|
||||
"forget": "忘记密码?",
|
||||
"exit": "退出登录"
|
||||
"forgotPassword": "忘记密码?",
|
||||
"logout": "退出登录",
|
||||
"logoutConfirm": "确定要退出当前账号吗?",
|
||||
"loginFailed": "登录失败",
|
||||
"invalidCredentials": "用户名或密码不正确",
|
||||
"retryHint": "请检查后重新输入"
|
||||
},
|
||||
"desc": {
|
||||
"question": "您的问题"
|
||||
},
|
||||
"prompt": {
|
||||
"enter": "请输入{msg}",
|
||||
"select": "请选择{msg}"
|
||||
},
|
||||
"slidebar": {
|
||||
"setting": "设置",
|
||||
"sidebar": {
|
||||
"chat": "对话",
|
||||
"models": "模型管理",
|
||||
"settings": "设置",
|
||||
"home": "首页",
|
||||
"platform": "平台",
|
||||
"chat": "创建对话",
|
||||
"model_setting": "模型配置",
|
||||
"home": "主页"
|
||||
},
|
||||
"chat": {
|
||||
"send": "发送",
|
||||
"chat": "对话"
|
||||
"mcp": "MCP"
|
||||
},
|
||||
"breadcrumb": {
|
||||
"main": "主菜单"
|
||||
"main": "主页"
|
||||
},
|
||||
"button": {
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"add": "添加{msg}"
|
||||
"settings": {
|
||||
"display": "显示设置",
|
||||
"language": "语言",
|
||||
"languagePlaceholder": "选择语言",
|
||||
"theme": "主题",
|
||||
"themePlaceholder": "选择主题",
|
||||
"themeLight": "浅色",
|
||||
"themeDark": "深色",
|
||||
"langZh": "中文",
|
||||
"langEn": "English"
|
||||
},
|
||||
"state": {
|
||||
"open": "Open"
|
||||
"chat": {
|
||||
"greeting": "你好!有什么我可以帮你的吗?",
|
||||
"inputPlaceholder": "输入你的问题…",
|
||||
"send": "发送"
|
||||
},
|
||||
"models": {
|
||||
"title": "模型",
|
||||
"searchPlaceholder": "搜索服务商…",
|
||||
"addModel": "添加模型",
|
||||
"editModel": "编辑模型",
|
||||
"deleteModelConfirm": "确定要删除这个模型吗?",
|
||||
"emptyTitle": "暂无模型",
|
||||
"emptyDescription": "点击上方按钮为当前服务商添加模型",
|
||||
"type": "类型",
|
||||
"typePlaceholder": "选择模型类型",
|
||||
"model": "模型 ID",
|
||||
"modelPlaceholder": "例如 gpt-4o",
|
||||
"displayName": "显示名称",
|
||||
"displayNamePlaceholder": "自定义显示名称",
|
||||
"dimensions": "向量维度",
|
||||
"dimensionsPlaceholder": "例如 1536",
|
||||
"multimodal": "支持多模态"
|
||||
},
|
||||
"provider": {
|
||||
"add": "添加服务商",
|
||||
"addBtn": "添加",
|
||||
"name": "名称",
|
||||
"namePlaceholder": "输入服务商名称",
|
||||
"apiKey": "API 密钥",
|
||||
"apiKeyPlaceholder": "输入 API 密钥",
|
||||
"url": "接口地址",
|
||||
"urlPlaceholder": "输入接口地址",
|
||||
"type": "类型",
|
||||
"typePlaceholder": "选择类型",
|
||||
"deleteConfirm": "确定要删除这个服务商吗?",
|
||||
"saveChanges": "保存修改",
|
||||
"emptyTitle": "暂无服务商",
|
||||
"emptyDescription": "请先添加模型服务商,才能配置模型"
|
||||
},
|
||||
"mcp": {
|
||||
"addTitle": "添加 MCP",
|
||||
"addDescription": "配置 MCP 服务器连接",
|
||||
"name": "名称",
|
||||
"namePlaceholder": "输入名称",
|
||||
"type": "类型",
|
||||
"typePlaceholder": "选择类型",
|
||||
"command": "命令",
|
||||
"commandPlaceholder": "输入启动命令",
|
||||
"arguments": "参数",
|
||||
"argumentsPlaceholder": "输入启动参数",
|
||||
"cwd": "工作目录",
|
||||
"cwdPlaceholder": "输入工作目录路径",
|
||||
"env": "环境变量",
|
||||
"envPlaceholder": "格式:KEY:VALUE",
|
||||
"active": "立即启用"
|
||||
},
|
||||
"platform": {
|
||||
"addTitle": "添加平台",
|
||||
"addDescription": "为模型配置调用平台",
|
||||
"name": "名称",
|
||||
"namePlaceholder": "输入平台名称",
|
||||
"config": "配置",
|
||||
"configPlaceholder": "格式:key:value",
|
||||
"active": "立即启用",
|
||||
"running": "运行中",
|
||||
"platformLabel": "平台",
|
||||
"deleteConfirm": "确定要删除这个平台吗?"
|
||||
},
|
||||
"home": {
|
||||
"title": "首页"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
class="scroll-m-20 text-3xl font-semibold tracking-tight text-center"
|
||||
style="font-family: 'Source Han Serif CN', 'Noto Serif SC', 'STSong', 'SimSun', serif;"
|
||||
>
|
||||
<TextGenerateEffect words="您好!有什么能帮助您的?" />
|
||||
<TextGenerateEffect :words="$t('chat.greeting')" />
|
||||
</h4>
|
||||
</section>
|
||||
|
||||
<Textarea
|
||||
v-model="curInputSay"
|
||||
class="pb-16 pt-4"
|
||||
:placeholder="$t('prompt.enter', { msg: $t('desc.question') })"
|
||||
:placeholder="$t('chat.inputPlaceholder')"
|
||||
/>
|
||||
|
||||
<section class="absolute bottom-0 h-14 px-2 inset-x-0 flex items-center">
|
||||
@@ -32,6 +32,7 @@
|
||||
>
|
||||
<template v-if="!loading">
|
||||
{{ $t('chat.send') }}
|
||||
|
||||
<FontAwesomeIcon :icon="['fas', 'paper-plane']" />
|
||||
</template>
|
||||
<LoadingDots v-else />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<section>
|
||||
<h1>主页</h1>
|
||||
<section>
|
||||
<h1>{{ $t('home.title') }}</h1>
|
||||
</section>
|
||||
</template>
|
||||
@@ -3,13 +3,13 @@
|
||||
<section class="w-full max-w-sm flex flex-col gap-10 ">
|
||||
<section>
|
||||
<h3
|
||||
class="scroll-m-20 text-3xl tracking-wide font-semibold text-white text-center"
|
||||
class="scroll-m-20 text-3xl tracking-wide font-semibold text-white text-center"
|
||||
style="font-family: 'Source Han Serif CN', 'Noto Serif SC', 'STSong', 'SimSun', serif;"
|
||||
>
|
||||
欢迎使用
|
||||
{{ $t('auth.welcome') }}
|
||||
</h3>
|
||||
</section>
|
||||
<form
|
||||
<form
|
||||
@submit="login"
|
||||
>
|
||||
<Card class="py-14">
|
||||
@@ -23,14 +23,14 @@
|
||||
class="mb-2"
|
||||
for="username"
|
||||
>
|
||||
{{ $t("login.username") }}
|
||||
{{ $t('auth.username') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Input
|
||||
v-bind="componentField"
|
||||
id="username"
|
||||
id="username"
|
||||
type="text"
|
||||
:placeholder="$t('prompt.enter', { msg: $t(`login.username`).toLocaleLowerCase() })"
|
||||
:placeholder="$t('auth.username')"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -45,14 +45,14 @@
|
||||
class="mb-2"
|
||||
for="password"
|
||||
>
|
||||
{{ $t('login.password') }}
|
||||
{{ $t('auth.password') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
:placeholder="$t('prompt.enter', { msg: $t(`login.password`).toLocaleLowerCase() })"
|
||||
autocomplete="new-password"
|
||||
type="password"
|
||||
:placeholder="$t('auth.password')"
|
||||
autocomplete="new-password"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -63,11 +63,11 @@
|
||||
href="#"
|
||||
class="ml-auto inline-block text-sm underline mt-2"
|
||||
>
|
||||
{{ $t('login.forget') }}
|
||||
{{ $t('auth.forgotPassword') }}
|
||||
</a>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
|
||||
<CardFooter class="flex flex-col gap-4">
|
||||
<Button
|
||||
class="w-full"
|
||||
@@ -75,13 +75,13 @@
|
||||
@click="login"
|
||||
>
|
||||
<Spinner v-if="loading" />
|
||||
{{ $t("login.login") }}
|
||||
{{ $t('auth.login') }}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
class="w-full"
|
||||
>
|
||||
{{ $t("login.register") }}
|
||||
{{ $t('auth.register') }}
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
@@ -101,7 +101,7 @@ import {
|
||||
FormField,
|
||||
FormItem,
|
||||
Label,
|
||||
Spinner
|
||||
Spinner,
|
||||
} from '@memoh/ui'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
@@ -110,9 +110,11 @@ import * as z from 'zod'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import { ref } from 'vue'
|
||||
import { toast } from 'vue-sonner'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { login as loginApi } from '@/composables/api/useAuth'
|
||||
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
|
||||
const formSchema = toTypedSchema(z.object({
|
||||
username: z.string().min(1),
|
||||
@@ -137,17 +139,15 @@ const login = form.handleSubmit(async (values) => {
|
||||
role: '',
|
||||
}, data.access_token)
|
||||
} else {
|
||||
throw new Error('登录失败')
|
||||
throw new Error(t('auth.loginFailed'))
|
||||
}
|
||||
router.replace({ name: 'Main' })
|
||||
} catch {
|
||||
toast.error('用户名或密码错误', {
|
||||
description: '请重新输入用户名和密码',
|
||||
toast.error(t('auth.invalidCredentials'), {
|
||||
description: t('auth.retryHint'),
|
||||
})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -70,7 +70,7 @@ const columns:ColumnDef<MCPType>[] = [
|
||||
},
|
||||
{
|
||||
accessorKey: 'control',
|
||||
header: () => h('div', { class: 'text-center' }, '操作'),
|
||||
header: () => h('div', { class: 'text-center' }, i18nRef('common.operation').value),
|
||||
cell: ({ row }) => h('div', {class:'flex gap-2'}, [
|
||||
h(Button, {
|
||||
onClick() {
|
||||
@@ -82,7 +82,7 @@ const columns:ColumnDef<MCPType>[] = [
|
||||
}
|
||||
open.value=true
|
||||
}
|
||||
}, ()=>i18nRef('button.edit').value),
|
||||
}, ()=>i18nRef('common.edit').value),
|
||||
h(Button, {
|
||||
variant: 'destructive',
|
||||
async onClick() {
|
||||
@@ -92,7 +92,7 @@ const columns:ColumnDef<MCPType>[] = [
|
||||
return
|
||||
}
|
||||
}
|
||||
},()=>i18nRef('button.delete').value)
|
||||
},()=>i18nRef('common.delete').value)
|
||||
])
|
||||
}
|
||||
]
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</Button>
|
||||
|
||||
<ConfirmPopover
|
||||
message="确认是否删除模型?"
|
||||
:message="$t('models.deleteModelConfirm')"
|
||||
:loading="deleteLoading"
|
||||
@confirm="$emit('delete', model.name)"
|
||||
>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<section>
|
||||
<section class="flex justify-between items-center mb-4">
|
||||
<h4 class="scroll-m-20 font-semibold tracking-tight">
|
||||
模型
|
||||
{{ $t('models.title') }}
|
||||
</h4>
|
||||
<CreateModel
|
||||
v-if="providerId"
|
||||
@@ -33,8 +33,8 @@
|
||||
<FontAwesomeIcon :icon="['far', 'rectangle-list']" />
|
||||
</EmptyMedia>
|
||||
</EmptyHeader>
|
||||
<EmptyTitle>还没有添加模型</EmptyTitle>
|
||||
<EmptyDescription>请为当前Provider添加模型</EmptyDescription>
|
||||
<EmptyTitle>{{ $t('models.emptyTitle') }}</EmptyTitle>
|
||||
<EmptyDescription>{{ $t('models.emptyDescription') }}</EmptyDescription>
|
||||
<EmptyContent />
|
||||
</Empty>
|
||||
</section>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="**:[input]:mt-3 **:[input]:mb-4">
|
||||
<section>
|
||||
<h4 class="scroll-m-20 font-semibold tracking-tight">
|
||||
Name
|
||||
{{ $t('provider.name') }}
|
||||
</h4>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
@@ -13,7 +13,7 @@
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="请输入名称"
|
||||
:placeholder="$t('provider.namePlaceholder')"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<section>
|
||||
<h4 class="scroll-m-20 font-semibold tracking-tight">
|
||||
API 密钥
|
||||
{{ $t('provider.apiKey') }}
|
||||
</h4>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
@@ -33,7 +33,7 @@
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="请输入API密钥"
|
||||
:placeholder="$t('provider.apiKeyPlaceholder')"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
<section>
|
||||
<h4 class="scroll-m-20 font-semibold tracking-tight">
|
||||
URL
|
||||
{{ $t('provider.url') }}
|
||||
</h4>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
@@ -53,7 +53,7 @@
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="请输入URL"
|
||||
:placeholder="$t('provider.urlPlaceholder')"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
<section class="flex justify-end mt-4 gap-4">
|
||||
<ConfirmPopover
|
||||
message="确认是否删除模型平台?"
|
||||
:message="$t('provider.deleteConfirm')"
|
||||
:loading="deleteLoading"
|
||||
@confirm="$emit('delete')"
|
||||
>
|
||||
@@ -80,7 +80,7 @@
|
||||
:disabled="!hasChanges || !form.meta.value.valid"
|
||||
>
|
||||
<Spinner v-if="editLoading" />
|
||||
确定修改
|
||||
{{ $t('provider.saveChanges') }}
|
||||
</Button>
|
||||
</section>
|
||||
</form>
|
||||
@@ -96,7 +96,7 @@ import {
|
||||
Spinner,
|
||||
} from '@memoh/ui'
|
||||
import ConfirmPopover from '@/components/confirm-popover/index.vue'
|
||||
import { computed, toValue, watch } from 'vue'
|
||||
import { computed, watch } from 'vue'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import z from 'zod'
|
||||
import { useForm } from 'vee-validate'
|
||||
|
||||
@@ -95,7 +95,7 @@ const openStatus = reactive({
|
||||
<InputGroup class="shadow-none">
|
||||
<InputGroupInput
|
||||
v-model="searchProviderTxt.temp_value"
|
||||
placeholder="搜索模型平台"
|
||||
:placeholder="$t('models.searchPlaceholder')"
|
||||
/>
|
||||
<InputGroupAddon
|
||||
align="inline-end"
|
||||
@@ -136,7 +136,7 @@ const openStatus = reactive({
|
||||
<SidebarFooter>
|
||||
<Select v-model:model-value="filterProvider">
|
||||
<SelectTrigger class="w-full">
|
||||
<SelectValue :placeholder="$t('prompt.select', { msg: 'Type' })" />
|
||||
<SelectValue :placeholder="$t('provider.typePlaceholder')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
@@ -169,8 +169,8 @@ const openStatus = reactive({
|
||||
<FontAwesomeIcon :icon="['far', 'rectangle-list']" />
|
||||
</EmptyMedia>
|
||||
</EmptyHeader>
|
||||
<EmptyTitle>No Provider</EmptyTitle>
|
||||
<EmptyDescription>没有添加模型提供商,无法配置模型</EmptyDescription>
|
||||
<EmptyTitle>{{ $t('provider.emptyTitle') }}</EmptyTitle>
|
||||
<EmptyDescription>{{ $t('provider.emptyDescription') }}</EmptyDescription>
|
||||
<EmptyContent>
|
||||
<!-- <Button>Add data</Button> -->
|
||||
<AddProvider v-model:open="openStatus.provideOpen" />
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle class="text-muted-foreground flex justify-between">
|
||||
<span>平台:{{ platform.name }}</span>
|
||||
<span>{{ $t('platform.platformLabel') }}: {{ platform.name }}</span>
|
||||
<Badge
|
||||
v-if="platform.active"
|
||||
variant="outline"
|
||||
>
|
||||
运行中...
|
||||
{{ $t('platform.running') }}
|
||||
</Badge>
|
||||
</CardTitle>
|
||||
<CardContent class="mt-4 p-0">
|
||||
@@ -31,13 +31,13 @@
|
||||
class="ml-auto"
|
||||
@click="$emit('edit', platform)"
|
||||
>
|
||||
编辑
|
||||
{{ $t('common.edit') }}
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
@click="$emit('delete', platform)"
|
||||
>
|
||||
删除
|
||||
{{ $t('common.delete') }}
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
|
||||
@@ -5,27 +5,27 @@
|
||||
:icon="['fas', 'gear']"
|
||||
class="mr-2"
|
||||
/>
|
||||
显示设置
|
||||
{{ $t('settings.display') }}
|
||||
</h6>
|
||||
<Separator />
|
||||
|
||||
<div class="mt-4 space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<Label>语言</Label>
|
||||
<Label>{{ $t('settings.language') }}</Label>
|
||||
<Select
|
||||
:model-value="language"
|
||||
@update:model-value="(v) => v && setLanguage(v as Locale)"
|
||||
>
|
||||
<SelectTrigger class="w-40">
|
||||
<SelectValue placeholder="选择语言" />
|
||||
<SelectValue :placeholder="$t('settings.languagePlaceholder')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="zh">
|
||||
中文
|
||||
{{ $t('settings.langZh') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="en">
|
||||
English
|
||||
{{ $t('settings.langEn') }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
@@ -35,21 +35,21 @@
|
||||
<Separator />
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<Label>主题</Label>
|
||||
<Label>{{ $t('settings.theme') }}</Label>
|
||||
<Select
|
||||
:model-value="theme"
|
||||
@update:model-value="(v) => v && setTheme(v as 'light' | 'dark')"
|
||||
>
|
||||
<SelectTrigger class="w-40">
|
||||
<SelectValue placeholder="选择主题" />
|
||||
<SelectValue :placeholder="$t('settings.themePlaceholder')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="light">
|
||||
亮色
|
||||
{{ $t('settings.themeLight') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="dark">
|
||||
暗色
|
||||
{{ $t('settings.themeDark') }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
@@ -62,22 +62,22 @@
|
||||
<template #default="{ close }">
|
||||
<PopoverTrigger as-child>
|
||||
<Button variant="outline">
|
||||
{{ $t("login.exit") }}
|
||||
{{ $t('auth.logout') }}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-80">
|
||||
<p class="mb-4">
|
||||
确认退出登录?
|
||||
{{ $t('auth.logoutConfirm') }}
|
||||
</p>
|
||||
<div class="flex justify-end gap-3">
|
||||
<Button
|
||||
variant="outline"
|
||||
@click="close"
|
||||
>
|
||||
取消
|
||||
{{ $t('common.cancel') }}
|
||||
</Button>
|
||||
<Button @click="exit(); close()">
|
||||
确定
|
||||
{{ $t('common.confirm') }}
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
@@ -118,4 +118,4 @@ const exit = () => {
|
||||
exitLogin()
|
||||
router.replace({ name: 'Login' })
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -17,34 +17,35 @@ const routes = [
|
||||
redirect: '/main/chat',
|
||||
meta: {
|
||||
breadcrumb: i18nRef('breadcrumb.main')
|
||||
|
||||
},
|
||||
children: [{
|
||||
name: 'chat',
|
||||
path: 'chat',
|
||||
component: () => import('@/pages/chat/index.vue'),
|
||||
meta: {
|
||||
breadcrumb: i18nRef('chat.chat')
|
||||
breadcrumb: i18nRef('sidebar.chat')
|
||||
}
|
||||
}, {
|
||||
name: 'home',
|
||||
path: 'home',
|
||||
component: () => import('@/pages/home/index.vue'),
|
||||
meta: {
|
||||
breadcrumb: '主页'
|
||||
breadcrumb: i18nRef('home.title')
|
||||
}
|
||||
}, {
|
||||
name: 'models',
|
||||
path: 'models',
|
||||
component: () => import('@/pages/models/index.vue'),
|
||||
meta: {
|
||||
breadcrumb: i18nRef('slidebar.model_setting')
|
||||
breadcrumb: i18nRef('sidebar.models')
|
||||
}
|
||||
}, {
|
||||
name: 'settings',
|
||||
path: 'settings',
|
||||
component: () => import('@/pages/settings/index.vue'),
|
||||
meta: {
|
||||
breadcrumb: i18nRef('slidebar.setting')
|
||||
breadcrumb: i18nRef('sidebar.settings')
|
||||
}
|
||||
}, {
|
||||
name: 'mcp',
|
||||
@@ -58,7 +59,7 @@ const routes = [
|
||||
path: 'platform',
|
||||
component: () => import('@/pages/platform/index.vue'),
|
||||
meta: {
|
||||
breadcrumb: i18nRef('slidebar.platform')
|
||||
breadcrumb: i18nRef('sidebar.platform')
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user