|
|
@@ -249,10 +249,9 @@
|
|
|
<div class="module-tab" data-module="admin-license">5.入驻信息审核</div>
|
|
|
<div class="module-tab" data-module="admin-payment">6.支付方案</div>
|
|
|
<div class="module-tab" data-module="admin-anxin">7.安心付管理</div>
|
|
|
- <div class="module-tab" data-module="admin-trial-quota">8.体验配额</div>
|
|
|
- <div class="module-tab" data-module="admin-user">9.用户管理</div>
|
|
|
- <div class="module-tab" data-module="admin-audit">10.审计日志</div>
|
|
|
- <div class="module-tab" data-module="upload">11.文件上传</div>
|
|
|
+ <div class="module-tab" data-module="admin-user">8.用户管理</div>
|
|
|
+ <div class="module-tab" data-module="admin-audit">9.审计日志</div>
|
|
|
+ <div class="module-tab" data-module="upload">10.文件上传</div>
|
|
|
</div>
|
|
|
|
|
|
<div id="panels"></div>
|
|
|
@@ -371,6 +370,26 @@ async function runTest(sectionId, method, path, body, requireAuth, validatorName
|
|
|
.forEach(fid => { const el = document.getElementById(fid); if (el) el.value = anxinCardId; });
|
|
|
}
|
|
|
|
|
|
+ // 自动更新Token:登录/刷新Token/心跳等接口返回新accessToken时,回填到当前侧Token输入框
|
|
|
+ // 避免后续需认证测试使用过期Token而失败
|
|
|
+ const newAccessToken = result.data?.data?.accessToken;
|
|
|
+ if (newAccessToken) {
|
|
|
+ if (activeSide === 'admin') {
|
|
|
+ const adminTokenEl = document.getElementById('adminToken');
|
|
|
+ if (adminTokenEl) adminTokenEl.value = newAccessToken;
|
|
|
+ } else {
|
|
|
+ const tokenEl = document.getElementById('token');
|
|
|
+ if (tokenEl) tokenEl.value = newAccessToken;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 自动回填refreshToken到刷新Token测试输入框(登录/心跳等接口返回refreshToken时)
|
|
|
+ const newRefreshToken = result.data?.data?.refreshToken;
|
|
|
+ if (newRefreshToken) {
|
|
|
+ const refreshEl = document.getElementById('auth-refresh-refreshToken');
|
|
|
+ if (refreshEl) refreshEl.value = newRefreshToken;
|
|
|
+ }
|
|
|
+
|
|
|
if (channel === 'ALIPAY' && qrBase64) {
|
|
|
// 支付宝:DeepSeek 风格自定义弹窗,展示二维码
|
|
|
showAlipayModal(qrBase64, amount, orderNo);
|
|
|
@@ -664,48 +683,60 @@ document.getElementById('adminModuleTabs').addEventListener('click', (e) => {
|
|
|
renderModule(e.target.dataset.module);
|
|
|
});
|
|
|
|
|
|
-// ===================== 渲染模块面板 =====================
|
|
|
+// ===================== 渲染模块面板(持久化:切换tab不丢失测试结果)=====================
|
|
|
+const renderedModules = new Set();
|
|
|
function renderModule(module) {
|
|
|
const panels = document.getElementById('panels');
|
|
|
- let html = '';
|
|
|
- switch (module) {
|
|
|
- // 用户侧模块
|
|
|
- case 'auth': html = renderAuthModule(); break;
|
|
|
- case 'crawler': html = renderCrawlerModule(); break;
|
|
|
- case 'invite': html = renderInviteModule(); break;
|
|
|
- case 'coupon': html = renderCouponModule(); break;
|
|
|
- case 'membership': html = renderMembershipModule(); break;
|
|
|
- case 'payment': html = renderPaymentModule(); break;
|
|
|
- case 'watchlist': html = renderWatchlistModule(); break;
|
|
|
- case 'trial-quota': html = renderTrialQuotaModule(); break;
|
|
|
- case 'upload': html = renderUploadModule(); break;
|
|
|
- case 'search': html = renderSearchModule(); break;
|
|
|
- case 'platform-account': html = renderPlatformAccountModule(); break;
|
|
|
- case 'business-license': html = renderBusinessLicenseModule(); break;
|
|
|
- case 'platform-config': html = renderPlatformConfigModule(); break;
|
|
|
- case 'search-record': html = renderSearchRecordModule(); break;
|
|
|
- case 'platform-session': html = renderPlatformSessionModule(); break;
|
|
|
- case 'content': html = renderContentModule(); break;
|
|
|
- case 'procurement-ledger': html = renderProcurementLedgerModule(); break;
|
|
|
- case 'purchase-intent': html = renderPurchaseIntentModule(); break;
|
|
|
- // 运营侧模块
|
|
|
- case 'admin-membership': html = renderAdminMembershipModule(); break;
|
|
|
- case 'admin-invite': html = renderAdminInviteModule(); break;
|
|
|
- case 'admin-crawler': html = renderAdminCrawlerModule(); break;
|
|
|
- case 'admin-coupon': html = renderAdminCouponModule(); break;
|
|
|
- case 'admin-license': html = renderAdminLicenseModule(); break;
|
|
|
- case 'admin-payment': html = renderAdminPaymentModule(); break;
|
|
|
- case 'admin-anxin': html = renderAdminAnxinModule(); break;
|
|
|
- case 'admin-trial-quota': html = renderAdminTrialQuotaModule(); break;
|
|
|
- case 'admin-user': html = renderAdminUserModule(); break;
|
|
|
- case 'admin-audit': html = renderAdminAuditModule(); break;
|
|
|
+ // 隐藏所有已渲染的模块面板
|
|
|
+ panels.querySelectorAll('.module-panel').forEach(p => p.style.display = 'none');
|
|
|
+ // 若该模块尚未渲染过,则创建并插入
|
|
|
+ let panel = document.getElementById('panel-' + module);
|
|
|
+ if (!panel) {
|
|
|
+ let html = '';
|
|
|
+ switch (module) {
|
|
|
+ // 用户侧模块
|
|
|
+ case 'auth': html = renderAuthModule(); break;
|
|
|
+ case 'crawler': html = renderCrawlerModule(); break;
|
|
|
+ case 'invite': html = renderInviteModule(); break;
|
|
|
+ case 'coupon': html = renderCouponModule(); break;
|
|
|
+ case 'membership': html = renderMembershipModule(); break;
|
|
|
+ case 'payment': html = renderPaymentModule(); break;
|
|
|
+ case 'watchlist': html = renderWatchlistModule(); break;
|
|
|
+ case 'upload': html = renderUploadModule(); break;
|
|
|
+ case 'search': html = renderSearchModule(); break;
|
|
|
+ case 'platform-account': html = renderPlatformAccountModule(); break;
|
|
|
+ case 'business-license': html = renderBusinessLicenseModule(); break;
|
|
|
+ case 'platform-config': html = renderPlatformConfigModule(); break;
|
|
|
+ case 'search-record': html = renderSearchRecordModule(); break;
|
|
|
+ case 'platform-session': html = renderPlatformSessionModule(); break;
|
|
|
+ case 'content': html = renderContentModule(); break;
|
|
|
+ case 'procurement-ledger': html = renderProcurementLedgerModule(); break;
|
|
|
+ case 'purchase-intent': html = renderPurchaseIntentModule(); break;
|
|
|
+ // 运营侧模块
|
|
|
+ case 'admin-membership': html = renderAdminMembershipModule(); break;
|
|
|
+ case 'admin-invite': html = renderAdminInviteModule(); break;
|
|
|
+ case 'admin-crawler': html = renderAdminCrawlerModule(); break;
|
|
|
+ case 'admin-coupon': html = renderAdminCouponModule(); break;
|
|
|
+ case 'admin-license': html = renderAdminLicenseModule(); break;
|
|
|
+ case 'admin-payment': html = renderAdminPaymentModule(); break;
|
|
|
+ case 'admin-anxin': html = renderAdminAnxinModule(); break;
|
|
|
+ case 'admin-user': html = renderAdminUserModule(); break;
|
|
|
+ case 'admin-audit': html = renderAdminAuditModule(); break;
|
|
|
+ }
|
|
|
+ panel = document.createElement('div');
|
|
|
+ panel.id = 'panel-' + module;
|
|
|
+ panel.className = 'module-panel';
|
|
|
+ panel.innerHTML = html;
|
|
|
+ panels.appendChild(panel);
|
|
|
+ renderedModules.add(module);
|
|
|
+ // 修复含引号的默认值:从 data-raw 属性恢复正确的 input value
|
|
|
+ panel.querySelectorAll('input[data-raw]').forEach(input => {
|
|
|
+ input.value = input.getAttribute('data-raw');
|
|
|
+ input.removeAttribute('data-raw');
|
|
|
+ });
|
|
|
}
|
|
|
- panels.innerHTML = html;
|
|
|
- // 修复含引号的默认值:从 data-raw 属性恢复正确的 input value
|
|
|
- panels.querySelectorAll('input[data-raw]').forEach(input => {
|
|
|
- input.value = input.getAttribute('data-raw');
|
|
|
- input.removeAttribute('data-raw');
|
|
|
- });
|
|
|
+ // 显示当前模块面板
|
|
|
+ panel.style.display = '';
|
|
|
}
|
|
|
|
|
|
function toValidatorName(id) {
|
|
|
@@ -1507,16 +1538,6 @@ function renderWatchlistModule() {
|
|
|
${testSection('watchlist-stats', '关注统计', 'GET', 'get', '/api/watchlist/stats', '需认证', 'auth-required', null, true, null, '获取关注统计信息')}`;
|
|
|
}
|
|
|
|
|
|
-function renderTrialQuotaModule() {
|
|
|
- return `
|
|
|
- <div class="batch-buttons">
|
|
|
- <button class="btn btn-warning btn-sm" onclick="runTrialQuotaTests()">运行全部体验配额测试</button>
|
|
|
- </div>
|
|
|
- ${testSection('trial-quota-active', '生效中的体验配额', 'GET', 'get', '/api/trial-quota/active', '公开', 'auth-public', null, true, 'trialQuotaConfig', '查询当前生效的体验配额配置')}`;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
function renderPaymentModule() {
|
|
|
return `
|
|
|
<div class="batch-buttons">
|
|
|
@@ -1927,28 +1948,6 @@ function renderAdminAnxinModule() {
|
|
|
|
|
|
|
|
|
|
|
|
-function renderAdminTrialQuotaModule() {
|
|
|
- return `
|
|
|
- <div class="batch-buttons"><button class="btn btn-warning btn-sm" onclick="runAdminTrialQuotaTests()">运行全部体验配额测试</button></div>
|
|
|
- ${testSection('admin-tq-active', '当前体验配置', 'GET', 'get', '/api/trial-quota/active', '公开', 'auth-public', null, true, 'trialQuota', '获取当前激活的体验配额配置')}
|
|
|
- ${testSection('admin-tq-list', '所有配置', 'GET', 'get', '/api/admin/trial-quota/configs', '需认证', 'auth-required', null, true, 'trialQuota', '查询所有体验配额配置列表')}
|
|
|
- ${testSection('admin-tq-create', '创建配置', 'POST', 'post', '/api/admin/trial-quota/config', '需认证', 'auth-required',
|
|
|
- [{label:'配置名称(configName)', name:'configName', placeholder:'新用户默认体验', default:'测试体验配置'},
|
|
|
- {label:'体验天数(trialDays)', name:'trialDays', placeholder:'15', default:'15'},
|
|
|
- {label:'日查询限制(dailyQueryLimit)', name:'dailyQueryLimit', placeholder:'20', default:'20'},
|
|
|
- {label:'月关注限制(monthlyWatchlistLimit)', name:'monthlyWatchlistLimit', placeholder:'199', default:'199'},
|
|
|
- {label:'配置类型(configType)', name:'configType', placeholder:'DEFAULT', default:'DEFAULT'},
|
|
|
- {label:'用户类型(applicableUserType)', name:'applicableUserType', placeholder:'NEW_USER', default:'NEW_USER'}], false, 'trialQuota', '创建新的体验配额配置')}
|
|
|
- ${testSection('admin-tq-update', '更新配置', 'PUT', 'put', '/api/admin/trial-quota/config/{id}', '需认证', 'auth-required',
|
|
|
- [{label:'配置ID(id)', name:'id', placeholder:'1', default:'1'},
|
|
|
- {label:'配置名称(configName)', name:'configName', placeholder:'更新后名称', default:'更新后的体验配置'},
|
|
|
- {label:'体验天数(trialDays)', name:'trialDays', placeholder:'30', default:'30'},
|
|
|
- {label:'日查询限制(dailyQueryLimit)', name:'dailyQueryLimit', placeholder:'50', default:'50'},
|
|
|
- {label:'月关注限制(monthlyWatchlistLimit)', name:'monthlyWatchlistLimit', placeholder:'199', default:'199'}], false, 'trialQuota', '更新指定体验配额配置')}
|
|
|
- ${testSection('admin-tq-delete', '删除配置', 'DELETE', 'delete', '/api/admin/trial-quota/config/{id}', '需认证', 'auth-required',
|
|
|
- [{label:'配置ID(id)', name:'id', placeholder:'1', default:'1'}], false, null, '删除指定体验配额配置')}`;
|
|
|
-}
|
|
|
-
|
|
|
function renderAdminUserModule() {
|
|
|
return `
|
|
|
<div class="batch-buttons"><button class="btn btn-warning btn-sm" onclick="runAdminUserTests()">运行全部用户管理测试</button></div>
|
|
|
@@ -1958,9 +1957,6 @@ function renderAdminUserModule() {
|
|
|
{label:'手机号(phone)', name:'phone', placeholder:'138', default:''},
|
|
|
{label:'昵称(nickname)', name:'nickname', placeholder:'测试', default:''}], true, null, '查询前端注册用户列表(仅USER角色)')}
|
|
|
${testSection('admin-admins-list', '管理员列表', 'GET', 'get', '/api/admin/admins?page=1&size=10', '需认证', 'auth-required', null, true, null, '查询管理员列表(t_admin表)')}
|
|
|
- ${testSection('admin-user-role', '修改用户角色', 'PUT', 'put', '/api/admin/users/{userId}/role', '需认证', 'auth-required',
|
|
|
- [{label:'用户ID(userId)', name:'userId', placeholder:'1', default:'1'},
|
|
|
- {label:'目标角色(role)', name:'role', placeholder:'ADMIN/SUPER_ADMIN/USER', default:'ADMIN'}], false, null, '升级用户为管理员(写入t_admin)/ 降级管理员为用户(删除t_admin记录)')}
|
|
|
${testSection('admin-user-kick', '强制踢出用户', 'POST', 'post', '/api/admin/users/{userId}/kick', '需认证', 'auth-required',
|
|
|
[{label:'用户ID(userId)', name:'userId', placeholder:'1', default:'1'}], false, null, '强制踢出前端用户:递增tokenVersion+清空RefreshToken')}
|
|
|
${testSection('admin-admin-kick', '强制踢出管理员', 'POST', 'post', '/api/admin/admins/{adminId}/kick', '需认证', 'auth-required',
|
|
|
@@ -2011,8 +2007,8 @@ function getSectionsInModule(modulePrefix) {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
-const USER_MODULES = ['auth','crawler','invite','coupon','membership','payment','upload','search','platform-account','business-license','platform-config','search-record','platform-session','watchlist','trial-quota','content','procurement-ledger','purchase-intent'];
|
|
|
-const ADMIN_MODULES = ['admin-membership','admin-invite','admin-crawler','admin-coupon','admin-license','admin-payment','admin-anxin','admin-trial-quota','admin-user','admin-audit','upload'];
|
|
|
+const USER_MODULES = ['auth','crawler','invite','coupon','membership','payment','upload','search','platform-account','business-license','platform-config','search-record','platform-session','watchlist','content','procurement-ledger','purchase-intent'];
|
|
|
+const ADMIN_MODULES = ['admin-membership','admin-invite','admin-crawler','admin-coupon','admin-license','admin-payment','admin-anxin','admin-user','admin-audit','upload'];
|
|
|
|
|
|
function countTestsInCurrentPanel() {
|
|
|
return document.querySelectorAll('.test-section button[onclick*="runTest"]').length;
|
|
|
@@ -2043,37 +2039,87 @@ async function runBatchTests(modulePrefix) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-async function runAllTests() {
|
|
|
- resetStats();
|
|
|
- // 先遍历用户侧模块
|
|
|
- for (const m of USER_MODULES) {
|
|
|
- const tab = document.querySelector(`#moduleTabs .module-tab[data-module="${m}"]`);
|
|
|
- if (tab) tab.click();
|
|
|
- await new Promise(r => setTimeout(r, 50));
|
|
|
- stats.total += countTestsInCurrentPanel();
|
|
|
- }
|
|
|
- // 再遍历运营侧模块
|
|
|
- for (const m of ADMIN_MODULES) {
|
|
|
- const tab = document.querySelector(`#adminModuleTabs .module-tab[data-module="${m}"]`);
|
|
|
- if (tab) tab.click();
|
|
|
- await new Promise(r => setTimeout(r, 50));
|
|
|
- stats.total += countTestsInCurrentPanel();
|
|
|
+// 按指定测试ID顺序执行批量测试(用于一键测试时控制破坏性操作顺序)
|
|
|
+async function runBatchTestsOrdered(testIds) {
|
|
|
+ // 将尚未运行过的测试计入total
|
|
|
+ for (const id of testIds) {
|
|
|
+ if (!stats.hasOwnProperty(id)) stats.total++;
|
|
|
}
|
|
|
+ stats.pending = Math.max(0, stats.total - stats.pass - stats.fail);
|
|
|
document.getElementById('totalCount').textContent = stats.total;
|
|
|
- stats.pending = stats.total;
|
|
|
document.getElementById('pendingCount').textContent = stats.pending;
|
|
|
- // 逐模块执行 - 用户侧
|
|
|
+ for (const id of testIds) {
|
|
|
+ const btn = document.querySelector(`button[onclick*="runTest('${id}'"]`);
|
|
|
+ if (btn) {
|
|
|
+ btn.click();
|
|
|
+ await new Promise(r => setTimeout(r, 600));
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 认证模块主流程测试顺序:登录类在前,只读查询类居中,刷新Token/心跳居后
|
|
|
+// 跳过破坏性操作(登出/设置密码/修改手机号/注册),确保主流程接口能正常返回数据
|
|
|
+const AUTH_TEST_ORDER = [
|
|
|
+ 'auth-send', 'auth-smslogin', 'auth-pwdlogin',
|
|
|
+ 'auth-wechat-url', 'auth-wechat-login', 'auth-wechat-callback',
|
|
|
+ 'auth-userinfo', 'auth-user-me', 'auth-dashboard',
|
|
|
+ 'auth-heartbeat', 'auth-refresh'
|
|
|
+];
|
|
|
+
|
|
|
+async function runAllTests() {
|
|
|
+ resetStats();
|
|
|
+ stopAlipayPolling();
|
|
|
+ closeAlipayModal();
|
|
|
+
|
|
|
+ // ===== 第一步:用户侧 - 先登录确保Token有效(直接调用API建立登录态,不触发测试统计和弹窗)=====
|
|
|
switchSide('user');
|
|
|
+ await new Promise(r => setTimeout(r, 100));
|
|
|
+ {
|
|
|
+ // 发送验证码
|
|
|
+ await api('POST', '/api/auth/sms/send', { phone: PHONE(), scene: 'login' }, false);
|
|
|
+ await new Promise(r => setTimeout(r, 500));
|
|
|
+ // 短信登录
|
|
|
+ const loginRes = await api('POST', '/api/auth/sms/login', { phone: PHONE(), code: SMS_CODE(), scene: 'login' }, false);
|
|
|
+ if (loginRes.data?.code === 200 && loginRes.data?.data?.accessToken) {
|
|
|
+ document.getElementById('token').value = loginRes.data.data.accessToken;
|
|
|
+ updateRoleBadge(loginRes.data.data.role);
|
|
|
+ // 回填refreshToken供后续刷新Token测试使用
|
|
|
+ if (loginRes.data.data.refreshToken) {
|
|
|
+ const refreshEl = document.getElementById('auth-refresh-refreshToken');
|
|
|
+ if (refreshEl) refreshEl.value = loginRes.data.data.refreshToken;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // ===== 第二步:逐模块执行用户侧测试(各模块自行统计测试数量,避免重复计数)=====
|
|
|
for (const m of USER_MODULES) {
|
|
|
try {
|
|
|
const tab = document.querySelector(`#moduleTabs .module-tab[data-module="${m}"]`);
|
|
|
if (tab) tab.click();
|
|
|
await new Promise(r => setTimeout(r, 100));
|
|
|
- await runBatchTests(m);
|
|
|
+ if (m === 'auth') {
|
|
|
+ // 认证模块按主流程顺序执行:登录类→只读查询→刷新Token/心跳(跳过登出等破坏性操作)
|
|
|
+ await runBatchTestsOrdered(AUTH_TEST_ORDER);
|
|
|
+ } else {
|
|
|
+ await runBatchTests(m);
|
|
|
+ }
|
|
|
} catch (e) { console.error('模块 ' + m + ' 测试出错:', e); }
|
|
|
}
|
|
|
- // 逐模块执行 - 运营侧
|
|
|
+
|
|
|
+ // ===== 第三步:运营侧 - 先管理员登录确保Token有效(直接调用API建立登录态,不触发测试统计和弹窗)=====
|
|
|
switchSide('admin');
|
|
|
+ await new Promise(r => setTimeout(r, 100));
|
|
|
+ {
|
|
|
+ const adminUsername = document.getElementById('adminPwdUsername')?.value || 'admin';
|
|
|
+ const adminPassword = document.getElementById('adminPwdPassword')?.value || 'admin@123';
|
|
|
+ const adminLoginRes = await api('POST', '/api/admin/auth/login', { username: adminUsername, password: adminPassword }, false);
|
|
|
+ if (adminLoginRes.data?.code === 200 && adminLoginRes.data?.data?.accessToken) {
|
|
|
+ document.getElementById('adminToken').value = adminLoginRes.data.data.accessToken;
|
|
|
+ updateAdminRoleBadge(adminLoginRes.data.data.role);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // ===== 第四步:逐模块执行运营侧测试 =====
|
|
|
for (const m of ADMIN_MODULES) {
|
|
|
try {
|
|
|
const tab = document.querySelector(`#adminModuleTabs .module-tab[data-module="${m}"]`);
|
|
|
@@ -2106,6 +2152,7 @@ function clearAllResults() {
|
|
|
closeAlipayModal();
|
|
|
document.querySelectorAll('.response-box').forEach(b => b.style.display = 'none');
|
|
|
document.querySelectorAll('.status-badge').forEach(b => { b.textContent = ''; b.className = 'status-badge'; });
|
|
|
+ document.querySelectorAll('.response-content').forEach(b => b.textContent = '');
|
|
|
resetStats();
|
|
|
}
|
|
|
|
|
|
@@ -2188,7 +2235,6 @@ function runBusinessLicenseTests() { runBatchTests('bl'); }
|
|
|
function runPlatformConfigTests() { runBatchTests('pc'); }
|
|
|
function runSearchRecordTests() { runBatchTests('sr'); }
|
|
|
function runPlatformSessionTests() { runBatchTests('ps'); }function runWatchlistTests() { runBatchTests('watchlist'); }
|
|
|
-function runTrialQuotaTests() { runBatchTests('trial-quota'); }
|
|
|
function runContentTests() { runBatchTests('content'); }
|
|
|
function runProcurementLedgerTests() { runBatchTests('pl'); }
|
|
|
function runPurchaseIntentTests() { runBatchTests('pi'); }
|
|
|
@@ -2200,7 +2246,6 @@ function runAdminCouponTests() { runBatchTests('admin-coupon'); }
|
|
|
function runAdminLicenseTests() { runBatchTests('admin-license'); }
|
|
|
function runAdminPaymentTests() { runBatchTests('admin-payment'); }
|
|
|
function runAdminAnxinTests() { runBatchTests('admin-anxin'); }
|
|
|
-function runAdminTrialQuotaTests() { runBatchTests('admin-tq'); }
|
|
|
function runAdminUserTests() { runBatchTests('admin-user'); }
|
|
|
function runAdminAuditTests() { runBatchTests('admin-audit'); }
|
|
|
|