417 lines
15 KiB
JavaScript
417 lines
15 KiB
JavaScript
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,
|
|
};
|