chore: 🔨 移除 vue-picture-cropper 插件(ts兼容问题)

This commit is contained in:
ray
2024-12-02 13:57:56 +08:00
parent 1c71768058
commit c2b05bac6c
6 changed files with 0 additions and 526 deletions

View File

@@ -65,7 +65,6 @@
"sortablejs": "^1.15.6", "sortablejs": "^1.15.6",
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-i18n": "9.9.1", "vue-i18n": "9.9.1",
"vue-picture-cropper": "^0.7.0",
"vue-router": "^4.5.0" "vue-router": "^4.5.0"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,92 +0,0 @@
/**
* 图片压缩类
* @param minSize
* @param maxSize
* @constructor
*/
export function PhotoCompress(minSize, maxSize) {
var nextQ = 0.5; // 压缩比例
var maxQ = 1;
var minQ = 0;
/**
* 将base64转换为文件
* @param base64Codes base64编码
* @param fileName 文件名称
* @returns {*}
*/
PhotoCompress.prototype.dataUrlToFile = function (base64Codes, fileName = new Date().getTime()) {
var arr = base64Codes.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bStr = atob(arr[1]),
n = bStr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bStr.charCodeAt(n);
}
return new File([u8arr], fileName, { type: mime });
};
/**
* 图片压缩
* @param file 文件
* @param callback 回调函数
*/
PhotoCompress.prototype.compress = function (file, callback) {
var self = this;
self.imgBase64(file, function (image, canvas) {
var base64Codes = canvas.toDataURL(file.type, nextQ); // y压缩
var compressFile = self.dataUrlToFile(base64Codes, file.name.split(".")[0]); // 转成file文件
var compressFileSize = compressFile.size; // 压缩后文件大小 k
// console.log("图片质量:" + nextQ);
// console.log("压缩后文件大小:" + compressFileSize / 1024);
if (compressFileSize > maxSize) {
// 压缩后文件大于最大值
maxQ = nextQ;
nextQ = (nextQ + minQ) / 2; // 质量降低
self.compress(file, callback);
} else if (compressFileSize < minSize) {
// 压缩以后文件小于最小值
minQ = nextQ;
nextQ = (nextQ + maxQ) / 2; // 质量提高
self.compress(file, callback);
} else {
callback(compressFile);
}
});
};
/**
* 将图片转化为base64
* @param file 文件
* @param callback 回调函数
*/
PhotoCompress.prototype.imgBase64 = function (file, callback) {
// 看支持不支持FileReader
if (!file || !window.FileReader) return;
var image = new Image();
// 绑定 load 事件处理器,加载完成后执行
image.onload = function () {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
canvas.width = image.width * nextQ;
canvas.height = image.height * nextQ;
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
callback(image, canvas);
};
if (/^image/.test(file.type)) {
// 创建一个reader
var reader = new FileReader();
// 将图片将转成 base64 格式
reader.readAsDataURL(file);
// 读取成功后的回调
reader.onload = function () {
// self.imgUrls.push(this.result);
// 设置src属性浏览器会自动加载。
// 记住必须先绑定事件才能设置src属性否则会出同步问题。
image.src = this.result;
};
}
};
}

View File

@@ -1,205 +0,0 @@
<template>
<el-dialog
v-model="isShowModal"
title="裁剪图片"
width="50%"
:close-on-press-escape="false"
:close-on-click-modal="false"
align-center
@close="cancel"
>
<div class="modal-content">
<VuePictureCropper
:img="pic"
:boxStyle="corpBoxStyle"
:options="corpOptions"
:presetMode="corpPresetMode"
@ready="ready"
/>
</div>
<div class="m-t-10 btns">
<el-button class="default-btn" @click="cancel">取消</el-button>
<el-button v-if="showClear" class="default-btn" @click="clear">关闭</el-button>
<el-button v-if="showReset" class="default-btn" @click="reset">重置</el-button>
<el-button class="default-btn primary" @click="getResult">确定</el-button>
</div>
</el-dialog>
</template>
<script setup lang="ts">
// 组件文档https://cropper.chengpeiquan.com/zh/quick-start.html
import VuePictureCropper, { cropper } from "vue-picture-cropper";
import { PhotoCompress } from "./compressUtil.js";
const props = defineProps({
visible: {
type: Boolean,
},
image: {
type: [String, File],
},
presetMode: {
type: Object,
},
options: {
type: Object,
},
boxStyle: {
type: Object,
},
showClear: {
// 是否显示 Clear 按钮
type: Boolean,
},
showReset: {
// 是否显示 Reset 按钮
type: Boolean,
},
isCompress: {
// 是否压缩裁剪后的图片大小
type: Boolean,
},
compressSize: {
// 压缩图片大小限制
type: Object,
default: {
maxSize: 0.3 * 1024 * 1024, // 300k
minSize: 0.03 * 1024 * 1024, // 30k
},
},
});
/** 裁剪组件属性配置 */
const corpOptions = computed(() => {
return {
viewMode: 1, // 裁剪框范围 1-只能在图片区域内活动
dragMode: "move", // 可选值 crop(可绘制裁剪框) | move(仅移动)
// aspectRatio: 1 / 1,// 裁剪框的宽高比
cropBoxResizable: false, // 是否可以调整裁剪区的大小
...props.options,
};
});
/** 裁剪区域的样式 */
const corpBoxStyle = computed(() => {
return {
width: "auto",
height: "400px",
backgroundColor: "#f8f8f8",
margin: "auto",
...props.boxStyle,
};
});
/** 预设模式配置 */
const corpPresetMode = computed(() => {
return {
mode: "fixedSize",
width: 200,
height: 200,
...props.presetMode,
};
});
const emits = defineEmits(["close"]);
watch(
() => props.visible,
(val) => {
isShowModal.value = val;
if (!val) {
pic.value = "";
result.dataURL = "";
result.blobURL = "";
reset();
}
}
);
watch(
() => props.image,
(val) => {
pic.value = val;
}
);
const isShowModal = ref(false);
const pic = ref("");
const result = reactive({
dataURL: "",
blobURL: "",
});
async function getResult() {
if (!cropper) return;
const base64 = cropper.getDataURL();
const blob = await cropper.getBlob();
if (!blob) return;
let file = await cropper.getFile({
fileName: "locales.fileName",
});
result.dataURL = base64;
result.blobURL = URL.createObjectURL(blob);
const { minSize, maxSize } = props.compressSize;
// console.log(file.size, maxSize)
// 是否限制文件大小
if (props.isCompress && file.size > maxSize) {
// console.log("compress")
const photoCompress = new PhotoCompress(minSize, maxSize);
photoCompress.compress(file, function (f) {
const r = new FileReader();
r.readAsDataURL(f);
r.onload = function (e) {
emits("close", { result, file: f });
};
});
} else {
// console.log("crop")
emits("close", { result, file });
}
}
/**
* Clear the crop box
*/
function clear() {
if (!cropper) return;
cropper.clear();
}
/**
* Reset the default cropping area
*/
function reset() {
if (!cropper) return;
cropper.reset();
}
/**
* The ready event passed to Cropper.js
*/
function ready() {
// console.log('Cropper is ready.')
}
function cancel() {
emits("close");
}
</script>
<style lang="scss" scoped>
.modal-wrap {
position: fixed;
top: 0;
left: 0;
z-index: 99;
width: 100%;
height: 100%;
overflow: hidden;
}
.btns {
display: flex;
justify-content: flex-end;
}
</style>

View File

