소스 검색

Merge branch 'dev' of http://39.106.8.246:3003/web/ibms into mainteance

# Conflicts:
#	src/components/business_space/dialogs/list/firm.vue
#	src/components/dialogs/list/firm.vue
#	src/components/ledger/handsontables/device.vue
shaun-sheep 5 년 전
부모
커밋
71bbd1416e
100개의 변경된 파일11461개의 추가작업 그리고 2276개의 파일을 삭제
  1. 109 0
      src/api/data_admin/buildTaskApi.js
  2. 56 0
      src/api/msgsever.js
  3. 165 2
      src/api/scan/request.js
  4. BIN
      src/assets/house.jpg
  5. 14 6
      src/assets/style/iconfont/iconfont.css
  6. BIN
      src/assets/style/iconfont/iconfont.eot
  7. 7 1
      src/assets/style/iconfont/iconfont.svg
  8. BIN
      src/assets/style/iconfont/iconfont.ttf
  9. BIN
      src/assets/style/iconfont/iconfont.woff
  10. 15 1
      src/components/business_space/business/handsontable.vue
  11. 63 19
      src/components/business_space/dialogs/list/firm.vue
  12. 2 1
      src/components/business_space/newAddDialogs/addEquipDialog.vue
  13. 1 0
      src/components/business_space/newAddDialogs/addSystemDialog.vue
  14. 42 9
      src/components/business_space/newGraphy/canvasFun.vue
  15. 364 158
      src/components/business_space/newGraphy/graphy.vue
  16. 137 27
      src/components/business_space/newGraphy/unRelateBSP.vue
  17. 1 1
      src/components/business_space/newTables/eqToSpaceTable.vue
  18. 1 0
      src/components/common/handsontable.vue
  19. 49 172
      src/components/config_point/dictionaryCascader.vue
  20. 3 3
      src/components/config_point/step3_edit/index.vue
  21. 3 3
      src/components/config_point/step3_point/3_temps.vue
  22. 1 0
      src/components/config_point/step3_point/steps3_main.vue
  23. 184 0
      src/components/data_admin/buildTask/detail/assetsDetail.vue
  24. 219 0
      src/components/data_admin/buildTask/detail/deviceDetail.vue
  25. 97 0
      src/components/data_admin/buildTask/dialog/addTaskDialog.vue
  26. 253 0
      src/components/data_admin/buildTask/dialog/modelTaskDialog.vue
  27. 239 0
      src/components/data_admin/buildTask/draw/drawModel.vue
  28. 70 0
      src/components/data_admin/buildTask/lib/assetsCascader.vue
  29. 70 0
      src/components/data_admin/buildTask/lib/deviceCascader.vue
  30. 70 0
      src/components/data_admin/buildTask/lib/modelCascader.vue
  31. 81 0
      src/components/data_admin/buildTask/lib/modelFile.vue
  32. 53 0
      src/components/data_admin/buildTask/lib/taskState.vue
  33. 220 0
      src/components/data_admin/buildTask/table/assetsTable.vue
  34. 248 0
      src/components/data_admin/buildTask/table/deviceTable.vue
  35. 238 0
      src/components/data_admin/buildTask/table/modelTable.vue
  36. 202 0
      src/components/data_admin/buildTask/table/replaceTable.vue
  37. 202 0
      src/components/data_admin/buildTask/table/tearTable.vue
  38. 160 0
      src/components/data_admin/buildTask/taskStatistics.vue
  39. 135 0
      src/components/data_admin/zoneInput.vue
  40. 11 7
      src/components/dialogs/list/firm.vue
  41. 223 0
      src/components/ledger/cenote/dialog/addSpaceDialog.vue
  42. 13 4
      src/components/ledger/handsontables/assets.vue
  43. 2 0
      src/components/ledger/handsontables/device.vue
  44. 62 32
      src/components/ledger/handsontables/system.vue
  45. 1 1
      src/components/ledger/lib/assets.vue
  46. 94 0
      src/components/ledger/lib/buildfloorCascader.vue
  47. 1 1
      src/components/ledger/lib/cascader.vue
  48. 299 0
      src/components/ledger/lib/cenoteGraphy.vue
  49. 107 0
      src/components/ledger/lib/editSysFloor.vue
  50. 6 5
      src/components/ledger/lib/floorCascader.vue
  51. 65 0
      src/components/ledger/lib/spaceSelect.vue
  52. 180 0
      src/components/ledger/system/dialog/addCenoteDialog.vue
  53. 209 0
      src/components/ledger/system/dialog/addEquipDialog.vue
  54. 225 0
      src/components/ledger/system/dialog/addSpaceDialog.vue
  55. 140 0
      src/components/ledger/system/lib/equipType.vue
  56. 156 0
      src/components/ledger/system/table/cenoteTable.vue
  57. 144 0
      src/components/ledger/system/table/deviceTable.vue
  58. 156 0
      src/components/ledger/system/table/spaceTable.vue
  59. 281 0
      src/components/point/dynamicdata/buildRules.vue
  60. 19 1
      src/components/point/dynamicdata/delRelationDialog.vue
  61. 1 1
      src/components/point/dynamicdata/equipRules.vue
  62. 289 0
      src/components/point/dynamicdata/floorRules.vue
  63. 25 5
      src/components/point/dynamicdata/historyDialog.vue
  64. 8 2
      src/components/point/dynamicdata/locationCascader.vue
  65. 287 0
      src/components/point/dynamicdata/projectRules.vue
  66. 278 0
      src/components/point/dynamicdata/tenantRules.vue
  67. 107 0
      src/components/ready/buildfloor/modelFile.vue
  68. 83 0
      src/components/ready/buildfloor/modelFolder.vue
  69. 6 0
      src/fetch/point_http.js
  70. 322 45
      src/framework/components/messagesever/index.vue
  71. 209 0
      src/framework/components/messagesever/msgAllDetails.vue
  72. 29 10
      src/framework/components/messagesever/msmq.js
  73. 14 10
      src/framework/layout/layout-store.js
  74. 110 17
      src/router/system.js
  75. 31 3
      src/store/modules/project.js
  76. 29 2
      src/utils/handsontable/mainText.js
  77. 1 1
      src/utils/handsontable/notShow.js
  78. 26 0
      src/utils/scan/directive.js
  79. 4 0
      src/utils/scan/tools.js
  80. 10 0
      src/utils/spaceColor.js
  81. 27 0
      src/utils/tools.js
  82. 161 0
      src/views/business_space/dataUtil/index2.vue
  83. 24 64
      src/views/data_admin/buildData/index.vue
  84. 214 0
      src/views/data_admin/buildGraphy/createPointZone.vue
  85. 349 909
      src/views/data_admin/buildGraphy/graphyCanvas.vue
  86. 481 452
      src/views/data_admin/buildGraphy/graphyTabs.vue
  87. 222 228
      src/views/data_admin/buildGraphy/index.vue
  88. 78 0
      src/views/data_admin/buildGraphy/locationPointMsg.vue
  89. 272 0
      src/views/data_admin/buildGraphy/updatePointZone.vue
  90. 241 0
      src/views/data_admin/buildTask/addTask/addAssetsTask.vue
  91. 301 0
      src/views/data_admin/buildTask/addTask/addDeviceTask.vue
  92. 211 0
      src/views/data_admin/buildTask/addTask/addModelTask.vue
  93. 152 30
      src/views/data_admin/buildTask/index.vue
  94. 5 28
      src/views/ledger/cenotelist/index.vue
  95. 402 0
      src/views/ledger/cenotelist/relatedSpace.vue
  96. 256 0
      src/views/ledger/cenotelist/relatedSpaceList.vue
  97. 9 5
      src/views/ledger/facility/addfacility.vue
  98. 9 5
      src/views/ledger/facility/partsmanage/addparts/index.vue
  99. 10 5
      src/views/ledger/facility/partsmanage/index.vue
  100. 0 0
      src/views/ledger/property/addproperty.vue

+ 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)
+}

+ 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)
+}

+ 165 - 2
src/api/scan/request.js

@@ -171,6 +171,37 @@ export function getPT(param) {
     return fetch({ method: 'POST', url: `${api}/service/fm/point_group`, data })
 }
 
+//查询点位标签信息/location-point/query
+export function locationPointQuery(param, success) {
+    let url = `${baseUrl}/datacenter/location-point/query`;
+    http.postJson(url, param, success)
+}
+
+//点位标签详情修改【数据中心接口】
+export function updateLocationPoint(param, success) {
+    let url = `${baseUrl}/datacenter/location-point/update`;
+    http.postJson(url, param, success)
+}
+
+//根据点位标签推荐业务空间
+export function zoneQueryByPoint(param, success) {
+    let url = `${baseUrl}/equip-component/space/in-bdfl-zonespacebase?X=${param.X}&Y=${param.Y}`;
+    http.postJson(url, param.data, success)
+}
+
+//更新业务空间图片
+export function updateZonePic(param, success) {
+    let url = `${baseUrl}/equip-component/space/update-space-picinfo`;
+    http.postJson(url, param, success)
+}
+
+//扫楼作业-位置标签-删除图片
+export function deleteLocationImg(param, success) {
+    let url = `${baseUrl}/datacenter/location-point/delete-image`;
+    http.postJson(url, param, success)
+}
+
+
 //点位标签查看详情
 export function getPoint(param) {
     let data = {
@@ -690,13 +721,27 @@ export function getSysToEq(param, success) {
     http.postJson(url, data, success)
 }
 
-//台账查询型号
+//按生产商名, 品牌名, 型号名模糊查询型号
 export function getSpecList(param, success) {
     let url = `${venders}/manufacturer/specification/query_spec`
     let data = param
     http.postJson(url, data, success)
 }
 
+//按品牌名称和生厂商名称模糊查询品牌
+export function getBrandList(param, success) {
+    let url = `${venders}/manufacturer/brand/queryByName`
+    let data = param
+    http.postJson(url, data, success)
+}
+
+//按名称模糊查询生产商
+export function getManufacturerList(param, success) {
+    let url = `${venders}/manufacturer/queryByName`
+    let data = param
+    http.postJson(url, data, success)
+}
+
 //台账根据设备id创建岗位
 export function EqToAssets(param, success) {
     let url = `${physics}/property/create_by_equip?projectId=${param.ProjId}&secret=${param.secret}`
@@ -765,6 +810,36 @@ export function saveCenoteRelateSpace(param, success) {
     http.postJson(url, param, success)
 }
 
+//竖井关联的业务空间的楼层
+export function shaftSpaceBuildingQuery(param, success) {
+    let url = `${baseUrl}/datacenter/shaft/shaft-zoneSpaceBaseTable-building`
+    http.getJson(url, param, success)
+}
+
+//竖井关联的业务空间
+export function shaftSpaceQuery(param, success) {
+    let url = `${baseUrl}/datacenter/shaft/shaft-zoneSpaceBaseTable?ShaftId=${param.ShaftId}`
+    http.postJson(url, param.data, success)
+}
+
+//获取未和当前竖井关联的业务空间
+export function shaftUnlinkSpaceQuery(param, success) {
+    let url = `${baseUrl}/datacenter/shaft/un-shaft-zoneSpaceBaseTable?ShaftId=${param.ShaftId}`
+    http.postJson(url, param.data, success)
+}
+
+//竖井下的业务空间,竖井一对多,不覆盖
+export function linkShaftSpace(param, success) {
+    let url = `${baseUrl}/datacenter/sh-contain-sp-base/link`
+    http.postJson(url, param, success)
+}
+
+//删除竖井下的业务空间,只针对一个对象
+export function spaceInShaftUnlink(param, success) {
+    let url = `${baseUrl}/datacenter/sh-contain-sp-base/unlink?type=${param.type}`
+    http.postJson(url, param.data, success)
+}
+
 //获取租户表格内容信息
 export function getRentTableData(param, success) {
     let url = `${baseUrl}/datacenter/tenant/query-with-count`
@@ -851,6 +926,12 @@ export function getDataDictionary(param, success) {
     http.postJson(url, data, success)
 }
 
+//all - 查询数据字典 --列表表头
+export function cacheDictionary(param, success) {
+    let url = `${baseUrl}/datacenter/class-def/query-dict`;
+    http.postJson(url, param, success)
+}
+
 //批量处理字典信息操作
 export function setInfoPoint(param, success) {
     let url = `${baseUrl}/datacenter/data-dictionary/project/dict-batch`;
@@ -919,6 +1000,19 @@ export function queryLinkSys(param, success) {
     http.postJson(url, param, success)
 }
 
+//查询系统信息 - 建筑楼层 - 系统一对多
+export function querySysLinkBuild(param, success) {
+    let url = `${baseUrl}/datacenter/general—system/query-new`;
+    if (param.buildingId) {
+        url += `?buildingId=${param.buildingId}`
+    }
+    if (param.floorId) {
+        url += `&floorId=${param.floorId}`
+    }
+    http.postJson(url, param.data, success)
+}
+
+
 //设备清单 - 设备关联系统 设备1-n
 export function equipLinkSys(param, success) {
     let url = `${baseUrl}/datacenter/sy-in-eq/link-sy`;
@@ -1058,6 +1152,18 @@ export function getEquipNotInSys(param, success) {
     http.postJson(url, param.data, success)
 }
 
+//创建系统所在建筑关系,系统一对多,覆盖
+export function sysRelateBuild(param, success) {
+    let url = `${baseUrl}/datacenter/sy-in-bd/link-bd`;
+    http.postJson(url, param, success)
+}
+
+//创建系统所在楼层关系,系统一对多,覆盖
+export function sysRelateFloor(param, success) {
+    let url = `${baseUrl}/datacenter/sy-in-fl/link-fl`;
+    http.postJson(url, param, success)
+}
+
 //查询当前系统下的设备
 export function getEquipInSys(param, success) {
     let url = `${baseUrl}/equip-component/equip-query/sys-equip`;
@@ -1328,6 +1434,24 @@ export function shthroughshUnlink(param, success) {
     let url = `${baseUrl}/datacenter/sh-through-sh/unlink`;
     http.postJson(url, param, success)
 }
+//查询没有和当前系统关联的设备
+export function unSysEq(param, success) {
+    let data = param.data
+    let url = `${baseUrl}/datacenter/general—system/un-sys-equip?sysId=${param.sysId}`;
+    http.postJson(url, data, success)
+}
+//查询没有和当前系统关联的竖井
+export function unSysShaft(param, success) {
+    let data = param.data
+    let url = `${baseUrl}/datacenter/general—system/un-sys-shaft?sysId=${param.sysId}`;
+    http.postJson(url, data, success)
+}
+//查询没有和当前系统关联的业务空间
+export function unSysZoneSpace(param, success) {
+    let data = param.data
+    let url = `${baseUrl}/datacenter/general—system/un-sys-zoneSpaceBaseTable?sysId=${param.sysId}`;
+    http.postJson(url, data, success)
+}
 //查询没有和当前竖井绑定的设备
 export function unshaftInEq(param, success) {
     let data = param.data
@@ -1351,6 +1475,11 @@ export function linkEqSh(param, success) {
     let url = `${baseUrl}/datacenter/eq-in-sh/link-eq-sh`;
     http.postJson(url, param, success)
 }
+//创建系统下的设备关系
+export function linkSysEq(param, success) {
+    let url = `${baseUrl}/datacenter/general—system/link-equip`;
+    http.postJson(url, param, success)
+}
 //竖井的贯通,竖井一对多,此方法不会覆盖以前的记录
 export function linkShaft(param, success) {
     let url = `${baseUrl}/datacenter/sh-through-sh/link-shaft`;
@@ -1361,7 +1490,31 @@ export function linkSySh(param, success) {
     let url = `${baseUrl}/datacenter/sy-in-sh/link-sy-sh`;
     http.postJson(url, param, success)
 }
-
+//创建系统所在业务空间关系
+export function linkSysSp(param, success) {
+    let url = `${baseUrl}/datacenter/sy-in-sp-base/link-list`;
+    http.postJson(url, param, success)
+}
+//系统所在竖井,系统一对多,此方法会覆盖以前的记录
+export function linkSh(param, success) {
+    let url = `${baseUrl}/datacenter/sy-in-sh/link-sh`;
+    http.postJson(url, param, success)
+}
+//系统所在竖井,系统一对多,此方法不会覆盖以前的记录
+export function linkSysSh(param, success) {
+    let url = `${baseUrl}/datacenter/sy-in-sh/link-sy-shs`;
+    http.postJson(url, param, success)
+}
+//根据对象删除系统和设备的关系,只针对一个对象
+export function eqInSysUnlink(param, success) {
+    let url = `${baseUrl}/datacenter/sy-in-eq/unlink`;
+    http.postJson(url, param, success)
+}
+//根据对象删除系统所在业务空间关系
+export function spaceInSysUnlink(param, success) {
+    let url = `${baseUrl}/datacenter/sy-in-sp-base/unlink-list?type=${param.type}`;
+    http.postJson(url, param.data, success)
+}
 //关系-----设备所在业务空间--删除关系
 export function eqInSpaceDelete(param, success) {
     let url = `${baseUrl}/datacenter/eq-in-sp-base/unlink-list?type=${param.type}`;
@@ -1437,6 +1590,16 @@ export function updateRelateInSpAndBuild(param, success) {
     let url = `${baseUrl}/datacenter/update-relationship/update-sp`;
     http.postJson(url, param, success)
 }
+//关系-----查询竖井关联的空间类型和名称
+export function shaftSpaceTypeQuery(param, success) {
+    let url = `${baseUrl}/datacenter/sh-contain-sp-base/space-type-query?shaftId=${param.shaftId}`;
+    http.postJson(url, param, success)
+}
+//关系-----竖井下的业务空间,竖井一对多,此方法会覆盖以前的记录
+export function shaftZoneLink(param, success) {
+    let url = `${baseUrl}/datacenter/sh-contain-sp-base/link-shsps-replace?BuildingId=${param.BuildingId}&FloorId=${param.FloorId}&Type=${param.Type}`;
+    http.postJson(url, param.data, success)
+}
 
 /**系统集成成果管理 */
 //系统集成统计条形图

BIN
src/assets/house.jpg


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 14 - 6
src/assets/style/iconfont/iconfont.css


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


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 7 - 1
src/assets/style/iconfont/iconfont.svg


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


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


+ 15 - 1
src/components/business_space/business/handsontable.vue

@@ -162,6 +162,9 @@ export default {
         });
         if (this.main && this.main.length && this.main[0].RoomID) {
           this.copyMain = tools.deepCopy(this.main);
+          if (this.onlyRead) {
+            this.getBatch(this.main)
+          }
         }
         this.isLoading = false
         this.getMain()
@@ -249,9 +252,15 @@ export default {
     getInfors(infos, row) {
       let val = this.hot.colToProp(row.col);
       if (val == "point") {
+        let query = {
+          RoomID: infos.RoomID,
+          zone: this.zoneCode,
+          isMyTab: 2,
+          buildFloorSelectd: this.buildFloorSelectd
+        }
         this.$router.push({
           path: "/ledger/spaceDetail",
-          query: { RoomID: infos.RoomID, zone: this.zoneCode, isMyTab: 2 }
+          query: query
         })
       } else if (val == "RoomQRCode") {
         this.qrcodeUrl = this.main[row.row].RoomQRCode
@@ -481,6 +490,9 @@ export default {
       });
       if (param.data.criterias.length) {
         BeatchQueryParam(param, res => {
+          if (!this.onlyRead) {
+            return false
+          }
           this.main = data.map(item => {
             res.Content.map(child => {
               if (item.RoomID == child.id) {
@@ -608,6 +620,8 @@ export default {
   },
   watch: {
     projectId() {
+      this.buildFloorData = []
+      buildFloor.getData(this.buildFloorData)
       this.setData()
       this.main = null
     },

+ 63 - 19
src/components/business_space/dialogs/list/firm.vue

@@ -14,6 +14,9 @@
             clearable
           ></el-input>
           <el-button @click="searchKey" size="small">查找</el-button>
+          <el-select v-model="value" style="margin-left:10px;" @change="handleChangeType" placeholder="请选择">
+            <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
+          </el-select>
         </div>
         <el-radio-group v-model="radio" style="width:100%;">
           <el-table class="data-table" border :data="tableData" style="width: 100%" height="300px">
@@ -22,11 +25,12 @@
                 <el-radio v-model="radio" :label="scope.row">{{scope.row.venderName || "--"}}</el-radio>
               </template>
             </el-table-column>
-            <el-table-column header-align='center' prop="brand" label="品牌"></el-table-column>
+            <el-table-column header-align='center' prop="brandName" label="品牌"></el-table-column>
             <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>
           </el-table>
@@ -51,9 +55,10 @@
   </el-dialog>
 </template>
 <script>
-    import myPagination from "@/components/common/myPagination";
-    import paramDetails from "@/components/business_space/dialogs/list/paramDetails"
-    import {getSpecList} from "@/api/scan/request"
+
+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 {
   components: {
@@ -77,8 +82,18 @@
     return {
       search: "", //搜索文案
       radio: "",
-      tableData: [
-      ],
+      value: "specification",//当前选择的查看类型
+      options: [{
+          value: 'specification',
+          label: '选型号'
+        }, {
+          value: 'brand',
+          label: '选生产厂家-品牌'
+        }, {
+          value: 'manufacturer',
+          label: '选生产厂家'
+      }],
+      tableData: [],
       data: {},
       isLoad: {
         paramShow: false
@@ -122,19 +137,48 @@
       }
       this.getData()
     },
+    handleChangeType(item) {
+      this.page.total = 0
+      this.tableData = []
+      this.getData()
+    },
     getData() {
-      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
-        console.log(this.tableData)
-      })
+      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: {
@@ -142,7 +186,7 @@
       deep: true,
       handler: function () {
         if (this.dialog.firm) {
-          console.log(this.mess)
+          this.value = 'specification'
           this.changePage()
         }
       }

+ 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

+ 42 - 9
src/components/business_space/newGraphy/canvasFun.vue

@@ -1,30 +1,41 @@
 <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 v-if="config.isEdit&&config.groupSelect" :class="{'active':active=='groupSelect'}">
+      <i class="iconfont icon-shuxingxuanze" @click="groupSelect"></i>
+    </div>
     <div>
       <i class="iconfont icon-maximize" @click="fitToWindow"></i>
     </div>
-    <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'}">
+      <el-dropdown size="mini" placement="top-start" @command="handleDivideCommand" :hide-on-click="false">
+        <i class="iconfont icon-edit1" @click="divide"></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">
+    <div v-if="config.isEdit&&config.divide">
       <i class="iconfont icon-Erase" @click="clearDivide"></i>
     </div>
-    <div v-if="isEdit">
+    <div v-if="config.isEdit">
       <i class="iconfont icon-Cancel" @click="undo"></i>
     </div>
-    <div v-if="isEdit">
+    <div v-if="config.isEdit">
       <i class="iconfont icon-Anti-cancel" @click="redo"></i>
     </div>
     <div>
@@ -46,11 +57,17 @@ export default {
       active: '',
       min: 1,
       everyScale: 1, // 每份的放大倍数
+      isSwitch: false, // 是否开启吸附
     }
   },
   props: {
-    isEdit: {
-      default: false
+    config: {
+      type: Object,
+      default: {
+        isEdit: false,
+        divide: true,
+        groupSelect: false
+      }
     }
   },
   computed: {
@@ -62,6 +79,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');
@@ -70,6 +92,10 @@ export default {
     handleCommand(command) {
       this.$emit(command)
     },
+    // 是否开启吸附
+    handleDivideCommand(commond) {
+      this.$emit('changeAbsorb', this.isSwitch);
+    },
     // 切割编辑
     divide() {
       this.active = 'divide';
@@ -124,14 +150,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;
   }

+ 364 - 158
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,18 +121,21 @@ 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,
@@ -124,6 +144,9 @@ export default {
       curZoneItem: {}, //当前选中的业务空间item
       allUnRelatISP: [], //
       zoneList: [], // 业务空间-canvas图中
+      groupCreateDialogVis: false, //批量创建业务空间弹窗
+      groupCreateType: 1, //批量创建方式
+      zoneDisable: true, // 重新划分是否禁用
     }
   },
   computed: {
@@ -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() {
@@ -200,7 +231,8 @@ export default {
       this.scene.clearZoneSelection();
       // 选中当前
       zone.selected = true;
-      this.type = 2;
+      this.curZoneItem = zone;
+      this.zoneDisable = false;
       this.view.fitSelectedToView();
     },
     // 父组件调用
@@ -216,18 +248,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 +283,7 @@ export default {
           })
           this.scene.addSceneMark(newArr)
         }
+        this.scene.isSpaceSelectable = false;
         // 绘制业务空间
         that.getBusinessSpace();
         that.view.fitSceneToView();
@@ -273,12 +294,6 @@ export default {
         }
       })
     },
-    // 清空绘制业务空间
-    clearZoneCanvas() {
-      this.zoneList.map(t => {
-        this.scene.removeItem(t);
-      })
-    },
     // 获取当前分区下的业务空间
     getBusinessSpace() {
       this.canvasLoading = true
@@ -293,31 +308,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;
@@ -326,18 +341,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;
         }
@@ -346,6 +369,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 +390,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 +444,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 +454,7 @@ export default {
           });
         });
       } else {
-        this.$message('没有未关联的空间')
+        this.$message('没有未关联的空间')
       }
     },
     // 创建新的业务空间
@@ -444,109 +470,270 @@ export default {
         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 (t.Height && (BSP.Height == 0 || t.Height < BSP.Height)) {
-          BSP.Height = t.Height;
+        if (this.BIMIDToSID[t.data.SourceId]) {
+          IspaceIdList.push(this.BIMIDToSID[t.data.SourceId]);
         }
-      })
-      let pa = {
-        zone: BSP.ObjectType,
-        data: {
-          Content: [BSP],
-          Projection: ['Outline']
+        if (t.Height && (BSP.Height == 0 || t.Height < BSP.Height)) {
+          BSP.Height = t.Height > 100 ? (t.Height / 1000).toFixed(2) : t.Height;
         }
-      }
-      updateZone(pa, res => {
-        this.$message.success('更新成功');
-        this.init(2);
       })
+      this.updateBSPOutline(BSP, IspaceIdList)
     },
     // 编辑空间详情
     editeSpaceDetail() {
       let item = this.curZoneItem.data;
+      let query = {
+        RoomID: item.RoomID,
+        zone: this.tab.code,
+        isMyTab: 1,
+        buildFloorSelectd: this.buildFloor
+      }
       this.$router.push({
         path: "/ledger/spaceDetail",
-        query: { RoomID: item.RoomID, zone: this.tab.code, isMyTab: 1 }
+        query: query
       })
     },
     // 重新划分业务空间
     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 = arr.map(t => {
+        return {
+          IspaceId: this.BIMIDToSID[t.data.SourceId],
+          RoomLocalName: t.data.Name,
+          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() {
@@ -554,22 +741,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 = true;
     },
     // 适配底图到窗口
     fit() {
@@ -583,13 +768,17 @@ 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() {
@@ -627,7 +816,23 @@ export default {
           this.$refs.canvasFun.sliderVal = n * 10 / this.view.minScale;
         }
       }
-    }
+    },
+    "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>
@@ -653,7 +858,8 @@ export default {
       width: 320px;
       margin-right: 10px;
     }
-    .button-group button {
+    .button-group button,
+    .button-group .el-dropdown {
       display: block;
       float: left;
     }

+ 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>

+ 1 - 1
src/components/business_space/newTables/eqToSpaceTable.vue

@@ -150,7 +150,7 @@ export default {
     },
     // 添加设备
     add() {
-      this.$refs.addEqDialog.floor = [this.params.BuildingId, this.params.FloorId];
+      this.$refs.addEqDialog.floor = this.params.buildFloorSelectd;
       this.$refs.addEqDialog.showDialog()
     }
   },

+ 1 - 0
src/components/common/handsontable.vue

@@ -166,6 +166,7 @@
                     sortIndicator: true, //添加排序
                     renderAllRows: true,
                     autoColumnSize: true,
+                    // observeChanges: false, //启用observeChanges插件
                     language: "zh-CN",
                     manualColumnResize: true,
                     manualColumnMove: true,

+ 49 - 172
src/components/config_point/dictionaryCascader.vue

@@ -1,207 +1,67 @@
 <template>
   <div>
     <el-form ref="form" :rules='rules' :model="form">
-      <el-form-item prop="dict">
-        <el-cascader style='width: 100%;' :options='options' v-model='form.dict' @active-item-change='handleChange' :props='props' filterable
-          @change="changeSelect" ref="dictCas"></el-cascader>
+      <el-form-item prop="dict" class="cascader-container">
+        <el-cascader :options='options' v-model='form.dict' :props='props' filterable @change="changeSelect" ref="dictCas">
+        </el-cascader>
+        <el-tooltip class="item" effect="dark" :content="`于${cacheTime}缓存,点击重新缓存`" placement="top">
+          <el-button icon="el-icon-refresh" class="update-button" @click="getDictionary"></el-button>
+        </el-tooltip>
       </el-form-item>
     </el-form>
   </div>
 </template>
 <script>
-import {
-  getDataDictionary,//查询信息点
-  queryPhysicsAllType,//查询所有部件类型
-  queryDictionaryHead,//查询所有空间类型
-
-} from "@/api/scan/request"
-import { mapGetters, mapActions } from "vuex";
+import { mapGetters, mapMutations, mapActions } from "vuex";
 import tools from "@/utils/scan/tools";
 export default {
   data() {
     return {
-      options: [
-        {
-          Code: 'Pj',
-          Name: '项目',
-          children: []
-        }, {
-          Code: 'Bd',
-          Name: '建筑',
-          children: []
-        }, {
-          Code: 'Fl',
-          Name: '楼层',
-          children: []
-        }, {
-          Code: 'Eq',
-          Name: '设备',
-          children: []
-        }, {
-          Code: 'Ec',
-          Name: '部件',
-          children: []
-        }, {
-          Code: 'Sy',
-          Name: '系统',
-          children: []
-        }, {
-          Code: 'Sp',
-          Name: '空间',
-          children: []
-        }, {
-          Code: 'VOTn',
-          Name: '租户',
-          children: []
-        },
-      ],
+      options: [],
       form: {
         dict: [],
       },
       props: {
-        value: 'Code',
-        label: 'Name',
-        children: 'children'
+        value: 'InfoPointCode',
+        label: 'InfoPointName',
+        children: 'Content'
       },
       rules: {
         dict: [{ required: true, message: '请选择对应数据字典', trigger: 'blur' }]
       },
-      typeRelation: {
-        Pj: 'Project',
-        Bd: 'Building',
-        Fl: 'Floor',
-        VOTn: 'Tenant',
-      },
-      timer: null
     }
   },
+  computed: {
+    ...mapGetters("project", ["dictionary", "cacheTime"]),
+  },
   created() {
-    this.getAllData()
+    if (!this.dictionary.length) {
+      this.getDictionary().then(res => {
+        this.getDictSuc(res.Content)
+      })
+    } else {
+      this.getDictSuc(this.dictionary);
+    }
   },
   methods: {
-    //选择
-    handleChange(val) {
-      let type = val[0];
-      let singleStr = "Pj-Bd-Fl-VOTn";
-      console.log(val)
-      if (type == "Eq" && val.length == 2) {
-        this.getDataPoint(val[1])
-      } else if (type == "Ec" && val.length == 2) {
-        this.getDataPoint(val[1])
-      } else if (type == "Sy" && val.length == 3) {
-        this.getDataPoint(val[2])
-      } else if (type == "Sp" && val.length == 2) {
-        this.getDataPoint(val[1])
-      } else if (singleStr.indexOf(type) > -1) {
-        this.hasChildren(type) && this.getDataPoint(type)
-      }
-    },
+    ...mapActions('project', ['getDictionary']),
     //获取物理世界所有设备类型
-    getAllData() {
-      queryPhysicsAllType('Equipment', res => {
-        this.options[3].children = this.formatOptions(res.Content)
-      })
-      queryPhysicsAllType('Component', res => {
-        this.options[4].children = this.formatOptions(res.Content)
-      })
-      queryPhysicsAllType('Major-System', res => {
-        let data = JSON.parse(JSON.stringify(res.Content).replace(/ListClassDef/g, 'children'));
-        this.options[5].children = this.formatOptions(data)
-      })
-      let param1 = {
-        Distinct: true,
-        Filters: "ParentId='Space'"
-      }
-      queryDictionaryHead(param1, res => {
-        this.options[6].children = this.formatOptions(res.Content)
-      })
-    },
-    //格式化options数据
-    formatOptions(arr) {
-      return arr.map(item => {
-        return {
-          Code: item.Code,
-          Name: item.Name,
-          children: item.children && item.children.length ? this.formatOptions(item.children) : []
-        }
-      })
-    },
-    //请求信息点
-    getDataPoint(type) {
-      let param = {
-        data: {
-          Filters: "InputMode='M' or InputMode='L'",
-          PageNumber: 1,
-          PageSize: 500,
-          Orders: 'InfoPointName asc'
-        },
-        type: this.typeRelation[type] || type
-      }
-      getDataDictionary(param, res => {
-        let tempArr = res.Content.map(item => {
-          return {
-            Code: item.InfoPointCode,
-            Name: item.InfoPointName
-          }
-        })
-        this.pointDataSource = {}
-        res.Content.map(item => {
-          let code = item.InfoPointCode
-          this.pointDataSource[code] = item
-        })
-        this.timer = setTimeout(() => {
-          if (this.interval()) {
-            this.pushPoints(this.options, tempArr, type);
-            this.changeSelect(this.form.dict);
-            clearTimeout(this.timer);
-            this.timer = null;
-            return
-          }
-          this.timer()
-        }, 100);
-      })
-    },
-    interval() {
-      for (let i = 0; i < this.options.length; i++) {
-        if (this.options[i].children.length > 0) {
-          return true;
-        }
-      }
-      return false;
-    },
-    //根据返回数据拼接options
-    pushPoints(options, arr, Code) {
-      options.map(option => {
-        if (option.Code == Code) {
-          option.children = arr;
-        } else {
-          if (option.children) {
-            this.pushPoints(option.children, arr, Code)
-          }
-        }
-      })
+    getDictSuc(list) {
+      this.options = list;
+      this.changeSelect(this.form.dict);
     },
     changeSelect(val) {
-      if (this.$refs.dictCas.getCheckedNodes()[0]) {
-        let labels = this.$refs.dictCas.getCheckedNodes()[0].pathLabels
-        this.$emit('change', { val: val, labels: labels })
-      }
-    },
-    //减少请求次数
-    hasChildren(Code) {
-      let flag = true;
-      this.options.map(option => {
-        if (option.Code == Code && option.children.length) {
-          flag = false;
+      setTimeout(() => {
+        if (this.$refs.dictCas.getCheckedNodes()[0]) {
+          let labels = this.$refs.dictCas.getCheckedNodes()[0].pathLabels;
+          let data = this.$refs.dictCas.getCheckedNodes()[0].data;
+          this.$emit('change', { val: val, labels: labels, data: data })
         }
-      })
-      return flag;
+      }, 500)
     },
     //设置值
     setCascaderVal(value) {
       this.form.dict = tools.deepCopy(value)
-      value.splice(value.length - 1, 1)
-      this.handleChange(value)
     },
     //校验是否选择
     validate(cb) {
@@ -217,4 +77,21 @@ export default {
 }
 </script>
 <style lang="less" scoped>
-</style>
+.cascader-container {
+  /deep/ .el-cascader {
+    width: 89%;
+    display: block;
+    float: left;
+    .el-input .el-input__inner {
+      border-radius: 4px 0 0 4px;
+      vertical-align: bottom;
+    }
+  }
+  .update-button {
+    display: block;
+    float: left;
+    border-left: 0;
+    border-radius: 0 4px 4px 0;
+  }
+}
+</style>

+ 3 - 3
src/components/config_point/step3_edit/index.vue

@@ -583,11 +583,11 @@ export default {
       return str
     },
     //对应数据字典变化
-    changeDictionaryCas({ val, labels }) {
+    changeDictionaryCas({ val, labels, data }) {
       this.dictionaryData = val;
       this.dictionaryNames = labels
-      this.infoDict = this.$refs.dictionaryCas.pointDataSource
-      this.unitObj = this.infoDict[val[val.length - 1]]
+      // this.infoDict = this.$refs.dictionaryCas.pointDataSource
+      this.unitObj = data
       this.InfomationPoint = this.unitObj.InfoPointName || ''
       this.ValueDescription = this.delDataSource(this.unitObj.DataSource)
     }

+ 3 - 3
src/components/config_point/step3_point/3_temps.vue

@@ -599,11 +599,11 @@ export default {
       return str
     },
     //对应数据字典变化
-    changeDictionaryCas({ val, labels }) {
+    changeDictionaryCas({ val, labels, data }) {
       this.dictionaryData = val;
       this.dictionaryNames = labels
-      this.infoDict = this.$refs.dictionaryCas.pointDataSource
-      this.unitObj = this.infoDict[val[val.length - 1]]
+      // this.infoDict = this.$refs.dictionaryCas.pointDataSource
+      this.unitObj = data
       this.InfomationPoint = this.unitObj.InfoPointName || ''
     },
     //分页发生更改

+ 1 - 0
src/components/config_point/step3_point/steps3_main.vue

@@ -145,6 +145,7 @@
                                     // KeyEquipmentParameter: '温度',
                                     // KeyEquipmentType: '冷机'
                                 },
+                                Orders: 'EquipmentMark asc',
                                 PageNumber: this.pages.currentPage,
                                 PageSize: this.pages.size
                             },

+ 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>

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

@@ -0,0 +1,219 @@
+<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">
+              <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"]),
+    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: '',//当前正在显示的图
+    };
+  },
+  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.maxScale = this.view.scale * 10;
+        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) {
+          this.$refs.canvasFun.sliderVal = n * 10 / this.view.minScale;
+        }
+      }
+    },
+    "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>

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

@@ -0,0 +1,220 @@
+<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"])
+  },
+  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: [{
+          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>

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

@@ -0,0 +1,248 @@
+<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"])
+  },
+  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: [{
+          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>

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

@@ -0,0 +1,238 @@
+<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"])
+  },
+  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: [{
+          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>

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

@@ -0,0 +1,135 @@
+<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>
+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) {
+              f[item.InfoPointCode] = item.inputValue.pop();
+            }
+            else {
+              f[item.InfoPointCode] = 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>

+ 11 - 7
src/components/dialogs/list/firm.vue

@@ -2,7 +2,7 @@
     firm 厂商
 -->
 <template>
-  <el-dialog title="选择型号" :visible.sync="dialog.firm" width="900px">
+  <el-dialog title="选择生产厂家/品牌/型号" :visible.sync="dialog.firm" width="900px">
     <div>
       <div id="firm">
         <div class="title-search query-form" style="padding: 10px;margin-bottom: 10px;">
@@ -14,6 +14,9 @@
             clearable
           ></el-input>
           <el-button @click="searchKey" size="small">查找</el-button>
+          <el-select v-model="value" style="margin-left:10px;" @change="handleChangeType" placeholder="请选择">
+            <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
+          </el-select>
         </div>
         <el-radio-group v-model="radio" style="width:100%;">
           <el-table class='data-table' :data="tableData" style="width: 100%" height="300px" border>
@@ -22,11 +25,11 @@
                 <el-radio v-model="radio" :label="scope.row">{{scope.row.venderName || "--"}}</el-radio>
               </template>
             </el-table-column>
-            <el-table-column prop="brand" label="品牌" header-align='center'></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'>
               <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>
           </el-table>
@@ -51,9 +54,10 @@
   </el-dialog>
 </template>
 <script>
-    import myPagination from "@/components/ledger/lib/myPagination";
-    import paramDetails from "@/components/dialogs/list/paramDetails"
-    import {getSpecList} from "@/api/scan/request"
+
+import myPagination from "@/components/ledger/lib/myPagination";
+import paramDetails from "@/components/dialogs/list/paramDetails"
+import { getSpecList, getBrandList, getManufacturerList } from "@/api/scan/request"
 
     export default {
         components: {
@@ -147,7 +151,7 @@
       deep: true,
       handler: function () {
         if (this.dialog.firm) {
-          console.log(this.mess)
+          this.value = 'specification'
           this.changePage()
         }
       }

+ 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>

+ 13 - 4
src/components/ledger/handsontables/assets.vue

@@ -525,6 +525,7 @@ export default {
         columnSorting: true, //添加排序
         sortIndicator: true, //添加排序
         renderAllRows: true,
+        // observeChanges: false, //启用observeChanges插件
         // colWidths: 200,
         autoColumnSize: true,
         language: "zh-CN",
@@ -584,7 +585,7 @@ export default {
     },
     // 更新
     handleUpdataTable(changeData, source) {
-      if (!this.onlyRead) {
+      if (!this.onlyRead && source != 'ObserveChanges.change') {
         if (changeData) {
           let trimmedArr = this.trimmedRows();
           let param = handsonUtils.getParam(changeData, source, this.hot, trimmedArr);
@@ -903,13 +904,19 @@ export default {
     },
     //选择型号修改
     firmChange(data) {
-      tools.setDataForKey(this.tableData[this.row], "DPManufacturerID", data.venderId)
-      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Brand", data.brand)
+      tools.setDataForKey(this.tableData[this.row], "DPManufacturerID", data.venderId)//生产商ID
+      tools.setDataForKey(this.tableData[this.row], "DPBrandID", data.brandId)//品牌ID
+      tools.setDataForKey(this.tableData[this.row], "DPSpecificationID", data.specificationId)//型号ID
+      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Manufacturer", data.venderName)
+      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Brand", data.brandName)
       tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Specification", data.name)
       this.handleUpdataTable(
         [
           [this.row, "DPManufacturerID", null, data.venderId],
-          [this.row, "LedgerParam.EquipManufactor.Brand", null, data.brand],
+          [this.row, "DPBrandID", null, data.brandId],
+          [this.row, "DPSpecificationID", null, data.specificationId],
+          [this.row, "LedgerParam.EquipManufactor.Manufacturer", null, data.venderName],
+          [this.row, "LedgerParam.EquipManufactor.Brand", null, data.brandName],
           [this.row, "LedgerParam.EquipManufactor.Specification", null, data.name]
         ],
         "edit"
@@ -991,6 +998,8 @@ export default {
   },
   watch: {
     projectId() {
+      this.buildFloorData = []
+      buildFloor.getData(this.buildFloorData)
       this.main = []
       this.mess.deviceId = null
       this.page.total = 0

+ 2 - 0
src/components/ledger/handsontables/device.vue

@@ -1265,6 +1265,8 @@ export default {
     },
     watch: {
     projectId() {
+      this.buildFloorData = []
+      buildFloor.getData(this.buildFloorData)
       this.tableData = []
       this.mess.deviceId = null
       this.page.total = 0

+ 62 - 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,
@@ -379,6 +393,7 @@ export default {
         columnSorting: true, //添加排序
         sortIndicator: true, //添加排序
         renderAllRows: true,
+        // observeChanges: false, //启用observeChanges插件
         // colWidths: 200,
         autoColumnSize: true,
         language: "zh-CN",
@@ -437,7 +452,7 @@ export default {
       }
     },
     handleUpdataTable(changeData, source) {
-      if (!this.onlyRead) {
+      if (!this.onlyRead && source != 'ObserveChanges.change') {
         if (changeData) {
           let trimmedArr = this.trimmedRows();
           let param = handsonUtils.getParam(changeData, source, this.hot, trimmedArr);
@@ -478,7 +493,7 @@ export default {
     async removeSys(param) {
       await deleteGeneralSys(param, res => {
         this.$message.success("删除成功")
-        this.$emit('close','')
+        this.$emit('close', '')
         this.getTableData()
       })
     },
@@ -488,7 +503,7 @@ export default {
         Content: [],
         Projection: []
       }, keyList = [];
-       //生成要修改字段列表
+      //生成要修改字段列表
       change.map(item => {
         let key = item[1].split(".")[0]
         if (item[1] && keyList.indexOf(key) == -1) {
@@ -520,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':
@@ -537,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;
       }
@@ -553,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/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.maxScale = that.view.scale * 10;
+        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) {
+          this.$refs.canvasFun.sliderVal = n * 10 / this.view.minScale;
+        }
+      }
+    }
+  }
+}
+</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>

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

@@ -0,0 +1,107 @@
+<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
+  },
+  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() {
+      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>

+ 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>

+ 281 - 0
src/components/point/dynamicdata/buildRules.vue

@@ -0,0 +1,281 @@
+
+<template>
+  <div id="equipRules">
+    <!-- 查询条件 -->
+    <div class="query-area">
+      <el-row>
+        <el-col :span="22">
+          <el-form ref="form" :model="form" :inline="true">
+            <el-row>
+              <div class="query-item special" style="margin-bottom:20px;">
+                <el-input :placeholder="`请输入${typeName}标识关键字`" v-model="form.EquipmentMark" @keyup.enter.native="queryTableData">
+                  <i slot="suffix" class="el-input__icon el-icon-search" @click="queryTableData"></i>
+                </el-input>
+              </div>
+              <div class="query-item">
+                <label style="padding-right:9px">数据源</label>
+                <dataSource :Related="null" @change="changeDataSource" :typeName="typeName"></dataSource>
+              </div>
+              <!-- <div class="query-item">
+                <dictionary-device @change="changeDictionary" :Related="null" :typeName="typeName"></dictionary-device>
+              </div> -->
+              <div class="query-item">
+                <label style="padding-right:9px">位置标签</label>
+                <locationFlag :Related="null" @change="changeLocationFlag" :typeName="typeName"></locationFlag>
+              </div>
+            </el-row>
+          </el-form>
+        </el-col>
+        <el-col :span="2">
+          <el-tooltip class="item" effect="dark" :content="`填充${typeName}标识与实例对应规则`" placement="left">
+            <el-button size="small" type="primary" @click="toAddRelation" icon="el-icon-edit-outline" style="float:right;" :disabled="isPending">
+            </el-button>
+          </el-tooltip>
+          <el-tooltip class="item" effect="dark" :content="`根据${typeName}标识自动填充实例`" placement="left">
+            <el-button size="small" type="primary" @click="autoGroupRela" :icon="autoLoading?'iconfont icon-jiazai':'iconfont icon-zidong'"
+              style="float:right;padding:7px 14px;margin-right:10px;" :disabled="autoLoading"></el-button>
+          </el-tooltip>
+        </el-col>
+      </el-row>
+    </div>
+    <el-row>
+      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">点位表中出现的所有{{typeName}}</el-col>
+      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">对应物理世界中的{{typeName}}实例</el-col>
+    </el-row>
+    <!-- 列表区域 -->
+    <div class="table-area">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column prop="EquipmentMark" :label="`${typeName}标识`" show-overflow-tooltip min-width="200"></el-table-column>
+        <el-table-column prop="LocationFlag" label="位置标签" min-width="200">
+          <template slot-scope="scope">
+            <el-tooltip :content="scope.row.LocationFlag.toString()" placement="top">
+              <div class="tool-tip">{{scope.row.LocationFlag.toString()}}</div>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column prop="Datasource" label="数据源" show-overflow-tooltip min-width="100"></el-table-column>
+        <!-- <el-table-column prop="SubTypeName" :label="`${typeName}类型`" show-overflow-tooltip min-width="100"></el-table-column> -->
+        <el-table-column prop="ObjectLocalName" :label="`${typeName}实例`" show-overflow-tooltip min-width="400" class-name="td-bl"></el-table-column>
+        <!-- <el-table-column label="所在建筑楼层" min-width="300">
+          <template slot-scope="scope">
+            <el-tooltip
+              :content="scope.row.BuildLocalName?scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:''"
+              placement="top">
+              <div class="tool-tip">
+                {{scope.row.BuildLocalName?scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:''}}
+              </div>
+            </el-tooltip>
+          </template>
+        </el-table-column> -->
+        <!-- <el-table-column prop="RoomLocalName" label="所在业务空间" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="CascadeEquipLocalName" label="所属设备实例" show-overflow-tooltip min-width="100"></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
+                :disabled="isPending||scope.row.Related=='False'" icon="el-icon-delete"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <!-- 分页 -->
+    <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>
+    <!-- 清除对应关系弹窗 -->
+    <del-relation-dialog ref="del" @refresh="refresh" :typeName="'build'"></del-relation-dialog>
+  </div>
+</template>
+<script>
+import tools from "@/utils/tools";
+import { mapGetters, mapActions } from "vuex";
+import applyRulesDialog from "@/components/point/dynamicdata/applyRulesDialog";
+import delRelationDialog from "@/components/point/dynamicdata/delRelationDialog";
+import dictionaryDevice from "@/components/point/dynamicdata/dictionaryDevice";
+import dataSource from "@/components/point/dynamicdata/dataSource";
+import locationFlag from "@/components/point/dynamicdata/locationFlag";
+import equipRules from "@/components/point/dynamicdata/equipRules";
+import {
+  dynamicClashConfirm,
+  dynamicExecute,
+  dynamicQuery,
+  dynamicQueryPoint,
+  dynamicPointTypeList
+} from "@/api/scan/request";
+export default {
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      },
+      sourceList: [], //数据源
+      DynEquipList: [], //数据字典部件类型
+      LocFlagList: [], //位置标签
+      tableData: [], //列表数据
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      form: {
+        EquipmentMark: "", //部件标识关键字
+        SubTypeName: [], //数据字典部件类型
+        LocationFlag: [], //位置标签
+        Datasource: [] //数据源
+      }, //查询条件
+      loading: false, //列表loading
+      autoLoading: false, //自动对应实例
+    };
+  },
+  components: {
+    applyRulesDialog,
+    delRelationDialog,
+    dictionaryDevice,
+    dataSource,
+    locationFlag
+  },
+  props: {
+    typeName: {},
+    isPending: {
+      default: false
+    }
+  },
+  created() {
+    this.init();
+  },
+  mounted() { },
+  methods: {
+    //获取查询条件-提示信息
+    init() {
+      this.getTableData()
+    },
+    //清除对应关系
+    handleDelete(index, row) {
+      this.$refs.del.showDialog(row);
+    },
+    //改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    //改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    //跳转至填充对应规则
+    toAddRelation() {
+      this.$router.push({ path: "buildRela", query: { typeName: this.typeName } });
+    },
+    //获取表格数据
+    getTableData() {
+      let param = {
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize,
+        TypeNameList: [this.typeName]
+      };
+      //处理查询条件
+      if (this.form.EquipmentMark && this.form.EquipmentMark.length) {
+        param.EquipmentMark = this.form.EquipmentMark;
+      }
+      if (this.form.SubTypeName.length) {
+        param.SubTypeNameList = this.form.SubTypeName;
+      }
+      if (this.form.LocationFlag.length) {
+        param.LocationFlagList = this.form.LocationFlag;
+      }
+      if (this.form.Datasource.length) {
+        param.DatasourceList = this.form.Datasource;
+      }
+      this.loading = true;
+      // 查询对应关系(P1)
+      dynamicQuery(param, res => {
+        this.loading = false;
+        this.tableData = res.Content;
+        this.page.total = res.PageSize < 50 ? res.PageSize : res.Total;
+      });
+    },
+    //刷新列表
+    refresh() {
+      this.page.pageNumber = 1;
+      this.$emit('refresh', this.typeName);
+      this.getTableData();
+    },
+    //数据字典部件类型修改
+    changeDictionary(val) {
+      this.page.pageNumber = 1;
+      this.form.SubTypeName = val;
+      this.getTableData();
+    },
+    //数据源修改
+    changeDataSource(val) {
+      this.page.pageNumber = 1;
+      this.form.Datasource = val;
+      this.getTableData();
+    },
+    //修改位置标签
+    changeLocationFlag(val) {
+      this.page.pageNumber = 1;
+      this.form.LocationFlag = val;
+      this.getTableData();
+    },
+    //查询列表
+    queryTableData() {
+      this.page.pageNumber = 1;
+      this.getTableData();
+    },
+    //自动对应实例
+    autoGroupRela() {
+      this.$emit('autoGroupRela', 'build');
+    }
+  },
+  watch: {
+    projectId() {
+      this.init();
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+#equipRules {
+  height: calc(100% - 54px);
+  /deep/ .text-right {
+    text-align: right;
+  }
+  .query-item {
+    float: left;
+    & + .query-item {
+      margin-left: 10px;
+    }
+  }
+  /deep/ .special .el-input__inner {
+    width: 220px;
+  }
+  /deep/ .table-area {
+    width: 100%;
+    height: calc(100% - 71px);
+    margin-bottom: 10px;
+    td div {
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      overflow: hidden;
+    }
+    .td-bl {
+      border-left: 1px solid #ebeef5;
+    }
+    .tool-tip {
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+    }
+  }
+}
+</style>
+

+ 19 - 1
src/components/point/dynamicdata/delRelationDialog.vue

@@ -110,7 +110,25 @@ export default {
           { label: '对象实例名称', prop: "ObjectLocalName" },
           { label: '对象本地编码', prop: "ObjectLocalCode" },
           { label: '所在建筑楼层', prop: "BuildLocalName" },
-        ]
+        ],
+        build: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象本地编码', prop: "ObjectLocalCode" }
+        ],
+        floor: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象顺序号', prop: "ObjectLocalCode" },
+          { label: '所在建筑', prop: "BuildLocalName" },
+        ],
+        tenant: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象本地编码', prop: "ObjectLocalCode" },
+          { label: '所在业务空间', prop: "BuildLocalName" },
+        ],
+        project: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象本地编码', prop: "ObjectLocalCode" },
+        ],
       },
       rightTableHeader: []
     };

+ 1 - 1
src/components/point/dynamicdata/equipRules.vue

@@ -233,7 +233,7 @@ export default {
     },
     //自动对应实例
     autoGroupRela() {
-      this.$emit('autoGroupRela','equip');
+      this.$emit('autoGroupRela', 'equip');
     }
   },
   watch: {

+ 289 - 0
src/components/point/dynamicdata/floorRules.vue

@@ -0,0 +1,289 @@
+
+<template>
+  <div id="equipRules">
+    <!-- 查询条件 -->
+    <div class="query-area">
+      <el-row>
+        <el-col :span="22">
+          <el-form ref="form" :model="form" :inline="true">
+            <el-row>
+              <div class="query-item special" style="margin-bottom:20px;">
+                <el-input :placeholder="`请输入${typeName}标识关键字`" v-model="form.EquipmentMark" @keyup.enter.native="queryTableData">
+                  <i slot="suffix" class="el-input__icon el-icon-search" @click="queryTableData"></i>
+                </el-input>
+              </div>
+              <div class="query-item">
+                <label style="padding-right:9px">数据源</label>
+                <dataSource :Related="null" @change="changeDataSource" :typeName="typeName"></dataSource>
+              </div>
+              <!-- <div class="query-item">
+                <dictionary-device @change="changeDictionary" :Related="null" :typeName="typeName"></dictionary-device>
+              </div> -->
+              <div class="query-item">
+                <label style="padding-right:9px">位置标签</label>
+                <locationFlag :Related="null" @change="changeLocationFlag" :typeName="typeName"></locationFlag>
+              </div>
+            </el-row>
+          </el-form>
+        </el-col>
+        <el-col :span="2">
+          <el-tooltip class="item" effect="dark" :content="`填充${typeName}标识与实例对应规则`" placement="left">
+            <el-button size="small" type="primary" @click="toAddRelation" icon="el-icon-edit-outline" style="float:right;" :disabled="isPending">
+            </el-button>
+          </el-tooltip>
+          <el-tooltip class="item" effect="dark" :content="`根据${typeName}标识自动填充实例`" placement="left">
+            <el-button size="small" type="primary" @click="autoGroupRela" :icon="autoLoading?'iconfont icon-jiazai':'iconfont icon-zidong'"
+              style="float:right;padding:7px 14px;margin-right:10px;" :disabled="autoLoading"></el-button>
+          </el-tooltip>
+        </el-col>
+      </el-row>
+    </div>
+    <el-row>
+      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">点位表中出现的所有{{typeName}}</el-col>
+      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">对应物理世界中的{{typeName}}实例</el-col>
+    </el-row>
+    <!-- 列表区域 -->
+    <div class="table-area">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column prop="EquipmentMark" :label="`${typeName}标识`" show-overflow-tooltip min-width="200"></el-table-column>
+        <el-table-column prop="LocationFlag" label="位置标签" min-width="200">
+          <template slot-scope="scope">
+            <el-tooltip :content="scope.row.LocationFlag.toString()" placement="top">
+              <div class="tool-tip">{{scope.row.LocationFlag.toString()}}</div>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column prop="Datasource" label="数据源" show-overflow-tooltip min-width="100"></el-table-column>
+        <!-- <el-table-column prop="SubTypeName" :label="`${typeName}类型`" show-overflow-tooltip min-width="100"></el-table-column> -->
+        <el-table-column prop="ObjectLocalName" :label="`${typeName}实例`" show-overflow-tooltip min-width="100" class-name="td-bl"></el-table-column>
+        <el-table-column :label="`${typeName}顺序号`" show-overflow-tooltip min-width="100">
+          <template slot-scope="scope">
+            <el-tooltip :content="(scope.row.ObjectSequenceID&&scope.row.ObjectSequenceID!='null')?scope.row.ObjectSequenceID:''" placement="top">
+              <div class="tool-tip">
+                {{(scope.row.ObjectSequenceID&&scope.row.ObjectSequenceID!='null')?scope.row.ObjectSequenceID:''}}</div>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column label="所属建筑" min-width="200">
+          <template slot-scope="scope">
+            <el-tooltip
+              :content="scope.row.BuildLocalName?scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:''"
+              placement="top">
+              <div class="tool-tip">
+                {{scope.row.BuildLocalName?scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:''}}
+              </div>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <!-- <el-table-column prop="RoomLocalName" label="所在业务空间" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="CascadeEquipLocalName" label="所属设备实例" show-overflow-tooltip min-width="100"></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
+                :disabled="isPending||scope.row.Related=='False'" icon="el-icon-delete"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <!-- 分页 -->
+    <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>
+    <!-- 清除对应关系弹窗 -->
+    <del-relation-dialog ref="del" @refresh="refresh" :typeName="'floor'"></del-relation-dialog>
+  </div>
+</template>
+<script>
+import tools from "@/utils/tools";
+import { mapGetters, mapActions } from "vuex";
+import applyRulesDialog from "@/components/point/dynamicdata/applyRulesDialog";
+import delRelationDialog from "@/components/point/dynamicdata/delRelationDialog";
+import dictionaryDevice from "@/components/point/dynamicdata/dictionaryDevice";
+import dataSource from "@/components/point/dynamicdata/dataSource";
+import locationFlag from "@/components/point/dynamicdata/locationFlag";
+import equipRules from "@/components/point/dynamicdata/equipRules";
+import {
+  dynamicClashConfirm,
+  dynamicExecute,
+  dynamicQuery,
+  dynamicQueryPoint,
+  dynamicPointTypeList
+} from "@/api/scan/request";
+export default {
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      },
+      sourceList: [], //数据源
+      DynEquipList: [], //数据字典部件类型
+      LocFlagList: [], //位置标签
+      tableData: [], //列表数据
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      form: {
+        EquipmentMark: "", //部件标识关键字
+        SubTypeName: [], //数据字典部件类型
+        LocationFlag: [], //位置标签
+        Datasource: [] //数据源
+      }, //查询条件
+      loading: false, //列表loading
+      autoLoading: false, //自动对应实例
+    };
+  },
+  components: {
+    applyRulesDialog,
+    delRelationDialog,
+    dictionaryDevice,
+    dataSource,
+    locationFlag
+  },
+  props: {
+    typeName: {},
+    isPending: {
+      default: false
+    }
+  },
+  created() {
+    this.init();
+  },
+  mounted() { },
+  methods: {
+    //获取查询条件-提示信息
+    init() {
+      this.getTableData()
+    },
+    //清除对应关系
+    handleDelete(index, row) {
+      this.$refs.del.showDialog(row);
+    },
+    //改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    //改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    //跳转至填充对应规则
+    toAddRelation() {
+      this.$router.push({ path: "floorRela", query: { typeName: this.typeName } });
+    },
+    //获取表格数据
+    getTableData() {
+      let param = {
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize,
+        TypeNameList: [this.typeName]
+      };
+      //处理查询条件
+      if (this.form.EquipmentMark && this.form.EquipmentMark.length) {
+        param.EquipmentMark = this.form.EquipmentMark;
+      }
+      if (this.form.SubTypeName.length) {
+        param.SubTypeNameList = this.form.SubTypeName;
+      }
+      if (this.form.LocationFlag.length) {
+        param.LocationFlagList = this.form.LocationFlag;
+      }
+      if (this.form.Datasource.length) {
+        param.DatasourceList = this.form.Datasource;
+      }
+      this.loading = true;
+      // 查询对应关系(P1)
+      dynamicQuery(param, res => {
+        this.loading = false;
+        this.tableData = res.Content;
+        this.page.total = res.PageSize < 50 ? res.PageSize : res.Total;
+      });
+    },
+    //刷新列表
+    refresh() {
+      this.page.pageNumber = 1;
+      this.$emit('refresh', this.typeName);
+      this.getTableData();
+    },
+    //数据字典部件类型修改
+    changeDictionary(val) {
+      this.page.pageNumber = 1;
+      this.form.SubTypeName = val;
+      this.getTableData();
+    },
+    //数据源修改
+    changeDataSource(val) {
+      this.page.pageNumber = 1;
+      this.form.Datasource = val;
+      this.getTableData();
+    },
+    //修改位置标签
+    changeLocationFlag(val) {
+      this.page.pageNumber = 1;
+      this.form.LocationFlag = val;
+      this.getTableData();
+    },
+    //查询列表
+    queryTableData() {
+      this.page.pageNumber = 1;
+      this.getTableData();
+    },
+    //自动对应实例
+    autoGroupRela() {
+      this.$emit('autoGroupRela', 'floor');
+    }
+  },
+  watch: {
+    projectId() {
+      this.init();
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+#equipRules {
+  height: calc(100% - 54px);
+  /deep/ .text-right {
+    text-align: right;
+  }
+  .query-item {
+    float: left;
+    & + .query-item {
+      margin-left: 10px;
+    }
+  }
+  /deep/ .special .el-input__inner {
+    width: 220px;
+  }
+  /deep/ .table-area {
+    width: 100%;
+    height: calc(100% - 71px);
+    margin-bottom: 10px;
+    td div {
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      overflow: hidden;
+    }
+    .td-bl {
+      border-left: 1px solid #ebeef5;
+    }
+    .tool-tip {
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+    }
+  }
+}
+</style>
+

+ 25 - 5
src/components/point/dynamicdata/historyDialog.vue

@@ -7,7 +7,8 @@
           <el-table-column v-for="item in showLeftHeader" :label="item.label" align="right" :key="item.prop">
             <template slot-scope="scope">
               <div v-for="t in scope.row.leftList" :key="t.id">
-                <el-tooltip :content="t[item.prop]&&t[item.prop].length?t[item.prop].toString():''" placement="top" :disabled="!(t[item.prop]&&t[item.prop].length)">
+                <el-tooltip :content="t[item.prop]&&t[item.prop].length?t[item.prop].toString():''" placement="top"
+                  :disabled="!(t[item.prop]&&t[item.prop].length)">
                   <div>{{t[item.prop]&&t[item.prop].length?t[item.prop].toString():'--'}}</div>
                 </el-tooltip>
               </div>
@@ -21,7 +22,8 @@
                 <div v-if="item.prop=='BuildLocalName'">
                   <el-tooltip
                     :content="t.BuildLocalName&&t.BuildLocalName!='null'?t.FloorLocalName&&t.FloorLocalName!='null'?t.BuildLocalName+'-'+t.FloorLocalName:t.BuildLocalName:''"
-                    placement="top" :disabled="!(t.BuildLocalName&&t.BuildLocalName!='null'?t.FloorLocalName&&t.FloorLocalName!='null'?t.BuildLocalName+'-'+t.FloorLocalName:t.BuildLocalName:'')">
+                    placement="top"
+                    :disabled="!(t.BuildLocalName&&t.BuildLocalName!='null'?t.FloorLocalName&&t.FloorLocalName!='null'?t.BuildLocalName+'-'+t.FloorLocalName:t.BuildLocalName:'')">
                     <div>
                       {{t.BuildLocalName&&t.BuildLocalName!='null'?t.FloorLocalName&&t.FloorLocalName!='null'?t.BuildLocalName+'-'+t.FloorLocalName:t.BuildLocalName:'--'}}
                     </div>
@@ -62,7 +64,7 @@ export default {
       showLeftHeader: [
         { label: '数据源', prop: 'Datasource' },
         { label: '位置标签', prop: 'LocationFlag' },
-        { label: '设备标识', prop: 'EquipmentMark' }
+        { label: '对象标识', prop: 'EquipmentMark' }
       ],
       tableHeader: {
         equip: [
@@ -82,11 +84,29 @@ export default {
           { label: '对象实例名称', prop: 'ObjectLocalName' },
           { label: '对象本地编码', prop: 'ObjectLocalCode' }
         ],
-        space:[
+        space: [
           { label: '对象实例名称', prop: "ObjectLocalName" },
           { label: '对象本地编码', prop: "ObjectLocalCode" },
           { label: '所在建筑楼层', prop: "BuildLocalName" },
-        ]
+        ],
+        build: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象本地编码', prop: "ObjectLocalCode" }
+        ],
+        floor: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象顺序号', prop: "ObjectLocalCode" },
+          { label: '所在建筑', prop: "BuildLocalName" },
+        ],
+        tenant: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象本地编码', prop: "ObjectLocalCode" },
+          { label: '所在业务空间', prop: "BuildLocalName" },
+        ],
+        project: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象本地编码', prop: "ObjectLocalCode" },
+        ],
       }, //所有类型列表头部
       showRightHeader: [], //实际显示的列表头部
     };

+ 8 - 2
src/components/point/dynamicdata/locationCascader.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-cascader placeholder="全部" :options="LocationList" v-model="value" filterable size="small" @change="changeCascader" change-on-select
+  <el-cascader placeholder="全部" :options="LocationList" v-model="value" filterable size="small" @change="changeCascader" :change-on-select="!isFloor"
     :props="props" clearable class="location"></el-cascader>
 </template>
 <script>
@@ -23,7 +23,10 @@ export default {
   },
   props: {
     Related: {},
-    typeName: {}
+    typeName: {},
+    isFloor: {
+      default: false
+    }
   },
   computed: {
     ...mapGetters("layout", ["projectId"])
@@ -36,6 +39,9 @@ export default {
         //添加未明确对象
         this.LocationList = this.delNullItems(this.LocationList)
         this.LocationList.map(item => {
+          if (this.isFloor) {
+            delete item.List;
+          }
           if (item.List) {
             item.List.map(child => {
               if (child.List) {

+ 287 - 0
src/components/point/dynamicdata/projectRules.vue

@@ -0,0 +1,287 @@
+
+<template>
+  <div id="equipRules">
+    <!-- 查询条件 -->
+    <div class="query-area">
+      <el-row>
+        <el-col :span="22">
+          <el-form ref="form" :model="form" :inline="true">
+            <el-row>
+              <div class="query-item special" style="margin-bottom:20px;">
+                <el-input :placeholder="`请输入${typeName}标识关键字`" v-model="form.EquipmentMark" @keyup.enter.native="queryTableData">
+                  <i slot="suffix" class="el-input__icon el-icon-search" @click="queryTableData"></i>
+                </el-input>
+              </div>
+              <div class="query-item">
+                <label style="padding-right:9px">数据源</label>
+                <dataSource :Related="null" @change="changeDataSource" :typeName="typeName"></dataSource>
+              </div>
+              <!-- <div class="query-item">
+                <dictionary-device @change="changeDictionary" :Related="null" :typeName="typeName"></dictionary-device>
+              </div> -->
+              <div class="query-item">
+                <label style="padding-right:9px">位置标签</label>
+                <locationFlag :Related="null" @change="changeLocationFlag" :typeName="typeName"></locationFlag>
+              </div>
+            </el-row>
+          </el-form>
+        </el-col>
+        <el-col :span="2">
+          <el-tooltip class="item" effect="dark" :content="`填充${typeName}标识与实例对应规则`" placement="left">
+            <el-button size="small" type="primary" @click="toAddRelation" icon="el-icon-edit-outline" style="float:right;" :disabled="isPending">
+            </el-button>
+          </el-tooltip>
+          <!-- <el-tooltip class="item" effect="dark" :content="`根据${typeName}标识自动填充实例`" placement="left">
+            <el-button size="small" type="primary" @click="autoGroupRela" :icon="autoLoading?'iconfont icon-jiazai':'iconfont icon-zidong'"
+              style="float:right;padding:7px 14px;margin-right:10px;" :disabled="autoLoading"></el-button>
+          </el-tooltip> -->
+        </el-col>
+      </el-row>
+    </div>
+    <el-row>
+      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">点位表中出现的所有{{typeName}}</el-col>
+      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">对应物理世界中的{{typeName}}实例</el-col>
+    </el-row>
+    <!-- 列表区域 -->
+    <div class="table-area">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column prop="EquipmentMark" :label="`${typeName}标识`" show-overflow-tooltip min-width="200"></el-table-column>
+        <el-table-column prop="LocationFlag" label="位置标签" min-width="200">
+          <template slot-scope="scope">
+            <el-tooltip :content="scope.row.LocationFlag.toString()" placement="top">
+              <div class="tool-tip">{{scope.row.LocationFlag.toString()}}</div>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column prop="Datasource" label="数据源" show-overflow-tooltip min-width="100"></el-table-column>
+        <!-- <el-table-column prop="SubTypeName" :label="`${typeName}类型`" show-overflow-tooltip min-width="100"></el-table-column> -->
+        <el-table-column prop="ObjectLocalName" :label="`${typeName}实例`" show-overflow-tooltip min-width="400" class-name="td-bl"></el-table-column>
+        <!-- <el-table-column label="所在建筑楼层" min-width="300">
+          <template slot-scope="scope">
+            <el-tooltip
+              :content="scope.row.BuildLocalName?scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:''"
+              placement="top">
+              <div class="tool-tip">
+                {{scope.row.BuildLocalName?scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:''}}
+              </div>
+            </el-tooltip>
+          </template>
+        </el-table-column> -->
+        <!-- <el-table-column prop="RoomLocalName" label="所在业务空间" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="CascadeEquipLocalName" label="所属设备实例" show-overflow-tooltip min-width="100"></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
+                :disabled="isPending||scope.row.Related=='False'" icon="el-icon-delete"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <!-- 分页 -->
+    <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>
+    <!-- 清除对应关系弹窗 -->
+    <del-relation-dialog ref="del" @refresh="refresh" :typeName="'space'"></del-relation-dialog>
+  </div>
+</template>
+<script>
+import tools from "@/utils/tools";
+import { mapGetters, mapActions } from "vuex";
+import applyRulesDialog from "@/components/point/dynamicdata/applyRulesDialog";
+import dictionaryDevice from "@/components/point/dynamicdata/dictionaryDevice";
+import delRelationDialog from "@/components/point/dynamicdata/delRelationDialog";
+import dataSource from "@/components/point/dynamicdata/dataSource";
+import locationFlag from "@/components/point/dynamicdata/locationFlag";
+import equipRules from "@/components/point/dynamicdata/equipRules";
+import {
+  dynamicClashConfirm,
+  dynamicExecute,
+  dynamicQuery,
+  dynamicQueryPoint,
+  dynamicPointTypeList,
+  dynamicPendingobjs,
+  dynamicCreateRelation,
+  dynamicDeleteRelation
+} from "@/api/scan/request";
+export default {
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      },
+      sourceList: [], //数据源
+      DynEquipList: [], //数据字典部件类型
+      LocFlagList: [], //位置标签
+      tableData: [], //列表数据
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      form: {
+        EquipmentMark: "", //部件标识关键字
+        SubTypeName: [], //数据字典部件类型
+        LocationFlag: [], //位置标签
+        Datasource: [] //数据源
+      }, //查询条件
+      loading: false, //列表loading
+      autoLoading: false, //自动对应实例
+      RtableData: {}, //当前项目实例
+      deleteRelationVis: false, // 删除弹窗
+      row: {}, // 删除时,选中的行
+    };
+  },
+  components: {
+    applyRulesDialog,
+    dictionaryDevice,
+    dataSource,
+    locationFlag,
+    delRelationDialog
+  },
+  props: {
+    typeName: {},
+    isPending: {
+      default: false
+    }
+  },
+  created() {
+    this.init();
+  },
+  mounted() { },
+  methods: {
+    //获取查询条件-提示信息
+    init() {
+      this.getTableData();
+    },
+    //清除对应关系
+    handleDelete(index, row) {
+      this.$refs.del.showDialog(row);
+    },
+    //改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    //改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    //跳转至填充对应规则
+    toAddRelation() {
+      this.$router.push({ path: "projectRela", query: { typeName: this.typeName } });
+    },
+    //获取表格数据
+    getTableData() {
+      let param = {
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize,
+        TypeNameList: [this.typeName]
+      };
+      //处理查询条件
+      if (this.form.EquipmentMark && this.form.EquipmentMark.length) {
+        param.EquipmentMark = this.form.EquipmentMark;
+      }
+      if (this.form.SubTypeName.length) {
+        param.SubTypeNameList = this.form.SubTypeName;
+      }
+      if (this.form.LocationFlag.length) {
+        param.LocationFlagList = this.form.LocationFlag;
+      }
+      if (this.form.Datasource.length) {
+        param.DatasourceList = this.form.Datasource;
+      }
+      this.loading = true;
+      // 查询对应关系(P1)
+      dynamicQuery(param, res => {
+        this.loading = false;
+        this.tableData = res.Content;
+        this.page.total = res.PageSize < 50 ? res.PageSize : res.Total;
+      });
+    },
+    //刷新列表
+    refresh() {
+      this.page.pageNumber = 1;
+      this.$emit('refresh', this.typeName);
+      this.getTableData();
+    },
+    //数据字典部件类型修改
+    changeDictionary(val) {
+      this.page.pageNumber = 1;
+      this.form.SubTypeName = val;
+      this.getTableData();
+    },
+    //数据源修改
+    changeDataSource(val) {
+      this.page.pageNumber = 1;
+      this.form.Datasource = val;
+      this.getTableData();
+    },
+    //修改位置标签
+    changeLocationFlag(val) {
+      this.page.pageNumber = 1;
+      this.form.LocationFlag = val;
+      this.getTableData();
+    },
+    //查询列表
+    queryTableData() {
+      this.page.pageNumber = 1;
+      this.getTableData();
+    },
+    //自动对应实例
+    // autoGroupRela() {
+    //   this.$emit('autoGroupRela','project');
+    // }
+  },
+  watch: {
+    projectId() {
+      this.init();
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+#equipRules {
+  height: calc(100% - 54px);
+  /deep/ .text-right {
+    text-align: right;
+  }
+  .query-item {
+    float: left;
+    & + .query-item {
+      margin-left: 10px;
+    }
+  }
+  /deep/ .special .el-input__inner {
+    width: 220px;
+  }
+  /deep/ .table-area {
+    width: 100%;
+    height: calc(100% - 71px);
+    margin-bottom: 10px;
+    td div {
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      overflow: hidden;
+    }
+    .td-bl {
+      border-left: 1px solid #ebeef5;
+    }
+    .tool-tip {
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+    }
+  }
+}
+</style>
+

+ 278 - 0
src/components/point/dynamicdata/tenantRules.vue

@@ -0,0 +1,278 @@
+
+<template>
+  <div id="equipRules">
+    <!-- 查询条件 -->
+    <div class="query-area">
+      <el-row>
+        <el-col :span="22">
+          <el-form ref="form" :model="form" :inline="true">
+            <el-row>
+              <div class="query-item special" style="margin-bottom:20px;">
+                <el-input :placeholder="`请输入${typeName}标识关键字`" v-model="form.EquipmentMark" @keyup.enter.native="queryTableData">
+                  <i slot="suffix" class="el-input__icon el-icon-search" @click="queryTableData"></i>
+                </el-input>
+              </div>
+              <div class="query-item">
+                <label style="padding-right:9px">数据源</label>
+                <dataSource :Related="null" @change="changeDataSource" :typeName="typeName"></dataSource>
+              </div>
+              <!-- <div class="query-item">
+                <dictionary-device @change="changeDictionary" :Related="null" :typeName="typeName"></dictionary-device>
+              </div> -->
+              <div class="query-item">
+                <label style="padding-right:9px">位置标签</label>
+                <locationFlag :Related="null" @change="changeLocationFlag" :typeName="typeName"></locationFlag>
+              </div>
+            </el-row>
+          </el-form>
+        </el-col>
+        <el-col :span="2">
+          <el-tooltip class="item" effect="dark" :content="`填充${typeName}标识与实例对应规则`" placement="left">
+            <el-button size="small" type="primary" @click="toAddRelation" icon="el-icon-edit-outline" style="float:right;" :disabled="isPending"></el-button>
+          </el-tooltip>
+          <el-tooltip class="item" effect="dark" :content="`根据${typeName}标识自动填充实例`" placement="left">
+            <el-button size="small" type="primary" @click="autoGroupRela" :icon="autoLoading?'iconfont icon-jiazai':'iconfont icon-zidong'"
+              style="float:right;padding:7px 14px;margin-right:10px;" :disabled="autoLoading"></el-button>
+          </el-tooltip>
+        </el-col>
+      </el-row>
+    </div>
+    <el-row>
+      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">点位表中出现的所有{{typeName}}</el-col>
+      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">对应物理世界中的{{typeName}}实例</el-col>
+    </el-row>
+    <!-- 列表区域 -->
+    <div class="table-area">
+      <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column prop="EquipmentMark" :label="`${typeName}标识`" show-overflow-tooltip min-width="200"></el-table-column>
+        <el-table-column prop="LocationFlag" label="位置标签" min-width="200">
+          <template slot-scope="scope">
+            <el-tooltip :content="scope.row.LocationFlag.toString()" placement="top">
+              <div class="tool-tip">{{scope.row.LocationFlag.toString()}}</div>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <el-table-column prop="Datasource" label="数据源" show-overflow-tooltip min-width="100"></el-table-column>
+        <!-- <el-table-column prop="SubTypeName" :label="`${typeName}类型`" show-overflow-tooltip min-width="100"></el-table-column> -->
+        <el-table-column prop="ObjectLocalName" :label="`${typeName}实例`" show-overflow-tooltip min-width="100" class-name="td-bl"></el-table-column>
+        <el-table-column label="所在业务空间" min-width="300">
+          <template slot-scope="scope">
+            <el-tooltip :content="scope.row.BuildLocalName?scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:''"
+              placement="top">
+              <div class="tool-tip">{{scope.row.BuildLocalName?scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:''}}
+              </div>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+        <!-- <el-table-column prop="RoomLocalName" label="所在业务空间" show-overflow-tooltip min-width="100"></el-table-column>
+        <el-table-column prop="CascadeEquipLocalName" label="所属设备实例" show-overflow-tooltip min-width="100"></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 :disabled="isPending||scope.row.Related=='False'"
+                icon="el-icon-delete"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <!-- 分页 -->
+    <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>
+    <!-- 清除对应关系弹窗 -->
+    <del-relation-dialog ref="del" @refresh="refresh" :typeName="'tenant'"></del-relation-dialog>
+  </div>
+</template>
+<script>
+import tools from "@/utils/tools";
+import { mapGetters, mapActions } from "vuex";
+import applyRulesDialog from "@/components/point/dynamicdata/applyRulesDialog";
+import delRelationDialog from "@/components/point/dynamicdata/delRelationDialog";
+import dictionaryDevice from "@/components/point/dynamicdata/dictionaryDevice";
+import dataSource from "@/components/point/dynamicdata/dataSource";
+import locationFlag from "@/components/point/dynamicdata/locationFlag";
+import equipRules from "@/components/point/dynamicdata/equipRules";
+import {
+  dynamicClashConfirm,
+  dynamicExecute,
+  dynamicQuery,
+  dynamicQueryPoint,
+  dynamicPointTypeList
+} from "@/api/scan/request";
+export default {
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      },
+      sourceList: [], //数据源
+      DynEquipList: [], //数据字典部件类型
+      LocFlagList: [], //位置标签
+      tableData: [], //列表数据
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      form: {
+        EquipmentMark: "", //部件标识关键字
+        SubTypeName: [], //数据字典部件类型
+        LocationFlag: [], //位置标签
+        Datasource: [] //数据源
+      }, //查询条件
+      loading: false, //列表loading
+      autoLoading: false, //自动对应实例
+    };
+  },
+  components: {
+    applyRulesDialog,
+    delRelationDialog,
+    dictionaryDevice,
+    dataSource,
+    locationFlag
+  },
+  props: {
+    typeName: {},
+    isPending: {
+      default: false
+    }
+  },
+  created() {
+    this.init();
+  },
+  mounted() { },
+  methods: {
+    //获取查询条件-提示信息
+    init() {
+      this.getTableData()
+    },
+    //清除对应关系
+    handleDelete(index, row) {
+      this.$refs.del.showDialog(row);
+    },
+    //改变pagesize
+    handleSizeChange(pageSize) {
+      this.page.pageSize = pageSize;
+      this.getTableData();
+    },
+    //改变pageno
+    handleCurrentChange(pageNo) {
+      this.page.pageNumber = pageNo;
+      this.getTableData();
+    },
+    //跳转至填充对应规则
+    toAddRelation() {
+      this.$router.push({ path: "tenantRela", query: { typeName: this.typeName } });
+    },
+    //获取表格数据
+    getTableData() {
+      let param = {
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize,
+        TypeNameList: [this.typeName]
+      };
+      //处理查询条件
+      if (this.form.EquipmentMark && this.form.EquipmentMark.length) {
+        param.EquipmentMark = this.form.EquipmentMark;
+      }
+      if (this.form.SubTypeName.length) {
+        param.SubTypeNameList = this.form.SubTypeName;
+      }
+      if (this.form.LocationFlag.length) {
+        param.LocationFlagList = this.form.LocationFlag;
+      }
+      if (this.form.Datasource.length) {
+        param.DatasourceList = this.form.Datasource;
+      }
+      this.loading = true;
+      // 查询对应关系(P1)
+      dynamicQuery(param, res => {
+        this.loading = false;
+        this.tableData = res.Content;
+        this.page.total = res.PageSize < 50 ? res.PageSize : res.Total;
+      });
+    },
+    //刷新列表
+    refresh() {
+      this.page.pageNumber = 1;
+      this.$emit('refresh', this.typeName);
+      this.getTableData();
+    },
+    //数据字典部件类型修改
+    changeDictionary(val) {
+      this.page.pageNumber = 1;
+      this.form.SubTypeName = val;
+      this.getTableData();
+    },
+    //数据源修改
+    changeDataSource(val) {
+      this.page.pageNumber = 1;
+      this.form.Datasource = val;
+      this.getTableData();
+    },
+    //修改位置标签
+    changeLocationFlag(val) {
+      this.page.pageNumber = 1;
+      this.form.LocationFlag = val;
+      this.getTableData();
+    },
+    //查询列表
+    queryTableData() {
+      this.page.pageNumber = 1;
+      this.getTableData();
+    },
+    //自动对应实例
+    autoGroupRela() {
+      this.$emit('autoGroupRela','tenant');
+    }
+  },
+  watch: {
+    projectId() {
+      this.init();
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+#equipRules {
+  height: calc(100% - 54px);
+  /deep/ .text-right {
+    text-align: right;
+  }
+  .query-item {
+    float: left;
+    & + .query-item {
+      margin-left: 10px;
+    }
+  }
+  /deep/ .special .el-input__inner {
+    width: 220px;
+  }
+  /deep/ .table-area {
+    width: 100%;
+    height: calc(100% - 71px);
+    margin-bottom: 10px;
+    td div {
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      overflow: hidden;
+    }
+    .td-bl {
+      border-left: 1px solid #ebeef5;
+    }
+    .tool-tip {
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+    }
+  }
+}
+</style>
+

+ 107 - 0
src/components/ready/buildfloor/modelFile.vue

@@ -0,0 +1,107 @@
+<template>
+    <div id="modelFile">
+        <span class="modelFile" style="margin-right: 12px;">模型文件</span>
+        <el-cascader :options="options" :show-all-levels="false" @change="handleChange" style="width:160px;"
+        @active-item-change='handleItemChange' clearable placeholder="请选择模型文件" v-model="casVal"></el-cascader>
+    </div>
+</template>
+<script>
+import tools from "@/utils/scan/tools"
+import request from "@/api/model/file.js";
+import { mapGetters, mapActions } from "vuex"
+
+export default {
+  computed: {
+    ...mapGetters("layout", [ "projectId", "secret", "userId" ])
+  },
+  data() {
+    return {
+      casVal: [],
+      options: [],
+      modelIdToFloorId: {}
+    };
+  },
+  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() {
+      request.queryModel("", res => {
+        this.options = res.Content.map(t => {
+          return {
+            value: t.Id,
+            label: t.Name,
+            children: []
+          }
+        })
+      });
+    },
+    // 通过id查询文件夹下模型文件
+    handleItemChange(val) {
+      let data = {
+        FolderId: val[0],
+        ProjectId: this.projectId
+      };
+      request.queryFloorList(data, res => {
+        let tempArr = res.Content.map(t => {
+          this.modelIdToFloorId[t.CurrentModelId] = t.Id;
+          return {
+            value: t.CurrentModelId,
+            label: t.FloorName
+          }
+        })
+        this.pushChild(this.options, tempArr, val[0])
+      })
+    },
+    // 将模型文件list填到相应的文件夹下
+    pushChild(options, arr, Code) {
+      options.map(option => {
+        if (option.value == Code) {
+          option.children = arr;
+        } else {
+          if (option.children) {
+            this.pushChild(option.children, arr, Code)
+          }
+        }
+      })    
+    },
+    //改变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>

+ 83 - 0
src/components/ready/buildfloor/modelFolder.vue

@@ -0,0 +1,83 @@
+<template>
+  <div id="modelFile">
+    <span class="modelFile" style="margin-right: 12px;">模型文件夹</span>
+    <el-select v-model="casVal" filterable clearable placeholder="请选择模型文件夹" style="width:160px;" @change="handleChange">
+      <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
+    </el-select>
+  </div>
+</template>
+<script>
+import tools from "@/utils/scan/tools"
+import request from "@/api/model/file.js";
+import { mapGetters, mapActions } from "vuex"
+
+export default {
+  computed: {
+    ...mapGetters("layout", ["projectId", "secret", "userId"])
+  },
+  data() {
+    return {
+      casVal: '',
+      options: []
+    };
+  },
+  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() {
+      request.queryModel("", res => {
+        this.options = res.Content.map(t => {
+          return {
+            value: t.Id,
+            label: t.Name
+          }
+        })
+      });
+    },
+    //改变item
+    handleChange(value) {
+      this.options.map(item =>{
+        if (item.value == value) {
+          value = item
+        }
+      })
+      value = value?value:{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>

+ 6 - 0
src/fetch/point_http.js

@@ -318,6 +318,12 @@ export function uploadPointFile(param, success) {
     return post(`${point}/point/${param.type}/point-import`, data, success)
 }
 
+//上传2
+export function uploadPointFile2(param, success) {
+    let data = param.data
+    return post(`${point}/point/${param.type}/point-import2`, data, success)
+}
+
 //根据id批量删除对应关系
 export function deleteRelationList(param, success) {
     let data = param

+ 322 - 45
src/framework/components/messagesever/index.vue

@@ -2,13 +2,48 @@
  * @Author: zhangyu
  * @Date: 2019-08-26 15:22:13
  * @Info: 
- * @LastEditTime: 2019-09-26 20:16:41
+ * @LastEditTime: 2019-11-13 15:46:29
  -->
 <template>
-  <div class="notification-box" @click="handleClickRead">
+  <div class="notification-box" v-clickOutside="handleClose" @click="handleClickRead">
     <el-badge :value="unreadNum" :hidden="!unreadNum" :max="99">
       <i class="el-icon-message-solid"></i>
     </el-badge>
+    <transition name="el-fade-in-linear">
+      <div v-show="noticeListShow" @click.stop="" class="noticeBox">
+        <ul class="noticeTab">
+          <li class="noticeTab_item">消息通知
+            <!-- <span class="unread_num">1</span> -->
+          </li>
+        </ul>
+        <div class="noticeList_scroll">
+          <el-scrollbar style="height:100%;">
+            <ul class="noticeList">
+              <li class="noticeList_item" v-for="item in messageList" :key="item.Id" :title="item.Content.Message?item.Content.Message:''">
+                <div class="noticeItem_box">
+                  <div class="noticeItem_text">
+                    <i :class="iconClassMap[item.Type]?iconClassMap[item.Type]:'msg-icon el-icon-warning warning-color'"></i>
+                    <p><span>{{`【${moduleMap[item.Module]?moduleMap[item.Module]:item.Module}】 `}}</span>{{item.Title?item.Title:""}}</p>
+                  </div>
+                  <div class="noticeItem_time">
+                    <span class="proname">{{item.Project[0].ProjLocalName || ''}}</span>
+                    {{item.CreateTime}}
+                    <el-link v-for="(btn, index) in item.Content.ButtonList?item.Content.ButtonList:[]"
+                      style="float:right;font-size:12px;margin-left:5px;" type="primary" :key="index"
+                      :href="`/image-service/common/file_get?systemId=revit&key=${btn.Url}`" :download="btn.FileName?btn.FileName:''">
+                      {{btn.Name?btn.Name:""}}</el-link>
+                  </div>
+                </div>
+              </li>
+            </ul>
+          </el-scrollbar>
+        </div>
+        <div class="notice_operate">
+          <!-- <div class="readAll">全部标为已读</div> -->
+          <div class="seeAll" @click="allDetails">查看全部<i class="iconfont icon-right"></i></div>
+        </div>
+      </div>
+    </transition>
     <!-- <el-button type="primary" @click="handleClickConnectMQ">连接MQ</el-button>
     <el-button type="primary" @click="handleClickDisconnectMQ">断开MQ</el-button>
     <el-button type="primary" @click="handleClickUnsubscribe">停止接收消息</el-button><br><br>
@@ -30,39 +65,90 @@
 import { mapGetters } from 'vuex'
 import Stomp from 'stompjs'
 import Msmq from './msmq'
+import Bus from '@/utils/bus.js'
 import { MQTT_SERVICE, MQTT_USERNAME, MQTT_PASSWORD } from './mqSetting'
+import { messgeCount, messgeQuery, messgeUpdateState } from '@/api/msgsever'
 
 export default {
+  components: {
+
+  },
   data() {
     return {
       client: Stomp.client(MQTT_SERVICE),
       unreadNum: 0,
+      noticeListShow: false,//是否显示消息列表
       sendMessage: '',
       messageList: [], // 历史消息
       subList: [], // 订阅的消息实例
-      topics: ["/topic/model.manage"] // 订阅的消息名称
+      topics: ["/topic/message.manage"], // 订阅的消息名称
+      messageList: [],
+      moduleMap: {//消息模块映射
+        "Model": "模型文件管理"
+      },
+      iconClassMap: { //消息类型图标映射
+        "Success": "msg-icon el-icon-success success-color",
+        "Error": "msg-icon el-icon-error error-color",
+        "Warning": "msg-icon el-icon-warning warning-color",
+        "Info": "msg-icon el-icon-info info-color",
+      },
     }
   },
-  created () {
+  created() {
     this.connect()
-    // let url = "ws://192.168.20.225:61614/stomp";
-    // let login = "admin";
-    // let passcode = "admin";
-    // let destination = "/topic/datacenter.broadcast";
-    // let client = Stomp.client(url)
-    // console.log('钩子:',client)
-    // var onconnect = function(frame) {
-    //   client.subscribe(destination, function(message) {
-    //     console.log(message.body);
-    //     alert(message.body);        
-    //   });
-    // };
-    // client.connect(login, passcode, onconnect)
+  },
+  mounted() {
+    this.getUnreadCount()
+    this.getMessageList()//获取消息列表
+    Bus.$on('messageListUpdate', message => {
+      this.getMessageList()
+    })
+    Bus.$on('getUnreadCountUpdate', message => {
+      this.getUnreadCount()
+    })
   },
   computed: {
-    ...mapGetters('layout', ['userInfo', 'projectId', 'projects'])
+    ...mapGetters('layout', ['userInfo', 'projectId', 'projects', 'userId'])
   },
-  methods:{
+  methods: {
+    getMessageList() {//获取消息列表(最新10条)
+      let params = {
+        Cascade: [
+          {
+            Name: "project"
+          }
+        ],
+        Filters: `UserId='${this.userId}'`,
+        Orders: "CreateTime desc, Id asc",
+        PageNumber: 1,
+        PageSize: 10
+      }
+      messgeQuery(params, res => {
+        this.messageList = res.Content
+      })
+    },
+    getUnreadCount() {//获取未读消息的数量
+      let params = {
+        Filters: `Read=false;UserId='${this.userId}'`
+      }
+      messgeCount(params, res => {
+        this.unreadNum = res.Count
+      })
+    },
+    setAllRead() {//将当前角色消息全部置为已读
+      if (this.userId) {
+        messgeUpdateState({ Read: true, UserId: this.userId }, res => { this.unreadNum = 0 })
+      }
+    },
+    handleClose(e) {//关闭消息列表
+      this.noticeListShow = false
+    },
+    handleClickRead() {//点击消息铃铛
+      this.noticeListShow ? this.noticeListShow = false : this.noticeListShow = true
+      if (this.noticeListShow) {
+        this.setAllRead()//将当前角色消息全部置为已读
+      }
+    },
     connect() {
       this.client = Stomp.client(MQTT_SERVICE)
       this.client.reconnect_delay = 5000
@@ -85,7 +171,7 @@ export default {
     },
     //接收到消息的回调
     onmessage(message) {
-      this.unreadNum = Msmq.handleMsg(message, this.projects, this.unreadNum);
+      this.unreadNum = Msmq.handleMsg(message, this.projects, this.userId, this.unreadNum);
     },
     // 接收消息失败回调
     onFailed(frame) {
@@ -99,7 +185,7 @@ export default {
     },
     //断开连接
     disconnect() {
-      this.client.disconnect(function() {
+      this.client.disconnect(function () {
         console.log("连接已断开!");
       })
     },
@@ -107,45 +193,236 @@ export default {
     send(destination, message, headers = {}) {
       this.client.send(destination, headers, JSON.stringify(message))
     },
-    
-    handleClickConnectMQ() {
+
+    handleClickConnectMQ() {//连接MQ
       this.connect()
     },
-    handleClickDisconnectMQ() {
+    handleClickDisconnectMQ() {//断开MQ
       this.disconnect()
     },
-    handleClickUnsubscribe() {
+    handleClickUnsubscribe() {//停止接收消息
       this.unsubscribe()
     },
-    handleClickSendMessage() {
-      this.send('/topic/datacenter.broadcast',this.sendMessage)
-    }, 
-    handleClickRead() {
-      this.unreadNum = 0;
+    handleClickSendMessage() {//发送消息
+      this.send('/topic/datacenter.broadcast', this.sendMessage)
+    },
+    allDetails() {
+      this.noticeListShow = false;
+      this.$router.push({ path: "/allDetails" });
     }
   }
 }
 </script>
 
 <style lang="scss" scoped>
-  .notification-box{
-    width: 100%;
-    height: 100%;
-    padding: 16px 10px 10px;
+.notification-box {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  padding: 16px 10px 10px;
+  box-sizing: border-box;
+  color: #79869a;
+  cursor: pointer;
+  .noticeBox {
+    position: absolute;
+    top: 50px;
+    left: 50%;
+    margin-left: -220px;
+    cursor: auto;
+    z-index: 1000;
+    text-align: left;
+    width: 272px;
+    height: 362px;
+    box-shadow: 0 1px 6px 0 #ccc;
+    color: #333;
+    background: #fff;
+    overflow: visible !important;
+  }
+  .noticeBox::before {
+    content: "";
+    border: solid 7px transparent;
+    border-bottom-color: #fff;
+    display: block;
+    position: absolute;
+    width: 2px;
+    top: -14px;
+    left: 50%;
+    margin-left: 77px;
+    z-index: 0;
+  }
+  .noticeTab {
+    padding: 8px 16px 0;
+    z-index: 10;
+    height: 32px;
+    zoom: 1;
+    box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.1) inset;
+    .noticeTab_item {
+      float: left;
+      position: relative;
+      width: 240px;
+      height: 32px;
+      line-height: 32px;
+      padding: 0;
+      margin-right: 0;
+      font-weight: 700;
+      text-align: left;
+      cursor: pointer;
+      -webkit-transition: all 0.2s ease-in-out;
+      -o-transition: all 0.2s ease-in-out;
+      transition: all 0.2s ease-in-out;
+      .unread_num {
+        display: inline-block;
+        color: #fff;
+        background-color: #5182e4;
+        height: 14px;
+        padding: 0 2px;
+        line-height: 14px;
+        text-align: center;
+        border-radius: 2px;
+        font-size: 12px;
+        padding: 0 3px;
+        font-family: Arial;
+        -webkit-transform: scale(0.85);
+        -ms-transform: scale(0.85);
+        -o-transform: scale(0.85);
+        transform: scale(0.85);
+      }
+    }
+    .active {
+      box-shadow: 0 -2px 0 0 #5182e4 inset;
+    }
+  }
+  .noticeList_scroll {
+    height: 282px;
+    /deep/ .el-scrollbar__wrap {
+      overflow-x: hidden;
+    }
+    .noticeList_item {
+      width: 100%;
+      height: auto;
+      position: relative;
+      cursor: pointer;
+      box-sizing: border-box;
+      padding: 12px 16px;
+      -webkit-transition: all 0.2s ease-in-out;
+      -o-transition: all 0.2s ease-in-out;
+      transition: all 0.2s ease-in-out;
+      zoom: 1;
+      .noticeItem_box {
+        float: left;
+        position: relative;
+        width: 100%;
+        .noticeItem_text {
+          color: rgba(10, 18, 32, 0.87);
+          font-weight: 700;
+          padding-left: 18px;
+          text-indent: -6px;
+          position: relative;
+          font-size: 12px;
+          line-height: 17px;
+          -webkit-transition: all 0.2s ease-in-out;
+          -o-transition: all 0.2s ease-in-out;
+          transition: all 0.2s ease-in-out;
+          .msg-icon {
+            position: absolute;
+            top: 2.5px;
+            left: 6px;
+          }
+          p {
+            word-break: break-all;
+          }
+        }
+        .noticeItem_time {
+          font-size: 12px;
+          height: 19px;
+          line-height: 19px;
+          color: rgba(10, 18, 32, 0.46);
+          margin-top: 4px;
+          padding-left: 18px;
+          .proname{
+            float: left;
+            display: block;
+            width: 80px;
+            overflow: hidden;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+          }
+        }
+      }
+    }
+    .noticeList_item:hover {
+      background-color: #f5f7f7;
+    }
+    .noticeList_item:after {
+      content: "";
+      display: block;
+      height: 0;
+      clear: both;
+      visibility: hidden;
+    }
+    .noticeList_item:before {
+      position: absolute;
+      right: 0;
+      bottom: 0;
+      left: 0;
+      height: 1px;
+      padding: 0 16px;
+      background-color: #ebebeb;
+      content: "";
+      background-clip: content-box;
+    }
+  }
+  .notice_operate {
+    height: 40px;
+    line-height: 20px;
+    padding: 10px 16px;
     box-sizing: border-box;
-    color: #79869a;
-    cursor: pointer;
-    .el-icon-message-solid{
-      font-size: 22px;
+    background-color: rgba(242, 243, 245, 0.48);
+    box-shadow: inset 0 1px 0 0 rgba(10, 18, 32, 0.06);
+    zoom: 1;
+    .readAll {
+      float: left;
+      cursor: pointer;
+      -webkit-transition: all 0.2s ease-in-out;
+      -o-transition: all 0.2s ease-in-out;
+      transition: all 0.2s ease-in-out;
     }
-    /deep/ .el-badge__content{
-      height: 16px;
-      line-height: 16px;
-      border: 1px solid transparent;
+    .readAll:hover {
+      text-decoration: underline;
     }
+    .seeAll {
+      float: right;
+      color: #5182e4;
+      cursor: pointer;
+      font-weight: 700;
+    }
+    .seeAll:hover {
+      text-decoration: underline;
+    }
+  }
+  .el-icon-message-solid {
+    font-size: 22px;
   }
-  .notification-box:hover{
-    color: #d3d8e2;
-    background-color: #3f4f62;
+  /deep/ .el-badge__content {
+    height: 16px;
+    line-height: 16px;
+    border: 1px solid transparent;
   }
+}
+.notification-box:hover {
+  color: #d3d8e2;
+  background-color: #3f4f62;
+}
+.success-color {
+  color: #67c23a;
+}
+.error-color {
+  color: #f56c6c;
+}
+.warning-color {
+  color: #e6a23c;
+}
+.info-color {
+  color: #909399;
+}
 </style>

+ 209 - 0
src/framework/components/messagesever/msgAllDetails.vue

@@ -0,0 +1,209 @@
+  <template>
+  <div class="box">
+    <div class="condition">
+      <div class="main" :style="tableData && tableData.length?'height: calc(100% - 50px);':'height: calc(100% - 46px);'">
+        <el-table ref="multipleTable" :data="tableData" v-loading='loading' stripe height="100%" :header-cell-style="headerStyle"
+          @expand-change="changeMessageState">
+          <el-table-column type="selection" width="55"></el-table-column>
+          <el-table-column width="25">
+            <template slot-scope="scope">
+              <el-badge class="item" type="warning" is-dot v-if="!scope.row.Read"></el-badge>
+            </template>
+          </el-table-column>
+          <el-table-column prop="Title" label="标题内容" min-width="300" show-overflow-tooltip></el-table-column>
+          <el-table-column label="项目">
+            <template slot-scope="scope">
+              {{ scope.row.Project[0].ProjLocalName }}
+            </template>
+          </el-table-column>
+          <el-table-column label="模块" width="200">
+            <template slot-scope="scope">
+              {{ moduleMap[scope.row.Module]?moduleMap[scope.row.Module]:scope.row.Module }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="CreateTime" label="消息时间">
+          </el-table-column>
+          <el-table-column label="消息类型">
+            <template slot-scope="scope">
+              <div>
+                <i :class="iconClassMap[scope.row.Type]?iconClassMap[scope.row.Type]:'msg-icon el-icon-warning warning-color'" style="font-size:14px;"></i>
+                <span>{{ typeMap[scope.row.Type]?typeMap[scope.row.Type]:scope.row.Type }}</span>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column type="expand">
+            <template slot-scope="scope">
+              <p>{{ scope.row.Content.Message }}</p>
+              <el-link v-for="(btn, index) in scope.row.Content.ButtonList" style="float:left;font-size:12px;color:white;width:"
+                :key="index" :href="`/image-service/common/file_get?systemId=revit&key=${btn.Url}`" :download="btn.FileName?btn.FileName:''">
+                {{btn.Name}}
+              </el-link>
+            </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>
+    </div>
+  </div>
+</template>
+
+  <script>
+import { mapGetters } from 'vuex'
+import { messgeQuery, messgeUpdate } from '@/api/msgsever'
+import Bus from '@/utils/bus.js'
+
+export default {
+  data() {
+    return {
+      tableData: [],
+      loading: false,
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      headerStyle: {// 列表样式
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      }, 
+      moduleMap: {//消息模块映射
+        "Model": "模型文件管理"
+      },
+      iconClassMap: { //消息类型图标映射
+        "Success": "msg-icon el-icon-success success-color",
+        "Error": "msg-icon el-icon-error error-color",
+        "Warning": "msg-icon el-icon-warning warning-color",
+        "Info": "msg-icon el-icon-info info-color",
+      },
+      typeMap: { //消息类型文字映射
+        "Success": "成功",
+        "Error": "错误",
+        "Warning": "警告",
+        "Info": "提醒",
+      }
+    }
+  },
+  computed: {
+    ...mapGetters('layout', ['userId'])
+  },
+  mounted() {
+    this.getTableData();
+  },
+  methods: {
+    // 获取列表数据
+    getTableData() {
+      let params = {
+        Cascade: [
+          {
+            Name: "project"
+          }
+        ],
+        Filters: `UserId='${this.userId}'`,
+        Orders: "CreateTime desc, Id asc",
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize
+      }
+      this.loading = true;
+      messgeQuery(params, res => {
+        this.tableData = res.Content;
+        this.page.total = res.Total;
+        this.loading = false;
+      })
+    },
+    // 切换每页显示数量
+    handleSizeChange(val) {
+      this.page.pageSize = val;
+      this.getTableData();
+    },
+    // 切换页码
+    handleCurrentChange(val) {
+      this.page.pageNumber = val;
+      this.getTableData();
+    },
+    // 更新消息状态:已读、未读
+    changeMessageState(val) {
+      if(!val.Read){
+        val.Read = true;
+        let params = {
+          Content: [{
+            Id: val.Id,
+            Read: true
+          }]
+        }
+        messgeUpdate(params, res => { 
+          Bus.$emit('getUnreadCountUpdate')
+        });// 展开更新为已读状态,未读数量同步变更
+      }
+    }
+  }
+};
+  </script>
+
+<style scoped lang='less'>
+.box {
+  .condition {
+    padding: 10px;
+    display: flex;
+    height: 100%;
+    flex-direction: column;
+    border: 1px solid #dfe6ec;
+    background: #fff;
+    .main {
+      margin-top: 10px;
+      a{
+        text-decoration: none;
+      }
+    }
+  }
+}
+.el-badge.item {
+  height: 10px;
+}
+.el-table__expanded-cell {
+  p {
+    margin-left: 40px;
+  }
+}
+.el-link {
+  margin: 20px 0 0 40px;
+  background: #409eff;
+  border-radius: 3px;
+  padding: 3px 15px;
+}
+.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%;
+}
+.success-color {
+  color: #67c23a;
+}
+.error-color {
+  color: #f56c6c;
+}
+.warning-color {
+  color: #e6a23c;
+}
+.info-color {
+  color: #909399;
+}
+</style>

+ 29 - 10
src/framework/components/messagesever/msmq.js

@@ -2,20 +2,39 @@ import { Notification } from 'element-ui';
 import Bus from '@/utils/bus.js'
 
 const MSMQ = {
-  handleMsg (message, projects, unreadNum ) {
+  msgTypeMap: {
+    "Success": "success",
+    "Error": "error",
+    "Warning": "warning",
+    "Info": "info",
+  },
+  moduleMap: {//消息模块映射
+    "Model": "模型文件管理"
+  },
+  handleMsg (message, projects, userId, unreadNum ) {
     let data
     try {
       data = JSON.parse(message.body)
-    } catch (err) {}
-    // if(projects.some((item) => {return item.id == data.projectId})) { //判断消息是否是当前用户拥有的项目
-      unreadNum++
-      if(message.headers.destination == '/topic/model.manage'){ //模型文件的消息触发模型文件列表刷新事件
-        Bus.$emit('modelStatusChange', data)
+    } catch (err) {
+      return false
+    }
+    if(data.ProjectId && projects.some((item) => {return item.id == data.ProjectId})) { //判断消息是否是当前用户拥有的项目
+      if(!data.UserList || (userId && data.UserList && data.UserList.includes(userId))){//判断消息接收人是否是当前用户
+        if(data.Module && data.Module == 'Model'){ //模型文件的消息触发模型文件列表刷新事件
+          Bus.$emit('modelStatusChange', data)
+        }
+        Notification({ 
+          title: `${data.Title?data.Title:''}`, 
+          dangerouslyUseHTMLString: true, 
+          message: `【${this.moduleMap[data.Module]?this.moduleMap[data.Module]:data.Module}】${data.Content?data.Content.Message?data.Content.Message:'':''}`,
+          type: this.msgTypeMap[data.Type]?this.msgTypeMap[data.Type]:'info'
+        })
+        // Notification.info({ title: '消息',dangerouslyUseHTMLString: true, message: `项目编号:${data.projectId}<br>消息类型:${data.type}<br>描述信息:${data.description}<br>` })
+        unreadNum++
+        Bus.$emit('messageListUpdate', data)//消息驱动消息列表刷新
+        return unreadNum
       }
-      // Notification.info({ title: '消息',dangerouslyUseHTMLString: true, message: `项目编号:${data.projectId}<br>消息类型:${data.type}<br>描述信息:${data.description}<br>` })
-      Notification.info({ title: '消息', dangerouslyUseHTMLString: true, message: `${JSON.stringify(data)}` })
-      return unreadNum
-    // }
+    }
   }
 }
 

+ 14 - 10
src/framework/layout/layout-store.js

@@ -63,19 +63,19 @@ export default {
             storage.set(KEY_MENU_SELECTED, val)
         },
         setprojectId: (state, val) => {
-            let cacheInfo = JSON.parse(localStorage.getItem('_sagacloud_admin_store_cacheInfo'))?JSON.parse(localStorage.getItem('_sagacloud_admin_store_cacheInfo')):{}
+            let cacheInfo = JSON.parse(localStorage.getItem('_sagacloud_admin_store_cacheInfo')) ? JSON.parse(localStorage.getItem('_sagacloud_admin_store_cacheInfo')) : {}
             state.projectId = val
             localStorage.setItem('projectId', val)
-            if(cacheInfo[state.userInfo.userName]){
+            if (cacheInfo[state.userInfo.userName]) {
                 cacheInfo[state.userInfo.userName].projectId = val
                 localStorage.setItem('_sagacloud_admin_store_cacheInfo', JSON.stringify(cacheInfo))
             } else {
-                cacheInfo[state.userInfo.userName] = {projectId: val}
+                cacheInfo[state.userInfo.userName] = { projectId: val }
                 localStorage.setItem('_sagacloud_admin_store_cacheInfo', JSON.stringify(cacheInfo))
             }
             storage.set(KEY_PROJECT_SELECTED, val)
-            state.projects.map((item) =>{
-                if(item.id == val) {
+            state.projects.map((item) => {
+                if (item.id == val) {
                     state.secret = item.pwd
                 }
             })
@@ -98,21 +98,21 @@ export default {
                         }
                         state.projects = []
                         if (resp.Projects) {
-                            if(resp.Projects[0] && resp.Projects[0].ProjId) {
+                            if (resp.Projects[0] && resp.Projects[0].ProjId) {
                                 state.projectId = resp.Projects[0].ProjId
-                                state.secret = resp.Projects[0].Secret?resp.Projects[0].Secret:""
+                                state.secret = resp.Projects[0].Secret ? resp.Projects[0].Secret : ""
                             }
                             resp.Projects.forEach(proj =>
                                 state.projects.push({
                                     id: proj.ProjId,
                                     name: proj.ProjLocalName,
-                                    pwd: proj.Secret?proj.Secret:""
+                                    pwd: proj.Secret ? proj.Secret : ""
                                 })
                             )
                         }
                     } else {
                         state.userInfo = null
-                       
+
                     }
                     resolve(resp)
                 })
@@ -120,7 +120,11 @@ export default {
         },
         setBreadcrumb: {
             root: true,
-            handler({ state }, val) {
+            handler({ state, commit }, val) {
+                let label = val[0].label;
+                if (label === "消息中心") {
+                    commit("setSidebarSelected", "message"); // 当进入消息中心页面的时候不选中导航栏
+                }
                 state.breadcrumb = []
                 state.breadcrumb = val
                 storage.set(KEY_PAGE_BRANDCRUMB, val)

+ 110 - 17
src/router/system.js

@@ -1,4 +1,5 @@
 import LayoutMain from '@/framework/layout/Main'
+import MsgAllDetails from "@/framework/components/messagesever/msgAllDetails"
 
 import Login from '@/framework/layout/Login'
 import Dasboard from '@/views/dasboard'
@@ -33,17 +34,27 @@ import equipRela from '@/views/point/dynamicdata/addRelation/equipRela'
 import partsRela from '@/views/point/dynamicdata/addRelation/partsRela'
 import systemRela from '@/views/point/dynamicdata/addRelation/systemRela'
 import spaceRela from '@/views/point/dynamicdata/addRelation/spaceRela'
+import buildRela from '@/views/point/dynamicdata/addRelation/buildRela'
+import floorRela from '@/views/point/dynamicdata/addRelation/floorRela'
+import tenantRela from '@/views/point/dynamicdata/addRelation/tenantRela'
+import projectRela from '@/views/point/dynamicdata/addRelation/projectRela'
 
 /** 扫楼作业 */
 import buildTask from '@/views/data_admin/buildTask'
+import addDeviceTask from '@/views/data_admin/buildTask/addTask/addDeviceTask'
+import addAssetsTask from '@/views/data_admin/buildTask/addTask/addAssetsTask'
+import addModelTask from '@/views/data_admin/buildTask/addTask/addModelTask'
 import buildAssets from '@/views/data_admin/buildAssets'
 import buildLog from '@/views/data_admin/buildLog'
 import buildData from '@/views/data_admin/buildData'
 import buildGraphy from '@/views/data_admin/buildGraphy'
+import updatePointZone from '@/views/data_admin/buildGraphy/updatePointZone'
+import createPointZone from '@/views/data_admin/buildGraphy/createPointZone'
 
 /**  台账管理 */
 import systemLedger from '@/views/ledger/system'
 import systemadd from '@/views/ledger/system/addsystem'
+import systemDetail from '@/views/ledger/system/systemDetail'
 import facilityLedger from '@/views/ledger/facility'
 import partsLedger from '@/views/ledger/facility/parts'
 import partsmanageLedger from '@/views/ledger/facility/partsmanage'
@@ -51,8 +62,8 @@ import partsadd from '@/views/ledger/facility/partsmanage/addparts'
 import deviceadd from '@/views/ledger/facility/addfacility'
 import propertyadd from '@/views/ledger/property/addproperty'
 import propertyLedger from '@/views/ledger/property'
-import spacelist from '@/views/ledger/spacelist'//业务空间台账
-import addPropertys from '@/views/ledger/property/addpropertys'//根据未关联资产的设备或部件批量创建设备
+import spacelist from '@/views/ledger/spacelist' //业务空间台账
+import addPropertys from '@/views/ledger/property/addpropertys' //根据未关联资产的设备或部件批量创建设备
 import batchlinkAssets from '@/views/ledger/facility/batchlink' //批量关联资产
 import cenotelist from '@/views/ledger/cenotelist' //竖井清单
 import cenoteadd from '@/views/ledger/cenotelist/cenoteadd' //添加竖井
@@ -63,6 +74,7 @@ import dataReport from '@/views/ledger/report'
 import auth from '@/views/system/auth'
 import noUser from '@/views/system/nouser'
 import spaceDetail from '@/views/ledger/spacelist/spaceDetail'
+import relatedSpace from '@/views/ledger/cenotelist/relatedSpace'
 
 /**  关系维护并计算 */
 import maintain from '@/views/relation/maintain'
@@ -72,19 +84,35 @@ import overView from '@/views/relation/overview'
 import supplier from '@/views/manufactor/supplier'
 
 /**  业务空间数据导入工具 */
-import dataUtil from '@/views/business_space/dataUtil'
+import dataUtil from '@/views/business_space/dataUtil/index'
+import dataUtil2 from '@/views/business_space/dataUtil/index2'
 
 /**市场及商务 */
 const OwnerManage = () =>
-    import('@/views/market/owner/manage')
+    import ('@/views/market/owner/manage')
 
-export default [
-    { path: '/', name: '', component: LayoutMain, children: [{ path: '', name: 'blank', component: Dasboard }] },
+export default [{
+        path: '/',
+        name: '',
+        component: LayoutMain,
+        children: [
+            { path: '', name: 'blank', component: Dasboard },
+            { path: 'allDetails', name: "allDetails", component: MsgAllDetails, meta: { keepAlive: false, breadcrumbs: [{ label: '消息中心' }] } }
+        ]
+    },
     //{ path: '/login', name: 'Login', component: Login },
     { path: '/auth', name: 'auth', component: auth },
     { path: '/noUser', name: 'noUser', component: noUser },
     // 业务空间数据导入工具
-    { path: '/dataUtil', name: 'dataUtil', component: LayoutMain,children:[{path:'index',component: dataUtil}] },
+    {
+        path: '/dataUtil',
+        name: 'dataUtil',
+        component: LayoutMain,
+        children: [
+            { path: 'index', component: dataUtil },
+            { path: 'index2', component: dataUtil2 }
+        ]
+    },
     // 平台管理
     {
         path: '/platform',
@@ -106,7 +134,7 @@ export default [
             // { path: 'buildfloor', name: 'buildFloor', component: Dasboard, meta: { keepAlive: false, breadcrumbs: [{ label: '建筑楼层管理' }] } },
             { path: 'collectsetting', name: 'collectsetting', component: collectsetting, meta: { keepAlive: false, breadcrumbs: [{ label: '需采集的信息点' }] } },
             { path: 'appuser', name: 'buildUser', component: buildUser, meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼App用户管理' }] } },
-            { path: 'repetitionGraphy', name: 'repetitionGraphy', component: repetitionGraphy, meta: { keepAlive: false, breadcrumbs: [{ label: '建筑楼层管理', path: '/ready/buildfloor' }, { label:'平面图维护' }] }}
+            { path: 'repetitionGraphy', name: 'repetitionGraphy', component: repetitionGraphy, meta: { keepAlive: false, breadcrumbs: [{ label: '建筑楼层管理', path: '/ready/buildfloor' }, { label: '平面图维护' }] } }
         ]
     },
     //模型管理
@@ -119,8 +147,8 @@ export default [
             {
                 path: 'file',
                 name: 'modelFile',
-                component: Dasboard,
-                // component: modelFile,
+                // component: Dasboard,
+                component: modelFile,
                 meta: { keepAlive: false, breadcrumbs: [{ label: '模型管理', path: '/model/file' }, { label: '模型文件管理' }] }
             },
             {
@@ -177,6 +205,30 @@ export default [
                 meta: { keepAlive: false, breadcrumbs: [{ label: '系统集成', path: '/point/pointsetting' }, { label: '配置动参从点位取值', path: '/point/dynamicdata' }, { label: '处理未对应实例对象标识' }] }
             },
             {
+                path: 'buildRela',
+                name: 'buildRela',
+                component: buildRela,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '系统集成', path: '/point/pointsetting' }, { label: '配置动参从点位取值', path: '/point/dynamicdata' }, { label: '处理未对应实例对象标识' }] }
+            },
+            {
+                path: 'floorRela',
+                name: 'floorRela',
+                component: floorRela,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '系统集成', path: '/point/pointsetting' }, { label: '配置动参从点位取值', path: '/point/dynamicdata' }, { label: '处理未对应实例对象标识' }] }
+            },
+            {
+                path: 'tenantRela',
+                name: 'tenantRela',
+                component: tenantRela,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '系统集成', path: '/point/pointsetting' }, { label: '配置动参从点位取值', path: '/point/dynamicdata' }, { label: '处理未对应实例对象标识' }] }
+            },
+            {
+                path: 'projectRela',
+                name: 'projectRela',
+                component: projectRela,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '系统集成', path: '/point/pointsetting' }, { label: '配置动参从点位取值', path: '/point/dynamicdata' }, { label: '处理未对应实例对象标识' }] }
+            },
+            {
                 path: 'objectdata',
                 name: 'objectData',
                 component: objectData,
@@ -196,36 +248,66 @@ export default [
         name: 'LayoutMain',
         component: LayoutMain,
         children: [
-            { path: '', name: 'buildData', component: buildData },
+            { path: '', name: 'buildTask', component: buildTask },
             {
                 path: 'task',
                 name: 'buildTask',
                 component: buildTask,
-                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor/task' }, { label: '现场任务管理' }] }
+                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor' }, { label: '现场任务管理' }] }
+            },
+            {
+                path: 'addDeviceTask',
+                name: 'addDeviceTask',
+                component: addDeviceTask,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor' }, { label: '现场任务管理', path: '/floor/task' }, { label: '现场验证设备台账' }] }
+            },
+            {
+                path: 'addAssetsTask',
+                name: 'addAssetsTask',
+                component: addAssetsTask,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor' }, { label: '现场任务管理', path: '/floor/task' }, { label: '现场验证资产台账' }] }
+            },
+            {
+                path: 'addModelTask',
+                name: 'addModelTask',
+                component: addModelTask,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor' }, { label: '现场任务管理', path: '/floor/task' }, { label: '现场验证模型' }] }
             },
             {
                 path: 'data',
                 name: 'buildData',
                 component: buildData,
-                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor/task' }, { label: '现场数据整理', path: '/floor/data' }, { label: '信息点整理' }] }
+                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor' }, { label: '现场数据整理', path: '/floor/data' }, { label: '信息点整理' }] }
             },
             {
                 path: 'plan',
                 name: 'buildGraphy',
                 component: buildGraphy,
-                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor/task' }, { label: '现场数据整理', path: '/floor/data' }, { label: '位置标签整理' }] }
+                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor' }, { label: '现场数据整理', path: '/floor/data' }, { label: '位置标签整理' }] }
             },
             {
                 path: 'abnormalprop',
                 name: 'buildAssets',
                 component: buildAssets,
-                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor/task' }, { label: '扫楼报告' }] }
+                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor' }, { label: '扫楼报告' }] }
             },
             {
                 path: 'log',
                 name: 'buildLog',
                 component: buildLog,
-                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor/task' }, { label: '扫楼日志查看' }] }
+                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor' }, { label: '扫楼日志查看' }] }
+            },
+            {
+                path: 'updatePointZone',
+                name: 'updatePointZone',
+                component: updatePointZone,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor' }, { label: '现场数据整理', path: '/floor/data' }, { label: '位置标签整理', path: '/floor/plan' }, { label: '维护业务空间信息' }] }
+            },
+            {
+                path: 'createPointZone',
+                name: 'createPointZone',
+                component: createPointZone,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '扫楼作业', path: '/floor' }, { label: '现场数据整理', path: '/floor/data' }, { label: '位置标签整理', path: '/floor/plan' }, { label: '创建业务空间' }] }
             }
         ]
     },
@@ -297,6 +379,12 @@ export default [
                 meta: { keepAlive: false, breadcrumbs: [{ label: '台账管理', path: '/ledger/facility' }, { label: '系统台账' }] }
             },
             {
+                path: 'systemDetail',
+                name: 'systemDetail',
+                component: systemDetail,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '台账管理', path: '/ledger/facility' }, { label: '系统台账', path: '/ledger/facility' }, { label: '系统详情' }] }
+            },
+            {
                 path: 'systemadd',
                 name: 'systemadd',
                 component: systemadd,
@@ -312,7 +400,7 @@ export default [
                 path: 'spaceDetail',
                 name: 'spaceDetail',
                 component: spaceDetail,
-                meta: { keepAlive: false, breadcrumbs: [{ label: '台账管理', path: '/ledger/facility' }, { label: '业务空间台账',path: '/ledger/spacelist' }, {label:'业务空间详情'}] }
+                meta: { keepAlive: false, breadcrumbs: [{ label: '台账管理', path: '/ledger/facility' }, { label: '业务空间台账', path: '/ledger/spacelist' }, { label: '业务空间详情' }] }
             },
             {
                 path: 'cenotelist',
@@ -331,6 +419,11 @@ export default [
                 name: 'cenoteDetail',
                 component: cenoteDetail,
                 meta: { keepAlive: false, breadcrumbs: [{ label: '台账管理', path: '/ledger/facility' }, { label: '竖井台账', path: '/ledger/cenotelist' }, { label: '竖井关系详情' }] }
+            }, {
+                path: 'relatedSpace',
+                name: 'relatedSpace',
+                component: relatedSpace,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '台账管理', path: '/ledger/facility' }, { label: '竖井台账', path: '/ledger/cenotelist' }, { label: '竖井关联的业务空间' }] }
             },
             {
                 path: 'rentlist',

+ 31 - 3
src/store/modules/project.js

@@ -1,9 +1,12 @@
+import { cacheDictionary } from "@/api/scan/request"
 const project_mess = {
     namespaced: true,
     state: {
         datasourceId: "", //数据源id
         protocolType: "", //数据源类型
-        dataName: ""
+        dataName: "",
+        dictionary: [], // 数据字典
+        cacheTime:''
     },
     mutations: {
         set_datasource(state, val) {
@@ -17,12 +20,37 @@ const project_mess = {
         }
     },
     actions: {
-
+        getDictionary({ state }){
+            let pa = ["Project", "Building", "Floor", "Equipment", "GeneralSystem", "Tenant", "Component", "Space"];
+            let firstLevelMap = {
+                Project: 'Pj',
+                Building: 'Bd',
+                Floor: 'Fl',
+                Tenant: 'VOTn',
+                Equipment: 'Eq',
+                GeneralSystem: 'Sy',
+                Space: 'Sp',
+                Component: 'Ec'
+            }
+            return new Promise((resolve,reject) => {
+                cacheDictionary(pa, res => {
+                    state.dictionary = res.Content.map(t => {
+                        t.InfoPointCode = firstLevelMap[t.InfoPointCode];
+                        return t;
+                    });
+                    let date = new Date();
+                    state.cacheTime = `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
+                    resolve(res);
+                })
+            })
+        }
     },
     getters: {
         datasourceId: state => state.datasourceId,
         protocolType: state => state.protocolType,
-        dataName: state => state.dataName
+        dataName: state => state.dataName,
+        dictionary: state => state.dictionary,
+        cacheTime: state => state.cacheTime
     }
 }
 

+ 29 - 2
src/utils/handsontable/mainText.js

@@ -62,9 +62,12 @@ const text = {
     //四大厂商
     idType: (instance, td, row, col, prop, value, cellProperties) => {
         let html = ''
+        let Manufacturer = instance.getDataAtRowProp(row,'LedgerParam.EquipManufactor.Manufacturer')?instance.getDataAtRowProp(row,'LedgerParam.EquipManufactor.Manufacturer'):'空',
+            Brand = instance.getDataAtRowProp(row,'LedgerParam.EquipManufactor.Brand')?instance.getDataAtRowProp(row,'LedgerParam.EquipManufactor.Brand'):'空',
+            Specification = instance.getDataAtRowProp(row,'LedgerParam.EquipManufactor.Specification')?instance.getDataAtRowProp(row,'LedgerParam.EquipManufactor.Specification'):'空';
         switch (prop){
             case 'DPManufacturerID':
-                html = instance.getDataAtRowProp(row,'LedgerParam.EquipManufactor.Specification') + '/' + instance.getDataAtRowProp(row,'LedgerParam.EquipManufactor.Brand')
+                html = Manufacturer + '/' + Brand + '/' + Specification
                 break;
             case 'DPSupplierID':
                 html = instance.getDataAtRowProp(row,'LedgerParam.SupplyPurchase.Supplier')
@@ -95,7 +98,31 @@ const text = {
         td.style.cursor = "pointer";
         td.innerHTML = "查看二维码"
         return td
-    }
+    },
+
+    //系统所属建筑楼层
+    sysInBuildFloor: (instance, td, row, col, prop, value, cellProperties) => {
+        td.style.color = "#409EFF";
+        td.style.cursor = "pointer";
+        if (value instanceof Array && value.length > 0) {
+            let text = ""
+            for (let i = 0; i < value.length; i++) {
+                if(value[i].BuildID && value[i].FloorID){
+                    text += `${value[i].BuildLocalName || value[i].BuildName}-${value[i].FloorLocalName || value[i].FloorName }、`
+                } else {
+                    text += `${value[i].BuildLocalName || value[i].BuildName}、`
+                }
+            }
+            text = text.substring(0,text.length-1);
+            if(text.length>15){
+                text = text.substring(0,15)+ "...";
+            }
+            td.innerHTML = text;
+        } else {
+            td.innerHTML = "无所属建筑楼层"
+        }
+        return td;
+    },
 }
 
 export default text

+ 1 - 1
src/utils/handsontable/notShow.js

@@ -305,7 +305,7 @@ const showTools = {
                         DataType: "Str",
                         FirstName: "基本信息",
                         InfoPointCode: "DPManufacturerID",
-                        InfoPointName: "品牌型号",
+                        InfoPointName: "生产厂家/品牌/型号",
                         InputMode: "X",
                         Path: "DPManufacturerID",
                         Priority: "S",

+ 26 - 0
src/utils/scan/directive.js

@@ -62,4 +62,30 @@ Vue.directive('load', function(el, binding) {
         // }
         el.src = imgDom.src
     }
+})
+//点击空白处隐藏div指令
+Vue.directive('clickOutside', {
+    // 初始化指令
+    bind(el, binding, vnode) {
+        function documentHandler(e) {
+            // 这里判断点击的元素是否是本身,是本身,则返回
+            if (el.contains(e.target)) {
+                return false;
+            }
+            // 判断指令中是否绑定了函数
+            if (binding.expression) {
+                // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法
+                binding.value(e);
+            }
+        }
+        // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
+        el.__vueClickOutside__ = documentHandler;
+        document.addEventListener('click', documentHandler);
+    },
+    update() {},
+    unbind(el, binding) {
+        // 解除事件监听
+        document.removeEventListener('click', el.__vueClickOutside__);
+        delete el.__vueClickOutside__;
+    },
 })

+ 4 - 0
src/utils/scan/tools.js

@@ -533,6 +533,10 @@ tools.setDataForKey = function (data, key, value) {
             if (i == arr.length - 1) {
                 data[arr[i]] = value
             }
+        } else {
+            if (i == arr.length - 1) {
+                data[arr[i]] = ''
+            }
         }
         data = data[arr[i]]
       }

+ 10 - 0
src/utils/spaceColor.js

@@ -0,0 +1,10 @@
+export const colorArr = [
+  "#fed44c",
+  "#3485d6",
+  "#a384fc",
+  "#4caf50",
+  "#ff6316",
+  "#fd8bbe",
+  "#03a9f3",
+  "#ea615b"
+];

+ 27 - 0
src/utils/tools.js

@@ -34,4 +34,31 @@ tools.deepCopy = (obj) => {
     return temp
 }
 
+//判断watch监听的值是否相同
+tools.isSimilarly = (newValue, oldValue) => {
+    if(typeof newValue === typeof oldValue){
+        if(newValue === oldValue){
+            return true
+        } else {
+            let flag = false
+            try {
+                Object.keys(newValue).forEach((item, index, arr) => {
+                    if(oldValue.hasOwnProperty(item) && newValue[item] === oldValue[item]){
+                        if(index == arr.length-1){
+                            flag = true
+                        }
+                    } else {
+                        throw new Error()
+                    }
+                })
+            } catch (error) {
+                return false
+            }
+            return flag
+        }
+    } else {
+        return false
+    }
+}
+
 export default tools

+ 161 - 0
src/views/business_space/dataUtil/index2.vue

@@ -0,0 +1,161 @@
+<template>
+  <div class="main-box">
+    <div class="saga-build-mess">
+      <el-button @click="queryZone">导入业务空间BIMLocation</el-button>
+    </div>
+  </div>
+</template>
+<script>
+import {
+  queryZone,
+  updateZone,
+} from "@/api/scan/request";
+import { mapGetters } from "vuex";
+import pako from '@/assets/pako/pako'
+import axios from "axios";
+export default {
+  data() {
+    return {
+      options: [],
+      tabsList: [
+        {
+          "Code": "GeneralZone",
+          "Name": "默认分区",
+          "Rel_type": "99"
+        },
+        {
+          "Name": "供电分区",
+          "Rel_type": "1",
+          "Code": "PowerSupplyZone"
+        },
+        {
+          "Name": "照明分区",
+          "Rel_type": "2",
+          "Code": "LightingZone"
+        },
+        {
+          "Name": "网络分区",
+          "Rel_type": "3",
+          "Code": "NetworkZone"
+        },
+        {
+          "Code": "AirConditioningZone",
+          "Name": "空调分区",
+          "Rel_type": "4"
+        },
+        {
+          "Name": "采暖分区",
+          "Rel_type": "5",
+          "Code": "HeatingZone"
+        },
+        {
+          "Name": "洁净分区",
+          "Rel_type": "6",
+          "Code": "CleanZone"
+        },
+        {
+          "Name": "生活给水分区",
+          "Rel_type": "7",
+          "Code": "DomesticWaterSupplyZone"
+        },
+        {
+          "Code": "FireZone",
+          "Name": "防火分区",
+          "Rel_type": "8"
+        },
+        {
+          "Name": "安防分区",
+          "Rel_type": "9",
+          "Code": "SecurityZone"
+        },
+        {
+          "Name": "租户分区",
+          "Rel_type": "10",
+          "Code": "TenantZone"
+        },
+        {
+          "Name": '功能分区',
+          'Rel_type': '11',
+          "Code": 'FunctionZone'
+        }
+      ],
+    }
+  },
+  computed: {
+    ...mapGetters('layout', ['projectId', 'userId', 'secret'])
+  },
+  methods: {
+    init() { },
+    // 查询该项目下所有的业务空间
+    queryZone() {
+      this.tabsList.map(t => {
+        this.getZone(t.Code, 1, t.Name);
+      })
+    },
+    getZone(Code, PageNumber, Name) {
+      let pa = {
+        data: {
+          PageNumber: PageNumber,
+          PageSize: 1000,
+          Orders: 'RoomID asc'
+        },
+        zone: Code
+      }
+      queryZone(pa, res => {
+        if (res.Total > PageNumber * 1000) {
+          let num = PageNumber + 1
+          console.log(num)
+          this.getZone(Code, num, Name)
+        }
+        let params = {
+          data: {
+            Content: [],
+            Projection: ["BIMLocation"]
+          },
+          zone: Code
+        }
+        res.Content.map(t => {
+          if (t.Outline && t.Outline[0]) {
+            t.BIMLocation = this.getAverageVal(t.Outline);
+            let obj = {
+              RoomID: t.RoomID,
+              BIMLocation: t.BIMLocation
+            }
+            params.data.Content.push(obj);
+          }
+        });
+        if (params.data.Content.length) {
+          updateZone(params, res => {
+            console.log(`${this.projectId},${Name},${params.data.Content.length}条更新完成`);
+          })
+        }
+      })
+    },
+    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}`
+    },
+  },
+  created() {
+    this.init()
+  },
+  watch: {
+    projectId() {
+      this.init()
+    }
+  }
+}
+</script>

+ 24 - 64
src/views/data_admin/buildData/index.vue

@@ -7,12 +7,12 @@
             <!-- 建筑选择 -->
             <span style="padding-right:12px;color:#999;vertical-align: middle;">建筑名称</span>
             <el-select v-model="buildId" style="margin-right:10px;" placeholder="请选择" @change="changeBuild">
-                <el-option v-for="item in buildList" :key="item.BuildId" :label="item.BuildLocalName" :value="item.BuildId"></el-option>
+                <el-option v-for="item in buildList" :key="item.BuildID" :label="item.BuildLocalName" :value="item.BuildID"></el-option>
             </el-select>
             <!-- 楼层选择 -->
             <span style="padding-right:12px;color:#999;">楼层</span>
             <el-select v-model="floorId" placeholder="请选择" @change="changeFloor">
-                <el-option v-for="item in floorList" :key="item.FloorId" :label="item.FloorLocalName" :value="item.FloorId"></el-option>
+                <el-option v-for="item in floorList" :key="item.FloorID" :label="item.FloorLocalName" :value="item.FloorID"></el-option>
             </el-select>
             <!-- 选择时间插件 -->
             <build-time :timeArr="timeArr" @checkTime="checkTime"></build-time>
@@ -332,6 +332,8 @@
         defaultFloor, //获取默认楼层
         getdelMain, //获取过滤掉后的表格主体
         getBasicMatch, //获取完全匹配的厂商库id
+        buildingQuery, //数据中心-建筑查询
+        floorQuery, //数据中心-楼层查询
     } from "@/api/scan/request";
     import { mapGetters, mapActions } from "vuex"
     export default {
@@ -596,20 +598,8 @@
             },
             //获取建筑列表
             getBuilding() {
-                let param = {
-                    ProjId: this.projectId,
-                    UserId: this.userId
-                };
-                getBuildSelect(param).then(result => {
-                    if (result.data.Result == "success" && result.data.BuildList) {
-                        this.buildList = result.data.BuildList;
-                        //获取建筑下列数据后请求默认楼层建筑数据
-                        this.getDefaultFloor();
-                    } else {
-                        // this.dialogVisible = true;
-                        // this.ajaxMsg = "请求出错";
-                        this.$message.error("请求出错")
-                    }
+                buildingQuery({}, res => {
+                    this.buildList = res.Content;
                 });
             },
             //获取点位标签详情
@@ -684,21 +674,23 @@
                 }
                 return list;
             },
-            //获取默认楼层
-            getDefaultFloor() {
+            //获取楼层列表
+            getFloorData() {
                 let param = {
-                    ProjId: this.projectId,
-                    UserId: this.userId
+                    Filters: `BuildID='${this.buildId}'`,
+                    Orders: 'FloorSequenceID desc'
                 };
-                defaultFloor(param).then(result => {
-                    //将默认建筑id赋予标签绑定
-                    // this.buildId = result.data.BuildId;
-                    //存储默认楼层,等待楼层下拉列表出现后赋予
-                    // this.defaultFloorData = result.data.FloorId;
-                    //请求楼层下拉数据
-                    if (this.buildId) {
-                        this.getFloorData();
-                    }
+                floorQuery(param, res => {
+                    this.floorList = res.Content
+                    this.floorList.unshift({
+                    FloorName: "全部",
+                    FloorLocalName: "全部",
+                    FloorID: "all"
+                    }, {
+                        FloorName: "未明确楼层",
+                        FloorLocalName: "未明确楼层",
+                        FloorID: "noKnow"
+                    })
                 });
             },
             //保存点位标签详情的修改
@@ -744,41 +736,6 @@
                     }
                 });
             },
-            //获取楼层列表
-            getFloorData() {
-                let param = {
-                    BuildId: this.buildId,
-                    ProjId: this.projectId,
-                    UserId: this.userId
-                };
-                getFloor(param).then(res => {
-                    if (res.data.Result == "success") {
-                        this.floorList = tools.sortArr(res.data.FloorList, "FloorSequenceId", false);
-                        // this.floorId = this.defaultFloorData;
-                        for (let i = 0; i < this.floorList.length; i++) {
-                            if (this.floorId == this.floorList[i].FloorId) {
-                                this.floorName = this.floorList[i].FloorLocalName;
-                            }
-                        }
-                        this.floorList.unshift({
-                            FloorName: "全部",
-                            FloorLocalName: "全部",
-                            FloorId: "all"
-                        },{
-                            FloorName: "未明确楼层",
-                            FloorLocalName: "未明确楼层",
-                            FloorId: "noKnow"
-                        })
-                        if (this.defaultFloorData) {
-                            this.getPT();
-                        }
-                    } else {
-                        // this.dialogVisible = true;
-                        // this.ajaxMsg = "请求出错";
-                        this.$message.error("请求出错")
-                    }
-                });
-            },
             //保存设备资产的更新
             upDateTableMain(paramList) {
                 let param = {
@@ -1496,6 +1453,9 @@
             },
             //创建表格实例
             createHot(variableNum, data, headerArr) {
+                if(!headerArr){
+                    return
+                }
                 let maxRow = "";
                 //当当前页数*当前页个数小于总个数时,当前表格行数为当前页数
                 if (

+ 214 - 0
src/views/data_admin/buildGraphy/createPointZone.vue

@@ -0,0 +1,214 @@
+<template>
+  <div id="createPoint">
+    <div class="condition">
+      <div class="header">
+        <el-button style="float:left;" size="small" type="default" icon="el-icon-back" @click="goBack"></el-button>
+        <el-button size="small" style="float:right" @click="createZ">创建</el-button>
+      </div>
+      <el-scrollbar style="height:calc(100% - 43px)">
+        <div class="item">
+          <span>基本信息:</span>
+          <div>
+            <label><span style="color:red;">*</span>业务空间名称</label>
+            <el-input placeholder="请输入业务空间名称" v-model="RoomLocalName" clearable style="width:215px;margin-right:10px;"></el-input>
+            <label>业务空间编码</label>
+            <el-input placeholder="请输入业务空间编码" v-model="RoomLocalID" clearable style="width:215px;margin-right:10px;"></el-input>
+          </div>
+          <div>
+            <label><span style="color:red;">*</span>所属建筑楼层</label>
+            <el-cascader placeholder='请选择' v-model="buildFloor" :options="options" :props="floorProps" filterable ref="buildfloor"
+              style="width:215px;margin-right:10px;"></el-cascader>
+            <label><span style="color:red;">*</span>业务空间类型</label>
+            <el-select v-model="space" placeholder="请选择空间" style="width:215px;margin-right:10px;" @change="changeSpace">
+              <el-option v-for="item in spaceList" :key="item.Code" :label="item.Name" :value="item.Code">
+              </el-option>
+            </el-select>
+          </div>
+        </div>
+        <div class="item">
+          <span>其它可补充信息:</span>
+          <i style="cursor: pointer;" :class="showEx"
+            @click="showEx = (showEx == 'el-icon-arrow-up' ? 'el-icon-arrow-down' : 'el-icon-arrow-up')"></i>
+          <div v-show="showEx == 'el-icon-arrow-up'" v-loading="loadingOtherMsg">
+            <zoneInput v-show="otherList.length" :inputList="otherList" labelWidth="140px" ref="zoneInput"></zoneInput>
+            <p v-show="!otherList.length">请选择业务空间类型</p>
+          </div>
+        </div>
+        <div class="item">
+          <p>位置标签图片信息:</p>
+          <locationPointMsg ref="pointMsg" :pointObj="$route.params.item"></locationPointMsg>
+        </div>
+      </el-scrollbar>
+    </div>
+  </div>
+</template>
+
+<script>
+import locationPointMsg from '@/views/data_admin/buildGraphy/locationPointMsg'
+import { queryDictionaryHead, getDataDictionary, createZone } from '@/api/scan/request';
+import { mapGetters } from 'vuex'
+import zoneInput from '@/components/data_admin/zoneInput'
+export default {
+  data() {
+    return {
+      floorProps: {
+        value: 'BuildID',
+        label: 'BuildLocalName',
+        children: 'Floor'
+      },
+      options: [],//建筑楼层
+      spaceList: [],//空间列表
+      space: '',//当前空间
+      buildFloor: [],//建筑楼层信息
+      zoneName: '',//业务空间名称
+      zoneLocalId: '',//业务空间编码
+      showEx: 'el-icon-arrow-down',//下拉菜单
+      RoomLocalID: '',//业务空间本地编码
+      RoomLocalName: '',//业务空间名称
+      otherList: [],//可补充信息list
+      loadingOtherMsg: false,
+    }
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  props: {
+
+  },
+  components: {
+    locationPointMsg,
+    zoneInput
+  },
+  created() {
+    this.options = this.$route.params.floorData
+    this.getSpaceList();
+  },
+  methods: {
+    //创建
+    createZ() {
+      let param = {
+        zone: '',
+        data: {
+          content: []
+        }
+      }
+      let zObj = this.$refs.zoneInput.getFormData();
+      zObj.Pic = this.$refs.pointMsg.choImg.concat();
+      zObj.Pic = zObj.Pic.map(item => ({
+        Id: item.ObjectId,
+        Key: item.Key,
+        Name: item.Name,
+        Type: item.Type
+      }))
+      if (this.RoomLocalName && this.buildFloor.length && this.space) {
+        zObj.RoomLocalName = this.RoomLocalName;
+        zObj.RoomLocalID = this.RoomLocalID;
+        zObj.BuildingId = this.buildFloor[0];
+        zObj.FloorId = this.buildFloor[1];
+        param.zone = this.space;
+        param.data.content = [zObj];
+        createZone(param, res => {
+          this.$message.success("创建成功");
+          this.$refs.pointMsg.clearImg();
+          this.RoomLocalName = ''
+          this.RoomLocalID = ''
+          this.buildFloor = []
+          this.space = ''
+          this.otherList = []
+        })
+      }
+      else if (!this.RoomLocalName) {
+        this.$message("请输入业务空间名称");
+      }
+      else if (!this.buildFloor.length) {
+        this.$message("请选择所属建筑楼层");
+      }
+      else {
+        this.$message("请选择业务空间类型");
+      }
+    },
+    //获取空间列表
+    getSpaceList() {
+      let pa = {
+        Filters: `parentId='Space'`
+      }
+      queryDictionaryHead(pa, res => {
+        this.spaceList = res.Content.filter((item => { return item.Name != '元空间' }));
+      });
+    },
+    //选择业务空间
+    changeSpace(val) {
+      this.space = val;
+      let pa = {
+        type: this.space,
+        data: {
+          "Orders": "sort asc", "PageNumber": 1, "PageSize": 500
+        }
+      };
+      this.loadingOtherMsg = true;
+      getDataDictionary(pa, res => {
+        this.loadingOtherMsg = false;
+        let filterCode = ["RoomLocalID", "RoomLocalName"]
+        res.Content = res.Content.filter(item => {
+          item.inputValue = null;
+          return filterCode.indexOf(item.InfoPointCode) == -1
+        });
+        this.otherList = res.Content;
+        this.$refs.zoneInput.init(this.otherList);
+      })
+    },
+    //返回
+    goBack() {
+      this.$router.push({
+        name: "buildGraphy",
+        params: { nowBuildFloor: this.$route.params.nowBuildFloor }
+      })
+    }
+  },
+  watch: {
+    projectId: {
+      handler(val) {
+        this.goBack();
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.condition {
+  position: relative;
+  padding: 10px 10px;
+  display: flex;
+  height: calc(100% - 22px);
+  flex-direction: column;
+  border: 1px solid #dfe6ec;
+  background: #fff;
+  .header {
+    padding-bottom: 10px;
+    border-bottom: 1px solid rgba(0, 0, 0, 0.5);
+    span {
+      line-height: 33px;
+      margin-left: 15px;
+    }
+    /deep/ .buildFloor {
+      line-height: 32px;
+    }
+  }
+}
+/deep/ .el-scrollbar__wrap {
+  overflow-x: hidden;
+}
+.item {
+  padding: 10px 10px;
+  label {
+    display: inline-block;
+    padding: 5px 10px;
+    width: 130px;
+  }
+}
+.suppMsg {
+  display: inline-block;
+  position: relative;
+}
+</style>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 349 - 909
src/views/data_admin/buildGraphy/graphyCanvas.vue


+ 481 - 452
src/views/data_admin/buildGraphy/graphyTabs.vue

@@ -3,49 +3,51 @@ setFalg 插旗事件
 getLocation 定位
 -->
 <template>
-    <div id="graphy-tabs">
-        <el-tabs style="height:100%;" v-model="activeName2" type="card" @tab-click="handleClick">
-            <el-tab-pane label="本层的点位标签" name="point">
-                <div v-if="pointData.length" v-loading="isLoading" style="max-height: 600px;overflow-y:auto;">
-                    <div v-for="(item,index) in pointData" :key="index">
-                        <div class="point">
-                            <span>{{item.Name}}</span>
-                            <el-button size="mini" @click="getDetails(item)">编辑点位标签</el-button>
-                            <el-button :disabled="!map" size="mini" @click="btnClick(item)">{{ item.X == 0 && item.Y == 0 ? '插旗' : '定位'}}</el-button>
-                        </div>
-                    </div>
-                </div>
-                <div v-if="!pointData.length" class="center" style="height: 400px;padding-top: 260px; box-sizing:border-box;">
-                    <i class="icon-wushuju iconfont"></i>
-                    {{pointParam.FloorId ? "数据为空" : "请选择楼层"}}
-                </div>
+  <div id="graphy-tabs">
+    <el-tabs style="height:100%;" v-model="activeName2" type="card" @tab-click="handleClick">
+      <el-tab-pane label="本层的点位标签" name="point" style="height:100%">
+        <el-scrollbar style="height:100%;width:calc(100% - 10px);" v-if="pointData.length" v-loading="isLoading">
+          <div v-for="(item,index) in pointData" :key="index">
+            <div class="point">
+              <span style="line-height:30px;">{{item.Name}}</span>
+              <div style="height:30px;float:right;font-size:14px;">
+                <el-button size="mini" @click="getDetails(item)" icon="el-icon-edit-outline"></el-button>
+                <el-button size="mini" @click="updateOrCreate(item)" icon="el-icon-link"></el-button>
+                <el-button :disabled="!map" size="mini" @click="btnClick(item)"
+                  :icon="item.X == 0 && item.Y == 0 ? 'el-icon-s-flag' : 'el-icon-place'"></el-button>
+              </div>
+            </div>
+          </div>
+        </el-scrollbar>
+
+        <div v-if="!pointData.length" class="center" style="height: 400px;padding-top: 260px; box-sizing:border-box;">
+          <i class="icon-wushuju iconfont"></i>
+          {{pointParam.FloorId ? "数据为空" : "请选择楼层"}}
+        </div>
       </el-tab-pane>
       <el-tab-pane label="无法定位到楼层的点位标签" name="noPoint">
-            <div v-if="pointNoData.length" v-loading="isLoading" style="max-height: 600px;">
-                <div v-for="(item,index) in pointNoData" :key="index">
-                    <div class="point">
-                    <span>{{item.Name}}</span>
-                    <el-button @click="getDetails(item)">编辑点位标签</el-button>
-                    <el-button
-                        :disabled="!(item.X == 0 && item.Y == 0)"
-                        @click="btnClick(item)"
-                    >{{ item.X == 0 && item.Y == 0 ? '插旗' : '定位'}}</el-button>
-                </div>
-            </div>
+        <div v-if="pointNoData.length" v-loading="isLoading" style="max-height: 600px;">
+          <div v-for="(item,index) in pointNoData" :key="index">
+            <div class="point">
+              <span>{{item.Name}}</span>
+              <el-button size="mini" @click="getDetails(item)" icon="el-icon-edit-outline"></el-button>
+              <el-button :disabled="true" size="mini" @click="btnClick(item)"
+                  :icon="item.X == 0 && item.Y == 0 ? 'el-icon-s-flag' : 'el-icon-place'"></el-button>
             </div>
-            <div v-if="!pointNoData.length" class="center" style="height: 400px;padding-top: 260px; box-sizing:border-box;">
-                <i class="icon-wushuju iconfont"></i>
-                {{pointParam.FloorId ? "数据为空" : "请选择楼层"}}
-            </div>
-        </el-tab-pane>
+          </div>
+        </div>
+        <div v-if="!pointNoData.length" class="center" style="height: 400px;padding-top: 260px; box-sizing:border-box;">
+          <i class="icon-wushuju iconfont"></i>
+          {{pointParam.FloorId ? "数据为空" : "请选择楼层"}}
+        </div>
+      </el-tab-pane>
     </el-tabs>
     <el-dialog title="详情" :visible.sync="pointShow" width="500px">
       <div class="qrcode">
         <div class="qrcode-view">
           <img
             :src="'/ScanBuilding/service/qrcode/point?projectId=' + projectId + '&pointId=' + pointDetails.PointId + '&FloorId=' + pointDetails.FloorId + '&width=200&height=200'"
-            alt="点位标签二维码"
-          >
+            alt="点位标签二维码">
         </div>
         <div class="point-edit">
           <p>
@@ -54,22 +56,10 @@ getLocation 定位
             -({{pointDetails.X}},{{pointDetails.Y}})
           </p>
           <div>
-            <form-input
-              :width="100"
-              @change="changeInput"
-              :value="pointDetails.PointName"
-              :keys="'PointName'"
-              :label="'点位标签'"
-              :isRule="false"
-            ></form-input>
-            <form-input
-              :width="100"
-              @change="changeInput"
-              :value="pointDetails.PointLocalId"
-              :keys="'PointLocalId'"
-              :label="'点位本地编码'"
-              :isRule="false"
-            ></form-input>
+            <form-input :width="100" @change="changeInput" :value="pointDetails.Name" :keys="'Name'" :label="'点位标签'" :isRule="false">
+            </form-input>
+            <form-input :width="100" @change="changeInput" :value="pointDetails.LocalId" :keys="'LocalId'" :label="'点位本地编码'"
+              :isRule="false"></form-input>
             <!-- <form-input></form-input> -->
           </div>
         </div>
@@ -97,66 +87,59 @@ getLocation 定位
           <li>
             <span>备注</span>
             <span>
-              <form-input
-                :width="0"
-                @change="changeInput"
-                :value="pointDetails.Note"
-                :keys="'Note'"
-                :label="''"
-                :isRule="false"
-              ></form-input>
+              <form-input :width="0" @change="changeInput" :value="pointDetails.Note" :keys="'Note'" :label="''" :isRule="false"></form-input>
             </span>
           </li>
         </ul>
       </div>
       <div class="point-pic">
-            <p>点位安装位置效果照片</p>
-            <template v-for="(item,index) in installPic">
-                <div class="point-image" :key="index">
-                    <i class="el-icon-delete" @click="delImage(index,installPic)"></i>
-                    <img :src="'/image-service/common/image_get?systemId=dataPlatform&key='+ item.key +'&width=200&height=200'" alt>
-                </div>
-            </template>
-            <load-img keyName="安装位置" @getKey="getKey"></load-img>
-        </div>
-        <div class="point-pic">
-            <p>全景照片</p>
-            <template v-for="(item,index) in panorama">
-                <div class="point-image" :key="index">
-                    <i class="el-icon-delete" @click="delImage(index,panorama)"></i>
-                    <img :src="'/image-service/common/image_get?systemId=dataPlatform&key='+ item.key +'&width=200&height=200'" alt>
-                </div>
-            </template>
-            <load-img keyName="全景照片" @getKey="getKey"></load-img>
-        </div>
-        <div class="point-pic">
-            <p>周边照片</p>
-            <template v-for="(item,index) in rimPic">
-                <div class="point-image" :key="index">
-                    <i class="el-icon-delete" @click="delImage(index,rimPic)"></i>
-                    <img :src="'/image-service/common/image_get?systemId=dataPlatform&key='+ item.key +'&width=200&height=200'" alt>
-                </div>
-            </template>
-            <load-img keyName="周边照片" @getKey="getKey"></load-img>
-        </div>
-        <div class="point-pic">
-            <p>视频资料</p>
-            <template v-for="(item,index) in videoPic">
-                <div class="point-image" :key="index">
-                    <i class="el-icon-delete" @click="delImage(index,videoPic)"></i>
-                    <img :src="'/image-service/common/image_get?systemId=dataPlatform&key='+ item.key +'&width=200&height=200'" alt>
-                </div>
-            </template>
-            <load-img keyName="视频" @getKey="getKey"></load-img>
-        </div>
-        <div class="point-pic">
-            <p>其他照片</p>
-            <template v-for="(item,index) in elsePic">
-                <div class="point-image" :key="index">
-                    <i class="el-icon-delete" @click="delImage(index,elsePic)"></i>
-                    <img :src="'/image-service/common/image_get?systemId=dataPlatform&key='+ item.key +'&width=200&height=200'" alt>
-                </div>
-            </template>
+        <p>点位安装位置效果照片</p>
+        <template v-for="(item,index) in installPic">
+          <div class="point-image" :key="index">
+            <i class="el-icon-delete" @click="delImage(index,installPic)"></i>
+            <img :src="'/image-service/common/image_get?systemId=dataPlatform&key='+ item.Key +'&width=200&height=200'" alt>
+          </div>
+        </template>
+        <load-img keyName="安装位置" @getKey="getKey"></load-img>
+      </div>
+      <div class="point-pic">
+        <p>全景照片</p>
+        <template v-for="(item,index) in panorama">
+          <div class="point-image" :key="index">
+            <i class="el-icon-delete" @click="delImage(index,panorama)"></i>
+            <img :src="'/image-service/common/image_get?systemId=dataPlatform&key='+ item.Key +'&width=200&height=200'" alt>
+          </div>
+        </template>
+        <load-img keyName="全景照片" @getKey="getKey"></load-img>
+      </div>
+      <div class="point-pic">
+        <p>周边照片</p>
+        <template v-for="(item,index) in rimPic">
+          <div class="point-image" :key="index">
+            <i class="el-icon-delete" @click="delImage(index,rimPic)"></i>
+            <img :src="'/image-service/common/image_get?systemId=dataPlatform&key='+ item.Key +'&width=200&height=200'" alt>
+          </div>
+        </template>
+        <load-img keyName="周边照片" @getKey="getKey"></load-img>
+      </div>
+      <div class="point-pic">
+        <p>视频资料</p>
+        <template v-for="(item,index) in videoPic">
+          <div class="point-image" :key="index">
+            <i class="el-icon-delete" @click="delImage(index,videoPic)"></i>
+            <img :src="'/image-service/common/image_get?systemId=dataPlatform&key='+ item.Key +'&width=200&height=200'" alt>
+          </div>
+        </template>
+        <load-img keyName="视频" @getKey="getKey"></load-img>
+      </div>
+      <div class="point-pic">
+        <p>其他照片</p>
+        <template v-for="(item,index) in elsePic">
+          <div class="point-image" :key="index">
+            <i class="el-icon-delete" @click="delImage(index,elsePic)"></i>
+            <img :src="'/image-service/common/image_get?systemId=dataPlatform&key='+ item.Key +'&width=200&height=200'" alt>
+          </div>
+        </template>
         <load-img keyName="其他照片" @getKey="getKey"></load-img>
       </div>
     </el-dialog>
@@ -164,360 +147,406 @@ getLocation 定位
 </template>
 
 <script>
-    import {
-        getPT, //获取点位列表
-        getPoint, //获取点位详情
-        updatePoint //修改点位
-    } from "@/api/scan/request";
-    import formInput from "./lib/formInput";
-    import loadImg from "./lib/uploadImg";
-    import {
-        mapGetters,
-        mapActions
-    } from 'vuex';
-    export default {
-        props: {
-            pointParam: {
-                type: Object
-            }
-        },
-        components: {
-            formInput,
-            loadImg
-        },
-        data() {
-            return {
-                activeName2: "point",
-                pointData: [], //tab为本层的点位标签
-                pointNoData: [], //tab为无法定位的点位标签
-                pointShow: false, //标签详情的弹窗
-                pointDetails: {}, //标签详情信息对象
-                // projId: this.$route.query.projId,
-                index: "",
-                installPic: [], //安装位置
-                panorama: [], //全景照片
-                rimPic: [], //周边照片
-                videoPic: [], //视频资料
-                elsePic: [], //其他照片
-                map: true
-            };
-        },
-        computed: {
-            ...mapGetters('layout', ['projectId', 'secret', 'userId'])
-        },
-        methods: {
-            //tabs被点击
-            handleClick(tab, event) {
-                this.index = tab.index;
-                this.getPointList();
-            },
-            //修改input
-            changeInput(val, key) {
-                this.pointDetails[key] = val;
-                this.updatePoint();
-            },
-            //删除图片
-            delImage(index, arr) {
-                arr.splice(index, 1);
-                this.updatePoint();
-            },
-            //获取key的值
-            getKey(val, name) {
-                switch (name) {
-                    case "安装位置":
-                        this.installPic.push({
-                            key: val,
-                            name: name,
-                            type: "image_wz"
-                        });
-                        break;
-                    case "全景照片":
-                        this.panorama.push({
-                            key: val,
-                            name: name,
-                            type: "panorama"
-                        });
-                        break;
-                    case "周边照片":
-                        this.rimPic.push({
-                            key: val,
-                            name: name,
-                            type: "image_zb"
-                        });
-                        break;
-                    case "视频":
-                        this.videoPic.push({
-                            key: val,
-                            name: name,
-                            type: "video"
-                        });
-                        break;
-                    default:
-                        this.elsePic.push({
-                            key: val,
-                            name: name,
-                            type: "image_else"
-                        });
-                }
-                this.updatePoint();
-            },
-            btnClick(item) {
-                if (item.X == 0 && item.Y == 0) {
-                    this.$emit("setFalg", item);
-                } else {
-                    this.$emit("getLocation", item);
-                }
-            },
-            mapPush(detailsArr, pic) {
-                pic.map(item => {
-                    detailsArr.push(item);
-                });
-            },
-            //修改详情
-            updatePoint() {
-                this.pointDetails.ImageList = [];
-                this.mapPush(this.pointDetails.ImageList, this.installPic);
-                this.mapPush(this.pointDetails.ImageList, this.panorama);
-                this.mapPush(this.pointDetails.ImageList, this.rimPic);
-                this.mapPush(this.pointDetails.ImageList, this.videoPic);
-                this.mapPush(this.pointDetails.ImageList, this.elsePic);
-                let param = {
-                    ProjId: this.pointParam.ProjId,
-                    UserId: this.pointParam.UserId,
-                    PointList: this.pointDetails
-                };
-                updatePoint(param).then(res => {
-                    this.$message.success("修改成功");
-                });
-            },
-            getDetails(item) {
-                let params = {
-                    ProjId: this.projectId,
-                    UserId: this.userId,
-                    PointId: item.Id
-                };
-                getPoint(params).then(res => {
-                    let data = res.data;
-                    if (data.Result == "success") {
-                        this.pointShow = true;
-                        this.pointDetails = data.PointList[0];
-                        this.getPic(data.PointList[0].ImageList);
-                    } else {
-                        this.$message.error("请求出错");
-                    }
-                });
-            },
-            getPic(imgArr) {
-                this.installPic = [];
-                this.panorama = [];
-                this.rimPic = [];
-                this.videoPic = [];
-                this.elsePic = [];
-                imgArr.map((item, index) => {
-                    switch (item.name) {
-                        case "安装位置":
-                            this.installPic.push(item);
-                            break;
-                        case "全景照片":
-                            this.panorama.push(item);
-                            break;
-                        case "周边照片":
-                            this.rimPic.push(item);
-                            break;
-                        case "视频":
-                            this.videoPic.push(item);
-                            break;
-                        default:
-                            this.elsePic.push(item);
-                    }
-                });
-            },
-            //获取point
-            getPointList() {
-                this.isLoading = true;
-                if (this.pointParam.FloorId) {
-                    let param = {
-                        FloorId: this.pointParam.FloorId,
-                        ProjId: this.pointParam.ProjId,
-                        UserId: this.pointParam.UserId
-                    };
-                    console.log(param)
-                    //当index为1时FloorId为空
-                    if (this.index == "1") {
-                        param.FloorId = "";
-                    }
-                    getPT(param).then(res => {
-                        res.data.PointList.splice(0, 1);
-                        if (this.index == "1") {
-                            this.pointNoData = res.data.PointList;
-                        } else {
-                            this.$emit("getPointList", res.data.PointList);
-                            this.pointData = res.data.PointList;
-                        }
-                        this.isLoading = false;
-                    });
-                }
-            },
-            //初始化
-            reset(data, map) {
-                this.map = map
-                this.pointParam.FloorId = data.FloorId;
-                this.pointParam.fllorName = data.fllorName;
-                this.activeName2 = "point";
-                this.getPointList();
-            }
-        },
-        watch: {
-            pointShow: {
-                deep: true,
-                handler: function(old, val) {
-                    if (old == false && val == true) {
-                        this.getPointList();
-                    }
-                }
-            },
-            projectId(){
-                this.pointData= []
-                this.pointNoData= []
-                this.activeName2 = "point"
-            }
-        }
+import {
+  locationPointQuery, //获取点位列表
+  getPoint, //获取点位详情
+  updateLocationPoint, //修改点位
+  deleteLocationImg,//数据中心删除图片
+} from "@/api/scan/request";
+import formInput from "./lib/formInput";
+import loadImg from "./lib/uploadImg";
+import {
+  mapGetters,
+  mapActions
+} from 'vuex';
+export default {
+  props: {
+    pointParam: {
+      type: Object
+    },
+    floorOption: {//建筑楼层
+      Type: Array,
+      default: () => []
+    },
+  },
+  components: {
+    formInput,
+    loadImg
+  },
+  data() {
+    return {
+      activeName2: "point",
+      pointData: [], //tab为本层的点位标签
+      pointNoData: [], //tab为无法定位的点位标签
+      pointShow: false, //标签详情的弹窗
+      pointDetails: {}, //标签详情信息对象
+      // projId: this.$route.query.projId,
+      index: "",
+      installPic: [], //安装位置
+      panorama: [], //全景照片
+      rimPic: [], //周边照片
+      videoPic: [], //视频资料
+      elsePic: [], //其他照片
+      map: true,
+      buildingData: [],//建筑楼层信息
     };
-</script>
-
-<style lang="scss" scoped>
-    #graphy-tabs {
-        height: 100%;
-        border-left: 1px solid #E4E7ED;
-        .el-tabs__content {
-            height: calc(100% - 60px) !important;
-            background: red;
-        }
-        .el-dialog__body{
-            max-height: 400px;
+  },
+  computed: {
+    ...mapGetters('layout', ['projectId', 'secret', 'userId'])
+  },
+  methods: {
+    //tabs被点击
+    handleClick(tab, event) {
+      this.index = tab.index;
+      this.getPointList();
+    },
+    //修改input
+    changeInput(val, key) {
+      this.pointDetails[key] = val;
+      this.updatePoint();
+    },
+    //删除图片
+    delImage(index, arr) {
+      let delArr = arr.splice(index, 1);
+      deleteLocationImg(delArr, res => {
+        this.$message.success("修改成功");
+      })
+    },
+    //获取key的值
+    getKey(val, name) {
+      switch (name) {
+        case "安装位置":
+          this.installPic.push({
+            Key: val,
+            name: name,
+            type: "image_wz"
+          });
+          break;
+        case "全景照片":
+          this.panorama.push({
+            Key: val,
+            name: name,
+            type: "panorama"
+          });
+          break;
+        case "周边照片":
+          this.rimPic.push({
+            Key: val,
+            name: name,
+            type: "image_zb"
+          });
+          break;
+        case "视频":
+          this.videoPic.push({
+            Key: val,
+            name: name,
+            type: "video"
+          });
+          break;
+        default:
+          this.elsePic.push({
+            Key: val,
+            name: name,
+            type: "image_else"
+          });
+      }
+      this.updatePoint();
+    },
+    //创建或更新
+    updateOrCreate(item) {
+      this.$confirm('更新:将位置标签图片填充到已有的业务空间中<br>创建:新建业务空间,并将位置标签图片和信息填充到新业务空间中', '创建/更新业务空间信息', {
+        dangerouslyUseHTMLString: true,
+        distinguishCancelAndClose: true,
+        confirmButtonText: '更新',
+        cancelButtonText: '创建'
+      }).then(() => {
+        this.$emit("closeCanvas")
+        this.$router.push({
+          name: 'updatePointZone',
+          params: { item: item, floorData: this.floorOption, nowBuildFloor: this.buildingData }
+        })
+      }).catch(action => {
+        if (action === 'cancel') {
+          this.$router.push({
+            name: 'createPointZone',
+            params: { item: item, floorData: this.floorOption, nowBuildFloor: this.buildingData }
+          })
         }
-        .saga-message {
-            height: calc(100vh - 220px);
-            line-height: 400px;
-            color: #ccc;
-            font-size: 24px;
-            text-align: center;
+      })
+    },
+    btnClick(item) {
+      if (item.X == 0 && item.Y == 0) {
+        this.$emit("setFalg", item);
+      } else {
+        this.$emit("getLocation", item);
+      }
+    },
+    mapPush(detailsArr, pic) {
+      pic.map(item => {
+        detailsArr.push(item);
+      });
+    },
+    //修改详情
+    updatePoint() {
+      this.pointDetails.ImageList = [];
+      this.mapPush(this.pointDetails.ImageList, this.installPic);
+      this.mapPush(this.pointDetails.ImageList, this.panorama);
+      this.mapPush(this.pointDetails.ImageList, this.rimPic);
+      this.mapPush(this.pointDetails.ImageList, this.videoPic);
+      this.mapPush(this.pointDetails.ImageList, this.elsePic);
+      let pa = {
+        Content: [this.pointDetails]
+      }
+      updateLocationPoint(pa, res => {
+        this.$message.success("修改成功");
+      })
+    },
+    getDetails(item) {
+      this.pointShow = true;
+      this.pointDetails = item;
+      if (item.ImageList && item.ImageList.length) {
+        this.getPic(item.ImageList);
+      }
+    },
+    getPic(imgArr) {
+      this.installPic = [];
+      this.panorama = [];
+      this.rimPic = [];
+      this.videoPic = [];
+      this.elsePic = [];
+      imgArr.map((item, index) => {
+        switch (item.name) {
+          case "安装位置":
+            this.installPic.push(item);
+            break;
+          case "全景照片":
+            this.panorama.push(item);
+            break;
+          case "周边照片":
+            this.rimPic.push(item);
+            break;
+          case "视频":
+            this.videoPic.push(item);
+            break;
+          default:
+            this.elsePic.push(item);
         }
-        .point {
-            padding-left: 20px;
-            height: 30px;
-            span {
-                font-size: 12px;
-                width: 180px;
-                display: inline-block;
-                white-space: nowrap;
-                text-overflow: ellipsis;
-                overflow: hidden;
-            }
-            button {
-                margin-bottom: 5px;
-            }
+      });
+    },
+    //获取point
+    getPointList() {
+      if (this.buildingData[0] && this.buildingData[1]) {
+        let param = {
+            Filters: `BuildId='${this.buildingData[0]}';floorId='${this.buildingData[1]}'`,
+            "Cascade": [{ "Name": "imageList" }]
+          };
+        if (this.activeName2 != "point") {
+          param.Filters =  `BuildId='${this.buildingData[0]}';floorId isNull`
         }
-        .point:hover {
-            background-color: #f2f6fc;
-        }
-        .qrcode {
-            width: 100%;
-            height: 180px;
-            overflow: hidden;
-            .qrcode-view {
-                width: 180px;
-                height: 180px;
-                overflow: hidden;
-                float: left;
-                img {
-                    width: 100%;
-                    height: 100%;
-                }
-            }
-            .point-edit {
-                height: 180px;
-                display: inline-block;
-                padding-top: 10px;
-                overflow-x: hidden;
-                width: calc(100% - 180px);
-            }
+        this.isLoading = true;
+        locationPointQuery(param, res => {
+          this.isLoading = false;
+          if (this.activeName2 != "point") {
+            this.pointNoData = res.Content;
+            this.$emit("getPointList", []);
+          }
+          else {
+            this.pointData = res.Content;
+            this.$emit("getPointList", res.Content);
+          }
+        })
+      }
+    },
+    //初始化
+    reset(data, map) {
+      this.map = map
+      this.pointParam.FloorId = data.FloorId;
+      this.pointParam.fllorName = data.fllorName;
+      this.buildingData = data.buildingData;
+      this.activeName2 = "point";
+      this.getPointList();
+    }
+  },
+  watch: {
+    pointShow: {
+      deep: true,
+      handler: function (old, val) {
+        if (old == false && val == true) {
+          this.getPointList();
         }
-        .point-coding {
-            width: 100%;
-            height: 120px;
-            margin-top: 5px;
-            overflow: hidden;
-            p {
-                height: 30px;
-                line-height: 30px;
-                padding-left: 10px;
-                font-weight: 500;
-                font-size: 16px;
-                text-align: left;
-            }
-            ul {
-                width: 100%;
-                border: 1px solid #ccc;
-                border-bottom: none;
-                box-sizing: border-box;
-                li {
-                    line-height: 40px;
-                    height: 40px;
-                    span {
-                        display: block;
-                        float: left;
-                        padding-left: 10px;
-                        box-sizing: border-box;
-                        border-right: 1px solid #ccc;
-                        border-bottom: 1px solid #ccc;
-                        border-left: 1px solid #ccc;
-                        height: 40px;
-                        overflow: hidden;
-                    }
-                    span:first-child {
-                        width: 30%;
-                    }
-                    span:last-child {
-                        width: 70%;
-                    }
-                }
-            }
+      }
+    },
+    projectId() {
+      this.pointData = []
+      this.pointNoData = []
+      this.activeName2 = "point"
+    }
+  }
+};
+
+</script>
+
+<style lang="scss" scoped>
+#graphy-tabs {
+  /deep/ .el-scrollbar__wrap {
+    overflow-x: hidden;
+  }
+  /deep/ .el-tabs__content {
+    height: calc(100% - 56px);
+  }
+  height: 100%;
+  border-left: 1px solid #e4e7ed;
+
+  .el-tabs__content {
+    height: calc(100% - 60px) !important;
+    background: red;
+  }
+
+  .el-dialog__body {
+    max-height: 400px;
+  }
+
+  .saga-message {
+    height: calc(100vh - 220px);
+    line-height: 400px;
+    color: #ccc;
+    font-size: 24px;
+    text-align: center;
+  }
+
+  .point {
+    padding-left: 20px;
+    height: 30px;
+
+    span {
+      font-size: 12px;
+      width: 180px;
+      display: inline-block;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      overflow: hidden;
+    }
+
+    button {
+      margin-bottom: 5px;
+    }
+  }
+
+  .point:hover {
+    background-color: #f2f6fc;
+  }
+
+  .qrcode {
+    width: 100%;
+    height: 180px;
+    overflow: hidden;
+
+    .qrcode-view {
+      width: 180px;
+      height: 180px;
+      overflow: hidden;
+      float: left;
+
+      img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    .point-edit {
+      height: 180px;
+      display: inline-block;
+      padding-top: 10px;
+      overflow-x: hidden;
+      width: calc(100% - 180px);
+    }
+  }
+
+  .point-coding {
+    width: 100%;
+    height: 120px;
+    margin-top: 5px;
+    overflow: hidden;
+
+    p {
+      height: 30px;
+      line-height: 30px;
+      padding-left: 10px;
+      font-weight: 500;
+      font-size: 16px;
+      text-align: left;
+    }
+
+    ul {
+      width: 100%;
+      border: 1px solid #ccc;
+      border-bottom: none;
+      box-sizing: border-box;
+
+      li {
+        line-height: 40px;
+        height: 40px;
+
+        span {
+          display: block;
+          float: left;
+          padding-left: 10px;
+          box-sizing: border-box;
+          border-right: 1px solid #ccc;
+          border-bottom: 1px solid #ccc;
+          border-left: 1px solid #ccc;
+          height: 40px;
+          overflow: hidden;
         }
-        .point-pic {
-            width: 100%;
-            overflow: hidden;
-            p {
-                height: 25px;
-                line-height: 25px;
-                padding-left: 10px;
-                font-weight: 500;
-                font-size: 16px;
-                margin-top: 5px;
-                margin-bottom: 5px;
-            }
+
+        span:first-child {
+          width: 30%;
         }
-        .point-image {
-            width: 180px;
-            height: 180px;
-            float: left;
-            position: relative;
-            margin-right: 10px;
-            margin-bottom: 10px;
-            border: 1px solid #ccc;
-            img {
-                width: 100%;
-                height: 100%;
-            }
-            i {
-                position: absolute;
-                bottom: 10px;
-                right: 10px;
-                background-color: #fff;
-                padding: 5px;
-                cursor: pointer;
-            }
+
+        span:last-child {
+          width: 70%;
         }
+      }
     }
-</style>
+  }
+
+  .point-pic {
+    width: 100%;
+    overflow: hidden;
+
+    p {
+      height: 25px;
+      line-height: 25px;
+      padding-left: 10px;
+      font-weight: 500;
+      font-size: 16px;
+      margin-top: 5px;
+      margin-bottom: 5px;
+    }
+  }
+
+  .point-image {
+    width: 180px;
+    height: 180px;
+    float: left;
+    position: relative;
+    margin-right: 10px;
+    margin-bottom: 10px;
+    border: 1px solid #ccc;
 
+    img {
+      width: 100%;
+      height: 100%;
+    }
+
+    i {
+      position: absolute;
+      bottom: 10px;
+      right: 10px;
+      background-color: #fff;
+      padding: 5px;
+      cursor: pointer;
+    }
+  }
+}
+</style>

+ 222 - 228
src/views/data_admin/buildGraphy/index.vue

@@ -2,242 +2,236 @@
   revit空间管理
  -->
 <template>
-    <div id="graphy">
-        <!-- <div class="graphy-left">
+  <div id="graphy">
+    <!-- <div class="graphy-left">
           <graphy-tree v-if="show" :param="param" @change="getPoint"></graphy-tree>
         </div> -->
-        <div class='search-title'>
-            <span class="p12">建筑楼层</span>
-            <el-cascader placeholder='请选择' :options="options" @active-item-change="handleItemChange" @change="changeFloor" filterable></el-cascader>
-        </div>
-        <div class="graphy-view">
-            <div class="graphy-main">
-                <graphy-canvas v-if="show" :param="param" @getDetails="getDetails" @resetPoint="resetPoint" ref="canvas"></graphy-canvas>
-            </div>
-            <div class="graphy-right">
-                <graphy-tabs v-show="show" ref="tabs" :pointParam="pointParam" @setFalg="setFalg" @getLocation="getLocation" @getPointList="sendPointList"></graphy-tabs>
-            </div>
-        </div>
+    <div class='search-title'>
+      <span class="p12">建筑楼层</span>
+      <el-cascader placeholder='请选择' v-model="buildVlaue" :options="options" @change="changeFloor" filterable :props="props" ref="buildfloor"></el-cascader>
     </div>
+    <div class="graphy-view">
+      <div class="graphy-main">
+        <graphy-canvas v-if="show" @getDetails="getDetails" @resetPoint="resetPoint" ref="canvas"></graphy-canvas>
+      </div>
+      <div class="graphy-right">
+        <graphy-tabs v-show="show" ref="tabs" :floorOption="options" :pointParam="pointParam" @setFalg="setFalg" @getLocation="getLocation" @getPointList="sendPointList" @closeCanvas="closeCanvas">
+        </graphy-tabs>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
-    //接口
-    import graphyTree from "./graphyTree";
-    import graphyTabs from "./graphyTabs";
-    import graphyCanvas from "./graphyCanvas";
-    import {
-        mapGetters,
-        mapActions
-    } from 'vuex';
-    import {
-        getPT,
-        getBuildSelect,
-        getFloor
-    } from "@/api/scan/request"; //获取点位坐标
-    import tools from "@/utils/scan/tools"
-    import Handsontable from "handsontable-pro"
-    import 'handsontable-pro/dist/handsontable.full.css'
-    import zhCN from 'handsontable-pro/languages/zh-CN';
-    export default {
-        components: {
-            graphyTree,
-            graphyTabs,
-            graphyCanvas
-        },
-        data() {
-            return {
-                param: {
-                    ProjId: this.projectId, //项目id
-                    UserId: this.userId //用户id
-                },
-                pointParam: {
-                    //point请求参数
-                    ProjId: this.projectId, //项目id
-                    UserId: this.userId, //用户id
-                    fllorName: ""
-                },
-                options: [],
-                map: null,
-                pointId: null,
-                show: false,
-                buildVlaue: []
-            };
-        },
-        mounted() {
-            this.changeValue()
-            this.getList()
-        },
-        computed: {
-            ...mapGetters('layout', ['projectId', 'secret', 'userId'])
-        },
-        methods: {
-            //修改楼层
-            changeFloor(val) {
-                console.log(val)
-                let floorMap = "",
-                    name = ""
-                this.options.map(item => {
-                    if (!!item.children && item.children.length) {
-                        if (item.value == val[0]) {
-                            item.children.map(child => {
-                                if (child.value == val[1]) {
-                                    console.log(child, 'child')
-                                    floorMap = child.map
-                                    name = child.label
-                                }
-                            })
-                        }
-                    }
-                })
-                let obj = {
-                    code: val[1],
-                    map: floorMap,
-                    name: name
-                }
-                this.getPoint(obj)
-                console.log(floorMap)
-            },
-            //获取建筑列表
-            getList() {
-                getBuildSelect(this.param).then(res => {
-                    console.log(res)
-                    this.options = res.data.BuildList.map(item => {
-                        return {
-                            value: item.BuildId,
-                            label: item.BuildLocalName,
-                            children: []
-                        }
-                    })
-                })
-            },
-            //点击事件
-            handleItemChange(val) {
-                if (val.length == 1) {
-                    let obj = Object.assign({
-                        BuildId: val[0]
-                    }, this.param)
-                    getFloor(obj).then(res => {
-                        console.log(res)
-                        this.options = this.options.map(item => {
-                            if (item.value == val[0]) {
-                                let FloorList = tools.sortArr(res.data.FloorList, "FloorSequenceId" , false)
-                                item.children = FloorList.map(child => {
-                                    return {
-                                        value: child.FloorId,
-                                        label: child.FloorLocalName + (child.FloorMap ? '' : '(需初始化数据)'),
-                                        map: child.FloorMap
-                                    }
-                                })
-                            }
-                            return item
-                        })
-                        console.log(this.options)
-                    })
-                } else if (val.length == 2) {
-                }
-            },
-            changeValue() {
-                this.$set(this.param, 'ProjId', this.projectId)
-                this.$set(this.param, 'UserId', this.userId)
-                this.$set(this.pointParam, 'ProjId', this.projectId)
-                this.$set(this.pointParam, 'UserId', this.userId)
-                this.show = true
-            },
-            //渲染
-            getPoint(data) {
-                this.pointParam.FloorId = data.code;
-                this.pointParam.fllorName = data.name;
-                this.$refs.tabs.reset(this.pointParam, data.map);
-                if (this.map != data.map) {
-                    this.map = data.map;
-                    this.$refs.canvas.getData(data);
-                } else {
-                    return;
-                }
-            },
-            //获取到点位标签坐标
-            sendPointList(list) {
-                if (list && list.length && list[0].Id == this.pointId) {
-                    this.$refs.canvas.doPoint(list);
-                } else {
-                    if (list.length) {
-                        this.pointId = list[0].Id;
-                        this.$refs.canvas.doPoint(list);
-                    } else {
-                        this.$refs.canvas.doPoint([]);
-                    }
-                }
-            },
-            //插旗setFalg
-            setFalg(item) {
-                this.$refs.canvas.addPoint(item);
-            },
-            //定位getLocation
-            getLocation(item) {
-                this.$refs.canvas.locationGraphy({
-                    X: item.X,
-                    Y: item.Y * -1
-                });
-            },
-            //重新获取点位信息resetPoint
-            resetPoint() {
-                this.$refs.tabs.reset(this.pointParam, true);
-            },
-            //查看详情
-            getDetails(item) {
-                this.$refs.tabs.getDetails(item);
-            }
-        },
-        watch: {
-            projectId(){
-                this. map = null
-                this.show = false
-                this.options = []
-                this.buildVlaue = []
-                this.changeValue()
-                this.getList()
-            }
-        }
+//接口
+import graphyTree from "./graphyTree";
+import graphyTabs from "./graphyTabs";
+import graphyCanvas from "./graphyCanvas";
+import {
+  mapGetters,
+  mapActions
+} from 'vuex';
+import {
+  getPT,
+  buildingQuery,
+  getFloor
+} from "@/api/scan/request"; //获取点位坐标
+import tools from "@/utils/scan/tools"
+import Handsontable from "handsontable-pro"
+import 'handsontable-pro/dist/handsontable.full.css'
+import zhCN from 'handsontable-pro/languages/zh-CN';
+export default {
+  components: {
+    graphyTree,
+    graphyTabs,
+    graphyCanvas
+  },
+  data() {
+    return {
+      props: {
+        value: 'BuildID',
+        label: 'BuildLocalName',
+        children: 'Floor'
+      },
+      param: {
+        ProjId: this.projectId, //项目id
+        UserId: this.userId //用户id
+      },
+      pointParam: {
+        ProjId: this.projectId, //项目id
+        UserId: this.userId, //用户id
+        fllorName: "",
+        buildingData:[],//建筑楼层信息
+      },
+      options: [],
+      map: null,
+      pointId: null,
+      show: false,
+      buildVlaue: []
     };
+  },
+  mounted() {
+    this.changeValue()
+    this.getList()
+  },
+  computed: {
+    ...mapGetters('layout', ['projectId', 'secret', 'userId'])
+  },
+  methods: {
+    //修改楼层
+    changeFloor(val) {
+      let floorMap = "",
+        name = ""
+      this.options.map(item => {
+        if (!!item.Floor && item.Floor.length) {
+          if (item.BuildID == val[0]) {
+            item.Floor.map(child => {
+              if (child.BuildID == val[1]) {
+                floorMap = child.StructureInfo ? child.StructureInfo.FloorMap : ''
+                name = child.FloorLocalName
+              }
+            })
+          }
+        }
+      })
+      let obj = {
+        code: val[1],
+        map: floorMap,
+        name: name,
+        buildingData:val
+      }
+      this.getPoint(obj)
+    },
+    //获取建筑列表
+    getList() {
+      let param = {
+        Cascade: [
+          { Name: "floor", Orders: "FloorSequenceID desc", }
+        ],
+        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
+        if(this.$route.params.nowBuildFloor){
+          this.changeFloor(this.$route.params.nowBuildFloor)
+          this.buildVlaue = this.$route.params.nowBuildFloor
+        }
+      })
+    },
+    changeValue() {
+      this.$set(this.param, 'ProjId', this.projectId)
+      this.$set(this.param, 'UserId', this.userId)
+      this.$set(this.pointParam, 'ProjId', this.projectId)
+      this.$set(this.pointParam, 'UserId', this.userId)
+      this.show = true
+    },
+    //渲染
+    getPoint(data) {
+      this.pointParam.FloorId = data.code;
+      this.pointParam.fllorName = data.name;
+      this.pointParam.buildingData = data.buildingData
+      
+      if (this.map != data.map) {
+        this.map = data.map;
+        this.$refs.canvas.getData(data);
+      } else {
+        // return;
+      }
+      this.$refs.tabs.reset(this.pointParam, data.map);
+    },
+    //获取到点位标签坐标
+    sendPointList(list) {
+      if (list && list.length) {
+        this.pointId = list[0].Id;
+        this.$refs.canvas.doPoint(list);
+      } else {
+        this.$refs.canvas.doPoint([]);
+      }
+    },
+    //插旗setFalg
+    setFalg(item) {
+      this.$refs.canvas.addPoint(item);
+    },
+    //定位getLocation
+    getLocation(item) {
+      this.$refs.canvas.locationGraphy({
+        X: item.X,
+        Y: item.Y * -1
+      });
+    },
+    //重新获取点位信息resetPoint
+    resetPoint() {
+      this.$refs.tabs.reset(this.pointParam, true);
+    },
+    //查看详情
+    getDetails(item) {
+      this.$refs.tabs.getDetails(item);
+    },
+    //关闭canvas
+    closeCanvas(){
+      this.show = false;
+    }
+  },
+  watch: {
+    projectId() {
+      this.map = null
+      this.show = false
+      this.options = []
+      this.buildVlaue = []
+      this.changeValue()
+      this.getList()
+    }
+  }
+};
 </script>
 
 <style lang="less" scoped>
-    #graphy {
-        // position: relative;
-        display: flex;
-        flex-direction: column;
-        .graphy-view {
-            display: flex;
-            background-color: #fff;
-            flex: 1; 
-            .graphy-main {
-                flex: 1;
-                // position: absolute;
-                // left: 200px;
-                // top: 0;
-                // right: 400px;
-                // bottom: 0;
-                // overflow: auto;
-            }
-            .graphy-right {
-                // position: absolute;
-                // right: 0;
-                width: 400px; // top: 0;
-                // bottom: 0;
-                // border-left: 1px solid #ccc;
-                // overflow: hidden;
-            }
-        }
-        .graphy-left {
-            // width: 200px;
-            // height: 100%;
-            // position: absolute;
-            // overflow-y: auto;
-            // left: 0;
-            // top: 0;
-            // bottom: 0;
-            // border-right: 1px solid #ccc;
-        }
+#graphy {
+  // position: relative;
+  display: flex;
+  flex-direction: column;
+  .graphy-view {
+    display: flex;
+    background-color: #fff;
+    flex: 1;
+    .graphy-main {
+      flex: 1;
+      // position: absolute;
+      // left: 200px;
+      // top: 0;
+      // right: 400px;
+      // bottom: 0;
+      // overflow: auto;
+    }
+    .graphy-right {
+      // position: absolute;
+      // right: 0;
+      width: 400px; // top: 0;
+      // bottom: 0;
+      // border-left: 1px solid #ccc;
+      // overflow: hidden;
     }
-</style>
+  }
+  .graphy-left {
+    // width: 200px;
+    // height: 100%;
+    // position: absolute;
+    // overflow-y: auto;
+    // left: 0;
+    // top: 0;
+    // bottom: 0;
+    // border-right: 1px solid #ccc;
+  }
+}
+</style>

+ 78 - 0
src/views/data_admin/buildGraphy/locationPointMsg.vue

@@ -0,0 +1,78 @@
+<template>
+  <div id="locationPointMsg" style="width:100%;border:1px solid rgb(204,204,204)">
+    <div style="padding:5px 10px;border-bottom:1px solid rgb(204,204,204);">
+      <label class="item">位置标签名称:{{pointObj.Name || '--'}}</label>
+      <label class="item">本地编码:{{pointObj.LocalId || '--'}}</label>
+      <label class="item">备注:{{pointObj.Note || '--'}}</label>
+    </div>
+    <div style="padding:5px 10px;">
+      <p>勾选需要补充到业务空间的图片信息</p>
+      <div v-if="pointObj.ImageList && pointObj.ImageList.length">
+        <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange"><span style="padding-left:20px">全选</span></el-checkbox>
+        <div style="margin: 15px 0;"></div>
+        <el-checkbox-group v-model="choImg" @change="handleCheckedCitiesChange">
+          <el-checkbox v-for="item in pointObj.ImageList" :label="item" :key="item.key">
+            <div style="max-width:250px;height:250px;float:left;">
+              <el-image :src="`/image-service/common/image_get?systemId=dataPlatform&key=${item.Key}`" style="height:250px;"></el-image>
+            </div>
+          </el-checkbox>
+        </el-checkbox-group>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      isIndeterminate: false,
+      checkAll: false,
+      choImg: [],//选中的图片
+    }
+  },
+  props: {
+    pointObj: {},//标签对象
+  },
+  created() {
+  },
+  methods: {
+    //是否全选
+    handleCheckAllChange(val) {
+      this.choImg = val ? this.pointObj.ImageList : [];
+      this.isIndeterminate = false;
+    },
+    //选中
+    handleCheckedCitiesChange(value) {
+      let checkedCount = value.length;
+      this.checkAll = checkedCount === this.pointObj.ImageList.length;
+      this.isIndeterminate = checkedCount > 0 && checkedCount < this.pointObj.ImageList.length;
+    },
+    //清空选项
+    clearImg(){
+      this.choImg = [];
+      this.isIndeterminate = false;
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+#locationPointMsg {
+  /deep/ .el-checkbox__input {
+    position: absolute;
+    left: 10px;
+  }
+  /deep/ .el-checkbox__inner {
+    width: 20px;
+    height: 20px;
+  }
+  /deep/ .el-checkbox__inner::after {
+    left: 7px;
+    top: 4px;
+  }
+  .item{
+    padding-right:20px;
+  }
+}
+</style>

+ 272 - 0
src/views/data_admin/buildGraphy/updatePointZone.vue

@@ -0,0 +1,272 @@
+<template>
+  <div id="updatePoint">
+    <div class="condition">
+      <div class="header">
+        <el-button style="float:left;" size="small" type="default" icon="el-icon-back" @click="goBack"></el-button>
+        <el-button size="small" style="float:right" @click="updateZ">更新</el-button>
+      </div>
+      <el-scrollbar style="height:calc(100% - 43px)">
+        <div class="item">
+          <p>将位置标签图片批量补充到业务空间:</p>
+          <div v-for="item in zoneList" :key="item.objid" class="zone-item">
+            <el-tooltip class="item" effect="dark"
+              :content="`${item.Building.BuildLocalName} / ${item.Floor.FloorLocalName} / ${item.DClassDef.Name} / ${item.RoomLocalName}`"
+              placement="top">
+              <p>{{item.RoomLocalName || item.RoomName}}</p>
+            </el-tooltip>
+            <i class="el-icon-delete" circle style="float:right;line-height:32px;padding: 0 9px 0 0;cursor: pointer;" size="mini"
+              @click="deleteZone(item.RoomID)"></i>
+          </div>
+          <div class="zone-item" style="border:none;border-left:-4px;width:auto;">
+            <el-cascader :props="zoneCascader" :show-all-levels="false" v-model="zoneCa" @change="changeCascader" filterable style="float:left;">
+            </el-cascader>
+            <el-button type="primary" icon="el-icon-plus" circle style="float:right;margin:2px 10px;" size="mini" @click="addZone"></el-button>
+          </div>
+        </div>
+        <div class="item">
+          <p>位置标签图片信息:</p>
+          <locationPointMsg :pointObj="$route.params.item" ref="pointMsg"></locationPointMsg>
+        </div>
+      </el-scrollbar>
+    </div>
+  </div>
+</template>
+
+<script>
+import locationPointMsg from '@/views/data_admin/buildGraphy/locationPointMsg'
+import { queryDictionaryHead, zoneQueryByPoint, queryZone, updateZonePic } from '@/api/scan/request';
+import { mapGetters } from 'vuex'
+export default {
+  data() {
+    let that = this;
+    return {
+      zoneList: [],//业务空间列表
+      pointItem: {},//点位标签对象
+      zoneTypeList: [],//业务空间类型
+      zoneCascader: {//业务空间忌廉器
+        lazy: true,
+        lazyLoad(node, resolve) {
+          const { level } = node;
+          that.getCascaderNode(level, node, resolve);
+        }
+      },
+      newZoneObj: {},//当前新建业务空间
+      zoneCa: []
+    }
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  components: {
+    locationPointMsg
+  },
+  created() {
+    this.pointItem = this.$route.params.item
+    this.getSpaceList();
+  },
+  methods: {
+    //创建
+    updateZ() {
+      let imgs = this.$refs.pointMsg.choImg.concat();
+      imgs = imgs.map(item => ({
+        Id: item.ObjectId,
+        Key: item.Key,
+        Name: item.Name,
+        Type: item.Type
+      }))
+      if (imgs.length && this.zoneList.length) {
+        let zones = this.zoneList.map(item => {
+          if (item.Pic) {
+            item.Pic = item.Pic.concat(imgs);
+          }
+          else {
+            item.Pic = imgs;
+          }
+          return { RoomID: item.RoomID, Pic: item.Pic, ObjectType: item.ObjectType };
+        })
+        let param = {
+          Content: zones
+        }
+        updateZonePic(param, res => {
+          this.$message.success("更新成功");
+          this.$refs.pointMsg.clearImg();
+        })
+      }
+      else if (!this.$refs.pointMsg.choImg.length) {
+        this.$message("请至少选择一张图片");
+      }
+      else {
+        this.$message("请至少添加一个业务空间");
+      }
+
+    },
+    //获取空间列表
+    getSpaceList() {
+      let pa = {
+        X: this.pointItem.X,
+        Y: this.pointItem.Y,
+        data: {
+          Filters: `buildingId = '${this.pointItem.BuildId}' and floorId = '${this.pointItem.FloorId}'`,
+          "Cascade": [{ "Name": "floor" }, { "Name": "building" }, { "Name": "objectTypeO" }]
+        }
+      }
+      zoneQueryByPoint(pa, res => {
+        this.zoneList = res.Content;
+      });
+    },
+    //级联node
+    getCascaderNode(level, node, resolve) {
+      let id = (level + 1) * 10;
+      //建筑
+      if (level == 0) {
+        let nodes = this.$route.params.floorData.map(item => ({
+          value: item.BuildID,
+          label: item.BuildLocalName || item.BuildName,
+          leaf: level >= 3
+        }))
+        resolve(nodes)
+      }
+      //楼层
+      else if (level == 1) {
+        let floors = this.$route.params.floorData.filter(item => { return item.BuildID == node.value })
+        let nodes = floors[0].Floor.map(item => ({
+          value: item.FloorID,
+          label: item.FloorLocalName || item.FloorName,
+          leaf: level >= 3
+        }))
+        resolve(nodes)
+      }
+      //空间类型
+      else if (level == 2) {
+        if (this.zoneTypeList && this.zoneTypeList.length) {
+          resolve(this.zoneTypeList)
+        }
+        else {
+          let pa = {
+            Filters: `parentId='Space'`
+          }
+          queryDictionaryHead(pa, res => {
+            this.zoneTypeList = res.Content.filter((item => { return item.Name != '元空间' })).map(item => ({
+              value: item.Code,
+              label: item.Name,
+              leaf: level >= 3
+            }))
+            resolve(this.zoneTypeList)
+          });
+        }
+      }
+      //业务空间
+      else {
+        let pa = {
+          zone: node.value,
+          data: {
+            "Filters": `buildingId='${node.parent.parent.value}';floorId='${node.parent.value}'`,
+            "Orders": "createTime desc, RoomID asc",
+            "PageNumber": 1,
+            "PageSize": 999
+          }
+        }
+        queryZone(pa, res => {
+          let nodes = res.Content.map(item => {
+            item.Building = { BuildLocalName: node.parent.parent.label };
+            item.Floor = { FloorLocalName: node.parent.label };
+            item.DClassDef = { Name: node.label };
+            return {
+              value: item,
+              label: item.RoomLocalName || item.RoomName,
+              leaf: level >= 3
+            }
+          })
+          resolve(nodes)
+        })
+      }
+    },
+    //删除业务空间
+    deleteZone(zoneid) {
+      this.zoneList = this.zoneList.filter(item => { return item.RoomID != zoneid });
+    },
+    //添加业务空间
+    addZone() {
+      if (this.newZoneObj.RoomID && this.zoneList.findIndex((item) => (item.RoomID == this.newZoneObj.RoomID)) == -1) {
+        this.zoneList.push(this.newZoneObj)
+      }
+      else if (!this.newZoneObj.RoomID) {
+        this.$message("请选择业务空间后添加")
+      }
+      else {
+        this.$message("已有业务空间,请重新选择");
+      }
+      this.zoneCa = [];
+      this.newZoneObj = {}
+    },
+    //选择业务空间
+    changeCascader(val) {
+      this.newZoneObj = val[3]
+    },
+    //返回
+    goBack() {
+      this.$router.push({
+        name: "buildGraphy",
+        params: { nowBuildFloor: this.$route.params.nowBuildFloor }
+      })
+    }
+  },
+  watch: {
+    projectId: {
+      handler(val) {
+        this.goBack();
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.condition {
+  position: relative;
+  padding: 10px 10px;
+  display: flex;
+  height: calc(100% - 22px);
+  flex-direction: column;
+  border: 1px solid #dfe6ec;
+  background: #fff;
+  .header {
+    padding-bottom: 10px;
+    border-bottom: 1px solid rgba(0, 0, 0, 0.5);
+    span {
+      line-height: 33px;
+      margin-left: 15px;
+    }
+    /deep/ .buildFloor {
+      line-height: 32px;
+    }
+  }
+}
+/deep/ .el-scrollbar__wrap {
+  overflow-x: hidden;
+}
+.item {
+  padding: 10px 10px;
+  label {
+    display: inline-block;
+    padding: 5px 10px;
+    width: 130px;
+  }
+}
+.zone-item {
+  display: inline-block;
+  position: relative;
+  width: 245px;
+  margin: 5px 15px 10px 0;
+  border: 1px solid rgb(220, 223, 230);
+  border-radius: 5px;
+}
+.zone-item p {
+  width: 200px;
+  float: left;
+  height: 32px;
+  overflow: hidden;
+  padding-left: 15px;
+  padding: 0 0 0 15px;
+}
+</style>

+ 241 - 0
src/views/data_admin/buildTask/addTask/addAssetsTask.vue

@@ -0,0 +1,241 @@
+<template>
+  <div class="box">
+    <div class="condition">
+      <div class="header">
+        <!-- <i style="float:left;font-size:30px;padding-right:10px;cursor:pointer;" title="返回" @click="goBack" class="el-icon-back"></i> -->
+        <el-button style="float:left;" size="small" type="default" icon="el-icon-back" @click="goBack"></el-button>
+        <floor-cascader ref="floorCascader" @change="changeFloor"></floor-cascader>
+        <my-cascader ref="cascader" @change="changeDevice"></my-cascader>
+        <el-input placeholder="请输入安装位置" style="width: 200px;margin-left:20px;" v-model="keycode" clearable @keyup.enter.native="getTableData">
+          <i slot="suffix" class="el-input__icon el-icon-search" style="cursor:pointer;" @click="getTableData"></i>
+        </el-input>
+        <el-button style="float:right;margin-top:1px;" @click="handleClickCreate">创建已选</el-button>
+      </div>
+      <div class="main" :style="tableData && tableData.length?'height: calc(100% - 96px);':'height: calc(100% - 46px);'">
+        <el-table ref="multipleTable" :data="tableData" v-loading='loading' stripe height="100%" @selection-change="handleSelectionChange" :header-cell-style="headerStyle">
+          <el-table-column type="selection" width="55"></el-table-column>
+          <el-table-column label="所属建筑楼层" width="200">
+            <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="EquipLocalName" label="资产本地名称" show-overflow-tooltip></el-table-column>
+          <el-table-column prop="EquipLocalID" label="资产本地编码" show-overflow-tooltip width="200"></el-table-column>
+          <el-table-column prop="FamilyName.Name" label="设备族"></el-table-column>
+          <el-table-column prop="LedgerParam.Siteinstall.InstallLocation" label="安装位置"></el-table-column>
+          <template slot="empty">
+          <div style="height: 60%;transform: translateY(50%);">
+            <i class="icon-wushuju iconfont"></i>
+            数据暂无
+          </div>
+        </template>
+        </el-table>
+      </div>
+      <div class=footer>
+        <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>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from "vuex"
+//组件
+import floorCascader from "@/components/ledger/lib/floorCascader"
+import myCascader from "@/components/ledger/lib/assets"
+//api
+import { queryProperty } from "@/api/scan/request"
+import { createAssetsTask } from "@/api/data_admin/buildTaskApi"
+export default {
+  data() {
+    return {
+      params: {},
+      loading: false,
+      keycode: '',
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      tableData: [],
+      multipleSelection:[],
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      }, // 列表样式
+    }
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId", "userId", "secret"])
+  },
+  components: {
+    floorCascader,
+    myCascader
+  },
+  created() {
+    this.params = this.$route.query
+  },
+  mounted() {
+    this.getTableData()
+  },
+  watch: {
+    projectId() {
+      this.page.pageNumber = 1
+      this.multipleSelection = []
+      this.getTableData()
+    }
+  },
+  methods: {
+    //返回
+    goBack() {
+      this.$router.push({ name: "buildTask" })
+    },
+    //选择设备族
+    changeDevice(val) {
+      if(val.code) {
+        this.params.category = val.code
+      } else {
+        this.params.category = ''
+      }
+      this.page.pageNumber = 1
+      this.getTableData()
+    },
+    //选择建筑楼层
+    changeFloor(value) {
+      if (value[0]) {
+        this.params.buildId = value[0]
+      }
+      if (value[1]) {
+        this.params.floorId = value[1]
+      } else {
+        this.params.floorId = ''
+      }
+      this.page.pageNumber = 1
+      this.getTableData()
+    },
+    //获取表格数据
+    getTableData() {
+      this.loading = true
+      let param = this.formatFilter()
+      queryProperty(param, res => {
+        this.tableData = res.Content
+        this.page.total = res.Total
+        this.loading = false
+      })
+    },
+    //格式化条件
+    formatFilter() {
+      let params = {
+        Cascade: [
+          {
+            Name: "familyName"
+          },
+          {
+            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.keycode){
+        params.Filters += `;LedgerParam.Siteinstall.InstallLocation contain '${this.keycode}'`
+      }
+
+      if(this.params.category){
+        params.Filters += `;Family='${this.params.category}'`
+      }
+
+      if (this.params.buildId == "noKnow") {
+        params.Filters += `;BuildingId isNull`
+      } else if (this.params.buildId && this.params.buildId != "all") {
+        params.Filters += `;BuildingId='${this.params.buildId}'`
+      }
+
+      if (this.params.floorId == "noKnow") {
+        params.Filters += `;FloorId isNull`
+      } else if (this.params.floorId && this.params.floorId != "all") {
+        params.Filters += `;FloorId='${this.params.floorId}'`
+      }
+
+      return params
+    },
+    //选择的设备或部件
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+    //切换每页显示多少条数据
+    handleSizeChange(val) {
+      this.page.pageSize = val
+      this.getTableData()
+    },
+    //切换页数
+    handleCurrentChange(val) {
+      this.page.pageNumber = 1
+      this.page.pageNumber = val
+      this.getTableData()
+    },
+    //创建已选
+    handleClickCreate() {
+      let list = this.multipleSelection.map((item) => {
+        return {EquipId: item.EquipID}
+      })
+      let param = {
+        Content: list
+      }
+      createAssetsTask(param, res => {
+        this.$message.success("创建成功!")
+        this.$router.push({ name: "buildTask",query:{ newTaskTypes:this.$route.query.newTaskTypes } })
+      })
+    }
+  }
+};
+</script>
+
+<style scoped lang='less'>
+.box {
+  .condition {
+    padding: 10px;
+    display: flex;
+    height: 100%;
+    flex-direction: column;
+    border: 1px solid #dfe6ec;
+    background: #fff;
+    margin-bottom: 10px;
+    .header{
+      padding-bottom: 10px;
+      border-bottom: 1px solid #bcbcbc;
+    }
+    .main{
+      margin-top: 10px;
+    }
+  }
+}
+</style>
+

+ 301 - 0
src/views/data_admin/buildTask/addTask/addDeviceTask.vue

@@ -0,0 +1,301 @@
+<template>
+  <div class="box">
+    <div class="condition">
+      <div class="header">
+        <el-button style="float:left;" size="small" type="default" icon="el-icon-back" @click="goBack"></el-button>
+        <floor-cascader ref="floorCascader" @change="changeFloor"></floor-cascader>
+        <my-cascader ref="cascader" @change="changeDevice"></my-cascader>
+        <el-input placeholder="请输入安装位置" style="width: 200px;margin-left:20px;" v-model="keycode" clearable @keyup.enter.native="getTableData">
+          <i slot="suffix" class="el-input__icon el-icon-search" style="cursor:pointer;" @click="getTableData"></i>
+        </el-input>
+        <el-button style="float:right;margin-top:1px;" @click="handleClickCreate">创建已选</el-button>
+      </div>
+      <div class="main" :style="tableData && tableData.length?'height: calc(100% - 96px);':'height: calc(100% - 46px);'">
+        <el-table ref="multipleTable" :data="tableData" v-loading='loading' stripe height="100%" @selection-change="handleSelectionChange" :header-cell-style="headerStyle">
+          <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 label="所属建筑楼层" width="200"></el-table-column>
+          <el-table-column prop="EquipLocalName" label="设备本地名称" show-overflow-tooltip>
+             <template slot-scope="scope">
+              <div>
+                {{scope.row.EquipLocalName}}
+                <el-badge v-if="scope.row.Component&&scope.row.Component.length?true:false" 
+                  :value="scope.row.Component&&scope.row.Component.length?scope.row.Component.length:0" class="item" type="warning">
+                </el-badge>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column prop="EquipLocalID" label="设备本地编码" show-overflow-tooltip width="200"></el-table-column>
+          <el-table-column prop="EquipCategory.EquipName" label="设备类"></el-table-column>
+          <el-table-column prop="LedgerParam.Siteinstall.InstallLocation" label="安装位置"></el-table-column>
+          <el-table-column prop="type" label="现场验证操作规定" width="200">
+            <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>
+      </div>
+      <div class=footer>
+        <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>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from "vuex"
+//组件
+import floorCascader from "@/components/ledger/lib/floorCascader"
+import myCascader from "@/components/ledger/lib/cascader"
+//api
+import { queryEquip } from "@/api/scan/request"
+import { createDeviceTask } from "@/api/data_admin/buildTaskApi"
+export default {
+  data() {
+    return {
+      params: {},
+      loading: false,
+      keycode: '',
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      options: [{//方案
+        value: '1',
+        label: '标准'
+      }],
+      tableData: [],
+      multipleSelection:[],
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      }, // 列表样式
+    }
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId", "userId", "secret"])
+  },
+  components: {
+    floorCascader,
+    myCascader
+  },
+  created() {
+    this.params = this.$route.query
+    console.log(this.params)
+  },
+  mounted() {
+    this.getTableData()
+  },
+  watch: {
+    projectId() {
+      this.page.pageNumber = 1
+      this.multipleSelection = []
+      this.getTableData()
+    }
+  },
+  methods: {
+    //返回
+    goBack() {
+      this.$router.push({ name: "buildTask" })
+    },
+    //选择设备或部件
+    changeDevice(val) {
+      if(val.code) {
+        this.params.category = val.code
+      } else {
+        this.params.category = ''
+      }
+      this.page.pageNumber = 1
+      this.getTableData()
+    },
+    //选择建筑楼层
+    changeFloor(value) {
+      if (value[0]) {
+        this.params.buildId = value[0]
+      }
+      if (value[1]) {
+        this.params.floorId = value[1]
+      } else {
+        this.params.floorId = ''
+      }
+      this.page.pageNumber = 1
+      this.getTableData()
+    },
+    //获取表格数据
+    getTableData() {
+      this.loading = true
+      let param = this.formatFilter()
+      queryEquip(param, 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.SchemeId = "1"
+          return item
+        })
+        this.page.total = res.Total
+        this.loading = false
+      })
+    },
+    //格式化条件
+    formatFilter() {
+      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.keycode){
+        params.Filters += `;LedgerParam.Siteinstall.InstallLocation contain '${this.keycode}'`
+      }
+
+      if(this.params.category){
+        params.Filters += `;Category='${this.params.category}'`
+      }
+
+      if (this.params.buildId == "noKnow") {
+        params.Filters += `;BuildingId isNull`
+      } else if (this.params.buildId && this.params.buildId != "all") {
+        params.Filters += `;BuildingId='${this.params.buildId}'`
+      }
+
+      if (this.params.floorId == "noKnow") {
+        params.Filters += `;FloorId isNull`
+      } else if (this.params.floorId && this.params.floorId != "all") {
+        params.Filters += `;FloorId='${this.params.floorId}'`
+      }
+      return params
+    },
+    //选择的设备或部件
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+    //切换每页显示多少条数据
+    handleSizeChange(val) {
+      this.page.pageSize = val
+      this.getTableData()
+    },
+    //切换页数
+    handleCurrentChange(val) {
+      this.page.pageNumber = val
+      this.getTableData()
+    },
+    //创建已选
+    handleClickCreate() {
+      let list = this.multipleSelection.map((item) => {
+        return {EquipId: item.EquipID}
+      })
+      let param = {
+        Content: list
+      }
+      createDeviceTask(param, res => {
+        this.$message.success("创建成功!")
+        this.$router.push({ name: "buildTask",query:{ newTaskTypes:this.$route.query.newTaskTypes } })
+      })
+    }
+  }
+};
+</script>
+
+<style scoped lang='less'>
+.box {
+  .condition {
+    padding: 10px;
+    display: flex;
+    height: 100%;
+    flex-direction: column;
+    border: 1px solid #dfe6ec;
+    background: #fff;
+    .header{
+      padding-bottom: 10px;
+      border-bottom: 1px solid #bcbcbc;
+    }
+    .main{
+      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>

+ 211 - 0
src/views/data_admin/buildTask/addTask/addModelTask.vue

@@ -0,0 +1,211 @@
+<template>
+  <div id="bd-fl-manage">
+    <div class="header-nav">
+      <el-button style="float:left;margin-right:20px;" size="small" type="default" icon="el-icon-back" @click="goBack"></el-button>
+      <model-folder ref="modelFolder" @change="handleChangeModelFolder" style="margin-right:10px;"></model-folder>
+      <my-cascader :isWidth="false" ref="cascader" @change="changeDevice"></my-cascader>
+      <el-button style="float:right;margin-top:1px;" @click="handleClickCreate">{{buttonContent}}</el-button>
+      <el-switch v-show="CurrentModelId" style="float:right;margin-top:7px;margin-right:20px;" v-model="isLight" active-text="高亮显示未完成验证的区块"></el-switch>
+    </div>
+    <el-row>
+      <div class="l-list">
+        <h4>模型文件</h4>
+        <div class="model-file-list">
+          <el-scrollbar style="height:100%;">
+            <div v-for="item in modelFileList" :key="item.Id" :class="{'model-file-item':true,'active':item.active}" @click="handleChangeModelFile(item)">
+              <span>{{item.FloorName}}</span>
+            </div>
+          </el-scrollbar>
+        </div>
+      </div>
+      <div class="r-model">
+        <draw-model ref="drawModel" :id="1" :CurrentModelId="CurrentModelId" :isLight="isLight" @changeButtonContent="changeButtonContent"></draw-model>
+      </div>
+    </el-row>
+    <modelTask-dialog :dialogVisible.sync="dialogVisible" :params="params" :newTaskTypes="newTaskTypes"></modelTask-dialog>
+  </div>
+</template>
+
+<script>
+import modelFolder from "@/components/ready/buildfloor/modelFolder"
+import myCascader from "@/components/ledger/lib/cascader"
+import drawModel from "@/components/data_admin/buildTask/draw/drawModel"
+import modelTaskDialog from "@/components/data_admin/buildTask/dialog/modelTaskDialog"
+import { mapGetters, mapActions } from "vuex";
+import request from "@/api/model/file.js";
+import {} from "@/api/scan/request";
+export default {
+  components: {
+    modelFolder,
+    myCascader,
+    drawModel,
+    modelTaskDialog
+  },
+  data() {
+    return {
+      isLight: false,//是否高亮未完成验证区块
+      query: {},//query信息
+      dialogVisible: false,//是否显示弹窗
+      modelFolderName: '',//模型文件夹名字
+      modelFolderId: '',//模型文件夹的id
+      modelFileName: '',//模型文件名字
+      modelFileList: [],
+      CurrentModelId: '',//模型文件id
+      device: '',//设备类别
+      spaceList: [],//选中的空间
+      newTaskTypes: [],
+      buttonContent: "通过模型创建",// 按钮文案
+    };
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"]),
+    params(){
+      return {
+        device: this.device,
+        CurrentModelId: this.CurrentModelId,
+        modelFolderName: this.modelFolderName,
+        modelFileName: this.modelFileName,
+        spaceList: this.spaceList,
+        isVerification: this.query.isVerification
+      }
+    }
+  },
+  created() { 
+    this.query = this.$route.query
+  },
+  methods: {
+    goBack(){//返回
+      this.$router.push({name:'buildTask'})
+    },
+    handleChangeModelFolder(item){//切换模型文件夹
+      let val = item.value
+      if(val){
+        this.modelFolderName = item.label
+        let data = {
+          FolderId: val,
+          ProjectId: this.projectId
+        };
+        request.queryFloorList(data, res => {
+          this.modelFileList = res.Content.map(item => {
+            item.active = false
+            return item
+          })
+          if (this.modelFileList.length) {
+            this.handleChangeModelFile(this.modelFileList[0]);
+          }
+        })
+      } else {
+        this.resetSelected()
+      }
+    },
+    resetSelected(){
+      this.modelFileList = []
+      this.CurrentModelId = ''
+      this.modelFolderName = ''
+      this.modelFolderId = ''
+      this.modelFileName = ''
+      this.spaceList = []
+      this.dialogVisible = false
+      this.$refs.drawModel.clearGraphy()
+    },
+    handleChangeModelFile(file){//切换模型文件
+      this.modelFileList.map(item => {
+        file.Id == item.Id?item.active = true:item.active = false
+        return item
+      })
+      this.CurrentModelId = file.CurrentModelId
+      this.modelFolderId = file.FolderId
+      this.modelFileName = file.FloorName
+      this.newTaskTypes = this.$route.query.newTaskTypes
+    },
+    changeDevice(val){//切换设备类别
+      this.device = val.code
+    },
+    handleClickCreate(){//创建已选
+      if(!this.CurrentModelId){
+        this.$message('请选择模型文件!')
+        return false
+      }
+      this.spaceList = this.$refs.drawModel.getSelectedSpaces().map(item => {
+        return item.data.SourceId
+      })
+      this.dialogVisible = true
+    },
+    changeButtonContent(val){// 通过判断是否选中模型空间调整文案
+      this.buttonContent = val;
+    }
+  },
+  watch: {
+    projectId() {
+      this.resetSelected()
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#bd-fl-manage {
+  overflow: hidden;
+  height: 100%;
+  position: relative;
+  .header-nav{
+    height: 32px;
+    padding-bottom: 10px;
+  }
+  .el-row {
+    height: calc(100% - 50px);
+    & > div {
+      float: left;
+      height: 100%;
+      overflow: hidden;
+      background-color: #fff;
+      box-sizing: border-box;
+      border: 1px solid #dfe6ec;
+      .action-box {
+        padding: 10px;
+        .el-button--small {
+          padding: 10px 11px;
+        }
+      }
+    }
+    .l-list {
+      width: 250px;
+      height: 100%;
+      border-right: 0;
+      h4 {
+        padding-left: 10px;
+        border-top: 1px solid #d9d9d9;
+        border-bottom: 1px solid #dfe6ec;
+        background: #d9d9d9;
+        color: #333;
+        line-height: 44px;
+      }
+      .model-file-list {
+        height: calc(100% - 46px);
+        line-height: 48px;
+        /deep/.el-scrollbar__wrap {
+          overflow-x: hidden;
+        }
+        .model-file-item {
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          cursor: pointer;
+          span {
+            margin-left: 10px;
+          }
+        }
+        .model-file-item.active,
+        .model-file-item:hover {
+          background-color: #f5f7fa;
+          color: #000;
+        }
+      }
+    }
+    .r-model {
+      width: calc(100% - 250px);
+      box-sizing: border-box;
+      padding: 10px;
+    }
+  }
+}
+</style>

+ 152 - 30
src/views/data_admin/buildTask/index.vue

@@ -1,36 +1,158 @@
 <template>
-    <div>
-      <das-board>
-        <template v-slot:plan>
-          <span>{{plan?plan:"yyyy-mm-dd"}}</span>
-        </template>
-        <template v-slot:finish>
-          <span>{{finish?finish:"yyyy-mm-dd"}}</span>
-        </template>
-        <template v-slot:onLine>
-          <span>{{onLine?onLine:"yyyy-mm-dd"}}</span>
-        </template>
-        <template v-slot:explain>
-          <span>{{explain?explain:"yyyy-mm-dd"}}</span>
-        </template>
-      </das-board>
-    </div>
+	<div>
+		<task-statistics></task-statistics>
+		<div class="hanson-bar">
+			<el-cascader v-model="taskTypes" :options="taskTypeList" filterable @change="handleChangeTask"></el-cascader>
+			<el-divider direction="vertical"></el-divider>
+			<div class="condition-list">
+				<floor-cascader  v-show="taskType == 'device' || taskType == 'assets'" :isWidth="false" @change="changeFloor"></floor-cascader>
+				<task-state v-show="taskType == 'model' || taskType == 'device' || taskType == 'assets'" ref="taskState" @change="changeState"></task-state>
+				<model-file  v-show="taskType == 'model'" ref="modelFile" @change="handleChangeModel"></model-file>
+				<model-cascader  v-show="taskType == 'model'" :isWidth="false" ref="modelCascader" @change="changeModelCascader"></model-cascader>
+				<device-cascader  v-show="taskType == 'device'" :isWidth="false" ref="deviceCascader" @change="changeDeviceCascader"></device-cascader>
+				<assets-cascader  v-show="taskType == 'assets'" :isWidth="false" ref="assets" @change="changeAssetsCascader"></assets-cascader>
+			</div>
+			<el-button class="add-task" @click="addTaskDialog = true">添加验证任务</el-button>
+		</div>
+		<div class="tabel-box">
+			<model-table :paramsData="{taskState, modelFile, modelCategory}" v-if="taskType == 'model'"></model-table>
+			<device-table :paramsData="{buildfloor, taskState, deviceCategory}" v-else-if="taskType == 'device'"></device-table>
+			<assets-table :paramsData="{buildfloor, taskState, family}" v-else-if="taskType == 'assets'"></assets-table>
+			<tear-table v-else-if="taskType == 'tear'"></tear-table>
+			<replace-table v-else-if="taskType == 'replace'"></replace-table>
+		</div>
+		<add-task :addTaskDialog.sync="addTaskDialog" :newTaskTypes="newTaskTypes"></add-task>
+	</div>
 </template>
 
 <script>
-import dasBoard from "@/views/dasboard/index";
+import { mapGetters } from "vuex"
+import taskStatistics from '@/components/data_admin/buildTask/taskStatistics'
+import floorCascader from "@/components/ledger/lib/floorCascader"
+
+import taskState from "@/components/data_admin/buildTask/lib/taskState"
+import modelFile from "@/components/data_admin/buildTask/lib/modelFile"
+import modelCascader from "@/components/data_admin/buildTask/lib/modelCascader"
+import deviceCascader from "@/components/data_admin/buildTask/lib/deviceCascader"
+import assetsCascader from "@/components/data_admin/buildTask/lib/assetsCascader"
+
+import modelTable from "@/components/data_admin/buildTask/table/modelTable"
+import deviceTable from "@/components/data_admin/buildTask/table/deviceTable"
+import assetsTable from "@/components/data_admin/buildTask/table/assetsTable"
+import tearTable from "@/components/data_admin/buildTask/table/tearTable"
+import replaceTable from "@/components/data_admin/buildTask/table/replaceTable"
+import addTask from "@/components/data_admin/buildTask/dialog/addTaskDialog"
 export default {
-    components: {
-      dasBoard
-    },
-    data() {
-        return {
-          plan: "2019-08-21",
-          finish: "2019-09-06",
-          onLine: "2019-09-30",
-          explain: "现场任务的创建和修改;v1.2:任务完成情况的查看"
-        }
-    },
-    mounted() {}
+  components: {
+		taskState,
+		modelCascader,
+		taskStatistics,
+		floorCascader,
+		modelFile,
+		deviceCascader,
+		assetsCascader,
+		modelTable,
+		deviceTable,
+		assetsTable,
+		tearTable,
+		replaceTable,
+		addTask
+	},
+	computed: {
+		...mapGetters("layout", [  "projectId",  "secret", "userId" ]),
+		taskType(){
+			return this.taskTypes.slice(-1)[0]
+		}
+	},
+  data() {
+    return {
+			taskTypeList: [
+				{ value: "verification", label: '现场验证任务', children:[
+					{value: "model", label: '现场验证模型'},
+					{value: "device", label: '现场验证设备台账'},
+					{value: "assets", label: '现场验证资产台账'}
+				]}, 
+				{ value: "tear", label: '现场撕码任务' }, 
+				{ value: "replace", label: '现场换码任务' }
+			],
+			taskStateList: [{
+				value: '',
+				label: '全部'
+			}, {
+				value: 1,
+				label: '待验证'
+			}, {
+				value: 0,
+				label: '已完成'
+			}, {
+				value: -1,
+				label: '未找到'
+			}],
+			taskState: '',//任务执行情况
+			modelFile: '',//模型文件
+			modelCategory: '',//模型-设备类型
+			deviceCategory: '',//设备-设备类型
+			family: '',//设备族
+			buildfloor: ['all'],//建筑楼层
+			taskTypes: [],
+			addTaskDialog: false, //是否显示添加任务弹窗
+			newTaskTypes:''
+    }
+	},
+	created(){
+		this.$route.query.newTaskTypes?this.newTaskTypes = this.$route.query.newTaskTypes:this.newTaskTypes = ['verification','model']
+		this.taskTypes = this.newTaskTypes
+	},
+  methods: {
+		handleChangeTask(val){//切换任务类型
+			this.newTaskTypes = val
+		},
+		handleChangeModel(val) {//修改模型文件
+			if(val[1]){
+				this.modelFile = val[1]
+			} else {
+        this.modelFile = ''
+      }
+		},
+		changeState(val) {//修改任务执行情况
+			this.taskState = val
+		},
+		changeFloor(val){//修改建筑楼层
+			this.buildfloor = val
+		},
+		changeModelCascader(val){//修改模型-设备类型
+			this.modelCategory = val.Code
+		},
+		changeDeviceCascader(val){//修改设备-设备类型
+			this.deviceCategory = val.Code
+		},
+		changeAssetsCascader(val){//修改设备族
+			this.family = val.Code
+		}
+  }
 }
-</script>
+</script>
+<style lang="scss" scoped>
+	.hanson-bar {
+    height: 40px;
+    padding: 5px 0;
+    font-size: 14px;
+    overflow: hidden;
+    margin-top: 0;
+    line-height: 40px;
+		position: relative;
+		.condition-list{
+			display: inline-block;
+			vertical-align: middle;
+			line-height: 32px;
+		}
+		.add-task{
+			position: absolute;
+			right: 0;
+			top: 9px;
+		}
+	}
+	.tabel-box{
+		height: calc(100% - 170px);
+	}
+</style>

+ 5 - 28
src/views/ledger/cenotelist/index.vue

@@ -25,24 +25,6 @@
       <div class="tableLeft" v-show="tableData && tableData.length">
         <handson-table ref="table"></handson-table>
       </div>
-      <div class="tableRight">
-        <div v-show="isTableRightShow">
-          <div class="table_right_box"><span class="iconfont close_right" @click="handleCloseRight">&#xe66b;</span></div>
-          <h5>管理需要关联的元空间</h5>
-          <p style="margin-bottom: 10px;">以下为关联的元空间id</p>
-          <el-input
-            type="textarea"
-            :autosize="{ minRows: 6, maxRows: 10}"
-            :disabled="onlyRead"
-            placeholder="请输入元空间id,以“,”分割"
-            v-model="spaceList">
-          </el-input>
-          <el-row class="right" v-show="!onlyRead">
-            <el-button @click="handleCloseRight">取消</el-button>
-            <el-button @click="saveSpaceList" type="primary">保存</el-button>
-          </el-row>
-        </div>
-      </div>
     </div>
     <el-pagination
       class="right"
@@ -75,7 +57,6 @@ import tools from "@/utils/scan/tools"
 import handsonUtils from "@/utils/hasontableUtils"
 import showTools from "@/utils/handsontable/notShow"
 import text from "@/utils/handsontable/mainText"
-
 import cenoteType from "@/components/ledger/lib/cenoteType";
 import handsonTable from "@/components/common/handsontable";
 import { getDataDictionary, getCenoteTableData, updataCenoteTableData, deleteCenoteTableData, saveCenoteRelateSpace, BeatchQueryParam } from "@/api/scan/request"
@@ -89,7 +70,6 @@ export default {
     return {
       cenoteId: "",//竖井类型id
       shaftId: "",//要操作的竖井id
-      isTableRightShow: false,
       spaceList: "",
       options: [{
         value: true,
@@ -297,11 +277,6 @@ export default {
       this.cenoteId = value.Id
       this.getTableHeader()
     },
-    //关闭右侧关联元空间输入按钮
-    handleCloseRight() {
-      this.isTableRightShow = false
-      this.spaceList = ""
-    },
     //切换每页显示多少条数据
     handleSizeChange(val) {
       this.page.pageSize = val
@@ -315,7 +290,7 @@ export default {
     formatHeaderData(list) {//格式化表头显示的数据
       let arr = tools.copyArr(list)
       let data = showTools.headerTextFilter(arr, "shaft", this.onlyRead, this.showType)
-      data.unshift("关联的空间", "其他关系");
+      data.unshift("关联的业务空间", "其他关系");
       return data;
     },
     formatHeaderType(list) {//格式化表头头映射的数据
@@ -372,8 +347,10 @@ export default {
       this.shaftId = infos.ShaftID //要操作的数据id
       //点击关联的元空间
       if (val === "SpaceCount") {
-        this.spaceList = infos.SpaceList
-        this.isTableRightShow = true
+        this.$router.push({
+          path:'/ledger/relatedSpace',
+          query:{ShaftId: this.shaftId,name:name,onlyRead:this.onlyRead}
+        })
         return false
       } else if (val === "OtheRelations") {
         this.$router.push({

+ 402 - 0
src/views/ledger/cenotelist/relatedSpace.vue

@@ -0,0 +1,402 @@
+<template>
+  <div id="relatedSpace">
+    <div class="condition">
+      <div class="header">
+        <el-button style="float:left;" size="small" type="default" icon="el-icon-back" @click="goBack"></el-button>
+        <div class="edit-tool" v-if="!cenoteObj.onlyRead">
+          <el-button v-if="isMyTab == 2" size="small" style="float:right" @click="dialogVisible = true">添加</el-button>
+          <div v-else>
+            <el-button v-show="!isEdit" @click="isEdit = true" size="small" style="float:right">编辑</el-button>
+            <el-button v-show="isEdit" size="small" @click="saveEdit" style="float:right">保存</el-button>
+            <el-button v-show="isEdit" size="small" @click="cancelEdit" style="float:right">取消</el-button>
+          </div>
+          <addSpaceDialog :dialogVisible.sync="dialogVisible" ref="addSpaceDialog" @refresh="refresh" :params="cenoteObj" :spaceType="spaceType"
+            :floorType="floorType"></addSpaceDialog>
+        </div>
+        <el-badge :is-dot="showSpaceDot" style="margin-left:15px;">
+          <label style="line-height:32px;">业务空间类型:</label>
+          <el-select v-model="space" placeholder="请选择业务空间" @change="changeSpace" style="margin-left:15px;">
+            <el-option v-for="item in spaceList" :key="item.Code" :label="item.Name" :value="item.Code">
+            </el-option>
+          </el-select>
+        </el-badge>
+      </div>
+      <div class="saga-build-tab">
+        <el-radio-group v-model="isMyTab" @change="changeRadio" style="width: 136px;">
+          <el-radio-button label="1">平面图</el-radio-button>
+          <el-radio-button label="2" class="space-own-radio" style="width: 68px;">列表</el-radio-button>
+        </el-radio-group>
+      </div>
+      <div v-show="isMyTab == 1" class="data-item">
+        <el-badge :is-dot="showBuildDot">
+          <label style="line-height:32px;padding: 0 10px;">所属建筑:</label>
+          <el-select v-model="building" placeholder="请选择建筑" @change="changeBuilding" v-loading="buildingLoading">
+            <el-option v-for="item in buildingList" :key="item.value" :label="item.BuildLocalName" :value="item.BuildID"></el-option>
+          </el-select>
+        </el-badge>
+        <div style="height:calc(100% - 42px);margin:10px 0 0 0;width:100%;position:relative;">
+          <el-scrollbar style="height:100%;width:148px;border:1px solid rgb(201,201,201);margin:0px;float:left;">
+            <div class="floor" style="width:149px;height:100%;">
+              <span class="floor-item" style="border-bottom:1px solid rgb(201,201,201)">楼 层</span>
+              <div v-if="building" v-loading="buildingLoading">
+                <span class="floor-item" @click="changeFloor(item.FloorID)" :class="{floorItemChoose:(item.FloorID == floor)}"
+                  v-for="item in buildingObj.Floor" :key="item.FloorID">{{ item.FloorLocalName }}</span>
+              </div>
+            </div>
+          </el-scrollbar>
+          <div style="float:right;height:100%;width:calc(100% - 152px);border:1px solid rgb(201,201,201);border-left:none;">
+            <cenote-graphy ref="cenotegraphy"></cenote-graphy>
+          </div>
+        </div>
+
+      </div>
+      <div v-show="isMyTab == 2" class="data-item">
+        <related-spaceList :space="space" :buildingList="buildingList" :spaceType="spaceType" :floorType="floorType" ref="relatedSpacelist">
+        </related-spaceList>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import spaceSelect from "@/components/ledger/lib/spaceSelect";
+import relatedSpaceList from "@/views/ledger/cenotelist/relatedSpaceList";
+import addSpaceDialog from '@/components/ledger/cenote/dialog/addSpaceDialog';
+import { queryDictionaryHead, buildingQuery, shaftSpaceTypeQuery, shaftSpaceBuildingQuery } from '@/api/scan/request';
+import cenoteGraphy from '@/components/ledger/lib/cenoteGraphy'
+import { mapGetters } from 'vuex'
+export default {
+  data() {
+    return {
+      isMyTab: 1,//默认平面图
+      isEdit: false,//是否正在编辑
+      building: '',//当前建筑id
+      buildingObj: {},//当前建筑obj
+      buildingList: [],
+      space: '',//当前业务空间
+      spaceList: [],//空间list
+      floor: '',//当前楼层
+      dialogVisible: false,//添加空间弹窗
+      spaceType: {},//空间种类
+      floorType: {},//子组件楼层信息
+      buildingLoading: false,//左侧列表加载
+      showSpaceDot: false,//空间提示红点
+      showBuildDot: false,//楼层提示红点
+    }
+  },
+  computed: {
+    cenoteObj() {
+      return this.$route.query;
+    },
+    ...mapGetters("layout", ["projectId"])
+  },
+  props: {
+
+  },
+  components: {
+    spaceSelect,
+    relatedSpaceList,
+    addSpaceDialog,
+    cenoteGraphy
+  },
+  created() {
+    this.getSpaceData();
+  },
+  methods: {
+    //获取空间信息
+    getSpaceData() {
+      if (this.cenoteObj.onlyRead) {
+        let pa = {
+          shaftId: this.$route.query.ShaftId
+        }
+        shaftSpaceTypeQuery(pa, res => {
+          this.spaceList = res.Content.map(item => {
+            return { Code: item.ObjectType, Name: item.ObjectTypeName };
+          });
+          this.showDefaultSpace();
+        });
+      }
+      else {
+        let pa = {
+          Filters: `parentId='Space'`
+        }
+        queryDictionaryHead(pa, res => {
+          this.spaceList = res.Content.map(t => {
+            if (t.Name != "元空间") {
+              this.spaceType[t.Code] = t.Name;
+            }
+            return t;
+          });
+          this.showDefaultSpace();
+        });
+      }
+    },
+    //默认显示第一个空间
+    showDefaultSpace() {
+      if (this.spaceList.length) {
+        this.space = this.spaceList[0].Code;
+        if (this.spaceList.length > 1 && this.cenoteObj.onlyRead) {
+          this.showSpaceDot = true;
+        }
+      }
+      //处理空间类型
+      this.spaceList.map(item => {
+        if (item.Name != "元空间") {
+          this.spaceType[item.Code] = item.Name;
+        }
+      });
+      //加载楼层信息
+      this.loadBuildingData();
+    },
+    //获取楼层信息
+    loadBuildingData() {
+      if (this.cenoteObj.onlyRead) {
+        let param = {
+          ShaftId: this.$route.query.ShaftId,
+          ObjectType: this.space
+        };
+        this.buildingLoading = true;
+        shaftSpaceBuildingQuery(param, res => {
+          this.buildingLoading = false;
+          this.buildingList = res.Content;
+          this.buildingList = this.buildingList.map(item => {
+            item.Floor = item.FloorList;
+            item.BuildID = item.BuildingId;
+            item.BuildLocalName = item.BuildingLocalName;
+            if (item.Floor) {
+              item.Floor = item.Floor.map(item => {
+                item.FloorID = item.FloorId;
+                item.FloorLocalName = item.FloorLocalName;
+                return item;
+              })
+            }
+            return item;
+          })
+          this.handleBuildingData();
+        });
+      }
+      else {
+        let param = {
+          Cascade: [
+            { Name: "floor" }
+          ]
+        };
+        buildingQuery(param, res => {
+          this.buildingList = res.Content;
+          this.handleBuildingData();
+        });
+      }
+    },
+    //处理建筑楼层数据
+    handleBuildingData() {
+      if (this.isMyTab == 2) {
+        this.$refs.relatedSpacelist.setFloorData(this.buildingList);
+      }
+      if (this.buildingList.length) {
+        if (this.buildingList.length > 1 && this.cenoteObj.onlyRead) {
+          this.showBuildDot = true;
+        }
+        this.changeBuilding(this.buildingList[0].BuildID);
+        // this.building = this.buildingList[0].BuildID;
+        // this.buildingObj = this.buildingList[0];
+        // if (this.buildingObj.Floor && this.buildingObj.Floor.length) {
+        //   this.floor = this.buildingObj.Floor[0].FloorID;
+        // }
+
+      }
+      else {
+        this.buildingList = [];
+        this.building = '';
+        this.floor = '';
+        this.showBuildDot = false;
+      }
+      this.buildingList.map(item => {
+        if (item.BuildID && item.BuildLocalName) {
+          this.floorType[item.BuildID] = item.BuildLocalName;
+          if (item.Floor instanceof Array) {
+            item.Floor.map(f => {
+              if (f.FloorID && f.FloorLocalName) {
+                this.floorType[f.FloorID] = f.FloorLocalName;
+              }
+            })
+          }
+        }
+      });
+    },
+    //更改业务空间类型
+    changeSpace(val) {
+      this.showSpaceDot = false;
+      this.space = val;
+      this.floor = '';
+      this.buildingList = [];
+      this.building = '';
+      this.changeFloor('');
+      this.loadBuildingData();
+    },
+    //更换建筑
+    changeBuilding(bid) {
+      this.buildingObj = {};
+      this.building = bid;
+      this.buildingList.map(item => {
+        if (item.BuildID == bid) {
+          this.buildingObj = item;
+          if (item.Floor && item.Floor.length) {
+            // this.floor = item.Floor[0].FloorID
+            this.changeFloor(item.Floor[0].FloorID);
+          }
+        }
+      })
+      this.showBuildDot = false;
+    },
+    //更换楼层
+    changeFloor(fid) {
+      this.floor = fid;
+      this.isEdit = false;
+      let buildfloor = [this.building, fid]
+      this.$refs.cenotegraphy.getFloorMap(buildfloor, this.space)
+    },
+    //取消编辑
+    cancelEdit() {
+      this.isEdit = false;
+      this.$refs.cenotegraphy.cancelEdit();
+    },
+    //保存编辑
+    saveEdit() {
+      this.isEdit = false;
+      this.$refs.cenotegraphy.saveEdit();
+    },
+    //更换列表或平面图
+    changeRadio(val) {
+      if (val == 2) {
+        this.spaceList.unshift({ Code: '', Name: '全部' });
+      }
+      if (val == 1) {
+        if (this.spaceList.length > 0) {
+          this.spaceList.shift();
+        }
+      }
+      if (this.spaceList.length) {
+        this.changeSpace(this.spaceList[0].Code);
+      }
+      this.isMyTab = val;
+    },
+    //返回
+    goBack() {
+      this.$router.push({
+        name: 'cenotelist'
+      })
+    },
+    //更新
+    refresh() {
+      this.$refs.relatedSpacelist.getSpaceList();
+      this.dialogVisible = false;
+    }
+  },
+  watch: {
+    isEdit: {
+      handler(val) {
+        this.$refs.cenotegraphy.setSelectAble(val);
+      }
+    },
+    projectId: {
+      handler(val) {
+        this.goBack();
+      }
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.condition {
+  position: relative;
+  padding: 10px 10px;
+  display: flex;
+  height: calc(100% - 22px);
+  flex-direction: column;
+  border: 1px solid #dfe6ec;
+  background: #fff;
+  .header {
+    padding-bottom: 10px;
+    border-bottom: 1px solid rgba(0, 0, 0, 0.5);
+    span {
+      line-height: 33px;
+      margin-left: 15px;
+    }
+    /deep/ .buildFloor {
+      line-height: 32px;
+    }
+  }
+  .spaceTypes {
+    .types {
+      float: left;
+      width: calc(100% - 200px);
+      /deep/ .el-tabs__item.is-top {
+        border-top: 2px solid transparent;
+        &.is-active {
+          border-top: 2px solid #409eff;
+        }
+      }
+    }
+    .deleBtn {
+      float: left;
+      width: 200px;
+      text-align: right;
+      height: 40px;
+      border-bottom: 1px solid #e4e7ed;
+    }
+  }
+}
+.saga-build-tab {
+  position: absolute;
+  left: 50%;
+  transform: translateX(-50%);
+  .tab-main {
+    float: left;
+    width: 120px;
+    padding: 0 5px;
+    margin: 5px 0;
+    border: 1px solid #ccc;
+    background-color: #fff;
+    height: 30px;
+    box-sizing: border-box;
+    text-align: center;
+    cursor: pointer;
+    overflow: hidden;
+    i {
+      font-size: 18px;
+      padding-right: 10px;
+      float: left;
+      line-height: 30px;
+      margin-left: 10px;
+    }
+    span {
+      line-height: 30px;
+      float: left;
+    }
+  }
+  .tab-active {
+    background-color: #409eff;
+    color: #fff;
+  }
+}
+.data-item {
+  height: calc(100% - 44px);
+  padding: 10px 0px;
+  /deep/ .is-horizontal {
+    display: none;
+  }
+}
+.floor-item {
+  padding: 10px 10px;
+  display: block;
+  margin: 0px;
+  cursor: pointer;
+}
+.floorItemChoose {
+  background: rgba(0, 0, 0, 0.2);
+}
+/deep/ .el-scrollbar__wrap {
+  overflow-x: hidden;
+}
+</style>

+ 256 - 0
src/views/ledger/cenotelist/relatedSpaceList.vue

@@ -0,0 +1,256 @@
+<template>
+  <div id="relatedSpaceList" style="height:100%;">
+    <div class="query">
+      <el-input v-model="keyword" placeholder="请输入关键词" @keyup.enter.native="getSpaceList" style="width:240px;margin:0 0;">
+        <i slot="suffix" class="el-input__icon el-icon-search" @click="getSpaceList"></i>
+      </el-input>
+      <label style="line-height:32px;padding: 0 10px;">所属建筑楼层:</label>
+      <el-cascader v-model="Buildfloor" :options="buildingData" @change="handleChange"></el-cascader>
+    </div>
+    <div class="table-area" style="height:calc(100% - 52px)">
+      <el-table :data="tableData" style="width: 100%;height:calc(100% - 48px);" v-loading="loading" :header-cell-style="headerStyle">
+        <el-table-column label='业务空间建筑楼层' show-overflow-tooltip min-width="200" header-align='center' align="center">
+          <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 label='业务空间类型' show-overflow-tooltip min-width="200" header-align='center' align="center">
+          <template slot-scope="scope">
+            {{spaceType[scope.row.ObjectType] || ''}}
+          </template>
+        </el-table-column>
+        <el-table-column prop='RoomLocalName' label='业务空间本地名称' show-overflow-tooltip min-width="200" header-align='center' align="center">
+        </el-table-column>
+        <el-table-column prop='RoomLocalID' label='业务空间本地编码' show-overflow-tooltip min-width="200" header-align='center' align="center">
+        </el-table-column>
+        <el-table-column v-if="!$route.query.onlyRead" prop='' label='操作' show-overflow-tooltip min-width="90" header-align='center' align='center'>
+          <template slot-scope="scope">
+            <el-button size="mini" @click="handleDelete(scope.$index, scope.row)" type="danger" plain icon="el-icon-delete"></el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <el-pagination @size-change="getSpaceList" @current-change="getSpaceList" :current-page="currentPage" :page-sizes="pageSizes"
+        :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="tableData.length" style="float:right;padding:20px 20px 0 0;">
+      </el-pagination>
+    </div>
+  </div>
+</template>
+
+<script>
+import { shaftSpaceQuery, spaceInShaftUnlink } from "@/api/scan/request";
+export default {
+  data() {
+    return {
+      //表格头样式
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      },
+      pageSizes: [10, 20, 50, 100],
+      pageSize: 50,
+      currentPage: 1,
+      keyword: '',//关键词
+      floor: '',//当前楼层
+      tableData: [],//表格数据
+      loading: false,//加载
+      Buildfloor: ["all"],//当前选中的楼层
+      page: {
+        pageSize: 50,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      buildingData: [],//楼层数据
+    }
+  },
+  components: {
+  },
+  methods: {
+    //空间列表
+    getSpaceList() {
+      this.loading = true;
+      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.space) {
+        params.data.Filters += `;ObjectType='${this.space}'`;
+      }
+      if (this.keyword) {
+        params.data.Filters += `;RoomName contain '${this.keyword}' or RoomLocalName contain '${this.keyword}'`;
+      }
+      shaftSpaceQuery(params, res => {
+        this.loading = false;
+        this.tableData = res.Content
+      })
+    },
+    //切换楼层
+    handleChange() {
+      this.getSpaceList();
+    },
+    // 删除关系
+    handleDelete(index, row) {
+      this.$confirm("确认删除该关系?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      })
+        .then(() => {
+          let params = {
+            data: [
+              {
+                ShaftId: this.$route.query.ShaftId,
+                SpaceId: row.RoomID
+              }
+            ],
+            type: row.ObjectType
+          };
+          this.deleteSpInSh(params);
+        })
+        .catch(() => {
+          this.$message("取消删除");
+        });
+    },
+    // 删除系统所在竖井关系
+    deleteSpInSh(params) {
+      spaceInShaftUnlink(params, res => {
+        this.$message.success("删除成功");
+        this.getSpaceList();
+      });
+    },
+    //楼层
+    setFloorData(val) {
+      if (val && val.length) {
+        let bL = val.concat();
+        bL.map(item => {
+          item.value = item.BuildID;
+          item.label = item.BuildLocalName;
+          item.children = [];
+          if (item.Floor instanceof Array) {
+            item.children = item.Floor.map(fitem => {
+              fitem.value = fitem.FloorID
+              fitem.label = fitem.FloorLocalName
+              return fitem
+            })
+          }
+          if (!this.$route.query.onlyRead) {
+            item.children.unshift({
+              value: "noKnow",
+              label: "未明确建筑"
+            })
+          }
+          item.children.unshift({
+            value: "all",
+            label: "全部"
+          })
+        });
+        if (!this.$route.query.onlyRead) {
+          bL.unshift({
+            value: "all",
+            label: "全部"
+          }, {
+            value: "noKnow",
+            label: "未明确建筑"
+          });
+        }
+        this.buildingData = bL;
+      }
+      else {
+        this.buildingData = [];
+      }
+    }
+  },
+  props: {
+    space: '',//空间id
+    buildingList: {//建筑楼层
+      Type: Array,
+      default: []
+    },
+    spaceType: Object,
+    floorType: Object
+  },
+  // computed: {
+  //   buildingData() {
+  //     if (!this.buildingList || !this.buildingList.length) {
+  //       return [];
+  //     }
+  //     let bL = this.buildingList.concat();
+  //     bL.map(item => {
+  //       item.value = item.BuildID;
+  //       item.label = item.BuildLocalName;
+  //       item.children = [];
+  //       if (item.Floor instanceof Array) {
+  //         item.children = item.Floor.map(fitem => {
+  //           fitem.value = fitem.FloorID
+  //           fitem.label = fitem.FloorLocalName
+  //           return fitem
+  //         })
+  //       }
+  //       if (!this.$route.query.onlyRead) {
+  //         item.children.unshift({
+  //           value: "noKnow",
+  //           label: "未明确建筑"
+  //         })
+  //       }
+  //       item.children.unshift({
+  //         value: "all",
+  //         label: "全部"
+  //       })
+  //     });
+  //     if (!this.$route.query.onlyRead) {
+  //       bL.unshift({
+  //         value: "all",
+  //         label: "全部"
+  //       }, {
+  //         value: "noKnow",
+  //         label: "未明确建筑"
+  //       });
+  //     }
+  //     console.log("这是", bL)
+  //     return bL;
+  //   }
+  // },
+  watch: {
+    space: {
+      handler() {
+        this.getSpaceList();
+      },
+      immediate: true
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.query {
+  padding: 10px 0px;
+}
+#relatedSpaceList {
+  /deep/ .el-scrollbar__wrap {
+    overflow-x: hidden;
+  }
+  /deep/ .el-table__body-wrapper{
+    overflow-x:hidden;
+    overflow-y:auto;
+    height:calc(100% - 47px);
+    width:100%;
+  }
+}
+</style>

+ 9 - 5
src/views/ledger/facility/addfacility.vue

@@ -321,7 +321,9 @@ export default {
     },
     //修改
     handleUpdataTable(changeData, source) {
-      this.formaTableData();
+      if (!this.onlyRead && source != 'ObserveChanges.change') {
+        this.formaTableData();
+      }
     },
     //保存去掉空字段的新增数据
     formaTableData() {
@@ -418,13 +420,15 @@ export default {
     },
     //选择型号修改
     firmChange(data) {
-      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Brand", data.brand)
+      tools.setDataForKey(this.tableData[this.row], "DPManufacturerID", data.venderId)//生产商ID
+      tools.setDataForKey(this.tableData[this.row], "DPBrandID", data.brandId)//品牌ID
+      tools.setDataForKey(this.tableData[this.row], "DPSpecificationID", data.specificationId)//型号ID
+      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Manufacturer", data.venderName)
+      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Brand", data.brandName)
       tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Specification", data.name)
-      tools.setDataForKey(this.tableData[this.row], "DPManufacturerID", data.venderId)
     },
     supplyChange(data) {
-      let changeData = { id: data };
-      this.utilToKey("id", "id", changeData, "SupplierContractID");
+      tools.setDataForKey(this.tableData[this.row], "LedgerParam.SupplyPurchase.SupplierContractID", { id: data });
     },
     //如果选择供应商之后
     supplierChange(data) {

+ 9 - 5
src/views/ledger/facility/partsmanage/addparts/index.vue

@@ -268,7 +268,9 @@ export default {
     },
     //修改
     handleUpdataTable(changeData, source) {
-      this.formaTableData();
+      if (!this.onlyRead && source != 'ObserveChanges.change') {
+        this.formaTableData();
+      }
     },
     //保存去掉空字段的新增数据
     formaTableData() {
@@ -347,9 +349,12 @@ export default {
     },
     //选择型号修改
     firmChange(data) {
-      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Brand", data.brand)
+      tools.setDataForKey(this.tableData[this.row], "DPManufacturerID", data.venderId)//生产商ID
+      tools.setDataForKey(this.tableData[this.row], "DPBrandID", data.brandId)//品牌ID
+      tools.setDataForKey(this.tableData[this.row], "DPSpecificationID", data.specificationId)//型号ID
+      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Manufacturer", data.venderName)
+      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Brand", data.brandName)
       tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Specification", data.name)
-      tools.setDataForKey(this.tableData[this.row], "DPManufacturerID", data.venderId)
     },
     //供应商变更
     supplierChange(data) {
@@ -367,8 +372,7 @@ export default {
       tools.setDataForKey(this.tableData[this.row], "DPMaintainerID", data.venderId)
     },
     supplyChange(data) {
-      let changeData = { id: data };
-      this.utilToKey("id", "id", changeData, "SupplierContractID");
+      tools.setDataForKey(this.tableData[this.row], "LedgerParam.SupplyPurchase.SupplierContractID", { id: data });
     },
     //保险合同
     guaranteeChange(data) {

+ 10 - 5
src/views/ledger/facility/partsmanage/index.vue

@@ -436,13 +436,19 @@ export default {
     },
     //选择型号修改
     firmChange(data) {
-      tools.setDataForKey(this.tableData[this.row], "DPManufacturerID", data.venderId)
-      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Brand", data.brand)
+      tools.setDataForKey(this.tableData[this.row], "DPManufacturerID", data.venderId)//生产商ID
+      tools.setDataForKey(this.tableData[this.row], "DPBrandID", data.brandId)//品牌ID
+      tools.setDataForKey(this.tableData[this.row], "DPSpecificationID", data.specificationId)//型号ID
+      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Manufacturer", data.venderName)
+      tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Brand", data.brandName)
       tools.setDataForKey(this.tableData[this.row], "LedgerParam.EquipManufactor.Specification", data.name)
       this.handleUpdataTable(
         [
           [this.row, "DPManufacturerID", null, data.venderId],
-          [this.row, "LedgerParam.EquipManufactor.Brand", null, data.brand],
+          [this.row, "DPBrandID", null, data.brandId],
+          [this.row, "DPSpecificationID", null, data.specificationId],
+          [this.row, "LedgerParam.EquipManufactor.Manufacturer", null, data.venderName],
+          [this.row, "LedgerParam.EquipManufactor.Brand", null, data.brandName],
           [this.row, "LedgerParam.EquipManufactor.Specification", null, data.name]
         ],
         "edit"
@@ -490,8 +496,7 @@ export default {
       // this.handleUpdataTable([[this.row, "LedgerParam.OperationMainte.Maintainer", null, data.name]], "edit")
     },
     supplyChange(data) {
-      let changeData = { id: data };
-      this.utilToKey("id", "id", changeData, "SupplierContractID");
+      tools.setDataForKey(this.tableData[this.row], "LedgerParam.SupplyPurchase.SupplierContractID", { id: data });
     },
     //保险合同
     guaranteeChange(data) {

+ 0 - 0
src/views/ledger/property/addproperty.vue


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.