163 lines
5.6 KiB
JavaScript
163 lines
5.6 KiB
JavaScript
import ExcelJS from 'exceljs';
|
|
import fs from 'fs/promises';
|
|
import path from 'path';
|
|
|
|
/**
|
|
* Flattens the nested JSON data into separate arrays for projects, licenses, and buildings.
|
|
* @param {Array<Object>} data - The nested data from merged_data.json.
|
|
* @returns {{projects: Array<Object>, licenses: Array<Object>, buildings: Array<Object>}}
|
|
*/
|
|
function flattenData(data) {
|
|
const projects = [];
|
|
const licenses = [];
|
|
const buildings = [];
|
|
|
|
data.forEach(project => {
|
|
// Create a shallow copy to avoid modifying the original object in memory
|
|
const projectCopy = { ...project };
|
|
const licensesData = projectCopy['预售许可证'];
|
|
// The nested array will not be included in the flattened project data
|
|
delete projectCopy['预售许可证'];
|
|
projects.push(projectCopy);
|
|
|
|
if (licensesData && Array.isArray(licensesData)) {
|
|
licensesData.forEach(license => {
|
|
const licenseCopy = { ...license };
|
|
const buildingsData = licenseCopy['楼幢'];
|
|
// The nested array will not be included in the flattened license data
|
|
delete licenseCopy['楼幢'];
|
|
|
|
// Add a key to link back to the parent project
|
|
licenseCopy['项目名称_key'] = project['项目名称'];
|
|
licenses.push(licenseCopy);
|
|
|
|
if (buildingsData && Array.isArray(buildingsData)) {
|
|
buildingsData.forEach(building => {
|
|
// Add keys to link back to the parent license and project
|
|
const buildingCopy = {
|
|
...building,
|
|
'许可证号_key': license['许可证号'],
|
|
'项目名称_key': project['项目名称'],
|
|
};
|
|
buildings.push(buildingCopy);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
return { projects, licenses, buildings };
|
|
}
|
|
|
|
|
|
/**
|
|
* Adds a worksheet to the workbook with the given data, headers, and styling.
|
|
* @param {ExcelJS.Workbook} workbook - The workbook instance.
|
|
* @param {string} sheetName - The name for the new worksheet.
|
|
* @param {Array<Object>} data - The array of data for the sheet.
|
|
*/
|
|
function addSheet(workbook, sheetName, data) {
|
|
if (data.length === 0) {
|
|
console.log(`- 注意: 没有数据可用于工作表 '${sheetName}'`);
|
|
return;
|
|
}
|
|
const worksheet = workbook.addWorksheet(sheetName);
|
|
// Get all unique keys from all objects to form a complete header
|
|
const allKeys = data.reduce((keys, item) => {
|
|
if (item) {
|
|
Object.keys(item).forEach(key => {
|
|
if (!keys.includes(key)) {
|
|
keys.push(key);
|
|
}
|
|
});
|
|
}
|
|
return keys;
|
|
}, []);
|
|
|
|
worksheet.columns = allKeys.map(key => ({
|
|
header: key,
|
|
key: key,
|
|
width: key.includes('地址') || key.includes('链接') || key.includes('简介') ? 50 : 25
|
|
}));
|
|
|
|
worksheet.addRows(data);
|
|
|
|
// Style header row
|
|
worksheet.getRow(1).eachCell(cell => {
|
|
cell.font = { bold: true };
|
|
cell.fill = {
|
|
type: 'pattern',
|
|
pattern: 'solid',
|
|
fgColor: { argb: 'FFD3D3D3' }
|
|
};
|
|
cell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
|
|
});
|
|
|
|
// Add autofilter to the header row
|
|
worksheet.autoFilter = {
|
|
from: 'A1',
|
|
to: {
|
|
row: 1,
|
|
column: allKeys.length
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
/**
|
|
* Generates a multi-sheet XLSX file from the nested real estate data.
|
|
* @param {Array<Object>} data - The nested data from merged_data.json.
|
|
* @param {string} filePath - The path to save the XLSX file.
|
|
*/
|
|
async function generateXlsx(data, filePath) {
|
|
if (!data || data.length === 0) {
|
|
console.log(`没有数据可生成 XLSX 文件 (${filePath})。`);
|
|
return;
|
|
}
|
|
|
|
console.log('正在将数据处理成多个工作表...');
|
|
const { projects, licenses, buildings } = flattenData(data);
|
|
console.log(`- 项目: ${projects.length} 条`);
|
|
console.log(`- 许可证: ${licenses.length} 条`);
|
|
console.log(`- 楼幢: ${buildings.length} 条`);
|
|
|
|
const workbook = new ExcelJS.Workbook();
|
|
workbook.creator = 'Gemini Assistant';
|
|
workbook.created = new Date();
|
|
workbook.modified = new Date();
|
|
|
|
console.log('正在创建 Excel 工作表...');
|
|
addSheet(workbook, '项目', projects);
|
|
addSheet(workbook, '预售许可证', licenses);
|
|
addSheet(workbook, '楼幢', buildings);
|
|
|
|
await workbook.xlsx.writeFile(filePath);
|
|
console.log(`✅ 成功生成多工作表 Excel 文件: ${filePath}`);
|
|
}
|
|
|
|
/**
|
|
* Main function to read data and trigger XLSX generation.
|
|
*/
|
|
async function run() {
|
|
console.log('🚀 开始生成 Excel 分析文件...');
|
|
const dataPath = path.join(process.cwd(), 'data', 'merged_data.json');
|
|
const outputPath = path.join(process.cwd(), '普宁房产数据分析.xlsx');
|
|
|
|
try {
|
|
await fs.access(dataPath);
|
|
console.log(`读取数据源: ${dataPath}`);
|
|
const jsonData = JSON.parse(await fs.readFile(dataPath, 'utf-8'));
|
|
await generateXlsx(jsonData, outputPath);
|
|
} catch (error) {
|
|
if (error.code === 'ENOENT') {
|
|
console.error(`❌ 错误: 未找到数据文件 '${path.basename(dataPath)}'。`);
|
|
console.error('请先运行 `npm start` 来生成完整的数据文件。');
|
|
} else {
|
|
console.error('❌ 生成 XLSX 文件时发生错误:', error);
|
|
}
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
run();
|