Преглед на файлове

引入 ali-oss, 实现直接上传文件到 aliyun oss, 具体流程文档 https://help.aliyun.com/zh/oss/use-cases/add-signatures-on-the-client-by-using-javascript-and-upload-data-to-oss 和 https://www.cnblogs.com/Yunssss/p/14342140.html

reghao преди 1 година
родител
ревизия
3221003f72
променени са 3 файла, в които са добавени 75 реда и са изтрити 81 реда
  1. 1 0
      package.json
  2. 11 1
      src/api/file.js
  3. 63 80
      src/components/upload/PublishFile.vue

+ 1 - 0
package.json

@@ -11,6 +11,7 @@
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@liripeng/vue-audio-player": "^1.5.0",
     "@tinymce/tinymce-vue": "^3.0.1",
+    "ali-oss": "^6.21.0",
     "axios": "^0.19.2",
     "babel-plugin-prismjs": "^2.0.1",
     "core-js": "^3.6.4",

+ 11 - 1
src/api/file.js

@@ -1,7 +1,9 @@
 import { post } from '@/utils/request'
 
 const fileApi = {
-  ossServerApi: '/api/file/oss/serverinfo'
+  ossServerApi: '/api/file/oss/serverinfo',
+  ossStsApi: '/api/file/aliyun/sts_token',
+  ossSignedUrlApi: '/api/file/aliyun/signed_url'
 }
 
 export function getAvatarChannelInfo() {
@@ -19,3 +21,11 @@ export function getVideoCoverChannelInfo() {
 export function getPhotoChannelInfo() {
   return post(fileApi.ossServerApi + '/photo')
 }
+
+export function getStsToken() {
+  return post(fileApi.ossStsApi)
+}
+
+export function getSignedUrl(data) {
+  return post(fileApi.ossSignedUrlApi, data)
+}

+ 63 - 80
src/components/upload/PublishFile.vue

@@ -4,22 +4,19 @@
       <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
         <el-card class="box-card">
           <div slot="header" class="clearfix">
-            <span>上传 IM 图片</span>
+            <span>上传文件</span>
           </div>
           <div class="text item">
-            <el-tooltip v-if="imgOssUrl !== null" class="item" effect="dark" content="点击上传图片" placement="top-end">
+            <el-tooltip class="item" effect="dark" content="点击上传文件" placement="top-end">
               <el-upload
-                class="avatar-uploader"
-                :action="imgOssUrl"
-                :headers="imgHeaders"
-                :data="imgData"
-                :with-credentials="true"
+                class=""
+                action=""
                 :show-file-list="false"
-                :before-upload="beforeAvatarUpload"
+                :http-request="fnUploadRequest"
                 :on-success="handleAvatarSuccess"
-                :on-change="handleOnChange"
+                :before-upload="beforeAvatarUpload"
               >
-                <img v-if="coverUrl" :src="coverUrl" class="avatar">
+                <img v-if="imageUrl" :src="imageUrl" class="avatar" alt="">
                 <i v-else class="el-icon-plus avatar-uploader-icon" />
               </el-upload>
             </el-tooltip>
@@ -34,108 +31,94 @@
             <span>OSS 地址</span>
           </div>
           <div class="text item">
-            <el-form ref="form" :model="formData" label-width="80px">
-              <el-form-item label="视频地址">
-                <el-input v-model="formData.uploadId" style="padding-right: 1px" readonly />
+            <span>{{ imageUrl }}</span>
+            <!--            <el-form ref="form" :model="imageUrl" label-width="80px">
+              <el-form-item label="文件地址">
+                <el-input v-model="imageUrl" style="padding-right: 1px" readonly />
               </el-form-item>
-            </el-form>
+            </el-form>-->
           </div>
         </el-card>
       </el-row>
-      <el-row v-if="imageUrl !== null" style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
-        <el-image :src="imageUrl" />
-      </el-row>
     </el-col>
   </el-row>
 </template>
 
 <script>
-import { getServerInfo } from '@/api/content'
-import { putImageFile } from '@/api/im'
+import OSS from 'ali-oss'
+import { getSignedUrl, getStsToken } from '@/api/file'
 
 export default {
   name: 'PublishFile',
   data() {
     return {
-      imgOssUrl: null,
-      imgHeaders: {
-        Authorization: ''
-      },
-      imgData: {
-        channelId: process.env.VUE_APP_UPLOAD_IMIMG_CHANNEL
-      },
-      coverUrl: null,
-      // ****************************************************************************************************************
-      formData: {
-        receiverId: 10011,
-        channelId: null,
-        uploadId: null
-      },
-      imageUrl: null
+      imageUrl: '',
+      ossUrl: ''
     }
   },
   created() {
-    getServerInfo(this.imgData.channelId).then(res => {
-      if (res.code === 0) {
-        const resData = res.data
-        this.imgOssUrl = resData.ossUrl
-        this.imgHeaders.Authorization = 'Bearer ' + resData.token
-      } else {
-        this.$notify({
-          title: '提示',
-          message: '获取 OSS 服务器地址失败, 暂时无法上传文件',
-          type: 'error',
-          duration: 3000
-        })
-      }
-    }).catch(error => {
-      this.$notify({
-        title: '提示',
-        message: error.message,
-        type: 'warning',
-        duration: 3000
-      })
-    })
-  },
-  mounted() {
   },
   methods: {
-    // ****************************************************************************************************************
+    // 图片上传成功回调
+    handleAvatarSuccess(res) {
+      if (res) {
+        const objectName = res.url.replace(this.ossUrl, '')
+        const payload = {}
+        payload.objectName = objectName
+        getSignedUrl(payload).then(resp => {
+          if (resp.code === 0) {
+            this.imageUrl = resp.data
+            // this.imageUrl = res.url
+          }
+        })
+      }
+    },
     beforeAvatarUpload(file) {
       const isJPG = file.type === 'image/jpeg'
-      const isLt2M = file.size / 1024 / 1024 < 10
+      const isLt2M = file.size / 1024 / 1024 < 2
+
       if (!isJPG) {
-        this.$message.error('封面图片只能是 JPG 格式!')
+        this.$message.error('上传头像图片只能是 JPG 格式!')
       }
       if (!isLt2M) {
-        this.$message.error('封面图片大小不能超过 10MB!')
+        this.$message.error('上传头像图片大小不能超过 2MB!')
       }
       return isJPG && isLt2M
     },
-    handleAvatarSuccess(res, file) {
-      if (res.code === 0) {
-        const resData = res.data
-        this.coverUrl = URL.createObjectURL(file.raw)
-
-        this.formData.channelId = this.imgData.channelId
-        this.formData.uploadId = resData.uploadId
-        putImageFile(this.formData).then(resp => {
+    async fnUploadRequest(options) {
+      try {
+        const file = options.file // 拿到 file
+        const index = file.name.lastIndexOf('.')
+        const suffix = file.name.substr(index)
+        getStsToken().then(resp => {
           if (resp.code === 0) {
-            this.imageUrl = resp.data
+            const credentials = resp.data
+            this.ossUrl = credentials.ossUrl
+            const client = new OSS({
+              region: credentials.region,
+              bucket: credentials.bucket,
+              accessKeyId: credentials.accessKeyId,
+              accessKeySecret: credentials.accessKeySecret,
+              stsToken: credentials.securityToken
+            })
+
+            const objectId = credentials.objectId
+            const objectName = 'image/i/' + objectId + suffix
+            client.put(objectName, file).then(resp1 => {
+              if (resp1.res.statusCode === 200) {
+                console.log(resp1)
+                options.onSuccess(resp1)
+              } else {
+                console.log(resp1)
+                options.onError('上传失败')
+              }
+            })
           }
         })
-      } else {
-        this.$notify({
-          title: '提示',
-          message: '视频封面上传失败,请重试!' + res.msg,
-          type: 'warning',
-          duration: 3000
-        })
+      } catch (e) {
+        options.onError('上传失败')
       }
-    },
-    handleOnChange(file, fileList) {
     }
-    // ****************************************************************************************************************
   }
 }
 </script>