現時須要開發一個Excel下載功能express
後臺有一個API,負責接收傳入的JSON文件,生成帶圖片的Excel文件在臨時目錄(生成Excel使用npm exceljs庫),並將文件經過Router返回npm
前臺Client調用後臺API,讀取文件流生成Excel文件下載json
API生成Excel文件代碼api
const getLinePlanExcelJson = (data) => { // let workBook; //workbook properties var workBook = new exceljs.Workbook(); workBook.creator = 'Esquel LPD Project'; workBook.lastModifiedBy = 'Esquel LPD Project'; workBook.created = new Date(); workBook.modified = new Date(); return new Promise((resolve, reject) => { if (typeof (data.customerCode) === 'undefined' || typeof (data.linePlanProducts) === 'undefined') { reject(new Error('{"Error Message":"incorrect format."}')); } //base var let mc_productStyles = data.productStyles; let mc_productFabrics = data.productFabrics; let mc_productTrims = data.productTrims; //--------------------------- let workSheet_name = "LinePlan"; // create worksheet let workSheet = workBook.addWorksheet(workSheet_name, { // properties: { // tabColor: { argb: 'FFC0000' } // }, // pageSetup: { // paperSize: 50, // orientation: 'landscape' // } }); //setting header title let headerTitleArray = config.LinePlan.columns; let headerColumns = []; for (let headerIndex = 0; headerIndex < headerTitleArray.length; headerIndex++) { headerColumns.push({ header: headerTitleArray[headerIndex].title, key: 'col' + headerIndex, width: headerTitleArray[headerIndex].width }); } //setting header to worksheet workSheet.columns = headerColumns; //setting auto filter workSheet.autoFilter = { from: 'A1', to: 'AA1' } //---------------------------------------------------- //col index let colIndex = 1; let rowIndex = 1; data.linePlanProducts.map((linePlanProduct) => { //get style data let find_StyleData = _.where(mc_productStyles, { styleID: linePlanProduct.productID }); linePlanProduct.productMaterialConfigs.map((colorway) => { //reset col index colIndex = 1; let newrow = []; //style id--------------------------------------- newrow[colIndex] = linePlanProduct.productID; //style image--------------------------------------- colIndex++; newrow[colIndex] = find_StyleData[0].imageURL ? find_StyleData[0].imageURL : ''; // cell = { v: find_StyleData[0].imageURL, t: 's', l: { Target: find_StyleData[0].imageURL, Tooltip: linePlanProduct.productID } }; // //colorway body fabirc image--------------------------------------- colIndex++; newrow[colIndex] = colorway.PrimaryFabricImageUrl ? colorway.PrimaryFabricImageUrl : ''; // cell = { v: colorway.PrimaryFabricImageUrl, t: 's', l: { Target: colorway.PrimaryFabricImageUrl, Tooltip: colorway.primaryFabricID } }; //matching--------------------------------------- colIndex++; //colorway body fabirc item code--------------------------------------- colIndex++; newrow[colIndex] = colorway.primaryFabricID; //colorway body fabirc info--------------------------------------- let find_FabricData = _.where(mc_productFabrics, { fabricID: colorway.primaryFabricID }); colIndex++; newrow[colIndex] = find_FabricData[0].longDescriptions[1] ? find_FabricData[0].longDescriptions[1] : ''; // //colorway body fabirc content--------------------------------------- colIndex++; newrow[colIndex] = find_FabricData[0].longDescriptions[2] ? find_FabricData[0].longDescriptions[2] : ''; // //fabric width--------------------------------------- colIndex++; newrow[colIndex] = find_FabricData[0].longDescriptions[4] ? find_FabricData[0].longDescriptions[4] : ''; //button colour--------------------------------------- colIndex++; // // let find_trims = _.where(colorway.appliedAuxiliaries, { auxiliaryType: 'T' }); // // let find_fabrics = _.where(colorway.appliedAuxiliaries, { auxiliaryType: 'F' }); // //button1 item code--------------------------------------- colIndex++; newrow[colIndex] = colorway.appliedAuxiliaries[0] ? colorway.appliedAuxiliaries[0].auxiliaryID : ''; //button2 item code--------------------------------------- colIndex++; newrow[colIndex] = colorway.appliedAuxiliaries[1] ? colorway.appliedAuxiliaries[1].auxiliaryID : ''; //button3 item code--------------------------------------- colIndex++; newrow[colIndex] = colorway.appliedAuxiliaries[2] ? colorway.appliedAuxiliaries[2].auxiliaryID : ''; //button4 item code--------------------------------------- colIndex++; newrow[colIndex] = colorway.appliedAuxiliaries[3] ? colorway.appliedAuxiliaries[3].auxiliaryID : ''; // //style fit--------------------------------------- colIndex++; newrow[colIndex] = linePlanProduct.fitName; //style collection--------------------------------------- colIndex++; newrow[colIndex] = linePlanProduct.collectionName ? linePlanProduct.collectionName + ' Collection' : ''; //style gender--------------------------------------- colIndex++; newrow[colIndex] = linePlanProduct.gender; //fabric--------------------------------------- colIndex++; newrow[colIndex] = find_FabricData[0].longDescriptions[0] ? find_FabricData[0].longDescriptions[0] : ''; //style collar--------------------------------------- colIndex++; newrow[colIndex] = linePlanProduct.collarName; //style sleeve--------------------------------------- colIndex++; newrow[colIndex] = linePlanProduct.sleeveName; //style cuff--------------------------------------- colIndex++; newrow[colIndex] = linePlanProduct.cuffName; //style washing--------------------------------------- colIndex++; //style pocket--------------------------------------- colIndex++; newrow[colIndex] = linePlanProduct.pocketName; //colorway body pattern pocket--------------------------------------- colIndex++; newrow[colIndex] = colorway.bodyPattern; //colorway body color name--------------------------------------- colIndex++; //colorway name--------------------------------------- colIndex++; newrow[colIndex] = colorway.colorway; //colorway plu--------------------------------------- colIndex++; newrow[colIndex] = colorway.pluNumber //colorway market--------------------------------------- let marketArray = []; colorway.markets.map((market) => { marketArray.push(market.marketCode); }); colIndex++; newrow[colIndex] = marketArray ? marketArray.join('/') : ''; workSheet.addRow(newrow).commit(); //setting row style // let row = workSheet.lastRow; // row.height = 120; rowIndex++; }); }); //need retry array let all_needProcessCellArray = []; let firsttime_faild_cellArray = []; let secendtime_faild_cellArray = []; //define add image function let fetchImageFun = function (workSheet, cell, CellArray) { return new Promise((resolve, reject) => { if (!cell.value) resolve('no'); // let starttime = new Date(); request.get({ url: cell.value, encoding: null, timeout: 10000 }, function (error, response, body) { if (error) { // let endtime = new Date(); // console.log(cell.address + ' Faild ' + starttime + ' ' + endtime); if (CellArray) CellArray.push(cell); resolve('err'); } if (body) { if (response.statusCode === 500) { console.log('load image error from url:' + cell.value); } else if (response.statusCode === 404) { console.log('can not load image from url:' + cell.value); } //get image let imageObject = workBook.addImage({ buffer: new Buffer(body), extension: response.headers["content-type"] }); //add image to cell let imageCellName = cell.address + ':' + cell.address; workSheet.addImage(imageObject, imageCellName); //clear value cell.value = ''; resolve('ok'); } }); }); } let functionArray = []; //add image to cell workSheet.eachRow({ includeEmpty: true }, function (row, rowNumber) { if (rowNumber > 1) { row.height = 150; row.eachCell({ includeEmpty: true }, function (cell, colNumber) { cell.alignment = { vertical: 'top', horizontal: 'left' }; // cell.border = { // top: { style: 'thin', color: { argb: 'FFFFFF00' } }, // left: { style: 'thin', color: { argb: 'FFFFFF00' } }, // bottom: { style: 'thin', color: { argb: 'FFFFFF00' } }, // right: { style: 'thin', color: { argb: 'FFFFFF00' } } // }; //add image is work if (colNumber === 2 || colNumber === 3) { all_needProcessCellArray.push(cell); } }); } }); all_needProcessCellArray.forEach((getCell) => { functionArray.push(fetchImageFun(workSheet, getCell, firsttime_faild_cellArray)); }); //add function to array //resolve function Promise.all(functionArray) .then((result) => { if (firsttime_faild_cellArray) { firsttime_faild_cellArray.forEach((getCell) => { functionArray.push(fetchImageFun(workSheet, getCell, secendtime_faild_cellArray)); }); //first time retry Promise.all(functionArray) .then((result2) => { if (secendtime_faild_cellArray) { secendtime_faild_cellArray.forEach((getCell) => { functionArray.push(fetchImageFun(workSheet, getCell)); }); //secend time retry Promise.all(functionArray) .then((result2) => { resolve(workBook); }).catch((err3) => { reject(null); }); } else { resolve(workBook); } }).catch((err2) => { reject(null); }); } else { resolve(workBook); } }).catch((err) => { reject(null); }) }); }
API路由代碼app
let express = require('express'); let genCSV = require("./genCSV.js"); let exceljs = require('exceljs'); let util = require('util'); let fs = require('fs'); let router = express.Router(); //post data to router router.post('/', function (req, res, next) { genCSV.getLinePlanExcelJson(req.body) .then((excelObject) => { // throw new Error('this is test error'); //return to client let fileName = 'LinePlan-' + req.body.linePlanID + '.xlsx'; let filePath = './public/temp/' + fileName; if (fs.existsSync(filePath)) { fs.unlink(filePath); } excelObject.xlsx.writeFile(filePath, { bookType: 'xlsx', bookSST: false, type: 'buffer' }) .then(() => { res.status(200).download(filePath, fileName); }).catch((err) => { throw err }); }) .catch((err) => { res.status(500).end('{"err":"' + err.message + '"}'); }); }); module.exports = router;
前臺Client調用代碼ide
fetchMethodExcel: function (apiName, method, requestObject, requestBody, callback) { fetch3(this.apiExport(apiName, requestObject), { // method: method, method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestBody), }) .then((data) => { if (data.status === 500) { throw new Error('Explort LinePlan API Error'); } else if (data.status === 404) { throw new Error('Can Not Found Explort LinePlan API'); } return data.blob(); }) .then((blob) => { let a = document.createElement('a'); let url = window.URL.createObjectURL(blob); let filename = 'LinePlan-' + requestBody.linePlanID + '.xlsx'; a.href = url; a.download = filename; a.click(); window.URL.revokeObjectURL(url); callback(); }) .catch(err => { callback(err); }); }
運行結果是post
可是下載的文件倒是沒法打開的,一直說是文件有內容有問題,嘗試恢復好久都沒有返回。fetch
解除鎖定後,能夠正常打開文件了ui