feat(auth): 实现基于令牌的用户认证和访问控制

- 在用户相关页面服务端加载函数中添加令牌检查,防止未授权访问
- 更新用户服务方法以支持携带认证令牌请求API
- 修改用户资料和用户列表组件以适配新的认证流程
- 引入侧边栏状态管理并在布局中注册上下文
- 调整HTTP客户端逻辑以正确传递请求头信息
- 更新用户类型定义以匹配后端返回的角色结构
- 优化应用头部和侧边栏组件的UI细节和交互逻辑
This commit is contained in:
Chaos
2025-11-25 23:33:32 +08:00
parent 81c61f433d
commit 7d627a45fb
14 changed files with 523 additions and 137 deletions

View File

@@ -1,41 +1,80 @@
<script lang="ts">
import DataTable from '$lib/components/DataTable.svelte';
import type { BaseRecord, TableColumn } from '$lib/types/dataTable.ts';
import type { PageData } from './$types'; // SvelteKit 自动生成的类型
import { resolve } from '$app/paths';
const {data} = $props();
// 从 load 函数获取的数据
export let data: PageData;
console.log(data);
// 1. 定义具体的业务接口
interface Role {
id: number;
name: string;
}
interface UserRecord extends BaseRecord {
username: string;
nickname: string;
roles: Role[];
email?: string; // 可选字段
}
// 2. 定义列配置
// 注意:这里显式声明了 TableColumn<UserRecord>[]
// 好处:如果我在 key 里写 "mobile"TS 会报错,因为 UserRecord 里没有 mobile。
const columns: TableColumn<UserRecord>[] = [
{ key: 'id', label: 'ID', width: '50px' },
{ key: 'nickname', label: '用户昵称' }, // 用 nickname 作为 key
{ key: 'roles', label: '角色列表' }, // key 必须是 'roles'
{ key: 'username', label: '登录账号' }
];
function handleEdit(e: CustomEvent<UserRecord>) {
// e.detail 自动被推断为 UserRecord 类型,不是 any
console.log(e.detail.username);
}
const {current,pages,size,total,records} = data.userList;
const rowTitles = ['ID','用户名','昵称','头像','用户组']
</script>
<div class="p-6">
<div class="flex justify-between items-center bg-base-100">
<div>
<h1 class="text-2xl font-bold">用户列表</h1>
</div>
<div class="breadcrumbs text-sm">
<ul>
<li><a href={resolve('/app/dashboard')} >仪表盘</a></li>
<li><a href={resolve('/app/settings')} >系统设置</a></li>
<li><a href={resolve('/app/settings/auth')} >认证管理</a></li>
<li><a href={resolve('/app/settings/auth/users')} >用户管理</a></li>
</ul>
</div>
</div>
<div class="overflow-x-auto">
<table class="table">
<thead>
<tr>
<th>
<label>
<input type="checkbox" class="checkbox" />
</label>
</th>
{#each rowTitles as title,index(index)}
<th>{title}</th>
{/each}
</tr>
</thead>
<tbody>
{#each records as record(record.id)}
<tr>
<th>
<label>
<input type="checkbox" class="checkbox" />
</label>
</th>
<td>{record.id}</td>
<td>{record.username}</td>
<td>{record.nickname}</td>
<td><img class="w-8 h-8 rounded-box bg-primary-content/10 border-0" src="{record.avatar}" alt=" "></td>
<td class="flex gap-2">
{#each record.roles as role(role.id)}
<span class="badge {role.id === 1 ? 'badge-primary' : 'badge-secondary'}">{role.name}</span>
{/each}
</td>
</tr>
{/each}
</tbody>
<tfoot>
<tr>
<th>
</th>
{#each rowTitles as title,index(index)}
<th>{title}</th>
{/each}
</tr>
</tfoot>
</table>
</div>
</div>