feat(forum,admin): plate follow-pay MVP, sales column, order type tabs

Wire paid plate follow (admin meta + points/balance purchase + AJAX),
re-check plate gate on topics, post list sales column, and order type
subtabs; update gap matrix and admin IA map.
This commit is contained in:
kate522 committed 2026-07-15 11:00:36 +08:00
1 parent bccb14a487
commit cf6ad0e972
12 files changed
+672 -12

No files matched your search

+59
View File
@@ -456,6 +456,7 @@ class AKSRT_Post_Meta_Box {
public function add_columns(array $columns): array {
$columns['aksrt_views'] = __('阅读量', 'aksrt');
$columns['aksrt_likes'] = __('点赞数', 'aksrt');
$columns['aksrt_sales'] = __('销售数据', 'aksrt');
return $columns;
}
@@ -473,9 +474,67 @@ class AKSRT_Post_Meta_Box {
$toc = esc_attr($meta['show_toc'] ?? '');
$mh = (int) ($meta['maxheight'] ?? 0);
echo '<span class="aksrt-col-data" data-views="' . (int) ($meta['views'] ?? 0) . '" data-likes="' . $likes . '" data-layout="' . $layout . '" data-toc="' . $toc . '" data-maxheight="' . $mh . '">' . esc_html($likes > 0 ? (string) $likes : '—') . '</span>';
} elseif ($column === 'aksrt_sales') {
$this->render_sales_column($post_id);
}
}
/**
* Content-pay sales summary for posts list (zibll 销售数据 column parity).
*/
private function render_sales_column(int $post_id): void {
if (!function_exists('aksrt_get_pay_meta') || !class_exists('AKSRT_Domain_Model')) {
echo '—';
return;
}
$pay = aksrt_get_pay_meta($post_id);
$pay_type = AKSRT_Domain_Model::normalize_pay_type((string) ($pay['pay_type'] ?? AKSRT_Domain_Model::PAY_TYPE_NO));
if ($pay_type === AKSRT_Domain_Model::PAY_TYPE_NO) {
echo '<span class="description">' . esc_html__('免费', 'aksrt') . '</span>';
return;
}
$labels = AKSRT_Domain_Model::pay_type_labels();
$type_label = $labels[$pay_type] ?? $pay_type;
$modo = (($pay['pay_modo'] ?? '0') === 'points') ? 'points' : '0';
if ($modo === 'points') {
$price_text = sprintf(__('%d 积分', 'aksrt'), (int) ceil((float) ($pay['points_price'] ?? $pay['price'] ?? 0)));
} else {
$price_text = '¥' . number_format((float) ($pay['price'] ?? 0), 2);
}
$meta_sales = (int) get_post_meta($post_id, AKSRT_Domain_Model::RESOURCE_SALES_VOLUME_KEY, true);
$db_sales = 0;
$revenue = 0.0;
if (class_exists('AKSRT_Order_Repository')) {
$map = AKSRT_Order_Repository::get_instance()->get_content_sales_map(
[$post_id],
AKSRT_Domain_Model::ORDER_PRODUCT_RESOURCE
);
if (isset($map[$post_id])) {
$db_sales = (int) ($map[$post_id]['sales_count'] ?? 0);
$revenue = (float) ($map[$post_id]['revenue'] ?? 0);
}
}
$orders_url = admin_url('admin.php?page=aksrt_orders&product_type=resource&product_id=' . $post_id);
$products_url = admin_url('admin.php?page=aksrt_pay_products&s=' . $post_id);
echo '<div style="font-size:12px;line-height:1.5;">';
echo '<strong style="color:#0c9cc8;">' . esc_html((string) $type_label) . '</strong>';
echo '<br>' . esc_html($price_text);
echo '<br>' . esc_html(sprintf(__('Meta销量 %d', 'aksrt'), max(0, $meta_sales)));
if ($db_sales > 0) {
printf(
'<br><a href="%s" title="%s">%s</a>',
esc_url($orders_url),
esc_attr__('查看销售明细', 'aksrt'),
esc_html(sprintf(__('真实销量 %d · ¥%s', 'aksrt'), $db_sales, number_format($revenue, 2)))
);
} else {
echo '<br><span class="description">' . esc_html__('暂无订单', 'aksrt') . '</span>';
}
echo '<br><a href="' . esc_url($products_url) . '">' . esc_html__('付费文章', 'aksrt') . '</a>';
echo '</div>';
}
/**
* §3.8 Render quick edit and bulk edit fields.
*/