Files
geo/apps/ops-web/src/views/ProfileView.vue
T
root f5254f6a27 feat(ops-web): add operations console frontend
Vue 3 + Ant Design Vue SPA scaffold for the internal ops console. Ships
the auth, account list, and audit log views that consume the new ops-api
endpoints, plus the nginx/vite/typecheck plumbing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 11:33:17 +08:00

82 lines
3.0 KiB
Vue

<template>
<h2 class="ops-page-title">个人资料</h2>
<div class="ops-card" style="max-width: 640px; margin-bottom: 24px;">
<h3 style="margin-top: 0; margin-bottom: 16px; font-size: 16px; font-weight: 600;">账号信息</h3>
<a-descriptions :column="1" bordered>
<a-descriptions-item label="ID">{{ auth.operator?.id }}</a-descriptions-item>
<a-descriptions-item label="账号">{{ auth.operator?.username }}</a-descriptions-item>
<a-descriptions-item label="姓名">{{ auth.operator?.display_name }}</a-descriptions-item>
<a-descriptions-item label="邮箱">{{ auth.operator?.email || "—" }}</a-descriptions-item>
<a-descriptions-item label="角色">{{ auth.operator?.role }}</a-descriptions-item>
<a-descriptions-item label="状态">
<a-tag :color="auth.operator?.status === 'active' ? 'green' : 'red'">
{{ auth.operator?.status === "active" ? "启用" : "停用" }}
</a-tag>
</a-descriptions-item>
</a-descriptions>
</div>
<div class="ops-card" style="max-width: 640px">
<h3 style="margin-top: 0; margin-bottom: 16px; font-size: 16px; font-weight: 600;">修改密码</h3>
<a-form layout="vertical" :model="form" @submit.prevent="onSubmit">
<a-form-item label="原密码" required>
<a-input-password v-model:value="form.oldPassword" autocomplete="current-password" />
</a-form-item>
<a-form-item label="新密码" required help="至少 8 位">
<a-input-password v-model:value="form.newPassword" autocomplete="new-password" />
</a-form-item>
<a-form-item label="确认新密码" required>
<a-input-password v-model:value="form.confirmPassword" autocomplete="new-password" />
</a-form-item>
<a-button type="primary" html-type="submit" :loading="loading">提交</a-button>
</a-form>
</div>
</template>
<script setup lang="ts">
import { message } from "ant-design-vue";
import { reactive, ref } from "vue";
import { OpsApiError, http } from "@/lib/http";
import { useAuthStore } from "@/stores/auth";
const auth = useAuthStore();
const form = reactive({
oldPassword: "",
newPassword: "",
confirmPassword: "",
});
const loading = ref(false);
async function onSubmit() {
if (!form.oldPassword || form.newPassword.length < 8) {
message.warning("请输入原密码,并将新密码设为至少 8 位");
return;
}
if (form.newPassword !== form.confirmPassword) {
message.warning("两次输入的新密码不一致");
return;
}
loading.value = true;
try {
await http.post("/auth/password", {
old_password: form.oldPassword,
new_password: form.newPassword,
});
message.success("密码已更新,请使用新密码重新登录");
auth.logout();
// router redirect handled by 401 interceptor or next route guard
if (typeof window !== "undefined") window.location.href = "/login";
} catch (error) {
if (error instanceof OpsApiError) {
message.error(error.detail || error.message);
}
} finally {
loading.value = false;
}
}
</script>