feat(cmdb-ui):preference citype order (#378)

This commit is contained in:
wang-liang0615 2024-01-12 11:14:53 +08:00 committed by GitHub
parent 7b593ce1bc
commit 4111ac8d31
7 changed files with 195 additions and 254 deletions

View File

@ -114,3 +114,12 @@ export function revokeRelationView(rid, data) {
data: data data: data
}) })
} }
// preference citype order
export function preferenceCitypeOrder(data) {
return axios({
url: `/v0.1/preference/ci_types/order`,
method: 'POST',
data: data
})
}

View File

@ -138,7 +138,7 @@ const genCmdbRoutes = async () => {
const [preference, relation] = await Promise.all([getPreference(), getRelationView()]) const [preference, relation] = await Promise.all([getPreference(), getRelationView()])
preference.forEach(item => { preference.forEach(item => {
routes.children[2].children.unshift({ routes.children[2].children.push({
path: `/cmdb/instances/types/${item.id}`, path: `/cmdb/instances/types/${item.id}`,
component: () => import(`../views/ci/index`), component: () => import(`../views/ci/index`),
name: `cmdb_${item.id}`, name: `cmdb_${item.id}`,

View File

@ -293,7 +293,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" />
<!-- <EditAttrsDrawer ref="editAttrsDrawer" @refresh="refreshAfterEditAttrs" /> -->
<!-- <batch-update-relation :typeId="typeId" ref="batchUpdateRelation" @submit="batchUpdateRelation" /> --> <!-- <batch-update-relation :typeId="typeId" ref="batchUpdateRelation" @submit="batchUpdateRelation" /> -->
<JsonEditor ref="jsonEditor" @jsonEditorOk="jsonEditorOk" /> <JsonEditor ref="jsonEditor" @jsonEditorOk="jsonEditorOk" />
<BatchDownload ref="batchDownload" @batchDownload="batchDownload" /> <BatchDownload ref="batchDownload" @batchDownload="batchDownload" />

View File

@ -1,103 +0,0 @@
<template>
<CustomDrawer
:visible="visible"
width="600"
@close="
() => {
visible = false
}
"
:title="$t('cmdb.ci.attributeSettings')"
>
<CustomTransfer
ref="customTransfer"
:dataSource="attrList"
:showSearch="true"
:listStyle="{
width: '230px',
height: '500px',
}"
:titles="[$t('cmdb.components.unselectAttributes'), $t('cmdb.components.selectAttributes')]"
:render="item => item.title"
:targetKeys="selectedAttrList"
@change="handleChange"
@selectChange="selectChange"
>
<span slot="notFoundContent">{{ $t('noData') }}</span>
</CustomTransfer>
<div class="custom-drawer-bottom-action">
<a-button @click="handleSubmit" type="primary">{{ $t('confirm') }}</a-button>
</div>
</CustomDrawer>
</template>
<script>
import { subscribeCIType, getSubscribeAttributes } from '@/modules/cmdb/api/preference'
import { getCITypeAttributesByName } from '@/modules/cmdb/api/CITypeAttr'
export default {
name: 'EditAttrsDrawer',
data() {
return {
attrList: [],
typeId: null,
visible: false,
selectedAttrList: [],
}
},
methods: {
open(typeId) {
this.typeId = typeId
this.getAttrs()
},
getAttrs() {
getCITypeAttributesByName(this.typeId).then(res => {
const attributes = res.attributes
getSubscribeAttributes(this.typeId).then(_res => {
const attrList = []
const selectedAttrList = []
const subAttributes = _res.attributes
this.instanceSubscribed = _res.is_subscribed
subAttributes.forEach(item => {
selectedAttrList.push(item.id.toString())
})
attributes.forEach(item => {
const data = {
key: item.id.toString(),
title: item.alias || item.name,
}
attrList.push(data)
})
this.attrList = attrList
this.selectedAttrList = selectedAttrList
this.visible = true
})
})
},
handleChange(targetKeys, direction, moveKeys) {
this.selectedAttrList = targetKeys
},
handleSubmit() {
const that = this
if (this.selectedAttrList.length) {
subscribeCIType(this.typeId, this.selectedAttrList).then(res => {
this.$message.success(this.$t('cmdb.components.subSuccess'))
this.visible = false
this.$emit('refresh')
})
} else {
this.$confirm({
title: that.$t('warning'),
content: that.$t('cmdb.ci.tips4'),
})
}
},
selectChange(sourceSelectedKeys, targetSelectedKeys) {
this.$refs.customTransfer.dbClick(sourceSelectedKeys, targetSelectedKeys, 'title', 'key')
},
},
}
</script>
<style></style>

View File

@ -1 +0,0 @@
editAttrsDrawer 这个文件似乎也没用了

View File

@ -16,8 +16,7 @@
height: '23px', height: '23px',
fontSize: '14px', fontSize: '14px',
}" }"
/></span /></span>
>
<span <span
class="cmdb-preference-left-card-content" class="cmdb-preference-left-card-content"
><ops-icon type="cmdb-tree" :style="{ marginRight: '5px' }"/>{{ $t('cmdb.menu.ciTree') }}: ><ops-icon type="cmdb-tree" :style="{ marginRight: '5px' }"/>{{ $t('cmdb.menu.ciTree') }}:
@ -31,19 +30,28 @@
height: '23px', height: '23px',
fontSize: '14px', fontSize: '14px',
}" }"
/></span /></span>
>
</div> </div>
<div class="cmdb-preference-group" v-for="(group, index) in myPreferences" :key="group.name"> <div class="cmdb-preference-group" v-for="(group, index) in myPreferences" :key="group.name">
<div class="cmdb-preference-group-title"> <div class="cmdb-preference-group-title">
<span> <ops-icon :style="{ marginRight: '10px' }" :type="group.icon" />{{ group.name }} </span> <span> <ops-icon :style="{ marginRight: '10px' }" :type="group.icon" />{{ group.name }} </span>
</div> </div>
<draggable
v-model="group.ci_types"
:animation="300"
@change="
(e) => {
orderChange(e, group)
}
"
>
<div class="cmdb-preference-group-content" v-for="ciType in group.ci_types" :key="ciType.id"> <div class="cmdb-preference-group-content" v-for="ciType in group.ci_types" :key="ciType.id">
<OpsMoveIcon class="cmdb-preference-move-icon" />
<div <div
:class="{ :class="{
'cmdb-preference-avatar': true, 'cmdb-preference-avatar': true,
'cmdb-preference-avatar-noicon': !ciType.icon, 'cmdb-preference-avatar-noicon': !ciType.icon,
'cmdb-preference-avatar-noicon-is_subscribed': !ciType.icon, 'cmdb-preference-avatar-noicon-is_subscribed': !ciType.icon && ciType.is_subscribed,
}" }"
:style="{ width: '30px', height: '30px', marginRight: '10px' }" :style="{ width: '30px', height: '30px', marginRight: '10px' }"
> >
@ -82,6 +90,7 @@
</a-tooltip> </a-tooltip>
</span> </span>
</div> </div>
</draggable>
</div> </div>
</div> </div>
<div class="cmdb-preference-right"> <div class="cmdb-preference-right">
@ -124,19 +133,12 @@
> >
</div> </div>
<div class="cmdb-preference-colleague"> <div class="cmdb-preference-colleague">
<template v-if="type_id2users[item.id] && type_id2users[item.id].length">
<span <span
v-if="type_id2users[item.id] && type_id2users[item.id].length"
>{{ type_id2users[item.id].length > 99 ? '99+' : type_id2users[item.id].length >{{ type_id2users[item.id].length > 99 ? '99+' : type_id2users[item.id].length
}}{{ $t('cmdb.preference.peopleSub') }}</span }}{{ $t('cmdb.preference.peopleSub') }}</span
> >
<span class="cmdb-preference-colleague-name"> <span v-else>{{ $t('cmdb.preference.noSub') }}</span>
<span v-for="uid in type_id2users[item.id].slice(0, 4)" :key="uid">
{{ getNameByUid(uid) }}
</span>
<span class="cmdb-preference-colleague-ellipsis" v-if="type_id2users[item.id].length > 4">...</span>
</span>
</template>
<span v-else :style="{ marginLeft: 'auto' }">{{ $t('cmdb.preference.noSub') }}</span>
</div> </div>
<div class="cmdb-preference-progress"> <div class="cmdb-preference-progress">
<div class="cmdb-preference-progress-info"> <div class="cmdb-preference-progress-info">
@ -190,15 +192,23 @@ import router, { resetRouter } from '@/router'
import store from '@/store' import store from '@/store'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import moment from 'moment' import moment from 'moment'
import draggable from 'vuedraggable'
import { getCITypeGroups } from '../../api/ciTypeGroup' import { getCITypeGroups } from '../../api/ciTypeGroup'
import { getPreference, getPreference2, subscribeCIType, subscribeTreeView } from '@/modules/cmdb/api/preference' import {
getPreference,
getPreference2,
subscribeCIType,
subscribeTreeView,
preferenceCitypeOrder,
} from '@/modules/cmdb/api/preference'
import CollapseTransition from '@/components/CollapseTransition' import CollapseTransition from '@/components/CollapseTransition'
import SubscribeSetting from '../../components/subscribeSetting/subscribeSetting' import SubscribeSetting from '../../components/subscribeSetting/subscribeSetting'
import { getCIAdcStatistics } from '../../api/ci' import { getCIAdcStatistics } from '../../api/ci'
import { ops_move_icon as OpsMoveIcon } from '@/core/icons'
export default { export default {
name: 'Preference', name: 'Preference',
components: { CollapseTransition, SubscribeSetting }, components: { CollapseTransition, SubscribeSetting, draggable, OpsMoveIcon },
data() { data() {
return { return {
citypeData: [], citypeData: [],
@ -214,7 +224,6 @@ export default {
computed: { computed: {
...mapState({ ...mapState({
windowHeight: (state) => state.windowHeight, windowHeight: (state) => state.windowHeight,
allUsers: (state) => state.user.allUsers,
}), }),
}, },
mounted() { mounted() {
@ -277,10 +286,6 @@ export default {
}, 300) }, 300)
} }
}, },
getNameByUid(uid) {
const _find = this.allUsers.find((item) => item.uid === uid)
return _find?.username[0].toUpperCase() || 'A'
},
getsubscribedDays(item) { getsubscribedDays(item) {
const subscribedTime = this.self.type_id2subs_time[item.id] const subscribedTime = this.self.type_id2subs_time[item.id]
moment.duration(moment().diff(moment(subscribedTime))) moment.duration(moment().diff(moment(subscribedTime)))
@ -351,6 +356,17 @@ export default {
this.expandKeys.push(group.id) this.expandKeys.push(group.id)
} }
}, },
orderChange(e, group) {
preferenceCitypeOrder({ type_ids: group.ci_types.map((type) => type.id), is_tree: group.type !== 'ci' })
.then(() => {
if (group.type === 'ci') {
this.resetRoute()
}
})
.catch(() => {
this.getCITypes(false)
})
},
}, },
} }
</script> </script>
@ -426,7 +442,7 @@ export default {
align-items: center; align-items: center;
height: 45px; height: 45px;
padding: 0 8px; padding: 0 8px;
cursor: default; cursor: move;
justify-content: flex-start; justify-content: flex-start;
&:hover { &:hover {
background: #ffffff; background: #ffffff;
@ -437,6 +453,15 @@ export default {
white-space: nowrap; white-space: nowrap;
margin-left: auto; margin-left: auto;
} }
.cmdb-preference-move-icon {
visibility: visible;
}
}
.cmdb-preference-move-icon {
width: 14px;
height: 20px;
cursor: move;
visibility: hidden;
} }
.cmdb-preference-group-content-title { .cmdb-preference-group-content-title {
flex: 1; flex: 1;

View File

@ -32,32 +32,24 @@
> >
<template #one> <template #one>
<div class="tree-views-left" :style="{ height: `${windowHeight - 115}px` }"> <div class="tree-views-left" :style="{ height: `${windowHeight - 115}px` }">
<a-collapse <draggable
:activeKey="current" v-model="subscribeTreeViewCiTypes"
accordion :animation="300"
@change="handleChangeCi" @change="
:bordered="false" (e) => {
:destroyInactivePanel="true" orderChange(e, subscribeTreeViewCiTypes)
> }
<a-collapse-panel "
v-for="ciType in subscribeTreeViewCiTypes"
:key="String(ciType.type_id)"
:showArrow="false"
:style="{
borderRadius: '4px',
marginBottom: '5px',
border: 0,
overflow: 'hidden',
width: '100%',
}"
> >
<div v-for="ciType in subscribeTreeViewCiTypes" :key="ciType.type_id">
<div <div
slot="header" @click="handleChangeCi(ciType.type_id)"
:class="{ :class="{
'custom-header': true, 'custom-header': true,
'custom-header-selected': Number(ciType.type_id) === Number(typeId), 'custom-header-selected': Number(ciType.type_id) === Number(typeId) && !treeKeys.length,
}" }"
> >
<OpsMoveIcon class="move-icon" />
<span class="tree-views-left-header-icon"> <span class="tree-views-left-header-icon">
<template v-if="ciType.icon"> <template v-if="ciType.icon">
<img <img
@ -95,6 +87,7 @@
:tree-data="treeData" :tree-data="treeData"
:load-data="onLoadData" :load-data="onLoadData"
:expandedKeys="expandedKeys" :expandedKeys="expandedKeys"
v-if="Number(ciType.type_id) === Number(typeId)"
> >
<a-icon slot="switcherIcon" type="down" /> <a-icon slot="switcherIcon" type="down" />
<template #title="{ key: treeKey, title, isLeaf }"> <template #title="{ key: treeKey, title, isLeaf }">
@ -107,8 +100,8 @@
/> />
</template> </template>
</a-tree> </a-tree>
</a-collapse-panel> </div>
</a-collapse> </draggable>
</div> </div>
</template> </template>
<template #two> <template #two>
@ -407,7 +400,13 @@
/* eslint-disable no-useless-escape */ /* eslint-disable no-useless-escape */
import _ from 'lodash' import _ from 'lodash'
import Sortable from 'sortablejs' import Sortable from 'sortablejs'
import { getSubscribeTreeView, getSubscribeAttributes, subscribeTreeView } from '@/modules/cmdb/api/preference' import draggable from 'vuedraggable'
import {
getSubscribeTreeView,
getSubscribeAttributes,
subscribeTreeView,
preferenceCitypeOrder,
} from '@/modules/cmdb/api/preference'
import { searchCI, updateCI, deleteCI } from '@/modules/cmdb/api/ci' import { searchCI, updateCI, deleteCI } from '@/modules/cmdb/api/ci'
import { getCITypes } from '@/modules/cmdb/api/CIType' import { getCITypes } from '@/modules/cmdb/api/CIType'
import { getCITableColumns } from '../../utils/helper' import { getCITableColumns } from '../../utils/helper'
@ -444,6 +443,7 @@ export default {
PreferenceSearch, PreferenceSearch,
MetadataDrawer, MetadataDrawer,
OpsMoveIcon, OpsMoveIcon,
draggable,
}, },
data() { data() {
return { return {
@ -463,7 +463,6 @@ export default {
pageSize: 50, pageSize: 50,
currentPage: 1, currentPage: 1,
totalNumber: 0, totalNumber: 0,
current: '', // 当前页面的type_id
currentAttrList: [], currentAttrList: [],
trigger: false, trigger: false,
newLoad: true, newLoad: true,
@ -571,7 +570,6 @@ export default {
this.subscribeTreeViewCiTypes = res this.subscribeTreeViewCiTypes = res
if (this.subscribeTreeViewCiTypes.length) { if (this.subscribeTreeViewCiTypes.length) {
this.typeId = this.$route.params.typeId || this.subscribeTreeViewCiTypes[0].type_id this.typeId = this.$route.params.typeId || this.subscribeTreeViewCiTypes[0].type_id
this.current = `${this.typeId}`
this.selectedRowKeys = [] this.selectedRowKeys = []
this.$refs.xTable.getVxetableRef().clearCheckboxRow() this.$refs.xTable.getVxetableRef().clearCheckboxRow()
this.$refs.xTable.getVxetableRef().clearCheckboxReserve() this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
@ -600,7 +598,6 @@ export default {
async loadCurrentView() { async loadCurrentView() {
if (this.subscribeTreeViewCiTypes.length) { if (this.subscribeTreeViewCiTypes.length) {
this.typeId = this.$route.params.typeId || this.subscribeTreeViewCiTypes[0].type_id this.typeId = this.$route.params.typeId || this.subscribeTreeViewCiTypes[0].type_id
this.current = String(this.typeId)
this.selectedRowKeys = [] this.selectedRowKeys = []
this.$refs.xTable.getVxetableRef().clearCheckboxRow() this.$refs.xTable.getVxetableRef().clearCheckboxRow()
this.$refs.xTable.getVxetableRef().clearCheckboxReserve() this.$refs.xTable.getVxetableRef().clearCheckboxReserve()
@ -746,9 +743,14 @@ export default {
name: 'cmdb_tree_views_item', name: 'cmdb_tree_views_item',
params: { typeId: Number(value) }, params: { typeId: Number(value) },
}) })
this.typeId = Number(value)
} else { } else {
this.typeId = null
this.$nextTick(() => {
this.typeId = Number(value)
this.newLoad = true this.newLoad = true
this.initPage() this.initPage()
})
} }
this.isSetDataNodes = [] this.isSetDataNodes = []
}, },
@ -1209,6 +1211,13 @@ export default {
this.$message.error(this.$t('cmdb.ci.copyFailed')) this.$message.error(this.$t('cmdb.ci.copyFailed'))
}) })
}, },
orderChange(e, subscribeTreeViewCiTypes) {
preferenceCitypeOrder({ type_ids: subscribeTreeViewCiTypes.map((type) => type.type_id), is_tree: true }).catch(
() => {
this.getTreeViews()
}
)
},
}, },
} }
</script> </script>
@ -1230,21 +1239,6 @@ export default {
&:hover { &:hover {
overflow: auto; overflow: auto;
} }
.ant-collapse-borderless {
background-color: #fff;
}
.ant-collapse-item:has(.custom-header-selected):not(:has(.ant-tree-treenode-selected)) > .ant-collapse-header,
.ant-collapse-item-active:not(:has(.ant-tree-treenode-selected)) > .ant-collapse-header {
background-color: #d6e4ff;
}
.ant-collapse-header {
padding: 8px 12px 4px;
&:hover {
background-color: #f0f5ff;
}
&:hover > .custom-header > .actions {
display: inherit;
}
.custom-header { .custom-header {
width: 100%; width: 100%;
display: inline-flex; display: inline-flex;
@ -1252,6 +1246,25 @@ export default {
flex-wrap: nowrap; flex-wrap: nowrap;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
padding: 8px 0 8px 12px;
cursor: move;
border-radius: 2px;
position: relative;
&:hover {
background-color: #f0f5ff;
> .actions,
> .move-icon {
display: inherit;
}
}
.move-icon {
width: 14px;
height: 20px;
cursor: move;
position: absolute;
display: none;
left: 0;
}
.tree-views-left-header-icon { .tree-views-left-header-icon {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@ -1274,6 +1287,7 @@ export default {
.actions { .actions {
display: none; display: none;
margin-left: auto; margin-left: auto;
cursor: pointer;
} }
.action { .action {
display: inline-block; display: inline-block;
@ -1285,10 +1299,8 @@ export default {
} }
} }
} }
} .custom-header-selected {
background-color: #d3e3fd !important;
.ant-collapse > .ant-collapse-item > .ant-collapse-header {
white-space: nowrap;
} }
.ant-tree li { .ant-tree li {
padding: 2px 0; padding: 2px 0;