feat(user): badge icon urls and wear medal chrome

Extend badge dictionary with optional icon_url, prefer aksrt_wear_badge
when assigned, and render medal images in identity chips.
This commit is contained in:
kate522 committed 2026-07-16 22:17:21 +08:00
1 parent a3585b0f96
commit 1d75170f8e
7 files changed
+99 -21

No files matched your search

@@ -648,7 +648,13 @@ class AKSRT_Admin_Schema_Users {
['key' => 'user_badge_limit', 'label' => '最多显示数量', 'type' => 'number', 'default' => 3, 'min' => 1, 'max' => 8],
]],
['key' => 'dictionary', 'title' => '徽章字典', 'fields' => [
['key' => 'user_badge_dictionary', 'label' => '徽章列表', 'type' => 'textarea', 'default' => "founder|创始成员|warning\nstaff|站务团队|info"],
[
'key' => 'user_badge_dictionary',
'label' => '徽章列表',
'type' => 'textarea',
'default' => "founder|创始成员|warning\nstaff|站务团队|info",
'help' => '每行:slug|显示文案|色调(neutral/info/success/warning/brand)|图标URL(可选)。配置 icon_url 后前台显示勋章图;用户 meta aksrt_wear_badge 指定当前佩戴。',
],
]],
],
],
+24 -7
View File
@@ -130,7 +130,7 @@ class AKSRT_User_Home {
/**
* 获取公开展示的身份信号(认证 / 等级 / 徽章)。
*
* @return array<int,array{label:string,icon:string,tone:string}>
* @return array<int,array{label:string,icon:string,tone:string,icon_url?:string,type?:string,slug?:string,wear?:bool}>
*/
public function get_profile_signals(int $user_id): array {
if ($user_id <= 0 || !class_exists('AKSRT_Settings')) {
@@ -142,6 +142,7 @@ class AKSRT_User_Home {
if (!empty($settings['verify']['enabled']) && !empty($settings['verify']['public_display']) && $this->is_user_verified($user_id, $settings['verify'])) {
$signals[] = [
'type' => 'verify',
'label' => (string) $settings['verify']['badge_text'],
'icon' => 'check-circle',
'tone' => 'success',
@@ -152,6 +153,7 @@ class AKSRT_User_Home {
$level = $this->get_user_level($user_id, $settings['level']);
if ($level > 0) {
$signals[] = [
'type' => 'level',
'label' => (string) $settings['level']['label_prefix'] . $level,
'icon' => 'layer-group',
'tone' => 'info',
@@ -171,21 +173,36 @@ class AKSRT_User_Home {
if (!is_array($assigned)) {
$assigned = preg_split('/[\s,]+/', (string) $assigned, -1, PREG_SPLIT_NO_EMPTY);
}
$assigned = array_values(array_filter(array_map(static function ($slug) {
return sanitize_key((string) $slug);
}, (array) $assigned)));
// Prefer worn badge first (Zibll wear-medal).
$wear = sanitize_key((string) get_user_meta($user_id, 'aksrt_wear_badge', true));
if ($wear !== '' && in_array($wear, $assigned, true) && isset($badge_map[$wear])) {
$assigned = array_values(array_unique(array_merge([$wear], $assigned)));
}
$limit = max(1, (int) ($settings['badge']['limit'] ?? 3));
foreach ((array) $assigned as $slug) {
$slug = sanitize_key((string) $slug);
$badge_count = 0;
foreach ($assigned as $slug) {
if ($slug === '' || !isset($badge_map[$slug])) {
continue;
}
$icon_url = (string) ($badge_map[$slug]['icon_url'] ?? '');
$signals[] = [
'label' => (string) $badge_map[$slug]['label'],
'icon' => 'award',
'tone' => (string) ($badge_map[$slug]['tone'] ?? 'neutral'),
'type' => 'badge',
'slug' => $slug,
'label' => (string) $badge_map[$slug]['label'],
'icon' => 'award',
'tone' => (string) ($badge_map[$slug]['tone'] ?? 'neutral'),
'icon_url' => $icon_url,
'wear' => ($wear !== '' && $slug === $wear),
];
$badge_count++;
if (count($signals) >= $limit + 2) {
if ($badge_count >= $limit) {
break;
}
}
@@ -120,7 +120,7 @@ class AKSRT_Settings_User_Runtime {
* @return array{
* verify:array{enabled:bool,public_display:bool,badge_text:string,accept_email_verified:bool,require_manual_review:bool},
* level:array{enabled:bool,public_display:bool,source:string,label_prefix:string,thresholds:array<int,int>},
* badge:array{enabled:bool,public_display:bool,limit:int,dictionary:array<int,array{slug:string,label:string,tone:string}>},
* badge:array{enabled:bool,public_display:bool,limit:int,dictionary:array<int,array{slug:string,label:string,tone:string,icon_url?:string}>},
* report:array{enabled:bool,public_entry:bool,public_notice:bool,ban_notice_text:string,categories:array<int,array{slug:string,label:string}>}
* }
*/
@@ -238,7 +238,7 @@ class AKSRT_Settings_User_Runtime {
}
/**
* @return array<int,array{slug:string,label:string,tone:string}>
* @return array<int,array{slug:string,label:string,tone:string,icon_url:string}>
*/
public static function parse_badge_dictionary(string $raw): array {
$lines = preg_split('/[\r\n]+/', $raw, -1, PREG_SPLIT_NO_EMPTY);
@@ -254,6 +254,7 @@ class AKSRT_Settings_User_Runtime {
$slug = sanitize_key((string) $parts[0]);
$label = sanitize_text_field((string) $parts[1]);
$tone = isset($parts[2]) ? sanitize_key((string) $parts[2]) : 'neutral';
$icon_url = isset($parts[3]) ? esc_url_raw((string) $parts[3]) : '';
if ($slug === '' || $label === '') {
continue;
@@ -264,9 +265,10 @@ class AKSRT_Settings_User_Runtime {
}
$items[] = [
'slug' => $slug,
'label' => $label,
'tone' => $tone,
'slug' => $slug,
'label' => $label,
'tone' => $tone,
'icon_url' => $icon_url,
];
}