mirror of https://github.com/veops/cmdb.git
feat(ui): CI change logs related itsm
This commit is contained in:
parent
bf1076fe4a
commit
51332c7236
|
@ -54,3 +54,20 @@ export function getCiTriggersByCiId(ci_id, params) {
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCiRelatedTickets(params) {
|
||||||
|
return axios({
|
||||||
|
url: `/itsm/v1/process_ticket/get_tickets_by`,
|
||||||
|
method: 'POST',
|
||||||
|
data: params,
|
||||||
|
isShowMessage: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function judgeItsmInstalled() {
|
||||||
|
return axios({
|
||||||
|
url: `/itsm/v1/process_ticket/itsm_existed`,
|
||||||
|
method: 'GET',
|
||||||
|
isShowMessage: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -402,7 +402,15 @@ const cmdb_en = {
|
||||||
noModifications: 'No Modifications',
|
noModifications: 'No Modifications',
|
||||||
attr: 'attribute',
|
attr: 'attribute',
|
||||||
attrId: 'attribute id',
|
attrId: 'attribute id',
|
||||||
changeDescription: 'attribute id: {attr_id}, {before_days} day(s) in advance, Subject: {subject}\nContent: {body}\nNotify At: {notify_at}'
|
changeDescription: 'attribute id: {attr_id}, {before_days} day(s) in advance, Subject: {subject}\nContent: {body}\nNotify At: {notify_at}',
|
||||||
|
ticketStartTime: 'Start Time',
|
||||||
|
ticketCreator: 'Creator',
|
||||||
|
ticketTitle: 'Title',
|
||||||
|
ticketFinishTime: 'Finish Time',
|
||||||
|
ticketNodeName: 'Node Name',
|
||||||
|
itsmUninstalled: 'Please use it in combination with VE ITSM',
|
||||||
|
applyItsm: 'Free Apply ITSM',
|
||||||
|
ticketId: 'Ticket ID',
|
||||||
},
|
},
|
||||||
relation_type: {
|
relation_type: {
|
||||||
addRelationType: 'New',
|
addRelationType: 'New',
|
||||||
|
|
|
@ -402,7 +402,15 @@ const cmdb_zh = {
|
||||||
noModifications: '没有修改',
|
noModifications: '没有修改',
|
||||||
attr: '属性名',
|
attr: '属性名',
|
||||||
attrId: '属性ID',
|
attrId: '属性ID',
|
||||||
changeDescription: '属性ID:{attr_id},提前:{before_days}天,主题:{subject}\n内容:{body}\n通知时间:{notify_at}'
|
changeDescription: '属性ID:{attr_id},提前:{before_days}天,主题:{subject}\n内容:{body}\n通知时间:{notify_at}',
|
||||||
|
ticketStartTime: '工单发起时间',
|
||||||
|
ticketCreator: '发起人',
|
||||||
|
ticketTitle: '工单名称',
|
||||||
|
ticketFinishTime: '节点完成时间',
|
||||||
|
ticketNodeName: '节点名称',
|
||||||
|
itsmUninstalled: '请结合维易ITSM使用',
|
||||||
|
applyItsm: '免费申请',
|
||||||
|
ticketId: '工单ID',
|
||||||
},
|
},
|
||||||
relation_type: {
|
relation_type: {
|
||||||
addRelationType: '新增关系类型',
|
addRelationType: '新增关系类型',
|
||||||
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
<template>
|
||||||
|
<div :style="{ height: '100%' }" v-if="itsmInstalled">
|
||||||
|
<vxe-table
|
||||||
|
ref="xTable"
|
||||||
|
show-overflow
|
||||||
|
show-header-overflow
|
||||||
|
resizable
|
||||||
|
border
|
||||||
|
size="small"
|
||||||
|
class="ops-stripe-table"
|
||||||
|
:span-method="mergeRowMethod"
|
||||||
|
:data="tableData"
|
||||||
|
v-bind="ci_id ? { height: 'auto' } : { height: `${windowHeight - 225}px` }"
|
||||||
|
>
|
||||||
|
<template #empty>
|
||||||
|
<a-empty :image-style="{ height: '100px' }" :style="{ paddingTop: '10%' }">
|
||||||
|
<img slot="image" :src="require('@/assets/data_empty.png')" />
|
||||||
|
<span slot="description"> {{ $t('noData') }} </span>
|
||||||
|
</a-empty>
|
||||||
|
</template>
|
||||||
|
<vxe-column field="ticket.ticket_id" min-width="80" :title="$t('cmdb.history.ticketId')"> </vxe-column>
|
||||||
|
<vxe-column field="ticket.created_at" width="160" :title="$t('cmdb.history.ticketStartTime')"> </vxe-column>
|
||||||
|
<vxe-column field="ticket.creator_name" min-width="80" :title="$t('cmdb.history.ticketCreator')"> </vxe-column>
|
||||||
|
<vxe-column field="ticket.title" min-width="150" :title="$t('cmdb.history.ticketTitle')">
|
||||||
|
<template slot-scope="{ row }">
|
||||||
|
<a target="_blank" :href="row.ticket.url">{{ row.ticket.title }}</a>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
<vxe-column field="ticket.node_finish_time" width="160" :title="$t('cmdb.history.ticketFinishTime')">
|
||||||
|
</vxe-column>
|
||||||
|
<vxe-column field="ticket.node_name" min-width="100" :title="$t('cmdb.history.ticketNodeName')"> </vxe-column>
|
||||||
|
<vxe-table-column
|
||||||
|
field="operate_type"
|
||||||
|
min-width="100"
|
||||||
|
:filters="[
|
||||||
|
{ value: 0, label: $t('new') },
|
||||||
|
{ value: 1, label: $t('delete') },
|
||||||
|
{ value: 3, label: $t('update') },
|
||||||
|
]"
|
||||||
|
:filter-method="filterOperateMethod"
|
||||||
|
:title="$t('operation')"
|
||||||
|
>
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ operateTypeMap[row.operate_type] }}
|
||||||
|
</template>
|
||||||
|
</vxe-table-column>
|
||||||
|
<vxe-table-column
|
||||||
|
field="attr_alias"
|
||||||
|
min-width="100"
|
||||||
|
:title="$t('cmdb.attribute')"
|
||||||
|
:filters="[]"
|
||||||
|
:filter-method="filterAttrMethod"
|
||||||
|
>
|
||||||
|
</vxe-table-column>
|
||||||
|
<vxe-table-column field="old" min-width="100" :title="$t('cmdb.history.old')"></vxe-table-column>
|
||||||
|
<vxe-table-column field="new" min-width="100" :title="$t('cmdb.history.new')"></vxe-table-column>
|
||||||
|
</vxe-table>
|
||||||
|
<div :style="{ textAlign: 'right' }" v-if="!ci_id">
|
||||||
|
<a-pagination
|
||||||
|
size="small"
|
||||||
|
show-size-changer
|
||||||
|
show-quick-jumper
|
||||||
|
:page-size-options="pageSizeOptions"
|
||||||
|
:current="tablePage.currentPage"
|
||||||
|
:total="tablePage.totalResult"
|
||||||
|
:show-total="(total, range) => $t('cmdb.history.totalItems', { total: total })"
|
||||||
|
:page-size="tablePage.pageSize"
|
||||||
|
:default-current="1"
|
||||||
|
@change="pageOrSizeChange"
|
||||||
|
@showSizeChange="pageOrSizeChange"
|
||||||
|
>
|
||||||
|
</a-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-empty
|
||||||
|
v-else
|
||||||
|
:image-style="{
|
||||||
|
height: '200px',
|
||||||
|
}"
|
||||||
|
:style="{ paddingTop: '10%' }"
|
||||||
|
>
|
||||||
|
<img slot="image" :src="require('@/modules/cmdb/assets/itsm_uninstalled.png')" />
|
||||||
|
<span slot="description"> {{ $t('cmdb.history.itsmUninstalled') }} </span>
|
||||||
|
<a-button href="https://veops.cn/apply" target="_blank" type="primary">
|
||||||
|
{{ $t('cmdb.history.applyItsm') }}
|
||||||
|
</a-button>
|
||||||
|
</a-empty>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getCiRelatedTickets } from '../../../api/history'
|
||||||
|
export default {
|
||||||
|
name: 'RelatedItsmTable',
|
||||||
|
props: {
|
||||||
|
ci_id: {
|
||||||
|
type: Number,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
ciHistory: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
itsmInstalled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tableData: [],
|
||||||
|
tablePage: {
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 50,
|
||||||
|
totalResult: 0,
|
||||||
|
},
|
||||||
|
pageSizeOptions: ['50', '100', '200'],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
windowHeight() {
|
||||||
|
return this.$store.state.windowHeight
|
||||||
|
},
|
||||||
|
operateTypeMap() {
|
||||||
|
return {
|
||||||
|
0: this.$t('new'),
|
||||||
|
1: this.$t('delete'),
|
||||||
|
2: this.$t('update'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.updateTableData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateTableData(currentPage = 1, pageSize = this.tablePage.pageSize) {
|
||||||
|
const params = { page: currentPage, page_size: pageSize, next_todo_ids: [] }
|
||||||
|
if (this.ci_id) {
|
||||||
|
const tableData = []
|
||||||
|
this.ciHistory.forEach((item) => {
|
||||||
|
if (item.ticket_id) {
|
||||||
|
params.next_todo_ids.push(item.ticket_id)
|
||||||
|
tableData.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (params.next_todo_ids.length) {
|
||||||
|
getCiRelatedTickets(params)
|
||||||
|
.then((res) => {
|
||||||
|
const ticketId2Detail = {}
|
||||||
|
res.forEach((item) => {
|
||||||
|
ticketId2Detail[item.next_todo_id] = item
|
||||||
|
})
|
||||||
|
this.tableData = tableData.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
ticket: ticketId2Detail[item.ticket_id],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.updateAttrFilter()
|
||||||
|
})
|
||||||
|
.catch((e) => {})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateAttrFilter() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const $table = this.$refs.xTable
|
||||||
|
if ($table) {
|
||||||
|
const attrColumn = $table.getColumnByField('attr_alias')
|
||||||
|
if (attrColumn) {
|
||||||
|
$table.setFilter(
|
||||||
|
attrColumn,
|
||||||
|
this.tableData.map((item) => {
|
||||||
|
return { value: item.attr_alias, label: item.attr_alias }
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
mergeRowMethod({ row, _rowIndex, column, visibleData }) {
|
||||||
|
const fields = [
|
||||||
|
'ticket.ticket_id',
|
||||||
|
'ticket.created_at',
|
||||||
|
'ticket.creator_name',
|
||||||
|
'ticket.title',
|
||||||
|
'ticket.node_finish_time',
|
||||||
|
'ticket.node_name',
|
||||||
|
]
|
||||||
|
const cellValue1 = row.ticket.ticket_id
|
||||||
|
const cellValue2 = row.ticket.node_name
|
||||||
|
if (cellValue1 && cellValue2 && fields.includes(column.property)) {
|
||||||
|
const prevRow = visibleData[_rowIndex - 1]
|
||||||
|
let nextRow = visibleData[_rowIndex + 1]
|
||||||
|
if (prevRow && prevRow.ticket.ticket_id === cellValue1 && prevRow.ticket.node_name === cellValue2) {
|
||||||
|
return { rowspan: 0, colspan: 0 }
|
||||||
|
} else {
|
||||||
|
let countRowspan = 1
|
||||||
|
while (nextRow && nextRow.ticket.ticket_id === cellValue1 && nextRow.ticket.node_name === cellValue2) {
|
||||||
|
nextRow = visibleData[++countRowspan + _rowIndex]
|
||||||
|
}
|
||||||
|
if (countRowspan > 1) {
|
||||||
|
return { rowspan: countRowspan, colspan: 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pageOrSizeChange(currentPage, pageSize) {
|
||||||
|
this.updateTableData(currentPage, pageSize)
|
||||||
|
},
|
||||||
|
filterOperateMethod({ value, row, column }) {
|
||||||
|
return Number(row.operate_type) === Number(value)
|
||||||
|
},
|
||||||
|
filterAttrMethod({ value, row, column }) {
|
||||||
|
return row.attr_alias === value
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
|
@ -41,9 +41,16 @@
|
||||||
height="auto"
|
height="auto"
|
||||||
:span-method="mergeRowMethod"
|
:span-method="mergeRowMethod"
|
||||||
border
|
border
|
||||||
|
resizable
|
||||||
:scroll-y="{ enabled: false }"
|
:scroll-y="{ enabled: false }"
|
||||||
class="ops-stripe-table"
|
class="ops-stripe-table"
|
||||||
>
|
>
|
||||||
|
<template #empty>
|
||||||
|
<a-empty :image-style="{ height: '100px' }" :style="{ paddingTop: '10%' }">
|
||||||
|
<img slot="image" :src="require('@/assets/data_empty.png')" />
|
||||||
|
<span slot="description"> {{ $t('noData') }} </span>
|
||||||
|
</a-empty>
|
||||||
|
</template>
|
||||||
<vxe-table-column sortable field="created_at" :title="$t('created_at')"></vxe-table-column>
|
<vxe-table-column sortable field="created_at" :title="$t('created_at')"></vxe-table-column>
|
||||||
<vxe-table-column
|
<vxe-table-column
|
||||||
field="username"
|
field="username"
|
||||||
|
@ -82,6 +89,12 @@
|
||||||
<TriggerTable :ci_id="ci._id" />
|
<TriggerTable :ci_id="ci._id" />
|
||||||
</div>
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="tab_5">
|
||||||
|
<span slot="tab"><ops-icon type="itsm-association" />{{ $t('cmdb.ci.relITSM') }}</span>
|
||||||
|
<div :style="{ padding: '24px', height: '100%' }">
|
||||||
|
<RelatedItsmTable :ci_id="ci._id" :ciHistory="ciHistory" :itsmInstalled="itsmInstalled" />
|
||||||
|
</div>
|
||||||
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
<a-empty
|
<a-empty
|
||||||
v-else
|
v-else
|
||||||
|
@ -100,11 +113,12 @@
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { Descriptions, DescriptionsItem } from 'element-ui'
|
import { Descriptions, DescriptionsItem } from 'element-ui'
|
||||||
import { getCITypeGroupById, getCITypes } from '@/modules/cmdb/api/CIType'
|
import { getCITypeGroupById, getCITypes } from '@/modules/cmdb/api/CIType'
|
||||||
import { getCIHistory } from '@/modules/cmdb/api/history'
|
import { getCIHistory, judgeItsmInstalled } from '@/modules/cmdb/api/history'
|
||||||
import { getCIById } from '@/modules/cmdb/api/ci'
|
import { getCIById } from '@/modules/cmdb/api/ci'
|
||||||
import CiDetailAttrContent from './ciDetailAttrContent.vue'
|
import CiDetailAttrContent from './ciDetailAttrContent.vue'
|
||||||
import CiDetailRelation from './ciDetailRelation.vue'
|
import CiDetailRelation from './ciDetailRelation.vue'
|
||||||
import TriggerTable from '../../operation_history/modules/triggerTable.vue'
|
import TriggerTable from '../../operation_history/modules/triggerTable.vue'
|
||||||
|
import RelatedItsmTable from './ciDetailRelatedItsmTable.vue'
|
||||||
export default {
|
export default {
|
||||||
name: 'CiDetailTab',
|
name: 'CiDetailTab',
|
||||||
components: {
|
components: {
|
||||||
|
@ -113,6 +127,7 @@ export default {
|
||||||
CiDetailAttrContent,
|
CiDetailAttrContent,
|
||||||
CiDetailRelation,
|
CiDetailRelation,
|
||||||
TriggerTable,
|
TriggerTable,
|
||||||
|
RelatedItsmTable,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
typeId: {
|
typeId: {
|
||||||
|
@ -134,6 +149,7 @@ export default {
|
||||||
ciId: null,
|
ciId: null,
|
||||||
ci_types: [],
|
ci_types: [],
|
||||||
hasPermission: true,
|
hasPermission: true,
|
||||||
|
itsmInstalled: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -179,6 +195,7 @@ export default {
|
||||||
}
|
}
|
||||||
this.ciId = ciId
|
this.ciId = ciId
|
||||||
await this.getCI()
|
await this.getCI()
|
||||||
|
await this.judgeItsmInstalled()
|
||||||
if (this.hasPermission) {
|
if (this.hasPermission) {
|
||||||
this.getAttributes()
|
this.getAttributes()
|
||||||
this.getCIHistory()
|
this.getCIHistory()
|
||||||
|
@ -203,7 +220,15 @@ export default {
|
||||||
this.hasPermission = false
|
this.hasPermission = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => {})
|
.catch((e) => {
|
||||||
|
if (e.response.status === 404) {
|
||||||
|
this.itsmInstalled = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async judgeItsmInstalled() {
|
||||||
|
await judgeItsmInstalled()
|
||||||
|
.catch((e) => { this.itsmInstalled = false })
|
||||||
},
|
},
|
||||||
|
|
||||||
getCIHistory() {
|
getCIHistory() {
|
||||||
|
|
|
@ -9,6 +9,12 @@
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
v-bind="ci_id ? { height: 'auto' } : { height: `${windowHeight - 225}px` }"
|
v-bind="ci_id ? { height: 'auto' } : { height: `${windowHeight - 225}px` }"
|
||||||
>
|
>
|
||||||
|
<template #empty>
|
||||||
|
<a-empty :image-style="{ height: '100px' }" :style="{ paddingTop: '10%' }">
|
||||||
|
<img slot="image" :src="require('@/assets/data_empty.png')" />
|
||||||
|
<span slot="description"> {{ $t('noData') }} </span>
|
||||||
|
</a-empty>
|
||||||
|
</template>
|
||||||
<vxe-column field="trigger_name" :title="$t('cmdb.history.triggerName')"> </vxe-column>
|
<vxe-column field="trigger_name" :title="$t('cmdb.history.triggerName')"> </vxe-column>
|
||||||
<vxe-column field="type" :title="$t('type')">
|
<vxe-column field="type" :title="$t('type')">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
|
|
Loading…
Reference in New Issue