diff --git a/assets/css/routes/user-center/credits.css b/assets/css/routes/user-center/credits.css index 9f29d0c7..07ddc9f7 100644 --- a/assets/css/routes/user-center/credits.css +++ b/assets/css/routes/user-center/credits.css @@ -928,3 +928,41 @@ body.uc-modal-open { } .uc-card-pass__tip.is-error { color: #b91c1c; } + + +/* Withdraw history + pending foot */ +.uc-asset-card__foot { + margin-top: 8px; + padding-top: 8px; + border-top: 1px dashed var(--muted-border-color, rgba(0,0,0,.08)); +} +.uc-asset-card__foot button { + background: none; + border: 0; + padding: 0; + cursor: pointer; +} +.uc-asset-card__head-action { + background: none; + border: 0; + cursor: pointer; +} +.uc-withdraw-history__item:last-child { + border-bottom: 0 !important; +} + + +/* Points tasks tab */ +.uc-points-tasks .border-bottom, +.uc-points-date .border-bottom, +.uc-withdraw-history__item.border-bottom { + border-bottom: 1px solid var(--muted-border-color, rgba(0,0,0,.08)); +} +.uc-points-tasks button, +.uc-points-date button { + background: none; + border: 0; + cursor: pointer; + padding: 0; +} +.focus-color { color: var(--focus-color, #f59e0b); } diff --git a/assets/js/credits.js b/assets/js/credits.js index 36bc8fb8..efbe0433 100644 --- a/assets/js/credits.js +++ b/assets/js/credits.js @@ -908,10 +908,17 @@ link.addEventListener('click', function (e) { e.preventDefault(); var key = link.getAttribute('data-aksrt-asset-tab'); - document.querySelectorAll('[data-aksrt-asset-tab]').forEach(function (a) { + document.querySelectorAll('.uc-asset-tabs__nav [data-aksrt-asset-tab]').forEach(function (a) { var li = a.closest('li'); - if (li) li.classList.toggle('active', a === link); + if (!li) return; + var aKey = a.getAttribute('data-aksrt-asset-tab'); + var on = aKey === key || (key === 'points_date' && aKey === 'points_free'); + li.classList.toggle('active', on); }); + var tabs = document.querySelector('.uc-asset-tabs'); + if (tabs && typeof tabs.scrollIntoView === 'function') { + tabs.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } document.querySelectorAll('[data-aksrt-asset-pane]').forEach(function (pane) { var on = pane.getAttribute('data-aksrt-asset-pane') === key; pane.classList.toggle('is-active', on); @@ -921,6 +928,20 @@ }); } + + function initWithdrawHistory() { + var modal = document.querySelector('[data-aksrt-withdraw-history-modal]'); + if (!modal) return; + function open() { modal.hidden = false; document.body.classList.add('uc-modal-open'); } + function close() { modal.hidden = true; document.body.classList.remove('uc-modal-open'); } + document.querySelectorAll('[data-aksrt-withdraw-history-open]').forEach(function (btn) { + btn.addEventListener('click', function (e) { e.preventDefault(); open(); }); + }); + modal.querySelectorAll('[data-aksrt-withdraw-history-close]').forEach(function (btn) { + btn.addEventListener('click', function (e) { e.preventDefault(); close(); }); + }); + } + function bootAssets() { initSignin(); initInvite(); @@ -932,6 +953,7 @@ initExchange(); initPointsBuy(); initWithdraw(); + initWithdrawHistory(); initAssetTabs(); } diff --git a/inc/classes/admin/native/class-aksrt-admin-pay-withdrawals.php b/inc/classes/admin/native/class-aksrt-admin-pay-withdrawals.php index f80e8a42..08197e28 100644 --- a/inc/classes/admin/native/class-aksrt-admin-pay-withdrawals.php +++ b/inc/classes/admin/native/class-aksrt-admin-pay-withdrawals.php @@ -107,13 +107,27 @@ class AKSRT_Admin_Pay_Withdrawals { $user_id = (int) ($row['user_id'] ?? 0); $user = $user_id > 0 ? get_userdata($user_id) : null; $st = (string) ($row['status'] ?? ''); + $gross = (float) ($row['gross_amount'] ?? $row['amount'] ?? 0); + $net = (float) ($row['amount'] ?? 0); + $fee = (int) ($row['fee_rate'] ?? 0); + $acct = (string) ($row['display_account'] ?? $row['account_info'] ?? ''); + $amount_txt = number_format($net, 2); + if ($gross > 0 && abs($gross - $net) > 0.001) { + $amount_txt = sprintf( + /* translators: 1: gross 2: net 3: fee percent */ + __('申请 %1$s / 到账 %2$s(手续费 %3$d%%)', 'aksrt'), + number_format($gross, 2), + number_format($net, 2), + $fee + ); + } echo ''; echo '' . esc_html((string) $id) . ''; echo '' . ($user ? esc_html($user->display_name . ' (#' . $user_id . ')') : esc_html((string) $user_id)) . ''; - echo '' . esc_html(number_format((float) ($row['amount'] ?? 0), 2)) . ''; + echo '' . esc_html($amount_txt) . ''; echo '' . esc_html((string) ($row['method'] ?? '')) . ''; - echo '' . esc_html((string) ($row['account_info'] ?? '')) . ''; + echo '' . esc_html($acct) . ''; echo '' . esc_html($status_options[$st] ?? $st) . ''; echo '' . esc_html((string) ($row['created_at'] ?? '')) . ''; echo ''; @@ -169,13 +183,18 @@ class AKSRT_Admin_Pay_Withdrawals { $note = isset($_POST['note']) ? sanitize_textarea_field((string) wp_unslash($_POST['note'])) : ''; check_admin_referer('aksrt_pay_update_withdrawal_' . $id); - $ok = false; + $msg = 'withdraw_failed'; if ($id > 0 && $new_status !== '' && class_exists('AKSRT_Withdrawal')) { - $ok = AKSRT_Withdrawal::get_instance()->update_status($id, $new_status, $note); + $result = AKSRT_Withdrawal::get_instance()->process_status_change($id, $new_status, $note); + if (!is_wp_error($result) && $result) { + $msg = 'withdraw_updated'; + } elseif (is_wp_error($result) && $result->get_error_code() === 'aksrt_balance') { + $msg = 'withdraw_refund_failed'; + } } wp_safe_redirect($this->page_url('aksrt_withdraw', [ - 'aksrt_pay_msg' => $ok ? 'withdraw_updated' : 'withdraw_failed', + 'aksrt_pay_msg' => $msg, ])); exit; } @@ -208,8 +227,9 @@ class AKSRT_Admin_Pay_Withdrawals { } $code = sanitize_key((string) wp_unslash($_GET['aksrt_pay_msg'])); $map = [ - 'withdraw_updated' => __('提现状态已更新。', 'aksrt'), - 'withdraw_failed' => __('提现状态更新失败。', 'aksrt'), + 'withdraw_updated' => __('提现状态已更新。', 'aksrt'), + 'withdraw_failed' => __('提现状态更新失败。', 'aksrt'), + 'withdraw_refund_failed' => __('状态未更新:余额退回失败,请检查钱包后重试。', 'aksrt'), ]; if (!isset($map[$code])) { return; diff --git a/inc/classes/class-aksrt-balance-service.php b/inc/classes/class-aksrt-balance-service.php index e7f22892..f4452fa2 100644 --- a/inc/classes/class-aksrt-balance-service.php +++ b/inc/classes/class-aksrt-balance-service.php @@ -734,6 +734,10 @@ class AKSRT_Balance_Service { if ($account === '') { return new WP_Error('aksrt_withdraw_account', __('请填写收款账号信息', 'aksrt'), ['status' => 400]); } + // One open balance withdrawal at a time (Zibll parity). + if (AKSRT_Withdrawal::get_instance()->has_open_withdrawal($user_id)) { + return new WP_Error('aksrt_withdraw_pending', __('您有处理中的提现申请,请等待完成后再申请', 'aksrt'), ['status' => 409]); + } $wallet = AKSRT_Balance::balance($user_id); if ($wallet < $amount) { return new WP_Error('aksrt_balance_insufficient', __('余额不足', 'aksrt'), ['status' => 402]); diff --git a/inc/classes/class-aksrt-withdrawal.php b/inc/classes/class-aksrt-withdrawal.php index 413ed541..8c8a363c 100644 --- a/inc/classes/class-aksrt-withdrawal.php +++ b/inc/classes/class-aksrt-withdrawal.php @@ -1,8 +1,6 @@ insert($this->table(), [ - 'user_id' => $user_id, - 'amount' => $amount, - 'method' => sanitize_key($method), - 'account_info' => sanitize_textarea_field($account_info), - 'status' => self::STATUS_PENDING, - 'created_at' => current_time('mysql'), - ], ['%d', '%f', '%s', '%s', '%s', '%s']); + $wpdb->insert($this->table(), [ + 'user_id' => $user_id, + 'amount' => $amount, + 'method' => sanitize_key($method), + 'account_info' => sanitize_textarea_field($account_info), + 'status' => self::STATUS_PENDING, + 'created_at' => current_time('mysql'), + ], ['%d', '%f', '%s', '%s', '%s', '%s']); - return (int) $wpdb->insert_id; - } + return (int) $wpdb->insert_id; + } - /** - * 更新提现状态 - */ - public function update_status(int $withdrawal_id, string $new_status, string $note = ''): bool { - global $wpdb; + /** + * Get single row. + * + * @return array|null + */ + public function get(int $withdrawal_id): ?array { + global $wpdb; + if ($withdrawal_id <= 0) { + return null; + } + $row = $wpdb->get_row( + $wpdb->prepare("SELECT * FROM {$this->table()} WHERE id = %d LIMIT 1", $withdrawal_id), + ARRAY_A + ); + return is_array($row) ? $row : null; + } - $update = ['status' => sanitize_key($new_status)]; - $format = ['%s']; + /** + * 更新提现状态(无余额副作用)。优先使用 process_status_change()。 + */ + public function update_status(int $withdrawal_id, string $new_status, string $note = ''): bool { + global $wpdb; - if ($new_status === self::STATUS_COMPLETED || $new_status === self::STATUS_REJECTED) { - $update['processed_at'] = current_time('mysql'); - $format[] = '%s'; - } + $update = ['status' => sanitize_key($new_status)]; + $format = ['%s']; - if ($note !== '') { - $update['note'] = sanitize_textarea_field($note); - $format[] = '%s'; - } + if ($new_status === self::STATUS_COMPLETED || $new_status === self::STATUS_REJECTED) { + $update['processed_at'] = current_time('mysql'); + $format[] = '%s'; + } - return $wpdb->update($this->table(), $update, ['id' => $withdrawal_id], $format, ['%d']) !== false; - } + if ($note !== '') { + $update['note'] = sanitize_textarea_field($note); + $format[] = '%s'; + } - /** - * 获取用户提现列表 - */ - public function get_user_withdrawals(int $user_id, array $args = []): array { - global $wpdb; + return $wpdb->update($this->table(), $update, ['id' => $withdrawal_id], $format, ['%d']) !== false; + } - $where = ['user_id = %d']; - $params = [$user_id]; + /** + * Status transition with balance side-effects. + * Reject of balance-source holds refunds gross_amount once (idempotent). + * + * @return true|WP_Error + */ + public function process_status_change(int $withdrawal_id, string $new_status, string $note = '') { + $new_status = sanitize_key($new_status); + $allowed = [ + self::STATUS_PENDING, + self::STATUS_APPROVED, + self::STATUS_PROCESSING, + self::STATUS_COMPLETED, + self::STATUS_REJECTED, + ]; + if ($withdrawal_id <= 0 || !in_array($new_status, $allowed, true)) { + return new WP_Error('aksrt_withdraw_status', __('提现状态无效', 'aksrt')); + } - $status = sanitize_key((string) ($args['status'] ?? '')); - if ($status !== '') { - $where[] = 'status = %s'; - $params[] = $status; - } + $row = $this->get($withdrawal_id); + if (!$row) { + return new WP_Error('aksrt_withdraw_missing', __('提现记录不存在', 'aksrt')); + } - $limit = max(1, min(100, (int) ($args['limit'] ?? 20))); - $offset = max(0, (int) ($args['offset'] ?? 0)); + $old_status = sanitize_key((string) ($row['status'] ?? '')); + if ($old_status === $new_status && $note === '') { + return true; + } - $sql = "SELECT * FROM {$this->table()} WHERE " . implode(' AND ', $where) . " ORDER BY created_at DESC LIMIT %d OFFSET %d"; - $params[] = $limit; - $params[] = $offset; + $meta = $this->parse_account_meta((string) ($row['account_info'] ?? '')); + $user_id = (int) ($row['user_id'] ?? 0); - return (array) $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A); - } + // Refund frozen balance when moving into rejected (once). + if ( + $new_status === self::STATUS_REJECTED + && $old_status !== self::STATUS_REJECTED + && empty($meta['balance_refunded']) + && $this->is_balance_source($meta) + && class_exists('AKSRT_Balance') + && $user_id > 0 + ) { + $gross = $this->resolve_gross_amount($row, $meta); + if ($gross > 0) { + $refund = AKSRT_Balance::add( + $user_id, + $gross, + 'withdraw_refund', + ['type' => 'withdraw', 'id' => $withdrawal_id], + sprintf(__('提现拒绝退回 #%d', 'aksrt'), $withdrawal_id) + ); + if (is_wp_error($refund)) { + return $refund; + } + $meta['balance_refunded'] = true; + $meta['refunded_at'] = current_time('mysql'); + } + } - /** - * 获取所有提现列表(管理后台) - */ - public function get_all(array $args = []): array { - global $wpdb; + $account_info = $this->encode_account_meta($meta, (string) ($row['account_info'] ?? '')); + $merged_note = $this->merge_note((string) ($row['note'] ?? ''), $note); - $where = []; - $params = []; + global $wpdb; + $update = [ + 'status' => $new_status, + 'account_info' => $account_info, + ]; + $format = ['%s', '%s']; - $status = sanitize_key((string) ($args['status'] ?? '')); - if ($status !== '') { - $where[] = 'status = %s'; - $params[] = $status; - } + if ($new_status === self::STATUS_COMPLETED || $new_status === self::STATUS_REJECTED) { + $update['processed_at'] = current_time('mysql'); + $format[] = '%s'; + } + if ($merged_note !== '') { + $update['note'] = $merged_note; + $format[] = '%s'; + } - $limit = max(1, min(100, (int) ($args['limit'] ?? 20))); - $offset = max(0, (int) ($args['offset'] ?? 0)); + $ok = $wpdb->update($this->table(), $update, ['id' => $withdrawal_id], $format, ['%d']) !== false; + return $ok ? true : new WP_Error('aksrt_withdraw_update', __('提现状态更新失败', 'aksrt')); + } - $where_sql = $where ? 'WHERE ' . implode(' AND ', $where) : ''; - $sql = "SELECT * FROM {$this->table()} {$where_sql} ORDER BY created_at DESC LIMIT %d OFFSET %d"; - $params[] = $limit; - $params[] = $offset; + /** + * Whether user has open (pending/processing/approved) withdrawals. + */ + public function has_open_withdrawal(int $user_id): bool { + return $this->count_open($user_id) > 0; + } - if (!empty($params)) { - return (array) $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A); - } - return (array) $wpdb->get_results($sql, ARRAY_A); - } + /** + * Count open withdrawals. + */ + public function count_open(int $user_id): int { + global $wpdb; + if ($user_id <= 0) { + return 0; + } + return (int) $wpdb->get_var($wpdb->prepare( + "SELECT COUNT(*) FROM {$this->table()} + WHERE user_id = %d AND status IN ('pending','approved','processing')", + $user_id + )); + } - /** - * 获取提现总数(支持状态过滤) - */ - public function get_count(array $args = []): int { - global $wpdb; + /** + * Sum of frozen gross amounts still open (balance source). + */ + public function sum_pending_hold(int $user_id): float { + global $wpdb; + if ($user_id <= 0) { + return 0.0; + } + $rows = $wpdb->get_results($wpdb->prepare( + "SELECT amount, account_info FROM {$this->table()} + WHERE user_id = %d AND status IN ('pending','approved','processing')", + $user_id + ), ARRAY_A); + $total = 0.0; + foreach ((array) $rows as $row) { + $meta = $this->parse_account_meta((string) ($row['account_info'] ?? '')); + if (!$this->is_balance_source($meta) || !empty($meta['balance_refunded'])) { + continue; + } + $total += $this->resolve_gross_amount($row, $meta); + } + return round($total, 2); + } - $status = sanitize_key((string) ($args['status'] ?? '')); - if ($status !== '') { - return (int) $wpdb->get_var($wpdb->prepare( - "SELECT COUNT(*) FROM {$this->table()} WHERE status = %s", - $status - )); - } - return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$this->table()}"); - } + /** + * 获取用户提现列表 + * + * @param array{status?:string,limit?:int,offset?:int,open_only?:bool} $args + * @return list> + */ + public function get_user_withdrawals(int $user_id, array $args = []): array { + global $wpdb; - /** - * 获取提现统计 - */ - public function get_stats(): array { - global $wpdb; + $where = ['user_id = %d']; + $params = [$user_id]; - $row = $wpdb->get_row( - "SELECT - COUNT(*) as total, - SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending, - SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed, - COALESCE(SUM(CASE WHEN status = 'completed' THEN amount ELSE 0 END), 0) as total_paid - FROM {$this->table()}", - ARRAY_A - ); + if (!empty($args['open_only'])) { + $where[] = "status IN ('pending','approved','processing')"; + } else { + $status = sanitize_key((string) ($args['status'] ?? '')); + if ($status !== '') { + $where[] = 'status = %s'; + $params[] = $status; + } + } - return [ - 'total' => (int) ($row['total'] ?? 0), - 'pending' => (int) ($row['pending'] ?? 0), - 'completed' => (int) ($row['completed'] ?? 0), - 'total_paid' => (float) ($row['total_paid'] ?? 0), - ]; - } + $limit = max(1, min(100, (int) ($args['limit'] ?? 20))); + $offset = max(0, (int) ($args['offset'] ?? 0)); + + $sql = "SELECT * FROM {$this->table()} WHERE " . implode(' AND ', $where) . ' ORDER BY created_at DESC LIMIT %d OFFSET %d'; + $params[] = $limit; + $params[] = $offset; + + $rows = (array) $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A); + return array_map([$this, 'normalize_row'], $rows); + } + + /** + * 获取所有提现列表(管理后台) + * + * @return list> + */ + public function get_all(array $args = []): array { + global $wpdb; + + $where = []; + $params = []; + + $status = sanitize_key((string) ($args['status'] ?? '')); + if ($status !== '') { + $where[] = 'status = %s'; + $params[] = $status; + } + + $limit = max(1, min(100, (int) ($args['limit'] ?? 20))); + $offset = max(0, (int) ($args['offset'] ?? 0)); + + $where_sql = $where ? 'WHERE ' . implode(' AND ', $where) : ''; + $sql = "SELECT * FROM {$this->table()} {$where_sql} ORDER BY created_at DESC LIMIT %d OFFSET %d"; + $params[] = $limit; + $params[] = $offset; + + if (!empty($params)) { + $rows = (array) $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A); + } else { + $rows = (array) $wpdb->get_results($sql, ARRAY_A); + } + return array_map([$this, 'normalize_row'], $rows); + } + + public function get_count(array $args = []): int { + global $wpdb; + + $status = sanitize_key((string) ($args['status'] ?? '')); + if ($status !== '') { + return (int) $wpdb->get_var($wpdb->prepare( + "SELECT COUNT(*) FROM {$this->table()} WHERE status = %s", + $status + )); + } + return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$this->table()}"); + } + + public function get_stats(): array { + global $wpdb; + + $row = $wpdb->get_row( + "SELECT + COUNT(*) as total, + SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending, + SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed, + COALESCE(SUM(CASE WHEN status = 'completed' THEN amount ELSE 0 END), 0) as total_paid + FROM {$this->table()}", + ARRAY_A + ); + + return [ + 'total' => (int) ($row['total'] ?? 0), + 'pending' => (int) ($row['pending'] ?? 0), + 'completed' => (int) ($row['completed'] ?? 0), + 'total_paid' => (float) ($row['total_paid'] ?? 0), + ]; + } + + /** + * @param array $row + * @return array + */ + private function normalize_row(array $row): array { + $meta = $this->parse_account_meta((string) ($row['account_info'] ?? '')); + $gross = $this->resolve_gross_amount($row, $meta); + $row['meta'] = $meta; + $row['gross_amount'] = $gross; + $row['fee_rate'] = (int) ($meta['fee_rate'] ?? 0); + $row['display_account'] = (string) ($meta['account'] ?? $row['account_info'] ?? ''); + $row['source'] = (string) ($meta['source'] ?? 'balance'); + return $row; + } + + /** + * @return array + */ + private function parse_account_meta(string $raw): array { + $raw = trim($raw); + if ($raw === '') { + return []; + } + $decoded = json_decode($raw, true); + return is_array($decoded) ? $decoded : ['account' => $raw]; + } + + /** + * @param array $meta + */ + private function encode_account_meta(array $meta, string $fallback_raw): string { + if ($meta === []) { + return $fallback_raw; + } + $json = wp_json_encode($meta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + return is_string($json) ? $json : $fallback_raw; + } + + /** + * @param array $meta + */ + private function is_balance_source(array $meta): bool { + $source = sanitize_key((string) ($meta['source'] ?? 'balance')); + // Empty / balance = cash wallet freeze path. + return $source === '' || $source === 'balance'; + } + + /** + * @param array $row + * @param array $meta + */ + private function resolve_gross_amount(array $row, array $meta): float { + if (isset($meta['gross_amount'])) { + return max(0, round((float) $meta['gross_amount'], 2)); + } + // Legacy rows: amount was net or gross without meta. + return max(0, round((float) ($row['amount'] ?? 0), 2)); + } + + private function merge_note(string $old, string $new): string { + $new = sanitize_textarea_field($new); + if ($new === '') { + return sanitize_textarea_field($old); + } + $old = sanitize_textarea_field($old); + if ($old === '') { + return $new; + } + return $old . "\n" . $new; + } } diff --git a/inc/helpers/user-center-renderers/credits-wallet.php b/inc/helpers/user-center-renderers/credits-wallet.php index 462fe5c7..f33b7d7d 100644 --- a/inc/helpers/user-center-renderers/credits-wallet.php +++ b/inc/helpers/user-center-renderers/credits-wallet.php @@ -26,6 +26,14 @@ $exchange_on = !empty($recharge['exchange']['enabled']); $all_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_all() : []; $withdraw_on = !empty($all_settings['pay_balance_withdraw_s']); $withdraw_min = max(1, (float) ($all_settings['pay_balance_withdraw_lowest_money'] ?? $all_settings['pay_rebate_withdraw_lowest_money'] ?? 50)); +$withdraw_pending_hold = 0.0; +$withdraw_history = []; +if ($withdraw_on && class_exists('AKSRT_Withdrawal')) { + $wd_svc = AKSRT_Withdrawal::get_instance(); + $withdraw_pending_hold = $wd_svc->sum_pending_hold((int) ($user_id ?? 0)); + $withdraw_history = $wd_svc->get_user_withdrawals((int) ($user_id ?? 0), ['limit' => 30]); +} +$withdraw_processing = $withdraw_pending_hold > 0; $card_pass_balance = ['enabled' => false, 'desc' => '', 'only_password' => true]; if (class_exists('AKSRT_Charge_Card')) { $opts = AKSRT_Charge_Card::get_instance()->get_public_options(); @@ -49,6 +57,12 @@ $mark = (string) ($charge_view['currency_mark'] ?? '元');
+ + +
@@ -60,7 +74,11 @@ $mark = (string) ($charge_view['currency_mark'] ?? '元'); - + + + + +
@@ -74,6 +92,12 @@ $mark = (string) ($charge_view['currency_mark'] ?? '元'); + +
+ + +
+
@@ -231,6 +255,53 @@ $mark = (string) ($charge_view['currency_mark'] ?? '元'); + + __('待处理', 'aksrt'), + 'approved' => __('已通过', 'aksrt'), + 'processing' => __('处理中', 'aksrt'), + 'completed' => __('已完成', 'aksrt'), + 'rejected' => __('已拒绝', 'aksrt'), + ]; + ?> + + +