Compare commits

...

26 Commits

Author SHA1 Message Date
8352b02110 feat: 优化修改密码输入框 2025-02-13 23:32:57 +08:00
2d3147d65d fix: 修复设置密码在真机上兼容问题 2025-02-13 21:54:31 +08:00
1c8de323fe feat: 完善支付密码逻辑 2025-01-21 23:45:15 +08:00
b50eb2f1c2 fix: 修复设置支付密码引用问题 2025-01-21 01:12:18 +08:00
894818401e feat: 支付密码设置逻辑调整 2025-01-21 01:10:27 +08:00
596433ed86 feat: 更新版本号 2025-01-19 14:40:03 +08:00
e16e1e3bdc feat(user): 添加支付密码设置功能 2025-01-19 14:34:45 +08:00
de509c7e14 店铺用户注册强制完善手机号 2024-06-18 12:33:25 +08:00
13ee0f593c bug修复 2024-06-17 16:02:46 +08:00
14b723ce1f 优化店铺名显示 2024-06-16 00:22:40 +08:00
41384ef8e9 优化错误提示 2024-06-15 19:08:56 +08:00
f83bf3dd98 优化打开团购券分享时用户已登录&未登录,店铺已注册&未注册逻辑处理 2024-06-14 02:21:35 +08:00
6921c82ad3 补充分享未注册店铺的团购券的注册流程 2024-06-12 23:01:53 +08:00
fe91157f6c 团购商品未配置图片问题修复 2024-06-12 16:23:22 +08:00
63b30c0695 修复购买微信团购券不到帐问题 2024-06-11 23:01:50 +08:00
49b1968ba5 团购券购买数量bug修复 2024-06-09 18:57:35 +08:00
a620ecf624 商品团购券分享处理 2024-06-08 17:05:25 +08:00
4b4ee44242 商品团购分享处理 2024-06-07 14:10:43 +08:00
613c0df738 登录逻辑调整 2024-06-06 17:48:37 +08:00
8f06cf703d 登录逻辑调整 2024-06-06 17:36:31 +08:00
351e675c6d 删除日志 2024-06-06 11:49:38 +08:00
7bbf436a1c 原先团购处理 2024-06-06 11:49:38 +08:00
9d138814f2 异常处理 2024-06-06 11:49:38 +08:00
f0ca5624ea 接口错误码兼容处理 2024-06-06 11:49:38 +08:00
947d85c1c6 bug修复 2024-06-06 11:49:38 +08:00
183a95f48b bug修复 2024-06-04 10:21:16 +08:00
37 changed files with 1218 additions and 207 deletions

View File

@ -1,6 +1,7 @@
<script lang='ts'>
import {
getCompanyId,
getQueryParam,
getRegisterStoreId,
mpUpdate,
setCompanyId,
@ -51,11 +52,11 @@ export default {
else {
//
if(import.meta.env.VITE_APP_BASE_API.includes('api.lakeapp')) {
// setCompanyId('1150930317231112193');
// setRegisterStoreId('1150930317436633090');
setCompanyId('1150930317231112193');
setRegisterStoreId('1150930317436633090');
setCompanyId('1471673498334113794');
setRegisterStoreId('1471673498413805570');
// setCompanyId('1471673498334113794');
// setRegisterStoreId('1471673498413805570');
}
//
else {
@ -85,12 +86,6 @@ export default {
}
if(options?.query.scene) {
function getQueryParam(queryParams: string, key: string) {
let regex = new RegExp('(?:[?&]|^)' + key + '=([^&]+)'),
match = queryParams.match(regex);
return match && match[1];
}
//id
const params = decodeURIComponent(options?.query.scene);
if(params.includes('companyId')) {
@ -107,15 +102,6 @@ export default {
}, 500);
}
}
//
if(options?.path?.includes('ticketsBuy/ticketsBuy') && options?.query.couponsId) {
setTimeout(() => {
uni.reLaunch({
url: 'pages/common/groupbuy/index?id=' + options?.query.couponsId
});
}, 500);
}
}
logger.info(`App Launch options ${env}: { companyId: `, getCompanyId() + ', storeId: ' + getRegisterStoreId() + ' }');
@ -134,7 +120,10 @@ export default {
globalData: {
logger: logger,
companyId: getCompanyId(),
storeId: getRegisterStoreId()
storeId: getRegisterStoreId(),
shareCompanyId: '',//id
shareStoreId: '',//id
sharePath: ''//便
}
};

View File

@ -2,3 +2,5 @@ import { get } from '@/utils/request';
export const getCompanyList = (maOpenId: string) => get({ url: `/wc/wechat/company?maOpenId=${maOpenId}` });
export const getCompanyInfo = () => get({ url: `/ext/zconfig/company_find` });
export const getStoreId = (data: any) => get({ url: '/wc/wechat/get_store_id', data });

View File

@ -13,13 +13,21 @@ export const getGroupBuyList = (data: {
export const getGroupBuyDetail = (
id: string) => get<GroupBuyBean>({ url: `wechat/coupons/group/get/${id}` });
export const getShareGoodsDetail = (shareId: string) => post<any>({ url: '/wechat/coupons/group/qrcode/' + `${shareId}` });
export const getShareGoodsCouponDetail = (couponId: string) => get<GroupBuyBean>({ url: 'wechat/coupons/get/' + `${couponId}` });
export const getGroupBuyRecordList = (groupId: string, pageNum: number, pageSize: number) => post<RecordBean[]>({
url: `wechat/coupons/group/order/list?groupId=${groupId}&pageNum=${pageNum}&pageSize=${pageSize}`
});
export const preOrder = (data: any) => post<GoodsBean>({ url: 'wechat/coupons/group/pre_v2', data });
export const preOrder = (data: any) => post<GoodsBean>({ url: 'wechat/coupons/pre', data });
export const preOrderV2 = (data: any) => post<GoodsBean>({ url: 'wechat/coupons/group/pre_v2', data });
export const progress = (data: any) => post<any>({ url: 'wechat/coupons/group/pay/progress', data });
export const pay = (data: any) => post<any>({ url: 'wechat/coupons/group/pay', data });
export const couponPay = (data: any) => post<any>({ url: 'wechat/coupons/pay', data });

View File

@ -1,7 +1,7 @@
/**
*
*/
import type { CouponBean, LoginParams, LoginResult, RegisterParams, TerminalBean } from './types';
import type { CouponBean, LoginParams, LoginResult, RegisterParams, TerminalBean, SetPayPasswordParams,PayPasswordResponse} from './types';
import { get, post } from '@/utils/request';
import { UserBean } from '@/store/modules/user/types';
@ -33,7 +33,8 @@ enum URL {
tradeList = '/memberIncoming/wx_balance_records',
terminal = 'wechat/coupons/terminal?companyId=',
cardLink = '/wc/wechat/get_card_url',
registerCoupon = '/couponsStrategy/wx_register_coupon'
registerCoupon = '/couponsStrategy/wx_register_coupon',
setPayPassword = '/app/pay/set_paypwd',
}
export const getUserProfile = () => get<UserBean>({ url: URL.profile });
@ -76,3 +77,11 @@ export const getTradeList = (data: any) => post<any>({ url: URL.tradeList, data
export const getCardLink = () => get<string>({ url: URL.cardLink });
export const getRegisterCoupon = () => get<any>({ url: URL.registerCoupon });
/**
*
*/
export const setPayPassword = (data: SetPayPasswordParams) => post<PayPasswordResponse>({
url: URL.setPayPassword,
data
});

View File

@ -118,3 +118,15 @@ export interface TerminalBean {
token: string;
type: number;
}
export interface SetPayPasswordParams {
paywithpwd: number // 0: 开启支付密码, 1: 关闭支付密码
oldpwd: string,
newpwd: string
}
export interface PayPasswordResponse {
success: boolean
message: string
hasPassword?: boolean
}

View File

@ -0,0 +1,290 @@
<template>
<uni-popup ref="popup" type="center" :safe-area="true" :mask-click="false">
<view class="pay-password-dialog">
<view class="dialog-header">
<text class="title">{{ getDialogTitle }}</text>
<u-icon name="close" size="20" color="#999" @click="hide" />
</view>
<view class="form-container">
<!-- 关闭支付密码选项 -->
<view class="switch-item" v-if="hasOldPassword">
<text>关闭支付密码</text>
<u-switch v-model="isClosePassword" activeColor="#F32B2B" @change="handleSwitchChange" />
</view>
<!-- 旧密码 - 只在修改密码或关闭密码时显示 -->
<view class="form-item" v-if="hasOldPassword">
<text class="label">原密码</text>
<view class="input-wrapper">
<u-input v-model="oldPassword" type="number" :border="false" placeholder="请输入原密码" :maxlength="6"
:disabled="isClosePassword" :password="!showOldPassword" @input="handleInput($event, 'oldPassword')" />
<u-icon :name="showOldPassword ? 'eye-off' : 'eye-fill'" size="20" color="#999"
v-if="hasOldPassword && !isClosePassword" @click="showOldPassword = !showOldPassword" />
</view>
</view>
<!-- 新密码和确认密码部分 -->
<template v-if="!isClosePassword">
<!-- 新密码 -->
<view class="form-item">
<text class="label">新密码</text>
<view class="input-wrapper">
<u-input v-model="newPassword" type="number" placeholder="请输入6位数字密码" maxlength="6" :border="false"
:password="!showNewPassword" @input="handleInput($event, 'newPassword')" />
<u-icon :name="showNewPassword ? 'eye-off' : 'eye-fill'" size="20" color="#999"
@click="showNewPassword = !showNewPassword" />
</view>
</view>
<!-- 确认密码 -->
<view class="form-item">
<text class="label">确认密码</text>
<view class="input-wrapper">
<u-input v-model="confirmPassword" type="number" :border="false" placeholder="请再次输入密码" maxlength="6"
:password="!showConfirmPassword" @input="handleInput($event, 'confirmPassword')" />
<u-icon :name="showConfirmPassword ? 'eye-off' : 'eye-fill'" size="20" color="#999"
@click="showConfirmPassword = !showConfirmPassword" />
</view>
</view>
</template>
</view>
<view class="footer">
<button :class="{ 'primary-button': isFormValid, 'disabled-button': !isFormValid }" :disabled="!isFormValid"
@click.stop='handleConfirm'>
完成
</button>
</view>
</view>
</uni-popup>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useUserStore } from '@/store'
const userStore = useUserStore()
const popup = ref<any>(null)
// -
const showOldPassword = ref(false)
const showNewPassword = ref(false)
const showConfirmPassword = ref(false)
//
const resetPasswordVisibility = () => {
showOldPassword.value = false
showNewPassword.value = false
showConfirmPassword.value = false
}
//
const oldPassword = ref('')
const newPassword = ref('')
const confirmPassword = ref('')
//
const hasOldPassword = ref(false)
//
const isClosePassword = ref(false)
//
const getDialogTitle = computed(() => {
if (!hasOldPassword.value) return '设置支付密码'
if (isClosePassword.value) return '关闭支付密码'
return '修改支付密码'
})
//
const isFormValid = computed(() => {
if (isClosePassword.value) {
//
return true
} else if (!hasOldPassword.value) {
//
if (!newPassword.value || !confirmPassword.value) return false
if (newPassword.value.length !== 6 || confirmPassword.value.length !== 6) return false
return newPassword.value === confirmPassword.value
} else {
//
if (!oldPassword.value || !newPassword.value || !confirmPassword.value) return false
if (oldPassword.value.length !== 6 || newPassword.value.length !== 6 || confirmPassword.value.length !== 6) return false
return newPassword.value === confirmPassword.value
}
})
// 6
const handleInput = (value: string, field: 'oldPassword' | 'newPassword' | 'confirmPassword') => {
// 6
const numericValue = value?.replace(/[^\d]/g, '').slice(0, 6)
//
switch (field) {
case 'oldPassword':
oldPassword.value = numericValue
break
case 'newPassword':
newPassword.value = numericValue
break
case 'confirmPassword':
confirmPassword.value = numericValue
break
}
}
// 6
const generateRandomPassword = () => {
return Math.floor(Math.random() * 1000000).toString().padStart(6, '0')
}
//
const resetForm = () => {
oldPassword.value = ''
newPassword.value = ''
confirmPassword.value = ''
resetPasswordVisibility()
isClosePassword.value = false
}
//
const show = async () => {
hasOldPassword.value = userStore.userInfo.paywithpwd === 1
isClosePassword.value = false
resetPasswordVisibility()
popup.value?.open('center')
}
//
const hide = () => {
popup.value?.close()
resetForm()
}
//
const handleConfirm = async () => {
try {
await userStore.setPayPassword({
paywithpwd: isClosePassword.value ? 0 : 1,
oldpwd: hasOldPassword.value ? oldPassword.value : '',
newpwd: isClosePassword.value ? '' : newPassword.value,
})
//
userStore.userInfo.paywithpwd = isClosePassword.value ? 0 : 1
uni.showToast({
title: isClosePassword.value ? '已关闭支付密码' : '设置成功',
icon: 'success',
})
hide()
resetForm()
} catch (error) {
uni.showToast({
title: '操作失败',
icon: 'error',
})
}
}
//
const handleSwitchChange = (value: boolean) => {
isClosePassword.value = value
//
if (value) {
newPassword.value = ''
confirmPassword.value = ''
oldPassword.value = generateRandomPassword() // 6
resetPasswordVisibility()
} else {
oldPassword.value = ''
}
}
// 使
defineExpose({
show,
hide
})
</script>
<style lang="scss" scoped>
.pay-password-dialog {
width: 600rpx;
padding: 40rpx;
background-color: #fff;
border-radius: 24rpx;
position: relative;
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 40rpx;
.title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
}
.form-container {
.switch-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
margin-bottom: 20rpx;
text {
font-size: 28rpx;
color: #333;
}
}
.form-item {
margin-bottom: 30rpx;
.label {
font-size: 30rpx;
color: #333;
margin-bottom: 16rpx;
display: block;
}
.input-wrapper {
display: flex;
align-items: center;
background-color: #f5f5f5;
border-radius: 12rpx;
padding: 20rpx;
height: 50rpx;
:deep(.u-border) {
border-style: hidden;
}
:deep(.u-input) {
flex: 1;
height: 100%;
background-color: transparent;
border: none;
font-size: 10rpx;
}
:deep(.u-input__input) {
height: 100%;
line-height: 60rpx;
font-size: 10rpx;
border: none;
padding: 0;
}
}
}
}
.footer {
padding: 0 30rpx;
}
}
</style>

View File

@ -2,8 +2,8 @@
"name": "SUKE-MP",
"appid": "",
"description": "",
"versionName": "3.0.2",
"versionCode": "302",
"versionName": "3.0.4",
"versionCode": "304",
"transformPx": false,
"app-plus": {
"usingComponents": true,
@ -25,7 +25,7 @@
"usingComponents": true,
"plugins": {
"sqb-pay": {
"version": "1.3.0",
"version": "1.3.1",
"provider": "wx55540b288c5ce319"
}
}

View File

@ -4,7 +4,8 @@
"^u--(.*)": "uview-plus/components/u-$1/u-$1.vue",
"^up-(.*)": "uview-plus/components/u-$1/u-$1.vue",
"^u-([^-].*)": "uview-plus/components/u-$1/u-$1.vue",
"^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)": "z-paging/components/z-paging$1/z-paging$1.vue"
"^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)": "z-paging/components/z-paging$1/z-paging$1.vue",
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
"pages": [
@ -36,7 +37,13 @@
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "肃客会员"
"navigationBarTitleText": "VIP顾客中心"
}
},
{
"path": "pages/coupons/ticketsBuy/ticketsBuy",
"style": {
"navigationBarTitleText": "团购详情"
}
}
],
@ -85,6 +92,15 @@
}
}
},
{
"path": "groupbuy/order-coupon-confirm",
"style": {
"navigationBarTitleText": "确认订单",
"usingComponents": {
"sqb-pay": "plugin://sqb-pay/sqb-pay"
}
}
},
{
"path": "webview/index",
"navigationBarTitleText": "网页"

View File

@ -2,13 +2,13 @@
<view class='content'>
<view class='swiper-container'>
<swiper class='swiper' :interval='1500' :duration='1000' @change='swiperChange'>
<swiper-item v-for='(item,index) in bannerList' :key='index'>
<image :src='item||defaultImage' mode='aspectFill' />
<swiper-item v-for='(item,index) in bannerList||[defaultImage]' :key='index'>
<image :src='item' mode='aspectFill' />
</swiper-item>
</swiper>
<view class='indicator'>
<text>{{ swiperIndex + 1 }}</text>
<text>/{{ bannerList.length }}</text>
<text>/{{ bannerList?.length || 0 }}</text>
</view>
</view>
<view class='countdown c-flex-row'>
@ -17,7 +17,7 @@
</view>
<view class='price c-flex-column' style='flex: 1'>
<text>{{ groupBuyBean?.payPrice || 0 }}</text>
<text>{{ groupBuyBean?.price || 0 }}</text>
<text v-if='(groupBuyBean?.price||0)>0&&!isCouponGoodsDetail'>{{ groupBuyBean?.price || 0 }}</text>
</view>
<view v-if='isPending()' class='countdown-time c-flex-column'>
<view class='c-flex-row'>{{ countdownTime?.days || 0 }}
@ -51,7 +51,7 @@
</view>
</view>
<view class='goods-sku-view c-flex-column'>
<view class='goods-sku-view c-flex-column' v-if='groupBuyBean?.goods'>
<view class='c-flex-row' @click.stop='showSkuDialog'>
<text>选择</text>
<text>规格 颜色/尺码</text>
@ -77,13 +77,16 @@
<!-- 商品详情图片 -->
<view class='card-view image-container' v-if='groupBuyBean?.content'>
<text class='card-view-title'>商品详情</text>
<image
v-for='(item,index) in JSON.parse(groupBuyBean?.content).filter((a: any) => a.type === 2).map((b: any) => b.images)'
:src='item' mode='aspectFill' :key='index' />
<text v-if='isCouponGoodsDetail' style='padding: 20rpx 35rpx;font-size: 30rpx'>
{{ groupBuyBean?.content }}
</text>
<image v-else
v-for='(item,index) in JSON.parse(groupBuyBean?.content).filter((a: any) => a.type === 2).map((b: any) => b.images)'
:src='item' mode='aspectFill' :key='index' />
</view>
<!-- 商品详情 -->
<view class='card-view goods-container'>
<view class='card-view goods-container' v-if='groupBuyBean?.goods'>
<view class='c-flex-row'>
<image :src='groupBuyBean?.goods?.images' />
<view class='c-flex-column'>
@ -101,7 +104,7 @@
</view>
<!-- 商品详情优惠券 -->
<view class='card-view coupon-container'>
<view class='card-view coupon-container' v-if='groupBuyBean?.couponsList&&groupBuyBean?.couponsList?.length>0'>
<text class='card-view-title'>赠送优惠券</text>
<view class='c-flex-column'>
<coupon-item v-for='(item,index) in groupBuyBean?.couponsList' :key='index' :item='item' />
@ -109,7 +112,7 @@
</view>
<!-- 商品详情跟团记录 -->
<view class='card-view record-container'>
<view class='card-view record-container' v-if='recordList&&(recordList?.length||0)>0'>
<text class='card-view-title'>跟团记录</text>
<u-list :list='recordList' :border='false' @scrolltolower='loadMore'>
<u-list-item v-for='(item,index) in recordList' :key='index'>
@ -139,15 +142,22 @@
<script lang='ts' setup>
import { assetsUrl, defaultImage } from '@/utils/assets';
import dayjs from 'dayjs';
import { formatTimeWithZeroPad, goPath, isLogin } from '@/utils';
import { formatTimeWithZeroPad, getCompanyId, getOpenId, goLogin, goPath, isLogin, showToast } from '@/utils';
import SkuDialog from '@/components/sku-dialog.vue';
import CouponItem from './components/coupon-item.vue';
import { getGroupBuyDetail, getGroupBuyRecordList, preOrder } from '@/api/groupbuy';
import {
getGroupBuyDetail,
getGroupBuyRecordList,
getShareGoodsCouponDetail,
getShareGoodsDetail,
preOrderV2
} from '@/api/groupbuy';
import { getGoodsList } from '@/api/goods';
import { GoodsBean } from '@/api/goods/types';
import { useUserStore } from '@/store';
import { GroupBuyBean, RecordBean } from '@/api/groupbuy/types';
import { getCompanyList } from '@/api/company';
const userStore = useUserStore();
const { userInfo } = storeToRefs(userStore);
@ -155,6 +165,7 @@ const { userInfo } = storeToRefs(userStore);
const skuDialogRef = ref();
const groupBuyBean = ref<GroupBuyBean>();
const recommendList = ref<GoodsBean[]>();
const isCouponGoodsDetail = ref(false);
const bannerList = ref([]);
const swiperIndex = ref(0);
@ -169,23 +180,79 @@ const countdownTime = ref<{
const recordList = ref<RecordBean[]>([]);
const currentPageNum = ref(1);
const shareGoodsId = ref();
const shareCouponId = ref();
onLoad(async (e: any) => {
if(isLogin()) {
await uni.showLoading();
groupBuyBean.value = await getGroupBuyDetail(e.id);
if(e.id != undefined) {
groupBuyBean.value = await getGroupBuyDetail(e.id);
}
if(e.shareId != undefined) {
shareGoodsId.value = e.shareId;
const { group, share } = await getShareGoodsDetail(e.shareId);
groupBuyBean.value = group;
}
if(e.couponId != undefined) {
shareCouponId.value = e.couponId;
isCouponGoodsDetail.value = true;
groupBuyBean.value = await getShareGoodsCouponDetail(e.couponId);
groupBuyBean.value.price = groupBuyBean.value?.offsetPrice;
bannerList.value = groupBuyBean.value?.image?.split(',');
}
const maOpenId = getOpenId() || userInfo.value?.maOpenId;
const data = await getCompanyList(maOpenId);
const companyList = data.map((item: any) => item.company);
const userList = data.map((item: any) => item.user);
let index = companyList.findIndex((res: {
id: string
}) => res.id === (getApp()?.globalData?.shareCompanyId || getCompanyId()));
if(index < 0) {
uni.showModal({
title: '提示',
content: '当前店铺还未注册,请先注册',
showCancel: true,
success: (res) => {
if(res.confirm) {
goPath('/pages/common/register/index');
} else {
goPath('/pages/home/index');
}
}
});
} else {
await userStore.setUserInfo(userList[index]);
}
// setCompanyId('1512403904150138881');
// groupBuyBean.value = await getGroupBuyDetail('1740922051118063618');
if(groupBuyBean.value) {
groupBuyBean.value.goods.price = groupBuyBean.value.price;
bannerList.value = JSON.parse(groupBuyBean.value.content).filter((item: any) => item.type === 2).map((item: any) => item.images);
countdown();
await fetchRecommendList();
await fetchBuyRecordList();
if(e.couponId === undefined) {
groupBuyBean.value.goods.price = groupBuyBean.value?.price || 0;
bannerList.value = JSON.parse(groupBuyBean.value?.content)?.filter((item: any) => item.type === 2).map((item: any) => item.images);
await fetchRecommendList();
await fetchBuyRecordList();
}
} else {
showToast('查询失败', {
complete: () => {
const pages = getCurrentPages();
if(pages.map(item => item?.route?.includes('pages/home/index'))) {
uni.navigateBack();
} else {
uni.reLaunch({
url: '/pages/home/index'
});
}
}
});
}
uni.hideLoading();
} else {
goPath('/pages/common/login/index');
goLogin(true);
}
});
@ -196,9 +263,15 @@ onUnload(() => {
});
onShareAppMessage((e) => {
let path = `/pages/common/groupbuy/detail?id=${groupBuyBean.value?.id}&companyId=${getApp().globalData?.companyId}&storeId=${getApp().globalData?.storeId}`;
if(shareGoodsId.value) {
path = `/pages/common/groupbuy/detail?shareId=${shareGoodsId.value}&companyId=${getApp().globalData?.companyId}&storeId=${getApp().globalData?.storeId}`;
} else if(shareCouponId.value) {
path = `/pages/common/groupbuy/detail?couponId=${shareCouponId.value}&companyId=${getApp().globalData?.companyId}&storeId=${getApp().globalData?.storeId}`;
}
return {
title: groupBuyBean.value?.goods?.name || 'VIP顾客中心',
path: `/pages/common/groupbuy/detail?id=${groupBuyBean.value?.id}&companyId=${getApp().globalData?.companyId}&storeId=${getApp().globalData?.storeId}`
path: path
};
});
@ -217,7 +290,7 @@ const isEnded = () => {
const getStockColorCount = computed(() => {
const list = Array.from(new Set(groupBuyBean.value?.goods?.stocks?.map(item => item.colorName)))
.map(colorName => groupBuyBean.value?.goods?.stocks?.find(item => item.colorName === colorName)!);
return list.length;
return (list?.length) || 0;
});
const fetchRecommendList = async () => {
@ -276,7 +349,8 @@ const showSkuDialog = (fn: Function) => {
const placeOrder = async () => {
async function create(bean: GoodsBean) {
async function createGoodsOrder(bean: GoodsBean) {
await uni.showLoading();
const params = {
'colorId': bean.checkedStock.colorId,
'sizeId': bean.checkedStock.sizeId,
@ -286,13 +360,18 @@ const placeOrder = async () => {
'shareId': '123456'
};
const result = await preOrder(params);
const result = await preOrderV2(params);
uni.hideLoading();
goPath(`/pages/common/groupbuy/order-confirm?orderBean=${encodeURIComponent(JSON.stringify(result))}`);
}
showSkuDialog((e: GoodsBean) => {
create(e);
});
if(isCouponGoodsDetail.value) {
goPath(`/pages/common/groupbuy/order-coupon-confirm?bean=${encodeURIComponent(JSON.stringify(groupBuyBean.value))}`);
} else {
showSkuDialog((e: GoodsBean) => {
createGoodsOrder(e);
});
}
};
</script>
@ -616,6 +695,8 @@ const placeOrder = async () => {
.goods-container {
padding: 30rpx;
position: relative;
margin-left: 20rpx;
margin-right: 20rpx;
image {
width: 200rpx;
@ -658,7 +739,14 @@ const placeOrder = async () => {
}
}
.coupon-container {
margin-left: 20rpx;
margin-right: 20rpx;
}
.record-container {
margin-left: 20rpx;
margin-right: 20rpx;
.item-view {
margin: 10rpx 30rpx;
@ -673,18 +761,19 @@ const placeOrder = async () => {
margin: 0 15rpx;
text:nth-of-type(1) {
font-size: 20rpx;
font-size: 25rpx;
color: #333333;
}
text:nth-of-type(2) {
font-size: 15rpx;
font-size: 25rpx;
color: #666666;
margin-top: 10rpx;
}
}
text:nth-of-type(1) {
font-size: 30rpx;
color: #F32B2B;
}
}

View File

@ -1,6 +1,5 @@
<template>
<view class='content'>
<view class='card-view'>
<template class='c-flex-row' v-for='item in orderBean?.orderGoods' :key='item.id'>
<image class='goods-image' :src='item?.images||defaultImage' />
@ -57,8 +56,12 @@ const { terminalInfo } = storeToRefs(userState);
const orderBean = ref<OrderBean>();
onLoad((e: any) => {
onLoad(async (e: any) => {
orderBean.value = JSON.parse(decodeURIComponent(e?.orderBean));
await userState.fetchTerminal();
if(!terminalInfo.value) {
showToast('当前店铺未配置收款渠道,请联系商家');
}
});
const buildSqbParams = computed(() => {
@ -66,10 +69,10 @@ const buildSqbParams = computed(() => {
client_sn: orderBean.value?.id || '',
return_url: '/pages/common/payresult/index',
total_amount: Number(((orderBean.value?.totalPrice || 0) * 100).toFixed(2)),
terminal_sn: terminalInfo.value.terminalSn,
subject: '商品团购券',
subject_img: orderBean?.value?.orderGoods[0].images || '',
merchant_name: terminalInfo.value.companyName,
terminal_sn: terminalInfo.value?.terminalSn,
subject: orderBean?.value?.orderGoods[0]?.goodsName || '商品团购券',
subject_img: orderBean?.value?.orderGoods[0]?.images || 'xxx',
merchant_name: terminalInfo.value?.companyName,
notify_url: 'https://www.baidu.com'
}, true);
@ -81,7 +84,7 @@ const buildSqbParams = computed(() => {
const navigateTo = (e: any) => {
handlePayResult(orderBean.value?.id, e, {
onSuccess: () => {
onSuccess: (options: any) => {
showToast('支付成功', {
icon: 'success',
complete: () => {
@ -94,11 +97,22 @@ const navigateTo = (e: any) => {
uni.hideLoading();
}
});
},
onFailure: (e: any) => {
showToast(e, {
complete: () => {
uni.navigateBack();
}
});
}
});
};
const payment = () => {
if(!terminalInfo.value) {
showToast('当前店铺未配置收款渠道,请联系商家');
return;
}
const params = {
'id': orderBean.value?.id,
'orderSn': buildSqbParams.value.client_sn,

View File

@ -0,0 +1,299 @@
<template>
<view class='content'>
<view class='card-view' style='justify-content: flex-start'>
<view class='c-flex-row' style='align-items: center;flex: 1'>
<image class='goods-image' :src='imageList?.length>0?imageList[0]:defaultImage' />
<view class='c-flex-column' style='margin-left: 10rpx;flex: 1'>
<text class='goods-name'>{{ groupBuyBean?.name || groupBuyBean?.title }}</text>
<text class='date'>{{ groupBuyBean?.startDate }}{{ groupBuyBean?.endDate }}</text>
</view>
<text class='goods-price'>¥{{ groupBuyBean?.payPrice }}</text>
</view>
</view>
<view class='card-view'>
<text style='flex: 1'>数量</text>
<view class='count-change-view c-flex-row'>
<view class='count-image' @click.stop='countChange(false)'>
<image :src='assetsUrl("ic_reduce.png")' />
</view>
<text>{{ goodsCount }}</text>
<view class='count-image' @click.stop='countChange(true)'>
<image :src='assetsUrl("ic_plus.png")' />
</view>
</view>
</view>
<view class='card-view'>
<text style='flex: 1'>实付</text>
<text style='color: #F32B2B'>¥{{ totalPrice || 0 }}</text>
</view>
<view class='bottom-view c-flex-row'>
<sqb-pay @navigateTo='navigateTo'
:return_url='buildSqbParams.return_url'
:total_amount='buildSqbParams.total_amount'
:terminal_sn='buildSqbParams.terminal_sn'
:client_sn='buildSqbParams.client_sn'
:subject='buildSqbParams.subject'
:subject_img='buildSqbParams.subject_img '
:merchant_name='buildSqbParams.merchant_name'
:notify_url='buildSqbParams.notify_url'
:sign='buildSqbParams.sign'>
<button class='confirm-button' @click='payment'>支付</button>
</sqb-pay>
</view>
</view>
</template>
<script lang='ts' setup>
import { couponPay, preOrder } from '@/api/groupbuy';
import { OrderBean } from '@/api/order/types';
import { parseParameter, showToast, sortASCII } from '@/utils';
import { hexMD5 } from '@/utils/common/md5';
import { useUserStore } from '@/store';
import { handlePayResult } from '@/utils/order';
import { assetsUrl, defaultImage } from '@/utils/assets';
import { GroupBuyBean } from '@/api/groupbuy/types';
const userState = useUserStore();
const { userInfo, terminalInfo } = storeToRefs(userState);
const groupBuyBean = ref<GroupBuyBean>();
const imageList = ref([]);
const orderBean = ref<OrderBean>();
const goodsCount = ref(1);
onLoad(async (e: any) => {
try {
groupBuyBean.value = JSON.parse(decodeURIComponent(e?.bean));
if(groupBuyBean.value) {
imageList.value = groupBuyBean.value?.image?.split(',');
}
await userState.fetchTerminal(groupBuyBean.value?.companyId || '');
createOrder();
} catch (e) {
getApp().globalData?.logger?.error('order-coupon-confirm: exception ', e);
}
});
const countChange = (isPlus: boolean) => {
if(isPlus) {
if(goodsCount.value < (groupBuyBean.value?.publicNum || 0)) {
goodsCount.value += 1;
} else {
showToast('超出最大购买数量');
}
} else {
if(goodsCount.value > 1) {
goodsCount.value -= 1;
}
}
};
const totalPrice = computed(() => {
return Number(((groupBuyBean.value?.payPrice || 0) * goodsCount.value).toFixed(2));
});
const buildSqbParams = computed(() => {
const params = sortASCII({
client_sn: orderBean.value?.id || '',
return_url: '/pages/common/payresult/index',
total_amount: Number(((totalPrice.value || 0) * 100).toFixed(2)),
terminal_sn: terminalInfo.value?.terminalSn,
subject: groupBuyBean.value?.name || '商品团购券',
subject_img: (imageList.value?.length > 0 && imageList.value[0]) || 'xxx',
merchant_name: terminalInfo.value?.companyName,
notify_url: 'https://www.baidu.com'
}, true);
getApp().globalData?.logger?.info('order-coupon-confirm: buildSqbParams before sign: ', params);
const paramsSign = {
...params,
sign: hexMD5(parseParameter(params) + '&key=' + terminalInfo.value?.terminalKey).toUpperCase()
};
getApp().globalData?.logger?.info('order-coupon-confirm: buildSqbParams after sign: ', paramsSign);
return paramsSign;
});
const navigateTo = (e: any) => {
handlePayResult(orderBean.value?.id, e, {
onSuccess: (options: any) => {
showToast('支付成功', {
icon: 'success',
complete: () => {
// delete orderBean.value && orderBean.value!.createTime;
couponPay({
...orderBean.value,
payResult: JSON.stringify(options),
status: 2
}).then(res => {
uni.navigateBack();
});
uni.navigateBack();
}
});
},
onFailure: (e: any) => {
getApp().globalData?.logger?.error('coupon pay failure params: ', buildSqbParams.value, e);
uni.showToast({
title: e,
icon: 'none',
duration: 1500,
complete(result) {
if(e?.includes('订单号重复')) {
createOrder();
}
}
});
}
});
};
const createOrder = () => {
if(!terminalInfo.value) {
showToast('当前店铺未配置收款渠道,请联系商家');
return;
}
const params = {
id: groupBuyBean.value?.id,
cash: totalPrice.value,
num: goodsCount.value,
memberId: userInfo.value.id,
payBo: {
terminal_sn: terminalInfo.value?.terminalSn,
terminal_key: terminalInfo.value?.terminalKey,
merchant_name: userInfo.value.companyName,
total_amount: totalPrice.value,
subject: groupBuyBean.value?.name || '微信团购券',
description: groupBuyBean.value?.title || '微信团购券',
subject_img: (imageList.value?.length > 0 && imageList.value[0]) || '',
device_id: groupBuyBean.value?.creatorId,
return_url: '/pages/payResult/index'
}
};
preOrder(params).then(res => {
orderBean.value = res as any;
if(orderBean.value) {
orderBean.value!.clientSn = res?.id;
}
}).catch(err => {
getApp().globalData?.logger?.error('order-coupon-confirm: preOrder exception ', err);
});
};
const payment = () => {
};
</script>
<style lang='scss' scoped>
.content {
.card-view:nth-of-type(1) {
margin-top: 30rpx;
}
}
.card-view {
display: flex;
flex-direction: row;
margin: 10rpx 30rpx;
background: #FFFFFF;
font-size: 35rpx;
padding: 30rpx;
.goods-image {
display: flex;
width: 130rpx;
height: 130rpx;
margin-right: 15rpx;
border-radius: 8rpx;
}
.goods-name {
display: flex;
font-size: 35rpx;
font-weight: bold;
color: #333333;
margin-left: 10rpx;
}
.date {
font-size: 30rpx;
color: #999999;
margin-left: 10rpx;
margin-top: 10rpx;
}
.goods-price {
display: flex;
font-size: 30rpx;
margin-right: 10rpx;
justify-content: flex-end;
color: #333333;
}
.count-change-view {
.count-image {
display: flex;
align-items: center;
justify-content: center;
width: 54rpx;
height: 54rpx;
background: #FBFBFB;
image {
width: 15rpx;
height: 2rpx;
}
}
.count-image:nth-of-type(2) image {
width: 17rpx;
height: 17rpx;
}
text {
display: flex;
width: 54rpx;
height: 54rpx;
align-items: center;
justify-content: center;
font-weight: 400;
font-size: 30rpx;
color: #333333;
background: #F2F2F2;
}
}
}
.bottom-view {
background: #FFFFFF;
padding: 20rpx 30rpx 78rpx 33rpx;
position: fixed;
left: 0;
right: 0;
bottom: 0;
sqb-pay {
flex: 1;
.confirm-button {
display: flex;
flex: 1;
font-weight: bold;
width: 100%;
font-size: 30rpx;
height: 80rpx;
align-items: center;
justify-content: center;
background: #F32B2B;
color: #FFFFFF;
border-radius: 40rpx;
}
}
}
</style>

View File

@ -24,31 +24,58 @@
</template>
<script setup lang='ts'>
import { getCompanyList } from '@/api/company';
import { useUserStore } from '@/store';
import { assetsUrl } from '@/utils/assets';
import { getRegisterStoreId, showToast } from '@/utils';
import { getCompanyId, getOpenId, goPath, showToast } from '@/utils';
const userStore = useUserStore();
const { userInfo } = storeToRefs(userStore);
const isAgreePrivacy = ref(false);
async function wechatLogin() {
function wechatLogin() {
if(!isAgreePrivacy.value) {
showToast('请先阅读并同意小程序隐私保护协议');
return;
}
userStore.login().then(() => {
uni.showLoading();
userStore.login().then(async () => {
const maOpenId = getOpenId() || userInfo.value?.maOpenId;
const data = await getCompanyList(maOpenId);
const companyList = data.map((item: any) => item.company);
uni.hideLoading();
uni.reLaunch({ url: '/pages/home/index' });
//
let index = companyList.findIndex((res: {
id: string
}) => res.id === (getApp()?.globalData?.shareCompanyId || getCompanyId()));
if(index < 0) {
uni.showModal({
title: '提示',
content: '当前店铺还未注册,请先注册',
showCancel: true,
success: (res) => {
if(res.confirm) {
goPath('/pages/common/register/index');
} else {
goPath('/pages/home/index');
}
}
});
return;
}
if(getApp()?.globalData && getApp()?.globalData?.sharePath) {
uni.reLaunch({
url: getApp()?.globalData?.sharePath,
onSuccess: () => {
getApp().globalData!.sharePath = '';
}
});
} else {
uni.reLaunch({ url: '/pages/home/index' });
}
});
// await uni.showLoading();
// const result = await userStore.login();
// uni.hideLoading();
// if(result) {
// await uni.reLaunch({ url: '/pages/home/index' });
// } else {
// await uni.navigateTo({ url: '/pages/common/register/index' });
// }
}
const bindCheck = () => {

View File

@ -114,13 +114,18 @@ const save = async () => {
return;
}
if(!telephone.value) {
showToast('请输入手机号');
return;
}
await uni.showLoading();
const registerForm = {
image: avatarUrl.value,
avatarUrl: avatarUrl.value,
nickName: nickName.value,
telephone: telephone.value,
birthday: dayjs(birthday.value).format('YYYY-MM-DD HH:mm:ss'),
birthday: dayjs(birthday.value).isValid() ? dayjs(birthday.value).format('YYYY-MM-DD HH:mm:ss') : dayjs().format('YYYY-MM-DD HH:mm:ss'),
gender: gender.value
};
@ -129,9 +134,18 @@ const save = async () => {
getApp().globalData?.logger.info('register params: ', registerForm);
if(result) {
showToast('注册成功');
await uni.reLaunch({
url: '/pages/home/index'
});
if(getApp()?.globalData && getApp()?.globalData?.sharePath) {
uni.reLaunch({
url: getApp()?.globalData?.sharePath,
onSuccess: () => {
getApp().globalData!.sharePath = '';
}
});
} else {
await uni.reLaunch({
url: '/pages/home/index'
});
}
}
uni.hideLoading();
};

View File

@ -0,0 +1,52 @@
<template>
</template>
<script lang='ts' setup>
import { getStoreId } from '@/api/company';
import { isLogin, setCompanyId, setRegisterStoreId } from '@/utils';
onLoad(async (options) => {
getApp().globalData?.logger?.info('ticketsBuy share options: ', options);
let couponId = options?.couponsId;
if(couponId) {
const path = `/pages/common/groupbuy/detail?couponId=${couponId}`;
if(!isLogin() && getApp()?.globalData) {
getApp().globalData!.sharePath = path;
}
if(options?.companyId && options?.creatorId) {
const storeId = await getStoreId({
companyid: options?.companyId,
deviceid: options?.creatorId
});
setCompanyId(options?.companyId);
if(storeId) {
setRegisterStoreId(storeId);
if(getApp()?.globalData) {
getApp().globalData!.shareCompanyId = options?.companyId;
getApp().globalData!.shareStoreId = storeId;
}
}
}
setTimeout(() => {
uni.reLaunch({
url: path
});
}, 300);
} else {
uni.reLaunch({
url: '/pages/home/index'
});
}
});
</script>
<style lang='scss' scoped>
</style>

View File

@ -14,15 +14,15 @@
</view>
</view>
<view class='user-info-card' @click.stop='goPath("/pages/mine/index")'>
<view class='user-info-card' @click.stop='goPath("/pages/mine/index",true)'>
<image class='user-avatar' :src='userInfo?.image||defaultAvatar' mode='aspectFill' />
<text class='user-name primary-text-color'>{{ userInfo?.nickName || '点击注册会员' }}</text>
<view class='integral-view primary-text-color' @click.stop='goPath("/pages/mine/subs/integral/index")'>
<view class='integral-view primary-text-color' @click.stop='goPath("/pages/mine/subs/integral/index",true)'>
<text>{{ userInfo?.integration || 0 }}</text>
<text>积分</text>
</view>
<view class='divider' style='height: 83rpx' />
<view class='balance-view' @click.stop='goPath("/pages/mine/subs/recharge/index")'>
<view class='balance-view' @click.stop='goPath("/pages/mine/subs/recharge/index",true)'>
<text class='accent-text-color'>{{ userInfo?.balance || 0 }}</text>
<text>余额()</text>
</view>
@ -33,12 +33,12 @@
</view>
<view class='menu-view'>
<view @click.stop='goPath("/pages/mine/subs/recharge/index")'>
<view @click.stop='goPath("/pages/mine/subs/recharge/index",true)'>
<image :src='assetsUrl("ic_member_card2.png")' style='width: 108rpx;height: 72rpx;padding: 11rpx 0' />
<text>会员充值</text>
</view>
<view class='divider' style='margin: 0;height: 153rpx' />
<view @click.stop='goPath("/pages/mine/subs/coupon/index")'>
<view @click.stop='goPath("/pages/mine/subs/coupon/index",true)'>
<image :src='assetsUrl("ic_coupon2.png")' style='width: 108rpx;height: 95rpx' />
<text>优惠券</text>
</view>
@ -87,6 +87,10 @@ const submenuList = [
icon: assetsUrl('ic_register_gift2.png'),
path: '/pages/common/register/reward'
// path: '/pages/common/register/index'
// path: '/pages/common/groupbuy/detail?id=1800768359753097217'
// path: '/pages/common/groupbuy/detail?shareId=1797548579864748033'
// path: '/pages/coupons/ticketsBuy/ticketsBuy?couponsId=1800381015472513026'
//1799264392762138626
},
{
title: '团购秒杀',
@ -150,7 +154,7 @@ const switchCompany = () => {
userStore.setUserInfo(userList[index]);
userStore.setCompanyInfo(companyList[index]);
avatarModifyRemind();
// avatarModifyRemind();
});
});
};
@ -175,34 +179,56 @@ function avatarModifyRemind() {
const fetchCompanyList = (fn: any = undefined) => {
const maOpenId = getOpenId() || userInfo.value?.maOpenId || (userList.value.filter((res: UserBean) => res?.maOpenId !== '')[0]?.maOpenId);
getCompanyList(maOpenId).then(res => {
companyList.value = res.map((res: { company: any }) => res.company);
userList.value = res.map((res: { user: any }) => res.user);
companyList.value = res.map((res: { company: any }) => res.company);
userList.value = res.map((res: { user: any }) => res.user);
if(companyList.value.length === 0) {
uni.showModal({
title: '提示',
content: '当前店铺还未注册,请先注册',
showCancel: true,
success: (res) => {
if(res.confirm) {
goPath('/pages/common/register/index');
}
}
});
return;
}
if(fn != undefined && fn instanceof Function) {
fn(companyList.value, userList.value);
} else {
let index = companyList.value.findIndex((res: { id: string }) => res.id === getApp().globalData?.companyId);
//
if(index < 0 && !getApp()?.globalData?.storeId) {
goPath('/pages/common/register/index');
if(companyList.value.length === 0) {
showRegisterModal();
return;
}
userStore.setUserInfo(userList.value[index]);
userStore.setCompanyInfo(companyList.value[index]);
avatarModifyRemind();
if(fn != undefined && fn instanceof Function) {
fn(companyList.value, userList.value);
} else {
let index = companyList.value.findIndex((res: { id: string }) => res.id === getApp()?.globalData?.companyId);
//
if(index < 0) {
showRegisterModal();
return;
}
//idid
if(getApp()?.globalData?.shareCompanyId && getApp()?.globalData?.shareStoreId) {
index = companyList.value.findIndex((res: { id: string }) => res.id === getApp().globalData?.shareCompanyId);
if(index < 0) {
showRegisterModal();
return;
}
}
userStore.setUserInfo(userList.value[index]);
userStore.setCompanyInfo(companyList.value[index]);
// avatarModifyRemind();
//
if(getApp()?.globalData?.shareCompanyId && getApp()?.globalData?.shareStoreId) {
getApp().globalData!.shareCompanyI = '';
getApp().globalData!.shareStoreId = '';
}
}
}
);
};
const showRegisterModal = () => {
uni.showModal({
title: '提示',
content: '当前店铺还未注册,请先注册',
showCancel: true,
success: (res) => {
if(res.confirm) {
goPath('/pages/common/register/index');
}
}
});
};

View File

@ -3,10 +3,51 @@
</template>
<script lang='ts' setup>
onMounted(() => {
uni.reLaunch({
url: '/pages/home/index'
});
import { isLogin, setCompanyId, setRegisterStoreId } from '@/utils';
import { getStoreId } from '@/api/company';
onLoad(async (options) => {
getApp().globalData?.logger?.info('app share index/index options: ', options);
if(options?.companyId) {
setCompanyId(options?.companyId);
let storeId = options?.storeId || await getStoreId({
companyid: options?.companyId,
deviceid: options?.creatorId
});
if(storeId) {
setRegisterStoreId(storeId);
}
if(getApp()?.globalData) {
getApp().globalData!.shareCompanyId = options?.companyId;
getApp().globalData!.shareStoreId = storeId;
}
}
let goodsShareId = '';
if(options?.shareId) {
goodsShareId = options?.shareId;
}
getApp().globalData?.logger?.info('app share index/index options: goodsShareId ', goodsShareId);
if(goodsShareId) {
const path = `/pages/common/groupbuy/detail?shareId=${goodsShareId}`;
if(!isLogin() && getApp()?.globalData) {
getApp().globalData!.sharePath = path;
}
setTimeout(() => {
uni.reLaunch({
url: path
});
}, 300);
} else {
uni.reLaunch({
url: '/pages/home/index'
});
}
});
</script>

View File

@ -50,7 +50,7 @@
import { onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app';
import SkuDialog from '@/components/sku-dialog.vue';
import { assetsUrl, defaultImage } from '@/utils/assets';
import { goLogin, goPath, isLogin, showToast } from '@/utils';
import { goPath, isLogin, showToast } from '@/utils';
import { getCategoryList, getGoodsList } from '@/api/goods';
import { CategoryBean, GoodsBean } from '@/api/goods/types';
import useShoppingCartStore from '@/store/modules/shoppingcart';
@ -69,7 +69,6 @@ const currentPageNum = ref<number>(1);
onLoad(() => {
if(!isLogin()) {
goLogin();
return;
}

View File

@ -163,7 +163,7 @@ const buildSqbParams = computed(() => {
total_amount: Number(((totalPrice.value || 0) * 100).toFixed(2)),
terminal_sn: terminalInfo.value?.terminalSn,
subject: orderBean?.value?.orderGoods[0].name || '未知',
subject_img: orderBean?.value?.orderGoods[0].images || '',
subject_img: orderBean?.value?.orderGoods[0].images || 'xxx',
merchant_name: terminalInfo.value?.companyName,
notify_url: 'https://www.baidu.com'
}, true);
@ -188,12 +188,12 @@ const confirmCoupon = (item: CouponBean) => {
};
const navigateTo = (e: any) => {
handlePayResult(orderBean.value?.id, e, {
onSuccess: () => {
onSuccess: (options:any) => {
console.log('pay success');
payment();
},
onFailure: () => {
console.error('pay onFailure');
onFailure: (e:any) => {
console.error('pay onFailure ',e);
if(orderBean.value?.id) {
orderBean.value.id = '';
}

View File

@ -59,8 +59,11 @@
<text>{{ item.title }}</text>
</view>
</view>
</view>
</view>
<!-- 支付密码设置弹框 -->
<pay-password-dialog ref="payPasswordDialogRef" />
<official-account-dialog ref='officialAccountDialogRef' />
</template>
@ -71,10 +74,12 @@ import { isPending } from '@/utils/order';
import { getCardLink } from '@/api/user';
import { getOrderList } from '@/api/order';
import OfficialAccountDialog from '@/components/official-account-dialog.vue';
import PayPasswordDialog from '@/components/pay-password-dialog.vue';
import { useUserStore } from '@/store';
const userStore = useUserStore();
const officialAccountDialogRef = ref();
const payPasswordDialogRef = ref<any>(null);
const orderActionList = ref([{
title: '未支付',
@ -114,6 +119,11 @@ const serviceList = [
title: '联系商家',
icon: assetsUrl('ic_member_service_contact.png'),
path: '/pages/mine/subs/contact/index'
},
{
title: '支付密码',
icon: '/static/images/ic_member_pay_password.png',
path: 'pay_password'
}
// ,{
// title: '广',
@ -129,22 +139,24 @@ const cardLink = ref('');
const unPaidOrderCount = ref(0);
onLoad(() => {
if(!isLogin()) {
goLogin();
return;
}
// if(!isLogin()) {
// goLogin();
// return;
// }
});
onShow(async () => {
const { list } = await getOrderList({
pageNum: 1,
pageSize: 9999,
obj: { payStatus: 1 }
});
unPaidOrderCount.value = list.filter((item: any) => isPending(item))?.length || 0;
const { cardurl } = await getCardLink();
cardLink.value = cardurl;
await userStore.getProfile();
if(isLogin()) {
const { list } = await getOrderList({
pageNum: 1,
pageSize: 9999,
obj: { payStatus: 1 }
});
unPaidOrderCount.value = list.filter((item: any) => isPending(item))?.length || 0;
const { cardurl } = await getCardLink();
cardLink.value = cardurl;
await userStore.getProfile();
}
});
const openCard = () => {
@ -161,9 +173,19 @@ const openCard = () => {
// });
};
const showOfficialAccountDialog = () => {
officialAccountDialogRef.value.show();
};
const showPayPasswordDialog = () => {
payPasswordDialogRef.value?.show();
};
const gotoPath = (path: string) => {
if(path === 'follow_official_account') {
showOfficialAccountDialog();
} else if(path === 'pay_password') {
showPayPasswordDialog();
} else if(path === 'qrcode') {
uni.switchTab({
url: '/pages/qrcode/index'
@ -173,13 +195,9 @@ const gotoPath = (path: string) => {
phoneNumber: companyInfo.value.telphone
});
} else {
goPath(path);
goPath(path, true);
}
};
const showOfficialAccountDialog = () => {
officialAccountDialogRef.value.show();
};
</script>
<style lang='scss' scoped>

View File

@ -9,7 +9,7 @@
<view class='right-content accent-text-color' :class='{"right-content-disabled": item?.status!=0}'>
<text>{{ item?.name }}</text>
<text>有效期至{{ dayjs(item?.startTime).format('YYYY-MM-DD') }}</text>
<text>有效期至{{ dayjs(item?.endTime).format('YYYY-MM-DD') }}</text>
<text class='btn-text' :class='{"btn-text-disabled": item?.status!=0}' @click.stop='goPath("/pages/mall/index")'>
立即使用
</text>
@ -80,7 +80,7 @@ defineProps({
position: relative;
flex: 1;
justify-content: center;
margin-left: 60rpx;
margin-left: 65rpx;
text:nth-of-type(1) {
font-size: 30rpx;

View File

@ -178,7 +178,7 @@ const buildSqbParams = computed(() => {
const navigateTo = (e: any) => {
handlePayResult(orderBean.value?.order.id, e, {
onSuccess: () => {
onSuccess: (options:any) => {
fetchData(orderBean.value?.order.id || '');
}
});

View File

@ -80,7 +80,7 @@ const params = ref<{
nickName: userInfo.value.nickName,
telephone: userInfo.value.telephone,
gender: userInfo.value.gender,
birthday: userInfo.value.birthday
birthday: userInfo.value.birthday || dayjs().format('YYYY-MM-DD')
});
onLoad(() => {
@ -135,7 +135,7 @@ const save = async () => {
const result = await updateProfile({
...params.value,
birthday: dayjs(params.value.birthday).format('YYYY-MM-DD HH:mm:ss'),
birthday: dayjs(params.value.birthday).isValid() ? dayjs(params.value.birthday).format('YYYY-MM-DD HH:mm:ss') : dayjs().format('YYYY-MM-DD HH:mm:ss'),
birthdayType: 0
});

View File

@ -120,7 +120,7 @@ const buildSqbParams = computed(() => {
const navigateTo = (e: any) => {
handlePayResult(preRechargeOrderId.value, e, {
onSuccess: async () => {
onSuccess: async (options: any) => {
await goRecharge();
await userState.setUserInfo({
...userInfo.value,
@ -128,7 +128,7 @@ const navigateTo = (e: any) => {
});
await uni.navigateBack();
},
onFailure: () => {
onFailure: (e: any) => {
}
});
};

View File

@ -11,7 +11,7 @@
<view class='qrcode-card'>
<view class='balance-view'>
<text class='balance-text'>账户余额{{ userInfo?.balance || 0 }}</text>
<view class='btn-recharge' @click.stop='goPath("/pages/mine/subs/recharge/index")'>
<view class='btn-recharge' @click.stop='goPath("/pages/mine/subs/recharge/index",true)'>
<text>去充值</text>
<image :src='assetsUrl("ic_arrow_right.png")' />
</view>
@ -33,10 +33,9 @@
<text>卡信息</text>
</view>
<text>店铺名称{{ userInfo?.creatorName }}</text>
<text>{{ getStoreName() }}</text>
<text>{{ userInfo?.storeId }}</text>
</view>
</view>
</view>
</template>
@ -47,7 +46,7 @@ import { assetsUrl } from '@/utils/assets';
import { generateBarCode, generateQrCode } from '@/api/common';
import { getDynamicCode } from '@/api/user';
import { useUserStore } from '@/store';
import { goLogin, goPath, isLogin } from '@/utils';
import { goPath, isLogin } from '@/utils';
const store = useUserStore();
const { userInfo } = storeToRefs(store);
@ -58,7 +57,7 @@ const codeRefreshInterval = ref(30);
onLoad(() => {
if(!isLogin()) {
goLogin();
// goLogin();
return;
}
generateCode();
@ -72,6 +71,10 @@ onLoad(() => {
}, 1000);
});
const getStoreName = () => {
return `${userInfo.value?.nickName || userInfo.value?.name}${userInfo.value?.storeName || userInfo.value?.companyName || userInfo.value?.creatorName}`;
};
const generateCode = async () => {
const { dynccode } = await getDynamicCode();
codeContent.value = dynccode;

View File

@ -0,0 +1,28 @@
<template>
<view class="user-page">
<!-- 其他现有内容 -->
<!-- 在联系商家后面添加支付密码设置入口 -->
<u-cell-group>
<!-- 现有的联系商家单元格 -->
<u-cell
title="支付密码"
is-link
@click="navigateToPayPassword"
/>
</u-cell-group>
<!-- 其他现有内容 -->
</view>
</template>
<script setup lang="ts">
// ... ...
//
const navigateToPayPassword = () => {
uni.navigateTo({
url: '/pages/common/pay-password/index'
})
}
</script>

View File

@ -25,11 +25,12 @@ list.forEach((item) => {
return true;
}
else {
if (checkWhite(to.url))
return true;
uni.reLaunch({ url: loginPage });
return false;
// if (checkWhite(to.url))
// return true;
//
// uni.reLaunch({ url: loginPage });
// return false;
return true;
}
},
fail(err) {

View File

@ -1,6 +1,6 @@
{
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"projectname": "肃客会员",
"projectname": "VIP顾客中心",
"setting": {
"compileHotReLoad": true
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -76,4 +76,17 @@ page {
justify-content: center;
min-width: 80%;
color: #FFFFFF;
border: none !important;
outline: none;
&::after {
display: none;
}
}
.disabled-button {
@extend .primary-button;
background: #cccccc;
&::after {
display: none;
}
}

View File

@ -10,8 +10,9 @@ import {
setSessionKey,
setToken
} from '@/utils/auth';
import type { RegisterParams, TerminalBean } from '@/api/user/types';
import type { RegisterParams, TerminalBean,SetPayPasswordParams } from '@/api/user/types';
import { getCompanyInfo } from '@/api/company';
import { setPayPassword } from '@/api/user'
const useUserStore = defineStore('user', {
state: () => ({
@ -36,7 +37,7 @@ const useUserStore = defineStore('user', {
mobile: '',
addr: '',
defaultstatus: 0
}
},
}),
persist: {
@ -93,16 +94,13 @@ const useUserStore = defineStore('user', {
// referrerUserId: getReferrerUserId()
});
getApp().globalData?.logger.info('login result: ', res);
console.log('login result: ', res);
console.log('login result: ', res.token);
console.log('login result: ', res.sessionKey);
setToken(res.token);
setSessionKey(res.sessionKey);
setOpenId(res.maOpenId);
if(res.user){
await this.setUserInfo(res.user);
}else {
this.setUserInfo(res.userInfo)
if(res.user) {
this.setUserInfo(res.user);
} else {
this.setUserInfo(res.userInfo);
}
// }
resolve(res);
@ -133,9 +131,9 @@ const useUserStore = defineStore('user', {
unionId: this.userInfo.unionId,
openId: this.userInfo.openId,
maOpenId: this.userInfo.maOpenId,
companyId: getCompanyId(),
companyId: getApp()?.globalData?.shareCompanyId || getCompanyId(),
creatorId: this.userInfo.creatorId,
storeId: getRegisterStoreId()
storeId: getApp()?.globalData?.shareStoreId || getRegisterStoreId()
} as RegisterParams;
return new Promise(async (resolve, reject) => {
try {
@ -155,17 +153,21 @@ const useUserStore = defineStore('user', {
if(this.userInfo) {
this.userInfo.userDiscount = this.getUserDiscount;
await setCompanyId(this.userInfo.companyId);
getApp().globalData!.companyId = this.userInfo.companyId;
if(getApp().globalData) {
getApp().globalData!.companyId = this.userInfo.companyId;
}
this.fetchTerminal(this.userInfo?.companyId);
this.fetchCompanyInfo();
} else {
await clearToken();
}
this.fetchTerminal();
this.fetchCompanyInfo();
},
setCompanyInfo(partial: Partial<any>) {
this.companyInfo = partial as any;
getApp().globalData!.companyId = this.companyInfo.id;
if(getApp()?.globalData) {
getApp().globalData!.companyId = this.companyInfo.id;
}
},
setDeliveryAddress(partial: Partial<any>) {
@ -182,8 +184,8 @@ const useUserStore = defineStore('user', {
this.companyConfigInfo = await getCompanyInfo();
},
async fetchTerminal() {
this.terminalInfo = await getTerminal(this.userInfo?.companyId);
async fetchTerminal(companyId: string = '') {
this.terminalInfo = await getTerminal(companyId || this.userInfo.companyId);
},
// 重置用户信息
@ -196,8 +198,18 @@ const useUserStore = defineStore('user', {
await userLogout();
this.resetInfo();
clearToken();
}
},
// 设置支付密码
async setPayPassword(params: SetPayPasswordParams) {
const res = await setPayPassword(params)
if (res.success) {
this.userInfo.paywithpwd = 1
return true
}
return false
},
}
});
export default useUserStore;

View File

@ -9,11 +9,12 @@ export interface UserBean {
birthdayType: number;
card: string;
companyId: string;
companyName: string;
consumption: string;
consumptionDay: string;
couponsCount: number;
createTime: string;
creatorId: string;
creatorId: string;
creatorName: string;
customerPrice: string;
email: string;
@ -42,6 +43,7 @@ export interface UserBean {
source: string;
status: string;
storeId: string;
storeName: string;
telephone: string;
totalConsumption: string;
totalIncoming: number;
@ -50,7 +52,8 @@ export interface UserBean {
updateTime: string;
useCouponsPrice: number;
wirelinedTelephone: string;
userDiscount:number
userDiscount: number;
paywithpwd: number;
}
export type providerType =

View File

@ -40,9 +40,11 @@ function getCompanyId() {
}
function setCompanyId(companyId: string) {
uni.setStorageSync(CompanyIdKey, companyId);
if(getApp()?.globalData) {
getApp().globalData!.companyId = companyId;
if(companyId) {
uni.setStorageSync(CompanyIdKey, companyId);
if(getApp()?.globalData) {
getApp().globalData!.companyId = companyId;
}
}
}

View File

@ -1,5 +1,7 @@
// 小程序更新检测
import { isLogin } from '@/utils';
export function mpUpdate() {
const updateManager = uni.getUpdateManager();
updateManager.onCheckForUpdate((res) => {
@ -50,7 +52,20 @@ export function showToast(title: string, { icon, duration, complete }: ToastOpti
});
}
export function goPath(path: string) {
export function goPath(path: string, needAuth: boolean = false) {
if(needAuth && !isLogin()) {
uni.showModal({
title: '提示',
content: '您还未登录,请先登录',
showCancel: true,
success: (res) => {
if(res.confirm) {
goLogin();
}
}
});
return;
}
if(path.includes('home/index') || path.includes('mall/index') || path.includes('qrcode/index') || path.includes('mine/index')) {
uni.switchTab({
url: path
@ -64,11 +79,17 @@ export function goPath(path: string) {
}
}
export function goLogin() {
uni.navigateTo({
url: '/pages/common/login/index'
}).then(r => {
});
export function goLogin(reLaunch: boolean = false) {
const path = '/pages/common/login/index';
if(reLaunch) {
uni.reLaunch({
url: path
}).then();
} else {
uni.navigateTo({
url: path
}).then();
}
}
export function formatTimeWithZeroPad(num: number): string {
@ -117,3 +138,9 @@ export function copy(content: string) {
}
});
}
export function getQueryParam(queryParams: string, key: string) {
let regex = new RegExp('(?:[?&]|^)' + key + '=([^&]+)'),
match = queryParams.match(regex);
return match && match[1];
}

View File

@ -34,8 +34,9 @@ export const handlePayResult = (orderId: string | undefined, e: any, { onSuccess
const resultObj = JSON.parse(str.replaceAll('result=', ''));
if(resultObj?.is_success === true) {
getApp().globalData?.logger?.info('pay success : ', orderId, resultObj);
if(onSuccess) {
onSuccess();
onSuccess(resultObj);
} else {
showToast('支付成功', {
icon: 'success',
@ -45,14 +46,23 @@ export const handlePayResult = (orderId: string | undefined, e: any, { onSuccess
});
}
} else {
if(onFailure) {
onFailure();
getApp().globalData?.logger?.error('pay failure :', orderId, str, resultObj);
let msg = '支付失败';
if(resultObj) {
msg = resultObj?.error_message || '支付失败';
} else {
msg = JSON.parse(str)?.error_message || '支付失败';
}
if(onFailure) {
onFailure(msg);
} else {
showToast(msg, {
complete: () => {
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
});
}
const msg = resultObj?.error_message || '支付失败';
showToast(msg, {
complete: () => {
uni.navigateBack();
}
});
}
};

View File

@ -1,5 +1,5 @@
import type { HttpError, HttpRequestConfig, HttpResponse } from 'uview-plus/libs/luch-request';
import { getToken } from '@/utils/auth';
import { getCompanyId, getToken } from '@/utils/auth';
import { showMessage } from '@/utils/request/status';
import { useUserStore } from '@/store';
@ -22,11 +22,11 @@ function requestInterceptors() {
const token = getToken();
if(token && config.header) {
config.header.token = token;
config.header.companyid = getApp().globalData?.companyId;
config.header.companyid = getCompanyId();
// config.header.contentType = "x-www-form-urlencoded"
}
getApp().globalData?.logger.info('request: ', config);
// getApp().globalData?.logger.info('request: ', config);
return config;
},
(
@ -53,7 +53,10 @@ function responseInterceptors() {
return data;
}
getApp().globalData?.logger.info('response: ', data);
getApp().globalData?.logger.info(response.config.url, {
'request': response.config,
'response': data
});
// 请求成功则返回结果
if(data.code === 200 || data?.retcode == 0) {
@ -61,7 +64,7 @@ function responseInterceptors() {
}
// 登录状态失效,重新登录
if(data.code === 4011) {
if(data?.code === 401 || data?.code === 4011 || data?.retcode === 4011) {
// 是否在获取token中,防止重复获取
if(!isRefreshing) {
// 修改登录状态为true
@ -86,7 +89,14 @@ function responseInterceptors() {
// 如果没有显式定义custom的toast参数为false的话默认对报错进行toast弹出提示
if(custom?.toast !== false) {
uni.$u.toast(data.message || data.retinfo);
if(data?.retinfo?.includes('未登录')
|| data?.retinfo?.includes('未登陆')
|| data.message?.includes('未登录')
|| data.message?.includes('未登陆')) {
getApp()?.globalData?.logger.error('未登录');
} else {
uni.$u.toast(data.message || data.retinfo);
}
}
// 如果需要catch返回则进行reject

View File

@ -28,10 +28,6 @@
"types/**/*.d.ts",
"types/**/*.ts"
],
"exclude": ["dist", "node_modules", "uni_modules"],
// uni-app Component type prompt
"vueCompilerOptions": {
"nativeTags": ["block", "component", "template", "slot"]
}
"exclude": ["dist", "node_modules", "uni_modules"]
}

View File

@ -12,6 +12,7 @@ declare module 'vue' {
PageNav: typeof import('./../src/components/page-nav/page-nav.vue')['default']
PaymentButton: typeof import('./../src/components/payment-button.vue')['default']
PaymentDialog: typeof import('./../src/components/payment-dialog.vue')['default']
PayPasswordDialog: typeof import('./../src/components/pay-password-dialog.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SkuDialog: typeof import('./../src/components/sku-dialog.vue')['default']