luckysheettool.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. import {showAlertWin, withDateFormatLength} from "@/utils/cqcy";
  2. import { parseString } from "cron-parser";
  3. import html2canvas from "html2canvas";
  4. function setCellSize(l, e, t, o) {
  5. const {
  6. cs: r,
  7. rs: c
  8. } = l[e][t].mc, n = (l.config && l.config.rowhidden) ? Object.keys(l.config.rowhidden) : [], s = [];
  9. for (let l = 0; l < c; l++) {
  10. let t = e + l;
  11. n.indexOf(String(t)) < 0 && s.push(t)
  12. }
  13. const i = [];
  14. for (let l = 0; l < r; l++) i.push(t + l);
  15. const u = Object.values(o.getRowHeight(s))
  16. .reduce((l, e) => l + e);
  17. return {
  18. w: Object.values(o.getColumnWidth(i))
  19. .reduce((l, e) => l + e),
  20. h: u
  21. }
  22. }
  23. export function insertLuckysheetEChart({
  24. selector: l,
  25. info: e,
  26. sheet: t,
  27. optionData: o,
  28. echarts: r,
  29. luckysheet: c,
  30. $: n,
  31. _self: _self,
  32. flag: flag
  33. }) {
  34. if (!e.option || !t) return;
  35. const [s, i] = e.pos, u = e.className, f = e.option, {
  36. data: _,
  37. visibledatacolumn: d,
  38. visibledatarow: m
  39. } = t, a = _[s][i];
  40. let b = 0,
  41. y = 0,
  42. g = [],
  43. h = [];
  44. if (a.mc) {
  45. if (!String(a.mc.cs) || !String(a.mc.rs)) {
  46. if (_self) {
  47. _self.$message({
  48. message: '无效单元!',
  49. type: 'error'
  50. })
  51. }
  52. return void console.error("无效单元");
  53. }
  54. for (; b < a.mc.rs;) g.push(s + b++);
  55. for (; y < a.mc.cs;) h.push(i + y++)
  56. } else g.push(s), h.push(i);
  57. const p = 0 == i ? 0 : d[i - 1],
  58. v = 0 == s ? 0 : m[s - 1],
  59. j = Object.values(c.getColumnWidth(h))
  60. .reduce((l, e) => l + e, 0),
  61. w = Object.values(c.getRowHeight(g))
  62. .reduce((l, e) => l + e, 0);
  63. if (j < 80 || w < 80) {
  64. if (_self) {
  65. luckysheet.cancelRangeMerge()
  66. showAlertWin(_self, null, '所选单元格不满足宽度大于80(默认情况下至少3格)或者高度大于80(默认情况下至少5格),请调整大小后重试!')
  67. }
  68. return void console.error(`单元[${s},${i}]不满足: width >= 80 && height >= 80,调整大小后重试!`);
  69. }
  70. let x = `<div class="${u} luckysheet-modal-dialog luckysheet-modal-dialog-chart luckysheet-data-visualization-chart" style="width: ${j}px;height: ${w}px;position: absolute;z-index: 1000;left: ${p}px;top: ${v}px;"></div>`;
  71. n(l + " #luckysheet-cell-main").append(x);
  72. n('.'+u).mousedown(function(){return false});
  73. let S = r.init(document.getElementsByClassName(u)[0]);
  74. f.animation = false;
  75. const height = getLegendHeight(j, f.legend.data)
  76. console.log(height)
  77. f.grid.bottom = height + 40
  78. S.on('finished', function() {
  79. // const imgBase = n(`.${u} canvas`)[0].toDataURL('image/png');
  80. // console.log(imgBase);
  81. html2canvas(n(`.${u}`)[0]).then(function(canvas) {
  82. // 将 Canvas 转换为图像(Base64 数据)
  83. const imageBase64 = canvas.toDataURL('image/png');
  84. sessionStorage.setItem(`print_${u}`, JSON.stringify({
  85. src: imageBase64,
  86. addr: toExcelColumn(h[0] + 1) + (g[0] + 1) + ":" + toExcelColumn(h[h.length - 1] + 1) + (g[g.length - 1] + 1)
  87. }));
  88. });
  89. })
  90. S.setOption(f);
  91. let k = S.getConnectedDataURL({
  92. type: "png",
  93. pixelRatio: 1,
  94. backgroundColor: "#ffffff"
  95. });
  96. if (flag) {
  97. // n('.' + u).css('display', 'none')
  98. $('.img-list').css('display', 'none');
  99. c.insertImage(k, {
  100. rowIndex: s,
  101. colIndex: i,
  102. cellSize: setCellSize(o, s, i, c),
  103. success: function () {
  104. console.log("插入成功")
  105. }
  106. })
  107. }
  108. }
  109. export function cellValueFormat(html) {
  110. const d = document.createElement('div')
  111. d.innerHTML = html
  112. const tr = d.getElementsByTagName('tr')
  113. let txt = ''
  114. for (let i = 0; i < tr.length; i++) {
  115. const td = tr[i].getElementsByTagName('td')
  116. for (let j = 0; j < td.length; j++) {
  117. txt += td[j].textContent
  118. if (j < td.length - 1) {
  119. txt += '\t'
  120. }
  121. }
  122. txt += '\r\n'
  123. }
  124. return txt
  125. }
  126. export function toExcelColumn(num) {
  127. let result = '';
  128. while (num > 0) {
  129. const remainder = (num - 1) % 26;
  130. result = String.fromCharCode(65 + remainder) + result;
  131. num = Math.floor((num - 1) / 26);
  132. }
  133. return result;
  134. }
  135. export function toLuckySheetJson(luckySheet) {
  136. let sheet = luckySheet.getSheetData(0);
  137. console.log(sheet)
  138. for (let i = 0; i < sheet.length; i++) {
  139. let row = sheet[i];
  140. for (let j = 0; j < row.length; j++) {
  141. if (!row[j]) {
  142. continue;
  143. }
  144. if (row[j].tb) {
  145. luckysheet.setCellFormat(i, j, 'tb', '0');
  146. }
  147. }
  148. }
  149. }
  150. export function setSheetDatas(tableItemList, luckysheet, type, isGenCountTime, sheData) {
  151. console.log(type)
  152. let arr = initArrays(tableItemList, type, isGenCountTime, sheData)
  153. console.log("A1:" + toExcelColumn(arr[0].length) + arr.length)
  154. setTimeout(function () {
  155. // luckysheet.insertColumn(arr[0].length)
  156. // luckysheet.insertRow(arr.length)
  157. luckysheet.setRangeValue(arr, {range: "A1:" + toExcelColumn(arr[0].length) + arr.length})
  158. },100)
  159. }
  160. Array.min = function(array) {
  161. return Math.min.apply(Math, array)
  162. }
  163. // 最大值
  164. Array.max = function (array) {
  165. return Math.max.apply(Math, array)
  166. }
  167. function initArrays(tableItemList, type, isGenCountTime, sheData) {
  168. // 纵向 reportTableType = 1
  169. let arr = {}
  170. let yAdd = 0;
  171. let xAdd = 0;
  172. let valueTimeList = null;
  173. let startTimes = [];
  174. let endTimes = [];
  175. for (let i = 0; i < tableItemList.length; i++) {
  176. let tableItem = tableItemList[i];
  177. let standby = JSON.parse(tableItem.standby)
  178. let fieldType = standby.fieldType ? standby.fieldType: 2
  179. let valueList = tableItem.valueList ?
  180. tableItem.valueList.split(",") : [];
  181. let xAxis = tableItem.xaxis;
  182. let yAxis = tableItem.yaxis;
  183. let xAxis2 = tableItem.yaxis;
  184. let yAxis2 = tableItem.xaxis;
  185. if (fieldType == 1) {
  186. for (var j = 0; j < valueList.length; j++) {
  187. arr[(yAxis2 + j)+ "_" + xAxis2] = valueList[j]
  188. }
  189. } else {
  190. for (var j = 0; j < valueList.length; j++) {
  191. arr[xAxis + "_" + (yAxis + j)] = valueList[j]
  192. }
  193. }
  194. if (i == 0 && (type == 2 || type == 4)) {
  195. valueTimeList = tableItem.valueTimeList
  196. ? tableItem.valueTimeList.split(",")
  197. : [];
  198. valueTimeList = withDateFormatLength(valueTimeList);
  199. yAdd = yAxis2
  200. }
  201. if (type == 5 || type == 6) {
  202. yAdd = yAxis2
  203. if (i == 0) {
  204. xAdd = xAxis2
  205. }
  206. let valueTimeList = tableItem.valueTimeList
  207. ? tableItem.valueTimeList.split(",")
  208. : [];
  209. valueTimeList = withDateFormatLength(valueTimeList);
  210. if (tableItem.timeItemType == 0) {
  211. // 开始时间
  212. startTimes = withDateFormatLength(valueTimeList);
  213. }
  214. if (tableItem.timeItemType == 1) {
  215. // 结束时间
  216. endTimes = withDateFormatLength(valueTimeList);
  217. }
  218. }
  219. }
  220. let x = 0;
  221. let y = 0;
  222. for (let key in arr) {
  223. let str = key.split("_");
  224. if (y < parseInt(str[0])) {
  225. y = parseInt(str[0])
  226. }
  227. if (x < parseInt(str[1])) {
  228. x = parseInt(str[1])
  229. }
  230. }
  231. let aIndex = isGenCountTime == 1 ? 1: 0;
  232. let array = []
  233. console.log(sheData)
  234. for (var i = 0; i < sheData.length; i++) {
  235. let row = sheData[i]
  236. for (var j = 0; j < row.length; j++) {
  237. if (arr[i + "_" + j]) {
  238. row[j] = (arr[i + "_" + j])
  239. } else {
  240. if (j == yAdd - 1 && (type == 2 || type == 4)) {
  241. if (i >= yAdd) {
  242. row[j] = (valueTimeList[i - yAdd])
  243. } else {
  244. row[j] = changeValStr(row[j])
  245. }
  246. } else if (type == 5 || type == 6) {
  247. if (i >= yAdd) {
  248. if (j == xAdd - 3 - aIndex) {
  249. // 序号列
  250. row[j] = (i - yAdd < startTimes.length ? i - yAdd + 1 : "")
  251. } else if (j == xAdd - 2 - aIndex) {
  252. // 开始时间
  253. row[j] = (i - yAdd < startTimes.length ? startTimes[i - yAdd] : "")
  254. } else if (j == xAdd - 1 - aIndex) {
  255. // 开始时间
  256. row[j] = (i - yAdd < endTimes.length ? endTimes[i - yAdd] : "")
  257. } else if(isGenCountTime == 1 && j == xAdd - 1 && row[j - 2] && row[j - 1]) {
  258. // 计算时间
  259. const time = calculateMinutes(row[j - 2], row[j - 1]);
  260. row[j] = (time)
  261. } else {
  262. row[j] = changeValStr(row[j])
  263. }
  264. } else {
  265. row[j] = changeValStr(row[j])
  266. }
  267. } else {
  268. row[j] = changeValStr(row[j])
  269. }
  270. }
  271. }
  272. array.push(row)
  273. }
  274. console.log(array)
  275. return array
  276. }
  277. function calculateMinutes(time1, time2) {
  278. // 将时间字符串转换为Date对象
  279. let date1 = new Date(time1);
  280. let date2 = new Date(time2);
  281. // 计算时间差(以毫秒为单位)
  282. let diffInMilliseconds = Math.abs(date2.getTime() - date1.getTime());
  283. // 将时间差转换为分钟
  284. let minutes = Math.floor(diffInMilliseconds / 1000 / 60);
  285. return minutes;
  286. }
  287. function changeValStr(str) {
  288. if (str) {
  289. if ((str + "").startsWith("${")) {
  290. return "";
  291. } else {
  292. if (str.v && str.v.startsWith("${")) {
  293. return "";
  294. } else {
  295. if (JSON.stringify(str).startsWith("${")) {
  296. return "";
  297. }
  298. }
  299. }
  300. return str;
  301. } else {
  302. return str;
  303. }
  304. }
  305. function getLegendHeight(clazzw, data){
  306. var height =0;
  307. var legend = [];
  308. console.log('legend',legend);
  309. //主算法,将legend中的设置渲染为DOM元素,用dom元素的宽高来模拟legend组件在echarts内部的高度
  310. var icongap = 5;//legend图形左右两边各有5个px的间隔
  311. var left = 10,right = 10;
  312. //计算legend组件的可用宽度
  313. var chartWidth = legend.width||clazzw-left-right;
  314. console.log(chartWidth)
  315. //legend的padding
  316. var padding = legend.padding || 0;
  317. if($.isArray(padding)) padding = padding.join('px ')+'px';
  318. else padding+='px';
  319. //每个legend item之间的间隙(包括水平和垂直)
  320. var itemGap = 5;
  321. //创建一个不可见的模拟盒子
  322. var $legendbox = $('<div class="legend-simulate-box"></div>').css({
  323. width: (chartWidth+itemGap) +'px',
  324. padding: padding,
  325. 'line-height': '1',
  326. 'box-sizing': 'border-box',
  327. overflow: 'hidden',
  328. 'position': 'absolute',
  329. 'z-index': '-1',
  330. 'opacity': '0',
  331. 'filter': 'alpha(opacity=0)',
  332. '-ms-filter': 'alpha(opacity=0)'
  333. }).appendTo('body');
  334. //模拟绘制单个legend item
  335. var itemHeight = 14,itemWidth = 25;
  336. console.log('itemHeight',itemHeight);
  337. if(itemHeight%2!=0) itemHeight++;
  338. if(itemWidth%2!=0) itemWidth++;
  339. var fontSize = 12;
  340. var fontWeight = 'normal';
  341. $.each(data,function(i,name){
  342. var $icon = $('<span></span>').css({
  343. display: 'inline-block',
  344. padding: '0 '+icongap+'px',
  345. 'box-sizing': 'content-box',
  346. 'width': itemWidth+'px',
  347. 'height': itemHeight+'px'
  348. });
  349. var $item = $('<div></div>').css({
  350. 'display': 'inline-block',
  351. 'float': 'left',
  352. 'margin-right': itemGap+'px',
  353. 'margin-bottom': itemGap+'px',
  354. 'font-size': fontSize+'px',
  355. 'font-weight': fontWeight,
  356. 'max-width': chartWidth - 30,
  357. 'white-space': 'nowrap',
  358. 'text-overflow': 'clip'
  359. }).append($icon).append(name).appendTo($legendbox);
  360. });
  361. //得到模拟高度
  362. console.log('legendbox',$legendbox.innerHeight());
  363. console.log('itemGap',itemGap);
  364. height = $legendbox.innerHeight()-itemGap;
  365. //善后工作
  366. $legendbox.remove();
  367. return height;
  368. }