明树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) {
}
}
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) {
try {
if (!req.body.id) {
......@@ -834,8 +863,8 @@ async function listProject(req, res, next) {
projectLzTypes = [5, 7, 8, 9];
break;
}
if(req.body.menuType) {
where.projectLzType = {[Op.in]: projectLzTypes}
if (req.body.menuType) {
where.projectLzType = { [Op.in]: projectLzTypes }
}
console.log(projectLzTypes)
search.where = where;
......@@ -999,4 +1028,5 @@ module.exports = {
saveProjectPreLixiang,
queryLixiangResult,
queryJueceResult,
getProjectCwpj,
}
\ No newline at end of file
......@@ -6,16 +6,25 @@
*/
const ExcelJS = require('exceljs');
const path = require('path');
const { HyperFormula } = require('hyperformula');
const errorMessage = require("../utils/errorMessage");
const keyName = {
tjjh: "投决计划",
xmtzzjll: "项目投资资金流量表",
xmzbjxjll: "项目资本金现金流量表",
njfxjll: "能建方现金流量表",
lrb: "利润表"
}
async function getXmtzzjllTem({ startYear, endYear, tampName, projectId }) {
const workbook = new ExcelJS.Workbook();
// 1. 读取空模板文件
const inputFilePath = path.join(__dirname, '../public/template/项目投资资金流量表.xlsx');
const inputFilePath = path.join(__dirname, `../public/template/${keyName[tampName]}.xlsx`);
// 2. 处理excel 文件,动态生成表格
await workbook.xlsx.readFile(inputFilePath);
const worksheet = await workbook.getWorksheet(1);
console.log(worksheet.actualRowCount, worksheet.actualColumnCount,)
// 2.1 处理表头
let count = Number(endYear) - Number(startYear);
let columns = [];
......@@ -24,7 +33,7 @@ async function getXmtzzjllTem({ startYear, endYear, tampName, projectId }) {
}
// 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) {
let tzzjlls = await DB.ProjectTzzjll.findAll({
where: { projectId: projectId, del: 0 },
......@@ -71,74 +80,30 @@ async function getXmtzzjllTem({ startYear, endYear, tampName, projectId }) {
wrapText: true
};
cell.border = BLACK_BORDER; //边框
});
});
const buffer = await workbook.xlsx.writeBuffer();
return buffer;
}
async function getTjjh({ startYear, endYear, projectId, tampName }) {
const workbook = new ExcelJS.Workbook();
const inputFilePath = path.join(__dirname, '../public/templates/投决计划.xlsx');
// 2. 处理excel 文件,动态生成表格
await workbook.xlsx.readFile(inputFilePath);
const worksheet = await workbook.getWorksheet(1);
// 2.1 处理表头
let count = endYear - startYear;
let columns = [];
for (let index = 0; index <= count; index++) {
columns.push({ name: Number(startYear + index) });
}
// 2.2 处理数据
let rows = Array(42).fill([]); // 5 是模板有5行
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'; //数字格式
if (tampName == "tjjh") {
let enColNum = getExcelColumnLetter(colNumber)
if (rowNumber == 13 && colNumber >= 4) {
cell.value = { formula: `=SUM(${enColNum}5,${enColNum}8,${enColNum}11)` }
}
if (rowNumber == 21 && colNumber >= 4) {
cell.value = { formula: `=${enColNum}19-${enColNum}20` } //{ formula: '=AF19-AF20' }
}
if (rowNumber == 26 && colNumber >= 4) {
cell.value = { formula: `=SUM(${enColNum}27,${enColNum}28)` }
}
if (rowNumber == 29 && colNumber >= 4) {
cell.value = { formula: `=SUM(${enColNum}30,${enColNum}31)` }
}
if (rowNumber == 35 && colNumber >= 4) {
cell.value = { formula: `=SUM(${enColNum}36-${enColNum}37)` }
}
if (rowNumber == 38 && colNumber >= 4) {
cell.value = { formula: `=${enColNum}39-${enColNum}40` }
}
if (rowNumber == 41 && colNumber >= 4) {
cell.value = { formula: `=SUM(${enColNum}42-${enColNum}43)` }
}
}
cell.alignment = {
horizontal: 'center',
vertical: 'middle', //垂直居中
wrapText: true
};
cell.border = BLACK_BORDER; //边框
});
});
const buffer = await workbook.xlsx.writeBuffer();
......@@ -150,14 +115,7 @@ async function getExcelTemplate(req, res, next) {
let { tampName, projectId, startYear, endYear } = req.query;
startYear = Number(startYear) || new Date().getFullYear();
endYear = endYear || Number(startYear + 33);
let keyName = {
tjjh: "投决计划",
xmtzzjll: "项目投资资金流量表",
xmzbjxjll: "项目资本金现金流量表",
njfxjll: "能建方现金流量表",
lrb: "利润表"
}
let buffer = await getXmtzzjllTem({ startYear, endYear, tampName, projectId, keyName });
let buffer = await getXmtzzjllTem({ startYear, endYear, tampName, projectId });
// 3. 将处理后的文件发送给前端
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', 'attachment; filename=' + encodeURIComponent(`${keyName[tampName]}.xlsx`));
......@@ -168,104 +126,87 @@ async function getExcelTemplate(req, res, next) {
}
}
//处理 项目投资资金流量表 以【数据项、年度】为【数据库表结构字段】 转化为excel行数据
function thvc(a) {
let xjlr = [], xjlc = [], sdsqjxjll = [], tzsds = [], sdshjxjll = [];
for (let index = 0; index < a.length; index++) {
const element = a[index];
xjlr.push(element.xjlr);
xjlc.push(element.xjlc);
sdsqjxjll.push(element.sdsqjxjll);
tzsds.push(element.tzsds);
sdshjxjll.push(element.sdshjxjll);
// year.push(element.year);
// 处理列数字转字母
function getExcelColumnLetter(columnNumber) {
// 验证输入有效性
if (typeof columnNumber !== 'number' || columnNumber < 1) {
throw new Error('列号必须是大于0的整数');
}
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) {
try {
let { tampName, projectId } = req.body;
if (tampName == 'xmtzzjll') {
// if (!projectId) {
// errorMessage.paramsError.message = "项目ID不能为空";
// return res.sendError(errorMessage.paramsError);
// }
const workbook = new ExcelJS.Workbook();
workbook.calcProperties.fullCalcOnLoad = true;
await workbook.xlsx.load(req.file.buffer, {
ignoreNodes: ['relationships', 'styles', 'calcChain', 'drawings', 'core']
});
const worksheet = await workbook.getWorksheet(1);
let headers = [], data = [];
worksheet.eachRow((row, rowIndex) => {
let colText = [];
row.eachCell((col, colIndex) => {
console.log(col.result, col.value, "--", col.text, "-", col.toString());
if (rowIndex == 3 && colIndex > 3) {
console.log(col);
headers.push(col.text);
}
if (rowIndex > 3) {
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));
console.log(tampName, projectId);
const workbook = new ExcelJS.Workbook();
console.log(req.file);
console.log(req.file.buffer);
await workbook.xlsx.load(req.file.buffer);
const worksheet = workbook.getWorksheet(1);
const hf = HyperFormula.buildEmpty({
licenseKey: 'gpl-v3',
precisionRounding: 14
});
const sheetData = [];
worksheet.eachRow({ includeEmpty: true }, (row, ri) => {
const rowData = [];
row.eachCell({ includeEmpty: true }, (cell, ci) => {
if (cell.formula) {
rowData.push(cell.formula);
} else if (cell.type === ExcelJS.ValueType.String) {
rowData.push(cell.text + "_suffix");
} else if (cell.value === null || cell.value === undefined) {
rowData.push(null);
} else {
rowData.push(cell.value);
}
});
const fieldMap = {
1: 'xjlr', // 现金流入
2: 'xjlc', // 现金流出
3: 'sdsqjxjll', // 所得税前净现金流量
4: 'tzsds', // 调整所得税
5: 'sdshjxjll' // 所得税后净现金流量
};
let retData = [];
years.map((year, yearIndex) => {
const yearData = { year };
for (let rowIndex = 1; rowIndex <= data.length; rowIndex++) {
const fieldKey = fieldMap[rowIndex];
if (fieldKey) {
const value = data[rowIndex - 1][yearIndex];
yearData[fieldKey] = parseFloat(value) || 0;
}
sheetData.push(rowData);
});
hf.addSheet('Sheet1'); // 先建表
hf.setSheetContent(0, sheetData); // 灌数据+公式
const { height, width } = hf.getSheetDimensions(0);
const out = [];
for (let r = 0; r < height; r++) {
let cc = [];
for (let c = 0; c < sheetData[0].length; c++) {
// const formulaString = hf.getCellFormula({ sheet: 0, row: r, col: c });
let calculated = hf.getCellValue({ sheet: 0, row: r, col: c });
// console.log(formulaString, calculated)
if(typeof calculated == 'string') {
calculated = removeSuffix(String(calculated),'_suffix')
}
retData.push(yearData);
});
await ProjectTzzjll.destroy({
where: { projectId: projectId },
});
await ProjectTzzjll.bulkCreate(retData);
cc.push(calculated);
}
out.push(cc);
}
await DB.ProjectExcelData.create({projectId, tampName, data: out});
return res.sendData(out);
} catch (error) {
next(error)
}
}
function removeSuffix(str, suffix) {
return str.endsWith(suffix)
? str.slice(0, -suffix.length)
: str;
}
async function importExcelTempData2(req, res, next) {
try {
let { tampName, projectId } = req.body;
......
const sequelize = require('./model/index');
// 模型初始化
const User = require("./model/system/user");
const Role = require("./model/system/role");
......@@ -31,6 +33,7 @@ const ProjectTzzjll = require("./model/jt/projectTzzjll");
const ProjectTzzt = require("./model/jt/projectTzzt");
const ProjectXmtzze = require("./model/jt/projectXmtzze");
const ProjectLixiang = require("./model/jt/projectLixiang");
const ProjectExcelData = require("./model/jt/projectExcelData");
/**
......@@ -40,6 +43,7 @@ const ProjectLixiang = require("./model/jt/projectLixiang");
global.DB = {
sequelize,
User,
RequestLog,
Role,
......@@ -69,6 +73,7 @@ global.DB = {
Message,
FlowRecord,
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 @@
"exceljs": "4.4.0",
"express": "4.19.2",
"form-data": "4.0.0",
"hyperformula": "^3.1.0",
"ioredis": "5.4.1",
"joi": "17.13.1",
"lodash": "4.17.21",
......
......@@ -25,6 +25,10 @@ router.post('/startJuece', projectController.startJuece); //发起决策
router.post('/queryJueceResult', projectController.queryJueceResult); //查询决策审批结果
// 财务评价
router.post('/getProjectCwpj', projectController.getProjectCwpj);
router.post('/getProjectInfo', projectController.getProjectInfo);
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