修改文件结构,统一文档格式

This commit is contained in:
ylweng
2025-09-02 23:22:10 +08:00
parent 02fe7d11da
commit 6b4e0c227f
85 changed files with 5501 additions and 272 deletions

View File

@@ -0,0 +1,225 @@
/**
* 分析数据库中表之间的外键关系
* @file analyze-foreign-keys.js
* @description 识别所有外键约束和引用关系为ID重排做准备
*/
const { sequelize } = require('./config/database-simple');
const { QueryTypes } = require('sequelize');
async function analyzeForeignKeys() {
try {
console.log('=== 分析数据库外键关系 ===\n');
// 获取所有外键约束
const foreignKeys = await sequelize.query(`
SELECT
kcu.TABLE_NAME as table_name,
kcu.COLUMN_NAME as column_name,
kcu.REFERENCED_TABLE_NAME as referenced_table,
kcu.REFERENCED_COLUMN_NAME as referenced_column,
rc.CONSTRAINT_NAME as constraint_name,
rc.UPDATE_RULE as update_rule,
rc.DELETE_RULE as delete_rule
FROM information_schema.KEY_COLUMN_USAGE kcu
JOIN information_schema.REFERENTIAL_CONSTRAINTS rc
ON kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
AND kcu.TABLE_SCHEMA = rc.CONSTRAINT_SCHEMA
WHERE kcu.TABLE_SCHEMA = DATABASE()
AND kcu.REFERENCED_TABLE_NAME IS NOT NULL
ORDER BY kcu.TABLE_NAME, kcu.COLUMN_NAME
`, { type: QueryTypes.SELECT });
console.log(`发现 ${foreignKeys.length} 个外键关系:\n`);
const relationshipMap = new Map();
const tablesWithForeignKeys = new Set();
const referencedTables = new Set();
foreignKeys.forEach(fk => {
const key = `${fk.table_name}.${fk.column_name}`;
const reference = `${fk.referenced_table}.${fk.referenced_column}`;
relationshipMap.set(key, {
table: fk.table_name,
column: fk.column_name,
referencedTable: fk.referenced_table,
referencedColumn: fk.referenced_column,
constraintName: fk.constraint_name,
updateRule: fk.update_rule,
deleteRule: fk.delete_rule
});
tablesWithForeignKeys.add(fk.table_name);
referencedTables.add(fk.referenced_table);
console.log(`🔗 ${fk.table_name}.${fk.column_name} -> ${fk.referenced_table}.${fk.referenced_column}`);
console.log(` 约束名: ${fk.constraint_name}`);
console.log(` 更新规则: ${fk.update_rule}`);
console.log(` 删除规则: ${fk.delete_rule}`);
console.log('');
});
// 分析每个外键字段的数据分布
console.log('\n=== 外键字段数据分布 ===\n');
const foreignKeyStats = [];
for (const [key, relationship] of relationshipMap) {
const { table, column, referencedTable, referencedColumn } = relationship;
try {
// 获取外键字段的统计信息
const stats = await sequelize.query(`
SELECT
COUNT(*) as total_count,
COUNT(DISTINCT ${column}) as unique_count,
MIN(${column}) as min_value,
MAX(${column}) as max_value,
COUNT(CASE WHEN ${column} IS NULL THEN 1 END) as null_count
FROM ${table}
`, { type: QueryTypes.SELECT });
const stat = stats[0];
// 检查引用完整性
const integrityCheck = await sequelize.query(`
SELECT COUNT(*) as invalid_references
FROM ${table} t
WHERE t.${column} IS NOT NULL
AND t.${column} NOT IN (
SELECT ${referencedColumn}
FROM ${referencedTable}
WHERE ${referencedColumn} IS NOT NULL
)
`, { type: QueryTypes.SELECT });
const invalidRefs = parseInt(integrityCheck[0].invalid_references);
const fkStat = {
table,
column,
referencedTable,
referencedColumn,
totalCount: parseInt(stat.total_count),
uniqueCount: parseInt(stat.unique_count),
minValue: stat.min_value,
maxValue: stat.max_value,
nullCount: parseInt(stat.null_count),
invalidReferences: invalidRefs,
hasIntegrityIssues: invalidRefs > 0
};
foreignKeyStats.push(fkStat);
console.log(`📊 ${table}.${column} -> ${referencedTable}.${referencedColumn}:`);
console.log(` - 总记录数: ${fkStat.totalCount}`);
console.log(` - 唯一值数: ${fkStat.uniqueCount}`);
console.log(` - 值范围: ${fkStat.minValue} - ${fkStat.maxValue}`);
console.log(` - NULL值数: ${fkStat.nullCount}`);
console.log(` - 无效引用: ${fkStat.invalidReferences}`);
console.log(` - 完整性问题: ${fkStat.hasIntegrityIssues ? '是' : '否'}`);
console.log('');
} catch (error) {
console.log(`${table}.${column}: 分析失败 - ${error.message}`);
}
}
// 生成依赖关系图
console.log('\n=== 表依赖关系 ===\n');
const dependencyGraph = new Map();
foreignKeys.forEach(fk => {
if (!dependencyGraph.has(fk.table_name)) {
dependencyGraph.set(fk.table_name, new Set());
}
dependencyGraph.get(fk.table_name).add(fk.referenced_table);
});
// 计算更新顺序(拓扑排序)
const updateOrder = [];
const visited = new Set();
const visiting = new Set();
function topologicalSort(table) {
if (visiting.has(table)) {
console.log(`⚠️ 检测到循环依赖: ${table}`);
return;
}
if (visited.has(table)) {
return;
}
visiting.add(table);
const dependencies = dependencyGraph.get(table) || new Set();
for (const dep of dependencies) {
topologicalSort(dep);
}
visiting.delete(table);
visited.add(table);
updateOrder.push(table);
}
// 对所有表进行拓扑排序
const allTables = new Set([...tablesWithForeignKeys, ...referencedTables]);
for (const table of allTables) {
topologicalSort(table);
}
console.log('建议的ID重排顺序被引用的表优先:');
updateOrder.reverse().forEach((table, index) => {
const deps = dependencyGraph.get(table);
const depList = deps ? Array.from(deps).join(', ') : '无';
console.log(`${index + 1}. ${table} (依赖: ${depList})`);
});
// 汇总报告
console.log('\n=== 汇总报告 ===');
console.log(`外键关系总数: ${foreignKeys.length}`);
console.log(`涉及外键的表: ${tablesWithForeignKeys.size}`);
console.log(`被引用的表: ${referencedTables.size}`);
const tablesWithIssues = foreignKeyStats.filter(stat => stat.hasIntegrityIssues);
if (tablesWithIssues.length > 0) {
console.log(`\n⚠️ 发现完整性问题的表:`);
tablesWithIssues.forEach(stat => {
console.log(`- ${stat.table}.${stat.column}: ${stat.invalidReferences} 个无效引用`);
});
} else {
console.log('\n✅ 所有外键关系完整性正常');
}
return {
foreignKeys,
foreignKeyStats,
updateOrder: updateOrder.reverse(),
relationshipMap,
tablesWithIssues
};
} catch (error) {
console.error('分析外键关系失败:', error);
throw error;
} finally {
await sequelize.close();
}
}
// 如果直接运行此脚本
if (require.main === module) {
analyzeForeignKeys()
.then(() => {
console.log('\n分析完成!');
process.exit(0);
})
.catch(error => {
console.error('分析失败:', error);
process.exit(1);
});
}
module.exports = { analyzeForeignKeys };

