zh há 8 meses atrás
pai
commit
aa0eb5d171
1 ficheiros alterados com 165 adições e 80 exclusões
  1. 165 80
      src/views/piece/dashboard/index.vue

+ 165 - 80
src/views/piece/dashboard/index.vue

@@ -1,99 +1,184 @@
 <template>
-  <div>
-    <button @click="_openCamera">打开相机</button>
-    <button @click="_openGallery">打开相册选择图片并返回路径</button>
-    <button @click="_openImageEditor">打开图片编辑器</button>
-
-    <!-- 显示图片的容器 -->
-    <div v-if="imageUrl" class="image-preview">
-      <img :src="imageUrl" alt="Selected Image" />
+  <div class="upload-container">
+    <!-- 上传组件 -->
+    <van-uploader
+      v-model="fileList"
+      :after-read="afterRead"
+      accept="image/*"
+      :max-count="5"
+      :max-size="5 * 1024 * 1024"
+    @oversize="onOversize"
+    multiple
+    >
+    </van-uploader>
+
+    <!-- 图片预览区域 -->
+    <div class="preview-container" v-if="fileList.length > 0">
+      <div class="preview-item" v-for="(item, index) in fileList" :key="index">
+        <img :src="item.content || item.url" class="preview-image" />
+        <div class="preview-status" :class="'status-' + item.status">
+          {{ item.message }}
+        </div>
+        <van-icon
+          name="close"
+          class="preview-remove"
+          @click="removeImage(index)"
+        />
+      </div>
     </div>
   </div>
 </template>
 
-<script setup>
-import { ref } from 'vue'
+<script>
+import { Uploader, Button, Icon, Toast } from 'vant';
 
-const imagePath = ref('')
-const imageUrl = ref('')
+export default {
+  components: {
+    [Uploader.name]: Uploader,
+    [Button.name]: Button,
+    [Icon.name]: Icon
+  },
+  data() {
+    return {
+      fileList: [
+        // 可以预置已上传的图片
+        // { url: 'https://example.com/image1.jpg', status: 'done' }
+      ]
+    };
+  },
+  methods: {
+    afterRead(file) {
+      if (!Array.isArray(file)) {
+        file = [file];
+      }
 
-const _openCamera = () => {
-  if (!window.android) {
-    alert('Android 接口不可用')
-    return
-  }
-  window.android.openCamera()
-}
+      file.forEach(item => {
+        // 生成预览图
+        if (item.file) {
+          item.content = URL.createObjectURL(item.file);
+        }
 
-const _openGallery = () => {
-  if (!window.android) {
-    alert('Android 接口不可用')
-    return
-  }
-  window.android.openGallery()
-}
+        // 设置上传状态
+        item.status = 'uploading';
+        item.message = '上传中...';
 
-const _openImageEditor = () => {
-  if (!window.android) {
-    alert('Android 接口不可用')
-    return
-  }
-  if (!imagePath.value) {
-    alert('请先选择图片')
-    return
-  }
-  window.android.openImageEditor(imagePath.value)
-}
-
-// 这个函数应该由 Android 调用
-window.handleImageResult = (path) => {
-  imagePath.value = path
-  // 如果是文件路径,直接使用
-  if (path.startsWith('file://') || path.startsWith('/storage')) {
-    imageUrl.value = path
-  }
-  // 如果是 base64,直接使用
-  else if (path.startsWith('data:image')) {
-    imageUrl.value = path
-  }
-}
-
-// 处理 Blob 数据
-window.handleImageBlob = (base64) => {
-  const blob = base64ToBlob(base64, 'image/jpeg')
-  imageUrl.value = URL.createObjectURL(blob)
-}
-
-// 将 base64 转换为 Blob
-const base64ToBlob = (base64, mimeType) => {
-  const byteCharacters = atob(base64.split(',')[1])
-  const byteNumbers = new Array(byteCharacters.length)
-  for (let i = 0; i < byteCharacters.length; i++) {
-    byteNumbers[i] = byteCharacters.charCodeAt(i)
+        this.uploadImage(item).then(res => {
+          item.status = 'done';
+          item.message = '上传成功';
+          // 保存服务器返回的URL
+          // item.url = res.data.url;
+        }).catch(err => {
+          item.status = 'failed';
+          item.message = '上传失败';
+          Toast.fail('上传失败');
+        });
+      });
+    },
+
+    uploadImage(file) {
+      return new Promise((resolve, reject) => {
+        // 这里替换为真实的上传逻辑
+        const formData = new FormData();
+        formData.append('file', file.file);
+
+        // 示例:使用axios上传
+        // axios.post('/api/upload', formData, {
+        //   headers: {
+        //     'Content-Type': 'multipart/form-data'
+        //   }
+        // }).then(resolve).catch(reject)
+
+        // 模拟上传
+        setTimeout(() => {
+          resolve({
+            data: {
+              url: URL.createObjectURL(file.file)
+            }
+          });
+        }, 1500);
+      });
+    },
+
+    onOversize(file) {
+      Toast.fail('文件大小不能超过5MB');
+    },
+
+    removeImage(index) {
+      this.fileList.splice(index, 1);
+    }
+  },
+
+  // 组件销毁时释放内存
+  beforeDestroy() {
+    this.fileList.forEach(file => {
+      if (file.content) {
+        URL.revokeObjectURL(file.content);
+      }
+    });
   }
-  const byteArray = new Uint8Array(byteNumbers)
-  return new Blob([byteArray], { type: mimeType })
-}
+};
 </script>
 
+
 <style scoped lang="sass">
-button
-  margin: 10px
-  padding: 8px 16px
-  background: #42b983
-  color: white
-  border: none
+.upload-container
+  padding: 15px
+
+
+.preview-container
+  display: flex
+  flex-wrap: wrap
+  margin-top: 15px
+
+
+.preview-item
+  position: relative
+  width: 100px
+  height: 100px
+  margin-right: 10px
+  margin-bottom: 10px
+  border: 1px solid #eee
   border-radius: 4px
-  cursor: pointer
+  overflow: hidden
+
+
+.preview-image
+  width: 100%
+  height: 100%
+  object-fit: cover
+
+
+.preview-status
+  position: absolute
+  bottom: 0
+  left: 0
+  right: 0
+  padding: 2px 5px
+  font-size: 12px
+  color: white
+  background-color: rgba(0, 0, 0, 0.6)
+
+
+.status-uploading
+  background-color: #1989fa
+
 
+.status-done
+  background-color: #07c160
 
-.image-preview
-  margin-top: 20px
-  img
-    max-width: 100%
-    max-height: 400px
-    border: 1px solid #ddd
-    border-radius: 4px
+
+.status-failed
+  background-color: #ee0a24
+
+.preview-remove
+  position: absolute
+  top: 0
+  right: 0
+  color: white
+  background-color: rgba(0, 0, 0, 0.5)
+  padding: 4px
+  border-radius: 0 0 0 4px
+  cursor: pointer
 
 
 </style>