觉得后台admin空荡荡的,索性加个图表自己魔改一下下。以下是完整的index.php  感兴趣的可以直接下载index.php文件覆盖/admin 下面的index.php文件 ## 下载地址: https://wonder1999.lanzouu.com/ikRiy32sfnah ```php %s 篇文章, 并有 %s 条关于你的评论在 %s 个分类中.', $stat->myPublishedPostsNum, $stat->myPublishedCommentsNum, $stat->categoriesNum); ?> pass('contributor', true)): ?> pass('editor', true) && 'on' == $request->get('__typecho_all_comments') && $stat->waitingCommentsNum > 0): ?> waitingCommentsNum(); ?> myWaitingCommentsNum > 0): ?> myWaitingCommentsNum(); ?> pass('editor', true) && 'on' == $request->get('__typecho_all_comments') && $stat->spamCommentsNum > 0): ?> spamCommentsNum(); ?> mySpamCommentsNum > 0): ?> mySpamCommentsNum(); ?> pass('administrator', true)): ?> myPublishedPostsNum; ?> myPublishedCommentsNum; ?> categoriesNum; ?> tagsNum; ?> to($posts); ?> have()): ?> next()): ?> date('n.j'); ?> title(); ?> to($comments); ?> have()): ?> next()): ?> date('n.j'); ?> author(false); ?>: excerpt(35, '...'); ?> ``` 其他插件推荐: [post cid="405" /] Loading... 觉得后台admin空荡荡的,索性加个图表自己魔改一下下。以下是完整的index.php  感兴趣的可以直接下载index.php文件覆盖/admin 下面的index.php文件 ## 下载地址: https://wonder1999.lanzouu.com/ikRiy32sfnah ```php <?php include 'common.php'; include 'header.php'; include 'menu.php'; $stat = \Widget\Stat::alloc(); ?> <script src="https://blog.iletter.top/usr/blog_img/chart.js"></script> <!-- 引入 Font Awesome 图标库 --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"> <style> /* 自定义美化样式 */ .typecho-dashboard { padding: 20px 0; } .card { background-color: #fff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); padding: 20px; margin-bottom: 20px; } .card-title { margin-top: 0; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid #eee; color: #333; font-size: 1.2em; } /* 欢迎区域 */ .welcome-card { background: linear-gradient(135deg, #1f1f20 0%, #0076bb 100%); color: white; } .welcome-card h3 { color: white; margin-top: 0; } .welcome-card p { font-size: 1.1em; margin-bottom: 20px; } .welcome-card a { color: #fff; text-decoration: underline; } .welcome-card a:hover { text-decoration: none; opacity: 0.9; } /* 快捷链接 */ #start-link { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 10px; } #start-link li { margin: 0; } #start-link a { display: inline-block; padding: 8px 16px; background-color: rgba(255, 255, 255, 0.2); border-radius: 4px; color: white !important; text-decoration: none; transition: background-color 0.3s ease; } #start-link a:hover { background-color: rgba(255, 255, 255, 0.3); } #start-link .balloon { background-color: #ff6b6b; color: white; border-radius: 10px; padding: 2px 6px; font-size: 0.8em; margin-left: 5px; } /* 统计卡片 */ .stat-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-bottom: 20px; } .stat-card { background-color: #f8f9fa; border: 1px solid #e9ecef; border-radius: 8px; padding: 15px; text-align: center; transition: transform 0.2s ease, box-shadow 0.2s ease; } .stat-icon { font-size: 2em; margin-bottom: 10px; color: #000000; /* 可根据不同类型调整颜色 */ } .stat-number { font-size: 1.8em; font-weight: bold; margin: 5px 0; color: #495057; } .stat-label { font-size: 0.9em; color: #6c757d; } /* 最近列表 */ .latest-link ul { list-style: none; padding: 0; margin: 0; } .latest-link li { padding: 8px 0; border-bottom: 1px solid #eee; } .latest-link li:last-child { border-bottom: none; } .latest-link .title { margin-left: 5px; } .latest-link span { color: #6c757d; font-size: 0.9em; } /* 图表区域 - 重新规划 */ .chart-container { max-width: 1200px; /* 限制图表区域最大宽度 */ margin: 0 auto; /* 水平居中 */ display: flex; flex-direction: column; gap: 20px; } .chart-row { display: flex; gap: 20px; flex-wrap: wrap; } .chart-box { flex: 1; min-width: 250px; /* 调整最小宽度以适应更多屏幕 */ background-color: #fff; border-radius: 8px; /*box-shadow: 0 2px 4px rgba(0,0,0,0.1);*/ padding: 15px; display: flex; flex-direction: column; /* 确保内部元素垂直排列 */ } .chart-box h4 { margin: 0 0 10px 0; /* 调整标题边距 */ text-align: center; color: #333; flex-shrink: 0; /* 防止标题被压缩 */ } .chart-box canvas { width: 100% !important; /* 确保画布宽度占满容器 */ max-height: 300px; /* 限制图表最大高度 */ flex-grow: 1; /* 画布占据剩余空间 */ } /* 响应式调整 */ @media (max-width: 768px) { .stat-cards { grid-template-columns: repeat(2, 1fr); } .chart-row { flex-direction: column; /* 小屏幕时堆叠 */ } .chart-box { min-width: 100%; /* 小屏幕时占满宽度 */ } #start-link { flex-direction: column; } } /* 中等屏幕调整 - 让图表在中等屏幕也能两列显示 */ @media (min-width: 769px) and (max-width: 1100px) { .chart-row { /* 在这个范围内,允许换行,但.chart-box的flex行为会使其尽可能并排 */ } .chart-box { /* 可以微调 min-width 来控制换行点 */ min-width: calc(50% - 10px); } } </style> <div class="main"> <div class="container typecho-dashboard"> <?php include 'page-title.php'; ?> <div class="row typecho-page-main"> <!-- 欢迎卡片 --> <div class="col-mb-12" role="main"> <div class="card welcome-card"> <h3><?php _e('欢迎使用 Typecho'); ?></h3> <p><?php _e('目前有 <em>%s</em> 篇文章, 并有 <em>%s</em> 条关于你的评论在 <em>%s</em> 个分类中.', $stat->myPublishedPostsNum, $stat->myPublishedCommentsNum, $stat->categoriesNum); ?></p> <ul id="start-link" class="clearfix"> <?php if ($user->pass('contributor', true)): ?> <li><a href="<?php $options->adminUrl('write-post.php'); ?>"><i class="fas fa-pen"></i> <?php _e('撰写新文章'); ?></a></li> <?php if ($user->pass('editor', true) && 'on' == $request->get('__typecho_all_comments') && $stat->waitingCommentsNum > 0): ?> <li> <a href="<?php $options->adminUrl('manage-comments.php?status=waiting'); ?>"><i class="fas fa-comments"></i> <?php _e('待审核的评论'); ?></a> <span class="balloon"><?php $stat->waitingCommentsNum(); ?></span> </li> <?php elseif ($stat->myWaitingCommentsNum > 0): ?> <li> <a href="<?php $options->adminUrl('manage-comments.php?status=waiting'); ?>"><i class="fas fa-comments"></i> <?php _e('待审核评论'); ?></a> <span class="balloon"><?php $stat->myWaitingCommentsNum(); ?></span> </li> <?php endif; ?> <?php if ($user->pass('editor', true) && 'on' == $request->get('__typecho_all_comments') && $stat->spamCommentsNum > 0): ?> <li> <a href="<?php $options->adminUrl('manage-comments.php?status=spam'); ?>"><i class="fas fa-trash-alt"></i> <?php _e('垃圾评论'); ?></a> <span class="balloon"><?php $stat->spamCommentsNum(); ?></span> </li> <?php elseif ($stat->mySpamCommentsNum > 0): ?> <li> <a href="<?php $options->adminUrl('manage-comments.php?status=spam'); ?>"><i class="fas fa-trash-alt"></i> <?php _e('垃圾评论'); ?></a> <span class="balloon"><?php $stat->mySpamCommentsNum(); ?></span> </li> <?php endif; ?> <?php if ($user->pass('administrator', true)): ?> <li><a href="<?php $options->adminUrl('manage-posts.php'); ?>"><i class="fas fa-list"></i> <?php _e('文章管理'); ?></a></li> <li><a href="<?php $options->adminUrl('plugins.php'); ?>"><i class="fas fa-plug"></i> <?php _e('插件管理'); ?></a></li> <li><a href="<?php $options->adminUrl('options-general.php'); ?>"><i class="fas fa-cog"></i> <?php _e('系统设置'); ?></a></li> <?php endif; ?> <?php endif; ?> </ul> </div> </div> <!-- 统计卡片 --> <div class="col-mb-12"> <div class="stat-cards"> <div class="stat-card"> <a href="<?php $options->adminUrl('manage-posts.php'); ?>"> <div class="stat-icon"><i class="fas fa-file-alt"></i></div> <div class="stat-number"><?php echo $stat->myPublishedPostsNum; ?></div> <div class="stat-label"><?php _e('文章'); ?></div> </a> </div> <div class="stat-card"> <a href="<?php $options->adminUrl('manage-comments.php'); ?>"> <div class="stat-icon"><i class="fas fa-comment"></i></div> <div class="stat-number"><?php echo $stat->myPublishedCommentsNum; ?></div> <div class="stat-label"><?php _e('评论'); ?></div> </a> </div> <div class="stat-card"> <a href="<?php $options->adminUrl('manage-categories.php'); ?>"> <div class="stat-icon"><i class="fas fa-folder"></i></div> <div class="stat-number"><?php echo $stat->categoriesNum; ?></div> <div class="stat-label"><?php _e('分类'); ?></div> </a> </div> <div class="stat-card"> <a href="<?php $options->adminUrl('manage-tags.php'); ?>"> <div class="stat-icon"><i class="fas fa-tags"></i></div> <div class="stat-number"><?php echo $stat->tagsNum; ?></div> <div class="stat-label"><?php _e('标签'); ?></div> </a> </div> <!-- 可根据需要添加更多统计 --> </div> </div> <!-- 左侧内容:最近文章 --> <div class="col-mb-12 col-tb-6" role="complementary"> <div class="card"> <h3 class="card-title"><?php _e('最近发布的文章'); ?></h3> <?php \Widget\Contents\Post\Recent::alloc('pageSize=10')->to($posts); ?> <ul class="latest-link"> <?php if ($posts->have()): ?> <?php while ($posts->next()): ?> <li> <span><?php $posts->date('n.j'); ?></span> <a href="<?php $posts->permalink(); ?>" class="title"><?php $posts->title(); ?></a> </li> <?php endwhile; ?> <?php else: ?> <li><em><?php _e('暂时没有文章'); ?></em></li> <?php endif; ?> </ul> </div> </div> <!-- 右侧内容:最近评论 --> <div class="col-mb-12 col-tb-6" role="complementary"> <div class="card"> <h3 class="card-title"><?php _e('最近得到的回复'); ?></h3> <ul class="latest-link"> <?php \Widget\Comments\Recent::alloc('pageSize=10')->to($comments); ?> <?php if ($comments->have()): ?> <?php while ($comments->next()): ?> <li> <span><?php $comments->date('n.j'); ?></span> <a href="<?php $comments->permalink(); ?>" class="title"><?php $comments->author(false); ?></a>: <?php $comments->excerpt(35, '...'); ?> </li> <?php endwhile; ?> <?php else: ?> <li><?php _e('暂时没有回复'); ?></li> <?php endif; ?> </ul> </div> </div> <!-- 图表显示区域 --> <div class="col-mb-12" role="complementary"> <div class="card"> <h3 class="card-title" style="color: #333;"><?php _e('文章统计数据'); ?></h3> <div class="chart-container"> <div class="chart-row"> <!-- 月度发布图表 --> <div class="chart-box"> <h4><?php _e('月度文章发布趋势'); ?></h4> <canvas id="monthlyPostChart" height="250"></canvas> </div> <!-- 状态分布图表 --> <div class="chart-box"> <h4><?php _e('文章状态分布'); ?></h4> <canvas id="statusChart" height="250"></canvas> </div> </div> <div class="chart-row"> <!-- 分类文章统计 --> <div class="chart-box"> <h4><?php _e('各分类文章数量'); ?></h4> <canvas id="categoryChart" height="250"></canvas> </div> <!-- 标签文章统计 --> <div class="chart-box"> <h4><?php _e('热门标签文章数量 (Top10)'); ?></h4> <canvas id="tagChart" height="250"></canvas> </div> </div> </div> </div> </div> </div> </div> </div> <?php include 'copyright.php'; include 'common-js.php'; ?> <script> $(document).ready(function() { <?php // ==================== PHP 数据计算部分 ==================== // 1. 月度文章统计数据 $db = Typecho_Db::get(); // 月度文章统计 $select = $db->select() ->from('table.contents') ->where('type = ?', 'post') ->where('status = ?', 'publish'); $posts = $db->fetchAll($select); $monthlyData = []; $monthLabels = []; $currentYear = date('Y'); $currentMonth = date('n'); // 初始化最近12个月的数据 for ($i = 11; $i >= 0; $i--) { $year = $currentYear; $month = $currentMonth - $i; if ($month <= 0) { $month += 12; $year--; } $key = $year . '-' . str_pad($month, 2, '0', STR_PAD_LEFT); $monthlyData[$key] = 0; $monthLabels[$key] = $year . '年' . $month . '月'; } // 统计实际数据 foreach ($posts as $post) { $created = $post['created']; $year = date('Y', $created); $month = date('m', $created); $key = $year . '-' . $month; if (isset($monthlyData[$key])) { $monthlyData[$key]++; } } // 2. 文章状态统计 $published = $db->fetchObject($db->select(['COUNT(*)' => 'count']) ->from('table.contents') ->where('type = ?', 'post') ->where('status = ?', 'publish'))->count; $draft = $db->fetchObject($db->select(['COUNT(*)' => 'count']) ->from('table.contents') ->where('type = ?', 'post_draft') // 注意:Typecho 草稿通常在 contents 表中 type 为 post_draft // ->where('status = ?', 'publish') // 草稿状态通常不是 publish,可以省略或检查实际结构 )->count; // 3. 分类文章统计 $categories = $db->fetchAll($db->select()->from('table.metas')->where('type = ?', 'category')); $categoryData = []; $categoryLabels = []; foreach ($categories as $category) { $count = $db->fetchObject($db->select(['COUNT(*)' => 'count']) ->from('table.relationships') ->where('mid = ?', $category['mid']))->count; if ($count > 0) { // 只显示有文章的分类 $categoryLabels[] = $category['name']; $categoryData[] = (int)$count; } } // 4. 标签文章统计 (取前10个) $tags = $db->fetchAll($db->select()->from('table.metas')->where('type = ?', 'tag')); $tagData = []; $tagLabels = []; foreach ($tags as $tag) { $count = $db->fetchObject($db->select(['COUNT(*)' => 'count']) ->from('table.relationships') ->where('mid = ?', $tag['mid']))->count; if ($count > 0) { $tagLabels[] = $tag['name']; $tagData[] = (int)$count; } } // 按数量排序,取前10个 array_multisort($tagData, SORT_DESC, $tagLabels); $topTagLabels = array_slice($tagLabels, 0, 10); $topTagData = array_slice($tagData, 0, 10); // 准备图表数据 $chartMonthlyData = [ 'labels' => array_values($monthLabels), 'values' => array_values($monthlyData) ]; $chartStatusData = [ 'published' => (int)$published, 'draft' => (int)$draft ]; $chartCategoryData = [ 'labels' => $categoryLabels, 'values' => $categoryData ]; $chartTagData = [ 'labels' => $topTagLabels, 'values' => $topTagData ]; ?> // ==================== JavaScript 图表渲染部分 ==================== // 1. 月度文章图表 var monthlyData = <?php echo json_encode($chartMonthlyData); ?>; if (monthlyData.labels && monthlyData.labels.length > 0) { var ctx1 = document.getElementById('monthlyPostChart').getContext('2d'); new Chart(ctx1, { type: 'line', data: { labels: monthlyData.labels, datasets: [{ label: '每月发文数', data: monthlyData.values, borderColor: 'rgb(54, 162, 235)', // 调整为蓝色系 backgroundColor: 'rgba(54, 162, 235, 0.1)', tension: 0.3, // 稍微增加曲线张力 fill: true }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, ticks: { precision: 0 }, grid: { color: 'rgba(0, 0, 0, 0.05)' // 网格线颜色 } }, x: { grid: { color: 'rgba(0, 0, 0, 0.05)' } } }, plugins: { legend: { display: false // 隐藏图例,因为只有一个数据集 }, tooltip: { mode: 'index', intersect: false } } } }); } // 2. 文章状态图表 var statusData = <?php echo json_encode($chartStatusData); ?>; if (statusData) { var ctx2 = document.getElementById('statusChart').getContext('2d'); new Chart(ctx2, { type: 'doughnut', data: { labels: ['已发布', '草稿'], datasets: [{ data: [statusData.published, statusData.draft], backgroundColor: [ 'rgba(75, 192, 192, 0.8)', // 已发布 - 青色 'rgba(255, 205, 86, 0.8)', // 草稿 - 黄色 ], borderWidth: 1, borderColor: '#fff' }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom', labels: { padding: 15, usePointStyle: true } }, tooltip: { callbacks: { label: function(context) { return context.label + ': ' + context.raw; } } } }, cutout: '60%' // 增加中间空心部分 } }); } // 3. 分类文章图表 var categoryData = <?php echo json_encode($chartCategoryData); ?>; if (categoryData.labels && categoryData.labels.length > 0) { var ctx3 = document.getElementById('categoryChart').getContext('2d'); new Chart(ctx3, { type: 'bar', data: { labels: categoryData.labels, datasets: [{ label: '文章数量', data: categoryData.values, backgroundColor: 'rgba(153, 102, 255, 0.7)', // 紫色系 borderColor: 'rgba(153, 102, 255, 1)', borderWidth: 1, borderRadius: 4, // 条形圆角 barPercentage: 0.7, // 调整条形宽度 categoryPercentage: 0.8 }] }, options: { indexAxis: 'x', // 保持为垂直柱状图 responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, ticks: { precision: 0 }, grid: { color: 'rgba(0, 0, 0, 0.05)' } }, x: { grid: { display: false // 隐藏 X 轴网格线 } } }, plugins: { legend: { display: false }, tooltip: { mode: 'index', intersect: false } } } }); } // 4. 标签文章图表 var tagData = <?php echo json_encode($chartTagData); ?>; if (tagData.labels && tagData.labels.length > 0) { var ctx4 = document.getElementById('tagChart').getContext('2d'); new Chart(ctx4, { type: 'bar', data: { labels: tagData.labels, datasets: [{ label: '文章数量', data: tagData.values, backgroundColor: 'rgba(255, 159, 64, 0.7)', // 橙色系 borderColor: 'rgba(255, 159, 64, 1)', borderWidth: 1, borderRadius: 4, barPercentage: 0.7, categoryPercentage: 0.8 }] }, options: { indexAxis: 'x', responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, ticks: { precision: 0 }, grid: { color: 'rgba(0, 0, 0, 0.05)' } }, x: { grid: { display: false } } }, plugins: { legend: { display: false }, tooltip: { mode: 'index', intersect: false } } } }); } }); </script> <script> $(document).ready(function () { }); </script> <?php include 'footer.php'; ?> ``` 其他插件推荐: <div class="preview"> <div class="post-inser post box-shadow-wrap-normal"> <a href="https://blog.iletter.top/archives/405.html" target="_blank" class="post_inser_a no-external-link no-underline-link"> <div class="inner-image bg" style="background-image: url(https://blog.iletter.top/usr/themes/handsome/assets/img/sj/4.jpg);background-size: cover;"></div> <div class="inner-content" > <p class="inser-title">为typecho博客添加Gotify插件通知</p> <div class="inster-summary text-muted"> 受限于typecho博客没有通知,自己写了一个博客有评论就通知的gotify插件,脚本使用之前的python改的。... </div> </div> </a> <!-- .inner-content #####--> </div> <!-- .post-inser ####--> </div> 最后修改:2025 年 08 月 07 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 1 如果觉得我的文章对你有用,请随意赞赏