更新v1.3.0-beta24-01-25

Squashed commit of the following:

commit 66d0e5e94c0394d83b47b58bd130ba2addce2930
Author: Sun <95302870@qq.com>
Date:   Thu Jan 25 13:20:34 2024 +0800

    更新1.3.0-beta24-01-25

commit 52a81e5f558b3e7b329f828adbd8255960dd750b
Author: Sun <95302870@qq.com>
Date:   Thu Jan 25 13:13:08 2024 +0800

    Squashed commit of the following:

    commit 908d87357c4e22868eff85f377bb8cd22f3785d7
    Author: Sun <95302870@qq.com>
    Date:   Thu Jan 25 13:12:14 2024 +0800

        增加前端版本号

    commit 8ed2b636476c7a14ae4e1761f7712949b7ce60fc
    Author: Sun <95302870@qq.com>
    Date:   Thu Jan 25 12:29:49 2024 +0800

        增加自动获取前端版本号的git tag

commit ba7d70f9cabf020ab9ce682be5e593b649aed071
Author: Sun <95302870@qq.com>
Date:   Thu Jan 25 10:58:15 2024 +0800

    优化代码

commit 104543b96fb4d5f9362d29da22390d9a0565c395
Author: Sun <95302870@qq.com>
Date:   Wed Jan 24 21:28:31 2024 +0800

    增加系统状态组件的部分样式

commit 70c87c94c688a14d3bbe53be191c2186ec469a01
Author: Sun <95302870@qq.com>
Date:   Wed Jan 24 20:55:05 2024 +0800

    时间组件和搜索栏组件增加样式类型

commit 6bab5a264fdb1281763d73bf022335667845dc67
Author: Sun <95302870@qq.com>
Date:   Wed Jan 24 20:41:33 2024 +0800

    将项目列表增加样式并优化减少dom嵌套

commit 99d18df7f0a57ec1cead9bce7b2b4b11427cc2e2
Author: Sun <95302870@qq.com>
Date:   Wed Jan 24 20:11:07 2024 +0800

    增加系统状态、logo等类名并简化部分组件dom

commit bf1cc0cc0014f751b6453ebfb357b575b0a54615
Author: Sun <95302870@qq.com>
Date:   Wed Jan 24 17:17:41 2024 +0800

    更新关于页面

commit fceacf58b87b988827f0baa6086e8296c843c495
Author: Sun <95302870@qq.com>
Date:   Wed Jan 24 14:54:37 2024 +0800

    增加隐藏网络模式切换开关

commit e0dcc49f5b23618103c5ee15e13758164d2eddf2
Author: Sun <95302870@qq.com>
Date:   Wed Jan 24 13:55:28 2024 +0800

    优化部分错误码

commit 863cdf0fc1fc406304784d4304ba6be31e5133ff
Author: Sun <95302870@qq.com>
Date:   Wed Jan 24 12:54:55 2024 +0800

    声明暴露端口

commit 5b25ef9c194dc0112cd10250c04344dd6f57be27
Author: Sun <95302870@qq.com>
Date:   Wed Jan 24 12:38:48 2024 +0800

    修改命令行所有的输出内容为英文
This commit is contained in:
Sun 2024-01-25 13:21:47 +08:00
parent d11e7b24e0
commit 956e645144
37 changed files with 281 additions and 229 deletions

View File

@ -55,6 +55,8 @@ COPY --from=server_image /build/sun-panel /app/sun-panel
# 中国国内源
# RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories
EXPOSE 3002
RUN apk add --no-cache bash ca-certificates su-exec tzdata \
&& chmod +x ./sun-panel \
&& ./sun-panel -config

28
add-frontend-version.js Normal file
View File

@ -0,0 +1,28 @@
const fs = require('fs')
// const { execSync } = require('child_process')
const moment = require('moment')
// git 最新标签
// const latestTag = execSync('git describe --tags --abbrev=0').toString().trim()
const packDate = moment().format('YYYYMMDD-HH')
// 要追加的内容
const contentToAppend = `\nVITE_APP_VERSION=${packDate}`
// 读取文件原始内容
const envFilePath = '.env'
let envContent = fs.readFileSync(envFilePath, 'utf-8')
const versionRegex = /^VITE_APP_VERSION=.*$/m
if (versionRegex.test(envContent)) {
// 使用正则表达式查找并替换 VITE_APP_VERSION=* 这一行
envContent = envContent.replace(versionRegex, contentToAppend)
}
else {
// 追加内容
envContent = envContent + contentToAppend
}
// 将新内容写回 .env 文件
fs.writeFileSync(envFilePath, envContent)
console.log('update to .env file.', contentToAppend)

View File

