feat(i18n): add internationalization support for settings pages
- Initialize locale store in App.vue alongside theme store - Replace hardcoded menu labels with i18n keys in system-config.ts - Add English, Chinese, and Japanese translations for settings content - Integrate vue-i18n in SystemConfig, AccountSetting, and Version components - Update UI components to use translated strings for all user-facing text - Implement language switching functionality in settings page
This commit is contained in:
@@ -9,10 +9,14 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import { useThemeStore } from '@src/stores/theme'
|
||||
import { useLocaleStore } from '@src/store/locale'
|
||||
|
||||
// 初始化主题设置
|
||||
// 初始化主题和语言设置
|
||||
const themeStore = useThemeStore()
|
||||
const localeStore = useLocaleStore()
|
||||
|
||||
onMounted(() => {
|
||||
themeStore.init().catch(console.error)
|
||||
localeStore.init().catch(console.error)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface MenuItem {
|
||||
export const systemMenus: MenuItem[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: '账号',
|
||||
name: 'setting.menu.account',
|
||||
icon: RiUserLine,
|
||||
color: '#525866',
|
||||
activeColor: '#2B7FFF',
|
||||
@@ -21,7 +21,7 @@ export const systemMenus: MenuItem[] = [
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '渠道管理',
|
||||
name: 'setting.menu.channel',
|
||||
icon: RiHotelLine,
|
||||
color: '#525866',
|
||||
activeColor: '#2B7FFF',
|
||||
@@ -29,7 +29,7 @@ export const systemMenus: MenuItem[] = [
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '房型管理',
|
||||
name: 'setting.menu.roomType',
|
||||
icon: RiHotelBedLine,
|
||||
color: '#525866',
|
||||
activeColor: '#2B7FFF',
|
||||
@@ -37,7 +37,7 @@ export const systemMenus: MenuItem[] = [
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '通用设置',
|
||||
name: 'setting.menu.general',
|
||||
icon: RiSettingsLine,
|
||||
color: '#525866',
|
||||
activeColor: '#2B7FFF',
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
{
|
||||
"title": "Settings",
|
||||
"menu": {
|
||||
"title": "System Settings",
|
||||
"account": "Account",
|
||||
"channel": "Channels",
|
||||
"roomType": "Room Types",
|
||||
"general": "General"
|
||||
},
|
||||
"account": {
|
||||
"title": "Account Settings",
|
||||
"desc": "Please associate PMS and channel room names, smart mapping is available",
|
||||
"account": "Account",
|
||||
"password": "Login Password",
|
||||
"passwordDesc": "Used for investor login operations, last login time: ",
|
||||
"configured": "Configured",
|
||||
"changePassword": "Change Password"
|
||||
},
|
||||
"base": "Basic Settings",
|
||||
"provider": {
|
||||
"modelConfig": "Model Configuration"
|
||||
@@ -50,5 +66,36 @@
|
||||
"defaultModel": "Default Model",
|
||||
"apiKey": "API Key",
|
||||
"apiUrl": "API URL"
|
||||
},
|
||||
"updates": {
|
||||
"title": "Updates",
|
||||
"description": "Keep zn-ai up to date",
|
||||
"autoCheck": "Auto check for updates",
|
||||
"autoCheckDesc": "Check for updates on startup",
|
||||
"autoDownload": "Auto download updates",
|
||||
"autoDownloadDesc": "Automatically download and install updates",
|
||||
"status": {
|
||||
"checking": "Checking for updates...",
|
||||
"downloading": "Downloading new version... {{percent}}%",
|
||||
"available": "New version available: v{{version}}",
|
||||
"downloaded": "Download complete, ready to install",
|
||||
"autoInstalling": "Will restart and install update in {{seconds}} seconds...",
|
||||
"failed": "Update error: {{error}}",
|
||||
"latest": "You have the latest version",
|
||||
"check": "Check for updates to get latest features"
|
||||
},
|
||||
"action": {
|
||||
"checking": "Checking...",
|
||||
"downloading": "Downloading...",
|
||||
"download": "Download Update",
|
||||
"install": "Restart and Install",
|
||||
"cancelAutoInstall": "Cancel",
|
||||
"retry": "Retry",
|
||||
"check": "Check for Updates"
|
||||
},
|
||||
"currentVersion": "Current Version",
|
||||
"whatsNew": "What's New:",
|
||||
"errorDetails": "Error Details:",
|
||||
"help": "When auto-update is enabled, updates will be downloaded and installed automatically."
|
||||
}
|
||||
}
|
||||
@@ -1 +1,101 @@
|
||||
{}
|
||||
{
|
||||
"title": "設定",
|
||||
"menu": {
|
||||
"title": "システム設定",
|
||||
"account": "アカウント",
|
||||
"channel": "チャネル管理",
|
||||
"roomType": "部屋タイプ",
|
||||
"general": "一般設定"
|
||||
},
|
||||
"account": {
|
||||
"title": "アカウント設定",
|
||||
"desc": "PMSとチャネルの部屋タイプ名を関連付けてください。スマートマッピングが利用可能です",
|
||||
"account": "アカウント",
|
||||
"password": "ログインパスワード",
|
||||
"passwordDesc": "投資家のログイン操作に使用されます、前回のログイン時間:",
|
||||
"configured": "設定済み",
|
||||
"changePassword": "パスワードを変更"
|
||||
},
|
||||
"base": "基本設定",
|
||||
"provider": {
|
||||
"modelConfig": "モデル設定"
|
||||
},
|
||||
"theme": {
|
||||
"label": "テーマ設定",
|
||||
"dark": "ダークテーマ",
|
||||
"light": "ライトテーマ",
|
||||
"system": "システムに従う",
|
||||
"primaryColor": "テーマカラー",
|
||||
"description": "アプリケーションの外観をカスタマイズする",
|
||||
"themeMode": "テーマモード",
|
||||
"themeModeDescription": "お好みのテーマモードを選択するか、システム設定に従って自動的に切り替えます。",
|
||||
"lightLabel": "ライト",
|
||||
"lightDescription": "明るくクリア",
|
||||
"darkLabel": "ダーク",
|
||||
"darkDescription": "目に優しい",
|
||||
"systemLabel": "システムに従う",
|
||||
"systemDescription": "自動切り替え",
|
||||
"currentTheme": "現在のテーマ",
|
||||
"followingSystem": "システムテーマに従う ({{theme}})",
|
||||
"setToLight": "ライトテーマに設定しました",
|
||||
"setToDark": "ダークテーマに設定しました",
|
||||
"preview": "プレビュー",
|
||||
"previewDescription": "現在のテーマ効果を表示",
|
||||
"lightPreview": "ライトプレビュー",
|
||||
"darkPreview": "ダークプレビュー"
|
||||
},
|
||||
"appearance": {
|
||||
"fontSize": "フォントサイズ",
|
||||
"fontSizeOptions": {
|
||||
"10": "極小 (10px)",
|
||||
"12": "小 (12px)",
|
||||
"14": "標準 (14px)",
|
||||
"16": "中 (16px)",
|
||||
"18": "大 (18px)",
|
||||
"20": "特大 (20px)",
|
||||
"24": "極大 (24px)"
|
||||
}
|
||||
},
|
||||
"behavior": {
|
||||
"minimizeToTray": "閉じる時にトレイに最小化"
|
||||
},
|
||||
"language": {
|
||||
"label": "言語設定"
|
||||
},
|
||||
"providers": {
|
||||
"defaultModel": "デフォルトモデル",
|
||||
"apiKey": "APIキー",
|
||||
"apiUrl": "API URL"
|
||||
},
|
||||
"updates": {
|
||||
"title": "アップデート",
|
||||
"description": "zn-ai を最新の状態に保つ",
|
||||
"autoCheck": "アップデートを自動確認",
|
||||
"autoCheckDesc": "起動時にアップデートを確認する",
|
||||
"autoDownload": "自動アップデート",
|
||||
"autoDownloadDesc": "アップデートを自動的にダウンロードしてインストールする",
|
||||
"status": {
|
||||
"checking": "アップデートを確認中...",
|
||||
"downloading": "新しいバージョンをダウンロード中... {{percent}}%",
|
||||
"available": "新しいバージョンが利用可能: v{{version}}",
|
||||
"downloaded": "ダウンロード完了、インストール準備完了",
|
||||
"autoInstalling": "{{seconds}} 秒後に再起動してアップデートをインストールします...",
|
||||
"failed": "アップデートエラー: {{error}}",
|
||||
"latest": "最新バージョンを使用しています",
|
||||
"check": "最新機能を利用するためにアップデートを確認する"
|
||||
},
|
||||
"action": {
|
||||
"checking": "確認中...",
|
||||
"downloading": "ダウンロード中...",
|
||||
"download": "アップデートをダウンロード",
|
||||
"install": "再起動してインストール",
|
||||
"cancelAutoInstall": "キャンセル",
|
||||
"retry": "再試行",
|
||||
"check": "アップデートを確認"
|
||||
},
|
||||
"currentVersion": "現在のバージョン",
|
||||
"whatsNew": "更新内容:",
|
||||
"errorDetails": "エラーの詳細:",
|
||||
"help": "自動アップデートを有効にすると、アップデートが自動的にダウンロードされ、インストールされます。"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,21 @@
|
||||
{
|
||||
"title": "设置",
|
||||
"menu": {
|
||||
"title": "系统设置",
|
||||
"account": "账号",
|
||||
"channel": "渠道管理",
|
||||
"roomType": "房型管理",
|
||||
"general": "通用设置"
|
||||
},
|
||||
"account": {
|
||||
"title": "账号设置",
|
||||
"desc": "请关联PMS和渠道房型名称,可使用智能对标",
|
||||
"account": "账号",
|
||||
"password": "登录密码",
|
||||
"passwordDesc": "保障投资者登录操作时使用,上次登录时间:",
|
||||
"configured": "已设置",
|
||||
"changePassword": "修改密码"
|
||||
},
|
||||
"base": "基础设置",
|
||||
"provider": {
|
||||
"modelConfig": "模型配置"
|
||||
@@ -50,5 +66,36 @@
|
||||
"defaultModel": "默认模型",
|
||||
"apiKey": "API密钥",
|
||||
"apiUrl": "API地址"
|
||||
},
|
||||
"updates": {
|
||||
"title": "更新",
|
||||
"description": "保持 zn-ai 最新",
|
||||
"autoCheck": "自动检查更新",
|
||||
"autoCheckDesc": "启动时检查更新",
|
||||
"autoDownload": "自动更新",
|
||||
"autoDownloadDesc": "自动下载并安装更新",
|
||||
"status": {
|
||||
"checking": "正在检查更新...",
|
||||
"downloading": "正在下载新版本... {{percent}}%",
|
||||
"available": "发现新版本: v{{version}}",
|
||||
"downloaded": "下载完成,准备安装",
|
||||
"autoInstalling": "将在 {{seconds}} 秒后重启并安装更新...",
|
||||
"failed": "更新出错: {{error}}",
|
||||
"latest": "您已拥有最新版本",
|
||||
"check": "检查更新以获取最新功能"
|
||||
},
|
||||
"action": {
|
||||
"checking": "检查中...",
|
||||
"downloading": "下载中...",
|
||||
"download": "下载更新",
|
||||
"install": "重启安装",
|
||||
"cancelAutoInstall": "取消",
|
||||
"retry": "重试",
|
||||
"check": "检查更新"
|
||||
},
|
||||
"currentVersion": "当前版本",
|
||||
"whatsNew": "更新内容:",
|
||||
"errorDetails": "错误详情:",
|
||||
"help": "开启自动更新后,更新将自动下载并安装。"
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,36 @@
|
||||
<template>
|
||||
<div class="flex-1 h-full p-[20px] select-none">
|
||||
<TitleSection title="账号设置" desc="请关联PMS和渠道房型名称,可使用智能对标" />
|
||||
<TitleSection :title="t('setting.account.title')" :desc="t('setting.account.desc')" />
|
||||
|
||||
<div
|
||||
class="w-full flex items-center mt-[20px] py-[20px] box-border border-b-[1px] border-dashed border-b-[#E5E8EE]">
|
||||
<div class="label w-[64px] text-[16px] font-medium text-[#171717] mr-[24px]">账号</div>
|
||||
<div class="label text-[16px] font-medium text-[#171717] mr-[24px] whitespace-nowrap">{{
|
||||
t('setting.account.account') }}</div>
|
||||
<div class="value text-[14px] font-medium text-[#171717]">1234567890</div>
|
||||
</div>
|
||||
|
||||
<div class="w-full flex items-center py-[20px] box-border border-b-[1px] border-dashed border-b-[#E5E8EE]">
|
||||
<div class="label w-[64px] text-[16px] font-medium text-[#171717] mr-[24px]">登录密码</div>
|
||||
<div class="value text-[14px] text-[#99A0AE]">保障投资者登录操作时使用,上次登录时间:2022-11-09 16:24:30</div>
|
||||
<div class="label text-[16px] font-medium text-[#171717] mr-[24px] whitespace-nowrap">{{
|
||||
t('setting.account.password') }}</div>
|
||||
<div class="value text-[14px] text-[#99A0AE]">
|
||||
{{ t('setting.account.passwordDesc') }} 2022-11-09 16:24:30
|
||||
</div>
|
||||
|
||||
<div class="border-[1px] border-[#E5E8EE] rounded-[6px] px-[6px] py-[4px] flex items-center ml-[24px]">
|
||||
<RiCheckboxCircleFill class="w-[16px] h-[16px]" color="#1FC16B" />
|
||||
<span class="text-[12px] text-[#525866] ml-[2px]">已设置</span>
|
||||
<span class="text-[12px] text-[#525866] ml-[2px] whitespace-nowrap">{{ t('setting.account.configured') }}</span>
|
||||
</div>
|
||||
|
||||
<el-button type="text" class="ml-auto">修改密码</el-button>
|
||||
<el-button type="text" class="ml-auto">{{ t('setting.account.changePassword') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { RiCheckboxCircleFill } from '@remixicon/vue'
|
||||
import TitleSection from '@src/components/TitleSection/index.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
</script>
|
||||
@@ -1,22 +1,24 @@
|
||||
<template>
|
||||
<div
|
||||
class="w-[136px] h-full box-border border-r-[1px] border-r-[#E5E8EE] py-[12px] px-[8px] flex flex-col gap-[4px] select-none">
|
||||
<div class="text-[12px] text-[#99A0AE] p-[4px]">系统设置</div>
|
||||
class="w-[160px] h-full box-border border-r-[1px] border-r-[#E5E8EE] py-[12px] px-[8px] flex flex-col gap-[4px] select-none">
|
||||
<div class="text-[12px] text-[#99A0AE] p-[4px]">{{ t('setting.menu.title') }}</div>
|
||||
|
||||
<div
|
||||
:class="['box-border flex items-center py-[10px] px-[12px] rounded-[6px] cursor-pointer', item.id === currentId ? 'bg-[#EFF6FF]' : '']"
|
||||
:class="['box-border flex items-center py-[10px] px-[12px] rounded-[6px] cursor-pointer hover:bg-[#EFF6FF]', item.id === currentId ? 'bg-[#EFF6FF]' : '']"
|
||||
v-for="item in systemMenus" :key="item.id" @click="handleClick(item)">
|
||||
<component :is="item.icon" :color="item.id === currentId ? item.activeColor : item.color"
|
||||
class="w-[20px] h-[20px]" />
|
||||
<span class="box-border px-[8px] text-[14px] font-medium text-[#525866]">{{ item.name }}</span>
|
||||
<span class="box-border px-[8px] text-[14px] font-medium text-[#525866]">{{ t(item.name) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, defineEmits } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { systemMenus } from '@src/constant/system-config'
|
||||
|
||||
const { t } = useI18n()
|
||||
const currentId = ref(1)
|
||||
|
||||
const emits = defineEmits(['change'])
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div class="flex-1 h-full p-[20px] select-none">
|
||||
<TitleSection title="通用设置" desc="配置应用程序的外观、语言和版本信息" />
|
||||
<TitleSection :title="t('setting.base')" :desc="t('setting.theme.description')" />
|
||||
|
||||
<!-- 主题设置 -->
|
||||
<div
|
||||
class="w-full flex items-center mt-[20px] py-[20px] box-border border-b-[1px] border-dashed border-b-[#E5E8EE] dark:border-gray-700">
|
||||
<div class="label w-[64px] text-[16px] font-medium text-[#171717] dark:text-gray-100 mr-[24px]">主题设置</div>
|
||||
<div class="label text-[16px] font-medium text-[#171717] dark:text-gray-100 mr-[24px] whitespace-nowrap">
|
||||
{{ t('setting.theme.label') }}</div>
|
||||
<div class="value flex-1">
|
||||
<div class="space-y-4">
|
||||
<div class="flex flex-wrap gap-3">
|
||||
@@ -18,7 +19,7 @@
|
||||
: 'bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
]" @click="handleThemeChange('light')">
|
||||
<RiSunLine class="w-4 h-4" />
|
||||
浅色
|
||||
{{ t('setting.theme.lightLabel') }}
|
||||
</button>
|
||||
|
||||
<!-- 深色主题 -->
|
||||
@@ -30,7 +31,7 @@
|
||||
: 'bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
]" @click="handleThemeChange('dark')">
|
||||
<RiMoonLine class="w-4 h-4" />
|
||||
深色
|
||||
{{ t('setting.theme.darkLabel') }}
|
||||
</button>
|
||||
|
||||
<!-- 跟随系统 -->
|
||||
@@ -39,10 +40,10 @@
|
||||
:class="[
|
||||
currentTheme === 'system'
|
||||
? 'bg-green-50 dark:bg-green-900/20 border-green-500 dark:border-green-400 text-green-700 dark:text-green-300'
|
||||
: 'bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
: 'bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
]" @click="handleThemeChange('system')">
|
||||
<RiComputerLine class="w-4 h-4" />
|
||||
跟随系统
|
||||
{{ t('setting.theme.systemLabel') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -52,24 +53,32 @@
|
||||
<!-- 语言设置 -->
|
||||
<div
|
||||
class="w-full flex items-center mt-[20px] py-[20px] box-border border-b-[1px] border-dashed border-b-[#E5E8EE] dark:border-gray-700">
|
||||
<div class="label w-[64px] text-[16px] font-medium text-[#171717] dark:text-gray-100 mr-[24px]">语言设置</div>
|
||||
<div class="label text-[16px] font-medium text-[#171717] dark:text-gray-100 mr-[24px] whitespace-nowrap">
|
||||
{{ t('setting.language.label') }}
|
||||
</div>
|
||||
<div class="value flex gap-2">
|
||||
<el-button v-for="lang in supportedLanguages" :key="lang.code"
|
||||
:type="currentLanguage === lang.code ? 'primary' : 'text'" @click="handleLanguageChange(lang.code)"
|
||||
class="px-4">
|
||||
<button v-for="lang in SUPPORTED_LANGUAGES" :key="lang.code" @click="handleLanguageChange(lang.code)"
|
||||
class="theme-button px-5 py-1.5 rounded-full border text-[14px] font-medium transition-all duration-200 flex items-center gap-2"
|
||||
:class="[
|
||||
currentLanguage === lang.code
|
||||
? 'bg-green-50 dark:bg-green-900/20 border-green-500 dark:border-green-400 text-green-700 dark:text-green-300'
|
||||
: 'bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
]">
|
||||
{{ lang.label }}
|
||||
</el-button>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 更新部分 -->
|
||||
<div class="mt-[40px]">
|
||||
<div class="text-[24px] font-medium text-[#171717] dark:text-gray-100 mb-[24px]">更新</div>
|
||||
<div class="text-[24px] font-medium text-[#171717] dark:text-gray-100 mb-[24px]">{{ t('setting.updates.title') }}
|
||||
</div>
|
||||
|
||||
<!-- 当前版本 -->
|
||||
<div class="flex items-center justify-between mb-[16px]">
|
||||
<div>
|
||||
<div class="text-[14px] text-[#525866] dark:text-gray-400 mb-[4px]">当前版本</div>
|
||||
<div class="text-[14px] text-[#525866] dark:text-gray-400 mb-[4px]">{{ t('setting.updates.currentVersion') }}
|
||||
</div>
|
||||
<div class="text-[28px] font-bold text-[#171717] dark:text-gray-100">v{{ updateStore.currentVersion }}</div>
|
||||
</div>
|
||||
<el-button link class="!p-[8px] hover:bg-gray-100 dark:hover:bg-gray-800 rounded-full"
|
||||
@@ -82,43 +91,48 @@
|
||||
<!-- 更新状态卡片 -->
|
||||
<div class="bg-[#F5F7FA] dark:bg-gray-800 rounded-[8px] p-[16px] flex items-center justify-between mb-[16px]">
|
||||
<div class="text-[14px] text-[#525866] dark:text-gray-300">
|
||||
<span v-if="updateStore.status === 'checking'">正在检查更新...</span>
|
||||
<span v-else-if="updateStore.status === 'not-available'">您已拥有最新版本</span>
|
||||
<span v-else-if="updateStore.status === 'available'">发现新版本: v{{ updateStore.updateInfo?.version }}</span>
|
||||
<span v-if="updateStore.status === 'checking'">{{ t('setting.updates.status.checking') }}</span>
|
||||
<span v-else-if="updateStore.status === 'not-available'">{{ t('setting.updates.status.latest') }}</span>
|
||||
<span v-else-if="updateStore.status === 'available'">{{ t('setting.updates.status.available', {
|
||||
version:
|
||||
updateStore.updateInfo?.version
|
||||
}) }}</span>
|
||||
<span v-else-if="updateStore.status === 'downloading'">
|
||||
正在下载新版本... {{ Math.round(updateStore.progress?.percent || 0) }}%
|
||||
{{ t('setting.updates.status.downloading', { percent: Math.round(updateStore.progress?.percent || 0) }) }}
|
||||
</span>
|
||||
<span v-else-if="updateStore.status === 'downloaded'">下载完成,准备安装</span>
|
||||
<span v-else-if="updateStore.status === 'error'" class="text-red-500">更新出错: {{ updateStore.error }}</span>
|
||||
<span v-else>检查更新以获取最新功能</span>
|
||||
<span v-else-if="updateStore.status === 'downloaded'">{{ t('setting.updates.status.downloaded') }}</span>
|
||||
<span v-else-if="updateStore.status === 'error'" class="text-red-500">{{ t('setting.updates.status.failed', {
|
||||
error: updateStore.error
|
||||
}) }}</span>
|
||||
<span v-else>{{ t('setting.updates.status.check') }}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<el-button v-if="updateStore.status === 'available'" type="primary" @click="updateStore.downloadUpdate()">
|
||||
下载更新
|
||||
{{ t('setting.updates.action.download') }}
|
||||
</el-button>
|
||||
<el-button v-else-if="updateStore.status === 'downloaded'" type="success"
|
||||
@click="updateStore.installUpdate()">
|
||||
重启安装
|
||||
{{ t('setting.updates.action.install') }}
|
||||
</el-button>
|
||||
<el-button v-else
|
||||
class="!bg-white dark:!bg-gray-700 !border-[#E5E8EE] dark:!border-gray-600 !text-[#171717] dark:!text-gray-100"
|
||||
@click="updateStore.checkUpdate()">
|
||||
<RiRefreshLine class="w-4 h-4 mr-[4px]" :class="{ 'animate-spin': updateStore.status === 'checking' }" />
|
||||
检查更新
|
||||
{{ t('setting.updates.action.check') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-[12px] text-[#99A0AE] dark:text-gray-500 mb-[32px]">
|
||||
开启自动更新后,更新将自动下载并安装。
|
||||
{{ t('setting.updates.help') }}
|
||||
</div>
|
||||
|
||||
<!-- 自动检查更新 -->
|
||||
<div class="flex items-center justify-between py-[16px] border-b-[1px] border-[#E5E8EE] dark:border-gray-800">
|
||||
<div>
|
||||
<div class="text-[16px] text-[#171717] dark:text-gray-100 mb-[4px]">自动检查更新</div>
|
||||
<div class="text-[14px] text-[#99A0AE] dark:text-gray-500">启动时检查更新</div>
|
||||
<div class="text-[16px] text-[#171717] dark:text-gray-100 mb-[4px]">{{ t('setting.updates.autoCheck') }}</div>
|
||||
<div class="text-[14px] text-[#99A0AE] dark:text-gray-500">{{ t('setting.updates.autoCheckDesc') }}</div>
|
||||
</div>
|
||||
<el-switch v-model="updateStore.autoCheckUpdate" @change="updateStore.setAutoCheckUpdate" />
|
||||
</div>
|
||||
@@ -126,8 +140,9 @@
|
||||
<!-- 自动更新 -->
|
||||
<div class="flex items-center justify-between py-[16px]">
|
||||
<div>
|
||||
<div class="text-[16px] text-[#171717] dark:text-gray-100 mb-[4px]">自动更新</div>
|
||||
<div class="text-[14px] text-[#99A0AE] dark:text-gray-500">自动下载并安装更新</div>
|
||||
<div class="text-[16px] text-[#171717] dark:text-gray-100 mb-[4px]">{{ t('setting.updates.autoDownload') }}
|
||||
</div>
|
||||
<div class="text-[14px] text-[#99A0AE] dark:text-gray-500">{{ t('setting.updates.autoDownloadDesc') }}</div>
|
||||
</div>
|
||||
<el-switch v-model="updateStore.autoDownloadUpdate" @change="updateStore.setAutoDownloadUpdate" />
|
||||
</div>
|
||||
@@ -138,11 +153,17 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import TitleSection from '@src/components/TitleSection/index.vue'
|
||||
import { setLanguage, getLanguage, type LanguageType } from '@src/i18n'
|
||||
import { useThemeStore } from '@src/stores/theme'
|
||||
import { useUpdateStore } from '@src/stores/update'
|
||||
import { RiSunLine, RiMoonLine, RiComputerLine, RiRefreshLine } from '@remixicon/vue'
|
||||
import { useLocaleStore } from '@src/store/locale'
|
||||
import type { LanguageCode } from '@src/i18n/constants'
|
||||
import { SUPPORTED_LANGUAGES } from '@src/i18n/constants'
|
||||
|
||||
const { t } = useI18n()
|
||||
const localeStore = useLocaleStore()
|
||||
|
||||
// 更新状态管理
|
||||
const updateStore = useUpdateStore()
|
||||
@@ -169,23 +190,15 @@ const handleThemeChange = async (theme: 'light' | 'dark' | 'system') => {
|
||||
}
|
||||
|
||||
// 语言设置
|
||||
const supportedLanguages = [
|
||||
{ code: 'zh', label: '中文' },
|
||||
{ code: 'en', label: 'English' },
|
||||
{ code: 'ja', label: '日本語' }
|
||||
] as const
|
||||
|
||||
const currentLanguage = ref<LanguageType>('zh')
|
||||
const currentLanguage = computed(() => localeStore.currentLanguage)
|
||||
|
||||
onMounted(() => {
|
||||
currentLanguage.value = getLanguage() as LanguageType
|
||||
updateStore.init()
|
||||
})
|
||||
|
||||
const handleLanguageChange = async (langCode: LanguageType) => {
|
||||
const handleLanguageChange = async (langCode: LanguageCode) => {
|
||||
if (langCode === currentLanguage.value) return
|
||||
await setLanguage(langCode)
|
||||
currentLanguage.value = langCode
|
||||
await localeStore.setLanguage(langCode)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user