feat(admin): 售后操作列改为点击「操作」展开快捷面板;新增顶部批量通过/批量拒绝(含复选框与全选)
This commit is contained in:
@@ -31,6 +31,7 @@ class PayOrders {
|
||||
add_action('admin_post_aksrt_pay_clear_closed_orders', [$this, 'handle_clear_closed_orders']);
|
||||
add_action('admin_post_aksrt_pay_delete_order', [$this, 'handle_delete_order']);
|
||||
add_action('admin_post_aksrt_after_sale_review', [$this, 'handle_after_sale_review']);
|
||||
add_action('admin_post_aksrt_after_sale_bulk', [$this, 'handle_after_sale_bulk']);
|
||||
}
|
||||
|
||||
public function render_orders_page(): void {
|
||||
@@ -401,8 +402,15 @@ class PayOrders {
|
||||
foreach ([\AKSRT\Payment\AfterSaleService::STATUS_PENDING => '待审核', \AKSRT\Payment\AfterSaleService::STATUS_PROCESSING => '处理中', \AKSRT\Payment\AfterSaleService::STATUS_APPROVED => '已通过', \AKSRT\Payment\AfterSaleService::STATUS_REJECTED => '已拒绝', \AKSRT\Payment\AfterSaleService::STATUS_CANCELLED => '已取消', \AKSRT\Payment\AfterSaleService::STATUS_COMPLETED => '已完成'] as $key => $label) echo '<option value="' . esc_attr($key) . '"' . selected($status, $key, false) . '>' . esc_html($label) . '</option>';
|
||||
echo '</select> <label>' . esc_html__('开始日期', 'aksrt') . ' <input type="date" name="date_from" value="' . esc_attr($date_from) . '" /></label> <label>' . esc_html__('结束日期', 'aksrt') . ' <input type="date" name="date_to" value="' . esc_attr($date_to) . '" /></label> ';
|
||||
submit_button(__('筛选', 'aksrt'), 'secondary', '', false);
|
||||
echo '</form><table class="widefat striped"><thead><tr><th>ID</th><th>订单号</th><th>用户</th><th>原因</th><th>申请资料</th><th>申请说明</th><th>举证图片</th><th>退款金额</th><th>状态</th><th>操作 / 处理记录</th></tr></thead><tbody>';
|
||||
if (!$items) echo '<tr><td colspan="10">' . esc_html__('暂无售后申请', 'aksrt') . '</td></tr>';
|
||||
echo '</form>';
|
||||
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" id="aksrt-after-sale-bulk-form">';
|
||||
echo '<input type="hidden" name="action" value="aksrt_after_sale_bulk" />'; wp_nonce_field('aksrt_after_sale_bulk');
|
||||
echo '<input type="hidden" name="bulk_note" id="aksrt-bulk-note" value="" />';
|
||||
echo '<div class="tablenav top"><div class="alignleft actions bulkactions">';
|
||||
echo '<select name="bulk_decision" id="aksrt-bulk-decision"><option value="">' . esc_html__('批量操作', 'aksrt') . '</option><option value="approve">' . esc_html__('批量通过', 'aksrt') . '</option><option value="reject">' . esc_html__('批量拒绝', 'aksrt') . '</option></select> ';
|
||||
echo '<button type="submit" class="button action">' . esc_html__('应用', 'aksrt') . '</button></div><div class="tablenav-spacer" style="clear:both;"></div></div>';
|
||||
echo '<table class="widefat striped"><thead><tr><th class="check-column"><input type="checkbox" class="aksrt-select-all" /></th><th>ID</th><th>订单号</th><th>用户</th><th>原因</th><th>申请资料</th><th>申请说明</th><th>举证图片</th><th>退款金额</th><th>状态</th><th>操作 / 处理记录</th></tr></thead><tbody>';
|
||||
if (!$items) echo '<tr><td colspan="11">' . esc_html__('暂无售后申请', 'aksrt') . '</td></tr>';
|
||||
foreach ($items as $item) {
|
||||
$id = (int) $item['id']; $number = (string) $item['order_number']; $uid = (int) $item['user_id'];
|
||||
$user = $uid > 0 ? get_userdata($uid) : null;
|
||||
@@ -436,8 +444,8 @@ class PayOrders {
|
||||
$thumbs[] = '<a href="' . esc_url($url) . '" target="_blank" rel="noopener"><img src="' . esc_url($url) . '" alt="" style="width:48px;height:48px;object-fit:cover;border-radius:4px;margin:0 4px 4px 0;vertical-align:middle;" loading="lazy" /></a>';
|
||||
}
|
||||
$images_cell = $thumbs ? implode('', $thumbs) : '—';
|
||||
echo '<tr><td>' . esc_html((string) $id) . '<br><small>' . esc_html((string) ($item['created_at'] ?? '')) . '</small></td><td><a href="' . esc_url($this->page_url(self::PAGE_SLUG, ['order' => $number])) . '"><code>' . esc_html($number) . '</code></a><br><span class="description">' . esc_html($type_label) . ($order ? ' · ' . esc_html(\AKSRT\Payment\UserOrders::get_instance()->decorate_order_view($order, false)['product_name'] ?? '') : '') . '</span></td><td>' . esc_html($user ? $user->display_name . ' (#' . $uid . ')' : '#' . $uid) . '</td><td>' . $reason_cell . '</td><td>' . $materials_cell . '</td><td>' . $desc_cell . '</td><td>' . $images_cell . '</td><td>' . esc_html($refund_amount) . '</td><td>' . esc_html($status_labels[(string) $item['status']] ?? (string) $item['status']) . '</td><td>';
|
||||
// 快捷操作:仿 WP 文章列表 row-actions(悬停显示),点击经 JS 以 POST 提交
|
||||
echo '<tr><td class="check-column"><input type="checkbox" class="aksrt-row-check" name="after_sale_ids[]" value="' . esc_attr((string) $id) . '" /></td><td>' . esc_html((string) $id) . '<br><small>' . esc_html((string) ($item['created_at'] ?? '')) . '</small></td><td><a href="' . esc_url($this->page_url(self::PAGE_SLUG, ['order' => $number])) . '"><code>' . esc_html($number) . '</code></a><br><span class="description">' . esc_html($type_label) . ($order ? ' · ' . esc_html(\AKSRT\Payment\UserOrders::get_instance()->decorate_order_view($order, false)['product_name'] ?? '') : '') . '</span></td><td>' . esc_html($user ? $user->display_name . ' (#' . $uid . ')' : '#' . $uid) . '</td><td>' . $reason_cell . '</td><td>' . $materials_cell . '</td><td>' . $desc_cell . '</td><td>' . $images_cell . '</td><td>' . esc_html($refund_amount) . '</td><td>' . esc_html($status_labels[(string) $item['status']] ?? (string) $item['status']) . '</td><td>';
|
||||
// 快捷操作:点击「操作」展开面板,点击链接经 JS 以 POST 提交
|
||||
$quick_actions = [];
|
||||
if ((string) $item['status'] === 'pending') {
|
||||
$quick_actions = ['approve' => __('通过', 'aksrt'), 'reject' => __('拒绝', 'aksrt')];
|
||||
@@ -458,7 +466,8 @@ class PayOrders {
|
||||
. ' data-nonce="' . esc_attr(wp_create_nonce('aksrt_after_sale_review_' . $id)) . '"'
|
||||
. '>' . esc_html($label) . '</a></span>';
|
||||
}
|
||||
echo '<div class="row-actions">' . implode(' | ', $links) . '</div>';
|
||||
echo '<a href="#" class="aksrt-toggle-row-actions" data-target="aksrt-ra-' . esc_attr((string) $id) . '">' . esc_html__('操作', 'aksrt') . '</a>';
|
||||
echo '<div class="aksrt-row-actions-panel" id="aksrt-ra-' . esc_attr((string) $id) . '" hidden style="margin-top:6px;"><div>' . implode(' | ', $links) . '</div></div>';
|
||||
}
|
||||
if (!empty($item['admin_note'])) echo '<small>' . esc_html__('备注:', 'aksrt') . esc_html((string) $item['admin_note']) . '</small><br>';
|
||||
if (!empty($item['gateway_result'])) {
|
||||
@@ -469,11 +478,18 @@ class PayOrders {
|
||||
echo '</td></tr>';
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
echo '</form>';
|
||||
echo '<script>(function(){'
|
||||
. 'var postUrl=' . wp_json_encode(esc_url_raw(admin_url('admin-post.php'))) . ';'
|
||||
. 'var tReject=' . wp_json_encode(__('请填写原因(将记为管理员备注,可留空):', 'aksrt')) . ';'
|
||||
. 'var tConfirmA=' . wp_json_encode(__('确认执行', 'aksrt')) . ';'
|
||||
. 'var tConfirmB=' . wp_json_encode(__('吗?', 'aksrt')) . ';'
|
||||
. 'document.querySelectorAll(".aksrt-toggle-row-actions").forEach(function(t){'
|
||||
. 't.addEventListener("click",function(e){e.preventDefault();'
|
||||
. 'var p=document.getElementById(t.getAttribute("data-target"));var willOpen=p.hasAttribute("hidden");'
|
||||
. 'document.querySelectorAll(".aksrt-row-actions-panel").forEach(function(x){x.setAttribute("hidden","");});'
|
||||
. 'if(willOpen)p.removeAttribute("hidden");'
|
||||
. '});});'
|
||||
. 'document.querySelectorAll(".aksrt-after-sale-quick-action").forEach(function(a){'
|
||||
. 'a.addEventListener("click",function(e){e.preventDefault();'
|
||||
. 'var decision=a.getAttribute("data-decision"),label=a.getAttribute("data-label"),note="";'
|
||||
@@ -483,7 +499,20 @@ class PayOrders {
|
||||
. 'var fields={action:"aksrt_after_sale_review",after_sale_id:a.getAttribute("data-id"),decision:decision,_wpnonce:a.getAttribute("data-nonce"),admin_note:note||""};'
|
||||
. 'Object.keys(fields).forEach(function(k){var i=document.createElement("input");i.type="hidden";i.name=k;i.value=fields[k];f.appendChild(i);});'
|
||||
. 'document.body.appendChild(f);f.submit();'
|
||||
. '});});})();</script>';
|
||||
. '});});'
|
||||
. 'var selAll=document.querySelector(".aksrt-select-all");'
|
||||
. 'if(selAll){selAll.addEventListener("change",function(){'
|
||||
. 'document.querySelectorAll(".aksrt-row-check").forEach(function(c){c.checked=selAll.checked;});});}'
|
||||
. 'var bulkForm=document.getElementById("aksrt-after-sale-bulk-form");'
|
||||
. 'if(bulkForm){bulkForm.addEventListener("submit",function(e){'
|
||||
. 'var checked=document.querySelectorAll(".aksrt-row-check:checked");'
|
||||
. 'var decision=document.getElementById("aksrt-bulk-decision").value;'
|
||||
. 'if(!checked.length){e.preventDefault();alert(' . wp_json_encode(__('请先勾选要操作的售后记录。', 'aksrt')) . ');return;}'
|
||||
. 'if(!decision){e.preventDefault();alert(' . wp_json_encode(__('请选择批量操作。', 'aksrt')) . ');return;}'
|
||||
. 'if(decision==="reject"){var note=prompt(tReject,"");if(note===null){e.preventDefault();return;}document.getElementById("aksrt-bulk-note").value=note;}'
|
||||
. 'else if(!confirm(' . wp_json_encode(__('确认批量通过选中的记录吗?', 'aksrt')) . ')){e.preventDefault();return;}'
|
||||
. '});}'
|
||||
. '})();</script>';
|
||||
}
|
||||
|
||||
public function handle_after_sale_review(): void {
|
||||
@@ -498,6 +527,31 @@ class PayOrders {
|
||||
wp_safe_redirect($this->page_url(self::PAGE_AFTER_SALES_SLUG, $args)); exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核售后申请(仅对待审核/处理中有效,其余由 review() 校验拒绝并计入失败)。
|
||||
*/
|
||||
public function handle_after_sale_bulk(): void {
|
||||
if (!current_user_can(self::CAPABILITY)) wp_die(esc_html__('权限不足', 'aksrt'));
|
||||
check_admin_referer('aksrt_after_sale_bulk');
|
||||
$decision = isset($_POST['bulk_decision']) ? sanitize_key((string) wp_unslash($_POST['bulk_decision'])) : '';
|
||||
if (!in_array($decision, ['approve', 'reject'], true)) {
|
||||
wp_safe_redirect($this->page_url(self::PAGE_AFTER_SALES_SLUG, ['aksrt_pay_msg' => 'after_sale_review_failed'])); exit;
|
||||
}
|
||||
$note = isset($_POST['bulk_note']) ? sanitize_textarea_field((string) wp_unslash($_POST['bulk_note'])) : '';
|
||||
$ids = array_values(array_unique(array_map('absint', (array) ($_POST['after_sale_ids'] ?? []))));
|
||||
$service = \AKSRT\Payment\AfterSaleService::get_instance();
|
||||
$done = 0; $failed = 0;
|
||||
foreach ($ids as $id) {
|
||||
if ($id <= 0) continue;
|
||||
$result = $service->review($id, $decision, $note);
|
||||
if (is_wp_error($result)) $failed++; else $done++;
|
||||
}
|
||||
$args = ['aksrt_pay_msg' => $failed > 0 ? 'after_sale_review_failed' : 'after_sale_reviewed'];
|
||||
if ($done > 0) $args['aksrt_bulk_done'] = $done;
|
||||
if ($failed > 0) $args['aksrt_bulk_failed'] = $failed;
|
||||
wp_safe_redirect($this->page_url(self::PAGE_AFTER_SALES_SLUG, $args)); exit;
|
||||
}
|
||||
|
||||
public function handle_update_order_status(): void {
|
||||
if (!current_user_can(self::CAPABILITY)) {
|
||||
wp_die(esc_html__('权限不足', 'aksrt'));
|
||||
|
||||
Reference in New Issue
Block a user