mirror of https://github.com/veops/cmdb.git
commit
20caae8263
|
@ -10,7 +10,10 @@
|
|||
</div>
|
||||
<div class="attribute-card_value-type">{{ valueTypeMap[property.value_type] }}</div>
|
||||
</div>
|
||||
<div class="attribute-card-trigger" v-if="property.value_type === '3' || property.value_type === '4'">
|
||||
<div
|
||||
class="attribute-card-trigger"
|
||||
v-if="(property.value_type === '3' || property.value_type === '4') && !isStore"
|
||||
>
|
||||
<a @click="openTrigger"><ops-icon type="ops-trigger"/></a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -47,7 +50,7 @@
|
|||
</a-popover>
|
||||
|
||||
<a-space class="attribute-card-operation">
|
||||
<a><a-icon type="edit" @click="handleEdit"/></a>
|
||||
<a v-if="!isStore"><a-icon type="edit" @click="handleEdit"/></a>
|
||||
<a style="color:red;"><a-icon type="delete" @click="handleDelete"/></a>
|
||||
</a-space>
|
||||
</div>
|
||||
|
@ -56,7 +59,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { deleteCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
||||
import { deleteCITypeAttributesById, deleteAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
||||
import ValueTypeIcon from '@/components/CMDBValueTypeMapIcon'
|
||||
import {
|
||||
ops_default_show,
|
||||
|
@ -92,6 +95,10 @@ export default {
|
|||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
isStore: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
const propertyList = [
|
||||
|
@ -140,10 +147,17 @@ export default {
|
|||
title: '警告',
|
||||
content: `确认删除 【${that.property.alias || that.property.name}】?`,
|
||||
onOk() {
|
||||
if (that.isStore) {
|
||||
deleteAttributesById(that.property.id).then(() => {
|
||||
that.$message.success('删除成功!')
|
||||
that.$emit('ok')
|
||||
})
|
||||
} else {
|
||||
deleteCITypeAttributesById(that.CITypeId, { attr_id: [that.property.id] }).then(() => {
|
||||
that.$message.success('删除成功!')
|
||||
that.$emit('ok')
|
||||
})
|
||||
}
|
||||
},
|
||||
onCancel() {},
|
||||
})
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
<template>
|
||||
<a-modal wrapClassName="attrbute-store-wrapper" width="80%" :visible="visible" @cancel="handleCancel">
|
||||
<template slot="title">
|
||||
<div class="attrbute-store-header">
|
||||
<span>属性库</span>
|
||||
<div class="attrbute-store-search">
|
||||
<a-input-group compact>
|
||||
<a-select class="attrbute-store-search-select" v-model="searchKey">
|
||||
<a-select-option value="alias">
|
||||
别名
|
||||
</a-select-option>
|
||||
<a-select-option value="name">
|
||||
名称
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-input
|
||||
ref="input"
|
||||
slot="default"
|
||||
class="attrbute-store-search-input"
|
||||
v-model="searchValue"
|
||||
@pressEnter="pressEnter"
|
||||
allowClear
|
||||
@change="handleInput"
|
||||
>
|
||||
<a-icon slot="suffix" type="search" @click="pressEnter" :style="{ cursor: 'pointer' }" />
|
||||
</a-input>
|
||||
</a-input-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<a-spin :spinning="loading" :style="{ height: '100%' }">
|
||||
<a-row v-if="attrList.length">
|
||||
<a-col
|
||||
class="attrbute-store-col"
|
||||
:xxl="4"
|
||||
:xl="6"
|
||||
:lg="8"
|
||||
:md="12"
|
||||
:sm="24"
|
||||
v-for="item in attrList"
|
||||
:key="item.id"
|
||||
>
|
||||
<AttributeCard
|
||||
@ok="
|
||||
() => {
|
||||
searchAttributes()
|
||||
}
|
||||
"
|
||||
:isStore="true"
|
||||
:property="item"
|
||||
/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-empty v-else>
|
||||
<img slot="image" :src="require('@/assets/data_empty.png')" />
|
||||
<span slot="description"> 暂无数据 </span>
|
||||
</a-empty>
|
||||
</a-spin>
|
||||
<template slot="footer">
|
||||
<a-pagination
|
||||
size="small"
|
||||
show-size-changer
|
||||
show-quick-jumper
|
||||
:current="tablePage.currentPage"
|
||||
:total="tablePage.totalResult"
|
||||
:show-total="(total, range) => `当前展示 ${range[0]}-${range[1]} 条数据, 共 ${total} 条`"
|
||||
:page-size="tablePage.pageSize"
|
||||
:default-current="1"
|
||||
@change="pageOrSizeChange"
|
||||
@showSizeChange="pageOrSizeChange"
|
||||
:pageSizeOptions="['20', '50', '100', '200']"
|
||||
/>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { searchAttributes } from '../../api/CITypeAttr'
|
||||
import AttributeCard from './attributeCard.vue'
|
||||
export default {
|
||||
name: 'AttributeStore',
|
||||
components: { AttributeCard },
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
attrList: [],
|
||||
tablePage: {
|
||||
currentPage: 1,
|
||||
pageSize: 50,
|
||||
totalResult: 0,
|
||||
},
|
||||
loading: false,
|
||||
searchKey: 'alias',
|
||||
searchValue: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.visible = true
|
||||
this.searchAttributes()
|
||||
},
|
||||
handleCancel() {
|
||||
this.visible = false
|
||||
},
|
||||
async searchAttributes(currentPage = 1, pageSize = this.tablePage.pageSize) {
|
||||
this.loading = true
|
||||
const params = {
|
||||
page: currentPage,
|
||||
page_size: pageSize,
|
||||
}
|
||||
if (this.searchKey && this.searchValue) {
|
||||
params[this.searchKey] = this.searchValue
|
||||
}
|
||||
searchAttributes(params)
|
||||
.then((res) => {
|
||||
this.attrList = res.attributes
|
||||
this.tablePage = {
|
||||
...this.tablePage,
|
||||
currentPage: res.page,
|
||||
pageSize: res.page_size,
|
||||
totalResult: res.numfound,
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
pageOrSizeChange(currentPage, pageSize) {
|
||||
this.searchAttributes(currentPage, pageSize)
|
||||
},
|
||||
pressEnter() {
|
||||
this.searchAttributes(1)
|
||||
},
|
||||
handleInput(e) {
|
||||
if (!e.target.value) {
|
||||
this.pressEnter()
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.attrbute-store-wrapper {
|
||||
.attrbute-store-col {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.attrbute-store-wrapper {
|
||||
.ant-modal-body {
|
||||
height: 70vh;
|
||||
overflow: auto;
|
||||
}
|
||||
.attrbute-store-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
@import '~@/style/static.less';
|
||||
|
||||
.attrbute-store-search {
|
||||
width: 300px;
|
||||
display: inline-block;
|
||||
margin-right: 60px;
|
||||
.ant-input-group.ant-input-group-compact > *:first-child,
|
||||
.ant-input-group.ant-input-group-compact > .ant-select:first-child > .ant-select-selection {
|
||||
border-top-left-radius: 20px !important;
|
||||
border-bottom-left-radius: 20px !important;
|
||||
background-color: #custom_colors[color_1];
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
.ant-select-focused .ant-select-selection,
|
||||
.ant-select-selection:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
.ant-select-selection__rendered {
|
||||
margin-right: 12px;
|
||||
}
|
||||
.ant-select-arrow {
|
||||
color: #fff;
|
||||
font-size: 10px;
|
||||
right: 8px;
|
||||
}
|
||||
.attrbute-store-search-select {
|
||||
width: 65px;
|
||||
.ant-select-selection-selected-value {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.attrbute-store-search-input {
|
||||
display: inline-block;
|
||||
width: calc(100% - 65px);
|
||||
.ant-input {
|
||||
background-color: #f0f5ff;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -25,7 +25,19 @@
|
|||
class="ops-button-primary"
|
||||
>分组</a-button
|
||||
>
|
||||
<a-space v-if="permissions.includes('admin') || permissions.includes('cmdb_admin')">
|
||||
<a-space>
|
||||
<a
|
||||
@click="
|
||||
() => {
|
||||
$refs.attributeStore.open()
|
||||
}
|
||||
"
|
||||
>属性库</a
|
||||
>
|
||||
<a-dropdown v-if="permissions.includes('admin') || permissions.includes('cmdb_admin')">
|
||||
<a><ops-icon type="ops-menu"/></a>
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item key="0">
|
||||
<a-upload
|
||||
name="file"
|
||||
accept="json"
|
||||
|
@ -33,17 +45,29 @@
|
|||
style="display: inline-block"
|
||||
action="/api/v0.1/ci_types/template/import/file "
|
||||
>
|
||||
<a>导入</a>
|
||||
<a-space
|
||||
><a><a-icon type="upload"/></a><a>导入</a></a-space
|
||||
>
|
||||
</a-upload>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="1">
|
||||
<a-space>
|
||||
<a><a-icon type="download"/></a>
|
||||
<a href="/api/v0.1/ci_types/template/export/file">导出</a>
|
||||
</a-space>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
</a-space>
|
||||
</div>
|
||||
<draggable class="ci-types-left-content" :list="CITypeGroups" @end="handleChangeGroups" filter=".undraggable">
|
||||
<div v-for="g in CITypeGroups" :key="g.id || g.name">
|
||||
<div
|
||||
:class="`${currentGId === g.id && !currentCId ? 'selected' : ''} ci-types-left-group ${
|
||||
:class="
|
||||
`${currentGId === g.id && !currentCId ? 'selected' : ''} ci-types-left-group ${
|
||||
g.id === -1 ? 'undraggable' : ''
|
||||
}`"
|
||||
}`
|
||||
"
|
||||
@click="handleClickGroup(g.id)"
|
||||
>
|
||||
<div>
|
||||
|
@ -185,8 +209,12 @@
|
|||
<a-divider :style="{ margin: '5px 0' }" />
|
||||
<div :style="{ textAlign: 'right' }">
|
||||
<a-radio-group v-model="default_order_asc">
|
||||
<a-radio value="1"> 正序 </a-radio>
|
||||
<a-radio value="2"> 倒序 </a-radio>
|
||||
<a-radio value="1">
|
||||
正序
|
||||
</a-radio>
|
||||
<a-radio value="2">
|
||||
倒序
|
||||
</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</el-select>
|
||||
|
@ -230,6 +258,7 @@
|
|||
</a-form>
|
||||
</CustomDrawer>
|
||||
<CMDBGrant ref="cmdbGrant" resourceType="CIType" app_id="cmdb" />
|
||||
<AttributeStore ref="attributeStore" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -257,6 +286,7 @@ import IconArea from './iconArea.vue'
|
|||
import SplitPane from '@/components/SplitPane'
|
||||
import CMDBGrant from '../../components/cmdbGrant'
|
||||
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
|
||||
import AttributeStore from './attributeStore.vue'
|
||||
|
||||
export default {
|
||||
name: 'CITypes',
|
||||
|
@ -270,6 +300,7 @@ export default {
|
|||
IconArea,
|
||||
SplitPane,
|
||||
OpsMoveIcon,
|
||||
AttributeStore,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -589,7 +620,6 @@ export default {
|
|||
}
|
||||
},
|
||||
async handleChangeCITypes(e, g) {
|
||||
console.log(111, g)
|
||||
if (g.id && g.id !== -1) {
|
||||
putCITypeGroupByGId(g.id, { name: g.name, type_ids: g.ci_types.map((i) => i.id) })
|
||||
.then(() => {
|
||||
|
@ -613,7 +643,6 @@ export default {
|
|||
const { type_id } = await createCIType(data).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
console.log(111)
|
||||
this.$message.success(`添加成功`)
|
||||
if (this.selectGroup && this.selectGroup.id && this.selectGroup.id !== -1) {
|
||||
const ids = this.selectGroup.ci_types.map((i) => i.id)
|
||||
|
|
|
@ -91,13 +91,8 @@ export default {
|
|||
})
|
||||
},
|
||||
},
|
||||
beforeMount() {
|
||||
this.loadTotalAttrs()
|
||||
},
|
||||
methods: {
|
||||
async handleSubmit(isCloseModal = true) {
|
||||
console.log(this.targetKeys)
|
||||
|
||||
if (this.activeKey === '2') {
|
||||
if (this.targetKeys.length) {
|
||||
this.confirmLoading = true
|
||||
|
@ -125,6 +120,7 @@ export default {
|
|||
this.visible = true
|
||||
this.currentGroup = group
|
||||
this.activeKey = '1'
|
||||
this.loadTotalAttrs()
|
||||
this.$nextTick(() => {
|
||||
this.$refs.createNewAttribute.checkCanDefineComputed()
|
||||
})
|
||||
|
|
|
@ -90,7 +90,12 @@ export default {
|
|||
)
|
||||
},
|
||||
},
|
||||
inject: ['refresh'],
|
||||
inject: {
|
||||
refresh: {
|
||||
from: 'refresh',
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
createFromTriggerTable(canAddTriggerAttr) {
|
||||
this.visible = true
|
||||
|
@ -163,8 +168,10 @@ export default {
|
|||
await addTrigger(this.CITypeId, params)
|
||||
}
|
||||
this.handleCancel()
|
||||
if (this.refresh) {
|
||||
this.refresh()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDetele() {
|
||||
|
@ -176,7 +183,9 @@ export default {
|
|||
deleteTrigger(that.CITypeId, that.triggerId).then(() => {
|
||||
that.$message.success('删除成功!')
|
||||
that.handleCancel()
|
||||
if (that.refresh) {
|
||||
that.refresh()
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<a-card :bordered="false">
|
||||
<div class="model-relation">
|
||||
<a-button @click="handleCreate" type="primary" style="margin-bottom: 15px;" icon="plus">新增关系</a-button>
|
||||
<model-relation-table ref="table"></model-relation-table>
|
||||
<a-modal
|
||||
|
@ -59,7 +58,6 @@
|
|||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -110,16 +108,13 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
const _currentId = localStorage.getItem('ops_cityps_currentId')
|
||||
console.log(_currentId)
|
||||
if (_currentId) {
|
||||
this.currentId = _currentId
|
||||
}
|
||||
searchResourceType({ page_size: 9999, app_id: 'cmdb' }).then((res) => {
|
||||
console.log('searchResourceType', res)
|
||||
this.resource_type = { groups: res.groups, id2perms: res.id2perms }
|
||||
})
|
||||
this.loadCITypes(!_currentId)
|
||||
console.log(this.CITypeId)
|
||||
},
|
||||
computed: {
|
||||
currentCId() {
|
||||
|
@ -168,7 +163,6 @@ export default {
|
|||
},
|
||||
getCITypes() {
|
||||
getCITypes().then((res) => {
|
||||
console.log('getCITypes', res.ci_types)
|
||||
this.CITypes = res.ci_types
|
||||
})
|
||||
},
|
||||
|
@ -196,9 +190,6 @@ export default {
|
|||
e.preventDefault()
|
||||
this.form.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Received values of form: ', values)
|
||||
|
||||
createRelation(values.source_ci_type_id, values.ci_type_id, values.relation_type_id, values.constraint).then(
|
||||
(res) => {
|
||||
this.$message.success(`添加成功`)
|
||||
|
@ -215,8 +206,6 @@ export default {
|
|||
this.$refs.table.refresh()
|
||||
},
|
||||
handleDelete(record) {
|
||||
console.log(record)
|
||||
|
||||
deleteRelation(record.source_ci_type_id, record.id).then((res) => {
|
||||
this.$message.success(`删除成功!`)
|
||||
|
||||
|
@ -236,4 +225,12 @@ export default {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style lang="less" scoped>
|
||||
.model-relation {
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
padding: 24px;
|
||||
height: calc(100vh - 64px);
|
||||
margin-bottom: -24px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
<template>
|
||||
<div>
|
||||
<vxe-table
|
||||
ref="xTable"
|
||||
stripe
|
||||
class="ops-stripe-table"
|
||||
show-header-overflow
|
||||
show-overflow
|
||||
resizable
|
||||
:max-height="`${windowHeight - 183}px`"
|
||||
:height="`${windowHeight - 160}px`"
|
||||
:data="tableData"
|
||||
:sort-config="{ defaultSort: { field: 'created_at', order: 'desc' } }"
|
||||
>
|
||||
|
@ -16,21 +17,8 @@
|
|||
field="relation_type_id"
|
||||
title="关系"
|
||||
:filters="[{ data: '' }]"
|
||||
:filter-method="filterRelationMethod"
|
||||
:filter-recover-method="filterRelationRecoverMethod"
|
||||
:filter-multiple="false"
|
||||
>
|
||||
<template #filter="{ $panel, column }">
|
||||
<template v-for="(option, index) in column.filters">
|
||||
<input
|
||||
type="type"
|
||||
:key="index"
|
||||
v-model="option.data"
|
||||
@input="$panel.changeOption($event, !!option.data, option)"
|
||||
@keyup.enter="$panel.confirmFilter()"
|
||||
placeholder="按回车确认筛选"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
<template #default="{ row }">
|
||||
<a-tag color="cyan">
|
||||
{{ row.relation_type.name }}
|
||||
|
@ -39,9 +27,14 @@
|
|||
</vxe-column>
|
||||
<vxe-column field="child.alias" title="目标模型"></vxe-column>
|
||||
<vxe-column field="constraint" title="关联约束"></vxe-column>
|
||||
<vxe-column field="authorization" title="授权" width="89px">
|
||||
<vxe-column field="authorization" title="操作" width="89px">
|
||||
<template #default="{ row }">
|
||||
<a-space>
|
||||
<a @click="handleOpenGrant(row)"><a-icon type="user-add"/></a>
|
||||
<a-popconfirm title="确认删除?" @confirm="deleteRelation(row)">
|
||||
<a :style="{ color: 'red' }"><ops-icon type="icon-xianxing-delete"/></a>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
|
@ -50,7 +43,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { getCITypeRelations } from '@/modules/cmdb/api/CITypeRelation'
|
||||
import { getCITypeRelations, deleteRelation } from '@/modules/cmdb/api/CITypeRelation'
|
||||
import { getRelationTypes } from '@/modules/cmdb/api/relationType'
|
||||
import CMDBGrant from '../../../components/cmdbGrant'
|
||||
|
||||
|
@ -86,40 +79,35 @@ export default {
|
|||
item.constraint = this.handleConstraint(item.constraint)
|
||||
})
|
||||
this.tableData = res
|
||||
console.log('MainData', res)
|
||||
},
|
||||
// 获取关系
|
||||
async getRelationTypes() {
|
||||
const res = await getRelationTypes()
|
||||
const relationTypeMap = new Map()
|
||||
res.forEach((item) => {
|
||||
relationTypeMap.set(item.id, item.name)
|
||||
})
|
||||
this.relationTypeList = relationTypeMap
|
||||
console.log('relationTypeList', this.relationTypeList)
|
||||
this.relationTypeList = res.map((item) => ({ value: item.id, label: item.name }))
|
||||
const $table = this.$refs.xTable
|
||||
if ($table) {
|
||||
const nameColumn = $table.getColumnByField('relation_type_id')
|
||||
if (nameColumn) {
|
||||
$table.setFilter(nameColumn, this.relationTypeList)
|
||||
}
|
||||
}
|
||||
},
|
||||
// 转换关联关系
|
||||
handleConstraint(constraintId) {
|
||||
return this.constraintMap[constraintId]
|
||||
},
|
||||
handleOpenGrant(record) {
|
||||
console.log('record', record)
|
||||
console.log(`${record.parent.name} -> ${record.child.name}`)
|
||||
// this.$refs.grantDrawer.open({ name: `${record.parent.name} -> ${record.child.name}` })
|
||||
this.$refs.cmdbGrant.open({
|
||||
name: `${record.parent.name} -> ${record.child.name}`,
|
||||
typeRelationIds: [record.parent_id, record.child_id],
|
||||
cmdbGrantType: 'type_relation',
|
||||
})
|
||||
},
|
||||
filterRelationMethod({ option, row }) {
|
||||
return row.relation_type.name.includes(String(option.data))
|
||||
},
|
||||
filterRelationRecoverMethod({ option }) {
|
||||
option.data = ''
|
||||
},
|
||||
refresh() {
|
||||
this.getMainData()
|
||||
deleteRelation(row) {
|
||||
deleteRelation(row.parent_id, row.child_id).then((res) => {
|
||||
this.$message.success(`删除成功!`)
|
||||
this.getRelationTypes()
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue