mirror of
https://github.com/acepanel/panel.git
synced 2026-02-06 14:47:18 +08:00
feat: 提交部分前端翻译
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { NButton, NCheckbox, NDataTable, NFlex, NInput, NPopconfirm, NTag } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import container from '@/api/panel/container'
|
||||
import { useFileStore } from '@/store'
|
||||
import { formatDateTime } from '@/utils'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const fileStore = useFileStore()
|
||||
const router = useRouter()
|
||||
|
||||
@@ -26,14 +28,14 @@ const updateModal = ref(false)
|
||||
|
||||
const columns: any = [
|
||||
{
|
||||
title: '名称',
|
||||
title: $gettext('Name'),
|
||||
key: 'name',
|
||||
minWidth: 150,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '目录',
|
||||
title: $gettext('Directory'),
|
||||
key: 'path',
|
||||
minWidth: 150,
|
||||
resizable: true,
|
||||
@@ -53,14 +55,14 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
title: $gettext('Status'),
|
||||
key: 'status',
|
||||
width: 150,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
title: $gettext('Creation Time'),
|
||||
key: 'created_at',
|
||||
width: 200,
|
||||
resizable: true,
|
||||
@@ -69,7 +71,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 280,
|
||||
align: 'center',
|
||||
@@ -92,7 +94,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => '编辑'
|
||||
default: () => $gettext('Edit')
|
||||
}
|
||||
),
|
||||
h(
|
||||
@@ -100,14 +102,14 @@ const columns: any = [
|
||||
{
|
||||
showIcon: false,
|
||||
onPositiveClick: () => {
|
||||
const messageReactive = window.$message.loading('启动中...', {
|
||||
const messageReactive = window.$message.loading($gettext('Starting...'), {
|
||||
duration: 0
|
||||
})
|
||||
useRequest(container.composeUp(row.name, forcePush.value))
|
||||
.onSuccess(() => {
|
||||
refresh()
|
||||
forcePush.value = false
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Start successful'))
|
||||
})
|
||||
.onComplete(() => {
|
||||
messageReactive?.destroy()
|
||||
@@ -123,14 +125,14 @@ const columns: any = [
|
||||
},
|
||||
{
|
||||
default: () => [
|
||||
h('strong', {}, { default: () => `确定启动编排 ${row.name} 吗?` }),
|
||||
h('strong', {}, { default: () => $gettext(`Are you sure you want to start compose %{ name }?`, { name: row.name }) }),
|
||||
h(
|
||||
NCheckbox,
|
||||
{
|
||||
checked: forcePush.value,
|
||||
onUpdateChecked: (v) => (forcePush.value = v)
|
||||
},
|
||||
{ default: () => '强制拉取镜像' }
|
||||
{ default: () => $gettext('Force pull images') }
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -145,7 +147,7 @@ const columns: any = [
|
||||
type: 'success'
|
||||
},
|
||||
{
|
||||
default: () => '启动'
|
||||
default: () => $gettext('Start')
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -157,13 +159,13 @@ const columns: any = [
|
||||
onPositiveClick: () => {
|
||||
useRequest(container.composeDown(row.name)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stop successful'))
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return `确定停止编排 ${row.name} 吗?`
|
||||
return $gettext(`Are you sure you want to stop compose %{ name }?`, { name: row.name })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -174,7 +176,7 @@ const columns: any = [
|
||||
type: 'warning'
|
||||
},
|
||||
{
|
||||
default: () => '停止'
|
||||
default: () => $gettext('Stop')
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -186,13 +188,13 @@ const columns: any = [
|
||||
onPositiveClick: () => {
|
||||
useRequest(container.composeRemove(row.name)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Delete successful'))
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return `确定删除编排 ${row.name} 吗?`
|
||||
return $gettext(`Are you sure you want to delete compose %{ name }?`, { name: row.name })
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -203,7 +205,7 @@ const columns: any = [
|
||||
type: 'error'
|
||||
},
|
||||
{
|
||||
default: () => '删除'
|
||||
default: () => $gettext('Delete')
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -229,7 +231,7 @@ const handleCreate = () => {
|
||||
useRequest(container.composeCreate(createModel.value))
|
||||
.onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('创建成功')
|
||||
window.$message.success($gettext('Created successfully'))
|
||||
})
|
||||
.onComplete(() => {
|
||||
loading.value = false
|
||||
@@ -247,7 +249,7 @@ const handleUpdate = () => {
|
||||
useRequest(container.composeUpdate(updateModel.value.name, updateModel.value))
|
||||
.onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('更新成功')
|
||||
window.$message.success($gettext('Update successful'))
|
||||
})
|
||||
.onComplete(() => {
|
||||
loading.value = false
|
||||
@@ -268,7 +270,7 @@ onMounted(() => {
|
||||
<template>
|
||||
<n-flex vertical :size="20">
|
||||
<n-flex>
|
||||
<n-button type="primary" @click="createModal = true">创建编排</n-button>
|
||||
<n-button type="primary" @click="createModal = true">{{ $gettext('Create Compose') }}</n-button>
|
||||
</n-flex>
|
||||
<n-data-table
|
||||
striped
|
||||
@@ -294,64 +296,64 @@ onMounted(() => {
|
||||
<n-modal
|
||||
v-model:show="createModal"
|
||||
preset="card"
|
||||
title="创建编排"
|
||||
:title="$gettext('Create Compose')"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-form :model="createModel">
|
||||
<n-form-item path="name" label="编排名">
|
||||
<n-form-item path="name" :label="$gettext('Compose Name')">
|
||||
<n-input v-model:value="createModel.name" type="text" />
|
||||
</n-form-item>
|
||||
<n-form-item path="compose" label="编排">
|
||||
<n-form-item path="compose" :label="$gettext('Compose')">
|
||||
<n-input
|
||||
v-model:value="createModel.compose"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 10, maxRows: 20 }"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="envs" label="环境变量">
|
||||
<n-form-item path="envs" :label="$gettext('Environment Variables')">
|
||||
<n-dynamic-input
|
||||
v-model:value="createModel.envs"
|
||||
preset="pair"
|
||||
key-placeholder="变量名"
|
||||
value-placeholder="变量值"
|
||||
:key-placeholder="$gettext('Variable Name')"
|
||||
:value-placeholder="$gettext('Variable Value')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block :loading="loading" :disabled="loading" @click="handleCreate">
|
||||
提交
|
||||
{{ $gettext('Submit') }}
|
||||
</n-button>
|
||||
</n-modal>
|
||||
<n-modal
|
||||
v-model:show="updateModal"
|
||||
preset="card"
|
||||
title="编辑编排"
|
||||
:title="$gettext('Edit Compose')"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-form :model="updateModel">
|
||||
<n-form-item path="compose" label="编排">
|
||||
<n-form-item path="compose" :label="$gettext('Compose')">
|
||||
<n-input
|
||||
v-model:value="updateModel.compose"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 10, maxRows: 20 }"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="envs" label="环境变量">
|
||||
<n-form-item path="envs" :label="$gettext('Environment Variables')">
|
||||
<n-dynamic-input
|
||||
v-model:value="updateModel.envs"
|
||||
preset="pair"
|
||||
key-placeholder="变量名"
|
||||
value-placeholder="变量值"
|
||||
:key-placeholder="$gettext('Variable Name')"
|
||||
:value-placeholder="$gettext('Variable Value')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block :loading="loading" :disabled="loading" @click="handleUpdate">
|
||||
提交
|
||||
{{ $gettext('Submit') }}
|
||||
</n-button>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import container from '@/api/panel/container'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
@@ -49,10 +52,10 @@ const createModel = reactive({
|
||||
const networks = ref<any>({})
|
||||
|
||||
const restartPolicyOptions = [
|
||||
{ label: '无', value: 'no' },
|
||||
{ label: '始终', value: 'always' },
|
||||
{ label: '失败时(默认重启 5 次)', value: 'on-failure' },
|
||||
{ label: '未手动停止则重启', value: 'unless-stopped' }
|
||||
{ label: $gettext('None'), value: 'no' },
|
||||
{ label: $gettext('Always'), value: 'always' },
|
||||
{ label: $gettext('On failure (default 5 retries)'), value: 'on-failure' },
|
||||
{ label: $gettext('Unless stopped'), value: 'unless-stopped' }
|
||||
]
|
||||
|
||||
const addPortRow = () => {
|
||||
@@ -100,7 +103,7 @@ const handleSubmit = () => {
|
||||
doSubmit.value = true
|
||||
useRequest(container.containerCreate(createModel))
|
||||
.onSuccess(() => {
|
||||
window.$message.success('创建成功')
|
||||
window.$message.success($gettext('Created successfully'))
|
||||
handleClose()
|
||||
})
|
||||
.onComplete(() => {
|
||||
@@ -121,7 +124,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<n-modal
|
||||
title="创建容器"
|
||||
:title="$gettext('Create Container')"
|
||||
preset="card"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
@@ -131,40 +134,40 @@ onMounted(() => {
|
||||
@close="handleClose"
|
||||
>
|
||||
<n-form :model="createModel">
|
||||
<n-form-item path="name" label="容器名">
|
||||
<n-form-item path="name" :label="$gettext('Container Name')">
|
||||
<n-input v-model:value="createModel.name" type="text" @keydown.enter.prevent />
|
||||
</n-form-item>
|
||||
<n-form-item path="name" label="镜像">
|
||||
<n-form-item path="name" :label="$gettext('Image')">
|
||||
<n-input v-model:value="createModel.image" type="text" @keydown.enter.prevent />
|
||||
</n-form-item>
|
||||
<n-form-item path="exposedAll" label="端口">
|
||||
<n-form-item path="exposedAll" :label="$gettext('Ports')">
|
||||
<n-radio
|
||||
:checked="!createModel.publish_all_ports"
|
||||
:value="false"
|
||||
@change="createModel.publish_all_ports = !$event.target.value"
|
||||
>
|
||||
映射端口
|
||||
{{ $gettext('Map Ports') }}
|
||||
</n-radio>
|
||||
<n-radio
|
||||
:checked="createModel.publish_all_ports"
|
||||
:value="true"
|
||||
@change="createModel.publish_all_ports = !!$event.target.value"
|
||||
>
|
||||
暴露所有
|
||||
{{ $gettext('Expose All') }}
|
||||
</n-radio>
|
||||
</n-form-item>
|
||||
<n-form-item path="ports" label="端口映射" v-if="!createModel.publish_all_ports">
|
||||
<n-form-item path="ports" :label="$gettext('Port Mapping')" v-if="!createModel.publish_all_ports">
|
||||
<n-space vertical>
|
||||
<n-table striped>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>IP</th>
|
||||
<th>主机(起始)</th>
|
||||
<th>主机(结束)</th>
|
||||
<th>容器(起始)</th>
|
||||
<th>容器(结束)</th>
|
||||
<th>协议</th>
|
||||
<th>操作</th>
|
||||
<th>{{ $gettext('Host (Start)') }}</th>
|
||||
<th>{{ $gettext('Host (End)') }}</th>
|
||||
<th>{{ $gettext('Container (Start)') }}</th>
|
||||
<th>{{ $gettext('Container (End)') }}</th>
|
||||
<th>{{ $gettext('Protocol') }}</th>
|
||||
<th>{{ $gettext('Actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -174,7 +177,7 @@ onMounted(() => {
|
||||
v-model:value="item.host"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="可留空"
|
||||
:placeholder="$gettext('Optional')"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
@@ -223,25 +226,25 @@ onMounted(() => {
|
||||
UDP
|
||||
</n-radio>
|
||||
</td>
|
||||
<td><n-button @click="removePortRow(index)" size="small">删除</n-button></td>
|
||||
<td><n-button @click="removePortRow(index)" size="small">{{ $gettext('Delete') }}</n-button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
<n-button @click="addPortRow">添加</n-button>
|
||||
<n-button @click="addPortRow">{{ $gettext('Add') }}</n-button>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
<n-form-item path="network" label="网络">
|
||||
<n-form-item path="network" :label="$gettext('Network')">
|
||||
<n-select v-model:value="createModel.network" :options="networks" />
|
||||
</n-form-item>
|
||||
<n-form-item path="mount" label="挂载">
|
||||
<n-form-item path="mount" :label="$gettext('Mount')">
|
||||
<n-space vertical>
|
||||
<n-table striped>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>主机目录</th>
|
||||
<th>容器目录</th>
|
||||
<th>权限</th>
|
||||
<th>操作</th>
|
||||
<th>{{ $gettext('Host Directory') }}</th>
|
||||
<th>{{ $gettext('Container Directory') }}</th>
|
||||
<th>{{ $gettext('Permission') }}</th>
|
||||
<th>{{ $gettext('Actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -259,7 +262,7 @@ onMounted(() => {
|
||||
name="mode"
|
||||
@change="item.mode = $event.target.value"
|
||||
>
|
||||
读写
|
||||
{{ $gettext('Read-Write') }}
|
||||
</n-radio>
|
||||
<n-radio
|
||||
:checked="item.mode === 'ro'"
|
||||
@@ -267,25 +270,25 @@ onMounted(() => {
|
||||
name="mode"
|
||||
@change="item.mode = $event.target.value"
|
||||
>
|
||||
只读
|
||||
{{ $gettext('Read-Only') }}
|
||||
</n-radio>
|
||||
</td>
|
||||
<td><n-button @click="removeVolumeRow(index)" size="small">删除</n-button></td>
|
||||
<td><n-button @click="removeVolumeRow(index)" size="small">{{ $gettext('Delete') }}</n-button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
<n-button @click="addVolumeRow">添加</n-button>
|
||||
<n-button @click="addVolumeRow">{{ $gettext('Add') }}</n-button>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
<n-form-item path="command" label="启动命令">
|
||||
<n-dynamic-input v-model:value="createModel.command" placeholder="命令" />
|
||||
<n-form-item path="command" :label="$gettext('Command')">
|
||||
<n-dynamic-input v-model:value="createModel.command" :placeholder="$gettext('Command')" />
|
||||
</n-form-item>
|
||||
<n-form-item path="entrypoint" label="入口点">
|
||||
<n-dynamic-input v-model:value="createModel.entrypoint" placeholder="入口点" />
|
||||
<n-form-item path="entrypoint" :label="$gettext('Entrypoint')">
|
||||
<n-dynamic-input v-model:value="createModel.entrypoint" :placeholder="$gettext('Entrypoint')" />
|
||||
</n-form-item>
|
||||
<n-row :gutter="[0, 24]">
|
||||
<n-col :span="8">
|
||||
<n-form-item path="memory" label="内存">
|
||||
<n-form-item path="memory" :label="$gettext('Memory')">
|
||||
<n-input-number v-model:value="createModel.memory" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
@@ -295,61 +298,61 @@ onMounted(() => {
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
<n-col :span="8">
|
||||
<n-form-item path="cpu_shares" label="CPU 权重">
|
||||
<n-form-item path="cpu_shares" :label="$gettext('CPU Shares')">
|
||||
<n-input-number v-model:value="createModel.cpu_shares" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
</n-row>
|
||||
<n-row :gutter="[0, 24]">
|
||||
<n-col :span="6">
|
||||
<n-form-item path="tty" label="伪终端(-t)">
|
||||
<n-form-item path="tty" :label="$gettext('TTY (-t)')">
|
||||
<n-switch v-model:value="createModel.tty" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
<n-col :span="6">
|
||||
<n-form-item path="open_stdin" label="标准输入(-i)">
|
||||
<n-form-item path="open_stdin" :label="$gettext('STDIN (-i)')">
|
||||
<n-switch v-model:value="createModel.open_stdin" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
<n-col :span="6">
|
||||
<n-form-item path="auto_remove" label="退出后自动删除">
|
||||
<n-form-item path="auto_remove" :label="$gettext('Auto Remove')">
|
||||
<n-switch v-model:value="createModel.auto_remove" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
<n-col :span="6">
|
||||
<n-form-item path="privileged" label="特权模式">
|
||||
<n-form-item path="privileged" :label="$gettext('Privileged Mode')">
|
||||
<n-switch v-model:value="createModel.privileged" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
</n-row>
|
||||
<n-form-item path="restart_policy" label="重启策略">
|
||||
<n-form-item path="restart_policy" :label="$gettext('Restart Policy')">
|
||||
<n-select
|
||||
v-model:value="createModel.restart_policy"
|
||||
placeholder="选择重启策略"
|
||||
:placeholder="$gettext('Select restart policy')"
|
||||
:options="restartPolicyOptions"
|
||||
>
|
||||
{{ createModel.restart_policy || '选择重启策略' }}
|
||||
{{ createModel.restart_policy || $gettext('Select restart policy') }}
|
||||
</n-select>
|
||||
</n-form-item>
|
||||
<n-form-item path="env" label="环境变量">
|
||||
<n-form-item path="env" :label="$gettext('Environment Variables')">
|
||||
<n-dynamic-input
|
||||
v-model:value="createModel.env"
|
||||
preset="pair"
|
||||
key-placeholder="变量名"
|
||||
value-placeholder="变量值"
|
||||
:key-placeholder="$gettext('Variable Name')"
|
||||
:value-placeholder="$gettext('Variable Value')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="labels" label="标签">
|
||||
<n-form-item path="labels" :label="$gettext('Labels')">
|
||||
<n-dynamic-input
|
||||
v-model:value="createModel.labels"
|
||||
preset="pair"
|
||||
key-placeholder="标签名"
|
||||
value-placeholder="标签值"
|
||||
:key-placeholder="$gettext('Label Name')"
|
||||
:value-placeholder="$gettext('Label Value')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block :loading="doSubmit" :disabled="doSubmit" @click="handleSubmit">
|
||||
提交
|
||||
{{ $gettext('Submit') }}
|
||||
</n-button>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NDataTable, NDropdown, NFlex, NInput, NSwitch, NTag } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import container from '@/api/panel/container'
|
||||
import ContainerCreate from '@/views/container/ContainerCreate.vue'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
|
||||
const logModal = ref(false)
|
||||
const logs = ref('')
|
||||
const renameModal = ref(false)
|
||||
@@ -19,14 +22,14 @@ const selectedRowKeys = ref<any>([])
|
||||
const columns: any = [
|
||||
{ type: 'selection', fixed: 'left' },
|
||||
{
|
||||
title: '容器名',
|
||||
title: $gettext('Container Name'),
|
||||
key: 'name',
|
||||
minWidth: 150,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
title: $gettext('Status'),
|
||||
key: 'state',
|
||||
width: 100,
|
||||
resizable: true,
|
||||
@@ -46,7 +49,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '镜像',
|
||||
title: $gettext('Image'),
|
||||
key: 'image',
|
||||
minWidth: 300,
|
||||
resizable: true,
|
||||
@@ -57,7 +60,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '端口(主机->容器)',
|
||||
title: $gettext('Ports (Host->Container)'),
|
||||
key: 'ports',
|
||||
minWidth: 200,
|
||||
resizable: true,
|
||||
@@ -74,14 +77,14 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '运行状态',
|
||||
title: $gettext('Running Status'),
|
||||
key: 'status',
|
||||
width: 300,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 250,
|
||||
align: 'center',
|
||||
@@ -97,7 +100,7 @@ const columns: any = [
|
||||
onClick: () => handleShowLog(row)
|
||||
},
|
||||
{
|
||||
default: () => '日志'
|
||||
default: () => $gettext('Logs')
|
||||
}
|
||||
),
|
||||
h(
|
||||
@@ -113,7 +116,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
default: () => '重命名'
|
||||
default: () => $gettext('Rename')
|
||||
}
|
||||
),
|
||||
h(
|
||||
@@ -121,37 +124,37 @@ const columns: any = [
|
||||
{
|
||||
options: [
|
||||
{
|
||||
label: '启动',
|
||||
label: $gettext('Start'),
|
||||
key: 'start',
|
||||
disabled: row.state === 'running'
|
||||
},
|
||||
{
|
||||
label: '停止',
|
||||
label: $gettext('Stop'),
|
||||
key: 'stop',
|
||||
disabled: row.state !== 'running'
|
||||
},
|
||||
{
|
||||
label: '重启',
|
||||
label: $gettext('Restart'),
|
||||
key: 'restart',
|
||||
disabled: row.state !== 'running'
|
||||
},
|
||||
{
|
||||
label: '强制停止',
|
||||
label: $gettext('Force Stop'),
|
||||
key: 'forceStop',
|
||||
disabled: row.state !== 'running'
|
||||
},
|
||||
{
|
||||
label: '暂停',
|
||||
label: $gettext('Pause'),
|
||||
key: 'pause',
|
||||
disabled: row.state !== 'running'
|
||||
},
|
||||
{
|
||||
label: '恢复',
|
||||
label: $gettext('Resume'),
|
||||
key: 'unpause',
|
||||
disabled: row.state === 'running'
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
label: $gettext('Delete'),
|
||||
key: 'delete'
|
||||
}
|
||||
],
|
||||
@@ -191,7 +194,7 @@ const columns: any = [
|
||||
style: 'margin-left: 15px;'
|
||||
},
|
||||
{
|
||||
default: () => '更多'
|
||||
default: () => $gettext('More')
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -224,7 +227,7 @@ const handleRename = () => {
|
||||
() => {
|
||||
refresh()
|
||||
renameModal.value = false
|
||||
window.$message.success('重命名成功')
|
||||
window.$message.success($gettext('Rename successful'))
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -232,62 +235,62 @@ const handleRename = () => {
|
||||
const handleStart = (id: string) => {
|
||||
useRequest(container.containerStart(id)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Start successful'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleStop = (id: string) => {
|
||||
useRequest(container.containerStop(id)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stop successful'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleRestart = (id: string) => {
|
||||
useRequest(container.containerRestart(id)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restart successful'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleForceStop = (id: string) => {
|
||||
useRequest(container.containerKill(id)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('强制停止成功')
|
||||
window.$message.success($gettext('Force stop successful'))
|
||||
})
|
||||
}
|
||||
|
||||
const handlePause = (id: string) => {
|
||||
useRequest(container.containerPause(id)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('暂停成功')
|
||||
window.$message.success($gettext('Pause successful'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleUnpause = (id: string) => {
|
||||
useRequest(container.containerUnpause(id)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('恢复成功')
|
||||
window.$message.success($gettext('Resume successful'))
|
||||
})
|
||||
}
|
||||
|
||||
const handleDelete = (id: string) => {
|
||||
useRequest(container.containerRemove(id)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Delete successful'))
|
||||
})
|
||||
}
|
||||
|
||||
const handlePrune = () => {
|
||||
useRequest(container.containerPrune()).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('清理成功')
|
||||
window.$message.success($gettext('Cleanup successful'))
|
||||
})
|
||||
}
|
||||
|
||||
const bulkStart = async () => {
|
||||
if (selectedRowKeys.value.length === 0) {
|
||||
window.$message.info('请选择要启动的容器')
|
||||
window.$message.info($gettext('Please select containers to start'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -296,12 +299,12 @@ const bulkStart = async () => {
|
||||
|
||||
selectedRowKeys.value = []
|
||||
refresh()
|
||||
window.$message.success('启动成功')
|
||||
window.$message.success($gettext('Start successful'))
|
||||
}
|
||||
|
||||
const bulkStop = async () => {
|
||||
if (selectedRowKeys.value.length === 0) {
|
||||
window.$message.info('请选择要停止的容器')
|
||||
window.$message.info($gettext('Please select containers to stop'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -310,12 +313,12 @@ const bulkStop = async () => {
|
||||
|
||||
selectedRowKeys.value = []
|
||||
refresh()
|
||||
window.$message.success('停止成功')
|
||||
window.$message.success($gettext('Stop successful'))
|
||||
}
|
||||
|
||||
const bulkRestart = async () => {
|
||||
if (selectedRowKeys.value.length === 0) {
|
||||
window.$message.info('请选择要重启的容器')
|
||||
window.$message.info($gettext('Please select containers to restart'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -324,12 +327,12 @@ const bulkRestart = async () => {
|
||||
|
||||
selectedRowKeys.value = []
|
||||
refresh()
|
||||
window.$message.success('重启成功')
|
||||
window.$message.success($gettext('Restart successful'))
|
||||
}
|
||||
|
||||
const bulkForceStop = async () => {
|
||||
if (selectedRowKeys.value.length === 0) {
|
||||
window.$message.info('请选择要强制停止的容器')
|
||||
window.$message.info($gettext('Please select containers to force stop'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -338,12 +341,12 @@ const bulkForceStop = async () => {
|
||||
|
||||
selectedRowKeys.value = []
|
||||
refresh()
|
||||
window.$message.success('强制停止成功')
|
||||
window.$message.success($gettext('Force stop successful'))
|
||||
}
|
||||
|
||||
const bulkDelete = async () => {
|
||||
if (selectedRowKeys.value.length === 0) {
|
||||
window.$message.info('请选择要删除的容器')
|
||||
window.$message.info($gettext('Please select containers to delete'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -352,12 +355,12 @@ const bulkDelete = async () => {
|
||||
|
||||
selectedRowKeys.value = []
|
||||
refresh()
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Delete successful'))
|
||||
}
|
||||
|
||||
const bulkPause = async () => {
|
||||
if (selectedRowKeys.value.length === 0) {
|
||||
window.$message.info('请选择要暂停的容器')
|
||||
window.$message.info($gettext('Please select containers to pause'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -366,12 +369,12 @@ const bulkPause = async () => {
|
||||
|
||||
selectedRowKeys.value = []
|
||||
refresh()
|
||||
window.$message.success('暂停成功')
|
||||
window.$message.success($gettext('Pause successful'))
|
||||
}
|
||||
|
||||
const bulkUnpause = async () => {
|
||||
if (selectedRowKeys.value.length === 0) {
|
||||
window.$message.info('请选择要恢复的容器')
|
||||
window.$message.info($gettext('Please select containers to resume'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -380,7 +383,7 @@ const bulkUnpause = async () => {
|
||||
|
||||
selectedRowKeys.value = []
|
||||
refresh()
|
||||
window.$message.success('恢复成功')
|
||||
window.$message.success($gettext('Resume successful'))
|
||||
}
|
||||
|
||||
const closeContainerCreateModal = () => {
|
||||
@@ -396,16 +399,16 @@ onMounted(() => {
|
||||
<template>
|
||||
<n-flex vertical :size="20">
|
||||
<n-flex>
|
||||
<n-button type="primary" @click="containerCreateModal = true">创建容器</n-button>
|
||||
<n-button type="primary" @click="handlePrune" ghost>清理容器</n-button>
|
||||
<n-button type="primary" @click="containerCreateModal = true">{{ $gettext('Create Container') }}</n-button>
|
||||
<n-button type="primary" @click="handlePrune" ghost>{{ $gettext('Cleanup Containers') }}</n-button>
|
||||
<n-button-group>
|
||||
<n-button @click="bulkStart">启动</n-button>
|
||||
<n-button @click="bulkStop">停止</n-button>
|
||||
<n-button @click="bulkRestart">重启</n-button>
|
||||
<n-button @click="bulkForceStop">强制停止</n-button>
|
||||
<n-button @click="bulkPause">暂停</n-button>
|
||||
<n-button @click="bulkUnpause">恢复</n-button>
|
||||
<n-button @click="bulkDelete">删除</n-button>
|
||||
<n-button @click="bulkStart">{{ $gettext('Start') }}</n-button>
|
||||
<n-button @click="bulkStop">{{ $gettext('Stop') }}</n-button>
|
||||
<n-button @click="bulkRestart">{{ $gettext('Restart') }}</n-button>
|
||||
<n-button @click="bulkForceStop">{{ $gettext('Force Stop') }}</n-button>
|
||||
<n-button @click="bulkPause">{{ $gettext('Pause') }}</n-button>
|
||||
<n-button @click="bulkUnpause">{{ $gettext('Resume') }}</n-button>
|
||||
<n-button @click="bulkDelete">{{ $gettext('Delete') }}</n-button>
|
||||
</n-button-group>
|
||||
</n-flex>
|
||||
<n-data-table
|
||||
@@ -433,7 +436,7 @@ onMounted(() => {
|
||||
<n-modal
|
||||
v-model:show="logModal"
|
||||
preset="card"
|
||||
title="日志"
|
||||
:title="$gettext('Logs')"
|
||||
style="width: 80vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
@@ -456,23 +459,23 @@ onMounted(() => {
|
||||
<n-modal
|
||||
v-model:show="renameModal"
|
||||
preset="card"
|
||||
title="重命名"
|
||||
:title="$gettext('Rename')"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-form :model="renameModel">
|
||||
<n-form-item path="name" label="新名称">
|
||||
<n-form-item path="name" :label="$gettext('New Name')">
|
||||
<n-input
|
||||
v-model:value="renameModel.name"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入新名称"
|
||||
:placeholder="$gettext('Enter new name')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleRename">提交</n-button>
|
||||
<n-button type="info" block @click="handleRename">{{ $gettext('Submit') }}</n-button>
|
||||
</n-modal>
|
||||
<ContainerCreate :show="containerCreateModal" @close="closeContainerCreateModal" />
|
||||
</template>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { NButton, NDataTable, NFlex, NInput, NPopconfirm, NTag } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import container from '@/api/panel/container'
|
||||
import { formatDateTime } from '@/utils'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
|
||||
const pullModel = ref({
|
||||
name: '',
|
||||
auth: false,
|
||||
@@ -23,14 +26,14 @@ const columns: any = [
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '容器数',
|
||||
title: $gettext('Container Count'),
|
||||
key: 'containers',
|
||||
width: 100,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '镜像',
|
||||
title: $gettext('Image'),
|
||||
key: 'repo_tags',
|
||||
minWidth: 200,
|
||||
resizable: true,
|
||||
@@ -47,14 +50,14 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '大小',
|
||||
title: $gettext('Size'),
|
||||
key: 'size',
|
||||
width: 150,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
title: $gettext('Creation Time'),
|
||||
key: 'created_at',
|
||||
width: 200,
|
||||
resizable: true,
|
||||
@@ -63,7 +66,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 120,
|
||||
align: 'center',
|
||||
@@ -79,7 +82,7 @@ const columns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定删除吗?'
|
||||
return $gettext('Are you sure you want to delete?')
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -89,7 +92,7 @@ const columns: any = [
|
||||
type: 'error'
|
||||
},
|
||||
{
|
||||
default: () => '删除'
|
||||
default: () => $gettext('Delete')
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -113,14 +116,14 @@ const { loading, data, page, total, pageSize, pageCount, refresh } = usePaginati
|
||||
const handleDelete = async (row: any) => {
|
||||
useRequest(container.imageRemove(row.id)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Delete successful'))
|
||||
})
|
||||
}
|
||||
|
||||
const handlePrune = () => {
|
||||
useRequest(container.imagePrune()).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('清理成功')
|
||||
window.$message.success($gettext('Cleanup successful'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -129,7 +132,7 @@ const handlePull = () => {
|
||||
useRequest(container.imagePull(pullModel.value))
|
||||
.onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('拉取成功')
|
||||
window.$message.success($gettext('Pull successful'))
|
||||
})
|
||||
.onComplete(() => {
|
||||
loading.value = false
|
||||
@@ -145,8 +148,8 @@ onMounted(() => {
|
||||
<template>
|
||||
<n-flex vertical :size="20">
|
||||
<n-flex>
|
||||
<n-button type="primary" @click="pullModal = true">拉取镜像</n-button>
|
||||
<n-button type="primary" @click="handlePrune" ghost>清理镜像</n-button>
|
||||
<n-button type="primary" @click="pullModal = true">{{ $gettext('Pull Image') }}</n-button>
|
||||
<n-button type="primary" @click="handlePrune" ghost>{{ $gettext('Cleanup Images') }}</n-button>
|
||||
</n-flex>
|
||||
<n-data-table
|
||||
striped
|
||||
@@ -173,44 +176,44 @@ onMounted(() => {
|
||||
<n-modal
|
||||
v-model:show="pullModal"
|
||||
preset="card"
|
||||
title="拉取镜像"
|
||||
:title="$gettext('Pull Image')"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-form :model="pullModel">
|
||||
<n-form-item path="name" label="镜像名">
|
||||
<n-form-item path="name" :label="$gettext('Image Name')">
|
||||
<n-input
|
||||
v-model:value="pullModel.name"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="docker.io/php:8.3-fpm"
|
||||
:placeholder="$gettext('docker.io/php:8.3-fpm')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="auth" label="验证">
|
||||
<n-form-item path="auth" :label="$gettext('Authentication')">
|
||||
<n-switch v-model:value="pullModel.auth" />
|
||||
</n-form-item>
|
||||
<n-form-item v-if="pullModel.auth" path="username" label="用户名">
|
||||
<n-form-item v-if="pullModel.auth" path="username" :label="$gettext('Username')">
|
||||
<n-input
|
||||
v-model:value="pullModel.username"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入用户名"
|
||||
:placeholder="$gettext('Enter username')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="pullModel.auth" path="password" label="密码">
|
||||
<n-form-item v-if="pullModel.auth" path="password" :label="$gettext('Password')">
|
||||
<n-input
|
||||
v-model:value="pullModel.password"
|
||||
type="password"
|
||||
show-password-on="click"
|
||||
@keydown.enter.prevent
|
||||
placeholder="输入密码"
|
||||
:placeholder="$gettext('Enter password')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block :loading="loading" :disabled="loading" @click="handlePull">
|
||||
提交
|
||||
{{ $gettext('Submit') }}
|
||||
</n-button>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import ComposeView from '@/views/container/ComposeView.vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
defineOptions({
|
||||
name: 'container-index'
|
||||
@@ -10,25 +11,26 @@ import ImageView from '@/views/container/ImageView.vue'
|
||||
import NetworkView from '@/views/container/NetworkView.vue'
|
||||
import VolumeView from '@/views/container/VolumeView.vue'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
const current = ref('container')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<common-page show-footer>
|
||||
<n-tabs v-model:value="current" type="line" animated>
|
||||
<n-tab-pane name="container" tab="容器">
|
||||
<n-tab-pane name="container" :tab="$gettext('Containers')">
|
||||
<container-view />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="compose" tab="编排">
|
||||
<n-tab-pane name="compose" :tab="$gettext('Compose')">
|
||||
<compose-view />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="image" tab="镜像">
|
||||
<n-tab-pane name="image" :tab="$gettext('Images')">
|
||||
<image-view />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="network" tab="网络">
|
||||
<n-tab-pane name="network" :tab="$gettext('Networks')">
|
||||
<network-view />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="volume" tab="卷">
|
||||
<n-tab-pane name="volume" :tab="$gettext('Volumes')">
|
||||
<volume-view />
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { NButton, NDataTable, NFlex, NInput, NPopconfirm, NTag } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import container from '@/api/panel/container'
|
||||
import { formatDateTime } from '@/utils'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
|
||||
const createModel = ref({
|
||||
name: '',
|
||||
driver: 'bridge',
|
||||
@@ -39,28 +42,28 @@ const selectedRowKeys = ref<any>([])
|
||||
const columns: any = [
|
||||
{ type: 'selection', fixed: 'left' },
|
||||
{
|
||||
title: '名称',
|
||||
title: $gettext('Name'),
|
||||
key: 'name',
|
||||
minWidth: 150,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '驱动',
|
||||
title: $gettext('Driver'),
|
||||
key: 'driver',
|
||||
width: 100,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '范围',
|
||||
title: $gettext('Scope'),
|
||||
key: 'scope',
|
||||
width: 100,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '子网',
|
||||
title: $gettext('Subnet'),
|
||||
key: 'subnet',
|
||||
minWidth: 150,
|
||||
resizable: true,
|
||||
@@ -77,7 +80,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '网关',
|
||||
title: $gettext('Gateway'),
|
||||
key: 'gateway',
|
||||
width: 150,
|
||||
resizable: true,
|
||||
@@ -94,7 +97,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
title: $gettext('Creation Time'),
|
||||
key: 'created_at',
|
||||
width: 200,
|
||||
resizable: true,
|
||||
@@ -103,7 +106,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 120,
|
||||
align: 'center',
|
||||
@@ -119,7 +122,7 @@ const columns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定删除吗?'
|
||||
return $gettext('Are you sure you want to delete?')
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -129,7 +132,7 @@ const columns: any = [
|
||||
type: 'error'
|
||||
},
|
||||
{
|
||||
default: () => '删除'
|
||||
default: () => $gettext('Delete')
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -153,14 +156,14 @@ const { loading, data, page, total, pageSize, pageCount, refresh } = usePaginati
|
||||
const handleDelete = (row: any) => {
|
||||
useRequest(container.networkRemove(row.id)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Delete successful'))
|
||||
})
|
||||
}
|
||||
|
||||
const handlePrune = () => {
|
||||
useRequest(container.networkPrune()).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('清理成功')
|
||||
window.$message.success($gettext('Cleanup successful'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -169,7 +172,7 @@ const handleCreate = () => {
|
||||
useRequest(container.networkCreate(createModel.value))
|
||||
.onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('创建成功')
|
||||
window.$message.success($gettext('Created successfully'))
|
||||
})
|
||||
.onComplete(() => {
|
||||
loading.value = false
|
||||
@@ -185,8 +188,8 @@ onMounted(() => {
|
||||
<template>
|
||||
<n-flex vertical :size="20">
|
||||
<n-flex>
|
||||
<n-button type="primary" @click="createModal = true">创建网络</n-button>
|
||||
<n-button type="primary" @click="handlePrune" ghost>清理网络</n-button>
|
||||
<n-button type="primary" @click="createModal = true">{{ $gettext('Create Network') }}</n-button>
|
||||
<n-button type="primary" @click="handlePrune" ghost>{{ $gettext('Cleanup Networks') }}</n-button>
|
||||
</n-flex>
|
||||
<n-data-table
|
||||
striped
|
||||
@@ -213,17 +216,17 @@ onMounted(() => {
|
||||
<n-modal
|
||||
v-model:show="createModal"
|
||||
preset="card"
|
||||
title="创建网络"
|
||||
:title="$gettext('Create Network')"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-form :model="createModel">
|
||||
<n-form-item path="name" label="网络名">
|
||||
<n-form-item path="name" :label="$gettext('Network Name')">
|
||||
<n-input v-model:value="createModel.name" type="text" @keydown.enter.prevent />
|
||||
</n-form-item>
|
||||
<n-form-item path="driver" label="驱动">
|
||||
<n-form-item path="driver" :label="$gettext('Driver')">
|
||||
<n-select
|
||||
:options="options"
|
||||
v-model:value="createModel.driver"
|
||||
@@ -235,76 +238,76 @@ onMounted(() => {
|
||||
<n-form-item path="ipv4" label="IPV4">
|
||||
<n-switch v-model:value="createModel.ipv4.enabled" />
|
||||
</n-form-item>
|
||||
<n-form-item v-if="createModel.ipv4.enabled" path="subnet" label="子网">
|
||||
<n-form-item v-if="createModel.ipv4.enabled" path="subnet" :label="$gettext('Subnet')">
|
||||
<n-input
|
||||
v-model:value="createModel.ipv4.subnet"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="172.16.10.0/24"
|
||||
:placeholder="$gettext('172.16.10.0/24')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="createModel.ipv4.enabled" path="gateway" label="网关">
|
||||
<n-form-item v-if="createModel.ipv4.enabled" path="gateway" :label="$gettext('Gateway')">
|
||||
<n-input
|
||||
v-model:value="createModel.ipv4.gateway"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="172.16.10.254"
|
||||
:placeholder="$gettext('172.16.10.254')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="createModel.ipv4.enabled" path="ip_range" label="IP范围">
|
||||
<n-form-item v-if="createModel.ipv4.enabled" path="ip_range" :label="$gettext('IP Range')">
|
||||
<n-input
|
||||
v-model:value="createModel.ipv4.ip_range"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="172.16.10.0/24"
|
||||
:placeholder="$gettext('172.16.10.0/24')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="ipv6" label="IPV6">
|
||||
<n-switch v-model:value="createModel.ipv6.enabled" />
|
||||
</n-form-item>
|
||||
<n-form-item v-if="createModel.ipv6.enabled" path="subnet" label="子网">
|
||||
<n-form-item v-if="createModel.ipv6.enabled" path="subnet" :label="$gettext('Subnet')">
|
||||
<n-input
|
||||
v-model:value="createModel.ipv6.subnet"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="2408:400e::/48"
|
||||
:placeholder="$gettext('2408:400e::/48')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="createModel.ipv6.enabled" path="gateway" label="网关">
|
||||
<n-form-item v-if="createModel.ipv6.enabled" path="gateway" :label="$gettext('Gateway')">
|
||||
<n-input
|
||||
v-model:value="createModel.ipv6.gateway"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="2408:400e::1"
|
||||
:placeholder="$gettext('2408:400e::1')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="createModel.ipv6.enabled" path="ip_range" label="IP范围">
|
||||
<n-form-item v-if="createModel.ipv6.enabled" path="ip_range" :label="$gettext('IP Range')">
|
||||
<n-input
|
||||
v-model:value="createModel.ipv6.ip_range"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
placeholder="2408:400e::/64"
|
||||
:placeholder="$gettext('2408:400e::/64')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="env" label="标签">
|
||||
<n-form-item path="env" :label="$gettext('Labels')">
|
||||
<n-dynamic-input
|
||||
v-model:value="createModel.labels"
|
||||
preset="pair"
|
||||
key-placeholder="标签名"
|
||||
value-placeholder="标签值"
|
||||
:key-placeholder="$gettext('Label Name')"
|
||||
:value-placeholder="$gettext('Label Value')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="env" label="选项">
|
||||
<n-form-item path="env" :label="$gettext('Options')">
|
||||
<n-dynamic-input
|
||||
v-model:value="createModel.options"
|
||||
preset="pair"
|
||||
key-placeholder="选项名"
|
||||
value-placeholder="选项值"
|
||||
:key-placeholder="$gettext('Option Name')"
|
||||
:value-placeholder="$gettext('Option Value')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block :loading="loading" :disabled="loading" @click="handleCreate">
|
||||
提交
|
||||
{{ $gettext('Submit') }}
|
||||
</n-button>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { NButton, NDataTable, NInput, NPopconfirm } from 'naive-ui'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import container from '@/api/panel/container'
|
||||
import { formatDateTime } from '@/utils'
|
||||
|
||||
const { $gettext } = useGettext()
|
||||
|
||||
const createModel = ref({
|
||||
name: '',
|
||||
driver: 'local',
|
||||
@@ -20,35 +23,35 @@ const selectedRowKeys = ref<any>([])
|
||||
const columns: any = [
|
||||
{ type: 'selection', fixed: 'left' },
|
||||
{
|
||||
title: '名称',
|
||||
title: $gettext('Name'),
|
||||
key: 'name',
|
||||
minWidth: 150,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '驱动',
|
||||
title: $gettext('Driver'),
|
||||
key: 'driver',
|
||||
width: 100,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '范围',
|
||||
title: $gettext('Scope'),
|
||||
key: 'scope',
|
||||
width: 100,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '挂载点',
|
||||
title: $gettext('Mount Point'),
|
||||
key: 'mount_point',
|
||||
resizable: true,
|
||||
minWidth: 150,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
title: $gettext('Creation Time'),
|
||||
key: 'created_at',
|
||||
width: 200,
|
||||
resizable: true,
|
||||
@@ -57,7 +60,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 120,
|
||||
align: 'center',
|
||||
@@ -73,7 +76,7 @@ const columns: any = [
|
||||
},
|
||||
{
|
||||
default: () => {
|
||||
return '确定删除吗?'
|
||||
return $gettext('Are you sure you want to delete?')
|
||||
},
|
||||
trigger: () => {
|
||||
return h(
|
||||
@@ -83,7 +86,7 @@ const columns: any = [
|
||||
type: 'error'
|
||||
},
|
||||
{
|
||||
default: () => '删除'
|
||||
default: () => $gettext('Delete')
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -107,14 +110,14 @@ const { loading, data, page, total, pageSize, pageCount, refresh } = usePaginati
|
||||
const handleDelete = async (row: any) => {
|
||||
useRequest(container.volumeRemove(row.id)).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Delete successful'))
|
||||
})
|
||||
}
|
||||
|
||||
const handlePrune = () => {
|
||||
useRequest(container.volumePrune()).onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('清理成功')
|
||||
window.$message.success($gettext('Cleanup successful'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -123,7 +126,7 @@ const handleCreate = () => {
|
||||
useRequest(container.volumeCreate(createModel.value))
|
||||
.onSuccess(() => {
|
||||
refresh()
|
||||
window.$message.success('创建成功')
|
||||
window.$message.success($gettext('Created successfully'))
|
||||
})
|
||||
.onComplete(() => {
|
||||
loading.value = false
|
||||
@@ -139,8 +142,8 @@ onMounted(() => {
|
||||
<template>
|
||||
<n-flex vertical :size="20">
|
||||
<n-flex>
|
||||
<n-button type="primary" @click="createModal = true">创建卷</n-button>
|
||||
<n-button type="primary" @click="handlePrune" ghost>清理卷</n-button>
|
||||
<n-button type="primary" @click="createModal = true">{{ $gettext('Create Volume') }}</n-button>
|
||||
<n-button type="primary" @click="handlePrune" ghost>{{ $gettext('Cleanup Volumes') }}</n-button>
|
||||
</n-flex>
|
||||
<n-data-table
|
||||
striped
|
||||
@@ -167,17 +170,17 @@ onMounted(() => {
|
||||
<n-modal
|
||||
v-model:show="createModal"
|
||||
preset="card"
|
||||
title="创建卷"
|
||||
:title="$gettext('Create Volume')"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
:segmented="false"
|
||||
>
|
||||
<n-form :model="createModel">
|
||||
<n-form-item path="name" label="卷名">
|
||||
<n-form-item path="name" :label="$gettext('Volume Name')">
|
||||
<n-input v-model:value="createModel.name" type="text" @keydown.enter.prevent />
|
||||
</n-form-item>
|
||||
<n-form-item path="driver" label="驱动">
|
||||
<n-form-item path="driver" :label="$gettext('Driver')">
|
||||
<n-select
|
||||
:options="options"
|
||||
v-model:value="createModel.driver"
|
||||
@@ -186,25 +189,25 @@ onMounted(() => {
|
||||
>
|
||||
</n-select>
|
||||
</n-form-item>
|
||||
<n-form-item path="env" label="标签">
|
||||
<n-form-item path="env" :label="$gettext('Labels')">
|
||||
<n-dynamic-input
|
||||
v-model:value="createModel.labels"
|
||||
preset="pair"
|
||||
key-placeholder="标签名"
|
||||
value-placeholder="标签值"
|
||||
:key-placeholder="$gettext('Label Name')"
|
||||
:value-placeholder="$gettext('Label Value')"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="env" label="选项">
|
||||
<n-form-item path="env" :label="$gettext('Options')">
|
||||
<n-dynamic-input
|
||||
v-model:value="createModel.options"
|
||||
preset="pair"
|
||||
key-placeholder="选项名"
|
||||
value-placeholder="选项值"
|
||||
:key-placeholder="$gettext('Option Name')"
|
||||
:value-placeholder="$gettext('Option Value')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block :loading="loading" :disabled="loading" @click="handleCreate">
|
||||
提交
|
||||
{{ $gettext('Submit') }}
|
||||
</n-button>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
import type { RouteType } from '~/types/router'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
@@ -15,7 +16,7 @@ export default {
|
||||
path: '',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: 'containerIndex.title',
|
||||
title: $gettext('Container'),
|
||||
icon: 'mdi:layers-outline',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
import { use } from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { NButton, NPopconfirm } from 'naive-ui'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import dashboard from '@/api/panel/dashboard'
|
||||
import { router } from '@/router'
|
||||
@@ -34,7 +34,7 @@ use([
|
||||
DataZoomComponent
|
||||
])
|
||||
|
||||
const { locale } = useI18n()
|
||||
const { current: locale, $gettext } = useGettext()
|
||||
const tabStore = useTabStore()
|
||||
const realtime = ref<Realtime | null>(null)
|
||||
|
||||
@@ -126,13 +126,13 @@ const statusColor = (percentage: number) => {
|
||||
|
||||
const statusText = (percentage: number) => {
|
||||
if (percentage >= 90) {
|
||||
return '运行堵塞'
|
||||
return $gettext('Running blocked')
|
||||
} else if (percentage >= 80) {
|
||||
return '运行缓慢'
|
||||
return $gettext('Running slowly')
|
||||
} else if (percentage >= 70) {
|
||||
return '运行正常'
|
||||
return $gettext('Running normally')
|
||||
}
|
||||
return '运行流畅'
|
||||
return $gettext('Running smoothly')
|
||||
}
|
||||
|
||||
const chartOptions = computed(() => {
|
||||
@@ -318,9 +318,9 @@ const fetchCurrent = () => {
|
||||
|
||||
const handleRestartPanel = () => {
|
||||
clearInterval(homeInterval)
|
||||
window.$message.loading('面板重启中...')
|
||||
window.$message.loading($gettext('Panel restarting...'))
|
||||
useRequest(dashboard.restart()).onSuccess(() => {
|
||||
window.$message.success('面板重启成功')
|
||||
window.$message.success($gettext('Panel restarted successfully'))
|
||||
setTimeout(() => {
|
||||
tabStore.reloadTab(tabStore.active)
|
||||
}, 3000)
|
||||
@@ -332,7 +332,7 @@ const handleUpdate = () => {
|
||||
if (data.update) {
|
||||
router.push({ name: 'dashboard-update' })
|
||||
} else {
|
||||
window.$message.success('当前已是最新版本')
|
||||
window.$message.success($gettext('Current version is the latest'))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -376,7 +376,14 @@ const clearCurrent = () => {
|
||||
}
|
||||
|
||||
const quantifier = computed(() => {
|
||||
return locale.value === 'en' ? '' : ' 个'
|
||||
switch (locale) {
|
||||
case 'zh_CN':
|
||||
return '个'
|
||||
case 'zh_TW':
|
||||
return '個'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
let homeInterval: any = null
|
||||
@@ -408,40 +415,48 @@ if (import.meta.hot) {
|
||||
<n-page-header :subtitle="systemInfo?.panel_version">
|
||||
<n-grid :cols="4" pb-10>
|
||||
<n-gi>
|
||||
<n-statistic label="网站" :value="countInfo.website + quantifier" />
|
||||
<n-statistic :label="$gettext('Website')" :value="countInfo.website + quantifier" />
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-statistic label="数据库" :value="countInfo.database + quantifier" />
|
||||
<n-statistic
|
||||
:label="$gettext('Database')"
|
||||
:value="countInfo.database + quantifier"
|
||||
/>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-statistic label="FTP" :value="countInfo.ftp + quantifier" />
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-statistic label="计划任务" :value="countInfo.cron + quantifier" />
|
||||
<n-statistic
|
||||
:label="$gettext('Scheduled Tasks')"
|
||||
:value="countInfo.cron + quantifier"
|
||||
/>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
<template #title>耗子面板</template>
|
||||
<template #title>{{ $gettext('Rat Panel') }}</template>
|
||||
<template #extra>
|
||||
<n-flex>
|
||||
<n-button type="primary" @click="toSponsor"> 赞助支持 </n-button>
|
||||
<n-button type="primary" @click="toSponsor">
|
||||
{{ $gettext('Sponsor Support') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="handleRestartPanel">
|
||||
<template #trigger>
|
||||
<n-button type="warning"> 重启 </n-button>
|
||||
<n-button type="warning"> {{ $gettext('Restart') }} </n-button>
|
||||
</template>
|
||||
确定要重启面板吗?
|
||||
{{ $gettext('Are you sure you want to restart the panel?') }}
|
||||
</n-popconfirm>
|
||||
<n-button type="success" @click="handleUpdate"> 更新 </n-button>
|
||||
<n-button type="success" @click="handleUpdate"> {{ $gettext('Update') }} </n-button>
|
||||
</n-flex>
|
||||
</template>
|
||||
</n-page-header>
|
||||
</n-card>
|
||||
|
||||
<n-card :segmented="true" size="small" title="资源总览">
|
||||
<n-card :segmented="true" size="small" :title="$gettext('Resource Overview')">
|
||||
<n-flex v-if="realtime" size="large">
|
||||
<n-popover placement="bottom" trigger="hover">
|
||||
<template #trigger>
|
||||
<n-flex vertical flex items-center p-20 pl-40 pr-40>
|
||||
<p>负载状态</p>
|
||||
<p>{{ $gettext('Load Status') }}</p>
|
||||
<n-progress
|
||||
type="dashboard"
|
||||
:percentage="Math.round(formatPercent((realtime.load.load1 / cores) * 100))"
|
||||
@@ -453,21 +468,21 @@ if (import.meta.hot) {
|
||||
</template>
|
||||
<n-table :single-line="false" striped>
|
||||
<tr>
|
||||
<th>最近 1 分钟</th>
|
||||
<th>{{ $gettext('Last 1 minute') }}</th>
|
||||
<td>
|
||||
{{ formatPercent((realtime.load.load1 / cores) * 100) }}% /
|
||||
{{ realtime.load.load1 }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>最近 5 分钟</th>
|
||||
<th>{{ $gettext('Last 5 minutes') }}</th>
|
||||
<td>
|
||||
{{ formatPercent((realtime.load.load5 / cores) * 100) }}% /
|
||||
{{ realtime.load.load5 }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>最近 15 分钟</th>
|
||||
<th>{{ $gettext('Last 15 minutes') }}</th>
|
||||
<td>
|
||||
{{ formatPercent((realtime.load.load15 / cores) * 100) }}% /
|
||||
{{ realtime.load.load15 }}
|
||||
@@ -485,25 +500,26 @@ if (import.meta.hot) {
|
||||
:color="statusColor(realtime.percent)"
|
||||
>
|
||||
</n-progress>
|
||||
<p>{{ cores }} 核心</p>
|
||||
<p>{{ cores }} {{ $gettext('cores') }}</p>
|
||||
</n-flex>
|
||||
</template>
|
||||
<n-table :single-line="false" striped>
|
||||
<tr>
|
||||
<th>型号</th>
|
||||
<th>{{ $gettext('Model') }}</th>
|
||||
<td>{{ realtime.cpus[0].modelName }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
<th>{{ $gettext('Parameters') }}</th>
|
||||
<td>
|
||||
{{ realtime.cpus.length }} CPU {{ cores }} 核心
|
||||
{{ formatBytes(realtime.cpus[0].cacheSize * 1024) }} 缓存
|
||||
{{ realtime.cpus.length }} CPU {{ cores }} {{ $gettext('cores') }}
|
||||
{{ formatBytes(realtime.cpus[0].cacheSize * 1024) }} {{ $gettext('cache') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-for="item in realtime.cpus" :key="item.modelName">
|
||||
<th>CPU-{{ item.cpu }}</th>
|
||||
<td>
|
||||
使用率 {{ formatPercent(realtime.percents[item.cpu]) }}% 频率 {{ item.mhz }} MHz
|
||||
{{ $gettext('Usage') }} {{ formatPercent(realtime.percents[item.cpu]) }}%
|
||||
{{ $gettext('Frequency') }} {{ item.mhz }} MHz
|
||||
</td>
|
||||
</tr>
|
||||
</n-table>
|
||||
@@ -511,7 +527,7 @@ if (import.meta.hot) {
|
||||
<n-popover placement="bottom" trigger="hover">
|
||||
<template #trigger>
|
||||
<n-flex vertical flex items-center p-20 pl-40 pr-40>
|
||||
<p>内存</p>
|
||||
<p>{{ $gettext('Memory') }}</p>
|
||||
<n-progress
|
||||
type="dashboard"
|
||||
:percentage="realtime.mem.usedPercent"
|
||||
@@ -523,73 +539,73 @@ if (import.meta.hot) {
|
||||
</template>
|
||||
<n-table :single-line="false" striped>
|
||||
<tr>
|
||||
<th>活跃</th>
|
||||
<th>{{ $gettext('Active') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.active) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>不活跃</th>
|
||||
<th>{{ $gettext('Inactive') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.inactive) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>空闲</th>
|
||||
<th>{{ $gettext('Free') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.free) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>共享</th>
|
||||
<th>{{ $gettext('Shared') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.shared) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>已提交</th>
|
||||
<th>{{ $gettext('Committed') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.committedas) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>提交限制</th>
|
||||
<th>{{ $gettext('Commit Limit') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.commitlimit) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>SWAP大小</th>
|
||||
<th>{{ $gettext('SWAP Size') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.swaptotal) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>SWAP已用</th>
|
||||
<th>{{ $gettext('SWAP Used') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.swapcached) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>SWAP可用</th>
|
||||
<th>{{ $gettext('SWAP Available') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.swapfree) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>物理内存大小</th>
|
||||
<th>{{ $gettext('Physical Memory Size') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.total) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>物理内存已用</th>
|
||||
<th>{{ $gettext('Physical Memory Used') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.used) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>物理内存可用</th>
|
||||
<th>{{ $gettext('Physical Memory Available') }}</th>
|
||||
<td>
|
||||
{{ formatBytes(realtime.mem.available) }}
|
||||
</td>
|
||||
@@ -622,27 +638,27 @@ if (import.meta.hot) {
|
||||
</template>
|
||||
<n-table :single-line="false">
|
||||
<tr>
|
||||
<th>挂载点</th>
|
||||
<th>{{ $gettext('Mount Point') }}</th>
|
||||
<td>{{ item.path }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>文件系统</th>
|
||||
<th>{{ $gettext('File System') }}</th>
|
||||
<td>{{ item.fstype }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Inodes 使用率</th>
|
||||
<th>{{ $gettext('Inodes Usage') }}</th>
|
||||
<td>{{ formatPercent(item.inodesUsedPercent) }}%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Inodes 总数</th>
|
||||
<th>{{ $gettext('Inodes Total') }}</th>
|
||||
<td>{{ item.inodesTotal }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Inodes 已用</th>
|
||||
<th>{{ $gettext('Inodes Used') }}</th>
|
||||
<td>{{ item.inodesUsed }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Inodes 可用</th>
|
||||
<th>{{ $gettext('Inodes Available') }}</th>
|
||||
<td>{{ item.inodesFree }}</td>
|
||||
</tr>
|
||||
</n-table>
|
||||
@@ -659,7 +675,7 @@ if (import.meta.hot) {
|
||||
>
|
||||
<n-gi>
|
||||
<n-flex vertical>
|
||||
<n-card :segmented="true" size="small" title="快捷应用" min-h-340>
|
||||
<n-card :segmented="true" size="small" :title="$gettext('Quick Apps')" min-h-340>
|
||||
<n-scrollbar max-h-270>
|
||||
<n-grid
|
||||
v-if="!homeAppsLoading"
|
||||
@@ -702,57 +718,60 @@ if (import.meta.hot) {
|
||||
</n-grid>
|
||||
</n-scrollbar>
|
||||
<n-text v-if="!homeAppsLoading && !homeApps.length">
|
||||
您还没有设置任何应用在此显示!
|
||||
{{ $gettext('You have not set any apps to display here!') }}
|
||||
</n-text>
|
||||
<n-skeleton v-if="homeAppsLoading" text :repeat="12" />
|
||||
</n-card>
|
||||
<n-card :segmented="true" size="small" title="环境信息">
|
||||
<n-card :segmented="true" size="small" :title="$gettext('Environment Information')">
|
||||
<n-table v-if="systemInfo" :single-line="false">
|
||||
<tr>
|
||||
<th>系统主机名</th>
|
||||
<th>{{ $gettext('System Hostname') }}</th>
|
||||
<td>
|
||||
{{ systemInfo?.hostname || '加载中...' }}
|
||||
{{ systemInfo?.hostname || $gettext('Loading...') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>系统版本号</th>
|
||||
<th>{{ $gettext('System Version') }}</th>
|
||||
<td>
|
||||
{{ `${systemInfo?.os_name} ${systemInfo?.kernel_arch}` || '加载中...' }}
|
||||
{{
|
||||
`${systemInfo?.os_name} ${systemInfo?.kernel_arch}` ||
|
||||
$gettext('Loading...')
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>系统内核版本</th>
|
||||
<th>{{ $gettext('System Kernel Version') }}</th>
|
||||
<td>
|
||||
{{ systemInfo?.kernel_version || '加载中...' }}
|
||||
{{ systemInfo?.kernel_version || $gettext('Loading...') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>系统运行时间</th>
|
||||
<th>{{ $gettext('System Uptime') }}</th>
|
||||
<td>
|
||||
{{ formatDuration(Number(systemInfo?.uptime)) || '加载中...' }}
|
||||
{{ formatDuration(Number(systemInfo?.uptime)) || $gettext('Loading...') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>面板内部版本</th>
|
||||
<th>{{ $gettext('Panel Internal Version') }}</th>
|
||||
<td>
|
||||
{{
|
||||
systemInfo?.commit_hash +
|
||||
' ' +
|
||||
systemInfo?.go_version +
|
||||
' ' +
|
||||
systemInfo?.build_time || '加载中...'
|
||||
systemInfo?.build_time || $gettext('Loading...')
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>面板编译信息</th>
|
||||
<th>{{ $gettext('Panel Compile Information') }}</th>
|
||||
<td>
|
||||
{{
|
||||
systemInfo?.build_id +
|
||||
' ' +
|
||||
systemInfo?.build_user +
|
||||
'/' +
|
||||
systemInfo?.build_host || '加载中...'
|
||||
systemInfo?.build_host || $gettext('Loading...')
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -762,7 +781,7 @@ if (import.meta.hot) {
|
||||
</n-flex>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-card :segmented="true" size="small" title="实时监控">
|
||||
<n-card :segmented="true" size="small" :title="$gettext('Real-time Monitoring')">
|
||||
<n-flex vertical v-if="systemInfo">
|
||||
<n-form
|
||||
inline
|
||||
@@ -772,11 +791,11 @@ if (import.meta.hot) {
|
||||
>
|
||||
<n-form-item>
|
||||
<n-radio-group v-model:value="chartType">
|
||||
<n-radio-button value="net" label="网络" />
|
||||
<n-radio-button value="disk" label="硬盘" />
|
||||
<n-radio-button value="net" :label="$gettext('Network')" />
|
||||
<n-radio-button value="disk" :label="$gettext('Disk')" />
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
<n-form-item label="单位" ml-auto>
|
||||
<n-form-item :label="$gettext('Unit')" ml-auto>
|
||||
<n-select
|
||||
v-model:value="unitType"
|
||||
:options="units"
|
||||
@@ -784,7 +803,7 @@ if (import.meta.hot) {
|
||||
w-80
|
||||
></n-select>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="chartType == 'net'" label="网卡">
|
||||
<n-form-item v-if="chartType == 'net'" :label="$gettext('Network Card')">
|
||||
<n-select
|
||||
multiple
|
||||
v-model:value="nets"
|
||||
@@ -793,7 +812,7 @@ if (import.meta.hot) {
|
||||
w-200
|
||||
></n-select>
|
||||
</n-form-item>
|
||||
<n-form-item v-if="chartType == 'disk'" label="硬盘">
|
||||
<n-form-item v-if="chartType == 'disk'" :label="$gettext('Disk')">
|
||||
<n-select
|
||||
multiple
|
||||
v-model:value="disks"
|
||||
@@ -804,16 +823,26 @@ if (import.meta.hot) {
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-flex v-if="chartType == 'net'">
|
||||
<n-tag>总发送 {{ formatBytes(total.netBytesSent) }}</n-tag>
|
||||
<n-tag>总接收 {{ formatBytes(total.netBytesRecv) }}</n-tag>
|
||||
<n-tag>实时发送 {{ formatBytes(current.netBytesSent) }}/s</n-tag>
|
||||
<n-tag>实时接收 {{ formatBytes(current.netBytesRecv) }}/s</n-tag>
|
||||
<n-tag>{{ $gettext('Total Sent') }} {{ formatBytes(total.netBytesSent) }} </n-tag>
|
||||
<n-tag>
|
||||
{{ $gettext('Total Received') }} {{ formatBytes(total.netBytesRecv) }}
|
||||
</n-tag>
|
||||
<n-tag>
|
||||
{{ $gettext('Real-time Sent') }}
|
||||
{{ formatBytes(current.netBytesSent) }}/s
|
||||
</n-tag>
|
||||
<n-tag
|
||||
>{{ $gettext('Real-time Received') }} {{ formatBytes(current.netBytesRecv) }}/s
|
||||
</n-tag>
|
||||
</n-flex>
|
||||
<n-flex v-if="chartType == 'disk'">
|
||||
<n-tag>读取 {{ formatBytes(total.diskReadBytes) }}</n-tag>
|
||||
<n-tag>写入 {{ formatBytes(total.diskWriteBytes) }}</n-tag>
|
||||
<n-tag>实时读写 {{ formatBytes(current.diskRWBytes) }}/s</n-tag>
|
||||
<n-tag>读写延迟 {{ current.diskRWTime }}ms</n-tag>
|
||||
<n-tag>{{ $gettext('Read') }} {{ formatBytes(total.diskReadBytes) }}</n-tag>
|
||||
<n-tag>{{ $gettext('Write') }} {{ formatBytes(total.diskWriteBytes) }}</n-tag>
|
||||
<n-tag
|
||||
>{{ $gettext('Real-time Read/Write') }}
|
||||
{{ formatBytes(current.diskRWBytes) }}/s</n-tag
|
||||
>
|
||||
<n-tag>{{ $gettext('Read/Write Latency') }} {{ current.diskRWTime }}ms</n-tag>
|
||||
</n-flex>
|
||||
<n-card :bordered="false" h-530 pt-10>
|
||||
<v-chart class="chart" :option="chartOptions" autoresize />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { $gettext } from '@/utils/gettext'
|
||||
import type { RouteType } from '~/types/router'
|
||||
|
||||
const Layout = () => import('@/layout/IndexView.vue')
|
||||
@@ -16,7 +17,7 @@ export default {
|
||||
path: 'dashboard',
|
||||
component: () => import('./IndexView.vue'),
|
||||
meta: {
|
||||
title: '仪表盘',
|
||||
title: $gettext('Dashboard'),
|
||||
icon: 'mdi:gauge',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
@@ -28,7 +29,7 @@ export default {
|
||||
component: () => import('./UpdateView.vue'),
|
||||
isHidden: true,
|
||||
meta: {
|
||||
title: 'homeUpdate.title',
|
||||
title: $gettext('Update'),
|
||||
icon: 'mdi:archive-arrow-up-outline',
|
||||
role: ['admin'],
|
||||
requireAuth: true
|
||||
|
||||
@@ -5,7 +5,7 @@ defineOptions({
|
||||
|
||||
import Editor from '@guolao/vue-monaco-editor'
|
||||
import { NButton, NCheckbox, NDataTable, NFlex, NInput, NPopconfirm, NSwitch, NTag } from 'naive-ui'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
||||
import dashboard from '@/api/panel/dashboard'
|
||||
import website from '@/api/panel/website'
|
||||
@@ -13,21 +13,21 @@ import { useFileStore } from '@/store'
|
||||
import { generateRandomString, isNullOrUndef, renderIcon } from '@/utils'
|
||||
|
||||
const fileStore = useFileStore()
|
||||
const { t } = useI18n()
|
||||
const { $gettext } = useGettext()
|
||||
const router = useRouter()
|
||||
const selectedRowKeys = ref<any>([])
|
||||
|
||||
const columns: any = [
|
||||
{ type: 'selection', fixed: 'left' },
|
||||
{
|
||||
title: t('websiteIndex.columns.name'),
|
||||
title: $gettext('Website Name'),
|
||||
key: 'name',
|
||||
width: 200,
|
||||
resizable: true,
|
||||
ellipsis: { tooltip: true }
|
||||
},
|
||||
{
|
||||
title: t('websiteIndex.columns.status'),
|
||||
title: $gettext('Running'),
|
||||
key: 'status',
|
||||
width: 150,
|
||||
align: 'center',
|
||||
@@ -41,7 +41,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t('websiteIndex.columns.path'),
|
||||
title: $gettext('Directory'),
|
||||
key: 'path',
|
||||
minWidth: 200,
|
||||
resizable: true,
|
||||
@@ -75,7 +75,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t('websiteIndex.columns.remark'),
|
||||
title: $gettext('Remark'),
|
||||
key: 'remark',
|
||||
minWidth: 200,
|
||||
resizable: true,
|
||||
@@ -92,7 +92,7 @@ const columns: any = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t('websiteIndex.columns.actions'),
|
||||
title: $gettext('Actions'),
|
||||
key: 'actions',
|
||||
width: 220,
|
||||
align: 'center',
|
||||
@@ -108,7 +108,7 @@ const columns: any = [
|
||||
onClick: () => handleEdit(row)
|
||||
},
|
||||
{
|
||||
default: () => '修改',
|
||||
default: () => $gettext('Edit'),
|
||||
icon: renderIcon('material-symbols:edit-outline', { size: 14 })
|
||||
}
|
||||
),
|
||||
@@ -127,14 +127,23 @@ const columns: any = [
|
||||
},
|
||||
{
|
||||
default: () => [
|
||||
h('strong', {}, { default: () => `确定删除网站 ${row.name} 吗?` }),
|
||||
h(
|
||||
'strong',
|
||||
{},
|
||||
{
|
||||
default: () =>
|
||||
$gettext('Are you sure you want to delete website %{ name }?', {
|
||||
name: row.name
|
||||
})
|
||||
}
|
||||
),
|
||||
h(
|
||||
NCheckbox,
|
||||
{
|
||||
checked: deleteModel.value.path,
|
||||
onUpdateChecked: (v) => (deleteModel.value.path = v)
|
||||
},
|
||||
{ default: () => '删除网站目录' }
|
||||
{ default: () => $gettext('Delete website directory') }
|
||||
),
|
||||
h(
|
||||
NCheckbox,
|
||||
@@ -142,7 +151,7 @@ const columns: any = [
|
||||
checked: deleteModel.value.db,
|
||||
onUpdateChecked: (v) => (deleteModel.value.db = v)
|
||||
},
|
||||
{ default: () => '删除本地同名数据库' }
|
||||
{ default: () => $gettext('Delete local database with the same name') }
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -157,7 +166,7 @@ const columns: any = [
|
||||
style: 'margin-left: 15px;'
|
||||
},
|
||||
{
|
||||
default: () => '删除',
|
||||
default: () => $gettext('Delete'),
|
||||
icon: renderIcon('material-symbols:delete-outline', { size: 14 })
|
||||
}
|
||||
)
|
||||
@@ -198,7 +207,7 @@ const { data: installedDbAndPhp } = useRequest(dashboard.installedDbAndPhp, {
|
||||
initialData: {
|
||||
php: [
|
||||
{
|
||||
label: '不使用',
|
||||
label: $gettext('Not used'),
|
||||
value: 0
|
||||
}
|
||||
],
|
||||
@@ -227,7 +236,11 @@ const handleStatusChange = (row: any) => {
|
||||
|
||||
useRequest(website.status(row.id, !row.status)).onSuccess(() => {
|
||||
row.status = !row.status
|
||||
window.$message.success('已' + (row.status ? '启动' : '停止'))
|
||||
window.$message.success(
|
||||
$gettext('Already %{ status }', {
|
||||
status: row.status ? $gettext('started') : $gettext('stopped')
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -237,7 +250,7 @@ const getDefaultPage = async () => {
|
||||
|
||||
const handleRemark = (row: any) => {
|
||||
useRequest(website.updateRemark(row.id, row.remark)).onSuccess(() => {
|
||||
window.$message.success('修改成功')
|
||||
window.$message.success($gettext('Modified successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -254,7 +267,7 @@ const handleDelete = (id: number) => {
|
||||
useRequest(website.delete(id, deleteModel.value.path, deleteModel.value.db)).onSuccess(() => {
|
||||
refresh()
|
||||
deleteModel.value.path = true
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Deleted successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -263,7 +276,7 @@ const handleSaveDefaultPage = () => {
|
||||
website.saveDefaultConfig(editDefaultPageModel.value.index, editDefaultPageModel.value.stop)
|
||||
).onSuccess(() => {
|
||||
editDefaultPageModal.value = false
|
||||
window.$message.success('修改成功')
|
||||
window.$message.success($gettext('Modified successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -293,13 +306,13 @@ const handleCreate = async () => {
|
||||
path: '',
|
||||
remark: ''
|
||||
}
|
||||
window.$message.success('创建成功')
|
||||
window.$message.success($gettext('Created successfully'))
|
||||
})
|
||||
}
|
||||
|
||||
const bulkDelete = async () => {
|
||||
if (selectedRowKeys.value.length === 0) {
|
||||
window.$message.info('请选择要删除的网站')
|
||||
window.$message.info($gettext('Please select the websites to delete'))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -308,7 +321,7 @@ const bulkDelete = async () => {
|
||||
|
||||
selectedRowKeys.value = []
|
||||
refresh()
|
||||
window.$message.success('删除成功')
|
||||
window.$message.success($gettext('Deleted successfully'))
|
||||
}
|
||||
|
||||
const formatDbValue = (value: string) => {
|
||||
@@ -332,16 +345,20 @@ onMounted(() => {
|
||||
<n-flex vertical :size="20">
|
||||
<n-flex>
|
||||
<n-button type="primary" @click="createModal = true">
|
||||
{{ $t('websiteIndex.create.trigger') }}
|
||||
{{ $gettext('Create Website') }}
|
||||
</n-button>
|
||||
<n-popconfirm @positive-click="bulkDelete">
|
||||
<template #trigger>
|
||||
<n-button type="error"> 批量删除 </n-button>
|
||||
<n-button type="error"> {{ $gettext('Batch Delete') }} </n-button>
|
||||
</template>
|
||||
这会删除网站目录但不会删除同名数据库,确定删除选中的网站吗?
|
||||
{{
|
||||
$gettext(
|
||||
'This will delete the website directory but not the database with the same name. Are you sure you want to delete the selected websites?'
|
||||
)
|
||||
}}
|
||||
</n-popconfirm>
|
||||
<n-button type="warning" @click="editDefaultPageModal = true">
|
||||
{{ $t('websiteIndex.edit.trigger') }}
|
||||
{{ $gettext('Modify Default Page') }}
|
||||
</n-button>
|
||||
</n-flex>
|
||||
<n-data-table
|
||||
@@ -369,7 +386,7 @@ onMounted(() => {
|
||||
</common-page>
|
||||
<n-modal
|
||||
v-model:show="createModal"
|
||||
:title="$t('websiteIndex.create.title')"
|
||||
:title="$gettext('Create Website')"
|
||||
preset="card"
|
||||
style="width: 60vw"
|
||||
size="huge"
|
||||
@@ -378,17 +395,21 @@ onMounted(() => {
|
||||
@close="createModal = false"
|
||||
>
|
||||
<n-form :model="createModel">
|
||||
<n-form-item path="name" :label="$t('websiteIndex.create.fields.name.label')">
|
||||
<n-form-item path="name" :label="$gettext('Website Name')">
|
||||
<n-input
|
||||
v-model:value="createModel.name"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
:placeholder="$t('websiteIndex.create.fields.name.placeholder')"
|
||||
:placeholder="
|
||||
$gettext(
|
||||
'Recommended to use English for the website name, it cannot be modified after setting'
|
||||
)
|
||||
"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-row :gutter="[0, 24]">
|
||||
<n-col :span="11">
|
||||
<n-form-item :label="$t('websiteIndex.create.fields.domains.label')">
|
||||
<n-form-item :label="$gettext('Domain')">
|
||||
<n-dynamic-input
|
||||
v-model:value="createModel.domains"
|
||||
placeholder="example.com"
|
||||
@@ -399,7 +420,7 @@ onMounted(() => {
|
||||
</n-col>
|
||||
<n-col :span="2"></n-col>
|
||||
<n-col :span="11">
|
||||
<n-form-item :label="$t('websiteIndex.create.fields.port.label')">
|
||||
<n-form-item :label="$gettext('Port')">
|
||||
<n-dynamic-input
|
||||
v-model:value="createModel.listens"
|
||||
placeholder="80"
|
||||
@@ -411,11 +432,11 @@ onMounted(() => {
|
||||
</n-row>
|
||||
<n-row :gutter="[0, 24]">
|
||||
<n-col :span="11">
|
||||
<n-form-item path="php" :label="$t('websiteIndex.create.fields.phpVersion.label')">
|
||||
<n-form-item path="php" :label="$gettext('PHP Version')">
|
||||
<n-select
|
||||
v-model:value="createModel.php"
|
||||
:options="installedDbAndPhp.php"
|
||||
:placeholder="$t('websiteIndex.create.fields.phpVersion.placeholder')"
|
||||
:placeholder="$gettext('Select PHP Version')"
|
||||
@keydown.enter.prevent
|
||||
>
|
||||
</n-select>
|
||||
@@ -423,11 +444,11 @@ onMounted(() => {
|
||||
</n-col>
|
||||
<n-col :span="2"></n-col>
|
||||
<n-col :span="11">
|
||||
<n-form-item path="db" :label="$t('websiteIndex.create.fields.db.label')">
|
||||
<n-form-item path="db" :label="$gettext('Database')">
|
||||
<n-select
|
||||
v-model:value="createModel.db_type"
|
||||
:options="installedDbAndPhp.db"
|
||||
:placeholder="$t('websiteIndex.create.fields.db.placeholder')"
|
||||
:placeholder="$gettext('Select Database')"
|
||||
@keydown.enter.prevent
|
||||
@update:value="
|
||||
() => {
|
||||
@@ -444,31 +465,23 @@ onMounted(() => {
|
||||
</n-row>
|
||||
<n-row :gutter="[0, 24]">
|
||||
<n-col :span="7">
|
||||
<n-form-item
|
||||
v-if="createModel.db"
|
||||
path="db_name"
|
||||
:label="$t('websiteIndex.create.fields.dbName.label')"
|
||||
>
|
||||
<n-form-item v-if="createModel.db" path="db_name" :label="$gettext('Database Name')">
|
||||
<n-input
|
||||
v-model:value="createModel.db_name"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
:placeholder="$t('websiteIndex.create.fields.dbName.placeholder')"
|
||||
:placeholder="$gettext('Database Name')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
<n-col :span="1"></n-col>
|
||||
<n-col :span="7">
|
||||
<n-form-item
|
||||
v-if="createModel.db"
|
||||
path="db_user"
|
||||
:label="$t('websiteIndex.create.fields.dbUser.label')"
|
||||
>
|
||||
<n-form-item v-if="createModel.db" path="db_user" :label="$gettext('Database User')">
|
||||
<n-input
|
||||
v-model:value="createModel.db_user"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
:placeholder="$t('websiteIndex.create.fields.dbUser.placeholder')"
|
||||
:placeholder="$gettext('Database User')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
@@ -477,42 +490,46 @@ onMounted(() => {
|
||||
<n-form-item
|
||||
v-if="createModel.db"
|
||||
path="db_password"
|
||||
:label="$t('websiteIndex.create.fields.dbPassword.label')"
|
||||
:label="$gettext('Database Password')"
|
||||
>
|
||||
<n-input
|
||||
v-model:value="createModel.db_password"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
:placeholder="$t('websiteIndex.create.fields.dbPassword.placeholder')"
|
||||
:placeholder="$gettext('Database Password')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
</n-row>
|
||||
<n-form-item path="path" :label="$t('websiteIndex.create.fields.path.label')">
|
||||
<n-form-item path="path" :label="$gettext('Directory')">
|
||||
<n-input
|
||||
v-model:value="createModel.path"
|
||||
type="text"
|
||||
@keydown.enter.prevent
|
||||
:placeholder="$t('websiteIndex.create.fields.path.placeholder')"
|
||||
:placeholder="
|
||||
$gettext(
|
||||
'Website root directory (if left empty, defaults to website directory/website name)'
|
||||
)
|
||||
"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item path="remark" :label="$t('websiteIndex.create.fields.remark.label')">
|
||||
<n-form-item path="remark" :label="$gettext('Remark')">
|
||||
<n-input
|
||||
v-model:value="createModel.remark"
|
||||
type="textarea"
|
||||
@keydown.enter.prevent
|
||||
:placeholder="$t('websiteIndex.create.fields.remark.placeholder')"
|
||||
:placeholder="$gettext('Remark')"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button type="info" block @click="handleCreate">
|
||||
{{ $t('websiteIndex.create.actions.submit') }}
|
||||
{{ $gettext('Create') }}
|
||||
</n-button>
|
||||
</n-modal>
|
||||
<n-modal
|
||||
v-model:show="editDefaultPageModal"
|
||||
preset="card"
|
||||
title="修改默认页"
|
||||
:title="$gettext('Modify Default Page')"
|
||||
style="width: 80vw"
|
||||
size="huge"
|
||||
:bordered="false"
|
||||
@@ -520,7 +537,7 @@ onMounted(() => {
|
||||
@close="handleSaveDefaultPage"
|
||||
>
|
||||
<n-tabs type="line" animated>
|
||||
<n-tab-pane name="index" tab="默认页">
|
||||
<n-tab-pane :name="$gettext('Default Page')" :tab="$gettext('Default Page')">
|
||||
<Editor
|
||||
v-model:value="editDefaultPageModel.index"
|
||||
language="html"
|
||||
@@ -534,7 +551,7 @@ onMounted(() => {
|
||||
}"
|
||||
/>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="stop" tab="停止页">
|
||||
<n-tab-pane :name="$gettext('Stop Page')" :tab="$gettext('Stop Page')">
|
||||
<Editor
|
||||
v-model:value="editDefaultPageModel.stop"
|
||||
language="html"
|
||||
|
||||
Reference in New Issue
Block a user