Browse Source

合并dev-master

zhangyu 4 years ago
parent
commit
61aa49d126
100 changed files with 11616 additions and 2975 deletions
  1. 8 0
      README.md
  2. 0 1
      build/webpack.dev.conf.js
  3. 1 1
      config/dev.env.js
  4. 2 1
      config/index.js
  5. 6 6
      config/prod.env.js
  6. 97 86
      package.json
  7. 39 0
      publish.js
  8. 7 1
      src/App.vue
  9. 109 0
      src/api/data_admin/buildTaskApi.js
  10. 168 139
      src/api/model/file.js
  11. 29 0
      src/api/model/report.js
  12. 56 0
      src/api/msgsever.js
  13. 135 0
      src/api/relation/api.js
  14. 21 21
      src/api/scan/fetch.js
  15. 42 42
      src/api/scan/httpUtil.js
  16. 1004 684
      src/api/scan/request.js
  17. 30 0
      src/api/uploader/index.js
  18. BIN
      src/assets/image/floorBG.png
  19. 78 6
      src/assets/style/iconfont/iconfont.css
  20. BIN
      src/assets/style/iconfont/iconfont.eot
  21. 55 1
      src/assets/style/iconfont/iconfont.svg
  22. BIN
      src/assets/style/iconfont/iconfont.ttf
  23. BIN
      src/assets/style/iconfont/iconfont.woff
  24. 19 9
      src/components/business_space/business/handsontable.vue
  25. 1 1
      src/components/business_space/dialogs/addDialog/businessDialog.vue
  26. 5 3
      src/components/business_space/dialogs/list/firm.vue
  27. 2 1
      src/components/business_space/newAddDialogs/addEquipDialog.vue
  28. 1 0
      src/components/business_space/newAddDialogs/addSystemDialog.vue
  29. 136 0
      src/components/business_space/newAddDialogs/roomInFloorDialog.vue
  30. 51 18
      src/components/business_space/newGraphy/canvasFun.vue
  31. 4 0
      src/components/business_space/newGraphy/createBSP.vue
  32. 408 163
      src/components/business_space/newGraphy/graphy.vue
  33. 137 27
      src/components/business_space/newGraphy/unRelateBSP.vue
  34. 16 5
      src/components/business_space/newTables/eqToSpaceTable.vue
  35. 17 5
      src/components/business_space/newTables/syInSpaceTable.vue
  36. 8 8
      src/components/business_space/table/equipTable.vue
  37. 184 0
      src/components/data_admin/buildTask/detail/assetsDetail.vue
  38. 287 0
      src/components/data_admin/buildTask/detail/deviceDetail.vue
  39. 97 0
      src/components/data_admin/buildTask/dialog/addTaskDialog.vue
  40. 253 0
      src/components/data_admin/buildTask/dialog/modelTaskDialog.vue
  41. 239 0
      src/components/data_admin/buildTask/draw/drawModel.vue
  42. 70 0
      src/components/data_admin/buildTask/lib/assetsCascader.vue
  43. 70 0
      src/components/data_admin/buildTask/lib/deviceCascader.vue
  44. 70 0
      src/components/data_admin/buildTask/lib/modelCascader.vue
  45. 81 0
      src/components/data_admin/buildTask/lib/modelFile.vue
  46. 53 0
      src/components/data_admin/buildTask/lib/taskState.vue
  47. 222 0
      src/components/data_admin/buildTask/table/assetsTable.vue
  48. 250 0
      src/components/data_admin/buildTask/table/deviceTable.vue
  49. 240 0
      src/components/data_admin/buildTask/table/modelTable.vue
  50. 202 0
      src/components/data_admin/buildTask/table/replaceTable.vue
  51. 202 0
      src/components/data_admin/buildTask/table/tearTable.vue
  52. 160 0
      src/components/data_admin/buildTask/taskStatistics.vue
  53. 136 0
      src/components/data_admin/zoneInput.vue
  54. 1 1
      src/components/dialogHanson/addDevice.vue
  55. 1 1
      src/components/dialogs/addDialog/businessDialog.vue
  56. 1 1
      src/components/dialogs/addDialog/dialogAssets.vue
  57. 2 2
      src/components/dialogs/addDialog/dialogDevice.vue
  58. 1 1
      src/components/dialogs/addDialog/dialogSystem.vue
  59. 582 0
      src/components/dialogs/list/batchDialog.vue
  60. 87 43
      src/components/dialogs/list/filesDialog.vue
  61. 126 121
      src/components/dialogs/list/firm.vue
  62. 111 107
      src/components/dialogs/list/insurerDialog.vue
  63. 111 107
      src/components/dialogs/list/maintainerDialog.vue
  64. 147 126
      src/components/dialogs/list/picDialog.vue
  65. 110 106
      src/components/dialogs/list/supplierDialog.vue
  66. 68 34
      src/components/dialogs/list/uploadImgDialog.vue
  67. 1 1
      src/components/echarts/doughnut.vue
  68. 99 0
      src/components/echarts/fanChart.vue
  69. 123 0
      src/components/echarts/reportDoughnut.vue
  70. 516 0
      src/components/globaluploader/index.vue
  71. 1 1
      src/components/ledger/addDialog/dialogAssets.vue
  72. 2 2
      src/components/ledger/addDialog/dialogDevice.vue
  73. 1 1
      src/components/ledger/addDialog/dialogSystem.vue
  74. 223 0
      src/components/ledger/cenote/dialog/addSpaceDialog.vue
  75. 2 2
      src/components/ledger/handsontables/assets.vue
  76. 1186 865
      src/components/ledger/handsontables/device.vue
  77. 61 32
      src/components/ledger/handsontables/system.vue
  78. 1 1
      src/components/ledger/lib/addDevice.vue
  79. 1 1
      src/components/ledger/lib/assets.vue
  80. 94 0
      src/components/ledger/lib/buildfloorCascader.vue
  81. 1 1
      src/components/ledger/lib/cascader.vue
  82. 299 0
      src/components/ledger/lib/cenoteGraphy.vue
  83. 119 0
      src/components/ledger/lib/editSysFloor.vue
  84. 6 5
      src/components/ledger/lib/floorCascader.vue
  85. 65 0
      src/components/ledger/lib/spaceSelect.vue
  86. 15 11
      src/components/ledger/lib/system.vue
  87. 196 155
      src/components/ledger/lib/uploadFiles.vue
  88. 1 1
      src/components/ledger/lib/uploadImgsName.vue
  89. 334 0
      src/components/ledger/rentList/roomCountDrawer.vue
  90. 82 0
      src/components/ledger/report/datafan.vue
  91. 101 0
      src/components/ledger/report/dataorigin.vue
  92. 180 0
      src/components/ledger/system/dialog/addCenoteDialog.vue
  93. 209 0
      src/components/ledger/system/dialog/addEquipDialog.vue
  94. 225 0
      src/components/ledger/system/dialog/addSpaceDialog.vue
  95. 140 0
      src/components/ledger/system/lib/equipType.vue
  96. 156 0
      src/components/ledger/system/table/cenoteTable.vue
  97. 144 0
      src/components/ledger/system/table/deviceTable.vue
  98. 156 0
      src/components/ledger/system/table/spaceTable.vue
  99. 20 17
      src/components/model/file/addFloorDialog.vue
  100. 0 0
      src/components/model/file/floorTable.vue

+ 8 - 0
README.md

@@ -145,3 +145,11 @@ export default {
 this.$store.dispatch('setBreadcrumb', [{ label: 'Demo' }, { label: 'Form'  ])
 this.$store.dispatch('setBreadcrumb', [{ label: 'Demo', path: '' }, { label: 'Form' , path: ''}])
 ```
+#### 上传管理器调用方法(上传较大文件时使用)
+
+```
+在组件中引入Bus中央时间总线
+    Bus.$emit('openUploader', query, file)    //添加文件到上传管理器中, query为参数, file为H5原生的文件对象
+    Bus.$on('fileAdded', () => {})            //文件选择后的回调
+    Bus.$on('fileSuccess', () => {})          //文件上传成功后的回调
+```

+ 0 - 1
build/webpack.dev.conf.js

@@ -87,7 +87,6 @@ module.exports = new Promise((resolve, reject) => {
                     onErrors: config.dev.notifyOnErrors ? utils.createNotifierCallback() : undefined
                 })
             )
-
             resolve(devWebpackConfig)
         }
     })

+ 1 - 1
config/dev.env.js

@@ -4,7 +4,7 @@ const prodEnv = require('./prod.env')
 
 module.exports = merge(prodEnv, {
     NODE_ENV: '"development"',
-    BASE_URL: '"http://192.168.20.215"', //测试iframe地址
+    BASE_URL: '"http://192.168.20.236"', //测试iframe地址
     SSO_SERVER: '"http://192.168.20.102:8080"', //(新)测试环境
     MQTT_SERVICE: '"ws://192.168.20.225:61614/stomp/"' //MQ测试环境地址
     // SSO_SERVER: '"http://sso.sagacloud.cn"',  //正式环境

+ 2 - 1
config/index.js

@@ -66,7 +66,7 @@ module.exports = {
             },
             '/ScanBuilding': {
                 // 目标 API 地址
-                target: 'http://192.168.20.235:8080/',
+                target: 'http://192.168.20.236:8080/',
                 // 如果要代理 websockets
                 ws: true,
                 // 将主机标头的原点更改为目标URL
@@ -90,6 +90,7 @@ module.exports = {
             },
             '/modelapi': {
                 target: 'http://192.168.20.225:8082',
+                // target: 'http://192.168.20.218:8082',//景灏
                 changeOrigin: true,
                 pathRewrite: {
                     "^/modelapi": "/"

+ 6 - 6
config/prod.env.js

@@ -1,10 +1,10 @@
 'use strict'
 module.exports = {
     NODE_ENV: '"production"',
-    // BASE_URL: '"http://192.168.20.215"', //测试iframe地址
-    // SSO_SERVER: '"http://192.168.20.102:8080"', //(新)测试环境
-    // MQTT_SERVICE: '"ws://192.168.20.225:61614/stomp/"' //MQ测试环境地址
-    BASE_URL: '"http://mbi.sagacloud.cn"', //线上iframe地址
-    SSO_SERVER: '"http://sso.sagacloud.cn"',  //正式环境
-    MQTT_SERVICE: '"ws://adm.sagacloud.cn/stomp/"' //MQ正式环境地址
+    BASE_URL: '"http://192.168.20.236"', //测试iframe地址
+    SSO_SERVER: '"http://192.168.20.102:8080"', //(新)测试环境
+    MQTT_SERVICE: '"ws://192.168.20.225:61614/stomp/"' //MQ测试环境地址
+    // BASE_URL: '"http://mbi.sagacloud.cn"', //线上iframe地址
+    // SSO_SERVER: '"http://sso.sagacloud.cn"',  //正式环境
+    // MQTT_SERVICE: '"ws://adm.sagacloud.cn/stomp/"' //MQ正式环境地址
 }

+ 97 - 86
package.json

@@ -1,88 +1,99 @@
 {
-    "name": "sagacloud-admin",
-    "version": "1.0.0",
-    "description": "A Vue.js project",
-    "author": "yaoll <yaolinlin@sagacloud.cn>",
-    "private": true,
-    "scripts": {
-        "i": "npm install",
-        "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
-        "start": "npm run dev",
-        "build": "node build/build.js"
-    },
-    "dependencies": {
-        "@sybotan-web/base": "2.1.5",
-        "@sybotan-web/draw": "2.1.56",
-        "@sybotan-web/graphy": "2.1.27",
-        "axios": "^0.18.0",
-        "echarts": "^4.1.0",
-        "element-ui": "^2.11.0",
-        "font-awesome": "^4.7.0",
-        "handsontable-pro": "^3.0.0",
-        "jquery": "^3.3.1",
-        "vue": "^2.5.2",
-        "vue-axios": "^2.1.4",
-        "vue-router": "^3.0.1",
-        "vuex": "^3.1.0",
-        "cad-engine": "2.0.250",
-        "@saga-web/base": "2.1.8",
-        "@saga-web/draw": "2.1.57",
-        "@saga-web/graphy": "2.1.28",
-        "@saga-web/cad-engine": "2.0.308"
-    },
-    "devDependencies": {
-        "ajv": "^6.9.1",
-        "autoprefixer": "^7.1.2",
-        "babel-core": "^6.22.1",
-        "babel-helper-vue-jsx-merge-props": "^2.0.3",
-        "babel-loader": "^7.1.1",
-        "babel-plugin-syntax-jsx": "^6.18.0",
-        "babel-plugin-transform-runtime": "^6.22.0",
-        "babel-plugin-transform-vue-jsx": "^3.5.0",
-        "babel-preset-env": "^1.3.2",
-        "babel-preset-stage-2": "^6.22.0",
-        "chalk": "^2.0.1",
-        "copy-webpack-plugin": "^4.0.1",
-        "css-loader": "^0.28.0",
-        "extract-text-webpack-plugin": "^3.0.0",
-        "file-loader": "^1.1.4",
-        "file-saver": "^2.0.2",
-        "friendly-errors-webpack-plugin": "^1.6.1",
-        "html-webpack-plugin": "^2.30.1",
-        "less": "^3.9.0",
-        "less-loader": "^4.1.0",
-        "node-notifier": "^5.1.2",
-        "node-sass": "^4.11.0",
-        "optimize-css-assets-webpack-plugin": "^3.2.0",
-        "ora": "^1.2.0",
-        "portfinder": "^1.0.13",
-        "postcss-import": "^11.0.0",
-        "postcss-loader": "^2.0.8",
-        "postcss-url": "^7.2.1",
-        "rimraf": "^2.6.0",
-        "sass-loader": "^7.1.0",
-        "semver": "^5.3.0",
-        "shelljs": "^0.7.6",
-        "stompjs": "^2.3.3",
-        "swiper": "^4.0.0",
-        "uglifyjs-webpack-plugin": "^1.1.1",
-        "url-loader": "^0.5.8",
-        "vue-loader": "^13.3.0",
-        "vue-style-loader": "^3.0.1",
-        "vue-template-compiler": "^2.5.2",
-        "webpack": "^3.6.0",
-        "webpack-bundle-analyzer": "^2.9.0",
-        "webpack-dev-server": "^2.9.1",
-        "webpack-merge": "^4.1.0",
-        "xlsx": "^0.15.1"
-    },
-    "engines": {
-        "node": ">= 6.0.0",
-        "npm": ">= 3.0.0"
-    },
-    "browserslist": [
-        "> 1%",
-        "last 2 versions",
-        "not ie <= 8"
-    ]
+  "name": "sagacloud-admin",
+  "version": "1.0.0",
+  "description": "A Vue.js project",
+  "author": "yaoll <yaolinlin@sagacloud.cn>",
+  "private": true,
+  "remote": {
+    "host": "192.168.20.236",
+    "path": "/opt/nginx/ibms/dist",
+    "user": "root",
+    "password": "saga",
+    "local": "dist"
+  },
+  "scripts": {
+    "i": "npm install",
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+    "start": "npm run dev",
+    "build": "node build/build.js",
+    "publish": "node publish.js"
+  },
+  "dependencies": {
+    "@sybotan-web/base": "2.1.5",
+    "@sybotan-web/draw": "2.1.56",
+    "@sybotan-web/graphy": "2.1.27",
+    "axios": "^0.18.0",
+    "echarts": "^4.1.0",
+    "element-ui": "^2.11.0",
+    "font-awesome": "^4.7.0",
+    "handsontable-pro": "^3.0.0",
+    "jquery": "^3.3.1",
+    "vue": "^2.5.2",
+    "vue-axios": "^2.1.4",
+    "vue-router": "^3.0.1",
+    "vuex": "^3.1.0",
+    "cad-engine": "2.0.250",
+    "@saga-web/base": "2.1.9",
+    "@saga-web/draw": "2.1.61",
+    "@saga-web/graphy": "2.1.34",
+    "@saga-web/cad-engine": "2.0.432"
+  },
+  "devDependencies": {
+    "ajv": "^6.9.1",
+    "autoprefixer": "^7.1.2",
+    "babel-core": "^6.22.1",
+    "babel-helper-vue-jsx-merge-props": "^2.0.3",
+    "babel-loader": "^7.1.1",
+    "babel-plugin-syntax-jsx": "^6.18.0",
+    "babel-plugin-transform-runtime": "^6.22.0",
+    "babel-plugin-transform-vue-jsx": "^3.5.0",
+    "babel-preset-env": "^1.3.2",
+    "babel-preset-stage-2": "^6.22.0",
+    "chalk": "^2.0.1",
+    "copy-webpack-plugin": "^4.0.1",
+    "css-loader": "^0.28.0",
+    "extract-text-webpack-plugin": "^3.0.0",
+    "file-loader": "^1.1.4",
+    "file-saver": "^2.0.2",
+    "friendly-errors-webpack-plugin": "^1.6.1",
+    "html-webpack-plugin": "^2.30.1",
+    "less": "^3.9.0",
+    "less-loader": "^4.1.0",
+    "node-notifier": "^5.1.2",
+    "node-sass": "^4.11.0",
+    "node-ssh": "^6.0.0",
+    "optimize-css-assets-webpack-plugin": "^3.2.0",
+    "ora": "^1.2.0",
+    "portfinder": "^1.0.13",
+    "postcss-import": "^11.0.0",
+    "postcss-loader": "^2.0.8",
+    "postcss-url": "^7.2.1",
+    "rimraf": "^2.6.0",
+    "sass-loader": "^7.1.0",
+    "semver": "^5.3.0",
+    "shelljs": "^0.7.6",
+    "spark-md5": "^3.0.0",
+    "stompjs": "^2.3.3",
+    "swiper": "^4.0.0",
+    "uglifyjs-webpack-plugin": "^1.1.1",
+    "url-loader": "^0.5.8",
+    "vue-loader": "^13.3.0",
+    "vue-simple-uploader": "^0.7.2",
+    "vue-style-loader": "^3.0.1",
+    "vue-template-compiler": "^2.5.2",
+    "webpack": "^3.6.0",
+    "webpack-bundle-analyzer": "^2.9.0",
+    "webpack-dev-server": "^2.9.1",
+    "webpack-merge": "^4.1.0",
+    "xlsx": "^0.15.1"
+  },
+  "engines": {
+    "node": ">= 6.0.0",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
 }

+ 39 - 0
publish.js

@@ -0,0 +1,39 @@
+/*
+ * @Author: zhangyu
+ * @Date: 2019-12-18 16:18:30
+ * @Info: 自动化部署
+ * @LastEditTime: 2019-12-18 16:20:55
+ */
+
+const Client = require("node-ssh");
+const ssh = new Client();
+
+ssh.connect({
+  host: process.env.npm_package_remote_host,
+  port: "22",
+  username: process.env.npm_package_remote_user,
+  password: process.env.npm_package_remote_password
+}).then(() => {
+  const failedList = [];
+  ssh.putDirectory(
+    process.env.npm_package_remote_local,
+    process.env.npm_package_remote_path,
+    {
+      recursive: true,
+      concurrency: 1,
+      tick: function(localPath, remotePath, error) {
+        if (error) {
+          failedList.push(localPath);
+        }
+      }
+    }
+  ).then(status => {
+    if (failedList.length > 0) {
+      console.log("发布失败");
+      console.log("failed transfers", failedList.join(", "));
+    } else {
+      console.log(status ? "发布成功" : "发布失败");
+    }
+    ssh.dispose();
+  });
+});

+ 7 - 1
src/App.vue

@@ -1,11 +1,17 @@
 <template>
     <div id='app'>
         <router-view/>
+        <global-uploader></global-uploader>
     </div>
 </template>
 
 <script>
+import globalUploader from '@/components/globaluploader'
+
 export default {
-    name: 'App'
+    name: 'App',
+    components: {
+        globalUploader
+    },
 }
 </script>

+ 109 - 0
src/api/data_admin/buildTaskApi.js

@@ -0,0 +1,109 @@
+import http from '../scan/httpUtil'
+const baseUrl = '/api';
+
+/**
+ * info: 查询统计数量(查询总数量不传参数,查询已完成数量TaskState=0,查询未找到TaskState=-1,查询未验证TaskState=1)
+ * @param {Filters:string} param 查询参数
+ * @param {*} success  成功的回调函数
+ * 
+ */
+export function queryTaskCount(param, success) {
+    let url = `${baseUrl}/datacenter/scan-task-base/count`;
+    http.postJson(url, param, success)
+}
+
+/*************************模型任务接口****************************/
+//创建模型任务
+export function createModelTask(param, success) {
+    let url = `${baseUrl}/datacenter/model-scan-task/create`;
+    http.postJson(url, param, success)
+}
+//根据id删除模型任务
+export function deleteModelTask(param, success) {
+    let url = `${baseUrl}/datacenter/model-scan-task/delete`;
+    http.postJson(url, param, success)
+}
+//查询:根据模型空间ID查询设备信息
+export function queryModelDiglog(param, success) {
+    let url = `${baseUrl}/datacenter/model-scan-task/equip-query`;
+    http.postJson(url, param, success)
+}
+//查询模型任务
+export function queryModelTask(param, success) {
+    let url = `${baseUrl}/datacenter/model-scan-task/page-query`;
+    http.postJson(url, param, success)
+}
+//更新模型任务
+export function updateModelTask(param, success) {
+    let url = `${baseUrl}/datacenter/model-scan-task/update`;
+    http.postJson(url, param, success)
+}
+//查询设备分类
+export function queryModelCategory(param, success) {
+    let url = `${baseUrl}/datacenter/model-scan-task/model-category-query`;
+    http.postJson(url, param, success)
+}
+//查询模型文件夹和文件
+export function queryModelFile(param, success) {
+    let url = `${baseUrl}/datacenter/model-scan-task/model-file-query`;
+    http.postJson(url, param, success)
+}
+
+/*************************设备台账任务接口****************************/
+//创建设备台账任务
+export function createDeviceTask(param, success) {
+    let url = `${baseUrl}/datacenter/equip-scan-task/create`;
+    http.postJson(url, param, success)
+}
+//根据id删除设备台账任务
+export function deleteDeviceTask(param, success) {
+    let url = `${baseUrl}/datacenter/equip-scan-task/delete`;
+    http.postJson(url, param, success)
+}
+//查询设备台账任务
+export function queryDeviceTask(param, success) {
+    let url = `${baseUrl}/datacenter/equip-scan-task/page-query`;
+    http.postJson(url, param, success)
+}
+//更新设备台账任务
+export function updateDeviceTask(param, success) {
+    let url = `${baseUrl}/datacenter/equip-scan-task/update`;
+    http.postJson(url, param, success)
+}
+//查询设备分类
+export function queryDeviceCategory(param, success) {
+    let url = `${baseUrl}/datacenter/equip-scan-task/equip-category-query`;
+    http.postJson(url, param, success)
+}
+
+/*************************资产台账任务接口****************************/
+//统计数量
+export function countAssetsTask(param, success) {
+    let url = `${baseUrl}/datacenter/property-scan-task/count`;
+    http.postJson(url, param, success)
+}
+//创建设备台账任务
+export function createAssetsTask(param, success) {
+    let url = `${baseUrl}/datacenter/property-scan-task/create`;
+    http.postJson(url, param, success)
+}
+//根据id删除设备台账任务
+export function deleteAssetsTask(param, success) {
+    let url = `${baseUrl}/datacenter/property-scan-task/delete`;
+    http.postJson(url, param, success)
+}
+//查询设备台账任务
+export function queryAssetsTask(param, success) {
+    let url = `${baseUrl}/datacenter/property-scan-task/page-query`;
+    http.postJson(url, param, success)
+}
+//更新设备台账任务
+export function updateAssetsTask(param, success) {
+    let url = `${baseUrl}/datacenter/property-scan-task/update`;
+    http.postJson(url, param, success)
+}
+//查询设备族
+export function queryAssetsFamily(param, success) {
+    let url = `${baseUrl}/datacenter/property-scan-task/property-category-query`;
+    http.postJson(url, param, success)
+}

+ 168 - 139
src/api/model/file.js

@@ -102,87 +102,87 @@ let api = {
         return httputils.postJson(`${baseUrl}/model-floor/query`, params, success)
     },
     // 创建楼层
-    createFloor(params) {
-        // 判断该楼层是否存在
+    // createFloor(params) {
+    //     // 判断该楼层是否存在
 
-        let data = {
-            Content: [{
-                FolderId: params.FolderId,
-                FloorName: params.FloorName,
-                ProjectId: params.ProjectId,      //项目id
-            }]
-        };
-        return new Promise((resolve, preject) => {
-            this.queryFloorItem(params, (res) => {
-                if (res.Total == 0) {
-                    // 创建楼层
-                    httputils.postJson(`${baseUrl}/model-floor/create`, data, (res) => {
-                        let modelFile = {
-                            Content: [{
-                                // ProjectId: params.ProjectId,      //项目id
-                                FloorModelId: res.EntityList[0].Id, //模型所属楼层(FloorModel外键)
-                                ModelName: params.Form.file.name,        //模型文件名
-                                UserName: params.userName,
-                                UserId: params.userId,
-                                Note: params.Form.desc
-                                // ReplaceReason: 0
-                            }]
-                        }
-                        //创建模型文件
-                        this.createModelFile(modelFile, (createModelRes) => {
-                            // 与此楼文件进行绑定
-                            let upDateModelData = {
-                                Content: [{
-                                    Id: res.EntityList[0].Id, //id
-                                    CurrentModelId: createModelRes.EntityList[0].Id //该楼层当前的模型id
-                                }]
-                            }
-                            this.updateFloorName(upDateModelData, (upDateModelSucess) => {
-                                if (upDateModelSucess.Result == "success") {
-                                    resolve({
-                                        Result: 'success',
-                                        FloorModelId: res.EntityList[0].Id,   //楼层模型文件
-                                        CurrentModelId: createModelRes.EntityList[0].Id //模型文件id
-                                    })
-                                }
-                            })
-                        })
-                    })
-                } else {
-                    let modelFile = {
-                        Content: [{
-                            // ProjectId: params.ProjectId,      //项目id
-                            FloorModelId: res.Content[0].Id, //模型所属楼层(FloorModel外键)
-                            ModelName: params.Form.file.name,        //模型文件名
-                            UserName: params.userName,
-                            UserId: params.userId,
-                            Note: params.Form.desc
-                            // ReplaceReason: 0
-                        }]
-                    }
-                    //创建模型文件
-                    this.createModelFile(modelFile, (createModelRes) => {
-                        // 与此楼文件进行绑定
-                        let upDateModelData = {
-                            Content: [{
-                                Id: res.Content[0].Id, //id
-                                CurrentModelId: createModelRes.EntityList[0].Id //该楼层当前的模型id
-                            }]
-                        }
-                        this.updateFloorName(upDateModelData, (upDateModelSucess) => {
-                            if (upDateModelSucess.Result == "success") {
-                                resolve({
-                                    Result: 'success',
-                                    FloorModelId: res.Content[0].Id,   //楼层模型文件
-                                    CurrentModelId: createModelRes.EntityList[0].Id //模型文件id
-                                })
-                            }
-                        })
-                    })
-                }
-            })
-        })
-    },
+    //     let data = {
+    //         Content: [{
+    //             FolderId: params.FolderId,
+    //             FloorName: params.FloorName,
+    //             ProjectId: params.ProjectId,      //项目id
+    //         }]
+    //     };
+    //     return new Promise((resolve, preject) => {
+    //         this.queryFloorItem(params, (res) => {
+    //             if (res.Total == 0) {
+    //                 // 创建楼层
+    //                 httputils.postJson(`${baseUrl}/model-floor/create`, data, (res) => {
+    //                     let modelFile = {
+    //                         Content: [{
+    //                             // ProjectId: params.ProjectId,      //项目id
+    //                             FloorModelId: res.EntityList[0].Id, //模型所属楼层(FloorModel外键)
+    //                             ModelName: params.Form.file.name,        //模型文件名
+    //                             UserName: params.userName,
+    //                             UserId: params.userId,
+    //                             Note: params.Form.desc
+    //                             // ReplaceReason: 0
+    //                         }]
+    //                     }
+    //                     //创建模型文件
+    //                     this.createModelFile(modelFile, (createModelRes) => {
+    //                         // 与此楼文件进行绑定
+    //                         let upDateModelData = {
+    //                             Content: [{
+    //                                 Id: res.EntityList[0].Id, //id
+    //                                 CurrentModelId: createModelRes.EntityList[0].Id //该楼层当前的模型id
+    //                             }]
+    //                         }
+    //                         this.updateFloorName(upDateModelData, (upDateModelSucess) => {
+    //                             if (upDateModelSucess.Result == "success") {
+    //                                 resolve({
+    //                                     Result: 'success',
+    //                                     FloorModelId: res.EntityList[0].Id,   //楼层模型文件
+    //                                     CurrentModelId: createModelRes.EntityList[0].Id //模型文件id
+    //                                 })
+    //                             }
+    //                         })
+    //                     })
+    //                 })
+    //             } else {
+    //                 let modelFile = {
+    //                     Content: [{
+    //                         // ProjectId: params.ProjectId,      //项目id
+    //                         FloorModelId: res.Content[0].Id, //模型所属楼层(FloorModel外键)
+    //                         ModelName: params.Form.file.name,        //模型文件名
+    //                         UserName: params.userName,
+    //                         UserId: params.userId,
+    //                         Note: params.Form.desc
+    //                         // ReplaceReason: 0
+    //                     }]
+    //                 }
+    //                 //创建模型文件
+    //                 this.createModelFile(modelFile, (createModelRes) => {
+    //                     // 与此楼文件进行绑定
+    //                     let upDateModelData = {
+    //                         Content: [{
+    //                             Id: res.Content[0].Id, //id
+    //                             CurrentModelId: createModelRes.EntityList[0].Id //该楼层当前的模型id
+    //                         }]
+    //                     }
+    //                     this.updateFloorName(upDateModelData, (upDateModelSucess) => {
+    //                         if (upDateModelSucess.Result == "success") {
+    //                             resolve({
+    //                                 Result: 'success',
+    //                                 FloorModelId: res.Content[0].Id,   //楼层模型文件
+    //                                 CurrentModelId: createModelRes.EntityList[0].Id //模型文件id
+    //                             })
+    //                         }
+    //                     })
+    //                 })
+    //             }
+    //         })
+    //     })
+    // },
     // 删除楼层文件
     deleteFloor(data) {
         return httputils.postJson(`${baseUrl}/model-floor/delete`, data)
@@ -210,7 +210,8 @@ let api = {
      */
     deleteModelFileList(params, success) {
         let data = {
-            Id:params
+            Id:params.Id,
+            Force: params.Force?params.Force:false
         } 
         return httputils.postJson(`${baseUrl}/model-file/delete-file`, data, success)
     },
@@ -223,67 +224,77 @@ let api = {
         return httputils.postJson(`${baseUrl}/model-file/query`, params, success)
     },
     // 上传模型文件
-    uploadModelFile(payload, ProjectId,callback1, callback2) {
-        axios({
-            url: baseUrl + '/model-file/upload',
-            method: 'post',
-            headers: {
-                ProjectId: ProjectId
-            },
-            onUploadProgress: function (progressEvent) { //原生获取上传进度的事件
-                if (progressEvent.lengthComputable) {
-                    //属性lengthComputable主要表明总共需要完成的工作量和已经完成的工作是否可以被测量
-                    //如果lengthComputable为false,就获取不到progressEvent.total和progressEvent.loaded
-                    callback1(progressEvent);
-                }
-            },
-            data: payload
-        }).then(res => {
-            callback2(res);
-        }).catch(error => {
-            console.log('this is a catch')
-            console.log(error)
-        })
+    // uploadModelFile(payload, ProjectId,callback1, callback2) {
+    //     axios({
+    //         url: baseUrl + '/model-file/upload',
+    //         method: 'post',
+    //         headers: {
+    //             ProjectId: ProjectId
+    //         },
+    //         onUploadProgress: function (progressEvent) { //原生获取上传进度的事件
+    //             if (progressEvent.lengthComputable) {
+    //                 //属性lengthComputable主要表明总共需要完成的工作量和已经完成的工作是否可以被测量
+    //                 //如果lengthComputable为false,就获取不到progressEvent.total和progressEvent.loaded
+    //                 callback1(progressEvent);
+    //             }
+    //         },
+    //         data: payload
+    //     }).then(res => {
+    //         callback2(res);
+    //     }).catch(error => {
+    //         console.log('this is a catch')
+    //         console.log(error)
+    //     })
+    // },
+
+    //准备分片上传模型文件接口
+    modelFileUpload(data, success) {
+        return httputils.postJson(`${baseUrl}/model-file/upload`, data, success)
     },
-    // 更新模型文件
-    upDateModelFile(data, ProjectId, UserName, UserId, callback1, callback2) {
-        let modelFile = {
-            Content: [{
-                FloorModelId:data.replaceModelItem.Id, //模型id
-                ModelName: data.Form.file.name,        //模型名字
-                UserName: UserName,
-                UserId: UserId,
-                Note: data.replaceModelItem.Note,
-                ReplaceReason: data.Form.ReplaceReason
-            }]
-        }
-        // //创建模型文件
-        this.createModelFile(modelFile, (createModelRes) => {
-            // 与此楼文件进行绑定
-            let upDateModelData = {
-                Content: [{
-                    Id:data.replaceModelItem.Id, //楼层
-                    CurrentModelId: createModelRes.EntityList[0].Id
-                }]
-            }
-            this.updateFloorName(upDateModelData, (upDateModelSucess) => {
-                if (upDateModelSucess.Result == "success") {
-                    // 处理数据
-                    let formData = new FormData();
-                    formData.append(
-                      "model",
-                      JSON.stringify({
-                        FloorModelId: data.replaceModelItem.Id,
-                        Id:createModelRes.EntityList[0].Id
-                      })
-                    );
-                    formData.append("file", data.Form.file.raw);
-                    this.uploadModelFile(formData,ProjectId,callback1,callback2)
-                }
-            })
-        })
+
+    mergeModelFile(data, success) {
+        return httputils.postJson(`${baseUrl}/model-file/merge`, data, success)
     }
 
+    // 更新模型文件
+    // upDateModelFile(data, ProjectId, UserName, UserId, callback1, callback2) {
+    //     let modelFile = {
+    //         Content: [{
+    //             FloorModelId:data.replaceModelItem.Id, //模型id
+    //             ModelName: data.Form.file.name,        //模型名字
+    //             UserName: UserName,
+    //             UserId: UserId,
+    //             Note: data.replaceModelItem.Note,
+    //             ReplaceReason: data.Form.ReplaceReason
+    //         }]
+    //     }
+    //     // //创建模型文件
+    //     this.createModelFile(modelFile, (createModelRes) => {
+    //         // 与此楼文件进行绑定
+    //         let upDateModelData = {
+    //             Content: [{
+    //                 Id:data.replaceModelItem.Id, //楼层
+    //                 CurrentModelId: createModelRes.EntityList[0].Id
+    //             }]
+    //         }
+    //         this.updateFloorName(upDateModelData, (upDateModelSucess) => {
+    //             if (upDateModelSucess.Result == "success") {
+    //                 // 处理数据
+    //                 let formData = new FormData();
+    //                 formData.append(
+    //                   "model",
+    //                   JSON.stringify({
+    //                     FloorModelId: data.replaceModelItem.Id,
+    //                     Id:createModelRes.EntityList[0].Id
+    //                   })
+    //                 );
+    //                 formData.append("file", data.Form.file.raw);
+    //                 this.uploadModelFile(formData,ProjectId,callback1,callback2)
+    //             }
+    //         })
+    //     })
+    // }
+
 }
 export default api
 
@@ -291,4 +302,22 @@ export default api
 export function bindFloorModel(param, success) {
     let url = `${baseUrl}/model-floor/bind`;
     httputils.postJson(url, param, success)
+}
+
+//根据模型id 获取模型文件夹及文件名
+export function getFileNameById(param, success) {
+    let url = `${baseUrl}/model-folder/get-name`;
+    httputils.postJson(url, param, success)
+}
+
+// 根据条件查询统计数量
+export function countSyncLogCount(param, success) {
+    let url = `${baseUrl}/sync-log/count`;
+    httputils.postJson(url, param, success)
+}
+
+// 查询同步日志
+export function querySyncLogCount(param, success) {
+    let url = `${baseUrl}/sync-log/query`;
+    httputils.postJson(url, param, success)
 }

+ 29 - 0
src/api/model/report.js

@@ -0,0 +1,29 @@
+import httputils from '@/api/scan/httpUtil'
+import { Message } from 'element-ui';
+import axios from 'axios'
+const baseUrl = '/modelapi';
+
+// 导出模型问题报告
+// export function exportReport(params, success) {
+//     httputils.postJson(`${baseUrl}/report/non-blocking`, params, success)
+// }
+
+// 查询楼层列表
+export function queryFloorList(params, success) {
+    return httputils.postJson(`${baseUrl}/model-floor/query-list`, params, success)
+}
+
+// 获取项目下所有模型文件夹
+export function queryModel(params, success) {
+    return httputils.postJson(`${baseUrl}/model-folder/query`, params, success)
+}
+
+// 查询文件夹下的所有楼层
+export function queryReportList(params, success) {
+    return httputils.postJson(`${baseUrl}/report/list/non-blocking`, params, success)
+}
+
+// 查询文件夹下的所有楼层(包含缺失楼层)
+export function queryLostReportList(params, success) {
+    return httputils.postJson(`${baseUrl}/model-floor/query-list-missing`, params, success)
+}

+ 56 - 0
src/api/msgsever.js

@@ -0,0 +1,56 @@
+import http from './scan/httpUtil'
+const baseUrl = '/api';
+
+/*************************消息中心接口****************************/
+
+/**
+ * title: 统计数量
+ * info: 查询总数量不传参数,查询 已读Read = true,未读 Read = false
+ */
+export function messgeCount(param, success) {
+    let url = `${baseUrl}/message-center/message/count`;
+    http.postJson(url, param, success)
+}
+
+/**
+ * title: 创建消息
+ * info: 消息类型:提示(Info)、警告(Warning)、错误(Error)、成功(Success)
+ */
+export function messgeCreate(param, success) {
+    let url = `${baseUrl}/message-center/message/create`;
+    http.postJson(url, param, success)
+}
+
+/**
+ * title: 删除消息
+ */
+export function messgeDelete(param, success) {
+    let url = `${baseUrl}/message-center/message/delete`;
+    http.postJson(url, param, success)
+}
+
+/**
+ * title: 查询消息列表
+ */
+export function messgeQuery(param, success) {
+    let url = `${baseUrl}/message-center/message/page-query`;
+    http.postJson(url, param, success)
+}
+
+/**
+ * title: 更新消息状态
+ * info: 是否读过:未读(f)、已读(t)
+ */
+export function messgeUpdate(param, success) {
+    let url = `${baseUrl}/message-center/message/update`;
+    http.postJson(url, param, success)
+}
+
+/**
+ * title: 根据接收人将消息置为已读
+ * info: 已读Read = true,*UserId
+ */
+export function messgeUpdateState(param, success) {
+    let url = `${baseUrl}/message-center/message/update-state`;
+    http.postJson(url, param, success)
+}

+ 135 - 0
src/api/relation/api.js

@@ -0,0 +1,135 @@
+import httpUtil from "../scan/httpUtil";
+import fetch from "../scan/fetch";
+import storage from '@/framework/utils/storage'
+
+
+//查询总览
+export function graphic(param, success) {
+  let url = '/api/datacenter/graphic/overview'
+  httpUtil.postJson(url, param, success)
+}
+
+// 查询总览数量
+export function graphicNumber(param, success) {
+  let url = '/api/datacenter/graphic/query-count'
+  httpUtil.postJson(url, param, success)
+
+}
+
+//导入excel
+export function graphicUpload(param, success) {
+  let url = '/api/datacenter/graphic/import'
+  httpUtil.postJson(url, param, success)
+}
+
+// 下载报告
+export function reportDownload(param, success) {
+  let url = '/api/datacenter/graphic/report-downloads'
+  httpUtil.getJson(url, param, success)
+}
+
+// 下载模板
+export function templateDownloads(param, success) {
+  let url = '/api/datacenter/graphic/template-downloads'
+  httpUtil.getJson(url, param, success)
+}
+
+
+//    建筑下的业务空间
+export function buildSpace(param, success) {
+  let url = '/api/datacenter/calc_building/space'
+  httpUtil.postJson(url, param, success)
+}
+
+
+// 管网系统设备分块 1
+export function calcSpecial(param, success) {
+  let url = ` /api/datacenter/calc_special/sys-block?Domain=${param.Domain}&SystemName=${param.SystemName}`
+  httpUtil.postJson(url, param, success)
+}
+
+
+//    获取源末端 2
+export function blockQuery(param, success) {
+  let url = '/api/datacenter/graphic/connected-block-query'
+  httpUtil.postJson(url, param, success)
+}
+
+
+// 覆盖源末端 3
+export function blockSource(param, success) {
+  let url = '/api/datacenter/graphic/replace-connected-block-source'
+  httpUtil.postJson(url, param, success)
+}
+
+//    管网系统确定流向 4
+export function sysDirection(param, success) {
+  let buildId = param.BuildingId ? `BuildingId=${param.BuildingId}&` : ''
+  let url = `/api/datacenter/calc_special/sys-direction?BlockId=${param.BlockId}&${buildId}Domain=${param.Domain}&SystemName=${param.SystemName}&isSource=${param.isSource}`
+  httpUtil.postJson(url, param, success)
+}
+
+//************************无需配置源末端关系计算15种********************************//
+// 建筑下的业务空间
+export function businessSpaceAll(param) {
+  let {relation_type, zone_type, proId} = param
+  let userName = storage.get("user_name")
+  let ProjectId = localStorage.getItem("projectId")
+  return fetch({
+    method: 'POST',
+    url: `/api/datacenter/relation-calc/${relation_type}${zone_type ? +'/' + zone_type : ''}`,
+    data: proId,
+    headers: {'ProjectId': ProjectId, 'Comming': 'adm', 'Account': userName}
+  })
+}
+
+//************************数据转换********************************//
+
+// 项目化字典-统计数量
+export function dictCount(param, success) {
+  let url = '/api/equip-component/dict-custom/project-dict-count'
+  httpUtil.postJson(url, param, success)
+}
+
+// 项目化字典-需补充转换规则数量
+export function dictSwitchCount(param, success) {
+  let url = '/api/equip-component/dict-custom/project-dict-switch-count'
+  httpUtil.postJson(url, param, success)
+}
+
+//项目化字典 - 内容
+export function dectInfo(param) {
+  let data = param
+  let userName = storage.get("user_name")
+  let ProjectId = localStorage.getItem("projectId")
+  return fetch({
+    method: 'POST',
+    url: `/api/equip-component/dict-custom/project-dict-info`,
+    data,
+    headers: {'ProjectId': ProjectId, 'Comming': 'adm', 'Account': userName}
+  })
+}
+
+//数据中心-物理世界数据转换
+export function dictDataCenter(param, success) {
+  let url = '/api/equip-component/dict-custom/project-dict-datacenter'
+  httpUtil.postJson(url, param, success)
+}
+
+//物理世界-数据中心数据转换
+export function dictDataPlatFrom(param, success) {
+  let url = '/api/equip-component/dict-custom/project-dict-dataplatfrom'
+  httpUtil.postJson(url, param, success)
+}
+
+// 同步设备
+export function createEquip(param, success) {
+  let url = `/api/dataplatform-sync/project-sync/create-equip?projectId=${param.projectId}`
+  httpUtil.postJson(url, {}, success)
+}
+
+//更新自定义自定脚本
+export function dictUpdate(param, success) {
+  let url = '/api/equip-component/dict-custom/update'
+  httpUtil.postJson(url, param, success)
+}

+ 21 - 21
src/api/scan/fetch.js

@@ -4,38 +4,38 @@ import vueAxios from 'vue-axios'
 import { Message } from 'element-ui';
 
 Vue.use(vueAxios, axios)
-    //创建实例
+//创建实例
 
 const service = axios.create({
-    timeout: 3000000, //请求时间超出
-    withCredentials: true, //是否跨站点访问控制请求
+  timeout: 3000000, //请求时间超出
+  withCredentials: true, //是否跨站点访问控制请求
 })
 
 //request拦截
 service.interceptors.request.use(config => {
-    return config
+  return config
 }, error => {
-    console.log(error)
-    Promise.reject(error)
+  console.log(error)
+  Promise.reject(error)
 })
 
 //response拦截器
 service.interceptors.response.use(
-    response => {
-        // let resp = response.data;
-        // let result = resp.result || resp.Result
-        return response
-        // if (result == 'success' || result == 'Success') {
-        //     return response
-        // } else {
-        //     let msg = resp.message ? resp.message : resp.ResultMsg? resp.ResultMsg: resp.Message;
-        //     Message.error({ message: msg });
-        // }        
-    },
-    error => {
-        console.log('err' + error)
-        return Promise.reject(error)
-    }
+  response => {
+    // let resp = response.data;
+    // let result = resp.result || resp.Result
+    return response
+    // if (result == 'success' || result == 'Success') {
+    //     return response
+    // } else {
+    //     let msg = resp.message ? resp.message : resp.ResultMsg? resp.ResultMsg: resp.Message;
+    //     Message.error({ message: msg });
+    // }
+  },
+  error => {
+    console.log('err' + error)
+    return Promise.reject(error)
+  }
 )
 
 export default service

+ 42 - 42
src/api/scan/httpUtil.js

@@ -1,54 +1,54 @@
-import { Message } from 'element-ui';
+import {Message} from 'element-ui';
 import fetch from './fetch'
 import storage from '@/framework/utils/storage'
 
 function successResponse(vm, response, success, failed) {
-    let resp = response.data;
-    let result = resp.result ? resp.result : resp.Result;
-    if (result === 'success') {
-        if (success) {
-            success(resp);
-        }
-    } else {
-        let msg = resp.message ? resp.message : resp.ResultMsg || resp.resultMsg || resp.Message;
-        Message.error({ message: msg });
-        if (failed) {
-            failed(resp);
-        }
+  let resp = response.data;
+  let result = resp.result ? resp.result : resp.Result;
+  if (result === 'success') {
+    if (success) {
+      success(resp);
     }
+  } else {
+    let msg = resp.message ? resp.message : resp.ResultMsg || resp.resultMsg || resp.Message;
+    Message.error({ message: msg });
+    if (failed) {
+      failed(resp);
+    }
+  }
 
 }
 
 function errorResponse(vm, response, err) {
-    let json = JSON.parse(JSON.stringify(response))
-    console.error(response)
-    if (json.response) {
-        Message.error({ message: `接口:${json.response.config.url}请求错误,错误状态为:${json.response.status}` })
-    } else {
-        console.error(vm, response, err)
-        Message.error({ message: '请求错误' });
-    }
+  let json = JSON.parse(JSON.stringify(response))
+  console.error(response)
+  if (json.response) {
+    Message.error({ message: `接口:${json.response.config.url}请求错误,错误状态为:${json.response.status}` })
+  } else {
+    console.error(vm, response, err)
+    Message.error({ message: '请求错误' });
+  }
 }
 
 export default {
-    getJson: function(url, data, success, failed, err) {
-        let ProjectId = storage.get("global_project_selected")
-        let userName = storage.get("user_name")
-        let vm = this;
-        fetch({ url: url, method: 'get', params: data, headers: {'ProjectId': ProjectId, 'Comming': 'adm' ,'Account': userName}}).then((response) => {
-            successResponse(vm, response, success, failed)
-        }).catch(error => {
-            errorResponse(vm, error, err);
-        });
-    },
-    postJson: function(url, data, success, failed, err) {
-        let ProjectId = storage.get("global_project_selected")
-        let userName = storage.get("user_name")
-        let vm = this;
-        fetch({ url: url, method: 'post', data: data, headers: {'ProjectId': ProjectId, 'Comming': 'adm' ,'Account': userName} }).then((response) => {
-            successResponse(vm, response, success, failed)
-        }).catch(error => {
-            errorResponse(vm, error, err);
-        });
-    }
-}
+  getJson: function(url, data, success, failed, err) {
+    let ProjectId = localStorage.getItem("projectId")
+    let userName = storage.get("user_name")
+    let vm = this;
+    fetch({ url: url, method: 'get', params: data, headers: {'ProjectId': ProjectId, 'Comming': 'adm' ,'Account': userName}}).then((response) => {
+      successResponse(vm, response, success, failed)
+    }).catch(error => {
+      errorResponse(vm, error, err);
+    });
+  },
+  postJson: function(url, data, success, failed, err) {
+    let ProjectId = localStorage.getItem("projectId")
+    let userName = storage.get("user_name")
+    let vm = this;
+    fetch({ url: url, method: 'post', data: data, headers: {'ProjectId': ProjectId, 'Comming': 'adm' ,'Account': userName} }).then((response) => {
+      successResponse(vm, response, success, failed)
+    }).catch(error => {
+      errorResponse(vm, error, err);
+    });
+  }
+}

File diff suppressed because it is too large
+ 1004 - 684
src/api/scan/request.js


+ 30 - 0
src/api/uploader/index.js

@@ -0,0 +1,30 @@
+import http from '../scan/httpUtil'
+
+const baseUrl = '/image-service'
+
+//分片上传文件接口
+
+/**
+ * info: 申请分片上传接口(获取上传UploadId)
+ * @param {systemId:string} param 系统的名称
+ * @param {secret:string} param 系统的密码
+ * @param {key:string} param  成功的回上传的文件名(可以包含文件路径)
+ * @param {overwrite:boolean} param 表示是否覆盖已有的文件(如果存在) 注:overwrite有一定风险, 只在注册分片时校验, 合并时候如果key被占用, 会覆盖掉之前文件
+ * 
+ */
+export function getUploadId(param, success) {
+  let url = ` ${baseUrl}/common/register_multipart_upload?systemId=${param.systemId}&secret=${param.secret}&key=${param.key}&overwrite=${param.overwrite}`
+  http.postJson(url, {}, success)
+}
+
+/**
+ * info: 合并分片的接口
+ * @param {systemId:string} param 系统的名称
+ * @param {secret:string} param 系统的密码
+ * @param {uploadId:string} param  需要合并的上传文件的uploadId
+ * 
+ */
+export function mergeMultipart(param, success) {
+  let url = ` ${baseUrl}/common/merge_multipart?systemId=${param.systemId}&secret=${param.secret}&uploadId=${param.uploadId}`
+  http.postJson(url, {}, success)
+}

BIN
src/assets/image/floorBG.png


File diff suppressed because it is too large
+ 78 - 6
src/assets/style/iconfont/iconfont.css


BIN
src/assets/style/iconfont/iconfont.eot


File diff suppressed because it is too large
+ 55 - 1
src/assets/style/iconfont/iconfont.svg


BIN
src/assets/style/iconfont/iconfont.ttf


BIN
src/assets/style/iconfont/iconfont.woff


+ 19 - 9
src/components/business_space/business/handsontable.vue

@@ -36,6 +36,7 @@
 import "@/assets/js/chosen.jquery.min";
 import tools from "@/utils/scan/tools";
 import "@/assets/js/handsontable-chosen-editor";
+import lStorage from '@/utils/localStorage'
 import myPagination from "@/components/common/myPagination";
 import addBusiness from "@/components/business_space/dialogs/addDialog/businessDialog"
 import showTools from "@/utils/handsontable/notShow"
@@ -62,7 +63,7 @@ export default {
     showTypes() {
       return this.onlyRead ?
         [{ value: "Visible", label: '只看采集信息' }, { value: "all", label: '全部' }] :
-        [{ value: "partInfo", label: '隐藏信息点' }, { value: "all", label: '全部' }]
+        [{ value: "partInfo", label: '隐藏信息点' }, { value: "all", label: '全部' }, { value: "Visible", label: '只看采集信息' }]
     }
   },
   data() {
@@ -118,6 +119,7 @@ export default {
     getHeader(headers, buildFloorSelectd) {
       this.headers = headers
       this.buildFloorSelectd = buildFloorSelectd
+      this.page.pageNumber = 1
       this.getData()
     },
     getData() {
@@ -212,7 +214,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该业务空间"
@@ -258,6 +260,7 @@ export default {
     },
     getInfors(infos, row) {
       let val = this.hot.colToProp(row.col);
+      lStorage.set('screen_data', {path: this.$route.path, data: {RoomID: infos.RoomID, zone: this.zoneCode}})
       if (val == "point") {
         let query = {
           RoomID: infos.RoomID,
@@ -350,13 +353,19 @@ export default {
         this.$message("新添加业务空间内容不能为空!")
         return
       }
-      if (this.buildFloorSelectd && this.buildFloorSelectd[0] && this.buildFloorSelectd[1]) {
-        param.BuildingId = this.buildFloorSelectd[0]
-        param.FloorId = this.buildFloorSelectd[1]
+      if (param.flowBuild) {
+        param.BuildingId = param.flowBuild.split('-')[0]
+        param.FloorId = param.flowBuild.split('-')[1] || null
+      } else {
+        if (this.buildFloorSelectd) {
+          if (this.buildFloorSelectd[0] != 'all' && this.buildFloorSelectd[0] != 'noKnow') {
+            param.BuildingId = this.buildFloorSelectd[0]
+          }
+          if (this.buildFloorSelectd[1] && this.buildFloorSelectd[1] != 'all' && this.buildFloorSelectd[1] != 'noKnow') {
+            param.FloorId = this.buildFloorSelectd[1]
+          }
+        }
       }
-      //  else if (this.buildMess.selectd && this.buildMess.selectd[0] && !this.buildMess.selectd[1]) {
-      //   param.BuildingId = this.buildMess.selectd[0]
-      // }
       let params = {
         zone: this.zoneCode,
         data: {
@@ -617,6 +626,7 @@ export default {
     //切换每页显示多少条数据
     handleSizeChange(val) {
       this.page.pageSize = val
+      this.page.pageNumber = 1
       this.getData()
     },
     //切换页数
@@ -659,4 +669,4 @@ export default {
     color: gray;
   }
 }
-</style>
+</style>

+ 1 - 1
src/components/business_space/dialogs/addDialog/businessDialog.vue

@@ -478,7 +478,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该业务空间"

+ 5 - 3
src/components/business_space/dialogs/list/firm.vue

@@ -29,6 +29,7 @@
             <el-table-column header-align='center' prop="name" label="型号"></el-table-column>
             <el-table-column header-align='center' label="技术参数">
               <template slot-scope="scope">
+                <el-button type="text"  @click="lookParam(scope.row)">技术参数</el-button>
                 <el-button :disabled="scope.row.specificationId?false:true" type="text" @click="lookParam(scope.row)">技术参数</el-button>
               </template>
             </el-table-column>
@@ -40,8 +41,8 @@
                 <i style="color:#46B0FF;cursor: pointer;">厂家库</i>维护吧
             </p>
             <my-pagination :page="page" @change="changed" style="margin-top:10px;"></my-pagination>
-        </div>       
-        
+        </div>
+
       </div>
     </div>
     <param-details :isLoad="isLoad" :data="data"></param-details>
@@ -54,11 +55,12 @@
   </el-dialog>
 </template>
 <script>
+
 import myPagination from "@/components/common/myPagination";
 import paramDetails from "@/components/business_space/dialogs/list/paramDetails"
 import { getSpecList, getBrandList, getManufacturerList } from "@/api/scan/request"
 
-export default {
+    export default {
   components: {
     myPagination,
     paramDetails

+ 2 - 1
src/components/business_space/newAddDialogs/addEquipDialog.vue

@@ -139,6 +139,7 @@ export default {
           Filters: '',
           PageNumber: this.page.pageNumber,
           PageSize: this.page.pageSize,
+          Orders: 'EquipID asc'
         },
         type: this.zone,
         spaceId: this.spaceId
@@ -157,7 +158,7 @@ export default {
         pa.data.Filters += `;EquipName contain "${this.keycode}" or EquipLocalName contain "${this.keycode}" or EquipLocalID contain "${this.keycode}"`
       }
       // 删除首尾分号
-      pa.data.Filters = pa.data.Filters.replace(/(^;)|(;$)/g,'');
+      pa.data.Filters = pa.data.Filters.replace(/(^;)|(;$)/g, '');
       if (pa.data.Filters == '') {
         delete pa.data.Filters
       }

+ 1 - 0
src/components/business_space/newAddDialogs/addSystemDialog.vue

@@ -87,6 +87,7 @@ export default {
       let pa = {
         data: {
           PageSize: 200,
+          Orders: 'SysID asc'
         },
         type: this.zone,
         spaceId: this.spaceId

+ 136 - 0
src/components/business_space/newAddDialogs/roomInFloorDialog.vue

@@ -0,0 +1,136 @@
+<template>
+  <el-dialog :title="title" :visible.sync="dialogVisible" width="800px" id="addSyDialog">
+    <div class="table-box">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle" ref="multipleTable" border>
+        <el-table-column label="业务空间名称" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.RoomLocalName||scope.row.RoomName||''}}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="所属建筑" show-overflow-tooltip min-width="100" class-name="mutiCol">
+          <template slot-scope="scope">
+            <div>
+              <div v-for="(t,i) in scope.row.FloorList" :key="i" class="muti">
+                {{t.Building.BuildLocalName||t.Building.BuildName}}
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="SysLocalID" label="所属楼层" show-overflow-tooltip min-width="100" class-name="mutiCol">
+          <template slot-scope="scope">
+            <div>
+              <div v-for="t in scope.row.FloorList" :key="t.FloorID" class="muti">
+                {{t.FloorLocalName||t.FloorName}}
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="action" label="操作" min-width="50" align='center' class-name="mutiCol">
+          <template slot-scope="scope">
+            <div>
+              <div v-for="t in scope.row.FloorList" :key="t.FloorID" class="muti">
+                <el-radio v-model="scope.row.selected" :label="t">{{''}}</el-radio>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button size="small" @click="dialogVisible = false">取 消</el-button>
+      <el-button size="small" type="primary" @click="savaRelation">确 定</el-button>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import {
+  getSpaceBdFlData, // 属于多建筑楼层的空间数据
+  updateRelateInSpAndBuild, //保存业务空间与建筑楼层关系
+} from "@/api/scan/request";
+export default {
+  data() {
+    return {
+      title: '请选择业务空间所属建筑',
+      inSpaceType: '系统',
+      dialogVisible: false,
+      tableData: [],
+      loading: false,
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      }, // 列表样式
+      selections: [], // 选中项
+    }
+  },
+  props: {
+    type: {}, //equipment--equipmentFor
+    spaceId: {},
+    zone: {}, //分区类型 
+  },
+  methods: {
+    // 显示
+    showDialog() {
+      this.dialogVisible = true;
+      this.tableData = [];
+      this.getTableData();
+    },
+    // 确认
+    savaRelation() {
+      let arr = [];
+      this.tableData.forEach(t => {
+        if (t.selected) {
+          arr.push({
+            spaceId: t.RoomID,
+            id: t.selected.FloorID,
+            type: t.ObjectType
+          })
+        }
+      })
+      if (arr.length) {
+        updateRelateInSpAndBuild(arr, res => {
+          this.$emit('relaSuc');
+          this.$message.success('关联成功');
+          this.dialogVisible = false;
+        })
+      } else {
+        this.$message.warning('请选择关联建筑楼层');
+      }
+    },
+    // 获取表格数据
+    getTableData() {
+      let pa = {
+        Cascade: [
+          { Name: "floorlList", Cascade: [{ Name: 'building' }] }
+        ],
+        PageSize: 1000
+      }
+      getSpaceBdFlData(pa, res => {
+        this.tableData = res.Content;
+      })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+#addSyDialog {
+  .table-box {
+    height: 350px;
+    /deep/ .mutiCol {
+      padding: 0;
+      & > div {
+        padding: 0;
+      }
+    }
+    .muti {
+      line-height: 32px;
+      padding: 0 10px;
+      & + .muti {
+        border-top: 1px solid #ebeef5;
+      }
+    }
+  }
+}
+</style>

+ 51 - 18
src/components/business_space/newGraphy/canvasFun.vue

@@ -1,40 +1,51 @@
 <template>
-  <el-row id="canvas-actions-box" :class="{'isEdit':isEdit}">
+  <el-row id="canvas-actions-box" :class="{'isEdit':config.isEdit}">
     <!-- <div :class="{'active':active=='move'}">
       <i class="iconfont icon-move" @click="moveCanvas"></i>
     </div> -->
-    <div>
-      <i class="iconfont icon-maximize" @click="fitToWindow"></i>
+    <div v-if="config.isEdit&&config.groupSelect" :class="{'active':active=='groupSelect'}" @click="groupSelect">
+      <i class="iconfont icon-shuxingxuanze"></i>
     </div>
-    <div>
+    <div @click="fitToWindow">
+      <i class="iconfont icon-maximize"></i>
+    </div>
+    <div v-if="!config.isEdit">
       <el-dropdown size="mini" placement="top-start" @command="handleCommand">
         <i class="el-icon-download" style="font-size:20px;color:#fff;"></i>
         <el-dropdown-menu slot='dropdown'>
           <el-dropdown-item command="savePng">保存为png</el-dropdown-item>
           <el-dropdown-item command="saveSvg">保存为svg</el-dropdown-item>
+          <el-dropdown-item command="saveJson">保存为Json</el-dropdown-item>
         </el-dropdown-menu>
       </el-dropdown>
     </div>
-    <div v-if="isEdit" :class="{'active':active=='divide'}">
-      <i class="iconfont icon-edit1" @click="divide"></i>
+    <div v-if="config.isEdit&&config.divide" :class="{'active':active=='divide'}" @click="divide">
+      <el-dropdown size="mini" placement="top-start" @command="handleDivideCommand" :hide-on-click="false">
+        <i class="iconfont icon-edit1"></i>
+        <el-dropdown-menu slot='dropdown'>
+          <el-dropdown-item command="savePng">
+            吸附 <el-switch v-model="isSwitch"></el-switch>
+          </el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
     </div>
-    <div v-if="isEdit">
-      <i class="iconfont icon-Erase" @click="clearDivide"></i>
+    <div v-if="config.isEdit&&config.divide" @click="clearDivide">
+      <i class="iconfont icon-Erase"></i>
     </div>
-    <div v-if="isEdit">
-      <i class="iconfont icon-Cancel" @click="undo"></i>
+    <div v-if="config.isEdit" @click="undo">
+      <i class="iconfont icon-Cancel"></i>
     </div>
-    <div v-if="isEdit">
-      <i class="iconfont icon-Anti-cancel" @click="redo"></i>
+    <div v-if="config.isEdit" @click="redo">
+      <i class="iconfont icon-Anti-cancel"></i>
     </div>
-    <div>
-      <i class="iconfont icon-narrow" @click="reduce"></i>
+    <div @click="reduce">
+      <i class="iconfont icon-narrow"></i>
     </div>
     <div class="line">
       <el-slider tooltip-class="tooltip-class" :min="min" v-model="sliderVal" :show-tooltip="false" @input="scale" :max="max"></el-slider>
     </div>
-    <div>
-      <i class="iconfont icon-zoom" @click="plus"></i>
+    <div @click="plus">
+      <i class="iconfont icon-zoom"></i>
     </div>
   </el-row>
 </template>
@@ -47,11 +58,17 @@ export default {
       min: 1,
       max: 1000,
       everyScale: 1, // 每份的放大倍数
+      isSwitch: false, // 是否开启吸附
     }
   },
   props: {
-    isEdit: {
-      default: false
+    config: {
+      type: Object,
+      default: {
+        isEdit: false,
+        divide: true,
+        groupSelect: false
+      }
     }
   },
   computed: {
@@ -63,6 +80,11 @@ export default {
     //   this.active = this.active != "move" ? "move" : '';
     //   this.$emit('move', this.active == 'move');
     // },
+    //
+    groupSelect() {
+      this.active = 'groupSelect';
+      this.$emit('groupSelect');
+    },
     // 适配大小
     fitToWindow() {
       this.$emit('fit');
@@ -71,6 +93,10 @@ export default {
     handleCommand(command) {
       this.$emit(command)
     },
+    // 是否开启吸附
+    handleDivideCommand(commond) {
+      this.$emit('changeAbsorb', this.isSwitch);
+    },
     // 切割编辑
     divide() {
       this.active = 'divide';
@@ -125,14 +151,21 @@ export default {
     background-color: #6da60f;
     i {
       cursor: pointer;
+      color: #fff;
     }
   }
+  & > div:active {
+    background-color: #4b7902;
+  }
   & > div.active {
     background-color: #4b7902;
   }
   &.isEdit > div {
     background-color: #02a7f0;
   }
+  &.isEdit > div:active {
+    background-color: #027db4;
+  }
   &.isEdit > div.active {
     background-color: #027db4;
   }

+ 4 - 0
src/components/business_space/newGraphy/createBSP.vue

@@ -26,6 +26,10 @@ export default {
     },
     // 确认
     confirm() {
+      if (this.roomName == '') {
+        this.$message.warning("请填写空间名称");
+        return
+      }
       this.$emit('createRoom', this.roomName);
       this.dialogVisible = false;
     }

+ 408 - 163
src/components/business_space/newGraphy/graphy.vue

@@ -25,18 +25,24 @@
         <div class="button-group">
           <!-- 默认操作模式 -->
           <div v-show="type==1">
-            <el-button @click="editGraphy">编辑平面图</el-button>
+            <el-dropdown split-button type="primary" @click="editGraphy" @command="handleCommand">
+              创建业务空间
+              <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item command="groupCreateBSpace">批量创建业务空间</el-dropdown-item>
+              </el-dropdown-menu>
+            </el-dropdown>
+            <!-- 点击已经关联的业务空间 -->
+            <el-button type="primary" plain @click="refactorBSP" :disabled="zoneDisable" style="margin-left:10px;">重新划分业务空间</el-button>
+            <el-button type="primary" @click="editeSpaceDetail" :disabled="zoneDisable">编辑空间详情</el-button>
+            <el-button plain @click="cancelGraphy" v-show="!zoneDisable">取 消</el-button>
           </div>
           <!-- 点击已经关联的业务空间 -->
-          <div v-show="type==2">
-            <el-button type="primary" plain @click="refactorBSP">重新划分业务空间</el-button>
-            <el-button type="primary" @click="editeSpaceDetail">编辑空间详情</el-button>
-            <el-button plain @click="cancelGraphy">取 消</el-button>
-          </div>
+          <!-- <div v-show="type==2">
+          </div> -->
           <!-- 点击未关联的业务空间 -->
           <div v-show="type==3">
-            <el-button plain @click="createNewZone">创建新的业务空间</el-button>
-            <el-button type="primary" @click="lookUnrelatBSpace(true)">从未关联平面图的业务空间中选择</el-button>
+            <el-button plain @click="createNewZone">创建单个全新的业务空间</el-button>
+            <el-button plain @click="lookUnrelatBSpace(true)">从未关联平面图的业务空间中选择</el-button>
             <el-button plain @click="cancelGraphy">取 消</el-button>
           </div>
           <!-- 重新划分业务空间 -->
@@ -44,6 +50,11 @@
             <el-button plain @click="cancelGraphy">取 消</el-button>
             <el-button type="primary" @click="saveRefactorBSP">保存</el-button>
           </div>
+          <!-- 批量创建所选业务空间 -->
+          <div v-show="type==5">
+            <el-button type="primary" @click="groupCreateZone">批量创建所选业务空间</el-button>
+            <el-button plain @click="cancelGraphy">取 消</el-button>
+          </div>
         </div>
         <div style="position: absolute;right: 0;">
           <el-button type="text" @click="lookUnrelatBSpace(false)">未关联平面图的业务空间 {{num}} 条</el-button>
@@ -51,46 +62,52 @@
       </el-row>
       <!-- 底部操作按钮 -->
       <el-row class="canvas-actions-box">
-        <canvasFun @move="moveCanvas" @fit="fit" @savePng="savePng" @saveSvg="saveSvg" @divide="divide" @clearDivide="clearDivide" @undo="undo"
-          @redo="redo" @scale="scale" :isEdit="isEdit" ref="canvasFun"></canvasFun>
+        <canvasFun @fit="fit" @savePng="savePng" @saveSvg="saveSvg" @divide="divide" @clearDivide="clearDivide" @undo="undo" @redo="redo"
+          @changeAbsorb="changeAbsorb" @scale="scale" @groupSelect="groupSelect" :config="config" ref="canvasFun" @saveJson="saveJson"></canvasFun>
       </el-row>
     </div>
     <!--  -->
     <!-- 未关联元空间的业务空间 -->
-    <unRelateBSP ref="unRelateBSP" :tableData="BSPUnrelaISPList" :isAction="isAction" @createFromUnrelated="createFromUnrelated"></unRelateBSP>
+    <unRelateBSP ref="unRelateBSP" :isAction="isAction" @createFromUnrelated="createFromUnrelated" :code="tab.code"></unRelateBSP>
     <!-- 创建新的业务空间 -->
     <createBSP ref="createBSP" @createRoom="createRoom"></createBSP>
+    <!-- 批量创建选择弹窗 -->
+    <el-dialog title="提示" :visible.sync="groupCreateDialogVis" width="30%">
+      <div id="autoRelate">
+        <p>请选择批量创建方式:</p>
+        <p>
+          <el-radio v-model="groupCreateType" :label="1">批量将所有的空白空间创建业务空间</el-radio>
+        </p>
+        <p>
+          <el-radio v-model="groupCreateType" :label="2">批量选择空白空间创建业务空间</el-radio>
+        </p>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button size="small" @click="groupCreateDialogVis=false">取消</el-button>
+        <el-button size="small" type="primary" @click="confirm">确认</el-button>
+      </span>
+    </el-dialog>
   </div>
 </template>
 <script>
 import canvasFun from "./canvasFun"
 import { mapGetters, mapActions } from "vuex";
 import { SColor, SPoint } from "@saga-web/draw/lib";
-import { DivideFloorScene, SpaceItem, ZoneItem } from "@saga-web/cad-engine/lib";
-import { FloorView } from "@saga-web/cad-engine/lib/FloorView";
+import { DivideFloorScene, SpaceItem, ZoneItem, FloorView } from "@saga-web/cad-engine/lib";
+import { colorArr } from "@/utils/spaceColor"
 import unRelateBSP from "./unRelateBSP";
 import createBSP from "./createBSP";
 import {
-  countZone,
+  buildingQuery,
   queryZone,
   updateZone,
   createZone,
+  countZone,
   getIspNotInSpace,
   createRelateInZoneAndISp,
   groupCreRelaZoneAndISp
 } from "@/api/scan/request"
-const colorArr = [
-  "#F9C3C3",
-  "#FFD1BF",
-  "#FFF3BF",
-  "#D8F7C6",
-  "#C6F2F6",
-  "#DCE3C0",
-  "#FAE6C9",
-  "#E3D7F7",
-  "#C4CBF8",
-  "#DEC3F6"
-];
+
 //  BSP => 业务空间
 export default {
   components: {
@@ -104,33 +121,39 @@ export default {
       canvasHeight: 600,
       type: 1, // 默认操作模式
       search: '',//搜索
-      num: 0, // 未关联空间的业务空间条数
       buildFloor: ['', ''],
       FloorObj: {}, //楼层对象
       FloorMap: '', //楼层底图
       tab: {},
-      isEdit: false,
+      config: {
+        isEdit: false,
+        divide: true,
+        groupSelect: true
+      },
       canvasLoading: false,
       view: null,
       scene: null,
       Outline: [], // 当前选中的多个空间组成的轮廓线->三维数组
       businessSpaceList: [], // 所有业务空间
-      BSPUnrelaISPList: [], // 未关联元空间的业务空间
+      num: 0, // 未关联元空间的业务空间统计
       BSPRelaISPList: [], // 已关联元空间的业务空间
       // 未关联元空间的业务空间弹窗
       isAction: false,
       curOutline: [],
       BIMIDToSID: {}, //bimid映射元空间id
+      BIMIDToSIName: {}, //bimid映射元空间名称
       curZoneItem: {}, //当前选中的业务空间item
       allUnRelatISP: [], //
       zoneList: [], // 业务空间-canvas图中
+      groupCreateDialogVis: false, //批量创建业务空间弹窗
+      groupCreateType: 1, //批量创建方式
+      zoneDisable: true, // 重新划分是否禁用
     }
   },
   computed: {
     ...mapGetters('layout', ['projectId'])
   },
-  created() {
-  },
+  created() {},
   mounted() {
     this.canvasWidth = this.$refs.graphy.offsetWidth;
     this.canvasHeight = this.$refs.graphy.offsetHeight;
@@ -140,10 +163,13 @@ export default {
     init(initType) {
       this.type = 1;
       if (this.scene) {
-        this.scene.isZoneSelectable = true;
-        this.scene.isSpaceSelectable = true;
         this.scene.clearSpaceSelection();
         this.scene.clearZoneSelection();
+        this.scene.clearCut();
+        this.scene.clearLikeSpaces();
+        this.zoneDisable = true;
+        this.scene.isZoneSelectable = true;
+        this.scene.isSpaceSelectable = false;
       }
       if (this.buildFloor.indexOf('all') > -1 || this.buildFloor.indexOf('noKnow') > -1) {
         return;
@@ -155,12 +181,17 @@ export default {
         // 业务空间
         this.getBusinessSpace();
       }
-      // 获取未关联平面图的业务空间统计
-      this.getUnrelateCount();
+      this.config = {
+        isEdit: false,
+        divide: true,
+        groupSelect: true
+      }
       // 获取当前楼层的元空间
       this.getFloorISpace();
       // 查询未关联业务空间的元空间
-      this.getISPSPUnrelaBSP()
+      this.getISPSPUnrelaBSP();
+      // 查询未关联平面图的业务空间
+      this.getBSPunrelaISP();
     },
     // 获取当前楼层的元空间
     getFloorISpace() {
@@ -173,8 +204,10 @@ export default {
       }
       queryZone(pa, res => {
         this.BIMIDToSID = {}
+        this.BIMIDToSIName = {}
         res.Content.map(t => {
           this.BIMIDToSID[t.BIMID.split(":")[1]] = t.RoomID;
+          this.BIMIDToSIName[t.BIMID.split(":")[1]] = t.RoomLocalName || t.RoomName;
         })
       })
     },
@@ -200,7 +233,8 @@ export default {
       this.scene.clearZoneSelection();
       // 选中当前
       zone.selected = true;
-      this.type = 2;
+      this.curZoneItem = zone;
+      this.zoneDisable = false;
       this.view.fitSelectedToView();
     },
     // 父组件调用
@@ -216,18 +250,6 @@ export default {
       console.log(arguments)
       this.init(initType);
     },
-    // 获取未关联平面图的业务空间统计
-    getUnrelateCount() {
-      let pa = {
-        data: {
-          Filters: `BuildingId='${this.buildFloor[0]}';FloorId='${this.buildFloor[1]}';Outline isNull`
-        },
-        zone: this.tab.code
-      }
-      countZone(pa, res => {
-        this.num = res.Count
-      })
-    },
     // 获取未绑定业务空间的元空间
     getISPSPUnrelaBSP() {
       let pa = {
@@ -263,6 +285,7 @@ export default {
           })
           this.scene.addSceneMark(newArr)
         }
+        this.scene.isSpaceSelectable = false;
         // 绘制业务空间
         that.getBusinessSpace();
         that.view.fitSceneToView();
@@ -272,12 +295,6 @@ export default {
         }
       })
     },
-    // 清空绘制业务空间
-    clearZoneCanvas() {
-      this.zoneList.map(t => {
-        this.scene.removeItem(t);
-      })
-    },
     // 获取当前分区下的业务空间
     getBusinessSpace() {
       this.canvasLoading = true
@@ -292,31 +309,31 @@ export default {
       if (this.buildFloor.length && this.buildFloor.length > 1) {
         pa.data.Filters = `BuildingId='${this.buildFloor[0]}';FloorId='${this.buildFloor[1]}'`
       }
-      this.clearZoneCanvas();
       queryZone(pa, res => {
         // 所有业务空间
         this.businessSpaceList = res.Content;
-        // 未关联元空间的业务空间
-        this.BSPUnrelaISPList = [];
         // 已关联元空间的业务空间
         this.BSPRelaISPList = [];
         res.Content.map(t => {
           if (t.Outline && t.Outline.length) {
             this.BSPRelaISPList.push(t)
-          } else {
-            this.BSPUnrelaISPList.push(t)
           }
         })
         // 绘制业务空间
         let tempArr = this.BSPRelaISPList.map((t, i) => {
-          return {
-            RoomLocalName: t.RoomLocalName,
-            OutLine: t.Outline,
-            RoomID: t.RoomID,
-            Color: new SColor(colorArr[i % colorArr.length]),
+          if (t.FloorId == this.buildFloor[1] && t.ObjectType == this.tab.code) {
+            return {
+              RoomLocalName: t.RoomLocalName,
+              OutLine: t.Outline,
+              RoomID: t.RoomID,
+              Color: colorArr[i % colorArr.length],
+            }
+          } else {
+            console.log('internet slow')
+            return undefined;
           }
-        })
-        this.scene.zoneList = [];
+        }).filter(item => item)
+        this.scene.removeAllZone();
         this.scene.addZoneList(tempArr);
         this.scene.click(this, this.canvasClick);
         this.zoneList = this.scene.zoneList;
@@ -325,18 +342,26 @@ export default {
     },
     // canvas点击事件
     canvasClick(item, event) {
-      if (this.type == 4) {
+      console.log(item)
+      console.log(event)
+      if (this.type == 4) {//重新划分
+
+      } else if (this.type == 5) {//批量
 
       } else {
         if (item instanceof SpaceItem && item.selectable) {
+          if (this.type == 2) {
+            this.scene.clearZoneSelection();
+          }
           this.type = 3;
           this.curZoneItem = {};
-          this.scene.isZoneSelectable = false;
         }
         if (item instanceof ZoneItem && item.selectable) {
-          this.type = 2;
+          if (this.type == 3) {
+            this.scene.clearSpaceSelection();
+          }
+          this.zoneDisable = false;
           this.curZoneItem = item;
-          this.scene.isSpaceSelectable = false;
           this.scene.clearZoneSelection();
           item.selected = true;
           this.$emit('copyID', this.curZoneItem.data.RoomID)
@@ -346,6 +371,12 @@ export default {
     // 编辑平面图
     editGraphy() {
       this.type = 3;
+      this.config.isEdit = true;
+      this.config.groupSelect = false;
+      this.config.divide = true;
+      this.scene.isSpaceSelectable = true;
+      // 设置业务空间不可选
+      this.scene.isZoneSelectable = false
     },
     // 查看未关联的业务空间--flag--查看-or-选择
     lookUnrelatBSpace(flag) {
@@ -361,7 +392,29 @@ export default {
     cancelGraphy() {
       this.init(2);
     },
-    // 批量创建业务空间
+    // 批量创建业务空间弹窗
+    handleCommand(command) {
+      this.groupCreateDialogVis = true;
+    },
+    // 创建弹窗确认
+    confirm() {
+      if (this.groupCreateType == 1) {
+        this.groupCreateBSpace()
+      } else if (this.groupCreateType == 2) {
+        this.type = 5;
+        this.config.isEdit = true;
+        this.config.groupSelect = true;
+        this.config.divide = false;
+        this.groupCreateDialogVis = false;
+        // 清空选中空间
+        this.scene.clearSpaceSelection();
+        // 设置空间可选
+        this.scene.isSpaceSelectable = true;
+        // 设置业务空间不可选
+        this.scene.isZoneSelectable = false;
+      }
+    },
+    // 根据未关联元空间批量创建业务空间
     groupCreateBSpace() {
       let text = []
       let Spaces = this.allUnRelatISP.map(t => {
@@ -393,34 +446,9 @@ export default {
           type: "warning"
         }
         ).then(() => {
-          let pa = {
-            zone: this.tab.code,
-            data: {
-              Content: Spaces
-            }
-          }
+          this.groupCreateDialogVis = false;
           this.canvasLoading = true;
-          createZone(pa, res => {
-            res.EntityList.map(t => {
-              Spaces = Spaces.map(item => {
-                if (t.RoomLocalName == item.RoomLocalName) {
-                  item.SpaceId = t.RoomID
-                }
-                return item;
-              })
-            })
-            let param = {
-              data: {
-                Content: Spaces
-              },
-              type: this.tab.code
-            }
-            groupCreRelaZoneAndISp(param, res => {
-              this.$message.success('创建成功')
-              this.canvasLoading = false;
-              this.init(2)
-            })
-          })
+          this.groupCreateBSP(Spaces)
         }).catch(() => {
           this.$message({
             type: "info",
@@ -428,7 +456,7 @@ export default {
           });
         });
       } else {
-        this.$message('没有未关联的空间')
+        this.$message('没有未关联的空间')
       }
     },
     // 创建新的业务空间
@@ -437,60 +465,82 @@ export default {
       if (arr.length) {
         let tempArr = [];
         arr.map(t => {
-          tempArr.push(t.data.Name);
+          tempArr.push(this.BIMIDToSIName[t.data.SourceId]);
         })
         this.$refs.createBSP.showDialog(tempArr.toString());
       } else {
         this.$message.warning('请至少选择一个空间');
       }
     },
-    // 创建新的业务空间-弹窗返回确认创建
+    // 根据图创建新的业务空间-弹窗返回确认创建
     createRoom(val) {
-      let arr = this.scene.getSelectedSpaces();
       let zoneObj = { Outline: [], Height: 0 }, IspaceIdList = [];
-      arr.map(t => {
+      let selectSpaces = this.scene.getSelectedSpaces();
+      selectSpaces.map(t => {
         zoneObj.Outline.push(t.data.OutLine);
-        IspaceIdList.push(this.BIMIDToSID[t.data.SourceId]);
-        console.log(zoneObj.Height)
+        if (this.BIMIDToSID[t.data.SourceId]) {
+          IspaceIdList.push(this.BIMIDToSID[t.data.SourceId]);
+        }
         if (t.data.Height && (zoneObj.Height == 0 || t.data.Height < zoneObj.Height)) {
-          zoneObj.Height = t.data.Height;
+          zoneObj.Height = t.data.Height > 100 ? (t.data.Height / 1000).toFixed(2) : t.data.Height;
         }
       })
+      // 如果有划分,求交集
+      if (this.scene.cutItem || this.scene.sceneMark) {
+        zoneObj.Outline = [];
+        let arr = this.scene.getIntersect();
+        arr.map(t => {
+          let temp = t.map(item => {
+            return {
+              X: item.x,
+              Y: -item.y,
+              Z: 0
+            }
+          })
+          zoneObj.Outline.push([temp]);
+        })
+      }
+      if (!zoneObj.Outline.length) {
+        zoneObj.Outline = null;
+      }
       zoneObj.RoomLocalName = val;
       zoneObj.BuildingId = this.buildFloor[0];
       zoneObj.FloorId = this.buildFloor[1];
-      let pa = {
-        zone: this.tab.code,
-        data: {
-          Content: [zoneObj]
-        }
-      }
-      createZone(pa, res => {
-        this.relationInBSPandISP(res.EntityList[0].RoomID, IspaceIdList)
-      })
+      this.createSingleBSP(zoneObj, IspaceIdList)
     },
-    // 从未关联平面图的业务空间中选择--按钮返回关联信号
+    // 根据图从未关联平面图的业务空间中选择--按钮返回关联信号
     createFromUnrelated(BSP) {
       BSP.Outline = [];
       BSP.Height = 0;
-      let arr = this.scene.getSelectedSpaces();
+      let arr = this.scene.getSelectedSpaces(), IspaceIdList = [];
       arr.map(t => {
         BSP.Outline.push(t.data.OutLine);
+        if (this.BIMIDToSID[t.data.SourceId]) {
+          IspaceIdList.push(this.BIMIDToSID[t.data.SourceId]);
+        }
         if (t.Height && (BSP.Height == 0 || t.Height < BSP.Height)) {
-          BSP.Height = t.Height;
+          BSP.Height = t.Height > 100 ? (t.Height / 1000).toFixed(2) : t.Height;
         }
       })
-      let pa = {
-        zone: BSP.ObjectType,
-        data: {
-          Content: [BSP],
-          Projection: ['Outline']
-        }
+      // 如果有划分,求交集
+      if (this.scene.cutItem || this.scene.sceneMark) {
+        BSP.Outline = [];
+        let spaceIntersect = this.scene.getIntersect();
+        spaceIntersect.map(t => {
+          let temp = t.map(item => {
+            return {
+              X: item.x,
+              Y: -item.y,
+              Z: 0
+            }
+          })
+          BSP.Outline.push([temp]);
+        })
       }
-      updateZone(pa, res => {
-        this.$message.success('更新成功');
-        this.init(2);
-      })
+      if (!BSP.Outline.length) {
+        BSP.Outline = null;
+      }
+      this.updateBSPOutline(BSP, IspaceIdList)
     },
     // 编辑空间详情
     editeSpaceDetail() {
@@ -508,51 +558,229 @@ export default {
     },
     // 重新划分业务空间
     refactorBSP() {
+      this.config.isEdit = true;
+      this.config.groupSelect = false;
+      this.config.divide = true;
       this.type = 4;
-      // 清空选中空间
-      this.scene.clearSpaceSelection();
       // 设置空间可选
       this.scene.isSpaceSelectable = true;
       // 将已关联的设置不可选,并将当前选的隐藏
-      this.scene.changeSelectZone(this.curZoneItem);
+      this.scene.isZoneSelectable = false;
+      this.curZoneItem.visible = false;
+      // 将当前业务空间的每个元素添加到场景中并选中
+      this.scene.addAllLikeSpace(this.curZoneItem.data.OutLine);
     },
     // 重新划分--保存
     saveRefactorBSP() {
-      let arr = this.scene.getSelectedSpaces();
+      let selectSpace = this.scene.getSelectedSpaces();
+      let selectLikeSpace = this.scene.getSelectedLikeSpace();
       //更新业务空间
       let zoneObj = { Outline: [], Height: 0 }, IspaceIdList = [];
-      arr.map(t => {
+      // 空间
+      selectSpace.map(t => {
         zoneObj.Outline.push(t.data.OutLine);
-        IspaceIdList.push(this.BIMIDToSID[t.data.SourceId]);
+        if (this.BIMIDToSID[t.data.SourceId]) {
+          IspaceIdList.push(this.BIMIDToSID[t.data.SourceId]);
+        }
         if (t.Height && (zoneObj.Height == 0 || t.Height < zoneObj.Height)) {
-          zoneObj.Height = t.Height;
+          zoneObj.Height = t.Height > 100 ? (t.Height / 1000).toFixed(2) : t.Height;
         }
       })
-      zoneObj.RoomID = this.curZoneItem.data.RoomID;
+      // 类空间
+      selectLikeSpace.map(t => {
+        zoneObj.Outline.push(t.data);
+      })
+      // 如果有划分,求交集
+      if (this.scene.cutItem || this.scene.sceneMark) {
+        zoneObj.Outline = [];
+        let spaceIntersect = this.scene.getIntersect();
+        spaceIntersect.map(t => {
+          let temp = t.map(item => {
+            return {
+              X: item.x,
+              Y: -item.y,
+              Z: 0
+            }
+          })
+          zoneObj.Outline.push([temp]);
+        })
+        let likeSpaceIntersect = this.scene.getLikeIntersect();
+        likeSpaceIntersect.map(t => {
+          let temp = t.map(item => {
+            return {
+              X: item.x,
+              Y: -item.y,
+              Z: 0
+            }
+          })
+          zoneObj.Outline.push([temp]);
+        })
+      }
       if (!zoneObj.Outline.length) {
         zoneObj.Outline = null;
       }
+      zoneObj.RoomID = this.curZoneItem.data.RoomID;
+      this.updateBSPOutline(zoneObj, IspaceIdList)
+    },
+    // 根据图批量创建所选业务空间
+    groupCreateZone() {
+      let arr = this.scene.getSelectedSpaces();
+      let spaces = [];
+      // 如果有划分,求交集
+      if (this.scene.cutItem || this.scene.sceneMark) {
+        let outlines = this.scene.getIntersectInSpace();
+        for (let k in outlines) {
+          outlines[k] = outlines[k].map(t => {
+            t = t.map(item => {
+              item = item.map(j => {
+                return { X: j.x, Y: -j.y, Z: 0 }
+              })
+              return item
+            })
+            return t;
+          })
+        }
+        spaces = arr.map(t => {
+          return {
+            IspaceId: this.BIMIDToSID[t.data.SourceId],
+            RoomLocalName: this.BIMIDToSIName[t.data.SourceId],
+            Outline: outlines[t.data.SourceId],
+            BuildingId: this.buildFloor[0],
+            FloorId: this.buildFloor[1],
+            Height: t.data.Height > 100 ? (t.data.Height / 1000).toFixed(2) : t.data.Height || 0
+          }
+        }).filter(item => item.Outline && item.Outline.length)
+      } else {
+        spaces = arr.map(t => {
+          return {
+            IspaceId: this.BIMIDToSID[t.data.SourceId],
+            RoomLocalName: this.BIMIDToSIName[t.data.SourceId],
+            Outline: [t.data.OutLine],
+            BuildingId: this.buildFloor[0],
+            FloorId: this.buildFloor[1],
+            Height: t.data.Height > 100 ? (t.data.Height / 1000).toFixed(2) : t.data.Height || 0
+          }
+        })
+      }
+      if (spaces.length) {
+        this.canvasLoading = true;
+        this.groupCreateBSP(spaces)
+      } else {
+        this.$message.warning('未选择本层空间');
+      }
+    },
+    // 更新业务空间和元空间的关系
+    relationInBSPandISP(SpaceId, IspaceIdList) {
+      let pa = {
+        data: { SpaceId: SpaceId, IspaceIdList: IspaceIdList },
+        type: this.tab.code
+      }
+      createRelateInZoneAndISp(pa, res => {
+        this.$message.success('创建成功');
+        this.init(2);
+      })
+    },
+    // 批量更新业务空间和元空间的关系
+    groupCreRelaZoneAndISp(Spaces) {
+      Spaces = Spaces.filter(item => item.IspaceId);
+      if (Spaces.length) {
+        let param = {
+          data: {
+            Content: Spaces
+          },
+          type: this.tab.code
+        }
+        groupCreRelaZoneAndISp(param, res => {
+          this.$message.success('创建成功')
+          this.canvasLoading = false;
+          this.init(2)
+        })
+      } else {
+        this.$message.success('创建成功')
+        this.canvasLoading = false;
+        this.init(2)
+      }
+    },
+    // 批量创建
+    groupCreateBSP(spaces) {
+      spaces = spaces.map(t => {
+        t.BIMLocation = this.getAverageVal(t.Outline);
+        return t;
+      })
+      let pa = {
+        zone: this.tab.code,
+        data: {
+          Content: spaces
+        }
+      }
+      createZone(pa, res => {
+        res.EntityList.map(t => {
+          spaces = spaces.map(item => {
+            if (t.RoomLocalName == item.RoomLocalName) {
+              item.SpaceId = t.RoomID
+            }
+            return item;
+          })
+        })
+        this.groupCreRelaZoneAndISp(spaces)
+      })
+    },
+    // 单个创建
+    createSingleBSP(space, IspaceIdList) {
+      space.BIMLocation = space.Outline ? this.getAverageVal(space.Outline) : null;
+      let pa = {
+        zone: this.tab.code,
+        data: {
+          Content: [space]
+        }
+      }
+      createZone(pa, res => {
+        this.relationInBSPandISP(res.EntityList[0].RoomID, IspaceIdList)
+      })
+    },
+    // 更新业务空间区域
+    updateBSPOutline(zoneObj, IspaceIdList) {
+      zoneObj.BIMLocation = zoneObj.Outline ? this.getAverageVal(zoneObj.Outline) : null;
       let pa = {
         zone: this.tab.code,
         data: {
           Content: [zoneObj],
-          Projection: ['Outline']
+          Projection: ['Outline', 'BIMLocation']
         },
       }
       updateZone(pa, res => {
         this.relationInBSPandISP(zoneObj.RoomID, IspaceIdList)
       })
     },
-    // 更新业务空间和元空间的关系
-    relationInBSPandISP(SpaceId, IspaceIdList) {
+    // 查询未关联平面图的业务空间(项目下+当前分区)
+    getBSPunrelaISP() {
       let pa = {
-        data: { SpaceId: SpaceId, IspaceIdList: IspaceIdList },
-        type: this.tab.code
+        zone: this.tab.code,
+        data: {
+          Filters: `Outline isNull`
+        }
       }
-      createRelateInZoneAndISp(pa, res => {
-        this.$message.success('创建成功');
-        this.init(2);
+      countZone(pa, res => {
+        this.num = res.Count;
+      })
+    },
+    // 计算平均值 作为业务空间BIMLocation
+    getAverageVal(Outline) {
+      let X = 0, Y = 0, Z = 0, len = 0;
+      Outline.map(t => {
+        if (t[0]) {
+          t[0].map(item => {
+            X += item.X;
+            Y += item.Y;
+            Z += item.Z;
+          })
+          len += t[0].length
+        }
       })
+      X = (X / len).toFixed(2);
+      Y = (Y / len).toFixed(2);
+      Z = (Z / len).toFixed(2);
+      return `${X},${Y},${Z}`
     },
     // canvas 获取焦点
     focus() {
@@ -560,22 +788,20 @@ export default {
     },
     // 清除canvas
     clearGraphy() {
-      if (this.view && this.view.scene) {
+      if (this.view) {
         this.view.scene = null;
         return
       }
       this.view = new FloorView('floorCanvas')
     },
     // 工具栏操作
-    // 移动底图
-    moveCanvas(move) {
-      // todo
-      let canvas = document.getElementById(`floorCanvas`);
-      if (move) {
-        canvas.style.cursor = 'move';
-      } else {
-        canvas.style.cursor = 'default';
-      }
+    // 吸附
+    changeAbsorb(isAbsorbing) {
+      this.scene.isAbsorbing = isAbsorbing;
+    },
+    // 框选
+    groupSelect() {
+      this.scene.isRectSelection = 1;
     },
     // 适配底图到窗口
     fit() {
@@ -589,18 +815,20 @@ export default {
     saveSvg() {
       this.view.saveSceneSvg(`${this.buildFloor[1]}.svg`, 6400, 4800);
     },
+    // 保存json
+    saveJson() {
+      this.view.saveFloorJson(`${this.buildFloor[1]}.json`)
+    },
     // 切割划分
     divide() {
-      this.scene.isMarking = true;
+      this.scene.isCutting = true;
     },
     // 清除切割划分
     clearDivide() {
-      this.scene.clearSceneMark()
+      this.scene.clearCut();
     },
     // 撤销
-    undo() {
-
-    },
+    undo() { },
     // 反撤销
     redo() { },
     // 缩放
@@ -634,7 +862,23 @@ export default {
           this.$refs.canvasFun.sliderVal = s > 1000 ? 1000 : s;
         }
       }
-    }
+    },
+    "scene.isRectSelection": {
+      handler(n) {
+        if (!n) {
+          this.$refs.canvasFun.active = '';
+        }
+      }
+    },
+    "scene.isCutting": {
+      handler(n) {
+        if (!n) {
+          this.$refs.canvasFun.active = '';
+          this.$refs.canvasFun.isSwitch = false;
+          this.scene.isAbsorbing = false;
+        }
+      }
+    },
   }
 }
 </script>
@@ -660,7 +904,8 @@ export default {
       width: 320px;
       margin-right: 10px;
     }
-    .button-group button {
+    .button-group button,
+    .button-group .el-dropdown {
       display: block;
       float: left;
     }
@@ -690,4 +935,4 @@ export default {
     z-index: 999;
   }
 }
-</style>
+</style>

+ 137 - 27
src/components/business_space/newGraphy/unRelateBSP.vue

@@ -1,27 +1,52 @@
 <template>
-  <el-dialog :title="title" :visible.sync="dialogVisible" width="600px" id="lookUnrelatBSpace">
-    <el-input :placeholder="`请输入业务空间名称`" v-model="queryString" @keyup.enter.native="queryTableData">
-      <i slot="suffix" class="el-input__icon el-icon-search" @click="queryTableData"></i>
-    </el-input>
-    <div style="margin-top:10px;height:300px;">
-      <el-table :data="data" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
-        <el-table-column prop="RoomLocalName" label="业务空间名称" show-overflow-tooltip min-width="200"></el-table-column>
+  <el-dialog :title="title" :visible.sync="dialogVisible" width="900px" id="unRelateBSP">
+    <el-row class="filters">
+      <el-col :span="9">
+        <el-input placeholder="输入业务空间名称进行查询" v-model="keycode" clearable @keyup.enter.native="getTableData">
+          <i slot="suffix" class="el-input__icon el-icon-search" @click="getTableData"></i>
+        </el-input>
+      </el-col>
+      <el-col :span="15">
+        <span style="margin-left:10px;">所属楼层</span>
+        <el-cascader @change="getTableData" v-model="floor" :options="options" :props="props"></el-cascader>
+      </el-col>
+    </el-row>
+    <div class="table-box">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column :label="`${inSpaceType}名称`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.RoomLocalName||scope.row.RoomName||''}}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="BNAME" label="所属建筑" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="FNAME" label="所属楼层" show-overflow-tooltip min-width="100"></el-table-column>
         <el-table-column prop="action" label="操作" min-width="100" v-if="isAction">
           <template slot-scope="scope">
-            <el-button @click="createRelation(scope.row)">关联平面图</el-button>
+            <el-button size="mini" @click="createRelation(scope.row)" type="primary" plain>关联平面图</el-button>
           </template>
         </el-table-column>
       </el-table>
+      <!-- 分页 -->
+      <el-pagination class="fr" v-show="tableData && tableData.length" @size-change="handleSizeChange" @current-change="handleCurrentChange"
+        :current-page="page.pageNumber" :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper"
+        :total="page.total"></el-pagination>
     </div>
   </el-dialog>
 </template>
 
 <script>
+import {
+  buildingQuery,
+  queryZone
+} from "@/api/scan/request"
 export default {
   name: "unRelateBSP",
   data() {
     return {
       title: '未关联平面图的业务空间',
+      inSpaceType: '业务空间',
       dialogVisible: false,
       loading: false,
       headerStyle: {
@@ -29,39 +54,124 @@ export default {
         color: '#2b2b2b',
         lineHeight: '30px'
       },
-      queryString: '',
-      data: []
+      keycode: '',
+      tableData: [],
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      floor: ['all'], // 级联建筑楼层
+      props: { //自定义字段
+        value: "BuildID",
+        label: "BuildLocalName",
+        children: "Floor"
+      },
+      bfData: {}, //建筑楼层id =>名称
+      options: [], //级联
     };
   },
   props: {
-    tableData: {
-      default: []
-    }, //列表数据
     isAction: false, //是否显示操作按钮
+    code: String
+  },
+  created() {
+    this.getBuilding()
   },
   methods: {
     // 显示弹窗
     showDialog() {
-      this.data = this.tableData;
       this.dialogVisible = true;
-    },
-    // 搜索
-    queryTableData() {
-      var restaurants = this.tableData;
-      this.data = this.queryString ?
-        restaurants.filter(this.createFilter(this.queryString)) :
-        restaurants;
-    },
-    createFilter(queryString) {
-      return restaurant => {
-        return restaurant.RoomLocalName.indexOf(queryString) > -1;
-      };
+      this.getTableData();
     },
     // 关联平面图
     createRelation(row) {
       this.$emit('createFromUnrelated', row);
       this.dialogVisible = false;
+    },
+    // 分页条数
+    handleSizeChange(val) {
+      this.page.pageSize = val;
+      this.page.pageNumber = 1;
+      this.getTableData();
+    },
+    // 页码
+    handleCurrentChange(val) { 
+      this.page.pageNumber = val;
+      this.getTableData();
+    },
+    // 获取项目下建筑
+    getBuilding() {
+      let pa = {
+        Cascade: [{ name: 'floor', Orders: 'SequenceId desc' }],
+        Orders: "BuildLocalName asc",
+      }
+      buildingQuery(pa, res => {
+        this.options = res.Content.map(t => {
+          this.bfData[t.BuildID] = t.BuildLocalName;
+          if (t.Floor) {
+            t.Floor = t.Floor.map(item => {
+              this.bfData[item.FloorID] = item.FloorLocalName;
+              item.BuildID = item.FloorID;
+              item.BuildLocalName = item.FloorLocalName;
+              return item;
+            })
+          } else {
+            t.Floor = []
+          }
+          t.Floor.unshift({ BuildID: 'all', BuildLocalName: '全部' }, { BuildID: 'isNull', BuildLocalName: '未明确楼层' })
+          return t;
+        })
+        this.options.unshift({ BuildID: 'all', BuildLocalName: '全部' }, { BuildID: 'isNull', BuildLocalName: '未明确建筑' })
+      })
+    },
+    // 查询未关联平面图的业务空间(项目下+当前分区)
+    getTableData() {
+      let pa = {
+        zone: this.code,
+        data: {
+          Filters: `Outline isNull`,
+          Orders: "createTime desc, RoomID asc",
+          PageSize: this.page.pageSize,
+          pageNumber: this.page.pageNumber
+        }
+      }
+      if (this.floor[0] == 'isNull') {
+        pa.data.Filters += `;BuildingId isNull`
+      } else if (this.floor[0] && this.floor[0] != 'all') {
+        pa.data.Filters += `;BuildingId='${this.floor[0]}'`
+      }
+      if (this.floor[1] == 'isNull') {
+        pa.data.Filters += `;FloorId isNull`
+      } else if (this.floor[1] && this.floor[1] != 'all') {
+        pa.data.Filters += `;FloorId='${this.floor[1]}'`
+      }
+      if (this.keycode != '') {
+        pa.data.Filters += `;RoomLocalName contain "${this.keycode}" or RoomName contain "${this.keycode}"`
+      }
+      queryZone(pa, res => {
+        this.page.total = res.Total;
+        this.tableData = res.Content.map(t => {
+          t.BNAME = this.bfData[t.BuildingId];
+          t.FNAME = this.bfData[t.FloorId];
+          return t;
+        })
+      })
     }
   },
 };
-</script>
+</script>
+<style lang="less" scoped>
+#unRelateBSP {
+  .filters {
+    margin-bottom: 10px;
+    /deep/ .el-input__inner {
+      vertical-align: baseline;
+    }
+  }
+  .table-box {
+    height: 350px;
+  }
+}
+</style>

+ 16 - 5
src/components/business_space/newTables/eqToSpaceTable.vue

@@ -1,13 +1,13 @@
 <template>
   <div id="eqInSp">
-    <el-row>
+    <el-row v-if="hidden">
       <el-button type="primary" @click="add">添加{{inSpaceType}}</el-button>
       <el-tooltip class="item" effect="dark" :content="`可前往“全部关系总览”中,按坐标计算${typeToTips[type]}`" placement="right">
         <el-button>按空间计算</el-button>
       </el-tooltip>
     </el-row>
     <div class="table-box">
-      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+      <el-table :data="tableData" style="width: 100%" height="100%" :header-cell-style="headerStyle" v-loading="loading">
         <el-table-column :label="`${inSpaceType}名称`" show-overflow-tooltip min-width="100">
           <template slot-scope="scope">
             <div>
@@ -31,7 +31,7 @@
           </template>
         </el-table-column>
         <template slot="empty">
-          <div style="height: 60%;transform: translateY(50%);">
+          <div style="height: 60%;transform: translateY(50%);lineHeight:20px;">
             <i class="icon-wushuju iconfont"></i>
             可前往“全部关系总览”中,按坐标计算{{typeToTips[type]}}
           </div>
@@ -71,7 +71,9 @@ export default {
       typeToTips: {
         Equipment: '空间内的设备',
         EquipmentFor: '服务于空间的设备',
-      }
+      },
+      hidden: true,
+      loading: false
     };
   },
   props: {
@@ -80,6 +82,7 @@ export default {
   },
   created() {
     this.getTableData()
+    this.changeContentStyle();
   },
   methods: {
     // 删除关系
@@ -128,6 +131,7 @@ export default {
     },
     // 获取列表数据
     getTableData() {
+      this.loading = true;
       let pa = {
         data: {
           Filters: `RoomID='${this.params.RoomID}'`,
@@ -141,6 +145,7 @@ export default {
         zone: this.params.zone
       }
       queryZone(pa, res => {
+        this.loading = false;
         this.tableData = res.Content[0][this.type] || []
         this.tableData.map(t => {
           t.SpaceId = res.Content[0].RoomID
@@ -150,13 +155,19 @@ export default {
     },
     // 添加设备
     add() {
-      this.$refs.addEqDialog.floor = [this.params.BuildingId, this.params.FloorId];
+      this.$refs.addEqDialog.floor = this.params.buildFloorSelectd;
       this.$refs.addEqDialog.showDialog()
+    },
+    changeContentStyle() {
+      this.$route.name == "spaceLedger" ? this.hidden = false : this.hidden = true;
     }
   },
   watch: {
     type() {
       this.getTableData()
+    },
+    params() {
+      this.getTableData()
     }
   }
 };

+ 17 - 5
src/components/business_space/newTables/syInSpaceTable.vue

@@ -1,6 +1,6 @@
 <template>
   <div id="eqInSp">
-    <el-row>
+    <el-row v-show="hidden">
       <el-button type="primary" @click="add">添加{{inSpaceType}}</el-button>
       <el-tooltip class="item" effect="dark" :content="`可前往“全部关系总览”中,按坐标计算${typeToTips[type]}`" placement="right">
         <el-button>按空间计算</el-button>
@@ -24,7 +24,7 @@
           </template>
         </el-table-column>
         <template slot="empty">
-          <div style="height: 60%;transform: translateY(50%);">
+          <div style="height: 60%;transform: translateY(50%);lineHeight:20px;">
             <i class="icon-wushuju iconfont"></i>
             可前往“全部关系总览”中,按坐标计算{{typeToTips[type]}}
           </div>
@@ -61,7 +61,9 @@ export default {
       tableData: [], //列表数据
       typeToTips: {
         generalSystem: '空间内的系统',
-      }
+      },
+      hidden: true,
+      loading: false
     };
   },
   props: {
@@ -69,7 +71,8 @@ export default {
     type: {}
   },
   created() {
-    this.getTableData()
+    this.getTableData();
+    this.changeContentStyle();
   },
   methods: {
     // 删除关系
@@ -89,7 +92,7 @@ export default {
       })
     },
     // 删除关系
-    deleteSyInSpace(pa){
+    deleteSyInSpace(pa) {
       syInSpaceDelete(pa, res => {
         this.$message.success('删除成功');
         this.getTableData();
@@ -97,6 +100,7 @@ export default {
     },
     // 获取列表数据
     getTableData() {
+      this.loading = true;
       let pa = {
         data: {
           Cascade: [{ Name: "generalSystem" }],
@@ -105,6 +109,7 @@ export default {
         zone: this.params.zone
       }
       queryZone(pa, res => {
+        this.loading = false;
         this.tableData = res.Content[0].GeneralSystem || [];
         this.tableData.map(t => {
           t.SpaceId = res.Content[0].RoomID;
@@ -115,11 +120,18 @@ export default {
     // 添加系统
     add() {
       this.$refs.addSyDialog.showDialog()
+    },
+    changeContentStyle() {
+      // 在辅助屏不显示添加按钮,动态设置高度
+      this.$route.name == "spaceLedger" ? this.hidden = false : this.hidden = true;
     }
   },
   watch: {
     type() {
       this.getTableData()
+    },
+    params() {
+      this.getTableData()
     }
   }
 };

+ 8 - 8
src/components/business_space/table/equipTable.vue

@@ -104,7 +104,7 @@
                     code: "EquipXSpace"
                 }],
                 activeRelation: "EquipinSpace",
-                relationType: {
+                CalcUrl: {
                     "code": "GeneralZone",
                     "name": "默认分区",
                     "rel_type": "99"
@@ -133,7 +133,7 @@
                     secret: this.secret
                 };
                 this.isLoading = true
-                if (this.relationType.rel_type == 99 && this.activeRelation == "EquipinSpace") {
+                if (this.CalcUrl.rel_type == 99 && this.activeRelation == "EquipinSpace") {
                     this.dataChange(param);
                 } else {
                     this.getRlations()
@@ -174,13 +174,13 @@
             getRlations() {
                 this.isLoading = true
                 this.relType = 0
-                if (this.relationType.rel_type == 99) {
+                if (this.CalcUrl.rel_type == 99) {
                     this.relType = "1"
                 } else {
-                    if (this.relationType.rel_type > 9) {
-                        this.relType = (this.relationType.rel_type * 100).toString()
+                    if (this.CalcUrl.rel_type > 9) {
+                        this.relType = (this.CalcUrl.rel_type * 100).toString()
                     } else {
-                        this.relType = '0' + (this.relationType.rel_type * 100)
+                        this.relType = '0' + (this.CalcUrl.rel_type * 100)
                     }
                 }
                 let param = {
@@ -280,7 +280,7 @@
              */
             getData(data, type) {
                 this.activeRelation = "EquipinSpace"
-                this.relationType = type
+                this.CalcUrl = type
                 this.page = {
                     size: 50,
                     sizes: [10, 30, 50, 100, 150, 200],
@@ -307,7 +307,7 @@
                     secret: this.secret
                 };
                 this.isLoading = true
-                if (this.relationType.rel_type == 99) {
+                if (this.CalcUrl.rel_type == 99) {
                     this.dataChange(param);
                 } else {
                     this.getRlations()

+ 184 - 0
src/components/data_admin/buildTask/detail/assetsDetail.vue

@@ -0,0 +1,184 @@
+<template>
+  <div class="detail-box">
+    <el-scrollbar style="height:100%;">
+      <div class="attribute-detail detail-item">
+        <el-form :model="detail" label-width="150px">
+          <el-form-item label="资产基本信息"></el-form-item>
+          <el-form-item label="任务创建时间:">{{ detail.CreateTime || '--' }}</el-form-item>
+          <el-form-item label="任务当前状态:">{{ detail.TaskState || '--' }}</el-form-item>
+          <el-form-item label="任务执行方案:">{{ detail.ScanScheme?detail.ScanScheme.SchemeName?detail.ScanScheme.SchemeName:'--':'--' }}</el-form-item>
+          <el-form-item label="设备族:">{{ detail.EquipFamily?detail.EquipFamily.FamilyName?detail.EquipFamily.FamilyName:'--':'--' }}</el-form-item>
+          <el-form-item label="全局名称:">{{ detail.EquipName || '--' }}</el-form-item>
+          <el-form-item label="资产本地名称:">{{ detail.EquipLocalName || '--' }}</el-form-item>
+          <el-form-item label="资产本地编码:">{{ detail.EquipLocalID || '--' }}</el-form-item>
+          <el-form-item label="设计图纸中编码:">{{ detail.CadId || '--' }}</el-form-item>
+          <el-form-item label="安装位置:">{{ detail.InstallLocation || '--' }}</el-form-item>
+          <el-form-item label="生产厂家:">{{ detail.Manufacturer || '--' }}</el-form-item>
+          <el-form-item label="型号:">{{ detail.Specification || '--' }}</el-form-item>
+          <el-form-item label="供应商:">{{ detail.Supplier || '--' }}</el-form-item>
+        </el-form>
+      </div>
+      <div class="implement-detail detail-item" v-if="detail.TaskState == '未找到'">
+        <el-form :model="detail" label-width="150px">
+          <el-form-item label="执行任务人:">{{ detail.WorkerName || '--' }}</el-form-item>
+          <el-form-item label="执行时间:">{{ detail.ProcessTime || '--' }}</el-form-item>
+          <el-form-item label="未找到对象信息"></el-form-item>
+          <el-form-item label="资产名称:">{{ detail.EquipLocalName || detail.EquipName || '--' }}</el-form-item>
+          <el-form-item label="全景图:" v-show="panoramaList && panoramaList.length">
+            <div class="img-item" @click="dialogVisible = true"  v-for="item in panoramaList" :key="item.Key">
+              <img :src="`/image-service/common/image_get?systemId=dataPlatform&key=${item.Key}`" style="width:100%;" :alt="item.Name">
+            </div>
+          </el-form-item>
+          <el-form-item label="资产照片:" v-show="imgList && imgList.length">
+            <div class="img-item">
+              <div class="demo-image__preview">
+                <el-image style="width:100%;" v-for="item in imgList"
+                 :key="item.Key" :title="item.Name"
+                 @click="nowUrl = item.Key" 
+                 :src="`/image-service/common/image_get?systemId=dataPlatform&key=${item.Key}&width=400`" 
+                 :preview-src-list="srcList">
+                </el-image>
+              </div>
+            </div>
+          </el-form-item>
+          <el-form-item label="现场视频:" v-show="videoList && videoList.length">
+            <video controls style="width:100%;" v-for="item in videoList" :key="item.Key" :title="item.Name">
+              <source :src="`/image-service/common/image_get?systemId=dataPlatform&key=${item.Key}`" type="video/mp4">
+              您的浏览器不支持 HTML5 video ,暂无法播放。
+            </video>
+          </el-form-item>
+          <el-form-item label="备注信息:">{{ detail.Note || '--' }}</el-form-item>
+        </el-form>
+      </div>
+      <div class="operation-detail detail-item">
+        <el-form>
+          <el-form-item label="操作信息:"></el-form-item>
+          <div class="block">
+            <el-timeline>
+              <el-timeline-item timestamp="2018/4/12" placement="top">
+                <el-card>
+                  <h4>更新 Github 模板</h4>
+                  <p>王小虎 提交于 2018/4/12 20:46</p>
+                </el-card>
+              </el-timeline-item>
+              <el-timeline-item timestamp="2018/4/3" placement="top">
+                <el-card>
+                  <h4>更新 Github 模板</h4>
+                  <p>王小虎 提交于 2018/4/3 20:46</p>
+                </el-card>
+              </el-timeline-item>
+              <el-timeline-item timestamp="2018/4/2" placement="top">
+                <el-card>
+                  <h4>更新 Github 模板</h4>
+                  <p>王小虎 提交于 2018/4/2 20:46</p>
+                </el-card>
+              </el-timeline-item>
+            </el-timeline>
+          </div>
+        </el-form>
+      </div>
+    </el-scrollbar>
+    <el-dialog title="全景图" :visible.sync="dialogVisible" width="70%" append-to-body>
+      一张图
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { } from "@/api/scan/request"
+import { mapGetters } from "vuex"
+export default {
+  components: {
+
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"]),
+    panoramaList(){
+      if(this.detail && this.detail.TaskPicList && this.detail.TaskPicList.length){
+        return this.detail.TaskPicList.filter(item => {
+          return item.Type == 'panorama'
+        })
+      } else {
+        return []
+      }
+    },
+    imgList(){
+      if(this.detail && this.detail.TaskPicList && this.detail.TaskPicList.length){
+        return this.detail.TaskPicList.filter(item => {
+          return item.Type == 'image'
+        })
+      } else {
+        return []
+      }
+    },
+    videoList(){
+      if(this.detail && this.detail.TaskPicList && this.detail.TaskPicList.length){
+        return this.detail.TaskPicList.filter(item => {
+          return item.Type == 'video'
+        })
+      } else {
+        return []
+      }
+    },
+    srcList(){
+      let nowIndex = this.imgList.findIndex(item => {return item.Key == this.nowUrl})
+      let index = nowIndex >= 1 ? nowIndex : 0;
+      let tempArr1 = this.imgList.slice(0, index);
+      let tempArr2 = this.imgList.slice(index, this.imgList.length);
+
+      let res = tempArr2.concat(tempArr1).map(item => {
+        return `/image-service/common/image_get?systemId=dataPlatform&key=${item.Key}`
+      });
+      return res;
+    }
+  },
+  props: {
+    detail: Object
+  },
+  data() {
+    return {
+      dialogVisible: false,//全景图弹出框
+      nowUrl: ''//当前正在显示的图
+    };
+  },
+  methods: {
+  },
+  watch: {
+    'detail.TaskId'() {
+      console.log(this.detail)
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+.detail-box {
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  /deep/ .el-scrollbar__wrap {
+    overflow-x: hidden;
+  }
+  /deep/ .el-icon-circle-close {
+    color: white;
+  }
+
+  /deep/ .el-form-item__content {
+    text-overflow: ellipsis;
+    overflow: hidden;
+  }
+
+  .detail-item {
+    width: calc(100% - 30px);
+    margin: 15px 15px 10px;
+    padding: 10px;
+    box-sizing: border-box;
+    border-left: 1px solid #eee;
+    box-shadow: 0px 1px 5px 0px rgba(59, 66, 84, 0.15);
+  }
+
+  .img-item {
+    position: relative;
+    cursor: pointer;
+  }
+}
+</style>

+ 287 - 0
src/components/data_admin/buildTask/detail/deviceDetail.vue

@@ -0,0 +1,287 @@
+<template>
+  <div class="detail-box">
+    <el-scrollbar style="height:100%;">
+      <div class="attribute-detail detail-item">
+        <el-form :model="detail" label-width="150px">
+          <el-form-item label="设备基本信息"></el-form-item>
+          <el-form-item label="任务创建时间:">{{ detail.CreateTime || '--' }}</el-form-item>
+          <el-form-item label="任务当前状态:">{{ detail.TaskState || '--' }}</el-form-item>
+          <el-form-item label="任务执行方案:">{{
+            detail.ScanScheme?detail.ScanScheme.SchemeName?detail.ScanScheme.SchemeName:'--':'--' }}
+          </el-form-item>
+          <el-form-item label="设备类:">{{
+            detail.EquipCategory?detail.EquipCategory.EquipName?detail.EquipCategory.EquipName:'--':'--' }}
+          </el-form-item>
+          <el-form-item label="全局名称:">{{ detail.EquipName || '--' }}</el-form-item>
+          <el-form-item label="设备本地名称:">{{ detail.EquipLocalName || '--' }}</el-form-item>
+          <el-form-item label="设备本地编码:">{{ detail.EquipLocalID || '--' }}</el-form-item>
+          <el-form-item label="设计图纸中编码:">{{ detail.CadId || '--' }}</el-form-item>
+          <el-form-item label="安装位置:">{{ detail.InstallLocation || '--' }}</el-form-item>
+          <el-form-item label="生产厂家:">{{ detail.Manufacturer || '--' }}</el-form-item>
+          <el-form-item label="型号:">{{ detail.Specification || '--' }}</el-form-item>
+          <el-form-item label="供应商:">{{ detail.Supplier || '--' }}</el-form-item>
+          <el-form-item label="包含部件:">
+            <div v-if="detail.Component && detail.Component.length">
+              <p v-for="(item, index) in detail.Component?detail.Component:[]" :key="index"
+                 show-overflow-tooltip>
+                {{ item.EquipName }}
+              </p>
+            </div>
+            <div v-else>--</div>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div class="implement-detail detail-item" v-if="detail.TaskState === '未找到'">
+        <el-form :model="detail" label-width="150px">
+          <el-form-item label="执行任务人:">{{ detail.WorkerName || '--' }}</el-form-item>
+          <el-form-item label="执行时间:">{{ detail.ProcessTime || '--' }}</el-form-item>
+          <el-form-item label="未找到对象信息"></el-form-item>
+          <el-form-item label="设备信息:" v-if="!detail.isComponent">{{ detail.EquipLocalName || detail.EquipName
+            ||'--' }}
+          </el-form-item>
+          <el-form-item label="部件信息:" v-else>
+            <div v-if="detail.Component && detail.Component.length">
+              <p v-for="item in detail.Component?detail.Component:[]" :key="item.TaskId"
+                 show-overflow-tooltip>
+                {{ item.EquipLocalName || item.EquipName }}
+              </p>
+            </div>
+            <div v-else>--</div>
+          </el-form-item>
+          <el-form-item label="全景图:" v-show="panoramaList && panoramaList.length">
+            <div class="img-item" @click="dialogVisible = true" v-for="item in panoramaList"
+                 :key="item.Key">
+              4 <img :src="`/image-service/common/image_get?systemId=dataPlatform&key=${item.Key}`"
+                     style="width:100%;" :alt="item.Name">
+            </div>
+          </el-form-item>
+          <el-form-item label="资产照片:" v-show="imgList && imgList.length">
+            <div class="img-item">
+              <div class="demo-image__preview">
+                <el-image style="width:100%;" v-for="item in imgList"
+                          :key="item.Key" :title="item.Name"
+                          @click="nowUrl = item.Key"
+                          :src="`/image-service/common/image_get?systemId=dataPlatform&key=${item.Key}&width=400`"
+                          :preview-src-list="srcList">
+                </el-image>
+              </div>
+            </div>
+          </el-form-item>
+          <el-form-item label="现场视频:" v-show="videoList && videoList.length">
+            <video controls style="width:100%;" v-for="item in videoList" :key="item.Key"
+                   :title="item.Name">
+              <source :src="`/image-service/common/image_get?systemId=dataPlatform&key=${item.Key}`"
+                      type="video/mp4">
+              您的浏览器不支持 HTML5 video ,暂无法播放。
+            </video>
+          </el-form-item>
+          <el-form-item label="备注信息:">{{ detail.Note || '--' }}</el-form-item>
+        </el-form>
+      </div>
+      <div class="operation-detail detail-item" v-if="detail.TaskState === '未找到'">
+        <el-form>
+          <el-form-item label="操作信息:"></el-form-item>
+          <div class="block">
+            <el-timeline>
+              <el-timeline-item
+                  placement="top"
+                  v-for="(item,index) in arr"
+                  :key="index"
+                  :timestamp="item.timestamp"
+              >
+                <el-card>
+                  <small>{{item.content}}</small>
+                  <p>{{item.title}}</p>
+                  <img
+                      v-for="isImg in item.imgs"
+                      :key="isImg.Key"
+                      :src="`/image-service/common/image_get?systemId=dataPlatform&key=${isImg.Key}`">
+
+                  <video controls style="width:100%;" v-for="v in videoList" :key="index"
+                         :title="v.Name">
+                    <source
+                        :src="`/image-service/common/image_get?systemId=dataPlatform&key=${v.Key}`"
+                        type="video/mp4">
+                    您的浏览器不支持 HTML5 video ,暂无法播放。
+                  </video>
+                </el-card>
+              </el-timeline-item>
+            </el-timeline>
+          </div>
+        </el-form>
+      </div>
+    </el-scrollbar>
+    <el-dialog title="全景图" :visible.sync="dialogVisible" width="70%" append-to-body>
+      一张图
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+  import {mapGetters} from "vuex"
+
+  export default {
+    components: {},
+    created() {
+      let {ConfirmTime, PositivePhotoTime, QrCodeTime, NameplateTime, SidePhotoTime, VideoTime, EquipProblemTime, EquipProblem, TaskPicList} = this.detail;
+      let arr = []
+      QrCodeTime && arr.push({
+        timestamp: QrCodeTime,
+        time: new Date(QrCodeTime).getTime(),
+        content: '黏贴二维码',
+        imgs: TaskPicList.length && TaskPicList.filter(i => i.Name.includes('带二维码的设备近景照片'))
+      })
+      PositivePhotoTime && arr.push({
+        timestamp: PositivePhotoTime,
+        time: new Date(PositivePhotoTime).getTime(),
+        content: '拍摄正面照片',
+        imgs: TaskPicList.length && TaskPicList.filter(i => i.Name.includes('设备正面照片'))
+      })
+      NameplateTime && arr.push({
+        timestamp: NameplateTime,
+        time: new Date(NameplateTime).getTime(),
+        content: '拍摄铭牌照片',
+        imgs: TaskPicList.length && TaskPicList.filter(i => i.Name.includes('铭牌照片'))
+      })
+      SidePhotoTime && arr.push({
+        timestamp: SidePhotoTime,
+        time: new Date(SidePhotoTime).getTime(),
+        content: '拍摄侧面照片',
+        imgs: TaskPicList.length && TaskPicList.filter(i => i.Name.includes('设备左侧照片' || '设备右侧照片'))
+      })
+      VideoTime && arr.push({
+        timestamp: VideoTime,
+        time: new Date(VideoTime).getTime(),
+        content: '拍摄30s视频',
+        videoList: TaskPicList.length && TaskPicList.filter(i => i.Name.includes('视频资料'))
+      })
+      EquipProblemTime && arr.push({
+        timestamp: EquipProblemTime,
+        time: new Date(EquipProblemTime).getTime(),
+        content: '记录设备问题',
+        title: EquipProblem
+      })
+      ConfirmTime && arr.push({
+        timestamp: ConfirmTime,
+        time: new Date(ConfirmTime).getTime(),
+        content: '确认信息',
+        title: '已确认的设备信息'
+      })
+      this.arr = arr.map(i => ({...i})).sort((a, b) => b.time - a.time)
+    },
+    computed: {
+      ...mapGetters("layout", ["projectId"]),
+      notFoundList() {
+        if (this.detail && this.detail.Component && this.detail.Component.length) {//是否存在部件
+          let index = this.detail.Component.findIndex(item => {
+            return item.TaskState == -1
+          })
+          if (index != -1) {//部件中存在未找到的对象
+            this.detail.isComponent = true
+            return this.detail.Component[index].TaskPicList ? this.detail.Component[index].TaskPicList : []
+          } else {//部件全部找到
+            this.detail.isComponent = false
+            return this.detail.TaskPicList ? this.detail.TaskPicList : []
+          }
+        } else {
+          this.detail.isComponent = false
+          if (this.detail && this.detail.TaskPicList && this.detail.TaskPicList.length) {
+            return this.detail.TaskPicList
+          } else {
+            return []
+          }
+        }
+      },
+      panoramaList() {
+        if (this.notFoundList && this.notFoundList.length) {
+          return this.notFoundList.filter(item => {
+            return item.Type == 'panorama'
+          })
+        } else {
+          return []
+        }
+      },
+      imgList() {
+        if (this.notFoundList && this.notFoundList.length) {
+          return this.notFoundList.filter(item => {
+            return item.Type == 'image'
+          })
+        } else {
+          return []
+        }
+      },
+      videoList() {
+        if (this.notFoundList && this.notFoundList.length) {
+          return this.notFoundList.filter(item => {
+            return item.Type == 'video'
+          })
+        } else {
+          return []
+        }
+      },
+      srcList() {
+        let nowIndex = this.imgList.findIndex(item => {
+          return item.Key == this.nowUrl
+        })
+        let index = nowIndex >= 1 ? nowIndex : 0;
+        let tempArr1 = this.imgList.slice(0, index);
+        let tempArr2 = this.imgList.slice(index, this.imgList.length);
+
+        let res = tempArr2.concat(tempArr1).map(item => {
+          return `/image-service/common/image_get?systemId=dataPlatform&key=${item.Key}`
+        });
+        return res;
+      }
+    },
+    props: {
+      detail: Object
+    },
+    data() {
+      return {
+        dialogVisible: false,//全景图弹出框
+        nowUrl: '',//当前正在显示的图
+        arr: [],
+      };
+    },
+    methods: {},
+    watch: {
+      'detail.TaskId'() {
+        console.log(this.detail)
+      }
+    }
+  };
+</script>
+<style lang="less" scoped>
+  .detail-box {
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+
+    /deep/ .el-scrollbar__wrap {
+      overflow-x: hidden;
+    }
+
+    /deep/ .el-icon-circle-close {
+      color: white;
+    }
+
+    /deep/ .el-form-item__content {
+      text-overflow: ellipsis;
+      overflow: hidden;
+    }
+
+    .detail-item {
+      width: calc(100% - 30px);
+      margin: 15px 15px 10px;
+      padding: 10px;
+      box-sizing: border-box;
+      border-left: 1px solid #eee;
+      box-shadow: 0px 1px 5px 0px rgba(59, 66, 84, 0.15);
+    }
+
+    .img-item {
+      position: relative;
+      cursor: pointer;
+    }
+  }
+</style>

+ 97 - 0
src/components/data_admin/buildTask/dialog/addTaskDialog.vue

@@ -0,0 +1,97 @@
+<template>
+  <el-dialog :title="title" :visible.sync="addTaskDialog" :before-close="handleClose" width="500px">
+    <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="110px">
+      <el-form-item label="未验证任务" prop="isVerification">
+        <el-switch v-model="ruleForm.isVerification"></el-switch>
+      </el-form-item>
+      <el-form-item label="任务类型" prop="taskType">
+        <div>
+          <el-radio v-model="ruleForm.taskType" label="model">现场验证模型</el-radio>
+        </div>
+        <div>
+          <el-radio v-model="ruleForm.taskType" label="device">现场验证设备台账</el-radio>
+        </div>
+        <div>
+          <el-radio v-model="ruleForm.taskType" label="assets">现场验证资产台账</el-radio>
+        </div>
+      </el-form-item>
+    </el-form>
+    <!-- <el-row>
+      请选择新建现场验证任务的数据源:
+      <el-checkbox v-model="ruleForm.isVerification">只选择未验证的</el-checkbox>
+    </el-row>
+    <el-row style="margin-top:15px;padding-left:15px;">
+      <div><el-radio v-model="ruleForm.taskType" label="model">现场验证模型</el-radio></div>
+      <div><el-radio v-model="ruleForm.taskType" label="device">现场验证设备台账</el-radio></div>
+      <div><el-radio v-model="ruleForm.taskType" label="assets">现场验证资产台账</el-radio></div>
+    </el-row>-->
+    <span slot="footer" class="dialog-footer">
+      <el-button type="primary" @click="$emit('update:addTaskDialog',false)">取 消</el-button>
+      <el-button type="primary" @click="toAddTask()">确 认</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import {} from "@/api/scan/request";
+import { mapGetters } from "vuex";
+export default {
+  components: {},
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      title: "添加验证任务",
+      dialogVisible: false,
+      ruleForm: {
+        isVerification: true,
+        taskType: ""
+      },
+      rules: {
+        taskType: [
+          { required: true, message: "请选择任务类型", trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {},
+  props: {
+    addTaskDialog: Boolean, //是否显示弹窗
+    newTaskTypes: Array
+  },
+  methods: {
+    toAddTask() {
+      this.$refs.ruleForm.validate(valid => {
+        if (valid) {
+          this.ruleForm.newTaskTypes = this.newTaskTypes;
+          if (this.ruleForm.taskType == "model") {
+            this.$router.push({
+              path: "/floor/addModelTask",
+              query: this.ruleForm
+            });
+          } else if (this.ruleForm.taskType == "device") {
+            this.$router.push({
+              path: "/floor/addDeviceTask",
+              query: this.ruleForm
+            });
+          } else if (this.ruleForm.taskType == "assets") {
+            this.$router.push({
+              path: "/floor/addAssetsTask",
+              query: this.ruleForm
+            });
+          }
+        } else {
+          console.log("error submit!!");
+          return false;
+        }
+      });
+    },
+    handleClose() {
+      this.$emit("update:addTaskDialog", this.dialogVisible);
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+</style>

+ 253 - 0
src/components/data_admin/buildTask/dialog/modelTaskDialog.vue

@@ -0,0 +1,253 @@
+<template>
+  <el-dialog :title="title" :visible.sync="dialogVisible" :before-close="handleClose" width="900px" id="addEqDialog">
+    <div class="table-box">
+      <el-table :data="tableData" style="width: 100%" height="350" v-loading="loading" :header-cell-style="headerStyle" ref="multipleTable"
+        @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55"></el-table-column>
+        <el-table-column type="expand">
+          <template slot-scope="props">
+            <p v-if="props.row.ComponentCount && props.row.ComponentCount.length" style="color:#99a9bf;line-height:32px;font-size:14px;">包含的部件:</p>
+            <el-form label-position="left" label-width="auto" inline class="demo-table-expand"
+              v-if="props.row.ComponentCount && props.row.ComponentCount.length">
+              <el-form-item v-for="item in props.row.ComponentCount?props.row.ComponentCount:[]" :key="item.code" :label="`${item.name}:`">
+                <span>{{ item.count }}</span>
+              </el-form-item>
+            </el-form>
+          </template>
+        </el-table-column>
+        <el-table-column prop="FolderName" label="所属模型文件夹" width="110" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="FileName" label="模型文件名" width="80" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="EquipLocalName" label="设备本地名称" show-overflow-tooltip width="100"></el-table-column>
+        <el-table-column prop="EquipLocalID" label="设备本地编码" show-overflow-tooltip width="100"></el-table-column>
+        <el-table-column prop="EquipCategory.EquipName" label="设备类" show-overflow-tooltip width="120"></el-table-column>
+        <el-table-column prop="BimId" label="BIM Id" show-overflow-tooltip width="80"></el-table-column>
+        <el-table-column prop="type" label="现场验证操作规定" width="150">
+          <template slot-scope="scope">
+            <el-select style="width:100px;" v-model="scope.row.SchemeId" placeholder="请选择">
+              <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
+            </el-select>
+          </template>
+        </el-table-column>
+        <template slot="empty">
+          <div style="height: 60%;transform: translateY(50%);">
+            <i class="icon-wushuju iconfont"></i>
+            数据暂无
+          </div>
+        </template>
+      </el-table>
+      <!-- 分页 -->
+      <el-pagination class="fr" v-show="tableData && tableData.length" @size-change="handleSizeChange" @current-change="handleCurrentChange"
+        :current-page="page.pageNumber" :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper"
+        :total="page.total"></el-pagination>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button size="small" @click="$emit('update:dialogVisible',false)">返回重选</el-button>
+      <el-button size="small" type="primary" @click="savaRelation">确认创建</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { queryEquip } from "@/api/scan/request"
+import { createModelTask, queryModelDiglog } from "@/api/data_admin/buildTaskApi"
+import { mapGetters } from "vuex"
+export default {
+  components: {
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      title: "确认创建任务",
+      options: [{//方案
+        value: '1',
+        label: '标准'
+      }],
+      tableData: [],
+      loading: false,
+      selections: [], // 选中项
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      } // 列表样式
+    };
+  },
+  props: {
+    dialogVisible: Boolean,//是否显示弹窗
+    params: Object, //模型和设备的信息
+    newTaskTypes: Array
+  },
+  created() {
+
+  },
+  methods: {
+    getTableData() {
+      let params = {
+        Cascade: [
+          {
+            Name: "equipCategory",
+            Projection: ["EquipCode", "EquipName"]
+          },
+          {
+            Name: "component",
+            Cascade: [{ Name: "equipCategory" }]
+          },
+          {
+            Name: "building",
+            Projection: ["BuildLocalName", "BuildName", "BuildID"]
+          },
+          {
+            Name: "floor",
+            Projection: ["FloorLocalName", "FloorName", "FloorID"]
+          }
+        ],
+        Filters: `ProjectId='${this.projectId}'`,
+        Orders: "CreateTime desc, EquipID asc",
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize
+      }
+
+      if (this.params.isVerification) {
+        params.Filters += `;TaskState isNull`
+      }
+
+      if (this.params.device) {
+        params.Filters += `;Category='${this.params.category}'`
+      }
+
+      if (this.params.spaceList && this.params.spaceList.length) {
+        //通过平面图区域查询
+        params.IdList = this.params.spaceList
+        queryModelDiglog(params, res => {
+          this.dataFormatter(res)
+        })
+      } else {
+        params.Filters += `;ModelId='${this.params.CurrentModelId}'`
+        queryEquip(params, res => {
+          this.dataFormatter(res)
+        })
+      }
+
+    },
+    // 表格数据格式化
+    dataFormatter(res) {
+      this.tableData = res.Content.map(item => {
+        if (item.Component && item.Component.length) {
+          item.ComponentCount = []
+          item.Component.map(parts => {
+            if (parts.EquipCategory && parts.EquipCategory.EquipCode && parts.EquipCategory.EquipName) {
+              let index = item.ComponentCount.findIndex(c => { return c.code == parts.EquipCategory.EquipCode })
+              if (index != -1) {
+                item.ComponentCount[index].count++
+              } else {
+                item.ComponentCount.push({
+                  name: parts.EquipCategory.EquipName,
+                  code: parts.EquipCategory.EquipCode,
+                  count: 1
+                })
+              }
+            }
+          })
+        }
+        item.FolderName = this.params.modelFolderName
+        item.FolderId = this.params.modelFolderId
+        item.FileName = this.params.modelFileName
+        item.FileId = this.params.CurrentModelId
+        item.SchemeId = "1"
+        return item
+      })
+      this.page.total = res.Total
+    },
+    //选中项修改
+    handleSelectionChange(val) {
+      this.selections = val;
+    },
+    savaRelation() {
+      if (this.selections.length) {
+        let list = this.selections.map((item) => {
+          return {
+            EquipId: item.EquipID,
+            FileId: item.FileId,
+            FileName: item.FileName,
+            FolderId: item.FolderId,
+            FolderName: item.FolderName
+          }
+        })
+        let params = {
+          Content: list
+        }
+        createModelTask(params, res => {
+          this.$emit('update:dialogVisible', false)
+          this.$message.success('创建成功!')
+          this.$router.push({ name: 'buildTask', query: { newTaskTypes: this.newTaskTypes } })//跳转回首页
+        })
+      } else {
+        this.$message('请选择要创建的任务!')
+      }
+    },
+    //改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    //改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = 1
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    handleClose() {//关闭弹窗
+      this.$emit('update:dialogVisible', false);
+    }
+  },
+  watch: {
+    dialogVisible(newData, oldData) {
+      if (newData) {
+        this.tableData = []
+        this.page.pageNumber = 1
+        this.getTableData()
+      }
+    }
+  },
+};
+</script>
+<style lang="less" scoped>
+#addEqDialog {
+  .filters {
+    margin-bottom: 10px;
+    /deep/ .el-input__inner {
+      vertical-align: baseline;
+    }
+  }
+  .table-box {
+    height: 370px;
+    .fr {
+      margin-top: 10px;
+    }
+  }
+}
+</style>
+
+<style>
+.demo-table-expand {
+  font-size: 0;
+}
+.demo-table-expand label {
+  width: 90px;
+  color: #99a9bf;
+}
+.demo-table-expand .el-form-item {
+  margin-right: 0;
+  margin-bottom: 0;
+  margin-left: 120px;
+  width: 100%;
+}
+</style>

+ 239 - 0
src/components/data_admin/buildTask/draw/drawModel.vue

@@ -0,0 +1,239 @@
+<template>
+  <div :id="`drawFloor${id}`" class="drawFloor" v-loading="canvasLoading">
+    <canvas :id="`floorCanvas${id}`" :width="cadWidth" :height="cadHeight" ref="canvas" tabindex="0"></canvas>
+    <div class="operate" v-show="showTools">
+      <canvasFun @fit="fit" @savePng="savePng" @saveSvg="saveSvg" @scale="scale" @saveJson="saveJson" :config="config" ref="canvasFun"></canvasFun>
+    </div>
+  </div>
+</template>
+
+<script>
+import { DivideFloorScene, FloorView } from "@saga-web/cad-engine/lib"
+import { SColor, SPoint } from "@sybotan-web/draw/lib";
+import canvasFun from "@/components/business_space/newGraphy/canvasFun"
+import { floorQuery, queryEquip } from "@/api/scan/request";
+export default {
+  components: {
+    canvasFun
+  },
+  data() {
+    return {
+      drawMainScene: null,
+      view: null,
+      dataKey: '',
+      cadWidth: 800,
+      cadHeight: 600,
+      canvasLoading: false,
+      modelId: '',
+      FloorID: '',
+      Outline: [],
+      deviceList: [],
+      buttonContent: "",
+      showTools: false,
+      config: {
+        isEdit: false
+      }
+    };
+  },
+  props: {
+    isEdit: {
+      default: false
+    },
+    id: {
+      default: 0
+    },
+    dialog: {
+      default: false
+    },
+    isLight:{
+      type: Boolean,
+      default: false
+    },
+    CurrentModelId: String
+  },
+  created() { },
+  mounted() {
+    this.cadWidth = document.getElementById(`drawFloor${this.id}`).offsetWidth;
+    this.cadHeight = document.getElementById(`drawFloor${this.id}`).offsetHeight;
+  },
+  methods: {
+    initGraphy(ModelId) {
+      this.modelId = ModelId;
+      this.clearGraphy()
+      this.drawMainScene = new DivideFloorScene();
+      this.canvasLoading = true;
+      this.drawMainScene.getFloorData('/modelapi/base-graph/query', { ModelId: ModelId }).then(res => {
+        // console.log(this)
+        this.getGraphtSuc(res);
+      })
+    },
+    getFloorData() {
+      let pa = {
+        Filters: `FloorID='${this.FloorID}'`
+      }
+      floorQuery(pa, res => {
+        let newArr = res.Content[0].Outline.map(t => {
+          return new SPoint(t.X, t.Y);
+        })
+        this.drawMainScene.addSceneMark(newArr)
+      })
+    },
+    getSelectedSpaces() {//获取选中区域
+      if (this.view && this.view.scene) {
+        let list = this.view.scene.getSelectedSpaces();
+        if (list.length) {
+          return list
+        } else {
+          return []
+        }
+      } else {
+        return []
+      }
+    },
+    // 清空平面图
+    clearGraphy() {
+      if (this.view) {
+        this.view.scene = null;
+        return
+      }
+      let id = `floorCanvas${this.id}`;
+      this.view = new FloorView(id)
+    },
+    canvasClick(item, eventObj) {//点击平面图事件 
+      this.$emit("changeButtonContent",this.drawMainScene.getSelectedSpaces().length?"通过模型空间创建":"通过模型创建") 
+    },
+    getGraphtSuc(res) {
+      this.showTools = true;
+      this.canvasLoading = false;
+      if (res.Result == 'failure') {
+        this.showTools = false;
+        this.$message.warning(res.Message);
+        return;
+      }
+      this.view.scene = this.drawMainScene;
+      if(this.isLight){//高亮显示未验证的区块
+        this.deviceList = []
+        this.highLightPoint()
+      }
+      this.view.fitSceneToView();
+      this.drawMainScene.click(this, this.canvasClick);
+      if (this.$refs.canvasFun) {
+        this.view.minScale = this.view.scale;
+        this.$refs.canvasFun.everyScale = this.view.scale;
+      }
+    },
+    //高亮未完成验证的区块
+    async highLightPoint() {
+      await this.getUnverificationDevice()
+      this.view.scene.spaceList.forEach(item => {
+        for(let deviceItem of this.deviceList) {
+          if(deviceItem.LocationJson && item.contains(deviceItem.LocationJson.X, -deviceItem.LocationJson.Y)){//注:坐标体系不同,Y坐标取反
+            item.highLightFlag = true
+            break
+          }
+        }
+      })
+    },
+    //获取模型下未验证的设备
+    getUnverificationDevice(pageNum) {
+      return new Promise((resolve) => {
+        pageNum = pageNum ? pageNum : 1
+        let params = {
+          Filters: `TaskState isNull;ModelId='${this.CurrentModelId}'`,
+          Orders: "CreateTime desc, EquipID asc",
+          Projection: ["EquipID", "BIMID", "BIMLocation", "LocationJson"],
+          PageNumber: pageNum,
+          PageSize: 1000
+        }
+        queryEquip(params, res => {
+          this.deviceList = res.Content
+          resolve();
+        });
+      });
+      // queryEquip(params, res => {
+      //   this.deviceList = this.deviceList.concat(res.Content)
+      //   if (res.Total / (res.PageSize * res.PageNumber) > 1) {
+      //     this.getUnverificationDevice(res.PageNumber + 1)
+      //   } else { }
+      // });
+    },
+    // canvas 获取焦点
+    focus() {
+      document.getElementById(`floorCanvas${this.id}`).focus()
+    },
+    // 工具栏操作
+    // 适配底图到窗口
+    fit() {
+      this.view.fitSceneToView()
+    },
+    // 保存为png
+    savePng() {
+      this.view.saveImage(`${this.floor}.png`, 'png');
+    },
+    // 保存为svg
+    saveSvg() {
+      this.view.saveSceneSvg(`${this.floor}.svg`, 6400, 4800);
+    },
+    saveJson() {
+      this.view.saveFloorJson(`${this.floor}.json`)
+    },
+    // 缩放
+    scale(val) {
+      if (!this.view) {
+        return;
+      }
+      let scale = this.view.scale;
+      this.view.scaleByPoint(val / scale, this.cadWidth / 2, this.cadHeight / 2);
+    }
+  },
+  watch: {
+    isLight: {
+      handler(newValue, oldValue) {
+        if(newValue){//高亮显示未验证的区块
+          this.deviceList = []
+          this.highLightPoint()
+        } else {
+          this.view.scene.spaceList.forEach(item => {
+            item.highLightFlag = false
+          })
+        }
+      }
+    },
+    CurrentModelId: {
+      handler(newName, oldName) {
+        if (newName) {
+          this.initGraphy(newName)
+        }
+      },
+      immediate: true,
+    },
+    "view.scale": {
+      handler(n) {
+        if (this.$refs.canvasFun) {
+          let s = n * 10 / this.view.minScale
+          this.$refs.canvasFun.sliderVal = s > 1000 ? 1000 : s;
+        }
+      }
+    },
+    "isEdit": {
+      handler(n) {
+        this.config.isEdit = n;
+      }
+    }
+  }
+};
+</script>
+<style scoped lang="less">
+.drawFloor {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  .operate {
+    position: absolute;
+    left: 50%;
+    bottom: 20px;
+    transform: translateX(-50%);
+    z-index: 99;
+  }
+}
+</style>

+ 70 - 0
src/components/data_admin/buildTask/lib/assetsCascader.vue

@@ -0,0 +1,70 @@
+<template>
+  <div id="cascaderMap">
+    <span class="buildFloor" style="margin-right: 12px;">设备族</span>
+    <el-select v-model="value" placeholder="请选择" clearable filterable :style="isWidth ? '' : 'width:160px;'" size="small" @change="changeVal">
+      <el-option  v-for="item in options" :key="item.Code" :label="item.Name" :value="item.Code"></el-option>
+    </el-select>
+  </div>
+</template>
+<script>
+import { mapGetters } from 'vuex';
+import { queryAssetsFamily } from "@/api/data_admin/buildTaskApi"
+export default {
+  props: {
+    isWidth: {
+      type: Boolean,
+      default: true
+    }
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      value: "",
+      options: []
+    };
+  },
+  created() {
+    this.getData();
+  },
+  watch: {
+    projectId() {
+      this.value = '';
+      this.getData();
+    }
+  },
+  methods: {
+    setValue(val) {
+      this.value = val
+    },
+    //修改val
+    changeVal(val) {
+      let value = {}
+      this.options.map(item => {
+        if (item.Code == val) {
+          value = item
+        }
+      })
+      this.value = val
+      this.$emit("change", value)
+    },
+    //获取当前项目下的资产任务-设备族
+    getData() {
+      queryAssetsFamily('', res => {
+        this.options = res.Content
+      })
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#cascaderMap {
+  float: left;
+  margin-left: 10px;
+  .buildFloor {
+    color: #999999;
+    font-size: 14px;
+  }
+}
+</style>

+ 70 - 0
src/components/data_admin/buildTask/lib/deviceCascader.vue

@@ -0,0 +1,70 @@
+<template>
+  <div id="cascaderMap">
+    <span class="buildFloor" style="margin-right: 12px;">设备类别</span>
+    <el-select v-model="value" placeholder="请选择" clearable filterable :style="isWidth ? '' : 'width:160px;'" size="small" @change="changeVal">
+      <el-option  v-for="item in options" :key="item.Code" :label="item.Name" :value="item.Code"></el-option>
+    </el-select>
+  </div>
+</template>
+<script>
+import { mapGetters } from 'vuex';
+import { queryDeviceCategory } from "@/api/data_admin/buildTaskApi"
+export default {
+  props: {
+    isWidth: {
+      type: Boolean,
+      default: true
+    }
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      value: "",
+      options: []
+    };
+  },
+  created() {
+    this.getData();
+  },
+  watch: {
+    projectId() {
+      this.value = '';
+      this.getData();
+    }
+  },
+  methods: {
+    setValue(val) {
+      this.value = val
+    },
+    //修改val
+    changeVal(val) {
+      let value = {}
+      this.options.map(item => {
+        if (item.Code == val) {
+          value = item
+        }
+      })
+      this.value = val
+      this.$emit("change", value)
+    },
+    //获取当前项目下的设备任务-设备类型
+    getData() {
+      queryDeviceCategory('', res => {
+        this.options = res.Content
+      })
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#cascaderMap {
+  float: left;
+  margin-left: 10px;
+  .buildFloor {
+    color: #999999;
+    font-size: 14px;
+  }
+}
+</style>

+ 70 - 0
src/components/data_admin/buildTask/lib/modelCascader.vue

@@ -0,0 +1,70 @@
+<template>
+  <div id="cascaderMap">
+    <span class="buildFloor" style="margin-right: 12px;">设备类别</span>
+    <el-select v-model="value" placeholder="请选择" clearable filterable :style="isWidth ? '' : 'width:160px;'" size="small" @change="changeVal">
+      <el-option  v-for="item in options" :key="item.Code" :label="item.Name" :value="item.Code"></el-option>
+    </el-select>
+  </div>
+</template>
+<script>
+import { mapGetters } from 'vuex';
+import { queryModelCategory } from "@/api/data_admin/buildTaskApi"
+export default {
+  props: {
+    isWidth: {
+      type: Boolean,
+      default: true
+    }
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      value: "",
+      options: []
+    };
+  },
+  created() {
+    this.getData();
+  },
+  watch: {
+    projectId() {
+      this.value = '';
+      this.getData();
+    }
+  },
+  methods: {
+    setValue(val) {
+      this.value = val
+    },
+    //修改val
+    changeVal(val) {
+      let value = {}
+      this.options.map(item => {
+        if (item.Code == val) {
+          value = item
+        }
+      })
+      this.value = val
+      this.$emit("change", value)
+    },
+    //获取当前项目下的模型任务-设备类型
+    getData() {
+      queryModelCategory('', res => {
+        this.options = res.Content
+      })
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#cascaderMap {
+  float: left;
+  margin-left: 10px;
+  .buildFloor {
+    color: #999999;
+    font-size: 14px;
+  }
+}
+</style>

+ 81 - 0
src/components/data_admin/buildTask/lib/modelFile.vue

@@ -0,0 +1,81 @@
+<template>
+    <div id="modelFile">
+        <span class="modelFile" style="margin-right: 12px;">模型文件</span>
+        <el-cascader :options="options" :props="props" :show-all-levels="false" @change="handleChange" style="width:160px;"
+        clearable placeholder="请选择模型文件" v-model="casVal"></el-cascader>
+    </div>
+</template>
+<script>
+import tools from "@/utils/scan/tools"
+import { queryModelFile } from "@/api/data_admin/buildTaskApi"
+import { mapGetters, mapActions } from "vuex"
+
+export default {
+  computed: {
+    ...mapGetters("layout", [ "projectId", "secret", "userId" ])
+  },
+  data() {
+    return {
+      casVal: [],
+      options: [],
+      modelIdToFloorId: {},
+      props: {
+        value: "FileId",
+        label: "FileName",
+        children: "FileList"
+      },
+    };
+  },
+  created() {
+    this.init()
+  },
+  watch: {
+    projectId() {
+      this.casVal =[]
+      this.options = []
+      this.init()
+    }
+  },
+  methods: {
+    //设置默认选项
+    setValue(val) {
+        if (val && val.length) {
+          this.casVal = val
+        }
+    },
+    //获取数据
+    init() {
+      this.getDirectory()
+    },
+    // 获取文件夹
+    getDirectory() {
+      queryModelFile("", res => {
+        this.options = res.Content.map(item => {
+          item.FileId = item.FolderId
+          item.FileName = item.FolderName
+          return item
+        })
+      });
+    },
+    //改变item
+    handleChange(value) {
+      this.$emit("change", value)
+    }
+  }
+};
+</script>
+<style lang="less">
+    .el-cascader .el-input .el-input__inner {
+        vertical-align: bottom;
+    }
+</style>
+<style lang="less" scoped>
+    #modelFile {
+        margin-left: 10px;
+        float: left;
+        .modelFile {
+            color: #999999;
+            font-size: 14px;
+        }
+    }
+</style>

+ 53 - 0
src/components/data_admin/buildTask/lib/taskState.vue

@@ -0,0 +1,53 @@
+<template>
+  <div id="cascaderMap">
+    <span class="task-state" style="margin-right: 12px;">任务执行情况</span>
+    <el-select v-model="taskState" placeholder="请选择" filterable style="width:120px;" size="small" @change="changeState">
+      <el-option  v-for="item in taskStateList" :key="item.code" :label="item.label" :value="item.value"></el-option>
+    </el-select>
+  </div>
+</template>
+<script>
+import { mapGetters } from 'vuex';
+export default {
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      taskStateList: [{
+				value: '',
+				label: '全部'
+			}, {
+				value: 1,
+				label: '待验证'
+			}, {
+				value: 0,
+				label: '已完成'
+			}, {
+				value: -1,
+				label: '未找到'
+			}],
+			taskState: '',//任务执行情况
+    };
+  },
+  methods: {
+    setValue(val) {
+      this.taskState = val
+    },
+    //修改val
+    changeState(val) {
+      this.$emit("change", val)
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#cascaderMap {
+  float: left;
+  margin-left: 10px;
+  .task-state {
+    color: #999999;
+    font-size: 14px;
+  }
+}
+</style>

+ 222 - 0
src/components/data_admin/buildTask/table/assetsTable.vue

@@ -0,0 +1,222 @@
+<template>
+  <div class="table-container">
+    <div class="table-list" :style="tableData && tableData.length?'height:calc(100% - 50px);':'height:100%;'">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column label="所属建筑楼层" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.Building?scope.row.Building.BuildLocalName?scope.row.Building.BuildLocalName:'':''}} -
+              {{scope.row.Floor?scope.row.Floor.FloorLocalName?scope.row.Floor.FloorLocalName:'':''}}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="EquipLocalID" :label="`${inSpaceType}本地名称`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="EquipLocalName" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="EquipFamily.FamilyName" label="设备族" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="InstallLocation" label="安装位置" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="TaskState" label="任务执行情况" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <i v-if="scope.row.TaskState == '待验证' || scope.row.TaskState == '未找到'" title="查看详情" class="iconfont icon-xiangqing table-button" @click="handleDetail(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '未找到'" title="重新生成任务" class="iconfont icon-Update table-button" @click="handleRegenerate(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '待验证'" title="删除任务" class="iconfont icon-delete table-button" @click="handleDelete(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '未找到'" title="认可此任务执行情况" class="iconfont icon-lijiqueren table-button" @click="handleConfirm(scope.$index, scope.row)"></i>
+          </template>
+        </el-table-column>
+        <template slot="empty">
+          <div style="height: 60%;transform: translateY(50%);">
+            <i class="icon-wushuju iconfont"></i>
+            数据暂无
+          </div>
+        </template>
+      </el-table>
+    </div>
+    <el-pagination class="right" v-show="tableData && tableData.length" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page.pageNumber"
+     :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="page.total">
+    </el-pagination>
+    <el-drawer title="任务详情" :visible.sync="drawer" direction="rtl" size="600px">
+      <assets-detail :detail="detailAssets"></assets-detail>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import { queryAssetsTask, deleteAssetsTask, createAssetsTask, updateAssetsTask } from "@/api/data_admin/buildTaskApi"
+import tools from "@/utils/tools"
+import { mapGetters } from "vuex"
+import assetsDetail from '../detail/assetsDetail'
+export default {
+  components: {
+    assetsDetail
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId", "userInfo"])
+  },
+  props: {
+    paramsData: Object,
+  },
+  data() {
+    return {
+      inSpaceType: '资产',
+      loading: false, // loading
+      drawer: false, // 详情侧弹窗
+      detailAssets: {},
+      tableData: [], //列表数据
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      taskStateMap: {
+        '-1': '未找到',
+        '0': '已完成',
+        '1': '待验证'
+      },
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      }, // 列表样式
+    };
+  },
+  methods: {
+    // 获取列表数据
+    getTableData() {
+      let params = {
+        Filters: `ProjectId='${this.projectId}'`,
+        Cascade: [
+          {
+            Name: 'equipFamily'
+          }, {
+            Name: 'scanScheme'
+          }, {
+            Name: 'building',
+          }, {
+            Name: 'floor',
+          }
+        ],
+        Orders: "CreateTime desc, TaskId asc",
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize
+      }
+      if (this.paramsData.buildfloor[0] == "noKnow") {
+        params.Filters += `;BuildingId isNull`
+      } else if (this.paramsData.buildfloor[0] && this.paramsData.buildfloor[0] != "all") {
+        params.Filters += `;BuildingId='${this.paramsData.buildfloor[0]}'`
+        if (this.paramsData.buildfloor[1] == "noKnow") {
+          params.Filters += `;FloorId isNull`
+        } else if (this.paramsData.buildfloor[1] && this.paramsData.buildfloor[1] != "all") {
+          params.Filters += `;FloorId='${this.paramsData.buildfloor[1]}'`
+        }
+      }
+      if(this.paramsData.taskState !== ''){
+        params.Filters += `;TaskState=${this.paramsData.taskState}`
+      }
+      if(this.paramsData.family){
+        params.Filters += `;Category='${this.paramsData.family}'`
+      }
+      queryAssetsTask(params, res => {
+        this.page.total = res.Total;
+        this.tableData = res.Content.map(item => {
+          item.TaskState = this.taskStateMap[item.TaskState]
+          return item
+        })
+      })
+    },
+    // 删除关系
+    handleDelete(index, row) {
+      this.$confirm("确认删除该任务?", "提示", {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        let params = [{TaskId: row.TaskId}]
+        deleteAssetsTask(params, res => {
+          this.$message.success('删除成功')
+          this.getTableData()
+        })
+      }).catch(() => {
+        this.$message("取消删除")
+      })
+    },
+    //重新生成任务
+    handleRegenerate(index, row){
+      let params = {
+        Content: [{
+          EquipId: row.EquipId,
+          TaskState: -1
+        }]
+      }
+      createAssetsTask(params, res => {
+        this.$message.success('重新生成任务成功!')
+        this.getTableData()
+      })
+    },
+    //认可此任务执行情况
+    handleConfirm(index, row){
+      let params = {
+        Content: [{
+          ConfirmingPersonId: this.userInfo.userId,
+          ConfirmingPersonName: this.userInfo.userName,
+          TaskId: row.TaskId,
+          TaskState: 0
+        }]
+      }
+      updateAssetsTask(params, res => {
+        this.$message.success('更新成功!')
+        this.getTableData()
+      })
+    },
+    //查看任务详情
+    handleDetail(index, row) {
+      this.drawer = true
+      this.detailAssets = row
+    },
+    // 改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageNumber = 1
+      this.page.pageSize = pageSize;
+      this.getTableData()
+    },
+    // 改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData()
+    },
+    projectId() {
+      this.page.pageNumber = 1
+      this.getTableData()
+    }
+  },
+  watch: {
+    paramsData: {
+      handler(newName, oldName) {
+        if(!tools.isSimilarly(newName, oldName)){
+          this.page.pageNumber = 1
+          this.getTableData()
+        }
+      },
+      immediate: true,
+      deep: true
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+/deep/ .el-drawer__body {
+  height: calc(100% - 80px);
+  border-top: 1px solid #c9c9c9;
+}
+/deep/ .el-drawer__header {
+  margin-bottom: 12px;
+}
+.table-container {
+  height: 100%;
+  background: #fff;
+  .table-button{
+    cursor: pointer;
+    margin-right: 15px;
+  }
+}
+</style>

+ 250 - 0
src/components/data_admin/buildTask/table/deviceTable.vue

@@ -0,0 +1,250 @@
+<template>
+  <div class="table-container">
+    <div class="table-list" :style="tableData && tableData.length?'height:calc(100% - 50px);':'height:100%;'">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column label="所属建筑楼层" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.Building?scope.row.Building.BuildLocalName?scope.row.Building.BuildLocalName:'':''}} -
+              {{scope.row.Floor?scope.row.Floor.FloorLocalName?scope.row.Floor.FloorLocalName:'':''}}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column :label="`${inSpaceType}本地名称`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.EquipLocalName}}
+              <el-badge v-if="scope.row.Equipment?scope.row.Equipment.Component?scope.row.Equipment.Component.length:false:false" 
+                :value="scope.row.Equipment?scope.row.Equipment.Component?scope.row.Equipment.Component.length:0:0" class="item" type="warning">
+              </el-badge>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="EquipLocalID" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="EquipCategory.EquipName" :label="`${inSpaceType}类型`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="InstallLocation" label="安装位置" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="TaskState" label="任务执行情况" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <i v-if="scope.row.TaskState == '待验证' || scope.row.TaskState == '未找到'" title="查看详情" class="iconfont icon-xiangqing table-button" @click="handleDetail(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '未找到'" title="重新生成任务" class="iconfont icon-Update table-button" @click="handleRegenerate(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '待验证'" title="删除任务" class="iconfont icon-delete table-button" @click="handleDelete(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '未找到'" title="认可此任务执行情况" class="iconfont icon-lijiqueren table-button" @click="handleConfirm(scope.$index, scope.row)"></i>
+          </template>
+        </el-table-column>
+        <template slot="empty">
+          <div style="height: 60%;transform: translateY(50%);">
+            <i class="icon-wushuju iconfont"></i>
+            数据暂无
+          </div>
+        </template>
+      </el-table>
+    </div>
+    <el-pagination class="right" v-show="tableData && tableData.length" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page.pageNumber"
+     :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="page.total">
+    </el-pagination>
+    <el-drawer title="任务详情" :visible.sync="drawer" direction="rtl" size="600px">
+      <device-detail :detail="detailDevice"></device-detail>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import { queryDeviceTask, deleteDeviceTask, createDeviceTask, updateDeviceTask } from "@/api/data_admin/buildTaskApi"
+import tools from "@/utils/tools"
+import { mapGetters } from "vuex"
+import deviceDetail from '../detail/deviceDetail'
+export default {
+  components: {
+    deviceDetail
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId", "userInfo"])
+  },
+  props: {
+    paramsData: Object,
+  },
+  data() {
+    return {
+      inSpaceType: '设备',
+      loading: false, // loading
+      drawer: false, // 详情侧弹窗
+      detailDevice: {},
+      tableData: [], //列表数据
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      taskStateMap: {
+        '-1': '未找到',
+        '0': '已完成',
+        '1': '待验证'
+      },
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      }, // 列表样式
+    };
+  },
+  methods: {
+    // 获取列表数据
+    getTableData() {
+      let params = {
+        Filters: `ProjectId='${this.projectId}'`,
+        Cascade: [
+          {
+            Name: 'component'
+          }, {
+            Name: 'scanScheme'
+          }, {
+            Name: 'building',
+          }, {
+            Name: 'floor',
+          }, {
+            Name: 'equipCategory'
+          }
+        ],
+        Orders: "CreateTime desc, TaskId asc",
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize
+      }
+      if (this.paramsData.buildfloor[0] == "noKnow") {
+        params.Filters += `;BuildingId isNull`
+      } else if (this.paramsData.buildfloor[0] && this.paramsData.buildfloor[0] != "all") {
+        params.Filters += `;BuildingId='${this.paramsData.buildfloor[0]}'`
+        if (this.paramsData.buildfloor[1] == "noKnow") {
+          params.Filters += `;FloorId isNull`
+        } else if (this.paramsData.buildfloor[1] && this.paramsData.buildfloor[1] != "all") {
+          params.Filters += `;FloorId='${this.paramsData.buildfloor[1]}'`
+        }
+      }
+      if(this.paramsData.taskState !== ''){
+        params.Filters += `;TaskState=${this.paramsData.taskState}`
+      }
+      if(this.paramsData.deviceCategory){
+        params.Filters += `;Category='${this.paramsData.deviceCategory}'`
+      }
+      queryDeviceTask(params, res => {
+        this.page.total = res.Total;
+        this.tableData = res.Content.map(item => {
+          if(item.Component && item.Component.length){
+            item.ComponentCount = []
+            item.Component.map(parts => {
+              if(parts.EquipCategory && parts.EquipCategory.EquipCode && parts.EquipCategory.EquipName){
+                let index = item.ComponentCount.findIndex(c => {return c.code == parts.EquipCategory.EquipCode})
+                if(index != -1){
+                  item.ComponentCount[index].count++
+                } else {
+                  item.ComponentCount.push({
+                    name: parts.EquipCategory.EquipName,
+                    code: parts.EquipCategory.EquipCode,
+                    count: 1
+                  })
+                }
+              }
+            })
+          }
+          item.TaskState = this.taskStateMap[item.TaskState]
+          return item
+        })
+      })
+    },
+    // 删除关系
+    handleDelete(index, row) {
+      this.$confirm("确认删除该任务?", "提示", {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        let params = [{TaskId: row.TaskId}]
+        deleteDeviceTask(params, res => {
+          this.$message.success('删除成功')
+          this.getTableData()
+        })
+      }).catch(() => {
+        this.$message("取消删除")
+      })
+    },
+    //重新生成任务
+    handleRegenerate(index, row){
+      let params = {
+        Content: [{
+          EquipId: row.EquipId,
+          TaskState: -1
+        }]
+      }
+      createDeviceTask(params, res => {
+        this.$message.success('重新生成任务成功!')
+        this.getTableData()
+      })
+    },
+    //认可此任务执行情况
+    handleConfirm(index, row){
+      let params = {
+        Content: [{
+          ConfirmingPersonId: this.userInfo.userId,
+          ConfirmingPersonName: this.userInfo.userName,
+          TaskId: row.TaskId,
+          TaskState: 0
+        }]
+      }
+      updateDeviceTask(params, res => {
+        this.$message.success('更新成功!')
+        this.getTableData()
+      })
+    },
+    //查看任务详情
+    handleDetail(index, row) {
+      this.drawer = true
+      this.detailDevice = row
+    },
+    // 改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageNumber = 1
+      this.page.pageSize = pageSize;
+      this.getTableData()
+    },
+    // 改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData()
+    }
+  },
+  watch: {
+    paramsData: {
+      handler(newName, oldName) {
+        if(!tools.isSimilarly(newName, oldName)){
+          this.page.pageNumber = 1
+          this.getTableData()
+        }
+      },
+      immediate: true,
+      deep: true
+    },
+    projectId() {
+      this.page.pageNumber = 1
+      this.getTableData()
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+/deep/ .el-drawer__body {
+  height: calc(100% - 80px);
+  border-top: 1px solid #c9c9c9;
+}
+/deep/ .el-drawer__header {
+  margin-bottom: 12px;
+}
+.table-container {
+  height: 100%;
+  background: #fff;
+  .table-button{
+    cursor: pointer;
+    margin-right: 15px;
+  }
+}
+</style>

+ 240 - 0
src/components/data_admin/buildTask/table/modelTable.vue

@@ -0,0 +1,240 @@
+<template>
+  <div class="table-container">
+    <div class="table-list" :style="tableData && tableData.length?'height:calc(100% - 50px);':'height:100%;'">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column prop="FolderName" label="所属模型文件夹" show-overflow-tooltip min-width="80"></el-table-column>
+        <el-table-column prop="FileName" label="模型文件名" show-overflow-tooltip min-width="80"></el-table-column>
+        <el-table-column :label="`${inSpaceType}本地名称`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.EquipLocalName}}
+              <el-badge v-if="scope.row.Equipment?scope.row.Equipment.Component?scope.row.Equipment.Component.length:false:false"
+                :value="scope.row.Equipment?scope.row.Equipment.Component?scope.row.Equipment.Component.length:0:0" class="item" type="warning">
+              </el-badge>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="EquipLocalID" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="EquipCategory.EquipName" :label="`${inSpaceType}类型`" show-overflow-tooltip min-width="80"></el-table-column>
+        <el-table-column prop="BIMID" label="BIM ID" show-overflow-tooltip min-width="220"></el-table-column>
+        <el-table-column prop="TaskState" label="任务执行情况" show-overflow-tooltip min-width="60"></el-table-column>
+        <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <i v-if="scope.row.TaskState == '待验证' || scope.row.TaskState == '未找到'" title="查看详情" class="iconfont icon-xiangqing table-button" @click="handleDetail(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '未找到'" title="重新生成任务" class="iconfont icon-Update table-button" @click="handleRegenerate(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '待验证'" title="删除任务" class="iconfont icon-delete table-button" @click="handleDelete(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '未找到'" title="认可此任务执行情况" class="iconfont icon-lijiqueren table-button" @click="handleConfirm(scope.$index, scope.row)"></i>
+          </template>
+        </el-table-column>
+        <template slot="empty">
+          <div style="height: 60%;transform: translateY(50%);">
+            <i class="icon-wushuju iconfont"></i>
+            数据暂无
+          </div>
+        </template>
+      </el-table>
+    </div>
+    <el-pagination class="right" v-show="tableData && tableData.length" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page.pageNumber"
+     :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="page.total">
+    </el-pagination>
+    <el-drawer title="任务详情" :visible.sync="drawer" direction="rtl" size="600px">
+      <device-detail :detail="detailModel"></device-detail>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import { queryModelTask, deleteModelTask, updateModelTask, createModelTask } from "@/api/data_admin/buildTaskApi"
+import tools from "@/utils/tools"
+import { mapGetters } from "vuex"
+import deviceDetail from '../detail/deviceDetail'
+export default {
+  components: {
+    deviceDetail
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId", "userInfo"])
+  },
+  props: {
+    paramsData: Object,
+  },
+  data() {
+    return {
+      inSpaceType: '设备',
+      loading: false, // loading
+      drawer: false, // 详情侧弹窗
+      detailModel: {},
+      tableData: [], //列表数据
+      taskStateMap: {
+        '-1': '未找到',
+        '0': '已完成',
+        '1': '待验证'
+      },
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      }, // 列表样式
+    };
+  },
+  created() {
+    // this.getTableData()
+  },
+  methods: {
+    // 获取列表数据
+    getTableData() {
+      let params = {
+        Filters: `ProjectId='${this.projectId}'`,
+        Cascade: [
+          {
+            Name: 'component'
+          }, {
+            Name: 'scanScheme'
+          }, {
+            Name: 'equipCategory'
+          }
+        ],
+        Orders: "CreateTime desc, TaskId asc",
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize
+      }
+      if(this.paramsData.taskState !== ''){
+        params.Filters += `;TaskState=${this.paramsData.taskState}`
+      }
+      if(this.paramsData.modelFile){
+        params.Filters += `;FileId='${this.paramsData.modelFile}'`
+      }
+      if(this.paramsData.modelCategory){
+        params.Filters += `;Category='${this.paramsData.modelCategory}'`
+      }
+      queryModelTask(params, res => {
+        this.page.total = res.Total;
+        this.tableData = res.Content.map(item => {
+          if(item.Component && item.Component.length){
+            item.ComponentCount = []
+            item.Component.map(parts => {
+              if(parts.EquipCategory && parts.EquipCategory.EquipCode && parts.EquipCategory.EquipName){
+                let index = item.ComponentCount.findIndex(c => {return c.code == parts.EquipCategory.EquipCode})
+                if(index != -1){
+                  item.ComponentCount[index].count++
+                } else {
+                  item.ComponentCount.push({
+                    name: parts.EquipCategory.EquipName,
+                    code: parts.EquipCategory.EquipCode,
+                    count: 1
+                  })
+                }
+              }
+            })
+          }
+          item.TaskState = this.taskStateMap[item.TaskState]
+          return item
+        })
+      })
+    },
+    // 删除任务
+    handleDelete(index, row) {
+      this.$confirm("确认删除该任务?", "提示", {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        let params = [{TaskId: row.TaskId}]
+        deleteModelTask(params, res => {
+          this.$message.success('删除成功')
+          this.getTableData()
+        })
+      }).catch(() => {
+        this.$message("取消删除")
+      })
+    },
+    //重新生成任务
+    handleRegenerate(index, row){
+      let params = {
+        Content: [{
+          EquipId: row.EquipId,
+          FileId: row.FileId,
+          FileName: row.FileName,
+          FolderId: row.FolderId,
+          FolderName: row.FolderName,
+          TaskState: -1
+        }]
+      }
+      createModelTask(params, res => {
+        this.$message.success('重新生成任务成功!')
+        this.getTableData()
+      })
+    },
+    //认可此任务执行情况
+    handleConfirm(index, row){
+      let params = {
+        Content: [{
+          ConfirmingPersonId: this.userInfo.userId,
+          ConfirmingPersonName: this.userInfo.userName,
+          TaskId: row.TaskId,
+          TaskState: 0
+        }]
+      }
+      updateModelTask(params, res => {
+        this.$message.success('更新成功!')
+        this.getTableData()
+      })
+    },
+    //查看任务详情
+    handleDetail(index, row) {
+      this.drawer = true
+      this.detailModel = row
+    },
+    // 改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageNumber = 1
+      this.page.pageSize = pageSize;
+      this.getTableData()
+    },
+    // 改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData()
+    }
+  },
+  watch: {
+    paramsData: {
+      handler(newName, oldName) {
+        if(!tools.isSimilarly(newName, oldName)){
+          this.page.pageNumber = 1
+          this.getTableData()
+        }
+      },
+      immediate: true,
+      deep: true
+    },
+    projectId() {
+      this.page.pageNumber = 1
+      this.getTableData()
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+/deep/ .el-drawer__body {
+  height: calc(100% - 80px);
+  border-top: 1px solid #c9c9c9;
+}
+/deep/ .el-drawer__header {
+  margin-bottom: 12px;
+}
+.table-container {
+  height: 100%;
+  background: #fff;
+  .table-button{
+    cursor: pointer;
+    margin-right: 15px;
+  }
+}
+</style>

+ 202 - 0
src/components/data_admin/buildTask/table/replaceTable.vue

@@ -0,0 +1,202 @@
+<template>
+  <div class="table-container">
+    <div class="table-list" :style="tableData && tableData.length?'height:calc(100% - 50px);':'height:100%;'">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column label="所属建筑楼层" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.Building?scope.row.Building.BuildLocalName?scope.row.Building.BuildLocalName:'':''}} -
+              {{scope.row.Floor?scope.row.Floor.FloorLocalName?scope.row.Floor.FloorLocalName:'':''}}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="EquipLocalID" :label="`${inSpaceType}本地名称`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="EquipLocalName" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="EquipFamily.FamilyName" label="设备族" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="InstallLocation" label="安装位置" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="TaskType" label="任务执行情况" show-overflow-tooltip min-width="100"></el-table-column>
+        <!-- <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <i v-if="scope.row.TaskState == '待验证' || scope.row.TaskState == '未找到'" title="查看详情" class="iconfont icon-xiangqing table-button" @click="handleDetail(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '未找到'" title="重新生成任务" class="iconfont icon-Update table-button" @click="handleRegenerate(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '待验证'" title="删除任务" class="iconfont icon-delete table-button" @click="handleDelete(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '未找到'" title="认可此任务执行情况" class="iconfont icon-lijiqueren table-button" @click="handleConfirm(scope.$index, scope.row)"></i>
+          </template>
+        </el-table-column> -->
+        <template slot="empty">
+          <div style="height: 60%;transform: translateY(50%);">
+            <i class="icon-wushuju iconfont"></i>
+            数据暂无
+          </div>
+        </template>
+      </el-table>
+    </div>
+    <el-pagination class="right" v-show="tableData && tableData.length" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page.pageNumber"
+     :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="page.total">
+    </el-pagination>
+    <el-drawer title="任务详情" :visible.sync="drawer" direction="rtl" size="600px">
+      <assets-detail :id="detailId"></assets-detail>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import { queryAssetsTask, deleteAssetsTask } from "@/api/data_admin/buildTaskApi"
+import tools from "@/utils/tools"
+import { mapGetters } from "vuex"
+import assetsDetail from '../detail/assetsDetail'
+export default {
+  components: {
+    assetsDetail
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  props: {
+    paramsData: Object,
+  },
+  data() {
+    return {
+      inSpaceType: '资产',
+      loading: false, // loading
+      drawer: false, // 详情侧弹窗
+      detailId: '',
+      tableData: [], //列表数据
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      taskTypeMap: {//待撕码,待换码
+        '-5': '已撕码',
+        '3': '待撕码',
+        '2': '待换码',
+        '0': '正常贴码'
+      },
+      taskStateMap: {
+        '-1': '未找到',
+        '0': '已完成',
+        '1': '待验证'
+      },
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      }, // 列表样式
+    };
+  },
+  created() {
+    this.getTableData()
+  },
+  methods: {
+    // 获取列表数据
+    getTableData() {
+      let params = {
+        Filters: `ProjectId='${this.projectId}';TaskType in ['2']`,
+        Cascade: [
+          {
+            Name: 'equipFamily'
+          }, {
+            Name: 'building',
+          }, {
+            Name: 'floor',
+          }
+        ],
+        Orders: "CreateTime desc, TaskId asc",
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize
+      }
+      // if (this.paramsData.buildfloor[0] == "noKnow") {
+      //   params.Filters += `;BuildingId isNull`
+      // } else if (this.paramsData.buildfloor[0] && this.paramsData.buildfloor[0] != "all") {
+      //   params.Filters += `;BuildingId='${this.paramsData.buildfloor[0]}'`
+      //   if (this.paramsData.buildfloor[1] == "noKnow") {
+      //     params.Filters += `;FloorId isNull`
+      //   } else if (this.paramsData.buildfloor[1] && this.paramsData.buildfloor[1] != "all") {
+      //     params.Filters += `;FloorId='${this.paramsData.buildfloor[1]}'`
+      //   }
+      // }
+      // if(this.paramsData.taskState !== ''){
+      //   params.Filters += `;TaskState=${this.paramsData.taskState}`
+      // }
+      // if(this.paramsData.family){
+      //   params.Filters += `;Family='${this.paramsData.family}'`
+      // }
+      queryAssetsTask(params, res => {
+        this.page.total = res.Total;
+        this.tableData = res.Content.map(item => {
+          item.TaskState = this.taskStateMap[item.TaskState]
+          item.TaskType = this.taskTypeMap[item.TaskType]
+          return item
+        })
+      })
+    },
+    // 删除关系
+    handleDelete(index, row) {
+      this.$confirm("确认删除该任务?", "提示", {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        let params = [{TaskId: row.TaskId}]
+        deleteAssetsTask(params, res => {
+          this.$message.success('删除成功')
+          this.getTableData()
+        })
+      }).catch(() => {
+        this.$message("取消删除")
+      })
+    },
+    //查看任务详情
+    handleDetail() {
+      this.drawer = true
+      this.detailId = row.TaskId
+    },
+    // 改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageNumber = 1
+      this.page.pageSize = pageSize;
+      this.getTableData()
+    },
+    // 改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData()
+    }
+  },
+  watch: {
+    paramsData: {
+      handler(newName, oldName) {
+        if(!tools.isSimilarly(newName, oldName)){
+          this.page.pageNumber = 1
+          this.getTableData()
+        }
+      },
+      immediate: true,
+      deep: true
+    },
+    projectId() {
+      this.page.pageNumber = 1
+      this.getTableData()
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+/deep/ .el-drawer__body {
+  height: calc(100% - 80px);
+  border-top: 1px solid #c9c9c9;
+}
+/deep/ .el-drawer__header {
+  margin-bottom: 12px;
+}
+.table-container {
+  height: 100%;
+  background: #fff;
+  .table-button{
+    cursor: pointer;
+    margin-right: 15px;
+  }
+}
+</style>

+ 202 - 0
src/components/data_admin/buildTask/table/tearTable.vue

@@ -0,0 +1,202 @@
+<template>
+  <div class="table-container">
+    <div class="table-list" :style="tableData && tableData.length?'height:calc(100% - 50px);':'height:100%;'">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column label="所属建筑楼层" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.Building?scope.row.Building.BuildLocalName?scope.row.Building.BuildLocalName:'':''}} -
+              {{scope.row.Floor?scope.row.Floor.FloorLocalName?scope.row.Floor.FloorLocalName:'':''}}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="EquipLocalID" :label="`${inSpaceType}本地名称`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="EquipLocalName" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="EquipFamily.FamilyName" label="设备族" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="InstallLocation" label="安装位置" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="TaskType" label="任务执行情况" show-overflow-tooltip min-width="100"></el-table-column>
+        <!-- <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <i v-if="scope.row.TaskState == '待验证' || scope.row.TaskState == '未找到'" title="查看详情" class="iconfont icon-xiangqing table-button" @click="handleDetail(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '未找到'" title="重新生成任务" class="iconfont icon-Update table-button" @click="handleRegenerate(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '待验证'" title="删除任务" class="iconfont icon-delete table-button" @click="handleDelete(scope.$index, scope.row)"></i>
+            <i v-if="scope.row.TaskState == '未找到'" title="认可此任务执行情况" class="iconfont icon-lijiqueren table-button" @click="handleConfirm(scope.$index, scope.row)"></i>
+          </template>
+        </el-table-column> -->
+        <template slot="empty">
+          <div style="height: 60%;transform: translateY(50%);">
+            <i class="icon-wushuju iconfont"></i>
+            数据暂无
+          </div>
+        </template>
+      </el-table>
+    </div>
+    <el-pagination class="right" v-show="tableData && tableData.length" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page.pageNumber"
+     :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="page.total">
+    </el-pagination>
+    <el-drawer title="任务详情" :visible.sync="drawer" direction="rtl" size="600px">
+      <assets-detail :id="detailId"></assets-detail>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import { queryAssetsTask, deleteAssetsTask } from "@/api/data_admin/buildTaskApi"
+import tools from "@/utils/tools"
+import { mapGetters } from "vuex"
+import assetsDetail from '../detail/assetsDetail'
+export default {
+  components: {
+    assetsDetail
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  props: {
+    paramsData: Object,
+  },
+  data() {
+    return {
+      inSpaceType: '资产',
+      loading: false, // loading
+      drawer: false, // 详情侧弹窗
+      detailId: '',
+      tableData: [], //列表数据
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      taskTypeMap: {//待撕码,待换码
+        '-5': '已撕码',
+        '3': '待撕码',
+        '2': '待换码',
+        '0': '正常贴码'
+      },
+      taskStateMap: {
+        '-1': '未找到',
+        '0': '已完成',
+        '1': '待验证'
+      },
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      }, // 列表样式
+    };
+  },
+  created() {
+    this.getTableData()
+  },
+  methods: {
+    // 获取列表数据
+    getTableData() {
+      let params = {
+        Filters: `ProjectId='${this.projectId}';TaskType in ['3','-5']`,
+        Cascade: [
+          {
+            Name: 'equipFamily'
+          }, {
+            Name: 'building',
+          }, {
+            Name: 'floor',
+          }
+        ],
+        Orders: "CreateTime desc, TaskId asc",
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize
+      }
+      // if (this.paramsData.buildfloor[0] == "noKnow") {
+      //   params.Filters += `;BuildingId isNull`
+      // } else if (this.paramsData.buildfloor[0] && this.paramsData.buildfloor[0] != "all") {
+      //   params.Filters += `;BuildingId='${this.paramsData.buildfloor[0]}'`
+      //   if (this.paramsData.buildfloor[1] == "noKnow") {
+      //     params.Filters += `;FloorId isNull`
+      //   } else if (this.paramsData.buildfloor[1] && this.paramsData.buildfloor[1] != "all") {
+      //     params.Filters += `;FloorId='${this.paramsData.buildfloor[1]}'`
+      //   }
+      // }
+      // if(this.paramsData.taskState !== ''){
+      //   params.Filters += `;TaskState=${this.paramsData.taskState}`
+      // }
+      // if(this.paramsData.family){
+      //   params.Filters += `;Family='${this.paramsData.family}'`
+      // }
+      queryAssetsTask(params, res => {
+        this.page.total = res.Total;
+        this.tableData = res.Content.map(item => {
+          item.TaskState = this.taskStateMap[item.TaskState]
+          item.TaskType = this.taskTypeMap[item.TaskType]
+          return item
+        })
+      })
+    },
+    // 删除关系
+    handleDelete(index, row) {
+      this.$confirm("确认删除该任务?", "提示", {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        let params = [{TaskId: row.TaskId}]
+        deleteAssetsTask(params, res => {
+          this.$message.success('删除成功')
+          this.getTableData()
+        })
+      }).catch(() => {
+        this.$message("取消删除")
+      })
+    },
+    //查看任务详情
+    handleDetail() {
+      this.drawer = true
+      this.detailId = row.TaskId
+    },
+    // 改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageNumber = 1
+      this.page.pageSize = pageSize;
+      this.getTableData()
+    },
+    // 改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData()
+    }
+  },
+  watch: {
+    paramsData: {
+      handler(newName, oldName) {
+        if(!tools.isSimilarly(newName, oldName)){
+          this.page.pageNumber = 1
+          this.getTableData()
+        }
+      },
+      immediate: true,
+      deep: true
+    },
+    projectId() {
+      this.page.pageNumber = 1
+      this.getTableData()
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+/deep/ .el-drawer__body {
+  height: calc(100% - 80px);
+  border-top: 1px solid #c9c9c9;
+}
+/deep/ .el-drawer__header {
+  margin-bottom: 12px;
+}
+.table-container {
+  height: 100%;
+  background: #fff;
+  .table-button{
+    cursor: pointer;
+    margin-right: 15px;
+  }
+}
+</style>

+ 160 - 0
src/components/data_admin/buildTask/taskStatistics.vue

@@ -0,0 +1,160 @@
+<template>
+  <div class="statistics-box flex-row">
+		<div class="statistics-all flex-row">
+      <div class="statistics-progress">
+        <div class="statistics-progress-num">
+          <p>{{taskProgress?taskProgress:0 + '%'}}</p>
+          <p>完成情况</p>
+        </div>
+        <el-progress :width="90" type="circle" :percentage="taskProgress?taskProgress:0" :show-text="false"></el-progress>
+      </div>
+      <div class="statistics-all-box flex-col">
+        <span>总任务:<b>{{allCount}}</b></span>
+        <span>已完成:<b>{{alreadyCount}}</b></span>
+      </div>
+    </div>
+		<ul class="statistics-list flex-row">
+      <li>
+        <p class="statistics-list-text">现场未找到(需人工确认):</p>
+        <p class="statistics-list-num">{{notFoundCount}}</p>
+      </li>
+      <li>
+        <p class="statistics-list-text">待验证任务:</p>
+        <p class="statistics-list-num">{{waitCount}}</p>
+      </li>
+      <li>
+        <p class="statistics-list-text">待撕码任务:</p>
+        <p class="statistics-list-num">{{waitTearCount}}</p>
+      </li>
+      <li>
+        <p class="statistics-list-text">待换码任务:</p>
+        <p class="statistics-list-num">{{waitReplaceCount}}</p>
+      </li>
+    </ul>
+	</div>
+</template>
+
+<script>
+import { mapGetters } from "vuex"
+import { queryTaskCount, countAssetsTask } from "@/api/data_admin/buildTaskApi"
+export default {
+  components: {
+    
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId", "secret", "userId" ]),
+    taskProgress(){
+      if(typeof this.alreadyCount == 'number' && typeof this.allCount == 'number'){
+        return Math.round(this.alreadyCount/this.allCount*100)
+      }
+    }
+  },
+  data() {
+    return {
+      allCount: '',//总任务
+      alreadyCount: '',//已完成
+      notFoundCount: '',//未找到
+      waitCount: '',//未完成验证
+      waitTearCount: '',//未完成撕码任务
+      waitReplaceCount: ''//未完成换码任务
+    }
+  },
+  created() {
+    this.getTaskCount();
+  },
+  methods: {
+    getTaskCount(){
+      queryTaskCount({},(res) => {
+        this.allCount = res.Count
+      })
+      queryTaskCount({Filters: `TaskState=0`},(res) => {
+        this.alreadyCount = res.Count
+      })
+      queryTaskCount({Filters: `TaskState=-1`},(res) => {
+        this.notFoundCount = res.Count
+      })
+      queryTaskCount({Filters: `TaskState=1`},(res) => {
+        this.waitCount = res.Count
+      })
+      countAssetsTask({Filters: `TaskState=1&&TaskType='3'`},(res) => {
+        this.waitTearCount = res.Count
+      })
+      countAssetsTask({Filters: `TaskState=1&&TaskType='2'`},(res) => {
+        this.waitReplaceCount = res.Count
+      })
+    }
+  },
+  watch: {
+    projectId() {
+      this.getTaskCount();
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+	.statistics-box {
+		height: 120px;
+    color: #333;
+    .statistics-all{
+      flex: 2;
+      border: 1px solid #c9c9c9;
+      margin-right: 10px;
+      background: #fff;
+      .statistics-progress{
+        flex: 1;
+        position: relative;
+        height: 120px;
+        box-sizing: border-box;
+        text-align: center;
+        padding: 15px 0;
+        .statistics-progress-num{
+          font-size: 12px;
+          line-height: 18px;
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          transform: translate(-50%, -50%);
+        }
+      }
+      .statistics-all-box{
+        flex: 1;
+        font-weight: bold;
+        padding: 25px 0;
+        >span{
+          flex: 1;
+          font-size: 15px;
+          line-height: 35px;
+        } 
+      }
+    }
+    .statistics-list{
+      flex: 7;
+      >li{
+        flex: 1;
+        border: 1px solid #c9c9c9;
+        padding: 10px;
+        margin-left: 10px;
+        background: #fff;
+        .statistics-list-text{
+          font-size: 15px;
+          line-height: 30px;
+          font-weight: bold;
+        }
+        .statistics-list-num{
+          text-align: center;
+          font-size: 20px;
+          line-height: 50px;
+          font-weight: bold;
+        }
+      }
+    }
+	}
+  .flex-row{
+    display: flex;
+		flex-direction: row;
+  }
+  .flex-col{
+    display: flex;
+		flex-direction: column;
+  }
+</style>

+ 136 - 0
src/components/data_admin/zoneInput.vue

@@ -0,0 +1,136 @@
+<template>
+  <div id="zoneinput">
+    <el-form label-position="left" :label-width="labelWidth" :model="form">
+      <div v-for="(titem, tkey) in inputTypeList" :key="tkey">
+        <h4>{{ tkey }}</h4>
+        <el-form-item v-for="(item, key) in titem" :key="key" :label="item.InfoPointName" class="input-item">
+          <el-input v-model="item.inputValue" v-if="item.InputMode == 'A1'|| item.InputMode == 'A2'" type="number">
+            <template slot="append" v-if="item.Unit">{{item.Unit}}</template>
+          </el-input>
+          <el-input v-model="item.inputValue" v-else-if="item.InputMode == 'B1' || item.InputMode == 'L' || item.InputMode == 'M'"></el-input>
+          <el-select v-model="item.inputValue" v-else-if="item.InputMode == 'D1'" placeholder="请选择">
+            <el-option v-for="(soption,skey) in item.options" :key="skey" :label="soption.Name" :value="soption.Code">
+            </el-option>
+          </el-select>
+          <el-cascader v-model="item.inputValue" v-else-if="item.InputMode == 'D1L'" placeholder="请选择"
+            :props="item.props" :options="item.options" filterable :show-all-levels="false"></el-cascader>
+          <el-input v-model="item.inputValue" v-else></el-input>
+        </el-form-item>
+      </div>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import tools from "@/utils/scan/tools";
+export default {
+  data() {
+    return {
+      form: {},
+      inputTypeList: {},//输入框表头种类
+      inputData: [],//所有输入框
+    }
+  },
+  props: {
+    labelWidth: {
+      default: "130px",
+      type: String
+    }
+  },
+  created() {
+  },
+  methods: {
+    //初始化
+    init(val) {
+      this.inputTypeList = {};
+      this.inputData = [];
+      this.inputData = val.concat()
+      this.filterInput();
+      this.inputGroup();
+    },
+    //数据过滤
+    filterInput() {
+      this.inputData = this.inputData.filter(item => {
+        return item.Editable == true && item.Visible == true && item.FirstName && item.InfoPointCode;
+      })
+      let numbersInput = ['A1', 'A2'];
+      let stringInput = ['B1', 'L', 'M'];
+      let arrayInput = ['D1'];
+      let cascaderInput = ['D1L'];
+      this.inputData.map(item => {
+        if (numbersInput.indexOf(item.InputMode) != -1) {
+          item.inputValue = null;
+        }
+        else if (stringInput.indexOf(item.InputMode) != -1) {
+          item.inputValue = '';
+        }
+        else if (arrayInput.indexOf(item.InputMode) != -1) {
+          let options = JSON.parse(item.DataSource)
+          item.inputValue = '';
+          item.options = options;
+        }
+        else if(cascaderInput.indexOf(item.InputMode) != -1){
+          let options = JSON.parse(item.DataSource);
+          if (options[0] && options[0].Content) {
+            item.props = {
+              value: 'Code',
+              label: 'Name',
+              children: 'Content'
+            }
+          }
+          item.options = options;
+          item.inputValue = [];
+        }
+        else {
+          item.inputValue = '';
+        }
+      });
+
+    },
+    //数据分组
+    inputGroup() {
+      this.inputData.map(item => {
+        if (!this.inputTypeList[item.FirstName]) {
+          this.inputTypeList[item.FirstName] = [];
+        }
+        this.inputTypeList[item.FirstName].push(item)
+      })
+      for (let key in this.inputTypeList) {
+        if (this.inputTypeList[key] instanceof Array) {
+          this.inputTypeList[key].sort((item1, item2) => { return item1.Sort < item2.Sort });
+        }
+      }
+    },
+    //父组件获取form
+    getFormData() {
+      let f = {}
+      for (let key in this.inputTypeList) {
+        this.inputTypeList[key].map(item => {
+          if (item.inputValue != '' && item.inputValue != null) {
+            if (item.inputValue instanceof Array) {
+              tools.setDataForKey(f, item.Path, item.inputValue.pop());
+            }
+            else {
+              tools.setDataForKey(f, item.Path, item.inputValue);
+            }
+          }
+        })
+      }
+      return f;
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.input-item {
+  display: inline-block;
+  position: relative;
+  margin-right: 10px;
+}
+#zoneinput {
+  /deep/ .el-form-item__content {
+    width: 220px;
+  }
+}
+</style>

+ 1 - 1
src/components/dialogHanson/addDevice.vue

@@ -344,7 +344,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该业务空间"

+ 1 - 1
src/components/dialogs/addDialog/businessDialog.vue

@@ -478,7 +478,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该业务空间"

+ 1 - 1
src/components/dialogs/addDialog/dialogAssets.vue

@@ -502,7 +502,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该资产"

+ 2 - 2
src/components/dialogs/addDialog/dialogDevice.vue

@@ -623,7 +623,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该业务空间"
@@ -972,7 +972,7 @@ export default {
 </style>
 <style lang="">
     .confirmButtonClass {
-    width: 180px; 
+    width: 180px;
 }
 .cancelButtonClass {
     width: 180px;

+ 1 - 1
src/components/dialogs/addDialog/dialogSystem.vue

@@ -556,7 +556,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该资产"

+ 582 - 0
src/components/dialogs/list/batchDialog.vue

@@ -0,0 +1,582 @@
+<template>
+  <el-dialog
+        title="批量维护信息点"
+        :visible.sync="batchDialog"
+        class="batchContainer"
+    >
+    <el-steps
+        :active="active"
+        align-center
+    >
+      <el-step
+          @click.native="active = 0"
+          description="填写需维护的信息点"
+      />
+      <el-step
+          @click.native="active = 1"
+          description="选择批量维护的对象实例"
+      />
+    </el-steps>
+    <hr>
+    <div v-show="active === 0">
+      <section>
+        <p class="text-message">维护只有单值的信息点</p>
+        <span class="small">请选择需维护的信息点</span>
+        <el-checkbox
+            :indeterminate="isIndeterminate"
+            v-model="checkAll"
+            @change="handleCheckChange"
+        >
+          全部选择
+        </el-checkbox>
+
+        <div style="margin: 15px "></div>
+        <el-checkbox-group
+            v-model="checkedCities"
+            @change="handleCheckedCitiesChange"
+        >
+          <el-checkbox
+              v-for="(city,index) in newFirm"
+              :label="city"
+              :key="index"
+          >
+            <span @click="fourVendors(city.code)"> {{city.name}}:</span>
+            <span>{{city.rname}}</span>
+          </el-checkbox>
+        </el-checkbox-group>
+      </section>
+      <!--维护有多个值的信息-->
+      <section>
+        <p class="text-message">维护有多个值的信息点</p>
+        <span class="small">选择值的更新方式</span>
+        <el-radio-group
+            v-model="radio"
+            @change="maintenance"
+        >
+          <el-radio :label="1">以增量方式维护</el-radio>
+          <el-radio :label="2">以覆盖方式维护</el-radio>
+        </el-radio-group>
+        <div style="margin: 15px "></div>
+        <div class="checkbox">
+          <p>
+            <el-checkbox
+                v-model="videoModel.archive"
+                @change="multiple('archive')"
+            > <!--设备文档-->
+              {{information.archive.name}}
+            </el-checkbox>
+            <span v-for="item in information.archive.Archive">{{item | filterImgName}}</span>
+          </p>
+          <p>
+            <el-checkbox
+                v-model="videoModel.checkReport"
+                @change="multiple('checkReport')"
+            ><!--安装质检报告-->
+              {{information.checkReport.name}}
+            </el-checkbox>
+            <span v-for="item in information.checkReport.CheckReport">{{item | filterImgName}}</span>
+
+          </p>
+          <p>
+            <el-checkbox
+                v-model="videoModel.drawing"
+                @change="multiple('drawing')"
+            ><!--设备图纸-->
+              {{information.drawing.name}}
+            </el-checkbox>
+            <span v-for="item in information.drawing.Drawing">{{item.key | filterImgName}}</span>
+
+          </p>
+          <p>
+            <el-checkbox
+                v-model="videoModel.installDrawing"
+                @change="multiple('installDrawing')"
+            ><!--安装图纸-->
+              {{information.installDrawing.name}}
+            </el-checkbox>
+            <span
+                v-for="item in information.installDrawing.InstallDrawing">{{item.key | filterImgName}}</span>
+          </p>
+
+          <p>
+            <el-checkbox
+                v-model="videoModel.installPic"
+                @change="multiple('installPic')"
+            ><!--安装照片-->
+              {{information.installPic.name}}
+            </el-checkbox>
+            <span v-for="item in information.installPic.InstallPic">{{item.key | filterImgName}}</span>
+          </p>
+          <p>
+            <el-checkbox
+                v-model="videoModel.insuranceFile"
+                @change="multiple('insuranceFile')"
+            ><!--保险文件-->
+              {{information.insuranceFile.name}}
+            </el-checkbox>
+            <span v-for="item in information.insuranceFile.InsuranceFile">{{item | filterImgName}}</span>
+
+          </p>
+          <p>
+            <el-checkbox
+                v-model="videoModel.pic"
+                @change="multiple('pic')"
+            ><!--设备照片-->
+              {{information.pic.name}}
+            </el-checkbox>
+            <span v-for="item in information.pic.Pic">{{item.key | filterImgName}}</span>
+          </p>
+          <p>
+            <el-checkbox
+                v-model="videoModel.nameplate"
+                @change="multiple('nameplate')"><!--设备铭牌照片-->
+              {{information.nameplate.name}}
+            </el-checkbox>
+            <span v-for="item in information.nameplate.Nameplate">{{item.key | filterImgName}}</span>
+          </p>
+        </div>
+      </section>
+      <el-button
+          class="next-step"
+          @click="next"
+      >下一步
+      </el-button>
+    </div>
+    <div
+        v-show="active === 1"
+        class="all-message"
+    >
+      <el-table
+          ref="multipleTable"
+          :data="tableData"
+          max-height="300"
+          tooltip-effect="dark"
+          style="width:100%;margin-bottom: 10px"
+          @selection-change="handleSelectionChange"
+      >
+        <el-table-column
+            type="selection"
+            width="55"
+        />
+        <el-table-column
+            label="设备本地名称"
+            width=""
+        >
+          <template slot-scope="scope">{{scope.row.EquipLocalName}}</template>
+        </el-table-column>
+        <el-table-column
+            prop="EquipLocalID"
+            label="设备本地编码"
+            width="120"
+        />
+        <el-table-column
+            prop="build"
+            label="所属建筑楼层"
+            show-overflow-tooltip
+        />
+      </el-table>
+      <my-pagination
+          @change="getAllData"
+          :page="page"
+      ></my-pagination>
+
+      <el-button
+          type="primary"
+          @click="maintenanceSelect"
+      >维护已选
+      </el-button>
+      <el-button
+          @click="active = 0"
+      >上一步
+      </el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+  import myPagination from "@/components/ledger/lib/myPagination"
+
+  export default {
+    name: "batchDialog",
+    props: ['firmName', 'allObject', 'page', 'information'],
+    components: {myPagination},
+    data() {
+      return {
+        batchDialog: false,//dialog
+        active: 0,//进度条
+        checkAll: false,//全选
+        isIndeterminate: true,
+        checkedCities: [],//选择的项,单项
+        firm: [
+          {
+            name: "生产厂家/品牌型号",
+            code: "DPManufacturerID",
+            num: 2,
+          }, {
+            name: "供应商信息",
+            code: "DPSupplierID",
+            num: 8
+          }, {
+            name: "维修商信息",
+            code: "DPMaintainerID",
+            num: 35
+          }, {
+            name: "保险公司信息",
+            code: "DPInsurerID",
+            num: 42
+          }
+        ],
+        radio: 1, //1增加,2覆盖
+        checkedFile: [],//多项
+        multipleSelection: [],//checkbox选择的对象数组
+        filterList: [],//过滤单项选择的值
+        deviceList: [],//过滤全选数据
+        onlySelect: [],//检测是否有勾选单值信息
+        videoModel: {
+          archive: false,
+          checkReport: false,
+          drawing: false,
+          installDrawing: false,
+          insuranceFile: false,
+          installPic: false,
+          nameplate: false,
+          pic: false
+        },
+      }
+    },
+    watch: {
+      information() {
+        return this.information
+      },
+    
+    },
+    computed: {
+      newFirm() {
+        this.firm.map(item => {
+          if (item.num === this.firmName.num) {
+            item.rname = this.firmName.name
+            item.info = this.firmName
+          }
+          return item
+        })
+        return this.firm
+      },
+      tableData() {
+        this.allObject.map(item => {
+          let build = ''
+          if (item.Building && item.Floor) {
+            build = item.Building.BuildLocalName + ' - ' + item.Floor.FloorLocalName
+          } else if (item.Building) {
+            build = item.Building.BuildLocalName
+          } else if (item.Floor) {
+            build = item.Floor.FloorLocalName
+          } else {
+            build = '-'
+          }
+          item.build = build
+          return item
+        })
+        return this.allObject
+      },
+    },
+    filters: {
+      filterImgName(value) {
+        if (value.length > 16) {
+          return value.substring(0, 12) + '...'
+        } else {
+          return value
+        }
+      }
+    },
+    methods: {
+      next() { //下一步按钮
+        // if (this.active++ > 1) this.active = 0
+        this.deviceList = this.firm.filter(item => item.info)
+        if (!this.onlySelect.length) { //对单项全选进行过滤
+          this.$message({
+            message: '还没有选择单值信息哦',
+            type: 'warning'
+          });
+          return false
+        }
+        if (!this.deviceList.length) { //对单项全选进行过滤
+          this.$message({
+            message: '单值信息没有填写哦',
+            type: 'warning'
+          });
+          return false
+        }
+        if (this.checkAll) {    // 如果单项全选
+          if (this.deviceList.length < 4) { //对单项全选进行过滤
+            this.$message({
+              message: '单值的信息点存在未填写',
+              type: 'warning'
+            });
+            return false
+          } else {
+            this.active++
+          }
+        } else {
+          this.active++
+        }
+      },
+      handleCheckChange(val) { //全选
+        this.checkedCities = val ? this.firm : []
+        this.isIndeterminate = false
+
+      },
+      handleCheckedCitiesChange(value) { //维护单项触发
+        this.onlySelect = value
+        this.filterList = value.filter(item => item.info)
+        let checkCount = value.length
+        this.checkAll = checkCount === this.firm.length
+        this.isIndeterminate = checkCount > 0 && checkCount < this.firm.length
+      },
+      handleCheckedFileChange(value) { //维护多项触发
+      },
+      fourVendors(code) {
+        this.$emit('code', code)
+      },
+      //    选择维护方式
+      maintenance(val) {
+      },
+
+      maintenanceSelect() { //维护已选
+        if (!this.multipleSelection.length) {
+          this.$message({
+            message: '还没有选择实例哦',
+            type: 'warning'
+          });
+          return false
+        }
+        let arr = []
+        // DPSupplierID 供应商 DPManufacturerID 生产商 DPBrandID 品牌
+        // DPSpecificationID 型号 DPInsurerID 保险商 DPMaintainerID 维修商
+        this.multipleSelection.forEach(item => {
+          let EquipID = item.EquipID
+          arr.push({EquipID})
+        })
+        let Id = {}
+        let single = {};
+        // this.filterList 单选数组,取到需要数据
+        // 过滤数组,取对象
+        this.checkedCities.filter(item => item.num === 2).forEach(i => { //型号
+          if(i.info) {
+            let {venderName, brandName, Specification, venderId, brandId, specificationId} = i.info
+            single.EquipManufactor = {
+              Manufacturer: venderName,
+              Brand: brandName,
+              Specification: Specification
+            }
+            Id.DPManufacturerID = venderId
+            Id.DPBrandID = brandId
+            Id.DPSpecificationID = specificationId
+          }
+        })
+        this.checkedCities.filter(item => item.num === 8).forEach(i => {  //供应商8
+         if(i.info) {
+           let {website, name, venderId} = i.info
+           single.SupplyPurchase = {
+             SupplierWeb: website,
+             Supplier: name,
+
+           }
+           Id.DPSupplierID = venderId
+         }
+        })
+        this.checkedCities.filter(item => item.num === 35).forEach(i => {  //维修商
+         if(i.info) {
+           let {name, venderId} = i.info
+           single.OperationMainte = {
+             Maintainer: name
+           }
+           Id.DPMaintainerID = venderId
+         }
+        })
+        this.checkedCities.filter(item => item.num === 42).forEach(i => {  //保险
+         if(i.info) {
+           let {website, name, venderId} = i.info
+           single.InsuranceDoc = {
+             Insurer: name,
+             InsurerWeb: website,
+             InsuranceFile: this.information.insuranceFile.InsuranceFile.length ? this.information.insuranceFile.InsuranceFile : undefined
+
+           }
+
+           Id.DPInsurerID = venderId
+         }
+        })
+        // this.information 多选信息
+        let {archive, checkReport, drawing, installDrawing, installPic, insuranceFile, nameplate, pic} = this.information
+        let multiple = {
+          InsuranceDoc: insuranceFile.InsuranceFile.length || this.videoModel.insuranceFile ? {
+            InsuranceFile: (insuranceFile.InsuranceFile.length && this.videoModel.insuranceFile) ? insuranceFile.InsuranceFile : undefined
+          } : undefined,
+          PhotoDoc: archive.Archive.length || drawing.Drawing.length || nameplate.Nameplate.length || pic.Pic.length ? {
+            Archive: (archive.Archive.length && this.videoModel.archive) ? archive.Archive : undefined,
+            Drawing: (drawing.Drawing.length && this.videoModel.drawing) ? drawing.Drawing : undefined,
+            Nameplate: (nameplate.Nameplate.length && this.videoModel.nameplate) ? nameplate.Nameplate : undefined,
+            Pic: (pic.Pic.length && this.videoModel.pic) ? pic.Pic : undefined
+          } : undefined,
+          Siteinstall: installPic.InstallPic.length || installDrawing.InstallDrawing.length || checkReport.CheckReport.length ? {
+            InstallPic: (installPic.InstallPic.length && this.videoModel.installPic) ? installPic.InstallPic : undefined,
+            InstallDrawing: (installDrawing.InstallDrawing.length && this.videoModel.installDrawing) ? installDrawing.InstallDrawing : undefined,
+            CheckReport: (checkReport.CheckReport.length && this.videoModel.checkReport) ? checkReport.CheckReport : undefined
+          } : undefined
+        }
+        console.log(multiple, 'multilp')
+        let LedgerParam = {}
+        if (this.radio === 1) { //组装数据,根据是覆盖该是增量,1是增量
+          //    1:单选数据
+          let arr1 = this.deepCopy(arr).map(item => ({
+            ...Id,
+            ...item,
+            LedgerParam: {...single}
+
+          }))
+          //    2:多选数据
+          let arr2 = this.deepCopy(arr).map(item => ({
+            ...item,
+            LedgerParam: {...multiple}
+          }))
+          this.$emit('upDataDevice', 1, arr1, arr2)
+          
+        }
+        if (this.radio === 2) {
+          let {InsuranceDoc, ...multiples} = multiple
+          LedgerParam = {
+            ...single,
+            ...multiples
+
+          };
+          let arr3 = this.deepCopy(arr).map(item => ({
+            ...Id,
+            ...item,
+            LedgerParam: {...LedgerParam}
+          }))
+          this.$emit('upDataDevice', 2, arr3)
+
+        }
+        this.closeDialog()
+      },
+      closeDialog() {  //关闭弹窗,返回初始状态
+        this.batchDialog = false
+        this.clearData()
+
+      },
+      clearData() { //清空规则 filterList
+        this.active = 0
+        this.checkedCities = []//清空单项的checkbox
+        this.firm.forEach(item => {
+          item.rname = ''
+          item.info = ''
+        })
+        // this.filterList = []
+        this.onlySelect = []
+        // this.deviceList = []
+        this.radio = 1 //返回到默认增量
+        // this.multipleSelection = [] //清空实例内容
+        this.videoModel = {
+          archive: false,
+          checkReport: false,
+          drawing: false,
+          installDrawing: false,
+          insuranceFile: false,
+          installPic: false,
+          nameplate: false,
+          pic: false
+        }
+        let {archive, checkReport, drawing, installDrawing, installPic, insuranceFile, nameplate, pic} = this.information
+        archive.Archive = []
+        checkReport.CheckReport = []
+        drawing.Drawing = []
+        installDrawing.InstallDrawing = []
+        installPic.InstallPic = []
+        insuranceFile.InsuranceFile = []
+        nameplate.Nameplate = []
+        pic.Pic = []
+      },
+      handleSelectionChange(val) {
+        this.multipleSelection = val
+      },
+      getAllData() {
+        this.$emit('getAllData')
+      },
+      multiple(val) {
+        this.$emit('multiple', val)
+      },
+
+      deepCopy(obj) {
+        return JSON.parse(JSON.stringify(obj))
+      }
+    }
+  }
+</script>
+
+<style scoped lang="less">
+  .batchContainer {
+    /deep/ .el-step__description {
+      margin: 2% 0;
+    }
+
+    .el-checkbox-group {
+      display: flex;
+      justify-content: space-between;
+      flex-direction: row;
+      flex-wrap: wrap;
+
+      .el-checkbox {
+        width: 43%;
+      }
+
+      .el-checkbox:last-of-type {
+        margin-right: 30px;
+      }
+    }
+
+    .next-step {
+      display: block;
+      margin: 12px auto 0 auto;
+    }
+
+    .checkbox {
+      display: flex;
+      justify-content: space-between;
+      flex-direction: row;
+      flex-wrap: wrap;
+
+      p {
+        width: 50%;
+      }
+
+      .el-checkbox:last-of-type {
+        margin-right: 10px;
+      }
+    }
+
+    .text-message {
+      overflow: hidden;
+      margin-top: 10px;
+      color: #333;
+      border-left: 8px solid #333;
+      text-indent: 10px;
+      font-weight: 600;
+    }
+
+    .small {
+      font-size: 12px;
+      color: #555;
+    }
+
+    .all-message {
+      overflow: hidden;
+
+      button {
+        float: right;
+        padding: 10px;
+        margin-left: 5px;
+      }
+    }
+
+  }
+</style>

+ 87 - 43
src/components/dialogs/list/filesDialog.vue

@@ -3,50 +3,94 @@
 -->
 
 <template>
-  <el-dialog title="上传文件" :visible.sync="dialog.uploadFiles" width="500px">
-      <div class='max-height: 500px; overflow-y: auto;'>
-        <upload-files :readOnly="read" :keysArr="keysArr" @change="changeItem" max="2"></upload-files>
-      </div>
-  </el-dialog>
+    <el-dialog
+        title="上传文件"
+        :visible.sync="dialog.uploadFiles"
+        width="500px">
+        <div class='max-height: 500px; overflow-y: auto;'>
+            <upload-files
+                :readOnly="read"
+                :keysArr="keysArr"
+                :firmDataType="firmDataType"
+                @change="changeItem"
+                max="2"/>
+        </div>
+    </el-dialog>
 </template>
 <script>
-import uploadFiles from "@/components/ledger/lib/uploadFiles";
-export default {
-  components: {
-    uploadFiles
-  },
-  props: {
-    dialog: {
-      type: Object,
-      default: function () {
-        return {
-          uploadFiles: false
-        };
-      }
-    },
-    keysArr: {
-      type: Array,
-      default: function () {
-        return []
-      }
-    },
-    read: {
-      type: Boolean,
-      default: false
-    }
-  },
-  data() {
-    return {};
-  },
-  created() { },
-  mounted() { },
-  methods: {
-    changeItem(file) {
-      console.log(file)
-      this.$emit("changeFile", file)
-    }
-  },
-};
+    import uploadFiles from "@/components/ledger/lib/uploadFiles";
+
+    export default {
+        components: {
+            uploadFiles
+        },
+        props: {
+            dialog: {
+                type: Object,
+                default: function () {
+                    return {
+                        uploadFiles: false
+                    };
+                }
+            },
+            keysArr: {
+                type: Array,
+                default: function () {
+                    return []
+                }
+            },
+            read: {
+                type: Boolean,
+                default: false
+            },
+            firmDataType: {
+                type: String
+            },
+            infoType: {
+                type: String
+            },
+            information: {
+                type: Object
+            }
+        },
+        data() {
+            return {};
+        },
+        created() {
+        },
+        computed: {
+
+        },
+        mounted() {
+        },
+        methods: {
+            changeItem(file) {
+                if (this.firmDataType === 'dialog') {
+                    let info = this.infoType;
+                    switch (info) {
+                        case 'archive':
+                            this.information.archive.Archive = file
+                            this.$emit("changeFile", this.information, this.firmDataType)
+                            break
+                        case 'checkReport':
+                            this.information.checkReport.CheckReport = file
+                            this.$emit("changeFile", this.information, this.firmDataType)
+                            break
+                        case 'insuranceFile':
+                            this.information.insuranceFile.InsuranceFile = file
+                            this.$emit("changeFile", this.information, this.firmDataType)
+                            break
+                    }
+                } else {
+                    this.$emit("changeFile", file, this.firmDataType)
+
+                }
+            },
+            deepCopy(obj) {
+                return JSON.parse((JSON.stringify(obj)))
+            }
+        },
+    };
 </script>
 <style>
-</style>
+</style>

+ 126 - 121
src/components/dialogs/list/firm.vue

@@ -27,7 +27,7 @@
             </el-table-column>
             <el-table-column prop="brandName" label="品牌" header-align='center'></el-table-column>
             <el-table-column prop="name" label="型号" header-align='center'></el-table-column>
-            <el-table-column label="技术参数" header-align='center'>
+            <el-table-column  label="技术参数" header-align='center'>
               <template slot-scope="scope">
                 <el-button :disabled="scope.row.specificationId?false:true" type="text" @click="lookParam(scope.row)">技术参数</el-button>
               </template>
@@ -40,8 +40,8 @@
                 <i style="color:#46B0FF;cursor: pointer;">厂家库</i>维护吧
             </p>
             <my-pagination :page="page" @change="changed" style="margin-top:10px;"></my-pagination>
-        </div> 
-        
+        </div>
+
       </div>
     </div>
     <div slot="footer" class="dialog-footer">
@@ -63,124 +63,129 @@ export default {
     myPagination,
     paramDetails
   },
-  props: {
-    dialog: {
-      type: Object,
-      default: function () {
-        return {
-          firm: false
-        };
-      }
-    },
-    mess: {
-      type: [Object, String]
-    }
-  },
-  data() {
-    return {
-      search: "", //搜索文案
-      radio: "",
-      value: "specification",//当前选择的查看类型
-      options: [{
-          value: 'specification',
-          label: '选型号'
-        }, {
-          value: 'brand',
-          label: '选生产厂家-品牌'
-        }, {
-          value: 'manufacturer',
-          label: '选生产厂家'
-      }],
-      tableData: [],
-      data: {},
-      isLoad: {
-        paramShow: false
-      },
-      page: {
-        size: 50,
-        sizes: [10, 30, 50, 100, 150, 200],
-        total: 0,
-        currentPage: 1
-      },
-    };
-  },
-  created() { },
-  mounted() { },
-  methods: {
-    changed() {
-      this.getData()
-    },
-    //查询技术参数
-    lookParam(data) {
-      this.data = data
-      this.isLoad.paramShow = true
-    },
-    getChange() {
-      if (!!this.radio) {
-        this.$emit("changeFirm", this.radio)
-        this.dialog.firm = false
-        this.radio = ''
-      } else {
-        this.$message("请选择型号")
-      }
-    },
-    searchKey() {
-      this.changePage()
-    },
-    changePage() {
-      this.page = {
-        size: 50,
-        sizes: [10, 30, 50, 100, 150, 200],
-        total: 0,
-        currentPage: 1
-      }
-      this.getData()
-    },
-    handleChangeType(item) {
-      this.page.total = 0
-      this.tableData = []
-      this.getData()
-    },
-    getData() {
-      if(this.value == 'specification') {//型号
-        getSpecList({
-          limit: {
-            skip: this.page.size * (this.page.currentPage - 1),
-            count: this.page.size
-          },
-          eqFamily: this.mess.deviceId,
-          name: this.search
-        }, res => {
-          this.page.total = res.totalCount
-          this.tableData = res.content
-        })
-      } else if(this.value == 'brand') {//生产厂家-品牌
-        getBrandList({
-          limit: {
-            skip: this.page.size * (this.page.currentPage - 1),
-            count: this.page.size
-          },
-          name: this.search
-        }, res => {
-          this.page.total = res.totalCount
-          this.tableData = res.content
-        })
-      } else if(this.value == 'manufacturer') {//生产厂家
-        getManufacturerList({
-          limit: {
-            skip: this.page.size * (this.page.currentPage - 1),
-            count: this.page.size
-          },
-          name: this.search
-        }, res => {
-          this.page.total = res.totalCount
-          this.tableData = res.content
-        })
-      }
-      console.log(this.tableData)
-    }
-  },
-  watch: {
+        props: {
+            dialog: {
+                type: Object,
+                default: function () {
+                    return {
+                        firm: false
+                    };
+                }
+            },
+            mess: {
+                type: [Object, String]
+            },
+            firmDataType: {
+                type: String
+            }
+        },
+        data() {
+            return {
+                search: "", //搜索文案
+                radio: "",
+                value: "specification",//当前选择的查看类型
+                options: [{
+                    value: 'specification',
+                    label: '选型号'
+                }, {
+                    value: 'brand',
+                    label: '选生产厂家-品牌'
+                }, {
+                    value: 'manufacturer',
+                    label: '选生产厂家'
+                }],
+                tableData: [],
+                data: {},
+                isLoad: {
+                    paramShow: false
+                },
+                page: {
+                    size: 50,
+                    sizes: [10, 30, 50, 100, 150, 200],
+                    total: 0,
+                    currentPage: 1
+                },
+            };
+        },
+        created() {
+        },
+        mounted() {
+        },
+        methods: {
+            changed() {
+                this.getData()
+            },
+            //查询技术参数
+            lookParam(data) {
+                this.data = data
+                this.isLoad.paramShow = true
+            },
+            getChange() {
+                if (!!this.radio) {
+                    this.$emit("changeFirm", this.radio,this.firmDataType)
+                    this.dialog.firm = false
+                    this.radio = ''
+                } else {
+                    this.$message("请选择型号")
+                }
+            },
+            searchKey() {
+                this.changePage()
+            },
+            changePage() {
+                this.page = {
+                    size: 50,
+                    sizes: [10, 30, 50, 100, 150, 200],
+                    total: 0,
+                    currentPage: 1
+                }
+                this.getData()
+            },
+            getData() {
+                if (this.value == 'specification') {//型号
+                    getSpecList({
+                        limit: {
+                            skip: this.page.size * (this.page.currentPage - 1),
+                            count: this.page.size
+                        },
+                        eqFamily: this.mess.deviceId,
+                        name: this.search
+                    }, res => {
+                        this.page.total = res.totalCount
+                        this.tableData = res.content
+                    })
+                } else if (this.value == 'brand') {//生产厂家-品牌
+                    getBrandList({
+                        limit: {
+                            skip: this.page.size * (this.page.currentPage - 1),
+                            count: this.page.size
+                        },
+                        name: this.search
+                    }, res => {
+                        this.page.total = res.totalCount
+                        this.tableData = res.content
+                    })
+                } else if (this.value == 'manufacturer') {//生产厂家
+                    getManufacturerList({
+                        limit: {
+                            skip: this.page.size * (this.page.currentPage - 1),
+                            count: this.page.size
+                        },
+                        name: this.search
+                    }, res => {
+                        this.page.total = res.totalCount
+                        this.tableData = res.content
+                    })
+                }
+                console.log(this.tableData)
+            },
+            handleChangeType(item) {
+                this.page.total = 0
+                this.tableData = []
+                this.getData()
+            },
+        },
+        watch: {
     dialog: {
       deep: true,
       handler: function () {

+ 111 - 107
src/components/dialogs/list/insurerDialog.vue

@@ -38,7 +38,7 @@
                 <i style="color:#46B0FF;cursor: pointer;">厂家库</i>维护吧
             </p>
             <my-pagination :page="page" @change="changePage" style="margin-top:10px;"></my-pagination>
-        </div>         
+        </div>
       </div>
     </div>
     <div slot="footer">
@@ -50,120 +50,124 @@
   </el-dialog>
 </template>
 <script>
-import myPagination from "@/components/ledger/lib/myPagination";
-import { getLib } from "@/api/scan/request"
-import { mapGetters, mapActions } from "vuex";
-import tools from "@/utils/scan/tools"
+    import myPagination from "@/components/ledger/lib/myPagination";
+    import {getLib} from "@/api/scan/request"
+    import {mapGetters} from "vuex";
+    import tools from "@/utils/scan/tools"
 
-export default {
-  components: {
+    export default {
+        components: {
     myPagination
   },
-  props: {
-    dialog: {
-      type: Object,
-      default: function () {
-        return {
-          insurer: true
-        };
-      }
-    }
-  },
-  computed: {
-    ...mapGetters("layout", ["projectId", "secret", "userId"]),
-  },
-  data() {
-    return {
-      search: "", //搜索文案
-      radio: "",
-      tableData: [],
-      page: {
-        size: 50,
-        sizes: [10, 30, 50, 100, 150, 200],
-        total: 0,
-        currentPage: 1
-      }
-    };
-  },
-  created() {
-    // this.getData()
-  },
-  mounted() { },
-  methods: {
-    //过滤
-    filterSearch() {
-      this.tableData = this.allData.map(item => {
-        if (item.name.indexOf(this.search) != -1) {
-          return item
-        } else {
-          return undefined
-        }
-      }).filter(cb => cb)
-    },
-    getData() {
-      console.log("insurer")
-      this.page = {
-        size: 50,
-        sizes: [10, 30, 50, 100, 150, 200],
-        total: 0,
-        currentPage: 1
-      }
-      getLib({ "type": ["insurance"] }).then(res => {
-        if (res.data.result == "success") {
-          let data = res.data.content.insurance.map(item => {
-            if (item.contacts && item.contacts.length) {
-              item.contacts.map(child => {
-                if (child.projectId == this.projectId) {
-                  item.phone = child.phone
-                  item.man = child.name
-                  item.fox = child.fox
-                  item.email = child.email
+        props: {
+            dialog: {
+                type: Object,
+                default: function () {
+                    return {
+                        insurer: true
+                    };
                 }
-                return child
-              })
-            }
-            if (!item.man) {
-              item.man = "--"
-              item.phone = "--"
-              item.fox = "--"
-              item.email = "--"
+            },
+            firmDataType: {
+                type: String
             }
-            return item
-          })
-          this.allData = tools.deepCopy(data)
-          this.tableData = this.pagination(this.page.currentPage, this.page.size, this.allData)
-          this.page.total = data.length
-        } else {
-          this.$message.error("请求失败:" + res.data.resultMsg)
-        }
-      })
-    },
+        },
+        computed: {
+            ...mapGetters("layout", ["projectId", "secret", "userId"]),
+        },
+        data() {
+            return {
+                search: "", //搜索文案
+                radio: "",
+                tableData: [],
+                page: {
+                    size: 50,
+                    sizes: [10, 30, 50, 100, 150, 200],
+                    total: 0,
+                    currentPage: 1
+                }
+            };
+        },
+        created() {
+            // this.getData()
+        },
+        mounted() {
+        },
+        methods: {
+            //过滤
+            filterSearch() {
+                this.tableData = this.allData.map(item => {
+                    if (item.name.indexOf(this.search) != -1) {
+                        return item
+                    } else {
+                        return undefined
+                    }
+                }).filter(cb => cb)
+            },
+            getData() {
+                console.log("insurer")
+                this.page = {
+                    size: 50,
+                    sizes: [10, 30, 50, 100, 150, 200],
+                    total: 0,
+                    currentPage: 1
+                }
+                getLib({"type": ["insurance"]}).then(res => {
+                    if (res.data.result == "success") {
+                        let data = res.data.content.insurance.map(item => {
+                            if (item.contacts && item.contacts.length) {
+                                item.contacts.map(child => {
+                                    if (child.projectId == this.projectId) {
+                                        item.phone = child.phone
+                                        item.man = child.name
+                                        item.fox = child.fox
+                                        item.email = child.email
+                                    }
+                                    return child
+                                })
+                            }
+                            if (!item.man) {
+                                item.man = "--"
+                                item.phone = "--"
+                                item.fox = "--"
+                                item.email = "--"
+                            }
+                            return item
+                        })
+                        this.allData = tools.deepCopy(data)
+                        this.tableData = this.pagination(this.page.currentPage, this.page.size, this.allData)
+                        this.page.total = data.length
+                    } else {
+                        this.$message.error("请求失败:" + res.data.resultMsg)
+                    }
+                })
+            },
 
-    //分页改变
-    changePage() {
-      this.pagination(this.page.currentPage, this.page.size, this.allData)
-    },
+            //分页改变
+            changePage() {
+                this.pagination(this.page.currentPage, this.page.size, this.allData)
+            },
 
-    //发生修改
-    getChange() {
-      if (!!this.radio) {
-        this.$emit("changeInsurer", this.radio)
-        this.dialog.insurer = false
-        this.radio = ''
-      } else {
-        this.$message("请选择一个生产厂商")
-      }
-    },
+            //发生修改
+            getChange() {
+                if (!!this.radio) {
+                    this.$emit("changeInsurer", this.radio,this.firmDataType)
+                    this.dialog.insurer = false
+                    this.radio = ''
+                } else {
+                    this.$message("请选择一个生产厂商")
+                }
+            },
 
-    //分页事件
-    pagination(pageNo, pageSize, array) {
-      let offset = (pageNo - 1) * pageSize;
-      return offset + pageSize >= array.length
-        ? array.slice(offset, array.length)
-        : array.slice(offset, offset + pageSize);
-    }
-  },
-  watch: {
+            //分页事件
+            pagination(pageNo, pageSize, array) {
+                let offset = (pageNo - 1) * pageSize;
+                return offset + pageSize >= array.length
+                    ? array.slice(offset, array.length)
+                    : array.slice(offset, offset + pageSize);
+            }
+        },
+        watch: {
     dialog: {
       deep: true,
       handler: function () {

+ 111 - 107
src/components/dialogs/list/maintainerDialog.vue

@@ -1,5 +1,5 @@
 <!--
-    maintenance 选择供应
+    maintenance 选择维修
 
 -->
 <template>
@@ -38,7 +38,7 @@
                 <i style="color:#46B0FF;cursor: pointer;">厂家库</i>维护吧
             </p>
             <my-pagination :page="page" @change="changePage" style="margin-top:10px;"></my-pagination>
-        </div>         
+        </div>
       </div>
     </div>
     <div slot="footer">
@@ -50,119 +50,123 @@
   </el-dialog>
 </template>
 <script>
-import myPagination from "@/components/ledger/lib/myPagination";
-import { mapGetters, mapActions } from "vuex";
-import { getLib } from "@/api/scan/request"
-import tools from "@/utils/scan/tools"
+    import myPagination from "@/components/ledger/lib/myPagination";
+    import {mapGetters} from "vuex";
+    import {getLib} from "@/api/scan/request"
+    import tools from "@/utils/scan/tools"
 
-export default {
-  components: {
+    export default {
+        components: {
     myPagination
   },
-  props: {
-    dialog: {
-      type: Object,
-      default: function () {
-        return {
-          maintainer: true
-        };
-      }
-    }
-  },
-  computed: {
-    ...mapGetters("layout", ["projectId", "secret", "userId"]),
-  },
-  data() {
-    return {
-      search: "", //搜索文案
-      radio: "",
-      tableData: [],
-      page: {
-        size: 50,
-        sizes: [10, 30, 50, 100, 150, 200],
-        total: 0,
-        currentPage: 1
-      }
-    };
-  },
-  created() {
-    // this.getData()
-  },
-  mounted() { },
-  methods: {
-    //过滤
-    filterSearch() {
-      this.tableData = this.allData.map(item => {
-        if (item.name.indexOf(this.search) != -1) {
-          return item
-        } else {
-          return undefined
-        }
-      }).filter(cb => cb)
-    },
-    getData() {
-      this.page = {
-        size: 50,
-        sizes: [10, 30, 50, 100, 150, 200],
-        total: 0,
-        currentPage: 1
-      }
-      getLib({ "type": ["maintenance"] }).then(res => {
-        if (res.data.result == "success") {
-          let data = res.data.content.maintenance.map(item => {
-            if (item.contacts && item.contacts.length) {
-              item.contacts.map(child => {
-                if (child.projectId == this.projectId) {
-                  item.phone = child.phone
-                  item.man = child.name
-                  item.fox = child.fox
-                  item.email = child.email
+        props: {
+            dialog: {
+                type: Object,
+                default: function () {
+                    return {
+                        maintainer: true
+                    };
                 }
-                return child
-              })
-            }
-            if (!item.man) {
-              item.man = "--"
-              item.phone = "--"
-              item.fox = "--"
-              item.email = "--"
+            },
+            firmDataType: {
+                type: String
             }
-            return item
-          })
-          this.allData = tools.deepCopy(data)
-          this.tableData = this.pagination(this.page.currentPage, this.page.size, this.allData)
-          this.page.total = data.length
-        } else {
-          this.$message.error("请求失败:" + res.data.resultMsg)
-        }
-      })
-    },
+        },
+        computed: {
+            ...mapGetters("layout", ["projectId", "secret", "userId"]),
+        },
+        data() {
+            return {
+                search: "", //搜索文案
+                radio: "",
+                tableData: [],
+                page: {
+                    size: 50,
+                    sizes: [10, 30, 50, 100, 150, 200],
+                    total: 0,
+                    currentPage: 1
+                }
+            };
+        },
+        created() {
+            // this.getData()
+        },
+        mounted() {
+        },
+        methods: {
+            //过滤
+            filterSearch() {
+                this.tableData = this.allData.map(item => {
+                    if (item.name.indexOf(this.search) != -1) {
+                        return item
+                    } else {
+                        return undefined
+                    }
+                }).filter(cb => cb)
+            },
+            getData() {
+                this.page = {
+                    size: 50,
+                    sizes: [10, 30, 50, 100, 150, 200],
+                    total: 0,
+                    currentPage: 1
+                }
+                getLib({"type": ["maintenance"]}).then(res => {
+                    if (res.data.result == "success") {
+                        let data = res.data.content.maintenance.map(item => {
+                            if (item.contacts && item.contacts.length) {
+                                item.contacts.map(child => {
+                                    if (child.projectId == this.projectId) {
+                                        item.phone = child.phone
+                                        item.man = child.name
+                                        item.fox = child.fox
+                                        item.email = child.email
+                                    }
+                                    return child
+                                })
+                            }
+                            if (!item.man) {
+                                item.man = "--"
+                                item.phone = "--"
+                                item.fox = "--"
+                                item.email = "--"
+                            }
+                            return item
+                        })
+                        this.allData = tools.deepCopy(data)
+                        this.tableData = this.pagination(this.page.currentPage, this.page.size, this.allData)
+                        this.page.total = data.length
+                    } else {
+                        this.$message.error("请求失败:" + res.data.resultMsg)
+                    }
+                })
+            },
 
-    //分页改变
-    changePage() {
-      this.pagination(this.page.currentPage, this.page.size, this.allData)
-    },
+            //分页改变
+            changePage() {
+                this.pagination(this.page.currentPage, this.page.size, this.allData)
+            },
 
-    //发生修改
-    getChange() {
-      if (!!this.radio) {
-        this.$emit("changeMaintainer", this.radio)
-        this.dialog.maintainer = false
-        this.radio = ''
-      } else {
-        this.$message("请选择一个生产厂商")
-      }
-    },
+            //发生修改
+            getChange() {
+                if (!!this.radio) {
+                    this.$emit("changeMaintainer", this.radio,this.firmDataType)
+                    this.dialog.maintainer = false
+                    this.radio = ''
+                } else {
+                    this.$message("请选择一个生产厂商")
+                }
+            },
 
-    //分页事件
-    pagination(pageNo, pageSize, array) {
-      let offset = (pageNo - 1) * pageSize;
-      return offset + pageSize >= array.length
-        ? array.slice(offset, array.length)
-        : array.slice(offset, offset + pageSize);
-    }
-  },
-  watch: {
+            //分页事件
+            pagination(pageNo, pageSize, array) {
+                let offset = (pageNo - 1) * pageSize;
+                return offset + pageSize >= array.length
+                    ? array.slice(offset, array.length)
+                    : array.slice(offset, offset + pageSize);
+            }
+        },
+        watch: {
     dialog: {
       deep: true,
       handler: function () {

+ 147 - 126
src/components/dialogs/list/picDialog.vue

@@ -3,139 +3,160 @@
 -->
 
 <template>
-  <el-dialog title="上传图片" :visible.sync="dialog.pic" width="500px;">
-    <div style="max-height:500px;overflow-y:auto;">
-      <div>
-        <h3>设备图片</h3>
-        <upload-imgs :readOnly="read" :keysArr="picArrs" @change="imageItem" max="6"></upload-imgs>
-      </div>
-      <div>
-        <h3>视频</h3>
-        <upload-imgs
-          :accept="'video/*'"
-          type="video"
-          :keysArr="videoArr"
-          @change="videoItem"
-          :videoPicArr="videoPicArr"
-          max="2"
-          :readOnly="read"
-        ></upload-imgs>
-      </div>
-    </div>
-  </el-dialog>
+    <el-dialog title="上传图片" :visible.sync="dialog.pic" width="500px;">
+        <div style="max-height:500px;overflow-y:auto;">
+            <div>
+                <h3>设备图片</h3>
+                <upload-imgs
+                    :readOnly="read"
+                    :keysArr="picArrs"
+                    @change="imageItem"
+                    max="6"
+                />
+            </div>
+            <div>
+                <h3>视频</h3>
+                <upload-imgs
+                    :accept="'video/*'"
+                    type="video"
+                    :keysArr="videoArr"
+                    @change="videoItem"
+                    :videoPicArr="videoPicArr"
+                    max="2"
+                    :readOnly="read"
+                />
+            </div>
+        </div>
+    </el-dialog>
 </template>
 <script>
-import uploadImgs from "@/components/ledger/lib/uploadImgsName";
-import tools from "@/utils/scan/tools"
-export default {
-  components: {
-    uploadImgs
-  },
-  props: {
-    dialog: {
-      type: Object,
-      default: function () {
-        return {
-          pic: true
-        };
-      }
-    },
-    keysArr: {
-      type: Array,
-      default: function () {
-        return []
-      }
-    },
-    read: {
-      type: Boolean,
-      default: false
-    }
-  },
-  data() {
-    return {
-      picArrs: [],
-      panoramaArr: [],
-      videoArr: [],
-      videoPicArr: [],
-      changeKeys: []
-    };
-  },
-  created() { },
-  mounted() { },
-  methods: {
-    imageItem(images) {
-      this.picArrs = images
-      this.change()
-    },
+    import uploadImgs from "@/components/ledger/lib/uploadImgsName";
+
+    export default {
+        components: {
+            uploadImgs
+        },
+        props: {
+            dialog: {
+                type: Object,
+                default: function () {
+                    return {
+                        pic: true
+                    };
+                }
+            },
+            keysArr: {
+                type: Array,
+                default: function () {
+                    return []
+                }
+            },
+            read: {
+                type: Boolean,
+                default: false
+            },
+            firmDataType: {
+                type: String
+            },
+            information: {
+                type: Object
+            },
+            infoType: {
+                type: String
+            }
+        },
+        data() {
+            return {
+                picArrs: [],
+                panoramaArr: [],
+                videoArr: [],
+                videoPicArr: [],
+                changeKeys: []
+            };
+        },
+        created() {
+        },
+        mounted() {
+        },
+        methods: {
+            imageItem(images) {
+                this.picArrs = images
+                this.change()
+            },
 
-    panoramaItem(images) {
-      this.panoramaArr = images
-      this.change()
-    },
+            panoramaItem(images) {
+                this.panoramaArr = images
+                this.change()
+            },
 
-    videoItem(videos, pe, pics) {
-      this.videoArr = videos
-      this.videoPicArr = pics
-      this.change()
-    },
+            videoItem(videos, pe, pics) {
+                this.videoArr = videos
+                this.videoPicArr = pics
+                this.change()
+            },
 
-    change() {
-      //   let picsArr = this.getArr(this.picArrs, "设备图片", "image")
-      //   let videos = this.getArr(this.videoArr, "视频", "video")
-      //   let videoPics = this.getArr(this.videoPicArr, "视频资料", "image_video")
-      //   let panoramas = this.getArr(this.panoramaArr, "全景照片", "panorama")
-      let picsArr = this.picArrs
-      let videos = this.videoArr
-      let videoPics = this.videoPicArr
-      let panoramas = this.panoramaArr
-      this.changeKeys = picsArr.concat(videos).concat(videoPics).concat(panoramas)
-      console.log(this.changeKeys)
-      this.$emit("change", this.changeKeys)
-    },
+            change() {
+                //   let picsArr = this.getArr(this.picArrs, "设备图片", "image")
+                //   let videos = this.getArr(this.videoArr, "视频", "video")
+                //   let videoPics = this.getArr(this.videoPicArr, "视频资料", "image_video")
+                //   let panoramas = this.getArr(this.panoramaArr, "全景照片", "panorama")
+                let picsArr = this.picArrs
+                let videos = this.videoArr
+                let videoPics = this.videoPicArr
+                let panoramas = this.panoramaArr
+                this.changeKeys = picsArr.concat(videos).concat(videoPics).concat(panoramas)
+                if (this.firmDataType === 'dialog') {
+                    this.information.pic.Pic = this.changeKeys
+                    this.$emit("change",this.information,this.firmDataType)
+                } else {
+                    this.$emit("change", this.changeKeys)
 
-    getArr(arr, name, type) {
-      return arr.map(item => {
-        return { "systemId": "dataPlatform", "name": name, "type": type, "key": item }
-      })
-    },
+                }
+            },
 
-    //将父组件传来的数据进行分组
-    fatherTochild() {
-      this.panoramaArr = []
-      this.videoArr = []
-      this.videoPicArr = []
-      this.picArrs = []
-      if (this.keysArr instanceof Array) {
-        this.keysArr.map(item => {
-          if (item.type == 'panorama') {
-            this.panoramaArr.push(item)
-          } else if (item.type == "video") {
-            this.videoArr.push(item)
-          } else if (item.type == 'image_video') {
-            this.videoPicArr.push(item)
-          } else {
-            this.picArrs.push(item)
-          }
-        })
-      } else {
-        this.panoramaArr = []
-        this.videoArr = []
-        this.videoPicArr = []
-        this.picArrs = []
-      }
-    }
-  },
-  watch: {
-    dialog: {
-      deep: true,
-      handler: function () {
-        if (this.dialog.pic) {
-          this.fatherTochild()
+            getArr(arr, name, type) {
+                return arr.map(item => {
+                    return {"systemId": "dataPlatform", "name": name, "type": type, "key": item}
+                })
+            },
+
+            //将父组件传来的数据进行分组
+            fatherTochild() {
+                this.panoramaArr = []
+                this.videoArr = []
+                this.videoPicArr = []
+                this.picArrs = []
+                if (this.keysArr instanceof Array) {
+                    this.keysArr.map(item => {
+                        if (item.type == 'panorama') {
+                            this.panoramaArr.push(item)
+                        } else if (item.type == "video") {
+                            this.videoArr.push(item)
+                        } else if (item.type == 'image_video') {
+                            this.videoPicArr.push(item)
+                        } else {
+                            this.picArrs.push(item)
+                        }
+                    })
+                } else {
+                    this.panoramaArr = []
+                    this.videoArr = []
+                    this.videoPicArr = []
+                    this.picArrs = []
+                }
+            }
+        },
+        watch: {
+            dialog: {
+                deep: true,
+                handler: function () {
+                    if (this.dialog.pic) {
+                        this.fatherTochild()
+                    }
+                }
+            }
         }
-      }
-    }
-  }
-};
+    };
 </script>
 <style>
-</style>
+</style>

+ 110 - 106
src/components/dialogs/list/supplierDialog.vue

@@ -38,7 +38,7 @@
                 <i style="color:#46B0FF;cursor: pointer;">厂家库</i>维护吧
             </p>
             <my-pagination :page="page" @change="changePage" style="margin-top:10px;"></my-pagination>
-        </div>        
+        </div>
       </div>
     </div>
     <div slot="footer" class="footer">
@@ -50,119 +50,123 @@
   </el-dialog>
 </template>
 <script>
-import myPagination from "@/components/ledger/lib/myPagination";
-import { mapGetters } from "vuex";
-import { getLib } from "@/api/scan/request"
-import tools from "@/utils/scan/tools"
+    import myPagination from "@/components/ledger/lib/myPagination";
+    import {mapGetters} from "vuex";
+    import {getLib} from "@/api/scan/request"
+    import tools from "@/utils/scan/tools"
 
-export default {
-  components: {
+    export default {
+        components: {
     myPagination
   },
-  props: {
-    dialog: {
-      type: Object,
-      default: function () {
-        return {
-          supplier: true
-        };
-      }
-    }
-  },
-  data() {
-    return {
-      search: "", //搜索文案
-      radio: "",
-      tableData: [],
-      page: {
-        size: 50,
-        sizes: [10, 30, 50, 100, 150, 200],
-        total: 0,
-        currentPage: 1
-      }
-    };
-  },
-  computed: {
-    ...mapGetters("layout", ["projectId", "secret", "userId"]),
-  },
-  created() {
-    // this.getData()
-  },
-  mounted() { },
-  methods: {
-    //过滤
-    filterSearch() {
-      this.tableData = this.allData.map(item => {
-        if (item.name.indexOf(this.search) != -1) {
-          return item
-        } else {
-          return undefined
-        }
-      }).filter(cb => cb)
-    },
-    getData() {
-      this.page = {
-        size: 50,
-        sizes: [10, 30, 50, 100, 150, 200],
-        total: 0,
-        currentPage: 1
-      }
-      getLib({ "type": ["supplier"] }).then(res => {
-        if (res.data.result == "success") {
-          let data = res.data.content.supplier.map(item => {
-            if (item.contacts && item.contacts.length) {
-              item.contacts.map(child => {
-                if (child.projectId == this.projectId) {
-                  item.phone = child.phone
-                  item.man = child.name
-                  item.fox = child.fox
-                  item.email = child.email
+        props: {
+            dialog: {
+                type: Object,
+                default: function () {
+                    return {
+                        supplier: true
+                    };
                 }
-                return child
-              })
-            }
-            if (!item.man) {
-              item.man = "--"
-              item.phone = "--"
-              item.fox = "--"
-              item.email = "--"
+            },
+            firmDataType: {
+                type: String
             }
-            return item
-          })
-          this.allData = tools.deepCopy(data)
-          this.tableData = this.pagination(this.page.currentPage, this.page.size, this.allData)
-          this.page.total = data.length
-        } else {
-          this.$message.error("请求失败:" + res.data.resultMsg)
-        }
-      })
-    },
+        },
+        data() {
+            return {
+                search: "", //搜索文案
+                radio: "",
+                tableData: [],
+                page: {
+                    size: 50,
+                    sizes: [10, 30, 50, 100, 150, 200],
+                    total: 0,
+                    currentPage: 1
+                }
+            };
+        },
+        computed: {
+            ...mapGetters("layout", ["projectId", "secret", "userId"]),
+        },
+        created() {
+            // this.getData()
+        },
+        mounted() {
+        },
+        methods: {
+            //过滤
+            filterSearch() {
+                this.tableData = this.allData.map(item => {
+                    if (item.name.indexOf(this.search) != -1) {
+                        return item
+                    } else {
+                        return undefined
+                    }
+                }).filter(cb => cb)
+            },
+            getData() {
+                this.page = {
+                    size: 50,
+                    sizes: [10, 30, 50, 100, 150, 200],
+                    total: 0,
+                    currentPage: 1
+                }
+                getLib({"type": ["supplier"]}).then(res => {
+                    if (res.data.result == "success") {
+                        let data = res.data.content.supplier.map(item => {
+                            if (item.contacts && item.contacts.length) {
+                                item.contacts.map(child => {
+                                    if (child.projectId == this.projectId) {
+                                        item.phone = child.phone
+                                        item.man = child.name
+                                        item.fox = child.fox
+                                        item.email = child.email
+                                    }
+                                    return child
+                                })
+                            }
+                            if (!item.man) {
+                                item.man = "--"
+                                item.phone = "--"
+                                item.fox = "--"
+                                item.email = "--"
+                            }
+                            return item
+                        })
+                        this.allData = tools.deepCopy(data)
+                        this.tableData = this.pagination(this.page.currentPage, this.page.size, this.allData)
+                        this.page.total = data.length
+                    } else {
+                        this.$message.error("请求失败:" + res.data.resultMsg)
+                    }
+                })
+            },
 
-    //分页改变
-    changePage() {
-      this.pagination(this.page.currentPage, this.page.size, this.allData)
-    },
+            //分页改变
+            changePage() {
+                this.pagination(this.page.currentPage, this.page.size, this.allData)
+            },
 
-    //发生修改
-    getChange() {
-      if (!!this.radio) {
-        this.$emit("changeSupplier", this.radio)
-        this.dialog.supplier = false
-        this.radio = ''
-      } else {
-        this.$message("请选择一个生产厂商")
-      }
-    },
+            //发生修改
+            getChange() {
+                if (!!this.radio) {
+                    this.$emit("changeSupplier", this.radio, this.firmDataType)
+                    this.dialog.supplier = false
+                    this.radio = ''
+                } else {
+                    this.$message("请选择一个生产厂商")
+                }
+            },
 
-    //分页事件
-    pagination(pageNo, pageSize, array) {
-      let offset = (pageNo - 1) * pageSize;
-      return offset + pageSize >= array.length
-        ? array.slice(offset, array.length)
-        : array.slice(offset, offset + pageSize);
-    }
-  },
-  watch: {
+            //分页事件
+            pagination(pageNo, pageSize, array) {
+                let offset = (pageNo - 1) * pageSize;
+                return offset + pageSize >= array.length
+                    ? array.slice(offset, array.length)
+                    : array.slice(offset, offset + pageSize);
+            }
+        },
+        watch: {
     dialog: {
       deep: true,
       handler: function () {

+ 68 - 34
src/components/dialogs/list/uploadImgDialog.vue

@@ -10,47 +10,81 @@
   </el-dialog>
 </template>
 <script>
-import uploadImgs from "@/components/ledger/lib/uploadImgs";
-export default {
-  components: {
-    uploadImgs
-  },
-  props: {
-    dialog: {
-      type: Object,
-      default: function () {
-        return {
-          uploadImgs: true
-        };
-      }
-    },
-    keysArr: {
-      type: Array,
-      default: function () {
-        return []
-      }
-    },
-    read: {
-      type: Boolean,
-      default: false
-    }
-  },
-  data() {
-    return {};
-  },
-  created() { },
-  mounted() { },
-  methods: {
+    import uploadImgs from "@/components/ledger/lib/uploadImgs";
+
+    export default {
+        components: {
+            uploadImgs
+        },
+        props: {
+            dialog: {
+                type: Object,
+                default: function () {
+                    return {
+                        uploadImgs: true
+                    };
+                }
+            },
+            keysArr: {
+                type: Array,
+                default: function () {
+                    return []
+                }
+            },
+            read: {
+                type: Boolean,
+                default: false
+            },
+            firmDataType: {
+                type: String
+            },
+            information: {
+                type: Object
+            },
+            infoType: {
+                type: String
+            }
+        },
+        data() {
+            return {};
+        },
+        created() {
+        },
+        mounted() {
+        },
+        methods: {
     deepcopy(obj) {
       console.log(obj, "out")
       return JSON.parse(JSON.stringify(obj));
     },
     changeItem(file) {
-      console.log(file, "changed")
-      this.$emit("changeFile", file)
+        if (this.firmDataType === 'dialog') {
+            let info = this.infoType
+            switch (info) {
+                case 'installPic':
+                    this.information.installPic.InstallPic = file
+                    this.$emit('changeFile', this.information, this.firmDataType)
+                    break
+                case 'installDrawing':
+                    this.information.installDrawing.InstallDrawing = file
+                    this.$emit('changeFile', this.information, this.firmDataType)
+                    break
+                case 'nameplate':
+                    this.information.nameplate.Nameplate = file
+                    this.$emit('changeFile', this.information, this.firmDataType)
+                    break
+                case 'drawing':
+                    this.information.drawing.Drawing = file
+                    this.$emit('changeFile', this.information, this.firmDataType)
+                    break
+            }
+        } else {
+            this.$emit("changeFile", file)
+        }
+
     }
   },
 };
 </script>
 <style>
-</style>
+</style>

+ 1 - 1
src/components/echarts/doughnut.vue

@@ -1,5 +1,5 @@
 <template>
-    <div style="width:100%;height:100%;" :id="id">
+    <div style="width:100%;height:100%;textAlign:center;" :id="id">
     </div>
 </template>
 <script>

+ 99 - 0
src/components/echarts/fanChart.vue

@@ -0,0 +1,99 @@
+<template>
+  <!-- 饼图 -->
+  <div style="width:100%;height:100%;textAlign:center;margin:-15px 0;" :id="id">
+  </div>
+</template>
+<script>
+import echarts from "echarts"
+export default {
+  name: "doughnut",
+  props: {
+    id: {
+      type: String,
+      default: function createRandomId() {
+        return (Math.random() * 10000000).toString(16).substr(0, 4) + '-' + (new Date()).getTime() + '-' + Math.random().toString().substr(2, 5);
+      }
+    },
+    renderData: {
+      type: Array,
+      default: function () {
+        return []
+      }
+    },
+    type: {},
+    name: "",
+    sum: ""
+  },
+  data() {
+    return {
+      myCharts: null
+    }
+  },
+  created() { },
+  mounted() {
+    this.drawDoughnut()
+  },
+  methods: {
+    drawDoughnut() {
+      let options = {
+        tooltip: {
+          trigger: 'item',
+          formatter: ""
+        },
+        series: [
+          {
+            // name: '占比',
+            type: 'pie',
+            radius: '55%',
+            center: ['50%', '60%'],
+            data: this.renderData,
+            label: {
+              normal: {
+                show: true,
+                position: 'outside',
+                textStyle: {
+                  fontSize: '11'
+                }
+              },
+              emphasis: {
+                show: true
+              }
+            },
+            labelLine: {
+              normal: {
+                show: true,
+                length: 20,
+                lineStyle: {
+                  color: '#999'
+                }
+              },
+              emphasis: {
+                show: true
+              }
+            }
+          },
+        ],
+      }
+      this.myCharts = echarts.init(document.getElementById(this.id))
+      this.myCharts.setOption(options)
+    },
+    delName(val) {
+      if (!!val && val.length > 3) {
+        return val.substring(0, 3) + '...'
+      } else {
+        return ''
+      }
+    }
+  },
+  watch: {
+    renderData: {
+      deep: true,
+      handler: function () {
+        this.drawDoughnut()
+      }
+    }
+  }
+}
+</script>
+<style>
+</style>

+ 123 - 0
src/components/echarts/reportDoughnut.vue

@@ -0,0 +1,123 @@
+<template>
+  <div style="width:100%;height:100%;textAlign:center;" :id="id">
+  </div>
+</template>
+<script>
+import echarts from "echarts"
+export default {
+  name: "doughnut",
+  props: {
+    id: {
+      type: String,
+      default: function createRandomId() {
+        return (Math.random() * 10000000).toString(16).substr(0, 4) + '-' + (new Date()).getTime() + '-' + Math.random().toString().substr(2, 5);
+      }
+    },
+    renderData: {
+      type: Array,
+      default: function () {
+        return []
+      }
+    },
+    text: {
+      type: String,
+      default: function () {
+        return []
+      }
+    },
+    type: {},
+    name: "",
+    sum: ""
+  },
+  created(){
+  },
+  data() {
+    return {
+      myCharts: null
+    }
+  },
+  created() { },
+  mounted() {
+    this.drawDoughnut()
+  },
+  methods: {
+    drawDoughnut() {
+      let options = {
+        tooltip: {
+          trigger: 'item',
+          formatter: "{b}"
+        },
+        legend: {
+          show: false,
+          orient: 'vertical',
+          right: 10,
+          top: 30,
+          bottom: 20,
+          data: this.renderData.map(item => {
+            return item.name
+          })
+        },
+        series: [{
+          name: '',
+          type: 'pie',
+          radius: ['40%', '60%'],
+          itemStyle: {
+            normal: {
+              label: {
+                show: this.type != 'left' ? false : true,
+                textStyle: {
+                  color: '#3c4858',
+                  fontSize: "12"
+                },
+                formatter: function (val) { //让series 中的文字进行换行
+                  return val.name.split("-")[0];
+                }
+              },
+              title: {
+                text: 'aaaa'
+              },
+              labelLine: {
+                show: this.type != 'left' ? false : true,
+                lineStyle: {
+                }
+              }
+            },
+            emphasis: {
+              shadowBlur: 5,
+              shadowOffsetX: 0,
+              shadowColor: 'rgba(0, 0, 0, 0.5)',
+              textColor: '#000'
+            }
+          },
+          data: this.renderData
+        }],
+        color: ['#67C23A', 'rgb(225, 243, 216)', 'rgb(244, 244, 245)']
+      }
+      options.graphic = {
+        type: 'text',
+        left: 'center',
+        top: 'center',
+        style: {
+          text: `${this.text|| ''}`,
+          textAlign: 'center',
+          fill: '#000',
+          width: 30,
+          height: 30
+        }
+      }
+      this.myCharts = echarts.init(document.getElementById(this.id))
+      this.myCharts.setOption(options)
+    }
+  },
+  watch: {
+    renderData: {
+      deep: true,
+      handler: function () {
+        this.drawDoughnut()
+      }
+    }
+  }
+}
+</script>
+<style>
+</style>

+ 516 - 0
src/components/globaluploader/index.vue

@@ -0,0 +1,516 @@
+<!--
+ * @Author: zhangyu
+ * @Date: 2019-11-28 10:05:28
+ * @Info: 
+ * @LastEditTime : 2019-12-25 17:48:31
+ -->
+<template>
+  <div id="global-uploader">
+
+    <!-- 上传 -->
+    <uploader
+        ref="uploader"
+        :options="options"
+        :autoStart="false"
+        @file-added="onFileAdded"
+        @file-success="onFileSuccess"
+        @file-progress="onFileProgress"
+        @file-error="onFileError"
+        @file-removed="onFileRemoved"
+        class="uploader-app">
+      <uploader-unsupport></uploader-unsupport>
+
+      <uploader-btn id="global-uploader-btn" :attrs="attrs" ref="uploadBtn">选择文件</uploader-btn>
+
+      <uploader-list v-show="panelShow">
+        <div class="file-panel" slot-scope="props" :class="{'collapse': collapse}">
+          <div class="file-title">
+            <h2>文件列表</h2>
+            <div class="operate">
+              <el-button @click="fileListShow" style="color:#999;" type="text" :title="collapse ? '折叠':'展开' ">
+                <i class="iconfont" :class="collapse ? 'icon-bottom': 'icon-top'"></i>
+              </el-button>
+              <el-button @click="close" style="color:#999;" type="text" title="关闭">
+                <i class="iconfont icon-guanbi"></i>
+              </el-button>
+            </div>
+          </div>
+
+          <ul class="file-list" v-show="collapse">
+            <el-scrollbar style="height:100%;">
+              <li v-for="file in props.fileList" :key="file.id">
+                <uploader-file :class="'file_' + file.id" ref="files" :file="file" :list="true"></uploader-file>
+              </li>
+              <div class="no-file" v-if="!props.fileList.length"><i class="iconfont icon-wushuju"></i> 暂无待上传文件</div>
+            </el-scrollbar>
+          </ul>
+        </div>
+      </uploader-list>
+
+    </uploader>
+
+  </div>
+</template>
+
+<script>
+/**
+ *   全局上传插件
+ *   调用方法:Bus.$emit('openUploader', {}) 打开文件选择框,参数为需要传递的额外参数
+ *   监听函数:Bus.$on('fileAdded', fn); 文件选择后的回调
+ *            Bus.$on('fileSuccess', fn); 文件上传成功的回调
+ */
+
+import Bus from '@/utils/bus.js';
+import SparkMD5 from 'spark-md5';
+import { getUploadId, mergeMultipart } from '@/api/uploader';
+import request from "@/api/model/file.js";
+import { mapGetters, mapMutations } from 'vuex'
+
+export default {
+  data() {
+    return {
+      options: {
+        target: '/image-service/common/multipart_upload',
+        chunkSize: 1*1024*1024,
+        fileParameterName: 'file',
+        maxChunkRetries: 3,
+        testChunks: false,   //是否开启服务器分片校验
+        // 服务器分片校验函数,秒传及断点续传基础
+        // checkChunkUploadedByResponse: function (chunk, message) {
+        //   let objMessage = JSON.parse(message);
+        //   if (objMessage.skipUpload) {
+        //     return true;
+        //   }
+
+        //   return (objMessage.uploaded || []).indexOf(chunk.offset + 1) >= 0
+        // },
+        // headers: {
+          // Authorization: Ticket.get() && "Bearer " + Ticket.get().access_token
+        // },
+        query: this.getFileQuery
+      },
+      attrs: {
+        // accept: ACCEPT_CONFIG.getAll()
+      },
+      panelShow: false,   //选择文件后,展示上传panel
+      collapse: false,
+    }
+  },
+  mounted() {
+    Bus.$on('openUploader', (query, file) => {
+      if(!this.uploaderList.some(item => {return item.name === file.name})){
+        if(query.uploadId){
+        // this.params = query || {};
+          file.uploadId = query.uploadId
+          file.modelId = query.modelId? query.modelId: ''
+          this.uploader.addFile(file)
+          this.setUploaderList(this.uploader.files.map(item => {
+            item.modelId = item.file.modelId?item.file.modelId:''
+            return item
+          }))
+        } else {
+          getUploadId({
+            systemId: query.systemId?query.systemId:'revit', 
+            secret: query.secret?query.secret:'63afbef6906c342b', 
+            overwrite: query.overwrite? query.overwrite: false,
+            key: file.name
+          }, res => {
+            if(res.UploadId){
+              // this.params = Object.assign(query, { uploadId: res.UploadId }) || {};
+              file = Object.assign(file, {
+                ...query,
+                uploadId: res.UploadId 
+              })
+              this.uploader.addFile(file)
+              this.setUploaderList(this.uploader.files.map(item => {
+                item.modelId = item.file.modelId?item.file.modelId:'';
+                return item
+              }))
+            } else {
+              this.$message.error(`请求分片上传接口失败!`);
+            }
+          })
+        }
+      }else {
+        this.$message.error(`该文件在上传列表中已存在!`);
+      }
+
+      // if (this.$refs.uploadBtn) {
+      //   document.getElementById('global-uploader-btn').click();
+      //   // $('#global-uploader-btn').click();
+      // }
+    });
+  },
+  computed: {
+    ...mapGetters('layout', ['uploaderList']),
+    //Uploader实例
+    uploader() {
+      return this.$refs.uploader.uploader;
+    }
+  },
+  methods: {
+    ...mapMutations('layout', ['setUploaderList']),
+    onFileAdded(file) {
+      this.panelShow = true;
+      this.collapse = true;
+      this.computeMD5(file);
+
+      Bus.$emit('fileAdded');
+    },
+    onFileProgress(rootFile, file, chunk) {
+      console.log(`上传中 ${file.name},chunk:${chunk.startByte / 1024 / 1024} ~ ${chunk.endByte / 1024 / 1024}`)
+    },
+    onFileSuccess(rootFile, file, response, chunk) {
+      let res = JSON.parse(response);
+
+      // 服务器自定义的错误(即虽返回200,但是是错误的情况),这种错误是Uploader无法拦截的
+      if (!res.Result || res.Result != 'success') {
+        this.$message({ message: res.ResultMsg?res.ResultMsg:'上传失败!', type: 'error' });
+        // 文件状态设为“失败”
+        this.statusSet(file.id, 'failed');
+        return
+      }
+      // 如果服务端返回需要合并
+      console.log('获取分片数',file.chunks.length)
+      if (parseInt(res.TotalCount) >= file.chunks.length) {
+        // 文件状态设为“合并中”
+        this.statusSet(file.id, 'merging');
+        if(file.file.modelId){
+          //模型文件合并专用接口
+          request.mergeModelFile({ ModelId: file.file.modelId, UploadId: file.file.uploadId }, res => {
+            Bus.$emit('modelStatusChange')
+            // 文件合并成功
+            Bus.$emit('fileSuccess');
+            this.statusRemove(file.id);
+          })
+        } else {
+          mergeMultipart({
+            systemId: file.file.systemId?file.file.systemId:'revit', 
+            secret: file.file.secret?file.file.secret:'63afbef6906c342b', 
+            uploadId: file.file.uploadId
+          }, res => {
+            // 文件合并成功
+            Bus.$emit('fileSuccess');
+            this.statusRemove(file.id);
+          })
+        }
+
+      // 不需要合并
+      } else {
+        Bus.$emit('fileSuccess');
+        console.log('上传成功');
+      }
+    },
+    onFileError(rootFile, file, response, chunk) {
+      this.$message({
+        message: response,
+        type: 'error'
+      })
+    },
+    onFileRemoved(file) {
+      this.uploaderList.splice(this.uploaderList.findIndex(item => {
+        return item.id == file.id;
+      },1))
+      this.setUploaderList(this.uploaderList);
+      if(file.modelId && !file.isComplete()) {
+        request.deleteModelFileList({Id: file.modelId, Force: true}, res => {
+          console.log('删除错误模型:',file.modelId);
+          Bus.$emit('modelStatusChange')
+        })
+      }
+    },
+
+    /**
+     * 计算md5,实现断点续传及秒传
+     * @param file
+     */
+    computeMD5(file) {
+      let fileReader = new FileReader();
+      let time = new Date().getTime();
+      let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
+      let currentChunk = 0;
+      const chunkSize = 1 * 1024 * 1024;
+      let chunks = Math.floor(file.size / chunkSize);
+      let spark = new SparkMD5.ArrayBuffer();
+
+      // 文件状态设为"计算MD5"
+      this.statusSet(file.id, 'md5');
+      file.pause();
+
+      loadNext();
+
+      fileReader.onload = (e => {
+        spark.append(e.target.result);
+
+        if (currentChunk < chunks) {
+          currentChunk++;
+          loadNext();
+
+          // 实时展示MD5的计算进度
+          this.$nextTick(() => {
+            document.getElementsByClassName(`myStatus_${file.id}`)[0].innerText = '校验MD5 '+ ((currentChunk/chunks)*100).toFixed(0)+'%'
+            // $(`.myStatus_${file.id}`).text('校验MD5 '+ ((currentChunk/chunks)*100).toFixed(0)+'%')
+          })
+        } else {
+          let md5 = spark.end();
+          file.file.md5 = md5;
+          this.computeMD5Success(md5, file);
+          console.log(`MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${file.size} 用时:${new Date().getTime() - time} ms`);
+        }
+      });
+
+      fileReader.onerror = function () {
+        this.error(`文件${file.name}读取出错,请检查该文件`)
+        file.cancel();
+      };
+
+      function loadNext() {
+        let start = currentChunk * chunkSize;
+        let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
+
+        fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
+      }
+    },
+
+    computeMD5Success(md5, file) {
+      // 将自定义参数直接加载uploader实例的opts上
+      console.log(this.uploader)
+      // Object.assign(this.uploader.opts, {
+      //   query: {
+      //     uploadId: file.file.uploadId,
+      //     md5
+      //   }
+      // })
+
+      // file.uniqueIdentifier = this.params.uploadId;
+      file.resume();
+      this.statusRemove(file.id);
+    },
+
+    //获取文件参数
+    getFileQuery(file, chunk) {
+      return {
+        uploadId: file.file.uploadId,
+        md5: file.file.md5
+      }
+    },
+
+    fileListShow() {
+      this.collapse = this.collapse? false: true;
+
+      // let $list = $('#global-uploader .file-list');
+      // let $list = document.querySelector('#global-uploader .file-list')
+
+      // if ($list.style.display == '' && $list.style.display == 'none') {
+      //   $list.style.display == 'block';//显示
+      //   this.collapse = false;
+      //   // $list.slideUp();//隐藏
+      //   // this.collapse = true;
+      // } else {
+      //   $list.style.display == 'none';//隐藏
+      //   this.collapse = true;
+      //   // $list.slideDown();//显示
+      //   // this.collapse = false;
+      // }
+    },
+    close() {
+      if(this.uploader.isUploading()) {
+        this.$alert(
+          "您有文件正在上传,关闭会中断上传,是否继续?",
+          "提示",
+          {
+            confirmButtonText: "确定",
+            callback: action => {
+              console.log(action);
+              if (action == "confirm") {
+                this.uploader.cancel();
+                this.panelShow = false;
+                this.uploader.files = [];
+                this.setUploaderList([]);
+                Bus.$emit('modelStatusChange')
+              } else { }
+            }
+          }
+        );
+      } else {
+        this.uploader.cancel();
+        this.panelShow = false;
+      }
+    },
+
+    /**
+     * 新增的自定义的状态: 'md5'、'transcoding'、'failed'
+     * @param id
+     * @param status
+     */
+    statusSet(id, status) {
+      let statusMap = {
+        md5: {
+          text: '校验MD5',
+          bgc: '#fff'
+        },
+        merging: {
+          text: '合并中',
+          bgc: '#e2eeff'
+        },
+        transcoding: {
+          text: '转码中',
+          bgc: '#e2eeff'
+        },
+        failed: {
+          text: '上传失败',
+          bgc: '#e2eeff'
+        }
+      }
+
+      this.$nextTick(() => {
+        let node = document.createElement("P");
+        let att = document.createAttribute("class");
+        att.value = `status_style myStatus_${id}`;
+        let text = document.createTextNode(`${statusMap[status].text}`);
+	      node.appendChild(text);
+        node.setAttributeNode(att);
+        node.style.backgroundColor = `${statusMap[status].bgc}`
+        document.querySelector(`.file_${id} .uploader-file-status`).appendChild(node);
+
+        // $(`<p class="myStatus_${id}"></p>`).appendTo(`.file_${id} .uploader-file-status`).css({
+        //   'position': 'absolute',
+        //   'top': '0',
+        //   'left': '0',
+        //   'right': '0',
+        //   'bottom': '0',
+        //   'zIndex': '1',
+        //   'backgroundColor': statusMap[status].bgc
+        // }).text(statusMap[status].text);
+      })
+    },
+    statusRemove(id) {
+      this.$nextTick(() => {
+        let dom = document.getElementsByClassName(`myStatus_${id}`)[0];
+        dom.parentNode.removeChild(dom);
+      })
+    },
+
+    error(msg) {
+      this.$notify({
+        title: '错误',
+        message: msg,
+        type: 'error',
+        duration: 2000
+      })
+    }
+  },
+  watch: {},
+  destroyed() {
+    Bus.$off('openUploader');
+  },
+  components: {}
+}
+</script>
+
+<style scoped lang="scss">
+#global-uploader {
+  position: fixed;
+  z-index: 101;
+  top: auto;
+  right: 15px;
+  bottom: 0;
+
+  .uploader-app {
+    width: 633px;
+  }
+
+  .file-panel {
+    background-color: #fff;
+    border: 1px solid #e2e2e2;
+    border-radius: 7px 7px 0 0;
+    box-shadow: 0 0 10px rgba(0, 0, 0, .2);
+
+    .file-title {
+      display: flex;
+      height: 40px;
+      line-height: 40px;
+      padding: 0 15px;
+      border-bottom: 1px solid #ddd;
+      h2{
+        font-size: 14px;
+        font-style: normal;
+        cursor: text;
+        font-weight: 200;
+        color: #666;
+      }
+
+      .operate {
+        flex: 1;
+        text-align: right;
+      }
+    }
+
+    .file-list {
+      position: relative;
+      height: 350px;
+      overflow-x: hidden;
+      overflow-y: auto;
+      background-color: #fff;
+      /deep/ .el-scrollbar__wrap{
+        overflow-x: hidden;
+      }
+
+      > li {
+        background-color: #fff;
+      }
+      /deep/ .uploader-file-info i{
+        display: none;
+      }
+      /deep/ .status_style{
+        position: absolute;
+        top: 0;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        z-index: 1;
+      }
+    }
+
+    // &.collapse {
+    //   .file-title {
+    //     background-color: #E7ECF2;
+    //   }
+    // }
+  }
+
+  .no-file {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    font-size: 16px;
+    text-align: center;
+  }
+
+  /deep/.uploader-file-icon {
+    &:before {
+      content: '' !important;
+    }
+
+    // &[icon=image] {
+    //   background: url(./images/image-icon.png);
+    // }
+    // &[icon=video] {
+    //   background: url(./images/video-icon.png);
+    // }
+    // &[icon=document] {
+    //   background: url(./images/text-icon.png);
+    // }
+  }
+
+  /deep/ .uploader-file-actions > span {
+    margin-right: 6px;
+  }
+}
+/* 隐藏上传按钮 */
+#global-uploader-btn {
+  position: absolute;
+  clip: rect(0, 0, 0, 0);
+}
+</style>

+ 1 - 1
src/components/ledger/addDialog/dialogAssets.vue

@@ -508,7 +508,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该资产"

+ 2 - 2
src/components/ledger/addDialog/dialogDevice.vue

@@ -612,7 +612,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该业务空间"
@@ -958,7 +958,7 @@ export default {
     overflow: hidden;
     // height: 300px;
     // overflow-x: hidden;
-    // overflow-y:auto; 
+    // overflow-y:auto;
 
 }
 </style>

+ 1 - 1
src/components/ledger/addDialog/dialogSystem.vue

@@ -570,7 +570,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该资产"

+ 223 - 0
src/components/ledger/cenote/dialog/addSpaceDialog.vue

@@ -0,0 +1,223 @@
+
+<template>
+  <el-dialog :title="title" :visible.sync="dialog" :before-close="handleClose" width="900px" id="addEqDialog">
+    <el-row class="filters">
+      <el-col :span="7" style="width:268px;padding:0px;">
+        <el-input style placeholder="输入业务空间名称、本地编码进行查询" v-model="keycode" clearable @keyup.enter.native="getTableData">
+          <i slot="suffix" class="el-input__icon el-icon-search" @click="getTableData"></i>
+        </el-input>
+      </el-col>
+      <el-col :span="8.5" style="padding:0 0;margin-left:-2px">
+        <floor-cascader ref="floorcas" @change="changeFloor"></floor-cascader>
+      </el-col>
+      <el-col :span="7.5" style="padding:0 0;">
+        <space-select ref="spacesel" @change="changeSpace"></space-select>
+      </el-col>
+    </el-row>
+    <el-row class="filters" :gutter="20"></el-row>
+    <div class="table-box">
+      <el-table :data="tableData" style="width: 100%" height="350" v-loading="loading" :header-cell-style="headerStyle" ref="multipleTable"
+        @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55"></el-table-column>
+        <el-table-column :label="`${inSpaceType}本地名称`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            {{scope.row.RoomLocalName||scope.row.RoomName||''}}
+          </template>
+        </el-table-column>
+        <el-table-column prop="RoomLocalID" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop :label="`所属建筑楼层`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            {{ scope.row.BuildingId && floorType[scope.row.BuildingId]? ((floorType[scope.row.BuildingId] || '') + (scope.row.FloorId && floorType[scope.row.FloorId] ? (' - ' + floorType[scope.row.FloorId] || '') : '')) : ''}}
+          </template>
+        </el-table-column>
+        <el-table-column prop="ObjectType" :label="`空间类型`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            {{spaceType[scope.row.ObjectType] || ''}}
+          </template>
+        </el-table-column>
+        <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <el-button size="mini" @click="toDetail(scope.$index, scope.row)" plain>查看详情</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <el-pagination class="fr" v-show="tableData && tableData.length" @size-change="handleSizeChange" @current-change="handleCurrentChange"
+        :current-page="page.pageNumber" :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper"
+        :total="page.total"></el-pagination>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button size="small" @click="handleClose">取 消</el-button>
+      <el-button size="small" type="primary" @click="savaRelation">确 定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import {
+  shaftUnlinkSpaceQuery,
+  unSysZoneSpace,
+  linkShaftSpace
+} from "@/api/scan/request";
+import floorCascader from "@/components/ledger/lib/floorCascader";
+import dictionaryCas from "@/components/config_point/dictionaryCascader";
+import spaceSelect from "@/components/ledger/lib/spaceSelect";
+import { mapGetters } from "vuex";
+export default {
+  components: {
+    floorCascader,
+    dictionaryCas,
+    spaceSelect
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"]),
+    dialog() {
+      return this.dialogVisible;
+    }
+  },
+  data() {
+    return {
+      title: "添加系统所在业务空间",
+      keycode: "", //输入查询条件
+      inSpaceType: "业务空间",
+      Buildfloor: ["all"], // 选中的建筑楼层
+      Spacecategory: null, // 选中的业务空间类型
+      tableData: [],
+      floorData: {}, //楼层
+      spaceData: {}, //业务空间分区
+      loading: false,
+      selections: [], // 选中项
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      headerStyle: {
+        backgroundColor: "#e1e4e5",
+        color: "#2b2b2b",
+        lineHeight: "30px"
+      } // 列表样式
+    };
+  },
+  props: {
+    params: Object, //查看的竖井关系信息
+    spaceType: Object,
+    dialogVisible: Boolean,
+    floorType: Object
+  },
+  mounted() { },
+  methods: {
+    // 显示弹窗
+    showDialog() {
+      this.dialogVisible = true;
+    },
+    //修改建筑楼层
+    changeFloor(value) {
+      this.Buildfloor = value;
+      this.getTableData();
+    },
+    //修改空间类型
+    changeSpace(value) {
+      this.Spacecategory = value;
+      this.getTableData();
+    },
+    getTableData() {
+      let params = {
+        data: {
+          Filters: "not RoomID isNull",
+          Orders: "RoomLocalName desc",
+          PageNumber: this.page.pageNumber,
+          PageSize: this.page.pageSize
+        },
+        ShaftId: this.$route.query.ShaftId
+      };
+      if (this.Buildfloor[0] == "noKnow") {
+        params.data.Filters += `;buildingId isNull`;
+      } else if (this.Buildfloor[0] && this.Buildfloor[0] != "all") {
+        params.data.Filters += `;buildingId='${this.Buildfloor[0]}'`;
+      }
+      if (this.Buildfloor[1] == "noKnow") {
+        params.data.Filters += `;floorId isNull`;
+      } else if (this.Buildfloor[1] && this.Buildfloor[1] != "all") {
+        params.data.Filters += `;floorId='${this.Buildfloor[1]}'`;
+      }
+      if (this.Spacecategory) {
+        params.data.Filters += `;ObjectType='${this.Spacecategory}'`;
+      }
+      if (this.keycode != "") {
+        params.data.Filters += `;RoomName contain '${this.keycode}' or RoomLocalName contain '${this.keycode}'`;
+      }
+      shaftUnlinkSpaceQuery(params, res => {
+        this.tableData = res.Content;
+        this.page.total = res.Total;
+      });
+    },
+    handleClose() {
+      this.$emit("update:dialogVisible", false);
+    },
+    //选中项修改
+    handleSelectionChange(val) {
+      this.selections = val;
+    },
+    savaRelation() {
+      if (this.selections.length) {
+        let params = {
+          Content: this.selections.map(item => {
+            return {
+              SpaceID: item.RoomID,
+              ShaftId: this.$route.query.ShaftId,
+              ObjectType: item.ObjectType
+            };
+          })
+        };
+        linkShaftSpace(params, res => {
+          this.$message.success("关联成功!");
+          this.$emit("refresh");
+        });
+      } else {
+        this.$message("请选择要关联的设备");
+      }
+    },
+    //改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    //改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    // 查看详情
+    toDetail() {
+      this.$message("开发中");
+    }
+  },
+  watch: {
+    dialogVisible: {
+      handler() {
+        if (this.dialogVisible) {
+          this.page.pageNumber = 1;
+          this.tableData = [];
+          this.getTableData();
+        }
+      },
+      immediate: true
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#addEqDialog {
+  .filters {
+    margin: 0 0 10px 0;
+  }
+  .table-box {
+    height: 370px;
+    .fr {
+      margin-top: 10px;
+    }
+  }
+}
+</style>

+ 2 - 2
src/components/ledger/handsontables/assets.vue

@@ -536,7 +536,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除选中资产"
@@ -890,7 +890,7 @@ export default {
     supplyChange(data) {
       tools.setDataForKey(this.tableData[this.row], "LedgerParam.SupplyPurchase.SupplierContractID", { id: data })
     },
-    //保险单号-保险文件 
+    //保险单号-保险文件
     guaranteeChange(data) {
       for (let key in data) {
         this.utilToKey(key, "insuranceNo", data, "InsuranceNum")

File diff suppressed because it is too large
+ 1186 - 865
src/components/ledger/handsontables/device.vue


+ 61 - 32
src/components/ledger/handsontables/system.vue

@@ -44,6 +44,8 @@
         <el-button type="primary" @click="handleClickUpdate">确 认</el-button>
       </span>
     </el-dialog>
+    <!-- 关联楼层 -->
+    <editSysfloor ref="editFloor" @relateSuccess="relateSuccess"></editSysfloor>
     <!-- 新增系统 -->
     <el-dialog title="确定新增系统的类型" :visible.sync="myDialog.addDevice" width="30%">
       <el-row>
@@ -57,13 +59,9 @@
 </template>
 <script>
 import {
-  getTableHeader,
-  getBillSystemList,
-  updateBusiness,
   BeatchQueryParam,
-  delBatchList,
   getDataDictionary,
-  queryLinkSys,
+  querySysLinkBuild,
   updateGeneralSys,
   deleteGeneralSys
 } from "@/api/scan/request"
@@ -80,13 +78,11 @@ import dialogAssets from "@/components/ledger/addDialog/dialogSystem"
 import detailsDialog from "@/components/business_space/lib/detailsDia"
 import systemRelevance from "@/components/ledger/tableTransfers"
 import Handsontable from "handsontable-pro"
+import text from "@/utils/handsontable/mainText"
 import 'handsontable-pro/dist/handsontable.full.css'
-import zhCN from 'handsontable-pro/languages/zh-CN'
+import editSysfloor from "@/components/ledger/lib/editSysFloor";
 
-import {
-  mapGetters,
-  mapActions
-} from "vuex";
+import { mapGetters } from "vuex";
 export default {
   components: {
     qrcode, //二维码页面
@@ -97,7 +93,8 @@ export default {
     dialogAssets,
     detailsDialog,
     systemRelevance,
-    myCascader
+    myCascader,
+    editSysfloor
   },
   computed: {
     ...mapGetters("layout", ["projectId", "secret", "userId"]),
@@ -187,7 +184,7 @@ export default {
         getDataDictionary(params, res => {
           this.tableHeader = res.Content;
           this.tableHeader.forEach(item => {
-            if(item.Path && item.InputMode){
+            if (item.Path && item.InputMode) {
               this.inputMap[item.Path] = item.InputMode
             }
           })
@@ -205,17 +202,24 @@ export default {
       this.loading = true
       if (!!this.mess.deviceId) {
         let param = {
-          PageSize: this.page.size,
-          Orders: "createTime desc, SysID desc",
-          PageNumber: this.page.currentPage,
-          Filters: `category='${this.mess.deviceId}'`
+          data: {
+            PageSize: this.page.size,
+            Orders: "createTime desc, SysID desc",
+            PageNumber: this.page.currentPage,
+            Filters: `category='${this.mess.deviceId}'`
+          }
         }
         if (this.mess.buildId == "noKnow") {
-          param.Filters += `;buildingId isNull`
+          param.buildingId = 1;
         } else if (this.mess.buildId && this.mess.buildId != "all") {
-          param.Filters += `;buildingId='${this.mess.buildId}'`
+          param.buildingId = this.mess.buildId;
+        }
+        if (this.mess.floorId == "noKnow") {
+          param.floorId = 1;
+        } else if (this.mess.floorId && this.mess.floorId != "all") {
+          param.floorId = this.mess.floorId;
         }
-        queryLinkSys(param, res => {
+        querySysLinkBuild(param, res => {
           this.loading = false;
           _this.tableData = res.Content;
           _this.copyMain = tools.deepCopy(res.Content);
@@ -271,7 +275,10 @@ export default {
     formatHeaderData(list) {
       let arr = tools.copyArr(list)
       let data = showTools.headerTextFilter(arr, 'system', this.onlyRead, this.showType)
-      data.unshift("操作", "关联设备数量");
+      data.unshift("操作");
+      if (this.showType == "all") {
+        data.splice(3, 0, "所属建筑楼层")
+      }
       return data;
     },
     //格式化表内容
@@ -284,17 +291,24 @@ export default {
           renderer: tools.lookDetails,
           readOnly: true
         },
-        {
-          data: "Count",
-          renderer: tools.num,
-          readOnly: true
-        }
+        // {
+        //   data: "Count",
+        //   renderer: tools.num,
+        //   readOnly: true
+        // }
       );
       if (this.onlyRead) {
         data.map(item => {
           item.readOnly = true
         })
       }
+      if (this.showType == "all") {
+        data.splice(3, 0, {
+          data: "BuildingFloorInfoList",
+          renderer: text.sysInBuildFloor,
+          readOnly: this.onlyRead
+        })
+      }
       return data;
     },
     //获取动态参数
@@ -347,7 +361,7 @@ export default {
                         item,
                         head.Path,
                         // child.error ? "表号功能号格式错误" : "表号功能号不存在"
-                        child.error ? child.value? "表号功能号格式错误" : "表号功能号不存在" : "暂未采集到实时数据"
+                        child.error ? child.value ? "表号功能号格式错误" : "表号功能号不存在" : "暂未采集到实时数据"
                       );
                     }
                   });
@@ -370,7 +384,7 @@ export default {
       }
       this.hot = new Handsontable(container, {
         data: this.tableData,
-        fixedColumnsLeft: 4,
+        fixedColumnsLeft: 3,
         colHeaders: this.formatHeaderData(this.tableHeader), //表头文案
         columns: this.formatHeaderType(this.tableHeader), //数据显示格式
         filters: true,
@@ -390,7 +404,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该系统"
@@ -479,7 +493,7 @@ export default {
     async removeSys(param) {
       await deleteGeneralSys(param, res => {
         this.$message.success("删除成功")
-        this.$emit('close','')
+        this.$emit('close', '')
         this.getTableData()
       })
     },
@@ -489,7 +503,7 @@ export default {
         Content: [],
         Projection: []
       }, keyList = [];
-       //生成要修改字段列表
+      //生成要修改字段列表
       change.map(item => {
         let key = item[1].split(".")[0]
         if (item[1] && keyList.indexOf(key) == -1) {
@@ -521,7 +535,11 @@ export default {
         //操作
         case 'caozuo':
           // window.open(`http://adm.sagacloud.cn:8058/system?id=${infos.id}&pid=${this.projectId}&secret=${this.secret}`,"_blank")
-          this.$message("开发中...")
+          // this.$message("开发中...")
+          this.$router.push({
+            path: "/ledger/systemDetail",
+            query: { SysID: infos.SysID, Name: infos.SysLocalName || infos.SysName, SysType: infos.Category }
+          })
           return false
         //设备二维码图片
         case 'EquipQRCode':
@@ -538,6 +556,11 @@ export default {
             this.myDialog.relevance = true
           }
           return false
+        case 'BuildingFloorInfoList':
+          if (!this.onlyRead) {
+            this.$refs.editFloor.showDialog(this.tableData[row.row]);
+          }
+          return false
         default:
           break;
       }
@@ -554,13 +577,19 @@ export default {
       this.updateInput = ''
     },
     //更新临时维护信息点
-    handleClickUpdate(){
+    handleClickUpdate() {
+      // this.$message("更新成功");
       tools.setDataForKey(this.tableData[this.row], this.updateInfoPoint, this.updateInput)
       this.handleUpdataTable([[this.row, this.updateInfoPoint, null, this.updateInput]], "edit")
       this.updateInputShow = false
       this.myDialog.update = false
       this.updateInput = ''
     },
+    //关联建筑楼层成功
+    relateSuccess(data) {
+      this.getTableData()
+      // tools.setDataForKey(this.tableData[this.row], "BuildingFloorInfoList", data)
+    },
     //获取被筛选掉的行号
     trimmedRows() {
       // var plugin = hot.getPlugin('trimRows').trimmedRows;//获取被筛选掉的行号

+ 1 - 1
src/components/ledger/lib/addDevice.vue

@@ -352,7 +352,7 @@ export default {
           "filter_by_value",
           "filter_action_bar"
         ],
-        contextMenu: {
+        contextMenu: this.onlyRead ? false :{
           items: {
             remove_row: {
               name: "删除该业务空间"

+ 1 - 1
src/components/ledger/lib/assets.vue

@@ -1,7 +1,7 @@
 <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-select v-model="value" placeholder="请选择" clearable :props="props" filterable :style="isWidth ? '' : 'width:160px;'" size="small" @change="changeVal">
       <el-option  v-for="item in options" :key="item.code" :label="item.facility" :value="item.code"></el-option>
     </el-select>
     <!-- <el-cascader

+ 94 - 0
src/components/ledger/lib/buildfloorCascader.vue

@@ -0,0 +1,94 @@
+<template>
+  <el-cascader v-model="value" :options="options" :props="props" clearable ref="elCascader" @remove-tag="removeTag"></el-cascader>
+</template>
+<script>
+import { buildingQuery } from "@/api/scan/request";
+export default {
+  data() {
+    return {
+      value: [],
+      props: {
+        multiple: true,
+        checkStrictly: true,
+        value: 'BuildID',
+        label: 'BuildLocalName',
+        children: 'Floor'
+      },
+      options: []
+    }
+  },
+  props: {
+    SysID: {
+      default: ''
+    }
+  },
+  methods: {
+    getCascader() {
+      let param = {
+        Cascade: [
+          { Name: "floor", Orders: "FloorSequenceID desc" }
+        ],
+        Orders: "BuildLocalName asc",
+        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.FloorID == this.FloorID) return
+              item.BuildID = item.FloorID
+              item.BuildLocalName = item.FloorLocalName || item.FloorName
+              return item
+            }).filter(it => it)
+          }
+        })
+        this.options = res.Content
+      })
+    },
+    getSelectedNodes() {
+      let nodes = this.$refs.elCascader.getCheckedNodes();
+      let arr = [], flag = false, brr = [];
+      if (nodes.length) {
+        nodes.map(t => {
+          let obj = {
+            BuildName: t.pathLabels[0],
+            BuildID: t.path[0]
+          }
+          if (t.path.length > 1) {
+            obj.FloorName = t.pathLabels[1]
+            obj.FloorID = t.path[1]
+          } else {
+            flag = true;
+          }
+          arr.push(obj);
+        })
+        if (flag) {
+          for (let i = 0; i < arr.length; i++) {
+            for (let j = 0; j < arr.length; j++) {
+              if (!arr[i].FloorID && arr[j].FloorID && arr[i].BuildID == arr[j].BuildID) {
+                brr.push(i)
+              }
+            }
+          }
+          arr = arr.map((t, i) => {
+            if (brr.indexOf(i) > -1) {
+              return undefined;
+            }
+            return t;
+          }).filter(item => item);
+        }
+      }
+      return arr;
+    },
+    removeTag(){
+      console.log(arguments)
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.el-cascader {
+  width: 100%;
+}
+</style>

+ 1 - 1
src/components/ledger/lib/cascader.vue

@@ -1,7 +1,7 @@
 <template>
   <div id="cascaderMap">
     <span class="buildFloor" style="margin-right: 12px;">设备类别</span>
-    <el-select v-model="value" placeholder="请选择" :props="props" filterable :style="isWidth ? '' : 'width:160px;'" size="small" @change="changeVal">
+    <el-select v-model="value" placeholder="请选择" clearable :props="props" filterable :style="isWidth ? '' : 'width:160px;'" size="small" @change="changeVal">
       <el-option  v-for="item in options" :key="item.code" :label="item.facility" :value="item.code"></el-option>
     </el-select>
     <!-- <el-cascader placeholder="请选择" :options="options" v-model="value" :props="props" filterable :style="isWidth ? '' : 'width:160px;'" size="small"

+ 299 - 0
src/components/ledger/lib/cenoteGraphy.vue

@@ -0,0 +1,299 @@
+<template>
+  <div id="cenoteGraphy" style="height:100%;width:100%;" ref="graphy">
+    <div v-show="!floorMap">
+      <div class="center" style="height: 400px;padding-top:182px;box-sizing:border-box;">
+        <i class="icon-wushuju iconfont"></i>
+        暂无数据
+      </div>
+    </div>
+    <div class="canvas-box" v-show="floorMap" v-loading="canvasLoading">
+      <canvas id="floorCanvas" :width="canvasWidth" :height="canvasHeight" ref="canvas" tabindex="0"></canvas>
+      <el-row class="canvas-actions-box">
+        <canvasFun @scale="scale" @fit="fit" @savePng="savePng" @saveSvg="saveSvg" @saveJson="saveJson" :config="config" ref="canvasFun"></canvasFun>
+      </el-row>
+    </div>
+  </div>
+</template>
+
+<script>
+import canvasFun from "@/components/business_space/newGraphy/canvasFun";
+import { SColor, SPoint } from "@saga-web/draw/lib";
+import { DivideFloorScene, SpaceItem, ZoneItem } from "@saga-web/cad-engine/lib";
+import { FloorView } from "@saga-web/cad-engine/lib/FloorView";
+import { colorArr } from '@/utils/spaceColor';
+import { getFloorMsgByFloorID, queryZone, shaftSpaceQuery, shaftZoneLink } from '@/api/scan/request';
+import { resolve, reject } from 'q';
+export default {
+  data() {
+    return {
+      canvasLoading: false,//加载canvas
+      floorMap: '',//地图
+      canvasWidth: 800,
+      canvasHeight: 600,
+      view: null,
+      scene: null,
+      buildingData: [],//建筑,楼层
+      space: '',//当前空间类型
+      businessSpaceList: [],//所有业务空间
+      BSPRelaISPList: [],//已关联元空间的业务空间
+      zoneList: [], // 业务空间-canvas图中
+      selectAble: false,
+      relatedSpaceIdList: [],//已关联的业务空间id
+      config: {
+        isEdit: false
+      },
+    }
+  },
+  mounted() {
+    this.canvasWidth = this.$refs.graphy.offsetWidth;
+    this.canvasHeight = this.$refs.graphy.offsetHeight;
+  },
+  components: {
+    canvasFun
+  },
+  created() {
+
+  },
+  methods: {
+    //获取楼层map
+    getFloorMap(buildfloor, space) {
+      if (buildfloor.length == 2 && space && buildfloor[1] && buildfloor[0]) {
+        this.buildingData = buildfloor
+        let pa = {
+          Filters: `FloorID='${this.buildingData[1]}'`
+        }
+        getFloorMsgByFloorID(pa, res => {
+          this.floorMap = res.Content[0].StructureInfo ? res.Content[0].StructureInfo.FloorMap : '';
+          this.space = space;
+          this.getGraphy();
+        })
+      }
+      else{
+        this.floorMap = '';
+      }
+    },
+    //加载
+    load() {
+      if (this.scene) {
+        this.scene.clearSpaceSelection();
+        this.scene.clearZoneSelection();
+      }
+      //加载底板
+      this.getGraphy()
+    },
+    //获取底图
+    getGraphy() {
+      let that = this;
+      that.clearGraphy()
+      that.scene = new DivideFloorScene();
+      that.scene.isSpaceSelectable = false;
+      that.canvasLoading = true;
+      that.scene.loadUrl(`/image-service/common/file_get?systemId=revit&key=${this.floorMap}`).then(res => {
+        that.canvasLoading = false;
+        if (res == 'error') {
+          this.floorMap = '';
+          this.$message.warning('数据解析异常');
+          return;
+        }
+        that.view.scene = that.scene;
+        // 绘制业务空间
+        that.getBusinessSpace();
+        that.view.fitSceneToView();
+        that.view.minScale = that.view.scale;
+        if (that.$refs.canvasFun) {
+          that.$refs.canvasFun.everyScale = that.view.scale;
+        }
+      })
+    },
+    // 获取当前分区下的业务空间
+    getBusinessSpace() {
+      this.canvasLoading = true
+      this.clearZoneCanvas();
+      let promise1 = new Promise((resolve, reject) => {
+        let params = {
+          data: {
+            Filters: `not RoomID isNull;ObjectType = '${this.space}';buildingId = '${this.buildingData[0]}';floorId = '${this.buildingData[1]}'`,
+            Orders: "RoomLocalName desc"
+          },
+          ShaftId: this.$route.query.ShaftId
+        };
+        shaftSpaceQuery(params, res => {
+          resolve(res)
+        })
+      });
+      let promise2 = new Promise((resolve, reject) => {
+        let pa = {
+          zone: this.space,
+          data: {
+            Filters: ``,
+            Orders: "createTime desc, RoomID asc",
+            PageSize: 1000
+          }
+        }
+        if (this.buildingData.length && this.buildingData.length > 1) {
+          pa.data.Filters = `BuildingId='${this.buildingData[0]}';FloorId='${this.buildingData[1]}'`
+        }
+        queryZone(pa, res => {
+          resolve(res);
+        })
+      })
+      Promise.all([promise1, promise2]).then(values => {
+        let relatedZone = values[0].Content;
+        let zoneData = values[1].Content;
+        this.relatedSpaceIdList = [];
+        relatedZone.map(item => {
+          this.relatedSpaceIdList.push(item.RoomID);
+        })
+        // 所有业务空间
+        this.businessSpaceList = zoneData;
+        // 已关联元空间的业务空间
+        this.BSPRelaISPList = [];
+        zoneData.map(t => {
+          if (t.Outline && t.Outline.length) {
+            this.BSPRelaISPList.push(t)
+          }
+        })
+        // 绘制业务空间
+        let tempArr = this.BSPRelaISPList.map((t, i) => {
+          let item = {
+            RoomLocalName: t.RoomLocalName,
+            OutLine: t.Outline,
+            RoomID: t.RoomID,
+            Color: colorArr[i % colorArr.length],
+          }
+          return item;
+        })
+        this.scene.zoneList = [];
+        this.scene.addZoneList(tempArr);
+        this.scene.click(this, this.canvasClick);
+        this.zoneList = this.scene.zoneList;
+        this.scene.zoneList.map(t => {
+          t.selected = false;
+          if (this.relatedSpaceIdList.indexOf(t.data.RoomID) != -1) {
+            // t.selected = true;
+            t.highLightFlag = true;
+          }
+        })
+        this.canvasLoading = false;
+      })
+    },
+    // canvas点击事件
+    canvasClick(item, event) {
+      if (item.selectable) {
+        if (this.selectAble) {
+          if (this.relatedSpaceIdList.indexOf(item.data.RoomID) != -1) {
+            this.relatedSpaceIdList = this.relatedSpaceIdList.filter(t => { return t != item.data.RoomID });
+          }
+          else {
+            this.relatedSpaceIdList.push(item.data.RoomID);
+          }
+        }
+        else {
+          item.selected = !item.selected;
+        }
+      }
+    },
+    //取消编辑
+    cancelEdit() {
+      this.getBusinessSpace();
+    },
+    //保存编辑
+    saveEdit() {
+      let param = {
+        BuildingId: this.buildingData[0],
+        FloorId: this.buildingData[1],
+        Type: this.space,
+        data: {
+          ShaftId: this.$route.query.ShaftId,
+          SpaceIdList: this.relatedSpaceIdList
+        }
+      }
+      shaftZoneLink(param, res => {
+        if (res.Result == "success") {
+          this.$message.success("保存成功");
+          this.getBusinessSpace();
+        }
+      })
+    },
+    //是否可点
+    setSelectAble(val) {
+      if (this.scene) {
+        this.selectAble = val && !this.$route.query.onlyRead;
+        if (this.selectAble) {
+          this.scene.zoneList.map(t => {
+            t.highLightFlag = false;
+            t.selected = false;
+            if (this.relatedSpaceIdList.indexOf(t.data.RoomID) != -1) {
+              t.selected = true;
+            }
+          })
+        }
+      }
+    },
+    // 清除canvas
+    clearGraphy() {
+      // debugger
+      this.scene = null;
+      if (this.view) {
+        this.view.scene = null;
+        return
+      }
+      this.view = new FloorView('floorCanvas')
+    },
+    // 清空绘制业务空间
+    clearZoneCanvas() {
+      this.zoneList.map(t => {
+        this.scene.removeItem(t);
+      })
+    },
+    // 适配底图到窗口
+    fit() {
+      this.view.fitSceneToView()
+    },
+    // 缩放
+    scale(val) {
+      if (!this.view) {
+        return;
+      }
+      let scale = this.view.scale;
+      this.view.scaleByPoint(val / scale, this.canvasWidth / 2, this.canvasHeight / 2);
+    },
+    // 保存为png
+    savePng() {
+      this.view.saveImage(`${this.buildingData[1]}.png`, 'png');
+    },
+    // 保存为svg
+    saveSvg() {
+      this.view.saveSceneSvg(`${this.buildingData[1]}.svg`, 6400, 4800);
+    },
+    // 保存json
+    saveJson() {
+      this.view.saveFloorJson(`${this.buildingData[1]}.json`)
+    },
+  },
+  watch: {
+    "view.scale": {
+      handler(n) {
+        if (this.$refs.canvasFun) {
+          let s = n * 10 / this.view.minScale
+          this.$refs.canvasFun.sliderVal = s > 1000 ? 1000 : s;
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.canvas-actions-box {
+  position: absolute;
+  bottom: 20px;
+  left: 50%;
+  transform: translateX(-50%);
+  z-index: 999;
+}
+.canvas-box {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 119 - 0
src/components/ledger/lib/editSysFloor.vue

@@ -0,0 +1,119 @@
+<template>
+  <el-dialog title="所属建筑楼层" :visible.sync="connectDialogVis" width="50%" id="messageDialog">
+    <el-row>
+      <div style="line-height:32px;">添加{{system.SysLocalName}}所属建筑楼层 : </div>
+      <div style="width:70%">
+        <bfCascader ref="bfCascader" :SysID="system.SysID"></bfCascader>
+      </div>
+    </el-row>
+    <span slot="footer" class="dialog-footer">
+      <el-button size="small" @click="connectDialogVis=false">取消</el-button>
+      <el-button size="small" type="primary" @click="save">确认</el-button>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import bfCascader from './buildfloorCascader'
+import { sysRelateBuild, sysRelateFloor } from "@/api/scan/request";
+import { resolve } from 'q';
+export default {
+  data() {
+    return {
+      buildName: '',
+      connectDialogVis: false,
+      system: {}
+    }
+  },
+  components: {
+    bfCascader
+  },
+  props: {
+    isCreate: {
+      default: false
+    }
+  },
+  methods: {
+    showDialog(system) {
+      this.system = system;
+      this.connectDialogVis = true;
+      this.$nextTick(() => {
+        this.$refs.bfCascader.getCascader()
+        let arr = this.system.BuildingFloorInfoList || [];
+        let value = []
+        if (arr.length) {
+          arr.map(t => {
+            if (t.FloorID) {
+              value.push([t.BuildID, t.FloorID]);
+            } else {
+              value.push([t.BuildID])
+            }
+          })
+        }
+        this.$refs.bfCascader.value = value
+      })
+    },
+    save() {
+      // 如果是创建
+      if (this.isCreate) {
+        let data = this.$refs.bfCascader.getSelectedNodes();
+        this.connectDialogVis = false;
+        this.$emit('relateSuccess', data);
+        return
+      }
+      let arr = this.$refs.bfCascader.value;
+      let buildIds = [], floorIds = [];
+      arr.map(t => {
+        if (buildIds.indexOf(t[0]) < 0) {
+          buildIds.push(t[0]);
+        }
+        if (t.length > 1 && floorIds.indexOf(t[1]) < 0) {
+          floorIds.push(t[1]);
+        }
+      })
+      let buildPa = {
+        SysId: this.system.SysID,
+        BuildingIdList: buildIds
+      }
+      let floorPa = {
+        SysId: this.system.SysID,
+        FloorIdList: floorIds
+      }
+      let promise1 = new Promise((resolve, reject) => {
+        sysRelateBuild(buildPa, res => {
+          resolve(res);
+        })
+      })
+      let primise2 = new Promise((resolve, reject) => {
+        sysRelateFloor(floorPa, res => {
+          resolve(res);
+        })
+      })
+      let buildFloor = this.$refs.bfCascader.getSelectedNodes();
+      Promise.all([promise1, primise2]).then(res => {
+        this.connectDialogVis = false;
+        this.$message.success("关联成功");
+        this.$emit('relateSuccess', buildFloor);
+      })
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+#messageDialog {
+  .el-row {
+    height: 50px;
+    max-height: 200px;
+    overflow-y: auto;
+    overflow-x: hidden;
+  }
+  .el-row > div {
+    float: left;
+  }
+  .el-row > div + div {
+    margin-left: 10px;
+  }
+  /deep/ .el-input__inner {
+    vertical-align: baseline;
+  }
+}
+</style>

+ 6 - 5
src/components/ledger/lib/floorCascader.vue

@@ -1,6 +1,6 @@
 <template>
     <div id="buildFloor">
-        <span class="buildFloor" style="margin-right: 12px;">建筑楼层</span>
+        <span class="buildFloor">建筑楼层</span>
         <el-cascader placeholder="请选择建筑楼层" :options="options" v-model="value" filterable size="small" :style="isWidth ? '' : 'width:160px;'" @change="changeCascader"></el-cascader>
     </div>
 </template>
@@ -149,9 +149,10 @@
     #buildFloor {
         margin-left: 10px;
         float: left;
-        .buildFloor {
-            color: #999999;
-            font-size: 14px;
-        }
+    }
+    .buildFloor {
+        color: #999999;
+        font-size: 14px;
+        margin-right: 12px;
     }
 </style>

+ 65 - 0
src/components/ledger/lib/spaceSelect.vue

@@ -0,0 +1,65 @@
+<template>
+  <div id="spaceSelect">
+    <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, key) in options" :key="key" :label="item.Name" :value="item.Code"></el-option>
+    </el-select>
+  </div>
+</template>
+
+<script>
+import { queryDictionaryHead } from '@/api/scan/request';
+export default {
+  props: {
+    isWidth: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      value:null,
+      spaceVal: null,//值
+      options: [],
+      props: {
+        isWidth:false
+      }
+    }
+  },
+  methods: {
+    //获取下拉框数据
+    getOptionData() {
+      let pa = {
+        Filters: `parentId = 'Space'`
+      }
+      queryDictionaryHead(pa, res => {
+        this.options = res.Content.map(t => {
+          if (t.Name == "元空间") {
+            return undefined;
+          }
+          return t;
+        }).filter(item => item);
+        this.options.unshift({Code:null, CreateTime:null, LastUpdate:null, Name:'全部', ObjectType: null, ParentId: null, Statistics: {}});
+      })
+    },
+    //改变空间
+    changeVal(value) {
+      this.$emit('change', value)
+    }
+  },
+  created() {
+    this.getOptionData();
+  }
+}
+</script>
+
+<style lang="less" scoped>
+#spaceSelect {
+  float: left;
+  margin-left: 10px;
+  .buildFloor {
+    color: #999999;
+    font-size: 14px;
+  }
+}
+</style>

+ 15 - 11
src/components/ledger/lib/system.vue

@@ -2,7 +2,7 @@
   <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.Category" :label="item.CategoryName" :value="item.Category"></el-option>
+      <el-option v-for="item in options" :key="item.Category" :label="item.CategoryName" :value="item.Category"></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> -->
@@ -18,8 +18,8 @@ export default {
       type: Boolean,
       default: true
     },
-    all:{
-      default:false
+    all: {
+      default: false
     }
   },
   computed: {
@@ -36,20 +36,24 @@ export default {
     };
   },
   created() {
-    if(this.all){
-      //物理世界所有系统
-      this.getAllData();
-    }else{
-      //当前项目下已有的系统
-      this.getData();
-    }
+    this.init()
   },
   watch: {
     projectId() {
       this.value = ''
+      this.init()
     }
   },
   methods: {
+    init() {
+      if (this.all) {
+        //物理世界所有系统
+        this.getAllData();
+      } else {
+        //当前项目下已有的系统
+        this.getData();
+      }
+    },
     setValue(val) {
       this.value = val
     },
@@ -80,7 +84,7 @@ export default {
         }
       })
     },
-    getAllData(){
+    getAllData() {
       getEqCode().then(res => {
         this.options = this.changeArr(res.data.Content)
         if (this.value) {

+ 196 - 155
src/components/ledger/lib/uploadFiles.vue

@@ -8,166 +8,207 @@
   isShow: 图片的显示
  -->
 <template>
-  <div id="saga-upload">
-    <div id="uploadFile">
-
-      <el-upload
-        v-if="filesArr.length < max"
-        class="upload-file"
-        action
-        :http-request="uploadAndSubmit"
-        drag
-      >
-        <el-button size="small" type="primary" v-if="!readOnly">点击上传</el-button>
-        <div slot="tip" class="el-upload__tip" v-if="!readOnly">请上传文件</div>
-      </el-upload>
-            <div v-if="item && filesArr.length" v-for="(item,index) in filesArr">
-        <el-button type="text" @click="download(item)">{{delFile(item)}}</el-button>
-        <i
-          v-if="!readOnly"
-          class="el-icon-close delete-icon"
-          style="margin-left:10px; cursor:pointer"
-          @click="deleteFile(index,item)"
-        ></i>
-      </div>
-    </div>
+    <div id="saga-upload">
+        <div id="uploadFile">
+
+            <el-upload
+                v-if="filesArr.length < max"
+                class="upload-file"
+                action
+                :show-file-list="showFileList"
+                :http-request="uploadAndSubmit"
+                drag
+            >
+
+                <el-button
+                    size="small"
+                    type="primary"
+                    v-if="!readOnly"
+                >点击上传
+                </el-button>
+                <div
+                    slot="tip"
+                    class="el-upload__tip"
+                    v-if="!readOnly"
+                >请上传文件
+                </div>
+            </el-upload>
+
+            <div
+                v-show="item && filesArr.length"
+                v-for="(item,index) in filesArr"
+            >
+                <el-button
+                    type="text"
+                    @click="download(item)"
+                >{{delFile(item)}}
+                </el-button>
+                <i
+                    v-if="!readOnly"
+                    class="el-icon-close delete-icon"
+                    style="margin-left:10px; cursor:pointer"
+                    @click="deleteFile(index,item)"
+                ></i>
+            </div>
+        </div>
   </div>
 </template>
 
 <script>
-import tools from "@/utils/scan/tools";
-export default {
-  props: {
-    keysArr: {
-      type: [Array, String],
-      default: function () {
-        return []
-      }
-    },
-    readOnly: {
-      type: Boolean,
-      default: false
-    },
-    max: {
-      type: [Number, String],
-      default: 6
-    },
-    defined: null
-  },
-  data() {
-    return {
-      filesArr: []
-    };
-  },
-  created() {
-    let type = typeof (this.keysArr)
-    this.fileFalg()
-  },
-  methods: {
-    //判断是否为空
-    fileFalg() {
-      let type = typeof (this.keysArr)
-      console.log(this.keysArr, "keysAee")
-      if (type == 'string') {
-        this.filesArr = [this.keysArr]
-      } else {
-        this.filesArr = tools.deepCopy(this.keysArr)
-      }
+    import tools from "@/utils/scan/tools";
 
-      if (!this.keysArr) {
-        this.filesArr = []
-      }
-    },
-    //处理地址
-    delFile(name) {
-      console.log(name, "name")
-      return name.length > 20 ? name.substring(0, 20) + "..." : ""
-    },
-
-    resetFile() {
-      this.filesArr = []
-    },
-
-
-    //点击下载
-    download(key) {
-      console.log(key)
-      window.open("/image-service/common/file_get/" + key + "?systemId=dataPlatform")
-    },
-
-    //删除图片
-    deleteFile(i, key) {
-      this.filesArr.splice(i, 1);
-      this.$emit("change", this.filesArr, this.defined);
-    },
-
-    //上传
-    uploadAndSubmit(item) {
-      // var form = document.forms["demoForm"];
-
-      // if (form["file"].files.length > 0) {
-      // 寻找表单域中的 <input type="file" ... /> 标签
-      // var file = form["file"].files[0];
-
-      let file = item.file;
-      // try sending
-      let reader = new FileReader();
-
-      let vm = this;
-
-      let fileType = file.name.split(".");
-      let type = fileType[fileType.length - 1];
-      let key = "&key=" + fileType[0] + file.uid + "." + type
-
-      reader.onloadstart = function () {
-        // 这个事件在读取开始时触发
-      };
-      reader.onprogress = function (p) {
-        // 这个事件在读取进行中定时触发
-      };
-
-      reader.onload = function () {
-        // 这个事件在读取成功结束后触发
-      };
-      reader.onloadend = function () {
-        // 这个事件在读取结束后,无论成功或者失败都会触发
-        if (reader.error) {
-        } else {
-          // document.getElementById("bytesRead").textContent = file.size;
-          // 构造 XMLHttpRequest 对象,发送文件 Binary 数据
-          var xhr = new XMLHttpRequest();
-          xhr.open(
-            /* method */
-            "POST",
-            /* target url */
-            "/image-service/common/file_upload?systemId=dataPlatform&secret=9e0891a7a8c8e885&overwrite=true" + key
-            /*, async, default to true */
-          );
-          //xhr.overrideMimeType("application/octet-stream");
-          xhr.send(reader.result);
-          xhr.onreadystatechange = function () {
-            if (xhr.readyState == 4) {
-              console.log(xhr)
-              if (xhr.status == 200) {
-                vm.filesArr.push(
-                  key.split("=")[1]
-                );
-                console.log(vm.filesArr)
-                vm.$emit("change", vm.filesArr, vm.defined);
-              } else {
-                this.$message.error(res.data.ResultMsg)
-              }
+    export default {
+        props: {
+            keysArr: {
+                type: [Array, String],
+                default: function () {
+                    return []
+                }
+            },
+            readOnly: {
+                type: Boolean,
+                default: false
+            },
+            max: {
+                type: [Number, String],
+                default: 6
+            },
+            defined: null,
+            firmDataType: {
+                type: String
+            },
+            information: {
+                type: Object
+            },
+            infoType: {
+                type: String
+            }
+        },
+        data() {
+            return {
+                filesArr: [],
+                isShow: Boolean
+            };
+        },
+        created() {
+            let type = typeof (this.keysArr)
+            this.fileFalg()
+            // this.resetFile()
+        },
+        computed: {
+            showFileList() {
+                if (this.firmDataType === 'dialog') {
+                    this.isShow = false
+                } else {
+                    this.isShow = true
+                }
+                return this.isShow
+            }
+        },
+        methods: {
+            //判断是否为空
+            fileFalg() {
+                let type = typeof (this.keysArr)
+                if (type == 'string') {
+                    this.filesArr = [this.keysArr]
+
+                } else {
+                    this.filesArr = tools.deepCopy(this.keysArr)
+
+                }
+
+                if (!this.keysArr) {
+                    this.filesArr = []
+                }
+            },
+            //处理地址
+            delFile(name) {
+                return name.length > 20 ? name.substring(0, 20) + "..." : name
+            },
+
+            resetFile() {
+                this.filesArr = []
+            },
+
+
+            //点击下载
+            download(key) {
+                console.log(key)
+                window.open("/image-service/common/file_get/" + key + "?systemId=dataPlatform")
+            },
+
+            //删除图片
+            deleteFile(i, key) {
+                this.filesArr.splice(i, 1);
+                this.$emit("change", this.filesArr, this.defined);
+            },
+
+            //上传
+            uploadAndSubmit(item) {
+                // var form = document.forms["demoForm"];
+
+                // if (form["file"].files.length > 0) {
+                // 寻找表单域中的 <input type="file" ... /> 标签
+                // var file = form["file"].files[0];
+
+                let file = item.file;
+                // try sending
+                let reader = new FileReader();
+
+                let vm = this;
+
+                let fileType = file.name.split(".");
+                let type = fileType[fileType.length - 1];
+                let key = "&key=" + fileType[0] + file.uid + "." + type
+
+                reader.onloadstart = function () {
+                    // 这个事件在读取开始时触发
+                };
+                reader.onprogress = function (p) {
+                    // 这个事件在读取进行中定时触发
+                };
+
+                reader.onload = function () {
+                    // 这个事件在读取成功结束后触发
+                };
+                reader.onloadend = function () {
+                    // 这个事件在读取结束后,无论成功或者失败都会触发
+                    if (reader.error) {
+                    } else {
+                        // document.getElementById("bytesRead").textContent = file.size;
+                        // 构造 XMLHttpRequest 对象,发送文件 Binary 数据
+                        var xhr = new XMLHttpRequest();
+                        xhr.open(
+                            /* method */
+                            "POST",
+                            /* target url */
+                            "/image-service/common/file_upload?systemId=dataPlatform&secret=9e0891a7a8c8e885&overwrite=true" + key
+                            /*, async, default to true */
+                        );
+                        //xhr.overrideMimeType("application/octet-stream");
+                        xhr.send(reader.result);
+                        xhr.onreadystatechange = function () {
+                            if (xhr.readyState == 4) {
+                                console.log(xhr)
+                                if (xhr.status == 200) {
+                                    vm.filesArr.push(
+                                        key.split("=")[1]
+                                    );
+                                    vm.$emit("change", vm.filesArr, vm.defined);
+                                } else {
+                                    this.$message.error(res.data.ResultMsg)
+                                }
+                            }
+                        };
+                    }
+                };
+                reader.readAsArrayBuffer(file);
+            }
+        },
+        watch: {
+            keysArr: function (val) {
+                this.fileFalg()
             }
-          };
-        }
-      };
-      reader.readAsArrayBuffer(file);
-    }
-  },
-  watch: {
-    keysArr: function (val) {
-      this.fileFalg()
-    }
   }
 };
 </script>
@@ -204,4 +245,4 @@ export default {
     }
   }
 }
-</style>
+</style>

+ 1 - 1
src/components/ledger/lib/uploadImgsName.vue

@@ -34,7 +34,7 @@
           :accept="accept"
           action
           drag
-          style="position: relation"
+          style="position: relative"
         >
           <i class="el-icon-plus avatar-uploader-icon"></i>
         </el-upload>

+ 334 - 0
src/components/ledger/rentList/roomCountDrawer.vue

@@ -0,0 +1,334 @@
+<template>
+  <el-drawer title="关联的业务空间" :visible.sync="drawer" :direction="direction" :before-close="handleClose" size="20%" custom-class="room-count">
+    <div class="drawer-body" :style="{height:drawerBodyHeight}">
+      <div class="default-zone zone">
+        <p>默认业务空间</p>
+        <div v-if="!(readonly&&!zoneList.GeneralZone.length)">
+          <div v-for="(item,index) in zoneList.GeneralZone" :key="item.RoomID" class="zoneItem">
+            {{item.BuildLocalName}}-{{item.FloorLocalName}}-{{item.RoomLocalName || item.RoomName}}
+            <i size="mini" class="el-icon-delete" title="删除" @click="deleteZoneItem('GeneralZone',index)" v-if="!readonly"></i>
+          </div>
+          <div class="zoneItem" style="border:none;padding:0;" v-if="!readonly">
+            <el-cascader placeholder="请选择" v-model="GeneralVal" :options="option.GeneralZone" :props="props" filterable @expand-change="expandChange"
+              @change="change" style="width:100%;">
+            </el-cascader>
+          </div>
+        </div>
+        <div v-else class="center">
+          <i class="icon-wushuju iconfont"></i>
+          暂无数据
+        </div>
+      </div>
+      <div class="tenant-zone zone">
+        <p>租户业务空间</p>
+        <div v-if="!(readonly&&!zoneList.TenantZone.length)">
+          <div v-for="(item,index) in zoneList.TenantZone" :key="item.RoomID" class="zoneItem">
+            {{item.BuildLocalName}}-{{item.FloorLocalName}}-{{item.RoomLocalName || item.RoomName}}
+            <i size="mini" class="el-icon-delete" title="删除" @click="deleteZoneItem('TenantZone',index)" v-if="!readonly"></i>
+          </div>
+          <div class="zoneItem" style="border:none;padding:0;" v-if="!readonly">
+            <el-cascader placeholder="请选择" v-model="TenantVal" :options="option.TenantZone" :props="props" filterable
+              @expand-change="expandChangeTenantZone" @change="changeTenantZone" style="width:100%;">
+            </el-cascader>
+          </div>
+        </div>
+        <div v-else class="center">
+          <i class="icon-wushuju iconfont"></i>
+          暂无数据
+        </div>
+      </div>
+    </div>
+    <div class="btn" v-if="!readonly">
+      <el-button type="primary" @click="save">保存</el-button>
+    </div>
+  </el-drawer>
+</template>
+<script>
+import {
+  tnRelateTenantZone, //关联租户空间
+  tnRelateGeneralZone, //关联默认空间
+  tnRelateOneZone,// 关联业务空间
+  delTnRelateZone, // 删除关系业务空间与租户
+  buildingQuery, //建筑查询
+  queryParentZone, //业务空间查询GeneralZone-TenantZone
+} from '@/api/scan/request'
+import { mapGetters } from "vuex";
+export default {
+  data() {
+    return {
+      drawer: false,
+      direction: 'rtl',
+      zoneList: {
+        GeneralZone: [],
+        TenantZone: []
+      },
+      option: {
+        GeneralZone: [],
+        TenantZone: []
+      },
+      props: {
+        children: 'Floor'
+      },
+      GeneralVal: [],
+      TenantVal: [],
+      curTenantId: '',
+      drawerBodyHeight: ''
+    }
+  },
+  props: {
+    readonly: {
+      default: true
+    }
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  watch: {
+    projectId() {
+      this.init();
+    }
+  },
+  mounted() {
+    this.drawerBodyHeight = document.body.clientHeight - 152 + 'px'
+  },
+  created() {
+    this.init();
+  },
+  methods: {
+    init() {
+      this.getBuilding()
+    },
+    getBuilding() {
+      let pa = {
+        Cascade: [{ Name: 'floor', Orders: 'FloorSequenceID desc' }],
+        Order: 'BuildLocalName asc'
+      }
+      buildingQuery(pa, res => {
+        this.option.GeneralZone = res.Content.map(build => {
+          build.value = build.BuildID;
+          build.label = build.BuildLocalName;
+          build.Floor = build.Floor.map(floor => {
+            floor.value = floor.FloorID;
+            floor.label = floor.FloorLocalName;
+            floor.Floor = [];
+            return floor;
+          });
+          build.Floor.unshift({ value: 'noknowFloor', label: '未明确楼层', Floor: [] })
+          return build;
+        })
+        this.option.GeneralZone.unshift({ value: 'noknowBuild', label: '未明确建筑', Floor: [] });
+        this.option.TenantZone = JSON.parse(JSON.stringify(this.option.GeneralZone));
+      })
+    },
+    expandChange(val) {
+      this.middleware(val, "GeneralZone")
+    },
+    expandChangeTenantZone(val) {
+      this.middleware(val, "TenantZone")
+    },
+    middleware(val, type) {
+      let filters = '';
+      if (val[0] == 'noknowBuild') { //未明确建筑
+        filters = `buildingId isNull`
+        this.getZone(filters, type, val)
+      } else if (val[1]) {
+        if (val[1] == "noknowFloor") {
+          filters = `buildingId='${val[0]}';floorId isNull`
+        } else {
+          filters = `buildingId='${val[0]}';floorId='${val[1]}'`
+        }
+        this.getZone(filters, type, val)
+      }
+    },
+    getZone(filters, type, selected) {
+      if (!filters) return;
+      let params = {
+        Cascade: [{ Name: 'building' }, { Name: 'floor' }],
+        Filters: `${filters};ObjectType='${type}'`,
+        Orders: "RoomID asc",
+        PageSize: 1000,
+        Projection: ["RoomID", "RoomLocalName", "RoomName", "ObjectType", "BuildingId", "FloorId"]
+      }
+      queryParentZone(params, res => {
+        if (res.Content.length) {
+          let tempArr = res.Content.map(t => {
+            t.BuildLocalName = t.Building ? t.Building.BuildLocalName : '未明确建筑';
+            t.FloorLocalName = t.Floor ? t.Floor.FloorLocalName : '未明确楼层';
+            delete t.Floor;
+            t.value = JSON.parse(JSON.stringify(t));
+            t.label = t.RoomLocalName || t.RoomName;
+            return t;
+          })
+          if (selected.length == 1) {
+            this.option[type][0].Floor = tempArr;
+          } else {
+            for (let i = 0; i < this.option[type].length; i++) {
+              if (this.option[type][i].value == selected[0]) {
+                for (let j = 0; j < this.option[type][i].Floor.length; j++) {
+                  if (this.option[type][i].Floor[j].value == selected[1]) {
+                    this.option[type][i].Floor[j].Floor = tempArr;
+                  }
+                }
+              }
+            }
+          }
+        }
+      })
+    },
+    change(val) {
+      let zoneObj = val[val.length - 1];
+      if (zoneObj.BuildLocalName == '未明确建筑') {
+        zoneObj.FloorLocalName = ''
+      }
+      if (this.zoneList.GeneralZone.findIndex((item) => (item.RoomID == zoneObj.RoomID)) == -1) {
+        this.zoneList.GeneralZone.push(zoneObj);
+        this.relateGeneral('GeneralZone', zoneObj.RoomID)
+      } else {
+        this.$message.warning('已有业务空间,请重新选择')
+      }
+      this.GeneralVal = [];
+    },
+    changeTenantZone(val) {
+      let zoneObj = val[val.length - 1];
+      if (zoneObj.BuildLocalName == '未明确建筑') {
+        zoneObj.FloorLocalName = ''
+      }
+      if (this.zoneList.TenantZone.findIndex((item) => (item.RoomID == zoneObj.RoomID)) == -1) {
+        this.zoneList.TenantZone.push(zoneObj);
+        this.relateGeneral('TenantZone', zoneObj.RoomID)
+      } else {
+        this.$message.warning('已有业务空间,请重新选择')
+      }
+      this.TenantVal = [];
+    },
+    showDrawer(tenant) {
+      this.curTenantId = tenant.TenantID;
+      if (tenant.ZoneGeneraltList) {
+        this.zoneList.GeneralZone = tenant.ZoneGeneraltList.map(t => {
+          if (t.Building) {
+            t.BuildLocalName = t.Building.BuildLocalName || t.Building.BuildName;
+          } else {
+            t.BuildLocalName = '未明确建筑'
+          }
+          if (t.Floor) {
+            t.FloorLocalName = t.Floor.FloorLocalName || t.Floor.FloorName;
+          } else {
+            t.FloorLocalName = '未明确楼层'
+          }
+          if (t.BuildLocalName == '未明确建筑') {
+            t.FloorLocalName = ''
+          }
+          return t;
+        });
+      } else {
+        this.zoneList.GeneralZone = [];
+      }
+      if (tenant.ZoneTenantList) {
+        this.zoneList.TenantZone = tenant.ZoneTenantList.map(t => {
+          if (t.Building) {
+            t.BuildLocalName = t.Building.BuildLocalName || t.Building.BuildName;
+          } else {
+            t.BuildLocalName = '未明确建筑'
+          }
+          if (t.Floor) {
+            t.FloorLocalName = t.Floor.FloorLocalName || t.Floor.FloorName;
+          } else {
+            t.FloorLocalName = '未明确楼层'
+          }
+          if (t.BuildLocalName == '未明确建筑') {
+            t.FloorLocalName = ''
+          }
+          return t;
+        });
+      } else {
+        this.zoneList.TenantZone = [];
+      }
+      this.drawer = true;
+    },
+    handleClose(done) {
+      this.zoneList.GeneralZone = [];
+      this.zoneList.GeneralZone = [];
+      this.$emit('refresh');
+      done();
+    },
+    // 删除
+    deleteZoneItem(type, index) {
+      let pa = {
+        type: type,
+        data: [
+          {
+            SpaceID: this.zoneList[type][index].RoomID,
+            TenantID: this.curTenantId
+          }
+        ]
+      }
+      this.zoneList[type].splice(index, 1);
+      delTnRelateZone(pa, res => { })
+    },
+    // 关联默认空间
+    relateGeneral(type, SpaceId) {
+      let pa = {
+        type: type,
+        data: {
+          Content: [
+            {
+              SpaceId: SpaceId,
+              TenantID: this.curTenantId
+            }
+          ]
+        }
+      }
+      tnRelateOneZone(pa, res => { })
+    },
+    save() {
+      this.$emit('refresh');
+      this.drawer = false;
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+.room-count {
+  .drawer-body {
+    position: relative;
+    padding: 10px 10px 30px;
+    overflow-y: auto;
+    .zone {
+      padding: 6px 14px 22px;
+      box-shadow: 0 0 3px #cacaca;
+      p {
+        margin-bottom: 4px;
+      }
+      .zoneItem {
+        position: relative;
+        padding: 2px 34px 2px 10px;
+        border: 1px solid #ccc;
+        border-radius: 4px;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        i {
+          position: absolute;
+          right: 10px;
+          top: 50%;
+          transform: translateY(-50%);
+          cursor: pointer;
+        }
+      }
+      .zoneItem + .zoneItem {
+        margin-top: 6px;
+      }
+    }
+    .zone + .zone {
+      margin-top: 10px;
+    }
+  }
+  .btn {
+    position: absolute;
+    width: calc(100% - 20px);
+    bottom: 20px;
+    right: 20px;
+    text-align: right;
+  }
+}
+</style>

+ 82 - 0
src/components/ledger/report/datafan.vue

@@ -0,0 +1,82 @@
+<template>
+  <div class="saga-fill">
+    <div class="mess-view">
+      <el-tooltip class="item" effect="dark" :content="renderData.tips" placement="bottom-start">
+        <i class="el-icon-info"><span>{{renderData.title}}</span></i>
+      </el-tooltip>
+    </div>
+    <div class="doughnut-view">
+      <fan-chart v-if="renderData.needCountO" type="type" width="200" height="200" :name="renderData.title" :renderData="echartsData" :id="id">
+      </fan-chart>
+    </div>
+    <slot></slot>
+  </div>
+</template>
+
+<script>
+import fanChart from "@/components/echarts/fanChart"
+export default {
+  data() {
+    return {
+      echartsData: [],
+      color: ["#AB7948", "#CAA679", "#DEC9A8", "#B3CFC4", "#7DAAA7", "#7484A6", "#9DABCB"]
+    }
+  },
+  created() {
+    this.echartsData = this.renderData.needCountO;
+    // this.echartsData.forEach((item, index) => {
+    //   item.itemStyle = {
+    //     color: this.color[index]
+    //   }
+    // })
+  },
+  components: {
+    fanChart
+  },
+  methods: {
+  },
+  props: {
+    id: {
+      type: String,
+      default: function createRandomId() {
+        return (Math.random() * 10000000).toString(16).substr(0, 4) + '-' + (new Date()).getTime() + '-' + Math.random().toString().substr(2, 5);
+      }
+    },
+    renderData: {
+      type: Object,
+      default: function () {
+        return {}
+      }
+    }
+  },
+}
+</script>
+
+<style lang="less" scoped>
+.mess-view {
+  box-sizing: border-box;
+  border-bottom: 1px solid #ddd;
+  padding: 10px 20px 10px 15px;
+  .saga-title {
+    font-size: 14px;
+    color: #333;
+    font-weight: 600;
+    line-height: 14px;
+  }
+  i {
+    span {
+      padding-left: 6px;
+    }
+  }
+}
+.saga-fill {
+  width: 345px;
+  // height: 220px;
+  .doughnut-view {
+    height: 165px;
+    width: 100%;
+    padding: 0 5px;
+    box-sizing: border-box;
+  }
+}
+</style>

+ 101 - 0
src/components/ledger/report/dataorigin.vue

@@ -0,0 +1,101 @@
+<template>
+  <div class="saga-fill">
+    <div class="mess-view">
+      <el-tooltip class="item" effect="dark" :content="renderData.tips" placement="bottom-start">
+        <i class="el-icon-info"><span>{{renderData.title}}</span></i>
+      </el-tooltip>
+    </div>
+    <div class="doughnut-view">
+      <report-doughnut v-if="renderData.needCountO || renderData.needCountT" type="type" width="200" height="200" :sum="renderData.sum"
+        :name="renderData.title" :renderData="echartsData" :id="id" :text="renderData.text">
+      </report-doughnut>
+    </div>
+    <slot></slot>
+  </div>
+</template>
+
+<script>
+import reportDoughnut from "@/components/echarts/reportDoughnut"
+export default {
+  name: "dataOrgin",
+  components: {
+    reportDoughnut
+  },
+  props: {
+    id: {
+      type: String,
+      default: function createRandomId() {
+        return (Math.random() * 10000000).toString(16).substr(0, 4) + '-' + (new Date()).getTime() + '-' + Math.random().toString().substr(2, 5);
+      }
+    },
+    renderData: {
+      type: Object,
+      default: function () {
+        return {
+
+        }
+      }
+    }
+  },
+  data() {
+    return {
+      echartsData: []
+    }
+  },
+  created() {
+    this.changeData()
+  },
+  mounted() { },
+  methods: {
+    changeData() {
+      this.echartsData = [
+        {
+          name: this.renderData.contentValueO + this.renderData.needCountO,
+          value: this.renderData.needCountO
+        },
+        {
+          name: this.renderData.contentValueT + this.renderData.needCountT,
+          value: this.renderData.needCountT
+        },
+      ]
+    }
+  },
+  watch: {
+    renderData: {
+      deep: true,
+      handler: function () {
+        this.changeData()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.mess-view {
+  box-sizing: border-box;
+  border-bottom: 1px solid #ddd;
+  padding: 10px 20px 10px 15px;
+  .saga-title {
+    font-size: 14px;
+    color: #333;
+    font-weight: 600;
+    line-height: 14px;
+  }
+  i {
+    span {
+      padding-left: 6px;
+    }
+  }
+}
+.saga-fill {
+  width: 345px;
+  // height: 220px;
+  .doughnut-view {
+    height: 165px;
+    width: 100%;
+    padding: 0 5px;
+    box-sizing: border-box;
+  }
+}
+</style>

+ 180 - 0
src/components/ledger/system/dialog/addCenoteDialog.vue

@@ -0,0 +1,180 @@
+<template>
+  <el-dialog :title="title" :visible.sync="dialogVisible" width="900px" id="addEqDialog">
+    <el-row class="filters">
+      <el-col :span="7" style="width:268px">
+        <el-input placeholder="输入竖井名称或竖井本地编码进行查询" v-model="keycode" clearable @keyup.enter.native="getTableData">
+          <i slot="suffix" class="el-input__icon el-icon-search" @click="getTableData"></i>
+        </el-input>
+      </el-col>
+      <el-col :span="7.5">
+        <cenote-type @change="changeCenote"></cenote-type>
+      </el-col>
+    </el-row>
+    <div class="table-box">
+      <el-table :data="tableData" style="width: 100%" height="350" v-loading="loading" :header-cell-style="headerStyle" ref="multipleTable"
+        @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55"></el-table-column>
+        <el-table-column :label="`${inSpaceType}名称`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.ShaftLocalName||scope.row.ShaftName||''}}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="ShaftLocalID" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="StructureInfo.ShaftFuncType" :label="`${inSpaceType}类`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <el-button size="mini" @click="toDetail(scope.$index, scope.row)" plain>查看详情</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <el-pagination class="fr" v-show="tableData && tableData.length" @size-change="handleSizeChange" @current-change="handleCurrentChange"
+        :current-page="page.pageNumber" :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper"
+        :total="page.total"></el-pagination>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button size="small" @click="dialogVisible = false">取 消</el-button>
+      <el-button size="small" type="primary" @click="savaRelation">确 定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { unSysShaft, queryShaftType, linkSysSh } from "@/api/scan/request";
+import cenoteType from "@/components/ledger/lib/cenoteType";
+import { mapGetters } from "vuex";
+export default {
+  components: {
+    cenoteType
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      title: "添加系统所在竖井",
+      keycode: '', //输入查询条件
+      cenoteType: '', // 选中的竖井类型
+      shaftType: {}, //全部竖井类型
+      inSpaceType: '竖井',
+      dialogVisible: false,
+      tableData: [],
+      loading: false,
+      selections: [], // 选中项
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      } // 列表样式
+    };
+  },
+  props: {
+    type: String, //选中的tab页
+    params: Object //查看的竖井关系信息
+  },
+  created() {
+    queryShaftType(res => {
+      res.Content.forEach(item => {
+        this.shaftType[item.Code] = item.Name
+      })
+    })
+  },
+  methods: {
+    //修改竖井类型
+    changeCenote(value) {
+      this.cenoteType = value.Id
+      this.getTableData()
+    },
+    // 显示弹窗
+    showDialog() {
+      this.dialogVisible = true
+      this.page.pageNumber = 1
+      this.tableData = []
+      this.getTableData()
+    },
+    getTableData() {
+      let params = {
+        data: {
+          Filters: this.cenoteType ? `ProjectId='${this.projectId}';structureInfo.ShaftFuncType='${this.cenoteType}'` : `ProjectId='${this.projectId}'`,
+          Orders: "createTime desc, ShaftID asc",
+          PageNumber: this.page.pageNumber,
+          PageSize: this.page.pageSize,
+        },
+        shaftId: this.params.ShaftID,
+        sysId: this.$route.query.SysID
+      }
+      if (this.keycode != '') {
+        params.data.Filters += `;ShaftName contain '${this.keycode}' or ShaftLocalName contain '${this.keycode}' or ShaftLocalID contain '${this.keycode}'`
+      }
+      unSysShaft(params, res => {
+        this.tableData = res.Content
+        this.tableData.forEach(item => {
+          if (item.StructureInfo && item.StructureInfo.ShaftFuncType) {
+            item.StructureInfo.ShaftFuncType = this.shaftType[item.StructureInfo.ShaftFuncType]
+          }
+        })
+        this.page.total = res.Total
+      })
+    },
+    //选中项修改
+    handleSelectionChange(val) {
+      this.selections = val;
+    },
+    savaRelation() {
+      if (this.selections.length) {
+        let params = {
+          SysId: this.$route.query.SysID,
+          ShaftIdList: this.selections.map(item => {
+            return item.ShaftID
+          })
+        }
+        linkSysSh(params, res => {
+          this.dialogVisible = false
+          this.$message.success('关联成功!')
+          this.$emit('refresh')
+        })
+      } else {
+        this.$message('请选择要关联的设备')
+      }
+    },
+    //改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    //改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    // 查看详情
+    toDetail() {
+      this.$message('开发中')
+    }
+  },
+};
+</script>
+<style lang="less" scoped>
+#addEqDialog {
+  .filters {
+    margin-bottom: 10px;
+    /deep/ .el-input__inner {
+      vertical-align: baseline;
+    }
+  }
+  .table-box {
+    height: 370px;
+    .fr {
+      margin-top: 10px;
+    }
+  }
+}
+</style>

+ 209 - 0
src/components/ledger/system/dialog/addEquipDialog.vue

@@ -0,0 +1,209 @@
+<template>
+  <el-dialog :title="title" :visible.sync="dialogVisible" width="900px" id="addEqDialog">
+    <el-row class="filters">
+      <el-col :span="7" style="width:268px">
+        <el-input placeholder="输入设备名称或设备本地编码进行查询" v-model="keycode" clearable @keyup.enter.native="getTableData">
+          <i slot="suffix" class="el-input__icon el-icon-search" @click="getTableData"></i>
+        </el-input>
+      </el-col>
+      <el-col :span="8.5" style="padding:0 0;">
+        <floor-cascader @change="changeFloor" style="margin-left:5px;"></floor-cascader>
+      </el-col>
+      <el-col :span="8.5" style="padding-right:0;">
+        <myCascader @change="changeDevice" :all="true" :params="childParams"></myCascader>
+      </el-col>
+    </el-row>
+
+    <div class="table-box">
+      <el-table :data="tableData" style="width: 100%" height="350" v-loading="loading" :header-cell-style="headerStyle" ref="multipleTable"
+        @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55"></el-table-column>
+        <el-table-column :label="`${inSpaceType}名称`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>{{scope.row.EquipLocalName||scope.row.EquipName||''}}</div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="EquipLocalID" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="EquipCategory.EquipName" :label="`${inSpaceType}类`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <el-button size="mini" @click="toDetail(scope.$index, scope.row)" plain>查看详情</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <el-pagination class="fr" v-show="tableData && tableData.length" @size-change="handleSizeChange" @current-change="handleCurrentChange"
+        :current-page="page.pageNumber" :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper"
+        :total="page.total"></el-pagination>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button size="small" @click="dialogVisible = false">取 消</el-button>
+      <el-button size="small" type="primary" @click="savaRelation">确 定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { sysLinkEquip, unSysEq } from "@/api/scan/request";
+import floorCascader from "@/components/ledger/lib/floorCascader";
+import myCascader from "@/components/ledger/system/lib/equipType";
+import { mapGetters } from "vuex";
+export default {
+  components: {
+    floorCascader,
+    myCascader
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      title: "添加系统内设备",
+      keycode: "", //输入查询条件
+      Buildfloor: ["all"], // 选中的建筑楼层
+      Equipcategory: null, // 选中的设备类型
+      inSpaceType: "设备",
+      dialogVisible: false,
+      tableData: [],
+      loading: false,
+      selections: [], // 选中项
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      headerStyle: {
+        backgroundColor: "#e1e4e5",
+        color: "#2b2b2b",
+        lineHeight: "30px"
+      } // 列表样式,
+    };
+  },
+  computed: {
+    childParams() {
+      let temp = JSON.parse(JSON.stringify(this.params));
+      temp.SysType = null;
+      return temp;
+    }
+  },
+  props: {
+    type: String, //选中的tab页
+    params: Object //查看的竖井关系信息
+  },
+  created() { },
+  methods: {
+    //修改建筑楼层
+    changeFloor(value) {
+      this.Buildfloor = value;
+      this.getTableData();
+    },
+    // 显示弹窗
+    showDialog() {
+      this.dialogVisible = true;
+      this.page.pageNumber = 1;
+      this.tableData = [];
+      this.getTableData();
+    },
+    getTableData() {
+      let params = {
+        data: {
+          Filters: `not EquipID isNull`,
+          Cascade: [{ Name: "equipCategory" }],
+          Orders: "createTime desc, EquipID desc",
+          PageNumber: this.page.pageNumber,
+          PageSize: this.page.pageSize
+        },
+        shaftId: this.params.ShaftID,
+        sysId: this.$route.query.SysID
+      };
+      if (this.Buildfloor[0] == "noKnow") {
+        params.data.Filters += `;buildingId isNull`;
+      } else if (this.Buildfloor[0] && this.Buildfloor[0] != "all") {
+        params.data.Filters += `;buildingId='${this.Buildfloor[0]}'`;
+      }
+      if (this.Buildfloor[1] == "noKnow") {
+        params.data.Filters += `;floorId isNull`;
+      } else if (this.Buildfloor[1] && this.Buildfloor[1] != "all") {
+        params.data.Filters += `;floorId='${this.Buildfloor[1]}'`;
+      }
+      if (this.keycode != "") {
+        params.data.Filters += `;EquipName contain '${this.keycode}' or EquipLocalName contain '${this.keycode}' or EquipLocalID contain '${this.keycode}'`;
+      }
+      if (this.Equipcategory) {
+        params.data.Filters += `;category='${this.Equipcategory}'`;
+      }
+      unSysEq(params, res => {
+        res.Content.forEach(item => {
+          item.ShaftListName = "";
+          if (item.ShaftList && item.ShaftList.length) {
+            item.ShaftListName = item.ShaftList.map(shaft => {
+              return shaft.ShaftLocalName
+                ? shaft.ShaftLocalName
+                : shaft.ShaftName;
+            }).join("、");
+          }
+        });
+        this.tableData = res.Content;
+        this.page.total = res.Total;
+      });
+    },
+    //选中项修改
+    handleSelectionChange(val) {
+      this.selections = val;
+    },
+    savaRelation() {
+      if (this.selections.length) {
+        let params = {
+          SysId: this.$route.query.SysID,
+          EquipIdList: this.selections.map(item => {
+            return item.EquipID;
+          })
+        };
+        sysLinkEquip(params, res => {
+          this.dialogVisible = false;
+          this.$message.success("关联成功!");
+          this.$emit("refresh");
+        });
+      } else {
+        this.$message("请选择要关联的设备");
+      }
+    },
+    //修改设备类别
+    changeDevice(value) {
+      this.Equipcategory = value.code;
+      this.getTableData();
+    },
+    //改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    //改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    // 查看详情
+    toDetail() {
+      this.$message("开发中");
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#addEqDialog {
+  .filters {
+    margin-bottom: 10px;
+  }
+  .table-box {
+    height: 370px;
+    .fr {
+      margin-top: 10px;
+    }
+  }
+}
+/deep/ #buildFloor .buildFloor {
+  margin: 0 5px 0 5px;
+}
+</style>

+ 225 - 0
src/components/ledger/system/dialog/addSpaceDialog.vue

@@ -0,0 +1,225 @@
+<template>
+  <el-dialog :title="title" :visible.sync="dialog" :before-close="handleClose" width="900px" id="addEqDialog">
+    <el-row class="filters">
+      <el-col :span="7" style="width:268px;padding:0px;">
+        <el-input style placeholder="输入业务空间名称、本地编码进行查询" v-model="keycode" clearable @keyup.enter.native="getTableData">
+          <i slot="suffix" class="el-input__icon el-icon-search" @click="getTableData"></i>
+        </el-input>
+      </el-col>
+      <el-col :span="8.5" style="padding:0 0;margin-left:-2px">
+        <floor-cascader ref="floorcas" @change="changeFloor"></floor-cascader>
+      </el-col>
+      <el-col :span="7.5" style="padding:0 0;">
+        <space-select ref="spacesel" @change="changeSpace"></space-select>
+      </el-col>
+    </el-row>
+    <el-row class="filters" :gutter="20"></el-row>
+    <div class="table-box">
+      <el-table :data="tableData" style="width: 100%" height="350" v-loading="loading" :header-cell-style="headerStyle" ref="multipleTable"
+        @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55"></el-table-column>
+        <el-table-column :label="`${inSpaceType}本地名称`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            {{scope.row.RoomLocalName||scope.row.RoomName||''}}
+          </template>
+        </el-table-column>
+        <el-table-column prop="RoomLocalID" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop :label="`所属建筑楼层`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            {{ scope.row.BuildingId && floorType[scope.row.BuildingId]? ((floorType[scope.row.BuildingId] || '') + (scope.row.FloorId && floorType[scope.row.FloorId] ? (' - ' + floorType[scope.row.FloorId] || '') : '')) : ''}}
+          </template>
+        </el-table-column>
+        <el-table-column prop="ObjectType" :label="`空间类型`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            {{spaceType[scope.row.ObjectType] || ''}}
+          </template>
+        </el-table-column>
+        <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <el-button size="mini" @click="toDetail(scope.$index, scope.row)" plain>查看详情</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <el-pagination class="fr" v-show="tableData && tableData.length" @size-change="handleSizeChange" @current-change="handleCurrentChange"
+        :current-page="page.pageNumber" :page-sizes="page.pageSizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper"
+        :total="page.total"></el-pagination>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button size="small" @click="handleClose">取 消</el-button>
+      <el-button size="small" type="primary" @click="savaRelation">确 定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import {
+  unSysZoneSpace,
+  linkSysSp,
+  queryDictionaryHead
+} from "@/api/scan/request";
+import floorCascader from "@/components/ledger/lib/floorCascader";
+import dictionaryCas from "@/components/config_point/dictionaryCascader";
+import spaceSelect from "@/components/ledger/lib/spaceSelect";
+import { mapGetters } from "vuex";
+export default {
+  components: {
+    floorCascader,
+    dictionaryCas,
+    spaceSelect
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"]),
+    dialog() {
+      return this.dialogVisible;
+    }
+  },
+  data() {
+    return {
+      title: "添加系统所在业务空间",
+      keycode: "", //输入查询条件
+      inSpaceType: "业务空间",
+      Buildfloor: ["all"], // 选中的建筑楼层
+      Spacecategory: null, // 选中的业务空间类型
+      tableData: [],
+      floorData: {}, //楼层
+      spaceData: {}, //业务空间分区
+      loading: false,
+      selections: [], // 选中项
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      headerStyle: {
+        backgroundColor: "#e1e4e5",
+        color: "#2b2b2b",
+        lineHeight: "30px"
+      } // 列表样式
+    };
+  },
+  props: {
+    type: String, //选中的tab页
+    params: Object, //查看的竖井关系信息
+    spaceType: Object,
+    dialogVisible: Boolean,
+    floorType: Object
+  },
+  mounted() { },
+  methods: {
+    // 显示弹窗
+    showDialog() {
+      this.dialogVisible = true;
+    },
+    //修改建筑楼层
+    changeFloor(value) {
+      this.Buildfloor = value;
+      this.getTableData();
+    },
+    //修改空间类型
+    changeSpace(value) {
+      this.Spacecategory = value;
+      this.getTableData();
+    },
+    getTableData() {
+      let params = {
+        data: {
+          Filters: "not RoomID isNull",
+          Orders: "RoomLocalName desc",
+          PageNumber: this.page.pageNumber,
+          PageSize: this.page.pageSize
+        },
+        shaftId: this.params.ShaftID,
+        sysId: this.$route.query.SysID
+      };
+      if (this.Buildfloor[0] == "noKnow") {
+        params.data.Filters += `;buildingId isNull`;
+      } else if (this.Buildfloor[0] && this.Buildfloor[0] != "all") {
+        params.data.Filters += `;buildingId='${this.Buildfloor[0]}'`;
+      }
+      if (this.Buildfloor[1] == "noKnow") {
+        params.data.Filters += `;floorId isNull`;
+      } else if (this.Buildfloor[1] && this.Buildfloor[1] != "all") {
+        params.data.Filters += `;floorId='${this.Buildfloor[1]}'`;
+      }
+      if (this.Spacecategory) {
+        params.data.Filters += `;ObjectType='${this.Spacecategory}'`;
+      }
+      if (this.keycode != "") {
+        params.data.Filters += `;RoomName contain '${this.keycode}' or RoomLocalName contain '${this.keycode}'`;
+      }
+
+      unSysZoneSpace(params, res => {
+        this.tableData = res.Content;
+        this.page.total = res.Total;
+      });
+    },
+    handleClose() {
+      this.$emit("update:dialogVisible", false);
+    },
+    //选中项修改
+    handleSelectionChange(val) {
+      this.selections = val;
+    },
+    savaRelation() {
+      if (this.selections.length) {
+        let params = {
+          Content: this.selections.map(item => {
+            return {
+              SpaceID: item.RoomID,
+              SysID: this.$route.query.SysID,
+              ObjectType: item.ObjectType
+            };
+          })
+        };
+        linkSysSp(params, res => {
+          this.$message.success("关联成功!");
+          this.$emit("refresh");
+        });
+      } else {
+        this.$message("请选择要关联的设备");
+      }
+    },
+    //改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    //改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    // 查看详情
+    toDetail() {
+      this.$message("开发中");
+    }
+  },
+  watch: {
+    dialogVisible: {
+      handler() {
+        if (this.dialogVisible) {
+          this.page.pageNumber = 1;
+          this.tableData = [];
+          this.getTableData();
+        }
+      },
+      immediate: true
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#addEqDialog {
+  .filters {
+    margin: 0 0 10px 0;
+  }
+  .table-box {
+    height: 370px;
+    .fr {
+      margin-top: 10px;
+    }
+  }
+}
+</style>

+ 140 - 0
src/components/ledger/system/lib/equipType.vue

@@ -0,0 +1,140 @@
+<template>
+  <div id="cascaderMap">
+    <span class="buildFloor" style="margin-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.code" :label="item.facility" :value="item.code"></el-option>
+    </el-select>
+  </div>
+</template>
+<script>
+import { mapGetters } from 'vuex';
+import { queryPhysicsAllType, queryEquip } from "@/api/scan/request";
+export default {
+  name: "getCode",
+  props: {
+    isWidth: {
+      type: Boolean,
+      default: true
+    },
+    all: {
+      type: Boolean,
+      default: false,
+    },
+    //系统
+    params: Object
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      value: "",
+      options: [],
+      props: {
+        value: "code",
+        label: "facility"
+      },
+      falg: true,
+      content: []
+    };
+  },
+  created() {
+    this.getData();
+  },
+  watch: {
+    projectId() {
+      this.value = '';
+      this.getData();
+    }
+  },
+  methods: {
+    setValue(val) {
+      this.value = val
+    },
+    //修改val
+    changeVal(val) {
+      let value = {}
+      this.options.map(item => {
+        if (item.code == val) {
+          value = item
+        }
+      })
+      this.value = val
+      this.$emit("change", value)
+    },
+    //获取当前项目下的设备类型(只拿到编码-需要过滤)
+    getData() {
+      let param2 = {
+        Distinct: true,
+        PageNumber: 1,
+        PageSize: 500,
+        Projection: [
+          "Category"
+        ]
+      }
+      let param1 = 'Equipment'
+      let promise2 = new Promise((resolve, reject) => {
+        queryEquip(param2, res => {
+          resolve(res)
+        })
+      })
+      let promise1 = new Promise((resolve, reject) => {
+        queryPhysicsAllType(param1, res => {
+          let tempArr = res.Content;
+          if (this.params.SysType) {
+            tempArr = res.Content.filter(t => {
+              return t.ParentId == `${this.params.SysType}`
+            })
+          }
+          resolve(tempArr)
+        })
+      })
+      Promise.all([promise1, promise2]).then((res) => {
+        let allData = res[0], data = res[1]
+        this.options = this.formatOptions(allData)
+        if (this.value) {
+          this.changeVal(this.value)
+        }
+        if (!this.all) {
+          this.content = data.Content.map(t => {
+            return t.Category
+          });
+          this.filterForOptions();
+          if (this.value) {
+            this.changeVal(this.value)
+          }
+        }
+      })
+    },
+    //格式化options数据
+    formatOptions(arr) {
+      let data = [];
+      arr.map(t => {
+        let temp = {};
+        temp.code = t.Code;
+        temp.facility = t.Name;
+        data.push(temp)
+      })
+      return data;
+    },
+    //过滤
+    filterForOptions() {
+      this.options = this.options.filter(item => {
+        if (this.content.indexOf(item.code) > -1) {
+          return item
+        }
+      })
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#cascaderMap {
+  float: left;
+  margin-left: 10px;
+  .buildFloor {
+    color: #999999;
+    font-size: 14px;
+  }
+}
+</style>

+ 156 - 0
src/components/ledger/system/table/cenoteTable.vue

@@ -0,0 +1,156 @@
+<template>
+  <div id="eqInSp">
+    <el-row>
+      <el-button type="primary" @click="add">添加{{inSpaceType}}</el-button>
+      <el-tooltip class="item" effect="dark" content="可前往“全部关系总览”中,按系统内包含的设备与竖井关系计算" placement="right">
+        <el-button>按系统内设备与竖井关系计算</el-button>
+      </el-tooltip>
+    </el-row>
+    <div class="table-box">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column :label="`${inSpaceType}名称`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.ShaftLocalName||scope.row.ShaftName||''}}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="ShaftLocalID" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column :label="`${inSpaceType}类型`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.StructureInfo.ShaftFuncType}}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <el-tooltip class="item" effect="dark" content="删除关系" placement="left">
+              <el-button size="mini" @click="handleDelete(scope.$index, scope.row)" type="danger" plain icon="el-icon-delete"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <template slot="empty">
+          <div style="height: 60%;transform: translateY(50%);">
+            <i class="icon-wushuju iconfont"></i>
+            可前往“全部关系总览”中计算连通的其它竖井
+          </div>
+        </template>
+      </el-table>
+    </div>
+    <!-- 添加设备弹窗 -->
+    <addCenoteDialog ref="addCenoteDialog" @refresh="getTableData" :type="type" :params="params"></addCenoteDialog>
+  </div>
+</template>
+
+<script>
+import { queryLinkSys, queryShaftType, syinshUnlink } from "@/api/scan/request";
+import { mapGetters } from "vuex";
+import addCenoteDialog from "@/components/ledger/system/dialog/addCenoteDialog"
+export default {
+  components: {
+    addCenoteDialog
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      inSpaceType: '竖井',
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      }, // 列表样式
+      loading: false, // loading
+      tableData: [], //列表数据
+      shaftType: {} //竖井类型
+    };
+  },
+  props: {
+    params: Object,
+    type: String
+  },
+  created() {
+    queryShaftType(res => {
+      res.Content.forEach(item => {
+        this.shaftType[item.Code] = item.Name
+      })
+      this.getTableData()
+    })
+  },
+  methods: {
+    // 获取列表数据
+    getTableData() {
+      let params = {
+        Filters: `SysID='${this.params.SysID}'`,
+        Cascade: [
+          {
+            Name: 'shaftList',
+          }
+        ]
+      }
+      queryLinkSys(params, res => {
+        this.tableData = res.Content[0].Shaft || []
+        this.tableData.forEach(item => {
+          if (item.StructureInfo && item.StructureInfo.ShaftFuncType) {
+            item.StructureInfo.ShaftFuncType = this.shaftType[item.StructureInfo.ShaftFuncType]
+          }
+        })
+      })
+    },
+    // 删除关系
+    handleDelete(index, row) {
+      let sysId = this.$route.query.SysID
+      this.$confirm("确认删除该关系?", "提示", {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        let params = {
+          ShaftId: row.ShaftID,
+          SysId: sysId
+        }
+        this.deleteShThroughSh(params);
+      }).catch(() => {
+        this.$message("取消删除")
+      })
+    },
+    // 删除设备所在空间关系
+    deleteShThroughSh(params) {
+      syinshUnlink(params, res => {
+        this.$message.success('删除成功')
+        this.getTableData()
+      })
+    },
+    // 改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    // 改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    // 添加设备
+    add() {
+      this.$refs.addCenoteDialog.showDialog()
+    }
+  },
+  watch: {
+    type() {
+      // this.getTableData()
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#eqInSp {
+  height: 100%;
+  .table-box {
+    margin-top: 10px;
+    height: calc(100% - 50px);
+  }
+}
+</style>

+ 144 - 0
src/components/ledger/system/table/deviceTable.vue

@@ -0,0 +1,144 @@
+<template>
+  <div id="eqInSp">
+    <el-row>
+      <el-button type="primary" @click="add">添加{{inSpaceType}}</el-button>
+      <!-- <el-tooltip class="item" effect="dark" content="可前往“全部关系总览”中计算竖井内设备" placement="right">
+        <el-button>按空间计算</el-button>
+      </el-tooltip> -->
+    </el-row>
+    <div class="table-box">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column :label="`${inSpaceType}名称`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.EquipLocalName||scope.row.EquipName||''}}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="EquipLocalID" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column :label="`${inSpaceType}类型`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>
+              {{scope.row.EquipCategory.EquipName}}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <el-button title="删除关系" size="mini" @click="handleDelete(scope.$index, scope.row)" type="danger" plain icon="el-icon-delete"></el-button>
+          </template>
+        </el-table-column>
+        <template slot="empty">
+          <div style="height: 60%;transform: translateY(50%);">
+            <i class="icon-wushuju iconfont"></i>
+            可前往“全部关系总览”中计算竖井内设备
+          </div>
+        </template>
+      </el-table>
+    </div>
+    <!-- 添加设备弹窗 -->
+    <addEquipDialog ref="addEqDialog" @refresh="getTableData" :type="type" :params="params"></addEquipDialog>
+  </div>
+</template>
+
+<script>
+import { queryLinkSys, eqInSysUnlink } from "@/api/scan/request";
+import { mapGetters } from "vuex";
+import addEquipDialog from "@/components/ledger/system/dialog/addEquipDialog"
+export default {
+  components: {
+    addEquipDialog
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      inSpaceType: '设备',
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      }, // 列表样式
+      loading: false, // loading
+      tableData: [] //列表数据
+    };
+  },
+  props: {
+    params: Object,
+    type: String
+  },
+  created() {
+    this.getTableData()
+  },
+  methods: {
+    // 获取列表数据
+    getTableData() {
+      let params = {
+        Filters: `SysID='${this.params.SysID}'`,
+        Cascade: [
+          {
+            Name: 'equipmentList',
+            Cascade: [{ Name: 'equipCategory' }]
+          }
+        ]
+      }
+      queryLinkSys(params, res => {
+        this.tableData = res.Content[0].Equipment || []
+      })
+    },
+    // 删除关系
+    handleDelete(index, row) {
+      let sysId = this.$route.query.SysID
+      this.$confirm("确认删除该关系?", "提示", {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        let params = {
+          EquipId: row.EquipID,
+          SysId: sysId
+        }
+        this.deleteEqInSh(params);
+      }).catch(() => {
+        this.$message("取消删除")
+      })
+    },
+    // 删除设备所在竖井关系
+    deleteEqInSh(params) {
+      eqInSysUnlink(params, res => {
+        this.$message.success('删除成功')
+        this.getTableData()
+      })
+    },
+    // 改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    // 改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    // 添加设备
+    add() {
+      this.$refs.addEqDialog.showDialog()
+    }
+  },
+  watch: {
+    type() {
+      // this.getTableData()
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#eqInSp {
+  height: 100%;
+  .table-box {
+    margin-top: 10px;
+    height: calc(100% - 50px);
+  }
+}
+</style>

+ 156 - 0
src/components/ledger/system/table/spaceTable.vue

@@ -0,0 +1,156 @@
+<template>
+  <div id="eqInSp">
+    <el-row>
+      <el-button type="primary" @click="add">添加{{inSpaceType}}</el-button>
+      <el-tooltip class="item" effect="dark" content="可前往“全部关系总览”中,按系统内包含的设备与空间关系计算" placement="right">
+        <el-button>按系统内设备与业务空间关系计算</el-button>
+      </el-tooltip>
+    </el-row>
+    <div class="table-box">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column :label="`${inSpaceType}名称`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>{{ scope.row.RoomLocalName || scope.row.RoomName||''}}</div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="RoomLocalID" :label="`${inSpaceType}本地编码`" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column :label="`${inSpaceType}类型`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <div>{{ spaceType[scope.row.ObjectType]}}</div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="action" label="操作" min-width="100">
+          <template slot-scope="scope">
+            <el-tooltip class="item" effect="dark" content="删除关系" placement="left">
+              <el-button size="mini" @click="handleDelete(scope.$index, scope.row)" type="danger" plain icon="el-icon-delete"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <template slot="empty">
+          <div style="height: 60%;transform: translateY(50%);">
+            <i class="icon-wushuju iconfont"></i>
+            可前往“全部关系总览”中计算竖井内系统
+          </div>
+        </template>
+      </el-table>
+    </div>
+    <!-- 添加空间弹窗 -->
+    <addSpaceDialog :dialogVisible.sync="dialogVisible" ref="addSpaceDialog" @refresh="refresh" :params="params" :spaceType="spaceType"
+      :floorType="floorType"></addSpaceDialog>
+  </div>
+</template>
+
+<script>
+import { queryLinkSys, spaceInSysUnlink } from "@/api/scan/request";
+import { mapGetters } from "vuex";
+import addSpaceDialog from "@/components/ledger/system/dialog/addSpaceDialog";
+export default {
+  components: {
+    addSpaceDialog
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      inSpaceType: "业务空间",
+      dialogVisible: false,
+      headerStyle: {
+        backgroundColor: "#e1e4e5",
+        color: "#2b2b2b",
+        lineHeight: "30px"
+      }, // 列表样式
+      loading: false, // loading
+      tableData: [] //列表数据
+    };
+  },
+  props: {
+    params: Object,
+    type: String,
+    spaceType: Object,
+    floorType: {}
+  },
+  created() {
+    this.getTableData();
+  },
+  methods: {
+    // 获取列表数据
+    getTableData() {
+      let params = {
+        Filters: `SysID='${this.params.SysID}'`,
+        Cascade: [
+          {
+            Name: "zoneSpaceBaseTableList"
+          }
+        ]
+      };
+      queryLinkSys(params, res => {
+        this.tableData = res.Content[0].ZoneSpaceBaseTable || [];
+      });
+    },
+    // 删除关系
+    handleDelete(index, row) {
+      this.$confirm("确认删除该关系?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(() => {
+          let params = {
+            data: [
+              {
+                SysId: this.params.SysID,
+                SpaceId: row.RoomID
+              }
+            ],
+            type: row.ObjectType
+          };
+          this.deleteSyInSh(params);
+        })
+        .catch(() => {
+          this.$message("取消删除");
+        });
+    },
+    // 删除系统所在竖井关系
+    deleteSyInSh(params) {
+      spaceInSysUnlink(params, res => {
+        this.$message.success("删除成功");
+        this.getTableData();
+      });
+    },
+    // 改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    // 改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    // 添加设备
+    add() {
+      this.dialogVisible = true;
+    },
+    //刷新
+    refresh() {
+      this.dialogVisible = false;
+      this.getTableData()
+    }
+  },
+  watch: {
+    type() {
+      // this.getTableData()
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#eqInSp {
+  height: 100%;
+  .table-box {
+    margin-top: 10px;
+    height: calc(100% - 50px);
+  }
+}
+</style>

+ 20 - 17
src/components/model/file/addFloorDialog.vue

@@ -82,7 +82,7 @@ export default {
     FolderId: String
   },
   computed: {
-    ...mapGetters("layout", ["projectId", "userInfo","userId", "secret"])
+    ...mapGetters("layout", ["projectId", "userInfo","userId", "secret", "uploaderList"])
   },
   data() {
     return {
@@ -137,6 +137,8 @@ export default {
       let FloorName = null;
       if (this.form.file == null) {
         this.$message.error("模型文件不能为空!");
+      } else if (this.uploaderList.some(item => {return item.name === this.form.file.name})) {
+        this.$message.error("该文件在上传列表中已存在!");
       } else {
         let FloorName = null;
         // 根据是否有夹层拼接楼层名
@@ -158,24 +160,25 @@ export default {
           this.$message.error('该楼层名称已存在,请勿重复创建!');
         } else {
           let data = {
-            ProjectId: this.projectId,
-            FolderId: this.FolderId,
+            FileName: this.form.file.name,
             FloorName: FloorName,
-            Form: this.form,
-            userName: this.userInfo.userName,
-            userId: this.userInfo.userId
+            FolderId: this.FolderId,
+            Note: this.form.desc,
+            ProjectId: this.projectId,
+            ReplaceReason: null,
+            Size: this.form.file.size,
+            UserName: this.userInfo.userName,
+            UserId: this.userInfo.userId
           };
-          request.createFloor(data).then(res => {
-            if (res.Result == "success") {
-              //  创建成功
-              this.$emit("finishCreateFloor", {
-                FloorModelId: res.FloorModelId,
-                CurrentModelId:res.CurrentModelId,
-                Form: this.form
-              });
-              this.handleClose();
-              // this.submitUpload(res.FloorModelId);
-            }
+          request.modelFileUpload(data, res => {
+            //  创建成功
+            this.$emit("finishCreateFloor", {
+              modelId: res.ModelId,
+              uploadId: res.UploadId,
+              floorId: res.floorId, 
+              file: this.form.file
+            });
+            this.handleClose();
           });
         }
       }

+ 0 - 0
src/components/model/file/floorTable.vue


Some files were not shown because too many files changed in this diff