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,