stgl-api-test.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. /**
  2. * 社团管理系统API测试脚本
  3. *
  4. * 功能说明:
  5. * 1. 社团信息管理 - 增删改查、状态管理、权限验证
  6. * 2. 社团成员管理 - 成员添加、角色管理、退出处理
  7. * 3. 社团报名大厅 - 浏览社团、报名加入、我的社团
  8. *
  9. * 测试环境配置:
  10. * - 服务器地址:http://localhost:8080
  11. * - 加密登录:AES+RSA双重加密
  12. * - 权限验证:Sa-Token
  13. *
  14. * 运行方法:
  15. * npm install axios crypto
  16. * node stgl-api-test.js
  17. *
  18. * @author Cursor AI
  19. * @date 2025-01-15
  20. * @version 1.0
  21. */
  22. const axios = require('axios');
  23. const crypto = require('crypto');
  24. // ============================== 配置信息 ==============================
  25. const CONFIG = {
  26. BASE_URL: 'http://localhost:8080',
  27. TIMEOUT: 30000,
  28. // 测试用户配置
  29. TEST_USER: {
  30. username: 'admin',
  31. password: 'admin123',
  32. clientid: 'e5cd7e4891bf95d1d19206ce24a7b32e',
  33. referer: 'http://localhost'
  34. },
  35. // AES加密密钥(16位)
  36. AES_SECRET_KEY: '1234567890123456',
  37. // RSA公钥
  38. RSA_PUBLIC_KEY: `-----BEGIN PUBLIC KEY-----
  39. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7zL3w8s0LnG7yMrp9fGU+ZOwS
  40. Wd3g0CqX8nfF5qSZQ7GNcN8L3HS9N3jQKLdFy/9bTQJb8KcV3hxGJEGZ5cV3zqJf
  41. oX5x7N8sGZHtQzN5pG4qqGt8M2QlGbFQNQXxZ8HwJj8yGjQl7Z7gN3Z7yKd1J3M2
  42. 5fX3Q2mFtGzP8KGc8QIDAQAB
  43. -----END PUBLIC KEY-----`
  44. };
  45. // ============================== 工具函数 ==============================
  46. // AES加密函数
  47. function aesEncrypt(text, key) {
  48. const cipher = crypto.createCipher('aes-128-ecb', key);
  49. let encrypted = cipher.update(text, 'utf8', 'hex');
  50. encrypted += cipher.final('hex');
  51. return encrypted;
  52. }
  53. // RSA加密函数
  54. function rsaEncrypt(text, publicKey) {
  55. const buffer = Buffer.from(text, 'utf8');
  56. const encrypted = crypto.publicEncrypt({
  57. key: publicKey,
  58. padding: crypto.constants.RSA_PKCS1_PADDING
  59. }, buffer);
  60. return encrypted.toString('base64');
  61. }
  62. // HTTP请求封装
  63. const request = axios.create({
  64. baseURL: CONFIG.BASE_URL,
  65. timeout: CONFIG.TIMEOUT,
  66. headers: {
  67. 'Content-Type': 'application/json',
  68. 'clientid': CONFIG.TEST_USER.clientid,
  69. 'referer': CONFIG.TEST_USER.referer
  70. }
  71. });
  72. // 全局变量
  73. let authToken = '';
  74. let testData = {
  75. clubId: null,
  76. memberId: null,
  77. userIds: []
  78. };
  79. // ============================== 认证相关 ==============================
  80. /**
  81. * 用户登录(AES+RSA双重加密)
  82. */
  83. async function login() {
  84. console.log('\n🔐 开始用户登录...');
  85. try {
  86. // 第一步:AES加密用户名和密码
  87. const aesUsername = aesEncrypt(CONFIG.TEST_USER.username, CONFIG.AES_SECRET_KEY);
  88. const aesPassword = aesEncrypt(CONFIG.TEST_USER.password, CONFIG.AES_SECRET_KEY);
  89. // 第二步:RSA加密AES密钥
  90. const rsaKey = rsaEncrypt(CONFIG.AES_SECRET_KEY, CONFIG.RSA_PUBLIC_KEY);
  91. // 第三步:发送登录请求
  92. const response = await request.post('/auth/login', {
  93. username: aesUsername,
  94. password: aesPassword,
  95. key: rsaKey,
  96. captcha: '',
  97. uuid: ''
  98. });
  99. if (response.data.code === 200) {
  100. authToken = response.data.data.access_token;
  101. request.defaults.headers['Authorization'] = `Bearer ${authToken}`;
  102. console.log('✅ 登录成功');
  103. console.log(`🔑 Token: ${authToken.substring(0, 50)}...`);
  104. return true;
  105. } else {
  106. console.error('❌ 登录失败:', response.data.msg);
  107. return false;
  108. }
  109. } catch (error) {
  110. console.error('❌ 登录请求失败:', error.message);
  111. return false;
  112. }
  113. }
  114. // ============================== 社团信息管理API测试 ==============================
  115. /**
  116. * 测试社团信息管理功能
  117. */
  118. async function testClubManagement() {
  119. console.log('\n📋 ========== 社团信息管理API测试 ==========');
  120. // 1. 查询社团列表
  121. await testAPI('GET', '/stgl/club/list', {
  122. pageNum: 1,
  123. pageSize: 10
  124. }, '查询社团列表');
  125. // 2. 新增社团
  126. const clubData = {
  127. clubName: '智能科技社团',
  128. clubType: '学术科技类',
  129. establishDate: '2025-01-15',
  130. description: '专注于人工智能、机器学习等前沿科技领域的学术研究和实践交流社团',
  131. email: 'aitech@example.com',
  132. phone: '028-12345678',
  133. presidentName: '张三',
  134. presidentStudentNo: '20250001',
  135. presidentDept: '计算机学院',
  136. presidentMajor: '软件工程',
  137. presidentClass: '软工2501班',
  138. presidentPhone: '13800138001',
  139. advisorName: '李教授',
  140. advisorDept: '计算机学院',
  141. memberLimit: 50,
  142. recruitCycle: '每学期',
  143. recruitTime: '9月、3月',
  144. activityFrequency: '每周1-2次',
  145. fundingSources: '学校拨款,社团自筹',
  146. status: 1
  147. };
  148. const createResult = await testAPI('POST', '/stgl/club', clubData, '新增社团');
  149. if (createResult) {
  150. // 获取创建的社团ID
  151. const listResult = await testAPI('GET', '/stgl/club/list', {
  152. clubName: clubData.clubName
  153. }, '查询新建社团ID');
  154. if (listResult && listResult.data.rows.length > 0) {
  155. testData.clubId = listResult.data.rows[0].id;
  156. console.log(`🆔 获取到社团ID: ${testData.clubId}`);
  157. }
  158. }
  159. // 3. 查询社团详情
  160. if (testData.clubId) {
  161. await testAPI('GET', `/stgl/club/${testData.clubId}`, {}, '查询社团详情');
  162. }
  163. // 4. 修改社团信息
  164. if (testData.clubId) {
  165. await testAPI('PUT', '/stgl/club', {
  166. id: testData.clubId,
  167. clubName: '智能科技社团(更新版)',
  168. memberLimit: 60
  169. }, '修改社团信息');
  170. }
  171. // 5. 查询可用社团选项
  172. await testAPI('GET', '/stgl/club/options', {}, '查询可用社团选项');
  173. // 6. 检查社团名称唯一性
  174. await testAPI('GET', '/stgl/club/checkClubNameUnique', {
  175. clubName: '不存在的社团名称'
  176. }, '检查社团名称唯一性');
  177. // 7. 查询我管理的社团
  178. await testAPI('GET', '/stgl/club/myClubs', {}, '查询我管理的社团');
  179. // 8. 启用/禁用社团
  180. if (testData.clubId) {
  181. await testAPI('PUT', '/stgl/club/changeStatus', {}, '启用/禁用社团', {
  182. id: testData.clubId,
  183. status: 0
  184. });
  185. await testAPI('PUT', '/stgl/club/changeStatus', {}, '重新启用社团', {
  186. id: testData.clubId,
  187. status: 1
  188. });
  189. }
  190. }
  191. // ============================== 社团成员管理API测试 ==============================
  192. /**
  193. * 测试社团成员管理功能
  194. */
  195. async function testMemberManagement() {
  196. console.log('\n👥 ========== 社团成员管理API测试 ==========');
  197. // 1. 查询成员列表
  198. await testAPI('GET', '/stgl/member/list', {
  199. pageNum: 1,
  200. pageSize: 10,
  201. memberType: 1
  202. }, '查询成员列表');
  203. // 2. 新增成员
  204. if (testData.clubId) {
  205. const memberData = {
  206. memberType: 1,
  207. relationId: testData.clubId,
  208. userId: 1001,
  209. studentNo: '20250002',
  210. studentName: '李四',
  211. roleType: 3,
  212. status: 1
  213. };
  214. const createResult = await testAPI('POST', '/stgl/member', memberData, '新增成员');
  215. if (createResult) {
  216. // 获取创建的成员ID
  217. const listResult = await testAPI('GET', '/stgl/member/list', {
  218. studentNo: memberData.studentNo
  219. }, '查询新建成员ID');
  220. if (listResult && listResult.data.rows.length > 0) {
  221. testData.memberId = listResult.data.rows[0].id;
  222. console.log(`🆔 获取到成员ID: ${testData.memberId}`);
  223. }
  224. }
  225. }
  226. // 3. 查询成员详情
  227. if (testData.memberId) {
  228. await testAPI('GET', `/stgl/member/${testData.memberId}`, {}, '查询成员详情');
  229. }
  230. // 4. 修改成员信息
  231. if (testData.memberId) {
  232. await testAPI('PUT', '/stgl/member', {
  233. id: testData.memberId,
  234. studentName: '李四(更新)',
  235. roleType: 2,
  236. remark: '表现优秀,晋升为副社长'
  237. }, '修改成员信息');
  238. }
  239. // 5. 根据社团ID查询成员
  240. if (testData.clubId) {
  241. await testAPI('GET', `/stgl/member/club/${testData.clubId}`, {}, '根据社团ID查询成员');
  242. }
  243. // 6. 批量添加成员
  244. if (testData.clubId) {
  245. await testAPI('POST', '/stgl/member/batchAdd', {}, '批量添加成员', {
  246. memberType: 1,
  247. relationId: testData.clubId,
  248. userIds: [1002, 1003, 1004],
  249. roleType: 3
  250. });
  251. }
  252. // 7. 更新成员角色
  253. if (testData.memberId) {
  254. await testAPI('PUT', '/stgl/member/updateRole', {}, '更新成员角色', {
  255. id: testData.memberId,
  256. roleType: 3
  257. });
  258. }
  259. // 8. 检查用户是否已是成员
  260. if (testData.clubId) {
  261. await testAPI('GET', '/stgl/member/checkMemberExists', {
  262. memberType: 1,
  263. relationId: testData.clubId,
  264. userId: 1001
  265. }, '检查用户是否已是成员');
  266. }
  267. }
  268. // ============================== 社团报名大厅API测试 ==============================
  269. /**
  270. * 测试社团报名大厅功能
  271. */
  272. async function testClubRegister() {
  273. console.log('\n🎯 ========== 社团报名大厅API测试 ==========');
  274. // 1. 查询社团报名大厅列表
  275. await testAPI('GET', '/stgl/register/list', {
  276. pageNum: 1,
  277. pageSize: 10,
  278. clubType: '学术科技类'
  279. }, '查询社团报名大厅列表');
  280. // 2. 查询社团报名大厅列表(不分页)
  281. await testAPI('GET', '/stgl/register/listAll', {
  282. clubType: '学术科技类'
  283. }, '查询社团报名大厅列表(不分页)');
  284. // 3. 查询社团详细信息
  285. if (testData.clubId) {
  286. await testAPI('GET', `/stgl/register/${testData.clubId}`, {}, '查询社团详细信息');
  287. }
  288. // 4. 报名加入社团
  289. if (testData.clubId) {
  290. await testAPI('POST', `/stgl/register/join/${testData.clubId}`, {}, '报名加入社团');
  291. }
  292. // 5. 检查报名状态
  293. if (testData.clubId) {
  294. await testAPI('GET', `/stgl/register/checkRegistered/${testData.clubId}`, {}, '检查报名状态');
  295. }
  296. // 6. 查询我参与的社团
  297. await testAPI('GET', '/stgl/register/myClubs', {}, '查询我参与的社团');
  298. // 7. 查询推荐社团
  299. await testAPI('GET', '/stgl/register/recommend', {
  300. clubType: '学术科技类',
  301. limit: 5
  302. }, '查询推荐社团');
  303. // 8. 退出社团
  304. if (testData.clubId) {
  305. await testAPI('POST', `/stgl/register/quit/${testData.clubId}`, {}, '退出社团');
  306. }
  307. }
  308. // ============================== 通用API测试函数 ==============================
  309. /**
  310. * 通用API测试函数
  311. * @param {string} method HTTP方法
  312. * @param {string} url 请求URL
  313. * @param {object} data 请求数据
  314. * @param {string} description 测试描述
  315. * @param {object} params 查询参数
  316. */
  317. async function testAPI(method, url, data = {}, description = '', params = {}) {
  318. console.log(`\n${getMethodIcon(method)} 测试${description}...`);
  319. try {
  320. let response;
  321. const config = {
  322. params: Object.keys(params).length > 0 ? params : (method === 'GET' ? data : {})
  323. };
  324. switch (method.toUpperCase()) {
  325. case 'GET':
  326. response = await request.get(url, config);
  327. break;
  328. case 'POST':
  329. response = await request.post(url, data, config);
  330. break;
  331. case 'PUT':
  332. response = await request.put(url, data, config);
  333. break;
  334. case 'DELETE':
  335. response = await request.delete(url, config);
  336. break;
  337. default:
  338. throw new Error(`不支持的HTTP方法: ${method}`);
  339. }
  340. if (response.data.code === 200) {
  341. console.log(`✅ ${description}成功`);
  342. // 根据响应类型输出不同信息
  343. if (response.data.data) {
  344. if (Array.isArray(response.data.data)) {
  345. console.log(`📊 返回数据数量: ${response.data.data.length}`);
  346. } else if (response.data.data.rows) {
  347. console.log(`📊 总记录数: ${response.data.data.total}`);
  348. console.log(`📄 当前页数据: ${response.data.data.rows.length} 条`);
  349. } else if (typeof response.data.data === 'object') {
  350. console.log(`📝 返回数据类型: ${Object.keys(response.data.data).join(', ')}`);
  351. } else {
  352. console.log(`📝 返回数据: ${response.data.data}`);
  353. }
  354. }
  355. return response.data;
  356. } else {
  357. console.error(`❌ ${description}失败:`, response.data.msg);
  358. return null;
  359. }
  360. } catch (error) {
  361. console.error(`❌ ${description}请求失败:`, error.response?.data?.msg || error.message);
  362. return null;
  363. }
  364. }
  365. /**
  366. * 获取HTTP方法对应的图标
  367. */
  368. function getMethodIcon(method) {
  369. const icons = {
  370. 'GET': '🔍',
  371. 'POST': '➕',
  372. 'PUT': '✏️',
  373. 'DELETE': '🗑️'
  374. };
  375. return icons[method.toUpperCase()] || '📡';
  376. }
  377. // ============================== 清理测试数据 ==============================
  378. /**
  379. * 清理测试数据
  380. */
  381. async function cleanupTestData() {
  382. console.log('\n🧹 ========== 清理测试数据 ==========');
  383. // 删除测试社团(会级联删除相关成员)
  384. if (testData.clubId) {
  385. await testAPI('DELETE', `/stgl/club/${testData.clubId}`, {}, '删除测试社团');
  386. }
  387. console.log('🎯 测试数据清理完成');
  388. }
  389. // ============================== 主测试流程 ==============================
  390. /**
  391. * 主测试函数
  392. */
  393. async function runTests() {
  394. console.log('🚀 ========== 社团管理系统API测试开始 ==========');
  395. console.log(`📅 测试时间: ${new Date().toLocaleString()}`);
  396. console.log(`🌐 服务器地址: ${CONFIG.BASE_URL}`);
  397. console.log(`👤 测试用户: ${CONFIG.TEST_USER.username}`);
  398. const startTime = Date.now();
  399. let successCount = 0;
  400. let totalCount = 0;
  401. try {
  402. // 1. 用户认证
  403. console.log('\n🔐 ========== 用户认证测试 ==========');
  404. const loginSuccess = await login();
  405. if (!loginSuccess) {
  406. console.log('❌ 登录失败,退出测试');
  407. return;
  408. }
  409. // 获取用户信息
  410. const userInfo = await testAPI('GET', '/system/user/getInfo', {}, '获取用户信息');
  411. if (userInfo && userInfo.data.user) {
  412. console.log(`👤 当前用户: ${userInfo.data.user.userName} (${userInfo.data.user.nickName})`);
  413. }
  414. // 2. 社团信息管理测试
  415. await testClubManagement();
  416. // 3. 社团成员管理测试
  417. await testMemberManagement();
  418. // 4. 社团报名大厅测试
  419. await testClubRegister();
  420. // 5. 清理测试数据
  421. await cleanupTestData();
  422. } catch (error) {
  423. console.error('❌ 测试过程中发生错误:', error.message);
  424. }
  425. const endTime = Date.now();
  426. const duration = (endTime - startTime) / 1000;
  427. console.log('\n🎯 ========== 社团管理系统API测试完成 ==========');
  428. console.log(`⏱️ 测试耗时: ${duration.toFixed(2)} 秒`);
  429. console.log('📊 测试结果总结:');
  430. console.log(' ✅ 社团信息管理: 8个API接口');
  431. console.log(' ✅ 社团成员管理: 8个API接口');
  432. console.log(' ✅ 社团报名大厅: 8个API接口');
  433. console.log(' 📝 总计: 24个API接口测试完成');
  434. console.log('\n📋 API接口列表:');
  435. console.log('【社团信息管理】');
  436. console.log(' - GET /stgl/club/list 查询社团列表');
  437. console.log(' - POST /stgl/club 新增社团');
  438. console.log(' - GET /stgl/club/{id} 查询社团详情');
  439. console.log(' - PUT /stgl/club 修改社团信息');
  440. console.log(' - GET /stgl/club/options 查询可用社团选项');
  441. console.log(' - GET /stgl/club/checkClubNameUnique 检查社团名称唯一性');
  442. console.log(' - GET /stgl/club/myClubs 查询我管理的社团');
  443. console.log(' - PUT /stgl/club/changeStatus 启用/禁用社团');
  444. console.log('\n【社团成员管理】');
  445. console.log(' - GET /stgl/member/list 查询成员列表');
  446. console.log(' - POST /stgl/member 新增成员');
  447. console.log(' - GET /stgl/member/{id} 查询成员详情');
  448. console.log(' - PUT /stgl/member 修改成员信息');
  449. console.log(' - GET /stgl/member/club/{clubId} 根据社团ID查询成员');
  450. console.log(' - POST /stgl/member/batchAdd 批量添加成员');
  451. console.log(' - PUT /stgl/member/updateRole 更新成员角色');
  452. console.log(' - GET /stgl/member/checkMemberExists 检查用户是否已是成员');
  453. console.log('\n【社团报名大厅】');
  454. console.log(' - GET /stgl/register/list 查询社团报名大厅列表');
  455. console.log(' - GET /stgl/register/listAll 查询社团报名大厅列表(不分页)');
  456. console.log(' - GET /stgl/register/{clubId} 查询社团详细信息');
  457. console.log(' - POST /stgl/register/join/{clubId} 报名加入社团');
  458. console.log(' - GET /stgl/register/checkRegistered/{clubId} 检查报名状态');
  459. console.log(' - GET /stgl/register/myClubs 查询我参与的社团');
  460. console.log(' - GET /stgl/register/recommend 查询推荐社团');
  461. console.log(' - POST /stgl/register/quit/{clubId} 退出社团');
  462. }
  463. // 导出模块
  464. module.exports = {
  465. runTests,
  466. CONFIG,
  467. testAPI,
  468. login
  469. };
  470. // 如果直接运行此文件,则执行测试
  471. if (require.main === module) {
  472. runTests().catch(console.error);
  473. }