feat:新增快递归还相关接口
This commit is contained in:
@@ -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
@@ -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);
|
uni.redirectTo({
|
||||||
console.log(res.data.orderStatus);
|
url: `/pages/waiting/index?orderNo=${order.orderNo}&deviceId=${deviceId.value}`
|
||||||
if (res.data.orderStatus == 'in_used') {
|
});
|
||||||
// 用户完成了支付流程,可以查询订单状态或跳转到订单页
|
return;
|
||||||
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)
|
|
||||||
|
|
||||||
}
|
|
||||||
// 用户取消等其他情况,不做特殊处理
|
|
||||||
}
|
}
|
||||||
// 用户取消等其他情况,不做特殊处理
|
// 用户取消等其他情况,不做特殊处理
|
||||||
} catch (payError) {
|
} catch (payError) {
|
||||||
|
|||||||
@@ -45,11 +45,17 @@
|
|||||||
import {
|
import {
|
||||||
onLoad
|
onLoad
|
||||||
} from '@dcloudio/uni-app'
|
} from '@dcloudio/uni-app'
|
||||||
import {
|
import {
|
||||||
queryById
|
queryById,
|
||||||
} from '@/config/user.js'
|
applyExpressReturn,
|
||||||
|
getExpressReturnByOrder,
|
||||||
|
getExpressReturnDetail,
|
||||||
|
fillExpressTrackingNumber
|
||||||
|
} 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'
|
||||||
@@ -120,38 +186,32 @@
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
if (!validate()) return
|
if (!validate()) return
|
||||||
// 这里保留与后端联调位置(未给出具体提交接口,先本地成功提示)
|
try {
|
||||||
try {
|
uni.showLoading({ title: isFillMode.value ? '补填中' : '提交中' })
|
||||||
uni.showLoading({
|
let res
|
||||||
title: '提交中'
|
if (isFillMode.value) {
|
||||||
})
|
res = await fillExpressTrackingNumber({ id: Number(recordId.value), logisticsTrackingNumber: trackingNumber.value })
|
||||||
|
} else {
|
||||||
// 示例:
|
res = await applyExpressReturn({
|
||||||
// await uni.request({
|
orderId: Number(orderId.value),
|
||||||
// url: `${URL}/app/express-return/submit`,
|
logisticsTrackingNumber: trackingNumber.value,
|
||||||
// method: 'POST',
|
remark: ''
|
||||||
// header: { 'Authorization': `Bearer ${uni.getStorageSync('token')}` },
|
})
|
||||||
// data: { orderId: orderId.value, phone: phone.value, trackingNumber: trackingNumber.value }
|
}
|
||||||
// })
|
if (res && res.code === 200) {
|
||||||
await new Promise(r => setTimeout(r, 500))
|
uni.showToast({ title: isFillMode.value ? '补填成功' : '提交成功', icon: 'success' })
|
||||||
uni.showToast({
|
setTimeout(() => { uni.navigateBack() }, 800)
|
||||||
title: '提交成功',
|
} else {
|
||||||
icon: 'success'
|
throw new Error(res?.msg || (isFillMode.value ? '补填失败' : '提交失败'))
|
||||||
})
|
}
|
||||||
setTimeout(() => {
|
} catch (e) {
|
||||||
uni.navigateBack()
|
uni.showToast({ title: e.message || (isFillMode.value ? '补填失败' : '提交失败'), icon: 'none' })
|
||||||
}, 800)
|
} finally {
|
||||||
} catch (e) {
|
uni.hideLoading()
|
||||||
uni.showToast({
|
}
|
||||||
title: e.message || '提交失败',
|
}
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
uni.hideLoading()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -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
|
||||||
|
try {
|
||||||
if (options.id) {
|
uni.showLoading({ title: '加载中' })
|
||||||
// 根据ID获取详情数据
|
const res = await getExpressReturnDetail(options.id)
|
||||||
console.log('获取详情数据,ID:', options.id)
|
if (res && res.code === 200 && res.data) {
|
||||||
// 这里可以调用API获取详情数据
|
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">
|
||||||
|
|||||||
@@ -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',
|
|
||||||
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 loadList = async () => {
|
||||||
const getStatusClass = (status) => {
|
try {
|
||||||
const statusMap = {
|
loading.value = true
|
||||||
'completed': 'status-completed',
|
const res = await getExpressReturnList(query.value)
|
||||||
'processing': 'status-processing',
|
if (res && res.code === 200) {
|
||||||
'pending': 'status-pending'
|
// 将后端字段映射到前端展示字段
|
||||||
}
|
const rows = (res.data && (res.data.rows || res.data)) || []
|
||||||
return statusMap[status] || 'status-pending'
|
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 mapStatus = (status) => {
|
||||||
const iconMap = {
|
// 文档:0-未填写 1-已填写 2-已取消 3-审批通过 4-审批拒绝 5-订单完成
|
||||||
'completed': '✓',
|
if (status === 5) return 'completed'
|
||||||
'processing': '⏳',
|
if (status === 3 || status === 1) return 'processing'
|
||||||
'pending': '⏸'
|
if (status === 4 || status === 2 || status === 0) return 'pending'
|
||||||
}
|
return 'pending'
|
||||||
return iconMap[status] || '⏸'
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 获取状态文本
|
const getStatusClass = (status) => ({
|
||||||
const getStatusText = (status) => {
|
'completed': 'status-completed',
|
||||||
const textMap = {
|
'processing': 'status-processing',
|
||||||
'completed': '已完成',
|
'pending': 'status-pending'
|
||||||
'processing': '处理中',
|
}[status] || 'status-pending')
|
||||||
'pending': '待处理'
|
|
||||||
}
|
|
||||||
return textMap[status] || '待处理'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 点击列表项
|
const getStatusIcon = (status) => ({
|
||||||
const handleItemClick = (item) => {
|
'completed': '✓',
|
||||||
|
'processing': '⏳',
|
||||||
|
'pending': '⏸'
|
||||||
|
}[status] || '⏸')
|
||||||
|
|
||||||
|
const getStatusText = (status) => ({
|
||||||
|
'completed': '已完成',
|
||||||
|
'processing': '处理中',
|
||||||
|
'pending': '待处理'
|
||||||
|
}[status] || '待处理')
|
||||||
|
|
||||||
|
// 点击列表项
|
||||||
|
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
@@ -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>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|||||||
Reference in New Issue
Block a user