This commit is contained in:
张成
2025-11-24 13:23:42 +08:00
commit 5d7444cd65
156 changed files with 50653 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
/**
* 添加"账号列表"菜单项到用户管理菜单下
* 执行 SQL 插入操作
*/
const Framework = require('../framework/node-core-framework.js');
const frameworkConfig = require('../config/framework.config.js');
async function addAccountListMenu() {
console.log('🔄 开始添加"账号列表"菜单项...\n');
try {
// 初始化框架
console.log('正在初始化框架...');
const framework = await Framework.init(frameworkConfig);
const models = Framework.getModels();
if (!models) {
throw new Error('无法获取模型列表');
}
// 从任意模型获取 sequelize 实例
const Sequelize = require('sequelize');
const firstModel = Object.values(models)[0];
if (!firstModel || !firstModel.sequelize) {
throw new Error('无法获取数据库连接');
}
const sequelize = firstModel.sequelize;
// 检查是否已存在
const [existing] = await sequelize.query(
`SELECT id, name FROM sys_menu WHERE parent_id = 120 AND path = 'pla_account' AND is_delete = 0`,
{ type: Sequelize.QueryTypes.SELECT }
);
if (existing) {
console.log(`⚠️ 菜单项已存在 (ID: ${existing.id}, 名称: ${existing.name})`);
console.log('✅ 无需重复添加\n');
return;
}
// 执行插入
const [result] = await sequelize.query(
`INSERT INTO sys_menu (
name,
parent_id,
model_id,
form_id,
icon,
path,
component,
api_path,
is_show_menu,
is_show,
type,
sort,
create_time,
last_modify_time,
is_delete
) VALUES (
'账号列表',
120,
0,
0,
'md-list',
'pla_account',
'account/pla_account.vue',
'account/pla_account_server.js',
1,
1,
'页面',
1,
NOW(),
NOW(),
0
)`,
{ type: Sequelize.QueryTypes.INSERT }
);
console.log('✅ "账号列表"菜单项添加成功!\n');
// 验证插入结果(通过 path 查询)
const [menus] = await sequelize.query(
`SELECT id, name, parent_id, path, component, api_path, sort
FROM sys_menu
WHERE parent_id = 120 AND path = 'pla_account' AND is_delete = 0`,
{ type: Sequelize.QueryTypes.SELECT }
);
const menu = menus && menus.length > 0 ? menus[0] : null;
if (menu) {
console.log('📋 菜单项详情:');
console.log(` 名称: ${menu.name}`);
console.log(` 父菜单ID: ${menu.parent_id}`);
console.log(` 路由路径: ${menu.path}`);
console.log(` 组件路径: ${menu.component}`);
console.log(` API路径: ${menu.api_path}`);
console.log(` 排序: ${menu.sort}\n`);
}
// 显示用户管理菜单下的所有子菜单
const [children] = await sequelize.query(
`SELECT id, name, path, sort, is_show_menu
FROM sys_menu
WHERE parent_id = 120 AND is_delete = 0
ORDER BY sort`,
{ type: Sequelize.QueryTypes.SELECT }
);
console.log('📋 用户管理菜单下的所有子菜单:');
children.forEach(child => {
const visible = child.is_show_menu ? '✅' : '🔒';
console.log(` ${visible} ${child.name} (ID: ${child.id}, 路径: ${child.path}, 排序: ${child.sort})`);
});
} catch (error) {
console.error('❌ 添加失败:', error.message);
console.error('\n详细错误:', error);
throw error;
}
}
// 执行添加
addAccountListMenu()
.then(() => {
console.log('\n✨ 操作完成!');
process.exit(0);
})
.catch(error => {
console.error('\n💥 执行失败:', error);
process.exit(1);
});

View File

