|
@@ -294,6 +294,29 @@ async function runTest(sectionId, method, path, body, requireAuth, validatorName
|
|
|
if (durEl) durEl.textContent = result.duration + 'ms';
|
|
if (durEl) durEl.textContent = result.duration + 'ms';
|
|
|
if (rawEl) rawEl.textContent = JSON.stringify(result.data, null, 2);
|
|
if (rawEl) rawEl.textContent = JSON.stringify(result.data, null, 2);
|
|
|
|
|
|
|
|
|
|
+ // 检测响应中的二维码并渲染图片预览
|
|
|
|
|
+ const qrBase64 = result.data?.data?.qrCodeBase64;
|
|
|
|
|
+ let qrBox = document.getElementById(sectionId + '-qrcode');
|
|
|
|
|
+ if (qrBase64) {
|
|
|
|
|
+ if (!qrBox) {
|
|
|
|
|
+ qrBox = document.createElement('div');
|
|
|
|
|
+ qrBox.id = sectionId + '-qrcode';
|
|
|
|
|
+ qrBox.style.cssText = 'text-align:center;padding:12px;background:#fff;border-radius:4px;margin-top:8px;';
|
|
|
|
|
+ rawEl.parentNode.insertBefore(qrBox, rawEl.nextSibling);
|
|
|
|
|
+ }
|
|
|
|
|
+ qrBox.innerHTML = '<img src="' + qrBase64 + '" style="max-width:220px;border:1px solid #eee;border-radius:4px;"><div style="margin-top:6px;font-size:12px;color:#666;">支付二维码(扫码付款后回调自动激活,也可手动确认支付测试回调)</div>';
|
|
|
|
|
+
|
|
|
|
|
+ // 自动回填订单号到相关输入框
|
|
|
|
|
+ const orderNo = result.data?.data?.orderNo;
|
|
|
|
|
+ if (orderNo) {
|
|
|
|
|
+ ['payment-query-order-orderNo', 'payment-mock-pay-orderNo',
|
|
|
|
|
+ 'payment-callback-wechat-out_trade_no', 'payment-callback-alipay-out_trade_no']
|
|
|
|
|
+ .forEach(fid => { const el = document.getElementById(fid); if (el) el.value = orderNo; });
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (qrBox) {
|
|
|
|
|
+ qrBox.remove();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
let passed = false;
|
|
let passed = false;
|
|
|
if (validatorName && typeof window[validatorName] === 'function') {
|
|
if (validatorName && typeof window[validatorName] === 'function') {
|
|
|
try { passed = window[validatorName](result); } catch (e) { passed = false; }
|
|
try { passed = window[validatorName](result); } catch (e) { passed = false; }
|
|
@@ -665,7 +688,7 @@ const FIELD_DESC = {
|
|
|
['createTime', 'DateTime', '创建时间']
|
|
['createTime', 'DateTime', '创建时间']
|
|
|
],
|
|
],
|
|
|
'inviteCode': [
|
|
'inviteCode': [
|
|
|
- ['code', 'String', '邀请码(6位)'],
|
|
|
|
|
|
|
+ ['code', 'String', '邀请码(8位)'],
|
|
|
['inviteLink', 'String', '完整邀请链接'],
|
|
['inviteLink', 'String', '完整邀请链接'],
|
|
|
['inviterNickname', 'String', '邀请人昵称'],
|
|
['inviterNickname', 'String', '邀请人昵称'],
|
|
|
['usedCount', 'Integer', '已使用次数(注册)'],
|
|
['usedCount', 'Integer', '已使用次数(注册)'],
|
|
@@ -852,9 +875,11 @@ const FIELD_DESC = {
|
|
|
],
|
|
],
|
|
|
'inviteConfig': [
|
|
'inviteConfig': [
|
|
|
['id', 'Long', '配置ID'],
|
|
['id', 'Long', '配置ID'],
|
|
|
- ['rewardCrawlerCount', 'Integer', '每次邀请奖励爬虫次数'],
|
|
|
|
|
- ['rewardType', 'String', '奖励类型(CRAWLER_COUNT等)'],
|
|
|
|
|
|
|
+ ['rewardCrawlerCount', 'Integer', '每次邀请奖励爬虫次数(历史字段)'],
|
|
|
|
|
+ ['rewardType', 'String', '奖励类型(MEMBERSHIP等)'],
|
|
|
|
|
+ ['rewardMonths', 'Integer', '邀请人奖励会员时长(月)'],
|
|
|
['maxDailyReward', 'Integer', '每日最大奖励次数'],
|
|
['maxDailyReward', 'Integer', '每日最大奖励次数'],
|
|
|
|
|
+ ['maxTotalInvites', 'Integer', '单个账号总邀请上限(默认30)'],
|
|
|
['inviteCodeExpireDays', 'Integer', '邀请码过期天数'],
|
|
['inviteCodeExpireDays', 'Integer', '邀请码过期天数'],
|
|
|
['maxInvitePerDay', 'Integer', '每日最大邀请数'],
|
|
['maxInvitePerDay', 'Integer', '每日最大邀请数'],
|
|
|
['appDownloadUrl', 'String', 'APP下载地址'],
|
|
['appDownloadUrl', 'String', 'APP下载地址'],
|
|
@@ -1106,6 +1131,8 @@ function renderInviteModule() {
|
|
|
${testSection('invite-stats', '邀请统计', 'GET', 'get', '/api/invite/stats', '需认证', 'auth-required', null, true, 'inviteStats', '获取邀请人数、注册人数、累计奖励等统计')}
|
|
${testSection('invite-stats', '邀请统计', 'GET', 'get', '/api/invite/stats', '需认证', 'auth-required', null, true, 'inviteStats', '获取邀请人数、注册人数、累计奖励等统计')}
|
|
|
${testSection('invite-rewards', '邀请记录', 'GET', 'get', '/api/invite/rewards', '需认证', 'auth-required', null, true, 'inviteReward', '获取邀请记录列表,含被邀请人注册状态')}
|
|
${testSection('invite-rewards', '邀请记录', 'GET', 'get', '/api/invite/rewards', '需认证', 'auth-required', null, true, 'inviteReward', '获取邀请记录列表,含被邀请人注册状态')}
|
|
|
${testSection('invite-extra-quota', '额外配额', 'GET', 'get', '/api/invite/extra-quota', '需认证', 'auth-required', null, false, null, '获取可用额外爬虫次数(邀请奖励+运营发放),返回Integer数值')}
|
|
${testSection('invite-extra-quota', '额外配额', 'GET', 'get', '/api/invite/extra-quota', '需认证', 'auth-required', null, false, null, '获取可用额外爬虫次数(邀请奖励+运营发放),返回Integer数值')}
|
|
|
|
|
+ ${testSection('invite-bind', '补填邀请码', 'POST', 'post', '/api/invite/bind', '需认证', 'auth-required',
|
|
|
|
|
+ [{label:'邀请码/链接(inviteCode)', name:'inviteCode', placeholder:'A3K7M9P2 或 https://app.zhijiayun.com/invite/A3K7M9P2', default:''}], true, null, '注册时未填邀请码,注册后30天内可补填。补填后邀请人获赠1个月高级会员时长')}
|
|
|
${testSection('invite-page', '落地页', 'GET', 'get', '/api/invite/page/{code}?channel=windows', '公开', 'auth-public',
|
|
${testSection('invite-page', '落地页', 'GET', 'get', '/api/invite/page/{code}?channel=windows', '公开', 'auth-public',
|
|
|
[{label:'邀请码(code)', name:'code', placeholder:'输入邀请码', default:''},
|
|
[{label:'邀请码(code)', name:'code', placeholder:'输入邀请码', default:''},
|
|
|
{label:'渠道(channel)', name:'channel', placeholder:'windows/app/wechat/miniapp/dingtalk/feishu', default:'windows'}], true, 'invitePage', '浏览器打开邀请链接时展示的落地页数据,默认渠道为windows(Windows桌面客户端)')}
|
|
{label:'渠道(channel)', name:'channel', placeholder:'windows/app/wechat/miniapp/dingtalk/feishu', default:'windows'}], true, 'invitePage', '浏览器打开邀请链接时展示的落地页数据,默认渠道为windows(Windows桌面客户端)')}
|
|
@@ -1143,21 +1170,21 @@ function renderPaymentModule() {
|
|
|
<div class="batch-buttons">
|
|
<div class="batch-buttons">
|
|
|
<button class="btn btn-warning btn-sm" onclick="runPaymentTests()">运行全部支付模块测试</button>
|
|
<button class="btn btn-warning btn-sm" onclick="runPaymentTests()">运行全部支付模块测试</button>
|
|
|
</div>
|
|
</div>
|
|
|
- ${testSection('payment-plans', '支付方案列表', 'GET', 'get', '/api/payment/plans', '公开', 'auth-public', null, true, null, '获取所有可用的支付方案列表(月卡/季卡/年卡)')}
|
|
|
|
|
|
|
+ ${testSection('payment-plans', '支付方案列表', 'GET', 'get', '/api/payment/plans', '公开', 'auth-public', null, true, null, '获取所有可用的支付方案列表(高级会员月卡/年卡)')}
|
|
|
${testSection('payment-create-order', '创建支付订单', 'POST', 'post', '/api/payment/order/create', '需认证', 'auth-required',
|
|
${testSection('payment-create-order', '创建支付订单', 'POST', 'post', '/api/payment/order/create', '需认证', 'auth-required',
|
|
|
[{label:'方案ID(planId)', name:'planId', placeholder:'1', default:'1'},
|
|
[{label:'方案ID(planId)', name:'planId', placeholder:'1', default:'1'},
|
|
|
- {label:'支付渠道(channel)', name:'channel', placeholder:'WECHAT/ALIPAY', default:'WECHAT'}], true, null, '创建支付订单并返回二维码(qrCodeBase64)和支付链接(payUrl),15分钟内未付款订单自动过期。mock模式返回模拟二维码,生产模式返回真实支付链接')}
|
|
|
|
|
|
|
+ {label:'支付渠道(channel)', name:'channel', placeholder:'WECHAT/ALIPAY', default:'WECHAT'}], true, null, '创建支付订单并返回二维码(qrCodeBase64)和支付链接(payUrl),15分钟内未付款订单自动过期。mock模式返回模拟二维码,真实支付模式返回真实支付链接,也可点击「手动确认支付」按钮测试回调流程')}
|
|
|
${testSection('payment-query-order', '查询订单', 'GET', 'get', '/api/payment/order/{orderNo}', '需认证', 'auth-required',
|
|
${testSection('payment-query-order', '查询订单', 'GET', 'get', '/api/payment/order/{orderNo}', '需认证', 'auth-required',
|
|
|
[{label:'订单号(orderNo)', name:'orderNo', placeholder:'OP...', default:''}], true, null, '根据订单号查询支付订单详情,响应中expireHint含过期提示')}
|
|
[{label:'订单号(orderNo)', name:'orderNo', placeholder:'OP...', default:''}], true, null, '根据订单号查询支付订单详情,响应中expireHint含过期提示')}
|
|
|
${testSection('payment-orders', '我的订单列表', 'GET', 'get', '/api/payment/orders', '需认证', 'auth-required', null, true, null, '查询当前用户的所有支付订单,待支付订单含expireHint过期提示')}
|
|
${testSection('payment-orders', '我的订单列表', 'GET', 'get', '/api/payment/orders', '需认证', 'auth-required', null, true, null, '查询当前用户的所有支付订单,待支付订单含expireHint过期提示')}
|
|
|
- ${testSection('payment-mock-pay', '模拟支付', 'POST', 'post', '/api/payment/order/{orderNo}/pay', '需认证', 'auth-required',
|
|
|
|
|
- [{label:'订单号(orderNo)', name:'orderNo', placeholder:'OP...', default:''}], false, null, '开发环境模拟支付(自动激活会员),需在15分钟过期前操作')}
|
|
|
|
|
|
|
+ ${testSection('payment-mock-pay', '手动确认支付', 'POST', 'post', '/api/payment/order/{orderNo}/pay', '需认证', 'auth-required',
|
|
|
|
|
+ [{label:'订单号(orderNo)', name:'orderNo', placeholder:'OP...', default:''}], false, null, '开发测试用。mock模式=模拟支付自动激活会员;真实支付模式=手动确认支付(不实际扣款,用于测试回调流程)。需在15分钟过期前操作')}
|
|
|
${testSection('payment-callback-wechat', '微信回调', 'POST', 'post', '/api/payment/callback/wechat', '公开', 'auth-public',
|
|
${testSection('payment-callback-wechat', '微信回调', 'POST', 'post', '/api/payment/callback/wechat', '公开', 'auth-public',
|
|
|
[{label:'订单号(out_trade_no)', name:'out_trade_no', placeholder:'OP...', default:''},
|
|
[{label:'订单号(out_trade_no)', name:'out_trade_no', placeholder:'OP...', default:''},
|
|
|
- {label:'交易号(transaction_id,可选)', name:'transaction_id', placeholder:'wx_', default:''}], false, null, '微信支付回调通知。mock模式从参数取订单号,生产模式需验签+解密(API v3)')}
|
|
|
|
|
|
|
+ {label:'交易号(transaction_id,可选)', name:'transaction_id', placeholder:'wx_', default:''}], false, null, '微信支付回调通知。mock模式从参数取订单号,真实支付模式需验签+解密(API v3)')}
|
|
|
${testSection('payment-callback-alipay', '支付宝回调', 'POST', 'post', '/api/payment/callback/alipay', '公开', 'auth-public',
|
|
${testSection('payment-callback-alipay', '支付宝回调', 'POST', 'post', '/api/payment/callback/alipay', '公开', 'auth-public',
|
|
|
[{label:'订单号(out_trade_no)', name:'out_trade_no', placeholder:'OP...', default:''},
|
|
[{label:'订单号(out_trade_no)', name:'out_trade_no', placeholder:'OP...', default:''},
|
|
|
- {label:'交易号(trade_no,可选)', name:'trade_no', placeholder:'2024...', default:''}], false, null, '支付宝回调通知。mock模式从参数取订单号,生产模式需RSA2验签')}`;
|
|
|
|
|
|
|
+ {label:'交易号(trade_no,可选)', name:'trade_no', placeholder:'2024...', default:''}], false, null, '支付宝回调通知。mock模式从参数取订单号,真实支付模式需RSA2验签')}`;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function renderUploadModule() {
|
|
function renderUploadModule() {
|
|
@@ -1263,12 +1290,13 @@ function renderAdminInviteModule() {
|
|
|
${testSection('admin-invite-config', '邀请配置查询', 'GET', 'get', '/api/admin/invite/config', '需认证', 'auth-required', null, true, 'inviteConfig', '获取当前激活的邀请配置')}
|
|
${testSection('admin-invite-config', '邀请配置查询', 'GET', 'get', '/api/admin/invite/config', '需认证', 'auth-required', null, true, 'inviteConfig', '获取当前激活的邀请配置')}
|
|
|
${testSection('admin-invite-configs', '全部邀请配置', 'GET', 'get', '/api/admin/invite/configs', '需认证', 'auth-required', null, true, 'inviteConfig', '获取所有邀请配置历史记录')}
|
|
${testSection('admin-invite-configs', '全部邀请配置', 'GET', 'get', '/api/admin/invite/configs', '需认证', 'auth-required', null, true, 'inviteConfig', '获取所有邀请配置历史记录')}
|
|
|
${testSection('admin-invite-config-update', '更新邀请配置', 'PUT', 'put', '/api/admin/invite/config', '需认证', 'auth-required',
|
|
${testSection('admin-invite-config-update', '更新邀请配置', 'PUT', 'put', '/api/admin/invite/config', '需认证', 'auth-required',
|
|
|
- [{label:'奖励次数(rewardCrawlerCount)', name:'rewardCrawlerCount', placeholder:'5', default:'5'},
|
|
|
|
|
|
|
+ [{label:'奖励月数(rewardMonths)', name:'rewardMonths', placeholder:'1', default:'1'},
|
|
|
|
|
+ {label:'总邀请上限(maxTotalInvites)', name:'maxTotalInvites', placeholder:'30', default:'30'},
|
|
|
{label:'日奖励上限(maxDailyReward)', name:'maxDailyReward', placeholder:'50', default:'50'},
|
|
{label:'日奖励上限(maxDailyReward)', name:'maxDailyReward', placeholder:'50', default:'50'},
|
|
|
{label:'邀请码过期天(inviteCodeExpireDays)', name:'inviteCodeExpireDays', placeholder:'30', default:'30'},
|
|
{label:'邀请码过期天(inviteCodeExpireDays)', name:'inviteCodeExpireDays', placeholder:'30', default:'30'},
|
|
|
{label:'日邀请上限(maxInvitePerDay)', name:'maxInvitePerDay', placeholder:'10', default:'10'},
|
|
{label:'日邀请上限(maxInvitePerDay)', name:'maxInvitePerDay', placeholder:'10', default:'10'},
|
|
|
{label:'APP下载URL(appDownloadUrl)', name:'appDownloadUrl', placeholder:'https://...', default:'https://download.example.com/app.exe'},
|
|
{label:'APP下载URL(appDownloadUrl)', name:'appDownloadUrl', placeholder:'https://...', default:'https://download.example.com/app.exe'},
|
|
|
- {label:'落地页标题(landingTitle)', name:'landingTitle', placeholder:'标题', default:'邀请你加入智价云药店'}], false, 'inviteConfig', '更新邀请配置参数')}
|
|
|
|
|
|
|
+ {label:'落地页标题(landingTitle)', name:'landingTitle', placeholder:'标题', default:'邀请你加入智价云药店'}], false, 'inviteConfig', '更新邀请配置参数,rewardMonths=邀请人每次获赠高级会员月数,maxTotalInvites=单个账号总邀请上限')}
|
|
|
${testSection('admin-invite-rewards', '邀请记录查询', 'GET', 'get', '/api/admin/invite/rewards?userId=1', '需认证', 'auth-required', null, true, 'inviteReward', '查看指定用户的邀请奖励记录')}
|
|
${testSection('admin-invite-rewards', '邀请记录查询', 'GET', 'get', '/api/admin/invite/rewards?userId=1', '需认证', 'auth-required', null, true, 'inviteReward', '查看指定用户的邀请奖励记录')}
|
|
|
${testSection('admin-invite-conversion', '邀请转化统计', 'GET', 'get', '/api/admin/invite/conversion-stats?userId=1', '需认证', 'auth-required', null, true, 'conversionStats', '查看用户邀请点击-注册转化率')}`;
|
|
${testSection('admin-invite-conversion', '邀请转化统计', 'GET', 'get', '/api/admin/invite/conversion-stats?userId=1', '需认证', 'auth-required', null, true, 'conversionStats', '查看用户邀请点击-注册转化率')}`;
|
|
|
}
|
|
}
|
|
@@ -1572,7 +1600,7 @@ function validate_adminAuditTarget(result) { return result.data?.code === 200 &&
|
|
|
function validate_adminAuditStats(result) { return result.data?.code === 200; }
|
|
function validate_adminAuditStats(result) { return result.data?.code === 200; }
|
|
|
|
|
|
|
|
// 支付模块验证器
|
|
// 支付模块验证器
|
|
|
-function validate_paymentPlans(result) { return result.data?.code === 200 && Array.isArray(result.data?.data) && result.data?.data?.length >= 3; }
|
|
|
|
|
|
|
+function validate_paymentPlans(result) { return result.data?.code === 200 && Array.isArray(result.data?.data) && result.data?.data?.length >= 2; }
|
|
|
function validate_paymentOrders(result) { return result.data?.code === 200 && Array.isArray(result.data?.data); }
|
|
function validate_paymentOrders(result) { return result.data?.code === 200 && Array.isArray(result.data?.data); }
|
|
|
function validate_searchQuery(result) { return result.data?.code === 200 && result.data?.data?.prices !== undefined; }
|
|
function validate_searchQuery(result) { return result.data?.code === 200 && result.data?.data?.prices !== undefined; }
|
|
|
function validate_searchSuggestions(result) { return result.data?.code === 200 && Array.isArray(result.data?.data) && result.data?.data?.length > 0; }
|
|
function validate_searchSuggestions(result) { return result.data?.code === 200 && Array.isArray(result.data?.data) && result.data?.data?.length > 0; }
|