Added many more fields to Export to Excel, and better formatting. Does not yet have all fields.

Thanks to xet7 !

Related #3173
This commit is contained in:
Lauri Ojansivu 2021-01-28 03:19:35 +02:00
parent 442a7b0fcd
commit 37372466cc

View file

@ -24,7 +24,6 @@ if (Meteor.isServer) {
Picker.route('/api/boards/:boardId/exportExcel', function(params, req, res) { Picker.route('/api/boards/:boardId/exportExcel', function(params, req, res) {
const boardId = params.boardId; const boardId = params.boardId;
let user = null; let user = null;
//console.log('Excel');
const loginToken = params.query.authToken; const loginToken = params.query.authToken;
if (loginToken) { if (loginToken) {
@ -163,6 +162,11 @@ export class ExporterExcel {
users[memberId] = true; users[memberId] = true;
}); });
} }
if (card.assignees) {
card.assignees.forEach(memberId => {
users[memberId] = true;
});
}
}); });
result.comments.forEach(comment => { result.comments.forEach(comment => {
users[comment.userId] = true; users[comment.userId] = true;
@ -184,7 +188,6 @@ export class ExporterExcel {
fields: { fields: {
_id: 1, _id: 1,
username: 1, username: 1,
'profile.fullname': 1,
'profile.initials': 1, 'profile.initials': 1,
'profile.avatarUrl': 1, 'profile.avatarUrl': 1,
}, },
@ -199,7 +202,6 @@ export class ExporterExcel {
return user; return user;
}); });
const jdata = result;
//init exceljs workbook //init exceljs workbook
const Excel = require('exceljs'); const Excel = require('exceljs');
const workbook = new Excel.Workbook(); const workbook = new Excel.Workbook();
@ -208,9 +210,9 @@ export class ExporterExcel {
workbook.created = new Date(); workbook.created = new Date();
workbook.modified = new Date(); workbook.modified = new Date();
workbook.lastPrinted = new Date(); workbook.lastPrinted = new Date();
const filename = `${jdata.title}.xlsx`; const filename = `${result.title}.xlsx`;
//init worksheet //init worksheet
const worksheet = workbook.addWorksheet(jdata.title, { const worksheet = workbook.addWorksheet(result.title, {
properties: { properties: {
tabColor: { tabColor: {
argb: 'FFC0000', argb: 'FFC0000',
@ -222,26 +224,26 @@ export class ExporterExcel {
}, },
}); });
//get worksheet //get worksheet
const ws = workbook.getWorksheet(jdata.title); const ws = workbook.getWorksheet(result.title);
ws.properties.defaultRowHeight = 20; ws.properties.defaultRowHeight = 20;
//init columns //init columns
//Excel font. Western: Arial. zh-CN: 宋体 //Excel font. Western: Arial. zh-CN: 宋体
ws.columns = [ ws.columns = [
{ {
key: 'a', key: 'a',
width: 7, width: 14,
}, },
{ {
key: 'b', key: 'b',
width: 16, width: 20,
}, },
{ {
key: 'c', key: 'c',
width: 7, width: 20,
}, },
{ {
key: 'd', key: 'd',
width: 14, width: 20,
style: { style: {
font: { font: {
name: TAPi18n.__('excel-font'), name: TAPi18n.__('excel-font'),
@ -252,7 +254,7 @@ export class ExporterExcel {
}, },
{ {
key: 'e', key: 'e',
width: 14, width: 20,
style: { style: {
font: { font: {
name: TAPi18n.__('excel-font'), name: TAPi18n.__('excel-font'),
@ -263,21 +265,88 @@ export class ExporterExcel {
}, },
{ {
key: 'f', key: 'f',
width: 10, width: 20,
style: {
font: {
name: TAPi18n.__('excel-font'),
size: '10',
},
numFmt: 'yyyy/mm/dd hh:mm:ss',
},
}, },
{ {
key: 'g', key: 'g',
width: 10, width: 20,
style: {
font: {
name: TAPi18n.__('excel-font'),
size: '10',
},
numFmt: 'yyyy/mm/dd hh:mm:ss',
},
}, },
{ {
key: 'h', key: 'h',
width: 18, width: 20,
style: {
font: {
name: TAPi18n.__('excel-font'),
size: '10',
},
numFmt: 'yyyy/mm/dd hh:mm:ss',
},
},
{
key: 'i',
width: 20,
style: {
font: {
name: TAPi18n.__('excel-font'),
size: '10',
},
numFmt: 'yyyy/mm/dd hh:mm:ss',
},
},
{
key: 'j',
width: 20,
style: {
font: {
name: TAPi18n.__('excel-font'),
size: '10',
},
numFmt: 'yyyy/mm/dd hh:mm:ss',
},
},
{
key: 'k',
width: 20,
},
{
key: 'l',
width: 20,
},
{
key: 'm',
width: 20,
},
{
key: 'n',
width: 20,
},
{
key: 'o',
width: 20,
},
{
key: 'p',
width: 20,
}, },
]; ];
//add title line //add title line
ws.mergeCells('A1:H1'); ws.mergeCells('A1:H1');
ws.getCell('A1').value = jdata.title; ws.getCell('A1').value = result.title;
ws.getCell('A1').style = { ws.getCell('A1').style = {
font: { font: {
name: TAPi18n.__('excel-font'), name: TAPi18n.__('excel-font'),
@ -289,38 +358,54 @@ export class ExporterExcel {
horizontal: 'center', horizontal: 'center',
}; };
ws.getRow(1).height = 40; ws.getRow(1).height = 40;
//get member info //get member and assignee info
let jmem = ''; let jmem = '';
let jassig = '';
const jmeml = {}; const jmeml = {};
for (const i in jdata.users) { const jassigl = {};
jmem = `${jmem + jdata.users[i].profile.fullname},`; for (const i in result.users) {
jmeml[jdata.users[i]._id] = jdata.users[i].profile.fullname; jmem = `${jmem + result.users[i].username},`;
jmeml[result.users[i]._id] = result.users[i].username;
} }
jmem = jmem.substr(0, jmem.length - 1); jmem = jmem.substr(0, jmem.length - 1);
for (const ia in result.users) {
jassig = `${jassig + result.users[ia].username},`;
jassigl[result.users[ia]._id] = result.users[ia].username;
}
jassig = jassig.substr(0, jassig.length - 1);
//get kanban list info //get kanban list info
const jlist = {}; const jlist = {};
for (const klist in jdata.lists) { for (const klist in result.lists) {
jlist[jdata.lists[klist]._id] = jdata.lists[klist].title; jlist[result.lists[klist]._id] = result.lists[klist].title;
} }
//get kanban label info //get kanban label info
const jlabel = {}; const jlabel = {};
for (const klabel in jdata.labels) { for (const klabel in result.labels) {
jlabel[jdata.labels[klabel]._id] = jdata.labels[klabel].name; jlabel[result.labels[klabel]._id] = result.labels[klabel].name;
} }
//add data +8 hours //add data +8 hours
function add8hours(jdate) { function addTZhours(jdate) {
const curdate = new Date(jdate); let curdate = new Date(jdate);
return new Date(curdate.setHours(curdate.getHours() + 8)); let checkCorrectDate = moment(curdate);
if (checkCorrectDate.isValid()) {
return curdate;
} else {
return ' ';
}
////Do not add 8 hours to GMT. Use GMT instead.
////Could not yet figure out how to get localtime.
//return new Date(curdate.setHours(curdate.getHours() + 8));
//return curdate;
} }
//add blank row //add blank row
ws.addRow().values = ['', '', '', '', '', '', '', '']; ws.addRow().values = ['', '', '', '', '', ''];
//add kanban info //add kanban info
ws.addRow().values = [ ws.addRow().values = [
TAPi18n.__('createdAt'), TAPi18n.__('createdAt'),
add8hours(jdata.createdAt), addTZhours(result.createdAt),
TAPi18n.__('modifiedAt'), TAPi18n.__('modifiedAt'),
add8hours(jdata.modifiedAt), addTZhours(result.modifiedAt),
TAPi18n.__('r-member'), TAPi18n.__('members'),
jmem, jmem,
]; ];
ws.getRow(3).font = { ws.getRow(3).font = {
@ -328,6 +413,7 @@ export class ExporterExcel {
size: 10, size: 10,
bold: true, bold: true,
}; };
ws.mergeCells('F3:P3');
ws.getCell('B3').style = { ws.getCell('B3').style = {
font: { font: {
name: TAPi18n.__('excel-font'), name: TAPi18n.__('excel-font'),
@ -344,12 +430,19 @@ export class ExporterExcel {
wrapText: true, wrapText: true,
}; };
} }
function cellLeft(cellno) {
ws.getCell(cellno).alignment = {
vertical: 'middle',
horizontal: 'left',
wrapText: true,
};
}
cellCenter('A3'); cellCenter('A3');
cellCenter('B3'); cellCenter('B3');
cellCenter('C3'); cellCenter('C3');
cellCenter('D3'); cellCenter('D3');
cellCenter('E3'); cellCenter('E3');
cellCenter('F3'); cellLeft('F3');
ws.getRow(3).height = 20; ws.getRow(3).height = 20;
//all border //all border
function allBorder(cellno) { function allBorder(cellno) {
@ -375,18 +468,42 @@ export class ExporterExcel {
allBorder('E3'); allBorder('E3');
allBorder('F3'); allBorder('F3');
//add blank row //add blank row
ws.addRow().values = ['', '', '', '', '', '', '', '', '']; ws.addRow().values = [
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
];
//add card title //add card title
//ws.addRow().values = ['编号', '标题', '创建人', '创建时间', '更新时间', '列表', '成员', '描述', '标签']; //ws.addRow().values = ['编号', '标题', '创建人', '创建时间', '更新时间', '列表', '成员', '描述', '标签'];
ws.addRow().values = [ ws.addRow().values = [
TAPi18n.__('number'), TAPi18n.__('number'),
TAPi18n.__('title'), TAPi18n.__('title'),
TAPi18n.__('description'),
TAPi18n.__('owner'), TAPi18n.__('owner'),
TAPi18n.__('createdAt'), TAPi18n.__('createdAt'),
TAPi18n.__('last-modified-at'), TAPi18n.__('last-modified-at'),
TAPi18n.__('card-received'),
TAPi18n.__('card-start'),
TAPi18n.__('card-due'),
TAPi18n.__('card-end'),
TAPi18n.__('list'), TAPi18n.__('list'),
TAPi18n.__('description'), TAPi18n.__('assignee'),
TAPi18n.__('status'), TAPi18n.__('members'),
TAPi18n.__('labels'),
TAPi18n.__('overtime-hours'),
TAPi18n.__('spent-time-hours'),
]; ];
ws.getRow(5).height = 20; ws.getRow(5).height = 20;
allBorder('A5'); allBorder('A5');
@ -398,6 +515,13 @@ export class ExporterExcel {
allBorder('G5'); allBorder('G5');
allBorder('H5'); allBorder('H5');
allBorder('I5'); allBorder('I5');
allBorder('J5');
allBorder('K5');
allBorder('L5');
allBorder('M5');
allBorder('N5');
allBorder('O5');
allBorder('P5');
cellCenter('A5'); cellCenter('A5');
cellCenter('B5'); cellCenter('B5');
cellCenter('C5'); cellCenter('C5');
@ -407,6 +531,13 @@ export class ExporterExcel {
cellCenter('G5'); cellCenter('G5');
cellCenter('H5'); cellCenter('H5');
cellCenter('I5'); cellCenter('I5');
cellCenter('J5');
cellCenter('K5');
cellCenter('L5');
cellCenter('M5');
cellCenter('N5');
cellCenter('O5');
cellCenter('P5');
ws.getRow(5).font = { ws.getRow(5).font = {
name: TAPi18n.__('excel-font'), name: TAPi18n.__('excel-font'),
size: 12, size: 12,
@ -414,34 +545,46 @@ export class ExporterExcel {
}; };
//add blank row //add blank row
//add card info //add card info
for (const i in jdata.cards) { for (const i in result.cards) {
const jcard = jdata.cards[i]; const jcard = result.cards[i];
//get member info //get member info
let jcmem = ''; let jcmem = '';
for (const j in jcard.members) { for (const j in jcard.members) {
jcmem += jmeml[jcard.members[j]]; jcmem += jmeml[jcard.members[j]];
jcmem += ' '; jcmem += ' ';
} }
//get assignee info
let jcassig = '';
for (const ja in jcard.assignees) {
jcassig += jassigl[jcard.assignees[ja]];
jcassig += ' ';
}
//get card label info //get card label info
let jclabel = ''; let jclabel = '';
for (const jl in jcard.labelIds) { for (const jl in jcard.labelIds) {
jclabel += jlabel[jcard.labelIds[jl]]; jclabel += jlabel[jcard.labelIds[jl]];
jclabel += ' '; jclabel += ' ';
} }
// console.log(jclabel);
//add card detail //add card detail
const t = Number(i) + 1; const t = Number(i) + 1;
ws.addRow().values = [ ws.addRow().values = [
t.toString(), t.toString(),
jcard.title, jcard.title,
jmeml[jcard.userId],
add8hours(jcard.createdAt),
add8hours(jcard.dateLastActivity),
jlist[jcard.listId],
jcmem,
jcard.description, jcard.description,
jmeml[jcard.userId],
addTZhours(jcard.createdAt),
addTZhours(jcard.dateLastActivity),
addTZhours(jcard.receivedAt),
addTZhours(jcard.startAt),
addTZhours(jcard.dueAt),
addTZhours(jcard.endAt),
jlist[jcard.listId],
jcassig,
jcmem,
jclabel, jclabel,
jcard.isOvertime ? 'true' : 'false',
jcard.spentTime,
]; ];
const y = Number(i) + 6; const y = Number(i) + 6;
//ws.getRow(y).height = 25; //ws.getRow(y).height = 25;
@ -454,20 +597,31 @@ export class ExporterExcel {
allBorder(`G${y}`); allBorder(`G${y}`);
allBorder(`H${y}`); allBorder(`H${y}`);
allBorder(`I${y}`); allBorder(`I${y}`);
allBorder(`J${y}`);
allBorder(`K${y}`);
allBorder(`L${y}`);
allBorder(`M${y}`);
allBorder(`N${y}`);
allBorder(`O${y}`);
allBorder(`P${y}`);
cellCenter(`A${y}`); cellCenter(`A${y}`);
ws.getCell(`B${y}`).alignment = { ws.getCell(`B${y}`).alignment = {
wrapText: true, wrapText: true,
}; };
ws.getCell(`H${y}`).alignment = { ws.getCell(`C${y}`).alignment = {
wrapText: true, wrapText: true,
}; };
ws.getCell(`I${y}`).alignment = { ws.getCell(`L${y}`).alignment = {
wrapText: true,
};
ws.getCell(`M${y}`).alignment = {
wrapText: true,
};
ws.getCell(`N${y}`).alignment = {
wrapText: true, wrapText: true,
}; };
} }
// var exporte=new Stream;
workbook.xlsx.write(res).then(function() {}); workbook.xlsx.write(res).then(function() {});
// return exporte;
} }
canExport(user) { canExport(user) {