diff --git a/cmdb-ui/src/api/company.js b/cmdb-ui/src/api/company.js
index 2b80af0..cae4bde 100644
--- a/cmdb-ui/src/api/company.js
+++ b/cmdb-ui/src/api/company.js
@@ -20,13 +20,7 @@ export function putCompanyInfo(id, parameter) {
     data: parameter,
   })
 }
-export function postImageFile(parameter) {
-  return axios({
-    url: '/common-setting/v1/file',
-    method: 'post',
-    data: parameter,
-  })
-}
+
 export function getDepartmentList(params) {
   // ?department_parent_id=-1 查询第一级部门,下面的id根据实际的传
   return axios({
diff --git a/cmdb-ui/src/api/file.js b/cmdb-ui/src/api/file.js
new file mode 100644
index 0000000..e53e681
--- /dev/null
+++ b/cmdb-ui/src/api/file.js
@@ -0,0 +1,31 @@
+import { axios } from '@/utils/request'
+
+export function postImageFile(parameter) {
+    return axios({
+        url: '/common-setting/v1/file',
+        method: 'post',
+        data: parameter,
+    })
+}
+
+export function getFileData(data_type) {
+    return axios({
+        url: `/common-setting/v1/data/${data_type}`,
+        method: 'get',
+    })
+}
+
+export function addFileData(data_type, data) {
+    return axios({
+        url: `/common-setting/v1/data/${data_type}`,
+        method: 'post',
+        data,
+    })
+}
+
+export function deleteFileData(data_type, id) {
+    return axios({
+        url: `/common-setting/v1/data/${data_type}/${id}`,
+        method: 'delete',
+    })
+}
diff --git a/cmdb-ui/src/components/CustomIconSelect/index.vue b/cmdb-ui/src/components/CustomIconSelect/index.vue
index beac81f..dceaa8f 100644
--- a/cmdb-ui/src/components/CustomIconSelect/index.vue
+++ b/cmdb-ui/src/components/CustomIconSelect/index.vue
@@ -15,31 +15,117 @@
         >
           {{ item.label }}
         </div>
+        <div :class="`${currentIconType === '4' ? 'selected' : ''}`" @click="handleChangeIconType('4')">
+          自定义
+        </div>
+        <a-upload
+          slot="description"
+          name="avatar"
+          :before-upload="beforeUpload"
+          :show-upload-list="false"
+          accept=".svg,.png,.jpg,.jpeg"
+          v-if="currentIconType === '4'"
+        >
+          <a-button icon="plus" size="small" type="primary">添加</a-button>
+        </a-upload>
       </div>
       <div class="custom-icon-select-popover-content">
-        <div v-for="category in iconList" :key="category.value">
-          <h4 class="category">{{ category.label }}</h4>
-          <div class="custom-icon-select-popover-content-wrapper">
+        <template v-if="iconList && iconList.length">
+          <template v-if="currentIconType !== '4'">
+            <div v-for="category in iconList" :key="category.value">
+              <h4 class="category">{{ category.label }}</h4>
+              <div class="custom-icon-select-popover-content-wrapper">
+                <div
+                  v-for="name in category.list"
+                  :key="name.value"
+                  :class="`custom-icon-select-popover-item ${value.name === name.value ? 'selected' : ''}`"
+                  @click="clickIcon(name.value)"
+                >
+                  <ops-icon :type="name.value" />
+                  <span class="custom-icon-select-popover-item-label">{{ name.label }}</span>
+                </div>
+              </div>
+            </div>
+          </template>
+          <div class="custom-icon-select-popover-content-wrapper" :style="{ marginTop: '10px' }" v-else>
             <div
-              v-for="name in category.list"
-              :key="name.value"
-              :class="`custom-icon-select-popover-item ${value.name === name.value ? 'selected' : ''}`"
-              @click="clickIcon(name.value)"
+              v-for="icon in iconList"
+              :key="icon.id"
+              :class="`custom-icon-select-popover-item ${value.id === icon.id ? 'selected' : ''}`"
+              @click="clickCustomIcon(icon)"
             >
-              <ops-icon :type="name.value" />
-              <span class="custom-icon-select-popover-item-label">{{ name.label }}</span>
+              <div class="custom-icon-select-popover-content-img-box">
+                <img :src="`/api/common-setting/v1/file/${icon.data.url}`" />
+                <a-popconfirm
+                  overlayClassName="custom-icon-select-confirm-popover"
+                  :getPopupContainer="(trigger) => trigger.parentNode"
+                  title="确认删除?"
+                  @confirm="(e) => deleteIcon(e, icon)"
+                  @cancel="
+                    (e) => {
+                      e.stopPropagation()
+                      e.preventDefault()
+                    }
+                  "
+                >
+                  <a-icon
+                    type="close"
+                    @click="
+                      (e) => {
+                        e.stopPropagation()
+                        e.preventDefault()
+                      }
+                    "
+                  />
+                </a-popconfirm>
+              </div>
+              <span class="custom-icon-select-popover-item-label" :title="icon.data.name">{{ icon.data.name }}</span>
             </div>
           </div>
-        </div>
+        </template>
+        <a-empty v-else :style="{ marginTop: '15%' }">
+          <img slot="image" :src="require('@/assets/data_empty.png')" />
+          <a-upload
+            slot="description"
+            name="avatar"
+            :before-upload="beforeUpload"
+            :show-upload-list="false"
+            accept=".svg,.png,.jpg,.jpeg"
+          >
+            <a> 暂无自定义图标,点击此处上传 </a>
+          </a-upload>
+        </a-empty>
       </div>
-      <template v-if="currentIconType !== '0' && currentIconType !== '3'">
+      <template v-if="!['0', '3', '4'].includes(currentIconType)">
         <a-divider :style="{ margin: '5px 0' }" />
         <el-color-picker size="mini" v-model="value.color"> </el-color-picker>
       </template>
+      <a-form class="custom-icon-select-form" :form="form" v-show="currentIconType === '4' && formVisible">
+        <a-form-item
+          label="名称"
+          :labelCol="{ span: 4 }"
+          :wrapperCol="{ span: 16 }"
+        ><a-input
+          v-decorator="['name', { rules: [{ required: true, message: '请输入名称' }] }]"
+        /></a-form-item>
+        <a-form-item label="预览" :labelCol="{ span: 4 }">
+          <div class="custom-icon-select-form-img">
+            <img :src="formImg" />
+          </div>
+        </a-form-item>
+        <a-form-item label=" " :colon="false" :labelCol="{ span: 16 }">
+          <a-space>
+            <a-button size="small" @click="handleCancel">取消</a-button>
+            <a-button size="small" type="primary" @click="handleOk">确定</a-button>
+          </a-space>
+        </a-form-item>
+      </a-form>
     </div>
 
     <div class="custom-icon-select-block" id="custom-icon-select-block" @click="showSelect">
+      <img v-if="value.id && value.url" :src="`/api/common-setting/v1/file/${value.url}`" />
       <ops-icon
+        v-else
         :type="value.name"
         :style="{ color: value.name && value.name.startsWith('icon-') ? value.color || '' : '' }"
       />
@@ -56,6 +142,8 @@ import {
   fillIconList,
   multicolorIconList,
 } from './constants'
+import { postImageFile, getFileData, addFileData, deleteFileData } from '@/api/file'
+
 export default {
   name: 'CustomIconSelect',
   components: { ElColorPicker: ColorPicker },
@@ -77,13 +165,18 @@ export default {
   },
   data() {
     return {
+      form: this.$form.createForm(this),
       iconTypeList,
       commonIconList,
       linearIconList,
       fillIconList,
       multicolorIconList,
       visible: false,
-      currentIconType: '1',
+      currentIconType: '3',
+      customIconList: [],
+      formVisible: false,
+      formImg: null,
+      file: null,
     }
   },
   computed: {
@@ -97,18 +190,30 @@ export default {
           return this.fillIconList
         case '3': // 多色
           return this.multicolorIconList
+        case '4': // 自定义
+          return this.customIconList
         default:
           return this.linearIconList
       }
     },
+    fileName() {
+      const splitFileName = this.file.name.split('.')
+      return splitFileName.splice(0, splitFileName.length - 1).join('')
+    },
   },
   mounted() {
     document.addEventListener('click', this.eventListener)
+    this.getFileData()
   },
   beforeDestroy() {
     document.removeEventListener('click', this.eventListener)
   },
   methods: {
+    getFileData() {
+      getFileData('ops-custom-icon').then((res) => {
+        this.customIconList = res
+      })
+    },
     eventListener(e) {
       if (this.visible) {
         const dom = document.getElementById(`custom-icon-select-popover`)
@@ -137,25 +242,87 @@ export default {
         })
       }
     },
+    clickCustomIcon(icon) {
+      if (icon.id === this.value.id) {
+        this.$emit('change', {
+          name: '',
+          color: '',
+        })
+      } else {
+        this.$emit('change', { name: icon.data.name, id: icon.id, url: icon.data.url })
+      }
+    },
     showSelect() {
       this.visible = true
+      console.log(this.value)
       if (!this.value.name) {
-        this.currentIconType = '1'
+        this.currentIconType = '3'
         return
       }
+      // changyong已废弃
       if (this.value.name.startsWith('changyong-')) {
         this.currentIconType = '0'
       } else if (this.value.name.startsWith('icon-xianxing')) {
         this.currentIconType = '1'
       } else if (this.value.name.startsWith('icon-shidi')) {
         this.currentIconType = '2'
-      } else {
+      } else if (this.value.name.startsWith('caise')) {
         this.currentIconType = '3'
+      } else {
+        this.currentIconType = '4'
       }
     },
     handleChangeIconType(value) {
       this.currentIconType = value
     },
+    beforeUpload(file) {
+      const isLt2M = file.size / 1024 / 1024 < 2
+      if (!isLt2M) {
+        this.$message.error('图片大小不可超过2MB!')
+        return false
+      }
+
+      const reader = new FileReader()
+      reader.readAsDataURL(file)
+      reader.onload = () => {
+        this.formVisible = true
+        this.$nextTick(() => {
+          this.file = file
+          this.formImg = reader.result
+          this.form.setFieldsValue({ name: this.fileName })
+        })
+      }
+      return false
+    },
+    handleCancel() {
+      this.formVisible = false
+      this.form.setFieldsValue({ name: '' })
+      this.formImg = null
+    },
+    handleOk() {
+      const fm = new FormData()
+      fm.append('file', this.file)
+      postImageFile(fm).then((res) => {
+        this.form.validateFields((err, values) => {
+          if (!err) {
+            addFileData('ops-custom-icon', { data: { name: values.name, url: res.file_name } }).then(() => {
+              this.$message.success('上传成功!')
+              this.handleCancel()
+              this.getFileData()
+            })
+          }
+        })
+      })
+    },
+    deleteIcon(e, icon) {
+      e.stopPropagation()
+      e.preventDefault()
+      deleteFileData('ops-custom-icon', icon.id).then(() => {
+        this.$message.success('删除成功!')
+        this.handleCancel()
+        this.getFileData()
+      })
+    },
   },
 }
 </script>
@@ -176,7 +343,7 @@ export default {
     padding: 4px 6px;
   }
   .custom-icon-select-popover-content {
-    max-height: 400px;
+    height: 400px;
     overflow: auto;
     .category {
       font-size: 14px;
@@ -197,12 +364,43 @@ export default {
         padding: 5px 5px 2px 5px;
         margin: 0 2px 6px;
         color: #666;
+        position: relative;
         .custom-icon-select-popover-item-label {
           margin-top: 6px;
           font-size: 11px;
+          width: 100%;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          text-align: center;
         }
         &:hover {
           background-color: #eeeeee;
+          .custom-icon-select-popover-content-img-box > i {
+            display: inline;
+          }
+        }
+        .custom-icon-select-popover-content-img-box {
+          width: 26px;
+          height: 26px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          > img {
+            max-width: 26px;
+            max-height: 26px;
+          }
+
+          > i {
+            display: none;
+            position: absolute;
+            top: 2px;
+            right: 2px;
+            font-size: 12px;
+            &:hover {
+              color: #2f54eb;
+            }
+          }
         }
       }
       .selected {
@@ -212,6 +410,8 @@ export default {
   }
   .custom-icon-select-popover-icon-type {
     display: inline-block;
+    width: 100%;
+    position: relative;
     > div {
       cursor: pointer;
       display: inline-block;
@@ -224,6 +424,16 @@ export default {
     .selected {
       border-color: #2f54eb;
     }
+    .ant-btn {
+      position: absolute;
+      right: 0;
+      top: 50%;
+      transform: translateY(-50%);
+    }
+  }
+
+  .custom-icon-select-confirm-popover .ant-popover-inner-content {
+    width: 150px;
   }
 }
 </style>
@@ -234,15 +444,39 @@ export default {
   width: 28px;
   height: 28px;
   border-radius: 4px;
-  border: 1px solid #eeeeee;
+  border: 1px solid #d9d9d9;
   display: inline-block;
   cursor: pointer;
-  > i {
+  > i,
+  > img {
     position: absolute;
     top: 50%;
     left: 50%;
     transform: translate(-50%, -50%);
+  }
+  > img {
+    max-width: 26px;
+    max-height: 26px;
+  }
+  > i {
     font-size: 18px;
   }
 }
+.custom-icon-select-form {
+  .custom-icon-select-form-img {
+    width: 28px;
+    height: 28px;
+    border-radius: 4px;
+    border: 1px solid #d9d9d9;
+    display: inline-flex;
+    margin-top: 5px;
+    justify-content: center;
+    align-items: center;
+    overflow: hidden;
+    img {
+      max-width: 26px;
+      max-height: 26px;
+    }
+  }
+}
 </style>
diff --git a/cmdb-ui/src/components/Menu/menu.js b/cmdb-ui/src/components/Menu/menu.js
index db7cdd6..dd959df 100644
--- a/cmdb-ui/src/components/Menu/menu.js
+++ b/cmdb-ui/src/components/Menu/menu.js
@@ -222,6 +222,9 @@ export default {
     renderIcon({ icon, selectedIcon, customIcon = undefined, name = undefined, typeId = undefined, routeName }) {
       if (typeId) {
         if (customIcon) {
+          if (customIcon.split('$$')[2]) {
+            return <img style={{ maxHeight: '14px', maxWidth: '14px', marginRight: '10px' }} src={`/api/common-setting/v1/file/${customIcon.split('$$')[3]}`}></img >
+          }
           return <ops-icon
             style={{
               color: customIcon.split('$$')[1],
diff --git a/cmdb-ui/src/modules/cmdb/views/ci/index.vue b/cmdb-ui/src/modules/cmdb/views/ci/index.vue
index cfa03ae..20d7ac1 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci/index.vue
+++ b/cmdb-ui/src/modules/cmdb/views/ci/index.vue
@@ -124,12 +124,21 @@
                   :key="'edit_' + col.field + idx"
                   v-for="(choice, idx) in col.filters"
                 >
-                  <span :style="choice[1] ? choice[1].style || {} : {}">
-                    <ops-icon
-                      :style="{ color: choice[1].icon.color }"
-                      v-if="choice[1] && choice[1].icon && choice[1].icon.name"
-                      :type="choice[1].icon.name"
-                    />
+                  <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>
@@ -152,10 +161,18 @@
                       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
-                      :style="{ color: getChoiceValueIcon(col, value).color }"
+                      v-else
+                      :style="{ color: getChoiceValueIcon(col, value).color, marginRight: '5px' }"
                       :type="getChoiceValueIcon(col, value).name"
                     />{{ value }}
                   </span>
@@ -167,10 +184,18 @@
                     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
-                    :style="{ color: getChoiceValueIcon(col, row[col.field]).color }"
+                    v-else
+                    :style="{ color: getChoiceValueIcon(col, row[col.field]).color, marginRight: '5px' }"
                     :type="getChoiceValueIcon(col, row[col.field]).name"
                   />
                   {{ row[col.field] }}</span
diff --git a/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelationTopo/index.less b/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelationTopo/index.less
index 7252e3a..6805814 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelationTopo/index.less
+++ b/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelationTopo/index.less
@@ -29,11 +29,14 @@
         overflow: hidden;
         text-overflow: ellipsis;
       }
-      .icon {
+      .icon,
+      img {
         position: absolute;
         top: 50%;
         transform: translateY(-50%);
         left: 6px;
+      }
+      .icon {
         width: 16px;
         height: 16px;
       }
diff --git a/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelationTopo/node.js b/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelationTopo/node.js
index a024dba..b2b4143 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelationTopo/node.js
+++ b/cmdb-ui/src/modules/cmdb/views/ci/modules/ciDetailRelationTopo/node.js
@@ -15,7 +15,11 @@ class BaseNode extends TreeNode {
             .attr('id', opts.id)
         let icon
         if (opts.options.icon) {
-            icon = $(`<svg class="icon" style="color:${opts.options.icon.split('$$')[1]}" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use data-v-5bd421da="" xlink:href="#${opts.options.icon.split('$$')[0]}"></use></svg>`)
+            if (opts.options.icon.split('$$')[2]) {
+                icon = $(`<img style="max-width:16px;max-height:16px;" src="/api/common-setting/v1/file/${opts.options.icon.split('$$')[3]}" />`)
+            } else {
+                icon = $(`<svg class="icon" style="color:${opts.options.icon.split('$$')[1]}" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><use data-v-5bd421da="" xlink:href="#${opts.options.icon.split('$$')[0]}"></use></svg>`)
+            }
         } else {
             icon = $(`<span class="icon icon-default">${opts.options.name[0].toUpperCase()}</span>`)
         }
diff --git a/cmdb-ui/src/modules/cmdb/views/ci/modules/createInstanceFormByGroup.vue b/cmdb-ui/src/modules/cmdb/views/ci/modules/createInstanceFormByGroup.vue
index 0b4c5be..0d53c3a 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci/modules/createInstanceFormByGroup.vue
+++ b/cmdb-ui/src/modules/cmdb/views/ci/modules/createInstanceFormByGroup.vue
@@ -1,6 +1,6 @@
 <template>
   <a-form :form="form">
-    <a-divider style="font-size:14px;margin:14px 0;font-weight:700;">{{ group.name || '其他' }}</a-divider>
+    <a-divider style="font-size: 14px; margin: 14px 0; font-weight: 700">{{ group.name || '其他' }}</a-divider>
     <a-row :gutter="24" align="top" type="flex">
       <a-col
         :span="12"
@@ -37,12 +37,19 @@
               :key="'New_' + attr.name + choice_idx"
               v-for="(choice, choice_idx) in attr.choice_value"
             >
-              <span :style="choice[1] ? choice[1].style || {} : {}">
-                <ops-icon
-                  :style="{ color: choice[1].icon.color }"
-                  v-if="choice[1] && choice[1].icon && choice[1].icon.name"
-                  :type="choice[1].icon.name"
-                />
+              <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>
diff --git a/cmdb-ui/src/modules/cmdb/views/ci_types/index.vue b/cmdb-ui/src/modules/cmdb/views/ci_types/index.vue
index 8bb5dfc..bdca475 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci_types/index.vue
+++ b/cmdb-ui/src/modules/cmdb/views/ci_types/index.vue
@@ -113,14 +113,20 @@
                       style="width: 17px; height: 17px; display: none; position: absolute; left: 15px; top: 5px"
                     />
                     <span class="ci-types-left-detail-icon">
-                      <ops-icon
-                        :style="{
-                          color: ci.icon.split('$$')[1],
-                          fontSize: '14px',
-                        }"
-                        v-if="ci.icon"
-                        :type="ci.icon.split('$$')[0]"
-                      />
+                      <template v-if="ci.icon">
+                        <img
+                          v-if="ci.icon.split('$$')[2]"
+                          :src="`/api/common-setting/v1/file/${ci.icon.split('$$')[3]}`"
+                        />
+                        <ops-icon
+                          v-else
+                          :style="{
+                            color: ci.icon.split('$$')[1],
+                            fontSize: '14px',
+                          }"
+                          :type="ci.icon.split('$$')[0]"
+                        />
+                      </template>
                       <span :style="{ color: '#2f54eb' }" v-else>{{ ci.name[0].toUpperCase() }}</span>
                     </span>
                   </div>
@@ -204,7 +210,7 @@
               :label="item.alias || item.name"
             >
               <span> {{ item.alias || item.name }}</span>
-              <span :title="item.name" style="font-size: 10px; color: #afafaf"> {{ item.name }}</span>
+              <span :title="item.name" style="font-size:10px;color:#afafaf;"> {{ item.name }}</span>
             </el-option>
             <a-divider :style="{ margin: '5px 0' }" />
             <div :style="{ textAlign: 'right' }">
@@ -235,7 +241,7 @@
               :label="item.alias || item.name"
             >
               <span> {{ item.alias || item.name }}</span>
-              <span :title="item.name" style="font-size: 10px; color: #afafaf"> {{ item.name }}</span>
+              <span :title="item.name" style="font-size:10px;color:#afafaf;"> {{ item.name }}</span>
             </el-option>
           </el-select>
           <a-divider type="vertical" />
@@ -533,21 +539,20 @@ export default {
       e.preventDefault()
       this.form.validateFields(async (err, values) => {
         if (!err) {
-          // eslint-disable-next-line no-console
-          console.log('Received values of form: ', values)
-          const icon = this.$refs.iconArea.getIcon()
           this.loading = true
           if (values.default_order_attr && this.default_order_asc === '2') {
             values.default_order_attr = `-${values.default_order_attr}`
           }
+          const _icon = this.$refs.iconArea.getIcon()
+          const icon =
+            _icon && _icon.name ? `${_icon.name}$$${_icon.color || ''}$$${_icon.id || ''}$$${_icon.url || ''}` : ''
           if (values.id) {
             await this.updateCIType(values.id, {
               ...values,
-              icon: icon && icon.name ? `${icon.name}$$${icon.color || ''}` : '',
+              icon,
             })
           } else {
-            await this.createCIType({ ...values, icon: icon && icon.name ? `${icon.name}$$${icon.color || ''}` : '' })
-            // todo 把改ci 类型绑定在当前group下
+            await this.createCIType({ ...values, icon })
           }
         }
       })
@@ -731,6 +736,8 @@ export default {
               ? {
                   name: record.icon.split('$$')[0] || '',
                   color: record.icon.split('$$')[1] || '',
+                  id: record.icon.split('$$')[2] ? Number(record.icon.split('$$')[2]) : null,
+                  url: record.icon.split('$$')[3] || '',
                 }
               : {}
           )
@@ -828,7 +835,7 @@ export default {
         margin-left: auto;
       }
       .ci-types-left-detail-icon {
-        display: inline-flex;
+        display: flex;
         align-items: center;
         justify-content: center;
         width: 20px;
@@ -837,6 +844,10 @@ export default {
         box-shadow: 0px 1px 2px rgba(47, 84, 235, 0.2);
         margin-right: 6px;
         background-color: #fff;
+        img {
+          max-height: 20px;
+          max-width: 20px;
+        }
       }
       &:hover {
         background-color: #e1efff;
diff --git a/cmdb-ui/src/modules/cmdb/views/ci_types/preValueTag.vue b/cmdb-ui/src/modules/cmdb/views/ci_types/preValueTag.vue
index 91e1b2e..d3e1b81 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci_types/preValueTag.vue
+++ b/cmdb-ui/src/modules/cmdb/views/ci_types/preValueTag.vue
@@ -102,8 +102,17 @@
       "
     >
       <span :style="{ cursor: disabled ? 'default' : 'move' }">
-        <ops-icon v-if="icon.name" :type="icon.name" :style="{ color: icon.color || '#595959' }" />
-        {{ item[0] }}
+        <img
+          v-if="icon.id && icon.url"
+          :src="`/api/common-setting/v1/file/${icon.url}`"
+          :style="{ maxHeight: '12px', maxWidth: '12px', marginRight: '5px' }"
+        />
+        <ops-icon
+          v-else-if="icon.name"
+          :type="icon.name"
+          :style="{ marginRight: '5px', color: icon.color || '#595959' }"
+        />
+        <span>{{ item[0] }}</span>
       </span>
       <a
         class="pre-value-tag-dropdown"
@@ -240,6 +249,10 @@ export default {
   border-radius: 4px;
   font-size: 12px;
   position: relative;
+  > span {
+    display: flex;
+    align-items: center;
+  }
   &:hover .pre-value-tag-dropdown-icon {
     display: inline !important;
   }
diff --git a/cmdb-ui/src/modules/cmdb/views/discovery/discoveryCard.vue b/cmdb-ui/src/modules/cmdb/views/discovery/discoveryCard.vue
index 96195a7..3139dd0 100644
--- a/cmdb-ui/src/modules/cmdb/views/discovery/discoveryCard.vue
+++ b/cmdb-ui/src/modules/cmdb/views/discovery/discoveryCard.vue
@@ -10,7 +10,12 @@
     <div class="discovery-bottom"></div>
     <div class="discovery-top">
       <div class="discovery-header">
-        <ops-icon :type="icon.name || 'caise-chajian'" :style="{ fontSize: '30px', color: icon.color }"></ops-icon>
+        <img
+          v-if="icon.id && icon.url"
+          :src="`/api/common-setting/v1/file/${icon.url}`"
+          :style="{ maxHeight: '30px', maxWidth: '30px' }"
+        />
+        <ops-icon v-else :type="icon.name || 'caise-chajian'" :style="{ fontSize: '30px', color: icon.color }" />
         <span :title="rule.name">{{ rule.name }}</span>
       </div>
       <template v-if="!isSelected">
diff --git a/cmdb-ui/src/modules/cmdb/views/discoveryCI/index.vue b/cmdb-ui/src/modules/cmdb/views/discoveryCI/index.vue
index 0018b75..581e46b 100644
--- a/cmdb-ui/src/modules/cmdb/views/discoveryCI/index.vue
+++ b/cmdb-ui/src/modules/cmdb/views/discoveryCI/index.vue
@@ -13,14 +13,17 @@
           @click="clickSidebar(type.id)"
         >
           <span class="cmdb-adc-side-icon">
-            <ops-icon
-              :style="{
-                color: type.icon.split('$$')[1],
-                fontSize: '14px',
-              }"
-              v-if="type.icon"
-              :type="type.icon.split('$$')[0]"
-            />
+            <template v-if="type.icon">
+              <img v-if="type.icon.split('$$')[2]" :src="`/api/common-setting/v1/file/${type.icon.split('$$')[3]}`" />
+              <ops-icon
+                v-else
+                :style="{
+                  color: type.icon.split('$$')[1],
+                  fontSize: '14px',
+                }"
+                :type="type.icon.split('$$')[0]"
+              />
+            </template>
             <span :style="{ color: '#2f54eb' }" v-else>{{ type.name[0].toUpperCase() }}</span>
           </span>
           <span :title="type.alias || type.name" class="cmdb-adc-side-name">{{ type.alias || type.name }}</span>
@@ -57,7 +60,7 @@
           @checkbox-change="onSelectChange"
           @checkbox-all="onSelectChange"
           @checkbox-range-end="onSelectChange"
-          :checkbox-config="{reserve: true, highlight: true, range: true}"
+          :checkbox-config="{ reserve: true, highlight: true, range: true }"
           :sort-config="{ remote: false, trigger: 'cell' }"
         >
           <vxe-column align="center" type="checkbox" width="60"></vxe-column>
@@ -316,7 +319,7 @@ export default {
     align-items: center;
     justify-content: center;
     .cmdb-adc-side-icon {
-      display: inline-flex;
+      display: flex;
       align-items: center;
       justify-content: center;
       width: 20px;
@@ -325,6 +328,10 @@ export default {
       box-shadow: 0px 1px 2px rgba(47, 84, 235, 0.2);
       margin-right: 6px;
       background-color: #fff;
+      img {
+        max-height: 20px;
+        max-width: 20px;
+      }
     }
     .cmdb-adc-side-name {
       display: inline-block;
diff --git a/cmdb-ui/src/modules/cmdb/views/preference/index.vue b/cmdb-ui/src/modules/cmdb/views/preference/index.vue
index 1b53679..71e1436 100644
--- a/cmdb-ui/src/modules/cmdb/views/preference/index.vue
+++ b/cmdb-ui/src/modules/cmdb/views/preference/index.vue
@@ -47,15 +47,21 @@
             }"
             :style="{ width: '30px', height: '30px', marginRight: '10px' }"
           >
-            <ops-icon
-              v-if="ciType.icon"
-              :style="{
-                overflow: 'hidden',
-                color: ciType.icon.split('$$')[1] || '',
-                fontSize: '26px',
-              }"
-              :type="ciType.icon.split('$$')[0]"
-            />
+            <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>
@@ -96,11 +102,21 @@
                     'cmdb-preference-avatar-noicon-is_subscribed': !item.icon && item.is_subscribed,
                   }"
                 >
-                  <ops-icon
-                    v-if="item.icon"
-                    :style="{ overflow: 'hidden', color: item.icon.split('$$')[1] || '', fontSize: '32px' }"
-                    :type="item.icon.split('$$')[0]"
-                  />
+                  <template v-if="item.icon">
+                    <img
+                      v-if="item.icon.split('$$')[2]"
+                      :src="`/api/common-setting/v1/file/${item.icon.split('$$')[3]}`"
+                      :style="{ maxHeight: '30px', maxWidth: '30px' }"
+                    />
+                    <ops-icon
+                      v-else
+                      :style="{
+                        color: item.icon.split('$$')[1],
+                        fontSize: '14px',
+                      }"
+                      :type="item.icon.split('$$')[0]"
+                    />
+                  </template>
                   <span v-else>{{ item.name[0].toUpperCase() }}</span>
                 </div>
                 <span class="cmdb-preference-title" :title="item.alias || item.name">
@@ -536,7 +552,7 @@ export default {
   }
 
   .cmdb-preference-avatar {
-    display: inline-flex;
+    display: flex;
     align-items: center;
     justify-content: center;
     width: 40px;
diff --git a/cmdb-ui/src/modules/cmdb/views/relation_views/index.vue b/cmdb-ui/src/modules/cmdb/views/relation_views/index.vue
index 1ad13c9..8796295 100644
--- a/cmdb-ui/src/modules/cmdb/views/relation_views/index.vue
+++ b/cmdb-ui/src/modules/cmdb/views/relation_views/index.vue
@@ -152,12 +152,21 @@
                       :key="'edit_' + col.field + idx"
                       v-for="(choice, idx) in col.filters"
                     >
-                      <span :style="choice[1] ? choice[1].style || {} : {}">
-                        <ops-icon
-                          :style="{ color: choice[1].icon.color }"
-                          v-if="choice[1] && choice[1].icon && choice[1].icon.name"
-                          :type="choice[1].icon.name"
-                        />
+                      <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>
@@ -165,7 +174,7 @@
                 </template>
                 <template
                   v-if="col.value_type === '6' || col.is_link || col.is_password || col.is_choice"
-                  #default="{ row }"
+                  #default="{row}"
                 >
                   <span v-if="col.value_type === '6' && row[col.field]">{{ row[col.field] }}</span>
                   <a v-else-if="col.is_link" :href="`${row[col.field]}`" target="_blank">{{ row[col.field] }}</a>
@@ -183,11 +192,20 @@
                           padding: '1px 5px',
                           margin: '2px',
                           ...getChoiceValueStyle(col, value),
+                          display: 'inline-flex',
+                          alignItems: 'center',
                         }"
-                      ><ops-icon
-                        :style="{ color: getChoiceValueIcon(col, value).color }"
-                        :type="getChoiceValueIcon(col, value).name"
-                      />{{ value }}</span
+                      >
+                        <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
@@ -197,10 +215,18 @@
                         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
-                        :style="{ color: getChoiceValueIcon(col, row[col.field]).color }"
+                        v-else
+                        :style="{ color: getChoiceValueIcon(col, row[col.field]).color, marginRight: '5px' }"
                         :type="getChoiceValueIcon(col, row[col.field]).name"
                       />{{ row[col.field] }}</span
                     >
@@ -433,11 +459,11 @@ export default {
   },
   inject: ['reload'],
   watch: {
-    '$route.path': function (newPath, oldPath) {
+    '$route.path': function(newPath, oldPath) {
       this.viewId = this.$route.params.viewId
       this.reload()
     },
-    pageNo: function (newPage, oldPage) {
+    pageNo: function(newPage, oldPage) {
       this.loadData({ pageNo: newPage }, undefined, this.sortByTable)
     },
   },
diff --git a/cmdb-ui/src/modules/cmdb/views/relation_views/modules/ContextMenu.vue b/cmdb-ui/src/modules/cmdb/views/relation_views/modules/ContextMenu.vue
index a177fc3..29bc3e2 100644
--- a/cmdb-ui/src/modules/cmdb/views/relation_views/modules/ContextMenu.vue
+++ b/cmdb-ui/src/modules/cmdb/views/relation_views/modules/ContextMenu.vue
@@ -15,14 +15,29 @@
     >
       <span
         :style="{
-          display: 'inline-block',
+          display: 'flex',
           overflow: 'hidden',
           width: '100%',
           textOverflow: 'ellipsis',
           whiteSpace: 'nowrap',
+          alignItems: 'center',
         }"
       >
-        <ops-icon :style="{ color: icon.split('$$')[1] }" v-if="icon" :type="icon.split('$$')[0]" />
+        <template v-if="icon">
+          <img
+            v-if="icon.split('$$')[2]"
+            :src="`/api/common-setting/v1/file/${icon.split('$$')[3]}`"
+            :style="{ maxHeight: '14px', maxWidth: '14px' }"
+          />
+          <ops-icon
+            v-else
+            :style="{
+              color: icon.split('$$')[1],
+              fontSize: '14px',
+            }"
+            :type="icon.split('$$')[0]"
+          />
+        </template>
         <span
           :style="{
             display: 'inline-block',
@@ -38,7 +53,7 @@
           v-else
         >{{ ciTypeName ? ciTypeName[0].toUpperCase() : 'i' }}</span
         >
-        {{ this.title }}
+        <span :style="{ marginLeft: '5px' }">{{ this.title }}</span>
       </span>
       <a-icon :style="{ fontSize: '10px' }" v-if="childLength && !isLeaf" :type="switchIcon"></a-icon>
     </div>
diff --git a/cmdb-ui/src/modules/cmdb/views/tree_views/index.vue b/cmdb-ui/src/modules/cmdb/views/tree_views/index.vue
index e0b4ad5..6da78c1 100644
--- a/cmdb-ui/src/modules/cmdb/views/tree_views/index.vue
+++ b/cmdb-ui/src/modules/cmdb/views/tree_views/index.vue
@@ -63,14 +63,21 @@
                   }"
                 >
                   <span class="tree-views-left-header-icon">
-                    <ops-icon
-                      :style="{
-                        color: ciType.icon.split('$$')[1],
-                        fontSize: '14px',
-                      }"
-                      v-if="ciType.icon"
-                      :type="ciType.icon.split('$$')[0]"
-                    />
+                    <template v-if="ciType.icon">
+                      <img
+                        v-if="ciType.icon.split('$$')[2]"
+                        :src="`/api/common-setting/v1/file/${ciType.icon.split('$$')[3]}`"
+                        :style="{ maxHeight: '14px', maxWidth: '14px' }"
+                      />
+                      <ops-icon
+                        v-else
+                        :style="{
+                          color: ciType.icon.split('$$')[1],
+                          fontSize: '14px',
+                        }"
+                        :type="ciType.icon.split('$$')[0]"
+                      />
+                    </template>
                     <span :style="{ color: '#2f54eb' }" v-else>{{ ciType.name[0].toUpperCase() }}</span>
                   </span>
                   <span class="tree-views-left-header-name">{{ ciType.alias || ciType.name }}</span>
@@ -203,12 +210,21 @@
                       :key="'edit_' + col.field + idx"
                       v-for="(choice, idx) in col.filters"
                     >
-                      <span :style="choice[1] ? choice[1].style || {} : {}">
-                        <ops-icon
-                          :style="{ color: choice[1].icon.color }"
-                          v-if="choice[1] && choice[1].icon && choice[1].icon.name"
-                          :type="choice[1].icon.name"
-                        />
+                      <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>
@@ -234,11 +250,20 @@
                           padding: '1px 5px',
                           margin: '2px',
                           ...getChoiceValueStyle(col, value),
+                          display: 'inline-flex',
+                          alignItems: 'center',
                         }"
-                      ><ops-icon
-                        :style="{ color: getChoiceValueIcon(col, value).color }"
-                        :type="getChoiceValueIcon(col, value).name"
-                      />{{ value }}</span
+                      >
+                        <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
@@ -248,10 +273,18 @@
                         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
-                        :style="{ color: getChoiceValueIcon(col, row[col.field]).color }"
+                        v-else
+                        :style="{ color: getChoiceValueIcon(col, row[col.field]).color, marginRight: '5px' }"
                         :type="getChoiceValueIcon(col, row[col.field]).name"
                       />{{ row[col.field] }}</span
                     >
diff --git a/cmdb-ui/src/views/setting/companyInfo/index.vue b/cmdb-ui/src/views/setting/companyInfo/index.vue
index c08d597..062402f 100644
--- a/cmdb-ui/src/views/setting/companyInfo/index.vue
+++ b/cmdb-ui/src/views/setting/companyInfo/index.vue
@@ -123,7 +123,8 @@
 </template>
 
 <script>
-import { getCompanyInfo, postCompanyInfo, putCompanyInfo, postImageFile } from '@/api/company'
+import { getCompanyInfo, postCompanyInfo, putCompanyInfo } from '@/api/company'
+import { postImageFile } from '@/api/file'
 import { mapMutations, mapState } from 'vuex'
 import SpanTitle from '../components/spanTitle.vue'
 import EditImage from '../components/EditImage.vue'
diff --git a/cmdb-ui/src/views/setting/person/index.vue b/cmdb-ui/src/views/setting/person/index.vue
index 8f9c8c8..e99feea 100644
--- a/cmdb-ui/src/views/setting/person/index.vue
+++ b/cmdb-ui/src/views/setting/person/index.vue
@@ -51,7 +51,7 @@
                 :customRequest="customRequest"
                 :before-upload="beforeUpload"
                 :style="{ width: '310px', height: '100px' }"
-                accept="png,jpg,jpeg"
+                accept=".svg,.png,.jpg,.jpeg"
               >
                 <a-button type="primary" ghost size="small">更换头像</a-button>
               </a-upload>
@@ -133,7 +133,8 @@
 
 <script>
 import { mapActions, mapGetters } from 'vuex'
-import { getAllDepartmentList, postImageFile } from '@/api/company'
+import { getAllDepartmentList } from '@/api/company'
+import { postImageFile } from '@/api/file'
 import {
   getEmployeeList,
   getEmployeeByUid,