feat(system): 完成前端系统管理(布局框架、三个管理页面、e2e)

- BasicLayout:侧边栏/顶栏/面包屑/移动端抽屉;菜单从路由表派生;
  路由守卫新增 requiresAdmin 层(菜单隐藏 + 直连 URL 弹回)
- 用户/角色/日志三个页面:分页请求序号防竞态、确认动作流抽 useConfirmAction、
  时间范围配 default-time、日志详情按需懒加载并缓存
- 空 catch 统一改 handledError 显式声明;词表/选项常量集中(与后端对齐),
  「停用」文案全站统一为「禁用」
- 品牌色提升为全局 token,Element Plus 主色指向赭金
- e2e:公共工具抽 common.py;系统管理 13 项(含详情懒加载脱敏断言),
  管理员密码改 E2E_ADMIN_PASSWORD 环境变量;login_flow 8 项回归通过

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
liuwenxinandClaude Code committed 2026-10-10 16:28:53 +08:00
1 parent c83287819a
commit 8355e0cc7d
26 files changed
+2785 -180

No files matched your search

+34 -83
View File
@@ -1,98 +1,49 @@
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/store/user'
import { formatDateTime } from '@/utils/format'
const router = useRouter()
/**
* 首页:登录链路验证页。
*
* 顶部栏(用户信息、退出登录)已由 BasicLayout 提供,本页只保留内容区;
* 用户名等字段的展示是端到端脚本的断言对象,调整时需同步 e2e。
*/
const userStore = useUserStore()
async function handleLogout(): Promise<void> {
await userStore.logout()
ElMessage.success('已退出登录')
await router.replace('/login')
}
</script>
<template>
<el-container class="layout">
<el-header class="layout-header">
<span class="layout-title">衍水集团营销人员工资管理系统</span>
<div class="layout-user">
<el-tag v-for="role in userStore.roles" :key="role" size="small" type="info">
{{ role }}
</el-tag>
<span class="layout-username">{{ userStore.displayName }}</span>
<el-button link type="primary" @click="handleLogout">退出登录</el-button>
</div>
</el-header>
<el-card shadow="never">
<template #header>
<span>登录状态验证通过</span>
</template>
<el-main class="layout-main">
<el-card shadow="never">
<template #header>
<span>登录状态验证通过</span>
</template>
<el-descriptions :column="2" border>
<el-descriptions-item label="用户 ID">{{ userStore.userInfo?.id }}</el-descriptions-item>
<el-descriptions-item label="用户名">{{ userStore.userInfo?.username }}</el-descriptions-item>
<el-descriptions-item label="姓名">
{{ userStore.userInfo?.real_name || '—' }}
</el-descriptions-item>
<el-descriptions-item label="角色">
{{ userStore.roles.join('、') || '—' }}
</el-descriptions-item>
<el-descriptions-item label="上次登录">
{{ formatDateTime(userStore.userInfo?.last_login_time) }}
</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="2" border>
<el-descriptions-item label="用户 ID">{{ userStore.userInfo?.id }}</el-descriptions-item>
<el-descriptions-item label="用户名">{{ userStore.userInfo?.username }}</el-descriptions-item>
<el-descriptions-item label="姓名">
{{ userStore.userInfo?.real_name || '—' }}
</el-descriptions-item>
<el-descriptions-item label="角色">
{{ userStore.roles.join('、') || '—' }}
</el-descriptions-item>
<el-descriptions-item label="上次登录">
{{ userStore.userInfo?.last_login_time || '—' }}
</el-descriptions-item>
</el-descriptions>
<el-alert
class="layout-hint"
type="info"
:closable="false"
show-icon
title="这是登录链路的验证页"
description="刷新页面可验证会话恢复(守卫会调用 /me);点击右上角退出登录可验证令牌即时失效。业务模块页面将在后续阶段接入。"
/>
</el-card>
</el-main>
</el-container>
<el-alert
class="dashboard-hint"
type="info"
:closable="false"
show-icon
title="这是登录链路的验证页"
description="刷新页面可验证会话恢复(守卫会调用 /me);「系统管理」菜单已接入用户管理、角色管理与日志查询。"
/>
</el-card>
</template>
<style scoped>
.layout {
height: 100%;
}
.layout-header {
display: flex;
align-items: center;
justify-content: space-between;
color: #fff;
background-color: #1f4e79;
}
.layout-title {
font-size: 16px;
font-weight: 600;
}
.layout-user {
display: flex;
align-items: center;
gap: 10px;
}
.layout-username {
font-size: 14px;
}
.layout-main {
padding: 20px;
}
.layout-hint {
.dashboard-hint {
margin-top: 18px;
}
</style>