You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/new/ui/layout/default.html

262 lines
5.3 KiB
HTML

7 months ago
<!DOCTYPE html>
<html>
<head>
<title>Auth Layout</title>
<style>
.layout-container {
display: flex;
flex-direction: column;
height: 100vh;
width: 100%;
}
.header {
user-select: none;
height: 60px;
background: #1e88e5;
color: white;
display: flex;
align-items: center;
padding: 0 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.header-title {
font-size: 18px;
font-weight: bold;
}
.header-user {
margin-left: auto;
display: flex;
align-items: center;
gap: 10px;
}
.user-avatar {
width: 32px;
height: 32px;
border-radius: 50%;
object-fit: cover;
}
.user-name {
font-size: 14px;
}
.logout-btn {
padding: 5px 10px;
background: #fff;
color: #1e88e5;
border: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
}
.logout-btn:hover {
background: #f5f5f5;
}
.main-container {
display: flex;
flex: 1;
overflow: hidden;
}
.menu {
width: 200px;
background: #f5f5f5;
border-right: 1px solid #ddd;
padding: 20px 0;
}
.menu-item {
padding: 10px 20px;
cursor: pointer;
transition: background 0.3s;
}
.menu-item:hover {
background: #e0e0e0;
}
.menu-item a {
display: block;
color: inherit;
text-decoration: none;
}
.content {
flex: 1;
overflow-y: auto;
width: 100%;
height: 100%;
}
.footer {
height: 40px;
background: #f5f5f5;
border-top: 1px solid #ddd;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
color: #666;
}
</style>
</head>
<body style="height: 100%;width: 100%;margin: 0;">
<div class="layout-container">
<header class="header">
<div class="header-title">
<a href="/">应用权限管理</a>
</div>
<div class="header-user" v-if="user.name">
<img :src="user.icon" class="user-avatar" alt="用户头像">
<span class="user-name">{{ user.name }}</span>
<button @click="logout" class="logout-btn">
退出
</button>
</div>
<div class="header-user" v-else>
<span>未登录</span>
<a :href="$env.root ? $env.root + '/login' : '/login'" class="logout-btn">
登录
</a>
</div>
</header>
<div class="main-container">
<vslot v='user' class="menu" name='menu'>
<div class="menu-item">
<a href="/app">应用管理</a>
</div>
<div class="menu-item">
<a href="/profile">个人中心</a>
</div>
<div class="menu-item">
<a href="/settings">系统设置</a>
</div>
</vslot>
<vslot class="content">
</vslot>
</div>
<footer class="footer">
Copyright © 2025 veypi. All Rights Reserved..
</footer>
</div>
</body>
<script setup>
user = {}
$env.user = user
class TokenService {
constructor() {
this.tokenKey = 'access';
this.refreshTokenKey = 'refresh';
}
setToken(token) {
localStorage.setItem(this.tokenKey, token);
}
getToken() {
return localStorage.getItem(this.tokenKey);
}
setRefreshToken(refreshToken) {
localStorage.setItem(this.refreshTokenKey, refreshToken);
}
getRefreshToken() {
return localStorage.getItem(this.refreshTokenKey);
}
clearTokens() {
localStorage.removeItem(this.tokenKey);
localStorage.removeItem(this.refreshTokenKey);
}
hasToken() {
return !!this.getToken();
}
parseToken(token) {
try {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
return JSON.parse(window.atob(base64));
} catch (error) {
console.error('Token解析失败:', error);
return null;
}
}
async refreshToken() {
const refreshToken = this.getRefreshToken();
if (!refreshToken) {
logout();
this.clearTokens();
return;
}
try {
let data = await api.Post('/api/token', {refresh: refreshToken})
this.setToken(data);
Object.assign(user, this.parseToken(data));
$env.user = user
} catch (e) {
console.error('Token刷新失败:', error);
logout();
}
}
isTokenExpired() {
const token = this.getToken();
if (!token) return true;
const decoded = this.parseToken(token);
if (!decoded) return true;
const currentTime = Date.now() / 1000;
return decoded.exp < currentTime;
}
}
const tokenService = new TokenService();
logout = () => {
let url = '/login';
if ($env.root) {
url = $env.root + url;
}
tokenService.clearTokens();
location.href = url;
}
await tokenService.refreshToken();
// 设置API请求拦截器自动添加token
api.wrapFetch((url, options) => {
const token = tokenService.getToken();
if (token) {
if (!options) {
options = {};
}
if (!options.headers) {
options.headers = {};
}
options.headers.Authorization = `Bearer ${token}`;
}
return fetch(url, options);
});
</script>
</html>