支持上传自定义图标

This commit is contained in:
wang-liang0615
2023-08-31 10:05:11 +08:00
parent 63562007df
commit f41873dc8c
18 changed files with 554 additions and 125 deletions

View File

@@ -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>

View File

@@ -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],