Files
TimeProgressStats/Plugin.php
2026-02-23 20:04:21 +08:00

1061 lines
30 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 归档页统计、时间、目标进度统计
*
* @package TimeProgressStats
* @author 石头厝
* @version 2.8.0
* @link https://www.shitoucuo.com/
*/
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
class TimeProgressStats_Plugin implements Typecho_Plugin_Interface
{
/**
* 激活插件
*/
public static function activate()
{
Typecho_Plugin::factory('Widget_Archive')->header = array('TimeProgressStats_Plugin', 'header');
Typecho_Plugin::factory('Widget_Archive')->footer = array('TimeProgressStats_Plugin', 'footer');
return '插件已激活';
}
/**
* 禁用插件
*/
public static function deactivate()
{
return '插件已禁用';
}
/**
* 插件配置
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
// 是否开启插件
$enable = new Typecho_Widget_Helper_Form_Element_Radio('enable', array(
'1' => '开启',
'0' => '关闭'
), '1', '是否开启插件', '启用或禁用时间进度统计功能');
$form->addInput($enable);
// 博客建立日期
$blog_start_date = new Typecho_Widget_Helper_Form_Element_Text('blog_start_date', null, date('Y-m-d'),
_t('博客建立日期'), _t('设置博客建立的日期用于计算运行天数格式YYYY-MM-DD'));
$form->addInput($blog_start_date);
// 显示样式设置
$style = new Typecho_Widget_Helper_Form_Element_Radio('style', array(
'card' => '卡片样式',
'simple' => '简洁样式',
'modern' => '现代样式'
), 'card', '显示样式', '选择统计信息的显示样式');
$form->addInput($style);
// 更新速度设置
$updateSpeed = new Typecho_Widget_Helper_Form_Element_Select('update_speed', array(
'100' => '0.1秒(非常流畅)',
'200' => '0.2秒(流畅)',
'500' => '0.5秒(标准)',
'1000' => '1秒节能'
), '200', '更新速度', '设置实时更新的速度');
$form->addInput($updateSpeed);
// 显示实时时钟
$showClock = new Typecho_Widget_Helper_Form_Element_Radio('show_clock', array(
'1' => '显示',
'0' => '隐藏'
), '1', '实时时钟', '是否显示实时时钟');
$form->addInput($showClock);
// 今年文章目标
$postGoal = new Typecho_Widget_Helper_Form_Element_Text('post_goal', null, '50',
_t('今年文章目标'), _t('设置今年计划写的文章数量'));
$form->addInput($postGoal);
// 今年字数目标
$charGoal = new Typecho_Widget_Helper_Form_Element_Text('char_goal', null, '100000',
_t('今年字数目标'), _t('设置今年计划写的总字数'));
$form->addInput($charGoal);
}
/**
* 个人配置
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form) {}
/**
* 获取统计数据
*/
public static function getStats()
{
$db = Typecho_Db::get();
$currentYear = date('Y');
$currentMonth = date('n');
// 今年文章
$yearPosts = $db->fetchRow($db->select('COUNT(*) as total')
->from('table.contents')
->where('type = ?', 'post')
->where('status = ?', 'publish')
->where('YEAR(FROM_UNIXTIME(created)) = ?', $currentYear));
// 本月文章
$monthPosts = $db->fetchRow($db->select('COUNT(*) as total')
->from('table.contents')
->where('type = ?', 'post')
->where('status = ?', 'publish')
->where('YEAR(FROM_UNIXTIME(created)) = ?', $currentYear)
->where('MONTH(FROM_UNIXTIME(created)) = ?', $currentMonth));
// 本月字数
$monthChars = $db->fetchRow($db->select('SUM(LENGTH(text)) as total')
->from('table.contents')
->where('type = ?', 'post')
->where('status = ?', 'publish')
->where('YEAR(FROM_UNIXTIME(created)) = ?', $currentYear)
->where('MONTH(FROM_UNIXTIME(created)) = ?', $currentMonth));
// 标签总数
$tags = $db->fetchRow($db->select('COUNT(*) as total')
->from('table.metas')
->where('type = ?', 'tag'));
// 分类总数
$categories = $db->fetchRow($db->select('COUNT(*) as total')
->from('table.metas')
->where('type = ?', 'category'));
// 评论总数(已审核)
$comments = $db->fetchRow($db->select('COUNT(*) as total')
->from('table.comments')
->where('status = ?', 'approved'));
// 文章总数
$totalPosts = $db->fetchRow($db->select('COUNT(*) as total')
->from('table.contents')
->where('type = ?', 'post')
->where('status = ?', 'publish'));
// 累计字数(全部)
$totalChars = $db->fetchRow($db->select('SUM(LENGTH(text)) as total')
->from('table.contents')
->where('type = ?', 'post')
->where('status = ?', 'publish'));
// 今年字数
$yearChars = $db->fetchRow($db->select('SUM(LENGTH(text)) as total')
->from('table.contents')
->where('type = ?', 'post')
->where('status = ?', 'publish')
->where('YEAR(FROM_UNIXTIME(created)) = ?', $currentYear));
return array(
'year_posts' => isset($yearPosts['total']) ? intval($yearPosts['total']) : 0,
'month_posts' => isset($monthPosts['total']) ? intval($monthPosts['total']) : 0,
'month_chars' => isset($monthChars['total']) ? intval($monthChars['total']) : 0,
'total_tags' => isset($tags['total']) ? intval($tags['total']) : 0,
'total_categories' => isset($categories['total']) ? intval($categories['total']) : 0,
'total_comments' => isset($comments['total']) ? intval($comments['total']) : 0,
'total_posts' => isset($totalPosts['total']) ? intval($totalPosts['total']) : 0,
'total_chars' => isset($totalChars['total']) ? intval($totalChars['total']) : 0,
'year_chars' => isset($yearChars['total']) ? intval($yearChars['total']) : 0
);
}
/**
* 获取运行天数
*/
private static function getRunningDays($blogStartDate)
{
try {
$startDate = new DateTime($blogStartDate);
$today = new DateTime();
$interval = $startDate->diff($today);
return $interval->days + 1; // +1 包含今天
} catch (Exception $e) {
// 如果日期格式错误,使用默认值
return 0;
}
}
/**
* 格式化数字
*/
private static function formatNumber($number)
{
$number = intval($number);
if ($number >= 100000000) {
return round($number / 100000000, 2) . '亿';
} elseif ($number >= 10000) {
return round($number / 10000, 1) . '万';
}
return number_format($number);
}
/**
* 渲染统计数据
*/
public static function renderStats($config = null)
{
if (!$config) {
$options = Typecho_Widget::widget('Widget_Options');
$config = $options->plugin('TimeProgressStats');
}
// 检查插件是否开启
if (isset($config->enable) && $config->enable == '0') {
return '';
}
$stats = self::getStats();
$year = date('Y');
$hour = date('H');
$minute = date('i');
$second = date('s');
// 获取运行天数
$runningDays = 0;
if (isset($config->blog_start_date) && !empty($config->blog_start_date)) {
$runningDays = self::getRunningDays($config->blog_start_date);
}
// 时间计算
$isLeapYear = (($year % 400 == 0) || ($year % 4 == 0 && $year % 100 != 0));
$totalDays = $isLeapYear ? 366 : 365;
$dayOfYear = date('z') + 1;
$remainingDays = $totalDays - $dayOfYear;
// 进度计算
$yearProgress = ($dayOfYear / $totalDays) * 100;
$totalSecondsToday = $hour * 3600 + $minute * 60 + $second;
$dayProgress = ($totalSecondsToday / 86400) * 100;
// 年度目标计算
$postGoal = isset($config->post_goal) ? intval($config->post_goal) : 50;
$charGoal = isset($config->char_goal) ? intval($config->char_goal) : 100000;
// 月度目标计算年度目标除以12
$monthPostGoal = ceil($postGoal / 12);
$monthCharGoal = ceil($charGoal / 12);
// 进度计算
$postGoalProgress = $postGoal > 0 ? ($stats['year_posts'] / $postGoal) * 100 : 0;
$charGoalProgress = $charGoal > 0 ? ($stats['year_chars'] / $charGoal) * 100 : 0;
$monthPostGoalProgress = $monthPostGoal > 0 ? ($stats['month_posts'] / $monthPostGoal) * 100 : 0;
$monthCharGoalProgress = $monthCharGoal > 0 ? ($stats['month_chars'] / $monthCharGoal) * 100 : 0;
// 格式化显示
$charsFormatted = self::formatNumber($stats['total_chars']);
$yearCharsFormatted = self::formatNumber($stats['year_chars']);
$monthCharsFormatted = self::formatNumber($stats['month_chars']);
$styleClass = 'tps-card';
if ($config && $config->style) {
$styleClass = 'tps-' . $config->style;
}
$showClockClass = '';
if ($config && isset($config->show_clock) && $config->show_clock == '1') {
$showClockClass = 'tps-has-clock';
}
ob_start();
?>
<div class="time-progress-stats <?php echo $styleClass; ?> <?php echo $showClockClass; ?>" id="tps-container">
<div class="tps-header">
<h3>🎯 实时数据</h3>
<div class="tps-time" id="tps-time-display">
<span class="tps-year"><?php echo $year; ?>年</span>
<span class="tps-day">第<?php echo $dayOfYear; ?>天</span>
<span class="tps-remaining">仅剩<?php echo $remainingDays; ?>天</span>
<?php if ($config && isset($config->show_clock) && $config->show_clock == '1'): ?>
<span id="tps-live-clock"><?php echo sprintf('%02d:%02d:%02d', $hour, $minute, $second); ?></span>
<?php endif; ?>
</div>
</div>
<div class="tps-content">
<!-- 新增:站点统计区 -->
<div class="tps-stats-area">
<div class="tps-stats-grid">
<div class="tps-stat-item">
<div class="tps-stat-title">运行天数</div>
<div class="tps-stat-value"><?php echo $runningDays; ?>天</div>
</div>
<div class="tps-stat-item">
<div class="tps-stat-title">分类数量</div>
<div class="tps-stat-value"><?php echo $stats['total_categories']; ?>个</div>
</div>
<div class="tps-stat-item">
<div class="tps-stat-title">标签总数</div>
<div class="tps-stat-value"><?php echo $stats['total_tags']; ?>个</div>
</div>
<div class="tps-stat-item">
<div class="tps-stat-title">文章总数</div>
<div class="tps-stat-value"><?php echo $stats['total_posts']; ?>篇</div>
</div>
<div class="tps-stat-item">
<div class="tps-stat-title">评论总数</div>
<div class="tps-stat-value"><?php echo $stats['total_comments']; ?>条</div>
</div>
<div class="tps-stat-item">
<div class="tps-stat-title">累计字数</div>
<div class="tps-stat-value"><?php echo $charsFormatted; ?>字</div>
</div>
</div>
</div>
<!-- 时间进度区 -->
<div class="tps-progress-area">
<div class="tps-progress-row">
<div class="tps-progress-info">
<span class="tps-progress-title">今年进度</span>
<span class="tps-progress-percent" id="tps-year-percent"><?php echo number_format($yearProgress, 6); ?>%</span>
</div>
<div class="tps-progress-track">
<div class="tps-progress-fill" id="tps-year-bar" style="width: <?php echo min($yearProgress, 100); ?>%"></div>
</div>
</div>
<div class="tps-progress-row">
<div class="tps-progress-info">
<span class="tps-progress-title">今日进度</span>
<span class="tps-progress-percent" id="tps-day-percent"><?php echo number_format($dayProgress, 6); ?>%</span>
</div>
<div class="tps-progress-track">
<div class="tps-progress-fill" id="tps-day-bar" style="width: <?php echo min($dayProgress, 100); ?>%"></div>
</div>
</div>
</div>
<!-- 年度目标进度区 -->
<div class="tps-goal-area">
<div class="tps-goal-row">
<div class="tps-goal-info">
<span class="tps-goal-title">今年文章</span>
<span class="tps-goal-status"><?php echo $stats['year_posts']; ?>篇 / <?php echo $postGoal; ?>篇</span>
<span class="tps-goal-percent"><?php echo number_format($postGoalProgress, 1); ?>%</span>
</div>
<div class="tps-progress-track tps-goal-track">
<div class="tps-goal-fill" style="width: <?php echo min($postGoalProgress, 100); ?>%"></div>
</div>
</div>
<div class="tps-goal-row">
<div class="tps-goal-info">
<span class="tps-goal-title">今年字数</span>
<span class="tps-goal-status"><?php echo $yearCharsFormatted; ?> / <?php echo self::formatNumber($charGoal); ?></span>
<span class="tps-goal-percent"><?php echo number_format($charGoalProgress, 1); ?>%</span>
</div>
<div class="tps-progress-track tps-goal-track">
<div class="tps-goal-fill" style="width: <?php echo min($charGoalProgress, 100); ?>%"></div>
</div>
</div>
</div>
<!-- 月度目标进度区 -->
<div class="tps-month-goal-area">
<div class="tps-month-goal-row">
<div class="tps-month-goal-info">
<span class="tps-month-goal-title">本月文章</span>
<span class="tps-month-goal-status"><?php echo $stats['month_posts']; ?>篇 / <?php echo $monthPostGoal; ?>篇</span>
<span class="tps-month-goal-percent"><?php echo number_format($monthPostGoalProgress, 1); ?>%</span>
</div>
<div class="tps-progress-track tps-month-goal-track">
<div class="tps-month-goal-fill" style="width: <?php echo min($monthPostGoalProgress, 100); ?>%"></div>
</div>
</div>
<div class="tps-month-goal-row">
<div class="tps-month-goal-info">
<span class="tps-month-goal-title">本月字数</span>
<span class="tps-month-goal-status"><?php echo $monthCharsFormatted; ?> / <?php echo self::formatNumber($monthCharGoal); ?></span>
<span class="tps-month-goal-percent"><?php echo number_format($monthCharGoalProgress, 1); ?>%</span>
</div>
<div class="tps-progress-track tps-month-goal-track">
<div class="tps-month-goal-fill" style="width: <?php echo min($monthCharGoalProgress, 100); ?>%"></div>
</div>
</div>
</div>
</div>
</div>
<script>
// 时间进度实时更新系统 - 完善版
(function() {
'use strict';
function initTimeProgress() {
var container = document.getElementById('tps-container');
if (!container) return;
// 核心更新函数
function updateTimeProgress() {
var now = new Date();
var year = now.getFullYear();
var hours = now.getHours();
var minutes = now.getMinutes();
var seconds = now.getSeconds();
var milliseconds = now.getMilliseconds();
// 更新时钟
var clock = document.getElementById('tps-live-clock');
if (clock) {
clock.textContent = padZero(hours) + ':' + padZero(minutes) + ':' + padZero(seconds);
}
// 计算今年进度
var startOfYear = new Date(year, 0, 1);
var msPassed = now.getTime() - startOfYear.getTime();
var daysPassed = msPassed / (1000 * 60 * 60 * 24);
var isLeapYear = (year % 400 === 0) || (year % 4 === 0 && year % 100 !== 0);
var totalDays = isLeapYear ? 366 : 365;
var yearProgress = (daysPassed / totalDays) * 100;
// 计算今天进度
var msPassedToday = (hours * 3600 + minutes * 60 + seconds) * 1000 + milliseconds;
var dayProgress = (msPassedToday / 86400000) * 100;
// 更新显示
var yearPercent = document.getElementById('tps-year-percent');
var dayPercent = document.getElementById('tps-day-percent');
var yearBar = document.getElementById('tps-year-bar');
var dayBar = document.getElementById('tps-day-bar');
if (yearPercent) yearPercent.textContent = yearProgress.toFixed(6) + '%';
if (yearBar) yearBar.style.width = Math.min(yearProgress, 100) + '%';
if (dayPercent) dayPercent.textContent = dayProgress.toFixed(6) + '%';
if (dayBar) dayBar.style.width = Math.min(dayProgress, 100) + '%';
}
function padZero(num) {
return (num < 10 ? '0' : '') + num;
}
// 立即执行一次
updateTimeProgress();
// 启动定时器
setInterval(updateTimeProgress, 200);
}
// 页面加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initTimeProgress);
} else {
initTimeProgress();
}
})();
</script>
<?php
return ob_get_clean();
}
/**
* 头部样式
*/
public static function header()
{
?>
<style>
/* 时间进度统计组件深色模式适配 */
.dark .time-stats-container,
.dark div[class*="time-stats"],
.dark div[class*="time-progress"] {
background: rgb(10 12 25 / var(--tw-bg-opacity))!important;
color: #e2e8f0 !important;
border-color: rgba(255, 255, 255, 0.1) !important;
}
.dark .time-stats-title,
.dark h2[class*="time-stats"],
.dark h3[class*="time-stats"] {
color: #e2e8f0 !important;
}
.dark .time-stat-item,
.dark div[class*="stat-item"] {
background: rgba(30, 35, 50, 0.8) !important;
color: #cbd5e0 !important;
}
.dark .time-progress-bar,
.dark div[class*="progress-bar"] {
background: rgba(255, 255, 255, 0.1) !important;
}
.dark .time-progress-fill,
.dark div[class*="progress-fill"] {
background: linear-gradient(90deg, #f15a22, #ff8c42) !important;
}
.dark .time-progress-value,
.dark span[class*="progress-value"],
.dark span[class*="stat-value"] {
color: #cbd5e0 !important;
}
.dark .tps-month-goal-area,
.dark .tps-progress-area,
.dark .tps-goal-area,
.dark .tps-stats-area {
background-color: hsl(0 0% 15%);
}
.dark .time-stat-label,
.dark span[class*="stat-label"] {
color: #a0aec0 !important;
}
.dark .time-stat-description,
.dark p[class*="stat-description"] {
color: #94a3b8 !important;
}
/* 通用深色模式文本颜色 */
.dark .dark\\:text-gray-400 {
color: #9ca3af !important;
}
.dark .dark\\:text-neutral-300 {
color: #d1d5db !important;
}
/* 基础容器 - 增加上边距 */
.time-progress-stats {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
margin: 30px 0 20px 0;
border-radius: 12px;
overflow: hidden;
box-sizing: border-box;
}
.tps-card {
background: #eee;
color: #666;
}
.tps-simple {
background: #ffffff;
border: 1px solid #e1e8ed;
color: #333;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.tps-modern {
background: linear-gradient(135deg, #141e30 0%, #243b55 100%);
color: #fff;
border: 1px solid #2c3e50;
}
.dark .tps-header{
background: rgb(10 12 25 / var(--tw-bg-opacity));
}
.tps-header {
padding: 18px 24px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
background: #eee;
}
.tps-simple .tps-header {
border-bottom: 1px solid #e1e8ed;
background: #f8f9fa;
}
.tps-modern .tps-header {
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(0, 0, 0, 0.2);
}
.tps-header h3 {
margin: 0;
font-size: 1.5em;
font-weight: 600;
display: flex; /* 添加这行 */
align-items: center; /* 添加这行 */
gap: 8px; /* 添加这行,调整图标和文字间距 */
}
#tps-time-display {
font-size: 14px;
font-family: 'Courier New', monospace;
text-align: right;
display: flex;
align-items: center;
gap: 10px;
}
.tps-year,
.tps-day,
.tps-remaining {
font-weight: 500;
}
.tps-remaining {
color: #ff6b6b;
font-weight: bold;
}
.tps-simple .tps-remaining {
color: #ff4757;
}
.tps-modern .tps-remaining {
color: #ff6b6b;
}
#tps-live-clock {
color: #00ff88;
font-weight: bold;
}
.tps-simple #tps-live-clock {
color: #1890ff;
}
.tps-modern #tps-live-clock {
color: #00c6ff;
}
.tps-content {
padding: 20px 20px 0px;
}
/* 新增:站点统计区样式 */
.tps-stats-area {
margin-bottom: 25px;
padding: 20px;
background: #faf8f1;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.15);
}
.tps-simple .tps-stats-area {
background: #f8f9fa;
border: 1px solid #e1e8ed;
}
.tps-modern .tps-stats-area {
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.05);
}
.tps-stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
}
.tps-stat-item {
padding: 15px;
background:#eee;
border-radius: 8px;
text-align: center;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
.tps-stat-item:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.tps-simple .tps-stat-item {
background: #ffffff;
border: 1px solid #e1e8ed;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.tps-simple .tps-stat-item:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.tps-modern .tps-stat-item {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.dark .tps-stat-title{color:#fff;}
.tps-stat-title {
font-size: 13px;
opacity: 0.9;
margin-bottom: 8px;
color: #666;
}
.tps-simple .tps-stat-title {
color: #666;
}
.tps-modern .tps-stat-title {
color: rgba(255, 255, 255, 0.8);
}
.tps-stat-value {
font-size: 18px;
font-weight: bold;
color: #f15a22;
}
.tps-simple .tps-stat-value {
color: #1890ff;
}
.tps-modern .tps-stat-value {
color: #00c6ff;
}
.tps-progress-area {
margin-bottom: 25px;
padding: 20px;
background: #faf8f1;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.15);
}
.tps-progress-row:last-child {
margin-bottom: 0;
}
.tps-progress-row {
margin-bottom: 20px;
}
.tps-progress-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.tps-progress-title {
font-size: 15px;
font-weight: 500;
}
/* 时间进度百分比颜色 - 与进度条颜色保持一致 */
.tps-progress-percent {
font-family: 'Courier New', monospace;
font-size: 16px;
font-weight: bold;
}
/* 卡片样式时间进度百分比颜色 */
.tps-card .tps-progress-percent {
color: #f15a22; /* 与进度条左侧颜色一致 */
}
.tps-simple .tps-progress-percent {
color: #1890ff;
}
.tps-modern .tps-progress-percent {
color: #00c6ff;
}
.tps-progress-track {
height: 10px;
background: rgba(255, 255, 255, 0.1);
border-radius: 5px;
overflow: hidden;
margin-bottom: 6px;
position: relative;
}
.tps-simple .tps-progress-track {
background: #f0f0f0;
}
.tps-modern .tps-progress-track {
background: rgba(255, 255, 255, 0.05);
}
.tps-progress-fill {
height: 100%;
border-radius: 5px;
transition: width 0.1s linear !important;
}
/* 时间进度条颜色 */
.tps-card .tps-progress-fill {
background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%);
}
.tps-simple .tps-progress-fill {
background: linear-gradient(90deg, #1890ff 0%, #36cfc9 100%);
}
.tps-modern .tps-progress-fill {
background: linear-gradient(90deg, #00c6ff 0%, #0072ff 100%);
}
.tps-progress-detail {
font-size: 13px;
opacity: 0.9;
text-align: center;
color: rgba(255, 255, 255, 0.8);
}
.tps-simple .tps-progress-detail {
color: #666;
}
.tps-modern .tps-progress-detail {
color: rgba(255, 255, 255, 0.7);
}
/* 年度目标区域样式 */
.tps-goal-area {
margin-bottom: 25px;
padding: 20px;
background: #faf8f1;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.tps-simple .tps-goal-area {
background: #f8f9fa;
border: 1px solid #e1e8ed;
}
.tps-modern .tps-goal-area {
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.05);
}
.tps-goal-row {
margin-bottom: 15px;
}
.tps-goal-row:last-child {
margin-bottom: 0;
}
.tps-goal-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.tps-goal-title {
font-size: 14px;
font-weight: 500;
flex: 1;
}
.tps-goal-status {
font-size: 14px;
font-weight: 500;
margin: 0 10px;
font-family: 'Courier New', monospace;
}
/* 年度目标百分比颜色 - 与进度条颜色保持一致 */
.tps-goal-percent {
font-family: 'Courier New', monospace;
font-size: 14px;
font-weight: bold;
min-width: 50px;
text-align: right;
}
/* 卡片样式年度目标百分比颜色 */
.tps-card .tps-goal-percent {
color: #ffd166; /* 与进度条左侧颜色一致 */
}
.tps-simple .tps-goal-percent {
color: #ffd166;
}
.tps-modern .tps-goal-percent {
color: #ffd166;
}
.tps-goal-track {
position: relative;
overflow: visible;
}
.tps-goal-fill {
height: 100%;
border-radius: 5px;
background: linear-gradient(90deg, #ffd166 0%, #ff9e6d 100%);
max-width: 100%;
}
.tps-simple .tps-goal-fill {
background: linear-gradient(90deg, #ffd166 0%, #ff9e6d 100%);
}
.tps-modern .tps-goal-fill {
background: linear-gradient(90deg, #ffd166 0%, #ff9e6d 100%);
}
/* 月度目标区域样式 */
.tps-month-goal-area {
margin-bottom: 25px;
padding: 20px;
background:#faf8f1;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.tps-simple .tps-month-goal-area {
background: #f8f9fa;
border: 1px solid #e1e8ed;
}
.tps-modern .tps-month-goal-area {
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.05);
}
.tps-month-goal-row {
margin-bottom: 15px;
}
.tps-month-goal-row:last-child {
margin-bottom: 0;
}
.tps-month-goal-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.tps-month-goal-title {
font-size: 14px;
font-weight: 500;
flex: 1;
}
.tps-month-goal-status {
font-size: 14px;
font-weight: 500;
margin: 0 10px;
font-family: 'Courier New', monospace;
}
/* 月度目标百分比颜色 - 与进度条颜色保持一致(偏橙色) */
.tps-month-goal-percent {
font-family: 'Courier New', monospace;
font-size: 14px;
font-weight: bold;
min-width: 50px;
text-align: right;
}
/* 卡片样式月度目标百分比颜色 */
.tps-card .tps-month-goal-percent {
color: #ff9500; /* 橙色系 */
}
.tps-simple .tps-month-goal-percent {
color: #ff9500;
}
.tps-modern .tps-month-goal-percent {
color: #ff9500;
}
.tps-month-goal-track {
position: relative;
overflow: visible;
}
.tps-month-goal-fill {
height: 100%;
border-radius: 5px;
background: linear-gradient(90deg, #ffb347 0%, #ff9500 100%); /* 偏橙色的渐变 */
max-width: 100%;
}
.tps-simple .tps-month-goal-fill {
background: linear-gradient(90deg, #ffb347 0%, #ff9500 100%);
}
.tps-modern .tps-month-goal-fill {
background: linear-gradient(90deg, #ffb347 0%, #ff9500 100%);
}
@media (max-width: 768px) {
.time-progress-stats {
margin: 25px 0 15px 0;
}
.tps-stats-grid {
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.tps-header {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
#tps-time-display {
flex-wrap: wrap;
gap: 8px;
text-align: left;
justify-content: flex-start;
}
.tps-content,
.tps-header {
padding: 18px !important;
}
.tps-goal-info {
flex-wrap: wrap;
}
.tps-goal-status {
order: 3;
width: 100%;
text-align: center;
margin: 5px 0 0 0;
}
.tps-month-goal-info {
flex-wrap: wrap;
}
.tps-month-goal-status {
order: 3;
width: 100%;
text-align: center;
margin: 5px 0 0 0;
}
}
@media (max-width: 480px) {
.tps-stats-grid {
grid-template-columns: 1fr;
}
}
</style>
<?php
}
/**
* 底部脚本
*/
public static function footer()
{
// 空函数JavaScript已内联在HTML中
}
}