View File

@@ -0,0 +1,19 @@
const { sequelize } = require('./config/database-simple');
async function checkAlertsStatus() {
try {
await sequelize.authenticate();
console.log('数据库连接成功');
const [results] = await sequelize.query('SHOW COLUMNS FROM alerts LIKE "status"');
console.log('Alerts表status字段信息:');
console.table(results);
} catch (error) {
console.error('查询失败:', error.message);
} finally {
await sequelize.close();
}
}
checkAlertsStatus();

View File

@@ -0,0 +1,80 @@
/**
* 检查当前数据库中的经纬度数据
* @file check-current-data.js
*/
const { Farm } = require('./models');
const { sequelize } = require('./config/database-simple');
async function checkCurrentData() {
try {
console.log('连接数据库...');
await sequelize.authenticate();
console.log('\n查询最近的养殖场记录...');
const farms = await Farm.findAll({
attributes: ['id', 'name', 'location', 'created_at'],
order: [['id', 'DESC']],
limit: 10
});
console.log(`\n找到 ${farms.length} 条记录:`);
console.log('=' .repeat(80));
farms.forEach((farm, index) => {
console.log(`${index + 1}. ID: ${farm.id}`);
console.log(` 名称: ${farm.name}`);
console.log(` Location对象: ${JSON.stringify(farm.location)}`);
if (farm.location && typeof farm.location === 'object') {
const lng = farm.location.lng;
const lat = farm.location.lat;
console.log(` 经度 (lng): ${lng} (类型: ${typeof lng})`);
console.log(` 纬度 (lat): ${lat} (类型: ${typeof lat})`);
if (lng !== undefined || lat !== undefined) {
console.log(` ✅ 有经纬度数据`);
} else {
console.log(` ❌ 无经纬度数据`);
}
} else {
console.log(` ❌ Location字段为空或格式错误`);
}
console.log(` 创建时间: ${farm.created_at}`);
console.log('-'.repeat(60));
});
// 查找包含经纬度数据的记录
console.log('\n查找包含经纬度数据的记录...');
const farmsWithLocation = await Farm.findAll({
where: sequelize.literal("JSON_EXTRACT(location, '$.lng') IS NOT NULL OR JSON_EXTRACT(location, '$.lat') IS NOT NULL"),
attributes: ['id', 'name', 'location'],
order: [['id', 'DESC']],
limit: 5
});
console.log(`\n包含经纬度数据的记录 (${farmsWithLocation.length} 条):`);
farmsWithLocation.forEach(farm => {
console.log(`ID: ${farm.id}, 名称: ${farm.name}`);
console.log(`经度: ${farm.location.lng}, 纬度: ${farm.location.lat}`);
console.log('');
});
} catch (error) {
console.error('查询失败:', error.message);
if (error.sql) {
console.error('SQL:', error.sql);
}
} finally {
await sequelize.close();
console.log('数据库连接已关闭');
}
}
// 运行检查
if (require.main === module) {
checkCurrentData();
}
module.exports = { checkCurrentData };

