350 行
15 KiB
HTML
350 行
15 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8"/>
|
|
<title>重置密码</title>
|
|
<link rel="stylesheet" type="text/css" href="__PUBLIC__/layui-v2.4.3/layui/css/layui.css"/>
|
|
<link rel="stylesheet" type="text/css" href="__PUBLIC__/vue/element-ui.css?v=2.13.2">
|
|
<script type="text/javascript" charset="utf-8" src="__PUBLIC__/vue/js/vue2.5.16.js"></script>
|
|
<script type="text/javascript" charset="utf-8" src="__PUBLIC__/vue/element-ui.js?v=2.13.2"></script>
|
|
<script type="text/javascript" charset="utf-8" src="__PUBLIC__/jquery/js/jquery-3.2.1.min.js"></script>
|
|
<script type="text/javascript" charset="utf-8" src="__PUBLIC__/layui-v2.4.3/layui/layui.js"></script>
|
|
<style>
|
|
body { margin: 0; padding: 20px; background: #f5f7fa; }
|
|
.reset-section { margin-bottom: 20px; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.1); }
|
|
.reset-section-title { font-size: 16px; font-weight: bold; color: #303133; margin-bottom: 15px; padding-left: 10px; border-left: 4px solid #409EFF; }
|
|
.rider-info { display: flex; align-items: center; margin-bottom: 20px; padding: 15px; background: #f8f9fa; border-radius: 8px; }
|
|
.rider-avatar { width: 60px; height: 60px; border-radius: 50%; object-fit: cover; margin-right: 15px; }
|
|
.rider-details { flex: 1; }
|
|
.rider-name { font-size: 16px; font-weight: bold; color: #303133; margin-bottom: 4px; }
|
|
.rider-phone { color: #606266; font-size: 14px; }
|
|
.password-tips { background: #fff7e6; border: 1px solid #ffd591; border-radius: 6px; padding: 12px; margin-bottom: 20px; }
|
|
.password-tips .el-icon-warning { color: #faad14; margin-right: 8px; }
|
|
.password-tips-title { color: #d48806; font-weight: bold; margin-bottom: 8px; }
|
|
.password-tips-content { color: #ad6800; font-size: 14px; line-height: 1.5; }
|
|
.password-strength { margin-top: 8px; }
|
|
.strength-bar { height: 6px; border-radius: 3px; background: #f0f0f0; margin-top: 8px; overflow: hidden; }
|
|
.strength-fill { height: 100%; transition: all 0.3s; }
|
|
.strength-weak { background: #ff4d4f; width: 33%; }
|
|
.strength-medium { background: #faad14; width: 66%; }
|
|
.strength-strong { background: #52c41a; width: 100%; }
|
|
.strength-text { font-size: 12px; margin-top: 4px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="PasswordResetApp" v-cloak>
|
|
<div v-loading="loading">
|
|
<!-- 骑手信息 -->
|
|
<div class="reset-section">
|
|
<div class="reset-section-title">骑手信息</div>
|
|
<div class="rider-info">
|
|
<img v-if="riderInfo.rider_avatar" :src="riderInfo.rider_avatar" class="rider-avatar" alt="骑手头像">
|
|
<div v-else style="width: 60px; height: 60px; background: #f5f7fa; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: #c0c4cc; margin-right: 15px;">
|
|
<i class="el-icon-user" style="font-size: 24px;"></i>
|
|
</div>
|
|
<div class="rider-details">
|
|
<div class="rider-name">{{ riderInfo.rider_name }}</div>
|
|
<div class="rider-phone">手机号:{{ riderInfo.rider_phone }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 密码重置表单 -->
|
|
<div class="reset-section">
|
|
<div class="reset-section-title">重置密码</div>
|
|
|
|
<!-- 密码安全提示 -->
|
|
<div class="password-tips">
|
|
<div class="password-tips-title">
|
|
<i class="el-icon-warning"></i>
|
|
密码安全提示
|
|
</div>
|
|
<div class="password-tips-content">
|
|
• 密码长度至少8位,最多20位<br>
|
|
• 必须包含字母和数字<br>
|
|
• 建议包含特殊字符以提高安全性<br>
|
|
• 不要使用过于简单的密码组合
|
|
</div>
|
|
</div>
|
|
|
|
<el-form :model="passwordForm" :rules="passwordRules" ref="passwordForm" label-width="120px">
|
|
<el-form-item label="重置方式" prop="resetType">
|
|
<el-radio-group v-model="passwordForm.resetType">
|
|
<el-radio label="manual">手动设置密码</el-radio>
|
|
<el-radio label="auto">系统生成密码</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
|
|
<template v-if="passwordForm.resetType === 'manual'">
|
|
<el-form-item label="新密码" prop="newPassword">
|
|
<el-input
|
|
v-model="passwordForm.newPassword"
|
|
type="password"
|
|
placeholder="请输入新密码"
|
|
show-password
|
|
@input="checkPasswordStrength">
|
|
</el-input>
|
|
<div class="password-strength" v-if="passwordForm.newPassword">
|
|
<div class="strength-bar">
|
|
<div :class="['strength-fill', strengthClass]"></div>
|
|
</div>
|
|
<div :class="['strength-text', strengthTextClass]">
|
|
密码强度:{{ strengthText }}
|
|
</div>
|
|
</div>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="确认密码" prop="confirmPassword">
|
|
<el-input
|
|
v-model="passwordForm.confirmPassword"
|
|
type="password"
|
|
placeholder="请再次输入新密码"
|
|
show-password>
|
|
</el-input>
|
|
</el-form-item>
|
|
</template>
|
|
|
|
<template v-if="passwordForm.resetType === 'auto'">
|
|
<el-form-item label="生成密码">
|
|
<el-input
|
|
v-model="generatedPassword"
|
|
readonly
|
|
placeholder="点击生成密码按钮">
|
|
<el-button slot="append" @click="generatePassword" :loading="generating">
|
|
{{ generatedPassword ? '重新生成' : '生成密码' }}
|
|
</el-button>
|
|
</el-input>
|
|
</el-form-item>
|
|
</template>
|
|
|
|
|
|
</el-form>
|
|
</div>
|
|
|
|
<!-- 操作按钮 -->
|
|
<div style="text-align: center; margin-top: 30px;">
|
|
<el-button @click="resetForm">重 置</el-button>
|
|
<el-button type="primary" @click="submitReset" :loading="submitting">确认重置</el-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
new Vue({
|
|
el: '#PasswordResetApp',
|
|
data() {
|
|
// 自定义密码验证器
|
|
const validatePassword = (rule, value, callback) => {
|
|
if (!value) {
|
|
callback(new Error('请输入新密码'));
|
|
} else if (value.length < 8 || value.length > 20) {
|
|
callback(new Error('密码长度必须在8-20位之间'));
|
|
} else if (!/(?=.*[a-zA-Z])(?=.*\d)/.test(value)) {
|
|
callback(new Error('密码必须包含字母和数字'));
|
|
} else {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
const validateConfirmPassword = (rule, value, callback) => {
|
|
if (!value) {
|
|
callback(new Error('请确认密码'));
|
|
} else if (value !== this.passwordForm.newPassword) {
|
|
callback(new Error('两次输入的密码不一致'));
|
|
} else {
|
|
callback();
|
|
}
|
|
};
|
|
|
|
return {
|
|
loading: false,
|
|
submitting: false,
|
|
generating: false,
|
|
riderInfo: {},
|
|
generatedPassword: '',
|
|
passwordStrength: 0,
|
|
passwordForm: {
|
|
id: null,
|
|
resetType: 'manual',
|
|
newPassword: '',
|
|
confirmPassword: ''
|
|
},
|
|
passwordRules: {
|
|
resetType: [
|
|
{ required: true, message: '请选择重置方式', trigger: 'change' }
|
|
],
|
|
newPassword: [
|
|
{ validator: validatePassword, trigger: 'blur' }
|
|
],
|
|
confirmPassword: [
|
|
{ validator: validateConfirmPassword, trigger: 'blur' }
|
|
]
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
strengthClass() {
|
|
if (this.passwordStrength <= 1) return 'strength-weak';
|
|
if (this.passwordStrength <= 2) return 'strength-medium';
|
|
return 'strength-strong';
|
|
},
|
|
strengthText() {
|
|
if (this.passwordStrength <= 1) return '弱';
|
|
if (this.passwordStrength <= 2) return '中';
|
|
return '强';
|
|
},
|
|
strengthTextClass() {
|
|
if (this.passwordStrength <= 1) return 'color: #ff4d4f';
|
|
if (this.passwordStrength <= 2) return 'color: #faad14';
|
|
return 'color: #52c41a';
|
|
}
|
|
},
|
|
mounted() {
|
|
// 获取URL参数中的骑手ID
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const riderId = urlParams.get('id');
|
|
if (riderId) {
|
|
this.passwordForm.id = riderId;
|
|
this.loadRiderInfo(riderId);
|
|
}
|
|
},
|
|
methods: {
|
|
async loadRiderInfo(id) {
|
|
this.loading = true;
|
|
try {
|
|
const response = await $.ajax({
|
|
url: '/Retail/Rider/getRiderInfo',
|
|
type: 'POST',
|
|
data: { id: id },
|
|
dataType: 'json'
|
|
});
|
|
|
|
if (response.code === 1) {
|
|
this.riderInfo = response.data;
|
|
} else {
|
|
this.$message.error(response.message || '获取骑手信息失败');
|
|
}
|
|
} catch (error) {
|
|
this.$message.error('网络错误,请重试');
|
|
console.error('获取骑手信息异常:', error);
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
|
|
checkPasswordStrength(password) {
|
|
let strength = 0;
|
|
|
|
// 长度检查
|
|
if (password.length >= 8) strength++;
|
|
|
|
// 复杂度检查
|
|
if (/[a-z]/.test(password)) strength++;
|
|
if (/[A-Z]/.test(password)) strength++;
|
|
if (/\d/.test(password)) strength++;
|
|
if (/[^a-zA-Z\d]/.test(password)) strength++;
|
|
|
|
// 综合评分
|
|
if (strength >= 4) this.passwordStrength = 3;
|
|
else if (strength >= 3) this.passwordStrength = 2;
|
|
else this.passwordStrength = 1;
|
|
},
|
|
|
|
generatePassword() {
|
|
this.generating = true;
|
|
|
|
// 模拟生成过程
|
|
setTimeout(() => {
|
|
const chars = 'ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789!@#$%&*';
|
|
const length = 12;
|
|
let password = '';
|
|
|
|
// 确保包含各种字符类型
|
|
password += 'ABCDEFGHJKMNPQRSTUVWXYZ'[Math.floor(Math.random() * 23)]; // 大写字母
|
|
password += 'abcdefghjkmnpqrstuvwxyz'[Math.floor(Math.random() * 23)]; // 小写字母
|
|
password += '23456789'[Math.floor(Math.random() * 8)]; // 数字
|
|
password += '!@#$%&*'[Math.floor(Math.random() * 7)]; // 特殊字符
|
|
|
|
// 填充剩余位数
|
|
for (let i = 4; i < length; i++) {
|
|
password += chars[Math.floor(Math.random() * chars.length)];
|
|
}
|
|
|
|
// 打乱顺序
|
|
this.generatedPassword = password.split('').sort(() => Math.random() - 0.5).join('');
|
|
this.generating = false;
|
|
}, 800);
|
|
},
|
|
|
|
async submitReset() {
|
|
this.$refs.passwordForm.validate(async (valid) => {
|
|
if (!valid) return;
|
|
|
|
// 检查密码设置
|
|
let finalPassword = '';
|
|
if (this.passwordForm.resetType === 'manual') {
|
|
finalPassword = this.passwordForm.newPassword;
|
|
} else {
|
|
if (!this.generatedPassword) {
|
|
this.$message.error('请先生成密码');
|
|
return;
|
|
}
|
|
finalPassword = this.generatedPassword;
|
|
}
|
|
|
|
this.submitting = true;
|
|
try {
|
|
const response = await $.ajax({
|
|
url: '/Retail/Rider/resetPassword',
|
|
type: 'POST',
|
|
data: {
|
|
id: this.passwordForm.id,
|
|
new_password: finalPassword
|
|
},
|
|
dataType: 'json'
|
|
});
|
|
|
|
if (response.code === 1) {
|
|
this.$message.success('密码重置成功');
|
|
// 显示新密码(如果是生成的)
|
|
if (this.passwordForm.resetType === 'auto') {
|
|
this.$alert(`新密码:${finalPassword}`, '密码重置成功', {
|
|
confirmButtonText: '确定',
|
|
type: 'success'
|
|
});
|
|
}
|
|
// 通知父窗口刷新
|
|
if (parent && parent.layer) {
|
|
parent.layer.closeAll();
|
|
if (parent.vm && parent.vm.loadRiders) {
|
|
parent.vm.loadRiders();
|
|
}
|
|
}
|
|
} else {
|
|
this.$message.error(response.message || '密码重置失败');
|
|
}
|
|
} catch (error) {
|
|
this.$message.error('网络错误,请重试');
|
|
console.error('密码重置异常:', error);
|
|
} finally {
|
|
this.submitting = false;
|
|
}
|
|
});
|
|
},
|
|
|
|
resetForm() {
|
|
this.$refs.passwordForm.resetFields();
|
|
this.generatedPassword = '';
|
|
this.passwordStrength = 0;
|
|
this.passwordForm = {
|
|
id: this.passwordForm.id,
|
|
resetType: 'manual',
|
|
newPassword: '',
|
|
confirmPassword: ''
|
|
};
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |