Browse Source

合并新开发功能分支并解决冲突

zhangyu 5 years ago
parent
commit
6dfdc28c06
75 changed files with 8594 additions and 364 deletions
  1. 0 1
      config/dev.env.js
  2. 8 2
      config/index.js
  3. 0 1
      config/prod.env.js
  4. 5 1
      package.json
  5. 281 0
      src/api/model/file.js
  6. 3 4
      src/api/scan/httpUtil.js
  7. 63 10
      src/api/scan/request.js
  8. 0 0
      src/assets/graphy/SGraphy/dataType.js
  9. 78 0
      src/assets/graphy/SGraphy/dataType.ts
  10. 240 0
      src/assets/graphy/SGraphy/mainScene.js
  11. 228 0
      src/assets/graphy/SGraphy/mainScene.ts
  12. 68 0
      src/assets/graphy/SGraphy/newItems/SGraphyCircleItem.js
  13. 65 0
      src/assets/graphy/SGraphy/newItems/SGraphyCircleItem.ts
  14. 111 0
      src/assets/graphy/SGraphy/newItems/SGraphyImgItem.js
  15. 116 0
      src/assets/graphy/SGraphy/newItems/SGraphyImgItem.ts
  16. 70 0
      src/assets/graphy/SGraphy/newItems/SGraphyPointItem.js
  17. 67 0
      src/assets/graphy/SGraphy/newItems/SGraphyPointItem.ts
  18. 212 0
      src/assets/graphy/SGraphy/newItems/SGraphyPolygonItem.js
  19. 220 0
      src/assets/graphy/SGraphy/newItems/SGraphyPolygonItem.ts
  20. 74 0
      src/assets/graphy/SGraphy/newItems/SGraphyRectItem.js
  21. 76 0
      src/assets/graphy/SGraphy/newItems/SGraphyRectItem.ts
  22. 92 0
      src/assets/graphy/SGraphy/newItems/SGraphyWallItem.js
  23. 89 0
      src/assets/graphy/SGraphy/newItems/SGraphyWallItem.ts
  24. 25 0
      src/assets/graphy/SGraphy/until/pako.js
  25. 27 0
      src/assets/graphy/SGraphy/until/pako.ts
  26. 22 0
      src/assets/graphy/SGraphy/until/tool.js
  27. 21 0
      src/assets/graphy/SGraphy/until/tool.ts
  28. 8 7
      src/assets/graphy/index.js
  29. 8 0
      src/assets/scss/point/point_config/reset.scss
  30. 1 1
      src/components/business_space/graphy/business.vue
  31. 3 2
      src/components/config_point/dictionaryCascader.vue
  32. 2 0
      src/components/config_point/step3_edit/index.vue
  33. 2 0
      src/components/config_point/step3_point/3_temps.vue
  34. 147 0
      src/components/dialogs/config/infoPoint.vue
  35. 236 0
      src/components/model/file/addFloorDialog.vue
  36. 83 0
      src/components/model/file/addFolder.vue
  37. 97 0
      src/components/model/file/changeFolderName.vue
  38. 234 0
      src/components/model/file/floorTable.vue
  39. 127 0
      src/components/model/file/modelLog.vue
  40. 119 0
      src/components/model/file/replaceModelDialog.vue
  41. 96 0
      src/components/point/dynamicdata/applyLog.vue
  42. 107 0
      src/components/point/dynamicdata/applyRulesDialog-copy.vue
  43. 1 1
      src/components/point/dynamicdata/dataSource.vue
  44. 63 21
      src/components/point/dynamicdata/delRelationDialog.vue
  45. 2 2
      src/components/point/dynamicdata/dictionaryDevice.vue
  46. 16 14
      src/components/point/dynamicdata/equipRules.vue
  47. 70 58
      src/components/point/dynamicdata/historyDialog.vue
  48. 2 2
      src/components/point/dynamicdata/locationCascader.vue
  49. 1 1
      src/components/point/dynamicdata/locationFlag.vue
  50. 54 37
      src/components/point/dynamicdata/partsRules.vue
  51. 269 0
      src/components/point/dynamicdata/spaceRules.vue
  52. 269 0
      src/components/point/dynamicdata/systemRules.vue
  53. 33 0
      src/components/ready/buildfloor/addBuild.vue
  54. 80 0
      src/components/ready/buildfloor/addConnectivity.vue
  55. 55 0
      src/components/ready/buildfloor/buildfloorCascader.vue
  56. 94 0
      src/components/ready/buildfloor/formItems.vue
  57. 6 1
      src/framework/layout/PageHeader.vue
  58. 36 13
      src/router/system.js
  59. 72 0
      src/utils/buildfloor/tools.js
  60. 2 2
      src/views/ledger/rentlist/index.vue
  61. 657 27
      src/views/model/file/index.vue
  62. 18 17
      src/views/point/dynamicdata/addRelation/equipRela/index.vue
  63. 722 0
      src/views/point/dynamicdata/addRelation/partsRela/index.vue
  64. 722 0
      src/views/point/dynamicdata/addRelation/spaceRela/index.vue
  65. 722 0
      src/views/point/dynamicdata/addRelation/systemRela/index.vue
  66. 43 11
      src/views/point/dynamicdata/index.vue
  67. 101 0
      src/views/ready/buildfloor/addFloor/index.vue
  68. 2 0
      src/views/ready/buildfloor/drawGraphy/bus.js
  69. 143 0
      src/views/ready/buildfloor/drawGraphy/checkGraphy.vue
  70. 118 0
      src/views/ready/buildfloor/drawGraphy/drawFloor.vue
  71. 112 0
      src/views/ready/buildfloor/drawGraphy/operateGraphyItem.vue
  72. 60 0
      src/views/ready/buildfloor/drawGraphy/repetitionGraphy.vue
  73. 315 28
      src/views/ready/buildfloor/index.vue
  74. 82 0
      src/views/ready/buildfloor/repetitionGraphy.vue
  75. 121 100
      src/views/ready/collectsetting/index.vue

+ 0 - 1
config/dev.env.js

@@ -6,7 +6,6 @@ module.exports = merge(prodEnv, {
     NODE_ENV: '"development"',
     BASE_URL: '"http://192.168.20.215"', //测试iframe地址
     SSO_SERVER: '"http://192.168.20.102:8080"' //(新)测试环境
-    // SSO_SERVER: '"http://192.168.20.101:8004"' //测试环境
     // SSO_SERVER: '"http://sso.sagacloud.cn"',  //正式环境
     // BASE_URL: '"http://mbi.sagacloud.cn"' //线上iframe地址
 })

+ 8 - 2
config/index.js

@@ -14,7 +14,6 @@ module.exports = {
                 target: 'http://192.168.20.235:8080',
                 changeOrigin: true,
                 pathRewrite: {
-                    // "^/apis": ""
                     "^/admin": "/"
                 }
             },
@@ -88,7 +87,14 @@ module.exports = {
                 ws: true,
                 // 将主机标头的原点更改为目标URL
                 changeOrigin: false
-            }
+            },
+            '/modelapi': {
+                target: 'http://192.168.20.225:8082',
+                changeOrigin: true,
+                pathRewrite: {
+                    "^/modelapi": "/"
+                }
+            },
         },
 
         // Various Dev Server settings

+ 0 - 1
config/prod.env.js

@@ -3,7 +3,6 @@ module.exports = {
     NODE_ENV: '"production"',
     // BASE_URL: '"http://192.168.20.215"', //测试iframe地址
     // SSO_SERVER: '"http://192.168.20.102:8080"' //(新)测试环境
-    // SSO_SERVER: '"http://192.168.20.101:8004"' //测试环境
     BASE_URL: '"http://mbi.sagacloud.cn"', //线上iframe地址
     SSO_SERVER: '"http://sso.sagacloud.cn"'  //正式环境
 }

+ 5 - 1
package.json

