1
This commit is contained in:
382
_script/api_test_complete.js
Normal file
382
_script/api_test_complete.js
Normal file
@@ -0,0 +1,382 @@
|
||||
/**
|
||||
* 完整API测试脚本
|
||||
* 测试所有核心API接口功能
|
||||
*/
|
||||
|
||||
const axios = require('axios');
|
||||
|
||||
const API_BASE = 'http://localhost:9097/api';
|
||||
let testResults = {
|
||||
total: 0,
|
||||
passed: 0,
|
||||
failed: 0,
|
||||
skipped: 0
|
||||
};
|
||||
|
||||
// 测试用的设备ID
|
||||
const TEST_DEVICE_ID = 'test_device_' + Date.now();
|
||||
let testResumeId = null;
|
||||
let testJobId = null;
|
||||
let testTaskId = null;
|
||||
|
||||
// 打印测试结果
|
||||
function printResult(testName, passed, message = '') {
|
||||
testResults.total++;
|
||||
if (passed) {
|
||||
testResults.passed++;
|
||||
console.log(`✅ [PASS] ${testName}`);
|
||||
if (message) console.log(` └─ ${message}`);
|
||||
} else {
|
||||
testResults.failed++;
|
||||
console.log(`❌ [FAIL] ${testName}`);
|
||||
if (message) console.log(` └─ ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
function printSkipped(testName, reason) {
|
||||
testResults.total++;
|
||||
testResults.skipped++;
|
||||
console.log(`⏭️ [SKIP] ${testName}`);
|
||||
console.log(` └─ ${reason}`);
|
||||
}
|
||||
|
||||
// API测试函数
|
||||
async function testAPI(name, method, endpoint, data = null, expectedStatus = 200) {
|
||||
try {
|
||||
const url = `${API_BASE}${endpoint}`;
|
||||
let response;
|
||||
|
||||
if (method === 'GET') {
|
||||
response = await axios.get(url, { params: data });
|
||||
} else if (method === 'POST') {
|
||||
response = await axios.post(url, data);
|
||||
} else if (method === 'PUT') {
|
||||
response = await axios.put(url, data);
|
||||
} else if (method === 'DELETE') {
|
||||
response = await axios.delete(url, { data });
|
||||
}
|
||||
|
||||
const passed = response.status === expectedStatus;
|
||||
printResult(name, passed, `状态码: ${response.status}`);
|
||||
return { success: true, data: response.data };
|
||||
} catch (error) {
|
||||
const message = error.response
|
||||
? `状态码: ${error.response.status}, 错误: ${error.response.data?.message || error.message}`
|
||||
: `网络错误: ${error.message}`;
|
||||
printResult(name, false, message);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// 主测试流程
|
||||
async function runTests() {
|
||||
console.log('='.repeat(60));
|
||||
console.log('🧪 开始API完整测试');
|
||||
console.log('='.repeat(60));
|
||||
console.log(`测试设备ID: ${TEST_DEVICE_ID}`);
|
||||
console.log('');
|
||||
|
||||
// ============================================
|
||||
// 1. 健康检查
|
||||
// ============================================
|
||||
console.log('\n📋 【1/8】健康检查 API\n');
|
||||
await testAPI('健康检查', 'GET', '/health');
|
||||
|
||||
// ============================================
|
||||
// 2. 设备管理
|
||||
// ============================================
|
||||
console.log('\n📋 【2/8】设备管理 API\n');
|
||||
|
||||
const registerResult = await testAPI('设备注册', 'POST', '/device/register', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
deviceName: '测试设备',
|
||||
clientVersion: '1.0.0',
|
||||
osVersion: 'Windows 10',
|
||||
pythonVersion: '3.9.0'
|
||||
});
|
||||
|
||||
await testAPI('设备心跳', 'POST', '/device/heartbeat', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
cpuUsage: 45.5,
|
||||
memoryUsage: 60.2,
|
||||
diskUsage: 50.0
|
||||
});
|
||||
|
||||
await testAPI('设备状态查询', 'GET', '/device/status', {
|
||||
sn_code: TEST_DEVICE_ID
|
||||
});
|
||||
|
||||
await testAPI('设备列表', 'GET', '/device/list', {
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
|
||||
// ============================================
|
||||
// 3. 简历管理
|
||||
// ============================================
|
||||
console.log('\n📋 【3/8】简历管理 API\n');
|
||||
|
||||
const resumeResult = await testAPI('简历同步', 'POST', '/resume/sync', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
platform: 'boss',
|
||||
resumeData: {
|
||||
fullName: '张三',
|
||||
gender: '男',
|
||||
age: 28,
|
||||
phone: '13800138000',
|
||||
email: 'test@example.com',
|
||||
location: '北京',
|
||||
education: '本科',
|
||||
major: '计算机科学',
|
||||
school: '清华大学',
|
||||
workYears: '5年',
|
||||
expectedPosition: '前端工程师',
|
||||
expectedSalary: '15-25K',
|
||||
skills: ['Vue', 'React', 'Node.js', 'TypeScript'],
|
||||
workExperience: [
|
||||
{
|
||||
company: 'XX科技公司',
|
||||
position: '高级前端工程师',
|
||||
duration: '2020-2024',
|
||||
description: '负责公司核心产品前端开发'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
if (resumeResult.success && resumeResult.data?.data?.resumeId) {
|
||||
testResumeId = resumeResult.data.data.resumeId;
|
||||
console.log(` 💡 简历ID: ${testResumeId}`);
|
||||
}
|
||||
|
||||
if (testResumeId) {
|
||||
await testAPI('获取简历详情', 'GET', '/resume/get', {
|
||||
resumeId: testResumeId
|
||||
});
|
||||
|
||||
// AI分析需要API Key,可能失败
|
||||
console.log(' ⚠️ 注意: AI分析需要配置API Key');
|
||||
await testAPI('简历AI分析', 'POST', '/resume/analyze', {
|
||||
resumeId: testResumeId
|
||||
});
|
||||
} else {
|
||||
printSkipped('获取简历详情', '简历创建失败');
|
||||
printSkipped('简历AI分析', '简历创建失败');
|
||||
}
|
||||
|
||||
await testAPI('简历列表', 'GET', '/resume/list', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
|
||||
// ============================================
|
||||
// 4. 岗位管理
|
||||
// ============================================
|
||||
console.log('\n📋 【4/8】岗位管理 API\n');
|
||||
|
||||
const jobResult = await testAPI('批量添加岗位', 'POST', '/job/batch-add', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
platform: 'boss',
|
||||
jobs: [
|
||||
{
|
||||
platformJobId: 'job_001',
|
||||
jobTitle: '前端工程师',
|
||||
companyName: 'XX科技有限公司',
|
||||
companySize: '500-1000人',
|
||||
companyIndustry: '互联网',
|
||||
salary: '15-25K',
|
||||
salaryMin: 15,
|
||||
salaryMax: 25,
|
||||
location: '北京',
|
||||
experienceRequired: '3-5年',
|
||||
educationRequired: '本科',
|
||||
jobDescription: '负责公司产品前端开发,使用Vue/React技术栈',
|
||||
skillsRequired: 'Vue, React, JavaScript, TypeScript'
|
||||
},
|
||||
{
|
||||
platformJobId: 'job_002',
|
||||
jobTitle: 'Node.js工程师',
|
||||
companyName: 'YY互联网公司',
|
||||
salary: '20-30K',
|
||||
salaryMin: 20,
|
||||
salaryMax: 30,
|
||||
location: '北京',
|
||||
experienceRequired: '3-5年',
|
||||
educationRequired: '本科',
|
||||
jobDescription: '负责后端服务开发,使用Node.js技术栈',
|
||||
skillsRequired: 'Node.js, Express, MongoDB'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
if (jobResult.success && jobResult.data?.data?.createdCount > 0) {
|
||||
console.log(` 💡 成功创建 ${jobResult.data.data.createdCount} 个岗位`);
|
||||
}
|
||||
|
||||
await testAPI('岗位列表', 'GET', '/job/list', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
platform: 'boss',
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
|
||||
// ============================================
|
||||
// 5. 任务管理
|
||||
// ============================================
|
||||
console.log('\n📋 【5/8】任务管理 API\n');
|
||||
|
||||
const taskResult = await testAPI('创建任务', 'POST', '/task/create', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
taskType: 'job_search',
|
||||
taskName: '搜索前端岗位',
|
||||
priority: 5,
|
||||
taskData: {
|
||||
platform: 'boss',
|
||||
keyword: '前端工程师',
|
||||
location: '北京',
|
||||
limit: 50
|
||||
}
|
||||
});
|
||||
|
||||
if (taskResult.success && taskResult.data?.data?.taskId) {
|
||||
testTaskId = taskResult.data.data.taskId;
|
||||
console.log(` 💡 任务ID: ${testTaskId}`);
|
||||
}
|
||||
|
||||
if (testTaskId) {
|
||||
await testAPI('启动任务', 'POST', '/task/start', {
|
||||
taskId: testTaskId
|
||||
});
|
||||
|
||||
await testAPI('更新任务进度', 'POST', '/task/progress', {
|
||||
taskId: testTaskId,
|
||||
progress: 50,
|
||||
message: '任务执行中'
|
||||
});
|
||||
|
||||
await testAPI('查询任务状态', 'GET', '/task/status', {
|
||||
taskId: testTaskId
|
||||
});
|
||||
|
||||
await testAPI('完成任务', 'POST', '/task/complete', {
|
||||
taskId: testTaskId,
|
||||
resultData: {
|
||||
jobsFound: 50,
|
||||
jobsFiltered: 20
|
||||
}
|
||||
});
|
||||
} else {
|
||||
printSkipped('启动任务', '任务创建失败');
|
||||
printSkipped('更新任务进度', '任务创建失败');
|
||||
printSkipped('查询任务状态', '任务创建失败');
|
||||
printSkipped('完成任务', '任务创建失败');
|
||||
}
|
||||
|
||||
await testAPI('任务列表', 'GET', '/task/list', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
|
||||
// ============================================
|
||||
// 6. 聊天管理
|
||||
// ============================================
|
||||
console.log('\n📋 【6/8】聊天管理 API\n');
|
||||
|
||||
// 需要先有岗位ID
|
||||
if (testJobId || jobResult.success) {
|
||||
await testAPI('添加聊天记录', 'POST', '/chat/add', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
platform: 'boss',
|
||||
jobId: testJobId || 'job_001',
|
||||
chatType: 'greeting',
|
||||
direction: 'outgoing',
|
||||
content: '您好,我对贵公司的前端工程师岗位非常感兴趣',
|
||||
aiGenerated: true
|
||||
});
|
||||
} else {
|
||||
printSkipped('添加聊天记录', '无可用岗位ID');
|
||||
}
|
||||
|
||||
await testAPI('聊天列表', 'GET', '/chat/list', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
|
||||
// ============================================
|
||||
// 7. 投递管理
|
||||
// ============================================
|
||||
console.log('\n📋 【7/8】投递管理 API\n');
|
||||
|
||||
// 需要简历ID和岗位ID
|
||||
if (testResumeId && (testJobId || jobResult.success)) {
|
||||
await testAPI('投递记录', 'POST', '/apply/record', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
platform: 'boss',
|
||||
jobId: testJobId || 'job_001',
|
||||
resumeId: testResumeId,
|
||||
applyMethod: 'online'
|
||||
});
|
||||
} else {
|
||||
printSkipped('投递记录', '缺少简历ID或岗位ID');
|
||||
}
|
||||
|
||||
await testAPI('投递列表', 'GET', '/apply/list', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
|
||||
await testAPI('投递统计', 'GET', '/apply/statistics', {
|
||||
sn_code: TEST_DEVICE_ID,
|
||||
startDate: '2024-01-01',
|
||||
endDate: '2024-12-31'
|
||||
});
|
||||
|
||||
// ============================================
|
||||
// 8. 清理测试数据(可选)
|
||||
// ============================================
|
||||
console.log('\n📋 【8/8】测试完成\n');
|
||||
|
||||
// ============================================
|
||||
// 打印测试结果统计
|
||||
// ============================================
|
||||
console.log('\n' + '='.repeat(60));
|
||||
console.log('📊 测试结果统计');
|
||||
console.log('='.repeat(60));
|
||||
console.log(`总测试数: ${testResults.total}`);
|
||||
console.log(`✅ 通过: ${testResults.passed}`);
|
||||
console.log(`❌ 失败: ${testResults.failed}`);
|
||||
console.log(`⏭️ 跳过: ${testResults.skipped}`);
|
||||
console.log(`成功率: ${((testResults.passed / testResults.total) * 100).toFixed(2)}%`);
|
||||
console.log('='.repeat(60));
|
||||
|
||||
if (testResults.failed > 0) {
|
||||
console.log('\n⚠️ 部分测试失败,可能原因:');
|
||||
console.log(' 1. 后端服务未启动或未连接到数据库');
|
||||
console.log(' 2. MQTT服务未启动');
|
||||
console.log(' 3. AI API Key未配置');
|
||||
console.log(' 4. 网络连接问题');
|
||||
console.log('\n💡 建议:');
|
||||
console.log(' - 检查后端服务是否正常运行');
|
||||
console.log(' - 查看后端服务日志');
|
||||
console.log(' - 确认数据库连接配置正确');
|
||||
} else if (testResults.failed === 0 && testResults.skipped === 0) {
|
||||
console.log('\n🎉 所有测试通过!系统运行正常!');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// 运行测试
|
||||
console.log('正在连接到后端服务...\n');
|
||||
setTimeout(() => {
|
||||
runTests().then(() => {
|
||||
process.exit(testResults.failed > 0 ? 1 : 0);
|
||||
}).catch(error => {
|
||||
console.warn('\n❌ 测试执行异常:', error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
}, 1000);
|
||||
122
_script/fix_all_models.js
Normal file
122
_script/fix_all_models.js
Normal file
@@ -0,0 +1,122 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// 递归查找所有 .js 文件
|
||||
function findJsFiles(dir) {
|
||||
let results = [];
|
||||
const list = fs.readdirSync(dir);
|
||||
|
||||
list.forEach(file => {
|
||||
const filePath = path.join(dir, file);
|
||||
const stat = fs.statSync(filePath);
|
||||
|
||||
if (stat && stat.isDirectory()) {
|
||||
results = results.concat(findJsFiles(filePath));
|
||||
} else if (file.endsWith('.js')) {
|
||||
results.push(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// 修复单个 model 文件
|
||||
function fixModelFile(filePath) {
|
||||
try {
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
const originalContent = content;
|
||||
|
||||
// 替换 DataTypes 为 Sequelize
|
||||
content = content.replace(/DataTypes/g, 'Sequelize');
|
||||
|
||||
// 修复 module.exports 格式
|
||||
// 匹配: module.exports = (sequelize, DataTypes) => { const model = sequelize.define(...) }
|
||||
const pattern1 = /module\.exports\s*=\s*\(sequelize,\s*DataTypes\)\s*=>\s*\{\s*const\s+(\w+)\s*=\s*sequelize\.define\('([^']+)',\s*\{([\s\S]*?)\}\);\s*\/\/[^}]*return\s+\1;\s*\};/g;
|
||||
|
||||
content = content.replace(pattern1, (match, modelName, tableName, fields) => {
|
||||
return `module.exports = (db) => {
|
||||
return db.define("${tableName}", {${fields}
|
||||
});
|
||||
};`;
|
||||
});
|
||||
|
||||
// 匹配: module.exports = (sequelize, DataTypes) => { const model = sequelize.define(...); return model; }
|
||||
const pattern2 = /module\.exports\s*=\s*\(sequelize,\s*DataTypes\)\s*=>\s*\{\s*const\s+(\w+)\s*=\s*sequelize\.define\('([^']+)',\s*\{([\s\S]*?)\}\);\s*return\s+\1;\s*\};/g;
|
||||
|
||||
content = content.replace(pattern2, (match, modelName, tableName, fields) => {
|
||||
return `module.exports = (db) => {
|
||||
return db.define("${tableName}", {${fields}
|
||||
});
|
||||
};`;
|
||||
});
|
||||
|
||||
// 匹配: module.exports = (sequelize, DataTypes) => { return sequelize.define(...); }
|
||||
const pattern3 = /module\.exports\s*=\s*\(sequelize,\s*DataTypes\)\s*=>\s*\{\s*return\s+sequelize\.define\('([^']+)',\s*\{([\s\S]*?)\}\);\s*\};/g;
|
||||
|
||||
content = content.replace(pattern3, (match, tableName, fields) => {
|
||||
return `module.exports = (db) => {
|
||||
return db.define("${tableName}", {${fields}
|
||||
});
|
||||
};`;
|
||||
});
|
||||
|
||||
// 匹配: module.exports = (sequelize, Sequelize) => { ... }
|
||||
const pattern4 = /module\.exports\s*=\s*\(sequelize,\s*Sequelize\)\s*=>\s*\{\s*const\s+(\w+)\s*=\s*sequelize\.define\('([^']+)',\s*\{([\s\S]*?)\}\);\s*\/\/[^}]*return\s+\1;\s*\};/g;
|
||||
|
||||
content = content.replace(pattern4, (match, modelName, tableName, fields) => {
|
||||
return `module.exports = (db) => {
|
||||
return db.define("${tableName}", {${fields}
|
||||
});
|
||||
};`;
|
||||
});
|
||||
|
||||
// 匹配: module.exports = (sequelize, Sequelize) => { const model = sequelize.define(...); return model; }
|
||||
const pattern5 = /module\.exports\s*=\s*\(sequelize,\s*Sequelize\)\s*=>\s*\{\s*const\s+(\w+)\s*=\s*sequelize\.define\('([^']+)',\s*\{([\s\S]*?)\}\);\s*return\s+\1;\s*\};/g;
|
||||
|
||||
content = content.replace(pattern5, (match, modelName, tableName, fields) => {
|
||||
return `module.exports = (db) => {
|
||||
return db.define("${tableName}", {${fields}
|
||||
});
|
||||
};`;
|
||||
});
|
||||
|
||||
// 清理多余的空行
|
||||
content = content.replace(/\n\s*\n\s*\n/g, '\n\n');
|
||||
|
||||
if (content !== originalContent) {
|
||||
fs.writeFileSync(filePath, content, 'utf8');
|
||||
console.log(`已修复: ${filePath}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error(`处理文件失败 ${filePath}:`, error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 主函数
|
||||
function main() {
|
||||
const modelDir = path.join(__dirname, 'api', 'model');
|
||||
|
||||
if (!fs.existsSync(modelDir)) {
|
||||
console.error('模型目录不存在:', modelDir);
|
||||
return;
|
||||
}
|
||||
|
||||
const jsFiles = findJsFiles(modelDir);
|
||||
let fixedCount = 0;
|
||||
|
||||
console.log(`找到 ${jsFiles.length} 个模型文件`);
|
||||
|
||||
jsFiles.forEach(filePath => {
|
||||
if (fixModelFile(filePath)) {
|
||||
fixedCount++;
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`修复完成,共修复 ${fixedCount} 个文件`);
|
||||
}
|
||||
|
||||
main();
|
||||
102
_script/fix_model_definitions.js
Normal file
102
_script/fix_model_definitions.js
Normal file
@@ -0,0 +1,102 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// 递归查找所有 .js 文件
|
||||
function findJsFiles(dir) {
|
||||
let results = [];
|
||||
const list = fs.readdirSync(dir);
|
||||
|
||||
list.forEach(file => {
|
||||
const filePath = path.join(dir, file);
|
||||
const stat = fs.statSync(filePath);
|
||||
|
||||
if (stat && stat.isDirectory()) {
|
||||
results = results.concat(findJsFiles(filePath));
|
||||
} else if (file.endsWith('.js')) {
|
||||
results.push(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// 修复 model 定义
|
||||
function fixModelDefinition(filePath) {
|
||||
try {
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
const originalContent = content;
|
||||
|
||||
// 检查是否已经是正确的格式
|
||||
if (content.includes('module.exports = (db) => {')) {
|
||||
console.log(`跳过已正确格式的文件: ${filePath}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 替换 DataTypes 为 Sequelize
|
||||
content = content.replace(/DataTypes/g, 'Sequelize');
|
||||
|
||||
// 替换 module.exports 格式
|
||||
// 从: module.exports = (sequelize, DataTypes) => { const model = sequelize.define(...) }
|
||||
// 到: module.exports = (db) => { return db.define(...) }
|
||||
|
||||
const sequelizeDefinePattern = /module\.exports\s*=\s*\(sequelize,\s*DataTypes\)\s*=>\s*\{\s*const\s+(\w+)\s*=\s*sequelize\.define\('([^']+)',\s*\{([\s\S]*?)\}\);\s*return\s+\1;\s*\};/g;
|
||||
|
||||
content = content.replace(sequelizeDefinePattern, (match, modelName, tableName, fields) => {
|
||||
return `module.exports = (db) => {
|
||||
return db.define("${tableName}", {${fields}
|
||||
});
|
||||
};`;
|
||||
});
|
||||
|
||||
// 如果上面的模式没有匹配到,尝试其他模式
|
||||
if (content === originalContent) {
|
||||
const simpleDefinePattern = /module\.exports\s*=\s*\(sequelize,\s*DataTypes\)\s*=>\s*\{\s*return\s+sequelize\.define\('([^']+)',\s*\{([\s\S]*?)\}\);\s*\};/g;
|
||||
|
||||
content = content.replace(simpleDefinePattern, (match, tableName, fields) => {
|
||||
return `module.exports = (db) => {
|
||||
return db.define("${tableName}", {${fields}
|
||||
});
|
||||
};`;
|
||||
});
|
||||
}
|
||||
|
||||
// 清理多余的空行
|
||||
content = content.replace(/\n\s*\n\s*\n/g, '\n\n');
|
||||
|
||||
if (content !== originalContent) {
|
||||
fs.writeFileSync(filePath, content, 'utf8');
|
||||
console.log(`已修复: ${filePath}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error(`处理文件失败 ${filePath}:`, error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 主函数
|
||||
function main() {
|
||||
const modelDir = path.join(__dirname, 'api', 'model');
|
||||
|
||||
if (!fs.existsSync(modelDir)) {
|
||||
console.error('模型目录不存在:', modelDir);
|
||||
return;
|
||||
}
|
||||
|
||||
const jsFiles = findJsFiles(modelDir);
|
||||
let fixedCount = 0;
|
||||
|
||||
console.log(`找到 ${jsFiles.length} 个模型文件`);
|
||||
|
||||
jsFiles.forEach(filePath => {
|
||||
if (fixModelDefinition(filePath)) {
|
||||
fixedCount++;
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`修复完成,共修复 ${fixedCount} 个文件`);
|
||||
}
|
||||
|
||||
main();
|
||||
80
_script/remove_custom_ids.js
Normal file
80
_script/remove_custom_ids.js
Normal file
@@ -0,0 +1,80 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// 递归查找所有 .js 文件
|
||||
function findJsFiles(dir) {
|
||||
let results = [];
|
||||
const list = fs.readdirSync(dir);
|
||||
|
||||
list.forEach(file => {
|
||||
const filePath = path.join(dir, file);
|
||||
const stat = fs.statSync(filePath);
|
||||
|
||||
if (stat && stat.isDirectory()) {
|
||||
results = results.concat(findJsFiles(filePath));
|
||||
} else if (file.endsWith('.js')) {
|
||||
results.push(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// 移除自定义主键字段
|
||||
function removeCustomIdsInFile(filePath) {
|
||||
try {
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
const originalContent = content;
|
||||
|
||||
// 匹配自定义主键字段模式
|
||||
const customIdPatterns = [
|
||||
// 模式1: applyId, taskId, chatId, resumeId, deviceId 等
|
||||
/(\w+Id):\s*\{\s*comment:\s*'[^']*',\s*type:\s*Sequelize\.STRING\(\d+\),\s*allowNull:\s*false,\s*primaryKey:\s*true\s*\},?\s*/g,
|
||||
// 模式2: 带 autoIncrement 的 id 字段
|
||||
/(\w+Id):\s*\{\s*comment:\s*'[^']*',\s*type:\s*Sequelize\.INTEGER,\s*primaryKey:\s*true,\s*autoIncrement:\s*true\s*\},?\s*/g
|
||||
];
|
||||
|
||||
customIdPatterns.forEach(pattern => {
|
||||
content = content.replace(pattern, '');
|
||||
});
|
||||
|
||||
// 清理多余的空行
|
||||
content = content.replace(/\n\s*\n\s*\n/g, '\n\n');
|
||||
|
||||
if (content !== originalContent) {
|
||||
fs.writeFileSync(filePath, content, 'utf8');
|
||||
console.log(`已修复: ${filePath}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error(`处理文件失败 ${filePath}:`, error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 主函数
|
||||
function main() {
|
||||
const modelDir = path.join(__dirname, 'api', 'model');
|
||||
|
||||
if (!fs.existsSync(modelDir)) {
|
||||
console.error('模型目录不存在:', modelDir);
|
||||
return;
|
||||
}
|
||||
|
||||
const jsFiles = findJsFiles(modelDir);
|
||||
let fixedCount = 0;
|
||||
|
||||
console.log(`找到 ${jsFiles.length} 个模型文件`);
|
||||
|
||||
jsFiles.forEach(filePath => {
|
||||
if (removeCustomIdsInFile(filePath)) {
|
||||
fixedCount++;
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`修复完成,共修复 ${fixedCount} 个文件`);
|
||||
}
|
||||
|
||||
main();
|
||||
78
_script/sync_all_models.js
Normal file
78
_script/sync_all_models.js
Normal file
@@ -0,0 +1,78 @@
|
||||
const Framework = require('../framework/node-core-framework.js');
|
||||
const frameworkConfig = require('../config/framework.config.js');
|
||||
|
||||
/**
|
||||
* 同步所有模型到数据库
|
||||
* 执行所有 model 的 sync() 操作
|
||||
*/
|
||||
async function syncAllModels() {
|
||||
try {
|
||||
console.log('开始同步所有模型到数据库...');
|
||||
|
||||
// 初始化框架
|
||||
console.log('正在初始化框架...');
|
||||
const framework = await Framework.init(frameworkConfig);
|
||||
|
||||
// 获取所有模型
|
||||
const models = Framework.getModels();
|
||||
|
||||
if (!models) {
|
||||
console.error('无法获取模型列表');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('找到以下模型:');
|
||||
Object.keys(models).forEach(modelName => {
|
||||
console.log(`- ${modelName}`);
|
||||
});
|
||||
|
||||
// 同步所有模型
|
||||
const syncPromises = Object.keys(models).map(async (modelName) => {
|
||||
try {
|
||||
const model = models[modelName];
|
||||
console.log(`正在同步模型: ${modelName}`);
|
||||
|
||||
// 执行同步
|
||||
await model.sync({ alter: true });
|
||||
console.log(`✅ ${modelName} 同步完成`);
|
||||
|
||||
return { modelName, success: true };
|
||||
} catch (error) {
|
||||
console.error(`❌ ${modelName} 同步失败:`, error.message);
|
||||
return { modelName, success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
// 等待所有同步操作完成
|
||||
const results = await Promise.all(syncPromises);
|
||||
|
||||
// 统计结果
|
||||
const successCount = results.filter(r => r.success).length;
|
||||
const failCount = results.filter(r => !r.success).length;
|
||||
|
||||
console.log('\n=== 同步结果统计 ===');
|
||||
console.log(`成功: ${successCount} 个模型`);
|
||||
console.log(`失败: ${failCount} 个模型`);
|
||||
|
||||
if (failCount > 0) {
|
||||
console.log('\n失败的模型:');
|
||||
results.filter(r => !r.success).forEach(r => {
|
||||
console.log(`- ${r.modelName}: ${r.error}`);
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n数据库同步操作完成!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('同步过程中发生错误:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 执行同步
|
||||
syncAllModels().then(() => {
|
||||
console.log('脚本执行完成');
|
||||
process.exit(0);
|
||||
}).catch(error => {
|
||||
console.error('脚本执行失败:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
102
_script/update_controller_ids.js
Normal file
102
_script/update_controller_ids.js
Normal file
@@ -0,0 +1,102 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// 递归查找所有 .js 文件
|
||||
function findJsFiles(dir) {
|
||||
let results = [];
|
||||
const list = fs.readdirSync(dir);
|
||||
|
||||
list.forEach(file => {
|
||||
const filePath = path.join(dir, file);
|
||||
const stat = fs.statSync(filePath);
|
||||
|
||||
if (stat && stat.isDirectory()) {
|
||||
results = results.concat(findJsFiles(filePath));
|
||||
} else if (file.endsWith('.js')) {
|
||||
results.push(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// 更新 controller 中的 ID 字段使用
|
||||
function updateControllerIds(filePath) {
|
||||
try {
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
const originalContent = content;
|
||||
|
||||
// 定义字段映射关系
|
||||
const fieldMappings = {
|
||||
'applyId': 'id',
|
||||
'taskId': 'id',
|
||||
'chatId': 'id',
|
||||
'resumeId': 'id',
|
||||
'deviceId': 'id'
|
||||
};
|
||||
|
||||
// 替换字段名
|
||||
Object.keys(fieldMappings).forEach(oldField => {
|
||||
const newField = fieldMappings[oldField];
|
||||
|
||||
// 替换变量声明和赋值
|
||||
content = content.replace(new RegExp(`const ${oldField} =`, 'g'), `const ${newField} =`);
|
||||
content = content.replace(new RegExp(`let ${oldField} =`, 'g'), `let ${newField} =`);
|
||||
content = content.replace(new RegExp(`var ${oldField} =`, 'g'), `var ${newField} =`);
|
||||
|
||||
// 替换对象属性
|
||||
content = content.replace(new RegExp(`${oldField}:`, 'g'), `${newField}:`);
|
||||
|
||||
// 替换解构赋值
|
||||
content = content.replace(new RegExp(`\\{ ${oldField} \\}`, 'g'), `{ ${newField} }`);
|
||||
content = content.replace(new RegExp(`\\{${oldField}\\}`, 'g'), `{${newField}}`);
|
||||
|
||||
// 替换 where 条件中的字段名
|
||||
content = content.replace(new RegExp(`where: \\{ ${oldField}:`, 'g'), `where: { ${newField}:`);
|
||||
content = content.replace(new RegExp(`where: \\{${oldField}:`, 'g'), `where: {${newField}:`);
|
||||
|
||||
// 替换注释中的字段名
|
||||
content = content.replace(new RegExp(`- ${oldField}`, 'g'), `- ${newField}`);
|
||||
content = content.replace(new RegExp(`${oldField}:`, 'g'), `${newField}:`);
|
||||
});
|
||||
|
||||
// 清理多余的空行
|
||||
content = content.replace(/\n\s*\n\s*\n/g, '\n\n');
|
||||
|
||||
if (content !== originalContent) {
|
||||
fs.writeFileSync(filePath, content, 'utf8');
|
||||
console.log(`已更新: ${filePath}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error(`处理文件失败 ${filePath}:`, error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 主函数
|
||||
function main() {
|
||||
const controllerDir = path.join(__dirname, 'api', 'controller_front');
|
||||
|
||||
if (!fs.existsSync(controllerDir)) {
|
||||
console.error('Controller 目录不存在:', controllerDir);
|
||||
return;
|
||||
}
|
||||
|
||||
const jsFiles = findJsFiles(controllerDir);
|
||||
let updatedCount = 0;
|
||||
|
||||
console.log(`找到 ${jsFiles.length} 个 controller 文件`);
|
||||
|
||||
jsFiles.forEach(filePath => {
|
||||
if (updateControllerIds(filePath)) {
|
||||
updatedCount++;
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`更新完成,共更新 ${updatedCount} 个文件`);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user