前端代码格式化
This commit is contained in:
@@ -20,39 +20,26 @@
|
||||
class="custom-upload"
|
||||
:class="{ 'drag-over': isDragOver }"
|
||||
>
|
||||
<div
|
||||
v-if="fileList.length < maxCount && !disabled"
|
||||
class="upload-area"
|
||||
>
|
||||
<div v-if="fileList.length < maxCount && !disabled" class="upload-area">
|
||||
<loading-outlined v-if="uploading" class="upload-icon" />
|
||||
<plus-outlined v-else class="upload-icon" />
|
||||
<div class="ant-upload-text">
|
||||
{{ uploading ? "上传中..." : uploadText }}
|
||||
{{ uploading ? '上传中...' : uploadText }}
|
||||
</div>
|
||||
<div v-if="tip" class="ant-upload-tip">{{ tip }}</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
<a-modal
|
||||
:open="previewVisible"
|
||||
:title="previewTitle"
|
||||
:footer="null"
|
||||
:width="800"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<img
|
||||
alt="图片预览"
|
||||
style="width: 100%; max-height: 600px; object-fit: contain"
|
||||
:src="previewImage"
|
||||
/>
|
||||
<a-modal :open="previewVisible" :title="previewTitle" :footer="null" :width="800" @cancel="handleCancel">
|
||||
<img alt="图片预览" style="width: 100%; max-height: 600px; object-fit: contain" :src="previewImage" />
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, computed } from "vue";
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
import { PlusOutlined, LoadingOutlined } from "@ant-design/icons-vue";
|
||||
import uploadConfig from "@/config/upload";
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { message, Modal } from 'ant-design-vue'
|
||||
import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue'
|
||||
import uploadConfig from '@/config/upload'
|
||||
|
||||
const props = defineProps({
|
||||
// 图片列表
|
||||
@@ -68,7 +55,7 @@ const props = defineProps({
|
||||
// 接受的文件类型
|
||||
accept: {
|
||||
type: String,
|
||||
default: "image/*",
|
||||
default: 'image/*',
|
||||
},
|
||||
// 是否禁用
|
||||
disabled: {
|
||||
@@ -83,12 +70,12 @@ const props = defineProps({
|
||||
// 上传按钮文字
|
||||
uploadText: {
|
||||
type: String,
|
||||
default: "上传图片",
|
||||
default: '上传图片',
|
||||
},
|
||||
// 提示文字
|
||||
tip: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: '',
|
||||
},
|
||||
// 最小宽度(像素)
|
||||
minWidth: {
|
||||
@@ -120,258 +107,236 @@ const props = defineProps({
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
"update:modelValue",
|
||||
"change",
|
||||
"preview",
|
||||
"remove",
|
||||
"uploadSuccess",
|
||||
"uploadError",
|
||||
]);
|
||||
const emit = defineEmits(['update:modelValue', 'change', 'preview', 'remove', 'uploadSuccess', 'uploadError'])
|
||||
|
||||
// 文件列表
|
||||
const fileList = ref([]);
|
||||
const fileList = ref([])
|
||||
|
||||
// 预览相关
|
||||
const previewVisible = ref(false);
|
||||
const previewImage = ref("");
|
||||
const previewVisible = ref(false)
|
||||
const previewImage = ref('')
|
||||
const previewTitle = computed(() => {
|
||||
return previewImage.value ? "图片预览" : "";
|
||||
});
|
||||
return previewImage.value ? '图片预览' : ''
|
||||
})
|
||||
|
||||
// 上传状态
|
||||
const uploading = ref(false);
|
||||
const uploading = ref(false)
|
||||
|
||||
// 拖拽状态
|
||||
const isDragOver = ref(false);
|
||||
const isDragOver = ref(false)
|
||||
|
||||
// 初始化文件列表
|
||||
const initFileList = () => {
|
||||
if (props.modelValue) {
|
||||
if (typeof props.modelValue === "string") {
|
||||
if (typeof props.modelValue === 'string') {
|
||||
// 单图上传,字符串格式
|
||||
fileList.value = props.modelValue
|
||||
? [
|
||||
{
|
||||
uid: "-1",
|
||||
name: "image.png",
|
||||
status: "done",
|
||||
uid: '-1',
|
||||
name: 'image.png',
|
||||
status: 'done',
|
||||
url: props.modelValue,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
: []
|
||||
} else if (Array.isArray(props.modelValue)) {
|
||||
// 多图上传,数组格式
|
||||
fileList.value = props.modelValue.map((url, index) => ({
|
||||
uid: `-${index}`,
|
||||
name: `image${index}.png`,
|
||||
status: "done",
|
||||
status: 'done',
|
||||
url: url,
|
||||
}));
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
fileList.value = [];
|
||||
fileList.value = []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 监听外部值变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
() => {
|
||||
initFileList();
|
||||
initFileList()
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
)
|
||||
|
||||
// 自定义上传
|
||||
const customUpload = (options) => {
|
||||
const { file, onProgress, onSuccess, onError } = options;
|
||||
const formData = new FormData();
|
||||
formData.append(uploadConfig.filename || "file", file);
|
||||
const { file, onProgress, onSuccess, onError } = options
|
||||
const formData = new FormData()
|
||||
formData.append(uploadConfig.filename || 'file', file)
|
||||
|
||||
uploading.value = true;
|
||||
uploading.value = true
|
||||
|
||||
uploadConfig
|
||||
.apiObj(formData, {
|
||||
onUploadProgress: (progressEvent) => {
|
||||
const percent = Math.round(
|
||||
(progressEvent.loaded / progressEvent.total) * 100,
|
||||
);
|
||||
onProgress({ percent }, file);
|
||||
const percent = Math.round((progressEvent.loaded / progressEvent.total) * 100)
|
||||
onProgress({ percent }, file)
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
const data = uploadConfig.parseData(res);
|
||||
const data = uploadConfig.parseData(res)
|
||||
if (data.code === uploadConfig.successCode) {
|
||||
onSuccess(data, file);
|
||||
message.success("上传成功");
|
||||
emit("uploadSuccess", data, file);
|
||||
onSuccess(data, file)
|
||||
message.success('上传成功')
|
||||
emit('uploadSuccess', data, file)
|
||||
} else {
|
||||
onError(new Error(data.msg || "上传失败"));
|
||||
message.error(data.msg || "上传失败");
|
||||
emit("uploadError", data.msg || "上传失败", file);
|
||||
onError(new Error(data.msg || '上传失败'))
|
||||
message.error(data.msg || '上传失败')
|
||||
emit('uploadError', data.msg || '上传失败', file)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
onError(error);
|
||||
message.error("上传失败:" + error.message);
|
||||
emit("uploadError", error.message, file);
|
||||
onError(error)
|
||||
message.error('上传失败:' + error.message)
|
||||
emit('uploadError', error.message, file)
|
||||
})
|
||||
.finally(() => {
|
||||
uploading.value = false;
|
||||
});
|
||||
};
|
||||
uploading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
// 上传前校验
|
||||
const beforeUpload = async (file) => {
|
||||
// 文件大小校验
|
||||
const maxSizeMB = uploadConfig.maxSize || 10;
|
||||
const maxSizeBytes = maxSizeMB * 1024 * 1024;
|
||||
const maxSizeMB = uploadConfig.maxSize || 10
|
||||
const maxSizeBytes = maxSizeMB * 1024 * 1024
|
||||
|
||||
if (file.size > maxSizeBytes) {
|
||||
message.error(`图片大小不能超过 ${maxSizeMB}MB`);
|
||||
return false;
|
||||
message.error(`图片大小不能超过 ${maxSizeMB}MB`)
|
||||
return false
|
||||
}
|
||||
|
||||
// 图片尺寸校验
|
||||
if (
|
||||
props.minWidth ||
|
||||
props.maxWidth ||
|
||||
props.minHeight ||
|
||||
props.maxHeight
|
||||
) {
|
||||
if (props.minWidth || props.maxWidth || props.minHeight || props.maxHeight) {
|
||||
try {
|
||||
const dimensions = await getImageDimensions(file);
|
||||
const { width, height } = dimensions;
|
||||
const dimensions = await getImageDimensions(file)
|
||||
const { width, height } = dimensions
|
||||
|
||||
if (props.minWidth && width < props.minWidth) {
|
||||
message.error(`图片宽度不能小于 ${props.minWidth}px`);
|
||||
return false;
|
||||
message.error(`图片宽度不能小于 ${props.minWidth}px`)
|
||||
return false
|
||||
}
|
||||
if (props.maxWidth && width > props.maxWidth) {
|
||||
message.error(`图片宽度不能大于 ${props.maxWidth}px`);
|
||||
return false;
|
||||
message.error(`图片宽度不能大于 ${props.maxWidth}px`)
|
||||
return false
|
||||
}
|
||||
if (props.minHeight && height < props.minHeight) {
|
||||
message.error(`图片高度不能小于 ${props.minHeight}px`);
|
||||
return false;
|
||||
message.error(`图片高度不能小于 ${props.minHeight}px`)
|
||||
return false
|
||||
}
|
||||
if (props.maxHeight && height > props.maxHeight) {
|
||||
message.error(`图片高度不能大于 ${props.maxHeight}px`);
|
||||
return false;
|
||||
message.error(`图片高度不能大于 ${props.maxHeight}px`)
|
||||
return false
|
||||
}
|
||||
} catch (error) {
|
||||
message.error("图片尺寸校验失败");
|
||||
return false;
|
||||
message.error('图片尺寸校验失败')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取图片尺寸
|
||||
const getImageDimensions = (file) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
const reader = new FileReader();
|
||||
const img = new Image()
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.onload = (e) => {
|
||||
img.src = e.target.result;
|
||||
img.src = e.target.result
|
||||
img.onload = () => {
|
||||
resolve({ width: img.width, height: img.height });
|
||||
};
|
||||
img.onerror = reject;
|
||||
};
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
};
|
||||
resolve({ width: img.width, height: img.height })
|
||||
}
|
||||
img.onerror = reject
|
||||
}
|
||||
reader.onerror = reject
|
||||
reader.readAsDataURL(file)
|
||||
})
|
||||
}
|
||||
|
||||
// 处理预览
|
||||
const handlePreview = async (file) => {
|
||||
if (!file.url && !file.preview) {
|
||||
file.preview = await getBase64(file.originFileObj);
|
||||
file.preview = await getBase64(file.originFileObj)
|
||||
}
|
||||
previewImage.value = file.url || file.preview;
|
||||
previewVisible.value = true;
|
||||
emit("preview", file);
|
||||
};
|
||||
previewImage.value = file.url || file.preview
|
||||
previewVisible.value = true
|
||||
emit('preview', file)
|
||||
}
|
||||
|
||||
// 获取Base64
|
||||
const getBase64 = (file) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => resolve(reader.result);
|
||||
reader.onerror = (error) => reject(error);
|
||||
});
|
||||
};
|
||||
const reader = new FileReader()
|
||||
reader.readAsDataURL(file)
|
||||
reader.onload = () => resolve(reader.result)
|
||||
reader.onerror = (error) => reject(error)
|
||||
})
|
||||
}
|
||||
|
||||
// 处理文件列表变化
|
||||
const handleChange = ({ fileList: newFileList }) => {
|
||||
// 更新文件列表,确保上传成功的文件有正确的 url
|
||||
const updatedFileList = newFileList.map((file) => {
|
||||
// 如果文件上传成功且有响应数据但没有 url,则设置 url
|
||||
if (file.status === "done" && file.response?.src && !file.url) {
|
||||
if (file.status === 'done' && file.response?.src && !file.url) {
|
||||
return {
|
||||
...file,
|
||||
url: file.response.src,
|
||||
};
|
||||
}
|
||||
}
|
||||
return file;
|
||||
});
|
||||
return file
|
||||
})
|
||||
|
||||
fileList.value = updatedFileList;
|
||||
fileList.value = updatedFileList
|
||||
|
||||
// 过滤掉失败的文件
|
||||
const validFileList = updatedFileList.filter(
|
||||
(file) => file.status !== "error",
|
||||
);
|
||||
const validFileList = updatedFileList.filter((file) => file.status !== 'error')
|
||||
|
||||
// 提取成功的文件URL
|
||||
const successFiles = validFileList
|
||||
.filter(
|
||||
(file) =>
|
||||
file.status === "done" && (file.url || file.response?.src),
|
||||
)
|
||||
.map((file) => file.url || file.response?.src);
|
||||
const successFiles = validFileList.filter((file) => file.status === 'done' && (file.url || file.response?.src)).map((file) => file.url || file.response?.src)
|
||||
|
||||
// 触发更新事件
|
||||
if (props.returnUrl) {
|
||||
// 返回URL字符串或数组
|
||||
const value =
|
||||
props.maxCount === 1 ? successFiles[0] || "" : successFiles;
|
||||
emit("update:modelValue", value);
|
||||
emit("change", value, validFileList);
|
||||
const value = props.maxCount === 1 ? successFiles[0] || '' : successFiles
|
||||
emit('update:modelValue', value)
|
||||
emit('change', value, validFileList)
|
||||
} else {
|
||||
// 返回完整文件列表
|
||||
emit("update:modelValue", validFileList);
|
||||
emit("change", validFileList);
|
||||
emit('update:modelValue', validFileList)
|
||||
emit('change', validFileList)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 拖拽相关
|
||||
const handleDragEnter = (e) => {
|
||||
e.preventDefault();
|
||||
isDragOver.value = true;
|
||||
};
|
||||
e.preventDefault()
|
||||
isDragOver.value = true
|
||||
}
|
||||
|
||||
const handleDragLeave = (e) => {
|
||||
e.preventDefault();
|
||||
isDragOver.value = false;
|
||||
};
|
||||
e.preventDefault()
|
||||
isDragOver.value = false
|
||||
}
|
||||
|
||||
const handleDrop = (e) => {
|
||||
e.preventDefault();
|
||||
isDragOver.value = false;
|
||||
};
|
||||
e.preventDefault()
|
||||
isDragOver.value = false
|
||||
}
|
||||
|
||||
// 取消预览
|
||||
const handleCancel = () => {
|
||||
previewVisible.value = false;
|
||||
};
|
||||
previewVisible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user