@@ -10,6 +10,9 @@
         "build": "node build/build.js"
     },
     "dependencies": {
+        "@sybotan-web/base": "2.0.54",
+        "@sybotan-web/draw": "2.0.128",
+        "@sybotan-web/graphy": "2.0.93",
         "axios": "^0.18.0",
         "echarts": "^4.1.0",
         "element-ui": "^2.11.0",
@@ -19,7 +22,8 @@
         "vue": "^2.5.2",
         "vue-axios": "^2.1.4",
         "vue-router": "^3.0.1",
-        "vuex": "^3.1.0"
+        "vuex": "^3.1.0",
+        "cad-engine": "2.0.56"
     },
     "devDependencies": {
         "ajv": "^6.9.1",

+ 281 - 0
src/api/model/file.js

@@ -0,0 +1,281 @@
+import httputils from '@/api/scan/httpUtil'
+import { Message } from 'element-ui';
+const baseUrl = '/modelapi';
+import axios from 'axios'
+let api = {
+    // 新建模型文件夹
+    /**
+     * 
+     * @param {Name:string,ProjectId:string} params 
+     */
+    createModel(params, success) {
+        let Name = params.Name;
+        this.queryModel(Name, (res) => {
+            if (res.Total == 0) {
+                let data = {
+                    Content: [params]
+                };
+                // 查询是否有该模型文件夹
+                // 创建
+                httputils.postJson(`${baseUrl}/model-folder/create`, data, success)
+            } else {
+                Message.error({ message: '该文件夹已经存在!' });
+            }
+        })
+    },
+    //删除模型文件夹
+    /**
+     * 
+     * @param {Id:string} params 
+     */
+    deleteModel(params, success) {
+        let Content = [params];
+        httputils.postJson(`${baseUrl}/model-folder/delete`, Content, success)
+    },
+    //修改模型文件夹名称
+    /**
+    * 
+    * @param {Name:string,ProjectId:string} params 
+    */
+    updateModelName(params, success) {
+        let Name = params.Name;
+        this.queryModel(Name, (res) => {
+            if (res.Total == 0) {
+                let data = {
+                    Content: [params]
+                };
+                // 更改文件夹名称
+                httputils.postJson(`${baseUrl}/model-folder/update`, data, success)
+            } else {
+                Message.error({ message: '该文件夹已经存在!' });
+            }
+        })
+    },
+    //查询模型文件夹
+    /** 
+     * @param Name string  注:查询多个 Name = '' 
+    */
+    queryModel(Name, success) {
+        let data = null;
+        if (Name) {
+            // 单个查询
+            data = {
+                Filters: `Name='${Name}'`
+            }
+        } else {
+            // 多个查询
+            data = {}
+        }
+        return httputils.postJson(`${baseUrl}/model-folder/query`, data, success)
+    },
+
+
+
+    //以下是楼层文件接口
+
+    // 查询模型文件夹下的所有模型文件
+    queryFloorList(data, success) {
+
+        let Filters = `FolderId='${data.FolderId}'`;
+        if (data.FloorName) {
+            Filters = `FolderId='${data.FolderId}';FloorName='${data.FloorName}';ProjectId='${data.ProjectId}'`;
+        }
+        let params = {
+            Filters: Filters
+        }
+        return httputils.postJson(`${baseUrl}/model-floor/query-list`, params, success)
+    },
+    // 查询模型文件夹下的单个模型文件
+    queryFloorItem(data, success) {
+
+        let Filters = `FolderId='${data.FolderId}'`;
+        if (data.FloorName) {
+            Filters = `FolderId='${data.FolderId}';FloorName='${data.FloorName}';ProjectId='${data.ProjectId}'`;
+        }
+        let params = {
+            Filters: Filters
+        }
+        return httputils.postJson(`${baseUrl}/model-floor/query`, params, success)
+    },
+    // 创建楼层
+    createFloor(params) {
+        // 判断该楼层是否存在
+
+        let data = {
+            Content: [{
+                FolderId: params.FolderId,
+                FloorName: params.FloorName,
+                ProjectId: params.ProjectId,      //项目id
+            }]
+        };
+        return new Promise((resolve, preject) => {
+            this.queryFloorItem(params, (res) => {
+                if (res.Total == 0) {
+                    // 创建楼层
+                    httputils.postJson(`${baseUrl}/model-floor/create`, data, (res) => {
+                        let modelFile = {
+                            Content: [{
+                                // ProjectId: params.ProjectId,      //项目id
+                                FloorModelId: res.EntityList[0].Id, //模型所属楼层(FloorModel外键)
+                                ModelName: params.Form.file.name,        //模型文件名
+                                UserName: params.userName,
+                                Note: params.Form.desc
+                                // ReplaceReason: 0
+                            }]
+                        }
+                        //创建模型文件
+                        this.createModelFile(modelFile, (createModelRes) => {
+                            // 与此楼文件进行绑定
+                            let upDateModelData = {
+                                Content: [{
+                                    Id: res.EntityList[0].Id, //id
+                                    CurrentModelId: createModelRes.EntityList[0].Id //该楼层当前的模型id
+                                }]
+                            }
+                            this.updateFloorName(upDateModelData, (upDateModelSucess) => {
+                                if (upDateModelSucess.Result == "success") {
+                                    resolve({
+                                        Result: 'success',
+                                        FloorModelId: res.EntityList[0].Id,   //楼层模型文件
+                                        CurrentModelId: createModelRes.EntityList[0].Id //模型文件id
+                                    })
+                                }
+                            })
+                        })
+                    })
+                } else {
+                    let modelFile = {
+                        Content: [{
+                            // ProjectId: params.ProjectId,      //项目id
+                            FloorModelId: res.Content[0].Id, //模型所属楼层(FloorModel外键)
+                            ModelName: params.Form.file.name,        //模型文件名
+                            UserName: params.userName,
+                            Note: params.Form.desc
+                            // ReplaceReason: 0
+                        }]
+                    }
+                    //创建模型文件
+                    this.createModelFile(modelFile, (createModelRes) => {
+                        // 与此楼文件进行绑定
+                        let upDateModelData = {
+                            Content: [{
+                                Id: res.Content[0].Id, //id
+                                CurrentModelId: createModelRes.EntityList[0].Id //该楼层当前的模型id
+                            }]
+                        }
+                        this.updateFloorName(upDateModelData, (upDateModelSucess) => {
+                            if (upDateModelSucess.Result == "success") {
+                                resolve({
+                                    Result: 'success',
+                                    FloorModelId: res.Content[0].Id,   //楼层模型文件
+                                    CurrentModelId: createModelRes.EntityList[0].Id //模型文件id
+                                })
+                            }
+                        })
+                    })
+                }
+            })
+        })
+    },
+    // 删除楼层文件
+    deleteFloor(data) {
+        return httputils.postJson(`${baseUrl}/model-floor/delete`, data)
+    },
+    //编辑楼层文件的名字
+    updateFloorName(data, success) {
+        return httputils.postJson(`${baseUrl}/model-floor/update`, data, success)
+    },
+
+
+    //以下是楼层文件接口
+
+    // 创建模型文件
+    createModelFile(data, success) {
+        return httputils.postJson(`${baseUrl}/model-file/create`, data, success)
+    },
+    //删除模型文件(只有记录,文件不动)
+    deleteModelFile(data, success) {
+        return httputils.postJson(`${baseUrl}/model-file/delete`, data, success)
+    },
+    /**
+     * info: 删除模型文件
+     * @param {*} params string 模型文件的id 
+     * @param {*} success  成功的回调函数
+     */
+    deleteModelFileList(params, success) {
+        let data = {
+            Id:params
+        } 
+        return httputils.postJson(`${baseUrl}/model-file/delete-file`, data, success)
+    },
+    //查询模型文件 
+    queryModelFile(FloorModelId, success) {
+        let params = {
+            Distince: true,
+            Filters: `FloorModelId='${FloorModelId}'`
+        }
+        return httputils.postJson(`${baseUrl}/model-file/query`, params, success)
+    },
+    // 上传模型文件
+    uploadModelFile(payload, ProjectId,callback1, callback2) {
+        axios({
+            url: baseUrl + '/model-file/upload',
+            method: 'post',
+            headers: {
+                ProjectId: ProjectId
+            },
+            onUploadProgress: function (progressEvent) { //原生获取上传进度的事件
+                if (progressEvent.lengthComputable) {
+                    //属性lengthComputable主要表明总共需要完成的工作量和已经完成的工作是否可以被测量
+                    //如果lengthComputable为false,就获取不到progressEvent.total和progressEvent.loaded
+                    callback1(progressEvent);
+                }
+            },
+            data: payload
+        }).then(res => {
+            callback2(res);
+        }).catch(error => {
+            console.log('this is a catch')
+            console.log(error)
+        })
+    },
+    // 更新模型文件
+    upDateModelFile(data, ProjectId,UserName, callback1, callback2) {
+        let modelFile = {
+            Content: [{
+                FloorModelId:data.replaceModelItem.Id, //模型id
+                ModelName: data.Form.file.name,        //模型名字
+                UserName: UserName,
+                Note: data.replaceModelItem.Note,
+                ReplaceReason: data.Form.ReplaceReason
+            }]
+        }
+        // //创建模型文件
+        this.createModelFile(modelFile, (createModelRes) => {
+            // 与此楼文件进行绑定
+            let upDateModelData = {
+                Content: [{
+                    Id:data.replaceModelItem.Id, //楼层
+                    CurrentModelId: createModelRes.EntityList[0].Id
+                }]
+            }
+            this.updateFloorName(upDateModelData, (upDateModelSucess) => {
+                if (upDateModelSucess.Result == "success") {
+                    // 处理数据
+                    let formData = new FormData();
+                    formData.append(
+                      "model",
+                      JSON.stringify({
+                        FloorModelId: data.replaceModelItem.Id,
+                        Id:createModelRes.EntityList[0].Id
+                      })
+                    );
+                    formData.append("file", data.Form.file.raw);
+                    this.uploadModelFile(formData,ProjectId,callback1,callback2)
+                }
+            })
+        })
+    }
+
+}
+export default api

+ 3 - 4
src/api/scan/httpUtil.js

@@ -20,11 +20,10 @@ function successResponse(vm, response, success, failed) {
 }
 
 function errorResponse(vm, response, err) {
-    let json = JSON.stringify(response)
-    json = JSON.parse(json)
+    let json = JSON.parse(JSON.stringify(response))
     console.error(response)
-    if (err) {
-        Message.error({ message: '接口:' + json.config.url + '请求错误' })
+    if (json.response) {
+        Message.error({ message: `接口:${json.response.config.url}请求错误,错误状态为:${json.response.status}` })
     } else {
         console.error(vm, response, err)
         Message.error({ message: '请求错误' });

+ 63 - 10
src/api/scan/request.js

@@ -4,7 +4,7 @@ import http from './httpUtil'
 let arithmetic = '/arithmetic'
 
 var Comming = 'revit'
-    //获取打印标签模板test
+//获取打印标签模板test
 export function getTest() {
     return fetch({ method: 'GET', url: `${api}/service/template/note_template` })
 }
@@ -393,11 +393,11 @@ export function setHeader(param) {
 //获取头部接口
 export function getHeader(param) {
     let data = {
-            "AppType": Comming,
-            "Code": param.code,
-            "ProjId": param.perjectId
-        }
-        // return fetch({ method: 'POST', url: `${api}/service/dict/equipment_family_info_header`, data })
+        "AppType": Comming,
+        "Code": param.code,
+        "ProjId": param.perjectId
+    }
+    // return fetch({ method: 'POST', url: `${api}/service/dict/equipment_family_info_header`, data })
     return fetch({ method: 'POST', url: `${api}/service/dict/infocode_query_header`, data })
 }
 
@@ -446,7 +446,7 @@ export function getSpaceFloor(param) {
 export function createBusiness(param) {
     let data = param.data
     return fetch({ method: "POST", url: `${physics}/space/create?projectId=${param.ProjId}&secret=${param.secret}`, data })
-        // return fetch({ method: "POST", url: `/test/space/create?projectId=${param.ProjId}&secret=${param.secret}`, data })
+    // return fetch({ method: "POST", url: `/test/space/create?projectId=${param.ProjId}&secret=${param.secret}`, data })
 }
 
 //批量创建业务空间
@@ -496,7 +496,7 @@ export function getGraphyId(param) {
 export function getBussines(param) {
     let data = param.data
     return fetch({ method: "POST", url: `${physics}/object/outside_query?projectId=${param.ProjId}&secret=${param.secret}`, data })
-        // return fetch({ method: "POST", url: `/test/object/outside_query?projectId=${param.ProjId}&secret=${param.secret}`, data })
+    // return fetch({ method: "POST", url: `/test/object/outside_query?projectId=${param.ProjId}&secret=${param.secret}`, data })
 }
 
 //替代前一个接口
@@ -845,6 +845,12 @@ export function getDataDictionary(param, success) {
     http.postJson(url, data, success)
 }
 
+//批量处理字典信息操作
+export function setInfoPoint(param, success) {
+    let url = `${baseUrl}/datacenter/data-dictionary/project/dict-batch`;
+    http.postJson(url, param, success)
+}
+
 //设置项目数据字典显隐 --列表表头
 export function setDataDictionary(param, success) {
     let url = `${baseUrl}/datacenter/data-dictionary/project/setting-dic-project`;
@@ -923,7 +929,7 @@ export function sysLinkEquip(param, success) {
 export function sysUnlinkEquip(param, success) {
     let url = `${baseUrl}/datacenter/sy-in-eq/unlinks-sy-eq`;
     http.postJson(url, param, success)
-} 
+}
 
 //设备清单 - 统计项目下所有设备数量
 export function countEquip(param, success) {
@@ -1040,6 +1046,12 @@ export function queryPhysicsAllType(param, success) {
     http.postJson(url, {}, success)
 }
 
+//查询所有设备族信息
+export function queryFamilyAll( success) {
+    let url = `${baseUrl}/datacenter/data-dictionary/family-query-All`;
+    http.getJson(url, {}, success)
+}
+
 //字典头部信息查询接口
 export function queryDictionaryHead(param, success) {
     let url = `${baseUrl}/datacenter/class-def/query`;
@@ -1192,4 +1204,45 @@ export function dynamicQueryPrompt(param, success) {
 export function dynamicQueryAI(param, success) {
     let url = `${baseUrl}/pointconfig/dynamic/ai`;
     http.postJson(url, param, success)
-}
+}
+
+//动态数据关联-执行对应结果详情
+export function dynamicExecuteDetail(param, success) {
+    let url = `${baseUrl}/pointconfig/dynamic/executeDetail`;
+    http.postJson(url, param, success)
+}
+
+//建筑楼层管理-创建楼层
+export function manageCreateFloor(param, success) {
+    let url = `${baseUrl}/datacenter/floor/create`;
+    http.postJson(url, param, success)
+}
+
+//建筑楼层管理-删除楼层
+export function manageDeleteFloor(param, success) {
+    let url = `${baseUrl}/datacenter/floor/delete`;
+    http.postJson(url, param, success)
+}
+
+//建筑楼层管理-修改楼层
+export function manageUpdateFloor(param, success) {
+    let url = `${baseUrl}/datacenter/floor/update`;
+    http.postJson(url, param, success)
+}
+
+//建筑楼层管理-创建楼层关联关系
+export function createRelationInFloor(param, success) {
+    let url = `${baseUrl}/datacenter/fl-through-fl/link-or`;
+    http.postJson(url, param, success)
+}
+//查询底图
+export function queryBaseGraphy(param, success) {
+    let url = `/modelapi/base-graph/query`;
+    http.postJson(url, param, success)
+}
+//楼层接口-----更新楼层信息
+export function floorUpdate(param, success) {
+    let url = `${baseUrl}/datacenter/floor/update`;
+    http.postJson(url, param, success)
+}
+

+ 0 - 0
src/assets/graphy/SGraphy/dataType.js


+ 78 - 0
src/assets/graphy/SGraphy/dataType.ts

@@ -0,0 +1,78 @@
+import { SPen, SPainter, SColor } from "@sybotan-web/draw";
+import SGraphyPolygonItem from './newItems/SGraphyPolygonItem'
+/**
+ * 接口类型
+ * @param
+ * 传入绘制地图参数的数据类型
+ */
+//path 和paths 的接口类型
+interface dataItemPath {
+    X: number,
+    Y: number,
+    Z: number
+}
+// 一个空间item中的数据类型 
+//包括ColumnList EquipmentList,VirtualWallList,WallList
+interface dataItem {
+    Id: string,
+    Path?: dataItemPath[],
+    PointList: dataItemPath[],
+    BimId?: string,
+    LocationPoint?: dataItemPath,
+    Name?: string,
+    Paths?: dataItemPath[][],
+}
+// 一个空间item中的接口类型 
+// 包括SpaceList
+interface dataSpaceItem {
+    Id: string,
+    // PointList: dataItemPath[],
+    BimId: string,
+    LocationPoint: dataItemPath,
+    Name: string,
+    Paths: dataItemPath[][],
+    id: string,
+    type: number,                  //item类型
+    businessId?: string | null,  //绑定的业务id
+    isBusiness?: number,        //业务类型
+    fillColor?: SColor,         //填充颜色
+    color?: SColor,             //边框颜色
+    businessName?: string | null,  //业务名称
+    width?: number
+}
+// 传入的data 的接口类型 
+interface dataInterface {
+    ColumnList: dataItem[],  //柱体
+    EquipmentList: dataItem[], //设备
+    SpaceList: dataSpaceItem[], //空间
+    VirtualWallList: dataItem[], //虚拟墙
+    WallList: dataItem[],    //墙
+    images: ImgItemInterface[],  //图片
+}
+//获取绑定空间的接口
+interface businessDataInterface {
+    id: string,
+    name: string,
+    children: string[],
+    isAdjacent: boolean,
+    isAbut: boolean
+}
+// 多边形传入的参数接口
+interface PolygonItemInterface {
+    parent: SGraphyPolygonItem | null //父类
+    space: dataSpaceItem,       //传入的item 参数
+    businessType?: string
+}
+// 图片传入的参数接口
+interface ImgItemInterface {
+    parent: SGraphyPolygonItem | null //父类
+    X: number;
+    Y: number;
+    width: number;
+    height: number;
+    img: string;
+    id?: string;
+    name: string;
+}
+
+export { dataItemPath, dataItem, dataSpaceItem, dataInterface, businessDataInterface, PolygonItemInterface, ImgItemInterface }

+ 240 - 0
src/assets/graphy/SGraphy/mainScene.js

@@ -0,0 +1,240 @@
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+import SGraphyPolygonItem from './newItems/SGraphyPolygonItem.js';
+import { SGraphyImgItem } from './newItems/SGraphyImgItem.js';
+import { SGraphyScene } from "@sybotan-web/graphy";
+import Axios from 'axios';
+import pako from "./until/pako.js";
+import tools from "./until/tool.js";
+/**
+ * @name mainScene
+ * @time 2019-07.07;
+ * 添加所有item的场景到scene中
+ */
+var mainScene = /** @class */ (function (_super) {
+    __extends(mainScene, _super);
+    /**
+     * @param data 绘制空间地图得所有参数
+     */
+    function mainScene(data) {
+        var _this_1 = _super.call(this) || this;
+        _this_1._isShowSpace = true; // 是否显示空间;
+        _this_1._isShowWallList = true; //是否展示墙体;
+        _this_1._isShowEquipmentList = true; //是否展示设备;
+        _this_1._isShowVrtualWallList = true; //是否展示虚拟墙
+        _this_1.data = data;
+        if (_this_1.data != null) {
+            _this_1.addAllItemList(_this_1.data);
+        }
+        return _this_1;
+    }
+    Object.defineProperty(mainScene.prototype, "isShowSpace", {
+        // 设置是否显示空间
+        get: function () {
+            return this._isShowSpace;
+        },
+        set: function (b) {
+            this._isShowSpace = b;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(mainScene.prototype, "isShowWallList", {
+        // 设置是否显示墙
+        get: function () {
+            return this._isShowWallList;
+        },
+        set: function (b) {
+            this._isShowWallList = b;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(mainScene.prototype, "isShowEquipmentList", {
+        // 设置是否显示设备
+        get: function () {
+            return this._isShowEquipmentList;
+        },
+        set: function (b) {
+            this._isShowEquipmentList = b;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    Object.defineProperty(mainScene.prototype, "isShowVrtualWallList", {
+        // 设置是否显示虚拟墙
+        get: function () {
+            return this._isShowVrtualWallList;
+        },
+        set: function (b) {
+            this._isShowVrtualWallList = b;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    //获取参数
+    mainScene.prototype.urlGetData = function (url) {
+        var _this_1 = this;
+        var that = this;
+        return new Promise(function (relove, reject) {
+            Axios({
+                method: 'get',
+                url: url,
+                data: {},
+                responseType: 'blob',
+            }).then(function (res) {
+                var blob = res.data;
+                _this_1.zipToJson(blob).then(function (jsonData) {
+                    that.addAllItemList(jsonData);
+                    relove();
+                }).catch(function (error) {
+                    console.log(error);
+                });
+                // console.log(reader)
+            }).catch(function (res) {
+                console.log(res);
+            });
+        });
+    };
+    // 压缩包变为json格式数据
+    mainScene.prototype.zipToJson = function (blob) {
+        var data = null;
+        var reader = new FileReader();
+        reader.readAsBinaryString(blob);
+        var _this = this;
+        return new Promise(function (resolve) {
+            reader.onload = function (readerEvt) {
+                var binaryString = readerEvt.target.result;
+                //解压数据
+                var base64Data = btoa(binaryString);
+                var unGzipData = pako.unzip(base64Data);
+                data = unGzipData;
+                if (data.WallList && data.WallList.length) {
+                    tools.changeMap(data.WallList, -1, "PointList");
+                }
+                if (data.SpaceList && data.SpaceList.length) {
+                    tools.changeMap(data.SpaceList, -1, "Paths");
+                }
+                if (data.ColumnList && data.ColumnList.length) {
+                    tools.changeMap(data.ColumnList, -1, "Path");
+                }
+                if (data.VirtualWallList && data.VirtualWallList.length) {
+                    tools.changeMap(data.VirtualWallList, -1, "PointList");
+                }
+                if (data.EquipmentList && data.EquipmentList.length) {
+                    tools.changeMap(data.EquipmentList, -1, "PointList");
+                }
+                resolve(data);
+            };
+        });
+    };
+    // 以下是绘制方法
+    /**
+     * 增添所有绘制item(地图);
+    */
+    mainScene.prototype.addAllItemList = function (data) {
+        var space = data.SpaceList;
+        // let wall:
+        this.addSpaceList(space); //绘制空间
+        this.addWallList(); //绘制墙
+        var images = data.images;
+        this.addImageList(images);
+    };
+    /**
+     * 添加所有空间到scene 中
+     * @param space 空间list
+     */
+    mainScene.prototype.addSpaceList = function (space) {
+        if (space && space.length) {
+            for (var i = 0; i < space.length; i++) {
+                if (space[i].Paths[1] && space[i].Paths[1].length >= 2) {
+                    this.addItem(this.constructeItem({
+                        parent: null,
+                        space: space[i],
+                        businessType: 'space'
+                    }));
+                }
+            }
+            for (var i = 0; i < space.length; i++) {
+                if (space[i].Paths[0] && space[i].Paths[0].length >= 2 && !space[i].Paths[1]) {
+                    this.addItem(this.constructeItem({
+                        parent: null,
+                        space: space[i],
+                        businessType: 'space'
+                    }));
+                }
+            }
+        }
+    };
+    // 绘制墙体
+    mainScene.prototype.addWallList = function () {
+    };
+    // 绘制设备
+    mainScene.prototype.addEquipmentList = function () {
+    };
+    // 绘制柱体
+    mainScene.prototype.addColumnListList = function () {
+    };
+    // 绘制虚拟墙
+    mainScene.prototype.addVrtualWallList = function () {
+    };
+    // 绘制图片
+    mainScene.prototype.addImageList = function (imageList) {
+        var _this_1 = this;
+        if (imageList && imageList.length) {
+            imageList.map(function (t) {
+                _this_1.addItem(new SGraphyImgItem(null, t.img, t.X, t.Y, t.width, t.height));
+            });
+        }
+    };
+    /**
+     * 产生item实例
+     */
+    mainScene.prototype.constructeItem = function (PolygonItemInterfaceData) {
+        return new SGraphyPolygonItem(PolygonItemInterfaceData);
+    };
+    // 鼠标交互类事件
+    // 点击
+    mainScene.prototype.click = function (_this, fn) {
+        this.root.children.forEach(function (item) {
+            item.connect("click", _this, fn);
+        });
+    };
+    // 双击
+    mainScene.prototype.dbclick = function (_this, fn) {
+        this.root.children.forEach(function (item) {
+            item.connect("doubleClick", _this, fn);
+        });
+    };
+    // 按下
+    mainScene.prototype.mouseDown = function (_this, fn) {
+        this.root.children.forEach(function (item) {
+            item.connect("mouseDown", _this, fn);
+        });
+    };
+    //移动
+    mainScene.prototype.mouseMove = function (_this, fn) {
+        this.root.children.forEach(function (item) {
+            item.connect("mouseMove", _this, fn);
+        });
+    };
+    // 点解结束
+    mainScene.prototype.mouseUp = function (_this, fn) {
+        this.root.children.forEach(function (item) {
+            item.connect("mouseUp", _this, fn);
+        });
+    };
+    return mainScene;
+}(SGraphyScene));
+export default mainScene;

+ 228 - 0
src/assets/graphy/SGraphy/mainScene.ts

@@ -0,0 +1,228 @@
+
+import { SRect, SSize, SPoint } from "@sybotan-web/base";
+import SGraphyPolygonItem from './newItems/SGraphyPolygonItem.js'
+import { SGraphyImgItem } from './newItems/SGraphyImgItem.js'
+import { SGraphyScene, SMouseEvent } from "@sybotan-web/graphy";
+import { SPen, SPainter, SColor } from "@sybotan-web/draw";
+import { dataItemPath, dataItem, dataSpaceItem, dataInterface, PolygonItemInterface, ImgItemInterface } from './dataType'   //传入参数的参数接口类型
+import Axios from 'axios';
+import pako from "./until/pako.js"
+import tools from "./until/tool.js"
+/**
+ * @name mainScene
+ * @time 2019-07.07;
+ * 添加所有item的场景到scene中
+ */
+
+export default class mainScene extends SGraphyScene {
+
+    data: dataInterface | null;
+
+    private _isShowSpace: boolean = true;  // 是否显示空间;
+    private _isShowWallList: boolean = true;  //是否展示墙体;
+    private _isShowEquipmentList: boolean = true; //是否展示设备;
+    private _isShowVrtualWallList: boolean = true; //是否展示虚拟墙
+
+    // 设置是否显示空间
+    get isShowSpace(): boolean {
+        return this._isShowSpace
+    }
+    set isShowSpace(b: boolean) {
+        this._isShowSpace = b
+    }
+
+    // 设置是否显示墙
+    get isShowWallList(): boolean {
+        return this._isShowWallList
+    }
+    set isShowWallList(b: boolean) {
+        this._isShowWallList = b
+    }
+
+    // 设置是否显示设备
+    get isShowEquipmentList(): boolean {
+        return this._isShowEquipmentList
+    }
+    set isShowEquipmentList(b: boolean) {
+        this._isShowEquipmentList = b
+    }
+
+    // 设置是否显示虚拟墙
+    get isShowVrtualWallList(): boolean {
+        return this._isShowVrtualWallList
+    }
+    set isShowVrtualWallList(b: boolean) {
+        this._isShowVrtualWallList = b
+    }
+
+    /**
+     * @param data 绘制空间地图得所有参数
+     */
+
+    constructor(data: dataInterface | null) {
+        super()
+        this.data = data;
+        if (this.data != null) {
+            this.addAllItemList(this.data);
+        }
+    }
+    //获取参数
+    urlGetData(url: string) {
+        let that = this;
+        return new Promise((relove, reject) => {
+            Axios({
+                method: 'get',
+                url: url,
+                data: {},
+                responseType: 'blob',
+                // contentType: "charset=utf-8"
+            }).then(res => {
+                var blob = res.data;
+                this.zipToJson(blob).then((jsonData: any) => {
+                    that.addAllItemList(jsonData)
+                    relove()
+                }).catch((error: any) => {
+                    console.log(error)
+                });
+                // console.log(reader)
+            }).catch(res => {
+                console.log(res)
+            })
+        })
+
+    }
+    // 压缩包变为json格式数据
+    zipToJson(blob: any): any {
+        let data = null;
+        var reader = new FileReader();
+        reader.readAsBinaryString(blob);
+        let _this = this;
+        return new Promise((resolve) => {
+            reader.onload = function (readerEvt: any) {
+                var binaryString = readerEvt.target.result;
+                //解压数据
+                let base64Data = btoa(binaryString)
+                let unGzipData = pako.unzip(base64Data)
+                data = unGzipData;
+                if (data.WallList && data.WallList.length) {
+                    tools.changeMap(data.WallList, -1, "PointList");
+                }
+                if (data.SpaceList && data.SpaceList.length) {
+                    tools.changeMap(data.SpaceList, -1, "Paths");
+                }
+                if (data.ColumnList && data.ColumnList.length) {
+                    tools.changeMap(data.ColumnList, -1, "Path");
+                }
+                if (data.VirtualWallList && data.VirtualWallList.length) {
+                    tools.changeMap(data.VirtualWallList, -1, "PointList");
+                }
+                if (data.EquipmentList && data.EquipmentList.length) {
+                    tools.changeMap(data.EquipmentList, -1, "PointList");
+                }
+                resolve(data)
+            };
+        })
+    }
+    // 以下是绘制方法
+
+    /** 
+     * 增添所有绘制item(地图);
+    */
+    addAllItemList(data: dataInterface) {
+        let space: dataSpaceItem[] = data.SpaceList;
+        // let wall:
+        this.addSpaceList(space) //绘制空间
+        this.addWallList()       //绘制墙
+        let images: ImgItemInterface[] = data.images
+        this.addImageList(images)
+    }
+
+    /**
+     * 添加所有空间到scene 中
+     * @param space 空间list
+     */
+    addSpaceList(space: dataSpaceItem[]): void {
+        if (space && space.length) {
+            for (let i = 0; i < space.length; i++) {
+                if (space[i].Paths[1] && space[i].Paths[1].length >= 2) {
+                    this.addItem(this.constructeItem(
+                        {
+                            parent: null,
+                            space: space[i],
+                            businessType: 'space'
+                        }));
+                }
+            }
+            for (let i = 0; i < space.length; i++) {
+                if (space[i].Paths[0] && space[i].Paths[0].length >= 2 && !space[i].Paths[1]) {
+                    this.addItem(this.constructeItem(
+                        {
+                            parent: null,
+                            space: space[i],
+                            businessType: 'space'
+                        }));
+                }
+            }
+        }
+    }
+    // 绘制墙体
+    addWallList(): void {
+
+    }
+    // 绘制设备
+    addEquipmentList() {
+    }
+    // 绘制柱体
+    addColumnListList(): void {
+    }
+    // 绘制虚拟墙
+    addVrtualWallList(): void {
+    }
+    // 绘制图片
+    addImageList(imageList: ImgItemInterface[]): void {
+        if (imageList && imageList.length) {
+            imageList.map(t => {
+                this.addItem(new SGraphyImgItem(null, t.img, t.X, t.Y, t.width, t.height))
+            })
+        }
+    }
+    /**
+     * 产生item实例
+     */
+    constructeItem(PolygonItemInterfaceData: PolygonItemInterface): SGraphyPolygonItem {
+        return new SGraphyPolygonItem(PolygonItemInterfaceData)
+    }
+    // 鼠标交互类事件
+
+    // 点击
+    click(_this: any, fn: any): void {
+        this.root.children.forEach(item => {
+            item.connect("click", _this, fn);
+        });
+    }
+    // 双击
+    dbclick(_this: any, fn: any): void {
+        this.root.children.forEach(item => {
+            item.connect("doubleClick", _this, fn);
+        });
+    }
+    // 按下
+    mouseDown(_this: any, fn: any) {
+        this.root.children.forEach(item => {
+            item.connect("mouseDown", _this, fn);
+        });
+    }
+    //移动
+    mouseMove(_this: any, fn: any) {
+        this.root.children.forEach(item => {
+            item.connect("mouseMove", _this, fn);
+        });
+    }
+    // 点解结束
+    mouseUp(_this: any, fn: any) {
+        this.root.children.forEach(item => {
+            item.connect("mouseUp", _this, fn);
+        });
+    }
+
+} 

+ 68 - 0
src/assets/graphy/SGraphy/newItems/SGraphyCircleItem.js

@@ -0,0 +1,68 @@
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+import { SGraphyItem } from '@sybotan-web/graphy';
+import { SRect } from "@sybotan-web/base";
+import { SColor } from "@sybotan-web/draw";
+/**
+ * 圆Item类
+ *
+ */
+var SGraphyCircleItem = /** @class */ (function (_super) {
+    __extends(SGraphyCircleItem, _super);
+    /**
+     * 构造函数
+     *
+     * @param r          圆半径
+     * @param width      圆线的宽度
+     * @param color      圆线的颜色
+     * @param fillColor  圆填充的颜色
+     * @param parent
+     */
+    function SGraphyCircleItem(parent, r, fillColor, color, width) {
+        if (fillColor === void 0) { fillColor = SColor.White; }
+        if (color === void 0) { color = SColor.Black; }
+        if (width === void 0) { width = 1; }
+        var _this = _super.call(this, parent) || this;
+        _this.fillColor = SColor.White;
+        _this.color = SColor.Black;
+        _this.width = 1;
+        _this.r = r;
+        _this.color = color;
+        _this.fillColor = fillColor;
+        _this.width = width;
+        return _this;
+    } // Constructor()
+    /**
+     * Item对象边界区域
+     *
+     * @return SRect
+     */
+    SGraphyCircleItem.prototype.boundingRect = function () {
+        return new SRect(-this.r, -this.r, 2 * this.r, 2 * this.r);
+    }; // Function boundingRect()
+    /**
+     * Item绘制操作
+     *
+     * @param   painter       painter对象
+     * @param   rect          绘制区域
+     */
+    SGraphyCircleItem.prototype.onDraw = function (painter, rect) {
+        // painter.pen = new SPen(new SColor("#FF0000"), 22);
+        painter.pen.color = this.color;
+        painter.brush.color = this.fillColor;
+        painter.drawCircle(500, 500, this.r);
+    };
+    return SGraphyCircleItem;
+}(SGraphyItem)); // Class SGraphyCircleItem
+export default SGraphyCircleItem;

+ 65 - 0
src/assets/graphy/SGraphy/newItems/SGraphyCircleItem.ts

@@ -0,0 +1,65 @@
+
+import { SGraphyItem } from '@sybotan-web/graphy';
+import { SRect, SSize } from "@sybotan-web/base";
+import { SPen, SPainter, SColor } from "@sybotan-web/draw";
+
+/**
+ * 圆Item类
+ *
+ */
+export default class SGraphyCircleItem extends SGraphyItem {
+    r: number;
+    fillColor: SColor = SColor.White;
+    color: SColor = SColor.Black;
+    width: number = 1;
+
+    /**
+     * 构造函数
+     *
+     * @param r          圆半径
+     * @param width      圆线的宽度
+     * @param color      圆线的颜色
+     * @param fillColor  圆填充的颜色
+     * @param parent    
+     */
+    constructor(
+        parent: SGraphyItem | null,
+        r: number,
+        fillColor: SColor = SColor.White,
+        color: SColor = SColor.Black,
+        width: number = 1
+    ) {
+        super(parent);
+        this.r = r;
+        this.color = color;
+        this.fillColor = fillColor;
+        this.width = width;
+    } // Constructor()
+
+    /**
+     * Item对象边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect(): SRect {
+        return new SRect(
+            -this.r,
+            -this.r,
+            2 * this.r,
+            2 * this.r
+        );
+    } // Function boundingRect()
+
+    /**
+     * Item绘制操作
+     *
+     * @param   painter       painter对象
+     * @param   rect          绘制区域
+     */
+    onDraw(painter: SPainter, rect?: SRect): void {
+        // painter.pen = new SPen(new SColor("#FF0000"), 22);
+        painter.pen.color = this.color;
+        painter.brush.color = this.fillColor;
+        painter.drawCircle(500, 500, this.r);
+    }
+} // Class SGraphyCircleItem

+ 111 - 0
src/assets/graphy/SGraphy/newItems/SGraphyImgItem.js

@@ -0,0 +1,111 @@
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+import { SGraphyItem } from '@sybotan-web/graphy';
+import { SRect } from "@sybotan-web/base";
+/**
+ * 图形Item类  todo
+ *
+ */
+var SGraphyImgItem = /** @class */ (function (_super) {
+    __extends(SGraphyImgItem, _super);
+    /**
+     * 构造函数
+     *
+     * @param width        		图片宽度
+     * @param height   				图片高度
+     * @param imgSource     	图片源
+     * @param X        				图片向x轴的偏移量
+     * @param Y        				图片向y轴的偏移量
+     * @param parent   				指向父元素
+     */
+    function SGraphyImgItem(parent, imgSource, X, Y, width, height) {
+        var _this = _super.call(this, parent) || this;
+        _this.width = 0;
+        _this.height = 0;
+        _this.imgSource = imgSource;
+        _this.X = X;
+        _this.Y = Y;
+        _this.width = width;
+        _this.height = height;
+        _this.img = new Image();
+        _this.img.src = _this.imgSource;
+        return _this;
+    } // Constructor()
+    /**
+     * Item对象边界区域
+     *
+     * @return SRect
+     */
+    SGraphyImgItem.prototype.boundingRect = function () {
+        return new SRect(this.X, this.Y, this.width, this.height);
+    }; // Function boundingRect()
+    // contains(x: number, y: number): boolean {
+    // 	return this.boundingRect().contains(x - this.X, y - this.Y);
+    // }
+    SGraphyImgItem.prototype.onClick = function (event) {
+        this.$emit('click', event);
+        return true;
+    }; // Function onClick()
+    /**
+  * 鼠标双击事件
+  *
+  * @param   event   保存事件参数
+  * @return  boolean
+  */
+    SGraphyImgItem.prototype.onDoubleClick = function (event) {
+        this.$emit('doubleClick', event);
+        return true;
+    };
+    /**
+  * 鼠标按下事件
+  *
+  * @param   event   保存事件参数
+  * @return  boolean
+  */
+    SGraphyImgItem.prototype.onMouseDown = function (event) {
+        this.$emit('mouseDown', event);
+        return true;
+    }; // Function onMouseDown()
+    /**
+     * 鼠标移动事件
+     *
+     * @param   event   保存事件参数
+     * @return  boolean
+     */
+    SGraphyImgItem.prototype.onMouseMove = function (event) {
+        this.$emit('mouseMove', event);
+        return true;
+    }; // Function onMouseMove()
+    /**
+     * 释放鼠标事件
+     *
+     * @param   event   保存事件参数
+     * @return  boolean
+     */
+    SGraphyImgItem.prototype.onMouseUp = function (event) {
+        this.$emit('mouseUp', event);
+        return true;
+    };
+    /**
+     * Item绘制操作
+     *
+     * @param   painter       painter对象
+     * @param   rect          绘制区域
+     */
+    SGraphyImgItem.prototype.onDraw = function (painter, rect) {
+        painter.drawImage(this.img, this.X, this.Y, this.width, this.height);
+    };
+    return SGraphyImgItem;
+}(SGraphyItem)); // Class SGraphyImgItem
+export { SGraphyImgItem };

+ 116 - 0
src/assets/graphy/SGraphy/newItems/SGraphyImgItem.ts

@@ -0,0 +1,116 @@
+import { SGraphyItem, SMouseEvent } from '@sybotan-web/graphy'
+import { SRect, SSize } from "@sybotan-web/base";
+import { SPen, SPainter, SColor } from "@sybotan-web/draw";
+
+/**
+ * 图形Item类  todo
+ *
+ */
+export class SGraphyImgItem extends SGraphyItem {
+	imgSource: string; //可以为url,base64
+	X: number;
+	Y: number;
+	width: number = 0;
+	height: number = 0;
+	img: CanvasImageSource
+
+	/**
+	 * 构造函数
+	 * 
+	 * @param width        		图片宽度
+	 * @param height   				图片高度
+	 * @param imgSource     	图片源
+	 * @param X        				图片向x轴的偏移量
+	 * @param Y        				图片向y轴的偏移量
+	 * @param parent   				指向父元素
+	 */
+	constructor(
+		parent: SGraphyItem | null,
+		imgSource: string,
+		X: number,
+		Y: number,
+		width: number,
+		height: number,
+	) {
+		super(parent);
+		this.imgSource = imgSource;
+		this.X = X;
+		this.Y = Y;
+		this.width = width;
+		this.height = height;
+		this.img = new Image();
+		this.img.src = this.imgSource;
+	} // Constructor()
+
+	/**
+	 * Item对象边界区域
+	 * 
+	 * @return SRect
+	 */
+	boundingRect(): SRect {
+		return new SRect(
+			this.X,
+			this.Y,
+			this.width,
+			this.height
+		);
+	} // Function boundingRect()
+	// contains(x: number, y: number): boolean {
+	// 	return this.boundingRect().contains(x - this.X, y - this.Y);
+	// }
+	onClick(event: SMouseEvent): boolean {
+		this.$emit('click', event);
+		return true;
+	} // Function onClick()
+	/**
+  * 鼠标双击事件
+  *
+  * @param   event   保存事件参数
+  * @return  boolean
+  */
+	onDoubleClick(event: SMouseEvent): boolean {
+		this.$emit('doubleClick', event);
+		return true;
+	}
+	/**
+  * 鼠标按下事件
+  *
+  * @param   event   保存事件参数
+  * @return  boolean
+  */
+	onMouseDown(event: SMouseEvent): boolean {
+		this.$emit('mouseDown', event);
+		return true;
+	} // Function onMouseDown()
+
+	/**
+	 * 鼠标移动事件
+	 *
+	 * @param   event   保存事件参数
+	 * @return  boolean
+	 */
+	onMouseMove(event: SMouseEvent): boolean {
+		this.$emit('mouseMove', event);
+		return true;
+	} // Function onMouseMove()
+
+	/**
+	 * 释放鼠标事件
+	 *
+	 * @param   event   保存事件参数
+	 * @return  boolean
+	 */
+	onMouseUp(event: SMouseEvent): boolean {
+		this.$emit('mouseUp', event);
+		return true;
+	}
+	/**
+	 * Item绘制操作
+	 *
+	 * @param   painter       painter对象
+	 * @param   rect          绘制区域
+	 */
+	onDraw(painter: SPainter, rect?: SRect): void {
+		painter.drawImage(this.img, this.X, this.Y, this.width, this.height);
+	}
+} // Class SGraphyImgItem

+ 70 - 0
src/assets/graphy/SGraphy/newItems/SGraphyPointItem.js

@@ -0,0 +1,70 @@
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+import { SGraphyItem } from '@sybotan-web/graphy';
+import { SRect, SPoint } from "@sybotan-web/base";
+import { SColor } from "@sybotan-web/draw";
+/**
+ * 坐标点
+ *
+ */
+var SGraphyPointItem = /** @class */ (function (_super) {
+    __extends(SGraphyPointItem, _super);
+    /**
+     * 构造函数
+     *
+     * @param r          圆半径
+     * @param width      圆线的宽度
+     * @param color      圆线的颜色
+     * @param fillColor  圆填充的颜色
+     * @param parent
+     */
+    function SGraphyPointItem(parent, width, point, color, fillColor) {
+        if (width === void 0) { width = 100; }
+        if (point === void 0) { point = new SPoint(0, 0); }
+        if (color === void 0) { color = new SColor('#F56C6C'); }
+        if (fillColor === void 0) { fillColor = new SColor('#F56C6C'); }
+        var _this = _super.call(this, parent) || this;
+        _this.width = 100;
+        _this.width = width;
+        _this.point = point;
+        _this.color = color;
+        _this.fillColor = fillColor;
+        return _this;
+    } // Constructor()
+    /**
+     * Item对象边界区域
+     *
+     * @return SRect
+     */
+    SGraphyPointItem.prototype.boundingRect = function () {
+        var minX = this.point.x;
+        var miny = this.point.y;
+        var maxX = this.point.x + this.width;
+        var maxY = this.point.y + this.width;
+        return new SRect(minX, miny, maxX, maxY);
+    }; // Function boundingRect()
+    /**
+     * Item绘制操作
+     *
+     * @param   painter       painter对象
+     * @param   rect          绘制区域
+     */
+    SGraphyPointItem.prototype.onDraw = function (painter, rect) {
+        painter.pen.color = this.color;
+        painter.brush.color = this.fillColor;
+        painter.drawRect(this.point.x, this.point.y, this.width, this.width);
+    };
+    return SGraphyPointItem;
+}(SGraphyItem)); // Class SGraphyCircleItem
+export default SGraphyPointItem;

+ 67 - 0
src/assets/graphy/SGraphy/newItems/SGraphyPointItem.ts

@@ -0,0 +1,67 @@
+
+import { SGraphyItem } from '@sybotan-web/graphy';
+import { SRect, SSize, SPoint } from "@sybotan-web/base";
+import { SPen, SPainter, SColor } from "@sybotan-web/draw";
+/**
+ * 坐标点
+ *
+ */
+export default class SGraphyPointItem extends SGraphyItem {
+    width: number = 100;
+    point: SPoint;
+    color: SColor;
+    fillColor: SColor;
+
+    /**
+     * 构造函数
+     *
+     * @param r          圆半径
+     * @param width      圆线的宽度
+     * @param color      圆线的颜色
+     * @param fillColor  圆填充的颜色
+     * @param parent    
+     */
+    constructor(
+        parent: SGraphyItem | null,
+        width: number = 100,
+        point: SPoint = new SPoint(0, 0),
+        color: SColor = new SColor('#F56C6C'),
+        fillColor: SColor = new SColor('#F56C6C')
+    ) {
+        super(parent);
+        this.width = width;
+        this.point = point;
+        this.color = color;
+        this.fillColor = fillColor;
+   
+    } // Constructor()
+
+    /**
+     * Item对象边界区域
+     * 
+     * @return SRect
+     */
+    boundingRect(): SRect {
+        let minX = this.point.x;
+        let miny = this.point.y;
+        let maxX = this.point.x + this.width;
+        let maxY = this.point.y + this.width;
+        return new SRect(
+            minX,
+            miny,
+            maxX, maxY
+        );
+    } // Function boundingRect()
+
+    /**
+     * Item绘制操作
+     *
+     * @param   painter       painter对象
+     * @param   rect          绘制区域
+     */
+    onDraw(painter: SPainter, rect?: SRect): void {
+        painter.pen.color = this.color;
+        painter.brush.color = this.fillColor;
+        painter.drawRect(this.point.x,this.point.y,this.width,this.width)
+    }
+} // Class SGraphyCircleItem

+ 212 - 0
src/assets/graphy/SGraphy/newItems/SGraphyPolygonItem.js

@@ -0,0 +1,212 @@
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+import { SGraphyItem } from '@sybotan-web/graphy';
+import { SRect, SPoint } from "@sybotan-web/base";
+import { SColor } from "@sybotan-web/draw";
+/**
+ * 不规则多边形Item类
+ *
+ */
+var SGraphyPolygonItem = /** @class */ (function (_super) {
+    __extends(SGraphyPolygonItem, _super);
+    // actived: boolean = false; 				//是否激活
+    /**
+     * 构造函数
+     *
+     * @param pointArr									点坐标list
+     * @param width											边框的宽度
+     * @param color											边框的颜色
+     * @param fillColor   							多边形填充的颜色
+     * @param businessId								空间id
+     * @param businessName							空间名称
+     * @param centerOfGravityPoint			中心点
+     * @param isBusiness								状态
+     * @param parent
+     */
+    function SGraphyPolygonItem(PolygonItemData) {
+        var _this = _super.call(this, PolygonItemData.parent) || this;
+        _this.fillColor = new SColor('#F2F6FC');
+        _this.color = SColor.Black;
+        _this.width = 200;
+        _this.viewText = ''; //绘出的文案
+        _this.isBusiness = 1;
+        _this.cacheColor = SColor.Black; //需要缓存的边框
+        _this.cacheFillColor = new SColor('#F2F6FC'); //需要缓存的填充色
+        _this.cacheWidth = 100;
+        _this.businessType = ''; //类型
+        // 修改绘制路径格式
+        var newSpacePaths = PolygonItemData.space.Paths[0].map(function (item) {
+            return new SPoint(item.X, item.Y);
+        });
+        _this.pointArr = newSpacePaths;
+        // 填充色
+        _this.fillColor = PolygonItemData.space.fillColor ? PolygonItemData.space.fillColor : new SColor('#F2F6FC');
+        // 边框色
+        _this.color = PolygonItemData.space.color ? PolygonItemData.space.color : SColor.Black;
+        //边框宽度
+        _this.width = PolygonItemData.space.width ? PolygonItemData.space.width : 100;
+        //中心点
+        _this.centerOfGravityPoint = {
+            x: PolygonItemData.space.LocationPoint.X,
+            y: -PolygonItemData.space.LocationPoint.Y
+        };
+        //业务空间类型
+        _this.isBusiness = PolygonItemData.space.isBusiness ? PolygonItemData.space.isBusiness : 1;
+        //业务空间id
+        _this.businessId = PolygonItemData.space.businessId ? PolygonItemData.space.businessId : null;
+        //业务空间名称
+        _this.businessName = PolygonItemData.space.Name;
+        _this.initName = PolygonItemData.space.Name;
+        // 空间id
+        _this.id = PolygonItemData.space.id;
+        _this.viewText = PolygonItemData.space.Name;
+        //类型
+        _this.businessType = PolygonItemData.businessType ? PolygonItemData.businessType : '';
+        return _this;
+    }
+    /**
+     * Item对象边界区域
+     *
+     * @return SRect
+     */
+    SGraphyPolygonItem.prototype.boundingRect = function () {
+        var minX = this.pointArr[0].x;
+        var maxX = minX;
+        var minY = this.pointArr[0].y;
+        var maxY = minY;
+        for (var i = 1; i < this.pointArr.length; i++) {
+            if (this.pointArr[i].x < minX) {
+                minX = this.pointArr[i].x;
+            }
+            if (this.pointArr[i].y < minY) {
+                minY = this.pointArr[i].y;
+            }
+            if (this.pointArr[i].x > maxX) {
+                maxX = this.pointArr[i].x;
+            }
+            if (this.pointArr[i].y > maxY) {
+                maxY = this.pointArr[i].y;
+            }
+        }
+        return new SRect(minX, minY, maxX - minX, maxY - minY);
+    }; // Function boundingRect()
+    /**
+     * 判断点是否在区域内
+     *
+     * @param x
+     * @param y
+     */
+    SGraphyPolygonItem.prototype.contains = function (x, y) {
+        var nCross = 0, point = [x, y], APoints = this.pointArr, length = APoints.length, p1, p2, i, xinters;
+        p1 = APoints[0];
+        for (i = 1; i <= length; i++) {
+            p2 = APoints[i % length];
+            if (point[0] > Math.min(p1.x, p2.x) &&
+                point[0] <= Math.max(p1.x, p2.x)) {
+                if (point[1] <= Math.max(p1.y, p2.y)) {
+                    if (p1.x != p2.x) {
+                        //计算位置信息
+                        xinters = (point[0] - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
+                        if (p1.y == p2.y || point[1] <= xinters) {
+                            nCross++;
+                        }
+                    }
+                }
+            }
+            p1 = p2;
+        }
+        return nCross % 2 === 1;
+    };
+    /**
+     *
+     * @param text 修改的文字
+     * @param centerOfGravityPoint 文字的坐标
+     */
+    SGraphyPolygonItem.prototype.addText = function (text, centerOfGravityPoint) {
+        this.viewText = text;
+        if (centerOfGravityPoint) {
+            this.centerOfGravityPoint = centerOfGravityPoint;
+        }
+    };
+    /**
+     * Item绘制操作
+     *
+     * @param   painter       painter对象
+     * @param   rect          绘制区域
+     */
+    SGraphyPolygonItem.prototype.onDraw = function (painter, rect) {
+        if (this.pointArr.length) {
+            painter.pen.color = this.color;
+            painter.brush.color = this.fillColor;
+            painter.pen.lineWidth = this.width;
+            painter.drawPolygon(this.pointArr);
+            // let text = ''
+            // if (this.businessName || this.businessId) {
+            // 	text = '👇   ' + this.businessName
+            // } else {
+            // 	text = '⬇️   ' + this.initName
+            // }
+            painter.font.size = this.scale * 200;
+            painter.brush.color = SColor.Black;
+            // painter.drawText(text,this.centerOfGravityPoint.x,this.centerOfGravityPoint.y)
+            painter.drawText(this.viewText, this.centerOfGravityPoint.x, this.centerOfGravityPoint.y);
+        }
+    };
+    SGraphyPolygonItem.prototype.onClick = function (event) {
+        this.$emit('click', { item: this, event: event });
+        return true;
+    }; // Function onClick()
+    /**
+  * 鼠标双击事件
+  *
+  * @param   event   保存事件参数
+  * @return  boolean
+  */
+    SGraphyPolygonItem.prototype.onDoubleClick = function (event) {
+        this.$emit('doubleClick', event);
+        return true;
+    };
+    /**
+  * 鼠标按下事件
+  *
+  * @param   event   保存事件参数
+  * @return  boolean
+  */
+    SGraphyPolygonItem.prototype.onMouseDown = function (event) {
+        this.$emit('mouseDown', event);
+        return true;
+    }; // Function onMouseDown()
+    /**
+     * 鼠标移动事件
+     *
+     * @param   event   保存事件参数
+     * @return  boolean
+     */
+    SGraphyPolygonItem.prototype.onMouseMove = function (event) {
+        this.$emit('mouseMove', event);
+        return true;
+    }; // Function onMouseMove()
+    /**
+     * 释放鼠标事件
+     *
+     * @param   event   保存事件参数
+     * @return  boolean
+     */
+    SGraphyPolygonItem.prototype.onMouseUp = function (event) {
+        this.$emit('mouseUp', event);
+        return true;
+    };
+    return SGraphyPolygonItem;
+}(SGraphyItem)); // Class SGraphyPolygonItem
+export default SGraphyPolygonItem;

+ 220 - 0
src/assets/graphy/SGraphy/newItems/SGraphyPolygonItem.ts

@@ -0,0 +1,220 @@
+
+import { SGraphyItem, SMouseEvent } from '@sybotan-web/graphy'
+import { SRect, SSize, SPoint } from "@sybotan-web/base";
+import { SPen, SPainter, SColor, SFont } from "@sybotan-web/draw";
+import { dataItemPath, dataItem, dataSpaceItem, dataInterface, PolygonItemInterface } from './../dataType'   //传入参数的参数接口类型
+/**
+ * 不规则多边形Item类
+ *
+ */
+export default class SGraphyPolygonItem extends SGraphyItem {
+	pointArr: SPoint[];
+	fillColor: SColor = new SColor('#F2F6FC');
+	color: SColor = SColor.Black;
+	width: number = 200;
+	businessId: string | null;
+	id: string | null;
+	centerOfGravityPoint: { x: number, y: number };
+	businessName: null | string | undefined;    //业务空间名字
+	initName: null | string | undefined;        //空间名字
+	viewText: string = ''                        //绘出的文案
+	isBusiness: number = 1;
+	cacheColor: SColor = SColor.Black             //需要缓存的边框
+	cacheFillColor: SColor = new SColor('#F2F6FC');        //需要缓存的填充色
+	cacheWidth: number = 100;
+	businessType: string = ''													//类型
+	// actived: boolean = false; 				//是否激活
+	/**
+	 * 构造函数
+	 *
+	 * @param pointArr									点坐标list
+	 * @param width											边框的宽度
+	 * @param color											边框的颜色
+	 * @param fillColor   							多边形填充的颜色 
+	 * @param businessId								空间id
+	 * @param businessName							空间名称
+	 * @param centerOfGravityPoint			中心点
+	 * @param isBusiness								状态
+	 * @param parent    
+	 */
+	constructor(PolygonItemData: PolygonItemInterface) {
+		super(PolygonItemData.parent);
+		// 修改绘制路径格式
+		let newSpacePaths: SPoint[] = PolygonItemData.space.Paths[0].map(item => {
+			return new SPoint(item.X, item.Y)
+		});
+		this.pointArr = newSpacePaths;
+		// 填充色
+		this.fillColor = PolygonItemData.space.fillColor ? PolygonItemData.space.fillColor : new SColor('#F2F6FC');
+		// 边框色
+		this.color = PolygonItemData.space.color ? PolygonItemData.space.color : SColor.Black;
+		//边框宽度
+		this.width = PolygonItemData.space.width ? PolygonItemData.space.width : 100;
+		//中心点
+		this.centerOfGravityPoint = {
+			x: PolygonItemData.space.LocationPoint.X,
+			y: -PolygonItemData.space.LocationPoint.Y
+		};
+		//业务空间类型
+		this.isBusiness = PolygonItemData.space.isBusiness ? PolygonItemData.space.isBusiness : 1;
+		//业务空间id
+		this.businessId = PolygonItemData.space.businessId ? PolygonItemData.space.businessId : null
+		//业务空间名称
+		this.businessName = PolygonItemData.space.Name;
+		this.initName = PolygonItemData.space.Name;
+		// 空间id
+		this.id = PolygonItemData.space.id;
+		this.viewText = PolygonItemData.space.Name;
+		//类型
+		this.businessType = PolygonItemData.businessType ? PolygonItemData.businessType : ''
+	}
+
+	/**
+	 * Item对象边界区域
+	 * 
+	 * @return SRect
+	 */
+	boundingRect(): SRect {
+		let minX = this.pointArr[0].x;
+		let maxX = minX;
+		let minY = this.pointArr[0].y;
+		let maxY = minY;
+		for (let i = 1; i < this.pointArr.length; i++) {
+			if (this.pointArr[i].x < minX) {
+				minX = this.pointArr[i].x
+			}
+			if (this.pointArr[i].y < minY) {
+				minY = this.pointArr[i].y
+			}
+			if (this.pointArr[i].x > maxX) {
+				maxX = this.pointArr[i].x
+			}
+			if (this.pointArr[i].y > maxY) {
+				maxY = this.pointArr[i].y
+			}
+		}
+
+		return new SRect(
+			minX,
+			minY,
+			maxX - minX,
+			maxY - minY
+		);
+	} // Function boundingRect()
+
+	/**
+	 * 判断点是否在区域内
+	 * 
+	 * @param x 
+	 * @param y 
+	 */
+	contains(x: number, y: number): boolean {
+		let nCross = 0,
+			point = [x, y],
+			APoints = this.pointArr,
+			length = APoints.length,
+			p1, p2, i, xinters;
+		p1 = APoints[0];
+		for (i = 1; i <= length; i++) {
+			p2 = APoints[i % length];
+			if (
+				point[0] > Math.min(p1.x, p2.x) &&
+				point[0] <= Math.max(p1.x, p2.x)
+			) {
+				if (point[1] <= Math.max(p1.y, p2.y)) {
+					if (p1.x != p2.x) {
+						//计算位置信息
+						xinters = (point[0] - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
+						if (p1.y == p2.y || point[1] <= xinters) {
+							nCross++
+						}
+					}
+				}
+			}
+			p1 = p2;
+		}
+		return nCross % 2 === 1
+	}
+	/**
+	 * 
+	 * @param text 修改的文字
+	 * @param centerOfGravityPoint 文字的坐标
+	 */
+	addText(text: string, centerOfGravityPoint?: { x: number, y: number }) {
+		this.viewText = text;
+		if (centerOfGravityPoint) {
+			this.centerOfGravityPoint = centerOfGravityPoint
+		}
+	}
+	/**
+	 * Item绘制操作
+	 *
+	 * @param   painter       painter对象
+	 * @param   rect          绘制区域
+	 */
+	onDraw(painter: SPainter, rect?: SRect): void {
+		if (this.pointArr.length) {
+			painter.pen.color = this.color;
+			painter.brush.color = this.fillColor;
+			painter.pen.lineWidth = this.width;
+			painter.drawPolygon(this.pointArr)
+			// let text = ''
+			// if (this.businessName || this.businessId) {
+			// 	text = '👇   ' + this.businessName
+			// } else {
+			// 	text = '⬇️   ' + this.initName
+			// }
+			painter.font.size = this.scale * 200;
+			painter.brush.color = SColor.Black;
+			// painter.drawText(text,this.centerOfGravityPoint.x,this.centerOfGravityPoint.y)
+			painter.drawText(this.viewText, this.centerOfGravityPoint.x, this.centerOfGravityPoint.y)
+		}
+	}
+	onClick(event: SMouseEvent): boolean {
+		this.$emit('click', { item: this, event: event });
+		return true;
+	} // Function onClick()
+	/**
+  * 鼠标双击事件
+  *
+  * @param   event   保存事件参数
+  * @return  boolean
+  */
+	onDoubleClick(event: SMouseEvent): boolean {
+		this.$emit('doubleClick', event);
+		return true;
+	}
+	/**
+  * 鼠标按下事件
+  *
+  * @param   event   保存事件参数
+  * @return  boolean
+  */
+	onMouseDown(event: SMouseEvent): boolean {
+		this.$emit('mouseDown', event);
+		return true;
+	} // Function onMouseDown()
+
+	/**
+	 * 鼠标移动事件
+	 *
+	 * @param   event   保存事件参数
+	 * @return  boolean
+	 */
+	onMouseMove(event: SMouseEvent): boolean {
+		this.$emit('mouseMove', event);
+		return true;
+	} // Function onMouseMove()
+
+	/**
+	 * 释放鼠标事件
+	 *
+	 * @param   event   保存事件参数
+	 * @return  boolean
+	 */
+	onMouseUp(event: SMouseEvent): boolean {
+		this.$emit('mouseUp', event);
+		return true;
+	}
+
+} // Class SGraphyPolygonItem

+ 74 - 0
src/assets/graphy/SGraphy/newItems/SGraphyRectItem.js

@@ -0,0 +1,74 @@
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+import { SGraphyItem } from '@sybotan-web/graphy';
+import { SRect } from "@sybotan-web/base";
+import { SColor } from "@sybotan-web/draw";
+/**
+ * 矩形Item类
+ *
+ */
+var SGraphyRectItem = /** @class */ (function (_super) {
+    __extends(SGraphyRectItem, _super);
+    /**
+     * 构造函数
+     *
+     * @param startX      线的起始x坐标
+   * @param startY      线的起始y坐标
+   * @param width       矩形的宽度
+   * @param height      矩形的宽度
+     * @param color       矩形边框的颜色
+     * @param fillColor   矩形填充的颜色
+     * @param parent
+   * @param isVirtual   是否为虚线
+     */
+    function SGraphyRectItem(parent, startX, startY, width, height, fillColor, color, isVirtual) {
+        if (fillColor === void 0) { fillColor = SColor.White; }
+        if (color === void 0) { color = SColor.Black; }
+        if (isVirtual === void 0) { isVirtual = false; }
+        var _this = _super.call(this, parent) || this;
+        _this.fillColor = SColor.White;
+        _this.color = SColor.Black;
+        _this.isVirtual = false;
+        _this.startX = startX;
+        _this.startY = startY;
+        _this.width = width;
+        _this.height = height;
+        _this.color = color;
+        _this.fillColor = fillColor;
+        _this.isVirtual = isVirtual;
+        return _this;
+    } // Constructor()
+    /**
+     * Item对象边界区域
+     *
+     * @return SRect
+     */
+    SGraphyRectItem.prototype.boundingRect = function () {
+        return new SRect(this.startX, this.startY, this.width, this.height);
+    }; // Function boundingRect()
+    /**
+     * Item绘制操作
+     *
+     * @param   painter       painter对象
+     * @param   rect          绘制区域
+     */
+    SGraphyRectItem.prototype.onDraw = function (painter, rect) {
+        // painter.pen = new SPen(this.color, this.width);
+        painter.pen.color = this.color;
+        painter.brush.color = this.fillColor;
+        painter.drawRect(this.startX, this.startY, this.width, this.height);
+    };
+    return SGraphyRectItem;
+}(SGraphyItem)); // Class SGraphyRectItem
+export default SGraphyRectItem;

+ 76 - 0
src/assets/graphy/SGraphy/newItems/SGraphyRectItem.ts

@@ -0,0 +1,76 @@
+
+import { SGraphyItem } from '@sybotan-web/graphy'
+import { SRect, SSize, SPoint } from "@sybotan-web/base";
+import { SPen, SPainter, SColor } from "@sybotan-web/draw";
+
+/**
+ * 矩形Item类
+ *
+ */
+export default class SGraphyRectItem extends SGraphyItem {
+  startX: number;
+  startY: number;
+  width: number;
+  height: number;
+  fillColor: SColor = SColor.White;
+  color: SColor = SColor.Black;
+  isVirtual: boolean = false;
+	/**
+	 * 构造函数
+	 *
+	 * @param startX      线的起始x坐标
+   * @param startY      线的起始y坐标
+   * @param width       矩形的宽度
+   * @param height      矩形的宽度
+	 * @param color       矩形边框的颜色 
+	 * @param fillColor   矩形填充的颜色 
+	 * @param parent    
+   * @param isVirtual   是否为虚线
+	 */
+  constructor(
+    parent: SGraphyItem | null,
+    startX: number,
+    startY: number,
+    width: number,
+    height: number,
+    fillColor: SColor = SColor.White,
+    color: SColor = SColor.Black,
+    isVirtual: boolean = false
+  ) {
+    super(parent);
+    this.startX = startX
+    this.startY = startY
+    this.width = width;
+    this.height = height
+    this.color = color;
+    this.fillColor = fillColor;
+    this.isVirtual = isVirtual;
+  } // Constructor()
+
+	/**
+	 * Item对象边界区域
+	 * 
+	 * @return SRect
+	 */
+  boundingRect(): SRect {
+    return new SRect(
+      this.startX,
+      this.startY,
+      this.width,
+      this.height
+    );
+  } // Function boundingRect()
+
+	/**
+	 * Item绘制操作
+	 *
+	 * @param   painter       painter对象
+	 * @param   rect          绘制区域
+	 */
+  onDraw(painter: SPainter, rect?: SRect): void {
+    // painter.pen = new SPen(this.color, this.width);
+    painter.pen.color = this.color;
+    painter.brush.color = this.fillColor;
+    painter.drawRect(this.startX, this.startY, this.width, this.height)
+  }
+} // Class SGraphyRectItem

+ 92 - 0
src/assets/graphy/SGraphy/newItems/SGraphyWallItem.js

@@ -0,0 +1,92 @@
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+import { SGraphyItem } from '@sybotan-web/graphy';
+import { SRect } from "@sybotan-web/base";
+import { SColor } from "@sybotan-web/draw";
+/**
+ * 墙Item类
+ *
+ */
+var SGraphyWallItem = /** @class */ (function (_super) {
+    __extends(SGraphyWallItem, _super);
+    /**
+     * 构造函数
+     *
+     * @param pointArr  		点坐标list
+     * @param isVirtual 		墙类型(实体墙-虚拟墙)
+     * @param color  				墙的颜色
+     * @param fillColor  		墙的填充颜色
+     * @param width   			墙的宽度
+     * @param parent
+     */
+    function SGraphyWallItem(parent, pointArr, isVirtual, fillColor, color, width) {
+        if (isVirtual === void 0) { isVirtual = false; }
+        if (fillColor === void 0) { fillColor = SColor.White; }
+        if (color === void 0) { color = SColor.Black; }
+        if (width === void 0) { width = 1; }
+        var _this = _super.call(this, parent) || this;
+        _this.isVirtual = false;
+        _this.fillColor = SColor.White;
+        _this.color = SColor.Black;
+        _this.width = 1;
+        _this.isVirtual = isVirtual;
+        _this.pointArr = pointArr;
+        _this.color = color;
+        _this.fillColor = fillColor;
+        _this.width = width;
+        return _this;
+    } // Constructor()
+    /**
+     * Item对象边界区域
+     *
+     * @return SRect
+     */
+    SGraphyWallItem.prototype.boundingRect = function () {
+        var minX = this.pointArr[0].x;
+        var maxX = minX;
+        var minY = this.pointArr[0].y;
+        var maxY = minY;
+        for (var i = 1; i < this.pointArr.length; i++) {
+            if (this.pointArr[i].x < minX) {
+                minX = this.pointArr[i].x;
+            }
+            if (this.pointArr[i].y < minY) {
+                minY = this.pointArr[i].y;
+            }
+            if (this.pointArr[i].x > maxX) {
+                maxX = this.pointArr[i].x;
+            }
+            if (this.pointArr[i].y > maxY) {
+                maxY = this.pointArr[i].y;
+            }
+        }
+        return new SRect(minX, minY, maxX - minX, maxY - minY);
+    }; // Function boundingRect()
+    /**
+     * Item绘制操作
+     *
+     * @param   painter       painter对象
+     * @param   rect          绘制区域
+     */
+    SGraphyWallItem.prototype.onDraw = function (painter, rect) {
+        if (this.pointArr.length) {
+            // painter.pen = new SPen(this.color, this.width);
+            painter.pen.color = this.color;
+            painter.brush.color = this.fillColor;
+            painter.drawPolyline(this.pointArr);
+        }
+    };
+    return SGraphyWallItem;
+}(SGraphyItem)); // Class SGraphyPolygonItem
+export default SGraphyWallItem;

+ 89 - 0
src/assets/graphy/SGraphy/newItems/SGraphyWallItem.ts

@@ -0,0 +1,89 @@
+
+import { SGraphyItem } from '@sybotan-web/graphy'
+import { SRect, SSize, SPoint } from "@sybotan-web/base";
+import { SPen, SPainter, SColor } from "@sybotan-web/draw";
+
+/**
+ * 墙Item类
+ *
+ */
+export default class SGraphyWallItem extends SGraphyItem {
+	pointArr: SPoint[];
+	isVirtual: boolean = false;
+	fillColor: SColor = SColor.White;
+	color: SColor = SColor.Black;
+	width: number = 1;
+	/**
+	 * 构造函数
+	 *
+	 * @param pointArr  		点坐标list
+	 * @param isVirtual 		墙类型(实体墙-虚拟墙)
+	 * @param color  				墙的颜色
+	 * @param fillColor  		墙的填充颜色
+	 * @param width   			墙的宽度
+	 * @param parent    
+	 */
+	constructor(
+		parent: SGraphyItem | null,
+		pointArr: SPoint[],
+		isVirtual: boolean = false,
+		fillColor: SColor = SColor.White,
+		color: SColor = SColor.Black,
+		width: number = 1,
+	) {
+		super(parent);
+		this.isVirtual = isVirtual;
+		this.pointArr = pointArr;
+		this.color = color;
+		this.fillColor = fillColor;
+		this.width = width;
+	} // Constructor()
+
+	/**
+	 * Item对象边界区域
+	 * 
+	 * @return SRect
+	 */
+	boundingRect(): SRect {
+		let minX = this.pointArr[0].x;
+		let maxX = minX;
+		let minY = this.pointArr[0].y;
+		let maxY = minY;
+		for (let i = 1; i < this.pointArr.length; i++) {
+			if (this.pointArr[i].x < minX) {
+				minX = this.pointArr[i].x
+			}
+			if (this.pointArr[i].y < minY) {
+				minY = this.pointArr[i].y
+			}
+			if (this.pointArr[i].x > maxX) {
+				maxX = this.pointArr[i].x
+			}
+			if (this.pointArr[i].y > maxY) {
+				maxY = this.pointArr[i].y
+			}
+		}
+
+		return new SRect(
+			minX,
+			minY,
+			maxX - minX,
+			maxY - minY
+		);
+	} // Function boundingRect()
+
+	/**
+	 * Item绘制操作
+	 *
+	 * @param   painter       painter对象
+	 * @param   rect          绘制区域
+	 */
+	onDraw(painter: SPainter, rect?: SRect): void {
+		if (this.pointArr.length) {
+			// painter.pen = new SPen(this.color, this.width);
+			painter.pen.color = this.color;
+			painter.brush.color = this.fillColor;
+			painter.drawPolyline(this.pointArr)
+		}
+	}
+} // Class SGraphyPolygonItem

+ 25 - 0
src/assets/graphy/SGraphy/until/pako.js

@@ -0,0 +1,25 @@
+// import pako from 'pako'
+var pako = require('pako');
+var funcTo = atob;
+console.log(funcTo);
+var pakoObj = {
+    unzip: function unzip(b64Data) {
+        // console.log(b64Data)
+        var strData = funcTo(b64Data);
+        // Convert binary string to character-number array
+        var charData = strData.split('').map(function (x) { return x.charCodeAt(0); });
+        // console.log("charData", charData)
+        // Turn number array into byte-array
+        var binData = new Uint8Array(charData);
+        // // unzip
+        var data = pako.inflate(binData, { to: 'string' });
+        return eval("(" + data + ")");
+    },
+    // 压缩
+    zip: function (str) {
+        //escape(str)  --->压缩前编码,防止中午乱码
+        var binaryString = pako.gzip(escape(str), { to: 'string' });
+        return binaryString;
+    }
+};
+export default pakoObj;

+ 27 - 0
src/assets/graphy/SGraphy/until/pako.ts

@@ -0,0 +1,27 @@
+// import pako from 'pako'
+let pako = require('pako');
+let funcTo = atob
+console.log(funcTo)
+
+const pakoObj = {
+    unzip: function unzip(b64Data:any) {
+        // console.log(b64Data)
+        var strData = funcTo(b64Data);
+        // Convert binary string to character-number array
+        var charData = strData.split('').map(function(x) { return x.charCodeAt(0); });
+        // console.log("charData", charData)
+        // Turn number array into byte-array
+        var binData = new Uint8Array(charData);
+        // // unzip
+        var data = pako.inflate(binData, { to: 'string' });
+        return eval("(" + data + ")");
+    },
+    // 压缩
+    zip: function(str:any) {
+        //escape(str)  --->压缩前编码,防止中午乱码
+        var binaryString = pako.gzip(escape(str), { to: 'string' });
+        return binaryString;
+    }
+}
+
+export default pakoObj

+ 22 - 0
src/assets/graphy/SGraphy/until/tool.js

@@ -0,0 +1,22 @@
+var tools = {
+    changeMap: function (arr, k, name) {
+        var data = arr.map(function (items) {
+            if (items[name] && items[name].length) {
+                items[name].map(function (children) {
+                    if (Array.isArray(children)) {
+                        return children.map(function (res) {
+                            res.Y = res.Y * k;
+                            return res;
+                        });
+                    }
+                    else {
+                        children.Y = children.Y * k;
+                        return children;
+                    }
+                });
+            }
+        });
+        return data;
+    }
+};
+export default tools;

+ 21 - 0
src/assets/graphy/SGraphy/until/tool.ts

@@ -0,0 +1,21 @@
+let tools = {
+    changeMap(arr: any, k: any, name: any) {
+        let data = arr.map((items: any) => {
+            if (items[name] && items[name].length) {
+                items[name].map((children: any) => {
+                    if (Array.isArray(children)) {
+                        return children.map(res => {
+                            res.Y = res.Y * k
+                            return res
+                        })
+                    } else {
+                        children.Y = children.Y * k
+                        return children
+                    }
+                })
+            }
+        })
+        return data
+    }
+}
+export default tools

+ 8 - 7
src/assets/graphy/index.js

@@ -1,13 +1,14 @@
-import SGraphyView from './SGraphy/SGraphyView'
-import SGraphyScene from './SGraphy/SGraphyScene'
-import SGraphyClockItem from './SGraphy/items/SGraphyClockItem'
-import SGraphyRectItem from './SGraphy/items/SGraphyRectItem'
-import SGraphyLineItem from './SGraphy/items/SGraphyLineItem'
-import SGraphyPolygonItem from './SGraphy/items/SGraphyPolygonItem'
+
+import SGraphyPolygonItem from './SGraphy/newItems/SGraphyPolygonItem.js'
 import SGraphyCircleItem from './SGraphy/items/SGraphyCircleItem'
 import SGraphyImageItem from './SGraphy/items/SGraphyImageItem'
 import SGraphyPillarItems from './SGraphy/items/SGraphyPillarItems'
 import SGraphyTextItems from './SGraphy/items/SGraphyTextItems'
 import SGraphyVirtualItem from './SGraphy/items/SGraphyVirtualItem'
+import mainScene from './SGraphy/mainScene.js'
+import SGraphyRectItem from './SGraphy/newItems/SGraphyRectItem.js' 
 
-export { SGraphyView, SGraphyScene, SGraphyClockItem, SGraphyRectItem, SGraphyLineItem, SGraphyPolygonItem, SGraphyCircleItem, SGraphyImageItem, SGraphyPillarItems, SGraphyTextItems, SGraphyVirtualItem }
+import SGraphyView from './SGraphy/SGraphyView';
+import SGraphyScene from './SGraphy/SGraphyScene'
+import SGraphyLineItem from './SGraphy/items/SGraphyLineItem'
+export {SGraphyView,SGraphyScene,SGraphyLineItem,mainScene,SGraphyRectItem, SGraphyPolygonItem, SGraphyCircleItem, SGraphyImageItem, SGraphyPillarItems, SGraphyTextItems, SGraphyVirtualItem }

+ 8 - 0
src/assets/scss/point/point_config/reset.scss

@@ -470,4 +470,12 @@ hr {
 
 .disIne {
     display: inline-block;
+}
+
+input::-webkit-outer-spin-button,
+input::-webkit-inner-spin-button {
+    -webkit-appearance: none;
+}
+input[type="number"]{
+    -moz-appearance: textfield;
 }

+ 1 - 1
src/components/business_space/graphy/business.vue

@@ -141,11 +141,11 @@
         SGraphyScene,
         SGraphyRectItem,
         SGraphyLineItem,
-        SGraphyPolygonItem,
         SGraphyVirtualItem,
         SGraphyImageItem,
         SGraphyPillarItems
     } from "@/assets/graphy";
+    import SGraphyPolygonItem from "@/assets/js/items/SGraphyPolygonItem";
     import pako from '@/assets/pako/pako'
     //ele动画组件
     import tools from "@/utils/scan/tools";

+ 3 - 2
src/components/config_point/dictionaryCascader.vue

@@ -132,7 +132,8 @@ export default {
         data: {
           Filters: "InputMode='M' or InputMode='L'",
           PageNumber: 1,
-          PageSize: 500
+          PageSize: 500,
+          Orders: 'InfoPointName asc'
         },
         type: this.typeRelation[type] || type
       }
@@ -167,7 +168,7 @@ export default {
       })
     },
     changeSelect(val) {
-      let labels = this.$refs.dictCas.currentLabels
+      let labels = this.$refs.dictCas.getCheckedNodes()[0].pathLabels
       this.$emit('change', { val: val, labels: labels })
     },
     //减少请求次数

+ 2 - 0
src/components/config_point/step3_edit/index.vue

@@ -215,6 +215,8 @@ export default {
         basicParams.Specialty = this.dictionaryNames[1]
         basicParams.SystemCode = this.dictionaryData[2]
         basicParams.System = this.dictionaryNames[2]
+        basicParams.EquipmentTypeCode = basicParams.SystemCode  //为了配置从动参取值存储
+        basicParams.EquipmentType = basicParams.System
       }
       let updateParams = {
         data: {

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

@@ -373,6 +373,8 @@ export default {
         basicParams.Specialty = this.dictionaryNames[1]
         basicParams.SystemCode = this.dictionaryData[2]
         basicParams.System = this.dictionaryNames[2]
+        basicParams.EquipmentTypeCode = basicParams.SystemCode //为了配置从动参取值存储
+        basicParams.EquipmentType = basicParams.System
       }
       let otherParams = {}
       switch (type) {

+ 147 - 0
src/components/dialogs/config/infoPoint.vue

@@ -0,0 +1,147 @@
+<template>
+  <el-dialog title="按条件批量配置" :visible.sync="dialog.config" @close="handleClose" width="900px">
+    <el-form ref="dataForm" :model="form" label-width="90px">
+      <el-form-item label="方案:">
+        <el-radio-group v-model="form.SchemeId">
+          <el-radio label="schemeZero">全新设定</el-radio>
+          <el-radio label="schemeOne">预置方案1</el-radio>
+          <!-- <el-radio label="schemeTwo">预置方案2</el-radio> -->
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item v-show="form.SchemeId == 'schemeZero'" label="优先级:">
+        <el-checkbox-group v-model="form.PriorityList">
+          <el-checkbox v-for="item in PriorityList" :key="item.Priority" :label="item.Priority" name="priority">{{ item.name }}</el-checkbox>
+        </el-checkbox-group>
+      </el-form-item>
+      <el-form-item v-show="form.SchemeId == 'schemeZero'" label="一级标签:">
+        <el-checkbox-group v-model="form.FirstNameList">
+          <el-checkbox style="width:99px;" v-for="(item, index) in FirstNameList" :key="index" :label="item.FirstName" name="firstTag"></el-checkbox>
+        </el-checkbox-group>
+      </el-form-item>
+      <el-form-item v-show="form.SchemeId == 'schemeZero'" label="二级标签:">
+        <span style="color:#bbb;font-size:12px;">二级标签暂未提供,如确实需要请联系产品添加。</span>
+      </el-form-item>
+    </el-form>
+    <div slot="footer">
+      <el-button @click="dialog.config = false">取 消</el-button>
+      <el-button type="primary" @click="onSubmit" :loading="loading">确 认</el-button>
+    </div>
+  </el-dialog>
+</template>
+<script>
+import { getDataDictionary, setInfoPoint } from "@/api/scan/request"
+import { mapGetters, mapActions } from "vuex"
+export default {
+  props: {
+    dialog: {
+      type: Object,
+      default: function () {
+        return {
+          config: false
+        };
+      }
+    }
+  },
+  data() {
+    return {
+      form: {
+        SchemeId: 'schemeZero',
+        PriorityList: [],
+        FirstNameList: []
+      },
+      FirstNameList: [],
+      PriorityList: [],
+      loading: false
+    };
+  },
+  created() {
+    this.getInfos()
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId", "secret", "userId"])
+  },
+  methods: {
+    getInfos() {
+      let params1 = {
+        data: {
+          Distinct: true,
+          Filters: "FirstName != ''",
+          Orders: "FirstName desc",
+          PageNumber: 1,
+          PageSize: 1000,
+          Projection: [ "FirstName" ]
+        },
+        type: ""
+      }, params2 = {
+        data: {
+          Distinct: true,
+          Filters: "Priority != '';Priority != 'null'",
+          Orders: "Priority desc",
+          PageNumber: 1,
+          PageSize: 1000,
+          Projection: [ "Priority" ]
+        },
+        type: ""
+      };
+      let promise1 = new Promise((resolve, reject) => {
+        getDataDictionary(params1, res => {
+          resolve(res)
+        })
+      })
+      let promise2 = new Promise((resolve, reject) => {
+        getDataDictionary(params2, res => {
+          resolve(res)
+        })
+      })
+      Promise.all([promise1, promise2]).then(values => {
+        this.FirstNameList = values[0].Content
+        this.PriorityList = values[1].Content.map((item) => {
+          if (item.Priority == "S") {
+            item.name = `(${item.Priority})关键信息`
+            return item
+          } else if (item.Priority == "M") {
+            item.name = `(${item.Priority})次要信息`
+            return item
+          } else if (item.Priority == "R") {
+            item.name = `(${item.Priority})参考信息`
+            return item
+          }
+        })
+      })
+    },
+    //确定
+    onSubmit() {
+      let params = {}
+      this.loading = true
+      if (this.form.SchemeId == 'schemeZero') {
+        params = this.form
+      } else {
+        params = {
+          SchemeId: this.form.SchemeId
+        }
+      }
+      setInfoPoint(params, res => {
+        this.form.SchemeId = 'schemeZero'
+        this.form.FirstNameList = []
+        this.form.PriorityList = []
+        this.dialog.config = false
+        this.loading = false
+        this.$emit('configInfo')
+      })
+    },
+    //弹窗关闭回调
+    handleClose() {
+      this.form.SchemeId = 'schemeZero'
+      this.form.FirstNameList = []
+      this.form.PriorityList = []
+      this.loading = false
+    }
+  }
+};
+</script>
+<style lang="scss">
+  .el-dialog__body {
+    max-height: 420px;
+    overflow-y: auto;
+  }
+</style>

+ 236 - 0
src/components/model/file/addFloorDialog.vue

@@ -0,0 +1,236 @@
+<template>
+  <!-- 新增楼层文件 -->
+  <div id="addFloorDialog">
+    <el-dialog
+      title="新增楼层"
+      :visible.sync="addFloorFileVisible"
+      width="900px"
+      :before-close="handleClose"
+    >
+      <el-form ref="addfloorform" :model="form" label-width="120px">
+        <el-form-item label="模型文件:">
+          <el-upload
+            class="upload-demo"
+            ref="upload"
+            :headers="headers"
+            :data="updataData"
+            action="/modelapi/model-file/upload"
+            :on-preview="handlePreview"
+            :on-remove="handleRemove"
+            :file-list="fileList"
+            :auto-upload="false"
+            :on-change="onChangeUpLoad"
+            :limit="1"
+          >
+            <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
+          </el-upload>
+        </el-form-item>
+        <el-form-item label="模型所属楼层:">
+          <div class="floorModle">
+            <el-select v-model="form.floorTypeVal" placeholder="请选择">
+              <el-option
+                v-for="item in floorType"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              ></el-option>
+            </el-select>
+            <!-- 计数 -->
+            <el-input-number
+              style="margin-left:10px;"
+              v-model="form.floorNum"
+              :min="1"
+              :disabled="form.floorTypeVal == 'RF'"
+              @change="handleChange"
+            ></el-input-number>
+            <!-- 是否夹层 -->
+            <el-checkbox style="margin:0 10px;" v-model="form.haveInterlayer">是否夹层</el-checkbox>
+            <!-- 夹层选择 -->
+            <el-select
+              v-model="form.interlayerTypeVal"
+              :disabled="!form.haveInterlayer"
+              placeholder="请选择"
+            >
+              <el-option
+                v-for="item in interlayerType"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              ></el-option>
+            </el-select>
+          </div>
+        </el-form-item>
+        <el-form-item label="备注信息:">
+          <el-input type="textarea" v-model="form.desc"></el-input>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="onSubmit">确认</el-button>
+          <el-button @click="handleClose">取消</el-button>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import request from "@/api/model/file.js";
+import { mapGetters } from "vuex";
+export default {
+  props: {
+    addFloorFileVisible: Boolean,
+    FolderName: String,
+    floorList: Array,
+    FolderId: String
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId", "userInfo","userId", "secret"])
+  },
+  data() {
+    return {
+      form: {
+        desc: "", //描述
+        floorTypeVal: "F", //楼层类型得值
+        interlayerTypeVal: "M1", //夹层类型得值
+        haveInterlayer: false, //是否有夹层
+        file: null, //上传文件
+        floorNum: 1 //楼层
+      },
+      fileList: [], //上传楼层列表
+      floorType: [
+        {
+          value: "F",
+          label: "正常层(F)"
+        },
+        {
+          value: "RF",
+          label: "屋顶(RF)"
+        },
+        {
+          value: "B",
+          label: "地下(B)"
+        }
+      ],
+      interlayerType: [
+        {
+          value: "M1",
+          label: "夹层M1"
+        },
+        {
+          value: "M2",
+          label: "夹层M2"
+        },
+        {
+          value: "M3",
+          label: "夹层M3"
+        }
+      ],
+      //请求头
+      headers: {
+        ProjectId: ""
+      },
+      updataData: {
+        model: {}
+      }
+    };
+  },
+  methods: {
+    onSubmit() {
+      let FloorName = null;
+      if (this.form.file == null) {
+        this.$message.error("模型文件不能为空!");
+      } else {
+        let FloorName = null;
+        // 根据是否有夹层拼接楼层名
+        if (this.form.haveInterlayer) {
+          if (this.form.floorTypeVal == "RF") {
+            FloorName = this.form.floorTypeVal + this.form.interlayerTypeVal;
+          } else {
+            FloorName =
+              this.form.floorTypeVal + this.form.floorNum + this.form.interlayerTypeVal;
+          }
+        } else {
+          if (this.form.floorTypeVal == "RF") {
+            FloorName = this.form.floorTypeVal;
+          } else {
+            FloorName = this.form.floorTypeVal + this.form.floorNum;
+          }
+        }
+        if(this.floorList.some((item) => {return item.FloorName == FloorName})) {
+          this.$message.error('该楼层名称已存在,请勿重复创建!');
+        } else {
+          let data = {
+            ProjectId: this.projectId,
+            FolderId: this.FolderId,
+            FloorName: FloorName,
+            Form: this.form,
+            userName:this.userInfo.username
+          };
+          request.createFloor(data).then(res => {
+            if (res.Result == "success") {
+              //  创建成功
+              this.$emit("finishCreateFloor", {
+                FloorModelId: res.FloorModelId,
+                CurrentModelId:res.CurrentModelId,
+                Form: this.form
+              });
+              this.handleClose();
+              // this.submitUpload(res.FloorModelId);
+            }
+          });
+        }
+      }
+    },
+    // /上传到服务器/
+    submitUpload(FloorModelId) {
+      this.$refs.upload.submit();
+    },
+    handleClose() {
+      this.$emit("closeAddFloorDia");
+    },
+    // 删除上传文件
+    handleRemove(file, fileList) {
+      this.fileList = []
+      this.form.file = null;
+    },
+    handlePreview(file, fileList) {
+      console.log(file, fileList);
+    },
+    handleChange(file, fileList) {
+      console.log(file, fileList);
+    },
+    // 获取上传文件
+    onChangeUpLoad(file, fileList) {
+      console.log(file, fileList);
+      if (fileList.length) {
+        this.form.file = file;
+      }
+    }
+  },
+  watch: {
+    addFloorFileVisible(val) {
+      if (val) {
+        this.handleRemove();
+        this.form = {
+          desc: "", //描述
+          floorTypeVal: "F", //楼层类型得值
+          interlayerTypeVal: "M1", //夹层类型得值
+          haveInterlayer: false, //是否有夹层
+          file: null, //上传文件
+          floorNum: 1 //楼层
+        };
+      }
+    }
+  },
+  mounted() {
+    this.fileList = [];
+    this.form.file = null;
+  }
+};
+</script>
+<style lang="less">
+#addFloorDialog {
+  .floorModle {
+    display: flex;
+    justify-content: left;
+  }
+}
+</style>

+ 83 - 0
src/components/model/file/addFolder.vue

@@ -0,0 +1,83 @@
+<template>
+  <div id="addFolder">
+    <el-dialog title="提示" :visible.sync="addFolderVisible" width="30%" :before-close="closeDiaLog">
+      <div>
+        <el-form
+          :model="ruleForm"
+          :rules="rules"
+          ref="addFolderModel"
+          label-width="100px"
+          class="demo-ruleForm"
+        >
+          <el-form-item label="文件夹名称" prop="name">
+            <el-input v-model="ruleForm.name" focus></el-input>
+          </el-form-item>
+        </el-form>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="closeDiaLog">取 消</el-button>
+        <el-button type="primary" @click="addFolder">确 定</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import request from "@/api/model/file.js";
+import { mapGetters } from "vuex";
+export default {
+  computed: {
+    ...mapGetters("layout", ["projectId", "userId", "secret"])
+  },
+  props: {
+    addFolderVisible: Boolean,
+    folderName: String
+  },
+  data() {
+    return {
+      ruleForm: {
+        name: ""
+      },
+      rules: {
+        name: [
+          { required: true, message: "文件夹名称不能为空!", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  methods: {
+    closeDiaLog() {
+      this.resetForm();
+      this.$emit("closeAddFolderVisible");
+    },
+    addFolder() {
+      this.$refs["addFolderModel"].validate(valid => {
+        if (valid) {
+          request.createModel({ ProjectId: this.projectId, Name:this.ruleForm.name },res => {
+              this.$message({
+                message: "模型文件夹创建成功",
+                type: "success"
+
+              });
+              // 重新获取文件夹列表
+              this.$emit('getfolderModel')
+              this.closeDiaLog();
+            })
+        } else {
+          return false;
+        }
+      });
+    },
+    resetForm() {
+      this.$refs["addFolderModel"].resetFields();
+    },
+    createModel(Name) {
+      return request.createModel({ ProjectId: this.projectId, Name });
+    }
+  },
+  watch: {
+    folderName: function(val, oldVal) {
+      this.ruleForm.name = val;
+    }
+  }
+};
+</script>

+ 97 - 0
src/components/model/file/changeFolderName.vue

@@ -0,0 +1,97 @@
+<template>
+  <div id="changeFolderName">
+    <el-dialog
+      title="提示"
+      :visible.sync="changeFolderNameVisible"
+      width="30%"
+      :before-close="closeDiaLog"
+    >
+      <div>
+        <el-form
+          :model="ruleForm"
+          :rules="rules"
+          ref="changeFolderModelName"
+          label-width="100px"
+          class="demo-ruleForm"
+        >
+          <el-form-item label="文件夹名称" prop="name">
+            <el-input v-model="ruleForm.name" focus></el-input>
+          </el-form-item>
+        </el-form>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="closeDiaLog">取 消</el-button>
+        <el-button type="primary" @click="changeFolder">确 定</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import request from "@/api/model/file.js";
+import { mapGetters } from "vuex";
+export default {
+  computed: {
+    ...mapGetters("layout", ["projectId", "userId", "secret"])
+  },
+  props: {
+    changeFolderNameVisible: Boolean,
+    folderName: String,
+    currentFolderId: String
+  },
+  data() {
+    return {
+      ruleForm: {
+        name: ""
+      },
+      rules: {
+        name: [
+          { required: true, message: "文件夹名称不能为空!", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  methods: {
+    closeDiaLog() {
+      this.resetForm();
+      this.$emit("closeChangeFolderVisible");
+    },
+    changeFolder() {
+      this.$refs["changeFolderModelName"].validate(valid => {
+        if (valid) {
+          if (this.folderName == this.ruleForm.name) {
+            this.$message({ message: "文件夹名字不可与原来相同!",type:'error' });
+          } else {
+            request.updateModelName(
+              { Name: this.ruleForm.name, Id: this.currentFolderId },
+              () => {
+                this.$message({
+                  message: "模型文件夹创建成功",
+                  type: "success"
+                });
+                // 重新获取文件夹列表
+                this.$emit("finishChangeFolderName");
+                this.closeDiaLog();
+              }
+            );
+          }
+        } else {
+          return false;
+        }
+      });
+    },
+    resetForm() {
+      this.$refs["changeFolderModelName"].resetFields();
+    },
+  },
+  watch: {
+    folderName: function(val, oldVal) {
+      this.ruleForm.name = val;
+    }
+  }
+};
+</script>
+<style scoped >
+.dialog-footer {
+  
+}
+</style>

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

@@ -0,0 +1,234 @@
+<template>
+  <el-table
+    ref="filterTable"
+    :data="tableData"
+    style="width: 100%"
+    :height="maxHeight"
+    :header-cell-style="{background:'#d9d9d9',color:'#2b2b2b'}"
+  >
+    <el-table-column prop="FloorName" label="模型文件" width="180">
+      <template slot-scope="scope">
+        <i class="el-icon-document-checked icon_font"></i>
+        <span style="margin-left: 10px">{{ scope.row.FloorName }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column prop="Note" label="备注" width="180"></el-table-column>
+    <el-table-column prop="Version" label="版本号"></el-table-column>
+    <el-table-column prop="AcceptTime" label="上传时间"></el-table-column>
+    <el-table-column prop="UserName" label="上传人"></el-table-column>
+    <el-table-column prop="address" align="center" label="操作"  width="240">
+      <template slot-scope="scope">
+        <div class="operate" v-show="!scope.row.isDown">
+          <el-button
+            type="primary"
+            size="mini"
+            class="iconfont icon-download"
+            @click="downloadModel(scope.row)"
+          ></el-button>
+          <el-button
+            type="primary"
+            size="mini"
+            class="iconfont icon-replace"
+            @click="repliaceModel(scope.row)"
+          ></el-button>
+          <el-button
+            type="primary"
+            size="mini"
+            class="iconfont icon-Log"
+            @click="queryModelLog(scope.row)"
+          ></el-button>
+        </div>
+        <div
+          :class="[scope.row.Status == 1 || scope.row.Status == 10 || scope.row.Status == 11 || (!scope.row.Status && scope.row.precent == 100)? 'upLoad-loading':'','upLoad']"
+          v-show="scope.row.isDown"
+        >
+          <div class="progress">
+            <el-progress
+              :text-inside="scope.row.Status == 1 || scope.row.Status == 10 || scope.row.Status == 11 || (!scope.row.Status && scope.row.precent == 100)?false:true"
+              :stroke-width="20"
+              :percentage="scope.row.precent"
+              :color="scope.row.Status == 1 || scope.row.Status == 10 || scope.row.Status == 11?'#909399':'#67C23A'"
+            ></el-progress>
+          </div>
+          <div class="progress-right">
+            <!-- <el-button
+              v-show="!scope.row.Status"
+              type="danger"
+              class="iconfont icon-termination"
+              @click="closeUpdate(scope.row)"
+              circle
+            ></el-button>-->
+            <span v-show="!scope.row.Status && scope.row.precent == 100">上传中</span>
+            <span v-show="scope.row.Status == 1">等待检查...</span>
+            <span v-show="scope.row.Status == 10">模型检查中</span>
+            <span v-show="scope.row.Status == 11">未通过检查</span>
+          </div>
+        </div>
+      </template>
+    </el-table-column>
+  </el-table>
+</template>
+<script>
+import { mapGetters } from "vuex";
+export default {
+  props: {
+    tableData: Array,
+    persentList: Array,
+    modelFolderName: String
+  },
+  data() {
+    return {
+      maxHeight: 0
+    };
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId", "userInfo", "userId", "secret"])
+  },
+  methods: {
+    // 查看日志
+    queryModelLog(item) {
+      this.$emit("openModelLog", item);
+    },
+    // 替换日志
+    repliaceModel(item) {
+      if (item.Status != 4) {
+        this.$alert("正在识别模型对象,请稍后再替换。", "替换模型", {
+          confirmButtonText: "确定",
+          callback: action => {
+          }
+        });
+      } else {
+        this.$emit("replaceModel", item);
+      }
+    },
+    filterTag(Id, precent) {
+      this.$refs.filterTable.data.map(item => {
+        if (item.Id == Id) {
+          if (precent >= 100) {
+            // 如过precent == 100 不能关闭进度条,
+            if (precent == 100) {
+              item.precent = 99;
+            } else if (precent == 101) {
+              // 如过precent == 101 则返回结果为suceess 不能关闭进度条,
+              item.precent = 100;
+              item.isDown = false;
+              this.$emit("percentFinish");
+            }
+            return;
+          } else {
+            item.precent = precent;
+          }
+        }
+      });
+    },
+    // 下载模型文件
+    downloadModel(item) {
+      if (item.Url) {
+        let a = document.createElement("a");
+        a.href = item.Url;
+        a.download =`${this.modelFolderName}${item.FloorName}模型文件v${item.Version}.rvt`;
+        a.click();
+      } else {
+        this.$message({
+          message: "该文件夹下没有资源",
+          type: "error"
+        });
+      }
+    },
+    // 停止上传
+    closeUpdate(item) {
+      if (this.userInfo.username == item.UserName) {
+        this.$emit("closeUpdateFile", item);
+      } else {
+        this.$message({
+          message: "您不是该文件的上传者,不能停止该文件上传!",
+          type: "error"
+        });
+      }
+    }
+  },
+  watch: {
+    persentList: {
+      immediate: true,
+      deep: true,
+      handler: function(val, oldVal) {
+        if (val.length != 0) {
+          val.map(item => {
+            if (item.precent != 0) {
+              this.filterTag(item.Id, item.precent);
+            }
+          });
+        }
+      }
+    }
+  },
+  mounted() {
+    this.$nextTick(function() {
+      this.maxHeight = $("#file_moddle_manage").height() - 60; // 获取最外层的高度
+    });
+  }
+};
+</script>
+<style scoped lang="less">
+.box-card {
+  height: 100%;
+  .operate {
+    .iconfont {
+      font-size: 12px;
+      padding: 7px 12px;
+    }
+  }
+  .icon-termination {
+    color: #f56c6c;
+    background: #fff;
+    padding: 0;
+    border: 0;
+    font-size: 20px;
+    margin-left: 5px;
+  }
+  .upLoad {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    padding: 4px 0;
+    .progress {
+      // width: 150px;
+      width: 175px;
+      height: 20px;
+    }
+    .progress-right {
+      height: 20px;
+      line-height: 20px;
+    }
+  }
+  .upLoad-loading {
+    position: relative;
+    justify-content: center;
+    .progress {
+      width: 220px;
+      height: 20px;
+    }
+    .progress-right {
+      position: absolute;
+      left: 50%;
+      top: 50%;
+      transform: translate(-50%, -50%);
+      color: #fff;
+    }
+  }
+}
+/deep/ .el-icon-warning {
+  display: none;
+  // color: transparent;
+}
+/deep/ .el-progress__text {
+  display: none;
+}
+/deep/ .upLoad-loading .el-progress-bar {
+  padding-right: 44px;
+  margin-right: -44px;
+}
+/deep/ .el-progress-bar__inner {
+  text-align: center;
+}
+</style>

+ 127 - 0
src/components/model/file/modelLog.vue

@@ -0,0 +1,127 @@
+<template>
+  <!-- 模型日志弹窗 -->
+  <div id="modelLog">
+    <el-dialog title="模型日志" :visible.sync="modelLogVisible" width="40%" :before-close="handleClose">
+      <div class="bodys">
+        <el-tabs v-model="activeName" type="card" @tab-click="changeModel">
+          <el-tab-pane label="上传日志" name="first">
+            <el-table :data="filterlogData" stripe height="300px" style="width: 100%">
+              <el-table-column prop="Version" label="版本"></el-table-column>
+              <el-table-column prop="CreateTime" label="上传时间"></el-table-column>
+              <el-table-column prop="UserName" label="上传人"></el-table-column>
+              <el-table-column prop="address" label="操作">
+                <template slot-scope="scope">
+                  <el-button @click="handleClick(scope.row)" v-if="!scope.row.Removed" type='primary' size="mini" class="iconfont icon-download"></el-button>
+                  <!-- 需求:先不支持删除 -->
+                  <!-- <el-button @click="deleteModel(scope.row)" v-if="!scope.row.Removed" type='danger' plain size="mini">删除</el-button> -->
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-tab-pane>
+          <el-tab-pane label="工程改造" name="second"></el-tab-pane>
+        </el-tabs>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import request from "@/api/model/file.js";
+export default {
+  props: {
+    modelLogVisible: Boolean,
+    modelFolderName: String,
+    logData: Array
+  },
+  data() {
+    return {
+      dialogVisible: false, //是否显示该弹窗
+      activeName: "first", //默认选择上传日志
+      tableData: [] //列表数据
+    };
+  },
+  computed: {
+    filterlogData: function() {
+      let newLogData = [];
+      if (this.logData.length) {
+        this.logData.forEach(item => {
+          newLogData.push(item);
+        });
+      }
+      return newLogData
+    }
+  },
+  methods: {
+    handleClose(done) {
+      this.$emit("CloseModelLogDia");
+    },
+    handleClick(item) {
+      console.log(item);
+      if (item.Url) {
+        let a = document.createElement("a");
+        a.href = item.Url;
+        a.download =`${this.modelFolderName}${item.FloorName}模型文件v${item.Version}.rvt`;
+        a.click();
+      } else {
+        this.$message({
+          message: "该文件夹下没有资源",
+          type: "error"
+        });
+      }
+    },
+    changeModel() {},
+    /**
+     * 删除模型
+     *
+     */
+    deleteModel(item) {
+      this.$confirm(
+        "此操作只可删除楼层模型文件,已经识别的对象及关系等,暂不可删除。确定删除?",
+        "提示",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }
+      )
+        .then(() => {
+          request.deleteModelFileList(item.Id, res => {
+            if (res.Result == "success") {
+              //  刷新页面
+              this.$emit("deleteFinish");
+              this.$message({
+                type: "success",
+                message: "删除成功!"
+              });
+            } else {
+              this.$message({
+                type: "error",
+                message: res.Result
+              });
+            }
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除"
+          });
+        });
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#modelLog {
+  .bodys {
+    position: relative;
+    padding-bottom: 30px;
+    .delete-model {
+      position: absolute;
+      right: 0;
+      top: 0;
+      z-index: 10;
+    }
+  }
+}
+</style>
+

+ 119 - 0
src/components/model/file/replaceModelDialog.vue

@@ -0,0 +1,119 @@
+ <!-- 替换模型弹窗 -->
+
+<template>
+  <!-- 新增楼层 -->
+  <div id="replaceModel">
+    <el-dialog
+      title="替换模型"
+      :visible.sync="repliceModelVisible"
+      width="30%"
+      :before-close="handleClose"
+    >
+      <el-form ref="form" :model="form" label-width="100px">
+        <el-form-item label="模型文件:">
+          <el-upload
+            class="upload-demo"
+            ref="upload"
+            action="https://jsonplaceholder.typicode.com/posts/"
+            :on-preview="handlePreview"
+            :on-remove="handleRemove"
+            :file-list="fileList"
+            :auto-upload="false"
+            :on-change="onChangeUpLoad"
+            :limit="1"
+          >
+            <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
+          </el-upload>
+        </el-form-item>
+        <el-form-item label="选择模型文件替换原因:">
+          <ul>
+            <li>
+              <el-radio :disabled="isChioce" v-model="form.ReplaceReason" label="0">之前模型画错要修改</el-radio>
+            </li>
+            <li>
+              <el-radio :disabled="isChioce" v-model="form.ReplaceReason" label="1">因工程改造,更新模型文件</el-radio>
+            </li>
+          </ul>
+        </el-form-item>
+        <el-form-item>
+          <div class="dateTime" v-show="form.ReplaceReason == '1'">
+            <p>工程改造竣工时间:</p>
+            <el-date-picker v-model="form.finishTime" type="date" placeholder="选择日期"></el-date-picker>
+          </div>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="onSubmit">确认</el-button>
+          <el-button @click="handleClose">取消</el-button>
+        </el-form-item>
+      </el-form>
+    </el-dialog>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    repliceModelVisible: Boolean,
+    replaceModelItem: Object
+  },
+  data() {
+    return {
+      form: {
+        file: null, //上传文件
+        ReplaceReason: "0",
+        finishTime: ""
+      },
+      isChioce: true, //是否可以选择替换原因
+      fileList: []
+    };
+  },
+  methods: {
+    onSubmit() {
+      if (this.form.file == null) {
+        this.$message.error("模型文件不能为空!");
+      } else {
+        this.$emit("updataModel", {
+          Form: this.form,
+          replaceModelItem: this.replaceModelItem
+        });
+        this.handleClose();
+      }
+    },
+    // /上传到服务器/
+    submitUpload() {
+      this.$refs.upload.submit();
+    },
+    handleClose() {
+      this.$emit("closeReplaceModelDia");
+    },
+    handleRemove(file, fileList) {
+      this.form.file = null;
+      this.fileList = []
+    },
+    handlePreview(file) {
+      console.log(file);
+    },
+    handleChange() {},
+    // 获取上传文件
+    onChangeUpLoad(file, fileList) {
+      if (fileList.length) {
+        this.form.file = file;
+      }
+    }
+  },
+  watch: {
+    repliceModelVisible(val) {
+      if (val) {
+        this.handleRemove();
+      }
+    }
+  }
+};
+</script>
+<style lang="less">
+#addFloorDialog {
+  .floorModle {
+    display: flex;
+    justify-content: left;
+  }
+}
+</style>

+ 96 - 0
src/components/point/dynamicdata/applyLog.vue

@@ -0,0 +1,96 @@
+<template>
+  <el-dialog title="提示" :visible.sync="dialogVisible" width="40%" id="applyRules">
+    <p>按对应规则配置动态参数,已完成!</p>
+    <p>请检查并关注以下实例及相关动态参数,自动配置结果是否正确</p>
+    <div ref="message" style="max-height:400px;overflow-x:hidden;overflow-y:auto;">
+      <div v-for="item in ContentList" :key="item.code" v-show="item.children.length">
+        <p>【{{item.name}}】</p>
+        <div v-for="t in item.children" :key="t.ObjectID+t.Id">
+          <p v-if="t.TypeCode=='Eq'">
+            {{`${t.ObjectLocalName?t.ObjectLocalName:'--'}/${t.ObjectID?t.ObjectID:'--'}/${t.TypeName?t.TypeName:'--'}/${t.BuildLocalName?t.BuildLocalName:'--' }/${t.FloorLocalName?t.FloorLocalName:'--'}/${t.RoomLocalName?t.RoomLocalName:'--'}`}}
+          </p>
+          <p v-if="t.TypeCode=='Ec'">
+            {{`${t.ObjectLocalName?t.ObjectLocalName:'--'}/${t.ObjectID?t.ObjectID:'--'}/${t.TypeName?t.TypeName:'--'}/${t.CascadeEquipLocalName}/${t.BuildLocalName?t.BuildLocalName:'--' }/${t.FloorLocalName?t.FloorLocalName:'--'}/${t.RoomLocalName?t.RoomLocalName:'--'}`}}
+          </p>
+          <p v-if="t.TypeCode=='Sp'">
+            {{`${t.ObjectLocalName?t.ObjectLocalName:'--'}/${t.ObjectID?t.ObjectID:'--'}/${t.TypeName?t.TypeName:'--'}/${t.BuildLocalName?t.BuildLocalName:'--' }/${t.FloorLocalName?t.FloorLocalName:'--'}`}}
+          </p>
+          <p v-if="t.TypeCode=='Sy'">{{`${t.ObjectLocalName?t.ObjectLocalName:'--'}/${t.ObjectID?t.ObjectID:'--'}/${t.TypeName?t.TypeName:'--'}`}}</p>
+          <p>{{`${t.InfomationPoint}/${t.Old}/${t.New}`}}</p>
+          <hr style="margin:10px 0;width:50%;">
+        </div>
+      </div>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button size="small" @click="copy">复制信息</el-button>
+      <el-button size="small" type="primary" @click="dialogVisible=false">关闭</el-button>
+    </span>
+  </el-dialog>
+</template>
+<script>
+
+import {
+  dynamicExecuteDetail // 查询执行日志
+} from "@/api/scan/request";
+export default {
+  data() {
+    return {
+      dialogVisible: false, //弹窗显示与隐藏
+      ContentList: [
+        { name: '人工维护过值的信息点', children: [], code: 'MeterDiff' },
+        { name: '多个表号功能号对应一个信息点,无法执行对应规则,请检查', children: [], code: 'Multiple' },
+      ],
+      typeList: ["MeterDiff", "Multiple"], //此分类索引需与上list保持一致
+    };
+  },
+  methods: {
+    showDialog(Id) {
+      this.dialogVisible = true
+      this.getApplyLog(Id)
+    },
+    handleClose() {
+      this.dialogVisible = false;
+    },
+    //复制信息
+    copy() {
+      let text = this.$refs.message.innerText;
+      let copyUrl = $('<input type="text" />').val(text);//创建一个input框获取需要复制的文本内容
+      copyUrl.appendTo('body');
+      copyUrl.select();
+      document.execCommand("Copy");
+      copyUrl.remove()
+      this.$message.success('复制成功')
+    },
+    //查询执行日志
+    getApplyLog(Id) {
+      let param = {
+        Filters: `Type='Multiple' or Type='MeterDiff';Id='${Id}'`,
+        PageNumber: 1,
+        PageSize: 50
+      }
+      dynamicExecuteDetail(param, res => {
+        res.Content.map(t => {
+          this.ContentList[this.typeList.indexOf(t.Type)].children.push(t)
+        })
+        this.ContentList[1].children = this.unique(this.ContentList[1].children)
+      })
+    },
+    //数组去重
+    unique(arr) {
+      let hash = [];
+      if (arr.length) {
+        for (var i = 0; i < arr.length; i++) {
+          for (var j = i + 1; j < arr.length; j++) {
+            if (arr[i].ObjectID === arr[j].ObjectID && arr[i].InfomationPointCode === arr[j].InfomationPointCode) {
+              ++i;
+              arr[i].New += '/' + arr[j].New
+            }
+          }
+          hash.push(arr[i]);
+        }
+      }
+      return hash;
+    }
+  }
+};
+</script>

+ 107 - 0
src/components/point/dynamicdata/applyRulesDialog-copy.vue

@@ -0,0 +1,107 @@
+<template>
+  <el-dialog title="提示" :visible.sync="dialogVisible" width="30%" @close="handleClose" id="applyRules">
+    <p>对应规则有冲突,请选择处理方式:</p>
+    <div>
+      <el-radio v-model="select" :label="'Old'">保留设备实例中人工维护的动态参数的值</el-radio>
+    </div>
+    <div>
+      <el-radio v-model="select" :label="'New'">按照规则自动覆盖动态参数的值</el-radio>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button size="small" @click="handleClose">取消</el-button>
+      <el-button size="small" type="primary" @click="confirmClash">确认</el-button>
+    </span>
+  </el-dialog>
+</template>
+<script>
+
+import {
+  dynamicPromptobjs, //提示冲突
+  dynamicClashConfirm, //冲突选择确认
+  dynamicExecute, //执行规则
+} from "@/api/scan/request";
+import Vue from 'vue'
+export default {
+  data() {
+    return {
+      dialogVisible: false, //弹窗显示与隐藏
+      tableData: [],
+      activeName: "first", //当前所在tab页
+      finished: false, //未处理所有冲突提示文字
+      force: false, //请求冲突-默认false
+      select: 'New'
+    };
+  },
+  methods: {
+    showDialog(force) {
+      this.force = force
+      if (this.tableData.length) {
+        this.dialogVisible = true;
+      } else {
+        this.rulesConfirm()
+      }
+    },
+    handleClose() {
+      this.dialogVisible = false;
+      this.$emit('cancel')
+    },
+    //查询是否有冲突
+    getPromptobjs() {
+      let param = {
+        Force: this.force
+      }
+      dynamicPromptobjs(param, res => {
+        this.tableData = res.Content;
+        this.$emit('clash', this.tableData.length);
+      })
+    },
+    //确认冲突
+    confirmClash() {
+      let selectedRows = this.tableData.map(t => {
+        t.checked = this.select
+        return t
+      });
+      let param = [];
+      selectedRows.map(t => {
+        let tempObj = {
+          Objs: [t],
+          Points: [t]
+        }
+        param.push(tempObj)
+      })
+      dynamicClashConfirm(param, res => {
+        this.rulesConfirm();
+      })
+    },
+    //执行规则
+    rulesConfirm() {
+      let param = {
+        Force: this.force
+      }
+      dynamicExecute(param, res => {
+        this.$message.success('执行成功');
+        this.dialogVisible = false;
+        let missionID = res.Content[0].Id
+        this.$emit('refresh', missionID)
+      })
+    }
+  },
+  mounted() { },
+  created() {
+    this.getPromptobjs()
+  }
+};
+</script>
+<style lang="scss" scoped>
+#applyRules {
+  /deep/ td.bgf5 {
+    background-color: #f5f7fa;
+  }
+  td p {
+    text-align: center;
+  }
+  /deep/ .el-radio__input.is-checked + .el-radio__label {
+    color: #000;
+  }
+}
+</style>

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

@@ -27,7 +27,7 @@ export default {
   methods: {
     init() {
       this.Datasource = [];
-      let param = { Related: this.Related, typeName: this.typeName };
+      let param = { Related: this.Related, TypeName: this.typeName };
       //数据源
       dynamicDataSource(param, res => {
         if (res.Result == "success") {

+ 63 - 21
src/components/point/dynamicdata/delRelationDialog.vue

@@ -3,36 +3,37 @@
     <span>确定要清除对应关系?</span>
     <div v-loading="loading">
       <div v-show="ltableData.length>1">
-        <div style="margin:10px 0;">有多个设备标识对应了该设备实例,是否一并清除对应关系?</div>
+        <div style="margin:10px 0;">有多个对象标识对应了该对象实例,是否一并清除对应关系?</div>
         <el-row class="bgf5">
           <el-col :span="18">
             <el-table :data="ltableData" style="width: 100%;max-height:400px;" height="calc(100% - 160px)" @selection-change="changeSelection"
               ref="ltable">
-              <el-table-column label="设备标识" align="right" class-name="bgfff">
+              <el-table-column label="对象标识" align="right" class-name="bgfff">
                 <el-table-column label="数据源" prop="Datasource" align="right" class-name="bgfff" show-overflow-tooltip></el-table-column>
                 <el-table-column label="位置标签" prop="LocationFlag" align="right" class-name="bgfff" show-overflow-tooltip>
                   <template slot-scope="scope">
                     <div class="tool-tip">{{scope.row.LocationFlag.toString()}}</div>
                   </template>
                 </el-table-column>
-                <el-table-column label="设备标识" prop="EquipmentMark" align="right" class-name="bgf5" show-overflow-tooltip></el-table-column>
+                <el-table-column label="对象标识" prop="EquipmentMark" align="right" class-name="bgf5" show-overflow-tooltip></el-table-column>
                 <el-table-column type="selection" class-name="bgf5"></el-table-column>
               </el-table-column>
             </el-table>
           </el-col>
           <el-col :span="6">
-            <div class="singleDir pl-10 font-default">设备实例</div>
-            <div class="pl-10 font-default">{{rtableData[0]?rtableData[0].ObjectLocalName:'--'}}</div>
-            <div class="pl-10 font-default">{{rtableData[0]?rtableData[0].BuildLocalName:'--'}}-{{rtableData[0]?rtableData[0].FloorLocalName:'--'}}</div>
-            <div class="pl-10 font-default">{{rtableData[0]?rtableData[0].RoomLocalName:'--'}}</div>
+            <div class="singleDir pl-10 font-default">对象实例</div>
+            <div class="pl-10 font-default">{{rtableData[0]?rtableData[0].ObjectLocalName?rtableData[0].ObjectLocalName:'--':'--'}}</div>
+            <div class="pl-10 font-default">{{rtableData[0]?rtableData[0].BuildLocalName:'--'}}-{{rtableData[0]?rtableData[0].FloorLocalName:'--'}}
+            </div>
+            <div class="pl-10 font-default">{{rtableData[0]?rtableData[0].RoomLocalName?rtableData[0].RoomLocalName:'--':'--'}}</div>
           </el-col>
         </el-row>
       </div>
       <div v-show="rtableData.length>1">
-        <div style="margin:10px 0;">有多个设备实例对应了该设备标识,是否一并清除对应关系?</div>
+        <div style="margin:10px 0;">有多个对象实例对应了该对象标识,是否一并清除对应关系?</div>
         <el-row class="bgf5">
           <el-col :span="6">
-            <div class="singleDir pr-10 font-default tr">设备标识</div>
+            <div class="singleDir pr-10 font-default tr">对象标识</div>
             <div class="pr-10 font-default tr">{{ltableData[0]?ltableData[0].EquipmentMark:'--'}}</div>
             <div class="pr-10 font-default tr">{{ltableData[0]?ltableData[0].LocationFlag.toString():'--'}}</div>
             <div class="pr-10 font-default tr">{{ltableData[0]?ltableData[0].Datasource:'--'}}</div>
@@ -40,18 +41,28 @@
           <el-col :span="18">
             <el-table :data="rtableData" style="width: 100%;max-height:400px;" height="calc(100% - 160px)" @selection-change="changeSelection"
               ref="rtable">
-              <el-table-column label="设备实例" class-name="bgfff">
+              <el-table-column label="对象实例" class-name="bgfff">
                 <el-table-column type="selection" class-name="bgf5"></el-table-column>
-                <el-table-column label="设备实例名称" prop="ObjectLocalName" class-name="bgf5" show-overflow-tooltip></el-table-column>
-                <el-table-column label="设备实例编码" prop="ObjectID" class-name="bgfff" show-overflow-tooltip></el-table-column>
-                <el-table-column label="所在建筑楼层" class-name="bgfff">
+                <el-table-column v-for="(item,index) in rightTableHeader" :label="item.label" :key="item.prop" :class-name="index>0?'bgfff':'bgf5'">
                   <template slot-scope="scope">
-                    <el-tooltip :content="scope.row.BuildLocalName&&scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:''" placement="top">
-                      <div class="tool-tip">{{scope.row.BuildLocalName&&scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:''}}</div>
-                    </el-tooltip>
+                    <div v-if="item.prop=='BuildLocalName'">
+                      <el-tooltip
+                        :content="scope.row.BuildLocalName&&scope.row.BuildLocalName!='null'?scope.row.FloorLocalName&&scope.row.FloorLocalName!='null'?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:''"
+                        placement="top"
+                        :disabled="!(scope.row.BuildLocalName&&scope.row.BuildLocalName!='null'?scope.row.FloorLocalName&&scope.row.FloorLocalName!='null'?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:'')">
+                        <div class="tool-tip">
+                          {{scope.row.BuildLocalName&&scope.row.BuildLocalName!='null'?scope.row.FloorLocalName&&scope.row.FloorLocalName!='null'?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:'--'}}
+                        </div>
+                      </el-tooltip>
+                    </div>
+                    <div v-else>
+                      <el-tooltip :content="scope.row[item.prop]?scope.row[item.prop].toString():''" placement="top"
+                        :disabled="!scope.row[item.prop]">
+                        <div class="tool-tip">{{scope.row[item.prop]?scope.row[item.prop].toString():'--'}}</div>
+                      </el-tooltip>
+                    </div>
                   </template>
                 </el-table-column>
-                <el-table-column label="所在业务空间" prop="RoomLocalName" class-name="bgfff" show-overflow-tooltip></el-table-column>
               </el-table-column>
             </el-table>
           </el-col>
@@ -76,14 +87,45 @@ export default {
       dialogWidth: "20%", //弹窗宽度
       selection: [],
       deleDisabled: true,
-      deleParam: []
+      deleParam: [],
+      allHeaderData: {
+        equip: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象实例编码', prop: "ObjectID" },
+          { label: '所在建筑楼层', prop: "BuildLocalName" },
+          { label: '所在业务空间', prop: "RoomLocalName" },
+        ],
+        parts: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象实例编码', prop: "ObjectID" },
+          { label: '所在建筑楼层', prop: "BuildLocalName" },
+          { label: '所在业务空间', prop: "RoomLocalName" },
+          { label: '所属设备实例', prop: "CascadeEquipLocalName" },
+        ],
+        system: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象实例编码', prop: "ObjectID" },
+        ],
+        space: [
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象实例编码', prop: "ObjectID" },
+          { label: '所在建筑楼层', prop: "BuildLocalName" },
+        ]
+      },
+      rightTableHeader: []
     };
   },
+  props: {
+    typeName: {
+      default: 'equip'
+    }
+  },
   methods: {
     //弹窗显示
     showDialog(row) {
       this.dialogVisible = true;
       this.loading = true;
+      this.rightTableHeader = this.allHeaderData[this.typeName]
       //需先用对象请求接口返回所需对象
       this.getDynamicQueryPrompt(row)
     },
@@ -123,14 +165,14 @@ export default {
         PageNumber: 1,
         PageSize: 500
       }
-      //通过标识查询设备实例
+      //通过标识查询对象实例
       let promise1 = new Promise((resolve, reject) => {
         dynamicQueryPrompt(p1, res => {
           resolve(res)
         })
       })
       let p2 = {
-        Filters: `ObjectID='${row.ObjectID}'`,
+        Filters: `ObjectID='${row.ObjectID}';TypeCode='${row.TypeCode}'`,
         PageNumber: 1,
         PageSize: 500
       }
@@ -205,7 +247,7 @@ export default {
   .tr {
     text-align: right;
   }
-  .tool-tip{
+  .tool-tip {
     white-space: nowrap;
     overflow: hidden;
     text-overflow: ellipsis;

+ 2 - 2
src/components/point/dynamicdata/dictionaryDevice.vue

@@ -1,7 +1,7 @@
 <template>
   <div>
     <el-form>
-      <el-form-item label="数据字典设备类型">
+      <el-form-item :label="`数据字典${typeName}类型`">
         <el-select v-model="SubTypeName" multiple collapse-tags placeholder="全部" filterable @change="changeType">
           <el-option v-for="item in DynEquipList" :key="item" :label="item" :value="item"></el-option>
         </el-select>
@@ -32,7 +32,7 @@ export default {
   },
   methods: {
     init() {
-      let param = { Related: this.Related, typeName: this.typeName };
+      let param = { Related: this.Related, TypeName: this.typeName };
       //数据字典
       dynamicDynEquipList(param, res => {
         if (res.Result == "success") {

+ 16 - 14
src/components/point/dynamicdata/equipRules.vue

@@ -8,7 +8,7 @@
           <el-form ref="form" :model="form" :inline="true">
             <el-row>
               <div class="query-item special">
-                <el-input placeholder="请输入设备标识关键字" v-model="form.EquipmentMark" @keyup.enter.native="queryTableData">
+                <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>
@@ -27,20 +27,20 @@
           </el-form>
         </el-col>
         <el-col :span="1">
-          <el-tooltip class="item" effect="dark" content="填充设备标识与实例对应规则" placement="left">
+          <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-col>
       </el-row>
     </div>
     <el-row>
-      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">点位表中出现的所有设备</el-col>
-      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">对应物理世界中的设备实例</el-col>
+      <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="{background:'#f7f9fb'}">
-        <el-table-column prop="EquipmentMark" label="设备标识" show-overflow-tooltip min-width="100"></el-table-column>
+      <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="100"></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">
@@ -49,13 +49,13 @@
           </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="数字字典设备类型" show-overflow-tooltip min-width="100"></el-table-column>
-        <el-table-column prop="ObjectLocalName" label="对应的设备实例" show-overflow-tooltip min-width="100" class-name="td-bl"></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="100">
           <template slot-scope="scope">
-            <el-tooltip :content="scope.row.BuildLocalName&&scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:''"
+            <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:''}}
+              <div class="tool-tip">{{scope.row.BuildLocalName?scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:scope.row.BuildLocalName:''}}
               </div>
             </el-tooltip>
           </template>
@@ -101,6 +101,11 @@ export default {
   },
   data() {
     return {
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      },
       sourceList: [], //数据源
       DynEquipList: [], //数据字典设备类型
       LocFlagList: [], //位置标签
@@ -243,6 +248,7 @@ export default {
   /deep/ .table-area {
     width: 100%;
     height: calc(100% - 125px);
+    margin-bottom: 10px;
     td div {
       white-space: nowrap;
       text-overflow: ellipsis;
@@ -257,10 +263,6 @@ export default {
       text-overflow: ellipsis;
     }
   }
-  .fr {
-    padding-top: 10px;
-    float: right;
-  }
 }
 </style>
 

+ 70 - 58
src/components/point/dynamicdata/historyDialog.vue

@@ -2,74 +2,42 @@
   <el-dialog title="本次对应记录" :visible.sync="dialogVisible" width="70%" @close="handleClose" id="historyAction" custom-class="act-history">
     <span>提示:可使用Contorl+F 搜索关键字</span>
     <div>
-      <el-table :data="tableData" style="width: 100%;" :show-header="showheader" height="400px">
+      <el-table :data="tableData" style="width: 100%;" :show-header="showheader" height="400px" :cell-style="cellStyle">
         <el-table-column>
-          <el-table-column label="数据源" align="right">
+          <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.Datasource" placement="top">
-                  <div>{{t.Datasource}}</div>
-                </el-tooltip>
-              </div>
-            </template>
-          </el-table-column>
-          <el-table-column label="位置标签" align="right">
-            <template slot-scope="scope">
-              <div v-for="t in scope.row.leftList" :key="t.id">
-                <el-tooltip :content="t.LocationFlag.toString()" placement="top">
-                  <div>{{t.LocationFlag.toString()}}</div>
-                </el-tooltip>
-              </div>
-            </template>
-          </el-table-column>
-          <el-table-column label="设备标识" width="200px" class-name="bgf5" align="right">
-            <template slot-scope="scope">
-              <div v-for="t in scope.row.leftList" :key="t.id">
-                <el-tooltip :content="t.EquipmentMark" placement="top">
-                  <div>{{t.EquipmentMark}}</div>
+                <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>
             </template>
           </el-table-column>
         </el-table-column>
         <el-table-column>
-          <el-table-column label="设备实例名称" width="200px" class-name="bgf5 border-l">
+          <el-table-column v-for="item in showRightHeader" :label="item.label" :key="item.prop">
             <template slot-scope="scope">
               <div v-for="t in scope.row.rightList" :key="t.id">
-                <el-tooltip :content="t.ObjectLocalName" placement="top">
-                  <div>{{t.ObjectLocalName}}</div>
-                </el-tooltip>
-              </div>
-            </template>
-          </el-table-column>
-          <el-table-column label="设备实例编码">
-            <template slot-scope="scope">
-              <div v-for="t in scope.row.rightList" :key="t.id">
-                <el-tooltip :content="t.ObjectID" placement="top">
-                  <div>{{t.ObjectID}}</div>
-                </el-tooltip>
-              </div>
-            </template>
-          </el-table-column>
-          <el-table-column label="所在建筑楼层">
-            <template slot-scope="scope">
-              <div v-for="t in scope.row.rightList" :key="t.id">
-                <el-tooltip
-                  :content="t.BuildLocalName&&t.FloorLocalName&&t.BuildLocalName!='null'&&t.FloorLocalName!='null'?t.BuildLocalName+'-'+t.FloorLocalName:''"
-                  placement="top">
-                  <div>
-                    {{t.BuildLocalName&&t.FloorLocalName&&t.BuildLocalName!='null'&&t.FloorLocalName!='null'?t.BuildLocalName+'-'+t.FloorLocalName:''}}
-                  </div>
-                </el-tooltip>
-              </div>
-            </template>
-          </el-table-column>
-          <el-table-column label="所在业务空间">
-            <template slot-scope="scope">
-              <div v-for="t in scope.row.rightList" :key="t.id">
-                <el-tooltip :content="t.RoomLocalName&&t.RoomLocalName!='null'?t.RoomLocalName:''" placement="top">
-                  <div>{{t.RoomLocalName&&t.RoomLocalName!='null'?t.RoomLocalName:''}}</div>
-                </el-tooltip>
+                <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:'')">
+                    <div>
+                      {{t.BuildLocalName&&t.BuildLocalName!='null'?t.FloorLocalName&&t.FloorLocalName!='null'?t.BuildLocalName+'-'+t.FloorLocalName:t.BuildLocalName:'--'}}
+                    </div>
+                  </el-tooltip>
+                </div>
+                <div v-else-if="item.prop=='RoomLocalName'">
+                  <el-tooltip :content="t.RoomLocalName&&t.RoomLocalName!='null'?t.RoomLocalName:''" placement="top"
+                    :disabled="!(t.RoomLocalName&&t.RoomLocalName!='null')">
+                    <div>{{t.RoomLocalName&&t.RoomLocalName!='null'?t.RoomLocalName:'--'}}</div>
+                  </el-tooltip>
+                </div>
+                <div v-else>
+                  <el-tooltip :content="t[item.prop]?t[item.prop].toString():''" placement="top" :disabled="!t[item.prop]">
+                    <div>{{t[item.prop]?t[item.prop].toString():'--'}}</div>
+                  </el-tooltip>
+                </div>
               </div>
             </template>
           </el-table-column>
@@ -90,11 +58,47 @@ export default {
     return {
       dialogVisible: false, //弹窗显示与隐藏
       showheader: false,
-      tableData: [] //数据list
+      tableData: [], //数据list
+      showLeftHeader: [
+        { label: '数据源', prop: 'Datasource' },
+        { label: '位置标签', prop: 'LocationFlag' },
+        { label: '设备标识', prop: 'EquipmentMark' }
+      ],
+      tableHeader: {
+        equip: [
+          { label: '对象实例名称', prop: 'ObjectLocalName' },
+          { label: '对象实例编码', prop: 'ObjectID' },
+          { label: '所在建筑楼层', prop: 'BuildLocalName' },
+          { label: '所在业务空间', prop: 'RoomLocalName' },
+        ],
+        parts: [
+          { label: '对象实例名称', prop: 'ObjectLocalName' },
+          { label: '对象实例编码', prop: 'ObjectID' },
+          { label: '对象所属设备', prop: 'CascadeEquipLocalName' },
+          { label: '所在建筑楼层', prop: 'BuildLocalName' },
+          { label: '所在业务空间', prop: 'RoomLocalName' },
+        ],
+        system: [
+          { label: '对象实例名称', prop: 'ObjectLocalName' },
+          { label: '对象实例编码', prop: 'ObjectID' }
+        ],
+        space:[
+          { label: '对象实例名称', prop: "ObjectLocalName" },
+          { label: '对象实例编码', prop: "ObjectID" },
+          { label: '所在建筑楼层', prop: "BuildLocalName" },
+        ]
+      }, //所有类型列表头部
+      showRightHeader: [], //实际显示的列表头部
     };
   },
+  props: {
+    typeName: {
+      default: 'equip'
+    }
+  },
   methods: {
     showDialog(data) {
+      this.showRightHeader = this.tableHeader[this.typeName]
       this.tableData = data;
       this.dialogVisible = true;
     },
@@ -114,6 +118,14 @@ export default {
           this.$emit("delSuc");
         }
       });
+    },
+    //渲染中间两列颜色
+    cellStyle(data) {
+      if (data.columnIndex == 2) {
+        return 'background-color:#f5f7fa'
+      } else if (data.columnIndex == 3) {
+        return 'background-color:#f5f7fa;border-left:2px solid #ccc;'
+      }
     }
   },
   mounted() { },

+ 2 - 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
     :props="props" clearable class="location"></el-cascader>
 </template>
 <script>
@@ -30,7 +30,7 @@ export default {
   },
   methods: {
     init() {
-      let param = { Related: this.Related, typeName: this.typeName };
+      let param = { Related: this.Related, TypeName: this.typeName };
       dynamicLocationList(param, res => {
         this.LocationList = res.Content[0].List;
         //添加未明确对象

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

@@ -27,7 +27,7 @@ export default {
   methods: {
     init() {
       this.Datasource = [];
-      let param = { Related: this.Related, typeName: this.typeName };
+      let param = { Related: this.Related, TypeName: this.typeName };
       // 位置标签
       dynamicLocFlagList(param, res => {
         if (res.Result == "success") {

+ 54 - 37
src/components/point/dynamicdata/partsRules.vue

@@ -1,6 +1,5 @@
 
 <template>
-<!-- 部件 -->
   <div id="equipRules">
     <!-- 查询条件 -->
     <div class="query-area">
@@ -8,58 +7,65 @@
         <el-col :span="23">
           <el-form ref="form" :model="form" :inline="true">
             <el-row>
-              <div class="query-item">
-                <el-form-item>
-                  <el-input placeholder="请输入部件标识关键字" v-model="form.EquipmentMark" class="input-with-select">
-                    <el-button slot="append" icon="el-icon-search" @click="queryTableData"></el-button>
-                  </el-input>
-                </el-form-item>
+              <div class="query-item special">
+                <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>数据源</label>
-                <dataSource :Related="true" @change="changeDataSource"></dataSource>
+                <label style="padding-right:9px">数据源</label>
+                <dataSource :Related="null" @change="changeDataSource" :typeName="typeName"></dataSource>
               </div>
               <div class="query-item">
-                <dictionary-device @change="changeDictionary" :Related="true"></dictionary-device>
+                <dictionary-device @change="changeDictionary" :Related="null" :typeName="typeName"></dictionary-device>
               </div>
               <div class="query-item">
-                <label>位置标签</label>
-                <locationFlag :Related="true" @change="changeLocationFlag"></locationFlag>
+                <label style="padding-right:9px">位置标签</label>
+                <locationFlag :Related="null" @change="changeLocationFlag" :typeName="typeName"></locationFlag>
               </div>
             </el-row>
           </el-form>
         </el-col>
         <el-col :span="1">
-          <el-tooltip class="item" effect="dark" content="填充部件标识与实例对应规则" placement="left">
-            <el-button size="small" type="primary" @click="toAddRelation" icon="el-icon-edit-outline" style="float:right;"></el-button>
+          <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-col>
       </el-row>
     </div>
     <el-row>
-      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">点位表中出现的所有部件</el-col>
-      <el-col :span="12" style="padding-left:10px;font-size:13px;border-left:2px solid #000;">对应物理世界中的部件实例</el-col>
+      <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="{background:'#f7f9fb'}">
-        <el-table-column prop="EquipmentMark" label="部件标识" show-overflow-tooltip min-width="100"></el-table-column>
+      <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="100"></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">
-              <span>{{scope.row.LocationFlag.toString()}}</span>
+              <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="数字字典部件类型" show-overflow-tooltip min-width="100"></el-table-column>
-        <el-table-column prop="EquipLocalName" label="对应的部件实例" show-overflow-tooltip min-width="100" class-name="td-bl"></el-table-column>
-        <el-table-column prop="FloorLocalName" label="实例所在建筑楼层" show-overflow-tooltip min-width="100"></el-table-column>
-        <el-table-column prop="RoomLocalName" label="实例所在业务空间" show-overflow-tooltip min-width="200"></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="100">
+          <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="scope.row.Related=='False'"
+              <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>
@@ -71,7 +77,7 @@
       :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"></del-relation-dialog>
+    <del-relation-dialog ref="del" @refresh="refresh" :typeName="'parts'"></del-relation-dialog>
   </div>
 </template>
 <script>
@@ -96,6 +102,11 @@ export default {
   },
   data() {
     return {
+      headerStyle: {
+        backgroundColor: '#e1e4e5',
+        color: '#2b2b2b',
+        lineHeight: '30px'
+      },
       sourceList: [], //数据源
       DynEquipList: [], //数据字典部件类型
       LocFlagList: [], //位置标签
@@ -123,7 +134,10 @@ export default {
     locationFlag
   },
   props: {
-    typeName: {}
+    typeName: {},
+    isPending: {
+      default: false
+    }
   },
   created() {
     this.init();
@@ -132,7 +146,6 @@ export default {
   methods: {
     //获取查询条件-提示信息
     init() {
-      alert(1)
       this.getTableData()
     },
     //清除对应关系
@@ -151,7 +164,7 @@ export default {
     },
     //跳转至填充对应规则
     toAddRelation() {
-      this.$router.push({ path: "equipRela", query: { typeName: this.typeName } });
+      this.$router.push({ path: "partsRela", query: { typeName: this.typeName } });
     },
     //获取表格数据
     getTableData() {
@@ -177,16 +190,15 @@ export default {
       // 查询对应关系(P1)
       dynamicQuery(param, res => {
         this.loading = false;
-        if (res.Result == "success") {
-          this.tableData = res.Content;
-          this.page.total = res.Total;
-        }
+        this.tableData = res.Content;
+        this.page.total = res.PageSize < 50 ? res.PageSize : res.Total;
       });
     },
     //刷新列表
     refresh() {
       this.page.pageNumber = 1;
-      this.getTypeNames();
+      this.$emit('refresh', this.typeName);
+      this.getTableData();
     },
     //数据字典部件类型修改
     changeDictionary(val) {
@@ -231,9 +243,13 @@ export default {
       margin-left: 10px;
     }
   }
+  /deep/ .special .el-input__inner {
+    width: 220px;
+  }
   /deep/ .table-area {
     width: 100%;
     height: calc(100% - 125px);
+    margin-bottom: 10px;
     td div {
       white-space: nowrap;
       text-overflow: ellipsis;
@@ -242,10 +258,11 @@ export default {
     .td-bl {
       border-left: 1px solid #ebeef5;
     }
-  }
-  .fr {
-    padding-top: 10px;
-    float: right;
+    .tool-tip {
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+    }
   }
 }
 </style>

+ 269 - 0
src/components/point/dynamicdata/spaceRules.vue

@@ -0,0 +1,269 @@
+
+<template>
+  <div id="equipRules">
+    <!-- 查询条件 -->
+    <div class="query-area">
+      <el-row>
+        <el-col :span="23">
+          <el-form ref="form" :model="form" :inline="true">
+            <el-row>
+              <div class="query-item special">
+                <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="1">
+          <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-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="100"></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="'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 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
+    };
+  },
+  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: "spaceRela", 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();
+    }
+  },
+  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% - 125px);
+    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>
+

+ 269 - 0
src/components/point/dynamicdata/systemRules.vue

@@ -0,0 +1,269 @@
+
+<template>
+  <div id="equipRules">
+    <!-- 查询条件 -->
+    <div class="query-area">
+      <el-row>
+        <el-col :span="23">
+          <el-form ref="form" :model="form" :inline="true">
+            <el-row>
+              <div class="query-item special">
+                <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="1">
+          <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-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="100"></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="100">
+          <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="'system'"></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
+    };
+  },
+  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: "systemRela", 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();
+    }
+  },
+  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% - 125px);
+    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>
+

+ 33 - 0
src/components/ready/buildfloor/addBuild.vue

@@ -0,0 +1,33 @@
+<template>
+  <el-dialog :title="buildTitle" :visible.sync="buildDialogVis" width="20%" id="messageDialog">
+    <div>
+      <label>建筑名称 : </label>
+      <el-input placeholder="请输入建筑名称" v-model="buildName"></el-input>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button size="small">取消</el-button>
+      <el-button size="small" type="primary" @click="save">确认</el-button>
+    </span>
+  </el-dialog>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      buildName: '',
+      buildDialogVis: false
+    }
+  },
+  props: {
+    buildTitle: {
+      default: "添加建筑"
+    }
+  },
+  methods: {
+    showDialog() {
+      this.buildDialogVis = true
+    },
+    save() { }
+  }
+}
+</script>

+ 80 - 0
src/components/ready/buildfloor/addConnectivity.vue

@@ -0,0 +1,80 @@
+<template>
+  <el-dialog title="楼层贯通关系维护" :visible.sync="connectDialogVis" width="50%" id="messageDialog">
+    <el-row>
+      <div style="line-height:32px;">添加与{{floor.FloorLocalName}}层有贯通关系的楼层 : </div>
+      <div style="width:70%">
+        <bfCascader ref="bfCascader" :FloorID="floor.FloorID"></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 '@/components/ready/buildfloor/buildfloorCascader'
+import { createRelationInFloor } from "@/api/scan/request";
+export default {
+  data() {
+    return {
+      buildName: '',
+      connectDialogVis: false,
+      floor: {}
+    }
+  },
+  components: {
+    bfCascader
+  },
+  methods: {
+    showDialog() {
+      this.connectDialogVis = true
+      this.$nextTick(() => {
+        this.$refs.bfCascader.getCascader()
+        let arr = this.floor.FloorThroughList || [];
+        let value = []
+        if (arr.length) {
+          arr.map(t => {
+            value.push([t.BuildID, t.FloorID])
+          })
+        }
+        this.$refs.bfCascader.value = value
+      })
+    },
+    save() {
+      let arr = this.$refs.bfCascader.value;
+      let param = {
+        FloorId: this.floor.FloorID,
+        FloorOtherIdList: []
+      }
+      arr.map(t => {
+        param.FloorOtherIdList.push(t[1])
+      })
+      createRelationInFloor(param, res => {
+        this.connectDialogVis = false;
+        this.$message.success('关联成功');
+        this.$emit('refresh')
+      })
+    }
+  }
+}
+</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>

+ 55 - 0
src/components/ready/buildfloor/buildfloorCascader.vue

@@ -0,0 +1,55 @@
+<template>
+  <el-cascader v-model="value" :options="options" :props="props" clearable></el-cascader>
+</template>
+<script>
+import { buildingQuery } from "@/api/scan/request";
+export default {
+  data() {
+    return {
+      value: [],
+      props: {
+        multiple: true,
+        value: 'BuildID',
+        label: 'BuildLocalName',
+        children: 'Floor'
+      },
+      options: []
+    }
+  },
+  props: {
+    FloorID: {
+      default: ''
+    }
+  },
+  created() { },
+  methods: {
+    getCascader() {
+      let param = {
+        Cascade: [
+          { Name: "floor" }
+        ],
+        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
+      })
+    },
+  }
+}
+</script>
+<style lang="less" scoped>
+.el-cascader {
+  width: 100%;
+}
+</style>

+ 94 - 0
src/components/ready/buildfloor/formItems.vue

@@ -0,0 +1,94 @@
+<template>
+  <div id="inforsPoint">
+    <el-form ref="ruleForm" :model="form" label-width="150px" :rules="rules" :inline="true" :label-position="'left'">
+      <div v-for="item in InforsList" :key="item.InfoPointCode" style="width:50%;float:left;">
+        <el-form-item :label="item.InfoPointName" :prop="item.InfoPointCode" v-if="all||item.Visible"
+          :class="{FloorTypeSelect:item.InputMode == 'D1'||item.Unit}">
+          <el-input v-model="form[item.Path]" v-if="item.InputMode == 'B1'"></el-input>
+          <el-input v-model="form[item.Path]" v-else-if="item.InputMode == 'A1'||item.InputMode == 'A2'" type="number">
+            <template slot="append" v-if="item.Unit">{{item.Unit}}</template>
+          </el-input>
+          <el-select v-model="form[item.Path]" placeholder="请选择" v-else-if="item.InputMode == 'D1'">
+            <el-option v-for="op in item.options" :key="op.Code" :label="op.Name" :value="op.Code"></el-option>
+          </el-select>
+          <el-input v-model="form[item.Path]"
+            v-else-if="item.InputMode == 'L'||item.InputMode == 'L1'||item.InputMode == 'L2'||item.InputMode == 'M'">
+            <template slot="append" v-if="item.Unit">{{item.Unit}}</template>
+          </el-input>
+          <el-input v-model="form[item.Path]" v-else disabled title="暂不支持"></el-input>
+        </el-form-item>
+      </div>
+    </el-form>
+  </div>
+</template>
+<script>
+import { getDataDictionary } from "@/api/scan/request";
+
+//  v-for="item in InforsList" :key="item.InfoPointCode"
+export default {
+  props: {
+    type: {
+      default: 'Floor'
+    }
+  },
+  data() {
+    return {
+      form: {},
+      InforsList: [],
+      all: true, // 默认显示全部
+      rules: {
+        "FloorLocalName": [
+          { "required": true, "message": "请输入楼层本地名称", "trigger": "blur" }
+        ],
+        "FloorSequenceID": [
+          { "required": true, "message": "请输入楼层顺序号", "trigger": "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getInforsPoint()
+  },
+  methods: {
+    getInforsPoint() {
+      let params = {
+        data: {
+          Orders: "sort asc,InfoPointCode asc",
+          PageNumber: 1,
+          PageSize: 50
+        },
+        type: this.type
+      };
+      getDataDictionary(params, res => {
+        this.InforsList = res.Content.map(item => {
+          if (item.InputMode === 'D1') {
+            item.options = JSON.parse(item.DataSource)
+          }
+          return item
+        })
+      })
+    },
+    submitForm(call) {
+      this.$refs.ruleForm.validate((valid) => {
+        if (valid) {
+          call()
+        } else {
+          return false;
+        }
+      });
+    },
+  }
+};
+</script>
+<style lang="scss" scoped>
+#inforsPoint {
+  .el-form-item {
+    /deep/ label.el-form-item__label {
+      font-size: 12px;
+    }
+  }
+  /deep/ .FloorTypeSelect .el-form-item__content {
+    width: 178px;
+  }
+}
+</style>

+ 6 - 1
src/framework/layout/PageHeader.vue

@@ -66,7 +66,12 @@ export default {
         }
     },
     created() {
-        this.selectedProjectId = this.projectId
+        let localProjectId = localStorage.getItem('projectId')
+        if(this.projects.some((item) => {return item.id == localProjectId})) {
+            this.selectedProjectId = localProjectId
+        } else {
+            this.selectedProjectId = this.projectId
+        }
     },
     mounted() {},
     components: {}

+ 36 - 13
src/router/system.js

@@ -16,6 +16,7 @@ import roleAdm from '@/views/platfrom/role'
 import buildFloor from '@/views/ready/buildfloor'
 import collectsetting from '@/views/ready/collectsetting'
 import buildUser from '@/views/ready/appuser'
+import repetitionGraphy from '@/views/ready/buildfloor/repetitionGraphy'
 
 /**模型管理 */
 import modelFile from '@/views/model/file'
@@ -29,6 +30,9 @@ import objectData from '@/views/point/objectData'
 import integrateReport from '@/views/point/report'
 import dynamicdata from '@/views/point/dynamicdata'
 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 buildTask from '@/views/data_admin/buildTask'
@@ -66,7 +70,7 @@ import supplier from '@/views/manufactor/supplier'
 
 /**市场及商务 */
 const OwnerManage = () =>
-    import ('@/views/market/owner/manage')
+    import('@/views/market/owner/manage')
 
 export default [
     { path: '/', name: '', component: LayoutMain, children: [{ path: '', name: 'blank', component: Dasboard }] },
@@ -79,10 +83,10 @@ export default [
         name: 'LayoutMain',
         component: LayoutMain,
         children: [
-            { path: 'project', name: 'projectAdm', component: projectAdm, meta: { keepAlive: false, breadcrumbs: [{ label: '项目管理' }] }},
-            { path: 'user', name: 'userAdm', component: userAdm, meta: { keepAlive: false, breadcrumbs: [{ label: '人员管理' }] }},
-            { path: 'role', name: 'roleAdm', component: roleAdm, meta: { keepAlive: false, breadcrumbs: [{ label: '角色管理' }] }}
-        ] 
+            { path: 'project', name: 'projectAdm', component: projectAdm, meta: { keepAlive: false, breadcrumbs: [{ label: '项目管理' }] } },
+            { path: 'user', name: 'userAdm', component: userAdm, meta: { keepAlive: false, breadcrumbs: [{ label: '人员管理' }] } },
+            { path: 'role', name: 'roleAdm', component: roleAdm, meta: { keepAlive: false, breadcrumbs: [{ label: '角色管理' }] } }
+        ]
     },
     // 前期准备
     {
@@ -90,10 +94,11 @@ export default [
         name: 'LayoutMain',
         component: LayoutMain,
         children: [
-            { path: 'buildfloor', name: 'buildFloor', component: buildFloor, 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: 'buildfloor', name: 'buildFloor', component: buildFloor, 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: 'buildfloor/repetitionGraphy', name: 'repetitionGraphy', component: repetitionGraphy, meta: { keepAlive: false, breadcrumbs: [{ label: '建筑楼层管理', path: '/ready/buildfloor' }, { label:'平面图维护' }] }}
+        ]
     },
     //模型管理
     {
@@ -141,7 +146,25 @@ export default [
                 path: 'equipRela',
                 name: 'equipRela',
                 component: equipRela,
-                meta: { keepAlive: false, breadcrumbs: [{ label: '系统集成', path: '/point/pointsetting' }, { label: '配置动参从点位取值', path: '/point/dynamicdata' }, { label: '处理未对应实例对象标识'}] }
+                meta: { keepAlive: false, breadcrumbs: [{ label: '系统集成', path: '/point/pointsetting' }, { label: '配置动参从点位取值', path: '/point/dynamicdata' }, { label: '处理未对应实例对象标识' }] }
+            },
+            {
+                path: 'partsRela',
+                name: 'partsRela',
+                component: partsRela,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '系统集成', path: '/point/pointsetting' }, { label: '配置动参从点位取值', path: '/point/dynamicdata' }, { label: '处理未对应实例对象标识' }] }
+            },
+            {
+                path: 'systemRela',
+                name: 'systemRela',
+                component: systemRela,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '系统集成', path: '/point/pointsetting' }, { label: '配置动参从点位取值', path: '/point/dynamicdata' }, { label: '处理未对应实例对象标识' }] }
+            },
+            {
+                path: 'spaceRela',
+                name: 'spaceRela',
+                component: spaceRela,
+                meta: { keepAlive: false, breadcrumbs: [{ label: '系统集成', path: '/point/pointsetting' }, { label: '配置动参从点位取值', path: '/point/dynamicdata' }, { label: '处理未对应实例对象标识' }] }
             },
             {
                 path: 'objectdata',
@@ -308,9 +331,9 @@ export default [
         name: 'LayoutMain',
         component: LayoutMain,
         children: [
-            { path: 'maintain', name: 'maintain', component: maintain, meta: { keepAlive: false, breadcrumbs: [{ label: '关系维护' }] }},
-            { path: 'overview', name: 'overView', component: overView, meta: { keepAlive: false, breadcrumbs: [{ label: '全部关系总览' }] }}
-        ] 
+            { path: 'maintain', name: 'maintain', component: maintain, meta: { keepAlive: false, breadcrumbs: [{ label: '关系维护' }] } },
+            { path: 'overview', name: 'overView', component: overView, meta: { keepAlive: false, breadcrumbs: [{ label: '全部关系总览' }] } }
+        ]
     },
     /******************** 通用字典 ***************************/
     //厂家库

+ 72 - 0
src/utils/buildfloor/tools.js

@@ -0,0 +1,72 @@
+const tools = {}
+
+/**
+ * @param arr [a,b,c]
+ * 
+ * val value
+ */
+function returnNewObj(data, arr, val) {
+  if (arr.length > 1) {
+    let k = arr.shift()
+    if (!data[k]) {
+      data[k] = {}
+    }
+    returnNewObj(data[k], arr, val)
+  } else {
+    let curk = arr[0]
+    data[curk] = val;
+  }
+}
+
+/**
+ * @param key a
+ * @param val {b:{c:''}}|''|1
+ * @return a.b.c
+ */
+function rKeyStrVal(key, val) {
+  let nk = key, arr = []
+  if (val instanceof Object && !(val instanceof Array)) {
+    // for(let k in )
+    return nk + '.' + rKeyStrVal()
+  }
+  return nk
+}
+
+/**
+ * @param data Object
+ * @returns 将对象中 key 为a.b.c 转换为a:{b:{c:''}}
+ */
+tools.formatData = (data) => {
+  let newData = JSON.parse(JSON.stringify(data))
+  for (let key in newData) {
+    if (key.indexOf('.') > -1) {
+      let arr = key.split('.')
+      returnNewObj(newData, arr, newData[key])
+      delete newData[key]
+    }
+  }
+  return newData
+}
+
+/**
+ * @param data {a:{b:{c:{}}}}
+ * 
+ * @returns a.b.c
+ * 
+ */
+tools.desFormatData = (data) => {
+  let newData = {}
+  for (let key in data) {
+    if (data[key] instanceof Object && !(data[key] instanceof Array)) {
+      for (let childK in data[key]) {
+        let nk = `${key}.${childK}`
+        newData[nk] = data[key][childK]
+      }
+    } else {
+      newData[key] = data[key]
+    }
+  }
+  return newData
+}
+
+export default tools

+ 2 - 2
src/views/ledger/rentlist/index.vue

@@ -122,8 +122,8 @@ export default {
     ]),
     showTypes () {
       return this.onlyRead?
-        [{value: "all", label: '全部'}, {value: "Visible", label: '只看采集信息'}]: 
-        [{value: "all", label: '全部'}, {value: "Visible", label: '只看采集信息'}, {value: "partInfo", label: '隐藏信息点'}]
+        [{value: "Visible", label: '只看采集信息'}, {value: "all", label: '全部'}]: 
+        [{value: "partInfo", label: '隐藏信息点'}, {value: "Visible", label: '只看采集信息'}, {value: "all", label: '全部'}]
     }
   },
   created() {

+ 657 - 27
src/views/model/file/index.vue

@@ -1,36 +1,666 @@
 <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>
-</template>
+  <div id="file_moddle_manage" v-loading="loading">
+    <!-- 左边模型文件夹列表 -->
+    <el-col class="col_left" :span="5">
+      <div class="grid-content grid-left">
+        <el-card class="box-card" :body-style="{ padding: '0px', height: '100%' }">
+          <div class="top_hand left_top_hand">
+            <div class="folder-box">
+              <el-tooltip class="item" effect="dark" content="新建文件夹" placement="top-start">
+                <el-button icon="el-icon-folder-add" @click="addFolder" class="icon_font"></el-button>
+              </el-tooltip>
+              <el-tooltip class="item" effect="dark" content="删除文件夹" placement="top-start">
+                <el-button icon="el-icon-folder-remove" class="icon_font" @click="removeFolder"></el-button>
+              </el-tooltip>
+            </div>
+            <div class="file-box">
+              <el-tooltip class="item" effect="dark" content="编辑文件夹" placement="top-start">
+                <el-button @click="editFolder" icon="el-icon-edit" class="icon_font"></el-button>
+              </el-tooltip>
+            </div>
+          </div>
+          <div class="folder-list">
+            <div class="head">模型文件夹</div>
+            <ul class="lists">
+              <el-scrollbar style="height:100%;">
+                <li
+                  @click="openFolder(index,item)"
+                  v-for="(item,index) in navigationModel"
+                  :key="index"
+                  :class="[choiceIndex == index + 1 ? 'li-active' : '']"
+                >
+                  <i
+                    :class="[choiceIndex == index + 1 ?  'el-icon-folder-opened':'el-icon-folder','icon_font']"
+                    width="40"
+                    height="40"
+                  ></i>
+                  <span>{{item.Name}}</span>
+                </li>
+              </el-scrollbar>
+            </ul>
+          </div>
+        </el-card>
+      </div>
+    </el-col>
+    <!-- 右边文件表格 -->
+    <el-col class="col_left" :span="19">
+      <el-card class="box-card" :body-style="{ padding: '0px' }">
+        <!-- 顶部操作栏 -->
+        <div class="top_hand right_top_hand">
+          <el-button @click="addFloorFile">添加楼层文件</el-button>
+          <el-button @click="queryFloorFile(currentFolderId)">刷新</el-button>
+        </div>
+        <!-- 列表 -->
+        <floorTable
+          ref="floorTable"
+          :tableData="tableData"
+          :modelFolderName="currentFolderName"
+          @openModelLog="queryModelLog"
+          @replaceModel="repliaceModel"
+          @closeUpdateFile="removePersentList"
+          @percentFinish="queryFloorFile(currentFolderId)"
+          :persentList="persentList"
+        ></floorTable>
+      </el-card>
+    </el-col>
+    <!-- 弹窗 开始-->
 
+    <!-- 模型日志弹窗 -->
+    <modelLog
+      :modelLogVisible="modelLogVisible"
+      :modelFolderName="currentFolderName"
+      @deleteFinish="updataLog"
+      @CloseModelLogDia="modelLogVisible=false"
+      :logData="logData"
+    ></modelLog>
+    <!-- 替换模型弹窗 -->
+    <repliceModel
+      :repliceModelVisible="repliceModelVisible"
+      @closeReplaceModelDia="repliceModelVisible=false"
+      :replaceModelItem="replaceModelItem"
+      @updataModel="updateModelFile"
+    ></repliceModel>
+    <!-- 新增楼层 -->
+    <addFloorDialog
+      :addFloorFileVisible="addFloorFileVisible"
+      :floorList="tableData"
+      :FolderName="currentFolderName"
+      :FolderId="currentFolderId"
+      @closeAddFloorDia="addFloorFileVisible=false"
+      @finishCreateFloor="uploadModelFIle"
+    ></addFloorDialog>
+    <!-- 新增文件夹名称 -->
+    <addFolder
+      :addFolderVisible="addFolderVisible"
+      @closeAddFolderVisible="addFolderVisible=false;folderName=''"
+      :folderName="folderName"
+      @getfolderModel="queryModel"
+    ></addFolder>
+    <!-- 编辑文件夹名字 -->
+    <changeFolderName
+      :currentFolderId="currentFolderId"
+      :changeFolderNameVisible="changeFolderNameVisible"
+      :folderName="folderName"
+      @finishChangeFolderName="queryModel"
+      @closeChangeFolderVisible="changeFolderNameVisible=false;folderName=''"
+    ></changeFolderName>
+    <!-- 弹窗 结束-->
+  </div>
+</template>
 <script>
+import { mapGetters } from "vuex";
+import request from "@/api/model/file.js";
 import dasBoard from "@/views/dasboard/index";
+import modelLog from "@/components/model/file/modelLog"; //模型日志弹窗
+import repliceModel from "@/components/model/file/replaceModelDialog"; //替换模型弹窗
+import addFloorDialog from "@/components/model/file/addFloorDialog"; //新增楼层弹窗
+import addFolder from "@/components/model/file/addFolder"; //新增文件夹
+import changeFolderName from "@/components/model/file/changeFolderName"; //编辑名字
+import floorTable from "@/components/model/file/floorTable"; //右侧list表
 export default {
-    components: {
-      dasBoard
+  // 离开此页面前要判断是是否有下载
+  beforeRouteLeave: function(to, from, next) {
+    console.log(this.uploadClassList);
+    if (this.uploadClassList.length) {
+      this.$alert(
+        "您有正在上传的模型文件,切换菜单会中断上传,是否继续?",
+        "提示",
+        {
+          confirmButtonText: "确定",
+          callback: action => {
+            console.log(action);
+            if (action == "confirm") {
+              next();
+            } else {
+              next(false);
+            }
+          }
+        }
+      );
+    } else {
+      next();
+    }
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId", "userInfo", "userId", "secret"])
+  },
+  components: {
+    dasBoard,
+    modelLog,
+    repliceModel,
+    addFloorDialog,
+    addFolder,
+    changeFolderName,
+    floorTable
+  },
+  data() {
+    return {
+      addFolderVisible: false, //是否显示新增文件夹弹窗
+      addFloorFileVisible: false, //是否显示增加楼层文件弹窗
+      repliceModelVisible: false, //是否显示替换楼层模型弹窗
+      modelLogVisible: false, //是否显示模型日志弹窗
+      changeFolderNameVisible: false, //是否显示编辑文件夹弹窗
+      folderName: "", //新建文件夹名称
+      navigationModel: [
+        {
+          Name: ""
+        }
+      ], //文件夹模型list
+      choiceIndex: 0, //当前文件夹index
+      currentFolderId: "", //当前选择的文件夹id
+      currentFolderName: "", //当前选择文件夹的Name
+      currentFloorModelId: "", //当前选择的楼层文件id
+      tableData: [],
+      loading: false, //加载loading
+      logData: [], //楼层文件对应的模型日志
+      replaceModelItem: null, //替换文件的item
+      uploadFloorModelIdList: [], //上传楼层文件得数组,上传完成则为空
+      //请求头
+      headers: {
+        ProjectId: ""
+      },
+      updataData: {
+        model: {}
+      },
+      persentList: [], //请求进度列表
+      uploadClassList: [], //请求list 用与缓存多个请求问题
+      isJump: true //是否可以调整页面
+    };
+  },
+  // mounted() {
+  //   window.addEventListener('beforeunload', e => {
+  //     if (this.uploadClassList.length) {
+  //       window.localStorage.removeItem("当前页有下载内容,关闭或刷新页面下载将会失败。您确定要继续吗?")
+  //     }
+  //   })
+  // },
+  methods: {
+    // 以下是模型文件夹
+
+    // 打开模型文件夹
+    openFolder(index, item) {
+      this.choiceIndex = index + 1;
+      this.currentFolderId = item.Id;
+      this.currentFolderName = item.Name;
+      // 获取模型文件夹对应得楼层文件
+      this.queryFloorFile(this.currentFolderId);
+    },
+    //新增模型文件夹
+    addFolder() {
+      this.folderName = "";
+      this.addFolderVisible = true;
+    },
+    //删除模型文件夹
+    removeFolder() {
+      this.$alert(`确定要删除文件夹 <${this.currentFolderName}> 吗?`, "提示", {
+        confirmButtonText: "确定",
+        callback: action => {
+          if (action == "confirm") {
+            let params = {
+              Id: this.currentFolderId,
+              ProjectId: this.projectId
+            };
+            request.deleteModel(params, res => {
+              this.$message({
+                message: "删除成功!",
+                type: "success"
+              });
+              this.queryModel();
+            });
+          } else {
+            this.$message({
+              type: "info",
+              message: `取消操作`
+            });
+          }
+        }
+      });
+    },
+    //编辑文件夹
+    editFolder() {
+      this.folderName = this.currentFolderName;
+      this.changeFolderNameVisible = true;
+    },
+    // 查询所有文件夹模型
+    queryModel() {
+      this.loading = true;
+      request.queryModel("", res => {
+        this.navigationModel = res.Content;
+        this.loading = false;
+        if(this.navigationModel.length){
+          //默认选择第一个文件夹
+          this.choiceIndex = 1;
+          this.currentFolderName = this.navigationModel[0].Name;
+          this.currentFolderId = this.navigationModel[0].Id;
+          this.queryFloorFile(this.currentFolderId);
+        } else {
+          this.tableData = []
+        }
+      });
+    },
+
+    ///一下是楼层文件
+
+    //获取楼层文件
+    /**
+     * @param currentFolderId 当前选择的文件夹id
+     */
+    queryFloorFile(currentFolderId) {
+      let data = {
+        FolderId: currentFolderId,
+        ProjectId: this.projectId
+      };
+      return new Promise((resolve, reject) => {
+        request.queryFloorList(data, res => {
+          res.Content.map(item => {
+            /**
+             * @info: 状态显示说明
+             * 0: 上传中(上传的用户可操作:中止)
+             * 1: 等待检查
+             * 10: 模型检查中
+             * 11: 未通过检查
+             * 2、20、21、3、31: 正常(所有用户可操作:下载、查看历史)
+             * 4: 正常(所有用户可操作:下载、替换、查看历史)
+             */
+            if (item.Status == 2 || item.Status == 20 || item.Status == 21 || item.Status == 3 || item.Status == 31 || item.Status == 4) {
+              Object.assign(item, { isDown: false, precent: 0 });
+            } else {
+              Object.assign(item, { isDown: true, precent: 100 });
+              if (this.persentList.length != 0) {
+                this.persentList.forEach(pItem => {
+                  if (item.Id == pItem.Id) {
+                    Object.assign(item, { isDown: true, precent: pItem.precent?pItem.precent:0 });
+                  }
+                });
+              }
+            }
+          });
+          this.tableData = res.Content;
+          this.loading = false;
+          resolve();
+        });
+      });
+    },
+    //添加楼层文件
+    addFloorFile() {
+      this.addFloorFileVisible = true;
+    },
+
+    //以下是文件模型
+
+    //打开替换文件模型
+    repliaceModel(item) {
+      this.replaceModelItem = item;
+      this.repliceModelVisible = true;
+    },
+    // 上传模型文件
+    uploadModelFIle(data) {
+      // 在列表中添加
+      this.persentList.push({
+        Id: data.FloorModelId,
+        precent: 0
+      });
+      let uploadClass = this.uploadClass();
+      this.uploadClassList.push({
+        obj: new uploadClass(data),
+        Id: data.FloorModelId
+      });
     },
-    data() {
-        return {
-          plan: "",
-          finish: "",
-          onLine: "",
-          explain: "模型文件管理"
+    // 上传文件的类
+    uploadClass() {
+      let that = this;
+      return class {
+        constructor(data) {
+          this.upload(data);
+        }
+        upload(data) {
+          that.queryFloorFile(that.currentFolderId).then(() => {
+            // 开始上传文件
+            // 开始处理数据
+            let formData = new FormData();
+            formData.append(
+              "model",
+              JSON.stringify({
+                FloorModelId: data.FloorModelId,
+                Id: data.CurrentModelId
+              })
+            );
+            formData.append("file", data.Form.file.raw);
+            // 处理数据结束
+
+            // 修改isdown得值
+            that.tableData.map(item => {
+              if (item.Id == data.FloorModelId) {
+                item.isDown = true;
+                item.precent = 0;
+              }
+            });
+
+            // 开始上传
+            request.uploadModelFile(
+              formData,
+              that.projectId,
+              res => {
+                let loaded = res.loaded, //加载量
+                  total = res.total; //文件大小
+                that.$nextTick(() => {
+                  let precent = Math.round((loaded / total) * 100);
+                  // this.$refs.floorTable.filterTag(data.FloorModelId, precent);
+                  if (that.persentList.length != 0) {
+                    that.persentList.map(item => {
+                      if (item.Id == data.FloorModelId) {
+                        item.precent = precent;
+                      }
+                    });
+                  }
+                });
+              },
+              val => {
+                if (val.data.Result === "success") {
+                  if (that.persentList.length != 0) {
+                    //深拷贝
+                    let persentListCopy = JSON.parse(JSON.stringify(that.persentList))
+                    persentListCopy.forEach((item, index) => {
+                      if (item.Id == data.FloorModelId) {
+                        // item.precent = 101;
+                        that.persentList.splice(index, 1);
+                        that.uploadClassList.splice(index, 1);
+                        return;
+                      }
+                    });
+                  }
+                  that.$message({ message: "文件上传成功", type: "success" });
+                  //  刷新list列表
+                  that.queryFloorFile(that.currentFolderId);
+                } else {
+                  if (that.persentList.length != 0) {
+                    //深拷贝
+                    let persentListCopy = JSON.parse(JSON.stringify(that.persentList))
+                    persentListCopy.forEach((item, index) => {
+                      if (item.Id == data.FloorModelId) {
+                        // item.precent = 101;
+                        that.persentList.splice(index, 1);
+                        that.uploadClassList.splice(index, 1);
+                        return;
+                      }
+                    });
+                  }
+                  that.$message({
+                    message: val.data.Message,
+                    type: "error"
+                  });
+                  //  刷新list列表
+                  that.queryFloorFile(that.currentFolderId);
+                }
+              }
+            );
+          });
         }
+      };
     },
-    mounted() {}
+    //更新模型文件;
+    updateModelFile(data) {
+      this.persentList.push({
+        Id: data.replaceModelItem.Id,
+        precent: 0
+      });
+      // 修改isdown得值
+      this.tableData.map(item => {
+        if (item.Id == data.replaceModelItem.Id) {
+          item.isDown = true;
+          item.precent = 0;
+        }
+      });
+      // 开始上传
+      let updataclass = this.updateModelClass();
+      this.uploadClassList.push({
+        obj: new updataclass(data),
+        Id: data.replaceModelItem.Id
+      });
+    },
+    // 更新文件的类
+    updateModelClass() {
+      let that = this;
+      // 开始上传
+      return class {
+        constructor(data) {
+          this.upDateModel(data);
+        }
+        upDateModel(data) {
+          request.upDateModelFile(
+            data,
+            that.projectId,
+            that.userInfo.username,
+            res => {
+              let loaded = res.loaded, //加载量
+                total = res.total; //文件大小
+              that.$nextTick(() => {
+                let precent = Math.round((loaded / total) * 100);
+                // this.$refs.floorTable.filterTag(data.FloorModelId, precent);
+                if (that.persentList.length != 0) {
+                  that.persentList.map(item => {
+                    if (item.Id == data.replaceModelItem.Id) {
+                      item.precent = precent;
+                    }
+                  });
+                }
+              });
+            },
+            val => {
+              if (val.data.Result === "success") {
+                if (that.persentList.length != 0) {
+                  //深拷贝
+                  let persentListCopy = JSON.parse(JSON.stringify(that.persentList))
+                  persentListCopy.forEach((item, index) => {
+                    if (item.Id == data.replaceModelItem.Id) {
+                      // item.precent = 101;
+                      that.persentList.splice(index, 1);
+                      that.uploadClassList.splice(index, 1);
+                      return;
+                    }
+                  });
+                }
+                that.$message({
+                  message: "文件上传成功",
+                  type: "success"
+                });
+                //  刷新list列表
+                that.queryFloorFile(that.currentFolderId);
+              } else {
+                if (that.persentList.length != 0) {
+                  //深拷贝
+                  let persentListCopy = JSON.parse(JSON.stringify(that.persentList))
+                  persentListCopy.forEach((item, index) => {
+                    if (item.Id == data.FloorModelId) {
+                      // item.precent = 101;
+                      that.persentList.splice(index, 1);
+                      that.uploadClassList.splice(index, 1);
+                      return;
+                    }
+                  });
+                }
+                that.$message({
+                  message: val.data.Message,
+                  type: "error"
+                });
+                //  刷新list列表
+                that.queryFloorFile(that.currentFolderId);
+              }
+            }
+          );
+        }
+      };
+    },
+    //查看模型日志
+    queryModelLog(item) {
+      this.FloorModelId = item.Id; //楼层模型文件
+      request.queryModelFile(this.FloorModelId, res => {
+        this.logData = res.Content;
+        this.modelLogVisible = true;
+      });
+    },
+    // 刷新日志
+    updataLog() {
+      request.queryModelFile(this.FloorModelId, res => {
+        this.logData = res.Content;
+      });
+    },
+    // 删除上传列表item
+    removePersentList(item) {
+      this.uploadClassList.forEach((i, index) => {
+        if (item.Id == i.Id) {
+          // this.$delete(this.uploadClassList, index);
+          this.uploadClassList.splice(index, 1);
+          return;
+        }
+      });
+      this.persentList.forEach((i, index) => {
+        if (item.Id == i.Id) {
+          this.$delete(this.persentList, index);
+          return;
+        }
+      });
+      this.$message({
+        message: "中止上传!",
+        type: "success"
+      });
+      //  刷新list列表
+      that.queryFloorFile(that.currentFolderId);
+    }
+  },
+  watch: {
+    uploadClassList: {
+      deep: true,
+      handler: function(val) {
+        console.log(val);
+      }
+    },
+    projectId() {
+      this.queryModel()
+    }
+  },
+  mounted() {
+    this.queryModel();
+    // 十秒刷新次楼层列表
+    // setInterval(()=>{
+    //    this.queryFloorFile(this.currentFolderId)
+    // },10000)
+  }
+};
+</script>
+<style lang="less" scoped>
+#file_moddle_manage {
+  width: 100%;
+  height: 100%;
+  overflow: hidden !important;
+  .col_left {
+    height: 100%;
+  }
+  .grid-content {
+    height: 100%;
+  }
+  .box-card {
+    height: 100%;
+  }
+  .grid-left {
+    padding-right: 10px;
+    box-sizing: border-box;
+  }
+  // 顶部
+  .top_hand {
+    height: 60px;
+    width: 100%;
+    padding: 10px;
+    box-sizing: border-box;
+    display: flex;
+  }
+  .left_top_hand {
+    align-items: center;
+    justify-content: space-between;
+    .folder-box {
+      display: flex;
+      height: 40px;
+      flex-direction: row;
+    }
+    .box-icon {
+      width: 40px;
+      height: 40px;
+      font-size: 30px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      float: left;
+    }
+  }
+  // 左侧文件夹列表
+  .folder-list {
+    width: 100%;
+    height: calc(100% - 60px);
+    .head {
+      height: 42px;
+      width: 100%;
+      padding-left: 10px;
+      box-sizing: border-box;
+      background: #d9d9d9;
+      color: #2b2b2b;
+      display: flex;
+      justify-content: left;
+      align-items: center;
+      font-weight: bold;
+    }
+    .lists {
+      width: 100%;
+      margin-top: 10px;
+      height: calc(100% - 52px);
+      overflow-y: auto;
+      li {
+        height: 42px;
+        display: flex;
+        justify-content: left;
+        align-items: center;
+        padding-left: 20px;
+        box-sizing: border-box;
+        color: #555;
+        cursor: pointer;
+        span {
+          padding-left: 6px;
+        }
+      }
+      li:hover {
+        background-color: #f5f7fa;
+        color: #000;
+      }
+      .li-active {
+        background-color: #f5f7fa;
+        color: #000;
+      }
+    }
+  }
+  .icon_font {
+    font-size: 18px;
+  }
+}
+/deep/ .el-scrollbar__wrap {
+  overflow-x: hidden;
 }
-</script>
+</style>

+ 18 - 17
src/views/point/dynamicdata/addRelation/equipRela/index.vue

@@ -5,7 +5,7 @@
       <el-col :span="12">
         <el-button size="small" type="default" icon="el-icon-back" @click="goback"></el-button>
         <div style="display:inline-block;width:317px;margin-left:10px;">
-          <dictionary-device @change="changeDictionary" :Related="false"></dictionary-device>
+          <dictionary-device @change="changeDictionary" :Related="false" :typeName="typeName"></dictionary-device>
         </div>
       </el-col>
       <el-col :span="12" class="text-right">
@@ -20,12 +20,12 @@
     <!-- 列表及查询条件区域 -->
     <div class="table-container clearfix">
       <div class="left-table">
-        <h5>未对应的设备标识</h5>
+        <h5>未对应的{{typeName}}标识</h5>
         <!-- 查询条件 -->
         <div class="query-box clearfix">
           <div class="query-item">
-            <label>设备标识关键字</label>
-            <el-input placeholder="请输入设备标识关键字" v-model="form.EquipmentMark" @keyup.enter.native="queryLeftTable">
+            <label>{{typeName}}标识关键字</label>
+            <el-input :placeholder="`请输入${typeName}标识关键字`" v-model="form.EquipmentMark" @keyup.enter.native="queryLeftTable">
               <i slot="suffix" class="el-input__icon el-icon-search" @click="queryLeftTable"></i>
             </el-input>
           </div>
@@ -53,8 +53,8 @@
                   </el-tooltip>
                 </template>
               </el-table-column>
-              <el-table-column prop="SubTypeName" label="设备类型关键字" align="right" show-overflow-tooltip></el-table-column>
-              <el-table-column prop="EquipmentMark" label="设备标识" show-overflow-tooltip align="right" width="200" class-name="bgf5"></el-table-column>
+              <el-table-column prop="SubTypeName" :label="`${typeName}类型关键字`" align="right" show-overflow-tooltip></el-table-column>
+              <el-table-column prop="EquipmentMark" :label="`${typeName}标识`" show-overflow-tooltip align="right" width="200" class-name="bgf5"></el-table-column>
               <el-table-column type="selection" width="35" class-name="bgf5"></el-table-column>
             </el-table>
           </div>
@@ -62,7 +62,7 @@
           <transition name="el-zoom-in-top">
             <div class="AIRecom" v-show="leftRecoList.length&&leftAI&&rArray.length">
               <div class="l-title">
-                可能对应的设备标识
+                可能对应的{{typeName}}标识
                 <i class="el-icon-close" @click="leftRecoList=[]"></i>
               </div>
               <div v-for="(t,i) in leftRecoList" :key="t.id" class="l-ai-recom-item ai-recom-item" @click="selectAI(i,'l')">
@@ -79,12 +79,12 @@
         </div>
       </div>
       <div class="right-table" style="float: right;">
-        <h5>未对应的设备实例</h5>
+        <h5>未对应的{{typeName}}实例</h5>
         <!-- 查询条件 -->
         <div class="query-box clearfix">
           <div class="query-item">
-            <label>设备实例关键字</label>
-            <el-input placeholder="请输入设备实例关键字" v-model="form.ObjectLocalName" @keyup.enter.native="queryRightTable">
+            <label>{{typeName}}实例关键字</label>
+            <el-input :placeholder="`请输入${typeName}实例关键字`" v-model="form.ObjectLocalName" @keyup.enter.native="queryRightTable">
               <i slot="suffix" class="el-input__icon el-icon-search" @click="queryRightTable"></i>
             </el-input>
           </div>
@@ -99,17 +99,17 @@
             <el-table ref="rTableBody" :data="RtableData" tooltip-effect="dark" style="width: 100%" height="100%" @row-click="clickRightRow"
               @selection-change="rightSelectionChange">
               <el-table-column type="selection" width="35" class-name="bgf5"></el-table-column>
-              <el-table-column label="设备实例名称" width="200" class-name="bgf5" show-overflow-tooltip>
+              <el-table-column :label="`${typeName}实例名称`" width="200" class-name="bgf5" show-overflow-tooltip>
                 <template slot-scope="scope">{{ scope.row.ObjectLocalName }}</template>
               </el-table-column>
-              <el-table-column prop="ObjectID" label="设备实例编码" show-overflow-tooltip></el-table-column>
-              <el-table-column prop="SubTypeName" label="设备类型" show-overflow-tooltip></el-table-column>
+              <el-table-column prop="ObjectID" :label="`${typeName}实例编码`" show-overflow-tooltip></el-table-column>
+              <el-table-column prop="SubTypeName" :label="`${typeName}类型`" show-overflow-tooltip></el-table-column>
               <el-table-column label="所在建筑楼层">
                 <template slot-scope="scope">
-                  <el-tooltip :content="scope.row.BuildLocalName&&scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:''"
+                  <el-tooltip :content="scope.row.BuildLocalName?scope.row.BuildLocalName+'-':''+scope.row.FloorLocalName?scope.row.FloorLocalName:''"
                     placement="top">
                     <div class="tool-tip">
-                      {{scope.row.BuildLocalName&&scope.row.FloorLocalName?scope.row.BuildLocalName+'-'+scope.row.FloorLocalName:''}}</div>
+                      {{scope.row.BuildLocalName?scope.row.BuildLocalName+'-':''+scope.row.FloorLocalName?scope.row.FloorLocalName:''}}</div>
                   </el-tooltip>
                 </template>
               </el-table-column>
@@ -120,7 +120,7 @@
           <transition name="el-zoom-in-top">
             <div class="AIRecom" v-show="rightRecoList.length&&!leftAI&&lArray.length">
               <div class="r-title">
-                可能对应的设备实例
+                可能对应的{{typeName}}实例
                 <i class="el-icon-close" @click="rightRecoList=[]"></i>
               </div>
               <div v-for="(t,i) in rightRecoList" :key="t.id" class="r-ai-recom-item ai-recom-item" @click="selectAI(i,'r')">
@@ -565,7 +565,8 @@ export default {
       h5 {
         line-height: 44px;
         padding-left: 5px;
-        background-color: #dfe6ec;
+        background-color: #e1e4e5;
+        color: #2b2b2b
       }
       .query-box {
         margin-bottom: 20px;

+ 722 - 0
src/views/point/dynamicdata/addRelation/partsRela/index.vue

@@ -0,0 +1,722 @@
+<template>
+  <div id="addRelation">
+    <!-- 数据字典部件类型 -->
+    <el-row>
+      <el-col :span="12">
+        <el-button size="small" type="default" icon="el-icon-back" @click="goback"></el-button>
+        <div style="display:inline-block;width:317px;margin-left:10px;">
+          <dictionary-device @change="changeDictionary" :Related="false" :typeName="typeName"></dictionary-device>
+        </div>
+      </el-col>
+      <el-col :span="12" class="text-right">
+        <el-switch @change="changeType" v-model="isSwitch"></el-switch>
+        <span style="padding:0 5px;">AI辅助</span>
+        <el-button size="medium" @click="showHistory" class="ani-his-plus">
+          本次对应记录 {{num}}
+          <span v-if="showPlus" :class="{'plusOne':true,'startAni':showPlus}">+1</span>
+        </el-button>
+      </el-col>
+    </el-row>
+    <!-- 列表及查询条件区域 -->
+    <div class="table-container clearfix">
+      <div class="left-table">
+        <h5>未对应的{{typeName}}标识</h5>
+        <!-- 查询条件 -->
+        <div class="query-box clearfix">
+          <div class="query-item">
+            <label>{{typeName}}标识关键字</label>
+            <el-input :placeholder="`请输入${typeName}标识关键字`" v-model="form.EquipmentMark" @keyup.enter.native="queryLeftTable">
+              <i slot="suffix" class="el-input__icon el-icon-search" @click="queryLeftTable"></i>
+            </el-input>
+          </div>
+          <div class="query-item">
+            <label>数据源</label>
+            <dataSource :Related="false" @change="changeDataSource" :typeName="typeName"></dataSource>
+          </div>
+          <div class="query-item">
+            <label>位置标签</label>
+            <locationFlag :Related="false" @change="changeLocationFlag" :typeName="typeName"></locationFlag>
+          </div>
+        </div>
+        <!-- 左侧列表 -->
+        <div class="table-box">
+          <div class="l-custom-table custom-table" v-loading="lTableLoading">
+            <el-table ref="lTableBody" :data="LtableData" tooltip-effect="dark" style="width: 100%" height="100%" @row-click="clickLeftRow"
+              @selection-change="leftSelectionChange">
+              <el-table-column label="数据源" align="right" show-overflow-tooltip>
+                <template slot-scope="scope">{{ scope.row.Datasource }}</template>
+              </el-table-column>
+              <el-table-column label="位置标签" align="right">
+                <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="SubTypeName" :label="`${typeName}类型关键字`" align="right" show-overflow-tooltip></el-table-column>
+              <el-table-column prop="EquipmentMark" :label="`${typeName}标识`" show-overflow-tooltip align="right" width="200" class-name="bgf5"></el-table-column>
+              <el-table-column type="selection" width="35" class-name="bgf5"></el-table-column>
+            </el-table>
+          </div>
+          <!-- 智能推荐 -->
+          <transition name="el-zoom-in-top">
+            <div class="AIRecom" v-show="leftRecoList.length&&leftAI&&rArray.length">
+              <div class="l-title">
+                可能对应的{{typeName}}标识
+                <i class="el-icon-close" @click="leftRecoList=[]"></i>
+              </div>
+              <div v-for="(t,i) in leftRecoList" :key="t.id" class="l-ai-recom-item ai-recom-item" @click="selectAI(i,'l')">
+                <p>
+                  <el-checkbox v-model="t.checked"></el-checkbox>
+                  <span>{{(t.Proximity*100).toFixed(2)}}%</span>
+                </p>
+                <p>{{t.EquipmentMark&&t.EquipmentMark!='null'?t.EquipmentMark:''}}</p>
+                <p>{{t.LocationFlag.toString()}}</p>
+                <!-- <p>{{t.address}}</p> -->
+              </div>
+            </div>
+          </transition>
+        </div>
+      </div>
+      <div class="right-table" style="float: right;">
+        <h5>未对应的{{typeName}}实例</h5>
+        <!-- 查询条件 -->
+        <div class="query-box clearfix">
+          <div class="query-item">
+            <label>{{typeName}}实例关键字</label>
+            <el-input :placeholder="`请输入${typeName}实例关键字`" v-model="form.ObjectLocalName" @keyup.enter.native="queryRightTable">
+              <i slot="suffix" class="el-input__icon el-icon-search" @click="queryRightTable"></i>
+            </el-input>
+          </div>
+          <div class="query-item">
+            <label>所在位置</label>
+            <location-cas @change="changeLocation" :Related="false" :typeName="typeName"></location-cas>
+          </div>
+        </div>
+        <!-- 右侧列表 -->
+        <div class="table-box">
+          <div class="r-custom-table custom-table" v-loading="rTableLoading">
+            <el-table ref="rTableBody" :data="RtableData" tooltip-effect="dark" style="width: 100%" height="100%" @row-click="clickRightRow"
+              @selection-change="rightSelectionChange">
+              <el-table-column type="selection" width="35" class-name="bgf5"></el-table-column>
+              <el-table-column :label="`${typeName}实例名称`" width="200" class-name="bgf5" show-overflow-tooltip>
+                <template slot-scope="scope">{{ scope.row.ObjectLocalName }}</template>
+              </el-table-column>
+              <el-table-column prop="ObjectID" :label="`${typeName}实例编码`" show-overflow-tooltip></el-table-column>
+              <el-table-column prop="SubTypeName" :label="`${typeName}类型`" show-overflow-tooltip></el-table-column>
+              <el-table-column prop="CascadeEquipLocalName" label="所属设备实例" show-overflow-tooltip></el-table-column>
+              <el-table-column label="所在建筑楼层">
+                <template slot-scope="scope">
+                  <el-tooltip :content="scope.row.BuildLocalName?scope.row.BuildLocalName+'-':''+scope.row.FloorLocalName?scope.row.FloorLocalName:''"
+                    placement="top">
+                    <div class="tool-tip">
+                      {{scope.row.BuildLocalName?scope.row.BuildLocalName+'-':''+scope.row.FloorLocalName?scope.row.FloorLocalName:''}}</div>
+                  </el-tooltip>
+                </template>
+              </el-table-column>
+              <el-table-column prop="RoomLocalName" label="所在业务空间" show-overflow-tooltip></el-table-column>
+            </el-table>
+          </div>
+          <!-- 智能推荐 -->
+          <transition name="el-zoom-in-top">
+            <div class="AIRecom" v-show="rightRecoList.length&&!leftAI&&lArray.length">
+              <div class="r-title">
+                可能对应的{{typeName}}实例
+                <i class="el-icon-close" @click="rightRecoList=[]"></i>
+              </div>
+              <div v-for="(t,i) in rightRecoList" :key="t.id" class="r-ai-recom-item ai-recom-item" @click="selectAI(i,'r')">
+                <p>
+                  <el-checkbox v-model="t.checked"></el-checkbox>
+                  <span>{{(t.Proximity*100).toFixed(2)}}%</span>
+                </p>
+                <p>{{t.ObjectLocalName}}</p>
+                <p>
+                  {{t.BuildLocalName&&t.BuildLocalName!='null'&&t.FloorLocalName&&t.FloorLocalName!='null'?t.BuildLocalName+'-'+t.FloorLocalName:''}}
+                </p>
+                <p>{{t.RoomLocalName&&t.RoomLocalName!='null'?t.RoomLocalName:''}}</p>
+                <p>{{t.InstallLocation&&t.InstallLocation!='null'?t.InstallLocation:''}}</p>
+              </div>
+            </div>
+          </transition>
+        </div>
+      </div>
+    </div>
+    <!-- 历史记录弹窗 -->
+    <history-dialog ref="history" @delSuc="deleteSuc" :typeName="'parts'"></history-dialog>
+  </div>
+</template>
+<script>
+import tools from "@/utils/tools";
+import historyDialog from "@/components/point/dynamicdata/historyDialog";
+import locationCas from "@/components/point/dynamicdata/locationCascader";
+import dictionaryDevice from "@/components/point/dynamicdata/dictionaryDevice";
+import dataSource from "@/components/point/dynamicdata/dataSource";
+import locationFlag from "@/components/point/dynamicdata/locationFlag";
+import { mapGetters, mapActions } from "vuex";
+import {
+  dynamicPendingobjs,
+  dynamicPendingPoint,
+  dynamicCreateRelation,
+  dynamicDeleteRelation,
+  dynamicPointTypeList,
+  dynamicQueryAI
+} from "@/api/scan/request";
+export default {
+  components: {
+    historyDialog,
+    locationCas,
+    dictionaryDevice,
+    dataSource,
+    locationFlag
+  },
+  data() {
+    return {
+      isSwitch: true, //AI辅助
+      typeName: "", //当前类型
+      LtableData: [], //列表数据
+      RtableData: [], //列表数据
+      form: {
+        EquipmentMark: "", //部件标识关键字
+        SubTypeName: [], //数据字典部件类型
+        LocationFlag: [], //位置标签
+        Datasource: [], //数据源
+        ObjectLocalName: "", //部件实例关键字
+        locationVal: [] //所在位置下拉
+      }, //查询条件
+      leftRecoList: [], //左推荐
+      rightRecoList: [], //右推荐
+      leftAI: true, //左右推荐公用-互斥
+      lArray: [], //左侧选中数据
+      rArray: [], //右侧选中数据
+      hasRequestedFlag: false, //用于标识是否关联过数据,若是则重新请求第一页数据,
+      showPlus: false, //+1记录动画
+      num: 0, //记录条数
+      timer: null, //函数节流 延时器
+      historyList: [], //操作历史
+      lTableLoading: false, //loading
+      rTableLoading: false,
+      lPage: {
+        pageNumber: 1,
+        pageSize: 50,
+        total: 0
+      },
+      rPage: {
+        pageNumber: 1,
+        pageSize: 50,
+        total: 0
+      }
+    };
+  },
+  created() {
+    this.typeName = this.$route.query.typeName;
+    this.init();
+  },
+  mounted() {
+    this.lTableBody = this.$refs.lTableBody.bodyWrapper;
+    this.rTableBody = this.$refs.rTableBody.bodyWrapper;
+
+    this.lTableBody.addEventListener("scroll", () => {
+      // 滚动距离
+      let scrollTop = this.lTableBody.scrollTop;
+      // 变量windowHeight是可视区的高度
+      let windowHeight =
+        this.lTableBody.clientHeight || this.lTableBody.clientHeight;
+      // 变量scrollHeight是滚动条的总高度
+      let scrollHeight =
+        this.lTableBody.scrollHeight || this.lTableBody.scrollHeight;
+      if (scrollTop + windowHeight === scrollHeight) {
+        if (this.lPage.pageNumber * this.lPage.pageSize < this.lPage.total) {
+          this.lPage.pageNumber++;
+          if (this.LtableData.length < 50) {
+            this.lPage.pageNumber = 1
+          }
+          this.getLeftData();
+        }
+      }
+    });
+    this.rTableBody.addEventListener("scroll", () => {
+      // 滚动距离
+      let scrollTop = this.rTableBody.scrollTop;
+      // 变量windowHeight是可视区的高度
+      let windowHeight =
+        this.rTableBody.clientHeight || this.rTableBody.clientHeight;
+      // 变量scrollHeight是滚动条的总高度
+      let scrollHeight =
+        this.rTableBody.scrollHeight || this.rTableBody.scrollHeight;
+      if (scrollTop + windowHeight === scrollHeight) {
+        // 获取到的不是全部数据 当滚动到底部 继续获取新的数据
+        if (this.rPage.pageNumber * this.rPage.pageSize < this.rPage.total) {
+          this.rPage.pageNumber++;
+          if (this.RtableData.length < 50) {
+            this.rPage.pageNumber = 1
+          }
+          this.getRightData();
+        }
+      }
+    });
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"]),
+    requestFlag() {
+      return this.lArray.length > 0 && this.rArray.length > 0;
+    }
+  },
+  methods: {
+    init() {
+      this.queryLeftTable();
+      this.queryRightTable();
+    },
+    //切换AI辅助
+    changeType() { },
+    //推荐中的选择事件
+    selectAI(i, l) {
+      //i 索引 l 左侧AI or 右侧AI
+      if (l == "l") {
+        this.leftRecoList[i].checked = true;
+        this.lArray = [];
+        this.lArray.push(this.leftRecoList[i]);
+      } else {
+        this.rightRecoList[i].checked = true;
+        this.rArray = [];
+        this.rArray.push(this.rightRecoList[i]);
+      }
+    },
+    //查看本次历史记录
+    showHistory() {
+      this.$refs.history.showDialog(this.historyList);
+    },
+    //重新获取数据
+    reGetData() {
+      //删除选中项
+      this.delSelectedRows(this.lArray, this.rArray);
+      let history = { leftList: this.lArray, rightList: this.rArray };
+      this.historyList.push(history); //保存本次操作记录
+      this.lArray = []; //清空选中list
+      this.rArray = [];
+      this.num++; //右上角操作记录
+      this.showPlus = true;
+      setTimeout(() => {
+        this.showPlus = false;
+      }, 800);
+    },
+    //少于20条请求数据-否则删除选中项
+    delSelectedRows(lArray, rArray) {
+      for (let li = this.LtableData.length - 1; li >= 0; li--) {
+        for (let lj = 0; lj < lArray.length; lj++) {
+          if (this.LtableData[li] && (this.LtableData[li].EquipmentMark == lArray[lj].EquipmentMark && this.LtableData[li].SubTypeCode == lArray[lj].SubTypeCode)) {
+            // this.LtableData.splice(i, 1)
+            delete this.LtableData[li]
+            continue; //结束当前本轮循环,开始新的一轮循环
+          }
+        }
+      }
+      this.LtableData = this.LtableData.filter(item => {
+        return !(item == 'undefined')
+      })
+      for (let ri = this.RtableData.length - 1; ri >= 0; ri--) {
+        for (let rj = 0; rj < rArray.length; rj++) {
+          if (this.RtableData[ri] && (this.RtableData[ri].ObjectID == rArray[rj].ObjectID && this.RtableData[ri].SubTypeCode == rArray[rj].SubTypeCode)) {
+            // this.RtableData.splice(i, 1)
+            delete this.RtableData[ri]
+            continue; //结束当前本轮循环,开始新的一轮循环
+          }
+        }
+      }
+      this.RtableData = this.RtableData.filter(item => {
+        return !(item == 'undefined')
+      })
+      if (this.LtableData.length < 20 && this.lPage.Total > 49) {
+        this.queryLeftTable()
+      }
+      if (this.RtableData.length < 20 && this.rPage.Total > 49) {
+        this.queryRightTable()
+      }
+    },
+    //表格中的选中事件
+    leftSelectionChange(selection) {
+      this.lArray = selection;
+    },
+    rightSelectionChange(selection) {
+      this.rArray = selection;
+    },
+    //查询左侧列表
+    queryLeftTable() {
+      this.lPage.pageNumber = 1;
+      if (this.$refs.lTableBody && this.$refs.lTableBody.bodyWrapper) {
+        this.$refs.lTableBody.bodyWrapper.scrollTop = 0
+      }
+      this.getLeftData();
+    },
+    //查询右侧列表
+    queryRightTable() {
+      this.rPage.pageNumber = 1;
+      if (this.$refs.rTableBody && this.$refs.rTableBody.bodyWrapper) {
+        this.$refs.rTableBody.bodyWrapper.scrollTop = 0
+      }
+      this.getRightData();
+    },
+    //获取待关联点位-左侧
+    getLeftData() {
+      let param = {
+        PageNumber: this.lPage.pageNumber,
+        PageSize: this.lPage.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.lTableLoading = true;
+      dynamicPendingPoint(param, res => {
+        this.lPage.total = res.PageSize < 50 ? res.PageSize : res.Total;
+        if (this.lPage.pageNumber == 1) {
+          this.LtableData = res.Content;
+        } else {
+          this.LtableData = this.LtableData.concat(res.Content);
+        }
+        this.lTableLoading = false;
+      });
+    },
+    //获取待关联实例-右侧
+    getRightData() {
+      let param = {
+        PageNumber: this.rPage.pageNumber,
+        PageSize: this.rPage.pageSize,
+        TypeNameList: [this.typeName]
+      };
+      //处理查询条件
+      if (this.form.ObjectLocalName && this.form.ObjectLocalName.length) {
+        param.ObjectLocalName = this.form.ObjectLocalName;
+      }
+      if (this.form.SubTypeName.length) {
+        param.SubTypeNameList = this.form.SubTypeName;
+      }
+      if (this.form.locationVal.length > 0) {
+        param.BuildLocalName = this.form.locationVal[0];
+      }
+      if (this.form.locationVal.length > 1) {
+        param.FloorLocalName = this.form.locationVal[1];
+      }
+      if (this.form.locationVal.length > 2) {
+        param.SpaceType = this.form.locationVal[2];
+      }
+      if (this.form.locationVal.length > 3) {
+        param.RoomLocalName = this.form.locationVal[3];
+      }
+      if (!this.form.locationVal.length) {
+        delete param.BuildLocalName
+        delete param.FloorLocalName
+        delete param.SpaceType
+        delete param.RoomLocalName
+      }
+      this.rTableLoading = true;
+      dynamicPendingobjs(param, res => {
+        this.rPage.total = res.PageSize < 50 ? res.PageSize : res.Total;
+        if (this.rPage.pageNumber == 1) {
+          this.RtableData = res.Content;
+        } else {
+          this.RtableData = this.RtableData.concat(res.Content);
+        }
+        this.rTableLoading = false;
+      });
+    },
+    //清除对应关系成功
+    deleteSuc() {
+      this.num--;
+      this.queryLeftTable();
+      this.queryRightTable();
+    },
+    //所在位置修改
+    changeLocation(val) {
+      this.form.locationVal = val;
+      this.queryRightTable();
+    },
+    //数据字典部件类型修改
+    changeDictionary(val) {
+      this.form.SubTypeName = val;
+      this.queryLeftTable();
+      this.queryRightTable();
+    },
+    //数据源修改
+    changeDataSource(val) {
+      this.form.Datasource = val;
+      this.queryLeftTable();
+    },
+    //修改位置标签
+    changeLocationFlag(val) {
+      this.form.LocationFlag = val;
+      this.queryLeftTable();
+    },
+    //返回
+    goback() {
+      this.$router.push({ path: '/point/dynamicdata', query: { typeName: this.typeName } })
+    },
+    //点击行
+    clickLeftRow(row, column, event) {
+      this.$refs.lTableBody.toggleRowSelection(row);
+    },
+    //点击行
+    clickRightRow(row, column, event) {
+      this.$refs.rTableBody.toggleRowSelection(row);
+    },
+  },
+  watch: {
+    projectId(n, o) {
+      this.init();
+    },
+    //判断两边是否均有选中值-创建关联
+    requestFlag(n, o) {
+      if (n) {
+        this.rightRecoList = [];
+        this.leftRecoList = [];
+        let object = {
+          Objs: this.rArray,
+          Points: this.lArray
+        };
+        let param = [];
+        param.push(object);
+        setTimeout(() => {
+          this.reGetData();
+        }, 200)
+        dynamicCreateRelation(param, res => {
+          if (res.Result == "success") {
+            this.$message.success("关联成功");
+          }
+        });
+      }
+    },
+    //AI辅助-左侧
+    lArray(n, o) {
+      //先清空,返回结果后赋值
+      this.rightRecoList = [];
+      clearTimeout(this.timer);
+      if (this.isSwitch && n.length) {
+        this.timer = setTimeout(() => {
+          let param = []
+          n.map(item => {
+            param.push({
+              Points: [item],
+              Top: 3,
+              Proximity: 0.5
+            })
+          })
+          dynamicQueryAI(param, res => {
+            this.rightRecoList = res.Content[0].Objs;
+            this.leftAI = !this.rightRecoList.length
+          })
+        }, 800)
+      } else {
+        this.rightRecoList = []
+        this.leftAI = true;
+      }
+    },
+    //AI辅助-右侧
+    rArray(n, o) {
+      this.leftRecoList = [];
+      clearTimeout(this.timer);
+      if (this.isSwitch && n.length) {
+        this.timer = setTimeout(() => {
+          let param = []
+          n.map(item => {
+            param.push({
+              Objs: [item],
+              Top: 3,
+              Proximity: 0.5
+            })
+          })
+          dynamicQueryAI(param, res => {
+            this.leftRecoList = res.Content[0].Points;
+            this.leftAI = !!this.leftRecoList.length
+          })
+        }, 800)
+      } else {
+        this.leftRecoList = []
+        this.leftAI = false
+      }
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+#addRelation {
+  height: 100%;
+  background-color: #fff;
+  padding: 10px 20px 10px 10px;
+  .text-right {
+    text-align: right;
+  }
+  /deep/ .table-container {
+    height: calc(100% - 160px);
+    & > div {
+      width: 49.5%;
+      float: left;
+    }
+    .left-table,
+    .right-table {
+      height: 100%;
+      h5 {
+        line-height: 44px;
+        padding-left: 5px;
+        background-color: #e1e4e5;
+        color: #2b2b2b
+      }
+      .query-box {
+        margin-bottom: 20px;
+        .query-item {
+          float: left;
+          width: 30%;
+          margin: 5px;
+          label {
+            display: block;
+            margin-bottom: 5px;
+          }
+          .el-select {
+            width: 100%;
+          }
+        }
+      }
+      .table-box {
+        height: calc(100% - 50px);
+        position: relative;
+        .AIRecom {
+          position: absolute;
+          width: 96%;
+          height: 160px;
+          bottom: 5px;
+          left: 1%;
+          background-color: rgba(255, 255, 255, 0.9);
+          z-index: 3;
+          font-size: 12px;
+          .r-title {
+            padding-left: 10px;
+            i {
+              float: right;
+            }
+          }
+          .l-title {
+            text-align: right;
+            padding-right: 10px;
+            i {
+              float: left;
+            }
+          }
+          .ai-recom-item {
+            width: 30%;
+            height: 126px;
+            float: left;
+            border: 1px solid #ebeef5;
+            overflow: hidden;
+            padding-top: 5px;
+            box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+            p {
+              position: relative;
+              white-space: nowrap;
+              text-overflow: ellipsis;
+              overflow: hidden;
+              padding: 0 8px;
+              z-index: -1;
+              span {
+                float: right;
+              }
+              .el-checkbox {
+                margin-right: 0;
+              }
+            }
+          }
+          .ai-recom-item.r-ai-recom-item + .ai-recom-item {
+            margin-left: 3%;
+          }
+          .l-ai-recom-item {
+            float: right;
+            p {
+              text-align: right;
+              padding-right: 10px;
+              span {
+                float: left;
+              }
+            }
+          }
+          .ai-recom-item.l-ai-recom-item + .ai-recom-item {
+            margin-right: 3%;
+          }
+        }
+      }
+      ::-webkit-scrollbar {
+        display: none;
+      }
+      //列表
+      .custom-table {
+        height: 100%;
+        .bgf5 {
+          background-color: #f5f7fa;
+        }
+        thead label.el-checkbox {
+          display: none;
+        }
+      }
+      .l-custom-table {
+        td {
+          text-align: right;
+        }
+      }
+      .tool-tip {
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+    }
+  }
+  .fr {
+    padding-top: 10px;
+    float: right;
+  }
+  .clearfix:before,
+  .clearfix:after {
+    content: "";
+    display: block;
+    clear: both;
+  }
+  .clearfix {
+    zoom: 1;
+  }
+  .ani-his-plus {
+    position: relative;
+    .plusOne {
+      position: absolute;
+      color: red;
+      left: 50%;
+      bottom: 50%;
+      font-size: 20px;
+      font-weight: 800;
+    }
+    .startAni {
+      animation: fadeToTop 1s;
+    }
+  }
+  @keyframes fadeToTop {
+    0% {
+      left: 50%;
+      bottom: 50%;
+      opacity: 1;
+    }
+    100% {
+      bottom: 100%;
+      opacity: 0;
+    }
+  }
+}
+</style>
+<style>
+body {
+  overflow-y: hidden;
+}
+</style>

+ 722 - 0
src/views/point/dynamicdata/addRelation/spaceRela/index.vue

@@ -0,0 +1,722 @@
+<template>
+  <div id="addRelation">
+    <!-- 数据字典部件类型 -->
+    <el-row>
+      <el-col :span="12">
+        <el-button size="small" type="default" icon="el-icon-back" @click="goback"></el-button>
+        <div style="display:inline-block;width:317px;margin-left:10px;">
+          <dictionary-device @change="changeDictionary" :Related="false" :typeName="typeName"></dictionary-device>
+        </div>
+      </el-col>
+      <el-col :span="12" class="text-right">
+        <el-switch @change="changeType" v-model="isSwitch"></el-switch>
+        <span style="padding:0 5px;">AI辅助</span>
+        <el-button size="medium" @click="showHistory" class="ani-his-plus">
+          本次对应记录 {{num}}
+          <span v-if="showPlus" :class="{'plusOne':true,'startAni':showPlus}">+1</span>
+        </el-button>
+      </el-col>
+    </el-row>
+    <!-- 列表及查询条件区域 -->
+    <div class="table-container clearfix">
+      <div class="left-table">
+        <h5>未对应的{{typeName}}标识</h5>
+        <!-- 查询条件 -->
+        <div class="query-box clearfix">
+          <div class="query-item">
+            <label>{{typeName}}标识关键字</label>
+            <el-input :placeholder="`请输入${typeName}标识关键字`" v-model="form.EquipmentMark" @keyup.enter.native="queryLeftTable">
+              <i slot="suffix" class="el-input__icon el-icon-search" @click="queryLeftTable"></i>
+            </el-input>
+          </div>
+          <div class="query-item">
+            <label>数据源</label>
+            <dataSource :Related="false" @change="changeDataSource" :typeName="typeName"></dataSource>
+          </div>
+          <div class="query-item">
+            <label>位置标签</label>
+            <locationFlag :Related="false" @change="changeLocationFlag" :typeName="typeName"></locationFlag>
+          </div>
+        </div>
+        <!-- 左侧列表 -->
+        <div class="table-box">
+          <div class="l-custom-table custom-table" v-loading="lTableLoading">
+            <el-table ref="lTableBody" :data="LtableData" tooltip-effect="dark" style="width: 100%" height="100%" @row-click="clickLeftRow"
+              @selection-change="leftSelectionChange">
+              <el-table-column label="数据源" align="right" show-overflow-tooltip>
+                <template slot-scope="scope">{{ scope.row.Datasource }}</template>
+              </el-table-column>
+              <el-table-column label="位置标签" align="right">
+                <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="SubTypeName" :label="`${typeName}类型关键字`" align="right" show-overflow-tooltip></el-table-column>
+              <el-table-column prop="EquipmentMark" :label="`${typeName}标识`" show-overflow-tooltip align="right" width="200" class-name="bgf5"></el-table-column>
+              <el-table-column type="selection" width="35" class-name="bgf5"></el-table-column>
+            </el-table>
+          </div>
+          <!-- 智能推荐 -->
+          <transition name="el-zoom-in-top">
+            <div class="AIRecom" v-show="leftRecoList.length&&leftAI&&rArray.length">
+              <div class="l-title">
+                可能对应的{{typeName}}标识
+                <i class="el-icon-close" @click="leftRecoList=[]"></i>
+              </div>
+              <div v-for="(t,i) in leftRecoList" :key="t.id" class="l-ai-recom-item ai-recom-item" @click="selectAI(i,'l')">
+                <p>
+                  <el-checkbox v-model="t.checked"></el-checkbox>
+                  <span>{{(t.Proximity*100).toFixed(2)}}%</span>
+                </p>
+                <p>{{t.EquipmentMark&&t.EquipmentMark!='null'?t.EquipmentMark:''}}</p>
+                <p>{{t.LocationFlag.toString()}}</p>
+                <!-- <p>{{t.address}}</p> -->
+              </div>
+            </div>
+          </transition>
+        </div>
+      </div>
+      <div class="right-table" style="float: right;">
+        <h5>未对应的{{typeName}}实例</h5>
+        <!-- 查询条件 -->
+        <div class="query-box clearfix">
+          <div class="query-item">
+            <label>{{typeName}}实例关键字</label>
+            <el-input :placeholder="`请输入${typeName}实例关键字`" v-model="form.ObjectLocalName" @keyup.enter.native="queryRightTable">
+              <i slot="suffix" class="el-input__icon el-icon-search" @click="queryRightTable"></i>
+            </el-input>
+          </div>
+          <div class="query-item">
+            <label>所在位置</label>
+            <location-cas @change="changeLocation" :Related="false" :typeName="typeName"></location-cas>
+          </div>
+        </div>
+        <!-- 右侧列表 -->
+        <div class="table-box">
+          <div class="r-custom-table custom-table" v-loading="rTableLoading">
+            <el-table ref="rTableBody" :data="RtableData" tooltip-effect="dark" style="width: 100%" height="100%" @row-click="clickRightRow"
+              @selection-change="rightSelectionChange">
+              <el-table-column type="selection" width="35" class-name="bgf5"></el-table-column>
+              <el-table-column :label="`${typeName}实例名称`" width="200" class-name="bgf5" show-overflow-tooltip>
+                <template slot-scope="scope">{{ scope.row.ObjectLocalName }}</template>
+              </el-table-column>
+              <el-table-column prop="ObjectID" :label="`${typeName}实例编码`" show-overflow-tooltip></el-table-column>
+              <el-table-column prop="SubTypeName" :label="`${typeName}类型`" show-overflow-tooltip></el-table-column>
+              <!-- <el-table-column prop="CascadeEquipLocalName" label="所属设备实例" show-overflow-tooltip></el-table-column> -->
+              <el-table-column label="所在建筑楼层">
+                <template slot-scope="scope">
+                  <el-tooltip :content="scope.row.BuildLocalName?scope.row.BuildLocalName+'-':''+scope.row.FloorLocalName?scope.row.FloorLocalName:''"
+                    placement="top">
+                    <div class="tool-tip">
+                      {{scope.row.BuildLocalName?scope.row.BuildLocalName+'-':''+scope.row.FloorLocalName?scope.row.FloorLocalName:''}}</div>
+                  </el-tooltip>
+                </template>
+              </el-table-column>
+              <!-- <el-table-column prop="RoomLocalName" label="所在业务空间" show-overflow-tooltip></el-table-column> -->
+            </el-table>
+          </div>
+          <!-- 智能推荐 -->
+          <transition name="el-zoom-in-top">
+            <div class="AIRecom" v-show="rightRecoList.length&&!leftAI&&lArray.length">
+              <div class="r-title">
+                可能对应的{{typeName}}实例
+                <i class="el-icon-close" @click="rightRecoList=[]"></i>
+              </div>
+              <div v-for="(t,i) in rightRecoList" :key="t.id" class="r-ai-recom-item ai-recom-item" @click="selectAI(i,'r')">
+                <p>
+                  <el-checkbox v-model="t.checked"></el-checkbox>
+                  <span>{{(t.Proximity*100).toFixed(2)}}%</span>
+                </p>
+                <p>{{t.ObjectLocalName}}</p>
+                <p>
+                  {{t.BuildLocalName&&t.BuildLocalName!='null'&&t.FloorLocalName&&t.FloorLocalName!='null'?t.BuildLocalName+'-'+t.FloorLocalName:''}}
+                </p>
+                <p>{{t.RoomLocalName&&t.RoomLocalName!='null'?t.RoomLocalName:''}}</p>
+                <p>{{t.InstallLocation&&t.InstallLocation!='null'?t.InstallLocation:''}}</p>
+              </div>
+            </div>
+          </transition>
+        </div>
+      </div>
+    </div>
+    <!-- 历史记录弹窗 -->
+    <history-dialog ref="history" @delSuc="deleteSuc" :typeName="'space'"></history-dialog>
+  </div>
+</template>
+<script>
+import tools from "@/utils/tools";
+import historyDialog from "@/components/point/dynamicdata/historyDialog";
+import locationCas from "@/components/point/dynamicdata/locationCascader";
+import dictionaryDevice from "@/components/point/dynamicdata/dictionaryDevice";
+import dataSource from "@/components/point/dynamicdata/dataSource";
+import locationFlag from "@/components/point/dynamicdata/locationFlag";
+import { mapGetters, mapActions } from "vuex";
+import {
+  dynamicPendingobjs,
+  dynamicPendingPoint,
+  dynamicCreateRelation,
+  dynamicDeleteRelation,
+  dynamicPointTypeList,
+  dynamicQueryAI
+} from "@/api/scan/request";
+export default {
+  components: {
+    historyDialog,
+    locationCas,
+    dictionaryDevice,
+    dataSource,
+    locationFlag
+  },
+  data() {
+    return {
+      isSwitch: true, //AI辅助
+      typeName: "", //当前类型
+      LtableData: [], //列表数据
+      RtableData: [], //列表数据
+      form: {
+        EquipmentMark: "", //部件标识关键字
+        SubTypeName: [], //数据字典部件类型
+        LocationFlag: [], //位置标签
+        Datasource: [], //数据源
+        ObjectLocalName: "", //部件实例关键字
+        locationVal: [] //所在位置下拉
+      }, //查询条件
+      leftRecoList: [], //左推荐
+      rightRecoList: [], //右推荐
+      leftAI: true, //左右推荐公用-互斥
+      lArray: [], //左侧选中数据
+      rArray: [], //右侧选中数据
+      hasRequestedFlag: false, //用于标识是否关联过数据,若是则重新请求第一页数据,
+      showPlus: false, //+1记录动画
+      num: 0, //记录条数
+      timer: null, //函数节流 延时器
+      historyList: [], //操作历史
+      lTableLoading: false, //loading
+      rTableLoading: false,
+      lPage: {
+        pageNumber: 1,
+        pageSize: 50,
+        total: 0
+      },
+      rPage: {
+        pageNumber: 1,
+        pageSize: 50,
+        total: 0
+      }
+    };
+  },
+  created() {
+    this.typeName = this.$route.query.typeName;
+    this.init();
+  },
+  mounted() {
+    this.lTableBody = this.$refs.lTableBody.bodyWrapper;
+    this.rTableBody = this.$refs.rTableBody.bodyWrapper;
+
+    this.lTableBody.addEventListener("scroll", () => {
+      // 滚动距离
+      let scrollTop = this.lTableBody.scrollTop;
+      // 变量windowHeight是可视区的高度
+      let windowHeight =
+        this.lTableBody.clientHeight || this.lTableBody.clientHeight;
+      // 变量scrollHeight是滚动条的总高度
+      let scrollHeight =
+        this.lTableBody.scrollHeight || this.lTableBody.scrollHeight;
+      if (scrollTop + windowHeight === scrollHeight) {
+        if (this.lPage.pageNumber * this.lPage.pageSize < this.lPage.total) {
+          this.lPage.pageNumber++;
+          if (this.LtableData.length < 50) {
+            this.lPage.pageNumber = 1
+          }
+          this.getLeftData();
+        }
+      }
+    });
+    this.rTableBody.addEventListener("scroll", () => {
+      // 滚动距离
+      let scrollTop = this.rTableBody.scrollTop;
+      // 变量windowHeight是可视区的高度
+      let windowHeight =
+        this.rTableBody.clientHeight || this.rTableBody.clientHeight;
+      // 变量scrollHeight是滚动条的总高度
+      let scrollHeight =
+        this.rTableBody.scrollHeight || this.rTableBody.scrollHeight;
+      if (scrollTop + windowHeight === scrollHeight) {
+        // 获取到的不是全部数据 当滚动到底部 继续获取新的数据
+        if (this.rPage.pageNumber * this.rPage.pageSize < this.rPage.total) {
+          this.rPage.pageNumber++;
+          if (this.RtableData.length < 50) {
+            this.rPage.pageNumber = 1
+          }
+          this.getRightData();
+        }
+      }
+    });
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"]),
+    requestFlag() {
+      return this.lArray.length > 0 && this.rArray.length > 0;
+    }
+  },
+  methods: {
+    init() {
+      this.queryLeftTable();
+      this.queryRightTable();
+    },
+    //切换AI辅助
+    changeType() { },
+    //推荐中的选择事件
+    selectAI(i, l) {
+      //i 索引 l 左侧AI or 右侧AI
+      if (l == "l") {
+        this.leftRecoList[i].checked = true;
+        this.lArray = [];
+        this.lArray.push(this.leftRecoList[i]);
+      } else {
+        this.rightRecoList[i].checked = true;
+        this.rArray = [];
+        this.rArray.push(this.rightRecoList[i]);
+      }
+    },
+    //查看本次历史记录
+    showHistory() {
+      this.$refs.history.showDialog(this.historyList);
+    },
+    //重新获取数据
+    reGetData() {
+      //删除选中项
+      this.delSelectedRows(this.lArray, this.rArray);
+      let history = { leftList: this.lArray, rightList: this.rArray };
+      this.historyList.push(history); //保存本次操作记录
+      this.lArray = []; //清空选中list
+      this.rArray = [];
+      this.num++; //右上角操作记录
+      this.showPlus = true;
+      setTimeout(() => {
+        this.showPlus = false;
+      }, 800);
+    },
+    //少于20条请求数据-否则删除选中项
+    delSelectedRows(lArray, rArray) {
+      for (let li = this.LtableData.length - 1; li >= 0; li--) {
+        for (let lj = 0; lj < lArray.length; lj++) {
+          if (this.LtableData[li] && (this.LtableData[li].EquipmentMark == lArray[lj].EquipmentMark && this.LtableData[li].SubTypeCode == lArray[lj].SubTypeCode)) {
+            // this.LtableData.splice(i, 1)
+            delete this.LtableData[li]
+            continue; //结束当前本轮循环,开始新的一轮循环
+          }
+        }
+      }
+      this.LtableData = this.LtableData.filter(item => {
+        return !(item == 'undefined')
+      })
+      for (let ri = this.RtableData.length - 1; ri >= 0; ri--) {
+        for (let rj = 0; rj < rArray.length; rj++) {
+          if (this.RtableData[ri] && (this.RtableData[ri].ObjectID == rArray[rj].ObjectID && this.RtableData[ri].SubTypeCode == rArray[rj].SubTypeCode)) {
+            // this.RtableData.splice(i, 1)
+            delete this.RtableData[ri]
+            continue; //结束当前本轮循环,开始新的一轮循环
+          }
+        }
+      }
+      this.RtableData = this.RtableData.filter(item => {
+        return !(item == 'undefined')
+      })
+      if (this.LtableData.length < 20 && this.lPage.Total > 49) {
+        this.queryLeftTable()
+      }
+      if (this.RtableData.length < 20 && this.rPage.Total > 49) {
+        this.queryRightTable()
+      }
+    },
+    //表格中的选中事件
+    leftSelectionChange(selection) {
+      this.lArray = selection;
+    },
+    rightSelectionChange(selection) {
+      this.rArray = selection;
+    },
+    //查询左侧列表
+    queryLeftTable() {
+      this.lPage.pageNumber = 1;
+      if (this.$refs.lTableBody && this.$refs.lTableBody.bodyWrapper) {
+        this.$refs.lTableBody.bodyWrapper.scrollTop = 0
+      }
+      this.getLeftData();
+    },
+    //查询右侧列表
+    queryRightTable() {
+      this.rPage.pageNumber = 1;
+      if (this.$refs.rTableBody && this.$refs.rTableBody.bodyWrapper) {
+        this.$refs.rTableBody.bodyWrapper.scrollTop = 0
+      }
+      this.getRightData();
+    },
+    //获取待关联点位-左侧
+    getLeftData() {
+      let param = {
+        PageNumber: this.lPage.pageNumber,
+        PageSize: this.lPage.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.lTableLoading = true;
+      dynamicPendingPoint(param, res => {
+        this.lPage.total = res.PageSize < 50 ? res.PageSize : res.Total;
+        if (this.lPage.pageNumber == 1) {
+          this.LtableData = res.Content;
+        } else {
+          this.LtableData = this.LtableData.concat(res.Content);
+        }
+        this.lTableLoading = false;
+      });
+    },
+    //获取待关联实例-右侧
+    getRightData() {
+      let param = {
+        PageNumber: this.rPage.pageNumber,
+        PageSize: this.rPage.pageSize,
+        TypeNameList: [this.typeName]
+      };
+      //处理查询条件
+      if (this.form.ObjectLocalName && this.form.ObjectLocalName.length) {
+        param.ObjectLocalName = this.form.ObjectLocalName;
+      }
+      if (this.form.SubTypeName.length) {
+        param.SubTypeNameList = this.form.SubTypeName;
+      }
+      if (this.form.locationVal.length > 0) {
+        param.BuildLocalName = this.form.locationVal[0];
+      }
+      if (this.form.locationVal.length > 1) {
+        param.FloorLocalName = this.form.locationVal[1];
+      }
+      if (this.form.locationVal.length > 2) {
+        param.SpaceType = this.form.locationVal[2];
+      }
+      if (this.form.locationVal.length > 3) {
+        param.RoomLocalName = this.form.locationVal[3];
+      }
+      if (!this.form.locationVal.length) {
+        delete param.BuildLocalName
+        delete param.FloorLocalName
+        delete param.SpaceType
+        delete param.RoomLocalName
+      }
+      this.rTableLoading = true;
+      dynamicPendingobjs(param, res => {
+        this.rPage.total = res.PageSize < 50 ? res.PageSize : res.Total;
+        if (this.rPage.pageNumber == 1) {
+          this.RtableData = res.Content;
+        } else {
+          this.RtableData = this.RtableData.concat(res.Content);
+        }
+        this.rTableLoading = false;
+      });
+    },
+    //清除对应关系成功
+    deleteSuc() {
+      this.num--;
+      this.queryLeftTable();
+      this.queryRightTable();
+    },
+    //所在位置修改
+    changeLocation(val) {
+      this.form.locationVal = val;
+      this.queryRightTable();
+    },
+    //数据字典部件类型修改
+    changeDictionary(val) {
+      this.form.SubTypeName = val;
+      this.queryLeftTable();
+      this.queryRightTable();
+    },
+    //数据源修改
+    changeDataSource(val) {
+      this.form.Datasource = val;
+      this.queryLeftTable();
+    },
+    //修改位置标签
+    changeLocationFlag(val) {
+      this.form.LocationFlag = val;
+      this.queryLeftTable();
+    },
+    //返回
+    goback() {
+      this.$router.push({ path: '/point/dynamicdata', query: { typeName: this.typeName } })
+    },
+    //点击行
+    clickLeftRow(row, column, event) {
+      this.$refs.lTableBody.toggleRowSelection(row);
+    },
+    //点击行
+    clickRightRow(row, column, event) {
+      this.$refs.rTableBody.toggleRowSelection(row);
+    },
+  },
+  watch: {
+    projectId(n, o) {
+      this.init();
+    },
+    //判断两边是否均有选中值-创建关联
+    requestFlag(n, o) {
+      if (n) {
+        this.rightRecoList = [];
+        this.leftRecoList = [];
+        let object = {
+          Objs: this.rArray,
+          Points: this.lArray
+        };
+        let param = [];
+        param.push(object);
+        setTimeout(() => {
+          this.reGetData();
+        }, 200)
+        dynamicCreateRelation(param, res => {
+          if (res.Result == "success") {
+            this.$message.success("关联成功");
+          }
+        });
+      }
+    },
+    //AI辅助-左侧
+    lArray(n, o) {
+      //先清空,返回结果后赋值
+      this.rightRecoList = [];
+      clearTimeout(this.timer);
+      if (this.isSwitch && n.length) {
+        this.timer = setTimeout(() => {
+          let param = []
+          n.map(item => {
+            param.push({
+              Points: [item],
+              Top: 3,
+              Proximity: 0.5
+            })
+          })
+          dynamicQueryAI(param, res => {
+            this.rightRecoList = res.Content[0].Objs;
+            this.leftAI = !this.rightRecoList.length
+          })
+        }, 800)
+      } else {
+        this.rightRecoList = []
+        this.leftAI = true;
+      }
+    },
+    //AI辅助-右侧
+    rArray(n, o) {
+      this.leftRecoList = [];
+      clearTimeout(this.timer);
+      if (this.isSwitch && n.length) {
+        this.timer = setTimeout(() => {
+          let param = []
+          n.map(item => {
+            param.push({
+              Objs: [item],
+              Top: 3,
+              Proximity: 0.5
+            })
+          })
+          dynamicQueryAI(param, res => {
+            this.leftRecoList = res.Content[0].Points;
+            this.leftAI = !!this.leftRecoList.length
+          })
+        }, 800)
+      } else {
+        this.leftRecoList = []
+        this.leftAI = false
+      }
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+#addRelation {
+  height: 100%;
+  background-color: #fff;
+  padding: 10px 20px 10px 10px;
+  .text-right {
+    text-align: right;
+  }
+  /deep/ .table-container {
+    height: calc(100% - 160px);
+    & > div {
+      width: 49.5%;
+      float: left;
+    }
+    .left-table,
+    .right-table {
+      height: 100%;
+      h5 {
+        line-height: 44px;
+        padding-left: 5px;
+        background-color: #e1e4e5;
+        color: #2b2b2b
+      }
+      .query-box {
+        margin-bottom: 20px;
+        .query-item {
+          float: left;
+          width: 30%;
+          margin: 5px;
+          label {
+            display: block;
+            margin-bottom: 5px;
+          }
+          .el-select {
+            width: 100%;
+          }
+        }
+      }
+      .table-box {
+        height: calc(100% - 50px);
+        position: relative;
+        .AIRecom {
+          position: absolute;
+          width: 96%;
+          height: 160px;
+          bottom: 5px;
+          left: 1%;
+          background-color: rgba(255, 255, 255, 0.9);
+          z-index: 3;
+          font-size: 12px;
+          .r-title {
+            padding-left: 10px;
+            i {
+              float: right;
+            }
+          }
+          .l-title {
+            text-align: right;
+            padding-right: 10px;
+            i {
+              float: left;
+            }
+          }
+          .ai-recom-item {
+            width: 30%;
+            height: 126px;
+            float: left;
+            border: 1px solid #ebeef5;
+            overflow: hidden;
+            padding-top: 5px;
+            box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+            p {
+              position: relative;
+              white-space: nowrap;
+              text-overflow: ellipsis;
+              overflow: hidden;
+              padding: 0 8px;
+              z-index: -1;
+              span {
+                float: right;
+              }
+              .el-checkbox {
+                margin-right: 0;
+              }
+            }
+          }
+          .ai-recom-item.r-ai-recom-item + .ai-recom-item {
+            margin-left: 3%;
+          }
+          .l-ai-recom-item {
+            float: right;
+            p {
+              text-align: right;
+              padding-right: 10px;
+              span {
+                float: left;
+              }
+            }
+          }
+          .ai-recom-item.l-ai-recom-item + .ai-recom-item {
+            margin-right: 3%;
+          }
+        }
+      }
+      ::-webkit-scrollbar {
+        display: none;
+      }
+      //列表
+      .custom-table {
+        height: 100%;
+        .bgf5 {
+          background-color: #f5f7fa;
+        }
+        thead label.el-checkbox {
+          display: none;
+        }
+      }
+      .l-custom-table {
+        td {
+          text-align: right;
+        }
+      }
+      .tool-tip {
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+    }
+  }
+  .fr {
+    padding-top: 10px;
+    float: right;
+  }
+  .clearfix:before,
+  .clearfix:after {
+    content: "";
+    display: block;
+    clear: both;
+  }
+  .clearfix {
+    zoom: 1;
+  }
+  .ani-his-plus {
+    position: relative;
+    .plusOne {
+      position: absolute;
+      color: red;
+      left: 50%;
+      bottom: 50%;
+      font-size: 20px;
+      font-weight: 800;
+    }
+    .startAni {
+      animation: fadeToTop 1s;
+    }
+  }
+  @keyframes fadeToTop {
+    0% {
+      left: 50%;
+      bottom: 50%;
+      opacity: 1;
+    }
+    100% {
+      bottom: 100%;
+      opacity: 0;
+    }
+  }
+}
+</style>
+<style>
+body {
+  overflow-y: hidden;
+}
+</style>

+ 722 - 0
src/views/point/dynamicdata/addRelation/systemRela/index.vue

@@ -0,0 +1,722 @@
+<template>
+  <div id="addRelation">
+    <!-- 数据字典系统类型 -->
+    <el-row>
+      <el-col :span="12">
+        <el-button size="small" type="default" icon="el-icon-back" @click="goback"></el-button>
+        <div style="display:inline-block;width:317px;margin-left:10px;">
+          <dictionary-device @change="changeDictionary" :Related="false" :typeName="typeName"></dictionary-device>
+        </div>
+      </el-col>
+      <el-col :span="12" class="text-right">
+        <!-- <el-switch @change="changeType" v-model="isSwitch"></el-switch>
+        <span style="padding:0 5px;">AI辅助</span> -->
+        <el-button size="medium" @click="showHistory" class="ani-his-plus">
+          本次对应记录 {{num}}
+          <span v-if="showPlus" :class="{'plusOne':true,'startAni':showPlus}">+1</span>
+        </el-button>
+      </el-col>
+    </el-row>
+    <!-- 列表及查询条件区域 -->
+    <div class="table-container clearfix">
+      <div class="left-table">
+        <h5>未对应的{{typeName}}标识</h5>
+        <!-- 查询条件 -->
+        <!-- <div class="query-box clearfix">
+          <div class="query-item">
+            <label>{{typeName}}标识关键字</label>
+            <el-input :placeholder="`请输入${typeName}标识关键字`" v-model="form.EquipmentMark" @keyup.enter.native="queryLeftTable">
+              <i slot="suffix" class="el-input__icon el-icon-search" @click="queryLeftTable"></i>
+            </el-input>
+          </div>
+          <div class="query-item">
+            <label>数据源</label>
+            <dataSource :Related="false" @change="changeDataSource" :typeName="typeName"></dataSource>
+          </div>
+          <div class="query-item">
+            <label>位置标签</label>
+            <locationFlag :Related="false" @change="changeLocationFlag" :typeName="typeName"></locationFlag>
+          </div>
+        </div> -->
+        <!-- 左侧列表 -->
+        <div class="table-box">
+          <div class="l-custom-table custom-table" v-loading="lTableLoading">
+            <el-table ref="lTableBody" :data="LtableData" tooltip-effect="dark" style="width: 100%" height="100%" @row-click="clickLeftRow"
+              @selection-change="leftSelectionChange">
+              <el-table-column label="数据源" align="right" show-overflow-tooltip>
+                <template slot-scope="scope">{{ scope.row.Datasource }}</template>
+              </el-table-column>
+              <el-table-column label="位置标签" align="right">
+                <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="SubTypeName" :label="`${typeName}类型关键字`" align="right" show-overflow-tooltip></el-table-column>
+              <el-table-column prop="EquipmentMark" :label="`${typeName}标识`" show-overflow-tooltip align="right" width="200" class-name="bgf5"></el-table-column>
+              <el-table-column type="selection" width="35" class-name="bgf5"></el-table-column>
+            </el-table>
+          </div>
+          <!-- 智能推荐 -->
+          <transition name="el-zoom-in-top">
+            <div class="AIRecom" v-show="leftRecoList.length&&leftAI&&rArray.length">
+              <div class="l-title">
+                可能对应的{{typeName}}标识
+                <i class="el-icon-close" @click="leftRecoList=[]"></i>
+              </div>
+              <div v-for="(t,i) in leftRecoList" :key="t.id" class="l-ai-recom-item ai-recom-item" @click="selectAI(i,'l')">
+                <p>
+                  <el-checkbox v-model="t.checked"></el-checkbox>
+                  <span>{{(t.Proximity*100).toFixed(2)}}%</span>
+                </p>
+                <p>{{t.EquipmentMark&&t.EquipmentMark!='null'?t.EquipmentMark:''}}</p>
+                <p>{{t.LocationFlag.toString()}}</p>
+                <!-- <p>{{t.address}}</p> -->
+              </div>
+            </div>
+          </transition>
+        </div>
+      </div>
+      <div class="right-table" style="float: right;">
+        <h5>未对应的{{typeName}}实例</h5>
+        <!-- 查询条件 -->
+        <!-- <div class="query-box clearfix">
+          <div class="query-item">
+            <label>{{typeName}}实例关键字</label>
+            <el-input :placeholder="`请输入${typeName}实例关键字`" v-model="form.ObjectLocalName" @keyup.enter.native="queryRightTable">
+              <i slot="suffix" class="el-input__icon el-icon-search" @click="queryRightTable"></i>
+            </el-input>
+          </div>
+          <div class="query-item">
+            <label>所在位置</label>
+            <location-cas @change="changeLocation" :Related="false" :typeName="typeName"></location-cas>
+          </div>
+        </div> -->
+        <!-- 右侧列表 -->
+        <div class="table-box">
+          <div class="r-custom-table custom-table" v-loading="rTableLoading">
+            <el-table ref="rTableBody" :data="RtableData" tooltip-effect="dark" style="width: 100%" height="100%" @row-click="clickRightRow"
+              @selection-change="rightSelectionChange">
+              <el-table-column type="selection" width="35" class-name="bgf5"></el-table-column>
+              <el-table-column :label="`${typeName}实例名称`" width="200" class-name="bgf5" show-overflow-tooltip>
+                <template slot-scope="scope">{{ scope.row.ObjectLocalName }}</template>
+              </el-table-column>
+              <el-table-column prop="ObjectID" :label="`${typeName}实例编码`" show-overflow-tooltip></el-table-column>
+              <!-- <el-table-column prop="SubTypeName" :label="`${typeName}类型`" show-overflow-tooltip></el-table-column>
+              <el-table-column prop="CascadeEquipLocalName" label="所属设备实例" show-overflow-tooltip></el-table-column>
+              <el-table-column label="所在建筑楼层">
+                <template slot-scope="scope">
+                  <el-tooltip :content="scope.row.BuildLocalName?scope.row.BuildLocalName+'-':''+scope.row.FloorLocalName?scope.row.FloorLocalName:''"
+                    placement="top">
+                    <div class="tool-tip">
+                      {{scope.row.BuildLocalName?scope.row.BuildLocalName+'-':''+scope.row.FloorLocalName?scope.row.FloorLocalName:''}}</div>
+                  </el-tooltip>
+                </template>
+              </el-table-column>
+              <el-table-column prop="RoomLocalName" label="所在业务空间" show-overflow-tooltip></el-table-column> -->
+            </el-table>
+          </div>
+          <!-- 智能推荐 -->
+          <transition name="el-zoom-in-top">
+            <div class="AIRecom" v-show="rightRecoList.length&&!leftAI&&lArray.length">
+              <div class="r-title">
+                可能对应的{{typeName}}实例
+                <i class="el-icon-close" @click="rightRecoList=[]"></i>
+              </div>
+              <div v-for="(t,i) in rightRecoList" :key="t.id" class="r-ai-recom-item ai-recom-item" @click="selectAI(i,'r')">
+                <p>
+                  <el-checkbox v-model="t.checked"></el-checkbox>
+                  <span>{{(t.Proximity*100).toFixed(2)}}%</span>
+                </p>
+                <p>{{t.ObjectLocalName}}</p>
+                <p>
+                  {{t.BuildLocalName&&t.BuildLocalName!='null'&&t.FloorLocalName&&t.FloorLocalName!='null'?t.BuildLocalName+'-'+t.FloorLocalName:''}}
+                </p>
+                <p>{{t.RoomLocalName&&t.RoomLocalName!='null'?t.RoomLocalName:''}}</p>
+                <p>{{t.InstallLocation&&t.InstallLocation!='null'?t.InstallLocation:''}}</p>
+              </div>
+            </div>
+          </transition>
+        </div>
+      </div>
+    </div>
+    <!-- 历史记录弹窗 -->
+    <history-dialog ref="history" @delSuc="deleteSuc" :typeName="'system'"></history-dialog>
+  </div>
+</template>
+<script>
+import tools from "@/utils/tools";
+import historyDialog from "@/components/point/dynamicdata/historyDialog";
+import locationCas from "@/components/point/dynamicdata/locationCascader";
+import dictionaryDevice from "@/components/point/dynamicdata/dictionaryDevice";
+import dataSource from "@/components/point/dynamicdata/dataSource";
+import locationFlag from "@/components/point/dynamicdata/locationFlag";
+import { mapGetters, mapActions } from "vuex";
+import {
+  dynamicPendingobjs,
+  dynamicPendingPoint,
+  dynamicCreateRelation,
+  dynamicDeleteRelation,
+  dynamicPointTypeList,
+  dynamicQueryAI
+} from "@/api/scan/request";
+export default {
+  components: {
+    historyDialog,
+    locationCas,
+    dictionaryDevice,
+    dataSource,
+    locationFlag
+  },
+  data() {
+    return {
+      isSwitch: false, //AI辅助
+      typeName: "", //当前类型
+      LtableData: [], //列表数据
+      RtableData: [], //列表数据
+      form: {
+        EquipmentMark: "", //系统标识关键字
+        SubTypeName: [], //数据字典系统类型
+        LocationFlag: [], //位置标签
+        Datasource: [], //数据源
+        ObjectLocalName: "", //系统实例关键字
+        locationVal: [] //所在位置下拉
+      }, //查询条件
+      leftRecoList: [], //左推荐
+      rightRecoList: [], //右推荐
+      leftAI: true, //左右推荐公用-互斥
+      lArray: [], //左侧选中数据
+      rArray: [], //右侧选中数据
+      hasRequestedFlag: false, //用于标识是否关联过数据,若是则重新请求第一页数据,
+      showPlus: false, //+1记录动画
+      num: 0, //记录条数
+      timer: null, //函数节流 延时器
+      historyList: [], //操作历史
+      lTableLoading: false, //loading
+      rTableLoading: false,
+      lPage: {
+        pageNumber: 1,
+        pageSize: 50,
+        total: 0
+      },
+      rPage: {
+        pageNumber: 1,
+        pageSize: 50,
+        total: 0
+      }
+    };
+  },
+  created() {
+    this.typeName = this.$route.query.typeName;
+    this.init();
+  },
+  mounted() {
+    this.lTableBody = this.$refs.lTableBody.bodyWrapper;
+    this.rTableBody = this.$refs.rTableBody.bodyWrapper;
+
+    this.lTableBody.addEventListener("scroll", () => {
+      // 滚动距离
+      let scrollTop = this.lTableBody.scrollTop;
+      // 变量windowHeight是可视区的高度
+      let windowHeight =
+        this.lTableBody.clientHeight || this.lTableBody.clientHeight;
+      // 变量scrollHeight是滚动条的总高度
+      let scrollHeight =
+        this.lTableBody.scrollHeight || this.lTableBody.scrollHeight;
+      if (scrollTop + windowHeight === scrollHeight) {
+        if (this.lPage.pageNumber * this.lPage.pageSize < this.lPage.total) {
+          this.lPage.pageNumber++;
+          if (this.LtableData.length < 50) {
+            this.lPage.pageNumber = 1
+          }
+          this.getLeftData();
+        }
+      }
+    });
+    this.rTableBody.addEventListener("scroll", () => {
+      // 滚动距离
+      let scrollTop = this.rTableBody.scrollTop;
+      // 变量windowHeight是可视区的高度
+      let windowHeight =
+        this.rTableBody.clientHeight || this.rTableBody.clientHeight;
+      // 变量scrollHeight是滚动条的总高度
+      let scrollHeight =
+        this.rTableBody.scrollHeight || this.rTableBody.scrollHeight;
+      if (scrollTop + windowHeight === scrollHeight) {
+        // 获取到的不是全部数据 当滚动到底部 继续获取新的数据
+        if (this.rPage.pageNumber * this.rPage.pageSize < this.rPage.total) {
+          this.rPage.pageNumber++;
+          if (this.RtableData.length < 50) {
+            this.rPage.pageNumber = 1
+          }
+          this.getRightData();
+        }
+      }
+    });
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"]),
+    requestFlag() {
+      return this.lArray.length > 0 && this.rArray.length > 0;
+    }
+  },
+  methods: {
+    init() {
+      this.queryLeftTable();
+      this.queryRightTable();
+    },
+    //切换AI辅助
+    changeType() { },
+    //推荐中的选择事件
+    selectAI(i, l) {
+      //i 索引 l 左侧AI or 右侧AI
+      if (l == "l") {
+        this.leftRecoList[i].checked = true;
+        this.lArray = [];
+        this.lArray.push(this.leftRecoList[i]);
+      } else {
+        this.rightRecoList[i].checked = true;
+        this.rArray = [];
+        this.rArray.push(this.rightRecoList[i]);
+      }
+    },
+    //查看本次历史记录
+    showHistory() {
+      this.$refs.history.showDialog(this.historyList);
+    },
+    //重新获取数据
+    reGetData() {
+      //删除选中项
+      this.delSelectedRows(this.lArray, this.rArray);
+      let history = { leftList: this.lArray, rightList: this.rArray };
+      this.historyList.push(history); //保存本次操作记录
+      this.lArray = []; //清空选中list
+      this.rArray = [];
+      this.num++; //右上角操作记录
+      this.showPlus = true;
+      setTimeout(() => {
+        this.showPlus = false;
+      }, 800);
+    },
+    //少于20条请求数据-否则删除选中项
+    delSelectedRows(lArray, rArray) {
+      for (let li = this.LtableData.length - 1; li >= 0; li--) {
+        for (let lj = 0; lj < lArray.length; lj++) {
+          if (this.LtableData[li] && (this.LtableData[li].EquipmentMark == lArray[lj].EquipmentMark && this.LtableData[li].SubTypeCode == lArray[lj].SubTypeCode)) {
+            // this.LtableData.splice(i, 1)
+            delete this.LtableData[li]
+            continue; //结束当前本轮循环,开始新的一轮循环
+          }
+        }
+      }
+      this.LtableData = this.LtableData.filter(item => {
+        return !(item == 'undefined')
+      })
+      for (let ri = this.RtableData.length - 1; ri >= 0; ri--) {
+        for (let rj = 0; rj < rArray.length; rj++) {
+          if (this.RtableData[ri] && (this.RtableData[ri].ObjectID == rArray[rj].ObjectID && this.RtableData[ri].SubTypeCode == rArray[rj].SubTypeCode)) {
+            // this.RtableData.splice(i, 1)
+            delete this.RtableData[ri]
+            continue; //结束当前本轮循环,开始新的一轮循环
+          }
+        }
+      }
+      this.RtableData = this.RtableData.filter(item => {
+        return !(item == 'undefined')
+      })
+      if (this.LtableData.length < 20 && this.lPage.Total > 49) {
+        this.queryLeftTable()
+      }
+      if (this.RtableData.length < 20 && this.rPage.Total > 49) {
+        this.queryRightTable()
+      }
+    },
+    //表格中的选中事件
+    leftSelectionChange(selection) {
+      this.lArray = selection;
+    },
+    rightSelectionChange(selection) {
+      this.rArray = selection;
+    },
+    //查询左侧列表
+    queryLeftTable() {
+      this.lPage.pageNumber = 1;
+      if (this.$refs.lTableBody && this.$refs.lTableBody.bodyWrapper) {
+        this.$refs.lTableBody.bodyWrapper.scrollTop = 0
+      }
+      this.getLeftData();
+    },
+    //查询右侧列表
+    queryRightTable() {
+      this.rPage.pageNumber = 1;
+      if (this.$refs.rTableBody && this.$refs.rTableBody.bodyWrapper) {
+        this.$refs.rTableBody.bodyWrapper.scrollTop = 0
+      }
+      this.getRightData();
+    },
+    //获取待关联点位-左侧
+    getLeftData() {
+      let param = {
+        PageNumber: this.lPage.pageNumber,
+        PageSize: this.lPage.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.lTableLoading = true;
+      dynamicPendingPoint(param, res => {
+        this.lPage.total = res.PageSize < 50 ? res.PageSize : res.Total;
+        if (this.lPage.pageNumber == 1) {
+          this.LtableData = res.Content;
+        } else {
+          this.LtableData = this.LtableData.concat(res.Content);
+        }
+        this.lTableLoading = false;
+      });
+    },
+    //获取待关联实例-右侧
+    getRightData() {
+      let param = {
+        PageNumber: this.rPage.pageNumber,
+        PageSize: this.rPage.pageSize,
+        TypeNameList: [this.typeName]
+      };
+      //处理查询条件
+      if (this.form.ObjectLocalName && this.form.ObjectLocalName.length) {
+        param.ObjectLocalName = this.form.ObjectLocalName;
+      }
+      if (this.form.SubTypeName.length) {
+        param.SubTypeNameList = this.form.SubTypeName;
+      }
+      if (this.form.locationVal.length > 0) {
+        param.BuildLocalName = this.form.locationVal[0];
+      }
+      if (this.form.locationVal.length > 1) {
+        param.FloorLocalName = this.form.locationVal[1];
+      }
+      if (this.form.locationVal.length > 2) {
+        param.SpaceType = this.form.locationVal[2];
+      }
+      if (this.form.locationVal.length > 3) {
+        param.RoomLocalName = this.form.locationVal[3];
+      }
+      if (!this.form.locationVal.length) {
+        delete param.BuildLocalName
+        delete param.FloorLocalName
+        delete param.SpaceType
+        delete param.RoomLocalName
+      }
+      this.rTableLoading = true;
+      dynamicPendingobjs(param, res => {
+        this.rPage.total = res.PageSize < 50 ? res.PageSize : res.Total;
+        if (this.rPage.pageNumber == 1) {
+          this.RtableData = res.Content;
+        } else {
+          this.RtableData = this.RtableData.concat(res.Content);
+        }
+        this.rTableLoading = false;
+      });
+    },
+    //清除对应关系成功
+    deleteSuc() {
+      this.num--;
+      this.queryLeftTable();
+      this.queryRightTable();
+    },
+    //所在位置修改
+    changeLocation(val) {
+      this.form.locationVal = val;
+      this.queryRightTable();
+    },
+    //数据字典系统类型修改
+    changeDictionary(val) {
+      this.form.SubTypeName = val;
+      this.queryLeftTable();
+      this.queryRightTable();
+    },
+    //数据源修改
+    changeDataSource(val) {
+      this.form.Datasource = val;
+      this.queryLeftTable();
+    },
+    //修改位置标签
+    changeLocationFlag(val) {
+      this.form.LocationFlag = val;
+      this.queryLeftTable();
+    },
+    //返回
+    goback() {
+      this.$router.push({ path: '/point/dynamicdata', query: { typeName: this.typeName } })
+    },
+    //点击行
+    clickLeftRow(row, column, event) {
+      this.$refs.lTableBody.toggleRowSelection(row);
+    },
+    //点击行
+    clickRightRow(row, column, event) {
+      this.$refs.rTableBody.toggleRowSelection(row);
+    },
+  },
+  watch: {
+    projectId(n, o) {
+      this.init();
+    },
+    //判断两边是否均有选中值-创建关联
+    requestFlag(n, o) {
+      if (n) {
+        this.rightRecoList = [];
+        this.leftRecoList = [];
+        let object = {
+          Objs: this.rArray,
+          Points: this.lArray
+        };
+        let param = [];
+        param.push(object);
+        setTimeout(() => {
+          this.reGetData();
+        }, 200)
+        dynamicCreateRelation(param, res => {
+          if (res.Result == "success") {
+            this.$message.success("关联成功");
+          }
+        });
+      }
+    },
+    //AI辅助-左侧
+    lArray(n, o) {
+      //先清空,返回结果后赋值
+      this.rightRecoList = [];
+      clearTimeout(this.timer);
+      if (this.isSwitch && n.length) {
+        this.timer = setTimeout(() => {
+          let param = []
+          n.map(item => {
+            param.push({
+              Points: [item],
+              Top: 3,
+              Proximity: 0.5
+            })
+          })
+          dynamicQueryAI(param, res => {
+            this.rightRecoList = res.Content[0].Objs;
+            this.leftAI = !this.rightRecoList.length
+          })
+        }, 800)
+      } else {
+        this.rightRecoList = []
+        this.leftAI = true;
+      }
+    },
+    //AI辅助-右侧
+    rArray(n, o) {
+      this.leftRecoList = [];
+      clearTimeout(this.timer);
+      if (this.isSwitch && n.length) {
+        this.timer = setTimeout(() => {
+          let param = []
+          n.map(item => {
+            param.push({
+              Objs: [item],
+              Top: 3,
+              Proximity: 0.5
+            })
+          })
+          dynamicQueryAI(param, res => {
+            this.leftRecoList = res.Content[0].Points;
+            this.leftAI = !!this.leftRecoList.length
+          })
+        }, 800)
+      } else {
+        this.leftRecoList = []
+        this.leftAI = false
+      }
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+#addRelation {
+  height: 100%;
+  background-color: #fff;
+  padding: 10px 20px 10px 10px;
+  .text-right {
+    text-align: right;
+  }
+  /deep/ .table-container {
+    height: calc(100% - 160px);
+    & > div {
+      width: 49.5%;
+      float: left;
+    }
+    .left-table,
+    .right-table {
+      height: 100%;
+      h5 {
+        line-height: 44px;
+        padding-left: 5px;
+        background-color: #e1e4e5;
+        color: #2b2b2b
+      }
+      .query-box {
+        margin-bottom: 20px;
+        .query-item {
+          float: left;
+          width: 30%;
+          margin: 5px;
+          label {
+            display: block;
+            margin-bottom: 5px;
+          }
+          .el-select {
+            width: 100%;
+          }
+        }
+      }
+      .table-box {
+        height: calc(100% - 50px);
+        position: relative;
+        .AIRecom {
+          position: absolute;
+          width: 96%;
+          height: 160px;
+          bottom: 5px;
+          left: 1%;
+          background-color: rgba(255, 255, 255, 0.9);
+          z-index: 3;
+          font-size: 12px;
+          .r-title {
+            padding-left: 10px;
+            i {
+              float: right;
+            }
+          }
+          .l-title {
+            text-align: right;
+            padding-right: 10px;
+            i {
+              float: left;
+            }
+          }
+          .ai-recom-item {
+            width: 30%;
+            height: 126px;
+            float: left;
+            border: 1px solid #ebeef5;
+            overflow: hidden;
+            padding-top: 5px;
+            box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+            p {
+              position: relative;
+              white-space: nowrap;
+              text-overflow: ellipsis;
+              overflow: hidden;
+              padding: 0 8px;
+              z-index: -1;
+              span {
+                float: right;
+              }
+              .el-checkbox {
+                margin-right: 0;
+              }
+            }
+          }
+          .ai-recom-item.r-ai-recom-item + .ai-recom-item {
+            margin-left: 3%;
+          }
+          .l-ai-recom-item {
+            float: right;
+            p {
+              text-align: right;
+              padding-right: 10px;
+              span {
+                float: left;
+              }
+            }
+          }
+          .ai-recom-item.l-ai-recom-item + .ai-recom-item {
+            margin-right: 3%;
+          }
+        }
+      }
+      ::-webkit-scrollbar {
+        display: none;
+      }
+      //列表
+      .custom-table {
+        height: 100%;
+        .bgf5 {
+          background-color: #f5f7fa;
+        }
+        thead label.el-checkbox {
+          display: none;
+        }
+      }
+      .l-custom-table {
+        td {
+          text-align: right;
+        }
+      }
+      .tool-tip {
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+    }
+  }
+  .fr {
+    padding-top: 10px;
+    float: right;
+  }
+  .clearfix:before,
+  .clearfix:after {
+    content: "";
+    display: block;
+    clear: both;
+  }
+  .clearfix {
+    zoom: 1;
+  }
+  .ani-his-plus {
+    position: relative;
+    .plusOne {
+      position: absolute;
+      color: red;
+      left: 50%;
+      bottom: 50%;
+      font-size: 20px;
+      font-weight: 800;
+    }
+    .startAni {
+      animation: fadeToTop 1s;
+    }
+  }
+  @keyframes fadeToTop {
+    0% {
+      left: 50%;
+      bottom: 50%;
+      opacity: 1;
+    }
+    100% {
+      bottom: 100%;
+      opacity: 0;
+    }
+  }
+}
+</style>
+<style>
+body {
+  overflow-y: hidden;
+}
+</style>

+ 43 - 11
src/views/point/dynamicdata/index.vue

@@ -2,7 +2,7 @@
   <div id="dynamicdata">
     <!-- tab分页 -->
     <el-row class="top-tab">
-      <el-tabs v-model="curType">
+      <el-tabs v-model="curType" type='card'>
         <el-tab-pane v-for="(item) in typeList" :key="item.Name" :label="item.Name+'('+item.Sum+'/'+item.Rcount+')'" :name="item.Name">
         </el-tab-pane>
       </el-tabs>
@@ -26,10 +26,20 @@
         </el-tooltip>
       </div>
     </el-row>
-    <equip-rules v-if="curType=='设备'" ref="equip" :typeName="curType" @refresh="equipRefresh" :isPending="isPending"></equip-rules>
-    <!-- <parts-rules v-if="!curType=='设备'" ref="parts" :typeName="'设备'"></parts-rules> -->
+    <!-- 设备 -->
+    <equipRules v-if="curType=='设备'" ref="equip" :typeName="curType" @refresh="refreshTabs" :isPending="isPending"></equipRules>
+    <!-- 部件 -->
+    <partsRules v-else-if="curType=='部件'" ref="parts" :typeName="curType" @refresh="refreshTabs" :isPending="isPending"></partsRules>
+    <!-- 系统 -->
+    <systemRules v-else-if="curType=='系统'" ref="system" :typeName="curType" @refresh="refreshTabs" :isPending="isPending"></systemRules>
+    <!-- 空间 -->
+    <spaceRules v-else-if="curType=='空间'" ref="space" :typeName="curType" @refresh="refreshTabs" :isPending="isPending"></spaceRules>
+    <!-- 开发中 -->
+    <div v-else>开发中</div>
     <!-- 应用规则弹窗 -->
-    <apply-rules-dialog ref="apply" @refresh="getExecuteFeedback" @cancel="cancelApply"></apply-rules-dialog>
+    <apply-rules-dialog ref="apply" @refresh="getExecuteFeedback" @cancel="cancelApply" @clash="getClash"></apply-rules-dialog>
+    <!-- 冲突日志 -->
+    <applyLog ref="applyLog"></applyLog>
     <!-- 规则更新提示 -->
     <el-dialog title="提示" :visible.sync="ruleDialogShow" width="25%" @close="rulesClose">
       <span>{{tipCon}}</span>
@@ -39,7 +49,7 @@
       </span>
     </el-dialog>
     <!-- 选择增量 or 全量 执行 -->
-    <el-dialog title="提示" :visible.sync="allApplyDialog" width="50%" @close="allApplyClose">
+    <el-dialog title="提示" :visible.sync="allApplyDialog" width="30%" @close="allApplyClose">
       <div id="applySelect">
         <el-radio v-model="force" :label="false">增量执行:只设定对应规则or原始点位有变化的实例动态参数信息点</el-radio>
         <p style="color:#999;">因自动判断是否变化,可能更新不够完整,但速度比较快</p>
@@ -63,9 +73,13 @@
 <script>
 import tools from "@/utils/tools";
 import { mapGetters, mapActions } from "vuex";
-import applyRulesDialog from "@/components/point/dynamicdata/applyRulesDialog";
+// import applyRulesDialog from "@/components/point/dynamicdata/applyRulesDialog";
+import applyRulesDialog from "@/components/point/dynamicdata/applyRulesDialog-copy";
+import applyLog from "@/components/point/dynamicdata/applyLog";
 import equipRules from "@/components/point/dynamicdata/equipRules";
 import partsRules from "@/components/point/dynamicdata/partsRules";
+import systemRules from "@/components/point/dynamicdata/systemRules";
+import spaceRules from "@/components/point/dynamicdata/spaceRules";
 import {
   dynamicClashConfirm,
   dynamicPromptmessage,
@@ -89,12 +103,16 @@ export default {
       force: false, //默认增量执行 ----- false - 增量 true - 全量执行
       isPending: false, //是否执行中:执行中禁用所有功能 true即为执行中
       missionID: '', //任务id
+      hasClash: false, //默认不含冲突
     };
   },
   components: {
     applyRulesDialog,
+    applyLog,
     equipRules,
-    partsRules
+    partsRules,
+    systemRules,
+    spaceRules
   },
   created() {
     let typeName = this.$route.query.typeName;
@@ -192,7 +210,7 @@ export default {
       this.tipsType = 0;
       this.isPending = true;
       this.allApplyClose()
-      this.$refs.apply.showDialog(this.force);
+      this.$refs.apply.showDialog(this.allApplyFlag);
     },
     //规则执行弹窗
     rulesClose() {
@@ -203,8 +221,8 @@ export default {
       this.allApplyDialog = false;
       this.force = false;
     },
-    //刷新设备类
-    equipRefresh(val) {
+    //刷新
+    refreshTabs(val) {
       this.curType = val;
       this.getTypeNames()
     },
@@ -224,6 +242,10 @@ export default {
             setTimeout(() => {
               this.isPending = false;
               this.getPrompt()
+              this.$refs.apply.getPromptobjs()
+              if (this.hasClash) {
+                this.$refs.applyLog.showDialog(missionID)
+              }
             }, 2000)
           } else {
             this.isPending = true;
@@ -239,6 +261,10 @@ export default {
     cancelApply(x) {
       this.isPending = false;
       this.tipsType = 1;
+    },
+    //接收是否有冲突
+    getClash(length) {
+      this.hasClash = !!length
     }
   },
   watch: {
@@ -255,7 +281,7 @@ export default {
   background-color: #fff;
   padding: 10px;
   position: relative;
-  .top-tab {
+  /deep/ .top-tab {
     position: relative;
     height: 54px;
     .pos-right {
@@ -272,6 +298,12 @@ export default {
         background-color: #fff;
       }
     }
+    /deep/ .el-tabs__item.is-top {
+      border-top: 2px solid transparent;
+      &.is-active {
+        border-top: 2px solid #409eff;
+      }
+    }
   }
   #applySelect {
     /deep/ .el-radio__input.is-checked + .el-radio__label {

+ 101 - 0
src/views/ready/buildfloor/addFloor/index.vue

@@ -0,0 +1,101 @@
+<template>
+  <el-dialog :title="title" :visible.sync="dialogVisible" width="40%" @close="handleClose" id="messageDialog">
+    <div>
+      <formItems :type="'Floor'" ref="formItems"></formItems>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button size="small">取消</el-button>
+      <el-button size="small" type="primary" @click="confirm">确认</el-button>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import {
+  manageCreateFloor,
+  manageUpdateFloor
+} from "@/api/scan/request";
+import formItems from "@/components/ready/buildfloor/formItems";
+import tools from "@/utils/buildfloor/tools";
+export default {
+  props: {
+    title: {
+      default: '提示'
+    },
+    type: {
+      default: 'Floor'
+    },
+    curBuildId: {
+      default: ''
+    },
+    curFloorId: {
+      default: ''
+    }
+  },
+  components: {
+    formItems
+  },
+  data() {
+    return {
+      dialogVisible: false, //弹窗显示与隐藏
+      floorData: {}
+    };
+  },
+  methods: {
+    showDialog(data) {
+      this.floorData = data || {};
+      this.floorData = tools.desFormatData(this.floorData)
+      this.timeoutSetVal()
+      this.dialogVisible = true;
+    },
+    timeoutSetVal() {
+      setTimeout(() => {
+        if (this.$refs.formItems) {
+          this.$refs.formItems.form = this.floorData
+        } else {
+          this.timeoutSetVal()
+        }
+      }, 500)
+    },
+    handleClose() { },
+    //创建
+    confirm() {
+      this.$refs.formItems.submitForm(this.save)
+    },
+    save() {
+      let form = this.$refs.formItems.form
+      let newform = tools.formatData(form)
+      newform.BuildID = this.curBuildId
+      let Param = {
+        Content: [newform]
+      }
+      if (newform.FloorID) {
+        manageUpdateFloor(Param, res => {
+          this.$message.success('更新成功')
+          this.$emit('refresh')
+          this.dialogVisible = false;
+        })
+      } else {
+        manageCreateFloor(Param, res => {
+          this.$message.success('创建成功')
+          this.$emit('refresh')
+          this.dialogVisible = false;
+        })
+      }
+    }
+  },
+  mounted() { },
+  created() { }
+};
+</script>
+<style lang="scss" scoped>
+#messageDialog {
+  .el-form-item {
+    /deep/ label.el-form-item__label {
+      font-size: 12px;
+    }
+  }
+  /deep/ .FloorTypeSelect .el-form-item__content {
+    width: 178px;
+  }
+}
+</style>

+ 2 - 0
src/views/ready/buildfloor/drawGraphy/bus.js

@@ -0,0 +1,2 @@
+import Vue from 'Vue';
+export default new Vue()

+ 143 - 0
src/views/ready/buildfloor/drawGraphy/checkGraphy.vue

@@ -0,0 +1,143 @@
+<template>
+  <el-dialog id="checkGraphy" title="添加平面图" :visible.sync="checkGraphyVisible" width="900px" @close="handleClose">
+    <div class="bodys">
+      <el-cascader :options="options" :show-all-levels="false" :props="props" @change="handleChange" @active-item-change='handleItemChange' clearable
+        placeholder="请选择模型文件" v-model="casVal"></el-cascader>
+      <div>
+        或
+        <el-button type="text">上传图片</el-button>
+      </div>
+      <!-- 展示框 -->
+      <div class="showBox">
+        <drawFloor ref="drawFloor"></drawFloor>
+      </div>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="handleClose">取 消</el-button>
+      <el-button type="primary" @click="bindGraphy">确 定</el-button>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import drawFloor from "./drawFloor";
+import { mapGetters, mapActions } from "vuex";
+import request from "@/api/model/file.js";
+import { floorUpdate } from "@/api/scan/request";
+export default {
+  components: {
+    drawFloor
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  data() {
+    return {
+      casVal:[],
+      jsonKey: "", //map.josn
+      checkGraphyVisible: false,
+      options: [],
+      floor: {}, // 当前选中的楼层数据
+    };
+  },
+  methods: {
+    // 弹窗显示
+    showDialog(floor) {
+      this.floor = floor;
+      this.checkGraphyVisible = true;
+    },
+    // 关闭弹窗
+    handleClose() {
+      this.checkGraphyVisible = false;
+      this.casVal = []
+      this.$refs.drawFloor.clearGraphy()
+    },
+    // 更新楼层 平面图文件
+    bindGraphy() {
+      if (!this.jsonKey) {
+        this.$message.warning("请选择模型文件");
+        return
+      }
+      if (!this.floor.StructureInfo) {
+        this.floor.StructureInfo = {}
+      }
+      this.floor.StructureInfo.FloorMap = this.jsonKey
+      let pa = {
+        Content: [this.floor]
+      };
+      floorUpdate(pa, res => {
+        this.$message.success("添加成功");
+        this.handleClose()
+        this.$emit('refresh')
+      });
+    },
+    // 点击多级联动
+    handleChange(val) {
+      this.$refs.drawFloor.initGraphy(val[1])
+      this.jsonKey = val[1]
+    },
+    // 通过id查询文件夹下模型文件
+    handleItemChange(val) {
+      let data = {
+        FolderId: val[0],
+        ProjectId: this.projectId
+      };
+      request.queryFloorList(data, res => {
+        let tempArr = res.Content.map(t => {
+          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)
+          }
+        }
+      })    },
+    init() {
+      this.getDirectory()
+    },
+    // 获取文件夹
+    getDirectory() {
+      request.queryModel("", res => {
+        this.options = res.Content.map(t => {
+          return {
+            value: t.Id,
+            label: t.Name,
+            children: []
+          }
+        })
+      });
+    },
+  },
+  created(){
+    this.init()
+  },
+  watch: {
+    projectId() {
+      this.init()
+    }
+  }
+};
+</script>
+<style lang="less">
+#checkGraphy {
+  .bodys {
+    .showBox {
+      box-sizing: border-box;
+      width: 100%;
+      height: 300px;
+      border: 1px #ccc solid;
+      padding: 10px;
+    }
+  }
+}
+</style>

+ 118 - 0
src/views/ready/buildfloor/drawGraphy/drawFloor.vue

@@ -0,0 +1,118 @@
+<template>
+  <div id="drawFloor" v-loading="canvasLoading">
+    <canvas id="floorCanvas" :width="cadWidth" :height="cadHeight" ref="canvas"></canvas>
+  </div>
+</template>
+
+<script>
+import eventBus from "./bus.js";
+import { SGraphyView } from "@sybotan-web/graphy/lib";
+import { FloorScene } from "cad-engine";
+import { SColor } from "@sybotan-web/draw/lib";
+export default {
+  data() {
+    return {
+      drawMainScene: null,
+      view: null,
+      dataKey: '',
+      cadWidth: 800,
+      cadHeight: 600,
+      canvasLoading: false
+    };
+  },
+  mounted() {
+    // this.initGraphy('3af6d175c34e11e993ac85337be80696');
+    // let that = this;
+    // eventBus.$on("suitableRatios", function () {
+    //   that.view.fitSceneToView();
+    // });
+    // eventBus.$on("changeRatios", function (val) {
+    //   that.changeRatios(val);
+    // });
+    // eventBus.$on("downImgs", function (val) {
+    //   that.view.saveImage("saveImage" + new Date(), "png");
+    // });
+    // eventBus.$on("openDrags", function (val) {
+    //   if (val) {
+
+    //   }
+    // });
+    this.cadWidth = document.getElementById("drawFloor").offsetWidth;
+    this.cadHeight = document.getElementById("drawFloor").offsetHeight;
+  },
+  methods: {
+    clickItem(item) {
+      this.$emit("clickGraphyItem", item);
+    },
+    // 单个个体绘制颜色
+    drawItemColor(item, color) {
+      item.fillColor = new SColor(color); //需要缓存的边框
+      item.cacheFillColor = new SColor(color); //需要
+    },
+    // 绘制所有的item
+    drawAllItemColor() {
+      this.drawMainScene.root.children.forEach((item, index) => {
+        let color = this.initColor[index % 10];
+        this.drawItemColor(item, color);
+      });
+    },
+    initGraphy(ModelId) {
+      this.dataKey = ModelId
+      if (!this.dataKey) {
+        return;
+      }
+      this.canvasLoading = true
+      this.clearGraphy()
+      // 初始化view类
+      this.view = new SGraphyView("floorCanvas");
+      this.drawMainScene = new FloorScene(null);
+      let that = this;
+      this.drawMainScene.getFloorData('/modelapi/base-graph/query', { ModelId: ModelId }).then(res => {
+        that.view.scene = that.drawMainScene
+        that.view.fitSceneToView();
+        this.canvasLoading = false
+      })
+      if (this.isScale) {
+        this.cancelScale(this.view);
+      }
+    },
+    // 单个item 高亮
+    heightLightitem(item, highlightColor) {
+      // this.drawItemColor(item, highlightColor);
+    },
+    // 取消放大缩小
+    cancelScale(view) {
+      // view.wheelZoom = 1;
+    },
+    // 左键长按控制canvas的坐标
+    leftClickMove(a, b) {
+      //  console.log('move',a,b)
+    },
+    changeRatios(val) {
+      //计算缩放比例
+      this.view.scale = val;
+    },
+    clearGraphy() {
+      if(this.drawMainScene){
+        this.drawMainScene.root.children = null
+        this.drawMainScene = null;
+        this.view = null;
+      }
+    }
+  },
+  watch: {
+    findGraphyItemId(n) {
+      if (n) {
+        this.heightLightitem();
+      }
+    }
+  }
+};
+</script>
+<style scoped lang="less">
+#drawFloor {
+  width: 100%;
+  height: 100%;
+  position: relative;
+}
+</style>

+ 112 - 0
src/views/ready/buildfloor/drawGraphy/operateGraphyItem.vue

@@ -0,0 +1,112 @@
+<template>
+  <div id="operateGraphyItem">
+    <div class="div-box" @click="openDrag">
+      <i class="el-icon-rank"></i>
+    </div>
+    <div class="div-box" @click="suitableRatio">
+      <i class="el-icon-rank"></i>
+    </div>
+    <div class="div-box" @click="downImg">
+      <i class="el-icon-download"></i>
+    </div>
+    <div class="div-box" @click="removeRatio">
+      <i class="el-icon-remove-outline"></i>
+    </div>
+    <div class="line">
+      <el-slider tooltip-class="tooltip-class"  :max="0.02" :min="0.004" v-model="sliderValue" @change="adjustRatio"></el-slider>
+    </div>
+    <div class="div-box" @click="addRatio">
+      <i class="el-icon-circle-plus-outline"></i>
+    </div>
+  </div>
+</template>
+<script>
+import eventBus from "./bus.js";
+export default {
+  data() {
+    return {
+      sliderValue: 0.004,
+      isopenDrags:false ,//是否鼠标左键移动图片
+    };
+  },
+  methods: {
+    // 开启拖动
+    openDrag() {
+      this.isopenDrags = !this.isopenDrags;
+      eventBus.$emit('openDrags',this.isopenDrags)
+    },
+    //合适比例
+    suitableRatio() {
+      eventBus.$emit("suitableRatios");
+    },
+    // 滑块调整比例
+    adjustRatio(val) {
+      this.sliderValue = val;
+      eventBus.$emit("changeRatios", this.sliderValue);
+    },
+    //增加比例
+    addRatio() {
+      if (this.sliderValue >= 0.02) {
+        this.sliderValue = 0.02;
+      } else {
+        this.sliderValue = this.sliderValue + 0.001;
+      }
+      eventBus.$emit("changeRatios", this.sliderValue);
+    },
+    //减少比例
+    removeRatio() {
+      if (this.sliderValue <=0.004) {
+        this.sliderValue = 0.004;
+      } else {
+        this.sliderValue = this.sliderValue - 0.001;
+      }
+      eventBus.$emit("changeRatios", this.sliderValue);
+    },
+    // 下载图片
+    downImg(){
+      eventBus.$emit("downImgs");
+    }
+  },
+  mounted() {
+    let that = this;
+     eventBus.$on('viewScale',function(scale){
+       console.log(scale,'scalescale')
+       that.sliderValue = scale;
+
+     })
+  },
+};
+</script>
+<style lang="less">
+#operateGraphyItem {
+  display: flex;
+  position: relative;
+  border: 1px #ddd solid;
+  border-radius: 5px;
+  overflow: hidden;
+  z-index: 999;
+  .div-box {
+    font-size: 24px;
+    width: 40px;
+    height: 40px;
+    background: #67c23a;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    color: #fff;
+    cursor: pointer;
+    border-right: 1px #ddd solid;
+  }
+  .line {
+    width: 200px;
+    font-size: 12px;
+    display: block;
+    background: #67c23a;
+    border-right: 1px #ddd solid;
+    .tooltip-class {
+      width: 100%;
+      background-color: #409eff;
+    }
+  }
+}
+</style>

+ 60 - 0
src/views/ready/buildfloor/drawGraphy/repetitionGraphy.vue

@@ -0,0 +1,60 @@
+<template>
+  <el-dialog id="checkdrawimg" title="前期准备/建筑楼层管理/平面图维护" :visible.sync="repetitionGraphyVisible" width="60%" :before-close="handleClose">
+    <div class="bodys">
+      <div class="buttons">
+        <el-button icon="el-icon-back" size="mini"></el-button>
+        <el-button size="mini">替换平面图</el-button>
+        <el-button size="mini">编辑平面图</el-button>
+      </div>
+      <!-- 展示图片 -->
+      <div class="drawImg">
+        <drawFloor ref="drawFloor" :findGraphyItemId="findGraphyItemId" :point="point" :pointWidth="pointWidth" :cadWidth="1000" :cadHeight="500"
+          :isScale="true"></drawFloor>
+      </div>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="dialogVisible = false">取 消</el-button>
+      <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import drawFloor from "./drawFloor";
+export default {
+  components: {
+    drawFloor
+  },
+  props: {
+    repetitionGraphyVisible: Boolean
+  },
+  data() {
+    return {
+      modelId: "04153a22ce3111e9b1c7318645437bfe", // key
+      point: [40703.54760591985, 42678.14510522981], //坐标
+      pointWidth: 2000,
+      findGraphyItemId: "" //高亮的id
+    };
+  },
+  methods: {
+    handleClose() {
+      this.$emit("closeRepeatVisible");
+    }
+  },
+  mounted(){
+    // this.modelId = this.$router.query.modelId
+    console.log(22222)
+    let modelId = this.modelId
+    this.$refs.drawFloor.initGraphy(modelId)
+  }
+};
+</script>
+<style lang="less">
+#checkdrawimg {
+  .drawImg {
+    width: 100%;
+    height: 500px;
+    margin-top: 12px;
+    border: 1px solid #ccc;
+  }
+}
+</style>

+ 315 - 28
src/views/ready/buildfloor/index.vue

@@ -1,36 +1,323 @@
 <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 id="bd-fl-manage">
+    <el-row>
+      <div class="l-list">
+        <div class="action-box">
+          <div>
+            <el-button size="small" type="default" icon="el-icon-plus" @click="addBuild"></el-button>
+            <el-button size="small" type="default" icon="el-icon-minus" @click="delBuild"></el-button>
+            <el-button size="small" type="default" icon="el-icon-edit-outline" @click="editBuild"></el-button>
+          </div>
+        </div>
+        <h4>建筑</h4>
+        <div class="build-list">
+          <div v-for="(item,index) in buildList" :key="item.BuildID" :class="{'floor-item':true,active:item.active}" @click="changeBuild(index)">
+            <span>
+              {{item.BuildLocalName || item.BuildName}}
+              <el-badge class="mark" :is-dot="false" />
+            </span>
+          </div>
+        </div>
+      </div>
+      <div class="r-table">
+        <div class="action-box">
+          <el-button size="small" type="default" @click="addFloor">添加楼层</el-button>
+        </div>
+        <div class="table-box">
+          <el-table :data="tableData" style="width: 100%" height="100%" v-loading="loading" :header-cell-style="headerStyle">
+            <el-table-column label="楼层本地名">
+              <template slot-scope="scope">{{scope.row.FloorLocalName||scope.row.FloorName}}</template>
+            </el-table-column>
+            <el-table-column label="楼层顺序号">
+              <template slot-scope="scope">{{scope.row.FloorSequenceID}}</template>
+            </el-table-column>
+            <el-table-column label="楼层信息">
+              <template slot-scope="scope">
+                <el-button size="mini" @click="editFloorData(scope.row)" plain icon="el-icon-edit-outline"></el-button>
+              </template>
+            </el-table-column>
+            <el-table-column prop="Datasource" label="平面图">
+              <template slot-scope="scope">
+                <p v-if="scope.row.StructureInfo&&scope.row.StructureInfo.FloorMap" @click="checfDrawImg(scope.row,1)">
+                  <i class="iconfont icon-floorplan"></i>
+                  查看平面图
+                </p>
+                <p v-else-if="scope.row.type==2" @click="checfDrawImg(scope.row,2)">
+                  <el-badge is-dot>
+                    <i class="iconfont icon-floorplan"></i>
+                  </el-badge>平面图重复
+                </p>
+                <p v-else @click="checfDrawImg(scope.row,3)">
+                  <i class="iconfont icon-nopicture"></i>
+                  暂无平面图
+                </p>
+              </template>
+            </el-table-column>
+            <el-table-column prop="SubTypeName" label="楼层贯通关系">
+              <template slot-scope="scope">
+                <span style="margin-right:20px">{{scope.row.FloorThroughList?scope.row.FloorThroughList.length:0}}</span>
+                <el-button size="mini" @click="changeConnection(scope.row)" plain icon="el-icon-edit-outline"></el-button>
+              </template>
+            </el-table-column>
+            <el-table-column prop="action" label="操作">
+              <template slot-scope="scope">
+                <el-button size="mini" @click="handleDelete(scope.row)" type="danger" plain icon="el-icon-delete"></el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </div>
+    </el-row>
+    <!-- 添加-修改楼层 -->
+    <addFloor :title="floorTitle" ref="addFloorDialog" :curBuildId="curBuildId" :curFloorId="curFloorId" @refresh="refresh"></addFloor>
+    <!-- 添加-修改建筑 -->
+    <addBuild :title="buildTitle" ref="addBuildDialog"></addBuild>
+    <!-- 删除建筑-删除楼层 -->
+    <el-dialog title="提示" :visible.sync="delDialogVis" width="20%" @close="handleClose" id="messageDialog">
+      <div>确定要删除该{{delText}}?</div>
+      <span slot="footer" class="dialog-footer">
+        <el-button size="small" @click="delDialogVis=false">取消</el-button>
+        <el-button size="small" type="primary" @click="confirmDel">确认</el-button>
+      </span>
+    </el-dialog>
+    <!-- 添加贯通关系弹窗 -->
+    <addConnectivity ref="addConnectivity" @refresh="refresh"></addConnectivity>
+    <!-- 查看图片弹窗 -->
+    <checkGraphy ref="checkGraphy" @refresh="refresh"></checkGraphy>
+  </div>
 </template>
 
 <script>
-import dasBoard from "@/views/dasboard/index";
+import addFloor from "@/views/ready/buildfloor/addFloor/index";
+import addBuild from "@/components/ready/buildfloor/addBuild";
+import { mapGetters, mapActions } from "vuex";
+import addConnectivity from "@/components/ready/buildfloor/addConnectivity";
+import checkGraphy from "./drawGraphy/checkGraphy"; //查看图片
+import { buildingQuery, floorQuery, manageDeleteFloor } from "@/api/scan/request";
 export default {
-    components: {
-      dasBoard
-    },
-    data() {
-        return {
-          plan: "2019-08",
-          finish: "2019-08",
-          onLine: "2019-08",
-          explain: "建筑楼层管理"
+  components: {
+    addFloor,
+    addBuild,
+    addConnectivity,
+    checkGraphy
+  },
+  data() {
+    return {
+      repetitionGraphyVisible: false, // 替换平面图弹窗
+      floorTitle: "添加楼层",
+      buildTitle: "添加建筑",
+      delDialogVis: false,
+      delText: "建筑",
+      headerStyle: {
+        backgroundColor: "#d9d9d9",
+        color: "#2b2b2b",
+        lineHeight: "30px"
+      },
+      buildList: [],
+      tableData: [
+        {
+          EquipmentMark: 1
+        }
+      ],
+      page: {
+        pageSize: 500,
+        pageSizes: [10, 20, 50, 100],
+        pageNumber: 1,
+        total: 0
+      },
+      loading: false, //列表loading
+      curBuildId: "", //当前选中的建筑id
+      curFloorId: "", //当前选中的楼层id
+      modelId: "",
+    };
+  },
+  computed: {
+    ...mapGetters("layout", ["projectId"])
+  },
+  mounted() { },
+  created() {
+    this.init();
+  },
+  methods: {
+    init() {
+      let bdParam = {
+        PageNumber: 1,
+        PageSize: 500
+      };
+      buildingQuery(bdParam, res => {
+        this.buildList = res.Content;
+        if (this.buildList.length) {
+          this.changeBuild(0);
         }
+      });
+    },
+    //change build
+    changeBuild(index) {
+      this.buildList.map(item => {
+        item.active = false;
+        return item;
+      });
+      this.buildList[index].active = true;
+      this.curBuildId = this.buildList[index].BuildID;
+      this.getFloorTableData();
+      this.$forceUpdate();
+    },
+    //add build
+    addBuild() {
+      this.$message.warning("开发中...");
+      return;
+      this.$refs.addBuildDialog.showDialog();
+    },
+    //delete build
+    delBuild() {
+      this.$message.warning("开发中...");
+      return;
+      this.delText = "建筑";
+      this.delDialogVis = true;
+    },
+    //edit build
+    editBuild() {
+      this.$message.warning("开发中...");
+      return;
+    },
+    //delete floor
+    handleDelete(floor) {
+      this.delText = "楼层";
+      this.delDialogVis = true;
+      this.curFloorId = floor.FloorID;
+    },
+    //确认删除弹窗关闭
+    handleClose() { },
+    addFloor() {
+      this.curFloorId = "";
+      this.$refs.addFloorDialog.showDialog();
+    },
+    // 获取列表
+    getFloorTableData() {
+      let floorParam = {
+        Cascade: [{ Name: "floorThroughList" }],
+        Orders: "FloorSequenceID desc",
+        PageNumber: this.page.pageNumber,
+        PageSize: this.page.pageSize,
+        Filters: `BuildID='${this.curBuildId}'`
+      };
+      floorQuery(floorParam, res => {
+        this.tableData = res.Content;
+        this.page.total = res.Total;
+      });
+    },
+    // 创建楼层成功-修改关系成功
+    refresh() {
+      this.getFloorTableData();
     },
-    mounted() {}
+    // 确认删除(删除建筑-楼层公用)
+    confirmDel() {
+      if (this.delText == "楼层") {
+        let delParam = [{ FloorID: this.curFloorId }];
+        manageDeleteFloor(delParam, res => {
+          this.$message.success("删除成功");
+          this.delDialogVis = false;
+          this.getFloorTableData();
+        });
+      } else {
+        //todo
+      }
+    },
+    // 修改楼层信息
+    editFloorData(floor) {
+      this.floorTitle = "编辑楼层信息";
+      this.curFloorId = floor.FloorID;
+      this.$refs.addFloorDialog.showDialog(floor);
+    },
+    // 修改楼层贯通关系
+    changeConnection(row) {
+      this.$refs.addConnectivity.showDialog();
+      this.$refs.addConnectivity.floor = row;
+    },
+    // 查看平面图
+    checfDrawImg(row, index) {
+      if (3 == index) {
+        this.$refs.checkGraphy.showDialog(row)
+        this.modelId = "";
+      } else {
+        this.modelId = row.StructureInfo.FloorMap;
+        this.$router.push({ name: "repetitionGraphy", query: { modelId: this.modelId } });
+      }
+    }
+  },
+  watch: {
+    projectId() {
+      this.init();
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+#bd-fl-manage {
+  overflow: hidden;
+  height: 100%;
+  position: relative;
+  .el-row {
+    height: 100%;
+    & > 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: 17%;
+      overflow-y: auto;
+      h4 {
+        padding-left: 10px;
+        border-top: 1px solid #d9d9d9;
+        border-bottom: 1px solid #d9d9d9;
+        background: #d9d9d9;
+        color: #2b2b2b;
+        line-height: 44px;
+      }
+      .build-list {
+        line-height: 48px;
+        .floor-item {
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          span {
+            margin-left: 10px;
+          }
+        }
+        .floor-item.active,
+        .floor-item:hover {
+          background-color: #f5f7fa;
+          color: #000;
+        }
+      }
+    }
+    .r-table {
+      width: 82%;
+      margin-left: 1%;
+      .table-box {
+        height: calc(100% - 54px);
+        margin-bottom: 8px;
+        .iconfont {
+          vertical-align: middle;
+        }
+        /deep/ .el-badge__content.is-fixed {
+          transform: translateY(-6%) translateX(-100%);
+        }
+        p {
+          cursor: pointer;
+        }
+      }
+    }
+  }
 }
-</script>
+</style>

+ 82 - 0
src/views/ready/buildfloor/repetitionGraphy.vue

@@ -0,0 +1,82 @@
+<template>
+  <!-- 查看平面图页面 -->
+  <div id="repetitionGraphy">
+    <div class="buttons">
+      <el-button icon="el-icon-back" size="mini" @click="backRouter"></el-button>
+      <el-button size="mini" @click="changeGraphy">替换平面图</el-button>
+      <el-button size="mini">编辑平面图</el-button>
+    </div>
+    <!-- 展示图片 -->
+    <div class="drawImg">
+      <drawFloor ref="drawFloor"></drawFloor>
+    </div>
+    <!-- 查看图片弹窗 -->
+    <checkGraphy :checkGraphyVisible="checkGraphyVisible" @handleCloseCGraphy="checkGraphyVisible=false"></checkGraphy>
+    <div id="operateList">
+      <operateGraphyItem></operateGraphyItem>
+    </div>
+  </div>
+</template>
+<script>
+import drawFloor from "./drawGraphy/drawFloor";
+import checkGraphy from "./drawGraphy/checkGraphy"; //查看图片
+import operateGraphyItem from "./drawGraphy/operateGraphyItem" //各个item
+export default {
+  components: {
+    drawFloor,
+    checkGraphy,
+    operateGraphyItem
+  },
+  data() {
+    return {
+      checkGraphyVisible: false, //查看平面图弹窗
+      modelId: "04153a22ce3111e9b1c7318645437bfe", // key
+      point: [40703.54760591985, 42678.14510522981], //坐标
+      pointWidth: 2000,
+      findGraphyItemId: "", //高亮的id
+      slidervalue: 0
+    };
+  },
+  methods: {
+    handleClose() {
+      this.$emit("closeRepeatVisible");
+    },
+    // 返回路由
+    backRouter() {
+      this.$router.go(-1);
+    },
+    // 替换模型文件
+    changeGraphy() {
+      this.checkGraphyVisible = true;
+    },
+  },
+  mounted() {
+    // this.dataKey = `/image-service/common/file_get/${this.$route.query.jsonKey}?systemId=revit`;
+    // this.modelId = this.$router.query.modelId
+    let modelId = this.modelId
+    console.log(this.$refs.drawFloor)
+    this.$refs.drawFloor.initGraphy(modelId)
+  },
+};
+</script>
+<style lang="less">
+#repetitionGraphy {
+  width: 100%;
+  height: 100%;
+  background: #fff;
+  position: relative;
+  padding: 10px;
+  box-sizing: border-box;
+  .drawImg {
+    width: 100%;
+    margin-top: 10px;
+    height: calc(100% - 40px);
+  }
+  #operateList {
+    position: absolute;
+    left: 50%;
+    bottom: 100px;
+    // margin-left:
+  }
+}
+</style>

+ 121 - 100
src/views/ready/collectsetting/index.vue

@@ -1,24 +1,21 @@
-<!--
-  revit信息点开关
- -->
 <template>
     <div id="family">
+        <nav>
+            <div class="tab-box">
+                <el-tabs v-model="value" @tab-click="chooseMedicine" type="card">
+                    <el-tab-pane v-for="item in options" :key="item.value" :label="item.label" :name="item.value">{{item.label}}</el-tab-pane>
+                </el-tabs>
+            </div>
+            <div class="button-box">
+                <el-button @click="handleClickConfig" size="small">批量配置信息点</el-button>
+            </div>
+        </nav>
         <main>
             <div class="left_main" v-loading="isLoading">
                 <header>
-                    <!-- <select class="form-control" v-model="value" @change="chooseMedicine">
-                    <option v-for="(opt,index) in options" :key="index" :value="opt.value">{{ opt.label }}</option>
-                </select>
-                    <build-input style="width:20rem;" @search="changeVal" :placeholder="'支持关键字、英文代号查找'"></build-input> -->
-                    <el-select style="width:90px;" v-model="value"  @change="chooseMedicine" placeholder="请选择">
-                        <el-option
-                        v-for="item in options"
-                        :key="item.value"
-                        :label="item.label"
-                        :value="item.value">
-                        </el-option>
-                    </el-select>
-                    <el-input style="width:235px;" v-model="searchVal" @change="changeVal" placeholder="支持关键字、英文代号查找" clear></el-input>
+                    <el-input style="width:323px;" v-model="searchVal" @change="changeVal" placeholder="支持关键字、英文代号查找" clearable>
+                        <i slot="prefix" class="el-input__icon el-icon-search" style="cursor:pointer;" @click="changeVal(searchVal)"></i>
+                    </el-input>
                 </header>
                 <div class="family_all">
                     <div class="family" v-for="(letter,index) in letterArr" :key="index">
@@ -44,13 +41,13 @@
                 </div>
             </div>
             <div class="right_main" v-loading="rightLoading">
-                <el-tabs v-if="labelKey.length && tabsFalg" tab-position="left" style="height: 100%;">
+                <el-tabs v-if="labelKey.length && tabsFalg" tab-position="right" style="height: 100%;">
                     <el-tab-pane v-for="(item,index) in labelKey" :key="index">
                         <span slot="label">{{item.FirstName || '信息'}}</span>
                         <div class="label_main" v-for="(tag,tagIndex) in item.details" :key="tagIndex">
                             <p>{{tag.SecondName}}</p>
                             <ul v-for="(detail,detailInd) in tag.details" :key="detailInd">
-                                <el-checkbox :title="detail.InfoPointName" v-model="detail.Visible" @change="boxChange(detail)">{{detail.InfoPointName}}</el-checkbox>
+                                <el-checkbox :title="detail.InfoPointName" :disabled="!detail.UnDisabled" v-model="detail.Visible" @change="boxChange(detail)">{{detail.InfoPointName}}</el-checkbox>
                             </ul>
                         </div>
                     </el-tab-pane>
@@ -60,6 +57,8 @@
                 </div>
             </div>
         </main>
+        <!-- 批量配置信息点 -->
+        <config-dialog :dialog="dialog" @configInfo="familyActive(active, code)"></config-dialog>
         <!-- 请求提示弹窗 -->
         <el-dialog title="提示" :Visible.sync="dialogVisible">
             <span>{{ajaxMsg}}</span>
@@ -73,34 +72,38 @@
 
 <script>
     import buildInput from "@/components/common/search_input";
+    import configDialog from "@/components/dialogs/config/infoPoint"
     import {
-        getAllFamily, //获取所有设备族
+        // getAllFamily, //获取所有设备族
+        queryPhysicsAllType, //查询设备、部件、系统
+        queryFamilyAll, //查询所有设备族
         getDataDictionary, //点击时后去右侧的数据
         setDataDictionary, //修改右侧数据
-        getEqCode,
+        // getEqCode,
         getBussTypes
     } from "@/api/scan/request";
-    import {
-         mapGetters,
-         mapActions
-     } from "vuex";
+    import { mapGetters, mapActions } from "vuex";
     export default {
         name: "family",
         components: {
+            configDialog,
             "build-input": buildInput
         },
         data() {
             return {
                 value: "property",
                 options: [{
-                    label: "系统",
-                    value: "system"
-                }, {
                     label: "资产",
                     value: "property"
                 }, {
+                    label: "系统",
+                    value: "System"
+                }, {
                     label: "设备",
-                    value: "equip"
+                    value: "Equipment"
+                }, {
+                    label: "部件",
+                    value: "Component"
                 }, {
                     label: "空间",
                     value: "space"
@@ -115,6 +118,9 @@
                 active: "",
                 checked2: false,
                 allFamily: [],
+                dialog: {
+                    config: false
+                },
                 dialogVisible: false,
                 ajaxMsg: "",
                 code: '',
@@ -519,19 +525,26 @@
             chooseMedicine(val) {
                 this.getAllFamily()
             },
+            //批量配置信息点
+            handleClickConfig() {
+                this.dialog.config = true
+            },
             //获取所有设备族
             getAllFamily() {
+                this.labelKey = []
+                this.active = ""
+                this.searchVal = ""
                 if (this.value == "property") {
-                    getAllFamily().then(result => {
+                    queryFamilyAll(res => {
+                       this.allFamily = res.Content.map((item) => {
+                            return {
+                                code: item.Code,
+                                name: item.Name
+                            }
+                        })
                         this.isLoading = false
-                        if (result.data.Result == "success") {
-                            this.allFamily = result.data.Content;
-                            this.familySort();
-                        } else {
-                            this.dialogVisible = true;
-                            this.ajaxMsg = "请求出错";
-                        }
-                    });
+                        this.familySort() 
+                    })
                 } else if (this.value == "space") {
                     getBussTypes(res => {
                         this.isLoading = false
@@ -578,16 +591,15 @@
                         }
                     ]
                     this.familySort()
-                } else {
-                    getEqCode().then(res => {
-                        if (res.data.Result == "success") {
-                            this.allFamily = this.changeValue(res.data.Content, this.value)
-                            this.familySort();
-                        } else {
-                            this.$message.error("请求错误:" + res.data.ResultMsg)
-                        }
-                    }).catch(_ => {
-                        this.$message.error("请求错误")
+                }else {
+                    queryPhysicsAllType(this.value, res => {
+                        this.allFamily = res.Content.map((item) => {
+                            return {
+                                code: item.Code,
+                                name: item.Name
+                            }
+                        })
+                        this.familySort()
                     })
                 }
             },
@@ -599,35 +611,6 @@
                     }
                 })
             },
-            changeValue(list, val) {
-                let data = []
-                list.map(item => {
-                    if (!!item.content && item.content.length) {
-                        item.content.map(child => {
-                            //val为系统放入
-                            if (val == "system") {
-                                data.push({
-                                    name: child.system,
-                                    code: child.code
-                                })
-                            } else {
-                                //否则为设备
-                                if (!!child.content && !!child.content.length) {
-                                    child.content.map(facility => {
-                                        if (val == "equip") {
-                                            data.push({
-                                                name: facility.facility,
-                                                code: facility.code
-                                            })
-                                        }
-                                    })
-                                }
-                            }
-                        })
-                    }
-                })
-                return data
-            },
             //点击checkBox的事件
             boxChange(detail) {
                 let param = [{
@@ -671,28 +654,30 @@
             },
             //高亮行
             familyActive(name, code) {
-                this.rightLoading = true
                 this.active = name
                 this.code = code
-                let param = {
-                    data: {
-                        Orders: "sort asc",
-                        PageNumber: 1,
-                        PageSize: 500
-                    },
-                    type: code
-                };
-                this.tabsFalg = false
-                getDataDictionary(param, result => {
-                    this.rightLoading = false
-                    if (result.Result == "success") {
-                        this.tabsFalg = true
-                        this.labelKey = this.arrayCnt(result.Content)
-                    } else {
-                        this.dialogVisible = true;
-                        this.ajaxMsg = "请求出错";
-                    }
-                });
+                if(code) {
+                    let param = {
+                        data: {
+                            Orders: "sort asc,InfoPointCode asc",
+                            PageNumber: 1,
+                            PageSize: 500
+                        },
+                        type: code
+                    };
+                    this.rightLoading = true
+                    this.tabsFalg = false
+                    getDataDictionary(param, result => {
+                        this.rightLoading = false
+                        if (result.Result == "success") {
+                            this.tabsFalg = true
+                            this.labelKey = this.arrayCnt(result.Content)
+                        } else {
+                            this.dialogVisible = true;
+                            this.ajaxMsg = "请求出错";
+                        }
+                    });
+                }
             },
             //处理头部函数
             arrayCnt(arr) {
@@ -706,6 +691,7 @@
                         InfoPointName: item.InfoPointName,
                         InfoPointCode: item.InfoPointCode,
                         Visible: item.Visible,
+                        UnDisabled: item.UnDisabled,
                         SecondName: item.SecondName? item.SecondName: ""
                     })
                 })
@@ -725,6 +711,7 @@
                             InfoPointName: item.InfoPointName,
                             InfoPointCode: item.InfoPointCode,
                             Visible: item.Visible,
+                            UnDisabled: item.UnDisabled
                         })
                     })
                     sound.push(obj)
@@ -858,10 +845,22 @@
     #page-main .el-scrollbar .el-scrollbar__wrap .el-scrollbar__view {
         height: 100%;
     }
-    #page-main .el-tabs__content{
+    #page-main .right_main .el-tabs__content{
         height: 100%;
+        padding-top: 5px;
         overflow-y: auto;
-        // overflow: hidden;
+    }
+    nav .el-tabs__content{
+        display: none;
+    }
+    nav .el-tabs__header {
+        margin: 0;
+    }
+    nav .el-tabs--card>.el-tabs__header .el-tabs__item.is-active {
+        border-top: 2px solid #409EFF;
+    }
+    nav .el-tabs--card>.el-tabs__header .el-tabs__item {
+        border-top: 2px solid transparent;
     }
 </style>
 
@@ -872,6 +871,8 @@
         height: 100%;
         display: flex;
         flex-direction: column;
+        padding: 10px;
+        background: #fff;
         select {
             height: 28px;
             line-height: 40px;
@@ -891,8 +892,26 @@
             background: #FFF;
         }
 
-        main {
+        nav {
             flex: 1;
+            display: flex;
+            flex-direction: row;
+            overflow: hidden;
+            .tab-box{
+                flex: 1;
+            }
+            .button-box{
+                width: 200px;
+                text-align: right;
+                border-bottom: 1px solid #E4E7ED;
+            }
+        }
+
+        main {
+            // flex: 1;
+            border: 1px solid #E4E7ED;
+            border-top: none;
+            height: calc(100% - 42px);
             overflow: hidden;
             position: relative;
             transform: translate(0, 0);
@@ -971,9 +990,11 @@
             .right_main {
                 float: right;
                 overflow-y: auto;
-                width: calc(100% - 360px);
+                width: calc(100% - 370px);
+                padding-left: 10px;
                 height: 100%;
                 background-color: #fff;
+                border-left: 1px solid #f5f5f5;
                 .right_main_msg {
                     padding-left: 10px;
                     padding-top: 200px;