pm_share.js 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Zhong
  6. * @date 2018/6/28
  7. * @version
  8. */
  9. const pmShare = (function () {
  10. const spreadDom = $('#shareSpread');
  11. let spreadObj = {workBook: null, sheet: null};
  12. //项目分享类型,由别人分享给自己的,和自己分享给别人的
  13. const shareType = {receive: 'receive', shareTo: 'shareTo'};
  14. //操作类型
  15. const oprType = {copy: 'copy', cancel: 'cancel'};
  16. let tree = null;
  17. const treeCol = 0;
  18. const treeSetting = {
  19. tree: {
  20. id: 'ID',
  21. pid: 'ParentID',
  22. nid: 'NextSiblingID',
  23. rootId: -1,
  24. autoUpdate: false
  25. }
  26. };
  27. const headers = [
  28. {name: '工程列表', dataCode: 'name', width: 300, rateWidth: 0.55, vAlign: 'center', hAlign: 'left'},
  29. {name: '由...分享', dataCode: 'from', width: 100, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},
  30. {name: '拷贝工程', dataCode: 'copy', width: 100, rateWidth: 0.075, vAlign: 'center', hAlign: 'left'},
  31. {name: '清除', dataCode: 'cancel', width: 100, rateWidth: 0.075, vAlign: 'center', hAlign: 'left'},
  32. {name: '工程造价', dataCode: 'engineeringCost', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  33. {name: '分部分项合计', dataCode: 'subEngineering', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  34. {name: '措施项目合计', dataCode: 'measure', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  35. {name: '其他项目合计', dataCode: 'other', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  36. {name: '规费', dataCode: 'charge', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  37. {name: '税金', dataCode: 'tax', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  38. {name: '占造价比例(%)', dataCode: 'rate', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  39. {name: '建筑面积', dataCode: 'buildingArea', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  40. {name: '单方造价', dataCode: 'perCost', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  41. {name: '工程专业', dataCode: 'feeStandardName', width: 100, vAlign: 'center', hAlign: 'left'},
  42. ];
  43. const spreadOpts = {
  44. workBook: {
  45. tabStripVisible: false,
  46. allowContextMenu: false,
  47. allowCopyPasteExcelStyle : false,
  48. allowExtendPasteRange: false,
  49. allowUserDragDrop : false,
  50. allowUserDragFill: false,
  51. scrollbarMaxAlign : true
  52. },
  53. sheet: {
  54. isProtected: true,
  55. protectionOptions: {allowResizeRows: true, allowResizeColumns: true},
  56. clipBoardOptions: GC.Spread.Sheets.ClipboardPasteOptions.values
  57. }
  58. };
  59. const spreadEvents = {
  60. SelectionChanging: function (sender, info) {
  61. initSelection(info.newSelections[0], info.oldSelections[0]);
  62. }
  63. };
  64. //设置选中行底色
  65. //@param
  66. function setSelStyle(sel, backColor,sheet) {
  67. sel.row = sel.row === -1 ? 0 : sel.row;
  68. renderSheetFunc(sheet, function () {
  69. let style = projTreeObj.getSelStyle(backColor);
  70. for(let i = 0; i < sel.rowCount; i++){
  71. let row = i + sel.row;
  72. sheet.setStyle(row, -1, style);
  73. }
  74. });
  75. }
  76. //初始化焦点
  77. //@param {Object}newSel {Object}oldSel @return {void}
  78. function initSelection(newSel, oldSel = null) {
  79. let node = tree.items[newSel.row];
  80. tree.selected = node;
  81. shareSeleted = node;
  82. //恢复底色
  83. if(oldSel){
  84. setSelStyle(oldSel, projTreeObj.setting.style.defalutBackColor, spreadObj.sheet);
  85. }
  86. //设置选中行底色
  87. if(newSel){
  88. setSelStyle(newSel, projTreeObj.setting.style.selectedColor, spreadObj.sheet);
  89. }
  90. }
  91. //渲染时方法,停止渲染
  92. //@param {Object}sheet {Function}func @return {void}
  93. function renderSheetFunc(sheet, func){
  94. sheet.suspendEvent();
  95. sheet.suspendPaint();
  96. if(func){
  97. func();
  98. }
  99. sheet.resumeEvent();
  100. sheet.resumePaint();
  101. }
  102. //设置表选项
  103. //@param {Object}workBook {Object}opts @return {void}
  104. function setSpreadOptions (workBook, opts) {
  105. for(let opt in opts.workBook){
  106. workBook.options[opt] = opts.workBook[opt];
  107. }
  108. for(let opt in opts.sheet){
  109. workBook.getActiveSheet().options[opt] = opts.sheet[opt];
  110. }
  111. }
  112. //建表头
  113. //@param {Object}sheet {Array}headers @return {void}
  114. function buildHeader(sheet, headers) {
  115. let fuc = function () {
  116. sheet.setColumnCount(headers.length);
  117. sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
  118. //let spreadWidth = getWorkBookWidth();
  119. for(let i = 0, len = headers.length; i < len; i++){
  120. sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
  121. if(headers[i].formatter){
  122. sheet.setFormatter(-1, i, headers[i].formatter);
  123. }
  124. if(headers[i].dataCode === oprType.copy){
  125. //合并列
  126. sheet.addSpan(0, i, 1, 2, GC.Spread.Sheets.SheetArea.colHeader);
  127. sheet.setValue(0, i, '操作', GC.Spread.Sheets.SheetArea.colHeader);
  128. continue;
  129. }
  130. if(headers[i].dataCode === '' || headers[i].dataCode === 'feeRateFile_delete'){
  131. continue;
  132. }
  133. sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
  134. sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
  135. sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
  136. }
  137. };
  138. renderSheetFunc(sheet, fuc);
  139. }
  140. //表监听事件
  141. //@param {Object}workBook @return {void}
  142. function bindEvent(workBook, events) {
  143. if(Object.keys(events).length === 0){
  144. return;
  145. }
  146. const Events = GC.Spread.Sheets.Events;
  147. for(let event in events){
  148. workBook.bind(Events[event], events[event]);
  149. }
  150. }
  151. //建表
  152. //
  153. function buildSheet(){
  154. spreadObj.workBook = new GC.Spread.Sheets.Workbook(spreadDom[0], {sheetCount: 1});
  155. sheetCommonObj.spreadDefaultStyle(spreadObj.workBook);
  156. spreadObj.sheet = spreadObj.workBook.getActiveSheet();
  157. setSpreadOptions(spreadObj.workBook, spreadOpts);
  158. bindEvent(spreadObj.workBook, spreadEvents);
  159. buildHeader(spreadObj.sheet, headers);
  160. //全表不可编辑
  161. spreadObj.sheet.getRange(-1, -1, -1, -1).locked(true);
  162. }
  163. //此项目是否可以拷贝
  164. //@param {String}userID {Object}project @return {Boolean}
  165. function isAllowCopy(userID, project){
  166. for(let shareData of project.shareInfo){
  167. if(shareData.userID === userID){
  168. return shareData.allowCopy;
  169. }
  170. }
  171. return false;
  172. }
  173. //
  174. //
  175. function getTreeNodeCell(tree){
  176. let indent = 20;
  177. let levelIndent = -5;
  178. let halfBoxLength = 5;
  179. let halfExpandLength = 3;
  180. let imgWidth = 18;
  181. let imgHeight = 14;
  182. let TreeNodeCellType = function () {
  183. };
  184. TreeNodeCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
  185. TreeNodeCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
  186. if (style.backColor) {
  187. ctx.save();
  188. ctx.fillStyle = style.backColor;
  189. ctx.fillRect(x, y, w, h);
  190. ctx.restore();
  191. } else {
  192. ctx.clearRect(x, y, w, h);
  193. }
  194. let drawLine = function (canvas, x1, y1, x2, y2, color) {
  195. ctx.save();
  196. ctx.translate(0.5, 0.5);
  197. ctx.beginPath();
  198. ctx.moveTo(x1, y1);
  199. ctx.lineTo(x2, y2);
  200. ctx.strokeStyle = color;
  201. ctx.stroke();
  202. ctx.restore();
  203. };
  204. let drawExpandBox = function (ctx, x, y, w, h, centerX, centerY, expanded) {
  205. let rect = {}, h1, h2, offset = 1;
  206. rect.top = centerY - halfBoxLength;
  207. rect.bottom = centerY + halfBoxLength;
  208. rect.left = centerX - halfBoxLength;
  209. rect.right = centerX + halfBoxLength;
  210. if (rect.left < x + w) {
  211. rect.right = Math.min(rect.right, x + w);
  212. ctx.save();
  213. ctx.translate(0.5, 0.5);
  214. ctx.strokeStyle = 'black';
  215. ctx.beginPath();
  216. ctx.moveTo(rect.left, rect.top);
  217. ctx.lineTo(rect.left, rect.bottom);
  218. ctx.lineTo(rect.right, rect.bottom);
  219. ctx.lineTo(rect.right, rect.top);
  220. ctx.lineTo(rect.left, rect.top);
  221. ctx.stroke();
  222. ctx.fillStyle = 'white';
  223. ctx.fill();
  224. ctx.restore();
  225. // Draw Horizontal Line
  226. h1 = centerX - halfExpandLength;
  227. h2 = Math.min(centerX + halfExpandLength, x + w);
  228. if (h2 > h1) {
  229. drawLine(ctx, h1, centerY, h2, centerY, 'black');
  230. }
  231. // Draw Vertical Line
  232. if (!expanded && (centerX < x + w)) {
  233. drawLine(ctx, centerX, centerY - halfExpandLength, centerX, centerY + halfExpandLength, 'black');
  234. }
  235. }
  236. }
  237. let node = tree.items[options.row];
  238. let showTreeLine = true;
  239. if (!node) { return; }
  240. let centerX = Math.floor(x) + node.depth() * indent + node.depth() * levelIndent + indent / 2;
  241. let x1 = centerX + indent / 2;
  242. let centerY = Math.floor((y + (y + h)) / 2);
  243. let y1;
  244. // Draw Sibling Line
  245. if (showTreeLine) {
  246. // Draw Horizontal Line
  247. if (centerX < x + w) {
  248. drawLine(ctx, centerX, centerY, Math.min(x1, x + w), centerY, 'gray');
  249. let img;
  250. if(node.data.projType === projectType.folder){
  251. img = document.getElementById('folder_open_pic');
  252. imgWidth = 15;
  253. }
  254. else if(node.data.projType === projectType.project){
  255. img = document.getElementById('proj_pic');
  256. imgWidth = 18;
  257. }
  258. else if(node.data.projType === projectType.engineering){
  259. img = document.getElementById('eng_pic');
  260. imgWidth = 14;
  261. }
  262. else if(node.data.projType === projectType.tender){
  263. img = document.getElementById('tender_pic');
  264. imgWidth = 14;
  265. }
  266. ctx.drawImage(img, centerX+indent/2+3, centerY - 7, imgWidth,imgHeight);
  267. }
  268. // Draw Vertical Line
  269. if (centerX < x + w) {
  270. y1 = node.isLast() ? centerY : y + h;
  271. if (node.isFirst() && !node.parent.parent) {
  272. drawLine(ctx, centerX, centerY, centerX, y1, 'gray');
  273. } else {
  274. drawLine(ctx, centerX, y, centerX, y1, 'gray');
  275. }
  276. }
  277. }
  278. // Draw Expand Box
  279. if (node.children.length > 0) {
  280. drawExpandBox(ctx, x, y, w, h, centerX, centerY, node.expanded);
  281. }
  282. // Draw Parent Line
  283. if (showTreeLine) {
  284. var parent = node.parent, parentCenterX = centerX - indent - levelIndent;
  285. while (parent.parent) {
  286. if (!parent.isLast()) {
  287. if (parentCenterX < x + w) {
  288. drawLine(ctx, parentCenterX, y, parentCenterX, y + h, 'gray');
  289. }
  290. }
  291. parent = parent.parent;
  292. parentCenterX -= (indent + levelIndent);
  293. }
  294. };
  295. // Draw Text
  296. arguments[2] = x + (node.depth() + 1) * indent + node.depth() * levelIndent + imgWidth + 3;
  297. arguments[4] = w - (node.depth() + 1) * indent - node.depth() * levelIndent - imgWidth - 3;
  298. GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
  299. };
  300. TreeNodeCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
  301. let info = {x: x, y: y, row: context.row, col: context.col, cellStyle: cellStyle, cellRect: cellRect, sheetArea: context.sheetArea};
  302. let node = tree.items[info.row];
  303. let offset = -1;
  304. let centerX = info.cellRect.x + offset + node.depth() * indent + node.depth() * levelIndent + indent / 2;
  305. let text = context.sheet.getText(info.row, info.col);
  306. let value = context.sheet.getValue(info.row, info.col);
  307. let acStyle = context.sheet.getActualStyle(info.row, info.col),
  308. zoom = context.sheet.zoom();
  309. let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: context.sheet, row: info.row, col: info.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
  310. if(info.x > centerX + halfBoxLength && info.x < centerX + halfBoxLength + imgWidth + indent/2+3 + textLength){
  311. info.isReservedLocation = true;
  312. }
  313. return info;
  314. };
  315. TreeNodeCellType.prototype.processMouseDown = function (hitinfo) {
  316. let offset = -1;
  317. let node = tree.items[hitinfo.row];
  318. let centerX = hitinfo.cellRect.x + offset + node.depth() * indent + node.depth() * levelIndent + indent / 2;
  319. let centerY = (hitinfo.cellRect.y + offset + (hitinfo.cellRect.y + offset + hitinfo.cellRect.height)) / 2;
  320. let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
  321. let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col);
  322. let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col),
  323. zoom = hitinfo.sheet.zoom();
  324. let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
  325. //(图标+名字)区域
  326. function withingClickArea(){
  327. return hitinfo.x > centerX + halfBoxLength && hitinfo.x < centerX + halfBoxLength + imgWidth + indent/2+3 + textLength;
  328. }
  329. //点击单位工程
  330. if(node.data.projType === projectType.tender && withingClickArea()){
  331. let newTab = window.open('about:blank');
  332. //打开项目的实际ID
  333. BeforeOpenProject(node.data.actualTreeInfo.ID, {'fullFolder': GetFullFolder(node.parent)}, function () {
  334. let mainUrl = `/main?project=${node.data.actualTreeInfo.ID}`;
  335. CommonAjax.get(mainUrl, [], function () {
  336. newTab.location.href = mainUrl;
  337. });
  338. });
  339. }
  340. if (!node || node.children.length === 0) { return; }
  341. if (hitinfo.x > centerX - halfBoxLength && hitinfo.x < centerX + halfBoxLength && hitinfo.y > centerY - halfBoxLength && hitinfo.y < centerY + halfBoxLength) {
  342. node.setExpanded(!node.expanded);
  343. TREE_SHEET_HELPER.massOperationSheet(hitinfo.sheet, function () {
  344. let iCount = node.posterityCount(), i, child;
  345. for (i = 0; i < iCount; i++) {
  346. child = tree.items[hitinfo.row + i + 1];
  347. hitinfo.sheet.setRowVisible(hitinfo.row + i + 1, child.visible, hitinfo.sheetArea);
  348. }
  349. hitinfo.sheet.invalidateLayout();
  350. });
  351. hitinfo.sheet.repaint();
  352. }
  353. };
  354. TreeNodeCellType.prototype.processMouseMove = function (hitInfo) {
  355. let sheet = hitInfo.sheet;
  356. let div = sheet.getParent().getHost();
  357. let canvasId = div.id + "vp_vp";
  358. let canvas = $(`#${canvasId}`)[0];
  359. //改变鼠标图案
  360. if (sheet && hitInfo.isReservedLocation) {
  361. canvas.style.cursor='pointer';
  362. return true;
  363. }else{
  364. canvas.style.cursor='default';
  365. }
  366. return false;
  367. };
  368. TreeNodeCellType.prototype.processMouseEnter = function (hitinfo) {
  369. let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
  370. let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col);
  371. let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col);
  372. let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col),
  373. zoom = hitinfo.sheet.zoom();
  374. let node = tree.items[hitinfo.row];
  375. let nodeIndent = node ? (node.depth() + 1) * indent + node.depth() * levelIndent + imgWidth + 3 : 0;
  376. let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
  377. let cellWidth = hitinfo.sheet.getCell(-1, hitinfo.col).width();
  378. if(textLength > cellWidth - nodeIndent){
  379. TREE_SHEET_HELPER.showTipsDiv(text,{pos: {}},hitinfo);
  380. }
  381. };
  382. TreeNodeCellType.prototype.processMouseLeave = function (hitinfo) {
  383. TREE_SHEET_HELPER.tipDiv = 'hide';
  384. if (TREE_SHEET_HELPER._toolTipElement) {
  385. $(TREE_SHEET_HELPER._toolTipElement).hide();
  386. TREE_SHEET_HELPER._toolTipElement = null;
  387. };
  388. TREE_SHEET_HELPER.tipDivCheck();//延时检查:当tips正在show的时候,就调用了hide方法,会导致tips一直存在,所以设置一个超时处理
  389. }
  390. return new TreeNodeCellType();
  391. }
  392. //互动单元格
  393. function getInteractionCell() {
  394. let InteractionCell = function () {
  395. };
  396. InteractionCell.prototype = new GC.Spread.Sheets.CellTypes.Text();
  397. InteractionCell.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
  398. return {
  399. x: x,
  400. y: y,
  401. row: context.row,
  402. col: context.col,
  403. cellStyle: cellStyle,
  404. cellRect: cellRect,
  405. sheetArea: context.sheetArea,
  406. isReservedLocation: true
  407. };
  408. };
  409. InteractionCell.prototype.processMouseDown = function (hitinfo) {
  410. let dataCode = headers[hitinfo.col]['dataCode'];
  411. let node = tree.items[hitinfo.row];
  412. let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
  413. let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col);
  414. let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col),
  415. zoom = hitinfo.sheet.zoom();
  416. let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
  417. if(hitinfo.x - hitinfo.cellRect.x > 0 && hitinfo.x - hitinfo.cellRect.x < textLength){
  418. //由..分享,弹出分享者信息
  419. if(dataCode === 'from'){
  420. if(node.data.shareType === shareType.receive){
  421. $('#userinfo').find('h4').text(node.data.userInfo.name);
  422. $('#userinfo').find('h6').text(node.data.userInfo.company);
  423. let mobileHtml = `<i class="fa fa-tablet"> ${node.data.userInfo.mobile ? node.data.userInfo.mobile : ''}</i>`;
  424. $('#userinfo').find('li:first-child').html(mobileHtml);
  425. let emailHtml = `<i class="fa fa-envelope-o"> ${node.data.userInfo.email ? node.data.userInfo.email : ''}</i>`;
  426. $('#userinfo').find('li:last-child').html(emailHtml);
  427. $('#userinfo').modal('show');
  428. }
  429. }
  430. //分享给
  431. else if(dataCode === 'to'){
  432. if(node.data.shareType === shareType.shareTo){
  433. setShareToModal(node);
  434. $('#shareTo').modal('show');
  435. }
  436. }
  437. //操作
  438. else if(dataCode === oprType.copy){
  439. /* if(node.data.copy === '添加分享'){
  440. $('#sharePhone').val('');
  441. $('#share-info').hide();
  442. $('#share').find('.card').hide();
  443. $('#share').modal('show');
  444. $('#allowCopy').prop('checked', false);
  445. $('#allowCopyHint').hide();
  446. }
  447. else*/
  448. if(node.data.copy === '拷贝工程'){
  449. $('#copyShare').modal('show');
  450. }
  451. }
  452. else if (dataCode === oprType.cancel) {
  453. if (node.data.cancel === '清除') {
  454. let $p = $('<p>').text(`点“确定”按钮,确认清除分享文件 “${node.data.name}”。`);
  455. $('#cancelShare').find('.modal-body').empty();
  456. $('#cancelShare').find('.modal-body').append($p);
  457. $('#cancelShare').modal('show');
  458. }
  459. }
  460. }
  461. };
  462. InteractionCell.prototype.processMouseMove = function (hitInfo) {
  463. let dataCode = headers[hitInfo.col]['dataCode'];
  464. let node = tree.items[hitInfo.row];
  465. let sheet = hitInfo.sheet;
  466. let div = sheet.getParent().getHost();
  467. let canvasId = div.id + "vp_vp";
  468. let canvas = $(`#${canvasId}`)[0];
  469. //改变鼠标图案
  470. let text = hitInfo.sheet.getText(hitInfo.row, hitInfo.col);
  471. let value = hitInfo.sheet.getValue(hitInfo.row, hitInfo.col);
  472. let acStyle = hitInfo.sheet.getActualStyle(hitInfo.row, hitInfo.col),
  473. zoom = hitInfo.sheet.zoom();
  474. let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitInfo.sheet, row: hitInfo.row, col: hitInfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
  475. if (sheet && hitInfo.x - hitInfo.cellRect.x > 0 && hitInfo.x - hitInfo.cellRect.x < textLength) {
  476. canvas.style.cursor='pointer';
  477. return true;
  478. }else{
  479. canvas.style.cursor='default';
  480. }
  481. return false;
  482. };
  483. return new InteractionCell();
  484. }
  485. //设置分享给界面数据
  486. //@param {Object}selected @return {void}
  487. function setShareToModal(selected){
  488. $('#shareToInfo').empty();
  489. if(!selected){
  490. return;
  491. }
  492. let userIDs = [];
  493. for(let user of selected.data.shareInfo){
  494. userIDs.push(user.userID);
  495. }
  496. CommonAjax.post('/user/getUsers', {userIDs: userIDs}, function (rstData) {
  497. for(let userInfo of rstData){
  498. for(let user of selected.data.shareInfo){
  499. if(user.userID === userInfo._id){
  500. user.name = userInfo.real_name;
  501. user.company = userInfo.company;
  502. user.mobile = userInfo.mobile;
  503. user.email = userInfo.email;
  504. }
  505. }
  506. }
  507. let infoArr = [];
  508. for(let user of selected.data.shareInfo){
  509. let infoHtml = `<tr>
  510. <td style="width: 106px;">${user.name}</td>
  511. <td style="width: 146px;">${user.company}</td>
  512. <td style="width: 146px;">${user.mobile}</td>
  513. <td style="width: 156px;">${user.email}</td>
  514. <td style="width: 70px;text-align: center"><input value="allowCopy" ${user.allowCopy ? 'checked' : ''} type="checkbox"></td>
  515. <td style="width: 70px;text-align: center"><input value="cancelShare" type="checkbox"></td>
  516. </tr>`;
  517. infoArr.push(infoHtml);
  518. }
  519. let infoHtml = infoArr.join('');
  520. $('#shareToInfo').html(infoHtml);
  521. });
  522. }
  523. //更新项目分享信息
  524. //@param {Object}selected
  525. function updateShareInfo(selected){
  526. if(!selected){
  527. return;
  528. }
  529. let usersTr = $('#shareToInfo').find('tr');
  530. let newShareInfo = [];
  531. for(let i = 0; i < usersTr.length; i++){
  532. let userTr = usersTr[i];
  533. let allowCopy = $(userTr).find('input:first').prop('checked');
  534. let cancelShare = $(userTr).find('input:last').prop('checked');
  535. selected.data.shareInfo[i].allowCopy = allowCopy;
  536. if(!cancelShare){
  537. newShareInfo.push(selected.data.shareInfo[i]);
  538. }
  539. }
  540. CommonAjax.post('/pm/api/updateProjects', {user_id: userID, updateData: [{updateType: 'update', updateData: {ID: selected.data.ID, shareInfo: newShareInfo}}]}, function () {
  541. selected.data.shareInfo = newShareInfo;
  542. if(newShareInfo.length === 0){
  543. renderSheetFunc(spreadObj.sheet, function () {
  544. let rIdx = selected.serialNo();
  545. tree.removeNode(selected);
  546. spreadObj.sheet.deleteRows(rIdx, 1);
  547. spreadObj.sheet.setRowCount(tree.items);
  548. initSelection({row: spreadObj.sheet.getActiveRowIndex(), rowCount: 1},null);
  549. });
  550. }
  551. });
  552. }
  553. const foreColor = '#007bff';
  554. const cancelForeColor = 'red';
  555. //显示树结构数据
  556. //@param {Array}nodes {Array}headers @return {void}
  557. function showTreeData(nodes, headers){
  558. let sheet = spreadObj.workBook.getActiveSheet();
  559. let fuc = function(){
  560. sheet.setRowCount(nodes.length);
  561. for(let i = 0; i < nodes.length; i++){
  562. let treeNodeCell = getTreeNodeCell(tree);
  563. sheet.getCell(i, treeCol).cellType(treeNodeCell);
  564. for(let j = 0; j < headers.length; j++){
  565. sheet.getRange(-1, j, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[j]['hAlign']]);
  566. sheet.getRange(-1, j, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[j]['vAlign']]);
  567. let dataCode = headers[j].dataCode;
  568. if(dataCode === oprType.copy){
  569. let style = new GC.Spread.Sheets.Style();
  570. style.foreColor = foreColor;
  571. sheet.setStyle(i, j, style);
  572. sheet.getCell(i, j).cellType(getInteractionCell());
  573. }
  574. else if (dataCode === oprType.cancel) {
  575. let style = new GC.Spread.Sheets.Style();
  576. style.foreColor = cancelForeColor;
  577. sheet.setStyle(i, j, style);
  578. sheet.getCell(i, j).cellType(getInteractionCell());
  579. }
  580. else if(dataCode === 'from'){
  581. if(nodes[i].data.shareType && nodes[i].data.shareType === shareType.receive){
  582. let style = new GC.Spread.Sheets.Style();
  583. style.foreColor = foreColor;
  584. sheet.setStyle(i, j, style);
  585. sheet.getCell(i, j).cellType(getInteractionCell());
  586. }
  587. }
  588. else if(dataCode === 'to'){
  589. if(nodes[i].data.shareType && nodes[i].data.shareType === shareType.shareTo){
  590. let style = new GC.Spread.Sheets.Style();
  591. style.foreColor = foreColor;
  592. sheet.setStyle(i, j, style);
  593. sheet.getCell(i, j).cellType(getInteractionCell());
  594. }
  595. }
  596. sheet.setValue(i, j, nodes[i].data[dataCode] !== null && typeof nodes[i].data[dataCode] !== 'undefined' ? nodes[i].data[dataCode] : '');
  597. }
  598. }
  599. };
  600. renderSheetFunc(sheet, fuc);
  601. }
  602. //同一棵树,可能存在相同数据显示多条的问题(传入的datas中不存在相同数据),将真实树结构数据存在actualTreeInfo中,外部树结构数据用uuid重置。
  603. //@param {Array}datas
  604. function setTreeInfo(datas) {
  605. let IDMapping = {};
  606. for (let data of datas) {
  607. IDMapping[data.ID] = uuid.v1();
  608. }
  609. for (let data of datas) {
  610. data.actualTreeInfo = {ID: data.ID, ParentID: data.ParentID, NextSiblingID: data.NextSiblingID};
  611. data.ID = IDMapping[data.ID];
  612. data.NextSiblingID = IDMapping[data.NextSiblingID] ? IDMapping[data.NextSiblingID] : -1;
  613. data.ParentID = IDMapping[data.ParentID] ? IDMapping[data.ParentID] : -1;
  614. }
  615. }
  616. //整理同层数据的NextSiblingID,ParentID
  617. //@param {Array}datas {Number || String}pid @return {void}
  618. function sortSameDepthData(datas, pid) {
  619. for (let i = 0; i < datas.length; i++) {
  620. let data = datas[i],
  621. nextData = datas[i + 1];
  622. data.NextSiblingID = nextData ? nextData.ID : -1;
  623. data.ParentID = pid;
  624. }
  625. }
  626. //给项目设置分享信息:由xx分享、分享给我、可进行的操作,含有userInfo信息的文件为他人直接分享的文件,他人分享父级文件,子文件不含有userInfo信息
  627. //@param {Array}datas @return {void}
  628. function setShareInfo(datas) {
  629. for (let data of datas) {
  630. if (data.userInfo) {
  631. data.from = `由 ${data.userInfo.name} 分享`;
  632. data.to = '分享给 我';
  633. data.cancel = '清除'
  634. //拷贝操作只允许到单位工程级
  635. let tendersCanCopy = isAllowCopy(userID, data);
  636. let tenders = data.projType === projectType.tender ? [data] : _.filter(data.children, {projType: projectType.tender});
  637. for (let tender of tenders) {
  638. tender.copy = tendersCanCopy ? '拷贝工程' : '';
  639. }
  640. }
  641. }
  642. }
  643. //给项目设置汇总信息
  644. //@param {Array}projs {Object}summaryInfo
  645. function setSummaryInfo(grouped, summaryInfo) {
  646. let allDatas = [];
  647. for (let data of grouped) {
  648. allDatas.push(data);
  649. if (data.children && data.children.length > 0) {
  650. allDatas = allDatas.concat(data.children);
  651. }
  652. }
  653. for(let proj of allDatas){
  654. let summaryProj = summaryInfo[proj.ID];
  655. if(summaryProj){
  656. proj.engineeringCost = summaryProj.engineeringCost;
  657. proj.subEngineering = summaryProj.subEngineering;
  658. proj.measure = summaryProj.measure;
  659. proj.safetyConstruction = summaryProj.safetyConstruction;
  660. proj.other = summaryProj.other;
  661. proj.charge = summaryProj.charge;
  662. proj.tax = summaryProj.tax;
  663. proj.rate = summaryProj.rate;
  664. proj.buildingArea = summaryProj.buildingArea;
  665. proj.perCost = summaryProj.perCost;
  666. }
  667. }
  668. }
  669. //获取可成树的数据
  670. //@param {Array}datas @return {Array}
  671. function getTreeDatas(groupedDatas, ungroupedDatas){
  672. //设置新的树结构数据
  673. for (let data of groupedDatas) {
  674. setTreeInfo([data].concat(data.children));
  675. }
  676. let engs = _.filter(ungroupedDatas, {projType: projectType.engineering}),
  677. tenders = _.filter(ungroupedDatas, {projType: projectType.tender});
  678. for (let data of engs) {
  679. setTreeInfo([data].concat(data.children));
  680. }
  681. setTreeInfo(tenders);
  682. let rst = [];
  683. //整理树结构
  684. sortSameDepthData(groupedDatas, -1);
  685. //新建未分类建设项目及单项工程
  686. let ungroupedProj = {ID: uuid.v1(), ParentID: -1, NextSiblingID: -1, name: '未分类建设项目', projType: projectType.project};
  687. let ungroupedEng = {ID: uuid.v1(), ParentID: ungroupedProj.ID, NextSiblingID: -1, name: '未分类单项工程', projType: projectType.engineering};
  688. if (groupedDatas.length > 0) {
  689. groupedDatas[groupedDatas.length - 1].NextSiblingID = ungroupedProj.ID;
  690. }
  691. //将未分类的数据归类
  692. sortSameDepthData(engs, ungroupedProj.ID);
  693. sortSameDepthData(tenders, ungroupedEng.ID);
  694. //未分类单项工程处于同层第一个节点
  695. ungroupedEng.NextSiblingID = engs[0] ? engs[0].ID : ungroupedEng.NextSiblingID;
  696. let allDatas = groupedDatas.concat(ungroupedDatas);
  697. //设置分享信息及操作信息
  698. setShareInfo(allDatas);
  699. for (let data of allDatas) {
  700. rst.push(data);
  701. if (data.children) {
  702. rst = rst.concat(data.children);
  703. }
  704. }
  705. rst.push(ungroupedProj);
  706. rst.push(ungroupedEng);
  707. return rst;
  708. }
  709. //按照时间排序
  710. //@param {Array}datas @return {void}
  711. function sortByDate(datas){
  712. datas.sort(function (a, b) {
  713. let shareInfoA = _.find(a.shareInfo, {userID}),
  714. shareInfoB = _.find(b.shareInfo, {userID});
  715. let aV = shareInfoA ? Date.parse(shareInfoA.shareDate) : 0,
  716. bV = shareInfoB ? Date.parse(shareInfoB.shareDate) : 0;
  717. //时间越晚越靠前
  718. if (aV > bV) {
  719. return -1;
  720. } else if (aV < bV) {
  721. return 1;
  722. }
  723. return 0;
  724. });
  725. }
  726. //建立树
  727. //@return void
  728. function initShareTree(){
  729. $.bootstrapLoading.start();
  730. //获取分享数据
  731. CommonAjax.post('/pm/api/receiveProjects', {user_id: userID}, function (rstData) {
  732. // 排序 --分享的文件按照时间先后顺序排序,分享文件下的子文件,按照原本树结构显示,不需要排序
  733. sortByDate(rstData.grouped);
  734. sortByDate(rstData.ungrouped);
  735. //设置汇总信息
  736. setSummaryInfo(rstData.grouped, rstData.summaryInfo);
  737. let treeDatas = getTreeDatas(rstData.grouped, rstData.ungrouped);
  738. console.log(treeDatas);
  739. tree = pmTree.createNew(treeSetting, treeDatas);
  740. console.log(tree);
  741. tree.selected = tree.items[0];
  742. showTreeData(tree.items, headers);
  743. //初始选择
  744. let initSel = spreadObj.sheet.getSelections()[0] ? spreadObj.sheet.getSelections()[0] : {row: 0, rowCount: 1};
  745. initSelection(initSel);
  746. autoFlashHeight();
  747. spreadObj.sheet.frozenColumnCount(4);
  748. spreadObj.workBook.refresh();
  749. $.bootstrapLoading.end();
  750. });
  751. }
  752. //初始化视图
  753. //@return void
  754. function initView(){
  755. if(tree){
  756. tree = null;
  757. }
  758. if(spreadObj.workBook){
  759. spreadObj.workBook.destroy();
  760. spreadObj.workBook = null;
  761. }
  762. buildSheet();
  763. initShareTree();
  764. }
  765. //根据建设项目获取单项工程
  766. //@param {Number}projID @return {void}
  767. function setEng(projID){
  768. let engQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], projType: projectType.engineering, userID: userID, ParentID: projID};
  769. CommonAjax.post('/pm/api/getProjectsByQuery', {user_id: userID, query: engQuery, options: '-_id -property'}, function (rstData) {
  770. $('#copyShare_selectEng').empty();
  771. for(let eng of rstData){
  772. let opt = $('<option>').val(eng.ID).text(eng.name);
  773. $('#copyShare_selectEng').append(opt);
  774. }
  775. });
  776. }
  777. //从其他建设项目中复制中,建设项目的文件层次结构名称和顺序
  778. //@param {Array}treeData @return {Array}
  779. function getFileHierarchyInfo(treeData){
  780. let tree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1});
  781. tree.loadDatas(treeData);
  782. let items = tree.items;
  783. let rst = [];
  784. function getFileHierarchyName(node){
  785. let nodeName = node.data.name;
  786. let name = [];
  787. while (node.parent){
  788. name.push(node.parent.data.name ? node.parent.data.name : '');
  789. node = node.parent;
  790. }
  791. name = name.reverse();
  792. name.push(nodeName);
  793. return name.join('\\');
  794. }
  795. for(let node of items){
  796. if(node.children.length === 0 ){//project
  797. rst.push({ID: node.data.ID, fileHierarchyName: getFileHierarchyName(node)})
  798. }
  799. }
  800. return rst;
  801. }
  802. //设置拷贝工程下拉选择
  803. //@return {void}
  804. function setCopyModal(){
  805. //获取建设项目
  806. let projQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], projType: {$in: [projectType.project, projectType.folder]}, userID: userID};
  807. CommonAjax.post('/pm/api/getProjectsByQuery', {user_id: userID, query: projQuery, options: '-_id -property'}, function (rstData) {
  808. let fileHierarchyData = getFileHierarchyInfo(rstData);
  809. $('#copyShare_selectProj').empty();
  810. for(let proj of fileHierarchyData){
  811. let opt = $('<option>').val(proj.ID).text(proj.fileHierarchyName);
  812. $('#copyShare_selectProj').append(opt);
  813. }
  814. //初始选择
  815. if(fileHierarchyData.length > 0){
  816. setEng(fileHierarchyData[0].ID);
  817. }
  818. });
  819. }
  820. //拷贝分享的工程
  821. //@param {Object}selected {Number}parentID @return {void}
  822. function copyShareProject(selected, projID, engID){
  823. if(!engID || !selected){
  824. return;
  825. }
  826. let copyMap = {copy: null, update: null};
  827. let newName = getCopyName(selected);
  828. //获取单项工程的单位工程
  829. let tenderQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], userID: userID, ParentID: engID};
  830. CommonAjax.post('/pm/api/getProjectsByQuery', {user_id: userID, query: tenderQuery, options: '-_id -property'}, function (rstData) {
  831. let updateTender = null;
  832. for(let tender of rstData){
  833. if(tender.name === newName){
  834. $('#copyShare_name').text('已存在此单位工程。');
  835. $('#copyShare_name').addClass('text-danger');
  836. return;
  837. }
  838. if(tender.NextSiblingID == -1){
  839. updateTender = tender;
  840. }
  841. }
  842. //更新前节点
  843. if(updateTender){
  844. copyMap.update = {query: {ID: updateTender.ID}};
  845. }
  846. //拷贝
  847. let copyData = {
  848. userID: userID,
  849. ID: selected.data.actualTreeInfo.ID,
  850. NextSiblingID: -1,
  851. ParentID: engID,
  852. name: newName,
  853. shareInfo: [],
  854. compilation: selected.data.compilation,
  855. createDateTime: selected.data.createDateTime,
  856. fileVer: selected.data.fileVer ? selected.data.fileVer : '',
  857. projType: selected.data.projType,
  858. property: {},
  859. recentDateTime: selected.data.recentDateTime,
  860. fullFolder: selected.data.fullFolder
  861. };
  862. copyData.property.rootProjectID = projID;
  863. copyMap.copy = {document: copyData};
  864. $('#copyShare').modal('hide');
  865. $.bootstrapLoading.start();
  866. CommonAjax.post('/pm/api/copyProjects', {projectMap: copyMap, user_id: userID}, function (rstData) {
  867. $.bootstrapLoading.end();
  868. }, function () {
  869. $.bootstrapLoading.end();
  870. });
  871. });
  872. }
  873. //获取拷贝后的名称
  874. //@param {Object}node @return {String}
  875. function getCopyName(node) {
  876. //当前单位工程可能没有分享的用户信息,可能他人分享的是父级文件,userInfo在父级文件中
  877. let orgName = node.data.name,
  878. userInfo = node.data.userInfo;
  879. while (node && !userInfo) {
  880. node = node.parent;
  881. userInfo = node.data.userInfo;
  882. }
  883. return `${orgName} (${userInfo.name}分享拷贝)`;
  884. }
  885. //事件监听器
  886. //@return void
  887. function eventListener(){
  888. //tab
  889. $('#tab_pm_share').on('shown.bs.tab', function () {
  890. //侧滑隐藏
  891. $('.slide-sidebar').removeClass('open');
  892. $('.slide-sidebar').css('width', '0');
  893. projTreeObj.tree = null;
  894. if(projTreeObj.workBook){
  895. projTreeObj.workBook.destroy();
  896. projTreeObj.workBook = null;
  897. }
  898. gcTreeObj.tree = null;
  899. if(gcTreeObj.workBook){
  900. gcTreeObj.workBook.destroy();
  901. gcTreeObj.workBook = null;
  902. }
  903. initView();
  904. });
  905. //关闭拷贝工程
  906. $('#copyShare').on('hidden.bs.modal', function () {
  907. $('#copyShareProj-info').hide();
  908. $('#copyShareEng-info').hide();
  909. });
  910. //打开拷贝工程
  911. $('#copyShare').on('shown.bs.modal', function () {
  912. setCopyModal();
  913. //更改显示名称
  914. let newName = getCopyName(shareSeleted);
  915. $('#copyShare_name').html(`拷贝后,工程将重命名为 "<b>${newName}</b>"`);
  916. $('#copyShare_name').removeClass('text-danger');
  917. });
  918. //拷贝工程改变选择建设项目
  919. $('#copyShare_selectProj').change(function () {
  920. //更改显示名称
  921. let newName = getCopyName(shareSeleted);
  922. $('#copyShare_name').html(`拷贝后,工程将重命名为 "<b>${newName}</b>"`);
  923. $('#copyShare_name').removeClass('text-danger');
  924. $('#copyShareProj-info').hide();
  925. $('#copyShareEng-info').hide();
  926. let curSelID = $(this).select().val();
  927. setEng(parseInt(curSelID));
  928. });
  929. //拷贝工程改变选择单项工程
  930. $('#copyShare_selectEng').change(function () {
  931. //更改显示名称
  932. let newName = getCopyName(shareSeleted);
  933. $('#copyShare_name').html(`拷贝后,工程将重命名为 "<b>${newName}</b>"`);
  934. $('#copyShare_name').removeClass('text-danger');
  935. });
  936. //确认拷贝
  937. $('#copyShare_confirm').click(function () {
  938. let selProj = $('#copyShare_selectProj').select().val();
  939. if(!selProj){
  940. $('#copyShareProj-info').show();
  941. return;
  942. }
  943. let selEng = $('#copyShare_selectEng').select().val();
  944. if(!selEng){
  945. $('#copyShareEng-info').show();
  946. return;
  947. }
  948. copyShareProject(tree.selected, parseInt(selProj), parseInt(selEng));
  949. });
  950. //清除分享
  951. $('#cancelShareConfirm').click(function () {
  952. $.bootstrapLoading.start();
  953. CommonAjax.post('/pm/api/share', {user_id: userID, type: oprType.cancel, projectID: tree.selected.data.actualTreeInfo.ID, shareData:[{userID: userID}]}, function (rstData) {
  954. $.bootstrapLoading.end();
  955. tree.removeNode(tree.selected);
  956. showTreeData(tree.items, headers);
  957. }, function () {
  958. $.bootstrapLoading.end();
  959. });
  960. });
  961. }
  962. return {spreadObj, headers, initView, eventListener}
  963. })();
  964. $(document).ready(function () {
  965. pmShare.eventListener();
  966. });