init:代码初始化

This commit is contained in:
bai
2026-01-06 09:19:12 +08:00
parent 2dff90de4a
commit ba478d70cc
34 changed files with 11917 additions and 1 deletions

159
scripts/import-data.js Normal file
View File

@@ -0,0 +1,159 @@
require('dotenv').config();
const fs = require('fs');
const path = require('path');
const Price = require('../src/models/Price');
/**
* 数据导入脚本
* 从 JSON 文件导入钢材价格数据到数据库
*/
// 数据文件映射
const dataFiles = [
{ file: '刚协指导价.json', source: '云南钢协', priceField: 'PR_PRICESET_HANGPRICE' },
{ file: '钢材网架.json', source: '我的钢铁', priceField: 'PR_PRICESET_HANGPRICE' },
{ file: '钢厂指导价.json', source: '德钢指导价', priceField: 'PR_PRICESET_HANGPRICE' }
];
/**
* 转换数据格式
*/
function transformData(rawData, source, priceField) {
if (!rawData || !rawData.data || !rawData.data.page || !rawData.data.page.result) {
return [];
}
return rawData.data.page.result.map(item => {
return {
price_id: item.PRICE_ID || null,
goods_material: item.GOODS_MATERIAL || '未知',
goods_spec: item.GOODS_SPEC || '未知',
partsname_name: item.PARTSNAME_NAME || '未知',
productarea_name: item.PRODUCTAREA_NAME || '未知',
price_source: item.PR_PRICE_SOURCE || source,
price_region: item.PR_PRICE_REGION || '未知',
pntree_name: item.PNTREE_NAME || '钢筋',
price_date: item.PIRCE_DATE || null,
make_price: item.PR_PRICESET_MAKEPRICE || null,
hang_price: item[priceField] || 0,
last_make_price: item.PR_LAST_PRICESET_MAKEPRICE || null,
last_hang_price: item.PR_LAST_PRICESET_HANGPRICE || 0,
make_price_updw: item.PR_MAKEPRICE_UPDW || null,
hang_price_updw: item.PR_HANGPRICE_UPDW || '0',
operator_code: item.OPERATOR_CODE || null,
operator_name: item.OPERATOR_NAME || null
};
}).filter(item => item.price_date && item.hang_price > 0); // 过滤无效数据
}
/**
* 导入单个数据文件
*/
async function importFile(filePath, source, priceField) {
try {
console.log(`\n📄 正在读取文件: ${path.basename(filePath)}`);
// 读取 JSON 文件
const rawData = JSON.parse(fs.readFileSync(filePath, 'utf8'));
// 转换数据格式
const prices = transformData(rawData, source, priceField);
console.log(`✅ 解析到 ${prices.length} 条有效数据`);
if (prices.length === 0) {
console.log('⚠️ 没有有效数据可导入');
return 0;
}
// 批量插入数据库(每批 1000 条)
const batchSize = 1000;
let totalImported = 0;
for (let i = 0; i < prices.length; i += batchSize) {
const batch = prices.slice(i, i + batchSize);
const imported = await Price.batchInsert(batch);
totalImported += imported;
console.log(` 进度: ${Math.min(i + batchSize, prices.length)}/${prices.length}`);
}
console.log(`✅ 成功导入 ${totalImported} 条数据`);
return totalImported;
} catch (error) {
console.error(`❌ 导入文件失败 ${path.basename(filePath)}:`, error.message);
return 0;
}
}
/**
* 主导入函数
*/
async function importAllData() {
console.log('🚀 开始导入钢材价格数据...\n');
let totalImported = 0;
const dataDir = path.join(__dirname, '../data');
for (const { file, source, priceField } of dataFiles) {
const filePath = path.join(dataDir, file);
// 检查文件是否存在
if (!fs.existsSync(filePath)) {
console.log(`⚠️ 文件不存在,跳过: ${file}`);
continue;
}
const count = await importFile(filePath, source, priceField);
totalImported += count;
}
console.log('\n' + '='.repeat(50));
console.log(`🎉 数据导入完成!总计导入 ${totalImported} 条数据`);
console.log('='.repeat(50));
return totalImported;
}
/**
* 查看导入统计
*/
async function showStats() {
try {
const total = await Price.count();
const stats = await Price.getStats({});
console.log('\n📊 数据库统计信息:');
console.log(` 总记录数: ${total}`);
// 处理 avgPrice 可能是字符串或 null 的情况
if (stats.avgPrice) {
const avgPrice = typeof stats.avgPrice === 'number'
? stats.avgPrice.toFixed(2)
: parseFloat(stats.avgPrice).toFixed(2);
console.log(` 平均价格: ${avgPrice} 元/吨`);
} else {
console.log(` 平均价格: N/A`);
}
console.log(` 最低价格: ${stats.minPrice || 'N/A'} 元/吨`);
console.log(` 最高价格: ${stats.maxPrice || 'N/A'} 元/吨`);
} catch (error) {
console.error('❌ 获取统计信息失败:', error.message);
}
}
// 如果直接运行此脚本
if (require.main === module) {
importAllData()
.then(() => showStats())
.then(() => {
console.log('\n✅ 脚本执行完成');
process.exit(0);
})
.catch(err => {
console.error('\n❌ 脚本执行失败:', err);
process.exit(1);
});
}
module.exports = { importAllData, importFile, transformData };