feat: update ui
This commit is contained in:
@@ -4,187 +4,377 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{.TableAlias}} - 数据管理系统</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<style>
|
||||
.tag {
|
||||
@apply inline-block px-2 py-1 text-xs font-medium rounded-full;
|
||||
}
|
||||
.modal {
|
||||
@apply fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden;
|
||||
}
|
||||
.modal-content {
|
||||
@apply bg-white rounded-lg max-w-4xl w-full mx-4 max-h-[80vh] overflow-y-auto;
|
||||
}
|
||||
.card {
|
||||
@apply bg-white rounded-lg shadow-md hover:shadow-lg transition-shadow;
|
||||
}
|
||||
.card-body {
|
||||
@apply p-6;
|
||||
}
|
||||
.loading {
|
||||
@apply animate-pulse;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/static/css/app.css">
|
||||
<link rel="stylesheet" href="/static/css/components/sidebar.css">
|
||||
<link rel="stylesheet" href="/static/css/components/content.css">
|
||||
<link rel="stylesheet" href="/static/css/responsive.css">
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
<div class="min-h-screen">
|
||||
<!-- Header -->
|
||||
<header class="bg-white shadow-sm border-b">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center py-4">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-gray-900">数据管理系统</h1>
|
||||
<p class="text-sm text-gray-600">{{.TableAlias}}</p>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<!-- 左侧导航栏 -->
|
||||
<aside class="sidebar" role="navigation" aria-label="主导航">
|
||||
<!-- Logo/标题区域 -->
|
||||
<div class="sidebar-header">
|
||||
<div class="brand">
|
||||
<svg class="brand-icon" width="32" height="32" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M4 6h16M4 12h16M4 18h7" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<div class="brand-text">
|
||||
<h1 class="brand-title">数据管理系统</h1>
|
||||
<p class="brand-subtitle">{{.TableAlias}}</p>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<select id="tableSelector" class="border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" onchange="changeTable(this.value)">
|
||||
{{range .Tables}}
|
||||
<option value="{{.Name}}" {{if eq .Name $.Table}}selected{{end}}>{{.Alias}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
<div class="text-sm text-gray-600">
|
||||
共 {{.Total}} 条记录
|
||||
</div>
|
||||
|
||||
<!-- 主题切换 -->
|
||||
<button class="theme-toggle"
|
||||
aria-label="切换主题"
|
||||
onclick="toggleTheme()"
|
||||
title="切换明暗主题">
|
||||
<svg class="sun-icon" width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 2.25a.75.75 0 01.75.75v2.25a.75.75 0 01-1.5 0V3a.75.75 0 01.75-.75zM7.5 12a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM18.894 6.166a.75.75 0 00-1.06-1.06l-1.591 1.59a.75.75 0 101.06 1.061l1.591-1.59zM21.75 12a.75.75 0 01-.75.75h-2.25a.75.75 0 010-1.5H21a.75.75 0 01.75.75zM17.834 18.894a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 10-1.061 1.06l1.59 1.591zM12 18a.75.75 0 01.75.75V21a.75.75 0 01-1.5 0v-2.25A.75.75 0 0112 18zM7.758 17.303a.75.75 0 00-1.061-1.06l-1.591 1.59a.75.75 0 001.06 1.061l1.591-1.59zM6 12a.75.75 0 01-.75.75H3a.75.75 0 010-1.5h2.25A.75.75 0 016 12zM6.697 7.757a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 00-1.061 1.06l1.59 1.591z"/>
|
||||
</svg>
|
||||
<svg class="moon-icon" width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M9.528 1.718a.75.75 0 01.162.819A8.97 8.97 0 009 6a9 9 0 009 9 8.97 8.97 0 003.463-.69.75.75 0 01.981.98 10.503 10.503 0 01-9.694 6.46c-5.799 0-10.5-4.701-10.5-10.5 0-4.368 2.667-8.112 6.46-9.694a.75.75 0 01.818.162z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 智能搜索框 -->
|
||||
<div class="sidebar-search">
|
||||
<div class="search-container">
|
||||
<svg class="search-icon" width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
<input type="search"
|
||||
class="sidebar-search-input"
|
||||
placeholder="快速查找表格..."
|
||||
aria-label="搜索数据表"
|
||||
oninput="filterTables(this.value)">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分组导航 -->
|
||||
<nav class="sidebar-nav" aria-label="数据表导航">
|
||||
<h2 class="nav-section-title">数据表</h2>
|
||||
<ul class="nav-list" role="list">
|
||||
{{range .Tables}}
|
||||
<li class="nav-item">
|
||||
<a href="/?table={{.Name}}"
|
||||
class="nav-link {{if eq .Name $.Table}}active{{end}}"
|
||||
role="menuitem"
|
||||
aria-current="{{if eq .Name $.Table}}page{{end}}"
|
||||
title="{{.Alias}} - {{.Description}}">
|
||||
<div class="nav-link-content">
|
||||
<svg class="nav-icon" width="18" height="18" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2z" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M8 5v14M16 5v14" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
<div class="nav-text-content">
|
||||
<span class="nav-title">{{.Alias}}</span>
|
||||
<span class="nav-description">{{.RowCount}} 条记录</span>
|
||||
</div>
|
||||
{{if eq .Name $.Table}}
|
||||
<div class="nav-indicator" aria-hidden="true"></div>
|
||||
{{end}}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- 系统信息 -->
|
||||
<div class="sidebar-footer">
|
||||
<div class="system-info">
|
||||
<div class="info-item">
|
||||
<span class="info-label">总记录数</span>
|
||||
<span class="info-value">{{.Total}}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">最后更新</span>
|
||||
<span class="info-value">{{.LastUpdate}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="settings-button" onclick="openSettings()" aria-label="系统设置">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
设置
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 移动端遮罩层 -->
|
||||
<div class="sidebar-backdrop" onclick="closeSidebar()" aria-hidden="true"></div>
|
||||
|
||||
<!-- 右侧主内容区 -->
|
||||
<main class="main-content" role="main">
|
||||
<!-- 移动端菜单按钮 -->
|
||||
<header class="content-header" role="banner">
|
||||
<div class="header-toolbar">
|
||||
<!-- 移动端菜单 -->
|
||||
<button class="mobile-menu-toggle"
|
||||
onclick="toggleSidebar()"
|
||||
aria-label="打开导航菜单"
|
||||
aria-controls="sidebar"
|
||||
aria-expanded="false">
|
||||
<svg class="menu-icon" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M4 6h16M4 12h16M4 18h16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- 面包屑导航 -->
|
||||
<nav class="breadcrumb" aria-label="当前位置">
|
||||
<ol class="breadcrumb-list" role="list">
|
||||
<li class="breadcrumb-item" role="listitem">
|
||||
<a href="/" class="breadcrumb-link">首页</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item" role="listitem" aria-current="page">
|
||||
<span class="breadcrumb-current">{{.TableAlias}}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div class="header-tools">
|
||||
<!-- 高级搜索 -->
|
||||
<div class="search-container">
|
||||
<div class="search-box">
|
||||
<svg class="search-icon" width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
<input type="search"
|
||||
id="searchInput"
|
||||
class="search-input"
|
||||
placeholder="在 {{.TableAlias}} 中搜索..."
|
||||
value="{{.Search}}"
|
||||
aria-label="搜索数据"
|
||||
oninput="debounceSearch(this.value)"
|
||||
onkeydown="handleSearchKeydown(event)">
|
||||
<button class="search-clear"
|
||||
onclick="clearSearch()"
|
||||
aria-label="清除搜索"
|
||||
style="display: {{if .Search}}block{{else}}none{{end}}">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M6 18L18 6M6 6l12 12" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<button class="search-button" onclick="performSearch()" aria-label="搜索">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 视图控制 -->
|
||||
<div class="view-controls">
|
||||
<button class="view-button active"
|
||||
onclick="setViewMode('table')"
|
||||
aria-label="表格视图"
|
||||
title="表格视图">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2z" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M8 5v14M16 5v14" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="view-button"
|
||||
onclick="setViewMode('cards')"
|
||||
aria-label="卡片视图"
|
||||
title="卡片视图">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 导出功能 -->
|
||||
<div class="export-dropdown">
|
||||
<button class="export-button"
|
||||
onclick="toggleExportMenu()"
|
||||
aria-label="导出数据"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M12 10v6m0 0l-3-3m3 3l3-3m2-8H7a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 002-2V4a2 2 0 00-2-2z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="export-menu" role="menu" aria-orientation="vertical">
|
||||
<button class="export-option" role="menuitem" onclick="exportData('csv')">导出 CSV</button>
|
||||
<button class="export-option" role="menuitem" onclick="exportData('json')">导出 JSON</button>
|
||||
<button class="export-option" role="menuitem" onclick="exportData('excel')">导出 Excel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<!-- Search and Filters -->
|
||||
<div class="mb-6 bg-white p-4 rounded-lg shadow">
|
||||
<div class="flex flex-col sm:flex-row gap-4">
|
||||
<div class="flex-1">
|
||||
<input type="text" id="searchInput" placeholder="搜索..." value="{{.Search}}"
|
||||
class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button onclick="performSearch()" class="px-4 py-2 bg-blue-600 text-white rounded-md text-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
搜索
|
||||
</button>
|
||||
<button onclick="clearSearch()" class="px-4 py-2 bg-gray-300 text-gray-700 rounded-md text-sm hover:bg-gray-400 focus:outline-none focus:ring-2 focus:ring-gray-500">
|
||||
清除
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 分页信息 -->
|
||||
<div class="pagination-info">
|
||||
<span class="pagination-text">
|
||||
显示 {{.StartRecord}} - {{.EndRecord}} / {{.Total}} 条记录
|
||||
</span>
|
||||
<select class="per-page-select"
|
||||
onchange="changePerPage(this.value)"
|
||||
aria-label="每页显示条数">
|
||||
<option value="10" {{if eq .PerPage 10}}selected{{end}}>10 条/页</option>
|
||||
<option value="25" {{if eq .PerPage 25}}selected{{end}}>25 条/页</option>
|
||||
<option value="50" {{if eq .PerPage 50}}selected{{end}}>50 条/页</option>
|
||||
<option value="100" {{if eq .PerPage 100}}selected{{end}}>100 条/页</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Data Display -->
|
||||
<div class="grid gap-6">
|
||||
<!-- Table View -->
|
||||
<div class="bg-white shadow overflow-hidden sm:rounded-md">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
{{range $col := .Columns}}
|
||||
{{if $col.ShowInList}}
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
{{$col.Alias}}
|
||||
</th>
|
||||
<!-- 主内容区域 -->
|
||||
<div class="content-main">
|
||||
<div class="content-container">
|
||||
<!-- 数据展示 -->
|
||||
<div class="data-display">
|
||||
<!-- 表格视图 -->
|
||||
<div class="data-table-container">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{{range $col := .Columns}}
|
||||
{{if $col.ShowInList}}
|
||||
<th>{{$col.Alias}}</th>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $row := .Data}}
|
||||
<tr>
|
||||
{{range $col := $.Columns}}
|
||||
{{if $col.ShowInList}}
|
||||
<td>
|
||||
{{if eq $col.RenderType "text"}}
|
||||
{{truncate (index $row $col.Name) 50}}
|
||||
{{else}}
|
||||
{{index $row $col.Name}}
|
||||
{{end}}
|
||||
</td>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<td>
|
||||
<button class="action-button" onclick="showDetail('{{index $row "id"}}')">
|
||||
查看详情
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
操作
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- 空状态 -->
|
||||
{{if eq (len .Data) 0}}
|
||||
<div class="empty-state">
|
||||
<svg class="empty-state-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
|
||||
</svg>
|
||||
<div class="empty-state-title">暂无数据</div>
|
||||
<div class="empty-state-description">
|
||||
{{if .Search}}
|
||||
没有找到与"{{.Search}}"相关的记录
|
||||
{{else}}
|
||||
当前表格暂无数据
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<!-- 卡片视图 -->
|
||||
<div class="data-cards-container" style="display: none;">
|
||||
<div class="data-cards">
|
||||
{{range $row := .Data}}
|
||||
<tr class="hover:bg-gray-50">
|
||||
{{range $col := $.Columns}}
|
||||
{{if $col.ShowInList}}
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
{{if eq $col.RenderType "text"}}
|
||||
{{truncate (index $row $col.Name) 50}}
|
||||
{{else}}
|
||||
{{index $row $col.Name}}
|
||||
{{end}}
|
||||
</td>
|
||||
<div class="data-card">
|
||||
<div class="data-card-title">
|
||||
{{index $row (index $.Columns 0).Name}}
|
||||
</div>
|
||||
{{range $i, $col := $.Columns}}
|
||||
{{if and $col.ShowInList (gt $i 0) (lt $i 4)}}
|
||||
<div class="data-card-item">
|
||||
<span class="data-card-label">{{$col.Alias}}:</span>
|
||||
<span class="data-card-value">
|
||||
{{if eq $col.RenderType "text"}}
|
||||
{{truncate (index $row $col.Name) 30}}
|
||||
{{else}}
|
||||
{{index $row $col.Name}}
|
||||
{{end}}
|
||||
</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
<button onclick="showDetail('{{index $row "id"}}')" class="text-blue-600 hover:text-blue-800">
|
||||
<div style="margin-top: 12px;">
|
||||
<button class="action-button" onclick="showDetail('{{index $row "id"}}')">
|
||||
查看详情
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
{{if eq (len .Data) 0}}
|
||||
<div class="empty-state">
|
||||
<svg class="empty-state-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"/>
|
||||
</svg>
|
||||
<div class="empty-state-title">暂无数据</div>
|
||||
<div class="empty-state-description">
|
||||
{{if .Search}}
|
||||
没有找到与"{{.Search}}"相关的记录
|
||||
{{else}}
|
||||
当前表格暂无数据
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<!-- 分页 -->
|
||||
{{if gt .Pages 1}}
|
||||
<div class="mt-6 bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6">
|
||||
<div class="flex-1 flex justify-between sm:hidden">
|
||||
<div class="pagination">
|
||||
<div class="pagination-info">
|
||||
显示 {{.StartRecord}} - {{.EndRecord}} / {{.Total}} 条记录
|
||||
</div>
|
||||
<div class="pagination-controls">
|
||||
{{if gt .Page 1}}
|
||||
<a href="?table={{.Table}}&page={{sub .Page 1}}&per_page={{.PerPage}}&search={{.Search}}&sort={{.SortField}}&order={{.SortOrder}}"
|
||||
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
|
||||
上一页
|
||||
</a>
|
||||
class="pagination-button">上一页</a>
|
||||
{{end}}
|
||||
|
||||
{{$start := sub .Page 2}}
|
||||
{{$end := add .Page 2}}
|
||||
{{if lt $start 1}}
|
||||
{{$start = 1}}
|
||||
{{$end = min 5 .Pages}}
|
||||
{{end}}
|
||||
{{if gt $end .Pages}}
|
||||
{{$end = .Pages}}
|
||||
{{$start = max 1 (sub .Pages 4)}}
|
||||
{{end}}
|
||||
|
||||
{{range $i := $start | $end}}
|
||||
{{if eq $i .Page}}
|
||||
<span class="pagination-button active">{{$i}}</span>
|
||||
{{else}}
|
||||
<a href="?table={{.Table}}&page={{$i}}&per_page={{.PerPage}}&search={{.Search}}&sort={{.SortField}}&order={{.SortOrder}}"
|
||||
class="pagination-button">{{$i}}</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if lt .Page .Pages}}
|
||||
<a href="?table={{.Table}}&page={{add .Page 1}}&per_page={{.PerPage}}&search={{.Search}}&sort={{.SortField}}&order={{.SortOrder}}"
|
||||
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
|
||||
下一页
|
||||
</a>
|
||||
class="pagination-button">下一页</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<p class="text-sm text-gray-700">
|
||||
显示第 <span class="font-medium">{{add (mul (sub .Page 1) .PerPage) 1}}</span>
|
||||
到 <span class="font-medium">{{if lt (mul .Page .PerPage) .Total}}{{mul .Page .PerPage}}{{else}}{{.Total}}{{end}}</span>
|
||||
条,共 <span class="font-medium">{{.Total}}</span> 条记录
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px">
|
||||
{{if gt .Page 1}}
|
||||
<a href="?table={{.Table}}&page={{sub .Page 1}}&per_page={{.PerPage}}&search={{.Search}}&sort={{.SortField}}&order={{.SortOrder}}"
|
||||
class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
|
||||
上一页
|
||||
</a>
|
||||
{{end}}
|
||||
|
||||
{{$start := sub .Page 2}}
|
||||
{{$end := add .Page 2}}
|
||||
{{if lt $start 1}}
|
||||
{{$start = 1}}
|
||||
{{$end = min 5 .Pages}}
|
||||
{{end}}
|
||||
{{if gt $end .Pages}}
|
||||
{{$end = .Pages}}
|
||||
{{$start = max 1 (sub .Pages 4)}}
|
||||
{{end}}
|
||||
|
||||
{{range $i := $start | $end}}
|
||||
{{if eq $i .Page}}
|
||||
<span class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-blue-50 text-sm font-medium text-blue-600">
|
||||
{{$i}}
|
||||
</span>
|
||||
{{else}}
|
||||
<a href="?table={{.Table}}&page={{$i}}&per_page={{.PerPage}}&search={{.Search}}&sort={{.SortField}}&order={{.SortOrder}}"
|
||||
class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50">
|
||||
{{$i}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if lt .Page .Pages}}
|
||||
<a href="?table={{.Table}}&page={{add .Page 1}}&per_page={{.PerPage}}&search={{.Search}}&sort={{.SortField}}&order={{.SortOrder}}"
|
||||
class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
|
||||
下一页
|
||||
</a>
|
||||
{{end}}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -207,72 +397,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Utility functions
|
||||
function changeTable(tableName) {
|
||||
window.location.href = `/?table=${tableName}&page=1`;
|
||||
}
|
||||
|
||||
function performSearch() {
|
||||
const search = document.getElementById('searchInput').value;
|
||||
const table = new URLSearchParams(window.location.search).get('table') || '{{.Table}}';
|
||||
window.location.href = `/?table=${table}&page=1&search=${encodeURIComponent(search)}`;
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
const table = new URLSearchParams(window.location.search).get('table') || '{{.Table}}';
|
||||
document.getElementById('searchInput').value = '';
|
||||
window.location.href = `/?table=${table}&page=1`;
|
||||
}
|
||||
|
||||
function showDetail(id) {
|
||||
const table = new URLSearchParams(window.location.search).get('table') || '{{.Table}}';
|
||||
fetch(`/api/data/${table}/detail/${id}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
let content = '';
|
||||
for (const [key, value] of Object.entries(data.data)) {
|
||||
content += `
|
||||
<div class="border-b pb-3">
|
||||
<label class="block text-sm font-medium text-gray-700">${key}</label>
|
||||
<div class="mt-1 text-sm text-gray-900">${value || ''}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
document.getElementById('detailContent').innerHTML = content;
|
||||
document.getElementById('detailModal').classList.remove('hidden');
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error loading detail:', error);
|
||||
alert('加载详情失败');
|
||||
});
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
document.getElementById('detailModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
// Event listeners
|
||||
document.getElementById('searchInput').addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
performSearch();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('detailModal').addEventListener('click', function(e) {
|
||||
if (e.target === this) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Add enter key support for search
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
if (searchInput) {
|
||||
searchInput.focus();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script src="/static/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
424
web/templates/test_layout.html
Normal file
424
web/templates/test_layout.html
Normal file
@@ -0,0 +1,424 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>数据管理系统 - 测试布局</title>
|
||||
<link rel="stylesheet" href="/static/css/app.css">
|
||||
<link rel="stylesheet" href="/static/css/components/sidebar.css">
|
||||
<link rel="stylesheet" href="/static/css/components/content.css">
|
||||
<link rel="stylesheet" href="/static/css/responsive.css">
|
||||
<style>
|
||||
/* 测试样式 */
|
||||
.test-data {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.test-item {
|
||||
background: var(--bg-primary);
|
||||
border: 1px solid var(--border-light);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<!-- 左侧导航栏 -->
|
||||
<aside class="sidebar" role="navigation" aria-label="主导航">
|
||||
<!-- Logo/标题区域 -->
|
||||
<div class="sidebar-header">
|
||||
<div class="brand">
|
||||
<svg class="brand-icon" width="32" height="32" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M4 6h16M4 12h16M4 18h7" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<div class="brand-text">
|
||||
<h1 class="brand-title">数据管理系统</h1>
|
||||
<p class="brand-subtitle">测试表格</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主题切换 -->
|
||||
<button class="theme-toggle"
|
||||
aria-label="切换主题"
|
||||
onclick="toggleTheme()"
|
||||
title="切换明暗主题">
|
||||
<svg class="sun-icon" width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 2.25a.75.75 0 01.75.75v2.25a.75.75 0 01-1.5 0V3a.75.75 0 01.75-.75zM7.5 12a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM18.894 6.166a.75.75 0 00-1.06-1.06l-1.591 1.59a.75.75 0 101.06 1.061l1.591-1.59zM21.75 12a.75.75 0 01-.75.75h-2.25a.75.75 0 010-1.5H21a.75.75 0 01.75.75zM17.834 18.894a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 10-1.061 1.06l1.59 1.591zM12 18a.75.75 0 01.75.75V21a.75.75 0 01-1.5 0v-2.25A.75.75 0 0112 18zM7.758 17.303a.75.75 0 00-1.061-1.06l-1.591 1.59a.75.75 0 001.06 1.061l1.591-1.59zM6 12a.75.75 0 01-.75.75H3a.75.75 0 010-1.5h2.25A.75.75 0 016 12zM6.697 7.757a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 00-1.061 1.06l1.59 1.591z"/>
|
||||
</svg>
|
||||
<svg class="moon-icon" width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M9.528 1.718a.75.75 0 01.162.819A8.97 8.97 0 009 6a9 9 0 009 9 8.97 8.97 0 003.463-.69.75.75 0 01.981.98 10.503 10.503 0 01-9.694 6.46c-5.799 0-10.5-4.701-10.5-10.5 0-4.368 2.667-8.112 6.46-9.694a.75.75 0 01.818.162z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 智能搜索框 -->
|
||||
<div class="sidebar-search">
|
||||
<div class="search-container">
|
||||
<svg class="search-icon" width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
<input type="search"
|
||||
class="sidebar-search-input"
|
||||
placeholder="快速查找表格..."
|
||||
aria-label="搜索数据表"
|
||||
oninput="filterTables(this.value)">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分组导航 -->
|
||||
<nav class="sidebar-nav" aria-label="数据表导航">
|
||||
<h2 class="nav-section-title">数据表</h2>
|
||||
<ul class="nav-list" role="list">
|
||||
<li class="nav-item">
|
||||
<a href="#" class="nav-link active"
|
||||
role="menuitem"
|
||||
aria-current="page"
|
||||
title="用户表 - 用户基本信息">
|
||||
<div class="nav-link-content">
|
||||
<svg class="nav-icon" width="18" height="18" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2z" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M8 5v14M16 5v14" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
<div class="nav-text-content">
|
||||
<span class="nav-title">用户表</span>
|
||||
<span class="nav-description">1,234 条记录</span>
|
||||
</div>
|
||||
<div class="nav-indicator" aria-hidden="true"></div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#" class="nav-link"
|
||||
role="menuitem"
|
||||
title="订单表 - 订单交易信息">
|
||||
<div class="nav-link-content">
|
||||
<svg class="nav-icon" width="18" height="18" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2z" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M8 5v14M16 5v14" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
<div class="nav-text-content">
|
||||
<span class="nav-title">订单表</span>
|
||||
<span class="nav-description">5,678 条记录</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="#" class="nav-link"
|
||||
role="menuitem"
|
||||
title="产品表 - 产品目录信息">
|
||||
<div class="nav-link-content">
|
||||
<svg class="nav-icon" width="18" height="18" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2z" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M8 5v14M16 5v14" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
<div class="nav-text-content">
|
||||
<span class="nav-title">产品表</span>
|
||||
<span class="nav-description">987 条记录</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- 系统信息 -->
|
||||
<div class="sidebar-footer">
|
||||
<div class="system-info">
|
||||
<div class="info-item">
|
||||
<span class="info-label">总记录数</span>
|
||||
<span class="info-value">8,901</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">最后更新</span>
|
||||
<span class="info-value">2分钟前</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="settings-button" onclick="openSettings()" aria-label="系统设置">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
设置
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 移动端遮罩层 -->
|
||||
<div class="sidebar-backdrop" onclick="closeSidebar()" aria-hidden="true"></div>
|
||||
|
||||
<!-- 右侧主内容区 -->
|
||||
<main class="main-content" role="main">
|
||||
<!-- 移动端菜单按钮 -->
|
||||
<header class="content-header" role="banner">
|
||||
<div class="header-toolbar">
|
||||
<!-- 移动端菜单 -->
|
||||
<button class="mobile-menu-toggle"
|
||||
onclick="toggleSidebar()"
|
||||
aria-label="打开导航菜单"
|
||||
aria-controls="sidebar"
|
||||
aria-expanded="false">
|
||||
<svg class="menu-icon" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M4 6h16M4 12h16M4 18h16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- 面包屑导航 -->
|
||||
<nav class="breadcrumb" aria-label="当前位置">
|
||||
<ol class="breadcrumb-list" role="list">
|
||||
<li class="breadcrumb-item" role="listitem">
|
||||
<a href="/" class="breadcrumb-link">首页</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item" role="listitem" aria-current="page">
|
||||
<span class="breadcrumb-current">测试表格</span>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div class="header-tools">
|
||||
<!-- 高级搜索 -->
|
||||
<div class="search-container">
|
||||
<div class="search-box">
|
||||
<svg class="search-icon" width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
<input type="search"
|
||||
id="searchInput"
|
||||
class="search-input"
|
||||
placeholder="在测试表格中搜索..."
|
||||
value=""
|
||||
aria-label="搜索数据"
|
||||
oninput="debounceSearch(this.value)">
|
||||
<button class="search-clear"
|
||||
onclick="clearSearch()"
|
||||
aria-label="清除搜索"
|
||||
style="display: none;">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M6 18L18 6M6 6l12 12" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<button class="search-button" onclick="performSearch()" aria-label="搜索">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 视图控制 -->
|
||||
<div class="view-controls">
|
||||
<button class="view-button active"
|
||||
onclick="setViewMode('table')"
|
||||
aria-label="表格视图"
|
||||
title="表格视图">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2z" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M8 5v14M16 5v14" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="view-button"
|
||||
onclick="setViewMode('cards')"
|
||||
aria-label="卡片视图"
|
||||
title="卡片视图">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 导出功能 -->
|
||||
<div class="export-dropdown">
|
||||
<button class="export-button"
|
||||
onclick="toggleExportMenu()"
|
||||
aria-label="导出数据"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false">
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24">
|
||||
<path d="M12 10v6m0 0l-3-3m3 3l3-3m2-8H7a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 002-2V4a2 2 0 00-2-2z" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="export-menu" role="menu" aria-orientation="vertical">
|
||||
<button class="export-option" role="menuitem" onclick="exportData('csv')">导出 CSV</button>
|
||||
<button class="export-option" role="menuitem" onclick="exportData('json')">导出 JSON</button>
|
||||
<button class="export-option" role="menuitem" onclick="exportData('excel')">导出 Excel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页信息 -->
|
||||
<div class="pagination-info">
|
||||
<span class="pagination-text">
|
||||
显示 1-10 / 100 条记录
|
||||
</span>
|
||||
<select class="per-page-select"
|
||||
onchange="changePerPage(this.value)"
|
||||
aria-label="每页显示条数">
|
||||
<option value="10" selected>10 条/页</option>
|
||||
<option value="25">25 条/页</option>
|
||||
<option value="50">50 条/页</option>
|
||||
<option value="100">100 条/页</option>
|
||||
</select>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
<div class="content-main">
|
||||
<div class="content-container">
|
||||
<!-- 数据展示 -->
|
||||
<div class="data-display">
|
||||
<!-- 表格视图 -->
|
||||
<div class="data-table-container">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>名称</th>
|
||||
<th>邮箱</th>
|
||||
<th>状态</th>
|
||||
<th>创建时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>张三</td>
|
||||
<td>zhangsan@example.com</td>
|
||||
<td>激活</td>
|
||||
<td>2024-01-15</td>
|
||||
<td><button class="action-button" onclick="alert('查看详情')">查看</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>李四</td>
|
||||
<td>lisi@example.com</td>
|
||||
<td>激活</td>
|
||||
<td>2024-01-16</td>
|
||||
<td><button class="action-button" onclick="alert('查看详情')">查看</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>王五</td>
|
||||
<td>wangwu@example.com</td>
|
||||
<td>禁用</td>
|
||||
<td>2024-01-17</td>
|
||||
<td><button class="action-button" onclick="alert('查看详情')">查看</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 卡片视图 -->
|
||||
<div class="data-cards-container" style="display: none;">
|
||||
<div class="data-cards">
|
||||
<div class="data-card">
|
||||
<div class="data-card-title">张三</div>
|
||||
<div class="data-card-item">
|
||||
<span class="data-card-label">ID:</span>
|
||||
<span class="data-card-value">1</span>
|
||||
</div>
|
||||
<div class="data-card-item">
|
||||
<span class="data-card-label">邮箱:</span>
|
||||
<span class="data-card-value">zhangsan@example.com</span>
|
||||
</div>
|
||||
<div class="data-card-item">
|
||||
<span class="data-card-label">状态:</span>
|
||||
<span class="data-card-value">激活</span>
|
||||
</div>
|
||||
<div style="margin-top: 12px;">
|
||||
<button class="action-button" onclick="alert('查看详情')">查看详情</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-card">
|
||||
<div class="data-card-title">李四</div>
|
||||
<div class="data-card-item">
|
||||
<span class="data-card-label">ID:</span>
|
||||
<span class="data-card-value">2</span>
|
||||
</div>
|
||||
<div class="data-card-item">
|
||||
<span class="data-card-label">邮箱:</span>
|
||||
<span class="data-card-value">lisi@example.com</span>
|
||||
</div>
|
||||
<div class="data-card-item">
|
||||
<span class="data-card-label">状态:</span>
|
||||
<span class="data-card-value">激活</span>
|
||||
</div>
|
||||
<div style="margin-top: 12px;">
|
||||
<button class="action-button" onclick="alert('查看详情')">查看详情</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-card">
|
||||
<div class="data-card-title">王五</div>
|
||||
<div class="data-card-item">
|
||||
<span class="data-card-label">ID:</span>
|
||||
<span class="data-card-value">3</span>
|
||||
</div>
|
||||
<div class="data-card-item">
|
||||
<span class="data-card-label">邮箱:</span>
|
||||
<span class="data-card-value">wangwu@example.com</span>
|
||||
</div>
|
||||
<div class="data-card-item">
|
||||
<span class="data-card-label">状态:</span>
|
||||
<span class="data-card-value">禁用</span>
|
||||
</div>
|
||||
<div style="margin-top: 12px;">
|
||||
<button class="action-button" onclick="alert('查看详情')">查看详情</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<div class="pagination-info">
|
||||
显示 1-3 / 100 条记录
|
||||
</div>
|
||||
<div class="pagination-controls">
|
||||
<span class="pagination-button disabled">上一页</span>
|
||||
<span class="pagination-button active">1</span>
|
||||
<a href="#" class="pagination-button">2</a>
|
||||
<a href="#" class="pagination-button">3</a>
|
||||
<a href="#" class="pagination-button">下一页</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- 详情模态框 -->
|
||||
<div id="detailModal" class="modal hidden">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">详细信息</h3>
|
||||
<button class="modal-close" onclick="closeModal()">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="detail-item">
|
||||
<label class="detail-label">姓名</label>
|
||||
<div class="detail-value">张三</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label class="detail-label">邮箱</label>
|
||||
<div class="detail-value">zhangsan@example.com</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<label class="detail-label">状态</label>
|
||||
<div class="detail-value">激活</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user