kukuasir@vip.qq.com 1 year ago
parent
commit
39eb91ad28
8 changed files with 753 additions and 16336 deletions
  1. 208 15894
      package-lock.json
  2. 5 1
      package.json
  3. 6 1
      src/App.vue
  4. 321 269
      src/components/Excel/Export2Excel.js
  5. 51 51
      src/js/common.js
  6. 36 17
      src/js/export.js
  7. 23 0
      src/js/export_excel.js
  8. 103 103
      src/js/merge.js

File diff suppressed because it is too large
+ 208 - 15894
package-lock.json


+ 5 - 1
package.json

@@ -13,8 +13,11 @@
     "core-js": "^3.6.4",
     "element-ui": "^2.15.12",
     "ex-table-column": "^1.1.2",
+    "file-saver": "^2.0.5",
     "v-fit-columns": "^0.2.0",
-    "vue": "^2.6.11"
+    "vue": "^2.6.11",
+    "xlsx": "^0.18.5",
+    "xlsx-style-hzx": "^1.0.8"
   },
   "devDependencies": {
     "@vue/cli-plugin-babel": "~4.3.1",
@@ -23,6 +26,7 @@
     "babel-eslint": "^10.1.0",
     "eslint": "^6.7.2",
     "eslint-plugin-vue": "^6.2.2",
+    "script-loader": "^0.7.2",
     "vue-template-compiler": "^2.6.11"
   },
   "eslintConfig": {

+ 6 - 1
src/App.vue

@@ -45,7 +45,8 @@
 				<el-button v-else type="success" size="small" @click="handleDerive">导出</el-button>
 			</el-form-item>
 		</el-form>
-		<el-table :data="tableData" border :span-method="objectSpanMethod">
+		<el-table :data="tableData" border :span-method="objectSpanMethod" @selection-change="handleSelectionChange">
+			<el-table-column type="selection" width="60" align="center" fixed />
 			<el-table-column label="序号" width="60" align="center" fixed>
 				<template slot-scope="scope">
 					<span>{{ (queryParams.page_index - 1) * queryParams.page_size + scope.$index + 1 }}</span>
@@ -560,6 +561,10 @@ export default {
 				console.log('[args/list]请求错误: ', err);
 			});
 		},
