| @{ |
| ViewData["Title"] = "仪表板"; |
| Layout = "_AdminLayout"; |
| } |
|
|
| |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 mb-6"> |
| <div class="stats-card"> |
| <div class="stats-number" style="color: var(--primary);"> |
| @(ViewBag.TotalTools ?? 0) |
| </div> |
| <div class="stats-label"> |
| <i class="fas fa-tools" style="margin-right: 0.5rem;"></i> |
| 工具总数 |
| </div> |
| </div> |
| |
| <div class="stats-card"> |
| <div class="stats-number" style="color: var(--secondary);"> |
| @(ViewBag.TotalCategories ?? 0) |
| </div> |
| <div class="stats-label"> |
| <i class="fas fa-tags" style="margin-right: 0.5rem;"></i> |
| 分类总数 |
| </div> |
| </div> |
| |
| <div class="stats-card"> |
| <div class="stats-number" style="color: var(--success);"> |
| @(ViewBag.TotalUsers ?? 0) |
| </div> |
| <div class="stats-label"> |
| <i class="fas fa-users" style="margin-right: 0.5rem;"></i> |
| 用户总数 |
| </div> |
| </div> |
| |
| <div class="stats-card"> |
| <div class="stats-number" style="color: var(--warning);"> |
| @{ |
| var totalViews = ViewBag.TotalViews as long? ?? 0; |
| var viewsDisplay = totalViews > 1000000 ? $"{totalViews / 1000000:F1}M" : |
| totalViews > 1000 ? $"{totalViews / 1000:F0}K" : |
| totalViews.ToString(); |
| } |
| @viewsDisplay |
| </div> |
| <div class="stats-label"> |
| <i class="fas fa-eye" style="margin-right: 0.5rem;"></i> |
| 总访问量 |
| </div> |
| </div> |
| </div> |
|
|
| <div class="grid grid-cols-1 lg:grid-cols-2"> |
| |
| <div class="data-table" style="margin-bottom: 2rem;"> |
| <div style="padding: 1.5rem; border-bottom: 1px solid var(--light-2);"> |
| <h3 style="margin: 0; font-size: 1.1rem; font-weight: 600; color: var(--dark);"> |
| <i class="fas fa-clock" style="margin-right: 0.5rem; color: var(--primary);"></i> |
| 最新工具 |
| </h3> |
| </div> |
| |
| @if (ViewBag.RecentTools is List<ToolHub.Models.Tool> recentTools && recentTools.Any()) |
| { |
| <table> |
| <thead> |
| <tr> |
| <th>工具名称</th> |
| <th>分类</th> |
| <th>状态</th> |
| <th>创建时间</th> |
| </tr> |
| </thead> |
| <tbody> |
| @foreach (var tool in recentTools) |
| { |
| <tr> |
| <td> |
| <div style="display: flex; align-items: center;"> |
| @if (!string.IsNullOrEmpty(tool.Icon)) |
| { |
| <i class="@tool.Icon" style="margin-right: 0.75rem; color: var(--primary);"></i> |
| } |
| <div> |
| <strong>@tool.Name</strong> |
| @if (!string.IsNullOrEmpty(tool.Description) && tool.Description.Length > 30) |
| { |
| <br><small style="color: var(--dark-2);">@(tool.Description.Substring(0, 30))...</small> |
| } |
| </div> |
| </div> |
| </td> |
| <td> |
| <span class="badge badge-primary">@tool.Category?.Name</span> |
| </td> |
| <td> |
| @if (tool.IsHot) |
| { |
| <span class="badge badge-danger">热门</span> |
| } |
| @if (tool.IsNew) |
| { |
| <span class="badge badge-warning">新品</span> |
| } |
| @if (tool.IsRecommended) |
| { |
| <span class="badge badge-success">推荐</span> |
| } |
| @if (!tool.IsHot && !tool.IsNew && !tool.IsRecommended) |
| { |
| <span class="badge badge-secondary">普通</span> |
| } |
| </td> |
| <td style="color: var(--dark-2); font-size: 0.875rem;"> |
| @tool.CreatedAt.ToString("MM-dd HH:mm") |
| </td> |
| </tr> |
| } |
| </tbody> |
| </table> |
| } |
| else |
| { |
| <div style="padding: 2rem; text-align: center; color: var(--dark-2);"> |
| <i class="fas fa-inbox" style="font-size: 2rem; margin-bottom: 1rem; display: block;"></i> |
| 暂无工具数据 |
| </div> |
| } |
| |
| <div style="padding: 1rem; border-top: 1px solid var(--light-2); text-align: center;"> |
| <a href="@Url.Action("Index", "Tool")" class="btn btn-outline btn-sm"> |
| 查看所有工具 |
| </a> |
| </div> |
| </div> |
|
|
| |
| <div class="data-table"> |
| <div style="padding: 1.5rem; border-bottom: 1px solid var(--light-2);"> |
| <h3 style="margin: 0; font-size: 1.1rem; font-weight: 600; color: var(--dark);"> |
| <i class="fas fa-bolt" style="margin-right: 0.5rem; color: var(--warning);"></i> |
| 快速操作 |
| </h3> |
| </div> |
| |
| <div style="padding: 1.5rem;"> |
| <div style="display: grid; gap: 1rem;"> |
| <a href="@Url.Action("Index", "Tool")" |
| style="display: flex; align-items: center; padding: 1rem; background: var(--light-1); border-radius: var(--border-radius); text-decoration: none; color: var(--dark); transition: var(--transition);" |
| onmouseover="this.style.background='var(--primary)'; this.style.color='white';" |
| onmouseout="this.style.background='var(--light-1)'; this.style.color='var(--dark)';"> |
| <i class="fas fa-plus-circle" style="font-size: 1.5rem; margin-right: 1rem; color: var(--primary);"></i> |
| <div> |
| <strong>工具管理</strong> |
| <br><small style="opacity: 0.8;">管理平台上的工具</small> |
| </div> |
| </a> |
| |
| <a href="@Url.Action("Index", "Category")" |
| style="display: flex; align-items: center; padding: 1rem; background: var(--light-1); border-radius: var(--border-radius); text-decoration: none; color: var(--dark); transition: var(--transition);" |
| onmouseover="this.style.background='var(--secondary)'; this.style.color='white';" |
| onmouseout="this.style.background='var(--light-1)'; this.style.color='var(--dark)';"> |
| <i class="fas fa-tag" style="font-size: 1.5rem; margin-right: 1rem; color: var(--secondary);"></i> |
| <div> |
| <strong>分类管理</strong> |
| <br><small style="opacity: 0.8;">管理工具分类</small> |
| </div> |
| </a> |
| |
| <a href="@Url.Action("Index", "Tag")" |
| style="display: flex; align-items: center; padding: 1rem; background: var(--light-1); border-radius: var(--border-radius); text-decoration: none; color: var(--dark); transition: var(--transition);" |
| onmouseover="this.style.background='var(--accent)'; this.style.color='white';" |
| onmouseout="this.style.background='var(--light-1)'; this.style.color='var(--dark)';"> |
| <i class="fas fa-tags" style="font-size: 1.5rem; margin-right: 1rem; color: var(--accent);"></i> |
| <div> |
| <strong>标签管理</strong> |
| <br><small style="opacity: 0.8;">管理工具标签</small> |
| </div> |
| </a> |
| |
| <a href="@Url.Action("Users", "Admin")" |
| style="display: flex; align-items: center; padding: 1rem; background: var(--light-1); border-radius: var(--border-radius); text-decoration: none; color: var(--dark); transition: var(--transition);" |
| onmouseover="this.style.background='var(--success)'; this.style.color='white';" |
| onmouseout="this.style.background='var(--light-1)'; this.style.color='var(--dark)';"> |
| <i class="fas fa-user-cog" style="font-size: 1.5rem; margin-right: 1rem; color: var(--success);"></i> |
| <div> |
| <strong>用户管理</strong> |
| <br><small style="opacity: 0.8;">管理注册用户</small> |
| </div> |
| </a> |
| |
| <a href="@Url.Action("Index", "Home")" target="_blank" |
| style="display: flex; align-items: center; padding: 1rem; background: var(--light-1); border-radius: var(--border-radius); text-decoration: none; color: var(--dark); transition: var(--transition);" |
| onmouseover="this.style.background='var(--accent)'; this.style.color='white';" |
| onmouseout="this.style.background='var(--light-1)'; this.style.color='var(--dark)';"> |
| <i class="fas fa-external-link-alt" style="font-size: 1.5rem; margin-right: 1rem; color: var(--accent);"></i> |
| <div> |
| <strong>访问网站</strong> |
| <br><small style="opacity: 0.8;">查看前台网站</small> |
| </div> |
| </a> |
| |
| <button onclick="initImageCompressor()" |
| style="display: flex; align-items: center; padding: 1rem; background: var(--light-1); border-radius: var(--border-radius); border: none; color: var(--dark); transition: var(--transition); cursor: pointer; width: 100%;" |
| onmouseover="this.style.background='var(--warning)'; this.style.color='white';" |
| onmouseout="this.style.background='var(--light-1)'; this.style.color='var(--dark)';"> |
| <i class="fas fa-compress-alt" style="font-size: 1.5rem; margin-right: 1rem; color: var(--warning);"></i> |
| <div style="text-align: left;"> |
| <strong>初始化图片压缩工具</strong> |
| <br><small style="opacity: 0.8;">添加图片压缩工具到数据库</small> |
| </div> |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="data-table mt-6"> |
| <div style="padding: 1.5rem; border-bottom: 1px solid var(--light-2);"> |
| <h3 style="margin: 0; font-size: 1.1rem; font-weight: 600; color: var(--dark);"> |
| <i class="fas fa-info-circle" style="margin-right: 0.5rem; color: var(--primary);"></i> |
| 系统信息 |
| </h3> |
| </div> |
| |
| <div style="padding: 1.5rem;"> |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4"> |
| <div> |
| <strong>系统版本</strong> |
| <p style="color: var(--dark-2); margin: 0.25rem 0 0;">ToolHub v1.0.0</p> |
| </div> |
| <div> |
| <strong>运行环境</strong> |
| <p style="color: var(--dark-2); margin: 0.25rem 0 0;">.NET 9.0</p> |
| </div> |
| <div> |
| <strong>数据库</strong> |
| <p style="color: var(--dark-2); margin: 0.25rem 0 0;">SQLite + FreeSql</p> |
| </div> |
| <div> |
| <strong>服务器时间</strong> |
| <p style="color: var(--dark-2); margin: 0.25rem 0 0;">@DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")</p> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| async function initImageCompressor() { |
| try { |
| const button = event.target.closest('button'); |
| const originalContent = button.innerHTML; |
| |
| |
| button.innerHTML = ` |
| <i class="fas fa-spinner fa-spin" style="font-size: 1.5rem; margin-right: 1rem; color: var(--warning);"></i> |
| <div style="text-align: left;"> |
| <strong>初始化中...</strong> |
| <br><small style="opacity: 0.8;">请稍候</small> |
| </div> |
| `; |
| button.disabled = true; |
| |
| const response = await fetch('/Tool/InitImageCompressor'); |
| const result = await response.json(); |
| |
| if (result.success) { |
| toolHub.showToast('图片压缩工具初始化成功!', 'success'); |
| |
| |
| button.innerHTML = ` |
| <i class="fas fa-check-circle" style="font-size: 1.5rem; margin-right: 1rem; color: var(--success);"></i> |
| <div style="text-align: left;"> |
| <strong>初始化完成</strong> |
| <br><small style="opacity: 0.8;">图片压缩工具已添加</small> |
| </div> |
| `; |
| |
| |
| setTimeout(() => { |
| button.innerHTML = originalContent; |
| button.disabled = false; |
| }, 3000); |
| } else { |
| toolHub.showToast(result.message || '初始化失败', 'error'); |
| button.innerHTML = originalContent; |
| button.disabled = false; |
| } |
| } catch (error) { |
| console.error('初始化失败:', error); |
| toolHub.showToast('初始化失败,请重试', 'error'); |
| |
| |
| const button = event.target.closest('button'); |
| button.innerHTML = originalContent; |
| button.disabled = false; |
| } |
| } |
| </script> |
|
|