[Frontend][全域功能] 電梯 elevator3D Forge 遍歷遍到底程序建置 | ADHeatMaps 熱圖 roomDbid以外部傳入程序調整 | 3D 剖面框程序原以模糊比對樓層名稱改以正規化字串比對 | 取得資料庫電梯設備,根據baja訂閱移動3D電梯共用CLASS(Forge3DElevFull)程序建置 | Map to ArrObj 程序建置 | [儀錶板] 套用 Forge3DElevFull class | [能源管理] 須量用電只有電源才有程序調整 | [電梯管理] 套用 Forge3DElevFull class | [系統監控] 總攬、平面圖套用 Forge3DElevFull class
This commit is contained in:
		
							parent
							
								
									48b3fa8579
								
							
						
					
					
						commit
						c4a1360677
					
				@ -271,18 +271,18 @@
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    var tempSysSubText = [
 | 
			
		||||
        { text: "高壓配電盤" ,mainSys: "EE", subSys: "E1", },
 | 
			
		||||
        { text: "低壓配電盤" ,mainSys: "EE", subSys: "E2", },
 | 
			
		||||
        { text: "緊急發電機" ,mainSys: "EE", subSys: "E3", },
 | 
			
		||||
        { text: "電錶系統" ,mainSys: "EE", subSys: "E4", },
 | 
			
		||||
        { text: "二線式照明系統" ,mainSys: "LT", subSys: "L1", },
 | 
			
		||||
        { text: "小型送風機" ,mainSys: "ME", subSys: "M10", },
 | 
			
		||||
        { text: "環境感測設備" ,mainSys: "ME", subSys: "M12", },
 | 
			
		||||
        { text: "電梯設備" ,mainSys: "ELEV", subSys: "EL", },
 | 
			
		||||
        { text: "消防設備" ,mainSys: "FE", subSys: "F1", },
 | 
			
		||||
        { text: "排煙系統" ,mainSys: "FE", subSys: "F2", },
 | 
			
		||||
        { text: "電子水錶" ,mainSys: "WP", subSys: "W1", },
 | 
			
		||||
        { text: "門禁安全系統" ,mainSys: "S", subSys: "R", }
 | 
			
		||||
        { text: "高壓配電盤", mainSys: "EE", subSys: "E1", },
 | 
			
		||||
        { text: "低壓配電盤", mainSys: "EE", subSys: "E2", },
 | 
			
		||||
        { text: "緊急發電機", mainSys: "EE", subSys: "E3", },
 | 
			
		||||
        { text: "電錶系統", mainSys: "EE", subSys: "E4", },
 | 
			
		||||
        { text: "二線式照明系統", mainSys: "LT", subSys: "L1", },
 | 
			
		||||
        { text: "小型送風機", mainSys: "ME", subSys: "M10", },
 | 
			
		||||
        { text: "環境感測設備", mainSys: "ME", subSys: "M12", },
 | 
			
		||||
        { text: "電梯設備", mainSys: "ELEV", subSys: "EL", },
 | 
			
		||||
        { text: "消防設備", mainSys: "FE", subSys: "F1", },
 | 
			
		||||
        { text: "排煙系統", mainSys: "FE", subSys: "F2", },
 | 
			
		||||
        { text: "電子水錶", mainSys: "WP", subSys: "W1", },
 | 
			
		||||
        { text: "門禁安全系統", mainSys: "S", subSys: "R", }
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    $(document).ready(function () {
 | 
			
		||||
@ -783,12 +783,13 @@
 | 
			
		||||
    //}
 | 
			
		||||
 | 
			
		||||
    function show3DModel() {
 | 
			
		||||
        launchViewerNoTools(pageAct.urn, (viewer, nodeIds) => {
 | 
			
		||||
            nodeIds = Array.from(nodeIds);
 | 
			
		||||
        launchViewerNoTools(pageAct.urn, (viewer) => {
 | 
			
		||||
            let nodeIds = allEleDevList.filter(x => !isNaN(parseInt(x.forge_dbid))).map(x => { return { devNum: x.device_number, nodeId: parseInt(x.forge_dbid) } });
 | 
			
		||||
 | 
			
		||||
            $.each(nodeIds, (idx, item) => {
 | 
			
		||||
                elev3DBind[item[0]] = item[1];
 | 
			
		||||
                elev3DBind[item.devNum] = item.nodeId;
 | 
			
		||||
            })
 | 
			
		||||
            nodeIds = nodeIds.map(x => x[1]);
 | 
			
		||||
            nodeIds = nodeIds.map(x => x.nodeId);
 | 
			
		||||
            $.each(nodeIds, function (idx, node) {
 | 
			
		||||
                let options = {
 | 
			
		||||
                    element: $("#forgeViewer"),
 | 
			
		||||
@ -838,7 +839,6 @@
 | 
			
		||||
        myBaja = new subscriptionDevices();
 | 
			
		||||
        myBaja.setSubscribeDevicesByBql(subOrdPath);
 | 
			
		||||
        myBaja.setSubscribeDevicesCallBack(function (data) {
 | 
			
		||||
            try {
 | 
			
		||||
 | 
			
		||||
            if (allEleDevList.length == 0) {
 | 
			
		||||
                return false;
 | 
			
		||||
@ -873,9 +873,7 @@
 | 
			
		||||
            if (subData) {
 | 
			
		||||
                subData[data.point_name] = data.value;
 | 
			
		||||
            }
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                console.log("e", e)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
        myBaja.setSubscribeDeviceEndCallBack(function (data) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -48,7 +48,7 @@
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="row flex-column col-xl-6 m-0 p-0">
 | 
			
		||||
            <div id="elecAutoReq" class="row flex-column col-xl-6 m-0 p-0">
 | 
			
		||||
                <div class="col-auto mb-2">
 | 
			
		||||
                    <div class="card">
 | 
			
		||||
                        <div class="card-body">
 | 
			
		||||
@ -245,6 +245,23 @@
 | 
			
		||||
                        }
 | 
			
		||||
                    })
 | 
			
		||||
                })
 | 
			
		||||
                if (type == 3) {
 | 
			
		||||
                    strHtml += `<div class="col-sm-12 col-xl-4 mb-2">
 | 
			
		||||
                                            <div class="card elecCard cur-poi">
 | 
			
		||||
                                                <div class="card-body">
 | 
			
		||||
                                                    <h4 class="card-title color-white">太陽能設備用電</h4>
 | 
			
		||||
                                                    <p class="card-text color-white pl-5 pr-3 d-flex justify-content-between">
 | 
			
		||||
                                                        <span>${elecCardConText[type]?.text1}</span>
 | 
			
		||||
                                                        <span id="insPow">---</span>
 | 
			
		||||
                                                    </p>
 | 
			
		||||
                                                    <p class="card-text color-white pl-5 pr-3 d-flex justify-content-between">
 | 
			
		||||
                                                        <span>${elecCardConText[type]?.text2}</span>
 | 
			
		||||
                                                         <span id="insPow">---</span>
 | 
			
		||||
                                                    </p>
 | 
			
		||||
                                                </div>
 | 
			
		||||
                                            </div>
 | 
			
		||||
                                        </div>`;
 | 
			
		||||
                }
 | 
			
		||||
                $("#eneSubSysList").html(strHtml);
 | 
			
		||||
            }
 | 
			
		||||
        }, null, "POST").send();
 | 
			
		||||
@ -518,5 +535,11 @@
 | 
			
		||||
        if (type == "1" || type == "2") {
 | 
			
		||||
            $("#eneSubSysList").parent("div").hide();
 | 
			
		||||
        }
 | 
			
		||||
        // 自動需量
 | 
			
		||||
        if (type != "0") {
 | 
			
		||||
            $("#elecAutoReq").hide();
 | 
			
		||||
        } else {
 | 
			
		||||
            $("#elecAutoReq").show();
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
</script>
 | 
			
		||||
@ -1,63 +1,25 @@
 | 
			
		||||
<style>
 | 
			
		||||
    .elevator {
 | 
			
		||||
        background-color: #fff;
 | 
			
		||||
        min-height: 520px;
 | 
			
		||||
    }
 | 
			
		||||
    .elevator { background-color: #fff; min-height: 520px; }
 | 
			
		||||
 | 
			
		||||
    .elevator-table-wrapper {
 | 
			
		||||
        padding: 0.8rem;
 | 
			
		||||
    }
 | 
			
		||||
    .elevator-table-wrapper { padding: 0.8rem; }
 | 
			
		||||
 | 
			
		||||
    table.elevator-build {
 | 
			
		||||
        /*border: 1px double #000;*/
 | 
			
		||||
    }
 | 
			
		||||
    table.elevator-build { /*border: 1px double #000;*/ }
 | 
			
		||||
 | 
			
		||||
    table.elevator-build td {
 | 
			
		||||
        padding: 0.2rem 0.5rem;
 | 
			
		||||
        height: 50px;
 | 
			
		||||
        width: 45px;
 | 
			
		||||
        border: 1px solid #000;
 | 
			
		||||
    }
 | 
			
		||||
    table.elevator-build td { padding: 0.2rem 0.5rem; height: 50px; width: 45px; border: 1px solid #000; }
 | 
			
		||||
 | 
			
		||||
    elevator .elevator-body, elevator .elevator-header {
 | 
			
		||||
        padding: 0.7rem;
 | 
			
		||||
    }
 | 
			
		||||
    elevator .elevator-body, elevator .elevator-header { padding: 0.7rem; }
 | 
			
		||||
 | 
			
		||||
    .elevator-item {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        width: 43px;
 | 
			
		||||
        height: 47px;
 | 
			
		||||
        border: 4px solid orange;
 | 
			
		||||
    }
 | 
			
		||||
    .elevator-item { position: absolute; width: 43px; height: 47px; border: 4px solid orange; }
 | 
			
		||||
 | 
			
		||||
    .elevator-item-toup {
 | 
			
		||||
        border: 4px solid rgba(255,255,255,0);
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        border-bottom: 0;
 | 
			
		||||
        z-index: 2;
 | 
			
		||||
    }
 | 
			
		||||
    .elevator-item-toup { border: 4px solid rgba(255,255,255,0); position: absolute; border-bottom: 0; z-index: 2; }
 | 
			
		||||
 | 
			
		||||
    .elevator-item-todown {
 | 
			
		||||
        border: 4px solid rgba(255,255,255,0);
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        border-top: 0;
 | 
			
		||||
        z-index: 2;
 | 
			
		||||
    }
 | 
			
		||||
    .elevator-item-todown { border: 4px solid rgba(255,255,255,0); position: absolute; border-top: 0; z-index: 2; }
 | 
			
		||||
 | 
			
		||||
    .table-compact td{
 | 
			
		||||
        padding:0.2rem 0.3rem;
 | 
			
		||||
    }
 | 
			
		||||
    .table-compact td { padding: 0.2rem 0.3rem; }
 | 
			
		||||
 | 
			
		||||
    #emerTurn tr td:nth-child(2) {
 | 
			
		||||
        width: 50%;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #emerTurn tr td:nth-child(1) {
 | 
			
		||||
        width:35%;
 | 
			
		||||
    }
 | 
			
		||||
    #emerTurn tr td:nth-child(2) { width: 50%; text-align: center; justify-content: center; }
 | 
			
		||||
 | 
			
		||||
    #emerTurn tr td:nth-child(1) { width: 35%; }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<div class="d-flex">
 | 
			
		||||
@ -915,10 +877,6 @@
 | 
			
		||||
    var subSeviceData = [];    //每個設備訂閱點位值
 | 
			
		||||
    var floList = [];          //每個樓層
 | 
			
		||||
    var elevObj = null;        //左側 2D 電梯物件
 | 
			
		||||
    var viewer3DNodeIds = [];
 | 
			
		||||
    var elev3DBind = {};
 | 
			
		||||
    var elev3DOption = {};
 | 
			
		||||
    var elev3DObj = [];
 | 
			
		||||
    var subOrdPath = {
 | 
			
		||||
        "area_tag": pageAct.AreaTag,
 | 
			
		||||
        "building_tag": pageAct.buiTag,
 | 
			
		||||
@ -938,7 +896,7 @@
 | 
			
		||||
 | 
			
		||||
        setBuildFloor();
 | 
			
		||||
        setCards();
 | 
			
		||||
        subDeviceSetStatus();
 | 
			
		||||
        
 | 
			
		||||
        setEleManTable();
 | 
			
		||||
        show3D();
 | 
			
		||||
    })
 | 
			
		||||
@ -948,17 +906,16 @@
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //baja 訂閱設備
 | 
			
		||||
    function subDeviceSetStatus() {
 | 
			
		||||
        myBaja = new subscriptionDevices();
 | 
			
		||||
        myBaja.setSubscribeDevicesByBql(subOrdPath);
 | 
			
		||||
        myBaja.setSubscribeDevicesCallBack(function (data) {
 | 
			
		||||
            try {
 | 
			
		||||
    function subDeviceSetStatus(data) {
 | 
			
		||||
 | 
			
		||||
        if (allDevList.length == 0) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        data.device_number = data.device_number_full;
 | 
			
		||||
        let matchDevice = allDevList.filter(x => x.device_number == data.device_number)[0];
 | 
			
		||||
        if (!matchDevice) return;
 | 
			
		||||
 | 
			
		||||
        let master = matchDevice.device_number.split("_")[5];
 | 
			
		||||
 | 
			
		||||
        //將訂閱值塞入 subSeviceData
 | 
			
		||||
@ -1065,64 +1022,7 @@
 | 
			
		||||
        subDeviceSetEleManDet(matchDevice.device_number);
 | 
			
		||||
        // 電梯管理 不服務樓層 detail
 | 
			
		||||
        subDeviceSetEleManNotSerFloor(master);
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                console.log("e", e)
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        myBaja.setSubscribeDeviceEndCallBack(function (data) {
 | 
			
		||||
            let devNumArr = data.map(x => { return { devNum: x.device_number_full, priority: allDevList.filter(y => y.device_number == x.device_number_full)[0]?.priority } }).DistinctBy("devNum");
 | 
			
		||||
            devNumArr = devNumArr.oSort("priority");
 | 
			
		||||
            $.each(devNumArr, (idx, devObj) => {
 | 
			
		||||
                devNum = devObj.devNum;
 | 
			
		||||
                let subData = subSeviceData.filter(x => x.device_number == devNum)[0];
 | 
			
		||||
 | 
			
		||||
                if (subData) {
 | 
			
		||||
                    //// 左側 3D 電梯 nodeID 與 device_number match
 | 
			
		||||
                    //if (Object.keys(elev3DBind).indexOf(devNum) == -1 && viewer3DNodeIds.length != 0) {
 | 
			
		||||
                    //    elev3DBind[devNum] = viewer3DNodeIds[Object.keys(elev3DBind).length];
 | 
			
		||||
                    //}
 | 
			
		||||
                    // 左側 3D 電梯 Viewer Option 設置
 | 
			
		||||
                    /*elev3DOption.nodes = Object.keys(elev3DBind).map(x => elev3DBind[x]);*/
 | 
			
		||||
                    elev3DOption.nodeId = elev3DBind[devNum];
 | 
			
		||||
                    elev3DOption.floorHeight = floList.map((x) => { return { floor: x } });
 | 
			
		||||
                    elev3DOption.floorHeight.forEach((floObj, idx) => {
 | 
			
		||||
                        if (floObj.floor.startsWith("B")) {
 | 
			
		||||
                            let floor = parseInt(floObj.floor.split("B")[1].split("F")[0]);
 | 
			
		||||
                            floObj.height = floor * -13;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            let floor = parseInt(floObj.floor.split("F")[0]);
 | 
			
		||||
                            if (floor == 1) {
 | 
			
		||||
                                floObj.height = 0;
 | 
			
		||||
                            } else if (floor == 2) {
 | 
			
		||||
                                floObj.height = 14.75;
 | 
			
		||||
                            } else {
 | 
			
		||||
                                floObj.height = (14.75 + ((floor - 2) * 9.75));
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    })
 | 
			
		||||
                    
 | 
			
		||||
                    if (isFirstLoad3D == false && elev3DObj.length != 0) {
 | 
			
		||||
                        let elevObj = elev3DObj.filter(x => x.nodeId == elev3DBind[devNum])[0];
 | 
			
		||||
                        if (!elevObj.id) {
 | 
			
		||||
                            elevObj.id = devNum;
 | 
			
		||||
                        }
 | 
			
		||||
                        elevObj.obj = Object.assign(elevObj.obj, elev3DOption);
 | 
			
		||||
                        elevObj.obj.init(function () {
 | 
			
		||||
                            let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == elev3DBind[devNum]);
 | 
			
		||||
                            
 | 
			
		||||
                            frags.forEach((fragProxy) => {
 | 
			
		||||
                                fragProxy.frag.position.z = elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
 | 
			
		||||
                                fragProxy.frag.updateAnimTransform();
 | 
			
		||||
                            })
 | 
			
		||||
                            elevObj.obj.viewer.impl.sceneUpdated(true);
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            reloadEleManTable(setEleManTabDataFromBaja());
 | 
			
		||||
            $(loadEle).Loading("close");
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // baja 訂閱 變更 電梯管理 Table
 | 
			
		||||
@ -1200,15 +1100,6 @@
 | 
			
		||||
            elevObj.setElevFloor(matchDevice.device_number, subData["CP"]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (elev3DObj.length != 0) {
 | 
			
		||||
            let elevObj = elev3DObj.filter(x => x.nodeId == elev3DBind[devNum])[0];
 | 
			
		||||
            if (elevObj && elevObj.id) {
 | 
			
		||||
                elevObj.obj.setElevatorFloor(subData["CP"])
 | 
			
		||||
                elevObj.obj.movElevator();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        elevObj.setEleMovStatus(matchDevice.device_number, subData["RD"] == "UP" ? 1 : subData["RD"] == "DOWN" ? 2 : 0);
 | 
			
		||||
        //現在樓層
 | 
			
		||||
        if (subData["CP"]) {
 | 
			
		||||
            $(`#imdStaTable_${devNum} [name=curFloor]`).text(subData["CP"]);
 | 
			
		||||
@ -1249,7 +1140,6 @@
 | 
			
		||||
        let sendData = {
 | 
			
		||||
            sub_system_tag: pageAct.sysSubTag,
 | 
			
		||||
            building_tag: pageAct.buiTag,
 | 
			
		||||
            floor_tag: pageAct.floTag,
 | 
			
		||||
        };
 | 
			
		||||
        objSendData.Data = sendData;
 | 
			
		||||
        ytAjax = new YourTeam.Ajax(url, objSendData, function (res) {
 | 
			
		||||
@ -1847,7 +1737,7 @@
 | 
			
		||||
                        min: 1
 | 
			
		||||
                    },
 | 
			
		||||
                    layoutSize: '100%',
 | 
			
		||||
                    layoutCenter: ['40%','50%'],
 | 
			
		||||
                    layoutCenter: ['40%', '50%'],
 | 
			
		||||
                    zoom: 1.2,
 | 
			
		||||
                    silent: true
 | 
			
		||||
                },
 | 
			
		||||
@ -2482,56 +2372,22 @@
 | 
			
		||||
    //載入3D模型
 | 
			
		||||
    function load3DModel() {
 | 
			
		||||
 | 
			
		||||
        launchViewer(pageAct.urn, (viewer, nodeIds) => {
 | 
			
		||||
            nodeIds = Array.from(nodeIds);
 | 
			
		||||
            $.each(nodeIds, (idx, item) => {
 | 
			
		||||
                elev3DBind[item[0]] = item[1];
 | 
			
		||||
            })
 | 
			
		||||
            nodeIds = nodeIds.map(x => x[1]);
 | 
			
		||||
            $.each(nodeIds, function (idx, node) {
 | 
			
		||||
                let options = {
 | 
			
		||||
                    element: $("#forgeViewer"),
 | 
			
		||||
        launchViewer(pageAct.urn, (viewer) => {
 | 
			
		||||
            let elevOption = {
 | 
			
		||||
                selector: "#forgeViewer",
 | 
			
		||||
                viewer: viewer,
 | 
			
		||||
                    nodeId: node,
 | 
			
		||||
                    floorHeight: elev3DOption.floorHeight ?? [],
 | 
			
		||||
                    inited: function () {
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                let elevator3DObj = new elevator3D(options);
 | 
			
		||||
                let devNum = Object.keys(elev3DBind).filter(x => elev3DBind[x] == node)[0];
 | 
			
		||||
                let subData = subSeviceData.filter(x => x.device_number == devNum)[0];
 | 
			
		||||
 | 
			
		||||
                if (elev3DObj.filter(x => x.nodeId == node).length == 0) {
 | 
			
		||||
                    elev3DObj.push({ id: devNum, nodeId: node, obj: elevator3DObj });
 | 
			
		||||
                ordPath: subOrdPath
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
                if (subData) {
 | 
			
		||||
                    let elevObj = elev3DObj.filter(x => x.nodeId == node)[0];
 | 
			
		||||
                    if (!elevObj.id) {
 | 
			
		||||
                        elevObj.id = devNum;
 | 
			
		||||
            // 電梯移動訂閱程序載入
 | 
			
		||||
            let forge3DElev = new Forge3DElevFull(elevOption);
 | 
			
		||||
            forge3DElev.bajaEndCallback = function () {
 | 
			
		||||
                endPageLoading();
 | 
			
		||||
            }
 | 
			
		||||
                    elevObj.obj = Object.assign(elevObj, elevator3DObj ?? {})
 | 
			
		||||
                    elevObj.obj.init(function () {
 | 
			
		||||
                        let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == node);
 | 
			
		||||
                        
 | 
			
		||||
                        frags.forEach((fragProxy) => {
 | 
			
		||||
                            fragProxy.frag.position.z = elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
 | 
			
		||||
                            fragProxy.frag.updateAnimTransform()
 | 
			
		||||
                        })
 | 
			
		||||
                        elevObj.obj.viewer.impl.sceneUpdated(true);
 | 
			
		||||
                    })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            forge3DElev.bajaChaCallback = function (data) {
 | 
			
		||||
                subDeviceSetStatus(data);
 | 
			
		||||
            }
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            //let elevator = elev3DObj[0];
 | 
			
		||||
            //elevator.obj.setElevatorFloor(3)
 | 
			
		||||
            //elevator.obj.movElevator()
 | 
			
		||||
            //setElevatorSpeed(0.2)
 | 
			
		||||
            //setElevatorFloor(2)
 | 
			
		||||
            //requestAnimationFrame(movElevator);
 | 
			
		||||
            forge3DElev.init();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,7 @@
 | 
			
		||||
                getFloDevList();
 | 
			
		||||
                setLightColor();
 | 
			
		||||
            }
 | 
			
		||||
            if (arr.indexOf(5) != -1) {
 | 
			
		||||
            if (arr.indexOf(3) != -1) {
 | 
			
		||||
                getHotspotPoint(() => {
 | 
			
		||||
                    show3DModel(data.urn_3D);
 | 
			
		||||
                });
 | 
			
		||||
@ -82,7 +82,7 @@
 | 
			
		||||
 | 
			
		||||
                            </div>`;
 | 
			
		||||
                break;
 | 
			
		||||
            case 5:
 | 
			
		||||
            case 3:
 | 
			
		||||
                strHtml = `<div name="forgeViewer" style="height:85vh;"></div>`;
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
@ -105,6 +105,7 @@
 | 
			
		||||
            if (!matchDevice) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let norDevPoiName = matchDevice.device_normal_point_name;
 | 
			
		||||
            let cloDevPoiName = matchDevice.device_close_point_name;
 | 
			
		||||
            let errDevPoiName = matchDevice.device_error_point_name;
 | 
			
		||||
@ -132,7 +133,7 @@
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    //根據 data-type 設置顏色 (判斷後台是否有設定,若無則帶預設)
 | 
			
		||||
    
 | 
			
		||||
    function setLightColor() {
 | 
			
		||||
        $("[data-light-type]").each((index, ele) => {
 | 
			
		||||
            let type = $(ele).data("light-type");
 | 
			
		||||
@ -214,7 +215,6 @@
 | 
			
		||||
        }, null, "POST").send();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // 取得根據棟別顯示左右區塊資訊
 | 
			
		||||
    function getBuildMenu(callback = null) {
 | 
			
		||||
        let url = baseApiUrl + "/api/Device/GetBuildMenu";
 | 
			
		||||
        let sendData = {
 | 
			
		||||
@ -278,14 +278,30 @@
 | 
			
		||||
 | 
			
		||||
            heatMap = new ADHeatMaps(option);
 | 
			
		||||
            heatMap.onComplete = () => {
 | 
			
		||||
                $.each(allDevList, (idx,dev) => {
 | 
			
		||||
                $.each(allDevList, (idx, dev) => {
 | 
			
		||||
                    heatMap.changeTemp(dev.device_number, dev._temp || 0);
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        },"[name=forgeViewer]");
 | 
			
		||||
            let elevOption = {
 | 
			
		||||
                selector:"[name=forgeViewer]",
 | 
			
		||||
                viewer: viewer,
 | 
			
		||||
                ordPath: {
 | 
			
		||||
                    "area_tag": pageAct.AreaTag,
 | 
			
		||||
                    "building_tag": pageAct.buiTag,
 | 
			
		||||
                },
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 電梯移動訂閱程序載入
 | 
			
		||||
            let forge3DElev = new Forge3DElevFull(elevOption);
 | 
			
		||||
            forge3DElev.bajaEndCallback = function () {
 | 
			
		||||
                endPageLoading();
 | 
			
		||||
            }
 | 
			
		||||
            forge3DElev.init();
 | 
			
		||||
        }, "[name=forgeViewer]");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    function getHotspotPoint(callback = null) {
 | 
			
		||||
        let url = baseApiUrl + "/api/GetDevForCor";
 | 
			
		||||
        let sendData = {
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,6 @@
 | 
			
		||||
    var allDeviceRowData = []; //所有設備原始資料
 | 
			
		||||
    var global_emergency_alarm_device_number = [];
 | 
			
		||||
    var zoomToggle = 3;
 | 
			
		||||
 | 
			
		||||
    $(function () {
 | 
			
		||||
        getHotspotPoint(() => {
 | 
			
		||||
            show3DModel(pageAct.urn);
 | 
			
		||||
@ -469,6 +468,110 @@
 | 
			
		||||
            });
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
   
 | 
			
		||||
    // 電梯 3D 位置呈現
 | 
			
		||||
    function set3DElevPos(viewer) {
 | 
			
		||||
 | 
			
		||||
        let nodeIds = allElevDevList.filter(x => !isNaN(parseInt(x.forge_dbid))).map(x => { return { devNum: x.device_number, nodeId: parseInt(x.forge_dbid) } });
 | 
			
		||||
 | 
			
		||||
        $.each(nodeIds, (idx, item) => {
 | 
			
		||||
            elev3DBind[item.devNum] = item.nodeId;
 | 
			
		||||
        })
 | 
			
		||||
        nodeIds = nodeIds.map(x => x.nodeId);
 | 
			
		||||
        $.each(nodeIds, function (idx, node) {
 | 
			
		||||
            let options = {
 | 
			
		||||
                element: $("[name=forgeViewer]"),
 | 
			
		||||
                viewer: viewer,
 | 
			
		||||
                nodeId: node,
 | 
			
		||||
                floorHeight: elev3DOption.floorHeight ?? [],
 | 
			
		||||
                inited: function () {
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            let elevator3DObj = new elevator3D(options);
 | 
			
		||||
            let devNum = Object.keys(elev3DBind).filter(x => elev3DBind[x] == node)[0];
 | 
			
		||||
            let subData = subSeviceData.filter(x => x.device_number == devNum)[0];
 | 
			
		||||
 | 
			
		||||
            if (elev3DObj.filter(x => x.nodeId == node).length == 0) {
 | 
			
		||||
                elev3DObj.push({ id: devNum, nodeId: node, obj: elevator3DObj });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (subData) {
 | 
			
		||||
                let elevObj = elev3DObj.filter(x => x.nodeId == node)[0];
 | 
			
		||||
                if (!elevObj.id) {
 | 
			
		||||
                    elevObj.id = devNum;
 | 
			
		||||
                }
 | 
			
		||||
                elevObj.obj = Object.assign(elevObj, elevator3DObj ?? {})
 | 
			
		||||
                elevObj.obj.init(function () {
 | 
			
		||||
                    let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == node);
 | 
			
		||||
 | 
			
		||||
                    frags.forEach((fragProxy) => {
 | 
			
		||||
                        fragProxy.frag.position.z = elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
 | 
			
		||||
                        fragProxy.frag.updateAnimTransform()
 | 
			
		||||
                    })
 | 
			
		||||
                    elevObj.obj.viewer.impl.sceneUpdated(true);
 | 
			
		||||
                })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 電梯 3D Option 設置
 | 
			
		||||
    function set3DElevOpt(data) {
 | 
			
		||||
        let devNumArr = data.map(x => { return { devNum: x.device_number_full, priority: allElevDevList.filter(y => y.device_number == x.device_number_full)[0]?.priority } }).DistinctBy("devNum");
 | 
			
		||||
        devNumArr = devNumArr.oSort("priority");
 | 
			
		||||
        $.each(devNumArr, (idx, devObj) => {
 | 
			
		||||
            devNum = devObj.devNum;
 | 
			
		||||
            let subData = subSeviceData.filter(x => x.device_number == devNum)[0];
 | 
			
		||||
 | 
			
		||||
            if (subData) {
 | 
			
		||||
                //// 左側 3D 電梯 nodeID 與 device_number match
 | 
			
		||||
                //if (Object.keys(elev3DBind).indexOf(devNum) == -1 && viewer3DNodeIds.length != 0) {
 | 
			
		||||
                //    elev3DBind[devNum] = viewer3DNodeIds[Object.keys(elev3DBind).length];
 | 
			
		||||
                //}
 | 
			
		||||
                // 左側 3D 電梯 Viewer Option 設置
 | 
			
		||||
                /*elev3DOption.nodes = Object.keys(elev3DBind).map(x => elev3DBind[x]);*/
 | 
			
		||||
                elev3DOption.nodeId = elev3DBind[devNum];
 | 
			
		||||
                elev3DOption.floorHeight = floList.map((x) => { return { floor: x } });
 | 
			
		||||
                elev3DOption.floorHeight.forEach((floObj, idx) => {
 | 
			
		||||
                    if (floObj.floor.startsWith("B")) {
 | 
			
		||||
                        let floor = parseInt(floObj.floor.split("B")[1].split("F")[0]);
 | 
			
		||||
                        floObj.height = floor * -13;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        let floor = parseInt(floObj.floor.split("F")[0]);
 | 
			
		||||
                        if (floor == 1) {
 | 
			
		||||
                            floObj.height = 0;
 | 
			
		||||
                        } else if (floor == 2) {
 | 
			
		||||
                            floObj.height = 14.75;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            floObj.height = (14.75 + ((floor - 2) * 9.75));
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
 | 
			
		||||
                if (elev3DObj.length != 0) {
 | 
			
		||||
                    let elevObj = elev3DObj.filter(x => x.nodeId == elev3DBind[devNum])[0];
 | 
			
		||||
                    if (!elevObj.id) {
 | 
			
		||||
                        elevObj.id = devNum;
 | 
			
		||||
                    }
 | 
			
		||||
                    elevObj.obj = Object.assign(elevObj.obj, elev3DOption);
 | 
			
		||||
                    elevObj.obj.init(function () {
 | 
			
		||||
                        let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == elev3DBind[devNum]);
 | 
			
		||||
 | 
			
		||||
                        frags.forEach((fragProxy) => {
 | 
			
		||||
                            fragProxy.frag.position.z = elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
 | 
			
		||||
                            fragProxy.frag.updateAnimTransform();
 | 
			
		||||
                        })
 | 
			
		||||
                        elevObj.obj.viewer.impl.sceneUpdated(true);
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // //訂閱設備的回傳值,並塞到全域變數
 | 
			
		||||
    // function subscribeCallBack(change_device, is_need_reset = false) {
 | 
			
		||||
    //     if (change_device != undefined && change_device != null) {
 | 
			
		||||
@ -934,7 +1037,7 @@
 | 
			
		||||
        launchViewerForHotspot(urn, (viewer, nodeIds) => {
 | 
			
		||||
            let nextFloor = getNextFloor(pageAct.floGuid);
 | 
			
		||||
            let curFloTag = pageAct.floTag;
 | 
			
		||||
            
 | 
			
		||||
            debugger
 | 
			
		||||
            if (!nextFloor) {
 | 
			
		||||
                toast_warning("超出樓層範圍");
 | 
			
		||||
                return;
 | 
			
		||||
@ -949,6 +1052,20 @@
 | 
			
		||||
 | 
			
		||||
            getLevelsData(curFloTag, nextFloor);
 | 
			
		||||
            setHeatMap();
 | 
			
		||||
 | 
			
		||||
            let elevOption = {
 | 
			
		||||
                viewer: viewer,
 | 
			
		||||
                ordPath: {
 | 
			
		||||
                    "area_tag": pageAct.AreaTag,
 | 
			
		||||
                    "building_tag": pageAct.buiTag,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // 電梯移動訂閱程序載入
 | 
			
		||||
            let forge3DElev = new Forge3DElevFull(elevOption);
 | 
			
		||||
            forge3DElev.bajaEndCallback = function () {
 | 
			
		||||
                endPageLoading();
 | 
			
		||||
            }
 | 
			
		||||
            forge3DElev.init();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -134,6 +134,7 @@ class elevator3D {
 | 
			
		||||
        this.viewer = option.viewer;
 | 
			
		||||
        this.nodeId = option.nodeId;
 | 
			
		||||
        this.speed = option.speed ?? 0.03;
 | 
			
		||||
        this.tagValue = option.tagValue ?? "";
 | 
			
		||||
        this.fragProxys = [];
 | 
			
		||||
        this.fragProxy = null;
 | 
			
		||||
        this.initCallback = option.inited ?? null;
 | 
			
		||||
@ -143,7 +144,26 @@ class elevator3D {
 | 
			
		||||
        this.init();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setTreeFrag = function (callback) {
 | 
			
		||||
    // 定義遍歷模型中所有片段的異步函數
 | 
			
		||||
    enumFragments = function (nodeId) {
 | 
			
		||||
        return new Promise((resolve, reject) => {
 | 
			
		||||
            // 定義結果陣列
 | 
			
		||||
            let result = [];
 | 
			
		||||
            // 使用 InstanceTree.enumNodeFragments 遍歷模型中的所有片段
 | 
			
		||||
            this.viewer?.model?.getData().instanceTree.enumNodeFragments(nodeId,(fragId) => {
 | 
			
		||||
                // 將遍歷到的片段 ID 添加到結果陣列中
 | 
			
		||||
                result.push(fragId);
 | 
			
		||||
            }, (nodeId) => {
 | 
			
		||||
                // 如果遍歷到的節點是葉節點,则返回 true,表示繼續遍歷該節點的片段
 | 
			
		||||
                return model.getData().instanceTree.isLeaf(nodeId);
 | 
			
		||||
            });
 | 
			
		||||
            // 将结果陣列作為参数调用 resolve 函数
 | 
			
		||||
            resolve(result);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 設置樹狀結構中片段
 | 
			
		||||
    setTreeFrag = async function (callback) {
 | 
			
		||||
        let tree = this.viewer?.model?.getData().instanceTree;
 | 
			
		||||
        if (!tree) {
 | 
			
		||||
            return;
 | 
			
		||||
@ -152,36 +172,42 @@ class elevator3D {
 | 
			
		||||
        let nodeId = this.nodeId;
 | 
			
		||||
 | 
			
		||||
        if (nodeId) {
 | 
			
		||||
            let childCnt = tree.getChildCount(nodeId);
 | 
			
		||||
            let curIdx = 1;
 | 
			
		||||
 | 
			
		||||
            // 刪除 fragmentProxys 中與當前 nodeId 相同的項目
 | 
			
		||||
            this.fragProxys.filter(x => x.nodeId == nodeId).forEach((x) => {
 | 
			
		||||
                let idx = this.fragProxys.indexOf(x);
 | 
			
		||||
                this.fragProxys.splice(idx, 1);
 | 
			
		||||
            })
 | 
			
		||||
            tree.enumNodeFragments(nodeId, (frag) => {
 | 
			
		||||
 | 
			
		||||
            // 遍歷當前 nodeId 中的所有片段
 | 
			
		||||
            let fragments = await this.enumFragments(nodeId);
 | 
			
		||||
 | 
			
		||||
            fragments.forEach((frag) => {
 | 
			
		||||
                // 取得當前片段的 FragmentProxy 物件
 | 
			
		||||
                let fragProxy = this.viewer.impl.getFragmentProxy(this.viewer.model, frag);
 | 
			
		||||
 | 
			
		||||
                // 將當前片段的信息添加到 fragProxys 陣列中
 | 
			
		||||
                this.fragProxys.push({ nodeId: nodeId, fragId: frag, frag: fragProxy });
 | 
			
		||||
 | 
			
		||||
                // 取得當前片段的動畫變換矩陣
 | 
			
		||||
                fragProxy.getAnimTransform();
 | 
			
		||||
                // 定義當前片段的位置向量
 | 
			
		||||
                let fragPosition = new THREE.Vector3(0, 0, 0);// 一樓0 二樓15 三樓 26
 | 
			
		||||
 | 
			
		||||
                // 設置當前片段的位置
 | 
			
		||||
                fragProxy.position = fragPosition;
 | 
			
		||||
 | 
			
		||||
                // 更新當前片段的動畫變換矩陣
 | 
			
		||||
                fragProxy.updateAnimTransform();
 | 
			
		||||
                if (childCnt == curIdx) {
 | 
			
		||||
                    this.initCallback ? this.initCallback() : "";
 | 
			
		||||
                    callback ? callback() : "";
 | 
			
		||||
                }
 | 
			
		||||
                curIdx++;
 | 
			
		||||
            }, true);
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        // 通知檢視器更新場景
 | 
			
		||||
        this.viewer.impl.sceneUpdated(true);
 | 
			
		||||
 | 
			
		||||
        if (typeof $(this.ele)[0]._elevator3D == "undefined") {
 | 
			
		||||
            $(this.ele)[0]._elevator3D = [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $(this.ele)[0]._elevator3D.push({ nodeId: nodeId, obj: this });
 | 
			
		||||
 | 
			
		||||
        this.initCallback ? this.initCallback() : "";
 | 
			
		||||
        callback ? callback() : "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    init = function (callback = null) {
 | 
			
		||||
@ -196,15 +222,17 @@ class elevator3D {
 | 
			
		||||
        this.speed = speed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    movElevator = function () {
 | 
			
		||||
 | 
			
		||||
        let tree = this.viewer.model.getData().instanceTree;
 | 
			
		||||
    // 電梯移動
 | 
			
		||||
    movElevator = async function () {
 | 
			
		||||
        let nodeId = this.nodeId;
 | 
			
		||||
        let fragProxyZ = 0;
 | 
			
		||||
        let fragProxyZ = 0;   // 定義 fragProxyZ 變量,用於存儲當前片段的 z 坐標
 | 
			
		||||
 | 
			
		||||
        // 取得當前 nodeId 的片段代理對象
 | 
			
		||||
        let fragProxy = this.fragProxys.filter(x => x.nodeId == nodeId)[0]?.frag;
 | 
			
		||||
        if (!fragProxy) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        changeColor(nodeId);
 | 
			
		||||
 | 
			
		||||
        if ((this.movStatus == 2 && fragProxy.position.z.roundDecimal(2) < this.targetFloorZ.roundDecimal(2)) ||
 | 
			
		||||
@ -213,11 +241,6 @@ class elevator3D {
 | 
			
		||||
            stoped(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //if (movStatus == 0) {
 | 
			
		||||
        //    recoverTransparentBuilding();
 | 
			
		||||
        //    return;
 | 
			
		||||
        //}
 | 
			
		||||
 | 
			
		||||
        if (fragProxy.position.z.roundDecimal(2) > this.targetFloorZ.roundDecimal(2)) {
 | 
			
		||||
            this.movStatus = 2;
 | 
			
		||||
        }
 | 
			
		||||
@ -225,25 +248,29 @@ class elevator3D {
 | 
			
		||||
            this.movStatus = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        tree.enumNodeFragments(nodeId, (frag) => {
 | 
			
		||||
        // 遍歷當前 nodeId 中的所有片段
 | 
			
		||||
        let fragments = await this.enumFragments(nodeId);
 | 
			
		||||
 | 
			
		||||
        fragments.forEach((frag) => {
 | 
			
		||||
            let fragProxy = this.viewer.impl.getFragmentProxy(this.viewer.model, frag);
 | 
			
		||||
            fragProxy.getAnimTransform();
 | 
			
		||||
            //let fragPosition = new THREE.Vector3(0, 0, 15);// 一樓0 二樓15 三樓 26
 | 
			
		||||
 | 
			
		||||
            if (this.movStatus == 2) {
 | 
			
		||||
                fragProxy.position.z -= this.speed;
 | 
			
		||||
            }
 | 
			
		||||
            else if (this.movStatus == 1) {
 | 
			
		||||
                fragProxy.position.z += this.speed;
 | 
			
		||||
            }
 | 
			
		||||
            this.fragProxys.filter(x => x.nodeId == nodeId && x.fragId == frag)[0].frag.position.z = fragProxy.position.z;
 | 
			
		||||
            let tarFrag = this.fragProxys.filter(x => x.nodeId == nodeId && x.fragId == frag)[0];
 | 
			
		||||
            if (tarFrag) { 
 | 
			
		||||
                tarFrag.frag.position.z = fragProxy.position.z;
 | 
			
		||||
            }
 | 
			
		||||
            fragProxyZ = fragProxy.position.z;
 | 
			
		||||
            fragProxy.updateAnimTransform()
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        }, true);
 | 
			
		||||
        this.viewer.impl.sceneUpdated(true);
 | 
			
		||||
 | 
			
		||||
        /*setTransparentBuilding();*/
 | 
			
		||||
 | 
			
		||||
        let movElevator = $(this.ele)[0]._elevator3D.filter(x => x.nodeId == this.nodeId)[0]?.obj.movElevator.bind(this);
 | 
			
		||||
 | 
			
		||||
        if (this.movStatus == 2) {
 | 
			
		||||
@ -269,17 +296,9 @@ class elevator3D {
 | 
			
		||||
 | 
			
		||||
        function stoped(obj) {
 | 
			
		||||
            obj.movStatus = 0;
 | 
			
		||||
            /*recoverTransparentBuilding();*/
 | 
			
		||||
            hideColor(nodeId);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        //let fragPosition = new THREE.Vector3(position);// 一樓0 二樓15 三樓 26
 | 
			
		||||
 | 
			
		||||
        //fragProxy.position = fragPosition;
 | 
			
		||||
 | 
			
		||||
        //fragProxy.updateAnimTransform();
 | 
			
		||||
 | 
			
		||||
        //viewer.impl.sceneUpdated(true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -338,14 +357,14 @@ async function getNodeIdBySearch(text) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 主函數 - 透過 model 全部 node 取得特定 nodeId 
 | 
			
		||||
async function getNodeIdByDbIds(checkName = "【電梯】", callback = null) {
 | 
			
		||||
async function getNodeIdByDbIds(checkValue = [], callback = null) {
 | 
			
		||||
    let evelMap = new Map();
 | 
			
		||||
    let hasElement = false; // 設置是否有 【tag_id】的node
 | 
			
		||||
    let targetNodeIds = await getNodeIdBySearch(checkName);
 | 
			
		||||
    let targetNodeIds = await getNodeIdBySearch(checkValue);
 | 
			
		||||
    let elements = await viewerGetProperties(targetNodeIds,"【tag_id】");
 | 
			
		||||
 | 
			
		||||
    // 從 elements 中篩選出包含 【tag_id】 屬性的元素
 | 
			
		||||
    elements = elements.filter(x => x.properties.findIndex(y => y.displayName == "【tag_id】" && y.displayValue.indexOf(checkName) != -1) != -1);
 | 
			
		||||
    elements = elements.filter(x => x.properties.findIndex(y => y.displayName == "【tag_id】" && checkValue.indexOf(y.displayValue) != -1) != -1);
 | 
			
		||||
 | 
			
		||||
    if (elements) {
 | 
			
		||||
        hasElement = true;
 | 
			
		||||
@ -514,15 +533,15 @@ class ADHeatMaps {
 | 
			
		||||
            SurfaceShadingNode,
 | 
			
		||||
        } = Autodesk.DataVisualization.Core;
 | 
			
		||||
 | 
			
		||||
        let nodeIds = await getNodeIdByDbIds(this.checkNodeString);
 | 
			
		||||
        nodeIds = Array.from(nodeIds);
 | 
			
		||||
        nodeIds = nodeIds.map(x => { return { room: x[0] , nodeId: x[1]} });
 | 
			
		||||
        this.roomDbIds = nodeIds;
 | 
			
		||||
        //let nodeIds = await getNodeIdByDbIds(this.checkNodeString);
 | 
			
		||||
        //nodeIds = Array.from(nodeIds);
 | 
			
		||||
        //nodeIds = nodeIds.map(x => { return { room: x[0] , nodeId: x[1]} });
 | 
			
		||||
        this.roomDbIds = this.devices.filter(x => x.roomDbId != -1).map(x => x.roomDbId).Distinct();
 | 
			
		||||
 | 
			
		||||
        // 建立一個 SurfaceShadingData 物件,並將 SurfaceShadingNode 加入到該物件中
 | 
			
		||||
        const heatmapData = new SurfaceShadingData();
 | 
			
		||||
 | 
			
		||||
        $.each(this.roomDbIds.map(x => x.nodeId), (idx, rDbid) => {
 | 
			
		||||
        $.each(this.roomDbIds, (idx, rDbid) => {
 | 
			
		||||
            // 建立一個名為 "Room Panel" 的 SurfaceShadingNode 物件,並將房間的模型給傳入,只在該房間呈現溫度
 | 
			
		||||
            const shadingNode = new SurfaceShadingNode("RoomPanel" + rDbid, rDbid);
 | 
			
		||||
 | 
			
		||||
@ -551,7 +570,7 @@ class ADHeatMaps {
 | 
			
		||||
 | 
			
		||||
        this.dataVizExtn = dataVizExtn;
 | 
			
		||||
 | 
			
		||||
        $.each(this.roomDbIds.map(x => x.nodeId), (idx, rDbid) => {
 | 
			
		||||
        $.each(this.roomDbIds, (idx, rDbid) => {
 | 
			
		||||
            this.dataVizExtn.renderSurfaceShading("RoomPanel" + rDbid, "temperature", this.getSensorValue.bind(this));
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
@ -977,13 +996,15 @@ async function getRemoteLevels() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function getLevelsData(lowerFloor, upperFloor) {
 | 
			
		||||
 | 
			
		||||
    // 樓層正規化 取得樓層 
 | 
			
		||||
    const floorRegex = /[\d|\w]+F/gmi;
 | 
			
		||||
    const data = await this.getRemoteLevels();
 | 
			
		||||
    for (var i = 0; i < data.length; i++) {
 | 
			
		||||
        if ((data[i].name).indexOf(lowerFloor) != -1) {
 | 
			
		||||
        let name = data[i].name?.match(floorRegex);
 | 
			
		||||
        if (name && name[0] == lowerFloor) {
 | 
			
		||||
            lowerIdx = i;
 | 
			
		||||
        }
 | 
			
		||||
        if ((data[i].name).indexOf(upperFloor) != -1) {
 | 
			
		||||
        if (name && name[0] == upperFloor) {
 | 
			
		||||
            upperIdx = i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@ $.fn.outerHtml = function () {
 | 
			
		||||
 * @param {any} type - close / start / exceed , exceed => 繼續執行並可切換文字
 | 
			
		||||
 * @param {any} text - 右下角 Alert 文字
 | 
			
		||||
 */
 | 
			
		||||
$.fn.Loading = function (type = "close",text) {
 | 
			
		||||
$.fn.Loading = function (type = "close", text) {
 | 
			
		||||
    let ele = this;
 | 
			
		||||
    let aleObj = $(this)[0]._aleObj;
 | 
			
		||||
 | 
			
		||||
@ -114,7 +114,7 @@ function defDev(obj) {
 | 
			
		||||
 * @param {any} table
 | 
			
		||||
 * @param {any} sendData
 | 
			
		||||
 */
 | 
			
		||||
function dtAjaxResetSendData(table,sendData) {
 | 
			
		||||
function dtAjaxResetSendData(table, sendData) {
 | 
			
		||||
    table.context[0].ajax.data = function (d) {
 | 
			
		||||
        d = sendData;
 | 
			
		||||
        return JSON.stringify(d)
 | 
			
		||||
@ -205,7 +205,7 @@ class ElevatorHandler {
 | 
			
		||||
        // 若已有每個設備的所在樓層,則預設到該樓層位置
 | 
			
		||||
        if (Object.keys(this.curElevFloor).length != 0) {
 | 
			
		||||
            $.each(Object.keys(this.curElevFloor), (idx, elevKey) => {
 | 
			
		||||
                this.setElevFloor(elevKey,this.curElevFloor[elevKey]);
 | 
			
		||||
                this.setElevFloor(elevKey, this.curElevFloor[elevKey]);
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -234,16 +234,16 @@ class ElevatorHandler {
 | 
			
		||||
 | 
			
		||||
        for (let e = 1; e <= _elevators.length + 2; e++) {
 | 
			
		||||
            let th = creEle("th");
 | 
			
		||||
            th.css({ "width": `${_w}px`, "height": `${_h}px` ,"position":"relative"});
 | 
			
		||||
            th.css({ "width": `${_w}px`, "height": `${_h}px`, "position": "relative" });
 | 
			
		||||
            if (e != 1 && e != _elevators.length + 2) {
 | 
			
		||||
                let elevId = _elevators[e - 2]?.id;
 | 
			
		||||
                // 電梯方框
 | 
			
		||||
                let span = creEle("span", null, "elevator-item-" + (elevId), null, ["elevator-item"]);
 | 
			
		||||
                let spanUp = creEle("span", null, null, null, ["elevator-item-toup"]);
 | 
			
		||||
                let spanDown = creEle("span", null, null, null, ["elevator-item-todown"]);
 | 
			
		||||
                span.css({ "width": `${_w - 3}px`, "height": `${_h - 3}px`, "top": `1.5px`,"left":"1.5px", "transition":`transform ${1 / this.speed}s cubic-bezier(0.43, 0.05, 0.62, 1) 0s`})
 | 
			
		||||
                spanUp.css({ "width": `${_w - 3}px`, "height": `${(_h - 3) / 2}px`, "top": `1.5px`, "left": "1.5px", "transition":`transform ${1 / this.speed}s cubic-bezier(0.43, 0.05, 0.62, 1) 0s`})
 | 
			
		||||
                spanDown.css({ "width": `${_w - 3}px`, "height": `${(_h - 3) / 2}px`, "top": `1.5px`, "left": "1.5px", "transition":`transform ${1 / this.speed}s cubic-bezier(0.43, 0.05, 0.62, 1) 0s`,"top":`${1.5 + (_h-3) / 2}px`})
 | 
			
		||||
                span.css({ "width": `${_w - 3}px`, "height": `${_h - 3}px`, "top": `1.5px`, "left": "1.5px", "transition": `transform ${1 / this.speed}s cubic-bezier(0.43, 0.05, 0.62, 1) 0s` })
 | 
			
		||||
                spanUp.css({ "width": `${_w - 3}px`, "height": `${(_h - 3) / 2}px`, "top": `1.5px`, "left": "1.5px", "transition": `transform ${1 / this.speed}s cubic-bezier(0.43, 0.05, 0.62, 1) 0s` })
 | 
			
		||||
                spanDown.css({ "width": `${_w - 3}px`, "height": `${(_h - 3) / 2}px`, "top": `1.5px`, "left": "1.5px", "transition": `transform ${1 / this.speed}s cubic-bezier(0.43, 0.05, 0.62, 1) 0s`, "top": `${1.5 + (_h - 3) / 2}px` })
 | 
			
		||||
                th.append(spanUp);
 | 
			
		||||
                th.append(span);
 | 
			
		||||
                th.append(spanDown);
 | 
			
		||||
@ -319,7 +319,7 @@ class ElevatorHandler {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 設定現在電梯狀態 (往上/往下/停止)
 | 
			
		||||
    setEleMovStatus = function (elevId,status) {
 | 
			
		||||
    setEleMovStatus = function (elevId, status) {
 | 
			
		||||
        this.movStatus[elevId] = status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -340,7 +340,7 @@ class ElevatorHandler {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 設定現在某個電梯所在樓層
 | 
			
		||||
    setCurElevFloor = function (elevId,floId) {
 | 
			
		||||
    setCurElevFloor = function (elevId, floId) {
 | 
			
		||||
        this.curElevFloor[elevId] = floId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -398,3 +398,206 @@ function isJSON(str) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 取得資料庫電梯設備,根據 baja 訂閱移動 3D 電梯
 | 
			
		||||
 * */
 | 
			
		||||
class Forge3DElevFull {
 | 
			
		||||
    constructor(option = {}) {
 | 
			
		||||
        this.allElevDevList = [];  //全電梯設備清單
 | 
			
		||||
        this.subSeviceData = [];    //每個設備訂閱點位值
 | 
			
		||||
        this.floList = [];
 | 
			
		||||
        this.elev3DBind = {};
 | 
			
		||||
        this.elev3DOption = {};
 | 
			
		||||
        this.elev3DObj = [];
 | 
			
		||||
        this.viewer = option.viewer ?? null;
 | 
			
		||||
        this.ordPath = option.ordPath ?? {};
 | 
			
		||||
        this.sysMainTag = option.system_tag ?? "ELEV";
 | 
			
		||||
        this.sysSubTag = option.name_tag ?? "EL";
 | 
			
		||||
        this.selector = option.selector ?? "#forgeViewer";
 | 
			
		||||
        this.bajaChaCallback = option.bajaChaCallback ?? null;
 | 
			
		||||
        this.bajaEndCallback = option.bajaEndCallback ?? null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    init = function () {
 | 
			
		||||
        // 系統大類、小類固定
 | 
			
		||||
        this.ordPath.system_tag = this.sysMainTag;
 | 
			
		||||
        this.ordPath.name_tag = this.sysSubTag;
 | 
			
		||||
        this.getElevDevList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 訂閱電梯設備
 | 
			
		||||
    subElevDevice = function () {
 | 
			
		||||
        let myBaja = new subscriptionDevices();
 | 
			
		||||
        let ordPath = this.ordPath;
 | 
			
		||||
 | 
			
		||||
        myBaja.setSubscribeDevicesByBql(ordPath);
 | 
			
		||||
        myBaja.setSubscribeDevicesCallBack((data) => {
 | 
			
		||||
            this.bajaChaCallback ? this.bajaChaCallback(data) : "";
 | 
			
		||||
            if (this.allElevDevList.length == 0) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            data.device_number = data.device_number_full;
 | 
			
		||||
 | 
			
		||||
            let matchDevice = this.allElevDevList.filter(x => x.device_number == data.device_number)[0];
 | 
			
		||||
 | 
			
		||||
            if (!matchDevice) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //將訂閱值塞入 subSeviceData
 | 
			
		||||
            if (this.subSeviceData.findIndex(x => x.device_number == matchDevice.device_number) == -1) {
 | 
			
		||||
                let obj = {};
 | 
			
		||||
                obj.device_number = matchDevice.device_number;
 | 
			
		||||
                this.subSeviceData.push(obj)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let subData = this.subSeviceData.filter(x => x.device_number == matchDevice.device_number)[0];
 | 
			
		||||
 | 
			
		||||
            if (subData) {
 | 
			
		||||
                subData[data.point_name] = data.value;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (data.point_name == "CP") {
 | 
			
		||||
                if (this.elev3DObj.length != 0) {
 | 
			
		||||
                    let elevObj = this.elev3DObj.filter(x => x.nodeId == this.elev3DBind[matchDevice.device_number])[0];
 | 
			
		||||
                    if (elevObj && elevObj.id) {
 | 
			
		||||
                        elevObj.obj.setElevatorFloor(data.value)
 | 
			
		||||
                        elevObj.obj.movElevator();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        myBaja.setSubscribeDeviceEndCallBack((data) => {
 | 
			
		||||
            this.floList = data.filter(x => x.point_name.startsWith("SP_FLS_")).map(x => x?.point_name?.split("SP_FLS_")[1]).Distinct();
 | 
			
		||||
            this.set3DElevOpt(data);
 | 
			
		||||
            this.bajaEndCallback != null ? this.bajaEndCallback() : "";
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 電梯 3D Option 設置
 | 
			
		||||
    set3DElevOpt = function (data) {
 | 
			
		||||
        let devNumArr = data.map(x => { return { devNum: x.device_number_full, priority: this.allElevDevList.filter(y => y.device_number == x.device_number_full)[0]?.priority } }).DistinctBy("devNum");
 | 
			
		||||
        devNumArr = devNumArr.oSort("priority");
 | 
			
		||||
        $.each(devNumArr, (idx, devObj) => {
 | 
			
		||||
            let devNum = devObj.devNum;
 | 
			
		||||
            let subData = this.subSeviceData.filter(x => x.device_number == devNum)[0];
 | 
			
		||||
 | 
			
		||||
            if (subData) {
 | 
			
		||||
                //// 左側 3D 電梯 nodeID 與 device_number match
 | 
			
		||||
                //if (Object.keys(elev3DBind).indexOf(devNum) == -1 && viewer3DNodeIds.length != 0) {
 | 
			
		||||
                //    elev3DBind[devNum] = viewer3DNodeIds[Object.keys(elev3DBind).length];
 | 
			
		||||
                //}
 | 
			
		||||
                // 左側 3D 電梯 Viewer Option 設置
 | 
			
		||||
                /*elev3DOption.nodes = Object.keys(elev3DBind).map(x => elev3DBind[x]);*/
 | 
			
		||||
                this.elev3DOption.nodeId = this.elev3DBind[devNum];
 | 
			
		||||
                this.elev3DOption.floorHeight = this.floList.map((x) => { return { floor: x } });
 | 
			
		||||
                this.elev3DOption.floorHeight.forEach((floObj, idx) => {
 | 
			
		||||
                    if (floObj.floor.startsWith("B")) {
 | 
			
		||||
                        let floor = parseInt(floObj.floor.split("B")[1].split("F")[0]);
 | 
			
		||||
                        floObj.height = floor * -13;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        let floor = parseInt(floObj.floor.split("F")[0]);
 | 
			
		||||
                        if (floor == 1) {
 | 
			
		||||
                            floObj.height = 0;
 | 
			
		||||
                        } else if (floor == 2) {
 | 
			
		||||
                            floObj.height = 14.75;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            floObj.height = (14.75 + ((floor - 2) * 9.75));
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
 | 
			
		||||
                if (this.elev3DObj.length != 0) {
 | 
			
		||||
                    let elevObj = this.elev3DObj.filter(x => x.nodeId == this.elev3DBind[devNum])[0];
 | 
			
		||||
                    if (!elevObj.id) {
 | 
			
		||||
                        elevObj.id = devNum;
 | 
			
		||||
                    }
 | 
			
		||||
                    elevObj.obj = Object.assign(elevObj.obj, this.elev3DOption);
 | 
			
		||||
                    elevObj.obj.init(() => {
 | 
			
		||||
                        let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == this.elev3DBind[devNum]);
 | 
			
		||||
 | 
			
		||||
                        frags.forEach((fragProxy) => {
 | 
			
		||||
                            fragProxy.frag.position.z = this.elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
 | 
			
		||||
                            fragProxy.frag.updateAnimTransform();
 | 
			
		||||
                        })
 | 
			
		||||
                        elevObj.obj.viewer.impl.sceneUpdated(true);
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        this.set3DElevPos();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 電梯 3D 位置呈現
 | 
			
		||||
    set3DElevPos = function () {
 | 
			
		||||
        let nodeIds = this.allElevDevList.filter(x => !isNaN(parseInt(x.forge_dbid))).map(x => { return { devNum: x.device_number, nodeId: parseInt(x.forge_dbid) } });
 | 
			
		||||
 | 
			
		||||
        $.each(nodeIds, (idx, item) => {
 | 
			
		||||
            this.elev3DBind[item.devNum] = item.nodeId;
 | 
			
		||||
        })
 | 
			
		||||
        nodeIds = nodeIds.map(x => x.nodeId);
 | 
			
		||||
        $.each(nodeIds, (idx, node) => {
 | 
			
		||||
            let options = {
 | 
			
		||||
                element: $(this.selector),
 | 
			
		||||
                viewer: this.viewer,
 | 
			
		||||
                nodeId: node,
 | 
			
		||||
                floorHeight: this.elev3DOption.floorHeight ?? [],
 | 
			
		||||
                inited: function () {
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            let elevator3DObj = new elevator3D(options);
 | 
			
		||||
            let devNum = Object.keys(this.elev3DBind).filter(x => this.elev3DBind[x] == node)[0];
 | 
			
		||||
            let subData = this.subSeviceData.filter(x => x.device_number == devNum)[0];
 | 
			
		||||
 | 
			
		||||
            if (this.elev3DObj.filter(x => x.nodeId == node).length == 0) {
 | 
			
		||||
                this.elev3DObj.push({ id: devNum, nodeId: node, obj: elevator3DObj });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (subData) {
 | 
			
		||||
                let elevObj = this.elev3DObj.filter(x => x.nodeId == node)[0];
 | 
			
		||||
                if (!elevObj.id) {
 | 
			
		||||
                    elevObj.id = devNum;
 | 
			
		||||
                }
 | 
			
		||||
                elevObj.obj = Object.assign(elevObj, elevator3DObj ?? {})
 | 
			
		||||
                elevObj.obj.init(() => {
 | 
			
		||||
                    let frags = elevObj.obj.fragProxys.filter(x => x.nodeId == node);
 | 
			
		||||
 | 
			
		||||
                    frags.forEach((fragProxy) => {
 | 
			
		||||
                        fragProxy.frag.position.z = this.elev3DOption.floorHeight.filter(x => x.floor == subData["CP"])[0]?.height ?? 0;
 | 
			
		||||
                        fragProxy.frag.updateAnimTransform()
 | 
			
		||||
                    })
 | 
			
		||||
                    elevObj.obj.viewer.impl.sceneUpdated(true);
 | 
			
		||||
                })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 取得設備列表
 | 
			
		||||
    getElevDevList = function () {
 | 
			
		||||
        let url = baseApiUrl + "/api/Device/GetDeviceList";
 | 
			
		||||
        let sendData = {
 | 
			
		||||
            sub_system_tag: this.ordPath.name_tag,
 | 
			
		||||
            building_tag: this.ordPath.building_tag,
 | 
			
		||||
        };
 | 
			
		||||
        objSendData.Data = sendData;
 | 
			
		||||
        ytAjax = new YourTeam.Ajax(url, objSendData, (res) => {
 | 
			
		||||
            if (!res || res.code != "0000" || !res.data) {
 | 
			
		||||
 | 
			
		||||
            } else {
 | 
			
		||||
                $.each(res.data, (index, floObj) => {
 | 
			
		||||
                    $.each(floObj.device_list, (index2, devObj) => {
 | 
			
		||||
                        this.allElevDevList.push(devObj);
 | 
			
		||||
                    })
 | 
			
		||||
                })
 | 
			
		||||
                this.subElevDevice();
 | 
			
		||||
            }
 | 
			
		||||
        }, null, "POST").send();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -74,8 +74,20 @@ Array.prototype.sum = function () {
 | 
			
		||||
        return a + b;
 | 
			
		||||
    }, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BigInt.prototype.toJSON = function () { return this.toString() }
 | 
			
		||||
 | 
			
		||||
Map.prototype.toArrObj = function () {
 | 
			
		||||
    let result = [];
 | 
			
		||||
    tarArr = Array.from(this);
 | 
			
		||||
    tarArr.forEach((target) => {
 | 
			
		||||
        let resObj = {};
 | 
			
		||||
        resObj[target[0]] = target[1];
 | 
			
		||||
        result.push(resObj);
 | 
			
		||||
    })
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$.fn.classList = function () { return this[0].className.split(/\s+/); };
 | 
			
		||||
 | 
			
		||||
$.fn.replaceClass = function (oriClass, newClass) { $(this).removeClass(oriClass).addClass(newClass); return $(this) };
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user