Project 'vue-project/liangXing/frontEnd' was moved to 'vue-project/ZhangJian/ZhangJianFrontEnd'. Please update any links and bookmarks that may still have the old path.
Commit 2ac68b34 by chenjinjing

no message

parent 49b94055
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -6,17 +6,21 @@ ...@@ -6,17 +6,21 @@
"dependencies": { "dependencies": {
"@alicloud/sms-sdk": "^1.1.6", "@alicloud/sms-sdk": "^1.1.6",
"@types/node": "^10.12.18", "@types/node": "^10.12.18",
"archiver": "^7.0.1",
"compression": "^1.7.4", "compression": "^1.7.4",
"exceljs": "^4.4.0",
"express": "^4.17.1", "express": "^4.17.1",
"express-async-handler": "^1.1.4", "express-async-handler": "^1.1.4",
"express-history-api-fallback": "^2.2.1", "express-history-api-fallback": "^2.2.1",
"formidable": "^1.2.1", "formidable": "^1.2.1",
"fs-extra": "^11.3.2",
"log4js": "^6.6.1", "log4js": "^6.6.1",
"lru-cache": "^4.1.5", "lru-cache": "^4.1.5",
"md5": "^2.2.1", "md5": "^2.2.1",
"moment": "^2.24.0", "moment": "^2.24.0",
"mongoose": "^5.4.0", "mongoose": "^5.4.0",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"node-fetch": "^2.7.0",
"node-xlsx": "^0.16.1", "node-xlsx": "^0.16.1",
"nodemailer": "^6.1.1", "nodemailer": "^6.1.1",
"officegen": "^0.6.5", "officegen": "^0.6.5",
......
<config> <config>
<port>9098</port> <port>9098</port>
<sign>xxx90909082fsdahfjosadjfpoiwausjorip2hjklrhn1ioud0u124rx0qwejfokasjfolksaujfoas</sign> <sign>xxx90909082fsdahfjosadjfpoiwausjorip2hjklrhn1ioud0u124rx0qwejfokasjfolksaujfoas</sign>
<dbServer>http://192.168.0.71:9096</dbServer> <dbServer>http://192.168.0.71:40012</dbServer>
<imgUrl>http://192.168.0.71:9098</imgUrl> <imgUrl>http://192.168.0.71:9098</imgUrl>
<imgFileUrl>http://192.168.0.71:9097</imgFileUrl> <imgFileUrl>http://192.168.0.71:9097</imgFileUrl>
<fileUrl>/yuyi/files/1/</fileUrl> <fileUrl>/yuyi/files/1/</fileUrl>
......
import { ERRORENUM } from "../config/enum/errorEnum";
import { BizError } from "../util/bizError";
import * as archiver from 'archiver';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as ExcelJS from 'exceljs';
import { selectData } from "../data/operationalData";
import { OPERATIONALDATATYPE, TABLENAME } from "../config/enum/dbEnum";
import { getAllDwOutPut } from './zaiFu';
const moment = require("moment");
const fetch = require('node-fetch');
/**
* 下载企业相关文件、数据表格和详情Excel的zip包
*/
export async function downloadEnterpriseFilesZip(eId: string) {
if (!eId) throw new BizError(ERRORENUM.参数错误, `下载企业文件缺失eId`);
try {
const projectRoot = path.resolve(__dirname, '../..');
const tempBaseDir = path.join(projectRoot, 'temp');
await fs.ensureDir(tempBaseDir);
const tempDir = path.join(tempBaseDir, `temp_enterprise_files_${eId}_${Date.now()}`);
console.log(`创建临时目录: ${tempDir}`);
await fs.ensureDir(tempDir);
// 获取企业名称
console.log('=== 开始获取企业信息 ===');
const enterpriseInfo = await getEnterpriseInfo(eId);
const enterpriseName = enterpriseInfo?.enterpriseName || '未知企业';
console.log(`企业名称: ${enterpriseName}`);
// 步骤1: 获取企业详情数据并生成Excel
console.log('=== 开始生成企业详情Excel ===');
const excelFilePath = await generateEnterpriseDetailExcel(eId, enterpriseName, tempDir);
// 步骤2: 下载企业相关文件
console.log('=== 开始下载企业文件 ===');
await downloadEnterpriseFiles(eId, tempDir);
// 步骤3: 创建zip文件
const safeEnterpriseName = sanitizeFileName(enterpriseName);
const zipFileName = `企业完整数据_${safeEnterpriseName}_${eId}_${moment().format('YYYYMMDDHHmmss')}.zip`;
const zipFilePath = path.join(tempBaseDir, zipFileName);
console.log(`创建ZIP文件: ${zipFilePath}`);
await createZipArchive(tempDir, zipFilePath);
const zipStats = await fs.stat(zipFilePath);
console.log(`ZIP文件创建成功,大小: ${zipStats.size} bytes`);
// 清理临时目录
console.log('清理临时目录...');
await fs.remove(tempDir);
return {
success: true,
filePath: zipFilePath,
fileName: zipFileName
};
} catch (error) {
console.error('下载企业文件zip包失败:', error);
throw new BizError(ERRORENUM.系统错误, '文件打包失败: ' + error.message);
}
}
/**
* 生成企业详情Excel文件
*/
async function generateEnterpriseDetailExcel(eId: string, enterpriseName: string, tempDir: string): Promise<string> {
try {
console.log('获取企业详情数据...');
const details = await getAllDwOutPut(eId);
console.log('企业详情数据结构:', JSON.stringify(details, null, 2));
const safeEnterpriseName = sanitizeFileName(enterpriseName);
const excelFileName = `企业详情_${safeEnterpriseName}_${eId}.xlsx`;
const excelFilePath = path.join(tempDir, excelFileName);
const workbook = new ExcelJS.Workbook();
// 设置文档属性
workbook.creator = '企业管理系统';
workbook.lastModifiedBy = '企业管理系统';
workbook.created = new Date();
workbook.modified = new Date();
// 1. 基础信息工作表
await createBasicInfoSheet(workbook, details.enterprise, '基础信息');
// 2. 经营数据工作表
await createBusinessDataSheet(workbook, details.manage, '经营数据');
// 3. 融资情况工作表
await createFinancingSheet(workbook, details.financing, '融资情况');
// 4. 荣誉奖项工作表
await createHonorSheet(workbook, details.honor, '荣誉奖项');
// 保存Excel文件
await workbook.xlsx.writeFile(excelFilePath);
console.log(`Excel文件生成成功: ${excelFilePath}`);
return excelFilePath;
} catch (error) {
console.error('生成企业详情Excel失败:', error);
throw new BizError(ERRORENUM.系统错误, '生成Excel文件失败: ' + error.message);
}
}
/**
* 创建基础信息工作表 - 表格格式
*/
async function createBasicInfoSheet(workbook: ExcelJS.Workbook, enterpriseData: any, sheetName: string) {
const worksheet = workbook.addWorksheet(sheetName);
if (!enterpriseData || !enterpriseData.dataList || !Array.isArray(enterpriseData.dataList)) {
worksheet.getCell('A1').value = '暂无基础信息数据';
return;
}
const dataList = enterpriseData.dataList;
// 设置列宽
worksheet.columns = [
{ width: 15 },
{ width: 20 },
{ width: 15 },
{ width: 25 },
{ width: 12 },
{ width: 25 },
{ width: 12 },
{ width: 8 },
{ width: 8 }
];
// 添加标题
worksheet.mergeCells('A1:I1');
const titleCell = worksheet.getCell('A1');
titleCell.value = '企业基础信息';
titleCell.font = { bold: true, size: 14 };
titleCell.alignment = { horizontal: 'center', vertical: 'middle' };
titleCell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFDDEBF7' }
};
// 添加表头(第一行)
if (dataList.length > 0 && Array.isArray(dataList[0])) {
const headerRow = worksheet.addRow(dataList[0]);
// 设置表头样式
headerRow.font = { bold: true, color: { argb: 'FFFFFFFF' } };
headerRow.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FF2F75B5' }
};
headerRow.alignment = { horizontal: 'center', vertical: 'middle' };
headerRow.height = 25;
}
// 添加数据行(从第二行开始)
let currentRow = 3; // 标题占1行,表头占1行,数据从第3行开始
for (let i = 1; i < dataList.length; i++) {
if (Array.isArray(dataList[i])) {
const dataRow = worksheet.addRow(dataList[i]);
// 设置数据行样式
dataRow.alignment = { horizontal: 'left', vertical: 'middle' };
// 交替行颜色
if (i % 2 === 0) {
dataRow.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFF2F2F2' }
};
}
currentRow++;
}
}
// 设置边框
const dataRange = `A2:I${currentRow}`;
for (let row = 2; row <= currentRow; row++) {
for (let col = 1; col <= 9; col++) {
const cell = worksheet.getCell(row, col);
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
};
}
}
console.log(`基础信息工作表创建完成,共 ${dataList.length - 1} 条数据`);
}
/**
* 创建经营数据工作表
*/
async function createBusinessDataSheet(workbook: ExcelJS.Workbook, manageData: any, sheetName: string) {
const worksheet = workbook.addWorksheet(sheetName);
if (!manageData || !manageData.dataList || !Array.isArray(manageData.dataList)) {
worksheet.getCell('A1').value = '暂无经营数据';
return;
}
const dataList = manageData.dataList;
// 设置列宽
worksheet.columns = [
{ width: 15 },
{ width: 20 },
{ width: 15 },
{ width: 15 },
{ width: 15 },
{ width: 15 }
];
// 添加标题
worksheet.mergeCells('A1:F1');
const titleCell = worksheet.getCell('A1');
titleCell.value = '企业经营数据';
titleCell.font = { bold: true, size: 14 };
titleCell.alignment = { horizontal: 'center', vertical: 'middle' };
titleCell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFE2EFDA' }
};
// 添加表头(第一行)
if (dataList.length > 0 && Array.isArray(dataList[0])) {
const headerRow = worksheet.addRow(dataList[0]);
// 设置表头样式
headerRow.font = { bold: true, color: { argb: 'FFFFFFFF' } };
headerRow.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FF70AD47' }
};
headerRow.alignment = { horizontal: 'center', vertical: 'middle' };
headerRow.height = 25;
}
// 添加数据行
let currentRow = 3;
let hasData = false;
for (let i = 1; i < dataList.length; i++) {
if (Array.isArray(dataList[i]) && dataList[i].some((cell: any) => cell && cell !== '-')) {
const dataRow = worksheet.addRow(dataList[i]);
// 设置数据行样式
dataRow.alignment = { horizontal: 'left', vertical: 'middle' };
// 交替行颜色
if (i % 2 === 0) {
dataRow.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFF2F2F2' }
};
}
currentRow++;
hasData = true;
}
}
if (!hasData) {
worksheet.getCell('A3').value = '暂无经营数据';
worksheet.getCell('A3').alignment = { horizontal: 'center', vertical: 'middle' };
} else {
// 设置边框
const dataRange = `A2:F${currentRow}`;
for (let row = 2; row <= currentRow; row++) {
for (let col = 1; col <= 6; col++) {
const cell = worksheet.getCell(row, col);
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
};
}
}
}
console.log(`经营数据工作表创建完成,共 ${dataList.length - 1} 条数据`);
}
/**
* 创建融资情况工作表
*/
async function createFinancingSheet(workbook: ExcelJS.Workbook, financingData: any, sheetName: string) {
const worksheet = workbook.addWorksheet(sheetName);
if (!financingData || !financingData.dataList || !Array.isArray(financingData.dataList)) {
worksheet.getCell('A1').value = '暂无融资数据';
return;
}
const dataList = financingData.dataList;
// 设置列宽
worksheet.columns = [
{ width: 15 },
{ width: 20 },
{ width: 15 },
{ width: 15 },
{ width: 15 },
{ width: 20 }
];
// 添加标题
worksheet.mergeCells('A1:F1');
const titleCell = worksheet.getCell('A1');
titleCell.value = '企业融资情况';
titleCell.font = { bold: true, size: 14 };
titleCell.alignment = { horizontal: 'center', vertical: 'middle' };
titleCell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFFFE699' }
};
// 添加表头(第一行)
if (dataList.length > 0 && Array.isArray(dataList[0])) {
const headerRow = worksheet.addRow(dataList[0]);
// 设置表头样式
headerRow.font = { bold: true, color: { argb: 'FFFFFFFF' } };
headerRow.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFFFC000' }
};
headerRow.alignment = { horizontal: 'center', vertical: 'middle' };
headerRow.height = 25;
}
// 添加数据行
let currentRow = 3;
let hasData = false;
for (let i = 1; i < dataList.length; i++) {
if (Array.isArray(dataList[i]) && dataList[i].some((cell: any) => cell && cell !== '-')) {
const dataRow = worksheet.addRow(dataList[i]);
// 设置数据行样式
dataRow.alignment = { horizontal: 'left', vertical: 'middle' };
// 交替行颜色
if (i % 2 === 0) {
dataRow.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFF2F2F2' }
};
}
currentRow++;
hasData = true;
}
}
if (!hasData) {
worksheet.getCell('A3').value = '暂无融资数据';
worksheet.getCell('A3').alignment = { horizontal: 'center', vertical: 'middle' };
} else {
// 设置边框
for (let row = 2; row <= currentRow; row++) {
for (let col = 1; col <= 6; col++) {
const cell = worksheet.getCell(row, col);
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
};
}
}
}
console.log(`融资情况工作表创建完成,共 ${dataList.length - 1} 条数据`);
}
/**
* 创建荣誉奖项工作表
*/
async function createHonorSheet(workbook: ExcelJS.Workbook, honorData: any, sheetName: string) {
const worksheet = workbook.addWorksheet(sheetName);
if (!honorData || !honorData.dataList || !Array.isArray(honorData.dataList)) {
worksheet.getCell('A1').value = '暂无荣誉数据';
return;
}
const dataList = honorData.dataList;
// 设置列宽
worksheet.columns = [
{ width: 15 },
{ width: 25 },
{ width: 20 },
{ width: 15 },
{ width: 15 }
];
// 添加标题
worksheet.mergeCells('A1:E1');
const titleCell = worksheet.getCell('A1');
titleCell.value = '企业荣誉奖项';
titleCell.font = { bold: true, size: 14 };
titleCell.alignment = { horizontal: 'center', vertical: 'middle' };
titleCell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFE6E0EC' }
};
// 添加表头(第一行)
if (dataList.length > 0 && Array.isArray(dataList[0])) {
const headerRow = worksheet.addRow(dataList[0]);
// 设置表头样式
headerRow.font = { bold: true, color: { argb: 'FFFFFFFF' } };
headerRow.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FF8064A2' }
};
headerRow.alignment = { horizontal: 'center', vertical: 'middle' };
headerRow.height = 25;
}
// 添加数据行
let currentRow = 3;
let hasData = false;
for (let i = 1; i < dataList.length; i++) {
if (Array.isArray(dataList[i]) && dataList[i].some((cell: any) => cell && cell !== '-')) {
const dataRow = worksheet.addRow(dataList[i]);
// 设置数据行样式
dataRow.alignment = { horizontal: 'left', vertical: 'middle' };
// 交替行颜色
if (i % 2 === 0) {
dataRow.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFF2F2F2' }
};
}
currentRow++;
hasData = true;
}
}
if (!hasData) {
worksheet.getCell('A3').value = '暂无荣誉数据';
worksheet.getCell('A3').alignment = { horizontal: 'center', vertical: 'middle' };
} else {
// 设置边框
for (let row = 2; row <= currentRow; row++) {
for (let col = 1; col <= 5; col++) {
const cell = worksheet.getCell(row, col);
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
};
}
}
}
console.log(`荣誉奖项工作表创建完成,共 ${dataList.length - 1} 条数据`);
}
/**
* 下载企业相关文件
*/
async function downloadEnterpriseFiles(eId: string, tempDir: string) {
// 先获取所有文件信息并验证
console.log('=== 开始验证文件信息 ===');
const leaseFiles = await getLeaseFiles(eId);
const leaseValidCount = await validateAndLogFiles(leaseFiles, '租赁信息');
const trademarkFiles = await getTrademarkFiles(eId);
const trademarkValidCount = await validateAndLogFiles(trademarkFiles, '商标');
const copyrightFiles = await getCopyrightFiles(eId);
const copyrightValidCount = await validateAndLogFiles(copyrightFiles, '作品著作权');
const softwareCopyrightFiles = await getSoftwareCopyrightFiles(eId);
const softwareValidCount = await validateAndLogFiles(softwareCopyrightFiles, '软件著作权');
const patentFiles = await getPatentFiles(eId);
const patentValidCount = await validateAndLogFiles(patentFiles, '专利');
console.log('=== 文件验证完成,开始下载 ===');
// 下载文件
await downloadAndSaveFiles(leaseFiles, path.join(tempDir, '租赁信息'), tempDir);
await downloadAndSaveFiles(trademarkFiles, path.join(tempDir, '商标'), tempDir);
await downloadAndSaveFiles(copyrightFiles, path.join(tempDir, '作品著作权'), tempDir);
await downloadAndSaveFiles(softwareCopyrightFiles, path.join(tempDir, '软件著作权'), tempDir);
await downloadAndSaveFiles(patentFiles, path.join(tempDir, '专利'), tempDir);
}
/**
* 获取企业信息
*/
async function getEnterpriseInfo(eId: string): Promise<any> {
try {
// 根据你的数据库结构调整查询
const enterpriseInfo = await selectData(
OPERATIONALDATATYPE.查询单个,
'enterprise', // 或者你的企业表名
{ eId },
['enterpriseName'] // 可能的名称字段
);
if (!enterpriseInfo) {
console.warn(`未找到企业信息: ${eId}`);
return null;
}
console.log(`获取到企业信息:`, enterpriseInfo);
return enterpriseInfo;
} catch (error) {
console.error(`获取企业信息失败: ${eId}`, error);
return null;
}
}
/**
* 清理文件名中的非法字符
*/
function sanitizeFileName(fileName: string): string {
if (!fileName) return '未知企业';
// 移除或替换文件名中的非法字符
return fileName
.replace(/[<>:"/\\|?*]/g, '_') // 替换Windows非法字符
.replace(/\s+/g, ' ') // 合并多个空格
.trim() // 去除首尾空格
.substring(0, 100); // 限制长度避免过长
}
/**
* 验证并记录文件信息
*/
async function validateAndLogFiles(files: {url: string, fileName: string}[], category: string) {
console.log(`\n=== ${category}文件验证 ===`);
console.log(`总数: ${files.length} 个文件`);
let existingCount = 0;
for (const file of files) {
console.log(`文件: ${file.fileName}`);
console.log(`URL: ${file.url}`);
// 检查文件是否存在
const exists = await checkFileExists(file.url);
console.log(`存在性: ${exists ? '存在' : '不存在'}`);
if (exists) {
existingCount++;
}
console.log('---');
}
console.log(`${category}文件统计: 存在 ${existingCount}/${files.length} 个文件`);
return existingCount;
}
/**
* 改进的下载函数 - 跳过不存在的文件
*/
async function downloadAndSaveFiles(files: {url: string, fileName: string}[], targetDir: string, baseTempDir: string): Promise<void> {
if (files.length === 0) {
console.log(`没有文件需要下载到目录: ${targetDir}`);
return;
}
await fs.ensureDir(targetDir);
// 先检查所有文件的存在性
const validFiles: {url: string, fileName: string}[] = [];
for (const file of files) {
const exists = await checkFileExists(file.url);
if (exists) {
validFiles.push(file);
console.log(`✅ 文件可用: ${file.fileName}`);
} else {
console.warn(`❌ 文件不存在,跳过: ${file.fileName} (${file.url})`);
}
}
console.log(`有效文件数量: ${validFiles.length}/${files.length}`);
if (validFiles.length === 0) {
console.log(`没有可下载的有效文件,跳过目录: ${targetDir}`);
return;
}
// 只下载存在的文件
const downloadPromises = validFiles.map(async (file) => {
try {
if (!file.url || typeof file.url !== 'string') {
console.warn(`文件URL无效:`, file.url);
return;
}
console.log(`开始下载文件: ${file.fileName} from ${file.url}`);
const fetchOptions: any = {
method: 'GET',
timeout: 30000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': '*/*'
}
};
// 关键修复:添加认证 token
const SECRET_TOKEN = "Ngz86cuAKxblwXR9OiKSWbfkj7oZ8R0lMU8pTfpVYBDCkvtUb0ZwbaBvwWyfv2O9";
// 如果是内部文件服务器的URL,添加认证token
if (file.url.includes('192.168.0.71') || file.url.includes('fh.tninnopark.cn')) {
fetchOptions.headers['token'] = SECRET_TOKEN;
console.log(`添加认证token到请求头`);
}
const response = await fetch(file.url, fetchOptions);
if (!response.ok) {
console.warn(`下载文件失败: ${file.url}, 状态码: ${response.status}`);
return;
}
const buffer = await response.buffer();
if (buffer.length === 0) {
console.warn(`文件内容为空: ${file.fileName}`);
return;
}
const filePath = path.join(targetDir, file.fileName);
await fs.writeFile(filePath, buffer);
console.log(`✅ 文件下载成功: ${file.fileName}, 大小: ${buffer.length} bytes`);
} catch (error) {
console.error(`下载文件失败: ${file.fileName} (${file.url})`, error.message);
}
});
const results = await Promise.allSettled(downloadPromises);
const successful = results.filter(result => result.status === 'fulfilled').length;
const failed = results.filter(result => result.status === 'rejected').length;
console.log(`目录 ${targetDir} 下载完成: 成功 ${successful} 个, 失败 ${failed} 个, 总共 ${validFiles.length} 个有效文件`);
}
/**
* 检查文件是否存在于文件服务器
*/
async function checkFileExists(url: string): Promise<boolean> {
try {
const SECRET_TOKEN = "Ngz86cuAKxblwXR9OiKSWbfkj7oZ8R0lMU8pTfpVYBDCkvtUb0ZwbaBvwWyfv2O9";
const fetchOptions: any = {
method: 'HEAD',
timeout: 10000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
};
// 同样为HEAD请求添加认证token
if (url.includes('192.168.0.71') || url.includes('fh.tninnopark.cn')) {
fetchOptions.headers['token'] = SECRET_TOKEN;
}
const response = await fetch(url, fetchOptions);
return response.ok;
} catch (error) {
console.log(`文件存在性检查失败: ${url}`, error.message);
return false;
}
}
/**
* 安全的URL构建函数,避免中文编码问题
*/
function buildSafeUrl(baseUrl: string, filePath: string): string {
// 确保基础URL格式正确
const cleanBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
// 确保文件路径格式正确
const cleanFilePath = filePath.startsWith('/') ? filePath : `/${filePath}`;
// 直接拼接,避免URL对象的自动编码
return `${cleanBaseUrl}${cleanFilePath}`;
}
/**
* 统一处理文件路径,将相对路径转换为绝对URL
* 修复中文文件名编码问题
* http://192.168.0.71:9097
* https://fh.tninnopark.cn
*/
function processFilePath(filePath: any, baseUrl: string = 'http://192.168.0.71:9097'): string | null {
if (!filePath) {
console.log('文件路径为空');
return null;
}
console.log(`原始文件路径: ${filePath}, 类型: ${typeof filePath}`);
// 如果是数组,取第一个元素
if (Array.isArray(filePath)) {
filePath = filePath[0];
}
// 处理JSON字符串格式
if (typeof filePath === 'string' && filePath.startsWith('[')) {
try {
const pathArray = JSON.parse(filePath);
filePath = pathArray[0];
console.log(`解析JSON数组路径: ${filePath}`);
} catch (e) {
console.warn('解析文件路径数组失败:', filePath);
return null;
}
}
// 验证路径格式
if (!filePath || typeof filePath !== 'string') {
return null;
}
// 如果已经是完整的URL,直接返回
if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
return filePath;
}
// 格式化基础URL
const formattedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
// 关键修复:确保路径格式正确且中文不被编码
let finalPath = filePath;
if (!finalPath.startsWith('/')) {
finalPath = '/' + finalPath;
}
// 构建完整的URL(不对路径部分进行编码)
const url = new URL(formattedBaseUrl);
url.pathname = finalPath;
const fullUrl = buildSafeUrl(baseUrl, finalPath);
console.log(`安全构建的URL: ${fullUrl}`);
return fullUrl;
}
/**
* 获取租赁信息相关文件
*/
async function getLeaseFiles(eId: string): Promise<{url: string, fileName: string}[]> {
const filesList = [
"sanFangXieYi", "fuHuaXieYi", "fangWuZuLing", "fuHuaXieYiBuChong",
"chengXinChengNuoHan", "yingYeZhiZhao", "ruFuZiLiao", "ruZhuJiHua",
"yaJinZhiFu", "cardCopy"
];
const leaseInfo = await selectData(
OPERATIONALDATATYPE.查询多个,
TABLENAME.租赁信息,
{ eId },
filesList
);
const files: {url: string, fileName: string}[] = [];
leaseInfo.forEach(lease => {
filesList.forEach(field => {
if (lease[field]) {
const processedUrl = processFilePath(lease[field]);
if (processedUrl) {
const fileName = getLeaseFileName(field, lease);
files.push({
url: processedUrl,
fileName: fileName
});
}
}
});
});
return files;
}
/**
* 获取租赁文件显示名称
*/
function getLeaseFileName(field: string, lease: any): string {
const nameMap: {[key: string]: string} = {
sanFangXieYi: '三方协议',
fuHuaXieYi: '孵化协议',
fangWuZuLing: '房屋租赁合同',
fuHuaXieYiBuChong: '孵化协议补充协议书',
chengXinChengNuoHan: '诚信承诺函',
yingYeZhiZhao: '营业执照复印件',
ruFuZiLiao: '入孵资料明细',
ruZhuJiHua: '入驻计划复印件',
yaJinZhiFu: '押金支付凭证',
cardCopy: '身份证复印件'
};
const baseName = nameMap[field] || field;
// 获取实际的文件扩展名
let extension = '';
if (lease[field] && typeof lease[field] === 'string') {
const processedUrl = processFilePath(lease[field]);
if (processedUrl) {
const ext = path.extname(processedUrl);
if (ext) {
extension = ext;
} else {
// 如果没有扩展名,根据字段类型推测
if (field === 'cardCopy' || field === 'yingYeZhiZhao') {
extension = '.jpg'; // 身份证和营业执照通常是图片
} else {
extension = '.pdf'; // 其他文件默认PDF
}
}
}
}
// 确保文件名安全
const safeFileName = baseName.replace(/[<>:"/\\|?*]/g, '_');
return `${safeFileName}${extension}`;
}
/**
* 获取商标相关文件
*/
async function getTrademarkFiles(eId: string): Promise<{url: string, fileName: string}[]> {
const trademarkInfo = await selectData(
OPERATIONALDATATYPE.查询多个,
'trade_mark',
{ eId },
["tmId", "regNo", "name", "imageUrl"]
);
const files: {url: string, fileName: string}[] = [];
trademarkInfo.forEach(trademark => {
if (trademark.imageUrl) {
let processedUrl = processFilePath(trademark.imageUrl);
// 特殊处理商标图片URL:移除多余的 /img 后缀
// if (processedUrl && processedUrl.endsWith('/img')) {
// processedUrl = processedUrl.slice(0, -4); // 移除最后的 '/img'
// console.log(`修复商标图片URL: ${processedUrl}`);
// }
if (processedUrl) {
const extension = path.extname(processedUrl) || '.jpg';
// 清理文件名中的特殊字符
const safeName = (trademark.name || '').replace(/[<>:"/\\|?*]/g, '_');
const fileName = `商标_${trademark.regNo || trademark.tmId}_${safeName}${extension}`;
files.push({
url: processedUrl,
fileName: fileName
});
}
}
});
return files;
}
/**
* 获取作品著作权相关文件
*/
async function getCopyrightFiles(eId: string): Promise<{url: string, fileName: string}[]> {
const copyrightInfo = await selectData(
OPERATIONALDATATYPE.查询多个,
'copy_right',
{ eId },
["crId", "registerNo", "name", "iprUrl"]
);
const files: {url: string, fileName: string}[] = [];
copyrightInfo.forEach(copyright => {
if (copyright.iprUrl) {
const processedUrl = processFilePath(copyright.iprUrl);
if (processedUrl) {
const extension = path.extname(processedUrl) || '.pdf';
const fileName = `作品著作权_${copyright.registerNo || copyright.crId}_${copyright.name}${extension}`;
files.push({
url: processedUrl,
fileName: fileName
});
}
}
});
return files;
}
/**
* 获取软件著作权相关文件
*/
async function getSoftwareCopyrightFiles(eId: string): Promise<{url: string, fileName: string}[]> {
const softwareCopyrightInfo = await selectData(
OPERATIONALDATATYPE.查询多个,
'software_copyright',
{ eId },
["scId", "registerNo", "name", "iprUrl"]
);
const files: {url: string, fileName: string}[] = [];
softwareCopyrightInfo.forEach(software => {
if (software.iprUrl) {
const processedUrl = processFilePath(software.iprUrl);
if (processedUrl) {
const extension = path.extname(processedUrl) || '.pdf';
const fileName = `软件著作权_${software.registerNo || software.scId}_${software.name}${extension}`;
files.push({
url: processedUrl,
fileName: fileName
});
}
}
});
return files;
}
/**
* 获取专利相关文件
*/
async function getPatentFiles(eId: string): Promise<{url: string, fileName: string}[]> {
const patentInfo = await selectData(
OPERATIONALDATATYPE.查询多个,
'patent',
{ eId },
["patentId", "applicationNumber", "title", "iprUrl"]
);
const files: {url: string, fileName: string}[] = [];
patentInfo.forEach(patent => {
if (patent.iprUrl) {
const processedUrl = processFilePath(patent.iprUrl);
if (processedUrl) {
const extension = path.extname(processedUrl) || '.pdf';
const fileName = `专利_${patent.applicationNumber || patent.patentId}_${patent.title}${extension}`;
files.push({
url: processedUrl,
fileName: fileName
});
}
}
});
return files;
}
/**
* 简单的图片文件头验证
*/
function isValidImageHeader(header: string): boolean {
const validHeaders = [
'ffd8ffe0', // JPEG
'ffd8ffe1', // JPEG
'ffd8ffe2', // JPEG
'89504e47', // PNG
'47494638', // GIF
'424d' // BMP (前2字节)
];
return validHeaders.some(valid => header.startsWith(valid));
}
/**
* 创建ZIP压缩包
*/
async function createZipArchive(sourceDir: string, outPath: string): Promise<void> {
return new Promise((resolve, reject) => {
const output = fs.createWriteStream(outPath);
const archive = archiver('zip', {
zlib: { level: 9 } // 最高压缩级别
});
output.on('close', () => {
console.log(`ZIP文件创建完成: ${outPath}, 大小: ${archive.pointer()} bytes`);
resolve();
});
archive.on('error', (err) => {
reject(err);
});
archive.pipe(output);
archive.directory(sourceDir, false);
archive.finalize();
});
}
//数据同步
import moment = require("moment");
import { OPERATIONALDATATYPE, TABLENAME } from "../config/enum/dbEnum";
import { selectData, selectManyTableData } from "../data/operationalData";
export async function integration() {
let selectParam:any = {startTime:{"%between%":["2025-07-01", "2025-09-30"]}};
let enterpriseFilesList = ["eId", "enterpriseName", "uscc", "industry", "logonTime", "logonAddress","operatingAddress", "mainBusiness"];
let leaseFileList = ["area", "rent", "building", "roomNumber", "startTime", "endTime" ];
let fuhuaFileList = [ "startTime", "endTime"];
let manyTableInfo:any = {};
manyTableInfo[TABLENAME.企业孵化信息] = {column:fuhuaFileList, where:selectParam };
manyTableInfo[TABLENAME.租赁信息] = {column:leaseFileList, where:{} };
let dbList = await selectManyTableData(OPERATIONALDATATYPE.多表联查, TABLENAME.企业基础信息表, {}, enterpriseFilesList, manyTableInfo);
let dataList = [];
let distinctMap = {};
dbList.forEach(info => {
let { enterprise_fuhuas, enterprise_leases } = info;
let enterprise_fuhua = enterprise_fuhuas[0];
let enterprise_lease = enterprise_leases[0];
let leaseAddress = "";
if (enterprise_lease.building ) leaseAddress += `${enterprise_lease.building}号楼`;
if (enterprise_lease.roomNumber) leaseAddress += `${enterprise_lease.roomNumber}室`;
if (!leaseAddress) leaseAddress = JSON.parse(info.logonAddress)[JSON.parse(info.logonAddress).length - 1]
let newindustry = [];
JSON.parse(info.industry).forEach(key => {
switch(key) {
case 1: newindustry.push(6);break;
case 2: newindustry.push(3);break;
case 3: newindustry.push(8);break;
case 4: newindustry.push(8);break;
case 5: newindustry.push(8);break;
case 6: newindustry.push(8);break;
}
})
let addInfo = {
name:info.enterpriseName,
uscc:info.uscc,
industry:newindustry,
logonTime:new Date(info.logonTime).valueOf(),
// logonTime:info.logonTime,
firstIncubationTime:new Date(enterprise_fuhua.startTime).valueOf(),
isNaturalPersonHolding:true,
logonAddress:JSON.parse(info.logonAddress),
operatingAddress:info.operatingAddress ? JSON.parse(info.operatingAddress) : JSON.parse(info.logonAddress),
leasedArea:enterprise_lease.area ? parseFloat(enterprise_lease.area) : 0,
mainBusiness:info.mainBusiness || "",
jiaSu:2,
leaseAddress,
price:parseFloat(enterprise_lease.rent),
contractStartTime:new Date(enterprise_fuhua.startTime).valueOf(),
contractEndTime:new Date(enterprise_fuhua.endTime).valueOf(),
payStartTime:new Date(enterprise_fuhua.startTime).valueOf(),
payLong:moment(enterprise_fuhua.endTime).diff(moment(enterprise_fuhua.startTime), 'months'),
areaUnit:1
};
dataList.push(addInfo);
if (!distinctMap[info.uscc]) distinctMap[info.uscc] = addInfo;
});
let outList = Object.values(distinctMap);
console.log();
}
...@@ -7,14 +7,117 @@ import moment = require("moment"); ...@@ -7,14 +7,117 @@ import moment = require("moment");
import { getQcc } from "../util/request"; import { getQcc } from "../util/request";
import { OPERATIONALDATATYPE, TABLEID, TABLENAME } from "../config/enum/dbEnum"; import { OPERATIONALDATATYPE, TABLEID, TABLENAME } from "../config/enum/dbEnum";
import { operationalData, selectData } from "../data/operationalData"; import { operationalData, selectData } from "../data/operationalData";
import { getMySqlMs, getPinyinInitials, randomId } from "../tools/system"; import { getMySqlMs, getPinyinInitials, getPwdMd5, randomId } from "../tools/system";
import { FINANCINGROUNDS, IPRALLTYPE } from "../config/enum/enum"; import { FINANCINGROUNDS } from "../config/enum/enum";
import { table } from "console";
import { changeEnumValue } from "../util/verificationEnum";
const xlsx = require('node-xlsx'); const xlsx = require('node-xlsx');
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
/**
* 迁移所有企业用户的密码为加密格式
*/
export async function migrateEnterpriseUserPasswords() {
try {
// 获取所有企业用户
const enterpriseUsers = await selectData(
OPERATIONALDATATYPE.查询多个,
TABLENAME.企业用户表,
{},
["uId", "uscc", "pwd", "userName"]
);
if (!enterpriseUsers || enterpriseUsers.length === 0) {
console.log("没有找到需要迁移的企业用户");
return { success: true, migrated: 0 };
}
let migratedCount = 0;
// 遍历所有用户并更新密码
for (const user of enterpriseUsers) {
// 跳过已经加密的密码(假设加密后的密码长度为32位)
if (user.pwd && user.pwd.length === 32) {
console.log(`用户 ${user.uscc} 的密码已经加密,跳过`);
continue;
}
// 使用uId作为盐值进行加密
const encryptedPwd = getPwdMd5(user.uId, user.pwd);
// 更新数据库中的密码
await operationalData(
OPERATIONALDATATYPE.修改,
TABLENAME.企业用户表,
{ pwd: encryptedPwd },
{ uId: user.uId }
);
migratedCount++;
console.log(`已迁移用户 ${user.userName} 的密码`);
}
console.log(`企业用户密码迁移完成,共迁移了 ${migratedCount} 个用户`);
return { success: true, migrated: migratedCount };
} catch (error) {
console.error("企业用户密码迁移过程中发生错误:", error);
return { success: false, error: error.message };
}
}
/**
* 迁移所有企业用户的密码为加密格式
*/
export async function migrateAdminPasswords() {
try {
// 获取所有企业用户
const enterpriseUsers = await selectData(
OPERATIONALDATATYPE.查询多个,
TABLENAME.管理后台用户,
{},
["aId", "loginId", "pwd", "name"]
);
if (!enterpriseUsers || enterpriseUsers.length === 0) {
console.log("没有找到需要迁移的企业用户");
return { success: true, migrated: 0 };
}
let migratedCount = 0;
// 遍历所有用户并更新密码
for (const user of enterpriseUsers) {
// 跳过已经加密的密码(假设加密后的密码长度为32位)
if (user.pwd && user.pwd.length === 32) {
console.log(`用户 ${user.loginId} 的密码已经加密,跳过`);
continue;
}
// 使用aId作为盐值进行加密
const encryptedPwd = getPwdMd5(user.aId, user.pwd);
// 更新数据库中的密码
await operationalData(
OPERATIONALDATATYPE.修改,
TABLENAME.管理后台用户,
{ pwd: encryptedPwd },
{ aId: user.aId }
);
migratedCount++;
console.log(`已迁移用户 ${user.name} 的密码`);
}
console.log(`企业用户密码迁移完成,共迁移了 ${migratedCount} 个用户`);
return { success: true, migrated: migratedCount };
} catch (error) {
console.error("企业用户密码迁移过程中发生错误:", error);
return { success: false, error: error.message };
}
}
/** /**
* 获取当个excel文件数据 * 获取当个excel文件数据
* @param filePath * @param filePath
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
import moment = require("moment"); import moment = require("moment");
import { OPERATIONALDATATYPE, TABLENAME } from "../config/enum/dbEnum"; import { OPERATIONALDATATYPE, TABLENAME } from "../config/enum/dbEnum";
import { BUILDING, CHANGESTATE, EMIGRATIONTYPE, FUHUASTATE, INDUSTRY, OFFLINEPROMOTION, ONLINEPROMOTION, PROMOTIONTYPE } from "../config/enum/enum"; import { BUILDING, CHANGESTATE, EMIGRATIONTYPE, FUHUASTATE, INDUSTRY, OFFLINEPROMOTION, ONLINEPROMOTION, PROMOTIONTYPE, STATE } from "../config/enum/enum";
import { operationalData, selectData, selectManyTableData } from "../data/operationalData"; import { operationalData, selectData, selectManyTableData } from "../data/operationalData";
import { getIntervalYear, getMySqlMs, randomId } from "../tools/system"; import { getIntervalYear, getMySqlMs, randomId } from "../tools/system";
import { changeEnumValue } from "../util/verificationEnum"; import { changeEnumValue } from "../util/verificationEnum";
...@@ -60,16 +60,19 @@ export async function getBaseData() { ...@@ -60,16 +60,19 @@ export async function getBaseData() {
// }) // })
// }) // })
// 累加在孵面积(考虑租赁时间) // 累加在孵面积(考虑租赁时间)
zaifuResList.forEach(info => { // zaifuResList.forEach(info => {
info.enterprise_leases.forEach(lease => { // info.enterprise_leases.forEach(lease => {
// 确认租赁时间在有效范围内 // // 确认租赁时间在有效范围内
baseData.fuhuaData["在孵面积"] += parseFloat(lease.area); // baseData.fuhuaData["在孵面积"] += parseFloat(lease.area);
// if (nowTime >= lease.startTime && nowTime <= lease.endTime) { // // if (nowTime >= lease.startTime && nowTime <= lease.endTime) {
// baseData.fuhuaData["在孵面积"] += parseFloat(lease.area); // // baseData.fuhuaData["在孵面积"] += parseFloat(lease.area);
// } // // }
}); // });
}); // });
// baseData.fuhuaData["在孵面积占比"] = ((baseData.fuhuaData["在孵面积(㎡)"] / baseData.fuhuaData["总面积(㎡)"])*100).toFixed(2) + "%"; // baseData.fuhuaData["在孵面积占比"] = ((baseData.fuhuaData["在孵面积(㎡)"] / baseData.fuhuaData["总面积(㎡)"])*100).toFixed(2) + "%";
/**在孵企业面积 */
let {孵化器总面积, 在孵企业面积, 在孵企业面积占比, 各楼栋在孵企业面积} = await get在孵企业面积();
baseData.fuhuaData["在孵面积"] = 在孵企业面积;
/**迁出企业 */ /**迁出企业 */
let qianchuList = await selectData(OPERATIONALDATATYPE.查询多个, TABLENAME.企业孵化信息, {state:FUHUASTATE.迁出}, {}); let qianchuList = await selectData(OPERATIONALDATATYPE.查询多个, TABLENAME.企业孵化信息, {state:FUHUASTATE.迁出}, {});
...@@ -119,18 +122,49 @@ export async function getBaseData() { ...@@ -119,18 +122,49 @@ export async function getBaseData() {
*/ */
let entryList = await selectData(OPERATIONALDATATYPE.查询多个, TABLENAME.入驻信息表, {}, [`info_enterId`, `building`, `occupancyRate`, `enteredEnterprises`]); let entryList = await selectData(OPERATIONALDATATYPE.查询多个, TABLENAME.入驻信息表, {}, [`info_enterId`, `building`, `occupancyRate`, `enteredEnterprises`]);
let 入驻企业 = await get入驻企业列表(); let 入驻企业 = await get入驻企业列表();
let 备案孵化面积 = {
"1":4800,
"3":6200,
"4":13200
}
let 入孵率占比 = {
"1":"",
"3":"",
"4":""
}
//这栋楼的在孵企业总面积 / 这栋楼的备案面积
let 入孵率1 = (各楼栋在孵企业面积["1"] / 备案孵化面积["1"]) * 100;
let 入孵率3 = (各楼栋在孵企业面积["3"] / 备案孵化面积["3"]) * 100;
let 入孵率4 = (各楼栋在孵企业面积["4"] / 备案孵化面积["4"]) * 100;
入孵率占比["1"] = 入孵率1.toFixed(2) + "%";
入孵率占比["3"] = 入孵率3.toFixed(2) + "%";
入孵率占比["4"] = 入孵率4.toFixed(2) + "%";
if (入孵率1 > 100) 入孵率占比["1"] = "100%";
if (入孵率3 > 100) 入孵率占比["3"] = "100%";
if (入孵率4 > 100) 入孵率占比["4"] = "100%";
let entryInfo = { let entryInfo = {
"1":{"入驻率":"", "入驻企业":入驻企业[BUILDING["1号楼"]].length}, "1":{"入孵率":入孵率占比["1"], "入驻企业":入驻企业[BUILDING["1号楼"]].length},
"3":{"入驻率":"", "入驻企业":入驻企业[BUILDING["3号楼"]].length}, "3":{"入孵率":入孵率占比["3"], "入驻企业":入驻企业[BUILDING["3号楼"]].length},
"4":{"入驻率":"", "入驻企业":入驻企业[BUILDING["4号楼"]].length}}; "4":{"入孵率":入孵率占比["4"], "入驻企业":入驻企业[BUILDING["4号楼"]].length}
};
for (let key in entryInfo) {
let 入驻信息updateInfo = {occupancyRate:entryInfo[key].入孵率, enteredEnterprises:entryInfo[key].入驻企业};
let updateParam = {building:key}
await operationalData(OPERATIONALDATATYPE.修改, TABLENAME.入驻信息表, 入驻信息updateInfo, updateParam);
}
if (entryList.length) { if (entryList.length) {
entryList.forEach( info => { entryList.forEach( info => {
// let = changeEnumValue(BUILDING, info.building); // let = changeEnumValue(BUILDING, info.building);
let building = info.building; let building = info.building;
if (!entryInfo[building]) { if (!entryInfo[building]) {
entryInfo[building] = { "入率": "", "入驻企业": "" }; entryInfo[building] = { "入率": "", "入驻企业": "" };
} }
entryInfo[building].入驻 = info.occupancyRate; // entryInfo[building].入孵率 = info.occupancyRate;
entryInfo[building].入驻企业 = 入驻企业[building].length; entryInfo[building].入驻企业 = 入驻企业[building].length;
}) })
} }
...@@ -367,16 +401,14 @@ export async function getRiskData() { ...@@ -367,16 +401,14 @@ export async function getRiskData() {
中低风险: 0, 中低风险: 0,
关注: 0 关注: 0
} }
let riskEnterprises: any[] = []; let riskEnterprises:any[] = [];
let fhColumn = ["enterpriseName", "industry", "eId", "shijiaoziben"]; let fhColumn = ["enterpriseName", "industry", "eId", "shijiaoziben"];
//获取所有企业孵化信息 //获取所有企业孵化信息
let manyTableInfo: any = {} let manyTableInfo:any = {};
// manyTableInfo[TABLENAME.企业孵化信息] = { column: ["fId", "eId", "startTime", "endTime", "state"], where: { state: FUHUASTATE.实体孵化 } }; manyTableInfo[TABLENAME.企业孵化信息] = { column: ["fId", "eId", "moveOutTime", "moveOutType", "state"], where: {} };
manyTableInfo[TABLENAME.企业孵化信息] = { column: ["fId", "eId", "moveOutTime", "moveOutType"], where: {} };
// manyTableInfo[TABLENAME.企业经营信息] = { column: ["annual"], where: {} };
let fhdbList = await selectManyTableData(OPERATIONALDATATYPE.多表联查, TABLENAME.企业基础信息表, {state: CHANGESTATE.已通过}, fhColumn, manyTableInfo); let fhdbList = await selectManyTableData(OPERATIONALDATATYPE.多表联查, TABLENAME.企业基础信息表, {state: CHANGESTATE.已通过}, fhColumn, manyTableInfo);
let manageList = await selectData(OPERATIONALDATATYPE.查询多个, TABLENAME.企业经营信息, {}, ["annual", "eId"]); let manageList = await selectData(OPERATIONALDATATYPE.查询多个, TABLENAME.企业经营信息, {isSubmit:STATE.}, ["annual", "eId"]);
let map = {}; let map = {};
manageList.forEach(info => { manageList.forEach(info => {
...@@ -389,17 +421,17 @@ export async function getRiskData() { ...@@ -389,17 +421,17 @@ export async function getRiskData() {
yj.高风险 += 1; yj.高风险 += 1;
riskLevel = "高风险"; riskLevel = "高风险";
riskEnterprises.push([info.enterpriseName, riskLevel]); riskEnterprises.push([info.enterpriseName, riskLevel]);
} else if (!map[info.eId]) {
yj.中低风险 += 1;
riskLevel = "中低风险";
riskEnterprises.push([info.enterpriseName, riskLevel]);
} else if (info.enterprise_fuhuas[0].moveOutType == EMIGRATIONTYPE.到期退租) { } else if (info.enterprise_fuhuas[0].moveOutType == EMIGRATIONTYPE.到期退租) {
yj.关注 += 1; yj.关注 += 1;
riskLevel = "关注"; riskLevel = "关注";
riskEnterprises.push([info.enterpriseName, riskLevel]); riskEnterprises.push([info.enterpriseName, riskLevel]);
} } else if (info.enterprise_fuhuas[0].state != FUHUASTATE.迁出 && !map[info.eId]) {
yj.中低风险 += 1;
riskLevel = "中低风险";
riskEnterprises.push([info.enterpriseName, riskLevel]);
}
}); });
let yujiData = []; let yujiData = [];
for (let key in yj) { for (let key in yj) {
yujiData.push({key, value:yj[key]}); yujiData.push({key, value:yj[key]});
...@@ -411,6 +443,58 @@ export async function getRiskData() { ...@@ -411,6 +443,58 @@ export async function getRiskData() {
}; };
} }
// export async function getRiskData() {
// let yj = {
// 高风险: 0,
// 中低风险: 0,
// 关注: 0
// }
// let riskEnterprises: any[] = [];
// let fhColumn = ["enterpriseName", "industry", "eId", "shijiaoziben"];
// //获取所有企业孵化信息
// let manyTableInfo: any = {}
// // manyTableInfo[TABLENAME.企业孵化信息] = { column: ["fId", "eId", "startTime", "endTime", "state"], where: { state: FUHUASTATE.实体孵化 } };
// manyTableInfo[TABLENAME.企业孵化信息] = { column: ["fId", "eId", "moveOutTime", "moveOutType"], where: {} };
// // manyTableInfo[TABLENAME.企业经营信息] = { column: ["annual"], where: {} };
// let fhdbList = await selectManyTableData(OPERATIONALDATATYPE.多表联查, TABLENAME.企业基础信息表, {state: CHANGESTATE.已通过}, fhColumn, manyTableInfo);
// let manageList = await selectData(OPERATIONALDATATYPE.查询多个, TABLENAME.企业经营信息, {}, ["annual", "eId"]);
// let map = {};
// manageList.forEach(info => {
// map[info.eId] = 1;
// });
// fhdbList.forEach(info => {
// let riskLevel = "";
// if (info.enterprise_fuhuas[0].moveOutType == EMIGRATIONTYPE.违约退租) {
// yj.高风险 += 1;
// riskLevel = "高风险";
// riskEnterprises.push([info.enterpriseName, riskLevel]);
// } else if (!map[info.eId]) {
// yj.中低风险 += 1;
// riskLevel = "中低风险";
// riskEnterprises.push([info.enterpriseName, riskLevel]);
// } else if (info.enterprise_fuhuas[0].moveOutType == EMIGRATIONTYPE.到期退租) {
// yj.关注 += 1;
// riskLevel = "关注";
// riskEnterprises.push([info.enterpriseName, riskLevel]);
// }
// });
// let yujiData = [];
// for (let key in yj) {
// yujiData.push({key, value:yj[key]});
// }
// return {
// yujiData,
// riskEnterprises
// };
// }
/** /**
* 价值分析 * 价值分析
*/ */
...@@ -527,18 +611,18 @@ export async function getYuYiFuHua() { ...@@ -527,18 +611,18 @@ export async function getYuYiFuHua() {
let entryList = await selectData(OPERATIONALDATATYPE.查询多个, TABLENAME.入驻信息表, {}, [`info_enterId`, `building`, `occupancyRate`, `enteredEnterprises`]); let entryList = await selectData(OPERATIONALDATATYPE.查询多个, TABLENAME.入驻信息表, {}, [`info_enterId`, `building`, `occupancyRate`, `enteredEnterprises`]);
let 入驻企业 = await get入驻企业列表(); let 入驻企业 = await get入驻企业列表();
let entryInfo = { let entryInfo = {
"1":{"入率":"", "入驻企业":入驻企业[BUILDING["1号楼"]].length}, "1":{"入率":"", "入驻企业":入驻企业[BUILDING["1号楼"]].length},
"3":{"入率":"", "入驻企业":入驻企业[BUILDING["3号楼"]].length}, "3":{"入率":"", "入驻企业":入驻企业[BUILDING["3号楼"]].length},
"4":{"入率":"", "入驻企业":入驻企业[BUILDING["4号楼"]].length}}; "4":{"入率":"", "入驻企业":入驻企业[BUILDING["4号楼"]].length}};
if (entryList.length) { if (entryList.length) {
entryList.forEach(info => { entryList.forEach(info => {
// let building = changeEnumValue(BUILDING, info.building); // let building = changeEnumValue(BUILDING, info.building);
let building = info.building; let building = info.building;
if (!entryInfo[building]) { if (!entryInfo[building]) {
entryInfo[building] = { "入率": "", "入驻企业": "" }; entryInfo[building] = { "入率": "", "入驻企业": "" };
} }
entryInfo[building]. = info.occupancyRate; entryInfo[building]. = info.occupancyRate;
entryInfo[building].入驻企业 = 入驻企业[building].length; entryInfo[building].入驻企业 = 入驻企业[building].length;
}); });
} }
...@@ -575,7 +659,7 @@ export async function getYuYiFuHua() { ...@@ -575,7 +659,7 @@ export async function getYuYiFuHua() {
/** /**
* 雨艺孵化器基本信息修改 * 雨艺孵化器基本信息修改
* @param yId * @param yId
* @param entryInfo {"1号楼":{入率:"", 入驻企业:""}, ......} * @param entryInfo {"1号楼":{入率:"", 入驻企业:""}, ......}
* @param promotionInfo {"线上推广":{"活动宣讲":0, "三方机构合作":0}, "线下推广":{"活动宣讲":0, "三方机构合作":0}} * @param promotionInfo {"线上推广":{"活动宣讲":0, "三方机构合作":0}, "线下推广":{"活动宣讲":0, "三方机构合作":0}}
*/ */
export async function updateYuYi(yId, param) { export async function updateYuYi(yId, param) {
...@@ -599,7 +683,7 @@ export async function updateYuYi(yId, param) { ...@@ -599,7 +683,7 @@ export async function updateYuYi(yId, param) {
let entryInfo = param.entryInfo; let entryInfo = param.entryInfo;
for (let key in entryInfo) { for (let key in entryInfo) {
let 入驻信息updateInfo = {occupancyRate:entryInfo[key]., enteredEnterprises:entryInfo[key].入驻企业}; let 入驻信息updateInfo = {occupancyRate:entryInfo[key]., enteredEnterprises:entryInfo[key].入驻企业};
let updateParam = {building:key} let updateParam = {building:key}
await operationalData(OPERATIONALDATATYPE.修改, TABLENAME.入驻信息表, 入驻信息updateInfo, updateParam); await operationalData(OPERATIONALDATATYPE.修改, TABLENAME.入驻信息表, 入驻信息updateInfo, updateParam);
} }
...@@ -636,6 +720,58 @@ export async function updateYuYi(yId, param) { ...@@ -636,6 +720,58 @@ export async function updateYuYi(yId, param) {
export async function get在孵企业面积() {
// 获取当前时间
// let nowTime = new Date( moment().format("YYYY-01-01") ).valueOf();
let nowTime = new Date().valueOf();
let zlColumn = ["eId", "area", "unitPrice", "isDeposit", "startTime", "endTime", "rentFreeStart", "rentFreeEnd", "roomNumber",
"rent", "notes", "building",
"sanFangXieYi", "fuHuaXieYi", "fangWuZuLing", "fuHuaXieYiBuChong", "chengXinChengNuoHan", "yingYeZhiZhao", "ruFuZiLiao", "ruZhuJiHua", "yaJinZhiFu", "cardCopy"];
// "rent", "notes", "leaseContract", "entryPlan", "businessLicense", "agreement"];
// let manyTableInfo: any = {}
// manyTableInfo[TABLENAME.企业孵化信息] = { column: ["fId", "eId", "startTime", "endTime", "state"], where: {state: { "%between%": [FUHUASTATE.实体孵化, FUHUASTATE.虚拟孵化] }} };
// manyTableInfo[TABLENAME.租赁信息] = { column: zlColumn, where: {"startTime": {"%lt%": nowTime}, "endTime": { "%gt%": nowTime }} }; //租赁开始时间小于当前时间、租赁结束时间大于当前时间
// let zldbList = await selectManyTableData(OPERATIONALDATATYPE.多表联查, TABLENAME.企业基础信息表, {}, ["industry", "eId"], manyTableInfo);
/**2025.06.05 罗总开会确认去掉租赁时间,在孵面积计算只用判断是否在孵企业 */
let manyTableInfo: any = {}
manyTableInfo[TABLENAME.企业孵化信息] = { column: ["fId", "eId", "startTime", "endTime", "state"], where: {state: { "%between%": [FUHUASTATE.实体孵化, FUHUASTATE.虚拟孵化] }} };
manyTableInfo[TABLENAME.租赁信息] = { column: zlColumn, where: {} }; //租赁开始时间小于当前时间、租赁结束时间大于当前时间
let zldbList = await selectManyTableData(OPERATIONALDATATYPE.多表联查, TABLENAME.企业基础信息表, {state: CHANGESTATE.已通过}, ["industry", "eId"], manyTableInfo);
let 在孵企业面积 = 0;
let 各楼栋在孵企业面积 = {
"1":0,
"3":0,
"4":0
}
zldbList.forEach( info => {
let {enterprise_fuhuas, enterprise_leases} = info;
// if (nowTime <= new Date(enterprise_fuhuas[0].endTime).valueOf()) {
// enterprise_leases.forEach( leases => {
// if (leases.area) 在孵企业面积 += parseFloat(leases.area);
// })
// }
enterprise_leases.forEach( leases => {
if (leases.building) {
if (leases.area) 各楼栋在孵企业面积[leases.building] += parseFloat(leases.area);
}
if (leases.area) 在孵企业面积 += parseFloat(leases.area);
})
});
let 雨艺孵化器dbList = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.羽翼孵化器信息, {}, []);
let 孵化器总面积 = parseFloat(雨艺孵化器dbList.totalArea);
let zfqymjzb = ((在孵企业面积 / 孵化器总面积) * 100);
let 在孵企业面积占比 = "0%";
if (zfqymjzb >= 100) 在孵企业面积占比 = "100%";
else 在孵企业面积占比 = zfqymjzb.toFixed(2) + "%";
return {孵化器总面积, 在孵企业面积, 在孵企业面积占比, 各楼栋在孵企业面积};
}
...@@ -46,7 +46,8 @@ import { systemSendMail } from "./mail"; ...@@ -46,7 +46,8 @@ import { systemSendMail } from "./mail";
logonAddress:JSON.stringify(["", "", "", param.logonAddress]), logonAddress:JSON.stringify(["", "", "", param.logonAddress]),
mail:param.mail,//邮箱地址 mail:param.mail,//邮箱地址
state:enumConfig.CHANGESTATE.未审核, state:enumConfig.CHANGESTATE.未审核,
register:enumConfig.CHANGESTATE.未审核 register:enumConfig.CHANGESTATE.未审核,
// createTime:getMySqlMs(),
}; };
await operationalData(OPERATIONALDATATYPE.增加, TABLENAME.企业基础信息表, addEInfo, {}); await operationalData(OPERATIONALDATATYPE.增加, TABLENAME.企业基础信息表, addEInfo, {});
...@@ -346,6 +347,29 @@ export async function settleInEnterpriseOut(eId:string, descType, desc:string) { ...@@ -346,6 +347,29 @@ export async function settleInEnterpriseOut(eId:string, descType, desc:string) {
mailStr += `<p>我们期待未来与贵公司的合作机会,衷心祝愿贵公司业务发展顺利!</p>`; mailStr += `<p>我们期待未来与贵公司的合作机会,衷心祝愿贵公司业务发展顺利!</p>`;
await systemSendMail(resInfo.eId, enumConfig.MAILTYPE.驳回入孵申请, mailStr ); await systemSendMail(resInfo.eId, enumConfig.MAILTYPE.驳回入孵申请, mailStr );
/**设置7天后再次提醒 */
setTimeout( async() => {
try {
//检查企业状态是否仍然是已驳回(未重新提交)
let currentInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.企业基础信息表, {eId}, ["register"]);
if (currentInfo && currentInfo.register === enumConfig.CHANGESTATE.已驳回) {
let reminderMailStr = "";
reminderMailStr += "<p>【雨艺孵化器】入孵申请提醒</p>";
reminderMailStr += "<p>尊敬的客户:</p>";
reminderMailStr += "<p>我们注意到您在7天前提交的入孵申请未通过初审,目前尚未收到您的重新提交。</p>";
reminderMailStr += `<p>驳回原因:${descStr}</p>`;
reminderMailStr += "<p>如果您仍有入驻意向,请根据审核意见完善资料后重新提交申请。</p>";
reminderMailStr += "<p>如有任何疑问,欢迎随时联系我们。</p>";
reminderMailStr += "<p>期待您的回复!</p>";
await systemSendMail(resInfo.eId, enumConfig.MAILTYPE.驳回入孵申请, reminderMailStr);
console.log(`7天后入孵申请驳回提醒邮件已发送给企业 ${resInfo.eId}`);
}
} catch (error) {
console.error(`发送7天后入孵申请驳回提醒邮件失败:`, error);
}
}, 7 * 24 * 60 * 60 * 1000); // 7天后的毫秒数
return {isSuccess:true}; return {isSuccess:true};
} }
...@@ -626,7 +650,7 @@ export async function enterpriseRegisterExamineOut(eId:string, descType, desc:st ...@@ -626,7 +650,7 @@ export async function enterpriseRegisterExamineOut(eId:string, descType, desc:st
} }
await operationalData( OPERATIONALDATATYPE.增加, TABLENAME.入孵申请审批表, addInfo, {} ); await operationalData( OPERATIONALDATATYPE.增加, TABLENAME.入孵申请审批表, addInfo, {} );
/**发送邮件 */ /**发送邮件 - 首次驳回通知 */
let mailStr = ""; let mailStr = "";
mailStr += "<p>感谢贵公司积极配合入孵流程。经审核,贵公司提交的入孵材料<span style='font-weight: 700;'>暂未通过审核</span>,主要原因如下:</p>"; mailStr += "<p>感谢贵公司积极配合入孵流程。经审核,贵公司提交的入孵材料<span style='font-weight: 700;'>暂未通过审核</span>,主要原因如下:</p>";
mailStr += `<ul>`; mailStr += `<ul>`;
...@@ -637,6 +661,29 @@ export async function enterpriseRegisterExamineOut(eId:string, descType, desc:st ...@@ -637,6 +661,29 @@ export async function enterpriseRegisterExamineOut(eId:string, descType, desc:st
mailStr += `<p>感谢理解与配合!</p>`; mailStr += `<p>感谢理解与配合!</p>`;
await systemSendMail(resInfo.eId, enumConfig.MAILTYPE.驳回入孵材料申请, mailStr ); await systemSendMail(resInfo.eId, enumConfig.MAILTYPE.驳回入孵材料申请, mailStr );
/**设置7天后再次提醒 */
setTimeout(async () => {
try {
// 检查企业状态是否仍然是已驳回(未重新提交材料)
let currentInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.企业基础信息表, {eId}, ["state"]);
if (currentInfo && currentInfo.state === enumConfig.CHANGESTATE.已驳回) {
let reminderMailStr = "";
reminderMailStr += "<p>【雨艺孵化器】入孵材料审核提醒</p>";
reminderMailStr += "<p>尊敬的客户:</p>";
reminderMailStr += "<p>我们注意到您在7天前提交的入孵材料未通过审核,目前尚未收到您重新提交的完善材料。</p>";
reminderMailStr += `<p>驳回原因:${descStr}</p>`;
reminderMailStr += "<p>请您根据审核意见尽快完善相关材料并重新提交,以便我们继续为您处理入孵申请。</p>";
reminderMailStr += "<p>如有任何疑问,欢迎随时联系我们。</p>";
reminderMailStr += "<p>期待您的完善材料!</p>";
await systemSendMail(resInfo.eId, enumConfig.MAILTYPE.驳回入孵材料申请, reminderMailStr);
console.log(`7天后入孵材料驳回提醒邮件已发送给企业 ${resInfo.eId}`);
}
} catch (error) {
console.error(`发送7天后入孵材料驳回提醒邮件失败:`, error);
}
}, 7 * 24 * 60 * 60 * 1000); // 7天后的毫秒数
return {isSuccess:true}; return {isSuccess:true};
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import { OPERATIONALDATATYPE, TABLENAME } from "../config/enum/dbEnum"; import { OPERATIONALDATATYPE, TABLENAME } from "../config/enum/dbEnum";
import { ERRORENUM } from "../config/enum/errorEnum"; import { ERRORENUM } from "../config/enum/errorEnum";
import { operationalData, selectData } from "../data/operationalData"; import { operationalData, selectData } from "../data/operationalData";
import { getMySqlMs, getToken, md5PwdStr } from "../tools/system"; import { getMySqlMs, getPwdMd5, getToken, md5PwdStr } from "../tools/system";
import { BizError } from "../util/bizError"; import { BizError } from "../util/bizError";
...@@ -16,10 +16,12 @@ export async function adminLogin(loginId:string, pwd:string) { ...@@ -16,10 +16,12 @@ export async function adminLogin(loginId:string, pwd:string) {
let filesList = ["name", "aId", "pwd"]; let filesList = ["name", "aId", "pwd"];
let adminUserInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.管理后台用户, {loginId}, filesList); let adminUserInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.管理后台用户, {loginId}, filesList);
console.log(adminUserInfo.pwd);
if (!adminUserInfo || !adminUserInfo.aId) { if (!adminUserInfo || !adminUserInfo.aId) {
throw new BizError(ERRORENUM.账号或密码错误); throw new BizError(ERRORENUM.账号或密码错误);
} }
if (adminUserInfo.pwd != pwd) { const encryptedPwd = getPwdMd5(adminUserInfo.aId, pwd);
if (adminUserInfo.pwd != encryptedPwd) {
throw new BizError(ERRORENUM.账号或密码错误); throw new BizError(ERRORENUM.账号或密码错误);
} }
...@@ -78,3 +80,29 @@ export async function enterpriseLogout(eId:string) { ...@@ -78,3 +80,29 @@ export async function enterpriseLogout(eId:string) {
return {isSuccess:true}; return {isSuccess:true};
} }
/**
* 修改密码
* @param uId
* @param pwd 原密码
* @param newPwd 新密码
* @param confirmPwd 再次确认密码
* @returns
*/
export async function changePassword(uId:string, pwd:string, newPwd:string, confirmPwd:string) {
let adminUserInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.管理后台用户, { aId:uId }, ["loginId", "aId", "pwd"]);
if (!adminUserInfo.aId) throw new BizError(ERRORENUM.数据不存在);
/**验证当前密码 */
if (pwd != adminUserInfo.pwd) throw new BizError(ERRORENUM.原密码错误);
if (newPwd != confirmPwd) throw new BizError(ERRORENUM.密码不一致);
if (newPwd.search(/^[A-Za-z0-9]{6,18}$/) < 0) throw new BizError(ERRORENUM.密码只能由618位字符和数字组成);
await operationalData(OPERATIONALDATATYPE.修改, TABLENAME.管理后台用户, {pwd:newPwd}, { aId:uId });
return {isSuccess:true};
}
...@@ -880,18 +880,18 @@ export async function dwFinancingSituatione(eId: string) { ...@@ -880,18 +880,18 @@ export async function dwFinancingSituatione(eId: string) {
resInfo.forEach(info => { resInfo.forEach(info => {
let {enterpriseName, uscc, enterprise_financings} = info; let {enterpriseName, uscc, enterprise_financings} = info;
let subList = []; enterprise_financings.forEach(finnancing => {
valueList.forEach(subInfo => { let subList = [];
if (subInfo == "enterpriseName") subList.push(enterpriseName);//企业名称 valueList.forEach(subInfo => {
if (subInfo == "uscc") subList.push(uscc); //统一信用代码 if (subInfo == "enterpriseName") subList.push(enterpriseName);//企业名称
if (subInfo == "financingAmount") subList.push(enterprise_financings[0].financingAmount);//融资金额 if (subInfo == "uscc") subList.push(uscc); //统一信用代码
if (subInfo == "financingRounds") subList.push(changeEnumValue(enumConfig.FINANCINGROUNDS, enterprise_financings[0].financingRounds));//融资轮次 if (subInfo == "financingAmount") subList.push(finnancing.financingAmount);//融资金额
if (subInfo == "investmentDate") subList.push(moment(enterprise_financings[0].investmentDate).format("YYYY-MM-DD"));//获得投资时间 if (subInfo == "financingRounds") subList.push(changeEnumValue(enumConfig.FINANCINGROUNDS, finnancing.financingRounds));//融资轮次
if (subInfo == "investmentInstitutionsName") subList.push(enterprise_financings[0].investmentInstitutionsName);//投资机构名称 if (subInfo == "investmentDate") subList.push(moment(finnancing.investmentDate).format("YYYY-MM-DD"));//获得投资时间
}); if (subInfo == "investmentInstitutionsName") subList.push(finnancing.investmentInstitutionsName);//投资机构名称
});
dataList.push(subList);
dataList.push(subList); })
}) })
return {dataList}; return {dataList};
......
...@@ -37,7 +37,7 @@ export enum TABLENAME { ...@@ -37,7 +37,7 @@ export enum TABLENAME {
企业服务表 ='enterprise_service', 企业服务表 ='enterprise_service',
企业基础信息表 ='enterprise', 企业基础信息表 ='enterprise',
政策表 = 'policy', 政策表 = 'policy',
管理后台用户 = 'adminUser',//以下为新表 管理后台用户 = 'adminuser',//以下为新表
变更信息表 = "info_update", 变更信息表 = "info_update",
企业标签表 = "enterprise_label", 企业标签表 = "enterprise_label",
股权结构 = "ownership", 股权结构 = "ownership",
......
...@@ -81,7 +81,8 @@ export enum EMIGRATIONTYPE { ...@@ -81,7 +81,8 @@ export enum EMIGRATIONTYPE {
毕业迁出 = 1, 毕业迁出 = 1,
毕业未迁出, //新加状态 毕业未迁出, //新加状态
到期退租, 到期退租,
违约退租 违约退租,
到期未迁出
} }
...@@ -176,7 +177,8 @@ export enum FINANCINGROUNDS { ...@@ -176,7 +177,8 @@ export enum FINANCINGROUNDS {
export enum POLICYTYPE { export enum POLICYTYPE {
财政补贴 = 1, 财政补贴 = 1,
资质申报 = 2, 资质申报 = 2,
政策扶持 = 3 政策扶持 = 3,
// 政策宣讲 = 3
} }
...@@ -187,7 +189,8 @@ export enum CLIENTPOLICYTYPE { ...@@ -187,7 +189,8 @@ export enum CLIENTPOLICYTYPE {
全部 = 0, 全部 = 0,
财政补贴 = 1, 财政补贴 = 1,
资质申报 = 2, 资质申报 = 2,
政策扶持 = 3 政策扶持 = 3,
// 政策宣讲 = 3
} }
......
...@@ -41,7 +41,10 @@ export enum ERRORENUM { ...@@ -41,7 +41,10 @@ export enum ERRORENUM {
该用户邮箱为空, 该用户邮箱为空,
邮件发送失败, 邮件发送失败,
该企业暂未提交入孵材料, 该企业暂未提交入孵材料,
请选择驳回原因 请选择驳回原因,
原密码错误,
密码不一致,
系统错误
} }
export enum ERRORCODEENUM { export enum ERRORCODEENUM {
......
// 使用示例:下载多个图片并打包成ZIP
const { downloadImagesByUrls, downloadImagesWithNames, downloadImagesAndZip } = require('./imgZip');
// 示例1:根据URL数组下载图片并打包
async function example1() {
const imageUrls = [
'https://example.com/image1.jpg',
'https://example.com/image2.png',
'https://example.com/image3.gif'
];
const result = await downloadImagesByUrls(imageUrls, 'my_images');
if (result.isSuccess) {
console.log('ZIP创建成功:', result.zipPath);
} else {
console.error('错误:', result.error);
}
}
// 示例2:指定自定义文件名
async function example2() {
const imageUrls = [
'https://example.com/image1.jpg',
'https://example.com/image2.png'
];
const filenames = [
'封面图.jpg',
'详情图.png'
];
const result = await downloadImagesWithNames(imageUrls, filenames, 'custom_names');
if (result.isSuccess) {
console.log('ZIP创建成功:', result.zipPath);
} else {
console.error('错误:', result.error);
}
}
// 示例3:使用完整的图片信息对象
async function example3() {
const images = [
{ url: 'https://example.com/image1.jpg', filename: '图片1.jpg' },
{ url: 'https://example.com/image2.png' }, // 不指定文件名,会自动生成
{ url: 'https://example.com/image3.gif', filename: '特殊图片.gif' }
];
const result = await downloadImagesAndZip(images, 'mixed_images');
if (result.isSuccess) {
console.log('ZIP创建成功:', result.zipPath);
} else {
console.error('错误:', result.error);
}
}
module.exports = {
example1,
example2,
example3
};
import { integration } from "./biz/dataAsync";
import { migrateAdminPasswords, migrateEnterpriseUserPasswords } from "./biz/dataInit";
import { updateItemQCCData } from "./biz/qccInit"; import { updateItemQCCData } from "./biz/qccInit";
import { initConfig, systemConfig } from "./config/serverConfig"; import { initConfig, systemConfig } from "./config/serverConfig";
import { initApiDataStorage } from "./data/dataInterfaceWithCache"; import { initApiDataStorage } from "./data/dataInterfaceWithCache";
...@@ -9,10 +11,14 @@ async function lanuch() { ...@@ -9,10 +11,14 @@ async function lanuch() {
httpServer.createServer(systemConfig.port); httpServer.createServer(systemConfig.port);
console.log('This indicates that the server is started successfully.'); console.log('This indicates that the server is started successfully.');
await initApiDataStorage(); // await initApiDataStorage();
// await migrateEnterpriseUserPasswords();
// await migrateAdminPasswords();
// await integration();
} }
lanuch(); lanuch();
\ No newline at end of file
...@@ -14,7 +14,7 @@ export class httpServer { ...@@ -14,7 +14,7 @@ export class httpServer {
httpServer.all('*', (req, res, next) => { httpServer.all('*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', req.headers.origin); res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header("Access-Control-Allow-Headers", "X-Requested-With"); res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header('Access-Control-Allow-Headers', 'Content-Type,request-origin,userid,token'); res.header('Access-Control-Allow-Headers', 'Content-Type,request-origin,userid,token,Authorization');
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header('Access-Control-Allow-Credentials', true); res.header('Access-Control-Allow-Credentials', true);
res.header("X-Powered-By", ' 3.2.1'); res.header("X-Powered-By", ' 3.2.1');
......
...@@ -18,6 +18,7 @@ export function setRouter(httpServer) { ...@@ -18,6 +18,7 @@ export function setRouter(httpServer) {
//管理员登录登出 //管理员登录登出
httpServer.post('/admin/user/login', asyncHandler(login)); httpServer.post('/admin/user/login', asyncHandler(login));
httpServer.post('/admin/user/logout', checkUser, asyncHandler(logout)); httpServer.post('/admin/user/logout', checkUser, asyncHandler(logout));
httpServer.post('/admin/user/changepwd', checkUser, asyncHandler(changePassword));
// //新入孵企业 // //新入孵企业
httpServer.post('/admin/enterprise/settlein/list', checkUser, asyncHandler(settleIn)); httpServer.post('/admin/enterprise/settlein/list', checkUser, asyncHandler(settleIn));
...@@ -737,6 +738,20 @@ async function logout(req, res) { ...@@ -737,6 +738,20 @@ async function logout(req, res) {
/** /**
* 修改密码
* @param req
* @param res
*/
async function changePassword(req, res) {
const UserInfo = req.userInfo;
let {pwd, newPwd, confirmPwd } = req.body
let result = await userBiz.changePassword(UserInfo.uId, pwd, newPwd, confirmPwd );
res.success(result);
}
/**
* *
* @param req * @param req
* @param res * @param res
......
...@@ -6,7 +6,7 @@ import * as asyncHandler from 'express-async-handler'; ...@@ -6,7 +6,7 @@ import * as asyncHandler from 'express-async-handler';
import { checkInterior } from '../middleware/user'; import { checkInterior } from '../middleware/user';
import { getMySqlMs, getPinyinInitials, randomId } from '../tools/system'; import { getMySqlMs, getPinyinInitials, randomId } from '../tools/system';
import { OPERATIONALDATATYPE, TABLEID, TABLENAME } from '../config/enum/dbEnum'; import { OPERATIONALDATATYPE, TABLEID, TABLENAME } from '../config/enum/dbEnum';
import { ANSWERTYPE, CHANGESTATE, DEGREE, FUHUASTATE, IPRALLTYPE, STATE, ZZMM } from '../config/enum/enum'; import { ANSWERTYPE, CHANGESTATE, DEGREE, FOLLOWUPSTATUS, FUHUASTATE, IPRALLTYPE, NEEDCATEGORY, OUTCOME, STATE, ZZMM } from '../config/enum/enum';
import { operationalData, selectData } from '../data/operationalData'; import { operationalData, selectData } from '../data/operationalData';
import { initApiDataStorage } from '../data/dataInterfaceWithCache'; import { initApiDataStorage } from '../data/dataInterfaceWithCache';
import { updateQCCDataTask } from '../biz/qccInit'; import { updateQCCDataTask } from '../biz/qccInit';
...@@ -30,8 +30,108 @@ export function setRouter(httpServer) { ...@@ -30,8 +30,108 @@ export function setRouter(httpServer) {
httpServer.post('/admin/data/maintenance/datainit/loginTime', checkInterior, asyncHandler(dataUpdateLoginTime)); httpServer.post('/admin/data/maintenance/datainit/loginTime', checkInterior, asyncHandler(dataUpdateLoginTime));
httpServer.post('/admin/data/maintenance/datainit/updatetime', checkInterior, asyncHandler(updateTime)); httpServer.post('/admin/data/maintenance/datainit/updatetime', checkInterior, asyncHandler(updateTime));
httpServer.post('/admin/data/maintenance/datainit/addenterprise', checkInterior, asyncHandler(addEnterprise)); httpServer.post('/admin/data/maintenance/datainit/addenterprise', checkInterior, asyncHandler(addEnterprise));
httpServer.post('/admin/data/maintenance/datainit/addservice', checkInterior, asyncHandler(addService));
}
/**
* 导入企业服务
*/
export async function addService(req, res) {
const FIELD_MAPPING = {
/**企业服务表 */
'需求类别': 'needCategory',
'需求内容': 'needContent',
'申请时间': 'applyTime',
'跟进状态': 'followUpStatus',
'解决时间': 'resolveTime',
'反馈': 'fangKui',
'反馈时间': 'shouLiTime',
'结果': 'outcome',
'备注': 'desc'
};
//2.读取文件
let {sheetMap} = getExcel(path.join(__dirname.substring(0,__dirname.indexOf("out")), "res", '企业服务导入数据.xlsx' ));
let dataList1 = sheetMap['未受理'];
let dataList2 = sheetMap['已受理'];
let dataList3 = sheetMap['已结束'];
for (let i = 1; i < dataList1.length; i++) {
let info = dataList1[i];
let enterpriseName =info[0];
let uscc = info[1];
let enterpriseDbInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.企业基础信息表, {enterpriseName, uscc}, ["eId", "uscc", "enterpriseName"]);
if (!enterpriseDbInfo.eId) throw new BizError("未匹配到对应企业");
let excelInfo = {
esId: randomId(TABLEID.企业服务表),
eId:enterpriseDbInfo.eId,
needCategory:NEEDCATEGORY[info[2]],
needContent:info[3],
applyTime:info[4],
followUpStatus:FOLLOWUPSTATUS.未受理,
}
// 新增企业服务
await operationalData(OPERATIONALDATATYPE.增加, TABLENAME.企业服务表, excelInfo, {});
console.log(`新增未受理企业服务信息完成:${enterpriseName}`);
}
for (let i = 1; i < dataList2.length; i++) {
let info = dataList2[i];
let enterpriseName =info[0];
let uscc = info[1];
let enterpriseDbInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.企业基础信息表, {enterpriseName, uscc}, ["eId", "uscc", "enterpriseName"]);
if (!enterpriseDbInfo.eId) throw new BizError("未匹配到对应企业");
//{fangKui, followUpStatus:enumConfig.FOLLOWUPSTATUS.受理中, shouLiTime:getMySqlMs()}
let excelInfo = {
esId: randomId(TABLEID.企业服务表),
eId:enterpriseDbInfo.eId,
needCategory:NEEDCATEGORY[info[2]],
needContent:info[3],
applyTime:info[4],
fangKui:info[5],
shouLiTime:getMySqlMs(info[6]),
followUpStatus:FOLLOWUPSTATUS.受理中,
}
// 新增企业服务
await operationalData(OPERATIONALDATATYPE.增加, TABLENAME.企业服务表, excelInfo, {});
console.log(`新增受理中企业服务信息完成:${enterpriseName}`);
}
for (let i = 1; i < dataList3.length; i++) {
let info = dataList3[i];
let enterpriseName =info[0];
let uscc = info[1];
let enterpriseDbInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.企业基础信息表, {enterpriseName, uscc}, ["eId", "uscc", "enterpriseName"]);
if (!Object.keys(enterpriseDbInfo).length) throw new BizError(ERRORENUM.企业不存在);
if (!enterpriseDbInfo.eId) throw new BizError(ERRORENUM.企业不存在);
//{outcome, followUpStatus:enumConfig.FOLLOWUPSTATUS.已完成, desc, resolveTime}
let excelInfo = {
esId: randomId(TABLEID.企业服务表),
eId:enterpriseDbInfo.eId,
needCategory:NEEDCATEGORY[info[2]],
needContent:info[3],
applyTime:info[4],
fangKui:info[5],
shouLiTime:getMySqlMs(info[6]),
outcome: OUTCOME[info[7]],
desc:info[8],
followUpStatus:FOLLOWUPSTATUS.已完成,
}
// 新增企业服务
await operationalData(OPERATIONALDATATYPE.增加, TABLENAME.企业服务表, excelInfo, {});
console.log(`新增已完成企业服务信息完成:${enterpriseName}`);
}
res.success({isSuccess:true});
} }
......
...@@ -8,6 +8,7 @@ import * as fuhuaRouters from './fuhua'; ...@@ -8,6 +8,7 @@ import * as fuhuaRouters from './fuhua';
import * as dbInitRouters from './dbinit'; import * as dbInitRouters from './dbinit';
import * as userRuFuRouters from './userRuFu'; import * as userRuFuRouters from './userRuFu';
import * as answerRouters from './answer'; import * as answerRouters from './answer';
import * as zipRouters from './zip';
export function setRouter(httpServer){ export function setRouter(httpServer){
/**下拉框等公用 路由 */ /**下拉框等公用 路由 */
publicRouters.setRouter(httpServer); publicRouters.setRouter(httpServer);
...@@ -20,4 +21,6 @@ export function setRouter(httpServer){ ...@@ -20,4 +21,6 @@ export function setRouter(httpServer){
userRuFuRouters.setRouter(httpServer); userRuFuRouters.setRouter(httpServer);
answerRouters.setRouter(httpServer); answerRouters.setRouter(httpServer);
zipRouters.setRouter(httpServer);
} }
\ No newline at end of file
/**
* zip文件下载
*/
import * as asyncHandler from 'express-async-handler';
import * as zipBiz from '../biz/createZip';
import { checkUser } from '../middleware/user';
import * as fs from 'fs-extra';
export function setRouter(httpServer) {
httpServer.post('/admin/zip/download', checkUser, asyncHandler(downloadZipfiles));
}
/**
* 下载企业文件ZIP包
* @param req
* @param res
*/
async function downloadZipfiles(req, res) {
try {
console.log('收到ZIP下载请求,参数:', req.body);
let { eId } = req.body;
if (!eId) {
return res.status(400).json({ error: '缺少必要参数eId' });
}
let result = await zipBiz.downloadEnterpriseFilesZip(eId);
console.log('ZIP文件创建成功:', result.fileName);
// 设置响应头
res.setHeader('Content-Type', 'application/zip');
res.setHeader('Content-Disposition', `attachment; filename=${encodeURIComponent(result.fileName)}`);
res.setHeader('Access-Control-Expose-Headers', 'Content-Disposition');
// 检查文件是否存在
if (!await fs.pathExists(result.filePath)) {
throw new Error('ZIP文件未找到: ' + result.filePath);
}
// 获取文件状态
const stats = await fs.stat(result.filePath);
res.setHeader('Content-Length', stats.size);
console.log(`准备发送文件: ${result.fileName}, 大小: ${stats.size} bytes`);
// 发送文件
res.sendFile(result.filePath, (err) => {
if (err) {
console.error('发送文件失败:', err);
if (!res.headersSent) {
res.status(500).json({ error: '文件发送失败', message: err.message });
}
} else {
console.log('文件发送成功');
}
// 可选:发送完成后删除临时文件
setTimeout(async () => {
try {
if (await fs.pathExists(result.filePath)) {
await fs.remove(result.filePath);
console.log('临时文件已清理:', result.filePath);
}
} catch (cleanupError) {
console.error('清理临时文件失败:', cleanupError);
}
}, 1000);
});
} catch (error) {
console.error('下载文件失败:', error);
if (!res.headersSent) {
res.status(500).json({
error: '下载失败',
message: error.message,
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
});
}
}
}
{ {
"compilerOptions": { "compilerOptions": {
"module": "commonjs", "module": "commonjs",
"target": "es2017", "target": "ES2020",
"sourceMap": true, "sourceMap": true,
"rootDir":"./src", "rootDir":"./src",
"outDir":"./out" "outDir":"./out"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment