场景说明
jeecgboot-vue3图片上传组件只吃显示的是网络地址,例如http://.....jpg格式,但如果既想支持显示网络地址,又想支持显示base64格式地址,那么需要对封装的JImageUpload组件进行修改,如下:
<template>
<div class="clearfix">
<a-upload :listType="listType" accept="image/*" :multiple="multiple" :action="uploadUrl" :headers="headers"
:data="{ biz: bizPath }" v-model:fileList="uploadFileList" :beforeUpload="beforeUpload" :disabled="disabled"
@change="handleChange" @preview="handlePreview" name="file" :show-upload-list="showUploadList">
<div v-if="uploadVisible">
<div v-if="listType == 'picture-card'">
<LoadingOutlined v-if="loading" />
<UploadOutlined v-else />
<div class="ant-upload-text">{{ text }}</div>
</div>
<a-button v-if="listType == 'picture'" :disabled="disabled">
<UploadOutlined></UploadOutlined>
{{ text }}
</a-button>
</div>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel()">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, reactive, watchEffect, computed, unref, watch, onMounted, defineProps } from 'vue';
import { LoadingOutlined, UploadOutlined } from '@ant-design/icons-vue';
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
import { propTypes } from '/@/utils/propTypes';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { useMessage } from '/@/hooks/web/useMessage';
import { getFileAccessHttpUrl, getRandom } from '/@/utils/common/compUtils';
import { uploadUrl } from '/@/api/common/api';
import { getToken } from '/@/utils/auth';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
const { createMessage, createErrorModal } = useMessage();
export default defineComponent({
name: 'JImageUpload',
components: { LoadingOutlined, UploadOutlined },
inheritAttrs: false,
props: {
//绑定值
value: propTypes.oneOfType([propTypes.string, propTypes.array]),
//按钮文本
listType: {
type: String,
required: false,
default: 'picture-card',
},
//按钮文本
text: {
type: String,
required: false,
default: t('modal.upload'),
},
//这个属性用于控制文件上传的业务路径
bizPath: {
type: String,
required: false,
default: 'temp',
},
//是否禁用
disabled: {
type: Boolean,
required: false,
default: false,
},
//上传数量
fileMax: {
type: Number,
required: false,
default: 1,
},
isBase64: {
type: Boolean,
required: false,
default: false,
},
},
emits: ['options-change', 'change', 'update:value','handle'],
setup(props, { emit, refs }) {
const emitData = ref<any[]>([]);
const attrs = useAttrs();
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
//获取文件名
const getFileName = (path) => {
if (path.lastIndexOf('\\') >= 0) {
let reg = new RegExp('\\\\', 'g');
path = path.replace(reg, '/');
}
return path.substring(path.lastIndexOf('/') + 1);
};
//token
const headers = ref<object>({
'X-Access-Token': getToken(),
});
//上传状态
const loading = ref<boolean>(false);
//是否是初始化加载
const initTag = ref<boolean>(true);
//文件列表
let uploadFileList = ref<any[]>([]);
//预览图
const previewImage = ref<string | undefined>('');
//预览框状态
const previewVisible = ref<boolean>(false);
//计算是否开启多图上传
const multiple = computed(() => {
return props['fileMax'] > 1;
});
//计算是否可以继续上传
const uploadVisible = computed(() => {
return uploadFileList.value.length < props['fileMax'];
});
// 是否隐藏上传列表(新增的时候为true)
const showUploadList = ref(true)
/**
* 监听value变化 查看传来得数据是base64还是网络地址 从而进行下一步处理
*/
watch(
() => props.value,
(val, prevCount) => {
// console.log(val,'watch',prevCount);
//update-begin---author:liusq ---date:20230601 for:【issues/556】JImageUpload组件value赋初始值没显示图片------------
if (val && val instanceof Array) {
// 正则表达式判断字符串是否以"data:image"开头,并且以";base64,"结尾
const regex = /^data:image\/[a-zA-Z]*;base64,/;
if (regex.test(val)) {
val = val
}
val = val.join(',');
}
if (initTag.value == true) {
initFileList(val);
}
},
{ immediate: true }
//update-end---author:liusq ---date:20230601 for:【issues/556】JImageUpload组件value赋初始值没显示图片------------
);
/**
* 初始化文件列表
*/
function initFileList(paths) {
// console.log(paths, 'path');
if (!paths || paths.length == 0) {
uploadFileList.value = [];
return;
}
let files = [];
// console.log(paths, 'paths');
// 正则表达式判断字符串是否以"data:image"开头,并且以";base64,"结尾
const regex = /^data:image\/[a-zA-Z]*;base64,/;
if (regex.test(paths)) {
files.push({
uid: getRandom(10),
name: 'image',
status: 'done',
url: paths,
response: {
status: 'history',
message: paths,
},
});
uploadFileList.value = files;
} else {
//网络地址
let arr = paths.split(',');
// console.log(arr, 'arr');
arr.forEach((value) => {
//getFileAccessHttpUrl 引入文件 转换网络地址
let url = getFileAccessHttpUrl(value);
files.push({
uid: getRandom(10),
name: getFileName(value),
status: 'done',
url: url,
response: {
status: 'history',
message: value,
},
});
});
uploadFileList.value = files;
}
}
/**
* 上传前校验
*/
function beforeUpload(file) {
let fileType = file.type;
if (fileType.indexOf('image') < 0) {
createMessage.info('请上传图片');
return false;
}
}
/**
* 文件上传结果回调
*/
function handleChange({ file, fileList, event }) {
// console.log(file, fileList, 'fileList');
// console.log(1);
initTag.value = false;
uploadFileList.value = fileList;
if (file.status === 'error') {
createMessage.error(`${file.name} 上传失败.`);
}
let fileUrls = [];
let res = {}
//上传完成
if (file.status != 'uploading') {
fileList.forEach((file) => {
if (file.status === 'done') {
//update-begin---author:wangshuai ---date:20221121 for:[issues/248]原生表单内使用图片组件,关闭弹窗图片组件值不会被清空------------
initTag.value = true;
//update-end---author:wangshuai ---date:20221121 for:[issues/248]原生表单内使用图片组件,关闭弹窗图片组件值不会被清空------------
fileUrls.push(file.response.message);
res = file.response
}
});
if (file.status === 'removed') {
handleDelete(file);
}
}
// emitData.value = fileUrls.join(',');
state.value = fileUrls.join(',');
// state.value = res;
console.log(res, 'res');
emit('update:value', fileUrls.join(','));
emit('handle',res)
}
/**
* 删除图片
*/
function handleDelete(file) {
//如有需要新增 删除逻辑
console.log(file);
}
/**
* 预览图片
*/
function handlePreview(file) {
previewImage.value = file.url || file.thumbUrl;
previewVisible.value = true;
}
function getAvatarView() {
if (uploadFileList.length > 0) {
let url = uploadFileList[0].url;
return getFileAccessHttpUrl(url, null);
}
}
function handleCancel() {
previewVisible.value = false;
}
return {
state,
attrs,
previewImage,
previewVisible,
uploadFileList,
multiple,
headers,
loading,
uploadUrl,
beforeUpload,
uploadVisible,
handlePreview,
handleCancel,
handleChange,
showUploadList,
};
},
});
</script>
<style scoped>
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
</style>
在其他页面使用该封装的组件
<a-form-item class="msgBoxItem" :label="t('modal.shopPhoto')" required="true">
<JImageUpload :fileMax="1" v-model:value="shopPhotoUrl" :biz-path="'SHOP_PHOTO'"
@handle="(info) => handleChange1(info, 'shop')" :disabled="viewDisabled"
style="margin-top: 20px;" />
</a-form-item>
// 个张图片的地址 显示
const shopPhotoUrl = ref('')
// 上传图片成功数据
const shopPhotoResult = ref({});
// 修改时 上传图片返回结果
const shopPhotoREdit = ref({});
// JImageUpload上传图片
const handleChange1 = (info, who) => {
// console.log(info, '上传', who,);
// 上传成功
if (info.code == 200) {
// 上传的是哪个
const result = info.result
if (who == 'shop') {
//上传成功数据
shopPhotoResult.value = result
shopPhotoUrl.value = ''
}
.......
} else {
// 上传失败
message.error('Upload error')
}
}
// 监听是否上传图 修改得时候判断是否有重新上传图片,若重新上传则获取新上传数据 (具体数据由返回结果看)
watch(() => shopPhotoResult.value, (n, o) => {
// console.log(n, o, '上传监听'); 重新上传则赋值新数据否则为空 再在新增修改接口根据shopPhotoREdit判断是否添加参数 如下
if (n) {
shopPhotoREdit.value = n
if (n.base64) {
shopPhotoUrl.value = n.base64
}
} else {
shopPhotoREdit.value = {}
}
})