Files
wordpress-theme-aksrt/src/Admin/Native/UsersMenusMessagesCompose.php
T
kate522andClaude Opus 5 35bb96e82f refactor: rename the theme brand and every identifier from AKSRT to Jio
Full-project rename. `git grep -i aksrt` is now empty apart from the
DBMigrator 3.3.0 changelog note that documents the rename itself.

Code identifiers
- PHP namespace AKSRT\ -> Jio\ (composer PSR-4 + 378 declarations)
- global constants AKSRT_* -> JIO_* (VERSION/DIR/URI, PAY_TYPE_*, CAPTCHA_*)
- procedural functions, hooks, options, meta keys, table names,
  cookies, query vars, ajax actions and nonces: aksrt_ -> jio_
- text domain aksrt -> jio; Theme Name -> Jio
- JS globals: aksrtData/aksrtAdminData/... -> jioData/jioAdminData/...,
  window.AKSRTCaptcha & friends -> window.JioCaptcha, Aksrt* -> Jio*
- Vue components Aks*.vue -> Jio*.vue (15 files renamed + imports)
- CSS classes/data-attrs/custom properties: aksrt- -> jio-
- REST namespace aksrt/v1 -> jio/v1 (incl. payment gateway callbacks)

Storage layer
- DB tables {prefix}aksrt_* -> {prefix}jio_*; SCHEMA_VERSION 3.2.0 -> 3.3.0
  so dbDelta creates the new names on install
- widget id_base aksrt_widget_* -> jio_widget_*
- uninstall.php drop list rebuilt from the actual migrator tables
  (dropped 3 stale entries, added the 17 missing ones)

Removed
- hardcoded https://api.aksrt.com/version.json default update endpoint;
  get_endpoint() now reads the 「更新端点」 setting and do_check() no-ops
  when it is empty

Files renamed: inc/helpers/aksrt-*.php -> jio-*.php (54),
assets/admin/src/components/form/Aks*.vue -> Jio*.vue (15).
Build artifacts regenerated: assets/css/build, assets/js/runtime,
assets/admin/build.

Verified: audit-psr4-paths errors=0, audit-admin-contracts errors=0
(warnings=56, unchanged baseline), 813/813 widget-system tests,
44/44 phpunit, php -l clean across all PHP.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-01 20:05:04 +08:00

110 lines
8.5 KiB
PHP

