jcloud/dashboard/src2/components/settings/profile/ResetPasswordDialog.vue

303 lines
7.3 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<Dialog v-model="showDialog" :options="{ title: '重置密码' }">
<template #body-content>
<div class="space-y-4">
<div v-if="!isResetMode" class="space-y-4">
<FormControl
v-model="oldPassword"
type="password"
:fieldtype="'Password'"
:label="'当前密码'"
:fieldname="'old_password'"
:reqd="1"
:placeholder="'请输入当前密码'"
/>
</div>
<div class="space-y-4">
<FormControl
v-model="newPassword"
type="password"
:fieldtype="'Password'"
:label="'新密码'"
:fieldname="'new_password'"
:reqd="1"
:placeholder="'请输入新密码'"
/>
<div v-if="passwordStrengthMessage" class="text-sm" :class="passwordStrengthClass">
{{ passwordStrengthMessage }}
</div>
<FormControl
v-model="confirmPassword"
type="password"
:fieldtype="'Password'"
:label="'确认密码'"
:fieldname="'confirm_password'"
:reqd="1"
:placeholder="'请再次输入新密码'"
/>
<div v-if="passwordMismatchMessage" class="text-sm text-red-600">
{{ passwordMismatchMessage }}
</div>
</div>
</div>
<ErrorMessage class="mt-2" :message="error" />
</template>
<template #actions>
<div class="flex gap-2 w-full">
<Button
variant="outline"
class="flex-1"
@click="hide"
>
取消
</Button>
<Button
variant="solid"
class="flex-1"
:loading="isLoading"
:disabled="!isFormValid"
@click="onConfirm"
>
确认
</Button>
</div>
</template>
</Dialog>
</template>
<script>
import { ErrorMessage, FormControl } from 'jingrow-ui';
import { toast } from 'vue-sonner';
export default {
name: 'ResetPasswordDialog',
props: {
isResetMode: {
type: Boolean,
default: false
},
modelValue: {
type: Boolean,
default: false
}
},
emits: ['update:modelValue'],
expose: ['show', 'hide'],
data() {
return {
error: null,
isLoading: false,
oldPassword: '',
newPassword: '',
confirmPassword: '',
passwordStrengthMessage: '',
passwordStrengthClass: '',
passwordMismatchMessage: '',
passwordStrengthTimeout: null
};
},
computed: {
showDialog: {
get() {
return this.modelValue;
},
set(value) {
this.$emit('update:modelValue', value);
}
},
isFormValid() {
const hasNewPassword = this.newPassword && this.newPassword.length > 0;
const hasConfirmPassword = this.confirmPassword && this.confirmPassword.length > 0;
const passwordsMatch = this.newPassword === this.confirmPassword;
const passwordsDifferent = this.oldPassword !== this.newPassword;
if (this.isResetMode) {
return hasNewPassword && hasConfirmPassword && passwordsMatch;
} else {
return this.oldPassword && hasNewPassword && hasConfirmPassword && passwordsMatch && passwordsDifferent;
}
}
},
components: { FormControl, ErrorMessage },
watch: {
newPassword() {
this.checkPasswordStrength();
},
confirmPassword() {
this.checkPasswordMismatch();
},
oldPassword() {
this.checkPasswordMismatch();
}
},
methods: {
checkPasswordStrength() {
if (this.passwordStrengthTimeout) {
clearTimeout(this.passwordStrengthTimeout);
}
this.passwordStrengthTimeout = setTimeout(() => {
if (!this.newPassword) {
this.passwordStrengthMessage = '';
return;
}
// 调用密码强度检查API
this.$resources.checkPasswordStrength.submit({
new_password: this.newPassword,
old_password: this.oldPassword
});
}, 200);
},
checkPasswordMismatch() {
if (this.oldPassword && this.newPassword && this.oldPassword === this.newPassword) {
this.passwordMismatchMessage = '新密码不能与当前密码相同';
this.passwordStrengthMessage = '';
} else if (this.confirmPassword && this.newPassword !== this.confirmPassword) {
this.passwordMismatchMessage = '两次输入的密码不一致';
this.passwordStrengthMessage = '';
} else {
this.passwordMismatchMessage = '';
}
},
async onConfirm() {
this.error = null;
if (!this.validateForm()) {
return;
}
this.isLoading = true;
try {
await this.$resources.updatePassword.submit({
old_password: this.oldPassword,
new_password: this.newPassword,
confirm_password: this.confirmPassword,
logout_all_sessions: 1
});
} catch (error) {
this.error = error.message || '密码更新失败';
} finally {
this.isLoading = false;
}
},
validateForm() {
if (!this.isResetMode && !this.oldPassword) {
this.error = '请输入当前密码';
return false;
}
if (!this.newPassword) {
this.error = '请输入新密码';
return false;
}
if (this.newPassword !== this.confirmPassword) {
this.error = '两次输入的密码不一致';
return false;
}
if (!this.isResetMode && this.oldPassword === this.newPassword) {
this.error = '新密码不能与当前密码相同';
return false;
}
return true;
},
show() {
this.showDialog = true;
this.resetForm();
},
hide() {
this.showDialog = false;
this.resetForm();
},
resetForm() {
this.oldPassword = '';
this.newPassword = '';
this.confirmPassword = '';
this.error = null;
this.passwordStrengthMessage = '';
this.passwordStrengthClass = '';
this.passwordMismatchMessage = '';
if (this.passwordStrengthTimeout) {
clearTimeout(this.passwordStrengthTimeout);
this.passwordStrengthTimeout = null;
}
}
},
resources: {
checkPasswordStrength() {
return {
url: 'jingrow.core.pagetype.user.user.test_password_strength',
params: {
old_password: this.oldPassword,
new_password: this.newPassword
},
onSuccess(data) {
if (data.message) {
const score = data.message.score;
const feedback = data.message.feedback;
if (feedback.password_policy_validation_passed) {
this.passwordStrengthMessage = '密码强度良好 👍';
this.passwordStrengthClass = 'text-green-600';
} else {
let message = [];
if (feedback.suggestions && feedback.suggestions.length) {
message = message.concat(feedback.suggestions);
} else if (feedback.warning) {
message.push(feedback.warning);
}
message.push('提示:密码应包含符号、数字和大写字母');
this.passwordStrengthMessage = message.join(' ');
this.passwordStrengthClass = 'text-red-600';
}
}
},
onError() {
this.passwordStrengthMessage = '';
}
};
},
updatePassword() {
return {
url: 'jingrow.core.pagetype.user.user.update_password',
onSuccess(data) {
// 显示成功提示5秒后自动消失
toast.success('密码更新成功', {
duration: 3000,
description: '您的密码已更新'
});
// 立即关闭对话框
this.hide();
// 如果有重定向消息,在关闭对话框后重定向
if (data.message) {
setTimeout(() => {
window.location.href = data.message;
}, 1000);
}
},
onError(error) {
if (error.status === 401) {
this.error = '当前密码不正确';
} else {
this.error = error.message || '密码更新失败';
}
}
};
}
}
};
</script>