|
@@ -16,7 +16,8 @@ const pmShare = (function () {
|
|
|
const shareType = {receive: 'receive', shareTo: 'shareTo'};
|
|
|
//操作类型
|
|
|
const oprType = {copy: 'copy', cancel: 'cancel'};
|
|
|
- let tree = null;
|
|
|
+ let tree = null,
|
|
|
+ actualIDShareInfo = {};//项目真实树ID与项目分享信息映射
|
|
|
const treeCol = 0;
|
|
|
const treeSetting = {
|
|
|
tree: {
|
|
@@ -29,9 +30,8 @@ const pmShare = (function () {
|
|
|
};
|
|
|
const headers = [
|
|
|
{name: '工程列表', dataCode: 'name', width: 300, rateWidth: 0.55, vAlign: 'center', hAlign: 'left'},
|
|
|
- {name: '由...分享', dataCode: 'from', width: 120, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},
|
|
|
- /* {name: '拷贝工程', dataCode: 'copy', width: 100, rateWidth: 0.075, vAlign: 'center', hAlign: 'left'},
|
|
|
- {name: '清除', dataCode: 'cancel', width: 100, rateWidth: 0.075, vAlign: 'center', hAlign: 'left'},*/
|
|
|
+ {name: '来自', dataCode: 'from', width: 80, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},
|
|
|
+ {name: '分享时间', dataCode: 'shareDate', width: 140, rateWidth: 0.15, vAlign: 'center', hAlign: 'left'},
|
|
|
{name: '工程造价', dataCode: 'engineeringCost', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
|
|
|
{name: '分部分项合计', dataCode: 'subEngineering', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
|
|
|
{name: '措施项目合计', dataCode: 'measure', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
|
|
@@ -125,12 +125,6 @@ const pmShare = (function () {
|
|
|
if(headers[i].formatter){
|
|
|
sheet.setFormatter(-1, i, headers[i].formatter);
|
|
|
}
|
|
|
- /* if(headers[i].dataCode === oprType.copy){
|
|
|
- //合并列
|
|
|
- sheet.addSpan(0, i, 1, 2, GC.Spread.Sheets.SheetArea.colHeader);
|
|
|
- sheet.setValue(0, i, '操作', GC.Spread.Sheets.SheetArea.colHeader);
|
|
|
- continue;
|
|
|
- }*/
|
|
|
sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
|
|
|
sheet.getRange(-1, i, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[i]['hAlign']]);
|
|
|
sheet.getRange(-1, i, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[i]['vAlign']]);
|
|
@@ -162,15 +156,56 @@ const pmShare = (function () {
|
|
|
spreadObj.sheet.getRange(-1, -1, -1, -1).locked(true);
|
|
|
|
|
|
}
|
|
|
+ //此项目的分享权限信息(可能会被父级项目覆盖,以新为准)
|
|
|
+ //@param {String}userID(本用户id) {Object}project(项目) @return {Object} || {Null}
|
|
|
+ function getShareInfo(userID, project) {
|
|
|
+ if (!project.actualTreeInfo) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ //获取跟本用户和选中项目相关的分享信息
|
|
|
+ let shareList = [];
|
|
|
+ let actualID = project.actualTreeInfo.ID,
|
|
|
+ actualData = actualIDShareInfo[actualID];
|
|
|
+ while (actualData) {
|
|
|
+ for (let data of actualData.shareInfo) {
|
|
|
+ if (data.userID === userID) {
|
|
|
+ shareList.push(data);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ actualData = actualIDShareInfo[actualData.ParentID];
|
|
|
+ }
|
|
|
+ //获取最新分享
|
|
|
+ shareList.sort(function (a, b) {
|
|
|
+ let aV = Date.parse(a.shareDate),
|
|
|
+ bV = Date.parse(b.shareDate);
|
|
|
+ if (aV > bV) {
|
|
|
+ return -1;
|
|
|
+ } else if (aV < bV) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ });
|
|
|
+ return shareList[0] || null;
|
|
|
+
|
|
|
+ }
|
|
|
//此项目是否可以拷贝
|
|
|
//@param {String}userID {Object}project @return {Boolean}
|
|
|
function isAllowCopy(userID, project){
|
|
|
- for(let shareData of project.shareInfo){
|
|
|
- if(shareData.userID === userID){
|
|
|
- return shareData.allowCopy;
|
|
|
- }
|
|
|
+ let myShareInfo = getShareInfo(userID, project);
|
|
|
+ if (!myShareInfo) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return !!myShareInfo.allowCopy;
|
|
|
+ }
|
|
|
+ //此项目是否可以协作
|
|
|
+ //@param {String}userID {Object}project @return {Boolean}
|
|
|
+ function isAllowCoop(userID, project) {
|
|
|
+ let myShareInfo = getShareInfo(userID, project);
|
|
|
+ if (!myShareInfo) {
|
|
|
+ return false;
|
|
|
}
|
|
|
- return false;
|
|
|
+ return !!myShareInfo.allowCooperate;
|
|
|
}
|
|
|
//获取树节点
|
|
|
//@param {Object}tree @return {Object}
|
|
@@ -398,9 +433,44 @@ const pmShare = (function () {
|
|
|
}
|
|
|
//互动单元格
|
|
|
function getInteractionCell() {
|
|
|
+ let workImg = document.getElementById('work_pic'),
|
|
|
+ workImgWidth = 13,
|
|
|
+ workImgHeight = 13,
|
|
|
+ copyImg = document.getElementById('copy_pic'),
|
|
|
+ copyImgWidth = 13,
|
|
|
+ copyImgHeight = 13;
|
|
|
let InteractionCell = function () {
|
|
|
};
|
|
|
InteractionCell.prototype = new GC.Spread.Sheets.CellTypes.Text();
|
|
|
+ InteractionCell.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
|
|
|
+ if (style.backColor) {
|
|
|
+ ctx.save();
|
|
|
+ ctx.fillStyle = style.backColor;
|
|
|
+ ctx.fillRect(x, y, w, h);
|
|
|
+ ctx.restore();
|
|
|
+ } else {
|
|
|
+ ctx.clearRect(x, y, w, h);
|
|
|
+ }
|
|
|
+ let node = tree.items[options.row];
|
|
|
+ // Draw Text
|
|
|
+ GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
|
|
|
+ if (node && node.data.projType === projectType.tender) {
|
|
|
+ let text = options.sheet.getText(options.row, options.col);
|
|
|
+ let acStyle = options.sheet.getActualStyle(options.row, options.col),
|
|
|
+ zoom = options.sheet.zoom();
|
|
|
+ let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: options.sheet, row: options.row, col: options.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
|
|
|
+ let nowX = Math.floor(x) + textLength + 3,
|
|
|
+ nowY = Math.floor((y + (y + h)) / 2) - 7;
|
|
|
+ if (node.data.allowCooperate) {
|
|
|
+ ctx.drawImage(workImg, nowX, nowY, workImgWidth, workImgHeight);
|
|
|
+ nowX += workImgWidth;
|
|
|
+ }
|
|
|
+ if (node.data.allowCopy) {
|
|
|
+ ctx.drawImage(copyImg, nowX, nowY, copyImgWidth, copyImgHeight);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
InteractionCell.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
|
|
|
return {
|
|
|
x: x,
|
|
@@ -434,36 +504,6 @@ const pmShare = (function () {
|
|
|
$('#userinfo').modal('show');
|
|
|
}
|
|
|
}
|
|
|
- //分享给
|
|
|
- else if(dataCode === 'to'){
|
|
|
- if(node.data.shareType === shareType.shareTo){
|
|
|
- setShareToModal(node);
|
|
|
- $('#shareTo').modal('show');
|
|
|
- }
|
|
|
- }
|
|
|
- //操作
|
|
|
- else if(dataCode === oprType.copy){
|
|
|
- /* if(node.data.copy === '添加分享'){
|
|
|
- $('#sharePhone').val('');
|
|
|
- $('#share-info').hide();
|
|
|
- $('#share').find('.card').hide();
|
|
|
- $('#share').modal('show');
|
|
|
- $('#allowCopy').prop('checked', false);
|
|
|
- $('#allowCopyHint').hide();
|
|
|
- }
|
|
|
- else*/
|
|
|
- if(node.data.copy === '拷贝工程'){
|
|
|
- $('#copyShare').modal('show');
|
|
|
- }
|
|
|
- }
|
|
|
- else if (dataCode === oprType.cancel) {
|
|
|
- if (node.data.cancel === '清除') {
|
|
|
- let $p = $('<p>').text(`点“确定”按钮,确认清除分享文件 “${node.data.name}”。`);
|
|
|
- $('#cancelShare').find('.modal-body').empty();
|
|
|
- $('#cancelShare').find('.modal-body').append($p);
|
|
|
- $('#cancelShare').modal('show');
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
};
|
|
|
InteractionCell.prototype.processMouseMove = function (hitInfo) {
|
|
@@ -573,45 +613,28 @@ const pmShare = (function () {
|
|
|
sheet.getRange(-1, j, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[headers[j]['hAlign']]);
|
|
|
sheet.getRange(-1, j, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[headers[j]['vAlign']]);
|
|
|
let dataCode = headers[j].dataCode;
|
|
|
- if(dataCode === oprType.copy){
|
|
|
+ if(dataCode === 'from'){
|
|
|
let style = new GC.Spread.Sheets.Style();
|
|
|
style.foreColor = foreColor;
|
|
|
sheet.setStyle(i, j, style);
|
|
|
sheet.getCell(i, j).cellType(getInteractionCell());
|
|
|
}
|
|
|
- else if (dataCode === oprType.cancel) {
|
|
|
- let style = new GC.Spread.Sheets.Style();
|
|
|
- style.foreColor = cancelForeColor;
|
|
|
- sheet.setStyle(i, j, style);
|
|
|
- sheet.getCell(i, j).cellType(getInteractionCell());
|
|
|
- }
|
|
|
- else if(dataCode === 'from'){
|
|
|
- if(nodes[i].data.shareType && nodes[i].data.shareType === shareType.receive){
|
|
|
- let style = new GC.Spread.Sheets.Style();
|
|
|
- style.foreColor = foreColor;
|
|
|
- sheet.setStyle(i, j, style);
|
|
|
- sheet.getCell(i, j).cellType(getInteractionCell());
|
|
|
- }
|
|
|
- }
|
|
|
- else if(dataCode === 'to'){
|
|
|
- if(nodes[i].data.shareType && nodes[i].data.shareType === shareType.shareTo){
|
|
|
- let style = new GC.Spread.Sheets.Style();
|
|
|
- style.foreColor = foreColor;
|
|
|
- sheet.setStyle(i, j, style);
|
|
|
- sheet.getCell(i, j).cellType(getInteractionCell());
|
|
|
- }
|
|
|
- }
|
|
|
sheet.setValue(i, j, nodes[i].data[dataCode] !== null && typeof nodes[i].data[dataCode] !== 'undefined' ? nodes[i].data[dataCode] : '');
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
renderSheetFunc(sheet, fuc);
|
|
|
}
|
|
|
- //同一棵树,可能存在相同数据显示多条的问题(传入的datas中不存在相同数据),将真实树结构数据存在actualTreeInfo中,外部树结构数据用uuid重置。
|
|
|
+ //同一棵树,可能存在相同数据显示多条的问题(传入的datas中不存在相同数据)
|
|
|
+ //将真实树结构数据存在actualTreeInfo中,外部树结构数据用uuid重置。
|
|
|
//@param {Array}datas
|
|
|
function setTreeInfo(datas) {
|
|
|
let IDMapping = {};
|
|
|
for (let data of datas) {
|
|
|
+ //项目真实ID与项目分享信息映射,方便确定项目的权限
|
|
|
+ if (!actualIDShareInfo[data.ID]) {
|
|
|
+ actualIDShareInfo[data.ID] = {ID: data.ID, ParentID: data.ParentID, NextSiblingID: data.NextSiblingID, shareInfo: data.shareInfo};
|
|
|
+ }
|
|
|
IDMapping[data.ID] = uuid.v1();
|
|
|
}
|
|
|
for (let data of datas) {
|
|
@@ -631,21 +654,17 @@ const pmShare = (function () {
|
|
|
data.ParentID = pid;
|
|
|
}
|
|
|
}
|
|
|
- //给项目设置分享信息:由xx分享、分享给我、可进行的操作,含有userInfo信息的文件为他人直接分享的文件,他人分享父级文件,子文件不含有userInfo信息
|
|
|
+ //给项目设置分享信息:由xx分享、分享时间、分享给我,含有userInfo信息的文件为他人直接分享的文件,他人分享父级文件,子文件不含有userInfo信息
|
|
|
//@param {Array}datas @return {void}
|
|
|
function setShareInfo(datas) {
|
|
|
for (let data of datas) {
|
|
|
if (data.userInfo) {
|
|
|
- data.from = `由 ${data.userInfo.name} 分享`;
|
|
|
+ //shareInfo中我的条目
|
|
|
+ let selfInfo = _.find(data.shareInfo, {userID: userID});
|
|
|
+ data.shareDate = selfInfo ? selfInfo.shareDate : ''
|
|
|
+ data.from = data.userInfo.name;
|
|
|
data.to = '分享给 我';
|
|
|
data.cancel = '清除';
|
|
|
-
|
|
|
- //拷贝操作只允许到单位工程级
|
|
|
- let tendersCanCopy = isAllowCopy(userID, data);
|
|
|
- let tenders = data.projType === projectType.tender ? [data] : _.filter(data.children, {projType: projectType.tender});
|
|
|
- for (let tender of tenders) {
|
|
|
- tender.copy = tendersCanCopy ? '拷贝工程' : '';
|
|
|
- }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -678,6 +697,30 @@ const pmShare = (function () {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ //从同层树数据获取第一个节点ID
|
|
|
+ //@param {Array}treeDatas树的数据 @return {String}第一个节点的虚拟树ID
|
|
|
+ function getFirstID(treeDatas) {
|
|
|
+ let treeMapping = {};
|
|
|
+ //建立ID索引
|
|
|
+ for (let data of treeDatas) {
|
|
|
+ //新建一个简单对象,防止污染treeDatas的数据
|
|
|
+ treeMapping[data.ID] = {ID: data.ID, prev: null, next: null};
|
|
|
+ }
|
|
|
+ //绑定prev next
|
|
|
+ for (let data of treeDatas) {
|
|
|
+ let me = treeMapping[data.ID],
|
|
|
+ next = treeMapping[data.NextSiblingID];
|
|
|
+ if (next) {
|
|
|
+ me.next = next;
|
|
|
+ next.prev = me;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //返回没有prev属性的数据
|
|
|
+ let result = _.find(treeDatas, function (data) {
|
|
|
+ return !treeMapping[data.ID].prev
|
|
|
+ });
|
|
|
+ return result ? result.ID : -1;
|
|
|
+ }
|
|
|
//获取可成树的数据
|
|
|
//@param {Array}datas @return {Array}
|
|
|
function getTreeDatas(groupedDatas, ungroupedDatas){
|
|
@@ -694,12 +737,14 @@ const pmShare = (function () {
|
|
|
let rst = [];
|
|
|
//整理树结构
|
|
|
sortSameDepthData(groupedDatas, -1);
|
|
|
+ //第一个根节点数据
|
|
|
+ let firstID = getFirstID(groupedDatas);
|
|
|
//新建未分类建设项目及单项工程
|
|
|
- let ungroupedProj = {ID: uuid.v1(), ParentID: -1, NextSiblingID: -1, name: '未分类建设项目', projType: projectType.project};
|
|
|
+ let ungroupedProj = {ID: uuid.v1(), ParentID: -1, NextSiblingID: firstID, name: '未分类建设项目', projType: projectType.project};
|
|
|
let ungroupedEng = {ID: uuid.v1(), ParentID: ungroupedProj.ID, NextSiblingID: -1, name: '未分类单项工程', projType: projectType.engineering};
|
|
|
- if (groupedDatas.length > 0) {
|
|
|
+ /*if (groupedDatas.length > 0) {
|
|
|
groupedDatas[groupedDatas.length - 1].NextSiblingID = ungroupedProj.ID;
|
|
|
- }
|
|
|
+ }*/
|
|
|
//将未分类的数据归类
|
|
|
sortSameDepthData(engs, ungroupedProj.ID);
|
|
|
sortSameDepthData(tenders, ungroupedEng.ID);
|
|
@@ -735,6 +780,19 @@ const pmShare = (function () {
|
|
|
return 0;
|
|
|
});
|
|
|
}
|
|
|
+ //设置节点数据权限
|
|
|
+ //@param {Array}datas项目数据
|
|
|
+ function setPermissionsInfo(datas) {
|
|
|
+ //data.allowCopy与shareInfo里allowCopy的区别:
|
|
|
+ //data.allowCopy为该单位实际的权限(跟着最新的分享信息走,可能随着父项)
|
|
|
+ for (let data of datas) {
|
|
|
+ if (data.projType === projectType.tender) {
|
|
|
+ data.allowCopy = isAllowCopy(userID, data);
|
|
|
+ data.allowCooperate = isAllowCoop(userID, data);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
//建立树
|
|
|
//@return void
|
|
|
function initShareTree(){
|
|
@@ -750,6 +808,7 @@ const pmShare = (function () {
|
|
|
setSummaryInfo(rstData.ungrouped, rstData.summaryInfo.ungrouped);
|
|
|
}
|
|
|
let treeDatas = getTreeDatas(rstData.grouped, rstData.ungrouped);
|
|
|
+ setPermissionsInfo(treeDatas);
|
|
|
tree = pmTree.createNew(treeSetting, treeDatas);
|
|
|
tree.selected = tree.items[0];
|
|
|
showTreeData(tree.items, headers);
|
|
@@ -777,7 +836,7 @@ const pmShare = (function () {
|
|
|
icon: 'fa-copy',
|
|
|
disabled: function () {
|
|
|
let selected = tree.selected;
|
|
|
- return !(selected && selected.data.copy && selected.data.copy === '拷贝工程');
|
|
|
+ return !(selected && selected.data.allowCopy);
|
|
|
},
|
|
|
callback: function (key, opt) {
|
|
|
$('#copyShare').modal('show');
|
|
@@ -1001,12 +1060,42 @@ const pmShare = (function () {
|
|
|
copyShareProject(tree.selected, parseInt(selProj), parseInt(selEng));
|
|
|
});
|
|
|
//清除分享
|
|
|
+ //清除了该节点后,可能还有该节点的数据在树上(树允许有重复数据),需要更新分享信息
|
|
|
+ function updateAfterCancel(userID, projectID) {
|
|
|
+ for (let item of tree.items) {
|
|
|
+ if (item.data.actualTreeInfo && item.data.actualTreeInfo.ID === projectID) {
|
|
|
+ _.remove(item.data.shareInfo, function (data) {
|
|
|
+ return data.userID === userID;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
$('#cancelShareConfirm').click(function () {
|
|
|
$.bootstrapLoading.start();
|
|
|
- CommonAjax.post('/pm/api/share', {user_id: userID, type: oprType.cancel, projectID: tree.selected.data.actualTreeInfo.ID, shareData:[{userID: userID}]}, function (rstData) {
|
|
|
- $.bootstrapLoading.end();
|
|
|
+ let cancelProjID = tree.selected.data.actualTreeInfo.ID;
|
|
|
+ CommonAjax.post('/pm/api/share', {user_id: userID, type: oprType.cancel, projectID: cancelProjID, shareData:[{userID: userID}]}, function (rstData) {
|
|
|
tree.removeNode(tree.selected);
|
|
|
+ //更新与清除节点数据相同,且为被清除缓存分享信息
|
|
|
+ updateAfterCancel(userID, cancelProjID);
|
|
|
+ //重新设置actualIDShareInfo,以正确更新权限(清除了分享信息后,可能会导致权限变化 eg:清除了新的分享,则存留的分享项目采用旧的)
|
|
|
+ actualIDShareInfo = {};
|
|
|
+ let treeDatas = [];
|
|
|
+ for (let item of tree.items) {
|
|
|
+ treeDatas.push(item.data);
|
|
|
+ let actualTreeInfo = item.data.actualTreeInfo;
|
|
|
+ if (actualTreeInfo && !actualIDShareInfo[actualTreeInfo.ID]) {
|
|
|
+ actualIDShareInfo[actualTreeInfo.ID] = {
|
|
|
+ ID: actualTreeInfo.ID,
|
|
|
+ ParentID: actualTreeInfo.ParentID,
|
|
|
+ NextSiblingID: actualTreeInfo.NextSiblingID,
|
|
|
+ shareInfo: item.data.shareInfo
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //重新设置权限
|
|
|
+ setPermissionsInfo(treeDatas);
|
|
|
showTreeData(tree.items, headers);
|
|
|
+ $.bootstrapLoading.end();
|
|
|
}, function () {
|
|
|
$.bootstrapLoading.end();
|
|
|
});
|