<?php
/**
* 消息管理弹窗:发送表单、只读详情、删除与角色群发共用的二次确认。
*
* @package Jio
*/
namespace Jio\Admin\Native;
use Jio\Messages\AdminBroadcast;
defined('ABSPATH') || exit;
trait UsersMenusMessagesCompose {
private function render_message_compose(): void {
$open = sanitize_key((string) wp_unslash($_GET['jio_msg'] ?? '')) === 'send_failed';
printf(
'<dialog class="jio-msg-dialog" id="%s" aria-labelledby="%s-title"%s>',
esc_attr(self::MESSAGE_COMPOSE_ID), esc_attr(self::MESSAGE_COMPOSE_ID), $open ? ' data-jio-dialog-autoopen' : ''
);
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" class="jio-msg-dialog__frame jio-messages-admin__compose" data-jio-msg-compose';
$strings = [
'count-error' => __('最多输入 {count} 字。', 'jio'),
'role-hint' => __('将发送给 {count} 位用户;提交前需再次确认。', 'jio'),
'role-title' => __('确认按角色群发', 'jio'),
'role-confirm' => __('将向「{role}」的 {count} 位用户发送系统消息,并按通知配置触发提醒。请确认收件人范围与消息内容。', 'jio'),
'role-send' => __('确认发送', 'jio'),
];
foreach ($strings as $key => $text) {
echo ' data-i18n-' . esc_attr($key) . '="' . esc_attr($text) . '"';
}
echo '>';
echo '<input type="hidden" name="action" value="jio_users_send_message" />';
echo '<input type="hidden" name="confirmed_role" value="" /><input type="hidden" name="confirmed_count" value="" />';
wp_nonce_field('jio_users_send_message');
$this->render_message_dialog_head(self::MESSAGE_COMPOSE_ID, __('发送系统消息', 'jio'), 'dashicons-megaphone');
echo '<div class="jio-msg-dialog__body">';
if ($open) {
$error = sanitize_text_field((string) wp_unslash($_GET['jio_msg_error'] ?? __('消息发送失败,请检查后重试。', 'jio')));
echo '<p class="jio-native-callout is-danger">' . esc_html($error) . '</p>';
}
echo '<fieldset class="jio-msg-modes"><legend class="jio-native-field__label">' . esc_html__('收件人', 'jio') . '</legend>';
foreach (['users' => [__('指定用户', 'jio'), 'dashicons-admin-users'], 'role' => [__('按角色群发', 'jio'), 'dashicons-groups']] as $value => [$label, $icon]) {
echo '<label class="jio-msg-mode"><input type="radio" name="recipient_mode" value="' . esc_attr($value) . '"' . checked($value, 'users', false) . ' />';
echo '<span><span class="dashicons ' . esc_attr($icon) . '" aria-hidden="true"></span>' . esc_html($label) . '</span></label>';
}
echo '</fieldset><div class="jio-native-form-grid">';
printf(
'<label class="jio-native-field is-wide" data-jio-msg-pane="users"><span class="jio-native-field__label">%s</span><textarea name="users" rows="2" required placeholder="%s"></textarea><small class="jio-native-field__hint">%s</small></label>',
esc_html__('用户', 'jio'), esc_attr__('用户 ID / 用户名 / 邮箱,逗号或换行分隔', 'jio'), esc_html(sprintf(__('单次最多 %d 位。', 'jio'), AdminBroadcast::MAX_USERS))
);
echo '<label class="jio-native-field is-wide" data-jio-msg-pane="role" hidden><span class="jio-native-field__label">' . esc_html__('角色', 'jio') . '</span>';
echo '<select name="role" required disabled><option value="" selected disabled>' . esc_html__('请选择角色', 'jio') . '</option>';
$counts = count_users('time');
foreach (wp_roles()->get_names() as $role => $name) {
$count = (int) ($counts['avail_roles'][$role] ?? 0);
$label = translate_user_role($name);
$disabled = $count === 0 || $count > AdminBroadcast::MAX_ROLE_USERS;
$suffix = $count > AdminBroadcast::MAX_ROLE_USERS ? __('(超过发送上限)', 'jio') : ($count === 0 ? __('(暂无用户)', 'jio') : '');
printf(
'<option value="%s" data-count="%d" data-label="%s"%s>%s</option>',
esc_attr($role), $count, esc_attr($label), $disabled ? ' disabled' : '',
esc_html(sprintf(__('%1$s · %2$s 人', 'jio'), $label, number_format_i18n($count)) . $suffix)
);
}
echo '</select><small class="jio-native-field__hint">' . esc_html(sprintf(__('单个角色最多 %d 人;空角色和超限角色不可选。', 'jio'), AdminBroadcast::MAX_ROLE_USERS)) . '</small>';
echo '<small class="jio-native-field__hint" data-jio-msg-role-hint aria-live="polite"></small></label>';
printf(
'<label class="jio-native-field"><span class="jio-native-field__label">%s</span><input type="text" name="title" data-count-limit="%d" aria-describedby="jio-msg-title-count" placeholder="%s" /><small class="jio-msg-counter" id="jio-msg-title-count" data-count-for="title"></small></label>',
esc_html__('标题', 'jio'), AdminBroadcast::TITLE_MAX, esc_attr__('留空则取内容开头', 'jio')
);
echo '<label class="jio-native-field"><span class="jio-native-field__label">' . esc_html__('跳转链接(可选)', 'jio') . '</span><input type="url" name="target_url" placeholder="https://" /></label>';
printf(
'<label class="jio-native-field is-wide"><span class="jio-native-field__label">%s</span><textarea name="content" rows="5" data-count-limit="%d" required aria-describedby="jio-msg-content-count"></textarea><small class="jio-msg-counter" id="jio-msg-content-count" data-count-for="content"></small></label>',
esc_html__('内容', 'jio'), AdminBroadcast::CONTENT_MAX
);
echo '</div><p class="jio-native-muted jio-msg-dialog__note">' . esc_html__('以「系统通知」类型逐人投递;邮件 / 公众号提醒按通知配置同步触发。', 'jio') . '</p></div>';
echo '<footer class="jio-msg-dialog__foot"><button type="button" class="button" data-jio-dialog-close>' . esc_html__('取消', 'jio') . '</button>';
echo '<button type="submit" class="button button-primary" data-jio-msg-send>' . esc_html__('发送', 'jio') . '</button></footer></form></dialog>';
}
private function render_message_dialogs(): void {
echo '<dialog class="jio-msg-dialog" id="jio-msg-detail" aria-labelledby="jio-msg-detail-title"><div class="jio-msg-dialog__frame">';
$this->render_message_dialog_head('jio-msg-detail', __('消息详情', 'jio'), 'dashicons-email-alt');
echo '<div class="jio-msg-dialog__body" data-jio-msg-detail-body></div>';
echo '<footer class="jio-msg-dialog__foot"><button type="button" class="button" data-jio-dialog-close>' . esc_html__('关闭', 'jio') . '</button></footer></div></dialog>';
echo '<dialog class="jio-msg-dialog jio-msg-dialog--confirm" id="jio-msg-confirm" aria-labelledby="jio-msg-confirm-title" aria-describedby="jio-msg-confirm-text"';
foreach ([
'delete-title' => __('删除消息', 'jio'),
'delete-text' => __('确定删除 {count} 条消息?删除后用户收件箱中也将不再显示,此操作不可撤销。', 'jio'),
'delete-send' => __('确认删除', 'jio'),
] as $key => $text) {
echo ' data-i18n-' . esc_attr($key) . '="' . esc_attr($text) . '"';
}
echo '><div class="jio-msg-dialog__frame">';
$this->render_message_dialog_head('jio-msg-confirm', __('确认操作', 'jio'), 'dashicons-warning');
echo '<div class="jio-msg-dialog__body"><p id="jio-msg-confirm-text"></p></div>';
echo '<footer class="jio-msg-dialog__foot"><button type="button" class="button" data-jio-dialog-close autofocus>' . esc_html__('取消', 'jio') . '</button>';
echo '<button type="button" class="button button-primary" data-jio-msg-confirm>' . esc_html__('确认', 'jio') . '</button></footer></div></dialog>';
}
private function render_message_dialog_head(string $id, string $title, string $icon): void {
echo '<header class="jio-msg-dialog__head"><h2 id="' . esc_attr($id) . '-title" class="jio-msg-dialog__title">';
echo '<span class="dashicons ' . esc_attr($icon) . '" aria-hidden="true"></span><span data-jio-dialog-title>' . esc_html($title) . '</span></h2>';
echo '<button type="button" class="jio-msg-dialog__close" data-jio-dialog-close aria-label="' . esc_attr__('关闭', 'jio') . '"><span class="dashicons dashicons-no-alt" aria-hidden="true"></span></button></header>';
}
}