添加通道设置,运维设置,apps设置

jcbranch
fanluyan 11 months ago
parent df8d69b1bd
commit f509d6075c

@ -0,0 +1,555 @@
<template>
<div class="appsetBox">
<!-- cmdid -->
<div class="cmdMsg">
<div class="cmdLeft">
<h4>CMDID</h4>
<el-input v-model="appForm.CMDID" size="mini"></el-input>
</div>
<div class="cmdRight">
<h4>通道数</h4>
<el-input v-model="appForm.channels" size="mini"></el-input>
</div>
</div>
<el-divider></el-divider>
<!-- serve -->
<div class="cmdMsg">
<div class="cmdLeft">
<h4>Server</h4>
<el-input v-model="appForm.server" size="mini"></el-input>
</div>
<div class="cmdRight portRight">
<h4>Port</h4>
<el-input v-model="appForm.port" size="mini"></el-input>
</div>
<div class="gropBtn">
<el-button type="primary" size="mini" @click="dellClick"
>DELL主站</el-button
>
<el-button type="primary" size="mini" @click="safeClick"
>安全平台</el-button
>
</div>
</div>
<el-divider></el-divider>
<!-- 网络协议 -->
<div class="cmdMsg">
<div class="cmdLeft">
<h4>网络协议</h4>
<el-select
size="mini"
v-model="appForm.networkProtocol"
placeholder="请选择"
>
<el-option
v-for="item in netWorkoptions"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
<div class="cmdRight protocolRight">
<h4>通信规约</h4>
<el-select
size="mini"
class="proClass"
v-model="appForm.protocol"
placeholder="请选择"
>
<el-option
v-for="item in protocoloptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
{{ item.id }} - {{ item.name }}
</el-option>
</el-select>
<el-select size="mini" class="mmClass" v-model="appForm.encryption">
<el-option
v-for="item in IsMMoptions"
:key="item.id"
:label="item.name"
:value="item.id"
>
{{ item.id }} - {{ item.name }}
</el-option>
</el-select>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg">
<div class="cmdLeft heartClass">
<h4>心跳周期</h4>
<el-input v-model="appForm.heartbeat" size="mini"></el-input>
<b>分钟默认10分钟</b>
</div>
<div class="cmdRight qualityClass">
<h4>图片质量</h4>
<el-input v-model="appForm.quality" size="mini"></el-input>
<b>可在通道配置中定义各自不同的照片压缩率</b>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg">
<div class="cmdLeft">
<h4>工作状态报周期</h4>
<el-select
size="mini"
v-model="appForm.workStatusTimes"
placeholder="请选择"
>
<el-option
v-for="item in workStausoptions"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
<div class="cmdRight">
<h4>分包大小</h4>
<el-input v-model="appForm.packetSize" size="mini"></el-input>
<b>字节默认2K1KB=1024B</b>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg">
<div class="cmdLeft packaClass">
<h4>起始包号 照片</h4>
<el-input v-model="appForm.packetBase" size="mini"></el-input>
<b>0/1默认为1</b>
</div>
<div class="cmdRight">
<h4>升级</h4>
<el-input v-model="appForm.upgradePacketBase" size="mini"></el-input>
<b>0/1默认为1</b>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg">
<div class="cmdLeft logClass">
<h4>日志保留</h4>
<el-input v-model="appForm.timeForKeepingLogs" size="mini"></el-input>
<b>默认15天</b>
</div>
<div class="cmdRight">
<h4>照片保留</h4>
<el-input v-model="appForm.timeForKeepingPhotos" size="mini"></el-input>
<b>默认15天</b>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg">
<div class="cmdLeft">
<h4>被监测装置</h4>
<el-input v-model="appForm.componentId" size="mini"></el-input>
</div>
<div class="cmdRight">
<el-checkbox v-model="appForm.postDataPaused"></el-checkbox>
<el-checkbox v-model="appForm.reportFault"></el-checkbox>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg">
<div class="cmdLeft">
<h4>原始编号</h4>
<el-input v-model="appForm.originalId" size="mini"></el-input>
</div>
<div class="cmdRight pwdClass">
<h4>装置密码</h4>
<el-input v-model="appForm.password" size="mini"></el-input>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg">
<div class="cmdLeft">
<h4>装置型号</h4>
<el-input v-model="appForm.model" size="mini"></el-input>
</div>
<div class="cmdRight dateClass">
<h4>生产日期</h4>
<el-date-picker
v-model="appForm.productionDate"
type="date"
value-format="timestamp"
placeholder="选择日期"
>
</el-date-picker>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg">
<div class="cmdLeft">
<h4>生产厂家</h4>
<el-input v-model="appForm.bsManufacturer" size="mini"></el-input>
</div>
<div class="cmdRight deviceClass">
<h4>装置名称</h4>
<el-input v-model="appForm.equipName" size="mini"></el-input>
</div>
</div>
</div>
</template>
<script>
export default {
props: ["terimMsgid"],
data() {
return {
appForm: {
CMDID: "", //cmdid
channels: "", //
server: "", //
port: "", //
networkProtocol: "", //
protocol: "", //
encryption: "", //
heartbeat: "", //
quality: "", //
workStatusTimes: "", //
packetSize: "", //
packetBase: "", // 0/11
upgradePacketBase: "", //0/11
timeForKeepingLogs: "", //15
timeForKeepingPhotos: "", //15
componentId: "", //
postDataPaused: false, //
reportFault: false, //
originalId: "", //
password: "", //
model: "", //
productionDate: "", //
bsManufacturer: "", //
equipName: "", //
},
originalAppForm: {}, // appForm
//
netWorkoptions: [
{
value: 0,
label: "tcp",
},
{
value: 1,
label: "udp",
},
],
//
protocoloptions: [
{
id: 2,
name: "南网",
},
{
id: 65280,
name: "国网I1",
},
{
id: 65281,
name: "安徽",
},
{
id: 65282,
name: "江苏",
},
{
id: 65283,
name: "湖南",
},
{
id: 65284,
name: "浙江",
},
{
id: 65285,
name: "河南全景",
},
{
id: 65286,
name: "河南郑州",
},
{
id: 65298,
name: "宁夏",
},
{
id: 65290,
name: "河南统一视频v2020",
},
{
id: 65296,
name: "陕西",
},
],
//
IsMMoptions: [
{
id: 0,
name: "安全平台-无",
},
{
id: 1,
name: "安全平台-明文",
},
{
id: 2,
name: "安全平台-加密",
},
],
//
workStausoptions: [
{
value: 1,
label: "每1次心跳",
},
{
value: 2,
label: "每2次心跳",
},
{
value: 3,
label: "每3次心跳",
},
{
value: 4,
label: "每4次心跳",
},
{
value: 5,
label: "每5次心跳",
},
{
value: 6,
label: "每6次心跳",
},
{
value: 7,
label: "每7次心跳",
},
{
value: 8,
label: "每8次心跳",
},
{
value: 9,
label: "每9次心跳",
},
{
value: 10,
label: "每10次心跳",
},
{
value: 11,
label: "每11次心跳",
},
{
value: 12,
label: "每12次心跳",
},
{
value: 13,
label: "每13次心跳",
},
{
value: 14,
label: "每14次心跳",
},
{
value: 15,
label: "每15次心跳",
},
{
value: 16,
label: "每16次心跳",
},
{
value: 17,
label: "每17次心跳",
},
{
value: 18,
label: "每18次心跳",
},
{
value: 19,
label: "每19次心跳",
},
],
};
},
created() {
// channelForm originalChannelForm
this.originalAppForm = JSON.parse(JSON.stringify(this.appForm));
},
computed: {
//
changedChannelFields() {
const changes = {};
for (const key in this.appForm) {
if (
this.appForm.hasOwnProperty(key) &&
this.appForm[key] !== this.originalAppForm[key]
) {
changes[key] = this.appForm[key];
}
}
return changes;
},
},
mounted() {},
methods: {
//DELL
dellClick() {
this.appForm.server = "61.169.135.146";
this.appForm.port = "6891";
},
//
safeClick() {
this.appForm.server = "61.169.135.146";
this.appForm.port = "6892";
},
//
handleConfim() {
console.log(this.appForm);
console.log(this.changedChannelFields); //
const result = [];
for (const [key, value] of Object.entries(this.changedChannelFields)) {
console.log(value);
let type, valueToStore;
if (typeof value === "string") {
//
//
type = 1; //
valueToStore = value;
} else if (typeof value === "number") {
if (Number.isInteger(value)) {
} else {
type = 2; //
}
valueToStore = value;
} else if (typeof value === "boolean") {
type = 0; //
valueToStore = value ? 1 : 0;
}
if (key == "productionDate") {
type = 0; //
valueToStore = value / 1000;
}
if (key == "timeForKeepingLogs") {
type = 0; //
valueToStore = value * 86400;
}
if (key == "timeForKeepingPhotos") {
type = 0; //
valueToStore = value * 86400;
}
result.push({ name: key, value: valueToStore, type: type });
}
console.log(result);
var params = {
action: "upd_cfg",
termIds: [this.terimMsgid.id],
path: " /sdcard/com.xypower.mpapp/data/",
fn: "App.json",
packageName: "com.xypower.mpapp",
configs: result,
};
console.log(params);
console.log(this.$parent.$parent.$parent);
this.$parent.$parent.handleclose();
this.$parent.$parent.$parent.changeIssue(params);
},
},
};
</script>
<style lang="less">
.appsetBox {
max-height: 442px;
overflow: auto;
padding-right: 12px;
.el-divider--horizontal {
margin: 6px 0px;
background-color: #edeaea;
}
h4 {
font-weight: normal;
margin-right: 12px;
width: 100px;
}
b {
font-size: 12px;
margin-left: 4px;
font-weight: normal;
}
.cmdMsg {
display: flex;
align-items: center;
.cmdLeft {
display: flex;
align-items: center;
margin-right: 40px;
.el-input {
width: 220px;
}
}
.cmdRight {
display: flex;
align-items: center;
.el-input {
width: 100px;
}
}
.portRight {
margin-right: 40px;
}
.protocolRight {
.proClass {
margin-right: 12px;
.el-input {
width: 200px;
}
}
.mmClass {
.el-input {
width: 160px;
}
}
}
.heartClass {
.el-input {
width: 108px;
}
}
.qualityClass {
.el-input {
width: 100px;
}
}
.packaClass {
.el-input {
width: 122px;
}
}
.logClass {
.el-input {
width: 132px;
}
}
.pwdClass,
.dateClass,
.deviceClass {
.el-input {
width: 200px;
}
}
}
}
</style>

