534 lines
19 KiB
Vue
534 lines
19 KiB
Vue
<template>
|
||
<div class="app-container">
|
||
<div class="filter-container">
|
||
<el-select v-model="listQuery.vendor" placeholder="机房/公司" clearable collapse-tags style="width: 150px" class="filter-item">
|
||
<el-option v-for="item in vendor_list" :key="item" :label="item" :value="item" />
|
||
</el-select>
|
||
<el-select v-model="listQuery.account" placeholder="租户/部门" clearable style="width: 150px" class="filter-item">
|
||
<el-option v-for="item in account_list" :key="item" :label="item" :value="item" />
|
||
</el-select>
|
||
<el-select v-model="listQuery.region" filterable placeholder="区域/项目" clearable style="width: 160px" class="filter-item">
|
||
<el-option v-for="item in region_list" :key="item" :label="item" :value="item" />
|
||
</el-select>
|
||
<el-select v-model="listQuery.group" filterable placeholder="分组/环境" clearable style="width: 100px" class="filter-item">
|
||
<el-option v-for="item in group_list" :key="item" :label="item" :value="item" />
|
||
</el-select>
|
||
<el-tooltip class="item" effect="light" content="点击清空查询条件" placement="top">
|
||
<el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-refresh" circle @click="handleReset" />
|
||
</el-tooltip>
|
||
<el-button class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">
|
||
新增
|
||
</el-button>
|
||
<el-button v-waves :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">
|
||
导出
|
||
</el-button>
|
||
<el-button class="filter-item" type="danger" icon="el-icon-delete" @click="handleDelAll">
|
||
批量删除
|
||
</el-button>
|
||
<div style="float: right;">
|
||
<el-input v-model="iname" prefix-icon="el-icon-search" placeholder="请输入名称或实例进行筛选" clearable style="width:230px" class="filter-item" @input="inameFilter(iname)" />
|
||
</div>
|
||
</div>
|
||
|
||
<el-table
|
||
v-loading="listLoading"
|
||
:data="all_list.filter(data => !iname || (data.name.toLowerCase().includes(iname.toLowerCase()) || data.instance.toLowerCase().includes(iname.toLowerCase())))"
|
||
border
|
||
fit
|
||
highlight-current-row
|
||
style="width: 100%;"
|
||
@selection-change="handleSelectionChange"
|
||
>
|
||
<el-table-column type="selection" align="center" width="35" />
|
||
<el-table-column label="ID" align="center" width="40px">
|
||
<template slot-scope="scope">
|
||
<span>{{ scope.$index+1 }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="vendor" label="机房/公司" sortable align="center">
|
||
<template slot-scope="{row}">
|
||
<span>{{ row.vendor }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="account" label="租户/部门" sortable align="center">
|
||
<template slot-scope="{row}">
|
||
<span>{{ row.account }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="region" label="区域/项目" sortable align="center" show-overflow-tooltip>
|
||
<template slot-scope="{row}">
|
||
<span>{{ row.region }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="group" label="分组/环境" sortable align="center">
|
||
<template slot-scope="{row}">
|
||
<span>{{ row.group }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="name" label="名称" sortable align="center" show-overflow-tooltip>
|
||
<template slot-scope="{row}">
|
||
<span>{{ row.name }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="instance" label="实例" sortable align="center" width="160" show-overflow-tooltip>
|
||
<template slot-scope="{row}">
|
||
<span>{{ row.instance }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="os" label="系统" sortable align="center" width="80">
|
||
<template slot-scope="{row}">
|
||
<span>{{ row.os }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
|
||
<template slot-scope="{row}">
|
||
<el-button type="primary" size="mini" @click="handleUpdate(row)">
|
||
编辑
|
||
</el-button>
|
||
<el-button size="mini" type="danger" @click="handleDelete(row)">
|
||
删除
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="handleFilter" />
|
||
|
||
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible" width="37%">
|
||
<el-form ref="dataForm" :rules="rules" :model="temp" label-position="right" label-width="auto" style="width: 90%; margin-left: 20px;">
|
||
<el-form-item label="机房/公司" prop="vendor">
|
||
<el-autocomplete v-model="temp.vendor" :fetch-suggestions="Sugg_vendor" placeholder="优先选择" clearable class="filter-item" />
|
||
</el-form-item>
|
||
<el-form-item label="租户/部门" prop="account">
|
||
<el-autocomplete v-model="temp.account" :fetch-suggestions="Sugg_account" placeholder="优先选择" clearable class="filter-item" />
|
||
</el-form-item>
|
||
<el-form-item label="区域/项目" prop="region">
|
||
<el-autocomplete v-model="temp.region" :fetch-suggestions="Sugg_region" placeholder="优先选择" clearable class="filter-item" />
|
||
</el-form-item>
|
||
<el-form-item label="分组/环境" prop="group">
|
||
<el-autocomplete v-model="temp.group" :fetch-suggestions="Sugg_group" placeholder="优先选择" clearable class="filter-item" />
|
||
</el-form-item>
|
||
<el-form ref="dataForm" :inline="true" :rules="rules" :model="temp" class="demo-form-inline" label-position="right" label-width="50px">
|
||
<el-form-item label="名称" prop="name">
|
||
<el-input v-model="temp.name" placeholder="请输入" clearable />
|
||
</el-form-item>
|
||
<el-form-item label="系统" prop="os">
|
||
<el-select v-model="temp.os" placeholder="请选择" style="width: 130px;" @change="temp.port=osport[temp.os]">
|
||
<el-option label="linux" value="linux" />
|
||
<el-option label="windows" value="windows" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="IP" prop="ip">
|
||
<el-input v-model="temp.ip" placeholder="请输入" clearable />
|
||
</el-form-item>
|
||
<el-form-item label="端口" prop="port">
|
||
<el-input v-model="temp.port" placeholder="请输入" clearable style="width: 130px;" />
|
||
</el-form-item>
|
||
</el-form>
|
||
</el-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button v-if="dialogStatus==='create'" type="primary" @click="createAndNew">
|
||
确认并新增
|
||
</el-button>
|
||
<el-button @click="dialogFormVisible = false">
|
||
取消
|
||
</el-button>
|
||
<el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">
|
||
确认
|
||
</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import waves from '@/directive/waves' // waves directive
|
||
import Pagination from '@/components/Pagination' // secondary package based on el-pagination
|
||
|
||
import { getAllList, getAllInfo, addService, updateService, delService } from '@/api/selfnode'
|
||
export default {
|
||
name: 'ComplexTable',
|
||
components: { Pagination },
|
||
directives: { waves },
|
||
filters: {
|
||
statusFilter(status) {
|
||
const statusMap = {
|
||
published: 'success',
|
||
draft: 'info',
|
||
deleted: 'danger'
|
||
}
|
||
return statusMap[status]
|
||
}
|
||
},
|
||
data() {
|
||
const validateInput = (rule, value, callback) => {
|
||
if (!this.checkSpecialKey(value)) {
|
||
callback(new Error('不能含有空格或 [ ]`~!#$^&*=|"{}\':;?'))
|
||
} else {
|
||
callback()
|
||
}
|
||
}
|
||
return {
|
||
all_list: [],
|
||
pall_list: [],
|
||
iname: '',
|
||
new_list: [],
|
||
total: 0,
|
||
listLoading: true,
|
||
listQuery: {
|
||
page: 1,
|
||
limit: 30,
|
||
vendor: '',
|
||
account: '',
|
||
region: '',
|
||
group: ''
|
||
},
|
||
value_vendor: [],
|
||
value_account: [],
|
||
value_region: [],
|
||
value_group: [],
|
||
multipleSelection: [],
|
||
del_dict: {},
|
||
osport: { linux: '9100', windows: '9182' },
|
||
temp: {
|
||
vendor: '',
|
||
account: '',
|
||
region: '',
|
||
group: '',
|
||
name: '',
|
||
os: '',
|
||
ip: '',
|
||
port: ''
|
||
},
|
||
dialogFormVisible: false,
|
||
dialogStatus: '',
|
||
textMap: {
|
||
update: '更新',
|
||
create: '创建'
|
||
},
|
||
rules: {
|
||
vendor: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||
account: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||
region: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||
group: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||
name: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||
ip: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||
port: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||
{ validator: validateInput, trigger: ['blur', 'change'] }],
|
||
os: [{ required: true, message: '此为必填项', trigger: 'change' },
|
||
{ validator: validateInput, trigger: ['blur', 'change'] }]
|
||
},
|
||
downloadLoading: false
|
||
}
|
||
},
|
||
|
||
computed: {
|
||
cvendor() {
|
||
return this.listQuery.vendor
|
||
},
|
||
caccount() {
|
||
return this.listQuery.account
|
||
},
|
||
cregion() {
|
||
return this.listQuery.region
|
||
},
|
||
cgroup() {
|
||
return this.listQuery.group
|
||
}
|
||
},
|
||
|
||
watch: {
|
||
cvendor(new_vendor) {
|
||
this.fetchList(new_vendor, this.listQuery.account, this.listQuery.region, this.listQuery.group)
|
||
},
|
||
caccount(new_account) {
|
||
this.fetchList(this.listQuery.vendor, new_account, this.listQuery.region, this.listQuery.group)
|
||
},
|
||
cregion(new_region) {
|
||
this.fetchList(this.listQuery.vendor, this.listQuery.account, new_region, this.listQuery.group)
|
||
},
|
||
cgroup(new_group) {
|
||
this.fetchList(this.listQuery.vendor, this.listQuery.account, this.listQuery.region, new_group)
|
||
}
|
||
},
|
||
|
||
created() {
|
||
this.fetchData()
|
||
},
|
||
|
||
methods: {
|
||
inameFilter(iname) {
|
||
if (iname === '') {
|
||
this.handleFilter()
|
||
} else {
|
||
this.total = 0
|
||
this.all_list = this.pall_list
|
||
}
|
||
},
|
||
handleFilter() {
|
||
this.total = this.pall_list.length
|
||
this.all_list = this.pall_list.slice(0 + this.listQuery.limit * (this.listQuery.page - 1), this.listQuery.limit + this.listQuery.limit * (this.listQuery.page - 1))
|
||
},
|
||
handleSelectionChange(val) {
|
||
this.multipleSelection = val
|
||
},
|
||
checkSpecialKey(str) {
|
||
const specialKey = '[]`~!#$^&*=|{}\'":;? '
|
||
for (let i = 0; i < str.length; i++) {
|
||
if (specialKey.indexOf(str.substr(i, 1)) !== -1) {
|
||
return false
|
||
}
|
||
}
|
||
return true
|
||
},
|
||
fetchData() {
|
||
this.listLoading = true
|
||
getAllInfo().then(response => {
|
||
this.all_list = response.all_list
|
||
this.vendor_list = response.vendor_list
|
||
this.account_list = response.account_list
|
||
this.region_list = response.region_list
|
||
this.group_list = response.group_list
|
||
this.listLoading = false
|
||
this.xvendor = this.load_vendor()
|
||
this.xaccount = this.load_account()
|
||
this.xregion = this.load_region()
|
||
this.xgroup = this.load_group()
|
||
this.pall_list = response.all_list
|
||
this.handleFilter()
|
||
})
|
||
},
|
||
fetchList(vendor, account, region, group) {
|
||
this.listLoading = true
|
||
getAllList(vendor, account, region, group).then(response => {
|
||
this.all_list = response.all_list
|
||
this.listLoading = false
|
||
this.vendor_list = response.vendor_list
|
||
this.account_list = response.account_list
|
||
this.region_list = response.region_list
|
||
this.group_list = response.group_list
|
||
this.listQuery.page = 1
|
||
this.pall_list = response.all_list
|
||
this.handleFilter()
|
||
})
|
||
},
|
||
resetTemp() {
|
||
this.temp = {}
|
||
},
|
||
|
||
handleCreate() {
|
||
this.resetTemp()
|
||
var newone = {
|
||
vendor: this.listQuery.vendor,
|
||
account: this.listQuery.account,
|
||
region: this.listQuery.region,
|
||
group: this.listQuery.group,
|
||
os: 'linux',
|
||
port: '9100'
|
||
}
|
||
this.temp = Object.assign({}, this.temp, newone)
|
||
this.dialogStatus = 'create'
|
||
this.dialogFormVisible = true
|
||
this.$nextTick(() => {
|
||
this.$refs['dataForm'].clearValidate()
|
||
})
|
||
},
|
||
createData() {
|
||
this.$refs['dataForm'].validate((valid) => {
|
||
if (valid) {
|
||
addService(this.temp).then(response => {
|
||
this.temp.instance = this.temp.ip + ':' + this.temp.port
|
||
this.all_list.unshift(this.temp)
|
||
this.dialogFormVisible = false
|
||
this.$message({
|
||
message: response.data,
|
||
type: 'success'
|
||
})
|
||
})
|
||
}
|
||
})
|
||
},
|
||
createAndNew() {
|
||
this.$refs['dataForm'].validate((valid) => {
|
||
if (valid) {
|
||
addService(this.temp).then(response => {
|
||
this.temp.instance = this.temp.ip + ':' + this.temp.port
|
||
this.all_list.unshift(this.temp)
|
||
this.dialogFormVisible = false
|
||
this.$message({
|
||
message: response.data,
|
||
type: 'success'
|
||
})
|
||
var newtemp = {
|
||
vendor: this.temp.vendor,
|
||
account: this.temp.account,
|
||
region: this.temp.region,
|
||
group: this.temp.group,
|
||
os: 'linux',
|
||
port: '9100'
|
||
}
|
||
this.resetTemp()
|
||
this.temp = Object.assign({}, this.temp, newtemp)
|
||
this.dialogStatus = 'create'
|
||
this.dialogFormVisible = true
|
||
this.$nextTick(() => {
|
||
this.$refs['dataForm'].clearValidate()
|
||
})
|
||
})
|
||
}
|
||
})
|
||
},
|
||
handleReset() {
|
||
this.listQuery.vendor = ''
|
||
this.listQuery.account = ''
|
||
this.listQuery.region = ''
|
||
this.listQuery.group = ''
|
||
},
|
||
handleUpdate(row) {
|
||
row.ip = row.instance.split(':')[0]
|
||
row.port = row.instance.split(':')[1]
|
||
this.temp = Object.assign({}, row) // copy obj
|
||
this.del_dict = row
|
||
this.dialogStatus = 'update'
|
||
this.dialogFormVisible = true
|
||
this.$nextTick(() => {
|
||
this.$refs['dataForm'].clearValidate()
|
||
})
|
||
},
|
||
updateData() {
|
||
this.$refs['dataForm'].validate((valid) => {
|
||
if (valid) {
|
||
const up_dict = Object.assign({}, this.temp)
|
||
updateService(this.del_dict, up_dict).then(response => {
|
||
this.dialogFormVisible = false
|
||
this.$message({
|
||
message: response.data,
|
||
type: 'success'
|
||
})
|
||
up_dict.instance = up_dict.ip + ':' + up_dict.port
|
||
this.all_list.splice(this.all_list.indexOf(this.del_dict), 1, up_dict)
|
||
})
|
||
}
|
||
})
|
||
},
|
||
handleDelete(row) {
|
||
this.$confirm('此操作将删除【' + row.group + ':' + row.region + ':' + row.name + '】,是否继续?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
delService(row).then(response => {
|
||
this.$message({
|
||
message: response.data,
|
||
type: 'success'
|
||
})
|
||
this.$delete(this.all_list, this.all_list.indexOf(row))
|
||
})
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消删除'
|
||
})
|
||
})
|
||
},
|
||
handleDelAll() {
|
||
this.$confirm('此操作将批量删除选中行,是否继续?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
for (let i = 0; i < this.multipleSelection.length; i++) {
|
||
delService(this.multipleSelection[i]).then(response => {
|
||
this.$message({
|
||
message: response.data,
|
||
type: 'success'
|
||
})
|
||
})
|
||
this.$delete(this.all_list, this.all_list.indexOf(this.multipleSelection[i]))
|
||
}
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消删除'
|
||
})
|
||
})
|
||
},
|
||
handleDownload() {
|
||
this.downloadLoading = true
|
||
import('@/vendor/Export2Excel').then(excel => {
|
||
const tHeader = ['机房/公司', '租户/部门', '区域/项目', '分组/环境', '名称', '实例', '系统']
|
||
const filterVal = ['vendor', 'account', 'region', 'group', 'name', 'instance', 'os']
|
||
const data = this.formatJson(filterVal)
|
||
excel.export_json_to_excel({
|
||
header: tHeader,
|
||
data,
|
||
filename: 'selfnode-list'
|
||
})
|
||
this.downloadLoading = false
|
||
})
|
||
},
|
||
formatJson(filterVal) {
|
||
return this.all_list.map(v => filterVal.map(j => {
|
||
return v[j]
|
||
}))
|
||
},
|
||
Sugg_vendor(queryString, cb) {
|
||
var xvendor = this.xvendor
|
||
var results = queryString ? xvendor.filter(this.createFilter(queryString)) : xvendor
|
||
cb(results)
|
||
},
|
||
Sugg_account(queryString, cb) {
|
||
var xaccount = this.xaccount
|
||
var results = queryString ? xaccount.filter(this.createFilter(queryString)) : xaccount
|
||
cb(results)
|
||
},
|
||
Sugg_region(queryString, cb) {
|
||
var xregion = this.xregion
|
||
var results = queryString ? xregion.filter(this.createFilter(queryString)) : xregion
|
||
cb(results)
|
||
},
|
||
Sugg_group(queryString, cb) {
|
||
var xgroup = this.xgroup
|
||
var results = queryString ? xgroup.filter(this.createFilter(queryString)) : xgroup
|
||
cb(results)
|
||
},
|
||
createFilter(queryString) {
|
||
return (restaurant) => {
|
||
return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
|
||
}
|
||
},
|
||
load_vendor() {
|
||
for (const x in this.vendor_list) {
|
||
this.value_vendor.push({ 'value': this.vendor_list[x] })
|
||
}
|
||
return this.value_vendor
|
||
},
|
||
load_account() {
|
||
for (const x in this.account_list) {
|
||
this.value_account.push({ 'value': this.account_list[x] })
|
||
}
|
||
return this.value_account
|
||
},
|
||
load_region() {
|
||
for (const x in this.region_list) {
|
||
this.value_region.push({ 'value': this.region_list[x] })
|
||
}
|
||
return this.value_region
|
||
},
|
||
load_group() {
|
||
for (const x in this.group_list) {
|
||
this.value_group.push({ 'value': this.group_list[x] })
|
||
}
|
||
return this.value_group
|
||
}
|
||
}
|
||
}
|
||
</script>
|