diff --git a/apps/daxpay-admin/src/api/payment/develop/developTrade.api.ts b/apps/daxpay-admin/src/api/payment/develop/developTrade.api.ts index 29f9599f3..90a9852e8 100644 --- a/apps/daxpay-admin/src/api/payment/develop/developTrade.api.ts +++ b/apps/daxpay-admin/src/api/payment/develop/developTrade.api.ts @@ -5,6 +5,8 @@ import { defHttp } from '#/api/request'; /** * 交易开发调试 API + * + * 仅组参辅助与签名, 真实支付见 unipay-trade.api (POST /unipay/pay) */ export const DevelopTradeApi = { /** @@ -14,13 +16,6 @@ export const DevelopTradeApi = { return defHttp.post({ url: '/admin/develop/trade/sign', data }); }, - /** - * 支付调试(真实发起) - */ - pay(data: DevelopParam): Promise> { - return defHttp.post({ url: '/admin/develop/trade/pay', data }); - }, - /** * 已启用渠道支付方式目录(供调试页支付方式下拉) */ @@ -57,7 +52,7 @@ export interface DevelopParam { privateKey?: string; } -/** 支付参数 */ +/** 支付参数(与 unipay NormalPayParam 对齐) */ export interface PayParam { /** 商户号 */ mchNo: string; @@ -89,6 +84,14 @@ export interface PayParam { returnUrl?: string; /** 过期时间(北京时间 yyyy-MM-dd HH:mm:ss) */ expiredTime?: string; + /** 客户端 IP(可选, 未传时由 unipay 从 HTTP 请求提取) */ + clientIp?: string; + /** 随机串 */ + nonceStr?: string; + /** 请求时间(北京时间 yyyy-MM-dd HH:mm:ss) */ + reqTime?: string; + /** 签名 */ + sign?: string; } /** 支付结果 */ @@ -114,11 +117,3 @@ export interface DevelopSignResult { /** 签名值 */ sign?: string; } - -/** 支付调试结果 */ -export interface DevelopPayResult { - /** 支付结果 */ - payResult?: PayResult; - /** 响应签名(平台私钥签名) */ - sign?: string; -} diff --git a/apps/daxpay-admin/src/api/payment/unipay/unipay-request.ts b/apps/daxpay-admin/src/api/payment/unipay/unipay-request.ts new file mode 100644 index 000000000..8005ce389 --- /dev/null +++ b/apps/daxpay-admin/src/api/payment/unipay/unipay-request.ts @@ -0,0 +1,60 @@ +/** + * unipay 轻量 HTTP 客户端 + * + * 用于管理端「交易调试」等场景模拟商户直调统一支付接口。 + * 与 defHttp/requestClient 隔离: + * - 不注入 Accesstoken / x-client-code / nonce + * - 不挂登录失效拦截器(避免业务错误误踢登录) + * - 业务 code !== 0 时仍原样返回 body, 由页面展示完整 DaxResult + */ +import type { RequestClientOptions } from '@vben/request'; + +import { useAppConfig } from '@vben/hooks'; +import { RequestClient } from '@vben/request'; + +const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); + +/** unipay 通用响应(与后端 DaxResult 对齐) */ +export interface DaxResult { + code: number; + msg?: string; + data?: T; + sign?: string; + resTime?: string; + traceId?: string; +} + +function createUnipayClient(baseURL: string, options?: RequestClientOptions) { + const client = new RequestClient({ + ...options, + baseURL, + // 通道调用可能较慢 + timeout: 60_000, + responseReturn: 'body', + }); + + // 始终返回响应体; 业务失败(code!=0)不 throw, 交给调用方展示 + client.addResponseInterceptor({ + fulfilled: (response) => response.data, + }); + + return client; +} + +const unipayClient = createUnipayClient(apiURL); + +/** + * POST unipay 接口, 返回完整 DaxResult(含业务失败) + */ +export async function unipayPost(url: string, data?: unknown): Promise> { + // RequestClient 在 HTTP 非 2xx 时 throw response.data; 尽量当成 DaxResult 透出 + try { + return await unipayClient.post>(url, data); + } catch (error: unknown) { + // 后端部分异常可能以非 2xx + body 形式返回 + if (error && typeof error === 'object' && 'code' in error) { + return error as DaxResult; + } + throw error; + } +} diff --git a/apps/daxpay-admin/src/api/payment/unipay/unipay-trade.api.ts b/apps/daxpay-admin/src/api/payment/unipay/unipay-trade.api.ts new file mode 100644 index 000000000..4d59a896c --- /dev/null +++ b/apps/daxpay-admin/src/api/payment/unipay/unipay-trade.api.ts @@ -0,0 +1,19 @@ +/** + * 统一支付(unipay)交易接口 — 商户侧契约 + * + * 调试页通过此 API 模拟真实商户 HTTP 调用, 不走 admin 特权通道。 + */ +import type { DaxResult } from './unipay-request'; +import type { PayParam, PayResult } from '#/api/payment/develop/developTrade.api'; + +import { unipayPost } from './unipay-request'; + +/** + * 统一支付下单 + * + * POST /unipay/pay + * 请求体须含完整商户签名字段(reqTime/nonceStr/sign 等) + */ +export function uniPay(data: PayParam): Promise> { + return unipayPost('/unipay/pay', data); +} diff --git a/apps/daxpay-admin/src/constants/perm-codes.ts b/apps/daxpay-admin/src/constants/perm-codes.ts index 970321f03..75526b87b 100644 --- a/apps/daxpay-admin/src/constants/perm-codes.ts +++ b/apps/daxpay-admin/src/constants/perm-codes.ts @@ -205,11 +205,10 @@ export const PermCodes = { /** 开发调试(独立顶级域) */ Develop: { - /** 支付调试 menuCode=develop:trade */ + /** 支付调试 menuCode=develop:trade(真实支付走 unipay, 无 develop:trade:pay 后门) */ Trade: { VIEW: 'develop:trade:view', SIGN: 'develop:trade:sign', - PAY: 'develop:trade:pay', }, /** 签名调试 menuCode=develop:sign */ Sign: { diff --git a/apps/daxpay-admin/src/locales/langs/en-US/payment/develop.json b/apps/daxpay-admin/src/locales/langs/en-US/payment/develop.json index a167d42e7..13904fe14 100644 --- a/apps/daxpay-admin/src/locales/langs/en-US/payment/develop.json +++ b/apps/daxpay-admin/src/locales/langs/en-US/payment/develop.json @@ -52,8 +52,8 @@ "trade": { "page": { "title": "Payment Develop", - "tag": "Real Trade", - "warning": "Clicking \"Submit\" sends a real payment request to the system. Please confirm the params." + "tag": "Simulated Merchant API", + "warning": "This page only builds params and signs them. Submit simulates a merchant call to /unipay/pay (not an admin privilege path). Confirm params carefully." }, "card": { "basic": "Basic Info", @@ -113,7 +113,7 @@ }, "privateKey": { "modalTitle": "Set Merchant Private Key", - "modalTip": "Enter the merchant RSA private key for server-side signing (stored in browser local cache only).", + "modalTip": "Enter the merchant RSA private key for request signing only (stored in browser local cache; not used for admin privilege pay).", "placeholder": "Enter the merchant private key", "savedTip": "Private key saved", "clearedTip": "Private key cleared", @@ -124,12 +124,14 @@ "clearConfirmContent": "Are you sure you want to clear the merchant private key? It will need to be re-entered." }, "result": { - "modalTitle": "Payment Result", + "modalTitle": "Payment Result (unipay)", "payLink": "Payment Link", "jsapiParam": "JSAPI Params", "formData": "Form Data", "markCode": "Mark Code", - "copyData": "Copy Data", + "copyData": "Copy Pay Body", + "copyFull": "Copy Full Response", + "rawResponse": "Full DaxResult Response", "empty": "No data", "field": { "orderNo": "System Order No." @@ -146,6 +148,8 @@ }, "msg": { "signSuccess": "Sign generated successfully", + "paySuccess": "Payment request succeeded", + "payFail": "Payment request failed", "inputPrivateKey": "Please set the merchant private key first", "copySuccess": "Copied" } diff --git a/apps/daxpay-admin/src/locales/langs/zh-CN/payment/develop.json b/apps/daxpay-admin/src/locales/langs/zh-CN/payment/develop.json index 00a901fbd..c0699c58d 100644 --- a/apps/daxpay-admin/src/locales/langs/zh-CN/payment/develop.json +++ b/apps/daxpay-admin/src/locales/langs/zh-CN/payment/develop.json @@ -52,8 +52,8 @@ "trade": { "page": { "title": "支付调试", - "tag": "真实交易", - "warning": "点击「提交支付」将向支付系统发起真实交易请求,请确认参数无误。" + "tag": "模拟商户 API", + "warning": "本页仅组装参数并签名,提交后将模拟商户调用 /unipay/pay 发起真实交易(非管理端特权通道),请确认参数无误。" }, "card": { "basic": "基础信息", @@ -113,7 +113,7 @@ }, "privateKey": { "modalTitle": "设置商户私钥", - "modalTip": "请输入商户 RSA 私钥,用于在服务端计算签名(仅保存在浏览器本地缓存中)。", + "modalTip": "请输入商户 RSA 私钥,仅用于生成请求签名(仅保存在浏览器本地缓存中,不会用于管理端特权下单)。", "placeholder": "请输入商户私钥", "savedTip": "私钥保存成功", "clearedTip": "私钥已清除", @@ -124,12 +124,14 @@ "clearConfirmContent": "确定要清除已设置的商户私钥吗?清除后需重新输入。" }, "result": { - "modalTitle": "支付结果", + "modalTitle": "支付结果 (unipay)", "payLink": "支付链接", "jsapiParam": "JSAPI 参数", "formData": "表单数据", "markCode": "标识码", - "copyData": "复制数据", + "copyData": "复制支付参数", + "copyFull": "复制完整响应", + "rawResponse": "完整 DaxResult 响应", "empty": "暂无数据", "field": { "orderNo": "系统订单号" @@ -146,6 +148,8 @@ }, "msg": { "signSuccess": "签名生成成功", + "paySuccess": "支付请求成功", + "payFail": "支付请求失败", "inputPrivateKey": "请先设置商户私钥", "copySuccess": "复制成功" } diff --git a/apps/daxpay-admin/src/views/payment/develop/trade/DevelopTrade.vue b/apps/daxpay-admin/src/views/payment/develop/trade/DevelopTrade.vue index 614a4256e..eb4df4e90 100644 --- a/apps/daxpay-admin/src/views/payment/develop/trade/DevelopTrade.vue +++ b/apps/daxpay-admin/src/views/payment/develop/trade/DevelopTrade.vue @@ -1,7 +1,8 @@