ssh 禁止命令修护,页面提示tooltip

This commit is contained in:
bwcx_jzy 2021-09-18 11:41:30 +08:00
parent 58091acbb7
commit f40224cdf7
10 changed files with 270 additions and 241 deletions

View File

@ -186,10 +186,16 @@ public class SshModel extends BaseModel {
List<String> commands = StrUtil.split(inputItem, StrUtil.CR);
commands.addAll(StrUtil.split(inputItem, "&"));
for (String s : split) {
//
boolean anyMatch = commands.stream().anyMatch(item -> StrUtil.startWithAny(item, s + StrUtil.SPACE, ("&" + s + StrUtil.SPACE), StrUtil.SPACE + s + StrUtil.SPACE));
if (anyMatch) {
return false;
}
//
anyMatch = commands.stream().anyMatch(item -> StrUtil.equals(item, s));
if (anyMatch) {
return false;
}
}
return true;
}

View File

@ -212,8 +212,28 @@ public class SshHandler extends BaseHandler {
ThreadUtil.execute(this);
}
/**
* 添加到命令队列
*
* @param msg 输入
* @return 当前待确认待所有命令
*/
private String append(String msg) {
char[] x = msg.toCharArray();
if (x.length == 1 && x[0] == 127) {
// 退格键
int length = nowLineInput.length();
if (length > 0) {
nowLineInput.delete(length - 1, length);
}
} else {
nowLineInput.append(msg);
}
return nowLineInput.toString();
}
public boolean checkInput(String msg) {
String allCommand = nowLineInput.append(msg).toString();
String allCommand = this.append(msg);
boolean refuse;
if (StrUtil.equalsAny(msg, StrUtil.CR, StrUtil.TAB)) {
String join = nowLineInput.toString();

View File

@ -5,8 +5,16 @@
<a-button type="primary" @click="loadData">刷新</a-button>
</div>
<!-- 数据表格 -->
<a-table :data-source="list" :loading="loading" :columns="columns" :style="{'max-height': tableHeight + 'px' }" :scroll="{x: 1110, y: tableHeight - 60}"
:pagination="false" bordered :rowKey="(record, index) => index">
<a-table
:data-source="list"
:loading="loading"
:columns="columns"
:style="{ 'max-height': tableHeight + 'px' }"
:scroll="{ x: 1110, y: tableHeight - 60 }"
:pagination="false"
bordered
:rowKey="(record, index) => index"
>
<a-tooltip slot="name" slot-scope="text" placement="topLeft" :title="text">
<span>{{ text }}</span>
</a-tooltip>
@ -50,30 +58,23 @@
</a-select>
</a-form-model-item>
<a-form-model-item label="报警联系人" prop="notifyUser" class="jpom-notify">
<a-transfer
:data-source="userList"
show-search
:filter-option="filterOption"
:target-keys="targetKeys"
:render="item => item.title"
@change="handleChange"
/>
<a-transfer :data-source="userList" show-search :filter-option="filterOption" :target-keys="targetKeys" :render="(item) => item.title" @change="handleChange" />
</a-form-model-item>
</a-form-model>
</a-modal>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import { getMonitorList, editMonitor, deleteMonitor } from '../../api/monitor';
import { getAdminUserList } from '../../api/user';
import { getNodeProjectList } from '../../api/node';
import { parseTime } from '../../utils/time';
import { mapGetters } from "vuex";
import { getMonitorList, editMonitor, deleteMonitor } from "../../api/monitor";
import { getAdminUserList } from "../../api/user";
import { getNodeProjectList } from "../../api/node";
import { parseTime } from "../../utils/time";
export default {
data() {
return {
loading: false,
tableHeight: '70vh',
tableHeight: "70vh",
list: [],
userList: [],
nodeProjectList: [],
@ -84,35 +85,36 @@ export default {
temp: {},
editMonitorVisible: false,
columns: [
{title: '名称', dataIndex: 'name', ellipsis: true, scopedSlots: {customRender: 'name'}, width: 150},
{title: '开启状态', dataIndex: 'status', ellipsis: true, scopedSlots: {customRender: 'status'}, width: 150},
{title: '自动重启', dataIndex: 'autoRestart', ellipsis: true, scopedSlots: {customRender: 'autoRestart'}, width: 150},
{title: '报警状态', dataIndex: 'alarm', ellipsis: true, scopedSlots: {customRender: 'alarm'}, width: 150},
{title: '创建人', dataIndex: 'parent', ellipsis: true, scopedSlots: {customRender: 'parent'}, width: 120},
{title: '修改时间', dataIndex: 'modifyTime', customRender: (text) => {
if (!text || text === '0') {
return '';
{ title: "名称", dataIndex: "name", ellipsis: true, scopedSlots: { customRender: "name" }, width: 150 },
{ title: "开启状态", dataIndex: "status", ellipsis: true, scopedSlots: { customRender: "status" }, width: 150 },
{ title: "自动重启", dataIndex: "autoRestart", ellipsis: true, scopedSlots: { customRender: "autoRestart" }, width: 150 },
{ title: "报警状态", dataIndex: "alarm", ellipsis: true, scopedSlots: { customRender: "alarm" }, width: 150 },
{ title: "创建人", dataIndex: "parent", ellipsis: true, scopedSlots: { customRender: "parent" }, width: 120 },
{
title: "修改时间",
dataIndex: "modifyTime",
customRender: (text) => {
if (!text || text === "0") {
return "";
}
return parseTime(text);
}, width: 180},
{title: '操作', dataIndex: 'operation', ellipsis: true, scopedSlots: {customRender: 'operation'}, width: 200}
},
width: 180,
},
{ title: "操作", dataIndex: "operation", ellipsis: true, scopedSlots: { customRender: "operation" }, width: 200 },
],
rules: {
name: [
{ required: true, message: 'Please input monitor name', trigger: 'blur' }
],
}
}
name: [{ required: true, message: "Please input monitor name", trigger: "blur" }],
},
};
},
computed: {
...mapGetters([
'getGuideFlag'
])
...mapGetters(["getGuideFlag"]),
},
watch: {
getGuideFlag() {
this.introGuide();
}
},
},
created() {
this.calcTableHeight();
@ -124,14 +126,18 @@ export default {
//
introGuide() {
if (this.getGuideFlag) {
this.$introJs().setOptions({
this.$introJs()
.setOptions({
hidePrev: true,
steps: [{
title: 'Jpom 导航助手',
element: document.querySelector('.jpom-notify'),
intro: '如果这里的报警联系人无法选择,说明这里面的管理员没有设置邮箱,在右上角下拉菜单里面的用户资料里可以设置。'
}]
}).start();
steps: [
{
title: "Jpom 导航助手",
element: document.querySelector(".jpom-notify"),
intro: "如果这里的报警联系人无法选择,说明这里面的管理员没有设置邮箱,在右上角下拉菜单里面的用户资料里可以设置。",
},
],
})
.start();
return false;
}
this.$introJs().exit();
@ -139,40 +145,40 @@ export default {
//
calcTableHeight() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - this.$refs['filter'].clientHeight - 135;
})
this.tableHeight = window.innerHeight - this.$refs["filter"].clientHeight - 135;
});
},
//
loadData() {
this.loading = true;
const params = {
nodeId: ''
}
getMonitorList(params).then(res => {
nodeId: "",
};
getMonitorList(params).then((res) => {
if (res.code === 200) {
this.list = res.data;
}
this.loading = false;
})
});
},
//
loadUserList() {
this.userList = [];
getAdminUserList().then(res => {
getAdminUserList().then((res) => {
if (res.code === 200) {
res.data.forEach(element => {
res.data.forEach((element) => {
this.userList.push({ key: element.value, title: element.title, disabled: element.disabled || false });
});
}
})
});
},
//
loadNodeProjectList() {
getNodeProjectList().then(res => {
getNodeProjectList().then((res) => {
if (res.code === 200) {
this.nodeProjectList = res.data;
}
})
});
},
// 穿
filterOption(inputValue, option) {
@ -186,22 +192,22 @@ export default {
handleSelectChange(value) {
this.projectKeys = value;
let projects = [];
this.nodeProjectList.forEach(node => {
this.nodeProjectList.forEach((node) => {
let tempProjects = [];
node.projects.forEach(project => {
this.projectKeys.forEach(element => {
node.projects.forEach((project) => {
this.projectKeys.forEach((element) => {
if (project.id === element) {
tempProjects.push(project.id);
}
})
})
});
});
if (tempProjects.length > 0) {
projects.push({
node: node.id,
projects: tempProjects
})
projects: tempProjects,
});
}
})
});
this.temp.projects = projects;
},
//
@ -211,7 +217,7 @@ export default {
setTimeout(() => {
this.introGuide();
}, 500);
})
});
},
//
handleEdit(record) {
@ -219,63 +225,63 @@ export default {
this.targetKeys = this.temp.notifyUser;
//
this.projectKeys = [];
this.temp.projects.forEach(node => {
node.projects.forEach(project => {
this.temp.projects.forEach((node) => {
node.projects.forEach((project) => {
this.projectKeys.push(project);
})
})
});
});
this.editMonitorVisible = true;
},
handleEditMonitorOk() {
//
this.$refs['editMonitorForm'].validate((valid) => {
this.$refs["editMonitorForm"].validate((valid) => {
if (!valid) {
return false;
}
const params = {
...this.temp,
status: this.temp.status ? 'on' : 'off',
autoRestart: this.temp.autoRestart ? 'on' : 'off',
status: this.temp.status ? "on" : "off",
autoRestart: this.temp.autoRestart ? "on" : "off",
projects: JSON.stringify(this.temp.projects),
notifyUser: JSON.stringify(this.targetKeys)
}
editMonitor(params).then(res => {
notifyUser: JSON.stringify(this.targetKeys),
};
editMonitor(params).then((res) => {
if (res.code === 200) {
//
this.$notification.success({
message: res.msg,
duration: 2
duration: 2,
});
this.$refs['editMonitorForm'].resetFields();
this.$refs["editMonitorForm"].resetFields();
this.editMonitorVisible = false;
this.loadData();
}
})
})
});
});
},
//
handleDelete(record) {
this.$confirm({
title: '系统提示',
content: '真的要删除监控么?',
okText: '确认',
cancelText: '取消',
title: "系统提示",
content: "真的要删除监控么?",
okText: "确认",
cancelText: "取消",
onOk: () => {
//
deleteMonitor(record.id).then((res) => {
if (res.code === 200) {
this.$notification.success({
message: res.msg,
duration: 2
duration: 2,
});
this.loadData();
}
})
}
});
}
}
}
},
});
},
},
};
</script>
<style scoped>
.filter {

View File

@ -17,9 +17,11 @@
<span>{{ text }}</span>
</a-tooltip>
<template slot="operation" slot-scope="text, record">
<a-button type="primary" @click="handleTerminal(record)" :disabled="!record.sshId">终端</a-button>
<a-button type="primary" @click="handleNode(record)" :disabled="record.openStatus === false">节点管理</a-button>
<a-button type="primary" @click="handleEdit(record)">编辑</a-button>
<a-tooltip title="需要到编辑中去为一个节点绑定一个 ssh信息才能启用该功能">
<a-button type="primary" @click="handleTerminal(record)" :disabled="!record.sshId">终端</a-button>
</a-tooltip>
<a-button type="danger" @click="handleDelete(record)">删除</a-button>
</template>
<!-- 嵌套表格 -->

View File

@ -52,7 +52,9 @@
<span>{{ text }}</span>
</a-tooltip>
<template slot="operation" v-if="!record.isDirectory" slot-scope="text, record">
<a-button type="primary" v-if="record.textFileEdit" @click="handleEditFile(record)">编辑</a-button>
<a-tooltip title="需要到 节点管理中的系统管理的白名单配置中配置允许编辑的文件后缀">
<a-button type="primary" :disabled="!record.textFileEdit" @click="handleEditFile(record)">编辑</a-button>
</a-tooltip>
<a-button type="primary" @click="handleDownload(record)">下载</a-button>
<a-button type="danger" @click="handleDelete(record)">删除</a-button>
</template>
@ -164,11 +166,11 @@ export default {
unzip: false,
},
columns: [
{ title: "文件名称", dataIndex: "filename", width: 100, ellipsis: true, scopedSlots: { customRender: "filename" } },
{ title: "文件名称", dataIndex: "filename", ellipsis: true, scopedSlots: { customRender: "filename" } },
{ title: "文件类型", dataIndex: "isDirectory", width: 100, ellipsis: true, scopedSlots: { customRender: "isDirectory" } },
{ title: "文件大小", dataIndex: "fileSize", width: 120, ellipsis: true, scopedSlots: { customRender: "fileSize" } },
{ title: "修改时间", dataIndex: "modifyTime", width: 180, ellipsis: true },
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" } },
{ title: "操作", dataIndex: "operation", width: 260, scopedSlots: { customRender: "operation" } },
],
rules: {
url: [{ required: true, message: "远程下载Url不为空", trigger: "change" }],

View File

@ -35,7 +35,9 @@
<span>{{ text }}</span>
</a-tooltip>
<template slot="operation" slot-scope="text, record">
<a-tooltip title="需要到 ssh 信息中配置允许编辑的文件后缀">
<a-button type="primary" :disabled="!record.textFileEdit" @click="handleEdit(record)">编辑 </a-button>
</a-tooltip>
<!-- <a-button type="primary" :disabled="!record.textFileEdit" @click="handlePreview(record)">跟踪</a-button> -->
<a-button type="primary" @click="handleDownload(record)">下载</a-button>
<a-button type="danger" @click="handleDelete(record)">删除</a-button>
@ -92,11 +94,11 @@ export default {
key: "key",
},
columns: [
{ title: "文件名称", dataIndex: "title", width: 100, ellipsis: true, scopedSlots: { customRender: "name" } },
{ title: "文件名称", dataIndex: "title", ellipsis: true, scopedSlots: { customRender: "name" } },
{ title: "文件类型", dataIndex: "dir", width: 100, ellipsis: true, scopedSlots: { customRender: "dir" } },
{ title: "文件大小", dataIndex: "size", width: 120, ellipsis: true, scopedSlots: { customRender: "size" } },
{ title: "修改时间", dataIndex: "modifyTime", width: 180, ellipsis: true },
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 280 },
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 270 },
],
editFileVisible: false,
};

