feat: 增加 daemon.json 文件不存在或为空提示

This commit is contained in:
ssongliu 2023-02-01 16:15:31 +08:00 committed by ssongliu
parent d22b0a1368
commit b6e660a6cd
39 changed files with 641 additions and 430 deletions

View File

@ -1,6 +1,9 @@
package v1
import (
"io/ioutil"
"os"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
@ -20,6 +23,26 @@ func (b *BaseApi) LoadDockerStatus(c *gin.Context) {
helper.SuccessWithData(c, status)
}
// @Tags Container Docker
// @Summary Load docker daemon.json
// @Description 获取 docker 配置信息(表单)
// @Produce json
// @Success 200 {object} string
// @Security ApiKeyAuth
// @Router /containers/daemonjson/file [get]
func (b *BaseApi) LoadDaemonJsonFile(c *gin.Context) {
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
helper.SuccessWithData(c, "daemon.json is not find in path")
return
}
content, err := ioutil.ReadFile(constant.DaemonJsonPath)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, string(content))
}
// @Tags Container Docker
// @Summary Load docker daemon.json
// @Description 获取 docker 配置信息

View File

@ -60,6 +60,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
baRouter.POST("/volume", baseApi.CreateVolume)
baRouter.GET("/daemonjson", baseApi.LoadDaemonJson)
baRouter.GET("/daemonjson/file", baseApi.LoadDaemonJsonFile)
baRouter.GET("/docker/status", baseApi.LoadDockerStatus)
baRouter.POST("/docker/operate", baseApi.OperateDocker)
baRouter.POST("/daemonjson/update", baseApi.UpdateDaemonJson)

View File

@ -881,17 +881,14 @@ var doc = `{
},
"/auth/status": {
"get": {
"description": "获取系统安全登录状态",
"description": "判断是否为首次登录",
"tags": [
"Auth"
],
"summary": "Load safety status",
"summary": "Check is First login",
"responses": {
"200": {
"description": ""
},
"402": {
"description": ""
}
}
}
@ -1637,6 +1634,31 @@ var doc = `{
}
}
},
"/containers/daemonjson/file": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取 docker 配置信息(表单)",
"produces": [
"application/json"
],
"tags": [
"Container Docker"
],
"summary": "Load docker daemon.json",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/containers/daemonjson/update": {
"post": {
"security": [
@ -6230,6 +6252,25 @@ var doc = `{
}
}
},
"/settings/search/available": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取系统可用状态",
"tags": [
"System Setting"
],
"summary": "Load system available status",
"responses": {
"200": {
"description": ""
}
}
}
},
"/settings/snapshot": {
"post": {
"security": [
@ -10553,15 +10594,18 @@ var doc = `{
"model.App": {
"type": "object",
"properties": {
"author": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"crossVersionUpdate": {
"type": "boolean"
},
"document": {
"type": "string"
},
"github": {
"type": "string"
},
"icon": {
"type": "string"
},
@ -10583,9 +10627,6 @@ var doc = `{
"shortDesc": {
"type": "string"
},
"source": {
"type": "string"
},
"status": {
"type": "string"
},
@ -10594,6 +10635,9 @@ var doc = `{
},
"updatedAt": {
"type": "string"
},
"website": {
"type": "string"
}
}
},
@ -10981,8 +11025,20 @@ var doc = `{
"pageSize": {
"type": "integer"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"type": {
"type": "string"
},
"unused": {
"type": "boolean"
},
"update": {
"type": "boolean"
}
}
},
@ -11852,15 +11908,18 @@ var doc = `{
"response.AppDTO": {
"type": "object",
"properties": {
"author": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"crossVersionUpdate": {
"type": "boolean"
},
"document": {
"type": "string"
},
"github": {
"type": "string"
},
"icon": {
"type": "string"
},
@ -11882,9 +11941,6 @@ var doc = `{
"shortDesc": {
"type": "string"
},
"source": {
"type": "string"
},
"status": {
"type": "string"
},
@ -11905,6 +11961,9 @@ var doc = `{
"items": {
"type": "string"
}
},
"website": {
"type": "string"
}
}
},

View File

@ -867,17 +867,14 @@
},
"/auth/status": {
"get": {
"description": "获取系统安全登录状态",
"description": "判断是否为首次登录",
"tags": [
"Auth"
],
"summary": "Load safety status",
"summary": "Check is First login",
"responses": {
"200": {
"description": ""
},
"402": {
"description": ""
}
}
}
@ -1623,6 +1620,31 @@
}
}
},
"/containers/daemonjson/file": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取 docker 配置信息(表单)",
"produces": [
"application/json"
],
"tags": [
"Container Docker"
],
"summary": "Load docker daemon.json",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/containers/daemonjson/update": {
"post": {
"security": [
@ -6216,6 +6238,25 @@
}
}
},
"/settings/search/available": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取系统可用状态",
"tags": [
"System Setting"
],
"summary": "Load system available status",
"responses": {
"200": {
"description": ""
}
}
}
},
"/settings/snapshot": {
"post": {
"security": [
@ -10539,15 +10580,18 @@
"model.App": {
"type": "object",
"properties": {
"author": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"crossVersionUpdate": {
"type": "boolean"
},
"document": {
"type": "string"
},
"github": {
"type": "string"
},
"icon": {
"type": "string"
},
@ -10569,9 +10613,6 @@
"shortDesc": {
"type": "string"
},
"source": {
"type": "string"
},
"status": {
"type": "string"
},
@ -10580,6 +10621,9 @@
},
"updatedAt": {
"type": "string"
},
"website": {
"type": "string"
}
}
},
@ -10967,8 +11011,20 @@
"pageSize": {
"type": "integer"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"type": {
"type": "string"
},
"unused": {
"type": "boolean"
},
"update": {
"type": "boolean"
}
}
},
@ -11838,15 +11894,18 @@
"response.AppDTO": {
"type": "object",
"properties": {
"author": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"crossVersionUpdate": {
"type": "boolean"
},
"document": {
"type": "string"
},
"github": {
"type": "string"
},
"icon": {
"type": "string"
},
@ -11868,9 +11927,6 @@
"shortDesc": {
"type": "string"
},
"source": {
"type": "string"
},
"status": {
"type": "string"
},
@ -11891,6 +11947,9 @@
"items": {
"type": "string"
}
},
"website": {
"type": "string"
}
}
},

