yshop意向点餐系统v1.2.2

This commit is contained in:
hupeng committed 2023-12-17 10:19:51 +08:00
1 parent d03982bf66
commit fc575265c3
4685 files changed
+518513 -182051

No files matched your search

+245
View File
@@ -0,0 +1,245 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="cart-popup">
<view class="top flex justify-between">
<text>已点{{ getCartGoodsNumber }}份</text>
<text @tap="handleCartClear">清空</text>
</view>
<scroll-view class="cart-list" scroll-y>
<view class="wrapper">
<uv-empty mode="car" v-if="cart.length == 0"></uv-empty>
<view class="item" v-for="(item, index) in cart" :key="index">
<view class="left">
<view class="name">{{ item.name }}</view>
<view class="props">{{ item.valueStr }}</view>
</view>
<view class="center">
<text>¥{{ item.price }}</text>
</view>
<view class="right">
<button type="default" plain size="mini" class="btn" hover-class="none"
@tap="handleCartItemReduce(index)">
<view class="iconfont iconsami-select"></view>
</button>
<view class="number">{{ item.number }}</view>
<button type="primary" class="btn" size="min" hover-class="none"
@tap="handleCartItemAdd(index)">
<view class="iconfont iconadd-select"></view>
</button>
</view>
</view>
</view>
</scroll-view>
</view>
<view class="fixed-bottom flex justify-between align-center bg-white ">
<view class="mx-2 ont-weight-light">应付:<text class="text-danger">¥{{ getCartGoodsPrice }}</text></view>
<view><uv-button type="warning" color="#dd524d" :customStyle="customStyle" size="large" text="去结算" @click="toPay"></uv-button></view>
</view>
<uv-toast ref="uToast"></uv-toast>
</template>
<script setup>
import {
ref,
computed
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onShow} from '@dcloudio/uni-app'
const main = useMainStore()
const { orderType,address, store,location,isLogin } = storeToRefs(main)
const title = ref('购物车')
const cart = ref([])
const uToast = ref()
// onLoad(() => {
// cart.value = uni.getStorageSync('cart')
// })
onShow(() => {
//cart.value = []
cart.value = uni.getStorageSync('cart')
})
const getCartGoodsNumber = computed(() => { //计算购物车总数
if(cart.value.length == 0) {
return 0
}
return cart.value.reduce((acc, cur) => acc + cur.number, 0)
})
const getCartGoodsPrice = computed(() =>{ //计算购物车总价
if(cart.value.length == 0) {
return 0
}
let price = cart.value.reduce((acc, cur) => acc + cur.number * cur.price, 0);
return parseFloat(price).toFixed(2);
})
const customStyle = computed(() =>{
return {
paddingLeft:'60rpx',
paddingRight:'60rpx'
}
})
const handleCartItemAdd = (index) => {
cart.value[index].number += 1
uni.setStorageSync('cart', JSON.parse(JSON.stringify(cart.value)))
}
const handleCartItemReduce = (index) => {
if (cart.value[index].number === 1) {
cart.value.splice(index, 1)
} else {
cart.value[index].number -= 1
}
if (!cart.value.length) {
cartPopupVisible.value = false
}
uni.setStorageSync('cart', JSON.parse(JSON.stringify(cart.value)))
}
const handleCartClear = () => { //清空购物车
uni.showModal({
title: '提示',
content: '确定清空购物车么',
success: ({
confirm
}) => {
if (confirm) {
cart.value = []
uni.setStorageSync('cart', JSON.parse(JSON.stringify(cart.value)))
}
}
})
}
const toPay = () => {
if(cart.value.length == 0){
uToast.value.show({message:'请先去点餐哦',type: 'error'});
return;
}
if (!isLogin.value) {
uni.navigateTo({
url: '/pages/components/pages/login/login'
})
return
} else {
if (store.value.status == 0) {
uToast.value.show({message:'不在店铺营业时间内',type: 'error'});
return;
}
// 判断当前是否在配送范围内
if (orderType.value == 'takeout' && store.value.distance < store.value.far) {
uToast.value.show({message:'选中的地址不在配送范围',type: 'error'});
return;
}
uni.showLoading({
title: '加载中'
})
uni.setStorageSync('cart', JSON.parse(JSON.stringify(cart.value)))
uni.navigateTo({
url: '/pages/components/pages/pay/pay'
})
}
uni.hideLoading()
}
</script>
<style lang="scss" scoped>
.cart-popup {
.top {
background-color: $bg-color-primary;
//color: $color-primary;
color: #5A5B5C;
padding: 10rpx 30rpx;
font-size: 24rpx;
text-align: right;
}
.cart-list {
background-color: #ffffff;
width: 100%;
overflow: hidden;
min-height: 1vh;
max-height: 60vh;
.wrapper {
height: 100%;
display: flex;
flex-direction: column;
padding: 0 30rpx;
margin-bottom: 156rpx;
.item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 0;
position: relative;
&::after {
content: ' ';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background-color: $border-color;
height: 2rpx;
transform: scaleY(0.6);
}
.left {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
margin-right: 30rpx;
.name {
font-size: $font-size-sm;
color: $text-color-base;
}
.props {
color: $text-color-assist;
font-size: 24rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.center {
margin-right: 120rpx;
font-size: $font-size-base;
}
.right {
display: flex;
align-items: center;
justify-content: space-between;
.btn {
width: 46rpx;
height: 46rpx;
border-radius: 100%;
padding: 0;
text-align: center;
line-height: 46rpx;
}
.number {
font-size: $font-size-base;
width: 46rpx;
height: 46rpx;
text-align: center;
line-height: 46rpx;
}
}
}
}
}
}
</style>
@@ -0,0 +1,182 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="container">
<view class="form-box">
<view class="form">
<list-cell :hover="false">
<view class="form-input">
<view class="label">收货人</view>
<input class="input" placeholder="请输入收货人" v-model="form.realName" placeholder-class="text-color-assist" />
</view>
</list-cell>
<list-cell :hover="false">
<view class="form-input">
<view class="label">联系方式</view>
<input class="input" placeholder="请输入收货人联系方式" v-model="form.phone" placeholder-class="text-color-assist" />
</view>
</list-cell>
<list-cell :hover="false">
<view class="form-input">
<view class="label">收货地址</view>
<view class="input" @click="chooseLocation">{{form.address ? form.address : '请选择收货地址'}}</view>
</view>
</list-cell>
<list-cell :hover="false">
<view class="form-input">
<view class="label">详细地址</view>
<input class="input" placeholder="请输入收货人详细地址" v-model="form.detail" placeholder-class="text-color-assist" />
</view>
</list-cell>
<list-cell :hover="false">
<view class="form-input">
<view class="label">默认地址</view>
<view class="radio-group">
<view class="radio" :class="{'checked': !form.isDefault}" style="margin-right: 10rpx;" @tap="form.isDefault=0">否</view>
<view class="radio" :class="{'checked': form.isDefault}" @tap="form.isDefault=1">是</view>
</view>
</view>
</list-cell>
</view>
<view class="btn-section">
<button type="primary" size="default" @tap="save">保存</button>
</view>
</view>
</view>
</template>
<script setup>
import {
ref,
computed
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onShow } from '@dcloudio/uni-app'
import { formatDateTime,prePage } from '@/utils/util'
import {
getAddressAddAndEdit
} from '@/api/address'
const main = useMainStore()
const { isLogin,addresses } = storeToRefs(main)
const title = ref('编辑地址')
const form = ref({
realName: '',
isDefault: 0,
phone: '',
address: '',
detail: '',
latitude: '',
longitude: ''
})
onLoad((option) => {
//为了方便演示,这里用本地缓存
console.log('option:',option)
if (option.id) {
form.value = addresses.value.find(item => item.id == option.id)
}
})
const save = async() => {
let data = {}
if (form.value.hasOwnProperty('id')) {
data = await getAddressAddAndEdit(form.value);
} else {
data = await getAddressAddAndEdit(form.value);
}
if (data) {
setTimeout(function(){
uni.navigateBack()
}, 2000);
}
}
const chooseLocation = async() => {
uni.chooseLocation({
success: function (res) {
form.value.address = res.address + ' ' + res.name;
form.value.latitude = res.latitude;
form.value.longitude = res.longitude;
}
});
// let [error, res] = await uni.chooseLocation();
// if (res) {
// form.value.address = res.address + ' ' + res.name;
// form.value.latitude = res.latitude;
// form.value.longitude = res.longitude;
// }
}
</script>
<style lang="scss" scoped>
.form-box {
width: 100%;
height: 100%;
padding: 30rpx;
display: flex;
flex-direction: column;
color: $text-color-base;
.form-input {
display: flex;
align-items: center;
width: 100%;
}
.label {
width: 200rpx;
font-size: $font-size-lg;
color: $text-color-base;
font-weight: 500;
}
.input {
flex: 1;
display: flex;
align-items: center;
}
.radio-group {
display: flex;
justify-content: flex-start;
.radio {
padding: 10rpx 30rpx;
border-radius: 6rpx;
border: 2rpx solid $text-color-assist;
color: $text-color-assist;
font-size: $font-size-base;
&.checked {
background-color: $color-primary;
color: $text-color-white;
border: 2rpx solid $color-primary;
}
}
}
.btn-section {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
button {
font-size: $font-size-base;
height: 90rpx;
border-radius: 50rem !important;
width: 85%;
display: flex;
align-items: center;
justify-content: center;
}
}
}
</style>
@@ -0,0 +1,223 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="container">
<view class="main">
<uv-empty v-if="addresses.length == 0" mode="address"></uv-empty>
<template v-else>
<uv-swipe-action>
<uv-swipe-action-item class="address-wrapper" :options="swipeOption"
@click="handleSwipeClick(address.id)" v-for="(address, index) in addresses" :key="index">
<view class="address" @tap="chooseAddress(address)">
<view class="left flex-fill overflow-hidden mr-20">
<view class="font-size-lg font-weight-bold text-truncate"
style="margin-bottom: 10rpx;white-space:normal;">
{{ address.address + ' ' + address.detail }}
</view>
<view class="font-size-sm text-color-assist">
{{ address.realName }} {{ address.isDefault ? '默认' : '' }} {{ address.phone }}
</view>
</view>
<image src="/static/images/edit.png" class="edit-icon" @tap.stop="edit(address.id)"></image>
</view>
</uv-swipe-action-item>
</uv-swipe-action>
</template>
</view>
<view class="btn-box">
<button type="primary" size="default" @tap="add">新增地址</button>
</view>
</view>
</template>
<script setup>
import {
ref,
computed
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onShow } from '@dcloudio/uni-app'
import { formatDateTime,prePage } from '@/utils/util'
import {
addressAll,
addressDelete,
shopGetDistanceFromLocation
} from '@/api/address'
const main = useMainStore()
const { isLogin,addresses,store } = storeToRefs(main)
const title = ref('我的地址')
const scene = ref('menu')
const is_choose = ref(false)
const swipeOption = ref(
[{
text: '删除',
style: {
backgroundColor: '#D12E32'
}
}])
onLoad((option) => {
console.log('option:',option)
is_choose.value = option.is_choose || false
scene.value = option.scene || 'menu'
})
onShow(() => {
init();
})
const init = async() => {
let data = await addressAll();
if (data) {
main.SET_ADDRESSES(data)
}
}
const add = () => {
uni.navigateTo({
url: '/pages/components/pages/address/add'
})
}
const edit = (id) => {
uni.navigateTo({
url: '/pages/components/pages/address/add?id=' + id
})
}
const handleSwipeClick = async(id) => {
let [error, res] = await uni.showModal({
title: '提示',
content: '确定要删除?'
});
if (res && res.confirm) {
let data = await addressDelete({
id: id
});
if (data) {
const index = addresses.value.findIndex(item => item.id == id)
const newaddresses = JSON.parse(JSON.stringify(addresses.value))
newaddresses.splice(index, 1)
main.SET_ADDRESSES(newaddresses)
uni.showToast({
title: '删除成功!',
icon: 'success'
})
}
}
}
const chooseAddress = async(address) => {
if (!is_choose.value) {
return;
}
console.log('scene.value:',scene.value)
if (scene.value == 'menu' || scene.value == 'pay') {
let data = await shopGetDistanceFromLocation({
lat: address.latitude,
lng: address.longitude,
lat2: main.store.lat,
lng2: main.store.lng
});
if (!data) {
return;
}
if (parseFloat(data) > store.value.distance) {
uni.showToast({
title: '不在配送范围!',
icon: 'error'
})
return;
}
main.SET_ADDRESS(address)
main.SET_ORDER_TYPE('takeout')
main.store.far = data
main.store.far_text = data + 'km'
main.SET_STORE(main.store)
main.SET_LOCATION({
latitude: address.lat,
longitude: address.lng
});
if (scene.value == 'menu') {
uni.switchTab({
url: '/pages/menu/menu'
})
} else if (scene.value == 'pay') {
uni.navigateBack();
}
} else if (scene.value == 'scoreShop') {
main.SET_ADDRESS(address)
uni.navigateBack()
}
}
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 100%;
}
.main {
width: 100%;
padding: 30rpx;
display: flex;
flex-direction: column;
padding-bottom: 100rpx;
.address-wrapper {
margin-bottom: 30rpx;
}
.address {
width: 100%;
padding: 40rpx 30rpx;
background-color: #FFFFFF;
display: flex;
justify-content: space-between;
align-items: center;
.right {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
.edit-icon {
width: 50rpx;
height: 50rpx;
flex-shrink: 0;
}
}
}
.btn-box {
height: 100rpx;
background-color: #FFFFFF;
box-shadow: 0 0 20rpx rgba($color: $text-color-assist, $alpha: 0.1);
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 10rpx 0;
display: flex;
align-items: center;
justify-content: center;
button {
height: 80rpx;
width: 80%;
border-radius: 50rem !important;
display: flex;
align-items: center;
justify-content: center;
}
}
</style>
@@ -0,0 +1,229 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view>
<view class="wrap">
<view class="bg-white" v-if="cate == 0">
<uv-tabs activeColor="#f29100" ref="tabs" :list="list" :current="current" @change="change" :scrollable="false" swiperWidth="750"></uv-tabs>
</view>
<view class="bg-white" v-else>
<uv-tabs activeColor="#f29100" ref="tabs" :list="list1" :current="current" @change="change" :scrollable="false" swiperWidth="750"></uv-tabs>
</view>
<swiper class="swiper-box" :current="swiperCurrent" @transition="transition" @animationfinish="animationfinish">
<swiper-item class="swiper-item" v-for="(item, index) in orderList" :key="index">
<scroll-view scroll-y style="height: 100%;width: 100%;" @scrolltolower="reachBottom">
<view class="page-box">
<view v-if="item.length == 0">
<view class="centre" v-if="loadStatus[index] != 'loading'">
<view class="explain">
您还没有相关的账单
<view class="tips">可以去看看有那些想买的</view>
</view>
<view class="btn">
<navigator open-type="switchTab" url="/pages/menu/menu">随便逛逛</navigator>
</view>
</view>
<view v-else>
<u-loadmore :status="loadStatus[index]" bgColor="#f2f2f2"></u-loadmore>
</view>
</view>
<view v-else>
<view class="order" v-for="(res, resIndex) in orderList[index]" :key="resIndex">
<view class="type">
<view>{{res.title}}</view>
<view>{{res.mark}}</view>
</view>
<view class="total">
<view>
{{res.pm == 0 ? '-':'+'}}¥{{res.number}}元
</view>
<view>
{{formatDateTime(res.createTime)}}
</view>
</view>
</view>
<u-loadmore :status="loadStatus[index]" bgColor="#f2f2f2"></u-loadmore>
</view>
</view>
</scroll-view>
</swiper-item>
</swiper>
</view>
</view>
</template>
<script setup>
import {
ref,
watch
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onShow} from '@dcloudio/uni-app'
import { formatDateTime } from '@/utils/util'
import {
balanceGetBillList
} from '@/api/user'
const main = useMainStore()
const { isLogin } = storeToRefs(main)
const title = ref('账单')
const orderList = ref([[], [], [], []])
const list = ref([
{
name: '全部'
},
{
name: '消费'
},
{
name: '充值'
},
{
name: '退款'
}
]
)
const list1 = ref([
{
name: '全部'
},
{
name: '消费'
}
]
)
const current = ref(0)
const swiperCurrent = ref(0)
const tabsHeight =ref(0)
const dx = ref(0)
const loadStatus = ref(['loadmore','loadmore','loadmore','loadmore'])
const page = ref(1)
const pageSize = ref(20)
const tabs = ref()
const cate = ref(0)
onLoad((option) => {
console.log('cate:',option.cate)
cate.value = option.cate
getBill();
})
const getBill = async() => {
if (loadStatus.value[swiperCurrent.value] == 'loading') {
return;
}
loadStatus.value.splice(swiperCurrent.value,1,"loading")
let data = await balanceGetBillList({cate:cate.value,type:swiperCurrent.value,page:page.value,pagesize:pageSize.value});
if (page.value == 1 ){
orderList.value[swiperCurrent.value] = [];
}
if (data && data.length > 0) {
page.value++;
orderList.value[swiperCurrent.value] = orderList.value[swiperCurrent.value].concat(data);
loadStatus.value.splice(swiperCurrent.value,1,"loadmore")
} else{
loadStatus.value.splice(swiperCurrent.value,1,"nomore")
}
}
const reachBottom = () => {
if (loadStatus.value[swiperCurrent.value] == 'nomore') {
return;
}
getBill();
}
// tab栏切换
const change = (e) => {
swiperCurrent.value = e.index;
page.value = 1;
}
const transition = ({ detail: { dx } }) => {
}
const animationfinish = ({ detail }) => {
swiperCurrent.value = detail.current;
current.value = detail.current;
page.value = 1;
getBill();
}
</script>
<style>
/* #ifndef H5 */
page {
height: 100%;
background-color: #f2f2f2;
}
/* #endif */
</style>
<style lang="scss" scoped>
.order {
width: 710rpx;
background-color: #ffffff;
margin: 20rpx auto;
border-radius: 20rpx;
box-sizing: border-box;
padding: 20rpx;
font-size: 28rpx;
.total {
display: inline-block;
text-align: right;
.total-price {
font-size: 36rpx;
}
float: right;
}
.type {
display: inline-block;
}
}
.centre {
text-align: center;
margin: 200rpx auto;
font-size: 32rpx;
image {
width: 164rpx;
height: 164rpx;
border-radius: 50%;
margin-bottom: 20rpx;
}
.tips {
font-size: 24rpx;
color: #999999;
margin-top: 20rpx;
}
.btn {
margin: 80rpx auto;
width: 200rpx;
border-radius: 32rpx;
line-height: 64rpx;
color: #ffffff;
font-size: 26rpx;
background: linear-gradient(270deg, rgba(249, 116, 90, 1) 0%, rgba(255, 158, 1, 1) 100%);
}
}
.wrap {
display: flex;
flex-direction: column;
height: calc(100vh - var(--window-top));
width: 100%;
}
.swiper-box {
flex: 1;
}
.swiper-item {
height: 100%;
}
</style>
@@ -0,0 +1,557 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="container position-relative w-100 h-100 overflow-hidden">
<view class="exchange-box">
<view class="input-box">
<input type="text" v-model="exchange_code" placeholder="请输入兑换码" placeholder-class="text-color-assist font-size-base" />
<button type="primary" @click="exchange">兑换</button>
</view>
</view>
<view class="tabbar">
<view class="tab" :class="{active: activeTabIndex == index}"
v-for="(item, index) in tabs" :key="index" @tap="handleTab(index)">
<view class="title">{{ item.title }}</view>
</view>
</view>
<view class="flex-fill">
<scroll-view scroll-y class="coupon-list" @scrolltolower="getCoupons(activeTabIndex)">
<view class="wrapper" v-if="0 === activeTabIndex">
<uv-empty v-if="myCoupons.length == 0" mode="list"></uv-empty>
<view class="coupon" v-for="(item, index) in myCoupons" :key="index" @tap="openDetailModal(item,index)">
<view class="taobao">
<view class="ticket">
<view class="left">
<image
class="picture"
:src="item.image"
mode="aspectFill"
></image>
<view class="introduce">
<view class="top">
¥
<text class="big">{{item.value}}</text>
<view>
满{{item.least}}减{{item.value}}
</view>
</view>
<view class="type">{{ item.title }}</view>
<view class="date u-line-1">{{formatDateTime(item.startTime, 'yyyy-MM-dd')}}-{{formatDateTime(item.endTime, 'yyyy-MM-dd')}}</view>
</view>
</view>
<view class="right" @click.stop="" v-if="activeTabIndex == 1">
<view class="use immediate-use" :round="true" @tap="receive(item, index)" >立即领取</view>
</view>
<view class="right" @click.stop="" v-if="activeTabIndex == 0">
<view v-if="item.status == 0" class="use immediate-use" :round="true" @tap="useCouponWith(item)" >立即使用</view>
<view v-else class="used">已使用</view>
</view>
</view>
</view>
</view>
</view>
<view class="wrapper" v-if="1 === activeTabIndex">
<uv-empty v-if="notCoupons.length == 0" mode="list"></uv-empty>
<view class="coupon" v-for="(item, index) in notCoupons" :key="index" @tap="openDetailModal(item,index)">
<view class="taobao">
<view class="ticket">
<view class="left">
<image
class="picture"
:src="item.image"
mode="aspectFill"
></image>
<view class="introduce">
<view class="top">
¥
<text class="big">{{item.value}}</text>
<view>
满{{item.least}}减{{item.value}}
</view>
</view>
<view class="type">{{ item.title }}</view>
<view class="date u-line-1">{{formatDateTime(item.startTime, 'yyyy-MM-dd')}}-{{formatDateTime(item.endTime, 'yyyy-MM-dd')}}</view>
</view>
</view>
<view class="right" @click.stop="" v-if="activeTabIndex == 1">
<view class="use immediate-use" :round="true" @tap="receive(item, index)" >立即领取</view>
</view>
<view class="right" @click.stop="" v-if="activeTabIndex == 0">
<view v-if="item.status == 0" class="use immediate-use" :round="true" @tap="useCouponWith(item)" >立即使用</view>
<view v-else class="used">已使用</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
<modal custom :show="detailModalVisible" @cancel="closeDetailModal" width="90%">
<view class="modal-content">
<view class="d-flex font-size-extra-lg text-color-base just-content-center mb-20">{{ coupon.title }}</view>
<view class="d-flex font-size-sm text-color-base mb-20">
有效期:{{formatDateTime(coupon.startTime, 'yyyy-MM-dd')}}-{{formatDateTime(coupon.endTime, 'yyyy-MM-dd')}}
</view>
<view class="d-flex font-size-sm text-color-base mb-20">
领取时间:{{formatDateTime(coupon.createTime)}}
</view>
<view class="d-flex font-size-sm text-color-base mb-20">
券价值:满{{ coupon.least }}减{{ coupon.value }}
</view>
<view class="d-flex font-size-sm text-color-base mb-20" v-if="activeTabIndex == 1">
每人限领:{{ coupon.limit }} 张
</view>
<view class="d-flex font-size-sm text-color-base mb-20">
适用范围:{{typeInfo(coupon.type)}}
</view>
<view class="d-flex font-size-sm text-color-base mb-20">
适用店铺:{{coupon.shopName}}
</view>
<view class="d-flex align-items-center just-content-center" v-if="activeTabIndex == 0">
<button type="primary" @tap="useCoupon" class="use-coupon-btn">立即使用</button>
</view>
<view class="d-flex align-items-center just-content-center" v-if="activeTabIndex == 1">
<button type="primary" @tap="receive(coupon, couponIndex)" class="use-coupon-btn">立即领取</button>
</view>
</view>
</modal>
<!--轻提示-->
<uv-toast ref="uToast"></uv-toast>
</view>
</template>
<script setup>
import {
ref,
watch
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onShow ,onPullDownRefresh,onHide} from '@dcloudio/uni-app'
import { formatDateTime,kmUnit } from '@/utils/util'
import {
couponReceive,
couponMine,
couponIndexApi
} from '@/api/coupon'
const main = useMainStore()
const { isLogin } = storeToRefs(main)
const title = ref('优惠券')
const tabs = ref([
{title: '我的优惠券', page:1, pagesize:10,
coupons: []
},
{title: '未领优惠券', page:1, pagesize:10,
coupons: []
}
])
const activeTabIndex = ref(0)
const detailModalVisible = ref(false)
const coupon = ref({})
const couponIndex = ref(0)
const exchange_code = ref('')
const uToast = ref()
const myCoupons = ref([])
const notCoupons = ref([])
onShow(() => {
getCoupons(0)
})
onPullDownRefresh(() => {
if(activeTabIndex.value == 0) {
myCoupons.value = []
}
if(activeTabIndex.value == 1) {
notCoupons.value = []
}
tabs.value[activeTabIndex.value].page = 1;
getCoupons(activeTabIndex.value)
})
watch(activeTabIndex, () => {
getCoupons(activeTabIndex.value)
})
// 兑换
const exchange = async() => {
let data = await couponReceive({code:this.exchange_code});
if (data) {
uToast.value.show({
message: '兑换成功',
type: 'success'
});
tabs.value[0].coupons = [];
tabs.value[0].page = 1;
getCoupons(0)
tabs.value[1].coupons = [];
tabs.value[1].page = 1;
getCoupons(1)
}
}
// 使用范围
const typeInfo = (type) => {
if (type == 0) {
return '通用'
}
if (type == 1) {
return '自取'
}
if (type == 2) {
return '外卖'
}
}
const handleTab = (index) => {
console.log('activeTabIndex2:',index)
activeTabIndex.value = index
}
const getCoupons = async(type) => {
let page = tabs.value[type].page;
let pagesize = tabs.value[type].pagesize;
// 我的优惠券
let data = [];
if (type == 0) {
myCoupons.value = await couponMine({page:page,pagesize:pagesize});
}
// 未领优惠券
if (type == 1) {
notCoupons.value = await couponIndexApi({page:page,pagesize:pagesize});
}
//console.log('data:',data)
uni.stopPullDownRefresh();
console.log('tabs.value:',tabs.value[type].title)
//tabs.value[type].page++;
}
const openDetailModal = (coupon,index) => {
couponIndex.value = index;
coupon.value = coupon
detailModalVisible.value = true
}
const useCouponWith = (coupon) => {
//coupon.value = coupon
useCoupon();
}
const closeDetailModal = () => {
detailModalVisible.value = false
coupon.value = {}
}
const useCoupon = () => {
uni.switchTab({
url: '/pages/menu/menu'
})
}
const showTip1 = () => {
uni.showToast({
title: '您暂时还没有赠送中卡券哦~',
icon: 'none'
})
}
const showTip2 = () => {
uni.showToast({
title: '您暂时还没有券码哦~',
icon: 'none'
})
}
// 领取优惠券
const receive = async(coupon,index) => {
let data = await couponReceive({id:coupon.id});
if (data) {
uToast.value.show({
message: '领取成功',
type: 'success'
});
detailModalVisible.value = false
}
}
</script>
<style lang="scss" scoped>
/* #ifdef H5 */
page {
height: 100%;
}
/* #endif */
.container {
display: flex;
flex-direction: column;
}
.exchange-box {
flex-shrink: 0;
height: 200rpx;
background-color: #ffffff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.input-box {
display: flex;
align-items: stretch;
width: 70%;
flex-shrink: 0;
input {
flex: 1;
height: 80rpx;
border: 1rpx solid #eee;
border-right: 0;
border-radius: 8rpx 0 0 8rpx;
// padding: 20rpx;
font-size: $font-size-base;
color: $text-color-base;
}
button {
border-radius: 0 8rpx 8rpx 0;
display: flex;
align-items: center;
}
}
}
.tabbar {
flex-shrink: 0;
width: 100%;
height: 120rpx;
display: flex;
align-items: center;
justify-content: center;
.tab {
flex: 1;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: $font-size-base;
color: $text-color-base;
position: relative;
.title {
padding: 15rpx 0;
}
&.active {
color: $color-primary;
.title {
border-bottom: 5rpx solid $color-primary;
}
}
}
}
.bottom-box {
height: 80rpx;
flex-shrink: 0;
.item {
padding: 0 20rpx;
position: relative;
&::after {
content: " ";
border-right: 1rpx solid $text-color-assist;
height: 100%;
position: absolute;
right: 0;
top: 0;
transform: scaleX(0.5) scaleY(0.8);
}
&:nth-last-child(1)::after {
border-right: 0;
}
}
}
.coupon-list {
height: calc(100vh - 120rpx - 200rpx);
/* #ifdef H5 */
height: calc(100vh - 120rpx - 200rpx - 44px);
/* #endif */
}
.wrapper {
padding: 0 20rpx;
display: flex;
flex-direction: column;
.coupon {
display: flex;
flex-direction: column;
background-color: #FFFFFF;
margin-bottom: 30rpx;
//padding: 0 30rpx;
border-radius: 6rpx;
box-shadow: 0 10rpx 10rpx -10rpx rgba(15, 15, 15, 0.1);
position: relative;
&::before {
content: "";
position: absolute;
background-color: $bg-color;
width: 30rpx;
height: 30rpx;
bottom: 65rpx;
left: -15rpx;
border-radius: 100%;
}
&::after {
content: "";
position: absolute;
background-color: $bg-color;
width: 30rpx;
height: 30rpx;
bottom: 65rpx;
right: -15rpx;
border-radius: 100%;
}
.detail {
padding: 20rpx 0;
position: relative;
&::after {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: 0;
border-bottom: 1rpx dashed #c6c6c6;
transform: scaleY(0.5);
}
.coupon-img {
width: 150rpx;
height: 150rpx;
margin-right: 40rpx;
}
}
}
}
.use-coupon-btn {
width: 95%;
border-radius: 50rem !important;
}
.taobao {
background-color: white;
.title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
font-size: 30rpx;
.left {
display: flex;
align-items: center;
}
.store {
font-weight: 500;
}
.buddha {
width: 70rpx;
height: 70rpx;
border-radius: 10rpx;
margin-right: 10rpx;
}
.entrance {
color: $uv-info;
border: solid 2rpx $uv-info;
line-height: 48rpx;
padding: 0 30rpx;
background: none;
border-radius: 15px;
}
}
.ticket {
display: flex;
.left {
width: 70%;
padding: 20rpx;
background-color: white;//rgb(255, 245, 244);
border-radius: 20rpx;
border-right: dashed 2rpx rgb(224, 215, 211);
display: flex;
.picture {
//width: 172rpx;
border-radius: 20rpx;
width: 190rpx;
height: 190rpx;
}
.introduce {
margin-left: 10rpx;
.top{
color:$uv-warning;
font-size: 28rpx;
.big{
font-size: 60rpx;
font-weight: bold;
margin-right: 10rpx;
}
}
.type{
font-size: 28rpx;
color: $uv-info-dark;
}
.date{
margin-top: 10rpx;
font-size: 20rpx;
color: $uv-info-dark;
}
}
}
.right {
width: 30%;
padding: 40rpx 20rpx;
background-color: white;//rgb(255, 245, 244);
border-radius: 20rpx;
display: flex;
align-items: center;
.use {
height: auto;
padding: 0 20rpx;
font-size: 24rpx;
border-radius: 40rpx;
color: #ffffff!important;
background-color: $uv-warning!important;
line-height: 40rpx;
color: rgb(117, 142, 165);
margin-left: 20rpx;
}
.used {
height: auto;
padding: 0 20rpx;
font-size: 24rpx;
border-radius: 40rpx;
//color: #ffffff!important;
//background-color: $u-type-warning!important;
line-height: 40rpx;
//color: rgb(117, 142, 165);
margin-left: 20rpx;
}
}
.right_log {
text-align: center;
width: 30%;
padding: 80rpx 0rpx;
background-color: white;//rgb(255, 245, 244);
border-radius: 20rpx;
align-items: center;
}
}
}
</style>
@@ -0,0 +1,326 @@
<template>
<layout>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="wrap">
<view class="top"></view>
<view class="content">
<view class="title">欢迎登录</view>
<input class="u-border-bottom" type="number" v-model="mobile" placeholder="请输入手机号" />
<view class="tips">未注册的手机号验证后自动创建账号</view>
<view style="display: flex;">
<view style="width: 50%;">
<input style="height: 100rpx;" class="u-border-bottom" type="number" v-model="captcha" placeholder="请输入验证码" />
</view>
<view style="width: 50%;">
<button style="height: 100rpx;" @tap="getCaptcha" :style="[captchaStyle]" class="getCaptcha">
{{captchaText}}
<uv-code :seconds="seconds" @end="endCaptcha" @start="startCaptcha" ref="uCode" @change="changeCapcha"></uv-code>
<!-- <u-verification-code :seconds="seconds" @end="endCaptcha" @change="changeCapcha" @start="startCaptcha" ref="uCode" >
</u-verification-code> -->
</button>
</view>
</view>
<button @tap="submit" style="color:#fff;background-color: #f9ae3d;" type="primary" class="login">登录</button>
</view>
<view class="buttom">
<view class="loginType">
<!-- #ifdef MP-WEIXIN -->
<button type="primary" size="default" class="login-btn" open-type="getPhoneNumber" @getphonenumber="loginForWechatMini">
<!-- <image src="/static/images/mine/wechat.png"></image> -->
手机号快捷登录
</button>
<!-- #endif -->
</view>
<view class="hint">
<!-- <label class="label"> -->
<radio value="isChecked" @tap.stop="onChange" />
我已经阅读并遵守
<text class="link" @tap="serv(29,'用户协议')">《用户协议》</text>与
<text class="link" @tap="serv(30,'隐私政策')">《隐私政策》</text>
<!-- </label> -->
</view>
</view>
<uv-toast ref="uToast"></uv-toast>
</view>
</layout>
</template>
<script setup>
import {
ref,
computed
} from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useMainStore } from '@/store/store'
import {
userLoginForWechatMini,
smsSend,
userLogin
} from '@/api/auth'
import * as util from '@/utils/util'
import { mobile as testMobible } from '@/uni_modules/uv-ui-tools/libs/function/test'
const main = useMainStore()
const title = ref('登录')
const mobile = ref('')
const captcha = ref('')
const captchaText = ref('获取验证码')
const password = ref('')
const seconds = ref(60)
const isChecked = ref(false)
const openid = ref(main.openid)
const uToast = ref()
const uCode = ref()
const captchaStyle = computed(() => {
let style = {};
if(mobile.value && captchaText.value == '获取验证码') {
style.color = "#fff";
style.backgroundColor = '#f9ae3d';
}
return style;
});
const loginForWechatMini = async (e) => {
if(!isChecked.value){
uToast.value.show({
message: '请勾选下面协议',
type: 'error'
});
return
}
if (e.detail.encryptedData && e.detail.iv) {
let data = await userLoginForWechatMini({
encryptedData: e.detail.encryptedData,
iv: e.detail.iv,
openid: openid.value
});
if (data) {
main.SET_MEMBER(data.userInfo);
main.SET_TOKEN(data.accessToken);
uToast.value.show({
title: '登录成功',
type: 'success'
});
setTimeout(function() {
uni.navigateBack();
}, 2000);
}
}
}
const getCaptcha = async () => {
if (testMobible(mobile.value) == false) {
uToast.value.show({
message: '手机号码格式不对',
type: 'error'
});
return
}
let data = await smsSend({
mobile: mobile.value,
scene: 1
});
if (data) {
uCode.value.start();
}
}
// 验证码开始计时
const startCaptcha = () => {
console.log('start')
}
// 验证码结束
const endCaptcha = () => {
console.log('end')
captchaText.value = '获取验证码';
}
const changeCapcha = (text) => {
console.log('change:' + text)
captchaText.value = text;
}
// 提交
const submit = () => {
if (testMobible(mobile.value) == false) {
uToast.value.show({
message: '手机号码格式不对',
type: 'error'
});
return
}
if(!isChecked.value){
uToast.value.show({
message: '请勾选下面协议',
type: 'error'
});
return
}
login()
}
// 登录
const login = async () => {
let from = 'routine'
// #ifdef H5
from = 'h5'
if(util.isWeixin()){
from = 'wechat'
}
// #endif
let data = await userLogin({
mobile: mobile.value,
code: captcha.value,
from: from,
openid: openid.value
})
if (data) {
uni.setStorage({
key: 'userinfo',
data: data.userInfo
});
uni.setStorage({
key: 'accessToken',
data: data.accessToken
});
main.SET_MEMBER(data.userInfo);
main.SET_TOKEN(data.accessToken);
uToast.value.show({
message: '登录成功',
type: 'success'
});
setTimeout(function() {
uni.navigateBack();
}, 2000);
}
}
const serv = (id,name) => {
uni.navigateTo({
url: '/pages/components/pages/mine/content?id=' + id + '&name=' + name
})
}
const onChange = () => {
isChecked.value = !isChecked.value
}
</script>
<style lang="scss" scoped>
.wrap {
background-color: #ffffff;
font-size: 28rpx;
position: relative;
height: 100%;
.content {
width: 600rpx;
margin: 0 auto;
.title {
text-align: left;
font-size: 60rpx;
font-weight: 500;
margin-bottom: 100rpx;
}
input {
text-align: left;
margin-bottom: 10rpx;
padding-bottom: 6rpx;
}
.tips {
color: $uv-info;
margin-bottom: 60rpx;
margin-top: 8rpx;
}
.getCaptcha {
background-color: rgb(253, 243, 208);
color: $uv-tips-color;
border: none;
font-size: 30rpx;
padding: 12rpx 0;
&::after {
border: none;
}
}
.login {
background-color: rgb(253, 243, 208);
color: $uv-tips-color;
border: none;
font-size: 30rpx;
padding: 12rpx 0;
margin-top: 40rpx;
&::after {
border: none;
}
}
.alternative {
color: $uv-tips-color;
display: flex;
justify-content: space-between;
margin-top: 30rpx;
}
}
.buttom {
//position: absolute;
bottom: 0;
//display: flex;
//flex-direction: column;
//align-items: center;
//justify-content: center;
.loginType {
padding: 80rpx;
//justify-content:space-between;
.login-btn {
background-color: #1aad19!important;
width: 100%;
border-radius: 50rem !important;
display: flex;
align-items: center;
justify-content: center;
padding: 10rpx 0;
text-align: center;
image {
width: 36rpx;
height: 30rpx;
margin-right: 10rpx;
vertical-align: middle;
}
}
}
.hint {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 40rpx;
font-size: 20rpx;
color: $uv-tips-color;
.link {
color: $uv-warning;
}
}
}
}
</style>
@@ -0,0 +1,54 @@
<template>
<!-- <layout> -->
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="top">
<button type="primary" size="default" class="login-btn" @click="logout">
确定退出登录
</button>
<uv-toast ref="uToast"></uv-toast>
</view>
<!-- </layout> -->
</template>
<script setup>
import {
ref
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
const main = useMainStore()
const { member,isLogin } = storeToRefs(main)
const uToast = ref()
const title = ref('退出')
const logout = () => {
uni.removeStorageSync( 'userinfo');
uni.removeStorageSync( 'accessToken');
main.SET_MEMBER({});
main.SET_TOKEN('');
uToast.value.show({
message: '已退出',
type: 'success'
});
setTimeout(function() {
uni.navigateBack();
}, 2000);
}
</script>
<style lang="scss" scoped>
.top {
display: flex;
height: 100%;
}
button{
margin: auto;
}
</style>
@@ -0,0 +1,48 @@
<template>
<layout>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view>
<rich-text :nodes="content"></rich-text>
</view>
</layout>
</template>
<script setup>
import {
ref
} from 'vue'
import { onLoad,onShow} from '@dcloudio/uni-app'
import {
mineServiceContent
} from '@/api/user'
const title = ref('内容')
const content = ref('')
onLoad((option) => {
if (option.name) {
title.value = option.name
}
if (option.id) {
getContent(option.id);
}
})
const getContent = async(id) => {
let data = await mineServiceContent({id:id});
if (data) {
content.value = data.content;
}
}
</script>
<style lang="scss" scoped>
</style>
@@ -0,0 +1,236 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="container d-flex flex-column">
<view class="flex-fill form">
<list-cell :hover="false">
<view class="form-input w-100 d-flex align-items-center">
<view class="label">头像</view>
<view class="input flex-fill">
<view class="form-input w-100 d-flex align-items-center" style="position: relative;">
<view class="flex user-box">
<view class="mr-1">
<uv-avatar :src="member.avatar" size="60"></uv-avatar>
</view>
<view v-if="!member.avatar" class="flex-1" style="right:0;height: 60rpx;">
<button style="background-color: #dd524d;color:#fff;" size='mini' open-type="chooseAvatar" @chooseavatar="chooseavatar" type="success">更改头像</button>
</view>
</view>
</view>
</view>
</view>
</list-cell>
<list-cell :hover="false">
<view class="form-input w-100 d-flex align-items-center">
<view class="label">昵称</view>
<view class="input flex-fill">
<input type="nickname" placeholder="请填写昵称" placeholder-class="text-color-assist font-size-base"
v-model="member.nickname">
</view>
</view>
</list-cell>
<list-cell :hover="false">
<view class="form-input w-100 d-flex align-items-center" style="position: relative;">
<view class="label">手机号码</view>
<view class="input flex-fill">
<input type="text" v-model="member.mobile" disabled>
</view>
</view>
</list-cell>
<list-cell :hover="false">
<view class="form-input w-100 d-flex align-items-center">
<view class="label">性别</view>
<view class="input flex-fill">
<view class="radio-group">
<view class="radio" :class="{'checked': member.gender == '0'}" style="margin-right: 10rpx;" @tap="member.gender=0">先生</view>
<view class="radio" :class="{'checked': member.gender == '1'}" @tap="member.gender=1">女士</view>
</view>
</view>
</view>
</list-cell>
<list-cell :hover="false" :arrow="!member.birthday">
<view class="form-input w-100 d-flex align-items-center">
<view class="label">生日</view>
<view class="input flex-fill">
<picker mode="date" :value="member.birthday" :start="startDate" :end="endDate" @change="handleDateChange">
{{member.birthday ? member.birthday : '无'}}
</picker>
</view>
</view>
</list-cell>
<list-cell :hover="false" last>
<view class="form-input w-100 d-flex align-items-center">
<view class="label">加入时间</view>
<view class="input flex-fill">
<input type="text" v-model="member.createTime" disabled>
</view>
</view>
</list-cell>
</view>
<view class="btn-box d-flex align-items-center just-content-center">
<button type="primary" class="save-btn" @tap="save">保存</button>
</view>
</view>
</template>
<script setup>
import {
ref,
computed
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onShow} from '@dcloudio/uni-app'
import { formatDateTime } from '@/utils/util'
import {
userEdit
} from '@/api/user'
import { VUE_APP_UPLOAD_URL } from '@/config';
const main = useMainStore()
const { openid, lang } = storeToRefs(main)
const title = ref('用户设置')
//const currentDate = ref('')
const date = ref('')
const member = ref({})
onLoad(() => {
member.value = main.member;
//this.$util
member.value.createTime = formatDateTime(member.value.createTime);
})
onShow(() => {
date.value = getDate({format: true})
})
const startDate = computed(() => {
return getDate('start');
})
const endDate = computed(() => {
return getDate('end');
})
const chooseavatar = (e) => {
console.log('detal:',e.detail);
uni.uploadFile({
url: VUE_APP_UPLOAD_URL,
filePath: e.detail.avatarUrl,
name: 'file',
header: {
Authorization: 'Bearer ' + member.value.accessToken,
lang: lang.value,
'content-type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
success(uploadFileResult){
console.log('uploadFileResult:',uploadFileResult)
if (uploadFileResult) {
const upload = JSON.parse(uploadFileResult.data);
console.log('upload:',upload.data)
member.value.avatar = upload.data;
}
},
fail(e){
console.log('网络链接错误');
console.log(e)
}
});
}
const getDate = (type) => {
const date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
if (type === 'start') {
year = year - 60;
} else if (type === 'end') {
year = year + 2;
}
month = month > 9 ? month : '0' + month;;
day = day > 9 ? day : '0' + day;
return `${year}-${month}-${day}`;
}
const handleDateChange = (e) => {
member.value.birthday = e.target.value
}
const save = async() => {
let data = await userEdit({
nickname: member.value.nickname,
mobile: member.value.mobile,
gender: member.value.gender,
birthday: member.value.birthday,
avatar: member.value.avatar
});
if (data) {
const member = Object.assign(main.member, member.value)
main.SET_MEMBER(member)
}
}
</script>
<style lang="scss" scoped>
page {
height: 100%;
}
.container {
padding: 20rpx 30rpx;
}
.form {
border-radius: 8rpx;
}
.form-input {
.label {
width: 160rpx;
font-size: $font-size-base;
color: $text-color-base;
}
.input {
}
.radio-group {
display: flex;
justify-content: flex-start;
.radio {
padding: 10rpx 30rpx;
border-radius: 6rpx;
border: 2rpx solid $text-color-assist;
color: $text-color-assist;
font-size: $font-size-base;
&.checked {
background-color: $color-primary;
color: $text-color-white;
border: 2rpx solid $color-primary;
}
}
}
}
.btn-box {
height: calc((100vh - 40rpx) / 2);
}
.save-btn {
width: 90%;
border-radius: 50rem !important;
font-size: $font-size-lg;
}
.logout-btn {
width: 90%;
border-radius: 50rem !important;
font-size: $font-size-lg;
background-color:rgb(237, 81, 29);
}
</style>
@@ -0,0 +1,488 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="container" style="padding:20rpx;">
<view style="padding-bottom: 100rpx;">
<view class="bg-white">
<view class="section">
<!-- store info begin -->
<list-cell :hover="false">
<view class="w-100 d-flex align-items-center">
<view class="d-flex flex-column w-60">
<view class="w-100 font-size-lg text-color-base text-truncate">{{ order.shop.name }}</view>
</view>
<view class="d-flex justify-content-end align-items-center w-40">
<view class="iconfont-yshop icon-mobile" @click="makePhoneCall(order.shop)" style="font-size: 45rpx;margin-right: 40rpx;"></view>
<view class="iconfont-yshop icon-location" @click="openLocation(order.shop)" style="font-size: 45rpx;"></view>
</view>
</view>
</list-cell>
<!-- store info end -->
<list-cell :hover="false" padding="50rpx 30rpx">
<view class="w-100 d-flex flex-column">
<view class="d-flex align-items-center just-content-center">
<view class="sort-num">{{ order.numberId }}</view>
</view>
<!-- steps begin -->
<view class="d-flex just-content-center">
<view class="steps d-flex flex-column w-80">
<view class="steps__img-column">
<view class="steps__img-column-item">
<view class="iconfont-yshop icon-lamp"></view>
</view>
<view class="steps__img-column-item">
<view class="iconfont-yshop icon-daojishi" v-if="{active: order.paid == 1 && order.status == 0}"></view>
<view class="iconfont-yshop icon-daojishi unactive" v-else></view>
</view>
<view class="steps__img-column-item" v-if="order.orderType == 'takeout'">
<view class="iconfont-yshop icon-takeout" v-if="order.status == 1"></view>
<view class="iconfont-yshop icon-takeout unactive" v-else></view>
</view>
<view class="steps__img-column-item" >
<view class="iconfont-yshop icon-doorbell" v-if="order.status >= 2"></view>
<view class="iconfont-yshop icon-doorbell unactive" v-else></view>
</view>
</view>
<view class="steps__text-column">
<view class="steps__text-column-item active">
<view class="steps__column-item-line bg-transparent"></view>
<view class="steps__text-column-item-text">已下单</view>
<view class="steps__column-item-line"></view>
</view>
<view class="steps__text-column-item activ" :class="{active: order.paid == 1}">
<view class="steps__column-item-line"></view>
<view class="steps__text-column-item-text">制作中</view>
<view class="steps__column-item-line"></view>
</view>
<view class="steps__text-column-item" :class="{active: order.status == 1}" v-if="order.orderType == 'takeout'">
<view class="steps__column-item-line"></view>
<view class="steps__text-column-item-text">配送中</view>
<view class="steps__column-item-line bg-transparent"></view>
</view>
<view class="steps__text-column-item" :class="{active: order.status >= 2}">
<view class="steps__column-item-line"></view>
<view class="steps__text-column-item-text">
{{ order.orderType == 'takeout' ? '已送达' : '请取餐' }}
</view>
<view class="steps__column-item-line bg-transparent"></view>
</view>
</view>
</view>
</view>
<!-- steps end -->
<view v-if="order.status==0 && order.paid > 0" class="d-flex just-content-center align-items-center font-size-base text-color-assist mb-40">
您前面还有 <text class="text-color-primary mr-10 ml-10">{{order.preNum}}</text> 单待制作
</view>
<!-- goods begin -->
<view class="w-100 d-flex flex-column position-relative mt-30" style="margin-bottom: -40rpx;">
<view class="w-100 d-flex align-items-center mb-40" v-for="(good, index) in order.products" :key="index">
<view class="d-flex flex-column w-60 overflow-hidden">
<view class="font-size-lg text-color-base mb-10 text-truncate">{{ good.title }}</view>
<view class="font-size-sm text-color-assist text-truncate">{{ good.spec }}</view>
</view>
<view class="d-flex w-40 align-items-center justify-content-between pl-30">
<view class="font-size-base text-color-base">x{{ good.number }}</view>
<view class="font-size-base text-color-base font-weight-bold">¥{{ good.price }}</view>
</view>
</view>
</view>
<!-- goods end -->
</view>
</list-cell>
</view>
<view class="section">
<!-- goods begin -->
<list-cell :hover="false" padding="30rpx 30rpx">
<view class="w-100 d-flex flex-column position-relative">
<view class="w-100 d-flex align-items-center mb-40" v-for="(good, index) in order.cartInfo" :key="index">
<image :src="good.image" mode="aspectFill" class="image"></image>
<view class="d-flex flex-column w-60 overflow-hidden">
<view class="font-size-lg text-color-base mb-10 text-truncate">{{ good.title }}</view>
<view class="font-size-sm text-color-assist text-truncate">{{ good.spec }}</view>
</view>
<view class="d-flex w-40 align-items-center justify-content-between pl-30">
<view class="font-size-base text-color-base">x{{ good.number }}</view>
<view class="font-size-base text-color-base font-weight-bold">¥{{ good.price }}</view>
</view>
</view>
</view>
</list-cell>
<!-- goods end -->
<!-- payment and amount begin -->
<list-cell :hover="false" padding="50rpx 30rpx">
<view class="w-100 d-flex flex-column">
<view class="pay-cell">
<view>支付方式</view>
<view class="font-weight-bold">{{ order._status._payType }}</view>
</view>
<view class="pay-cell">
<view>订单金额</view>
<view class="font-weight-bold">¥{{ order.totalPrice }}</view>
</view>
<view class="pay-cell" v-if="order.orderType == 'takeout'">
<view>配送费</view>
<view class="font-weight-bold">¥{{ order.payPostage }}</view>
</view>
<view class="pay-cell">
<view>优惠金额</view>
<view class="font-weight-bold">¥{{ order.couponPrice }}</view>
</view>
<view class="pay-cell">
<view>实付金额</view>
<view class="font-weight-bold">¥{{ order.payPrice }}</view>
</view>
</view>
</list-cell>
<!-- payment and amount end -->
</view>
<view class="section">
<!-- order info begin -->
<list-cell :hover="false" padding="50rpx 30rpx">
<view class="w-100 d-flex flex-column">
<view class="pay-cell">
<view>下单时间</view>
<view class="font-weight-bold">{{ formatDateTime(order.createTime )}}</view>
</view>
<view class="pay-cell">
<view>下单门店</view>
<view class="font-weight-bold">{{ order.shop.name }}</view>
</view>
<view class="pay-cell">
<view>订单号</view>
<view class="font-weight-bold">{{ order.id }}</view>
</view>
</view>
</list-cell>
<!-- order info end -->
</view>
<!-- order other info begin -->
<list-cell :hover="false" padding="50rpx 30rpx 20rpx" last>
<view class="w-100 d-flex flex-column">
<view class="pay-cell">
<view>享用方式</view>
<view class="font-weight-bold">{{order.orderType == 'takein' ? '自取' : '外卖'}}</view>
</view>
<view class="pay-cell">
<view>取餐时间</view>
<view class="font-weight-bold">{{order.getTime ? formatDateTime(order.getTime) : '立即取餐'}}</view>
</view>
<view class="pay-cell">
<view>制作完成时间</view>
<view class="font-weight-bold">{{ order.deliveryTime ? formatDateTime(order.deliveryTime) : '无' }}</view>
</view>
<view class="pay-cell">
<view>备注</view>
<view class="font-weight-bold">{{ order.remark ? order.remark : '无' }}</view>
</view>
</view>
</list-cell>
<!-- order other info end -->
</view>
<view class="fixed-bottom flex justify-end bg-white p-2" v-if="order.paid > 0 && order.refundStatus == 0">
<view class="mr-1"><uv-button type="success" v-if="order.status < 2" :plain="true" size="small" text="确认收到餐" @click="receive(order)"></uv-button></view>
<view><uv-button type="warning" :plain="true" size="small" text="申请退款" @click="refund(order)"></uv-button></view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue'
import { onLoad} from '@dcloudio/uni-app'
import { formatDateTime } from '@/utils/util'
import {
orderDetail,
orderReceive,
} from '@/api/order'
const title = ref('订单详情')
const order = ref({
shop:{name:''},
_status:{_payType:''}
})
const numForMading = ref(5)
onLoad((option) => {
detail(option.id);
})
const detail = async(id) => {
let data = await orderDetail(id);
if (data) {
order.value = data;
}
}
const openLocation = () => {
let shop = order.value.shop;
uni.openLocation({
address: shop.addressMap + shop.address + " " + shop.name,
latitude: parseFloat(shop.lat),
longitude: parseFloat(shop.lng),
fail(res) {
console.log(res);
}
});
}
const makePhoneCall = () =>{
let shop = order.value.shop;
uni.makePhoneCall({
phoneNumber: shop.mobile,
fail(res) {
console.log(res)
}
})
}
// 确认收到货
const receive = async(order) => {
let data = await orderReceive({uni:order.orderId});
if (data) {
await getOrders(true)
}
}
//提交退款
const refund = (order) => {
uni.navigateTo({
url: '/pages/components/pages/orders/refund?orderId=' + order.orderId + '&payPrice=' + order.payPrice + '&totalPrice=' + order.totalPrice
})
}
</script>
<style lang="scss" scoped>
.image {
width: 120rpx;
height: 120rpx;
margin-right: 30rpx;
border-radius: 8rpx;
}
// @mixin arch {
// content: "";
// position: absolute;
// background-color: $bg-color;
// width: 30rpx;
// height: 30rpx;
// bottom: -15rpx;
// z-index: 10;
// border-radius: 100%;
// }
// .section {
// position: relative;
// &::before {
// @include arch;
// left: -15rpx;
// }
// &::after {
// @include arch;
// right: -15rpx;
// }
// }
.pay-cell {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
font-size: $font-size-base;
color: $text-color-base;
margin-bottom: 40rpx;
&:nth-last-child(1) {
margin-bottom: 0;
}
}
.invote-box {
position: absolute;
width: 100%;
left: 0;
top: 0;
display: flex;
justify-content: center;
align-items: center;
image {
width: 30rpx;
height: 30rpx;
}
}
.btn-box {
background-color: #ffffff;
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 120rpx;
box-shadow: 0 0 20rpx rgba($color: #000000, $alpha: 0.1);
display: flex;
align-items: center;
justify-content: space-evenly;
z-index: 11;
.item {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 10rpx;
flex: 1;
flex-shrink: 0;
button {
width: 100%;
border-radius: 50rem !important;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
}
}
}
/* #ifdef H5 */
page {
min-height: 100%;
background-color: $bg-color;
}
/* #endif */
.order-box {
padding: 20rpx;
/* #ifdef H5 */
margin-bottom: 100rpx;
/* #endif */
}
.drinks-img {
width: 260rpx;
height: 260rpx;
}
.tips {
margin: 60rpx 0 80rpx;
line-height: 48rpx;
}
.drink-btn {
width: 320rpx;
border-radius: 50rem !important;
margin-bottom: 40rpx;
font-size: $font-size-base;
line-height: 3.0;
}
@mixin arch {
content: "";
position: absolute;
background-color: $bg-color;
width: 30rpx;
height: 30rpx;
bottom: -15rpx;
z-index: 10;
border-radius: 100%;
}
.section {
position: relative;
&::before {
@include arch;
left: -15rpx;
}
&::after {
@include arch;
right: -15rpx;
}
}
.pay-cell {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
font-size: $font-size-base;
color: $text-color-base;
margin-bottom: 40rpx;
&:nth-last-child(1) {
margin-bottom: 0;
}
}
.sort-num {
font-size: 64rpx;
font-weight: bold;
color: $text-color-base;
line-height: 2;
}
.steps__img-column {
display: flex;
margin: 30rpx 0;
.steps__img-column-item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
image {
width: 80rpx;
height: 80rpx;
}
.unactive {
color: #919293;
}
}
}
.steps__text-column {
display: flex;
margin-bottom: 40rpx;
.steps__text-column-item {
flex: 1;
display: inline-flex;
display: flex;
align-items: center;
justify-content: center;
font-size: $font-size-base;
color: $text-color-assist;
&.active {
color: $text-color-base;
font-weight: bold;
.steps__column-item-line {
background-color: $text-color-base;
}
}
.steps__column-item-line{
flex: 1;
height: 2rpx;
background-color: #919293;
transform: scaleY(0.5);
}
.steps__text-column-item-text {
margin: 0 8px;
}
}
}
.icon-lamp, .icon-daojishi, .icon-takeout, .icon-doorbell{
font-size: 60rpx;
}
.iconfont-yshop {
color: #dd524d;
}
</style>
@@ -0,0 +1,181 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="container">
<view class="bg-white">
<uv-tabs :list="tabList" :current="current" @change="change" keyName="name" :scrollable="false"></uv-tabs>
</view>
<view class="orders-list d-flex flex-column w-100" style="padding: 20rpx; padding-bottom: 0;">
<view class="order-item" v-for="(item, index) in orders" :key="index" style="margin-bottom: 30rpx;" @tap="detail(item.orderId)">
<list-cell :hover="false">
<view class="w-100 d-flex align-items-center">
<view class="flex-fill d-flex flex-column">
<view class="font-size-lg text-color-base" style="margin-bottom: 20rpx;">
{{ item.shop.name }}
</view>
<view class="font-size-sm text-color-assist">取餐号:{{ item.numberId }}</view>
<view class="font-size-sm text-color-assist">订单编号:{{ item.orderId }}</view>
</view>
<view class="font-size-lg text-color-primary">
{{ item._status._title }}
</view>
</view>
</list-cell>
<list-cell :hover="false" last>
<view class="w-100 d-flex flex-column">
<view class="w-100 text-truncate font-size-lg text-color-base" style="margin-bottom: 20rpx;">
<!-- {{ orderGoodsName(item.cartInfo) }} -->
<view class="flex mb-2" v-for="(good,index) in item.cartInfo" :key="index">
<image :src="good.image" mode="aspectFill" class="image"></image>
<view class="flex flex-column">
<view class="font-size-medium mt-1 text-color-base">{{ good.title }}</view>
<view class="font-size-sm mt-1">{{ good.spec }}</view>
<view class="font-size-sm mt-2">×{{ good.number }} ¥{{ good.price }}</view>
</view>
</view>
</view>
<view class="d-flex justify-content-between align-items-center" style="margin-bottom: 30rpx;">
<view class="font-size-sm text-color-assist">
{{formatDateTime(item.createTime) }}
</view>
<view class="d-flex font-size-sm text-color-base align-items-center">
<view style="margin-right: 10rpx;">共{{ goodsNum(item.cartInfo) }}件商品,实付</view>
<view class="font-size-lg">¥{{ item.payPrice }}</view>
</view>
</view>
<view class="d-flex align-items-center justify-content-end">
<view>
<button v-if="item.paid > 0 && item.status < 2 && item.refundStatus == 0" class="left-margin" plain size="mini" @tap.stop="receive(item)">确认收到餐</button>
<button class="left-margin" plain size="mini" @tap="detail(item.orderId)">订单详情</button>
</view>
</view>
</view>
</list-cell>
</view>
</view>
<uv-empty v-if="orders.length == 0" mode="order"></uv-empty>
</view>
</template>
<script setup>
import {
ref,
computed
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onPullDownRefresh,onReachBottom} from '@dcloudio/uni-app'
import { formatDateTime,kmUnit } from '@/utils/util'
import {
orderGetOrders,
orderReceive
} from '@/api/order'
const main = useMainStore()
const { isLogin } = storeToRefs(main)
const title = ref('我的订单')
const page = ref(1)
const pageSize = ref(10)
const orders = ref([])
const tabList = ref([{
type: -1,
name: '全部',
}, {
type: 0,
name: '待支付',
}, {
type: 1,
name: '进行中'
}, {
type: 4,
name: '已完成'
}, {
type: -3,
name: '退款单'
}]
)
const current = ref(0)
const type = ref(-1)
const orderGoodsName = computed(() => { //计算单个饮品添加到购物车的数量
return (goods) => {
let arr = []
goods.forEach(good => arr.push(good.title + '*' + good.number))
return arr.join(',')
}
})
const goodsNum = computed(() => { //计算单个饮品添加到购物车的数量
return (goods) => {
let num = 0;
goods.forEach(good => num += parseInt(good.number))
return num;
}
})
onLoad(() => {
if(!isLogin.value) {
uni.navigateTo({url: '/pages/components/pages/login/login'})
}
getOrders(false)
})
onPullDownRefresh(() => {
getOrders(false)
})
onReachBottom(() => {
getOrders(false)
})
// tab栏切换
const change = (e) => {
type.value = e.type
getOrders(true)
}
const getOrders = async(isRefresh = false) => {
uni.showLoading({
title: '加载中'
})
if(isRefresh) {
orders.value = []
page.value = 1
}
let ordersData = await orderGetOrders({page:page.value, limit:pageSize.value,type:type.value});
if(ordersData) {
orders.value = orders.value.concat(ordersData)
page.value += 1
}
uni.stopPullDownRefresh();
uni.hideLoading()
}
const detail = (id) => {
uni.navigateTo({
url: '/pages/components/pages/orders/detail?id=' + id
})
}
// 确认收到货
const receive = async(order) => {
let data = await orderReceive({uni:order.orderId});
if (data) {
await getOrders(true)
}
}
</script>
<style lang="scss" scoped>
.left-margin {
margin-left: 10rpx;
}
.image {
width: 160rpx;
height: 160rpx;
margin-right: 30rpx;
border-radius: 8rpx;
}
</style>
@@ -0,0 +1,59 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="p-2">
<uv-list>
<uv-list-item title="订单金额" :rightText="'¥'+totalPrice"></uv-list-item>
<uv-list-item title="退款金额" :rightText="'¥'+payPrice"></uv-list-item>
<uv-list-item title="退款类型" rightText="整个订单"></uv-list-item>
<uv-list-item title="退款原因" rightText="协商一致"></uv-list-item>
<uv-list-item title="退款留言" >
<template #footer><uv-input placeholder="请输入内容" border="none" v-model="refundReasonWapExplain"></uv-input></template>
</uv-list-item>
</uv-list>
<view class="mt-2">
<uv-button shape="circle" type="warning" :plain="true" size="small" text="申请退款" @click="refund()"></uv-button>
</view>
<uv-toast ref="toast"></uv-toast>
</view>
</template>
<script setup>
import {
ref
} from 'vue'
import { onLoad} from '@dcloudio/uni-app'
import {
orderRefund
} from '@/api/order'
const title = ref('申请退款')
const orderId = ref('')
const payPrice = ref('')
const totalPrice = ref('')
const refundReasonWapExplain = ref('')
const toast = ref()
onLoad((option) => {
console.log('option:',option)
orderId.value = option.orderId
payPrice.value = option.payPrice
totalPrice.value = option.totalPrice
})
const refund = async() => {
let data = await orderRefund({refundReasonWapExplain:refundReasonWapExplain.value,uni:orderId.value,text:'协商一致'});
if (data) {
uni.showToast({
title: '提交成功',
icon: 'success'
})
}
}
</script>
<style>
</style>
@@ -0,0 +1,395 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="container position-relative w-100 h-100 overflow-hidden">
<uv-empty v-if="coupons.length == 0" mode="coupon"></uv-empty>
<scroll-view scroll-y class="coupon-list">
<view class="wrapper">
<view class="coupon" v-for="(item, index) in coupons" :key="index" @tap="openDetailModal(item, index)">
<view class="taobao">
<view class="ticket" :style="{border: item.id == coupon_id ? '1rpx solid red':''}">
<view class="left">
<image class="picture" :src="item.image" mode="aspectFill"></image>
<view class="introduce">
<view class="top">
¥
<text class="big">{{ item.value }}</text>
<view>满{{ item.least }}减{{ item.value }}</view>
</view>
<view class="type">{{ item.title }}</view>
<view class="date u-line-1">{{formatDateTime(item.startTime, 'yyyy-MM-dd')}}-{{formatDateTime(item.endTime, 'yyyy-MM-dd')}}</view>
</view>
</view>
<view class="right" @click.stop="" v-if="activeTabIndex == 0">
<view v-if="item.id != coupon_id" class="use immediate-use" :round="true" @tap="useCouponWith(item)">立即使用</view>
<view v-else class="use immediate-use" :round="true" @tap="cancelCoupon(item)">取消使用</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<modal custom :show="detailModalVisible" @cancel="closeDetailModal" width="90%">
<view class="modal-content">
<view class="d-flex font-size-extra-lg text-color-base just-content-center mb-20">{{ coupon.title }}</view>
<view class="d-flex font-size-sm text-color-base mb-20">有效期:{{formatDateTime(coupon.startTime, 'yyyy-MM-dd')}}至{{formatDateTime(coupon.endTime, 'yyyy-MM-dd')}}</view>
<view class="d-flex font-size-sm text-color-base mb-20">领取时间:{{ coupon.createtime_text }}</view>
<view class="d-flex font-size-sm text-color-base mb-20">卷价值:满{{ coupon.least }}减{{ coupon.value }}</view>
<view class="d-flex font-size-sm text-color-base mb-20">适用范围:{{ typeInfo(coupon.type) }}</view>
<view class="d-flex font-size-sm text-color-base mb-20">适用店铺:{{ coupon.shopName }}</view>
<view class="d-flex align-items-center just-content-center" v-if="activeTabIndex == 0">
<button type="primary" @tap="useCoupon" class="use-coupon-btn">立即使用</button>
</view>
</view>
</modal>
<!--轻提示-->
<uv-toast ref="uToast"></uv-toast>
</view>
</template>
<script setup>
import {
ref,
watch,
toRaw
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onShow ,onPullDownRefresh,onHide} from '@dcloudio/uni-app'
import { formatDateTime,prePage } from '@/utils/util'
import {
couponMine
} from '@/api/coupon'
const main = useMainStore()
const { isLogin } = storeToRefs(main)
const title = ref('优惠券')
const activeTabIndex = ref(0)
const detailModalVisible = ref(false)
const coupon = ref({})
const couponIndex = ref(0)
const coupons = ref([])
const amount = ref(0)
const buttonLock = ref(false)
const coupon_id = ref(0)
const shop_id = ref(0)
const type = ref(0)
const uToast = ref()
onLoad((options) => {
if (options.amount) {
amount.value = options.amount;
}
if (options.coupon_id) {
coupon_id.value = options.coupon_id
}
if (options.shop_id) {
shop_id.value = options.shop_id;
}
if (options.type) {
type.value = options.type;
}
activeTabIndex.value = 0;
getCoupons();
})
onPullDownRefresh(() => {
getCoupons();
})
// 使用范围
const typeInfo = (type) => {
if (type == 0) {
return '外卖和自取';
}
if (type == 1) {
return '自取';
}
if (type == 2) {
return '外卖';
}
}
const getCoupons = async() => {
let data = await couponMine({shop_id: shop_id.value, type: type.value, page:1, pagesize:10000});
uni.stopPullDownRefresh();
if (data) {
coupons.value = data;
}
}
const openDetailModal = (mycoupon, index) => {
couponIndex.value = index;
coupon.value = mycoupon;
detailModalVisible.value = true;
}
// 使用优惠券
const useCouponWith = (mycoupon) => {
coupon.value = mycoupon;
useCoupon();
}
// 取消优惠券
const cancelCoupon = () => {
coupon.value = {}
coupon_id.value = 0
prePage().coupon = {}
}
const closeDetailModal = () => {
detailModalVisible.value = false;
coupon.value = {};
}
// 使用优惠及
const useCoupon = () => {
if (buttonLock.value == true) {
return;
}
buttonLock.value = true
//console.log('coupon:',coupon.value);
if (parseFloat(coupon.value.least) > parseFloat(amount.value)) {
//console.log('pages3:');
uToast.value.show({
message: '订单金额满'+coupon.value.least+'才能使用',
type: 'error'
});
buttonLock.value = false
} else {
main.SET_COUPON(coupon)
console.log('main.myconpon:',main.mycoupon)
//prePage().coupon = coupon.value;
//prePage().coupons = 1; // 哨兵
uni.navigateBack({
})
}
}
</script>
<style lang="scss" scoped>
/* #ifdef H5 */
page {
height: 100%;
}
/* #endif */
.container {
display: flex;
flex-direction: column;
}
.bottom-box {
height: 80rpx;
flex-shrink: 0;
.item {
padding: 0 20rpx;
position: relative;
&::after {
content: ' ';
border-right: 1rpx solid $text-color-assist;
height: 100%;
position: absolute;
right: 0;
top: 0;
transform: scaleX(0.5) scaleY(0.8);
}
&:nth-last-child(1)::after {
border-right: 0;
}
}
}
.coupon-list {
margin-top: 30rpx;
height:calc(100vh - 120rpx);
// height: calc(100vh - 120rpx - 200rpx);
/* #ifdef H5 */
// height: calc(100vh - 120rpx - 200rpx - 44px);
/* #endif */
}
.wrapper {
padding: 0 20rpx;
display: flex;
flex-direction: column;
.coupon {
display: flex;
flex-direction: column;
background-color: #ffffff;
margin-bottom: 30rpx;
//padding: 0 30rpx;
border-radius: 6rpx;
box-shadow: 0 10rpx 10rpx -10rpx rgba(15, 15, 15, 0.1);
position: relative;
&::before {
content: '';
position: absolute;
background-color: $bg-color;
width: 30rpx;
height: 30rpx;
bottom: 65rpx;
left: -15rpx;
border-radius: 100%;
}
&::after {
content: '';
position: absolute;
background-color: $bg-color;
width: 30rpx;
height: 30rpx;
bottom: 65rpx;
right: -15rpx;
border-radius: 100%;
}
.detail {
padding: 20rpx 0;
position: relative;
&::after {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: 0;
border-bottom: 1rpx dashed #c6c6c6;
transform: scaleY(0.5);
}
.coupon-img {
width: 150rpx;
height: 150rpx;
margin-right: 40rpx;
}
}
}
}
.use-coupon-btn {
width: 95%;
border-radius: 50rem !important;
}
.taobao {
background-color: white;
.title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
font-size: 30rpx;
.left {
display: flex;
align-items: center;
}
.store {
font-weight: 500;
}
.buddha {
width: 70rpx;
height: 70rpx;
border-radius: 10rpx;
margin-right: 10rpx;
}
.entrance {
color: $uv-info;
border: solid 2rpx $uv-info;
line-height: 48rpx;
padding: 0 30rpx;
background: none;
border-radius: 15px;
}
}
.ticket {
display: flex;
.left {
width: 70%;
padding: 20rpx;
background-color: white; //rgb(255, 245, 244);
border-radius: 20rpx;
border-right: dashed 2rpx rgb(224, 215, 211);
display: flex;
.picture {
//width: 172rpx;
border-radius: 20rpx;
width: 190rpx;
height: 190rpx;
}
.introduce {
margin-left: 10rpx;
.top {
color: $uv-warning;
font-size: 28rpx;
.big {
font-size: 60rpx;
font-weight: bold;
margin-right: 10rpx;
}
}
.type {
font-size: 28rpx;
color: $uv-info-dark;
}
.date {
margin-top: 10rpx;
font-size: 20rpx;
color: $uv-info-dark;
}
}
}
.right {
width: 30%;
padding: 40rpx 20rpx;
background-color: white; //rgb(255, 245, 244);
border-radius: 20rpx;
display: flex;
align-items: center;
.use {
height: auto;
padding: 0 20rpx;
font-size: 24rpx;
border-radius: 40rpx;
color: #ffffff !important;
background-color: $uv-warning !important;
line-height: 40rpx;
color: rgb(117, 142, 165);
margin-left: 20rpx;
}
.used {
height: auto;
padding: 0 20rpx;
font-size: 24rpx;
border-radius: 40rpx;
//color: #ffffff!important;
//background-color: $u-type-warning!important;
line-height: 40rpx;
//color: rgb(117, 142, 165);
margin-left: 20rpx;
}
}
.right_log {
text-align: center;
width: 30%;
padding: 80rpx 0rpx;
background-color: white; //rgb(255, 245, 244);
border-radius: 20rpx;
align-items: center;
}
}
}
</style>
@@ -0,0 +1,814 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="container position-relative">
<view style="margin-bottom: 130rpx;">
<view class="section-1">
<template v-if="store.distance > 0">
<list-cell class="location">
<view class="flex-fill d-flex justify-content-between align-items-center">
<view class="store-name flex-fill">{{ orderType == 'takeout' ? '外卖配送' : '点餐自取' }}</view>
<uv-switch activeColor="#dd524d" v-model="active" @change="takout">
</uv-switch>
</view>
</list-cell>
</template>
<template v-if="orderType == 'takeout'">
<list-cell @click="chooseAddress">
<view v-if="address.realName" class="w-100 d-flex flex-column">
<view class="d-flex align-items-center justify-content-between mb-10">
<view class="font-size-lg text-color-base">
{{ address.address + ' ' + address.detail }}
</view>
<image src="/static/images/navigator-1.png" class="arrow"></image>
</view>
<view class="d-flex text-color-assist font-size-sm align-items-center">
<view class="mr-10">{{ address.realName }}</view>
<view>{{ address.phone }}</view>
</view>
</view>
<view v-else class="flex-fill d-flex justify-content-between align-items-center">
<view class="store-name flex-fill">选择收货地址</view>
<image src="/static/images/navigator-1.png" class="arrow"></image>
</view>
</list-cell>
</template>
</view>
<view class="section-1">
<template>
<list-cell class="location" @click="goToShop">
<view class="flex-fill d-flex justify-content-between align-items-center">
<view class="store-name flex-fill">{{ store.name }}</view>
<image src="/static/images/navigator-1.png" class="arrow"></image>
</view>
</list-cell>
</template>
<template>
<list-cell arrow class="meal-time" v-if="orderType == 'takein'">
<view class="flex-fill d-flex justify-content-between align-items-center"
@click="takeinTIme = !takeinTIme">
<view class="title">取餐时间</view>
<view class="time">
{{ takeinRange[defaultSelector[0]].name }}
<u-picker v-model="takeinTIme" :range="takeinRange" range-key="name" mode="selector"
@cancel="takeinCancelTime" @confirm="takeinConfirmTime"
:default-selector="defaultSelector"></u-picker>
</view>
</view>
</list-cell>
<list-cell class="contact" last :hover="false" v-if="orderType == 'takein'">
<view class="flex-fill d-flex justify-content-between align-items-center">
<view class="title flex-fill">联系电话</view>
<view class="time"><input class="text-right" placeholder="请输入手机号码" :value="member.mobile" />
</view>
<button class="contact-tip font-size-sm">自动填写</button>
</view>
</list-cell>
</template>
<template v-if="orderType == 'takeout'">
<list-cell>
<view class="w-100 d-flex flex-column">
<view class="d-flex align-items-center font-size-base text-color-base">
<view class="flex-fill">预计送达时间</view>
<view class="mr-10">
{{ defaultTime }}
<u-picker :default-time="defaultTime" v-model="takeoutTIme" :params="paramsTime"
mode="time" @cancel="cancelTime" @confirm="choiceTime"></u-picker>
</view>
</view>
</view>
</list-cell>
</template>
</view>
<!-- 购物车列表 begin -->
<view class="section-2">
<view class="cart d-flex flex-column">
<list-cell last v-for="(item, index) in cart" :key="index">
<view class="w-100 d-flex flex-column">
<view class="d-flex align-items-center mb-10">
<view
class="d-flex flex-fill justify-content-between align-items-center text-color-base font-size-lg">
<image style="width: 80rpx;height: 80rpx;" mode="aspectFill" :src="item.image">
</image>
</view>
<view class="name-and-props overflow-hidden">
<view class="text-color-base font-size-lg">{{ item.name }}</view>
</view>
<view
class="d-flex flex-fill justify-content-between align-items-center text-color-base font-size-lg">
<view>x{{ item.number }}</view>
<view>¥{{ item.price }}</view>
</view>
</view>
<view class="text-truncate font-size-base text-color-assist">{{ item.valueStr }}</view>
</view>
</list-cell>
</view>
<list-cell arrow @click="goToPackages">
<view class="flex-fill d-flex justify-content-between align-items-center">
<view class="text-color-base">优惠券</view>
<view v-if="coupons == 0" class="text-color-base">暂无可用</view>
<view v-else-if="coupon.title" class="text-color-danger">
{{ coupon.title }}(满{{ coupon.least }}减{{ coupon.value }})
</view>
<view v-else class="text-color-primary">可用优惠券{{ coupons }}张</view>
</view>
</list-cell>
<list-cell last>
<view class="flex-fill d-flex justify-content-end align-items-center">
<view>
总计¥{{ total }}
<text v-if="orderType == 'takeout'">,配送费¥{{ store.deliveryPrice }}</text>
<text v-if="coupon.value">,¥-{{ coupon.value }}</text>
,实付
</view>
<view class="font-size-extra-lg font-weight-bold">¥{{ amount }}</view>
</view>
</list-cell>
</view>
<!-- 购物车列表 end -->
<view class="d-flex align-items-center justify-content-start font-size-sm text-color-warning"
style="padding: 20rpx 0;">
</view>
<!-- 支付方式 begin -->
<view class="payment">
<list-cell last :hover="false"><text>支付方式</text></list-cell>
<list-cell>
<view class="d-flex align-items-center justify-content-between w-100 disabled"
@click="setPayType('yue')">
<view class="iconfont iconbalance line-height-100 payment-icon"></view>
<view class="flex-fill">余额支付(余额¥{{ member.nowMoney }})</view>
<view class="font-size-sm" v-if="member.nowMoney == 0">余额不足</view>
<view class="iconfont line-height-100 checkbox checked iconradio-button-on" v-if="payType == 'yue'">
</view>
<view class="iconfont line-height-100 checkbox iconradio-button-off" v-else></view>
</view>
</list-cell>
<list-cell last>
<view class="d-flex align-items-center justify-content-between w-100" @click="setPayType('weixin')">
<view class="iconfont iconwxpay line-height-100 payment-icon" style="color: #7EB73A"></view>
<view class="flex-fill">微信支付</view>
<view class="iconfont line-height-100 checkbox checked iconradio-button-on" v-if="payType == 'weixin'">
</view>
<view class="iconfont line-height-100 checkbox iconradio-button-off" v-else></view>
</view>
</list-cell>
<!-- #ifdef H5 -->
<list-cell>
<view class="d-flex align-items-center justify-content-between w-100" @click="setPayType('alipay')">
<view class="iconfont-yshop icon-alipay line-height-100 payment-icon" style="color:#07b4fd" ></view>
<view class="flex-fill">支付宝</view>
<view class="iconfont line-height-100 checkbox checked iconradio-button-on" v-if="payType == 'alipay'" ></view>
<view class="iconfont line-height-100 checkbox iconradio-button-off" v-else ></view>
</view>
</list-cell>
<!-- #endif -->
</view>
<!-- 支付方式 end -->
<!-- 备注 begin -->
<list-cell last @click="goToRemark">
<view class="d-flex flex-fill align-items-center justify-content-between overflow-hidden" style="margin-bottom: 110rpx;">
<view class="flex-shrink-0 mr-20">备注</view>
<view class="text-color-primary flex-fill text-truncate text-right">{{ form.remark || '点击填写备注' }}
</view>
</view>
</list-cell>
<!-- 备注 end -->
</view>
<!-- 付款栏 begin -->
<view style="z-index: 1;"
class="w-100 pay-box position-fixed fixed-bottom d-flex align-items-center justify-content-between bg-white">
<view class="font-size-sm" style="margin-left: 20rpx;">合计:</view>
<view class="font-size-lg flex-fill">¥{{ amount }}</view>
<view class="bg-primary h-100 d-flex align-items-center just-content-center text-color-white font-size-base"
style="padding: 0 60rpx;" @tap="debounce(submit, 500)">付款</view>
</view>
<!-- 付款栏 end -->
<modal :show="ensureAddressModalVisible" custom :mask-closable="false" :radius="'0rpx'" width="90%">
<view class="modal-content">
<view class="d-flex justify-content-end">
<image src="/static/images/pay/close.png" style="width: 40rpx; height: 40rpx;"
@tap="ensureAddressModalVisible = false"></image>
</view>
<view class="d-flex just-content-center align-items-center" style="margin-bottom: 40px;">
<view class="font-size-extra-lg text-color-base">请再次确认下单地址</view>
</view>
<view
class="d-flex font-size-base text-color-base font-weight-bold align-items-center justify-content-between mb-20">
<view>{{ address.realName }}</view>
<view>{{ address.phone }}</view>
</view>
<view class="d-flex font-size-sm text-color-assist align-items-center justify-content-between mb-40">
<view style="max-width: 60%;">{{ address.address + address.detail }}</view>
<button type="primary" size="mini" plain class="change-address-btn" style="white-space: nowrap;"
@click="chooseAddress">修改地址</button>
</view>
<button type="primary" class="pay_btn" @tap="debounce(pay, 500)">确认并付款</button>
</view>
</modal>
<uv-toast ref="uToast"></uv-toast>
</view>
</template>
<script setup>
import {
ref,
computed,
nextTick
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onShow ,onPullDownRefresh,onHide} from '@dcloudio/uni-app'
import { formatDateTime,isWeixin } from '@/utils/util'
import debounce from '@/uni_modules/uv-ui-tools/libs/function/debounce'
import {
orderSubmit,
payUnify,
getWechatConfig
} from '@/api/order'
import {
couponCount
} from '@/api/coupon'
// #ifdef H5
import * as jweixin from 'weixin-js-sdk'
// #endif
const main = useMainStore()
const { orderType,address, store,location,isLogin,member,mycoupon } = storeToRefs(main)
const active = ref(false)
const title = ref('支付')
const jsStr = ref('')
const cart = ref([])
const form = ref({
remark: ''
})
const ensureAddressModalVisible = ref(false)
const takeoutTIme = ref(false) // 外卖取餐时间picker
const paramsTime = ref({
year: false,
month: false,
day: false,
hour: true,
minute: true,
second: false
})
const defaultTime = ref('00:00')
const takeinTIme = ref(false) // 到店自取时间selector
const takeinRange = ref([{
name: '立即用餐',
value: 0
},
{
name: '10分钟后',
value: 10
},
{
name: '20分钟后',
value: 20
},
{
name: '30分钟后',
value: 30
},
{
name: '40分钟后',
value: 40
},
{
name: '50分钟后',
value: 50
}
])
const defaultSelector = ref([0])
const payType = ref('weixin') // 付款方式
const coupons = ref(0) // 可用优惠券数量
const coupon = ref(main.mycoupon) // 选中的
const subscribeMss = ref({
'takein': '',
'takeout': '',
'takein_made': '',
'takeout_made': ''
})// 微信订阅信息
const uToast = ref()
const total = computed(() =>{
return cart.value.reduce((acc, cur) => acc + cur.number * cur.price, 0);
})
const amount = computed(() =>{
let amount = cart.value.reduce((acc, cur) => acc + cur.number * cur.price, 0);
// 加配送费
if (store.value.distance > 0 && orderType.value == 'takeout') {
amount += parseFloat(store.value.deliveryPrice);
}
// 减去优惠券
if (main.mycoupon.hasOwnProperty('id')) {
amount -= parseFloat(main.mycoupon.value);
}
return amount.toFixed(2);
})
onShow(() => {
coupon.value = main.mycoupon
let date = new Date(new Date().getTime() + 3600000); // 一个小时后
let hour = date.getHours();
let minute = date.getMinutes();
if (hour < 10) {
hour = '0' + hour;
}
if (minute < 10) {
minute = '0' + minute;
}
defaultTime.value = hour + ':' + minute;
console.log('member:',member.value)
if(orderType.value == 'takeout'){
active.value = true
}else{
active.value = false
}
getCoupons();
let paytype = uni.getStorageSync('paytype');
payType.value = paytype ? paytype : 'weixin';
})
onHide(() => {
subscribeMss.value = [];
coupons.value = 0;
})
onLoad((option) => {
cart.value = uni.getStorageSync('cart')
if(option.remark) {
form.value.remark = option.remark
}
})
const getSubscribeMss = async() => {
let data = []
if (data) {
subscribeMss.value = data;
}
}
// 更改支付方式
const setPayType = (paytype) => {
payType.value = 'weixin';
payType.value= paytype;
uni.setStorage({
key: 'paytype',
data: paytype
})
}
const getCoupons = async() => {
//0=通用,1=自取,2=外卖
let type = orderType.value == 'takein' ? 1 : 2;
let data = await couponCount({
shop_id: store.value.id ? store.value.id : 0,
type: type
});
if (data) {
coupons.value = data;
}
}
// 选择时间
const choiceTime = (value) => {
let hour = value.hour;
let minute = value.minute;
let date = new Date(new Date().getTime() + 3600000); // 一个小时后
let nowhour = date.getHours();
let nowminute = date.getMinutes();
if ((hour * 60 * 60 + minute * 60) * 1000 - 3600000 < (nowhour * 60 * 60 + nowminute * 60) * 1000) {
uToast.value.show({
message: '请至少选择一个小时之后',
type: 'error'
});
return
}
if (hour < 10) {
hour = '0' + hour;
}
if (minute < 10) {
minute = '0' + minute;
}
defaultTime,value = hour + ':' + minute;
takeoutTIme.value = false;
}
const cancelTime = (value) => {
takeoutTIme.value = false;
}
// 到店自取-取消选择取餐时间
const takeinCancelTime = (value) => {
takeinTIme.value = false;
}
// 到店自取-选择取餐时间
const takeinConfirmTime = (value) => {
defaultSelector.value = value;
}
// 是否外卖开关
const takout = (value) => {
let type = 'takeout';
if (value == false) {
type = 'takein';
}
main.SET_ORDER_TYPE(type);
// 如果存在优惠券看看需不需要清除
if (coupon.value.hasOwnProperty('type')) {
//0=通用,1=自取,2=外卖
if (coupon.value.type != 0) {
if (coupon.value.type == 1 && orderType.value == 'takeout') {
coupon.value = {};
}
if (coupon.value.type == 2 && orderType.value == 'takeint') {
coupon.value = {};
}
}
}
subscribeMss.value = [];
coupons.value = 0;
getCoupons();
}
const goToRemark = () => {
uni.navigateTo({
url: '/pages/components/pages/remark/remark?remark=' + form.value.remark
});
}
const chooseAddress = () => {
uni.navigateTo({
url: '/pages/components/pages/address/address?is_choose=true&scene=pay'
});
}
const goToPackages = () => {
let newamount = amount.value;
let coupon_id = coupon.value.id ? coupon.value.id : 0;
let type = orderType.value == 'takein' ? 1 : 2;
let shop_id = store.value.id;
uni.navigateTo({
url: '/pages/components/pages/packages/index?amount=' + newamount + '&coupon_id=' + coupon_id +
'&shop_id=' + shop_id + '&type=' + type
});
}
const goToShop = () => {
uni.navigateTo({
url: `/pages/components/pages/shop/shop`
});
}
const submit = () => {
if (orderType.value == 'takeout') {
// 外卖类型
if (typeof address.value.id == 'undefined') {
uToast.value.show({
message: '请选择收货地址',
type: 'error'
});
return
}
// 起送价钱
if (store.value.min_price > total.value) {
uToast.value.show({
message: '本店外卖起送价为¥' + store.value.min_price,
type: 'error'
});
return
}
pay();
} else {
pay();
}
}
const pay = async() => {
let that = this;
// #ifdef MP-WEIXIN
await new Promise(function(revolve) {
//订阅号信息id
let subscribeMss = ['KBtfY9G1IWCzC6q-ZKo-Q-MmdP7aaF79nx0XFcBf3h4'];
wx.showModal({
title: '温馨提示',
content: '为更好的促进您与商家的交流,小程序需要在您成交时向您发送消息',
confirmText: "同意",
cancelText: "拒绝",
success: function(res) {
if (res.confirm) {
uni.requestSubscribeMessage({
tmplIds: subscribeMss,
complete(res) {
console.log(res)
revolve(true)
}
});
} else {
revolve(true)
}
}
})
});
// #endif
uni.showLoading({
title: '加载中'
});
let data = {
orderType: orderType.value, // 购买类型:takein=自取,takeout=外卖
addressId:orderType.value == 'takeout' ? address.value.id : 0, // 外卖配送地址
shopId: store.value.id, // 店铺id
mobile: member.value.mobile, // 联系电话
gettime: takeinRange.value[defaultSelector.value[0]].value, // 取餐时间
payType: payType.value, // 支付类型
remark: form.value.remark, // 备注
productId: [],
spec: [],
number: [],
couponId: coupon.value.id ? coupon.value.id : 0 // 优惠券id
};
cart.value.forEach((item, index) => {
data.productId.push(item.id);
data.spec.push(item.valueStr.replace(/,/g, '|'));
//data.spec.push(item.valueStr);
data.number.push(item.number);
});
//console.log(data);
let order = await orderSubmit(data);
if (!order) {
uni.hideLoading();
return;
}
if (payType.value == 'weixin') {
// 微信支付
weixinPay(order);
} else if (payType.value == 'yue') {
// 余额支付
balancePay(order);
} else if (payType.value == 'alipay') {
// 余额支付
aliPay(order);
}
uni.hideLoading()
return
}
const balancePay = async(order) => {
let from = 'routine'
// #ifdef H5
from = 'h5'
// #endif
let pay = await payUnify({
uni: order.orderId,
from: from,
paytype: 'yue'
});
uni.hideLoading();
if (!pay) {
return;
}
member.value.money -= amount.value
main.SET_MEMBER(member.value)
uni.removeStorageSync('cart');
uni.switchTab({
url: '/pages/order/order',
fail(res) {
console.log(res);
}
});
}
const weixinPay = async(order) => {
let from = 'routine'
// #ifdef H5
from = 'h5'
if(isWeixin()){
from = 'wechat'
}
// #endif
//let that = this;
let data = await payUnify({
uni: order.orderId,
from: from,
paytype: 'weixin'
});
console.log('param2:',data)
if (!data) {
uni.hideLoading();
return;
}
if (data.trade_type == 'MWEB') {
// #ifdef H5
// 微信外的H5
console.log('data:',data)
location.href = data.data;
// #endif
console.log('data1:',data)
} else if (data.trade_type == 'JSAPI') {
console.log('param:',data)
// #ifdef MP-WEIXIN
uni.requestPayment({
provider: 'wxpay',
timeStamp: data.data.timeStamp,
nonceStr: data.data.nonceStr,
package: data.data.package,
signType: 'MD5',
paySign: data.data.paySign,
success: function(res) {
uni.removeStorageSync('cart');
uni.switchTab({
url: '/pages/order/order'
});
},
fail: function(err) {
console.log('fail:' + JSON.stringify(err));
}
});
// #endif
} else if (data.trade_type == 'W-JSAPI'){
//公众号支付
}else if (data.trade_type == 'APP') {
}
}
const aliPay = async(order) => {
// #ifdef H5
//let that = this;
if(isWeixin()){
uni.showToast({
title: '请普通浏览器打开进行支付宝支付~',
icon: 'none'
})
return
}
let data = await payUnify({
uni: order.orderId,
from: 'h5',
paytype: 'alipay'
});
console.log('data:',data.data)
// 支付宝支付,这里只要提交表单
let form = data.data
const div = document.createElement('formdiv');
div.innerHTML = form;
document.body.appendChild(div);
//document.forms[0].setAttribute('target', ' self');
document.forms[0].submit();
//div.remove();
// #endif
}
</script>
<style lang="scss" scoped>
.container {
padding: 30rpx;
}
.arrow {
width: 50rpx;
height: 50rpx;
position: relative;
margin-right: -10rpx;
}
.location {
.store-name {
font-size: $font-size-lg;
}
.iconfont {
font-size: 50rpx;
line-height: 100%;
color: $color-primary;
}
}
.section-1 {
margin-bottom: 30rpx;
.contact {
.contact-tip {
margin-left: 10rpx;
border: 2rpx solid $color-primary;
padding: 6rpx 10rpx;
color: $color-primary;
}
}
}
.section-2 {
.name-and-props {
width: 65%;
}
}
.payment {
margin-bottom: 30rpx;
.disabled {
color: $text-color-grey;
}
.payment-icon {
font-size: 44rpx;
margin-right: 10rpx;
}
.checkbox {
font-size: 36rpx;
margin-left: 10rpx;
}
.checked {
color: $color-primary;
}
}
.pay-box {
box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.1);
height: 100rpx;
}
.modal-content {
.change-address-btn {
line-height: 2;
padding: 0 1em;
}
.pay_btn {
width: 100%;
border-radius: 50rem !important;
line-height: 3;
}
}
.choice {
background-color: $bg-color-grey;
border-radius: 38rpx;
display: flex;
align-items: center;
font-size: $font-size-sm;
padding: 0 38rpx;
color: $text-color-assist;
.dinein,
.takeout {
width: 50%;
position: relative;
display: flex;
align-items: center;
&.active {
padding: 14rpx 38rpx;
color: #ffffff;
background-color: $color-primary;
border-radius: 38rpx;
}
}
.takeout {
margin-left: 20rpx;
height: 100%;
flex: 1;
padding: 14rpx 0;
}
.dinein.active {
//margin-left: -38rpx;
}
.takeout.active {
//margin-right: -38rpx;
}
}
</style>
@@ -0,0 +1,117 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="container w-100 h-100 overflow-hidden">
<view class="textarea">
<textarea placeholder-class="text-color-assist font-size-base" v-model="remark"
class="bg-white w-100 border-box font-size-base remark"
:class="{'text-color-danger': remarkLength > 50, 'text-color-assist' : remarkLength <=50}"
placeholder="请填写备注信息" focus/>
<view class="tips" :class="{'text-color-danger': remarkLength > 50, 'text-color-assist' : remarkLength <=50}">
{{ remarkLength }}/50
</view>
</view>
<view class="d-flex font-size-base text-color-assist" style="margin: 40rpx 0;">
快捷输入
</view>
<view class="quick-inputs d-flex flex-wrap justify-content-start">
<view class="quick-input" v-for="(item, index) in quickInputs" :key="index" @tap="handleQuickInput(item)">
{{ item }}
</view>
</view>
<view class="d-flex just-content-center align-items-center" style="margin-top: 60rpx;">
<button type="primary" class="submit-btn font-size-base" @tap="submit">完成</button>
</view>
<!--轻提示-->
<uv-toast ref="uToast"></uv-toast>
</view>
</template>
<script setup>
import {
ref,
computed
} from 'vue'
import { onLoad} from '@dcloudio/uni-app'
const remark = ref('')
const quickInputs = ref( ['请放门把手上', '请放门口', '请放前台桌上', '如地址封闭管理,请电话与我联系'])
const uToast = ref()
onLoad((opt) => {
remark.value = opt.remark
})
const remarkLength = computed(() => {
return remark.value.length
})
const isDanger = computed(() => {
return remark.value.length > 50
})
const handleQuickInput = (item) => {
remark.value = remark.value.concat(" ", item)
}
const submit = () => {
if (remark.value.length > 50) {
uToast.value.show({
message: '不能超过50个字符',
type: 'error'
});
return
}
uni.navigateTo({
url: "/pages/components/pages/pay/pay?remark=" + remark.value
})
}
</script>
<style lang="scss" scoped>
.container {
padding: 30rpx 40rpx;
.textarea {
position: relative;
.remark {
border-radius: 8rpx;
padding: 30rpx 40rpx;
height: 320rpx;
color: $font-size-base;
}
.tips {
position: absolute;
bottom: 30rpx;
right: 40rpx;
}
}
.quick-inputs {
padding-right: 20rpx;
.quick-input {
background-color: #FFFFFF;
border: 2rpx solid $color-primary;
color: $color-primary;
font-size: $font-size-base;
padding: 16rpx 26rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
}
}
.submit-btn {
width: 90%;
height: 80rpx;
border-radius: 40rpx;
line-height: 80rpx;
}
}
</style>
@@ -0,0 +1,135 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view>
<view>
<uv-search margin="30rpx" v-model="keywork" @custom="search(keywork)"></uv-search>
</view>
<view v-for="(item,index) in list" :key="index">
<uni-card @click="choice(item)" :border="item.id == store.id" :title="item.name" :thumbnail="item.image" :thumb-width="80" :sub-title="item.status_text">
<view class="body">
<view class="body-left">
<view>距离您 {{kmUnit(item.dis)}}</view>
<view v-if="item.distance > 0">配送距离:{{item.distance + 'km '}} & 配送费:{{item.delivery_price}}</view>
<view v-else>外卖不配送</view>
<view>{{item.addressMap + ' ' + item.address}}</view>
<view>营业时间 {{formatDateTime(item.startTime,'hh:mm')}} - {{formatDateTime(item.endTime,'hh:mm')}}</view>
</view>
<view class="body-right">
<uv-button @click="openLocation(item)">导航</uv-button>
<uv-button @click="call(item.mobile)">致电</uv-button>
</view>
</view>
</uni-card>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onShow ,onPullDownRefresh,onHide} from '@dcloudio/uni-app'
import { formatDateTime,kmUnit,prePage } from '@/utils/util'
import {
shopNearby,
menuGoods
} from '@/api/goods'
import {
shopGetList
} from '@/api/market'
const main = useMainStore()
const { store,location } = storeToRefs(main)
const title = ref('店铺')
const list = ref([])
const keywork = ref('')
const page = ref(1)
const pagesize = ref(10)
onLoad(() => {
getShop();
})
const getShop = async(keywork = '') => {
let data = await shopGetList({
lat: location.value.latitude ? location.value.latitude : 0,
lng: location.value.longitude ? location.value.longitude : 0,
kw: keywork,
shop_id: 0
});
if (data) {
//console.log(data);
if (page.value == 1) {
list.value = data;
} else {
for(let i in data) {
list.value.push(data[i]);
}
}
}
}
//打开定位
const openLocation = (shop) => {
//console.log(shop);
uni.openLocation({
latitude: parseFloat(shop.lat),
longitude: parseFloat(shop.lng),
name:shop.name,
address: shop.addressMap + shop.address,
fail: (res) => {
console.log(res);
}
})
}
// 打电话
const call = (mobile) => {
uni.makePhoneCall({
phoneNumber:mobile
})
}
// 搜索按钮
const search = (keywork) => {
page.value = 1;
getShop(keywork);
}
// 选中店铺
const choice = (shop) => {
main.SET_STORE(shop);
uni.$emit('refreshMenu')
uni.switchTab({
url:'/pages/menu/menu',
success(res) {
},
fail(res) {
console.log(res);
}
});
}
</script>
<style lang="scss">
.body {
.body-left {
display: inline-block;
width: 77%;
padding-left: 6rpx;
}
.body-right {
display: inline-block;
width: 20%;
}
}
.u-border {
border: 1rpx solid #1296db;
}
</style>
@@ -0,0 +1,314 @@
<template>
<layout>
<uv-sticky
bg-color="#F5F5F5"
offset-top="0"
customNavHeight="0"
>
<uv-navbar
:fixed="false"
:safeAreaInsetTop="true"
height="0"
bgColor="transparent"
leftIcon=""
/>
<!-- #ifndef MP -->
<blank size="10"></blank>
<!-- #endif -->
<blank size="5"></blank>
</uv-sticky>
<blank size="10"></blank>
<view class="container">
<view class="banner">
<uv-swiper class="bg" height="300" imgMode="aspectFill" keyName="image" :list="listAds" indicatorMode="dot" indicatorStyle="bottom"></uv-swiper>
<view class="intro">
<view class="greet">您好,{{ isLogin ? member.nickname : '游客' }}</view>
<view class="note">java-springboot-意向点餐外卖系统</view>
</view>
</view>
<view class="content">
<view class="entrance">
<view class="item " @tap="takein">
<view>
<view class="font-md">自取</view>
<view class="font-small text-light-black flex-1">下单免排队</view>
</view>
<view class="index-img">
<image src="/static/images/index002.png" mode="aspectFit" class="img-01"></image>
</view>
</view>
<view class="item" @tap="takeout">
<view>
<view class="font-md">外卖</view>
<view class="font-small text-light-black">美食送到家</view>
</view>
<view class="index-img"><image src="/static/images/index003.png" mode="aspectFit" class="img-02"></image></view>
</view>
</view>
<view class="info">
<view class="integral_section">
<view class="top">
<text class="title">我的卡券</text>
<text class="value">{{member.couponCount}}</text>
</view>
<view class="bottom">
可抵扣商品价格哦
</view>
</view>
<view class="qrcode_section" @tap="coupons">
去领个券
<view class="iconfont iconarrow-right"></view>
</view>
</view>
</view>
</view>
</layout>
</template>
<script setup>
import {
ref
} from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import {
menuAds
} from '@/api/market'
import { storeToRefs } from 'pinia'
import { useMainStore } from '@/store/store'
//
const main = useMainStore()
const { member,store, isLogin} = storeToRefs(main)
//const store = ref(main.store)
const listAds = ref([])
// const isLogin = ref(main.isLogin)
const handGetListAds = async () => {
let shop_id = store.id ? store.id : 0;
let data = await menuAds({
shop_id: shop_id
});
if (data) {
listAds.value = data.list;
console.log('listAds:',listAds.value)
uni.setStorage({
key: 'isActive',
data: data.isActive
});
if(data.list.length > 0){
uni.setStorage({
key: 'shopAd',
data: data.list[0].image
});
}
}
}
const takein = () => {
main.SET_ORDER_TYPE('takein')
uni.switchTab({
url: '/pages/menu/menu'
})
}
const takeout = () => {
main.SET_ORDER_TYPE('takeout')
uni.switchTab({
url: '/pages/menu/menu'
})
}
const coupons = () => {
console.log("--> % orderType:\n", main.orderType)
console.log("--> % isLogin:\n", main.isLogin)
if(!main.isLogin) {
uni.navigateTo({url: '/pages/components/pages/login/login'})
return
}
uni.navigateTo({
url: '/pages/components/pages/coupons/coupons'
})
}
const goScore = () => {
uni.navigateTo({
url: '/pages/components/pages/scoreproduct/list'
})
}
onLoad(() => {
// main.init()
handGetListAds()
})
</script>
<style lang="scss">
.index-img {
width: 120px;
height: 120rpx;
position: relative;
left:-20rpx
}
.img-01 {
width: 100px;
height: 100rpx;
margin-top: 30rpx;
}
.img-02 {
width: 110px;
height: 110rpx;
margin-top: 20rpx;
}
/* #ifdef H5 */
page {
height: auto;
min-height: 100%;
}
/* #endif */
page {
background-color: #ffffff!important;
}
.banner {
position: relative;
width: 100%;
//height: 300rpx;
.bg {
width: 100%;
height: 300rpx;
}
.intro {
position: absolute;
top: calc(50rpx + var(--status-bar-height));
left: 40rpx;
color: #FFFFFF;
display: flex;
flex-direction: column;
.greet {
font-size: $font-size-lg;
margin-bottom: 10rpx;
}
.note {
font-size: $font-size-sm;
}
}
}
.content {
padding: 0 50rpx;
}
.entrance {
position: relative;
//top:0;
margin-top: 30rpx;
margin-bottom: 30rpx;
border-radius: 10rpx;
background-color: #ffffff;
box-shadow: $box-shadow;
padding: 30rpx 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50rpx;
.item {
//flex: 1;
display: flex;
//flex-direction: column;
justify-content: center;
//align-items: center;
position: relative;
&:nth-child(1):after {
content: '';
position: absolute;
width: 1rpx;
background-color: #ddd;
right: 0;
height: 100%;
transform: scaleX(0.5) scaleY(0.8);
}
.icon {
font-size: 90rpx;
// color: #5A5B5C;
color: #dd524d;
}
.title {
font-size: 30rpx;
color: $text-color-base;
font-weight: 600;
}
}
}
.info {
position: relative;
margin-bottom: 30rpx;
border-radius: 10rpx;
background-color: #ffffff;
box-shadow: $box-shadow;
//padding: 30rpx;
display: flex;
align-items: center;
justify-content: center;
.integral_section {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
.top {
display: flex;
align-items: center;
.title {
color: $text-color-base;
font-size: $font-size-base;
margin-right: 10rpx;
}
.value {
font-size: 44rpx;
font-weight: bold;
}
}
.bottom {
font-size: $font-size-sm;
color: $text-color-assist;
display: flex;
align-items: center;
}
}
.qrcode_section {
color: $color-primary;
display: flex;
//flex-direction: column;
align-items: center;
justify-content: center;
font-size: $font-size-sm;
image {
width: 40rpx;
height: 40rpx;
margin-bottom: 10rpx;
}
}
}
</style>
File diff suppressed because it is too large. Load diff
+373
View File
@@ -0,0 +1,373 @@
<template>
<layout>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="container">
<view style="padding: 0 30rpx;">
<!-- user box begin -->
<view class="d-flex flex-column bg-white user-box">
<view class="d-flex align-items-center">
<view class="avatar rounded-circle">
<image :src="isLogin ? member.avatar ? member.avatar : '/static/images/mine/default.png' : '/static/images/mine/default.png'"></image>
</view>
<view class="d-flex flex-column flex-fill overflow-hidden" style="margin-top: 20rpx;">
<view v-if="isLogin"
class="font-size-lg font-weight-bold d-flex justify-content-start align-items-center"
@tap="serv({type:'pages',pages:'/pages/components/pages/mine/userinfo'})">
<view class="text-truncate">{{ member.nickname }}</view>
<view class="iconfont iconarrow-right line-height-100"></view>
</view>
<view v-else class="font-size-lg font-weight-bold" @tap="login">游客</view>
</view>
</view>
<!-- user grid begin -->
<view class="w-100 d-flex align-items-center just-content-center">
<view class="user-grid" @tap="serv({type:'pages',pages:'/pages/components/pages/coupons/coupons'})">
<view class="value font-size-extra-lg font-weight-bold text-color-base">
{{ isLogin ? member.couponCount : 0}}
</view>
<view class="font-size-sm text-color-assist">优惠券</view>
</view>
<view class="user-grid" @tap="serv({type:'pages', pages: '/pages/components/pages/balance/bill?cate=1'})">
<view class="value font-size-extra-lg font-weight-bold text-color-base">
{{ isLogin ? member.integral : 0 }}
</view>
<view class="font-size-sm text-color-assist">积分</view>
</view>
<view class="user-grid">
<view class="value font-size-extra-lg font-weight-bold text-color-base">
{{ isLogin ? member.nowMoney : 0 }}
</view>
<view class="font-size-sm text-color-assist">余额</view>
</view>
<view class="user-grid" @tap="serv({type:'pages', pages: '/pages/components/pages/balance/bill?cate=0'})">
<view class="value font-size-extra-lg font-weight-bold text-color-base">
{{ isLogin ? member.sumMoney : 0 }}
</view>
<view class="font-size-sm text-color-assist">历史消费</view>
</view>
</view>
<!-- user grid end -->
</view>
<!-- user box end -->
</view>
<!-- service box begin -->
<view class="service-box">
<view class="font-size-lg text-color-base font-weight-bold" style="margin-bottom: 20rpx;">我的服务</view>
<view class="u-m-t-20">
<uv-cell-group>
<block v-for="(item, index) in services" :key='index'>
<uv-cell :title="item.name" v-if="item.type == 'contact'" :isLink="true">
<template #icon>
<image :src="item.image" style="width: 40rpx;height: 40rpx;" class="mr-1"></image>
</template>
</uv-cell>
<uv-cell :isLink="true" :title="item.name" v-else-if="item.type == 'call'" v-on:click="makePhoneCall(item.phone)">
<template #icon>
<image :src="item.image" style="width: 40rpx;height: 40rpx;" class="mr-1"></image>
</template>
</uv-cell>
<uv-cell :isLink="true" :title="item.name" v-else @tap="serv(item)">
<template #icon>
<image :src="item.image" style="width: 40rpx;height: 40rpx;" class="mr-1"></image>
</template>
</uv-cell>
</block>
</uv-cell-group>
</view>
</view>
</view>
</layout>
</template>
<script setup>
import {
ref,
computed
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onShow} from '@dcloudio/uni-app'
import { formatDateTime,kmUnit } from '@/utils/util'
import {
userGetUserInfo,
mineService
} from '@/api/user'
const main = useMainStore()
const { member,isLogin } = storeToRefs(main)
const title = ref('个人中心')
const services = ref([])
const growthValue = computed(() => {
if (!isLogin.value) return 0
const {
currentValue,
needValue
} = member.value
return currentValue / (currentValue + needValue) * 100
})
onLoad(() => {
getServices();
})
onShow(() => {
getUserInfo();
})
const getUserInfo = async() => {
if (isLogin.value) {
let data = await userGetUserInfo();
if (data) {
main.SET_MEMBER(data);
}
}
}
const getServices = async() => {
let data = await mineService();
if (data) {
services.value = data;
}
}
const makePhoneCall = (phoneNumber) => {
uni.makePhoneCall({
phoneNumber: phoneNumber,
})
}
const login = () => {
uni.navigateTo({
url: '/pages/components/pages/login/login'
})
}
const packages = () => {
if (!isLogin.value) {
login()
return
}
uni.navigateTo({
url: '/pages/components/pages/packages/index'
})
}
const serv = (item) => {
switch (item.type) {
case 'pages':
if (!isLogin.value) {
login()
return
}
uni.navigateTo({
url: item.pages
})
break;
case 'miniprogram':
uni.navigateToMiniProgram({
appId: item.app_id
})
break;
case 'menu':
uni.navigateTo({
url: '/pages/components/pages/mine/service?id=' + item.id + '&name=' + item.name
})
break;
case 'content':
uni.navigateTo({
url: '/pages/components/pages/mine/content?id=' + item.id + '&name=' + item.name
})
break;
}
}
</script>
<style lang="scss" scoped>
page {
height: auto;
min-height: 100%;
}
.bg {
width: 100%;
height: calc(410 / 594 * 750rpx);
}
.hym-btn {
position: absolute;
top: 40rpx;
right: 40rpx;
color: $color-primary;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50rem;
font-size: $font-size-sm;
box-shadow: 0 0 20rpx rgba(66, 66, 66, 0.1);
&::after {
border: 0;
}
image {
width: 30rpx;
height: 30rpx;
margin-right: 10rpx;
}
}
.user-box {
position: relative;
border-radius: 8rpx;
margin-bottom: 30rpx;
margin-top: 70rpx;
box-shadow: $box-shadow;
}
.avatar {
position: relative;
margin-top: -35rpx;
margin-left: 35rpx;
margin-right: 35rpx;
width: 160rpx;
height: 160rpx;
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #FFFFFF;
box-shadow: 0 0 20rpx rgba($color: #000000, $alpha: 0.2);
image {
width: 140rpx;
height: 140rpx;
border-radius: 100%;
}
.badge {
position: absolute;
right: -10rpx;
bottom: -10rpx;
background-color: #FFFFFF;
border-radius: 50rem;
display: flex;
align-items: center;
justify-content: center;
color: $color-warning;
font-size: 24rpx;
padding: 8rpx 16rpx;
box-shadow: 0 0 20rpx rgba($color: #000000, $alpha: 0.2);
image {
width: 30rpx;
height: 30rpx;
}
}
}
.level-benefit {
margin-left: 35rpx;
padding: 10rpx 0 10rpx 30rpx;
border-radius: 50rem 0 0 50rem;
}
.user-grid {
width: 25%;
padding: 30rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.value {
margin-bottom: 20rpx;
}
}
.level-benefit-box {
border-radius: 8rpx;
margin-bottom: 30rpx;
box-shadow: 0 10rpx 8rpx rgba($color: #878889, $alpha: 0.1);
width: 100%;
display: flex;
padding: 30rpx;
flex-direction: column;
background-color: #FFFFFF;
.row {
display: flex;
padding: 30rpx 0 20rpx;
justify-content: space-around;
align-items: center;
.grid {
width: 20%;
display: flex;
flex-direction: column;
font-size: $font-size-sm;
color: $text-color-assist;
align-items: center;
image {
width: 80rpx;
height: 80rpx;
margin-bottom: 10rpx;
}
}
}
}
.banner {
width: 100%;
border-radius: 8rpx;
margin-bottom: 30rpx;
}
.service-box {
width: 100%;
background-color: #FFFFFF;
padding: 32rpx 30rpx 10rpx;
box-shadow: $box-shadow;
.row {
display: flex;
flex-wrap: wrap;
color: $text-color-assist;
font-size: $font-size-sm;
padding-bottom: -40rpx;
.grid {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-bottom: 40rpx;
width: 25%;
position: relative;
image {
width: 80rpx;
height: 80rpx;
margin-bottom: 20rpx;
}
}
.opacity-0 {
position: absolute;
width: 100%;
height: 100%;
opacity: 0;
z-index: 10;
}
}
}
</style>
@@ -0,0 +1,183 @@
<template>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="$onClickLeft"
/>
<view class="container">
<view class="bg-white">
<uv-tabs :list="tabList" :current="current" @change="change" keyName="name" :scrollable="false"></uv-tabs>
</view>
<view class="orders-list d-flex flex-column w-100" style="padding: 20rpx; padding-bottom: 0;">
<view class="order-item" v-for="(item, index) in orders" :key="index" style="margin-bottom: 30rpx;" >
<list-cell :hover="false">
<view class="w-100 d-flex align-items-center">
<view class="flex-fill d-flex flex-column">
<view class="font-size-lg text-color-base" style="margin-bottom: 20rpx;">
{{ item.shop.name }}
</view>
<view class="font-size-sm text-color-assist">取餐号:{{ item.numberId }}</view>
<view class="font-size-sm text-color-assist">订单编号:{{ item.orderId }}</view>
</view>
<view class="font-size-lg text-color-primary">
{{ item._status._title }}
</view>
</view>
</list-cell>
<list-cell :hover="false" last>
<view class="w-100 d-flex flex-column">
<view class="w-100 text-truncate font-size-lg text-color-base" style="margin-bottom: 20rpx;">
<!-- {{ orderGoodsName(item.cartInfo) }} -->
<view class="flex mb-2" v-for="(good,index) in item.cartInfo" :key="index">
<image :src="good.image" mode="aspectFill" class="image"></image>
<view class="flex flex-column">
<view class="font-size-medium mt-1 text-color-base">{{ good.title }}</view>
<view class="font-size-sm mt-1">{{ good.spec }}</view>
<view class="font-size-sm mt-2">×{{ good.number }} ¥{{ good.price }}</view>
</view>
</view>
</view>
<view class="d-flex justify-content-between align-items-center" style="margin-bottom: 30rpx;">
<view class="font-size-sm text-color-assist">
{{formatDateTime(item.createTime) }}
</view>
<view class="d-flex font-size-sm text-color-base align-items-center">
<view style="margin-right: 10rpx;">共{{ goodsNum(item.cartInfo) }}件商品,实付</view>
<view class="font-size-lg">¥{{ item.payPrice }}</view>
</view>
</view>
<view class="d-flex align-items-center justify-content-end">
<view>
<button v-if="item.paid > 0 && item.status < 2 && item.refundStatus == 0" class="left-margin" plain size="mini" @tap.stop="receive(item)">确认收到餐</button>
<button class="left-margin" plain size="mini" @tap="detail(item.orderId)">订单详情</button>
</view>
</view>
</view>
</list-cell>
</view>
</view>
<uv-empty v-if="orders.length == 0" mode="order"></uv-empty>
</view>
</template>
<script setup>
import {
ref,
computed
} from 'vue'
import { useMainStore } from '@/store/store'
import { storeToRefs } from 'pinia'
import { onLoad,onPullDownRefresh,onReachBottom} from '@dcloudio/uni-app'
import { formatDateTime,kmUnit } from '@/utils/util'
import {
orderGetOrders,
orderReceive
} from '@/api/order'
const main = useMainStore()
const { isLogin } = storeToRefs(main)
const title = ref('我的订单')
const page = ref(1)
const pageSize = ref(10)
const orders = ref([])
const tabList = ref([{
type: -1,
name: '全部',
}, {
type: 0,
name: '待支付',
}, {
type: 1,
name: '进行中'
}, {
type: 4,
name: '已完成'
}, {
type: -3,
name: '退款单'
}]
)
const current = ref(0)
const type = ref(-1)
const orderGoodsName = computed(() => { //计算单个饮品添加到购物车的数量
return (goods) => {
let arr = []
goods.forEach(good => arr.push(good.title + '*' + good.number))
return arr.join(',')
}
})
const goodsNum = computed(() => { //计算单个饮品添加到购物车的数量
return (goods) => {
let num = 0;
goods.forEach(good => num += parseInt(good.number))
return num;
}
})
onLoad(() => {
if(!isLogin.value) {
uni.navigateTo({url: '/pages/components/pages/login/login'})
}
getOrders(false)
})
onPullDownRefresh(() => {
getOrders(false)
})
onReachBottom(() => {
getOrders(false)
})
// tab栏切换
const change = (e) => {
//console.log('e;',e.type)
//console.log('e.index;',e.index)
type.value = e.type
getOrders(true)
}
const getOrders = async(isRefresh = false) => {
uni.showLoading({
title: '加载中'
})
if(isRefresh) {
orders.value = []
page.value = 1
}
let ordersData = await orderGetOrders({page:page.value, limit:pageSize.value,type:type.value});
if(ordersData) {
orders.value = orders.value.concat(ordersData)
page.value += 1
}
uni.stopPullDownRefresh();
uni.hideLoading()
}
const detail = (id) => {
uni.navigateTo({
url: '/pages/components/pages/orders/detail?id=' + id
})
}
// 确认收到货
const receive = async(order) => {
let data = await orderReceive({uni:order.orderId});
if (data) {
await getOrders(true)
}
}
</script>
<style lang="scss" scoped>
.left-margin {
margin-left: 10rpx;
}
.image {
width: 160rpx;
height: 160rpx;
margin-right: 30rpx;
border-radius: 8rpx;
}
</style>