View File

@@ -0,0 +1,23 @@
const { Device } = require('./models');
(async () => {
try {
const devices = await Device.findAll({
limit: 5,
attributes: ['id', 'name', 'type']
});
console.log('前5个设备:');
devices.forEach(d => {
console.log(`ID: ${d.id}, 名称: ${d.name}, 类型: ${d.type}`);
});
const totalCount = await Device.count();
console.log(`\n设备总数: ${totalCount}`);
} catch (error) {
console.error('检查设备时出错:', error);
} finally {
process.exit();
}
})();

View File

@@ -0,0 +1,56 @@
const { Animal, Device, Alert, Order } = require('./models');
async function checkFarmForeignKeys() {
try {
console.log('检查引用farms表的外键情况...');
// 检查animals表
const animals = await Animal.findAll({
attributes: ['id', 'farmId'],
order: [['farmId', 'ASC']]
});
console.log('\nAnimals表中的farmId分布:');
const animalFarmIds = [...new Set(animals.map(a => a.farmId))].sort((a, b) => a - b);
console.log('引用的farmId:', animalFarmIds);
console.log(`总共 ${animals.length} 条动物记录`);
// 检查devices表
const devices = await Device.findAll({
attributes: ['id', 'farmId'],
order: [['farmId', 'ASC']]
});
console.log('\nDevices表中的farmId分布:');
const deviceFarmIds = [...new Set(devices.map(d => d.farmId))].sort((a, b) => a - b);
console.log('引用的farmId:', deviceFarmIds);
console.log(`总共 ${devices.length} 条设备记录`);
// 检查alerts表
const alerts = await Alert.findAll({
attributes: ['id', 'farmId'],
order: [['farmId', 'ASC']]
});
console.log('\nAlerts表中的farmId分布:');
const alertFarmIds = [...new Set(alerts.map(a => a.farmId))].sort((a, b) => a - b);
console.log('引用的farmId:', alertFarmIds);
console.log(`总共 ${alerts.length} 条警报记录`);
// 检查orders表
const orders = await Order.findAll({
attributes: ['id', 'farmId'],
order: [['farmId', 'ASC']]
});
console.log('\nOrders表中的farmId分布:');
const orderFarmIds = [...new Set(orders.map(o => o.farmId))].sort((a, b) => a - b);
console.log('引用的farmId:', orderFarmIds);
console.log(`总共 ${orders.length} 条订单记录`);
} catch (error) {
console.error('检查失败:', error.message);
}
}
checkFarmForeignKeys();

View File

@@ -0,0 +1,28 @@
const { Farm } = require('./models');
async function checkFarmsId() {
try {
console.log('检查farms表ID分布情况...');
const farms = await Farm.findAll({
order: [['id', 'ASC']]
});
console.log('当前farms表ID分布:');
farms.forEach(farm => {
console.log(`ID: ${farm.id}, Name: ${farm.name}`);
});
console.log(`\n总共有 ${farms.length} 个养殖场`);
if (farms.length > 0) {
console.log(`最小ID: ${farms[0].id}`);
console.log(`最大ID: ${farms[farms.length - 1].id}`);
}
} catch (error) {
console.error('检查失败:', error.message);
}
}
checkFarmsId();

View File

