主题打包的是 Font Awesome 5,solid 字形必须带样式类 fas。全站有 18 处仍写成 FA4 的裸 fa fa-*,FA5 下并不存在对应字形,表现为图标位置空白;而 FA5-only 契约此前只扫描部分运行时文件,没有覆盖模板与渲染器,这些写法一直没被拦下。 同时发现一处真实的失效图标名:profile-level.php 用的是 fa-line-chart。这是 FA4 名称,FA5 把该系列重命名为 chart-*,正确写法是 fa-chart-line。 - 18 处 "fa fa-*" 补上 fas:首页模板、组件标记、评论表单、用户等级页、菜单 装饰、SchemaPayment 促销标签默认值、VIP 服务弹窗、ContentRenderer / GeneralRenderer、后台卡片样式校验、pay-vip.js - profile-level.php 的 fa-line-chart 修正为 fa-chart-line - 三处注释里的示例值同步为合法形态("fa fas fa-star"),避免被当成正确写法 抄走;credits.css 注释中直接写出旧字体族名的一处改为描述性表述,否则会被 FA5-only 契约当作违规命中 - legacy-navigation-contract:FA 资产断言改为跟随 aksrt_enqueue_fontawesome() 这一间接层(注册点已从脚本文件移到 inc/helpers/aksrt-icons.php),并把 fa-zibsvg-<key> 识别为项目自有 SVG sprite 族,而非 Font Awesome 字形 - vip-points-exchange-modal 契约同步断言 fa fas fa-angle-right 验证:改动前在干净 HEAD 上跑 node --test(已追踪用例)为 327 项 / 325 通过 / 2 失败,两项失败正是本次修复的失效图标名断言与 FA 版本号断言;改动后 333 项 / 333 通过(含 5 个本地专用用例共 370 项全部通过)。php -l 全部改动的 PHP 文件 通过。
171 lines
11 KiB
PHP
171 lines
11 KiB
PHP
<?php
|
|
/**
|
|
* User center: level summary, growth path and experience history.
|
|
*
|
|
* @package AKSRT
|
|
*/
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
|
|
$user_id = (int) ($context['user_id'] ?? get_current_user_id());
|
|
if ($user_id <= 0 || !class_exists('\\AKSRT\\User\\Level')) {
|
|
return;
|
|
}
|
|
|
|
$cfg = \AKSRT\User\Level::settings();
|
|
if (empty($cfg['enabled'])) {
|
|
return;
|
|
}
|
|
|
|
$progress = \AKSRT\User\Level::get_progress($user_id);
|
|
$details = array_slice(\AKSRT\User\Level::get_details($user_id), 0, 50);
|
|
$date_details = array_slice(\AKSRT\User\Level::get_date_details($user_id), 0, 30, true);
|
|
$labels = \AKSRT\User\Level::integral_labels();
|
|
$level_opt = is_array($cfg['level_opt'] ?? null) ? $cfg['level_opt'] : [];
|
|
$today = current_time('Y-m-d');
|
|
$today_integral = max(0, (int) ($date_details[$today] ?? 0));
|
|
$day_max = \AKSRT\User\Level::day_max();
|
|
$current_level = max(1, (int) ($progress['level'] ?? 1));
|
|
$max_level = max(1, (int) ($cfg['max'] ?? 10));
|
|
$level_icon = (string) ($progress['icon'] ?? '');
|
|
$level_name = (string) ($progress['name'] ?? \AKSRT\User\Level::get_level_name($current_level));
|
|
|
|
$badge_html = '';
|
|
if ($level_icon !== '') {
|
|
$badge_html = '<img' . aksrt_get_lazy_attr('lazy_other', $level_icon, 'aksrt-level-card__badge img-icon') . ' alt="' . esc_attr($level_name) . '" title="' . esc_attr($level_name) . '" decoding="async">';
|
|
} else {
|
|
$badge_html = '<span class="aksrt-level-card__badge-text" title="' . esc_attr($level_name) . '">LV' . esc_html((string) $current_level) . '</span>';
|
|
}
|
|
|
|
$avatar_html = function_exists('aksrt_get_avatar_html')
|
|
? aksrt_get_avatar_html($user_id, 48, ['class' => 'avatar-mini'])
|
|
: get_avatar($user_id, 48);
|
|
|
|
$next_need = max(0, (int) ($progress['next_need'] ?? 0));
|
|
$integral = max(0, (int) ($progress['integral'] ?? 0));
|
|
$remaining = max(0, (int) ($progress['remaining'] ?? 0));
|
|
$percentage = max(0, min(100, (int) ($progress['progress'] ?? 0)));
|
|
?>
|
|
<div class="aksrt-level-page">
|
|
<div class="row aksrt-level-page__summary">
|
|
<div class="col-md-5">
|
|
<section class="zib-widget colorful-bg jb-vip1 aksrt-level-card aksrt-level-card--summary">
|
|
<div class="colorful-make" aria-hidden="true"></div>
|
|
<div class="aksrt-level-card__summary-inner">
|
|
<div class="aksrt-level-card__identity">
|
|
<div class="avatar-mini aksrt-level-card__avatar"><?php echo $avatar_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
|
|
<strong><?php esc_html_e('我的等级', 'aksrt'); ?></strong>
|
|
</div>
|
|
<div class="aksrt-level-card__current">
|
|
<?php echo $badge_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
|
<span><?php echo esc_html($level_name); ?></span>
|
|
</div>
|
|
<div class="aksrt-level-card__progress-copy">
|
|
<?php if (!empty($progress['is_max'])) : ?>
|
|
<div class="flex jsb mb6 ab"><strong><?php echo esc_html((string) $integral); ?>/<?php echo esc_html((string) $integral); ?></strong><span><?php esc_html_e('已为最高等级', 'aksrt'); ?></span></div>
|
|
<?php else : ?>
|
|
<div class="flex jsb mb6 ab"><strong><?php echo esc_html((string) $integral); ?>/<?php echo esc_html((string) $next_need); ?></strong><span><?php printf(esc_html__('升级还需 %d 经验', 'aksrt'), $remaining); ?></span></div>
|
|
<?php endif; ?>
|
|
<div class="aksrt-level-progress" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="<?php echo esc_attr((string) $percentage); ?>" aria-label="<?php esc_attr_e('等级进度', 'aksrt'); ?>"><span style="width:<?php echo esc_attr((string) $percentage); ?>%;"></span></div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
<div class="col-md-7">
|
|
<section class="zib-widget colorful-bg c-gray aksrt-level-card aksrt-level-card--growth">
|
|
<div class="colorful-make" aria-hidden="true"></div>
|
|
<div class="aksrt-level-card__growth-inner">
|
|
<div class="aksrt-level-card__growth-head">
|
|
<div>
|
|
<strong><i class="fa fas fa-chart-line" aria-hidden="true"></i><?php esc_html_e('成长体系', 'aksrt'); ?></strong>
|
|
<a class="muted-2-color" data-aksrt-level-tab="tab_integral_my" href="#tab_integral_my"><?php printf(esc_html__('我的经验值:%d', 'aksrt'), $integral); ?></a>
|
|
</div>
|
|
<a id="tab-integral-date-link" class="muted-2-color" data-aksrt-level-tab="tab_integral_date" href="#tab_integral_date"><?php echo $today_integral > 0 ? esc_html(sprintf(__('今日 +%d', 'aksrt'), $today_integral)) : esc_html__('查看详情', 'aksrt'); ?><i class="fa fas fa-angle-right ml6" aria-hidden="true"></i></a>
|
|
</div>
|
|
<div class="swiper-container swiper-scroll pillar-box aksrt-level-growth" scroll-nogroup="1">
|
|
<div class="swiper-wrapper">
|
|
<?php for ($level = 1; $level <= $max_level; $level++) :
|
|
$need = $level === 1 ? 0 : max(0, (int) ($level_opt['upgrade_integral_' . $level] ?? (($level - 1) * 500 * $level)));
|
|
$name = \AKSRT\User\Level::get_level_name($level);
|
|
$icon = \AKSRT\User\Level::get_level_icon_url($level);
|
|
$height = $level === 1 ? 0 : (int) round(86 * ($level / $max_level));
|
|
$state = $level === $current_level ? ' active' : ($level > $current_level ? ' is-future' : '');
|
|
?>
|
|
<div class="swiper-slide pillar-item<?php echo esc_attr($state); ?>" title="<?php echo esc_attr($name); ?>">
|
|
<div class="value"><?php echo esc_html((string) $need); ?></div>
|
|
<div class="pillar" style="height:<?php echo esc_attr((string) $height); ?>px;"></div>
|
|
<div class="level-name">
|
|
<?php if ($icon !== '') : ?><img<?php echo aksrt_get_lazy_attr('lazy_other', $icon, 'aksrt-level-growth__badge img-icon'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> alt="<?php echo esc_attr($name); ?>" title="<?php echo esc_attr($name); ?>" decoding="async"><?php else : ?><span>LV<?php echo esc_html((string) $level); ?></span><?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<?php endfor; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
|
|
<section class="zib-widget aksrt-level-experience">
|
|
<div class="box-body">
|
|
<div class="aksrt-level-tabs" role="tablist" aria-label="<?php esc_attr_e('经验记录', 'aksrt'); ?>">
|
|
<a id="tab-integral-get" class="but mr6 is-active" data-aksrt-level-tab="tab_integral_get" href="#tab_integral_get" role="tab" aria-controls="tab_integral_get" aria-selected="true"><?php esc_html_e('获取经验值', 'aksrt'); ?></a>
|
|
<a id="tab-integral-my" class="but" data-aksrt-level-tab="tab_integral_my" href="#tab_integral_my" role="tab" aria-controls="tab_integral_my" aria-selected="false"><?php esc_html_e('我的经验值', 'aksrt'); ?></a>
|
|
</div>
|
|
<div class="tab-content mt20">
|
|
<div class="tab-pane fade active in" id="tab_integral_get" role="tabpanel" aria-labelledby="tab-integral-get">
|
|
<?php
|
|
$methods = \AKSRT\User\Level::integral_defaults();
|
|
$methods['checkin'] = 0;
|
|
$methods['referral'] = 0;
|
|
$methods['shop_gift'] = 0;
|
|
$referral_settings = class_exists('\\AKSRT\\Settings\\Settings') ? \AKSRT\Settings\Settings::get_referral_reward_settings() : [];
|
|
$methods['referral'] = max(0, (int) ($referral_settings['level_points'] ?? 0));
|
|
foreach ($methods as $key => $default_value) :
|
|
if ($key === 'day_max') {
|
|
continue;
|
|
}
|
|
$value = in_array($key, ['checkin', 'shop_gift'], true) ? 0 : ($key === 'referral' ? (int) $default_value : \AKSRT\User\Level::task_points($key));
|
|
if ($value <= 0 && !in_array($key, ['checkin', 'shop_gift'], true)) {
|
|
continue;
|
|
}
|
|
?>
|
|
<div class="border-bottom padding-h10 aksrt-level-list-row">
|
|
<div class="flex jsb ac">
|
|
<div class="flex1 mr20"><div class="font-bold mb6"><?php echo esc_html($labels[$key] ?? $key); ?></div><div class="muted-2-color em09"><?php echo in_array($key, ['checkin', 'shop_gift'], true) ? esc_html__('按活动或商品配置发放', 'aksrt') : esc_html__('完成后自动计入经验', 'aksrt'); ?></div></div>
|
|
<span class="focus-color em14 shrink0"><i class="fa fas fa-bolt mr6" aria-hidden="true"></i><?php echo $value > 0 ? '+' . esc_html((string) $value) : esc_html__('动态', 'aksrt'); ?></span>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<div class="tab-pane fade" id="tab_integral_my" role="tabpanel" aria-labelledby="tab-integral-my" hidden>
|
|
<?php if ($today_integral > 0) : ?>
|
|
<div class="border-bottom padding-h10 aksrt-level-list-row"><div class="flex jsb ac"><div class="flex1 mr20"><div class="font-bold mb6"><?php printf(esc_html__('今日累计 +%d', 'aksrt'), $today_integral); ?></div><div class="muted-2-color em09"><?php echo $day_max > $today_integral ? esc_html(sprintf(__('每日最多获得 %d 经验', 'aksrt'), $day_max)) : esc_html__('今日累计已达到上限', 'aksrt'); ?></div></div><a class="muted-2-color shrink0" data-aksrt-level-tab="tab_integral_date" href="#tab_integral_date" role="tab" aria-controls="tab_integral_date"><?php esc_html_e('每日详情', 'aksrt'); ?><i class="fa fas fa-angle-right ml6" aria-hidden="true"></i></a></div></div>
|
|
<?php endif; ?>
|
|
<?php if ($details) : ?>
|
|
<?php foreach ($details as $row) :
|
|
$key = sanitize_key((string) ($row['key'] ?? ''));
|
|
$value = max(0, (int) ($row['value'] ?? 0));
|
|
$detail_integral = max(0, (int) ($row['integral'] ?? 0));
|
|
?>
|
|
<div class="border-bottom padding-h10 aksrt-level-list-row"><div class="flex jsb ac"><div class="flex1 mr20"><div class="font-bold mb6"><?php echo esc_html($labels[$key] ?? $key); ?></div><div class="muted-2-color em09"><?php echo esc_html((string) ($row['time'] ?? '')); ?></div></div><div class="text-right shrink0"><div class="focus-color em14 mb6">+ <?php echo esc_html((string) $value); ?></div><div class="muted-2-color em09"><?php printf(esc_html__('累计:%d', 'aksrt'), $detail_integral); ?></div></div></div></div>
|
|
<?php endforeach; ?>
|
|
<?php else : ?>
|
|
<p class="aksrt-level-empty"><?php esc_html_e('暂无经验值获取明细', 'aksrt'); ?></p>
|
|
<?php endif; ?>
|
|
<?php if ($details) : ?><div class="text-center mt20 muted-3-color"><?php esc_html_e('最多显示近50条记录', 'aksrt'); ?></div><?php endif; ?>
|
|
</div>
|
|
<div class="tab-pane fade" id="tab_integral_date" role="tabpanel" aria-labelledby="tab-integral-date-link" hidden>
|
|
<?php if ($date_details) : ?>
|
|
<?php foreach ($date_details as $date => $value) : ?><div class="border-bottom padding-h6 flex jsb ac aksrt-level-date-row"><div class="em12"><?php echo esc_html((string) $date); ?></div><div class="text-right shrink0 focus-color em14 font-bold">+ <?php echo esc_html((string) max(0, (int) $value)); ?></div></div><?php endforeach; ?>
|
|
<div class="text-center mt20 muted-3-color"><?php esc_html_e('最多显示近30条记录', 'aksrt'); ?></div>
|
|
<?php else : ?>
|
|
<p class="aksrt-level-empty"><?php esc_html_e('暂无经验值获取明细', 'aksrt'); ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|