View File

@ -41,7 +41,7 @@
<a-button type="danger" @click="handleDelete(record)">删除</a-button>
</a-menu-item>
<a-menu-item>
<a-button type="primary" @click="handleViewLog(record)">操作日志</a-button>
<a-button type="primary" @click="handleViewLog(record)">终端日志</a-button>
</a-menu-item>
</a-menu>
</a-dropdown>
@ -83,15 +83,20 @@
<template slot="label">
文件目录
<a-tooltip v-show="temp.type !== 'edit'">
<template slot="title">
绑定指定目录可以在线管理同时构建 ssh 发布目录也需要在此配置
</template>
<template slot="title"> 绑定指定目录可以在线管理同时构建 ssh 发布目录也需要在此配置 </template>
<a-icon type="question-circle" theme="filled" />
</a-tooltip>
</template>
<a-textarea v-model="temp.fileDirs" :auto-size="{ minRows: 3, maxRows: 5 }" placeholder="授权可以直接访问的目录,多个回车换行即可" />
</a-form-model-item>
<a-form-model-item label="禁止命令" prop="notAllowedCommand">
<a-form-model-item prop="notAllowedCommand">
<template slot="label">
禁止命令
<a-tooltip v-show="temp.type !== 'edit'">
<template slot="title"> 限制禁止在在线终端执行的命令 </template>
<a-icon type="question-circle" theme="filled" />
</a-tooltip>
</template>
<a-textarea v-model="temp.notAllowedCommand" :auto-size="{ minRows: 3, maxRows: 5 }" placeholder="禁止命令是不允许在终端执行的名,多个逗号隔开" />
</a-form-model-item>
<a-form-model-item label="文件后缀" prop="suffix">
@ -156,7 +161,7 @@
<terminal v-if="terminalVisible" :sshId="temp.id" />
</a-modal>
<!-- 操作日志 -->
<a-modal v-model="viewOperationLog" title="操作日志" width="60vw" :footer="null" :maskClosable="false">
<a-modal v-model="viewOperationLog" title="操作日志" width="80vw" :footer="null" :maskClosable="false">
<div ref="filter" class="filter">
<a-range-picker class="filter-item" :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" @change="onchangeListLogTime" />
<a-button type="primary" @click="handleListLog">搜索</a-button>

