NEZ-1778 NEZ-1779 feat: 系统备份 页面开发

This commit is contained in:
zhangxiaolong
2022-04-08 14:09:56 +08:00
parent 76ae65f0cc
commit d287509948
11 changed files with 955 additions and 2 deletions

View File

@@ -0,0 +1,37 @@
.right-box{
.right-box__container{
.container__form{
.el-tabs--card>.el-tabs__header{
.el-tabs__nav{
width: 100%;
> div{
width: 25%;
box-sizing: border-box;
text-align: center;
padding: 0!important;
}
}
}
.el-tabs--card>.el-tabs__header .el-tabs__item.is-active {
color: $--color-primary;
border: 1px solid $--color-primary;
}
.el-tabs--card>.el-tabs__header .el-tabs__item{
border-bottom: 1px solid $--border-color-light ;
}
.el-tabs--card>.el-tabs__content{
display: none;
}
.start_at{
.el-form-item__content{
.el-date-editor:first{
margin-right: 20px;
}
}
}
}
}
}

View File

@@ -0,0 +1,32 @@
.nz-table2 {
.el-table:not(.chart-table) {
.table-operation-items {
display: flex;
justify-content: center;
.table-operation-del {
background: $--button-primary-color;
border: 1px solid #DEDEDE;
border-radius: 2px;
width: 30px;
height: 22px;
}
.table-operation-button {
border: none;
background-color: $--color-primary;
color: $--button-primary-color;
display: flex;
text-align: center;
line-height: 22px;
justify-content: center;
align-items: center;
height: 22px;
width: 130px;
cursor: pointer;
// border-radius: $--button-border-radius;
// outline: none;
}
}
}
}

View File

@@ -33,6 +33,7 @@
@import './common/project/topology.scss'; @import './common/project/topology.scss';
@import './common/project/topologyL5.scss'; @import './common/project/topologyL5.scss';
@import './common/rightBox/asset/assetBox.scss'; @import './common/rightBox/asset/assetBox.scss';
@import './common/rightBox/backupsBox.scss';
@import './common/rightBox/trafficSetting/subBox.scss'; @import './common/rightBox/trafficSetting/subBox.scss';
@import './common/rightBox/trafficSetting/trafficSettingTab.scss'; @import './common/rightBox/trafficSetting/trafficSettingTab.scss';
@import './common/rightBox/addEndpointBox.scss'; @import './common/rightBox/addEndpointBox.scss';
@@ -54,6 +55,7 @@
@import './common/table/alert/alertSilenceTable.scss'; @import './common/table/alert/alertSilenceTable.scss';
@import './common/table/asset/assetTable.scss'; @import './common/table/asset/assetTable.scss';
@import './common/table/settings/userTable.scss'; @import './common/table/settings/userTable.scss';
@import './common/table/settings/backupsTable.scss';
@import './common/table/settings/switchTab.scss'; @import './common/table/settings/switchTab.scss';
@import './common/table/special/endpointQuery.scss'; @import './common/table/special/endpointQuery.scss';
@import './common/globalSearch/globalSearch'; @import './common/globalSearch/globalSearch';
@@ -84,6 +86,7 @@
@import './page/config/about.scss'; @import './page/config/about.scss';
@import './page/config/agent.scss'; @import './page/config/agent.scss';
@import './page/config/assetMeta.scss'; @import './page/config/assetMeta.scss';
@import './page/config/backups.scss';
@import './page/config/mibBrowser.scss'; @import './page/config/mibBrowser.scss';
@import './page/config/operationRecord.scss'; @import './page/config/operationRecord.scss';
@import './page/config/profile.scss'; @import './page/config/profile.scss';

View File

