2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 01:57:19 +08:00

feat: new style

This commit is contained in:
2025-09-17 02:58:39 +08:00
parent df9b2ff009
commit 978ae70e44
58 changed files with 550 additions and 734 deletions

View File

@@ -37,7 +37,7 @@ func (s *App) Route(r chi.Router) {
r.Get("/load", s.Load)
r.Get("/config", s.GetConfig)
r.Post("/config", s.UpdateConfig)
r.Post("/clear_error_log", s.ClearErrorLog)
r.Post("/clear_log", s.ClearLog)
r.Get("/slow_log", s.SlowLog)
r.Post("/clear_slow_log", s.ClearSlowLog)
r.Get("/root_password", s.GetRootPassword)
@@ -159,8 +159,8 @@ func (s *App) Load(w http.ResponseWriter, r *http.Request) {
service.Success(w, load)
}
// ClearErrorLog 清空错误日志
func (s *App) ClearErrorLog(w http.ResponseWriter, r *http.Request) {
// ClearLog 清空日志
func (s *App) ClearLog(w http.ResponseWriter, r *http.Request) {
if err := systemctl.LogClear("mysqld"); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return

View File

@@ -46,9 +46,9 @@ func (s *App) Route(version uint) func(r chi.Router) {
r.Get("/fpm_config", php.GetFPMConfig)
r.Post("/fpm_config", php.UpdateFPMConfig)
r.Get("/load", php.Load)
r.Get("/error_log", php.ErrorLog)
r.Get("/log", php.Log)
r.Get("/slow_log", php.SlowLog)
r.Post("/clear_error_log", php.ClearErrorLog)
r.Post("/clear_log", php.ClearLog)
r.Post("/clear_slow_log", php.ClearSlowLog)
r.Get("/extensions", php.ExtensionList)
r.Post("/extensions", php.InstallExtension)
@@ -169,7 +169,7 @@ func (s *App) Load(w http.ResponseWriter, r *http.Request) {
service.Success(w, loads)
}
func (s *App) ErrorLog(w http.ResponseWriter, r *http.Request) {
func (s *App) Log(w http.ResponseWriter, r *http.Request) {
service.Success(w, fmt.Sprintf("%s/server/php/%d/var/log/php-fpm.log", app.Root, s.version))
}
@@ -177,7 +177,7 @@ func (s *App) SlowLog(w http.ResponseWriter, r *http.Request) {
service.Success(w, fmt.Sprintf("%s/server/php/%d/var/log/slow.log", app.Root, s.version))
}
func (s *App) ClearErrorLog(w http.ResponseWriter, r *http.Request) {
func (s *App) ClearLog(w http.ResponseWriter, r *http.Request) {
if _, err := shell.Execf("cat /dev/null > %s/server/php/%d/var/log/php-fpm.log", app.Root, s.version); err != nil {
service.Error(w, http.StatusInternalServerError, "%v", err)
return

View File

@@ -9,6 +9,10 @@ type AppSlug struct {
Slug string `json:"slug" form:"slug" validate:"required"`
}
type AppSlugs struct {
Slugs string `json:"slugs" form:"slugs" validate:"required"`
}
type AppUpdateShow struct {
Slug string `json:"slug" form:"slug" validate:"required|exists:apps,slug"`
Show bool `json:"show" form:"show"`

View File

@@ -2,6 +2,7 @@ package service
import (
"net/http"
"strings"
"github.com/leonelquinteros/gotext"
"github.com/libtnb/chix"
@@ -144,28 +145,27 @@ func (s *AppService) UpdateShow(w http.ResponseWriter, r *http.Request) {
}
func (s *AppService) IsInstalled(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.AppSlug](r)
req, err := Bind[request.AppSlugs](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
app, err := s.appRepo.Get(req.Slug)
if err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
flag := false
slugs := strings.Split(req.Slugs, ",")
for _, item := range slugs {
installed, err := s.appRepo.IsInstalled(item)
if err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
}
if installed {
flag = true
break
}
}
installed, err := s.appRepo.IsInstalled(req.Slug)
if err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
}
Success(w, chix.M{
"name": app.Name,
"installed": installed,
})
Success(w, flag)
}
func (s *AppService) UpdateCache(w http.ResponseWriter, r *http.Request) {

View File

@@ -68,6 +68,10 @@ func (s *MonitorService) List(w http.ResponseWriter, r *http.Request) {
Error(w, http.StatusInternalServerError, "%v", err)
return
}
if len(monitors) == 0 {
Success(w, types.MonitorData{})
return
}
var list types.MonitorData
var bytesSent uint64

View File

@@ -29,5 +29,7 @@
"automerge": true
}
],
"ignoreDeps": []
"ignoreDeps": [
"monaco-editor"
]
}

View File

@@ -23,7 +23,6 @@
</div>
<div class="loading-title"><%= title %></div>
</div>
<script src="/loading/index.js"></script>
</div>
<script src="/src/main.ts" type="module"></script>
</body>

View File

@@ -65,6 +65,7 @@
"@types/luxon": "^3.6.2",
"@types/node": "^22.15.21",
"@types/node-forge": "^1.3.11",
"@typescript/native-preview": "7.0.0-dev.20250904.1",
"@unocss/eslint-config": "^66.1.2",
"@vitejs/plugin-vue": "^6.0.0",
"@vue/eslint-config-prettier": "^10.2.0",
@@ -75,7 +76,7 @@
"eslint": "^9.27.0",
"eslint-plugin-vue": "^10.1.0",
"md-editor-v3": "^6.0.0",
"monaco-editor": "^0.53.0",
"monaco-editor": "0.52.2",
"naive-ui": "^2.41.0",
"npm-run-all2": "^8.0.4",
"prettier": "^3.5.3",

104
web/pnpm-lock.yaml generated
View File

@@ -19,7 +19,7 @@ importers:
version: 5.2.7
'@guolao/vue-monaco-editor':
specifier: ^1.5.5
version: 1.5.5(monaco-editor@0.53.0)(vue@3.5.21(typescript@5.9.2))
version: 1.5.5(monaco-editor@0.52.2)(vue@3.5.21(typescript@5.9.2))
'@vavt/copy2clipboard':
specifier: ^1.0.3
version: 1.0.3
@@ -123,6 +123,9 @@ importers:
'@types/node-forge':
specifier: ^1.3.11
version: 1.3.14
'@typescript/native-preview':
specifier: 7.0.0-dev.20250904.1
version: 7.0.0-dev.20250904.1
'@unocss/eslint-config':
specifier: ^66.1.2
version: 66.5.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)
@@ -154,8 +157,8 @@ importers:
specifier: ^6.0.0
version: 6.0.1(vue@3.5.21(typescript@5.9.2))
monaco-editor:
specifier: ^0.53.0
version: 0.53.0
specifier: 0.52.2
version: 0.52.2
naive-ui:
specifier: ^2.41.0
version: 2.43.1(vue@3.5.21(typescript@5.9.2))
@@ -1063,9 +1066,6 @@ packages:
'@types/node@22.18.4':
resolution: {integrity: sha512-UJdblFqXymSBhmZf96BnbisoFIr8ooiiBRMolQgg77Ea+VM37jXw76C2LQr9n8wm9+i/OvlUlW6xSvqwzwqznw==}
'@types/trusted-types@1.0.6':
resolution: {integrity: sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==}
'@types/web-bluetooth@0.0.21':
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
@@ -1128,6 +1128,53 @@ packages:
resolution: {integrity: sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript/native-preview-darwin-arm64@7.0.0-dev.20250904.1':
resolution: {integrity: sha512-1rt4DhERW1VM4OwWYVIrCp1k1S4kpZAxzbCnprNinVJInhHexY2K0FFD9IGXKWSRANHg/OmJRQYTEoDKM6pqNw==}
engines: {node: '>=20.6.0'}
cpu: [arm64]
os: [darwin]
'@typescript/native-preview-darwin-x64@7.0.0-dev.20250904.1':
resolution: {integrity: sha512-d2DMQnsXAkZDDk9bU/FhY/D74tbMAkboIGb+hq7kIIgOVcxOswhwLFZ/ajW/9NTesktz8Z14t40Ber+/Pny25A==}
engines: {node: '>=20.6.0'}
cpu: [x64]
os: [darwin]
'@typescript/native-preview-linux-arm64@7.0.0-dev.20250904.1':
resolution: {integrity: sha512-+fv13RDSk+7wFYY846q5ig7X6G07JT7wbajk6p4rELXTIfS1c6gRHGhODETCfFVaPziP4IlvqyinNP8F8wc9uQ==}
engines: {node: '>=20.6.0'}
cpu: [arm64]
os: [linux]
'@typescript/native-preview-linux-arm@7.0.0-dev.20250904.1':
resolution: {integrity: sha512-YyfTK1SGmfeDJv6G3vSmVxjM914Xio7O57NzRKOyEQnmBT5tdXTzeWgkjrUh1jE8wCUu0f0ZZ+xDTwgys+E2ug==}
engines: {node: '>=20.6.0'}
cpu: [arm]
os: [linux]
'@typescript/native-preview-linux-x64@7.0.0-dev.20250904.1':
resolution: {integrity: sha512-BjWJI42cUUilIyQHZpQQeSjC/Ifj/UaIf4oj6lRHDcg5qgLHWe5bAUxuNjE6i7wi+TTN9YxUvBDkMAcm/hI8wg==}
engines: {node: '>=20.6.0'}
cpu: [x64]
os: [linux]
'@typescript/native-preview-win32-arm64@7.0.0-dev.20250904.1':
resolution: {integrity: sha512-rPv/mVaneZTuFESk/zDg3dFiZjpdipVMcLaF10Ns1fIyWdZ0ja79Ufm1eCFbk8KFNEX2dEx+vFEvD9n4bhEneg==}
engines: {node: '>=20.6.0'}
cpu: [arm64]
os: [win32]
'@typescript/native-preview-win32-x64@7.0.0-dev.20250904.1':
resolution: {integrity: sha512-+twwqKYEv5UdZX5FRaBo0bDQgw/uPQjU3hqaqaO0Dhp1Ou8Ce4oi5hgwauB1j29JwBbvOi9/yoEcjsjT2Wsaxw==}
engines: {node: '>=20.6.0'}
cpu: [x64]
os: [win32]
'@typescript/native-preview@7.0.0-dev.20250904.1':
resolution: {integrity: sha512-IzPzhumNsWsIg4Kmt0y+0b2BBtsvD17rDmKj78yNeU3AsuA6xignQ5eDkFtRmLdGPVZwa8Yg5zPcJRFln98Ocw==}
engines: {node: '>=20.6.0'}
hasBin: true
'@unocss/astro@66.5.1':
resolution: {integrity: sha512-f17+xfyBZ9prFx4jda3D9ngOigjO8btHsR3uG7WeDQPW6OBdhETfIGdXs8WD99J/3A3LJtk7J0u9p121S+RE8Q==}
peerDependencies:
@@ -2561,8 +2608,8 @@ packages:
resolution: {integrity: sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==}
hasBin: true
monaco-editor@0.53.0:
resolution: {integrity: sha512-0WNThgC6CMWNXXBxTbaYYcunj08iB5rnx4/G56UOPeL9UVIUGGHA1GR0EWIh9Ebabj7NpCRawQ5b0hfN1jQmYQ==}
monaco-editor@0.52.2:
resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==}
mrmime@2.0.1:
resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
@@ -4133,10 +4180,10 @@ snapshots:
'@fontsource-variable/jetbrains-mono@5.2.7': {}
'@guolao/vue-monaco-editor@1.5.5(monaco-editor@0.53.0)(vue@3.5.21(typescript@5.9.2))':
'@guolao/vue-monaco-editor@1.5.5(monaco-editor@0.52.2)(vue@3.5.21(typescript@5.9.2))':
dependencies:
'@monaco-editor/loader': 1.5.0
monaco-editor: 0.53.0
monaco-editor: 0.52.2
vue: 3.5.21(typescript@5.9.2)
vue-demi: 0.14.10(vue@3.5.21(typescript@5.9.2))
@@ -4506,8 +4553,6 @@ snapshots:
dependencies:
undici-types: 6.21.0
'@types/trusted-types@1.0.6': {}
'@types/web-bluetooth@0.0.21': {}
'@typescript-eslint/eslint-plugin@8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)':
@@ -4603,6 +4648,37 @@ snapshots:
'@typescript-eslint/types': 8.43.0
eslint-visitor-keys: 4.2.1
'@typescript/native-preview-darwin-arm64@7.0.0-dev.20250904.1':
optional: true
'@typescript/native-preview-darwin-x64@7.0.0-dev.20250904.1':
optional: true
'@typescript/native-preview-linux-arm64@7.0.0-dev.20250904.1':
optional: true
'@typescript/native-preview-linux-arm@7.0.0-dev.20250904.1':
optional: true
'@typescript/native-preview-linux-x64@7.0.0-dev.20250904.1':
optional: true
'@typescript/native-preview-win32-arm64@7.0.0-dev.20250904.1':
optional: true
'@typescript/native-preview-win32-x64@7.0.0-dev.20250904.1':
optional: true
'@typescript/native-preview@7.0.0-dev.20250904.1':
optionalDependencies:
'@typescript/native-preview-darwin-arm64': 7.0.0-dev.20250904.1
'@typescript/native-preview-darwin-x64': 7.0.0-dev.20250904.1
'@typescript/native-preview-linux-arm': 7.0.0-dev.20250904.1
'@typescript/native-preview-linux-arm64': 7.0.0-dev.20250904.1
'@typescript/native-preview-linux-x64': 7.0.0-dev.20250904.1
'@typescript/native-preview-win32-arm64': 7.0.0-dev.20250904.1
'@typescript/native-preview-win32-x64': 7.0.0-dev.20250904.1
'@unocss/astro@66.5.1(vite@7.1.5(@types/node@22.18.4)(jiti@2.5.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5))':
dependencies:
'@unocss/core': 66.5.1
@@ -6242,9 +6318,7 @@ snapshots:
dependencies:
commander: 14.0.1
monaco-editor@0.53.0:
dependencies:
'@types/trusted-types': 1.0.6
monaco-editor@0.52.2: {}
mrmime@2.0.1: {}

View File

@@ -42,7 +42,7 @@
position: absolute;
height: 16px;
width: 16px;
background-color: var(--primary-color);
background-color: #333333;
border-radius: 8px;
-webkit-animation: loadingPulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
animation: loadingPulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;

View File

@@ -1,9 +0,0 @@
function addThemeColorCssVars() {
const key = '__THEME_COLOR__'
const defaultColor = '#00BFFF'
const themeColor = window.localStorage.getItem(key) || defaultColor
const cssVars = `--primary-color: ${themeColor}`
document.documentElement.style.cssText = cssVars
}
addThemeColorCssVars()

View File

@@ -14,13 +14,6 @@
"visible": true,
"height": 60
},
"primaryColor": "#00BFFF",
"otherColor": {
"info": "#2080F0",
"success": "#18A058",
"warning": "#F0A020",
"error": "#D03050"
},
"locale": "zh_CN",
"name": "AcePanel"
}

View File

@@ -7,8 +7,8 @@ export default {
config: (): any => http.Get('/apps/mysql/config'),
// 保存配置
saveConfig: (config: string): any => http.Post('/apps/mysql/config', { config }),
// 清空错误日志
clearErrorLog: (): any => http.Post('/apps/mysql/clear_error_log'),
// 清空日志
clearLog: (): any => http.Post('/apps/mysql/clear_log'),
// 获取慢查询日志
slowLog: (): any => http.Get('/apps/mysql/slow_log'),
// 清空慢查询日志

View File

@@ -15,10 +15,10 @@ export default {
http.Post(`/apps/php${version}/fpm_config`, { config }),
// 负载状态
load: (version: number): any => http.Get(`/apps/php${version}/load`),
// 获取错误日志
errorLog: (version: number): any => http.Get(`/apps/php${version}/error_log`),
// 清空错误日志
clearErrorLog: (version: number): any => http.Post(`/apps/php${version}/clear_error_log`),
// 获取日志
log: (version: number): any => http.Get(`/apps/php${version}/log`),
// 清空日志
clearLog: (version: number): any => http.Post(`/apps/php${version}/clear_log`),
// 获取慢日志
slowLog: (version: number): any => http.Get(`/apps/php${version}/slow_log`),
// 清空慢日志

View File

@@ -13,7 +13,7 @@ export default {
// 设置首页显示
updateShow: (slug: string, show: boolean): any => http.Post('/app/update_show', { slug, show }),
// 应用是否已安装
isInstalled: (slug: string): any => http.Get('/app/is_installed', { params: { slug } }),
isInstalled: (slugs: string): any => http.Get('/app/is_installed', { params: { slugs } }),
// 更新缓存
updateCache: (): any => http.Get('/app/update_cache')
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -1,26 +1,8 @@
<script lang="ts" setup>
import { useThemeStore } from '@/store'
import { kebabCase } from 'lodash-es'
import type { GlobalThemeOverrides } from 'naive-ui'
type ThemeVars = Exclude<GlobalThemeOverrides['common'], undefined>
type ThemeVarsKeys = keyof ThemeVars
const themeStore = useThemeStore()
watch(
() => themeStore.naiveThemeOverrides.common,
(common) => {
for (const key in common) {
useCssVar(`--${kebabCase(key)}`, document.documentElement).value =
common[key as ThemeVarsKeys] || ''
if (key === 'primaryColor')
window.localStorage.setItem('__THEME_COLOR__', common[key as ThemeVarsKeys] || '')
}
},
{ immediate: true }
)
watch(
() => themeStore.darkMode,
(newValue) => {
@@ -48,7 +30,6 @@ onBeforeUnmount(() => {
<template>
<n-config-provider
:theme="themeStore.naiveTheme"
:theme-overrides="themeStore.naiveThemeOverrides"
:locale="themeStore.naiveLocale"
:date-locale="themeStore.naiveDateLocale"
wh-full

View File

@@ -65,7 +65,7 @@ const columns: DataTableColumns<RowData> = [
}
},
() => [
h(TheIcon, { icon, size: 24, color: `var(--primary-color)` }),
h(TheIcon, { icon, size: 24 }),
h(NEllipsis, null, {
default: () => {
if (row.symlink) {

View File

@@ -6,7 +6,6 @@ import ThemeMode from './components/ThemeMode.vue'
import UserAvatar from './components/UserAvatar.vue'
import MenuCollapse from '@/layout/header/components/MenuCollapse.vue'
import ThemeSetting from '@/layout/header/components/ThemeSetting.vue'
import { useThemeStore } from '@/store'
const themeStore = useThemeStore()
@@ -23,7 +22,6 @@ const themeStore = useThemeStore()
<reload-page />
<full-screen />
<theme-mode />
<theme-setting />
<user-avatar />
</div>
</div>

View File

@@ -1,21 +0,0 @@
<script setup lang="ts">
import { useThemeStore } from '@/store'
import { useGettext } from 'vue3-gettext'
const { $gettext } = useGettext()
const themeStore = useThemeStore()
</script>
<template>
<n-tooltip trigger="hover">
<template #trigger>
<n-color-picker
class="mr-16 h-24 w-24"
:show-alpha="false"
v-model:value="themeStore.primaryColor"
:render-label="() => ''"
/>
</template>
{{ $gettext('Set Theme Color') }}
</n-tooltip>
</template>

View File

@@ -3,11 +3,12 @@ import { translateTitle } from '@/locales/menu'
import { usePermissionStore, useTabStore, useThemeStore } from '@/store'
import { isUrl, renderIcon } from '@/utils'
import type { MenuInst, MenuOption } from 'naive-ui'
import { MenuInst, MenuOption, useThemeVars } from 'naive-ui'
import type { VNodeChild } from 'vue'
import { RouterLink } from 'vue-router'
import type { Meta, RouteType } from '~/types/router'
const themeVars = useThemeVars()
const router = useRouter()
const currentRoute = useRoute()
const permissionStore = usePermissionStore()
@@ -142,8 +143,8 @@ function handleMenuSelect(key: string, item: MenuOption) {
.n-menu-item-content--child-active,
.n-menu-item-content--selected {
.n-menu-item-content__icon {
border-color: var(--primary-color);
background-color: var(--primary-color);
border-color: v-bind('themeVars.primaryColor');
background-color: v-bind('themeVars.primaryColor');
i {
color: #fff;

View File

@@ -2,8 +2,10 @@
import { translateTitle } from '@/locales/menu'
import type { TabItem } from '@/store'
import { useTabStore } from '@/store'
import { useThemeVars } from 'naive-ui'
import ContextMenu from './components/ContextMenu.vue'
const themeVars = useThemeVars()
const router = useRouter()
const tabStore = useTabStore()
@@ -88,13 +90,12 @@ async function handleContextMenu(e: MouseEvent, tabItem: TabItem) {
margin-right: 4px;
&:hover {
border: 1px solid var(--primary-color) !important;
border: 1px solid v-bind('themeVars.primaryColor') !important;
}
}
.n-tabs-tab--active {
border: 1px solid var(--primary-color) !important;
background-color: var(--selected-bg) !important;
border: 1px solid v-bind('themeVars.primaryColor') !important;
}
.n-tabs-pad,

View File

@@ -1,13 +1,27 @@
import app from '@/api/panel/app'
import type { Router } from 'vue-router'
// 防止重复显示错误消息
let lastErrorMsg = ''
let lastErrorTime = 0
const ERROR_COOLDOWN = 2000
function showErrorMessage(message: string) {
const now = Date.now()
if (lastErrorMsg !== message || now - lastErrorTime > ERROR_COOLDOWN) {
window.$message.error(message)
lastErrorMsg = message
lastErrorTime = now
}
}
export function createAppInstallGuard(router: Router) {
router.beforeEach(async (to) => {
const slug = to.path.split('/').pop()
if (to.path.startsWith('/apps/') && slug) {
useRequest(app.isInstalled(slug)).onSuccess(({ data }) => {
if (!data.installed) {
window.$message.error(`应用 ${data.name} 未安装`)
await useRequest(app.isInstalled(slug)).onSuccess(({ data }) => {
if (!data) {
showErrorMessage(`应用未安装`)
return router.push({ name: 'app-index' })
}
})
@@ -15,9 +29,9 @@ export function createAppInstallGuard(router: Router) {
// 网站
if (to.path.startsWith('/website')) {
useRequest(app.isInstalled('nginx')).onSuccess(({ data }) => {
if (!data.installed) {
window.$message.error(`Web 服务器 ${data.name} 未安装`)
await useRequest(app.isInstalled('nginx')).onSuccess(({ data }) => {
if (!data) {
showErrorMessage(`Web 服务器未安装`)
return router.push({ name: 'app-index' })
}
})
@@ -25,14 +39,10 @@ export function createAppInstallGuard(router: Router) {
// 容器
if (to.path.startsWith('/container')) {
useRequest(app.isInstalled('docker')).onSuccess(({ data }) => {
if (!data.installed) {
useRequest(app.isInstalled('podman')).onSuccess(({ data }) => {
if (!data.installed) {
window.$message.error(`容器引擎 Docker / Podman 未安装`)
return router.push({ name: 'app-index' })
}
})
await useRequest(app.isInstalled('docker,podman')).onSuccess(({ data }) => {
if (!data) {
showErrorMessage(`容器引擎未安装`)
return router.push({ name: 'app-index' })
}
})
}

View File

@@ -1,17 +1,5 @@
import { addColorAlpha, getColorPalette } from '@/utils'
import type { GlobalThemeOverrides } from 'naive-ui'
import themeSetting from '~/settings/theme.json'
type ColorType = 'primary' | 'info' | 'success' | 'warning' | 'error'
type ColorScene = '' | 'Suppl' | 'Hover' | 'Pressed' | 'Active'
type ColorKey = `${ColorType}Color${ColorScene}`
type ThemeColor = Partial<Record<ColorKey, string>>
interface ColorAction {
scene: ColorScene
handler: (color: string) => string
}
/** 初始化主题配置 */
export function defaultSettings(): Theme.Setting {
const isMobile = themeSetting.isMobile || false
@@ -23,62 +11,8 @@ export function defaultSettings(): Theme.Setting {
}
const header = themeSetting.header || { visible: true, height: 60 }
const tab = themeSetting.tab || { visible: true, height: 50 }
const primaryColor = themeSetting.primaryColor || '#00BFFF'
const otherColor = themeSetting.otherColor || {
info: '#0099ad',
success: '#52c41a',
warning: '#faad14',
error: '#f5222d'
}
const locale = themeSetting.locale || 'zh_CN'
const name = themeSetting.name || import.meta.env.VITE_APP_TITLE
const logo = ''
return { isMobile, darkMode, sider, header, tab, primaryColor, otherColor, locale, name, logo }
}
/** 获取naive的主题颜色 */
export function getNaiveThemeOverrides(colors: Record<ColorType, string>): GlobalThemeOverrides {
const { primary, info, success, warning, error } = colors
const themeColors = getThemeColors([
['primary', primary],
['info', info],
['success', success],
['warning', warning],
['error', error]
])
const colorLoading = primary
return {
common: {
...themeColors
},
LoadingBar: {
colorLoading
}
}
}
/** 获取主题颜色的各种场景对应的颜色 */
function getThemeColors(colors: [ColorType, string][]) {
const colorActions: ColorAction[] = [
{ scene: '', handler: (color) => color },
{ scene: 'Suppl', handler: (color) => color },
{ scene: 'Hover', handler: (color) => getColorPalette(color, 5) },
{ scene: 'Pressed', handler: (color) => getColorPalette(color, 7) },
{ scene: 'Active', handler: (color) => addColorAlpha(color, 0.1) }
]
const themeColor: ThemeColor = {}
colors.forEach((color) => {
colorActions.forEach((action) => {
const [colorType, colorValue] = color
const colorKey: ColorKey = `${colorType}Color${action.scene}`
themeColor[colorKey] = action.handler(colorValue)
})
})
return themeColor
return { isMobile, darkMode, sider, header, tab, locale, name, logo }
}

View File

@@ -1,8 +1,8 @@
import type { GlobalThemeOverrides, NDateLocale, NLocale } from 'naive-ui'
import type { NDateLocale, NLocale } from 'naive-ui'
import { darkTheme, dateEnUS, dateJaJP, dateZhCN, dateZhTW, enUS, jaJP, zhCN, zhTW } from 'naive-ui'
import type { BuiltInGlobalTheme } from 'naive-ui/es/themes/interface'
import { defaultSettings, getNaiveThemeOverrides } from './helpers'
import { defaultSettings } from './helpers'
type ThemeState = Theme.Setting
@@ -16,12 +16,6 @@ const locales: Record<string, { locale: NLocale; dateLocale: NDateLocale }> = {
export const useThemeStore = defineStore('theme', {
state: (): ThemeState => defaultSettings(),
getters: {
naiveThemeOverrides(): GlobalThemeOverrides {
return getNaiveThemeOverrides({
primary: this.primaryColor,
...this.otherColor
})
},
naiveTheme(): BuiltInGlobalTheme | undefined {
return this.darkMode ? darkTheme : undefined
},
@@ -52,10 +46,6 @@ export const useThemeStore = defineStore('theme', {
setCollapsed(collapsed: boolean) {
this.sider.collapsed = collapsed
},
/** 设置主题色 */
setPrimaryColor(color: string) {
this.primaryColor = color
},
/** 设置语言 */
setLocale(locale: string) {
this.locale = locale

View File

@@ -71,9 +71,5 @@ body {
&::-webkit-scrollbar-thumb {
background: #bfbfbf;
}
&::-webkit-scrollbar-thumb:hover {
background: var(--primary-color);
}
}
}

View File

@@ -5,8 +5,7 @@ import * as NaiveUI from 'naive-ui'
export async function setupNaiveDiscreteApi() {
const themeStore = useThemeStore()
const configProviderProps = computed(() => ({
theme: themeStore.naiveTheme,
themeOverrides: themeStore.naiveThemeOverrides
theme: themeStore.naiveTheme
}))
const { message, dialog, notification, loadingBar } = NaiveUI.createDiscreteApi(
['message', 'dialog', 'notification', 'loadingBar'],

View File

@@ -27,8 +27,7 @@ const columns: any = [
render(row: any) {
return h(TheIcon, {
icon: row.icon,
size: 26,
color: `var(--primary-color)`
size: 26
})
}
},
@@ -211,12 +210,12 @@ onMounted(() => {
<template>
<common-page show-footer>
<template #action>
<n-button type="primary" @click="handleUpdateCache">
{{ $gettext('Update Cache') }}
</n-button>
</template>
<n-flex vertical>
<n-flex>
<n-button type="primary" @click="handleUpdateCache">
{{ $gettext('Update Cache') }}
</n-button>
</n-flex>
<n-alert type="warning">{{
$gettext(
'Before updating apps, it is strongly recommended to backup/snapshot first, so you can roll back immediately if there are any issues!'

View File

@@ -28,22 +28,12 @@ const handleSaveConfig = () => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<service-status service="code-server" />
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Modify Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -63,7 +53,12 @@ const handleSaveConfig = () => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
<realtime-log service="code-server" />

View File

@@ -28,22 +28,12 @@ const handleSaveConfig = () => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<service-status service="docker" />
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{ $gettext('This modifies the Docker configuration file (/etc/docker/daemon.json)') }}
</n-alert>
@@ -59,7 +49,12 @@ const handleSaveConfig = () => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
<realtime-log service="docker" />

View File

@@ -215,7 +215,7 @@ onMounted(() => {
refresh()
getWhiteList()
useRequest(app.isInstalled('nginx')).onSuccess(({ data }) => {
if (data.installed) {
if (data) {
getWebsiteList(1, 10000)
}
})
@@ -224,24 +224,6 @@ onMounted(() => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'status'"
class="ml-16"
type="primary"
@click="handleSaveWhiteList"
>
{{ $gettext('Save Whitelist') }}
</n-button>
<n-button
v-if="currentTab == 'jails'"
class="ml-16"
type="primary"
@click="addJailModal = true"
>
{{ $gettext('Add Rule') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<n-flex vertical>
@@ -254,31 +236,48 @@ onMounted(() => {
:placeholder="$gettext('IP whitelist, separated by commas')"
/>
</n-card>
<n-flex>
<n-button type="primary" @click="handleSaveWhiteList">
{{ $gettext('Save Whitelist') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="jails" :tab="$gettext('Rule Management')">
<n-card :title="$gettext('Rule List')" :segmented="true">
<n-data-table
striped
remote
:scroll-x="1000"
:loading="loading"
:columns="jailsColumns"
:data="data"
:row-key="(row: any) => row.name"
v-model:page="page"
v-model:pageSize="pageSize"
:pagination="{
page: page,
pageCount: pageCount,
pageSize: pageSize,
itemCount: total,
showQuickJumper: true,
showSizePicker: true,
pageSizes: [20, 50, 100, 200]
}"
/>
</n-card>
<n-flex>
<n-card :title="$gettext('Rule List')" :segmented="true">
<n-data-table
striped
remote
:scroll-x="1000"
:loading="loading"
:columns="jailsColumns"
:data="data"
:row-key="(row: any) => row.name"
v-model:page="page"
v-model:pageSize="pageSize"
:pagination="{
page: page,
pageCount: pageCount,
pageSize: pageSize,
itemCount: total,
showQuickJumper: true,
showSizePicker: true,
pageSizes: [20, 50, 100, 200]
}"
/>
</n-card>
<n-flex>
<n-button
v-if="currentTab == 'jails'"
class="ml-16"
type="primary"
@click="addJailModal = true"
>
{{ $gettext('Add Rule') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
<realtime-log service="fail2ban" />

View File

@@ -26,22 +26,12 @@ const handleSaveConfig = () => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<service-status service="gitea" />
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Modify Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -61,7 +51,12 @@ const handleSaveConfig = () => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
<realtime-log service="gitea" />

View File

@@ -48,22 +48,12 @@ const handleSaveConfig = () => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<service-status service="memcached" />
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Service Configuration')">
<n-space vertical>
<n-flex vertical>
<Editor
v-model:value="config"
language="ini"
@@ -76,7 +66,12 @@ const handleSaveConfig = () => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="load" :tab="$gettext('Load Status')">
<n-data-table

View File

@@ -26,17 +26,12 @@ const handleSaveEnv = () => {
<template>
<common-page show-footer>
<template #action>
<n-button v-if="currentTab == 'env'" class="ml-16" type="primary" @click="handleSaveEnv">
{{ $gettext('Save') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<service-status service="minio" />
</n-tab-pane>
<n-tab-pane name="env" :tab="$gettext('Environment Variables')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -56,7 +51,12 @@ const handleSaveEnv = () => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveEnv">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
<realtime-log service="minio" />

View File

@@ -48,8 +48,8 @@ const handleSaveConfig = () => {
})
}
const handleClearErrorLog = () => {
useRequest(mysql.clearErrorLog()).onSuccess(() => {
const handleClearLog = () => {
useRequest(mysql.clearLog()).onSuccess(() => {
window.$message.success($gettext('Cleared successfully'))
})
}
@@ -68,46 +68,16 @@ const handleSetRootPassword = async () => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
<n-button
v-if="currentTab == 'error-log'"
class="ml-16"
type="primary"
@click="handleClearErrorLog"
>
{{ $gettext('Clear Log') }}
</n-button>
<n-button
v-if="currentTab == 'slow-log'"
class="ml-16"
type="primary"
@click="handleClearSlowLog"
>
{{ $gettext('Clear Slow Log') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<n-flex vertical>
<service-status service="mysqld" />
<n-card :title="$gettext('Root Password')">
<n-flex vertical>
<n-input
v-model:value="rootPassword"
type="password"
show-password-on="click"
></n-input>
<n-button type="primary" @click="handleSetRootPassword">{{
$gettext('Save Changes')
}}</n-button>
<n-input v-model:value="rootPassword" type="password" show-password-on="click" />
<n-button type="primary" @click="handleSetRootPassword">
{{ $gettext('Save Changes') }}
</n-button>
</n-flex>
</n-card>
</n-flex>
@@ -133,6 +103,11 @@ const handleSetRootPassword = async () => {
formatOnPaste: true
}"
/>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="load" :tab="$gettext('Load Status')">
@@ -146,9 +121,15 @@ const handleSetRootPassword = async () => {
/>
</n-tab-pane>
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
<n-button type="primary" @click="handleClearLog">
{{ $gettext('Clear Log') }}
</n-button>
<realtime-log service="mysqld" />
</n-tab-pane>
<n-tab-pane name="slow-log" :tab="$gettext('Slow Query Log')">
<n-button type="primary" @click="handleClearSlowLog">
{{ $gettext('Clear Slow Log') }}
</n-button>
<realtime-log :path="slowLog" />
</n-tab-pane>
</n-tabs>

View File

@@ -54,30 +54,12 @@ const handleClearErrorLog = () => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
<n-button
v-if="currentTab == 'error-log'"
class="ml-16"
type="primary"
@click="handleClearErrorLog"
>
{{ $gettext('Clear Log') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<service-status service="nginx" show-reload />
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Modify Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -97,7 +79,12 @@ const handleClearErrorLog = () => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="load" :tab="$gettext('Load Status')">
<n-data-table
@@ -113,7 +100,14 @@ const handleClearErrorLog = () => {
<realtime-log service="nginx" />
</n-tab-pane>
<n-tab-pane name="error-log" :tab="$gettext('Error Logs')">
<realtime-log :path="errorLog" />
<n-flex vertical>
<n-flex>
<n-button type="primary" @click="handleClearErrorLog">
{{ $gettext('Clear Log') }}
</n-button>
</n-flex>
<realtime-log :path="errorLog" />
</n-flex>
</n-tab-pane>
</n-tabs>
</common-page>

View File

@@ -24,7 +24,7 @@ const { data: config } = useRequest(php.config(version.value), {
const { data: fpmConfig } = useRequest(php.fpmConfig(version.value), {
initialData: ''
})
const { data: errorLog } = useRequest(php.errorLog(version.value), {
const { data: log } = useRequest(php.log(version.value), {
initialData: ''
})
const { data: slowLog } = useRequest(php.slowLog(version.value), {
@@ -150,8 +150,8 @@ const handleSaveFPMConfig = async () => {
})
}
const handleClearErrorLog = async () => {
useRequest(php.clearErrorLog(version.value)).onSuccess(() => {
const handleClearLog = async () => {
useRequest(php.clearLog(version.value)).onSuccess(() => {
window.$message.success($gettext('Cleared successfully'))
})
}
@@ -177,46 +177,14 @@ const handleUninstallExtension = async (name: string) => {
<template>
<common-page show-footer>
<template #action>
<n-button v-if="currentTab == 'status'" class="ml-16" type="info" @click="handleSetCli">
{{ $gettext('Set as CLI Default Version') }}
</n-button>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
<n-button
v-if="currentTab == 'fpm-config'"
class="ml-16"
type="primary"
@click="handleSaveFPMConfig"
>
{{ $gettext('Save') }}
</n-button>
<n-button
v-if="currentTab == 'error-log'"
class="ml-16"
type="primary"
@click="handleClearErrorLog"
>
{{ $gettext('Clear Error Log') }}
</n-button>
<n-button
v-if="currentTab == 'slow-log'"
class="ml-16"
type="primary"
@click="handleClearSlowLog"
>
{{ $gettext('Clear Slow Log') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<service-status :service="`php-fpm-${version}`" show-reload />
<n-flex vertical>
<service-status :service="`php-fpm-${version}`" show-reload />
<n-button type="info" @click="handleSetCli">
{{ $gettext('Set as CLI Default Version') }}
</n-button>
</n-flex>
</n-tab-pane>
<n-tab-pane name="extensions" :tab="$gettext('Extension Management')">
<n-flex vertical>
@@ -232,7 +200,7 @@ const handleUninstallExtension = async (name: string) => {
</n-flex>
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Main Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -253,10 +221,15 @@ const handleUninstallExtension = async (name: string) => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="fpm-config" :tab="$gettext('FPM Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -277,7 +250,12 @@ const handleUninstallExtension = async (name: string) => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveFPMConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="load" :tab="$gettext('Load Status')">
<n-data-table
@@ -292,11 +270,25 @@ const handleUninstallExtension = async (name: string) => {
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
<realtime-log :service="'php-fpm-' + version" />
</n-tab-pane>
<n-tab-pane name="error-log" :tab="$gettext('Error Logs')">
<realtime-log :path="errorLog" />
<n-tab-pane name="log" :tab="$gettext('Error Logs')">
<n-flex vertical>
<n-flex>
<n-button type="primary" @click="handleClearLog">
{{ $gettext('Clear Log') }}
</n-button>
</n-flex>
<realtime-log :path="log" />
</n-flex>
</n-tab-pane>
<n-tab-pane name="slow-log" :tab="$gettext('Slow Logs')">
<realtime-log :path="slowLog" />
<n-flex vertical>
<n-flex>
<n-button type="primary" @click="handleClearSlowLog">
{{ $gettext('Clear Slow Log') }}
</n-button>
</n-flex>
<realtime-log :path="slowLog" />
</n-flex>
</n-tab-pane>
</n-tabs>
</common-page>

View File

@@ -52,35 +52,27 @@ onMounted(() => {
<template>
<common-page show-footer>
<template #action>
<n-button v-if="currentTab == 'status'" class="ml-16" type="primary" @click="handleSave">
{{ $gettext('Save') }}
</n-button>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Status')">
<n-space vertical>
<n-flex vertical>
<n-card :title="$gettext('Access Information')">
<n-alert type="info">
{{ $gettext('Access URL:') }} <a :href="url" target="_blank">{{ url }}</a>
</n-alert>
</n-card>
<n-card :title="$gettext('Modify Port')">
<n-input-number v-model:value="newPort" :min="1" :max="65535" />
<n-flex>
<n-input-number v-model:value="newPort" :min="1" :max="65535" />
<n-button type="primary" @click="handleSave">
{{ $gettext('Save') }}
</n-button>
</n-flex>
{{ $gettext('Modify phpMyAdmin access port') }}
</n-card>
</n-space>
</n-flex>
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Modify Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -100,7 +92,12 @@ onMounted(() => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
</n-tabs>
</common-page>

View File

@@ -36,24 +36,6 @@ const handleSaveStorageConfig = () => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'registryConfig'"
class="ml-16"
type="primary"
@click="handleSaveRegistryConfig"
>
{{ $gettext('Save') }}
</n-button>
<n-button
v-if="currentTab == 'storageConfig'"
class="ml-16"
type="primary"
@click="handleSaveStorageConfig"
>
{{ $gettext('Save') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<n-flex vertical>
@@ -68,7 +50,7 @@ const handleSaveStorageConfig = () => {
</n-flex>
</n-tab-pane>
<n-tab-pane name="registryConfig" :tab="$gettext('Registry Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -88,10 +70,15 @@ const handleSaveStorageConfig = () => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveRegistryConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="storageConfig" :tab="$gettext('Storage Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -111,7 +98,12 @@ const handleSaveStorageConfig = () => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveStorageConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
<realtime-log service="podman" />

View File

@@ -60,33 +60,12 @@ const handleClearLog = async () => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
<n-button
v-if="currentTab == 'user-config'"
class="ml-16"
type="primary"
@click="handleSaveUserConfig"
>
{{ $gettext('Save') }}
</n-button>
<n-button v-if="currentTab == 'log'" class="ml-16" type="primary" @click="handleClearLog">
{{ $gettext('Clear Log') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<service-status service="postgresql" show-reload />
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Main Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -106,10 +85,15 @@ const handleClearLog = async () => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="user-config" :tab="$gettext('User Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -129,7 +113,12 @@ const handleClearLog = async () => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveUserConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="load" :tab="$gettext('Load Status')">
<n-data-table
@@ -142,7 +131,14 @@ const handleClearLog = async () => {
/>
</n-tab-pane>
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
<realtime-log service="postgresql" />
<n-flex vertical>
<n-flex>
<n-button type="primary" @click="handleClearLog">
{{ $gettext('Clear Log') }}
</n-button>
</n-flex>
<realtime-log service="postgresql" />
</n-flex>
</n-tab-pane>
<n-tab-pane name="slow-log" :tab="$gettext('Slow Logs')">
<realtime-log :path="log" />

View File

@@ -154,31 +154,28 @@ onMounted(() => {
<template>
<common-page show-footer>
<template #action>
<n-button v-if="currentTab == 'status'" class="ml-16" type="primary" @click="handleSavePort">
{{ $gettext('Save') }}
</n-button>
<n-button
v-if="currentTab == 'users'"
class="ml-16"
type="primary"
@click="addUserModal = true"
>
{{ $gettext('Add User') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<n-flex vertical>
<service-status service="pure-ftpd" />
<n-card :title="$gettext('Port Settings')">
<n-input-number v-model:value="port" :min="1" :max="65535" />
<n-flex>
<n-input-number v-model:value="port" :min="1" :max="65535" />
<n-button type="primary" @click="handleSavePort">
{{ $gettext('Save') }}
</n-button>
</n-flex>
{{ $gettext('Modify Pure-Ftpd listening port') }}
</n-card>
</n-flex>
</n-tab-pane>
<n-tab-pane name="users" :tab="$gettext('User Management')">
<n-flex vertical>
<n-flex>
<n-button type="primary" @click="addUserModal = true">
{{ $gettext('Add User') }}
</n-button>
</n-flex>
<n-data-table
striped
remote

View File

@@ -45,22 +45,12 @@ const handleSaveConfig = () => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<service-status service="redis" />
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Main Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -80,7 +70,12 @@ const handleSaveConfig = () => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="load" :tab="$gettext('Load Status')">
<n-data-table

View File

@@ -188,30 +188,17 @@ onMounted(() => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
<n-button
v-if="currentTab == 'modules'"
class="ml-16"
type="primary"
@click="addModuleModal = true"
>
{{ $gettext('Add Module') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<service-status service="rsyncd" />
</n-tab-pane>
<n-tab-pane name="modules" :tab="$gettext('Module Management')">
<n-flex vertical>
<n-flex>
<n-button type="primary" @click="addModuleModal = true">
{{ $gettext('Add Module') }}
</n-button>
</n-flex>
<n-data-table
striped
remote
@@ -235,7 +222,7 @@ onMounted(() => {
</n-flex>
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Main Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -255,7 +242,12 @@ onMounted(() => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
<realtime-log service="rsyncd" />

View File

@@ -97,12 +97,12 @@ onMounted(() => {
<template>
<common-page show-footer>
<template #action>
<n-button class="ml-16" type="primary" @click="addMountModal = true">
{{ $gettext('Add Mount') }}
</n-button>
</template>
<n-flex vertical>
<n-flex>
<n-button type="primary" @click="addMountModal = true">
{{ $gettext('Add Mount') }}
</n-button>
</n-flex>
<n-data-table
striped
remote

View File

@@ -295,33 +295,17 @@ onUnmounted(() => {
<template>
<common-page show-footer>
<template #action>
<n-button
v-if="currentTab == 'config'"
class="ml-16"
type="primary"
@click="handleSaveConfig"
>
{{ $gettext('Save') }}
</n-button>
<n-button
v-if="currentTab == 'processes'"
class="ml-16"
type="primary"
@click="createProcessModal = true"
>
{{ $gettext('Add Process') }}
</n-button>
<n-button v-if="currentTab == 'log'" class="ml-16" type="primary" @click="handleClearLog">
{{ $gettext('Clear Log') }}
</n-button>
</template>
<n-tabs v-model:value="currentTab" type="line" animated>
<n-tab-pane name="status" :tab="$gettext('Running Status')">
<service-status v-if="serviceName != ''" :service="serviceName" />
</n-tab-pane>
<n-tab-pane name="processes" :tab="$gettext('Process Management')">
<n-flex vertical>
<n-flex>
<n-button type="primary" @click="createProcessModal = true">
{{ $gettext('Add Process') }}
</n-button>
</n-flex>
<n-data-table
striped
remote
@@ -345,7 +329,7 @@ onUnmounted(() => {
</n-flex>
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Main Configuration')">
<n-space vertical>
<n-flex vertical>
<n-alert type="warning">
{{
$gettext(
@@ -365,13 +349,25 @@ onUnmounted(() => {
formatOnPaste: true
}"
/>
</n-space>
<n-flex>
<n-button type="primary" @click="handleSaveConfig">
{{ $gettext('Save') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
<realtime-log service="supervisor" />
</n-tab-pane>
<n-tab-pane name="log" :tab="$gettext('Daemon Logs')">
<realtime-log path="/var/log/supervisor/supervisord.log" />
<n-flex vertical>
<n-flex>
<n-button type="primary" @click="handleClearLog">
{{ $gettext('Clear Log') }}
</n-button>
</n-flex>
<realtime-log path="/var/log/supervisor/supervisord.log" />
</n-flex>
</n-tab-pane>
</n-tabs>
</common-page>

View File

@@ -163,7 +163,7 @@ watch(
onMounted(() => {
useRequest(app.isInstalled('nginx')).onSuccess(({ data }) => {
if (data.installed) {
if (data) {
useRequest(website.list(1, 10000)).onSuccess(({ data }: { data: any }) => {
for (const item of data.items) {
websites.value.push({

View File

@@ -39,7 +39,7 @@ const getAsyncData = () => {
websites.value = []
useRequest(app.isInstalled('nginx')).onSuccess(({ data }) => {
if (data.installed) {
if (data) {
useRequest(website.list(1, 10000)).onSuccess(({ data }) => {
for (const item of data.items) {
websites.value.push({

View File

@@ -13,7 +13,7 @@ import {
} from 'echarts/components'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { NButton, NPopconfirm } from 'naive-ui'
import { NButton, NPopconfirm, useThemeVars } from 'naive-ui'
import { useGettext } from 'vue3-gettext'
import dashboard from '@/api/panel/dashboard'
@@ -35,6 +35,7 @@ use([
])
const { current: locale, $gettext } = useGettext()
const themeVars = useThemeVars()
const tabStore = useTabStore()
const realtime = ref<Realtime | null>(null)
@@ -115,13 +116,13 @@ const current = reactive({
const statusColor = (percentage: number) => {
if (percentage >= 90) {
return 'var(--error-color)'
return themeVars.value.errorColor
} else if (percentage >= 80) {
return 'var(--warning-color)'
return themeVars.value.warningColor
} else if (percentage >= 70) {
return 'var(--info-color)'
return themeVars.value.infoColor
}
return 'var(--success-color)'
return themeVars.value.successColor
}
const statusText = (percentage: number) => {
@@ -448,7 +449,7 @@ if (import.meta.hot) {
</template>
{{ $gettext('Are you sure you want to restart the panel?') }}
</n-popconfirm>
<n-button type="success" @click="handleUpdate"> {{ $gettext('Update') }} </n-button>
<n-button type="info" @click="handleUpdate"> {{ $gettext('Update') }} </n-button>
</n-flex>
</template>
</n-page-header>
@@ -701,11 +702,7 @@ if (import.meta.hot) {
<n-thing>
<template #avatar>
<div class="mt-8">
<the-icon
:size="30"
:icon="item.icon"
color="var(--primary-color)"
/>
<the-icon :size="30" :icon="item.icon" />
</div>
</template>
<template #header>

View File

@@ -52,13 +52,6 @@ const handleUpdate = () => {
<template>
<common-page show-footer>
<template #action>
<div>
<n-button v-if="versions" class="ml-16" type="primary" @click="handleUpdate">
{{ $gettext('Update Now') }}
</n-button>
</div>
</template>
<n-timeline v-if="versions" pt-10>
<n-timeline-item
v-for="(item, index) in versions"
@@ -76,6 +69,9 @@ const handleUpdate = () => {
noImgZoomIn
/>
</n-timeline-item>
<n-button class="ml-16" type="primary" @click="handleUpdate">
{{ $gettext('Update Now') }}
</n-button>
</n-timeline>
<div v-else pt-40>
<n-result

View File

@@ -127,7 +127,7 @@ const columns: DataTableColumns<RowData> = [
}
},
() => [
h(TheIcon, { icon, size: 24, color: `var(--primary-color)` }),
h(TheIcon, { icon, size: 24 }),
h(NEllipsis, null, {
default: () => {
if (row.symlink) {

View File

@@ -28,7 +28,7 @@ const channels = [
</script>
<template>
<n-space vertical>
<n-flex vertical>
<n-alert type="info">
{{
$gettext(
@@ -56,7 +56,7 @@ const channels = [
<n-input v-model:value="model.backup_path" :placeholder="$gettext('/www/backup')" />
</n-form-item>
</n-form>
</n-space>
</n-flex>
</template>
<style scoped lang="scss"></style>

View File

@@ -257,7 +257,7 @@ watch(
<n-date-picker
v-model:value="createModel.expired_at"
type="datetime"
placeholder="$gettext('Please select the expiration time')"
:placeholder="$gettext('Please select the expiration time')"
w-full
/>
</n-form-item>
@@ -290,7 +290,7 @@ watch(
<n-date-picker
v-model:value="updateModel.expired_at"
type="datetime"
placeholder="$gettext('Please select the expiration time')"
:placeholder="$gettext('Please select the expiration time')"
w-full
/>
</n-form-item>

View File

@@ -67,7 +67,7 @@ watch(createModel, (value) => {
onMounted(() => {
useRequest(app.isInstalled('nginx')).onSuccess(({ data }) => {
if (data.installed) {
if (data) {
useRequest(website.list(1, 10000)).onSuccess(({ data }: { data: any }) => {
for (const item of data.items) {
websites.value.push({

View File

@@ -98,7 +98,7 @@ const handleTest = async () => {
>
{{ $gettext('Current project: %{ current }', { current: current }) }}
</n-alert>
<n-progress v-if="inTest" :percentage="progress" color="var(--primary-color)" processing />
<n-progress v-if="inTest" :percentage="progress" processing />
</n-flex>
<n-flex vertical items-center pt-40>
<div w-800>
@@ -111,13 +111,8 @@ const handleTest = async () => {
<n-number-animation :from="0" :to="cpuTotal" show-separator />
</div>
<div v-else>{{ $gettext('Pending benchmark') }}</div>
<n-progress
type="circle"
:percentage="100"
:stroke-width="3"
color="var(--primary-color)"
>
<the-icon :size="50" icon="bi:cpu" color="var(--primary-color)" />
<n-progress type="circle" :percentage="100" :stroke-width="3">
<the-icon :size="50" icon="bi:cpu" />
</n-progress>
{{ $gettext('CPU') }}
</n-flex>
@@ -176,13 +171,8 @@ const handleTest = async () => {
<n-number-animation :from="0" :to="memory.score" show-separator />
</div>
<div v-else>{{ $gettext('Pending benchmark') }}</div>
<n-progress
type="circle"
:percentage="100"
:stroke-width="3"
color="var(--primary-color)"
>
<the-icon :size="50" icon="bi:memory" color="var(--primary-color)" />
<n-progress type="circle" :percentage="100" :stroke-width="3">
<the-icon :size="50" icon="bi:memory" />
</n-progress>
{{ $gettext('Memory') }}
</n-flex>
@@ -207,13 +197,8 @@ const handleTest = async () => {
<n-number-animation :from="0" :to="disk.score" show-separator />
</div>
<div v-else>{{ $gettext('Pending benchmark') }}</div>
<n-progress
type="circle"
:percentage="100"
:stroke-width="3"
color="var(--primary-color)"
>
<the-icon :size="50" icon="bi:hdd-stack" color="var(--primary-color)" />
<n-progress type="circle" :percentage="100" :stroke-width="3">
<the-icon :size="50" icon="bi:hdd-stack" />
</n-progress>
{{ $gettext('Disk') }}
</n-flex>

View File

@@ -172,55 +172,6 @@ const onCreateListen = () => {
<template>
<common-page show-footer :title="title">
<template #action>
<n-flex>
<n-tag v-if="current === 'config'" type="warning">
{{
$gettext(
'If you modify the original text, other modifications will not take effect after clicking save!'
)
}}
</n-tag>
<n-popconfirm v-if="current === 'config'" @positive-click="handleReset">
<template #trigger>
<n-button type="success">
{{ $gettext('Reset Configuration') }}
</n-button>
</template>
{{ $gettext('Are you sure you want to reset the configuration?') }}
</n-popconfirm>
<n-button
v-if="current === 'rewrite'"
class="ml-16"
type="success"
@click="proxyBuilderModal = true"
>
{{ $gettext('Generate Reverse Proxy Configuration') }}
</n-button>
<n-button
v-if="current === 'https'"
:loading="isObtainCert"
:disabled="isObtainCert"
class="ml-16"
type="success"
@click="handleObtainCert"
>
{{ $gettext('One-click Certificate Issuance') }}
</n-button>
<n-button v-if="current !== 'log'" class="ml-16" type="primary" @click="handleSave">
{{ $gettext('Save') }}
</n-button>
<n-popconfirm v-if="current === 'log'" @positive-click="clearLog">
<template #trigger>
<n-button type="primary">
{{ $gettext('Clear Logs') }}
</n-button>
</template>
{{ $gettext('Are you sure you want to clear?') }}
</n-popconfirm>
</n-flex>
</template>
<n-tabs v-model:value="current" type="line" animated>
<n-tab-pane name="listen" :tab="$gettext('Domain & Listening')">
<n-form v-if="setting">
@@ -287,6 +238,15 @@ const onCreateListen = () => {
</n-tab-pane>
<n-tab-pane name="https" tab="HTTPS">
<n-flex vertical v-if="setting">
<n-button
:loading="isObtainCert"
:disabled="isObtainCert"
class="ml-16"
type="success"
@click="handleObtainCert"
>
{{ $gettext('One-click Certificate Issuance') }}
</n-button>
<n-card v-if="setting.https && setting.ssl_issuer != ''">
<n-descriptions :title="$gettext('Certificate Information')" :column="2">
<n-descriptions-item>
@@ -369,6 +329,9 @@ const onCreateListen = () => {
</n-tab-pane>
<n-tab-pane name="rewrite" :tab="$gettext('Rewrite')">
<n-flex vertical>
<n-button type="success" @click="proxyBuilderModal = true">
{{ $gettext('Generate Reverse Proxy Configuration') }}
</n-button>
<n-form label-placement="left" label-width="auto">
<n-form-item :label="$gettext('Presets')">
<n-select
@@ -395,6 +358,13 @@ const onCreateListen = () => {
</n-tab-pane>
<n-tab-pane name="config" :tab="$gettext('Configuration')">
<n-flex vertical>
<n-alert type="info" w-full>
{{
$gettext(
'If you modify the original text, other modifications will not take effect after clicking save!'
)
}}
</n-alert>
<n-alert type="warning" w-full>
{{
$gettext(
@@ -402,6 +372,14 @@ const onCreateListen = () => {
)
}}
</n-alert>
<n-popconfirm @positive-click="handleReset">
<template #trigger>
<n-button type="success">
{{ $gettext('Reset Configuration') }}
</n-button>
</template>
{{ $gettext('Are you sure you want to reset the configuration?') }}
</n-popconfirm>
<Editor
v-if="setting"
v-model:value="setting.raw"
@@ -424,6 +402,14 @@ const onCreateListen = () => {
<n-tag>{{ setting.log }}</n-tag>
{{ $gettext('view') }}.
</n-alert>
<n-popconfirm @positive-click="clearLog">
<template #trigger>
<n-button type="primary">
{{ $gettext('Clear Logs') }}
</n-button>
</template>
{{ $gettext('Are you sure you want to clear?') }}
</n-popconfirm>
</n-flex>
<realtime-log :path="setting.log" />
</n-flex>
@@ -441,6 +427,9 @@ const onCreateListen = () => {
</n-flex>
</n-tab-pane>
</n-tabs>
<n-button v-if="current !== 'log'" type="primary" @click="handleSave">
{{ $gettext('Save') }}
</n-button>
</common-page>
<ProxyBuilderModal v-model:show="proxyBuilderModal" v-model:config="setting.rewrite" />
</template>

View File

@@ -38,46 +38,67 @@ onMounted(() => {
<template>
<n-tabs v-model:value="currentTab" type="line" placement="left" animated>
<n-tab-pane name="default-page" :tab="$gettext('Default Page')">
<Editor
v-model:value="defaultPageModel.index"
language="html"
theme="vs-dark"
height="60vh"
mt-8
:options="{
automaticLayout: true,
formatOnType: true,
formatOnPaste: true
}"
/>
<n-flex vertical>
<Editor
v-model:value="defaultPageModel.index"
language="html"
theme="vs-dark"
height="60vh"
mt-8
:options="{
automaticLayout: true,
formatOnType: true,
formatOnPaste: true
}"
/>
<n-flex>
<n-button type="primary">
{{ $gettext('Save Changes') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="404-page" :tab="$gettext('404 Page')">
<Editor
v-model:value="defaultPageModel.not_found"
language="html"
theme="vs-dark"
height="60vh"
mt-8
:options="{
automaticLayout: true,
formatOnType: true,
formatOnPaste: true
}"
/>
<n-flex>
<Editor
v-model:value="defaultPageModel.not_found"
language="html"
theme="vs-dark"
height="60vh"
mt-8
:options="{
automaticLayout: true,
formatOnType: true,
formatOnPaste: true
}"
/>
<n-flex>
<n-button type="primary">
{{ $gettext('Save Changes') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="stop-page" :tab="$gettext('Stop Page')">
<Editor
v-model:value="defaultPageModel.stop"
language="html"
theme="vs-dark"
height="60vh"
mt-8
:options="{
automaticLayout: true,
formatOnType: true,
formatOnPaste: true
}"
/>
<n-flex>
<Editor
v-model:value="defaultPageModel.stop"
language="html"
theme="vs-dark"
height="60vh"
mt-8
:options="{
automaticLayout: true,
formatOnType: true,
formatOnPaste: true
}"
/>
<n-flex>
<n-button type="primary">
{{ $gettext('Save Changes') }}
</n-button>
</n-flex>
</n-flex>
</n-tab-pane>
<n-tab-pane name="default-site" :tab="$gettext('Default Site')">
<n-alert type="info">待开发</n-alert>

14
web/types/theme.d.ts vendored
View File

@@ -23,17 +23,6 @@ interface Tab {
height: number
}
interface OtherColor {
/** 信息 */
info: string
/** 成功 */
success: string
/** 警告 */
warning: string
/** 错误 */
error: string
}
declare namespace Theme {
interface Setting {
isMobile: boolean
@@ -41,9 +30,6 @@ declare namespace Theme {
sider: Sider
header: Header
tab: Tab
/** 主题颜色 */
primaryColor: string
otherColor: OtherColor
/** 语言 */
locale: string
/** 名称 */

View File

@@ -25,32 +25,7 @@ const config: UserConfig = {
'card-shadow',
{ 'box-shadow': '0 1px 2px -2px #00000029, 0 3px 6px #0000001f, 0 5px 12px 4px #00000017' }
]
],
theme: {
colors: {
primary: 'var(--primary-color)',
primary_hover: 'var(--primary-color-hover)',
primary_pressed: 'var(--primary-color-pressed)',
primary_active: 'var(--primary-color-active)',
info: 'var(--info-color)',
info_hover: 'var(--info-color-hover)',
info_pressed: 'var(--info-color-pressed)',
info_active: 'var(--info-color-active)',
success: 'var(--success-color)',
success_hover: 'var(--success-color-hover)',
success_pressed: 'var(--success-color-pressed)',
success_active: 'var(--success-color-active)',
warning: 'var(--warning-color)',
warning_hover: 'var(--warning-color-hover)',
warning_pressed: 'var(--warning-color-pressed)',
warning_active: 'var(--warning-color-active)',
error: 'var(--error-color)',
error_hover: 'var(--error-color-hover)',
error_pressed: 'var(--error-color-pressed)',
error_active: 'var(--error-color-active)',
dark: '#18181c'
}
}
]
}
export default defineConfig(config)