1312 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1312 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
$(function () {
 | 
						|
  $(".dropdown-menu.dropdown-select-menu").each((index, value) => {
 | 
						|
    setDropdownItem(value);
 | 
						|
  });
 | 
						|
  setTopBuildingText();
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * fn 定義 | 手動初始化 Bootstrap dropdown select
 | 
						|
 */
 | 
						|
$.fn.droSetItem = function () {
 | 
						|
  setDropdownItem(this);
 | 
						|
  return this;
 | 
						|
};
 | 
						|
/**
 | 
						|
 * fn 定義 | 輸出含原元素 html
 | 
						|
 */
 | 
						|
$.fn.outerHtml = function () {
 | 
						|
  return $(this).prop("outerHTML");
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * fn 定義 | Loading 操作
 | 
						|
 * @param {any} type - close / start / exceed , exceed => 繼續執行並可切換文字
 | 
						|
 * @param {any} text - 右下角 Alert 文字
 | 
						|
 */
 | 
						|
$.fn.Loading = function (type = "close", text) {
 | 
						|
  let ele = this;
 | 
						|
  let aleObj = $(this)[0]._aleObj;
 | 
						|
  let showStatus = $(ele).data("loading-show-status");
 | 
						|
 | 
						|
  function closeLoading() {
 | 
						|
    $(ele).data("loading-show-status", "close");
 | 
						|
    $("body").css("overflow", "auto");
 | 
						|
    $(aleObj.ele).YTAlert().hide();
 | 
						|
    $(ele).animate({ opacity: 0 }, 300, () => {
 | 
						|
      if ($(ele).data("loading-show-status") == "close") {
 | 
						|
        $(ele).hide();
 | 
						|
      }
 | 
						|
    });
 | 
						|
  }
 | 
						|
  function showLoading() {
 | 
						|
    $(ele).data("loading-show-status", "show");
 | 
						|
    $("body").css("overflow", "hidden");
 | 
						|
    let aleObj = YT.Alert.Tip(text || "讀取中,請稍後", "show");
 | 
						|
    $(ele)[0]._aleObj = aleObj;
 | 
						|
    $(ele).show();
 | 
						|
    $(ele).animate({ opacity: 1 }, 300);
 | 
						|
 | 
						|
    $(aleObj.ele).YTAlert().text(text);
 | 
						|
  }
 | 
						|
  if (type == "close") {
 | 
						|
    closeLoading();
 | 
						|
  } else if (type == "exceed") {
 | 
						|
    $(aleObj.ele).YTAlert().text(text);
 | 
						|
  } else if (type == "start") {
 | 
						|
    showLoading();
 | 
						|
  }
 | 
						|
 | 
						|
  return $(this);
 | 
						|
};
 | 
						|
 | 
						|
$.fn.YTAlert = function () {
 | 
						|
  let th = { element: this };
 | 
						|
  th.hide = function (delay = 0) {
 | 
						|
    let obj = this;
 | 
						|
    setTimeout(function () {
 | 
						|
      $(obj.element).fadeOut(300);
 | 
						|
      alertIdArray.splice(
 | 
						|
        $.inArray($(obj.element).prop("id"), alertIdArray),
 | 
						|
        1
 | 
						|
      );
 | 
						|
      setTimeout(function () {
 | 
						|
        $(obj.element).remove();
 | 
						|
      }, 1000);
 | 
						|
    }, delay);
 | 
						|
  };
 | 
						|
 | 
						|
  th.text = function (text) {
 | 
						|
    let obj = this;
 | 
						|
    let id = $(obj.element).prop("id").split("tip-alert-")[1];
 | 
						|
    $(`#alert-text-${id}`).text(text);
 | 
						|
  };
 | 
						|
  return th;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * 設置 bootstrap dropdown 為下拉選單
 | 
						|
 * @param {any} menuEle - .dropdown-menu element
 | 
						|
 */
 | 
						|
function setDropdownItem(menuEle) {
 | 
						|
  if ($(menuEle).find(".dropdown-item.active").length == 0) {
 | 
						|
    $(menuEle).find(".dropdown-item").first().addClass("active");
 | 
						|
  }
 | 
						|
 | 
						|
  let actText = $(menuEle).find(".dropdown-item.active").first().text();
 | 
						|
  let actEleId = $(menuEle).prop("id");
 | 
						|
  if (actEleId) {
 | 
						|
    $(`.dropdown-toggle[data-target=${actEleId}]`).text(actText);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /*actChaCallback($(menuEle).find(".dropdown-item.active"))*/
 | 
						|
  $(menuEle).trigger("active:change", $(menuEle).find(".dropdown-item.active"));
 | 
						|
 | 
						|
  //點選選項 add active class
 | 
						|
  onEvent(
 | 
						|
    "click",
 | 
						|
    ".dropdown-menu.dropdown-select-menu .dropdown-item",
 | 
						|
    function () {
 | 
						|
      $(this)
 | 
						|
        .parent(".dropdown-menu.dropdown-select-menu")
 | 
						|
        .find(".dropdown-item")
 | 
						|
        .removeClass("active");
 | 
						|
      $(this).addClass("active");
 | 
						|
      setDropdownItem($(this).parent(".dropdown-menu.dropdown-select-menu"));
 | 
						|
    }
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * 預設設備圖像
 | 
						|
 * @param {any} obj
 | 
						|
 */
 | 
						|
function defDev(obj) {
 | 
						|
  let defSrc = "img/defdev.png";
 | 
						|
  obj.src = defSrc;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * jquery datatable - ajax send data reset
 | 
						|
 * @param {any} table
 | 
						|
 * @param {any} sendData
 | 
						|
 */
 | 
						|
function dtAjaxResetSendData(table, sendData) {
 | 
						|
  table.context[0].ajax.data = function (d) {
 | 
						|
    d = sendData;
 | 
						|
    return JSON.stringify(d);
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * element 建造
 | 
						|
 * @param {any} text
 | 
						|
 * @param {any} id
 | 
						|
 * @param {any} name
 | 
						|
 * @param {any} cls
 | 
						|
 * @param {any} data
 | 
						|
 * @param {any} attr
 | 
						|
 */
 | 
						|
function eleBuild(
 | 
						|
  text = null,
 | 
						|
  id = null,
 | 
						|
  name = null,
 | 
						|
  cls = [],
 | 
						|
  data = {},
 | 
						|
  attr = {}
 | 
						|
) {
 | 
						|
  (cls = cls ?? []), (data = data ?? {}), (attr = attr ?? {});
 | 
						|
  id = id ? `id="${id}"` : "";
 | 
						|
  name = name ? `name="${name}"` : "";
 | 
						|
  cls = cls.length != 0 ? `class="${cls.join(" ")}"` : "";
 | 
						|
  data =
 | 
						|
    data.length != 0
 | 
						|
      ? `${Object.keys(data)
 | 
						|
        .map((x) => `data-${x}="${data[x]}"`)
 | 
						|
        .join(" ")}`
 | 
						|
      : "";
 | 
						|
  attr = attr
 | 
						|
    ? `${Object.keys(attr)
 | 
						|
      .map((x) => `${x}="${attr[x]}"`)
 | 
						|
      .join(" ")}`
 | 
						|
    : "";
 | 
						|
  let attrArr = [],
 | 
						|
    attrText = "";
 | 
						|
  attrArr = [id, name, cls, data, attr];
 | 
						|
  attrText = attrArr.filter((x) => x != "").join(" ");
 | 
						|
  text = text === null ? "" : text;
 | 
						|
  return { attrText: attrText, text: text };
 | 
						|
}
 | 
						|
 | 
						|
function creEle(
 | 
						|
  ele,
 | 
						|
  text = null,
 | 
						|
  id = null,
 | 
						|
  name = null,
 | 
						|
  cls = [],
 | 
						|
  data = {},
 | 
						|
  attr = {}
 | 
						|
) {
 | 
						|
  let comp = eleBuild(text, id, name, cls, data, attr);
 | 
						|
  return $(`<${ele} ${comp.attrText}>${comp.text}</${ele}>`);
 | 
						|
}
 | 
						|
 | 
						|
function creDiv(
 | 
						|
  cls = [],
 | 
						|
  attr = {},
 | 
						|
  id = null,
 | 
						|
  name = null,
 | 
						|
  data = {},
 | 
						|
  text = null
 | 
						|
) {
 | 
						|
  return creEle("div", text, id, name, cls, data, attr);
 | 
						|
}
 | 
						|
 | 
						|
function creBtn(
 | 
						|
  text = null,
 | 
						|
  id = null,
 | 
						|
  name = null,
 | 
						|
  cls = [],
 | 
						|
  data = {},
 | 
						|
  attr = {}
 | 
						|
) {
 | 
						|
  return creEle("button", text, id, name, cls, data, attr);
 | 
						|
}
 | 
						|
 | 
						|
function creBtnHtml(
 | 
						|
  text = null,
 | 
						|
  id = null,
 | 
						|
  name = null,
 | 
						|
  cls = [],
 | 
						|
  data = {},
 | 
						|
  attr = {}
 | 
						|
) {
 | 
						|
  return creEle("button", text, id, name, cls, data, attr).prop("outerHTML");
 | 
						|
}
 | 
						|
 | 
						|
function creSelect(
 | 
						|
  id = null,
 | 
						|
  cls = [],
 | 
						|
  name = null,
 | 
						|
  data = {},
 | 
						|
  attr = {},
 | 
						|
  text = null
 | 
						|
) {
 | 
						|
  return creEle("select", text, id, name, cls, data, attr);
 | 
						|
}
 | 
						|
 | 
						|
function creOption(
 | 
						|
  text = null,
 | 
						|
  value = null,
 | 
						|
  data = {},
 | 
						|
  attr = {},
 | 
						|
  cls = [],
 | 
						|
  name = null,
 | 
						|
  id = null
 | 
						|
) {
 | 
						|
  value != null ? (attr.value = value) : attr;
 | 
						|
  return creEle("option", text, id, name, cls, data, attr);
 | 
						|
}
 | 
						|
 | 
						|
function creImg(
 | 
						|
  ele,
 | 
						|
  text = null,
 | 
						|
  id = null,
 | 
						|
  name = null,
 | 
						|
  cls = [],
 | 
						|
  data = {},
 | 
						|
  attr = {}
 | 
						|
) {
 | 
						|
  let comp = eleBuild(text, id, name, cls, data, attr);
 | 
						|
  return $(`<${ele} ${comp.attrText}>${comp.text}`);
 | 
						|
}
 | 
						|
 | 
						|
function creI(
 | 
						|
  cls = [],
 | 
						|
  data = {},
 | 
						|
  attr = {},
 | 
						|
  id = null,
 | 
						|
  name = null,
 | 
						|
  text = null
 | 
						|
) {
 | 
						|
  return creEle("i", text, id, name, cls, data, attr);
 | 
						|
}
 | 
						|
 | 
						|
function creA(
 | 
						|
  text = null,
 | 
						|
  attr = {},
 | 
						|
  cls = [],
 | 
						|
  id = null,
 | 
						|
  data = {},
 | 
						|
  name = null
 | 
						|
) {
 | 
						|
  return creEle("a", text, id, name, cls, data, attr);
 | 
						|
}
 | 
						|
 | 
						|
function creSpan(
 | 
						|
  text = null,
 | 
						|
  cls = [],
 | 
						|
  id = null,
 | 
						|
  attr = {},
 | 
						|
  data = {},
 | 
						|
  name = null
 | 
						|
) {
 | 
						|
  return creEle("span", text, id, name, cls, data, attr);
 | 
						|
}
 | 
						|
/**
 | 
						|
 * 根據該棟建築底下的'所有'電梯執行緒物件
 | 
						|
 * */
 | 
						|
class ElevatorHandler {
 | 
						|
  constructor(ele, option = {}) {
 | 
						|
    this.ele = ele;
 | 
						|
    this.eleId = "";
 | 
						|
    this.eleWra = $("<div></div>");
 | 
						|
    this.speed = 0.3;
 | 
						|
    this.movStatus = {}; // {id:elevator01,value:0} 0=no 1=up 2=down
 | 
						|
    this.floorHeight =
 | 
						|
      typeof option.fHeight == "undefined" ? 60 : option.fHeight;
 | 
						|
    this.floorWidth = typeof option.fWidth == "undefined" ? 45 : option.fWidth;
 | 
						|
    this.floors = typeof option.floors == "undefined" ? [{}] : option.floors;
 | 
						|
    this.elevators =
 | 
						|
      typeof option.elevators == "undefined" ? [{}] : option.elevators; // {id:elevator01}
 | 
						|
    this.curElevFloor =
 | 
						|
      typeof option.curElevFloor == "undefined" ? {} : option.curElevFloor;
 | 
						|
    this.setTimeout = null;
 | 
						|
    this.init();
 | 
						|
  }
 | 
						|
 | 
						|
  // 所有電梯初始化
 | 
						|
  init = function () {
 | 
						|
    this.setTabWra();
 | 
						|
    this.setTabFloor();
 | 
						|
    // 若已有每個設備的所在樓層,則預設到該樓層位置
 | 
						|
    if (Object.keys(this.curElevFloor).length != 0) {
 | 
						|
      $.each(Object.keys(this.curElevFloor), (idx, elevKey) => {
 | 
						|
        this.setElevFloor(elevKey, this.curElevFloor[elevKey]);
 | 
						|
      });
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  // 設置 wrapper
 | 
						|
  setTabWra = function () {
 | 
						|
    let id = $(this.ele).prop("id");
 | 
						|
    this.eleId = id;
 | 
						|
    if ($(this.ele).parent(".elevator-table-wrapper").length != 0) {
 | 
						|
      $(this.ele).unwrap(".elevator-table-wrapper");
 | 
						|
    }
 | 
						|
    let wrapper = creDiv(["elevator-table-wrapper"], null, `${id}_wrapper`);
 | 
						|
    $(this.ele).wrap(wrapper);
 | 
						|
    this.eleWra = wrapper;
 | 
						|
  };
 | 
						|
 | 
						|
  // 設置 table 樓層
 | 
						|
  setTabFloor = function () {
 | 
						|
    let _w = this.floorWidth,
 | 
						|
      _h = this.floorHeight;
 | 
						|
    let thead = creEle("thead"),
 | 
						|
      tbody = creEle("tbody");
 | 
						|
    let _floors = this.floors,
 | 
						|
      _ele = this.ele,
 | 
						|
      _elevators = this.elevators;
 | 
						|
    //樓層從小到大
 | 
						|
    _floors = _floors
 | 
						|
      .oSort("sort")
 | 
						|
      .reverse()
 | 
						|
      .map((x) => x.name);
 | 
						|
 | 
						|
    let theadTr = creEle("tr");
 | 
						|
 | 
						|
    for (let e = 1; e <= _elevators.length + 2; e++) {
 | 
						|
      let th = creEle("th");
 | 
						|
      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`,
 | 
						|
        });
 | 
						|
        th.append(spanUp);
 | 
						|
        th.append(span);
 | 
						|
        th.append(spanDown);
 | 
						|
      }
 | 
						|
      theadTr.append(th);
 | 
						|
    }
 | 
						|
    thead.css("position", "absolute");
 | 
						|
    thead.append(theadTr);
 | 
						|
 | 
						|
    //樓層表格建置 tbody
 | 
						|
    for (let f = 1; f <= _floors.length; f++) {
 | 
						|
      let tr = creEle("tr");
 | 
						|
 | 
						|
      for (let e = 1; e <= _elevators.length + 2; e++) {
 | 
						|
        let td = creEle("td");
 | 
						|
        td.css({ width: `${_w}px`, height: `${_h}px` });
 | 
						|
        if (e == 1) {
 | 
						|
          td.addClass("t-black");
 | 
						|
          td.text(_floors[f - 1]);
 | 
						|
        } else if (e == _elevators.length + 2) {
 | 
						|
        } else {
 | 
						|
          let div = creDiv([
 | 
						|
            "d-flex",
 | 
						|
            "justify-content-center",
 | 
						|
            "align-items-end",
 | 
						|
            "h-100",
 | 
						|
          ]);
 | 
						|
          div.append(`<i class="fal fa-door-open fs-1-2"></i>`);
 | 
						|
          td.append(div);
 | 
						|
        }
 | 
						|
        tr.append(td);
 | 
						|
      }
 | 
						|
      tbody.append(tr);
 | 
						|
    }
 | 
						|
 | 
						|
    $(_ele).append(thead);
 | 
						|
    $(_ele).append(tbody);
 | 
						|
 | 
						|
    //表格外圍無框線
 | 
						|
    $(_ele)
 | 
						|
      .find("tbody tr")
 | 
						|
      .each((index, tr) => {
 | 
						|
        $(tr).find("td:eq(0)").css("border-left", "0");
 | 
						|
        $(tr).find("td:eq(-1)").css("border-right", "0");
 | 
						|
 | 
						|
        if (index == 0) {
 | 
						|
          $(tr)
 | 
						|
            .find("td")
 | 
						|
            .each((index, td) => {
 | 
						|
              $(td).css("border-top", "0");
 | 
						|
            });
 | 
						|
        } else if (index == $("#floorTable tbody tr").length - 1) {
 | 
						|
          $(tr)
 | 
						|
            .find("td")
 | 
						|
            .each((index, td) => {
 | 
						|
              $(td).css("border-bottom", "0");
 | 
						|
            });
 | 
						|
        }
 | 
						|
      });
 | 
						|
  };
 | 
						|
 | 
						|
  // 設置某個電梯到某個樓層
 | 
						|
  setElevFloor = function (elevId, floId) {
 | 
						|
    let curFloId = this.curElevFloor[elevId];
 | 
						|
    let curSort = this.floors
 | 
						|
      .filter((x) => x.id == curFloId)
 | 
						|
      .map((x) => x.sort)[0];
 | 
						|
    let tarSort = this.floors
 | 
						|
      .filter((x) => x.id == floId)
 | 
						|
      .map((x) => x.sort)[0];
 | 
						|
    let gapFloor = tarSort - curSort;
 | 
						|
    let cssEle = [
 | 
						|
      $(`#elevator-item-${elevId}`)[0],
 | 
						|
      $(`#elevator-item-${elevId}`).prev("span.elevator-item-toup")[0],
 | 
						|
      $(`#elevator-item-${elevId}`).next("span.elevator-item-todown")[0],
 | 
						|
    ];
 | 
						|
    if (this.movStatus[elevId] != 0) {
 | 
						|
      $(cssEle).css(
 | 
						|
        "transition",
 | 
						|
        `transform ${(1 / this.speed) * Math.abs(gapFloor)
 | 
						|
        }s cubic-bezier(0, 0, 0.62, 1) 0s`
 | 
						|
      );
 | 
						|
    }
 | 
						|
    clearTimeout(this.setTimeout);
 | 
						|
    this.setTimeout = setTimeout(() => {
 | 
						|
      $(cssEle).css(
 | 
						|
        "transition",
 | 
						|
        `transform ${(1 / this.speed) * Math.abs(gapFloor)
 | 
						|
        }s cubic-bezier(0.43, 0.05, 0.62, 1) 0s`
 | 
						|
      );
 | 
						|
      this.setEleUpDownStyle(elevId);
 | 
						|
    }, (1 / this.speed) * Math.abs(gapFloor) * 1000);
 | 
						|
    this.setEleUpDownStyle(elevId);
 | 
						|
    this.curElevFloor[elevId] = floId;
 | 
						|
    $(cssEle).css(
 | 
						|
      "transition",
 | 
						|
      `transform ${(1 / this.speed) * Math.abs(gapFloor)
 | 
						|
      }s cubic-bezier(0.43, 0.05, 0.62, 1) 0s`
 | 
						|
    );
 | 
						|
    $(cssEle).css(
 | 
						|
      "transform",
 | 
						|
      `translateY(${this.floorHeight * (this.floors.length - tarSort)}px)`
 | 
						|
    );
 | 
						|
  };
 | 
						|
 | 
						|
  // 設定現在電梯狀態 (往上/往下/停止)
 | 
						|
  setEleMovStatus = function (elevId, status) {
 | 
						|
    this.movStatus[elevId] = status;
 | 
						|
  };
 | 
						|
 | 
						|
  // 電梯方框 往上或往下閃爍
 | 
						|
  setEleUpDownStyle = function (elevId) {
 | 
						|
    if (this.movStatus[elevId] == 1) {
 | 
						|
      $(`#elevator-item-${elevId}`)
 | 
						|
        .next("span.elevator-item-todown")
 | 
						|
        .removeClass("light-flash-c-bd");
 | 
						|
      $(`#elevator-item-${elevId}`)
 | 
						|
        .prev("span.elevator-item-toup")
 | 
						|
        .addClass("light-flash-c-bd")
 | 
						|
        .css("--flash-color-1", "#44ea8e")
 | 
						|
        .css("--flash-color-2", "rgba(255,255,255,0)");
 | 
						|
    } else if (this.movStatus[elevId] == 2) {
 | 
						|
      $(`#elevator-item-${elevId}`)
 | 
						|
        .prev("span.elevator-item-toup")
 | 
						|
        .removeClass("light-flash-c-bd");
 | 
						|
      $(`#elevator-item-${elevId}`)
 | 
						|
        .next("span.elevator-item-todown")
 | 
						|
        .addClass("light-flash-c-bd")
 | 
						|
        .css("--flash-color-1", "#44ea8e")
 | 
						|
        .css("--flash-color-2", "rgba(255,255,255,0)");
 | 
						|
    } else {
 | 
						|
      $(`#elevator-item-${elevId}`)
 | 
						|
        .prev("span.elevator-item-toup")
 | 
						|
        .removeClass("light-flash-c-bd");
 | 
						|
      $(`#elevator-item-${elevId}`)
 | 
						|
        .next("span.elevator-item-todown")
 | 
						|
        .removeClass("light-flash-c-bd");
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  // 設定現在某個電梯所在樓層
 | 
						|
  setCurElevFloor = function (elevId, floId) {
 | 
						|
    this.curElevFloor[elevId] = floId;
 | 
						|
  };
 | 
						|
 | 
						|
  // 重新繪製
 | 
						|
  redraw = function () {
 | 
						|
    $(this.ele).empty();
 | 
						|
    this.setTabFloor();
 | 
						|
    if (Object.keys(this.curElevFloor).length != 0) {
 | 
						|
      $.each(Object.keys(this.curElevFloor), (idx, elevKey) => {
 | 
						|
        this.setElevFloor(elevKey, this.curElevFloor[elevKey]);
 | 
						|
      });
 | 
						|
    }
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
// 從數字週數轉為中文週數
 | 
						|
function dayToChiDay(num) {
 | 
						|
  let chiDay = ["週日", "週一", "週二", "週三", "週四", "週五", "週六"];
 | 
						|
  return chiDay[num];
 | 
						|
}
 | 
						|
 | 
						|
// 取得現在或前後時間,輸出單位依據 type
 | 
						|
function getTimeByType(type = null, cal = 0, unit = "d") {
 | 
						|
  let now = new Date();
 | 
						|
  return strToDate(now, type, cal, unit);
 | 
						|
}
 | 
						|
 | 
						|
// 取得某當下時間或前後時間,輸出單位依據 type
 | 
						|
function strToDate(text, type = null, cal = 0, unit = "d") {
 | 
						|
  let dec = 24 * 60 * 60 * 1000;
 | 
						|
 | 
						|
  if (unit == "d") {
 | 
						|
    dec = 24 * 60 * 60 * 1000;
 | 
						|
  } else if (unit == "h") {
 | 
						|
    dec = 60 * 60 * 1000;
 | 
						|
  } else if (unit == "m") {
 | 
						|
    dec = 60 * 1000;
 | 
						|
  } else if (unit == "s") {
 | 
						|
    dec = 1000;
 | 
						|
  }
 | 
						|
 | 
						|
  let calDay = function (_d, _cal) {
 | 
						|
    return new Date(_d.getTime() + cal * dec);
 | 
						|
  };
 | 
						|
 | 
						|
  let tarDate = new Date(text);
 | 
						|
  let result = 0;
 | 
						|
  if (type == "year") {
 | 
						|
    result = calDay(tarDate, cal).getFullYear();
 | 
						|
  } else if (type == "month") {
 | 
						|
    result = calDay(tarDate, cal).getMonth();
 | 
						|
  } else if (type == "date") {
 | 
						|
    result = calDay(tarDate, cal).getDate();
 | 
						|
  } else if (type == "day") {
 | 
						|
    result = calDay(tarDate, cal).getDay();
 | 
						|
  } else {
 | 
						|
    result = calDay(tarDate, cal);
 | 
						|
  }
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
// 將只有時間(Hms) 格式轉換為當日的時間
 | 
						|
function fullTime(time) {
 | 
						|
  let nowDate = displayDate(new Date(), "date");
 | 
						|
  return new Date(nowDate + " " + time);
 | 
						|
}
 | 
						|
 | 
						|
function dateRanCutPart(start, end, cutNum) {
 | 
						|
  let sTime = new Date(start).getTime();
 | 
						|
  let eTime = new Date(end).getTime();
 | 
						|
  let cutTimeArr = [];
 | 
						|
  if (sTime < eTime) return [];
 | 
						|
 | 
						|
  let partNum = (sTime - eTime) / cutNum;
 | 
						|
  for (let i = eTime; i <= sTime; i = i + partNum) {
 | 
						|
    cutTimeArr.push(i);
 | 
						|
  }
 | 
						|
 | 
						|
  cutTimeArr.forEach((x) => new Date(x));
 | 
						|
 | 
						|
  return cutTimeArr;
 | 
						|
}
 | 
						|
 | 
						|
function isJSON(str) {
 | 
						|
  try {
 | 
						|
    JSON.parse(str);
 | 
						|
    return true;
 | 
						|
  } catch {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function addBsToast(
 | 
						|
  container,
 | 
						|
  type = "warning",
 | 
						|
  title = "",
 | 
						|
  content = "",
 | 
						|
  id,
 | 
						|
  datas = {},
 | 
						|
  option = {}
 | 
						|
) {
 | 
						|
  datas =
 | 
						|
    Object.keys(datas).length != 0
 | 
						|
      ? `${Object.keys(datas)
 | 
						|
        .map((x) => `data-${x}="${datas[x]}"`)
 | 
						|
        .join(" ")}`
 | 
						|
      : "";
 | 
						|
  let iconClass = option.iconHtml ?? `fas fa-exclamation-triangle`;
 | 
						|
  let strHtml = `<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false" ${datas}>
 | 
						|
                      <div class="toast-header ${warning ? `bg-` + warning : ""
 | 
						|
    }">
 | 
						|
                          <i class="${iconClass}"></i>
 | 
						|
                          <strong class="mr-auto">${title}</strong>
 | 
						|
                          <small class="text-muted">just now</small>
 | 
						|
                          <button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
 | 
						|
                              <span aria-hidden="true">×</span>
 | 
						|
                          </button>
 | 
						|
                      </div>
 | 
						|
                      <div class="toast-body">
 | 
						|
                          ${content}
 | 
						|
                      </div>
 | 
						|
                  </div>`;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * 取得資料庫電梯設備,根據 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;
 | 
						|
    this.sensorObjs = option.sensorObjs ?? null;
 | 
						|
  }
 | 
						|
 | 
						|
  init = function () {
 | 
						|
    // 系統大類、小類固定
 | 
						|
    this.ordPath.system_tag = this.sysMainTag;
 | 
						|
    this.ordPath.name_tag = this.sysSubTag;
 | 
						|
 | 
						|
    // if (pageAct.sysSubTag === "M12") {
 | 
						|
    //   console.log("@@",pageAct, pageAct.sysSubTag)
 | 
						|
    //   this.getSensorDevList();
 | 
						|
    // }
 | 
						|
    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;
 | 
						|
              let start = 0;
 | 
						|
              // 改變感測器熱點位置
 | 
						|
              this.sensorObjs &&
 | 
						|
                this.sensorObjs[0]?.changePos(
 | 
						|
                  node + 2,
 | 
						|
                  fragProxy.frag.position.z
 | 
						|
                );
 | 
						|
              // if (node === 15200 && start == 0) {
 | 
						|
              //     start = 1;
 | 
						|
              // }
 | 
						|
              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 ?? [],
 | 
						|
        sensorObjs: this.sensorObjs,
 | 
						|
        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;
 | 
						|
            let start = 0;
 | 
						|
            this.sensorObjs &&
 | 
						|
              this.sensorObjs[0]?.changePos(
 | 
						|
                node + 2,
 | 
						|
                fragProxy.frag.position.z
 | 
						|
              );
 | 
						|
            // if (node === 15200 && start == 0) {
 | 
						|
            //     // 改變感測器熱點位置
 | 
						|
            //     start = 1;
 | 
						|
            // }
 | 
						|
            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();
 | 
						|
  };
 | 
						|
 | 
						|
  getNodeIds = function () {
 | 
						|
    return this.elev3DObj.map((x) => x.nodeId);
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * 取得資料庫溫度感測器
 | 
						|
 * 1. baja 取得溫度感測器改變顏色
 | 
						|
 * 2. 參數取得要移動到的電梯位置
 | 
						|
 * */
 | 
						|
class Forge3DSensor {
 | 
						|
  constructor(option = {}) {
 | 
						|
    this.subDeviceData = []; //每個設備訂閱點位值
 | 
						|
    this.viewer = option.viewer ?? null;
 | 
						|
    this.ordPath = option.ordPath; // TPE_B1
 | 
						|
    this.sysMainTag = "ME";
 | 
						|
    this.sysSubTag = "M12";
 | 
						|
    this.selector = "#forgeViewer";
 | 
						|
    this.heatMap = null;
 | 
						|
    this.bajaChaCallback = option.bajaChaCallback ?? null;
 | 
						|
    this.bajaEndCallback = option.bajaEndCallback ?? null;
 | 
						|
    this.floorHeight = 0;
 | 
						|
    this.dataVizExtn = null;
 | 
						|
    this.DataVizCore = null;
 | 
						|
    this.tempVal = 20;
 | 
						|
    this.curDevice = option.curDevice ?? null;
 | 
						|
    this.deviceList = option.deviceList ?? null;
 | 
						|
    this.selector = option.selector ?? "#forgeViewer";
 | 
						|
    this.elevCb = option.elevCb ?? null;
 | 
						|
    this.#init();
 | 
						|
  }
 | 
						|
 | 
						|
  static sensorTimes = 0;
 | 
						|
 | 
						|
  #init = async function () {
 | 
						|
    // 系統大類、小類固定
 | 
						|
    this.ordPath.system_tag = this.sysMainTag;
 | 
						|
    this.ordPath.name_tag = this.sysSubTag;
 | 
						|
    // this.dataVizExtn = await this.viewer.loadExtension(
 | 
						|
    //   "Autodesk.DataVisualization"
 | 
						|
    // );
 | 
						|
    // this.DataVizCore = Autodesk.DataVisualization.Core;
 | 
						|
    await this.registerHotPoint();
 | 
						|
    this.addSensorHotspotList(this.curDevice.forge_dbid, 35);
 | 
						|
    this.subSensorDevice();
 | 
						|
    this.elevCb && this.elevCb();
 | 
						|
  };
 | 
						|
 | 
						|
  // // 建立熱點
 | 
						|
  // async addHotPoint() {
 | 
						|
 | 
						|
  //     // this.dataVizExtn.removeAllViewables()
 | 
						|
  //     await this.registerHotPoint()
 | 
						|
  //     this.subSensorDevice();
 | 
						|
  //     // console.log("2",this.dataVizExtn)
 | 
						|
  // }
 | 
						|
 | 
						|
  async registerHotPoint(color = "") {
 | 
						|
    if (Forge3DSensor.sensorTimes === 1) {
 | 
						|
      var viewer = this.viewer;
 | 
						|
      const dataVizExtn = await viewer.loadExtension(
 | 
						|
        "Autodesk.DataVisualization"
 | 
						|
      );
 | 
						|
      const DataVizCore = Autodesk.DataVisualization.Core;
 | 
						|
      const viewableType = DataVizCore.ViewableType.SPRITE; //DataVizCore.ViewableType.SPRITE;
 | 
						|
      const spriteColor = new THREE.Color(0xff8c00);
 | 
						|
      // const highlightedColor = new THREE.Color(0xe0e0ff);
 | 
						|
      let spriteIcon = "/file/img/forge/sensor_circle.svg";
 | 
						|
      if (location.href.indexOf("localhost:5966") != -1) {
 | 
						|
        spriteIcon = "/img/forge/sensor_circle.svg";
 | 
						|
      }
 | 
						|
      const style = new DataVizCore.ViewableStyle(
 | 
						|
        viewableType,
 | 
						|
        spriteColor,
 | 
						|
        spriteIcon
 | 
						|
      );
 | 
						|
      const viewableData = new DataVizCore.ViewableData();
 | 
						|
      viewableData.spriteSize = 30; // Sprites as points of size 24 x 24 pixels
 | 
						|
      this.deviceList.forEach((myData, index) => {
 | 
						|
        const dbId = myData.forge_dbid;
 | 
						|
        const myPosition = myData.position;
 | 
						|
        const viewable = new DataVizCore.SpriteViewable(
 | 
						|
          myPosition,
 | 
						|
          style,
 | 
						|
          dbId
 | 
						|
        );
 | 
						|
        myData._dbId = dbId;
 | 
						|
        viewableData.addViewable(viewable);
 | 
						|
      });
 | 
						|
      await viewableData.finish();
 | 
						|
      dataVizExtn.addViewables(viewableData);
 | 
						|
      viewer.addEventListener(
 | 
						|
        DataVizCore.MOUSE_CLICK,
 | 
						|
        this.onSpriteClicked.bind(this)
 | 
						|
      ); // SPRITE_SELECTED
 | 
						|
      // viewer.addEventListener(this.DataVizCore.MOUSE_CLICK_OUT, onSpriteClickedOut.bind(this));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  // ---------------- 熱點點擊事件 --------------------
 | 
						|
  onSpriteClicked(event) {
 | 
						|
    event.hasStopped = true;
 | 
						|
    const dbIdStart = 10;
 | 
						|
    if (event != undefined && event != null) {
 | 
						|
      if (event.dbId >= dbIdStart) {
 | 
						|
        let myData = this.deviceList.find((x) => x.forge_dbid == event.dbId);
 | 
						|
        console.log("site", myData);
 | 
						|
        // this.changeColorForSensorHotspot(event.dbId, this.tempVal);
 | 
						|
        myData && moveViewToDevice(myData.forge_dbid); //移動視角至該設備
 | 
						|
        myData &&
 | 
						|
          $(this.selector).trigger("autodesk:click:sprite", { event, myData });
 | 
						|
      } else {
 | 
						|
        $(this.selector).trigger("autodesk:clickOut:sprite", { event });
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // 改變熱點位置
 | 
						|
  async changePos(dbId, positionZ) {
 | 
						|
    const dataVizExtn = await viewer.loadExtension(
 | 
						|
      "Autodesk.DataVisualization"
 | 
						|
    );
 | 
						|
    dataVizExtn?.invalidateViewables(dbId, (viewable) => {
 | 
						|
      // console.log(viewable._position)
 | 
						|
      const z = viewable._position.z + positionZ;
 | 
						|
      const newPos = { ...viewable._position, z };
 | 
						|
      return {
 | 
						|
        // Move the viewable to a new location.
 | 
						|
        position: newPos,
 | 
						|
      };
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  // 溫度感測器 sprite 隨溫度變化
 | 
						|
  static lowerTempForSensor = [];
 | 
						|
  static normalTempForSensor = [];
 | 
						|
  static highTempForSensor = [];
 | 
						|
  static highestTempForSensor = [];
 | 
						|
 | 
						|
  async addSensorHotspotList(dbid, temp) {
 | 
						|
    let index = Math.floor(temp / 10) - 1 || 0;
 | 
						|
 | 
						|
    // 清空資料
 | 
						|
    Forge3DSensor.lowerTempForSensor = Forge3DSensor.lowerTempForSensor.filter(
 | 
						|
      (point) => point !== dbid
 | 
						|
    );
 | 
						|
    Forge3DSensor.normalTempForSensor =
 | 
						|
      Forge3DSensor.normalTempForSensor.filter((point) => point !== dbid);
 | 
						|
    Forge3DSensor.highTempForSensor = Forge3DSensor.highTempForSensor.filter(
 | 
						|
      (point) => point !== dbid
 | 
						|
    );
 | 
						|
    Forge3DSensor.highestTempForSensor =
 | 
						|
      Forge3DSensor.highestTempForSensor.filter((point) => point !== dbid);
 | 
						|
 | 
						|
    const temps = [
 | 
						|
      new THREE.Color(0x00009c),
 | 
						|
      new THREE.Color(0xffff31),
 | 
						|
      new THREE.Color(0xff8c00),
 | 
						|
      new THREE.Color(0xff0000),
 | 
						|
    ];
 | 
						|
 | 
						|
    switch (index) {
 | 
						|
      case -1:
 | 
						|
        Forge3DSensor.lowerTempForSensor.push(dbid);
 | 
						|
        break;
 | 
						|
      case 0:
 | 
						|
        Forge3DSensor.lowerTempForSensor.push(dbid);
 | 
						|
        break;
 | 
						|
      case 1:
 | 
						|
        Forge3DSensor.normalTempForSensor.push(dbid);
 | 
						|
        break;
 | 
						|
      case 2:
 | 
						|
        Forge3DSensor.highTempForSensor.push(dbid);
 | 
						|
        break;
 | 
						|
      case 3:
 | 
						|
        Forge3DSensor.highestTempForSensor.push(dbid);
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        Forge3DSensor.highTempForSensor.push(dbid);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    if (
 | 
						|
      (Forge3DSensor.lowerTempForSensor.length,
 | 
						|
        Forge3DSensor.normalTempForSensor.length,
 | 
						|
        Forge3DSensor.highTempForSensor.length,
 | 
						|
        Forge3DSensor.highestTempForSensor.length,
 | 
						|
        allDevList.length)
 | 
						|
    ) {
 | 
						|
      await this.changeColorForSensorHotspot(
 | 
						|
        Forge3DSensor.lowerTempForSensor,
 | 
						|
        temps[0]
 | 
						|
      );
 | 
						|
      await this.changeColorForSensorHotspot(
 | 
						|
        Forge3DSensor.normalTempForSensor,
 | 
						|
        temps[1]
 | 
						|
      );
 | 
						|
      await this.changeColorForSensorHotspot(
 | 
						|
        Forge3DSensor.highTempForSensor,
 | 
						|
        temps[2]
 | 
						|
      );
 | 
						|
      await this.changeColorForSensorHotspot(
 | 
						|
        Forge3DSensor.highestTempForSensor,
 | 
						|
        temps[3]
 | 
						|
      );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  async changeColorForSensorHotspot(viewablesToUpdate, color) {
 | 
						|
    const dataVizExtn = await viewer.loadExtension(
 | 
						|
      "Autodesk.DataVisualization"
 | 
						|
    );
 | 
						|
    dataVizExtn.invalidateViewables(viewablesToUpdate, (viewable) => {
 | 
						|
      return {
 | 
						|
        color: color,
 | 
						|
      };
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  // 訂閱sensor設備
 | 
						|
  subSensorDevice() {
 | 
						|
    let myBaja = new subscriptionDevices();
 | 
						|
    myBaja.setSubscribeDevicesByBql(this.ordPath);
 | 
						|
 | 
						|
    myBaja.setSubscribeDevicesCallBack((data) => {
 | 
						|
      this.bajaChaCallback ? this.bajaChaCallback(data) : "";
 | 
						|
      if (this.curDevice == null) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      data.device_number = data.device_number_full; // "TPE_B1_ME_M12_U1F_NA_TH_N1" (forge TPE_B1_ME_M12_R2F_NA_TH_N1)
 | 
						|
 | 
						|
      //將訂閱值塞入 subDeviceData
 | 
						|
      if (
 | 
						|
        this.subDeviceData.findIndex(
 | 
						|
          (d) => d.device_number == this.curDevice.id
 | 
						|
        ) == -1
 | 
						|
      ) {
 | 
						|
        let obj = {};
 | 
						|
        obj.device_number = this.curDevice.id;
 | 
						|
        obj.dbid = this.curDevice.roomDbId;
 | 
						|
        this.subDeviceData.push(obj);
 | 
						|
      }
 | 
						|
      let subData = this.subDeviceData.find(
 | 
						|
        (x) => x.device_number == this.curDevice.id
 | 
						|
      );
 | 
						|
 | 
						|
      if (subData) {
 | 
						|
        subData = { ...subData, [data.point_name]: data.value };
 | 
						|
      }
 | 
						|
 | 
						|
      if (data.point_name == "Temp" || data.point_name == "TEMP") {
 | 
						|
        this.tempVal = !isNaN(parseInt(data.value)) ? parseInt(data.value) : 0;
 | 
						|
        this.curDevice = {
 | 
						|
          ...this.curDevice,
 | 
						|
          temp: !isNaN(parseInt(data.value)) ? parseInt(data.value) : 0,
 | 
						|
        };
 | 
						|
 | 
						|
        if (data.device_number_full === this.curDevice.id) {
 | 
						|
          this.addSensorHotspotList(
 | 
						|
            this.curDevice.forge_dbid,
 | 
						|
            this.curDevice.temp
 | 
						|
          );
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      let matchDevice = allDevList.find(
 | 
						|
        (x) => x.device_number == data.device_number_full
 | 
						|
      );
 | 
						|
 | 
						|
      let norDevPoiName = matchDevice.device_normal_point_name;
 | 
						|
      let cloDevPoiName = matchDevice.device_close_point_name;
 | 
						|
      let errDevPoiName = matchDevice.device_error_point_name;
 | 
						|
      if (
 | 
						|
        data.point_name == norDevPoiName &&
 | 
						|
        data.value == matchDevice.device_normal_point_value
 | 
						|
      ) {
 | 
						|
 | 
						|
        //顯示正常燈號
 | 
						|
        $(`#${matchDevice.device_number}_status`)
 | 
						|
          .attr("data-light-type", "normal")
 | 
						|
          .data("light-type", "normal");
 | 
						|
      } else if (
 | 
						|
        data.point_name == cloDevPoiName &&
 | 
						|
        data.value == matchDevice.device_close_point_value
 | 
						|
      ) {
 | 
						|
 | 
						|
        $(`#${matchDevice.device_number}_status`)
 | 
						|
          .attr("data-light-type", "close")
 | 
						|
          .data("light-type", "close");
 | 
						|
      } else if (
 | 
						|
        data.point_name == errDevPoiName &&
 | 
						|
        data.value == matchDevice.device_error_point_value
 | 
						|
      ) {
 | 
						|
        $(`#${matchDevice.device_number}_status`)
 | 
						|
          .attr("data-light-type", "error")
 | 
						|
          .data("light-type", "error");
 | 
						|
      }
 | 
						|
 | 
						|
      setLightColor();
 | 
						|
      setDevItemPoiValBySub(data);
 | 
						|
      $(loadEle).Loading("close");
 | 
						|
    });
 | 
						|
 | 
						|
    myBaja.setSubscribeDeviceEndCallBack((data) => {
 | 
						|
      if (
 | 
						|
        data.findIndex(
 | 
						|
          (x) => x.point_name == "Temp" || x.point_name == "TEMP"
 | 
						|
        ) != -1
 | 
						|
      ) {
 | 
						|
        // 顯示溫度條
 | 
						|
        showHeat("[name=forgeHeatBar]");
 | 
						|
      }
 | 
						|
    });
 | 
						|
    // window.x = 28
 | 
						|
    // setInterval(()=>{
 | 
						|
    //   this.changeColorForSensorHotspot(this.curDevice.forge_dbid, x++)
 | 
						|
    // }, 2000)
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function setTopBuildingText() {
 | 
						|
  $(".top-building-text-container").load("_topBuildingText.html", function () {
 | 
						|
 | 
						|
  })
 | 
						|
}
 | 
						|
 | 
						|
function buildingTagOnJquery(building_tag) {
 | 
						|
  let frontSyntax = building_tag.slice(0, 2);
 | 
						|
  if (frontSyntax == "$3") {
 | 
						|
    return building_tag.slice(2, building_tag.length);
 | 
						|
  }
 | 
						|
  return building_tag;
 | 
						|
}
 | 
						|
 | 
						|
function buildingTagOnProcess(building_tag) {
 | 
						|
  if (!isNaN(parseInt(building_tag.slice(0, 1)))) {
 | 
						|
    building_tag = "$3" + building_tag;
 | 
						|
  }
 | 
						|
  return building_tag;
 | 
						|
}
 | 
						|
 | 
						|
function deviceNumber(devNum) {
 | 
						|
  if (devNum.includes("$3")) {
 | 
						|
    devNum = devNum.replaceAll("$3", "");
 | 
						|
  }
 | 
						|
  return devNum;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
function deviceNumberOnProcess(devNum) {
 | 
						|
  if (devNum.includes("/")) {
 | 
						|
    tags = devNum.split("/");
 | 
						|
    buildingTag = tags[1];
 | 
						|
    buildingTag = buildingTagOnProcess(buildingTag);
 | 
						|
    devNum = tags[0] + "/" + buildingTag + "/" + tags.slice(2, tags.length).join("/")
 | 
						|
  }
 | 
						|
  return devNum;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
function convertToBase64(imagePath, callback) {
 | 
						|
  // 創建一個新的 FileReader 物件
 | 
						|
  const reader = new FileReader();
 | 
						|
 | 
						|
  // 當 FileReader 讀取完成時的處理函數
 | 
						|
  reader.onloadend = () => {
 | 
						|
    if (typeof callback === 'function') {
 | 
						|
      // 從 result 中獲取 base64 編碼的圖像數據
 | 
						|
      const base64String = reader.result.split(',')[1];
 | 
						|
      callback(base64String);
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  // 讀取圖像文件
 | 
						|
  fetch(imagePath)
 | 
						|
    .then((response) => response.blob())
 | 
						|
    .then((blob) => reader.readAsDataURL(blob))
 | 
						|
    .catch((error) => console.error('Error:', error));
 | 
						|
} |