feat(device): add device management feature

- Created device list page with loading states
- Implemented device service with API integration
- Added device response and request types
- Updated sidebar navigation with device management section
- Added laptop-settings icon
- Modified user table component to accept props
- Updated user service to return array of user profiles
- Changed app language to Chinese (zh-CN)
This commit is contained in:
Chaos
2025-11-27 17:12:03 +08:00
parent 2a14389daf
commit 2caa8f26a3
18 changed files with 596 additions and 458 deletions

View File

@@ -1,192 +1,31 @@
<script lang="ts">
import { resolve } from '$app/paths';
import Icon from '$lib/components/icon/Icon.svelte';
import UserTable from '$lib/components/table/UserTable.svelte';
import { resolve } from '$app/paths';
const { data } = $props();
console.log("data", data);
const newRowTitles = [
{ title: 'ID', width: 5}
, { title: '用户名', width: 15 }
, { title: '昵称', width: 20 }
, { title: '头像', width: 10 }
, { title: '用户组', width: 45 }
];
let x ;
const handleRoleChange = (e) => {
console.log(e.target.value);
x = e.target.value;
}
const {data} = $props();
</script>
<div class=" ">
<div class="flex justify-between items-center ">
<p class="font-bold">用户管理</p>
<div class="breadcrumbs ">
<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 class="flex justify-between items-center ">
<p class="font-bold">用户管理</p>
<div class="breadcrumbs ">
<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 class="overflow-x-auto rounded-box shadow bg-base-100 mt-1 ">
<div class="flex items-center justify-between px-4 pt-4 pb-2">
<div class="flex gap-4">
<label class="input">
<svg class="h-[1em] opacity-50" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g
stroke-linejoin="round"
stroke-linecap="round"
stroke-width="2.5"
fill="none"
stroke="currentColor"
>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</g>
</svg>
<input type="search" required placeholder="Search" />
<button class="btn btn-xs btn-primary">搜索</button>
</label>
{#await data.streamed.roles}
<div></div>
{:then roles }
<div class="filter w-64">
<input class="btn filter-reset " type="radio" value='' name="metaframeworks" aria-label="All" onchange={handleRoleChange} />
{#each roles as role(role.id)}
<input class="btn " type="radio" name="metaframeworks" aria-label="{role.name}" value={role.id} onchange={handleRoleChange} />
{/each}
</div>
{/await}
</div>
<div class=" flex items-center justify-center gap-4">
<button class="btn btn-primary">添加用户</button>
<div class="dropdown dropdown-bottom dropdown-end">
<div tabindex="0" role="button" class="btn" ><Icon id="menu" size="24" /></div>
<ul tabindex="-1" class="dropdown-content menu bg-base-200 rounded-box z-1 w-52 p-2 mt-2 shadow-sm" >
<li><div>删除</div></li>
<li><div>封禁</div></li>
</ul>
</div>
</div>
</div>
<table class="table">
<thead>
<tr>
<th style="width: 5%">
<label>
<input type="checkbox" class="checkbox" />
</label>
</th>
{#each newRowTitles as item,index(index)}
<th style="width: {item.width}%" >{item.title}</th>
{/each}
</tr>
</thead>
{#await data.streamed.userList}
<tbody>
<tr>
<td colspan={newRowTitles.length + 1} class="text-center py-4 ">
<div class="min-h-96 flex items-center justify-center">
<div class="loading text-base-content"></div>
</div>
</td>
</tr>
</tbody>
{:then userList}
<tbody>
{#each userList.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>
<div class="w-8 h-8 rounded-box bg-primary-content/10 border-0">
{#if record.avatar}
<img class="w-8 h-8 rounded-box bg-primary-content/10 border-0" src="{record.avatar}" alt=" ">
{/if}
</div>
</td>
<td class="">
{#each record.roles as role (role.id)}
<span class="badge mr-2 last:mr-0 {role.id === 1 ? 'badge-primary' : 'badge-secondary'}">{role.name}</span>
{/each}
</td>
</tr>
{/each}
</tbody>
<tfoot>
<tr>
<th colspan={newRowTitles.length + 1} class="text-center py-4 ">
<div class=" flex items-center justify-between">
<div>
page {userList.current} of {userList.pages}
</div>
<div class="join">
<button class="join-item btn">1</button>
<button class="join-item btn">2</button>
<button class="join-item btn btn-disabled">...</button>
<button class="join-item btn">99</button>
<button class="join-item btn">100</button>
</div>
<div>
<button class="btn btn-primary">下一页</button>
</div>
</div>
</th>
</tr>
</tfoot>
{:catch error}
<tbody>
<tr>
<td colspan={newRowTitles.length + 1} class="text-center py-4 ">
<div class="min-h-96 flex items-center justify-center">
<p class="error">组件加载失败: {error.message}</p>
</div>
</td>
</tr>
</tbody>
{/await}
</table>
</div>
</div>
<style lang="scss">
.loading {
padding: 20px;
background: #f0f0f0;
border-radius: 8px;
text-align: center;
}
.error {
color: red;
}
</style>
{#await data.streamed.userList}
加载中
{:then result}
{#await data.streamed.roles}
加载中
{:then roles}
<UserTable users={result} roles={roles}/>
{:catch err}
<p>出错了: {err.message}</p>
{/await}
{:catch err}
<p>出错了: {err.message}</p>
{/await}