<template>
|
<div class="photo-capture">
|
<div v-if="modelValue" class="photo-box">
|
<el-image :src="modelValue" :preview-src-list="[modelValue]" fit="cover" class="photo-img" />
|
<div class="photo-remove" @click.stop="remove">
|
<el-icon><Close /></el-icon>
|
</div>
|
</div>
|
<div v-else class="photo-box photo-empty" @click="pick">
|
<el-icon class="photo-icon"><Camera /></el-icon>
|
<span class="photo-text">{{ placeholder }}</span>
|
</div>
|
<input
|
ref="inputRef"
|
type="file"
|
accept="image/*"
|
capture="environment"
|
class="photo-input"
|
@change="onChange"
|
/>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref } from "vue";
|
import axios from "axios";
|
import { ElMessage } from "element-plus";
|
import { Camera, Close } from "@element-plus/icons-vue";
|
import { getToken } from "@/utils/auth";
|
|
defineOptions({ name: "PhotoCapture" });
|
|
const props = defineProps({
|
modelValue: { type: String, default: "" },
|
placeholder: { type: String, default: "拍照 / 上传" },
|
});
|
|
const emit = defineEmits(["update:modelValue"]);
|
|
const inputRef = ref();
|
const loading = ref(false);
|
const MAX_SIZE = 10 * 1024 * 1024;
|
|
const pick = () => {
|
if (loading.value) return;
|
inputRef.value && inputRef.value.click();
|
};
|
|
const remove = () => {
|
emit("update:modelValue", "");
|
};
|
|
const onChange = async (e) => {
|
const file = e.target.files && e.target.files[0];
|
e.target.value = "";
|
if (!file) return;
|
if (!/^image\//.test(file.type)) {
|
ElMessage.warning("请选择图片文件");
|
return;
|
}
|
if (file.size > MAX_SIZE) {
|
ElMessage.warning("图片不能超过 10MB,请压缩后重试");
|
return;
|
}
|
loading.value = true;
|
try {
|
const fd = new FormData();
|
fd.append("file", file);
|
const res = await axios.post(import.meta.env.VITE_APP_BASE_API + "/common/upload", fd, {
|
headers: {
|
Authorization: "Bearer " + getToken(),
|
"Content-Type": "multipart/form-data",
|
},
|
});
|
const body = res && res.data;
|
if (body && body.code === 200) {
|
emit("update:modelValue", body.url || body.fileName || "");
|
ElMessage.success("上传成功");
|
} else {
|
ElMessage.error((body && body.msg) || "上传失败");
|
}
|
} catch (err) {
|
ElMessage.error("上传失败,请检查网络后重试");
|
} finally {
|
loading.value = false;
|
}
|
};
|
</script>
|
|
<style scoped lang="scss">
|
.photo-capture {
|
width: 100%;
|
}
|
.photo-box {
|
position: relative;
|
width: 100%;
|
height: 140px;
|
border-radius: 6px;
|
overflow: hidden;
|
border: 1px solid #dcdfe6;
|
background: #fafafa;
|
box-sizing: border-box;
|
}
|
.photo-empty {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
border-style: dashed;
|
cursor: pointer;
|
color: #909399;
|
|
&:active {
|
background: #f0f2f5;
|
}
|
}
|
.photo-icon {
|
font-size: 30px;
|
margin-bottom: 6px;
|
}
|
.photo-text {
|
font-size: 13px;
|
}
|
.photo-img {
|
width: 100%;
|
height: 140px;
|
display: block;
|
}
|
.photo-remove {
|
position: absolute;
|
top: 4px;
|
right: 4px;
|
width: 24px;
|
height: 24px;
|
border-radius: 50%;
|
background: rgba(0, 0, 0, 0.55);
|
color: #fff;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
cursor: pointer;
|
font-size: 13px;
|
}
|
.photo-input {
|
display: none;
|
}
|
</style>
|