cmc-web/webs/cop-web/src/views/resource-manage/group/worker.vue

646 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="wrapper-container">
<el-row :gutter="10">
<el-col :span="6" style="width: 286px">
<el-card class="group">
<div slot="header">
分组管理
<el-tooltip class="item" effect="dark" content="添加根节点" placement="top-start">
<el-button class="pull-right" type="text" @click="add('0')" icon="el-icon-plus"></el-button>
</el-tooltip>
</div>
<el-row>
<el-col :span="24">
<el-tree :data="treeData" ref="scriptTree" node-key="id" :props="defaultProps" :highlight-current="true" :check-on-click-node="true" @node-click="handleNodeClick">
<span class="custom-tree-node" slot-scope="{ node, data }">
<div class="custom-tree-node-wrapper">
<span class="custom-tree-node-label">
{{ node.label }}
</span>
<span class="operate-btns">
<dot-dropdown :events="dropMenuEvents" :data="{ node, data }" @addNode="addNode" @editNode="editNode" @removeNode="removeNode" />
</span>
</div>
</span>
</el-tree>
</el-col>
</el-row>
</el-card>
</el-col>
<el-col :span="18" style="width: calc(100% - 286px)">
<el-card>
<el-tabs v-model="typeName" @tab-click="handleSearch">
<el-tab-pane name="Ansible" label="Ansible">
<cb-advance-table :data="list" :card-border="false" :searchConfigs="searchConfigs" :params="params" :total="total" :columns="ansibleColumns" :get-list="getList" :loading="loading" ref="ansibleTableRef" @select="handleSelectItem" @select-all="handleSelectAll">
<!-- <template #action>
<el-button type="primary" :disabled="!selectList.length" @click.native="handleConfig({}, 'exclude')"> 排除 </el-button>
<el-button type="primary" :disabled="!selectList.length" @click.native="handleConfig({}, 'recovery')"> 恢复 </el-button>
<el-button type="primary" @click.native="handleDeployGaia"> 扩容 </el-button>
</template> -->
<template #name="val, record">
<span class="detail-href" @click="getDetail(record.id)">{{ val }}</span>
</template>
<template #isSuper="val">
{{ val == null ? '--' : val ? '是' : '否' }}
</template>
<template #deleted="deleted">
{{ deleted == null ? '--' : deleted ? '异常' : '正常' }}
</template>
<template #isExclude="val">
{{ val == null ? '--' : val ? '是' : '否' }}
</template>
<template #level="level">
<cb-status-icon :type="level | levelFilter('color')">{{ level | levelFilter('name') }} </cb-status-icon>
</template>
<template #operate="val, record">
<el-button type="text" @click.native="setting(record)" :disabled="record.deleted"> 配置 </el-button>
<!-- <div class="action-divider"></div>
<el-button type="text" @click.native="handleConfig(record)" :disabled="record.deleted"> {{ record.isExclude ? '恢复' : '排除' }} </el-button>
<div class="action-divider"></div>
<el-dropdown trigger="click">
<span class="el-dropdown-link"> 更多<i class="el-icon-arrow-down el-icon--right"></i> </span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click.native="handleDelGaia(record)" :disabled="record.deleted"> 缩容 </el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown> -->
</template>
</cb-advance-table>
</el-tab-pane>
<!-- <el-tab-pane name="SaltMaster" label="SaltMaster">
<cb-advance-table
:card-border="false"
:data="saltMasterList"
:searchConfigs="saltMasterSearchConfigs"
:params="paramt"
:total="saltMasterTotal"
:columns="saltMasterColumns"
:get-list="getSaltMasterList"
:loading="saltMasterLoading"
ref="saltTableRef"
@select="handleSelectItem"
@select-all="handleSelectAll"
>
<template #action>
<el-button @click="handleCreate(null, 1)" type="primary" icon="el-icon-plus">新增 </el-button>
</template>
<template #name="val, record">
<span class="detail-href" @click="getDetail(record.id)">{{ val }}</span>
</template>
<template #level="level">
<cb-status-icon :type="level | levelFilter('color')">{{ level | levelFilter('name') }} </cb-status-icon>
</template>
<template #operate="val, record">
<el-button icon="el-icon-edit" type="text" @click="handleCreate(record, 2)"> 编辑 </el-button>
<div class="action-divider"></div>
<el-button icon="el-icon-delete" type="text" @click="handleDelete(record.id)"> 删除 </el-button>
<div class="action-divider"></div>
<el-dropdown trigger="click">
<span class="el-dropdown-link"> 更多<i class="el-icon-arrow-down el-icon--right"></i> </span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="syncMinion(record)"> minion同步 </el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</cb-advance-table>
</el-tab-pane> -->
</el-tabs>
</el-card>
</el-col>
</el-row>
<!--新增编辑worker分组-->
<cb-dialog :title="textMap1[dialogStatus]" :close-on-click-modal="false" v-if="addScriptGroupVisible" :visible.sync="addScriptGroupVisible" width="35%">
<cb-form :model="addScriptGroup" ref="addScriptGroup">
<cb-form-item label="分组名称:" prop="name" validate="required">
<el-input v-model="addScriptGroup.name" auto-complete="off"></el-input>
</cb-form-item>
<cb-form-item label="分组描述:" prop="remark">
<el-input type="textarea" :autosize="{ minRows: 3, maxRows: 6 }" v-model="addScriptGroup.remark" auto-complete="off"></el-input>
</cb-form-item>
</cb-form>
<div slot="footer" class="dialog-footer">
<el-button type="ghost" @click.native="addScriptGroupVisible = false">取消</el-button>
<el-button type="primary" @click.native="addScriptGroupSubmit">确定</el-button>
</div>
</cb-dialog>
<!--新增编辑worker-->
<cb-dialog :title="textMap2[dialogStatus]" :close-on-click-modal="false" v-if="addWorkerVisible" :visible.sync="addWorkerVisible" width="35%">
<cb-form :model="addWorkerData" ref="addWorkerData" label-width="150px">
<cb-form-item label="SaltMaster地址" prop="instance" validate="required">
<el-input v-model="addWorkerData.instance" auto-complete="off"></el-input>
</cb-form-item>
<cb-form-item label="协议类型:" prop="protocol" validate="required">
<el-input v-model="addWorkerData.protocol" auto-complete="off"></el-input>
</cb-form-item>
<cb-form-item label="用户名:" prop="username" validate="required">
<el-input v-model="addWorkerData.username"></el-input>
</cb-form-item>
<cb-form-item label="密码:" prop="password" validate="required">
<el-input v-model="addWorkerData.password" show-password auto-complete="new-password"></el-input>
</cb-form-item>
</cb-form>
<div slot="footer" class="dialog-footer">
<el-button type="ghost" @click.native="addWorkerVisible = false">取消</el-button>
<el-button type="primary" @click.native="addWorkerSubmit">确定</el-button>
</div>
</cb-dialog>
<set-group :set-data="setData" v-if="setData.dialog" @setOk="handleSearch"></set-group>
<GaiaDialog :dialog="gaiaDialog" v-if="gaiaDialog.visible" @back="handleSearch"></GaiaDialog>
</div>
</template>
<script>
import SetGroup from '@/views/resource-manage/components/setGroup'
import { createBsmHostGroup, deleteBsmHostGroup, getBsmHostGroup, getWorkers, getWorkerDetail, updateBsmHostGroup, createBsmHostWorker, updateBsmHostWorker, deleteBsmHostWorker, updateWorkersConfig, syncMinionApi } from '@/services/task/resource'
import DotDropdown from 'views/repository/component/dotDropdown.vue'
import crypto from 'utils/crypto.js'
import GaiaDialog from './GaiaDialog.vue'
export default {
components: {
SetGroup,
DotDropdown,
GaiaDialog,
},
data() {
return {
loading: false,
searchConfigs: [
{ label: '实例', value: 'instance', type: 'Input' },
{ value: 'category', initValue: 'Ansible', type: 'Const' },
],
saltMasterSearchConfigs: [
{ label: '实例', value: 'instance', type: 'Input' },
{ value: 'category', initValue: 'SaltMaster', type: 'Const' },
],
ansibleColumns: [
{
type: 'selection',
selectable(row, index) {
return !row.deleted
},
},
{ label: '实例', prop: 'instance', scopedSlots: { customRender: 'instance' } },
{ label: '心跳状态', prop: 'deleted', scopedSlots: { customRender: 'deleted' } },
{ label: '超级worker', prop: 'isSuper', scopedSlots: { customRender: 'isSuper' } },
{ label: '所属分组', prop: 'groupName' },
{ label: '任务数量', prop: 'tasks' },
{ label: '是否排除', prop: 'isExclude', scopedSlots: { customRender: 'isExclude' } },
{ label: '操作', disabled: true, width: '200px', scopedSlots: { customRender: 'operate' } },
],
saltMasterColumns: [
{ type: 'selection' },
{ label: '实例', prop: 'instance', scopedSlots: { customRender: 'instance' } },
{ label: '类型', prop: 'category' },
{ label: '协议类型', prop: 'protocol' },
{ label: '所属分组', prop: 'groupName' },
{ label: '操作', disabled: true, width: '200px', scopedSlots: { customRender: 'operate' } },
],
list: [],
saltMasterList: [],
saltMasterLoading: false,
total: null,
saltMasterTotal: null,
paramt: {
page: 1,
rows: 20,
},
params: {
page: 1,
rows: 20,
},
listQuery: {
name: '',
version: '',
},
groupId: null,
parentId: null,
nodedata: {},
// 树形菜单
treeData: [],
defaultProps: {
children: 'childrenList',
label: 'name',
},
dropMenuEvents: [
{ label: '编辑', funcName: 'editNode' },
{ label: '删除', funcName: 'removeNode' },
// { label: '新建子节点', funcName: 'addNode' }
],
// 详情
detailFlag: false,
detailData: [],
// 新增编辑worker分组
dialogStatus: '',
textMap1: {
update: '编辑分组',
create: '新增分组',
},
addScriptGroup: {},
addScriptGroupVisible: false,
props: {
value: 'id',
children: 'childrenList',
label: 'name',
checkStrictly: true,
},
addScript: {
name: '',
},
flag: null,
// 树
operate: false,
chartObject: {},
setData: {
dialog: false,
data: {},
},
// 新增编辑worker
textMap2: {
update: '编辑代理',
create: '新增代理',
},
addWorkerVisible: false,
addWorkerData: {},
typeName: 'Ansible',
selectList: [],
idList: [],
timer: null,
gaiaDialog: {
visible: false,
record: {},
},
}
},
created() {
this.getTreeData()
this.startInterval()
// this.handleSearch()
},
destroyed() {
clearInterval(this.timer)
},
methods: {
startInterval() {
this.timer = setInterval(this.handleSearch, 1000 * 10)
},
addNode({ node, data }) {
this.addScriptGroup = {}
this.dialogStatus = 'create'
this.parentId = data.id
this.addScriptGroupVisible = true
},
editNode({ node, data }) {
this.addScriptGroup = Object.assign({}, data)
this.dialogStatus = 'update'
this.addScriptGroupVisible = true
},
removeNode({ node, data }) {
this.$confirm('您确定要删除该分组吗?', '提示', {
type: 'warning',
})
.then(() => {
deleteBsmHostGroup(data.id).then((data) => {
if (data.success) {
this.$message.success({
message: data.message,
type: 'success',
})
this.getTreeData()
this.groupId = null
}
})
})
.catch(() => {})
},
setting(row) {
this.setData = {
dialog: true,
data: {
...row,
},
}
},
syncMinion({ id }) {
this.$confirm('您确定要执行同步吗?', '提示', {
type: 'warning',
})
.then(async () => {
const res = await syncMinionApi(id)
if (res.success) {
this.$message.success(res.message)
this.getSaltMasterList()
}
})
.catch(() => {})
},
async getTreeData() {
const that = this
const data = await getBsmHostGroup({ parentId: 0 })
if (data.success) {
that.treeData = data.data
setTimeout(function () {
if (that.groupId) {
that.$refs.scriptTree.setCurrentKey(that.groupId)
}
}, 10)
}
},
async getList() {
this.selectList = []
this.refreshId()
this.loading = true
const data = await getWorkers(this.params)
if (data.success) {
this.list = data.data.rows
this.total = data.data.total
this.loading = false
}
},
handleNodeClick(node) {
this.groupId = node.id
this.nodedata = node
this.handleSearch()
},
// 查询
handleSearch() {
this.selectList = []
this.refreshId()
const { ansibleTableRef, saltTableRef } = this.$refs
if (this.typeName == 'Ansible') ansibleTableRef.handleSearch()
else saltTableRef.handleSearch()
},
// 新增worker分组
add(flag) {
this.flag = flag
this.addScriptGroup = {}
this.dialogStatus = 'create'
this.parentId = '0'
this.addScriptGroupVisible = true
},
// 保存新增的worker分组
addScriptGroupSubmit() {
const that = this
this.$refs.addScriptGroup.validate((valid) => {
if (valid) {
const editObj = ['name', 'code', 'remark']
const param = {}
for (const a in editObj) {
const attr = editObj[a]
param[attr] = that.addScriptGroup[attr]
}
let service = ''
if (that.dialogStatus === 'update') {
service = updateBsmHostGroup
param.id = this.groupId
} else {
service = createBsmHostGroup
}
service(param).then((data) => {
if (data.success) {
that.$notify({
message: data.message,
type: 'success',
})
that.addScriptGroupVisible = false
if (that.flag === '2') {
that.nodedata = param
}
that.getTreeData()
}
})
}
})
},
// 详情
getDetail(id) {
this.listQuery.version = ''
this.activeName = 'storage'
getWorkerDetail(id).then((data) => {
if (data.success) {
this.addScript = Object.assign({}, data.data)
this.addScript.id = id
this.addScript.groupIds = [this.addScript.groupIds]
this.detailFlag = true
}
})
},
goBack() {
this.detailFlag = false
},
async getSaltMasterList() {
this.selectList = []
this.refreshId()
this.saltMasterLoading = true
const data = await getWorkers(this.paramt)
if (data.success) {
this.saltMasterList = data.data.rows
this.saltMasterTotal = data.data.total
this.saltMasterLoading = false
}
},
// 新增编辑
handleCreate(row, flag) {
this.addWorkerData = {
content: '',
}
this.source = '1'
switch (flag) {
case 1:
this.dialogStatus = 'create'
this.addWorkerData = {
instance: '',
category: 'SaltMaster',
protocol: '',
username: '',
password: '',
}
break
case 2:
this.dialogStatus = 'update'
this.addWorkerData = row
this.addWorkerData.password = crypto.decrypt(this.addWorkerData.password)
break
}
this.addWorkerVisible = true
},
handleDelete(id) {
this.$confirm('您确定要删除该网段吗?', '提示', {
type: 'warning',
})
.then(() => {
deleteBsmHostWorker(id).then((data) => {
if (data.success) {
this.$message.success({
message: data.message,
type: 'success',
})
this.getSaltMasterList()
}
})
})
.catch(() => {})
},
// 保存worker
addWorkerSubmit() {
const that = this
this.$refs.addWorkerData.validate((valid) => {
if (valid) {
const password = crypto.encrypt(this.addWorkerData.password)
let service
switch (this.dialogStatus) {
case 'create':
service = createBsmHostWorker
break
case 'update':
service = updateBsmHostWorker
break
}
service({ ...this.addWorkerData, password }).then((data) => {
if (data.success) {
this.$message({
message: data.message,
type: 'success',
})
that.addWorkerVisible = false
that.getSaltMasterList()
}
})
}
})
},
refreshId() {
this.idList = []
this.selectList.forEach((item) => {
this.idList.push(item.id)
})
},
// 单选
handleSelectItem(selection, row) {
this.refreshId()
if (this.idList.indexOf(row.id) > -1) {
for (let j = 0; j < this.selectList.length; j++) {
const item = this.selectList[j]
if (item.id == row.id) {
this.selectList.splice(j, 1)
break
}
}
} else {
this.selectList.push(row)
}
},
// 全选
handleSelectAll(selection) {
this.refreshId()
if (selection.length) {
// 全选情况下
selection.forEach((item) => {
if (this.idList.indexOf(item.id) == -1) {
this.selectList.push(item)
}
})
} else {
// 全不选情况下
this.list.forEach((item) => {
if (this.idList.indexOf(item.id) > -1) {
for (let j = 0; j < this.selectList.length; j++) {
const row = this.selectList[j]
if (item.id == row.id) {
this.selectList.splice(j, 1)
break
}
}
}
})
}
},
// 排除恢复
handleConfig(row, type) {
this.refreshId()
const { isExclude = type } = row
this.$confirm(`您确定要${(!type && isExclude) || type == 'recovery' ? '恢复' : '排除'}吗?`, '提示', {
confirmButtonClass: 'el-button--danger',
type: 'warning',
})
.then(async () => {
const { success, message } = await updateWorkersConfig((!type && isExclude) || type == 'recovery' ? 'recovery' : 'exclude', {
workerIds: type ? this.idList : [row.id],
})
if (!success) return
this.$message.success({
message: message,
type: 'success',
})
this.selectList = []
this.getList()
})
.catch(() => {})
},
handleDeployGaia() {
this.gaiaDialog = {
visible: true,
record: {},
isDeploy: true,
}
},
handleDelGaia(row) {
this.gaiaDialog = {
visible: true,
record: { ...row },
}
},
},
}
</script>
<style scoped="scoped" lang="scss">
.code-type {
height: 35px;
padding-left: 15px;
line-height: 35px;
border: 1px solid #ddd;
}
.operate {
position: absolute !important;
z-index: 99;
}
.content {
font-size: 14px;
border: 1px solid #cccccc;
min-height: 50px;
max-height: 300px;
padding: 10px;
overflow: auto;
}
.item {
color: rgb(64 158 255);
font-size: 16px;
}
::v-deep .tree .el-tree-node__expand-icon.expanded {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
::v-deep .el-icon-caret-right:before {
content: '\e6e0';
font-size: 14px;
}
::v-deep .el-tree-node__content {
position: relative;
height: 32px;
line-height: 32px;
.operate-btns {
position: absolute;
right: 2px;
display: none;
}
//
&:hover,
:focus-within {
.operate-btns {
display: inline;
}
}
}
</style>