Commit 663f7447 authored by zhangsan's avatar zhangsan

1

parent 2e2ba9cf
......@@ -25,7 +25,7 @@
},
"scripts": {
"dev": "vite --host",
"build": "vue-tsc --noEmit && vite build",
"build": "vite build",
"build:test": "vue-tsc --noEmit && vite build --mode test",
"preinstall": "npx only-allow pnpm",
"prepare": "husky install",
......@@ -45,6 +45,7 @@
"crypto-js": "^4.2.0",
"dayjs": "^1.11.10",
"mitt": "^3.0.1",
"qrcode": "^1.5.4",
"vant": "^4.8.5",
"vue": "^3.4.21"
},
......@@ -54,8 +55,10 @@
"@commitlint/config-conventional": "^19.1.0",
"@iconify-json/carbon": "^1.1.31",
"@ls-lint/ls-lint": "^2.2.2",
"@types/crypto-js": "^4.2.2",
"@types/fs-extra": "^11.0.4",
"@types/node": "20.9.0",
"@types/qrcode": "^1.5.5",
"@unocss/eslint-plugin": "^0.58.6",
"@unocss/preset-rem-to-px": "^0.58.6",
"@varlet/import-resolver": "^3.8.5",
......
......@@ -3,10 +3,6 @@
"path": "404",
"title": "404-页面未找到"
},
{
"path": "detail",
"title": "项目详情"
},
{
"path": "guquan",
"title": "股权"
......
This diff is collapsed.
......@@ -3,7 +3,6 @@ import App from './App.vue';
import Varlet from '@varlet/ui'
import router from './router';
import './assets/global.css'; // 引入全局样式
'
const app = createApp(App);
app.use(router);
......
<template>
<defaultLayout>
<div class="container">
<GuideModal :show="showGuide" :guide-list="content" @close="showGuide = false" />
<GuideModal v-model="showGuide" :guide-list="content" />
<div class="imgwarp">
<img src="@/static/common/login.png" />
</div>
......@@ -99,12 +99,16 @@ const navigateTo = (path) => {
async function handleGetCard() {
if (userData.value.data !== 'true') {
showFailToast('请先实名注册后启用此卡');
navigateTo('/user/shiming.html');
setTimeout(() => {
navigateTo('/user/shiming.html');
}, 2000)
return;
}
if (userData.value.smCount < 3) {
showFailToast('需邀请3位用户参与一带一路即可启用此卡');
navigateTo('/user/invite.html');
setTimeout(() => {
navigateTo('/user/invite.html');
}, 2000)
return;
}
if (cardinfo.value?.bankNum) {
......@@ -112,7 +116,7 @@ async function handleGetCard() {
return;
}
try {
const res = await post('/ops/bankcard/add', { cardtype: 2 });
const res = await request.post('/ops/bankcard/add', { cardtype: 2 });
if (res.code === 200) {
showSuccessToast('启用成功');
await getCardList(); // 刷新卡片列表
......@@ -125,12 +129,16 @@ async function handleGetCard() {
function gotx(balance, type, title) {
if (userData.value.data != 'true') {
showFailToast('请先实名注册后启用此卡')
navigateTo('/user/shiming.html')
setTimeout(() => {
navigateTo('/user/shiming.html')
}, 2000)
return
}
if (userData.value.smCount < 3) {
showFailToast('需邀请3位用户参与一带一路即可启用此卡')
navigateTo('/user/invite.html')
setTimeout(() => {
navigateTo('/user/invite.html')
}, 2000)
return
}
if (balance && balance > 0) {
......
......@@ -13,6 +13,12 @@ import png6 from '@/static/my/a6.png'
import png7 from '@/static/my/a7.png'
import png8 from '@/static/my/a8.png'
import png9 from '@/static/my/a9.png'
const kfurl = ref('')
request.get('/system/config/configKey/mous/apk_version', {}).then(res => {
if (res.code === 200) {
kfurl.value = res.msg
}
})
const MENU_ITEMS = ref([
{ name: '实名认证', icon: png1, path: '/user/shiming.html' },
......@@ -23,7 +29,7 @@ const MENU_ITEMS = ref([
{ name: 'APP下载', icon: png6, path: '/user/appdownload.html' },
{ name: '我的团队', icon: png7, path: '/user/myteam.html' },
{ name: '账号安全', icon: png8, path: '/user/accountSecurity.html' },
{ name: '邀请好友', icon: png9, path: '/yaoqing.html' },
{ name: '邀请好友', icon: png9, path: '/user/invite.html' },
])
const navigateTo = (path) => {
window.location.href = window.location.origin + path
......@@ -79,6 +85,9 @@ function logout() {
navigateTo('/login.html')
})
}
function navigateTo1(kfurl) {
window.location.href = kfurl
}
onMounted(fetchData)
</script>
......@@ -115,7 +124,7 @@ onMounted(fetchData)
<img src="@/static/my/qd.png" alt="sign">
<span>每日签到</span>
</div>
<div v-ripple class="qd" style="margin-top: 4px;">
<div v-ripple class="qd" style="margin-top: 4px;" @click="navigateTo1(kfurl)">
<img src="@/static/my/kf.png" alt="sign">
<span>在线客服</span>
</div>
......
......@@ -40,7 +40,7 @@
立即注册
</div>
<div class="infowarp">
<div class="register">
<div class="register" @click="navigateTo(kfurl)">
联系我们
</div>
<div class="line">
......@@ -60,7 +60,6 @@ const navigateTo = (path: string) => {
import { ref, reactive } from 'vue'
import request from '@/utils/request'
import { showFailToast, showSuccessToast } from 'vant'
interface FormData {
username: string
password: string
......@@ -80,7 +79,14 @@ const formData = reactive<FormData>({
inviteCode: '',
extend3: '',
})
const kfurl = ref('')
request.get('/system/config/configKey/mous/apk_version', {}).then(res => {
if (res.code === 200) {
kfurl.value = res.msg
}
})
formData.inviteCode = window.location.search.split('=')[1]
function validateForm(): boolean {
if (!formData.username) {
showFailToast('请输入手机号')
......@@ -128,7 +134,7 @@ async function handleSubmit() {
if (res.code === 200) {
showSuccessToast('注册成功')
setTimeout(() => {
navigateTo('/')
window.location.href = '/login.html'
}, 1000)
} else {
showFailToast(res.msg || '注册失败')
......
......@@ -111,7 +111,7 @@ onMounted(() => {
</div> -->
<!-- 昵称设置 -->
<div class="menu-item" @click="navigateTo('/user/resetNickname')">
<div class="menu-item" @click="navigateTo('/user/resetNickname.html')">
<div class="left">
<van-icon name="contact" class="menu-icon" />
<span>姓名</span>
......@@ -123,7 +123,7 @@ onMounted(() => {
</div>
<!-- 登录密码 -->
<div class="menu-item" @click="navigateTo('/user/resetPass')">
<div class="menu-item" @click="navigateTo('/user/resetPass.html')">
<div class="left">
<van-icon name="lock" class="menu-icon" />
<span>修改登录密码</span>
......@@ -134,7 +134,7 @@ onMounted(() => {
</div>
<!-- 交易密码 -->
<div class="menu-item" @click="navigateTo('/user/resetPayPass')">
<div class="menu-item" @click="navigateTo('/user/resetPayPass.html')">
<div class="left">
<van-icon name="shield-o" class="menu-icon" />
<span>修改交易密码</span>
......
......@@ -2,10 +2,8 @@
import { ref } from 'vue'
import AppHeader from '@/components/AppHeader.vue'
const isqq = ref(false)
// const downloadUrl = ref('https://dwlink.dwzhengs13.com')
const downloadUrl = ref('')
const downloadUrl = ref('https://down.yidaiyilu2025.com')
const handleDownload = () => {
return false
window.open(downloadUrl.value, '_blank')
}
......
......@@ -8,12 +8,12 @@
<meta name="description" content="一带一路" />
<meta name="keywords" content="ares-admin,ares-mobile,ares admin,ares mobile,ares,mpa,vue,h5,template">
<meta name="format-detection" content="telephone=no" />
<title>项目详情</title>
<title>邀请好友</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./detail/main.ts"></script>
<script type="module" src="./invite/main.ts"></script>
</body>
</html>
\ No newline at end of file
<template>
<AppHeader title="邀请好友"/>
<div class="container">
<img class="logo" src="@/static/invite/logo.png" alt="邀请好友">
<div class="invite-code" @click="handleCopy(userInfo.yqm)">
您的专属邀请码:<span>{{ userInfo.yqm }}</span>
<img class="copy" src="@/static/invite/copy.png" alt="">
</div>
<div class="imgwarp">
<img class="invite" src="@/static/invite/invite.png" alt="邀请好友">
</div>
<div class="qr-section">
<img :src="QRImgUrl" alt="QR Code" />
</div>
<div class="tips">
扫描二维码,注册世界银行APP
</div>
<div class="action-buttons">
<div @click="saveImage" class="btn1" style="margin-right: 112px;">
<img src="@/static/invite/download.png" alt="">
<span>保存图片</span>
</div>
<div @click="copyFullLink" class="btn1">
<img src="@/static/invite/copyl.png" alt="">
<span>复制链接</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import QRCode from 'qrcode'
import request from '@/utils/request'
import { showSuccessToast, showFailToast } from 'vant';
import AppHeader from '@/components/AppHeader.vue'
// 类型定义
interface UserInfo {
yqm: string
}
// 响应式状态
const QRImgUrl = ref('')
const linkstr = ref('')
const userInfo = reactive<UserInfo>({
yqm: ''
})
// 生成二维码
const generateQRCode = async () => {
const opts = {
errorCorrectionLevel: 'L',
type: 'image/png',
quality: 0.3,
margin: 1,
width: 200,
height: 200,
color: {
dark: '#333333',
light: '#fff'
}
}
try {
QRImgUrl.value = await QRCode.toDataURL(linkstr.value, opts)
} catch (error) {
console.error('Failed to generate QR code:', error)
}
}
// 复制文本
const handleCopy = (text: string) => {
const textarea = document.createElement('textarea')
textarea.value = text
document.body.appendChild(textarea)
textarea.select()
document.execCommand('copy')
document.body.removeChild(textarea)
showSuccessToast('复制成功')
}
// 获取用户信息
const fetchUserInfo = async () => {
try {
const res = await request.get('/system/user/', {})
if (res.code === 200) {
userInfo.yqm = res.yqm || ''
}
} catch (error) {
console.error('Failed to fetch user info:', error)
}
}
// 获取邀请码和链接
const fetchInviteInfo = async () => {
try {
const res = await request.get('/system/user/qRCode', {})
linkstr.value = `https://${location.host}/register.html?yqm=${res.data.slice(-6)}`
await generateQRCode()
} catch (error) {
console.error('Failed to fetch invite info:', error)
}
}
// 修改保存图片方法
const saveImage = async () => {
try {
// 获取二维码图片的 base64 数据
const imageData = QRImgUrl.value
// 判断是否在 Android 环境
if (window.android && window.android.saveImage) {
// 调用 Android 的保存图片方法
window.android.saveImage(imageData)
showSuccessToast('保存成功')
}
// 判断是否在 iOS 环境
else if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.saveImage) {
// 调用 iOS 的保存图片方法
window.webkit.messageHandlers.saveImage.postMessage(imageData)
showSuccessToast('保存成功')
}
// 其他环境(PC浏览器等)
else {
const link = document.createElement('a')
link.href = imageData
link.download = '邀请二维码.png'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
showSuccessToast('保存成功')
}
} catch (error) {
console.error('Failed to save image:', error)
showFailToast('保存失败')
}
}
// 为了 TypeScript 类型检查,添加全局类型声明
declare global {
interface Window {
android?: {
saveImage: (base64: string) => void
}
webkit?: {
messageHandlers: {
saveImage: {
postMessage: (base64: string) => void
}
}
}
}
}
// 复制完整链接
const copyFullLink = () => {
const textarea = document.createElement('textarea')
textarea.value = linkstr.value
document.body.appendChild(textarea)
textarea.select()
document.execCommand('copy')
document.body.removeChild(textarea)
showSuccessToast('复制成功')
}
// 初始化
onMounted(async () => {
await Promise.all([
fetchUserInfo(),
fetchInviteInfo()
])
})
</script>
<style lang="scss" scoped>
.container {
margin-top: 54px;
min-height: 100vh;
padding: 20px 0;
background: url('@/static/invite/bg.png') no-repeat;
background-size: 100% 100%;
.imgwarp{
display: flex;
justify-content: center;
align-items: center;
}
.logo {
width: 337px;
height: 80px;
display: block;
margin: 61px auto 313px;
}
.invite-code {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-size: 16px;
width: 308px;
height: 32px;
line-height: 32px;
font-weight: 400;
font-size: 17px;
background-color: #fff9e8;
margin: 0 auto;
text-align: center;
color: #9b3500;
span {
font-weight: 700;
}
.copy {
width: 16px;
height: 16px;
margin-left: 5px;
}
}
.invite {
width: 186px;
height: 20px;
margin: 20px auto 22px;
}
.qr-section {
text-align: center;
margin: 20px;
img {
width: 122px;
height: 120px;
margin: 0 auto;
}
}
.tips {
font-family: HarmonyOS Sans SC;
font-weight: 700;
font-size: 14px;
color: #9B3500;
line-height: 20px;
text-align: center;
}
.action-buttons {
display: flex;
justify-content: center;
gap: 20px;
padding: 0 20px;
margin-top: 30px;
img {
width: 26px;
height: 26px;
margin-bottom: 10px;
}
.btn1 {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
span {
font-weight: 400;
font-size: 14px;
color: #9B3500;
line-height: 20px;
}
}
}
}
</style>
\ No newline at end of file
import 'virtual:uno.css'
import '@/styles/index.scss'
import Varlet from '@varlet/ui'
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).use(Varlet).mount('#app')
\ No newline at end of file
<template>
<div class="container">
reset-nickname
<AppHeader title="修改昵称"/>
<div class="auth-container">
<div class="label">修改昵称</div>
<div class="warpinput">
<div style="display: flex;align-items: center;">
<input type="texat" maxlength="20" v-model="nickname" placeholder="请输入修改昵称" />
</div>
<div class="count">{{ nickname.length }}/20</div>
</div>
<div class="tips">
* 昵称长度为2-20个字符
</div>
<div class="buynow" @click="() => handleSubmit()" v-ripple>确定修改</div>
</div>
</template>
<script setup lang="ts">
// import { ref } from 'vue'
import { ref } from 'vue'
import { showFailToast, showSuccessToast } from 'vant'
import request from '@/utils/request'
import { useDebounceFn } from '@vueuse/core'
import AppHeader from '@/components/AppHeader.vue'
const navigateTo = (path: string) => {
window.location.href = window.location.origin + path
}
// 响应式状态
const loading = ref(false)
const nickname = ref('')
// 表单验证
const validateForm = (): boolean => {
if (!nickname.value) {
showFailToast('请输入昵称')
return false
}
if (nickname.value.length < 2) {
showFailToast('昵称长度不能少于2个字符')
return false
}
if (nickname.value.length > 20) {
showFailToast('昵称长度不能超过20个字符')
return false
}
return true
}
const getUserInfo = () => {
request.get('/system/user/info',{}).then(res => {
nickname.value = res.extend2 || res.nickName
})
}
getUserInfo()
// 提交处理
const handleUpdateNickname = async () => {
if (loading.value) return
try {
loading.value = true
const res = await request.post('/system/user/edit/edityhxx', {
extend2: nickname.value
})
console.log(res)
if (res.code === 200) {
showSuccessToast('昵称修改成功')
// 修改成功后延迟返回
setTimeout(() => window.location.replace('/user/accountSecurity.html'), 2000)
} else {
showFailToast(res.msg || '修改失败')
}
} catch (error) {
console.error('Update nickname error:', error)
showFailToast('修改失败,请稍后重试')
} finally {
loading.value = false
}
}
// 表单提交(带防抖)
const handleSubmit = useDebounceFn(async () => {
if (!validateForm()) return
await handleUpdateNickname()
}, 500)
</script>
<style lang="scss">
body {
background-color: #f5f6f6;
<style lang="scss" scoped>
.auth-container {
margin-top: 54px;
padding: 20px 20px 49px;
background: url('@/static/common/commonbg.png') no-repeat;
background-size: 100% 100%;
min-height: 100vh;
.label {
font-size: 14px;
color: #460A0B;
margin-bottom: 10px;
margin-left: 5px;
}
.warpinput {
display: flex;
background: #fff;
border-radius: 10px;
margin-bottom: 20px;
align-items: center;
justify-content: space-between;
padding: 15px;
input {
margin-left: 12px;
background-color: #fff !important;
border: none;
outline: none;
color: #460A0B;
font-size: 14px;
width: 100%;
&::placeholder {
color: #999;
font-size: 14px;
}
&:-webkit-autofill {
-webkit-box-shadow: 0 0 0 30px white inset !important;
-webkit-text-fill-color: #460A0B !important;
}
}
.count {
color: #999;
font-size: 12px;
margin-left: 10px;
}
}
.tips {
color: #999;
font-size: 12px;
padding: 0 15px;
margin-top: 10px;
margin-bottom: 40px;
}
.buynow {
width: 291px;
height: 63px;
background: url('@/static/common/btn.png') no-repeat;
background-size: 100% 100%;
font-weight: 500;
margin: 0 auto;
font-size: 21px;
color: #FFF7E9;
text-align: center;
line-height: 46px;
}
}
</style>
\ No newline at end of file
</style>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<meta name="description" content="一带一路" />
<meta name="keywords" content="ares-admin,ares-mobile,ares admin,ares mobile,ares,mpa,vue,h5,template">
<meta name="format-detection" content="telephone=no" />
<title>修改登录密码</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./resetPass/main.ts"></script>
</body>
</html>
<template>
<AppHeader title="修改登录密码"/>
<div class="auth-container">
<div class="label">原密码</div>
<div class="warpinput">
<div style="display: flex;align-items: center;">
<input :type="showOldPass ? 'text' : 'password'" v-model="formData.oldPassword" placeholder="请输入原密码" />
</div>
<van-icon name="closed-eye" @click="showOldPass = !showOldPass" v-if="!showOldPass" />
<van-icon name="eye-o" @click="showOldPass = !showOldPass" v-if="showOldPass" />
</div>
<div class="label">新密码</div>
<div class="warpinput">
<div style="display: flex;align-items: center;">
<input :type="showNewPass ? 'text' : 'password'" v-model="formData.newPassword" placeholder="请输入新密码" />
</div>
<van-icon name="closed-eye" @click="showNewPass = !showNewPass" v-if="!showNewPass" />
<van-icon name="eye-o" @click="showNewPass = !showNewPass" v-if="showNewPass" />
</div>
<div class="label">确认新密码</div>
<div class="warpinput">
<div style="display: flex;align-items: center;">
<input :type="showConfirmPass ? 'text' : 'password'" v-model="formData.confirmPassword" placeholder="请确认新密码" />
</div>
<van-icon name="closed-eye" @click="showConfirmPass = !showConfirmPass" v-if="!showConfirmPass" />
<van-icon name="eye-o" @click="showConfirmPass = !showConfirmPass" v-if="showConfirmPass" />
</div>
<div class="buynow" @click="() => handleSubmit()" v-ripple>确定修改</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { encrypt } from '@/utils/encrypt'
import { useDebounceFn } from '@vueuse/core'
import AppHeader from '@/components/AppHeader.vue'
import { showFailToast, showSuccessToast } from 'vant'
import request from '@/utils/request'
const navigateTo = (path: string) => {
window.location.href = window.location.origin + path
}
// 类型定义
interface ResetPasswordForm {
oldPassword: string
newPassword: string
confirmPassword: string
}
// 响应式状态
const showOldPass = ref(false)
const showNewPass = ref(false)
const showConfirmPass = ref(false)
const loading = ref(false)
// 表单数据
const formData = reactive<ResetPasswordForm>({
oldPassword: '',
newPassword: '',
confirmPassword: ''
})
// 表单验证
const validateForm = (): boolean => {
if (!formData.oldPassword) {
showFailToast('请输入原密码')
return false
}
if (!formData.newPassword) {
showFailToast('请输入新密码')
return false
}
if (!formData.confirmPassword) {
showFailToast('请确认新密码')
return false
}
if (formData.newPassword !== formData.confirmPassword) {
showFailToast('两次输入的密码不一致')
return false
}
return true
}
// 提交处理
const handleResetPassword = async () => {
if (loading.value) return
try {
loading.value = true
const res = await request.put('/system/user/profile/updatePwd', {
oldPassword: encrypt(formData.oldPassword),
newPassword: encrypt(formData.newPassword)
})
if (res.code === 200) {
showSuccessToast('密码修改成功')
localStorage.clear()
window.location.replace('/login.html')
// 修改成功后延迟返回
// setTimeout(() => navigateTo('/user/accountSecurity'), 1000)
setTimeout(() => window.location.replace('/login.html'), 2000)
} else {
showFailToast(res.msg || '修改失败')
}
} catch (error) {
console.error('Reset password error:', error)
showFailToast('修改失败,请稍后重试')
} finally {
loading.value = false
}
}
// 表单提交(带防抖)
const handleSubmit = useDebounceFn(async () => {
if (!validateForm()) return
await handleResetPassword()
}, 500)
</script>
<style lang="scss" scoped>
.auth-container {
margin-top: 54px;
padding: 20px 20px 49px;
background: url('@/static/common/commonbg.png') no-repeat;
background-size: 100% 100%;
min-height: 100vh;
.label {
font-size: 14px;
color: #460A0B;
margin-bottom: 10px;
margin-left: 5px;
}
.warpinput {
display: flex;
background: #fff;
border-radius: 10px;
margin-bottom: 40px;
align-items: center;
justify-content: space-between;
padding: 15px;
input {
margin-left: 12px;
background-color: #fff !important;
border: none;
outline: none;
color: #460A0B;
font-size: 14px;
width: 100%;
&::placeholder {
color: #999;
font-size: 14px;
}
&:-webkit-autofill {
-webkit-box-shadow: 0 0 0 30px white inset !important;
-webkit-text-fill-color: #460A0B !important;
}
}
}
.buynow {
width: 291px;
height: 63px;
background: url('@/static/common/btn.png') no-repeat;
background-size: 100% 100%;
font-weight: 500;
margin: 0 auto;
margin-top: 60px;
font-size: 21px;
color: #FFF7E9;
text-align: center;
line-height: 46px;
}
}
</style>
\ No newline at end of file
import 'virtual:uno.css'
import '@/styles/index.scss'
import Varlet from '@varlet/ui'
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).use(Varlet).mount('#app')
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<meta name="description" content="一带一路" />
<meta name="keywords" content="ares-admin,ares-mobile,ares admin,ares mobile,ares,mpa,vue,h5,template">
<meta name="format-detection" content="telephone=no" />
<title>修改交易密码</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./resetPayPass/main.ts"></script>
</body>
</html>
\ No newline at end of file
<template>
<AppHeader title="修改交易密码"/>
<div class="auth-container">
<div class="label">原密码</div>
<div class="warpinput">
<div style="display: flex;align-items: center;">
<input type="password" maxlength="6" v-model="formData.oldPassword" placeholder="请输入原交易密码" />
</div>
</div>
<div class="label">新密码</div>
<div class="warpinput">
<div style="display: flex;align-items: center;">
<input type="password" maxlength="6" v-model="formData.newPassword" placeholder="请输入新交易密码" />
</div>
</div>
<div class="label">确认新密码</div>
<div class="warpinput">
<div style="display: flex;align-items: center;">
<input type="password" maxlength="6" v-model="formData.confirmPassword" placeholder="请确认新交易密码" />
</div>
</div>
<div class="tips">
* 交易密码为6位数字
</div>
<div class="buynow" @click="() => handleSubmit()" v-ripple>确定修改</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { useDebounceFn } from '@vueuse/core'
import { showFailToast, showSuccessToast } from 'vant'
import AppHeader from '@/components/AppHeader.vue'
import request from '@/utils/request'
const navigateTo = (path: string) => {
window.location.replace(window.location.origin + path)
}
// 类型定义
interface PayPasswordForm {
oldPassword: string
newPassword: string
confirmPassword: string
}
// 响应式状态
const loading = ref(false)
// 表单数据
const formData = reactive<PayPasswordForm>({
oldPassword: '',
newPassword: '',
confirmPassword: ''
})
// 表单验证
const validateForm = (): boolean => {
if (!formData.oldPassword) {
showFailToast('请输入原交易密码')
return false
}
if (!formData.newPassword) {
showFailToast('请输入新交易密码')
return false
}
if (!formData.confirmPassword) {
showFailToast('请确认新交易密码')
return false
}
if (formData.newPassword !== formData.confirmPassword) {
showFailToast('两次输入的密码不一致')
return false
}
return true
}
// 提交处理
const handleResetPayPassword = async () => {
if (loading.value) return
try {
loading.value = true
const res = await request.put('/system/user/profile/updatePwdEx3', {
oldPassword: formData.oldPassword,
newPassword: formData.newPassword
})
if (res.code === 200) {
showSuccessToast('交易密码修改成功')
// 修改成功后延迟返回
setTimeout(() => window.location.replace('/user/accountSecurity.html'), 1000)
} else {
showFailToast(res.msg || '修改失败')
}
} catch (error) {
console.error('Reset pay password error:', error)
showFailToast('修改失败,请稍后重试')
} finally {
loading.value = false
}
}
// 表单提交(带防抖)
const handleSubmit = useDebounceFn(async () => {
if (!validateForm()) return
await handleResetPayPassword()
}, 500)
</script>
<style lang="scss" scoped>
.auth-container {
margin-top: 54px;
padding: 20px 20px 49px;
background: url('@/static/common/commonbg.png') no-repeat;
background-size: 100% 100%;
min-height: 100vh;
.label {
font-size: 14px;
color: #460A0B;
margin-bottom: 10px;
margin-left: 5px;
}
.warpinput {
display: flex;
background: #fff;
border-radius: 10px;
margin-bottom: 20px;
align-items: center;
justify-content: space-between;
padding: 15px;
input {
margin-left: 12px;
background-color: #fff !important;
border: none;
outline: none;
color: #460A0B;
font-size: 14px;
width: 100%;
&::placeholder {
color: #999;
font-size: 14px;
}
&:-webkit-autofill {
-webkit-box-shadow: 0 0 0 30px white inset !important;
-webkit-text-fill-color: #460A0B !important;
}
}
}
.tips {
color: #460A0B;
font-size: 12px;
padding: 0 15px;
margin-top: 10px;
margin-bottom: 40px;
}
.buynow {
width: 291px;
height: 63px;
background: url('@/static/common/btn.png') no-repeat;
background-size: 100% 100%;
font-weight: 500;
margin: 0 auto;
font-size: 21px;
color: #FFF7E9;
text-align: center;
line-height: 46px;
}
}
</style>
import 'virtual:uno.css'
import '@/styles/index.scss'
import Varlet from '@varlet/ui'
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).use(Varlet).mount('#app')
\ No newline at end of file
......@@ -76,7 +76,7 @@ const add = async () => {
})
setTimeout(() => {
navigateTo('/')
window.location.href = '/index.html'
}, 1000)
} else {
showToast(res.msg)
......
......@@ -9,23 +9,16 @@ declare module 'vue' {
export interface GlobalComponents {
AppHeader: typeof import('./../src/components/AppHeader.vue')['default']
GuideModal: typeof import('./../src/components/GuideModal.vue')['default']
ICarbonWorshipMuslim: typeof import('~icons/carbon/worship-muslim')['default']
ICustomGithub: typeof import('~icons/custom/github')['default']
KLineChart: typeof import('./../src/components/KLineChart.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Tabbar: typeof import('./../src/components/tabbar.vue')['default']
VanButton: typeof import('vant/es')['Button']
VanCell: typeof import('vant/es')['Cell']
VanCheckbox: typeof import('vant/es')['Checkbox']
VanIcon: typeof import('vant/es')['Icon']
VanImage: typeof import('vant/es')['Image']
VanList: typeof import('vant/es')['List']
VanPopup: typeof import('vant/es')['Popup']
VanRadio: typeof import('vant/es')['Radio']
VanRadioGroup: typeof import('vant/es')['RadioGroup']
VanTab: typeof import('vant/es')['Tab']
VanTabs: typeof import('vant/es')['Tabs']
VarAppBar: typeof import('@varlet/ui')['AppBar']
VarButton: typeof import('@varlet/ui')['Button']
VarDivider: typeof import('@varlet/ui')['Divider']
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment