浏览代码

Merge branch 'master' of http://192.168.1.41:3000/SmartCost/ConstructionCost

Conflicts:
	public/web/socket/connection.js
	web/building_saas/css/custom.css
zhangweicheng 5 年之前
父节点
当前提交
b5756353fa

+ 30 - 0
modules/all_models/stdGlj_lib.js

@@ -0,0 +1,30 @@
+/**
+ * Created by Zhong on 2018/3/23.
+ */
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const oprSchema = require('../all_schemas/opr_schema');
+let gjlMapRationLibsSchema = new Schema(
+    {
+        ID: Number,
+        dispName: String
+    },
+    {_id: false},
+    {versionKey: false}
+);
+let gljMapSchema = new Schema({
+        deleted: Boolean,
+        ID: Number,
+        dispName: String,
+        appType: String,
+        creator: String,
+        createDate: String,
+        recentOpr: [oprSchema],
+        rationLibs: [gjlMapRationLibsSchema],
+        compilationId: String,
+        compilationName: String
+    },
+    {versionKey: false}
+);
+
+mongoose.model('std_glj_lib_map', gljMapSchema, 'std_glj_lib_map');

+ 2 - 1
modules/pm/controllers/pm_controller.js

@@ -258,7 +258,8 @@ module.exports = {
                 projInfo.shareState = await pm_facade.getShareState(projectID, userID);
             }
             // 获取项目所属用户
-            projInfo.owner = await userModel.findOne({_id: mongoose.Types.ObjectId(project.userID)}, 'real_name');
+            projInfo.owner = await userModel.findOne({_id: mongoose.Types.ObjectId(project.userID)}, 'real_name mobile').lean();
+            projInfo.opener = await userModel.findOne({_id: mongoose.Types.ObjectId(userID)}, 'real_name mobile').lean();
             callback('', consts.projectConst.PROJECT_INFO, project);
         }, function (err) {
             callback(err, consts.projectConst.PROJECT_INFO, {});

+ 4 - 3
modules/ration_glj/controllers/ration_glj_controller.js

@@ -63,11 +63,12 @@ async function getGLJDataPaging(req, res) {
     };
     let data = JSON.parse(req.body.data);
     try {
-        let gljLibId = await ration_glj_facade.getGLJLibByEngineerID(data.engineerID);
+        const compilationId = req.session.sessionCompilation._id;
+        const gljLib = await ration_glj_facade.getGLJLib({ compilationId });
         let info = {
-            gljLibId,
+            gljLibId: gljLib.ID,
             userID: req.session.sessionUser.id,
-            compilationId: req.session.sessionCompilation._id
+            compilationId
         };
         result.data = await ration_glj_facade.getGLJDataPaging(info, data.condition);
         if (req.session.sessionCompilation.priceProperties) {

+ 6 - 0
modules/ration_glj/facade/ration_glj_facade.js

@@ -7,6 +7,7 @@ module.exports = {
     deleteByRation: deleteByRation,
     getQuantityByProjectGLJ: getQuantityByProjectGLJ,
     getLibInfo: getLibInfo,
+    getGLJLib,
     getGLJData: getGLJData,
     getGLJDataPaging: getGLJDataPaging,
     getGLJDataByCodes:getGLJDataByCodes,
@@ -53,6 +54,7 @@ import gljType from "../../common/const/glj_type_const.js";
 const complementaryGljModel = mongoose.model('complementary_glj_lib');
 const stdGljModel = mongoose.model('std_glj_lib_gljList');
 const gljClassModel = mongoose.model('std_glj_lib_gljClass');
+const stdGLJLibModel = mongoose.model('std_glj_lib_map');
 const projectDao = require('../../pm/models/project_model').project;
 const compleClassModel = mongoose.model('complementary_glj_section');
 
@@ -535,6 +537,10 @@ async function getLibInfo(req) {
     return data;
 }
 
+async function getGLJLib(query) {
+    return stdGLJLibModel.findOne(query);
+}
+
 async function getGLJLibByEngineerID  (engineerID) {
     let engineeringLibModel = new EngineeringLibModel() ;
     let engineeringInfo = await engineeringLibModel.findDataByCondition({'_id': engineerID});

+ 2 - 0
public/common_constants.js

@@ -139,6 +139,7 @@
         BILLS: 'bills',
         RATION: 'ration',
     };
+    const DEFAULT_REGION = '全省';
     return {
         fixedFlag,
         billType,
@@ -148,5 +149,6 @@
         supplyType,
         supplyText,
         SourceType,
+        DEFAULT_REGION,
     };
 });

+ 43 - 33
public/web/socket/connection.js

@@ -1,33 +1,40 @@
 /**
  * Created by zhangweicheng on 2017/8/7.
  */
-socketObject={
-  roomInfo : null,
-  messages:[],
-  connect:function (from) {
+socketObject = {
+  roomInfo: null,
+  messages: [],
+  connect: function (from, payload) {
       // 连接socket服务器
       var hostName = window.location.hostname;
       let me = this;
-      let port = window.location.protocol ==='http:'?3300:3301;
-      socket = io(window.location.protocol+'//'+hostName+':'+port);
+      let port = window.location.protocol === 'http:' ? 3300 : 3301;
+      socket = io(window.location.protocol + '//' + hostName + ':' + port);
       socket.on('connect', function () {
-          if(from == 'pm'){
-              me.roomInfo={
-                  userID:userID
+          if (from == 'pm') {
+              me.roomInfo = {
+                  userID: userID
               };
-          }else if(from == 'unitPrice'){
-            me.roomInfo = {
-              unitFile:unitPriceFileID
-            }
-          }else {
+        }else if(from == 'unitPrice'){
+          me.roomInfo = {
+            unitFile:unitPriceFileID
+          }
+        } else {
             me.roomInfo={
                 feeRate:me.getFeeRateRoomID(),
                 unitFile:me.getUnitFileRoomID()
             };
+              if (payload && payload.projectReadOnly === false) {
+                  me.roomInfo.projectID = `projectID${projectObj.project.ID()}`;
+              }
           }
-          socket.emit('join', me.roomInfo);
-          if(me.messages.length > 0){//发送缓存消息;
-              for(let m of me.messages){
+          const emitData = {
+              roomData: me.roomInfo,
+              payload
+          };
+          socket.emit('join', emitData);
+          if (me.messages.length > 0) {//发送缓存消息;
+              for (let m of me.messages) {
                   socket.emit(m.message, m.data);
               }
           }
@@ -36,7 +43,7 @@ socketObject={
 
       //=========================================================
       //造价书页面接收消息部分
-      socket.on('feeRateChange', function(data) {
+      socket.on('feeRateChange', function (data) {
           //data = JSON.parse(data);
 
           $("#message").html('费率文件已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
@@ -53,34 +60,37 @@ socketObject={
           $("#notify").show();
       });
       socket.on('changeFileNotify', function (data) {//收到文件改变的消息
-          if(data.projectID==projectObj.project.ID()){//如果是同个项目,则给出提示,否则忽略
-                let preString ="";
-                if(data.name=='feeRate'){
-                    preString = "费率文件";
-                }
-                if(data.name=='unitFile'){
-                    preString = "单价文件";
-                }
-              $("#message").html(preString+'已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
+          if (data.projectID == projectObj.project.ID()) {//如果是同个项目,则给出提示,否则忽略
+              let preString = "";
+              if (data.name == 'feeRate') {
+                  preString = "费率文件";
+              }
+              if (data.name == 'unitFile') {
+                  preString = "单价文件";
+              }
+              $("#message").html(preString + '已被修改,<a href="javascript:void(0);" id="load-data" onclick="window.location.reload()">点击加载并重新进行造价计算</a>');
               $("#notify").show();
           }
       });
+      socket.on('handleAvatarList', function ({ editingUsers }) {
+          projectInfoObj.handleAvatarList(editingUsers);
+      });
 
 
       //=============================================================================================
       //项目管理页面接收消息部分
 
       socket.on('refreshProjectIcon', function (data) {//收到刷新图标消息
-           if(data.projectID && typeof projTreeObj !== 'undefined') projTreeObj.refreshProjectIcon(data.projectID);
+          if (data.projectID && typeof projTreeObj !== 'undefined') projTreeObj.refreshProjectIcon(data.projectID);
       });
       socket.on('fileDataChange', function (data) {//收到单价文件、费率文件内容修改、文件切换、另存(暂时能共用,以后有需要可分离)推送消息
-          if(data.projectID && typeof projTreeObj !== 'undefined') projTreeObj.refreshWhenFileDateChange(data.projectID);
+          if (data.projectID && typeof projTreeObj !== 'undefined') projTreeObj.refreshWhenFileDateChange(data.projectID);
       });
   },
-  getFeeRateRoomID:function (){
-      return  projectObj.project.FeeRate.getActivateFeeRateFileID();
+  getFeeRateRoomID: function () {
+      return projectObj.project.FeeRate.getActivateFeeRateFileID();
   },
-  getUnitFileRoomID:function () {
-      return projectObj.project.projectGLJ.datas.constData.roomId?projectObj.project.projectGLJ.datas.constData.roomId:roomId;
+  getUnitFileRoomID: function () {
+      return projectObj.project.projectGLJ.datas.constData.roomId ? projectObj.project.projectGLJ.datas.constData.roomId : roomId;
   }
 }

+ 60 - 5
socket.js

@@ -9,16 +9,58 @@ import socket from "socket.io";
 
 const socketIO = socket(3300);
 
+const userCache = {};
+
+function getEditingUsers(projectID) {
+    const users = userCache[projectID];
+    if (!users) {
+        return [];
+    }
+    const rst = [];
+    const existMap = {};
+    for (const user of users) {
+        if (existMap[user._id]) {
+            continue;
+        }
+        existMap[user._id] = true;
+        rst.push(user);
+    }
+    return rst;
+}
+
 // socket.io相关操作
 socketIO.on('connection', function(socket) {
     let roomInfo = {};
+    let curUser;
+    let curProjectID;
     console.log("new connection");
     // 加入房间
     socket.on('join', function(data) {
-        console.log(data);
-        for(let key in data){
-            roomInfo[key] = data[key];
-            socket.join(data[key]);
+        const { roomData, payload } = data;
+        if (payload && payload.user) {
+            curUser = payload.user;
+        }
+        if (roomData) {
+            if (roomData.projectID) {
+                curProjectID = roomData.projectID;
+                if (!userCache[roomData.projectID]) {
+                    userCache[roomData.projectID] = [];
+                }
+                // 由于用户可以重复打开项目,因此不做唯一性处理
+                userCache[roomData.projectID].push(curUser);
+            }
+            for(let key in roomData){
+                roomInfo[key] = roomData[key];
+                socket.join(roomData[key], () => {
+                    if (key === 'projectID') {
+                        const editingUsers = getEditingUsers(curProjectID);
+                        if (editingUsers.length > 1) { // 只有一个用户数据,说明只有用户自己打开项目,不需要推送数据,减少触发。
+                            socket.broadcast.to(roomInfo.projectID).emit('handleAvatarList', {editingUsers});
+                            socket.emit('handleAvatarList', {editingUsers});
+                        }
+                    }
+                });
+            }
         }
     });
     // 数据更改通知
@@ -60,6 +102,19 @@ socketIO.on('connection', function(socket) {
 
 
     socket.on('disconnect', function () {
+        // 由于用户可以重复打开项目,因此不做唯一性处理,只删除一个数据,不删除所有的同用户数据
+        if (curProjectID && userCache[curProjectID]) {
+            const index = userCache[curProjectID].findIndex(user => user._id === curUser._id);
+            if (index >= 0) {
+                userCache[curProjectID].splice(index, 1);
+                if (!userCache[curProjectID].length) {
+                    delete userCache[curProjectID];
+                }
+                const editingUsers = getEditingUsers(curProjectID);
+                socket.broadcast.to(roomInfo.projectID).emit('handleAvatarList', {editingUsers});
+                socket.emit('handleAvatarList', {editingUsers});
+            }
+        }
         console.log("client disconnect =========="+JSON.stringify(roomInfo));
     });
-});
+});

+ 254 - 250
web/building_saas/css/custom.css

@@ -1,146 +1,146 @@
 
 .text-green{
-    color: #172a30
+  color: #172a30
 }
 label.title{
-    display: inline-block;
-    width: 100px;
+  display: inline-block;
+  width: 100px;
 }
 .modal-feeRate {max-width: 550px}
 
 div.resize{
-    height: 10px;
-    background: #efefef;
-    width: 100%;
-    cursor: s-resize;
+  height: 10px;
+  background: #efefef;
+  width: 100%;
+  cursor: s-resize;
 }
 div.resize-y{
-    height: 5px;
-    background: #efefef;
-    width: 100%;
-    cursor: s-resize;
+  height: 5px;
+  background: #efefef;
+  width: 100%;
+  cursor: s-resize;
 }
 div.resize-x{
-    width: 4px;
-    height: 100%;
-    background: #efefef;
-    cursor: w-resize;
-    float: left;
+  width: 4px;
+  height: 100%;
+  background: #efefef;
+  cursor: w-resize;
+  float: left;
 }
 /*.zlfb-check{
-    margin-left: 20px;
+  margin-left: 20px;
 }*/
 legend.legend{
-    display:block;
-    width:auto;
-    font-size:0.9rem;
-    top:-15px;
-    background: white;
+  display:block;
+  width:auto;
+  font-size:0.9rem;
+  top:-15px;
+  background: white;
 }
 
 .toolsbar_feeRate {
-    border-bottom: 1px solid #ccc
+  border-bottom: 1px solid #ccc
 }
 
 .li_sub {
-    margin-left: 14px;
+  margin-left: 14px;
 }
 
 .filterType{
-    width: 122px;
+  width: 122px;
 }
 
 .filterType ul{
-    width: 110px;
+  width: 110px;
 }
 .a_color{
-    color: #007bff
+  color: #007bff
 }
 
 .filterType a{
-    padding: 1px;
-    padding-top: 7px;
-    padding-bottom: 7px;
+  padding: 1px;
+  padding-top: 7px;
+  padding-bottom: 7px;
 }
 
 #gljPriceTenderCoe::-webkit-outer-spin-button,
 #gljPriceTenderCoe::-webkit-inner-spin-button {
-         -webkit-appearance: none;
-     }
+       -webkit-appearance: none;
+   }
 #gljPriceTenderCoe {
-    -moz-appearance: textfield;
+  -moz-appearance: textfield;
 }
 
 .modal-quantity-edit-height {
-    height: 200px;
-    overflow-y: auto;
+  height: 200px;
+  overflow-y: auto;
 }
 
 .message-box {
-    position:absolute;
-    background:#000;
-    padding:8px 10px;
-    line-height: 18px;
-    border-radius:4px;
-    text-align:left;
-    font:0.9rem Calibri;
-    box-shadow:2px 2px 6px #ccc;
-    color:#fff;
+  position:absolute;
+  background:#000;
+  padding:8px 10px;
+  line-height: 18px;
+  border-radius:4px;
+  text-align:left;
+  font:0.9rem Calibri;
+  box-shadow:2px 2px 6px #ccc;
+  color:#fff;
 }
 .triangle-border {
-    position:absolute;
-    left:10px;
-    overflow:hidden;
-    width:0;
-    height:0;
-    border-width:6px;
-    border-style:solid dashed dashed dashed;
+  position:absolute;
+  left:10px;
+  overflow:hidden;
+  width:0;
+  height:0;
+  border-width:6px;
+  border-style:solid dashed dashed dashed;
 }
 .triangle-border_dropdown {
-    position:absolute;
-    left:0px;
-    overflow:hidden;
-    width:0;
-    height:0;
-    border-width:4px;
-    z-index: 10;
-    border-style:solid dashed dashed dashed;
+  position:absolute;
+  left:0px;
+  overflow:hidden;
+  width:0;
+  height:0;
+  border-width:4px;
+  z-index: 10;
+  border-style:solid dashed dashed dashed;
 }
 .tb-border_dropdown {
-    top:7px;
-    border-color:#000 transparent transparent transparent;
+  top:7px;
+  border-color:#000 transparent transparent transparent;
 }
 
 .tb-background_dropdown {
-    bottom:-11px;
-    border-color:#000 transparent transparent transparent;
+  bottom:-11px;
+  border-color:#000 transparent transparent transparent;
 }
 
 .tb-border {
-    bottom:-12px;
-    border-color:#000 transparent transparent transparent;
+  bottom:-12px;
+  border-color:#000 transparent transparent transparent;
 }
 .tb-background {
-    bottom:-11px;
-    border-color:#000 transparent transparent transparent;
+  bottom:-11px;
+  border-color:#000 transparent transparent transparent;
 }
 
 .tb-border_up {
-    top:-12px;
-    border-color:transparent transparent #000 transparent;
+  top:-12px;
+  border-color:transparent transparent #000 transparent;
 }
 .tb-background_up {
-    top:-11px;
-    border-color:transparent transparent #000 transparent;
+  top:-11px;
+  border-color:transparent transparent #000 transparent;
 }
 
 
 .elf-options:hover{
-    background-color: #CCCCCC;
+  background-color: #CCCCCC;
 }
 
 .inline-div{
-    display:inline;
+  display:inline;
 }
 
 /*快捷切换单位工程*/
@@ -150,331 +150,335 @@ legend.legend{
 
 
 /*.menu a:hover {
-    color: #fff;
-    background: #40DE5A;
+  color: #fff;
+  background: #40DE5A;
 }*/
 
 
 .menu ul ul {
-    visibility: hidden;
-    position: absolute;
-    top: -1px;
-    left: 100px;
+  visibility: hidden;
+  position: absolute;
+  top: -1px;
+  left: 100px;
 }
 
 .menu ul li:hover ul, .menu ul a:hover ul {
-    visibility: visible;
+  visibility: visible;
 }
 
 .menu ul :hover ul ul {
-    visibility: hidden;
+  visibility: hidden;
 }
 
 .menu ul :hover ul :hover ul {
-    visibility: visible;
+  visibility: visible;
 }
 
 .ui-datepicker-next, .ui-datepicker-next:hover{
-    background-image: url("/lib/jquery-ui/images/ui-icons_444444_256x240.png");
-    background-repeat: no-repeat;
-    background-position: -28px -12px;
+  background-image: url("/lib/jquery-ui/images/ui-icons_444444_256x240.png");
+  background-repeat: no-repeat;
+  background-position: -28px -12px;
 }
 .ui-datepicker-prev, .ui-datepicker-prev:hover{
-    background-image: url("/lib/jquery-ui/images/ui-icons_444444_256x240.png");
-    background-repeat: no-repeat;
-    background-position: -90px -12px;
+  background-image: url("/lib/jquery-ui/images/ui-icons_444444_256x240.png");
+  background-repeat: no-repeat;
+  background-position: -90px -12px;
 }
 
 .feerateInput {
-    padding: 0;
+  padding: 0;
 }
 
 #toolToastWrap{
-    display:-webkit-box;
-    display:-ms-flexbox;
-    display:flex;
-    -webkit-box-pack:center;
-    -ms-flex-pack:center;
-    justify-content:center;
-    pointer-events:none;
+  display:-webkit-box;
+  display:-ms-flexbox;
+  display:flex;
+  -webkit-box-pack:center;
+  -ms-flex-pack:center;
+  justify-content:center;
+  pointer-events:none;
 }
 
 #toolToast{
-    padding:11px 20px;
-    line-height:18px;
-    font-size:14px;
-    position:relative;
-    word-wrap:break-word;
-    color:#fff;
-    text-align:center;
-    background:rgba(0,0,0,.75);
-    background-size:cover;
-    -webkit-user-select:none;
-    -moz-user-select:none;
-    -ms-user-select:none;
-    user-select:none;
-    display:-webkit-box;
-    display:-ms-flexbox;
-    display:flex;
-    -webkit-box-align:center;
-    -ms-flex-align:center;
-    align-items:center;
-    max-width:686px;
-    box-sizing:border-box;
-    box-shadow:0 0 0 0 rgba(0,0,0,.15),0 2px 5px 0 rgba(0,0,0,.25);
-    pointer-events:auto;
-    border-radius:2px
+  padding:11px 20px;
+  line-height:18px;
+  font-size:14px;
+  position:relative;
+  word-wrap:break-word;
+  color:#fff;
+  text-align:center;
+  background:rgba(0,0,0,.75);
+  background-size:cover;
+  -webkit-user-select:none;
+  -moz-user-select:none;
+  -ms-user-select:none;
+  user-select:none;
+  display:-webkit-box;
+  display:-ms-flexbox;
+  display:flex;
+  -webkit-box-align:center;
+  -ms-flex-align:center;
+  align-items:center;
+  max-width:686px;
+  box-sizing:border-box;
+  box-shadow:0 0 0 0 rgba(0,0,0,.15),0 2px 5px 0 rgba(0,0,0,.25);
+  pointer-events:auto;
+  border-radius:2px
 }
 
 #toolToastBtn{
-    color:#0188fb;
-    margin:0 2px;
-    white-space:nowrap;
-    cursor:pointer;
-    font-weight:700
+  color:#0188fb;
+  margin:0 2px;
+  white-space:nowrap;
+  cursor:pointer;
+  font-weight:700
 }
 
 #toolToastBtn:hover{
-    color:#4060c9
+  color:#4060c9
 }
 
 #toolToastBtn:active{
-    color:#354ea1
+  color:#354ea1
 }
 
 .select_input{
-    border:none;
+  border:none;
 }
 
 /*.es-list>li:hover{
-    background: lightgrey;
+  background: lightgrey;
 }*/
 
 .es-list-selected{
-    background: lightgrey;
+  background: lightgrey;
 }
 
 .es-list>li{
-    font-size:13px;
+  font-size:13px;
 }
 .es-list{
-    white-space:nowrap;
+  white-space:nowrap;
 }
 
 /*.dropdown-toggle::after{
-    vertical-align:.5em
+  vertical-align:.5em
 }*/
 #esInput{
-    font-size:13px;
-    color: black;
+  font-size:13px;
+  color: black;
 }
 .ration_glj_spread{
-    width: 83%;
-    float: left;
+  width: 83%;
+  float: left;
 }
 
 .item_spread{
-    width: 29.8%;
-    float: left;
-    background: #F1F1F1;
-    word-wrap:break-word
+  width: 29.8%;
+  float: left;
+  background: #F1F1F1;
+  word-wrap:break-word
 }
 
 input.text-right{
-    text-align: right;
+  text-align: right;
 }
 
 .cus-width{
-    width: 100px;
-    margin-left: 10px;
+  width: 100px;
+  margin-left: 10px;
 }
 .more{
-    padding-left:.25rem!important
+  padding-left:.25rem!important
 }
 .bottom-tznrTools {
-    height: 30px;
-    line-height: 30px;
-    background:#efefef;
-    bottom:30px;
-    left:0px;
-    z-index: 999
+  height: 30px;
+  line-height: 30px;
+  background:#efefef;
+  bottom:30px;
+  left:0px;
+  z-index: 999
 }
 
 .zmhs-link{
-    padding:0.4em 0.4em !important;
+  padding:0.4em 0.4em !important;
 }
 
 /*修改tooltip默认最大宽度 */
 .tooltip-inner{
-    max-width: 400px !important;
+  max-width: 400px !important;
 }
 .applySuccess{
-    display: none;
-    color: #43CD80;
-    margin-left: 8px
+  display: none;
+  color: #43CD80;
+  margin-left: 8px
 }
 .font_blue{
-    color: #3FB2E5;
+  color: #3FB2E5;
 }
 
 .nomargin{
-    margin: 0px;
+  margin: 0px;
 }
 .border_bottom{
-    border-bottom:  1px solid #ccc
+  border-bottom:  1px solid #ccc
 }
 .export-check{
-    overflow: auto;
-    height: 400px;
+  overflow: auto;
+  height: 400px;
 }
 .shake-input {
-    animation: shake-input 0.2s 4;
+  animation: shake-input 0.2s 4;
 }
 @keyframes shake-input {
-    0% {
-        transform: translateX(0);
-    }
-    30% {
-        transform: translateX(-2%);
-    }
-    100% {
-        transform: translateX(4%)
-    }
+  0% {
+      transform: translateX(0);
+  }
+  30% {
+      transform: translateX(-2%);
+  }
+  100% {
+      transform: translateX(4%)
+  }
 }
 /*占位底色*/
 .occupied {
-    background: #f1f1f1;
+  background: #f1f1f1;
 }
 /*书签批注*/
 .annotate-color-1::before{
-    color: #E2F2C5 !important;
-    -webkit-text-stroke:.5px #ced4da;
+  color: #E2F2C5 !important;
+  -webkit-text-stroke:.5px #ced4da;
 }
 .annotate-color-2::before{
-    color: #F9E2CF !important;
-    -webkit-text-stroke:.5px #ced4da;
+  color: #F9E2CF !important;
+  -webkit-text-stroke:.5px #ced4da;
 }
 .annotate-color-3::before{
-    color:#F2EFD9 !important;
-    -webkit-text-stroke:.5px #ced4da;
+  color:#F2EFD9 !important;
+  -webkit-text-stroke:.5px #ced4da;
 }
 .annotate-color-4::before{
-    color:#F5D1DA !important;
-    -webkit-text-stroke:.5px #ced4da;
+  color:#F5D1DA !important;
+  -webkit-text-stroke:.5px #ced4da;
 }
 .annotate-color-5::before{
-    color:#E3E3E3 !important;
-    -webkit-text-stroke:.5px #ced4da;
+  color:#E3E3E3 !important;
+  -webkit-text-stroke:.5px #ced4da;
 }
 .annotate-color-6::before{
-    color:#B6F3F2 !important;
-    -webkit-text-stroke:.5px #ced4da;
+  color:#B6F3F2 !important;
+  -webkit-text-stroke:.5px #ced4da;
 }
 .annotate-color-7::before{
-    color:#ECE0F5 !important;
-    -webkit-text-stroke:.5px #ced4da;
+  color:#ECE0F5 !important;
+  -webkit-text-stroke:.5px #ced4da;
 }
 .z-index-3000 {
-    z-index: 3000;
+  z-index: 3000;
 }
 .progress-bar {
-    position: relative;
-    width: 100%;
+  position: relative;
+  width: 100%;
 }
 .progress-move {
-    position: absolute;
-    left: 0;
-    top: 0;
-    z-index: 999;
-    width: 200%;
-    height: 100%;
-    border-radius: .25rem;
-    animation: progressMove 20s linear infinite;
+  position: absolute;
+  left: 0;
+  top: 0;
+  z-index: 999;
+  width: 200%;
+  height: 100%;
+  border-radius: .25rem;
+  animation: progressMove 20s linear infinite;
 }
 @keyframes progressMove {
-    from {
-        transform: translateX(0);
-    }
-    to {
-        transform: translateX(-280px);
-    }
+  from {
+      transform: translateX(0);
+  }
+  to {
+      transform: translateX(-280px);
+  }
 }
 .progress-cover {
-    position: absolute;
-    left: 0;
-    top: 0;
-    z-index: 1000;
-    width: 100%;
-    height: 100%;
-    background-color: #e9ecef;
+  position: absolute;
+  left: 0;
+  top: 0;
+  z-index: 1000;
+  width: 100%;
+  height: 100%;
+  background-color: #e9ecef;
 }
 .progress-cover-move {
-    animation: progressCoverMove 40s linear;
-    animation-fill-mode: forwards;
+  animation: progressCoverMove 40s linear;
+  animation-fill-mode: forwards;
 }
 @keyframes progressCoverMove {
-    0% {
-        transform: translateX(0);
-    }
-    20% {
-        transform: translateX(330px);
-    }
-    40% {
-        transform: translateX(380px);
-    }
-    100% {
-        transform: translateX(420px);
-    }
+  0% {
+      transform: translateX(0);
+  }
+  20% {
+      transform: translateX(330px);
+  }
+  40% {
+      transform: translateX(380px);
+  }
+  100% {
+      transform: translateX(420px);
+  }
 }
 .text-ellipsis {
-    overflow: hidden;
-    white-space: nowrap;
-    text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
 }
 .border-radius {
-    border-radius: .2rem !important;
+  border-radius: .2rem !important;
 }
 .pm-i {
-    width: 18px;
+  width: 18px;
 }
 .calcbase-btn {
-    width: 24px;
-    padding-left: 0;
-    padding-right: 0;
+  width: 24px;
+  padding-left: 0;
+  padding-right: 0;
 }
 .over-height {
-    max-width: 550px !important;
+  max-width: 550px !important;
 }
 .hide-area {
-    display: none;
+  display: none;
 }
 .middle-modal-width {
-    max-width: 650px;
+  max-width: 650px;
 }
 .middle-modal-height {
-    height: 500px;
+  height: 500px;
 }
 
 @media screen and (max-width: 1366px), (max-height: 768px) {
-    .middle-modal-width {
-        max-width: 500px;
-    }
-    .middle-modal-height {
-        height: 350px;
-    }
+  .middle-modal-width {
+      max-width: 500px;
+  }
+  .middle-modal-height {
+      height: 350px;
+  }
 }
 .textarea-inherit {
-    width: 100%;
-    overflow: auto;
-    word-break: break-all;
+  width: 100%;
+  overflow: auto;
+  word-break: break-all;
 }
 /* 初始样式,防止projspread初始化完后背景从白突然变灰 */
 .poj-list {
-    height: 1000px; 
-    background: #f7f7f9;
+  height: 1000px; 
+  background: #f7f7f9;
 }
+.default-cursor {
+  cursor: default !important;
+}
+
 .unit_price_header{
-  padding-top:6px;
-  margin-left: 50px;
-  margin-right: 100px !important;
+padding-top:6px;
+margin-left: 50px;
+margin-right: 100px !important;
 }

+ 33 - 12
web/building_saas/css/main.css

@@ -57,8 +57,11 @@ height: calc(1.5em + .5rem + 2px);
 font-size: .875rem;
 }
 .btn-xs{
-  padding:0rem .5rem;
-  font-size:.875rem;
+padding:0rem .5rem;
+font-size:.875rem;
+}
+.table-sc thead tr{
+background-color: #f1f1f1
 }
 /*自定义css*/
 .login-body,.login-html{
@@ -766,34 +769,52 @@ background:#999;
 color:#fff;
 border-radius: 30px
 }
-.book-list li .avatar.bg-1{
+.avatar-list {
+padding:0;
+margin:0 0 0 5px;
+list-style: none;
+}
+.avatar-list li{
+  float: left;
+  margin-right: 5px;
+}
+.avatar-list li .avatar{
+height: 24px;
+line-height: 24px;
+width:24px;
+border-radius: 20px;
+color:#fff;
+font-size: 10px;
+text-align: center;
+}
+.book-list li .avatar.bg-1,.avatar-list li .avatar.bg-1{
 background:rgb(16,109,156)
 }
-.book-list li .avatar.bg-2{
+.book-list li .avatar.bg-2,.avatar-list li .avatar.bg-2{
 background:rgb(90,146,173)
 }
-.book-list li .avatar.bg-3{
+.book-list li .avatar.bg-3,.avatar-list li .avatar.bg-3{
 background:rgb(150,164,139)
 }
-.book-list li .avatar.bg-4{
+.book-list li .avatar.bg-4,.avatar-list li .avatar.bg-4{
 background:rgb(216,202,175)
 }
-.book-list li .avatar.bg-5{
+.book-list li .avatar.bg-5,.avatar-list li .avatar.bg-5{
 background:rgb(201,192,211)
 }
-.book-list li .avatar.bg-6{
+.book-list li .avatar.bg-6,.avatar-list li .avatar.bg-6{
 background:rgb(61,89,171)
 }
-.book-list li .avatar.bg-7{
+.book-list li .avatar.bg-7,.avatar-list li .avatar.bg-7{
 background:rgb(243,203,211)
 }
-.book-list li .avatar.bg-8{
+.book-list li .avatar.bg-8,.avatar-list li .avatar.bg-8{
 background:rgb(181,196,177)
 }
-.book-list li .avatar.bg-9{
+.book-list li .avatar.bg-9,.avatar-list li .avatar.bg-9{
 background:rgb(150,84,84)
 }
-.book-list li .avatar.bg-0{
+.book-list li .avatar.bg-0,.avatar-list li .avatar.bg-0{
 background:rgb(191,191,191)
 }
 .book-list li .book-body{

+ 3 - 3
web/building_saas/main/js/models/ration_glj.js

@@ -517,9 +517,8 @@ let ration_glj = {
         ration_glj.prototype.getGLJDataPaging = function (condition, cb) {
             gljOprObj.loadingPagination = true;
             const property = projectObj.project.projectInfo.property;
-            const engineerID = property.engineering_id;
             const actionType = $('#actionType').val();
-            CommonAjax.post('/rationGlj/getGLJDataPaging', {engineerID, condition}, function (data) {
+            CommonAjax.post('/rationGlj/getGLJDataPaging', { condition }, function (data) {
                 gljOprObj.curPageTotal = data.total;
                 data.complementaryGLJs.forEach(glj => {
                     glj.isComplementary = true;
@@ -559,7 +558,8 @@ let ration_glj = {
                 // 设置人材机类型名称
                 gljOprObj.setTypeName(gljOprObj.distTypeTree.comboDatas, newData);
                 if (data.priceProperties && data.priceProperties.length > 0) {
-                    let tmp = _.find(data.priceProperties, {region: property.region, taxModel: parseInt(property.taxType)});
+                    // region: region目前跟单位工程绑定,这里暂时固定写死commonConstants.DEFAULT_REGION,以后应改成跟建设项目绑定的region,
+                    let tmp = _.find(data.priceProperties, {region: commonConstants.DEFAULT_REGION, taxModel: parseInt(property.taxType)});
                     if (tmp) {
                         let dataCode = tmp.price.dataCode;
                         let allData = data.stdGLJ.concat(data.complementaryGLJs);

+ 42 - 24
web/building_saas/main/js/views/project_info.js

@@ -3,20 +3,42 @@
  */
 
 var projectInfoObj = {
-    getSubShareInfo: function (proj) {
-        const { allowCopy, allowCooperate } = proj.shareState;
-        let str = '(';
-        if (allowCopy) {
-            str += '可拷贝 ';
+    // 头部同时编辑的用户头像
+    handleAvatarList: function (users) {
+        const opener = projectObj.project.projectInfo.opener;
+        if (opener) {
+            users = users.filter(user => user._id !== opener._id);
         }
-        if (allowCooperate) {
-            if (allowCopy) {
-                str += ' ';
-            }
-            str += '可编辑';
+        const avatarListHtml = users.reduce((acc, user) => {
+            const avatarSpan = SHARE_TO.getAvatarHTML(user.mobile, user.real_name);
+            const li = 
+                `<li data-toggle="tooltip" data-placement="bottom" title="${user.real_name}" data-original-title="${user.real_name}">
+                    ${avatarSpan}
+                </li>`
+            return acc += li;
+        }, '');
+        $('#avatar-list').html(avatarListHtml);
+        $('#avatar-list [data-toggle="tooltip"]').tooltip(); 
+    },
+    getReceiveInfo: function (projectReadOnly, projectCooperate, owner) {
+        if (!projectReadOnly && !projectCooperate) {
+            return '';
+        }
+        const action = projectCooperate ? '可编辑' : '只能查看';
+        const ownerName = owner && owner.real_name || '';
+        return `
+            <span class="pl-2" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="来自 ${ownerName} 的分享">
+                <a href="javascript:;" class="btn btn-xs btn-primary default-cursor"><i class="fa fa-share-alt"></i> ${action}</a>
+            </span>`;
+    },
+    getShareButton: function (projectReadOnly, projectCooperate, shareTip) {
+        if (projectReadOnly || projectCooperate) {
+            return '';
         }
-        str += ')';
-        return str === '()' ? '' : str;
+        return `
+            <span id="share-tip" class="ml-2" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="${shareTip}">
+                <a id="init-share" href="javascript:;" class="btn btn-xs btn-primary"><i class="fa fa-share-alt"></i> 分享</a>
+            </span>`;
     },
     getFullPathHtml: function (proj) {
         let fullPath = [], i, pm = '<span class="text-truncate"><a href="/pm">项目管理</a></span>', angleRight = '<span class="text-truncate"><i class="fa fa-angle-right fa-fw"></i></span>';
@@ -25,26 +47,22 @@ var projectInfoObj = {
             let engName = pathArr[pathArr.length - 2] || '',
                 projectName = pathArr[pathArr.length - 3] || '',
                 folderName = pathArr[pathArr.length - 4] || '';
-            const subShareInfo = projectInfoObj.getSubShareInfo(proj);
-            const receiveTip = `<span class="alert alert-success py-0 px-2 m-0" id="share-info"><i class="fa fa-share-alt"></i>来自 ${proj.owner && proj.owner.real_name || ''} 的分享${subShareInfo}</span>`;
+            const receiveInfo = this.getReceiveInfo(projectReadOnly, projectCooperate, proj.owner);
+            const shareButton = this.getShareButton(projectReadOnly, projectCooperate, proj.shareTip);
             let newHtml = `   <span data-toggle="tooltip" data-placement="bottom" data-original-title="${folderName}"><i class="fa fa-folder-open-o"></i>...</span>
                 <span class="text-muted px-1">\</span>
                 <span data-toggle="tooltip" data-placement="bottom" data-original-title="${projectName}"><i class="fa fa-cubes"></i>...</span>
                 <span class="text-muted px-1">\</span>
                 <span data-toggle="tooltip" data-placement="bottom" data-original-title="${engName}"><i class="fa fa-cube"></i>...</span>
                 <span class="text-muted px-1">\</span>
-                 <span><i class="fa fa-sticky-note-o"></i></span>
+                <span><i class="fa fa-sticky-note-o"></i></span>
                 <span class="text-truncate"  data-toggle="tooltip" data-placement="bottom" data-original-title="${proj.name}">&nbsp;${proj.name}</span>
-                ${projectReadOnly || projectCooperate ? receiveTip : `<span id="share-tip" class="ml-2" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="${proj.shareTip}"><a id="init-share" href="javascript:;" class="btn btn-xs btn-primary"><i class="fa fa-share-alt"></i> 分享</a></span>`}
+                ${receiveInfo}${shareButton}
+                <span>
+                    <ul class="avatar-list mb-0" id="avatar-list">
+                    </ul>
+                </span>
                 `;
-            /* ${projectReadOnly ?
-                    '<span data-toggle="tooltip" data-placement="bottom" data-original-title="当前的工程状态为“只读”,如果要进行编辑,请在项目管理-分享界面,使用“拷贝工程”功能。">(只读)</span>'
-                    : ''}
-                ${projectCooperate ?
-                    '<span data-toggle="tooltip" data-placement="bottom" data-original-title="当前的工程状态为“协作”,可直接编辑分享人的原始数据。">(协作)</span>'
-                    : ''}
-                
-                ${projectReadOnly || projectCooperate ? '' : `<span id="share-tip" class="ml-2" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="${proj.shareTip}"><a id="init-share" href="javascript:;" class="btn btn-xs btn-primary"><i class="fa fa-share-alt"></i> 分享</a></span>`} */
             fullPath.push(newHtml);
             fullPath.push(`<input id="rootProjectName" value="${projectName}" type="hidden">`);
 

+ 2 - 1
web/building_saas/main/js/views/project_view.js

@@ -1011,7 +1011,8 @@ var projectObj = {
                 //if(!projectReadOnly){
                     that.loadMainSpreadContextMenu();
                 //}
-                socketObject.connect();//连接socket服务器
+                
+                socketObject.connect('main', { projectReadOnly: !!projectReadOnly, user: { ...projectObj.project.projectInfo.opener } });//连接socket服务器
                 let endTime = +new Date();
                 console.log(`其它时间——${endTime - endShowTime}`);
                 console.log("加载完成-----"+endTime);

+ 1 - 1
web/building_saas/pm/js/pm_import.js

@@ -248,7 +248,7 @@ const importView = (() => {
         let curEngineering = tbcObj.engineeringList.find(data => query.engineeringName === data.lib.name &&
             query.feeStandard === data.lib.feeName);
         return {
-            region: '全省',   //地区
+            region: commonConstants.DEFAULT_REGION,   //地区
             valuationType: tbcObj.valuationType,    //计价方式
             valuation: tbcObj.valuation.id, //计价规则
             valuationName: tbcObj.valuation.name,

+ 1 - 1
web/building_saas/pm/js/pm_newMain.js

@@ -3821,7 +3821,7 @@ function AddTender() {
             };
         let selectedItem = projTreeObj.tree.selected;
         //地区
-        let region = $('#regionDiv').find('select').val() || '全省';
+        let region = $('#regionDiv').find('select').val() || commonConstants.DEFAULT_REGION;
         let tenderInfo = {
             gljAdjustType: 'priceInfo', //默认为造价信息差额调整法
             valuation: valuation,

+ 1 - 0
web/common/components/share/index.js

@@ -433,5 +433,6 @@ const SHARE_TO = (() => {
     return {
         initModal,
         handleEventListener,
+        getAvatarHTML,
     }
 })();