django-vue3-admin-web/node_modules/@fast-crud/fast-extends/dist/fs-cropper-uploader-c3fbe88c.mjs.map
2025-10-20 21:21:14 +08:00

1 line
35 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{"version":3,"file":"fs-cropper-uploader-c3fbe88c.mjs","sources":["../src/uploader/components/fs-cropper-uploader.vue","../src/uploader/components/fs-cropper-uploader.vue"],"sourcesContent":["<template>\n <div class=\"fs-cropper-uploader\" :class=\"{ 'is-disabled': computedProps.disabled }\">\n <div class=\"image-list\">\n <component :is=\"ui.imageGroup.name\">\n <div v-for=\"(item, index) in listRef\" :key=\"index\" class=\"image-item\">\n <component :is=\"ui.image.name\" class=\"image\" :src=\"getImageSrc(item)\" v-bind=\"computedProps.img\">\n <template #placeholder>\n <div class=\"image-slot\">\n <fs-loading :loading=\"true\" />\n </div>\n </template>\n </component>\n <div class=\"delete\">\n <fs-icon v-if=\"!computedProps.disabled\" :icon=\"ui.icons.remove\" @click=\"removeImage(index as number)\" />\n <fs-icon :icon=\"ui.icons.search\" @click=\"preview(item)\" />\n </div>\n <div v-if=\"item.status === 'uploading'\" class=\"status-uploading\">\n <component :is=\"ui.progress.name\" type=\"circle\" :percentage=\"item.progress\" :width=\"70\" />\n </div>\n <div v-else-if=\"item.status === 'done'\" class=\"status-done\">\n <fs-icon :icon=\"ui.icons.check\" class=\"status-down-icon\" />\n </div>\n </div>\n <div\n v-if=\"computedProps.limit <= 0 || computedProps.limit > listRef.length\"\n class=\"image-item image-plus\"\n @click=\"addNewImage\"\n >\n <fs-icon :icon=\"ui.icons.plus\" class=\"cropper-uploader-icon\" />\n </div>\n </component>\n </div>\n <fs-cropper\n ref=\"cropperRef\"\n :title=\"computedProps.title\"\n :cropper-height=\"computedProps.cropperHeight\"\n :dialog-width=\"computedProps.dialogWidth\"\n :accept=\"computedProps.accept\"\n :upload-tip=\"computedProps.uploadTip\"\n :max-size=\"computedProps.maxSize\"\n :cropper=\"computedProps.cropper\"\n :compress-quality=\"computedProps.compressQuality\"\n output=\"all\"\n @done=\"cropComplete\"\n @ready=\"doReady\"\n />\n <div class=\"fs-cropper-preview\" :class=\"{ open: previewVisible }\" @click=\"closePreview\">\n <div class=\"fs-cropper-preview-content\">\n <img v-if=\"previewUrl\" :src=\"previewUrl\" class=\"preview-image\" />\n </div>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, getCurrentInstance, reactive, ref, Ref, watch } from \"vue\";\nimport { useUi } from \"@fast-crud/fast-crud\";\nimport { FsUploaderDoUploadOptions } from \"../d/type\";\nimport { useUploader } from \"./utils\";\n\n/**\n * 图片裁剪上传组件,封装了fs-cropper\n * fs-cropper内部封装了[cropperjs](https://github.com/fengyuanchen/cropperjs)\n */\nexport default defineComponent({\n name: \"FsCropperUploader\",\n props: {\n /**\n * 初始图片url,或者是数组\n */\n modelValue: {\n type: [String, Object, Array]\n },\n img: {},\n /**\n * 上传后端类型,[form, cos, qiniu , alioss]\n */\n type: {\n type: String\n },\n /**\n * 上传提示\n */\n uploadTip: {\n type: String\n },\n /**\n * 对话框标题\n */\n title: String,\n /**\n * cropper的高度默认为浏览器可视窗口高度的40%最小270\n */\n cropperHeight: {\n type: [String, Number]\n },\n /**\n * 对话框宽度默认50%\n */\n dialogWidth: {\n type: [String, Number],\n default: \"50%\"\n },\n /**\n * 图片大小限制单位MB\n */\n maxSize: {\n type: Number,\n default: 5\n },\n /**\n * 图片数量限制,0为不限制\n */\n limit: {\n type: Number,\n default: 1\n },\n /**\n * 可接收的文件后缀\n */\n accept: {\n type: String,\n default: \".jpg, .jpeg, .png, .gif, .webp\"\n },\n /**\n * [cropperjs的参数](https://github.com/fengyuanchen/cropperjs)\n */\n cropper: {\n type: Object\n },\n /**\n * FsUploaderXXX的配置会临时覆盖全局上传配置参数\n */\n uploader: {\n type: Object\n },\n /**\n * 压缩质量\n */\n compressQuality: {\n type: Number,\n default: 0.8\n },\n /**\n * 构建下载url方法,不影响提交的value\n */\n buildUrl: {\n type: Function,\n default: async function (value: any) {\n return typeof value === \"object\" ? value.url : value;\n }\n },\n /**\n * 返回值类型\n * 支持:`[url,key,object]`\n */\n valueType: {\n type: String, // url ,key, object\n default: \"url\"\n },\n /**\n * 是否禁用\n */\n disabled: {}\n },\n emits: [\"update:modelValue\", \"change\", \"ready\"],\n setup(props: any, ctx: any) {\n const { ui } = useUi();\n const cropperRef: Ref = ref();\n const uploaderImplRef: Ref = ref();\n\n const indexRef: Ref = ref();\n const listRef: Ref = ref([]);\n const formValidator = ui.formItem.injectFormItemContext();\n // eslint-disable-next-line vue/no-setup-props-destructure\n // @ts-ignore\n let emitValue: any = props.modelValue;\n // eslint-disable-next-line vue/no-setup-props-destructure\n // @ts-ignore\n initValue(props.modelValue);\n\n async function initValue(value: any) {\n const list: any = [];\n if (value == null || value === \"\") {\n listRef.value = list;\n return;\n }\n if (typeof value === \"string\") {\n // @ts-ignore\n list.push({ url: await props.buildUrl(value), value: value, status: \"done\" });\n } else if (Array.isArray(value)) {\n for (const item of value) {\n // @ts-ignore\n list.push({ url: await props.buildUrl(item), value: item, status: \"done\" });\n }\n } else if (typeof value === \"object\") {\n // @ts-ignore\n list.push({ url: await props.buildUrl(value), value, status: \"done\" });\n } else {\n for (const item of value) {\n // @ts-ignore\n list.push({ url: await props.buildUrl(item), value: item, status: \"done\" });\n }\n }\n listRef.value = list;\n }\n function addNewImage() {\n // @ts-ignore\n if (props.disabled) {\n return;\n }\n indexRef.value = undefined;\n cropperRef.value.clear();\n cropperRef.value.open();\n }\n function removeImage(index: number) {\n listRef.value.splice(index, 1);\n doEmit();\n }\n function hasUploading() {\n const fileList: any = listRef.value;\n if (fileList && fileList.length > 0) {\n for (const item of fileList) {\n if (item.status === \"uploading\") {\n return true;\n }\n }\n }\n return false;\n }\n async function cropComplete(ret: any) {\n const blob = ret.blob;\n const dataUrl = ret.dataUrl;\n const file = ret.file;\n const filename = file.name;\n const blobFile = new File([blob], filename, { type: blob.type });\n\n // 开始上传\n const item: any = reactive({\n url: undefined,\n dataUrl: dataUrl,\n status: \"uploading\",\n progress: 0\n });\n const onProgress = (e: any) => {\n item.progress = e.percent;\n };\n const onError = (e: any) => {\n item.status = \"error\";\n item.message = \"文件上传出错:\" + e.message;\n console.error(e);\n };\n const option = {\n file: blobFile,\n onProgress,\n onError,\n fileName: filename\n };\n listRef.value.push(item);\n try {\n const uploaded = await doUpload(option);\n let value = uploaded;\n // @ts-ignore\n if (props.valueType !== \"object\") {\n // @ts-ignore\n value = uploaded[props.valueType];\n }\n // @ts-ignore\n item.url = await props.buildUrl(value);\n item.value = value;\n item.status = \"done\";\n doEmit();\n } catch (e) {\n onError(e);\n }\n }\n\n async function doUpload(option: FsUploaderDoUploadOptions) {\n // @ts-ignore\n option.options = props.uploader || {};\n const { getUploaderImpl } = useUploader();\n let uploaderRef = await getUploaderImpl(option.options.type);\n if (uploaderRef == null) {\n throw new Error(\"SorryThe component is not ready yet\");\n }\n return await uploaderRef?.upload(option);\n }\n\n async function doEmit() {\n const list = [];\n for (const item of listRef.value) {\n if (typeof item === \"string\") {\n list.push(item);\n } else {\n list.push(item.value);\n }\n }\n let ret = list;\n // @ts-ignore\n if (props.limit === 1) {\n ret = list && list.length > 0 ? list[0] : undefined;\n }\n emitValue = ret;\n ctx.emit(\"update:modelValue\", ret);\n await formValidator.onChange();\n await formValidator.onBlur();\n }\n\n function getImageSrc(item: any) {\n return item.dataUrl ? item.dataUrl : item.url;\n }\n\n const previewVisible = ref(false);\n const previewUrl = ref();\n function preview(item: any) {\n previewVisible.value = true;\n previewUrl.value = getImageSrc(item);\n }\n function closePreview() {\n previewVisible.value = false;\n previewUrl.value = null;\n }\n watch(\n () => {\n // @ts-ignore\n return props.modelValue;\n },\n async (val: any) => {\n ctx.emit(\"change\", val);\n if (val === emitValue) {\n return;\n }\n await initValue(val);\n }\n );\n const current = getCurrentInstance();\n function doReady(context: any) {\n ctx.emit(\"ready\", {\n uploaderRef: current,\n ...context\n });\n }\n\n const computedProps = computed(() => {\n return {\n ...props\n };\n });\n return {\n ui,\n cropperRef,\n uploaderImplRef,\n indexRef,\n listRef,\n addNewImage,\n hasUploading,\n cropComplete,\n doUpload,\n removeImage,\n getImageSrc,\n previewUrl,\n previewVisible,\n preview,\n closePreview,\n doReady,\n computedProps\n };\n }\n});\n</script>\n\n<style lang=\"less\">\n.fs-cropper-uploader {\n .fs-box {\n display: flex;\n flex-wrap: wrap;\n }\n .el-image-viewer__close {\n color: #fff;\n }\n &.is-disabled {\n .image-list {\n .image-item {\n cursor: not-allowed;\n }\n }\n i {\n cursor: not-allowed;\n }\n }\n .image-list {\n display: flex;\n justify-content: left;\n align-items: center;\n flex-wrap: wrap;\n .image-item {\n width: 100px;\n height: 100px;\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: #fbfdff;\n border: 1px solid #c0ccda;\n border-radius: 6px;\n position: relative;\n margin-right: 8px;\n margin-bottom: 8px;\n cursor: pointer;\n overflow: hidden;\n &.image-plus {\n border: 1px dashed #c0ccda;\n }\n .cropper-uploader-icon {\n vertical-align: top;\n font-size: 28px;\n color: #8c939d;\n }\n .image {\n width: 100px;\n }\n\n .delete {\n border-radius: 6px;\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n cursor: default;\n text-align: center;\n color: #fff;\n opacity: 0;\n font-size: 20px;\n background-color: rgba(0, 0, 0, 0.9);\n -webkit-transition: opacity 0.3s;\n transition: opacity 0.3s;\n &:hover {\n opacity: 0.9;\n }\n display: flex;\n justify-content: center;\n align-items: center;\n i {\n cursor: pointer;\n }\n\n display: flex;\n > * {\n margin: 5px;\n }\n }\n .status-uploading {\n border-radius: 6px;\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n cursor: default;\n text-align: center;\n color: #fff;\n opacity: 1;\n font-size: 20px;\n background-color: rgba(0, 0, 0, 0.5);\n -webkit-transition: opacity 0.3s;\n transition: opacity 0.3s;\n display: flex;\n justify-content: center;\n align-items: center;\n .el-progress {\n width: 70px;\n height: 70px;\n .el-progress__text {\n color: #fff;\n }\n }\n }\n .status-done {\n position: absolute;\n right: -15px;\n top: -6px;\n width: 40px;\n height: 24px;\n background: #13ce66;\n text-align: center;\n -webkit-transform: rotate(45deg);\n transform: rotate(45deg);\n -webkit-box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);\n box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);\n display: flex;\n justify-content: center;\n align-items: center;\n .status-down-icon {\n font-size: 12px;\n margin-top: 11px;\n color: #fff;\n -webkit-transform: rotate(-45deg);\n transform: rotate(-45deg);\n }\n }\n }\n }\n\n .fs-cropper-preview {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(183, 180, 180, 0.7);\n display: flex;\n justify-content: center;\n align-items: center;\n visibility: hidden;\n z-index: 10000;\n &.open {\n visibility: visible;\n }\n .fs-cropper-preview-content {\n max-height: 800px;\n max-width: 800px;\n img {\n max-height: 800px;\n max-width: 800px;\n object-fit: contain;\n }\n }\n }\n}\n</style>\n","<template>\n <div class=\"fs-cropper-uploader\" :class=\"{ 'is-disabled': computedProps.disabled }\">\n <div class=\"image-list\">\n <component :is=\"ui.imageGroup.name\">\n <div v-for=\"(item, index) in listRef\" :key=\"index\" class=\"image-item\">\n <component :is=\"ui.image.name\" class=\"image\" :src=\"getImageSrc(item)\" v-bind=\"computedProps.img\">\n <template #placeholder>\n <div class=\"image-slot\">\n <fs-loading :loading=\"true\" />\n </div>\n </template>\n </component>\n <div class=\"delete\">\n <fs-icon v-if=\"!computedProps.disabled\" :icon=\"ui.icons.remove\" @click=\"removeImage(index as number)\" />\n <fs-icon :icon=\"ui.icons.search\" @click=\"preview(item)\" />\n </div>\n <div v-if=\"item.status === 'uploading'\" class=\"status-uploading\">\n <component :is=\"ui.progress.name\" type=\"circle\" :percentage=\"item.progress\" :width=\"70\" />\n </div>\n <div v-else-if=\"item.status === 'done'\" class=\"status-done\">\n <fs-icon :icon=\"ui.icons.check\" class=\"status-down-icon\" />\n </div>\n </div>\n <div\n v-if=\"computedProps.limit <= 0 || computedProps.limit > listRef.length\"\n class=\"image-item image-plus\"\n @click=\"addNewImage\"\n >\n <fs-icon :icon=\"ui.icons.plus\" class=\"cropper-uploader-icon\" />\n </div>\n </component>\n </div>\n <fs-cropper\n ref=\"cropperRef\"\n :title=\"computedProps.title\"\n :cropper-height=\"computedProps.cropperHeight\"\n :dialog-width=\"computedProps.dialogWidth\"\n :accept=\"computedProps.accept\"\n :upload-tip=\"computedProps.uploadTip\"\n :max-size=\"computedProps.maxSize\"\n :cropper=\"computedProps.cropper\"\n :compress-quality=\"computedProps.compressQuality\"\n output=\"all\"\n @done=\"cropComplete\"\n @ready=\"doReady\"\n />\n <div class=\"fs-cropper-preview\" :class=\"{ open: previewVisible }\" @click=\"closePreview\">\n <div class=\"fs-cropper-preview-content\">\n <img v-if=\"previewUrl\" :src=\"previewUrl\" class=\"preview-image\" />\n </div>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { computed, defineComponent, getCurrentInstance, reactive, ref, Ref, watch } from \"vue\";\nimport { useUi } from \"@fast-crud/fast-crud\";\nimport { FsUploaderDoUploadOptions } from \"../d/type\";\nimport { useUploader } from \"./utils\";\n\n/**\n * 图片裁剪上传组件,封装了fs-cropper\n * fs-cropper内部封装了[cropperjs](https://github.com/fengyuanchen/cropperjs)\n */\nexport default defineComponent({\n name: \"FsCropperUploader\",\n props: {\n /**\n * 初始图片url,或者是数组\n */\n modelValue: {\n type: [String, Object, Array]\n },\n img: {},\n /**\n * 上传后端类型,[form, cos, qiniu , alioss]\n */\n type: {\n type: String\n },\n /**\n * 上传提示\n */\n uploadTip: {\n type: String\n },\n /**\n * 对话框标题\n */\n title: String,\n /**\n * cropper的高度默认为浏览器可视窗口高度的40%最小270\n */\n cropperHeight: {\n type: [String, Number]\n },\n /**\n * 对话框宽度默认50%\n */\n dialogWidth: {\n type: [String, Number],\n default: \"50%\"\n },\n /**\n * 图片大小限制单位MB\n */\n maxSize: {\n type: Number,\n default: 5\n },\n /**\n * 图片数量限制,0为不限制\n */\n limit: {\n type: Number,\n default: 1\n },\n /**\n * 可接收的文件后缀\n */\n accept: {\n type: String,\n default: \".jpg, .jpeg, .png, .gif, .webp\"\n },\n /**\n * [cropperjs的参数](https://github.com/fengyuanchen/cropperjs)\n */\n cropper: {\n type: Object\n },\n /**\n * FsUploaderXXX的配置会临时覆盖全局上传配置参数\n */\n uploader: {\n type: Object\n },\n /**\n * 压缩质量\n */\n compressQuality: {\n type: Number,\n default: 0.8\n },\n /**\n * 构建下载url方法,不影响提交的value\n */\n buildUrl: {\n type: Function,\n default: async function (value: any) {\n return typeof value === \"object\" ? value.url : value;\n }\n },\n /**\n * 返回值类型\n * 支持:`[url,key,object]`\n */\n valueType: {\n type: String, // url ,key, object\n default: \"url\"\n },\n /**\n * 是否禁用\n */\n disabled: {}\n },\n emits: [\"update:modelValue\", \"change\", \"ready\"],\n setup(props: any, ctx: any) {\n const { ui } = useUi();\n const cropperRef: Ref = ref();\n const uploaderImplRef: Ref = ref();\n\n const indexRef: Ref = ref();\n const listRef: Ref = ref([]);\n const formValidator = ui.formItem.injectFormItemContext();\n // eslint-disable-next-line vue/no-setup-props-destructure\n // @ts-ignore\n let emitValue: any = props.modelValue;\n // eslint-disable-next-line vue/no-setup-props-destructure\n // @ts-ignore\n initValue(props.modelValue);\n\n async function initValue(value: any) {\n const list: any = [];\n if (value == null || value === \"\") {\n listRef.value = list;\n return;\n }\n if (typeof value === \"string\") {\n // @ts-ignore\n list.push({ url: await props.buildUrl(value), value: value, status: \"done\" });\n } else if (Array.isArray(value)) {\n for (const item of value) {\n // @ts-ignore\n list.push({ url: await props.buildUrl(item), value: item, status: \"done\" });\n }\n } else if (typeof value === \"object\") {\n // @ts-ignore\n list.push({ url: await props.buildUrl(value), value, status: \"done\" });\n } else {\n for (const item of value) {\n // @ts-ignore\n list.push({ url: await props.buildUrl(item), value: item, status: \"done\" });\n }\n }\n listRef.value = list;\n }\n function addNewImage() {\n // @ts-ignore\n if (props.disabled) {\n return;\n }\n indexRef.value = undefined;\n cropperRef.value.clear();\n cropperRef.value.open();\n }\n function removeImage(index: number) {\n listRef.value.splice(index, 1);\n doEmit();\n }\n function hasUploading() {\n const fileList: any = listRef.value;\n if (fileList && fileList.length > 0) {\n for (const item of fileList) {\n if (item.status === \"uploading\") {\n return true;\n }\n }\n }\n return false;\n }\n async function cropComplete(ret: any) {\n const blob = ret.blob;\n const dataUrl = ret.dataUrl;\n const file = ret.file;\n const filename = file.name;\n const blobFile = new File([blob], filename, { type: blob.type });\n\n // 开始上传\n const item: any = reactive({\n url: undefined,\n dataUrl: dataUrl,\n status: \"uploading\",\n progress: 0\n });\n const onProgress = (e: any) => {\n item.progress = e.percent;\n };\n const onError = (e: any) => {\n item.status = \"error\";\n item.message = \"文件上传出错:\" + e.message;\n console.error(e);\n };\n const option = {\n file: blobFile,\n onProgress,\n onError,\n fileName: filename\n };\n listRef.value.push(item);\n try {\n const uploaded = await doUpload(option);\n let value = uploaded;\n // @ts-ignore\n if (props.valueType !== \"object\") {\n // @ts-ignore\n value = uploaded[props.valueType];\n }\n // @ts-ignore\n item.url = await props.buildUrl(value);\n item.value = value;\n item.status = \"done\";\n doEmit();\n } catch (e) {\n onError(e);\n }\n }\n\n async function doUpload(option: FsUploaderDoUploadOptions) {\n // @ts-ignore\n option.options = props.uploader || {};\n const { getUploaderImpl } = useUploader();\n let uploaderRef = await getUploaderImpl(option.options.type);\n if (uploaderRef == null) {\n throw new Error(\"SorryThe component is not ready yet\");\n }\n return await uploaderRef?.upload(option);\n }\n\n async function doEmit() {\n const list = [];\n for (const item of listRef.value) {\n if (typeof item === \"string\") {\n list.push(item);\n } else {\n list.push(item.value);\n }\n }\n let ret = list;\n // @ts-ignore\n if (props.limit === 1) {\n ret = list && list.length > 0 ? list[0] : undefined;\n }\n emitValue = ret;\n ctx.emit(\"update:modelValue\", ret);\n await formValidator.onChange();\n await formValidator.onBlur();\n }\n\n function getImageSrc(item: any) {\n return item.dataUrl ? item.dataUrl : item.url;\n }\n\n const previewVisible = ref(false);\n const previewUrl = ref();\n function preview(item: any) {\n previewVisible.value = true;\n previewUrl.value = getImageSrc(item);\n }\n function closePreview() {\n previewVisible.value = false;\n previewUrl.value = null;\n }\n watch(\n () => {\n // @ts-ignore\n return props.modelValue;\n },\n async (val: any) => {\n ctx.emit(\"change\", val);\n if (val === emitValue) {\n return;\n }\n await initValue(val);\n }\n );\n const current = getCurrentInstance();\n function doReady(context: any) {\n ctx.emit(\"ready\", {\n uploaderRef: current,\n ...context\n });\n }\n\n const computedProps = computed(() => {\n return {\n ...props\n };\n });\n return {\n ui,\n cropperRef,\n uploaderImplRef,\n indexRef,\n listRef,\n addNewImage,\n hasUploading,\n cropComplete,\n doUpload,\n removeImage,\n getImageSrc,\n previewUrl,\n previewVisible,\n preview,\n closePreview,\n doReady,\n computedProps\n };\n }\n});\n</script>\n\n<style lang=\"less\">\n.fs-cropper-uploader {\n .fs-box {\n display: flex;\n flex-wrap: wrap;\n }\n .el-image-viewer__close {\n color: #fff;\n }\n &.is-disabled {\n .image-list {\n .image-item {\n cursor: not-allowed;\n }\n }\n i {\n cursor: not-allowed;\n }\n }\n .image-list {\n display: flex;\n justify-content: left;\n align-items: center;\n flex-wrap: wrap;\n .image-item {\n width: 100px;\n height: 100px;\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: #fbfdff;\n border: 1px solid #c0ccda;\n border-radius: 6px;\n position: relative;\n margin-right: 8px;\n margin-bottom: 8px;\n cursor: pointer;\n overflow: hidden;\n &.image-plus {\n border: 1px dashed #c0ccda;\n }\n .cropper-uploader-icon {\n vertical-align: top;\n font-size: 28px;\n color: #8c939d;\n }\n .image {\n width: 100px;\n }\n\n .delete {\n border-radius: 6px;\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n cursor: default;\n text-align: center;\n color: #fff;\n opacity: 0;\n font-size: 20px;\n background-color: rgba(0, 0, 0, 0.9);\n -webkit-transition: opacity 0.3s;\n transition: opacity 0.3s;\n &:hover {\n opacity: 0.9;\n }\n display: flex;\n justify-content: center;\n align-items: center;\n i {\n cursor: pointer;\n }\n\n display: flex;\n > * {\n margin: 5px;\n }\n }\n .status-uploading {\n border-radius: 6px;\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n cursor: default;\n text-align: center;\n color: #fff;\n opacity: 1;\n font-size: 20px;\n background-color: rgba(0, 0, 0, 0.5);\n -webkit-transition: opacity 0.3s;\n transition: opacity 0.3s;\n display: flex;\n justify-content: center;\n align-items: center;\n .el-progress {\n width: 70px;\n height: 70px;\n .el-progress__text {\n color: #fff;\n }\n }\n }\n .status-done {\n position: absolute;\n right: -15px;\n top: -6px;\n width: 40px;\n height: 24px;\n background: #13ce66;\n text-align: center;\n -webkit-transform: rotate(45deg);\n transform: rotate(45deg);\n -webkit-box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);\n box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);\n display: flex;\n justify-content: center;\n align-items: center;\n .status-down-icon {\n font-size: 12px;\n margin-top: 11px;\n color: #fff;\n -webkit-transform: rotate(-45deg);\n transform: rotate(-45deg);\n }\n }\n }\n }\n\n .fs-cropper-preview {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(183, 180, 180, 0.7);\n display: flex;\n justify-content: center;\n align-items: center;\n visibility: hidden;\n z-index: 10000;\n &.open {\n visibility: visible;\n }\n .fs-cropper-preview-content {\n max-height: 800px;\n max-width: 800px;\n img {\n max-height: 800px;\n max-width: 800px;\n object-fit: contain;\n }\n }\n }\n}\n</style>\n"],"names":["_sfc_main","defineComponent","value","props","ctx","ui","useUi","cropperRef","ref","uploaderImplRef","indexRef","listRef","formValidator","emitValue","initValue","list","item","addNewImage","removeImage","index","doEmit","hasUploading","fileList","cropComplete","ret","blob","dataUrl","filename","blobFile","reactive","onProgress","e","onError","option","uploaded","doUpload","getUploaderImpl","useUploader","uploaderRef","getImageSrc","previewVisible","previewUrl","preview","closePreview","watch","val","current","getCurrentInstance","doReady","context","computedProps","computed","_hoisted_1","_hoisted_4","_hoisted_5","_resolveComponent","_normalizeClass","_ctx","_createElementVNode","_openBlock","_createBlock","_resolveDynamicComponent","_withCtx","_createElementBlock","_Fragment","_renderList","_mergeProps","_hoisted_2","_hoisted_3","_createCommentVNode","_component_fs_icon","_createVNode","_cache","args","_hoisted_6"],"mappings":"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"}