feat: 填写订单

This commit is contained in:
jqtmviyu 2025-05-08 16:40:38 +08:00
parent 6935ad15d0
commit f8673b8553
8 changed files with 614 additions and 5 deletions

View File

@ -143,6 +143,17 @@
}
}
]
},
{
"root": "pagesOrder",
"pages": [
{
"path": "create/create",
"style": {
"navigationBarTitleText": "新建订单"
}
}
]
}
],

View File

@ -213,9 +213,8 @@ const handlerPay = () => {
})
return
}
uni.showToast({
title: '跳转结算页面占用',
icon: 'none',
uni.navigateTo({
url: '/pagesOrder/create/create',
})
}
</script>

View File

@ -7,7 +7,7 @@
<uni-swipe-action class="item" v-for="item in addressList" :key="item.id">
<uni-swipe-action-item :text="item.receiver">
<view class="item-content">
<view class="left">
<view class="left" @tap="handleSelectAddress(item)">
<view class="user">
{{ item.receiver }}
<text class="contact">{{ item.contact }}</text>
@ -42,6 +42,7 @@
<script setup lang="ts">
import { deleteMemberAddressAPI, getMemberAddressAPI } from '@/services/address'
import { useSelectedAddressStore } from '@/stores/modules/selectedAddress'
import type { AddressItem } from '@/types/address'
import { onShow } from '@dcloudio/uni-app'
import { ref } from 'vue'
@ -60,6 +61,7 @@ onShow(() => {
getAddressList()
})
//
const handleDelete = (id: string) => {
uni.showModal({
content: '确定要删除该地址吗?',
@ -74,6 +76,20 @@ const handleDelete = (id: string) => {
},
})
}
//
const props = defineProps<{
from: string
}>()
const useSelectedAddress = useSelectedAddressStore()
const handleSelectAddress = (address: AddressItem) => {
if (props.from === 'order') {
useSelectedAddress.setSelectedAddress(address)
uni.navigateBack()
}
}
</script>
<style lang="scss">

View File

@ -0,0 +1,361 @@
<template>
<scroll-view scroll-y class="viewport">
<!-- 收货地址 -->
<navigator
v-if="selectedAddress"
class="shipment"
hover-class="none"
url="/pagesMember/address/address?from=order"
>
<view class="user"> {{ selectedAddress.receiver }} {{ selectedAddress.contact }} </view>
<view class="address">
{{ selectedAddress.fullLocation }} {{ selectedAddress.address }}
</view>
<text class="icon icon-right"></text>
</navigator>
<navigator
v-else
class="shipment"
hover-class="none"
url="/pagesMember/address/address?from=order"
>
<view class="address"> 请选择收货地址 </view>
<text class="icon icon-right"></text>
</navigator>
<!-- 商品信息 -->
<view class="goods">
<navigator
v-for="item in orderPreList?.goods"
:key="item.skuId"
:url="`/pages/goods/goods?id=${item.id}`"
class="item"
hover-class="none"
>
<image class="picture" :src="item.picture" />
<view class="meta">
<view class="name ellipsis"> {{ item.name }} </view>
<view class="attrs"> {{ item.attrsText.replaceAll('', ' ') }} </view>
<view class="prices">
<view class="pay-price symbol"> {{ item.payPrice }} </view>
<view class="price symbol">{{ item.price }}</view>
</view>
<view class="count">x{{ item.count }}</view>
</view>
</navigator>
</view>
<!-- 配送及支付方式 -->
<view class="related">
<view class="item">
<text class="text">配送时间</text>
<picker :range="deliveryList" range-key="text" @change="onChangeDelivery">
<view class="icon-fonts picker">{{ activeDelivery.text }}</view>
</picker>
</view>
<view class="item">
<text class="text">订单备注</text>
<input
class="input"
:cursor-spacing="30"
placeholder="可选,建议留言前先与商家沟通确认"
v-model="buyerMessage"
/>
</view>
</view>
<!-- 支付金额 -->
<view class="settlement">
<view class="item">
<text class="text">商品总价: </text>
<text class="number symbol">{{ orderPreList?.summary.totalPrice.toFixed(2) }}</text>
</view>
<view class="item">
<text class="text">运费: </text>
<text class="number symbol">{{ orderPreList?.summary.postFee.toFixed(2) }}</text>
</view>
</view>
</scroll-view>
<!-- 吸底工具栏 -->
<view class="toolbar" :style="{ paddingBottom: safeAreaInsets?.bottom + 'px' }">
<view class="total-pay symbol">
<text class="number"> {{ orderPreList?.summary.totalPayPrice.toFixed(2) }} </text>
</view>
<view
class="button"
:class="{ disabled: orderPreList == null || orderPreList?.goods.length === 0 }"
>
提交订单
</view>
</view>
</template>
<script setup lang="ts">
import { getMemberOrderAPI } from '@/services/order'
import { useSelectedAddressStore } from '@/stores/modules/selectedAddress'
import type { AddressItem } from '@/types/address'
import type { OrderPreResult } from '@/types/order'
import { onShow } from '@dcloudio/uni-app'
import { computed, ref } from 'vue'
//
const { safeAreaInsets } = uni.getSystemInfoSync()
//
const buyerMessage = ref('')
//
const deliveryList = ref([
{ type: 1, text: '时间不限 (周一至周日)' },
{ type: 2, text: '工作日送 (周一至周五)' },
{ type: 3, text: '周末配送 (周六至周日)' },
])
//
const activeIndex = ref(0)
//
const activeDelivery = computed(() => deliveryList.value[activeIndex.value])
//
const onChangeDelivery: UniHelper.SelectorPickerOnChange = (ev) => {
activeIndex.value = ev.detail.value
}
//
const orderPreList = ref<OrderPreResult>()
const getOrderPre = async () => {
const res = await getMemberOrderAPI()
console.log(res)
if (res.code === '1') {
orderPreList.value = res.result
}
}
onShow(() => {
getOrderPre()
})
//
const useSelectedAddress = useSelectedAddressStore()
const selectedAddress = computed(() => {
return (
useSelectedAddress.selectedAddress ||
orderPreList.value?.userAddresses.find((item) => item.isDefault === 1)
)
})
</script>
<style lang="scss">
page {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
background-color: #f4f4f4;
}
.symbol::before {
content: '¥';
font-size: 80%;
margin-right: 5rpx;
}
.shipment {
margin: 20rpx;
padding: 30rpx 30rpx 30rpx 84rpx;
font-size: 26rpx;
border-radius: 10rpx;
background: url(https://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/images/locate.png)
20rpx center / 50rpx no-repeat #fff;
position: relative;
.icon {
font-size: 36rpx;
color: #333;
transform: translateY(-50%);
position: absolute;
top: 50%;
right: 20rpx;
}
.user {
color: #333;
margin-bottom: 5rpx;
}
.address {
color: #666;
}
}
.goods {
margin: 20rpx;
padding: 0 20rpx;
border-radius: 10rpx;
background-color: #fff;
.item {
display: flex;
padding: 30rpx 0;
border-top: 1rpx solid #eee;
&:first-child {
border-top: none;
}
.picture {
width: 170rpx;
height: 170rpx;
border-radius: 10rpx;
margin-right: 20rpx;
}
.meta {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
}
.name {
height: 80rpx;
font-size: 26rpx;
color: #444;
}
.attrs {
line-height: 1.8;
padding: 0 15rpx;
margin-top: 6rpx;
font-size: 24rpx;
align-self: flex-start;
border-radius: 4rpx;
color: #888;
background-color: #f7f7f8;
}
.prices {
display: flex;
align-items: baseline;
margin-top: 6rpx;
font-size: 28rpx;
.pay-price {
margin-right: 10rpx;
color: #cf4444;
}
.price {
font-size: 24rpx;
color: #999;
text-decoration: line-through;
}
}
.count {
position: absolute;
bottom: 0;
right: 0;
font-size: 26rpx;
color: #444;
}
}
}
.related {
margin: 20rpx;
padding: 0 20rpx;
border-radius: 10rpx;
background-color: #fff;
.item {
display: flex;
justify-content: space-between;
align-items: center;
min-height: 80rpx;
font-size: 26rpx;
color: #333;
}
.input {
flex: 1;
text-align: right;
margin: 20rpx 0;
padding-right: 20rpx;
font-size: 26rpx;
color: #999;
}
.item .text {
width: 125rpx;
}
.picker {
color: #666;
}
.picker::after {
content: '\e6c2';
}
}
/* 结算清单 */
.settlement {
margin: 20rpx;
padding: 0 20rpx;
border-radius: 10rpx;
background-color: #fff;
.item {
display: flex;
align-items: center;
justify-content: space-between;
height: 80rpx;
font-size: 26rpx;
color: #333;
}
.danger {
color: #cf4444;
}
}
/* 吸底工具栏 */
.toolbar {
position: fixed;
left: 0;
right: 0;
bottom: calc(var(--window-bottom));
z-index: 1;
background-color: #fff;
height: 100rpx;
padding: 0 20rpx;
border-top: 1rpx solid #eaeaea;
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: content-box;
.total-pay {
font-size: 40rpx;
color: #cf4444;
.decimal {
font-size: 75%;
}
}
.button {
width: 220rpx;
text-align: center;
line-height: 72rpx;
font-size: 26rpx;
color: #fff;
border-radius: 72rpx;
background-color: #27ba9b;
}
.disabled {
opacity: 0.6;
}
}
</style>

38
src/services/order.ts Normal file
View File

@ -0,0 +1,38 @@
import type { OrderPreResult } from '@/types/order'
import { http } from '@/utils/http'
/** 订单状态枚举 */
export enum OrderState {
/** 待付款 */
DaiFuKuan = 1,
/** 待发货 */
DaiFaHuo = 2,
/** 待收货 */
DaiShouHuo = 3,
/** 待评价 */
DaiPingJia = 4,
/** 已完成 */
YiWanCheng = 5,
/** 已取消 */
YiQuXiao = 6,
}
/** 订单状态列表 */
export const orderStateList = [
{ id: 0, text: '' },
{ id: 1, text: '待付款' },
{ id: 2, text: '待发货' },
{ id: 3, text: '待收货' },
{ id: 4, text: '待评价' },
{ id: 5, text: '已完成' },
{ id: 6, text: '已取消' },
]
/**
*
*/
export const getMemberOrderAPI = () => {
return http<OrderPreResult>({
url: '/member/order/pre',
method: 'GET',
})
}

View File

@ -1,4 +1,4 @@
import type { LoginResult, ProfileDetail, ProfileParams } from '@/types/member'
import type { LoginResult, ProfileDetail } from '@/types/member'
import { defineStore } from 'pinia'
import { ref } from 'vue'

View File

@ -0,0 +1,19 @@
import type { AddressItem } from '@/types/address'
import { defineStore } from 'pinia'
import { ref } from 'vue'
/**
*
*/
export const useSelectedAddressStore = defineStore('selectedAddress', () => {
const selectedAddress = ref<AddressItem | null>(null)
const setSelectedAddress = (address: AddressItem) => {
selectedAddress.value = address
}
return {
selectedAddress,
setSelectedAddress,
}
})

165
src/types/order.d.ts vendored Normal file
View File

@ -0,0 +1,165 @@
import type { OrderState } from '@/services/order'
import type { AddressItem } from './address'
import type { PageParams } from '@/types/global'
/** 获取预付订单 返回信息 */
export type OrderPreResult = {
/** 商品集合 [ 商品信息 ] */
goods: OrderPreGoods[]
/** 结算信息 */
summary: {
/** 商品总价 */
totalPrice: number
/** 邮费 */
postFee: number
/** 应付金额 */
totalPayPrice: number
}
/** 用户地址列表 [ 地址信息 ] */
userAddresses: AddressItem[]
}
/** 商品信息 */
export type OrderPreGoods = {
/** 属性文字,例如“颜色:瓷白色 尺寸8寸” */
attrsText: string
/** 数量 */
count: number
/** id */
id: string
/** 商品名称 */
name: string
/** 实付单价 */
payPrice: string
/** 图片 */
picture: string
/** 原单价 */
price: string
/** SKUID */
skuId: string
/** 实付价格小计 */
totalPayPrice: string
/** 小计总价 */
totalPrice: string
}
/** 提交订单 请求参数 */
export type OrderCreateParams = {
/** 所选地址Id */
addressId: string
/** 配送时间类型1为不限2为工作日3为双休或假日 */
deliveryTimeType: number
/** 订单备注 */
buyerMessage: string
/** 商品集合[ 商品信息 ] */
goods: {
/** 数量 */
count: number
/** skuId */
skuId: string
}[]
/** 支付渠道支付渠道1支付宝、2微信--支付方式为在线支付时,传值,为货到付款时,不传值 */
payChannel: 1 | 2
/** 支付方式1为在线支付2为货到付款 */
payType: 1 | 2
}
/** 提交订单 返回信息 */
export type OrderCreateResult = {
/** 订单Id */
id: string
}
/** 订单详情 返回信息 */
export type OrderResult = {
/** 订单编号 */
id: string
/** 订单状态1为待付款、2为待发货、3为待收货、4为待评价、5为已完成、6为已取消 */
orderState: OrderState
/** 倒计时--剩余的秒数 -1 表示已经超时,正数表示倒计时未结束 */
countdown: number
/** 商品集合 [ 商品信息 ] */
skus: OrderSkuItem[]
/** 收货人 */
receiverContact: string
/** 收货人手机 */
receiverMobile: string
/** 收货人地址 */
receiverAddress: string
/** 下单时间 */
createTime: string
/** 商品总价 */
totalMoney: number
/** 运费 */
postFee: number
/** 应付金额 */
payMoney: number
}
/** 商品信息 */
export type OrderSkuItem = {
/** sku id */
id: string
/** 商品 id */
spuId: string
/** 商品名称 */
name: string
/** 商品属性文字 */
attrsText: string
/** 数量 */
quantity: number
/** 购买时单价 */
curPrice: number
/** 图片地址 */
image: string
}
/** 物流信息 返回值类型 */
export type OrderLogisticResult = {
/** 快递公司 */
company: {
/** 公司名称 */
name: string
/** 快递编号 */
number: string
/** 联系电话 */
tel: string
}
/** 商品件数 */
count: number
/** 物流日志 */
list: LogisticItem[]
}
/** 物流日志 */
export type LogisticItem = {
/** 信息ID */
id: string
/** 信息文字 */
text: string
/** 时间 */
time: string
}
/** 订单列表参数 */
export type OrderListParams = PageParams & { orderState: number }
/** 订单列表 */
export type OrderListResult = {
/** 总记录数 */
counts: number
/** 数据集合 [ 订单信息 ] */
items: OrderItem[]
/** 当前页码 */
page: number
/** 总页数 */
pages: number
/** 页尺寸 */
pageSize: number
}
/** 订单列表项 */
export type OrderItem = OrderResult & {
/** 总件数 */
totalNum: number
}