__('全部', 'jio'), 'href' => $this->page_url], ]; if ($s === '') { $sub_but[] = ['name' => __('未使用', 'jio'), 'href' => add_query_arg('status', '0', $this->page_url)]; $sub_but[] = ['name' => __('已使用', 'jio'), 'href' => add_query_arg('status', 'used', $this->page_url)]; foreach ($this->type_labels() as $_k => $_v) { $sub_but[] = ['name' => $_v, 'href' => add_query_arg('type', $_k, $this->page_url)]; } } $but_html = ''; foreach ($sub_but as $but) { $but_html .= '
  • ' . esc_html($but['name']) . '
  • | '; } $but_html = substr($but_html, 0, -2); $search = '
    '; // 当前筛选参数(不含 paged)。分页链接显式带上它,不再依赖 add_query_arg() // 默认取 $_SERVER['REQUEST_URI'](链接会随环境漂移,且列条件容易丢)。 $query_args = $this->list_query_args($status, $type, $other, $s, $orderby, $order, $per_page); echo '
    ' . $search . '
    '; $filters = [ 'status' => $status, 'type' => $type, 'other' => $other, 'search' => $s, 'orderby' => $orderby, 'order' => $order, ]; $result = $svc->get_list($filters + ['limit' => $per_page, 'offset' => ($paged - 1) * $per_page]); $items = (array) ($result['items'] ?? []); $count_all = (int) ($result['total'] ?? 0); // 页码越界(手工改 URL、或筛选后总数变小)会让 offset 落到数据之外, // 表现为「空白表格 + 一个分页控件都没有」的死胡同,只能靠手改 URL 退出。 // 这里回退到最后一页重查一次,保证越界页码也能拿到数据与分页条。 $max_page = max(1, (int) ($result['max_pages'] ?? 1)); if (!$items && $count_all > 0 && $paged > $max_page) { $paged = $max_page; $result = $svc->get_list($filters + ['limit' => $per_page, 'offset' => ($paged - 1) * $per_page]); $items = (array) ($result['items'] ?? []); $count_all = (int) ($result['total'] ?? $count_all); } if (!$items) { NativeUi::table_card_open(); echo ''; echo '' . NativeUi::empty_row(1, esc_html__('未找到对应内容,或暂无内容', 'jio')) . ''; echo '
    '; NativeUi::table_wrap_close(); NativeUi::card_close(); return; } // 表头(与参考主题同列、同排序链接)。 $theads = [ ['width' => '6%', 'orderby' => 'card', 'name' => __('卡号', 'jio')], ['width' => '10%', 'orderby' => 'password', 'name' => __('密码', 'jio')], ['width' => '5%', 'orderby' => 'type', 'name' => __('类型', 'jio')], ['width' => '5%', 'orderby' => 'create_time', 'name' => __('创建时间', 'jio')], ['width' => '5%', 'orderby' => 'modified_time', 'name' => __('更新时间', 'jio')], ['width' => '5%', 'orderby' => 'status', 'name' => __('状态', 'jio')], ['width' => '8%', 'orderby' => 'other', 'name' => __('标识', 'jio')], ]; $thead_th = ''; foreach ($theads as $thead) { $orderby_links = ''; if ($thead['orderby']) { $orderby_url = add_query_arg('orderby', $thead['orderby']); $orderby_links .= ''; $orderby_links .= ''; $orderby_links = '' . $orderby_links . ''; } $thead_th .= '' . esc_html($thead['name']) . $orderby_links . ''; } $tbody = ''; foreach ($items as $msg) { $meta = []; if (!empty($msg['meta'])) { $decoded = json_decode((string) $msg['meta'], true); $meta = is_array($decoded) ? $decoded : []; } // 自定义卡密不展示状态;其余类型按状态着色(类型链接统一在下方链表中生成)。 $status_html = ''; if ($msg['type'] !== 'custom') { $status_html = '' . esc_html__('未使用', 'jio') . ''; if ($msg['status'] === 'used') { $status_html = '' . esc_html__('已使用', 'jio') . ''; if (!empty($msg['order_number'])) { $order_link_url = admin_url('admin.php?page=jio_orders&s=' . urlencode((string) $msg['order_number'])); $status_html .= ' [' . esc_html__('查看', 'jio') . ']'; } } elseif ($msg['status'] === 'expired') { $status_html = '' . esc_html__('已过期', 'jio') . ''; } elseif ($msg['status'] === 'disabled') { $status_html = '' . esc_html__('已禁用', 'jio') . ''; } } $other_a = ''; if (!empty($msg['note'])) { $other_a = '' . esc_html($msg['note']) . ''; } if ($msg['type'] === 'vip') { $type_html = '' . esc_html__('会员兑换', 'jio') . ''; $level = (int) ($meta['level'] ?? 1); $type_html .= '
    ' . esc_html($this->vip_level_name($level)) . ':' . esc_html($this->vip_time_text($meta)); } elseif ($msg['type'] === 'credits') { $type_html = '' . esc_html__('积分兑换', 'jio') . ''; $type_html .= '
    ' . esc_html__('积分:', 'jio') . esc_html((string) (int) ($meta['points'] ?? 0)); } elseif ($msg['type'] === 'balance') { $type_html = '' . esc_html__('余额充值', 'jio') . ''; $type_html .= '
    ' . esc_html__('金额:', 'jio') . esc_html($this->balance_amount_text($meta)); } else { $type_html = '' . esc_html__('自定义卡密', 'jio') . ''; } $card_name = (string) ($meta['custom_name']['card_name'] ?? ''); $password_name = (string) ($meta['custom_name']['password_name'] ?? ''); $tbody .= ''; $tbody .= ' '; $tbody .= "" . esc_html($card_name) . ' ' . esc_html((string) $msg['card']) . ''; $tbody .= "" . esc_html($password_name) . ' ' . esc_html((string) $msg['password']) . ''; $tbody .= "$type_html"; $tbody .= '' . esc_html((string) $msg['created_at']) . ''; $tbody .= '' . esc_html((string) ($msg['used_at'] ?: $msg['created_at'])) . ''; $tbody .= "$status_html"; $tbody .= "$other_a"; $tbody .= ''; } echo '
    '; wp_nonce_field(self::NONCE); echo '
    '; NativeUi::table_card_open(); echo ''; echo '' . $thead_th . ''; // phpcs:ignore WordPress.Security.EscapeOutput -- 已转义。 echo '' . $tbody . ''; // phpcs:ignore WordPress.Security.EscapeOutput -- 已转义。 echo '
    '; NativeUi::table_wrap_close(); AdminListPagination::render(self::PAGE_SLUG, $count_all, $paged, $per_page, $query_args); NativeUi::card_close(); echo '
    '; } /** * 列表筛选参数(不含 paged / page),用于构造翻页链接与「每页显示」表单。 * 显式列条件而不是依赖 add_query_arg() 默认取 $_SERVER['REQUEST_URI']: * 后者把链接绑到当前请求上,一旦请求形态变化(POST、代理改写)就会丢条件。 * * @return array */ private function list_query_args(string $status, string $type, string $other, string $s, string $orderby, string $order, int $per_page): array { $args = []; if ($status !== '') { $args['status'] = $status; } if ($type !== '') { $args['type'] = $type; } if ($other !== '') { $args['other'] = $other; } if ($s !== '') { $args['s'] = $s; } if ($orderby !== '' && $orderby !== 'modified_time') { $args['orderby'] = $orderby; } if ($order === 'ASC') { $args['desc'] = 'ASC'; } if ($per_page !== AdminListPagination::DEFAULT_PER_PAGE) { $args['ice_perpage'] = (string) $per_page; } return $args; } }