@ -1,18 +1,17 @@
{
"name": "sun-panel",
"version": "2.10.9",
"version": "0.0.0",
"private": false,
"description": "ChatGPT Web",
"author": "ChenZhaoYu <chenzhaoyu1994@gmail.com>",
"description": "Sun-Panel Web",
"author": "BraisedHunter <95302870@qq.com>",
"keywords": [
"Sun-Panel",
"chatgpt",
"chatbot",
"vue"
],
"scripts": {
"dev": "vite",
"build": "run-p type-check build-only",
"build": "run-p add-version type-check build-only",
"add-version": "node ./add-frontend-version.js",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit",

View File

@ -1,12 +1,15 @@
package apiReturn
var ErrorCodeMap = map[int]string{
// -1:操作失败
// -1:操作失败(前端会自动弹窗)
// 100: "operation failed",
1000: "Not logged in yet", // 还未登录
1003: "Incorrect username or password", // 用户名或密码错误
1004: "Account disabled or not activated", // 账号已停用或未激活
1005: "No current permission for operation", // 当前无权限操作
1006: "Account does not exist", // 账号不存在
1007: "Old password error", // 旧密码不正确
// 数据类
1200: "Database error", // 数据库错误

View File

@ -28,7 +28,8 @@ func (a *ItemIcon) Edit(c *gin.Context) {
}
if req.ItemIconGroupId == 0 {
apiReturn.Error(c, "Group is mandatory")
// apiReturn.Error(c, "Group is mandatory")
apiReturn.ErrorParamFomat(c, "Group is mandatory")
return
}

View File

@ -97,7 +97,7 @@ func (a *UserApi) UpdatePasssword(c *gin.Context) {
} else {
if v.Password != cmn.PasswordEncryption(params.OldPassword) {
// 旧密码不正确
apiReturn.Error(c, global.Lang.Get("user.api_old_pass_error"))
apiReturn.ErrorByCode(c, 1007)
return
}
}

View File

@ -1 +1 @@
9|1.3.0-beta24-01-17-19
9|1.3.0-beta24-01-25

View File

@ -35,7 +35,7 @@ func InitApp() error {
// 日志
if logger, err := runlog.InitRunlog(global.RUNCODE, "running.log"); err != nil {
log.Panicln("日志初始化错误", err)
log.Panicln("Log initialization error", err)
panic(err)
} else {
global.Logger = logger
@ -47,7 +47,7 @@ func InitApp() error {
// 配置初始化
{
if config, err := config.ConfigInit(); err != nil {
global.Logger.Errorln("配置初始化错误", err)
global.Logger.Errorln("Configuration initialization error", err)
return err
} else {
global.Config = config
@ -74,7 +74,7 @@ func InitApp() error {
})
if err != nil {
log.Panicln("Redis初始化错误", err)
log.Panicln("Redis initialization error", err)
panic(err)
// return err
}
@ -114,7 +114,7 @@ func DatabaseConnect() {
}
if db, err := database.DbInit(dbClientInfo); err != nil {
log.Panicln("数据库初始化错误", err)
log.Panicln("Database initialization error", err)
panic(err)
} else {
global.Db = db
@ -133,17 +133,17 @@ func CommandRun() {
pwd bool
)
flag.BoolVar(&cfg, "config", false, "生成配置文件")
flag.BoolVar(&pwd, "password-reset", false, "重置第一个用户的密码")
flag.BoolVar(&cfg, "config", false, "Generate configuration file")
flag.BoolVar(&pwd, "password-reset", false, "Reset the password of the first user")
flag.Parse()
if cfg {
// 生成配置文件
fmt.Println("正在生成配置文件")
fmt.Println("Generating configuration file")
cmn.AssetsTakeFileToPath("conf.example.ini", "conf/conf.example.ini")
cmn.AssetsTakeFileToPath("conf.example.ini", "conf/conf.ini")
fmt.Println("配置文件已经创建 conf/conf.ini ", "请按照自己的需求修改")
fmt.Println("The configuration file has been created conf/conf.ini ", "Please modify according to your own needs")
os.Exit(0) // 务必退出
} else if pwd {
// 重置密码
@ -171,9 +171,9 @@ func CommandRun() {
os.Exit(0) // 务必退出
}
fmt.Println("密码已经重置成功,以下是账号信息")
fmt.Println("用户名 ", userInfo.Username)
fmt.Println("密码 ", newPassword)
fmt.Println("The password has been successfully reset. Here is the account information")
fmt.Println("Username ", userInfo.Username)
fmt.Println("Password ", newPassword)
os.Exit(0) // 务必退出
} else {
return

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,12 +1,15 @@
<script setup lang="ts">
import { NDivider, NGradientText } from 'naive-ui'
import { NDivider, NGradientText, NTag } from 'naive-ui'
import { onMounted, ref } from 'vue'
import { get } from '@/api/system/about'
import { useAppStore } from '@/store'
import srcSvglogo from '@/assets/logo.svg'
import srcGitee from '@/assets/about_image/gitee.png'
import srcGithub from '@/assets/about_image/github.png'
import srcDocker from '@/assets/about_image/docker.png'
import srcQQGroupQR from '@/assets/about_image/qq_group_qr.jpg'
import srcBilibili from '@/assets/about_image/bilibili.png'
import srcYoutube from '@/assets/about_image/youtube.png'
import srcQQGroupQR from '@/assets/about_image/qq_group_qr2.png'
import { RoundCardModal } from '@/components/common'
interface Version {
@ -14,8 +17,10 @@ interface Version {
versionCode: number
}
const appStore = useAppStore()
const versionName = ref('')
const qqGroupQRShow = ref(false)
const frontVersion = import.meta.env.VITE_APP_VERSION || 'unknown'
onMounted(() => {
get<Version>().then((res) => {
@ -26,43 +31,44 @@ onMounted(() => {
</script>
<template>
<div class="pt-10">
<div>
<div class="flex flex-col items-center justify-center">
<img :src="srcSvglogo" width="100" height="100" alt="">
<div class="text-3xl font-semibold">
{{ $t('common.appName') }}
</div>
<div class="text-xl">
<NGradientText type="info">
<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 class="pt-5">
<div class="flex flex-col items-center justify-center">
<img :src="srcSvglogo" width="100" height="100" alt="">
<div class="text-3xl font-semibold">
{{ $t('common.appName') }}
</div>
</div>
<NDivider> </NDivider>
<div class="flex flex-col items-center justify-center text-base">
<div>
<div class="text-xl">
<NGradientText type="info">
<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 class="mt-2">
<a href="https://github.com/hslr-s/sun-panel/releases" target="_blank" class="link">{{ $t('apps.about.checkUpdate') }}</a>
</div>
</div>
<NDivider style="margin:10px 0">
</NDivider>
<div class="flex flex-col items-center justify-center text-base">
<div>
{{ $t('apps.about.author') }}<a href="https://github.com/hslr-s" 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>
{{ $t('apps.about.issue') }}<a href="https://github.com/hslr-s/sun-panel/issues" target="_blank" class="link">Github Issues</a>
</div>
<div>
{{ $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">{{ $t("apps.about.addQQGroupUrl") }}</a>
{{ $t('apps.about.discussions') }}<a href="https://github.com/hslr-s/sun-panel/discussions" target="_blank" class="link">Github Discussions</a>
</div>
<div>
{{ $t('apps.about.QQGroup') }}<a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=K6UII6aEPZUeDRIPOEpOSJZH-Vmr_RPu&authKey=jEXhnVekLbDDx5UkQzKtd3bRmhZggkGBxmvW4NT5LLIAFP7toMmqABwvkANGHbLb&noverify=0&group_code=831615449" target="_blank" class="link">{{ $t("apps.about.addQQGroupUrl") }}</a>
|
<span class="link cursor-pointer" @click="qqGroupQRShow = !qqGroupQRShow">
{{ $t('apps.about.QR') }}
</span>
</div>
<div>
{{ $t('apps.about.author') }}<a href="https://github.com/hslr-s" 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]">
<div class="flex mt-[10px] flex-wrap justify-center">
<div class="flex items-center mx-[10px]">
<img class="w-[20px] h-[20px] mr-[5px]" :src="srcGithub" alt="">
<a href="https://github.com/hslr-s/sun-panel" target="_blank" class="link">Github</a>
@ -75,6 +81,21 @@ onMounted(() => {
<img class="w-[20px] h-[20px] mr-[5px]" :src="srcDocker" alt="">
<a href="https://hub.docker.com/r/hslr/sun-panel" target="_blank" class="link">Docker</a>
</div>
<div class="flex items-center mx-[10px]">
<img class="w-[20px] h-[20px] mr-[5px]" :src="srcBilibili" alt="">
<!-- <a href="https://space.bilibili.com/27407696/channel/collectiondetail?sid=2023810" target="_blank" class="link">Bilibili</a> -->
<a href="https://space.bilibili.com/27407696/channel/collectiondetail?sid=2023810" target="_blank" class="link">Bilibili</a>
</div>
<div v-if="appStore.language !== 'zh-CN'" class="flex items-center mx-[10px]">
<img class="w-[20px] h-[20px] mr-[5px]" :src="srcYoutube" alt="">
<a href="https://www.youtube.com/channel/UCKwbFmKU25R602z6P2fgPYg" target="_blank" class="link">YouTube</a>
</div>
</div>
<div class="mt-5">
<NTag :bordered="false" size="small">
{{ $t("apps.about.frontVersionText") }}: FV-{{ frontVersion }}
</NTag>
</div>
<RoundCardModal v-model:show="qqGroupQRShow" title="交流群二维码" style="width: 300px;">

View File

@ -237,6 +237,13 @@ function resetPanelConfig() {
</div>
<NGrid cols="2">
<NGridItem span="12 400:12">
<div class="flex items-center mt-[5px]">
<span class="mr-[10px]">{{ $t('apps.baseSettings.netModeChangeButtonShow') }}</span>
<NSwitch v-model:value="panelState.panelConfig.netModeChangeButtonShow" />
</div>
</NGridItem>
<NGridItem span="12 400:12">
<div class="flex items-center mt-[10px]">
<span class="mr-[10px]">{{ $t('apps.baseSettings.maxWidth') }}</span>

View File

@ -104,14 +104,6 @@ function handleUpdatePassword(e: MouseEvent) {
updatePasswordModalState.value.show = false
ms.success(t('common.success'))
}
else if (code === 0) {
//
}
else {
//
ms.error(`${t('common.failed')}:${msg}`)
}
}).finally(() => {
updatePasswordModalState.value.loading = false
}).catch(() => {

View File

@ -18,11 +18,11 @@ const propClass = ref(props.class)
</script>
<template>
<div class="w-full">
<div class="item-card w-full">
<!-- 详情图标 -->
<div
v-if="cardTypeStyle === PanelPanelConfigStyleEnum.info"
class="w-full rounded-2xl transition-all duration-200 flex"
class="item-card-info w-full rounded-2xl transition-all duration-200 flex"
:class="propClass"
:style="{ backgroundColor: backgroundColor ?? defaultBackground }"
>
@ -32,9 +32,10 @@ const propClass = ref(props.class)
<!-- 极简图标APP -->
<div
v-if="cardTypeStyle === PanelPanelConfigStyleEnum.icon"
class="item-card-small"
>
<div
class="overflow-hidden rounded-2xl sunpanel w-[70px] h-[70px] mx-auto transition-all duration-200"
class="item-card-small-icon overflow-hidden rounded-2xl sunpanel w-[70px] h-[70px] mx-auto transition-all duration-200"
:class="propClass"
:style="{ backgroundColor: backgroundColor ?? defaultBackground }"
>
@ -43,7 +44,7 @@ const propClass = ref(props.class)
<div
v-if="!iconTextIconHideTitle"
class="text-center app-icon-text-shadow cursor-pointer mt-[2px]"
class="item-card-small-title text-center app-icon-text-shadow cursor-pointer mt-[2px]"
:style="{ color: iconTextColor }"
>
{{ iconText }}

View File

@ -21,32 +21,32 @@ const iconExt = computed(() => {
</script>
<template>
<div :style="defaultStyle">
<div class="item-icon" :style="defaultStyle">
<slot>
<div v-if="itemIcon">
<div v-if="itemIcon?.itemType === 1">
<template v-if="itemIcon">
<template v-if="itemIcon?.itemType === 1">
<NAvatar :size="props.size" :style="{ backgroundColor: (forceBackground ?? itemIcon?.backgroundColor) || defaultBackground }">
{{ itemIcon.text }}
</NAvatar>
</div>
</template>
<div v-else-if="itemIcon?.itemType === 2">
<template v-else-if="itemIcon?.itemType === 2">
<div v-if="iconExt === 'svg'" :style="{ backgroundColor: (forceBackground ?? itemIcon?.backgroundColor) || defaultBackground, ...defaultStyle }" class="flex justify-center items-center">
<img :src="itemIcon?.src" class="w-[35px] h-[35px]">
</div>
<NImage v-else :style="{ backgroundColor: (forceBackground ?? itemIcon?.backgroundColor) || defaultBackground, ...defaultStyle }" :src="itemIcon?.src" preview-disabled />
</div>
</template>
<div v-else-if="itemIcon?.itemType === 3">
<template v-else-if="itemIcon?.itemType === 3">
<NAvatar :size="props.size" :style="{ backgroundColor: (forceBackground ?? itemIcon?.backgroundColor) || defaultBackground }">
<SvgIconOnline style="font-size: 35px;" :icon="itemIcon.text" />
</NAvatar>
</div>
</div>
</template>
</template>
<div v-else>
<template v-else>
<NAvatar :size="props.size" />
</div>
</template>
</slot>
</div>
</template>

View File

@ -1,8 +0,0 @@
<template>
<div class="text-neutral-400">
<span>Star on</span>
<a href="https://github.com/Chanzhaoyu/chatgpt-bot" target="_blank" class="text-blue-500">
GitHub
</a>
</div>
</template>

View File

@ -1,3 +0,0 @@
import GithubSite from './GithubSite.vue'
export { GithubSite }

View File

@ -67,15 +67,15 @@ onBeforeUnmount(() => {
</script>
<template>
<div class="w-full text-center">
<span class="text-2xl sm:text-2xl md:text-3xl font-[600]">
<div class="clock w-full text-center">
<span class="clock-time text-2xl sm:text-2xl md:text-3xl font-[600]">
{{ currentDate.time }}
</span>
<div class="hidden sm:hidden md:block">
<span class="mr-1">
<span class="clock-date mr-1">
{{ currentDate.date }}
</span>
<span>
<span class="clock-week">
{{ currentDate.week }}
</span>
</div>

View File

@ -120,18 +120,18 @@ onMounted(() => {
</script>
<template>
<div class="w-full" @keydown.enter="handleSearchClick">
<div class="search-box w-full" @keydown.enter="handleSearchClick" @keydown.esc="handleClearSearchTerm">
<div class="search-container flex rounded-2xl items-center justify-center text-white w-full" :style="{ background, color: textColor }" :class="{ focused: isFocused }">
<div class="w-[40px] flex justify-center cursor-pointer" @click="handleEngineClick">
<div class="search-box-btn-engine w-[40px] flex justify-center cursor-pointer" @click="handleEngineClick">
<NAvatar :src="state.currentSearchEngine.iconSrc" style="background-color: transparent;" :size="20" />
</div>
<input v-model="searchTerm" :placeholder="$t('deskModule.searchBox.inputPlaceholder')" @focus="onFocus" @blur="onBlur" @input="handleItemSearch">
<div v-if="searchTerm !== ''" class="w-[25px] mr-[10px] flex justify-center cursor-pointer" @click="handleClearSearchTerm">
<div v-if="searchTerm !== ''" class="search-box-btn-clear w-[25px] mr-[10px] flex justify-center cursor-pointer" @click="handleClearSearchTerm">
<SvgIcon style="width: 20px;height: 20px;" icon="line-md:close-small" />
</div>
<div class="w-[25px] flex justify-center cursor-pointer" @click="handleSearchClick">
<div class="search-box-btn-search w-[25px] flex justify-center cursor-pointer" @click="handleSearchClick">
<SvgIcon style="width: 20px;height: 20px;" icon="iconamoon:search-fill" />
</div>
</div>

View File

@ -1,6 +1,7 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import GenericProgress from '../components/GenericProgress/index.vue'
import { correctionNumber, correctionNumberByCardStyle } from './common'
import { getCpuState } from '@/api/system/systemMonitor'
import type { PanelPanelConfigStyleEnum } from '@/enums'
@ -16,10 +17,6 @@ const props = defineProps<Prop>()
let timer: NodeJS.Timer
const cpuState = ref<SystemMonitor.CPUInfo | null>(null)
function correctionNumber(v: number, keepNum = 2): number {
return v === 0 ? 0 : Number(v.toFixed(keepNum))
}
async function getData() {
try {
const { data, code } = await getCpuState<SystemMonitor.CPUInfo>()
@ -44,16 +41,15 @@ onUnmounted(() => {
</script>
<template>
<div class="w-full">
<GenericProgress
:progress-color="progressColor"
:progress-rail-color="progressRailColor"
:progress-height="5"
:percentage="correctionNumber(cpuState?.usages[0] || 0)"
:card-type-style="cardTypeStyle"
:info-card-right-text="`${correctionNumber(cpuState?.usages[0] || 0)}%`"
info-card-left-text="CPU"
:text-color="textColor"
/>
</div>
<GenericProgress
:progress-color="progressColor"
:progress-rail-color="progressRailColor"
:progress-height="5"
:percentage="correctionNumberByCardStyle(cpuState?.usages[0] || 0, cardTypeStyle)"
:card-type-style="cardTypeStyle"
:info-card-right-text="`${correctionNumber(cpuState?.usages[0] || 0)}%`"
info-card-left-text="CPU"
:text-color="textColor"
style="width: 100%;"
/>
</template>

View File

@ -1,6 +1,7 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import GenericProgress from '../components/GenericProgress/index.vue'
import { correctionNumberByCardStyle } from './common'
import type { PanelPanelConfigStyleEnum } from '@/enums'
import { bytesToSize } from '@/utils/cmn'
import { getDiskStateByPath } from '@/api/system/systemMonitor'
@ -18,10 +19,6 @@ const props = defineProps<Prop>()
let timer: NodeJS.Timer
const diskState = ref<SystemMonitor.DiskInfo | null>(null)
function correctionNumber(v: number, keepNum = 2): number {
return v === 0 ? 0 : Number(v.toFixed(keepNum))
}
function formatdiskSize(v: number): string {
return bytesToSize(v)
}
@ -54,16 +51,14 @@ onUnmounted(() => {
</script>
<template>
<div class="w-full">
<GenericProgress
:progress-color="progressColor"
:progress-rail-color="progressRailColor"
:progress-height="5"
:percentage="correctionNumber(diskState?.usedPercent || 0)"
:card-type-style="cardTypeStyle"
:info-card-right-text="`${formatdiskSize(formatdiskToByte(diskState?.used || 0))}/${formatdiskSize(formatdiskToByte(diskState?.free || 0))}`"
:info-card-left-text="diskState?.mountpoint"
:text-color="textColor"
/>
</div>
<GenericProgress
:progress-color="progressColor"
:progress-rail-color="progressRailColor"
:progress-height="5"
:percentage="correctionNumberByCardStyle(diskState?.usedPercent || 0, cardTypeStyle)"
:card-type-style="cardTypeStyle"
:info-card-right-text="`${formatdiskSize(formatdiskToByte(diskState?.used || 0))}/${formatdiskSize(formatdiskToByte(diskState?.free || 0))}`"
:info-card-left-text="diskState?.mountpoint"
:text-color="textColor"
/>
</template>

View File

@ -1,6 +1,7 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import GenericProgress from '../components/GenericProgress/index.vue'
import { correctionNumberByCardStyle } from './common'
import { getMemonyState } from '@/api/system/systemMonitor'
import type { PanelPanelConfigStyleEnum } from '@/enums'
import { bytesToSize } from '@/utils/cmn'
@ -17,10 +18,6 @@ const props = defineProps<Prop>()
let timer: NodeJS.Timer
const memoryState = ref<SystemMonitor.MemoryInfo | null>(null)
function correctionNumber(v: number, keepNum = 2): number {
return v === 0 ? 0 : Number(v.toFixed(keepNum))
}
function formatMemorySize(v: number): string {
return bytesToSize(v)
}
@ -49,16 +46,14 @@ onUnmounted(() => {
</script>
<template>
<div class="w-full">
<GenericProgress
:progress-color="progressColor"
:progress-rail-color="progressRailColor"
:progress-height="5"
:percentage="correctionNumber(memoryState?.usedPercent || 0)"
:card-type-style="cardTypeStyle"
:info-card-right-text="`${formatMemorySize(memoryState?.used || 0)}/${formatMemorySize((memoryState?.total || 0) - (memoryState?.used || 0) || 0)}`"
info-card-left-text="RAM"
:text-color="textColor"
/>
</div>
<GenericProgress
:progress-color="progressColor"
:progress-rail-color="progressRailColor"
:progress-height="5"
:percentage="correctionNumberByCardStyle(memoryState?.usedPercent || 0, cardTypeStyle)"
:card-type-style="cardTypeStyle"
:info-card-right-text="`${formatMemorySize(memoryState?.used || 0)}/${formatMemorySize((memoryState?.total || 0) - (memoryState?.used || 0) || 0)}`"
info-card-left-text="RAM"
:text-color="textColor"
/>
</template>

View File

@ -0,0 +1,15 @@
import { PanelPanelConfigStyleEnum } from '@/enums'
export function correctionNumberByCardStyle(v: number, cardStyle: PanelPanelConfigStyleEnum): number {
let keepNum = 0
if (cardStyle === PanelPanelConfigStyleEnum.small)
keepNum = 1
else if (cardStyle === PanelPanelConfigStyleEnum.info)
keepNum = 2
return correctionNumber(v, keepNum)
}
export function correctionNumber(v: number, keepNum = 2): number {
return v === 0 ? 0 : Number(v.toFixed(keepNum))
}

View File

@ -47,7 +47,7 @@ const refreshInterval = 5000
<template #icon>
<!-- 图标 -->
<div class="w-[60px] h-[70px]">
<div class="w-[60px] h-full flex items-center justify-center text-white">
<div class="app-icon w-[60px] h-full flex items-center justify-center text-white">
<SvgIcon v-if="monitorType === MonitorType.cpu" icon="solar-cpu-bold" :style="{ color: extendParam.color }" style="width:35px;height:35px" />
<SvgIcon v-if="monitorType === MonitorType.memory" icon="material-symbols-memory-alt-rounded" :style="{ color: extendParam.color }" style="width:35px;height:35px" />
<SvgIcon v-if="monitorType === MonitorType.disk" icon="clarity-hard-disk-solid" :style="{ color: extendParam.color }" style="width:35px;height:35px" />

View File

@ -27,7 +27,7 @@ const propClass = ref(props.class)
</script>
<template>
<div class="w-full">
<div class="generic-monitor-card w-full">
<ItemCard
:card-type-style="cardTypeStyle"
:icon-text="iconText"

View File

@ -17,8 +17,8 @@ defineProps<Prop>()
</script>
<template>
<div class="w-full">
<div v-if="cardTypeStyle === PanelPanelConfigStyleEnum.info">
<template v-if="cardTypeStyle === PanelPanelConfigStyleEnum.info">
<div class="w-full">
<div class="mb-1 text-xs" :style="{ color: textColor }">
<span>
{{ infoCardLeftText }}
@ -38,20 +38,20 @@ defineProps<Prop>()
style="max-width: 135px;"
/>
</div>
<div v-else>
<div class="flex justify-center h-full w-full mt-3">
<NProgress
:color="progressColor"
:rail-color="progressRailColor"
type="dashboard"
:percentage="percentage" :stroke-width="15"
style="width: 50px;"
>
<div class="text-white" style="font-size: 8px;" :style="{ color: textColor }">
{{ percentage }}%
</div>
</NProgress>
</div>
</template>
<template v-else>
<div class="w-full flex justify-center h-full w-full mt-3">
<NProgress
:color="progressColor"
:rail-color="progressRailColor"
type="dashboard"
:percentage="percentage" :stroke-width="15"
style="width: 50px;"
>
<div class="text-white" style="font-size: 8px;" :style="{ color: textColor }">
{{ percentage }}%
</div>
</NProgress>
</div>
</div>
</template>
</template>

View File

@ -171,7 +171,7 @@ function handleRightMenuSelect(key: string | number) {
</script>
<template>
<div class="w-full">
<div class="system-monitor w-full">
<div
class="mt-[50px]"
:class="monitorGroup.sortStatus ? 'shadow-2xl border shadow-[0_0_30px_10px_rgba(0,0,0,0.3)] p-[10px] rounded-2xl' : ''"
@ -179,13 +179,13 @@ function handleRightMenuSelect(key: string | number) {
@mouseleave="handleSetHoverStatus(false)"
>
<!-- 分组标题 -->
<div class="text-white text-xl font-extrabold mb-[20px] ml-[10px] flex items-center">
<div class="system-monitor-header 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="system-monitor-buttons ml-2 delay-100 transition-opacity flex"
:class="monitorGroup.hoverStatus ? 'opacity-100' : 'opacity-0'"
>
<span class="mr-2 cursor-pointer" @click="handleAddItem()">
@ -198,7 +198,7 @@ function handleRightMenuSelect(key: string | number) {
</div>
<!-- 详情图标 -->
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.info">
<template v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.info">
<VueDraggable
v-model="monitorDatas" item-key="sort" :animation="300"
class="icon-info-box"
@ -221,39 +221,37 @@ function handleRightMenuSelect(key: string | number) {
/>
</div>
</VueDraggable>
</div>
</template>
<!-- APP图标宫型盒子 -->
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.icon">
<div v-if="monitorDatas">
<VueDraggable
v-model="monitorDatas" item-key="sort" :animation="300"
class="icon-small-box"
filter=".not-drag"
:disabled="!monitorGroup.sortStatus"
<template v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.icon">
<VueDraggable
v-model="monitorDatas" item-key="sort" :animation="300"
class="icon-small-box"
filter=".not-drag"
:disabled="!monitorGroup.sortStatus"
>
<div
v-for="item, index in monitorDatas" :key="index"
:title="item.description"
@click="handleClick(index, item)"
@contextmenu="(e) => handleContextMenu(e, index, item)"
>
<div
v-for="item, index in monitorDatas" :key="index"
:title="item.description"
@click="handleClick(index, item)"
@contextmenu="(e) => handleContextMenu(e, index, item)"
>
<AppIconSystemMonitor
:extend-param="item.extendParam"
:icon-text-icon-hide-title="false"
:card-type-style="panelState.panelConfig.iconStyle"
:monitor-type="item.monitorType"
:card-style="cardStyle"
:icon-text-color="panelState.panelConfig.iconTextColor"
/>
</div>
</vuedraggable>
</div>
</div>
<AppIconSystemMonitor
:extend-param="item.extendParam"
:icon-text-icon-hide-title="false"
:card-type-style="panelState.panelConfig.iconStyle"
:monitor-type="item.monitorType"
:card-style="cardStyle"
:icon-text-color="panelState.panelConfig.iconTextColor"
/>
</div>
</vuedraggable>
</template>
<!-- 编辑栏 -->
<div v-if="monitorGroup.sortStatus && allowEdit" class="flex mt-[10px]">
<div>
<template v-if="monitorGroup.sortStatus && allowEdit">
<div class="system-monitor-edit-bar flex mt-[10px]">
<NButton color="#2a2a2a6b" @click="handleSaveSort()">
<template #icon>
<SvgIcon class="text-white font-xl" icon="material-symbols:save" />
@ -263,7 +261,7 @@ function handleRightMenuSelect(key: string | number) {
</div>
</NButton>
</div>
</div>
</template>
</div>
<Edit v-model:visible="editShowStatus" :monitor-data="editData" :index="editIndex" @done="handleSaveDone" />

View File

@ -25,6 +25,7 @@
"1004": "Account has been deactivated or inactivated",
"1005": "Currently no permission to operate",
"1006": "Account does not exist",
"1007": "Old password error",
"1200": "database error",
"1201": "Please keep at least one",
"1202": "Data record not found",
@ -38,12 +39,14 @@
"apps": {
"about": {
"QQGroup": "QQ Group:",
"QR": "QR Code (Recommended)",
"QR": "QR Code(recommend)",
"addQQGroupUrl": "Click to join",
"appName": "About",
"author": "Author:",
"checkUpdate": "Check for new version",
"discussions": "Discussions:",
"donate": "☕Donate",
"frontVersionText": "Front-end version number",
"issue": "Feedback:",
"viewUpdateLog": "Click here to view update log"
},
@ -63,6 +66,7 @@
"leftRightMargin": "Left-right margin",
"mask": "Mask",
"maxWidth": "Max width",
"netModeChangeButtonShow": "Show network mode switch button",
"publicVisitModeShow": "Allow public mode display",
"resetWarnText": "Are you sure you want to reset these styles?",
"searchBar": "Search bar component",

View File

@ -25,6 +25,7 @@
"1004": "账号已停用或未激活",
"1005": "当前无权限操作",
"1006": "账号不存在",
"1007": "旧密码错误",
"1200": "数据库出错",
"1201": "请至少保留一个",
"1202": "未找到数据记录",
@ -43,7 +44,9 @@
"appName": "关于",
"author": "作者:",
"checkUpdate": "检查新版本",
"discussions": "交流社区:",
"donate": "🧧打赏",
"frontVersionText": "前端版本号",
"issue": "建议反馈:",
"viewUpdateLog": "点此查看更新说明"
},
@ -55,7 +58,7 @@
"configFailed": "配置保存失败,{message}",
"configSaved": "配置已保存",
"contentArea": "内容区域",
"customFooter": "自定义footer",
"customFooter": "自定义页脚",
"customImageAddress": "展开图片链接输入框",
"detailIcon": "详情图标",
"hideDescription": "隐藏描述信息",
@ -63,6 +66,7 @@
"leftRightMargin": "左右边距",
"mask": "遮罩",
"maxWidth": "最大宽度",
"netModeChangeButtonShow": "显示网络模式切换按钮",
"publicVisitModeShow": "公开模式允许显示",
"resetWarnText": "确定要重置这些样式吗?",
"searchBar": "搜索栏组件",
@ -222,8 +226,8 @@
"iconGroup": "分组",
"inputIconName": "请输入图标名称",
"inputIconUrlOrUpload": "输入图标地址或上传",
"lanUrl": "局域网地址",
"lanUrlInputPlaceholder": "http(s)://局域网模式,会跳转该地址)",
"lanUrl": "网地址",
"lanUrlInputPlaceholder": "http(s)://网模式,会跳转该地址)",
"newWindowOpen": "新窗口打开",
"onlineIcon": "在线图标",
"onlineIconLibrary": "在线图标库",

View File

@ -28,6 +28,7 @@ export function defaultStatePanelConfig(): Panel.panelConfig {
systemMonitorShow: false,
systemMonitorShowTitle: true,
systemMonitorPublicVisitModeShow: false,
netModeChangeButtonShow: true,
}
}

View File

@ -26,7 +26,7 @@ export const usePanelState = defineStore('panel', {
this.recordState()
},
// 获取云端的面板配置
// 获取云端(搭建的服务器)的面板配置
updatePanelConfigByCloud() {
getUserConfig<Panel.userConfig>().then((res) => {
if (res.code === 0)

View File

@ -17,7 +17,6 @@ export function defaultSetting(): UserState {
userInfo: {
// headImage: userDefaultAvatar,
name: '-- --',
// description: 'Star on <a href="https://github.com/Chanzhaoyu/chatgpt-bot" class="text-blue-500" target="_blank" >GitHub</a>',
},
}
}

View File

@ -59,6 +59,7 @@ declare namespace Panel {
systemMonitorShow?:boolean
systemMonitorShowTitle?:boolean
systemMonitorPublicVisitModeShow?:boolean
netModeChangeButtonShow?:boolean
}
interface userConfig{

View File

@ -35,15 +35,15 @@ const textColor = computed(() => {
</script>
<template>
<div class="w-full">
<div class="app-icon w-full">
<!-- 详情图标 -->
<div
v-if="style === PanelPanelConfigStyleEnum.info"
class="w-full rounded-2xl transition-all duration-200 hover:shadow-[0_0_20px_10px_rgba(0,0,0,0.2)] flex"
class="app-icon-info w-full rounded-2xl transition-all duration-200 hover:shadow-[0_0_20px_10px_rgba(0,0,0,0.2)] flex"
:style="{ background: itemInfo?.icon?.backgroundColor || defaultBackground }"
>
<!-- 图标 -->
<div class="w-[70px] h-[70px]">
<div class="app-icon-info-icon w-[70px] h-[70px]">
<div class="w-[70px] h-full flex items-center justify-center ">
<ItemIcon :item-icon="itemInfo?.icon" force-background="transparent" :size="50" class="overflow-hidden rounded-xl" />
</div>
@ -52,13 +52,13 @@ const textColor = computed(() => {
<!-- 文字 -->
<!-- 如果为纯白色将自动根据背景的明暗计算字体的黑白色 -->
<div class="text-white flex items-center" :style="{ color: (iconTextColor === '#ffffff') ? textColor : iconTextColor, maxWidth: 'calc(100% - 80px)' }">
<div class="w-full">
<div class="font-semibold w-full">
<div class="app-icon-info-text-box w-full">
<div class="app-icon-info-text-box-title font-semibold w-full">
<NEllipsis>
{{ itemInfo?.title }}
</NEllipsis>
</div>
<div v-if="!iconTextInfoHideDescription">
<div v-if="!iconTextInfoHideDescription" class="app-icon-info-text-box-description">
<NEllipsis :line-clamp="2" class="text-xs">
{{ itemInfo?.description }}
</NEllipsis>
@ -67,17 +67,17 @@ const textColor = computed(() => {
</div>
</div>
<!-- 极简图标APP -->
<div v-if="style === PanelPanelConfigStyleEnum.icon">
<!-- 极简()图标APP -->
<div v-if="style === PanelPanelConfigStyleEnum.icon" class="app-icon-small">
<div
class="overflow-hidden rounded-2xl sunpanel w-[70px] h-[70px] mx-auto rounded-2xl transition-all duration-200 hover:shadow-[0_0_20px_10px_rgba(0,0,0,0.2)]"
class="app-icon-small-icon overflow-hidden rounded-2xl sunpanel w-[70px] h-[70px] mx-auto rounded-2xl transition-all duration-200 hover:shadow-[0_0_20px_10px_rgba(0,0,0,0.2)]"
:title="itemInfo?.description"
>
<ItemIcon :item-icon="itemInfo?.icon" />
</div>
<div
v-if="!iconTextIconHideTitle"
class="text-center app-icon-text-shadow cursor-pointer mt-[2px]"
class="app-icon-small-title text-center app-icon-text-shadow cursor-pointer mt-[2px]"
:style="{ color: iconTextColor }"
>
<span>{{ itemInfo?.title }}</span>

View File

@ -323,9 +323,9 @@ function handleAddItem(itemIconGroupId?: number) {
</script>
<template>
<div class="w-full h-full sun-main ">
<div class="w-full h-full sun-main">
<div
class="cover" :style="{
class="cover wallpaper" :style="{
filter: `blur(${panelState.panelConfig.backgroundBlur}px)`,
background: `url(${panelState.panelConfig.backgroundImageSrc}) no-repeat`,
backgroundSize: 'cover',
@ -345,12 +345,12 @@ function handleAddItem(itemIconGroupId?: number) {
<!-- -->
<div class="mx-[auto] w-[80%]">
<div class="flex mx-[auto] items-center justify-center text-white">
<div>
<div class="logo">
<span class="text-2xl md:text-6xl font-bold text-shadow">
{{ panelState.panelConfig.logoText }}
</span>
</div>
<div class="text-base lg:text-2xl mx-[10px]">
<div class="divider text-base lg:text-2xl mx-[10px]">
|
</div>
<div class="text-shadow">
@ -380,19 +380,19 @@ function handleAddItem(itemIconGroupId?: number) {
<!-- 组纵向排列 -->
<div
v-for="(itemGroup, itemGroupIndex) in filterItems" :key="itemGroupIndex"
class="mt-[50px]"
class="item-list mt-[50px]"
:class="itemGroup.sortStatus ? 'shadow-2xl border shadow-[0_0_30px_10px_rgba(0,0,0,0.3)] p-[10px] rounded-2xl' : ''"
@mouseenter="handleSetHoverStatus(itemGroupIndex, true)"
@mouseleave="handleSetHoverStatus(itemGroupIndex, false)"
>
<!-- 分组标题 -->
<div class="text-white text-xl font-extrabold mb-[20px] ml-[10px] flex items-center">
<span class="text-shadow">
<span class="group-title text-shadow">
{{ itemGroup.title }}
</span>
<div
v-if="authStore.visitMode === VisitMode.VISIT_MODE_LOGIN"
class="ml-2 delay-100 transition-opacity flex"
class="group-buttons ml-2 delay-100 transition-opacity flex"
:class="itemGroup.hoverStatus ? 'opacity-100' : 'opacity-0'"
>
<span class="mr-2 cursor-pointer" :title="t('common.add')" @click="handleAddItem(itemGroup.id)">
@ -503,10 +503,11 @@ function handleAddItem(itemIconGroupId?: number) {
/>
<!-- 悬浮按钮 -->
<div class="fixed-element shadow-[0_0_10px_2px_rgba(0,0,0,0.2)]">
<div class="fixed-element shadow-[0_0_10px_2px_rgba(0,0,0,0.2)]">
<NButtonGroup vertical>
<!-- 网络模式切换按钮组 -->
<NButton
v-if="panelState.networkMode === PanelStateNetworkModeEnum.lan" color="#2a2a2a6b"
v-if="panelState.networkMode === PanelStateNetworkModeEnum.lan && panelState.panelConfig.netModeChangeButtonShow" color="#2a2a2a6b"
:title="t('panelHome.changeToWanModel')" @click="handleChangeNetwork(PanelStateNetworkModeEnum.wan)"
>
<template #icon>
@ -515,7 +516,7 @@ function handleAddItem(itemIconGroupId?: number) {
</NButton>
<NButton
v-if="panelState.networkMode === PanelStateNetworkModeEnum.wan" color="#2a2a2a6b"
v-if="panelState.networkMode === PanelStateNetworkModeEnum.wan && panelState.panelConfig.netModeChangeButtonShow" color="#2a2a2a6b"
:title="t('panelHome.changeToLanModel')" @click="handleChangeNetwork(PanelStateNetworkModeEnum.lan)"
>
<template #icon>
@ -536,25 +537,25 @@ function handleAddItem(itemIconGroupId?: number) {
</NButton>
</NButtonGroup>
<NBackTop
:listen-to="() => scrollContainerRef"
:right="10"
:bottom="10"
style="background-color:transparent;border: none;box-shadow: none;"
>
<div class="shadow-[0_0_10px_2px_rgba(0,0,0,0.2)]">
<NButton color="#2a2a2a6b">
<template #icon>
<SvgIcon class="text-white font-xl" icon="icon-park-outline:to-top" />
</template>
</NButton>
</div>
</NBackTop>
<AppStarter v-model:visible="settingModalShow" />
<!-- <Setting v-model:visible="settingModalShow" /> -->
</div>
<NBackTop
:listen-to="() => scrollContainerRef"
:right="10"
:bottom="10"
style="background-color:transparent;border: none;box-shadow: none;"
>
<div class="shadow-[0_0_10px_2px_rgba(0,0,0,0.2)]">
<NButton color="#2a2a2a6b">
<template #icon>
<SvgIcon class="text-white font-xl" icon="icon-park-outline:to-top" />
</template>
</NButton>
</div>
</NBackTop>
<EditItem v-model:visible="editItemInfoShow" :item-info="editItemInfoData" :item-group-id="currentAddItenIconGroupId" @done="handleEditSuccess" />
<!-- 弹窗 -->