mirror of https://github.com/veops/cmdb.git
UI: relation type define [done]
This commit is contained in:
parent
ba80ec4403
commit
0a563deb11
|
@ -119,11 +119,12 @@ class PreferenceManager(object):
|
||||||
|
|
||||||
id2type = dict()
|
id2type = dict()
|
||||||
for view_name in result:
|
for view_name in result:
|
||||||
result[view_name] = toposort.toposort_flatten(
|
|
||||||
{i['child_id']: {i['parent_id']} for i in result[view_name]})
|
|
||||||
for i in result[view_name]:
|
for i in result[view_name]:
|
||||||
id2type[i['parent_id']] = None
|
id2type[i['parent_id']] = None
|
||||||
id2type[i['child']] = None
|
id2type[i['child_id']] = None
|
||||||
|
|
||||||
|
result[view_name] = toposort.toposort_flatten(
|
||||||
|
{i['child_id']: {i['parent_id']} for i in result[view_name]})
|
||||||
|
|
||||||
for type_id in id2type:
|
for type_id in id2type:
|
||||||
id2type[type_id] = CITypeCache.get(type_id).to_dict()
|
id2type[type_id] = CITypeCache.get(type_id).to_dict()
|
||||||
|
|
|
@ -15,14 +15,6 @@ export function getCITypeParent (CITypeID) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRelationTypes (CITypeID, parameter) {
|
|
||||||
return axios({
|
|
||||||
url: '/v0.1/relation_types',
|
|
||||||
method: 'get',
|
|
||||||
params: parameter
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createRelation (parentId, childrenId, relationTypeId) {
|
export function createRelation (parentId, childrenId, relationTypeId) {
|
||||||
return axios({
|
return axios({
|
||||||
url: `/v0.1/ci_type_relations/${parentId}/${childrenId}`,
|
url: `/v0.1/ci_type_relations/${parentId}/${childrenId}`,
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { axios } from '@/utils/request'
|
||||||
|
|
||||||
|
export function getRelationTypes () {
|
||||||
|
return axios({
|
||||||
|
url: '/v0.1/relation_types',
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addRelationType (payload) {
|
||||||
|
return axios({
|
||||||
|
url: `/v0.1/relation_types`,
|
||||||
|
method: 'POST',
|
||||||
|
data: payload
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateRelationType (rtId, payload) {
|
||||||
|
return axios({
|
||||||
|
url: `/v0.1/relation_types/${rtId}`,
|
||||||
|
method: 'PUT',
|
||||||
|
data: payload
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteRelationType (rtId) {
|
||||||
|
return axios({
|
||||||
|
url: `/v0.1/relation_types/${rtId}`,
|
||||||
|
method: 'DELETE'
|
||||||
|
})
|
||||||
|
}
|
|
@ -12,7 +12,23 @@ const cmdbRouter = [
|
||||||
name: 'cmdb_preference',
|
name: 'cmdb_preference',
|
||||||
meta: { title: '我的订阅', icon: 'book', keepAlive: true }
|
meta: { title: '我的订阅', icon: 'book', keepAlive: true }
|
||||||
},
|
},
|
||||||
// views
|
// relation views
|
||||||
|
{
|
||||||
|
path: '/relation_views',
|
||||||
|
component: () => import('@/views/cmdb/relation_views'),
|
||||||
|
name: 'cmdb_relation_views',
|
||||||
|
meta: { title: '关系视图', icon: 'link', keepAlive: true },
|
||||||
|
hideChildrenInMenu: true,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/relation_views/:id',
|
||||||
|
name: 'cmdb_relation_views_item',
|
||||||
|
component: () => import('@/views/cmdb/relation_views'),
|
||||||
|
meta: { title: '关系视图', keepAlive: true },
|
||||||
|
hidden: true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
// tree views
|
||||||
{
|
{
|
||||||
path: '/tree_views',
|
path: '/tree_views',
|
||||||
component: () => import('@/views/cmdb/tree_views'),
|
component: () => import('@/views/cmdb/tree_views'),
|
||||||
|
@ -36,33 +52,47 @@ const cmdbRouter = [
|
||||||
meta: { 'title': '批量导入', icon: 'upload', keepAlive: true }
|
meta: { 'title': '批量导入', icon: 'upload', keepAlive: true }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/ci_types',
|
path: '/config//ci_types',
|
||||||
name: 'cmdb_ci_type',
|
name: 'cmdb_ci_type',
|
||||||
component: RouteView,
|
component: RouteView,
|
||||||
redirect: '/ci_type',
|
redirect: '/ci_types',
|
||||||
meta: { title: '模型配置', icon: 'setting', permission: ['admin'] },
|
meta: { title: '模型配置', icon: 'setting', permission: ['admin'] },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/ci_types',
|
path: '/config/ci_types',
|
||||||
name: 'ci_type',
|
name: 'ci_type',
|
||||||
hideChildrenInMenu: true, // 强制显示 MenuItem 而不是 SubMenu
|
hideChildrenInMenu: true,
|
||||||
component: () => import('@/views/cmdb/ci_type/list'),
|
component: () => import('@/views/cmdb/model_config/ci_type/list'),
|
||||||
meta: { title: '模型定义', keepAlive: true }
|
meta: { title: '模型管理', keepAlive: true }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/ci_types/:CITypeName/detail/:CITypeId',
|
path: '/config/ci_types/:CITypeName/detail/:CITypeId',
|
||||||
name: 'ci_type_detail',
|
name: 'ci_type_detail',
|
||||||
hideChildrenInMenu: true, // 强制显示 MenuItem 而不是 SubMenu
|
hideChildrenInMenu: true,
|
||||||
component: () => import('@/views/cmdb/ci_type/detail'),
|
component: () => import('@/views/cmdb/model_config/ci_type/detail'),
|
||||||
meta: { title: '模型配置', keepAlive: true, hidden: true },
|
meta: { title: '模型管理', keepAlive: true, hidden: true },
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/attributes',
|
path: '/config/attributes',
|
||||||
name: 'attributes',
|
name: 'attributes',
|
||||||
hideChildrenInMenu: true, // 强制显示 MenuItem 而不是 SubMenu
|
hideChildrenInMenu: true,
|
||||||
component: () => import('@/views/cmdb/attributes/index'),
|
component: () => import('@/views/cmdb/model_config/attributes/index'),
|
||||||
meta: { title: '属性库', keepAlive: true }
|
meta: { title: '属性库', keepAlive: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/config/relation_type',
|
||||||
|
name: 'relation_type',
|
||||||
|
hideChildrenInMenu: true,
|
||||||
|
component: () => import('@/views/cmdb/model_config/relation_type/index'),
|
||||||
|
meta: { title: '关系类型', keepAlive: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/config/preference_relation',
|
||||||
|
name: 'preference_relation',
|
||||||
|
hideChildrenInMenu: true,
|
||||||
|
component: () => import('@/views/cmdb/model_config/preference_relation/index'),
|
||||||
|
meta: { title: '关系视图配置', keepAlive: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -128,7 +158,7 @@ export const generatorDynamicRouter = () => {
|
||||||
component: () => import(`@/views/cmdb/ci/index`),
|
component: () => import(`@/views/cmdb/ci/index`),
|
||||||
name: `cmdb_${item.id}`,
|
name: `cmdb_${item.id}`,
|
||||||
meta: { title: item.alias, icon: 'table', keepAlive: true, typeId: item.id },
|
meta: { title: item.alias, icon: 'table', keepAlive: true, typeId: item.id },
|
||||||
hideChildrenInMenu: true // 强制显示 MenuItem 而不是 SubMenu
|
hideChildrenInMenu: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,8 +143,8 @@ import {
|
||||||
} from '@/api/cmdb/CITypeAttr'
|
} from '@/api/cmdb/CITypeAttr'
|
||||||
import { STable } from '@/components'
|
import { STable } from '@/components'
|
||||||
import { mixin, mixinDevice } from '@/utils/mixin'
|
import { mixin, mixinDevice } from '@/utils/mixin'
|
||||||
import AttributeForm from '@/views/cmdb/attributes/module/attributeForm'
|
import AttributeForm from '@/views/cmdb/model_config/attributes/module/attributeForm'
|
||||||
import { valueTypeMap } from '@/views/cmdb/attributes/module/const'
|
import { valueTypeMap } from '@/views/cmdb/model_config/attributes/module/const'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AttributesTable',
|
name: 'AttributesTable',
|
|
@ -103,7 +103,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { createRelation, deleteRelation, getCITypeChildren, getRelationTypes } from '@/api/cmdb/CITypeRelation'
|
import { createRelation, deleteRelation, getCITypeChildren } from '@/api/cmdb/CITypeRelation'
|
||||||
|
import { getRelationTypes } from '@/api/cmdb/relationType'
|
||||||
import { getCITypes } from '@/api/cmdb/CIType'
|
import { getCITypes } from '@/api/cmdb/CIType'
|
||||||
|
|
||||||
import { STable } from '@/components'
|
import { STable } from '@/components'
|
|
@ -0,0 +1,6 @@
|
||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {}
|
||||||
|
</script>
|
|
@ -0,0 +1,280 @@
|
||||||
|
<template>
|
||||||
|
<a-card :bordered="false">
|
||||||
|
|
||||||
|
<div class="action-btn">
|
||||||
|
<a-button @click="handleCreate" type="primary" style="margin-right: 0.3rem;">{{ btnName }}</a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<s-table
|
||||||
|
:alert="options.alert"
|
||||||
|
:columns="columns"
|
||||||
|
:data="loadData"
|
||||||
|
:pagination="{ showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条记录`, pageSizeOptions: pageSizeOptions}"
|
||||||
|
:showPagination="false"
|
||||||
|
:pageSize="25"
|
||||||
|
:rowKey="record=>record.id"
|
||||||
|
:rowSelection="options.rowSelection"
|
||||||
|
:scroll="scroll"
|
||||||
|
ref="table"
|
||||||
|
size="middle"
|
||||||
|
|
||||||
|
>
|
||||||
|
<div slot="filterDropdown" slot-scope="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }" class="custom-filter-dropdown">
|
||||||
|
<a-input
|
||||||
|
v-ant-ref="c => searchInput = c"
|
||||||
|
:placeholder="` ${column.title}`"
|
||||||
|
:value="selectedKeys[0]"
|
||||||
|
@change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
|
||||||
|
@pressEnter="() => handleSearch(selectedKeys, confirm, column)"
|
||||||
|
style="width: 188px; margin-bottom: 8px; display: block;"
|
||||||
|
/>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
@click="() => handleSearch(selectedKeys, confirm, column)"
|
||||||
|
icon="search"
|
||||||
|
size="small"
|
||||||
|
style="width: 90px; margin-right: 8px"
|
||||||
|
>搜索</a-button>
|
||||||
|
<a-button
|
||||||
|
@click="() => handleReset(clearFilters, column)"
|
||||||
|
size="small"
|
||||||
|
style="width: 90px"
|
||||||
|
>重置</a-button>
|
||||||
|
</div>
|
||||||
|
<a-icon slot="filterIcon" slot-scope="filtered" type="search" :style="{ color: filtered ? '#108ee9' : undefined }" />
|
||||||
|
|
||||||
|
<template slot="nameSearchRender" slot-scope="text">
|
||||||
|
<span v-if="columnSearchText.name">
|
||||||
|
<template v-for="(fragment, i) in text.toString().split(new RegExp(`(?<=${columnSearchText.name})|(?=${columnSearchText.name})`, 'i'))">
|
||||||
|
<mark v-if="fragment.toLowerCase() === columnSearchText.name.toLowerCase()" :key="i" class="highlight">{{ fragment }}</mark>
|
||||||
|
<template v-else>{{ fragment }}</template>
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
<template v-else>{{ text }}</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template slot="description" slot-scope="text">{{ text }}</template>
|
||||||
|
|
||||||
|
<span slot="action" slot-scope="text, record">
|
||||||
|
<template>
|
||||||
|
<a @click="handleEdit(record)">编辑</a>
|
||||||
|
<a-divider type="vertical"/>
|
||||||
|
|
||||||
|
<a-popconfirm
|
||||||
|
title="确认删除?"
|
||||||
|
@confirm="handleDelete(record)"
|
||||||
|
@cancel="cancel"
|
||||||
|
okText="是"
|
||||||
|
cancelText="否"
|
||||||
|
>
|
||||||
|
<a>删除</a>
|
||||||
|
</a-popconfirm>
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</s-table>
|
||||||
|
<relation-type-form ref="relationTypeForm" :handleOk="handleOk"> </relation-type-form>
|
||||||
|
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { STable } from '@/components'
|
||||||
|
import RelationTypeForm from './module/relationTypeForm'
|
||||||
|
import { getRelationTypes, deleteRelationType } from '@/api/cmdb/relationType'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Index',
|
||||||
|
components: {
|
||||||
|
STable,
|
||||||
|
RelationTypeForm
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
scroll: { x: 1000, y: 500 },
|
||||||
|
btnName: '新增关系类型',
|
||||||
|
|
||||||
|
formLayout: 'vertical',
|
||||||
|
|
||||||
|
pageSizeOptions: ['10', '25', '50', '100'],
|
||||||
|
|
||||||
|
columnSearchText: {
|
||||||
|
name: ''
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
width: 150,
|
||||||
|
title: '类型名',
|
||||||
|
dataIndex: 'name',
|
||||||
|
sorter: false,
|
||||||
|
scopedSlots: {
|
||||||
|
customRender: 'nameSearchRender',
|
||||||
|
filterDropdown: 'filterDropdown',
|
||||||
|
filterIcon: 'filterIcon'
|
||||||
|
},
|
||||||
|
onFilter: (value, record) => record.name && record.name.toLowerCase().includes(value.toLowerCase()),
|
||||||
|
onFilterDropdownVisibleChange: (visible) => {
|
||||||
|
if (visible) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.searchInput.focus()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
width: 150,
|
||||||
|
title: '操作',
|
||||||
|
key: 'operation',
|
||||||
|
scopedSlots: { customRender: 'action' }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
loadData: parameter => {
|
||||||
|
return getRelationTypes()
|
||||||
|
.then(res => {
|
||||||
|
const result = {}
|
||||||
|
result.data = res
|
||||||
|
console.log('loadData.res', result)
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
mdl: {},
|
||||||
|
// 高级搜索 展开/关闭
|
||||||
|
advanced: false,
|
||||||
|
// 查询参数
|
||||||
|
queryParam: {},
|
||||||
|
// 表头
|
||||||
|
|
||||||
|
selectedRowKeys: [],
|
||||||
|
selectedRows: [],
|
||||||
|
|
||||||
|
// custom table alert & rowSelection
|
||||||
|
options: {
|
||||||
|
alert: false,
|
||||||
|
rowSelection: null
|
||||||
|
},
|
||||||
|
optionAlertShow: false
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeCreate () {
|
||||||
|
this.form = this.$form.createForm(this)
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
|
||||||
|
formItemLayout () {
|
||||||
|
const { formLayout } = this
|
||||||
|
return formLayout === 'horizontal' ? {
|
||||||
|
labelCol: { span: 4 },
|
||||||
|
wrapperCol: { span: 14 }
|
||||||
|
} : {}
|
||||||
|
},
|
||||||
|
|
||||||
|
horizontalFormItemLayout () {
|
||||||
|
return {
|
||||||
|
labelCol: { span: 5 },
|
||||||
|
wrapperCol: { span: 12 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buttonItemLayout () {
|
||||||
|
const { formLayout } = this
|
||||||
|
return formLayout === 'horizontal' ? {
|
||||||
|
wrapperCol: { span: 14, offset: 4 }
|
||||||
|
} : {}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.setScrollY()
|
||||||
|
},
|
||||||
|
inject: ['reload'],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
handleSearch (selectedKeys, confirm, column) {
|
||||||
|
confirm()
|
||||||
|
this.columnSearchText[column.dataIndex] = selectedKeys[0]
|
||||||
|
this.queryParam[column.dataIndex] = selectedKeys[0]
|
||||||
|
},
|
||||||
|
|
||||||
|
handleReset (clearFilters, column) {
|
||||||
|
clearFilters()
|
||||||
|
this.columnSearchText[column.dataIndex] = ''
|
||||||
|
this.queryParam[column.dataIndex] = ''
|
||||||
|
},
|
||||||
|
|
||||||
|
setScrollY () {
|
||||||
|
this.scroll.y = window.innerHeight - this.$refs.table.$el.offsetTop - 200
|
||||||
|
},
|
||||||
|
|
||||||
|
handleEdit (record) {
|
||||||
|
console.log(record)
|
||||||
|
this.$refs.relationTypeForm.handleEdit(record)
|
||||||
|
},
|
||||||
|
handleDelete (record) {
|
||||||
|
this.deleteRelationType(record.id)
|
||||||
|
},
|
||||||
|
handleOk () {
|
||||||
|
this.$refs.table.refresh()
|
||||||
|
},
|
||||||
|
|
||||||
|
handleCreate () {
|
||||||
|
this.$refs.relationTypeForm.handleCreate()
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteRelationType (id) {
|
||||||
|
deleteRelationType(id)
|
||||||
|
.then(res => {
|
||||||
|
this.$message.success(`删除成功`)
|
||||||
|
this.handleOk()
|
||||||
|
})
|
||||||
|
.catch(err => this.requestFailed(err))
|
||||||
|
},
|
||||||
|
requestFailed (err) {
|
||||||
|
const msg = ((err.response || {}).data || {}).message || '请求出现错误,请稍后再试'
|
||||||
|
this.$message.error(`${msg}`)
|
||||||
|
},
|
||||||
|
cancel () {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
watch: {}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.search {
|
||||||
|
margin-bottom: 54px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// .fold {
|
||||||
|
// width: calc(100% - 216px);
|
||||||
|
// display: inline-block
|
||||||
|
// }
|
||||||
|
|
||||||
|
.operator {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
.action-btn {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.custom-filter-dropdown {
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
background-color: rgb(255, 192, 105);
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
.fold {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,196 @@
|
||||||
|
<template>
|
||||||
|
<a-drawer
|
||||||
|
:closable="false"
|
||||||
|
:title="drawerTitle"
|
||||||
|
:visible="drawerVisible"
|
||||||
|
@close="onClose"
|
||||||
|
placement="right"
|
||||||
|
width="30%"
|
||||||
|
>
|
||||||
|
|
||||||
|
<a-form :form="form" :layout="formLayout" @submit="handleSubmit">
|
||||||
|
|
||||||
|
<a-form-item
|
||||||
|
:label-col="formItemLayout.labelCol"
|
||||||
|
:wrapper-col="formItemLayout.wrapperCol"
|
||||||
|
label="类型名"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
name="name"
|
||||||
|
placeholder=""
|
||||||
|
v-decorator="['name', {rules: [{ required: true, message: '请输入资源名'}]} ]"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item>
|
||||||
|
<a-input
|
||||||
|
name="id"
|
||||||
|
type="hidden"
|
||||||
|
v-decorator="['id', {rules: []} ]"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
position: 'absolute',
|
||||||
|
left: 0,
|
||||||
|
bottom: 0,
|
||||||
|
width: '100%',
|
||||||
|
borderTop: '1px solid #e9e9e9',
|
||||||
|
padding: '0.8rem 1rem',
|
||||||
|
background: '#fff',
|
||||||
|
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<a-button @click="handleSubmit" type="primary" style="margin-right: 1rem">确定</a-button>
|
||||||
|
<a-button @click="onClose">取消</a-button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</a-form>
|
||||||
|
</a-drawer>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { STable } from '@/components'
|
||||||
|
import { addRelationType, updateRelationType } from '@/api/cmdb/relationType'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'RelationTypeForm',
|
||||||
|
components: {
|
||||||
|
STable
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
drawerTitle: '新增关系类型',
|
||||||
|
drawerVisible: false,
|
||||||
|
formLayout: 'vertical'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeCreate () {
|
||||||
|
this.form = this.$form.createForm(this)
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
formItemLayout () {
|
||||||
|
const { formLayout } = this
|
||||||
|
return formLayout === 'horizontal' ? {
|
||||||
|
labelCol: { span: 4 },
|
||||||
|
wrapperCol: { span: 14 }
|
||||||
|
} : {}
|
||||||
|
},
|
||||||
|
|
||||||
|
horizontalFormItemLayout () {
|
||||||
|
return {
|
||||||
|
labelCol: { span: 5 },
|
||||||
|
wrapperCol: { span: 12 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buttonItemLayout () {
|
||||||
|
const { formLayout } = this
|
||||||
|
return formLayout === 'horizontal' ? {
|
||||||
|
wrapperCol: { span: 14, offset: 4 }
|
||||||
|
} : {}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleCreate () {
|
||||||
|
this.drawerVisible = true
|
||||||
|
},
|
||||||
|
onClose () {
|
||||||
|
this.form.resetFields()
|
||||||
|
this.drawerVisible = false
|
||||||
|
},
|
||||||
|
onChange (e) {
|
||||||
|
console.log(`checked = ${e}`)
|
||||||
|
},
|
||||||
|
|
||||||
|
handleEdit (record) {
|
||||||
|
this.drawerVisible = true
|
||||||
|
console.log(record)
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.form.setFieldsValue({
|
||||||
|
id: record.id,
|
||||||
|
name: record.name
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSubmit (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
this.form.validateFields((err, values) => {
|
||||||
|
if (!err) {
|
||||||
|
console.log('Received values of form: ', values)
|
||||||
|
|
||||||
|
if (values.id) {
|
||||||
|
this.updateResourceType(values.id, values)
|
||||||
|
} else {
|
||||||
|
this.createResourceType(values)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateResourceType (id, data) {
|
||||||
|
updateRelationType(id, data)
|
||||||
|
.then(res => {
|
||||||
|
this.$message.success(`更新成功`)
|
||||||
|
this.handleOk()
|
||||||
|
this.onClose()
|
||||||
|
}).catch(err => this.requestFailed(err))
|
||||||
|
},
|
||||||
|
|
||||||
|
createResourceType (data) {
|
||||||
|
addRelationType(data)
|
||||||
|
.then(res => {
|
||||||
|
this.$message.success(`添加成功`)
|
||||||
|
this.handleOk()
|
||||||
|
this.onClose()
|
||||||
|
})
|
||||||
|
.catch(err => this.requestFailed(err))
|
||||||
|
},
|
||||||
|
|
||||||
|
requestFailed (err) {
|
||||||
|
const msg = ((err.response || {}).data || {}).message || '请求出现错误,请稍后再试'
|
||||||
|
this.$message.error(`${msg}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
watch: {},
|
||||||
|
props: {
|
||||||
|
handleOk: {
|
||||||
|
type: Function,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.search {
|
||||||
|
margin-bottom: 54px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fold {
|
||||||
|
width: calc(100% - 216px);
|
||||||
|
display: inline-block
|
||||||
|
}
|
||||||
|
|
||||||
|
.operator {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
.action-btn {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 900px) {
|
||||||
|
.fold {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,248 @@
|
||||||
|
<template>
|
||||||
|
<a-card :bordered="false">
|
||||||
|
<a-menu v-model="current" mode="horizontal" v-if="ciTypes.length">
|
||||||
|
<a-menu-item :key="ciType.id" v-for="ciType in ciTypes">
|
||||||
|
<router-link
|
||||||
|
:to="{name: 'cmdb_tree_views_item', params: {typeId: ciType.id}}"
|
||||||
|
>{{ ciType.alias || ciTypes.name }}</router-link>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
<a-alert message="请先到 我的订阅 页面完成订阅!" banner v-else></a-alert>
|
||||||
|
<div style="clear: both; margin-top: 20px"></div>
|
||||||
|
<template>
|
||||||
|
<a-row :gutter="8">
|
||||||
|
<a-col :span="5">
|
||||||
|
<a-tree showLine :loadData="onLoadData" @select="onSelect" :treeData="treeData"></a-tree>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="19">
|
||||||
|
<s-table
|
||||||
|
v-if="ciTypes.length"
|
||||||
|
bordered
|
||||||
|
ref="table"
|
||||||
|
size="middle"
|
||||||
|
rowKey="ci_id"
|
||||||
|
:columns="columns"
|
||||||
|
:data="loadInstances"
|
||||||
|
:scroll="{ x: scrollX, y: scrollY }"
|
||||||
|
:pagination="{ showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条记录`, pageSizeOptions: pageSizeOptions}"
|
||||||
|
:pageSize="25"
|
||||||
|
showPagination="auto"
|
||||||
|
></s-table>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { STable } from '@/components'
|
||||||
|
|
||||||
|
import { getSubscribeTreeView, getSubscribeAttributes } from '@/api/cmdb/preference'
|
||||||
|
import { searchCI } from '@/api/cmdb/ci'
|
||||||
|
export default {
|
||||||
|
components: { STable },
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
treeData: [],
|
||||||
|
triggerSelect: false,
|
||||||
|
treeNode: null,
|
||||||
|
ciTypes: [],
|
||||||
|
levels: [],
|
||||||
|
typeId: null,
|
||||||
|
current: [],
|
||||||
|
instanceList: [],
|
||||||
|
treeKeys: [],
|
||||||
|
columns: [],
|
||||||
|
pageSizeOptions: ['10', '25', '50', '100'],
|
||||||
|
loading: false,
|
||||||
|
scrollX: 0,
|
||||||
|
scrollY: 0,
|
||||||
|
|
||||||
|
loadInstances: parameter => {
|
||||||
|
const params = parameter || {}
|
||||||
|
// const params = Object.assign(parameter, this.$refs.search.queryParam)
|
||||||
|
let q = `q=_type:${this.typeId}`
|
||||||
|
Object.keys(params).forEach(key => {
|
||||||
|
if (!['pageNo', 'pageSize', 'sortField', 'sortOrder'].includes(key) && params[key] + '' !== '') {
|
||||||
|
if (typeof params[key] === 'object' && params[key].length > 1) {
|
||||||
|
q += `,${key}:(${params[key].join(';')})`
|
||||||
|
} else if (params[key]) {
|
||||||
|
q += `,${key}:${params[key]}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof params[key] === 'string') {
|
||||||
|
q += '*'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (this.treeKeys.length > 0) {
|
||||||
|
this.treeKeys.forEach((item, idx) => {
|
||||||
|
q += `,${this.levels[idx].name}:${item}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.levels.length > this.treeKeys.length) {
|
||||||
|
q += `&facet=${this.levels[this.treeKeys.length].name}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('pageNo' in params) {
|
||||||
|
q += `&page=${params['pageNo']}&count=${params['pageSize']}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('sortField' in params) {
|
||||||
|
let order = ''
|
||||||
|
if (params['sortOrder'] !== 'ascend') {
|
||||||
|
order = '-'
|
||||||
|
}
|
||||||
|
q += `&sort=${order}${params['sortField']}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchCI(q).then(res => {
|
||||||
|
const result = {}
|
||||||
|
result.pageNo = res.page
|
||||||
|
result.pageSize = res.total
|
||||||
|
result.totalCount = res.numfound
|
||||||
|
result.totalPage = Math.ceil(res.numfound / (params.pageSize || 25))
|
||||||
|
result.data = Object.assign([], res.result)
|
||||||
|
result.data.forEach((item, index) => (item.key = item.ci_id))
|
||||||
|
setTimeout(() => {
|
||||||
|
this.setColumnWidth()
|
||||||
|
}, 200)
|
||||||
|
|
||||||
|
if (Object.values(res.facet).length) {
|
||||||
|
this.wrapTreeData(res.facet)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created () {
|
||||||
|
this.getCITypes()
|
||||||
|
},
|
||||||
|
|
||||||
|
inject: ['reload'],
|
||||||
|
watch: {
|
||||||
|
'$route.path': function (newPath, oldPath) {
|
||||||
|
this.typeId = this.$route.params.typeId
|
||||||
|
this.getCITypes()
|
||||||
|
this.reload()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onSelect (keys) {
|
||||||
|
this.triggerSelect = true
|
||||||
|
if (keys.length) {
|
||||||
|
this.treeKeys = keys[0].split('-').filter(item => item !== '')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$refs.table.refresh(true)
|
||||||
|
},
|
||||||
|
wrapTreeData (facet) {
|
||||||
|
if (this.triggerSelect) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const treeData = []
|
||||||
|
Object.values(facet)[0].forEach(item => {
|
||||||
|
treeData.push({
|
||||||
|
title: `${item[0]} (${item[1]})`,
|
||||||
|
key: this.treeKeys.join('-') + '-' + item[0],
|
||||||
|
isLeaf: this.levels.length - 1 === this.treeKeys.length
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (this.treeNode === null) {
|
||||||
|
this.treeData = treeData
|
||||||
|
} else {
|
||||||
|
this.treeNode.dataRef.children = treeData
|
||||||
|
this.treeData = [...this.treeData]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setColumnWidth () {
|
||||||
|
let rows = []
|
||||||
|
try {
|
||||||
|
rows = document.querySelector('.ant-table-body').childNodes[0].childNodes[2].childNodes[0].childNodes
|
||||||
|
} catch (e) {
|
||||||
|
rows = document.querySelector('.ant-table-body').childNodes[0].childNodes[1].childNodes[0].childNodes
|
||||||
|
}
|
||||||
|
let scrollX = 0
|
||||||
|
|
||||||
|
const columns = Object.assign([], this.columns)
|
||||||
|
for (let i = 0; i < rows.length; i++) {
|
||||||
|
columns[i].width = rows[i].offsetWidth < 80 ? 80 : rows[i].offsetWidth
|
||||||
|
scrollX += columns[i].width
|
||||||
|
}
|
||||||
|
this.columns = columns
|
||||||
|
|
||||||
|
this.scrollX = scrollX
|
||||||
|
this.scrollY = window.innerHeight - this.$refs.table.$el.offsetTop - 300
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoadData (treeNode) {
|
||||||
|
this.triggerSelect = false
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if (treeNode.dataRef.children) {
|
||||||
|
resolve()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.treeKeys = treeNode.eventKey.split('-').filter(item => item !== '')
|
||||||
|
this.treeNode = treeNode
|
||||||
|
this.$refs.table.refresh(true)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getCITypes () {
|
||||||
|
getSubscribeTreeView().then(res => {
|
||||||
|
this.ciTypes = res
|
||||||
|
if (this.ciTypes.length) {
|
||||||
|
this.typeId = this.$route.params.typeId || this.ciTypes[0].id
|
||||||
|
this.current = [this.typeId]
|
||||||
|
this.loadColumns()
|
||||||
|
this.levels = res.find(item => item.id === this.typeId).levels
|
||||||
|
this.$refs.table && this.$refs.table.refresh(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadColumns () {
|
||||||
|
getSubscribeAttributes(this.typeId).then(res => {
|
||||||
|
const prefAttrList = res.attributes
|
||||||
|
|
||||||
|
const columns = []
|
||||||
|
prefAttrList.forEach((item, index) => {
|
||||||
|
const col = {}
|
||||||
|
col.title = item.alias
|
||||||
|
col.dataIndex = item.name
|
||||||
|
if (index !== prefAttrList.length - 1) {
|
||||||
|
col.width = 80
|
||||||
|
}
|
||||||
|
if (item.is_sortable) {
|
||||||
|
col.sorter = true
|
||||||
|
}
|
||||||
|
if (item.is_choice) {
|
||||||
|
const filters = []
|
||||||
|
item.choice_value.forEach(item => filters.push({ text: item, value: item }))
|
||||||
|
col.filters = filters
|
||||||
|
}
|
||||||
|
col.scopedSlots = { customRender: item.name }
|
||||||
|
columns.push(col)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.columns = columns
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ant-menu-horizontal {
|
||||||
|
border-bottom: 1px solid #ebedf0 !important;
|
||||||
|
}
|
||||||
|
.ant-menu-horizontal {
|
||||||
|
border-bottom: 1px solid #ebedf0 !important;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue