357 lines
12 KiB
JavaScript
357 lines
12 KiB
JavaScript
const axios = require('axios');
|
|
const FormData = require('form-data');
|
|
const fs = require('fs');
|
|
const colors = require('colors');
|
|
|
|
/**
|
|
* 附件上传功能测试脚本
|
|
* 功能:测试新增报修单时附件是否能正确上传并记录到数据库
|
|
* 作者:wuzilong/Cursor AI辅助
|
|
* 时间:2025-06-30 19:15:00
|
|
*/
|
|
|
|
// 配置信息
|
|
const CONFIG = {
|
|
baseURL: 'http://localhost/dev-api',
|
|
clientId: 'e5cd7e4891bf95d1d19206ce24a7b32e',
|
|
timeout: 30000,
|
|
};
|
|
|
|
// 全局Token
|
|
let authToken = '';
|
|
|
|
/**
|
|
* 获取登录Token
|
|
*/
|
|
async function getAuthToken() {
|
|
const CryptoJS = require('crypto-js');
|
|
const NodeRSA = require('node-rsa');
|
|
|
|
// 生成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-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==\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');
|
|
}
|
|
|
|
try {
|
|
console.log('🔐 正在获取登录Token...'.yellow);
|
|
|
|
const aesKey = generateAESKey();
|
|
const loginData = {
|
|
tenantId: '000000',
|
|
username: 'admin',
|
|
password: 'admin123',
|
|
clientId: CONFIG.clientId,
|
|
grantType: 'password',
|
|
};
|
|
|
|
const encryptedData = aesEncrypt(JSON.stringify(loginData), aesKey);
|
|
const encryptedKey = rsaEncrypt(aesKey);
|
|
|
|
const response = await axios.post(`${CONFIG.baseURL}/auth/login`, encryptedData, {
|
|
headers: {
|
|
'Content-Type': 'application/json;charset=utf-8',
|
|
clientid: CONFIG.clientId,
|
|
'encrypt-key': encryptedKey,
|
|
referer: 'http://localhost/login?redirect=%252Findex',
|
|
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
|
isToken: 'false',
|
|
isEncrypt: 'true',
|
|
},
|
|
timeout: CONFIG.timeout,
|
|
});
|
|
|
|
if (response.data.code === 200 && response.data.data?.access_token) {
|
|
authToken = response.data.data.access_token;
|
|
console.log('✅ 登录成功'.green);
|
|
return authToken;
|
|
} else {
|
|
throw new Error(`登录失败: ${response.data.msg}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('❌ 登录失败:'.red, error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 创建测试报修工单
|
|
*/
|
|
async function createTestRepairOrder() {
|
|
try {
|
|
console.log('\n📝 正在创建测试报修工单...'.yellow);
|
|
|
|
const orderData = {
|
|
title: '附件上传测试工单',
|
|
description: '这是一个用于测试附件上传功能的报修工单',
|
|
repairLocation: '测试地点A座101',
|
|
categoryId: '1', // 假设的维修类型ID
|
|
priorityLevel: 3,
|
|
reporterName: '测试用户',
|
|
reporterPhone: '13800138000',
|
|
reporterDept: '技术部',
|
|
expectedFinishTime: new Date(Date.now() + 24 * 60 * 60 * 1000)
|
|
.toISOString()
|
|
.slice(0, 19)
|
|
.replace('T', ' '),
|
|
remark: '测试备注信息',
|
|
};
|
|
|
|
const response = await axios.post(`${CONFIG.baseURL}/pm/repairOrder`, orderData, {
|
|
headers: {
|
|
Authorization: `Bearer ${authToken}`,
|
|
'Content-Type': 'application/json;charset=utf-8',
|
|
clientid: CONFIG.clientId,
|
|
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
|
},
|
|
timeout: CONFIG.timeout,
|
|
});
|
|
|
|
if (response.data.code === 200) {
|
|
console.log('🐛 完整响应数据:', JSON.stringify(response.data, null, 2)); // 调试信息
|
|
const orderId = response.data.data;
|
|
console.log('✅ 工单创建成功'.green, `工单ID: ${orderId}`);
|
|
return orderId;
|
|
} else {
|
|
throw new Error(`工单创建失败: ${response.data.msg}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('❌ 创建工单失败:'.red, error.response?.data || error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 创建测试文件
|
|
*/
|
|
function createTestFile() {
|
|
const testContent = `测试附件内容
|
|
创建时间: ${new Date().toLocaleString()}
|
|
文件用途: 验证附件上传功能
|
|
测试编号: ATT-${Date.now()}`;
|
|
|
|
const fileName = `test-attachment-${Date.now()}.txt`;
|
|
fs.writeFileSync(fileName, testContent, 'utf8');
|
|
|
|
console.log(`📎 已创建测试文件: ${fileName}`.cyan);
|
|
return fileName;
|
|
}
|
|
|
|
/**
|
|
* 上传附件到工单
|
|
*/
|
|
async function uploadAttachment(orderId, fileName) {
|
|
try {
|
|
console.log(`\n📤 正在上传附件到工单 ${orderId}...`.yellow);
|
|
|
|
const formData = new FormData();
|
|
formData.append('orderId', orderId.toString());
|
|
formData.append('uploadStage', '1');
|
|
formData.append('file', fs.createReadStream(fileName), {
|
|
filename: fileName,
|
|
contentType: 'text/plain',
|
|
});
|
|
formData.append('description', '测试附件描述');
|
|
|
|
const response = await axios.post(`${CONFIG.baseURL}/pm/attachment/upload`, formData, {
|
|
headers: {
|
|
Authorization: `Bearer ${authToken}`,
|
|
clientid: CONFIG.clientId,
|
|
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
|
...formData.getHeaders(),
|
|
},
|
|
timeout: CONFIG.timeout,
|
|
});
|
|
|
|
if (response.data.code === 200) {
|
|
console.log('✅ 附件上传成功'.green);
|
|
console.log('📋 附件信息:'.cyan, {
|
|
id: response.data.data.id,
|
|
fileName: response.data.data.fileName,
|
|
filePath: response.data.data.filePath,
|
|
orderId: response.data.data.orderId,
|
|
});
|
|
return response.data.data;
|
|
} else {
|
|
throw new Error(`附件上传失败: ${response.data.msg}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('❌ 附件上传失败:'.red, error.response?.data || error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 验证附件是否记录到数据库
|
|
*/
|
|
async function verifyAttachmentInDatabase(orderId) {
|
|
try {
|
|
console.log(`\n🔍 正在验证工单 ${orderId} 的附件记录...`.yellow);
|
|
|
|
const response = await axios.get(`${CONFIG.baseURL}/pm/attachment/order/${orderId}`, {
|
|
headers: {
|
|
Authorization: `Bearer ${authToken}`,
|
|
clientid: CONFIG.clientId,
|
|
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
|
},
|
|
timeout: CONFIG.timeout,
|
|
});
|
|
|
|
if (response.data.code === 200) {
|
|
const attachments = response.data.data || [];
|
|
console.log(`📊 数据库查询结果: 找到 ${attachments.length} 个附件`.cyan);
|
|
|
|
if (attachments.length > 0) {
|
|
console.log('✅ 附件已成功记录到数据库'.green);
|
|
attachments.forEach((att, index) => {
|
|
console.log(`📎 附件 ${index + 1}:`.cyan, {
|
|
id: att.id,
|
|
fileName: att.fileName,
|
|
fileSize: att.fileSize,
|
|
orderId: att.orderId,
|
|
createTime: att.createTime,
|
|
});
|
|
});
|
|
return true;
|
|
} else {
|
|
console.log('❌ 数据库中未找到附件记录'.red);
|
|
return false;
|
|
}
|
|
} else {
|
|
throw new Error(`查询附件失败: ${response.data.msg}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('❌ 验证数据库记录失败:'.red, error.response?.data || error.message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 清理测试数据
|
|
*/
|
|
async function cleanup(orderId, fileName) {
|
|
try {
|
|
console.log('\n🧹 正在清理测试数据...'.yellow);
|
|
|
|
// 删除测试文件
|
|
if (fs.existsSync(fileName)) {
|
|
fs.unlinkSync(fileName);
|
|
console.log(`🗑️ 已删除测试文件: ${fileName}`.gray);
|
|
}
|
|
|
|
// 删除测试工单(可选)
|
|
// 注意:实际环境中可能不需要删除,用于保留测试记录
|
|
/*
|
|
await axios.delete(`${CONFIG.baseURL}/pm/repairOrder/${orderId}`, {
|
|
headers: {
|
|
'Authorization': `Bearer ${authToken}`,
|
|
'clientid': CONFIG.clientId
|
|
}
|
|
});
|
|
console.log(`🗑️ 已删除测试工单: ${orderId}`.gray);
|
|
*/
|
|
|
|
console.log('✅ 清理完成'.gray);
|
|
} catch (error) {
|
|
console.error('❌ 清理失败:'.red, error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 主测试函数
|
|
*/
|
|
async function runAttachmentTest() {
|
|
console.log('🚀 开始附件上传功能测试'.rainbow);
|
|
console.log('=' * 50);
|
|
|
|
let orderId = null;
|
|
let fileName = null;
|
|
|
|
try {
|
|
// 1. 获取登录Token
|
|
await getAuthToken();
|
|
|
|
// 2. 创建测试工单
|
|
orderId = await createTestRepairOrder();
|
|
|
|
// 3. 创建测试文件
|
|
fileName = createTestFile();
|
|
|
|
// 4. 上传附件
|
|
await uploadAttachment(orderId, fileName);
|
|
|
|
// 5. 验证数据库记录
|
|
const isRecorded = await verifyAttachmentInDatabase(orderId);
|
|
|
|
// 6. 测试结果
|
|
console.log('\n📊 测试结果总结'.rainbow);
|
|
console.log('=' * 30);
|
|
|
|
if (isRecorded) {
|
|
console.log('🎉 测试通过: 附件上传功能正常,数据已记录到数据库'.green.bold);
|
|
} else {
|
|
console.log('⚠️ 测试失败: 附件未正确记录到数据库'.red.bold);
|
|
console.log('🔧 建议检查以下问题:'.yellow);
|
|
console.log(' 1. 后端附件上传接口是否正常工作');
|
|
console.log(' 2. 数据库连接和表结构是否正确');
|
|
console.log(' 3. orderId 是否正确传递给上传接口');
|
|
console.log(' 4. 上传阶段参数是否正确');
|
|
}
|
|
} catch (error) {
|
|
console.error('\n💥 测试过程中发生错误:'.red.bold, error.message);
|
|
console.log('🔧 故障排查建议:'.yellow);
|
|
console.log(' 1. 检查后端服务是否正常运行');
|
|
console.log(' 2. 验证API接口路径和权限配置');
|
|
console.log(' 3. 查看后端日志获取详细错误信息');
|
|
console.log(' 4. 确认数据库表结构和字段是否正确');
|
|
} finally {
|
|
// 清理测试数据
|
|
if (orderId && fileName) {
|
|
await cleanup(orderId, fileName);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 执行测试
|
|
if (require.main === module) {
|
|
runAttachmentTest()
|
|
.then(() => {
|
|
console.log('\n✅ 测试脚本执行完成'.green);
|
|
process.exit(0);
|
|
})
|
|
.catch((error) => {
|
|
console.error('\n❌ 测试脚本执行失败:'.red, error.message);
|
|
process.exit(1);
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
runAttachmentTest,
|
|
getAuthToken,
|
|
createTestRepairOrder,
|
|
uploadAttachment,
|
|
verifyAttachmentInDatabase,
|
|
};
|