| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- const axios = require('axios');
- const CryptoJS = require('crypto-js');
- const NodeRSA = require('node-rsa');
- const colors = require('colors');
- // 配置信息
- const CONFIG = {
- baseURL: 'http://localhost/dev-api',
- loginURL: 'http://localhost/dev-api/auth/login',
- clientId: 'e5cd7e4891bf95d1d19206ce24a7b32e',
- tenantId: '000000',
- referer: 'http://localhost/login?redirect=%252Findex',
- rsaKey: 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==',
- };
- /**
- * 生成32位随机AES密钥
- */
- function generateAESKey() {
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- let result = '';
- for (let i = 0; i < 32; i++) {
- result += chars.charAt(Math.floor(Math.random() * chars.length));
- }
- return result;
- }
- /**
- * AES加密
- */
- function aesEncrypt(data, key) {
- const keyUtf8 = CryptoJS.enc.Utf8.parse(key);
- return CryptoJS.AES.encrypt(data, keyUtf8, {
- mode: CryptoJS.mode.ECB,
- padding: CryptoJS.pad.Pkcs7,
- }).toString();
- }
- /**
- * RSA加密AES密钥
- */
- function rsaEncrypt(aesKey) {
- const pemKey = `-----BEGIN PUBLIC KEY-----\n${CONFIG.rsaKey}\n-----END PUBLIC KEY-----`;
- const rsaKey = new NodeRSA(pemKey);
- rsaKey.setOptions({ encryptionScheme: 'pkcs1' });
- const aesKeyBase64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(aesKey));
- return rsaKey.encrypt(aesKeyBase64, 'base64');
- }
- /**
- * 登录获取Token
- */
- async function login(username = 'admin', password = 'admin123') {
- try {
- console.log(colors.blue('🔐 开始登录获取Token...'));
- // 生成AES密钥并加密登录数据
- const aesKey = generateAESKey();
- const loginData = {
- tenantId: CONFIG.tenantId,
- username: username,
- password: password,
- clientId: CONFIG.clientId,
- grantType: 'password',
- };
- const encryptedData = aesEncrypt(JSON.stringify(loginData), aesKey);
- const encryptedKey = rsaEncrypt(aesKey);
- // 设置请求头
- const headers = {
- 'Content-Type': 'application/json;charset=utf-8',
- clientid: CONFIG.clientId,
- 'encrypt-key': encryptedKey,
- referer: CONFIG.referer,
- 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
- isToken: 'false',
- isEncrypt: 'true',
- repeatSubmit: 'false',
- };
- // 发送登录请求
- const response = await axios.post(CONFIG.loginURL, encryptedData, {
- headers: headers,
- timeout: 10000,
- });
- if (response.data.code === 200 && response.data.data?.access_token) {
- console.log(colors.green('✅ 登录成功!'));
- console.log(
- colors.gray(`Token: ${response.data.data.access_token.substring(0, 50)}...`),
- );
- return response.data.data.access_token;
- } else {
- throw new Error(response.data.msg || 'Login failed');
- }
- } catch (error) {
- console.error(colors.red('❌ 登录失败:'), error.message);
- throw error;
- }
- }
- /**
- * 通用API请求方法
- */
- async function apiRequest(token, method, endpoint, data = null, params = null) {
- try {
- const config = {
- method: method,
- url: `${CONFIG.baseURL}${endpoint}`,
- headers: {
- 'Content-Type': 'application/json;charset=utf-8',
- Authorization: `Bearer ${token}`,
- clientid: CONFIG.clientId,
- referer: CONFIG.referer,
- 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
- },
- timeout: 10000,
- };
- if (data) {
- config.data = data;
- }
- if (params) {
- config.params = params;
- }
- const response = await axios(config);
- return {
- success: true,
- data: response.data,
- status: response.status,
- };
- } catch (error) {
- return {
- success: false,
- error: error.response?.data || error.message,
- status: error.response?.status || 0,
- };
- }
- }
- /**
- * 测试物业报修分类接口
- */
- async function testRepairCategoryAPIs(token) {
- console.log(colors.yellow('\n📂 测试物业报修分类接口'));
- console.log(colors.gray('=' * 50));
- // 1. 查询维修类型列表
- console.log(colors.cyan('1. 查询维修类型列表 - GET /pm/repairCategory/list'));
- const listResult = await apiRequest(token, 'GET', '/pm/repairCategory/list', null, {
- pageNum: 1,
- pageSize: 10,
- });
- if (listResult.success) {
- console.log(colors.green('✅ 成功'), `状态码: ${listResult.status}`);
- console.log(
- colors.gray(`响应: ${JSON.stringify(listResult.data, null, 2).substring(0, 200)}...`),
- );
- } else {
- console.log(colors.red('❌ 失败'), `状态码: ${listResult.status}`);
- console.log(colors.gray(`错误: ${JSON.stringify(listResult.error, null, 2)}`));
- }
- // 2. 获取维修类型树形结构
- console.log(colors.cyan('\n2. 获取维修类型树形结构 - GET /pm/repairCategory/tree'));
- const treeResult = await apiRequest(token, 'GET', '/pm/repairCategory/tree');
- if (treeResult.success) {
- console.log(colors.green('✅ 成功'), `状态码: ${treeResult.status}`);
- console.log(
- colors.gray(`响应: ${JSON.stringify(treeResult.data, null, 2).substring(0, 200)}...`),
- );
- } else {
- console.log(colors.red('❌ 失败'), `状态码: ${treeResult.status}`);
- console.log(colors.gray(`错误: ${JSON.stringify(treeResult.error, null, 2)}`));
- }
- // 3. 新增维修类型
- console.log(colors.cyan('\n3. 新增维修类型 - POST /pm/repairCategory'));
- const addCategoryData = {
- categoryName: '测试维修类型',
- categoryCode: 'TEST_REPAIR',
- categoryDescription: '这是一个测试的维修类型',
- parentId: 0,
- skillLevel: '1',
- estimatedDuration: 60,
- standardCost: 100.0,
- colorCode: '#1890FF',
- sortOrder: 99,
- status: '1',
- remark: '测试数据',
- };
- const addResult = await apiRequest(token, 'POST', '/pm/repairCategory', addCategoryData);
- if (addResult.success) {
- console.log(colors.green('✅ 成功'), `状态码: ${addResult.status}`);
- console.log(colors.gray(`响应: ${JSON.stringify(addResult.data, null, 2)}`));
- } else {
- console.log(colors.red('❌ 失败'), `状态码: ${addResult.status}`);
- console.log(colors.gray(`错误: ${JSON.stringify(addResult.error, null, 2)}`));
- }
- }
- /**
- * 测试物业报修工单接口
- */
- async function testRepairOrderAPIs(token) {
- console.log(colors.yellow('\n🔧 测试物业报修工单接口'));
- console.log(colors.gray('=' * 50));
- // 1. 生成工单编号
- console.log(colors.cyan('1. 生成工单编号 - GET /pm/repairOrder/generateOrderNo'));
- const generateResult = await apiRequest(token, 'GET', '/pm/repairOrder/generateOrderNo');
- let orderNo = null;
- if (generateResult.success) {
- console.log(colors.green('✅ 成功'), `状态码: ${generateResult.status}`);
- console.log(colors.gray(`响应: ${JSON.stringify(generateResult.data, null, 2)}`));
- orderNo = generateResult.data.data;
- } else {
- console.log(colors.red('❌ 失败'), `状态码: ${generateResult.status}`);
- console.log(colors.gray(`错误: ${JSON.stringify(generateResult.error, null, 2)}`));
- orderNo = `RO${new Date().toISOString().slice(0, 10).replace(/-/g, '')}001`;
- }
- // 2. 查询报修工单列表
- console.log(colors.cyan('\n2. 查询报修工单列表 - GET /pm/repairOrder/list'));
- const listResult = await apiRequest(token, 'GET', '/pm/repairOrder/list', null, {
- pageNum: 1,
- pageSize: 10,
- });
- if (listResult.success) {
- console.log(colors.green('✅ 成功'), `状态码: ${listResult.status}`);
- console.log(
- colors.gray(`响应: ${JSON.stringify(listResult.data, null, 2).substring(0, 300)}...`),
- );
- } else {
- console.log(colors.red('❌ 失败'), `状态码: ${listResult.status}`);
- console.log(colors.gray(`错误: ${JSON.stringify(listResult.error, null, 2)}`));
- }
- // 3. 新增报修工单
- console.log(colors.cyan('\n3. 新增报修工单 - POST /pm/repairOrder'));
- const addOrderData = {
- orderNo: orderNo,
- title: '测试报修工单 - 办公室空调故障',
- description: '办公室空调不制冷,温度调节失效,影响正常办公。请尽快安排维修人员检查处理。',
- repairLocation: '行政楼305办公室',
- categoryId: 1,
- priorityLevel: 2,
- expectedFinishTime: new Date(Date.now() + 24 * 60 * 60 * 1000)
- .toISOString()
- .slice(0, 19)
- .replace('T', ' '),
- reporterName: '张三',
- reporterPhone: '13800138001',
- reporterDept: '行政办公室',
- remark: '测试工单数据',
- };
- const addResult = await apiRequest(token, 'POST', '/pm/repairOrder', addOrderData);
- let createdOrderId = null;
- if (addResult.success) {
- console.log(colors.green('✅ 成功'), `状态码: ${addResult.status}`);
- console.log(colors.gray(`响应: ${JSON.stringify(addResult.data, null, 2)}`));
- // 尝试从响应中获取创建的工单ID
- if (addResult.data.data && typeof addResult.data.data === 'object') {
- createdOrderId = addResult.data.data.id || Date.now();
- } else {
- createdOrderId = Date.now();
- }
- } else {
- console.log(colors.red('❌ 失败'), `状态码: ${addResult.status}`);
- console.log(colors.gray(`错误: ${JSON.stringify(addResult.error, null, 2)}`));
- }
- // 4. 如果有创建的工单ID,测试工单详情查询
- if (createdOrderId) {
- console.log(colors.cyan(`\n4. 查询工单详情 - GET /pm/repairOrder/${createdOrderId}`));
- const detailResult = await apiRequest(token, 'GET', `/pm/repairOrder/${createdOrderId}`);
- if (detailResult.success) {
- console.log(colors.green('✅ 成功'), `状态码: ${detailResult.status}`);
- console.log(
- colors.gray(
- `响应: ${JSON.stringify(detailResult.data, null, 2).substring(0, 300)}...`,
- ),
- );
- } else {
- console.log(colors.red('❌ 失败'), `状态码: ${detailResult.status}`);
- console.log(colors.gray(`错误: ${JSON.stringify(detailResult.error, null, 2)}`));
- }
- }
- return createdOrderId;
- }
- /**
- * 测试工单操作接口
- */
- async function testOrderOperationAPIs(token, orderId) {
- if (!orderId) {
- console.log(colors.yellow('\n⚠️ 跳过工单操作测试(没有可用的工单ID)'));
- return;
- }
- console.log(colors.yellow('\n⚙️ 测试工单操作接口'));
- console.log(colors.gray('=' * 50));
- // 1. 分派工单
- console.log(colors.cyan(`1. 分派工单 - PUT /pm/repairOrder/${orderId}/assign`));
- const assignResult = await apiRequest(token, 'PUT', `/pm/repairOrder/${orderId}/assign`, null, {
- assigneeId: 1001,
- assignRemark: '分派给李师傅处理,请尽快联系报修人',
- });
- if (assignResult.success) {
- console.log(colors.green('✅ 成功'), `状态码: ${assignResult.status}`);
- console.log(colors.gray(`响应: ${JSON.stringify(assignResult.data, null, 2)}`));
- } else {
- console.log(colors.red('❌ 失败'), `状态码: ${assignResult.status}`);
- console.log(colors.gray(`错误: ${JSON.stringify(assignResult.error, null, 2)}`));
- }
- // 2. 开始维修
- console.log(colors.cyan(`\n2. 开始维修 - PUT /pm/repairOrder/${orderId}/start`));
- const startResult = await apiRequest(token, 'PUT', `/pm/repairOrder/${orderId}/start`);
- if (startResult.success) {
- console.log(colors.green('✅ 成功'), `状态码: ${startResult.status}`);
- console.log(colors.gray(`响应: ${JSON.stringify(startResult.data, null, 2)}`));
- } else {
- console.log(colors.red('❌ 失败'), `状态码: ${startResult.status}`);
- console.log(colors.gray(`错误: ${JSON.stringify(startResult.error, null, 2)}`));
- }
- // 3. 完成维修
- console.log(colors.cyan(`\n3. 完成维修 - PUT /pm/repairOrder/${orderId}/finish`));
- const finishResult = await apiRequest(token, 'PUT', `/pm/repairOrder/${orderId}/finish`, null, {
- repairResult: '已更换空调滤网,清洁空调系统,制冷功能恢复正常',
- usedMaterials: '空调滤网 x1, 清洁剂 x1',
- });
- if (finishResult.success) {
- console.log(colors.green('✅ 成功'), `状态码: ${finishResult.status}`);
- console.log(colors.gray(`响应: ${JSON.stringify(finishResult.data, null, 2)}`));
- } else {
- console.log(colors.red('❌ 失败'), `状态码: ${finishResult.status}`);
- console.log(colors.gray(`错误: ${JSON.stringify(finishResult.error, null, 2)}`));
- }
- }
- /**
- * 主测试函数
- */
- async function main() {
- console.log(colors.rainbow('🏢 物业报修接口测试工具'));
- console.log(colors.gray('=' * 60));
- try {
- // 1. 登录获取Token
- const token = await login();
- // 2. 测试物业报修分类接口
- await testRepairCategoryAPIs(token);
- // 3. 测试物业报修工单接口
- const orderId = await testRepairOrderAPIs(token);
- // 4. 测试工单操作接口
- await testOrderOperationAPIs(token, orderId);
- // 5. 测试结果总结
- console.log(colors.rainbow('\n🎉 物业报修接口测试完成!'));
- console.log(colors.green('\n✅ 测试覆盖的接口:'));
- console.log(colors.gray(' - 维修类型列表查询'));
- console.log(colors.gray(' - 维修类型树形结构'));
- console.log(colors.gray(' - 新增维修类型'));
- console.log(colors.gray(' - 生成工单编号'));
- console.log(colors.gray(' - 工单列表查询'));
- console.log(colors.gray(' - 新增报修工单'));
- console.log(colors.gray(' - 工单详情查询'));
- console.log(colors.gray(' - 分派工单'));
- console.log(colors.gray(' - 开始维修'));
- console.log(colors.gray(' - 完成维修'));
- console.log(colors.blue('\n💡 提示:'));
- console.log(colors.gray(' - 所有接口都需要Token认证'));
- console.log(colors.gray(' - 接口路径基于后端Controller定义'));
- console.log(colors.gray(' - 部分操作可能需要特定的权限码'));
- console.log(colors.gray(' - 建议检查后端数据库是否有相应的表结构'));
- } catch (error) {
- console.error(colors.red('\n💥 测试过程中发生错误:'), error.message);
- process.exit(1);
- }
- }
- // 运行测试
- if (require.main === module) {
- main();
- }
- module.exports = {
- login,
- apiRequest,
- testRepairCategoryAPIs,
- testRepairOrderAPIs,
- testOrderOperationAPIs,
- };
|