@@ -0,0 +1,48 @@
const { sequelize } = require('./config/database-simple');
async function checkFarmsSQL() {
try {
console.log('检查farms表状态...');
// 检查表是否存在
const tables = await sequelize.query("SHOW TABLES LIKE 'farms'");
console.log('farms表存在:', tables[0].length > 0);
if (tables[0].length > 0) {
// 检查记录数
const count = await sequelize.query('SELECT COUNT(*) as count FROM farms');
console.log('farms表记录数:', count[0][0].count);
// 如果有记录,显示所有记录
if (count[0][0].count > 0) {
const farms = await sequelize.query('SELECT * FROM farms ORDER BY id ASC');
console.log('farms表数据:');
farms[0].forEach(farm => {
console.log(`ID: ${farm.id}, Name: ${farm.name}`);
});
}
// 检查临时表是否还存在
const tempTables = await sequelize.query("SHOW TABLES LIKE 'farms_temp'");
console.log('farms_temp表存在:', tempTables[0].length > 0);
if (tempTables[0].length > 0) {
const tempCount = await sequelize.query('SELECT COUNT(*) as count FROM farms_temp');
console.log('farms_temp表记录数:', tempCount[0][0].count);
if (tempCount[0][0].count > 0) {
const tempFarms = await sequelize.query('SELECT * FROM farms_temp ORDER BY id ASC');
console.log('farms_temp表数据:');
tempFarms[0].forEach(farm => {
console.log(`ID: ${farm.id}, Name: ${farm.name}`);
});
}
}
}
} catch (error) {
console.error('检查失败:', error.message);
}
}
checkFarmsSQL();

View File

@@ -0,0 +1,69 @@
const { sequelize } = require('./config/database-simple');
async function checkOrphanedForeignKeys() {
try {
console.log('检查孤立外键数据...');
// 检查farm_id=12的记录数量
const [devicesResult] = await sequelize.query(
'SELECT COUNT(*) as count FROM devices WHERE farm_id = 12'
);
const [alertsResult] = await sequelize.query(
'SELECT COUNT(*) as count FROM alerts WHERE farm_id = 12'
);
const [animalsResult] = await sequelize.query(
'SELECT COUNT(*) as count FROM animals WHERE farm_id = 12'
);
console.log('\nfarm_id=12的孤立记录数量:');
console.log('devices表:', devicesResult[0].count);
console.log('alerts表:', alertsResult[0].count);
console.log('animals表:', animalsResult[0].count);
// 检查具体的孤立记录
if (devicesResult[0].count > 0) {
const [devices] = await sequelize.query(
'SELECT id, name, type FROM devices WHERE farm_id = 12'
);
console.log('\ndevices表中farm_id=12的记录:');
devices.forEach(device => {
console.log(`- ID: ${device.id}, 名称: ${device.name}, 类型: ${device.type}`);
});
}
if (alertsResult[0].count > 0) {
const [alerts] = await sequelize.query(
'SELECT id, type, level FROM alerts WHERE farm_id = 12'
);
console.log('\nalerts表中farm_id=12的记录:');
alerts.forEach(alert => {
console.log(`- ID: ${alert.id}, 类型: ${alert.type}, 级别: ${alert.level}`);
});
}
if (animalsResult[0].count > 0) {
const [animals] = await sequelize.query(
'SELECT id, type, count FROM animals WHERE farm_id = 12'
);
console.log('\nanimals表中farm_id=12的记录:');
animals.forEach(animal => {
console.log(`- ID: ${animal.id}, 类型: ${animal.type}, 数量: ${animal.count}`);
});
}
// 检查farms表的最大ID
const [farmsMaxId] = await sequelize.query(
'SELECT MAX(id) as max_id FROM farms'
);
console.log('\nfarms表最大ID:', farmsMaxId[0].max_id);
} catch (error) {
console.error('检查失败:', error.message);
} finally {
await sequelize.close();
}
}
checkOrphanedForeignKeys();

View File