View File

@ -12,14 +12,7 @@
<div class="title">Agent最新版本{{ agentVersion | version }}</div>
<div class="version">打包时间{{ agentTimeStamp | version }}</div>
<div class="action">
<a-upload
name="file"
accept=".jar,.zip"
action=""
:showUploadList="false"
:multiple="false"
:before-upload="beforeUpload"
>
<a-upload name="file" accept=".jar,.zip" action="" :showUploadList="false" :multiple="false" :before-upload="beforeUpload">
<a-button type="primary">
<a-icon type="upload" />
上传新版本
@ -29,17 +22,14 @@
</div>
</div>
<div class="table-div">
<a-table :columns="columns" :data-source="listComputed" bordered rowKey="id" class="table" :pagination="false"
:row-selection="rowSelection">
<a-table :columns="columns" :data-source="listComputed" bordered rowKey="id" class="table" :pagination="false" :row-selection="rowSelection">
<template slot="version" slot-scope="text">
{{ text | version }}
</template>
<template slot="status" slot-scope="text">
<div class="restarting" v-if="text && text.type === 'restarting'">
重启中大约需要30秒
</div>
<div class="restarting" v-if="text && text.type === 'restarting'">重启中大约需要30秒</div>
<div class="uploading" v-if="text && text.type === 'uploading'">
<div class="text">{{ text.percent === 100 ? '上传成功' : '正在上传文件' }}</div>
<div class="text">{{ text.percent === 100 ? "上传成功" : "正在上传文件" }}</div>
<a-progress :percent="text.percent" />
</div>
</template>
@ -52,49 +42,47 @@
</template>
<script>
import {getNodeGroupList, uploadAgentFile} from "@/api/node"
import { getNodeGroupList, uploadAgentFile } from "@/api/node";
import { mapGetters } from "vuex";
export default {
name: "NodeUpdate",
filters: {
version(value) {
return value && value || '未知'
return (value && value) || "未知";
},
status(value) {
return value && value || '未知'
}
return (value && value) || "未知";
},
},
data() {
return {
agentVersion: '',
agentTimeStamp: '',
agentVersion: "",
agentTimeStamp: "",
websocket: null,
groupFilter: undefined,
groupList: [],
list: [],
columns: [
{title: '节点 ID', dataIndex: 'id', ellipsis: true, scopedSlots: {customRender: 'id'}},
{title: '节点名称', dataIndex: 'name', ellipsis: true, scopedSlots: {customRender: 'name'}},
{title: '分组', dataIndex: 'group', ellipsis: true, scopedSlots: {customRender: 'group'}},
{title: 'Agent版本号', dataIndex: 'version', ellipsis: true, scopedSlots: {customRender: 'version'}},
{title: '打包时间', dataIndex: 'timeStamp', ellipsis: true, scopedSlots: {customRender: 'timeStamp'}},
{title: '状态', dataIndex: 'status', ellipsis: true, scopedSlots: {customRender: 'status'}},
{ title: "节点 ID", dataIndex: "id", ellipsis: true, scopedSlots: { customRender: "id" } },
{ title: "节点名称", dataIndex: "name", ellipsis: true, scopedSlots: { customRender: "name" } },
{ title: "分组", dataIndex: "group", ellipsis: true, scopedSlots: { customRender: "group" } },
{ title: "Agent版本号", dataIndex: "version", width: "100", ellipsis: true, scopedSlots: { customRender: "version" } },
{ title: "打包时间", dataIndex: "timeStamp", ellipsis: true, scopedSlots: { customRender: "timeStamp" } },
{ title: "状态", dataIndex: "status", ellipsis: true, scopedSlots: { customRender: "status" } },
// {title: '', dataIndex: 'autoUpdate', ellipsis: true, scopedSlots: {customRender: 'autoUpdate'}},
{title: '操作', dataIndex: 'operation', width: '250px', scopedSlots: {customRender: 'operation'}, align: 'left'}
{ title: "操作", dataIndex: "operation", width: "100", scopedSlots: { customRender: "operation" }, align: "left" },
],
nodeVersion: {},
nodeStatus: {},
tableSelections: []
}
tableSelections: [],
};
},
computed: {
...mapGetters([
'getLongTermToken'
]),
...mapGetters(["getLongTermToken"]),
listComputed() {
const data = []
this.list.forEach(item => {
const data = [];
this.list.forEach((item) => {
if (item.group === this.groupFilter || this.groupFilter === undefined) {
let itemData = this.nodeVersion[item.id];
if (itemData) {
@ -107,94 +95,96 @@ export default {
}
}
item.status = this.nodeStatus[item.id]
data.push(item)
item.status = this.nodeStatus[item.id];
data.push(item);
}
})
return data
});
return data;
},
rowSelection() {
return {
onChange: this.tableSelectionChange,
selectedRowKeys: this.tableSelections
}
selectedRowKeys: this.tableSelections,
};
},
socketUrl() {
const protocol = location.protocol === 'https:' ? 'wss://' : 'ws://';
const protocol = location.protocol === "https:" ? "wss://" : "ws://";
return `${protocol}${location.host}/node_update?userId=${this.getLongTermToken}&nodeId=system&type=nodeUpdate`;
}
},
},
mounted() {
this.initWebsocket()
this.loadGroupList()
this.initWebsocket();
this.loadGroupList();
},
methods: {
initWebsocket() {
if (!this.socket || this.socket.readyState !== this.socket.OPEN || this.socket.readyState !== this.socket.CONNECTING) {
this.socket = new WebSocket(this.socketUrl)
this.socket = new WebSocket(this.socketUrl);
}
this.socket.onopen = () => {
this.init()
}
this.init();
};
this.socket.onmessage = ({ data: socketData }) => {
const msgObj = JSON.parse(socketData)
const msgObj = JSON.parse(socketData);
if (msgObj) {
const {command, data, nodeId} = msgObj
this[`${command}Result`] && this[`${command}Result`](data, nodeId)
}
const { command, data, nodeId } = msgObj;
this[`${command}Result`] && this[`${command}Result`](data, nodeId);
}
};
},
init() {
this.getNodeList()
this.getAgentVersion()
this.getNodeList();
this.getAgentVersion();
},
loadGroupList() {
getNodeGroupList().then(({ code, data }) => {
if (code === 200) {
this.groupList = data
this.groupList = data;
}
})
});
},
refresh() {
if (this.socket) {
this.socket.close()
this.socket.close();
}
this.nodeStatus = {}
this.nodeVersion = {}
this.initWebsocket()
this.loadGroupList()
this.nodeStatus = {};
this.nodeVersion = {};
this.initWebsocket();
this.loadGroupList();
},
batchUpdate() {
if (this.tableSelections.length === 0) {
this.$notification.warning({
message: "请选择要升级的节点"
})
message: "请选择要升级的节点",
});
return;
}
this.updateNode()
this.updateNode();
},
updateNodeHandler(record) {
this.tableSelections = [record.id]
this.updateNode()
this.tableSelections = [record.id];
this.updateNode();
},
tableSelectionChange(selectedRowKeys) {
this.tableSelections = selectedRowKeys
this.tableSelections = selectedRowKeys;
},
sendMsg(command, params) {
this.socket.send(JSON.stringify({
this.socket.send(
JSON.stringify({
command,
params
}))
params,
})
);
},
getNodeList() {
this.sendMsg('getNodeList')
this.sendMsg("getNodeList");
},
getNodeListResult(data) {
this.list = data
this.list = data;
},
getAgentVersion() {
this.sendMsg('getAgentVersion')
this.sendMsg("getAgentVersion");
},
getAgentVersionResult(data) {
try {
@ -202,57 +192,57 @@ export default {
this.agentVersion = newData.version;
this.agentTimeStamp = newData.timeStamp;
} catch (e) {
this.agentVersion = data
this.agentVersion = data;
}
},
getVersionResult(data, nodeId) {
this.nodeVersion = Object.assign({}, this.nodeVersion, {
[nodeId]: data
})
[nodeId]: data,
});
},
onErrorResult(data) {
this.$notification.warning({
message: data
})
message: data,
});
},
updateNode() {
this.sendMsg("updateNode", {
ids: this.tableSelections
})
this.tableSelections = []
ids: this.tableSelections,
});
this.tableSelections = [];
},
updateNodeResult(data, nodeId) {
const {completeSize, size} = data
const { completeSize, size } = data;
this.nodeStatus = Object.assign({}, this.nodeStatus, {
[nodeId]: {
...data,
type: 'uploading',
percent: (completeSize / size) * 100
}
})
type: "uploading",
percent: (completeSize / size) * 100,
},
});
},
restartResult(data, nodeId) {
this.nodeStatus = Object.assign({}, this.nodeStatus, {
[nodeId]: {
type: 'restarting'
}
})
type: "restarting",
},
});
},
beforeUpload(file) {
const formData = new FormData();
formData.append('file', file);
formData.append("file", file);
uploadAgentFile(formData).then(({ code, msg }) => {
if (code === 200) {
this.$notification.success({message: "上传成功"})
this.getAgentVersion()
this.$notification.success({ message: "上传成功" });
this.getAgentVersion();
} else {
this.$notification.error({message: msg})
}
})
return false
}
}
this.$notification.error({ message: msg });
}
});
return false;
},
},
};
</script>
<style scoped lang="stylus">
@ -310,6 +300,4 @@ export default {
.ant-select, .ant-btn {
margin-right 20px
}
</style>

View File

@ -15,16 +15,7 @@
<a-button type="primary" @click="loadData">刷新</a-button>
</div>
<!-- 表格 -->
<a-table
:loading="loading"
:columns="columns"
:data-source="list"
:style="{ 'max-height': tableHeight + 'px' }"
:scroll="{ x: 970, y: tableHeight - 120 }"
bordered
rowKey="id"
:pagination="pagination"
>
<a-table :loading="loading" :columns="columns" :data-source="list" :style="{ 'max-height': tableHeight + 'px' }" :scroll="{ y: tableHeight - 120 }" bordered rowKey="id" :pagination="pagination">
<a-tooltip slot="name" slot-scope="text" placement="topLeft" :title="text">
<span>{{ text }}</span>
</a-tooltip>
@ -117,14 +108,21 @@
<a-textarea :auto-size="{ minRows: 3, maxRows: 3 }" v-model="temp.rsaPrv" placeholder="私钥,不填将使用默认的 $HOME/.ssh 目录中的配置。支持配置文件目录:file:"></a-textarea>
</a-tooltip>
</a-form-model-item>
<a-form-model-item v-if="temp.id" label="隐藏字段">
<a-button type="danger" @click="restHideField(temp)">清除</a-button>
</a-form-model-item>
<!-- 公钥暂时没用用到 -->
<a-form-model-item label="公钥" prop="rsaPub" v-if="false">
<a-textarea :auto-size="{ minRows: 3, maxRows: 3 }" v-model="temp.rsaPub" placeholder="公钥,不填将使用默认的 $HOME/.ssh 目录中的配置。支持配置文件目录:file:"></a-textarea>
</a-form-model-item>
</template>
<a-form-model-item v-if="temp.id">
<template slot="label">
隐藏字段
<a-tooltip>
<template slot="title"> 密码字段和私钥字段在编辑的时候不会返回如果需要重置或者清空就请点我 </template>
<a-icon type="question-circle" theme="filled" />
</a-tooltip>
</template>
<a-button style="margin-left: 10px" type="danger" @click="restHideField(temp)">清除</a-button>
</a-form-model-item>
</a-form-model>
</a-modal>
</div>
@ -186,7 +184,7 @@ export default {
{
title: "操作",
dataIndex: "operation",
width: 240,
width: 160,
scopedSlots: { customRender: "operation" },
align: "left",
},

View File

@ -26,7 +26,7 @@
</a-upload>
<a-button type="primary" class="upload-btn" :disabled="fileList.length === 0" @click="startUpload">上传升级文件</a-button>
</a-spin>
<div>
<div style="margin-top: 20px">
<markdown-it-vue class="md-body" :content="changelog" :options="markdownOptions" />
</div>
</div>