适配多语言

Squashed commit of the following:

commit 632f86c0228c68391c01865c7576f3aa0408c102
Author: Sun <95302870@qq.com>
Date:   Sun Jan 7 14:47:55 2024 +0800

    退出的时候清除appstore

commit b9d805e49a3c6b2ad38bc8d527cb12cc8709012e
Author: Sun <95302870@qq.com>
Date:   Sun Jan 7 13:55:20 2024 +0800

    系统状态监控适配国际化

commit daece99723ec96d210241d2ca4e5a85dc5ae69bd
Author: Sun <95302870@qq.com>
Date:   Sun Jan 7 13:09:46 2024 +0800

    适配添加项目页面的国际化配置还有时钟的星期*

commit 8ea2b2fe951f6266415c96a197cb8d00faef4058
Author: Sun <95302870@qq.com>
Date:   Sun Jan 7 12:01:55 2024 +0800

    完成适配所有apps国际化

commit 21ef54e0d4afb10f560c8cb7aff666374afe0f87
Author: Sun <95302870@qq.com>
Date:   Sat Jan 6 21:36:07 2024 +0800

    增加读取默认浏览器语言

commit 6f710bbebe63ab2800193f27c71e5c0034f11978
Author: Sun <95302870@qq.com>
Date:   Sat Jan 6 21:09:58 2024 +0800

    登录页面增加语言选择选项

commit cb7c4a89a160ed3ef91ad566ec98e75325e7601f
Author: Sun <95302870@qq.com>
Date:   Sat Jan 6 20:37:16 2024 +0800

    首次尝试增加英文语言,并在我的信息设置

commit fb996e17cd11611d30c0e12feee00ddf7b225e32
Author: Sun <95302870@qq.com>
Date:   Sat Jan 6 18:22:40 2024 +0800

    完成基础设置页面的语言国际化适配
