Files
TimeProgressStats/Plugin.php

1061 lines
30 KiB
PHP
Raw Normal View History

2026-02-23 20:04:21 +08:00
<?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中
}
}