feat:新增快递归还相关接口

This commit is contained in:
2025-10-08 03:15:30 +08:00
parent 6aba65a856
commit a67030ec43
6 changed files with 289 additions and 152 deletions
+68
View File
@@ -238,3 +238,71 @@ export const uploadOssResource = (filePath) => {
}) })
}) })
} }
// 获取系统配置(预留接口)
// 期望后端返回形如:{ code: 200, data: { expressReturnCountdownSeconds: number } }
export const getSystemConfig = () => {
return request({
url: '/app/system/config',
method: 'get',
hideLoading: true
})
}
// ===================== 快递归还相关接口 =====================
// 1) 申请快递归还
export const applyExpressReturn = (data) => {
// data: { orderId: number, logisticsTrackingNumber?: string, remark?: string }
return request({
url: '/app/express-return/apply',
method: 'post',
data
})
}
// 2) 补填快递单号
export const fillExpressTrackingNumber = (data) => {
// data: { id: number, logisticsTrackingNumber: string }
return request({
url: '/app/express-return/fill-tracking-number',
method: 'post',
data
})
}
// 3) 查询快递归还记录列表
export const getExpressReturnList = (params) => {
// params: { orderId?: number, status?: number, logisticsTrackingNumber?: string, pageNum?: number, pageSize?: number }
return request({
url: '/app/express-return/list',
method: 'get',
data: params,
hideLoading: true
})
}
// 4) 根据订单ID查询快递归还记录
export const getExpressReturnByOrder = (orderId) => {
return request({
url: `/app/express-return/by-order/${orderId}`,
method: 'get',
hideLoading: true
})
}
// 5) 获取快递归还记录详情
export const getExpressReturnDetail = (id) => {
return request({
url: `/app/express-return/${id}`,
method: 'get',
hideLoading: true
})
}
// 6) 取消快递归还申请
export const cancelExpressReturn = (id) => {
return request({
url: `/app/express-return/cancel/${id}`,
method: 'post'
})
}
+3 -32
View File
@@ -500,41 +500,12 @@
try { try {
// 调用微信支付分小程序 // 调用微信支付分小程序
const payResult = await initiateWeChatScorePayment(res); const payResult = await initiateWeChatScorePayment(res);
// 支付成功后的逻辑处理 - 可以根据业务需求决定是否跳转或刷新页面 // 成功则跳转等待页,轮询在等待页处理
if (payResult.errCode == '0') { if (payResult.errCode == '0') {
const res = await getOrderByOrderNoScorePayStatus(order.orderNo);
console.log(res.data.orderStatus);
if (res.data.orderStatus == 'in_used') {
// 用户完成了支付流程,可以查询订单状态或跳转到订单页
uni.showToast({
title: '设备租借成功',
icon: 'success'
});
setTimeout(() => {
// 延迟跳转到租用中页面或订单页
uni.redirectTo({ uni.redirectTo({
url: '/pages/order/index' url: `/pages/waiting/index?orderNo=${order.orderNo}&deviceId=${deviceId.value}`
}); });
}, 1500); return;
} else if (res.data.orderStatus == 'waiting_for_payment') {
uni.showToast({
title: '设备租借失败,订单已取消',
icon: 'error'
});
await cancelOrder({
orderId: order.orderNo
});
// 延迟跳转到租用中页面或订单页
setTimeout(() => {
uni.switchTab({
url: '/pages/index/index'
});
}, 1500)
}
// 用户取消等其他情况,不做特殊处理
} }
// 用户取消等其他情况,不做特殊处理 // 用户取消等其他情况,不做特殊处理
} catch (payError) { } catch (payError) {
+85 -25
View File
@@ -46,10 +46,16 @@
onLoad onLoad
} from '@dcloudio/uni-app' } from '@dcloudio/uni-app'
import { import {
queryById queryById,
applyExpressReturn,
getExpressReturnByOrder,
getExpressReturnDetail,
fillExpressTrackingNumber
} from '@/config/user.js' } from '@/config/user.js'
const orderId = ref('') const orderId = ref('')
const recordId = ref('')
const isFillMode = ref(false)
const orderInfo = reactive({ const orderInfo = reactive({
orderNo: '', orderNo: '',
deviceNo: '', deviceNo: '',
@@ -62,6 +68,14 @@
onLoad(async (options) => { onLoad(async (options) => {
orderId.value = options?.orderId || '' orderId.value = options?.orderId || ''
recordId.value = options?.id || ''
isFillMode.value = !!recordId.value
if (isFillMode.value) {
await loadRecordAndOrderByRecord()
return
}
if (!orderId.value) { if (!orderId.value) {
uni.showToast({ uni.showToast({
title: '缺少订单号', title: '缺少订单号',
@@ -73,6 +87,7 @@
return return
} }
await loadOrder() await loadOrder()
await checkExistingExpressReturn()
}) })
const loadOrder = async () => { const loadOrder = async () => {
@@ -100,6 +115,57 @@
} }
} }
const loadRecordAndOrderByRecord = async () => {
try {
uni.showLoading({ title: '加载中' })
const res = await getExpressReturnDetail(recordId.value)
if (res?.code === 200 && res.data) {
if (res.data.orderId) {
orderId.value = res.data.orderId
await loadOrder()
}
if (res.data.userPhone && !phone.value) phone.value = res.data.userPhone
} else {
throw new Error(res?.msg || '获取记录失败')
}
} catch (e) {
uni.showToast({ title: e.message || '加载失败', icon: 'none' })
} finally {
uni.hideLoading()
}
}
const checkExistingExpressReturn = async () => {
try {
const res = await getExpressReturnByOrder(orderId.value)
if (res && res.code === 200 && res.data) {
const rec = res.data
if (rec.status === 0) {
recordId.value = rec.id
uni.showModal({
title: '提示',
content: '已存在快递归还申请,是否前往补填快递单号?',
confirmText: '去补填',
cancelText: '取消',
success: (r) => {
if (r.confirm) {
uni.redirectTo({ url: `/pages/expressReturn/addExpressReturn?id=${rec.id}` })
}
}
})
return
} else {
uni.showToast({ title: '已有归还记录', icon: 'none' })
setTimeout(() => {
uni.redirectTo({ url: `/pages/expressReturn/detail?id=${rec.id}` })
}, 800)
}
}
} catch (e) {
// 无记录则忽略
}
}
const validate = () => { const validate = () => {
// 简单手机检查(兼容座机/国际号,放宽到至少 5 位数字) // 简单手机检查(兼容座机/国际号,放宽到至少 5 位数字)
const digits = (phone.value || '').replace(/\D/g, '') const digits = (phone.value || '').replace(/\D/g, '')
@@ -110,7 +176,7 @@
}) })
return false return false
} }
if (!trackingNumber.value) { if (isFillMode.value && !trackingNumber.value) {
uni.showToast({ uni.showToast({
title: '请填写快递单号', title: '请填写快递单号',
icon: 'none' icon: 'none'
@@ -122,32 +188,26 @@
const handleSubmit = async () => { const handleSubmit = async () => {
if (!validate()) return if (!validate()) return
// 这里保留与后端联调位置(未给出具体提交接口,先本地成功提示)
try { try {
uni.showLoading({ uni.showLoading({ title: isFillMode.value ? '补填中' : '提交中' })
title: '提交中' let res
if (isFillMode.value) {
res = await fillExpressTrackingNumber({ id: Number(recordId.value), logisticsTrackingNumber: trackingNumber.value })
} else {
res = await applyExpressReturn({
orderId: Number(orderId.value),
logisticsTrackingNumber: trackingNumber.value,
remark: ''
}) })
}
// 示例: if (res && res.code === 200) {
// await uni.request({ uni.showToast({ title: isFillMode.value ? '补填成功' : '提交成功', icon: 'success' })
// url: `${URL}/app/express-return/submit`, setTimeout(() => { uni.navigateBack() }, 800)
// method: 'POST', } else {
// header: { 'Authorization': `Bearer ${uni.getStorageSync('token')}` }, throw new Error(res?.msg || (isFillMode.value ? '补填失败' : '提交失败'))
// data: { orderId: orderId.value, phone: phone.value, trackingNumber: trackingNumber.value } }
// })
await new Promise(r => setTimeout(r, 500))
uni.showToast({
title: '提交成功',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack()
}, 800)
} catch (e) { } catch (e) {
uni.showToast({ uni.showToast({ title: e.message || (isFillMode.value ? '补填失败' : '提交失败'), icon: 'none' })
title: e.message || '提交失败',
icon: 'none'
})
} finally { } finally {
uni.hideLoading() uni.hideLoading()
} }
+48 -19
View File
@@ -87,20 +87,21 @@
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { getExpressReturnDetail } from '@/config/user.js'
// 详情数据 // 详情数据
const detailData = ref({ const detailData = ref({
id: 1, id: '',
expressCompany: '顺丰速运', expressCompany: '-',
trackingNumber: 'SF1234567890123', trackingNumber: '-',
returnAddress: '北京市朝阳区建国门外大街1号', returnAddress: '-',
returnTime: '2024-01-15 14:30:00', returnTime: '-',
processTime: '2024-01-15 15:00:00', processTime: '-',
completeTime: '2024-01-15 16:30:00', completeTime: '-',
packageType: '文件', packageType: '-',
weight: '0.5kg', weight: '-',
status: 'completed', status: 'pending',
remark: '包裹已安全送达,感谢您的使用!' remark: ''
}) })
// 获取状态样式类 // 获取状态样式类
@@ -174,18 +175,46 @@ const handleContactService = () => {
} }
// 页面加载时获取详情数据 // 页面加载时获取详情数据
onMounted(() => { onMounted(async () => {
// 这里可以根据路由参数获取详情数据
const pages = getCurrentPages() const pages = getCurrentPages()
const currentPage = pages[pages.length - 1] const currentPage = pages[pages.length - 1]
const options = currentPage.options const options = currentPage.options || {}
if (!options.id) return
if (options.id) { try {
// 根据ID获取详情数据 uni.showLoading({ title: '加载中' })
console.log('获取详情数据,ID:', options.id) const res = await getExpressReturnDetail(options.id)
// 这里可以调用API获取详情数据 if (res && res.code === 200 && res.data) {
const r = res.data
detailData.value = {
id: r.id,
expressCompany: r.expressCompany || r.company || '-',
trackingNumber: r.logisticsTrackingNumber || r.trackingNumber || '-',
returnAddress: r.returnAddress || r.address || '-',
returnTime: r.createTime || r.returnTime || '-',
processTime: r.processTime || '-',
completeTime: r.completeTime || '-',
packageType: r.packageType || '-',
weight: r.weight || '-',
status: mapStatus(r.status),
remark: r.remark || ''
}
} else {
throw new Error(res?.msg || '获取详情失败')
}
} catch (e) {
uni.showToast({ title: e.message || '加载失败', icon: 'none' })
} finally {
uni.hideLoading()
} }
}) })
// 状态映射
const mapStatus = (status) => {
if (status === 5) return 'completed'
if (status === 3 || status === 1) return 'processing'
if (status === 4 || status === 2 || status === 0) return 'pending'
return 'pending'
}
</script> </script>
<style lang="scss"> <style lang="scss">
+55 -46
View File
@@ -49,71 +49,80 @@
</template> </template>
<script setup> <script setup>
import { import { ref, onMounted } from 'vue'
ref import { getExpressReturnList } from '@/config/user.js'
} from 'vue'
// 模拟数据 const returnList = ref([])
const returnList = ref([{ const loading = ref(false)
id: 1, const query = ref({ pageNum: 1, pageSize: 20 })
expressCompany: '顺丰速运',
trackingNumber: 'SF1234567890123', const loadList = async () => {
returnAddress: '北京市朝阳区建国门外大街1号', try {
returnTime: '2024-01-15 14:30:00', loading.value = true
packageType: '文件', const res = await getExpressReturnList(query.value)
weight: '0.5kg', if (res && res.code === 200) {
status: 'completed' // 将后端字段映射到前端展示字段
}, const rows = (res.data && (res.data.rows || res.data)) || []
{ returnList.value = rows.map(r => ({
id: 2, id: r.id,
expressCompany: '圆通快递', expressCompany: r.expressCompany || r.company || '-',
trackingNumber: 'YT9876543210987', trackingNumber: r.logisticsTrackingNumber || r.trackingNumber || '-',
returnAddress: '上海市浦东新区陆家嘴环路1000号', returnAddress: r.returnAddress || r.address || '-',
returnTime: '2024-01-14 09:15:00', returnTime: r.createTime || r.returnTime || '-',
packageType: '电子产品', packageType: r.packageType || '-',
weight: '2.1kg', weight: r.weight || '-',
status: 'processing' status: mapStatus(r.status),
rawStatus: r.status
}))
} else {
throw new Error(res?.msg || '获取列表失败')
}
} catch (e) {
uni.showToast({ title: e.message || '加载失败', icon: 'none' })
} finally {
loading.value = false
}
} }
])
// 获取状态样式类 // 状态映射
const getStatusClass = (status) => { const mapStatus = (status) => {
const statusMap = { // 文档:0-未填写 1-已填写 2-已取消 3-审批通过 4-审批拒绝 5-订单完成
if (status === 5) return 'completed'
if (status === 3 || status === 1) return 'processing'
if (status === 4 || status === 2 || status === 0) return 'pending'
return 'pending'
}
const getStatusClass = (status) => ({
'completed': 'status-completed', 'completed': 'status-completed',
'processing': 'status-processing', 'processing': 'status-processing',
'pending': 'status-pending' 'pending': 'status-pending'
} }[status] || 'status-pending')
return statusMap[status] || 'status-pending'
}
// 获取状态图标 const getStatusIcon = (status) => ({
const getStatusIcon = (status) => {
const iconMap = {
'completed': '✓', 'completed': '✓',
'processing': '⏳', 'processing': '⏳',
'pending': '⏸' 'pending': '⏸'
} }[status] || '⏸')
return iconMap[status] || '⏸'
}
// 获取状态文本 const getStatusText = (status) => ({
const getStatusText = (status) => {
const textMap = {
'completed': '已完成', 'completed': '已完成',
'processing': '处理中', 'processing': '处理中',
'pending': '待处理' 'pending': '待处理'
} }[status] || '待处理')
return textMap[status] || '待处理'
}
// 点击列表项 // 点击列表项
const handleItemClick = (item) => { const handleItemClick = (item) => {
console.log('点击了归还记录:', item) console.log('点击了归还记录:', item)
// 跳转到详情页面 // 未填写(status=0 -> mapped 'pending')时跳转到补填页,其它跳详情
uni.navigateTo({ if (item && item.rawStatus === 0) {
url: `/pages/expressReturn/detail?id=${item.id}` uni.navigateTo({ url: `/pages/expressReturn/addExpressReturn?id=${item.id}` })
}) } else {
uni.navigateTo({ url: `/pages/expressReturn/detail?id=${item.id}` })
} }
}
onMounted(loadList)
</script> </script>
<style lang="scss"> <style lang="scss">
+2 -2
View File
@@ -77,7 +77,7 @@
<uni-icons type="right" size="16" color="#999"></uni-icons> <uni-icons type="right" size="16" color="#999"></uni-icons>
</view> </view>
</view> </view>
<!-- <view class="function-item" @click="navigateTo('/pages/expressReturn/index')"> <view class="function-item" @click="navigateTo('/pages/expressReturn/index')">
<view class="item-left"> <view class="item-left">
<view class="item-icon"> <view class="item-icon">
<image src="/static/express.png" mode="aspectFit"></image> <image src="/static/express.png" mode="aspectFit"></image>
@@ -87,7 +87,7 @@
<view class="item-right"> <view class="item-right">
<uni-icons type="right" size="16" color="#999"></uni-icons> <uni-icons type="right" size="16" color="#999"></uni-icons>
</view> </view>
</view> --> </view>
</view> </view>
<!-- <!--