fix: 优化提交订单页面js警告,充值订单跳转bug以及其他bug。refactor: 重构地址选择

This commit is contained in:
黄少君
2024-03-05 12:16:58 +08:00
parent 3fc1284094
commit a9533e2d7f
18 changed files with 553 additions and 671 deletions

View File

@ -17,7 +17,7 @@ export function getAddressAddAndEdit(data) {
// 用户地址列表
export function getAddressList(data) {
return requestUtil.get(`/address/list`, data, {login: true})
return requestUtil.get(`/address/list`, data)
}
// 城市列表

View File

@ -162,3 +162,5 @@ export const wechatPay = (data) => requestUtil.post(`/pay/payment`, data)
* @returns {*}
*/
export const checkPay = (data) => requestUtil.post(`/order/pay/orderQuery`, data)
export const checkRecharge = (data) => requestUtil.get(`/recharge-order/isPay`, data)

View File

@ -60,7 +60,7 @@ async function handleSubmit() {
close()
} catch (e) {
console.error(e)
push({url: '/pages/payStatus/index'}, {data: {type: 2}})
push({url: '/pages/payStatus/index'}, {data: {type: 1}})
toast({title: '支付失败了'})
close()
}

View File

@ -1,11 +1,11 @@
export const VUE_APP_API_URL = 'https://b2c-pro-api-dev.zkthink.com/app-api'
export const VUE_APP_API_URL = 'https://b2c-pro-api.zkthink.com/app-api'
// export const VUE_APP_API_URL = 'https://843308749k.wocp.fun/app-api'
export const VUE_APP_UPLOAD_URL = VUE_APP_API_URL + '/infra/file/upload'
export const VUE_APP_STATIC_URL = "https://b2c-pro-static-dev.zkthink.com/" // 静态资源路径
export const VUE_SHARE_TITLE = '邀请您使用YShop~'
// export const VUE_H5_DOMAIN_NAME = "http://localhost:10086/#"
export const VUE_H5_DOMAIN_NAME = "https://b2c-pro-ui-h5-dev.zkthink.com/#"
export const VUE_H5_DOMAIN_NAME = "https://b2c-pro-ui-h5.zkthink.com/#"
const orderListStatus = {}

View File

@ -8,22 +8,36 @@
/**
* 封装uni app界面相关接口利于维护
* @returns { * }
* @returns {
* {
* toast:Function,
* loading:Function,
* hideLoading:Function,
* setNavTitle:Function,
* setNavBgColor:Function,
* scrollTo:Function,
* pageResize:Function,
* unPageResize:Function,
* startPullDownRefresh:Function,
* stopPullDownRefresh:Function,
* createSelectorQuery:Function,
* createObserver:Function,
* createMediaObserver:Function,
* createAnimation:Function,
* getMenuButtonInfo:Function
* }
* }
*/
export const useInterface = () => {
/**
* 使用uni的toast
* @param options
* @returns {Promise<unknown>}
* @returns {Promise<any>}
*/
function toast(options) {
return new Promise((resolve, reject) => {
uni.showToast({
icon: 'none',
mask: false,
...options,
success: () => resolve(true),
fail: (error) => reject(error)
icon: 'none', mask: false, ...options, success: () => resolve(true), fail: (error) => reject(error)
})
})
}
@ -36,11 +50,7 @@ export const useInterface = () => {
function loading(options = {}) {
return new Promise((resolve, reject) => {
uni.showLoading({
icon: 'none',
mask: true,
...options,
success: () => resolve(true),
fail: (error) => reject(error)
icon: 'none', mask: true, ...options, success: () => resolve(true), fail: (error) => reject(error)
})
})
}
@ -57,9 +67,7 @@ export const useInterface = () => {
function setNavTitle(title) {
return new Promise((resolve, reject) => {
uni.setNavigationBarTitle({
title,
success: () => resolve(true),
fail: (error) => reject(error)
title, success: () => resolve(true), fail: (error) => reject(error)
})
})
}
@ -73,18 +81,14 @@ export const useInterface = () => {
function setNavBgColor(options, timeout = 500) {
return new Promise((resolve, reject) => {
const setNavigationBarColor = () => uni.setNavigationBarColor({
...options,
success: () => resolve(true),
fail: (error) => reject(error)
...options, success: () => resolve(true), fail: (error) => reject(error)
})
if (timeout === 0) {
setNavigationBarColor()
} else {
setTimeout(() => {
uni.setNavigationBarColor({
...options,
success: () => resolve(true),
fail: (error) => reject(error)
...options, success: () => resolve(true), fail: (error) => reject(error)
})
}, timeout)
}
@ -100,9 +104,7 @@ export const useInterface = () => {
function scrollTo(options) {
return new Promise((resolve, reject) => {
uni.pageScrollTo({
...options,
success: () => resolve(true),
fail: (error) => reject(error)
...options, success: () => resolve(true), fail: (error) => reject(error)
})
})
}
@ -134,8 +136,7 @@ export const useInterface = () => {
function startPullDownRefresh() {
return new Promise((resolve, reject) => {
uni.startPullDownRefresh({
success: () => resolve(true),
fail: (error) => reject(error)
success: () => resolve(true), fail: (error) => reject(error)
})
})
}

View File

@ -17,7 +17,7 @@ export const useRouter = () => {
* 注意2.8.9+以后版本可以使用events参数传递一个方法对象和新打开的页面建立一个channel通讯getOpenerEventChannel获取到这个channel
* @docs: https://uniapp.dcloud.net.cn/api/router.html#navigateto
* @param {object} options 原始参数
* @param {object} config 配置参数
* @param {any} config 配置参数
* @param {'navigateTo'|'redirectTo'|'reLaunch'} config.type 跳转类型
* @param {object} config.data 跳转参数
* @param {number} config.timeout 延时时间

View File

@ -2,9 +2,9 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- <meta-->
<!-- http-equiv="Content-Security-Policy"-->
<!-- content="upgrade-insecure-requests">-->
<meta
http-equiv="Content-Security-Policy"
content="upgrade-insecure-requests">
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))

View File

@ -10,7 +10,7 @@ import { createSSRApp } from 'vue'
import store from "@/store";
import util from '@/utils'
// #ifdef H5
import VConsole from 'vconsole'
// import VConsole from 'vconsole'
// #endif

View File

@ -1,68 +1,31 @@
<template>
<layout>
<Header :scroll-top="scrollTop">
{{ title }}
{{ pageTitle }}
</Header>
<view class="addressList">
<template v-if=" main.address.length>0">
<view
class="address-list"
v-if="list.length>0">
<uv-swipe-action>
<uv-swipe-action-item
v-for="(item, index) in main.address"
:key="index"
v-for="(item, index) in list"
:key="item.id"
:options="options"
@click="showModal( item)"
>
<view
:class="{ address: true, noBorder: index == 0 }"
@tap="handleClick(item)"
>
<view class="address-main">
<view class="address-header">
<view class="address-name">{{ item.realName }}</view>
<view class="address-phone">{{ item.phone }}</view>
</view>
<view class="address-content">
<view
class="address-default"
v-if="item.isDefault"
>
<uv-tags
text="默认"
plain
size="mini"
></uv-tags>
</view>
<view class="address-desc">{{ item.province }}-{{ item.city }}-{{ item.district }} {{
item.detail
}}
</view>
</view>
</view>
<view class="address-actions">
<view
class="address-actions-edit"
@tap.stop="goEditorAddress(item)"
>
<image
class="image"
:src="addressEditIcon"
alt=""
></image>
</view>
</view>
</view>
<AddressItem
:address-item="item"
:border="index!==list.length - 1"
@edit="goEditorAddress"
@click="handleClick" />
</uv-swipe-action-item>
</uv-swipe-action>
</template>
</view>
<Empty
:iconSrc="emptyAddressIcon"
v-else
>
您还没有新增地址~
</Empty>
</view>
<view class="form-buttons">
<view class="btn">
<uv-button
@ -77,102 +40,105 @@
</view>
<ReturnTop :scroll-top="scrollTop" />
<Modal
ref="modalRef"
ref="delModalRef"
content="确认要删除地址吗?"
@confirm="doDeleteRequest" />
</layout>
</template>
<script setup>
import { ref, unref } from 'vue'
import { onLoad, onReachBottom } from '@dcloudio/uni-app'
import { useMainStore } from '@/store/modules/useMainStore'
import { ref, unref, computed } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import Empty from '@/components/Empty/index.vue'
import { addressEditIcon, emptyAddressIcon } from "@/utils/images";
import { getAddressDel, } from '@/api/address'
import { emptyAddressIcon } from "@/utils/images";
import { getAddressDel, getAddressList, } from '@/api/address'
import { useRouter } from "@/hooks/useRouter";
import Header from "@/components/Header/index.vue"
import ReturnTop from "@/components/ReturnTop/index.vue";
import { useScroll } from "@/hooks/useScroll";
import Modal from "@/components/Modal/index.vue";
import UvSwipeAction from "@/uni_modules/uv-swipe-action/components/uv-swipe-action/uv-swipe-action.vue";
import UvSwipeActionItem from "@/uni_modules/uv-swipe-action/components/uv-swipe-action-item/uv-swipe-action-item.vue";
import AddressItem from "@/pages/address/component/AddressItem.vue";
import UvButton from "@/uni_modules/uv-button/components/uv-button/uv-button.vue";
import { usePaging } from "@/hooks/usePaging";
import { emitter } from "@/utils/emitter";
const {push, goBack} = useRouter()
// ================================= hooks =============================================
const {push, goBack, getParams} = useRouter()
const {scrollTop} = useScroll()
const title = ref('')
const main = useMainStore()
const moreLoding = ref(true)
const actionType = ref('')
const page = ref(1)
const selectCartId = ref(undefined)
const actionType = ref(undefined) // 页面状态是选择还是管理 'select' | undefined
const pageTitle = computed(() => actionType.value === 'select' ? '选择地址' : '地址管理') // 页面title
// swipe配置
const options = ref([{
text: '删除',
// text: '删 除',
icon: 'trash',
style: {
backgroundColor: '#EE6D46'
}
}])
onReachBottom((e) => {
if (main.moreLoading) {
page.value = page.value + 1
main.getAddressList(page.value)
}
})
const goCreateAddress = () => {
let addressData = {};
if (actionType.value === 'select') {
addressData.type = 'select';
}
push({url: '/pages/createAddress/createAddress'}, {data: addressData})
}
const goEditorAddress = (address) => {
let addressData = {
id: address.id
};
if (actionType.value === 'select') {
addressData.type = 'select';
}
push({url: '/pages/createAddress/createAddress'}, {data: addressData})
}
const handleClick = (item) => {
if (actionType.value === 'select') {
main.setSelectAddress(item.id)
goBack()
// push({url: '/pages/submitOrder/submitOrder'}, {
// data: {cartId: unref(selectCartId) || main.cartId},
// type: 'redirectTo'
// })
}
}
const {getParams} = useRouter()
onLoad((option) => {
main.restAddress()
const params = getParams(option)
params.cartId ? main.cartId = params.cartId : void (0)
if (params.type) {
actionType.value = params.type
title.value = '选择地址'
selectCartId.value = params.cartId
} else {
title.value = '地址管理'
}
main.getAddressList(page.value)
const params = getParams?.(option)
actionType.value = params?.type
})
const modalRef = ref()
const prepareData = ref({})
onShow(() => {
refreshPage?.()
})
// ============================== 用户地址列表相关 =================================
const {list, refreshPage} = usePaging({
request: getAddressList,
// load: true
});
/**
* 去创建地址
*/
function goCreateAddress() {
push?.({url: '/pages/createAddress/createAddress'}, {
data: {
type: actionType.value
}
})
}
/**
* 去修改地址
* @param address
*/
function goEditorAddress(address) {
push?.({url: '/pages/createAddress/createAddress'}, {
data: {
type: actionType.value,
address
}
})
}
/**
* 处理选择状态下返回
* @param item
*/
function handleClick(item) {
if (actionType.value === 'select') {
emitter.emit('selectAddress', item)
goBack?.({delta: 1})
}
}
// ============================ 删除相关 ============================
const delModalRef = ref()
const prepareData = ref(undefined)
/**
* 打开弹窗
*/
function showModal(data) {
prepareData.value = data
unref(modalRef).show()
unref(delModalRef).show()
}
/**
@ -180,110 +146,20 @@ function showModal(data) {
*/
async function doDeleteRequest() {
await getAddressDel(prepareData.value)
await main.restAddress()
await main.getAddressList(1)
if (main.selectAddress && prepareData.value.id === main.selectAddress.id) {
main.clearSelectAddress()
}
await refreshPage?.()
}
</script>
<style lang="scss">
@import "../../style/images";
.address {
padding: 25rpx 35rpx;
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
&-actions {
&-edit {
width: 33rpx;
height: 33rpx;
.image {
width: 100%;
height: 100%;
display: block;
}
}
}
&.noBorder {
&::after {
display: none;
}
}
&::after {
content: '';
position: absolute;
left: 35rpx;
top: 0;
right: 0;
height: 1rpx;
background: #E6E6E6;
}
background: #fff;
&-header {
display: flex;
align-items: center;
margin-bottom: 8rpx;
}
&-name {
line-height: 40rpx;
font-size: 28rpx;
color: #333333;
margin-right: 30rpx;
}
&-phone {
line-height: 40rpx;
font-size: 28rpx;
color: #333333;
}
&-content {
display: flex;
align-items: center;
padding-right: 10rpx;
}
&-default {
width: 80rpx;
margin-right: 20rpx;
}
&-desc {
flex: 1;
line-height: 33rpx;
font-size: 24rpx;
color: #999999;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
}
.addressList {
.address-list {
padding-bottom: 100rpx;
}
.form-buttons {
position: fixed;
bottom: env(safe-area-inset-bottom);
bottom: calc(env(safe-area-inset-bottom) + 20rpx);
left: 0;
z-index: 999;
width: 100%;
@ -295,25 +171,4 @@ async function doDeleteRequest() {
margin: 0 auto;
}
.address-default :deep(.uv-tags) {
justify-content: center;
white-space: nowrap;
}
.addressList :deep(.uv-swipe-action-item__right__button__wrapper) {
position: relative;
&:before {
position: absolute;
content: '';
background: $addDelIcon no-repeat center center;
width: 50rpx;
height: 50rpx;
background-size: contain;
}
}
.addressList :deep(.uv-swipe-action-item__right__button__wrapper__text) {
visibility: hidden;
}
</style>

View File

@ -0,0 +1,139 @@
<!--
@name: addressItem
@author: kahu4
@date: 2024-03-04 15:58
@descriptionaddressItem
@update: 2024-03-04 15:58
-->
<script setup>
import { addressEditIcon } from "@/utils/images";
import { toRefs } from "vue";
import UvTags from "@/uni_modules/uv-tags/components/uv-tags/uv-tags.vue";
const emits = defineEmits(['edit', 'click'])
const props = defineProps({
addressItem: {
type: Object,
required: true
},
border: {
type: Boolean,
default: true
}
})
const {addressItem, border} = toRefs(props)
</script>
<template>
<view
class="address"
:class="{'no-border':!border}"
@tap="emits('click',addressItem)"
>
<view class="address-main">
<view class="address-header">
<view class="address-name">{{ addressItem.realName }}</view>
<view class="address-phone">{{ addressItem.phone }}</view>
</view>
<view class="address-content">
<view
class="address-default"
v-if="addressItem.isDefault"
>
<uv-tags
text="默认"
plain
size="mini"
/>
</view>
<view class="address-desc">
{{ addressItem.province }}-{{ addressItem.city }}-{{ addressItem.district }} {{ addressItem.detail }}
</view>
</view>
</view>
<view class="address-actions">
<view
class="address-actions-edit"
@tap.stop="emits('edit',addressItem)"
>
<image
class="image"
:src="addressEditIcon"
/>
</view>
</view>
</view>
</template>
<style
scoped
lang="scss">
.address {
padding: 25rpx 35rpx;
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
&-actions {
&-edit {
width: 33rpx;
height: 33rpx;
.image {
width: 100%;
height: 100%;
display: block;
}
}
}
background: #fff;
&-header {
display: flex;
align-items: center;
margin-bottom: 8rpx;
}
&-name {
line-height: 40rpx;
font-size: 28rpx;
color: #333333;
margin-right: 30rpx;
}
&-phone {
line-height: 40rpx;
font-size: 28rpx;
color: #333333;
}
&-content {
display: flex;
align-items: center;
padding-right: 10rpx;
}
&-default {
width: 80rpx;
margin-right: 20rpx;
}
&-desc {
flex: 1;
line-height: 33rpx;
font-size: 24rpx;
color: #999999;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
}
</style>

View File

@ -1,13 +1,7 @@
<template>
<layout>
<uv-navbar
:fixed="false"
:title="title"
left-arrow
@leftClick="goBack"
/>
<view>
<Header>{{ title }}</Header>
<view class="create-address">
<view class="list noBorder">
<view class="list-main">
<view class="list-label w-158">
@ -15,15 +9,15 @@
</view>
<view
class="list-content"
@click="handleChooseAddress"
@click="openAddressSelect"
>
<template v-if="addressData.address.cityId">
{{ addressData.address.province }} {{ addressData.address.city }} {{ addressData.address.district }}
<template v-if="form.address.cityId">
{{ form.address.province }} {{ form.address.city }} {{ form.address.district }}
</template>
<template v-else>
<span class="chooise">
<span class="choose">
点击选择
<uv-icon name="arrow-right"></uv-icon>
<uv-icon name="arrow-right" />
</span>
</template>
</view>
@ -38,7 +32,7 @@
<input
type="text"
placeholder="请输入详细地址"
v-model="addressData.detail"
v-model="form.detail"
/>
</view>
</view>
@ -52,7 +46,7 @@
<input
type="text"
placeholder="请输入姓名"
v-model="addressData.realName"
v-model="form.realName"
/>
</view>
@ -68,23 +62,21 @@
type="tel"
placeholder="请输入电话"
maxlength="11"
v-model="addressData.phone"
@input="phoneInput"
v-model="form.phone"
/>
</view>
</view>
</view>
</view>
<view class="form-checkbox">
<uv-checkbox-group v-model="isDefaultList">
<uv-checkbox-group v-model="defaultAddress">
<uv-checkbox
shape="circle"
label="设为默认地址"
name="isDefault"
labelColor="#999999"
activeColor="#EE6D46"
@change="changeDefault"
></uv-checkbox>
/>
</uv-checkbox-group>
</view>
<view class="form-buttons">
@ -92,38 +84,41 @@
type="primary"
text="提交"
customStyle="margin-top: 10px"
@click="onSave"
></uv-button>
@click="submit"
/>
</view>
<AddressSelect
ref="addressSelectRef"
@confirm="addressSelectConfirm" />
</view>
<uv-picker
ref="addressPickerRef"
:columns="columns"
keyName="name"
@change="handlePickerChange"
@confirm="handlePickerConfirm"
></uv-picker>
</layout>
</template>
<script setup>
import { computed, nextTick, onMounted, ref, unref, watch } from 'vue'
import { computed, onMounted, ref, unref, } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useMainStore } from '@/store/modules/useMainStore'
import { getAddressAddAndEdit, getAddressDel, } from '@/api/address'
import { getAddressAddAndEdit } from '@/api/address'
import { useRouter } from "@/hooks/useRouter";
import { storeToRefs } from "pinia";
import UvPicker from "@/uni_modules/uv-picker/components/uv-picker/uv-picker.vue";
import Header from "@/components/Header/index.vue";
import UvCheckboxGroup from "@/uni_modules/uv-checkbox/components/uv-checkbox-group/uv-checkbox-group.vue";
import UvCheckbox from "@/uni_modules/uv-checkbox/components/uv-checkbox/uv-checkbox.vue";
import UvButton from "@/uni_modules/uv-button/components/uv-button/uv-button.vue";
import UvIcon from "@/uni_modules/uv-icon/components/uv-icon/uv-icon.vue";
import AddressSelect from '@/components/AddressSelect/index.vue'
import { useInterface } from "@/hooks/useInterface";
import { checkPhone } from "@/utils/utils";
const main = useMainStore()
// ========================== hooks ================================================
const {toast} = useInterface();
const {getParams, push, goBack} = useRouter()
const {areaList, address} = storeToRefs(main)
// const areaList = ref(main.areaList)
const title = ref('')
const title = computed(() => form.value.id ? '编辑地址' : '添加地址')
const defaultAddress = ref([]) // 是否为默认地址 ['isDefault']默认 []非默认
const actionType = ref(undefined) // 是否是选择地址
const editId = ref('')
const addressData = ref({
// =========================== 表单相关 ==========================================
// 表单
const form = ref({
id: undefined,
realName: undefined,
phone: undefined,
detail: undefined,
@ -136,209 +131,108 @@ const addressData = ref({
}
});
const isDefaultList = ref([])
const changeDefault = (props) => {
addressData.value.isDefault = props
/**
* 校验表单
* @param form
* @return {boolean}
*/
function checkForm(form) {
if (!form.address?.cityId) {
toast?.({title: "请选择收货地址"})
return false
}
const actionType = ref('')
const onSave = async () => {
if (!addressData.value.address?.cityId) {
uni.showToast({
title: "请选择收货地址",
icon: "none",
duration: 2000
});
return;
if (!form.detail) {
toast?.({title: "请输入详细地址"})
return false
}
if (!addressData.value.detail) {
uni.showToast({
title: "请输入详细地址!",
icon: "none",
duration: 2000
});
return;
if (!form.realName) {
toast?.({title: "请输入姓名"})
return false
}
if (!addressData.value.realName) {
uni.showToast({
title: "请输入姓名!",
icon: "none",
duration: 2000
});
return;
if (!checkPhone(form.phone)) {
toast?.({title: "请输入正确手机号"})
return false
}
if (!addressData.value.phone || !(/^1[34578]\d{9}$/.test(addressData.value.phone))) {
uni.showToast({
title: "请输入正确手机号!",
icon: "none",
duration: 2000
});
return;
return true
}
uni.showLoading({
title: '保存中',
mask: true,
})
const submitLoading = ref(false) // 是否正在提交
/**
* 提交表单
* @return {Promise<void>}
*/
async function submit() {
if (!checkForm(form.value) || submitLoading.value) return
try {
let res = await getAddressAddAndEdit({
id: editId.value,
realName: addressData.value.realName,
postCode: addressData.value.postCode,
isDefault: addressData.value.isDefault ? 1 : 0,
detail: addressData.value.detail,
phone: addressData.value.phone,
address: {
cityId: addressData.value.address.cityId,
city: addressData.value.address.city,
district: addressData.value.address.district,
province: addressData.value.address.province,
}
submitLoading.value = true
await getAddressAddAndEdit({
...form.value,
postCode: undefined,
isDefault: defaultAddress.value.length > 0 ? 1 : 0,
})
uni.showToast({
title: "保存成功",
icon: "none",
duration: 2000
});
uni.hideLoading()
main.restAddress()
if (actionType.value == 'select') {
push({url: '/pages/address/address'}, {data: {type: 'select'}, type: 'redirectTo'})
} else {
main.getAddressList(1)
toast?.({title: '保存成功'})
goBack()
} finally {
submitLoading.value = false
}
} catch (error) {
console.log(error, 'err')
// closeToast()
if (error.msg) {
// showFailToast(error.msg);
}
}
};
const onDelete = async () => {
getAddressDel()
main.getAddressList(1)
};
const result = (values) => {
addressData.value.address = {
province: values.province.name || '',
city: values.city.name || '',
district: values.district.name || '',
cityId: values.city.id,
}
}
const addressPickerRef = ref()
const provinces = ref([])
const citys = ref([])
const areas = ref([])
const pickerValue = ref([0, 0, 0])
const defaultValue = ref([0, 0, 0])
const columns = computed(() => {
return [
provinces.value, citys.value, areas.value
]
})
function handleSetDefaultColumns() {
console.log(addressPickerRef.value)
pickerValue.value[0] = provinces.value.findIndex((item, index) => index === defaultValue.value[0])
citys.value = provinces.value[pickerValue.value[0]].children || []
pickerValue.value[1] = citys.value.findIndex((item, index) => index === defaultValue.value[1])
areas.value = citys.value[pickerValue.value[1]].children || []
pickerValue.value[2] = areas.value.findIndex((item, index) => index === defaultValue.value[2])
// 重置下位置
// addressPickerRef.value.setColumnValues(0,provinces.value)
// addressPickerRef.value.setColumnValues(1,citys.value)
// addressPickerRef.value.setColumnValues(2,areas.value)
nextTick(() => {
addressPickerRef.value.setIndexs([pickerValue.value[0], pickerValue.value[1], pickerValue.value[2]], true);
console.log('设置完毕')
})
}
function handlePickerChange(e) {
const {columnIndex, index, indexs} = e
// 改变了省
if (columnIndex === 0) {
citys.value = provinces.value[index]?.children || []
areas.value = citys.value[0]?.children || []
addressPickerRef.value.setIndexs([index, 0, 0], true)
} else if (columnIndex === 1) {
areas.value = citys.value[index]?.children || []
addressPickerRef.value.setIndexs(indexs, true)
}
}
function handlePickerConfirm(e) {
const {indexs, value} = e
defaultValue.value = indexs
addressData.value.address = {
province: value[0].name || '',
city: value[1].name || '',
district: value[2].name || '',
cityId: value[1].id,
}
}
function handleFindDefault(data) {
const provinceIndex = areaList.value.findIndex(item => item.name === data.province);
const cityIndex = areaList.value[provinceIndex].children.findIndex(item => item.name === data.city);
const areasIndex = areaList.value[provinceIndex].children[cityIndex].children.findIndex(item => item.name === data.district);
defaultValue.value = [provinceIndex, cityIndex, areasIndex]
}
function handleChooseAddress() {
provinces.value = areaList.value
handleSetDefaultColumns()
unref(addressPickerRef).open()
}
/**
* 手机号验证
* 设置编辑表单
* @param addressItem
*/
function phoneInput(event) {
const pattern = /[^\d]/g;
nextTick(() => {
addressData.value.phone = event.detail.value.replace(pattern, '');
})
function setFormDefault(addressItem) {
form.value.id = addressItem.id
form.value = {
...form.value,
...addressItem,
address: {
cityId: addressItem.cityId,
city: addressItem.city,
district: addressItem.district,
province: addressItem.province,
}
}
// 默认地址
if (addressItem.isDefault) {
defaultAddress.value = ['isDefault']
}
}
// ================================= 地址选择相关 ==================================
const addressSelectRef = ref()
/**
* 打开选择地址
*/
function openAddressSelect() {
const {address} = unref(form)
let defaultAddressStr = ''
if (address.province && address.city && address.district) {
defaultAddressStr = `${ address.province }-${ address.city }-${ address.district }`
}
unref(addressSelectRef).open(defaultAddressStr)
}
/**
* 地址选择confirm
* @param areaList 地区 [省, 市, 区]
*/
function addressSelectConfirm(areaList) {
if (areaList.length < 3) return
const {address} = unref(form)
address.province = areaList[0]?.name
address.city = areaList[1]?.name
address.cityId = areaList[2]?.id
address.district = areaList[2]?.name
}
onLoad(async (options) => {
const params = getParams(options)
let id = params.id
actionType.value = params.type
// main.restAddress()
await main.getAddressCityList()
if (id) {
editId.value = id
title.value = '编辑地址'
let data = address.value.filter(item => item.id == id)[0]
if (!data) return
addressData.value = {
realName: data.realName,
phone: data.phone,
detail: data.detail,
isDefault: data.isDefault,
address: {
cityId: data.cityId,
city: data.city,
district: data.district,
province: data.province,
}
}
console.log(addressData.value)
// 设置默认选择
handleFindDefault(data)
isDefaultList.value = data.isDefault ? ['isDefault'] : []
} else {
title.value = '新增地址'
const params = getParams?.(options)
actionType.value = params?.type
if (params?.address) {
setFormDefault(params?.address)
}
})
onMounted(() => {
@ -358,8 +252,8 @@ onMounted(() => {
flex: 0 0 158rpx;
}
.chooise {
.choose {
@include useFlex(space-between, center);
color: #999;
color: #808080;
}
</style>

View File

@ -9,7 +9,7 @@
import { useRouter } from "@/hooks/useRouter";
import { computed, nextTick, ref, unref } from "vue";
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
import {checkPay, orderInfo} from "@/api/order";
import { checkPay, checkRecharge, orderInfo } from "@/api/order";
import { CacheKey } from "@/utils/config";
import Header from '@/components/Header/index.vue'
import Recommend from '@/components/Recommend/index.vue'
@ -47,7 +47,7 @@ const retryTime = ref(3) // 重试次数
* 查询服务端支付状态
*/
async function queryOrderStatus() {
loading({title: '查询中...'})
loading?.({title: '查询中...'})
// 异步去查,有可能接口比微信快
setTimeout(async () => {
try {
@ -57,6 +57,8 @@ async function queryOrderStatus() {
return orderType.value === 2 ? toMyBalance() : toOrderList(0)
}
const parse = JSON.parse(payInfoStr);
// 商品
if (orderType.value === 1) {
if (parse.options && parse.options.isGroup) {
campaignType.value = 1
}
@ -74,19 +76,43 @@ async function queryOrderStatus() {
uni.removeStorageSync(CacheKey.PAY_INFO)
}
return
} else {
type.value = 1
uni.removeStorageSync(CacheKey.PAY_INFO)
}
// todo 查询订单详情
// 平团
if (parse.options && parse.options.isGroup) {
const order = await orderInfo({key: parse.payData.orderId})
if (order && order._status._type === '8') {
campaignType.value = 4
}
console.log(campaignType.value)
}
}
if (orderType.value === 2) {
const res = await checkRecharge({
id: parse.payData.orderId
})
console.log(res)
if (Number(res) === 0) {
// 支付失败重新查询
if (retryTime.value > 0) {
retryTime.value--
await queryOrderStatus()
} else {
type.value = 2
uni.removeStorageSync(CacheKey.PAY_INFO)
}
} else {
type.value = 1
uni.removeStorageSync(CacheKey.PAY_INFO)
}
}
} catch (e) {
retryTime.value = 0
type.value = 2
uni.removeStorageSync(CacheKey.PAY_INFO)
} finally {
hideLoading()
hideLoading?.()
}
}, 500)
}
@ -129,8 +155,12 @@ onReachBottom(() => {
const orderType = ref(1) // 1商品 2充值
onLoad(async (options) => {
if (options.details) {
options = getParams?.(options)
}
console.log(options)
// type
orderType.value = options.type
orderType.value = Number(options.type) || 1
// const params = getParams(options)
// campaignType.value = params.campaignType
// H5 和 APP 需要弹窗去确认
@ -177,6 +207,7 @@ onLoad(async (options) => {
text="查询中..." />
</view>
<view class="button-group flex flex-ai__center flex-jc__center">
<template v-if="orderType === 1">
<view
class="animation-button button white-button"
v-if="Number(type)===1"
@ -184,7 +215,6 @@ onLoad(async (options) => {
>
继续逛逛
</view>
<template v-if="orderType !== 1">
<view
class="animation-button button"
v-if="Number(type)===1"

View File

@ -25,7 +25,7 @@ onPageScroll(() => {
const {getParams, push, goBack} = useRouter()
const {toast, loading, hideLoading} = useInterface();
const mainStore = useMainStore();
const {selectAddress, defaultAddress, address, integralName} = storeToRefs(mainStore);
const {integralName} = storeToRefs(mainStore);
const campaignType = ref(0)
const zeroPrice = ref(false) // 本单支付金额是否为0
/**
@ -34,20 +34,19 @@ const zeroPrice = ref(false) // 本单支付金额是否为0
*/
async function calculateOrder() {
orderDetail.value = await orderConfirm({
cartId: unref(routerParams).cartId,
orderType: unref(routerParams).orderType,
cartId: unref(routerParams)?.cartId,
orderType: unref(routerParams)?.orderType,
addressId: unref(selectAddress)?.id || undefined,
shippingType: addressTabSelect.value, // 默认快递 1快递 2门店
storeId: shopSelect.value?.id,
useIntegral: useIntegral.value.length > 0,
couponId: currentCouponId.value
})
console.log(orderDetail.value)
// 余额为0 自动走余额支付
if (orderDetail.value.priceGroup.totalPrice <= 0) {
payType.value = PayType["1"]
zeroPrice.value = true
toast({title: '支付金额为0.00,自动选择余额支付', icon: 'none', duration: 3000})
toast?.({title: '支付金额为0.00,自动选择余额支付', icon: 'none', duration: 3000})
} else {
zeroPrice.value = false
}
@ -59,13 +58,13 @@ const currentCouponId = ref(undefined)
const selectCouponFn = async (coupon) => {
currentCouponId.value = coupon.couponId
await calculateOrder()
selectCouponRef.value.close()
selectCouponRef.value?.close()
}
const showCouponSelect = (index) => {
if (index === 0) {
selectCouponRef.value.open()
selectCouponRef.value?.open()
}
}
@ -86,29 +85,25 @@ function changeAddressTab(tab) {
* 去选择地址
*/
function gotoSelectAddress() {
push({url: '/pages/address/address'}, {data: {type: 'select', cartId: unref(routerParams).cartId}})
push?.({url: '/pages/address/address'}, {
data: {
type: 'select', cartId: unref(routerParams)?.cartId
}
})
}
/**
* 获取默认选择的地址
*/
async function doGetSelectAddress() {
// store内部没有地址就先去获取地址
if (unref(address).length <= 0) {
await mainStore.getAddressList(1)
}
// 获取完地址还是空
if (unref(address).length <= 0) {
return
}
// 没有默认地址设置默认地址
if (!selectAddress.value || !selectAddress.value?.id) {
defaultAddress.value && defaultAddress.value.id ? mainStore.setSelectAddress(defaultAddress.value.id) : mainStore.setSelectAddress(unref(address)[0].id)
doGetInitConfirmOrder()
if (!selectAddress.value && orderDetail.value?.addressInfo) {
selectAddress.value = orderDetail.value?.addressInfo
await doGetInitConfirmOrder()
}
}
const shopSelect = ref(null) // 当前选择的店铺
const selectAddress = ref(null) // 当前选择的地址
// 注册事件监听
emitter.on('selectShop', (res) => {
@ -116,7 +111,9 @@ emitter.on('selectShop', (res) => {
shopSelect.value = res
doGetInitConfirmOrder()
})
emitter.on('selectAddress', async () => {
emitter.on('selectAddress', async (item) => {
// item
selectAddress.value = item
// 处理门店选择逻辑
await doGetSelectAddress()
await doGetInitConfirmOrder()
@ -126,7 +123,7 @@ emitter.on('selectAddress', async () => {
* 选择店铺
*/
function selectShop() {
push({url: '/pages/submitOrder/shopSelect'}, {data: {shopSelect: shopSelect.value}})
push?.({url: '/pages/submitOrder/shopSelect'}, {data: {shopSelect: shopSelect.value}})
}
// =============================== 订单信息相关 ======================================================
@ -155,8 +152,8 @@ const orderDetail = ref({
*/
async function doGetInitConfirmOrder() {
await calculateOrder()
cartIds.value = unref(routerParams).cartId
currentCouponId.value = orderDetail.value.priceGroup.couponId
cartIds.value = unref(routerParams)?.cartId
currentCouponId.value = orderDetail.value.priceGroup?.couponId
flag.value = true
}
@ -177,11 +174,11 @@ const subLoading = ref(false) // 加载中
*/
async function handleConfirm() {
if (addressTabSelect.value === 1 && (!unref(selectAddress) || !unref(selectAddress).id)) {
toast({title: '请先选择地址'})
toast?.({title: '请先选择地址'})
return
}
if (addressTabSelect.value === 2 && !shopSelect.value) {
toast({title: '请先选择门店'})
toast?.({title: '请先选择门店'})
return
}
subLoading.value = true
@ -190,18 +187,18 @@ async function handleConfirm() {
// 去拉取支付
await doPayment({type: payType.value, payInfo, isGroup: routerParams.value.campaignType === 1})
// #ifndef H5
push({url: '/pages/payStatus/index'}, {data: {campaignType: campaignType.value}, type: 'redirectTo'})
push?.({url: '/pages/payStatus/index'}, {data: {campaignType: campaignType.value}, type: 'redirectTo'})
// #endif
// 处理微信内h5
// #ifdef H5
if (h5InWeChat()) {
push({url: '/pages/payStatus/index'}, {data: {campaignType: campaignType.value}, type: 'redirectTo'})
push?.({url: '/pages/payStatus/index'}, {data: {campaignType: campaignType.value}, type: 'redirectTo'})
}
// #endif
} catch (e) {
console.error(e)
toast({title: '支付失败'})
push({url: '/pages/payStatus/index'}, {data: {campaignType: campaignType.value}, type: 'redirectTo'})
toast?.({title: '支付失败'})
push?.({url: '/pages/payStatus/index'}, {data: {campaignType: campaignType.value}, type: 'redirectTo'})
} finally {
subLoading.value = false
mainStore.cartId = null
@ -213,11 +210,11 @@ async function handleConfirm() {
*/
async function doCreateServiceOrder() {
try {
loading({title: '订单创建中...'})
loading?.({title: '订单创建中...'})
const data = {
key: unref(orderDetail).orderKey,
addressId: unref(selectAddress) && unref(selectAddress).id,
storeId: unref(shopSelect) && unref(shopSelect).id,
key: unref(orderDetail)?.orderKey,
addressId: unref(selectAddress)?.id,
storeId: unref(shopSelect)?.id,
bargainId: 0,
combinationId: 0,
couponId: currentCouponId.value,
@ -235,7 +232,7 @@ async function doCreateServiceOrder() {
const res = await orderCreate(data);
return res.result
} finally {
hideLoading()
hideLoading?.()
}
}
@ -245,15 +242,15 @@ async function doCreateServiceOrder() {
*/
function setActivityData(data) {
// 处理活动数据 路由参数 orderType 1普通下单 2活动下单
if (routerParams.value.orderType !== 2) return
if (routerParams.value?.orderType !== 2) return
// 活动商品
data.campaignType = routerParams.value.campaignType // 1拼团 2秒杀 3砍价
campaignType.value = routerParams.value.campaignType
data.campaignDetailId = routerParams.value.campaignDetailId // 活动营销ID
data.campaignType = routerParams.value?.campaignType // 1拼团 2秒杀 3砍价
campaignType.value = routerParams.value?.campaignType
data.campaignDetailId = routerParams.value?.campaignDetailId // 活动营销ID
// 拼团 路由参数 campaignType 1拼团活动
if (routerParams.value.campaignType !== 1) return;
data.teamworkType = routerParams.value.teamworkType // 1发起拼团 2加入
data.teamworkType === 2 ? data.teamworkId = routerParams.value.teamworkId : void (0) // 加入拼团的id
if (routerParams.value?.campaignType !== 1) return;
data.teamworkType = routerParams.value?.teamworkType // 1发起拼团 2加入
data.teamworkType === 2 ? data.teamworkId = routerParams.value?.teamworkId : void (0) // 加入拼团的id
}
@ -267,7 +264,7 @@ const cartIds = ref('')
*/
function checkRouterParam(params) {
if (!params.cartId) {
toast({title: '路由参数错误'})
toast?.({title: '路由参数错误'})
return
}
routerParams.value = params
@ -276,7 +273,7 @@ function checkRouterParam(params) {
onLoad(async options => {
try {
const params = getParams(options)
const params = getParams?.(options)
await checkRouterParam(params)
} catch (e) {
console.error(e)
@ -318,8 +315,8 @@ onShow(async () => {
<!-- address info -->
<template v-if="addressTabSelect === 1">
<view
v-if="selectAddress"
class="address-row flex flex-ai__center flex-jc__sb"
v-if="address.length>0"
@click="gotoSelectAddress"
>
<view
@ -351,7 +348,7 @@ onShow(async () => {
v-else
@click="gotoSelectAddress"
>
点击添加地址
点击选择地址
<image
class="arrow-icon"
:src="nextIcon"

View File

@ -12,18 +12,13 @@ const {push} = useRouter()
export const useMainStore = defineStore('main', {
state: () => ({
user: null,
address: [],
areaList: [],
selectAddress: null,
moreLoading: true,
cartId: null,
integralName: '积分'
}),
getters: {
defaultAddress(state) {
return state.address?.filter(item => item.isDefault)?.[0]
},
},
getters: {},
actions: {
setAccessToken(user) {
cookie.set('accessToken', user)
@ -37,25 +32,7 @@ export const useMainStore = defineStore('main', {
this.user = res
return res
},
restAddress() {
this.address = []
this.moreLoading = true
},
clearSelectAddress() {
this.selectAddress = null
},
async getAddressList(page) {
let res = await getAddressList({page: page})
if (res.length) {
this.address = this.address.concat(res)
} else {
this.moreLoading = false
}
// console.log('--> % getUserInfo % res:\n', res)
},
async getAddressCityList() {
this.areaList = await getAddressCityList()
},
init() {
let accessToken = cookie.get('accessToken')
if (accessToken) {

View File

@ -865,15 +865,6 @@ image {
display: none;
}
.address::after {
content: '';
position: absolute;
left: 35rpx;
top: 0;
right: 0;
height: 1rpx;
background: #e6e6e6;
}
.address-icon {
margin-right: 20rpx;

View File

@ -281,9 +281,9 @@ function _aliPay(payInfo) {
/**
* 余额支付
* @param payInfo
* @return {Promise<never>}
* @private
* @param options
*/
async function _balancePay(options) {
let from

View File

@ -31,14 +31,6 @@ export function formatRemainTime(time) {
return `还剩${ remainTimeStr }自动确认`
}
/**
* 正则检测大陆手机号
* @param phone
*/
export function checkPhone(phone) {
return /^1[3456789]\d{9}$/.test(phone);
}
/**
* 创建一个滚动动画
@ -261,3 +253,7 @@ export const filterParams = (obj) => {
}
return newObj;
}
export const checkPhone = (phone) => {
return /^1[3456789]\d{9}$/.test(phone)
}

View File

@ -117,12 +117,12 @@ async function confirm() {
payInfo: {orderId}
})
// #ifndef H5
push({url: '/views/account/balance/index'})
push?.({url: '/pages/payStatus/index?type=2'})
// #endif
// 处理微信内h5
// #ifdef H5
if (h5InWeChat()) {
push({url: '/views/account/balance/index'})
push?.({url: '/pages/payStatus/index?type=2'})
}
// #endif
} catch (e) {