diff --git a/cmdb-ui/src/components/Menu/menu.js b/cmdb-ui/src/components/Menu/menu.js
index 5fd203a..3884604 100644
--- a/cmdb-ui/src/components/Menu/menu.js
+++ b/cmdb-ui/src/components/Menu/menu.js
@@ -182,8 +182,8 @@ export default {
           <tag {...{ props, attrs }}>
             {this.renderIcon({ icon: menu.meta.icon, customIcon: menu.meta.customIcon, name: menu.meta.name, typeId: menu.meta.typeId, routeName: menu.name, selectedIcon: menu.meta.selectedIcon, })}
             <span>
-              <span class={this.renderI18n(menu.meta.title).length > 10 ? 'scroll' : ''}>{this.renderI18n(menu.meta.title)}</span>
-              {isShowDot &&
+              <span style={menu.meta.style} class={this.renderI18n(menu.meta.title).length > 10 ? 'scroll' : ''}>{this.renderI18n(menu.meta.title)}</span>
+              {isShowDot && !menu.meta.disabled &&
                 <a-popover
                   overlayClassName="custom-menu-extra-submenu"
                   placement="rightTop"
diff --git a/cmdb-ui/src/components/tools/TopMenu.vue b/cmdb-ui/src/components/tools/TopMenu.vue
index f87a0a2..21f7a3f 100644
--- a/cmdb-ui/src/components/tools/TopMenu.vue
+++ b/cmdb-ui/src/components/tools/TopMenu.vue
@@ -81,7 +81,7 @@ export default {
         if (route.name === 'cmdb') {
           const preference = await getPreference()
           const lastTypeId = window.localStorage.getItem('ops_ci_typeid') || undefined
-          if (lastTypeId && preference.some((item) => item.id === Number(lastTypeId))) {
+          if (lastTypeId && preference.type_ids.some((item) => item === Number(lastTypeId))) {
             this.$router.push(`/cmdb/instances/types/${lastTypeId}`)
           } else {
             this.$router.push('/cmdb/dashboard')
diff --git a/cmdb-ui/src/modules/cmdb/router/index.js b/cmdb-ui/src/modules/cmdb/router/index.js
index 1a2522b..ad5078b 100644
--- a/cmdb-ui/src/modules/cmdb/router/index.js
+++ b/cmdb-ui/src/modules/cmdb/router/index.js
@@ -144,17 +144,26 @@ const genCmdbRoutes = async () => {
   // Dynamically add subscription items and business relationships
   const [preference, relation] = await Promise.all([getPreference(), getRelationView()])
 
-  preference.forEach(item => {
-    routes.children[2].children.push({
-      path: `/cmdb/instances/types/${item.id}`,
-      component: () => import(`../views/ci/index`),
-      name: `cmdb_${item.id}`,
-      meta: { title: item.alias, keepAlive: false, typeId: item.id, name: item.name, customIcon: item.icon },
-      // hideChildrenInMenu: true // Force display of MenuItem instead of SubMenu
+  preference.group_types.forEach(group => {
+    if (preference.group_types.length > 1) {
+      routes.children[2].children.push({
+        path: `/cmdb/instances/types/group${group.id}`,
+        name: `cmdb_instances_group_${group.id}`,
+        meta: { title: group.name || 'other', disabled: true, style: 'margin-left: 12px' },
+      })
+    }
+    group.ci_types.forEach(item => {
+      routes.children[2].children.push({
+        path: `/cmdb/instances/types/${item.id}`,
+        component: () => import(`../views/ci/index`),
+        name: `cmdb_${item.id}`,
+        meta: { title: item.alias, keepAlive: false, typeId: item.id, name: item.name, customIcon: item.icon },
+        // hideChildrenInMenu: true // Force display of MenuItem instead of SubMenu
+      })
     })
   })
   const lastTypeId = window.localStorage.getItem('ops_ci_typeid') || undefined
-  if (lastTypeId && preference.some(item => item.id === Number(lastTypeId))) {
+  if (lastTypeId && preference.type_ids.some(item => item === Number(lastTypeId))) {
     routes.redirect = `/cmdb/instances/types/${lastTypeId}`
   } else if (routes.children[2]?.children?.length > 0) {
     routes.redirect = routes.children[2].children.find(item => !item.hidden)?.path
diff --git a/cmdb-ui/src/modules/cmdb/views/preference/index.vue b/cmdb-ui/src/modules/cmdb/views/preference/index.vue
index 9bd9601..65e68d6 100644
--- a/cmdb-ui/src/modules/cmdb/views/preference/index.vue
+++ b/cmdb-ui/src/modules/cmdb/views/preference/index.vue
@@ -32,62 +32,77 @@
             }"
           /></span>
       </div>
-      <div class="cmdb-preference-group" v-for="(group, index) in myPreferences" :key="group.name">
+      <div class="cmdb-preference-group" v-for="(subType, index) in myPreferences" :key="subType.name">
         <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="subType.icon" />{{ subType.name }} </span>
         </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">
-            <OpsMoveIcon class="cmdb-preference-move-icon" />
+        <draggable class="ci-types-left-content" :list="subType.groups" @end="handleChangeGroups" filter=".undraggable">
+          <div v-for="group in subType.groups" :key="group.id || group.name">
             <div
-              :class="{
-                'cmdb-preference-avatar': true,
-                'cmdb-preference-avatar-noicon': !ciType.icon,
-              }"
-              :style="{ width: '30px', height: '30px', marginRight: '10px' }"
+              :class="
+                `${group.id === undefined ? 'undraggable' : ''}`
+              "
             >
-              <template v-if="ciType.icon">
-                <img
-                  v-if="ciType.icon.split('$$')[2]"
-                  :src="`/api/common-setting/v1/file/${ciType.icon.split('$$')[3]}`"
-                  :style="{ maxHeight: '30px', maxWidth: '30px' }"
-                />
-                <ops-icon
-                  v-else
-                  :style="{
-                    color: ciType.icon.split('$$')[1],
-                    fontSize: '14px',
-                  }"
-                  :type="ciType.icon.split('$$')[0]"
-                />
-              </template>
-              <span v-else :style="{ fontSize: '20px' }">{{ ciType.name[0].toUpperCase() }}</span>
+              <div v-if="index === 0 && subType.groups.length > 1" class="cmdb-preference-group-content">
+                <OpsMoveIcon class="cmdb-preference-move-icon" v-if="group.name || index === 1"/>
+                <span style="font-weight: 500; color: #a5a9bc">{{ group.name || $t('other') }}</span>
+                <span :style="{ color: '#c3cdd7' }">({{ group.ci_types.length }})</span>
+              </div>
             </div>
-            <span class="cmdb-preference-group-content-title">{{ ciType.alias || ciType.name }}</span>
-            <span class="cmdb-preference-group-content-action">
-              <a-tooltip :title="$t('cmdb.preference.cancelSub')">
-                <span
-                  @click="unsubscribe(ciType, group.type)"
-                ><ops-icon type="cmdb-preference-cancel-subscribe" />
+            <draggable
+              v-model="group.ci_types"
+              :animation="300"
+              @change="
+                (e) => {
+                  orderChange(e, group, index === 1)
+                }
+              "
+            >
+              <div class="cmdb-preference-group-content" v-for="ciType in group.ci_types" :key="ciType.id">
+                <OpsMoveIcon class="cmdb-preference-move-icon" />
+                <div
+                  :class="{
+                    'cmdb-preference-avatar': true,
+                    'cmdb-preference-avatar-noicon': !ciType.icon,
+                  }"
+                  :style="{ width: '30px', height: '30px', marginRight: '10px' }"
+                >
+                  <template v-if="ciType.icon">
+                    <img
+                      v-if="ciType.icon.split('$$')[2]"
+                      :src="`/api/common-setting/v1/file/${ciType.icon.split('$$')[3]}`"
+                      :style="{ maxHeight: '30px', maxWidth: '30px' }"
+                    />
+                    <ops-icon
+                      v-else
+                      :style="{
+                        color: ciType.icon.split('$$')[1],
+                        fontSize: '14px',
+                      }"
+                      :type="ciType.icon.split('$$')[0]"
+                    />
+                  </template>
+                  <span v-else :style="{ fontSize: '20px' }">{{ ciType.name[0].toUpperCase() }}</span>
+                </div>
+                <span class="cmdb-preference-group-content-title">{{ ciType.alias || ciType.name }}</span>
+                <span class="cmdb-preference-group-content-action">
+                  <a-tooltip :title="$t('cmdb.preference.cancelSub')">
+                    <span
+                      @click="unsubscribe(ciType, group.type)"
+                    ><ops-icon type="cmdb-preference-cancel-subscribe" />
+                    </span>
+                  </a-tooltip>
+                  <a-divider type="vertical" :style="{ margin: '0 3px' }" />
+                  <a-tooltip :title="$t('cmdb.preference.editSub')">
+                    <span
+                      @click="openSubscribeSetting(ciType, `${index + 1}`)"
+                    ><ops-icon
+                      type="cmdb-preference-subscribe"
+                    /></span>
+                  </a-tooltip>
                 </span>
-              </a-tooltip>
-              <a-divider type="vertical" :style="{ margin: '0 3px' }" />
-              <a-tooltip :title="$t('cmdb.preference.editSub')">
-                <span
-                  @click="openSubscribeSetting(ciType, `${index + 1}`)"
-                ><ops-icon
-                  type="cmdb-preference-subscribe"
-                /></span>
-              </a-tooltip>
-            </span>
+              </div>
+            </draggable>
           </div>
         </draggable>
       </div>
@@ -261,7 +276,7 @@ export default {
       ciTypeGroup.forEach((group) => {
         if (group.ci_types && group.ci_types.length) {
           group.ci_types.forEach((type) => {
-            const idx = pref.findIndex((p) => p.id === type.id)
+            const idx = pref.type_ids.findIndex((p) => p === type.id)
             if (idx > -1) {
               type.is_subscribed = true
             }
@@ -283,19 +298,18 @@ export default {
       const _myPreferences = [
         {
           name: this.$t('cmdb.menu.ciTable'),
-          ci_types: self.instance.map((item) => {
-            const _find = pref.find((ci) => ci.id === item)
-            return _find
-          }),
+          groups: pref.group_types,
           icon: 'cmdb-ci',
           type: 'ci',
         },
         {
           name: this.$t('cmdb.menu.ciTree'),
-          ci_types: self.tree.map((item) => {
-            const _find = pref.find((ci) => ci.id === item)
-            return _find
-          }),
+          groups: [
+            {
+              ci_types: pref.tree_types,
+              name: null,
+            }
+          ],
           icon: 'cmdb-tree',
           type: 'tree',
         },
@@ -377,10 +391,41 @@ export default {
         this.expandKeys.push(group.id)
       }
     },
-    orderChange(e, group) {
-      preferenceCitypeOrder({ type_ids: group.ci_types.map((type) => type.id), is_tree: group.type !== 'ci' })
+    async handleChangeGroups() {
+      const typeIds = []
+      this.myPreferences[0].groups.forEach(groupTypes => {
+        groupTypes.ci_types.forEach(ciType => {
+          typeIds.push(ciType.id)
+        })
+      })
+      preferenceCitypeOrder({ type_ids: typeIds, is_tree: false })
         .then(() => {
-          if (group.type === 'ci') {
+          this.resetRoute()
+        })
+        .catch(() => {
+          this.getCITypes(false)
+        })
+    },
+    orderChange(e, group, isTree) {
+      let typeIds = []
+      if (!isTree) {
+        this.myPreferences[0].groups.forEach(groupTypes => {
+          if (group.id === groupTypes.id) {
+            group.ci_types.forEach(ciType => {
+              typeIds.push(ciType.id)
+            })
+          } else {
+            groupTypes.ci_types.forEach(ciType => {
+              typeIds.push(ciType.id)
+            })
+          }
+        })
+      } else {
+        typeIds = group.ci_types.map(item => item.id)
+      }
+      preferenceCitypeOrder({ type_ids: typeIds, is_tree: isTree })
+        .then(() => {
+          if (!isTree) {
             this.resetRoute()
           }
         })
@@ -442,6 +487,18 @@ export default {
       margin-bottom: 20px;
     }
     .cmdb-preference-group {
+      .ci-types-left-content {
+        max-height: calc(100% - 45px);
+        overflow: hidden;
+        &:hover {
+          overflow: auto;
+        }
+        .undraggable{
+          .cmdb-preference-group-content {
+            cursor: default;
+          }
+        }
+      }
       .cmdb-preference-group-title {
         text-align: center;
         margin-bottom: 5px;