View File

@ -1447,12 +1447,14 @@ definitions:
type: object
model.App:
properties:
author:
type: string
createdAt:
type: string
crossVersionUpdate:
type: boolean
document:
type: string
github:
type: string
icon:
type: string
id:
@ -1467,14 +1469,14 @@ definitions:
type: string
shortDesc:
type: string
source:
type: string
status:
type: string
type:
type: string
updatedAt:
type: string
website:
type: string
type: object
model.AppInstall:
properties:
@ -1727,8 +1729,16 @@ definitions:
type: integer
pageSize:
type: integer
tags:
items:
type: string
type: array
type:
type: string
unused:
type: boolean
update:
type: boolean
required:
- page
- pageSize
@ -2314,12 +2324,14 @@ definitions:
type: object
response.AppDTO:
properties:
author:
type: string
createdAt:
type: string
crossVersionUpdate:
type: boolean
document:
type: string
github:
type: string
icon:
type: string
id:
@ -2334,8 +2346,6 @@ definitions:
type: string
shortDesc:
type: string
source:
type: string
status:
type: string
tags:
@ -2350,6 +2360,8 @@ definitions:
items:
type: string
type: array
website:
type: string
type: object
response.AppDetailDTO:
properties:
@ -3125,13 +3137,11 @@ paths:
- Auth
/auth/status:
get:
description: 获取系统安全登录状态
description: 判断是否为首次登录
responses:
"200":
description: ""
"402":
description: ""
summary: Load safety status
summary: Check is First login
tags:
- Auth
/backups:
@ -3605,6 +3615,21 @@ paths:
summary: Load docker daemon.json
tags:
- Container Docker
/containers/daemonjson/file:
get:
description: 获取 docker 配置信息(表单)
produces:
- application/json
responses:
"200":
description: OK
schema:
type: string
security:
- ApiKeyAuth: []
summary: Load docker daemon.json
tags:
- Container Docker
/containers/daemonjson/update:
post:
consumes:
@ -6529,6 +6554,17 @@ paths:
summary: Load system setting info
tags:
- System Setting
/settings/search/available:
get:
description: 获取系统可用状态
responses:
"200":
description: ""
security:
- ApiKeyAuth: []
summary: Load system available status
tags:
- System Setting
/settings/snapshot:
post:
consumes:

View File

