mirror of https://github.com/veops/cmdb.git
feat(ui): CI change logs related itsm
This commit is contained in:
parent
d2b7161e39
commit
69fb7f88ae
|
@ -54,3 +54,20 @@ export function getCiTriggersByCiId(ci_id, 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',
|
||||
attr: 'attribute',
|
||||
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: {
|
||||
addRelationType: 'New',
|
||||
|
|
|
@ -402,7 +402,15 @@ const cmdb_zh = {
|
|||
noModifications: '没有修改',
|
||||
attr: '属性名',
|
||||
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: {
|
||||
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"
|
||||
:span-method="mergeRowMethod"
|
||||
border
|
||||
resizable
|
||||
:scroll-y="{ enabled: false }"
|
||||
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
|
||||
field="username"
|
||||
|
@ -82,6 +89,12 @@
|
|||
<TriggerTable :ci_id="ci._id" />
|
||||
</div>
|
||||
</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-empty
|
||||
v-else
|
||||
|
@ -100,11 +113,12 @@
|
|||
import _ from 'lodash'
|
||||
import { Descriptions, DescriptionsItem } from 'element-ui'
|
||||
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 CiDetailAttrContent from './ciDetailAttrContent.vue'
|
||||
import CiDetailRelation from './ciDetailRelation.vue'
|
||||
import TriggerTable from '../../operation_history/modules/triggerTable.vue'
|
||||
import RelatedItsmTable from './ciDetailRelatedItsmTable.vue'
|
||||
export default {
|
||||
name: 'CiDetailTab',
|
||||
components: {
|
||||
|
@ -113,6 +127,7 @@ export default {
|
|||
CiDetailAttrContent,
|
||||
CiDetailRelation,
|
||||
TriggerTable,
|
||||
RelatedItsmTable,
|
||||
},
|
||||
props: {
|
||||
typeId: {
|
||||
|
@ -134,6 +149,7 @@ export default {
|
|||
ciId: null,
|
||||
ci_types: [],
|
||||
hasPermission: true,
|
||||
itsmInstalled: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -179,6 +195,7 @@ export default {
|
|||
}
|
||||
this.ciId = ciId
|
||||
await this.getCI()
|
||||
await this.judgeItsmInstalled()
|
||||
if (this.hasPermission) {
|
||||
this.getAttributes()
|
||||
this.getCIHistory()
|
||||
|
@ -203,7 +220,15 @@ export default {
|
|||
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() {
|
||||
|
|
|
@ -9,6 +9,12 @@
|
|||
: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="trigger_name" :title="$t('cmdb.history.triggerName')"> </vxe-column>
|
||||
<vxe-column field="type" :title="$t('type')">
|
||||
<template #default="{ row }">
|
||||
|
|
Loading…
Reference in New Issue