+
@@ -90,6 +91,8 @@ import {
} from '@/modules/cmdb/api/preference'
import { getCITypeAttributesByName } from '@/modules/cmdb/api/CITypeAttr'
import AttributesTransfer from '../attributesTransfer'
+import { CI_DEFAULT_ATTR } from '@/modules/cmdb/utils/const.js'
+
export default {
name: 'SubscribeSetting',
components: { AttributesTransfer },
@@ -110,16 +113,32 @@ export default {
...mapState({
windowHeight: (state) => state.windowHeight,
}),
+ treeViewAttrList() {
+ return this.attrList.filter((item) => ![CI_DEFAULT_ATTR.UPDATE_USER, CI_DEFAULT_ATTR.UPDATE_TIME].includes(item.name))
+ }
},
methods: {
open(ciType = {}, activeKey = '1') {
this.ciType = ciType
this.activeKey = activeKey
+ const updatedByKey = CI_DEFAULT_ATTR.UPDATE_USER
+ const updatedAtKey = CI_DEFAULT_ATTR.UPDATE_TIME
+
getCITypeAttributesByName(ciType.type_id).then((res) => {
- const attributes = res.attributes
+ const attributes = res.attributes.filter((item) => ![updatedByKey, updatedAtKey].includes(item.name))
+
+ ;[updatedByKey, updatedAtKey].map((key) => {
+ attributes.push({
+ alias: key,
+ name: key,
+ id: key
+ })
+ })
+
getSubscribeAttributes(ciType.type_id).then((_res) => {
this.instanceSubscribed = _res.is_subscribed
const selectedAttrList = _res.attributes.map((item) => item.id.toString())
+
const attrList = attributes.map((item) => {
return {
key: item.id.toString(),
@@ -188,9 +207,20 @@ export default {
})
},
subInstanceSubmit() {
+ const customAttr = []
+ const defaultAttr = []
+ this.selectedAttrList.map((attr) => {
+ if ([CI_DEFAULT_ATTR.UPDATE_USER, CI_DEFAULT_ATTR.UPDATE_TIME].includes(attr)) {
+ defaultAttr.push(attr)
+ } else {
+ customAttr.push(attr)
+ }
+ })
+ const selectedAttrList = [...customAttr, ...defaultAttr]
+
subscribeCIType(
this.ciType.type_id,
- this.selectedAttrList.map((item) => {
+ selectedAttrList.map((item) => {
return [item, !!this.fixedList.includes(item)]
})
).then((res) => {
diff --git a/cmdb-ui/src/modules/cmdb/lang/en.js b/cmdb-ui/src/modules/cmdb/lang/en.js
index fc13d7d..9ceb9fb 100644
--- a/cmdb-ui/src/modules/cmdb/lang/en.js
+++ b/cmdb-ui/src/modules/cmdb/lang/en.js
@@ -24,7 +24,8 @@ const cmdb_en = {
operationHistory: 'Operation Audit',
relationType: 'Relation Type',
ad: 'AutoDiscovery',
- cidetail: 'CI Detail'
+ cidetail: 'CI Detail',
+ scene: 'Scene'
},
ciType: {
ciType: 'CIType',
@@ -377,6 +378,9 @@ const cmdb_en = {
param: 'Parameter{param}',
value: 'Value{value}',
clear: 'Clear',
+ updater: 'Update User',
+ updateTime: 'Update Time',
+ default: 'Default'
},
batch: {
downloadFailed: 'Download failed',
@@ -757,6 +761,83 @@ if __name__ == "__main__":
conditionName: 'Condition Name',
path: 'Path',
expandCondition: 'Expand Condition',
+ },
+ ipam: {
+ overview: 'Overview',
+ addressAssign: 'Address Assign',
+ ipSearch: 'IP Search',
+ subnetList: 'Subnet List',
+ history: 'History Log',
+ ticket: 'Related Tickets',
+ addSubnet: 'Add Subnet',
+ editSubnet: 'Edit Subnet',
+ addCatalog: 'Add Catalog',
+ editCatalog: 'Edit Catalog',
+ catalogName: 'Catalog Name',
+ editName: 'Edit Name',
+ editNode: 'Edit Node',
+ deleteNode: 'Delete Node',
+ basicInfo: 'Basic Info',
+ scanRule: 'Scan Rule',
+ adExecTarget: 'Execute targets',
+ masterMachineTip: 'The machine where OneMaster is installed',
+ oneagentIdTips: 'Please enter the hexadecimal OneAgent ID starting with 0x ID',
+ selectFromCMDBTips: 'Select from CMDB',
+ adInterval: 'Collection frequency',
+ cronTips: 'The format is the same as crontab, for example: 0 15 * * 1-5',
+ masterMachine: 'Master machine',
+ specifyMachine: 'Specify machine',
+ specifyMachineTips: 'Please fill in the specify machine!',
+ cronRequiredTip: 'Acquisition frequency cannot be null',
+ addressNullTip: ' Please select the leaf node of the left subnet tree first',
+ addressNullTip2: 'Subnet prefix length must be >= 16',
+ assignedOnline: 'Assigned Online',
+ assignedOffline: 'Assigned Offline',
+ unassignedOnline: 'Unassigned Online',
+ unused: 'Unused',
+ allStatus: 'All Status',
+ editAssignAddress: 'Edit Assign Address',
+ assign: 'Assign',
+ recycle: 'Recycle',
+ assignStatus: 'Assign Status',
+ reserved: 'Reserved',
+ assigned: 'Assigned',
+ recycleTip: 'Confirmed for recycle? After recycling, the status of the segment will be changed to unassigned.',
+ recycleSuccess: '{ip} Recycled successfully, status changed to: unassigned.',
+ operationLog: 'Operation Log',
+ scanLog: 'Scan Log',
+ updateCatalog: 'Update Catalog',
+ deleteCatalog: 'Delete Catalog',
+ updateSubnet: 'Update Subnet',
+ deleteSubnet: 'Delete Subnet',
+ revokeAddress: 'Revoke Address',
+ operateTime: 'Operate Time',
+ operateUser: 'Operate User',
+ operateType: 'Operate Type',
+ subnet: 'Subnet',
+ description: 'Description',
+ ipNumber: 'Number of online IP',
+ startTime: 'Start Time',
+ endTime: 'End Time',
+ scanningTime: 'Scanning Time',
+ viewResult: 'View Result',
+ scannedIP: 'Scanned IP',
+ subnetStats: 'Subnet Stats',
+ addressStats: 'Address Stats',
+ onlineStats: 'Online Stats',
+ assignStats: 'Assign Stats',
+ total: 'Total',
+ free: 'Free',
+ unassigned: 'Unassigned',
+ online: 'Online',
+ offline: 'Offline',
+ onlineUsageStats: 'Subnet Online Stats',
+ subnetName: 'Subnet Name',
+ addressCount: 'Address Count',
+ onlineRatio: 'Online Ratio',
+ scanEnable: 'Scan Enable',
+ lastScanTime: 'Last Scan Time',
+ isSuccess: 'Is Success'
}
}
export default cmdb_en
diff --git a/cmdb-ui/src/modules/cmdb/lang/zh.js b/cmdb-ui/src/modules/cmdb/lang/zh.js
index d65642c..66aaba6 100644
--- a/cmdb-ui/src/modules/cmdb/lang/zh.js
+++ b/cmdb-ui/src/modules/cmdb/lang/zh.js
@@ -24,7 +24,8 @@ const cmdb_zh = {
operationHistory: '操作审计',
relationType: '关系类型',
ad: '自动发现',
- cidetail: 'CI 详情'
+ cidetail: 'CI 详情',
+ scene: '场景'
},
ciType: {
ciType: '模型',
@@ -377,6 +378,9 @@ const cmdb_zh = {
param: '参数{param}',
value: '值{value}',
clear: '清空',
+ updater: '更新人',
+ updateTime: '更新时间',
+ default: '默认'
},
batch: {
downloadFailed: '失败下载',
@@ -756,6 +760,83 @@ if __name__ == "__main__":
conditionName: '条件命名',
path: '路径',
expandCondition: '展开条件',
+ },
+ ipam: {
+ overview: '概览',
+ addressAssign: '地址分配',
+ ipSearch: 'IP查询',
+ subnetList: '子网列表',
+ history: '历史记录',
+ ticket: '关联工单',
+ addSubnet: '新增子网',
+ editSubnet: '编辑子网',
+ addCatalog: '新增目录',
+ editCatalog: '修改目录',
+ catalogName: '目录名称',
+ editName: '修改名称',
+ editNode: '修改节点',
+ deleteNode: '删除节点',
+ basicInfo: '基本信息',
+ scanRule: '扫描规则',
+ adExecTarget: '执行机器',
+ masterMachineTip: '安装OneMaster的所在机器',
+ oneagentIdTips: '请输入以0x开头的16进制OneAgent ID',
+ selectFromCMDBTips: '从CMDB中选择',
+ adInterval: '采集频率',
+ cronTips: '格式同crontab, 例如:0 15 * * 1-5',
+ masterMachine: 'Master机器',
+ specifyMachine: '指定机器',
+ specifyMachineTips: '请填写指定机器!',
+ cronRequiredTip: '采集频率不能为空',
+ addressNullTip: '请先选择左侧子网树的叶子节点',
+ addressNullTip2: '子网前缀长度必须 >= 16',
+ assignedOnline: '已分配在线',
+ assignedOffline: '已分配离线',
+ unassignedOnline: '未分配在线',
+ unused: '空闲',
+ allStatus: '全部状态',
+ editAssignAddress: '编辑分配地址',
+ assign: '分配',
+ recycle: '回收',
+ assignStatus: '分配状态',
+ reserved: '预留',
+ assigned: '已分配',
+ recycleTip: '确认要回收吗?回收后该网段状态变更为:未分配',
+ recycleSuccess: '{ip} 回收成功,状态变更为: 未分配',
+ operationLog: '操作记录',
+ scanLog: '扫描记录',
+ updateCatalog: '更新目录',
+ deleteCatalog: '删除目录',
+ updateSubnet: '修改子网',
+ deleteSubnet: '删除子网',
+ revokeAddress: '地址回收',
+ operateTime: '操作时间',
+ operateUser: '操作人',
+ operateType: '操作类型',
+ subnet: '子网',
+ description: '描述',
+ ipNumber: '在线IP地址数',
+ startTime: '开始时间',
+ endTime: '结束时间',
+ scanningTime: '扫描耗时',
+ viewResult: '查看结果',
+ scannedIP: '已扫描的IP',
+ subnetStats: '子网统计',
+ addressStats: '地址数统计',
+ onlineStats: '在线统计',
+ assignStats: '分配统计',
+ total: '总数',
+ free: '空闲',
+ unassigned: '未分配',
+ online: '在线',
+ offline: '离线',
+ onlineUsageStats: '子网在线统计',
+ subnetName: '子网名称',
+ addressCount: '地址数',
+ onlineRatio: '在线率',
+ scanEnable: '是否扫描',
+ lastScanTime: '最后扫描时间',
+ isSuccess: '是否成功'
}
}
export default cmdb_zh
diff --git a/cmdb-ui/src/modules/cmdb/router/index.js b/cmdb-ui/src/modules/cmdb/router/index.js
index 3ff5a87..d2bc284 100644
--- a/cmdb-ui/src/modules/cmdb/router/index.js
+++ b/cmdb-ui/src/modules/cmdb/router/index.js
@@ -70,6 +70,17 @@ const genCmdbRoutes = async () => {
meta: { title: 'cmdb.menu.cidetail', keepAlive: false },
component: () => import('../views/ci/ciDetailPage.vue')
},
+ {
+ path: '/cmdb/disabled4',
+ name: 'cmdb_disabled4',
+ meta: { title: 'cmdb.menu.scene', appName: 'cmdb', disabled: true, permission: ['admin', 'cmdb_admin'] },
+ },
+ {
+ path: '/cmdb/ipam',
+ component: () => import('../views/ipam'),
+ name: 'cmdb_ipam',
+ meta: { title: 'IPAM', appName: 'cmdb', icon: 'veops-ipam', selectedIcon: 'veops-ipam', keepAlive: false, permission: ['admin', 'cmdb_admin'] }
+ },
{
path: '/cmdb/disabled2',
name: 'cmdb_disabled2',
diff --git a/cmdb-ui/src/modules/cmdb/utils/const.js b/cmdb-ui/src/modules/cmdb/utils/const.js
index 65b1701..9354957 100644
--- a/cmdb-ui/src/modules/cmdb/utils/const.js
+++ b/cmdb-ui/src/modules/cmdb/utils/const.js
@@ -33,3 +33,8 @@ export const defautValueColor = [
]
export const defaultBGColors = ['#ffccc7', '#ffd8bf', '#ffe7ba', '#fff1b8', '#d9f7be', '#b5f5ec', '#bae7ff', '#d6e4ff', '#efdbff', '#ffd6e7']
+
+export const CI_DEFAULT_ATTR = {
+ UPDATE_USER: '_updated_by',
+ UPDATE_TIME: '_updated_at'
+}
diff --git a/cmdb-ui/src/modules/cmdb/utils/helper.js b/cmdb-ui/src/modules/cmdb/utils/helper.js
index a6ae527..6892533 100644
--- a/cmdb-ui/src/modules/cmdb/utils/helper.js
+++ b/cmdb-ui/src/modules/cmdb/utils/helper.js
@@ -2,6 +2,9 @@
import _ from 'lodash'
import XLSX from 'xlsx'
import XLSXS from 'xlsx-js-style'
+import { CI_DEFAULT_ATTR } from './const.js'
+import i18n from '@/lang'
+
export function sum(arr) {
if (!arr.length) {
return 0
@@ -49,7 +52,10 @@ export function getCITableColumns(data, attrList, width = 1600, height) {
const _attrList = _.orderBy(attrList, ['is_fixed'], ['desc'])
const columns = []
for (let attr of _attrList) {
- const editRender = { name: 'input' }
+ const editRender = {
+ name: 'input',
+ enabled: !attr.is_computed && !attr.sys_computed
+ }
switch (attr.value_type) {
case '0':
editRender['props'] = { 'type': 'float' }
@@ -83,13 +89,35 @@ export function getCITableColumns(data, attrList, width = 1600, height) {
delete editRender.props
}
+
+ let title = attr.alias || attr.name
+ let sortable = !!attr.is_sortable
+ let attr_id = attr.id
+
+ if ([CI_DEFAULT_ATTR.UPDATE_TIME, CI_DEFAULT_ATTR.UPDATE_USER].includes(attr.name)) {
+ editRender.enabled = false
+ attr_id = attr.name
+
+ switch (attr.name) {
+ case CI_DEFAULT_ATTR.UPDATE_USER:
+ title = i18n.t('cmdb.components.updater')
+ break;
+ case CI_DEFAULT_ATTR.UPDATE_TIME:
+ title = i18n.t('cmdb.components.updateTime')
+ sortable = true
+ break;
+ default:
+ break;
+ }
+ }
+
columns.push({
- attr_id: attr.id,
+ attr_id,
editRender,
- title: attr.alias || attr.name,
+ title,
field: attr.name,
value_type: attr.value_type,
- sortable: !!attr.is_sortable,
+ sortable,
filters: attr.is_choice ? attr.choice_value : null,
choice_builtin: null,
width: Math.min(Math.max(100, ...data.map(item => strLength(item[attr.name]))), 350),
diff --git a/cmdb-ui/src/modules/cmdb/views/ci/modules/CreateInstanceForm.vue b/cmdb-ui/src/modules/cmdb/views/ci/modules/CreateInstanceForm.vue
index 4d2603d..0fad2eb 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci/modules/CreateInstanceForm.vue
+++ b/cmdb-ui/src/modules/cmdb/views/ci/modules/CreateInstanceForm.vue
@@ -259,7 +259,7 @@ export default {
this.attributeList = _attrList.sort((x, y) => y.is_required - x.is_required)
await getCITypeGroupById(this.typeId).then((res1) => {
const _attributesByGroup = res1.map((g) => {
- g.attributes = g.attributes.filter((attr) => !attr.is_computed)
+ g.attributes = g.attributes.filter((attr) => !attr.is_computed && !attr.sys_computed)
return g
})
const attrHasGroupIds = []
@@ -268,7 +268,7 @@ export default {
attrHasGroupIds.push(...id)
})
const otherGroupAttr = this.attributeList.filter(
- (attr) => !attrHasGroupIds.includes(attr.id) && !attr.is_computed
+ (attr) => !attrHasGroupIds.includes(attr.id) && !attr.is_computed && !attr.sys_computed
)
if (otherGroupAttr.length) {
_attributesByGroup.push({ id: -1, name: this.$t('other'), attributes: otherGroupAttr })
diff --git a/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailAttrContent.vue b/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailAttrContent.vue
index 29d7c7e..b292f27 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailAttrContent.vue
+++ b/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailAttrContent.vue
@@ -178,7 +178,7 @@
-
+
@@ -267,7 +267,7 @@ export default {
async handleCloseEdit() {
const newData = this.form.getFieldValue(this.attr.name)
if (!_.isEqual(this.ci[this.attr.name], newData)) {
- await updateCI(this.ci._id, { [`${this.attr.name}`]: newData })
+ await updateCI(this.ci._id, { [`${this.attr.name}`]: newData ?? null })
.then(() => {
this.$message.success(this.$t('updateSuccess'))
this.$emit('updateCIByself', { [`${this.attr.name}`]: newData }, this.attr.name)
diff --git a/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelation.vue b/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelation.vue
index dbe659c..26280bd 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelation.vue
+++ b/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelation.vue
@@ -18,7 +18,7 @@
:disabled="!canEdit[parent.id]"
@click="
() => {
- $refs.addTableModal.openModal({ [`${ci.unique}`]: ci[ci.unique] }, ci._id, parent.id, 'parents')
+ $refs.addTableModal.openModal({ [`${ci.unique}`]: ci[ci.unique] }, ci._id, parent, 'parents')
}
"
>
{
- $refs.addTableModal.openModal({ [`${ci.unique}`]: ci[ci.unique] }, ci._id, child.id, 'children')
+ $refs.addTableModal.openModal({ [`${ci.unique}`]: ci[ci.unique] }, ci._id, child, 'children')
}
"
> {
const sourceNode = data?.id || null
if (type === 'custom:clickLeft') {
- searchCIRelation(`root_id=${Number(sourceNode)}&level=1&reverse=1&count=10000`).then((res) => {
- this.redrawData(res, sourceNode, 'left')
- })
+ this.debounceClick(sourceNode, 1)
}
if (type === 'custom:clickRight') {
- searchCIRelation(`root_id=${Number(sourceNode)}&level=1&reverse=0&count=10000`).then((res) => {
- this.redrawData(res, sourceNode, 'right')
- })
+ this.debounceClick(sourceNode, 0)
}
})
},
+
+ debounceClick: _.debounce(function(sourceNode, reverse) {
+ searchCIRelation(`root_id=${Number(sourceNode)}&level=1&reverse=${reverse}&count=10000`).then((res) => {
+ this.redrawData(res, sourceNode, reverse === 1 ? 'left' : 'right')
+ })
+ }, 300),
+
setTopoData(data) {
const root = document.getElementById('ci-detail-relation-topo')
if (root && root?.innerHTML) {
diff --git a/cmdb-ui/src/modules/cmdb/views/ci/modules/editAttrsPopover.vue b/cmdb-ui/src/modules/cmdb/views/ci/modules/editAttrsPopover.vue
index 9255db8..0a2a7bc 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci/modules/editAttrsPopover.vue
+++ b/cmdb-ui/src/modules/cmdb/views/ci/modules/editAttrsPopover.vue
@@ -4,6 +4,7 @@
{
- const attributes = res.attributes
+ const attributes = res.attributes.filter((item) => ![updatedByKey, updatedAtKey].includes(item.name))
+ ;[updatedByKey, updatedAtKey].map((key) => {
+ attributes.push({
+ alias: key,
+ name: key,
+ id: key
+ })
+ })
+
getSubscribeAttributes(this.typeId).then((_res) => {
const selectedAttrList = _res.attributes.map((item) => item.id.toString())
@@ -71,12 +85,23 @@ export default {
handleSubmit() {
if (this.selectedAttrList.length) {
+ const customAttr = []
+ const defaultAttr = []
+ this.selectedAttrList.map((attr) => {
+ if ([CI_DEFAULT_ATTR.UPDATE_USER, CI_DEFAULT_ATTR.UPDATE_TIME].includes(attr)) {
+ defaultAttr.push(attr)
+ } else {
+ customAttr.push(attr)
+ }
+ })
+ const selectedAttrList = [...customAttr, ...defaultAttr]
+
subscribeCIType(
this.typeId,
- this.selectedAttrList.map((item) => {
+ selectedAttrList.map((item) => {
return [item, !!this.fixedList.includes(item)]
})
- ).then((res) => {
+ ).then(() => {
this.$message.success(this.$t('cmdb.components.subSuccess'))
this.visible = false
this.$emit('refresh')
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/components/catalogForm.vue b/cmdb-ui/src/modules/cmdb/views/ipam/components/catalogForm.vue
new file mode 100644
index 0000000..d3df1c5
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/components/catalogForm.vue
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/components/ipamTree.vue b/cmdb-ui/src/modules/cmdb/views/ipam/components/ipamTree.vue
new file mode 100644
index 0000000..d5bfdf1
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/components/ipamTree.vue
@@ -0,0 +1,317 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ treeNodeData.title }}
+
+
+
+
+ {{ treeNodeData.count }}
+
+
+
+
+
+
+
+
+
+ {{ $t('cmdb.ipam.addCatalog') }}
+
+
+
+ {{ $t('cmdb.ipam.addSubnet') }}
+
+
+
+
+
+ {{ $t('cmdb.ipam.editName') }}
+
+
+
+ {{ $t('cmdb.ipam.editNode') }}
+
+
+
+ {{ $t('cmdb.ipam.deleteNode') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/components/subnetForm.vue b/cmdb-ui/src/modules/cmdb/views/ipam/components/subnetForm.vue
new file mode 100644
index 0000000..94192a6
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/components/subnetForm.vue
@@ -0,0 +1,445 @@
+
+
+
+
+
+ {{ group.name }}
+
+
+
+
+
+
+
+ {{ choiceItem.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('cmdb.ipam.masterMachineTip') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t('cancel') }}
+
{{ $t('save') }}
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/constants.js b/cmdb-ui/src/modules/cmdb/views/ipam/constants.js
new file mode 100644
index 0000000..f887e1c
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/constants.js
@@ -0,0 +1,3 @@
+export const SUB_NET_CITYPE_NAME = 'ipam_subnet'
+export const SCOPE_CITYPE_NAME = 'ipam_scope'
+export const ADDRESS_CITYPE_NAME = 'ipam_address'
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/index.vue b/cmdb-ui/src/modules/cmdb/views/ipam/index.vue
new file mode 100644
index 0000000..fc75476
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/index.vue
@@ -0,0 +1,296 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/assignForm.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/assignForm.vue
new file mode 100644
index 0000000..45ce276
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/assignForm.vue
@@ -0,0 +1,284 @@
+
+
+
+
+ {{ ipData.ip }}
+
+
+
+
+
+
+ {{ choiceItem.label }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/constants.js b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/constants.js
new file mode 100644
index 0000000..31dacce
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/constants.js
@@ -0,0 +1,39 @@
+export const ADDRESS_STATUS = {
+ ONLINE_ASSIGNED: '0',
+ ONLINE_UNASSIGNED: '1',
+ OFFLINE_ASSIGNED: '2',
+ OFFLINE_UNASSIGNED: '3',
+}
+
+export const STATUS_COLOR = {
+ [ADDRESS_STATUS.ONLINE_ASSIGNED]: '#00B42A',
+ [ADDRESS_STATUS.ONLINE_UNASSIGNED]: '#FF7D00',
+ [ADDRESS_STATUS.OFFLINE_ASSIGNED]: '#2F54EB',
+ [ADDRESS_STATUS.OFFLINE_UNASSIGNED]: '#A5A9BC'
+}
+
+export const STATUS_LABEL = {
+ [ADDRESS_STATUS.ONLINE_ASSIGNED]: 'cmdb.ipam.assignedOnline',
+ [ADDRESS_STATUS.ONLINE_UNASSIGNED]: 'cmdb.ipam.unassignedOnline',
+ [ADDRESS_STATUS.OFFLINE_ASSIGNED]: 'cmdb.ipam.assignedOffline',
+ [ADDRESS_STATUS.OFFLINE_UNASSIGNED]: 'cmdb.ipam.unused'
+}
+
+export const STATUS_OPTION = [
+ {
+ value: ADDRESS_STATUS.ONLINE_ASSIGNED,
+ label: STATUS_LABEL[ADDRESS_STATUS.ONLINE_ASSIGNED],
+ },
+ {
+ value: ADDRESS_STATUS.ONLINE_UNASSIGNED,
+ label: STATUS_LABEL[ADDRESS_STATUS.ONLINE_UNASSIGNED],
+ },
+ {
+ value: ADDRESS_STATUS.OFFLINE_ASSIGNED,
+ label: STATUS_LABEL[ADDRESS_STATUS.OFFLINE_ASSIGNED],
+ },
+ {
+ value: ADDRESS_STATUS.OFFLINE_UNASSIGNED,
+ label: STATUS_LABEL[ADDRESS_STATUS.OFFLINE_UNASSIGNED],
+ }
+]
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/gridIP.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/gridIP.vue
new file mode 100644
index 0000000..e327a1c
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/gridIP.vue
@@ -0,0 +1,399 @@
+
+
+
+ {{ item.gridTitle }}
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/index.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/index.vue
new file mode 100644
index 0000000..2413575
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/index.vue
@@ -0,0 +1,721 @@
+
+
+
+
![]()
+
{{ $t('noData') }}
+
{{ $t(addressNullTip) }}
+
+
+
+
+
{{ $t('loading') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/tableIP.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/tableIP.vue
new file mode 100644
index 0000000..062eb01
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/address/tableIP.vue
@@ -0,0 +1,346 @@
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/index.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/index.vue
new file mode 100644
index 0000000..9d3324b
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/index.vue
@@ -0,0 +1,96 @@
+
+
+
+
+ {{ $t(item.title) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/operation/constants.js b/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/operation/constants.js
new file mode 100644
index 0000000..d681084
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/operation/constants.js
@@ -0,0 +1,56 @@
+export const OPERATE_TYPE = {
+ ADD_SCOPE: '0',
+ UPDATE_SCOPE: '1',
+ DELETE_SCOPE: '2',
+ ADD_SUBNET: '3',
+ UPDATE_SUBNET: '4',
+ DELETE_SUBNET: '5',
+ ASSIGN_ADDRESS: '6',
+ REVOKE_ADDRESS: '7',
+}
+
+export const OPERATE_TYPE_TEXT = {
+ [OPERATE_TYPE.ADD_SCOPE]: 'cmdb.ipam.addCatalog',
+ [OPERATE_TYPE.UPDATE_SCOPE]: 'cmdb.ipam.updateCatalog',
+ [OPERATE_TYPE.DELETE_SCOPE]: 'cmdb.ipam.deleteCatalog',
+ [OPERATE_TYPE.ADD_SUBNET]: 'cmdb.ipam.addSubnet',
+ [OPERATE_TYPE.UPDATE_SUBNET]: 'cmdb.ipam.updateSubnet',
+ [OPERATE_TYPE.DELETE_SUBNET]: 'cmdb.ipam.deleteSubnet',
+ [OPERATE_TYPE.ASSIGN_ADDRESS]: 'cmdb.ipam.addressAssign',
+ [OPERATE_TYPE.REVOKE_ADDRESS]: 'cmdb.ipam.revokeAddress',
+}
+
+export const OPERATE_TYPE_COLOR = {
+ [OPERATE_TYPE.ADD_SCOPE]: {
+ color: '#2F54EB',
+ backgroundColor: '#DCF5FF'
+ },
+ [OPERATE_TYPE.UPDATE_SCOPE]: {
+ color: '#FF7D00',
+ backgroundColor: '#FFECCF'
+ },
+ [OPERATE_TYPE.DELETE_SCOPE]: {
+ color: '#FD4C6A',
+ backgroundColor: '#FFECE8'
+ },
+ [OPERATE_TYPE.ADD_SUBNET]: {
+ color: '#2F54EB',
+ backgroundColor: '#DCF5FF'
+ },
+ [OPERATE_TYPE.UPDATE_SUBNET]: {
+ color: '#FF7D00',
+ backgroundColor: '#FFECCF'
+ },
+ [OPERATE_TYPE.DELETE_SUBNET]: {
+ color: '#FD4C6A',
+ backgroundColor: '#FFECE8'
+ },
+ [OPERATE_TYPE.ASSIGN_ADDRESS]: {
+ color: '#00B42A',
+ backgroundColor: '#F6FFED'
+ },
+ [OPERATE_TYPE.REVOKE_ADDRESS]: {
+ color: '#0AA5A8',
+ backgroundColor: '#E8FFFB'
+ },
+}
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/operation/index.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/operation/index.vue
new file mode 100644
index 0000000..bbf7a3d
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/operation/index.vue
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+
+
+ {{ row.nickname }}
+
+
+
+
+
+ {{ $t(OPERATE_TYPE_TEXT[row.operate_type]) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/scan/index.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/scan/index.vue
new file mode 100644
index 0000000..a541e47
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/history/scan/index.vue
@@ -0,0 +1,286 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ $t('success') }}
+
+
+
+
+
+
+
+
+ {{ row.status === 0 ? row.ips ? row.ips.join(', ') : '' : row.stdout }}
+
+
+
+
+ {{ row.stdout }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/ipSearch/index.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/ipSearch/index.vue
new file mode 100644
index 0000000..fe71354
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/ipSearch/index.vue
@@ -0,0 +1,385 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/index.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/index.vue
new file mode 100644
index 0000000..5b8086c
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/index.vue
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/stats.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/stats.vue
new file mode 100644
index 0000000..463199c
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/stats.vue
@@ -0,0 +1,212 @@
+
+
+
+
+
{{ $t(item.title) }}
+
+
+
+ {{ $t(dataItem.label) }}
+ {{ dataItem.value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/statsChart.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/statsChart.vue
new file mode 100644
index 0000000..85f06c3
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/statsChart.vue
@@ -0,0 +1,105 @@
+
+
+
+
+ {{ statsData.ratio }}%
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/subnetTable.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/subnetTable.vue
new file mode 100644
index 0000000..d4eecfc
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/overview/subnetTable.vue
@@ -0,0 +1,207 @@
+
+
+
+ {{ $t('cmdb.ipam.onlineUsageStats') }}
+
+
+
+
+
+
+
+
+
+
+ {{ row.used_ratio }}%
+
+
+
+ {{ row.used_count }}/{{ row.hosts_count }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/ipam/modules/subnetList/index.vue b/cmdb-ui/src/modules/cmdb/views/ipam/modules/subnetList/index.vue
new file mode 100644
index 0000000..fd89ae4
--- /dev/null
+++ b/cmdb-ui/src/modules/cmdb/views/ipam/modules/subnetList/index.vue
@@ -0,0 +1,387 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmdb-ui/src/modules/cmdb/views/preference/index.vue b/cmdb-ui/src/modules/cmdb/views/preference/index.vue
index 494c785..324e997 100644
--- a/cmdb-ui/src/modules/cmdb/views/preference/index.vue
+++ b/cmdb-ui/src/modules/cmdb/views/preference/index.vue
@@ -233,6 +233,7 @@ import CollapseTransition from '@/components/CollapseTransition'
import SubscribeSetting from '../../components/subscribeSetting/subscribeSetting'
import { getCIAdcStatistics } from '../../api/ci'
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
+import { SUB_NET_CITYPE_NAME, SCOPE_CITYPE_NAME, ADDRESS_CITYPE_NAME } from '../ipam/constants.js'
export default {
name: 'Preference',
@@ -282,8 +283,16 @@ export default {
getPreference2(true, true),
getCIAdcStatistics(),
])
+
+ const IPAM_CI = [
+ SUB_NET_CITYPE_NAME,
+ SCOPE_CITYPE_NAME,
+ ADDRESS_CITYPE_NAME
+ ]
+
ciTypeGroup.forEach((group) => {
if (group.ci_types && group.ci_types.length) {
+ group.ci_types = group.ci_types.filter((type) => !IPAM_CI.includes(type.name))
group.ci_types.forEach((type) => {
const idx = pref.type_ids.findIndex((p) => p === type.id)
if (idx > -1) {
@@ -304,10 +313,17 @@ export default {
const { self, type_id2users } = pref2
this.self = self
this.type_id2users = type_id2users
+
+ const prefGroupTypes = pref.group_types.filter((group) => {
+ group.ci_types = group?.ci_types?.filter((type) => !IPAM_CI.includes(type?.name)) || []
+ return group?.ci_types?.length
+ })
+ const prefTreeTypes = pref?.tree_types?.filter((type) => !IPAM_CI.includes(type?.name)) || []
+
const _myPreferences = [
{
name: this.$t('cmdb.menu.ciTable'),
- groups: pref.group_types,
+ groups: prefGroupTypes,
icon: 'cmdb-ci',
type: 'ci',
},
@@ -315,7 +331,7 @@ export default {
name: this.$t('cmdb.menu.ciTree'),
groups: [
{
- ci_types: pref.tree_types,
+ ci_types: prefTreeTypes,
name: null,
}
],
@@ -382,11 +398,13 @@ export default {
})
},
resetRoute() {
- resetRouter()
const roles = store.getters.roles
store.dispatch('GenerateRoutes', { roles }, { root: true }).then(() => {
- router.addRoutes(store.getters.appRoutes)
- this.getCITypes()
+ resetRouter()
+ this.$nextTick(() => {
+ router.addRoutes(store.getters.appRoutes)
+ this.getCITypes()
+ })
})
},
diff --git a/cmdb-ui/src/modules/cmdb/views/relation_views/index.vue b/cmdb-ui/src/modules/cmdb/views/relation_views/index.vue
index 9ac9359..8e7199b 100644
--- a/cmdb-ui/src/modules/cmdb/views/relation_views/index.vue
+++ b/cmdb-ui/src/modules/cmdb/views/relation_views/index.vue
@@ -984,7 +984,28 @@ export default {
this.batchTreeKey = []
} else {
const childTypeId = menuKey
- this.$refs.addTableModal.openModal(firstCIObj, firstCIId, childTypeId, 'children', ancestor_ids)
+
+ let typeName = ''
+ if (this?.relationViews?.id2type?.[childTypeId]) {
+ typeName = this.relationViews.id2type[childTypeId]?.name || ''
+ } else {
+ const node2show_types = this?.relationViews?.views?.[this.viewName]?.node2show_types
+ const typeId = _tempTree?.[1]
+ if (node2show_types?.[typeId]?.length) {
+ const findType = node2show_types[typeId].find((item) => item.id === childTypeId)
+ typeName = findType?.name || ''
+ }
+ }
+ this.$refs.addTableModal.openModal(
+ firstCIObj,
+ firstCIId,
+ {
+ id: childTypeId,
+ name: typeName
+ },
+ 'children',
+ ancestor_ids
+ )
}
}
},
diff --git a/cmdb-ui/src/modules/cmdb/views/relation_views/modules/AddTableModal.vue b/cmdb-ui/src/modules/cmdb/views/relation_views/modules/AddTableModal.vue
index 6bc79d2..f9f3234 100644
--- a/cmdb-ui/src/modules/cmdb/views/relation_views/modules/AddTableModal.vue
+++ b/cmdb-ui/src/modules/cmdb/views/relation_views/modules/AddTableModal.vue
@@ -18,6 +18,7 @@
@refresh="handleSearch"
>
{
$refs.createInstanceForm.handleOpen(true, 'create')
@@ -116,6 +117,7 @@ import { getCITableColumns } from '../../../utils/helper'
import SearchForm from '../../../components/searchForm/SearchForm.vue'
import CreateInstanceForm from '../../ci/modules/CreateInstanceForm.vue'
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
+import { SUB_NET_CITYPE_NAME, SCOPE_CITYPE_NAME, ADDRESS_CITYPE_NAME } from '@/modules/cmdb/views/ipam/constants.js'
export default {
name: 'AddTableModal',
@@ -137,6 +139,7 @@ export default {
preferenceAttrList: [],
ancestor_ids: undefined,
attrList1: [],
+ showCreateBtn: true, // 是否展示新增按钮
}
},
computed: {
@@ -159,18 +162,20 @@ export default {
},
watch: {},
methods: {
- async openModal(ciObj, ciId, addTypeId, type, ancestor_ids = undefined) {
- console.log(ciObj, ciId, addTypeId, type)
+ async openModal(ciObj, ciId, addType, type, ancestor_ids = undefined) {
+ console.log(ciObj, ciId, addType, type)
this.visible = true
this.ciObj = ciObj
this.ciId = ciId
- this.addTypeId = addTypeId
+ this.addTypeId = addType.id
this.type = type
this.ancestor_ids = ancestor_ids
- await getSubscribeAttributes(addTypeId).then((res) => {
+ this.showCreateBtn = ![SUB_NET_CITYPE_NAME, SCOPE_CITYPE_NAME, ADDRESS_CITYPE_NAME].includes(addType.name)
+
+ await getSubscribeAttributes(this.addTypeId).then((res) => {
this.preferenceAttrList = res.attributes // 已经订阅的全部列
})
- getCITypeAttributesById(addTypeId).then((res) => {
+ getCITypeAttributesById(this.addTypeId).then((res) => {
this.attrList = res.attributes
})
this.getTableData(true)
@@ -232,6 +237,7 @@ export default {
this.expression = ''
this.isFocusExpression = false
this.visible = false
+ this.showCreateBtn = true
},
async handleOk() {
const selectRecordsCurrent = this.$refs.xTable.getCheckboxRecords()
diff --git a/cmdb-ui/src/modules/cmdb/views/resource_search_2/relationSearch/components/ciTable.vue b/cmdb-ui/src/modules/cmdb/views/resource_search_2/relationSearch/components/ciTable.vue
index 8962b8b..845ff6c 100644
--- a/cmdb-ui/src/modules/cmdb/views/resource_search_2/relationSearch/components/ciTable.vue
+++ b/cmdb-ui/src/modules/cmdb/views/resource_search_2/relationSearch/components/ciTable.vue
@@ -38,6 +38,9 @@
:column-config="{ resizable: true }"
:resizable-config="{ minWidth: 60 }"
class="checkbox-hover-table"
+ @checkbox-change="onSelectChange"
+ @checkbox-all="onSelectChange"
+ @checkbox-range-end="onSelectChange"
>
import _ from 'lodash'
-import moment from 'moment'
import { mapState } from 'vuex'
import ExcelJS from 'exceljs'
import FileSaver from 'file-saver'
@@ -266,8 +268,7 @@ export default {
ciTypeName: this.tabActive || '',
})
},
- batchDownload({ checkedKeys }) {
- const excel_name = `cmdb-${this.tabActive}-${moment().format('YYYYMMDDHHmmss')}.xlsx`
+ batchDownload({ checkedKeys, filename }) {
const wb = new ExcelJS.Workbook()
const tableRef = this.$refs.xTable.getVxetableRef()
@@ -341,12 +342,16 @@ export default {
const file = new Blob([buffer], {
type: 'application/octet-stream',
})
- FileSaver.saveAs(file, excel_name)
+ FileSaver.saveAs(file, `${filename}.xlsx`)
})
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
- }
+ },
+
+ onSelectChange() {
+ console.log('onSelectChange')
+ },
}
}