|
@@ -1,113 +1,182 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div>
|
|
<div>
|
|
|
|
|
+ <!-- 图片预览 -->
|
|
|
<div class="img-view" v-if="dialogImageUrl">
|
|
<div class="img-view" v-if="dialogImageUrl">
|
|
|
<img :src="dialogImageUrl" alt="" srcset="" />
|
|
<img :src="dialogImageUrl" alt="" srcset="" />
|
|
|
</div>
|
|
</div>
|
|
|
<div class="placeholder-box" v-else>
|
|
<div class="placeholder-box" v-else>
|
|
|
<img src="~@/assets/upload-placeholder.svg" alt="" />
|
|
<img src="~@/assets/upload-placeholder.svg" alt="" />
|
|
|
|
|
+ <span>请上传签名</span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 操作按钮 -->
|
|
|
<div class="btn-box">
|
|
<div class="btn-box">
|
|
|
- <el-upload class="avatar-div" action="#" accept="image/png,image/jpeg" :show-file-list="false" ref="uploadRef"
|
|
|
|
|
- :on-exceed="handleExceed" :limit="1" :http-request="handlSuccess" :multiple="false">
|
|
|
|
|
- <el-button type="text">上传{{ assetName }}图片</el-button>
|
|
|
|
|
- </el-upload>
|
|
|
|
|
|
|
+ <el-button type="text" @click="triggerFileInput" :loading="uploading">
|
|
|
|
|
+ 上传{{ assetName }}图片
|
|
|
|
|
+ </el-button>
|
|
|
<el-button type="text" @click="clearImg">清除图片</el-button>
|
|
<el-button type="text" @click="clearImg">清除图片</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 隐藏的文件选择器 -->
|
|
|
|
|
+ <input
|
|
|
|
|
+ type="file"
|
|
|
|
|
+ ref="fileInput"
|
|
|
|
|
+ accept="image/png,image/jpeg"
|
|
|
|
|
+ style="display: none"
|
|
|
|
|
+ @change="handleFileChange"
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
|
|
+ <!-- ele-cropper-modal 裁剪弹窗 -->
|
|
|
|
|
+ <EleCropperDialog
|
|
|
|
|
+ :show.sync="showCropper"
|
|
|
|
|
+ :src="cropperSrc"
|
|
|
|
|
+ :aspect-ratio="1 / 1"
|
|
|
|
|
+ append-to-body
|
|
|
|
|
+ image-type="image/png"
|
|
|
|
|
+ :to-blob="true"
|
|
|
|
|
+ @crop="handleCropSuccess"
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
-import { uploadFile, removeFile } from '@/api/system/file/index.js';
|
|
|
|
|
-import { getImageUrl } from '@/utils/file';
|
|
|
|
|
-export default {
|
|
|
|
|
- props: {
|
|
|
|
|
- assetName: {
|
|
|
|
|
- type: String,
|
|
|
|
|
- default: '设备'
|
|
|
|
|
|
|
+ import { uploadFile, removeFile } from '@/api/system/file/index.js';
|
|
|
|
|
+ import { getImageUrl } from '@/utils/file';
|
|
|
|
|
+
|
|
|
|
|
+ // 如果 ele-cropper-modal 没有全局注册,需要在此处导入
|
|
|
|
|
+ import EleCropperDialog from 'ele-admin/es/ele-cropper-dialog';
|
|
|
|
|
+
|
|
|
|
|
+ export default {
|
|
|
|
|
+ // 如果未全局注册,取消下面注释
|
|
|
|
|
+ components: { EleCropperDialog },
|
|
|
|
|
+ props: {
|
|
|
|
|
+ assetName: {
|
|
|
|
|
+ type: String,
|
|
|
|
|
+ default: '设备'
|
|
|
|
|
+ },
|
|
|
|
|
+ value: {
|
|
|
|
|
+ type: Object,
|
|
|
|
|
+ default: () => ({})
|
|
|
|
|
+ },
|
|
|
|
|
+ // 所属模块
|
|
|
|
|
+ module: {
|
|
|
|
|
+ type: String,
|
|
|
|
|
+ default: 'main'
|
|
|
|
|
+ }
|
|
|
},
|
|
},
|
|
|
- value: {
|
|
|
|
|
- type: Object,
|
|
|
|
|
- default: () => []
|
|
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ showCropper: false, // 控制裁剪弹窗显示
|
|
|
|
|
+ cropperSrc: null, // 待裁剪图片的临时地址
|
|
|
|
|
+ uploading: false // 上传状态
|
|
|
|
|
+ };
|
|
|
},
|
|
},
|
|
|
- // 所属模块
|
|
|
|
|
- module: {
|
|
|
|
|
- type: String,
|
|
|
|
|
- default: 'main'
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- data() {
|
|
|
|
|
- return {};
|
|
|
|
|
- },
|
|
|
|
|
- computed: {
|
|
|
|
|
- dialogImageUrl() {
|
|
|
|
|
- return this.value?.storePath && getImageUrl(this.value.storePath);
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- methods: {
|
|
|
|
|
- // 清空已上传的文件列表
|
|
|
|
|
- clearUploadFiles() { },
|
|
|
|
|
- //图片添加
|
|
|
|
|
- async handlSuccess(params) {
|
|
|
|
|
- let res = await uploadFile({
|
|
|
|
|
- multiPartFile: params.file,
|
|
|
|
|
- module: this.module
|
|
|
|
|
- });
|
|
|
|
|
- if (res?.data) {
|
|
|
|
|
- this.$emit('input', res.data);
|
|
|
|
|
|
|
+ computed: {
|
|
|
|
|
+ dialogImageUrl() {
|
|
|
|
|
+ return this.value?.storePath && getImageUrl(this.value.storePath);
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
- async clearImg() {
|
|
|
|
|
- if(!this.value.id){
|
|
|
|
|
- return
|
|
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ // 触发隐藏的文件选择器
|
|
|
|
|
+ triggerFileInput() {
|
|
|
|
|
+ this.$refs.fileInput.click();
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 文件选择后的处理
|
|
|
|
|
+ handleFileChange(event) {
|
|
|
|
|
+ const file = event.target.files[0];
|
|
|
|
|
+ if (!file) return;
|
|
|
|
|
+
|
|
|
|
|
+ // 读取文件为 Data URL,用作裁剪器的图片源
|
|
|
|
|
+ const reader = new FileReader();
|
|
|
|
|
+ reader.onload = (e) => {
|
|
|
|
|
+ this.cropperSrc = e.target.result;
|
|
|
|
|
+ this.showCropper = true;
|
|
|
|
|
+ // 重置 input,允许重复选择同一文件
|
|
|
|
|
+ event.target.value = '';
|
|
|
|
|
+ };
|
|
|
|
|
+ reader.readAsDataURL(file);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 裁剪成功回调
|
|
|
|
|
+ async handleCropSuccess(blob) {
|
|
|
|
|
+ // 因为设置了 :to-blob="true",所以直接拿到 Blob 对象
|
|
|
|
|
+ if (!blob) {
|
|
|
|
|
+ this.showCropper = false;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.uploading = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const file = new File([blob], 'signature.png', { type: 'image/png' });
|
|
|
|
|
+ // const formData = new FormData();
|
|
|
|
|
+ // formData.append('multiPartFile', file);
|
|
|
|
|
+ // formData.append('module', this.module);
|
|
|
|
|
+
|
|
|
|
|
+ const res = await uploadFile({
|
|
|
|
|
+ multiPartFile: file,
|
|
|
|
|
+ module: this.module
|
|
|
|
|
+ });
|
|
|
|
|
+ if (res?.data) {
|
|
|
|
|
+ this.$emit('input', res.data);
|
|
|
|
|
+ this.$message.success('上传成功');
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error(error);
|
|
|
|
|
+ this.$message.error('上传失败,请稍后重试');
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ this.uploading = false;
|
|
|
|
|
+ this.showCropper = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 清除图片
|
|
|
|
|
+ async clearImg() {
|
|
|
|
|
+ if (!this.value.id) return;
|
|
|
|
|
+ try {
|
|
|
|
|
+ await removeFile({ fileId: this.value.id });
|
|
|
|
|
+ this.$emit('input', {});
|
|
|
|
|
+ this.$message.success('已清除');
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ this.$message.error('清除失败');
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- await removeFile({ fileId: this.value.id });
|
|
|
|
|
- this.$emit('input', {});
|
|
|
|
|
- this.$refs.uploadRef.clearFiles();
|
|
|
|
|
- },
|
|
|
|
|
- // 限制上传的数量
|
|
|
|
|
- handleExceed(files, fileList) {
|
|
|
|
|
- this.$message.warning(`最多允许上传一张图片!`);
|
|
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
-};
|
|
|
|
|
|
|
+ };
|
|
|
</script>
|
|
</script>
|
|
|
|
|
+
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
|
-.img-view {
|
|
|
|
|
- width: 280px;
|
|
|
|
|
- height: 342px;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- border-width: 1px;
|
|
|
|
|
- border-style: solid;
|
|
|
|
|
- border-color: rgba(215, 215, 215, 1);
|
|
|
|
|
-
|
|
|
|
|
- img {
|
|
|
|
|
- max-width: 100%;
|
|
|
|
|
- max-height: 100%;
|
|
|
|
|
|
|
+ .img-view {
|
|
|
|
|
+ width: 280px;
|
|
|
|
|
+ height: 342px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ border: 1px solid #d7d7d7;
|
|
|
|
|
+
|
|
|
|
|
+ img {
|
|
|
|
|
+ max-width: 100%;
|
|
|
|
|
+ max-height: 100%;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.placeholder-box {
|
|
|
|
|
- width: 250px;
|
|
|
|
|
- height: 200px;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
-
|
|
|
|
|
- background-color: rgba(242, 242, 242, 1);
|
|
|
|
|
- box-sizing: border-box;
|
|
|
|
|
- border-width: 1px;
|
|
|
|
|
- border-style: solid;
|
|
|
|
|
- border-color: rgba(215, 215, 215, 1);
|
|
|
|
|
- padding-top: 60px;
|
|
|
|
|
-
|
|
|
|
|
- img {
|
|
|
|
|
- width: 100px;
|
|
|
|
|
- height: 100px;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ .placeholder-box {
|
|
|
|
|
+ width: 250px;
|
|
|
|
|
+ height: 200px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ background-color: #f2f2f2;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ border: 1px solid #d7d7d7;
|
|
|
|
|
+ padding-top: 60px;
|
|
|
|
|
+
|
|
|
|
|
+ img {
|
|
|
|
|
+ width: 100px;
|
|
|
|
|
+ height: 100px;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
-.btn-box {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- justify-content: space-around;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ .btn-box {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-around;
|
|
|
|
|
+ }
|
|
|
</style>
|
|
</style>
|