@@ -0,0 +1,128 @@
/**
* 检查数据库中所有表的主键ID分布情况
* @file check-primary-keys.js
* @description 分析各表的主键ID范围为重新排序做准备
*/
const { sequelize } = require('./config/database-simple');
const { QueryTypes } = require('sequelize');
async function checkPrimaryKeys() {
try {
console.log('=== 检查数据库表主键ID分布情况 ===\n');
// 获取所有表名
const tables = await sequelize.query(
"SELECT TABLE_NAME as table_name FROM information_schema.tables WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'",
{ type: QueryTypes.SELECT }
);
console.log(`发现 ${tables.length} 个表:\n`);
const tableStats = [];
for (const table of tables) {
const tableName = table.table_name;
try {
// 检查表是否有id字段
const columns = await sequelize.query(
`SELECT COLUMN_NAME as column_name, DATA_TYPE as data_type, IS_NULLABLE as is_nullable, COLUMN_KEY as column_key
FROM information_schema.columns
WHERE table_schema = DATABASE() AND TABLE_NAME = '${tableName}' AND COLUMN_NAME = 'id'`,
{ type: QueryTypes.SELECT }
);
if (columns.length === 0) {
console.log(`${tableName}: 没有id字段`);
continue;
}
// 获取ID统计信息
const stats = await sequelize.query(
`SELECT
COUNT(*) as total_count,
MIN(id) as min_id,
MAX(id) as max_id,
COUNT(DISTINCT id) as unique_count
FROM ${tableName}`,
{ type: QueryTypes.SELECT }
);
const stat = stats[0];
// 检查ID连续性
const gapCheck = await sequelize.query(
`SELECT COUNT(*) as gap_count
FROM (
SELECT id + 1 as next_id
FROM ${tableName}
WHERE id + 1 NOT IN (SELECT id FROM ${tableName})
AND id < (SELECT MAX(id) FROM ${tableName})
) as gaps`,
{ type: QueryTypes.SELECT }
);
const hasGaps = gapCheck[0].gap_count > 0;
const tableInfo = {
tableName,
totalCount: parseInt(stat.total_count),
minId: stat.min_id,
maxId: stat.max_id,
uniqueCount: parseInt(stat.unique_count),
hasGaps,
needsReorder: stat.min_id !== 1 || hasGaps
};
tableStats.push(tableInfo);
console.log(`${tableName}:`);
console.log(` - 记录数: ${tableInfo.totalCount}`);
console.log(` - ID范围: ${tableInfo.minId} - ${tableInfo.maxId}`);
console.log(` - 唯一ID数: ${tableInfo.uniqueCount}`);
console.log(` - 有间隙: ${hasGaps ? '是' : '否'}`);
console.log(` - 需要重排: ${tableInfo.needsReorder ? '是' : '否'}`);
console.log('');
} catch (error) {
console.log(`${tableName}: 检查失败 - ${error.message}`);
}
}
// 汇总统计
console.log('\n=== 汇总统计 ===');
const needReorderTables = tableStats.filter(t => t.needsReorder);
console.log(`需要重新排序的表: ${needReorderTables.length}/${tableStats.length}`);
if (needReorderTables.length > 0) {
console.log('\n需要重新排序的表:');
needReorderTables.forEach(table => {
console.log(`- ${table.tableName} (${table.minId}-${table.maxId}, ${table.totalCount}条记录)`);
});
}
return tableStats;
} catch (error) {
console.error('检查主键失败:', error);
throw error;
} finally {
await sequelize.close();
}
}
// 如果直接运行此脚本
if (require.main === module) {
checkPrimaryKeys()
.then(() => {
console.log('\n检查完成!');
process.exit(0);
})
.catch(error => {
console.error('检查失败:', error);
process.exit(1);
});
}
module.exports = { checkPrimaryKeys };

View File

@@ -0,0 +1,48 @@
const db = require('./config/database');
const SensorData = require('./models/SensorData');
(async () => {
try {
// 检查传感器数据总数
const count = await SensorData.count();
console.log('传感器数据总数:', count);
// 检查最近的温度数据
const temperatureData = await SensorData.findAll({
where: { sensor_type: 'temperature' },
limit: 10,
order: [['recorded_at', 'DESC']]
});
console.log('\n最近10条温度数据:');
temperatureData.forEach(r => {
console.log(`${r.sensor_type}: ${r.value}${r.unit} at ${r.recorded_at}`);
});
// 检查最近的湿度数据
const humidityData = await SensorData.findAll({
where: { sensor_type: 'humidity' },
limit: 10,
order: [['recorded_at', 'DESC']]
});
console.log('\n最近10条湿度数据:');
humidityData.forEach(r => {
console.log(`${r.sensor_type}: ${r.value}${r.unit} at ${r.recorded_at}`);
});
// 检查24小时内的数据
const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
const recentCount = await SensorData.count({
where: {
recorded_at: {
[require('sequelize').Op.gte]: twentyFourHoursAgo
}
}
});
console.log('\n24小时内的传感器数据总数:', recentCount);
} catch (error) {
console.error('检查数据时出错:', error);
} finally {
process.exit();
}
})();

View File

@@ -0,0 +1,19 @@
const { sequelize } = require('./config/database-simple');
async function checkSensorTable() {
try {
await sequelize.authenticate();
console.log('数据库连接成功');
const [results] = await sequelize.query('SHOW COLUMNS FROM sensor_data');
console.log('sensor_data表结构:');
console.table(results);
} catch (error) {
console.error('查询失败:', error.message);
} finally {
await sequelize.close();
}
}
checkSensorTable();

View File

@@ -0,0 +1,47 @@
const { Animal, Device, Alert, Order, Farm } = require('./models');
async function checkTableColumns() {
try {
console.log('检查各表的列结构...');
// 检查farms表结构
console.log('\n=== Farms表结构 ===');
const farmAttrs = await Farm.describe();
Object.keys(farmAttrs).forEach(col => {
console.log(`${col}: ${farmAttrs[col].type}`);
});
// 检查animals表结构
console.log('\n=== Animals表结构 ===');
const animalAttrs = await Animal.describe();
Object.keys(animalAttrs).forEach(col => {
console.log(`${col}: ${animalAttrs[col].type}`);
});
// 检查devices表结构
console.log('\n=== Devices表结构 ===');
const deviceAttrs = await Device.describe();
Object.keys(deviceAttrs).forEach(col => {
console.log(`${col}: ${deviceAttrs[col].type}`);
});
// 检查alerts表结构
console.log('\n=== Alerts表结构 ===');
const alertAttrs = await Alert.describe();
Object.keys(alertAttrs).forEach(col => {
console.log(`${col}: ${alertAttrs[col].type}`);
});
// 检查orders表结构
console.log('\n=== Orders表结构 ===');
const orderAttrs = await Order.describe();
Object.keys(orderAttrs).forEach(col => {
console.log(`${col}: ${orderAttrs[col].type}`);
});
} catch (error) {
console.error('检查失败:', error.message);
}
}
checkTableColumns();