@@ -1,211 +0,0 @@
<template>
<el-upload
v-model:file-list="fileList"
list-type="picture-card"
:auto-upload="true"
:class="fileList.length >= 1 || !props.showUploadBtn ? 'hide' : 'show'"
:before-upload="handleBeforeUpload"
:data="props.data"
:name="props.name"
:accept="props.accept"
:limit="1"
>
<i-ep-plus />
{{ title }}
<template #file="{ file }">
<div style="width: 100%">
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
<span class="el-upload-list__item-actions">
<span class="el-upload-list__item-preview" @click="previewImg(file)">
<el-icon><zoom-in /></el-icon>
</span>
<span
v-if="props.showDelBtn"
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<el-icon><Delete /></el-icon>
</span>
</span>
</div>
</template>
</el-upload>
<el-image-viewer
v-if="viewVisible"
:zoom-rate="1.2"
:initialIndex="initialIndex"
:url-list="[viewFile]"
@close="closePreview"
/>
<CorpperDialog
:visible="isShowCorpper"
:image="selectPic"
:isCompress="true"
:showReset="true"
:presetMode="presetMode"
@close="hideCorpper"
/>
</template>
<script setup lang="ts">
import CorpperDialog from "./corpperDialog.vue";
import { UploadRawFile, UploadUserFile, UploadFile, UploadProps } from "element-plus";
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
/**
* 文件路径
*/
modelValue: {
type: String,
default: "",
},
title: {
type: String,
default: "上传图片",
},
/**
* 上传文件的参数名
*/
name: {
type: String,
default: "file",
},
/**
* 文件上传数量限制
*/
limit: {
type: Number,
default: 1,
},
/**
* 是否显示删除按钮
*/
showDelBtn: {
type: Boolean,
default: true,
},
/**
* 是否显示上传按钮
*/
showUploadBtn: {
type: Boolean,
default: true,
},
/**
* 单张图片最大大小
*/
uploadMaxSize: {
type: Number,
default: 2 * 1024 * 1024,
},
/**
* 上传文件类型
*/
accept: {
type: String,
default: "image/*",
},
presetMode: {
type: Object,
default: "{ width: 200, height: 200 }",
},
});
const selectPic = ref("");
const isShowCorpper = ref(false);
const viewVisible = ref(false);
const initialIndex = ref(0);
const fileList = ref([] as UploadUserFile[]);
const viewFile = ref(props.modelValue as string);
watch(
() => props.modelValue,
(newVal: string) => {
if (!newVal) {
fileList.value = [];
return;
}
fileList.value = [{ url: newVal } as UploadUserFile];
viewFile.value = newVal;
},
{ immediate: true }
);
/**
* 删除图片
*/
function handleRemove(removeFile: UploadFile) {
const filePath = removeFile.url;
if (filePath) {
emit("update:modelValue", "");
}
}
/**
* 限制用户上传文件的格式和大小
*/
function handleBeforeUpload(file: UploadRawFile) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
selectPic.value = String(reader.result);
isShowCorpper.value = true;
};
if (file.size > props.uploadMaxSize) {
ElMessage.warning("上传图片不能大于 " + Math.trunc(props.uploadMaxSize / 1024 / 1024) + "M");
return false;
}
return true;
}
/**
* 预览图片
*/
const previewImg: UploadProps["onPreview"] = (uploadFile: UploadFile) => {
viewFile.value = uploadFile.url!;
initialIndex.value = 0;
viewVisible.value = true;
};
/**
* 关闭预览
*/
const closePreview = () => {
viewVisible.value = false;
};
function hideCorpper(data: any) {
isShowCorpper.value = false;
if (data) {
const {
result: { dataURL },
file,
} = data;
emit("update:modelValue", dataURL);
}
}
</script>
<style lang="scss" scoped>
.hide {
:deep(.el-upload--picture-card) {
display: none;
}
}
.show {
:deep(.el-upload--picture-card) {
display: flex;
}
}
</style>

View File

@@ -91,7 +91,6 @@ declare module "vue" {
ThemeColorPicker: (typeof import("./../layout/components/Settings/components/ThemeColorPicker.vue"))["default"]; ThemeColorPicker: (typeof import("./../layout/components/Settings/components/ThemeColorPicker.vue"))["default"];
SingleImageUpload: (typeof import("./../components/Upload/SingleImageUpload.vue"))["default"]; SingleImageUpload: (typeof import("./../components/Upload/SingleImageUpload.vue"))["default"];
WangEditor: (typeof import("./../components/WangEditor/index.vue"))["default"]; WangEditor: (typeof import("./../components/WangEditor/index.vue"))["default"];
ImgCorpper: (typeof import("./../components/ImgCorpper/index.vue"))["default"];
} }
export interface ComponentCustomProperties { export interface ComponentCustomProperties {
vLoading: (typeof import("element-plus/es"))["ElLoadingDirective"]; vLoading: (typeof import("element-plus/es"))["ElLoadingDirective"];

View File

@@ -23,22 +23,6 @@
</el-table> </el-table>
</el-form-item> </el-form-item>
<el-form-item label="单图裁剪">
<ImgCorpper
v-model="cprpperValue"
:presetMode="{ width: 295, height: 413 }"
:title="'上传图片'"
/>
</el-form-item>
<el-form-item label="参数说明">
<el-table :data="imageCprpperUploadArgData" border>
<el-table-column prop="argsName" label="参数名称" width="300" />
<el-table-column prop="type" label="参数类型" width="200" />
<el-table-column prop="default" label="默认值" width="400" />
<el-table-column prop="desc" label="描述" width="300" />
</el-table>
</el-form-item>
<el-form-item label="多图上传"> <el-form-item label="多图上传">
<MultiImageUpload v-model="picUrls" /> <MultiImageUpload v-model="picUrls" />
</el-form-item> </el-form-item>