457 lines
12 KiB
Vue
457 lines
12 KiB
Vue
<template>
|
||
<view class="order-submit">
|
||
<!-- 自定义导航栏 -->
|
||
<view class="navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||
<view class="navbar__content" :style="{ height: navBarHeight + 'px' }">
|
||
<view class="navbar__back" @click="goBack">
|
||
<image src="/static/ic_back.png" class="navbar__back-icon" mode="aspectFit" />
|
||
</view>
|
||
<text class="navbar__title">订单提交</text>
|
||
<view class="navbar__placeholder"></view>
|
||
</view>
|
||
</view>
|
||
<view :style="{ height: (statusBarHeight + navBarHeight) + 'px' }"></view>
|
||
|
||
<!-- 公司地址 -->
|
||
<view class="address-section">
|
||
<view class="address-section__header">
|
||
<image src="/static/ic_address.png" class="address-section__icon" mode="aspectFit" />
|
||
<text class="address-section__title">公司地址</text>
|
||
</view>
|
||
<view class="address-section__content">
|
||
<text class="address-section__name">叶生珠宝-空托之城</text>
|
||
<text class="address-section__detail">广东省深圳市罗湖区水贝2路贝丽花园21栋108#生珠宝</text>
|
||
<text class="address-section__phone">15920028399</text>
|
||
<text class="address-section__contact">联系电话:空托之城 叶生15920028399</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 您的信息 -->
|
||
<view class="info-section">
|
||
<view class="info-section__header">
|
||
<image src="/static/ic_tip.png" class="info-section__icon" mode="aspectFit" />
|
||
<text class="info-section__title">您的信息</text>
|
||
<text class="info-section__subtitle">请留下您的联系方式</text>
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-item__label required">姓名</text>
|
||
<input class="form-item__input" v-model="receiverName" placeholder="请输入真实姓名" />
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-item__label required">电话</text>
|
||
<input class="form-item__input" v-model="receiverPhone" type="number" placeholder="请输入电话" />
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-item__label required">地址</text>
|
||
<input class="form-item__input" v-model="receiverAddress" placeholder="请输入收货地址" />
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-item__label">备注</text>
|
||
<input class="form-item__input" v-model="remark" placeholder="请输入备注信息" />
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 发货时间 -->
|
||
<view class="delivery-section">
|
||
<view class="delivery-section__header">
|
||
<image src="/static/ic_time.png" class="delivery-section__icon" mode="aspectFit" />
|
||
<text class="delivery-section__title">发货时间</text>
|
||
</view>
|
||
<text class="delivery-section__content">上班时间9:30-20:30分,下单15分钟即可出货。镶嵌主石每天18:00前,正常情况当天出货。</text>
|
||
</view>
|
||
|
||
<!-- 商品列表 -->
|
||
<view class="product-section">
|
||
<view class="product-item" v-for="item in orderItems" :key="item.id">
|
||
<image class="product-item__img" :src="fullUrl(item.product.thumb || item.product.bannerImages?.[0] || '')" mode="aspectFill" />
|
||
<view class="product-item__info">
|
||
<text class="product-item__name">{{ item.product.name }}</text>
|
||
<view class="product-item__specs">
|
||
<text class="product-item__spec">款号:{{ item.specData.modelName || 'B2022' }}</text>
|
||
<text class="product-item__spec">商品型号:{{ item.specData.fineness || '2606' }}</text>
|
||
<text class="product-item__spec">成色:{{ item.specData.fineness || '30' }}</text>
|
||
<text class="product-item__spec">主石:{{ item.specData.mainStone || '13.00#' }}</text>
|
||
<text class="product-item__spec">手寸:{{ item.specData.ringSize || '13.00#' }}</text>
|
||
<text class="product-item__spec">金料总重:{{ item.specData.goldTotalWeight || '236' }}</text>
|
||
</view>
|
||
<text class="product-item__price">¥{{ item.specData.totalPrice }}元</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 贵重物品不退换提醒 -->
|
||
<view class="agreement" @click="agreed = !agreed">
|
||
<image :src="agreed ? '/static/ic_check_s.png' : '/static/ic_check.png'" class="agreement__checkbox" mode="aspectFit" />
|
||
<text class="agreement__text">因珠宝产品属于贵重物品,一旦出货,产品无质量问题不支持退换!</text>
|
||
</view>
|
||
|
||
<!-- 底部提交栏 -->
|
||
<view class="submit-bar">
|
||
<view class="submit-bar__left">
|
||
<text class="submit-bar__label">合计:</text>
|
||
<text class="submit-bar__price">¥{{ totalPrice }}</text>
|
||
</view>
|
||
<view
|
||
class="submit-bar__btn"
|
||
:class="{ 'submit-bar__btn--disabled': !canSubmit }"
|
||
@click="handleSubmit"
|
||
>
|
||
开始下单
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed, onMounted } from 'vue'
|
||
import { useCartStore } from '../../store/cart'
|
||
import { createOrder } from '../../api/order'
|
||
import { BASE_URL } from '../../utils/request'
|
||
import type { CartItem } from '../../types'
|
||
|
||
const cartStore = useCartStore()
|
||
|
||
const statusBarHeight = ref(0)
|
||
const navBarHeight = ref(44)
|
||
const receiverName = ref('')
|
||
const receiverPhone = ref('')
|
||
const receiverAddress = ref('')
|
||
const remark = ref('')
|
||
const agreed = ref(false)
|
||
const submitting = ref(false)
|
||
|
||
function fullUrl(path: string): string {
|
||
if (!path) return ''
|
||
if (path.startsWith('http')) return path
|
||
return BASE_URL + path
|
||
}
|
||
|
||
function goBack() {
|
||
uni.navigateBack()
|
||
}
|
||
|
||
/** 从购物车获取已勾选的商品作为订单项 */
|
||
const orderItems = computed<CartItem[]>(() => cartStore.checkedItems)
|
||
|
||
const totalPrice = computed(() =>
|
||
orderItems.value.reduce((sum, item) => sum + item.specData.totalPrice * item.quantity, 0),
|
||
)
|
||
|
||
const canSubmit = computed(() => agreed.value && !submitting.value)
|
||
|
||
async function handleSubmit() {
|
||
if (!canSubmit.value) return
|
||
|
||
if (!receiverName.value.trim()) {
|
||
uni.showToast({ title: '请输入收货人姓名', icon: 'none' })
|
||
return
|
||
}
|
||
if (!receiverPhone.value.trim()) {
|
||
uni.showToast({ title: '请输入联系电话', icon: 'none' })
|
||
return
|
||
}
|
||
if (!receiverAddress.value.trim()) {
|
||
uni.showToast({ title: '请输入收货地址', icon: 'none' })
|
||
return
|
||
}
|
||
|
||
submitting.value = true
|
||
try {
|
||
const order = await createOrder({
|
||
items: orderItems.value.map((item) => ({
|
||
productId: item.productId,
|
||
specDataId: item.specDataId,
|
||
quantity: item.quantity,
|
||
unitPrice: item.specData.totalPrice,
|
||
})),
|
||
receiverName: receiverName.value.trim(),
|
||
receiverPhone: receiverPhone.value.trim(),
|
||
receiverAddress: receiverAddress.value.trim(),
|
||
})
|
||
|
||
// 清除已下单的购物车项
|
||
for (const item of orderItems.value) {
|
||
cartStore.removeFromCart(item.id)
|
||
}
|
||
|
||
uni.redirectTo({ url: `/pages/order/detail?id=${order.id}` })
|
||
} catch {
|
||
uni.showToast({ title: '提交订单失败,请重试', icon: 'none' })
|
||
} finally {
|
||
submitting.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
const sysInfo = uni.getSystemInfoSync()
|
||
statusBarHeight.value = sysInfo.statusBarHeight || 0
|
||
const menuBtn = uni.getMenuButtonBoundingClientRect()
|
||
navBarHeight.value = menuBtn.height + (menuBtn.top - (sysInfo.statusBarHeight || 0)) * 2
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.order-submit {
|
||
min-height: 100vh;
|
||
background: #f5f5f5;
|
||
padding-bottom: 140rpx;
|
||
}
|
||
|
||
/* 导航栏 */
|
||
.navbar {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 100;
|
||
background: linear-gradient(135deg, #FFCFDE 0%, #FFA6C4 100%);
|
||
}
|
||
.navbar__content {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 24rpx;
|
||
}
|
||
.navbar__back {
|
||
padding: 10rpx;
|
||
}
|
||
.navbar__back-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
.navbar__title {
|
||
font-size: 34rpx;
|
||
font-weight: 600;
|
||
color: #000;
|
||
}
|
||
.navbar__placeholder {
|
||
width: 60rpx;
|
||
}
|
||
|
||
/* 公司地址 */
|
||
.address-section {
|
||
background: #fff;
|
||
margin: 16rpx 24rpx;
|
||
padding: 24rpx;
|
||
border-radius: 16rpx;
|
||
}
|
||
.address-section__header {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
.address-section__icon {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
margin-right: 8rpx;
|
||
}
|
||
.address-section__title {
|
||
font-size: 28rpx;
|
||
color: #e91e63;
|
||
font-weight: 600;
|
||
}
|
||
.address-section__content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8rpx;
|
||
}
|
||
.address-section__name {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: 600;
|
||
}
|
||
.address-section__detail,
|
||
.address-section__phone,
|
||
.address-section__contact {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
line-height: 36rpx;
|
||
}
|
||
|
||
/* 您的信息 */
|
||
.info-section {
|
||
background: #fff;
|
||
margin: 0 24rpx 16rpx;
|
||
padding: 24rpx;
|
||
border-radius: 16rpx;
|
||
}
|
||
.info-section__header {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
.info-section__icon {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
margin-right: 8rpx;
|
||
}
|
||
.info-section__title {
|
||
font-size: 28rpx;
|
||
color: #e91e63;
|
||
font-weight: 600;
|
||
margin-right: 12rpx;
|
||
}
|
||
.info-section__subtitle {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
.form-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 20rpx 0;
|
||
border-bottom: 1rpx solid #f0f0f0;
|
||
}
|
||
.form-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
.form-item__label {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
width: 100rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
.form-item__label.required::before {
|
||
content: '*';
|
||
color: #e91e63;
|
||
margin-right: 4rpx;
|
||
}
|
||
.form-item__input {
|
||
flex: 1;
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
}
|
||
|
||
/* 发货时间 */
|
||
.delivery-section {
|
||
background: #fff;
|
||
margin: 0 24rpx 16rpx;
|
||
padding: 24rpx;
|
||
border-radius: 16rpx;
|
||
}
|
||
.delivery-section__header {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
.delivery-section__icon {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
margin-right: 8rpx;
|
||
}
|
||
.delivery-section__title {
|
||
font-size: 28rpx;
|
||
color: #e91e63;
|
||
font-weight: 600;
|
||
}
|
||
.delivery-section__content {
|
||
font-size: 24rpx;
|
||
color: #e91e63;
|
||
line-height: 36rpx;
|
||
}
|
||
|
||
/* 商品列表 */
|
||
.product-section {
|
||
background: #fff;
|
||
margin: 0 24rpx 16rpx;
|
||
padding: 24rpx;
|
||
border-radius: 16rpx;
|
||
}
|
||
.product-item {
|
||
display: flex;
|
||
gap: 20rpx;
|
||
}
|
||
.product-item__img {
|
||
width: 160rpx;
|
||
height: 160rpx;
|
||
border-radius: 12rpx;
|
||
flex-shrink: 0;
|
||
background: #f5f5f5;
|
||
}
|
||
.product-item__info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.product-item__name {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: 600;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
.product-item__specs {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 8rpx;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
.product-item__spec {
|
||
font-size: 22rpx;
|
||
color: #666;
|
||
}
|
||
.product-item__price {
|
||
font-size: 30rpx;
|
||
color: #e91e63;
|
||
font-weight: 700;
|
||
}
|
||
|
||
/* 协议 */
|
||
.agreement {
|
||
background: #fffbe6;
|
||
margin: 0 24rpx 16rpx;
|
||
padding: 20rpx 24rpx;
|
||
border-radius: 16rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.agreement__checkbox {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
margin-right: 12rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
.agreement__text {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
line-height: 36rpx;
|
||
}
|
||
|
||
/* 底部提交栏 */
|
||
.submit-bar {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
background: #fff;
|
||
padding: 16rpx 24rpx;
|
||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
.submit-bar__left {
|
||
display: flex;
|
||
align-items: baseline;
|
||
}
|
||
.submit-bar__label {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
}
|
||
.submit-bar__price {
|
||
font-size: 36rpx;
|
||
color: #e91e63;
|
||
font-weight: 700;
|
||
}
|
||
.submit-bar__btn {
|
||
background: linear-gradient(135deg, #FF6D9B, #FF4081);
|
||
color: #fff;
|
||
padding: 20rpx 60rpx;
|
||
border-radius: 44rpx;
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
}
|
||
.submit-bar__btn--disabled {
|
||
background: #ccc;
|
||
pointer-events: none;
|
||
}
|
||
</style>
|