View File

@@ -0,0 +1,53 @@
/**
* 检查并同步数据库表结构脚本
*/
const { sequelize } = require('./models/index');
async function checkAndSyncDatabase() {
try {
console.log('连接数据库...');
await sequelize.authenticate();
console.log('数据库连接成功');
// 强制同步数据库(这会删除现有表并重新创建)
console.log('\n开始同步数据库模型...');
await sequelize.sync({ force: true });
console.log('数据库模型同步完成');
// 检查创建的表
console.log('\n=== 检查创建的表 ===');
const [tables] = await sequelize.query("SHOW TABLES");
console.log('已创建的表:', tables.map(row => Object.values(row)[0]));
// 检查devices表结构
console.log('\n=== devices表结构 ===');
const [devicesFields] = await sequelize.query("DESCRIBE devices");
console.log('devices表字段:');
devicesFields.forEach(field => {
console.log(`- ${field.Field}: ${field.Type} (${field.Null === 'YES' ? 'NULL' : 'NOT NULL'})`);
});
// 检查animals表结构
console.log('\n=== animals表结构 ===');
const [animalsFields] = await sequelize.query("DESCRIBE animals");
console.log('animals表字段:');
animalsFields.forEach(field => {
console.log(`- ${field.Field}: ${field.Type} (${field.Null === 'YES' ? 'NULL' : 'NOT NULL'})`);
});
// 检查alerts表结构
console.log('\n=== alerts表结构 ===');
const [alertsFields] = await sequelize.query("DESCRIBE alerts");
console.log('alerts表字段:');
alertsFields.forEach(field => {
console.log(`- ${field.Field}: ${field.Type} (${field.Null === 'YES' ? 'NULL' : 'NOT NULL'})`);
});
} catch (error) {
console.error('操作失败:', error);
} finally {
await sequelize.close();
}
}
checkAndSyncDatabase();

View File

@@ -0,0 +1,50 @@
const { User, Role } = require('./models');
const { sequelize } = require('./config/database-simple');
const bcrypt = require('bcrypt');
async function checkUsers() {
try {
console.log('连接数据库...');
await sequelize.authenticate();
console.log('数据库连接成功');
// 查看所有用户
console.log('\n=== 查看所有用户 ===');
const users = await User.findAll({
attributes: ['id', 'username', 'email', 'password', 'status']
});
console.log('用户数量:', users.length);
users.forEach(user => {
console.log(`ID: ${user.id}, 用户名: ${user.username}, 邮箱: ${user.email}, 状态: ${user.status}`);
console.log(`密码哈希: ${user.password}`);
});
// 测试密码验证
console.log('\n=== 测试密码验证 ===');
const testPassword = '123456';
// 测试testuser的密码
const testHash1 = '$2b$10$CT0Uk9ueBFN4jc/5vnKGguDfr4cAyV3NUXKVKG6GrFJVsbcJakXLy'; // testuser的哈希
const isValid1 = await bcrypt.compare(testPassword, testHash1);
console.log('testuser密码验证结果:', isValid1);
// 测试testuser2的密码
const testHash2 = '$2b$10$KJAf.o1ItgiTeff9dAJqyeLQ.f2QCRCR2cUlU/DLn6ifXcBLM3FvK'; // testuser2的哈希
const isValid2 = await bcrypt.compare(testPassword, testHash2);
console.log('testuser2密码验证结果:', isValid2);
// 测试手动生成的哈希
const manualHash = await bcrypt.hash(testPassword, 10);
console.log('手动生成的哈希:', manualHash);
const isValid3 = await bcrypt.compare(testPassword, manualHash);
console.log('手动哈希验证结果:', isValid3);
} catch (error) {
console.error('检查用户失败:', error);
} finally {
await sequelize.close();
}
}
checkUsers();

View File

@@ -0,0 +1,27 @@
const { User } = require('./models');
const bcrypt = require('bcrypt');
User.findOne({ where: { username: 'admin' } })
.then(user => {
if (user) {
console.log('Admin 用户信息:');
console.log(`用户名: ${user.username}`);
console.log(`邮箱: ${user.email}`);
console.log(`密码哈希: ${user.password}`);
// 测试常见密码
const testPasswords = ['123456', 'admin', 'password', 'admin123'];
testPasswords.forEach(pwd => {
const isMatch = bcrypt.compareSync(pwd, user.password);
console.log(`密码 '${pwd}': ${isMatch ? '匹配' : '不匹配'}`);
});
} else {
console.log('未找到 admin 用户');
}
process.exit(0);
})
.catch(err => {
console.error('查询失败:', err);
process.exit(1);
});