@@ -0,0 +1,109 @@
/**
* 添加职位类型数据
* 添加 web全栈工程师 和 售前工程师 两条记录
*/
const Framework = require('../framework/node-core-framework.js');
const frameworkConfig = require('../config/framework.config.js');
async function addJobTypesData() {
console.log('🔄 开始添加职位类型数据...\n');
try {
// 初始化框架
console.log('正在初始化框架...');
await Framework.init(frameworkConfig);
const models = Framework.getModels();
if (!models || !models.job_types) {
throw new Error('无法获取 job_types 模型');
}
const job_types = models.job_types;
// 1. 添加 web全栈工程师
const [webFullStack, created1] = await job_types.findOrCreate({
where: { name: 'web全栈工程师' },
defaults: {
name: 'web全栈工程师',
description: 'Web全栈开发工程师掌握前后端技术栈',
commonSkills: JSON.stringify([
'Vue', 'React', 'Angular', 'JavaScript', 'TypeScript', 'Node.js',
'Express', 'Koa', 'NestJS', 'Webpack', 'Vite',
'HTML5', 'CSS3', 'Sass', 'Less',
'MySQL', 'MongoDB', 'Redis',
'Git', 'Docker', 'Linux',
'RESTful API', 'GraphQL', 'WebSocket'
]),
excludeKeywords: JSON.stringify([
'外包', '外派', '驻场', '销售', '客服',
'地推', '推广', '市场', '运营'
]),
is_enabled: 1,
sort_order: 1
}
});
if (created1) {
console.log('✅ 添加成功web全栈工程师');
} else {
console.log('⚠️ 已存在web全栈工程师');
}
// 2. 添加 售前工程师
const [preSales, created2] = await job_types.findOrCreate({
where: { name: '售前工程师' },
defaults: {
name: '售前工程师',
description: '售前技术支持工程师,负责技术方案设计和客户沟通',
commonSkills: JSON.stringify([
'技术方案', '产品演示', '客户沟通', '需求分析',
'技术咨询', '解决方案', 'PPT制作', '技术文档',
'项目管理', '商务谈判', '行业知识'
]),
excludeKeywords: JSON.stringify([
'纯销售', '电话销售', '地推', '推广',
'客服', '文员', '行政'
]),
is_enabled: 1,
sort_order: 2
}
});
if (created2) {
console.log('✅ 添加成功:售前工程师');
} else {
console.log('⚠️ 已存在:售前工程师');
}
// 显示所有职位类型
console.log('\n📋 当前所有职位类型:');
const allTypes = await job_types.findAll({
where: { is_enabled: 1 },
order: [['sort_order', 'ASC'], ['id', 'ASC']]
});
allTypes.forEach((type, index) => {
const data = type.toJSON();
console.log(` ${index + 1}. ${data.name} (ID: ${data.id}, 排序: ${data.sort_order})`);
});
console.log('\n✨ 操作完成!');
} catch (error) {
console.error('❌ 添加失败:', error.message);
console.error('\n详细错误:', error);
throw error;
}
}
// 执行添加
addJobTypesData()
.then(() => {
process.exit(0);
})
.catch(error => {
console.error('\n💥 执行失败:', error);
process.exit(1);
});

View File

