This commit is contained in:
2026-04-24 18:32:18 +08:00
parent 118b932b29
commit 9332db0198
3 changed files with 171 additions and 112 deletions

View File

@ -443,6 +443,18 @@ export function upImage(data) {
})
}
// 单个文件上传
export function uploadFile(file) {
const formData = new FormData()
formData.append('file', file)
return service({
url: '/common/upload',
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data' }
})
}
//根据身份证号查询涉疫登记信息
export function getRySydjInfo(data) {
return service({

View File

@ -0,0 +1,141 @@
<template>
<div class="file-uploader">
<van-uploader
:max-count="1"
:after-read="handleAfterRead"
:preview-size="previewSize"
:show-upload="!modelValue"
:disabled="uploading"
>
<slot v-if="!modelValue">
<div class="upload-placeholder" :style="{ width: previewSize + 'px', height: previewSize + 'px' }">
<van-icon name="photograph" class="upload-icon" />
<div class="upload-text">{{ uploading ? '上传中...' : placeholder }}</div>
</div>
</slot>
</van-uploader>
<div v-if="modelValue" class="preview-wrapper">
<van-image
:src="modelValue"
:preview-src-list="[modelValue]"
class="preview-image"
:width="previewSize"
:height="previewSize"
fit="cover"
radius="6"
preview
/>
<van-icon v-if="showDelete" name="cross" class="delete-btn" @click.stop="handleDelete" />
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Toast } from 'vant'
import { uploadFile } from '@/api/common'
const props = defineProps({
modelValue: { type: String, default: '' },
previewSize: { type: [Number, String], default: 100 },
placeholder: { type: String, default: '点击上传' },
showDelete: { type: Boolean, default: true }
})
const emit = defineEmits(['update:modelValue', 'success', 'error', 'delete'])
const uploading = ref(false)
async function handleAfterRead(file) {
uploading.value = true
try {
const fileObj = file.file
const res = await uploadFile(fileObj)
// 根据响应结构获取 URL请根据实际返回调整
const url = res? res.fileName : ''
if (url) {
emit('update:modelValue', url)
emit('success', url)
} else {
throw new Error('上传失败')
}
} catch (err) {
console.error('上传失败:', err)
Toast('上传失败,请重试')
emit('error', err)
} finally {
uploading.value = false
}
}
function handleDelete() {
emit('update:modelValue', '')
emit('delete')
}
</script>
<style lang="scss" scoped>
.file-uploader {
display: inline-block;
:deep(.van-uploader) {
display: block;
}
:deep(.van-uploader__wrapper) {
display: block;
}
:deep(.van-uploader__preview) {
margin: 0;
}
}
::v-deep .upload-placeholder {
background: #fff;
border: 1px dashed #d1d5db;
border-radius: 6px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
width: 135px !important;
height: 135px !important;
.upload-icon {
font-size: 28px;
color: #9ca3af;
}
.upload-text {
font-size: 12px;
color: #6b7280;
}
}
.preview-wrapper {
position: relative;
display: inline-block;
.preview-image {
display: block;
}
.delete-btn {
position: absolute;
top: -6px;
right: -6px;
width: 20px;
height: 20px;
background: rgba(0, 0, 0, 0.6);
border-radius: 50%;
color: #fff;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
}
</style>

View File

@ -89,15 +89,13 @@
<div class="photo-upload-list">
<div class="photo-upload-item" v-for="(photo, index) in photoList" :key="index">
<div style="text-align: left;">照片{{ index + 1 }}</div>
<van-uploader :max-count="1" :after-read="(file) => onPhotoRead(file, index)" :preview-size="200"
:show-upload="!photo.url">
<div class="photo-upload-content" v-if="!photo.url">
<van-icon name="photograph" class="photo-icon" />
<div class="photo-text">点击拍照/上传</div>
</div>
</van-uploader>
<van-image v-if="photo.url" :src="photo.url" :preview-src-list="[photo.url]" class="photo-preview-img" width="100" height="100" fit="cover" radius="6" preview/>
<van-icon v-if="photo.url" @click.stop="deletePhoto(index)" name="cross" class="photo-delete" />
<FileUploader
v-model="photo.url"
:preview-size="200"
placeholder="点击拍照/上传"
@success="(url) => onPhotoUploaded(url, index)"
@delete="onPhotoDelete(index)"
/>
<van-field v-model="photo.url" label="图片链接" placeholder="请输入图片链接" class="photo-link-field" />
</div>
</div>
@ -141,10 +139,10 @@
<script setup>
import PopupView from '@/components/popupView.vue'
import FileUploader from '@/components/FileUploader.vue'
import { ref, reactive, onMounted } from "vue";
import { useRouter } from "vue-router";
import { Toast } from "vant";
import { upImage } from "@/api/common";
import { addSsPai } from "@/api/traffic";
const isLoading = ref(false);
const router = useRouter();
@ -297,18 +295,18 @@ function toggleSection(key) {
openSections[key] = !openSections[key];
}
// 删除照片
function deletePhoto(index) {
photoList.value[index].url = "";
const uploadedCount = photoList.value.filter(p => p.url).length;
formData.zpsl = uploadedCount.toString();
// 照片上传成功回调
function onPhotoUploaded(url, index) {
photoList.value[index].url = url
const uploadedCount = photoList.value.filter(p => p.url).length
formData.zpsl = uploadedCount.toString()
}
// vant upload上传后处理
function onPhotoRead(file, index) {
photoList.value[index].url = file.content;
const uploadedCount = photoList.value.filter(p => p.url).length;
formData.zpsl = uploadedCount.toString();
// 照片删除回调
function onPhotoDelete(index) {
photoList.value[index].url = ""
const uploadedCount = photoList.value.filter(p => p.url).length
formData.zpsl = uploadedCount.toString()
}
// 返回上一页
@ -564,98 +562,6 @@ onMounted(() => {
border-radius: 8px;
border: 1px solid #e5e7eb;
:deep(.van-uploader) {
width: 100%;
}
:deep(.van-uploader__wrapper) {
display: block;
}
:deep(.van-uploader__preview) {
margin: 0;
}
:deep(.van-uploader__preview-image) {
width: 100%;
aspect-ratio: 3/1;
border-radius: 6px;
object-fit: cover;
}
:deep(.van-uploader__preview-delete) {
width: 18px;
height: 18px;
background: rgba(0, 0, 0, 0.6);
border-radius: 50%;
top: -6px;
right: -6px;
}
:deep(.van-uploader__upload) {
margin: 0;
width: 100%;
aspect-ratio: 3/1;
background: #fff;
border: 1px dashed #d1d5db;
border-radius: 6px;
}
:deep(.van-uploader__upload-icon) {
font-size: 28px;
color: #9ca3af;
}
:deep(.van-uploader__upload-text) {
font-size: 12px;
color: #6b7280;
}
.photo-upload-content {
width: 100%;
aspect-ratio: 3/1;
background: #fff;
border: 1px dashed #d1d5db;
border-radius: 6px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
.photo-icon {
font-size: 32px;
color: #9ca3af;
}
.photo-text {
font-size: 12px;
color: #6b7280;
}
}
.photo-preview-img {
width: 100px;
border-radius: 6px;
object-fit: cover;
}
.photo-delete {
position: absolute;
top: 8px;
right: 8px;
width: 20px;
height: 20px;
background: rgba(0, 0, 0, 0.6);
border-radius: 50%;
color: #fff;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.photo-label {
font-size: 13px;
color: #374151;