feat: 新增确认送达弹框组件、添加安卓打包测试证书、骑手配送流程接口对接

This commit is contained in:
admin
2026-02-24 11:58:30 +08:00
parent b85833690f
commit bc1833ec89
25 changed files with 2982 additions and 1205 deletions

View File

@@ -0,0 +1,298 @@
<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>