代码提交
This commit is contained in:
47
.gitignore
vendored
Normal file
47
.gitignore
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
/unpackage/dist/dev
|
||||||
|
/unpackage/dist/static
|
||||||
|
/unpackage/dist/build/mp-alipay/
|
||||||
|
/unpackage/dist/build/mp-weixin/
|
||||||
|
/unpackage/dist/build/app-plus/
|
||||||
|
/unpackage/dist/build/.automator
|
||||||
|
/unpackage/cache/
|
||||||
|
/unpackage/cache/apk
|
||||||
|
/unpackage/release
|
||||||
|
/unpackage/res
|
||||||
|
/unpackage/resources
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
.cache
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
.tmp*
|
||||||
|
.svn
|
||||||
|
.tags
|
||||||
|
*.sublime-*
|
||||||
|
sftp-config.json
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
.idea*
|
||||||
|
.yo-rc.json
|
||||||
|
*.swo
|
||||||
|
*.swp
|
||||||
|
/deps
|
||||||
|
yarn.lock
|
||||||
|
dev-stats.json
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.hbuilderx
|
||||||
|
.history
|
18
api/api.js
18
api/api.js
@ -144,3 +144,21 @@ const request = ['post', 'put', 'patch'].reduce((request, method) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
export default request
|
export default request
|
||||||
|
|
||||||
|
export const upload = (options)=>{
|
||||||
|
const token = cookie.get('accessToken')
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
uni.showLoading({title:'上传中'})
|
||||||
|
uni.uploadFile({
|
||||||
|
...options,
|
||||||
|
header:{
|
||||||
|
...options.headers,
|
||||||
|
Authorization: 'Bearer ' + token.accessToken,
|
||||||
|
},
|
||||||
|
url:options.url?`${VUE_APP_API_URL}${options.url}`:VUE_APP_API_URL+'/member/user/update-avatar',
|
||||||
|
success:(res)=>resolve(res),
|
||||||
|
fail:(err)=>reject(err),
|
||||||
|
complete:()=>uni.hideLoading()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -149,8 +149,8 @@ export function orderExpress(data) {
|
|||||||
export const wechatPay = (data) => api.post(`/order/pay`, data)
|
export const wechatPay = (data) => api.post(`/order/pay`, data)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查h5支付
|
* 检查支付
|
||||||
* @param data
|
* @param data
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export const checkH5Pay = (data) => api.post(`/order/pay/orderQuery`, data)
|
export const checkPay = (data) => api.post(`/order/pay/orderQuery`, data)
|
||||||
|
@ -41,3 +41,4 @@ export function updateMobile(data) {
|
|||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export const updateUserInfo = (data) => api.put(`/member/user/update-nickname?nickname=${ data.nickname }&birthday=${ data.birthday }&sex=${ data.sex }`)
|
export const updateUserInfo = (data) => api.put(`/member/user/update-nickname?nickname=${ data.nickname }&birthday=${ data.birthday }&sex=${ data.sex }`)
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import { computed, defineProps, ref, toRefs, unref, watch } from "vue";
|
|||||||
import { onLoad } from "@dcloudio/uni-app";
|
import { onLoad } from "@dcloudio/uni-app";
|
||||||
import { useRouter } from "@/hooks/useRouter";
|
import { useRouter } from "@/hooks/useRouter";
|
||||||
import { createAnimation } from "@/utils/utils";
|
import { createAnimation } from "@/utils/utils";
|
||||||
|
import { useScroll } from "@/hooks/useScroll";
|
||||||
|
|
||||||
const HEADER_HEIGHT = 40 // header高度
|
const HEADER_HEIGHT = 40 // header高度
|
||||||
|
|
||||||
@ -66,10 +67,6 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: () => '#fff'
|
default: () => '#fff'
|
||||||
},
|
},
|
||||||
scrollTop: {
|
|
||||||
type: Number,
|
|
||||||
default: () => 0
|
|
||||||
},
|
|
||||||
propUp: {
|
propUp: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => true
|
default: () => true
|
||||||
@ -94,7 +91,6 @@ const {
|
|||||||
textShadow,
|
textShadow,
|
||||||
bgChangeByScroll,
|
bgChangeByScroll,
|
||||||
bgChangeColor,
|
bgChangeColor,
|
||||||
scrollTop,
|
|
||||||
propUp,
|
propUp,
|
||||||
showRight,
|
showRight,
|
||||||
leftWidth
|
leftWidth
|
||||||
@ -146,7 +142,7 @@ function getMenuInfo() {
|
|||||||
// scss全局变量
|
// scss全局变量
|
||||||
const scssVarStyle = computed(() => {
|
const scssVarStyle = computed(() => {
|
||||||
return {
|
return {
|
||||||
'--header-height': `${ HEADER_HEIGHT * 2 }rpx`
|
'--header-height': `${ HEADER_HEIGHT }px`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -154,7 +150,7 @@ const scssVarStyle = computed(() => {
|
|||||||
const systemBarAreaStyle = computed(() => {
|
const systemBarAreaStyle = computed(() => {
|
||||||
return {
|
return {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: `${ unref(heightInfo).safeAreaInsets.top * 2 }rpx`,
|
height: `${ unref(heightInfo).statusBarHeight * 2 }rpx`,
|
||||||
background: unref(systemBarAreaBg)
|
background: unref(systemBarAreaBg)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -163,7 +159,7 @@ const systemBarAreaStyle = computed(() => {
|
|||||||
const headerAreaStyle = computed(() => {
|
const headerAreaStyle = computed(() => {
|
||||||
// 计算margin top
|
// 计算margin top
|
||||||
// margin-top (导航条高度 - 胶囊高度) / 2 永远确保胶囊在header中央
|
// margin-top (导航条高度 - 胶囊高度) / 2 永远确保胶囊在header中央
|
||||||
const marginTop = unref(menuInfo).height > 0 ? `-${ ((HEADER_HEIGHT - (unref(menuInfo).height)) / 2) * 2 }rpx` : 0
|
const marginTop = unref(menuInfo).height > 0 ? `-${((HEADER_HEIGHT - unref(menuInfo).height))/2}px` : 0
|
||||||
return {
|
return {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
background: unref(headerAreaBg),
|
background: unref(headerAreaBg),
|
||||||
@ -202,7 +198,7 @@ const scrollMaskStyle = computed(() => {
|
|||||||
|
|
||||||
// 总高度
|
// 总高度
|
||||||
const containerHeight = computed(() => {
|
const containerHeight = computed(() => {
|
||||||
return (unref(heightInfo).safeAreaInsets.top + HEADER_HEIGHT) * 2
|
return (unref(heightInfo).statusBarHeight + HEADER_HEIGHT)
|
||||||
})
|
})
|
||||||
|
|
||||||
let animation
|
let animation
|
||||||
@ -212,6 +208,7 @@ function doCreateAnimation() {
|
|||||||
animation = createAnimation(0, scrollEnd, 0, 1)
|
animation = createAnimation(0, scrollEnd, 0, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const {scrollTop} = useScroll();
|
||||||
watch(scrollTop, () => {
|
watch(scrollTop, () => {
|
||||||
if (!bgChangeByScroll.value) return
|
if (!bgChangeByScroll.value) return
|
||||||
if (!animation) doCreateAnimation()
|
if (!animation) doCreateAnimation()
|
||||||
@ -289,7 +286,7 @@ onLoad(() => {
|
|||||||
<!-- 撑起 -->
|
<!-- 撑起 -->
|
||||||
<view
|
<view
|
||||||
class="prop-up"
|
class="prop-up"
|
||||||
:style="{height:`${containerHeight}rpx`}"
|
:style="{height:`${containerHeight}px`}"
|
||||||
v-if="propUp"
|
v-if="propUp"
|
||||||
></view>
|
></view>
|
||||||
</view>
|
</view>
|
||||||
|
@ -126,7 +126,7 @@ defineExpose({show, close})
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
height: 80rpx;
|
height: 80rpx;
|
||||||
line-height: 80rpx;
|
line-height: 80rpx;
|
||||||
border: 1rpx solid #ee6d46;
|
border: 1px solid #ee6d46;
|
||||||
background: #ee6d46;
|
background: #ee6d46;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ async function handleSubmit() {
|
|||||||
close()
|
close()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
push({url: '/pages/payStatus/index?type=2'})
|
push({url: '/pages/payStatus/index'},{data:{type:2}})
|
||||||
toast({title: '支付失败了'})
|
toast({title: '支付失败了'})
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import { nextTick, ref, toRefs } from "vue";
|
|||||||
import UniPopup from "@/components/uniComponents/UPopup/uni-popup/uni-popup.vue";
|
import UniPopup from "@/components/uniComponents/UPopup/uni-popup/uni-popup.vue";
|
||||||
|
|
||||||
/** some javascript code in here */
|
/** some javascript code in here */
|
||||||
const emit = defineEmits(['open', 'close'])
|
const emit = defineEmits(['open', 'close', 'maskClick'])
|
||||||
/**
|
/**
|
||||||
* @property {String} title 标题
|
* @property {String} title 标题
|
||||||
* @property {String} mode 模式
|
* @property {String} mode 模式
|
||||||
@ -73,6 +73,10 @@ const handlePopupChange = (e) => {
|
|||||||
if (!e.show) emit('close')
|
if (!e.show) emit('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleMaskClick = (e) => {
|
||||||
|
emit('maskClick')
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
show,
|
show,
|
||||||
close
|
close
|
||||||
@ -86,6 +90,7 @@ defineExpose({
|
|||||||
:is-mask-click="isMaskClick"
|
:is-mask-click="isMaskClick"
|
||||||
background-color="#fff"
|
background-color="#fff"
|
||||||
@change="handlePopupChange"
|
@change="handlePopupChange"
|
||||||
|
@maskClick="handleMaskClick"
|
||||||
class="y-popup"
|
class="y-popup"
|
||||||
>
|
>
|
||||||
<view class="popup_inner">
|
<view class="popup_inner">
|
||||||
|
192
components/Recommend/index.vue
Normal file
192
components/Recommend/index.vue
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
<!--
|
||||||
|
@name: 新品首发
|
||||||
|
@author: kahu4
|
||||||
|
@date: 2023-10-27 14:42
|
||||||
|
@description:index
|
||||||
|
@update: 2023-10-27 14:42
|
||||||
|
-->
|
||||||
|
<script setup>
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { usePage } from "@/hooks";
|
||||||
|
import { getProductList } from "@/api/product";
|
||||||
|
import Empty from "@/components/Empty/index.vue"
|
||||||
|
import ListLoadOver from "@/components/ListLoadOver/index.vue"
|
||||||
|
import ListLoadLoading from "@/components/ListLoadLoading/index.vue"
|
||||||
|
import { useRouter } from "@/hooks/useRouter";
|
||||||
|
import emptyIcon from "@/static/icon/empty/收藏.png";
|
||||||
|
import Goods from "@/components/goodsComponents/Goods.vue";
|
||||||
|
import { computed, toRefs } from "vue";
|
||||||
|
|
||||||
|
const {refresh, dataList, loadend, loading, listEmpty} = usePage(getProductList)
|
||||||
|
const {push} = useRouter()
|
||||||
|
onLoad(() => {
|
||||||
|
refresh()
|
||||||
|
})
|
||||||
|
const props = defineProps({
|
||||||
|
more:{
|
||||||
|
type:Boolean,
|
||||||
|
default:()=>true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const { more } = toRefs(props)
|
||||||
|
|
||||||
|
|
||||||
|
const colList = computed(() => [
|
||||||
|
{
|
||||||
|
name: 'all',
|
||||||
|
data: dataList.value.filter((item,index)=>index%2===0)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name:'right',
|
||||||
|
data: dataList.value.filter((item,index)=>index%2!==0)
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!--push({ url: '/pages/goodsList/goodsList' }-->
|
||||||
|
<view class="recommend-container">
|
||||||
|
<slot name="head">
|
||||||
|
<view class="title-row">
|
||||||
|
商品推荐
|
||||||
|
</view>
|
||||||
|
</slot>
|
||||||
|
<view
|
||||||
|
class="product-box"
|
||||||
|
v-if="!listEmpty"
|
||||||
|
>
|
||||||
|
<!-- 分两列 后期瀑布流 -->
|
||||||
|
<template
|
||||||
|
v-for="col in colList"
|
||||||
|
:key="col.name"
|
||||||
|
>
|
||||||
|
<view class="goods-col">
|
||||||
|
<template
|
||||||
|
v-for="item in col.data"
|
||||||
|
:key="item.id"
|
||||||
|
>
|
||||||
|
<view class="product">
|
||||||
|
<Goods
|
||||||
|
:ratio="true"
|
||||||
|
:goods="item"
|
||||||
|
infoPadding="30rpx 10rpx"
|
||||||
|
>
|
||||||
|
<template #options>
|
||||||
|
<view class="good-bottom">
|
||||||
|
<view class="price">
|
||||||
|
¥{{ item.price }}
|
||||||
|
</view>
|
||||||
|
<view class="sale">
|
||||||
|
仅剩{{ item.stock }}件
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</Goods>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
<Empty
|
||||||
|
v-else
|
||||||
|
:iconSrc="emptyIcon"
|
||||||
|
>
|
||||||
|
暂时没有商品推荐哦~
|
||||||
|
</Empty>
|
||||||
|
<!-- 加载中 -->
|
||||||
|
<ListLoadLoading v-if="loading" />
|
||||||
|
<!-- 加载完毕-->
|
||||||
|
<ListLoadOver v-if="loadend" >
|
||||||
|
<template v-if="more">
|
||||||
|
<span @click="push({ url: '/pages/goodsList/goodsList' })">
|
||||||
|
浏览更多商品
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
到底了~
|
||||||
|
</template>
|
||||||
|
</ListLoadOver>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style
|
||||||
|
scoped
|
||||||
|
lang="scss"
|
||||||
|
>
|
||||||
|
.recommend-container{
|
||||||
|
@include usePadding(30, 20);
|
||||||
|
width: 100%;
|
||||||
|
.title-row{
|
||||||
|
width: 100%;
|
||||||
|
font-size:32rpx;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
&::before,&::after{
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 10%;
|
||||||
|
height: 3rpx;
|
||||||
|
border-radius: 5rpx;
|
||||||
|
background: #333;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(0,50%);
|
||||||
|
}
|
||||||
|
&::before{
|
||||||
|
left: 25%;
|
||||||
|
}
|
||||||
|
&::after{
|
||||||
|
right: 25%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.product-box {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
//display: flex;
|
||||||
|
//gap: 20rpx;
|
||||||
|
|
||||||
|
.goods-col {
|
||||||
|
width: 49%;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-grow: 0;
|
||||||
|
float: left;
|
||||||
|
&:nth-child(2){
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.product {
|
||||||
|
flex-grow: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: $white-color;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
|
||||||
|
.good-bottom {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 20rpx;
|
||||||
|
|
||||||
|
.price {
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sale {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -9,6 +9,7 @@
|
|||||||
import { toRefs } from "vue";
|
import { toRefs } from "vue";
|
||||||
import { GOODS_ITEM_TYPE } from "@/components/goodsComponents/utils/index.type";
|
import { GOODS_ITEM_TYPE } from "@/components/goodsComponents/utils/index.type";
|
||||||
import { useRouter } from "@/hooks/useRouter";
|
import { useRouter } from "@/hooks/useRouter";
|
||||||
|
import { getRandom } from "@/utils/utils";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
goods: {
|
goods: {
|
||||||
@ -21,17 +22,17 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
/** 图片比例 */
|
/** 图片比例 */
|
||||||
ratio: {
|
ratio: {
|
||||||
type: String,
|
type: [String,Boolean],
|
||||||
default: () => "1/1"
|
default: () => '1/1'
|
||||||
},
|
},
|
||||||
infoPadding: {
|
infoPadding: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => "0 0"
|
default: () => "0 0"
|
||||||
},
|
},
|
||||||
/** title是否换行 */
|
/** title是否换行 */
|
||||||
titleNowrap: {
|
titleWrap: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => true
|
default: () => false
|
||||||
},
|
},
|
||||||
/** title 文字大小 rpx */
|
/** title 文字大小 rpx */
|
||||||
titleSize: {
|
titleSize: {
|
||||||
@ -53,7 +54,7 @@ const {
|
|||||||
imgWidth,
|
imgWidth,
|
||||||
ratio,
|
ratio,
|
||||||
infoPadding,
|
infoPadding,
|
||||||
titleNowrap,
|
titleWrap,
|
||||||
titleSize,
|
titleSize,
|
||||||
row,
|
row,
|
||||||
} = toRefs(props)
|
} = toRefs(props)
|
||||||
@ -63,6 +64,7 @@ const {push} = useRouter()
|
|||||||
function toDetail() {
|
function toDetail() {
|
||||||
push({url: '/pages/goodsDetail/goodsDetail'}, {data: {id: goods.value.id}})
|
push({url: '/pages/goodsDetail/goodsDetail'}, {data: {id: goods.value.id}})
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -75,13 +77,13 @@ function toDetail() {
|
|||||||
class="goods-image"
|
class="goods-image"
|
||||||
:style="{
|
:style="{
|
||||||
'width':imgWidth,
|
'width':imgWidth,
|
||||||
'aspect-ratio':ratio
|
'aspect-ratio': ratio===true?`${1/getRandom(1,1.3)}`:ratio
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<image
|
<image
|
||||||
:src="goods.image"
|
:src="goods.image"
|
||||||
class="image"
|
class="image"
|
||||||
mode="aspectFill"
|
:mode="ratio===true?'aspectFit':'aspectFill'"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
<!-- good info -->
|
<!-- good info -->
|
||||||
@ -96,7 +98,7 @@ function toDetail() {
|
|||||||
<view
|
<view
|
||||||
:class="{
|
:class="{
|
||||||
'title-row':true,
|
'title-row':true,
|
||||||
'nowrap': titleNowrap
|
'nowrap': !titleWrap
|
||||||
}"
|
}"
|
||||||
:style="{
|
:style="{
|
||||||
'font-size':`${titleSize}rpx`
|
'font-size':`${titleSize}rpx`
|
||||||
@ -136,7 +138,7 @@ function toDetail() {
|
|||||||
.title-row {
|
.title-row {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
//padding: 14rpx 0;
|
padding-bottom: 15rpx;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<view>
|
|
||||||
<view
|
<view
|
||||||
:class="['order', className]"
|
:class="['order']"
|
||||||
v-if="data"
|
v-if="data"
|
||||||
>
|
>
|
||||||
|
|
||||||
@ -119,7 +118,6 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
@ -39,10 +39,10 @@
|
|||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
class="reply-pic flex flex-ai__center"
|
class="reply-pic flex flex-ai__center"
|
||||||
v-if="data.pics && data.pics.length>0"
|
v-if="data.pics && data.pics.filter(item=>!!item).length>0"
|
||||||
>
|
>
|
||||||
<template
|
<template
|
||||||
v-for="(pic,index) in data.pics"
|
v-for="(pic,index) in data.pics.filter(item=>!!item)"
|
||||||
:key="index"
|
:key="index"
|
||||||
>
|
>
|
||||||
<image
|
<image
|
||||||
@ -154,11 +154,12 @@ function doPreviewImage(current, urls) {
|
|||||||
|
|
||||||
.reply-pic {
|
.reply-pic {
|
||||||
gap: 20rpx;
|
gap: 20rpx;
|
||||||
margin-bottom: 20rpx;
|
margin: 20rpx 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 0;
|
||||||
.image {
|
.image {
|
||||||
width: 180rpx;
|
width: 212rpx;
|
||||||
height: 180rpx;
|
height: 212rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -18,6 +18,9 @@ export const usePage = getPage => {
|
|||||||
// 分类ID
|
// 分类ID
|
||||||
const sid = ref('')
|
const sid = ref('')
|
||||||
|
|
||||||
|
// 优惠券ID
|
||||||
|
const couponId = ref('')
|
||||||
|
|
||||||
// 是否新品,不为空的字符串即可
|
// 是否新品,不为空的字符串即可
|
||||||
const news = ref('')
|
const news = ref('')
|
||||||
|
|
||||||
@ -45,6 +48,7 @@ export const usePage = getPage => {
|
|||||||
keyword: keyword.value,
|
keyword: keyword.value,
|
||||||
type: type.value,
|
type: type.value,
|
||||||
sid: sid.value,
|
sid: sid.value,
|
||||||
|
couponId: couponId.value,
|
||||||
news: news.value,
|
news: news.value,
|
||||||
isIntegral: isIntegral.value,
|
isIntegral: isIntegral.value,
|
||||||
})
|
})
|
||||||
@ -92,6 +96,7 @@ export const usePage = getPage => {
|
|||||||
listEmpty,
|
listEmpty,
|
||||||
news,
|
news,
|
||||||
sid,
|
sid,
|
||||||
|
couponId,
|
||||||
refresh: handleRefresh,
|
refresh: handleRefresh,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,6 +127,9 @@ export const useRouter = () => {
|
|||||||
function getParams(options) {
|
function getParams(options) {
|
||||||
if (typeof options !== 'object') return {}
|
if (typeof options !== 'object') return {}
|
||||||
if (!options[PARAMS_KEY]) return {}
|
if (!options[PARAMS_KEY]) return {}
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
console.log(typeof options[PARAMS_KEY],options[PARAMS_KEY],decodeURIComponent(options[PARAMS_KEY]))
|
||||||
|
// #endif
|
||||||
return JSON.parse(decodeURIComponent(options[PARAMS_KEY]));
|
return JSON.parse(decodeURIComponent(options[PARAMS_KEY]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
hooks/useScroll.js
Normal file
15
hooks/useScroll.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { onPageScroll } from "@dcloudio/uni-app";
|
||||||
|
import { onBeforeUnmount, ref } from "vue";
|
||||||
|
const scrollTop = ref(0)
|
||||||
|
|
||||||
|
export function useScroll(){
|
||||||
|
onPageScroll((e)=>{
|
||||||
|
scrollTop.value = e.scrollTop
|
||||||
|
})
|
||||||
|
onBeforeUnmount(()=>{
|
||||||
|
scrollTop.value = 0
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
scrollTop
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout>
|
<layout>
|
||||||
<uv-navbar
|
|
||||||
:fixed="false"
|
<Header>
|
||||||
:title="title"
|
{{ title }}
|
||||||
left-arrow
|
</Header>
|
||||||
@leftClick="goBack"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<view class="addressList">
|
<view class="addressList">
|
||||||
<template v-if=" main.address.length>0">
|
<template v-if=" main.address.length>0">
|
||||||
@ -65,16 +63,18 @@
|
|||||||
您还没有新增地址~
|
您还没有新增地址~
|
||||||
</Empty>
|
</Empty>
|
||||||
</view>
|
</view>
|
||||||
<div class="form-buttons">
|
<view class="form-buttons">
|
||||||
<uv-button
|
<view class="btn">
|
||||||
round
|
<uv-button
|
||||||
block
|
round
|
||||||
type="primary"
|
block
|
||||||
@tap="goCreateAddress"
|
type="primary"
|
||||||
>
|
@tap="goCreateAddress"
|
||||||
新增地址
|
>
|
||||||
</uv-button>
|
新增地址
|
||||||
</div>
|
</uv-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
</template>
|
</template>
|
||||||
@ -87,6 +87,7 @@ import Empty from '@/components/Empty/index.vue'
|
|||||||
import emptyIcon from '@/static/icon/empty/地址.png'
|
import emptyIcon from '@/static/icon/empty/地址.png'
|
||||||
import { getAddressDel, } from '@/api/address'
|
import { getAddressDel, } from '@/api/address'
|
||||||
import { useRouter } from "@/hooks/useRouter";
|
import { useRouter } from "@/hooks/useRouter";
|
||||||
|
import Header from "@/components/Header/index.vue"
|
||||||
|
|
||||||
const {push, goBack} = useRouter()
|
const {push, goBack} = useRouter()
|
||||||
|
|
||||||
@ -156,6 +157,8 @@ onLoad((option) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleAddressClick = async ({index}, data) => {
|
const handleAddressClick = async ({index}, data) => {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
@ -302,12 +305,13 @@ const handleAddressClick = async ({index}, data) => {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-buttons :deep(.uv-button) {
|
.form-buttons .btn {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.address-default :deep(.uv-tags) {
|
.address-default :deep(.uv-tags) {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -221,6 +221,7 @@ async function handleUnCollectSingle() {
|
|||||||
await unCollectSingle(toDeleteItem)
|
await unCollectSingle(toDeleteItem)
|
||||||
await refresh()
|
await refresh()
|
||||||
await toast({title: '删除成功'})
|
await toast({title: '删除成功'})
|
||||||
|
toDeleteItem = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,14 +13,19 @@
|
|||||||
<view class="list-label w-158">
|
<view class="list-label w-158">
|
||||||
收货地址
|
收货地址
|
||||||
</view>
|
</view>
|
||||||
<view class="list-content">
|
<view
|
||||||
<city-select
|
class="list-content"
|
||||||
ref="cityselect"
|
@click="handleChooseAddress"
|
||||||
:defaultValue="defaultAddress"
|
>
|
||||||
@callback="result"
|
<template v-if="addressData.address.cityId">
|
||||||
:items="main.areaList"
|
{{ addressData.address.province }} {{ addressData.address.city }} {{ addressData.address.district }}
|
||||||
></city-select>
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<span class="chooise">
|
||||||
|
点击选择
|
||||||
|
<uv-icon name="arrow-right"></uv-icon>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -34,7 +39,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入详细地址"
|
placeholder="请输入详细地址"
|
||||||
v-model="addressData.detail"
|
v-model="addressData.detail"
|
||||||
>
|
/>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -49,7 +54,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入姓名"
|
placeholder="请输入姓名"
|
||||||
v-model="addressData.realName"
|
v-model="addressData.realName"
|
||||||
>
|
/>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -64,7 +69,7 @@
|
|||||||
type="number"
|
type="number"
|
||||||
placeholder="请输入电话"
|
placeholder="请输入电话"
|
||||||
v-model="addressData.phone"
|
v-model="addressData.phone"
|
||||||
>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -89,37 +94,45 @@
|
|||||||
@click="onSave"
|
@click="onSave"
|
||||||
></uv-button>
|
></uv-button>
|
||||||
</view>
|
</view>
|
||||||
|
<uv-picker
|
||||||
|
ref="addressPickerRef"
|
||||||
|
:columns="columns"
|
||||||
|
keyName="name"
|
||||||
|
@change="handlePickerChange"
|
||||||
|
@confirm="handlePickerConfirm"
|
||||||
|
></uv-picker>
|
||||||
</layout>
|
</layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from 'vue'
|
import { computed, nextTick, onMounted, ref, unref, watch } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { useMainStore } from '@/store/store'
|
import { useMainStore } from '@/store/store'
|
||||||
import { getAddressAddAndEdit, getAddressDel, } from '@/api/address'
|
import { getAddressAddAndEdit, getAddressDel, } from '@/api/address'
|
||||||
import { useRouter } from "@/hooks/useRouter";
|
import { useRouter } from "@/hooks/useRouter";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
|
import UvPicker from "@/uni_modules/uv-picker/components/uv-picker/uv-picker.vue";
|
||||||
|
|
||||||
const main = useMainStore()
|
const main = useMainStore()
|
||||||
const {getParams, push, goBack} = useRouter()
|
const {getParams, push, goBack} = useRouter()
|
||||||
|
|
||||||
|
const {areaList, address} = storeToRefs(main)
|
||||||
const areaList = ref(main.areaList)
|
// const areaList = ref(main.areaList)
|
||||||
const title = ref('')
|
const title = ref('')
|
||||||
|
|
||||||
const editId = ref('')
|
const editId = ref('')
|
||||||
const defaultAddress = ref('')
|
|
||||||
|
|
||||||
const addressData = ref({
|
const addressData = ref({
|
||||||
"realName": '',
|
realName: undefined,
|
||||||
"postCode": '',
|
phone: undefined,
|
||||||
"isDefault": false,
|
detail: undefined,
|
||||||
"detail": '',
|
isDefault: undefined,
|
||||||
"phone": '',
|
address: {
|
||||||
"cityId": '',
|
cityId: undefined,
|
||||||
"city": '',
|
city: undefined,
|
||||||
"district": '',
|
district: undefined,
|
||||||
"province": '',
|
province: undefined,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const isDefaultList = ref([])
|
const isDefaultList = ref([])
|
||||||
@ -188,9 +201,9 @@ const onSave = async () => {
|
|||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
main.restAddress()
|
main.restAddress()
|
||||||
if (actionType.value == 'select') {
|
if (actionType.value == 'select') {
|
||||||
push({url: '/pages/address/address'}, {data: {type: 'select'}})
|
push({url: '/pages/address/address'}, {data: {type: 'select'},type:'redirectTo'})
|
||||||
} else {
|
} else {
|
||||||
push({url: '/pages/address/address'})
|
goBack()
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error, 'err')
|
console.log(error, 'err')
|
||||||
@ -218,38 +231,72 @@ const result = (values) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => main.areaList, (next) => {
|
const addressPickerRef = ref()
|
||||||
areaList.value = next
|
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
|
||||||
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => main.address, (next) => {
|
function handleSetDefaultColumns() {
|
||||||
let data = next.filter(item => item.id == editId.value)[0]
|
console.log(addressPickerRef.value)
|
||||||
if (!data) return
|
pickerValue.value[0] = provinces.value.findIndex((item, index) => index === defaultValue.value[0])
|
||||||
addressData.value = {
|
citys.value = provinces.value[pickerValue.value[0]].children || []
|
||||||
realName: data.realName,
|
pickerValue.value[1] = citys.value.findIndex((item, index) => index === defaultValue.value[1])
|
||||||
phone: data.phone,
|
areas.value = citys.value[pickerValue.value[1]].children || []
|
||||||
detail: data.detail,
|
pickerValue.value[2] = areas.value.findIndex((item, index) => index === defaultValue.value[2])
|
||||||
isDefault: data.isDefault ? 1 : 0,
|
// 重置下位置
|
||||||
address: {
|
// addressPickerRef.value.setColumnValues(0,provinces.value)
|
||||||
cityId: data.cityId,
|
// addressPickerRef.value.setColumnValues(1,citys.value)
|
||||||
district: data.district,
|
// addressPickerRef.value.setColumnValues(2,areas.value)
|
||||||
province: data.province,
|
nextTick(() => {
|
||||||
city: data.city
|
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)
|
||||||
}
|
}
|
||||||
isDefaultList.value = data.isDefault ? ['isDefault'] : [],
|
}
|
||||||
defaultAddress.value = {
|
|
||||||
province: {
|
function handlePickerConfirm(e) {
|
||||||
name: data.province
|
const {indexs, value} = e
|
||||||
},
|
defaultValue.value = indexs
|
||||||
city: {
|
addressData.value.address = {
|
||||||
name: data.city
|
province: value[0].name || '',
|
||||||
},
|
city: value[1].name || '',
|
||||||
district: {
|
district: value[2].name || '',
|
||||||
name: data.district
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
onLoad(async (options) => {
|
onLoad(async (options) => {
|
||||||
const params = getParams(options)
|
const params = getParams(options)
|
||||||
@ -260,7 +307,7 @@ onLoad(async (options) => {
|
|||||||
if (id) {
|
if (id) {
|
||||||
editId.value = id
|
editId.value = id
|
||||||
title.value = '编辑地址'
|
title.value = '编辑地址'
|
||||||
let data = main.address.filter(item => item.id == id)[0]
|
let data = address.value.filter(item => item.id == id)[0]
|
||||||
if (!data) return
|
if (!data) return
|
||||||
addressData.value = {
|
addressData.value = {
|
||||||
realName: data.realName,
|
realName: data.realName,
|
||||||
@ -274,24 +321,15 @@ onLoad(async (options) => {
|
|||||||
province: data.province,
|
province: data.province,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defaultAddress.value = {
|
// 设置默认选择
|
||||||
province: {
|
handleFindDefault(data)
|
||||||
name: data.province
|
|
||||||
},
|
|
||||||
city: {
|
|
||||||
name: data.city
|
|
||||||
},
|
|
||||||
district: {
|
|
||||||
name: data.district
|
|
||||||
}
|
|
||||||
}
|
|
||||||
isDefaultList.value = data.isDefault ? ['isDefault'] : []
|
isDefaultList.value = data.isDefault ? ['isDefault'] : []
|
||||||
} else {
|
} else {
|
||||||
title.value = '新增地址'
|
title.value = '新增地址'
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
onMounted(() => {
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -306,4 +344,9 @@ onLoad(async (options) => {
|
|||||||
.w-158 {
|
.w-158 {
|
||||||
flex: 0 0 158rpx;
|
flex: 0 0 158rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chooise {
|
||||||
|
@include useFlex(space-between, center);
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -39,10 +39,8 @@ const getCoupon = async () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const goToProduct = () => {
|
const goToProduct = (coupons) => {
|
||||||
push({
|
push({url: '/pages/goodsList/goodsList'},{data: {couponId: coupons.id}})
|
||||||
url: '/pages/goodsList/goodsList'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@ -71,7 +69,7 @@ const goToProduct = () => {
|
|||||||
<!-- button -->
|
<!-- button -->
|
||||||
<view v-if="type === 'select'">
|
<view v-if="type === 'select'">
|
||||||
<view class="button" v-if="tabType === 0">
|
<view class="button" v-if="tabType === 0">
|
||||||
<span @click="goToProduct">去使用</span>
|
<span @click="goToProduct(coupons)">去使用</span>
|
||||||
</view>
|
</view>
|
||||||
<view class="button disable" v-if="tabType === 1">
|
<view class="button disable" v-if="tabType === 1">
|
||||||
<span>已使用</span>
|
<span>已使用</span>
|
||||||
@ -90,8 +88,7 @@ const goToProduct = () => {
|
|||||||
scoped
|
scoped
|
||||||
lang="scss"
|
lang="scss"
|
||||||
>
|
>
|
||||||
.coupon-item{
|
.coupon-item {
|
||||||
margin-bottom: 30rpx;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
aspect-ratio: 682/176;
|
aspect-ratio: 682/176;
|
||||||
background: url("@/static/background/coupon-bg.png") no-repeat ;
|
background: url("@/static/background/coupon-bg.png") no-repeat ;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
<uv-line color="#E6E6E6"></uv-line>
|
<uv-line color="#E6E6E6"></uv-line>
|
||||||
<view class="evaluate-content">
|
<view class="evaluate-content">
|
||||||
<uv-textarea
|
<uv-textarea
|
||||||
|
border="none"
|
||||||
v-model="comment"
|
v-model="comment"
|
||||||
placeholder="请填写您遇到的问题,这将帮助我们为您提供更好的服务"
|
placeholder="请填写您遇到的问题,这将帮助我们为您提供更好的服务"
|
||||||
></uv-textarea>
|
></uv-textarea>
|
||||||
|
@ -223,6 +223,7 @@ async function handleUnCollectSingle() {
|
|||||||
await unFootprintSingle(toDeleteItem)
|
await unFootprintSingle(toDeleteItem)
|
||||||
await refresh()
|
await refresh()
|
||||||
await toast({title: '删除成功'})
|
await toast({title: '删除成功'})
|
||||||
|
toDeleteItem = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
>
|
>
|
||||||
<uv-vtabs
|
<uv-vtabs
|
||||||
:list="categoryData"
|
:list="categoryData"
|
||||||
:hdHeight="`${headerRef&&headerRef.containerHeight || 0}rpx`"
|
:hdHeight="`${headerRef&&headerRef.containerHeight || 0}px`"
|
||||||
>
|
>
|
||||||
<template
|
<template
|
||||||
v-for="(item, index) in categoryData"
|
v-for="(item, index) in categoryData"
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout class="goodsDetail">
|
<layout class="goodsDetail">
|
||||||
<!-- <uv-navbar-->
|
<view :style="computedHeightStyle"></view>
|
||||||
<!-- fixed-->
|
|
||||||
<!-- :safeAreaInsetTop="true"-->
|
|
||||||
<!-- title=""-->
|
|
||||||
<!-- bg-color="transparent"-->
|
|
||||||
<!-- @leftClick="goBack"-->
|
|
||||||
<!-- />-->
|
|
||||||
<Header
|
<Header
|
||||||
|
ref="headerRef"
|
||||||
:propUp="false"
|
:propUp="false"
|
||||||
:scrollTop="scrollTop"
|
|
||||||
>
|
>
|
||||||
|
|
||||||
</Header>
|
</Header>
|
||||||
<view v-if="detailData">
|
<view v-if="detailData">
|
||||||
<swiper
|
<swiper
|
||||||
@ -28,7 +21,7 @@
|
|||||||
<image
|
<image
|
||||||
class="image"
|
class="image"
|
||||||
:src="item"
|
:src="item"
|
||||||
mode="widthFix"
|
mode="aspectFill"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</swiper-item>
|
</swiper-item>
|
||||||
@ -44,9 +37,9 @@
|
|||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
class="goodsDetail-price goodsDetail-price-original"
|
class="goodsDetail-price goodsDetail-price-original"
|
||||||
v-if="(storeAttr&& storeAttr.otPrice) || (storeInfo&&storeInfo.otPrice)"
|
v-if="storeAttr && storeInfo"
|
||||||
>
|
>
|
||||||
¥{{ storeAttr.otPrice || storeInfo.otPrice }}
|
¥{{ storeAttr&&storeAttr.otPrice || storeInfo&&storeInfo.otPrice }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="goodsDetail-storeName">{{ storeInfo.storeName }}</view>
|
<view class="goodsDetail-storeName">{{ storeInfo.storeName }}</view>
|
||||||
@ -115,7 +108,10 @@
|
|||||||
|
|
||||||
|
|
||||||
<view class="card full">
|
<view class="card full">
|
||||||
<view class="card-head" :style="{borderBottom:detailData.replyCount<=0?'none':'1rpx solid #e6e6e6'}">
|
<view
|
||||||
|
class="card-head"
|
||||||
|
:style="{borderBottom:detailData.replyCount<=0?'none':'1rpx solid #e6e6e6'}"
|
||||||
|
>
|
||||||
<view class="card-title">商品评价({{ detailData.replyCount }})</view>
|
<view class="card-title">商品评价({{ detailData.replyCount }})</view>
|
||||||
<view
|
<view
|
||||||
class="card-more"
|
class="card-more"
|
||||||
@ -256,7 +252,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, unref } from 'vue'
|
import { computed, onMounted, ref, unref } from 'vue'
|
||||||
import { collectSingle, getProductDetail, unCollectSingle } from '@/api/product'
|
import { collectSingle, getProductDetail, unCollectSingle } from '@/api/product'
|
||||||
import { getCartAdd, getCartCount } from '@/api/cart'
|
import { getCartAdd, getCartCount } from '@/api/cart'
|
||||||
import { onLoad, onPageScroll } from '@dcloudio/uni-app'
|
import { onLoad, onPageScroll } from '@dcloudio/uni-app'
|
||||||
@ -265,6 +261,7 @@ import { useInterface } from "@/hooks/useInterface";
|
|||||||
import Header from '@/components/Header/index.vue'
|
import Header from '@/components/Header/index.vue'
|
||||||
import GoodCouponSelect from "@/components/good-coupon-select/good-coupon-select.vue";
|
import GoodCouponSelect from "@/components/good-coupon-select/good-coupon-select.vue";
|
||||||
import UvIcon from "@/uni_modules/uv-icon/components/uv-icon/uv-icon.vue";
|
import UvIcon from "@/uni_modules/uv-icon/components/uv-icon/uv-icon.vue";
|
||||||
|
import { useScroll } from "@/hooks/useScroll";
|
||||||
|
|
||||||
const {push, getParams, pushToTab, goBack} = useRouter();
|
const {push, getParams, pushToTab, goBack} = useRouter();
|
||||||
const {toast} = useInterface()
|
const {toast} = useInterface()
|
||||||
@ -279,6 +276,16 @@ const cardCount = ref(null)
|
|||||||
const selectAttrPanel = ref(false)
|
const selectAttrPanel = ref(false)
|
||||||
const selectCouponPanel = ref(false)
|
const selectCouponPanel = ref(false)
|
||||||
const selectCoupon = ref(false)
|
const selectCoupon = ref(false)
|
||||||
|
const headerRef = ref()
|
||||||
|
|
||||||
|
const computedHeightStyle = computed(() => {
|
||||||
|
const style = {width: '100 %', height: 0,background:'#f5f5f5'}
|
||||||
|
if (!headerRef.value || !headerRef.value.heightInfo) return style
|
||||||
|
return {...style, height: `${ headerRef.value.heightInfo.statusBarHeight }px`}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
})
|
||||||
|
|
||||||
const handleGetDetail = async (id) => {
|
const handleGetDetail = async (id) => {
|
||||||
try {
|
try {
|
||||||
@ -312,7 +319,7 @@ onLoad((options) => {
|
|||||||
handleGetDetail(params.id)
|
handleGetDetail(params.id)
|
||||||
handleGetCartCount(params.id)
|
handleGetCartCount(params.id)
|
||||||
})
|
})
|
||||||
|
useScroll()
|
||||||
const goToService = () => {
|
const goToService = () => {
|
||||||
toast({title: '😒敬请期待😒'})
|
toast({title: '😒敬请期待😒'})
|
||||||
}
|
}
|
||||||
@ -407,10 +414,7 @@ const handleGetCartCount = async () => {
|
|||||||
cardCount.value = count.count
|
cardCount.value = count.count
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollTop = ref(0)
|
|
||||||
onPageScroll((e) => {
|
|
||||||
scrollTop.value = e.scrollTop
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -743,7 +747,9 @@ onPageScroll((e) => {
|
|||||||
|
|
||||||
// ======================= 👇 kahu ===
|
// ======================= 👇 kahu ===
|
||||||
.row-context {
|
.row-context {
|
||||||
margin: 30rpx 0 ;
|
margin: 30rpx 0;
|
||||||
|
|
||||||
|
|
||||||
.label-row {
|
.label-row {
|
||||||
@include useFlex(space-between, center);
|
@include useFlex(space-between, center);
|
||||||
@include usePadding(30, 20);
|
@include usePadding(30, 20);
|
||||||
@ -775,6 +781,20 @@ onPageScroll((e) => {
|
|||||||
.value {
|
.value {
|
||||||
@include useFlex(flex-end, center);
|
@include useFlex(flex-end, center);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.swiper {
|
||||||
|
.swiper-item {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.image {
|
||||||
|
width: inherit;
|
||||||
|
height: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,13 +76,14 @@ import ListLoadLoading from "@/components/ListLoadLoading/index.vue"
|
|||||||
import emptyIcon from "@/static/icon/empty/收藏.png"
|
import emptyIcon from "@/static/icon/empty/收藏.png"
|
||||||
|
|
||||||
const {getParams, goBack} = useRouter()
|
const {getParams, goBack} = useRouter()
|
||||||
const {keyword, refresh, sid, dataList, loadend, loading, listEmpty} = usePage(getProductList)
|
const {keyword, refresh, sid, couponId, dataList, loadend, loading, listEmpty} = usePage(getProductList)
|
||||||
|
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
const params = getParams(options)
|
const params = getParams(options)
|
||||||
keyword.value = params.keyword || ''
|
keyword.value = params.keyword || ''
|
||||||
sid.value = params.sid || ''
|
sid.value = params.sid || ''
|
||||||
|
couponId.value = params.couponId || ''
|
||||||
refresh()
|
refresh()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -6,83 +6,39 @@
|
|||||||
@update: 2023-10-27 14:42
|
@update: 2023-10-27 14:42
|
||||||
-->
|
-->
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import Recommend from "@/components/Recommend/index.vue";
|
||||||
import { usePage } from "@/hooks";
|
import UvIcon from "@/uni_modules/uv-icon/components/uv-icon/uv-icon.vue";
|
||||||
import { getProductList } from "@/api/product";
|
|
||||||
import Empty from "@/components/Empty/index.vue"
|
|
||||||
import ListLoadOver from "@/components/ListLoadOver/index.vue"
|
|
||||||
import ListLoadLoading from "@/components/ListLoadLoading/index.vue"
|
|
||||||
import { useRouter } from "@/hooks/useRouter";
|
|
||||||
|
|
||||||
const {refresh, dataList, loadend, loading, listEmpty} = usePage(getProductList)
|
|
||||||
const {push} = useRouter()
|
|
||||||
onLoad(() => {
|
|
||||||
refresh()
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<blank size="15"></blank>
|
<Recommend ref="recommendRef" :more="false">
|
||||||
|
<template #head>
|
||||||
<activity
|
<view class="head flex flex-ai__center flex-jc__sb">
|
||||||
title="商品推荐"
|
<view class="left">
|
||||||
more="查看更多"
|
商品推荐
|
||||||
@moreClick="push({ url: '/pages/goodsList/goodsList' })"
|
</view>
|
||||||
>
|
<view class="right flex flex-ai__center flex-jc__end">
|
||||||
<view class="card goods-row">
|
查看更多
|
||||||
<template v-if="!listEmpty">
|
<uv-icon name="arrow-right" color="#999" size="14" />
|
||||||
<uv-grid
|
</view>
|
||||||
:border="false"
|
</view>
|
||||||
:col="2"
|
</template>
|
||||||
:gutter="10"
|
</Recommend>
|
||||||
>
|
|
||||||
<uv-grid-item
|
|
||||||
v-for="(item, index) in dataList"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<goods
|
|
||||||
class="item"
|
|
||||||
link
|
|
||||||
card
|
|
||||||
:data="item"
|
|
||||||
:storeName="item.storeName"
|
|
||||||
:price="item.price"
|
|
||||||
:stock="true"
|
|
||||||
>
|
|
||||||
</goods>
|
|
||||||
</uv-grid-item>
|
|
||||||
</uv-grid>
|
|
||||||
</template>
|
|
||||||
<Empty
|
|
||||||
v-else
|
|
||||||
:iconSrc="emptyIcon"
|
|
||||||
>
|
|
||||||
这里空空如也~
|
|
||||||
</Empty>
|
|
||||||
<!-- 加载中 -->
|
|
||||||
<ListLoadLoading v-if="loading" />
|
|
||||||
<!-- 加载完毕-->
|
|
||||||
<ListLoadOver v-if="loadend" />
|
|
||||||
</view>
|
|
||||||
|
|
||||||
</activity>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style
|
<style
|
||||||
scoped
|
scoped
|
||||||
lang="scss"
|
lang="scss"
|
||||||
>
|
>
|
||||||
@import "@/style/main.scss";
|
.head{
|
||||||
|
margin-top: 20rpx;
|
||||||
.goods-row {
|
.left{
|
||||||
@include usePadding(20, 20);
|
font-size: 32rpx;
|
||||||
border-radius: 15rpx;
|
color: #333333;
|
||||||
|
}
|
||||||
.item {
|
.right{
|
||||||
width: 100%;
|
font-size: 24rpx;
|
||||||
margin: 0 10rpx;
|
color: #999999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
<view class="home-container">
|
<view class="home-container">
|
||||||
<view class="header-row">
|
<view class="header-row">
|
||||||
<Header
|
<Header
|
||||||
:scroll-top="scrollTop"
|
|
||||||
:left-width="140"
|
:left-width="140"
|
||||||
@animation="handleHeaderAnimation"
|
@animation="handleHeaderAnimation"
|
||||||
>
|
>
|
||||||
@ -19,19 +18,14 @@
|
|||||||
<view
|
<view
|
||||||
class="search-col"
|
class="search-col"
|
||||||
:style="searchShadow"
|
:style="searchShadow"
|
||||||
@click="toSearch"
|
@tap="toSearch"
|
||||||
>
|
>
|
||||||
<uv-icon
|
<uv-icon
|
||||||
name="search"
|
name="search"
|
||||||
size="26"
|
size="40rpx"
|
||||||
/>
|
/>
|
||||||
<view class="search-input">
|
<view class="search-input">
|
||||||
<input
|
搜索商品
|
||||||
type="text"
|
|
||||||
disabled
|
|
||||||
placeholder="搜索商品"
|
|
||||||
@click="toSearch"
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@ -68,7 +62,7 @@
|
|||||||
|
|
||||||
<!-- 热门直播 -->
|
<!-- 热门直播 -->
|
||||||
<Live v-if="false" />
|
<Live v-if="false" />
|
||||||
<Recommend ref="recommendRef" />
|
<Recommend />
|
||||||
</template>
|
</template>
|
||||||
<!-- h5 tabbar 底部 -->
|
<!-- h5 tabbar 底部 -->
|
||||||
<view class="h5-tabbar-height"></view>
|
<view class="h5-tabbar-height"></view>
|
||||||
@ -89,8 +83,9 @@ import Group from './components/Group/index.vue'
|
|||||||
import Live from './components/Live/index.vue'
|
import Live from './components/Live/index.vue'
|
||||||
import NewProduct from './components/NewProduct/index.vue'
|
import NewProduct from './components/NewProduct/index.vue'
|
||||||
import Seckill from './components/Seckill/index.vue'
|
import Seckill from './components/Seckill/index.vue'
|
||||||
import Recommend from './components/Recommend/index.vue'
|
import Recommend from "./components/Recommend/index.vue";
|
||||||
import UvIcon from "@/uni_modules/uv-icon/components/uv-icon/uv-icon.vue";
|
import UvIcon from "@/uni_modules/uv-icon/components/uv-icon/uv-icon.vue";
|
||||||
|
import { useScroll } from "@/hooks/useScroll";
|
||||||
|
|
||||||
const main = useMainStore()
|
const main = useMainStore()
|
||||||
const {push} = useRouter()
|
const {push} = useRouter()
|
||||||
@ -118,19 +113,18 @@ function handleHeaderAnimation(numericalValue) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollTop = ref(0)
|
/*const scrollTop = ref(0)
|
||||||
onPageScroll((e) => {
|
onPageScroll((e) => {
|
||||||
scrollTop.value = e.scrollTop
|
scrollTop.value = e.scrollTop
|
||||||
})
|
})*/
|
||||||
|
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
main.init()
|
main.init()
|
||||||
doGetHomeData()
|
doGetHomeData()
|
||||||
})
|
})
|
||||||
|
|
||||||
onReachBottom(() => {
|
useScroll()
|
||||||
unref(recommendRef).onReachBottom && unref(recommendRef).onReachBottom();
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -153,13 +147,16 @@ onReachBottom(() => {
|
|||||||
.search-col {
|
.search-col {
|
||||||
@include useFlex(flex-start, center);
|
@include useFlex(flex-start, center);
|
||||||
@include usePadding(30, 15);
|
@include usePadding(30, 15);
|
||||||
width: 100%;
|
width: 320rpx;
|
||||||
height: 60rpx;
|
height: 60rpx;
|
||||||
border-radius: 50rpx;
|
border-radius: 50rpx;
|
||||||
background: $white-color;
|
background: $white-color;
|
||||||
|
margin-left: 50rpx;
|
||||||
|
|
||||||
.search-input {
|
.search-input {
|
||||||
margin-left: 30rpx;
|
margin-left: 30rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999999;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,4 +166,6 @@ onReachBottom(() => {
|
|||||||
.goods-row {
|
.goods-row {
|
||||||
padding: 0 8rpx;
|
padding: 0 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -6,19 +6,96 @@
|
|||||||
@update: 2023-11-08 16:20
|
@update: 2023-11-08 16:20
|
||||||
-->
|
-->
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import wechat from '@/static/icon/login/wechat.png'
|
||||||
import { useRouter } from "@/hooks/useRouter";
|
import { useRouter } from "@/hooks/useRouter";
|
||||||
import { loginMethods } from "@/pages/login/index.data";
|
import { loginMethods } from "@/pages/login/index.data";
|
||||||
|
import { wxLogin } from "@/utils/wechatUtils";
|
||||||
|
import { error } from "@/uni_modules/uv-ui-tools/libs/function";
|
||||||
|
import { nextTick, ref } from "vue";
|
||||||
|
import { useInterface } from "@/hooks/useInterface";
|
||||||
|
import { privacyAgreementUrl, userAgreementUrl, weixinLogin } from "@/api/auth";
|
||||||
|
import { useMainStore } from "@/store/store";
|
||||||
|
import { afterLogin } from "@/utils";
|
||||||
|
|
||||||
|
const {toast, loading, hideLoading} = useInterface()
|
||||||
const {goBack, push} = useRouter()
|
const {goBack, push} = useRouter()
|
||||||
|
const mainStore = useMainStore()
|
||||||
|
|
||||||
function toLogin(loginMethod) {
|
async function toLogin(loginMethod) {
|
||||||
if (loginMethod.type === 0) {
|
|
||||||
// 微信登录
|
|
||||||
console.log('微信登录')
|
|
||||||
} else {
|
|
||||||
push({url: '/pages/login/index', animationType: 'slide-in-right'}, {data: {...loginMethod}})
|
push({url: '/pages/login/index', animationType: 'slide-in-right'}, {data: {...loginMethod}})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================= 微信登录相关
|
||||||
|
const code = ref('') // logingCode必须比getPhoneNumber的code先获取
|
||||||
|
|
||||||
|
async function getCode() {
|
||||||
|
loading({
|
||||||
|
title: '登陆中...'
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
code.value = await wxLogin();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
toast('获取code失败')
|
||||||
|
hideLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getPhoneNumber(e) {
|
||||||
|
if (e.detail.errMsg !== 'getPhoneNumber:ok') {
|
||||||
|
console.error(e)
|
||||||
|
hideLoading()
|
||||||
|
toast({title: '登录失败'})
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const phoneCode = e.detail.code
|
||||||
|
const res = await weixinLogin({
|
||||||
|
phoneCode,
|
||||||
|
loginCode: code.value
|
||||||
|
});
|
||||||
|
if (res) {
|
||||||
|
await mainStore.setAccessToken(res)
|
||||||
|
afterLogin()
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
toast({title: '登录失败'})
|
||||||
|
} finally {
|
||||||
|
hideLoading()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const privacyPolicy = ref([]) // 协议双向绑定
|
||||||
|
|
||||||
|
const isPrivacyError = ref(false) // 未勾选协议
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否勾选协议
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function checkPrivacy() {
|
||||||
|
const flag = privacyPolicy.value.length > 0
|
||||||
|
if (!flag) {
|
||||||
|
toast({title: '请先阅读并同意用户协议和隐私政策'})
|
||||||
|
isPrivacyError.value = true
|
||||||
|
setTimeout(() => {
|
||||||
|
isPrivacyError.value = false
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
return flag
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转协议
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
function toAgreement(type) {
|
||||||
|
const urls = [userAgreementUrl, privacyAgreementUrl]
|
||||||
|
push({url: '/pages/webview/index'}, {data: {src: urls[type]}})
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -37,6 +114,32 @@ function toLogin(loginMethod) {
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="button-group">
|
<view class="button-group">
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<view
|
||||||
|
v-if="privacyPolicy.length<=0"
|
||||||
|
class="button animation-button disabled"
|
||||||
|
@click="checkPrivacy"
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
class="icon"
|
||||||
|
:src="wechat"
|
||||||
|
/>
|
||||||
|
微信快捷登录
|
||||||
|
</view>
|
||||||
|
<button
|
||||||
|
v-else
|
||||||
|
class="button animation-button"
|
||||||
|
open-type="getPhoneNumber"
|
||||||
|
@getphonenumber="getPhoneNumber"
|
||||||
|
@click="getCode"
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
class="icon"
|
||||||
|
:src="wechat"
|
||||||
|
/>
|
||||||
|
微信快捷登录
|
||||||
|
</button>
|
||||||
|
<!-- #endif -->
|
||||||
<template
|
<template
|
||||||
v-for="(loginMethod) in loginMethods"
|
v-for="(loginMethod) in loginMethods"
|
||||||
:key="loginMethod.type"
|
:key="loginMethod.type"
|
||||||
@ -55,8 +158,34 @@ function toLogin(loginMethod) {
|
|||||||
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="tips-row">
|
<view
|
||||||
为了给您提供更好的服务 我们需要您的授权哦~
|
class="agreement-box"
|
||||||
|
:class="{'error-animation':isPrivacyError}"
|
||||||
|
>
|
||||||
|
<uv-checkbox-group
|
||||||
|
v-model="privacyPolicy"
|
||||||
|
shape="circle"
|
||||||
|
activeColor="#ec6e47"
|
||||||
|
>
|
||||||
|
<uv-checkbox :name="1">
|
||||||
|
<view class="agreement-text">
|
||||||
|
阅读并同意
|
||||||
|
<span
|
||||||
|
class="color"
|
||||||
|
@click="toAgreement(0)"
|
||||||
|
>
|
||||||
|
《YSHOP商城用户协议》
|
||||||
|
</span>
|
||||||
|
和
|
||||||
|
<span
|
||||||
|
class="color"
|
||||||
|
@click="toAgreement(1)"
|
||||||
|
>
|
||||||
|
《YSHOP商城隐私协议》
|
||||||
|
</span>
|
||||||
|
</view>
|
||||||
|
</uv-checkbox>
|
||||||
|
</uv-checkbox-group>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@ -112,14 +241,54 @@ function toLogin(loginMethod) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tips-row {
|
}
|
||||||
position: absolute;
|
|
||||||
bottom: 5%;
|
.agreement-box {
|
||||||
left: 0;
|
@include usePadding(30, 0);
|
||||||
width: 100%;
|
position: fixed;
|
||||||
color: $tips-color;
|
bottom: 5%;
|
||||||
font-size: 24rpx;
|
width: 100%;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: $tips-color;
|
||||||
|
transition: all .3s;
|
||||||
|
|
||||||
|
|
||||||
|
.agreement-text {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
.color {
|
||||||
|
color: $primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.uv-checkbox ) {
|
||||||
|
width: 100%;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
.uv-checkbox__icon-wrap {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-animation {
|
||||||
|
animation: error-text 0.8s 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes error-text {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
5%, 25%, 45%, 65%, 85% {
|
||||||
|
transform: translateX(-10rpx);
|
||||||
|
}
|
||||||
|
10%, 30%, 50%, 70%, 90% {
|
||||||
|
transform: translateX(10rpx);
|
||||||
|
}
|
||||||
|
15%, 35%, 55%, 75%, 95% {
|
||||||
|
transform: translateX(20rpx);
|
||||||
|
}
|
||||||
|
20%, 40%, 60%, 80%, 100% {
|
||||||
|
transform: translateX(-20rpx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -13,12 +13,7 @@ import phone from '@/static/icon/login/phone.png'
|
|||||||
* @type {[{icon: *, label: string},{icon: *, label: string}]}
|
* @type {[{icon: *, label: string},{icon: *, label: string}]}
|
||||||
*/
|
*/
|
||||||
export const loginMethods = [
|
export const loginMethods = [
|
||||||
{
|
|
||||||
type: 0,
|
|
||||||
label: '微信快捷登录',
|
|
||||||
icon: wechat,
|
|
||||||
classNames: []
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
type: 1,
|
type: 1,
|
||||||
label: '手机号快捷登录',
|
label: '手机号快捷登录',
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
:fixed="false"
|
:fixed="false"
|
||||||
title="订单详情"
|
title="订单详情"
|
||||||
left-arrow
|
left-arrow
|
||||||
@leftClick="goList"
|
@leftClick="goBack"
|
||||||
/>
|
/>
|
||||||
<view v-if="orderInfoData">
|
<view v-if="orderInfoData">
|
||||||
<view class="orderInfo-header background-warp">
|
<view class="orderInfo-header background-warp">
|
||||||
@ -70,6 +70,7 @@
|
|||||||
>
|
>
|
||||||
<goods
|
<goods
|
||||||
list
|
list
|
||||||
|
link
|
||||||
interval
|
interval
|
||||||
desc="3"
|
desc="3"
|
||||||
showAction
|
showAction
|
||||||
@ -407,14 +408,16 @@ const handleOrderTake = async () => {
|
|||||||
uni: orderInfoData.value.orderId,
|
uni: orderInfoData.value.orderId,
|
||||||
}
|
}
|
||||||
const res = await orderTake(option)
|
const res = await orderTake(option)
|
||||||
toast({
|
uni.showToast({
|
||||||
title: '收货成功'
|
title: '收货成功',
|
||||||
})
|
duration: 2000
|
||||||
|
});
|
||||||
handleOrderInfo({
|
handleOrderInfo({
|
||||||
key: option.uni
|
key: option.uni
|
||||||
})
|
})
|
||||||
|
|
||||||
} else if (res.cancel) {
|
} else if (res.cancel) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -434,9 +437,23 @@ const handlePay = () => {
|
|||||||
|
|
||||||
// 返回列表
|
// 返回列表
|
||||||
const goList = ()=>{
|
const goList = ()=>{
|
||||||
|
let status = 0
|
||||||
|
switch (orderInfoData.value.status){
|
||||||
|
case -1:
|
||||||
|
status = -1
|
||||||
|
break
|
||||||
|
case 0:
|
||||||
|
status = 0
|
||||||
|
break
|
||||||
|
case 99:
|
||||||
|
status = 1
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
status = orderInfoData.value.status +1
|
||||||
|
}
|
||||||
push({url: '/pages/orderList/orderList'}, {
|
push({url: '/pages/orderList/orderList'}, {
|
||||||
data: {
|
data: {
|
||||||
type: orderInfoData.value.status === 99?1:orderInfoData.value.status+1,
|
type: status
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -494,13 +511,15 @@ const handleCancel = async () => {
|
|||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
await orderCancel({
|
await orderCancel({
|
||||||
id: data.value.orderId
|
id: orderInfoData.value.orderId
|
||||||
})
|
})
|
||||||
data.value = null
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '已取消',
|
title: '已取消',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
});
|
});
|
||||||
|
setTimeout(()=>{
|
||||||
|
goList()
|
||||||
|
},2000)
|
||||||
} else if (res.cancel) {
|
} else if (res.cancel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
>
|
>
|
||||||
<uv-navbar
|
<uv-navbar
|
||||||
:fixed="false"
|
:fixed="false"
|
||||||
title="全部订单"
|
:title="title"
|
||||||
@leftClick="goBack"
|
@leftClick="goBack"
|
||||||
/>
|
/>
|
||||||
<uv-tabs
|
<uv-tabs
|
||||||
@ -18,6 +18,7 @@
|
|||||||
>
|
>
|
||||||
</uv-tabs>
|
</uv-tabs>
|
||||||
</uv-sticky>
|
</uv-sticky>
|
||||||
|
|
||||||
<view class="orderList">
|
<view class="orderList">
|
||||||
<template v-if="!listEmpty">
|
<template v-if="!listEmpty">
|
||||||
<order
|
<order
|
||||||
@ -40,23 +41,26 @@
|
|||||||
<ListLoadOver v-if="loadend" />
|
<ListLoadOver v-if="loadend" />
|
||||||
</view>
|
</view>
|
||||||
</layout>
|
</layout>
|
||||||
|
<!-- 支付弹窗 -->
|
||||||
|
<PayPopup
|
||||||
|
ref="payPopupRef"
|
||||||
|
@confirm="paySuccess"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
<!-- 支付弹窗 -->
|
|
||||||
<PayPopup
|
|
||||||
ref="payPopupRef"
|
|
||||||
@confirm="paySuccess"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, unref } from 'vue'
|
import { computed, ref, unref } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { orderList } from '@/api/order'
|
import { orderList } from '@/api/order'
|
||||||
import { useRouter } from "@/hooks/useRouter";
|
import { useRouter } from "@/hooks/useRouter";
|
||||||
|
import ListLoadOver from "@/components/ListLoadOver/index.vue"
|
||||||
|
import ListLoadLoading from "@/components/ListLoadLoading/index.vue"
|
||||||
import Empty from '@/components/Empty/index.vue'
|
import Empty from '@/components/Empty/index.vue'
|
||||||
import emptyIcon from '@/static/icon/empty/订单.png'
|
import emptyIcon from '@/static/icon/empty/订单.png'
|
||||||
import PayPopup from '@/components/PayPopup/index.vue'
|
import PayPopup from '@/components/PayPopup/index.vue'
|
||||||
import { usePage } from "@/hooks";
|
import { usePage } from "@/hooks";
|
||||||
|
import Header from "@/components/Header/index.vue"
|
||||||
import { getProductList } from "@/api/product";
|
import { getProductList } from "@/api/product";
|
||||||
|
|
||||||
const {type, refresh, dataList, loadend, loading, listEmpty} = usePage(orderList)
|
const {type, refresh, dataList, loadend, loading, listEmpty} = usePage(orderList)
|
||||||
@ -78,6 +82,11 @@ const navList = ref([
|
|||||||
// { name: "退款", value: 7, },
|
// { name: "退款", value: 7, },
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const title = computed(()=>{
|
||||||
|
const find = navList.value.find(item=>item.value === type.value);
|
||||||
|
return find?`${find.name}订单`:'订单'
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
// const handleOrderList = async (option) => {
|
// const handleOrderList = async (option) => {
|
||||||
// orderListData.value = []
|
// orderListData.value = []
|
||||||
@ -110,7 +119,7 @@ function openPay(orderId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function paySuccess() {
|
function paySuccess() {
|
||||||
// push({url: '/pages/payStatus/index?type=1'})
|
push({url: '/pages/payStatus/index'},{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,14 +8,18 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useRouter } from "@/hooks/useRouter";
|
import { useRouter } from "@/hooks/useRouter";
|
||||||
import { computed, ref, unref } from "vue";
|
import { computed, ref, unref } from "vue";
|
||||||
import { onLoad } from "@dcloudio/uni-app";
|
import { onLoad, onPageScroll, onReachBottom } from "@dcloudio/uni-app";
|
||||||
import { checkH5Pay } from "@/api/order";
|
import { checkPay } from "@/api/order";
|
||||||
import { CacheKey } from "@/utils/config";
|
import { CacheKey } from "@/utils/config";
|
||||||
|
import Header from '@/components/Header/index.vue'
|
||||||
|
import Recommend from '@/components/Recommend/index.vue'
|
||||||
|
import { useInterface } from "@/hooks/useInterface";
|
||||||
|
import { useScroll } from "@/hooks/useScroll";
|
||||||
|
|
||||||
const {getParams, goBack, push, pushToTab} = useRouter()
|
const {getParams, goBack, push, pushToTab} = useRouter()
|
||||||
|
const {loading,hideLoading} = useInterface()
|
||||||
const type = ref(0) // 支付状态 : 0支付中 1支付成功 2支付失败
|
const type = ref(0) // 支付状态 : 0支付中 1支付成功 2支付失败
|
||||||
|
useScroll()
|
||||||
const title = computed(() => {
|
const title = computed(() => {
|
||||||
if (type.value === 0) return '支付中...'
|
if (type.value === 0) return '支付中...'
|
||||||
if (type.value === 1) return '支付成功'
|
if (type.value === 1) return '支付成功'
|
||||||
@ -36,23 +40,48 @@ function toBackHome() {
|
|||||||
pushToTab({url: '/pages/index/index'})
|
pushToTab({url: '/pages/index/index'})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const retryTime = ref(3)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询服务端支付状态
|
* 查询服务端支付状态
|
||||||
*/
|
*/
|
||||||
async function queryOrderStatus() {
|
async function queryOrderStatus() {
|
||||||
const payInfoStr = uni.getStorageSync(CacheKey.PAY_INFO);
|
loading({title: '查询中...'})
|
||||||
if (payInfoStr) {
|
// 异步去查,有可能接口比微信快
|
||||||
const parse = JSON.parse(payInfoStr);
|
setTimeout(async () => {
|
||||||
const res = await checkH5Pay(parse);
|
try {
|
||||||
type.value = res ? 1 : 2
|
const payInfoStr = uni.getStorageSync(CacheKey.PAY_INFO);
|
||||||
uni.removeStorageSync(CacheKey.PAY_INFO)
|
// 没有订单缓存直接跳到订单页面
|
||||||
} else {
|
if (!payInfoStr) return toOrderList(0)
|
||||||
// 没有订单缓存直接跳到订单页面
|
|
||||||
toOrderList(0)
|
const parse = JSON.parse(payInfoStr);
|
||||||
}
|
const res = await checkPay(parse);
|
||||||
|
if (!res) {
|
||||||
|
// 支付失败重新查询
|
||||||
|
if (retryTime.value > 0) {
|
||||||
|
retryTime.value--
|
||||||
|
await queryOrderStatus()
|
||||||
|
} else {
|
||||||
|
type.value = 2
|
||||||
|
uni.removeStorageSync(CacheKey.PAY_INFO)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
type.value = 1
|
||||||
|
uni.removeStorageSync(CacheKey.PAY_INFO)
|
||||||
|
} finally {
|
||||||
|
hideLoading()
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const recommendRef = ref(null)
|
||||||
|
onReachBottom(() => {
|
||||||
|
unref(recommendRef).onReachBottom && unref(recommendRef).onReachBottom();
|
||||||
|
})
|
||||||
|
|
||||||
onLoad(async (options) => {
|
onLoad(async (options) => {
|
||||||
|
// H5 和 APP 需要弹窗去确认
|
||||||
// #ifdef H5
|
// #ifdef H5
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
content: '请确认支付是否完成',
|
content: '请确认支付是否完成',
|
||||||
@ -61,23 +90,15 @@ onLoad(async (options) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
// #endif
|
// #endif
|
||||||
const params = getParams(options);
|
await queryOrderStatus()
|
||||||
if (params && params.type === 1) {
|
|
||||||
type.value = 1
|
|
||||||
} else {
|
|
||||||
type.value = 2
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="pay-status">
|
<view class="pay-status">
|
||||||
<uv-navbar
|
<Header>
|
||||||
:fixed="false"
|
{{ title }}
|
||||||
:title="title"
|
</Header>
|
||||||
left-arrow
|
|
||||||
@leftClick="goBack"
|
|
||||||
/>
|
|
||||||
<view class="status-main flex flex-column flex-ai__center">
|
<view class="status-main flex flex-column flex-ai__center">
|
||||||
<image
|
<image
|
||||||
class="icon"
|
class="icon"
|
||||||
@ -123,6 +144,8 @@ onLoad(async (options) => {
|
|||||||
重新支付
|
重新支付
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- 商品推荐 -->
|
||||||
|
<Recommend ref="recommendRef" />
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -230,15 +230,17 @@ const handleOrderInfo = async (option) => {
|
|||||||
|
|
||||||
let price = 0
|
let price = 0
|
||||||
let productParamList = []
|
let productParamList = []
|
||||||
|
let productAttrUnique = []
|
||||||
goodsList.value.forEach(item => {
|
goodsList.value.forEach(item => {
|
||||||
price += item.cartInfo.truePrice * item.cartInfo.cartNum
|
price += item.cartInfo.truePrice * item.cartInfo.cartNum
|
||||||
productParamList.push({
|
productParamList.push({
|
||||||
productId: item.productId
|
productId: item.productId,
|
||||||
|
productAttrUnique: item.cartInfo.productAttrUnique
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
totalPrice.value = price
|
|
||||||
|
totalPrice.value = price.toFixed(2)
|
||||||
data.value.orderId = res[0].orderId
|
data.value.orderId = res[0].orderId
|
||||||
data.value.serviceType = refundType.value
|
data.value.serviceType = refundType.value
|
||||||
data.value.productParamList = productParamList
|
data.value.productParamList = productParamList
|
||||||
@ -281,9 +283,10 @@ const handleApplyForAfterSales = async () => {
|
|||||||
title: '申请成功,请等待审核'
|
title: '申请成功,请等待审核'
|
||||||
})
|
})
|
||||||
push({url: '/pages/refundInfo/refundInfo'}, {
|
push({url: '/pages/refundInfo/refundInfo'}, {
|
||||||
|
type:'redirectTo',
|
||||||
data: {
|
data: {
|
||||||
id: res,
|
id: res,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +115,7 @@
|
|||||||
model
|
model
|
||||||
:purchase="item.cartNum"
|
:purchase="item.cartNum"
|
||||||
:data="item.productInfo"
|
:data="item.productInfo"
|
||||||
|
:price="item.truePrice"
|
||||||
v-for="(item, index) in orderInfoData.cartInfo"
|
v-for="(item, index) in orderInfoData.cartInfo"
|
||||||
>
|
>
|
||||||
</goods>
|
</goods>
|
||||||
@ -133,7 +134,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="info-cell ">
|
<view class="info-cell ">
|
||||||
<view class="info-cell-label">总计:</view>
|
<view class="info-cell-label">总计:</view>
|
||||||
<view class="info-cell-value">¥{{ orderInfoData.refundAmount }}</view>
|
<view class="info-cell-value">¥{{ orderInfoData.payPrice.toFixed(2) }}</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -160,7 +161,7 @@
|
|||||||
服务类型
|
服务类型
|
||||||
</view>
|
</view>
|
||||||
<view class="info-cell-value">
|
<view class="info-cell-value">
|
||||||
{{ orderInfoData.serviceType }}
|
{{ orderInfoData.serviceType===0?'仅退款':'退货退款' }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
@ -321,8 +322,8 @@ const handleDelete = async () => {
|
|||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
await afterSalesOrderDelete({
|
await afterSalesOrderDelete({
|
||||||
id: orderInfoData.value.id,
|
id: orderId.value,
|
||||||
orderCode: orderInfoData.value.orderCode
|
orderCode: orderInfoData.value.orderId
|
||||||
})
|
})
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '已删除',
|
title: '已删除',
|
||||||
|
@ -20,21 +20,43 @@
|
|||||||
<card class="shopping-checkbox">
|
<card class="shopping-checkbox">
|
||||||
<view
|
<view
|
||||||
v-for="(item, index) in goodsList"
|
v-for="(item, index) in goodsList"
|
||||||
class="shopping-checkbox-cell"
|
:key="item.id"
|
||||||
|
class="goods-row"
|
||||||
>
|
>
|
||||||
<uv-checkbox
|
<uv-checkbox
|
||||||
:name="item.cartInfo.productAttrUnique"
|
:name="item.cartInfo.productAttrUnique"
|
||||||
:disabled="item.isAfterSales != 1"
|
:disabled="item.isAfterSales != 1"
|
||||||
/>
|
/>
|
||||||
<goods
|
<view class="goods-col">
|
||||||
list
|
<Goods
|
||||||
interval
|
row
|
||||||
showAction
|
imgWidth="200rpx"
|
||||||
model
|
info-padding="10rpx 40rpx"
|
||||||
:price="item.cartInfo.truePrice"
|
:goods="item.cartInfo.productInfo"
|
||||||
:data="item.cartInfo.productInfo"
|
>
|
||||||
>
|
<template #options>
|
||||||
</goods>
|
<view class="goods-options">
|
||||||
|
<!-- sku select -->
|
||||||
|
<view class="sku-row flex">
|
||||||
|
<view
|
||||||
|
class="sku-info flex flex-jc__sb flex-ai__center"
|
||||||
|
>
|
||||||
|
<view class="info">
|
||||||
|
{{ item.cartInfo.productInfo &&item.cartInfo.productInfo.attrInfo && item.cartInfo.productInfo.attrInfo.sku }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- bottom -->
|
||||||
|
<view class="price-row flex flex-ai__center flex-jc__sb">
|
||||||
|
<!-- price -->
|
||||||
|
<view class="price-box flex flex-ai__end">
|
||||||
|
¥{{item.cartInfo.truePrice }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</Goods>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</card>
|
</card>
|
||||||
</space>
|
</space>
|
||||||
@ -87,6 +109,7 @@ import { ref, watch } from 'vue'
|
|||||||
import { applyForAfterSalesInfo } from '@/api/order'
|
import { applyForAfterSalesInfo } from '@/api/order'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { useRouter } from "@/hooks/useRouter";
|
import { useRouter } from "@/hooks/useRouter";
|
||||||
|
import Goods from "@/components/goodsComponents/Goods.vue";
|
||||||
|
|
||||||
const {getParams, push, goBack} = useRouter()
|
const {getParams, push, goBack} = useRouter()
|
||||||
const goodsList = ref([])
|
const goodsList = ref([])
|
||||||
@ -118,7 +141,7 @@ watch(goodsSelect, (goodsSelect) => {
|
|||||||
price += item.cartInfo.truePrice * item.cartInfo.cartNum
|
price += item.cartInfo.truePrice * item.cartInfo.cartNum
|
||||||
})
|
})
|
||||||
|
|
||||||
totalPrice.value = price
|
totalPrice.value = price.toFixed(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleOrderInfo = async (option) => {
|
const handleOrderInfo = async (option) => {
|
||||||
@ -140,7 +163,8 @@ const toRefund = (type) => {
|
|||||||
goods: goodsSelect.value.toString(),
|
goods: goodsSelect.value.toString(),
|
||||||
orderId: orderId.value,
|
orderId: orderId.value,
|
||||||
id: id.value
|
id: id.value
|
||||||
}
|
},
|
||||||
|
type:'redirectTo'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,4 +229,95 @@ onLoad((options) => {
|
|||||||
background: $white-color;
|
background: $white-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.goods-row{
|
||||||
|
@include useFlex(space-between,center);
|
||||||
|
@include usePadding(20,10);
|
||||||
|
width: 100%;
|
||||||
|
.goods-col{
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 商品SKU 数量等操作条
|
||||||
|
.goods-options {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.sku-row {
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
|
||||||
|
.sku-info {
|
||||||
|
@include usePadding(10, 4);
|
||||||
|
border: 1rpx solid #ccc;
|
||||||
|
border-radius: 5rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
transition: all .3s;
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
|
|
||||||
|
.info {
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
scale: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-left: 15rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-row {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.price-box {
|
||||||
|
font-size: 30rpx;
|
||||||
|
color:$primary-color;
|
||||||
|
|
||||||
|
.old-price {
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: $tips-color;
|
||||||
|
text-decoration: line-through;
|
||||||
|
margin-left: 10rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-num {
|
||||||
|
font-size: 24rpx;
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 120rpx;
|
||||||
|
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
font-size: 32rpx;
|
||||||
|
width: 34rpx;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
border-radius: 5rpx;
|
||||||
|
border: 2rpx solid #cccccc;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all .3s;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
scale: 1.2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
<Header
|
<Header
|
||||||
system-bar-area-bg="#fff"
|
system-bar-area-bg="#fff"
|
||||||
header-area-bg="#fff"
|
header-area-bg="#fff"
|
||||||
:scroll-top="scrollTop"
|
|
||||||
bg-change-by-scroll
|
bg-change-by-scroll
|
||||||
>
|
>
|
||||||
购物车
|
购物车
|
||||||
@ -27,6 +26,7 @@
|
|||||||
<!-- 购物车信息 -->
|
<!-- 购物车信息 -->
|
||||||
<view
|
<view
|
||||||
v-for="(item) in cartList"
|
v-for="(item) in cartList"
|
||||||
|
:key="item.id"
|
||||||
class="shopping-item"
|
class="shopping-item"
|
||||||
>
|
>
|
||||||
<uv-checkbox
|
<uv-checkbox
|
||||||
@ -164,13 +164,17 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="action-height"></view>
|
|
||||||
<view class="h5-tabbar-height"></view>
|
|
||||||
</view>
|
</view>
|
||||||
<!-- null data -->
|
<!-- null data -->
|
||||||
<CartEmpty v-else />
|
<CartEmpty v-else />
|
||||||
|
<!-- 商品推荐 -->
|
||||||
|
<Recommend />
|
||||||
|
<view class="action-height"></view>
|
||||||
|
<view class="h5-tabbar-height"></view>
|
||||||
<!-- sku select -->
|
<!-- sku select -->
|
||||||
<GoodAttrSelect
|
<GoodAttrSelect
|
||||||
|
style="z-index: 999"
|
||||||
:id="openSkuProductId"
|
:id="openSkuProductId"
|
||||||
ref="goodsAttrSelectRef"
|
ref="goodsAttrSelectRef"
|
||||||
@close="handleCloseSkuSelect"
|
@close="handleCloseSkuSelect"
|
||||||
@ -194,7 +198,9 @@ import { settleFields } from "@/pages/shoppingCart/index.data";
|
|||||||
import { useCartData, useCartNumber, useCartOption, useSku } from "@/pages/shoppingCart/index.utils";
|
import { useCartData, useCartNumber, useCartOption, useSku } from "@/pages/shoppingCart/index.utils";
|
||||||
import CartEmpty from "@/pages/shoppingCart/components/CartEmpty.vue";
|
import CartEmpty from "@/pages/shoppingCart/components/CartEmpty.vue";
|
||||||
import Header from "@/components/Header/index.vue"
|
import Header from "@/components/Header/index.vue"
|
||||||
import { onHide, onPageScroll } from "@dcloudio/uni-app";
|
import { onHide, onPageScroll, onReachBottom } from "@dcloudio/uni-app";
|
||||||
|
import Recommend from "@/components/Recommend/index.vue";
|
||||||
|
import { useScroll } from "@/hooks/useScroll";
|
||||||
|
|
||||||
const modalRef = ref() // 删除弹窗
|
const modalRef = ref() // 删除弹窗
|
||||||
const goodsAttrSelectRef = ref() // 更改sku
|
const goodsAttrSelectRef = ref() // 更改sku
|
||||||
@ -233,15 +239,14 @@ const {
|
|||||||
} = useCartNumber({afterChange: computeSelectInfoByShoppingSelect})
|
} = useCartNumber({afterChange: computeSelectInfoByShoppingSelect})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
onHide(() => {
|
onHide(() => {
|
||||||
modalRef.value?.close()
|
modalRef.value?.close()
|
||||||
goodsAttrSelectRef.value?.close()
|
goodsAttrSelectRef.value?.close()
|
||||||
})
|
})
|
||||||
|
|
||||||
const scrollTop = ref(0)
|
useScroll()
|
||||||
onPageScroll((e) => {
|
|
||||||
scrollTop.value = e.scrollTop
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
ref="popupRef"
|
ref="popupRef"
|
||||||
:showCloseable="false"
|
:showCloseable="false"
|
||||||
@close="emit('close')"
|
@close="emit('close')"
|
||||||
|
@maskClick="clickMask"
|
||||||
>
|
>
|
||||||
<template v-if="couponList.length>0">
|
<template v-if="couponList.length>0">
|
||||||
<view
|
<view
|
||||||
@ -22,6 +23,7 @@
|
|||||||
@change="radioChage"
|
@change="radioChage"
|
||||||
>
|
>
|
||||||
<CouponItem
|
<CouponItem
|
||||||
|
class="select-coupon"
|
||||||
:coupons="item"
|
:coupons="item"
|
||||||
:type="'noType'"
|
:type="'noType'"
|
||||||
/>
|
/>
|
||||||
@ -39,6 +41,7 @@
|
|||||||
>
|
>
|
||||||
暂无可用的优惠券
|
暂无可用的优惠券
|
||||||
</Empty>
|
</Empty>
|
||||||
|
<view class="action-height"></view>
|
||||||
<view class="button-action">
|
<view class="button-action">
|
||||||
<view
|
<view
|
||||||
class="animation-button"
|
class="animation-button"
|
||||||
@ -71,6 +74,7 @@ const popupRef = ref(false)
|
|||||||
const currentCoupon = ref({})
|
const currentCoupon = ref({})
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const couponItem = ref(props.currentCouponId ? props.currentCouponId : -1)
|
const couponItem = ref(props.currentCouponId ? props.currentCouponId : -1)
|
||||||
|
const oldCoupon = ref(props.currentCouponId ? props.currentCouponId : -1)
|
||||||
const num = ref(0)
|
const num = ref(0)
|
||||||
const radioValue = ref('')
|
const radioValue = ref('')
|
||||||
const selectCouponPanel = ref(false)
|
const selectCouponPanel = ref(false)
|
||||||
@ -86,6 +90,7 @@ const handleSubmit = () => {
|
|||||||
close()
|
close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
oldCoupon.value = couponItem.value
|
||||||
emit('submitCoupon', {
|
emit('submitCoupon', {
|
||||||
couponId: couponItem.value
|
couponId: couponItem.value
|
||||||
})
|
})
|
||||||
@ -100,6 +105,12 @@ const groupChange = (n) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const clickMask = () => {
|
||||||
|
if (oldCoupon.value !== couponItem.value) {
|
||||||
|
couponItem.value = oldCoupon.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const radioChage = (n) => {
|
const radioChage = (n) => {
|
||||||
radioValue.value = n
|
radioValue.value = n
|
||||||
num.value = 0
|
num.value = 0
|
||||||
@ -142,8 +153,7 @@ defineExpose({
|
|||||||
|
|
||||||
.select-box {
|
.select-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 30rpx;
|
||||||
|
|
||||||
.select-icon {
|
.select-icon {
|
||||||
width: 20rpx;
|
width: 20rpx;
|
||||||
height: 20rpx;
|
height: 20rpx;
|
||||||
@ -153,15 +163,26 @@ defineExpose({
|
|||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
padding: 0 60rpx;
|
padding: 0 60rpx;
|
||||||
}
|
}
|
||||||
|
.select-coupon {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-height{
|
||||||
|
width: 100%;
|
||||||
|
height: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.button-action {
|
.button-action {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
.animation-button {
|
.animation-button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 80rpx;
|
height: 80rpx;
|
||||||
line-height: 80rpx;
|
line-height: 80rpx;
|
||||||
border-radius: 80rpx;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import UvRadio from "@/uni_modules/uv-radio/components/uv-radio/uv-radio.vue";
|
|||||||
import { doPayment, PayType } from "@/utils/paymentUtils";
|
import { doPayment, PayType } from "@/utils/paymentUtils";
|
||||||
import CouponSelect from "@/pages/submitOrder/components/coupon-select.vue";
|
import CouponSelect from "@/pages/submitOrder/components/coupon-select.vue";
|
||||||
import Header from "@/components/Header/index.vue"
|
import Header from "@/components/Header/index.vue"
|
||||||
|
import { useScroll } from "@/hooks/useScroll";
|
||||||
|
|
||||||
const {getParams, push, goBack} = useRouter()
|
const {getParams, push, goBack} = useRouter()
|
||||||
const {toast, loading, hideLoading} = useInterface();
|
const {toast, loading, hideLoading} = useInterface();
|
||||||
@ -117,16 +118,15 @@ async function handleConfirm() {
|
|||||||
subLoading.value = true
|
subLoading.value = true
|
||||||
try {
|
try {
|
||||||
const payInfo = await doCreateServiceOrder()
|
const payInfo = await doCreateServiceOrder()
|
||||||
debugger
|
|
||||||
// 去拉取支付
|
// 去拉取支付
|
||||||
await doPayment({type: payType.value, payInfo})
|
await doPayment({type: payType.value, payInfo})
|
||||||
// #ifndef H5
|
// #ifndef H5
|
||||||
push({url: '/pages/payStatus/index?type=1'}, {type: 'redirectTo'})
|
push({url: '/pages/payStatus/index'}, {type: 'redirectTo'})
|
||||||
// #endif
|
// #endif
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
toast({title: '支付失败'})
|
toast({title: '支付失败'})
|
||||||
push({url: '/pages/payStatus/index?type=2'}, {type: 'redirectTo'})
|
push({url: '/pages/payStatus/index'}, {type: 'redirectTo'})
|
||||||
} finally {
|
} finally {
|
||||||
subLoading.value = false
|
subLoading.value = false
|
||||||
mainStore.cartId = null
|
mainStore.cartId = null
|
||||||
@ -159,12 +159,7 @@ async function doCreateServiceOrder() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollTop = ref(0)
|
useScroll()
|
||||||
|
|
||||||
onPageScroll(e => {
|
|
||||||
scrollTop.value = e.scrollTop
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查路由参数
|
* 检查路由参数
|
||||||
@ -192,7 +187,7 @@ onLoad(async options => {
|
|||||||
<template>
|
<template>
|
||||||
<view class="order-confirm">
|
<view class="order-confirm">
|
||||||
<!-- header -->
|
<!-- header -->
|
||||||
<Header :scroll-top="scrollTop">
|
<Header>
|
||||||
提交订单
|
提交订单
|
||||||
</Header>
|
</Header>
|
||||||
<!-- 地址 -->
|
<!-- 地址 -->
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useMainStore } from "@/store/store";
|
import { useMainStore } from "@/store/store";
|
||||||
import { useInterface } from "@/hooks/useInterface";
|
import { useInterface } from "@/hooks/useInterface";
|
||||||
import { updateAvatar, updateUserInfo } from "@/api/user";
|
import { updateAvatar, updateUserInfo } from "@/api/user";
|
||||||
|
import { upload } from "@/api/api";
|
||||||
|
|
||||||
export function useRequest() {
|
export function useRequest() {
|
||||||
const {loading, hideLoading, toast} = useInterface()
|
const {loading, hideLoading, toast} = useInterface()
|
||||||
@ -12,12 +13,15 @@ export function useRequest() {
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async function doUpdateAvatar(file) {
|
async function doUpdateAvatar(file) {
|
||||||
let data = new FormData()
|
try {
|
||||||
data.append('avatarFile', file)
|
await upload({
|
||||||
loading({title: '上传中...'})
|
filePath: file.url,
|
||||||
await updateAvatar(data)
|
name: 'avatarFile'
|
||||||
await userStore.getUserInfo()
|
});
|
||||||
hideLoading()
|
await userStore.getUserInfo()
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doUpdateUserInfo() {
|
async function doUpdateUserInfo() {
|
||||||
|
@ -44,8 +44,7 @@ const modelRef = ref()
|
|||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async function afterChooseFile(event) {
|
async function afterChooseFile(event) {
|
||||||
const imgObj = await objectURLToBlob(event.file.url)
|
await doUpdateAvatar(event.file)
|
||||||
await doUpdateAvatar(new File([imgObj], '', {type: imgObj.type}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexChange(event) {
|
function sexChange(event) {
|
||||||
|
@ -48,8 +48,7 @@ export const useMainStore = defineStore('main', {
|
|||||||
// console.log('--> % getUserInfo % res:\n', res)
|
// console.log('--> % getUserInfo % res:\n', res)
|
||||||
},
|
},
|
||||||
async getAddressCityList() {
|
async getAddressCityList() {
|
||||||
let res = await getAddressCityList()
|
this.areaList = await getAddressCityList()
|
||||||
this.areaList = res
|
|
||||||
},
|
},
|
||||||
init() {
|
init() {
|
||||||
let accessToken = cookie.get('accessToken')
|
let accessToken = cookie.get('accessToken')
|
||||||
|
@ -16,12 +16,19 @@ const {loading, hideLoading} = useInterface()
|
|||||||
export const WechatProvider = 'wxpay'
|
export const WechatProvider = 'wxpay'
|
||||||
|
|
||||||
// 支付类型(后端用)
|
// 支付类型(后端用)
|
||||||
export const ServicePayType = {
|
export const ServiceFrom = {
|
||||||
0: 'weixin_h5', // H5(微信内h5、微信外H5)
|
'h5': 'weixin_h5', // H5(微信内h5、微信外H5)
|
||||||
1: 'weixin_applet', // 微信小程序
|
'weixin': 'weixin_applet', // 微信小程序
|
||||||
2: 'weixin_app' // 微信APP
|
'app': 'weixin_app' // 微信APP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const ServicePayType = {
|
||||||
|
'h5': 'weixin_h5', // H5(微信内h5、微信外H5)
|
||||||
|
'weixin': 'weixin_applet', // 微信小程序
|
||||||
|
'app': 'weixin_app' // 微信APP
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 支付类型(前端用)
|
// 支付类型(前端用)
|
||||||
export const PayType = {
|
export const PayType = {
|
||||||
@ -116,12 +123,15 @@ async function _chooseEnvToPayment(options) {
|
|||||||
*/
|
*/
|
||||||
function _appWechatPay(payInfo) {
|
function _appWechatPay(payInfo) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
// 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no }
|
const payData = {
|
||||||
const res = await _doWechatPayRequest({
|
from: ServiceFrom['app'],
|
||||||
from: ServicePayType['2'],
|
paytype: ServicePayType['app'],
|
||||||
paytype: ServicePayType['2'],
|
|
||||||
uni: payInfo.orderId
|
uni: payInfo.orderId
|
||||||
})
|
}
|
||||||
|
// 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no }
|
||||||
|
const res = await _doWechatPayRequest(payData)
|
||||||
|
// 兼容性写法:防止电脑端用户支付后马上关闭支付弹窗导致失败
|
||||||
|
uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify(payData))
|
||||||
const orderInfo = {
|
const orderInfo = {
|
||||||
appid: res.appId, // 微信开放平台审核通过的移动应用AppID 。
|
appid: res.appId, // 微信开放平台审核通过的移动应用AppID 。
|
||||||
prepayid: res.merchant_id, // 请填写商户号mchid对应的值。
|
prepayid: res.merchant_id, // 请填写商户号mchid对应的值。
|
||||||
@ -148,13 +158,15 @@ function _appWechatPay(payInfo) {
|
|||||||
*/
|
*/
|
||||||
function _miniProgramPay(payInfo) {
|
function _miniProgramPay(payInfo) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
// 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no }
|
const payData = {
|
||||||
const res = await _doWechatPayRequest({
|
from: ServiceFrom['weixin'],
|
||||||
from: ServicePayType['1'],
|
paytype: ServiceFrom['weixin'],
|
||||||
paytype: ServicePayType['1'],
|
|
||||||
uni: payInfo.orderId
|
uni: payInfo.orderId
|
||||||
})
|
}
|
||||||
|
// 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no }
|
||||||
|
const res = await _doWechatPayRequest(payData)
|
||||||
|
// 兼容性写法:防止电脑端用户支付后马上关闭支付弹窗导致失败
|
||||||
|
uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify(payData))
|
||||||
uni.requestPayment({
|
uni.requestPayment({
|
||||||
timeStamp: res.timeStamp,
|
timeStamp: res.timeStamp,
|
||||||
nonceStr: res.nonceStr,
|
nonceStr: res.nonceStr,
|
||||||
@ -177,12 +189,13 @@ function _miniProgramPay(payInfo) {
|
|||||||
*/
|
*/
|
||||||
async function _h5InWechatPay(payInfo) {
|
async function _h5InWechatPay(payInfo) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
// 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no }
|
const payData = {
|
||||||
const res = await _doWechatPayRequest({
|
from: ServiceFrom['h5'],
|
||||||
from: 'h5',
|
paytype: ServicePayType['h5'],
|
||||||
paytype: ServicePayType['0'],
|
|
||||||
uni: payInfo.orderId
|
uni: payInfo.orderId
|
||||||
})
|
}
|
||||||
|
// 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no }
|
||||||
|
const res = await _doWechatPayRequest(payData)
|
||||||
/** 注册JS SDK */
|
/** 注册JS SDK */
|
||||||
jweixin.config({
|
jweixin.config({
|
||||||
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
|
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
|
||||||
@ -203,6 +216,7 @@ async function _h5InWechatPay(payInfo) {
|
|||||||
return reject(createMessage('微信版本过低,请升级微信版本', error))
|
return reject(createMessage('微信版本过低,请升级微信版本', error))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify(payData))
|
||||||
/** 去拉起微信支付 */
|
/** 去拉起微信支付 */
|
||||||
jweixin.chooseWXPay({
|
jweixin.chooseWXPay({
|
||||||
timestamp: res.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
|
timestamp: res.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
|
||||||
@ -212,16 +226,6 @@ async function _h5InWechatPay(payInfo) {
|
|||||||
paySign: res.paySign, // 支付签名
|
paySign: res.paySign, // 支付签名
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
// 支付成功后的回调函数
|
// 支付成功后的回调函数
|
||||||
uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify(
|
|
||||||
{
|
|
||||||
from: 'h5',
|
|
||||||
paytype: ServicePayType['0'],
|
|
||||||
uni: payInfo.orderId
|
|
||||||
}
|
|
||||||
))
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.redirectTo({url: '/pages/payStatus/index'})
|
|
||||||
}, 3000)
|
|
||||||
return resolve(createMessage('用户支付成功', res))
|
return resolve(createMessage('用户支付成功', res))
|
||||||
},
|
},
|
||||||
cancel: (r) => {
|
cancel: (r) => {
|
||||||
@ -246,20 +250,15 @@ async function _h5InWechatPay(payInfo) {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
async function _h5OutWechatPay(payInfo) {
|
async function _h5OutWechatPay(payInfo) {
|
||||||
const res = await _doWechatPayRequest({
|
const payData = {
|
||||||
from: 'h5',
|
from: ServiceFrom['h5'],
|
||||||
paytype: ServicePayType['0'],
|
paytype: ServicePayType['h5'],
|
||||||
uni: payInfo.orderId
|
uni: payInfo.orderId
|
||||||
})
|
}
|
||||||
|
const res = await _doWechatPayRequest(payData)
|
||||||
if (res && res.mwebUrl) {
|
if (res && res.mwebUrl) {
|
||||||
// 缓存支付订单数据
|
// 缓存支付订单数据
|
||||||
uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify(
|
uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify(payData))
|
||||||
{
|
|
||||||
from: 'h5',
|
|
||||||
paytype: ServicePayType['0'],
|
|
||||||
uni: payInfo.orderId
|
|
||||||
}
|
|
||||||
))
|
|
||||||
location.replace(res.mwebUrl)
|
location.replace(res.mwebUrl)
|
||||||
return Promise.resolve(createMessage('用户支付成功', {type: 'h5'}))
|
return Promise.resolve(createMessage('用户支付成功', {type: 'h5'}))
|
||||||
} else {
|
} else {
|
||||||
|
@ -146,3 +146,12 @@ export function hasNetWork() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取两数之间的随机数
|
||||||
|
* @param min
|
||||||
|
* @param max
|
||||||
|
*/
|
||||||
|
export function getRandom(min, max) {
|
||||||
|
return (Math.random() * (max - min) + min).toFixed(2);
|
||||||
|
}
|
||||||
|
206
utils/wechatUtils.js
Normal file
206
utils/wechatUtils.js
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
/**
|
||||||
|
* @FileDescription: 微信工具类
|
||||||
|
* @Author: kahu
|
||||||
|
* @Date: 2023/6/29
|
||||||
|
* @LastEditors: kahu
|
||||||
|
* @LastEditTime: 2023/6/29
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拍摄或从手机相册中选择图片或视频
|
||||||
|
* @param options
|
||||||
|
* @param options.count 数量 最大选取数量 最多可以选择的文件个数,基础库2.25.0前,最多可支持9个文件,2.25.0及以后最多可支持20个文件
|
||||||
|
* @param options.mediaType 选取类型 image图片 video视频
|
||||||
|
* @param options.sourceType 选取的方式 album相册 camera相机
|
||||||
|
* @param options.maxDuration 录取视频的最大秒数,时间范围为 3s 至 60s 之间。不限制相册
|
||||||
|
* @param options.sizeType 是否压缩所选内容,基础库2.25.0前仅对 mediaType 为 image 时有效,2.25.0及以后对全量 mediaType 有效
|
||||||
|
* @param options.camera 拍摄时候的摄像头,仅在 sourceType 为 camera 时生效,使用前置或后置摄像头
|
||||||
|
*/
|
||||||
|
export function wxChooseMedia(options={}){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const mergeOptions = {
|
||||||
|
count:9,
|
||||||
|
mediaType:['image','video'],
|
||||||
|
sourceType:['album','camera'],
|
||||||
|
maxDuration:10,
|
||||||
|
sizeType:['original','compressed'],
|
||||||
|
camera:'back',
|
||||||
|
...options,
|
||||||
|
success:(res)=>{
|
||||||
|
resolve(res)
|
||||||
|
},
|
||||||
|
fail:(err)=>{
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wx.chooseMedia(mergeOptions)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用微信接口编辑图片
|
||||||
|
* @param src 被编辑图片的临时路径
|
||||||
|
*/
|
||||||
|
export function wxEditImage(src){
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
wx.editImage({
|
||||||
|
src,
|
||||||
|
success:(res)=>{
|
||||||
|
resolve(res.tempFilePath)
|
||||||
|
},
|
||||||
|
fail:(err)=>{
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用微信接口裁剪图片
|
||||||
|
* @param options
|
||||||
|
* @param options.src 被裁剪图片的临时路径
|
||||||
|
* @param options.cropScale 裁剪比例
|
||||||
|
*/
|
||||||
|
export function wxCropImage(options){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const mergeOptions = {
|
||||||
|
cropScale:'1:1',
|
||||||
|
...options,
|
||||||
|
success:(res)=>{
|
||||||
|
resolve(res.tempFilePath)
|
||||||
|
},
|
||||||
|
fail:(err)=>{
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wx.cropImage(mergeOptions)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用微信接口处理视频
|
||||||
|
* @param options
|
||||||
|
* @param options.filePath 视频的本地路径
|
||||||
|
* @param options.minDuration 视频的最小长度
|
||||||
|
* @param options.maxDuration 视频的最大长度
|
||||||
|
* @return { Promise<{duration:number,size:number,tempFilePath:string,tempThumbPath:string}> }
|
||||||
|
*/
|
||||||
|
export function wxEditVideo(options){
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
if(options.minDuration>=options.maxDuration)return reject('MaxDuration Must Greater Than MinDuration')
|
||||||
|
wx.openVideoEditor({
|
||||||
|
...options,
|
||||||
|
success:(res)=>{
|
||||||
|
resolve(res)
|
||||||
|
},
|
||||||
|
fail:(err)=>{
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取视频的详情
|
||||||
|
* @param src
|
||||||
|
*/
|
||||||
|
export function wxGetVideoInfo(src){
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
wx.getVideoInfo({
|
||||||
|
src,
|
||||||
|
success:(res)=>{
|
||||||
|
resolve(res)
|
||||||
|
},
|
||||||
|
fail:(err)=>{
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取照片的详情
|
||||||
|
* @param src
|
||||||
|
*/
|
||||||
|
export function wxGetImageInfo(src){
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
wx.getImageInfo({
|
||||||
|
src,
|
||||||
|
success:(res)=>{
|
||||||
|
resolve(res)
|
||||||
|
},
|
||||||
|
fail:(err)=>{
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用微信login获取code
|
||||||
|
*/
|
||||||
|
export function wxLogin(){
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
uni.login({
|
||||||
|
provider: 'weixin',
|
||||||
|
success: (res) => {
|
||||||
|
resolve(res.code)
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
reject({
|
||||||
|
message:'微信login方法出现错误',
|
||||||
|
data:err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用微信getUserProfile获取encryptedData、iv
|
||||||
|
*/
|
||||||
|
export function wxGetUserProfile(){
|
||||||
|
return new Promise((resolve, reject)=> {
|
||||||
|
uni.getUserProfile({
|
||||||
|
desc: '用于完善用户信息',
|
||||||
|
success: ({ encryptedData, iv }) => {
|
||||||
|
resolve({encryptedData,iv})
|
||||||
|
},
|
||||||
|
fail:(err)=>{
|
||||||
|
console.log(err)
|
||||||
|
reject({
|
||||||
|
message:'微信getUserProfile方法出现错误',
|
||||||
|
data:err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用地图获取位置信息
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
export function wxChooseLocation(params){
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
const obj = {
|
||||||
|
success(e){
|
||||||
|
resolve(e)
|
||||||
|
},
|
||||||
|
fail(err){
|
||||||
|
console.log(err)
|
||||||
|
reject({
|
||||||
|
message:'微信ChooseLocation方法出现错误',
|
||||||
|
data:err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object.keys(params).forEach(key=>{
|
||||||
|
// @ts-ignore
|
||||||
|
obj[key] = params[key]
|
||||||
|
})
|
||||||
|
uni.chooseLocation(obj)
|
||||||
|
})
|
||||||
|
}
|
Reference in New Issue
Block a user