feat(user): 添加支付密码设置功能
This commit is contained in:
parent
de509c7e14
commit
e16e1e3bdc
@ -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 { get, post } from '@/utils/request';
|
||||||
import { UserBean } from '@/store/modules/user/types';
|
import { UserBean } from '@/store/modules/user/types';
|
||||||
|
|
||||||
@ -33,7 +33,9 @@ enum URL {
|
|||||||
tradeList = '/memberIncoming/wx_balance_records',
|
tradeList = '/memberIncoming/wx_balance_records',
|
||||||
terminal = 'wechat/coupons/terminal?companyId=',
|
terminal = 'wechat/coupons/terminal?companyId=',
|
||||||
cardLink = '/wc/wechat/get_card_url',
|
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 });
|
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 getCardLink = () => get<string>({ url: URL.cardLink });
|
||||||
|
|
||||||
export const getRegisterCoupon = () => get<any>({ url: URL.registerCoupon });
|
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
|
||||||
|
});
|
||||||
|
@ -118,3 +118,14 @@ export interface TerminalBean {
|
|||||||
token: string;
|
token: string;
|
||||||
type: number;
|
type: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SetPayPasswordParams {
|
||||||
|
paywithpwd: number
|
||||||
|
oldpwd: string,
|
||||||
|
newpwd: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PayPasswordResponse {
|
||||||
|
success: boolean
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
240
src/components/pay-password-dialog.vue
Normal file
240
src/components/pay-password-dialog.vue
Normal 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>
|
@ -18,7 +18,7 @@
|
|||||||
"modules": {}
|
"modules": {}
|
||||||
},
|
},
|
||||||
"mp-weixin": {
|
"mp-weixin": {
|
||||||
"appid": "wx67a750d0ceed4d88",
|
"appid": "wx92e663dc11d0c0a8",
|
||||||
"setting": {
|
"setting": {
|
||||||
"urlCheck": false
|
"urlCheck": false
|
||||||
},
|
},
|
||||||
|
@ -59,8 +59,11 @@
|
|||||||
<text>{{ item.title }}</text>
|
<text>{{ item.title }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
|
||||||
|
|
||||||
|
|
||||||
|
</view>
|
||||||
|
<!-- 支付密码设置弹框 -->
|
||||||
|
<pay-password-dialog ref="payPasswordDialogRef" />
|
||||||
<official-account-dialog ref='officialAccountDialogRef' />
|
<official-account-dialog ref='officialAccountDialogRef' />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -71,10 +74,12 @@ import { isPending } from '@/utils/order';
|
|||||||
import { getCardLink } from '@/api/user';
|
import { getCardLink } from '@/api/user';
|
||||||
import { getOrderList } from '@/api/order';
|
import { getOrderList } from '@/api/order';
|
||||||
import OfficialAccountDialog from '@/components/official-account-dialog.vue';
|
import OfficialAccountDialog from '@/components/official-account-dialog.vue';
|
||||||
|
import PayPasswordDialog from '@/components/pay-password-dialog.vue';
|
||||||
import { useUserStore } from '@/store';
|
import { useUserStore } from '@/store';
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const officialAccountDialogRef = ref();
|
const officialAccountDialogRef = ref();
|
||||||
|
const payPasswordDialogRef = ref<any>(null);
|
||||||
|
|
||||||
const orderActionList = ref([{
|
const orderActionList = ref([{
|
||||||
title: '未支付',
|
title: '未支付',
|
||||||
@ -114,6 +119,11 @@ const serviceList = [
|
|||||||
title: '联系商家',
|
title: '联系商家',
|
||||||
icon: assetsUrl('ic_member_service_contact.png'),
|
icon: assetsUrl('ic_member_service_contact.png'),
|
||||||
path: '/pages/mine/subs/contact/index'
|
path: '/pages/mine/subs/contact/index'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '支付密码',
|
||||||
|
icon: '/static/images/ic_member_pay_password.png',
|
||||||
|
path: 'pay_password'
|
||||||
}
|
}
|
||||||
// ,{
|
// ,{
|
||||||
// title: '推广中心',
|
// title: '推广中心',
|
||||||
@ -146,6 +156,7 @@ onShow(async () => {
|
|||||||
const { cardurl } = await getCardLink();
|
const { cardurl } = await getCardLink();
|
||||||
cardLink.value = cardurl;
|
cardLink.value = cardurl;
|
||||||
await userStore.getProfile();
|
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) => {
|
const gotoPath = (path: string) => {
|
||||||
if(path === 'follow_official_account') {
|
if(path === 'follow_official_account') {
|
||||||
showOfficialAccountDialog();
|
showOfficialAccountDialog();
|
||||||
|
} else if(path === 'pay_password') {
|
||||||
|
showPayPasswordDialog();
|
||||||
} else if(path === 'qrcode') {
|
} else if(path === 'qrcode') {
|
||||||
uni.switchTab({
|
uni.switchTab({
|
||||||
url: '/pages/qrcode/index'
|
url: '/pages/qrcode/index'
|
||||||
@ -178,10 +199,6 @@ const gotoPath = (path: string) => {
|
|||||||
goPath(path, true);
|
goPath(path, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const showOfficialAccountDialog = () => {
|
|
||||||
officialAccountDialogRef.value.show();
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
|
28
src/pages/tab/user/index.vue
Normal file
28
src/pages/tab/user/index.vue
Normal 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>
|
BIN
src/static/images/ic_member_pay_password.png
Normal file
BIN
src/static/images/ic_member_pay_password.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
@ -77,3 +77,8 @@ page {
|
|||||||
min-width: 80%;
|
min-width: 80%;
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.disabled-button {
|
||||||
|
@extend .primary-button;
|
||||||
|
background: #cccccc;
|
||||||
|
}
|
@ -10,8 +10,9 @@ import {
|
|||||||
setSessionKey,
|
setSessionKey,
|
||||||
setToken
|
setToken
|
||||||
} from '@/utils/auth';
|
} 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 { getCompanyInfo } from '@/api/company';
|
||||||
|
import { setPayPassword, getPayPasswordStatus } from '@/api/user'
|
||||||
|
|
||||||
const useUserStore = defineStore('user', {
|
const useUserStore = defineStore('user', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
@ -36,7 +37,7 @@ const useUserStore = defineStore('user', {
|
|||||||
mobile: '',
|
mobile: '',
|
||||||
addr: '',
|
addr: '',
|
||||||
defaultstatus: 0
|
defaultstatus: 0
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
persist: {
|
persist: {
|
||||||
@ -197,7 +198,23 @@ const useUserStore = defineStore('user', {
|
|||||||
await userLogout();
|
await userLogout();
|
||||||
this.resetInfo();
|
this.resetInfo();
|
||||||
clearToken();
|
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
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -52,7 +52,8 @@ export interface UserBean {
|
|||||||
updateTime: string;
|
updateTime: string;
|
||||||
useCouponsPrice: number;
|
useCouponsPrice: number;
|
||||||
wirelinedTelephone: string;
|
wirelinedTelephone: string;
|
||||||
userDiscount:number
|
userDiscount: number;
|
||||||
|
hasPayPassword: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type providerType =
|
export type providerType =
|
||||||
|
@ -28,10 +28,6 @@
|
|||||||
"types/**/*.d.ts",
|
"types/**/*.d.ts",
|
||||||
"types/**/*.ts"
|
"types/**/*.ts"
|
||||||
],
|
],
|
||||||
"exclude": ["dist", "node_modules", "uni_modules"],
|
"exclude": ["dist", "node_modules", "uni_modules"]
|
||||||
// uni-app Component type prompt
|
|
||||||
"vueCompilerOptions": {
|
|
||||||
"nativeTags": ["block", "component", "template", "slot"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
types/components.d.ts
vendored
1
types/components.d.ts
vendored
@ -12,6 +12,7 @@ declare module 'vue' {
|
|||||||
PageNav: typeof import('./../src/components/page-nav/page-nav.vue')['default']
|
PageNav: typeof import('./../src/components/page-nav/page-nav.vue')['default']
|
||||||
PaymentButton: typeof import('./../src/components/payment-button.vue')['default']
|
PaymentButton: typeof import('./../src/components/payment-button.vue')['default']
|
||||||
PaymentDialog: typeof import('./../src/components/payment-dialog.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']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
SkuDialog: typeof import('./../src/components/sku-dialog.vue')['default']
|
SkuDialog: typeof import('./../src/components/sku-dialog.vue')['default']
|
||||||
|
Loading…
Reference in New Issue
Block a user