@@ -0,0 +1,149 @@
/**
* 添加"职位类型管理"菜单项到系统设置菜单下
* 执行 SQL 插入操作
*/
const Framework = require('../framework/node-core-framework.js');
const frameworkConfig = require('../config/framework.config.js');
async function addJobTypesMenu() {
console.log('🔄 开始添加"职位类型管理"菜单项...\n');
try {
// 初始化框架
console.log('正在初始化框架...');
const framework = await Framework.init(frameworkConfig);
const models = Framework.getModels();
if (!models) {
throw new Error('无法获取模型列表');
}
// 从任意模型获取 sequelize 实例
const Sequelize = require('sequelize');
const firstModel = Object.values(models)[0];
if (!firstModel || !firstModel.sequelize) {
throw new Error('无法获取数据库连接');
}
const sequelize = firstModel.sequelize;
// 先查找系统设置菜单的ID通常 parent_id 为 0 或特定的系统菜单ID
// 需要根据实际情况调整查询条件
const [systemMenu] = await sequelize.query(
`SELECT id FROM sys_menu WHERE (name LIKE '%系统%' OR name LIKE '%设置%') AND parent_id = 0 AND is_delete = 0 LIMIT 1`,
{ type: Sequelize.QueryTypes.SELECT }
);
let parentId = 0;
if (systemMenu && systemMenu.id) {
parentId = systemMenu.id;
console.log(`找到系统设置菜单ID: ${parentId}`);
} else {
// 如果没有找到,尝试查找 system_config 菜单的父菜单
const [configMenu] = await sequelize.query(
`SELECT parent_id FROM sys_menu WHERE path = 'system_config' AND is_delete = 0 LIMIT 1`,
{ type: Sequelize.QueryTypes.SELECT }
);
if (configMenu && configMenu.parent_id) {
parentId = configMenu.parent_id;
console.log(`从系统配置菜单获取父菜单ID: ${parentId}`);
} else {
console.log('未找到系统设置菜单,将使用 parent_id = 0');
}
}
// 检查是否已存在
const [existing] = await sequelize.query(
`SELECT id, name FROM sys_menu WHERE path = 'job_types' AND is_delete = 0`,
{ type: Sequelize.QueryTypes.SELECT }
);
if (existing) {
console.log(`⚠️ 菜单项已存在 (ID: ${existing.id}, 名称: ${existing.name})`);
console.log('✅ 无需重复添加\n');
return;
}
// 获取最大排序值
const [maxSort] = await sequelize.query(
`SELECT MAX(sort) as maxSort FROM sys_menu WHERE parent_id = ${parentId} AND is_delete = 0`,
{ type: Sequelize.QueryTypes.SELECT }
);
const nextSort = (maxSort && maxSort.maxSort ? maxSort.maxSort : 0) + 1;
// 执行插入
await sequelize.query(
`INSERT INTO sys_menu (
name,
parent_id,
model_id,
form_id,
icon,
path,
component,
api_path,
is_show_menu,
is_show,
type,
sort,
create_time,
last_modify_time,
is_delete
) VALUES (
'职位类型管理',
${parentId},
0,
0,
'md-briefcase',
'job_types',
'system/job_types.vue',
'system/job_types_server.js',
1,
1,
'页面',
${nextSort},
NOW(),
NOW(),
0
)`,
{ type: Sequelize.QueryTypes.INSERT }
);
console.log('✅ "职位类型管理"菜单项添加成功!\n');
// 验证插入结果
const [menu] = await sequelize.query(
`SELECT id, name, parent_id, path, component, api_path, sort
FROM sys_menu
WHERE path = 'job_types' AND is_delete = 0`,
{ type: Sequelize.QueryTypes.SELECT }
);
if (menu) {
console.log('📋 菜单项详情:');
console.log(` 名称: ${menu.name}`);
console.log(` 父菜单ID: ${menu.parent_id}`);
console.log(` 路由路径: ${menu.path}`);
console.log(` 组件路径: ${menu.component}`);
console.log(` API路径: ${menu.api_path}`);
console.log(` 排序: ${menu.sort}\n`);
}
} catch (error) {
console.error('❌ 添加失败:', error.message);
console.error('\n详细错误:', error);
throw error;
}
}
// 执行添加
addJobTypesMenu()
.then(() => {
console.log('\n✨ 操作完成!');
process.exit(0);
})
.catch(error => {
console.error('\n💥 执行失败:', error);
process.exit(1);
});

View File

@@ -0,0 +1,120 @@
/**
* 同步 job_postings 表结构
* 用于创建或更新数据库表
*/
const Sequelize = require('sequelize');
// 加载配置
const config = require('../config/config');
const dbConfig = config.db;
async function syncJobPostingsTable() {
console.log('🔄 开始同步 job_postings 表结构...\n');
try {
// 创建 Sequelize 实例
const sequelize = new Sequelize(
dbConfig.database,
dbConfig.username,
dbConfig.password,
{
host: dbConfig.host,
port: dbConfig.port,
dialect: dbConfig.dialect,
logging: false
}
);
// 测试连接
await sequelize.authenticate();
console.log('✅ 数据库连接成功\n');
// 加载模型定义
const job_postings = require('../api/model/job_postings')(sequelize);
// 同步表结构alter: true 会自动添加缺失的字段,保留现有数据)
console.log('⚠️ 注意:使用 alter: true 模式同步(保留现有数据)');
console.log('如果需要完全重建表,请修改为 force: true\n');
await job_postings.sync({ alter: true });
console.log('✅ job_postings 表同步成功!\n');
// 显示表结构
const tableInfo = await sequelize.query(
`DESCRIBE job_postings`,
{ type: Sequelize.QueryTypes.SELECT }
);
console.log('📋 当前表结构:');
console.table(tableInfo.map(field => ({
字段名: field.Field,
类型: field.Type,
允许空: field.Null,
默认值: field.Default
})));
// 检查关键字段
const requiredFields = [
'id',
'sn_code',
'platform',
'keyword',
'encryptBossId',
'jobId',
'jobTitle',
'companyId',
'companyName',
'companySize',
'companyIndustry',
'salary',
'jobRequirements',
'jobDescription',
'location',
'experience',
'education',
'aiMatchScore',
'applyStatus',
'chatStatus',
'originalData'
];
const existingFields = tableInfo.map(f => f.Field);
console.log('\n🔍 检查关键字段:');
const missingFields = [];
requiredFields.forEach(field => {
const exists = existingFields.includes(field);
console.log(` ${exists ? '✅' : '❌'} ${field}`);
if (!exists) {
missingFields.push(field);
}
});
if (missingFields.length > 0) {
console.log('\n⚠ 缺少以下字段:', missingFields.join(', '));
console.log('建议:重新运行同步或手动添加这些字段');
} else {
console.log('\n✅ 所有必需字段都存在!');
}
// 关闭连接
await sequelize.close();
} catch (error) {
console.error('❌ 同步失败:', error.message);
console.error('\n详细错误:', error);
}
}
// 执行同步
syncJobPostingsTable()
.then(() => {
console.log('\n✨ 同步完成!');
process.exit(0);
})
.catch(error => {
console.error('\n💥 执行失败:', error);
process.exit(1);
});

