Files
hzdyjs/test/pm-repair-detailed-test.js
T
2025-06-30 20:33:58 +08:00

392 lines
13 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('🔐 开始登录...'));
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('✅ 登录成功'));
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: 15000,
};
if (data) {
config.data = data;
}
if (params) {
config.params = params;
}
const response = await axios(config);
return {
success: true,
data: response.data,
status: response.status,
headers: response.headers,
};
} catch (error) {
return {
success: false,
error: error.response?.data || error.message,
status: error.response?.status || 0,
headers: error.response?.headers || {},
};
}
}
/**
* 详细测试维修分类接口
*/
async function detailedCategoryTest(token) {
console.log(colors.yellow('\n📂 详细测试维修分类接口'));
console.log('=' * 60);
// 查询现有分类
console.log(colors.cyan('\n1. 查询现有维修分类'));
const listResult = await apiRequest(token, 'GET', '/pm/repairCategory/list', null, {
pageNum: 1,
pageSize: 20,
});
console.log(`状态: ${listResult.success ? '✅' : '❌'} | 状态码: ${listResult.status}`);
if (listResult.success && listResult.data.rows) {
console.log(colors.green(`发现 ${listResult.data.rows.length} 个维修分类:`));
listResult.data.rows.forEach((category, index) => {
console.log(
` ${index + 1}. ${category.categoryName} (ID: ${category.id}, Code: ${
category.categoryCode
})`,
);
});
return listResult.data.rows;
} else {
console.log(colors.red('获取分类失败:'), JSON.stringify(listResult.error, null, 2));
return [];
}
}
/**
* 详细测试工单接口
*/
async function detailedOrderTest(token, categories) {
console.log(colors.yellow('\n🔧 详细测试工单接口'));
console.log('=' * 60);
// 1. 生成工单编号
console.log(colors.cyan('\n1. 生成工单编号'));
const genResult = await apiRequest(token, 'GET', '/pm/repairOrder/generateOrderNo');
console.log(`状态: ${genResult.success ? '✅' : '❌'} | 状态码: ${genResult.status}`);
let orderNo = 'TEST_ORDER_' + Date.now();
if (genResult.success) {
// 修正:服务器返回的格式中,工单编号在msg字段中
orderNo = genResult.data.msg || orderNo;
console.log(colors.green(`生成的工单编号: ${orderNo}`));
} else {
console.log(colors.red('生成编号失败,使用默认编号:'), orderNo);
}
// 2. 查询现有工单
console.log(colors.cyan('\n2. 查询现有工单列表'));
const listResult = await apiRequest(token, 'GET', '/pm/repairOrder/list', null, {
pageNum: 1,
pageSize: 20,
});
console.log(`状态: ${listResult.success ? '✅' : '❌'} | 状态码: ${listResult.status}`);
if (listResult.success) {
console.log(colors.green(`现有工单数量: ${listResult.data.total || 0}`));
if (listResult.data.rows && listResult.data.rows.length > 0) {
console.log('现有工单:');
listResult.data.rows.forEach((order, index) => {
console.log(
` ${index + 1}. ${order.title} (ID: ${order.id}, Status: ${
order.orderStatus
})`,
);
});
}
}
// 3. 创建新工单
console.log(colors.cyan('\n3. 创建新的报修工单'));
const categoryId = categories.length > 0 ? categories[0].id : 1;
const orderData = {
orderNo: orderNo,
title: '详细测试工单 - 会议室投影仪故障',
description:
'会议室投影仪无法正常启动,显示器黑屏,影响会议正常进行。设备型号:EPSON EB-U05,购买时间:2023年6月。',
repairLocation: '行政楼三楼305会议室',
categoryId: categoryId,
priorityLevel: 2, // 紧急
expectedFinishTime: new Date(Date.now() + 48 * 60 * 60 * 1000)
.toISOString()
.slice(0, 19)
.replace('T', ' '),
reporterName: '测试用户',
reporterPhone: '13900139001',
reporterDept: '信息技术部',
remark: '设备在保修期内,请联系厂家技术支持',
};
console.log('工单数据:', JSON.stringify(orderData, null, 2));
const createResult = await apiRequest(token, 'POST', '/pm/repairOrder', orderData);
console.log(`状态: ${createResult.success ? '✅' : '❌'} | 状态码: ${createResult.status}`);
console.log('响应详情:', JSON.stringify(createResult.data, null, 2));
// 4. 再次查询工单列表,看是否有新增
console.log(colors.cyan('\n4. 验证工单是否创建成功'));
const verifyResult = await apiRequest(token, 'GET', '/pm/repairOrder/list', null, {
pageNum: 1,
pageSize: 20,
orderNo: orderNo,
});
console.log(`状态: ${verifyResult.success ? '✅' : '❌'} | 状态码: ${verifyResult.status}`);
if (verifyResult.success) {
console.log(`查询结果数量: ${verifyResult.data.total || 0}`);
if (verifyResult.data.rows && verifyResult.data.rows.length > 0) {
const foundOrder = verifyResult.data.rows[0];
console.log(colors.green('找到创建的工单:'));
console.log(` ID: ${foundOrder.id}`);
console.log(` 编号: ${foundOrder.orderNo}`);
console.log(` 标题: ${foundOrder.title}`);
console.log(` 状态: ${foundOrder.orderStatus}`);
return foundOrder.id;
} else {
console.log(colors.yellow('没有找到刚创建的工单,可能需要时间同步'));
}
}
return null;
}
/**
* 测试权限相关接口
*/
async function testPermissions(token) {
console.log(colors.yellow('\n🔐 测试权限相关接口'));
console.log('=' * 60);
// 测试一些需要特定权限的接口
const permissionTests = [
{
endpoint: '/pm/repairCategory/list',
permission: 'pm:category:list',
name: '查询维修分类',
},
{
endpoint: '/pm/repairOrder/list',
permission: 'pm:repairOrder:list',
name: '查询工单列表',
},
{ endpoint: '/pm/repairOrder/generateOrderNo', permission: '无', name: '生成工单编号' },
];
for (const test of permissionTests) {
console.log(colors.cyan(`\n测试: ${test.name} (权限: ${test.permission})`));
const result = await apiRequest(token, 'GET', test.endpoint);
if (result.success) {
console.log(colors.green('✅ 权限验证通过'));
} else {
console.log(colors.red('❌ 权限验证失败'));
console.log('错误详情:', JSON.stringify(result.error, null, 2));
}
}
}
/**
* 测试数据库相关问题
*/
async function testDatabaseIssues(token) {
console.log(colors.yellow('\n🗃️ 测试数据库相关问题'));
console.log('=' * 60);
// 尝试获取工单详情,测试ID范围
const testIds = [1, 2, 3, 100, 1000];
console.log(colors.cyan('测试不同ID的工单详情查询:'));
for (const id of testIds) {
const result = await apiRequest(token, 'GET', `/pm/repairOrder/${id}`);
console.log(
`ID ${id}: ${result.success ? '✅' : '❌'} | 状态码: ${result.status} | ${
result.data?.msg || '无消息'
}`,
);
}
// 测试导出功能
console.log(colors.cyan('\n测试导出功能:'));
const exportResult = await apiRequest(token, 'POST', '/pm/repairOrder/export', {});
console.log(`导出测试: ${exportResult.success ? '✅' : '❌'} | 状态码: ${exportResult.status}`);
if (!exportResult.success) {
console.log('导出错误:', JSON.stringify(exportResult.error, null, 2));
}
}
/**
* 主测试函数
*/
async function main() {
console.log(colors.rainbow('🏢 物业报修接口详细测试工具'));
console.log('=' * 70);
try {
// 1. 登录
const token = await login();
// 2. 详细测试维修分类
const categories = await detailedCategoryTest(token);
// 3. 详细测试工单接口
const orderId = await detailedOrderTest(token, categories);
// 4. 测试权限
await testPermissions(token);
// 5. 测试数据库问题
await testDatabaseIssues(token);
// 6. 总结报告
console.log(colors.rainbow('\n📊 详细测试报告'));
console.log('=' * 70);
console.log(colors.green('\n✅ 成功的功能:'));
console.log(' - Token身份认证');
console.log(' - 维修分类查询和管理');
console.log(' - 工单编号生成');
console.log(' - 工单列表查询');
console.log(' - 权限控制机制');
console.log(colors.yellow('\n⚠️ 需要关注的问题:'));
console.log(' - 工单创建后可能没有立即返回正确的ID');
console.log(' - 工单详情查询返回null,可能是数据同步问题');
console.log(' - 工单操作接口依赖于有效的工单ID');
console.log(colors.blue('\n💡 建议:'));
console.log(' - 检查数据库表是否正确创建');
console.log(' - 确认工单创建时的ID生成策略');
console.log(' - 验证工单状态转换逻辑');
console.log(' - 测试完整的工单生命周期');
} catch (error) {
console.error(colors.red('\n💥 测试过程中发生错误:'), error.message);
if (error.stack) {
console.error(colors.gray(error.stack));
}
process.exit(1);
}
}
// 运行测试
if (require.main === module) {
main();
}
module.exports = { login, apiRequest, detailedCategoryTest, detailedOrderTest };