@@ -0,0 +1,39 @@
.system {
padding-top: 40px;
.system-config-form {
padding-bottom: 20px;
.system-title {
font-family: Roboto-Medium;
font-size: 14px;
color: $--license-left-title-color;
letter-spacing: 0;
font-weight: 500;
margin-bottom: -2px;
}
#modelTable {
.main-list {
.main-container {
border: none;
padding: inherit;
.el-table__header-wrapper {
.table-operation-items {
.items-button {
background: $--color-warning;
border-radius: 2px;
width: 98px;
height: 30px;
font-family: PingFangSC-Regular;
font-size: 14px;
color: $--license-left-title-color;
font-weight: 400;
}
}
}
}
}
}
}
}

View File

@@ -367,7 +367,8 @@ export const fromRoute = {
link: 'link', link: 'link',
ipam: 'ipam', ipam: 'ipam',
apiKey: 'apiKey', apiKey: 'apiKey',
chartTemp: 'chartTemp' chartTemp: 'chartTemp',
backups:'backups'
} }
export const chartdatasource = [ export const chartdatasource = [

View File

@@ -0,0 +1,510 @@
<template>
<div
v-clickoutside="{ obj: editBackup, func: esc }"
class="right-box "
>
<div class="right-box__header">
<div class="header__title">{{ editBackup.name }}</div>
<div class="header__operation">
<span v-cancel="{ obj: editBackup, func: esc }"
><i class="nz-icon nz-icon-close"></i
></span>
</div>
</div>
<div class="right-box__container right-box-container__left">
<div class="container__form">
<el-form
:model="editBackup"
:rules="rules"
label-position="top"
label-width="120px"
ref="backupsForm"
>
<el-form-item label="schedule" prop="type">
<el-tabs
v-model="editBackup.type"
@tab-click="datasourceChange"
type="card"
class="backups-info-tab"
>
<el-tab-pane label="One time only" name="1"> </el-tab-pane>
<el-tab-pane label="Daily" name="2"> </el-tab-pane>
<el-tab-pane label="Weekly" name="3"> </el-tab-pane>
<el-tab-pane label="Monthly" name="4"> </el-tab-pane>
</el-tabs>
</el-form-item>
<el-form-item label="Start at" prop="datepicker" v-if="whoshow" class="start_at">
<el-date-picker
v-model="editBackup.datepicker[0]"
type="date"
placeholder="选择日期"
>
</el-date-picker>
<el-time-picker
:value-format="'HH:mm:ss'"
:format="'HH:mm:ss'"
v-model="editBackup.datepicker[1]"
placeholder="选择时间"
>
</el-time-picker>
</el-form-item>
<el-form-item
label="Enable"
prop="status"
class="form-item__switch"
v-if="whoshow !== 2 ? true : false"
>
<el-switch
class="switch"
v-model="editBackup.status"
@change="statusChange"
>
</el-switch>
</el-form-item>
<el-form-item
label="Every day of the months"
prop="checkDays"
v-if="whoshow === 4 ? true : false"
style=""
>
<el-checkbox-group
v-model="editBackup.checkDays"
@change="changeCheck"
>
<el-checkbox-button
v-for="(item, day) in month"
:label="day"
:key="item"
>{{ item }}</el-checkbox-button
>
</el-checkbox-group>
</el-form-item>
<el-form-item
label="Backup Retention"
prop="retention"
v-if="whoshow !== 2 ? true : false"
>
<el-input
maxlength="64"
size="small"
v-model="editBackup.retention"
id="chart-box-title"
@change="inputchange"
></el-input>
</el-form-item>
<el-form-item
label="Week on"
prop="checkDay"
v-if="whoshow === 3 ? true : false"
class="check_box"
>
<el-checkbox-group
v-model="editBackup.checkDay"
@change="changeCheck"
>
<el-checkbox-button
v-for="(day, index) in week"
:label="index"
:key="index"
>{{ week[index] }}</el-checkbox-button
>
</el-checkbox-group>
</el-form-item>
<el-form-item
label="Repeat every"
prop="repeat"
v-if="whoshow === 2 || whoshow === 3 ? true : false"
>
<el-input
v-if="whoshow === 3 ? true : false"
size="small"
v-model="editBackup.repeat"
id="chart-box-title"
@change="inputchange"
>
<template slot="append">week</template>
</el-input>
<el-input
v-if="whoshow === 2 ? true : false"
size="small"
v-model="editBackup.repeat"
id="chart-box-title"
@change="inputchange"
>
<template slot="append">days</template>
</el-input>
</el-form-item>
</el-form>
</div>
</div>
<div class="right-box__footer">
<button
id="asset-edit-cancel"
v-cancel="{ obj: editBackup, func: esc }"
class="footer__btn footer__btn--light"
>
<span>{{ $t("overall.cancel") }}</span>
</button>
<button
id="asset-edit-save"
:class="{ 'footer__btn--disabled': prevent_opt.save }"
:disabled="prevent_opt.save"
class="footer__btn"
@click="save"
>
<span>{{ $t("overall.save") }}</span>
</button>
</div>
</div>
</template>
<script>
import bus from "@/libs/bus";
import { put } from "@/http";
export default {
name: "backupsBox",
props: {
obj: {
type: Object,
},
},
data() {
return {
editBackup: {
status: "",
checkDays: [],
checkDay: [],
timepicker: "",
datepicker: "",
retention: "",
state: "",
schedule: {
repeat: "",
stime: "",
type: "",
nums: [],
},
},
whoshow: "",
activeName: "",
rules: {
type: [
{
required: true,
message: this.$t("validate.required"),
trigger: "change",
},
],
datepicker: [
{
required: true,
message: this.$t("validate.required"),
trigger: "change",
},
],
checkDays: [
{
required: true,
message: this.$t("validate.required"),
trigger: "change",
},
],
retention: [
{
required: true,
message: this.$t("validate.required"),
trigger: ["blur", "change"],
},
],
Status: [
{
required: true,
message: this.$t("validate.required"),
trigger: "change",
},
],
repeat: [
{
required: true,
message: this.$t("validate.required"),
trigger: "blur",
},
],
checkDay: [
{
required: true,
message: this.$t("validate.required"),
trigger: "change",
},
],
},
week: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
month: [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
"Last",
],
};
},
components: {},
computed: {},
beforeMount() {},
mounted() {
},
methods: {
changeCheck(item) {
if (this.editBackup.type == 3) {
let nums = [];
this.editBackup.nums = [];
for (let i in this.editBackup.checkDay) {
nums.push(Number(this.editBackup.checkDay[i]) + 1);
}
console.log(nums);
this.editBackup.nums = nums;
} else if (this.editBackup.type == 4) {
let nums = [];
this.editBackup.nums = [];
this.editBackup.checkDays.forEach((e, i) => {
if (e === 31) {
nums.push(-1);
} else {
nums.push(Number(this.editBackup.checkDays[i]) + 1);
}
});
console.log(nums);
this.editBackup.nums = nums;
}
this.$forceUpdate();
},
statusChange(item){
this.$forceUpdate();
console.log(item);
if(item){
this.editBackup.state = 1;
this.$emit("statechange", true);
}else{
this.editBackup.state = 0;
this.$emit("statechange", false);
}
},
save() {
console.log(this.editBackup);
this.editBackup.stime = this.editBackup.datepicker.join(" ");
put("/sys/backup", {
state: Number(this.editBackup.state),
schedule: {
type: Number(this.editBackup.type),
stime: this.editBackup.stime,
repeat: Number(this.editBackup.repeat),
nums: this.editBackup.nums,
},
retention: Number(this.editBackup.retention),
}).then((res) => {
if (res.code === 200) {
this.esc(true);
}
});
},
inputchange(n) {
this.$forceUpdate();
},
datasourceChange(tab) {
console.log(tab.name);
switch (tab.name) {
case "2":
this.whoshow = 2;
break;
case "1":
this.whoshow = 1;
break;
case "3":
this.whoshow = 3;
break;
case "4":
this.whoshow = 4;
break;
}
console.log(this.whoshow);
console.log(this.editBackup);
this.$forceUpdate();
},
clickOutside() {
this.esc(false);
},
/* 关闭弹框 */
esc(refresh) {
this.$emit("close", refresh);
},
},
watch: {
obj: {
deep: true,
immediate: true,
handler(n) {
// debugger
console.log(n);
this.editBackup = JSON.parse(JSON.stringify(n));
this.editBackup.checkDay = [];
this.editBackup.checkDays = [];
this.editBackup.type = this.editBackup.type + "";
let stime = this.editBackup.stime;
let time = stime.split(" ");
this.$set(this.editBackup, "datepicker", time);
console.log("obj", this.editBackup);
if (this.editBackup.state == 1) {
this.editBackup.status = true;
this.$emit("statechange", true);
} else {
this.editBackup.status = false;
this.$emit("statechange", false);
}
switch (this.editBackup.type) {
case "1":
this.activeName = "1";
this.whoshow = 1;
break;
case "2":
this.activeName = "2";
this.whoshow = 2;
break;
case "3":
this.activeName = "3";
this.whoshow = 3;
break;
case "4":
this.activeName = "4";
this.whoshow = 4;
break;
}
let checkdays = [];
this.checkDay = [];
if (this.editBackup.type == 3) {
this.editBackup.nums.forEach((e) => {
checkdays.push(e - 1);
if (e === -1) {
checkdays.push(6);
}
});
// for (let i in checkdays) {
// this.checkDay.push(this.week[i]);
// }
this.$set(this.editBackup, "checkDay", checkdays);
// this.editBackup.checkDay = checkdays
} else if (this.editBackup.type == 4) {
this.editBackup.nums.forEach((e) => {
if (e === -1) {
checkdays.push(31);
} else {
checkdays.push(e - 1);
}
});
this.$set(this.editBackup, "checkDays", checkdays);
}
console.log("editBackupNow", this.editBackup);
// this.$nextTick(() => {
// this.$forceUpdate();
// });
this.$forceUpdate();
},
},
"editBackup.status": {
deep: true,
handler(n) {
console.log(n);
if (n) {
this.editBackup.state = 1;
this.editBackup.status = n;
this.$emit("statechange", true);
} else {
this.editBackup.state = 0;
this.editBackup.status = n;
this.$emit("statechange", false);
}
},
},
"editBackup.checkDay": {
deep: true,
handler(n) {
console.log(n);
n.forEach((e, i) => {
if (e === 6) {
this.editBackup.checkDay[i] = -1;
}
});
let nums = [];
this.editBackup.nums = [];
this.editBackup.checkDay.forEach((e, i) => {
nums.push(Number(i) + 1);
});
this.editBackup.nums = nums;
console.log("checkDay", this.editBackup.checkDay);
},
},
"editBackup.datepicker": {
deep: true,
handler(n) {
this.editBackup.datepicker[0] = bus.timeFormate(
new Date(n[0]),
"YYYY-MM-DD"
);
},
},
// "editBackup.checkDays": {
// deep: true,
// handler(n) {
// n.forEach((e, i) => {
// if (e === 31) {
// this.editBackup.checkDays[i] = -2;
// }
// });
// console.log("checkDays", this.editBackup.checkDays);
// },
// },
},
};
</script>
<style lang='' scoped>
</style>

View File

@@ -642,6 +642,7 @@ export default {
handler (n, o) { handler (n, o) {
this.isEdit = true this.isEdit = true
this.editAlertRule = JSON.parse(JSON.stringify(n)) this.editAlertRule = JSON.parse(JSON.stringify(n))
console.log(this.editAlertRule);
if (this.editAlertRule.id || this.editAlertRule.name) { if (this.editAlertRule.id || this.editAlertRule.name) {
this.expressions = [this.editAlertRule.expr] this.expressions = [this.editAlertRule.expr]
this.showTypeSelect = true // 当 edit 时禁用 type下拉框 this.showTypeSelect = true // 当 edit 时禁用 type下拉框

View File

@@ -0,0 +1,199 @@
<template>
<el-table :data="isConfigurations ? tableData : tableData2" border>
<el-table-column
class="table-column__head"
v-for="(item, index) in customTableTitle"
:key="`col-${index}`"
:label="item.label"
:prop="item.prop"
:resizable="true"
>
<template slot="header">
<span class="data-column__span">{{ item.label }}</span>
<div class="col-resize-area"></div>
</template>
<template slot-scope="scope" :column="item">
<span v-if="item.prop === 'repeat'">
{{ tableData[0].schedule && tableData[0].schedule.repeat }}
</span>
<span v-if="item.prop === 'retention'">
{{ tableData[0].retention }}
</span>
<span v-if="item.prop === 'last'">
{{ tableData[0].schedule && tableData[0].schedule.stime }}
</span>
<span v-if="item.prop === 'state'">
<el-switch class="switch" v-model="switchStatus"> </el-switch>
</span>
<span v-if="item.prop === 'time'">
{{ scope.row.time ? scope.row.time : "-" }}
</span>
<span v-if="item.prop === 'size'">
{{ scope.row.size ? scope.row.size : "" }}
</span>
<span v-if="item.prop === 'fileName'"> {{ scope.row.fileName }} </span>
</template>
</el-table-column>
<el-table-column :resizable="false" fixed="right">
<div
slot-scope="scope"
class="table-operation-items"
v-if="isConfigurations"
>
<button class="table-operation-button" @click="backupNow(scope.row)">
backup now
</button>
<el-dropdown size="medium" trigger="click" @command="tableOperation">
<div class="table-operation-item table-operation-item--more">
<i class="nz-icon nz-icon-more3"></i>
</div>
<el-dropdown-menu
slot="dropdown"
class="right-box-select-top right-public-box-dropdown-top"
>
<el-dropdown-item command="edit"
><i class="nz-icon nz-icon-edit"></i
><span class="operation-dropdown-text">{{
$t("overall.edit")
}}</span></el-dropdown-item
>
<el-dropdown-item @click="tableOperation('del', scope.row)"
><i class="nz-icon nz-icon-delete"></i
><span class="operation-dropdown-text">{{
$t("overall.delete")
}}</span></el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
</div>
<div slot-scope="scope" v-else class="table-operation-items">
<button class="table-operation-button" @click="Restore(scope.row)">
Restore
</button>
<button class="table-operation-del" @click="del(scope.row)">
<i class="nz-icon nz-icon-delete"></i>
</button>
</div>
</el-table-column>
</el-table>
</template>
<script>
import { get, post } from "@/http";
import lodash from "lodash";
import bus from "@/libs/bus";
export default {
name: "backupsTable",
mixins: [],
props: {
loading: Boolean,
customTableTitle: Array,
isConfigurations: Boolean,
isState: Boolean,
},
data() {
return {
switchStatus: true,
tableData: [
{
retention: "",
state: "",
schedule: {
repeat: "",
stime: "",
type: "",
nums: [],
},
},
],
tableData2: [
{
fileName: "",
time: "",
size: "",
},
],
};
},
components: {},
computed: {},
created() {},
mounted() {
this.getTableData();
this.monitoring()
},
methods: {
monitoring(){
this.$on('getData',(res)=>{
console.log('getdata');
this.getTableData()
window.location.reload()
})
},
async getTableData() {
await get("/sys/backup").then((res) => {
if (res.code === 200) {
if (res.data) {
this.tableData[0].retention = res.data.retention;
this.tableData[0].state = res.data.state;
this.switchStatus = res.data.state === 1 ? true : false;
for (let i in res.data.schedule) {
this.tableData[0].schedule[i] = res.data.schedule[i];
}
}
}
});
await post("/sys/backup/list").then((res) => {
if (res.code === 200) {
if (res.data) {
for (let i in res.data) {
this.tableData2[i].fileName = res.data[i].fileName;
this.tableData2[i].size = bus.getNumStr(res.data[i].size);
this.tableData2[i].time = res.data[i].time;
}
}
}
});
},
backupNow(item) {
post("/sys/backup").then((res) => {
console.log(res);
});
},
tableOperation(command) {
if (command) {
if (command === "edit") {
this.$emit("edit", this.tableData[0]);
} else if (command === "del") {
}
}
},
},
watch: {
isState: {
deep: true,
handler(n) {
this.switchStatus = n;
this.tableData[0].state = n === true ? 1 : 0;
},
},
switchStatus:{
deep:true,
handler(n){
this.tableData[0].state = n=== true ? 1 : 0;
}
}
},
};
</script>
<style lang='' scoped>
</style>

View File

@@ -0,0 +1,126 @@
<template>
<div class="system">
<div class="system-config-form">
<div class="system-title">backup configurations</div>
<nz-data-list
ref="dataList"
id="modelTable"
:data="tableData"
border
from="backups"
>
<template v-slot="slotProps">
<backups-table
ref="backupsTable"
:custom-table-title="customTableTitle"
:is-configurations="true"
:is-state ='isState'
@edit="edit"
>
</backups-table>
</template>
</nz-data-list>
</div>
<div class="system-config-form">
<div class="system-title">Recent backup</div>
<nz-data-list
ref="dataList"
id="modelTable"
:data="tableData2"
border
from="backups"
>
<template v-slot="slotProps">
<backups-table
ref="backupsTable"
:custom-table-title="customTableTitle2"
:is-configurations="false"
>
</backups-table>
</template>
</nz-data-list>
</div>
<transition name="right-box">
<backups-box v-if="rightBoxshow" :obj="object" @close="closeRightBox" @statechange='statechange'></backups-box>
</transition>
</div>
</template>
<script>
import nzDataList from "@/components/common/table/nzDataList";
import backupsTable from "@/components/common/table/settings/backupsTable";
import backupsBox from '@/components/common/rightBox/administration/backupsBox'
export default {
name: "backups",
mixins: [],
props: [""],
data() {
return {
url: "/sys/backup/list",
customTableTitle: [
{ label: "Frequency", prop: "repeat" },
{ label: "Backup Retention", prop: "retention" },
{ label: "Last backup at", prop: "last" },
{ label: "Enable", prop: "state" },
],
customTableTitle2: [
{ label: "Date", prop: "time" },
{ label: "File", prop: "fileName" },
{ label: "Size", prop: "size" },
{ label: "Description", prop: "Description" },
],
tableData: [
{
retention: "",
state: "",
schedule: {},
},
],
tableData2: [
{
list: {},
},
],
rightBoxshow:false,
isState:'',
isRefresh:''
};
},
components: { nzDataList, backupsTable,backupsBox },
computed: {},
created() {},
mounted() {},
methods: {
edit(row){
this.object = { ...row }
this.object.name = `Edit backup configurations`
if(this.object.schedule){
for(let i in this.object.schedule){
this.object[i]=this.object.schedule[i]
}
}
this.rightBoxshow = true
},
closeRightBox(refresh){
if(refresh){
this.$refs.backupsTable.$emit('getData')
}
this.rightBoxshow = false
},
statechange(Boolean){
this.isState = Boolean
}
},
watch: {},
};
</script>

View File

@@ -82,6 +82,7 @@ export default {
}, },
methods: { methods: {
edit (row, copyFlag) { edit (row, copyFlag) {
console.log(row,copyFlag);
this.object = { ...row } this.object = { ...row }
if (copyFlag) { if (copyFlag) {
this.object.name = this.object.name + '-copy' this.object.name = this.object.name + '-copy'

View File

@@ -193,7 +193,11 @@ export default new Router({
{ {
path: '/chartTemp', path: '/chartTemp',
component: resolve => require(['../components/page/config/template/chartTemp.vue'], resolve) component: resolve => require(['../components/page/config/template/chartTemp.vue'], resolve)
} },
{
path: '/backup',
component: resolve => require(['../components/page/config/backups.vue'], resolve)
},
] ]
} }
] ]