You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

564 lines
19 KiB

<script setup lang="ts">
import { addressDetailApi, addressListApi, computedPriceApi, orderCreateApi, orderLoadPreApi } from '~/server/orderApi'
import { AddressInfo, OrderInfoVo } from '~/types/order'
import { defaultAddressInfo, defaultOrderInfo } from '~/pages/order/defaultOrder'
import { getCouponTime, linkNavigateTo } from '~/utils/util'
import { ref, reactive } from 'vue'
import { addressDefault } from '~/pages/users/defaultUser'
import { couponTypeFilter } from '~/utils/filter'
//获取浏览器值
const route = useRoute()
const orderNo = ref<string>(<string>route.query.orderNo)
const loading = ref<boolean>(false)
/**
* 预下单详情
*/
const orderInfoVo = reactive<OrderInfoVo>(defaultOrderInfo())
const platCouponFee = ref<string>('') //平台优惠券金额
const platUserCouponId = ref<number>(0) //平台优惠券id
const merCouponFee = ref<string>('') //商户优惠券id
const orderMerchantRequestList = ref<Array<T>>([]) //提交订单数据
const orderProNum = ref<number>(0)
const addressId = ref<number>(0) //地址id
const merchantOrderVoList = ref<Array<T>>([])
const orderType = ref<number>(0) // 0普通订单,1视频号订单,2秒杀订单
const getloadPreOrder = async () => {
loading.value = true
await orderLoadPreApi(orderNo.value)
.then((res: any) => {
Object.assign(orderInfoVo, res)
if (res.addressId) addressId.value = res.addressId
//地址详情
getaddressInfo()
merchantOrderVoList.value = res.merchantInfoList //商户端数据
platCouponFee.value = res.platCouponFee //平台优惠券总金额
platUserCouponId.value = res.platUserCouponId //平台优惠券id
merCouponFee.value = res.merCouponFee //店铺优惠券总金额
orderType.value = res.type //订单类型
res.merchantInfoList.map((item:any) => {
orderMerchantRequestList.value.push({
shippingType: item.shippingType,
merId: item.merId,
remark: item.remark,
userCouponId: item.userCouponId,
})
})
orderProNum.value = res.orderProNum
loading.value = false
})
.catch((res:any) => {
linkNavigateTo(`/users/order_list`, { type: 1 })
loading.value = false
})
}
getloadPreOrder()
/**
* 获取默认收货地址或者获取某条地址信息
*/
const addressInfo = reactive<AddressInfo>(defaultAddressInfo())
const getaddressInfo = async () => {
let data = await addressDetailApi(addressId.value)
Object.assign(addressInfo, data)
}
/**
* 地址列表
*/
const showAddress = ref<boolean>(true) //是否展示更多地址
const { data: addressList, refresh } = await useAsyncData(async () => addressListApi())
/**
* 选择使用优惠券,优惠券弹窗
* @param {Object} item优惠券对象
* @param {Number} merId商户id
* @param {Number} index索引
* @param {Object} itm 商户对象
*/
const loadingCoupon = ref<boolean>(true)
const dialogVisible = ref<boolean>(false)
const coupon = reactive({
list: [],
})
const merId = ref<number>(0)
const activeIndexCoupon = ref<number>(0)
const couponObj = reactive({}) //选中这条优惠券的对象
const couponTap = (item: any, merIds: number, index: number, itm: any) => {
loadingCoupon.value = true
coupon.list = JSON.parse(JSON.stringify(item))
merId.value = merIds
if (merIds !== 0) {
activeIndexCoupon.value = index
orderMerchantRequestList.value[activeIndexCoupon.value].userCouponId = itm.userCouponId
}
if (coupon.list.length === 0) return
dialogVisible.value = true
loadingCoupon.value = false
}
//选择优惠券
const getCouponUser = (index: number, item: any) => {
if (!item.isChecked && !item.isChoose) return
coupon.list.map((i) => {
if (!item.isChecked) i.isChecked = false
})
item.isChecked = !item.isChecked
Object.assign(couponObj, item)
}
//确认选中优惠券
const handleConfirm = async () => {
let item = couponObj
if (Object.keys(item).length > 0) {
if (item.merId === 0) {
platUserCouponId.value = item.isChecked ? item.id : 0
} else {
orderMerchantRequestList.value[activeIndexCoupon.value].userCouponId = item.isChecked ? item.id : 0
}
}
coupon.list = []
dialogVisible.value = false
await computedPrice()
}
//买家留言
const handleMessage = (remark: string, index: number) => {
orderMerchantRequestList.value[index].remark = remark
}
/**
* 计算订单价格
*/
const isUseIntegral = ref<boolean>(false) //是否使用积分
const merUserCouponId = ref<number>(0) //店铺使用优惠券的id
const computedPrice = () => {
loading.value = true
let fromData = {
addressId: addressId.value,
isUseIntegral: isUseIntegral.value,
orderMerchantRequestList: orderMerchantRequestList.value,
preOrderNo: orderNo.value,
platUserCouponId: platUserCouponId.value,
}
computedPriceApi(fromData)
.then((res: any) => {
let data = res
//usedIntegral 使用的积分,surplusIntegral 剩余积分
if (data.merOrderResponseList && data.merOrderResponseList.length) {
data.merOrderResponseList.map((item, i) => {
merchantOrderVoList.value[i].freightFee = item.freightFee
merchantOrderVoList.value[i].couponFee = item.couponFee
})
} else {
merchantOrderVoList.value[0].freightFee = data.freightFee
merchantOrderVoList.value[0].couponFee = data.couponFee
}
Object.assign(orderInfoVo, data)
merCouponFee.value = data.merCouponFee //店铺优惠券总金额
orderInfoVo.userIntegral = data.surplusIntegral //使用的积分`
orderInfoVo.surplusIntegral = data.usedIntegral //剩余积分
platCouponFee.value = data.platCouponFee //平台优惠金额
//选中商户优惠券的值
merchantOrderVoList.value[activeIndexCoupon.value].merCouponUserList =
data.merOrderResponseList[activeIndexCoupon.value].merCouponUserList //商户数据
merUserCouponId.value = data.merOrderResponseList[activeIndexCoupon.value].userCouponId //店铺使用优惠券的id
loading.value = false
})
.catch((err) => {
loading.value = false
})
}
/**
* 创建订单 立即下单
*/
const handleCreatOrder = async () => {
if (!addressId.value) return feedback.msgWarning('请选择下单地址')
loading.value = true
let fromData = {
addressId: addressId.value,
isUseIntegral: isUseIntegral.value,
orderMerchantRequestList: orderMerchantRequestList.value,
preOrderNo: orderNo.value,
platUserCouponId: platUserCouponId.value,
}
await orderCreateApi(fromData)
.then((res) => {
linkNavigateTo(`/order/order_payment`, { orderNo: res.orderNo })
loading.value = false
})
.catch((err) => {
loading.value = false
})
}
//取消选择
const handleCancel = () => {
dialogVisible.value = false
}
/**
* 使用积分
*/
const handleIntegral = async () => {
await computedPrice()
}
/**
* 添加收货地址
*/
const selAddressData = ref<any[]>([]) //选中的地址数组
const { bool: dialogVisibleAddress, DialogOpen, DialogClose } = useDialog()
const userAddAddressRef = shallowRef()
const handleAddAddress = async () => {
Object.assign(addressInfo, addressDefault())
selAddressData.value = []
DialogOpen()
}
//关闭弹窗
const handleSubmitClose = () => {
DialogClose()
}
//添加成功回调
const handleSubmitAddress = (addressIds: number) => {
addressId.value = addressIds
refresh()
computedPrice()
DialogClose()
}
/**
* 选择地址
*/
const currentAddress = ref<number | null>(null)
const handleChangeAddress = async (index: number, item) => {
currentAddress.value = index
Object.assign(addressInfo, item)
addressId.value = item.id
await computedPrice()
}
// 跳入页面
const handleGoPage = (id: number) => {
linkNavigateTo(`/merchant/merchant_home`, { merId: id })
}
</script>
<template>
<div class="wrapper_1200" v-loading="loading">
<page-header title="提交订单"></page-header>
<!--收货地址-->
<div class="w-100% borRadius bg-#FFF pt-30px pb-20px px-30px mbtom20">
<div class="fontColor333 text-16px mb20px">收货地址</div>
<div class="acea-row justify-between address-list" :class="showAddress ? 'on' : ''">
<div
v-if="addressList.length < 10"
@click="handleAddAddress"
class="cursors w-560px h-90px lh-90px fontColor333 text-14px b-rd-8px address-item text-center"
>
<span class="fontColor6 text-14px">+</span> 添加收货地址
</div>
<div
@click="handleChangeAddress(index, item)"
v-for="(item, index) in addressList"
:key="item.id"
:class="addressId === item.id ? ' address-check' : 'address-item'"
class="w-560px mb-20px b-rd-8px py-20px px-20px cursors"
>
<div class="fontColor333 text-14px mb10px font-500 oppoSans-M">
{{ item.realName }} {{ item.phone }}
<span
v-show="item.isDefault"
class="text-12px bg-color text-#fff b-rd-2px px-4px py-1px mr-6px oppoSans-R font-400"
>默认</span
>
</div>
<div class="fontColor6 text-14px line1 oppoSans-R font-400">
{{ item.province }}{{ item.city }}{{ item.district }}{{ item.street }}{{ item.detail }}
</div>
</div>
</div>
<div
v-if="!showAddress"
class="cursors fontColor6 text-14px text-center p-t-10px"
@click="showAddress = !showAddress"
>
收起 <span class="iconfont icon-gao"></span>
</div>
<div
v-if="showAddress"
class="fontColor6 text-14px text-center cursors p-t-10px"
@click="showAddress = !showAddress"
>
查看全部地址 <span class="iconfont icon-di"></span>
</div>
</div>
<!-- 商品信息-->
<div
v-for="(item, index) in merchantOrderVoList"
:key="item.id"
class="w-100% borRadius bg-#FFF pt-30px pb-20px px-30px mbtom20"
>
<div @click="handleGoPage(item.merId)" class="acea-row mb-30px cursors items-center">
<div v-if="item.isSelf">
<span
class="lh-12px bg-color inline-block text-12px text-#fff b-rd-2px py-2px mr-6px px-4px relative"
style="top: -1px"
>自营</span
>
</div>
<div class="fontColor333 text-14px">{{ item.merName }}</div>
</div>
<div v-for="(itm, indexs) in item.orderInfoList" :key="indexs">
<confirm-product :list="itm" :productType="orderInfoVo.type"></confirm-product>
</div>
<el-divider border-style="dashed" />
<div v-if="orderType === 0" class="acea-row justify-between mbtom30">
<div class="text-16px fontColor6">店铺优惠</div>
<div @click="couponTap(item.merCouponUserList, item.merId, index, item)" class="fonts16 fontColor333 cursors">
{{
item.merCouponUserList.length === 0
? '暂无优惠券'
: item.couponFee == 0
? `有${item.merCouponUserList.length}张优惠券可选`
: `-¥${item.couponFee}`
}}<span
v-show="Number(item.merCouponUserList.length > 0)"
class="iconfont icon-xiala"
style="font-size: 12px"
></span>
</div>
</div>
<div class="acea-row justify-between mbtom30">
<div class="text-16px fontColor6">快递费用</div>
<div class="fonts16 fontColor333">{{ item.freightFee == 0 ? '免运费' : '¥' + item.freightFee }}</div>
</div>
<div class="acea-row justify-between">
<div class="text-16px fontColor6 mr30px">买家留言</div>
<textarea
class="textarea w-1041px"
@blur="handleMessage(item.remark, index)"
v-model="item.remark"
maxlength="150"
rows="5"
placeholder="建议提前与商家协商"
></textarea>
</div>
<!-- <div class="flex justify-end text-14px fontColor333" style="align-items: baseline">-->
<!-- 店铺合计(含运费):<span class="text-14px font-color fw-600">¥</span-->
<!-- ><span class="text-22px font-color fw-600">{{ item.proTotalFee }}</span>-->
<!-- </div>-->
</div>
<!--结算信息-->
<div class="w-100% borRadius bg-#FFF pt-30px pb-20px px-30px">
<div v-if="orderType === 0" class="acea-row justify-between mbtom30">
<div class="text-16px fontColor6">平台优惠</div>
<div @click="couponTap(orderInfoVo.platCouponUserList, 0, 0, null)" class="fonts16 fontColor333 cursors">
{{
orderInfoVo.platCouponUserList.length === 0
? '暂无优惠券'
: platCouponFee == 0
? `有${orderInfoVo.platCouponUserList.length}张优惠券可选`
: `-¥${platCouponFee}`
}}<span
v-show="Number(orderInfoVo.platCouponUserList.length > 0)"
class="iconfont icon-xiala"
style="font-size: 12px"
></span>
</div>
</div>
<div v-if="orderInfoVo.integralDeductionSwitch && orderType === 0" class="acea-row justify-between mbtom30">
<div class="text-16px fontColor6">积分抵扣</div>
<div class="fonts16 fontColor333 isUseIntegral">
<el-radio-group v-model="isUseIntegral" @change="handleIntegral">
<el-radio :label="false" class="fonts16" size="large">不使用</el-radio>
<el-radio :label="true" size="large">
<div>
{{ isUseIntegral ? '使用积分' : '当前积分' }}
<span class="num font_color">{{
isUseIntegral ? orderInfoVo.surplusIntegral : orderInfoVo.userIntegral
}}</span>
<span v-if="orderInfoVo.deductionPrice != 0"> 可抵¥{{ orderInfoVo.deductionPrice }}</span>
</div>
</el-radio>
</el-radio-group>
</div>
</div>
<!--费用详情-->
<div class="w-1140px borRadius bg-#F7F7F7 px-20px py-20px">
<div class="acea-row justify-between mb15px">
<div class="text-14px fontColor6">运费</div>
<div class="text-14px fontColor333">
{{ orderInfoVo.freightFee == '0' ? '免运费' : '¥' + orderInfoVo.freightFee }}
</div>
</div>
<div v-if="orderType === 0" class="acea-row justify-between mb15px">
<div class="text-14px fontColor6">商家优惠</div>
<div class="text-14px fontColor333">
-¥<span class="">{{ orderInfoVo.merCouponFee }}</span>
</div>
</div>
<div v-if="orderType === 0" class="acea-row justify-between mb15px">
<div class="text-14px fontColor6">平台优惠</div>
<div class="text-14px fontColor333">
-¥<span class="">{{ orderInfoVo.platCouponFee }}</span>
</div>
</div>
<div v-if="orderInfoVo.integralDeductionSwitch && orderType === 0" class="acea-row justify-between mb15px">
<div class="text-14px fontColor6">积分抵扣</div>
<div class="text-14px fontColor333">
-¥<span class="">{{ orderInfoVo.deductionPrice || 0 }}</span>
</div>
</div>
<div class="acea-row justify-between">
<div class="text-14px fontColor6">实付款</div>
<div class="text-14px font-color fw-600">
<span class="oppoSans-M">¥</span
><span class="text-22px"
><span class="dinProRegular">{{ orderInfoVo.payFee }}</span></span
>
</div>
</div>
</div>
<div class="flex justify-end mt-30px">
<div class="w-120px handleBtn h-44px lh-44px cursors" @click="handleCreatOrder" style="font-size: 16px">
立即下单
</div>
</div>
</div>
<!--优惠券-->
<el-dialog
modal-class="createDialog"
v-model="dialogVisible"
:align-center="true"
:width="780"
:append-to-body="true"
:show-close="false"
center
title="选择优惠券"
>
<div class="acea-row justify-between" v-loading="loadingCoupon">
<div
@click="getCouponUser(index, item)"
v-for="item in coupon.list"
:key="item.id"
class="coupon-list flex-y-center check nocheck w-350px h-110px"
>
<div class="pos-relative w-100px h-110px coupon-item items-center">
<div class="text-12px font-color pos-absolute top-2px left-10px">{{ couponTypeFilter(item.category) }}</div>
<div class="font-color text-14px">
<span class="oppoSans-M">¥</span><span class="text-30px dinProRegular">{{ item.money }}</span>
</div>
<div class="font-color text-12px">满{{ item.minPrice }}元可用</div>
</div>
<div class="ml-15px h-110px pos-relative coupon-item w-250px">
<div class="pos-absolute top-10px right-10px">
<div
v-if="!item.isChecked && item.isChoose"
class="iconfont icon-weixuanzhong cursors"
style="font-size: 18px"
></div>
<div
v-if="item.isChecked && item.isChoose"
class="cursors iconfont icon-xuanzhong font-color"
style="font-size: 18px"
></div>
<div
v-if="!item.isChoose && !item.isChecked"
class="noCheck w-15px h-15px b-rd-50% borderSol bg-#F5F5F5"
></div>
</div>
<div class="text-14px fontColor333 fw-500 mb-15px line2 h-36px lh-19px w-196px">{{ item.name }}</div>
<div class="text-14px text-#999">{{ getCouponTime(item.startTime, item.endTime) }}</div>
</div>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm"> 确认 </el-button>
</span>
</template>
</el-dialog>
<!--地址弹窗-->
<add-address
ref="userAddAddressRef"
:addressInfo="addressInfo"
:isShowDialog="dialogVisibleAddress"
@handleSubmitAddress="handleSubmitAddress"
v-if="dialogVisibleAddress"
@handleSubmitClose="handleSubmitClose"
:selAddressData="selAddressData"
></add-address>
</div>
</template>
<style lang="scss">
.createDialog {
.el-button {
width: 120px !important;
height: 44px !important;
border-radius: 25px 25px 25px 25px;
}
.el-dialog {
background-color: #f5f5f5 !important;
}
:deep(.el-dialog) {
background-color: #f5f5f5 !important;
--el-dialog-bg-color: #f5f5f5 !important;
--el-bg-color: #f5f5f5 !important;
border-radius: 16px 16px 16px 16px;
}
.el-dialog__body {
max-height: 70vh !important;
overflow-y: auto;
padding: 0 30px 0 30px;
}
}
</style>
<style lang="scss" scoped>
:deep(.el-radio__label) {
font-size: 16px !important;
}
.fonts16 {
font-size: 16px !important;
}
:deep(.el-dialog) {
background-color: #f5f5f5 !important;
--el-dialog-bg-color: #f5f5f5 !important;
--el-bg-color: #f5f5f5 !important;
border-radius: 16px 16px 16px 16px;
}
.coupon {
&-list {
background-image: url('@/assets/images/coupon.png');
margin-bottom: 20px;
}
&-item {
display: flex;
flex-direction: column;
justify-content: center;
}
}
.address {
&-list {
&.on {
height: 106px;
overflow: hidden;
}
}
&-check {
border: 1px solid #e93323;
}
&-item {
border: 1px solid #cccccc;
}
}
.btn {
height: 50px;
line-height: 50px;
border-radius: 33px 33px 33px 33px;
}
</style>