354 lines
6.3 KiB
Plaintext
354 lines
6.3 KiB
Plaintext
<template>
|
||
<view class="change-password-page">
|
||
<view class="header">
|
||
<view class="back-btn" @click="goBack">
|
||
<text class="back-icon">‹</text>
|
||
</view>
|
||
<text class="header-title">修改密码</text>
|
||
</view>
|
||
|
||
<view class="content">
|
||
<form @submit="onSubmit">
|
||
<!-- 当前密码 -->
|
||
<view class="form-item">
|
||
<text class="label">当前密码</text>
|
||
<input
|
||
class="input"
|
||
type="password"
|
||
placeholder="请输入当前密码"
|
||
v-model="form.currentPassword"
|
||
:disabled="loading"
|
||
required
|
||
/>
|
||
</view>
|
||
|
||
<!-- 新密码 -->
|
||
<view class="form-item">
|
||
<text class="label">新密码</text>
|
||
<input
|
||
class="input"
|
||
type="password"
|
||
placeholder="请输入新密码(6-20位字符)"
|
||
v-model="form.newPassword"
|
||
:disabled="loading"
|
||
required
|
||
/>
|
||
<text class="hint">6-20位字符,建议包含字母、数字和特殊符号</text>
|
||
</view>
|
||
|
||
<!-- 确认新密码 -->
|
||
<view class="form-item">
|
||
<text class="label">确认新密码</text>
|
||
<input
|
||
class="input"
|
||
type="password"
|
||
placeholder="请再次输入新密码"
|
||
v-model="form.confirmPassword"
|
||
:disabled="loading"
|
||
required
|
||
/>
|
||
</view>
|
||
|
||
<!-- 提交按钮 -->
|
||
<button
|
||
class="submit-btn"
|
||
form-type="submit"
|
||
:disabled="loading || !isFormValid"
|
||
:loading="loading"
|
||
>
|
||
{{ loading ? '处理中...' : '确认修改' }}
|
||
</button>
|
||
</form>
|
||
|
||
<!-- 忘记密码提示 -->
|
||
<view class="forgot-password">
|
||
<text class="forgot-text" @click="goToForgotPassword">忘记密码?</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 成功提示 -->
|
||
<view v-if="showSuccess" class="success-modal" @click="hideSuccess">
|
||
<view class="success-content" @click.stop>
|
||
<text class="success-icon">✓</text>
|
||
<text class="success-title">修改成功</text>
|
||
<text class="success-text">密码已成功修改,请使用新密码登录</text>
|
||
<button class="success-btn" @click="hideSuccess">确定</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
import { ref, computed } from 'vue'
|
||
import supa from '@/components/supadb/aksupainstance.uts'
|
||
|
||
// 表单数据
|
||
const form = ref({
|
||
currentPassword: '',
|
||
newPassword: '',
|
||
confirmPassword: ''
|
||
})
|
||
|
||
const loading = ref<boolean>(false)
|
||
const showSuccess = ref<boolean>(false)
|
||
|
||
// 表单验证
|
||
const isFormValid = computed((): boolean => {
|
||
const { currentPassword, newPassword, confirmPassword } = form.value
|
||
return currentPassword.length >= 6 &&
|
||
newPassword.length >= 6 &&
|
||
newPassword.length <= 20 &&
|
||
newPassword === confirmPassword
|
||
})
|
||
|
||
// 提交表单
|
||
const onSubmit = async () => {
|
||
if (!isFormValid.value) {
|
||
uni.showToast({
|
||
title: '请填写完整且正确的密码信息',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
loading.value = true
|
||
|
||
try {
|
||
// 调用 Supabase 更新密码
|
||
const { error } = await supa.auth.updateUser({
|
||
password: form.value.newPassword
|
||
})
|
||
|
||
if (error !== null) {
|
||
throw error
|
||
}
|
||
|
||
// 成功
|
||
showSuccess.value = true
|
||
|
||
// 清除表单
|
||
form.value = {
|
||
currentPassword: '',
|
||
newPassword: '',
|
||
confirmPassword: ''
|
||
}
|
||
|
||
} catch (error: any) {
|
||
console.error('修改密码失败:', error)
|
||
|
||
let errorMessage = '修改密码失败'
|
||
if (error.message?.includes('invalid_credentials')) {
|
||
errorMessage = '当前密码错误'
|
||
} else if (error.message?.includes('password')) {
|
||
errorMessage = '新密码不符合要求'
|
||
}
|
||
|
||
uni.showToast({
|
||
title: errorMessage,
|
||
icon: 'none'
|
||
})
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 导航函数
|
||
const goBack = () => {
|
||
uni.navigateBack()
|
||
}
|
||
|
||
const goToForgotPassword = () => {
|
||
uni.navigateTo({
|
||
url: '/pages/user/forgot-password'
|
||
})
|
||
}
|
||
|
||
const hideSuccess = () => {
|
||
showSuccess.value = false
|
||
goBack()
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.change-password-page {
|
||
min-height: 100vh;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.header {
|
||
background-color: #ffffff;
|
||
padding: 15px;
|
||
display: flex;
|
||
align-items: center;
|
||
border-bottom: 1px solid #e5e5e5;
|
||
}
|
||
|
||
.back-btn {
|
||
width: 40px;
|
||
height: 40px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.back-icon {
|
||
font-size: 24px;
|
||
color: #333;
|
||
}
|
||
|
||
.header-title {
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
flex: 1;
|
||
}
|
||
|
||
.content {
|
||
padding: 20px;
|
||
}
|
||
|
||
.form-item {
|
||
margin-bottom: 20px;
|
||
background-color: #ffffff;
|
||
border-radius: 10px;
|
||
padding: 15px;
|
||
}
|
||
|
||
.label {
|
||
display: block;
|
||
font-size: 16px;
|
||
color: #333;
|
||
margin-bottom: 10px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.input {
|
||
width: 100%;
|
||
height: 44px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 8px;
|
||
padding: 0 15px;
|
||
font-size: 16px;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.input:focus {
|
||
border-color: #007aff;
|
||
outline: none;
|
||
}
|
||
|
||
.input:disabled {
|
||
background-color: #f9f9f9;
|
||
color: #999;
|
||
}
|
||
|
||
.hint {
|
||
display: block;
|
||
font-size: 12px;
|
||
color: #999;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.submit-btn {
|
||
width: 100%;
|
||
height: 50px;
|
||
background-color: #007aff;
|
||
color: #ffffff;
|
||
border-radius: 25px;
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
border: none;
|
||
margin-top: 30px;
|
||
}
|
||
|
||
.submit-btn:disabled {
|
||
background-color: #cccccc;
|
||
}
|
||
|
||
.forgot-password {
|
||
text-align: center;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.forgot-text {
|
||
color: #007aff;
|
||
font-size: 14px;
|
||
text-decoration: underline;
|
||
}
|
||
|
||
/* 成功提示模态框 */
|
||
.success-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.success-content {
|
||
width: 280px;
|
||
background-color: #ffffff;
|
||
border-radius: 15px;
|
||
padding: 30px 20px;
|
||
text-align: center;
|
||
}
|
||
|
||
.success-icon {
|
||
display: block;
|
||
width: 60px;
|
||
height: 60px;
|
||
line-height: 60px;
|
||
background-color: #4cd964;
|
||
color: #ffffff;
|
||
font-size: 30px;
|
||
border-radius: 50%;
|
||
margin: 0 auto 20px;
|
||
}
|
||
|
||
.success-title {
|
||
display: block;
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.success-text {
|
||
display: block;
|
||
font-size: 14px;
|
||
color: #666;
|
||
margin-bottom: 20px;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.success-btn {
|
||
width: 100%;
|
||
height: 44px;
|
||
background-color: #007aff;
|
||
color: #ffffff;
|
||
border-radius: 22px;
|
||
font-size: 16px;
|
||
border: none;
|
||
}
|
||
|
||
/* 响应式优化 */
|
||
@media screen and (min-width: 768px) {
|
||
.change-password-page {
|
||
max-width: 500px;
|
||
margin: 0 auto;
|
||
border-left: 1px solid #e5e5e5;
|
||
border-right: 1px solid #e5e5e5;
|
||
}
|
||
|
||
.content {
|
||
padding: 40px;
|
||
}
|
||
}
|
||
</style>
|