mirror of
https://github.com/veops/cmdb.git
synced 2025-09-23 05:49:18 +08:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e9342f1101 | ||
|
6661eb846d | ||
|
c371f1defe | ||
|
4837ac8a35 | ||
|
bdf9bc576c | ||
|
99aea57948 | ||
|
23cded688e | ||
|
d78cb0f94e | ||
|
c915b46374 | ||
|
6112dc83ef | ||
|
0603783574 |
@@ -255,7 +255,9 @@ def cmdb_trigger():
|
|||||||
try:
|
try:
|
||||||
ready_cis = CITriggerManager.waiting_cis(trigger)
|
ready_cis = CITriggerManager.waiting_cis(trigger)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
import traceback
|
||||||
|
current_app.logger.error("cmdb trigger waiting_cis exception for trigger_id {}: {}".format(trigger.id, e))
|
||||||
|
current_app.logger.error("traceback: {}".format(traceback.format_exc()))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if trigger.id not in trigger2cis:
|
if trigger.id not in trigger2cis:
|
||||||
|
@@ -256,8 +256,13 @@ class AutoDiscoveryCITypeCRUD(DBMixin):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
rules = cls.cls.get_by(to_dict=True)
|
rules = cls.cls.get_by(to_dict=True)
|
||||||
|
|
||||||
|
last_update_at = last_update_at or ""
|
||||||
|
new_last_update_at = ""
|
||||||
for rule in rules:
|
for rule in rules:
|
||||||
if not rule['enabled']:
|
if not rule['enabled']:
|
||||||
|
if (rule['created_at'] or '') > last_update_at or (
|
||||||
|
rule['updated_at'] or '') > last_update_at:
|
||||||
|
new_last_update_at = max([rule['created_at'] or '', rule['updated_at'] or ''])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(rule.get("extra_option"), dict):
|
if isinstance(rule.get("extra_option"), dict):
|
||||||
@@ -299,7 +304,6 @@ class AutoDiscoveryCITypeCRUD(DBMixin):
|
|||||||
result.append(rule)
|
result.append(rule)
|
||||||
|
|
||||||
ad_rules_updated_at = (SystemConfigManager.get('ad_rules_updated_at') or {}).get('option', {}).get('v') or ""
|
ad_rules_updated_at = (SystemConfigManager.get('ad_rules_updated_at') or {}).get('option', {}).get('v') or ""
|
||||||
new_last_update_at = ""
|
|
||||||
for i in result:
|
for i in result:
|
||||||
i['adr'] = AutoDiscoveryRule.get_by_id(i['adr_id']).to_dict()
|
i['adr'] = AutoDiscoveryRule.get_by_id(i['adr_id']).to_dict()
|
||||||
i['adr'].pop("attributes", None)
|
i['adr'].pop("attributes", None)
|
||||||
@@ -308,6 +312,8 @@ class AutoDiscoveryCITypeCRUD(DBMixin):
|
|||||||
if new_last_update_at < __last_update_at:
|
if new_last_update_at < __last_update_at:
|
||||||
new_last_update_at = __last_update_at
|
new_last_update_at = __last_update_at
|
||||||
|
|
||||||
|
new_last_update_at = new_last_update_at or ad_rules_updated_at
|
||||||
|
|
||||||
write_ad_rule_sync_history.apply_async(args=(result, oneagent_id, oneagent_name, datetime.datetime.now()),
|
write_ad_rule_sync_history.apply_async(args=(result, oneagent_id, oneagent_name, datetime.datetime.now()),
|
||||||
queue=CMDB_QUEUE)
|
queue=CMDB_QUEUE)
|
||||||
if not last_update_at or new_last_update_at > last_update_at:
|
if not last_update_at or new_last_update_at > last_update_at:
|
||||||
@@ -693,6 +699,11 @@ class AutoDiscoveryCICRUD(DBMixin):
|
|||||||
stdout="delete resource: {}".format(unique_value))
|
stdout="delete resource: {}".format(unique_value))
|
||||||
# TODO: delete ci
|
# TODO: delete ci
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_instance_by_id(cls, adc_id):
|
||||||
|
adc = cls.cls.get_by_id(adc_id) or abort(404, ErrFormat.adc_not_found)
|
||||||
|
return adc.instance
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def accept(cls, adc, adc_id=None, nickname=None):
|
def accept(cls, adc, adc_id=None, nickname=None):
|
||||||
if adc_id is not None:
|
if adc_id is not None:
|
||||||
|
@@ -1618,7 +1618,8 @@ class CITriggerManager(object):
|
|||||||
ci_id, need_children=False, use_master=False, enum_use_label=True)
|
ci_id, need_children=False, use_master=False, enum_use_label=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = webhook_request(webhook, ci_dict).text
|
response = webhook_request(webhook, ci_dict)
|
||||||
|
response.raise_for_status()
|
||||||
is_ok = True
|
is_ok = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
current_app.logger.warning("exec webhook failed: {}".format(e))
|
current_app.logger.warning("exec webhook failed: {}".format(e))
|
||||||
|
@@ -1144,6 +1144,8 @@ class CITypeAttributeGroupManager(object):
|
|||||||
group2pos[group['name']] = group_pos
|
group2pos[group['name']] = group_pos
|
||||||
else:
|
else:
|
||||||
group_pos = group2pos[group['name']]
|
group_pos = group2pos[group['name']]
|
||||||
|
if type_id == group['type_id']:
|
||||||
|
result[group_pos]['type_id'] = type_id
|
||||||
|
|
||||||
for i in items:
|
for i in items:
|
||||||
if i.attr_id in id2attr:
|
if i.attr_id in id2attr:
|
||||||
@@ -1564,6 +1566,8 @@ class CITypeTemplateManager(object):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
for order, attr in enumerate(group['attributes'] or []):
|
for order, attr in enumerate(group['attributes'] or []):
|
||||||
|
if attr.get('inherited'):
|
||||||
|
continue
|
||||||
item_existed = CITypeAttributeGroupItem.get_by(group_id=existed.id,
|
item_existed = CITypeAttributeGroupItem.get_by(group_id=existed.id,
|
||||||
attr_id=attr_id_map.get(attr['id'], attr['id']),
|
attr_id=attr_id_map.get(attr['id'], attr['id']),
|
||||||
first=True, to_dict=False)
|
first=True, to_dict=False)
|
||||||
|
@@ -205,12 +205,14 @@ class AutoDiscoveryCITypeRelationView(APIView):
|
|||||||
class AutoDiscoveryCIView(APIView):
|
class AutoDiscoveryCIView(APIView):
|
||||||
url_prefix = ("/adc", "/adc/<int:adc_id>", "/adc/ci_types/<int:type_id>/attributes", "/adc/ci_types")
|
url_prefix = ("/adc", "/adc/<int:adc_id>", "/adc/ci_types/<int:type_id>/attributes", "/adc/ci_types")
|
||||||
|
|
||||||
def get(self, type_id=None):
|
def get(self, type_id=None, adc_id=None):
|
||||||
if "attributes" in request.url:
|
if "attributes" in request.url:
|
||||||
return self.jsonify(AutoDiscoveryCICRUD.get_attributes_by_type_id(type_id))
|
return self.jsonify(AutoDiscoveryCICRUD.get_attributes_by_type_id(type_id))
|
||||||
elif "ci_types" in request.url:
|
if "ci_types" in request.url:
|
||||||
need_other = request.values.get("need_other")
|
need_other = request.values.get("need_other")
|
||||||
return self.jsonify(AutoDiscoveryCICRUD.get_ci_types(need_other))
|
return self.jsonify(AutoDiscoveryCICRUD.get_ci_types(need_other))
|
||||||
|
if adc_id is not None:
|
||||||
|
return self.jsonify(AutoDiscoveryCICRUD.get_instance_by_id(adc_id))
|
||||||
|
|
||||||
page = get_page(request.values.pop('page', 1))
|
page = get_page(request.values.pop('page', 1))
|
||||||
page_size = get_page_size(request.values.pop('page_size', None))
|
page_size = get_page_size(request.values.pop('page_size', None))
|
||||||
|
@@ -138,6 +138,14 @@ export function getAdc(params) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAdcById(id, params) {
|
||||||
|
return axios({
|
||||||
|
url: `v0.1/adc/${id}`,
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function deleteAdc(adc_id) {
|
export function deleteAdc(adc_id) {
|
||||||
return axios({
|
return axios({
|
||||||
url: `v0.1/adc/${adc_id}`,
|
url: `v0.1/adc/${adc_id}`,
|
||||||
|
@@ -38,6 +38,7 @@ const cmdb_en = {
|
|||||||
attributeAD: 'Attributes AutoDiscovery',
|
attributeAD: 'Attributes AutoDiscovery',
|
||||||
relationAD: 'Relation AutoDiscovery',
|
relationAD: 'Relation AutoDiscovery',
|
||||||
grant: 'Grant',
|
grant: 'Grant',
|
||||||
|
resourceViewTip: 'Not subscribed yet. Please go to the Preference page to complete your subscription.',
|
||||||
addGroup: 'New Group',
|
addGroup: 'New Group',
|
||||||
editGroup: 'Edit Group',
|
editGroup: 'Edit Group',
|
||||||
group: 'Group',
|
group: 'Group',
|
||||||
@@ -602,6 +603,8 @@ const cmdb_en = {
|
|||||||
acceptTime: 'Accept Time',
|
acceptTime: 'Accept Time',
|
||||||
confirmAccept: 'Confirm Accept?',
|
confirmAccept: 'Confirm Accept?',
|
||||||
acceptSuccess: 'Accept successfully',
|
acceptSuccess: 'Accept successfully',
|
||||||
|
batchAccept: 'Currently being stored...',
|
||||||
|
batchAccept2: 'Currently being stored: {total} items, {successNum} successful, {errorNum} failed',
|
||||||
isAccept: 'Accept',
|
isAccept: 'Accept',
|
||||||
deleteADC: 'Confirm to delete this data?',
|
deleteADC: 'Confirm to delete this data?',
|
||||||
batchDelete: 'Confirm to delete this data?',
|
batchDelete: 'Confirm to delete this data?',
|
||||||
@@ -686,7 +689,8 @@ if __name__ == "__main__":
|
|||||||
tabCustom: 'Custom',
|
tabCustom: 'Custom',
|
||||||
tabConfig: 'Configured',
|
tabConfig: 'Configured',
|
||||||
addConfig: 'Add Config',
|
addConfig: 'Add Config',
|
||||||
configErrTip: 'Please select config'
|
configErrTip: 'Please select config',
|
||||||
|
viewRawData: 'View Raw Data'
|
||||||
},
|
},
|
||||||
ci: {
|
ci: {
|
||||||
attributeDesc: 'Attribute Description',
|
attributeDesc: 'Attribute Description',
|
||||||
|
@@ -38,6 +38,7 @@ const cmdb_zh = {
|
|||||||
attributeAD: '属性自动发现',
|
attributeAD: '属性自动发现',
|
||||||
relationAD: '关系自动发现',
|
relationAD: '关系自动发现',
|
||||||
grant: '权限配置',
|
grant: '权限配置',
|
||||||
|
resourceViewTip: '暂未订阅, 请先到我的订阅页面完成订阅',
|
||||||
addGroup: '新增分组',
|
addGroup: '新增分组',
|
||||||
editGroup: '修改分组',
|
editGroup: '修改分组',
|
||||||
group: '分组',
|
group: '分组',
|
||||||
@@ -602,6 +603,8 @@ const cmdb_zh = {
|
|||||||
acceptTime: '入库时间',
|
acceptTime: '入库时间',
|
||||||
confirmAccept: '确认入库?',
|
confirmAccept: '确认入库?',
|
||||||
acceptSuccess: '入库成功',
|
acceptSuccess: '入库成功',
|
||||||
|
batchAccept: '正在入库...',
|
||||||
|
batchAccept2: '正在入库,共{total}个,成功{successNum}个,失败{errorNum}个',
|
||||||
isAccept: '入库',
|
isAccept: '入库',
|
||||||
deleteADC: '确认删除该条数据?',
|
deleteADC: '确认删除该条数据?',
|
||||||
batchDelete: '确认删除这些数据?',
|
batchDelete: '确认删除这些数据?',
|
||||||
@@ -685,7 +688,8 @@ if __name__ == "__main__":
|
|||||||
tabCustom: '自定义',
|
tabCustom: '自定义',
|
||||||
tabConfig: '已有配置',
|
tabConfig: '已有配置',
|
||||||
addConfig: '添加配置',
|
addConfig: '添加配置',
|
||||||
configErrTip: '请选择配置'
|
configErrTip: '请选择配置',
|
||||||
|
viewRawData: '查看原始数据'
|
||||||
},
|
},
|
||||||
ci: {
|
ci: {
|
||||||
attributeDesc: '查看属性配置',
|
attributeDesc: '查看属性配置',
|
||||||
|
@@ -47,6 +47,13 @@
|
|||||||
<a-icon type="star" />
|
<a-icon type="star" />
|
||||||
{{ $t('cmdb.preference.cancelSub') }}
|
{{ $t('cmdb.preference.cancelSub') }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
<a-menu-item
|
||||||
|
key="citypeConfig"
|
||||||
|
@click="handleCITypeConfig"
|
||||||
|
>
|
||||||
|
<ops-icon type="ops-cmdb-citype" />
|
||||||
|
{{ $t('cmdb.menu.citypeManage') }}
|
||||||
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
</a-space>
|
</a-space>
|
||||||
@@ -782,6 +789,28 @@ export default {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleCITypeConfig() {
|
||||||
|
const { id, name } = this.CIType || {}
|
||||||
|
if (id && name) {
|
||||||
|
roleHasPermissionToGrant({
|
||||||
|
app_id: 'cmdb',
|
||||||
|
resource_type_name: 'CIType',
|
||||||
|
perm: 'config',
|
||||||
|
resource_name: name,
|
||||||
|
}).then((res) => {
|
||||||
|
if (res?.result) {
|
||||||
|
const storageId = `null%${id}%${name}`
|
||||||
|
localStorage.setItem('ops_cityps_currentId', storageId)
|
||||||
|
localStorage.setItem('ops_model_config_tab_key', '1')
|
||||||
|
window.open('/cmdb/ci_types', '_blank')
|
||||||
|
} else {
|
||||||
|
this.$message.error(this.$t('noPermission'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
handlePerm() {
|
handlePerm() {
|
||||||
roleHasPermissionToGrant({
|
roleHasPermissionToGrant({
|
||||||
app_id: 'cmdb',
|
app_id: 'cmdb',
|
||||||
|
@@ -20,6 +20,18 @@
|
|||||||
<RelationTable isInGrantComp :CITypeId="CITypeId" :CITypeName="CITypeName"></RelationTable>
|
<RelationTable isInGrantComp :CITypeId="CITypeId" :CITypeName="CITypeName"></RelationTable>
|
||||||
</div>
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
|
||||||
|
<a-button
|
||||||
|
slot="tabBarExtraContent"
|
||||||
|
type="primary"
|
||||||
|
ghost
|
||||||
|
size="small"
|
||||||
|
class="ops-button-ghost ops-tab-button"
|
||||||
|
@click="jumpResourceView"
|
||||||
|
>
|
||||||
|
<ops-icon type="ops-cmdb-resource" />
|
||||||
|
{{ $t('cmdb.menu.ciTable') }}
|
||||||
|
</a-button>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</a-card>
|
</a-card>
|
||||||
</template>
|
</template>
|
||||||
@@ -52,6 +64,10 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
preferenceData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -91,6 +107,16 @@ export default {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
jumpResourceView() {
|
||||||
|
const isSub = this?.preferenceData?.type_ids?.includes(this.CITypeId)
|
||||||
|
|
||||||
|
if (!isSub) {
|
||||||
|
this.$message.error(this.$t('cmdb.ciType.resourceViewTip'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
localStorage.setItem('ops_ci_typeid', this.CITypeId)
|
||||||
|
window.open('/cmdb/instances/types', '_blank')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="ci-types-wrap" :style="{ height: `${windowHeight - 96}px` }">
|
<div class="ci-types-wrap" :style="{ height: `${windowHeight - 96}px` }">
|
||||||
<div v-if="!CITypeGroups.length" class="ci-types-empty">
|
<div v-if="pageLoading" class="ci-types-loading">
|
||||||
|
<a-spin size="large" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="!CITypeGroups.length" class="ci-types-empty">
|
||||||
<a-empty :image="emptyImage" description=""></a-empty>
|
<a-empty :image="emptyImage" description=""></a-empty>
|
||||||
<a-button icon="plus" size="small" type="primary" @click="handleClickAddGroup">{{
|
<a-button icon="plus" size="small" type="primary" @click="handleClickAddGroup">{{
|
||||||
$t('cmdb.ciType.addGroup')
|
$t('cmdb.ciType.addGroup')
|
||||||
@@ -178,7 +182,12 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #two>
|
<template #two>
|
||||||
<div class="ci-types-right">
|
<div class="ci-types-right">
|
||||||
<CITypeDetail v-if="currentCId" :CITypeId="currentCId" :CITypeName="currentCName" />
|
<CITypeDetail
|
||||||
|
v-if="currentCId"
|
||||||
|
:CITypeId="currentCId"
|
||||||
|
:CITypeName="currentCName"
|
||||||
|
:preferenceData="preferenceData"
|
||||||
|
/>
|
||||||
<div v-else class="ci-types-right-empty">
|
<div v-else class="ci-types-right-empty">
|
||||||
<a-empty :image="emptyImage" description=""></a-empty>
|
<a-empty :image="emptyImage" description=""></a-empty>
|
||||||
<a-button icon="plus" size="small" type="primary" @click="handleCreateCiFromEmpty">{{
|
<a-button icon="plus" size="small" type="primary" @click="handleCreateCiFromEmpty">{{
|
||||||
@@ -409,6 +418,7 @@ import {
|
|||||||
exportCITypeGroups
|
exportCITypeGroups
|
||||||
} from '@/modules/cmdb/api/ciTypeGroup'
|
} from '@/modules/cmdb/api/ciTypeGroup'
|
||||||
import { searchAttributes, getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
import { searchAttributes, getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
||||||
|
import { getPreference } from '@/modules/cmdb/api/preference'
|
||||||
import CreateNewAttribute from './ceateNewAttribute.vue'
|
import CreateNewAttribute from './ceateNewAttribute.vue'
|
||||||
import CITypeDetail from './ciTypedetail.vue'
|
import CITypeDetail from './ciTypedetail.vue'
|
||||||
import emptyImage from '@/assets/data_empty.png'
|
import emptyImage from '@/assets/data_empty.png'
|
||||||
@@ -485,6 +495,9 @@ export default {
|
|||||||
|
|
||||||
searchValue: '',
|
searchValue: '',
|
||||||
modelExportVisible: false,
|
modelExportVisible: false,
|
||||||
|
pageLoading: false,
|
||||||
|
|
||||||
|
preferenceData: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -505,14 +518,19 @@ export default {
|
|||||||
},
|
},
|
||||||
currentGId() {
|
currentGId() {
|
||||||
if (this.currentId) {
|
if (this.currentId) {
|
||||||
return Number(this.currentId.split('%')[0])
|
const id = this?.currentId?.split?.('%')?.[0]
|
||||||
|
if (id !== 'null') {
|
||||||
|
return Number(id)
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
currentCId() {
|
currentCId() {
|
||||||
if (this.currentId) {
|
if (this.currentId) {
|
||||||
if (this.currentId.split('%')[1] !== 'null') {
|
const id = this?.currentId?.split?.('%')?.[1]
|
||||||
return Number(this.currentId.split('%')[1])
|
if (id !== 'null') {
|
||||||
|
return Number(id)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -520,8 +538,9 @@ export default {
|
|||||||
},
|
},
|
||||||
currentCName() {
|
currentCName() {
|
||||||
if (this.currentId) {
|
if (this.currentId) {
|
||||||
if (this.currentId.split('%')[2] !== 'null') {
|
const name = this?.currentId?.split?.('%')?.[2]
|
||||||
return this.currentId.split('%')[2]
|
if (name !== 'null') {
|
||||||
|
return name
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -578,7 +597,7 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
this.getAllDepAndEmployee()
|
this.getAllDepAndEmployee()
|
||||||
const _currentId = localStorage.getItem('ops_cityps_currentId')
|
const _currentId = localStorage.getItem('ops_cityps_currentId')
|
||||||
if (_currentId) {
|
if (_currentId) {
|
||||||
@@ -587,8 +606,13 @@ export default {
|
|||||||
searchResourceType({ page_size: 9999, app_id: 'cmdb' }).then((res) => {
|
searchResourceType({ page_size: 9999, app_id: 'cmdb' }).then((res) => {
|
||||||
this.resource_type = { groups: res.groups, id2perms: res.id2perms }
|
this.resource_type = { groups: res.groups, id2perms: res.id2perms }
|
||||||
})
|
})
|
||||||
this.loadCITypes(!_currentId, true)
|
|
||||||
|
this.pageLoading = true
|
||||||
|
await this.loadCITypes(!_currentId, true)
|
||||||
|
this.pageLoading = false
|
||||||
|
|
||||||
this.getAttributes()
|
this.getAttributes()
|
||||||
|
this.getPreference()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getAllDepAndEmployee() {
|
getAllDepAndEmployee() {
|
||||||
@@ -599,6 +623,13 @@ export default {
|
|||||||
handleSearch(e) {
|
handleSearch(e) {
|
||||||
this.searchValue = e.target.value
|
this.searchValue = e.target.value
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getPreference() {
|
||||||
|
getPreference().then((res) => {
|
||||||
|
this.preferenceData = res || {}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
async loadCITypes(isResetCurrentId = false, isInit = false) {
|
async loadCITypes(isResetCurrentId = false, isInit = false) {
|
||||||
const groups = await getCITypeGroupsConfig({ need_other: true })
|
const groups = await getCITypeGroupsConfig({ need_other: true })
|
||||||
let alreadyReset = false
|
let alreadyReset = false
|
||||||
@@ -623,8 +654,10 @@ export default {
|
|||||||
if (isInit) {
|
if (isInit) {
|
||||||
const isMatch = groups.some((g) => {
|
const isMatch = groups.some((g) => {
|
||||||
const matchGroup = `${g?.id}%null%null` === this.currentId
|
const matchGroup = `${g?.id}%null%null` === this.currentId
|
||||||
const matchCITypes = g?.ci_types?.some((item) => `${g?.id}%${item?.id}%${item?.name}` === this.currentId)
|
const matchCIType = g?.ci_types?.some((item) => {
|
||||||
return matchGroup || matchCITypes
|
return `${g?.id}%${item?.id}%${item?.name}` === this.currentId || `null%${item?.id}%${item?.name}` === this.currentId
|
||||||
|
})
|
||||||
|
return matchGroup || matchCIType
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!isMatch) {
|
if (!isMatch) {
|
||||||
@@ -1082,6 +1115,12 @@ export default {
|
|||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.ci-types-wrap {
|
.ci-types-wrap {
|
||||||
margin: 0 0 -24px 0;
|
margin: 0 0 -24px 0;
|
||||||
|
|
||||||
|
.ci-types-loading {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
.ci-types-empty {
|
.ci-types-empty {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@@ -239,6 +239,8 @@
|
|||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-select
|
<a-select
|
||||||
:placeholder="$t('cmdb.ciType.attributeAssociationTip4')"
|
:placeholder="$t('cmdb.ciType.attributeAssociationTip4')"
|
||||||
|
optionFilterProp="title"
|
||||||
|
show-search
|
||||||
allowClear
|
allowClear
|
||||||
v-model="item.parentAttrId"
|
v-model="item.parentAttrId"
|
||||||
>
|
>
|
||||||
@@ -250,6 +252,7 @@
|
|||||||
'parent'
|
'parent'
|
||||||
)"
|
)"
|
||||||
:key="attr.id"
|
:key="attr.id"
|
||||||
|
:title="attr.alias || attr.name"
|
||||||
>
|
>
|
||||||
{{ attr.alias || attr.name }}
|
{{ attr.alias || attr.name }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
@@ -263,6 +266,8 @@
|
|||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-select
|
<a-select
|
||||||
:placeholder="$t('cmdb.ciType.attributeAssociationTip5')"
|
:placeholder="$t('cmdb.ciType.attributeAssociationTip5')"
|
||||||
|
optionFilterProp="title"
|
||||||
|
show-search
|
||||||
allowClear
|
allowClear
|
||||||
v-model="item.childAttrId"
|
v-model="item.childAttrId"
|
||||||
>
|
>
|
||||||
@@ -274,6 +279,7 @@
|
|||||||
'child'
|
'child'
|
||||||
)"
|
)"
|
||||||
:key="attr.id"
|
:key="attr.id"
|
||||||
|
:title="attr.alias || attr.name"
|
||||||
>
|
>
|
||||||
{{ attr.alias || attr.name }}
|
{{ attr.alias || attr.name }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
|
@@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
:title="$t('cmdb.ad.viewRawData')"
|
||||||
|
:visible="visible"
|
||||||
|
wrapClassName="ci-json-editor"
|
||||||
|
width="50%"
|
||||||
|
:footer="null"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
>
|
||||||
|
<vue-json-editor
|
||||||
|
v-model="jsonData"
|
||||||
|
:style="{ '--custom-height': `${windowHeight - 300}px` }"
|
||||||
|
:showBtns="false"
|
||||||
|
:mode="'code'"
|
||||||
|
lang="zh"
|
||||||
|
/>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import vueJsonEditor from 'vue-json-editor'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'RawDataModal',
|
||||||
|
components: { vueJsonEditor },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
jsonData: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
windowHeight() {
|
||||||
|
return this.$store.state.windowHeight
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open(jsonData) {
|
||||||
|
this.visible = true
|
||||||
|
this.jsonData = jsonData
|
||||||
|
},
|
||||||
|
handleCancel() {
|
||||||
|
this.visible = false
|
||||||
|
this.jsonData = {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.ci-json-editor {
|
||||||
|
.jsoneditor-outer {
|
||||||
|
height: var(--custom-height) !important;
|
||||||
|
border: 1px solid #2f54eb;
|
||||||
|
}
|
||||||
|
div.jsoneditor-menu {
|
||||||
|
background-color: #2f54eb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -33,10 +33,11 @@
|
|||||||
<template #two>
|
<template #two>
|
||||||
<div id="discovery-ci">
|
<div id="discovery-ci">
|
||||||
<AdcCounter :typeId="currentType" />
|
<AdcCounter :typeId="currentType" />
|
||||||
|
<a-spin :tip="loadTip" :spinning="loading">
|
||||||
<div class="discovery-ci-header">
|
<div class="discovery-ci-header">
|
||||||
<a-input-search
|
<a-input-search
|
||||||
:placeholder="$t('cmdb.components.pleaseSearch')"
|
:placeholder="$t('cmdb.components.pleaseSearch')"
|
||||||
:style="{ width: '200px', marginRight: '20px' }"
|
:style="{ width: '200px' }"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
allowClear
|
allowClear
|
||||||
/>
|
/>
|
||||||
@@ -46,6 +47,15 @@
|
|||||||
<span @click="batchDelete">{{ $t('delete') }}</span>
|
<span @click="batchDelete">{{ $t('delete') }}</span>
|
||||||
<span>{{ $t('cmdb.ci.selectRows', { rows: selectedCount }) }}</span>
|
<span>{{ $t('cmdb.ci.selectRows', { rows: selectedCount }) }}</span>
|
||||||
</span>
|
</span>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
class="ops-button-ghost"
|
||||||
|
ghost
|
||||||
|
@click="getAdc()"
|
||||||
|
>
|
||||||
|
<ops-icon type="veops-refresh" />
|
||||||
|
{{ $t('refresh') }}
|
||||||
|
</a-button>
|
||||||
<a-button
|
<a-button
|
||||||
type="primary"
|
type="primary"
|
||||||
ghost
|
ghost
|
||||||
@@ -68,11 +78,11 @@
|
|||||||
:height="tableHeight"
|
:height="tableHeight"
|
||||||
:scroll-y="{ enabled: true, gt: 50 }"
|
:scroll-y="{ enabled: true, gt: 50 }"
|
||||||
:scroll-x="{ enabled: true, gt: 0 }"
|
:scroll-x="{ enabled: true, gt: 0 }"
|
||||||
|
:checkbox-config="{ reserve: true, highlight: true, range: true }"
|
||||||
|
:sort-config="{ remote: false, trigger: 'cell' }"
|
||||||
@checkbox-change="onSelectChange"
|
@checkbox-change="onSelectChange"
|
||||||
@checkbox-all="onSelectChange"
|
@checkbox-all="onSelectChange"
|
||||||
@checkbox-range-end="onSelectChange"
|
@checkbox-range-end="onSelectChange"
|
||||||
:checkbox-config="{ reserve: true, highlight: true, range: true }"
|
|
||||||
:sort-config="{ remote: false, trigger: 'cell' }"
|
|
||||||
>
|
>
|
||||||
<vxe-column
|
<vxe-column
|
||||||
align="center"
|
align="center"
|
||||||
@@ -92,15 +102,13 @@
|
|||||||
:width="col.width"
|
:width="col.width"
|
||||||
:sortable="col.sortable"
|
:sortable="col.sortable"
|
||||||
>
|
>
|
||||||
<template v-if="col.value_type === '6' || col.is_password" #default="{row}">
|
<template #default="{row}">
|
||||||
<PasswordField
|
<PasswordField
|
||||||
v-if="col.is_password"
|
v-if="col.is_password"
|
||||||
:password="row[col.field]"
|
:password="row[col.field]"
|
||||||
/>
|
/>
|
||||||
<span
|
<span>
|
||||||
v-else-if="col.value_type === '6' && row[col.field]"
|
{{ typeof row[col.field] === 'object' ? JSON.stringify(row[col.field]) : row[col.field] }}
|
||||||
>
|
|
||||||
{{ row[col.field] }}
|
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</vxe-column>
|
</vxe-column>
|
||||||
@@ -137,7 +145,7 @@
|
|||||||
></vxe-column>
|
></vxe-column>
|
||||||
<vxe-column
|
<vxe-column
|
||||||
:title="$t('operation')"
|
:title="$t('operation')"
|
||||||
v-bind="columns.length ? { width: '60px' } : { minWidth: '60px' }"
|
v-bind="columns.length ? { width: '100px' } : { minWidth: '100px' }"
|
||||||
align="center"
|
align="center"
|
||||||
fixed="right"
|
fixed="right"
|
||||||
>
|
>
|
||||||
@@ -146,6 +154,9 @@
|
|||||||
<a-tooltip :title="$t('cmdb.ad.accept')">
|
<a-tooltip :title="$t('cmdb.ad.accept')">
|
||||||
<a v-if="!row.is_accept" @click="accept(row)"><ops-icon type="cmdb-manual_warehousing"/></a>
|
<a v-if="!row.is_accept" @click="accept(row)"><ops-icon type="cmdb-manual_warehousing"/></a>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
|
<a-tooltip :title="$t('cmdb.ad.viewRawData')">
|
||||||
|
<a @click="viewADC(row)"><a-icon type="eye"/></a>
|
||||||
|
</a-tooltip>
|
||||||
<a :style="{ color: 'red' }" @click="deleteADC(row)"><a-icon type="delete"/></a>
|
<a :style="{ color: 'red' }" @click="deleteADC(row)"><a-icon type="delete"/></a>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
@@ -157,6 +168,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ops-table>
|
</ops-table>
|
||||||
|
</a-spin>
|
||||||
|
|
||||||
<a-modal
|
<a-modal
|
||||||
v-model="logModalVisible"
|
v-model="logModalVisible"
|
||||||
@@ -175,6 +187,8 @@
|
|||||||
</p>
|
</p>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<RawDataModal ref="rawDataModalRef" />
|
||||||
</template>
|
</template>
|
||||||
</TwoColumnLayout>
|
</TwoColumnLayout>
|
||||||
</template>
|
</template>
|
||||||
@@ -185,6 +199,7 @@ import XEUtils from 'xe-utils'
|
|||||||
import TwoColumnLayout from '@/components/TwoColumnLayout'
|
import TwoColumnLayout from '@/components/TwoColumnLayout'
|
||||||
import AdcCounter from './components/adcCounter.vue'
|
import AdcCounter from './components/adcCounter.vue'
|
||||||
import PasswordField from './components/passwordField.vue'
|
import PasswordField from './components/passwordField.vue'
|
||||||
|
import RawDataModal from './components/rawDataModal.vue'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getADCCiTypes,
|
getADCCiTypes,
|
||||||
@@ -192,7 +207,8 @@ import {
|
|||||||
updateADCAccept,
|
updateADCAccept,
|
||||||
getADCCiTypesAttrs,
|
getADCCiTypesAttrs,
|
||||||
deleteAdc,
|
deleteAdc,
|
||||||
getAdcExecHistories
|
getAdcExecHistories,
|
||||||
|
getAdcById
|
||||||
} from '../../api/discovery'
|
} from '../../api/discovery'
|
||||||
import { getCITableColumns } from '../../utils/helper'
|
import { getCITableColumns } from '../../utils/helper'
|
||||||
|
|
||||||
@@ -201,7 +217,8 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
TwoColumnLayout,
|
TwoColumnLayout,
|
||||||
AdcCounter,
|
AdcCounter,
|
||||||
PasswordField
|
PasswordField,
|
||||||
|
RawDataModal
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -216,6 +233,8 @@ export default {
|
|||||||
logTextArray: [],
|
logTextArray: [],
|
||||||
acceptByFilters: [],
|
acceptByFilters: [],
|
||||||
selectedCount: 0,
|
selectedCount: 0,
|
||||||
|
loading: false,
|
||||||
|
loadTip: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -283,6 +302,9 @@ export default {
|
|||||||
this.$refs.xTable.getVxetableRef().clearSort()
|
this.$refs.xTable.getVxetableRef().clearSort()
|
||||||
},
|
},
|
||||||
getAdc(isInit) {
|
getAdc(isInit) {
|
||||||
|
this.loading = true
|
||||||
|
this.loadTip = this.$t('loading')
|
||||||
|
|
||||||
getAdc({
|
getAdc({
|
||||||
type_id: this.currentType,
|
type_id: this.currentType,
|
||||||
page_size: 100000,
|
page_size: 100000,
|
||||||
@@ -314,6 +336,9 @@ export default {
|
|||||||
xTable.refreshColumn()
|
xTable.refreshColumn()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
},
|
},
|
||||||
getColumns(data, attrList) {
|
getColumns(data, attrList) {
|
||||||
const width = document.getElementById('discovery-ci').clientWidth - 50
|
const width = document.getElementById('discovery-ci').clientWidth - 50
|
||||||
@@ -352,36 +377,80 @@ export default {
|
|||||||
onCancel() {},
|
onCancel() {},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async viewADC(row) {
|
||||||
|
const res = await getAdcById(row.id)
|
||||||
|
this.$refs.rawDataModalRef.open(res || {})
|
||||||
|
},
|
||||||
|
|
||||||
async batchAccept() {
|
async batchAccept() {
|
||||||
|
let successNum = 0
|
||||||
|
let errorNum = 0
|
||||||
|
this.loading = true
|
||||||
|
this.loadTip = this.$t('cmdb.ad.batchAccept')
|
||||||
|
|
||||||
for (let i = 0; i < this.selectedRowKeys.length; i++) {
|
for (let i = 0; i < this.selectedRowKeys.length; i++) {
|
||||||
await updateADCAccept(this.selectedRowKeys[i])
|
await updateADCAccept(this.selectedRowKeys[i]).then((res) => {
|
||||||
|
successNum += 1
|
||||||
|
}).catch(() => {
|
||||||
|
errorNum += 1
|
||||||
|
}).finally(() => {
|
||||||
|
this.loadTip = this.$t('cmdb.ad.batchAccept2', {
|
||||||
|
total: this.selectedRowKeys.length,
|
||||||
|
successNum: successNum,
|
||||||
|
errorNum: errorNum,
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
this.$message.success(this.$t('cmdb.ad.acceptSuccess'))
|
|
||||||
this.getAdc(false)
|
this.loading = false
|
||||||
|
this.loadTip = ''
|
||||||
this.selectedRowKeys = []
|
this.selectedRowKeys = []
|
||||||
|
this.getAdc(false)
|
||||||
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||||
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||||
this.$refs.xTable.getVxetableRef().clearSort()
|
this.$refs.xTable.getVxetableRef().clearSort()
|
||||||
},
|
},
|
||||||
|
|
||||||
async batchDelete() {
|
async batchDelete() {
|
||||||
const that = this
|
|
||||||
this.$confirm({
|
this.$confirm({
|
||||||
title: that.$t('warning'),
|
title: this.$t('warning'),
|
||||||
content: that.$t('cmdb.ad.batchDelete'),
|
content: this.$t('cmdb.ad.batchDelete'),
|
||||||
async onOk() {
|
onOk: () => {
|
||||||
for (let i = 0; i < that.selectedRowKeys.length; i++) {
|
this.batchDeleteAsync()
|
||||||
await deleteAdc(that.selectedRowKeys[i])
|
|
||||||
}
|
}
|
||||||
that.$message.success(that.$t('deleteSuccess'))
|
|
||||||
that.getAdc(false)
|
|
||||||
that.selectedRowKeys = []
|
|
||||||
that.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
|
||||||
that.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
|
||||||
that.$refs.xTable.getVxetableRef().clearSort()
|
|
||||||
},
|
|
||||||
onCancel() {},
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async batchDeleteAsync() {
|
||||||
|
let successNum = 0
|
||||||
|
let errorNum = 0
|
||||||
|
this.loading = true
|
||||||
|
this.loadTip = this.$t('cmdb.ci.batchDeleting')
|
||||||
|
|
||||||
|
for (let i = 0; i < this.selectedRowKeys.length; i++) {
|
||||||
|
await deleteAdc(this.selectedRowKeys[i]).then((res) => {
|
||||||
|
successNum += 1
|
||||||
|
}).catch(() => {
|
||||||
|
errorNum += 1
|
||||||
|
}).finally(() => {
|
||||||
|
this.loadTip = this.$t('cmdb.ci.batchDeleting2', {
|
||||||
|
total: this.selectedRowKeys.length,
|
||||||
|
successNum: successNum,
|
||||||
|
errorNum: errorNum,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = false
|
||||||
|
this.loadTip = ''
|
||||||
|
this.selectedRowKeys = []
|
||||||
|
this.getAdc(false)
|
||||||
|
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||||
|
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||||
|
this.$refs.xTable.getVxetableRef().clearSort()
|
||||||
|
},
|
||||||
|
|
||||||
onSelectChange({ records, checked }) {
|
onSelectChange({ records, checked }) {
|
||||||
this.selectedRowKeys = records.map((item) => item.id)
|
this.selectedRowKeys = records.map((item) => item.id)
|
||||||
},
|
},
|
||||||
@@ -458,6 +527,7 @@ export default {
|
|||||||
.discovery-ci-header {
|
.discovery-ci-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
column-gap: 20px;
|
||||||
padding-top: 18px;
|
padding-top: 18px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
@@ -77,12 +77,15 @@
|
|||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-select
|
<a-select
|
||||||
:placeholder="$t('cmdb.ciType.attributeAssociationTip4')"
|
:placeholder="$t('cmdb.ciType.attributeAssociationTip4')"
|
||||||
|
optionFilterProp="title"
|
||||||
|
show-search
|
||||||
allowClear
|
allowClear
|
||||||
v-model="item.parentAttrId"
|
v-model="item.parentAttrId"
|
||||||
>
|
>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
v-for="attr in filterAttributes(modalParentAttributes, item.childAttrId, modalChildAttributes, 'parent')"
|
v-for="attr in filterAttributes(modalParentAttributes, item.childAttrId, modalChildAttributes, 'parent')"
|
||||||
:key="attr.id"
|
:key="attr.id"
|
||||||
|
:title="attr.alias || attr.name"
|
||||||
>
|
>
|
||||||
{{ attr.alias || attr.name }}
|
{{ attr.alias || attr.name }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
@@ -96,12 +99,15 @@
|
|||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-select
|
<a-select
|
||||||
:placeholder="$t('cmdb.ciType.attributeAssociationTip5')"
|
:placeholder="$t('cmdb.ciType.attributeAssociationTip5')"
|
||||||
|
optionFilterProp="title"
|
||||||
|
show-search
|
||||||
allowClear
|
allowClear
|
||||||
v-model="item.childAttrId"
|
v-model="item.childAttrId"
|
||||||
>
|
>
|
||||||
<a-select-option
|
<a-select-option
|
||||||
v-for="attr in filterAttributes(modalChildAttributes, item.parentAttrId, modalParentAttributes, 'child')"
|
v-for="attr in filterAttributes(modalChildAttributes, item.parentAttrId, modalParentAttributes, 'child')"
|
||||||
:key="attr.id"
|
:key="attr.id"
|
||||||
|
:title="attr.alias || attr.name"
|
||||||
>
|
>
|
||||||
{{ attr.alias || attr.name }}
|
{{ attr.alias || attr.name }}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :style="{ marginBottom: '-24px' }">
|
<div :style="{ marginBottom: '-24px' }">
|
||||||
<div v-if="!subscribeTreeViewCiTypesLoading && subscribeTreeViewCiTypes.length === 0">
|
<div v-if="subscribeTreeViewCiTypesLoading" class="page-loading">
|
||||||
|
<a-spin size="large" />
|
||||||
|
</div>
|
||||||
|
<div v-else-if="subscribeTreeViewCiTypes.length === 0">
|
||||||
<a-alert banner>
|
<a-alert banner>
|
||||||
<template #message>
|
<template #message>
|
||||||
<span>{{ $t('cmdb.preference.tips1') }}</span>
|
<span>{{ $t('cmdb.preference.tips1') }}</span>
|
||||||
@@ -638,7 +641,11 @@ export default {
|
|||||||
},
|
},
|
||||||
columnDrop() {
|
columnDrop() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const xTable = this.$refs.xTable.getVxetableRef()
|
const xTable = this.$refs?.xTable?.getVxetableRef?.()
|
||||||
|
if (!xTable) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.sortable = Sortable.create(
|
this.sortable = Sortable.create(
|
||||||
xTable.$el.querySelector('.body--wrapper>.vxe-table--header .vxe-header--row'),
|
xTable.$el.querySelector('.body--wrapper>.vxe-table--header .vxe-header--row'),
|
||||||
{
|
{
|
||||||
@@ -1015,6 +1022,11 @@ export default {
|
|||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
@import '../index.less';
|
@import '../index.less';
|
||||||
|
.page-loading {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
.tree-views {
|
.tree-views {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100% - 32px);
|
height: calc(100% - 32px);
|
||||||
|
Reference in New Issue
Block a user