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/ui/page/app.html

217 lines
5.1 KiB
HTML

11 months ago
<!doctype html>
<html>
2 weeks ago
11 months ago
<head>
2 weeks ago
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="App List Page">
<title>应用列表</title>
11 months ago
</head>
3 weeks ago
<style>
2 weeks ago
body {
3 weeks ago
padding: var(--spacing-lg);
background-color: var(--bg-color-primary);
color: var(--text-color-primary);
2 weeks ago
}
header {
3 weeks ago
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-xl);
flex-wrap: wrap;
gap: var(--spacing-md);
2 weeks ago
}
h1 {
3 weeks ago
font-size: 2rem;
font-weight: 700;
color: var(--color-primary);
2 weeks ago
}
.filters {
3 weeks ago
display: flex;
gap: var(--spacing-sm);
margin-bottom: var(--spacing-lg);
2 weeks ago
}
.app-grid {
3 weeks ago
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: var(--spacing-lg);
2 weeks ago
}
.app-card {
3 weeks ago
background-color: var(--bg-color-secondary);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
transition: var(--transition-base);
display: flex;
flex-direction: column;
overflow: hidden;
2 weeks ago
}
.app-card:hover {
3 weeks ago
transform: translateY(-5px);
box-shadow: var(--shadow-lg);
2 weeks ago
}
.app-card-header {
3 weeks ago
padding: var(--spacing-md);
display: flex;
align-items: center;
border-bottom: 1px solid var(--border-color);
2 weeks ago
}
.app-icon {
3 weeks ago
width: 48px;
height: 48px;
border-radius: var(--radius-sm);
margin-right: var(--spacing-md);
object-fit: cover;
background-color: var(--bg-color-tertiary);
2 weeks ago
}
.app-info {
3 weeks ago
flex: 1;
2 weeks ago
}
.app-title {
3 weeks ago
font-weight: 600;
margin-bottom: var(--spacing-xs);
color: var(--text-color-primary);
2 weeks ago
}
.app-status {
3 weeks ago
font-size: 0.8rem;
padding: 2px 8px;
border-radius: 10px;
2 weeks ago
}
.status-active {
background-color: color-mix(in srgb, var(--color-success), transparent 90%);
color: var(--color-success);
}
.status-pending {
background-color: color-mix(in srgb, var(--color-warning), transparent 90%);
color: var(--color-warning);
}
3 weeks ago
2 weeks ago
.status-inactive {
background-color: color-mix(in srgb, var(--color-danger), transparent 90%);
color: var(--color-danger);
}
.app-card-body {
3 weeks ago
padding: var(--spacing-md);
flex: 1;
color: var(--text-color-secondary);
font-size: 0.9rem;
line-height: 1.5;
2 weeks ago
}
.app-card-footer {
3 weeks ago
padding: var(--spacing-md);
border-top: 1px solid var(--border-color);
display: flex;
justify-content: flex-end;
gap: var(--spacing-sm);
background-color: color-mix(in srgb, var(--bg-color-secondary), black 2%);
2 weeks ago
}
3 weeks ago
</style>
2 weeks ago
3 weeks ago
<body layout="app">
2 weeks ago
<header>
<h1>应用中心</h1>
<div style="width: 300px;">
<v-input v:value="searchQuery" placeholder="搜索应用..." prefix="search"></v-input>
</div>
2 weeks ago
</header>
<div class="filters">
<v-btn v-for="filter in filters" :key="filter.value"
:variant="currentFilter === filter.value ? 'primary' : 'outline'" @click="currentFilter = filter.value" size="sm">
{{ filter.label }}
</v-btn>
</div>
2 weeks ago
<div class="app-grid">
<div class="app-card" v-for="app in filteredApps" :key="app.id">
<div class="app-card-header">
<img :src="app.icon" class="app-icon" alt="icon">
<div class="app-info">
<div class="app-title">{{ app.name }}</div>
<span class="app-status" :class="getStatusClass(app.status)">
{{ getStatusLabel(app.status) }}
</span>
11 months ago
</div>
2 weeks ago
</div>
<div class="app-card-body">
{{ app.des || '暂无描述' }}
</div>
<div class="app-card-footer">
<v-btn size="sm" variant="text" @click="openApp(app)">访问</v-btn>
<v-btn size="sm" variant="outline" @click="manageApp(app)">管理</v-btn>
</div>
</div>
2 weeks ago
</div>
11 months ago
</body>
<script setup>
2 weeks ago
searchQuery = ''
currentFilter = 'all'
filters = [
{label: '全部', value: 'all'},
{label: '我的应用', value: 'my'},
{label: '最近使用', value: 'recent'}
]
apps = []
filteredApps = []
getStatusClass = (status) => {
3 weeks ago
if (status === 'ok') return 'status-active'
if (status === 'pending') return 'status-pending'
return 'status-inactive'
2 weeks ago
}
3 weeks ago
2 weeks ago
getStatusLabel = (status) => {
3 weeks ago
if (status === 'ok') return '运行中'
if (status === 'pending') return '审核中'
return '已停止'
2 weeks ago
}
3 weeks ago
2 weeks ago
openApp = (app) => {
3 weeks ago
if (app.init_url) {
2 weeks ago
window.open(app.init_url, '_blank')
3 weeks ago
} else {
2 weeks ago
$message.info('该应用暂无入口')
3 weeks ago
}
2 weeks ago
}
3 weeks ago
2 weeks ago
manageApp = (app) => {
$router.push(`/app/${app.id}/settings`)
}
3 weeks ago
2 weeks ago
// Fetch apps
$axios.get('/api/app').then(res => {
3 weeks ago
apps = res || []
$data.filteredApps = apps
2 weeks ago
})
3 weeks ago
</script>
<script>
2 weeks ago
$watch(() => [searchQuery, currentFilter, apps], () => {
3 weeks ago
let result = $data.apps
if ($data.searchQuery) {
2 weeks ago
const q = $data.searchQuery.toLowerCase()
result = result.filter(app => app.name.toLowerCase().includes(q) || (app.des && app.des.toLowerCase().includes(q)))
3 weeks ago
}
// Filter logic for 'my' and 'recent' would go here, simplified for now
if ($data.currentFilter === 'my') {
2 weeks ago
// Mock logic
3 weeks ago
}
$data.filteredApps = result
2 weeks ago
})
11 months ago
</script>
2 weeks ago
11 months ago
</html>