@ -907,7 +907,11 @@ export default {
type = 1; //
valueToStore = value;
} else if (typeof value === "number") {
type = 0; // JavaScriptnumber
if (Number.isInteger(value)) {
type = 0; //
} else {
type = 2; //
}
valueToStore = value;
} else if (typeof value === "boolean") {
type = 0; //
@ -1030,7 +1034,7 @@ export default {
</script>
<style lang="less">
.channelsetBox {
max-height: 438px;
max-height: 442px;
overflow: auto;
padding-right: 12px;

@ -3,7 +3,7 @@
title="修改配置文件"
:visible.sync="configisShow"
:close-on-click-modal="false"
width="870px"
width="930px"
class="configDialog"
@close="handleclose"
>
@ -31,8 +31,12 @@
<div class="channelClass" v-if="configValue == 1">
<channelSet ref="setChannel_ref" :terimMsgid="terimMsg"></channelSet>
</div>
<div class="mappClass" v-if="configValue == 2">app</div>
<div class="masterClass" v-if="configValue == 3"></div>
<div class="mappClass" v-if="configValue == 2">
<appSet ref="setAPP_ref" :terimMsgid="terimMsg"></appSet>
</div>
<div class="masterClass" v-if="configValue == 3">
<mappSet ref="setMAPP_ref" :terimMsgid="terimMsg"></mappSet>
</div>
</div>
</div>
<div slot="footer" class="dialog-footer">
@ -44,9 +48,11 @@
<script>
import { cmdSendApi } from "@/utils/api/index";
import channelSet from "./channelSet.vue";
import appSet from "./appSet.vue";
import mappSet from "./mappSet.vue";
export default {
props: ["multipleSelection"],
components: { channelSet },
components: { channelSet, appSet, mappSet },
data() {
return {
configisShow: false,
@ -82,6 +88,15 @@ export default {
comfirmClick() {
if (this.configValue == 1) {
this.$refs.setChannel_ref.handleConfim();
return;
}
if (this.configValue == 2) {
this.$refs.setAPP_ref.handleConfim();
return;
}
if (this.configValue == 3) {
this.$refs.setMAPP_ref.handleConfim();
return;
}
},
// //
@ -99,6 +114,7 @@ export default {
//
handleclose() {
this.configisShow = false;
this.configValue = 1;
},
},
};

@ -0,0 +1,427 @@
<template>
<div class="mappsetBox">
<!-- cmdid -->
<div class="modelCheck">
<div class="checkgroup">
<el-checkbox v-model="mappForm.mntnMode"></el-checkbox>
<el-checkbox v-model="mappForm.quickHbMode"></el-checkbox>
<el-checkbox v-model="mappForm.separateNetwork"
>运维使用独立网络SIM卡2</el-checkbox
>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg serveBox">
<div class="cmdLeft">
<h4>Server</h4>
<el-input v-model="mappForm.server" size="mini"></el-input>
</div>
<div class="cmdRight portRight">
<h4>Port</h4>
<el-input v-model="mappForm.port" size="mini"></el-input>
</div>
<div class="gropBtn">
<el-button type="primary" size="mini" @click="dellClick"
>默认主站</el-button
>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg serveBox">
<div class="cmdLeft">
<h4>心跳模式</h4>
<el-select
size="mini"
v-model="mappForm.usingAbsHbTime"
placeholder="请选择"
>
<el-option
v-for="item in hbModelOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg">
<div class="cmdLeft heartClass">
<h4>心跳周期</h4>
<el-input v-model="mappForm.heartbeat" size="mini"></el-input>
<b>分钟默认10分钟</b>
</div>
<div class="cmdRight qualityClass">
<h4>快心跳周期</h4>
<el-input v-model="mappForm.quickHeartbeat" size="mini"></el-input>
<b>默认60分钟</b>
</div>
</div>
<el-divider></el-divider>
<div class="timeBox">
<h4>固定心跳时间</h4>
<div class="timeList">
<span
class="timeMsg"
v-for="(item, index) in timearr"
:key="index"
:class="{ selected: index === selectedIndex }"
@click="selectItem(index)"
>
{{ item }}
</span>
</div>
<div class="btngroup">
<el-button type="primary" @click="addTime"></el-button>
<el-button type="danger" @click="deleteTime"></el-button>
</div>
</div>
<el-divider></el-divider>
<div class="cmdMsg">
<div class="cmdLeft mpappClass">
<h4>保活检测时间</h4>
<el-input v-model="mappForm.mpappMonitorTimeout" size="mini"></el-input>
<b>分钟有效值5-35默认30</b>
</div>
<div class="cmdRight logClass">
<h4>日志保存时间</h4>
<el-input v-model="mappForm.timeForKeepingLogs" size="mini"></el-input>
<b>有效值5-60默认15</b>
</div>
</div>
<div class="timeDialog" v-if="dialogVisible">
<div class="dialogContain">
<div class="head">
<span>输入时间</span>
<span
@click="dialogVisible = false"
class="el-dialog__close el-icon el-icon-close"
></span>
</div>
<div class="timeselectClass">
<h4>选择时间</h4>
<el-time-picker format v-model="timeVal" placeholder="任意时间点">
</el-time-picker>
</div>
<div class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="pushTime"> </el-button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ["terimMsgid"],
data() {
return {
timearr: [], //
timeVal: "", //
selectedIndex: null, // span
secondsArray: [], //
dialogVisible: false,
mappForm: {
mntnMode: false, //
quickHbMode: false, //
separateNetwork: false, //使SIM2
server: "", //Server
port: "", //Port
usingAbsHbTime: "", //
heartbeat: "", //
quickHeartbeat: "", //
absHeartbeats: [], //
mpappMonitorTimeout: "", //
timeForKeepingLogs: "", //
},
hbModelOptions: [
{
value: 1,
label: "每天固定时间",
},
{
value: 2,
label: "周期性时间",
},
],
originalmAppForm: {}, // appForm
};
},
created() {
// channelForm originalChannelForm
this.originalmAppForm = JSON.parse(JSON.stringify(this.mappForm));
},
computed: {
//
changedmappFields() {
const changes = {};
for (const key in this.mappForm) {
if (
this.mappForm.hasOwnProperty(key) &&
this.mappForm[key] !== this.originalmAppForm[key]
) {
changes[key] = this.mappForm[key];
}
}
return changes;
},
},
mounted() {},
methods: {
//DELL
dellClick() {
this.mappForm.server = "61.169.135.146";
this.mappForm.port = "6891";
},
//
addTime() {
this.dialogVisible = true;
},
//
convertToSeconds(timeStr) {
const [hours, minutes, seconds] = timeStr.split(":").map(Number);
return hours * 3600 + minutes * 60 + seconds;
},
//push
pushTime() {
this.dialogVisible = false;
console.log(this.timeVal);
this.timeVal = this.$moment(this.timeVal).format("HH:mm:ss");
if (!this.timearr.includes(this.timeVal)) {
//
this.timearr.push(this.timeVal);
}
console.log(this.timearr);
this.secondsArray = this.timearr.map(this.convertToSeconds);
console.log(this.secondsArray);
},
//
selectItem(index) {
this.selectedIndex = index; //
},
//
deleteTime() {
if (
this.selectedIndex !== null &&
this.timearr[this.selectedIndex] !== undefined
) {
//
this.timearr.splice(this.selectedIndex, 1);
//
this.selectedIndex = null;
//
// this.selectedIndex = this.timearr.length - 1;
}
},
//
handleConfim() {
console.log(this.mappForm);
console.log(this.changedmappFields); //
const result = [];
for (const [key, value] of Object.entries(this.changedmappFields)) {
console.log(value);
let type, valueToStore;
if (typeof value === "string") {
//
//
type = 1; //
valueToStore = value;
} else if (typeof value === "number") {
if (Number.isInteger(value)) {
} else {
type = 2; //
}
valueToStore = value;
} else if (typeof value === "boolean") {
type = 0; //
valueToStore = value ? 1 : 0;
}
if (key == "mpappMonitorTimeout") {
type = 0; //
valueToStore = value * 60000;
}
if (key == "absHeartbeats") {
type = 1; //
valueToStore = this.secondsArray;
}
result.push({ name: key, value: valueToStore, type: type });
}
console.log(result);
var params = {
action: "upd_cfg",
termIds: [this.terimMsgid.id],
path: " /sdcard/com.xypower.mpmaster/data/",
fn: "Master.json",
packageName: "com.xypower.mpmaster",
configs: result,
};
console.log(params);
console.log(this.$parent.$parent.$parent);
this.$parent.$parent.handleclose();
this.$parent.$parent.$parent.changeIssue(params);
},
},
};
</script>
<style lang="less">
.mappsetBox {
max-height: 442px;
overflow: auto;
padding-right: 12px;
.el-divider--horizontal {
margin: 6px 0px;
background-color: #edeaea;
}
h4 {
font-weight: normal;
margin-right: 12px;
width: 100px;
}
b {
font-size: 12px;
margin-left: 4px;
font-weight: normal;
}
.modelCheck {
display: flex;
align-items: center;
}
.cmdMsg {
display: flex;
align-items: center;
.cmdLeft {
display: flex;
align-items: center;
margin-right: 40px;
.el-input {
width: 220px;
}
}
.cmdRight {
display: flex;
align-items: center;
.el-input {
width: 100px;
}
}
.gropBtn {
margin-left: 24px;
}
.heartClass {
.el-input {
width: 108px;
}
}
.qualityClass {
.el-input {
width: 100px;
}
}
.mpappClass {
.el-input {
width: 62px;
}
}
.logClass {
.el-input {
width: 100px;
}
}
}
.timeBox {
display: flex;
.timeList {
width: 290px;
height: 160px;
border: 1px solid #dcdfe6;
margin-right: 12px;
padding: 8px;
display: flex;
flex-direction: column;
overflow: auto;
span {
height: 24px;
line-height: 24px;
cursor: pointer;
padding-left: 8px;
&:hover {
background-color: #169e8c;
color: #fff;
}
}
.selected {
background-color: #169e8c;
color: #fff;
}
}
.btngroup {
display: flex;
flex-direction: column;
.el-button + .el-button {
margin-left: 0px;
margin-top: 12px;
}
}
}
.timeDialog {
position: fixed;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background: rgba(0, 0, 0, 0.5);
z-index: 3000;
.dialogContain {
width: 300px;
//height: 200px;
background: #fcc;
top: 50%;
left: 50%;
position: absolute;
transform: translate(-50%, -50%); /* 完美居中 */
background: #fff;
border-radius: 2px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
box-sizing: border-box;
.head {
display: flex;
padding: 20px;
padding-bottom: 10px;
justify-content: space-between;
span {
line-height: 24px;
font-size: 18px;
color: #303133;
cursor: pointer;
}
.el-dialog__close {
font-size: 26px;
color: #909399;
&:hover {
color: #169e8c;
background: #e2e2e2;
}
}
}
.timeselectClass {
display: flex;
align-items: center;
padding: 12px;
h4 {
width: 80px;
}
}
.dialog-footer {
padding: 20px;
padding-top: 10px;
text-align: right;
box-sizing: border-box;
}
}
}
}
</style>

@ -2079,10 +2079,18 @@ export default {
return;
case 6:
console.log("上传日志");
let logSetparam = JSON.parse(localStorage.getItem("logset"));
if (logSetparam !== null) {
console.log(logSetparam);
} else {
logSetparam = { noSpecData: 0, mTime: 0 };
}
var params = {
action: "yw_cmd_upload_i1_zip_log",
//url: "http://180.166.218.222:40101/upload/",
termIds: this.idArray,
noSpecData: Number(logSetparam.noSpecData),
mTime: Number(logSetparam.mTime),
};
this.changeIssue(params);
return;

@ -51,6 +51,27 @@
>
</div>
</div>
<div class="logSet">
<h4>日志设置</h4>
<div class="logMain">
<div class="top">
<h2>noSpecData</h2>
<el-input
v-model="logset.noSpecData"
placeholder="请输入内容"
></el-input>
<!-- <b>(不上传specdata日志 默认为0)</b> -->
</div>
<div class="bottom">
<h2>mTime</h2>
<el-input v-model="logset.mTime" placeholder="请输入内容"></el-input>
<!-- <b>(日志最后修改时间为多少秒以内 默认为0)</b> -->
</div>
<el-button type="primary" class="savebtn" @click="saveLog"
>保存</el-button
>
</div>
</div>
</div>
</template>
<script>
@ -67,6 +88,11 @@ export default {
dahan: "",
m2m10086: "",
lwwlkj: "",
logset: {
noSpecData: 0,
mTime: 0,
},
};
},
computed: {},
@ -135,6 +161,10 @@ export default {
refresh() {
this.getAuthfn();
},
saveLog() {
localStorage.setItem("logset", JSON.stringify(this.logset));
},
},
};
</script>
@ -164,5 +194,32 @@ export default {
}
}
}
.logSet {
width: 300px;
border: 1px solid #f00;
padding: 12px;
.logMain {
.top,
.bottom {
display: flex;
align-items: center;
h2 {
font-size: 14px;
font-weight: normal;
margin-right: 8px;
text-align: right;
width: 100px;
}
}
.top {
margin-bottom: 20px;
}
.savebtn {
display: flex;
margin-top: 12px;
margin-left: auto;
}
}
}
}
</style>

Loading…
Cancel
Save