jeecgBoot-vue3图片上传

场景说明

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 = {}
  }

})
相关推荐
Mike_jia35 分钟前
Memos:知识工作者的理想开源笔记系统
前端
前端大白话36 分钟前
前端崩溃瞬间救星!10 个 JavaScript 实战技巧大揭秘
前端·javascript
loveoobaby37 分钟前
Shadertoy着色器移植到Three.js经验总结
前端
蓝易云40 分钟前
在Linux、CentOS7中设置shell脚本开机自启动服务
前端·后端·centos
浩龙不eMo40 分钟前
前端获取环境变量方式区分(Vite)
前端·vite
一千柯橘1 小时前
Nestjs 解决 request entity too large
javascript·后端
土豆骑士1 小时前
monorepo 实战练习
前端
土豆骑士1 小时前
monorepo最佳实践
前端
见青..1 小时前
【学习笔记】文件包含漏洞--本地远程包含、伪协议、加密编码
前端·笔记·学习·web安全·文件包含
举个栗子dhy1 小时前
如何处理动态地址栏参数,以及Object.entries() 、Object.fromEntries()和URLSearchParams.entries()使用
javascript