fix(pay): 修复后台收款接口显示顺序不可用并接入收银台排序

后台「收款接口 → 收款接口显示顺序」有三处缺陷叠加:
1) sortable 渲染组件读取 item.label,而 schema 写的是 title,导致 6 行
   只剩上下箭头;
2) SchemaProvider 的 sortable 分支遍历 items 定义重建数组,而该字段的
   键顺序本身就是配置值,用户排序被静默改回 schema 静态顺序;
3) 真正构建收银台支付方式列表的 aksrt_list_cash_payment_methods() 使用
   硬编码顺序,Gateway::get_available()/apply_sdk_order() 那套排序逻辑
   无任何调用方,配置对前台毫无影响。

改为:schema 项统一使用 label(JS 与 PHP 两处对齐);sortable 持久化按
提交键顺序重建,items 定义仅作白名单;新增唯一排序实现
aksrt_sort_payment_methods()(语义对齐参考主题 zibpay_get_payment_methods
+ pay_sdk_order 键顺序),并接入内容收银台、余额充值、购买积分与会员
购买四个入口。卡密输入盒改为按渠道存在与否判断,不再假定卡密固定在末位。

清理死代码:无调用方的 Gateway::get_available/apply_sdk_order/
get_status_summary、VipServicePackages 中不可达的支付方式列表回退分支、
零引用的 settings-defaults 模块及 schema/index.js 未使用的导出、支付
sortable 的 fields 死元数据、无拖拽实现却声明的 cursor:move。

未配置 pay_sdk_order 时顺序保持不变;未写数据迁移。

验证:php -l 8 个改动文件全部通过;新增 pay-sdk-order-contract 契约测试
(6 项);node --test tests/widget-system/*.test.cjs 301 项全部通过;
后台 SPA 已重新构建。
This commit is contained in:
2026-09-18 19:01:19 +08:00
parent 530a5b998f
commit d2447f8aa6
14 changed files with 223 additions and 181 deletions
+70 -1
View File
@@ -136,7 +136,76 @@ if (!function_exists('aksrt_list_cash_payment_methods')) {
// Do not inject a fake balance/alipay option when nothing is configured —
// callers should surface “暂无可用支付方式” instead of a dead method.
return $methods;
return aksrt_sort_payment_methods($methods);
}
}
/**
* 「收款接口显示顺序」槽位 → 网关 id 映射。
*
* 后台 sortable 项的 key 与之一一对应;微信/支付宝槽位同时收纳易支付子通道。
*
* @return array<string, array<int, string>>
*/
if (!function_exists('aksrt_payment_order_slots')) {
function aksrt_payment_order_slots(): array {
return [
'wechat' => ['wechatpay', 'epay_wxpay'],
'alipay' => ['alipay', 'epay_alipay'],
'paypal' => ['paypal'],
'stripe' => ['stripe'],
'balance' => ['balance'],
'card_pass' => ['card_pass'],
];
}
}
/**
* 按后台「收款接口显示顺序」(pay_sdk_order)重排支付方式列表。
*
* 语义对齐参考主题 zibpay_get_payment_methods():按配置槽位顺序把命中的方式
* 依次提到前面,未纳入槽位的方式保持原有相对顺序并留在末尾;未配置顺序时
* 原样返回(即保持注册顺序)。这是排序的唯一实现,所有收银台构建支付方式
* 列表的位置都必须经由此函数。
*
* @param array<int, array{id:string,name:string}> $methods
* @return array<int, array{id:string,name:string}>
*/
if (!function_exists('aksrt_sort_payment_methods')) {
function aksrt_sort_payment_methods(array $methods): array {
if (!$methods) {
return $methods;
}
$settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_all() : [];
$configured = is_array($settings) ? ($settings['pay_sdk_order'] ?? []) : [];
if (!is_array($configured) || $configured === []) {
return $methods;
}
$slots = aksrt_payment_order_slots();
$remaining = $methods;
$sorted = [];
foreach (array_keys($configured) as $slot) {
$slot = sanitize_key((string) $slot);
if ($slot === '') {
continue;
}
foreach ($slots[$slot] ?? [] as $gateway_id) {
foreach ($remaining as $index => $method) {
if ((string) ($method['id'] ?? '') !== $gateway_id) {
continue;
}
$sorted[] = $method;
unset($remaining[$index]);
break;
}
}
}
foreach ($remaining as $method) {
$sorted[] = $method;
}
return $sorted;
}
}
@@ -73,6 +73,10 @@ $currency = (string) ($currency_name ?? __('积分', 'aksrt'));
if (!empty($points_card_pass['enabled'])) {
$points_methods[] = ['id' => 'card_pass', 'name' => __('卡密', 'aksrt')];
}
// 「收款接口显示顺序」:购买积分弹窗只含余额与卡密两个槽位。
if (function_exists('aksrt_sort_payment_methods')) {
$points_methods = aksrt_sort_payment_methods($points_methods);
}
$points_custom_limit_html = sprintf(__('最低购买%d积分,最高购买%d积分', 'aksrt'), $pb_min_points, $pb_daily_max_points);
$points_gateway = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_payment_gateway_settings() : [];
$points_mark = (string) ($points_gateway['currency']['mark'] ?? '¥');
@@ -116,7 +116,9 @@ $charge_img_uri = get_template_directory_uri() . '/assets/img/';
$charge_default_product = $packages ? (string) $packages[0]['key'] : 'custom';
// 仅卡密可用时隐藏金额选择(参考主题:卡密决定充值金额)。
$charge_card_only = count($methods) === 1 && (string) ($methods[0]['id'] ?? '') === 'card_pass';
$charge_card_in_methods = count($methods) > 0 && $methods[count($methods) - 1]['id'] === 'card_pass';
// 卡密输入盒是 payment_method 条件块,与它在渠道行中的位置无关:卡密渠道可由
// 「收款接口显示顺序」移到任意位置,故此处只判断渠道是否存在。
$charge_card_in_methods = in_array('card_pass', array_column($methods, 'id'), true);
$charge_mark_symbol = !in_array($mark, ['', '元'], true);
$charge_mark_html = $charge_mark_symbol
? '<span class="px12">' . esc_html($mark) . '</span>'