mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 12:40:25 +08:00
feat: 添加前端翻译
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5,9 +5,11 @@ defineOptions({
|
||||
|
||||
import benchmark from '@/api/apps/benchmark'
|
||||
import TheIcon from '@/components/custom/TheIcon.vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const inTest = ref(false)
|
||||
const current = ref('CPU')
|
||||
const current = ref($gettext('CPU'))
|
||||
const progress = ref(0)
|
||||
|
||||
const tests = [
|
||||
@@ -62,35 +64,35 @@ const cpuTotal = computed(() => {
|
||||
|
||||
const memory = ref({
|
||||
score: 0,
|
||||
bandwidth: '待跑分',
|
||||
latency: '待跑分'
|
||||
bandwidth: $gettext('Pending benchmark'),
|
||||
latency: $gettext('Pending benchmark')
|
||||
})
|
||||
|
||||
const disk = ref({
|
||||
score: 0,
|
||||
1024: {
|
||||
read_iops: '待跑分',
|
||||
read_speed: '待跑分',
|
||||
write_iops: '待跑分',
|
||||
write_speed: '待跑分'
|
||||
read_iops: $gettext('Pending benchmark'),
|
||||
read_speed: $gettext('Pending benchmark'),
|
||||
write_iops: $gettext('Pending benchmark'),
|
||||
write_speed: $gettext('Pending benchmark')
|
||||
},
|
||||
4: {
|
||||
read_iops: '待跑分',
|
||||
read_speed: '待跑分',
|
||||
write_iops: '待跑分',
|
||||
write_speed: '待跑分'
|
||||
read_iops: $gettext('Pending benchmark'),
|
||||
read_speed: $gettext('Pending benchmark'),
|
||||
write_iops: $gettext('Pending benchmark'),
|
||||
write_speed: $gettext('Pending benchmark')
|
||||
},
|
||||
512: {
|
||||
read_iops: '待跑分',
|
||||
read_speed: '待跑分',
|
||||
write_iops: '待跑分',
|
||||
write_speed: '待跑分'
|
||||
read_iops: $gettext('Pending benchmark'),
|
||||
read_speed: $gettext('Pending benchmark'),
|
||||
write_iops: $gettext('Pending benchmark'),
|
||||
write_speed: $gettext('Pending benchmark')
|
||||
},
|
||||
64: {
|
||||
read_iops: '待跑分',
|
||||
read_speed: '待跑分',
|
||||
write_iops: '待跑分',
|
||||
write_speed: '待跑分'
|
||||
read_iops: $gettext('Pending benchmark'),
|
||||
read_speed: $gettext('Pending benchmark'),
|
||||
write_iops: $gettext('Pending benchmark'),
|
||||
write_speed: $gettext('Pending benchmark')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -123,10 +125,18 @@ const handleTest = async () => {
|
||||
<common-page show-footer>
|
||||
<n-flex vertical>
|
||||
<n-alert type="warning">
|
||||
跑分结果仅供参考,受系统资源调度和缓存等因素影响可能与实际性能有所偏差!
|
||||
{{
|
||||
$gettext(
|
||||
'Benchmark results are for reference only and may differ from actual performance due to system resource scheduling, caching, and other factors!'
|
||||
)
|
||||
}}
|
||||
</n-alert>
|
||||
<n-alert v-if="inTest" title="跑分中,可能需要较长时间..." type="info">
|
||||
当前项目:{{ current }}
|
||||
<n-alert
|
||||
v-if="inTest"
|
||||
:title="$gettext('Benchmarking in progress, it may take some time...')"
|
||||
type="info"
|
||||
>
|
||||
{{ $gettext('Current project: %{ current }', { current: current }) }}
|
||||
</n-alert>
|
||||
<n-progress v-if="inTest" :percentage="progress" color="var(--primary-color)" processing />
|
||||
</n-flex>
|
||||
@@ -138,12 +148,12 @@ const handleTest = async () => {
|
||||
<template #trigger>
|
||||
<n-flex vertical items-center>
|
||||
<div v-if="cpuTotal.single !== 0 && cpuTotal.multi !== 0">
|
||||
单核
|
||||
{{ $gettext('Single-core') }}
|
||||
<n-number-animation :from="0" :to="cpuTotal.single" show-separator />
|
||||
/ 多核
|
||||
/ {{ $gettext('Multi-core') }}
|
||||
<n-number-animation :from="0" :to="cpuTotal.multi" show-separator />
|
||||
</div>
|
||||
<div v-else>待跑分</div>
|
||||
<div v-else>{{ $gettext('Pending benchmark') }}</div>
|
||||
<n-progress
|
||||
type="circle"
|
||||
:percentage="100"
|
||||
@@ -152,37 +162,86 @@ const handleTest = async () => {
|
||||
>
|
||||
<TheIcon :size="50" icon="bi:cpu" color="var(--primary-color)" />
|
||||
</n-progress>
|
||||
CPU
|
||||
{{ $gettext('CPU') }}
|
||||
</n-flex>
|
||||
</template>
|
||||
<n-table :single-line="false" striped>
|
||||
<tr>
|
||||
<th>图像处理</th>
|
||||
<td>单核 {{ cpu.image.single }} / 多核 {{ cpu.image.multi }}</td>
|
||||
<th>{{ $gettext('Image Processing') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Single-core %{ single } / Multi-core %{ multi }', {
|
||||
single: cpu.image.single,
|
||||
multi: cpu.image.multi
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>机器学习</th>
|
||||
<td>单核 {{ cpu.machine.single }} / 多核 {{ cpu.machine.multi }}</td>
|
||||
<th>{{ $gettext('Machine Learning') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Single-core %{ single } / Multi-core %{ multi }', {
|
||||
single: cpu.machine.single,
|
||||
multi: cpu.machine.multi
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>程序编译</th>
|
||||
<td>单核 {{ cpu.compile.single }} / 多核 {{ cpu.compile.multi }}</td>
|
||||
<th>{{ $gettext('Program Compilation') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Single-core %{ single } / Multi-core %{ multi }', {
|
||||
single: cpu.compile.single,
|
||||
multi: cpu.compile.multi
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>AES 加密</th>
|
||||
<td>单核 {{ cpu.encryption.single }} / 多核 {{ cpu.encryption.multi }}</td>
|
||||
<th>{{ $gettext('AES Encryption') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Single-core %{ single } / Multi-core %{ multi }', {
|
||||
single: cpu.encryption.single,
|
||||
multi: cpu.encryption.multi
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>压缩/解压缩</th>
|
||||
<td>单核 {{ cpu.compression.single }} / 多核 {{ cpu.compression.multi }}</td>
|
||||
<th>{{ $gettext('Compression/Decompression') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Single-core %{ single } / Multi-core %{ multi }', {
|
||||
single: cpu.compression.single,
|
||||
multi: cpu.compression.multi
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>物理仿真</th>
|
||||
<td>单核 {{ cpu.physics.single }} / 多核 {{ cpu.physics.multi }}</td>
|
||||
<th>{{ $gettext('Physics Simulation') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Single-core %{ single } / Multi-core %{ multi }', {
|
||||
single: cpu.physics.single,
|
||||
multi: cpu.physics.multi
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>JSON 解析</th>
|
||||
<td>单核 {{ cpu.json.single }} / 多核 {{ cpu.json.multi }}</td>
|
||||
<th>{{ $gettext('JSON Parsing') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Single-core %{ single } / Multi-core %{ multi }', {
|
||||
single: cpu.json.single,
|
||||
multi: cpu.json.multi
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
</n-table>
|
||||
</n-popover>
|
||||
@@ -194,7 +253,7 @@ const handleTest = async () => {
|
||||
<div v-if="memory.score !== 0">
|
||||
<n-number-animation :from="0" :to="memory.score" show-separator />
|
||||
</div>
|
||||
<div v-else>待跑分</div>
|
||||
<div v-else>{{ $gettext('Pending benchmark') }}</div>
|
||||
<n-progress
|
||||
type="circle"
|
||||
:percentage="100"
|
||||
@@ -203,16 +262,16 @@ const handleTest = async () => {
|
||||
>
|
||||
<TheIcon :size="50" icon="bi:memory" color="var(--primary-color)" />
|
||||
</n-progress>
|
||||
内存
|
||||
{{ $gettext('Memory') }}
|
||||
</n-flex>
|
||||
</template>
|
||||
<n-table :single-line="false" striped>
|
||||
<tr>
|
||||
<th>内存带宽</th>
|
||||
<th>{{ $gettext('Memory Bandwidth') }}</th>
|
||||
<td>{{ memory.bandwidth }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>内存延迟</th>
|
||||
<th>{{ $gettext('Memory Latency') }}</th>
|
||||
<td>{{ memory.latency }}</td>
|
||||
</tr>
|
||||
</n-table>
|
||||
@@ -225,7 +284,7 @@ const handleTest = async () => {
|
||||
<div v-if="disk.score !== 0">
|
||||
<n-number-animation :from="0" :to="disk.score" show-separator />
|
||||
</div>
|
||||
<div v-else>待跑分</div>
|
||||
<div v-else>{{ $gettext('Pending benchmark') }}</div>
|
||||
<n-progress
|
||||
type="circle"
|
||||
:percentage="100"
|
||||
@@ -234,41 +293,97 @@ const handleTest = async () => {
|
||||
>
|
||||
<TheIcon :size="50" icon="bi:hdd-stack" color="var(--primary-color)" />
|
||||
</n-progress>
|
||||
硬盘
|
||||
{{ $gettext('Disk') }}
|
||||
</n-flex>
|
||||
</template>
|
||||
<n-table :single-line="false" striped>
|
||||
<tr>
|
||||
<th>4KB 读取</th>
|
||||
<td>速度 {{ disk['4'].read_speed }} / {{ disk['4'].read_iops }} IOPS</td>
|
||||
<th>{{ $gettext('4KB Read') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Speed %{ speed } / %{ iops } IOPS', {
|
||||
speed: disk['4'].read_speed,
|
||||
iops: disk['4'].read_iops
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>4KB 写入</th>
|
||||
<td>速度 {{ disk['4'].write_speed }} / {{ disk['4'].write_iops }} IOPS</td>
|
||||
<th>{{ $gettext('4KB Write') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Speed %{ speed } / %{ iops } IOPS', {
|
||||
speed: disk['4'].write_speed,
|
||||
iops: disk['4'].write_iops
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>64KB 读取</th>
|
||||
<td>速度 {{ disk['64'].read_speed }} / {{ disk['64'].read_iops }} IOPS</td>
|
||||
<th>{{ $gettext('64KB Read') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Speed %{ speed } / %{ iops } IOPS', {
|
||||
speed: disk['64'].read_speed,
|
||||
iops: disk['64'].read_iops
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>64KB 写入</th>
|
||||
<td>速度 {{ disk['64'].write_speed }} / {{ disk['64'].write_iops }} IOPS</td>
|
||||
<th>{{ $gettext('64KB Write') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Speed %{ speed } / %{ iops } IOPS', {
|
||||
speed: disk['64'].write_speed,
|
||||
iops: disk['64'].write_iops
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>512KB 读取</th>
|
||||
<td>速度 {{ disk['512'].read_speed }} / {{ disk['512'].read_iops }} IOPS</td>
|
||||
<th>{{ $gettext('512KB Read') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Speed %{ speed } / %{ iops } IOPS', {
|
||||
speed: disk['512'].read_speed,
|
||||
iops: disk['512'].read_iops
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>512KB 写入</th>
|
||||
<td>速度 {{ disk['512'].write_speed }} / {{ disk['512'].write_iops }} IOPS</td>
|
||||
<th>{{ $gettext('512KB Write') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Speed %{ speed } / %{ iops } IOPS', {
|
||||
speed: disk['512'].write_speed,
|
||||
iops: disk['512'].write_iops
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>1MB 读取</th>
|
||||
<td>速度 {{ disk['1024'].read_speed }} / {{ disk['1024'].read_iops }} IOPS</td>
|
||||
<th>{{ $gettext('1MB Read') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Speed %{ speed } / %{ iops } IOPS', {
|
||||
speed: disk['1024'].read_speed,
|
||||
iops: disk['1024'].read_iops
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>1MB 写入</th>
|
||||
<td>速度 {{ disk['1024'].write_speed }} / {{ disk['1024'].write_iops }} IOPS</td>
|
||||
<th>{{ $gettext('1MB Write') }}</th>
|
||||
<td>
|
||||
{{
|
||||
$gettext('Speed %{ speed } / %{ iops } IOPS', {
|
||||
speed: disk['1024'].write_speed,
|
||||
iops: disk['1024'].write_iops
|
||||
})
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
</n-table>
|
||||
</n-popover>
|
||||
@@ -284,7 +399,7 @@ const handleTest = async () => {
|
||||
mt-40
|
||||
w-200
|
||||
>
|
||||
{{ inTest ? '跑分中...' : '开始跑分' }}
|
||||
{{ inTest ? $gettext('Benchmarking...') : $gettext('Start Benchmark') }}
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</common-page>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: '耗子跑分',
|
||||
title: $gettext('Rat Benchmark'),
|
||||
icon: 'dashicons:performance',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -5,10 +5,12 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import docker from '@/api/apps/docker'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
@@ -20,7 +22,7 @@ const { data: config } = useRequest(docker.getConfig, {
|
||||
})
|
||||
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const getStatus = async () => {
|
||||
@@ -33,27 +35,27 @@ const getIsEnabled = async () => {
|
||||
|
||||
const handleSaveConfig = () => {
|
||||
useRequest(docker.updateConfig(config.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleStart = () => {
|
||||
useRequest(systemctl.start('docker')).onSuccess(() => {
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
getStatus()
|
||||
})
|
||||
}
|
||||
|
||||
const handleStop = () => {
|
||||
useRequest(systemctl.stop('docker')).onSuccess(() => {
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
getStatus()
|
||||
})
|
||||
}
|
||||
|
||||
const handleRestart = () => {
|
||||
useRequest(systemctl.restart('docker')).onSuccess(() => {
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
getStatus()
|
||||
})
|
||||
}
|
||||
@@ -61,10 +63,10 @@ const handleRestart = () => {
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable('docker')
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable('docker')
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
@@ -85,17 +87,17 @@ onMounted(() => {
|
||||
@click="handleSaveConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-flex vertical>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -105,30 +107,30 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
确定要停止 Docker 吗?
|
||||
{{ $gettext('Are you sure you want to stop Docker?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-flex>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="config" tab="配置">
|
||||
<n-tab-pane name="config" :tab="$gettext('Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 Docker 配置文件(/etc/docker/daemon.json)
|
||||
{{ $gettext('This modifies the Docker configuration file (/etc/docker/daemon.json)') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="config"
|
||||
@@ -144,7 +146,7 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
|
||||
<realtime-log service="docker" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Docker',
|
||||
title: $gettext('Docker'),
|
||||
icon: 'logos:docker-icon',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -4,6 +4,7 @@ defineOptions({
|
||||
})
|
||||
|
||||
import { NButton, NDataTable, NInput, NPopconfirm, NSwitch } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import fail2ban from '@/api/apps/fail2ban'
|
||||
import app from '@/api/panel/app'
|
||||
@@ -11,6 +12,7 @@ import systemctl from '@/api/panel/systemctl'
|
||||
import website from '@/api/panel/website'
|
||||
import { renderIcon } from '@/utils'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
@@ -37,18 +39,18 @@ const statusType = computed(() => {
|
||||
return status.value ? 'success' : 'error'
|
||||
})
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const jailsColumns: any = [
|
||||
{
|
||||
title: '名称',
|
||||
title: $gettext('Name'),
|
||||
key: 'name',
|
||||
minWidth: 250,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
title: $gettext('Status'),
|
||||
key: 'enabled',
|
||||
minWidth: 60,
|
||||
align: 'center',
|
||||
@@ -61,11 +63,11 @@ const jailsColumns: any = [
|
||||
})
|
||||
}
|
||||
},
|
||||
{ title: '最大尝试', key: 'max_retry', minWidth: 150, ellipsis: { tooltip: true } },
|
||||
{ title: '封禁时间', key: 'ban_time', minWidth: 150, ellipsis: { tooltip: true } },
|
||||
{ title: '周期', key: 'find_time', minWidth: 150, ellipsis: { tooltip: true } },
|
||||
{ title: $gettext('Max Retries'), key: 'max_retry', minWidth: 150, ellipsis: { tooltip: true } },
|
||||
{ title: $gettext('Ban Time'), key: 'ban_time', minWidth: 150, ellipsis: { tooltip: true } },
|
||||
{ title: $gettext('Find Time'), key: 'find_time', minWidth: 150, ellipsis: { tooltip: true } },
|
||||
{
|
||||
title: '操作',
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 280,
|
||||
align: 'center',
|
||||
@@ -84,7 +86,7 @@ const jailsColumns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => '查看',
|
||||
default: () => $gettext('View'),
|
||||
icon: renderIcon('material-symbols:visibility', { size: 14 })
|
||||
}
|
||||
),
|
||||
@@ -95,7 +97,7 @@ const jailsColumns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定删除规则' + row.name + '吗?'
|
||||
return $gettext('Are you sure you want to delete rule %{ name }?', { name: row.name })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -106,7 +108,7 @@ const jailsColumns: any = [
|
||||
style: 'margin-left: 15px'
|
||||
},
|
||||
{
|
||||
default: () => '删除',
|
||||
default: () => $gettext('Delete'),
|
||||
icon: renderIcon('material-symbols:delete-outline', { size: 14 })
|
||||
}
|
||||
)
|
||||
@@ -127,7 +129,7 @@ const banedIPColumns: any = [
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
@@ -141,7 +143,7 @@ const banedIPColumns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定解封' + row.ip + '吗?'
|
||||
return $gettext('Are you sure you want to unban %{ ip }?', { ip: row.ip })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -151,7 +153,7 @@ const banedIPColumns: any = [
|
||||
type: 'error'
|
||||
},
|
||||
{
|
||||
default: () => '解封',
|
||||
default: () => $gettext('Unban'),
|
||||
icon: renderIcon('material-symbols:delete-outline', { size: 14 })
|
||||
}
|
||||
)
|
||||
@@ -171,7 +173,7 @@ const getWhiteList = async () => {
|
||||
|
||||
const handleSaveWhiteList = () => {
|
||||
useRequest(fail2ban.setWhitelist(white.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -206,43 +208,43 @@ const getIsEnabled = async () => {
|
||||
|
||||
const handleStart = async () => {
|
||||
await systemctl.start('fail2ban')
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable('fail2ban')
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable('fail2ban')
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
await systemctl.stop('fail2ban')
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async () => {
|
||||
await systemctl.restart('fail2ban')
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleReload = async () => {
|
||||
await systemctl.reload('fail2ban')
|
||||
window.$message.success('重载成功')
|
||||
window.$message.success($gettext('Reloaded successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleAddJail = () => {
|
||||
useRequest(fail2ban.add(addJailModel.value)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('添加成功')
|
||||
window.$message.success($gettext('Added successfully'))
|
||||
addJailModal.value = false
|
||||
})
|
||||
}
|
||||
@@ -250,7 +252,7 @@ const handleAddJail = () => {
|
||||
const handleDeleteJail = (name: string) => {
|
||||
useRequest(fail2ban.delete(name)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Deleted successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -263,7 +265,7 @@ const getJailInfo = async (name: string) => {
|
||||
|
||||
const handleUnBan = (name: string, ip: string) => {
|
||||
useRequest(fail2ban.unban(name, ip)).onSuccess(() => {
|
||||
window.$message.success('解封成功')
|
||||
window.$message.success($gettext('Unbanned successfully'))
|
||||
getJailInfo(name)
|
||||
})
|
||||
}
|
||||
@@ -291,7 +293,7 @@ onMounted(() => {
|
||||
@click="handleSaveWhiteList"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存白名单
|
||||
{{ $gettext('Save Whitelist') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'jails'"
|
||||
@@ -300,17 +302,17 @@ onMounted(() => {
|
||||
@click="addJailModal = true"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:add" />
|
||||
添加规则
|
||||
{{ $gettext('Add Rule') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-space vertical>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -320,40 +322,40 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
停止 Fail2ban 会导致所有规则失效,确定停止吗?
|
||||
{{ $gettext('Stopping Fail2ban will disable all rules. Are you sure you want to stop?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
<n-button type="primary" @click="handleReload">
|
||||
<TheIcon :size="20" icon="material-symbols:refresh-rounded" />
|
||||
重载
|
||||
{{ $gettext('Reload') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
<n-card title="IP 白名单">
|
||||
<n-card :title="$gettext('IP Whitelist')">
|
||||
<n-input
|
||||
v-model:value="white"
|
||||
type="textarea"
|
||||
autosize
|
||||
placeholder="IP 白名单,以英文逗号,分隔"
|
||||
:placeholder="$gettext('IP whitelist, separated by commas')"
|
||||
/>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="jails" tab="规则管理">
|
||||
<n-card title="规则列表" :segmented="true">
|
||||
<n-tab-pane name="jails" :tab="$gettext('Rule Management')">
|
||||
<n-card :title="$gettext('Rule List')" :segmented="true">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -376,56 +378,56 @@ onMounted(() => {
|
||||
/>
|
||||
</n-card>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
|
||||
<realtime-log service="fail2ban" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</common-page>
|
||||
<n-modal v-model:show="addJailModal" title="添加规则">
|
||||
<n-card closable @close="() => (addJailModal = false)" title="添加规则" style="width: 60vw">
|
||||
<n-modal v-model:show="addJailModal" :title="$gettext('Add Rule')">
|
||||
<n-card closable @close="() => (addJailModal = false)" :title="$gettext('Add Rule')" style="width: 60vw">
|
||||
<n-space vertical>
|
||||
<n-alert type="info">
|
||||
在设置周期内(秒)有超过最大重试(次)的IP访问,将禁止该IP禁止时间(秒)
|
||||
{{ $gettext('If an IP exceeds the maximum retries within the find time (seconds), it will be banned for the ban time (seconds)') }}
|
||||
</n-alert>
|
||||
<n-alert type="warning">
|
||||
防护端口自动获取,如果修改了规则项对应的端口,请删除重新添加,否则防护可能不会生效
|
||||
{{ $gettext('Protected ports are automatically obtained. If you modify the port corresponding to a rule, please delete and re-add the rule, otherwise protection may not be effective') }}
|
||||
</n-alert>
|
||||
|
||||
<n-form :model="addJailModel">
|
||||
<n-form-item label="类型">
|
||||
<n-form-item :label="$gettext('Type')">
|
||||
<n-select
|
||||
v-model:value="addJailModel.type"
|
||||
:options="[
|
||||
{ label: '网站', value: 'website' },
|
||||
{ label: '服务', value: 'service' }
|
||||
{ label: $gettext('Website'), value: 'website' },
|
||||
{ label: $gettext('Service'), value: 'service' }
|
||||
]"
|
||||
>
|
||||
</n-select>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="addJailModel.type === 'website'" label="选择网站">
|
||||
<n-form-item v-if="addJailModel.type === 'website'" :label="$gettext('Select Website')">
|
||||
<n-select
|
||||
v-model:value="addJailModel.website_name"
|
||||
:options="websites"
|
||||
placeholder="选择网站"
|
||||
:placeholder="$gettext('Select Website')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="addJailModel.type === 'website'" label="保护模式">
|
||||
<n-form-item v-if="addJailModel.type === 'website'" :label="$gettext('Protection Mode')">
|
||||
<n-select
|
||||
v-model:value="addJailModel.website_mode"
|
||||
:options="[
|
||||
{ label: 'CC', value: 'cc' },
|
||||
{ label: '路径', value: 'path' }
|
||||
{ label: $gettext('Path'), value: 'path' }
|
||||
]"
|
||||
>
|
||||
</n-select>
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
v-if="addJailModel.type === 'website' && addJailModel.website_mode === 'path'"
|
||||
label="保护路径"
|
||||
:label="$gettext('Protection Path')"
|
||||
>
|
||||
<n-input v-model:value="addJailModel.website_path" placeholder="保护路径" />
|
||||
<n-input v-model:value="addJailModel.website_path" :placeholder="$gettext('Protection Path')" />
|
||||
</n-form-item>
|
||||
<n-form-item v-if="addJailModel.type === 'service'" label="服务">
|
||||
<n-form-item v-if="addJailModel.type === 'service'" :label="$gettext('Service')">
|
||||
<n-select
|
||||
v-model:value="addJailModel.name"
|
||||
:options="[
|
||||
@@ -436,36 +438,36 @@ onMounted(() => {
|
||||
>
|
||||
</n-select>
|
||||
</n-form-item>
|
||||
<n-form-item path="maxretry" label="最大尝试">
|
||||
<n-form-item path="maxretry" :label="$gettext('Max Retries')">
|
||||
<n-input-number v-model:value="addJailModel.maxretry" @keydown.enter.prevent :min="1" />
|
||||
</n-form-item>
|
||||
<n-form-item path="findtime" label="周期">
|
||||
<n-form-item path="findtime" :label="$gettext('Find Time')">
|
||||
<n-input-number v-model:value="addJailModel.findtime" @keydown.enter.prevent :min="1" />
|
||||
</n-form-item>
|
||||
<n-form-item path="bantime" label="禁止时间">
|
||||
<n-form-item path="bantime" :label="$gettext('Ban Time')">
|
||||
<n-input-number v-model:value="addJailModel.bantime" @keydown.enter.prevent :min="1" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleAddJail">提交</n-button>
|
||||
<n-button type="info" block @click="handleAddJail">{{ $gettext('Submit') }}</n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
<n-modal v-model:show="jailModal" title="查看规则">
|
||||
<n-card closable @close="() => (jailModal = false)" title="查看规则" style="width: 60vw">
|
||||
<n-modal v-model:show="jailModal" :title="$gettext('View Rule')">
|
||||
<n-card closable @close="() => (jailModal = false)" :title="$gettext('View Rule')" style="width: 60vw">
|
||||
<n-space vertical>
|
||||
<n-card title="规则信息" :segmented="true">
|
||||
<n-card :title="$gettext('Rule Information')" :segmented="true">
|
||||
<n-space vertical>
|
||||
<n-space>
|
||||
<n-text>当前封禁</n-text>
|
||||
<n-text>{{ $gettext('Currently Banned') }}</n-text>
|
||||
<n-text>{{ jailCurrentlyBan }}</n-text>
|
||||
</n-space>
|
||||
<n-space>
|
||||
<n-text>总封禁</n-text>
|
||||
<n-text>{{ $gettext('Total Bans') }}</n-text>
|
||||
<n-text>{{ jailTotalBan }}</n-text>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
<n-card title="封禁列表" :segmented="true">
|
||||
<n-card :title="$gettext('Ban List')" :segmented="true">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Fail2ban',
|
||||
title: $gettext('Fail2ban'),
|
||||
icon: 'mdi:wall-fire',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -5,10 +5,12 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import frp from '@/api/apps/frp'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('frps')
|
||||
const status = ref({
|
||||
frpc: false,
|
||||
@@ -25,8 +27,8 @@ const config = ref({
|
||||
|
||||
const statusStr = computed(() => {
|
||||
return {
|
||||
frpc: status.value.frpc ? '正常运行中' : '已停止运行',
|
||||
frps: status.value.frps ? '正常运行中' : '已停止运行'
|
||||
frpc: status.value.frpc ? $gettext('Running normally') : $gettext('Stopped'),
|
||||
frps: status.value.frps ? $gettext('Running normally') : $gettext('Stopped')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -48,36 +50,36 @@ const getConfig = async () => {
|
||||
const handleSaveConfig = (service: string) => {
|
||||
useRequest(frp.saveConfig(service, config.value[service as keyof typeof config.value])).onSuccess(
|
||||
() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const handleStart = async (name: string) => {
|
||||
await systemctl.start(name)
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleStop = async (name: string) => {
|
||||
await systemctl.stop(name)
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async (name: string) => {
|
||||
await systemctl.restart(name)
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleIsEnabled = async (name: string) => {
|
||||
if (isEnabled.value[name as keyof typeof isEnabled.value]) {
|
||||
await systemctl.enable(name)
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable(name)
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
@@ -94,11 +96,11 @@ onMounted(() => {
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="frps" tab="Frps">
|
||||
<n-space vertical>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled.frps" @update:value="handleIsEnabled('frps')">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -108,29 +110,29 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart('frps')">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop('frps')">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
确定要停止 Frps 吗?
|
||||
{{ $gettext('Are you sure you want to stop Frps?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart('frps')">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
<n-card title="修改配置">
|
||||
<n-card :title="$gettext('Modify Configuration')">
|
||||
<template #header-extra>
|
||||
<n-button type="primary" @click="handleSaveConfig('frps')">
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline-rounded" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<Editor
|
||||
@@ -150,11 +152,11 @@ onMounted(() => {
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="frpc" tab="Frpc">
|
||||
<n-space vertical>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled.frpc" @update:value="handleIsEnabled('frpc')">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -164,29 +166,29 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart('frpc')">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop('frpc')">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
确定要停止 Frpc 吗?
|
||||
{{ $gettext('Are you sure you want to stop Frpc?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart('frpc')">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
<n-card title="修改配置">
|
||||
<n-card :title="$gettext('Modify Configuration')">
|
||||
<template #header-extra>
|
||||
<n-button type="primary" @click="handleSaveConfig('frpc')">
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline-rounded" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<Editor
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Frp',
|
||||
title: $gettext('Frp'),
|
||||
icon: 'icon-park-outline:connection-box',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -5,17 +5,19 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import gitea from '@/api/apps/gitea'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
const config = ref('')
|
||||
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const getStatus = async () => {
|
||||
@@ -32,35 +34,35 @@ const getConfig = async () => {
|
||||
|
||||
const handleSaveConfig = () => {
|
||||
useRequest(gitea.saveConfig(config.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleStart = async () => {
|
||||
await systemctl.start('gitea')
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
await systemctl.stop('gitea')
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async () => {
|
||||
await systemctl.restart('gitea')
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable('gitea')
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable('gitea')
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
@@ -82,16 +84,16 @@ onMounted(() => {
|
||||
@click="handleSaveConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-card title="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -101,29 +103,29 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
确定要停止 Gitea 吗?
|
||||
{{ $gettext('Are you sure you want to stop Gitea?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="config" tab="修改配置">
|
||||
<n-tab-pane name="config" :tab="$gettext('Modify Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 Gitea 配置文件,如果您不了解各参数的含义,请不要随意修改!
|
||||
{{ $gettext('This modifies the Gitea configuration file. If you do not understand the meaning of each parameter, please do not modify it randomly!') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="config"
|
||||
@@ -139,7 +141,7 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
|
||||
<realtime-log service="gitea" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Gitea',
|
||||
title: $gettext('Gitea'),
|
||||
icon: 'simple-icons:gitea',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -5,10 +5,12 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NDataTable, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import memcached from '@/api/apps/memcached'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
@@ -17,19 +19,19 @@ const statusType = computed(() => {
|
||||
return status.value ? 'success' : 'error'
|
||||
})
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const loadColumns: any = [
|
||||
{
|
||||
title: '属性',
|
||||
title: $gettext('Property'),
|
||||
key: 'name',
|
||||
minWidth: 200,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '当前值',
|
||||
title: $gettext('Current Value'),
|
||||
key: 'value',
|
||||
minWidth: 200,
|
||||
ellipsis: { tooltip: true }
|
||||
@@ -56,36 +58,36 @@ const { data: config } = useRequest(memcached.getConfig, {
|
||||
|
||||
const handleSaveConfig = () => {
|
||||
useRequest(memcached.updateConfig(config.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleStart = async () => {
|
||||
await systemctl.start('memcached')
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable('memcached')
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable('memcached')
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
await systemctl.stop('memcached')
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async () => {
|
||||
await systemctl.restart('memcached')
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
@@ -105,17 +107,17 @@ onMounted(() => {
|
||||
@click="handleSaveConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-space vertical>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -125,27 +127,27 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
停止 Memcached 会导致使用 Memcached 的网站无法访问,确定要停止吗?
|
||||
{{ $gettext('Stopping Memcached will cause websites using Memcached to become inaccessible. Are you sure you want to stop?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="config" tab="服务配置">
|
||||
<n-tab-pane name="config" :tab="$gettext('Service Configuration')">
|
||||
<n-space vertical>
|
||||
<Editor
|
||||
v-model:value="config"
|
||||
@@ -161,7 +163,7 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="load" tab="负载状态">
|
||||
<n-tab-pane name="load" :tab="$gettext('Load Status')">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -171,7 +173,7 @@ onMounted(() => {
|
||||
:data="load"
|
||||
/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
|
||||
<realtime-log service="memcached" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Memcached',
|
||||
title: $gettext('Memcached'),
|
||||
icon: 'logos:memcached',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -5,17 +5,19 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import minio from '@/api/apps/minio'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
const env = ref('')
|
||||
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const getStatus = async () => {
|
||||
@@ -32,35 +34,35 @@ const getEnv = async () => {
|
||||
|
||||
const handleSaveEnv = () => {
|
||||
useRequest(minio.saveEnv(env.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleStart = async () => {
|
||||
await systemctl.start('minio')
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
await systemctl.stop('minio')
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async () => {
|
||||
await systemctl.restart('minio')
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable('minio')
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable('minio')
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
@@ -77,16 +79,16 @@ onMounted(() => {
|
||||
<template #action>
|
||||
<n-button v-if="currentTab == 'env'" class="ml-16" type="primary" @click="handleSaveEnv">
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-card title="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -96,30 +98,29 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
确定要停止 Minio 吗?
|
||||
{{ $gettext('Are you sure you want to stop Minio?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="env" tab="环境变量">
|
||||
<n-tab-pane name="env" :tab="$gettext('Environment Variables')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 Minio 环境变量文件
|
||||
/etc/default/minio,如果您不了解各参数的含义,请不要随意修改!
|
||||
{{ $gettext('This is modifying the Minio environment variable file /etc/default/minio. If you do not understand the meaning of each parameter, please do not modify it arbitrarily!') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="env"
|
||||
@@ -135,7 +136,7 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
|
||||
<realtime-log service="minio" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Minio',
|
||||
title: $gettext('Minio'),
|
||||
icon: 'simple-icons:minio',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -5,10 +5,12 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NDataTable, NInput, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import mysql from '@/api/apps/mysql'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
@@ -30,19 +32,19 @@ const statusType = computed(() => {
|
||||
return status.value ? 'success' : 'error'
|
||||
})
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const loadColumns: any = [
|
||||
{
|
||||
title: '属性',
|
||||
title: $gettext('Property'),
|
||||
key: 'name',
|
||||
minWidth: 200,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '当前值',
|
||||
title: $gettext('Current Value'),
|
||||
key: 'value',
|
||||
minWidth: 200,
|
||||
ellipsis: { tooltip: true }
|
||||
@@ -59,54 +61,54 @@ const getIsEnabled = async () => {
|
||||
|
||||
const handleSaveConfig = () => {
|
||||
useRequest(mysql.saveConfig(config.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleClearErrorLog = () => {
|
||||
useRequest(mysql.clearErrorLog()).onSuccess(() => {
|
||||
window.$message.success('清空成功')
|
||||
window.$message.success($gettext('Cleared successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleClearSlowLog = () => {
|
||||
useRequest(mysql.clearSlowLog()).onSuccess(() => {
|
||||
window.$message.success('清空成功')
|
||||
window.$message.success($gettext('Cleared successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable('mysqld')
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable('mysqld')
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
|
||||
const handleStart = async () => {
|
||||
await systemctl.start('mysqld')
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
await systemctl.stop('mysqld')
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async () => {
|
||||
await systemctl.restart('mysqld')
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleSetRootPassword = async () => {
|
||||
await mysql.setRootPassword(rootPassword.value)
|
||||
window.$message.success('修改成功')
|
||||
window.$message.success($gettext('Modified successfully'))
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@@ -125,7 +127,7 @@ onMounted(() => {
|
||||
@click="handleSaveConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'error-log'"
|
||||
@@ -134,7 +136,7 @@ onMounted(() => {
|
||||
@click="handleClearErrorLog"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:delete-outline" />
|
||||
清空日志
|
||||
{{ $gettext('Clear Log') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'slow-log'"
|
||||
@@ -143,17 +145,17 @@ onMounted(() => {
|
||||
@click="handleClearSlowLog"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:delete-outline" />
|
||||
清空慢日志
|
||||
{{ $gettext('Clear Slow Log') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-space vertical>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -163,40 +165,40 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
停止 MySQL 会导致使用 MySQL 的网站无法访问,确定要停止吗?
|
||||
{{ $gettext('Stopping MySQL will cause websites using MySQL to become inaccessible. Are you sure you want to stop?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
<n-card title="Root 密码">
|
||||
<n-card :title="$gettext('Root Password')">
|
||||
<n-space vertical>
|
||||
<n-input
|
||||
v-model:value="rootPassword"
|
||||
type="password"
|
||||
show-password-on="click"
|
||||
></n-input>
|
||||
<n-button type="primary" @click="handleSetRootPassword">保存修改</n-button>
|
||||
<n-button type="primary" @click="handleSetRootPassword">{{ $gettext('Save Changes') }}</n-button>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="config" tab="修改配置">
|
||||
<n-tab-pane name="config" :tab="$gettext('Modify Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 MySQL 主配置文件,如果您不了解各参数的含义,请不要随意修改!
|
||||
{{ $gettext('This modifies the MySQL main configuration file. If you do not understand the meaning of each parameter, please do not modify it randomly!') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="config"
|
||||
@@ -212,7 +214,7 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="load" tab="负载状态">
|
||||
<n-tab-pane name="load" :tab="$gettext('Load Status')">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -222,10 +224,10 @@ onMounted(() => {
|
||||
:data="load"
|
||||
/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
|
||||
<realtime-log service="mysqld" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="slow-log" tab="慢查询日志">
|
||||
<n-tab-pane name="slow-log" :tab="$gettext('Slow Query Log')">
|
||||
<realtime-log :path="slowLog" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Percona(MySQL)',
|
||||
title: $gettext('Percona (MySQL)'),
|
||||
icon: 'logos:percona',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -5,10 +5,12 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NDataTable, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import nginx from '@/api/apps/nginx'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
@@ -28,19 +30,19 @@ const statusType = computed(() => {
|
||||
})
|
||||
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const columns: any = [
|
||||
{
|
||||
title: '属性',
|
||||
title: $gettext('Property'),
|
||||
key: 'name',
|
||||
minWidth: 200,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '当前值',
|
||||
title: $gettext('Current Value'),
|
||||
key: 'value',
|
||||
minWidth: 200,
|
||||
ellipsis: { tooltip: true }
|
||||
@@ -57,48 +59,48 @@ const getIsEnabled = async () => {
|
||||
|
||||
const handleSaveConfig = () => {
|
||||
useRequest(nginx.saveConfig(config.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleClearErrorLog = () => {
|
||||
useRequest(nginx.clearErrorLog()).onSuccess(() => {
|
||||
window.$message.success('清空成功')
|
||||
window.$message.success($gettext('Cleared successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable('nginx')
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable('nginx')
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
|
||||
const handleStart = async () => {
|
||||
await systemctl.start('nginx')
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
await systemctl.stop('nginx')
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async () => {
|
||||
await systemctl.restart('nginx')
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleReload = async () => {
|
||||
await systemctl.reload('nginx')
|
||||
window.$message.success('重载成功')
|
||||
window.$message.success($gettext('Reloaded successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
@@ -118,7 +120,7 @@ onMounted(() => {
|
||||
@click="handleSaveConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'error-log'"
|
||||
@@ -127,16 +129,16 @@ onMounted(() => {
|
||||
@click="handleClearErrorLog"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:delete-outline" />
|
||||
清空日志
|
||||
{{ $gettext('Clear Log') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-card title="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -146,33 +148,33 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
停止 OpenResty 会导致所有网站无法访问,确定要停止吗?
|
||||
{{ $gettext('Stopping OpenResty will cause all websites to become inaccessible. Are you sure you want to stop?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
<n-button type="primary" @click="handleReload">
|
||||
<TheIcon :size="20" icon="material-symbols:refresh-rounded" />
|
||||
重载
|
||||
{{ $gettext('Reload') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="config" tab="修改配置">
|
||||
<n-tab-pane name="config" :tab="$gettext('Modify Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 OpenResty 主配置文件,如果您不了解各参数的含义,请不要随意修改!
|
||||
{{ $gettext('This modifies the OpenResty main configuration file. If you do not understand the meaning of each parameter, please do not modify it randomly!') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="config"
|
||||
@@ -188,7 +190,7 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="load" tab="负载状态">
|
||||
<n-tab-pane name="load" :tab="$gettext('Load Status')">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -198,10 +200,10 @@ onMounted(() => {
|
||||
:data="load"
|
||||
/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
|
||||
<realtime-log service="nginx" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="error-log" tab="错误日志">
|
||||
<n-tab-pane name="error-log" :tab="$gettext('Error Logs')">
|
||||
<realtime-log :path="errorLog" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'OpenResty(Nginx)',
|
||||
title: $gettext('OpenResty (Nginx)'),
|
||||
icon: 'logos:nginx',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NDataTable, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import php from '@/api/apps/php'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
import { renderIcon } from '@/utils'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const props = defineProps({
|
||||
version: {
|
||||
type: Number,
|
||||
@@ -42,26 +44,26 @@ const statusType = computed(() => {
|
||||
return status.value ? 'success' : 'error'
|
||||
})
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const extensionColumns: any = [
|
||||
{
|
||||
title: '拓展名',
|
||||
title: $gettext('Extension Name'),
|
||||
key: 'name',
|
||||
minWidth: 250,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
title: $gettext('Description'),
|
||||
key: 'description',
|
||||
resizable: true,
|
||||
minWidth: 250,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 240,
|
||||
align: 'center',
|
||||
@@ -76,7 +78,7 @@ const extensionColumns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定安装 ' + row.name + ' 吗?'
|
||||
return $gettext('Are you sure you want to install %{ name }?', { name: row.name })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -86,7 +88,7 @@ const extensionColumns: any = [
|
||||
type: 'info'
|
||||
},
|
||||
{
|
||||
default: () => '安装',
|
||||
default: () => $gettext('Install'),
|
||||
icon: renderIcon('material-symbols:download-rounded', { size: 14 })
|
||||
}
|
||||
)
|
||||
@@ -102,7 +104,7 @@ const extensionColumns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定卸载 ' + row.name + ' 吗?'
|
||||
return $gettext('Are you sure you want to uninstall %{ name }?', { name: row.name })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -112,7 +114,7 @@ const extensionColumns: any = [
|
||||
type: 'error'
|
||||
},
|
||||
{
|
||||
default: () => '删除',
|
||||
default: () => $gettext('Delete'),
|
||||
icon: renderIcon('material-symbols:delete-outline', { size: 14 })
|
||||
}
|
||||
)
|
||||
@@ -127,14 +129,14 @@ const extensionColumns: any = [
|
||||
|
||||
const loadColumns: any = [
|
||||
{
|
||||
title: '属性',
|
||||
title: $gettext('Property'),
|
||||
key: 'name',
|
||||
minWidth: 200,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '当前值',
|
||||
title: $gettext('Current Value'),
|
||||
key: 'value',
|
||||
minWidth: 200,
|
||||
ellipsis: { tooltip: true }
|
||||
@@ -151,78 +153,78 @@ const getIsEnabled = async () => {
|
||||
|
||||
const handleSetCli = async () => {
|
||||
useRequest(php.setCli(version.value)).onSuccess(() => {
|
||||
window.$message.success('设置成功')
|
||||
window.$message.success($gettext('Set successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleSaveConfig = async () => {
|
||||
useRequest(php.saveConfig(version.value, config.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleSaveFPMConfig = async () => {
|
||||
useRequest(php.saveFPMConfig(version.value, fpmConfig.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleClearErrorLog = async () => {
|
||||
useRequest(php.clearErrorLog(version.value)).onSuccess(() => {
|
||||
window.$message.success('清空成功')
|
||||
window.$message.success($gettext('Cleared successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleClearSlowLog = async () => {
|
||||
useRequest(php.clearSlowLog(version.value)).onSuccess(() => {
|
||||
window.$message.success('清空成功')
|
||||
window.$message.success($gettext('Cleared successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable(`php-fpm-${version.value}`)
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable(`php-fpm-${version.value}`)
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
|
||||
const handleStart = async () => {
|
||||
await systemctl.start(`php-fpm-${version.value}`)
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
await systemctl.stop(`php-fpm-${version.value}`)
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async () => {
|
||||
await systemctl.restart(`php-fpm-${version.value}`)
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleReload = async () => {
|
||||
await systemctl.reload(`php-fpm-${version.value}`)
|
||||
window.$message.success('重载成功')
|
||||
window.$message.success($gettext('Reloaded successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleInstallExtension = async (slug: string) => {
|
||||
useRequest(php.installExtension(version.value, slug)).onSuccess(() => {
|
||||
window.$message.success('任务已提交,请前往后台任务查看进度')
|
||||
window.$message.success($gettext('Task submitted, please check progress in background tasks'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleUninstallExtension = async (name: string) => {
|
||||
useRequest(php.uninstallExtension(version.value, name)).onSuccess(() => {
|
||||
window.$message.success('任务已提交,请前往后台任务查看进度')
|
||||
window.$message.success($gettext('Task submitted, please check progress in background tasks'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -236,7 +238,7 @@ onMounted(() => {
|
||||
<common-page show-footer>
|
||||
<template #action>
|
||||
<n-button v-if="currentTab == 'status'" class="ml-16" type="info" @click="handleSetCli">
|
||||
设为 CLI 默认版本
|
||||
{{ $gettext('Set as CLI Default Version') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'config'"
|
||||
@@ -245,7 +247,7 @@ onMounted(() => {
|
||||
@click="handleSaveConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'fpm-config'"
|
||||
@@ -254,7 +256,7 @@ onMounted(() => {
|
||||
@click="handleSaveFPMConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'error-log'"
|
||||
@@ -263,7 +265,7 @@ onMounted(() => {
|
||||
@click="handleClearErrorLog"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:delete-outline" />
|
||||
清空错误日志
|
||||
{{ $gettext('Clear Error Log') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'slow-log'"
|
||||
@@ -272,17 +274,17 @@ onMounted(() => {
|
||||
@click="handleClearSlowLog"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:delete-outline" />
|
||||
清空慢日志
|
||||
{{ $gettext('Clear Slow Log') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-space vertical>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -292,32 +294,32 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
停止 PHP {{ version }} 会导致使用 PHP {{ version }} 的网站无法访问,确定要停止吗?
|
||||
{{ $gettext('Stopping PHP %{ version } will cause websites using PHP %{ version } to become inaccessible. Are you sure you want to stop?', { version: version }) }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
<n-button type="primary" @click="handleReload">
|
||||
<TheIcon :size="20" icon="material-symbols:refresh-rounded" />
|
||||
重载
|
||||
{{ $gettext('Reload') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="extensions" tab="拓展管理">
|
||||
<n-card title="拓展列表" :segmented="true">
|
||||
<n-tab-pane name="extensions" :tab="$gettext('Extension Management')">
|
||||
<n-card :title="$gettext('Extension List')" :segmented="true">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -329,10 +331,10 @@ onMounted(() => {
|
||||
/>
|
||||
</n-card>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="config" tab="主配置">
|
||||
<n-tab-pane name="config" :tab="$gettext('Main Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 PHP {{ version }} 主配置文件,如果您不了解各参数的含义,请不要随意修改!
|
||||
{{ $gettext('This modifies the PHP %{ version } main configuration file. If you do not understand the meaning of each parameter, please do not modify it randomly!', { version: version }) }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="config"
|
||||
@@ -348,10 +350,10 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="fpm-config" tab="FPM 配置">
|
||||
<n-tab-pane name="fpm-config" :tab="$gettext('FPM Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 PHP {{ version }} FPM 配置文件,如果您不了解各参数的含义,请不要随意修改!
|
||||
{{ $gettext('This modifies the PHP %{ version } FPM configuration file. If you do not understand the meaning of each parameter, please do not modify it randomly!', { version: version }) }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="fpmConfig"
|
||||
@@ -367,7 +369,7 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="load" tab="负载状态">
|
||||
<n-tab-pane name="load" :tab="$gettext('Load Status')">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -377,13 +379,13 @@ onMounted(() => {
|
||||
:data="load"
|
||||
/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<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="错误日志">
|
||||
<n-tab-pane name="error-log" :tab="$gettext('Error Logs')">
|
||||
<realtime-log :path="errorLog" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="slow-log" tab="慢日志">
|
||||
<n-tab-pane name="slow-log" :tab="$gettext('Slow Logs')">
|
||||
<realtime-log :path="slowLog" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
@@ -5,9 +5,11 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import phpmyadmin from '@/api/apps/phpmyadmin'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const hostname = ref(window.location.hostname)
|
||||
const port = ref(0)
|
||||
@@ -32,14 +34,14 @@ const getInfo = async () => {
|
||||
|
||||
const handleSave = () => {
|
||||
useRequest(phpmyadmin.port(newPort.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
getInfo()
|
||||
})
|
||||
}
|
||||
|
||||
const handleSaveConfig = () => {
|
||||
useRequest(phpmyadmin.saveConfig(config.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -53,7 +55,7 @@ onMounted(() => {
|
||||
<template #action>
|
||||
<n-button v-if="currentTab == 'status'" class="ml-16" type="primary" @click="handleSave">
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'config'"
|
||||
@@ -62,28 +64,27 @@ onMounted(() => {
|
||||
@click="handleSaveConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Status')">
|
||||
<n-space vertical>
|
||||
<n-card title="访问信息">
|
||||
<n-card :title="$gettext('Access Information')">
|
||||
<n-alert type="info">
|
||||
访问地址: <a :href="url" target="_blank">{{ url }}</a>
|
||||
{{ $gettext('Access URL:') }} <a :href="url" target="_blank">{{ url }}</a>
|
||||
</n-alert>
|
||||
</n-card>
|
||||
<n-card title="修改端口">
|
||||
<n-card :title="$gettext('Modify Port')">
|
||||
<n-input-number v-model:value="newPort" :min="1" :max="65535" />
|
||||
修改 phpMyAdmin 访问端口
|
||||
{{ $gettext('Modify phpMyAdmin access port') }}
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="config" tab="修改配置">
|
||||
<n-tab-pane name="config" :tab="$gettext('Modify Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 phpMyAdmin 的 OpenResty
|
||||
配置文件,如果您不了解各参数的含义,请不要随意修改!
|
||||
{{ $gettext('This modifies the OpenResty configuration file for phpMyAdmin. If you do not understand the meaning of each parameter, please do not modify it randomly!') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="config"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
import type { RouteType } from '~/types/router'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'phpMyAdmin',
|
||||
title: $gettext('phpMyAdmin'),
|
||||
icon: 'simple-icons:phpmyadmin',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -5,10 +5,12 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import podman from '@/api/apps/podman'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
@@ -16,7 +18,7 @@ const registryConfig = ref('')
|
||||
const storageConfig = ref('')
|
||||
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const getStatus = async () => {
|
||||
@@ -34,41 +36,41 @@ const getConfig = async () => {
|
||||
|
||||
const handleSaveRegistryConfig = () => {
|
||||
useRequest(podman.saveRegistryConfig(registryConfig.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleSaveStorageConfig = () => {
|
||||
useRequest(podman.saveStorageConfig(storageConfig.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleStart = async () => {
|
||||
await systemctl.start('podman')
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
await systemctl.stop('podman')
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async () => {
|
||||
await systemctl.restart('podman')
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable('podman')
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable('podman')
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
@@ -90,7 +92,7 @@ onMounted(() => {
|
||||
@click="handleSaveRegistryConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'storageConfig'"
|
||||
@@ -99,20 +101,20 @@ onMounted(() => {
|
||||
@click="handleSaveStorageConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-flex vertical>
|
||||
<n-alert type="info">
|
||||
Podman 是一个无守护进程的容器管理工具,处于停止状态为正常现象且不会影响使用!
|
||||
{{ $gettext('Podman is a daemonless container management tool. Being in a stopped state is normal and does not affect usage!') }}
|
||||
</n-alert>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -122,30 +124,30 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
确定要停止 Podman 吗?
|
||||
{{ $gettext('Are you sure you want to stop Podman?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-flex>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="registryConfig" tab="注册表配置">
|
||||
<n-tab-pane name="registryConfig" :tab="$gettext('Registry Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 Podman 注册表配置文件(/etc/containers/registries.conf)
|
||||
{{ $gettext('This modifies the Podman registry configuration file (/etc/containers/registries.conf)') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="registryConfig"
|
||||
@@ -161,10 +163,10 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="storageConfig" tab="存储配置">
|
||||
<n-tab-pane name="storageConfig" :tab="$gettext('Storage Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 Podman 存储配置文件(/etc/containers/storage.conf)
|
||||
{{ $gettext('This modifies the Podman storage configuration file (/etc/containers/storage.conf)') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="storageConfig"
|
||||
@@ -180,7 +182,7 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
|
||||
<realtime-log service="podman" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Podman',
|
||||
title: $gettext('Podman'),
|
||||
icon: 'devicon:podman',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -5,10 +5,12 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NDataTable, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import postgresql from '@/api/apps/postgresql'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
@@ -30,19 +32,19 @@ const statusType = computed(() => {
|
||||
return status.value ? 'success' : 'error'
|
||||
})
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const loadColumns: any = [
|
||||
{
|
||||
title: '属性',
|
||||
title: $gettext('Property'),
|
||||
key: 'name',
|
||||
minWidth: 200,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '当前值',
|
||||
title: $gettext('Current Value'),
|
||||
key: 'value',
|
||||
minWidth: 200,
|
||||
ellipsis: { tooltip: true }
|
||||
@@ -59,51 +61,51 @@ const getIsEnabled = async () => {
|
||||
|
||||
const handleSaveConfig = async () => {
|
||||
await postgresql.saveConfig(config.value)
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
}
|
||||
|
||||
const handleSaveUserConfig = async () => {
|
||||
await postgresql.saveUserConfig(userConfig.value)
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
}
|
||||
|
||||
const handleClearLog = async () => {
|
||||
await postgresql.clearLog()
|
||||
window.$message.success('清空成功')
|
||||
window.$message.success($gettext('Cleared successfully'))
|
||||
}
|
||||
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable('postgresql')
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable('postgresql')
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
|
||||
const handleStart = async () => {
|
||||
await systemctl.start('postgresql')
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
await systemctl.stop('postgresql')
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async () => {
|
||||
await systemctl.restart('postgresql')
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleReload = async () => {
|
||||
await systemctl.reload('postgresql')
|
||||
window.$message.success('重载成功')
|
||||
window.$message.success($gettext('Reloaded successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
@@ -123,7 +125,7 @@ onMounted(() => {
|
||||
@click="handleSaveConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'user-config'"
|
||||
@@ -132,21 +134,21 @@ onMounted(() => {
|
||||
@click="handleSaveUserConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button v-if="currentTab == 'log'" class="ml-16" type="primary" @click="handleClearLog">
|
||||
<TheIcon :size="18" icon="material-symbols:delete-outline" />
|
||||
清空日志
|
||||
{{ $gettext('Clear Log') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-space vertical>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -156,34 +158,34 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
停止 PostgreSQL 会导致使用 PostgreSQL 的网站无法访问,确定要停止吗?
|
||||
{{ $gettext('Stopping PostgreSQL will cause websites using PostgreSQL to become inaccessible. Are you sure you want to stop?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
<n-button type="primary" @click="handleReload">
|
||||
<TheIcon :size="20" icon="material-symbols:refresh-rounded" />
|
||||
重载
|
||||
{{ $gettext('Reload') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="config" tab="主配置">
|
||||
<n-tab-pane name="config" :tab="$gettext('Main Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 PostgreSQL 主配置文件,如果您不了解各参数的含义,请不要随意修改!
|
||||
{{ $gettext('This modifies the PostgreSQL main configuration file. If you do not understand the meaning of each parameter, please do not modify it randomly!') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="config"
|
||||
@@ -199,10 +201,10 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="user-config" tab="用户配置">
|
||||
<n-tab-pane name="user-config" :tab="$gettext('User Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 PostgreSQL 用户配置文件,如果您不了解各参数的含义,请不要随意修改!
|
||||
{{ $gettext('This modifies the PostgreSQL user configuration file. If you do not understand the meaning of each parameter, please do not modify it randomly!') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="userConfig"
|
||||
@@ -218,7 +220,7 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="load" tab="负载状态">
|
||||
<n-tab-pane name="load" :tab="$gettext('Load Status')">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -228,10 +230,10 @@ onMounted(() => {
|
||||
:data="load"
|
||||
/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
|
||||
<realtime-log service="postgresql" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="slow-log" tab="慢日志">
|
||||
<n-tab-pane name="slow-log" :tab="$gettext('Slow Logs')">
|
||||
<realtime-log :path="log" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'PostgreSQL',
|
||||
title: $gettext('PostgreSQL'),
|
||||
icon: 'logos:postgresql',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -4,11 +4,13 @@ defineOptions({
|
||||
})
|
||||
|
||||
import { NButton, NDataTable, NInput, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import pureftpd from '@/api/apps/pureftpd'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
import { generateRandomString, renderIcon } from '@/utils'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
@@ -20,7 +22,7 @@ const statusType = computed(() => {
|
||||
return status.value ? 'success' : 'error'
|
||||
})
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const addUserModel = ref({
|
||||
@@ -36,21 +38,21 @@ const changePasswordModel = ref({
|
||||
|
||||
const userColumns: any = [
|
||||
{
|
||||
title: '用户名',
|
||||
title: $gettext('Username'),
|
||||
key: 'username',
|
||||
minWidth: 250,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '路径',
|
||||
title: $gettext('Path'),
|
||||
key: 'path',
|
||||
minWidth: 250,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 240,
|
||||
align: 'center',
|
||||
@@ -70,7 +72,7 @@ const userColumns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => '改密',
|
||||
default: () => $gettext('Change Password'),
|
||||
icon: renderIcon('material-symbols:key-outline', { size: 14 })
|
||||
}
|
||||
),
|
||||
@@ -81,7 +83,7 @@ const userColumns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定删除用户' + row.username + '吗?'
|
||||
return $gettext('Are you sure you want to delete user %{ username }?', { username: row.username })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -92,7 +94,7 @@ const userColumns: any = [
|
||||
style: 'margin-left: 15px'
|
||||
},
|
||||
{
|
||||
default: () => '删除',
|
||||
default: () => $gettext('Delete'),
|
||||
icon: renderIcon('material-symbols:delete-outline', { size: 14 })
|
||||
}
|
||||
)
|
||||
@@ -128,36 +130,36 @@ const getPort = async () => {
|
||||
|
||||
const handleSavePort = async () => {
|
||||
useRequest(pureftpd.updatePort(port.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleStart = async () => {
|
||||
await systemctl.start('pure-ftpd')
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable('pure-ftpd')
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Auto-start enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable('pure-ftpd')
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Auto-start disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
await systemctl.stop('pure-ftpd')
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async () => {
|
||||
await systemctl.restart('pure-ftpd')
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
@@ -170,7 +172,7 @@ const handleAddUser = async () => {
|
||||
addUserModel.value.username = ''
|
||||
addUserModel.value.password = generateRandomString(16)
|
||||
addUserModel.value.path = ''
|
||||
window.$message.success('添加成功')
|
||||
window.$message.success($gettext('Added successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -180,14 +182,14 @@ const handleChangePassword = async () => {
|
||||
).onSuccess(() => {
|
||||
refresh()
|
||||
changePasswordModal.value = false
|
||||
window.$message.success('修改成功')
|
||||
window.$message.success($gettext('Modified successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleDeleteUser = async (username: string) => {
|
||||
useRequest(pureftpd.delete(username)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Deleted successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -204,7 +206,7 @@ onMounted(() => {
|
||||
<template #action>
|
||||
<n-button v-if="currentTab == 'status'" class="ml-16" type="primary" @click="handleSavePort">
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'users'"
|
||||
@@ -213,17 +215,17 @@ onMounted(() => {
|
||||
@click="addUserModal = true"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:add" />
|
||||
添加用户
|
||||
{{ $gettext('Add User') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-space vertical>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Auto-start On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Auto-start Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -233,32 +235,32 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
停止 Pure-Ftpd 会导致无法使用 FTP 服务,确定要停止吗?
|
||||
{{ $gettext('Stopping Pure-Ftpd will cause FTP service to be unavailable. Are you sure you want to stop it?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
<n-card title="端口设置">
|
||||
<n-card :title="$gettext('Port Settings')">
|
||||
<n-input-number v-model:value="port" :min="1" :max="65535" />
|
||||
修改 Pure-Ftpd 监听端口
|
||||
{{ $gettext('Modify Pure-Ftpd listening port') }}
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="users" tab="用户管理">
|
||||
<n-card title="用户列表" :segmented="true">
|
||||
<n-tab-pane name="users" :tab="$gettext('User Management')">
|
||||
<n-card :title="$gettext('User List')" :segmented="true">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -281,61 +283,61 @@ onMounted(() => {
|
||||
/>
|
||||
</n-card>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Run Log')">
|
||||
<realtime-log service="pure-ftpd" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</common-page>
|
||||
<n-modal v-model:show="addUserModal" title="创建用户">
|
||||
<n-card closable @close="() => (addUserModal = false)" title="创建用户" style="width: 60vw">
|
||||
<n-modal v-model:show="addUserModal" :title="$gettext('Create User')">
|
||||
<n-card closable @close="() => (addUserModal = false)" :title="$gettext('Create User')" style="width: 60vw">
|
||||
<n-form :model="addUserModel">
|
||||
<n-form-item path="username" label="用户名">
|
||||
<n-form-item path="username" :label="$gettext('Username')">
|
||||
<n-input
|
||||
v-model:value="addUserModel.username"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入用户名"
|
||||
:placeholder="$gettext('Enter username')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="password" label="密码">
|
||||
<n-form-item path="password" :label="$gettext('Password')">
|
||||
<n-input
|
||||
v-model:value="addUserModel.password"
|
||||
type="password"
|
||||
show-password-on="click"
|
||||
@keydown.enter.prevent
|
||||
placeholder="建议使用生成器生成随机密码"
|
||||
:placeholder="$gettext('It is recommended to use the generator to generate a random password')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="path" label="目录">
|
||||
<n-form-item path="path" :label="$gettext('Directory')">
|
||||
<n-input
|
||||
v-model:value="addUserModel.path"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入授权给该用户的目录"
|
||||
:placeholder="$gettext('Enter the directory authorized to the user')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleAddUser">提交</n-button>
|
||||
<n-button type="info" block @click="handleAddUser">{{ $gettext('Submit') }}</n-button>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
<n-modal v-model:show="changePasswordModal">
|
||||
<n-card
|
||||
closable
|
||||
@close="() => (changePasswordModal = false)"
|
||||
title="修改密码"
|
||||
:title="$gettext('Change Password')"
|
||||
style="width: 60vw"
|
||||
>
|
||||
<n-form :model="changePasswordModel">
|
||||
<n-form-item path="password" label="密码">
|
||||
<n-form-item path="password" :label="$gettext('Password')">
|
||||
<n-input
|
||||
v-model:value="changePasswordModel.password"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="建议使用生成器生成随机密码"
|
||||
:placeholder="$gettext('It is recommended to use the generator to generate a random password')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleChangePassword">提交</n-button>
|
||||
<n-button type="info" block @click="handleChangePassword">{{ $gettext('Submit') }}</n-button>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
import type { RouteType } from '~/types/router'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Pure-FTPd',
|
||||
title: $gettext('Pure-FTPd'),
|
||||
icon: 'mdi:server-network',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -5,10 +5,12 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NDataTable, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import redis from '@/api/apps/redis'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
@@ -24,19 +26,19 @@ const statusType = computed(() => {
|
||||
return status.value ? 'success' : 'error'
|
||||
})
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const loadColumns: any = [
|
||||
{
|
||||
title: '属性',
|
||||
title: $gettext('Property'),
|
||||
key: 'name',
|
||||
minWidth: 200,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '当前值',
|
||||
title: $gettext('Current Value'),
|
||||
key: 'value',
|
||||
minWidth: 200,
|
||||
ellipsis: { tooltip: true }
|
||||
@@ -53,36 +55,36 @@ const getIsEnabled = async () => {
|
||||
|
||||
const handleSaveConfig = () => {
|
||||
useRequest(redis.saveConfig(config.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleStart = async () => {
|
||||
await systemctl.start('redis')
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleIsEnabled = async () => {
|
||||
if (isEnabled.value) {
|
||||
await systemctl.enable('redis')
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
} else {
|
||||
await systemctl.disable('redis')
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
}
|
||||
await getIsEnabled()
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
await systemctl.stop('redis')
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
const handleRestart = async () => {
|
||||
await systemctl.restart('redis')
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
await getStatus()
|
||||
}
|
||||
|
||||
@@ -102,17 +104,17 @@ onMounted(() => {
|
||||
@click="handleSaveConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-space vertical>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开 </template>
|
||||
<template #unchecked> 自启动关 </template>
|
||||
<template #checked> {{ $gettext('Autostart On') }} </template>
|
||||
<template #unchecked> {{ $gettext('Autostart Off') }} </template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -122,30 +124,30 @@ onMounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
停止 Redis 会导致使用 Redis 的网站无法访问,确定要停止吗?
|
||||
{{ $gettext('Stopping Redis will cause websites using Redis to become inaccessible. Are you sure you want to stop?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="config" tab="主配置">
|
||||
<n-tab-pane name="config" :tab="$gettext('Main Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 Redis 主配置文件,如果您不了解各参数的含义,请不要随意修改!
|
||||
{{ $gettext('This modifies the Redis main configuration file. If you do not understand the meaning of each parameter, please do not modify it randomly!') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="config"
|
||||
@@ -161,7 +163,7 @@ onMounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="load" tab="负载状态">
|
||||
<n-tab-pane name="load" :tab="$gettext('Load Status')">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -171,7 +173,7 @@ onMounted(() => {
|
||||
:data="load"
|
||||
/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
|
||||
<realtime-log service="redis" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RouteType } from '~/types/router'
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Redis',
|
||||
title: $gettext('Redis'),
|
||||
icon: 'logos:redis',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
import type { RouteType } from '~/types/router'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'Rsync',
|
||||
title: $gettext('Rsync'),
|
||||
icon: 'file-icons:rsync',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -4,10 +4,12 @@ defineOptions({
|
||||
})
|
||||
|
||||
import { NButton, NDataTable, NInput, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import s3fs from '@/api/apps/s3fs'
|
||||
import { renderIcon } from '@/utils'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const addMountModal = ref(false)
|
||||
|
||||
const addMountModel = ref({
|
||||
@@ -20,7 +22,7 @@ const addMountModel = ref({
|
||||
|
||||
const columns: any = [
|
||||
{
|
||||
title: '挂载路径',
|
||||
title: $gettext('Mount Path'),
|
||||
key: 'path',
|
||||
minWidth: 250,
|
||||
resizable: true,
|
||||
@@ -28,7 +30,7 @@ const columns: any = [
|
||||
},
|
||||
{ title: 'Bucket', key: 'bucket', resizable: true, minWidth: 250, ellipsis: { tooltip: true } },
|
||||
{
|
||||
title: '操作',
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 240,
|
||||
align: 'center',
|
||||
@@ -42,7 +44,7 @@ const columns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定删除挂载' + row.path + '吗?'
|
||||
return $gettext('Are you sure you want to delete mount %{ path }?', { path: row.path })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -52,7 +54,7 @@ const columns: any = [
|
||||
type: 'error'
|
||||
},
|
||||
{
|
||||
default: () => '卸载',
|
||||
default: () => $gettext('Unmount'),
|
||||
icon: renderIcon('material-symbols:delete-outline', { size: 14 })
|
||||
}
|
||||
)
|
||||
@@ -78,14 +80,14 @@ const handleAddMount = () => {
|
||||
useRequest(s3fs.add(addMountModel.value)).onSuccess(() => {
|
||||
refresh()
|
||||
addMountModal.value = false
|
||||
window.$message.success('添加成功')
|
||||
window.$message.success($gettext('Added successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleDeleteMount = (id: number) => {
|
||||
useRequest(s3fs.delete(id)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Deleted successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -99,10 +101,10 @@ onMounted(() => {
|
||||
<template #action>
|
||||
<n-button class="ml-16" type="primary" @click="addMountModal = true">
|
||||
<TheIcon :size="18" icon="material-symbols:add" />
|
||||
添加挂载
|
||||
{{ $gettext('Add Mount') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-card title="挂载列表" :segmented="true">
|
||||
<n-card :title="$gettext('Mount List')" :segmented="true">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -125,15 +127,15 @@ onMounted(() => {
|
||||
/>
|
||||
</n-card>
|
||||
</common-page>
|
||||
<n-modal v-model:show="addMountModal" title="添加挂载">
|
||||
<n-card closable @close="() => (addMountModal = false)" title="添加挂载" style="width: 60vw">
|
||||
<n-modal v-model:show="addMountModal" :title="$gettext('Add Mount')">
|
||||
<n-card closable @close="() => (addMountModal = false)" :title="$gettext('Add Mount')" style="width: 60vw">
|
||||
<n-form :model="addMountModel">
|
||||
<n-form-item path="bucket" label="Bucket">
|
||||
<n-input
|
||||
v-model:value="addMountModel.bucket"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入 Bucket 名(COS 为: xxxx-ID)"
|
||||
:placeholder="$gettext('Enter Bucket name (COS format: xxxx-ID)')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="ak" label="AK">
|
||||
@@ -141,7 +143,7 @@ onMounted(() => {
|
||||
v-model:value="addMountModel.ak"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入 AK 密钥"
|
||||
:placeholder="$gettext('Enter AK key')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="sk" label="SK">
|
||||
@@ -149,27 +151,27 @@ onMounted(() => {
|
||||
v-model:value="addMountModel.sk"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入 SK 密钥"
|
||||
:placeholder="$gettext('Enter SK key')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="url" label="地域节点">
|
||||
<n-form-item path="url" :label="$gettext('Region Endpoint')">
|
||||
<n-input
|
||||
v-model:value="addMountModel.url"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入地域节点的完整 URL(https://oss-cn-beijing.aliyuncs.com)"
|
||||
:placeholder="$gettext('Enter complete URL of region endpoint (e.g., https://oss-cn-beijing.aliyuncs.com)')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="path" label="挂载目录">
|
||||
<n-form-item path="path" :label="$gettext('Mount Directory')">
|
||||
<n-input
|
||||
v-model:value="addMountModel.path"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入挂载目录(/oss)"
|
||||
:placeholder="$gettext('Enter mount directory (e.g., /oss)')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleAddMount">提交</n-button>
|
||||
<n-button type="info" block @click="handleAddMount">{{ $gettext('Submit') }}</n-button>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
import type { RouteType } from '~/types/router'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
@@ -13,8 +14,8 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'S3fs',
|
||||
icon: 'mdi:server-network',
|
||||
title: $gettext('S3FS'),
|
||||
icon: 'logos:aws',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NDataTable, NInput, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import supervisor from '@/api/apps/supervisor'
|
||||
import systemctl from '@/api/panel/systemctl'
|
||||
import { renderIcon } from '@/utils'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('status')
|
||||
const status = ref(false)
|
||||
const isEnabled = ref(false)
|
||||
@@ -49,19 +51,19 @@ const statusType = computed(() => {
|
||||
return status.value ? 'success' : 'error'
|
||||
})
|
||||
const statusStr = computed(() => {
|
||||
return status.value ? '正常运行中' : '已停止运行'
|
||||
return status.value ? $gettext('Running normally') : $gettext('Stopped')
|
||||
})
|
||||
|
||||
const processColumns: any = [
|
||||
{
|
||||
title: '名称',
|
||||
title: $gettext('Name'),
|
||||
key: 'name',
|
||||
minWidth: 200,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
title: $gettext('Status'),
|
||||
key: 'status',
|
||||
minWidth: 100,
|
||||
resizable: true,
|
||||
@@ -75,14 +77,14 @@ const processColumns: any = [
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '运行时间',
|
||||
title: $gettext('Uptime'),
|
||||
key: 'uptime',
|
||||
minWidth: 150,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 500,
|
||||
align: 'center',
|
||||
@@ -98,7 +100,7 @@ const processColumns: any = [
|
||||
onClick: () => handleShowProcessLog(row)
|
||||
},
|
||||
{
|
||||
default: () => '日志',
|
||||
default: () => $gettext('Logs'),
|
||||
icon: renderIcon('material-symbols:visibility', { size: 14 })
|
||||
}
|
||||
),
|
||||
@@ -111,7 +113,7 @@ const processColumns: any = [
|
||||
onClick: () => handleEditProcess(row.name)
|
||||
},
|
||||
{
|
||||
default: () => '配置',
|
||||
default: () => $gettext('Configure'),
|
||||
icon: renderIcon('material-symbols:settings-outline', { size: 14 })
|
||||
}
|
||||
),
|
||||
@@ -126,7 +128,7 @@ const processColumns: any = [
|
||||
onClick: () => handleProcessStart(row.name)
|
||||
},
|
||||
{
|
||||
default: () => '启动',
|
||||
default: () => $gettext('Start'),
|
||||
icon: renderIcon('material-symbols:play-arrow-outline', { size: 18 })
|
||||
}
|
||||
)
|
||||
@@ -139,7 +141,7 @@ const processColumns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定停止进程' + row.name + '吗?'
|
||||
return $gettext('Are you sure you want to stop process %{ name }?', { name: row.name })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -150,7 +152,7 @@ const processColumns: any = [
|
||||
style: 'margin-left: 15px'
|
||||
},
|
||||
{
|
||||
default: () => '停止',
|
||||
default: () => $gettext('Stop'),
|
||||
icon: renderIcon('material-symbols:stop-outline', { size: 18 })
|
||||
}
|
||||
)
|
||||
@@ -166,7 +168,7 @@ const processColumns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定重启进程' + row.name + '吗?'
|
||||
return $gettext('Are you sure you want to restart process %{ name }?', { name: row.name })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -177,7 +179,7 @@ const processColumns: any = [
|
||||
style: 'margin-left: 15px'
|
||||
},
|
||||
{
|
||||
default: () => '重启',
|
||||
default: () => $gettext('Restart'),
|
||||
icon: renderIcon('material-symbols:replay', { size: 18 })
|
||||
}
|
||||
)
|
||||
@@ -192,7 +194,7 @@ const processColumns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定删除进程' + row.name + '吗?'
|
||||
return $gettext('Are you sure you want to delete process %{ name }?', { name: row.name })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -203,7 +205,7 @@ const processColumns: any = [
|
||||
style: 'margin-left: 15px'
|
||||
},
|
||||
{
|
||||
default: () => '删除',
|
||||
default: () => $gettext('Delete'),
|
||||
icon: renderIcon('material-symbols:delete-outline', { size: 14 })
|
||||
}
|
||||
)
|
||||
@@ -236,13 +238,13 @@ const getIsEnabled = async () => {
|
||||
const handleSaveConfig = () => {
|
||||
useRequest(supervisor.saveConfig(config.value)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleClearLog = () => {
|
||||
useRequest(supervisor.clearLog()).onSuccess(() => {
|
||||
window.$message.success('清空成功')
|
||||
window.$message.success($gettext('Cleared successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -250,12 +252,12 @@ const handleIsEnabled = () => {
|
||||
if (isEnabled.value) {
|
||||
useRequest(systemctl.enable(serviceName.value)).onSuccess(() => {
|
||||
getIsEnabled()
|
||||
window.$message.success('开启自启动成功')
|
||||
window.$message.success($gettext('Autostart enabled successfully'))
|
||||
})
|
||||
} else {
|
||||
useRequest(systemctl.disable(serviceName.value)).onSuccess(() => {
|
||||
getIsEnabled()
|
||||
window.$message.success('禁用自启动成功')
|
||||
window.$message.success($gettext('Autostart disabled successfully'))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -263,21 +265,21 @@ const handleIsEnabled = () => {
|
||||
const handleStart = () => {
|
||||
useRequest(systemctl.start(serviceName.value)).onSuccess(() => {
|
||||
getStatus()
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleStop = () => {
|
||||
useRequest(systemctl.stop(serviceName.value)).onSuccess(() => {
|
||||
getStatus()
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleRestart = () => {
|
||||
useRequest(systemctl.restart(serviceName.value)).onSuccess(() => {
|
||||
getStatus()
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -285,35 +287,35 @@ const handleCreateProcess = () => {
|
||||
useRequest(supervisor.createProcess(createProcessModel.value)).onSuccess(() => {
|
||||
refresh()
|
||||
createProcessModal.value = false
|
||||
window.$message.success('添加成功')
|
||||
window.$message.success($gettext('Added successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleProcessStart = (name: string) => {
|
||||
useRequest(supervisor.startProcess(name)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Started successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleProcessStop = (name: string) => {
|
||||
useRequest(supervisor.stopProcess(name)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stopped successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleProcessRestart = (name: string) => {
|
||||
useRequest(supervisor.restartProcess(name)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restarted successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleProcessDelete = (name: string) => {
|
||||
useRequest(supervisor.deleteProcess(name)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Deleted successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -336,7 +338,7 @@ const handleSaveProcessConfig = () => {
|
||||
useRequest(
|
||||
supervisor.saveProcessConfig(editProcessModel.value.process, editProcessModel.value.config)
|
||||
).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -357,7 +359,7 @@ onUnmounted(() => {
|
||||
@click="handleSaveConfig"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'processes'"
|
||||
@@ -366,21 +368,21 @@ onUnmounted(() => {
|
||||
@click="createProcessModal = true"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:add" />
|
||||
添加进程
|
||||
{{ $gettext('Add Process') }}
|
||||
</n-button>
|
||||
<n-button v-if="currentTab == 'log'" class="ml-16" type="primary" @click="handleClearLog">
|
||||
<TheIcon :size="18" icon="material-symbols:delete-outline" />
|
||||
清空日志
|
||||
{{ $gettext('Clear Log') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="status" tab="运行状态">
|
||||
<n-tab-pane name="status" :tab="$gettext('Running Status')">
|
||||
<n-space vertical>
|
||||
<n-card title="运行状态">
|
||||
<n-card :title="$gettext('Running Status')">
|
||||
<template #header-extra>
|
||||
<n-switch v-model:value="isEnabled" @update:value="handleIsEnabled">
|
||||
<template #checked> 自启动开</template>
|
||||
<template #unchecked> 自启动关</template>
|
||||
<template #checked>{{ $gettext('Autostart On') }}</template>
|
||||
<template #unchecked>{{ $gettext('Autostart Off') }}</template>
|
||||
</n-switch>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
@@ -390,28 +392,28 @@ onUnmounted(() => {
|
||||
<n-space>
|
||||
<n-button type="success" @click="handleStart">
|
||||
<TheIcon :size="24" icon="material-symbols:play-arrow-outline-rounded" />
|
||||
启动
|
||||
{{ $gettext('Start') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleStop">
|
||||
<template #trigger>
|
||||
<n-button type="error">
|
||||
<TheIcon :size="24" icon="material-symbols:stop-outline-rounded" />
|
||||
停止
|
||||
{{ $gettext('Stop') }}
|
||||
</n-button>
|
||||
</template>
|
||||
停止 Supervisor 会导致 Supervisor 管理的所有进程被杀死,确定要停止吗?
|
||||
{{ $gettext('Stopping Supervisor will cause all processes managed by Supervisor to be killed. Are you sure you want to stop?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="handleRestart">
|
||||
<TheIcon :size="18" icon="material-symbols:replay-rounded" />
|
||||
重启
|
||||
{{ $gettext('Restart') }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="processes" tab="进程管理">
|
||||
<n-card title="进程列表" :segmented="true">
|
||||
<n-tab-pane name="processes" :tab="$gettext('Process Management')">
|
||||
<n-card :title="$gettext('Process List')" :segmented="true">
|
||||
<n-data-table
|
||||
striped
|
||||
remote
|
||||
@@ -434,10 +436,10 @@ onUnmounted(() => {
|
||||
/>
|
||||
</n-card>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="config" tab="主配置">
|
||||
<n-tab-pane name="config" :tab="$gettext('Main Configuration')">
|
||||
<n-space vertical>
|
||||
<n-alert type="warning">
|
||||
此处修改的是 Supervisor 主配置文件,如果您不了解各参数的含义,请不要随意修改!
|
||||
{{ $gettext('This modifies the Supervisor main configuration file. If you do not understand the meaning of each parameter, please do not modify it randomly!') }}
|
||||
</n-alert>
|
||||
<Editor
|
||||
v-model:value="config"
|
||||
@@ -453,10 +455,10 @@ onUnmounted(() => {
|
||||
/>
|
||||
</n-space>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="run-log" tab="运行日志">
|
||||
<n-tab-pane name="run-log" :tab="$gettext('Runtime Logs')">
|
||||
<realtime-log service="supervisor" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="log" tab="守护日志">
|
||||
<n-tab-pane name="log" :tab="$gettext('Daemon Logs')">
|
||||
<realtime-log path="/var/log/supervisor/supervisord.log" />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
@@ -464,7 +466,7 @@ onUnmounted(() => {
|
||||
<n-modal
|
||||
v-model:show="createProcessModal"
|
||||
preset="card"
|
||||
title="添加进程"
|
||||
:title="$gettext('Add Process')"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
@@ -472,49 +474,49 @@ onUnmounted(() => {
|
||||
@close="createProcessModal = false"
|
||||
>
|
||||
<n-form :model="createProcessModel">
|
||||
<n-form-item path="name" label="名称">
|
||||
<n-form-item path="name" :label="$gettext('Name')">
|
||||
<n-input
|
||||
v-model:value="createProcessModel.name"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="名称禁止使用中文"
|
||||
:placeholder="$gettext('Name cannot contain Chinese characters')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="command" label="启动命令">
|
||||
<n-form-item path="command" :label="$gettext('Start Command')">
|
||||
<n-input
|
||||
v-model:value="createProcessModel.command"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="启动命令中的文件请填写绝对路径"
|
||||
:placeholder="$gettext('Please enter absolute path for files in start command')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="path" label="运行目录">
|
||||
<n-form-item path="path" :label="$gettext('Working Directory')">
|
||||
<n-input
|
||||
v-model:value="createProcessModel.path"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="运行目录请填写绝对路径"
|
||||
:placeholder="$gettext('Please enter absolute path for working directory')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="user" label="启动用户">
|
||||
<n-form-item path="user" :label="$gettext('Run As User')">
|
||||
<n-input
|
||||
v-model:value="createProcessModel.user"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="一般情况下填写www即可"
|
||||
:placeholder="$gettext('Usually www is sufficient')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="num" label="进程数量">
|
||||
<n-form-item path="num" :label="$gettext('Number of Processes')">
|
||||
<n-input-number v-model:value="createProcessModel.num" :min="1" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleCreateProcess">提交</n-button>
|
||||
<n-button type="info" block @click="handleCreateProcess">{{ $gettext('Submit') }}</n-button>
|
||||
</n-modal>
|
||||
<realtime-log-modal v-model:show="processLogModal" :path="processLog" />
|
||||
<n-modal
|
||||
v-model:show="editProcessModal"
|
||||
preset="card"
|
||||
title="进程配置"
|
||||
:title="$gettext('Process Configuration')"
|
||||
style="width: 80vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
import type { RouteType } from '~/types/router'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'SuperVisor',
|
||||
title: $gettext('Supervisor'),
|
||||
icon: 'mdi:monitor-dashboard',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -6,9 +6,11 @@ defineOptions({
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { DateTime } from 'luxon'
|
||||
import { NButton } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import toolbox from '@/api/apps/toolbox'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const currentTab = ref('dns')
|
||||
const dns1 = ref('')
|
||||
const dns2 = ref('')
|
||||
@@ -46,13 +48,13 @@ useRequest(toolbox.timezone()).onSuccess(({ data }) => {
|
||||
|
||||
const handleUpdateDNS = () => {
|
||||
useRequest(toolbox.updateDns(dns1.value, dns2.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleUpdateSwap = () => {
|
||||
useRequest(toolbox.updateSwap(swap.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -61,13 +63,13 @@ const handleUpdateHost = async () => {
|
||||
useRequest(toolbox.updateHostname(hostname.value)),
|
||||
useRequest(toolbox.updateHosts(hosts.value))
|
||||
]).then(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleUpdateRootPassword = () => {
|
||||
useRequest(toolbox.updateRootPassword(rootPassword.value)).onSuccess(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -76,13 +78,13 @@ const handleUpdateTime = async () => {
|
||||
useRequest(toolbox.updateTime(String(DateTime.fromMillis(time.value).toISO()))),
|
||||
useRequest(toolbox.updateTimezone(timezone.value))
|
||||
]).then(() => {
|
||||
window.$message.success('保存成功')
|
||||
window.$message.success($gettext('Saved successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleSyncTime = () => {
|
||||
useRequest(toolbox.syncTime()).onSuccess(() => {
|
||||
window.$message.success('同步成功')
|
||||
window.$message.success($gettext('Synchronized successfully'))
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -92,19 +94,19 @@ const handleSyncTime = () => {
|
||||
<template #action>
|
||||
<n-button v-if="currentTab == 'dns'" class="ml-16" type="primary" @click="handleUpdateDNS">
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button v-if="currentTab == 'swap'" class="ml-16" type="primary" @click="handleUpdateSwap">
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button v-if="currentTab == 'host'" class="ml-16" type="primary" @click="handleUpdateHost">
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button v-if="currentTab == 'time'" class="ml-16" type="primary" @click="handleUpdateTime">
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
保存
|
||||
{{ $gettext('Save') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="currentTab == 'root-password'"
|
||||
@@ -113,13 +115,13 @@ const handleSyncTime = () => {
|
||||
@click="handleUpdateRootPassword"
|
||||
>
|
||||
<TheIcon :size="18" icon="material-symbols:save-outline" />
|
||||
修改
|
||||
{{ $gettext('Modify') }}
|
||||
</n-button>
|
||||
</template>
|
||||
<n-tabs v-model:value="currentTab" type="line" animated>
|
||||
<n-tab-pane name="dns" tab="DNS">
|
||||
<n-flex vertical>
|
||||
<n-alert type="warning"> DNS 修改后重启系统会还原默认。 </n-alert>
|
||||
<n-alert type="warning"> {{ $gettext('DNS modifications will revert to default after system restart.') }} </n-alert>
|
||||
<n-form>
|
||||
<n-form-item label="DNS1">
|
||||
<n-input v-model:value="dns1" />
|
||||
@@ -133,20 +135,20 @@ const handleSyncTime = () => {
|
||||
<n-tab-pane name="swap" tab="SWAP">
|
||||
<n-flex vertical>
|
||||
<n-alert type="info">
|
||||
总共 {{ swapTotal }},已使用 {{ swapUsed }},剩余 {{ swapFree }}
|
||||
{{ $gettext('Total %{ total }, used %{ used }, free %{ free }', { total: swapTotal, used: swapUsed, free: swapFree }) }}
|
||||
</n-alert>
|
||||
<n-form>
|
||||
<n-form-item label="SWAP大小">
|
||||
<n-form-item :label="$gettext('SWAP Size')">
|
||||
<n-input-number v-model:value="swap" />
|
||||
MB
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-flex>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="host" tab="主机">
|
||||
<n-tab-pane name="host" :tab="$gettext('Host')">
|
||||
<n-flex vertical>
|
||||
<n-form>
|
||||
<n-form-item label="主机名">
|
||||
<n-form-item :label="$gettext('Hostname')">
|
||||
<n-input v-model:value="hostname" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
@@ -164,25 +166,25 @@ const handleSyncTime = () => {
|
||||
/>
|
||||
</n-flex>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="time" tab="时间">
|
||||
<n-tab-pane name="time" :tab="$gettext('Time')">
|
||||
<n-flex vertical>
|
||||
<n-alert type="info"> 手动修改时间后,仍有可能被系统自动同步时间覆盖。 </n-alert>
|
||||
<n-alert type="info"> {{ $gettext('After manually changing the time, it may still be overwritten by system automatic time synchronization.') }} </n-alert>
|
||||
<n-form>
|
||||
<n-form-item label="选择时区">
|
||||
<n-select v-model:value="timezone" placeholder="请选择时区" :options="timezones" />
|
||||
<n-form-item :label="$gettext('Select Timezone')">
|
||||
<n-select v-model:value="timezone" :placeholder="$gettext('Please select a timezone')" :options="timezones" />
|
||||
</n-form-item>
|
||||
<n-form-item label="修改时间">
|
||||
<n-form-item :label="$gettext('Modify Time')">
|
||||
<n-date-picker v-model:value="time" type="datetime" clearable />
|
||||
</n-form-item>
|
||||
<n-form-item label="NTP 同步时间">
|
||||
<n-button type="info" @click="handleSyncTime">同步时间</n-button>
|
||||
<n-form-item :label="$gettext('NTP Time Synchronization')">
|
||||
<n-button type="info" @click="handleSyncTime">{{ $gettext('Synchronize Time') }}</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-flex>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="root-password" tab="Root 密码">
|
||||
<n-tab-pane name="root-password" :tab="$gettext('Root Password')">
|
||||
<n-form>
|
||||
<n-form-item label="Root 密码">
|
||||
<n-form-item :label="$gettext('Root Password')">
|
||||
<n-input v-model:value="rootPassword" type="password" show-password-on="click" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
import type { RouteType } from '~/types/router'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: '系统工具箱',
|
||||
title: $gettext('Toolbox'),
|
||||
icon: 'mdi:tools',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
Reference in New Issue
Block a user