From 5cae5b5c93b89079cbcf14e0bc030ae09a66433b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 24 Aug 2026 15:59:11 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=AF=E5=88=86=E4=B8=8E=E4=BD=99=E9=A2=9D?= =?UTF-8?q?=E8=B4=A6=E5=8A=A1=E7=B3=BB=E7=BB=9F=E7=A1=AC=E5=88=87=E9=87=8D?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 + assets/admin/src/api/index.js | 30 + assets/admin/src/api/modules/users.js | 12 +- assets/admin/src/pages/CmsCredits.vue | 118 +++- .../content/NotificationCenterSettings.vue | 16 +- .../src/pages/payment/PaymentChargeCard.vue | 27 +- .../admin/src/pages/payment/PaymentRebate.vue | 315 ---------- .../src/pages/payment/PaymentRevenue.vue | 66 +- .../components/ChargeCardDetailDrawer.vue | 2 +- .../payment/components/RebateDetailDrawer.vue | 175 ------ .../admin/src/pages/users/UsersMessages.vue | 12 +- assets/admin/src/pages/users/UsersVerify.vue | 8 +- assets/admin/src/router/index.js | 1 - .../src/schema/sections/payment/cardPass.js | 4 +- .../src/schema/sections/payment/recharge.js | 2 - .../admin/src/schema/sections/payment/vip.js | 4 +- .../src/schema/sections/payment/withdrawal.js | 8 +- .../src/schema/sections/post-list/page.js | 4 +- .../src/schema/sections/post-list/submit.js | 8 +- .../admin/src/schema/sections/users/badge.js | 4 +- .../src/schema/sections/users/credits.js | 12 +- .../admin/src/schema/sections/users/verify.js | 8 +- assets/js/cms-download.js | 26 +- assets/js/core/request.js | 18 + assets/js/credits.js | 92 ++- assets/js/order-center.js | 49 +- assets/js/reward.js | 18 +- assets/js/routes/user-center-auth.js | 28 +- assets/js/runtime/admin-main.js | 6 +- assets/js/runtime/admin-main.min.js | 2 +- assets/js/vip-purchase-coordinator.js | 17 +- inc/helpers/aksrt-coupon-order.php | 21 +- inc/helpers/aksrt-credits.php | 88 +-- inc/helpers/aksrt-frontend-tags.php | 6 +- inc/helpers/aksrt-header-userbox.php | 7 +- inc/helpers/aksrt-pay.php | 188 ++++-- inc/helpers/aksrt-resource.php | 48 +- inc/helpers/aksrt-rewards.php | 73 ++- inc/helpers/aksrt-transactions.php | 51 -- inc/helpers/aksrt-user-dashboard.php | 10 +- inc/helpers/aksrt-vip.php | 2 +- .../user-center-renderers/credits-balance.php | 9 +- .../credits-transactions.php | 15 +- .../user-center-renderers/credits-wallet.php | 55 +- .../user-center-renderers/profile-creator.php | 9 +- .../user-center-renderers/profile-credits.php | 14 +- .../user-center-renderers/profile-orders.php | 13 +- .../user-center-renderers/profile-revenue.php | 36 +- .../sidebar-commerce.php | 12 +- .../user-center-renderers/withdraw-modal.php | 12 +- inc/modules/user-notifications.php | 57 +- phpunit.xml.dist | 8 + src/Admin/ControllerBase.php | 16 +- src/Admin/ImportExportController.php | 4 +- src/Admin/Native/PayChargeCards.php | 32 +- src/Admin/Native/PayCoupons.php | 18 +- src/Admin/Native/PayIncome.php | 41 +- src/Admin/Native/PayMenus.php | 13 +- src/Admin/Native/PayOrders.php | 12 +- src/Admin/Native/PayProducts.php | 23 +- src/Admin/Native/PayRebate.php | 202 ------- src/Admin/Native/PayWithdrawals.php | 65 +- src/Admin/PaymentController.php | 385 ++++-------- src/Admin/Schema/SchemaPayment.php | 9 +- src/Admin/Schema/SchemaPostList.php | 8 +- src/Admin/Schema/SchemaUsers.php | 10 +- src/Admin/SchemaProvider.php | 33 +- src/Admin/UserController.php | 172 +++++- src/Content/Download.php | 10 +- src/Content/DownloadState.php | 39 +- src/Content/Pay.php | 1 - src/Content/PayHelpers.php | 226 ++++--- src/Content/PayOrders.php | 316 ++++++---- src/Content/PayRest.php | 37 +- src/Content/VipService.php | 1 - src/Content/VipServicePackages.php | 128 ++-- src/Content/VipServicePurchase.php | 268 +++++--- src/Content/VipServiceRest.php | 17 +- src/Content/Visibility.php | 54 +- src/Core/DBMigrator.php | 2 +- src/Core/DBMigratorIdentity.php | 5 +- src/Core/DBMigratorPart2.php | 137 ++--- src/Core/DBMigratorPart3.php | 6 +- src/Core/DBMigratorVip.php | 2 +- src/Core/DomainModel.php | 60 +- src/Core/FrontSubmitPay.php | 111 +++- src/Core/PostMetaBox.php | 33 +- src/Core/ResourceMetaBox.php | 23 +- src/Core/ScriptsPart1b.php | 7 +- src/Core/ScriptsPart1c.php | 2 +- src/Core/Setup.php | 26 +- src/Credits/Balance.php | 379 ------------ src/Credits/BalanceService.php | 1 - src/Credits/BalanceServiceCharge.php | 286 +++++---- src/Credits/BalanceServiceRest.php | 346 +++++------ src/Credits/Credits.php | 305 ---------- src/Credits/PointsFree.php | 64 +- src/Credits/Signin.php | 182 ++++-- src/Identity/ApplicationRepository.php | 22 +- src/Identity/ApplicationService.php | 424 ++++++++----- src/Identity/EventRepository.php | 19 +- src/Identity/EvidenceService.php | 21 + src/Identity/RestController.php | 82 ++- src/Identity/TransitionService.php | 135 +++-- src/Ledger/AssetAmount.php | 88 +++ src/Ledger/AssetType.php | 17 + src/Ledger/LedgerAbort.php | 14 + src/Ledger/LedgerCommand.php | 138 +++++ src/Ledger/LedgerPresentation.php | 44 ++ src/Ledger/LedgerQuery.php | 245 ++++++++ src/Ledger/LedgerResult.php | 36 ++ src/Ledger/LedgerService.php | 562 +++++++++++++++++ src/Ledger/OperationKey.php | 39 ++ src/Payment/BalanceGateway.php | 247 ++++++-- src/Payment/ChargeCard.php | 571 ++++++++++++------ src/Payment/CommissionLedger.php | 425 ++++++++++--- src/Payment/Coupon.php | 123 +++- src/Payment/Gateway.php | 20 +- src/Payment/GatewayInterface.php | 6 +- src/Payment/Gateways/AlipayGateway.php | 42 +- src/Payment/Gateways/EpayGateway.php | 30 +- src/Payment/Gateways/PayPalGateway.php | 29 +- src/Payment/Gateways/StripeGateway.php | 47 +- src/Payment/Gateways/WechatPayGateway.php | 30 +- src/Payment/Order.php | 4 +- src/Payment/OrderCenterRest.php | 24 +- src/Payment/OrderRepository.php | 3 + src/Payment/OrderRepositoryAdmin.php | 95 ++- src/Payment/OrderRepositoryCore.php | 261 ++++++-- src/Payment/PaymentOrchestrator.php | 58 +- src/Payment/Rebate.php | 235 ------- src/Payment/ReferralAttribution.php | 120 ++-- src/Payment/Revenue.php | 333 ++++++---- src/Payment/UserOrders.php | 41 +- src/Payment/Withdrawal.php | 501 +++++++++------ src/Settings/CreditsPaymentGroups.php | 6 +- src/Settings/Integration.php | 10 +- src/Settings/PaymentRuntime.php | 35 +- src/Settings/PostDisplay.php | 54 +- src/Settings/UserRuntime.php | 23 +- src/User/AuthApply.php | 2 +- src/User/Badges.php | 28 +- src/User/BalanceAdmin.php | 78 ++- src/User/Center.php | 3 +- src/User/CreditsAdmin.php | 128 ++-- src/User/Metrics.php | 49 +- src/WidgetSystem/Renderers/UserRenderer.php | 2 +- templates/pages/page-download.php | 4 +- templates/pages/page-messages.php | 15 +- templates/parts/resource-download-box.php | 2 +- templates/parts/user-home/panel-credits.php | 2 +- templates/shortcodes/profile.php | 2 +- tests/asset-ledger/AssetAmountTest.php | 76 +++ tests/asset-ledger/LedgerCommandTest.php | 115 ++++ tests/asset-ledger/LedgerResultTest.php | 18 + tests/asset-ledger/OperationKeyTest.php | 28 + tests/asset-ledger/bootstrap.php | 61 ++ .../asset-ledger-contract.test.cjs | 170 ++++++ uninstall.php | 4 +- 159 files changed, 7275 insertions(+), 4718 deletions(-) delete mode 100644 assets/admin/src/pages/payment/PaymentRebate.vue delete mode 100644 assets/admin/src/pages/payment/components/RebateDetailDrawer.vue create mode 100644 phpunit.xml.dist delete mode 100644 src/Admin/Native/PayRebate.php delete mode 100644 src/Credits/Balance.php delete mode 100644 src/Credits/Credits.php create mode 100644 src/Ledger/AssetAmount.php create mode 100644 src/Ledger/AssetType.php create mode 100644 src/Ledger/LedgerAbort.php create mode 100644 src/Ledger/LedgerCommand.php create mode 100644 src/Ledger/LedgerPresentation.php create mode 100644 src/Ledger/LedgerQuery.php create mode 100644 src/Ledger/LedgerResult.php create mode 100644 src/Ledger/LedgerService.php create mode 100644 src/Ledger/OperationKey.php delete mode 100644 src/Payment/Rebate.php create mode 100644 tests/asset-ledger/AssetAmountTest.php create mode 100644 tests/asset-ledger/LedgerCommandTest.php create mode 100644 tests/asset-ledger/LedgerResultTest.php create mode 100644 tests/asset-ledger/OperationKeyTest.php create mode 100644 tests/asset-ledger/bootstrap.php create mode 100644 tests/widget-system/asset-ledger-contract.test.cjs diff --git a/.gitignore b/.gitignore index f3b6baed..7b3eb20c 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,9 @@ !/tests/widget-system/auth-source-contract.test.cjs !/tests/widget-system/user-badges-contract.test.cjs !/tests/widget-system/user-features-contract.test.cjs +!/tests/widget-system/asset-ledger-contract.test.cjs +!/tests/asset-ledger/ +!/tests/asset-ledger/*.php !/tests/visual/docker-compose.zibll.yml !/tests/visual/zibll-Caddyfile !/tests/visual/README.md @@ -48,6 +51,7 @@ assets/admin/.vite-temp/ # Temporary / recovery helpers restore-helper-monoliths.php +/.phpunit.cache/ # OS / editor noise .DS_Store diff --git a/assets/admin/src/api/index.js b/assets/admin/src/api/index.js index be925358..c8fbbf28 100644 --- a/assets/admin/src/api/index.js +++ b/assets/admin/src/api/index.js @@ -12,6 +12,21 @@ import { apiMethods } from './modules/index.js' const API_ROOT = window.aksrtAdminData?.apiUrl || '/wp-json/aksrt/v1' const NONCE = window.aksrtAdminData?.nonce || '' +function createIdempotencyKey() { + if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { + return crypto.randomUUID() + } + if (typeof crypto === 'undefined' || typeof crypto.getRandomValues !== 'function') { + throw new Error('当前浏览器无法生成安全操作标识') + } + const bytes = new Uint8Array(16) + crypto.getRandomValues(bytes) + bytes[6] = (bytes[6] & 0x0f) | 0x40 + bytes[8] = (bytes[8] & 0x3f) | 0x80 + const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('') + return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}` +} + function normalizeDomainKey(domain) { return String(domain || 'global').trim().replace(/-/g, '_') } @@ -85,6 +100,7 @@ function joinRestUrl(baseUrl, endpoint) { class ApiClient { constructor() { this.baseUrl = API_ROOT + this.pendingIdempotencyKeys = new Map() } normalizeDomainKey(domain) { @@ -138,11 +154,22 @@ class ApiClient { finalBody = JSON.stringify(body) } + const isWrite = method !== 'GET' && method !== 'HEAD' + const suppliedKey = headers?.['Idempotency-Key'] || headers?.['idempotency-key'] || '' + const idempotencySignature = isWrite ? `${method}:${url}:${finalBody ?? ''}` : '' + const idempotencyKey = isWrite && !suppliedKey + ? (this.pendingIdempotencyKeys.get(idempotencySignature) || createIdempotencyKey()) + : suppliedKey + if (isWrite && !suppliedKey) { + this.pendingIdempotencyKeys.set(idempotencySignature, idempotencyKey) + } + const config = { method, headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': NONCE, + ...(idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : {}), ...headers, }, ...rest, @@ -174,6 +201,9 @@ class ApiClient { throw new Error(msg) } + if (idempotencySignature !== '') { + this.pendingIdempotencyKeys.delete(idempotencySignature) + } return data } catch (error) { console.error(`[API Error] ${endpoint}:`, error) diff --git a/assets/admin/src/api/modules/users.js b/assets/admin/src/api/modules/users.js index b9aed5e6..60f2f5c7 100644 --- a/assets/admin/src/api/modules/users.js +++ b/assets/admin/src/api/modules/users.js @@ -28,17 +28,17 @@ export const usersApiMethods = { return this.request('/identity/settings/test', { method: 'POST', body: JSON.stringify(data) }) }, - getCreditSettings() { return this.request('/credits/settings') }, - saveCreditSettings(data) { return this.request('/credits/settings', { method: 'POST', body: JSON.stringify(data) }) }, + getCreditSettings() { return this.request('/assets/settings') }, + saveCreditSettings(data) { return this.request('/assets/settings', { method: 'POST', body: JSON.stringify(data) }) }, listCreditUsers(params = {}) { const qs = new URLSearchParams(params).toString() - return this.request('/credits/users' + (qs ? `?${qs}` : '')) + return this.request('/assets/accounts' + (qs ? `?${qs}` : '')) }, - adjustUserCredits(id, delta, reason) { - return this.request(`/credits/users/${id}/adjust`, { method: 'POST', body: JSON.stringify({ delta, reason }) }) + adjustUserCredits(id, asset, delta, remark) { + return this.request(`/assets/accounts/${id}/adjust`, { method: 'POST', body: JSON.stringify({ asset, delta, remark }) }) }, getCreditLog(params = {}) { const qs = new URLSearchParams(params).toString() - return this.request('/credits/log' + (qs ? `?${qs}` : '')) + return this.request('/assets/transactions' + (qs ? `?${qs}` : '')) }, } diff --git a/assets/admin/src/pages/CmsCredits.vue b/assets/admin/src/pages/CmsCredits.vue index f77b92e0..34933637 100644 --- a/assets/admin/src/pages/CmsCredits.vue +++ b/assets/admin/src/pages/CmsCredits.vue @@ -1,8 +1,8 @@