mirror of https://github.com/veops/cmdb.git
Merge pull request #591 from veops/dev_ui_240813
refactor(ui): ci table
This commit is contained in:
commit
e2872f041e
|
@ -0,0 +1,393 @@
|
||||||
|
<template>
|
||||||
|
<div class="ci-table-wrap">
|
||||||
|
<ops-table
|
||||||
|
:id="id"
|
||||||
|
border
|
||||||
|
keep-source
|
||||||
|
show-overflow
|
||||||
|
resizable
|
||||||
|
ref="xTable"
|
||||||
|
size="small"
|
||||||
|
:loading="loading"
|
||||||
|
:row-config="{ useKey: true, keyField: '_id' }"
|
||||||
|
show-header-overflow
|
||||||
|
highlight-hover-row
|
||||||
|
:checkbox-config="{ reserve: true, highlight: true, range: true }"
|
||||||
|
:edit-config="{ trigger: 'dblclick', mode: 'row', showIcon: false }"
|
||||||
|
:sort-config="{ remote: true, trigger: 'cell' }"
|
||||||
|
:row-key="true"
|
||||||
|
:column-key="true"
|
||||||
|
:cell-style="getCellStyle"
|
||||||
|
:scroll-y="{ enabled: true, gt: 20 }"
|
||||||
|
:scroll-x="{ enabled: true, gt: 20 }"
|
||||||
|
class="ops-unstripe-table checkbox-hover-table"
|
||||||
|
:custom-config="{ storage: true }"
|
||||||
|
@checkbox-change="onSelectChange"
|
||||||
|
@checkbox-all="onSelectChange"
|
||||||
|
@checkbox-range-end="onSelectRangeEnd"
|
||||||
|
v-bind="$attrs"
|
||||||
|
v-on="$listeners"
|
||||||
|
>
|
||||||
|
<vxe-column
|
||||||
|
align="center"
|
||||||
|
type="checkbox"
|
||||||
|
width="60"
|
||||||
|
:fixed="isCheckboxFixed ? 'left' : ''"
|
||||||
|
v-if="showCheckbox"
|
||||||
|
>
|
||||||
|
<template #default="{row}">
|
||||||
|
{{ getRowSeq(row) }}
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
<vxe-table-column
|
||||||
|
v-for="(col, index) in columns"
|
||||||
|
:key="`${col.field}_${index}`"
|
||||||
|
:title="col.title"
|
||||||
|
:field="col.field"
|
||||||
|
:width="col.width"
|
||||||
|
:sortable="col.sortable"
|
||||||
|
:edit-render="getColumnsEditRender(col)"
|
||||||
|
:cell-type="col.value_type === '2' ? 'string' : 'auto'"
|
||||||
|
:fixed="col.is_fixed ? 'left' : ''"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<span class="vxe-handle">
|
||||||
|
<OpsMoveIcon class="header-move-icon" />
|
||||||
|
<span>{{ col.title }}</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template v-if="col.is_choice || col.is_password" #edit="{ row }">
|
||||||
|
<vxe-input v-if="col.is_password" v-model="passwordValue[col.field]" />
|
||||||
|
<a-select
|
||||||
|
v-if="col.is_choice"
|
||||||
|
v-model="row[col.field]"
|
||||||
|
:getPopupContainer="(trigger) => trigger.parentElement"
|
||||||
|
:style="{ width: '100%', height: '32px' }"
|
||||||
|
:placeholder="$t('placeholder2')"
|
||||||
|
:showArrow="false"
|
||||||
|
:mode="col.is_list ? 'multiple' : 'default'"
|
||||||
|
class="ci-table-edit-select"
|
||||||
|
allowClear
|
||||||
|
showSearch
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="(choice, idx) in col.filters"
|
||||||
|
:value="choice[0]"
|
||||||
|
:key="'edit_' + col.field + idx"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
:style="{
|
||||||
|
...(choice[1] ? choice[1].style : {}),
|
||||||
|
display: 'inline-flex',
|
||||||
|
alignItems: 'center'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template v-if="choice[1] && choice[1].icon && choice[1].icon.name">
|
||||||
|
<img
|
||||||
|
v-if="choice[1].icon.id && choice[1].icon.url"
|
||||||
|
:src="`/api/common-setting/v1/file/${choice[1].icon.url}`"
|
||||||
|
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
||||||
|
/>
|
||||||
|
<ops-icon
|
||||||
|
v-else
|
||||||
|
:style="{ color: choice[1].icon.color, marginRight: '5px' }"
|
||||||
|
:type="choice[1].icon.name"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<span>{{ choice[0] }}</span>
|
||||||
|
</span>
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
<template
|
||||||
|
v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice"
|
||||||
|
#default="{ row }"
|
||||||
|
>
|
||||||
|
<span v-if="col.value_type === '6' && row[col.field]">{{ row[col.field] }}</span>
|
||||||
|
<template v-else-if="col.is_link && row[col.field]">
|
||||||
|
<a
|
||||||
|
v-for="(item, linkIndex) in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||||
|
:key="linkIndex"
|
||||||
|
:href="
|
||||||
|
item.startsWith('http') || item.startsWith('https')
|
||||||
|
? `${item}`
|
||||||
|
: `http://${item}`
|
||||||
|
"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{{ item }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<PasswordField
|
||||||
|
v-else-if="col.is_password && row[col.field]"
|
||||||
|
:ci_id="row._id"
|
||||||
|
:attr_id="col.attr_id"
|
||||||
|
></PasswordField>
|
||||||
|
<template v-else-if="col.is_choice">
|
||||||
|
<span
|
||||||
|
v-for="value in (col.is_list ? row[col.field] : [row[col.field]])"
|
||||||
|
:key="value"
|
||||||
|
:style="getChoiceValueStyle(col, value)"
|
||||||
|
class="column-default-choice"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-if="getChoiceValueIcon(col, value).id && getChoiceValueIcon(col, value).url"
|
||||||
|
:src="`/api/common-setting/v1/file/${getChoiceValueIcon(col, value).url}`"
|
||||||
|
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
||||||
|
/>
|
||||||
|
<ops-icon
|
||||||
|
v-else-if="getChoiceValueIcon(col, value).name"
|
||||||
|
:style="{ color: getChoiceValueIcon(col, value).color, marginRight: '5px' }"
|
||||||
|
:type="getChoiceValueIcon(col, value).name"
|
||||||
|
/>
|
||||||
|
{{ value }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</vxe-table-column>
|
||||||
|
<vxe-column align="left" field="operate" fixed="right" width="80">
|
||||||
|
<template #header>
|
||||||
|
<span>{{ $t('operation') }}</span>
|
||||||
|
</template>
|
||||||
|
<template #default="{ row }">
|
||||||
|
<a-space>
|
||||||
|
<a @click="openDetail(row.ci_id || row._id)">
|
||||||
|
<a-icon type="unordered-list" />
|
||||||
|
</a>
|
||||||
|
<a-tooltip :title="$t('cmdb.ci.addRelation')">
|
||||||
|
<a @click="openDetail(row.ci_id || row._id, 'tab_2', '2')">
|
||||||
|
<a-icon type="retweet" />
|
||||||
|
</a>
|
||||||
|
</a-tooltip>
|
||||||
|
<a v-if="showDelete" @click="deleteCI(row)" :style="{ color: 'red' }">
|
||||||
|
<a-icon type="delete" />
|
||||||
|
</a>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
<template #empty>
|
||||||
|
<div
|
||||||
|
v-if="loading"
|
||||||
|
class="ci-table-loading"
|
||||||
|
>
|
||||||
|
{{ loadingTip || $t('loading') }}
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<img :style="{ width: '200px' }" :src="require('@/assets/data_empty.png')" />
|
||||||
|
<div>{{ $t('noData') }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #loading>
|
||||||
|
<div class="ci-table-loading">{{ loadingTip || $t('loading') }}</div>
|
||||||
|
</template>
|
||||||
|
</ops-table>
|
||||||
|
|
||||||
|
<JsonEditor ref="jsonEditor" @jsonEditorOk="jsonEditorOk" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import JsonEditor from '../JsonEditor/jsonEditor.vue'
|
||||||
|
import PasswordField from '../passwordField/index.vue'
|
||||||
|
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CITable',
|
||||||
|
components: {
|
||||||
|
JsonEditor,
|
||||||
|
PasswordField,
|
||||||
|
OpsMoveIcon
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
// table ID
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// table Loading
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
// ci 属性列表
|
||||||
|
attrList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
// table column
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
passwordValue: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
|
// 加载提示
|
||||||
|
loadingTip: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否展示复选框
|
||||||
|
showCheckbox: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否展示删除按钮
|
||||||
|
showDelete: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
isCheckboxFixed() {
|
||||||
|
const idx = this.columns.findIndex((item) => item.is_fixed)
|
||||||
|
return idx > -1
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
getVxetableRef() {
|
||||||
|
return this?.$refs?.['xTable']?.getVxetableRef?.() || null
|
||||||
|
},
|
||||||
|
|
||||||
|
onSelectChange() {
|
||||||
|
const xTable = this.getVxetableRef()
|
||||||
|
const records = [...xTable.getCheckboxRecords(), ...xTable.getCheckboxReserveRecords()]
|
||||||
|
this.$emit('onSelectChange', records)
|
||||||
|
},
|
||||||
|
|
||||||
|
onSelectRangeEnd({ records }) {
|
||||||
|
this.$emit('onSelectChange', records)
|
||||||
|
},
|
||||||
|
|
||||||
|
getCellStyle({ row, rowIndex, $rowIndex, column, columnIndex, $columnIndex }) {
|
||||||
|
const { property } = column
|
||||||
|
const _find = this.attrList.find((attr) => attr.name === property)
|
||||||
|
if (
|
||||||
|
_find &&
|
||||||
|
_find.option &&
|
||||||
|
_find.option.fontOptions &&
|
||||||
|
row[`${property}`] !== undefined &&
|
||||||
|
row[`${property}`] !== null
|
||||||
|
) {
|
||||||
|
return { ..._find.option.fontOptions }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getColumnsEditRender(col) {
|
||||||
|
const _editRender = {
|
||||||
|
...col.editRender,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (col.value_type === '6') {
|
||||||
|
_editRender.events = { focus: this.handleFocusJson }
|
||||||
|
}
|
||||||
|
|
||||||
|
return _editRender
|
||||||
|
},
|
||||||
|
|
||||||
|
handleFocusJson({ column, row }) {
|
||||||
|
this.$refs.jsonEditor.open(column, row)
|
||||||
|
},
|
||||||
|
|
||||||
|
jsonEditorOk(row, column, jsonData) {
|
||||||
|
this.$attrs.data.forEach((item) => {
|
||||||
|
if (item._id === row._id) {
|
||||||
|
item[column.property] = JSON.stringify(jsonData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.getVxetableRef().refreshColumn()
|
||||||
|
},
|
||||||
|
|
||||||
|
getChoiceValueStyle(col, colValue) {
|
||||||
|
const _find = col.filters.find((item) => String(item[0]) === String(colValue))
|
||||||
|
if (_find) {
|
||||||
|
return _find[1]?.style || {}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
|
||||||
|
getChoiceValueIcon(col, colValue) {
|
||||||
|
const _find = col.filters.find((item) => String(item[0]) === String(colValue))
|
||||||
|
if (_find) {
|
||||||
|
return _find[1]?.icon || {}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开启当前 ci 详情弹窗
|
||||||
|
*/
|
||||||
|
openDetail(id, activeTabKey, ciDetailRelationKey) {
|
||||||
|
this.$emit('openDetail', id, activeTabKey, ciDetailRelationKey)
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteCI(row) {
|
||||||
|
this.$emit('deleteCI', row)
|
||||||
|
},
|
||||||
|
|
||||||
|
getRowSeq(row) {
|
||||||
|
return this.getVxetableRef().getRowSeq(row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.ci-table-wrap {
|
||||||
|
.ci-table-loading {
|
||||||
|
width: 100%;
|
||||||
|
line-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-move-icon {
|
||||||
|
width: 17px;
|
||||||
|
height: 17px;
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
left: -3px;
|
||||||
|
top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-default-choice {
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1px 5px;
|
||||||
|
margin: 2px;
|
||||||
|
vertical-align: bottom;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-hover-table {
|
||||||
|
/deep/ .vxe-table--body-wrapper {
|
||||||
|
.vxe-checkbox--label {
|
||||||
|
display: inline;
|
||||||
|
padding-left: 0px !important;
|
||||||
|
color: #bfbfbf;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-icon-checkbox-unchecked {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-icon-checkbox-checked ~ .vxe-checkbox--label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-cell--checkbox {
|
||||||
|
&:hover {
|
||||||
|
.vxe-icon-checkbox-unchecked {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-checkbox--label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -74,205 +74,24 @@
|
||||||
</div>
|
</div>
|
||||||
</SearchForm>
|
</SearchForm>
|
||||||
<CiDetailDrawer ref="detail" :typeId="typeId" />
|
<CiDetailDrawer ref="detail" :typeId="typeId" />
|
||||||
<ops-table
|
|
||||||
:id="`cmdb-ci-${typeId}`"
|
<CITable
|
||||||
border
|
|
||||||
keep-source
|
|
||||||
show-overflow
|
|
||||||
resizable
|
|
||||||
ref="xTable"
|
ref="xTable"
|
||||||
size="small"
|
:id="`cmdb-ci-${typeId}`"
|
||||||
:row-config="{ useKey: true, keyField: '_id' }"
|
:loading="loading"
|
||||||
:height="tableHeight"
|
:attrList="preferenceAttrList"
|
||||||
show-header-overflow
|
:columns="columns"
|
||||||
highlight-hover-row
|
:passwordValue="passwordValue"
|
||||||
:data="instanceList"
|
:data="instanceList"
|
||||||
@checkbox-change="onSelectChange"
|
:height="tableHeight"
|
||||||
@checkbox-all="onSelectChange"
|
@onSelectChange="onSelectChange"
|
||||||
@checkbox-range-end="onSelectRangeEnd"
|
|
||||||
:checkbox-config="{ reserve: true, highlight: true, range: true }"
|
|
||||||
@edit-closed="handleEditClose"
|
@edit-closed="handleEditClose"
|
||||||
@edit-actived="handleEditActived"
|
@edit-actived="handleEditActived"
|
||||||
:edit-config="{ trigger: 'dblclick', mode: 'row', showIcon: false }"
|
|
||||||
:sort-config="{ remote: true, trigger: 'cell' }"
|
|
||||||
@sort-change="handleSortCol"
|
@sort-change="handleSortCol"
|
||||||
:row-key="true"
|
@openDetail="openDetail"
|
||||||
:column-key="true"
|
@deleteCI="deleteCI"
|
||||||
:cell-style="getCellStyle"
|
/>
|
||||||
:scroll-y="{ enabled: true, gt: 20 }"
|
|
||||||
:scroll-x="{ enabled: true, gt: 0 }"
|
|
||||||
class="ops-unstripe-table checkbox-hover-table"
|
|
||||||
:custom-config="{ storage: true }"
|
|
||||||
>
|
|
||||||
<vxe-column align="center" type="checkbox" width="60" :fixed="isCheckboxFixed ? 'left' : ''">
|
|
||||||
<template #default="{row}">
|
|
||||||
{{ getRowSeq(row) }}
|
|
||||||
</template>
|
|
||||||
</vxe-column>
|
|
||||||
<vxe-table-column
|
|
||||||
v-for="(col, index) in columns"
|
|
||||||
:key="`${col.field}_${index}`"
|
|
||||||
:title="col.title"
|
|
||||||
:field="col.field"
|
|
||||||
:width="col.width"
|
|
||||||
:sortable="col.sortable"
|
|
||||||
:edit-render="getColumnsEditRender(col)"
|
|
||||||
:cell-type="col.value_type === '2' ? 'string' : 'auto'"
|
|
||||||
:fixed="col.is_fixed ? 'left' : ''"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<span class="vxe-handle">
|
|
||||||
<OpsMoveIcon
|
|
||||||
style="width: 17px; height: 17px; display: none; position: absolute; left: -3px; top: 12px"
|
|
||||||
/>
|
|
||||||
<span>{{ col.title }}</span>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<template v-if="col.is_choice || col.is_password" #edit="{ row }">
|
|
||||||
<vxe-input v-if="col.is_password" v-model="passwordValue[col.field]" />
|
|
||||||
<a-select
|
|
||||||
:getPopupContainer="(trigger) => trigger.parentElement"
|
|
||||||
:style="{ width: '100%', height: '32px' }"
|
|
||||||
v-model="row[col.field]"
|
|
||||||
:v-bind="$t('placeholder2')"
|
|
||||||
v-if="col.is_choice"
|
|
||||||
:showArrow="false"
|
|
||||||
:mode="col.is_list ? 'multiple' : 'default'"
|
|
||||||
class="ci-table-edit-select"
|
|
||||||
allowClear
|
|
||||||
showSearch
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
:value="choice[0]"
|
|
||||||
:key="'edit_' + col.field + idx"
|
|
||||||
v-for="(choice, idx) in col.filters"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
:style="{ ...(choice[1] ? choice[1].style : {}), display: 'inline-flex', alignItems: 'center' }"
|
|
||||||
>
|
|
||||||
<template v-if="choice[1] && choice[1].icon && choice[1].icon.name">
|
|
||||||
<img
|
|
||||||
v-if="choice[1].icon.id && choice[1].icon.url"
|
|
||||||
:src="`/api/common-setting/v1/file/${choice[1].icon.url}`"
|
|
||||||
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
|
||||||
/>
|
|
||||||
<ops-icon
|
|
||||||
v-else
|
|
||||||
:style="{ color: choice[1].icon.color, marginRight: '5px' }"
|
|
||||||
:type="choice[1].icon.name"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<span>{{ choice[0] }}</span>
|
|
||||||
</span>
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</template>
|
|
||||||
<template
|
|
||||||
v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice"
|
|
||||||
#default="{ row }"
|
|
||||||
>
|
|
||||||
<span v-if="col.value_type === '6' && row[col.field]">{{ row[col.field] }}</span>
|
|
||||||
<template v-else-if="col.is_link && row[col.field]">
|
|
||||||
<a
|
|
||||||
v-for="(item, linkIndex) in (col.is_list ? row[col.field] : [row[col.field]])"
|
|
||||||
:key="linkIndex"
|
|
||||||
:href="
|
|
||||||
item.startsWith('http') || item.startsWith('https')
|
|
||||||
? `${item}`
|
|
||||||
: `http://${item}`
|
|
||||||
"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
{{ item }}
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
<PasswordField
|
|
||||||
v-else-if="col.is_password && row[col.field]"
|
|
||||||
:ci_id="row._id"
|
|
||||||
:attr_id="col.attr_id"
|
|
||||||
></PasswordField>
|
|
||||||
<template v-else-if="col.is_choice">
|
|
||||||
<template v-if="col.is_list">
|
|
||||||
<span
|
|
||||||
v-for="value in row[col.field]"
|
|
||||||
:key="value"
|
|
||||||
:style="{
|
|
||||||
borderRadius: '4px',
|
|
||||||
padding: '1px 5px',
|
|
||||||
margin: '2px',
|
|
||||||
verticalAlign: 'bottom',
|
|
||||||
...getChoiceValueStyle(col, value),
|
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
v-if="getChoiceValueIcon(col, value).id && getChoiceValueIcon(col, value).url"
|
|
||||||
:src="`/api/common-setting/v1/file/${getChoiceValueIcon(col, value).url}`"
|
|
||||||
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
|
||||||
/>
|
|
||||||
<ops-icon
|
|
||||||
v-else-if="getChoiceValueIcon(col, value).name"
|
|
||||||
:style="{ color: getChoiceValueIcon(col, value).color, marginRight: '5px' }"
|
|
||||||
:type="getChoiceValueIcon(col, value).name"
|
|
||||||
/>{{ value }}
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<span
|
|
||||||
v-else
|
|
||||||
:style="{
|
|
||||||
borderRadius: '4px',
|
|
||||||
padding: '1px 5px',
|
|
||||||
margin: '2px 0',
|
|
||||||
verticalAlign: 'bottom',
|
|
||||||
...getChoiceValueStyle(col, row[col.field]),
|
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
v-if="getChoiceValueIcon(col, row[col.field]).id && getChoiceValueIcon(col, row[col.field]).url"
|
|
||||||
:src="`/api/common-setting/v1/file/${getChoiceValueIcon(col, row[col.field]).url}`"
|
|
||||||
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
|
||||||
/>
|
|
||||||
<ops-icon
|
|
||||||
v-else-if="getChoiceValueIcon(col, row[col.field]).name"
|
|
||||||
:style="{ color: getChoiceValueIcon(col, row[col.field]).color, marginRight: '5px' }"
|
|
||||||
:type="getChoiceValueIcon(col, row[col.field]).name"
|
|
||||||
/>
|
|
||||||
{{ row[col.field] }}
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</vxe-table-column>
|
|
||||||
<vxe-column align="left" field="operate" fixed="right" width="80">
|
|
||||||
<template #header>
|
|
||||||
<span>{{ $t('operation') }}</span>
|
|
||||||
</template>
|
|
||||||
<template #default="{ row }">
|
|
||||||
<a-space>
|
|
||||||
<a @click="$refs.detail.create(row.ci_id || row._id)">
|
|
||||||
<a-icon type="unordered-list" />
|
|
||||||
</a>
|
|
||||||
<a-tooltip :title="$t('cmdb.ci.addRelation')">
|
|
||||||
<a @click="$refs.detail.create(row.ci_id || row._id, 'tab_2', '2')">
|
|
||||||
<a-icon type="retweet" />
|
|
||||||
</a>
|
|
||||||
</a-tooltip>
|
|
||||||
<a @click="deleteCI(row)" :style="{ color: 'red' }">
|
|
||||||
<a-icon type="delete" />
|
|
||||||
</a>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</vxe-column>
|
|
||||||
<template #empty>
|
|
||||||
<div v-if="loading" style="height: 200px; line-height: 200px">{{ $t('loading') }}</div>
|
|
||||||
<div v-else>
|
|
||||||
<img :style="{ width: '200px' }" :src="require('@/assets/data_empty.png')" />
|
|
||||||
<div>{{ $t('noData') }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</ops-table>
|
|
||||||
<div :style="{ textAlign: 'right', marginTop: '4px' }">
|
<div :style="{ textAlign: 'right', marginTop: '4px' }">
|
||||||
<a-pagination
|
<a-pagination
|
||||||
:showSizeChanger="true"
|
:showSizeChanger="true"
|
||||||
|
@ -304,7 +123,6 @@
|
||||||
</a-pagination>
|
</a-pagination>
|
||||||
</div>
|
</div>
|
||||||
<create-instance-form ref="create" @reload="reloadData" @submit="batchUpdate" />
|
<create-instance-form ref="create" @reload="reloadData" @submit="batchUpdate" />
|
||||||
<JsonEditor ref="jsonEditor" @jsonEditorOk="jsonEditorOk" />
|
|
||||||
<BatchDownload ref="batchDownload" @batchDownload="batchDownload" />
|
<BatchDownload ref="batchDownload" @batchDownload="batchDownload" />
|
||||||
<ci-rollback-form ref="ciRollbackForm" @batchRollbackAsync="batchRollbackAsync($event)" :ciIds="selectedRowKeys" />
|
<ci-rollback-form ref="ciRollbackForm" @batchRollbackAsync="batchRollbackAsync($event)" :ciIds="selectedRowKeys" />
|
||||||
<MetadataDrawer ref="metadataDrawer" />
|
<MetadataDrawer ref="metadataDrawer" />
|
||||||
|
@ -324,7 +142,6 @@ import SearchForm from '../../components/searchForm/SearchForm.vue'
|
||||||
import CreateInstanceForm from './modules/CreateInstanceForm'
|
import CreateInstanceForm from './modules/CreateInstanceForm'
|
||||||
import CiDetailDrawer from './modules/ciDetailDrawer.vue'
|
import CiDetailDrawer from './modules/ciDetailDrawer.vue'
|
||||||
import EditAttrsPopover from './modules/editAttrsPopover'
|
import EditAttrsPopover from './modules/editAttrsPopover'
|
||||||
import JsonEditor from '../../components/JsonEditor/jsonEditor.vue'
|
|
||||||
import { searchCI, updateCI, deleteCI } from '@/modules/cmdb/api/ci'
|
import { searchCI, updateCI, deleteCI } from '@/modules/cmdb/api/ci'
|
||||||
import { getSubscribeAttributes, subscribeCIType, subscribeTreeView } from '@/modules/cmdb/api/preference'
|
import { getSubscribeAttributes, subscribeCIType, subscribeTreeView } from '@/modules/cmdb/api/preference'
|
||||||
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
||||||
|
@ -332,15 +149,14 @@ import { roleHasPermissionToGrant } from '@/modules/acl/api/permission'
|
||||||
import { searchResourceType } from '@/modules/acl/api/resource'
|
import { searchResourceType } from '@/modules/acl/api/resource'
|
||||||
import { getCITableColumns } from '../../utils/helper'
|
import { getCITableColumns } from '../../utils/helper'
|
||||||
import { intersection } from '@/utils/functions/set'
|
import { intersection } from '@/utils/functions/set'
|
||||||
import PasswordField from '../../components/passwordField/index.vue'
|
|
||||||
import BatchDownload from '../../components/batchDownload/batchDownload.vue'
|
import BatchDownload from '../../components/batchDownload/batchDownload.vue'
|
||||||
import PreferenceSearch from '../../components/preferenceSearch/preferenceSearch.vue'
|
import PreferenceSearch from '../../components/preferenceSearch/preferenceSearch.vue'
|
||||||
import MetadataDrawer from './modules/MetadataDrawer.vue'
|
import MetadataDrawer from './modules/MetadataDrawer.vue'
|
||||||
import CMDBGrant from '../../components/cmdbGrant'
|
import CMDBGrant from '../../components/cmdbGrant'
|
||||||
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
|
|
||||||
import { getAttrPassword } from '../../api/CITypeAttr'
|
import { getAttrPassword } from '../../api/CITypeAttr'
|
||||||
import CiRollbackForm from './modules/ciRollbackForm.vue'
|
import CiRollbackForm from './modules/ciRollbackForm.vue'
|
||||||
import { CIBaselineRollback } from '../../api/history'
|
import { CIBaselineRollback } from '../../api/history'
|
||||||
|
import CITable from '@/modules/cmdb/components/ciTable/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'InstanceList',
|
name: 'InstanceList',
|
||||||
|
@ -348,24 +164,18 @@ export default {
|
||||||
SearchForm,
|
SearchForm,
|
||||||
CreateInstanceForm,
|
CreateInstanceForm,
|
||||||
CiDetailDrawer,
|
CiDetailDrawer,
|
||||||
JsonEditor,
|
|
||||||
PasswordField,
|
|
||||||
EditAttrsPopover,
|
EditAttrsPopover,
|
||||||
BatchDownload,
|
BatchDownload,
|
||||||
PreferenceSearch,
|
PreferenceSearch,
|
||||||
MetadataDrawer,
|
MetadataDrawer,
|
||||||
CMDBGrant,
|
CMDBGrant,
|
||||||
OpsMoveIcon,
|
|
||||||
CiRollbackForm,
|
CiRollbackForm,
|
||||||
|
CITable
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
windowHeight() {
|
windowHeight() {
|
||||||
return this.$store.state.windowHeight
|
return this.$store.state.windowHeight
|
||||||
},
|
},
|
||||||
isCheckboxFixed() {
|
|
||||||
const idx = this.columns.findIndex((item) => item.is_fixed)
|
|
||||||
return idx > -1
|
|
||||||
},
|
|
||||||
tableHeight() {
|
tableHeight() {
|
||||||
// if (this.selectedRowKeys && this.selectedRowKeys.length) {
|
// if (this.selectedRowKeys && this.selectedRowKeys.length) {
|
||||||
// return this.windowHeight - 246
|
// return this.windowHeight - 246
|
||||||
|
@ -551,12 +361,7 @@ export default {
|
||||||
const subscribed = await getSubscribeAttributes(this.typeId)
|
const subscribed = await getSubscribeAttributes(this.typeId)
|
||||||
this.preferenceAttrList = subscribed.attributes // All columns that have been subscribed
|
this.preferenceAttrList = subscribed.attributes // All columns that have been subscribed
|
||||||
},
|
},
|
||||||
onSelectChange() {
|
onSelectChange(records) {
|
||||||
const xTable = this.$refs.xTable.getVxetableRef()
|
|
||||||
const records = [...xTable.getCheckboxRecords(), ...xTable.getCheckboxReserveRecords()]
|
|
||||||
this.selectedRowKeys = records.map((i) => i.ci_id || i._id)
|
|
||||||
},
|
|
||||||
onSelectRangeEnd({ records }) {
|
|
||||||
this.selectedRowKeys = records.map((i) => i.ci_id || i._id)
|
this.selectedRowKeys = records.map((i) => i.ci_id || i._id)
|
||||||
},
|
},
|
||||||
reloadData() {
|
reloadData() {
|
||||||
|
@ -820,28 +625,6 @@ export default {
|
||||||
await this.loadPreferenceAttrList()
|
await this.loadPreferenceAttrList()
|
||||||
await this.loadTableData()
|
await this.loadTableData()
|
||||||
},
|
},
|
||||||
getColumnsEditRender(col) {
|
|
||||||
const _editRender = {
|
|
||||||
...col.editRender,
|
|
||||||
}
|
|
||||||
if (col.value_type === '6') {
|
|
||||||
_editRender.events = { focus: this.handleFocusJson }
|
|
||||||
}
|
|
||||||
return _editRender
|
|
||||||
},
|
|
||||||
handleFocusJson({ column, row }) {
|
|
||||||
this.$refs.jsonEditor.open(column, row)
|
|
||||||
},
|
|
||||||
jsonEditorOk(row, column, jsonData) {
|
|
||||||
// The backend writes data at different speeds. You can modify the table data directly without pulling the interface.
|
|
||||||
// this.reloadData()
|
|
||||||
this.instanceList.forEach((item) => {
|
|
||||||
if (item._id === row._id) {
|
|
||||||
item[column.property] = JSON.stringify(jsonData)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.$refs.xTable.getVxetableRef().refreshColumn()
|
|
||||||
},
|
|
||||||
onShowSizeChange(current, pageSize) {
|
onShowSizeChange(current, pageSize) {
|
||||||
this.pageSize = pageSize
|
this.pageSize = pageSize
|
||||||
if (this.currentPage === 1) {
|
if (this.currentPage === 1) {
|
||||||
|
@ -903,23 +686,6 @@ export default {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// tableFilterChangeEvent({ column, property, values, datas, filterList, $event }) {
|
|
||||||
// console.log(111)
|
|
||||||
// },
|
|
||||||
getChoiceValueStyle(col, colValue) {
|
|
||||||
const _find = col.filters.find((item) => String(item[0]) === String(colValue))
|
|
||||||
if (_find) {
|
|
||||||
return _find[1]?.style || {}
|
|
||||||
}
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
getChoiceValueIcon(col, colValue) {
|
|
||||||
const _find = col.filters.find((item) => String(item[0]) === String(colValue))
|
|
||||||
if (_find) {
|
|
||||||
return _find[1]?.icon || {}
|
|
||||||
}
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
handleEditActived() {
|
handleEditActived() {
|
||||||
this.isEditActive = true
|
this.isEditActive = true
|
||||||
const passwordCol = this.columns.filter((col) => col.is_password)
|
const passwordCol = this.columns.filter((col) => col.is_password)
|
||||||
|
@ -945,19 +711,6 @@ export default {
|
||||||
this.lastEditCiId = row._id
|
this.lastEditCiId = row._id
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getCellStyle({ row, rowIndex, $rowIndex, column, columnIndex, $columnIndex }) {
|
|
||||||
const { property } = column
|
|
||||||
const _find = this.preferenceAttrList.find((attr) => attr.name === property)
|
|
||||||
if (
|
|
||||||
_find &&
|
|
||||||
_find.option &&
|
|
||||||
_find.option.fontOptions &&
|
|
||||||
row[`${property}`] !== undefined &&
|
|
||||||
row[`${property}`] !== null
|
|
||||||
) {
|
|
||||||
return { ..._find.option.fontOptions }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getQAndSort() {
|
getQAndSort() {
|
||||||
const fuzzySearch = this.$refs['search'].fuzzySearch || ''
|
const fuzzySearch = this.$refs['search'].fuzzySearch || ''
|
||||||
const expression = this.$refs['search'].expression || ''
|
const expression = this.$refs['search'].expression || ''
|
||||||
|
@ -1055,8 +808,8 @@ export default {
|
||||||
this.visible = false
|
this.visible = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getRowSeq(row) {
|
openDetail(id, activeTabKey, ciDetailRelationKey) {
|
||||||
return this.$refs.xTable.getVxetableRef().getRowSeq(row)
|
this.$refs.detail.create(id, activeTabKey, ciDetailRelationKey)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1075,33 +828,4 @@ export default {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
margin-bottom: -24px;
|
margin-bottom: -24px;
|
||||||
}
|
}
|
||||||
.checkbox-hover-table {
|
|
||||||
/deep/ .vxe-table--body-wrapper {
|
|
||||||
.vxe-checkbox--label {
|
|
||||||
display: inline;
|
|
||||||
padding-left: 0px !important;
|
|
||||||
color: #bfbfbf;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-icon-checkbox-unchecked {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-icon-checkbox-checked ~ .vxe-checkbox--label {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-cell--checkbox {
|
|
||||||
&:hover {
|
|
||||||
.vxe-icon-checkbox-unchecked {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-checkbox--label {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -73,6 +73,7 @@ export const category_1_bar_options = (data, options) => {
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
stack: options?.barStack ?? 'total',
|
stack: options?.barStack ?? 'total',
|
||||||
barGap: 0,
|
barGap: 0,
|
||||||
|
barMaxWidth: '16px',
|
||||||
emphasis: {
|
emphasis: {
|
||||||
focus: 'series'
|
focus: 'series'
|
||||||
},
|
},
|
||||||
|
@ -242,6 +243,7 @@ export const category_2_bar_options = (data, options, chartType) => {
|
||||||
label: {
|
label: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
|
barMaxWidth: '16px',
|
||||||
areaStyle: chartType === 'line' && options?.isShadow ? {
|
areaStyle: chartType === 'line' && options?.isShadow ? {
|
||||||
opacity: 0.5,
|
opacity: 0.5,
|
||||||
color: {
|
color: {
|
||||||
|
|
|
@ -163,204 +163,26 @@
|
||||||
</div>
|
</div>
|
||||||
</a-space>
|
</a-space>
|
||||||
</SearchForm>
|
</SearchForm>
|
||||||
<vxe-table
|
|
||||||
:id="`cmdb-relation-${viewId}-${currentTypeId}`"
|
<CITable
|
||||||
border
|
|
||||||
keep-source
|
|
||||||
show-overflow
|
|
||||||
resizable
|
|
||||||
ref="xTable"
|
ref="xTable"
|
||||||
size="small"
|
:id="`cmdb-relation-${viewId}-${currentTypeId}`"
|
||||||
row-id="_id"
|
|
||||||
:height="tableHeight"
|
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
show-header-overflow
|
:attrList="preferenceAttrList"
|
||||||
highlight-hover-row
|
:columns="columns"
|
||||||
|
:passwordValue="passwordValue"
|
||||||
:data="instanceList"
|
:data="instanceList"
|
||||||
@checkbox-change="onSelectChange"
|
:height="tableHeight"
|
||||||
@checkbox-all="onSelectChange"
|
:showCheckbox="isLeaf"
|
||||||
@checkbox-range-start="checkboxRangeStart"
|
:showDelete="isLeaf"
|
||||||
@checkbox-range-change="checkboxRangeChange"
|
@onSelectChange="onSelectChange"
|
||||||
@checkbox-range-end="checkboxRangeEnd"
|
|
||||||
:checkbox-config="{ reserve: true, range: true }"
|
|
||||||
@edit-closed="handleEditClose"
|
@edit-closed="handleEditClose"
|
||||||
@edit-actived="handleEditActived"
|
@edit-actived="handleEditActived"
|
||||||
:edit-config="{ trigger: 'dblclick', mode: 'row', showIcon: false }"
|
|
||||||
:sort-config="{ remote: true, trigger: 'cell' }"
|
|
||||||
@sort-change="handleSortCol"
|
@sort-change="handleSortCol"
|
||||||
:row-key="true"
|
@openDetail="openDetail"
|
||||||
:column-key="true"
|
@deleteCI="deleteCI"
|
||||||
:cell-style="getCellStyle"
|
/>
|
||||||
:scroll-y="{ enabled: true, gt: 20 }"
|
|
||||||
:scroll-x="{ enabled: true, gt: 0 }"
|
|
||||||
class="ops-unstripe-table checkbox-hover-table"
|
|
||||||
:custom-config="{ storage: true }"
|
|
||||||
>
|
|
||||||
<vxe-column v-if="isLeaf" align="center" type="checkbox" width="50" fixed="left">
|
|
||||||
<template #default="{row}">
|
|
||||||
{{ getRowSeq(row) }}
|
|
||||||
</template>
|
|
||||||
</vxe-column>
|
|
||||||
<vxe-table-column
|
|
||||||
v-for="(col, index) in columns"
|
|
||||||
:key="`${col.field}_${index}`"
|
|
||||||
:title="col.title"
|
|
||||||
:field="col.field"
|
|
||||||
:width="col.width"
|
|
||||||
:sortable="col.sortable"
|
|
||||||
:edit-render="getColumnsEditRender(col)"
|
|
||||||
:cell-type="col.value_type === '2' ? 'string' : 'auto'"
|
|
||||||
:fixed="col.is_fixed ? 'left' : ''"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<span class="vxe-handle">
|
|
||||||
<OpsMoveIcon
|
|
||||||
style="width: 17px; height: 17px; display: none; position: absolute; left: -3px; top: 12px"
|
|
||||||
/>
|
|
||||||
{{ col.title }}</span
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
<template v-if="col.is_choice || col.is_password" #edit="{ row }">
|
|
||||||
<vxe-input v-if="col.is_password" v-model="passwordValue[col.field]" />
|
|
||||||
<a-select
|
|
||||||
:getPopupContainer="(trigger) => trigger.parentElement"
|
|
||||||
:style="{ width: '100%', height: '32px' }"
|
|
||||||
v-model="row[col.field]"
|
|
||||||
:placeholder="$t('placeholder2')"
|
|
||||||
v-if="col.is_choice"
|
|
||||||
:showArrow="false"
|
|
||||||
:mode="col.is_list ? 'multiple' : 'default'"
|
|
||||||
class="ci-table-edit-select"
|
|
||||||
allowClear
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
:value="choice[0]"
|
|
||||||
:key="'edit_' + col.field + idx"
|
|
||||||
v-for="(choice, idx) in col.filters"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
:style="{ ...(choice[1] ? choice[1].style : {}), display: 'inline-flex', alignItems: 'center' }"
|
|
||||||
>
|
|
||||||
<template v-if="choice[1] && choice[1].icon && choice[1].icon.name">
|
|
||||||
<img
|
|
||||||
v-if="choice[1].icon.id && choice[1].icon.url"
|
|
||||||
:src="`/api/common-setting/v1/file/${choice[1].icon.url}`"
|
|
||||||
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
|
||||||
/>
|
|
||||||
<ops-icon
|
|
||||||
v-else
|
|
||||||
:style="{ color: choice[1].icon.color, marginRight: '5px' }"
|
|
||||||
:type="choice[1].icon.name"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
{{ choice[0] }}
|
|
||||||
</span>
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</template>
|
|
||||||
<template
|
|
||||||
v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice"
|
|
||||||
#default="{row}"
|
|
||||||
>
|
|
||||||
<span v-if="col.value_type === '6' && row[col.field]">{{ row[col.field] }}</span>
|
|
||||||
<a
|
|
||||||
v-else-if="col.is_link && row[col.field]"
|
|
||||||
:href="
|
|
||||||
row[col.field].startsWith('http') || row[col.field].startsWith('https')
|
|
||||||
? `${row[col.field]}`
|
|
||||||
: `http://${row[col.field]}`
|
|
||||||
"
|
|
||||||
target="_blank"
|
|
||||||
>{{ row[col.field] }}</a
|
|
||||||
>
|
|
||||||
<PasswordField
|
|
||||||
v-else-if="col.is_password && row[col.field]"
|
|
||||||
:ci_id="row._id"
|
|
||||||
:attr_id="col.attr_id"
|
|
||||||
></PasswordField>
|
|
||||||
<template v-else-if="col.is_choice">
|
|
||||||
<template v-if="col.is_list">
|
|
||||||
<span
|
|
||||||
v-for="value in row[col.field]"
|
|
||||||
:key="value"
|
|
||||||
:style="{
|
|
||||||
borderRadius: '4px',
|
|
||||||
padding: '1px 5px',
|
|
||||||
margin: '2px',
|
|
||||||
...getChoiceValueStyle(col, value),
|
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
v-if="getChoiceValueIcon(col, value).id && getChoiceValueIcon(col, value).url"
|
|
||||||
:src="`/api/common-setting/v1/file/${getChoiceValueIcon(col, value).url}`"
|
|
||||||
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
|
||||||
/>
|
|
||||||
<ops-icon
|
|
||||||
v-else
|
|
||||||
:style="{ color: getChoiceValueIcon(col, value).color, marginRight: '5px' }"
|
|
||||||
:type="getChoiceValueIcon(col, value).name"
|
|
||||||
/>{{ value }}</span
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
<span
|
|
||||||
v-else-if="row[col.field]"
|
|
||||||
:style="{
|
|
||||||
borderRadius: '4px',
|
|
||||||
padding: '1px 5px',
|
|
||||||
margin: '2px 0',
|
|
||||||
...getChoiceValueStyle(col, row[col.field]),
|
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
v-if="getChoiceValueIcon(col, row[col.field]).id && getChoiceValueIcon(col, row[col.field]).url"
|
|
||||||
:src="`/api/common-setting/v1/file/${getChoiceValueIcon(col, row[col.field]).url}`"
|
|
||||||
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
|
||||||
/>
|
|
||||||
<ops-icon
|
|
||||||
v-else
|
|
||||||
:style="{ color: getChoiceValueIcon(col, row[col.field]).color, marginRight: '5px' }"
|
|
||||||
:type="getChoiceValueIcon(col, row[col.field]).name"
|
|
||||||
/>{{ row[col.field] }}</span
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</vxe-table-column>
|
|
||||||
<vxe-column align="left" field="operate" fixed="right" width="80">
|
|
||||||
<template #header>
|
|
||||||
<span>{{ $t('operation') }}</span>
|
|
||||||
</template>
|
|
||||||
<template #default="{ row }">
|
|
||||||
<a-space>
|
|
||||||
<a @click="$refs.detail.create(row.ci_id || row._id)">
|
|
||||||
<a-icon type="unordered-list" />
|
|
||||||
</a>
|
|
||||||
<a-tooltip :title="$t('cmdb.ci.addRelation')">
|
|
||||||
<a @click="$refs.detail.create(row.ci_id || row._id, 'tab_2', '2')">
|
|
||||||
<a-icon type="retweet" />
|
|
||||||
</a>
|
|
||||||
</a-tooltip>
|
|
||||||
<template v-if="isLeaf">
|
|
||||||
<a-tooltip :title="$t('cmdb.ciType.deleteInstance')">
|
|
||||||
<a @click="deleteCI(row)" :style="{ color: 'red' }">
|
|
||||||
<a-icon type="delete" />
|
|
||||||
</a>
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</vxe-column>
|
|
||||||
<template #empty>
|
|
||||||
<div v-if="loading" style="height: 200px; line-height: 200px">{{ $t('loading') }}</div>
|
|
||||||
<div v-else>
|
|
||||||
<img :style="{ width: '200px' }" :src="require('@/assets/data_empty.png')" />
|
|
||||||
<div>{{ $t('noData') }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</vxe-table>
|
|
||||||
<div :style="{ textAlign: 'right', marginTop: '4px' }">
|
<div :style="{ textAlign: 'right', marginTop: '4px' }">
|
||||||
<a-pagination
|
<a-pagination
|
||||||
:showSizeChanger="true"
|
:showSizeChanger="true"
|
||||||
|
@ -405,7 +227,6 @@
|
||||||
@reload="sumbitFromCreateInstance"
|
@reload="sumbitFromCreateInstance"
|
||||||
@submit="batchUpdateFromCreateInstance"
|
@submit="batchUpdateFromCreateInstance"
|
||||||
/>
|
/>
|
||||||
<JsonEditor ref="jsonEditor" @jsonEditorOk="jsonEditorOk" />
|
|
||||||
<BatchDownload ref="batchDownload" @batchDownload="batchDownload" />
|
<BatchDownload ref="batchDownload" @batchDownload="batchDownload" />
|
||||||
<ReadPermissionsModal ref="readPermissionsModal" />
|
<ReadPermissionsModal ref="readPermissionsModal" />
|
||||||
<RevokeModal ref="revokeModal" @handleRevoke="handleRevoke" />
|
<RevokeModal ref="revokeModal" @handleRevoke="handleRevoke" />
|
||||||
|
@ -440,16 +261,14 @@ import SplitPane from '@/components/SplitPane'
|
||||||
import EditAttrsPopover from '../ci/modules/editAttrsPopover.vue'
|
import EditAttrsPopover from '../ci/modules/editAttrsPopover.vue'
|
||||||
import CiDetailDrawer from '../ci/modules/ciDetailDrawer.vue'
|
import CiDetailDrawer from '../ci/modules/ciDetailDrawer.vue'
|
||||||
import CreateInstanceForm from '../ci/modules/CreateInstanceForm'
|
import CreateInstanceForm from '../ci/modules/CreateInstanceForm'
|
||||||
import JsonEditor from '../../components/JsonEditor/jsonEditor.vue'
|
|
||||||
import BatchDownload from '../../components/batchDownload/batchDownload.vue'
|
import BatchDownload from '../../components/batchDownload/batchDownload.vue'
|
||||||
import PasswordField from '../../components/passwordField/index.vue'
|
|
||||||
import PreferenceSearch from '../../components/preferenceSearch/preferenceSearch.vue'
|
import PreferenceSearch from '../../components/preferenceSearch/preferenceSearch.vue'
|
||||||
import CMDBGrant from '../../components/cmdbGrant'
|
import CMDBGrant from '../../components/cmdbGrant'
|
||||||
import GrantModal from '../../components/cmdbGrant/grantModal.vue'
|
import GrantModal from '../../components/cmdbGrant/grantModal.vue'
|
||||||
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
|
|
||||||
import { getAttrPassword } from '../../api/CITypeAttr'
|
import { getAttrPassword } from '../../api/CITypeAttr'
|
||||||
import ReadPermissionsModal from './modules/ReadPermissionsModal.vue'
|
import ReadPermissionsModal from './modules/ReadPermissionsModal.vue'
|
||||||
import RevokeModal from '../../components/cmdbGrant/revokeModal.vue'
|
import RevokeModal from '../../components/cmdbGrant/revokeModal.vue'
|
||||||
|
import CITable from '@/modules/cmdb/components/ciTable/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RelationViews',
|
name: 'RelationViews',
|
||||||
|
@ -464,13 +283,11 @@ export default {
|
||||||
EditAttrsPopover,
|
EditAttrsPopover,
|
||||||
CiDetailDrawer,
|
CiDetailDrawer,
|
||||||
CreateInstanceForm,
|
CreateInstanceForm,
|
||||||
JsonEditor,
|
|
||||||
BatchDownload,
|
BatchDownload,
|
||||||
PasswordField,
|
|
||||||
PreferenceSearch,
|
PreferenceSearch,
|
||||||
OpsMoveIcon,
|
|
||||||
ReadPermissionsModal,
|
ReadPermissionsModal,
|
||||||
RevokeModal,
|
RevokeModal,
|
||||||
|
CITable
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -635,7 +452,7 @@ export default {
|
||||||
refreshTable() {
|
refreshTable() {
|
||||||
this.selectedRowKeys = []
|
this.selectedRowKeys = []
|
||||||
this.sortByTable = undefined
|
this.sortByTable = undefined
|
||||||
const xTable = this.$refs.xTable
|
const xTable = this.$refs.xTable.getVxetableRef()
|
||||||
if (xTable) {
|
if (xTable) {
|
||||||
xTable.clearCheckboxRow()
|
xTable.clearCheckboxRow()
|
||||||
xTable.clearCheckboxReserve()
|
xTable.clearCheckboxReserve()
|
||||||
|
@ -815,8 +632,8 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
changeCIType(typeId) {
|
changeCIType(typeId) {
|
||||||
this.$refs.xTable.clearCheckboxRow()
|
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||||
this.$refs.xTable.clearCheckboxReserve()
|
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||||
this.$refs.search.reset()
|
this.$refs.search.reset()
|
||||||
this.selectedRowKeys = []
|
this.selectedRowKeys = []
|
||||||
this.currentTypeId = [typeId]
|
this.currentTypeId = [typeId]
|
||||||
|
@ -983,8 +800,8 @@ export default {
|
||||||
if (keys) {
|
if (keys) {
|
||||||
const _tempKeys = keys.split('@^@').filter((item) => item !== '')
|
const _tempKeys = keys.split('@^@').filter((item) => item !== '')
|
||||||
if (_tempKeys.length === this.levels.length) {
|
if (_tempKeys.length === this.levels.length) {
|
||||||
this.$refs.xTable.clearCheckboxRow()
|
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||||
this.$refs.xTable.clearCheckboxReserve()
|
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||||
this.selectedRowKeys = []
|
this.selectedRowKeys = []
|
||||||
}
|
}
|
||||||
this.treeKeys = _tempKeys
|
this.treeKeys = _tempKeys
|
||||||
|
@ -1073,7 +890,10 @@ export default {
|
||||||
this.currentView = `${this.viewId}`
|
this.currentView = `${this.viewId}`
|
||||||
this.typeId = this.levels[0][0]
|
this.typeId = this.levels[0][0]
|
||||||
this.viewOption = this.relationViews.views[this.viewName].option ?? {}
|
this.viewOption = this.relationViews.views[this.viewName].option ?? {}
|
||||||
this.refreshTable()
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.refreshTable()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -1097,7 +917,7 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.xTable.refreshColumn()
|
this.$refs.xTable.getVxetableRef().refreshColumn()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
calculateParamsFromTreeKey(treeKey, menuKey) {
|
calculateParamsFromTreeKey(treeKey, menuKey) {
|
||||||
|
@ -1167,23 +987,8 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSelectChange({ records, reserves }) {
|
onSelectChange(records) {
|
||||||
this.selectedRowKeys = [...records, ...reserves]
|
this.selectedRowKeys = records
|
||||||
},
|
|
||||||
checkboxRangeStart(e) {
|
|
||||||
const xTable = this.$refs.xTable
|
|
||||||
const lastSelected = xTable.getCheckboxRecords()
|
|
||||||
const selectedReserve = xTable.getCheckboxReserveRecords()
|
|
||||||
this.lastSelected = [...lastSelected, ...selectedReserve]
|
|
||||||
},
|
|
||||||
checkboxRangeChange(e) {
|
|
||||||
const xTable = this.$refs.xTable
|
|
||||||
xTable.setCheckboxRow(this.lastSelected, true)
|
|
||||||
},
|
|
||||||
checkboxRangeEnd(e) {
|
|
||||||
const xTable = this.$refs.xTable
|
|
||||||
this.lastSelected = []
|
|
||||||
this.selectedRowKeys = [...xTable.getCheckboxRecords(), ...xTable.getCheckboxReserveRecords()]
|
|
||||||
},
|
},
|
||||||
batchDeleteCIRelation() {
|
batchDeleteCIRelation() {
|
||||||
const currentShowType = this.showTypes.find((item) => item.id === Number(this.currentTypeId[0]))
|
const currentShowType = this.showTypes.find((item) => item.id === Number(this.currentTypeId[0]))
|
||||||
|
@ -1214,8 +1019,8 @@ export default {
|
||||||
[first_ci_id],
|
[first_ci_id],
|
||||||
ancestor_ids
|
ancestor_ids
|
||||||
).then((res) => {
|
).then((res) => {
|
||||||
that.$refs.xTable.clearCheckboxRow()
|
that.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||||
that.$refs.xTable.clearCheckboxReserve()
|
that.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||||
that.selectedRowKeys = []
|
that.selectedRowKeys = []
|
||||||
that.loadData({ parameter: {}, refreshType: 'refreshNumber' })
|
that.loadData({ parameter: {}, refreshType: 'refreshNumber' })
|
||||||
})
|
})
|
||||||
|
@ -1273,7 +1078,7 @@ export default {
|
||||||
},
|
},
|
||||||
columnDrop() {
|
columnDrop() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const xTable = this.$refs.xTable
|
const xTable = this.$refs.xTable.getVxetableRef()
|
||||||
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'),
|
||||||
{
|
{
|
||||||
|
@ -1305,49 +1110,13 @@ export default {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getChoiceValueStyle(col, colValue) {
|
|
||||||
const _find = col.filters.find((item) => String(item[0]) === String(colValue))
|
|
||||||
if (_find) {
|
|
||||||
return _find[1]?.style || {}
|
|
||||||
}
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
getChoiceValueIcon(col, colValue) {
|
|
||||||
const _find = col.filters.find((item) => String(item[0]) === String(colValue))
|
|
||||||
if (_find) {
|
|
||||||
return _find[1]?.icon || {}
|
|
||||||
}
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
getCellStyle({ row, rowIndex, $rowIndex, column, columnIndex, $columnIndex }) {
|
|
||||||
const { property } = column
|
|
||||||
const _find = this.preferenceAttrList.find((attr) => attr.name === property)
|
|
||||||
if (
|
|
||||||
_find &&
|
|
||||||
_find.option &&
|
|
||||||
_find.option.fontOptions &&
|
|
||||||
row[`${property}`] !== undefined &&
|
|
||||||
row[`${property}`] !== null
|
|
||||||
) {
|
|
||||||
return { ..._find.option.fontOptions }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
refreshAfterEditAttrs() {
|
refreshAfterEditAttrs() {
|
||||||
this.loadColumns()
|
this.loadColumns()
|
||||||
},
|
},
|
||||||
getColumnsEditRender(col) {
|
|
||||||
const _editRender = {
|
|
||||||
...col.editRender,
|
|
||||||
}
|
|
||||||
if (col.value_type === '6') {
|
|
||||||
_editRender.events = { focus: this.handleFocusJson }
|
|
||||||
}
|
|
||||||
return _editRender
|
|
||||||
},
|
|
||||||
handleEditActived() {
|
handleEditActived() {
|
||||||
const passwordCol = this.columns.filter((col) => col.is_password)
|
const passwordCol = this.columns.filter((col) => col.is_password)
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const editRecord = this.$refs.xTable.getEditRecord()
|
const editRecord = this.$refs.xTable.getVxetableRef().getEditRecord()
|
||||||
const { row, column } = editRecord
|
const { row, column } = editRecord
|
||||||
if (passwordCol.length && this.lastEditCiId !== row._id) {
|
if (passwordCol.length && this.lastEditCiId !== row._id) {
|
||||||
this.$nextTick(async () => {
|
this.$nextTick(async () => {
|
||||||
|
@ -1358,10 +1127,10 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.isContinueCloseEdit = false
|
this.isContinueCloseEdit = false
|
||||||
await this.$refs.xTable.clearEdit()
|
await this.$refs.xTable.getVxetableRef().clearEdit()
|
||||||
this.isContinueCloseEdit = true
|
this.isContinueCloseEdit = true
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.xTable.setEditCell(row, column.field)
|
this.$refs.xTable.getVxetableRef().setEditCell(row, column.field)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1372,7 +1141,7 @@ export default {
|
||||||
if (!this.isContinueCloseEdit) {
|
if (!this.isContinueCloseEdit) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const $table = this.$refs['xTable']
|
const $table = this.$refs['xTable'].getVxetableRef()
|
||||||
const data = {}
|
const data = {}
|
||||||
this.columns.forEach((item) => {
|
this.columns.forEach((item) => {
|
||||||
if (
|
if (
|
||||||
|
@ -1501,10 +1270,10 @@ export default {
|
||||||
if (_find && _find.value_type === '6') jsonAttrList.push(key)
|
if (_find && _find.value_type === '6') jsonAttrList.push(key)
|
||||||
})
|
})
|
||||||
const data = _.cloneDeep([
|
const data = _.cloneDeep([
|
||||||
...this.$refs.xTable.getCheckboxReserveRecords(),
|
...this.$refs.xTable.getVxetableRef().getCheckboxReserveRecords(),
|
||||||
...this.$refs.xTable.getCheckboxRecords(true),
|
...this.$refs.xTable.getVxetableRef().getCheckboxRecords(true),
|
||||||
])
|
])
|
||||||
this.$refs.xTable.exportData({
|
this.$refs.xTable.getVxetableRef().exportData({
|
||||||
filename,
|
filename,
|
||||||
type,
|
type,
|
||||||
columnFilterMethod({ column }) {
|
columnFilterMethod({ column }) {
|
||||||
|
@ -1518,8 +1287,8 @@ export default {
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
this.selectedRowKeys = []
|
this.selectedRowKeys = []
|
||||||
this.$refs.xTable.clearCheckboxRow()
|
this.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||||
this.$refs.xTable.clearCheckboxReserve()
|
this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||||
},
|
},
|
||||||
batchDelete() {
|
batchDelete() {
|
||||||
const that = this
|
const that = this
|
||||||
|
@ -1543,25 +1312,13 @@ export default {
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
that.loading = false
|
that.loading = false
|
||||||
that.selectedRowKeys = []
|
that.selectedRowKeys = []
|
||||||
that.$refs.xTable.clearCheckboxRow()
|
that.$refs.xTable.getVxetableRef().clearCheckboxRow()
|
||||||
that.$refs.xTable.clearCheckboxReserve()
|
that.$refs.xTable.getVxetableRef().clearCheckboxReserve()
|
||||||
that.loadData({ parameter: {}, refreshType: 'refreshNumber' })
|
that.loadData({ parameter: {}, refreshType: 'refreshNumber' })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
handleFocusJson({ column, row }) {
|
|
||||||
this.$refs.jsonEditor.open(column, row)
|
|
||||||
},
|
|
||||||
jsonEditorOk(row, column, jsonData) {
|
|
||||||
// 后端写数据有快慢,不拉接口直接修改table的数据
|
|
||||||
this.instanceList.forEach((item) => {
|
|
||||||
if (item._id === row._id) {
|
|
||||||
item[column.property] = JSON.stringify(jsonData)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.$refs.xTable.refreshColumn()
|
|
||||||
},
|
|
||||||
relationViewRefreshNumber() {
|
relationViewRefreshNumber() {
|
||||||
this.loadData({ parameter: {}, refreshType: 'refreshNumber' })
|
this.loadData({ parameter: {}, refreshType: 'refreshNumber' })
|
||||||
},
|
},
|
||||||
|
@ -1585,7 +1342,9 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
setPreferenceSearchCurrent(id = null) {
|
setPreferenceSearchCurrent(id = null) {
|
||||||
this.$refs.preferenceSearch.currentPreferenceSearch = id
|
this.$nextTick(() => {
|
||||||
|
this.$refs.preferenceSearch.currentPreferenceSearch = id
|
||||||
|
})
|
||||||
},
|
},
|
||||||
copyExpression() {
|
copyExpression() {
|
||||||
const expression = this.$refs['search'].expression || ''
|
const expression = this.$refs['search'].expression || ''
|
||||||
|
@ -1846,8 +1605,8 @@ export default {
|
||||||
return array
|
return array
|
||||||
},
|
},
|
||||||
|
|
||||||
getRowSeq(row) {
|
openDetail(id, activeTabKey, ciDetailRelationKey) {
|
||||||
return this.$refs.xTable.getRowSeq(row)
|
this.$refs.detail.create(id, activeTabKey, ciDetailRelationKey)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1916,36 +1675,6 @@ export default {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: @border-radius-box;
|
border-radius: @border-radius-box;
|
||||||
|
|
||||||
.checkbox-hover-table {
|
|
||||||
.vxe-table--body-wrapper {
|
|
||||||
.vxe-checkbox--label {
|
|
||||||
display: inline;
|
|
||||||
padding-left: 0px !important;
|
|
||||||
color: #bfbfbf;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-icon-checkbox-unchecked {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-icon-checkbox-checked ~ .vxe-checkbox--label {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-cell--checkbox {
|
|
||||||
&:hover {
|
|
||||||
.vxe-icon-checkbox-unchecked {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-checkbox--label {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -144,209 +144,25 @@
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</SearchForm>
|
</SearchForm>
|
||||||
<ops-table
|
|
||||||
:id="`cmdb-tree-${typeId}`"
|
<CITable
|
||||||
border
|
|
||||||
ref="xTable"
|
ref="xTable"
|
||||||
size="small"
|
:id="`cmdb-tree-${typeId}`"
|
||||||
keep-source
|
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
|
:attrList="currentAttrList"
|
||||||
|
:columns="columns"
|
||||||
|
:passwordValue="passwordValue"
|
||||||
:data="instanceList"
|
:data="instanceList"
|
||||||
highlight-hover-row
|
|
||||||
show-overflow
|
|
||||||
show-header-overflow
|
|
||||||
row-id="_id"
|
|
||||||
resizable
|
|
||||||
:row-key="true"
|
|
||||||
:column-key="true"
|
|
||||||
:sort-config="{ remote: true, trigger: 'cell' }"
|
|
||||||
@sort-change="handleSortCol"
|
|
||||||
:cell-style="getCellStyle"
|
|
||||||
:scroll-y="{ enabled: true, gt: 20 }"
|
|
||||||
:scroll-x="{ enabled: true, gt: 0 }"
|
|
||||||
:height="`${windowHeight - 240}px`"
|
:height="`${windowHeight - 240}px`"
|
||||||
@checkbox-change="onSelectChange"
|
:loadingTip="loadTip"
|
||||||
@checkbox-all="onSelectChange"
|
@onSelectChange="onSelectChange"
|
||||||
@checkbox-range-end="onSelectRangeEnd"
|
|
||||||
:checkbox-config="{ reserve: true, highlight: true, range: true }"
|
|
||||||
@edit-closed="handleEditClose"
|
@edit-closed="handleEditClose"
|
||||||
@edit-actived="handleEditActived"
|
@edit-actived="handleEditActived"
|
||||||
:edit-config="{ trigger: 'dblclick', mode: 'row', showIcon: false }"
|
@sort-change="handleSortCol"
|
||||||
class="ops-unstripe-table checkbox-hover-table"
|
@openDetail="openDetail"
|
||||||
:custom-config="{ storage: true }"
|
@deleteCI="deleteCI"
|
||||||
>
|
/>
|
||||||
<vxe-column align="center" type="checkbox" width="60" :fixed="isCheckboxFixed ? 'left' : ''">
|
|
||||||
<template #default="{row}">
|
|
||||||
{{ getRowSeq(row) }}
|
|
||||||
</template>
|
|
||||||
</vxe-column>
|
|
||||||
<vxe-table-column
|
|
||||||
v-for="(col, index) in columns"
|
|
||||||
:key="`${col.field}_${index}`"
|
|
||||||
:title="col.title"
|
|
||||||
:field="col.field"
|
|
||||||
:width="col.width"
|
|
||||||
:sortable="col.sortable"
|
|
||||||
:edit-render="getColumnsEditRender(col)"
|
|
||||||
:cell-type="col.value_type === '2' ? 'string' : 'auto'"
|
|
||||||
:fixed="col.is_fixed ? 'left' : ''"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<span class="vxe-handle">
|
|
||||||
<OpsMoveIcon
|
|
||||||
style="width: 17px; height: 17px; display: none; position: absolute; left: -3px; top: 12px"
|
|
||||||
/>
|
|
||||||
{{ col.title }}</span
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
<template v-if="col.is_choice || col.is_password" #edit="{ row }">
|
|
||||||
<vxe-input v-if="col.is_password" v-model="passwordValue[col.field]" />
|
|
||||||
<a-select
|
|
||||||
:getPopupContainer="(trigger) => trigger.parentElement"
|
|
||||||
:style="{ width: '100%', height: '32px' }"
|
|
||||||
v-model="row[col.field]"
|
|
||||||
:placeholder="$t('placeholder2')"
|
|
||||||
v-if="col.is_choice"
|
|
||||||
:showArrow="false"
|
|
||||||
:mode="col.is_list ? 'multiple' : 'default'"
|
|
||||||
class="ci-table-edit-select"
|
|
||||||
allowClear
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
:value="choice[0]"
|
|
||||||
:key="'edit_' + col.field + idx"
|
|
||||||
v-for="(choice, idx) in col.filters"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
:style="{ ...(choice[1] ? choice[1].style : {}), display: 'inline-flex', alignItems: 'center' }"
|
|
||||||
>
|
|
||||||
<template v-if="choice[1] && choice[1].icon && choice[1].icon.name">
|
|
||||||
<img
|
|
||||||
v-if="choice[1].icon.id && choice[1].icon.url"
|
|
||||||
:src="`/api/common-setting/v1/file/${choice[1].icon.url}`"
|
|
||||||
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
|
||||||
/>
|
|
||||||
<ops-icon
|
|
||||||
v-else
|
|
||||||
:style="{ color: choice[1].icon.color, marginRight: '5px' }"
|
|
||||||
:type="choice[1].icon.name"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
{{ choice[0] }}
|
|
||||||
</span>
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</template>
|
|
||||||
<template
|
|
||||||
v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice"
|
|
||||||
#default="{row}"
|
|
||||||
>
|
|
||||||
<span v-if="col.value_type === '6' && row[col.field]">{{ row[col.field] }}</span>
|
|
||||||
<template v-else-if="col.is_link && row[col.field]">
|
|
||||||
<a
|
|
||||||
v-for="(item, linkIndex) in (col.is_list ? row[col.field] : [row[col.field]])"
|
|
||||||
:key="linkIndex"
|
|
||||||
:href="
|
|
||||||
item.startsWith('http') || item.startsWith('https')
|
|
||||||
? `${item}`
|
|
||||||
: `http://${item}`
|
|
||||||
"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
{{ item }}
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
<PasswordField
|
|
||||||
v-else-if="col.is_password && row[col.field]"
|
|
||||||
:ci_id="row._id"
|
|
||||||
:attr_id="col.attr_id"
|
|
||||||
></PasswordField>
|
|
||||||
<template v-else-if="col.is_choice">
|
|
||||||
<template v-if="col.is_list">
|
|
||||||
<span
|
|
||||||
v-for="value in row[col.field]"
|
|
||||||
:key="value"
|
|
||||||
:style="{
|
|
||||||
borderRadius: '4px',
|
|
||||||
padding: '1px 5px',
|
|
||||||
margin: '2px',
|
|
||||||
...getChoiceValueStyle(col, value),
|
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
v-if="getChoiceValueIcon(col, value).id && getChoiceValueIcon(col, value).url"
|
|
||||||
:src="`/api/common-setting/v1/file/${getChoiceValueIcon(col, value).url}`"
|
|
||||||
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
|
||||||
/>
|
|
||||||
<ops-icon
|
|
||||||
v-else
|
|
||||||
:style="{ color: getChoiceValueIcon(col, value).color, marginRight: '5px' }"
|
|
||||||
:type="getChoiceValueIcon(col, value).name"
|
|
||||||
/>{{ value }}</span
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
<span
|
|
||||||
v-else-if="row[col.field]"
|
|
||||||
:style="{
|
|
||||||
borderRadius: '4px',
|
|
||||||
padding: '1px 5px',
|
|
||||||
margin: '2px 0',
|
|
||||||
...getChoiceValueStyle(col, row[col.field]),
|
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
v-if="getChoiceValueIcon(col, row[col.field]).id && getChoiceValueIcon(col, row[col.field]).url"
|
|
||||||
:src="`/api/common-setting/v1/file/${getChoiceValueIcon(col, row[col.field]).url}`"
|
|
||||||
:style="{ maxHeight: '13px', maxWidth: '13px', marginRight: '5px' }"
|
|
||||||
/>
|
|
||||||
<ops-icon
|
|
||||||
v-else
|
|
||||||
:style="{ color: getChoiceValueIcon(col, row[col.field]).color, marginRight: '5px' }"
|
|
||||||
:type="getChoiceValueIcon(col, row[col.field]).name"
|
|
||||||
/>{{ row[col.field] }}</span
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</vxe-table-column>
|
|
||||||
<vxe-table-column align="left" field="operate" fixed="right" width="120">
|
|
||||||
<template #header>
|
|
||||||
<span>{{ $t('operation') }}</span>
|
|
||||||
</template>
|
|
||||||
<template #default="{ row }">
|
|
||||||
<a-space>
|
|
||||||
<a @click="$refs.detail.create(row.ci_id || row._id)">
|
|
||||||
<a-icon type="unordered-list" />
|
|
||||||
</a>
|
|
||||||
<a-tooltip :title="$t('cmdb.ci.addRelation')">
|
|
||||||
<a @click="$refs.detail.create(row.ci_id || row._id, 'tab_2', '2')">
|
|
||||||
<a-icon type="retweet" />
|
|
||||||
</a>
|
|
||||||
</a-tooltip>
|
|
||||||
<template>
|
|
||||||
<a-tooltip :title="$t('cmdb.ciType.deleteInstance')">
|
|
||||||
<a @click="deleteCI(row)" :style="{ color: 'red' }">
|
|
||||||
<a-icon type="delete" />
|
|
||||||
</a>
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
</a-space>
|
|
||||||
</template>
|
|
||||||
</vxe-table-column>
|
|
||||||
<template #empty>
|
|
||||||
<div v-if="loading" style="height: 200px; line-height: 200px">{{ $t('loading') }}</div>
|
|
||||||
<div v-else>
|
|
||||||
<img :style="{ width: '200px' }" :src="require('@/assets/data_empty.png')" />
|
|
||||||
<div>{{ $t('noData') }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #loading>
|
|
||||||
<div style="height: 200px; line-height: 200px">{{ loadTip || $t('loading') }}</div>
|
|
||||||
</template>
|
|
||||||
</ops-table>
|
|
||||||
<div :style="{ textAlign: 'right', marginTop: '4px' }">
|
<div :style="{ textAlign: 'right', marginTop: '4px' }">
|
||||||
<a-pagination
|
<a-pagination
|
||||||
:showSizeChanger="true"
|
:showSizeChanger="true"
|
||||||
|
@ -398,7 +214,6 @@
|
||||||
@reload="sumbitFromCreateInstance"
|
@reload="sumbitFromCreateInstance"
|
||||||
@submit="batchUpdateFromCreateInstance"
|
@submit="batchUpdateFromCreateInstance"
|
||||||
/>
|
/>
|
||||||
<JsonEditor ref="jsonEditor" @jsonEditorOk="jsonEditorOk" />
|
|
||||||
<BatchDownload ref="batchDownload" @batchDownload="batchDownload" />
|
<BatchDownload ref="batchDownload" @batchDownload="batchDownload" />
|
||||||
<MetadataDrawer ref="metadataDrawer" />
|
<MetadataDrawer ref="metadataDrawer" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -420,38 +235,36 @@ import { getCITypes } from '@/modules/cmdb/api/CIType'
|
||||||
import { getCITableColumns } from '../../utils/helper'
|
import { getCITableColumns } from '../../utils/helper'
|
||||||
import SearchForm from '../../components/searchForm/SearchForm.vue'
|
import SearchForm from '../../components/searchForm/SearchForm.vue'
|
||||||
import SubscribeSetting from '../../components/subscribeSetting/subscribeSetting'
|
import SubscribeSetting from '../../components/subscribeSetting/subscribeSetting'
|
||||||
import PasswordField from '../../components/passwordField/index.vue'
|
|
||||||
import SplitPane from '@/components/SplitPane'
|
import SplitPane from '@/components/SplitPane'
|
||||||
import TreeViewsNode from './modules/treeViewsNode.vue'
|
import TreeViewsNode from './modules/treeViewsNode.vue'
|
||||||
import EditAttrsPopover from '../ci/modules/editAttrsPopover.vue'
|
import EditAttrsPopover from '../ci/modules/editAttrsPopover.vue'
|
||||||
import CiDetailDrawer from '../ci/modules/ciDetailDrawer.vue'
|
import CiDetailDrawer from '../ci/modules/ciDetailDrawer.vue'
|
||||||
import CreateInstanceForm from '../ci/modules/CreateInstanceForm'
|
import CreateInstanceForm from '../ci/modules/CreateInstanceForm'
|
||||||
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
|
||||||
import JsonEditor from '../../components/JsonEditor/jsonEditor.vue'
|
|
||||||
import BatchDownload from '../../components/batchDownload/batchDownload.vue'
|
import BatchDownload from '../../components/batchDownload/batchDownload.vue'
|
||||||
import PreferenceSearch from '../../components/preferenceSearch/preferenceSearch.vue'
|
import PreferenceSearch from '../../components/preferenceSearch/preferenceSearch.vue'
|
||||||
import MetadataDrawer from '../ci/modules/MetadataDrawer.vue'
|
import MetadataDrawer from '../ci/modules/MetadataDrawer.vue'
|
||||||
import { intersection } from '@/utils/functions/set'
|
import { intersection } from '@/utils/functions/set'
|
||||||
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
|
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
|
||||||
import { getAttrPassword } from '../../api/CITypeAttr'
|
import { getAttrPassword } from '../../api/CITypeAttr'
|
||||||
|
import CITable from '@/modules/cmdb/components/ciTable/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TreeViews',
|
name: 'TreeViews',
|
||||||
components: {
|
components: {
|
||||||
SearchForm,
|
SearchForm,
|
||||||
SubscribeSetting,
|
SubscribeSetting,
|
||||||
PasswordField,
|
|
||||||
SplitPane,
|
SplitPane,
|
||||||
TreeViewsNode,
|
TreeViewsNode,
|
||||||
EditAttrsPopover,
|
EditAttrsPopover,
|
||||||
CiDetailDrawer,
|
CiDetailDrawer,
|
||||||
CreateInstanceForm,
|
CreateInstanceForm,
|
||||||
JsonEditor,
|
|
||||||
BatchDownload,
|
BatchDownload,
|
||||||
PreferenceSearch,
|
PreferenceSearch,
|
||||||
MetadataDrawer,
|
MetadataDrawer,
|
||||||
OpsMoveIcon,
|
OpsMoveIcon,
|
||||||
draggable,
|
draggable,
|
||||||
|
CITable
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -516,10 +329,6 @@ export default {
|
||||||
const _find = this.subscribeTreeViewCiTypes.find((item) => item.type_id === Number(this.typeId))
|
const _find = this.subscribeTreeViewCiTypes.find((item) => item.type_id === Number(this.typeId))
|
||||||
return _find?.id
|
return _find?.id
|
||||||
},
|
},
|
||||||
isCheckboxFixed() {
|
|
||||||
const idx = this.columns.findIndex((item) => item.is_fixed)
|
|
||||||
return idx > -1
|
|
||||||
},
|
|
||||||
currentCiTypeName() {
|
currentCiTypeName() {
|
||||||
const _find = this.citypes.find((item) => Number(item.id) === Number(this.typeId))
|
const _find = this.citypes.find((item) => Number(item.id) === Number(this.typeId))
|
||||||
return _find?.alias || _find?.name || ''
|
return _find?.alias || _find?.name || ''
|
||||||
|
@ -858,33 +667,6 @@ export default {
|
||||||
this.currentPage = 1
|
this.currentPage = 1
|
||||||
this.handleLoadInstance({ sortByTable })
|
this.handleLoadInstance({ sortByTable })
|
||||||
},
|
},
|
||||||
getChoiceValueStyle(col, colValue) {
|
|
||||||
const _find = col.filters.find((item) => String(item[0]) === String(colValue))
|
|
||||||
if (_find) {
|
|
||||||
return _find[1]?.style || {}
|
|
||||||
}
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
getChoiceValueIcon(col, colValue) {
|
|
||||||
const _find = col.filters.find((item) => String(item[0]) === String(colValue))
|
|
||||||
if (_find) {
|
|
||||||
return _find[1]?.icon || {}
|
|
||||||
}
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
getCellStyle({ row, rowIndex, $rowIndex, column, columnIndex, $columnIndex }) {
|
|
||||||
const { property } = column
|
|
||||||
const _find = this.currentAttrList.find((attr) => attr.name === property)
|
|
||||||
if (
|
|
||||||
_find &&
|
|
||||||
_find.option &&
|
|
||||||
_find.option.fontOptions &&
|
|
||||||
row[`${property}`] !== undefined &&
|
|
||||||
row[`${property}`] !== null
|
|
||||||
) {
|
|
||||||
return { ..._find.option.fontOptions }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onNodeClick(keys, type) {
|
onNodeClick(keys, type) {
|
||||||
console.log(keys)
|
console.log(keys)
|
||||||
if (keys) {
|
if (keys) {
|
||||||
|
@ -921,9 +703,7 @@ export default {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onSelectChange(e) {
|
onSelectChange(records) {
|
||||||
const xTable = this.$refs.xTable.getVxetableRef()
|
|
||||||
const records = [...xTable.getCheckboxRecords(), ...xTable.getCheckboxReserveRecords()]
|
|
||||||
this.selectedRowKeys = records.map((i) => i.ci_id || i._id)
|
this.selectedRowKeys = records.map((i) => i.ci_id || i._id)
|
||||||
},
|
},
|
||||||
setSelectRows() {
|
setSelectRows() {
|
||||||
|
@ -942,9 +722,6 @@ export default {
|
||||||
this.$refs['xTable'].getVxetableRef().setCheckboxRow(rows, true)
|
this.$refs['xTable'].getVxetableRef().setCheckboxRow(rows, true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSelectRangeEnd({ records }) {
|
|
||||||
this.selectedRowKeys = records.map((i) => i.ci_id || i._id)
|
|
||||||
},
|
|
||||||
handleEditActived() {
|
handleEditActived() {
|
||||||
const passwordCol = this.columns.filter((col) => col.is_password)
|
const passwordCol = this.columns.filter((col) => col.is_password)
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
@ -1023,28 +800,6 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
jsonEditorOk(row, column, jsonData) {
|
|
||||||
// 后端写数据有快慢,不拉接口直接修改table的数据
|
|
||||||
// this.reloadData()
|
|
||||||
this.instanceList.forEach((item) => {
|
|
||||||
if (item._id === row._id) {
|
|
||||||
item[column.property] = JSON.stringify(jsonData)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.$refs.xTable.getVxetableRef().refreshColumn()
|
|
||||||
},
|
|
||||||
getColumnsEditRender(col) {
|
|
||||||
const _editRender = {
|
|
||||||
...col.editRender,
|
|
||||||
}
|
|
||||||
if (col.value_type === '6') {
|
|
||||||
_editRender.events = { focus: this.handleFocusJson }
|
|
||||||
}
|
|
||||||
return _editRender
|
|
||||||
},
|
|
||||||
handleFocusJson({ column, row }) {
|
|
||||||
this.$refs.jsonEditor.open(column, row)
|
|
||||||
},
|
|
||||||
async openBatchDownload() {
|
async openBatchDownload() {
|
||||||
this.$refs.batchDownload.open({ preferenceAttrList: this.currentAttrList, ciTypeName: this.currentCiTypeName })
|
this.$refs.batchDownload.open({ preferenceAttrList: this.currentAttrList, ciTypeName: this.currentCiTypeName })
|
||||||
},
|
},
|
||||||
|
@ -1237,8 +992,8 @@ export default {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
getRowSeq(row) {
|
openDetail(id, activeTabKey, ciDetailRelationKey) {
|
||||||
return this.$refs.xTable.getVxetableRef().getRowSeq(row)
|
this.$refs.detail.create(id, activeTabKey, ciDetailRelationKey)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1348,36 +1103,6 @@ export default {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: @border-radius-box;
|
border-radius: @border-radius-box;
|
||||||
|
|
||||||
.checkbox-hover-table {
|
|
||||||
.vxe-table--body-wrapper {
|
|
||||||
.vxe-checkbox--label {
|
|
||||||
display: inline;
|
|
||||||
padding-left: 0px !important;
|
|
||||||
color: #bfbfbf;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-icon-checkbox-unchecked {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-icon-checkbox-checked ~ .vxe-checkbox--label {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-cell--checkbox {
|
|
||||||
&:hover {
|
|
||||||
.vxe-icon-checkbox-unchecked {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vxe-checkbox--label {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue