Explorar o código

Merge branch 'master' into dev_duxiangyu

# Conflicts:
#	src/meri.js
duxiangyu %!s(int64=3) %!d(string=hai) anos
pai
achega
45c30a56f0

+ 3 - 2
package.json

@@ -15,11 +15,12 @@
     "@saga-web/graph": "^2.1.139",
     "font-awesome": "^4.7.0",
     "handsontable-pro": "^3.0.0",
+    "jquery": "^3.3.1",
     "meri-design": "^1.5.515",
     "moment": "^2.29.1",
+    "spark-md5": "^3.0.2",
     "vue-router": "^3.5.3",
-    "vuex": "^3.6.2",
-    "jquery": "^3.3.1"
+    "vuex": "^3.6.2"
   },
   "devDependencies": {
     "@vue/cli-plugin-babel": "~4.5.0",

+ 6 - 2
public/systemConf.js

@@ -8,9 +8,9 @@ var __systemConf = {
   //中间件服务域名
   middlewareServiceUrl: '/middleService',
   //登录服务域名
-  loginServiceUrl: '/loginRequest',
+  loginServiceUrl: 'http://develop.ysbdtp.com/adm-server',
   //文件服务域名
-  fileServiceUrl: 'http://develop.ysbdtp.com/adm-server',
+  fileServiceUrl: 'http://develop.ysbdtp.com/dmp-file',
   // 地图key
   mapKey: 'd42beb96e0e4fb0d49482975abeae1b7',
   //登录相关配置
@@ -27,6 +27,10 @@ var __systemConf = {
         color: '#646C73',
         weight: 600,
         backGround: '#FFFFFF'
+      },
+      line:{
+        width: 2,
+        color: '#0091ff'
       }
     }
   },

+ 6 - 9
src/components/old-adm/ledger/components/handsontables/system.vue

@@ -75,7 +75,6 @@
             <el-row>
                 <div class="row_class">
                     <my-cascader ref="cascader" @change="changeAddType" :all="true"></my-cascader>
-                    <el-checkbox v-model="checked">仅项目交付范围内</el-checkbox>
                 </div>
                 
             </el-row>
@@ -371,7 +370,9 @@ export default {
             if (this.addData.category) {
                 this.$router.push({
                     path: "/ledger/systemadd",
-                    query: this.addData,
+                    query: {
+                        ...this.addData,
+                    }
                 });
             }
         },
@@ -379,8 +380,8 @@ export default {
         changeAddType(val) {
             this.addData.category = val.classCode;
             this.addData.categoryName = val.categoryName;
-            this.addData.showType = this.showType;
-            console.log("val", val, this.addData);
+            this.addData.showType = val.isDelivery;
+            // this.addData.showType = this.showType;
         },
         /**
          * 切换信息点查看类型
@@ -858,9 +859,5 @@ export default {
         font-size: 12px;
     }
 }
-.row_class {
-    display: flex;
-    justify-content: space-around;
-    align-items: center;
-}
+
 </style>

+ 14 - 14
src/components/old-adm/ledger/components/lib/buildfloorCascader.vue

@@ -5,7 +5,7 @@
 // import { buildingQuery } from "@/api/scan/request";
 // import { buildingQuery } from '@/api/object/build';
 import Builder from "@/controller/old-adm/buildController";
-const { buildingQuery } = Builder;
+// const { buildingQuery } = Builder;
 
 export default {
   data() {
@@ -28,7 +28,7 @@ export default {
   },
 
   methods: {
-    getCascader() {
+    async getCascader() {
       let param = {
         cascade: [
           { name: "floor", orders: "floorSequenceID desc" }
@@ -37,19 +37,19 @@ export default {
         pageNumber: 1,
         pageSize: 50
       }
-      buildingQuery(param, res => {
-        res.content.map(t => {
-          if (t.floor && t.floor.length) {
-            t.floor = t.floor.map(item => {
-              if (item.id == this.FloorID) return
-              item.BuildID = item.id
-              item.BuildLocalName = item.localName || item.name
-              return item
-            }).filter(it => it)
-          }
-        })
-        this.options = res.content
+      const res = await Builder.buildingQuery(param)
+      res.content.map(t => {
+        if (t.floor && t.floor.length) {
+          t.floor = t.floor.map(item => {
+            if (item.id == this.FloorID) return
+            item.BuildID = item.id
+            item.BuildLocalName = item.localName || item.name
+            return item
+          }).filter(it => it)
+        }
       })
+      this.options = res.content
+      
     },
     getSelectedNodes() {
       let nodes = this.$refs.elCascader.getCheckedNodes();

+ 31 - 23
src/components/old-adm/ledger/components/lib/system.vue

@@ -1,13 +1,15 @@
 <template>
-  <div id="cascaderMap">
-    <span class="buildFloor" style="padding-right: 12px;">所属专业系统类型</span>
-    <el-select v-model="value" placeholder="请选择" :props="props" filterable :style="isWidth ? '' : 'width:160px;'"
-               size="small" @change="changeVal">
-      <el-option v-for="item in options" :key="item.classCode" :label="item.categoryName"
-                 :value="item.classCode"></el-option>
-    </el-select>
-    <!-- <el-cascader placeholder="请选择" :options="options" v-model="value" :props="props" filterable :style="isWidth ? '' : 'width:160px;'" size="small"
-      @change="changeVal" change-on-select></el-cascader> -->
+  <div id="cascaderMap" :style="{'justify-content': all ? 'space-around' : ''}">
+    <div>
+      <span class="buildFloor" style="padding:0 12px;">所属专业系统类型</span>
+      <el-select v-model="value" placeholder="请选择" :props="props" filterable :style="isWidth ? '' : 'width:160px;'"
+                size="small" @change="changeVal">
+        <el-option v-for="item in options" :key="item.classCode" :label="item.categoryName"
+                  :value="item.classCode"></el-option>
+      </el-select>
+    </div>
+    
+    <el-checkbox v-if='all' v-model="isDelivery" @change="deliverChange" >仅项目交付范围内</el-checkbox>
   </div>
 </template>
 <script>
@@ -39,10 +41,13 @@ export default {
     return {
       value: [],
       options: [],
+      full_options: [],
       props: {
         value: "classCode",
         label: "categoryName"
-      }
+      },
+      isDelivery: true,
+      query: {},
     };
   },
   created() {
@@ -64,9 +69,6 @@ export default {
         this.getData();
       }
     },
-    setValue(val) {
-      this.value = val
-    },
     //修改val
     changeVal(val) {
       let value = {}
@@ -75,8 +77,9 @@ export default {
           value = item
         }
       })
-      this.value = val
-      this.$emit("change", value)
+      this.value = val;
+      this.query = {...this.query, ...value};
+      this.$emit("change", this.query)
     },
     async getData() {
       let param = {
@@ -89,8 +92,8 @@ export default {
       }
       try {
         const res = await  queryLinkSys(param);
-        console.log({res})
-        this.options = res.content;
+        this.options = this.changeArr(res.content)
+        // console.log({res})
         if (this.value && this.options.find(item => item.classCode === this.value)) {
           this.changeVal(this.value)
         } else {
@@ -107,9 +110,8 @@ export default {
         type: 'system'
       }
       const res = await queryPhysicsAllType(param);
-      
-      
-      this.options = this.changeArr(res.content)
+      this.full_options = this.changeArr(res.content);
+      this.options = this.isDelivery ? this.full_options.filter(item => item?.isDelivery) : this.full_options
       if (this.value && this.options.find(item => item.classCode === this.value)) {
         this.changeVal(this.value)
       } else {
@@ -122,16 +124,22 @@ export default {
       arr.forEach(item => {
         data.push({ classCode: item.classCode || item.code, categoryName: item.categoryName || item.name });
       });
-      console.log(data, 'data')
+      // console.log(data, 'data')
       return data;
+    },
+    deliverChange(val) {
+      this.query = {...this.query, isDelivery: val ? 'Visible' : 'all'};
+      this.options = val ? this.full_options.filter(item => item?.isDelivery) : this.full_options;
+      this.$emit("change", this.query)
     }
   }
 };
 </script>
 <style lang="less" scoped>
 #cascaderMap {
-  float: left;
-  margin-left: 10px;
+  display: flex;
+  // justify-content: space-around;
+  align-items: center;
 
   .buildFloor {
     color: #999999;

+ 484 - 0
src/components/old-adm/ledger/system/addsystem.vue

@@ -0,0 +1,484 @@
+<template>
+  <div id="deviceList">
+    <el-row class="right">
+      <el-col span="4">
+        <span style="float:left;">当前选择的系统类型:{{ category.categoryName }}</span>
+      </el-col>
+      
+      <el-col span="20" style="text-align: right">
+        <el-select :disabled='showType === "all"' v-model="showType" @change="initTable" style="width:125px;margin-right:10px;vertical-align:bottom;">
+          <el-option v-for="item in showTypes" :key="item.value" :label="item.label" :value="item.value"></el-option>
+        </el-select>
+        <span>增加</span>
+        <el-input-number v-model="addNum" :controls="false" style="width:50px;" :min="1" :max="50"></el-input-number>
+        <span>个{{ category.categoryName }}</span>
+        <el-button @click="handleAddTableRow">增加</el-button>
+      </el-col>
+    </el-row>
+    <div class="tableBox">
+      <div class="center middle_sty" style="flex:2;" v-show="tableData && !tableData.length">
+        <p>
+          <i class="icon-wushuju iconfont"></i>
+          暂无数据
+        </p>
+      </div>
+      <div class="tableLeft" v-show="tableData && tableData.length">
+        <handson-table ref="table"></handson-table>
+      </div>
+    </div>
+    <el-row class="center">
+      <el-button type="primary" size="medium" @click="handleCreateTableData" class="create_button" :disabled="createDisable">创建系统</el-button>
+    </el-row>
+		<!-- 上传图片组件 -->
+		<upload-img-dialog :read="onlyRead ? true : false" @changeFile="imgChange" :keysArr="imgsArr" firmDataType="row" :dialog="myDialog"></upload-img-dialog>
+    <!-- 关联楼层 -->
+    <editSysfloor ref="editFloor" @relateSuccess="relateSuccess" :isCreate="true"></editSysfloor>
+    <!-- 多选枚举类型维护 -->
+   <menum :dialog="myDialog" :updateInfoData="updateInfoData" :updateInput="updateInput" @change="handleChangeMenum"></menum>
+  </div>
+</template>
+<script>
+import tools from "@/utils/old-adm/scan/tools";
+import showTools from "@/utils/old-adm/handsontable/notShow";
+import text from "@/utils/old-adm/handsontable/mainText";
+import session from "@/utils/storageUtil";
+
+import editSysfloor from "@/components/old-adm/ledger/components/lib/editSysFloor";
+import uploadImgDialog from "@/components/old-adm/dialogs/list/uploadImgDialog"
+import handsonTable from "@/components/old-adm/common/handsontable";
+import Dict from "@/controller/old-adm/dicController";
+
+import Scan from '@/controller/old-adm/ScanController'
+import { mapGetters, mapActions } from "vuex";
+import BuildController from "@/controller/old-adm/buildController"
+import menum from "@/components/old-adm/dialogs/list/menum";
+
+const { getDataDictionary } = Dict
+const { createSystemBuildFloor }  = Scan
+export default {
+  components: {
+    handsonTable,
+    menum,
+    editSysfloor,
+		uploadImgDialog
+  },
+  data() {
+    return {
+      addNum: 1,
+      onlyRead: false,
+      showTypes: [
+        { value: "Visible", label: '只看采集信息' },
+        { value: "all", label: '全部' }
+      ],
+      tableHeader: [],
+      tableData: session.get("systemAddData")
+        ? session.get("systemAddData").length
+          ? session.get("systemAddData")
+          : [{}]
+        : [{}],
+      copyTableData: [],
+      category: "", //当前设备类
+      myDialog: {
+        qrcode: false, //二维码弹窗
+        uploadFiles: false, //上传文件
+        uploadImgs: false, //上传单个图片
+        pic: false, //多个图片
+        addDevice: false,
+        systemType: false,
+        details: false, //详情页
+        changeRea: false,
+        lookPic: false, //图片查看
+        menum: false, //临时多选枚举类型信息点
+      },
+      inputMap: {
+        flowBuild: {
+          editable: true,
+          code: "flowBuild",
+          name: "建筑楼层",
+          path: "flowBuild",
+          category: 'STATIC',
+          dataType: "ENUM"
+        }
+      }, //信息点和输入方式映射表
+      qrcodeUrl: "", //二维码图片地址
+      filesArr: [], //保存临时的文件key
+      imgsArr: [], //临时保存的图片key数组
+      picsArr: [], //临时设备图片keys数组
+      systemId: null,
+      graphyId: null,
+      id: 0,
+      showType: this.$route.query.showType,
+      EquipmentList: [],
+      createDisable: false,
+      updateInfoData: {}, //当前信息点信息
+      updateInfoPoint: "", //临时维护信息点键
+      updateInput: "", //临时维护信息点值
+    };
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId", "secret", "userId"])
+  },
+  created() {
+    this.category = this.$route.query;
+
+    this.getBuildData();
+    this.getTableHeader();
+  },
+  methods: {
+    //获取建筑数据
+    getBuildData() {
+      let param = {
+        pageNumber: 1,
+        pageSize: 1000,
+        projection: [
+          "id",
+          "localName"
+        ]
+      }
+      const res = BuildController.buildingQuery(param);
+        let data = res.content.map(t => {
+          return {
+            Code: t.id,
+            Name: t.localName,
+          }
+        })
+        data.unshift({ Code: '', Name: '未明确建筑' })
+        this.buildingData = data;
+      
+    },
+    // 获取表头数据(初始化表格)
+    async getTableHeader() {
+      let params = {
+        orders: "sort asc, name desc",
+        pageNumber: 1,
+        pageSize: 1000,
+        type: this.category.category
+      };
+      await getDataDictionary(params, res => {
+        this.tableHeader = res.content;
+        this.tableHeader.forEach(item => {
+            if (item.path) {
+              this.inputMap[item.path] = item;
+            }
+        })
+        this.initTable();
+      });
+    },
+    // 创建设备数据
+    async handleCreateTableData() {
+      let params = {}
+      let newData = this.tableData.filter(item => {
+        let keys = Object.keys(item);
+        keys.map(key => {
+          //将值为空字符串的属性删除
+          if (item[key] == "") {
+            delete item[key];
+          }
+        });
+        let newK = Object.keys(item)
+        if (newK.length) {
+          return item;
+        }
+      });
+      if (!newData.length) {
+        this.$message("创建信息为空,请录入信息后再创建!");
+        return;
+      }
+      let flag = false;
+      newData.map(item => {
+        if (!item.localName) {
+          flag = true;
+        }
+        item.classCode = this.category.category
+      })
+      if (flag) {
+        this.$message.info("存在系统的本地名称为空,请检查")
+        return;
+      }
+      params.content = newData
+      this.createDisable = true;
+      createSystemBuildFloor(params, res => {
+        this.createDisable = false;
+        this.$message.success('创建成功')
+        session.remove("systemAddData")
+        this.$router.push({
+          name: "systemlist",
+          params: { SysType: this.category.category }
+        });
+      })
+    },
+    // 删除表格行
+    handleDeleteTableRow(a,b,c,d) {
+      if (d && d === 'ContextMenu.removeRow') {
+				this.$message.success("删除成功");
+    		this.formaTableData();
+			}
+    },
+    // 添加行
+    handleAddTableRow() {
+      let addRowLength = this.addNum;
+      for (let i = 0; i < addRowLength; i++) {
+        this.tableData.push({});
+      }
+      this.initTable();
+      this.formaTableData();
+    },
+    //修改
+    handleUpdataTable(changeData, source) {
+      this.formaTableData();
+    },
+    //保存去掉空字段的新增数据
+    formaTableData() {
+      let newData = this.tableData.filter(item => {
+        let keys = Object.keys(item);
+        keys.map(key => {
+          //将值为空字符串的属性删除
+          if (item[key] == "") {
+            delete item[key];
+          }
+        });
+        if (keys.length && Object.keys(item).length) {
+          return item;
+        }
+      });
+      session.set("systemAddData", newData);
+    },
+    //格式化表头显示的数据
+    formatHeaderData(list) {
+      let arr = tools.copyArr(list);
+      let data = showTools.headerTextFilter(arr, 'system', this.onlyRead, this.showType);
+      data.unshift("所属建筑楼层");
+      return data;
+    },
+    formatHeaderType(list) {
+      //格式化表头头映射的数据
+      let arr = tools.copyArr(list);
+      let data = showTools.headerTypeFilter(arr, 'system', this.onlyRead, this.showType);
+      data.unshift({
+        data: "buildingFloorInfoList",
+        renderer: text.sysInBuildFloor
+      });
+      return data;
+    },
+    initTable() {
+      //实例化表格
+      let settings = {
+        data: this.tableData,
+        colHeaders: this.formatHeaderData(this.tableHeader),
+        columns: this.formatHeaderType(this.tableHeader),
+        rowHeights: 30,
+        fillHandle: 'vertical', //允许纵向填充
+        maxRows: this.tableData.length,
+        contextMenu: this.onlyRead ? false : {
+          items: {
+            remove_row: {
+              name: "删除该系统"
+            }
+          }
+        },
+        autoColumnSize: true,
+        language: "zh-CN",
+        manualColumnResize: true,
+        manualColumnMove: true,
+        // 事件
+        afterChange: this.handleUpdataTable, //修改后
+        afterFilter: this.trimmedRows, //排序前
+        afterRemoveRow: this.handleDeleteTableRow, //右键删除
+        afterOnCellMouseDown: this.handleTdClick //鼠标点击
+      };
+      this.$nextTick(() => {
+        this.tableExample = this.$refs.table.init(settings);
+      });
+    },
+    //去除数组中相同的元素
+    array_diff(a, b) {
+      for (var i = 0; i < b.length; i++) {
+        for (var j = 0; j < a.length; j++) {
+          if (a[j] == b[i]) {
+            a.splice(j, 1);
+            j = j - 1;
+          }
+        }
+      }
+      return a;
+    },
+    //表格点击事件
+    handleTdClick(el, rowArr) {
+      //点击的是表头
+      if (rowArr.row < 0) {
+        return;
+      }
+      //被筛选过后的数组
+      let trimmedArr = this.trimmedRows();
+      //是否启用了排序
+      let isSort = this.tableExample.getPlugin("columnSorting").isSorted();
+      if (trimmedArr.length && isSort) {
+        let sortArr = this.myHotArr.getPlugin("columnSorting").rowsMapper
+          .__arrayMap;
+        let infos = this.tableData[trimmedArr[sortArr[rowArr.row]]];
+        this.getInfors(infos, { row: sortArr[rowArr.row], col: rowArr.col });
+      } else if (isSort) {
+        //排序后的数组
+        let sortArr = this.tableExample.getPlugin("columnSorting").rowsMapper
+          .__arrayMap;
+        let infos = this.tableData[sortArr[rowArr.row]];
+        this.getInfors(infos, { row: sortArr[rowArr.row], col: rowArr.col });
+      } else if (trimmedArr.length) {
+        let infos = this.tableData[trimmedArr[rowArr.row]];
+        this.getInfors(infos, { row: trimmedArr[rowArr.row], col: rowArr.col });
+      } else {
+        let infos = this.tableData[rowArr.row];
+        this.getInfors(infos, rowArr);
+      }
+    },
+    //获取被筛选掉的行号
+    trimmedRows() {
+      var plugin = this.tableExample.getPlugin("trimRows").trimmedRows;
+      let dataLength = this.tableData.length;
+      let dataArr = new Array();
+      for (let i = 0; i < dataLength; i++) {
+        dataArr.push(i);
+      }
+      if (plugin.length <= 0) {
+        dataArr = undefined;
+      } else {
+        dataArr = this.array_diff(dataArr, plugin);
+      }
+      return dataArr || [];
+    },
+    getInfors(infos, row) {
+      let val = this.tableExample.colToProp(row.col);
+      let inputData = this.inputMap[val];
+      this.row = row.row;
+      this.messKey = val;
+      switch (val) {
+        //操作
+        case 'caozuo':
+          // window.open(`http://adm.sagacloud.cn:8058/spread?id=${infos.EquipID}&pid=${this.projectId}&secret=${this.secret}`,"_blank")
+          this.$message("开发中...")
+          break;
+        //设备二维码图片
+        // case 'EquipQRCode':
+        // case "defaultQRCode":
+        //   this.qrcodeUrl = this.tableData[row.row].EquipQRCode;
+        //   if (!!this.qrcodeUrl) {
+        //     this.myDialog.qrcode = true;
+        //   } else {
+        //     this.$message("此设备没有设备二维码");
+        //   }
+        //   break;
+        //关联设备数量
+        case 'count':
+          if (!this.onlyRead) {
+            this.myDialog.relevance = true
+          }
+          break;
+        //所属建筑楼层
+        case 'buildingFloorInfoList':
+          if (!this.onlyRead) {
+            this.$refs.editFloor.showDialog(this.tableData[row.row]);
+          }
+          break;
+				//系统图(F2)
+        case "infos.systemChart":
+          let SSPPdata = tools.dataForKey(this.tableData[row.row], val);
+          this.imgsArr = SSPPdata ? SSPPdata : [];
+          this.myDialog.uploadImgs = true;
+          return false;
+        default:
+          break;
+      }
+      // 维护多选枚举值
+      if (!this.onlyRead && inputData.dataType == "MENUM") {
+        this.updateInfoData = inputData;
+        this.updateInfoPoint = val;
+        this.updateInput = tools.dataForKey(this.tableData[row.row], val);
+        this.myDialog.menum = true;
+        return false;
+      }
+      if (!this.onlyRead && !inputData.editable) {
+        this.$confirm('该信息点的值为自动生成,不可人工维护!', '提示', {
+            confirmButtonText: '我知道了',
+            showCancelButton: false,
+            type: 'warning',
+            center: true
+        }).then(() => {
+            return false;
+        });
+      }
+    },
+    //多选枚举类型值修改
+    handleChangeMenum(newValue) {
+        tools.setDataForKey(
+        this.tableData[this.row],
+        this.updateInfoPoint,
+        newValue
+      );
+      this.handleUpdataTable(
+        [[this.row, this.updateInfoPoint, null, newValue]],
+        "edit"
+      );
+      this.myDialog.menum = false;
+      this.updateInput = "";
+    },
+	//上传图片弹窗触发事件
+    imgChange(keys) {
+		this.setDataToMain(keys, this.messKey, this.row);
+    },
+    //建筑楼层
+    relateSuccess(data) {
+      this.tableData[this.row].buildingFloorInfoList = data
+      this.tableExample.render()
+    },
+		//判断是否有值,有值赋值
+    setDataToMain(data, key, row) {
+		if (!!data && data != "--") {
+        if (!!this.tableData[row]) {
+          tools.setDataForKey(this.tableData[row], key, data);
+          this.handleUpdataTable([[row, key, null, data]], "edit");
+        } else {
+          this.tableData[row] = {};
+          tools.setDataForKey(this.tableData[row], key, data);
+        }
+      } else {
+        tools.setDataForKey(this.tableData[row], key, "");
+      }
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#deviceList {
+  overflow: hidden;
+  height: 100%;
+  background-color: #fff;
+  padding: 10px;
+  position: relative;
+
+  .right {
+    background: #fff;
+    padding: 16px;
+    line-height: 32px;
+  }
+
+  .search-header {
+    overflow: hidden;
+    padding: 0 10px 10px 10px;
+    border-bottom: 1px solid #bcbcbc;
+  }
+
+  .tableBox {
+    display: flex;
+    height: calc(100% - 100px);
+    margin-top: 10px;
+
+    .tableLeft {
+      flex: 1;
+    }
+  }
+
+  .create_button {
+    padding-top: 10px;
+  }
+}
+</style>

+ 12 - 0
src/components/old-adm/relation/overview/index.vue

@@ -1,5 +1,12 @@
 <template>
   <div style="overflow: hidden auto" v-loading="loading">
+    
+    <div style="text-align: right; margin: 8px; user-select:none;">
+        <a  style="text-decoration: underline; cursor: pointer" @click="toggleRelation">
+          {{currentRelation === 'deliver' ?  '显示数据字典中的全部关系' : '只显示项目要交付的关系' }}
+        </a>
+    </div>
+    <!-- <Divider style="height: 0.5px" /> -->
     <cardList
       :content="content"
       :source="source"
@@ -46,6 +53,7 @@ export default {
       currentRelationTypeName: "", //当前点击卡片的RelationTypeName
       TableVisibleMoreLoading: false,
       computingNum: 0, //正在计算的关系数量
+      currentRelation: 'deliver'    //当前所展示的关系 all: 全部关系, deliver: 交付关系
     };
   },
   created() {
@@ -66,6 +74,10 @@ export default {
     CardList 
   },
   methods: {
+    toggleRelation() {
+      
+      this.currentRelation = this.currentRelation === 'deliver' ? 'all' : 'deliver'
+    },
     init() {
       this.loading = true;
       let dataNumber = {

+ 28 - 6
src/components/systemGraph/edit.vue

@@ -315,6 +315,7 @@ import graph from "./graph.vue";
 import { logicConfig } from "@/logicConfig";
 import { Message } from "element-ui";
 import Vue from "vue";
+import vueStore from "@/store";
 
 export default {
   props: [],
@@ -582,15 +583,33 @@ export default {
      */
     saveGraph: async function () {
       this.fullscreenLoading = true;
-      var saveResultObj = await sysGraphController.saveSysGraph(this.graphInfo);
-      this.fullscreenLoading = false;
+      var saveResultObj = await sysGraphController.saveSysGraph(
+        this.graphInfo,
+        this.project.id,
+        this.project.groupCode
+      );
       switch (saveResultObj.result) {
         case logicConfig.resultObj.failure:
+          this.fullscreenLoading = false;
           Message.error("保存失败:" + (saveResultObj.message || ""));
           return;
         case logicConfig.resultObj.success:
-          Message.success("保存成功");
           this.graphOriginInfo = JSON.parse(JSON.stringify(this.graphInfo));
+          //保存成功后,更新系统图状态为下架
+          var draftResultObj = await sysGraphController.draftGraph(
+            this.diagramId
+          );
+          this.fullscreenLoading = false;
+          switch (draftResultObj.result) {
+            case logicConfig.resultObj.success:
+              Message.success("保存成功");
+              break;
+            case logicConfig.resultObj.failure:
+              Message.error(
+                "保存成功,更新状态失败,原因:" + (resultObj.message || "")
+              );
+              break;
+          }
           break;
       }
     },
@@ -613,7 +632,7 @@ export default {
           this.graphInfo.extraProps.state = graphStateEnum.Publish;
           return Message.success("上架成功");
         case logicConfig.resultObj.failure:
-          return Message.success("上架失败,原因:" + (resultObj.message || ""));
+          return Message.error("上架失败,原因:" + (resultObj.message || ""));
       }
     },
     //下架系统图
@@ -627,7 +646,7 @@ export default {
           this.graphInfo.extraProps.state = graphStateEnum.Draft;
           return Message.success("下架成功");
         case logicConfig.resultObj.failure:
-          return Message.success("下架失败,原因:" + (resultObj.message || ""));
+          return Message.error("下架失败,原因:" + (resultObj.message || ""));
       }
     },
     //删除系统图
@@ -655,7 +674,7 @@ export default {
               });
               return;
             case logicConfig.resultObj.failure:
-              return Message.success(
+              return Message.error(
                 "删除图纸失败,原因:" + (resultObj.message || "")
               );
           }
@@ -778,6 +797,9 @@ export default {
       groupCode: this.$route.query.gc,
       name: this.$route.query.prn,
     };
+    if (this.operState === 0 || this.operState === 1) {
+      vueStore.commit("updateSelectProject", this.project);
+    }
   },
   mounted() {
     var _this = this;

+ 75 - 4
src/components/systemGraph/graph.vue

@@ -101,6 +101,7 @@ export default {
   methods: {
     //绘图入口
     drawEntry: function (graphInfo) {
+      if (!graphInfo) return;
       //把原始数据转为易于绘图的数据
       var graphDataObj = this.parseDataToDraw(graphInfo);
       this.nodeArr = graphDataObj.nodeArr;
@@ -234,12 +235,12 @@ export default {
         pixiApp.stage.addChild(textInstance);
       });
 
-      return;
       //画线
-      _this.dataSource.view.diagram.lines.forEach((_cLine) => {
+      _this.lineArr.forEach((_cLine) => {
         var lineColor = "0x" + _cLine.style.lineColor.substring(1);
         var lineInstance = new PIXI.Graphics();
         lineInstance.lineStyle(_cLine.style.lineWidth, lineColor, 1, 0, false);
+        lineInstance.name = _cLine.id;
 
         var _newStart = _this.convertCoordToLeftOrigina({
           x: _cLine.path[0].x,
@@ -254,6 +255,14 @@ export default {
         lineInstance.moveTo(_newStart.x, _newStart.y);
         lineInstance.lineTo(_newEnd.x, _newEnd.y);
 
+        //设置点击范围,不然click事件不会触发
+        lineInstance.hitArea = lineInstance.getBounds();
+        //启用事件
+        lineInstance.interactive = true;
+        lineInstance.on("click", (event) => {
+          _this.clickEventCall(event, 2);
+        });
+
         pixiApp.stage.addChild(lineInstance);
       });
     },
@@ -267,9 +276,14 @@ export default {
       //文本数组
       var labelArr = [];
 
-      var rootContainerArr = graphInfo.template.frame.children;
+      if (graphInfo.template) {
+        var rootContainerArr = graphInfo.template.frame.children;
 
-      parseNode(rootContainerArr, graphInfo.template.frame.location);
+        parseNode(rootContainerArr, graphInfo.template.frame.location);
+
+        parseLine(graphInfo.lines || []);
+        parseMainPies(graphInfo.template.mainPipes);
+      }
 
       return {
         nodeArr,
@@ -365,6 +379,63 @@ export default {
           }
         });
       }
+
+      /**
+       * 解析线
+       */
+      function parseLine(lines) {
+        lines.forEach((_line) => {
+          if (_line.flag != "duplicate") {
+            _line.id = _line.id || _line.dataObjectId;
+            let lineDefaultStyle = window.__systemConf.systemGraph.peiDian.line;
+            lineArr.push({
+              id: _line.id,
+              path: _line.locationPath,
+              style: {
+                lineWidth: lineDefaultStyle.width,
+                lineColor: lineDefaultStyle.color,
+              },
+            });
+          }
+        });
+      }
+
+      /**
+       * 解析干管,当做线处理
+       */
+      function parseMainPies(_dataArr) {
+        _dataArr.forEach((_data) => {
+          _data.id = _data.id || _data.dataObjectId;
+          let lineDefaultStyle = window.__systemConf.systemGraph.peiDian.line;
+
+          var pathArr = eachPathArr(_data.locationPath || [], []);
+
+          lineArr.push({
+            id: _data.id,
+            path: pathArr,
+            style: {
+              lineWidth: lineDefaultStyle.width,
+              lineColor: lineDefaultStyle.color,
+            },
+          });
+        });
+      }
+
+      /**
+       * 递归解析path数组
+       */
+      function eachPathArr(_arr, returnArr) {
+        _arr.forEach((_data) => {
+          if (_data instanceof Array) {
+            eachPathArr(_data, returnArr);
+          } else
+            returnArr.push({
+              x: _data.x,
+              y: _data.y,
+            });
+        });
+        return returnArr;
+      }
     },
     /**
      * 1、X轴的原始坐标两端可能是不对称的;Y轴的原始坐标两端也可能是不对称的,所以计算各自的差值,以便把两端对称起来,以此把图形显示到正中间

+ 20 - 5
src/components/systemGraph/index.vue

@@ -60,7 +60,6 @@
 </template>
 <script>
 import { mapState } from "vuex";
-import { logicConfig } from "@/logicConfig";
 import { sysGraphController } from "@/controller/systemGraph/sysGraphController";
 
 export default {
@@ -71,6 +70,8 @@ export default {
       searchVal: "",
       //后台返回的所有的数据
       allGraphArr: [],
+      //用于页面绑定的数据全集
+      allGraphArrToPage: [],
       //用于表格内绑定
       graphArr: [],
       //当前页码
@@ -123,24 +124,33 @@ export default {
     getCurrPageData: function () {
       var startIndex = (this.currentPage - 1) * this.pageSize;
       var endIndex = startIndex + this.pageSize;
-      this.graphArr = this.allGraphArr.slice(startIndex, endIndex);
+      this.graphArr = this.allGraphArrToPage.slice(startIndex, endIndex);
     },
     //关键词输入框输入改变事件
     searchInputChange: function () {
       this.currentPage = 1;
-      this.getData();
+      var keyVal = this.searchVal;
+      var tempArr = !keyVal
+        ? this.allGraphArr
+        : this.allGraphArr.filter((_c) => {
+            return (_c.sysInstance || "").indexOf(keyVal) > -1;
+          });
+      this.allGraphArrToPage = tempArr;
+      this.dataCount = this.allGraphArrToPage.length;
+      this.getCurrPageData();
     },
     //查询数据
     getData: async function () {
       try {
-        this.allGraphArr = await sysGraphController.getDiagrams(this.searchVal);
-        this.dataCount = this.allGraphArr.length;
+        this.allGraphArr = await sysGraphController.getDiagrams();
+        this.searchInputChange();
         this.getCurrPageData();
 
         this.fullscreenLoading = false;
       } catch (error) {
         console.error(error);
         this.allGraphArr = [];
+        this.allGraphArrToPage = [];
         this.graphArr = [];
         this.dataCount = 0;
         this.fullscreenLoading = false;
@@ -164,6 +174,11 @@ export default {
   },
   mounted() {},
   components: {},
+  watch: {
+    selectProject: function () {
+      this.getData();
+    },
+  },
 };
 </script>
 

+ 12 - 0
src/controller/old-adm/ScanController.ts

@@ -419,6 +419,18 @@ class ScanController {
       params
     );
   }
+  /**
+   * @description: 创建系统---处理建筑楼层(一对多)
+   * @param {*}
+   * @return {*}
+   */  
+  static async createSystemBuildFloor(params, fn) {
+    const res = await this.http.postRequest(
+      object_pre + '/general-system/create-bd-fl',
+      params
+    )
+    return fn ? fn(res) : res
+  }
 }
 
 export default ScanController;

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 23 - 10127
src/controller/systemGraph/sysGraphController.ts


+ 2 - 1
src/meri.js

@@ -1,5 +1,5 @@
 import Vue from 'vue'
-import {Button, Input, MSelect, Icon, Popover, ImageUpload, Modal, MCascade, PickerDate} from 'meri-design'
+import {Button, Input, MSelect, Icon, Popover, ImageUpload, Modal, MCascade, PickerDate, Divider} from 'meri-design'
 
 Vue.use(Button)
 Vue.use(Input)
@@ -10,3 +10,4 @@ Vue.use(ImageUpload)
 Vue.use(Modal)
 Vue.use(MCascade)
 Vue.use(PickerDate)
+Vue.use(Divider)

+ 13 - 0
src/router/system.js

@@ -12,6 +12,7 @@ import deviceDetails from "@/components/old-adm/ledger/facility/details/index";
 import deviceadd from '@/components/old-adm/ledger/facility/addfacility'
 // 系统台账
 import systemLedger from '@/components/old-adm/ledger/system/index';
+import systemadd from '@/components/old-adm/ledger/system/addsystem'
 import batchPointAssets from '@/components/old-adm/ledger/facility/batchPoint' //批量维护设备位置
 import buildFloor from '@/components/old-adm/ready/buildfloor/index'
 import repetitionGraphy from '@/components/old-adm/ready/buildfloor/repetitionGraphy'
@@ -111,6 +112,18 @@ export default [
         component: systemLedger,
       },
       {
+        path: '/ledger/systemadd',
+        name: 'systemadd',
+        component: systemadd,
+        meta: {
+          keepAlive: false,
+          breadcrumbs: [{label: '台账管理', path: '/ledger/facility'}, {
+            label: '系统台账',
+            path: '/ledger/list'
+          }, {label: '添加系统'}]
+        }
+      },
+      {
         path: '/relation/overview',
         name: "全部关系总览",
         component: overView,

+ 158 - 10
src/utils/http/basic/axiosUtils.ts

@@ -6,6 +6,8 @@
 import axios from "axios";
 import vueStore from "@/store";
 import { logicConfig } from "@/logicConfig";
+import { toolUtils } from "@/utils/toolUtils";
+import SparkMD5 from 'spark-md5';
 
 var CancelToken = axios.CancelToken;
 var cancel;
@@ -35,7 +37,7 @@ axiosservice.interceptors.response.use(
     return res;
   },
   function (err) {
-    console.log("axios interceptors err = ", err);
+    console.error("axios interceptors err = ", err);
     return Promise.reject(err);
   }
 );
@@ -53,12 +55,9 @@ export class axiosUtils {
       var urlPrefix = urlArr[0];
       var urlParamStr = urlArr[1] || "";
 
-      var paramKeyArr = Object.keys(data || {});
-      paramKeyArr.forEach(_key => { 
-        urlParamStr = _key + '=' + data[_key] + '&' + urlParamStr;
-      });
+      var _newParamStr = toolUtils.objectKeyToUrlParam(data);
 
-      var newUrl = urlPrefix + '?' + urlParamStr;
+      var newUrl = urlPrefix + '?' + _newParamStr + (_newParamStr ? '&' : '') + urlParamStr;
 
       let response = await this.customRequest(newUrl, {}, {}, "get");
       return response;
@@ -131,10 +130,159 @@ export class axiosUtils {
     } catch (err) {
       // throw err;
       console.error(err);
-      return {
-        result: logicConfig.resultObj.failure,
-        message: '请求异常'
-      };
+      return toolUtils.resultConstructor(logicConfig.resultObj.failure, null, '请求异常,' + err.message);
     }
   }
+
+
+  /**
+   * 上传文件
+   * @param _paramobj 格式如下:
+   * {
+   *    fileServiceUrl 文件服务地址
+   *    uploadProgressCall 上传进度回调函数,函数参数为object,格式如下:{fileName:'文件名称',uploadedTotal:1},uploadedTotal某个文件总共上传的字节数
+   *    oneUploadedCall 每上传完一个后的回调函数,函数参数为object,格式如下:{fileName:'文件名称',fileId:'文件ID'}
+   *    userId:'不传时,默认会取vuex中user.id',
+   *    files 数组或者object,示例
+   *    { 
+   *      groupCode:'不传时,默认会取vuex中selectProject.groupCode',
+   *      projectId:'不传时,默认会取vuex中selectProject.id',
+   *      fileName:'文件名称',
+   *      fileBucket:'存储空间名称,可以不传',
+   *      file:文件信息,假设有一个input type为file id为txtFile的标签,那么file为document.getElementById('txtFile').files[0]
+   *    }
+   * }
+   * @returns 
+   */
+  protected async uploadFiles(_paramobj: any) {
+    //注意,这里的this 指向的是实例化的子类
+    var _this = this;
+    let userId = _paramobj.userId || vueStore.state.user.id;
+    let fileServiceUrl = _paramobj.fileServiceUrl;
+    let files = _paramobj.files;
+    try {
+      let waitFiles = files instanceof Array == true ? files : [files];
+      //上传成功的文件数量
+      let uploadedCount = 0;
+
+      for (let i = 0; i < waitFiles.length; i++) {
+        let _currFileObj = waitFiles[i];
+
+        //获取文件md5
+        let fileContentMd5 = await getFileContentMd5(_currFileObj);
+        //获取文件上传地址
+        let getUploadResult = await getUploadUrl(fileContentMd5 as string, _currFileObj);
+        switch (getUploadResult.result) {
+          case logicConfig.resultObj.success:
+            let getUploadData = getUploadResult.data || {};
+            //uploadCode 200 代表已经上传过了;    201  代表需上传
+            switch (getUploadData.uploadCode) { 
+              case 201:
+                //获取文件地址上传成功时进行上传
+                let uploadUrl = ((getUploadData.content || [])[0] || {}).uploadUrl;
+                if (!uploadUrl)
+                  return toolUtils.resultConstructor(logicConfig.resultObj.failure, null, '未获取到文件' + _currFileObj.fileName + '的上传地址');
+                //开始上传
+                await upload(uploadUrl, _currFileObj.file, function (progressObj) {
+                  if (typeof _paramobj.uploadProgressCall == 'function') {
+                    let uploadedFileSize = progressObj.loaded / progressObj.total * _currFileObj.file.size;
+                    _paramobj.uploadProgressCall({ uploadedTotal: uploadedFileSize, fileName: _currFileObj.fileName });
+                  }
+                });
+              case 200:
+                ++uploadedCount;
+                if (typeof _paramobj.oneUploadedCall == 'function') {
+                  _paramobj.oneUploadedCall({ fileName: _currFileObj.fileName, fileId: getUploadData.id });
+                }
+                break;
+            }
+            break;
+          default:
+            return toolUtils.resultConstructor(logicConfig.resultObj.failure, null, '获取文件' + _currFileObj.fileName + '的上传地址时出错:' + getUploadResult.message);
+        }
+        if (uploadedCount == waitFiles.length)
+          return toolUtils.resultConstructor(logicConfig.resultObj.success, null, null);
+      }
+    } catch (error) {
+      console.error(error);
+      return toolUtils.resultConstructor(logicConfig.resultObj.failure, null, error.message);
+    }
+
+    //获取文件内容的md5值
+    function getFileContentMd5(_fileObj) {
+      return new Promise((resolve, reject) => {
+        let file = _fileObj.file;
+        let blobSlice = File.prototype.slice;
+        let chunkSize = 2097152;
+        let chunks = Math.ceil(file.size / chunkSize);
+        let currentChunk = 0;
+        let spark = new SparkMD5.ArrayBuffer();
+        let fileReader = new FileReader();
+        fileReader.onload = function (e) {
+          spark.append(e.target.result);                   // Append array buffer
+          currentChunk++;
+          if (currentChunk < chunks) {
+            loadNext();
+          } else {
+            let fileContentMd5 = spark.end();
+            console.info('computed hash', fileContentMd5);  // Compute hash
+            //文件md5获取完成后,调用后台接口获取上传地址
+            // let getUploadResult = await getUploadUrl(fileContentMd5, _fileObj.fileName, file.size);
+            resolve(fileContentMd5);
+          }
+        };
+
+        fileReader.onerror = function (e) {
+          let errStr = '文件:' + _fileObj.fileName + '读取错误:';
+          console.error(e);
+          reject(errStr);
+        };
+
+        function loadNext() {
+          var start = currentChunk * chunkSize,
+            end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
+
+          fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
+        }
+
+        loadNext();
+      });
+    };
+
+    //获取文件上传地址
+    async function getUploadUrl(fileContentMd5: string, _fileObj: any) {
+      let fileName = _fileObj.fileName;
+      let fileSize = _fileObj.file.size;
+      let projectId = _fileObj.projectId || vueStore.state.selectProject.id;
+      let groupCode = _fileObj.groupCode || vueStore.state.selectProject.groupCode;
+      //应用ID暂时用不上
+      let appId = '';
+
+      let getUploadUrl = toolUtils.getBaseHttpUrl(fileServiceUrl, 'file/initSingleUpload') +
+        '?userId=' + userId + '&projectId=' + projectId + '&groupCode=' + groupCode + '&appId=';
+
+      let paramObj = {
+        fileMd5: fileContentMd5,
+        fileName: fileName,
+        fileBucket: (window as any).__systemConf.baseRouteUrl,
+        fileSize: fileSize
+      };
+      return await _this.customRequest(getUploadUrl, null, paramObj, 'post');
+    };
+
+    //上传
+    async function upload(uploadUrl, file, uploadProgressCall) {
+      return new Promise((resolve, reject) => {
+        var formData = new FormData();
+        formData.append('file', file);
+        axios.put(uploadUrl, formData, {
+          onUploadProgress: uploadProgressCall
+        }).then(function (res) {
+          resolve(res);
+        }).catch(function (error) {
+          reject(error);
+        });
+      });
+    }
+  };
 }

+ 22 - 0
src/utils/http/basic/httpUtils.ts

@@ -62,4 +62,26 @@ export class httpUtils extends axiosUtils {
   ) {
     return await super.customRequest(url, headers, data, method);
   }
+
+  /**
+   * 上传文件
+   * @param _paramobj 格式如下:
+   * {
+   *    uploadProgressCall 上传进度回调函数,函数参数为object,格式如下:{uploadedTotal:1},uploadedTotal总共上传了多少字节,是所有文件上传的字节数总和
+   *    oneUploadedCall 每上传完一个后的回调函数,函数参数为object,格式如下:{fileName:'文件名称'}
+   *    userId:'不传时,默认会取vuex中user.id',
+   *    files 数组或者object,示例
+   *    { 
+   *      groupCode:'不传时,默认会取vuex中selectProject.groupCode',
+   *      projectId:'不传时,默认会取vuex中selectProject.id',
+   *      fileName:'文件名称',
+   *      fileBucket:'存储空间名称,可以不传',
+   *      file:文件信息,假设有一个input type为file id为txtFile的标签,那么file为document.getElementById('txtFile').files[0]
+   *    }
+   * }
+   */
+  public async uploadFiles(_paramobj: any) {
+    _paramobj.fileServiceUrl = this.baseUrl;
+    return await super.uploadFiles(_paramobj);
+  }
 }

+ 12 - 0
src/utils/http/fileHttpUtils.ts

@@ -0,0 +1,12 @@
+/**
+ * 文件访问的http辅助类,供业务调用
+ * nh 2022.01.18
+ */
+
+import { httpUtils } from "./basic/httpUtils";
+
+export class fileHttpUtils extends httpUtils {
+    constructor() {
+        super((window as any).__systemConf.fileServiceUrl);
+    };
+}

+ 26 - 0
src/utils/toolUtils.ts

@@ -74,4 +74,30 @@ export class toolUtils {
     }
     return newData;
   };
+
+  /**
+   * 把object对象中的属性转为url中的参数字符串。比如:{a:1,b:2}转为a=1&b=2
+   */
+  static objectKeyToUrlParam(_obj: any) {
+    var paramStr = '';
+    var keyArr = Object.keys(_obj || {});
+    keyArr.forEach((_key, _index) => {
+      paramStr = paramStr + _key + '=' + _obj[_key] + (_index == keyArr.length - 1 ? '' : '&');
+    });
+    return paramStr;
+  };
+
+  /**
+   * 拼装返回给页面的接口调用结果
+   * resultStr 结果字符串,成功时为success,否则为失败码
+   * data 数据
+   * reason 失败时的原因
+   */
+  static resultConstructor(resultStr, data, reason) {
+    return {
+      result: resultStr,
+      data: data,
+      message: reason
+    };
+  };
 }