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'
})
}
+5 -34
View File
@@ -500,41 +500,12 @@
try {
// 调用微信支付分小程序
const payResult = await initiateWeChatScorePayment(res);
// 支付成功后的逻辑处理 - 可以根据业务需求决定是否跳转或刷新页面
// 成功则跳转等待页,轮询在等待页处理
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({
url: '/pages/order/index'
});
}, 1500);
} 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)
}
// 用户取消等其他情况,不做特殊处理
uni.redirectTo({
url: `/pages/waiting/index?orderNo=${order.orderNo}&deviceId=${deviceId.value}`
});
return;
}
// 用户取消等其他情况,不做特殊处理
} catch (payError) {
+96 -36
View File
@@ -45,11 +45,17 @@
import {
onLoad
} from '@dcloudio/uni-app'
import {
queryById
} from '@/config/user.js'
import {
queryById,
applyExpressReturn,
getExpressReturnByOrder,
getExpressReturnDetail,
fillExpressTrackingNumber
} from '@/config/user.js'
const orderId = ref('')
const recordId = ref('')
const isFillMode = ref(false)
const orderInfo = reactive({
orderNo: '',
deviceNo: '',
@@ -62,6 +68,14 @@
onLoad(async (options) => {
orderId.value = options?.orderId || ''
recordId.value = options?.id || ''
isFillMode.value = !!recordId.value
if (isFillMode.value) {
await loadRecordAndOrderByRecord()
return
}
if (!orderId.value) {
uni.showToast({
title: '缺少订单号',
@@ -73,6 +87,7 @@
return
}
await loadOrder()
await checkExistingExpressReturn()
})
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 = () => {
// 简单手机检查(兼容座机/国际号,放宽到至少 5 位数字)
const digits = (phone.value || '').replace(/\D/g, '')
@@ -110,7 +176,7 @@
})
return false
}
if (!trackingNumber.value) {
if (isFillMode.value && !trackingNumber.value) {
uni.showToast({
title: '请填写快递单号',
icon: 'none'
@@ -120,38 +186,32 @@
return true
}
const handleSubmit = async () => {
if (!validate()) return
// 这里保留与后端联调位置(未给出具体提交接口,先本地成功提示)
try {
uni.showLoading({
title: '提交中'
})
// 示例:
// await uni.request({
// url: `${URL}/app/express-return/submit`,
// method: 'POST',
// header: { 'Authorization': `Bearer ${uni.getStorageSync('token')}` },
// 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) {
uni.showToast({
title: e.message || '提交失败',
icon: 'none'
})
} finally {
uni.hideLoading()
}
}
const handleSubmit = async () => {
if (!validate()) return
try {
uni.showLoading({ title: isFillMode.value ? '补填中' : '提交中' })
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) {
uni.showToast({ title: isFillMode.value ? '补填成功' : '提交成功', icon: 'success' })
setTimeout(() => { uni.navigateBack() }, 800)
} else {
throw new Error(res?.msg || (isFillMode.value ? '补填失败' : '提交失败'))
}
} catch (e) {
uni.showToast({ title: e.message || (isFillMode.value ? '补填失败' : '提交失败'), icon: 'none' })
} finally {
uni.hideLoading()
}
}
</script>
<style lang="scss" scoped>
+51 -22
View File
@@ -87,20 +87,21 @@
<script setup>
import { ref, onMounted } from 'vue'
import { getExpressReturnDetail } from '@/config/user.js'
// 详情数据
const detailData = ref({
id: 1,
expressCompany: '顺丰速运',
trackingNumber: 'SF1234567890123',
returnAddress: '北京市朝阳区建国门外大街1号',
returnTime: '2024-01-15 14:30:00',
processTime: '2024-01-15 15:00:00',
completeTime: '2024-01-15 16:30:00',
packageType: '文件',
weight: '0.5kg',
status: 'completed',
remark: '包裹已安全送达,感谢您的使用!'
id: '',
expressCompany: '-',
trackingNumber: '-',
returnAddress: '-',
returnTime: '-',
processTime: '-',
completeTime: '-',
packageType: '-',
weight: '-',
status: 'pending',
remark: ''
})
// 获取状态样式类
@@ -174,18 +175,46 @@ const handleContactService = () => {
}
// 页面加载时获取详情数据
onMounted(() => {
// 这里可以根据路由参数获取详情数据
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const options = currentPage.options
if (options.id) {
// 根据ID获取详情数据
console.log('获取详情数据,ID:', options.id)
// 这里可以调用API获取详情数据
}
onMounted(async () => {
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const options = currentPage.options || {}
if (!options.id) return
try {
uni.showLoading({ title: '加载中' })
const res = await getExpressReturnDetail(options.id)
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>
<style lang="scss">
+67 -58
View File
@@ -49,71 +49,80 @@
</template>
<script setup>
import {
ref
} from 'vue'
import { ref, onMounted } from 'vue'
import { getExpressReturnList } from '@/config/user.js'
// 模拟数据
const returnList = ref([{
id: 1,
expressCompany: '顺丰速运',
trackingNumber: 'SF1234567890123',
returnAddress: '北京市朝阳区建国门外大街1号',
returnTime: '2024-01-15 14:30:00',
packageType: '文件',
weight: '0.5kg',
status: 'completed'
},
{
id: 2,
expressCompany: '圆通快递',
trackingNumber: 'YT9876543210987',
returnAddress: '上海市浦东新区陆家嘴环路1000号',
returnTime: '2024-01-14 09:15:00',
packageType: '电子产品',
weight: '2.1kg',
status: 'processing'
}
])
const returnList = ref([])
const loading = ref(false)
const query = ref({ pageNum: 1, pageSize: 20 })
// 获取状态样式类
const getStatusClass = (status) => {
const statusMap = {
'completed': 'status-completed',
'processing': 'status-processing',
'pending': 'status-pending'
}
return statusMap[status] || 'status-pending'
}
const loadList = async () => {
try {
loading.value = true
const res = await getExpressReturnList(query.value)
if (res && res.code === 200) {
// 将后端字段映射到前端展示字段
const rows = (res.data && (res.data.rows || res.data)) || []
returnList.value = rows.map(r => ({
id: r.id,
expressCompany: r.expressCompany || r.company || '-',
trackingNumber: r.logisticsTrackingNumber || r.trackingNumber || '-',
returnAddress: r.returnAddress || r.address || '-',
returnTime: r.createTime || r.returnTime || '-',
packageType: r.packageType || '-',
weight: r.weight || '-',
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 getStatusIcon = (status) => {
const iconMap = {
'completed': '✓',
'processing': '⏳',
'pending': '⏸'
}
return iconMap[status] || '⏸'
}
// 状态映射
const mapStatus = (status) => {
// 文档: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 getStatusText = (status) => {
const textMap = {
'completed': '已完成',
'processing': '处理中',
'pending': '待处理'
}
return textMap[status] || '待处理'
}
const getStatusClass = (status) => ({
'completed': 'status-completed',
'processing': 'status-processing',
'pending': 'status-pending'
}[status] || 'status-pending')
// 点击列表项
const handleItemClick = (item) => {
const getStatusIcon = (status) => ({
'completed': '✓',
'processing': '⏳',
'pending': '⏸'
}[status] || '⏸')
const getStatusText = (status) => ({
'completed': '已完成',
'processing': '处理中',
'pending': '待处理'
}[status] || '待处理')
// 点击列表项
const handleItemClick = (item) => {
console.log('点击了归还记录:', item)
// 跳转到详情页面
uni.navigateTo({
url: `/pages/expressReturn/detail?id=${item.id}`
})
// 未填写(status=0 -> mapped 'pending')时跳转到补填页,其它跳详情
if (item && item.rawStatus === 0) {
uni.navigateTo({ url: `/pages/expressReturn/addExpressReturn?id=${item.id}` })
} else {
uni.navigateTo({ url: `/pages/expressReturn/detail?id=${item.id}` })
}
}
onMounted(loadList)
</script>
<style lang="scss">
+2 -2
View File
@@ -77,7 +77,7 @@
<uni-icons type="right" size="16" color="#999"></uni-icons>
</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-icon">
<image src="/static/express.png" mode="aspectFit"></image>
@@ -87,7 +87,7 @@
<view class="item-right">
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
</view> -->
</view>
</view>
<!--