feat: 完成多多畅职就业服务平台核心功能开发
主要更新: - ✅ 完成主题配色从暗色到亮蓝白配色的全面转换 - ✅ 实现高薪岗位页面及后端API集成 - ✅ 完成登录注册页面及认证系统 - ✅ 实现预招录确认功能 - ✅ 添加数据库管理和维护工具脚本 - ✅ 优化错误处理和用户体验 核心功能: 1. 首页 (index.html) - 3D地球、专业分类、过渡岗位 2. 高薪岗位页面 (high.html) - 岗位详情、预招录确认、成功案例 3. 登录注册 (auth.html) - 用户认证、专业分类选择 4. 后端API - RESTful接口,JWT认证,MySQL数据库 技术栈: - 前端:Three.js, GSAP, 原生JavaScript - 后端:Node.js, Express, MySQL - 认证:JWT, bcrypt - 样式:自定义CSS,响应式设计 数据库工具: - kill-by-ids.js - 批量终止MySQL进程 - unlock-all-tables.js - 解锁数据库表 - init-db.js - 初始化数据库 - 其他管理脚本 🤖 Generated with Claude Code Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
110
scripts/add-professional-category.js
Normal file
110
scripts/add-professional-category.js
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 数据库迁移脚本:添加专业大类字段
|
||||
* 执行方式: node scripts/add-professional-category.js
|
||||
*/
|
||||
|
||||
const mysql = require('mysql2/promise');
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
|
||||
// 数据库配置
|
||||
const dbConfig = {
|
||||
host: '123.60.55.248',
|
||||
port: 3306,
|
||||
user: 'ddcz_bitmap',
|
||||
password: 'EyTimzFHa8YfYEfY',
|
||||
database: 'ddcz_bitmap'
|
||||
};
|
||||
|
||||
async function runMigration() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🔄 连接数据库...');
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 数据库连接成功\n');
|
||||
|
||||
// 执行ALTER TABLE添加字段
|
||||
console.log('🔧 执行ALTER TABLE添加专业大类字段...');
|
||||
const alterSQL = `
|
||||
ALTER TABLE \`user_profiles\`
|
||||
ADD COLUMN \`professional_category\` VARCHAR(100) DEFAULT NULL COMMENT '专业大类名称' AFTER \`major\`,
|
||||
ADD COLUMN \`professional_category_code\` VARCHAR(20) DEFAULT NULL COMMENT '专业大类代码' AFTER \`professional_category\`
|
||||
`;
|
||||
|
||||
try {
|
||||
await connection.query(alterSQL);
|
||||
console.log('✅ 字段添加成功\n');
|
||||
} catch (alterError) {
|
||||
if (alterError.code === 'ER_DUP_FIELDNAME') {
|
||||
console.log('⚠️ 字段已存在,跳过添加\n');
|
||||
} else {
|
||||
throw alterError;
|
||||
}
|
||||
}
|
||||
|
||||
// 验证字段添加
|
||||
console.log('🔍 验证字段添加...');
|
||||
const [rows] = await connection.query(`
|
||||
SELECT COLUMN_NAME, COLUMN_TYPE, COLUMN_COMMENT
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'ddcz_bitmap'
|
||||
AND TABLE_NAME = 'user_profiles'
|
||||
AND COLUMN_NAME IN ('professional_category', 'professional_category_code')
|
||||
`);
|
||||
|
||||
if (rows.length === 2) {
|
||||
console.log('✅ 验证成功!新增字段如下:\n');
|
||||
rows.forEach(row => {
|
||||
console.log(` - ${row.COLUMN_NAME}: ${row.COLUMN_TYPE}`);
|
||||
console.log(` 注释: ${row.COLUMN_COMMENT}\n`);
|
||||
});
|
||||
} else {
|
||||
console.log(`⚠️ 警告:预期找到2个字段,实际找到 ${rows.length} 个`);
|
||||
}
|
||||
|
||||
console.log('🎉 数据库迁移完成!\n');
|
||||
|
||||
// 显示当前user_profiles表的所有字段
|
||||
console.log('📋 user_profiles 表当前所有字段:\n');
|
||||
const [columns] = await connection.query(`
|
||||
SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'ddcz_bitmap'
|
||||
AND TABLE_NAME = 'user_profiles'
|
||||
ORDER BY ORDINAL_POSITION
|
||||
`);
|
||||
|
||||
columns.forEach(col => {
|
||||
console.log(` ${col.COLUMN_NAME.padEnd(30)} ${col.COLUMN_TYPE.padEnd(20)} ${col.COLUMN_COMMENT || ''}`);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('\n❌ 迁移失败:', error.message);
|
||||
|
||||
if (error.code === 'ER_DUP_FIELDNAME') {
|
||||
console.log('\n💡 提示:字段已存在,无需重复添加');
|
||||
} else if (error.code === 'ECONNREFUSED') {
|
||||
console.log('\n💡 提示:无法连接到数据库,请检查:');
|
||||
console.log(' 1. 数据库服务器是否运行');
|
||||
console.log(' 2. 网络连接是否正常');
|
||||
console.log(' 3. 数据库配置是否正确');
|
||||
} else {
|
||||
console.log('\n💡 提示:请检查错误信息并修正后重试');
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('\n🔌 数据库连接已关闭');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行迁移
|
||||
console.log('='.repeat(60));
|
||||
console.log('数据库迁移:添加专业大类字段');
|
||||
console.log('='.repeat(60));
|
||||
|
||||
runMigration();
|
||||
13
scripts/add-professional-category.sql
Normal file
13
scripts/add-professional-category.sql
Normal file
@@ -0,0 +1,13 @@
|
||||
-- 添加专业大类字段到 user_profiles 表
|
||||
-- 执行日期: 2025-12-08
|
||||
|
||||
ALTER TABLE `user_profiles`
|
||||
ADD COLUMN `professional_category` VARCHAR(100) DEFAULT NULL COMMENT '专业大类名称' AFTER `major`,
|
||||
ADD COLUMN `professional_category_code` VARCHAR(20) DEFAULT NULL COMMENT '专业大类代码' AFTER `professional_category`;
|
||||
|
||||
-- 验证字段添加成功
|
||||
SELECT COLUMN_NAME, COLUMN_TYPE, COLUMN_COMMENT
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'ddcz_bitmap'
|
||||
AND TABLE_NAME = 'user_profiles'
|
||||
AND COLUMN_NAME IN ('professional_category', 'professional_category_code');
|
||||
87
scripts/create-admin.js
Normal file
87
scripts/create-admin.js
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 创建默认管理员账号
|
||||
* 在数据库和表已经创建后运行此脚本
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
// 数据库配置
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE || 'ddcz_platform'
|
||||
};
|
||||
|
||||
async function createAdminUser() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🔌 正在连接到MySQL数据库...');
|
||||
console.log(` 数据库: ${dbConfig.database}`);
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 数据库连接成功!\n');
|
||||
|
||||
// 生成管理员密码哈希
|
||||
console.log('🔐 正在生成管理员密码...');
|
||||
const defaultPassword = 'admin123456';
|
||||
const passwordHash = await bcrypt.hash(defaultPassword, 10);
|
||||
console.log('✅ 密码哈希生成成功!\n');
|
||||
|
||||
// 插入或更新管理员账号
|
||||
console.log('👤 正在创建管理员账号...');
|
||||
const [result] = await connection.query(`
|
||||
INSERT INTO users (username, password_hash, email, role, status)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
password_hash = VALUES(password_hash),
|
||||
email = VALUES(email),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
`, ['admin', passwordHash, 'admin@ddcz.com', 'admin', 'active']);
|
||||
|
||||
if (result.affectedRows > 0) {
|
||||
console.log('✅ 管理员账号创建/更新成功!\n');
|
||||
console.log('📝 管理员登录信息:');
|
||||
console.log(' 用户名: admin');
|
||||
console.log(' 密码: admin123456');
|
||||
console.log(' ⚠️ 请在首次登录后立即修改密码!\n');
|
||||
}
|
||||
|
||||
// 验证表是否存在
|
||||
console.log('📊 验证数据库表...');
|
||||
const [tables] = await connection.query('SHOW TABLES');
|
||||
console.log(`✅ 数据库中共有 ${tables.length} 个表:`);
|
||||
tables.forEach(table => {
|
||||
const tableName = Object.values(table)[0];
|
||||
console.log(` - ${tableName}`);
|
||||
});
|
||||
|
||||
console.log('\n🎉 管理员账号设置完成!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('\n❌ 操作失败:');
|
||||
console.error(error.message);
|
||||
|
||||
if (error.code === 'ECONNREFUSED') {
|
||||
console.error('\n💡 无法连接到MySQL服务器');
|
||||
} else if (error.code === 'ER_ACCESS_DENIED_ERROR') {
|
||||
console.error('\n💡 用户名或密码错误');
|
||||
} else if (error.code === 'ER_NO_SUCH_TABLE') {
|
||||
console.error('\n💡 表不存在,请先在Navicat中执行 database-setup.sql');
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 数据库连接已关闭');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行
|
||||
createAdminUser();
|
||||
27
scripts/create-database.sql
Normal file
27
scripts/create-database.sql
Normal file
@@ -0,0 +1,27 @@
|
||||
-- ========================================
|
||||
-- 多多畅职平台 - 手动创建数据库脚本
|
||||
-- ========================================
|
||||
-- 使用说明:
|
||||
-- 1. 在Navicat中连接到MySQL服务器(使用root或其他管理员账号)
|
||||
-- 2. 打开查询窗口,粘贴并执行此脚本
|
||||
-- 3. 执行完成后,再运行项目的 npm run init-db
|
||||
-- ========================================
|
||||
|
||||
-- 创建数据库
|
||||
CREATE DATABASE IF NOT EXISTS `ddcz_platform`
|
||||
DEFAULT CHARACTER SET utf8mb4
|
||||
COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- 授予 ddcz_bitmap 用户对该数据库的所有权限
|
||||
GRANT ALL PRIVILEGES ON `ddcz_platform`.* TO 'ddcz_bitmap'@'%';
|
||||
|
||||
-- 刷新权限
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
-- 验证权限
|
||||
SHOW GRANTS FOR 'ddcz_bitmap'@'%';
|
||||
|
||||
-- 提示信息
|
||||
SELECT '✅ 数据库创建成功!' AS message;
|
||||
SELECT '✅ 权限授予成功!' AS message;
|
||||
SELECT '📌 下一步:在项目中运行 npm run init-db' AS next_step;
|
||||
143
scripts/database-setup.sql
Normal file
143
scripts/database-setup.sql
Normal file
@@ -0,0 +1,143 @@
|
||||
-- ========================================
|
||||
-- 多多畅职平台 - 完整数据库初始化SQL脚本
|
||||
-- ========================================
|
||||
-- 使用说明:
|
||||
-- 1. 在Navicat中使用root或管理员账号连接MySQL
|
||||
-- 2. 打开此SQL文件,点击"运行"执行整个脚本
|
||||
-- 3. 执行完成后即可使用
|
||||
-- ========================================
|
||||
|
||||
-- 创建数据库
|
||||
CREATE DATABASE IF NOT EXISTS `ddcz_platform`
|
||||
DEFAULT CHARACTER SET utf8mb4
|
||||
COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- 使用数据库
|
||||
USE `ddcz_platform`;
|
||||
|
||||
-- ========================================
|
||||
-- 表1: users(用户表)
|
||||
-- ========================================
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
||||
`username` VARCHAR(50) NOT NULL COMMENT '用户名',
|
||||
`password_hash` VARCHAR(255) NOT NULL COMMENT '密码哈希',
|
||||
`email` VARCHAR(100) DEFAULT NULL COMMENT '邮箱',
|
||||
`phone` VARCHAR(20) DEFAULT NULL COMMENT '手机号',
|
||||
`role` ENUM('user', 'admin') NOT NULL DEFAULT 'user' COMMENT '用户角色',
|
||||
`status` ENUM('active', 'inactive', 'banned') NOT NULL DEFAULT 'active' COMMENT '账号状态',
|
||||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`last_login` TIMESTAMP NULL DEFAULT NULL COMMENT '最后登录时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `unique_username` (`username`),
|
||||
UNIQUE KEY `unique_email` (`email`),
|
||||
UNIQUE KEY `unique_phone` (`phone`),
|
||||
KEY `idx_username` (`username`),
|
||||
KEY `idx_email` (`email`),
|
||||
KEY `idx_role` (`role`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';
|
||||
|
||||
-- ========================================
|
||||
-- 表2: user_profiles(用户资料表)
|
||||
-- ========================================
|
||||
CREATE TABLE IF NOT EXISTS `user_profiles` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT COMMENT '资料ID',
|
||||
`user_id` INT NOT NULL COMMENT '用户ID',
|
||||
`real_name` VARCHAR(50) DEFAULT NULL COMMENT '真实姓名',
|
||||
`gender` ENUM('male', 'female', 'other') DEFAULT NULL COMMENT '性别',
|
||||
`birth_date` DATE DEFAULT NULL COMMENT '出生日期',
|
||||
`id_card` VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
|
||||
`education` VARCHAR(50) DEFAULT NULL COMMENT '学历',
|
||||
`major` VARCHAR(100) DEFAULT NULL COMMENT '专业',
|
||||
`school` VARCHAR(100) DEFAULT NULL COMMENT '学校',
|
||||
`graduation_year` YEAR DEFAULT NULL COMMENT '毕业年份',
|
||||
`city` VARCHAR(50) DEFAULT NULL COMMENT '所在城市',
|
||||
`address` TEXT DEFAULT NULL COMMENT '详细地址',
|
||||
`avatar_url` VARCHAR(255) DEFAULT NULL COMMENT '头像URL',
|
||||
`resume_url` VARCHAR(255) DEFAULT NULL COMMENT '简历URL',
|
||||
`self_intro` TEXT DEFAULT NULL COMMENT '自我介绍',
|
||||
`skills` TEXT DEFAULT NULL COMMENT '技能标签(JSON数组)',
|
||||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `unique_user_id` (`user_id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
CONSTRAINT `fk_profile_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户资料表';
|
||||
|
||||
-- ========================================
|
||||
-- 表3: job_applications(投递记录表)
|
||||
-- ========================================
|
||||
CREATE TABLE IF NOT EXISTS `job_applications` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT COMMENT '投递记录ID',
|
||||
`user_id` INT NOT NULL COMMENT '用户ID',
|
||||
`job_type` ENUM('transition', 'referral') NOT NULL COMMENT '岗位类型:transition-过渡岗位, referral-内推岗位',
|
||||
`job_name` VARCHAR(100) NOT NULL COMMENT '岗位名称',
|
||||
`company_name` VARCHAR(100) NOT NULL COMMENT '企业名称',
|
||||
`company_short_name` VARCHAR(50) DEFAULT NULL COMMENT '企业简称',
|
||||
`city` VARCHAR(50) DEFAULT NULL COMMENT '城市',
|
||||
`province` VARCHAR(50) DEFAULT NULL COMMENT '省份',
|
||||
`segment_name` VARCHAR(100) DEFAULT NULL COMMENT '业务板块名称',
|
||||
`status` ENUM('pending', 'reviewing', 'interviewed', 'offered', 'rejected', 'withdrawn') NOT NULL DEFAULT 'pending' COMMENT '投递状态',
|
||||
`application_data` JSON DEFAULT NULL COMMENT '投递详细数据(岗位详情JSON)',
|
||||
`applied_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '投递时间',
|
||||
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`notes` TEXT DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_job_type` (`job_type`),
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_applied_at` (`applied_at`),
|
||||
CONSTRAINT `fk_application_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='投递记录表';
|
||||
|
||||
-- ========================================
|
||||
-- 表4: favorites(收藏表)
|
||||
-- ========================================
|
||||
CREATE TABLE IF NOT EXISTS `favorites` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT COMMENT '收藏ID',
|
||||
`user_id` INT NOT NULL COMMENT '用户ID',
|
||||
`favorite_type` ENUM('company', 'job') NOT NULL COMMENT '收藏类型',
|
||||
`company_name` VARCHAR(100) DEFAULT NULL COMMENT '企业名称',
|
||||
`job_name` VARCHAR(100) DEFAULT NULL COMMENT '岗位名称',
|
||||
`favorite_data` JSON DEFAULT NULL COMMENT '收藏详细数据',
|
||||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '收藏时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_type` (`favorite_type`),
|
||||
UNIQUE KEY `unique_favorite` (`user_id`, `favorite_type`, `company_name`, `job_name`),
|
||||
CONSTRAINT `fk_favorite_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='收藏表';
|
||||
|
||||
-- ========================================
|
||||
-- 插入默认管理员账号
|
||||
-- ========================================
|
||||
-- 注意:密码哈希需要在Node.js中生成
|
||||
-- 默认密码:admin123456
|
||||
-- 这里使用bcrypt哈希后的值(rounds=10)
|
||||
INSERT INTO `users` (`username`, `password_hash`, `email`, `role`, `status`)
|
||||
VALUES (
|
||||
'admin',
|
||||
'$2a$10$YourBcryptHashWillBeGeneratedByNodeJS',
|
||||
'admin@ddcz.com',
|
||||
'admin',
|
||||
'active'
|
||||
) ON DUPLICATE KEY UPDATE `username` = `username`;
|
||||
|
||||
-- ========================================
|
||||
-- 授予权限(如果需要)
|
||||
-- ========================================
|
||||
-- 如果您使用的是root账号创建的数据库,需要给 ddcz_bitmap 授权
|
||||
-- GRANT ALL PRIVILEGES ON `ddcz_platform`.* TO 'ddcz_bitmap'@'%';
|
||||
-- FLUSH PRIVILEGES;
|
||||
|
||||
-- ========================================
|
||||
-- 验证表创建
|
||||
-- ========================================
|
||||
SELECT '✅ 数据库创建完成!' AS message;
|
||||
SHOW TABLES;
|
||||
SELECT '✅ 以上是已创建的表' AS message;
|
||||
|
||||
-- 查看users表结构
|
||||
DESC `users`;
|
||||
117
scripts/fix-database-locks.js
Normal file
117
scripts/fix-database-locks.js
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* 修复数据库锁定问题 - 简化版
|
||||
* 分步骤执行,避免复杂查询导致临时表满
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
async function fixDatabaseLocks() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
connection = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT || 3306,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE
|
||||
});
|
||||
|
||||
console.log('✅ 已连接到数据库');
|
||||
|
||||
// 步骤1: 查找并终止所有waiting for handler commit的进程
|
||||
console.log('\n📋 步骤1: 查找锁定的进程...');
|
||||
const [processes] = await connection.query(
|
||||
"SELECT Id, State, Info FROM INFORMATION_SCHEMA.PROCESSLIST WHERE State LIKE '%waiting for handler commit%'"
|
||||
);
|
||||
|
||||
console.log(`找到 ${processes.length} 个锁定的进程`);
|
||||
|
||||
let killedCount = 0;
|
||||
for (const p of processes) {
|
||||
try {
|
||||
console.log(` 正在终止进程 ${p.Id}...`);
|
||||
await connection.query(`KILL ${p.Id}`);
|
||||
console.log(` ✅ 已终止进程 ${p.Id}`);
|
||||
killedCount++;
|
||||
} catch (err) {
|
||||
console.log(` ⚠️ 无法终止进程 ${p.Id}:`, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n✅ 成功终止 ${killedCount} 个锁定的进程`);
|
||||
|
||||
// 步骤2: 终止所有Sleep状态的连接
|
||||
console.log('\n📋 步骤2: 终止Sleep状态的连接...');
|
||||
const [allProcesses] = await connection.query('SHOW FULL PROCESSLIST');
|
||||
|
||||
let sleepKilled = 0;
|
||||
for (const p of allProcesses) {
|
||||
if (p.Command === 'Sleep' && p.Id !== connection.threadId) {
|
||||
try {
|
||||
await connection.query(`KILL ${p.Id}`);
|
||||
console.log(` ✅ 已终止Sleep进程 ${p.Id}`);
|
||||
sleepKilled++;
|
||||
} catch (err) {
|
||||
console.log(` ⚠️ 无法终止进程 ${p.Id}:`, err.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n✅ 成功终止 ${sleepKilled} 个Sleep连接`);
|
||||
|
||||
// 步骤3: 检查是否有重复的确认记录(使用简单查询)
|
||||
console.log('\n📋 步骤3: 检查重复记录...');
|
||||
const [allConfirmations] = await connection.query(
|
||||
'SELECT id, user_id, training_unit_id FROM training_confirmations ORDER BY user_id, training_unit_id, id'
|
||||
);
|
||||
|
||||
console.log(`总共有 ${allConfirmations.length} 条确认记录`);
|
||||
|
||||
// 找出重复的记录(在应用层处理,避免复杂SQL)
|
||||
const seen = new Map();
|
||||
const duplicates = [];
|
||||
|
||||
for (const record of allConfirmations) {
|
||||
const key = `${record.user_id}_${record.training_unit_id}`;
|
||||
if (seen.has(key)) {
|
||||
// 这是重复的,标记为要删除
|
||||
duplicates.push(record.id);
|
||||
} else {
|
||||
// 第一次见到,保留
|
||||
seen.set(key, record.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (duplicates.length > 0) {
|
||||
console.log(`\n发现 ${duplicates.length} 条重复记录,正在删除...`);
|
||||
for (const id of duplicates) {
|
||||
await connection.query('DELETE FROM training_confirmations WHERE id = ?', [id]);
|
||||
console.log(` ✅ 已删除重复记录 ID: ${id}`);
|
||||
}
|
||||
} else {
|
||||
console.log('✅ 没有发现重复记录');
|
||||
}
|
||||
|
||||
// 步骤4: 解锁所有表
|
||||
console.log('\n📋 步骤4: 解锁所有表...');
|
||||
await connection.query('UNLOCK TABLES');
|
||||
console.log('✅ 表已解锁');
|
||||
|
||||
console.log('\n✅ 所有操作完成!');
|
||||
console.log('\n💡 现在可以重新测试预招录确认功能了');
|
||||
console.log('\n建议:如果问题仍然存在,可能需要重启Node.js服务器以释放连接池');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 操作失败:', error.message);
|
||||
console.error('错误详情:', error);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fixDatabaseLocks();
|
||||
88
scripts/fix-locked-transaction.js
Normal file
88
scripts/fix-locked-transaction.js
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* 修复锁定的事务
|
||||
* 强制终止等待提交的进程
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
async function fixLockedTransaction() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
connection = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT || 3306,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE
|
||||
});
|
||||
|
||||
console.log('✅ 已连接到数据库');
|
||||
|
||||
// 1. 查找所有waiting for handler commit的进程
|
||||
console.log('\n📋 查找锁定的进程...');
|
||||
const [processes] = await connection.query(
|
||||
"SELECT Id, State, Info FROM INFORMATION_SCHEMA.PROCESSLIST WHERE State LIKE '%waiting for handler commit%'"
|
||||
);
|
||||
|
||||
console.log(`找到 ${processes.length} 个锁定的进程`);
|
||||
|
||||
// 2. 终止所有锁定的进程
|
||||
let killedCount = 0;
|
||||
for (const p of processes) {
|
||||
try {
|
||||
console.log(` 正在终止进程 ${p.Id}: ${p.Info?.substring(0, 100)}...`);
|
||||
await connection.query(`KILL ${p.Id}`);
|
||||
console.log(` ✅ 已终止进程 ${p.Id}`);
|
||||
killedCount++;
|
||||
} catch (err) {
|
||||
console.log(` ⚠️ 无法终止进程 ${p.Id}:`, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n✅ 成功终止 ${killedCount} 个锁定的进程`);
|
||||
|
||||
// 3. 清理可能重复的确认记录
|
||||
console.log('\n🧹 清理可能的重复记录...');
|
||||
const [duplicates] = await connection.query(`
|
||||
SELECT user_id, training_unit_id, COUNT(*) as count
|
||||
FROM training_confirmations
|
||||
GROUP BY user_id, training_unit_id
|
||||
HAVING count > 1
|
||||
`);
|
||||
|
||||
if (duplicates.length > 0) {
|
||||
console.log(`发现 ${duplicates.length} 组重复记录,正在清理...`);
|
||||
for (const dup of duplicates) {
|
||||
// 保留最早的记录,删除其他
|
||||
await connection.query(`
|
||||
DELETE FROM training_confirmations
|
||||
WHERE user_id = ? AND training_unit_id = ?
|
||||
AND id NOT IN (
|
||||
SELECT id FROM (
|
||||
SELECT MIN(id) as id FROM training_confirmations
|
||||
WHERE user_id = ? AND training_unit_id = ?
|
||||
) as temp
|
||||
)
|
||||
`, [dup.user_id, dup.training_unit_id, dup.user_id, dup.training_unit_id]);
|
||||
console.log(` ✅ 清理了 user_id=${dup.user_id}, training_unit_id=${dup.training_unit_id} 的重复记录`);
|
||||
}
|
||||
} else {
|
||||
console.log('没有发现重复记录');
|
||||
}
|
||||
|
||||
console.log('\n✅ 所有操作完成!');
|
||||
console.log('\n💡 现在可以重新测试预招录确认功能了');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 操作失败:', error.message);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fixLockedTransaction();
|
||||
18
scripts/grant-permissions.sql
Normal file
18
scripts/grant-permissions.sql
Normal file
@@ -0,0 +1,18 @@
|
||||
-- ========================================
|
||||
-- 授予 ddcz_bitmap 用户对 ddcz_platform 数据库的权限
|
||||
-- ========================================
|
||||
-- 请使用 root 或管理员账号在 Navicat 中执行此脚本
|
||||
-- ========================================
|
||||
|
||||
-- 授予 ddcz_bitmap 对 ddcz_platform 数据库的所有权限
|
||||
GRANT ALL PRIVILEGES ON `ddcz_platform`.* TO 'ddcz_bitmap'@'%';
|
||||
|
||||
-- 刷新权限,使其立即生效
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
-- 验证权限是否授予成功
|
||||
SHOW GRANTS FOR 'ddcz_bitmap'@'%';
|
||||
|
||||
-- 提示信息
|
||||
SELECT '✅ 权限授予成功!' AS message;
|
||||
SELECT '📌 现在可以运行: node scripts/test-permissions.js' AS next_step;
|
||||
209
scripts/init-db.js
Normal file
209
scripts/init-db.js
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* 数据库初始化脚本
|
||||
* 创建数据库和表结构
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
// 数据库配置
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD
|
||||
};
|
||||
|
||||
// 数据库名称
|
||||
const DATABASE_NAME = process.env.DB_DATABASE || 'ddcz_platform';
|
||||
|
||||
async function initDatabase() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🔌 正在连接到MySQL服务器...');
|
||||
console.log(` 主机: ${dbConfig.host}:${dbConfig.port}`);
|
||||
console.log(` 用户: ${dbConfig.user}`);
|
||||
|
||||
// 连接到MySQL服务器(不指定数据库)
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ MySQL连接成功!\n');
|
||||
|
||||
// 创建数据库(如果不存在)
|
||||
console.log(`📦 创建数据库: ${DATABASE_NAME}...`);
|
||||
await connection.query(`CREATE DATABASE IF NOT EXISTS \`${DATABASE_NAME}\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`);
|
||||
console.log('✅ 数据库创建成功!\n');
|
||||
|
||||
// 切换到目标数据库
|
||||
await connection.query(`USE \`${DATABASE_NAME}\``);
|
||||
|
||||
// ========================================
|
||||
// 清理旧表(如果存在)
|
||||
// ========================================
|
||||
console.log('🧹 清理可能存在的旧表...');
|
||||
await connection.query('DROP TABLE IF EXISTS `ddcz_platform`');
|
||||
await connection.query('DROP TABLE IF EXISTS `favorites`');
|
||||
await connection.query('DROP TABLE IF EXISTS `job_applications`');
|
||||
await connection.query('DROP TABLE IF EXISTS `user_profiles`');
|
||||
await connection.query('DROP TABLE IF EXISTS `users`');
|
||||
console.log('✅ 旧表清理完成!\n');
|
||||
|
||||
// ========================================
|
||||
// 创建 users 表 - 用户基本信息
|
||||
// ========================================
|
||||
console.log('📋 创建 users 表...');
|
||||
await connection.query(`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID',
|
||||
username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名',
|
||||
password_hash VARCHAR(255) NOT NULL COMMENT '密码哈希',
|
||||
email VARCHAR(100) UNIQUE COMMENT '邮箱',
|
||||
phone VARCHAR(20) UNIQUE COMMENT '手机号',
|
||||
role ENUM('user', 'admin') DEFAULT 'user' COMMENT '用户角色',
|
||||
status ENUM('active', 'inactive', 'banned') DEFAULT 'active' COMMENT '账号状态',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
last_login TIMESTAMP NULL COMMENT '最后登录时间',
|
||||
INDEX idx_username (username),
|
||||
INDEX idx_email (email),
|
||||
INDEX idx_role (role)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表'
|
||||
`);
|
||||
console.log('✅ users 表创建成功!');
|
||||
|
||||
// ========================================
|
||||
// 创建 user_profiles 表 - 用户详细资料
|
||||
// ========================================
|
||||
console.log('📋 创建 user_profiles 表...');
|
||||
await connection.query(`
|
||||
CREATE TABLE IF NOT EXISTS user_profiles (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '资料ID',
|
||||
user_id INT NOT NULL UNIQUE COMMENT '用户ID',
|
||||
real_name VARCHAR(50) COMMENT '真实姓名',
|
||||
gender ENUM('male', 'female', 'other') COMMENT '性别',
|
||||
birth_date DATE COMMENT '出生日期',
|
||||
id_card VARCHAR(18) COMMENT '身份证号',
|
||||
education VARCHAR(50) COMMENT '学历',
|
||||
major VARCHAR(100) COMMENT '专业',
|
||||
school VARCHAR(100) COMMENT '学校',
|
||||
graduation_year YEAR COMMENT '毕业年份',
|
||||
city VARCHAR(50) COMMENT '所在城市',
|
||||
address TEXT COMMENT '详细地址',
|
||||
avatar_url VARCHAR(255) COMMENT '头像URL',
|
||||
resume_url VARCHAR(255) COMMENT '简历URL',
|
||||
self_intro TEXT COMMENT '自我介绍',
|
||||
skills TEXT COMMENT '技能标签(JSON数组)',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
INDEX idx_user_id (user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户资料表'
|
||||
`);
|
||||
console.log('✅ user_profiles 表创建成功!');
|
||||
|
||||
// ========================================
|
||||
// 创建 job_applications 表 - 投递记录
|
||||
// ========================================
|
||||
console.log('📋 创建 job_applications 表...');
|
||||
await connection.query(`
|
||||
CREATE TABLE IF NOT EXISTS job_applications (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '投递记录ID',
|
||||
user_id INT NOT NULL COMMENT '用户ID',
|
||||
job_type ENUM('transition', 'referral') NOT NULL COMMENT '岗位类型:transition-过渡岗位, referral-内推岗位',
|
||||
job_name VARCHAR(100) NOT NULL COMMENT '岗位名称',
|
||||
company_name VARCHAR(100) NOT NULL COMMENT '企业名称',
|
||||
company_short_name VARCHAR(50) COMMENT '企业简称',
|
||||
city VARCHAR(50) COMMENT '城市',
|
||||
province VARCHAR(50) COMMENT '省份',
|
||||
segment_name VARCHAR(100) COMMENT '业务板块名称',
|
||||
status ENUM('pending', 'reviewing', 'interviewed', 'offered', 'rejected', 'withdrawn') DEFAULT 'pending' COMMENT '投递状态',
|
||||
application_data JSON COMMENT '投递详细数据(岗位详情JSON)',
|
||||
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '投递时间',
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
notes TEXT COMMENT '备注',
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_job_type (job_type),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_applied_at (applied_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='投递记录表'
|
||||
`);
|
||||
console.log('✅ job_applications 表创建成功!');
|
||||
|
||||
// ========================================
|
||||
// 创建 favorites 表 - 收藏夹
|
||||
// ========================================
|
||||
console.log('📋 创建 favorites 表...');
|
||||
await connection.query(`
|
||||
CREATE TABLE IF NOT EXISTS favorites (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '收藏ID',
|
||||
user_id INT NOT NULL COMMENT '用户ID',
|
||||
favorite_type ENUM('company', 'job') NOT NULL COMMENT '收藏类型',
|
||||
company_name VARCHAR(100) COMMENT '企业名称',
|
||||
job_name VARCHAR(100) COMMENT '岗位名称',
|
||||
favorite_data JSON COMMENT '收藏详细数据',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '收藏时间',
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_type (favorite_type),
|
||||
UNIQUE KEY unique_favorite (user_id, favorite_type, company_name, job_name)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='收藏表'
|
||||
`);
|
||||
console.log('✅ favorites 表创建成功!');
|
||||
|
||||
// ========================================
|
||||
// 创建默认管理员账号
|
||||
// ========================================
|
||||
console.log('\n👤 创建默认管理员账号...');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const defaultPassword = 'admin123456';
|
||||
const passwordHash = await bcrypt.hash(defaultPassword, 10);
|
||||
|
||||
await connection.query(`
|
||||
INSERT INTO users (username, password_hash, email, role, status)
|
||||
VALUES ('admin', ?, 'admin@ddcz.com', 'admin', 'active')
|
||||
ON DUPLICATE KEY UPDATE username=username
|
||||
`, [passwordHash]);
|
||||
|
||||
console.log('✅ 默认管理员账号创建成功!');
|
||||
console.log(' 用户名: admin');
|
||||
console.log(' 密码: admin123456');
|
||||
console.log(' ⚠️ 请在首次登录后立即修改密码!\n');
|
||||
|
||||
// ========================================
|
||||
// 显示表结构信息
|
||||
// ========================================
|
||||
console.log('📊 数据库表统计:');
|
||||
const [tables] = await connection.query('SHOW TABLES');
|
||||
console.log(` 共创建 ${tables.length} 个表:`);
|
||||
tables.forEach(table => {
|
||||
const tableName = Object.values(table)[0];
|
||||
console.log(` - ${tableName}`);
|
||||
});
|
||||
|
||||
console.log('\n🎉 数据库初始化完成!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('\n❌ 数据库初始化失败:');
|
||||
console.error(error.message);
|
||||
|
||||
if (error.code === 'ECONNREFUSED') {
|
||||
console.error('\n💡 提示:无法连接到MySQL服务器,请检查:');
|
||||
console.error(' 1. MySQL服务器是否正在运行');
|
||||
console.error(' 2. 主机地址和端口是否正确');
|
||||
console.error(' 3. 防火墙是否允许连接');
|
||||
} else if (error.code === 'ER_ACCESS_DENIED_ERROR') {
|
||||
console.error('\n💡 提示:用户名或密码错误,请检查.env文件中的配置');
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 数据库连接已关闭');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行初始化
|
||||
initDatabase();
|
||||
341
scripts/init-high-page-data.sql
Normal file
341
scripts/init-high-page-data.sql
Normal file
@@ -0,0 +1,341 @@
|
||||
-- ==========================================
|
||||
-- 高薪岗位页面数据库初始化脚本
|
||||
-- 基于high.html的最新数据结构
|
||||
-- 包含所有测试数据
|
||||
-- ==========================================
|
||||
|
||||
USE ddcz_bitmap;
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ==========================================
|
||||
-- 1. 创建高薪岗位表
|
||||
-- ==========================================
|
||||
DROP TABLE IF EXISTS high_salary_jobs;
|
||||
CREATE TABLE high_salary_jobs (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
title VARCHAR(100) NOT NULL COMMENT '职位名称',
|
||||
salary VARCHAR(50) NOT NULL COMMENT '薪资范围',
|
||||
company VARCHAR(200) NOT NULL COMMENT '公司名称',
|
||||
location VARCHAR(100) NOT NULL COMMENT '工作地点',
|
||||
quota INT NOT NULL DEFAULT 0 COMMENT '招聘人数',
|
||||
tags JSON COMMENT '福利标签数组',
|
||||
requirements TEXT COMMENT '岗位要求',
|
||||
description TEXT COMMENT '企业介绍',
|
||||
icon VARCHAR(50) DEFAULT 'fa-microchip' COMMENT '图标类名',
|
||||
is_active BOOLEAN DEFAULT TRUE COMMENT '是否启用',
|
||||
display_order INT DEFAULT 0 COMMENT '显示顺序',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_location (location),
|
||||
INDEX idx_is_active (is_active),
|
||||
INDEX idx_display_order (display_order)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='高薪岗位信息表';
|
||||
|
||||
-- ==========================================
|
||||
-- 2. 创建培训单元表
|
||||
-- ==========================================
|
||||
DROP TABLE IF EXISTS training_units;
|
||||
CREATE TABLE training_units (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
title VARCHAR(200) NOT NULL COMMENT '课程标题',
|
||||
start_date DATE NOT NULL COMMENT '开课时间',
|
||||
related_positions JSON COMMENT '对应岗位列表',
|
||||
related_companies JSON COMMENT '相关企业列表',
|
||||
status ENUM('locked', 'active') DEFAULT 'locked' COMMENT '单元状态',
|
||||
display_order INT DEFAULT 0 COMMENT '显示顺序',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_start_date (start_date),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_display_order (display_order)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='培训单元信息表';
|
||||
|
||||
-- ==========================================
|
||||
-- 3. 创建成功案例表
|
||||
-- ==========================================
|
||||
DROP TABLE IF EXISTS success_stories;
|
||||
CREATE TABLE success_stories (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
name VARCHAR(50) NOT NULL COMMENT '姓名 (脱敏)',
|
||||
job VARCHAR(100) NOT NULL COMMENT '职位',
|
||||
company VARCHAR(200) NOT NULL COMMENT '公司名称',
|
||||
salary VARCHAR(20) NOT NULL COMMENT '薪资 (如:9k)',
|
||||
avatar_color VARCHAR(20) DEFAULT '#2563eb' COMMENT '头像背景色',
|
||||
track_type ENUM('fast', 'slow', 'medium') DEFAULT 'fast' COMMENT '轨道类型',
|
||||
is_active BOOLEAN DEFAULT TRUE COMMENT '是否显示',
|
||||
display_order INT DEFAULT 0 COMMENT '显示顺序',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_track_type (track_type),
|
||||
INDEX idx_is_active (is_active)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='成功案例弹幕数据表';
|
||||
|
||||
-- ==========================================
|
||||
-- 4. 创建面试进度表
|
||||
-- ==========================================
|
||||
DROP TABLE IF EXISTS transition_progress;
|
||||
CREATE TABLE transition_progress (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
user_id INT COMMENT '用户ID (可选,关联users表)',
|
||||
company VARCHAR(200) NOT NULL COMMENT '公司名称',
|
||||
job VARCHAR(100) NOT NULL COMMENT '职位',
|
||||
status VARCHAR(50) NOT NULL COMMENT '状态描述',
|
||||
status_type ENUM('offer', 'hr', 'ing', 'pending') DEFAULT 'pending' COMMENT '状态类型',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_status_type (status_type)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='面试进度信息表';
|
||||
|
||||
-- ==========================================
|
||||
-- 5. 创建培训单元确认表
|
||||
-- ==========================================
|
||||
DROP TABLE IF EXISTS training_confirmations;
|
||||
CREATE TABLE training_confirmations (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
user_id INT NOT NULL COMMENT '用户ID',
|
||||
training_unit_id INT NOT NULL COMMENT '培训单元ID',
|
||||
confirmed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '确认时间',
|
||||
INDEX idx_user_id (user_id),
|
||||
INDEX idx_training_unit_id (training_unit_id),
|
||||
UNIQUE KEY uk_user_training (user_id, training_unit_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='培训单元确认记录表';
|
||||
|
||||
-- ==========================================
|
||||
-- 插入高薪岗位数据 (20条完整数据)
|
||||
-- ==========================================
|
||||
INSERT INTO high_salary_jobs (title, salary, company, location, quota, tags, requirements, description, icon, display_order) VALUES
|
||||
('自动化技术员', '4K-6K', '恒力集团有限公司', '苏州市', 5,
|
||||
'["五险一金", "年终奖", "项目奖金", "单休", "员工宿舍", "绩效奖金"]',
|
||||
'1. 电气、自动化或相关专业,大专及以上学历;\n2. 熟悉 PLC/继电器/电气控制原理,能独立完成设备电气线路安装与调试;\n3. 有自动化设备维护、故障分析经验者优先;\n4. 工作认真负责,有团队协作精神。',
|
||||
'恒力集团有限公司成立于1994年,总部位于江苏省苏州市吴江区,是立足实业发展的全球化民营企业。集团注册资产达520亿元人民币,全球员工总数超12万人,2022年实现营业收入6117亿元,连续七年跻身世界500强企业榜单。\n公司以石化、聚酯新材料、纺织为主业,构建形成"原油-芳烃-乙烯-精对苯二甲酸(PTA)-聚酯-纺织"全产业链布局。',
|
||||
'fa-microchip', 1),
|
||||
|
||||
('自动化技术员', '6-8K', '东莞市宇瞳光学科技股份有限公司', '东莞市', 10,
|
||||
'["住宿/宿舍", "五险一金", "定期体检", "加班费依法支付"]',
|
||||
'1. 男女不限。\n2. 大专或高职以上学历,25届/26届实习+就业的实习生。\n3. 光学光电、机械及自动化、机电一体化、工业机器人、电气及自动化等理工科专业。\n4. 能吃苦耐劳、服从安排、具备良好的沟通能力及团队合作精神。\n5. 能接受实习期深入基层、扎根基础岗位学习各类自动化工艺。',
|
||||
'东莞市宇瞳光学科技股份有限公司成立于2011年9月,是一家专营光学产品的高新技术企业,占地面积15万平方米,月镜头生产能力1000万多支,年产值10亿元,现有员工2500多人。\n公司主要经营光学精密镜片、光学镜头、光学仪器等相关产品的研发、生产、销售和售后服务。',
|
||||
'fa-microchip', 2),
|
||||
|
||||
('工业机器人调试工程师', '8-10K', '爱仕达股份有限公司', '温州', 15,
|
||||
'["项目奖金", "出差补贴", "定期体检", "交通补贴"]',
|
||||
'1. 熟悉机器人焊接、搬运、码垛等工艺的调试;\n2. 熟悉ABB/KUKA/FANUC机器人优先;\n3. 具备现场项目管理能力和技术沟通能力;\n4. 熟悉机器人编程语言,了解工业机器人的结构特点;\n5. 熟悉电气控制系统原理,IO通讯、总线系统、PLC原理;\n6. 学历:专科及以上学历,可接受能力优秀的应届生。',
|
||||
'爱仕达股份有限公司创立于1978年,是一家集炊具、厨房小家电、工业机器人研发、制造、营销为一体的上市企业(股票代码:002403)。员工近10000人, 2021年公司销售收入30多亿。\n公司是不粘锅、无油烟锅、铝压力锅、不锈钢压力锅、电压力锅等20项与炊具产业相关的国家或行业标准起草单位。',
|
||||
'fa-robot', 3),
|
||||
|
||||
('非标自动化工程师', '7-10k', '光深自动化有限公司', '西安', 20,
|
||||
'["五险一金", "年终奖", "项目奖金", "单休", "员工宿舍", "绩效奖金"]',
|
||||
'1. 机械工程或相关专业背景,具备扎实的机械设计基础;\n2. 熟练掌握3D建模软件(如SolidWorks、AutoCAD)及2D绘图能力;\n3. 拥有良好的项目管理能力和沟通技巧,能有效协调跨部门合作;\n4. 对非标自动化设备有深刻理解和实践经验,具备较强的分析和解决复杂问题的能力。',
|
||||
'光深自动化有限公司专注于工业自动化系统设计开发、自动化控制器等产品研发制造及智能家居系统开发,秉持创新理念,为客户提供高品质自动化产品与解决方案,并致力于推动行业发展。',
|
||||
'fa-microchip', 4),
|
||||
|
||||
('自动化设备调试工程师', '7-9k', '深圳市标王工业设备有限公司', '东莞', 25,
|
||||
'["差旅报销/住宿安排", "出差补贴", "项目奖金", "夜班津贴"]',
|
||||
'1. 具备强烈的问题解决能力,能够独立处理和解决设备调试过程中遇到的问题。\n2. 拥有良好的团队合作精神,能与团队成员有效沟通。\n3. 具备良好的动手能力,能够进行设备装配和调试。\n4. 能够熟练使用相关调试工具和设备。\n5. 有较强的学习能力和技术研究能力。',
|
||||
'深圳市标王工业设备有限公司是中国领先的半导体封测设备、半导体3D检测设备的研发、设计、生产、销售和服务于一体的中大型高科技企业。\n公司创建于2009年,经过十多年的拼搏已成为半导体分选设备及老化设备领域行业领先、技术先进的高新技术企业。',
|
||||
'fa-screwdriver-wrench', 5),
|
||||
|
||||
('自动化调试工程师', '6-10K', '苏州科林利华电子有限公司', '苏州', 5,
|
||||
'["带薪年假", "年终奖", "五险一金"]',
|
||||
'1. 负责非标自动化设备的电气调试和维护;\n2. 能够阅读电气原理图,熟练接线;\n3. 熟悉各种传感器、伺服、步进电机的使用;\n4. 适应出差,有较强的责任心。',
|
||||
'苏州科林利华电子有限公司成立于2010年,是一家专注于自动化设备研发和制造的高科技企业。公司主要产品包括自动组装机、检测设备、包装设备等,服务于消费电子、汽车零部件等行业。',
|
||||
'fa-screwdriver-wrench', 6),
|
||||
|
||||
('机器人应用工程师', '5-8K', '佛山华数机器人有限公司', '佛山', 10,
|
||||
'["五险一金", "定期体检", "带薪年假", "通讯补贴"]',
|
||||
'1. 机械、电气自动化等相关专业,大专及以上学历;\n2. 熟悉工业机器人的操作和编程,如华数、FANUC、ABB等;\n3. 具备良好的电气基础知识,能看懂电气图纸;\n4. 有机器人焊接、打磨、搬运项目经验者优先;\n5. 工作积极主动,具备良好的团队协作能力。',
|
||||
'佛山华数机器人有限公司是武汉华中数控股份有限公司旗下子公司,专注于工业机器人产品的研发、制造和销售。公司产品涵盖多关节机器人、SCARA机器人、Delta机器人等,广泛应用于焊接、打磨、搬运、装配等领域。',
|
||||
'fa-robot', 7),
|
||||
|
||||
('自动化工程师', '10-15K', '成都宏明双新科技股份有限公司', '成都', 15,
|
||||
'["六险一金", "带薪年假", "餐补", "定期体检"]',
|
||||
'1. 本科及以上学历,自动化、测控等相关专业;\n2. 3年以上自动化设备设计开发经验;\n3. 熟练掌握PLC编程(西门子、三菱等);\n4. 熟悉上位机软件开发(C#、LabVIEW等);\n5. 具备良好的项目管理能力和英语阅读能力。',
|
||||
'成都宏明双新科技股份有限公司成立于2000年,主要从事精密模具、精密冲压件、注塑件及自动化设备的研发、生产和销售。公司是国家高新技术企业,产品广泛应用于3C电子、汽车电子等领域。',
|
||||
'fa-microchip', 8),
|
||||
|
||||
('自动化调试工程师', '5-8K', '湖南德沃智能制造有限公司', '长沙', 20,
|
||||
'["包吃住", "节日福利", "专业培训"]',
|
||||
'1. 自动化类相关专业,中专及以上学历;\n2. 了解PLC控制原理,认识常用电气元件;\n3. 动手能力强,能吃苦耐劳;\n4. 适应倒班和加班,有志于在自动化行业长期发展。',
|
||||
'湖南德沃智能制造有限公司是一家集研发、生产、销售为一体的智能装备制造企业。公司主要产品包括自动化装配线、检测设备、机器人工作站等。公司注重人才培养,为员工提供良好的晋升通道和发展空间。',
|
||||
'fa-screwdriver-wrench', 9),
|
||||
|
||||
('电气自动化工程师', '7-9K', '江西联创电子有限公司', '南昌', 25,
|
||||
'["五险一金", "年终奖", "股票期权", "带薪年假"]',
|
||||
'1. 电气工程及其自动化专业,本科及以上学历;\n2. 熟悉PLC、触摸屏、伺服驱动器的应用;\n3. 能独立完成小型自动化项目的电气设计和调试;\n4. 熟练使用AutoCAD或EPLAN绘制电气图纸;\n5. 具备良好的沟通能力和学习能力。',
|
||||
'江西联创电子有限公司是联创电子科技股份有限公司(股票代码:002036)的全资子公司,主要从事光学镜头、摄像模组及触控显示一体化产品的研发、生产和销售。公司产品广泛应用于智能手机、平板电脑、智能汽车等领域。',
|
||||
'fa-microchip', 10),
|
||||
|
||||
('设备调试工程师', '8-12K', '宁德时代新能源科技股份有限公司', '宁德', 5,
|
||||
'["五险一金", "补充医疗保险", "定期体检", "免费班车"]',
|
||||
'1. 大专及以上学历,机械、电气自动化相关专业;\n2. 2年以上锂电设备调试经验;\n3. 熟悉涂布机、卷绕机、化成设备等锂电前中后段设备;\n4. 具备较强的故障排查和分析能力;\n5. 适应无尘车间工作环境。',
|
||||
'宁德时代新能源科技股份有限公司(CATL)是全球领先的新能源创新科技公司,致力于为全球新能源应用提供一流解决方案和服务。公司主要从事动力电池及储能电池的研发、生产和销售。',
|
||||
'fa-screwdriver-wrench', 11),
|
||||
|
||||
('自动化助理工程师', '5-7K', '郑州富士康科技集团', '郑州', 10,
|
||||
'["包吃住", "五险一金", "带薪年假", "加班补助"]',
|
||||
'1. 大专及以上学历,机电一体化、自动化相关专业;\n2. 了解基本的电路知识和机械原理;\n3. 熟练使用办公软件;\n4. 工作细致认真,服从安排;\n5. 优秀应届毕业生亦可。',
|
||||
'郑州富士康科技集团是鸿海精密集团在大陆投资兴建的专业研发制造基地,主要从事智能手机等电子产品的生产。公司拥有先进的生产设备和完善的管理体系,是全球最大的智能手机生产基地之一。',
|
||||
'fa-microchip', 12),
|
||||
|
||||
('机器人维护工程师', '6-9K', '杭州海康威视数字技术股份有限公司', '杭州', 15,
|
||||
'["五险一金", "补充医疗保险", "定期体检", "交通补贴"]',
|
||||
'1. 专科及以上学历,工业机器人、自动化等相关专业;\n2. 熟悉海康机器人或其他品牌机器人的操作和维护;\n3. 具备一定的电气故障排查能力;\n4. 了解机器视觉系统者优先;\n5. 有良好的服务意识和团队合作精神。',
|
||||
'杭州海康威视数字技术股份有限公司是全球领先的以视频为核心的物联网解决方案提供商。公司致力于通过持续创新,为客户提供高质量的产品和服务。海康机器人是海康威视旗下的机器视觉和移动机器人业务单元。',
|
||||
'fa-robot', 13),
|
||||
|
||||
('PLC自动化工程师', '7-10K', '厦门盈趣科技股份有限公司', '厦门', 20,
|
||||
'["五险一金", "年终奖", "股票期权", "带薪年假"]',
|
||||
'1. 本科及以上学历,自动化、电子信息等相关专业;\n2. 精通西门子或欧姆龙PLC编程;\n3. 熟悉工业网络通信协议(Profinet, EtherCAT等);\n4. 有非标自动化设备电气设计经验者优先;\n5. 具备良好的英语读写能力。',
|
||||
'厦门盈趣科技股份有限公司成立于2011年,致力于成为"工业互联网"和"民用物联网"领域的领军企业。公司主要为客户提供智能控制部件、创新消费电子等产品的研发、生产和销售。',
|
||||
'fa-microchip', 14),
|
||||
|
||||
('产线调试技术员', '6-8K', '重庆长安汽车股份有限公司', '重庆', 25,
|
||||
'["五险一金", "免费班车", "定期体检", "高温补贴"]',
|
||||
'1. 中专及以上学历,汽车维修、机电一体化相关专业;\n2. 熟悉汽车总装工艺流程;\n3. 掌握常用的汽车检测设备和工具的使用;\n4. 具备一定的汽车故障诊断和排除能力;\n5. 吃苦耐劳,适应倒班工作。',
|
||||
'重庆长安汽车股份有限公司是中国汽车行业的骨干企业,拥有160年的历史底蕴。公司主要从事汽车及发动机的研发、制造和销售。长安汽车始终坚持自主创新,致力于打造世界一流的汽车企业。',
|
||||
'fa-screwdriver-wrench', 15),
|
||||
|
||||
('自动化系统集成工程师', '9-13K', '青岛海尔集团', '青岛', 5,
|
||||
'["五险一金", "补充医疗保险", "年终奖", "员工旅游"]',
|
||||
'1. 本科及以上学历,自动化、计算机等相关专业;\n2. 熟悉SCADA系统、MES系统的开发和应用;\n3. 掌握SQL Server或Oracle数据库;\n4. 有智能工厂系统集成项目经验者优先;\n5. 具备良好的逻辑思维能力和解决问题的能力。',
|
||||
'海尔集团是全球领先的美好生活解决方案服务商。公司在物联网时代,致力于转型为物联网生态品牌。海尔智家是海尔集团旗下上市公司,提供全场景智慧家庭解决方案。公司拥有全球领先的互联工厂,积极探索工业4.0和智能制造的实践。',
|
||||
'fa-microchip', 16),
|
||||
|
||||
('工业机器人现场工程师', '8-12K', '埃斯顿自动化股份有限公司', '南京', 10,
|
||||
'["五险一金", "带薪年假", "定期体检", "通讯补贴"]',
|
||||
'1. 大专及以上学历,机电一体化、机器人工程专业;\n2. 熟悉埃斯顿机器人产品特性及编程;\n3. 能适应长期出差,在客户现场进行调试和培训;\n4. 具备良好的沟通协调能力和抗压能力;\n5. 有焊接、折弯机器人应用经验者优先。',
|
||||
'埃斯顿自动化股份有限公司是中国工业机器人行业的领军企业之一。公司形成了"核心部件+本体+工业机器人集成应用"的全产业链竞争优势。产品广泛应用于光伏、锂电、金属加工等行业。',
|
||||
'fa-robot', 17),
|
||||
|
||||
('电气控制技术员', '6-9K', '天津长城汽车哈弗分公司', '天津', 15,
|
||||
'["五险一金", "免费工作餐", "提供住宿", "年终奖"]',
|
||||
'1. 大专学历,电气自动化相关专业;\n2. 熟悉西门子S7-1200/1500 PLC;\n3. 了解变频器、伺服驱动器的参数设置;\n4. 具备电气柜配盘和现场布线能力;\n5. 工作踏实,服从管理。',
|
||||
'天津长城汽车哈弗分公司是长城汽车在天津的重要生产基地,主要生产哈弗品牌SUV车型。工厂拥有冲压、焊装、涂装、总装四大工艺车间,自动化程度高。公司为员工提供广阔的发展平台和完善的薪酬福利体系。',
|
||||
'fa-microchip', 18),
|
||||
|
||||
('设备维护调试员', '7-10K', '合肥京东方光电科技有限公司', '合肥', 20,
|
||||
'["六险二金", "提供住宿", "免费班车", "带薪年假"]',
|
||||
'1. 大专及以上学历,机械、电子、自动化相关专业;\n2. 有液晶面板厂设备维护经验者优先;\n3. 熟悉气动元件、真空设备、传动机构的维护;\n4. 具备基本的PLC故障诊断能力;\n5. 适应倒班工作制。',
|
||||
'京东方科技集团股份有限公司(BOE)是全球领先的半导体显示技术、产品与服务提供商。合肥京东方拥有多条高世代TFT-LCD生产线,是全球重要的显示面板生产基地。公司坚持创新驱动,不仅在显示领域保持领先,还在智慧系统、健康服务等领域积极布局。',
|
||||
'fa-screwdriver-wrench', 19),
|
||||
|
||||
('初级自动化技术员', '5-8K', '昆山龙腾光电股份有限公司', '昆山', 25,
|
||||
'["五险一金", "加班补助", "包吃住", "节日福利"]',
|
||||
'1. 中专或高中以上学历,理工科背景;\n2. 对自动化设备感兴趣,愿意学习新技术;\n3. 具备一定的动手能力;\n4. 身体健康,视力良好;\n5. 欢迎应届毕业生加入。',
|
||||
'昆山龙腾光电股份有限公司成立于2005年,是国内知名的液晶显示面板制造商。公司主要产品为笔记本电脑、车载显示、手机等中小尺寸显示面板。公司位于江苏省昆山市光电产业园,拥有先进的生产技术和严格的质量管理体系。',
|
||||
'fa-microchip', 20);
|
||||
|
||||
|
||||
-- ==========================================
|
||||
-- 插入培训单元数据 (8条完整数据)
|
||||
-- ==========================================
|
||||
INSERT INTO training_units (title, start_date, related_positions, related_companies, display_order) VALUES
|
||||
('SOLIDWORKS与钣金设计类岗位', '2026-04-20',
|
||||
'["焊接工艺工程师", "焊接技术员", "钣金工程师"]',
|
||||
'["吉利控股集团有限公司", "保定成聚模具冲压有限公司", "佳创机械设备制造(固安)有限公司", "浙江华岳包装机械有限公司", "江阴兴澄特种钢铁有限公司", "江苏交通控股有限公司", "徐州工程机械集团有限公司"]',
|
||||
1),
|
||||
|
||||
('UG编程与CNC编程类岗位', '2026-04-25',
|
||||
'["CNC编程工程师", "刀具应用工程师", "刀具技术工程师", "CNC技术员", "CNC调试员"]',
|
||||
'["盛虹控股集团有限公司", "江苏沙钢集团有限公司", "协鑫集团有限公司", "中天钢铁集团有限公司", "江苏新长江实业集团有限公司", "苏美达股份有限公司"]',
|
||||
2),
|
||||
|
||||
('模具设计类岗位必备核心技能', '2026-05-05',
|
||||
'["模具设计师", "模具质检员", "模具质量工程师", "模具工", "模具工程师"]',
|
||||
'["江苏江中集团有限公司", "无锡江南电缆有限公司", "江苏长电科技股份有限公司", "江苏扬子江船业集团有限公司", "中车唐山机车车辆有限公司"]',
|
||||
3),
|
||||
|
||||
('快速上手PLC编程调试类岗位', '2026-05-11',
|
||||
'["PLC编程工程师", "电气控制工程师", "PLC自动化工程师", "PLC工程师", "电气自动化管培生"]',
|
||||
'["上海汽车集团股份有限公司", "中国石化上海石油化工股份有限公司", "上海华谊控股集团有限公司", "上海通用电焊机股份有限公司"]',
|
||||
4),
|
||||
|
||||
('工业机器人运维调试类岗位实战技巧', '2026-05-18',
|
||||
'["工业机器人工程师", "工业机器人调试工程师", "工业机器人调试技术员", "工业机器人工程师助理"]',
|
||||
'["奇瑞控股集团有限公司", "华勤技术股份有限公司", "蔚来集团", "美的集团股份有限公司", "TCL科技集团股份有限公司", "立讯精密工业股份有限公司"]',
|
||||
5),
|
||||
|
||||
('机器识别类岗位上岗必学技能', '2026-05-25',
|
||||
'["视觉检测工程师", "机器视觉工程师", "机器视觉应用工程师", "机器视觉调试技术员", "机器视觉调试工程师"]',
|
||||
'["中天科技集团有限公司", "立铠精密科技(盐城)有限公司", "远景能源有限公司", "天合光能股份有限公司", "惠州亿纬锂能股份有限公司", "广东伊之密精密机械股份有限公司"]',
|
||||
6),
|
||||
|
||||
('C#与上位机;高阶岗位技能', '2026-06-01',
|
||||
'["工业机器人工程师", "PLC自动化工程师", "自动化工程师", "通信协议工程师", "机器视觉应用工程师"]',
|
||||
'["恒力集团有限公司", "亨通集团有限公司", "永鼎集团有限公司", "江苏沃得机电集团有限公司", "重庆长线智能科技有限责任公司", "宁波均胜电子股份有限公司"]',
|
||||
7),
|
||||
|
||||
('非标自动化实战与行业发展精进', '2026-06-08',
|
||||
'["非标自动化工艺工程师", "非标自动化结构工程师", "非标设备电气工程师", "非标自动化工程师"]',
|
||||
'["宿迁阿特斯阳光能源科技有限公司", "重庆钢铁股份有限公司", "重庆宗申发动机制造有限公司", "重庆美利信科技股份有限公司", "重庆京东方光电科技有限公司", "江苏恒瑞医药股份有限公司"]',
|
||||
8);
|
||||
|
||||
-- ==========================================
|
||||
-- 插入成功案例数据 (35条完整数据)
|
||||
-- ==========================================
|
||||
|
||||
-- fast轨道 (12条)
|
||||
INSERT INTO success_stories (name, job, company, salary, avatar_color, track_type, display_order) VALUES
|
||||
('赵**', '自动化技术员', '恒力集团有限公司', '9k', '#2563eb', 'fast', 1),
|
||||
('钱**', '工业机器人调试工程师', '亨通集团有限公司', '11k', '#db2777', 'fast', 2),
|
||||
('孙**', '非标自动化工程师', '盛虹控股集团有限公司', '10k', '#7c3aed', 'fast', 3),
|
||||
('李**', '自动化设备调试工程师', '江苏沙钢集团有限公司', '12k', '#059669', 'fast', 4),
|
||||
('周**', '自动化仪表工程师', '协鑫集团有限公司', '8k', '#d97706', 'fast', 5),
|
||||
('吴**', '电气自动化工程师', '新誉集团有限公司', '9k', '#0891b2', 'fast', 6),
|
||||
('郑**', 'PLC工程师', '中天科技集团有限公司', '11k', '#4f46e5', 'fast', 7),
|
||||
('王**', '自动化产线维护员', '海澜集团有限公司', '8k', '#be185d', 'fast', 8),
|
||||
('冯**', '机电工程师', '红豆集团有限公司', '10k', '#ca8a04', 'fast', 9),
|
||||
('陈**', '自动化控制技术员', '江苏国泰国际集团股份有限公司', '12k', '#16a34a', 'fast', 10),
|
||||
('褚**', '智能制造工程师', '瑞声科技控股有限公司', '9k', '#ea580c', 'fast', 11),
|
||||
('卫**', '机器人维护工程师', '天合光能股份有限公司', '11k', '#0284c7', 'fast', 12);
|
||||
|
||||
-- slow轨道 (12条)
|
||||
INSERT INTO success_stories (name, job, company, salary, avatar_color, track_type, display_order) VALUES
|
||||
('蒋**', '自动化测试工程师', '信达生物制药(苏州)有限公司', '12k', '#9333ea', 'slow', 1),
|
||||
('沈**', '电气设计师', '同程网络科技股份有限公司', '10k', '#dc2626', 'slow', 2),
|
||||
('韩**', '设备自动化工程师', '江苏新潮科技集团有限公司', '9k', '#4b5563', 'slow', 3),
|
||||
('杨**', '工控网络工程师', '远东控股集团有限公司', '11k', '#0d9488', 'slow', 4),
|
||||
('朱**', '自动化系统集成工程师', '江苏中南建设集团股份有限公司', '12k', '#2563eb', 'slow', 5),
|
||||
('秦**', '现场应用工程师', '苏宁易购集团股份有限公司', '8k', '#db2777', 'slow', 6),
|
||||
('尤**', '自动化运维工程师', '南京钢铁集团有限公司', '9k', '#7c3aed', 'slow', 7),
|
||||
('许**', '视觉算法工程师(助理)', '江苏扬子江船厂有限公司', '12k', '#059669', 'slow', 8),
|
||||
('何**', '运动控制算法工程师', '徐工集团工程机械有限公司', '11k', '#d97706', 'slow', 9),
|
||||
('吕**', '自动化项目经理助理', '中信泰富特钢集团股份有限公司', '10k', '#0891b2', 'slow', 10),
|
||||
('施**', '电气调试员', '江苏悦达集团有限公司', '8k', '#4f46e5', 'slow', 11),
|
||||
('张**', '自动化装配技术员', '东方润安集团有限公司', '9k', '#be185d', 'slow', 12);
|
||||
|
||||
-- medium轨道 (11条)
|
||||
INSERT INTO success_stories (name, job, company, salary, avatar_color, track_type, display_order) VALUES
|
||||
('孔**', '自动化售后工程师', '江苏永钢集团有限公司', '8k', '#ca8a04', 'medium', 1),
|
||||
('曹**', 'MES实施工程师', '江苏恒顺集团有限公司', '9k', '#16a34a', 'medium', 2),
|
||||
('严**', 'SCADA开发工程师', '江苏索普(集团)有限公司', '11k', '#ea580c', 'medium', 3),
|
||||
('华**', '嵌入式软件工程师', '通鼎集团有限公司', '12k', '#0284c7', 'medium', 4),
|
||||
('金**', '自动化硬件工程师', '波司登股份有限公司', '10k', '#9333ea', 'medium', 5),
|
||||
('魏**', '工控机维护员', '扬州泰富特种材料有限公司', '8k', '#dc2626', 'medium', 6),
|
||||
('陶**', '自动化仓储运维', '江苏飞达控股集团有限公司', '9k', '#4b5563', 'medium', 7),
|
||||
('姜**', 'AGV调度工程师', '大全集团有限公司', '11k', '#0d9488', 'medium', 8),
|
||||
('戚**', '自动化采购专员', '弘元绿色能源股份有限公司', '8k', '#2563eb', 'medium', 9),
|
||||
('谢**', '技术支持工程师', '亚邦投资控股集团有限公司', '10k', '#db2777', 'medium', 10),
|
||||
('邹**', '自动化培训讲师', '江苏林洋能源股份有限公司', '12k', '#7c3aed', 'medium', 11);
|
||||
|
||||
-- ==========================================
|
||||
-- 恢复外键检查
|
||||
-- ==========================================
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
-- ==========================================
|
||||
-- 数据验证
|
||||
-- ==========================================
|
||||
SELECT '========== 数据验证 ==========' as message;
|
||||
SELECT 'high_salary_jobs' as table_name, COUNT(*) as count FROM high_salary_jobs
|
||||
UNION ALL
|
||||
SELECT 'training_units', COUNT(*) FROM training_units
|
||||
UNION ALL
|
||||
SELECT 'success_stories', COUNT(*) FROM success_stories;
|
||||
|
||||
SELECT '========== 初始化完成 ==========' as message;
|
||||
SELECT '已插入 20 条高薪岗位数据' as info
|
||||
UNION ALL SELECT '已插入 8 条培训单元数据'
|
||||
UNION ALL SELECT '已插入 35 条成功案例数据';
|
||||
62
scripts/kill-by-ids.js
Normal file
62
scripts/kill-by-ids.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* 超简单的进程终止工具
|
||||
* 直接指定进程ID列表,避免复杂查询
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
async function killProcessIds(ids) {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
connection = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT || 3306,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE
|
||||
});
|
||||
|
||||
console.log('✅ 已连接到数据库\n');
|
||||
|
||||
if (!ids || ids.length === 0) {
|
||||
console.log('⚠️ 没有提供要终止的进程ID');
|
||||
console.log('\n使用方法:');
|
||||
console.log(' node scripts/kill-by-ids.js 123 456 789');
|
||||
console.log(' 或在代码中修改 processIds 数组\n');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`🔪 准备终止 ${ids.length} 个进程: ${ids.join(', ')}\n`);
|
||||
|
||||
let killed = 0;
|
||||
for (const id of ids) {
|
||||
try {
|
||||
await connection.query(`KILL ${id}`);
|
||||
console.log(`✅ 已终止进程 ${id}`);
|
||||
killed++;
|
||||
} catch (err) {
|
||||
console.log(`⚠️ 进程 ${id} 终止失败: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n✅ 成功终止 ${killed}/${ids.length} 个进程\n`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 操作失败:', error.message);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 从命令行参数获取进程ID
|
||||
const processIds = process.argv.slice(2).map(id => parseInt(id)).filter(id => !isNaN(id));
|
||||
|
||||
// 或者直接在这里列出要终止的进程ID(如果知道的话)
|
||||
// const processIds = [123, 456, 789];
|
||||
|
||||
killProcessIds(processIds);
|
||||
136
scripts/kill-locked-processes.js
Normal file
136
scripts/kill-locked-processes.js
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 批量终止锁定的MySQL进程
|
||||
* 安全版本 - 会列出要终止的进程供确认
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
const readline = require('readline');
|
||||
|
||||
// 创建命令行接口用于用户确认
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
function question(query) {
|
||||
return new Promise(resolve => rl.question(query, resolve));
|
||||
}
|
||||
|
||||
async function killLockedProcesses() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
connection = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT || 3306,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE
|
||||
});
|
||||
|
||||
console.log('✅ 已连接到数据库\n');
|
||||
|
||||
// 查找所有符合条件的进程
|
||||
console.log('📋 查找需要终止的进程...\n');
|
||||
|
||||
const [processes] = await connection.query(`
|
||||
SELECT Id, User, Host, db, Command, Time, State, Info
|
||||
FROM INFORMATION_SCHEMA.PROCESSLIST
|
||||
WHERE (
|
||||
State LIKE '%waiting for handler commit%'
|
||||
OR State LIKE '%Locked%'
|
||||
OR (Command = 'Sleep' AND Time > 300)
|
||||
)
|
||||
AND Id != CONNECTION_ID()
|
||||
`);
|
||||
|
||||
if (processes.length === 0) {
|
||||
console.log('✅ 没有找到需要终止的进程\n');
|
||||
rl.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示找到的进程
|
||||
console.log(`找到 ${processes.length} 个需要终止的进程:\n`);
|
||||
console.log('ID\t用户\t\t命令\t时间(秒)\t状态');
|
||||
console.log('─'.repeat(80));
|
||||
|
||||
processes.forEach(p => {
|
||||
const user = (p.User || '').padEnd(12);
|
||||
const command = (p.Command || '').padEnd(8);
|
||||
const time = String(p.Time || 0).padEnd(8);
|
||||
const state = (p.State || 'Sleep').substring(0, 40);
|
||||
console.log(`${p.Id}\t${user}\t${command}\t${time}\t${state}`);
|
||||
});
|
||||
|
||||
console.log('\n');
|
||||
|
||||
// 询问用户确认
|
||||
const answer = await question('确认要终止这些进程吗?(yes/no): ');
|
||||
|
||||
if (answer.toLowerCase() !== 'yes' && answer.toLowerCase() !== 'y') {
|
||||
console.log('\n❌ 操作已取消\n');
|
||||
rl.close();
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('\n🔪 开始终止进程...\n');
|
||||
|
||||
// 批量终止进程
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
|
||||
for (const p of processes) {
|
||||
try {
|
||||
await connection.query(`KILL ${p.Id}`);
|
||||
console.log(`✅ 已终止进程 ${p.Id} (${p.Command}, ${p.State})`);
|
||||
successCount++;
|
||||
} catch (err) {
|
||||
console.log(`❌ 无法终止进程 ${p.Id}: ${err.message}`);
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n' + '═'.repeat(80));
|
||||
console.log(`✅ 成功终止: ${successCount} 个进程`);
|
||||
if (failCount > 0) {
|
||||
console.log(`❌ 失败: ${failCount} 个进程`);
|
||||
}
|
||||
console.log('═'.repeat(80) + '\n');
|
||||
|
||||
// 验证结果
|
||||
console.log('📋 验证当前进程状态...\n');
|
||||
const [remaining] = await connection.query(`
|
||||
SELECT COUNT(*) as count
|
||||
FROM INFORMATION_SCHEMA.PROCESSLIST
|
||||
WHERE (
|
||||
State LIKE '%waiting for handler commit%'
|
||||
OR State LIKE '%Locked%'
|
||||
OR (Command = 'Sleep' AND Time > 300)
|
||||
)
|
||||
AND Id != CONNECTION_ID()
|
||||
`);
|
||||
|
||||
if (remaining[0].count === 0) {
|
||||
console.log('✅ 所有锁定的进程已清除!\n');
|
||||
} else {
|
||||
console.log(`⚠️ 仍有 ${remaining[0].count} 个锁定的进程\n`);
|
||||
}
|
||||
|
||||
rl.close();
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 操作失败:', error.message);
|
||||
console.error('\n提示:如果遇到权限问题,请联系数据库管理员\n');
|
||||
rl.close();
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行
|
||||
killLockedProcesses();
|
||||
66
scripts/quick-kill-all.js
Normal file
66
scripts/quick-kill-all.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 快速批量终止锁定的MySQL进程
|
||||
* 无需确认 - 直接终止所有锁定的进程
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
async function quickKillAll() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
connection = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT || 3306,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE
|
||||
});
|
||||
|
||||
console.log('✅ 已连接到数据库\n');
|
||||
|
||||
// 查找并终止所有锁定的进程
|
||||
const [processes] = await connection.query(`
|
||||
SELECT Id, Command, State, Time
|
||||
FROM INFORMATION_SCHEMA.PROCESSLIST
|
||||
WHERE (
|
||||
State LIKE '%waiting for handler commit%'
|
||||
OR State LIKE '%Locked%'
|
||||
OR State LIKE '%lock%'
|
||||
OR (Command = 'Sleep' AND Time > 300)
|
||||
)
|
||||
AND Id != CONNECTION_ID()
|
||||
`);
|
||||
|
||||
if (processes.length === 0) {
|
||||
console.log('✅ 没有找到锁定的进程\n');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`🔪 找到 ${processes.length} 个锁定的进程,正在终止...\n`);
|
||||
|
||||
let killed = 0;
|
||||
for (const p of processes) {
|
||||
try {
|
||||
await connection.query(`KILL ${p.Id}`);
|
||||
console.log(`✅ 已终止进程 ${p.Id}`);
|
||||
killed++;
|
||||
} catch (err) {
|
||||
console.log(`⚠️ 进程 ${p.Id} 终止失败: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n✅ 成功终止 ${killed}/${processes.length} 个进程\n`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 操作失败:', error.message);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quickKillAll();
|
||||
46
scripts/run-init-sql.js
Normal file
46
scripts/run-init-sql.js
Normal file
@@ -0,0 +1,46 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
require('dotenv').config();
|
||||
|
||||
async function runInitSQL() {
|
||||
const connection = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE,
|
||||
multipleStatements: true
|
||||
});
|
||||
|
||||
try {
|
||||
console.log('✅ 数据库连接成功');
|
||||
|
||||
const sqlFile = path.join(__dirname, 'init-high-page-data.sql');
|
||||
const sql = fs.readFileSync(sqlFile, 'utf8');
|
||||
|
||||
console.log('📝 开始执行SQL脚本...');
|
||||
await connection.query(sql);
|
||||
|
||||
console.log('✅ SQL脚本执行完成!');
|
||||
|
||||
// 验证数据
|
||||
const [jobs] = await connection.query('SELECT COUNT(*) as count FROM high_salary_jobs');
|
||||
const [units] = await connection.query('SELECT COUNT(*) as count FROM training_units');
|
||||
const [stories] = await connection.query('SELECT COUNT(*) as count FROM success_stories');
|
||||
|
||||
console.log('\n========== 数据验证 ==========');
|
||||
console.log(`✅ high_salary_jobs: ${jobs[0].count} 条`);
|
||||
console.log(`✅ training_units: ${units[0].count} 条`);
|
||||
console.log(`✅ success_stories: ${stories[0].count} 条`);
|
||||
console.log('========== 初始化完成 ==========\n');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 执行失败:', error.message);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
|
||||
runInitSQL();
|
||||
116
scripts/simple-test.js
Normal file
116
scripts/simple-test.js
Normal file
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* 简单测试预招录确认功能
|
||||
* 避免使用复杂查询导致临时表问题
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
async function simpleTest() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
connection = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT || 3306,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE
|
||||
});
|
||||
|
||||
console.log('✅ 已连接到数据库\n');
|
||||
|
||||
// 简单测试1: 查询training_confirmations表
|
||||
console.log('📋 测试1: 查询确认记录...');
|
||||
const [confirmations] = await connection.query(
|
||||
'SELECT id, user_id, training_unit_id FROM training_confirmations LIMIT 5'
|
||||
);
|
||||
console.log(`✅ 成功查询到 ${confirmations.length} 条记录\n`);
|
||||
|
||||
// 简单测试2: 尝试INSERT操作
|
||||
console.log('📋 测试2: 测试INSERT操作...');
|
||||
const testUserId = 99999;
|
||||
const testTrainingUnitId = 99999;
|
||||
|
||||
try {
|
||||
// 先清理可能存在的测试数据
|
||||
await connection.query(
|
||||
'DELETE FROM training_confirmations WHERE user_id = ? AND training_unit_id = ?',
|
||||
[testUserId, testTrainingUnitId]
|
||||
);
|
||||
|
||||
// 尝试插入
|
||||
const startTime = Date.now();
|
||||
await connection.query(
|
||||
'INSERT INTO training_confirmations (user_id, training_unit_id) VALUES (?, ?)',
|
||||
[testUserId, testTrainingUnitId]
|
||||
);
|
||||
const endTime = Date.now();
|
||||
|
||||
console.log(`✅ INSERT操作成功 (耗时: ${endTime - startTime}ms)`);
|
||||
|
||||
// 验证插入
|
||||
const [inserted] = await connection.query(
|
||||
'SELECT id FROM training_confirmations WHERE user_id = ? AND training_unit_id = ?',
|
||||
[testUserId, testTrainingUnitId]
|
||||
);
|
||||
|
||||
if (inserted.length > 0) {
|
||||
console.log(`✅ 成功插入记录,ID: ${inserted[0].id}`);
|
||||
}
|
||||
|
||||
// 清理测试数据
|
||||
await connection.query(
|
||||
'DELETE FROM training_confirmations WHERE user_id = ? AND training_unit_id = ?',
|
||||
[testUserId, testTrainingUnitId]
|
||||
);
|
||||
console.log('✅ 已清理测试数据\n');
|
||||
|
||||
} catch (err) {
|
||||
console.error('❌ INSERT操作失败:', err.message);
|
||||
console.error('错误代码:', err.code);
|
||||
|
||||
if (err.code === 'ER_LOCK_WAIT_TIMEOUT') {
|
||||
console.error('\n⚠️ 数据库仍然存在锁定问题!');
|
||||
console.error('建议:');
|
||||
console.error('1. 联系数据库管理员检查锁定的事务');
|
||||
console.error('2. 或等待锁定的事务超时释放\n');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// 简单测试3: 测试UPDATE操作
|
||||
console.log('📋 测试3: 测试UPDATE操作...');
|
||||
try {
|
||||
const startTime = Date.now();
|
||||
await connection.query(
|
||||
'UPDATE training_confirmations SET user_id = user_id WHERE id = 1'
|
||||
);
|
||||
const endTime = Date.now();
|
||||
console.log(`✅ UPDATE操作成功 (耗时: ${endTime - startTime}ms)\n`);
|
||||
} catch (err) {
|
||||
console.error('❌ UPDATE操作失败:', err.message);
|
||||
if (err.code === 'ER_LOCK_WAIT_TIMEOUT') {
|
||||
console.error('⚠️ 数据库存在锁定问题\n');
|
||||
}
|
||||
}
|
||||
|
||||
console.log('========================================');
|
||||
console.log('✅ 基本功能测试完成!');
|
||||
console.log('========================================\n');
|
||||
console.log('💡 数据库连接和基本操作正常');
|
||||
console.log('📍 现在可以在浏览器中测试预招录确认按钮');
|
||||
console.log('🌐 访问: http://localhost:8080/high.html\n');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 测试失败:', error.message);
|
||||
console.error('错误代码:', error.code);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simpleTest();
|
||||
92
scripts/test-permissions.js
Normal file
92
scripts/test-permissions.js
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 测试数据库权限
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE || 'ddcz_platform'
|
||||
};
|
||||
|
||||
async function testPermissions() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🔌 正在连接到MySQL数据库...');
|
||||
console.log(` 主机: ${dbConfig.host}:${dbConfig.port}`);
|
||||
console.log(` 用户: ${dbConfig.user}`);
|
||||
console.log(` 数据库: ${dbConfig.database}\n`);
|
||||
|
||||
connection = await mysql.createConnection(dbConfig);
|
||||
console.log('✅ 数据库连接成功!\n');
|
||||
|
||||
// 测试1: 查看当前用户权限
|
||||
console.log('📋 测试1: 查看用户权限...');
|
||||
const [grants] = await connection.query('SHOW GRANTS');
|
||||
console.log('✅ 当前用户权限:');
|
||||
grants.forEach(grant => {
|
||||
console.log(` ${Object.values(grant)[0]}`);
|
||||
});
|
||||
console.log('');
|
||||
|
||||
// 测试2: 创建测试表
|
||||
console.log('📋 测试2: 测试创建表权限...');
|
||||
await connection.query(`
|
||||
CREATE TABLE IF NOT EXISTS test_permissions (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(50),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
console.log('✅ 创建表权限正常\n');
|
||||
|
||||
// 测试3: 插入数据
|
||||
console.log('📋 测试3: 测试插入数据权限...');
|
||||
await connection.query(`
|
||||
INSERT INTO test_permissions (name) VALUES ('test_data')
|
||||
`);
|
||||
console.log('✅ 插入数据权限正常\n');
|
||||
|
||||
// 测试4: 修改表结构
|
||||
console.log('📋 测试4: 测试修改表结构权限...');
|
||||
await connection.query(`
|
||||
ALTER TABLE test_permissions ADD COLUMN description TEXT
|
||||
`);
|
||||
console.log('✅ 修改表结构权限正常\n');
|
||||
|
||||
// 测试5: 删除表
|
||||
console.log('📋 测试5: 测试删除表权限...');
|
||||
await connection.query(`
|
||||
DROP TABLE IF EXISTS test_permissions
|
||||
`);
|
||||
console.log('✅ 删除表权限正常\n');
|
||||
|
||||
console.log('🎉 所有权限测试通过!');
|
||||
console.log('✅ 您的账号具有完整的数据库操作权限');
|
||||
console.log('📌 可以继续运行 npm run init-db 创建所有表\n');
|
||||
|
||||
} catch (error) {
|
||||
console.error('\n❌ 权限测试失败:');
|
||||
console.error(error.message);
|
||||
|
||||
if (error.code === 'ER_DBACCESS_DENIED_ERROR') {
|
||||
console.error('\n💡 没有访问数据库的权限');
|
||||
} else if (error.code === 'ER_TABLEACCESS_DENIED_ERROR') {
|
||||
console.error('\n💡 没有操作表的权限');
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 数据库连接已关闭');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testPermissions();
|
||||
125
scripts/test-training-confirmation.js
Normal file
125
scripts/test-training-confirmation.js
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* 测试预招录确认功能是否正常
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
async function testConfirmation() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
connection = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT || 3306,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE
|
||||
});
|
||||
|
||||
console.log('✅ 已连接到数据库\n');
|
||||
|
||||
// 测试1: 检查是否还有锁定的进程
|
||||
console.log('📋 测试1: 检查锁定的进程...');
|
||||
const [lockedProcesses] = await connection.query(
|
||||
"SELECT Id, State, Info FROM INFORMATION_SCHEMA.PROCESSLIST WHERE State LIKE '%waiting for handler commit%' OR State LIKE '%Locked%'"
|
||||
);
|
||||
|
||||
if (lockedProcesses.length > 0) {
|
||||
console.log(`⚠️ 发现 ${lockedProcesses.length} 个锁定的进程:`);
|
||||
lockedProcesses.forEach(p => {
|
||||
console.log(` - 进程 ${p.Id}: ${p.State}`);
|
||||
});
|
||||
} else {
|
||||
console.log('✅ 没有发现锁定的进程\n');
|
||||
}
|
||||
|
||||
// 测试2: 查看当前所有进程状态
|
||||
console.log('📋 测试2: 当前活动进程...');
|
||||
const [allProcesses] = await connection.query('SHOW FULL PROCESSLIST');
|
||||
console.log(`当前活动进程数: ${allProcesses.length}`);
|
||||
|
||||
const sleepCount = allProcesses.filter(p => p.Command === 'Sleep').length;
|
||||
const queryCount = allProcesses.filter(p => p.Command === 'Query').length;
|
||||
console.log(` - Sleep状态: ${sleepCount}`);
|
||||
console.log(` - Query状态: ${queryCount}\n`);
|
||||
|
||||
// 测试3: 检查training_confirmations表是否可以正常查询
|
||||
console.log('📋 测试3: 查询training_confirmations表...');
|
||||
const [confirmations] = await connection.query(
|
||||
'SELECT COUNT(*) as count FROM training_confirmations'
|
||||
);
|
||||
console.log(`✅ 当前共有 ${confirmations[0].count} 条确认记录\n`);
|
||||
|
||||
// 测试4: 测试是否可以执行INSERT操作(使用一个不存在的user_id和training_unit_id)
|
||||
console.log('📋 测试4: 测试INSERT操作...');
|
||||
const testUserId = 99999;
|
||||
const testTrainingUnitId = 99999;
|
||||
|
||||
try {
|
||||
// 先检查是否存在
|
||||
const [existing] = await connection.query(
|
||||
'SELECT id FROM training_confirmations WHERE user_id = ? AND training_unit_id = ?',
|
||||
[testUserId, testTrainingUnitId]
|
||||
);
|
||||
|
||||
if (existing.length === 0) {
|
||||
// 尝试插入
|
||||
await connection.query(
|
||||
'INSERT INTO training_confirmations (user_id, training_unit_id) VALUES (?, ?)',
|
||||
[testUserId, testTrainingUnitId]
|
||||
);
|
||||
console.log('✅ INSERT操作成功');
|
||||
|
||||
// 清理测试数据
|
||||
await connection.query(
|
||||
'DELETE FROM training_confirmations WHERE user_id = ? AND training_unit_id = ?',
|
||||
[testUserId, testTrainingUnitId]
|
||||
);
|
||||
console.log('✅ 已清理测试数据\n');
|
||||
} else {
|
||||
console.log('⚠️ 测试记录已存在,跳过INSERT测试\n');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('❌ INSERT操作失败:', err.message);
|
||||
if (err.code === 'ER_LOCK_WAIT_TIMEOUT') {
|
||||
console.error('⚠️ 数据库仍然存在锁定问题!\n');
|
||||
}
|
||||
}
|
||||
|
||||
// 测试5: 检查是否有重复记录
|
||||
console.log('📋 测试5: 检查重复记录...');
|
||||
const [duplicates] = await connection.query(`
|
||||
SELECT user_id, training_unit_id, COUNT(*) as count
|
||||
FROM training_confirmations
|
||||
GROUP BY user_id, training_unit_id
|
||||
HAVING count > 1
|
||||
`);
|
||||
|
||||
if (duplicates.length > 0) {
|
||||
console.log(`⚠️ 发现 ${duplicates.length} 组重复记录:`);
|
||||
duplicates.forEach(dup => {
|
||||
console.log(` - user_id: ${dup.user_id}, training_unit_id: ${dup.training_unit_id}, 数量: ${dup.count}`);
|
||||
});
|
||||
} else {
|
||||
console.log('✅ 没有发现重复记录\n');
|
||||
}
|
||||
|
||||
console.log('========================================');
|
||||
console.log('✅ 所有测试完成!');
|
||||
console.log('========================================\n');
|
||||
console.log('💡 现在可以在浏览器中测试预招录确认按钮了');
|
||||
console.log('📍 访问: http://localhost:8080/high.html');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 测试失败:', error.message);
|
||||
console.error('错误详情:', error);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testConfirmation();
|
||||
44
scripts/unlock-all-tables.js
Normal file
44
scripts/unlock-all-tables.js
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 解锁所有表
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
async function unlockAllTables() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
connection = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT || 3306,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE
|
||||
});
|
||||
|
||||
console.log('✅ 已连接到数据库\n');
|
||||
|
||||
// 执行UNLOCK TABLES
|
||||
console.log('🔓 正在解锁所有表...');
|
||||
await connection.query('UNLOCK TABLES');
|
||||
console.log('✅ 所有表已解锁\n');
|
||||
|
||||
// 提交任何待处理的事务
|
||||
console.log('📝 提交待处理的事务...');
|
||||
await connection.query('COMMIT');
|
||||
console.log('✅ 事务已提交\n');
|
||||
|
||||
console.log('✅ 数据库解锁完成!\n');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 操作失败:', error.message);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unlockAllTables();
|
||||
68
scripts/unlock-tables.js
Normal file
68
scripts/unlock-tables.js
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 解锁数据库表
|
||||
* 终止所有锁定的连接并重置事务
|
||||
*/
|
||||
|
||||
require('dotenv').config();
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
async function unlockTables() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
// 创建数据库连接
|
||||
connection = await mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
port: process.env.DB_PORT || 3306,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE
|
||||
});
|
||||
|
||||
console.log('✅ 已连接到数据库');
|
||||
|
||||
// 1. 查看当前进程
|
||||
console.log('\n📋 查看当前锁定的进程...');
|
||||
const [processes] = await connection.query('SHOW FULL PROCESSLIST');
|
||||
|
||||
console.log('当前活动进程数:', processes.length);
|
||||
processes.forEach(p => {
|
||||
console.log(` - ID: ${p.Id}, User: ${p.User}, State: ${p.State}, Info: ${p.Info}`);
|
||||
});
|
||||
|
||||
// 2. 杀掉Sleep状态的连接(这些可能持有未提交的事务)
|
||||
console.log('\n🔪 终止Sleep状态的连接...');
|
||||
let killedCount = 0;
|
||||
for (const p of processes) {
|
||||
if (p.Command === 'Sleep' && p.Id !== connection.threadId) {
|
||||
try {
|
||||
await connection.query(`KILL ${p.Id}`);
|
||||
console.log(` ✅ 已终止进程 ${p.Id}`);
|
||||
killedCount++;
|
||||
} catch (err) {
|
||||
console.log(` ⚠️ 无法终止进程 ${p.Id}:`, err.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n终止了 ${killedCount} 个连接`);
|
||||
|
||||
// 3. 解锁所有表
|
||||
console.log('\n🔓 解锁所有表...');
|
||||
await connection.query('UNLOCK TABLES');
|
||||
console.log('✅ 表已解锁');
|
||||
|
||||
console.log('\n✅ 数据库解锁完成!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 解锁失败:', error.message);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行
|
||||
unlockTables();
|
||||
Reference in New Issue
Block a user