Files
ss-tiku-manage-h5/src/pages/mine/password-change.vue
2026-01-29 17:39:43 +08:00

501 lines
11 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="password-change-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">密码修改</view>
<view class="header-right" @click="savePassword">
<view class="save-btn">保存</view>
</view>
</view>
<!-- 密码修改表单 -->
<view class="form-section">
<view class="form-group">
<view class="form-label">当前密码</view>
<view class="form-control">
<input
v-model="passwordForm.oldPassword"
class="form-input"
placeholder="请输入当前密码"
maxlength="20"
:type="showPassword ? 'text' : 'password'"
/>
<view class="password-toggle" @click="togglePassword">
{{ showPassword ? '🙈' : '👁' }}
</view>
</view>
</view>
<view class="form-group">
<view class="form-label">新密码</view>
<view class="form-control">
<input
v-model="passwordForm.newPassword"
class="form-input"
placeholder="请输入新密码"
maxlength="20"
:type="showPassword ? 'text' : 'password'"
/>
<view class="password-toggle" @click="togglePassword">
{{ showPassword ? '🙈' : '👁' }}
</view>
</view>
</view>
<view class="form-group">
<view class="form-label">确认新密码</view>
<view class="form-control">
<input
v-model="passwordForm.confirmPassword"
class="form-input"
placeholder="请再次输入新密码"
maxlength="20"
:type="showPassword ? 'text' : 'password'"
/>
<view class="password-toggle" @click="togglePassword">
{{ showPassword ? '🙈' : '👁' }}
</view>
</view>
</view>
</view>
<!-- 密码强度提示 -->
<view class="strength-section">
<view class="section-title">密码强度要求</view>
<view class="strength-tips">
<view class="tip-item" :class="{ active: passwordForm.newPassword.length >= 8 }">
密码长度至少8位
</view>
<view class="tip-item" :class="{ active: /[A-Z]/.test(passwordForm.newPassword) }">
包含大写字母
</view>
<view class="tip-item" :class="{ active: /[a-z]/.test(passwordForm.newPassword) }">
包含小写字母
</view>
<view class="tip-item" :class="{ active: /[0-9]/.test(passwordForm.newPassword) }">
包含数字
</view>
<view class="tip-item" :class="{ active: /[!@#$%^&*(),.?":{}|<>]/.test(passwordForm.newPassword) }">
• 包含特殊字符
</view>
</view>
<!-- 密码强度指示器 -->
<view class="strength-indicator">
<view class="strength-label">密码强度:</view>
<view class="strength-bars">
<view
class="strength-bar"
:class="getStrengthClass()"
></view>
<view class="strength-text">{{ getStrengthText() }}</view>
</view>
</view>
</view>
<!-- 操作提示 -->
<view class="operation-tips">
<view class="tips-title">操作提示</view>
<view class="tips-content">
<view class="tip-item">• 请确保新密码符合强度要求</view>
<view class="tip-item">• 密码修改后需要重新登录</view>
<view class="tip-item">• 如忘记当前密码,请联系管理员重置</view>
<view class="tip-item">• 请妥善保管您的密码,不要泄露给他人</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from "vue"
// 密码表单
const passwordForm = ref({
oldPassword: '',
newPassword: '',
confirmPassword: ''
})
// 显示密码
const showPassword = ref(false)
// 切换密码显示状态
function togglePassword() {
showPassword.value = !showPassword.value
}
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 获取密码强度等级
function getPasswordStrength() {
const password = passwordForm.value.newPassword
if (!password) return 0
let strength = 0
if (password.length >= 8) strength++
if (/[A-Z]/.test(password)) strength++
if (/[a-z]/.test(password)) strength++
if (/[0-9]/.test(password)) strength++
if (/[!@#$%^&*(),.?":{}|<>]/.test(password)) strength++
return strength
}
// 获取密码强度样式类
function getStrengthClass() {
const strength = getPasswordStrength()
switch (strength) {
case 0: return 'weak'
case 1: return 'weak'
case 2: return 'medium'
case 3: return 'medium'
case 4: return 'strong'
case 5: return 'strong'
default: return 'weak'
}
}
// 获取密码强度文本
function getStrengthText() {
const strength = getPasswordStrength()
switch (strength) {
case 0: return '未设置'
case 1: return '弱'
case 2: return '较弱'
case 3: return '中等'
case 4: return '强'
case 5: return '很强'
default: return '未设置'
}
}
// 验证密码
function validatePassword() {
if (!passwordForm.value.oldPassword) {
uni.showToast({ title: '请输入当前密码', icon: 'none' })
return false
}
if (!passwordForm.value.newPassword) {
uni.showToast({ title: '请输入新密码', icon: 'none' })
return false
}
if (passwordForm.value.newPassword.length < 8) {
uni.showToast({ title: '新密码长度至少8位', icon: 'none' })
return false
}
if (passwordForm.value.newPassword !== passwordForm.value.confirmPassword) {
uni.showToast({ title: '两次输入的新密码不一致', icon: 'none' })
return false
}
if (passwordForm.value.newPassword === passwordForm.value.oldPassword) {
uni.showToast({ title: '新密码不能与当前密码相同', icon: 'none' })
return false
}
return true
}
// 保存密码
function savePassword() {
if (!validatePassword()) {
return
}
// 实际项目中应调用接口修改密码
uni.showLoading({ title: '修改中...' })
setTimeout(() => {
uni.hideLoading()
uni.showModal({
title: '修改成功',
content: '密码修改成功,请重新登录',
showCancel: false,
success: function() {
// 实际项目中应跳转到登录页面
uni.redirectTo({
url: '/pages/login/index'
})
}
})
}, 1000)
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.password-change-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
text-align: right;
}
.save-btn {
font-size: 28rpx;
color: #409eff;
font-weight: 600;
cursor: pointer;
}
/* 表单区域 */
.form-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.form-group {
margin-bottom: 32rpx;
}
.form-label {
font-size: 28rpx;
font-weight: 600;
color: #303133;
margin-bottom: 12rpx;
line-height: 1.2;
}
.form-control {
position: relative;
}
.form-input {
width: 100%;
height: 80rpx;
padding: 0 100rpx 0 24rpx;
font-size: 28rpx;
color: #303133;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
background-color: #f9f9f9;
box-sizing: border-box;
}
.form-input:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
.password-toggle {
position: absolute;
right: 24rpx;
top: 50%;
transform: translateY(-50%);
font-size: 32rpx;
cursor: pointer;
}
/* 密码强度 */
.strength-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 24rpx;
padding-left: 12rpx;
border-left: 8rpx solid #409eff;
line-height: 1.2;
}
.strength-tips {
margin-bottom: 32rpx;
}
.tip-item {
font-size: 24rpx;
color: #606266;
margin-bottom: 12rpx;
line-height: 1.4;
}
.tip-item.active {
color: #67c23a;
}
.strength-indicator {
display: flex;
align-items: center;
padding: 20rpx;
background-color: #f9f9f9;
border-radius: 8rpx;
}
.strength-label {
font-size: 24rpx;
color: #606266;
margin-right: 16rpx;
}
.strength-bars {
flex: 1;
display: flex;
align-items: center;
}
.strength-bar {
height: 8rpx;
border-radius: 4rpx;
flex: 1;
margin-right: 8rpx;
}
.strength-bar.weak {
background-color: #f56c6c;
}
.strength-bar.medium {
background-color: #e6a23c;
}
.strength-bar.strong {
background-color: #67c23a;
}
.strength-text {
font-size: 24rpx;
font-weight: 600;
margin-left: 16rpx;
}
.strength-text.weak {
color: #f56c6c;
}
.strength-text.medium {
color: #e6a23c;
}
.strength-text.strong {
color: #67c23a;
}
/* 操作提示 */
.operation-tips {
padding: 32rpx;
background-color: #ecf5ff;
margin: 0 16rpx 32rpx;
border-radius: 16rpx;
border-left: 8rpx solid #409eff;
}
.tips-title {
font-size: 28rpx;
font-weight: bold;
color: #409eff;
margin-bottom: 16rpx;
line-height: 1.2;
}
.tips-content {
font-size: 24rpx;
color: #606266;
line-height: 1.6;
}
/* 响应式设计 */
@media screen and (min-width: 500px) {
.password-change-container {
max-width: 900px;
margin: 0 auto;
}
.form-section {
padding: 40rpx;
}
.form-group {
margin-bottom: 40rpx;
}
.form-label {
font-size: 32rpx;
margin-bottom: 16rpx;
}
.form-input {
height: 100rpx;
font-size: 32rpx;
padding: 0 120rpx 0 32rpx;
}
.strength-section {
padding: 40rpx;
}
.tip-item {
font-size: 28rpx;
}
.operation-tips {
padding: 40rpx;
}
}
</style>