fix: 修改密码
This commit is contained in:
parent
0aa2448c92
commit
70e8132429
268
app/profile.tsx
268
app/profile.tsx
|
|
@ -7,6 +7,7 @@ import React, { useEffect, useState } from 'react'
|
||||||
import { ScrollView } from 'react-native'
|
import { ScrollView } from 'react-native'
|
||||||
|
|
||||||
import { imgPicker } from '@/@share/apis'
|
import { imgPicker } from '@/@share/apis'
|
||||||
|
import ChangePasswordModal from '@/components/ChangePasswordModal'
|
||||||
import { authClient } from '@/lib/auth'
|
import { authClient } from '@/lib/auth'
|
||||||
import { userStore } from '@/stores'
|
import { userStore } from '@/stores'
|
||||||
import { uploadFile } from '@/utils'
|
import { uploadFile } from '@/utils'
|
||||||
|
|
@ -55,267 +56,6 @@ function EditNicknameModal({ initialName, onConfirm, onCancel }: EditNicknameMod
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChangePasswordModalProps = {
|
|
||||||
onConfirm: (currentPassword: string, newPassword: string) => void | Promise<void>
|
|
||||||
onCancel: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证密码强度
|
|
||||||
const validatePassword = (password: string): string | null => {
|
|
||||||
if (!password) {
|
|
||||||
return '请输入新密码'
|
|
||||||
}
|
|
||||||
if (password.length < 6) {
|
|
||||||
return '密码长度至少6位'
|
|
||||||
}
|
|
||||||
// 检查是否是无效密码:全是相同字符
|
|
||||||
if (/^(.)\1+$/.test(password)) {
|
|
||||||
return '密码不能全是相同字符'
|
|
||||||
}
|
|
||||||
// 检查是否是连续数字(如 123456, 654321)
|
|
||||||
const isSequentialNumbers = (str: string): boolean => {
|
|
||||||
for (let i = 0; i < str.length - 1; i++) {
|
|
||||||
const current = parseInt(str[i], 10)
|
|
||||||
const next = parseInt(str[i + 1], 10)
|
|
||||||
if (isNaN(current) || isNaN(next)) return false
|
|
||||||
if (Math.abs(current - next) !== 1) return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// 检查是否是连续字母(如 abcdef, fedcba)
|
|
||||||
const isSequentialLetters = (str: string): boolean => {
|
|
||||||
const lowerStr = str.toLowerCase()
|
|
||||||
for (let i = 0; i < lowerStr.length - 1; i++) {
|
|
||||||
const current = lowerStr.charCodeAt(i)
|
|
||||||
const next = lowerStr.charCodeAt(i + 1)
|
|
||||||
if (Math.abs(current - next) !== 1) return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (isSequentialNumbers(password) || isSequentialLetters(password)) {
|
|
||||||
return '密码不能是连续字符'
|
|
||||||
}
|
|
||||||
// 检查是否是简单密码(如 111111, 000000, aaaaaa)
|
|
||||||
const commonWeakPasswords = ['111111', '222222', '333333', '444444', '555555', '666666', '777777', '888888', '999999', '000000', 'aaaaaa', 'bbbbbb', 'cccccc', 'dddddd', 'eeeeee', 'ffffff', '123456', '654321', 'abcdef', 'fedcba']
|
|
||||||
if (commonWeakPasswords.includes(password.toLowerCase())) {
|
|
||||||
return '密码过于简单,请使用更复杂的密码'
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
function ChangePasswordModal({ onConfirm, onCancel }: ChangePasswordModalProps) {
|
|
||||||
const [currentPassword, setCurrentPassword] = useState('')
|
|
||||||
const [newPassword, setNewPassword] = useState('')
|
|
||||||
const [confirmPassword, setConfirmPassword] = useState('')
|
|
||||||
const [showCurrentPassword, setShowCurrentPassword] = useState(false)
|
|
||||||
const [showNewPassword, setShowNewPassword] = useState(false)
|
|
||||||
const [showConfirmPassword, setShowConfirmPassword] = useState(false)
|
|
||||||
const [loading, setLoading] = useState(false)
|
|
||||||
const [errors, setErrors] = useState<{
|
|
||||||
currentPassword?: string
|
|
||||||
newPassword?: string
|
|
||||||
confirmPassword?: string
|
|
||||||
}>({})
|
|
||||||
|
|
||||||
const validateCurrentPassword = (value: string) => {
|
|
||||||
if (!value) {
|
|
||||||
setErrors((prev) => ({ ...prev, currentPassword: '请输入当前密码' }))
|
|
||||||
} else {
|
|
||||||
setErrors((prev) => {
|
|
||||||
const newErrors = { ...prev }
|
|
||||||
delete newErrors.currentPassword
|
|
||||||
return newErrors
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const validateNewPassword = (value: string) => {
|
|
||||||
const error = validatePassword(value)
|
|
||||||
if (error) {
|
|
||||||
setErrors((prev) => ({ ...prev, newPassword: error }))
|
|
||||||
} else {
|
|
||||||
setErrors((prev) => {
|
|
||||||
const newErrors = { ...prev }
|
|
||||||
delete newErrors.newPassword
|
|
||||||
return newErrors
|
|
||||||
})
|
|
||||||
// 如果确认密码已输入,重新验证确认密码
|
|
||||||
if (confirmPassword) {
|
|
||||||
validateConfirmPassword(confirmPassword, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const validateConfirmPassword = (value: string, newPwd = newPassword) => {
|
|
||||||
if (!value) {
|
|
||||||
setErrors((prev) => ({ ...prev, confirmPassword: '请再次输入新密码' }))
|
|
||||||
} else if (value !== newPwd) {
|
|
||||||
setErrors((prev) => ({ ...prev, confirmPassword: '两次密码输入不一致' }))
|
|
||||||
} else {
|
|
||||||
setErrors((prev) => {
|
|
||||||
const newErrors = { ...prev }
|
|
||||||
delete newErrors.confirmPassword
|
|
||||||
return newErrors
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleConfirm = async () => {
|
|
||||||
if (loading) return
|
|
||||||
|
|
||||||
// 验证所有字段并收集错误
|
|
||||||
const newErrors: typeof errors = {}
|
|
||||||
|
|
||||||
if (!currentPassword) {
|
|
||||||
newErrors.currentPassword = '请输入当前密码'
|
|
||||||
}
|
|
||||||
|
|
||||||
const newPasswordError = validatePassword(newPassword)
|
|
||||||
if (newPasswordError) {
|
|
||||||
newErrors.newPassword = newPasswordError
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!confirmPassword) {
|
|
||||||
newErrors.confirmPassword = '请再次输入新密码'
|
|
||||||
} else if (confirmPassword !== newPassword) {
|
|
||||||
newErrors.confirmPassword = '两次密码输入不一致'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置错误状态
|
|
||||||
setErrors(newErrors)
|
|
||||||
|
|
||||||
// 如果有错误,不继续提交
|
|
||||||
if (Object.keys(newErrors).length > 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
setLoading(true)
|
|
||||||
try {
|
|
||||||
await onConfirm(currentPassword, newPassword)
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ConfirmModal
|
|
||||||
badge="password"
|
|
||||||
cancelText="取消"
|
|
||||||
confirmText={loading ? '修改中...' : '确定'}
|
|
||||||
confirmLoading={loading}
|
|
||||||
content={
|
|
||||||
<Block className="w-full gap-[16px]">
|
|
||||||
<Block className="w-full">
|
|
||||||
<Text className="mb-[8px] text-[14px] text-black">当前密码</Text>
|
|
||||||
<Block className="relative w-full">
|
|
||||||
<Input
|
|
||||||
className={`w-full rounded-lg border-2 px-[12px] py-[10px] text-[14px] text-black ${
|
|
||||||
errors.currentPassword ? 'border-red-500' : 'border-black'
|
|
||||||
}`}
|
|
||||||
placeholder="请输入当前密码"
|
|
||||||
placeholderTextColor="#9CA3AF"
|
|
||||||
value={currentPassword}
|
|
||||||
onChangeText={(text) => {
|
|
||||||
setCurrentPassword(text)
|
|
||||||
if (errors.currentPassword) {
|
|
||||||
validateCurrentPassword(text)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onBlur={() => validateCurrentPassword(currentPassword)}
|
|
||||||
secureTextEntry={!showCurrentPassword}
|
|
||||||
/>
|
|
||||||
<Block
|
|
||||||
className="absolute right-[12px] top-1/2 -translate-y-1/2"
|
|
||||||
onClick={() => setShowCurrentPassword(!showCurrentPassword)}
|
|
||||||
>
|
|
||||||
<Ionicons
|
|
||||||
color="#9CA3AF"
|
|
||||||
name={showCurrentPassword ? 'eye-off-outline' : 'eye-outline'}
|
|
||||||
size={20}
|
|
||||||
/>
|
|
||||||
</Block>
|
|
||||||
</Block>
|
|
||||||
{errors.currentPassword && (
|
|
||||||
<Text className="mt-[4px] text-[12px] text-red-500">{errors.currentPassword}</Text>
|
|
||||||
)}
|
|
||||||
</Block>
|
|
||||||
<Block className="w-full">
|
|
||||||
<Text className="mb-[8px] text-[14px] text-black">新密码</Text>
|
|
||||||
<Block className="relative w-full">
|
|
||||||
<Input
|
|
||||||
className={`w-full rounded-lg border-2 px-[12px] py-[10px] text-[14px] text-black ${
|
|
||||||
errors.newPassword ? 'border-red-500' : 'border-black'
|
|
||||||
}`}
|
|
||||||
placeholder="请输入新密码(至少6位)"
|
|
||||||
placeholderTextColor="#9CA3AF"
|
|
||||||
value={newPassword}
|
|
||||||
onChangeText={(text) => {
|
|
||||||
setNewPassword(text)
|
|
||||||
if (errors.newPassword) {
|
|
||||||
validateNewPassword(text)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onBlur={() => validateNewPassword(newPassword)}
|
|
||||||
secureTextEntry={!showNewPassword}
|
|
||||||
/>
|
|
||||||
<Block
|
|
||||||
className="absolute right-[12px] top-1/2 -translate-y-1/2"
|
|
||||||
onClick={() => setShowNewPassword(!showNewPassword)}
|
|
||||||
>
|
|
||||||
<Ionicons
|
|
||||||
color="#9CA3AF"
|
|
||||||
name={showNewPassword ? 'eye-off-outline' : 'eye-outline'}
|
|
||||||
size={20}
|
|
||||||
/>
|
|
||||||
</Block>
|
|
||||||
</Block>
|
|
||||||
{errors.newPassword && (
|
|
||||||
<Text className="mt-[4px] text-[12px] text-red-500">{errors.newPassword}</Text>
|
|
||||||
)}
|
|
||||||
</Block>
|
|
||||||
<Block className="w-full">
|
|
||||||
<Text className="mb-[8px] text-[14px] text-black">确认新密码</Text>
|
|
||||||
<Block className="relative w-full">
|
|
||||||
<Input
|
|
||||||
className={`w-full rounded-lg border-2 px-[12px] py-[10px] text-[14px] text-black ${
|
|
||||||
errors.confirmPassword ? 'border-red-500' : 'border-black'
|
|
||||||
}`}
|
|
||||||
placeholder="请再次输入新密码"
|
|
||||||
placeholderTextColor="#9CA3AF"
|
|
||||||
value={confirmPassword}
|
|
||||||
onChangeText={(text) => {
|
|
||||||
setConfirmPassword(text)
|
|
||||||
if (errors.confirmPassword) {
|
|
||||||
validateConfirmPassword(text)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onBlur={() => validateConfirmPassword(confirmPassword)}
|
|
||||||
secureTextEntry={!showConfirmPassword}
|
|
||||||
/>
|
|
||||||
<Block
|
|
||||||
className="absolute right-[12px] top-1/2 -translate-y-1/2"
|
|
||||||
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
|
|
||||||
>
|
|
||||||
<Ionicons
|
|
||||||
color="#9CA3AF"
|
|
||||||
name={showConfirmPassword ? 'eye-off-outline' : 'eye-outline'}
|
|
||||||
size={20}
|
|
||||||
/>
|
|
||||||
</Block>
|
|
||||||
</Block>
|
|
||||||
{errors.confirmPassword && (
|
|
||||||
<Text className="mt-[4px] text-[12px] text-red-500">{errors.confirmPassword}</Text>
|
|
||||||
)}
|
|
||||||
</Block>
|
|
||||||
</Block>
|
|
||||||
}
|
|
||||||
title="修改密码"
|
|
||||||
onCancel={onCancel}
|
|
||||||
onConfirm={handleConfirm}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default observer(function ProfilePage() {
|
export default observer(function ProfilePage() {
|
||||||
const { user } = userStore
|
const { user } = userStore
|
||||||
|
|
||||||
|
|
@ -403,7 +143,11 @@ export default observer(function ProfilePage() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Toast.hideModal()
|
Toast.hideModal()
|
||||||
Toast.show({ title: '密码已修改' })
|
Toast.show({ title: '密码已修改,请重新登录' })
|
||||||
|
// 退出登录
|
||||||
|
await userStore.signOut()
|
||||||
|
// 跳转到登录页
|
||||||
|
router.replace('/auth')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Toast.show({ title: '修改失败,请重试' })
|
Toast.show({ title: '修改失败,请重试' })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,285 @@
|
||||||
|
import { Ionicons } from '@expo/vector-icons'
|
||||||
|
import { Block, ConfirmModal, Input, Text } from '@share/components'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
|
export type ChangePasswordModalProps = {
|
||||||
|
onConfirm: (currentPassword: string, newPassword: string) => void | Promise<void>
|
||||||
|
onCancel: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证密码强度
|
||||||
|
const validatePassword = (password: string): string | null => {
|
||||||
|
if (!password) {
|
||||||
|
return '请输入新密码'
|
||||||
|
}
|
||||||
|
if (password.length < 6) {
|
||||||
|
return '密码长度至少6位'
|
||||||
|
}
|
||||||
|
// 检查是否是无效密码:全是相同字符
|
||||||
|
if (/^(.)\1+$/.test(password)) {
|
||||||
|
return '密码不能全是相同字符'
|
||||||
|
}
|
||||||
|
// 检查是否是连续数字(如 123456, 654321)
|
||||||
|
const isSequentialNumbers = (str: string): boolean => {
|
||||||
|
for (let i = 0; i < str.length - 1; i++) {
|
||||||
|
const current = parseInt(str[i], 10)
|
||||||
|
const next = parseInt(str[i + 1], 10)
|
||||||
|
if (isNaN(current) || isNaN(next)) return false
|
||||||
|
if (Math.abs(current - next) !== 1) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 检查是否是连续字母(如 abcdef, fedcba)
|
||||||
|
const isSequentialLetters = (str: string): boolean => {
|
||||||
|
const lowerStr = str.toLowerCase()
|
||||||
|
for (let i = 0; i < lowerStr.length - 1; i++) {
|
||||||
|
const current = lowerStr.charCodeAt(i)
|
||||||
|
const next = lowerStr.charCodeAt(i + 1)
|
||||||
|
if (Math.abs(current - next) !== 1) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (isSequentialNumbers(password) || isSequentialLetters(password)) {
|
||||||
|
return '密码不能是连续字符'
|
||||||
|
}
|
||||||
|
// 检查是否是简单密码(如 111111, 000000, aaaaaa)
|
||||||
|
const commonWeakPasswords = [
|
||||||
|
'111111',
|
||||||
|
'222222',
|
||||||
|
'333333',
|
||||||
|
'444444',
|
||||||
|
'555555',
|
||||||
|
'666666',
|
||||||
|
'777777',
|
||||||
|
'888888',
|
||||||
|
'999999',
|
||||||
|
'000000',
|
||||||
|
'aaaaaa',
|
||||||
|
'bbbbbb',
|
||||||
|
'cccccc',
|
||||||
|
'dddddd',
|
||||||
|
'eeeeee',
|
||||||
|
'ffffff',
|
||||||
|
'123456',
|
||||||
|
'654321',
|
||||||
|
'abcdef',
|
||||||
|
'fedcba',
|
||||||
|
]
|
||||||
|
if (commonWeakPasswords.includes(password.toLowerCase())) {
|
||||||
|
return '密码过于简单,请使用更复杂的密码'
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ChangePasswordModal({ onConfirm, onCancel }: ChangePasswordModalProps) {
|
||||||
|
const [currentPassword, setCurrentPassword] = useState('')
|
||||||
|
const [newPassword, setNewPassword] = useState('')
|
||||||
|
const [confirmPassword, setConfirmPassword] = useState('')
|
||||||
|
const [showCurrentPassword, setShowCurrentPassword] = useState(false)
|
||||||
|
const [showNewPassword, setShowNewPassword] = useState(false)
|
||||||
|
const [showConfirmPassword, setShowConfirmPassword] = useState(false)
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [errors, setErrors] = useState<{
|
||||||
|
currentPassword?: string
|
||||||
|
newPassword?: string
|
||||||
|
confirmPassword?: string
|
||||||
|
}>({})
|
||||||
|
|
||||||
|
const validateCurrentPassword = (value: string) => {
|
||||||
|
if (!value) {
|
||||||
|
setErrors((prev) => ({ ...prev, currentPassword: '请输入当前密码' }))
|
||||||
|
} else {
|
||||||
|
setErrors((prev) => {
|
||||||
|
const newErrors = { ...prev }
|
||||||
|
delete newErrors.currentPassword
|
||||||
|
return newErrors
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateNewPassword = (value: string) => {
|
||||||
|
const error = validatePassword(value)
|
||||||
|
if (error) {
|
||||||
|
setErrors((prev) => ({ ...prev, newPassword: error }))
|
||||||
|
} else {
|
||||||
|
setErrors((prev) => {
|
||||||
|
const newErrors = { ...prev }
|
||||||
|
delete newErrors.newPassword
|
||||||
|
return newErrors
|
||||||
|
})
|
||||||
|
// 如果确认密码已输入,重新验证确认密码
|
||||||
|
if (confirmPassword) {
|
||||||
|
validateConfirmPassword(confirmPassword, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateConfirmPassword = (value: string, newPwd = newPassword) => {
|
||||||
|
if (!value) {
|
||||||
|
setErrors((prev) => ({ ...prev, confirmPassword: '请再次输入新密码' }))
|
||||||
|
} else if (value !== newPwd) {
|
||||||
|
setErrors((prev) => ({ ...prev, confirmPassword: '两次密码输入不一致' }))
|
||||||
|
} else {
|
||||||
|
setErrors((prev) => {
|
||||||
|
const newErrors = { ...prev }
|
||||||
|
delete newErrors.confirmPassword
|
||||||
|
return newErrors
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleConfirm = async () => {
|
||||||
|
if (loading) return
|
||||||
|
|
||||||
|
// 验证所有字段并收集错误
|
||||||
|
const newErrors: typeof errors = {}
|
||||||
|
|
||||||
|
if (!currentPassword) {
|
||||||
|
newErrors.currentPassword = '请输入当前密码'
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPasswordError = validatePassword(newPassword)
|
||||||
|
if (newPasswordError) {
|
||||||
|
newErrors.newPassword = newPasswordError
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!confirmPassword) {
|
||||||
|
newErrors.confirmPassword = '请再次输入新密码'
|
||||||
|
} else if (confirmPassword !== newPassword) {
|
||||||
|
newErrors.confirmPassword = '两次密码输入不一致'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置错误状态
|
||||||
|
setErrors(newErrors)
|
||||||
|
|
||||||
|
// 如果有错误,不继续提交
|
||||||
|
if (Object.keys(newErrors).length > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true)
|
||||||
|
try {
|
||||||
|
await onConfirm(currentPassword, newPassword)
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmModal
|
||||||
|
badge="password"
|
||||||
|
cancelText="取消"
|
||||||
|
confirmText={loading ? '修改中...' : '确定'}
|
||||||
|
confirmLoading={loading}
|
||||||
|
content={
|
||||||
|
<Block className="w-full gap-[16px]">
|
||||||
|
<Block className="w-full">
|
||||||
|
<Text className="mb-[8px] text-[14px] text-black">当前密码</Text>
|
||||||
|
<Block className="relative w-full">
|
||||||
|
<Input
|
||||||
|
className={`w-full rounded-lg border-2 px-[12px] py-[10px] text-[14px] text-black ${
|
||||||
|
errors.currentPassword ? 'border-red-500' : 'border-black'
|
||||||
|
}`}
|
||||||
|
placeholder="请输入当前密码"
|
||||||
|
placeholderTextColor="#9CA3AF"
|
||||||
|
value={currentPassword}
|
||||||
|
onChangeText={(text) => {
|
||||||
|
setCurrentPassword(text)
|
||||||
|
if (errors.currentPassword) {
|
||||||
|
validateCurrentPassword(text)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onBlur={() => validateCurrentPassword(currentPassword)}
|
||||||
|
secureTextEntry={!showCurrentPassword}
|
||||||
|
/>
|
||||||
|
<Block
|
||||||
|
className="absolute right-[12px] top-1/2 -translate-y-1/2"
|
||||||
|
onClick={() => setShowCurrentPassword(!showCurrentPassword)}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
color="#9CA3AF"
|
||||||
|
name={showCurrentPassword ? 'eye-off-outline' : 'eye-outline'}
|
||||||
|
size={20}
|
||||||
|
/>
|
||||||
|
</Block>
|
||||||
|
</Block>
|
||||||
|
{errors.currentPassword && (
|
||||||
|
<Text className="mt-[4px] text-[12px] text-red-500">{errors.currentPassword}</Text>
|
||||||
|
)}
|
||||||
|
</Block>
|
||||||
|
<Block className="w-full">
|
||||||
|
<Text className="mb-[8px] text-[14px] text-black">新密码</Text>
|
||||||
|
<Block className="relative w-full">
|
||||||
|
<Input
|
||||||
|
className={`w-full rounded-lg border-2 px-[12px] py-[10px] text-[14px] text-black ${
|
||||||
|
errors.newPassword ? 'border-red-500' : 'border-black'
|
||||||
|
}`}
|
||||||
|
placeholder="请输入新密码(至少6位)"
|
||||||
|
placeholderTextColor="#9CA3AF"
|
||||||
|
value={newPassword}
|
||||||
|
onChangeText={(text) => {
|
||||||
|
setNewPassword(text)
|
||||||
|
if (errors.newPassword) {
|
||||||
|
validateNewPassword(text)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onBlur={() => validateNewPassword(newPassword)}
|
||||||
|
secureTextEntry={!showNewPassword}
|
||||||
|
/>
|
||||||
|
<Block
|
||||||
|
className="absolute right-[12px] top-1/2 -translate-y-1/2"
|
||||||
|
onClick={() => setShowNewPassword(!showNewPassword)}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
color="#9CA3AF"
|
||||||
|
name={showNewPassword ? 'eye-off-outline' : 'eye-outline'}
|
||||||
|
size={20}
|
||||||
|
/>
|
||||||
|
</Block>
|
||||||
|
</Block>
|
||||||
|
{errors.newPassword && (
|
||||||
|
<Text className="mt-[4px] text-[12px] text-red-500">{errors.newPassword}</Text>
|
||||||
|
)}
|
||||||
|
</Block>
|
||||||
|
<Block className="w-full">
|
||||||
|
<Text className="mb-[8px] text-[14px] text-black">确认新密码</Text>
|
||||||
|
<Block className="relative w-full">
|
||||||
|
<Input
|
||||||
|
className={`w-full rounded-lg border-2 px-[12px] py-[10px] text-[14px] text-black ${
|
||||||
|
errors.confirmPassword ? 'border-red-500' : 'border-black'
|
||||||
|
}`}
|
||||||
|
placeholder="请再次输入新密码"
|
||||||
|
placeholderTextColor="#9CA3AF"
|
||||||
|
value={confirmPassword}
|
||||||
|
onChangeText={(text) => {
|
||||||
|
setConfirmPassword(text)
|
||||||
|
if (errors.confirmPassword) {
|
||||||
|
validateConfirmPassword(text)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onBlur={() => validateConfirmPassword(confirmPassword)}
|
||||||
|
secureTextEntry={!showConfirmPassword}
|
||||||
|
/>
|
||||||
|
<Block
|
||||||
|
className="absolute right-[12px] top-1/2 -translate-y-1/2"
|
||||||
|
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
color="#9CA3AF"
|
||||||
|
name={showConfirmPassword ? 'eye-off-outline' : 'eye-outline'}
|
||||||
|
size={20}
|
||||||
|
/>
|
||||||
|
</Block>
|
||||||
|
</Block>
|
||||||
|
{errors.confirmPassword && (
|
||||||
|
<Text className="mt-[4px] text-[12px] text-red-500">{errors.confirmPassword}</Text>
|
||||||
|
)}
|
||||||
|
</Block>
|
||||||
|
</Block>
|
||||||
|
}
|
||||||
|
title="修改密码"
|
||||||
|
onCancel={onCancel}
|
||||||
|
onConfirm={handleConfirm}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue