diff --git a/docs/zibll-gap-matrix.md b/docs/zibll-gap-matrix.md
index 72ed3a70..472164bf 100644
--- a/docs/zibll-gap-matrix.md
+++ b/docs/zibll-gap-matrix.md
@@ -99,7 +99,8 @@ Note: zibll「商品管理」`zibpay_product_page` is **paid article sales**, no
| 2b Shipping/after-sale/coupons/income/rebate | done |
| 3 users.php submenus | done |
| 4 SPA strip | done (ops routes redirect to native) |
-| 5+ behavior parity | backlog |
+| 5+ behavior parity | in progress — shipping list create + order links; after-sale `s`/type filters + list create + merchant approve/reject/confirm + order links; order admin note (JSON-safe) + complete/refund/close quick actions |
+| 5 remaining | coupons/cards UX depth; product/forum runtime field parity; pending-to-ship board; express timeline |
## Dual-UI rule
diff --git a/inc/classes/admin/native/class-aksrt-admin-pay-menus.php b/inc/classes/admin/native/class-aksrt-admin-pay-menus.php
index 34f523b9..26d453e7 100644
--- a/inc/classes/admin/native/class-aksrt-admin-pay-menus.php
+++ b/inc/classes/admin/native/class-aksrt-admin-pay-menus.php
@@ -31,6 +31,7 @@ class AKSRT_Admin_Pay_Menus {
add_action('admin_menu', [$this, 'register_menus']);
add_action('admin_notices', [$this, 'pending_notices']);
add_action('admin_post_aksrt_pay_update_order_status', [$this, 'handle_update_order_status']);
+ add_action('admin_post_aksrt_pay_update_order_note', [$this, 'handle_update_order_note']);
add_action('admin_post_aksrt_pay_update_withdrawal', [$this, 'handle_update_withdrawal']);
add_action('admin_post_aksrt_pay_disable_charge_card', [$this, 'handle_disable_charge_card']);
add_action('admin_post_aksrt_pay_batch_charge_cards', [$this, 'handle_batch_charge_cards']);
@@ -38,6 +39,7 @@ class AKSRT_Admin_Pay_Menus {
add_action('admin_post_aksrt_pay_create_shipping', [$this, 'handle_create_shipping']);
add_action('admin_post_aksrt_pay_update_after_sale', [$this, 'handle_update_after_sale']);
add_action('admin_post_aksrt_pay_create_after_sale', [$this, 'handle_create_after_sale']);
+ add_action('admin_post_aksrt_pay_after_sale_action', [$this, 'handle_after_sale_action']);
add_action('admin_post_aksrt_pay_create_coupon', [$this, 'handle_create_coupon']);
add_action('admin_post_aksrt_pay_disable_coupon', [$this, 'handle_disable_coupon']);
add_action('admin_post_aksrt_pay_settle_income', [$this, 'handle_settle_income']);
@@ -196,6 +198,10 @@ class AKSRT_Admin_Pay_Menus {
$map = [
'order_updated' => __('订单状态已更新。', 'aksrt'),
'order_failed' => __('订单状态更新失败。', 'aksrt'),
+ 'order_note_updated' => __('订单备注已保存。', 'aksrt'),
+ 'order_note_failed' => __('订单备注保存失败。', 'aksrt'),
+ 'after_sale_action_ok' => __('售后操作已完成。', 'aksrt'),
+ 'after_sale_action_failed' => __('售后操作失败。', 'aksrt'),
'withdraw_updated' => __('提现状态已更新。', 'aksrt'),
'withdraw_failed' => __('提现状态更新失败。', 'aksrt'),
'card_disabled' => __('充值卡已禁用。', 'aksrt'),
@@ -368,6 +374,7 @@ class AKSRT_Admin_Pay_Menus {
echo '
' . esc_html((string) ($row['created_at'] ?? '')) . ' | ';
echo '';
echo '' . esc_html__('详情', 'aksrt') . '';
+ $this->render_order_quick_status_buttons($order_number, $status_key);
echo '';
+
echo '' . esc_html__('更新状态', 'aksrt') . '';
+ echo '';
+ $this->render_order_quick_status_buttons($order_number, $status, true);
+ echo ' ';
echo '';
if (!$shipping_items) {
echo '' . esc_html__('暂无物流记录。', 'aksrt') . ' ';
} else {
- echo '| ID | ' . esc_html__('承运商', 'aksrt') . ' | ' . esc_html__('运单号', 'aksrt') . ' | ' . esc_html__('状态', 'aksrt') . ' | ' . esc_html__('时间', 'aksrt') . ' | ';
+ $status_options = $this->shipping_status_options(false);
+ echo '| ID | ' . esc_html__('承运商', 'aksrt') . ' | ' . esc_html__('运单号', 'aksrt') . ' | ' . esc_html__('状态', 'aksrt') . ' | ' . esc_html__('时间', 'aksrt') . ' | ' . esc_html__('操作', 'aksrt') . ' | ';
foreach ($shipping_items as $item) {
+ $sid = (int) ($item['id'] ?? 0);
+ $st = (string) ($item['status'] ?? '');
echo '';
- echo '| ' . esc_html((string) ($item['id'] ?? '')) . ' | ';
+ echo '' . esc_html((string) $sid) . ' | ';
echo '' . esc_html((string) ($item['carrier'] ?? '')) . ' | ';
echo '' . esc_html((string) ($item['tracking_no'] ?? '')) . ' | ';
- echo '' . esc_html((string) ($item['status'] ?? '')) . ' | ';
+ echo '' . esc_html($status_options[$st] ?? $st) . ' | ';
echo '' . esc_html((string) ($item['created_at'] ?? '')) . ' | ';
+ echo ' | ';
echo ' ';
}
echo ' ';
@@ -500,14 +544,10 @@ class AKSRT_Admin_Pay_Menus {
echo '';
echo '';
echo '';
+ echo '';
wp_nonce_field('aksrt_pay_create_after_sale_' . $order_number);
echo '';
@@ -520,13 +560,15 @@ class AKSRT_Admin_Pay_Menus {
if (!$after_sale) {
echo '' . esc_html__('暂无售后工单。', 'aksrt') . ' ';
} else {
- echo '| ID | ' . esc_html__('类型', 'aksrt') . ' | ' . esc_html__('状态', 'aksrt') . ' | ' . esc_html__('时间', 'aksrt') . ' | ';
+ echo '| ID | ' . esc_html__('类型', 'aksrt') . ' | ' . esc_html__('状态', 'aksrt') . ' | ' . esc_html__('时间', 'aksrt') . ' | ' . esc_html__('操作', 'aksrt') . ' | ';
foreach ($after_sale as $item) {
+ $tid = (int) ($item['id'] ?? 0);
echo '';
- echo '| ' . esc_html((string) ($item['id'] ?? '')) . ' | ';
- echo '' . esc_html((string) ($item['type'] ?? '')) . ' | ';
- echo '' . esc_html((string) ($item['status'] ?? '')) . ' | ';
+ echo '' . esc_html((string) $tid) . ' | ';
+ echo '' . esc_html((string) ($item['type_label'] ?? $item['type'] ?? '')) . ' | ';
+ echo '' . esc_html((string) ($item['status_label'] ?? $item['status'] ?? '')) . ' | ';
echo '' . esc_html((string) ($item['created_at'] ?? '')) . ' | ';
+ echo '' . esc_html__('在售后页处理', 'aksrt') . ' | ';
echo ' ';
}
echo ' ';
@@ -557,9 +599,26 @@ class AKSRT_Admin_Pay_Menus {
exit;
}
- /* ------------------------------------------------------------------
- * Withdrawals
- * ----------------------------------------------------------------*/
+ public function handle_update_order_note(): void {
+ if (!current_user_can(self::CAPABILITY)) {
+ wp_die(esc_html__('权限不足', 'aksrt'));
+ }
+
+ $order_number = isset($_POST['order_number']) ? sanitize_text_field((string) wp_unslash($_POST['order_number'])) : '';
+ $admin_note = isset($_POST['admin_note']) ? sanitize_textarea_field((string) wp_unslash($_POST['admin_note'])) : '';
+ check_admin_referer('aksrt_pay_update_order_note_' . $order_number);
+
+ $ok = false;
+ if ($order_number !== '' && class_exists('AKSRT_Order_Repository')) {
+ $ok = AKSRT_Order_Repository::get_instance()->update_admin_note($order_number, $admin_note);
+ }
+
+ wp_safe_redirect($this->page_url('aksrt_orders', [
+ 'order' => $order_number,
+ 'aksrt_pay_msg' => $ok ? 'order_note_updated' : 'order_note_failed',
+ ]));
+ exit;
+ }
public function render_withdrawals_page(): void {
$this->ensure_cap();
@@ -960,6 +1019,7 @@ class AKSRT_Admin_Pay_Menus {
$per_page = 20;
$svc = AKSRT_Shipping::get_instance();
$stats = $svc->get_stats();
+ $status_options = $this->shipping_status_options(true);
echo '' . esc_html(sprintf(
/* translators: 1: total */
@@ -967,16 +1027,23 @@ class AKSRT_Admin_Pay_Menus {
(int) ($stats['total'] ?? 0)
)) . ' ';
+ echo '' . esc_html__('新建发货', 'aksrt') . '';
+ echo '';
+
echo '
|