View File

@@ -0,0 +1,14 @@
const { User } = require('./models');
User.findAll({ attributes: ['username', 'email'] })
.then(users => {
console.log('数据库中的用户:');
users.forEach(user => {
console.log(`用户名: ${user.username}, 邮箱: ${user.email}`);
});
process.exit(0);
})
.catch(err => {
console.error('查询失败:', err);
process.exit(1);
});

View File

@@ -0,0 +1,26 @@
const { sequelize } = require('./config/database-simple');
async function countData() {
try {
await sequelize.authenticate();
console.log('数据库连接成功\n');
// 检查各表的数据量
const tables = ['farms', 'animals', 'devices', 'alerts', 'sensor_data'];
console.log('=== 数据统计 ===');
for (const table of tables) {
const [results] = await sequelize.query(`SELECT COUNT(*) as count FROM ${table}`);
console.log(`${table.padEnd(12)}: ${results[0].count.toString().padStart(6)} 条记录`);
}
console.log('\n数据导入完成');
} catch (error) {
console.error('统计失败:', error.message);
} finally {
await sequelize.close();
}
}
countData();

View File

@@ -0,0 +1,32 @@
const { sequelize } = require('./config/database-simple');
async function verifyData() {
try {
await sequelize.authenticate();
console.log('数据库连接成功');
// 检查各表的数据量
const tables = ['farms', 'animals', 'devices', 'alerts', 'sensor_data'];
for (const table of tables) {
const [results] = await sequelize.query(`SELECT COUNT(*) as count FROM ${table}`);
console.log(`${table} 表: ${results[0].count} 条记录`);
}
// 检查最新的一些数据
console.log('\n=== 最新的预警数据 ===');
const [alerts] = await sequelize.query('SELECT * FROM alerts ORDER BY created_at DESC LIMIT 5');
console.table(alerts);
console.log('\n=== 最新的传感器数据 ===');
const [sensors] = await sequelize.query('SELECT * FROM sensor_data ORDER BY recorded_at DESC LIMIT 10');
console.table(sensors);
} catch (error) {
console.error('验证失败:', error.message);
} finally {
await sequelize.close();
}
}
verifyData();

View File

@@ -0,0 +1,105 @@
const mysql = require('mysql2/promise');
require('dotenv').config();
async function verifyEnvironmentData() {
let connection;
try {
// 创建数据库连接
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_NAME
});
console.log('数据库连接成功');
// 检查表是否存在
const [tables] = await connection.execute(
"SHOW TABLES LIKE 'environment_schedules'"
);
if (tables.length === 0) {
console.log('环境监测时刻表不存在');
return;
}
console.log('环境监测时刻表存在');
// 获取总记录数
const [countResult] = await connection.execute(
'SELECT COUNT(*) as total_records FROM environment_schedules'
);
console.log(`\n总记录数: ${countResult[0].total_records}`);
// 按农场分组统计
const [farmStats] = await connection.execute(
`SELECT farm_id, COUNT(*) as record_count,
MIN(monitoring_date) as earliest_date,
MAX(monitoring_date) as latest_date
FROM environment_schedules
GROUP BY farm_id
ORDER BY farm_id`
);
console.log('\n按农场统计:');
farmStats.forEach(stat => {
console.log(`农场${stat.farm_id}: ${stat.record_count}条记录, 日期范围: ${stat.earliest_date}${stat.latest_date}`);
});
// 获取最新的10条记录
const [recentRecords] = await connection.execute(
`SELECT farm_id, device_id, schedule_time, temperature, humidity,
DATE(monitoring_date) as date, status
FROM environment_schedules
ORDER BY monitoring_date DESC, schedule_time DESC
LIMIT 10`
);
console.log('\n最新的10条环境监测记录:');
console.log('农场ID | 设备ID | 日期 | 时间 | 温度(°C) | 湿度(%) | 状态');
console.log('-------|----------|------------|----------|----------|---------|--------');
recentRecords.forEach(record => {
console.log(`${record.farm_id.toString().padEnd(6)} | ${record.device_id.padEnd(8)} | ${record.date} | ${record.schedule_time} | ${record.temperature.toString().padEnd(8)} | ${record.humidity.toString().padEnd(7)} | ${record.status}`);
});
// 检查数据分布
const [timeStats] = await connection.execute(
`SELECT schedule_time, COUNT(*) as count
FROM environment_schedules
GROUP BY schedule_time
ORDER BY schedule_time`
);
console.log('\n按监测时间统计:');
timeStats.forEach(stat => {
console.log(`${stat.schedule_time}: ${stat.count}条记录`);
});
// 温度湿度范围统计
const [rangeStats] = await connection.execute(
`SELECT
MIN(temperature) as min_temp, MAX(temperature) as max_temp, AVG(temperature) as avg_temp,
MIN(humidity) as min_humidity, MAX(humidity) as max_humidity, AVG(humidity) as avg_humidity
FROM environment_schedules`
);
console.log('\n温度湿度统计:');
const stats = rangeStats[0];
console.log(`温度范围: ${parseFloat(stats.min_temp).toFixed(2)}°C - ${parseFloat(stats.max_temp).toFixed(2)}°C (平均: ${parseFloat(stats.avg_temp).toFixed(2)}°C)`);
console.log(`湿度范围: ${parseFloat(stats.min_humidity).toFixed(2)}% - ${parseFloat(stats.max_humidity).toFixed(2)}% (平均: ${parseFloat(stats.avg_humidity).toFixed(2)}%)`);
} catch (error) {
console.error('验证失败:', error.message);
} finally {
if (connection) {
await connection.end();
console.log('\n数据库连接已关闭');
}
}
}
// 运行验证脚本
verifyEnvironmentData();

