feat(ftp): support receive ftp connection (#6)

Co-authored-by: E99p1ant <[email protected]>
This commit is contained in:
Li4n0
2021-04-25 13:39:27 +08:00
committed by GitHub
co-authored by E99p1ant
parent 5e24f9530d
commit 26755351f7
36 changed files with 1446 additions and 141 deletions
+12 -6
View File
@@ -3,12 +3,12 @@
<a-layout-sider v-model="collapsed" :trigger="null" collapsible>
<div class="logo"><b>R</b><span v-if="!collapsed"><b>ev</b>Suit</span></div>
<a-menu theme="dark" mode="inline" :selectedKeys="[this.$route.path]" :open-keys.sync='openKeys'>
<!-- <a-menu-item key="/">-->
<!-- <router-link to="/">-->
<!-- <a-icon type="dashboard"/>-->
<!-- <span>Dashboard</span>-->
<!-- </router-link>-->
<!-- </a-menu-item>-->
<!-- <a-menu-item key="/">-->
<!-- <router-link to="/">-->
<!-- <a-icon type="dashboard"/>-->
<!-- <span>Dashboard</span>-->
<!-- </router-link>-->
<!-- </a-menu-item>-->
<a-sub-menu key="logs">
<span slot="title"><a-icon type="bar-chart"/><span>Logs</span></span>
<a-menu-item key="/logs/http">
@@ -23,6 +23,9 @@
<a-menu-item key="/logs/mysql">
<router-link to="/logs/mysql">MySQL Logs</router-link>
</a-menu-item>
<a-menu-item key="/logs/ftp">
<router-link to="/logs/ftp">FTP Logs</router-link>
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="rules">
<span slot="title"><a-icon type="radar-chart"/><span>Rules</span></span>
@@ -38,6 +41,9 @@
<a-menu-item key="/rules/mysql">
<router-link to="/rules/mysql">MySQL Rules</router-link>
</a-menu-item>
<a-menu-item key="/rules/ftp">
<router-link to="/rules/ftp">FTP Rules</router-link>
</a-menu-item>
</a-sub-menu>
</a-menu>
</a-layout-sider>
+11
View File
@@ -42,4 +42,15 @@ export function getRmiRecord(params) {
return status >= 200 && status < 300 // 默认的
}
})
}
export function getFtpRecord(params) {
return request({
url: '/record/ftp',
params: params,
method: 'get',
validateStatus: function (status) {
return status >= 200 && status < 300 // 默认的
}
})
}
+33
View File
@@ -131,4 +131,37 @@ export function deleteRmiRule(data) {
return status >= 200 && status < 300 // 默认的
}
})
}
export function getFtpRule(params) {
return request({
url: '/rule/ftp',
params: params,
method: 'get',
validateStatus: function (status) {
return status >= 200 && status < 300 // 默认的
}
})
}
export function upsertFtpRule(data) {
return request({
url: '/rule/ftp',
data: data,
method: 'post',
validateStatus: function (status) {
return status >= 200 && status < 300 // 默认的
}
})
}
export function deleteFtpRule(data) {
return request({
url: '/rule/ftp',
data: data,
method: 'delete',
validateStatus: function (status) {
return status >= 200 && status < 300 // 默认的
}
})
}
+1 -1
View File
@@ -7,7 +7,7 @@
@cancel="cancel"
@ok="auth"
>
<a-input v-model.lazy="token" placeholder="Your token"/>
<a-input v-model.lazy="token" @pressEnter="auth" placeholder="Your token"/>
</a-modal>
</div>
</template>
+6 -3
View File
@@ -15,10 +15,13 @@
<a-form-model-item :rules="rules.flagFormat" prop="flag_format">
<span slot="label">
Flag Format&nbsp;
<a-tooltip title="1. Only when the request contains content that satisfies the flag format, the request will be captured.
2. Please use regular expression syntax.
<a-tooltip title="Basic usage:
1. Only when the request contains content that satisfies the flag format, the request will be captured.
2. Use regular expression syntax.
3. The character '*' means to capture all requests.
4. Advanced usage: When the format uses grouping, the platform will only notify the user or push to the client when the first group appears for the first time.">
Advanced usage:
1. When the regex uses grouping without group name, the platform will only notify the user or push to the client when the first group appears for the first time.
2. When the regex uses grouping with group name, you can get these submatches through template variables and use them in other fields of the rule.">
<a-icon type="question-circle-o"/>
</a-tooltip>
</span>
+18 -8
View File
@@ -13,42 +13,52 @@ const routes = [
{
path: '/logs/http',
name: 'HttpLogs',
component: () => import(/* webpackChunkName: "about" */ '../views/logs/Http')
component: () => import( '../views/logs/Http')
},
{
path: '/logs/dns',
name: 'DnsLogs',
component: () => import(/* webpackChunkName: "about" */ '../views/logs/Dns')
component: () => import( '../views/logs/Dns')
},
{
path: '/logs/mysql',
name: 'MysqlLogs',
component: () => import(/* webpackChunkName: "about" */ '../views/logs/Mysql')
component: () => import( '../views/logs/Mysql')
},
{
path: '/logs/rmi',
name: 'RmiLogs',
component: () => import(/* webpackChunkName: "about" */ '../views/logs/Rmi')
component: () => import( '../views/logs/Rmi')
},
{
path: '/logs/ftp',
name: 'FtpLogs',
component: () => import( '../views/logs/Ftp')
},
{
path: '/rules/http',
name: 'HttpRules',
component: () => import(/* webpackChunkName: "about" */ '../views/rules/Http')
component: () => import( '../views/rules/Http')
},
{
path: '/rules/dns',
name: 'DnsRules',
component: () => import(/* webpackChunkName: "about" */ '../views/rules/Dns')
component: () => import( '../views/rules/Dns')
},
{
path: '/rules/mysql',
name: 'MysqlRules',
component: () => import(/* webpackChunkName: "about" */ '../views/rules/Mysql')
component: () => import( '../views/rules/Mysql')
},
{
path: '/rules/rmi',
name: 'RmiRules',
component: () => import(/* webpackChunkName: "about" */ '../views/rules/Rmi')
component: () => import( '../views/rules/Rmi')
},
{
path: '/rules/ftp',
name: 'FtpRules',
component: () => import( '../views/rules/Ftp')
}
]
+220
View File
@@ -0,0 +1,220 @@
<template>
<a-table
:columns="columns"
:data-source="data"
:loading="loading"
:pagination="pagination"
@change="handleTableChange"
:rowClassName="(record, index) => index % 2 === 0 ? '' : 'gray-table-row'"
>
<div slot="selectDropdown"
slot-scope="{ setSelectedKeys, selectedKeys, clearFilters, column }"
style="padding: 8px">
<a-checkbox
:checked="filters[column.dataIndex] === 'CRASHED'"
@change="(e)=>{e.target.checked?filters[column.dataIndex] = 'CRASHED':filters[column.dataIndex] = '';fetch()}">
CRASHED
</a-checkbox>
<br/>
<a-checkbox
:checked="filters[column.dataIndex] === 'FINISHED'"
@change="(e)=>{e.target.checked?filters[column.dataIndex] = 'FINISHED':filters[column.dataIndex] = '';fetch()}">
FINISHED
</a-checkbox>
</div>
<div
slot="filterDropdown"
slot-scope="{ setSelectedKeys, selectedKeys, clearFilters, column }"
style="padding: 8px"
>
<a-input
:placeholder="`Search ${column.dataIndex}`"
:value="selectedKeys[0]"
style="width: 188px; margin-bottom: 8px; display: block;"
@change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
@pressEnter="() => {
filters[column.dataIndex] = selectedKeys[0];
fetch()
}"
/>
<a-button
type="primary"
icon="search"
size="small"
style="width: 90px; margin-right: 8px"
@click="() => {
filters[column.dataIndex] = selectedKeys[0];
fetch()
}"
>
Search
</a-button>
<a-button size="small" style="width: 90px" @click="() =>{
clearFilters();
delete filters[column.dataIndex];
fetch()
}">
Reset
</a-button>
</div>
<a-icon
slot="filterIcon"
slot-scope="filtered"
type="search"
:style="{ color: filtered ? '#108ee9' : undefined }"
/>
<span slot="time" slot-scope="time">
{{ new Date(time).format("yyyy-MM-dd hh:mm:ss") }}
</span>
<span slot="status" slot-scope="status">
<a-tag
:color="colors[status]"
>
{{ status }}
</a-tag>
</span>
</a-table>
</template>
<style>
.gray-table-row {
background-color: #f5f5f5;
}
</style>
<script>
import {getFtpRecord} from '@/api/record'
import {store} from '@/main'
const colors = {
"CRASHED": "#f50",
"FINISHED": "#87d068"
}
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id',
sorter: true,
sortDirections: ['descend', 'ascend'],
},
{
title: 'REQUEST TIME',
dataIndex: 'request_time',
key: 'request_time',
scopedSlots: {customRender: 'time'},
},
{
title: 'RULE',
dataIndex: 'rule_name',
key: 'rule_name',
scopedSlots: {
filterDropdown: 'filterDropdown',
filterIcon: 'filterIcon',
},
},
{
title: 'FLAG',
dataIndex: 'flag',
key: 'flag',
scopedSlots: {
filterDropdown: 'filterDropdown',
filterIcon: 'filterIcon',
},
},
{
title: 'USER',
dataIndex: 'user',
key: 'user',
},
{
title: 'PASSWORD',
dataIndex: 'password',
key: 'password',
},
{
title: 'PATH',
dataIndex: 'path',
key: 'path',
ellipsis: true,
},
{
title: 'STATUS',
dataIndex: 'status',
key: 'status',
scopedSlots: {
customRender: 'status',
filterDropdown: 'selectDropdown',
filterIcon: 'filterIcon',
},
},
{
title: 'REMOTE IP',
key: 'remote_ip',
dataIndex: 'remote_ip',
scopedSlots: {
filterDropdown: 'filterDropdown',
filterIcon: 'filterIcon',
},
},
{
title: 'IP AREA',
key: 'ip_area',
dataIndex: 'ip_area'
}
];
export default {
name: 'DnsLogs',
data() {
return {
data: [],
pagination: {current: 1},
filters: {},
order: "desc",
loading: false,
columns,
colors: colors
};
},
methods: {
handleTableChange(pagination, filters, sorter) {
const pager = {...this.pagination};
pager.current = pagination.current;
this.pagination = pager;
this.order = sorter.order === "ascend" ? "asc" : "desc"
this.fetch();
},
fetch: function () {
this.loading = true;
let params = {
...this.filters,
page: this.pagination.current,
order: this.order
}
getFtpRecord(params).then(res => {
let result = res.data.result
this.data = result.data
const pagination = {...this.pagination};
// Read total count from server
// pagination.total = data.totalCount;
pagination.total = result.count;
this.pagination = pagination;
this.loading = false
}).catch(e => {
if (e.response.status === 403) {
store.authed = false
return []
} else {
console.error(e)
}
})
}
},
mounted() {
this.fetch({page: "1"});
},
}
</script>
+6 -6
View File
@@ -77,12 +77,12 @@ import {getHttpRecord} from '@/api/record'
import {store} from '@/main'
const colors = {
"GET": "green",
"POST": "red",
"HEAD": "pink",
"PUT": "geekblue",
"OPTIONS": "cyan",
"DELETE": "purple",
"GET": "#52c41a",
"POST": "#f5222d",
"PUT": "#eb2f96",
"HEAD": "#02a7ff",
"OPTIONS": "#13c2c2",
"DELETE": "#722ed1",
}
const columns = [
+25 -7
View File
@@ -9,7 +9,23 @@
>
<div v-if="record.files.length" slot="expandedRowRender" slot-scope="record" style="margin: 0">
<b v-if="record.files.length" style="color: gray">FILES:</b><br>
<a v-for="file in record.files" :key="file.name+record.id" :href="'/revsuit/api/file/mysql/'+file.id" target="_blank">{{ file.name }} </a>
<a v-for="file in record.files" :key="file.name+record.id" :href="'/revsuit/api/file/mysql/'+file.id"
target="_blank">{{ file.name }} </a>
</div>
<div slot="selectDropdown"
slot-scope="{ setSelectedKeys, selectedKeys, clearFilters, column }"
style="padding: 8px">
<a-checkbox
:checked="filters[column.dataIndex] === 'true'"
@change="(e)=>{e.target.checked?filters[column.dataIndex] = 'true':filters[column.dataIndex] = '';fetch()}">
True
</a-checkbox>
<br/>
<a-checkbox
:checked="filters[column.dataIndex] === 'false'"
@change="(e)=>{e.target.checked?filters[column.dataIndex] = 'false':filters[column.dataIndex] = '';fetch()}">
False
</a-checkbox>
</div>
<div
slot="filterDropdown"
@@ -58,12 +74,12 @@
</span>
<span slot="loadData" slot-scope="loadData">
<a-tag v-if="loadData"
color="green"
>True</a-tag><a-tag v-else color="red">False</a-tag>
color="#eb2f96"
>True</a-tag><a-tag v-else color="#f5222d">False</a-tag>
</span>
<span slot="fileNum" slot-scope="files">
<a-tag v-if="files.length>=3"
color="purple"
color="#722ed1"
>{{ files.length }}</a-tag>
<a-tag v-else :color="colors[files.length]">
{{ files.length }}
@@ -82,9 +98,9 @@ import {getMysqlRecord} from '@/api/record'
import {store} from '@/main'
const colors = [
"geekblue",
"blue",
"pink",
"#13c2c2",
"#52c41a",
"#02a7ff",
]
const columns = [
@@ -133,6 +149,8 @@ const columns = [
dataIndex: 'load_local_data',
key: 'load_local_data',
scopedSlots: {
filterDropdown: 'selectDropdown',
filterIcon: 'filterIcon',
customRender: "loadData",
}
},
+18 -10
View File
@@ -6,7 +6,7 @@
</a-button>
<!-- rule form-->
<a-drawer
:title="formAction+ ' Dns rule'"
:title="formAction+ ' DNS rule'"
:width="460"
:visible="formVisible"
:body-style="{ paddingBottom: '80px' }"
@@ -47,7 +47,14 @@
</a-row>
<a-row :gutter="24">
<a-col :span="24">
<a-form-model-item label="Value" :rules="rules.value">
<a-form-model-item :rules="rules.value">
<span slot="label">
Value
<a-tooltip
title="Support template such as ${varname}">
<a-icon type="question-circle-o"/>
</a-tooltip>
</span>
<a-input
v-model="form.value"
style="width: 100%"
@@ -139,19 +146,19 @@
<span v-for="value in values.split(',')" :key="value">{{ value }}<br/></span>
</span>
<span slot="action" slot-scope="text,record,index">
<!-- <a-button @click="viewRule(record)" style="-->
<!-- color: #67C23A;-->
<!-- background-color: transparent;-->
<!-- border-color: #67C23A;-->
<!-- text-shadow: none;-->
<!-- margin-right: 10px;-->
<!--" size="small" ghost>View</a-button>-->
<a-button @click="viewRule(record)" style="
color: #67C23A;
background-color: transparent;
border-color: #67C23A;
text-shadow: none;
margin:0 10px 3px 0;
" size="small" ghost>View</a-button>
<a-button @click="editRule(record,index)" style="
color: #909399;
background-color: transparent;
border-color: #909399;
text-shadow: none;
margin-right: 10px;
margin:0 10px 3px 0;
" size="small" ghost>Edit</a-button>
<a-popconfirm
title="Are you sure delete this task?"
@@ -219,6 +226,7 @@ const columns = [
title: 'FLAG FORMAT',
dataIndex: 'flag_format',
key: 'flag_format',
ellipsis: true,
},
{
title: 'RANK',
+356
View File
@@ -0,0 +1,356 @@
<template xmlns:a-col="http://www.w3.org/1999/html">
<div>
<a-button id="add-rule" type="primary" @click="addRule">
<a-icon type="plus"/>
New Rule
</a-button>
<!-- rule form-->
<a-drawer
:title="formAction+ ' FTP rule'"
:width="460"
:visible="formVisible"
:body-style="{ paddingBottom: '80px' }"
@close="closeDrawer"
>
<a-form-model :model="form" ref="form" layout="vertical" @submit="handleSubmit">
<BasicRule :form="form" :readOnly="formReadOnly"/>
<a-row :gutter="24">
<a-col :span="24">
<a-form-model-item>
<span slot="label">
Pasv Address
<a-tooltip
title="Support template such as ${user}/${password}/${varname}">
<a-icon type="question-circle-o"/>
</a-tooltip>
</span>
<a-input
v-model="form.pasv_address"
style="width: 100%"
placeholder="use default value in the config"
:readOnly="formReadOnly"
/>
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
<div
:style="{
position: 'absolute',
right: 0,
bottom: 0,
width: '100%',
borderTop: '1px solid #e9e9e9',
padding: '10px 16px',
background: '#fff',
textAlign: 'right',
zIndex: 1,
}"
>
<a-button :style="{ marginRight: '8px' }" @click="handleCancel">
Cancel
</a-button>
<a-button type="primary" :disabled="formReadOnly" @click="handleSubmit">
Submit
</a-button>
</div>
</a-drawer>
<!-- rule table -->
<a-table
:columns="columns"
:data-source="data"
:loading="loading"
:pagination="pagination"
@change="handleTableChange"
>
<div
slot="filterDropdown"
slot-scope="{ setSelectedKeys, selectedKeys, clearFilters, column }"
style="padding: 8px"
>
<a-input
:placeholder="`Search ${column.dataIndex}`"
:value="selectedKeys[0]"
style="width: 188px; margin-bottom: 8px; display: block;"
@change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
@pressEnter="() => {filters[column.dataIndex] = selectedKeys[0];fetch()}"
/>
<a-button
type="primary"
icon="search"
size="small"
style="width: 90px; margin-right: 8px"
@click="() => {filters[column.dataIndex] = selectedKeys[0];fetch()}"
>
Search
</a-button>
</div>
<a-icon
slot="filterIcon"
slot-scope="filtered"
type="search"
:style="{ color: filtered ? '#108ee9' : undefined }"
/>
<span slot="rank" slot-scope="rank">
<a-tag
:color="'#'+(0x2db7f5+rank*80).toString(16)"
>
{{ rank }}
</a-tag>
</span>
<span slot="switchRender" slot-scope="checked,record,index,dataIndex">
<a-switch :checked="checked" @click="clickSwitch(record,dataIndex.dataIndex)"></a-switch>
</span>
<span slot="valueRender" slot-scope="values">
<span v-for="value in values.split(',')" :key="value">{{ value }}<br/></span>
</span>
<span slot="action" slot-scope="text,record,index">
<a-button @click="viewRule(record)" style="
color: #67C23A;
background-color: transparent;
border-color: #67C23A;
text-shadow: none;
margin:0 10px 3px 0;
" size="small" ghost>View</a-button>
<a-button @click="editRule(record,index)" style="
color: #909399;
background-color: transparent;
border-color: #909399;
text-shadow: none;
margin:0 10px 3px 0;
" size="small" ghost>Edit</a-button>
<a-popconfirm
title="Are you sure delete this task?"
ok-text="Yes"
cancel-text="No"
@confirm="deleteRule(record,index)"
>
<a-button type="danger" size="small" ghost>Delete</a-button>
</a-popconfirm>
</span>
</a-table>
</div>
</template>
<style scoped>
#add-rule {
margin-bottom: 10px;
}
</style>
<script>
import {getFtpRule, upsertFtpRule, deleteFtpRule} from '@/api/rule'
import {store} from '@/main'
import BasicRule from "@/components/BasicRule";
const VIEW = "View"
const EDIT = "Edit"
const CREATE = "Create"
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id',
sorter: true,
sortDirections: ['descend', 'ascend'],
},
{
title: 'NAME',
dataIndex: 'name',
key: 'name',
scopedSlots: {
filterDropdown: 'filterDropdown',
filterIcon: 'filterIcon',
},
},
{
title: 'FLAG FORMAT',
dataIndex: 'flag_format',
key: 'flag_format',
ellipsis: true,
},
{
title: 'RANK',
dataIndex: 'rank',
key: 'rank',
scopedSlots: {
customRender: 'rank',
},
},
{
title: 'PASV ADDRESS',
dataIndex: 'pasv_address',
key: 'pasv_address',
ellipsis: true,
},
{
title: 'PUSH TO CLIENT',
dataIndex: 'push_to_client',
key: 'push_to_client',
scopedSlots: {
customRender: 'switchRender',
}
},
{
title: 'NOTICE',
dataIndex: 'notice',
key: 'notice',
scopedSlots: {
customRender: 'switchRender',
}
},
{
title: 'Action',
key: 'action',
scopedSlots: {customRender: 'action'},
},
];
export default {
name: 'FtpRules',
data() {
return {
data: [],
formVisible: false,
pagination: {current: 1},
filters: {},
loading: false,
columns,
form: {},
formReadOnly: false,
formAction: "", // View ,Create or Edit
}
},
methods: {
handleTableChange(pagination, filters, sorter) {
const pager = {...this.pagination};
pager.current = pagination.current;
this.pagination = pager;
this.order = sorter.order === "ascend" ? "asc" : "desc"
this.fetch();
},
fetch: function () {
this.loading = true;
let params = {
...this.filters,
page: this.pagination.current,
order: this.order
}
getFtpRule(params).then(res => {
let result = res.data.result
this.data = result.data
const pagination = {...this.pagination};
// Read total count from server
// pagination.total = data.totalCount;
pagination.total = result.count;
this.pagination = pagination;
this.loading = false
}).catch(e => {
if (e.response.status === 403) {
store.authed = false
return []
} else {
this.$notification.error({
message: 'Unknown error: ' + e.response.status,
style: {
width: '100px',
marginLeft: `${335 - 600}px`,
},
duration: 4
});
}
})
},
clickSwitch(record, prop) {
record[prop] = !record[prop]
upsertFtpRule(record).then().catch(e => {
this.$notification.error({
message: 'Edit failed',
description:
e.response.data.error,
style: {
width: '600px',
marginLeft: `${335 - 600}px`,
},
duration: 4
});
})
},
addRule() {
this.form = {}
this.showForm(CREATE)
},
viewRule(record) {
this.form = record
this.showForm(VIEW)
},
editRule(record) {
this.form = JSON.parse(JSON.stringify(record))
this.showForm(EDIT)
},
deleteRule(record, index) {
deleteFtpRule(record).then(() => {
this.data.splice(index, 1)
}).catch(e => {
this.$notification.error({
message: 'Error',
description:
e.response.data.error,
style: {
width: '600px',
marginLeft: `${335 - 600}px`,
},
duration: 4
});
})
},
showForm(action) {
this.formAction = action
this.formReadOnly = action === VIEW;
this.formVisible = true;
},
closeDrawer() {
this.formVisible = false;
},
handleSubmit() {
this.$refs.form.validate(valid => {
if (valid) {
upsertFtpRule(this.form).then(() => {
this.closeDrawer()
this.fetch({page: this.pagination.current});
this.$notification.info({
message: 'Success',
style: {
width: '600px',
marginLeft: `${335 - 600}px`,
},
duration: 2.5
});
}).catch(e => {
this.$notification.error({
message: this.formAction + ' failed',
description:
e.response.data.error,
style: {
width: '600px',
marginLeft: `${335 - 600}px`,
},
duration: 4
});
})
}
})
},
handleCancel() {
this.form = {}
this.closeDrawer()
}
},
mounted() {
this.fetch({page: "1"});
},
components: {
BasicRule,
}
}
</script>
+10 -8
View File
@@ -21,7 +21,7 @@
<span slot="label">
Response Status Code
<a-tooltip
title="Number between 100-600, or template such as ${query.var_name}/${body.var_name}/${header.var_name}">
title="Number between 100-600, or template such as ${query.varname}/${body.varname}/${header.varname}">
<a-icon type="question-circle-o"/>
</a-tooltip>
</span>
@@ -39,7 +39,7 @@
<span slot="label">
Response Headers
<a-tooltip
title="Support template such as ${query.var_name}/${body.var_name}/${header.var_name}">
title="Support template such as ${query.varname}/${body.varname}/${header.varname}">
<a-icon type="question-circle-o"/>
</a-tooltip>
</span>
@@ -77,13 +77,14 @@
<span slot="label">
Response Body
<a-tooltip
title="Support template such as ${query.var_name}/${body.var_name}/${header.var_name}">
title="Support template such as ${query.varname}/${body.varname}/${header.varname}">
<a-icon type="question-circle-o"/>
</a-tooltip>
</span>
<a-textarea v-model="form.response_body"
placeholder="Hello RevSuit!"
:readOnly="formReadOnly"
rows="10"
/>
</a-form-model-item>
</a-col>
@@ -161,17 +162,17 @@
<span slot="action" slot-scope="text,record,index">
<a-button @click="viewRule(record)" style="
color: #67C23A;
background-color: transparent;
border-color: #67C23A;
text-shadow: none;
margin-right: 10px;
background-color: transparent;
border-color: #67C23A;
text-shadow: none;
margin:0 10px 3px 0;
" size="small" ghost>View</a-button>
<a-button @click="editRule(record,index)" style="
color: #909399;
background-color: transparent;
border-color: #909399;
text-shadow: none;
margin-right: 10px;
margin:0 10px 3px 0;
" size="small" ghost>Edit</a-button>
<a-popconfirm
title="Are you sure delete this task?"
@@ -221,6 +222,7 @@ const columns = [
title: 'FLAG FORMAT',
dataIndex: 'flag_format',
key: 'flag_format',
ellipsis: true,
},
{
title: 'RANK',
+3 -2
View File
@@ -146,14 +146,14 @@
background-color: transparent;
border-color: #67C23A;
text-shadow: none;
margin-right: 10px;
margin:0 10px 3px 0;
" size="small" ghost>View</a-button>
<a-button @click="editRule(record,index)" style="
color: #909399;
background-color: transparent;
border-color: #909399;
text-shadow: none;
margin-right: 10px;
margin:0 10px 3px 0;
" size="small" ghost>Edit</a-button>
<a-popconfirm
title="Are you sure delete this task?"
@@ -203,6 +203,7 @@ const columns = [
title: 'FLAG FORMAT',
dataIndex: 'flag_format',
key: 'flag_format',
ellipsis: true,
},
{
title: 'RANK',
+10 -16
View File
@@ -6,7 +6,7 @@
</a-button>
<!-- rule form-->
<a-drawer
:title="formAction+ ' Dns rule'"
:title="formAction+ ' RMI rule'"
:width="460"
:visible="formVisible"
:body-style="{ paddingBottom: '80px' }"
@@ -79,13 +79,6 @@
{{ rank }}
</a-tag>
</span>
<span slot="type" slot-scope="type">
<a-tag
:color="colors[type]"
>
{{ resolveTypes[type] }}
</a-tag>
</span>
<span slot="switchRender" slot-scope="checked,record,index,dataIndex">
<a-switch :checked="checked" @click="clickSwitch(record,dataIndex.dataIndex)"></a-switch>
@@ -94,19 +87,19 @@
<span v-for="value in values.split(',')" :key="value">{{ value }}<br/></span>
</span>
<span slot="action" slot-scope="text,record,index">
<!-- <a-button @click="viewRule(record)" style="-->
<!-- color: #67C23A;-->
<!-- background-color: transparent;-->
<!-- border-color: #67C23A;-->
<!-- text-shadow: none;-->
<!-- margin-right: 10px;-->
<!--" size="small" ghost>View</a-button>-->
<a-button @click="viewRule(record)" style="
color: #67C23A;
background-color: transparent;
border-color: #67C23A;
text-shadow: none;
margin:0 10px 3px 0;
" size="small" ghost>View</a-button>
<a-button @click="editRule(record,index)" style="
color: #909399;
background-color: transparent;
border-color: #909399;
text-shadow: none;
margin-right: 10px;
margin:0 10px 3px 0;
" size="small" ghost>Edit</a-button>
<a-popconfirm
title="Are you sure delete this task?"
@@ -156,6 +149,7 @@ const columns = [
title: 'FLAG FORMAT',
dataIndex: 'flag_format',
key: 'flag_format',
ellipsis: true,
},
{
title: 'RANK',