From 089bf5d2378b3c4a61d795b2a92bede2c193b771 Mon Sep 17 00:00:00 2001
From: admin <344137771@qq.com>
Date: Tue, 06 Jan 2026 11:22:58 +0800
Subject: [PATCH] 1

---
 src/components/layout/AvatarCropper.vue |  255 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 255 insertions(+), 0 deletions(-)

diff --git a/src/components/layout/AvatarCropper.vue b/src/components/layout/AvatarCropper.vue
new file mode 100644
index 0000000..b129288
--- /dev/null
+++ b/src/components/layout/AvatarCropper.vue
@@ -0,0 +1,255 @@
+<template>
+  <div class="lum-dialog-mask">
+    <el-container class="lum-dialog-box">
+      <el-header class="header" height="50px">
+        <p>选择头像</p>
+        <p class="tools">
+          <i class="el-icon-close" @click="$emit('close', 0)" />
+        </p>
+      </el-header>
+      <el-main class="main">
+        <el-container class="full-height">
+          <el-aside width="400px">
+            <div class="cropper-box">
+              <vue-cropper
+                ref="cropper"
+                mode="cover"
+                :img="option.img"
+                :output-size="option.size"
+                :output-type="option.outputType"
+                :info="true"
+                :full="option.full"
+                :fixed="fixed"
+                :fixed-number="fixedNumber"
+                :can-move="option.canMove"
+                :can-move-box="option.canMoveBox"
+                :fixed-box="option.fixedBox"
+                :original="option.original"
+                :auto-crop="option.autoCrop"
+                :auto-crop-width="option.autoCropWidth"
+                :auto-crop-height="option.autoCropHeight"
+                :center-box="option.centerBox"
+                :high="option.high"
+                @real-time="realTime"
+              />
+              <input
+                type="file"
+                id="uploads"
+                ref="fileInput"
+                accept="image/png, image/jpeg, image/jpg"
+                style="display: none"
+                @change="uploadImg($event, 1)"
+              />
+            </div>
+            <div class="tools tools-flex">
+              <el-button
+                size="small"
+                plain
+                icon="el-icon-upload"
+                @click="clickUpload"
+                >上传图片
+              </el-button>
+              <el-button
+                size="small"
+                plain
+                icon="el-icon-refresh"
+                @click="refreshCrop"
+                >刷新
+              </el-button>
+              <el-button
+                size="small"
+                plain
+                icon="el-icon-refresh-left"
+                @click="rotateLeft"
+                >左转
+              </el-button>
+              <el-button
+                size="small"
+                plain
+                icon="el-icon-refresh-right"
+                @click="rotateRight"
+                >右转
+              </el-button>
+            </div>
+          </el-aside>
+          <el-main class="no-padding">
+            <div class="cropper-box">
+              <div class="preview-img">
+                <img v-if="cusPreviewsImg" :src="cusPreviewsImg" />
+              </div>
+            </div>
+            <div class="tools">
+              <el-button type="primary" size="small" @click="uploadService">
+                保存图片
+              </el-button>
+            </div>
+          </el-main>
+        </el-container>
+      </el-main>
+    </el-container>
+  </div>
+</template>
+<script>
+import { VueCropper } from 'vue-cropper'
+import { ServeUploadAvatar } from '@/api/upload'
+
+export default {
+  name: 'AvatarCropper',
+  components: {
+    VueCropper,
+  },
+  data() {
+    return {
+      cusPreviewsImg: '',
+      previews: {},
+      option: {
+        img: '',
+        size: 1,
+        full: false,
+        outputType: 'png',
+        canMove: true,
+        fixedBox: true,
+        original: false,
+        canMoveBox: true,
+        autoCrop: true,
+        // 只有自动截图开启 宽度高度才生效
+        autoCropWidth: 200,
+        autoCropHeight: 150,
+        centerBox: false,
+        high: true,
+      },
+      fixed: true,
+      fixedNumber: [1, 1],
+    }
+  },
+  methods: {
+    clickUpload() {
+      this.$refs.fileInput.click()
+    },
+    clearCrop() {
+      if (!this.cusPreviewsImg) return false
+      this.$refs.cropper.clearCrop()
+    },
+    refreshCrop() {
+      if (!this.cusPreviewsImg) return false
+      this.$refs.cropper.refresh()
+    },
+    rotateLeft() {
+      if (!this.cusPreviewsImg) return false
+      this.$refs.cropper.rotateLeft()
+    },
+    rotateRight() {
+      if (!this.cusPreviewsImg) return false
+      this.$refs.cropper.rotateRight()
+    },
+    // 实时预览函数
+    realTime() {
+      this.$refs.cropper.getCropData(img => {
+        this.cusPreviewsImg = img
+      })
+    },
+
+    // 上传回调事件
+    uploadImg(e, num) {
+      let file = e.target.files[0]
+      if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
+        this.$message('图片类型必须是.gif,jpeg,jpg,png,bmp中的一种')
+        return false
+      }
+
+      let reader = new FileReader()
+      reader.onload = e => {
+        let data
+        if (typeof e.target.result === 'object') {
+          // 把Array Buffer转化为blob 如果是base64不需要
+          data = window.URL.createObjectURL(new Blob([e.target.result]))
+        } else {
+          data = e.target.result
+        }
+        if (num === 1) {
+          this.option.img = data
+        } else if (num === 2) {
+          this.example2.img = data
+        }
+      }
+      // 转化为base64
+      // reader.readAsDataURL(file)
+      // 转化为blob
+      reader.readAsArrayBuffer(file)
+    },
+
+    // 上传图片到服务器
+    uploadService() {
+      if (this.cusPreviewsImg == '') return
+
+      this.$refs.cropper.getCropBlob(blob => {
+        let file = new File([blob], 'avatar.png', {
+          type: blob.type,
+          lastModified: Date.now(),
+        })
+
+        const form = new FormData()
+        form.append('file', file)
+
+        ServeUploadAvatar(form)
+          .then(res => {
+            if (res.code == 200) {
+              this.$emit('close', 1, res.data.avatar)
+            } else {
+              this.$message('文件上传失败,请稍后再试...')
+            }
+          })
+          .catch(() => {
+            this.$message('文件上传失败,请稍后再试...')
+          })
+      })
+    },
+  },
+}
+</script>
+
+<style lang="less" scoped>
+.lum-dialog-box {
+  height: 550px;
+  max-width: 800px;
+
+  .main {
+    .cropper-box {
+      height: 400px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+
+      .preview-img {
+        width: 180px;
+        height: 180px;
+        border-radius: 50%;
+        overflow: hidden;
+        box-shadow: 0 0 4px #ccc;
+
+        img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+
+    .tools {
+      height: 40px;
+      margin-top: 20px;
+      text-align: center;
+
+      button {
+        border-radius: 1px;
+      }
+    }
+
+    .tools-flex {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: center;
+    }
+  }
+}
+</style>

--
Gitblit v1.9.3