快递模板更新 #2

Merged
root merged 1 commits from zzw-one into master 2024-09-18 17:34:11 +08:00
8 changed files with 1039 additions and 152 deletions

View File

@ -0,0 +1,261 @@
<!-- 下单界面收货地址 or 自提门店的选择组件 -->
<template>
<view class="allAddress" :style="state.isPickUp ? '':'padding-top:10rpx;'">
<view class="nav flex flex-wrap">
<view class="item font-color" :class="state.deliveryType === 1 ? 'on' : 'on2'"
@tap="switchDeliveryType(1)" v-if='state.isPickUp' />
<view class="item font-color" :class="state.deliveryType === 2 ? 'on' : 'on2'"
@tap="switchDeliveryType(2)" v-if='state.isPickUp' />
</view>
<!-- 情况一收货地址的选择 -->
<view class='address flex flex-wrap flex-center ss-row-between' @tap='onSelectAddress' v-if='state.deliveryType === 1'
:style="state.isPickUp ? '':'border-top-left-radius: 14rpx;border-top-right-radius: 14rpx;'">
<view class='addressCon' v-if="state.addressInfo.name">
<view class='name'>{{ state.addressInfo.name }}
<text class='phone'>{{ state.addressInfo.mobile }}</text>
</view>
<view class="flex flex-wrap">
<text class='default font-color' v-if="state.addressInfo.defaultStatus">[默认]</text>
<text class="line2">{{ state.addressInfo.areaName }} {{ state.addressInfo.detailAddress }}</text>
</view>
</view>
<view class='addressCon' v-else>
<view class='setaddress'>设置收货地址</view>
</view>
<view class='iconfont'>
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</view>
</view>
<!-- 情况二门店的选择 -->
<view class='address flex flex-wrap flex-center ss-row-between' v-else @tap="onSelectAddress">
<view class='addressCon' v-if="state.pickUpInfo.name">
<view class='name'>{{ state.pickUpInfo.name }}
<text class='phone'>{{ state.pickUpInfo.phone }}</text>
</view>
<view class="line1"> {{ state.pickUpInfo.areaName }}{{ ', ' + state.pickUpInfo.detailAddress }}
</view>
</view>
<view class='addressCon' v-else>
<view class='setaddress'>选择自提门店</view>
</view>
<view class='iconfont'>
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</view>
</view>
<view class='line'>
<image :src="sheep.$url.static('/static/images/line.png', 'local')" />
</view>
</view>
</template>
<script setup>
import { computed } from 'vue';
import sheep from '@/sheep';
import { isEmpty } from 'lodash-es';
const props = defineProps({
modelValue: {
type: Object,
default() {},
}
});
const emits = defineEmits(['update:modelValue']);
// computed
const state = computed({
get(){
return new Proxy(props.modelValue, {
set(obj, name, val) {
emits('update:modelValue', {
...obj,
[name]: val,
});
return true;
}
})
},
set(val){
emits('update:modelValue', val);
}
})
//
function onSelectAddress() {
let emitName = 'SELECT_ADDRESS'
let addressPage = '/pages/user/address/list?type=select';
if (state.value.deliveryType === 2){
emitName = 'SELECT_PICK_UP_INFO'
addressPage = '/pages/user/goods_details_store/index'
}
uni.$once(emitName, (e) => {
changeConsignee(e.addressInfo);
});
sheep.$router.go(addressPage);
}
// &
async function changeConsignee(addressInfo = {}) {
if (!isEmpty(addressInfo)) {
if (state.value.deliveryType === 1){
state.value.addressInfo = addressInfo;
}
if (state.value.deliveryType === 2){
state.value.pickUpInfo = addressInfo;
}
}
}
//
const switchDeliveryType = (type) =>{
state.value.deliveryType = type;
}
</script>
<style scoped lang="scss">
.allAddress .font-color{
color: #E93323!important
}
.line2{
width: 504rpx;
}
.textR {
text-align: right;
}
.line {
width: 100%;
height: 3rpx;
}
.line image {
width: 100%;
height: 100%;
display: block;
}
.address {
padding: 28rpx;
background-color: #fff;
box-sizing: border-box;
}
.address .addressCon {
width: 596rpx;
font-size: 26rpx;
color: #666;
}
.address .addressCon .name {
font-size: 30rpx;
color: #282828;
font-weight: bold;
margin-bottom: 10rpx;
}
.address .addressCon .name .phone {
margin-left: 50rpx;
}
.address .addressCon .default {
margin-right: 12rpx;
}
.address .addressCon .setaddress {
color: #333;
font-size: 28rpx;
}
.address .iconfont {
font-size: 35rpx;
color: #707070;
}
.allAddress {
width: 100%;
background: linear-gradient(to bottom, #e93323 0%, #f5f5f5 100%);
// background-image: linear-gradient(to bottom, #e93323 0%, #f5f5f5 100%);
// background-image: -webkit-linear-gradient(to bottom, #e93323 0%, #f5f5f5 100%);
// background-image: -moz-linear-gradient(to bottom, #e93323 0%, #f5f5f5 100%);
//padding: 100rpx 30rpx 0 30rpx;
padding-top: 100rpx;
padding-bottom: 10rpx;
}
.allAddress .nav {
width: 690rpx;
margin: 0 auto;
}
.allAddress .nav .item {
width: 334rpx;
}
.allAddress .nav .item.on {
position: relative;
width: 230rpx;
}
.allAddress .nav .item.on::before {
position: absolute;
bottom: 0;
content: "快递配送";
font-size: 28rpx;
display: block;
height: 0;
width: 336rpx;
border-width: 0 20rpx 80rpx 0;
border-style: none solid solid;
border-color: transparent transparent #fff;
z-index: 2;
border-radius: 14rpx 36rpx 0 0;
text-align: center;
line-height: 80rpx;
}
.allAddress .nav .item:nth-of-type(2).on::before {
content: "到店自提";
border-width: 0 0 80rpx 20rpx;
border-radius: 36rpx 14rpx 0 0;
}
.allAddress .nav .item.on2 {
position: relative;
}
.allAddress .nav .item.on2::before {
position: absolute;
bottom: 0;
content: "到店自提";
font-size: 28rpx;
display: block;
height: 0;
width: 401rpx;
border-width: 0 0 60rpx 60rpx;
border-style: none solid solid;
border-color: transparent transparent #f7c1bd;
border-radius: 36rpx 14rpx 0 0;
text-align: center;
line-height: 60rpx;
}
.allAddress .nav .item:nth-of-type(1).on2::before {
content: "快递配送";
border-width: 0 60rpx 60rpx 0;
border-radius: 14rpx 36rpx 0 0;
}
.allAddress .address {
width: 690rpx;
max-height: 180rpx;
margin: 0 auto;
}
.allAddress .line {
width: 100%;
margin: 0 auto;
}
</style>

View File

@ -1,35 +1,29 @@
<template>
<s-layout title="确认订单">
<!-- TODO这个判断先删除 v-if="state.orderInfo.need_address === 1" -->
<view class="bg-white address-box ss-m-b-14 ss-r-b-10" @tap="onSelectAddress">
<s-address-item :item="state.addressInfo" :hasBorderBottom="false">
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</s-address-item>
</view>
<!-- 头部地址选择配送地址自提地址 -->
<AddressSelection v-model="addressState" />
<!-- 商品信息 -->
<view class="order-card-box ss-m-b-14">
<s-goods-item
v-for="item in state.orderInfo.items"
:key="item.skuId"
:img="item.picUrl"
:title="item.spuName"
:skuText="item.properties.map((property) => property.valueName).join(' ')"
:price="item.price"
:num="item.count"
marginBottom="10"
v-for="item in state.orderInfo.items"
:key="item.skuId"
:img="item.picUrl"
:title="item.spuName"
:skuText="item.properties.map((property) => property.valueName).join(' ')"
:price="item.price"
:num="item.count"
marginBottom="10"
/>
<view class="order-item ss-flex ss-col-center ss-row-between ss-p-x-20 bg-white ss-r-10">
<view class="item-title">订单备注</view>
<view class="ss-flex ss-col-center">
<uni-easyinput
maxlength="20"
placeholder="建议留言前先与商家沟通"
v-model="state.orderPayload.remark"
:inputBorder="false"
:clearable="false"
maxlength="20"
placeholder="建议留言前先与商家沟通"
v-model="state.orderPayload.remark"
:inputBorder="false"
:clearable="false"
/>
</view>
</view>
@ -46,32 +40,64 @@
</text>
</view>
</view>
<!-- TODO 芋艿接入积分 -->
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderPayload.order_type === 'score'"
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.type === 0"
>
<view class="item-title">扣除积分</view>
<view class="item-title">积分抵扣</view>
<view class="ss-flex ss-col-center">
{{ state.pointStatus ? '剩余积分' : '当前积分' }}
<image
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
class="score-img"
:src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
class="score-img"
/>
<text class="item-value ss-m-r-24">{{ state.orderInfo.score_amount }}</text>
<text class="item-value ss-m-r-24">
{{ state.pointStatus ? state.orderInfo.totalPoint - state.orderInfo.usePoint : (state.orderInfo.totalPoint || 0) }}
</text>
<checkbox-group @change="changeIntegral">
<checkbox :checked='state.pointStatus' :disabled="!state.orderInfo.totalPoint || state.orderInfo.totalPoint <= 0" />
</checkbox-group>
</view>
</view>
<view class="order-item ss-flex ss-col-center ss-row-between">
<!-- 快递配置时信息的展示 -->
<view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 1'>
<view class="item-title">运费</view>
<view class="ss-flex ss-col-center">
<text class="item-value ss-m-r-24">
<text class="item-value ss-m-r-24" v-if="state.orderInfo.price.deliveryPrice > 0">
+{{ fen2yuan(state.orderInfo.price.deliveryPrice) }}
</text>
<view class='item-value ss-m-r-24' v-else>免运费</view>
</view>
</view>
<!-- 门店自提时需要填写姓名和手机号 -->
<view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 2'>
<view class="item-title">联系人</view>
<view class="ss-flex ss-col-center">
<uni-easyinput
maxlength="20"
placeholder="请填写您的联系姓名"
v-model="addressState.receiverName"
:inputBorder="false"
:clearable="false"
/>
</view>
</view>
<view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 2'>
<view class="item-title">联系电话</view>
<view class="ss-flex ss-col-center">
<uni-easyinput
maxlength="20"
placeholder="请填写您的联系电话"
v-model="addressState.receiverMobile"
:inputBorder="false"
:clearable="false"
/>
</view>
</view>
<!-- 优惠劵只有 type = 0 普通订单非拼团秒杀砍价才可以使用优惠劵 -->
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.type === 0"
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.type === 0"
>
<view class="item-title">优惠券</view>
<view class="ss-flex ss-col-center" @tap="state.showCoupon = true">
@ -79,20 +105,20 @@
-{{ fen2yuan(state.orderInfo.price.couponPrice) }}
</text>
<text
class="item-value"
:class="state.couponInfo.length > 0 ? 'text-red' : 'text-disabled'"
v-else
class="item-value"
:class="state.couponInfo.length > 0 ? 'text-red' : 'text-disabled'"
v-else
>
{{
state.couponInfo.length > 0 ? state.couponInfo.length + ' 张可用' : '暂无可用优惠券'
state.couponInfo.length > 0 ? state.couponInfo.length + ' 张可用' : '暂无可用优惠券'
}}
</text>
<text class="_icon-forward item-icon" />
</view>
</view>
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.price.discountPrice > 0"
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.price.discountPrice > 0"
>
<view class="item-title">活动优惠</view>
<view class="ss-flex ss-col-center">
@ -104,8 +130,8 @@
</view>
</view>
<view
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.price.vipPrice > 0"
class="order-item ss-flex ss-col-center ss-row-between"
v-if="state.orderInfo.price.vipPrice > 0"
>
<view class="item-title">会员优惠</view>
<view class="ss-flex ss-col-center">
@ -120,23 +146,23 @@
{{ state.orderInfo.items.reduce((acc, item) => acc + item.count, 0) }}
</view>
<view>合计</view>
<view class="total-num text-red"> {{ fen2yuan(state.orderInfo.price.payPrice) }} </view>
<view class="total-num text-red"> {{ fen2yuan(state.orderInfo.price.payPrice) }}</view>
</view>
</view>
<!-- 选择优惠券弹框 -->
<s-coupon-select
v-model="state.couponInfo"
:show="state.showCoupon"
@confirm="onSelectCoupon"
@close="state.showCoupon = false"
v-model="state.couponInfo"
:show="state.showCoupon"
@confirm="onSelectCoupon"
@close="state.showCoupon = false"
/>
<!-- 满额折扣弹框 TODO 芋艿后续要把优惠信息打进去 -->
<s-discount-list
v-model="state.orderInfo"
:show="state.showDiscount"
@close="state.showDiscount = false"
v-model="state.orderInfo"
:show="state.showDiscount"
@close="state.showDiscount = false"
/>
<!-- 底部 -->
@ -148,8 +174,8 @@
</view>
</view>
<button
class="ss-reset-button ui-BG-Main-Gradient ss-r-40 submit-btn ui-Shadow-Main"
@tap="onConfirm"
class="ss-reset-button ui-BG-Main-Gradient ss-r-40 submit-btn ui-Shadow-Main"
@tap="onConfirm"
>
提交订单
</button>
@ -159,10 +185,10 @@
</template>
<script setup>
import { reactive } from 'vue';
import { reactive, ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import AddressSelection from '@/pages/order/addressSelection.vue';
import sheep from '@/sheep';
import { isEmpty } from 'lodash';
import OrderApi from '@/sheep/api/trade/order';
import CouponApi from '@/sheep/api/promotion/coupon';
import { fen2yuan } from '@/sheep/hooks/useGoods';
@ -173,27 +199,30 @@
items: [], //
price: {}, //
},
addressInfo: {}, //
showCoupon: false, //
couponInfo: [], //
showDiscount: false, //
// ========== ==========
pointStatus: false, //使
});
//
function onSelectAddress() {
uni.$once('SELECT_ADDRESS', (e) => {
changeConsignee(e.addressInfo);
});
sheep.$router.go('/pages/user/address/list');
}
const addressState = ref({
addressInfo: {}, //
deliveryType: 1, // 1 - 2 -
isPickUp: true, // TODO puhui999:
pickUpInfo: {}, //
receiverName: '', //
receiverMobile: '', //
});
// &
async function changeConsignee(addressInfo = {}) {
if (!isEmpty(addressInfo)) {
state.addressInfo = addressInfo;
}
// ========== ==========
/**
* 使用积分抵扣
*/
const changeIntegral = async () => {
state.pointStatus = !state.pointStatus;
await getOrderInfo();
}
};
//
async function onSelectCoupon(couponId) {
@ -204,10 +233,28 @@
//
function onConfirm() {
if (!state.addressInfo.id) {
if (addressState.value.deliveryType === 1 && !addressState.value.addressInfo.id) {
sheep.$helper.toast('请选择收货地址');
return;
}
if (addressState.value.deliveryType === 2) {
if (!addressState.value.pickUpInfo.id) {
sheep.$helper.toast('请选择自提门店地址');
return;
}
if (addressState.value.receiverName === '' || addressState.value.receiverMobile === '') {
sheep.$helper.toast('请填写联系人或联系人电话');
return;
}
if (!/^[\u4e00-\u9fa5\w]{2,16}$/.test(addressState.value.receiverName)) {
sheep.$helper.toast('请填写您的真实姓名');
return;
}
if (!/^1(3|4|5|7|8|9|6)\d{9}$/.test(addressState.value.receiverMobile)) {
sheep.$helper.toast('请填写正确的手机号');
return;
}
}
submitOrder();
}
@ -216,9 +263,13 @@
const { code, data } = await OrderApi.createOrder({
items: state.orderPayload.items,
couponId: state.orderPayload.couponId,
addressId: state.addressInfo.id,
deliveryType: 1, // TODO
pointStatus: false, // TODO
remark: state.orderPayload.remark,
deliveryType: addressState.value.deliveryType,
addressId: addressState.value.addressInfo.id, //
pickUpStoreId: addressState.value.pickUpInfo.id,//
receiverName: addressState.value.receiverName,//
receiverMobile: addressState.value.receiverMobile,//
pointStatus: state.pointStatus,
combinationActivityId: state.orderPayload.combinationActivityId,
combinationHeadId: state.orderPayload.combinationHeadId,
seckillActivityId: state.orderPayload.seckillActivityId,
@ -230,6 +281,7 @@
if (state.orderPayload.items[0].cartId > 0) {
sheep.$store('cart').getList();
}
//
sheep.$router.redirect('/pages/pay/index', {
id: data.payOrderId,
@ -242,9 +294,12 @@
const { data, code } = await OrderApi.settlementOrder({
items: state.orderPayload.items,
couponId: state.orderPayload.couponId,
addressId: state.addressInfo.id,
deliveryType: 1, // TODO
pointStatus: false, // TODO
deliveryType: addressState.value.deliveryType,
addressId: addressState.value.addressInfo.id, //
pickUpStoreId: addressState.value.pickUpInfo.id,//
receiverName: addressState.value.receiverName,//
receiverMobile: addressState.value.receiverMobile,//
pointStatus: state.pointStatus,
combinationActivityId: state.orderPayload.combinationActivityId,
combinationHeadId: state.orderPayload.combinationHeadId,
seckillActivityId: state.orderPayload.seckillActivityId,
@ -255,17 +310,17 @@
state.orderInfo = data;
//
if (state.orderInfo.address) {
state.addressInfo = state.orderInfo.address;
addressState.value.addressInfo = state.orderInfo.address;
}
}
//
async function getCoupons() {
const { code, data } = await CouponApi.getMatchCouponList(
state.orderInfo.price.payPrice,
state.orderInfo.items.map((item) => item.spuId),
state.orderPayload.items.map((item) => item.skuId),
state.orderPayload.items.map((item) => item.categoryId),
state.orderInfo.price.payPrice,
state.orderInfo.items.map((item) => item.spuId),
state.orderPayload.items.map((item) => item.skuId),
state.orderPayload.items.map((item) => item.categoryId),
);
if (code === 0) {
state.couponInfo = data;

View File

@ -3,8 +3,8 @@
<s-layout title="订单详情" class="index-wrap" navbar="inner">
<!-- 订单状态 TODO -->
<view
class="state-box ss-flex-col ss-col-center ss-row-right"
:style="[
class="state-box ss-flex-col ss-col-center ss-row-right"
:style="[
{
marginTop: '-' + Number(statusBarHeight + 88) + 'rpx',
paddingTop: Number(statusBarHeight + 88) + 'rpx',
@ -13,41 +13,41 @@
>
<view class="ss-flex ss-m-t-32 ss-m-b-20">
<image
v-if="
v-if="
state.orderInfo.status_code == 'unpaid' ||
state.orderInfo.status === 10 || //
state.orderInfo.status_code == 'nocomment'
"
class="state-img"
:src="sheep.$url.static('/static/img/shop/order/order_loading.png')"
class="state-img"
:src="sheep.$url.static('/static/img/shop/order/order_loading.png')"
>
</image>
<image
v-if="
v-if="
state.orderInfo.status_code == 'completed' ||
state.orderInfo.status_code == 'refund_agree'
"
class="state-img"
:src="sheep.$url.static('/static/img/shop/order/order_success.png')"
class="state-img"
:src="sheep.$url.static('/static/img/shop/order/order_success.png')"
>
</image>
<image
v-if="state.orderInfo.status_code == 'cancel' || state.orderInfo.status_code == 'closed'"
class="state-img"
:src="sheep.$url.static('/static/img/shop/order/order_close.png')"
v-if="state.orderInfo.status_code == 'cancel' || state.orderInfo.status_code == 'closed'"
class="state-img"
:src="sheep.$url.static('/static/img/shop/order/order_close.png')"
>
</image>
<image
v-if="state.orderInfo.status_code == 'noget'"
class="state-img"
:src="sheep.$url.static('/static/img/shop/order/order_express.png')"
v-if="state.orderInfo.status_code == 'noget'"
class="state-img"
:src="sheep.$url.static('/static/img/shop/order/order_express.png')"
>
</image>
<view class="ss-font-30">{{ formatOrderStatus(state.orderInfo) }}</view>
</view>
<view class="ss-font-26 ss-m-x-20 ss-m-b-70">{{
formatOrderStatusDescription(state.orderInfo)
}}</view>
<view class="ss-font-26 ss-m-x-20 ss-m-b-70">
{{ formatOrderStatusDescription(state.orderInfo) }}
</view>
</view>
<!-- 收货地址 -->
@ -64,26 +64,26 @@
</view>
<view
class="detail-goods"
:style="[{ marginTop: state.orderInfo.receiverAreaId > 0 ? '0' : '-40rpx' }]"
class="detail-goods"
:style="[{ marginTop: state.orderInfo.receiverAreaId > 0 ? '0' : '-40rpx' }]"
>
<!-- 订单信 -->
<view class="order-list" v-for="item in state.orderInfo.items" :key="item.goods_id">
<view class="order-card">
<s-goods-item
@tap="onGoodsDetail(item.spuId)"
:img="item.picUrl"
:title="item.spuName"
:skuText="item.properties.map((property) => property.valueName).join(' ')"
:price="item.price"
:num="item.count"
@tap="onGoodsDetail(item.spuId)"
:img="item.picUrl"
:title="item.spuName"
:skuText="item.properties.map((property) => property.valueName).join(' ')"
:price="item.price"
:num="item.count"
>
<template #tool>
<view class="ss-flex">
<button
class="ss-reset-button apply-btn"
v-if="[10, 20, 30].includes(state.orderInfo.status) && item.afterSaleStatus === 0"
@tap.stop="
class="ss-reset-button apply-btn"
v-if="[10, 20, 30].includes(state.orderInfo.status) && item.afterSaleStatus === 0"
@tap.stop="
sheep.$router.go('/pages/order/aftersale/apply', {
orderId: state.orderInfo.id,
itemId: item.id,
@ -93,9 +93,9 @@
申请售后
</button>
<button
class="ss-reset-button apply-btn"
v-if="item.afterSaleStatus === 10"
@tap.stop="
class="ss-reset-button apply-btn"
v-if="item.afterSaleStatus === 10"
@tap.stop="
sheep.$router.go('/pages/order/aftersale/detail', {
id: item.afterSaleId,
})
@ -104,9 +104,9 @@
退款中
</button>
<button
class="ss-reset-button apply-btn"
v-if="item.afterSaleStatus === 20"
@tap.stop="
class="ss-reset-button apply-btn"
v-if="item.afterSaleStatus === 20"
@tap.stop="
sheep.$router.go('/pages/order/aftersale/detail', {
id: item.afterSaleId,
})
@ -126,6 +126,9 @@
</view>
</view>
<!-- 自提核销 -->
<PickUpVerify :order-info="state.orderInfo" :systemStore="systemStore" ref="pickUpVerifyRef"></PickUpVerify>
<!-- 订单信息 -->
<view class="notice-box">
<view class="notice-box__content">
@ -172,6 +175,10 @@
<text class="title">优惠劵金额</text>
<text class="detail">-¥{{ fen2yuan(state.orderInfo.couponPrice) }}</text>
</view>
<view class="notice-item ss-flex ss-row-between" v-if="state.orderInfo.pointPrice > 0">
<text class="title">积分抵扣</text>
<text class="detail">-¥{{ fen2yuan(state.orderInfo.pointPrice) }}</text>
</view>
<view class="notice-item ss-flex ss-row-between" v-if="state.orderInfo.discountPrice > 0">
<text class="title">活动优惠</text>
<text class="detail">¥{{ fen2yuan(state.orderInfo.discountPrice) }}</text>
@ -185,8 +192,8 @@
<text class="detail all-price">{{ fen2yuan(state.orderInfo.payPrice) }}</text>
</view>
<view
class="notice-item all-rpice-item ss-flex ss-m-t-20"
v-if="state.orderInfo.refundPrice > 0"
class="notice-item all-rpice-item ss-flex ss-m-t-20"
v-if="state.orderInfo.refundPrice > 0"
>
<text class="title">已退款</text>
<text class="detail all-price">{{ fen2yuan(state.orderInfo.refundPrice) }}</text>
@ -198,23 +205,23 @@
<su-fixed bottom placeholder bg="bg-white" v-if="state.orderInfo.buttons?.length">
<view class="footer-box ss-flex ss-col-center ss-row-right">
<button
class="ss-reset-button cancel-btn"
v-if="state.orderInfo.buttons?.includes('cancel')"
@tap="onCancel(state.orderInfo.id)"
class="ss-reset-button cancel-btn"
v-if="state.orderInfo.buttons?.includes('cancel')"
@tap="onCancel(state.orderInfo.id)"
>
取消订单
</button>
<button
class="ss-reset-button pay-btn ui-BG-Main-Gradient"
v-if="state.orderInfo.buttons?.includes('pay')"
@tap="onPay(state.orderInfo.payOrderId)"
class="ss-reset-button pay-btn ui-BG-Main-Gradient"
v-if="state.orderInfo.buttons?.includes('pay')"
@tap="onPay(state.orderInfo.payOrderId)"
>
继续支付
</button>
<button
class="ss-reset-button cancel-btn"
v-if="state.orderInfo.buttons?.includes('combination')"
@tap="
class="ss-reset-button cancel-btn"
v-if="state.orderInfo.buttons?.includes('combination')"
@tap="
sheep.$router.go('/pages/activity/groupon/detail', {
id: state.orderInfo.combinationRecordId,
})
@ -223,23 +230,23 @@
拼团详情
</button>
<button
class="ss-reset-button cancel-btn"
v-if="state.orderInfo.buttons?.includes('express')"
@tap="onExpress(state.orderInfo.id)"
class="ss-reset-button cancel-btn"
v-if="state.orderInfo.buttons?.includes('express')"
@tap="onExpress(state.orderInfo.id)"
>
查看物流
</button>
<button
class="ss-reset-button cancel-btn"
v-if="state.orderInfo.buttons?.includes('confirm')"
@tap="onConfirm(state.orderInfo.id)"
class="ss-reset-button cancel-btn"
v-if="state.orderInfo.buttons?.includes('confirm')"
@tap="onConfirm(state.orderInfo.id)"
>
确认收货
</button>
<button
class="ss-reset-button cancel-btn"
v-if="state.orderInfo.buttons?.includes('comment')"
@tap="onComment(state.orderInfo.id)"
class="ss-reset-button cancel-btn"
v-if="state.orderInfo.buttons?.includes('comment')"
@tap="onComment(state.orderInfo.id)"
>
评价
</button>
@ -251,8 +258,8 @@
<script setup>
import sheep from '@/sheep';
import { onLoad } from '@dcloudio/uni-app';
import { reactive } from 'vue';
import { isEmpty } from 'lodash';
import { reactive, ref } from 'vue';
import { isEmpty } from 'lodash-es';
import {
fen2yuan,
formatOrderStatus,
@ -260,6 +267,8 @@
handleOrderButtons,
} from '@/sheep/hooks/useGoods';
import OrderApi from '@/sheep/api/trade/order';
import DeliveryApi from '@/sheep/api/trade/delivery';
import PickUpVerify from '@/pages/order/pickUpVerify.vue';
const statusBarHeight = sheep.$platform.device.statusBarHeight * 2;
const headerBg = sheep.$url.css('/static/img/shop/order/order_bg.png');
@ -270,6 +279,9 @@
comeinType: '', //
});
// ========== ==========
const systemStore = ref({}); //
//
const onCopy = () => {
sheep.$helper.copyText(state.orderInfo.no);
@ -294,7 +306,7 @@
uni.showModal({
title: '提示',
content: '确定要取消订单吗?',
success: async function (res) {
success: async function(res) {
if (!res.confirm) {
return;
}
@ -321,10 +333,10 @@
// 2.mpConfirm,App.vueshow
let isOpenBusinessView = true;
if (
sheep.$platform.name === 'WechatMiniProgram' &&
!isEmpty(state.orderInfo.wechat_extra_data) &&
isOpenBusinessView &&
!ignore
sheep.$platform.name === 'WechatMiniProgram' &&
!isEmpty(state.orderInfo.wechat_extra_data) &&
isOpenBusinessView &&
!ignore
) {
mpConfirm(orderId);
return;
@ -366,6 +378,7 @@
},
});
}
// #endif
//
@ -375,6 +388,8 @@
});
}
const pickUpVerifyRef = ref();
async function getOrderDetail(id) {
//
let res;
@ -389,6 +404,14 @@
if (res.code === 0) {
state.orderInfo = res.data;
handleOrderButtons(state.orderInfo);
//
if (res.data.pickUpStoreId) {
const { data } = await DeliveryApi.getDeliveryPickUpStore(res.data.pickUpStoreId);
systemStore.value = data || {};
}
if (state.orderInfo.deliveryType === 2 && state.orderInfo.payStatus) {
pickUpVerifyRef.value && pickUpVerifyRef.value.markCode(res.data.pickUpVerifyCode);
}
} else {
sheep.$router.back();
}
@ -429,7 +452,7 @@
color: rgba(#fff, 0.9);
width: 100%;
background: v-bind(headerBg) no-repeat,
linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
linear-gradient(90deg, var(--ui-BG-Main), var(--ui-BG-Main-gradient));
background-size: 750rpx 100%;
box-sizing: border-box;

View File

@ -0,0 +1,263 @@
<template>
<view class='order-details'>
<!-- 自提商品核销 -->
<view v-if="orderInfo.deliveryType === 2 && orderInfo.payStatus" class="writeOff borRadius14">
<view class="title">核销信息</view>
<view class="grayBg flex-center">
<view class="pictrue">
<image
v-if="!!painterImageUrl"
:src="painterImageUrl"
:style="{width: `${state.qrcodeSize}px`, height: `${state.qrcodeSize}px`}"
:show-menu-by-longpress="true"
/>
</view>
</view>
<view class="gear">
<image :src="sheep.$url.static('/static/images/writeOff.png', 'local')"></image>
</view>
<view class="num">{{ orderInfo.pickUpVerifyCode }}</view>
<view class="rules">
<!-- TODO puhui999: 需要后端放回使用 receiveTime 即可 -->
<!-- <view class="item">-->
<!-- <view class="rulesTitle flex flex-wrap align-center">-->
<!-- 核销时间-->
<!-- </view>-->
<!-- <view class="info">-->
<!-- 每日-->
<!-- <text class="time">2020-2-+52</text>-->
<!-- </view>-->
<!-- </view>-->
<view class="item">
<view class="rulesTitle flex flex-wrap align-center">
<text class="iconfont icon-shuoming1"></text>
使用说明
</view>
<view class="info">可将二维码出示给店员扫描或提供数字核销码</view>
</view>
</view>
</view>
<view v-if="orderInfo.deliveryType === 2" class="map flex flex-wrap align-center ss-row-between borRadius14">
<view>自提地址信息</view>
<view class="place cart-color flex flex-wrap flex-center" @tap="showMaoLocation">
查看位置
</view>
</view>
<!-- 海报画板默认隐藏只用来生成海报生成方式为主动调用 -->
<l-painter
v-if="showPainter"
isCanvasToTempFilePath
pathType="url"
@success="setPainterImageUrl"
hidden
ref="painterRef"
/>
</view>
</template>
<script setup>
import sheep from '@/sheep';
import { reactive, ref } from 'vue';
const props = defineProps({
orderInfo: {
type: Object,
default() {},
},
systemStore:{
type: Object,
default() {},
}
});
const state = reactive({
qrcodeSize: 145
})
/**
* 打开地图
*/
const showMaoLocation = () => {
console.log(props.systemStore);
if (!props.systemStore.latitude || !props.systemStore.longitude) {
sheep.$helper.toast('缺少经纬度信息无法查看地图!');
return
}
uni.openLocation({
latitude: props.systemStore.latitude,
longitude: props.systemStore.longitude,
scale: 8,
name: props.systemStore.name,
address: props.systemStore.areaName + props.systemStore.detailAddress,
});
}
/**
* 拨打电话
*/
const makePhone = () => {
uni.makePhoneCall({
phoneNumber: props.systemStore.phone
})
}
const painterRef = ref(); //
const painterImageUrl = ref(); // url
const showPainter = ref(true)
//
const renderPoster = async (poster) => {
await painterRef.value.render(poster);
};
//
const setPainterImageUrl = (path) => {
console.log(path,'path')
painterImageUrl.value = path;
showPainter.value = false
};
/**
* 生成核销二维码
*/
const markCode = (text) => {
renderPoster({
css: {
width: `${state.qrcodeSize}px`,
height: `${state.qrcodeSize}px`
},
views:[
{
type: 'qrcode',
text: text,
css: {
width: `${state.qrcodeSize}px`,
height: `${state.qrcodeSize}px`
}
}
]
})
console.log(text,'text')
}
defineExpose({
markCode
})
</script>
<style scoped lang="scss">
// TODO puhui999: bug
.borRadius14 {
border-radius: 14rpx !important;
}
.cart-color {
color: #E93323 !important;
border: 1px solid #E93323 !important
}
.order-details{
border-radius: 10rpx;
margin: 0 20rpx 20rpx 20rpx;
}
.order-details .writeOff {
background-color: #fff;
margin-top: 15rpx;
padding-bottom: 50rpx;
}
.order-details .writeOff .title {
font-size: 30rpx;
color: #282828;
height: 87rpx;
border-bottom: 1px solid #f0f0f0;
padding: 0 24rpx;
line-height: 87rpx;
}
.order-details .writeOff .grayBg {
background-color: #f2f5f7;
width: 590rpx;
height: 384rpx;
border-radius: 20rpx 20rpx 0 0;
margin: 50rpx auto 0 auto;
padding-top: 55rpx;
}
.order-details .writeOff .grayBg .pictrue {
width: 290rpx;
height: 290rpx;
}
.order-details .writeOff .grayBg .pictrue image {
width: 100%;
height: 100%;
}
.order-details .writeOff .gear {
width: 590rpx;
height: 30rpx;
margin: 0 auto;
}
.order-details .writeOff .gear image {
width: 100%;
height: 100%;
}
.order-details .writeOff .num {
background-color: #f0c34c;
width: 590rpx;
height: 84rpx;
color: #282828;
font-size: 48rpx;
margin: 0 auto;
border-radius: 0 0 20rpx 20rpx;
text-align: center;
padding-top: 4rpx;
}
.order-details .writeOff .rules {
margin: 46rpx 30rpx 0 30rpx;
border-top: 1px solid #f0f0f0;
padding-top: 10rpx;
}
.order-details .writeOff .rules .item {
margin-top: 20rpx;
}
.order-details .writeOff .rules .item .rulesTitle {
font-size: 28rpx;
color: #282828;
}
.order-details .writeOff .rules .item .rulesTitle .iconfont {
font-size: 30rpx;
color: #333;
margin-right: 8rpx;
margin-top: 5rpx;
}
.order-details .writeOff .rules .item .info {
font-size: 28rpx;
color: #999;
margin-top: 7rpx;
}
.order-details .writeOff .rules .item .info .time {
margin-left: 20rpx;
}
.order-details .map {
height: 86rpx;
font-size: 30rpx;
color: #282828;
line-height: 86rpx;
border-bottom: 1px solid #f0f0f0;
margin-top: 15rpx;
background-color: #fff;
padding: 0 24rpx;
}
.order-details .map .place {
font-size: 26rpx;
width: 176rpx;
height: 50rpx;
border-radius: 25rpx;
line-height: 50rpx;
text-align: center;
}
</style>

View File

@ -0,0 +1,275 @@
<template>
<s-layout title="选择自提门店" :bgStyle="{ color: '#FFF' }">
<view class="storeBox" ref="container">
<view class="storeBox-box" v-for="(item, index) in state.storeList" :key="index" @tap="checked(item)">
<view class="store-img">
<image :src="item.logo" class="img" />
</view>
<view class="store-cent-left">
<view class="store-name">{{ item.name }}</view>
<view class="store-address line1">
{{ item.areaName }}{{ ', ' + item.detailAddress }}
</view>
</view>
<view class="row-right ss-flex-col ss-col-center">
<view>
<!-- #ifdef H5 -->
<a class="store-phone" :href="'tel:' + item.phone">
<view class="iconfont">
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</view>
</a>
<!-- #endif -->
<!-- #ifdef MP -->
<view class="store-phone" @click="call(item.phone)">
<view class="iconfont">
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</view>
</view>
<!-- #endif -->
</view>
<view class="store-distance ss-flex ss-row-center" @tap.stop="showMaoLocation(item)">
<text class="addressTxt" v-if="item.distance">距离{{ item.distance.toFixed(2) }}千米</text>
<text class="addressTxt" v-else>查看地图</text>
<view class="iconfont">
<view class="ss-rest-button">
<text class="_icon-forward" />
</view>
</view>
</view>
</view>
</view>
</view>
</s-layout>
</template>
<script setup>
import DeliveryApi from '@/sheep/api/trade/delivery';
import { onMounted, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import sheep from '@/sheep';
const LONGITUDE = 'user_longitude';
const LATITUDE = 'user_latitude';
const state = reactive({
loaded: false,
loading: false,
storeList: [],
system_store: {},
locationShow: false,
user_latitude: 0,
user_longitude: 0,
});
const call = (phone) => {
uni.makePhoneCall({
phoneNumber: phone,
});
};
const selfLocation = () => {
// #ifdef H5
const jsWxSdk = sheep.$platform.useProvider('wechat').jsWxSdk;
if (jsWxSdk.isWechat()) {
jsWxSdk.getLocation((res) => {
console.log(res);
state.user_latitude = res.latitude;
state.user_longitude = res.longitude;
uni.setStorageSync(LATITUDE, res.latitude);
uni.setStorageSync(LONGITUDE, res.longitude);
getList();
});
} else {
// #endif
uni.getLocation({
type: 'gcj02',
success: (res) => {
try {
state.user_latitude = res.latitude;
state.user_longitude = res.longitude;
uni.setStorageSync(LATITUDE, res.latitude);
uni.setStorageSync(LONGITUDE, res.longitude);
} catch {
}
getList();
},
complete: () => {
getList();
},
});
// #ifdef H5
}
// #endif
};
const showMaoLocation = (e) => {
// #ifdef H5
const jsWxSdk = sheep.$platform.useProvider('wechat').jsWxSdk;
if (jsWxSdk.isWechat()) {
jsWxSdk.openLocation({
latitude: Number(e.latitude),
longitude: Number(e.longitude),
name: e.name,
address: `${e.areaName}-${e.detailAddress}`
});
} else {
// #endif
uni.openLocation({
latitude: Number(e.latitude),
longitude: Number(e.longitude),
name: e.name,
address: `${e.areaName}-${e.detailAddress}`,
success: function() {
console.log('success');
},
});
// #ifdef H5
}
// #endif
};
/**
* 选中门店
*/
const checked = (addressInfo) => {
uni.$emit('SELECT_PICK_UP_INFO', {
addressInfo,
});
sheep.$router.back();
};
/**
* 获取门店列表数据
*/
const getList = async () => {
if (state.loading || state.loaded) {
return;
}
state.loading = true;
const { data, code } = await DeliveryApi.getDeliveryPickUpStoreList({
latitude: state.user_latitude,
longitude: state.user_longitude,
});
if (code !== 0) {
return;
}
state.loading = false;
state.storeList = data;
};
onMounted(() => {
if (state.user_latitude && state.user_longitude) {
getList();
} else {
selfLocation();
getList();
}
});
onLoad(() => {
try {
state.user_latitude = uni.getStorageSync(LATITUDE);
state.user_longitude = uni.getStorageSync(LONGITUDE);
} catch (e) {
// error
}
});
</script>
<style lang="scss" scoped>
.line1 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap
}
.geoPage {
position: fixed;
width: 100%;
height: 100%;
top: 0;
z-index: 10000;
}
.storeBox {
width: 100%;
background-color: #fff;
padding: 0 30rpx;
}
.storeBox-box {
width: 100%;
height: auto;
display: flex;
align-items: center;
padding: 23rpx 0;
justify-content: space-between;
border-bottom: 1px solid #eee;
}
.store-cent {
display: flex;
align-items: center;
width: 80%;
}
.store-cent-left {
//width: 45%;
flex: 2;
}
.store-img {
flex: 1;
width: 120rpx;
height: 120rpx;
border-radius: 6rpx;
margin-right: 22rpx;
}
.store-img .img {
width: 100%;
height: 100%;
}
.store-name {
color: #282828;
font-size: 30rpx;
margin-bottom: 22rpx;
font-weight: 800;
}
.store-address {
color: #666666;
font-size: 24rpx;
}
.store-phone {
width: 50rpx;
height: 50rpx;
color: #fff;
border-radius: 50%;
display: block;
text-align: center;
line-height: 48rpx;
background-color: #e83323;
margin-bottom: 22rpx;
text-decoration: none;
}
.store-distance {
font-size: 22rpx;
color: #e83323;
}
.iconfont {
font-size: 20rpx;
}
.row-right {
flex: 2;
//display: flex;
//flex-direction: column;
//align-items: flex-end;
//width: 33.5%;
}
</style>

View File

@ -4,18 +4,18 @@ export default {
// 微信相关
wechat: {
// 小程序订阅消息
subscribeTemplate: (params) =>
request({
url: 'third/wechat/subscribeTemplate',
method: 'GET',
params: {
platform: 'miniProgram',
},
custom: {
showError: false,
showLoading: false,
},
}),
// subscribeTemplate: (params) =>
// request({
// url: 'third/wechat/subscribeTemplate',
// method: 'GET',
// params: {
// platform: 'miniProgram',
// },
// custom: {
// showError: false,
// showLoading: false,
// },
// }),
// 获取微信小程序码
// TODO @puhui999这个接口挪到 /Users/yunai/Java/yudao-mall-uniapp/sheep/api/member/social.js

View File

@ -1,4 +1,5 @@
import request from '@/sheep/request';
import { isEmpty } from '@/sheep/helper/utils';
const OrderApi = {
// 计算订单信息
@ -13,6 +14,15 @@ const OrderApi = {
if (!(data.addressId > 0)) {
delete data2.addressId;
}
if (!(data.pickUpStoreId > 0)) {
delete data2.pickUpStoreId;
}
if (isEmpty(data.receiverName)) {
delete data2.receiverName;
}
if (isEmpty(data.receiverMobile)) {
delete data2.receiverMobile;
}
if (!(data.combinationActivityId > 0)) {
delete data2.combinationActivityId;
}

BIN
static/images/writeOff.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB