uniapp Anodrid 实现上传附件(所有格式的文件)

486 阅读2分钟

效果 直接打开资源管理器,然后选择文件后直接上传,返回上传结果

WechatIMG832.jpg

自己写一个 fileSys.ts 文件

export default function fileSys(token: any, accept: string[] = [], size: number = 10) {
  // 打开文件管理器
  function openFileManager() {
    const permissionStatus = (plus.android as any).checkPermission(
      'android.permission.READ_EXTERNAL_STORAGE',
    )
    if (permissionStatus !== 0) {
      console.log('权限未授权,正在请求权限')
      ;(plus.android as any).requestPermissions(
        ['android.permission.READ_EXTERNAL_STORAGE'],
        function () {
          console.log('权限请求成功')

          // 打开文件系统
          const main: any = plus.android.runtimeMainActivity()
          const IntentClass: any = plus.android.importClass('android.content.Intent')
          const intent = new IntentClass(IntentClass.ACTION_GET_CONTENT)
          intent.setType('*/*')
          intent.addCategory(IntentClass.CATEGORY_OPENABLE)
          main.startActivityForResult(intent, 1001)
        },
        function () {
          console.log('权限请求失败')
        },
      )
    } else {
      console.log('权限已经授予')
    }
  }

  // 处理回调结果
  const result = ref()
  function onActivityResult(requestCode: number, resultCode: any, data: any) {
    if (requestCode === 1001 && resultCode === -1) {
      const uri = data.getData()
      const filePath = getFilePathFromContentUri(uri)
      // console.log('filePath: ', filePath)
      if (!filePath) return

      uni.showLoading({
        title: '文件上传中...',
        mask: true,
      })
      const uploadTask = uni.uploadFile({
        url: import.meta.env.VITE_SERVER_BASEURL + '/resource/oss/upload',
        header: {
          'Content-Type': 'multipart/form-data',
          clientid: import.meta.env.VITE_APP_CLIENT_ID,
          Authorization: 'Bearer ' + token,
        },
        name: 'file',
        filePath,
        success: (uploadFileRes) => {
          const d: any = uploadFileRes.data
          if (d) {
            try {
              const data = JSON.parse(d)
              if (data.code === 200) {
                result.value = data.data
              }
            } catch (error) {
              console.log('返回结果错误')
            }
          }
        },
        fail: (err) => {
          uni.hideLoading()
          console.log(err)
        },
      })

      uploadTask.onProgressUpdate(({ progress }) => {
        if (progress === 100) uni.hideLoading()
      })
    }
  }

  function getFilePathFromContentUri(uri: any) {
    const context: any = plus.android.runtimeMainActivity()
    const ContentResolver: any = plus.android.importClass('android.content.ContentResolver')
    const Cursor: any = plus.android.importClass('android.database.Cursor')

    const resolver = context.getContentResolver()
    const cursor = resolver.query(uri, null, null, null, null)

    if (cursor != null && cursor.moveToFirst()) {
      // 获取文件名
      const nameIndex = cursor.getColumnIndex('_display_name')
      const fileName = cursor.getString(nameIndex)

      // 获取文件大小
      const sizeIndex = cursor.getColumnIndex('_size')
      const fileSize = cursor.getLong(sizeIndex) / 1024 / 1024 // 转换为 MB

      cursor.close()

      // 文件格式验证
      const fileType = fileName.split('.').pop()
      if (fileType && accept.length > 0) {
        const lowerType = fileType.toLowerCase()
        if (!accept.includes(lowerType)) {
          uni.showModal({
            title: '提示',
            content: `请上传${accept.join('/')}格式的文件`,
            showCancel: false,
            mask: true,
          })
          return ''
        }
      }

      // 文件大小验证
      if (!fileSize) {
        uni.showModal({
          title: '提示',
          content: `${fileName}为空文件!`,
          showCancel: false,
          mask: true,
        })
        return ''
      }

      if (fileSize > size) {
        uni.showModal({
          title: '提示',
          content: `文件过大,单个文件最大为${size}M`,
          showCancel: false,
          mask: true,
        })
        return ''
      }

      return uri.toString()
    }

    console.log('无法访问文件')
    return ''
  }

  // 注册 onActivityResult 监听器
  function registerActivityResultListener() {
    const main: any = plus.android.runtimeMainActivity()
    main.onActivityResult = function (requestCode: any, resultCode: any, data: any) {
      onActivityResult(requestCode, resultCode, data)
    }
  }

  // 初始化时注册回调监听器
  registerActivityResultListener()

  return {
    openFileManager,
    result,
  }
}

外部使用

<script lang="ts" setup>
import fileSys from './fileSys'
const reShowFileList = ref<any[]>([])

// #ifdef APP
const { openFileManager, result } = fileSys(userInfo.token, props.accept, props.maxSize)
watch(
  () => result.value,
  (obj) => {
    // obj 为上传接口返回的数据
    if (obj) {
      // reShowFileList 为回显的附件数组
      reShowFileList.value.push({
        name: obj.fileName,
        status: 'success',
        url: obj.url,
      })
    }
  },
  { immediate: true, deep: true },
)
// #endif


const imgType = ['jpg', 'png', 'jpeg', 'webp', 'gif']


// beforeChoose 是一个上传前置的方法 具体可参照
// https://wot-design-uni.cn/component/upload.html#%E4%B8%8A%E4%BC%A0%E5%89%8D%E7%BD%AE%E5%A4%84%E7%90%86

function beforeChoose({ resolve }: { resolve: any }) {
  // #ifdef APP
  if (props.accept.filter((i) => !imgType.includes(i)).length) {
    openFileManager()
    return resolve(false)
  } else {
    resolve(true)
  }
  // #endif

  // #ifdef WEB || H5
  resolve(true)
  // #endif
}
</script>
<template>
<wd-upload
  v-model:file-list="reShowFileList"
  :before-choose="beforeChoose"
></wd-upload>
<template>