feat(user): 添加支付密码设置功能

This commit is contained in:
Waiting 2025-01-19 14:34:45 +08:00
parent de509c7e14
commit e16e1e3bdc
12 changed files with 350 additions and 17 deletions

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,9 @@ 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',
payPasswordStatus = '/user/pay-password/status',
}
export const getUserProfile = () => get<UserBean>({ url: URL.profile });
@ -76,3 +78,18 @@ 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
});
/**
*
*/
export const getPayPasswordStatus = () => get<{ hasPassword: boolean }>({
url: URL.payPasswordStatus
});

View File

@ -118,3 +118,14 @@ export interface TerminalBean {
token: string;
type: number;
}
export interface SetPayPasswordParams {
paywithpwd: number
oldpwd: string,
newpwd: string
}
export interface PayPasswordResponse {
success: boolean
message: string
}

View File

@ -0,0 +1,240 @@
<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">设置支付密码</text>
<u-icon name="close" size="20" color="#999" @click="hide" />
</view>
<view class="form-container">
<!-- 旧密码 -->
<view class="form-item">
<text class="label">旧密码</text>
<view class="input-wrapper">
<u-input
v-model="oldPassword"
:type="showOldPassword ? 'text' : 'password'"
placeholder="请输入旧密码"
:maxlength="6"
:border="false"
fontSize="28rpx"
/>
<u-icon
:name="showOldPassword ? 'eye-fill' : 'eye-off'"
size="22"
color="#999"
@click="showOldPassword = !showOldPassword"
/>
</view>
</view>
<!-- 新密码 -->
<view class="form-item">
<text class="label">新密码</text>
<view class="input-wrapper">
<u-input
v-model="newPassword"
:type="showNewPassword ? 'text' : 'password'"
placeholder="请输入6位数字密码"
maxlength="6"
:border="false"
fontSize="28rpx"
@input="validateInput"
/>
<u-icon
:name="showNewPassword ? 'eye-fill' : 'eye-off'"
size="22"
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="showConfirmPassword ? 'text' : 'password'"
placeholder="请再次输入密码"
maxlength="6"
:border="false"
fontSize="28rpx"
@input="validateInput"
/>
<u-icon
:name="showConfirmPassword ? 'eye-fill' : 'eye-off'"
size="22"
color="#999"
@click="showConfirmPassword = !showConfirmPassword"
/>
</view>
</view>
</view>
<view class="footer">
<button
:class="{'primary-button': isValid, 'disabled-button': !isValid}"
:disabled="!isValid"
@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 oldPassword = ref('')
const newPassword = ref('')
const confirmPassword = ref('')
//
const hasOldPassword = computed(() => userStore.userInfo.hasPayPassword)
//
const isValid = computed(() => {
if (!newPassword.value || !confirmPassword.value) return false
if (newPassword.value.length !== 6 || confirmPassword.value.length !== 6) return false
return newPassword.value === confirmPassword.value
})
//
const validateInput = (value: string) => {
const numericValue = value.replace(/\D/g, '')
if (value !== numericValue) {
newPassword.value = numericValue
confirmPassword.value = numericValue
}
}
//
const resetForm = () => {
oldPassword.value = ''
newPassword.value = ''
confirmPassword.value = ''
showOldPassword.value = false
showNewPassword.value = false
showConfirmPassword.value = false
}
//
const show = () => {
console.log('show pay password dialog')
popup.value?.open('center')
}
//
const hide = () => {
console.log('hide pay password dialog')
popup.value?.close()
resetForm()
}
//
const handleCancel = () => {
hide()
resetForm()
}
//
const handleConfirm = async () => {
try {
await userStore.setPayPassword({
paywithpwd:'0',
oldpwd: oldPassword.value,
newpwd: newPassword.value,
})
uni.showToast({
title: '设置成功',
icon: 'success',
})
hide()
resetForm()
} catch (error) {
uni.showToast({
title: '设置失败',
icon: 'error',
})
}
}
// 使
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 {
.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-input) {
flex: 1;
height: 100%;
}
:deep(.u-input__input) {
height: 100%;
line-height: 60rpx;
}
}
}
}
.footer {
padding: 0 30rpx;
}
}
</style>

View File

@ -18,7 +18,7 @@
"modules": {}
},
"mp-weixin": {
"appid": "wx67a750d0ceed4d88",
"appid": "wx92e663dc11d0c0a8",
"setting": {
"urlCheck": false
},

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: '广',
@ -146,6 +156,7 @@ onShow(async () => {
const { cardurl } = await getCardLink();
cardLink.value = cardurl;
await userStore.getProfile();
await userStore.getPayPasswordStatus();
}
});
@ -163,9 +174,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'
@ -178,10 +199,6 @@ const gotoPath = (path: string) => {
goPath(path, true);
}
};
const showOfficialAccountDialog = () => {
officialAccountDialogRef.value.show();
};
</script>
<style lang='scss' scoped>

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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -77,3 +77,8 @@ page {
min-width: 80%;
color: #FFFFFF;
}
.disabled-button {
@extend .primary-button;
background: #cccccc;
}

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, getPayPasswordStatus } from '@/api/user'
const useUserStore = defineStore('user', {
state: () => ({
@ -36,7 +37,7 @@ const useUserStore = defineStore('user', {
mobile: '',
addr: '',
defaultstatus: 0
}
},
}),
persist: {
@ -197,7 +198,23 @@ const useUserStore = defineStore('user', {
await userLogout();
this.resetInfo();
clearToken();
}
},
// 设置支付密码
async setPayPassword(params: SetPayPasswordParams) {
const res = await setPayPassword(params)
if (res.success) {
this.userInfo.hasPayPassword = true
return true
}
return false
},
// 获取支付密码状态
async getPayPasswordStatus() {
const res = await getPayPasswordStatus()
this.userInfo.hasPayPassword = res.hasPassword
},
}
});

View File

@ -52,7 +52,8 @@ export interface UserBean {
updateTime: string;
useCouponsPrice: number;
wirelinedTelephone: string;
userDiscount:number
userDiscount: number;
hasPayPassword: boolean;
}
export type providerType =

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']