campus-errand/miniapp/pages/delivery/delivery.vue
18631081161 58b34666bd
All checks were successful
continuous-integration/drone/push Build is passing
佣金
2026-03-30 15:29:56 +08:00

337 lines
8.5 KiB
Vue

<template>
<view class="order-page">
<!-- 自定义导航栏 -->
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="navbar-content">
<view class="nav-back" @click="goBack">
<image class="back-icon" src="/static/ic_back.png" mode="aspectFit"></image>
</view>
<text class="navbar-title">代送</text>
<view class="nav-placeholder"></view>
</view>
</view>
<view :style="{ height: (statusBarHeight + 44) + 'px' }"></view>
<!-- 顶部大图 -->
<view class="top-banner" v-if="bannerUrl">
<image class="banner-img" :src="bannerUrl" mode="aspectFill"></image>
</view>
<!-- 表单区域 -->
<view class="form-section">
<!-- 1.代送物品 -->
<view class="form-group">
<text class="form-label">1.代送物品</text>
<view class="input-box">
<input v-model="form.itemName" placeholder="请输入要代送的物品名" placeholder-class="placeholder" />
</view>
</view>
<!-- 2.取货地点 -->
<view class="form-group">
<text class="form-label">2.取货地点</text>
<view class="input-box">
<input v-model="form.pickupLocation" placeholder="请输入取货地点" placeholder-class="placeholder" />
</view>
</view>
<!-- 3.送达地点 -->
<view class="form-group">
<text class="form-label">3.送达地点</text>
<view class="input-box">
<input v-model="form.deliveryLocation" placeholder="请输入送达地点" placeholder-class="placeholder" />
</view>
</view>
<!-- 4.备注信息 -->
<view class="form-group">
<text class="form-label">4.备注信息</text>
<view class="input-box textarea-box">
<textarea v-model="form.remark" placeholder="请输入备注信息,如注意事项等" placeholder-class="placeholder" :maxlength="200" />
</view>
</view>
<!-- 5.如何联系您 -->
<view class="form-group">
<text class="form-label">5.如何联系您?</text>
<view class="input-box">
<input v-model="form.phone" type="number" placeholder="请输入手机号,对方接单后才能看到" placeholder-class="placeholder" maxlength="11" />
</view>
</view>
<!-- 6.跑腿佣金 -->
<view class="form-group">
<text class="form-label">6.跑腿佣金</text>
<view class="input-box">
<input v-model="form.commission" type="digit" :placeholder="`请输入跑腿佣金,最低${minCommission}元`" placeholder-class="placeholder" />
</view>
<text class="form-tip">佣金先由平台保管,接单方完成订单后才会收到佣金</text>
</view>
</view>
<!-- 提交按钮 -->
<view class="submit-section">
<button class="submit-btn" @click="onSubmit" :loading="submitting" :disabled="submitting">
支付佣金 确定下单
</button>
</view>
</view>
</template>
<script>
import { createOrder, getPageBanner, getMinCommission } from '../../utils/api'
export default {
data() {
return {
statusBarHeight: 0,
bannerUrl: '',
form: {
itemName: '',
pickupLocation: '',
deliveryLocation: '',
remark: '',
phone: '',
commission: ''
},
submitting: false,
minCommission: 1.0
}
},
onLoad() {
const sysInfo = uni.getSystemInfoSync()
this.statusBarHeight = sysInfo.statusBarHeight || 0
this.loadBanner()
this.loadMinCommission()
this.restoreFormData()
},
methods: {
/** 恢复登录前保存的表单数据 */
restoreFormData() {
const saved = uni.getStorageSync('loginFormData')
if (saved) {
try {
const data = JSON.parse(saved)
Object.assign(this.form, data)
} catch (e) {}
uni.removeStorageSync('loginFormData')
}
},
goBack() { uni.navigateBack() },
async loadBanner() {
try {
const res = await getPageBanner('delivery')
if (res?.value) this.bannerUrl = res.value
} catch (e) {}
},
async loadMinCommission() {
try {
const res = await getMinCommission()
if (res?.value) this.minCommission = parseFloat(res.value) || 1.0
} catch (e) {}
},
validateCommission() {
const val = this.form.commission
if (!val) {
uni.showToast({ title: '请输入跑腿佣金', icon: 'none' }); return false
}
const num = parseFloat(val)
if (isNaN(num) || num < this.minCommission) {
uni.showToast({ title: `跑腿佣金不可低于${this.minCommission}`, icon: 'none' }); return false
}
if (val.includes('.') && val.split('.')[1].length > 1) {
uni.showToast({ title: '佣金最多支持小数点后1位', icon: 'none' }); return false
}
return true
},
validateForm() {
if (!this.form.itemName.trim()) {
uni.showToast({ title: '请输入代送物品', icon: 'none' }); return false
}
if (!this.form.pickupLocation.trim()) {
uni.showToast({ title: '请输入取货地点', icon: 'none' }); return false
}
if (!this.form.deliveryLocation.trim()) {
uni.showToast({ title: '请输入送达地点', icon: 'none' }); return false
}
if (!this.form.phone.trim()) {
uni.showToast({ title: '请输入手机号', icon: 'none' }); return false
}
if (!/^1\d{10}$/.test(this.form.phone.trim())) {
uni.showToast({ title: '请输入正确的11位手机号', icon: 'none' }); return false
}
return this.validateCommission()
},
async onSubmit() {
if (!this.validateForm()) return
const token = uni.getStorageSync('token')
if (!token) {
// 保存表单数据,登录后恢复
uni.setStorageSync('loginFormData', JSON.stringify(this.form))
uni.setStorageSync('loginRedirect', '/pages/delivery/delivery')
uni.navigateTo({ url: '/pages/login/login' }); return
}
this.submitting = true
try {
const commission = parseFloat(this.form.commission)
const result = await createOrder({
orderType: 'Delivery',
itemName: this.form.itemName.trim(),
pickupLocation: this.form.pickupLocation.trim(),
deliveryLocation: this.form.deliveryLocation.trim(),
remark: this.form.remark.trim(),
phone: this.form.phone.trim(),
commission,
totalAmount: commission
})
if (result.paymentParams) await this.wxPay(result.paymentParams)
uni.showToast({ title: '下单成功', icon: 'success' })
setTimeout(() => { uni.navigateBack() }, 1500)
} catch (e) {} finally { this.submitting = false }
},
wxPay(params) {
return new Promise((resolve, reject) => {
uni.requestPayment({
provider: 'wxpay',
timeStamp: params.timeStamp,
nonceStr: params.nonceStr,
package: params.package_,
signType: params.signType,
paySign: params.paySign,
success: resolve,
fail: (err) => {
if (err.errMsg !== 'requestPayment:fail cancel')
uni.showToast({ title: '支付失败', icon: 'none' })
reject(err)
}
})
})
}
}
}
</script>
<style scoped>
.order-page {
padding-bottom: 40rpx;
background-color: #f5f5f5;
min-height: 100vh;
}
/* 自定义导航栏 */
.custom-navbar {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 999;
background: #FFB700;
}
.navbar-content {
height: 44px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20rpx;
}
.nav-back {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
.back-icon {
width: 40rpx;
height: 40rpx;
}
.navbar-title {
font-size: 34rpx;
font-weight: bold;
color: #363636;
}
.nav-placeholder {
width: 60rpx;
}
/* 顶部大图 */
.top-banner {
width: 100%;
}
.banner-img {
width: 100%;
height: 330rpx;
}
/* 表单区域 */
.form-section {
padding: 10rpx 24rpx 0;
}
.form-group {
margin-bottom: 24rpx;
}
.form-label {
font-size: 30rpx;
color: #333333;
font-weight: bold;
display: block;
margin-bottom: 16rpx;
}
.input-box {
background-color: #ffffff;
border-radius: 16rpx;
padding: 0 24rpx;
height: 88rpx;
display: flex;
align-items: center;
}
.input-box input {
width: 100%;
height: 100%;
font-size: 28rpx;
color: #333;
}
.textarea-box {
height: 240rpx;
padding: 20rpx 24rpx;
align-items: flex-start;
}
.textarea-box textarea {
width: 100%;
height: 100%;
font-size: 28rpx;
color: #333;
}
.form-tip {
font-size: 24rpx;
color: #999999;
margin-top: 12rpx;
display: block;
text-align: center;
}
/* 提交按钮 */
.submit-section {
padding: 20rpx 24rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
}
.submit-btn {
width: 100%;
height: 96rpx;
line-height: 96rpx;
background: #FAD146;
color: #ffffff;
font-size: 32rpx;
font-weight: bold;
border-radius: 10rpx;
border: none;
text-align: center;
}
.submit-btn::after {
border: none;
}
.submit-btn[disabled] {
opacity: 0.6;
}
</style>