明树Git Lab

Commit 6588ab91 authored by zfp1's avatar zfp1

update

parent 7912bdfb
Pipeline #104235 passed with stage
in 4 seconds
...@@ -766,6 +766,35 @@ async function finalJugProject(req, res, next) { ...@@ -766,6 +766,35 @@ async function finalJugProject(req, res, next) {
} }
} }
async function getProjectCwpj(req, res, next) {
try {
const projectId = req.body.id;
if (!projectId) {
return res.sendError(errorMessage.resourceNotFound);
}
const sql = `SELECT * FROM (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY tampName
ORDER BY updatedAt DESC, id DESC
) AS row_num
FROM jt_project_excel_data
WHERE projectId = :projectId AND del = 0
) AS ranked
WHERE row_num = 1`;
const results = await DB.sequelize.query(sql, {
replacements: { projectId },
type: sequelize.QueryTypes.SELECT,
model: DB.ProjectExcelData, // 替换为实际模型
mapToModel: true
});
return res.sendData(results);
} catch (error) {
next(error);
}
}
async function getProjectInfo(req, res, next) { async function getProjectInfo(req, res, next) {
try { try {
if (!req.body.id) { if (!req.body.id) {
...@@ -834,8 +863,8 @@ async function listProject(req, res, next) { ...@@ -834,8 +863,8 @@ async function listProject(req, res, next) {
projectLzTypes = [5, 7, 8, 9]; projectLzTypes = [5, 7, 8, 9];
break; break;
} }
if(req.body.menuType) { if (req.body.menuType) {
where.projectLzType = {[Op.in]: projectLzTypes} where.projectLzType = { [Op.in]: projectLzTypes }
} }
console.log(projectLzTypes) console.log(projectLzTypes)
search.where = where; search.where = where;
...@@ -999,4 +1028,5 @@ module.exports = { ...@@ -999,4 +1028,5 @@ module.exports = {
saveProjectPreLixiang, saveProjectPreLixiang,
queryLixiangResult, queryLixiangResult,
queryJueceResult, queryJueceResult,
getProjectCwpj,
} }
\ No newline at end of file
...@@ -6,16 +6,25 @@ ...@@ -6,16 +6,25 @@
*/ */
const ExcelJS = require('exceljs'); const ExcelJS = require('exceljs');
const path = require('path'); const path = require('path');
const { HyperFormula } = require('hyperformula');
const errorMessage = require("../utils/errorMessage"); const errorMessage = require("../utils/errorMessage");
const keyName = {
tjjh: "投决计划",
xmtzzjll: "项目投资资金流量表",
xmzbjxjll: "项目资本金现金流量表",
njfxjll: "能建方现金流量表",
lrb: "利润表"
}
async function getXmtzzjllTem({ startYear, endYear, tampName, projectId }) { async function getXmtzzjllTem({ startYear, endYear, tampName, projectId }) {
const workbook = new ExcelJS.Workbook(); const workbook = new ExcelJS.Workbook();
// 1. 读取空模板文件 // 1. 读取空模板文件
const inputFilePath = path.join(__dirname, '../public/template/项目投资资金流量表.xlsx'); const inputFilePath = path.join(__dirname, `../public/template/${keyName[tampName]}.xlsx`);
// 2. 处理excel 文件,动态生成表格 // 2. 处理excel 文件,动态生成表格
await workbook.xlsx.readFile(inputFilePath); await workbook.xlsx.readFile(inputFilePath);
const worksheet = await workbook.getWorksheet(1); const worksheet = await workbook.getWorksheet(1);
console.log(worksheet.actualRowCount, worksheet.actualColumnCount,)
// 2.1 处理表头 // 2.1 处理表头
let count = Number(endYear) - Number(startYear); let count = Number(endYear) - Number(startYear);
let columns = []; let columns = [];
...@@ -24,7 +33,7 @@ async function getXmtzzjllTem({ startYear, endYear, tampName, projectId }) { ...@@ -24,7 +33,7 @@ async function getXmtzzjllTem({ startYear, endYear, tampName, projectId }) {
} }
// 2.2 处理数据 // 2.2 处理数据
let rows = Array(5).fill(Array(columns.length).fill(0)); // 5 是模板有5行 let rows = Array(worksheet.actualRowCount - 3).fill(Array(columns.length).fill("")); // 5 是模板有5行
if (projectId) { if (projectId) {
let tzzjlls = await DB.ProjectTzzjll.findAll({ let tzzjlls = await DB.ProjectTzzjll.findAll({
where: { projectId: projectId, del: 0 }, where: { projectId: projectId, del: 0 },
...@@ -71,74 +80,30 @@ async function getXmtzzjllTem({ startYear, endYear, tampName, projectId }) { ...@@ -71,74 +80,30 @@ async function getXmtzzjllTem({ startYear, endYear, tampName, projectId }) {
wrapText: true wrapText: true
}; };
cell.border = BLACK_BORDER; //边框 cell.border = BLACK_BORDER; //边框
}); if (tampName == "tjjh") {
}); let enColNum = getExcelColumnLetter(colNumber)
const buffer = await workbook.xlsx.writeBuffer(); if (rowNumber == 13 && colNumber >= 4) {
return buffer; cell.value = { formula: `=SUM(${enColNum}5,${enColNum}8,${enColNum}11)` }
} }
if (rowNumber == 21 && colNumber >= 4) {
async function getTjjh({ startYear, endYear, projectId, tampName }) { cell.value = { formula: `=${enColNum}19-${enColNum}20` } //{ formula: '=AF19-AF20' }
const workbook = new ExcelJS.Workbook(); }
if (rowNumber == 26 && colNumber >= 4) {
const inputFilePath = path.join(__dirname, '../public/templates/投决计划.xlsx'); cell.value = { formula: `=SUM(${enColNum}27,${enColNum}28)` }
// 2. 处理excel 文件,动态生成表格 }
await workbook.xlsx.readFile(inputFilePath); if (rowNumber == 29 && colNumber >= 4) {
const worksheet = await workbook.getWorksheet(1); cell.value = { formula: `=SUM(${enColNum}30,${enColNum}31)` }
// 2.1 处理表头 }
let count = endYear - startYear; if (rowNumber == 35 && colNumber >= 4) {
let columns = []; cell.value = { formula: `=SUM(${enColNum}36-${enColNum}37)` }
for (let index = 0; index <= count; index++) { }
columns.push({ name: Number(startYear + index) }); if (rowNumber == 38 && colNumber >= 4) {
} cell.value = { formula: `=${enColNum}39-${enColNum}40` }
}
// 2.2 处理数据 if (rowNumber == 41 && colNumber >= 4) {
let rows = Array(42).fill([]); // 5 是模板有5行 cell.value = { formula: `=SUM(${enColNum}42-${enColNum}43)` }
if (!projectId) { }
let tzzjlls = await ProjectTzzjll.findAll({
where: { projectId: projectId, del: 0 },
raw: true,
});
tzzjlls = _.sortBy(tzzjlls, 'year');
rows = thvc(tzzjlls);
}
console.log(rows, "=============")
// 使用addTable创建表格
worksheet.addTable({
name: 'FinancialData',
ref: 'D3',
headerRow: true,
totalsRow: false,
style: {
theme: null,
showRowStripes: false,
showColumnStripes: false,
},
columns: columns,
rows: rows
});
worksheet.mergeCells(2, 3, 2, (3 + columns.length))
worksheet.mergeCells(1, 1, 1, (3 + columns.length))
const BLACK_BORDER = {
top: { style: 'thin', color: { argb: 'FF000000' } },
left: { style: 'thin', color: { argb: 'FF000000' } },
bottom: { style: 'thin', color: { argb: 'FF000000' } },
right: { style: 'thin', color: { argb: 'FF000000' } }
};
// 遍历所有单元格添加边框
worksheet.eachRow((row, rowNumber) => {
row.eachCell((cell, colNumber) => {
if (rowNumber >= 4 && rowNumber <= 8 && colNumber >= 4 && colNumber <= (3 + columns.length)) {
cell.numFmt = '#,##0.00'; //数字格式
} }
cell.alignment = {
horizontal: 'center',
vertical: 'middle', //垂直居中
wrapText: true
};
cell.border = BLACK_BORDER; //边框
}); });
}); });
const buffer = await workbook.xlsx.writeBuffer(); const buffer = await workbook.xlsx.writeBuffer();
...@@ -150,14 +115,7 @@ async function getExcelTemplate(req, res, next) { ...@@ -150,14 +115,7 @@ async function getExcelTemplate(req, res, next) {
let { tampName, projectId, startYear, endYear } = req.query; let { tampName, projectId, startYear, endYear } = req.query;
startYear = Number(startYear) || new Date().getFullYear(); startYear = Number(startYear) || new Date().getFullYear();
endYear = endYear || Number(startYear + 33); endYear = endYear || Number(startYear + 33);
let keyName = { let buffer = await getXmtzzjllTem({ startYear, endYear, tampName, projectId });
tjjh: "投决计划",
xmtzzjll: "项目投资资金流量表",
xmzbjxjll: "项目资本金现金流量表",
njfxjll: "能建方现金流量表",
lrb: "利润表"
}
let buffer = await getXmtzzjllTem({ startYear, endYear, tampName, projectId, keyName });
// 3. 将处理后的文件发送给前端 // 3. 将处理后的文件发送给前端
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', 'attachment; filename=' + encodeURIComponent(`${keyName[tampName]}.xlsx`)); res.setHeader('Content-Disposition', 'attachment; filename=' + encodeURIComponent(`${keyName[tampName]}.xlsx`));
...@@ -168,104 +126,87 @@ async function getExcelTemplate(req, res, next) { ...@@ -168,104 +126,87 @@ async function getExcelTemplate(req, res, next) {
} }
} }
//处理 项目投资资金流量表 以【数据项、年度】为【数据库表结构字段】 转化为excel行数据 // 处理列数字转字母
function thvc(a) { function getExcelColumnLetter(columnNumber) {
let xjlr = [], xjlc = [], sdsqjxjll = [], tzsds = [], sdshjxjll = []; // 验证输入有效性
for (let index = 0; index < a.length; index++) { if (typeof columnNumber !== 'number' || columnNumber < 1) {
const element = a[index]; throw new Error('列号必须是大于0的整数');
xjlr.push(element.xjlr);
xjlc.push(element.xjlc);
sdsqjxjll.push(element.sdsqjxjll);
tzsds.push(element.tzsds);
sdshjxjll.push(element.sdshjxjll);
// year.push(element.year);
} }
return [xjlr, xjlc, sdsqjxjll, tzsds, sdshjxjll];
let dividend = columnNumber;
let columnLetter = '';
while (dividend > 0) {
// 取余数(0-25对应A-Z)
const modulo = (dividend - 1) % 26;
// 将ASCII码转换为字母(65是'A'的ASCII码)
columnLetter = String.fromCharCode(65 + modulo) + columnLetter;
// 更新被除数
dividend = Math.floor((dividend - modulo) / 26);
}
return columnLetter;
} }
async function importExcelTempData(req, res, next) { async function importExcelTempData(req, res, next) {
try { try {
let { tampName, projectId } = req.body; let { tampName, projectId } = req.body;
if (tampName == 'xmtzzjll') { console.log(tampName, projectId);
// if (!projectId) { const workbook = new ExcelJS.Workbook();
// errorMessage.paramsError.message = "项目ID不能为空"; console.log(req.file);
// return res.sendError(errorMessage.paramsError); console.log(req.file.buffer);
// } await workbook.xlsx.load(req.file.buffer);
const workbook = new ExcelJS.Workbook(); const worksheet = workbook.getWorksheet(1);
workbook.calcProperties.fullCalcOnLoad = true; const hf = HyperFormula.buildEmpty({
await workbook.xlsx.load(req.file.buffer, { licenseKey: 'gpl-v3',
ignoreNodes: ['relationships', 'styles', 'calcChain', 'drawings', 'core'] precisionRounding: 14
}); });
const worksheet = await workbook.getWorksheet(1); const sheetData = [];
worksheet.eachRow({ includeEmpty: true }, (row, ri) => {
let headers = [], data = []; const rowData = [];
worksheet.eachRow((row, rowIndex) => { row.eachCell({ includeEmpty: true }, (cell, ci) => {
let colText = []; if (cell.formula) {
row.eachCell((col, colIndex) => { rowData.push(cell.formula);
console.log(col.result, col.value, "--", col.text, "-", col.toString()); } else if (cell.type === ExcelJS.ValueType.String) {
if (rowIndex == 3 && colIndex > 3) { rowData.push(cell.text + "_suffix");
console.log(col); } else if (cell.value === null || cell.value === undefined) {
headers.push(col.text); rowData.push(null);
} } else {
if (rowIndex > 3) { rowData.push(cell.value);
colText.push(col.value);
}
});
if (rowIndex > 3) {
data.push(colText);
}
});
return res.sendData({ headers, data });
} else if (tampName === 'tjjh') {
if (!projectId) {
errorMessage.paramsError.message = "项目ID不能为空";
return res.sendError(errorMessage.paramsError);
}
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.load(req.file.buffer);
const worksheet = await workbook.getWorksheet(1);
let years = [], data = [];
worksheet.eachRow((row, rowIndex) => {
if (rowIndex === 3) {
years = row.values.slice(4);
}
if (rowIndex > 3) {
data.push(row.values.slice(4));
} }
}); });
const fieldMap = { sheetData.push(rowData);
1: 'xjlr', // 现金流入 });
2: 'xjlc', // 现金流出 hf.addSheet('Sheet1'); // 先建表
3: 'sdsqjxjll', // 所得税前净现金流量 hf.setSheetContent(0, sheetData); // 灌数据+公式
4: 'tzsds', // 调整所得税 const { height, width } = hf.getSheetDimensions(0);
5: 'sdshjxjll' // 所得税后净现金流量 const out = [];
}; for (let r = 0; r < height; r++) {
let retData = []; let cc = [];
years.map((year, yearIndex) => { for (let c = 0; c < sheetData[0].length; c++) {
const yearData = { year }; // const formulaString = hf.getCellFormula({ sheet: 0, row: r, col: c });
for (let rowIndex = 1; rowIndex <= data.length; rowIndex++) { let calculated = hf.getCellValue({ sheet: 0, row: r, col: c });
const fieldKey = fieldMap[rowIndex]; // console.log(formulaString, calculated)
if (fieldKey) { if(typeof calculated == 'string') {
const value = data[rowIndex - 1][yearIndex]; calculated = removeSuffix(String(calculated),'_suffix')
yearData[fieldKey] = parseFloat(value) || 0;
}
} }
retData.push(yearData); cc.push(calculated);
}); }
await ProjectTzzjll.destroy({ out.push(cc);
where: { projectId: projectId },
});
await ProjectTzzjll.bulkCreate(retData);
} }
await DB.ProjectExcelData.create({projectId, tampName, data: out});
return res.sendData(out);
} catch (error) { } catch (error) {
next(error) next(error)
} }
} }
function removeSuffix(str, suffix) {
return str.endsWith(suffix)
? str.slice(0, -suffix.length)
: str;
}
async function importExcelTempData2(req, res, next) { async function importExcelTempData2(req, res, next) {
try { try {
let { tampName, projectId } = req.body; let { tampName, projectId } = req.body;
......
const sequelize = require('./model/index');
// 模型初始化 // 模型初始化
const User = require("./model/system/user"); const User = require("./model/system/user");
const Role = require("./model/system/role"); const Role = require("./model/system/role");
...@@ -31,6 +33,7 @@ const ProjectTzzjll = require("./model/jt/projectTzzjll"); ...@@ -31,6 +33,7 @@ const ProjectTzzjll = require("./model/jt/projectTzzjll");
const ProjectTzzt = require("./model/jt/projectTzzt"); const ProjectTzzt = require("./model/jt/projectTzzt");
const ProjectXmtzze = require("./model/jt/projectXmtzze"); const ProjectXmtzze = require("./model/jt/projectXmtzze");
const ProjectLixiang = require("./model/jt/projectLixiang"); const ProjectLixiang = require("./model/jt/projectLixiang");
const ProjectExcelData = require("./model/jt/projectExcelData");
/** /**
...@@ -40,6 +43,7 @@ const ProjectLixiang = require("./model/jt/projectLixiang"); ...@@ -40,6 +43,7 @@ const ProjectLixiang = require("./model/jt/projectLixiang");
global.DB = { global.DB = {
sequelize,
User, User,
RequestLog, RequestLog,
Role, Role,
...@@ -69,6 +73,7 @@ global.DB = { ...@@ -69,6 +73,7 @@ global.DB = {
Message, Message,
FlowRecord, FlowRecord,
ProjectLixiang, ProjectLixiang,
ProjectExcelData,
} }
......
const { DataTypes } = require('sequelize');
const sequelize = require('../index');
const moment = require('moment');
//投决计划---决策信息--财务评价--投决计划
const ProjectExcelData = sequelize.define('ProjectExcelData', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
tampName: { type: DataTypes.STRING, allowNull: true, comment: "模板名称" },
data: { type: DataTypes.JSON, allowNull: true, comment: "解析数据" }, //原本设计数据横向转纵向存储,再取出来纵向转横向还原,过于复杂,而且数据无其他统计计算要求,只是展示,暂时此方案,后续若改动,清洗数据即可
projectId: {
type: DataTypes.INTEGER,
comment: "所属项目ID",
},
del: {
type: DataTypes.INTEGER,
defaultValue: 0,
comment: "0 正常 1 删除"
},
// createdAt: {
// type: DataTypes.DATE,
// defaultValue: new Date(),
// get() {
// const rawValue = this.getDataValue('createdAt');
// return rawValue ? moment(rawValue).format('YYYY-MM-DD HH:mm:ss') : '';
// }
// },
// updatedAt: { // 同样处理 updatedAt
// type: DataTypes.DATE,
// defaultValue: new Date(),
// get() {
// const rawValue = this.getDataValue('createdAt');
// return rawValue ? moment(rawValue).format('YYYY-MM-DD HH:mm:ss') : '';
// }
// }
}, {
tableName: 'jt_project_excel_data', // 指定表名(如果与模型名不同)
timestamps: true, // 是否自动添加 createdAt 和 updatedAt 字段(覆盖全局设置)
});
// 同步模型到数据库(创建表)
ProjectExcelData.sync({
force: false,
// force: true ,//会删除已存在表并重新创建
// alter: true
})
.then(() => {
console.log('ProjectExcelData 表同步成功');
});
module.exports = ProjectExcelData;
\ No newline at end of file
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
"exceljs": "4.4.0", "exceljs": "4.4.0",
"express": "4.19.2", "express": "4.19.2",
"form-data": "4.0.0", "form-data": "4.0.0",
"hyperformula": "^3.1.0",
"ioredis": "5.4.1", "ioredis": "5.4.1",
"joi": "17.13.1", "joi": "17.13.1",
"lodash": "4.17.21", "lodash": "4.17.21",
......
...@@ -25,6 +25,10 @@ router.post('/startJuece', projectController.startJuece); //发起决策 ...@@ -25,6 +25,10 @@ router.post('/startJuece', projectController.startJuece); //发起决策
router.post('/queryJueceResult', projectController.queryJueceResult); //查询决策审批结果 router.post('/queryJueceResult', projectController.queryJueceResult); //查询决策审批结果
// 财务评价
router.post('/getProjectCwpj', projectController.getProjectCwpj);
router.post('/getProjectInfo', projectController.getProjectInfo); router.post('/getProjectInfo', projectController.getProjectInfo);
router.post('/updateProject', projectController.updateProject); router.post('/updateProject', projectController.updateProject);
......
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