Files
delivery-uniapp/pages/index/components/delivery-popup.vue

299 lines
5.6 KiB
Vue
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.
<template>
<u-popup :show="show" mode="bottom" :closeable="true" @close="onClose" :safeAreaInsetBottom="false" border-radius="16">
<view class="delivery-popup">
<!-- 标题 -->
<view class="popup-header">
<text class="popup-title">确认送达</text>
</view>
<!-- 内容区域 -->
<view class="popup-content">
<view class="upload-label">
<text class="required">*</text>
<text>上传送达照片</text>
</view>
<!-- 照片列表 -->
<up-upload
:fileList="photoList"
@afterRead="afterRead"
@delete="deleteUpload"
:maxCount="1"
:maxSize="5 * 1024 * 1024"
uploadText="上传照片"
:previewFullImage="true"
></up-upload>
</view>
<!-- 底部按钮 -->
<view class="popup-footer">
<view class="btn submit" @click="onSubmit">提交</view>
</view>
</view>
</u-popup>
</template>
<script setup>
import { ref, watch } from 'vue';
import sheep from '@/sheep';
import { baseUrl, apiPath } from '@/sheep/config';
const props = defineProps({
// 控制显示隐藏
show: {
type: Boolean,
default: false
}
});
const emit = defineEmits(['update:show', 'submit', 'close']);
// 照片列表 (用于 up-upload 组件)
const photoList = ref([])
// 监听弹框显示,重置数据
watch(() => props.show, (newVal) => {
if (newVal) {
photoList.value = [];
}
});
// 关闭弹框
function onClose() {
emit('update:show', false);
emit('close');
}
// 删除上传的图片
function deleteUpload(event) {
photoList.value.splice(event.index, 1);
}
// 上传单个文件到 OSS
async function uploadFile(filePath) {
const token = uni.getStorageSync('token');
return new Promise((resolve, reject) => {
uni.uploadFile({
url: baseUrl + apiPath + '/app/file/uploadOss', // 上传接口地址
header: {
'Authorization': token
},
filePath: filePath,
name: 'file',
success: (res) => {
if (res.statusCode === 200) {
try {
const data = JSON.parse(res.data);
if (data.code === 0 && data.data) {
resolve(data.data);
} else {
console.error('上传失败:', data.msg);
resolve(null);
}
} catch (e) {
console.error('解析上传响应失败:', e);
resolve(null);
}
} else {
console.error('上传失败:', res.statusCode);
resolve(null);
}
},
fail: (err) => {
console.error('上传请求失败:', err);
reject(err);
}
});
});
}
// 上传图片后的回调
async function afterRead(event) {
// 当设置 mutiple 为 true 时, event.file.list 为数组
const { file } = event;
// 如果是单选,转换为数组处理
const fileList = Array.isArray(file) ? file : [file];
for (const item of fileList) {
// 标记为上传中
photoList.value.push({
...item,
status: 'uploading',
message: '上传中'
});
}
// 依次上传文件
for (let i = 0; i < fileList.length; i++) {
const item = fileList[i];
const index = photoList.value.findIndex(f => f.url === item.url);
try {
const url = await uploadFile(item.url);
if (url) {
// 上传成功,更新状态
photoList.value[index] = {
...photoList.value[index],
status: 'success',
message: ''
};
} else {
// 上传失败
photoList.value[index] = {
...photoList.value[index],
status: 'failed',
message: '上传失败'
};
}
} catch (error) {
console.error('上传图片异常:', error);
photoList.value[index] = {
...photoList.value[index],
status: 'failed',
message: '上传失败'
};
}
}
}
// 提交
async function onSubmit() {
if (photoList.value.length === 0) {
uni.showToast({
title: '请上传送达照片',
icon: 'none'
});
return;
}
// 查找上传成功的照片
const uploadedPhoto = photoList.value.find(p => p.status === 'success');
if (!uploadedPhoto) {
uni.showToast({
title: '照片上传中,请稍候',
icon: 'none'
});
return;
}
// 提交成功,返回上传后的 URL
emit('submit', uploadedPhoto.url);
onClose();
}
</script>
<style scoped lang="scss">
.delivery-popup {
padding: 30rpx;
padding-bottom: calc(30rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(30rpx + env(safe-area-inset-bottom));
}
.popup-header {
text-align: center;
padding-bottom: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.popup-title {
font-size: 34rpx;
font-weight: 600;
color: #333;
}
.popup-content {
padding: 30rpx 0;
}
.upload-label {
display: flex;
align-items: center;
font-size: 28rpx;
color: #333;
margin-bottom: 24rpx;
}
.required {
color: #f5222d;
margin-right: 4rpx;
}
.photo-list {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.photo-item {
position: relative;
width: 180rpx;
height: 180rpx;
border-radius: 12rpx;
overflow: hidden;
}
.photo-preview {
width: 100%;
height: 100%;
border-radius: 12rpx;
}
.photo-delete {
position: absolute;
top: 10rpx;
right: 10rpx;
width: 40rpx;
height: 40rpx;
background: rgba(0, 0, 0, 0.5);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.delete-icon {
color: #fff;
font-size: 32rpx;
line-height: 1;
}
.photo-add {
width: 180rpx;
height: 180rpx;
background: #f5f5f5;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
border: 2rpx dashed #ddd;
}
.add-icon {
font-size: 72rpx;
color: #999;
font-weight: 300;
}
.popup-footer {
margin-top: 40rpx;
}
.btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
text-align: center;
border-radius: 12rpx;
font-size: 32rpx;
font-weight: 500;
}
.btn.submit {
background: #1e9fff;
color: #fff;
}
</style>