pm_share.js 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223
  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 shareSeleted = null;
  12. let spreadObj = {workBook: null, sheet: null};
  13. let preSelection = null;
  14. //项目分享类型,由别人分享给自己的,和自己分享给别人的
  15. const shareType = {receive: 'receive', shareTo: 'shareTo'};
  16. //操作类型
  17. const oprType = {copy: 'copy', cancel: 'cancel'};
  18. let tree = null,
  19. actualIDShareInfo = {};//项目真实树ID与项目分享信息映射
  20. let curCopySelTree = null; //拷贝工程建设项目选项树
  21. const treeCol = 0;
  22. const treeSetting = {
  23. tree: {
  24. id: 'ID',
  25. pid: 'ParentID',
  26. nid: 'NextSiblingID',
  27. rootId: -1,
  28. autoUpdate: false
  29. }
  30. };
  31. const headers = [
  32. {name: '工程列表', dataCode: 'name', width: 300, rateWidth: 0.55, vAlign: 'center', hAlign: 'left'},
  33. {name: '来自', dataCode: 'from', width: 80, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},
  34. {name: '分享时间', dataCode: 'shareDate', width: 140, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},
  35. {name: '工程造价', dataCode: 'engineeringCost', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  36. {name: '分部分项合计', dataCode: 'subEngineering', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  37. {name: '措施项目合计', dataCode: 'measure', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  38. {name: '其他项目合计', dataCode: 'other', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  39. {name: '规费', dataCode: 'charge', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  40. {name: '税金', dataCode: 'tax', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  41. {name: '占造价比例(%)', dataCode: 'rate', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  42. {name: '建筑面积', dataCode: 'buildingArea', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  43. {name: '单方造价', dataCode: 'perCost', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
  44. {name: '工程专业', dataCode: 'feeStandardName', width: 100, vAlign: 'center', hAlign: 'left'},
  45. ];
  46. const spreadOpts = {
  47. workBook: {
  48. tabStripVisible: false,
  49. allowContextMenu: false,
  50. allowCopyPasteExcelStyle : false,
  51. allowExtendPasteRange: false,
  52. allowUserDragDrop : false,
  53. allowUserDragFill: false,
  54. scrollbarMaxAlign : true
  55. },
  56. sheet: {
  57. isProtected: true,
  58. frozenlineColor : '#ababab',
  59. protectionOptions: {allowResizeRows: true, allowResizeColumns: true},
  60. clipBoardOptions: GC.Spread.Sheets.ClipboardPasteOptions.values
  61. }
  62. };
  63. const spreadEvents = {
  64. SelectionChanging: function (sender, info) {
  65. initSelection(info.newSelections[0], info.oldSelections[0]);
  66. }
  67. };
  68. //设置选中行底色
  69. //@param
  70. function setSelStyle(sel, backColor,sheet) {
  71. sel.row = sel.row === -1 ? 0 : sel.row;
  72. renderSheetFunc(sheet, function () {
  73. let style = projTreeObj.getSelStyle(backColor);
  74. for(let i = 0; i < sel.rowCount; i++){
  75. let row = i + sel.row;
  76. sheet.setStyle(row, -1, style);
  77. }
  78. });
  79. }
  80. //初始化焦点
  81. //@param {Object}newSel {Object}oldSel @return {void}
  82. function initSelection(newSel, oldSel = null) {
  83. let node = tree.items[newSel.row];
  84. tree.selected = node;
  85. shareSeleted = node;
  86. //恢复底色
  87. if(oldSel){
  88. setSelStyle(oldSel, projTreeObj.setting.style.defalutBackColor, spreadObj.sheet);
  89. }
  90. //设置选中行底色
  91. if(newSel){
  92. setSelStyle(newSel, projTreeObj.setting.style.selectedColor, spreadObj.sheet);
  93. }
  94. preSelection = newSel;
  95. }
  96. //渲染时方法,停止渲染
  97. //@param {Object}sheet {Function}func @return {void}
  98. function renderSheetFunc(sheet, func){
  99. sheet.suspendEvent();
  100. sheet.suspendPaint();
  101. if(func){
  102. func();
  103. }
  104. sheet.resumeEvent();
  105. sheet.resumePaint();
  106. }
  107. //设置表选项
  108. //@param {Object}workBook {Object}opts @return {void}
  109. function setSpreadOptions (workBook, opts) {
  110. for(let opt in opts.workBook){
  111. workBook.options[opt] = opts.workBook[opt];
  112. }
  113. for(let opt in opts.sheet){
  114. workBook.getActiveSheet().options[opt] = opts.sheet[opt];
  115. }
  116. }
  117. //建表头
  118. //@param {Object}sheet {Array}headers @return {void}
  119. function buildHeader(sheet, headers) {
  120. let fuc = function () {
  121. sheet.setColumnCount(headers.length);
  122. sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
  123. //let spreadWidth = getWorkBookWidth();
  124. for(let i = 0, len = headers.length; i < len; i++){
  125. sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
  126. if(headers[i].formatter){
  127. sheet.setFormatter(-1, i, headers[i].formatter);
  128. }
  129. sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
  130. sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
  131. sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
  132. }
  133. };
  134. renderSheetFunc(sheet, fuc);
  135. }
  136. //表监听事件
  137. //@param {Object}workBook @return {void}
  138. function bindEvent(workBook, events) {
  139. if(Object.keys(events).length === 0){
  140. return;
  141. }
  142. const Events = GC.Spread.Sheets.Events;
  143. for(let event in events){
  144. workBook.bind(Events[event], events[event]);
  145. }
  146. }
  147. //建表
  148. //@return {void}
  149. function buildSheet(){
  150. spreadObj.workBook = new GC.Spread.Sheets.Workbook(spreadDom[0], {sheetCount: 1});
  151. sheetCommonObj.spreadDefaultStyle(spreadObj.workBook);
  152. spreadObj.sheet = spreadObj.workBook.getActiveSheet();
  153. setSpreadOptions(spreadObj.workBook, spreadOpts);
  154. bindEvent(spreadObj.workBook, spreadEvents);
  155. buildHeader(spreadObj.sheet, headers);
  156. //全表不可编辑
  157. spreadObj.sheet.getRange(-1, -1, -1, -1).locked(true);
  158. }
  159. //此项目的分享权限信息(可能会被父级项目覆盖,以新为准)
  160. //@param {String}userID(本用户id) {Object}project(项目) @return {Object} || {Null}
  161. function getShareInfo(userID, project) {
  162. if (!project.actualTreeInfo) {
  163. return null;
  164. }
  165. //获取跟本用户和选中项目相关的分享信息
  166. let shareList = [];
  167. let actualID = project.actualTreeInfo.ID,
  168. actualData = actualIDShareInfo[actualID];
  169. while (actualData) {
  170. for (let data of actualData.shareInfo) {
  171. if (data.userID === userID) {
  172. shareList.push(data);
  173. break;
  174. }
  175. }
  176. actualData = actualIDShareInfo[actualData.ParentID];
  177. }
  178. //获取最新分享
  179. shareList.sort(function (a, b) {
  180. //return Date.parse(b.shareDate) - Date.parse(a.shareDate)
  181. return Date.parse(b.updateDate) - Date.parse(a.updateDate);
  182. });
  183. return shareList[0] || null;
  184. }
  185. //此项目是否可以拷贝
  186. //@param {String}userID {Object}project @return {Boolean}
  187. function isAllowCopy(userID, project){
  188. let myShareInfo = getShareInfo(userID, project);
  189. if (!myShareInfo) {
  190. return false;
  191. }
  192. return !!myShareInfo.allowCopy;
  193. }
  194. //此项目是否可以协作
  195. //@param {String}userID {Object}project @return {Boolean}
  196. function isAllowCoop(userID, project) {
  197. let myShareInfo = getShareInfo(userID, project);
  198. if (!myShareInfo) {
  199. return false;
  200. }
  201. return !!myShareInfo.allowCooperate;
  202. }
  203. //获取树节点
  204. //@param {Object}tree @return {Object}
  205. function getTreeNodeCell(tree){
  206. let indent = 20;
  207. let levelIndent = -5;
  208. let halfBoxLength = 5;
  209. let halfExpandLength = 3;
  210. let imgWidth = 18;
  211. let imgHeight = 14;
  212. let TreeNodeCellType = function () {
  213. };
  214. TreeNodeCellType.prototype = new GC.Spread.Sheets.CellTypes.Text();
  215. TreeNodeCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
  216. if (style.backColor) {
  217. ctx.save();
  218. ctx.fillStyle = style.backColor;
  219. ctx.fillRect(x, y, w, h);
  220. ctx.restore();
  221. } else {
  222. ctx.clearRect(x, y, w, h);
  223. }
  224. let drawLine = function (canvas, x1, y1, x2, y2, color) {
  225. ctx.save();
  226. ctx.translate(0.5, 0.5);
  227. ctx.beginPath();
  228. ctx.moveTo(x1, y1);
  229. ctx.lineTo(x2, y2);
  230. ctx.strokeStyle = color;
  231. ctx.stroke();
  232. ctx.restore();
  233. };
  234. let drawExpandBox = function (ctx, x, y, w, h, centerX, centerY, expanded) {
  235. let rect = {}, h1, h2, offset = 1;
  236. rect.top = centerY - halfBoxLength;
  237. rect.bottom = centerY + halfBoxLength;
  238. rect.left = centerX - halfBoxLength;
  239. rect.right = centerX + halfBoxLength;
  240. if (rect.left < x + w) {
  241. rect.right = Math.min(rect.right, x + w);
  242. ctx.save();
  243. ctx.translate(0.5, 0.5);
  244. ctx.strokeStyle = 'black';
  245. ctx.beginPath();
  246. ctx.moveTo(rect.left, rect.top);
  247. ctx.lineTo(rect.left, rect.bottom);
  248. ctx.lineTo(rect.right, rect.bottom);
  249. ctx.lineTo(rect.right, rect.top);
  250. ctx.lineTo(rect.left, rect.top);
  251. ctx.stroke();
  252. ctx.fillStyle = 'white';
  253. ctx.fill();
  254. ctx.restore();
  255. // Draw Horizontal Line
  256. h1 = centerX - halfExpandLength;
  257. h2 = Math.min(centerX + halfExpandLength, x + w);
  258. if (h2 > h1) {
  259. drawLine(ctx, h1, centerY, h2, centerY, 'black');
  260. }
  261. // Draw Vertical Line
  262. if (!expanded && (centerX < x + w)) {
  263. drawLine(ctx, centerX, centerY - halfExpandLength, centerX, centerY + halfExpandLength, 'black');
  264. }
  265. }
  266. }
  267. let node = tree.items[options.row];
  268. let showTreeLine = true;
  269. if (!node) { return; }
  270. let centerX = Math.floor(x) + node.depth() * indent + node.depth() * levelIndent + indent / 2;
  271. let x1 = centerX + indent / 2;
  272. let centerY = Math.floor((y + (y + h)) / 2);
  273. let y1;
  274. const lineColor = '#ababab';
  275. // Draw Sibling Line
  276. if (showTreeLine) {
  277. // Draw Horizontal Line
  278. if (centerX < x + w) {
  279. drawLine(ctx, centerX, centerY, Math.min(x1, x + w), centerY, lineColor);
  280. let img;
  281. if(node.data.projType === projectType.folder){
  282. img = document.getElementById('folder_open_pic');
  283. imgWidth = 15;
  284. }
  285. else if(node.data.projType === projectType.project){
  286. img = document.getElementById('proj_pic');
  287. imgWidth = 18;
  288. }
  289. else if(node.data.projType === projectType.engineering){
  290. img = document.getElementById('eng_pic');
  291. imgWidth = 14;
  292. }
  293. else if(node.data.projType === projectType.tender){
  294. img = document.getElementById('tender_pic');
  295. imgWidth = 14;
  296. }
  297. ctx.drawImage(img, centerX+indent/2+3, centerY - 7, imgWidth,imgHeight);
  298. }
  299. // Draw Vertical Line
  300. if (centerX < x + w) {
  301. y1 = node.isLast() ? centerY : y + h;
  302. if (node.isFirst() && !node.parent.parent) {
  303. drawLine(ctx, centerX, centerY, centerX, y1, lineColor);
  304. } else {
  305. drawLine(ctx, centerX, y, centerX, y1, lineColor);
  306. }
  307. }
  308. }
  309. // Draw Expand Box
  310. if (node.children.length > 0) {
  311. drawExpandBox(ctx, x, y, w, h, centerX, centerY, node.expanded);
  312. }
  313. // Draw Parent Line
  314. if (showTreeLine) {
  315. var parent = node.parent, parentCenterX = centerX - indent - levelIndent;
  316. while (parent.parent) {
  317. if (!parent.isLast()) {
  318. if (parentCenterX < x + w) {
  319. drawLine(ctx, parentCenterX, y, parentCenterX, y + h, lineColor);
  320. }
  321. }
  322. parent = parent.parent;
  323. parentCenterX -= (indent + levelIndent);
  324. }
  325. };
  326. // Draw Text
  327. arguments[2] = x + (node.depth() + 1) * indent + node.depth() * levelIndent + imgWidth + 3;
  328. arguments[4] = w - (node.depth() + 1) * indent - node.depth() * levelIndent - imgWidth - 3;
  329. GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
  330. };
  331. TreeNodeCellType.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
  332. let info = {x: x, y: y, row: context.row, col: context.col, cellStyle: cellStyle, cellRect: cellRect, sheetArea: context.sheetArea};
  333. let node = tree.items[info.row];
  334. if (node && node.data.projType === projectType.tender) {
  335. info.isReservedLocation = true;
  336. }
  337. return info;
  338. };
  339. TreeNodeCellType.prototype.processMouseDown = function (hitinfo) {
  340. let offset = -1;
  341. let node = tree.items[hitinfo.row];
  342. let centerX = hitinfo.cellRect.x + offset + node.depth() * indent + node.depth() * levelIndent + indent / 2;
  343. let centerY = (hitinfo.cellRect.y + offset + (hitinfo.cellRect.y + offset + hitinfo.cellRect.height)) / 2;
  344. //点击单位工程
  345. if(node.data.projType === projectType.tender){
  346. let thisClick = Date.now(),
  347. open = false;
  348. if (this.preNode === node && this.preClick && thisClick - this.preClick <= 300) {
  349. open = true;
  350. projTreeObj.openTender(node.data.actualTreeInfo.ID, node.parent, 200);
  351. }
  352. this.preClick = open ? null : thisClick;
  353. this.preNode = open ? null : node;
  354. }
  355. if (!node || node.children.length === 0) {
  356. return;
  357. }
  358. if (hitinfo.x >= centerX - halfBoxLength - 2 && hitinfo.x <= centerX + halfBoxLength + 2 &&
  359. hitinfo.y >= centerY - halfBoxLength - 2 && hitinfo.y <= centerY + halfBoxLength + 2) {
  360. node.setExpanded(!node.expanded);
  361. TREE_SHEET_HELPER.massOperationSheet(hitinfo.sheet, function () {
  362. let iCount = node.posterityCount(), i, child;
  363. for (i = 0; i < iCount; i++) {
  364. child = tree.items[hitinfo.row + i + 1];
  365. hitinfo.sheet.setRowVisible(hitinfo.row + i + 1, child.visible, hitinfo.sheetArea);
  366. }
  367. hitinfo.sheet.invalidateLayout();
  368. });
  369. hitinfo.sheet.repaint();
  370. }
  371. };
  372. TreeNodeCellType.prototype.processMouseEnter = function (hitinfo) {
  373. let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
  374. let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col);
  375. let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col),
  376. zoom = hitinfo.sheet.zoom();
  377. let node = tree.items[hitinfo.row];
  378. let nodeIndent = node ? (node.depth() + 1) * indent + node.depth() * levelIndent + imgWidth + 3 : 0;
  379. let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
  380. let cellWidth = hitinfo.sheet.getCell(-1, hitinfo.col).width();
  381. if(textLength > cellWidth - nodeIndent){
  382. TREE_SHEET_HELPER.showTipsDiv(text,{pos: {}},hitinfo);
  383. }
  384. };
  385. TreeNodeCellType.prototype.processMouseLeave = function (hitinfo) {
  386. TREE_SHEET_HELPER.tipDiv = 'hide';
  387. if (TREE_SHEET_HELPER._toolTipElement) {
  388. $(TREE_SHEET_HELPER._toolTipElement).hide();
  389. TREE_SHEET_HELPER._toolTipElement = null;
  390. };
  391. TREE_SHEET_HELPER.tipDivCheck();//延时检查:当tips正在show的时候,就调用了hide方法,会导致tips一直存在,所以设置一个超时处理
  392. }
  393. return new TreeNodeCellType();
  394. }
  395. //互动单元格
  396. function getInteractionCell() {
  397. let editImg = document.getElementById('edit_pic'),
  398. workImgWidth = 13,
  399. workImgHeight = 13,
  400. copyImg = document.getElementById('copy_pic'),
  401. copyImgWidth = 13,
  402. copyImgHeight = 13;
  403. let InteractionCell = function () {
  404. };
  405. InteractionCell.prototype = new GC.Spread.Sheets.CellTypes.Text();
  406. InteractionCell.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
  407. if (style.backColor) {
  408. ctx.save();
  409. ctx.fillStyle = style.backColor;
  410. ctx.fillRect(x, y, w, h);
  411. ctx.restore();
  412. } else {
  413. ctx.clearRect(x, y, w, h);
  414. }
  415. let node = tree.items[options.row];
  416. // Draw Text
  417. GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
  418. if (node && (node.data.projType === projectType.tender||node.data.projType === projectType.project)) {
  419. let text = options.sheet.getText(options.row, options.col);
  420. let acStyle = options.sheet.getActualStyle(options.row, options.col),
  421. zoom = options.sheet.zoom();
  422. let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: options.sheet, row: options.row, col: options.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
  423. const imgIndent = 5;
  424. let nowX = Math.floor(x) + textLength + imgIndent,
  425. nowY = Math.floor((y + (y + h)) / 2) - 7;
  426. if (node.data.allowCooperate) {
  427. ctx.drawImage(editImg, nowX, nowY, workImgWidth, workImgHeight);
  428. nowX += workImgWidth;
  429. }
  430. if (node.data.allowCopy) {
  431. ctx.drawImage(copyImg, nowX, nowY, copyImgWidth, copyImgHeight);
  432. }
  433. }
  434. };
  435. InteractionCell.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
  436. return {
  437. x: x,
  438. y: y,
  439. row: context.row,
  440. col: context.col,
  441. cellStyle: cellStyle,
  442. cellRect: cellRect,
  443. sheetArea: context.sheetArea,
  444. isReservedLocation: true
  445. };
  446. };
  447. InteractionCell.prototype.processMouseDown = function (hitinfo) {
  448. let dataCode = headers[hitinfo.col]['dataCode'];
  449. let node = tree.items[hitinfo.row];
  450. let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
  451. let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col);
  452. let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col),
  453. zoom = hitinfo.sheet.zoom();
  454. let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
  455. if(hitinfo.x - hitinfo.cellRect.x > 0 && hitinfo.x - hitinfo.cellRect.x < textLength){
  456. //由..分享,弹出分享者信息
  457. if(dataCode === 'from'){
  458. if(node.data.shareType === shareType.receive){
  459. $('#userinfo').find('h4').text(node.data.userInfo.name);
  460. $('#userinfo').find('h6').text(node.data.userInfo.company);
  461. let mobileHtml = `<i class="fa fa-tablet"> ${node.data.userInfo.mobile ? node.data.userInfo.mobile : ''}</i>`;
  462. $('#userinfo').find('li:first-child').html(mobileHtml);
  463. let emailHtml = `<i class="fa fa-envelope-o"> ${node.data.userInfo.email ? node.data.userInfo.email : ''}</i>`;
  464. $('#userinfo').find('li:last-child').html(emailHtml);
  465. $('#userinfo').modal('show');
  466. }
  467. }
  468. }
  469. };
  470. InteractionCell.prototype.processMouseMove = function (hitInfo) {
  471. let dataCode = headers[hitInfo.col]['dataCode'];
  472. let node = tree.items[hitInfo.row];
  473. let sheet = hitInfo.sheet;
  474. let div = sheet.getParent().getHost();
  475. let canvasId = div.id + "vp_vp";
  476. let canvas = $(`#${canvasId}`)[0];
  477. //改变鼠标图案
  478. let text = hitInfo.sheet.getText(hitInfo.row, hitInfo.col);
  479. let value = hitInfo.sheet.getValue(hitInfo.row, hitInfo.col);
  480. let acStyle = hitInfo.sheet.getActualStyle(hitInfo.row, hitInfo.col),
  481. zoom = hitInfo.sheet.zoom();
  482. let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitInfo.sheet, row: hitInfo.row, col: hitInfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
  483. if (sheet && hitInfo.x - hitInfo.cellRect.x > 0 && hitInfo.x - hitInfo.cellRect.x < textLength) {
  484. canvas.style.cursor='pointer';
  485. return true;
  486. }else{
  487. canvas.style.cursor='default';
  488. }
  489. return false;
  490. };
  491. return new InteractionCell();
  492. }
  493. function isUnread(unreadList, node) {
  494. if (!unreadList) {
  495. return false;
  496. }
  497. const actualID = node && node.data && node.data.actualTreeInfo && node.data.actualTreeInfo.ID || null;
  498. if (!actualID) {
  499. return false;
  500. }
  501. return !!unreadList.find(ID => ID === actualID);
  502. }
  503. const foreColor = '#007bff';
  504. const dangerColor = '#dc3545';
  505. // 标记已读
  506. // 打开任意的单位工程,都会将其父分享条目标记和自身为已读
  507. // eg:被分享了一个建设项目,和其下一个单位工程,打开该一个单位工程,建设项目标记为已读、该单位工程也标记为已读
  508. function handleMarkRead(unreadList, markReadProjectIDs) {
  509. const col = headers.findIndex(item => item.dataCode === 'shareDate');
  510. const sheet = spreadObj.workBook.getActiveSheet();
  511. const style = new GC.Spread.Sheets.Style();
  512. projTreeObj.renderSheetFuc(sheet, function () {
  513. markReadProjectIDs.forEach(projectID => {
  514. SHARE_TO.removeUnread(projectID, unreadList);
  515. tree.items.forEach(node => {
  516. if (node.data && node.data.actualTreeInfo && node.data.actualTreeInfo.ID === projectID) {
  517. const row = node.serialNo();
  518. sheet.setStyle(row, col, style);
  519. }
  520. });
  521. });
  522. });
  523. }
  524. //显示树结构数据
  525. //@param {Array}nodes {Array}headers @return {void}
  526. function showTreeData(nodes, headers){
  527. let sheet = spreadObj.workBook.getActiveSheet();
  528. let fuc = function(){
  529. sheet.setRowCount(nodes.length);
  530. for(let i = 0; i < nodes.length; i++){
  531. let treeNodeCell = getTreeNodeCell(tree);
  532. sheet.getCell(i, treeCol).cellType(treeNodeCell);
  533. for(let j = 0; j < headers.length; j++){
  534. sheet.getRange(-1, j, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[j]['hAlign']]);
  535. sheet.getRange(-1, j, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[j]['vAlign']]);
  536. let dataCode = headers[j].dataCode;
  537. if(dataCode === 'from'){
  538. let style = new GC.Spread.Sheets.Style();
  539. style.foreColor = foreColor;
  540. sheet.setStyle(i, j, style);
  541. sheet.getCell(i, j).cellType(getInteractionCell());
  542. } else if (dataCode === 'shareDate') {
  543. let style = new GC.Spread.Sheets.Style();
  544. if (isUnread(unreadShareList, nodes[i])) {
  545. style.foreColor = dangerColor;
  546. }
  547. sheet.setStyle(i, j, style);
  548. }
  549. sheet.setValue(i, j, nodes[i].data[dataCode] !== null && typeof nodes[i].data[dataCode] !== 'undefined' ? nodes[i].data[dataCode] : '');
  550. }
  551. }
  552. };
  553. renderSheetFunc(sheet, fuc);
  554. }
  555. // 获取实际树ID为某值的所有节点
  556. function getNodesByActualID(ID, items) {
  557. return items.filter(node => node.data && node.data.actualTreeInfo && node.data.actualTreeInfo.ID === ID);
  558. }
  559. // 刷新显示某些节点
  560. function refreshNodes(nodes, headers) {
  561. const sheet = spreadObj.workBook.getActiveSheet();
  562. const fuc = function(){
  563. for (let i = 0; i < nodes.length; i++) {
  564. const row = nodes[i].serialNo();
  565. for (let j = 0; j < headers.length; j++) {
  566. const dataCode = headers[j].dataCode;
  567. if (dataCode === 'from') {
  568. const style = new GC.Spread.Sheets.Style();
  569. style.foreColor = foreColor;
  570. sheet.setStyle(row, j, style);
  571. sheet.getCell(row, j).cellType(getInteractionCell());
  572. }
  573. sheet.setValue(row, j, nodes[i].data[dataCode] !== null && typeof nodes[i].data[dataCode] !== 'undefined' ? nodes[i].data[dataCode] : '');
  574. }
  575. }
  576. };
  577. renderSheetFunc(sheet, fuc);
  578. }
  579. //同一棵树,可能存在相同数据显示多条的问题(传入的datas中不存在相同数据)
  580. //将真实树结构数据存在actualTreeInfo中,外部树结构数据用uuid重置。
  581. //@param {Array}datas
  582. function setTreeInfo(datas) {
  583. let IDMapping = {};
  584. for (let data of datas) {
  585. //项目真实ID与项目分享信息映射,方便确定项目的权限
  586. if (!actualIDShareInfo[data.ID]) {
  587. actualIDShareInfo[data.ID] = {ID: data.ID, ParentID: data.ParentID, NextSiblingID: data.NextSiblingID, shareInfo: data.shareInfo};
  588. }
  589. IDMapping[data.ID] = uuid.v1();
  590. }
  591. for (let data of datas) {
  592. data.actualTreeInfo = {ID: data.ID, ParentID: data.ParentID, NextSiblingID: data.NextSiblingID};
  593. data.ID = IDMapping[data.ID];
  594. data.NextSiblingID = IDMapping[data.NextSiblingID] ? IDMapping[data.NextSiblingID] : -1;
  595. data.ParentID = IDMapping[data.ParentID] ? IDMapping[data.ParentID] : -1;
  596. }
  597. }
  598. //整理同层数据的NextSiblingID,ParentID
  599. //@param {Array}datas {Number || String}pid @return {void}
  600. function sortSameDepthData(datas, pid) {
  601. for (let i = 0; i < datas.length; i++) {
  602. let data = datas[i],
  603. nextData = datas[i + 1];
  604. data.NextSiblingID = nextData ? nextData.ID : -1;
  605. data.ParentID = pid;
  606. }
  607. }
  608. //给项目设置分享信息:由xx分享、分享时间、分享给我,含有userInfo信息的文件为他人直接分享的文件,他人分享父级文件,子文件不含有userInfo信息
  609. //@param {Array}datas @return {void}
  610. function setShareInfo(datas) {
  611. for (let data of datas) {
  612. if (data.userInfo) {
  613. //shareInfo中我的条目
  614. let selfInfo = _.find(data.shareInfo, {userID: userID});
  615. data.shareDate = selfInfo ? selfInfo.shareDate : ''
  616. data.from = data.userInfo.name;
  617. data.to = '分享给 我';
  618. data.cancel = '清除';
  619. }
  620. }
  621. }
  622. //给项目设置汇总信息
  623. //@param {Array}projs {Object}summaryInfo
  624. function setSummaryInfo(grouped, summaryInfo) {
  625. if (!summaryInfo) {
  626. return;
  627. }
  628. let allDatas = [];
  629. for (let data of grouped) {
  630. allDatas.push(data);
  631. if (data.children && data.children.length > 0) {
  632. allDatas = allDatas.concat(data.children);
  633. }
  634. }
  635. for(let proj of allDatas){
  636. let summaryProj = summaryInfo[proj.ID];
  637. if(summaryProj){
  638. proj.engineeringCost = summaryProj.engineeringCost;
  639. proj.subEngineering = summaryProj.subEngineering;
  640. proj.measure = summaryProj.measure;
  641. proj.safetyConstruction = summaryProj.safetyConstruction;
  642. proj.other = summaryProj.other;
  643. proj.charge = summaryProj.charge;
  644. proj.tax = summaryProj.tax;
  645. proj.rate = summaryProj.rate;
  646. proj.buildingArea = summaryProj.buildingArea;
  647. proj.perCost = summaryProj.perCost;
  648. }
  649. }
  650. }
  651. //从同层树数据获取第一个节点ID
  652. //@param {Array}treeDatas树的数据 @return {String}第一个节点的虚拟树ID
  653. function getFirstID(treeDatas) {
  654. let treeMapping = {};
  655. //建立ID索引
  656. for (let data of treeDatas) {
  657. //新建一个简单对象,防止污染treeDatas的数据
  658. treeMapping[data.ID] = {ID: data.ID, prev: null, next: null};
  659. }
  660. //绑定prev next
  661. for (let data of treeDatas) {
  662. let me = treeMapping[data.ID],
  663. next = treeMapping[data.NextSiblingID];
  664. if (next) {
  665. me.next = next;
  666. next.prev = me;
  667. }
  668. }
  669. //返回没有prev属性的数据
  670. let result = _.find(treeDatas, function (data) {
  671. return !treeMapping[data.ID].prev
  672. });
  673. return result ? result.ID : -1;
  674. }
  675. //获取可成树的数据
  676. //@param {Array}datas @return {Array}
  677. function getTreeDatas(groupedDatas, ungroupedDatas){
  678. //设置新的树结构数据
  679. for (let data of groupedDatas) {
  680. setTreeInfo([data].concat(data.children));
  681. }
  682. let engs = _.filter(ungroupedDatas, {projType: projectType.engineering}),
  683. tenders = _.filter(ungroupedDatas, {projType: projectType.tender});
  684. for (let data of engs) {
  685. setTreeInfo([data].concat(data.children));
  686. }
  687. setTreeInfo(tenders);
  688. let rst = [];
  689. //整理树结构
  690. sortSameDepthData(groupedDatas, -1);
  691. //第一个根节点数据
  692. let firstID = getFirstID(groupedDatas);
  693. //新建未分类建设项目及单项工程
  694. let ungroupedProj = {ID: uuid.v1(), ParentID: -1, NextSiblingID: firstID, name: '未分类建设项目', projType: projectType.project};
  695. let ungroupedEng = {ID: uuid.v1(), ParentID: ungroupedProj.ID, NextSiblingID: -1, name: '未分类单项工程', projType: projectType.engineering};
  696. //将未分类的数据归类
  697. sortSameDepthData(engs, ungroupedProj.ID);
  698. sortSameDepthData(tenders, ungroupedEng.ID);
  699. //未分类单项工程处于同层第一个节点
  700. ungroupedEng.NextSiblingID = engs[0] ? engs[0].ID : ungroupedEng.NextSiblingID;
  701. let allDatas = groupedDatas.concat(ungroupedDatas);
  702. //设置分享信息及操作信息
  703. setShareInfo(allDatas);
  704. for (let data of allDatas) {
  705. rst.push(data);
  706. if (data.children) {
  707. rst = rst.concat(data.children);
  708. }
  709. }
  710. rst.push(ungroupedProj);
  711. rst.push(ungroupedEng);
  712. return rst;
  713. }
  714. //按照时间排序
  715. //@param {Array}datas @return {void}
  716. function sortByDate(datas){
  717. datas.sort(function (a, b) {
  718. let shareInfoA = _.find(a.shareInfo, {userID}),
  719. shareInfoB = _.find(b.shareInfo, {userID});
  720. let aV = shareInfoA ? Date.parse(shareInfoA.shareDate) : 0,
  721. bV = shareInfoB ? Date.parse(shareInfoB.shareDate) : 0;
  722. //时间越晚越靠前
  723. if (aV > bV) {
  724. return -1;
  725. } else if (aV < bV) {
  726. return 1;
  727. }
  728. return 0;
  729. });
  730. }
  731. //设置节点数据权限
  732. //@param {Array}datas项目数据
  733. function setPermissionsInfo(datas) {
  734. //data.allowCopy与shareInfo里allowCopy的区别:
  735. //data.allowCopy为该单位实际的权限(跟着最新的分享信息走,可能随着父项)
  736. for (let data of datas) {
  737. if(data.projType == projectType.project) data.allowCopy = isAllowCopy(userID, data); //20200715 专业版要求能复制建设项目
  738. if (data.projType === projectType.tender) {
  739. data.allowCopy = isAllowCopy(userID, data);
  740. data.allowCooperate = isAllowCoop(userID, data);
  741. }
  742. }
  743. }
  744. //建立树
  745. //@return void
  746. function initShareTree(){
  747. $.bootstrapLoading.start();
  748. //获取分享数据
  749. CommonAjax.post('/pm/api/receiveProjects', {user_id: userID}, function (rstData) {
  750. actualIDShareInfo = {};
  751. // 排序 --分享的文件按照时间先后顺序排序,分享文件下的子文件,按照原本树结构显示,不需要排序
  752. sortByDate(rstData.grouped);
  753. sortByDate(rstData.ungrouped);
  754. //设置汇总信息
  755. if (rstData.summaryInfo) {
  756. setSummaryInfo(rstData.grouped, rstData.summaryInfo.grouped);
  757. setSummaryInfo(rstData.ungrouped, rstData.summaryInfo.ungrouped);
  758. }
  759. let treeDatas = getTreeDatas(rstData.grouped, rstData.ungrouped);
  760. setPermissionsInfo(treeDatas);
  761. tree = pmTree.createNew(treeSetting, treeDatas);
  762. tree.selected = tree.items[0];
  763. showTreeData(tree.items, headers);
  764. //初始选择
  765. let initSel = spreadObj.sheet.getSelections()[0] ? spreadObj.sheet.getSelections()[0] : {row: 0, rowCount: 1};
  766. initSelection(initSel);
  767. autoFlashHeight();
  768. spreadObj.sheet.frozenColumnCount(4);
  769. spreadObj.workBook.refresh();
  770. $.bootstrapLoading.end();
  771. });
  772. }
  773. //初始化右键菜单
  774. function initContextMenu() {
  775. $.contextMenu({
  776. selector: '#shareSpread',
  777. build: function ($trigger, e) {
  778. let target = SheetDataHelper.safeRightClickSelection($trigger, e, spreadObj.workBook);
  779. initSelection({row: target.row, rowCount: 1}, preSelection ? preSelection : null, spreadObj.sheet);
  780. return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
  781. },
  782. items: {
  783. "copy": {
  784. name: "拷贝工程",
  785. icon: 'fa-copy',
  786. disabled: function () {
  787. let selected = tree.selected;
  788. return !(selected && selected.data.allowCopy && selected.data.projType === projectType.tender);
  789. },
  790. callback: function (key, opt) {
  791. $('#copyShare').modal('show');
  792. }
  793. },
  794. "copyProject": {
  795. name: "拷贝建设项目",
  796. icon: 'fa-copy',
  797. disabled: function () {
  798. let selected = tree.selected;
  799. return !(selected && selected.data.allowCopy && selected.data.projType === projectType.project);
  800. },
  801. callback: function (key, opt) {
  802. /* if($(".p-title").text().includes('免费')){
  803. hintBox.versionBox('此功能仅在专业版中提供,免费版可选择单位工程进行拷贝');
  804. return;
  805. } */
  806. copyContructionProject(tree.selected);
  807. }
  808. },
  809. "cancel": {
  810. name: "清除",
  811. icon: 'fa-remove',
  812. disabled: function () {
  813. let selected = tree.selected;
  814. return !(selected && selected.data.cancel && selected.data.cancel === '清除');
  815. },
  816. callback: function (key, opt) {
  817. let $p = $('<p>').text(`点“确定”按钮,确认清除分享文件 “${tree.selected.data.name}”。`);
  818. $('#cancelShare').find('.modal-body').empty();
  819. $('#cancelShare').find('.modal-body').append($p);
  820. $('#cancelShare').modal('show');
  821. }
  822. }
  823. }
  824. });
  825. }
  826. //初始化视图
  827. //@return void
  828. function initView(){
  829. if(tree){
  830. tree = null;
  831. }
  832. if(spreadObj.workBook){
  833. spreadObj.workBook.destroy();
  834. spreadObj.workBook = null;
  835. }
  836. initContextMenu();
  837. buildSheet();
  838. initShareTree();
  839. }
  840. //根据建设项目获取单项工程
  841. //@param {Number}projID @return {void}
  842. function setEng(projID){
  843. let engQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], projType: projectType.engineering, userID: userID, ParentID: projID};
  844. CommonAjax.post('/pm/api/getProjectsByQuery', {user_id: userID, query: engQuery, options: '-_id -property'}, function (rstData) {
  845. $('#copyShare_selectEng').empty();
  846. for(let eng of rstData){
  847. let opt = $('<option>').val(eng.ID).text(eng.name);
  848. $('#copyShare_selectEng').append(opt);
  849. }
  850. });
  851. }
  852. //从其他建设项目中复制中,建设项目的文件层次结构名称和顺序
  853. //@param {Array}treeData @return {Array}
  854. function getFileHierarchyInfo(treeData){
  855. curCopySelTree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1});
  856. curCopySelTree.loadDatas(treeData);
  857. let items = curCopySelTree.items;
  858. let rst = [];
  859. function getFileHierarchyName(node){
  860. let nodeName = node.data.name;
  861. let name = [];
  862. while (node.parent){
  863. name.push(node.parent.data.name ? node.parent.data.name : '');
  864. node = node.parent;
  865. }
  866. name = name.reverse();
  867. name.push(nodeName);
  868. return name.join('\\');
  869. }
  870. for(let node of items){
  871. if(node.children.length === 0 ){//project
  872. rst.push({ID: node.data.ID, fileHierarchyName: getFileHierarchyName(node)})
  873. }
  874. }
  875. return rst;
  876. }
  877. //设置拷贝工程下拉选择
  878. //@return {void}
  879. function setCopyModal(){
  880. //获取建设项目
  881. let projQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], projType: {$in: [projectType.project, projectType.folder]}, userID: userID};
  882. CommonAjax.post('/pm/api/getProjectsByQuery', {user_id: userID, query: projQuery, options: '-_id'}, function (rstData) {
  883. let fileHierarchyData = getFileHierarchyInfo(rstData);
  884. $('#copyShare_selectProj').empty();
  885. for(let proj of fileHierarchyData){
  886. let opt = $('<option>').val(proj.ID).text(proj.fileHierarchyName);
  887. $('#copyShare_selectProj').append(opt);
  888. }
  889. //初始选择
  890. if(fileHierarchyData.length > 0){
  891. setEng(fileHierarchyData[0].ID);
  892. }
  893. });
  894. }
  895. //拷贝分享的工程
  896. //@param {Object}selected {Number}parentID @return {void}
  897. async function copyShareProject(selected, projID, engID){
  898. try {
  899. if(!engID || !selected){
  900. return;
  901. }
  902. let copyMap = {copy: null, update: null};
  903. let newName = $('#copyShare_name').val();
  904. if (!newName) {
  905. $('#copyShareTender-info').text('单位工程名称不可为空');
  906. $('#copyShareTender-info').show();
  907. return;
  908. }
  909. //获取单项工程的单位工程
  910. let tenderQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], userID: userID, ParentID: engID};
  911. const rstData = await ajaxPost('/pm/api/getProjectsByQuery', {user_id: userID, query: tenderQuery, options: '-_id -property'}, false, 10000);
  912. let updateTender = null;
  913. for(let tender of rstData){
  914. if(tender.name === newName){
  915. $('#copyShareTender-info').text('已存在同名单位工程');
  916. $('#copyShareTender-info').show();
  917. return;
  918. }
  919. if(tender.NextSiblingID == -1){
  920. updateTender = tender;
  921. }
  922. }
  923. //更新前节点
  924. if(updateTender){
  925. copyMap.update = {query: {ID: updateTender.ID}};
  926. }
  927. //拷贝
  928. let copyData = {
  929. userID: userID,
  930. ID: selected.data.actualTreeInfo.ID,
  931. NextSiblingID: -1,
  932. ParentID: engID,
  933. name: newName,
  934. shareInfo: [],
  935. compilation: selected.data.compilation,
  936. createDateTime: selected.data.createDateTime,
  937. fileVer: selected.data.fileVer ? selected.data.fileVer : '',
  938. projType: selected.data.projType,
  939. property: {},
  940. recentDateTime: selected.data.recentDateTime,
  941. fullFolder: selected.data.fullFolder
  942. };
  943. copyData.property.rootProjectID = projID;
  944. copyMap.copy = {document: copyData};
  945. $('#copyShare').modal('hide');
  946. $.bootstrapLoading.progressStart('拷贝项目', true);
  947. $("#progress_modal_body").text('正在拷贝项目,请稍候……');
  948. await ajaxPost('/pm/api/copyProjects', {projectMap: copyMap, user_id: userID, tenderCount: 1});
  949. importProcessChecking(null, null, projTreeObj.emitTreeChange);
  950. } catch (err) {
  951. alert(err);
  952. }
  953. }
  954. let projectQueryResult = [];
  955. //拷贝分享的建设项目
  956. //@param {Object}selected
  957. async function copyContructionProject(selected, rename){
  958. try {
  959. let newName = rename ? rename : getCopyName(selected);
  960. //获取单项工程的单位工程
  961. let projectQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], userID: userID,projType: "Project"};
  962. projectQueryResult = await ajaxPost('/pm/api/getProjectsByQuery', {user_id: userID, query: projectQuery, options: '-_id -property'}, false, 10000);
  963. for(let project of projectQueryResult){
  964. if(project.name === newName){
  965. $("#share-rename-dialog").modal('show');
  966. $("#share-rename-input").val(newName);
  967. return;
  968. }
  969. }
  970. let tenderCount = 0;
  971. if(selected.children) {
  972. for(let c of selected.children){
  973. if(c.children) tenderCount += c.children.length;
  974. }
  975. }
  976. let key = uuid.v1();
  977. $.bootstrapLoading.progressStart('拷贝建设项目', true);
  978. $("#progress_modal_body").text('正在拷贝建设项目,请稍候……');
  979. await ajaxPost('/pm/api/copyConstructionProject', {user_id: userID, tenderCount: tenderCount,key:key,projectID:selected.data.actualTreeInfo.ID,newName:newName});
  980. importProcessChecking(key, null, projTreeObj.emitTreeChange);
  981. } catch (error) {
  982. console.log(error);
  983. }
  984. }
  985. //获取拷贝后的名称
  986. //@param {Object}node @return {String}
  987. function getCopyName(node) {
  988. //当前单位工程可能没有分享的用户信息,可能他人分享的是父级文件,userInfo在父级文件中
  989. let orgName = node.data.name,
  990. userInfo = node.data.userInfo;
  991. while (node && !userInfo) {
  992. node = node.parent;
  993. userInfo = node.data.userInfo;
  994. }
  995. return `${orgName}`;
  996. }
  997. //清除了该节点后,可能还有该节点的数据在树上(树允许有重复数据),需要更新分享信息
  998. function updateAfterCancel(userID, projectID) {
  999. for (let item of tree.items) {
  1000. if (item.data.actualTreeInfo && item.data.actualTreeInfo.ID === projectID) {
  1001. _.remove(item.data.shareInfo, function (data) {
  1002. return data.userID === userID;
  1003. });
  1004. }
  1005. }
  1006. }
  1007. // 处理节点操作属性变更(是否可拷贝、是否可编辑)
  1008. function handlePropChange(projectID, prop) {
  1009. const actualShareData = actualIDShareInfo[projectID];
  1010. if (actualShareData) {
  1011. const shareItem = actualShareData.shareInfo.find(s => s.userID === userID);
  1012. if(shareItem) {
  1013. Object.assign(shareItem, prop);
  1014. }
  1015. }
  1016. const nodes = getNodesByActualID(projectID, tree.items);
  1017. nodes.forEach(node => {
  1018. const shareItem = node.data.shareInfo.find(s => s.userID === userID);
  1019. if(shareItem) {
  1020. Object.assign(shareItem, prop);
  1021. }
  1022. });
  1023. const treeData = tree.items.map(item => item.data);
  1024. setPermissionsInfo(treeData);
  1025. showTreeData(tree.items, headers);
  1026. }
  1027. // 处理清除
  1028. /* function handleCancelShare(cancelProjID, callback) {
  1029. $.bootstrapLoading.start();
  1030. CommonAjax.post('/pm/api/share', {user_id: userID, type: oprType.cancel, projectID: cancelProjID, shareData:[{userID: userID}]}, function (rstData) {
  1031. const node = tree.items.find(item => item.data.actualTreeInfo && item.data.actualTreeInfo.ID === cancelProjID);
  1032. if (node) {
  1033. tree.removeNode(node);
  1034. }
  1035. //更新与清除节点数据相同,且未被清除缓存分享信息
  1036. updateAfterCancel(userID, cancelProjID);
  1037. //重新设置actualIDShareInfo,以正确更新权限(清除了分享信息后,可能会导致权限变化 eg:清除了新的分享,则存留的分享项目采用旧的)
  1038. actualIDShareInfo = {};
  1039. let treeDatas = [];
  1040. for (let item of tree.items) {
  1041. treeDatas.push(item.data);
  1042. let actualTreeInfo = item.data.actualTreeInfo;
  1043. if (actualTreeInfo && !actualIDShareInfo[actualTreeInfo.ID]) {
  1044. actualIDShareInfo[actualTreeInfo.ID] = {
  1045. ID: actualTreeInfo.ID,
  1046. ParentID: actualTreeInfo.ParentID,
  1047. NextSiblingID: actualTreeInfo.NextSiblingID,
  1048. shareInfo: item.data.shareInfo
  1049. };
  1050. }
  1051. }
  1052. //重新设置权限
  1053. setPermissionsInfo(treeDatas);
  1054. showTreeData(tree.items, headers);
  1055. $.bootstrapLoading.end();
  1056. if (callback) {
  1057. callback(rstData);
  1058. }
  1059. }, function () {
  1060. $.bootstrapLoading.end();
  1061. });
  1062. } */
  1063. function handleCancelShare(cancelProjID) {
  1064. const node = tree.items.find(item => item.data.actualTreeInfo && item.data.actualTreeInfo.ID === cancelProjID);
  1065. if (node) {
  1066. tree.removeNode(node);
  1067. }
  1068. //更新与清除节点数据相同,且未被清除缓存分享信息
  1069. updateAfterCancel(userID, cancelProjID);
  1070. //重新设置actualIDShareInfo,以正确更新权限(清除了分享信息后,可能会导致权限变化 eg:清除了新的分享,则存留的分享项目采用旧的)
  1071. actualIDShareInfo = {};
  1072. let treeDatas = [];
  1073. for (let item of tree.items) {
  1074. treeDatas.push(item.data);
  1075. let actualTreeInfo = item.data.actualTreeInfo;
  1076. if (actualTreeInfo && !actualIDShareInfo[actualTreeInfo.ID]) {
  1077. actualIDShareInfo[actualTreeInfo.ID] = {
  1078. ID: actualTreeInfo.ID,
  1079. ParentID: actualTreeInfo.ParentID,
  1080. NextSiblingID: actualTreeInfo.NextSiblingID,
  1081. shareInfo: item.data.shareInfo
  1082. };
  1083. }
  1084. }
  1085. //重新设置权限
  1086. setPermissionsInfo(treeDatas);
  1087. showTreeData(tree.items, headers);
  1088. }
  1089. //事件监听器
  1090. //@return void
  1091. function eventListener(){
  1092. //tab
  1093. $('#tab_pm_share').on('shown.bs.tab', function () {
  1094. //侧滑隐藏
  1095. $('.slide-sidebar').removeClass('open');
  1096. $('.slide-sidebar').css('width', '0');
  1097. projTreeObj.tree = null;
  1098. if(projTreeObj.workBook){
  1099. projTreeObj.workBook.destroy();
  1100. projTreeObj.workBook = null;
  1101. }
  1102. gcTreeObj.tree = null;
  1103. if(gcTreeObj.workBook){
  1104. gcTreeObj.workBook.destroy();
  1105. gcTreeObj.workBook = null;
  1106. }
  1107. initView();
  1108. });
  1109. //关闭拷贝工程
  1110. $('#copyShare').on('hidden.bs.modal', function () {
  1111. $('#copyShareProj-info').hide();
  1112. $('#copyShareEng-info').hide();
  1113. });
  1114. //打开拷贝工程
  1115. $('#copyShare').on('shown.bs.modal', function () {
  1116. setCopyModal();
  1117. //更改显示名称
  1118. $('#copyShare_name').val(shareSeleted.data.name);
  1119. });
  1120. //拷贝工程改变选择建设项目
  1121. $('#copyShare_selectProj').change(function () {
  1122. $('#copyShareProj-info').hide();
  1123. $('#copyShareEng-info').hide();
  1124. $('#copyShareTender-info').hide();
  1125. let curSelID = $(this).select().val();
  1126. setEng(parseInt(curSelID));
  1127. });
  1128. //拷贝工程改变选择单项工程
  1129. $('#copyShare_selectEng').change(function () {
  1130. $('#copyShareTender-info').hide();
  1131. });
  1132. //确认拷贝
  1133. $('#copyShare_confirm').click(function () {
  1134. let selProj = $('#copyShare_selectProj').select().val();
  1135. if(!selProj){
  1136. $('#copyShareProj-info').show();
  1137. return;
  1138. }
  1139. //目标建设项目的计税方法与单位工程的一致时,才可拷贝
  1140. if (curCopySelTree) {
  1141. let projectNode = curCopySelTree.nodes[curCopySelTree.prefix + selProj];
  1142. if (!projectNode || !projectNode.data.property || projectNode.data.property.taxType != tree.selected.data.taxType){
  1143. alert('当前单位工程计税方法与目标建设项目不一致,不可复制。');
  1144. return;
  1145. }
  1146. }
  1147. let selEng = $('#copyShare_selectEng').select().val();
  1148. if(!selEng){
  1149. $('#copyShareEng-info').show();
  1150. return;
  1151. }
  1152. copyShareProject(tree.selected, parseInt(selProj), parseInt(selEng));
  1153. });
  1154. //清除分享
  1155. $('#cancelShareConfirm').click(function (data) {
  1156. $.bootstrapLoading.start();
  1157. const cancelProjID = tree.selected.data.actualTreeInfo.ID;
  1158. const permissionType = commonConstants.SharePermissionChangeType.CANCEL;
  1159. CommonAjax.post('/pm/api/share', { user_id: userID, type: oprType.cancel, permissionType, projectID: cancelProjID, shareData: [{ userID: userID }] }, function (rstData) {
  1160. handleCancelShare(cancelProjID);
  1161. // 推送已打开的项目,通知已取消分享
  1162. SHARE_TO.emitPermissionChange(permissionType, userID, cancelProjID, rstData.emitTenders);
  1163. // 清除已读
  1164. SHARE_TO.removeUnread(cancelProjID, unreadShareList);
  1165. $.bootstrapLoading.end();
  1166. }, function () {
  1167. $.bootstrapLoading.end();
  1168. });
  1169. });
  1170. // 拷贝重命名
  1171. $('#share-rename-dialog').on('show.bs.modal', () => {
  1172. $('#share-rename-info').hide();
  1173. setTimeout(() => {
  1174. $('#share-rename-input').focus();
  1175. }, 200)
  1176. });
  1177. $('#share-rename-confirm').click(function () {
  1178. const newName = $('#share-rename-input').val().trim();
  1179. for(let project of projectQueryResult){
  1180. if(project.name === newName){
  1181. $('#share-rename-info').text(`已存在 “${newName}”`);
  1182. $('#share-rename-info').show();
  1183. return;
  1184. }
  1185. }
  1186. $("#share-rename-dialog").modal('hide');
  1187. copyContructionProject(tree.selected, newName);
  1188. });
  1189. }
  1190. return {
  1191. spreadObj,
  1192. headers,
  1193. initView,
  1194. eventListener,
  1195. initShareTree,
  1196. handlePropChange,
  1197. handleCancelShare,
  1198. handleMarkRead
  1199. }
  1200. })();
  1201. $(document).ready(function () {
  1202. pmShare.eventListener();
  1203. });