View File

@@ -0,0 +1,110 @@
const { Farm } = require('./models');
/**
* 验证farms数据导入结果
*/
async function verifyFarmsImport() {
try {
console.log('验证farms数据导入结果...');
// 获取所有farms数据
const farms = await Farm.findAll({
order: [['id', 'ASC']]
});
console.log(`\n✅ 数据库中共有 ${farms.length} 个农场`);
// 验证API静态数据前3个
const apiStaticFarms = farms.slice(0, 3);
console.log('\n📊 API静态数据验证:');
apiStaticFarms.forEach(farm => {
console.log(` ID: ${farm.id}, Name: ${farm.name}, Type: ${farm.type}, Address: ${farm.address}`);
});
// 验证种子数据后8个
const seedFarms = farms.slice(3);
console.log('\n🌱 种子数据验证:');
seedFarms.forEach(farm => {
console.log(` ID: ${farm.id}, Name: ${farm.name}, Type: ${farm.type}, Address: ${farm.address}`);
});
// 验证数据完整性
console.log('\n🔍 数据完整性检查:');
const missingFields = [];
farms.forEach(farm => {
if (!farm.name) missingFields.push(`Farm ${farm.id}: 缺少name字段`);
if (!farm.type) missingFields.push(`Farm ${farm.id}: 缺少type字段`);
if (!farm.location) missingFields.push(`Farm ${farm.id}: 缺少location字段`);
if (!farm.status) missingFields.push(`Farm ${farm.id}: 缺少status字段`);
});
if (missingFields.length === 0) {
console.log(' ✅ 所有农场数据字段完整');
} else {
console.log(' ❌ 发现缺失字段:');
missingFields.forEach(field => console.log(` ${field}`));
}
// 验证ID连续性
const ids = farms.map(farm => farm.id);
const expectedIds = Array.from({length: farms.length}, (_, i) => i + 1);
const idsMatch = JSON.stringify(ids) === JSON.stringify(expectedIds);
if (idsMatch) {
console.log(' ✅ ID序列连续 (1 到 ' + farms.length + ')');
} else {
console.log(' ❌ ID序列不连续');
console.log(` 实际ID: [${ids.join(', ')}]`);
console.log(` 期望ID: [${expectedIds.join(', ')}]`);
}
// 统计农场类型
const typeStats = {};
farms.forEach(farm => {
typeStats[farm.type] = (typeStats[farm.type] || 0) + 1;
});
console.log('\n📈 农场类型统计:');
Object.entries(typeStats).forEach(([type, count]) => {
console.log(` ${type}: ${count}`);
});
// 验证地理位置数据
console.log('\n🗺 地理位置数据验证:');
const locationErrors = [];
farms.forEach(farm => {
try {
if (typeof farm.location === 'string') {
const location = JSON.parse(farm.location);
if (!location.lat || !location.lng) {
locationErrors.push(`Farm ${farm.id} (${farm.name}): 缺少经纬度信息`);
}
} else if (typeof farm.location === 'object') {
if (!farm.location.lat || !farm.location.lng) {
locationErrors.push(`Farm ${farm.id} (${farm.name}): 缺少经纬度信息`);
}
} else {
locationErrors.push(`Farm ${farm.id} (${farm.name}): location字段格式错误`);
}
} catch (error) {
locationErrors.push(`Farm ${farm.id} (${farm.name}): location JSON解析失败`);
}
});
if (locationErrors.length === 0) {
console.log(' ✅ 所有农场地理位置数据有效');
} else {
console.log(' ❌ 发现地理位置数据问题:');
locationErrors.forEach(error => console.log(` ${error}`));
}
console.log('\n🎉 farms数据导入验证完成!');
} catch (error) {
console.error('❌ 验证失败:', error.message);
}
}
// 执行验证
verifyFarmsImport();