修复修改密码弹窗样式并拆分逻辑与悬浮说明
This commit is contained in:
parent
daa7c01116
commit
d943eb3012
@ -433,3 +433,24 @@ test("serverModal.compilesAndPreservesDeploymentFields", async () => {
|
||||
assert.ok(html.includes("nginx\n-s\nreload"));
|
||||
}
|
||||
});
|
||||
|
||||
test("changePassword.loadsScopedBaseStylesAndCompiles", async () => {
|
||||
const { readFile } = await import("node:fs/promises");
|
||||
const { parse, compileScript, compileTemplate } = await import("@vue/compiler-sfc");
|
||||
const source = await readFile(new URL("../components/ChangePassword/ChangePassword.vue", import.meta.url), "utf8");
|
||||
const { descriptor, errors } = parse(source);
|
||||
assert.deepEqual(errors, []);
|
||||
assert.ok(compileScript(descriptor, { id: "change-password" }));
|
||||
const compiled = compileTemplate({
|
||||
source: descriptor.template.content,
|
||||
filename: "ChangePassword.vue",
|
||||
id: "change-password",
|
||||
});
|
||||
assert.deepEqual(compiled.errors, []);
|
||||
assert.ok(descriptor.styles.some(style => style.scoped && style.src === "../../Dashboard/Dashboard.css"));
|
||||
assert.ok(descriptor.styles.some(style => style.scoped && style.src === "./ChangePassword.css"));
|
||||
assert.match(source, /<HelpTip>/);
|
||||
const base = await readFile(new URL("./Dashboard.css", import.meta.url), "utf8");
|
||||
assert.match(base, /\.modal-backdrop\s*\{[^}]*position:\s*fixed;/);
|
||||
assert.match(base, /\.field\s*\{/);
|
||||
});
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
.change-password-form {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.change-password-form small {
|
||||
@ -39,3 +39,13 @@
|
||||
width: min(100%, calc(100vw - 28px));
|
||||
}
|
||||
}
|
||||
|
||||
.change-password-modal .field > span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.change-password-modal .modal-actions {
|
||||
padding-top: 12px;
|
||||
}
|
||||
|
||||
@ -0,0 +1,85 @@
|
||||
import { onBeforeUnmount, ref } from "vue";
|
||||
|
||||
export function useChangePassword() {
|
||||
const visible = ref(false);
|
||||
const submitting = ref(false);
|
||||
const success = ref(false);
|
||||
const error = ref("");
|
||||
const notice = ref("");
|
||||
const form = ref({
|
||||
currentPassword: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
});
|
||||
let redirectTimer = 0;
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
success.value = false;
|
||||
error.value = "";
|
||||
notice.value = "";
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (submitting.value || success.value) {
|
||||
return;
|
||||
}
|
||||
visible.value = false;
|
||||
error.value = "";
|
||||
notice.value = "";
|
||||
form.value = {
|
||||
currentPassword: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
};
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (submitting.value) {
|
||||
return;
|
||||
}
|
||||
error.value = "";
|
||||
notice.value = "";
|
||||
if (form.value.newPassword !== form.value.confirmPassword) {
|
||||
error.value = "两次输入的新密码不一致。";
|
||||
return;
|
||||
}
|
||||
submitting.value = true;
|
||||
try {
|
||||
const response = await fetch("/api/v1/auth/password", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
current_password: form.value.currentPassword,
|
||||
new_password: form.value.newPassword,
|
||||
confirm_password: form.value.confirmPassword,
|
||||
}),
|
||||
});
|
||||
const result = await response.json().catch(() => ({}));
|
||||
if (!response.ok) {
|
||||
throw new Error(result.error || "修改密码失败,请稍后重试。");
|
||||
}
|
||||
success.value = true;
|
||||
notice.value = result.message || "密码修改成功,请重新登录。";
|
||||
redirectTimer = window.setTimeout(() => {
|
||||
window.location.href = "/login";
|
||||
}, 1600);
|
||||
} catch (submitError) {
|
||||
error.value = submitError.message || "修改密码失败,请稍后重试。";
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (redirectTimer) {
|
||||
window.clearTimeout(redirectTimer);
|
||||
}
|
||||
});
|
||||
|
||||
return { visible, submitting, success, error, notice, form, open, close, submit };
|
||||
}
|
||||
@ -1,85 +1,18 @@
|
||||
<script setup>
|
||||
import { onBeforeUnmount, ref } from "vue";
|
||||
import HelpTip from "../HelpTip/HelpTip.vue";
|
||||
import { useChangePassword } from "./ChangePassword.js";
|
||||
|
||||
const visible = ref(false);
|
||||
const submitting = ref(false);
|
||||
const success = ref(false);
|
||||
const error = ref("");
|
||||
const notice = ref("");
|
||||
const form = ref({
|
||||
currentPassword: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
});
|
||||
let redirectTimer = 0;
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
success.value = false;
|
||||
error.value = "";
|
||||
notice.value = "";
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (submitting.value || success.value) {
|
||||
return;
|
||||
}
|
||||
visible.value = false;
|
||||
error.value = "";
|
||||
notice.value = "";
|
||||
form.value = {
|
||||
currentPassword: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
};
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (submitting.value) {
|
||||
return;
|
||||
}
|
||||
error.value = "";
|
||||
notice.value = "";
|
||||
if (form.value.newPassword !== form.value.confirmPassword) {
|
||||
error.value = "两次输入的新密码不一致。";
|
||||
return;
|
||||
}
|
||||
submitting.value = true;
|
||||
try {
|
||||
const response = await fetch("/api/v1/auth/password", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
credentials: "include",
|
||||
body: JSON.stringify({
|
||||
current_password: form.value.currentPassword,
|
||||
new_password: form.value.newPassword,
|
||||
confirm_password: form.value.confirmPassword,
|
||||
}),
|
||||
});
|
||||
const result = await response.json().catch(() => ({}));
|
||||
if (!response.ok) {
|
||||
throw new Error(result.error || "修改密码失败,请稍后重试。");
|
||||
}
|
||||
success.value = true;
|
||||
notice.value = result.message || "密码修改成功,请重新登录。";
|
||||
redirectTimer = window.setTimeout(() => {
|
||||
window.location.href = "/login";
|
||||
}, 1600);
|
||||
} catch (submitError) {
|
||||
error.value = submitError.message || "修改密码失败,请稍后重试。";
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (redirectTimer) {
|
||||
window.clearTimeout(redirectTimer);
|
||||
}
|
||||
});
|
||||
const {
|
||||
visible,
|
||||
submitting,
|
||||
success,
|
||||
error,
|
||||
notice,
|
||||
form,
|
||||
open,
|
||||
close,
|
||||
submit,
|
||||
} = useChangePassword();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -123,7 +56,7 @@ onBeforeUnmount(() => {
|
||||
/>
|
||||
</label>
|
||||
<label class="field">
|
||||
<span>新密码 <small>8 到 12 个字符,需同时包含字母和数字</small></span>
|
||||
<span>新密码 <HelpTip>8 到 12 个字符,需同时包含字母和数字</HelpTip></span>
|
||||
<input
|
||||
v-model="form.newPassword"
|
||||
type="password"
|
||||
@ -168,4 +101,5 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style src="./ChangePassword.css"></style>
|
||||
<style scoped src="../../Dashboard/Dashboard.css"></style>
|
||||
<style scoped src="./ChangePassword.css"></style>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user