+		/** 多选 */
+		handleSelectionChange(val) {
+			
+		},
 		/** 计算颜色 */
 		getArgsColor(row, prop, action, threshold) {
 			if (action === ">") {

+ 321 - 269
src/components/Excel/Export2Excel.js

@@ -1,270 +1,322 @@
-/* eslint-disable */
-require('script-loader!file-saver'); //For saving files
-require('./Blob.js'); //For binary conversion
-require('script-loader!xlsx/dist/xlsx.core.min'); //xlsx core
-
-function generateArray(table) {
-	var out = [];
-	var rows = table.querySelectorAll('tr');
-	var ranges = [];
-	for (var R = 0; R < rows.length; ++R) {
-		var outRow = [];
-		var row = rows[R];
-		var columns = row.querySelectorAll('td');
-		for (var C = 0; C < columns.length; ++C) {
-			var cell = columns[C];
-			var colspan = cell.getAttribute('colspan');
-			var rowspan = cell.getAttribute('rowspan');
-			var cellValue = cell.innerText;
-			if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;
-
-			//Skip ranges
-			ranges.forEach(function(range) {
-				if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e
-					.c) {
-					for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
-				}
-			});
-
-			//Handle Row Span
-			if (rowspan || colspan) {
-				rowspan = rowspan || 1;
-				colspan = colspan || 1;
-				ranges.push({
-					s: {
-						r: R,
-						c: outRow.length
-					},
-					e: {
-						r: R + rowspan - 1,
-						c: outRow.length + colspan - 1
-					}
-				});
-			};
-
-			//Handle Value
-			outRow.push(cellValue !== "" ? cellValue : null);
-
-			//Handle Colspan
-			if (colspan)
-				for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
-		}
-		out.push(outRow);
-	}
-	return [out, ranges];
-};
-
-function datenum(v, date1904) {
-	if (date1904) v += 1462;
-	var epoch = Date.parse(v);
-	return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
-}
-
-function sheet_from_array_of_arrays(data, opts) {
-	var ws = {};
-	var range = {
-		s: {
-			c: 10000000,
-			r: 10000000
-		},
-		e: {
-			c: 0,
-			r: 0
-		}
-	};
-	for (var R = 0; R != data.length; ++R) {
-		for (var C = 0; C != data[R].length; ++C) {
-			if (range.s.r > R) range.s.r = R;
-			if (range.s.c > C) range.s.c = C;
-			if (range.e.r < R) range.e.r = R;
-			if (range.e.c < C) range.e.c = C;
-			var cell = {
-				v: data[R][C]
-			};
-			if (cell.v == null) continue;
-			var cell_ref = XLSX.utils.encode_cell({
-				c: C,
-				r: R
-			});
-
-			if (typeof cell.v === 'number') cell.t = 'n';
-			else if (typeof cell.v === 'boolean') cell.t = 'b';
-			else if (cell.v instanceof Date) {
-				cell.t = 'n';
-				cell.z = XLSX.SSF._table[14];
-				cell.v = datenum(cell.v);
-			} else cell.t = 's';
-
-			ws[cell_ref] = cell;
-		}
-	}
-	if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
-	return ws;
-}
-
-function Workbook() {
-	if (!(this instanceof Workbook)) return new Workbook();
-	this.SheetNames = [];
-	this.Sheets = {};
-}
-
-function s2ab(s) {
-	var buf = new ArrayBuffer(s.length);
-	var view = new Uint8Array(buf);
-	for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
-	return buf;
-}
-
-export function export_table_to_excel(id) {
-	var theTable = document.getElementById(id);
-	var oo = generateArray(theTable);
-	var ranges = oo[1];
-
-	/* original data */
-	var data = oo[0];
-	var ws_name = "SheetJS";
-	// console.log(data);
-
-	var wb = new Workbook(),
-		ws = sheet_from_array_of_arrays(data);
-
-	/* add ranges to worksheet */
-	// ws['!cols'] = ['apple', 'banan'];
-	ws['!merges'] = ranges;
-
-	/* add worksheet to workbook */
-	wb.SheetNames.push(ws_name);
-	wb.Sheets[ws_name] = ws;
-
-	var wbout = XLSX.write(wb, {
-		bookType: 'xlsx',
-		bookSST: false,
-		type: 'binary'
-	});
-
-	saveAs(new Blob([s2ab(wbout)], {
-		type: "application/octet-stream"
-	}), "test.xlsx")
-}
-
-function formatJson(jsonData) {
-	console.log(jsonData)
-}
-
-export function export_json_to_excel(th, jsonData, defaultTitle) {
-
-	var data = jsonData;
-
-	// 添加标题
-	for (var i = 0; i < th.length; i++) {
-		data[i].unshift([th[i]])
-	}
-
-	// 这里是定义sheet的名称 有几个sheet就加几个
-	var ws_name = [];
-	th.forEach(item => {
-		ws_name.push(item);
-	});
-
-	var wb = new Workbook(),
-		ws = [];
-	//数据转换
-	for (var j = 0; j < th.length; j++) {
-		ws.push(sheet_from_array_of_arrays(data[j]))
-	}
-
-	//生成多个sheet
-	for (var k = 0; k < th.length; k++) {
-		wb.SheetNames.push(ws_name[k])
-		wb.Sheets[ws_name[k]] = ws[k]
-	}
-
-	var wbout = XLSX.write(wb, {
-		bookType: 'xlsx',
-		bookSST: false,
-		type: 'binary'
-	});
-
-	var title = defaultTitle || '列表'
-	saveAs(new Blob([s2ab(wbout)], {
-		type: "application/octet-stream"
-	}), title + ".xlsx");
-}
-
-export function export_json_to_excel_merges({
-	multiHeader = [],
-	header,
-	data,
-	filename,
-	merges = [],
-	autoWidth = true,
-	bookType = 'xlsx'
-} = {}) {
-	filename = filename || 'excel-list'
-	data = [...data]
-	data.unshift(header)
-
-	for (let i = multiHeader.length - 1; i > -1; i--) {
-		data.unshift(multiHeader[i])
-	}
-
-	var wsName = 'SheetJS'
-	var wb = new Workbook()
-	var ws = sheetFromArrayOfArrays(data)
-
-	if (merges.length > 0) {
-		// ws[!merges]:存放一些单元格合并信息,是一个数组,每个数组由包含s和e构成的对象组成,s表示开始,e表示结束,r表示行,c表示列
-		if (!ws['!merges']) ws['!merges'] = []
-		merges.forEach(item => {
-			ws['!merges'].push(XLSX.utils.decode_range(item))
-		})
-	}
-
-	if (autoWidth) {
-		/* 设置worksheet每列的最大宽度 */
-		const colWidth = data.map(row => row.map(val => {
-			/* 先判断是否为null/undefined */
-			if (val == null) {
-				return {
-					'wch': 10
-				}
-			} else if (val.toString().charCodeAt(0) > 255) {
-				/* 再判断是否为中文 */
-				return {
-					'wch': val.toString().length * 2
-				}
-			} else {
-				return {
-					'wch': val.toString().length
-				}
-			}
-		}))
-		/* 以第一行为初始值 */
-		let result = colWidth[0]
-		for (let i = 1; i < colWidth.length; i++) {
-			for (let j = 0; j < colWidth[i].length; j++) {
-				if (result[j] && result[j]['wch'] < colWidth[i][j]['wch']) {
-					result[j]['wch'] = colWidth[i][j]['wch']
-				}
-			}
-		}
-		// ws['!cols']设置单元格宽度, [{'wch': 10},{'wch': 10}] ===> 第一列和第二列设置了宽度
-		ws['!cols'] = result
-	}
-
-	/* add worksheet to workbook */
-	wb.SheetNames.push(wsName)
-	wb.Sheets[wsName] = ws
-
-	var wbout = XLSX.write(wb, {
-		bookType: bookType,
-		bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
-		type: 'binary'
-	})
-	saveAs(
-		new Blob([s2ab(wbout)], {
-			type: 'application/octet-stream'
-		}),
-		`${filename}.${bookType}`
-	)
+/* eslint-disable */
+require('script-loader!file-saver'); //For saving files
+require('./Blob.js'); //For binary conversion
+require('script-loader!xlsx/dist/xlsx.core.min'); //xlsx core
+
+function generateArray(table) {
+	var out = [];
+	var rows = table.querySelectorAll('tr');
+	var ranges = [];
+	for (var R = 0; R < rows.length; ++R) {
+		var outRow = [];
+		var row = rows[R];
+		var columns = row.querySelectorAll('td');
+		for (var C = 0; C < columns.length; ++C) {
+			var cell = columns[C];
+			var colspan = cell.getAttribute('colspan');
+			var rowspan = cell.getAttribute('rowspan');
+			var cellValue = cell.innerText;
+			if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;
+
+			//Skip ranges
+			ranges.forEach(function(range) {
+				if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e
+					.c) {
+					for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
+				}
+			});
+
+			//Handle Row Span
+			if (rowspan || colspan) {
+				rowspan = rowspan || 1;
+				colspan = colspan || 1;
+				ranges.push({
+					s: {
+						r: R,
+						c: outRow.length
+					},
+					e: {
+						r: R + rowspan - 1,
+						c: outRow.length + colspan - 1
+					}
+				});
+			};
+
+			//Handle Value
+			outRow.push(cellValue !== "" ? cellValue : null);
+
+			//Handle Colspan
+			if (colspan)
+				for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
+		}
+		out.push(outRow);
+	}
+	return [out, ranges];
+};
+
+function datenum(v, date1904) {
+	if (date1904) v += 1462;
+	var epoch = Date.parse(v);
+	return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
+}
+
+function sheet_from_array_of_arrays(data, opts) {
+	var ws = {};
+	var range = {
+		s: {
+			c: 10000000,
+			r: 10000000
+		},
+		e: {
+			c: 0,
+			r: 0
+		}
+	};
+	for (var R = 0; R != data.length; ++R) {
+		for (var C = 0; C != data[R].length; ++C) {
+			if (range.s.r > R) range.s.r = R;
+			if (range.s.c > C) range.s.c = C;
+			if (range.e.r < R) range.e.r = R;
+			if (range.e.c < C) range.e.c = C;
+			var cell = {
+				v: data[R][C]
+			};
+			if (cell.v == null) continue;
+			var cell_ref = XLSX.utils.encode_cell({
+				c: C,
+				r: R
+			});
+
+			if (typeof cell.v === 'number') cell.t = 'n';
+			else if (typeof cell.v === 'boolean') cell.t = 'b';
+			else if (cell.v instanceof Date) {
+				cell.t = 'n';
+				cell.z = XLSX.SSF._table[14];
+				cell.v = datenum(cell.v);
+			} else cell.t = 's';
+
+			ws[cell_ref] = cell;
+		}
+	}
+	if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
+	return ws;
+}
+
+function Workbook() {
+	if (!(this instanceof Workbook)) return new Workbook();
+	this.SheetNames = [];
+	this.Sheets = {};
+}
+
+function s2ab(s) {
+	var buf = new ArrayBuffer(s.length);
+	var view = new Uint8Array(buf);
+	for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
+	return buf;
+}
+
+export function export_table_to_excel(id) {
+	var theTable = document.getElementById(id);
+	var oo = generateArray(theTable);
+	var ranges = oo[1];
+
+	/* original data */
+	var data = oo[0];
+	var ws_name = "SheetJS";
+	// console.log(data);
+
+	var wb = new Workbook(),
+		ws = sheet_from_array_of_arrays(data);
+
+	/* add ranges to worksheet */
+	// ws['!cols'] = ['apple', 'banan'];
+	ws['!merges'] = ranges;
+
+	/* add worksheet to workbook */
+	wb.SheetNames.push(ws_name);
+	wb.Sheets[ws_name] = ws;
+
+	var wbout = XLSX.write(wb, {
+		bookType: 'xlsx',
+		bookSST: false,
+		type: 'binary'
+	});
+
+	saveAs(new Blob([s2ab(wbout)], {
+		type: "application/octet-stream"
+	}), "test.xlsx")
+}
+
+function formatJson(jsonData) {
+	console.log(jsonData)
+}
+
+export function export_json_to_excel(th, jsonData, defaultTitle) {
+
+	var data = jsonData;
+
+	// 添加标题
+	for (var i = 0; i < th.length; i++) {
+		data[i].unshift([th[i]])
+	}
+
+	// 这里是定义sheet的名称 有几个sheet就加几个
+	var ws_name = [];
+	th.forEach(item => {
+		ws_name.push(item);
+	});
+
+	var wb = new Workbook(),
+		ws = [];
+	//数据转换
+	for (var j = 0; j < th.length; j++) {
+		ws.push(sheet_from_array_of_arrays(data[j]))
+	}
+
+	//生成多个sheet
+	for (var k = 0; k < th.length; k++) {
+		wb.SheetNames.push(ws_name[k])
+		wb.Sheets[ws_name[k]] = ws[k]
+	}
+
+	var wbout = XLSX.write(wb, {
+		bookType: 'xlsx',
+		bookSST: false,
+		type: 'binary'
+	});
+
+	var title = defaultTitle || '列表'
+	saveAs(new Blob([s2ab(wbout)], {
+		type: "application/octet-stream"
+	}), title + ".xlsx");
+}
+
+export function export_json_to_excel_merges({
+	multiHeader = [],
+	header,
+	data,
+	filename,
+	merges = [],
+	autoWidth = true,
+	bookType = 'xlsx'
+} = {}) {
+	/* original data */
+	filename = filename || '列表';
+	data = [...data]
+	data.unshift(header);
+	for (let i = multiHeader.length - 1; i > -1; i--) {
+		data.unshift(multiHeader[i])
+	}
+	
+	var ws_name = "Sheet1";
+	var wb = new Workbook(),
+		ws = sheet_from_array_of_arrays(data);
+	
+	/* add worksheet to workbook */
+	wb.SheetNames.push(ws_name);
+	wb.Sheets[ws_name] = ws;
+	
+	// 单元格样式定义
+	var dataInfo = wb.Sheets[wb.SheetNames[0]];
+	const tableTitleFont = {
+		font: {
+		  name: "微软雅黑",
+		  sz: 18,
+		},
+		alignment: {
+		  horizontal: "center",
+		  vertical: "center",
+		},
+		bold: true
+	}
+	const tableColumnFont = {
+		font: {
+		  name: "微软雅黑",
+		  sz: 11,
+		},
+		alignment: {
+			horizontal: "center",
+			vertical: "center",
+			wrapText: 1,
+		}
+	}
+	dataInfo["A1"].s = tableTitleFont
+	// dataInfo["A2"].s = tableTitleFont
+	// 从第2行开始
+	let regexColumn = /[A-Z]2$/;
+	for (var b in dataInfo) {
+	  if (regexColumn.test(b)) {
+	    dataInfo[b].s = tableColumnFont;
+	  }
+	}
+	
+	// 合并单元格
+	if (merges.length > 0) {
+		if (!ws['!merges']) ws['!merges'] = [];
+		merges.forEach(item => {
+			ws['!merges'].push(XLSX.utils.decode_range(item))
+		})
+	}
+	
+	// 自动计算单元格宽度
+	if (autoWidth) {
+		let colWidths = [];
+		// 计算每一列的所有单元格宽度
+		// 先遍历行
+		data.forEach((row) => {
+			// 列序号
+			let index = 0
+			// 遍历列
+			for (const key in row) {
+				if (colWidths[index] == null) colWidths[index] = []
+				switch (typeof row[key]) {
+					case 'string':
+					case 'number':
+					case 'boolean':
+						colWidths[index].push(getCellWidth(row[key]))
+						break
+					case 'object':
+					case 'function':
+						colWidths[index].push(0)
+						break
+				}
+				index++
+			}
+		})
+		ws['!cols'] = [];
+		colWidths.forEach((widths, index) => {
+			// 计算列头的宽度
+			widths.push(getCellWidth(header[index]))
+			// 设置最大值为列宽
+			ws['!cols'].push({
+				wch: Math.max(...widths)
+			})
+		})
+	}
+	
+	var wbout = XLSX.write(wb, {
+		bookType: bookType,
+		bookSST: false,
+		type: 'binary'
+	});
+	
+	saveAs(new Blob([s2ab(wbout)], {
+		type: "application/octet-stream"
+	}), `${filename}.${bookType}`);
+}
+
+export function getCellWidth(value) {
+	if (value == null) {
+		return 10
+	} else if (value.toString().charCodeAt(0) > 255) {
+		// 判断是否包含中文
+		let length = value.toString().length * 2
+		if (length > 60) {
+			length = length - 40
+			//这里的宽度可以自己设定,在前面设置wrapText: 1可以在单元格内换行
+		}
+		return length + 2
+	} else {
+		return value.toString().length * 1.2
+	}
 }

+ 51 - 51
src/js/common.js

@@ -1,54 +1,54 @@
-export const runStatDict = {
-	0: {
-		label: '离线',
-		color: 'lightgray'
-	},
-	1: {
-		label: '在线',
-		color: 'yellowgreen'
-	},
-	2: {
-		label: '未关联',
-		color: 'lightgray'
-	}
-}
-
-export const runModeDict = {
-	0: {
-		label: '无',
-		color: 'lightgray'
-	},
-	1: {
-		label: '制冷',
-		color: 'darkgreen'
-	},
-	2: {
-		label: '采暖',
-		color: 'orange'
-	},
-	3: {
-		label: '除湿',
-		color: 'rgb(182, 172, 195)'
-	},
-	4: {
-		label: '预热',
-		color: 'yellow'
-	},
-	5: {
-		label: '通风',
-		color: 'rgb(182, 174, 227)'
-	}
-}
-
-export const connectStatDict = {
-	0: {
-		label: '异常',
-		color: 'yellow'
-	},
-	1: {
-		label: '正常',
-		color: 'yellowgreen'
-	}
+export const runStatDict = {
+	0: {
+		label: '离线',
+		color: 'lightgray'
+	},
+	1: {
+		label: '在线',
+		color: 'yellowgreen'
+	},
+	2: {
+		label: '未关联',
+		color: 'lightgray'
+	}
+}
+
+export const runModeDict = {
+	0: {
+		label: '无',
+		color: 'lightgray'
+	},
+	1: {
+		label: '制冷',
+		color: 'darkgreen'
+	},
+	2: {
+		label: '采暖',
+		color: 'orange'
+	},
+	3: {
+		label: '除湿',
+		color: 'rgb(182, 172, 195)'
+	},
+	4: {
+		label: '预热',
+		color: 'yellow'
+	},
+	5: {
+		label: '通风',
+		color: 'rgb(182, 174, 227)'
+	}
+}
+
+export const connectStatDict = {
+	0: {
+		label: '异常',
+		color: 'yellow'
+	},
+	1: {
+		label: '正常',
+		color: 'yellowgreen'
+	}
 }
 
 export const faultDict = {

+ 36 - 17
src/js/export.js

@@ -1,4 +1,4 @@
-import { Export2Excel } from './export_excel.js'
+import { Export2ExcelMerge } from './export_excel.js'
 import { listProjects } from './api'
 import { runStatDict, runModeDict, connectStatDict, faultDict, hexPumpStatDict } from './common.js'
 
@@ -17,19 +17,38 @@ function reset() {
 export function exportToExcel(fn) {
 	reset()
 	_listAllProjects(function(finished) {
-		let defaultFilename = 'LINKSEE-智能报表';
-		let tableDatas = [[
-			'项目名称', '盒子名称', '在线状态', '运行模式', 
+		// Excel文件名
+		let defaultFilename = 'LINKSEE-智能报表'
+		// 多级表头
+		const multiHeader = [[
+			'项目名称', '盒子名称', '在线状态', '运行模式',
+			'主机', '', '', '', '', '',
+			'新风机', '', '', '', '', '',
+			'换热站', '', '', '', '', '', '',
+			'末端', '', '', '', '', '', '', ''
+		]]
+		// 二级表头
+		let header = [
+			'项目名称', '盒子名称', '在线状态', '运行模式',
 			'编号', '通讯状态', '故障', '供水水温(℃)', '回水水温(℃)', '温差',
 			'编号', '通讯状态', '故障', '送风温度(℃)', '送风湿度(%)', '露点(℃)',
 			'编号', '通讯状态', '故障', '供水水温(℃)', '回水水温(℃)', '温差', '水泵状态',
-			'编号', '通讯异常数量', '最低室内温度(℃)', '最低室内湿度(%)', '最低室内露点(℃)', 
-			'最高室内温度(℃)', '最高室内湿度(%)', '最高室内露点(℃)'
-		]]
-		config.rowDatas.forEach(row => {
-			tableDatas.push(row)
+			'编号', '通讯异常数量', '最低室内温度(℃)', '最低室内湿度(%)', '最低室内露点(℃)', '最高室内温度(℃)', '最高室内湿度(%)', '最高室内露点(℃)'
+		]
+		// 合并项
+		const merges = ['A1:A2', 'B1:B2', 'C1:C2', 'D1:D2', 'E1:J1', 'K1:P1', 'Q1:W1', 'X1:AE1']
+		// 数据整理
+		// let tableDatas = []
+		// config.rowDatas.forEach(row => {
+		// 	tableDatas.push(row)
+		// })
+		Export2ExcelMerge({
+			multiHeader, 
+			header: header, 
+			data: config.rowDatas, 
+			filename: defaultFilename, 
+			merges
 		})
-		Export2Excel([], [tableDatas], defaultFilename)
 		fn()
 	})
 }
@@ -111,13 +130,13 @@ function _transferDataToXlsx(projects) {
 	return tableData
 }
 
-// 取最大单机数
-function _calcMaxStandaloneCnt(box) {
-	let hpStandaloneCnt = box.hostCtrl ? box.hostCtrl.length : 0
-	let dhStandaloneCnt = box.newTrendCtrl ? box.newTrendCtrl.length : 0
-	let hexStandaloneCnt = box.hex ? box.hex.length : 0
-	let cbStandalineCnt = box.end ? box.end.length : 0
-	return Math.max(hpStandaloneCnt, dhStandaloneCnt, hexStandaloneCnt, cbStandalineCnt)
+// 取最大单机数
+function _calcMaxStandaloneCnt(box) {
+	let hpStandaloneCnt = box.hostCtrl ? box.hostCtrl.length : 0
+	let dhStandaloneCnt = box.newTrendCtrl ? box.newTrendCtrl.length : 0
+	let hexStandaloneCnt = box.hex ? box.hex.length : 0
+	let cbStandalineCnt = box.end ? box.end.length : 0
+	return Math.max(hpStandaloneCnt, dhStandaloneCnt, hexStandaloneCnt, cbStandalineCnt)
 }
 
 function _getConnectState(val) {

+ 23 - 0
src/js/export_excel.js

@@ -4,3 +4,26 @@ export function Export2Excel(columns, list, title) {
     export_json_to_excel(columns, list, title);
   })
 }
+
+export function Export2ExcelMerge({
+	multiHeader = [],
+	header,
+	data,
+	filename,
+	merges = [],
+	autoWidth = true,
+	bookType = 'xlsx'
+} = {}) {
+	require.ensure([], () => {
+		const { export_json_to_excel_merges } = require('../components/Excel/Export2Excel');
+		export_json_to_excel_merges({
+			multiHeader,
+			header,
+			data,
+			filename,
+			merges,
+			autoWidth: autoWidth,
+			bookType: bookType
+		});
+	})
+}

+ 103 - 103
src/js/merge.js

@@ -1,106 +1,106 @@
-// 展开所有数据
-export function expandAllNodes(projects) {
-	let tableData = []
-	projects.forEach(p => {
-		if (Array.isArray(p.boxList)) {
-			p.boxList.forEach(b => {
-				// 继续判断有多少单机,主机、新风机、换热站、末端单机数量取最大值
-				let maxCnt = _calcMaxStandaloneCnt(b)
-				for (let i = 0; i < maxCnt; i++) {
-					let hpStandalone = b.hostCtrl && i < b.hostCtrl.length ? b.hostCtrl[i] : {}
-					let dhStandalone = b.newTrendCtrl && i < b.newTrendCtrl.length ? b.newTrendCtrl[i] : {}
-					let hexStandalone = b.hex && i < b.hex.length ? b.hex[i] : {}
-					let cbStandalone = b.end && i < b.end.length ? b.end[i] : {}
-					tableData.push({
-						projectId: p.project_auto_id,
-						projectName: p.projectName,
-						boxId: b.box_id,
-						boxName: b.boxName,
-						runStatus: b.runStatus,
-						runMode: b.runMode,
-						hpCnt: b.hostCtrl && b.hostCtrl.length,
-						dhCnt: b.newTrendCtrl && b.newTrendCtrl.length,
-						hexCnt: b.hex && b.hex.length,
-						cbCnt: b.end && b.end.length,
-						maxCnt,
-						...hpStandalone,
-						...dhStandalone,
-						...hexStandalone,
-						...cbStandalone
-					})
-				}
-			})
-		}
-	})
-	return _getStandaloneSpanRows(tableData);
-}
-
-// 合并行数据
-export function mergeTableRows(data, merge) {
-	if (!merge || merge.length === 0) {
-		return data
-	}
-	merge.forEach(m => {
-		const mList = {}
-		let spliceLocation = merge.indexOf(m)
-		data = data.map((v, index) => {
-			const rowVal = v[m]
-			if (mList[rowVal] && mList[rowVal].newIndex === index) {
-				let flag = false
-				let mergeSolve = merge.slice(0, spliceLocation)
-				mergeSolve.slice(0, spliceLocation).forEach(mergeItem => {
-					if (data[index][mergeItem] == data[index - 1][mergeItem]) {
-						flag = true
-					}
-				})
-				if (m == merge[0]) {
-					flag = true
-				}
-				if (flag) {
-					mList[rowVal]["num"]++
-					mList[rowVal]["newIndex"]++
-					data[mList[rowVal]["index"]][m + "-span"].rowspan++
-					v[m + "-span"] = {
-						rowspan: 0,
-						colspan: 0,
-					}
-				} else {
-					mList[rowVal] = {
-						num: 1,
-						index: index,
-						newIndex: index + 1,
-					}
-					v[m + "-span"] = {
-						rowspan: 1,
-						colspan: 1,
-					}
-				}
-			} else {
-				mList[rowVal] = {
-					num: 1,
-					index: index,
-					newIndex: index + 1,
-				}
-				v[m + "-span"] = {
-					rowspan: 1,
-					colspan: 1,
-				}
-			}
-			return v
-		})
-	})
-	return data
-}
-
-// 取最大单机数(最多显示2行)
-function _calcMaxStandaloneCnt(box) {
-	let hpStandaloneCnt = box.hostCtrl ? box.hostCtrl.length : 0
-	let dhStandaloneCnt = box.newTrendCtrl ? box.newTrendCtrl.length : 0
-	let hexStandaloneCnt = box.hex ? box.hex.length : 0
-	// 需求:末端最多显示一行,其他类型设备最多两行。如果其他类型设备超过一行,末端需要合并
-	// 所以就无需考虑末端单机的个数
-	let max = Math.max(hpStandaloneCnt, dhStandaloneCnt, hexStandaloneCnt)
-	return Math.min(2, max)
+// 展开所有数据
+export function expandAllNodes(projects) {
+	let tableData = []
+	projects.forEach((p, index) => {
+		if (Array.isArray(p.boxList)) {
+			p.boxList.forEach(b => {
+				// 继续判断有多少单机,主机、新风机、换热站、末端单机数量取最大值
+				let maxCnt = _calcMaxStandaloneCnt(b)
+				for (let i = 0; i < maxCnt; i++) {
+					let hpStandalone = b.hostCtrl && i < b.hostCtrl.length ? b.hostCtrl[i] : {}
+					let dhStandalone = b.newTrendCtrl && i < b.newTrendCtrl.length ? b.newTrendCtrl[i] : {}
+					let hexStandalone = b.hex && i < b.hex.length ? b.hex[i] : {}
+					let cbStandalone = b.end && i < b.end.length ? b.end[i] : {}
+					tableData.push({
+						projectId: p.project_auto_id,
+						projectName: p.projectName,
+						boxId: b.box_id,
+						boxName: b.boxName,
+						runStatus: b.runStatus,
+						runMode: b.runMode,
+						hpCnt: b.hostCtrl && b.hostCtrl.length,
+						dhCnt: b.newTrendCtrl && b.newTrendCtrl.length,
+						hexCnt: b.hex && b.hex.length,
+						cbCnt: b.end && b.end.length,
+						maxCnt,
+						...hpStandalone,
+						...dhStandalone,
+						...hexStandalone,
+						...cbStandalone
+					})
+				}
+			})
+		}
+	})
+	return _getStandaloneSpanRows(tableData);
+}
+
+// 合并行数据
+export function mergeTableRows(data, merge) {
+	if (!merge || merge.length === 0) {
+		return data
+	}
+	merge.forEach(m => {
+		const mList = {}
+		let spliceLocation = merge.indexOf(m)
+		data = data.map((v, index) => {
+			const rowVal = v[m]
+			if (mList[rowVal] && mList[rowVal].newIndex === index) {
+				let flag = false
+				let mergeSolve = merge.slice(0, spliceLocation)
+				mergeSolve.slice(0, spliceLocation).forEach(mergeItem => {
+					if (data[index][mergeItem] == data[index - 1][mergeItem]) {
+						flag = true
+					}
+				})
+				if (m == merge[0]) {
+					flag = true
+				}
+				if (flag) {
+					mList[rowVal]["num"]++
+					mList[rowVal]["newIndex"]++
+					data[mList[rowVal]["index"]][m + "-span"].rowspan++
+					v[m + "-span"] = {
+						rowspan: 0,
+						colspan: 0,
+					}
+				} else {
+					mList[rowVal] = {
+						num: 1,
+						index: index,
+						newIndex: index + 1,
+					}
+					v[m + "-span"] = {
+						rowspan: 1,
+						colspan: 1,
+					}
+				}
+			} else {
+				mList[rowVal] = {
+					num: 1,
+					index: index,
+					newIndex: index + 1,
+				}
+				v[m + "-span"] = {
+					rowspan: 1,
+					colspan: 1,
+				}
+			}
+			return v
+		})
+	})
+	return data
+}
+
+// 取最大单机数(最多显示2行)
+function _calcMaxStandaloneCnt(box) {
+	let hpStandaloneCnt = box.hostCtrl ? box.hostCtrl.length : 0
+	let dhStandaloneCnt = box.newTrendCtrl ? box.newTrendCtrl.length : 0
+	let hexStandaloneCnt = box.hex ? box.hex.length : 0
+	// 需求:末端最多显示一行,其他类型设备最多两行。如果其他类型设备超过一行,末端需要合并
+	// 所以就无需考虑末端单机的个数
+	let max = Math.max(hpStandaloneCnt, dhStandaloneCnt, hexStandaloneCnt)
+	return Math.min(2, max)
 }
 
 // 计算每条记录末端所占的行数