97
scripts/sync_job_types.js Normal file
View File

@@ -0,0 +1,97 @@
/**
* 同步职位类型表结构
* 创建 job_types 表并添加 job_type_id 字段到 pla_account 表
*/
const Framework = require('../framework/node-core-framework.js');
const frameworkConfig = require('../config/framework.config.js');
async function syncJobTypes() {
try {
console.log('[同步职位类型] 开始同步...');
// 初始化框架
await Framework.init(frameworkConfig);
const models = Framework.getModels();
const { job_types, pla_account } = models;
if (!job_types) {
throw new Error('无法获取 job_types 模型');
}
if (!pla_account) {
throw new Error('无法获取 pla_account 模型');
}
// 从模型获取 sequelize 实例
const sequelize = job_types.sequelize;
if (!sequelize) {
throw new Error('无法获取 sequelize 实例');
}
// 1. 同步 job_types 表
console.log('[同步职位类型] 同步 job_types 表...');
await job_types.sync({ alter: true });
console.log('[同步职位类型] job_types 表同步完成');
// 2. 同步 pla_account 表(会自动添加 job_type_id 字段)
console.log('[同步职位类型] 同步 pla_account 表...');
await pla_account.sync({ alter: true });
console.log('[同步职位类型] pla_account 表同步完成');
// 3. 检查 pla_account 表是否有 job_type_id 字段
console.log('[同步职位类型] 检查 pla_account 表结构...');
const Sequelize = require('sequelize');
const tableInfo = await sequelize.query("DESCRIBE pla_account", { type: Sequelize.QueryTypes.SELECT });
const hasJobTypeId = Array.isArray(tableInfo) && tableInfo.some(field => field.Field === 'job_type_id');
if (hasJobTypeId) {
console.log('[同步职位类型] ✅ pla_account 表已存在 job_type_id 字段');
} else {
console.log('[同步职位类型] ⚠️ pla_account 表未找到 job_type_id 字段,可能需要手动添加');
}
// 4. 显示表结构
console.log('\n[同步职位类型] job_types 表结构:');
const jobTypesInfo = await sequelize.query("DESCRIBE job_types", { type: Sequelize.QueryTypes.SELECT });
if (Array.isArray(jobTypesInfo)) {
console.table(jobTypesInfo.map(field => ({
字段名: field.Field,
类型: field.Type,
允许空: field.Null,
: field.Key,
默认值: field.Default,
注释: field.Comment || ''
})));
}
console.log('\n[同步职位类型] pla_account 表 job_type_id 字段:');
const plaAccountInfo = await sequelize.query("DESCRIBE pla_account", { type: Sequelize.QueryTypes.SELECT });
if (Array.isArray(plaAccountInfo)) {
const jobTypeIdField = plaAccountInfo.find(field => field.Field === 'job_type_id');
if (jobTypeIdField) {
console.table([{
字段名: jobTypeIdField.Field,
类型: jobTypeIdField.Type,
允许空: jobTypeIdField.Null,
: jobTypeIdField.Key,
默认值: jobTypeIdField.Default,
注释: jobTypeIdField.Comment || ''
}]);
} else {
console.log(' ⚠️ 未找到 job_type_id 字段');
}
}
console.log('\n[同步职位类型] 同步完成!');
process.exit(0);
} catch (error) {
console.error('[同步职位类型] 同步失败:', error);
process.exit(1);
}
}
// 执行同步
syncJobTypes();