@ -130,6 +130,9 @@ export const dockerOperate = (params: Container.DockerOperate) => {
export const loadDaemonJson = () => {
return http.get<Container.DaemonJsonConf>(`/containers/daemonjson`);
};
export const loadDaemonJsonFile = () => {
return http.get<string>(`/containers/daemonjson/file`);
};
export const loadDockerStatus = () => {
return http.get<string>(`/containers/docker/status`);
};

View File

@ -17,7 +17,7 @@
placeholder="None data"
:indent-with-tab="true"
:tabSize="4"
style="margin-top: 10px; height: calc(100vh - 350px)"
style="margin-top: 10px; height: calc(100vh - 375px)"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"

View File

@ -3,12 +3,12 @@ export default {
true: 'true',
false: 'false',
button: {
create: 'Create',
add: 'Add',
save: 'Save',
create: 'Create ',
add: 'Add ',
save: 'Save ',
set: 'Reset',
sync: 'Sync',
delete: 'Delete',
sync: 'Sync ',
delete: 'Delete ',
edit: 'Edit',
enable: 'Enable',
disable: 'Disable',

View File

@ -79,7 +79,7 @@ export default {
infoTitle: '提示',
notRecords: '当前任务未产生执行记录',
sureLogOut: '您是否确认退出登录?',
createSuccess: '建成功',
createSuccess: '建成功',
updateSuccess: '更新成功',
uploadSuccess: '上传成功',
operate: '操作',
@ -245,7 +245,7 @@ export default {
database: {
delete: '删除操作无法回滚请输入 "',
deleteHelper: '" 删除此数据库',
create: '建数据库',
create: '建数据库',
noMysql: '当前未检测到 {0} 数据库请进入应用商店点击安装',
mysqlBadStatus: '当前 mysql 应用状态异常请在',
adjust: '中查看原因或修改配置',
@ -269,7 +269,6 @@ export default {
portSetting: '端口',
portHelper: '该端口为容器对外暴露端口修改需要单独保存并且重启容器',
baseSetting: '基础设置',
confChange: '配置修改',
unSupportType: '不支持当前文件类型',
@ -746,7 +745,7 @@ export default {
snapshot: '快照',
recoverDetail: '恢复详情',
createSnapshot: '建快照',
createSnapshot: '建快照',
recover: '恢复',
noRecoverRecord: '暂无恢复记录',
lastRecoverAt: '上次恢复时间',
@ -890,7 +889,7 @@ export default {
remark: '备注',
group: '分组',
groupSetting: '分组管理',
createGroup: '建分组',
createGroup: '建分组',
app: '应用',
appNew: '新装应用',
appInstalled: '已装应用',
@ -923,7 +922,7 @@ export default {
check: '查看',
acmeAccountManage: 'Acme 账户',
email: '邮箱',
addAccount: '建账户',
addAccount: '建账户',
acmeAccount: 'Acme 账户',
provider: '验证方式',
dnsCommon: '手动解析',
@ -1052,7 +1051,7 @@ export default {
saveAndReload: '保存并重载',
},
ssl: {
create: '建证书',
create: '建证书',
provider: '类型',
manualCreate: '手动创建',
acmeAccount: 'Acme 账号',
@ -1072,7 +1071,7 @@ export default {
autoRenewHelper: '距离到期时间7天自动续签',
renewSuccess: '续签成功',
renewWebsite: '该证书已经和以下网站关联续签会同步应用到这些网站',
createAcme: '建账户',
createAcme: '建账户',
},
firewall: {
ccDeny: 'CC 防护',

View File

@ -100,7 +100,7 @@ const showBack = computed(() => {
}
.content-container__toolbar {
margin-top: 30px;
margin-top: 20px;
}
.content-container_form {

View File

@ -35,7 +35,7 @@
</el-row>
</el-card>
</div>
<el-card style="margin-top: 20px">
<el-card style="margin-top: 40px">
<LayoutContent :header="$t('container.containerList')" back-name="Compose" :reload="true">
<ComplexTable
:pagination-config="paginationConfig"
@ -99,7 +99,7 @@
show-overflow-tooltip
/>
<fu-table-operations
width="200px"
width="220"
:ellipsis="10"
:buttons="buttons"
:label="$t('commons.table.operate')"

View File

@ -10,13 +10,13 @@
<LayoutContent v-loading="loading" :title="$t('container.image')" :class="{ mask: dockerStatus != 'Running' }">
<template #toolbar>
<el-button @click="onOpenPull">
<el-button type="primary" plain @click="onOpenPull">
{{ $t('container.imagePull') }}
</el-button>
<el-button @click="onOpenload">
<el-button type="primary" plain @click="onOpenload">
{{ $t('container.importImage') }}
</el-button>
<el-button @click="onOpenBuild">
<el-button type="primary" plain @click="onOpenBuild">
{{ $t('container.build') }}
</el-button>
</template>

View File

@ -7,7 +7,7 @@
size="50%"
>
<template #header>
<DrawerHeader :header="$t('container.imagePull')" :back="handleClose" />
<DrawerHeader :header="$t('container.imagePull')" :back="onCloseLog" />
</template>
<el-row type="flex" justify="center">
<el-col :span="22">
@ -106,13 +106,8 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
buttonDisabled.value = false;
logInfo.value = '';
};
const emit = defineEmits<{ (e: 'search'): void }>();
const handleClose = () => {
drawerVisiable.value = false;
};
type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
@ -150,6 +145,7 @@ const onCloseLog = async () => {
emit('search');
clearInterval(Number(timer));
timer = null;
drawerVisiable.value = false;
};
function loadDetailInfo(id: number) {

View File

@ -1,13 +1,13 @@
<template>
<el-drawer
v-model="drawerVisiable"
@close="onCloseLog"
:destroy-on-close="true"
@close="onCloseLog"
:close-on-click-modal="false"
size="50%"
>
<template #header>
<DrawerHeader :header="$t('container.imagePush')" :back="handleClose" />
<DrawerHeader :header="$t('container.imagePush')" :back="onCloseLog" />
</template>
<el-row type="flex" justify="center">
<el-col :span="22">
@ -116,10 +116,6 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
};
const emit = defineEmits<{ (e: 'search'): void }>();
const handleClose = () => {
drawerVisiable.value = false;
};
type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
@ -154,6 +150,7 @@ const onCloseLog = async () => {
emit('search');
clearInterval(Number(timer));
timer = null;
drawerVisiable.value = false;
};
function loadDetailInfo(id: number) {

View File

@ -17,7 +17,7 @@
<el-button type="primary" @click="onCreate()">
{{ $t('container.createNetwork') }}
</el-button>
<el-button plain :disabled="selects.length === 0" @click="batchDelete(null)">
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>

View File

@ -13,7 +13,7 @@
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('container.createRepo') }}
</el-button>
<el-button plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>

View File

@ -1,6 +1,6 @@
<template>
<div>
<div class="app-content" style="margin-top: 20px">
<div class="app-content" style="margin-top: 30px">
<el-card class="app-card">
<el-row :gutter="20">
<el-col :lg="3" :xl="2">
@ -49,7 +49,7 @@
</el-card>
</div>
<LayoutContent v-loading="loading" :title="$t('container.setting')" :divider="true">
<LayoutContent v-loading="loading" style="margin-top: 30px" :title="$t('container.setting')" :divider="true">
<template #main>
<el-radio-group v-model="confShowType" @change="changeMode">
<el-radio-button label="base">{{ $t('database.baseConf') }}</el-radio-button>
@ -58,7 +58,7 @@
<el-row style="margin-top: 20px" v-if="confShowType === 'base'">
<el-col :span="1"><br /></el-col>
<el-col :span="10">
<el-form :model="form" ref="formRef" label-width="120px">
<el-form :model="form" label-position="left" ref="formRef" label-width="120px">
<el-form-item :label="$t('container.mirrors')" prop="mirrors">
<el-input
type="textarea"
@ -98,10 +98,10 @@
<div v-if="confShowType === 'all'">
<codemirror
:autofocus="true"
placeholder="None data"
placeholder="# The Docker configuration file does not exist or is empty (/etc/docker/daemon.json)"
:indent-with-tab="true"
:tabSize="4"
style="margin-top: 10px; height: calc(100vh - 380px)"
style="margin-top: 10px; height: calc(100vh - 430px)"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"
@ -128,13 +128,18 @@ import { Codemirror } from 'vue-codemirror';
import LayoutContent from '@/layout/layout-content.vue';
import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
import { LoadFile } from '@/api/modules/files';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import i18n from '@/lang';
import { dockerOperate, loadDaemonJson, updateDaemonJson, updateDaemonJsonByfile } from '@/api/modules/container';
import {
dockerOperate,
loadDaemonJson,
loadDaemonJsonFile,
updateDaemonJson,
updateDaemonJsonByfile,
} from '@/api/modules/container';
const loading = ref(false);
const showDaemonJsonAlert = ref(false);
const extensions = [javascript(), oneDark];
const confShowType = ref('base');
@ -224,14 +229,20 @@ const onSubmitSave = async () => {
};
const loadDockerConf = async () => {
const res = await LoadFile({ path: '/etc/docker/daemon.json' });
dockerConf.value = res.data;
const res = await loadDaemonJsonFile();
if (res.data === 'daemon.json is not find in path') {
console.log(res.data);
showDaemonJsonAlert.value = true;
} else {
dockerConf.value = res.data;
}
};
const changeMode = async () => {
if (confShowType.value === 'all') {
loadDockerConf();
} else {
showDaemonJsonAlert.value = false;
search();
}
};

View File

@ -17,7 +17,7 @@
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('container.createComposeTemplate') }}
</el-button>
<el-button plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>

View File

@ -13,7 +13,7 @@
<el-button type="primary" @click="onCreate()">
{{ $t('container.createVolume') }}
</el-button>
<el-button plain :disabled="selects.length === 0" @click="batchDelete(null)">
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>

View File

@ -13,7 +13,7 @@
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('commons.button.create') }}{{ $t('cronjob.cronTask') }}
</el-button>
<el-button plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>

View File

@ -3,130 +3,148 @@
<template #header>
<DrawerHeader :header="$t('cronjob.cronTask')" :back="handleClose" />
</template>
<el-form ref="formRef" :model="dialogData.rowData" label-position="left" :rules="rules" label-width="120px">
<el-form-item :label="$t('cronjob.taskType')" prop="type">
<el-select style="width: 100%" v-model="dialogData.rowData!.type">
<el-option value="shell" :label="$t('cronjob.shell')" />
<el-option value="website" :label="$t('cronjob.website')" />
<el-option value="database" :label="$t('cronjob.database')" />
<el-option value="directory" :label="$t('cronjob.directory')" />
<el-option value="curl" :label="$t('cronjob.curl') + ' URL'" />
</el-select>
</el-form-item>
<el-form ref="formRef" label-position="top" :model="dialogData.rowData" :rules="rules" label-width="120px">
<el-row type="flex" justify="center">
<el-col :span="22">
<el-form-item :label="$t('cronjob.taskType')" prop="type">
<el-select style="width: 100%" v-model="dialogData.rowData!.type">
<el-option value="shell" :label="$t('cronjob.shell')" />
<el-option value="website" :label="$t('cronjob.website')" />
<el-option value="database" :label="$t('cronjob.database')" />
<el-option value="directory" :label="$t('cronjob.directory')" />
<el-option value="curl" :label="$t('cronjob.curl') + ' URL'" />
</el-select>
</el-form-item>
<el-form-item :label="$t('cronjob.taskName')" prop="name">
<el-input style="width: 100%" clearable v-model.trim="dialogData.rowData!.name" />
</el-form-item>
<el-form-item :label="$t('cronjob.taskName')" prop="name">
<el-input style="width: 100%" clearable v-model.trim="dialogData.rowData!.name" />
</el-form-item>
<el-form-item :label="$t('cronjob.cronSpec')" prop="spec">
<el-select style="width: 20%" v-model="dialogData.rowData!.specType">
<el-option v-for="item in specOptions" :key="item.label" :value="item.value" :label="item.label" />
</el-select>
<el-select
v-if="dialogData.rowData!.specType === 'perWeek'"
style="width: 12%; margin-left: 20px"
v-model="dialogData.rowData!.week"
>
<el-option v-for="item in weekOptions" :key="item.label" :value="item.value" :label="item.label" />
</el-select>
<el-input
v-if="dialogData.rowData!.specType === 'perMonth' || dialogData.rowData!.specType === 'perNDay'"
style="width: 20%; margin-left: 20px"
v-model.number="dialogData.rowData!.day"
>
<template #append>{{ $t('cronjob.day') }}</template>
</el-input>
<el-input
v-if="dialogData.rowData!.specType !== 'perHour' && dialogData.rowData!.specType !== 'perNMinute'"
style="width: 20%; margin-left: 20px"
v-model.number="dialogData.rowData!.hour"
>
<template #append>{{ $t('cronjob.hour') }}</template>
</el-input>
<el-input style="width: 20%; margin-left: 20px" v-model.number="dialogData.rowData!.minute">
<template #append>{{ $t('cronjob.minute') }}</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('cronjob.cronSpec')" prop="spec">
<el-select style="width: 20%" v-model="dialogData.rowData!.specType">
<el-option
v-for="item in specOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
<el-select
v-if="dialogData.rowData!.specType === 'perWeek'"
style="width: 12%; margin-left: 20px"
v-model="dialogData.rowData!.week"
>
<el-option
v-for="item in weekOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
<el-input
v-if="dialogData.rowData!.specType === 'perMonth' || dialogData.rowData!.specType === 'perNDay'"
style="width: 20%; margin-left: 20px"
v-model.number="dialogData.rowData!.day"
>
<template #append>{{ $t('cronjob.day') }}</template>
</el-input>
<el-input
v-if="dialogData.rowData!.specType !== 'perHour' && dialogData.rowData!.specType !== 'perNMinute'"
style="width: 20%; margin-left: 20px"
v-model.number="dialogData.rowData!.hour"
>
<template #append>{{ $t('cronjob.hour') }}</template>
</el-input>
<el-input style="width: 20%; margin-left: 20px" v-model.number="dialogData.rowData!.minute">
<template #append>{{ $t('cronjob.minute') }}</template>
</el-input>
</el-form-item>
<el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script">
<el-input
style="width: 100%"
clearable
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
v-model="dialogData.rowData!.script"
/>
</el-form-item>
<el-form-item v-if="dialogData.rowData!.type === 'website'" :label="$t('cronjob.website')" prop="website">
<el-select style="width: 100%" v-model="dialogData.rowData!.website">
<el-option v-for="item in websiteOptions" :key="item" :value="item" :label="item" />
</el-select>
</el-form-item>
<div v-if="dialogData.rowData!.type === 'database'">
<el-form-item :label="$t('cronjob.database')" prop="dbName">
<el-select style="width: 100%" clearable v-model="dialogData.rowData!.dbName">
<el-option v-for="item in mysqlInfo.dbNames" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</div>
<el-form-item
v-if="dialogData.rowData!.type === 'directory'"
:label="$t('cronjob.sourceDir')"
prop="sourceDir"
>
<el-input style="width: 100%" disabled v-model="dialogData.rowData!.sourceDir">
<template #append>
<FileList @choose="loadDir" :dir="true"></FileList>
</template>
</el-input>
</el-form-item>
<div v-if="isBackup()">
<el-form-item :label="$t('cronjob.target')" prop="targetDirID">
<el-select style="width: 100%" v-model="dialogData.rowData!.targetDirID">
<el-option
v-for="item in backupOptions"
:key="item.label"
:value="item.value"
:label="item.label"
<el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script">
<el-input
style="width: 100%"
clearable
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
v-model="dialogData.rowData!.script"
/>
</el-select>
</el-form-item>
<el-form-item v-if="dialogData.rowData!.targetDirID !== localDirID">
<el-checkbox v-model="dialogData.rowData!.keepLocal">
{{ $t('cronjob.saveLocal') }}
</el-checkbox>
</el-form-item>
<el-form-item :label="$t('cronjob.retainCopies')" prop="retainCopies">
<el-input-number
:min="1"
:max="30"
v-model.number="dialogData.rowData!.retainCopies"
></el-input-number>
</el-form-item>
</div>
</el-form-item>
<el-form-item v-if="dialogData.rowData!.type === 'curl'" :label="$t('cronjob.url')" prop="url">
<el-input style="width: 100%" clearable v-model.trim="dialogData.rowData!.url" />
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type === 'website'"
:label="$t('cronjob.website')"
prop="website"
>
<el-select style="width: 100%" v-model="dialogData.rowData!.website">
<el-option v-for="item in websiteOptions" :key="item" :value="item" :label="item" />
</el-select>
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type === 'website' || dialogData.rowData!.type === 'directory'"
:label="$t('cronjob.exclusionRules')"
prop="exclusionRules"
>
<el-input
style="width: 100%"
type="textarea"
:placeholder="$t('cronjob.rulesHelper')"
:autosize="{ minRows: 3, maxRows: 6 }"
clearable
v-model="dialogData.rowData!.exclusionRules"
/>
</el-form-item>
<div v-if="dialogData.rowData!.type === 'database'">
<el-form-item :label="$t('cronjob.database')" prop="dbName">
<el-select style="width: 100%" clearable v-model="dialogData.rowData!.dbName">
<el-option v-for="item in mysqlInfo.dbNames" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</div>
<el-form-item
v-if="dialogData.rowData!.type === 'directory'"
:label="$t('cronjob.sourceDir')"
prop="sourceDir"
>
<el-input style="width: 100%" disabled v-model="dialogData.rowData!.sourceDir">
<template #append>
<FileList @choose="loadDir" :dir="true"></FileList>
</template>
</el-input>
</el-form-item>
<div v-if="isBackup()">
<el-form-item :label="$t('cronjob.target')" prop="targetDirID">
<el-select style="width: 100%" v-model="dialogData.rowData!.targetDirID">
<el-option
v-for="item in backupOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item v-if="dialogData.rowData!.targetDirID !== localDirID">
<el-checkbox v-model="dialogData.rowData!.keepLocal">
{{ $t('cronjob.saveLocal') }}
</el-checkbox>
</el-form-item>
<el-form-item :label="$t('cronjob.retainCopies')" prop="retainCopies">
<el-input-number
:min="1"
:max="30"
v-model.number="dialogData.rowData!.retainCopies"
></el-input-number>
</el-form-item>
</div>
<el-form-item v-if="dialogData.rowData!.type === 'curl'" :label="$t('cronjob.url')" prop="url">
<el-input style="width: 100%" clearable v-model.trim="dialogData.rowData!.url" />
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type === 'website' || dialogData.rowData!.type === 'directory'"
:label="$t('cronjob.exclusionRules')"
prop="exclusionRules"
>
<el-input
style="width: 100%"
type="textarea"
:placeholder="$t('cronjob.rulesHelper')"
:autosize="{ minRows: 3, maxRows: 6 }"
clearable
v-model="dialogData.rowData!.exclusionRules"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">

View File

@ -2,16 +2,14 @@
<div>
<el-drawer v-model="backupVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
<template #header>
<div class="card-header">
<span>{{ $t('database.backup') }} - {{ dbName }}</span>
</div>
<DrawerHeader :header="$t('database.backup')" :resource="dbName" :back="handleClose" />
</template>
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" @search="search" :data="data">
<template #toolbar>
<el-button type="primary" @click="onBackup()">
{{ $t('database.backup') }}
</el-button>
<el-button type="danger" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>
@ -64,6 +62,9 @@ const acceptParams = (params: DialogProps): void => {
backupVisiable.value = true;
search();
};
const handleClose = () => {
backupVisiable.value = false;
};
const search = async () => {
let params = {

View File

@ -1,43 +1,45 @@
<template>
<el-drawer v-model="createVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
<template #header>
<div class="card-header">
<span>{{ $t('database.create') }}</span>
</div>
<DrawerHeader :header="$t('database.create')" :back="handleClose" />
</template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item :label="$t('commons.table.name')" prop="name">
<el-input clearable v-model.trim="form.name">
<template #append>
<el-select v-model="form.format" style="width: 80px">
<el-option label="utf8mb4" value="utf8mb4" />
<el-option label="utf-8" value="utf8" />
<el-option label="gbk" value="gbk" />
<el-option label="big5" value="big5" />
</el-select>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('commons.login.username')" prop="username">
<el-input clearable v-model.trim="form.username" />
</el-form-item>
<el-form-item :label="$t('commons.login.password')" prop="password">
<el-input type="password" clearable show-password v-model.trim="form.password" />
</el-form-item>
<el-form ref="formRef" label-position="top" :model="form" :rules="rules" label-width="80px">
<el-row type="flex" justify="center">
<el-col :span="22">
<el-form-item :label="$t('commons.table.name')" prop="name">
<el-input clearable v-model.trim="form.name">
<template #append>
<el-select v-model="form.format" style="width: 120px">
<el-option label="utf8mb4" value="utf8mb4" />
<el-option label="utf-8" value="utf8" />
<el-option label="gbk" value="gbk" />
<el-option label="big5" value="big5" />
</el-select>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('commons.login.username')" prop="username">
<el-input clearable v-model.trim="form.username" />
</el-form-item>
<el-form-item :label="$t('commons.login.password')" prop="password">
<el-input type="password" clearable show-password v-model.trim="form.password" />
</el-form-item>
<el-form-item :label="$t('database.permission')" prop="permission">
<el-select v-model="form.permission">
<el-option value="localhost" :label="$t('database.permissionLocal')" />
<el-option value="%" :label="$t('database.permissionAll')" />
<el-option value="ip" :label="$t('database.permissionForIP')" />
</el-select>
</el-form-item>
<el-form-item v-if="form.permission === 'ip'" prop="permissionIPs">
<el-input clearable v-model="form.permissionIPs" />
</el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description">
<el-input type="textarea" clearable v-model="form.description" />
</el-form-item>
<el-form-item :label="$t('database.permission')" prop="permission">
<el-select v-model="form.permission">
<el-option value="localhost" :label="$t('database.permissionLocal')" />
<el-option value="%" :label="$t('database.permissionAll')" />
<el-option value="ip" :label="$t('database.permissionForIP')" />
</el-select>
</el-form-item>
<el-form-item v-if="form.permission === 'ip'" prop="permissionIPs">
<el-input clearable v-model="form.permissionIPs" />
</el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description">
<el-input type="textarea" clearable v-model="form.description" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
@ -92,6 +94,9 @@ const acceptParams = (params: DialogProps): void => {
form.description = '';
createVisiable.value = true;
};
const handleClose = () => {
createVisiable.value = false;
};
const emit = defineEmits<{ (e: 'search'): void }>();
const onSubmit = async (formEl: FormInstance | undefined) => {

View File

@ -1,6 +1,6 @@
<template>
<div v-loading="loading">
<LayoutContent :title="'Mysql ' + $t('menu.database')">
<LayoutContent :title="'Mysql ' + $t('menu.database')" :class="{ mask: mysqlStatus != 'Running' }">
<template #app>
<AppStatus
:app-key="'mysql'"
@ -82,15 +82,17 @@
fix
/>
</ComplexTable>
<el-card
width="30%"
v-if="mysqlStatus != 'Running' && !isOnSetting && mysqlIsExist && !loading"
class="mask-prompt"
>
<span style="font-size: 14px">{{ $t('commons.service.serviceNotStarted', ['Mysql']) }}</span>
</el-card>
</template>
</LayoutContent>
<el-card
width="30%"
v-if="mysqlStatus != 'Running' && !isOnSetting && mysqlIsExist && !loading"
class="mask-prompt"
>
<span style="font-size: 14px">{{ $t('commons.service.serviceNotStarted', ['Mysql']) }}</span>
</el-card>
<Setting ref="settingRef" style="margin-top: 20px" />
<el-dialog v-model="changeVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="30%">
<template #header>

View File

@ -1,6 +1,6 @@
<template>
<div v-show="onSetting">
<LayoutContent :title="$t('nginx.nginxConfig')" :reload="true">
<LayoutContent :title="'Mysql ' + $t('database.setting')" :reload="true">
<template #buttons>
<el-button type="primary" :plain="activeName !== 'conf'" @click="changeTab('conf')">
{{ $t('database.confChange') }}
@ -33,7 +33,7 @@
placeholder="None data"
:indent-with-tab="true"
:tabSize="4"
style="margin-top: 10px; height: calc(100vh - 360px)"
style="margin-top: 10px; height: calc(100vh - 375px)"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"

View File

@ -1,12 +1,12 @@
<template>
<div v-loading="loading">
<span style="float: left">{{ $t('database.longQueryTime') }}</span>
<span style="float: left; line-height: 30px">{{ $t('database.longQueryTime') }}</span>
<div style="margin-left: 5px; float: left">
<el-input type="number" v-model.number="variables.long_query_time">
<template #append>{{ $t('database.second') }}</template>
</el-input>
</div>
<span style="float: left; margin-left: 20px">{{ $t('database.isOn') }}</span>
<span style="float: left; margin-left: 20px; line-height: 30px">{{ $t('database.isOn') }}</span>
<el-switch
style="margin-left: 5px; float: left"
v-model="variables.slow_query_log"
@ -25,7 +25,7 @@
placeholder="None data"
:indent-with-tab="true"
:tabSize="4"
style="margin-top: 10px; height: calc(100vh - 370px)"
style="margin-top: 10px; height: calc(100vh - 392px)"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"

View File

@ -2,9 +2,7 @@
<div>
<el-drawer v-model="upVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
<template #header>
<div class="card-header">
<span>{{ $t('commons.button.import') }}</span>
</div>
<DrawerHeader :header="$t('commons.button.import')" :back="handleClose" />
</template>
<el-upload
ref="uploadRef"
@ -31,7 +29,6 @@
<template #toolbar>
<el-button
style="margin-left: 10px"
type="danger"
plain
:disabled="selects.length === 0"
@click="onBatchDelete(null)"

View File

@ -1,6 +1,7 @@
<template>
<div v-loading="loading">
<AppStatus
:class="{ mask: redisStatus != 'Running' }"
:app-key="'redis'"
style="margin-top: 20px"
@before="onBefore"
@ -8,18 +9,26 @@
@is-exist="checkExist"
></AppStatus>
<LayoutContent v-show="!isOnSetting && redisIsExist" :title="'Redis ' + $t('menu.database')">
<LayoutContent
v-show="!isOnSetting && redisIsExist"
:title="'Redis ' + $t('menu.database')"
:class="{ mask: redisStatus != 'Running' }"
>
<template #toolbar v-if="!isOnSetting && redisIsExist">
<el-button type="primary" plain @click="goDashboard" icon="Position">Redis-Commander</el-button>
<el-button plain @click="onChangePassword">
<el-button type="primary" plain @click="onChangePassword">
{{ $t('database.changePassword') }}
</el-button>
</template>
<template #main>
<Terminal :key="isRefresh" style="margin-top: 10px" ref="terminalRef" />
<Terminal :key="isRefresh" ref="terminalRef" />
</template>
</LayoutContent>
<el-card width="30%" v-if="redisStatus != 'Running' && !isOnSetting && redisIsExist" class="mask-prompt">
<span style="font-size: 14px">{{ $t('commons.service.serviceNotStarted', ['Redis']) }}</span>
</el-card>
<Setting ref="settingRef" style="margin-top: 30px" />
<Password ref="passwordRef" @check-exist="initTerminal" @close-terminal="closeTerminal(true)" />
<el-dialog

View File

@ -1,6 +1,6 @@
<template>
<div v-show="settingShow">
<LayoutContent :title="$t('nginx.nginxConfig')" :reload="true">
<LayoutContent :title="'Redis' + $t('database.setting')" :reload="true">
<template #buttons>
<el-button type="primary" :plain="activeName !== 'conf'" @click="changeTab('conf')">
{{ $t('database.confChange') }}
@ -40,7 +40,7 @@
placeholder="None data"
:indent-with-tab="true"
:tabSize="4"
style="margin-top: 10px; height: calc(100vh - 370px)"
style="margin-top: 10px; height: calc(100vh - 380px)"
:lineWrapping="true"
:matchBrackets="true"
theme="cobalt"

View File

@ -87,7 +87,7 @@
>
<template #toolbar>
<el-button type="primary" @click="onBackup">{{ $t('setting.backup') }}</el-button>
<el-button type="danger" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>

View File

@ -3,7 +3,7 @@
<el-row>
<el-col :span="1"><br /></el-col>
<el-col :span="12">
<table style="margin-top: 20px; width: 100%" class="myTable">
<table style="width: 100%" class="myTable">
<tr>
<td>uptime_in_days</td>
<td>{{ redisStatus!.uptime_in_days }}</td>

View File

@ -1,6 +1,6 @@
<template>
<div v-show="terminalShow" style="height: 100%">
<div style="height: calc(100vh - 360px)" :id="'terminal-exec'"></div>
<div style="height: calc(100vh - 370px)" :id="'terminal-exec'"></div>
</div>
</template>

View File

@ -3,7 +3,7 @@
<RouterButton
:buttons="[
{
label: i18n.global.t('menu.monitor'),
label: i18n.global.t('menu.home'),
path: '/home/index',
},
]"

View File

@ -5,7 +5,7 @@
<el-button type="primary" @click="onCreate()">
{{ $t('commons.button.create') }}{{ $t('terminal.quickCommand') }}
</el-button>
<el-button plain :disabled="selects.length === 0" @click="batchDelete(null)">
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>
@ -28,7 +28,7 @@
</ComplexTable>
</template>
</LayoutContent>
<el-drawer v-model="cmdVisiable" size="50%">
<el-drawer v-model="cmdVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
<template #header>
<DrawerHeader
:header="$t('commons.button.' + operate) + $t('terminal.quickCommand')"

View File

@ -1,6 +1,6 @@
<template>
<div>
<el-drawer v-model="dialogVisiable" size="50%">
<el-drawer v-model="dialogVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
<template #header>
<DrawerHeader :header="$t('terminal.addHost')" :back="handleClose" />
</template>

View File

@ -1,6 +1,6 @@
<template>
<div>
<LayoutContent :title="$t('setting.backup')" :divider="true">
<LayoutContent :title="$t('setting.backup')">
<template #main>
<el-form label-position="left" label-width="130px" :v-key="reflash">
<el-row :gutter="20">

View File

@ -3,99 +3,118 @@
<template #header>
<DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" />
</template>
<el-form ref="formRef" v-loading="loading" :model="dialogData.rowData" label-width="120px">
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
<span>{{ dialogData.rowData!.type }}</span>
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type === 'LOCAL'"
:label="$t('setting.currentPath')"
prop="varsJson['dir']"
:rules="Rules.requiredInput"
>
<el-input disabled v-model="dialogData.rowData!.varsJson['dir']">
<template #append>
<FileList @choose="loadDir" :dir="true"></FileList>
</template>
</el-input>
</el-form-item>
<el-form-item
v-if="hasBucket(dialogData.rowData!.type)"
label="Access Key ID"
prop="accessKey"
:rules="Rules.requiredInput"
>
<el-input v-model.trim="dialogData.rowData!.accessKey" />
</el-form-item>
<el-form-item
v-if="hasBucket(dialogData.rowData!.type)"
label="Secret Key"
prop="credential"
:rules="Rules.requiredInput"
>
<el-input show-password clearable v-model.trim="dialogData.rowData!.credential" />
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type === 'S3'"
label="Region"
prop="varsJson.region"
:rules="Rules.requiredInput"
>
<el-input v-model.trim="dialogData.rowData!.varsJson['region']" />
</el-form-item>
<el-form-item
v-if="hasBucket(dialogData.rowData!.type) && dialogData.rowData!.type !== 'MINIO'"
label="Endpoint"
prop="varsJson.endpoint"
:rules="Rules.requiredInput"
>
<el-input v-model.trim="dialogData.rowData!.varsJson['endpoint']" />
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type === 'MINIO'"
label="Endpoint"
prop="varsJson.endpointItem"
:rules="Rules.requiredInput"
>
<el-input v-model="dialogData.rowData!.varsJson['endpointItem']">
<template #prepend>
<el-select v-model.trim="endpoints" style="width: 80px">
<el-option label="http" value="http" />
<el-option label="https" value="https" />
<el-form ref="formRef" v-loading="loading" label-position="top" :model="dialogData.rowData" label-width="120px">
<el-row type="flex" justify="center">
<el-col :span="22">
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
<div style="margin-left: 10px">
<el-tag>{{ dialogData.rowData!.type }}</el-tag>
</div>
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type === 'LOCAL'"
:label="$t('setting.currentPath')"
prop="varsJson['dir']"
:rules="Rules.requiredInput"
>
<el-input disabled v-model="dialogData.rowData!.varsJson['dir']">
<template #append>
<FileList @choose="loadDir" :dir="true"></FileList>
</template>
</el-input>
</el-form-item>
<el-form-item
v-if="hasBucket(dialogData.rowData!.type)"
label="Access Key ID"
prop="accessKey"
:rules="Rules.requiredInput"
>
<el-input v-model.trim="dialogData.rowData!.accessKey" />
</el-form-item>
<el-form-item
v-if="hasBucket(dialogData.rowData!.type)"
label="Secret Key"
prop="credential"
:rules="Rules.requiredInput"
>
<el-input show-password clearable v-model.trim="dialogData.rowData!.credential" />
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type === 'S3'"
label="Region"
prop="varsJson.region"
:rules="Rules.requiredInput"
>
<el-input v-model.trim="dialogData.rowData!.varsJson['region']" />
</el-form-item>
<el-form-item
v-if="hasBucket(dialogData.rowData!.type) && dialogData.rowData!.type !== 'MINIO'"
label="Endpoint"
prop="varsJson.endpoint"
:rules="Rules.requiredInput"
>
<el-input v-model.trim="dialogData.rowData!.varsJson['endpoint']" />
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type === 'MINIO'"
label="Endpoint"
prop="varsJson.endpointItem"
:rules="Rules.requiredInput"
>
<el-input v-model="dialogData.rowData!.varsJson['endpointItem']">
<template #prepend>
<el-select v-model.trim="endpoints" style="width: 80px">
<el-option label="http" value="http" />
<el-option label="https" value="https" />
</el-select>
</template>
</el-input>
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type !== '' && hasBucket(dialogData.rowData!.type)"
label="Bucket"
prop="bucket"
:rules="Rules.requiredSelect"
>
<el-select style="width: 80%" v-model="dialogData.rowData!.bucket">
<el-option v-for="item in buckets" :key="item" :value="item" />
</el-select>
</template>
</el-input>
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type !== '' && hasBucket(dialogData.rowData!.type)"
label="Bucket"
prop="bucket"
:rules="Rules.requiredSelect"
>
<el-select style="width: 80%" v-model="dialogData.rowData!.bucket">
<el-option v-for="item in buckets" :key="item" :value="item" />
</el-select>
<el-button style="width: 20%" plain @click="getBuckets">
{{ $t('setting.loadBucket') }}
</el-button>
</el-form-item>
<div v-if="dialogData.rowData!.type === 'SFTP'">
<el-form-item :label="$t('setting.address')" prop="varsJson.address" :rules="Rules.requiredInput">
<el-input v-model.trim="dialogData.rowData!.varsJson['address']" />
</el-form-item>
<el-form-item :label="$t('setting.port')" prop="varsJson.port" :rules="[Rules.number]">
<el-input-number :min="0" :max="65535" v-model.number="dialogData.rowData!.varsJson['port']" />
</el-form-item>
<el-form-item :label="$t('setting.username')" prop="accessKey" :rules="[Rules.requiredInput]">
<el-input v-model="dialogData.rowData!.accessKey" />
</el-form-item>
<el-form-item :label="$t('setting.password')" prop="credential" :rules="[Rules.requiredInput]">
<el-input type="password" clearable show-password v-model="dialogData.rowData!.credential" />
</el-form-item>
<el-form-item :label="$t('setting.path')" prop="bucket">
<el-input v-model="dialogData.rowData!.bucket" />
</el-form-item>
</div>
<el-button style="width: 20%" plain @click="getBuckets">
{{ $t('setting.loadBucket') }}
</el-button>
</el-form-item>
<div v-if="dialogData.rowData!.type === 'SFTP'">
<el-form-item
:label="$t('setting.address')"
prop="varsJson.address"
:rules="Rules.requiredInput"
>
<el-input v-model.trim="dialogData.rowData!.varsJson['address']" />
</el-form-item>
<el-form-item :label="$t('setting.port')" prop="varsJson.port" :rules="[Rules.number]">
<el-input-number
:min="0"
:max="65535"
v-model.number="dialogData.rowData!.varsJson['port']"
/>
</el-form-item>
<el-form-item :label="$t('setting.username')" prop="accessKey" :rules="[Rules.requiredInput]">
<el-input v-model="dialogData.rowData!.accessKey" />
</el-form-item>
<el-form-item :label="$t('setting.password')" prop="credential" :rules="[Rules.requiredInput]">
<el-input
type="password"
clearable
show-password
v-model="dialogData.rowData!.credential"
/>
</el-form-item>
<el-form-item :label="$t('setting.path')" prop="bucket">
<el-input v-model="dialogData.rowData!.bucket" />
</el-form-item>
</div>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">

View File

@ -31,36 +31,6 @@
</template>
</el-input>
</el-form-item>
<!-- <el-form-item :label="$t('setting.panelPort')" :rules="Rules.port" prop="serverPort">
<el-input clearable v-model.number="form.serverPort">
<template #append>
<el-button
@click="onSavePort(panelFormRef, 'ServerPort', form.serverPort)"
icon="Collection"
>
{{ $t('commons.button.save') }}
</el-button>
</template>
</el-input>
</el-form-item> -->
<el-form-item :label="$t('setting.theme')" :rules="Rules.requiredSelect" prop="theme">
<el-radio-group
@change="onSave(panelFormRef, 'Theme', form.theme)"
v-model="form.theme"
>
<el-radio-button label="light">
<el-icon><Sunny /></el-icon>
{{ $t('setting.light') }}
</el-radio-button>
<el-radio-button label="dark">
<el-icon><Moon /></el-icon>
{{ $t('setting.dark') }}
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('setting.language')" :rules="Rules.requiredSelect" prop="language">
<el-radio-group
style="width: 100%"
@ -70,11 +40,6 @@
<el-radio label="zh">中文</el-radio>
<el-radio label="en">English</el-radio>
</el-radio-group>
<div>
<span class="input-help">
{{ $t('setting.languageHelper') }}
</span>
</div>
</el-form-item>
<el-form-item

View File

@ -1,6 +1,14 @@
<template>
<div>
<LayoutContent v-loading="loading" v-if="!isRecordShow" :title="$t('setting.snapshot')" :divider="true">
<LayoutContent v-loading="loading" v-if="!isRecordShow" :title="$t('setting.snapshot')">
<template #toolbar>
<el-button type="primary" @click="onCreate()">
{{ $t('setting.createSnapshot') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>
<template #main>
<ComplexTable
:pagination-config="paginationConfig"
@ -9,14 +17,6 @@
style="margin-top: 20px"
@search="search"
>
<template #toolbar>
<el-button type="primary" icon="Plus" @click="onCreate()">
{{ $t('setting.createSnapshot') }}
</el-button>
<el-button type="danger" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>
<el-table-column type="selection" fix />
<el-table-column
show-overflow-tooltip
@ -72,20 +72,31 @@
<template #header>
<DrawerHeader :header="$t('setting.createSnapshot')" :back="handleClose" />
</template>
<el-form v-loading="loading" ref="snapRef" label-width="100px" :model="snapInfo" :rules="rules">
<el-form-item :label="$t('cronjob.target')" prop="from">
<el-select v-model="snapInfo.from" clearable>
<el-option
v-for="item in backupOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description">
<el-input type="textarea" clearable v-model="snapInfo.description" />
</el-form-item>
<el-form
v-loading="loading"
label-position="top"
ref="snapRef"
label-width="100px"
:model="snapInfo"
:rules="rules"
>
<el-row type="flex" justify="center">
<el-col :span="22">
<el-form-item :label="$t('cronjob.target')" prop="from">
<el-select v-model="snapInfo.from" clearable>
<el-option
v-for="item in backupOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description">
<el-input type="textarea" clearable v-model="snapInfo.description" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">