This commit is contained in:
Sun
2024-01-07 14:53:53 +08:00
parent ffc378a38f
commit 394c6ce20c
23 changed files with 609 additions and 467 deletions
+5 -5
View File
@@ -35,7 +35,7 @@ onMounted(() => {
</div>
<div class="text-xl">
<NGradientText type="info">
<a href="https://github.com/hslr-s/sun-panel/releases" class="font-semibold" title="点此查看更新说明" target="_blank">v{{ versionName }}</a>
<a href="https://github.com/hslr-s/sun-panel/releases" class="font-semibold" :title="$t('apps.about.viewUpdateLog')" target="_blank">v{{ versionName }}</a>
</NGradientText>
</div>
</div>
@@ -43,19 +43,19 @@ onMounted(() => {
<NDivider> </NDivider>
<div class="flex flex-col items-center justify-center text-base">
<div>
建议反馈<a href="https://github.com/hslr-s/sun-panel/issues" target="_blank" class="link">Github Issues</a>
{{ $t('apps.about.issue') }}<a href="https://github.com/hslr-s/sun-panel/issues" target="_blank" class="link">Github Issues</a>
</div>
<div>
QQ交流群<a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=_I9WIoJn1roIdoaAqelSj9qClLKlXIa1&authKey=GfsQP2GagHnus0jMc7U8Sm6VhWjtsipXUzCHbFwQsGyHMgmYWx6ZbAP%2Bhut%2B4D6N&noverify=0&group_code=276594668" target="_blank" class="link">276594668</a>
{{ $t('apps.about.QQGroup') }}<a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=_I9WIoJn1roIdoaAqelSj9qClLKlXIa1&authKey=GfsQP2GagHnus0jMc7U8Sm6VhWjtsipXUzCHbFwQsGyHMgmYWx6ZbAP%2Bhut%2B4D6N&noverify=0&group_code=276594668" target="_blank" class="link">276594668</a>
|
<span class="link cursor-pointer" @click="qqGroupQRShow = !qqGroupQRShow">
二维码(推荐)
{{ $t('apps.about.QR') }}
</span>
</div>
<div>
开发者<a href="https://blog.enianteam.com/u/sun/content/11" target="_blank" class="link">红烧猎人</a> | <a href="https://github.com/hslr-s/sun-panel/blob/master/doc/donate.md" target="_blank" class="text-red-600 hover:text-red-900">🧧打赏</a>
{{ $t('apps.about.author') }}<a href="https://blog.enianteam.com/u/sun/content/11" target="_blank" class="link">红烧猎人</a> | <a href="https://github.com/hslr-s/sun-panel/blob/master/doc/donate.md" target="_blank" class="text-red-600 hover:text-red-900">{{ $t('apps.about.donate') }}</a>
</div>
<div class="flex mt-[10px]">
+27 -27
View File
@@ -91,9 +91,9 @@ async function importIcons(): Promise<string | null> {
}
catch (error) {
if (error instanceof Error)
return `发生错误: ${error.message}`
return `${t('common.failed')}: ${error.message}`
else
return '发生未知错误'
return t('common.unknownError')
}
}
@@ -162,7 +162,7 @@ function handleFileChange(options: { file: UploadFileInfo; fileList: Array<Uploa
importCheck()
}
else {
ms.error('异常请重新上传')
ms.error(`${t('common.failed')}: ${t('common.repeatLater')}`)
}
uploadLoading.value = false
}
@@ -178,13 +178,13 @@ function importCheck() {
importObj.value = importJsonString(jsonData.value)
if (importObj.value) {
if (!importObj.value.isPassCheckMd5())
importWarning.value.push('文件被修改过,谨慎导入')
importWarning.value.push(t('apps.exportImport.fileModified'))
if (!importObj.value.isPassCheckConfigVersionOld())
importWarning.value.push('配置文件版本过低,但是兼容')
importWarning.value.push(t('apps.exportImport.warnConfigFileLow'))
if (!importObj.value.isPassCheckConfigVersionNew())
importWarning.value.push('当前软件版本可能过旧,很有可能无法兼容该配置文件,请谨慎导入。推荐将软件更新到新版后再次导入')
importWarning.value.push(t('apps.exportImport.softwareVersionLow'))
// (暂时不做)此处可以判断,当前的配置文件是否存在的导入项目(不存在隐藏importItems里面的值)操作变量:importItems
@@ -196,24 +196,24 @@ function importCheck() {
}
catch (error) {
if (error instanceof ConfigVersionLowError) {
ms.error('配置文件版本过低,无法兼容')
console.log('配置文件版本过低')
ms.error(t('apps.exportImport.errorConfigFileLow'))
console.error('The configuration file version is too low to be compatible')
}
else if (error instanceof FormatError) {
ms.error('格式不正确,无法导入')
console.log('格式不正确')
ms.error(t('apps.exportImport.errorConfigFileFormat'))
console.error('The format is incorrect and cannot be imported')
}
}
}
else {
ms.error('数据不正确')
ms.error(t('apps.exportImport.errorConfigFileFormat'))
}
}
// 开始导出
async function handleStartExport() {
loading.value = true
console.log('要导出的项目', checkedItems.value)
// console.log('要导出的项目', checkedItems.value)
// 获取软件版本号
const exportResult = exportJson(version.value)
if (checkedItems.value.includes('icons')) {
@@ -223,7 +223,7 @@ async function handleStartExport() {
console.log('export icons finish', iconGroups)
}
console.log('导出结果')
// console.log('导出结果')
jsonData.value = exportResult.string()
exportResult.exportFile()
@@ -244,14 +244,14 @@ async function handleStartImport() {
loading.value = false
importRoundModalShow.value = false
ms.success(`${t('common.success')},请手动刷新页面`)
ms.success(`${t('common.success')}, ${t('common.refreshPage')}`)
}
</script>
<template>
<div class="pt-2">
<NAlert type="info" :bordered="false">
<p>导入图标配置数据不会清空现有图标数据</p>
<p>{{ $t('apps.exportImport.tip') }}</p>
</NAlert>
<div class="flex justify-center m-[50px]">
<div class="m-[10px]">
@@ -266,7 +266,7 @@ async function handleStartImport() {
<template #icon>
<SvgIcon icon="fa6:solid-file-import" />
</template>
导入配置
{{ $t('apps.exportImport.import') }}
</NButton>
</NUpload>
</div>
@@ -275,7 +275,7 @@ async function handleStartImport() {
<template #icon>
<SvgIcon icon="fa6:solid-file-export" />
</template>
导出配置
{{ $t('apps.exportImport.export') }}
</NButton>
</div>
</div>
@@ -310,7 +310,7 @@ async function handleStartImport() {
</div>
</div>
<RoundCardModal v-model:show="importRoundModalShow" style="max-width: 400px;" title="导入">
<RoundCardModal v-model:show="importRoundModalShow" style="max-width: 400px;" :title=" $t('apps.exportImport.import')">
<div v-if="importWarning.length > 0">
<NAlert :title="$t('common.warning')" type="warning">
<div v-for="(text, index) in importWarning " :key="index">
@@ -319,39 +319,39 @@ async function handleStartImport() {
</NAlert>
</div>
<NDivider title-placement="left">
请选择要导入的配置数据
{{ $t('apps.exportImport.selectImportData') }}
</NDivider>
<NSpace justify="center" style="margin-top: 20px;">
<NCheckboxGroup v-model:value="checkedItems">
<NCheckbox v-if="importItems.includes('icons')" value="icons" label="图标" />
<NCheckbox v-if="importItems.includes('style')" value="style" label="样式配置" />
<NCheckbox v-if="importItems.includes('icons')" value="icons" :label="$t('apps.exportImport.moduleIcon')" />
<NCheckbox v-if="importItems.includes('style')" value="style" :label="$t('apps.exportImport.moduleStyle')" />
</NCheckboxGroup>
</NSpace>
<NSpace justify="center">
<div class="mt-[50px]">
<NButton type="success" :disabled="checkedItems.length === 0" :loading="loading" @click="handleStartImport">
继续导入
{{ $t('common.continue') }}
</NButton>
</div>
</NSpace>
</RoundCardModal>
<RoundCardModal v-model:show="exportRoundModalShow" style="max-width: 400px;" title="导出">
<RoundCardModal v-model:show="exportRoundModalShow" style="max-width: 400px;" :title=" $t('apps.exportImport.export')">
<NDivider title-placement="left">
请选择要导出的配置数据
{{ $t('apps.exportImport.selectExportData') }}
</NDivider>
<NSpace justify="center" style="margin-top: 20px;">
<NCheckboxGroup v-model:value="checkedItems">
<NCheckbox v-if="importItems.includes('icons')" value="icons" label="图标" />
<NCheckbox v-if="importItems.includes('style')" value="style" label="样式配置" />
<NCheckbox v-if="importItems.includes('icons')" value="icons" :label="$t('apps.exportImport.moduleIcon')" />
<NCheckbox v-if="importItems.includes('style')" value="style" :label="$t('apps.exportImport.moduleStyle')" />
</NCheckboxGroup>
</NSpace>
<NSpace justify="center">
<div class="mt-[50px]">
<NButton type="success" :disabled="checkedItems.length === 0" :loading="loading" @click="handleStartExport">
继续导出
{{ $t('common.continue') }}
</NButton>
</div>
</NSpace>
+15 -14
View File
@@ -5,6 +5,7 @@ import { NButton, NCard, NForm, NFormItem, NInput, useDialog, useMessage } from
import { VueDraggable } from 'vue-draggable-plus'
import { deletes, edit, getList, saveSort } from '@/api/panel/itemIconGroup'
import { RoundCardModal, SvgIcon } from '@/components/common'
import { t } from '@/locales'
interface EditModalArg {
show: boolean
@@ -33,7 +34,7 @@ const editModalArg = ref<EditModalArg>({
{
required: true,
trigger: 'blur',
message: '必填项',
message: t('form.required'),
},
],
},
@@ -66,26 +67,26 @@ function handleSaveSort() {
}
saveSort(saveItems).then(({ code, msg }) => {
if (code === 0) {
ms.success('保存成功')
ms.success(t('common.saveSuccess'))
sortStatus.value = false
}
else {
ms.error(`保存失败:${msg}`)
ms.error(`${t('common.saveFail')}:${msg}`)
}
})
}
function handleDelete(groupInfo: Panel.ItemIconGroup) {
dialog.warning({
title: '警告',
content: `你确定删除此分组[ ${groupInfo.title} ],删除后此分组应用图标将丢失?`,
positiveText: '确定',
negativeText: '取消',
title: t('common.warning'),
content: t('apps.itemGroupManage.deleteWarnText', { name: groupInfo.title }),
positiveText: t('common.confirm'),
negativeText: t('common.cancel'),
onPositiveClick: () => {
if (groupInfo.id) {
deletes([groupInfo.id]).then(({ code, msg }) => {
if (code !== 0)
ms.error(`删除失败:${msg}`)
ms.error(t('common.deleteFail'))
else
refreshList()
})
@@ -126,15 +127,15 @@ onMounted(() => {
<div class="h-full">
<div class="p-2">
<NButton type="success" size="small" style="margin-right: 10px;" @click="handleAddGroup">
新增分组
{{ $t('common.add') }}
</NButton>
<NButton v-if="!sortStatus" size="small" @click="handleDragSort">
排序
{{ $t('common.sort') }}
</NButton>
<NButton v-else type="warning" size="small" @click="handleSaveSort">
保存排序
{{ $t('common.saveSort') }}
</NButton>
</div>
@@ -181,8 +182,8 @@ onMounted(() => {
<RoundCardModal v-model:show="editModalArg.show" size="small" type="small" :title="editModalArg.editStatus === 1 ? '添加' : '编辑'" style="width: 400px;">
<NForm ref="formRef" :model="editModalArg.model" :rules="editModalArg.rules">
<NFormItem path="title" label="分组名称">
<NInput v-model:value="editModalArg.model.title" type="text" :maxlength="20" show-count placeholder="请输入" />
<NFormItem path="title" :label="$t('apps.itemGroupManage.groupName')">
<NInput v-model:value="editModalArg.model.title" type="text" :maxlength="20" show-count />
</NFormItem>
<!-- <NFormItem path="name" label="昵称">
@@ -191,7 +192,7 @@ onMounted(() => {
</NForm>
<template #footer>
<NButton type="success" size="small" class="float-right" @click="handleSaveGroup">
确定
{{ $t('common.confirm') }}
</NButton>
</template>
</RoundCardModal>
+33 -32
View File
@@ -5,6 +5,7 @@ import { NButton, NCard, NColorPicker, NGrid, NGridItem, NInput, NInputGroup, NP
import { useAuthStore, usePanelState } from '@/store'
import { set as setUserConfig } from '@/api/panel/userConfig'
import { PanelPanelConfigStyleEnum } from '@/enums/panel'
import { t } from '@/locales'
const authStore = useAuthStore()
const panelState = usePanelState()
@@ -14,11 +15,11 @@ const isSaveing = ref(false)
const iconTypeOptions = [
{
label: '详情图标',
label: t('apps.baseSettings.detailIcon'),
value: PanelPanelConfigStyleEnum.info,
},
{
label: '小图标',
label: t('apps.baseSettings.smallIcon'),
value: PanelPanelConfigStyleEnum.icon,
},
]
@@ -61,9 +62,9 @@ function handleUploadBackgroundFinish({
function uploadCloud() {
setUserConfig({ panel: panelState.panelConfig }).then((res) => {
if (res.code === 0)
ms.success('配置已保存')
ms.success(t('apps.baseSettings.configSaved'))
else
ms.error(`配置已保存${res.msg}`)
ms.error(t('apps.baseSettings.configFailed', { message: res.msg }))
})
}
@@ -82,7 +83,7 @@ function resetPanelConfig() {
<div>
<div>
文本内容
{{ $t('apps.baseSettings.textContent') }}
</div>
<div class="flex items-center mt-[5px]">
<NInput v-model:value="panelState.panelConfig.logoText" type="text" show-count :maxlength="20" placeholder="请输入文字" />
@@ -92,53 +93,53 @@ function resetPanelConfig() {
<NCard style="border-radius:10px" class="mt-[10px]" size="small">
<div class="text-slate-500 mb-[5px] font-bold">
时钟
{{ $t('apps.baseSettings.clock') }}
</div>
<div class="flex items-center mt-[5px]">
<span class="mr-[10px]">显示秒</span>
<span class="mr-[10px]">{{ $t('apps.baseSettings.clockSecondShow') }}</span>
<NSwitch v-model:value="panelState.panelConfig.clockShowSecond" />
</div>
</NCard>
<NCard style="border-radius:10px" class="mt-[10px]" size="small">
<div class="text-slate-500 mb-[5px] font-bold">
搜索框
{{ $t('apps.baseSettings.searchBar') }}
</div>
<div class="flex items-center mt-[5px]">
<span class="mr-[10px]">显示</span>
<span class="mr-[10px]">{{ $t('common.show') }}</span>
<NSwitch v-model:value="panelState.panelConfig.searchBoxShow" />
</div>
<div v-if="panelState.panelConfig.searchBoxShow" class="flex items-center mt-[5px]">
<span class="mr-[10px]">允许搜索快捷图标</span>
<span class="mr-[10px]">{{ $t('apps.baseSettings.searchBarSearchItem') }}</span>
<NSwitch v-model:value="panelState.panelConfig.searchBoxSearchIcon" />
</div>
</NCard>
<NCard style="border-radius:10px" class="mt-[10px]" size="small">
<div class="text-slate-500 mb-[5px] font-bold">
系统监控
{{ $t('apps.baseSettings.systemMonitorStatus') }}
</div>
<div class="flex items-center mt-[5px]">
<span class="mr-[10px]">显示</span>
<span class="mr-[10px]">{{ $t('common.show') }}</span>
<NSwitch v-model:value="panelState.panelConfig.systemMonitorShow" />
</div>
<div v-if="panelState.panelConfig.systemMonitorShow" class="flex items-center mt-[5px]">
<span class="mr-[10px]">显示标题</span>
<span class="mr-[10px]">{{ $t('apps.baseSettings.showTitle') }}</span>
<NSwitch v-model:value="panelState.panelConfig.systemMonitorShowTitle" />
</div>
<div v-if="panelState.panelConfig.systemMonitorShow" class="flex items-center mt-[5px]">
<span class="mr-[10px]">公开模式允许显示</span>
<span class="mr-[10px]">{{ $t('apps.baseSettings.publicVisitModeShow') }}</span>
<NSwitch v-model:value="panelState.panelConfig.systemMonitorPublicVisitModeShow" />
</div>
</NCard>
<NCard style="border-radius:10px" class="mt-[10px]" size="small">
<div class="text-slate-500 mb-[5px] font-bold">
图标
{{ $t('common.icon') }}
</div>
<div class="mt-[5px]">
<div>
样式
{{ $t('common.style') }}
</div>
<div class="flex items-center mt-[5px]">
<NSelect v-model:value="panelState.panelConfig.iconStyle" :options="iconTypeOptions" />
@@ -147,7 +148,7 @@ function resetPanelConfig() {
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.info" class="mt-[5px]">
<div>
隐藏描述信息
{{ $t('apps.baseSettings.hideDescription') }}
</div>
<div class="flex items-center mt-[5px]">
<NSwitch v-model:value="panelState.panelConfig.iconTextInfoHideDescription" />
@@ -156,7 +157,7 @@ function resetPanelConfig() {
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.icon" class="mt-[5px]">
<div>
隐藏标题
{{ $t('apps.baseSettings.hideTitle') }}
</div>
<div class="flex items-center mt-[5px]">
<NSwitch v-model:value="panelState.panelConfig.iconTextIconHideTitle" />
@@ -165,7 +166,7 @@ function resetPanelConfig() {
<div class="mt-[5px]">
<div>
文字颜色
{{ $t('common.textColor') }}
</div>
<div class="flex items-center mt-[5px]">
<NColorPicker
@@ -186,7 +187,7 @@ function resetPanelConfig() {
</NCard>
<NCard style="border-radius:10px" class="mt-[10px]" size="small">
<div class="text-slate-500 mb-[5px] font-bold">
壁纸
{{ $t('apps.baseSettings.customFooter') }}
</div>
<NUpload
action="/api/file/uploadImg"
@@ -204,32 +205,32 @@ function resetPanelConfig() {
:style="{ background: `url(${panelState.panelConfig.backgroundImageSrc}) no-repeat`, backgroundSize: 'cover' }"
>
<div class="text-shadow text-white">
点击上传替换图片或拖拽到框内
{{ $t('apps.baseSettings.uploadOrDragText') }}
</div>
</div>
</NUploadDragger>
</NUpload>
<div class="flex items-center mt-[10px]">
<span class="mr-[10px]">模糊</span>
<span class="mr-[10px]">{{ $t('apps.baseSettings.vague') }}</span>
<NSlider v-model:value="panelState.panelConfig.backgroundBlur" class="max-w-[200px]" :step="2" :max="20" />
</div>
<div class="flex items-center mt-[10px]">
<span class="mr-[10px]">遮罩</span>
<span class="mr-[10px]">{{ $t('apps.baseSettings.mask') }}</span>
<NSlider v-model:value="panelState.panelConfig.backgroundMaskNumber" class="max-w-[200px]" :step="0.1" :max="1" />
</div>
</NCard>
<NCard style="border-radius:10px" class="mt-[10px]" size="small">
<div class="text-slate-500 mb-[5px] font-bold">
内容区域
{{ $t('apps.baseSettings.contentArea') }}
</div>
<NGrid cols="2">
<NGridItem span="12 400:12">
<div class="flex items-center mt-[10px]">
<span class="mr-[10px]">最大宽度</span>
<span class="mr-[10px]">{{ $t('apps.baseSettings.maxWidth') }}</span>
<div class="flex">
<NInputGroup>
<NInput v-model:value="panelState.panelConfig.maxWidth" size="small" type="number" :maxlength="10" :style="{ width: '100px' }" placeholder="1200" />
@@ -240,19 +241,19 @@ function resetPanelConfig() {
</NGridItem>
<NGridItem span="12 400:12">
<div class="flex items-center mt-[10px]">
<span class="mr-[10px]">左右边距</span>
<span class="mr-[10px]">{{ $t('apps.baseSettings.leftRightMargin') }}</span>
<NSlider v-model:value="panelState.panelConfig.marginX" class="max-w-[200px]" :step="1" :max="100" />
</div>
</NGridItem>
<NGridItem span="12 400:12">
<div class="flex items-center mt-[10px]">
<span class="mr-[10px]">上边距 (%)</span>
<span class="mr-[10px]">{{ $t('apps.baseSettings.topMargin') }} (%)</span>
<NSlider v-model:value="panelState.panelConfig.marginTop" class="max-w-[200px]" :step="1" :max="50" />
</div>
</NGridItem>
<NGridItem span="12 400:6">
<div class="flex items-center mt-[10px]">
<span class="mr-[10px]">下边距 (%)</span>
<span class="mr-[10px]">{{ $t('apps.baseSettings.bottomMargin') }} (%)</span>
<NSlider v-model:value="panelState.panelConfig.marginBottom" class="max-w-[200px]" :step="1" :max="50" />
</div>
</NGridItem>
@@ -261,7 +262,7 @@ function resetPanelConfig() {
<NCard style="border-radius:10px" class="mt-[10px]" size="small">
<div class="text-slate-500 mb-[5px] font-bold">
自定义footer
{{ $t('apps.baseSettings.customFooter') }}
</div>
<NInput
@@ -276,14 +277,14 @@ function resetPanelConfig() {
>
<template #trigger>
<NButton size="small" quaternary type="error">
重置
{{ $t('common.reset') }}
</NButton>
</template>
确定要重置这些样式吗
{{ $t('apps.baseSettings.resetWarnText') }}
</NPopconfirm>
<NButton size="small" quaternary type="success" class="ml-[10px]" @click="uploadCloud">
立即保存
{{ $t('common.save') }}
</NButton>
</NCard>
</div>
+22 -4
View File
@@ -1,10 +1,11 @@
<script setup lang="ts">
import type { FormInst, FormRules } from 'naive-ui'
import { NButton, NCard, NDivider, NForm, NFormItem, NInput, useDialog, useMessage } from 'naive-ui'
import { NButton, NCard, NDivider, NForm, NFormItem, NInput, NSelect, useDialog, useMessage } from 'naive-ui'
import { ref } from 'vue'
import { useAuthStore, usePanelState, useUserStore } from '@/store'
import { useAppStore, useAuthStore, usePanelState, useUserStore } from '@/store'
import { languageOptions } from '@/utils/defaultData'
import type { Language } from '@/store/modules/app/helper'
import { logout } from '@/api'
import { router } from '@/router'
import { RoundCardModal, SvgIcon } from '@/components/common/'
import { updateInfo, updatePassword } from '@/api/system/user'
import { updateLocalUserInfo } from '@/utils/cmn'
@@ -12,10 +13,12 @@ import { t } from '@/locales'
const userStore = useUserStore()
const authStore = useAuthStore()
const appStore = useAppStore()
const panelState = usePanelState()
const ms = useMessage()
const dialog = useDialog()
const languageValue = ref(appStore.language)
const nickName = ref(authStore.userInfo?.name || '')
const isEditNickNameStatus = ref(false)
const formRef = ref<FormInst | null>(null)
@@ -59,8 +62,9 @@ async function logoutApi() {
userStore.resetUserInfo()
authStore.removeToken()
panelState.removeState()
appStore.removeToken()
ms.success(t('settingUserInfo.logoutSuccess'))
router.push({ path: '/login' })
// router.push({ path: '/login' })
location.reload()// 强制刷新一下页面
}
@@ -122,6 +126,12 @@ function handleLogout() {
},
})
}
function handleChangeLanuage(value: Language) {
languageValue.value = value
appStore.setLanguage(value)
location.reload()
}
</script>
<template>
@@ -157,6 +167,14 @@ function handleLogout() {
</div>
</div>
<div class="mt-[10px]">
<div class="text-slate-500 font-bold">
{{ $t('common.language') }}
</div>
<div class="max-w-[200px]">
<NSelect v-model:value="languageValue" :options="languageOptions" @update-value="handleChangeLanuage" />
</div>
</div>
<NDivider style="margin: 10px 0;" dashed />
<div>
<NButton size="small" text type="info" @click="updatePasswordModalState.show = !updatePasswordModalState.show">
+12 -3
View File
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue'
import { t } from '@/locales'
const props = defineProps<{
hideSecond?: boolean
@@ -35,7 +36,15 @@ function updateCurrentDate() {
const month = now.getMonth() + 1 // 月份从0开始,所以要加1
// const year = now.getFullYear()
const daysOfWeek = ['日', '一', '二', '三', '四', '五', '六']
const daysOfWeek = [
t('deskModule.clock.sun'),
t('deskModule.clock.mon'),
t('deskModule.clock.tue'),
t('deskModule.clock.wed'),
t('deskModule.clock.thu'),
t('deskModule.clock.fri'),
t('deskModule.clock.sat'),
]
// const daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
currentDate.value.week = daysOfWeek[now.getDay()]
currentDate.value.date = `${month}-${day}`
@@ -63,11 +72,11 @@ onBeforeUnmount(() => {
{{ currentDate.time }}
</span>
<div class="hidden sm:hidden md:block">
<span>
<span class="mr-1">
{{ currentDate.date }}
</span>
<span>
星期{{ currentDate.week }}
{{ currentDate.week }}
</span>
</div>
</div>
@@ -103,19 +103,19 @@ onMounted(() => {
</div>
<NForm ref="formRef" v-model="extendParam">
<NFormItem label="磁盘挂载点">
<NFormItem :label="$t('deskModule.systemMonitor.diskMountPoint')">
<NSelect v-model:value="extendParam.path" size="small" :options="mountPointList" />
</NFormItem>
<NFormItem label="主色">
<NFormItem :label="$t('deskModule.systemMonitor.progressColor')">
<NColorPicker v-model:value="extendParam.progressColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
</NFormItem>
<NFormItem label="副色">
<NFormItem :label="$t('deskModule.systemMonitor.progressRailColor')">
<NColorPicker v-model:value="extendParam.progressRailColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
</NFormItem>
<NFormItem label="文字图标颜色">
<NFormItem :label="$t('common.textColor')">
<NColorPicker v-model:value="extendParam.color" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
</NFormItem>
<NFormItem label="卡片背景色">
<NFormItem :label="$t('common.backgroundColor')">
<NColorPicker v-model:value="extendParam.backgroundColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
</NFormItem>
</NForm>
@@ -74,16 +74,16 @@ const data = computed({
</div>
<NForm ref="formRef" v-model="data">
<NFormItem label="主色">
<NFormItem :label="$t('deskModule.systemMonitor.progressColor')">
<NColorPicker v-model:value="data.progressColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
</NFormItem>
<NFormItem label="副色">
<NFormItem :label="$t('deskModule.systemMonitor.progressRailColor')">
<NColorPicker v-model:value="data.progressRailColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
</NFormItem>
<NFormItem label="文字图标颜色">
<NFormItem :label="$t('common.textColor')">
<NColorPicker v-model:value="data.color" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
</NFormItem>
<NFormItem label="卡片背景色">
<NFormItem :label="$t('common.backgroundColor')">
<NColorPicker v-model:value="data.backgroundColor" :swatches="defautSwatchesBackground" :modes="['hex']" size="small" />
</NFormItem>
</NForm>
@@ -7,6 +7,7 @@ import { add, saveByIndex } from '../common'
import GenericProgressStyleEditor from './GenericProgressStyleEditor/index.vue'
import DiskEditor from './DiskEditor/index.vue'
import { t } from '@/locales'
interface Props {
visible: boolean
@@ -84,7 +85,7 @@ async function handleSubmit() {
else if (currentMonitorData.value.monitorType === MonitorType.disk)
currentMonitorData.value.extendParam = currentDiskExtendParam
console.log('保存', currentMonitorData.value.extendParam)
// console.log('保存', currentMonitorData.value.extendParam)
if (props.index !== null) {
const res = await saveByIndex(props.index, currentMonitorData.value)
@@ -93,7 +94,7 @@ async function handleSubmit() {
emit('done', true)
}
else {
ms.error('保存失败')
ms.error(t('common.saveFail'))
}
}
else {
@@ -103,43 +104,36 @@ async function handleSubmit() {
emit('done', true)
}
else {
ms.error('保存失败')
ms.error(t('common.saveFail'))
}
}
}
</script>
<template>
<NModal v-model:show="show" preset="card" size="small" style="width: 600px;border-radius: 1rem;" :title="monitorData ? '修改项目' : '添加项目'">
<NModal v-model:show="show" preset="card" size="small" style="width: 600px;border-radius: 1rem;" :title="monitorData ? t('common.edit') : t('common.add')">
<!-- 选择监视器 -->
<!-- <div>
{{ JSON.stringify(currentGenericProgressStyleExtendParam) }}
{{ JSON.stringify(currentDiskExtendParam) }}
</div> -->
<NTabs v-model:value="active" type="segment">
<NTabPane :name="MonitorType.cpu" tab="CPU状态">
<NTabPane :name="MonitorType.cpu" :tab="$t('deskModule.systemMonitor.cpuState')">
<GenericProgressStyleEditor v-model:genericProgressStyleExtendParam="currentGenericProgressStyleExtendParam" />
<NButton @click="handleResetExtendParam">
重置
</NButton>
</NTabPane>
<NTabPane :name="MonitorType.memory" tab="内存状态">
<NTabPane :name="MonitorType.memory" :tab="$t('deskModule.systemMonitor.memoryState')">
<GenericProgressStyleEditor v-model:genericProgressStyleExtendParam="currentGenericProgressStyleExtendParam" />
<NButton @click="handleResetExtendParam">
重置
</NButton>
</NTabPane>
<NTabPane :name="MonitorType.disk" tab="磁盘状态">
<NTabPane :name="MonitorType.disk" :tab="$t('deskModule.systemMonitor.diskState')">
<DiskEditor v-model:disk-extend-param="currentDiskExtendParam" />
<NButton @click="handleResetExtendParam">
重置
</NButton>
</NTabPane>
</NTabs>
<NButton @click="handleResetExtendParam">
{{ t('common.reset') }}
</NButton>
<template #footer>
<NButton type="success" :loading="submitLoading" style="float: right;" @click="handleSubmit">
确定
{{ t('common.confirm') }}
</NButton>
</template>
</NModal>
@@ -1,171 +0,0 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import { NProgress } from 'naive-ui'
import { getAll } from '@/api/system/systemMonitor'
import { SvgIcon } from '@/components/common'
import { bytesToSize } from '@/utils/cmn'
interface ProgressStyle {
color: string
railColor: string
height: number
}
const systemMonitorData = ref<SystemMonitor.GetAllRes | null>(null)
const progressStyle = ref<ProgressStyle>({
color: 'white',
railColor: 'rgba(0, 0, 0, 0.5)',
height: 5,
})
const svgStyle = {
width: '25px',
height: '25px',
}
async function getData() {
try {
const { data, code } = await getAll<SystemMonitor.GetAllRes>()
if (code === 0)
systemMonitorData.value = data
}
catch (error) {
}
}
function correctionNumber(v: number, keepNum = 2): number {
return v === 0 ? 0 : Number(v.toFixed(keepNum))
}
function formatMemorySize(v: number): string {
return bytesToSize(v)
}
function formatdiskSize(v: number): string {
return bytesToSize(v)
}
function formatdiskToByte(v: number): number {
return v * 1024 * 1024
}
onMounted(() => {
getData()
// timer = setInterval(() => {
// getData()
// }, 5000)
})
onUnmounted(() => {
// clearInterval(timer)
})
</script>
<template>
<div class="w-full system-monitor flex items-center px-2 text-white overflow-auto">
<!-- <div class="flex flex-col items-center justify-center ">
<div>
<NProgress type="dashboard" :percentage="correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0)" :stroke-width="15" style="width: 50px;">
<div class="text-white text-xs">
{{ correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0, 1) }}%
</div>
</NProgress>
</div>
<span>
CPU
</span>
</div> -->
<div class="text-xs mr-10 flex justify-center items-center">
<div class="mr-2">
<SvgIcon icon="solar-cpu-bold" :style="svgStyle" />
</div>
<div>
<div class="mb-1">
<span>
CPU
</span>
<span class="float-right">
{{ correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0) }}%
</span>
</div>
<NProgress
type="line"
:color="progressStyle.color"
:rail-color="progressStyle.railColor"
:height="progressStyle.height"
:percentage="correctionNumber(systemMonitorData?.cpuInfo.usages[0] || 0)"
:show-indicator="false"
:stroke-width="15"
style="width: 150px;"
/>
</div>
</div>
<div class="text-xs mr-10 flex justify-center items-center">
<div class="mr-2">
<SvgIcon icon="material-symbols-memory-alt-rounded" :style="svgStyle" />
</div>
<div>
<div class="mb-1">
<span>
RAM
</span>
<span class="float-right">
{{ formatMemorySize(systemMonitorData?.memoryInfo.total || 0) }}/{{ formatMemorySize(systemMonitorData?.memoryInfo.free || 0) }}
</span>
</div>
<NProgress
type="line"
:color="progressStyle.color"
:rail-color="progressStyle.railColor"
:height="progressStyle.height"
:percentage="systemMonitorData?.memoryInfo.usedPercent"
:show-indicator="false"
:stroke-width="15" style="width: 150px;"
/>
</div>
</div>
<!-- <div class="text-xs mr-2">
<div class="mb-1">
<span>
网络:{{ systemMonitorData?.netIOCountersInfo[0].name }}
</span>
</div>
<div>
<span class="float-right">
上行{{ netIOToKB(systemMonitorData?.netIOCountersInfo[0].bytesSent || 0) }}
下行{{ netIOToKB(systemMonitorData?.netIOCountersInfo[0].bytesRecv || 0) }}
</span>
</div>
</div> -->
<!-- 磁盘信息 -->
<div v-for=" item, index in systemMonitorData?.diskInfo" :key="index">
<div class="text-xs mr-10 flex justify-center items-center">
<div class="mr-2">
<SvgIcon icon="clarity-hard-disk-solid" :style="svgStyle" />
</div>
<div>
<div class="mb-1">
<span>
{{ item.mountpoint }}
</span>
<span class="float-right">
{{ formatdiskSize(formatdiskToByte(item.total || 0)) }}/{{ formatdiskSize(formatdiskToByte(item.free || 0)) }}
</span>
</div>
<NProgress
:color="progressStyle.color"
:rail-color="progressStyle.railColor"
:height="progressStyle.height"
type="line"
:percentage="item.usedPercent"
:show-indicator="false"
:stroke-width="15"
style="width: 150px;"
/>
</div>
</div>
</div>
</div>
</template>
@@ -149,10 +149,10 @@ function handleRightMenuSelect(key: string | number) {
switch (key) {
case 'delete':
dialog.warning({
title: '警告',
content: '你确定要删除吗?',
positiveText: '确定',
negativeText: '取消',
title: t('common.warning'),
content: t('common.deleteConfirm'),
positiveText: t('common.confirm'),
negativeText: t('common.cancel'),
onPositiveClick: () => {
if (monitorDatas.value.length <= 1) {
ms.warning(t('common.leastOne'))
@@ -181,17 +181,17 @@ function handleRightMenuSelect(key: string | number) {
<!-- 分组标题 -->
<div class="text-white text-xl font-extrabold mb-[20px] ml-[10px] flex items-center">
<span v-if="showTitle" class="text-shadow">
系统状态
{{ $t('deskModule.systemMonitor.systemState') }}
</span>
<div
v-if="allowEdit"
class="ml-2 delay-100 transition-opacity flex"
:class="monitorGroup.hoverStatus ? 'opacity-100' : 'opacity-0'"
>
<span class="mr-2 cursor-pointer" title="添加快捷图标" @click="handleAddItem()">
<span class="mr-2 cursor-pointer" @click="handleAddItem()">
<SvgIcon class="text-white font-xl" icon="typcn:plus" />
</span>
<span class="mr-2 cursor-pointer " title="排序组快捷图标" @click="handleSetSortStatus(!monitorGroup.sortStatus)">
<span class="mr-2 cursor-pointer" @click="handleSetSortStatus(!monitorGroup.sortStatus)">
<SvgIcon class="text-white font-xl" icon="ri:drag-drop-line" />
</span>
</div>
@@ -259,7 +259,7 @@ function handleRightMenuSelect(key: string | number) {
<SvgIcon class="text-white font-xl" icon="material-symbols:save" />
</template>
<div>
保存排序
{{ $t('common.saveSort') }}
</div>
</NButton>
</div>