View File

@@ -0,0 +1,117 @@
/**
* 同步 pla_account 表的新字段
* 添加自动投递、自动沟通、自动活跃等配置字段
*/
const Framework = require('../framework/node-core-framework.js');
const frameworkConfig = require('../config/framework.config.js');
async function syncPlaAccountFields() {
console.log('🔄 开始同步 pla_account 表字段...\n');
try {
// 初始化框架
console.log('正在初始化框架...');
const framework = await Framework.init(frameworkConfig);
const models = Framework.getModels();
if (!models) {
throw new Error('无法获取模型列表');
}
// 从任意模型获取 sequelize 实例
const Sequelize = require('sequelize');
const firstModel = Object.values(models)[0];
if (!firstModel || !firstModel.sequelize) {
throw new Error('无法获取数据库连接');
}
const sequelize = firstModel.sequelize;
// 获取 pla_account 模型
const pla_account = models.pla_account;
if (!pla_account) {
throw new Error('无法获取 pla_account 模型');
}
console.log('正在同步表结构(使用 alter: true 模式,保留现有数据)...\n');
await pla_account.sync({ alter: true });
console.log('✅ pla_account 表同步成功!\n');
// 显示表结构
const tableInfo = await sequelize.query(
`DESCRIBE pla_account`,
{ type: Sequelize.QueryTypes.SELECT }
);
console.log('📋 当前表结构:');
console.table(tableInfo.map(field => ({
字段名: field.Field,
类型: field.Type,
允许空: field.Null,
默认值: field.Default,
注释: field.Comment || ''
})));
// 检查新增字段
const newFields = [
'auto_deliver',
'page_count',
'max_deliver',
'min_salary',
'max_salary',
'filter_keywords',
'exclude_keywords',
'auto_chat',
'chat_interval',
'auto_reply',
'chat_strategy',
'auto_active',
'active_interval',
'active_actions'
];
const existingFields = tableInfo.map(f => f.Field);
console.log('\n🔍 检查新增字段:');
const missingFields = [];
newFields.forEach(field => {
const exists = existingFields.includes(field);
console.log(` ${exists ? '✅' : '❌'} ${field}`);
if (!exists) {
missingFields.push(field);
}
});
if (missingFields.length > 0) {
console.log('\n⚠ 以下字段未添加:', missingFields.join(', '));
console.log('建议:重新运行同步或手动添加这些字段');
} else {
console.log('\n✅ 所有新增字段都已存在!');
}
// 显示字段统计
console.log('\n📊 字段统计:');
console.log(` 总字段数: ${existingFields.length}`);
console.log(` 自动投递相关: ${newFields.filter(f => ['auto_deliver', 'page_count', 'max_deliver', 'min_salary', 'max_salary', 'filter_keywords', 'exclude_keywords'].includes(f) && existingFields.includes(f)).length}/7`);
console.log(` 自动沟通相关: ${newFields.filter(f => ['auto_chat', 'chat_interval', 'auto_reply', 'chat_strategy'].includes(f) && existingFields.includes(f)).length}/4`);
console.log(` 自动活跃相关: ${newFields.filter(f => ['auto_active', 'active_interval', 'active_actions'].includes(f) && existingFields.includes(f)).length}/3`);
} catch (error) {
console.error('❌ 同步失败:', error.message);
console.error('\n详细错误:', error);
throw error;
}
}
// 执行同步
syncPlaAccountFields()
.then(() => {
console.log('\n✨ 同步完成!');
process.exit(0);
})
.catch(error => {
console.error('\n💥 执行失败:', error);
process.exit(1);
});

View File

@@ -0,0 +1,67 @@
const Framework = require('../framework/node-core-framework.js');
const frameworkConfig = require('../config/framework.config.js');
const Sequelize = require('sequelize');
async function syncPlaAccountIsEnabled() {
console.log('🔄 开始同步 pla_account 表 is_enabled 字段...\n');
try {
const framework = await Framework.init(frameworkConfig);
const models = Framework.getModels();
if (!models) {
throw new Error('无法获取模型列表');
}
const pla_account = models.pla_account;
if (!pla_account) {
throw new Error('无法获取 pla_account 模型');
}
console.log('正在同步表结构(使用 alter: true 模式,保留现有数据)...\n');
await pla_account.sync({ alter: true });
console.log('✅ pla_account 表同步成功!\n');
// 显示表结构
const sequelize = pla_account.sequelize;
const tableInfo = await sequelize.query(
`DESCRIBE pla_account`,
{ type: Sequelize.QueryTypes.SELECT }
);
console.table(tableInfo.map(field => ({
字段名: field.Field,
类型: field.Type,
允许空: field.Null,
默认值: field.Default,
注释: field.Comment || ''
})));
// 检查 is_enabled 字段是否存在
const isEnabledField = tableInfo.find(field => field.Field === 'is_enabled');
if (isEnabledField) {
console.log('\n✅ is_enabled 字段已存在');
console.log(` 类型: ${isEnabledField.Type}`);
console.log(` 默认值: ${isEnabledField.Default}`);
console.log(` 注释: ${isEnabledField.Comment || '无'}\n`);
} else {
console.warn('\n⚠ is_enabled 字段不存在,可能需要手动添加\n');
}
} catch (error) {
console.error('❌ 同步失败:', error.message);
console.error('\n详细错误:', error);
throw error;
}
}
syncPlaAccountIsEnabled()
.then(() => {
console.log('✅ 同步完成');
process.exit(0);
})
.catch(error => {
console.error('❌ 同步失败');
process.exit(1);
});

View File

@@ -0,0 +1,105 @@
/**
* 同步 resume_info 表结构
* 用于创建或更新数据库表
*/
const db = require('../api/middleware/dbProxy');
async function syncResumeTable() {
console.log('🔄 开始同步 resume_info 表结构...\n');
try {
// 获取模型
const resume_info = db.getModel('resume_info');
if (!resume_info) {
console.error('❌ 无法获取 resume_info 模型');
return;
}
// 同步表结构force: true 会删除并重建表,慎用!)
// 如果表已存在且有数据,请使用 alter: true
console.log('⚠️ 注意:使用 alter: true 模式同步(保留现有数据)');
console.log('如果需要完全重建表,请修改为 force: true\n');
await resume_info.sync({ alter: true });
console.log('✅ resume_info 表同步成功!\n');
// 显示表结构
const tableInfo = await db.models.sequelize.query(
`DESCRIBE resume_info`,
{ type: db.models.sequelize.QueryTypes.SELECT }
);
console.log('📋 当前表结构:');
console.table(tableInfo.map(field => ({
字段名: field.Field,
类型: field.Type,
允许空: field.Null,
默认值: field.Default
})));
// 检查关键字段
const requiredFields = [
'id',
'sn_code',
'account_id',
'platform',
'fullName',
'gender',
'age',
'phone',
'email',
'education',
'workYears',
'expectedPosition',
'expectedSalary',
'skills',
'projectExperience',
'workExperience',
'aiSkillTags',
'aiStrengths',
'aiWeaknesses',
'aiCareerSuggestion',
'aiCompetitiveness',
'originalData',
'isActive',
'syncTime'
];
const existingFields = tableInfo.map(f => f.Field);
console.log('\n🔍 检查关键字段:');
const missingFields = [];
requiredFields.forEach(field => {
const exists = existingFields.includes(field);
console.log(` ${exists ? '✅' : '❌'} ${field}`);
if (!exists) {
missingFields.push(field);
}
});
if (missingFields.length > 0) {
console.log('\n⚠ 缺少以下字段:', missingFields.join(', '));
console.log('建议:重新运行同步或手动添加这些字段');
} else {
console.log('\n✅ 所有必需字段都存在!');
}
} catch (error) {
console.error('❌ 同步失败:', error.message);
console.error('\n详细错误:', error);
}
}
// 执行同步
syncResumeTable()
.then(() => {
console.log('\n✨ 同步完成!');
process.exit(0);
})
.catch(error => {
console.error('\n💥 执行失败:', error);
process.exit(1);
});