<template>
  <div :style="pageStyle">
    <q-card v-if="showSearchPanel" style="margin-bottom: 15px">
      <q-resize-observable @resize="onSearchPanelResize"></q-resize-observable>
      <q-card-actions class="row items-center" align="center">
        <div class="col">
          <slot name="search-form"></slot>
        </div>
        <div class="col">
          <q-btn
            color="primary"
            v-if="showSearchBtn"
            @click="searchOk"
            :label="$t('sys.search')"
            style="min-width: 80px"
          ></q-btn>
          <q-btn
            color="secondary"
            v-if="showDownloadBtn"
            @click="downloadCsv"
            :label="$t('sys.export')"
            style="min-width: 80px"
          ></q-btn>
        </div>
        <div class="w3-container">
          <slot name="search-panel-actions"></slot>
        </div>
      </q-card-actions>
    </q-card>
    <q-modal
      position="top"
      no-backdrop-dismiss
      no-esc-dismiss
      v-model="searchOpened"
    >
      <div style="min-width: 300px; min-height: 100px">
        <div class="w3-padding">
          <slot name="search-form"></slot>
        </div>
        <div class="w3-padding w3-center">
          <q-btn
            color="primary"
            @click="searchOk"
            :label="$t('sys.search')"
            style="width: 100px"
          ></q-btn>
          <q-btn
            color="secondary"
            @click="searchCancel"
            :label="$t('sys.cancel')"
            style="width: 100px"
          ></q-btn>
        </div>
      </div>
    </q-modal>
    <div>
      <q-search
        v-if="showSearchFieldWithMobile"
        v-model="filter"
        clearable
      ></q-search>
    </div>
    <q-modal
      no-esc-dismiss
      no-backdrop-dismiss
      v-model="isShowColumnsUsersSetting"
    >
      <div style="overflow-y: hidden">
        <div
          style="
            color: #fff;
            background-color: #334048;
            text-align: center;
            font-size: 18pt;
            padding: 5px;
          "
        >
          {{ $t("sys.column").toUpperCase() }}
        </div>
        <!--螢幕高度80%-->
        <div
          :style="{
            'overflow-y': 'auto',
            'min-height': 'min-content',
            'max-height': columnsSettingHeight,
          }"
        >
          <q-list separator link>
            <q-item
              v-for="(itm, idx) in columnsTemp"
              :key="itm.name"
              :class="currentColumnName == itm['name'] ? 'w3-khaki' : ''"
            >
              <q-item-side
                ><q-toggle
                  v-model="columnsTemp[idx].$$users_setting_is_show"
                ></q-toggle
              ></q-item-side>
              <q-item-main :label="itm.label"></q-item-main>
              <q-item-side>
                <q-btn
                  dense
                  icon="arrow_upward"
                  color="blue"
                  @click="columnsMoveUpDown(idx, itm['name'], 'up')"
                ></q-btn>
                &nbsp;
                <q-btn
                  dense
                  icon="arrow_downward"
                  color="red"
                  @click="columnsMoveUpDown(idx, itm['name'], 'down')"
                ></q-btn>
              </q-item-side>
            </q-item>
          </q-list>
        </div>
        <div class="w3-center w3-padding">
          <q-btn
            :label="$t('sys.ok')"
            color="primary"
            @click="doColumnsUsersSetting"
            style="width: 70px"
          ></q-btn>
          <q-btn
            :label="$t('sys.cancel')"
            color="secondary"
            @click="openColumnsUsersSetting(false)"
            style="width: 70px"
          ></q-btn>
          <q-btn
            :label="$t('sys.default')"
            color="orange"
            @click="initColumnsDefault(true)"
            style="width: 70px"
          ></q-btn>
        </div>
      </div>
    </q-modal>
    <q-table
      :title="title"
      :data="data"
      :filter="filter"
      :columns="columnsList"
      :row-key="rowKey"
      :pagination.sync="pagination"
      :selection="selection"
      :selected.sync="selfSelected"
      :rows-per-page-options="rowsPerPageOptions"
      :binary-state-sort="true"
    >
      <template slot="top-left">
        <div v-if="!showSearchFieldWithMobile && showSearchField">
          <q-search v-model="filter" clearable></q-search>
        </div>
        <q-btn
          v-if="showUsersSettingBtn"
          color="primaty"
          flat
          round
          dense
          icon="settings"
          @click="openColumnsUsersSetting(true)"
        >
        </q-btn>
      </template>
      <q-tr slot="header" slot-scope="props">
        <q-th auto-width class="text-center" v-if="selection == 'multiple'">
          <q-checkbox
            color="primary"
            v-model="select_all"
            @input="select_all_check"
          ></q-checkbox>
        </q-th>
        <q-th
          v-for="(col, index) in props.cols"
          :style="col.style"
          :key="col.name"
          :props="props"
          :class="`${
            sticky_col.includes(index) ? 'sticky_col sticku_col_' + index : ''
          }`"
        >
          {{ col.label }}
        </q-th>
      </q-tr>
      <q-tr
        slot="body"
        slot-scope="props"
        :props="props"
        @click.native="rowClick(props, event)"
      >
        <q-td
          auto-width
          class="text-center"
          v-if="selection == 'multiple' || selection == 'single'"
        >
          <q-checkbox color="primary" v-model="props.selected"></q-checkbox>
        </q-td>
        <q-td
          v-for="(col, index) in props.cols"
          :key="col.name"
          :props="props"
          :style="col.$$data_style"
          :class="`${
            sticky_col.includes(index) ? 'sticky_col sticku_col_' + index : ''
          }`"
        >
          <slot
            v-if="col.$$is_slot"
            :name="'row_col_' + col.name"
            :row_data="props"
          ></slot>
          <div
            v-else-if="col.$$is_num_format"
            v-text="$root.FnFormatNumber(col.value, col.$$num_format_decimal)"
          ></div>
          <div
            v-else-if="col.$$is_date_format"
            v-text="moment(col.value).format('YYYY/MM/DD')"
          ></div>
          <div
            v-else-if="col.$$is_datetime_format"
            v-text="moment(col.value).format('YYYY/MM/DD HH:mm:ss')"
          ></div>
          <div
            v-else
            v-text="col.value"
            :style="
              _.isFunction(col.$$fn_data_style)
                ? col.$$fn_data_style(props.row)
                : ''
            "
          ></div>
        </q-td>
        <q-td style="width: 10px" align="center">
          <slot name="row-control" :row_data="props"></slot>
        </q-td>
      </q-tr>
    </q-table>
    <q-page-sticky position="top-right" :offset="[10, 10]">
      <!-- 預設有一個 search button //-->
      <q-btn
        round
        v-if="showSearchBtn && showMiniSearchPanel"
        color="primary"
        @click="searchOpened = true"
        icon="search"
      ></q-btn>
      <q-btn
        round
        v-if="showSearchBtn && showDownloadBtn && showMiniSearchPanel"
        color="primary"
        @click="downloadCsv"
        icon="download"
      ></q-btn>
      <slot name="page-sticky"> </slot>
    </q-page-sticky>
  </div>
</template>

<script>
module.exports = {
  name: "data-table",
  props: {
    title: {
      type: "String",
    },
    "offset-screen-height": {
      // 微調螢幕的長度, 因為要算每頁筆數, 本元件可能有配合父頁版面調整大小
      type: "Number",
      default: -150,
    },
    "show-search-btn": {
      // 是否顯示查詢按鈕
      type: "Boolean",
      default: true,
    },
    "show-mini-search-panel": {
      // 是否顯示右上按鈕小圖示區塊
      type: "Boolean",
      default: false,
    },
    "show-search-panel": {
      // 是否顯示查詢面版
      type: "Boolean",
      default: false,
    },
    "show-download-btn": {
      // 是否顯示下載按鈕
      type: "Boolean",
      default: false,
    },
    "show-search-field": {
      // 是否顯示slot top-left 的查詢欄位
      type: "Boolean",
      default: false,
    },
    "show-users-setting-btn": {
      // 是否顯示slot top-left 的欄位設定按鈕
      type: "Boolean",
      default: true,
    },
    "rows-num": {
      // 一頁要幾筆
      default: 0,
    },
    outfilter: {
      // 來自外部的過濾
      default: "",
    },
    selection: {
      type: "String", // 是否出現checkbox選單(原quasar功能), single:單選, multiple:多選
    },
    selected: {
      // 回傳選擇記錄後的值給父層, 父層需使用.sync修飾詞 <data-table :selected.sync="xxx" />
      type: "Array",
      default: [],
    },
    "row-key": {
      // 表格資料的主key
      default: "__index",
    },
    columns: {
      // 欄位清單
      type: "Array",
      default: [],
    },
    data: {
      // 資料清單
      type: "Array",
      default: [],
    },
    "page-style": {
      // 放在頁面 template / div 的 style
      type: "String",
      default: "",
    },
    excel_name: {
      // 資料清單
      type: "String",
      default: "report",
    },
    sort_by: {
      //對應個欄位的name
      type: "String",
      default: "",
    },
    sort_type: {
      //排序方式 預設降序 參數 降序:DESC 升序:ASC
      type: "String",
      default: "DESC",
    },
    sticky_col: {
      type: "Array",
      default: [],
    },
  },
  data() {
    return {
      select_all: false, //複選框總控制項 false: 未選擇 null: 已選擇其中幾項 true: 全選
      filter: "",
      pagination: {
        sortBy: "",
        descending: false,
        rowsPerPage: 10,
      },
      searchOpened: false,
      searchPanelHeight: 0,
      columnsData: [], // 由page傳入後,可能會再經過修改顯示與順序等功能, 所以要另外存一份(若不存另一份,toggle無法填值到props)
      columnsTemp: [], // 在設定時的暫存資料(要確定後才會寫入columsData)
      columnsDb: [], // 從db取得的欄位設定資料
      isShowColumnsUsersSetting: false, // 開啟欄位設定的視窗
      currentColumnName: "", // 目前操作的欄位索引
    };
  },
  computed: {
    isDesktop() {
      // 是否為桌面平台
      return this.$root.VarIsDesktop;
    },
    isMobile() {
      // 是否為手機平台
      return this.$root.VarIsMobile;
    },
    isTablet() {
      // 是否為平板平台
      return this.$root.VarIsTablet;
    },
    isMenuOpen() {
      // 是否開啟選單
      return this.$root.VarIsMenuOpen;
    },
    screenIsVertical() {
      // 螢幕是否直立
      return this.$root.VarScreenIsVertical;
    },
    showSearchFieldWithMobile() {
      // 是否顯示查詢框, 加上 mobile 判斷
      return (
        this.showSearchField &&
        ((this.isMobile && this.screenIsVertical) ||
          (this.isTablet && this.isMenuOpen))
      );
    },
    layoutScreenHeight() {
      // 螢幕的高
      return this.$root.VarLayoutScreenHeight;
    },
    layoutContainerHeight() {
      // 螢幕的寬
      return this.$root.VarLayoutContainerHeight;
    },
    rowsPerPage() {
      // 每頁顯示幾筆, 會根據螢幕高度與平台計算
      var newNum = 0;
      if (this.rowsNum > 0) {
        newNum = this.rowsNum;
      } else {
        var screenHeightNow = this.layoutScreenHeight + this.offsetScreenHeight;
        if (this.isMobile && this.screenIsVertical) {
          // 手機 & 垂直
          newNum = Math.round((screenHeightNow - this.searchPanelHeight) / 70);
        } else if (this.isMobile) {
          newNum = Math.round(screenHeightNow / 120);
        } else if (this.isTablet && this.screenIsVertical) {
          // 平板 & 垂直
          newNum = Math.round((screenHeightNow - this.searchPanelHeight) / 70);
          // } else if (this.isTablet && this.isMenuOpen) { // 沒效, 有空再找原因
          //   return Math.round(this.layoutContainerHeight / 60) - 2
        } else if (this.isTablet) {
          newNum = Math.round(screenHeightNow / 100);
        } else {
          // 桌面
          newNum = Math.round((screenHeightNow - this.searchPanelHeight) / 70);
        }
      }
      return newNum;
    },
    rowsPerPageOptions() {
      // 每頁筆數選單
      if (this.isPhone) {
        return _.uniq([Math.round(this.rowsPerPage), 0]);
      } else {
        return _.uniq([Math.round(this.rowsPerPage), 5, 10, 20, 30, 50, 0]);
      }
    },
    selfSelected: {
      // 選擇哪些row
      get() {
        //這邊順便判斷是否已全選或選擇部分或全部取消，需更動全選框的判別狀態select_all
        if (this.selected.length == 0) {
          this.select_all = false;
        } else if (
          this.selected.length > 0 &&
          this.selected.length < this.data.length
        ) {
          this.select_all = null;
        } else {
          this.select_all = true;
        }
        return this.selected;
      },
      set(val) {
        this.$emit("update:selected", val); // 為了讓父層 :selected.sync 生效
      },
    },
    columns_for_excel() {
      let arr = [];
      arr = this.columns.filter((itm) => {
        return itm.$$excel_index != undefined;
      });
      arr.sort((a, b) => {
        return a.$$excel_index - b.$$excel_index;
      });
      if (arr.length == 0) {
        arr = this.columns;
      }
      return arr;
    },
    columnsList() {
      // 介面用的欄位清單
      return _.filter(this.columnsData, (itm) => {
        return itm.$$users_setting_is_show;
      });
    },
    columnsSettingHeight() {
      // 欄位設定視窗的清單的高度
      if (this.isMobile) {
        return "60vh";
      } else {
        return "600px";
      }
    },
    columnsDataMapIdx() {
      // 將 columnsData 轉成 map {欄位名稱:索引值}, 方便取用
      return _.reduce(
        this.columnsData,
        (result, value, idx) => {
          result[value.name] = idx;
          return result;
        },
        {}
      );
    },
  },
  updated() {
    //欄位固定需在updated階段進行偵測dom渲染完畢後才可執行 不然會是undefined
    this.init_table_sticky();
  },
  watch: {
    layoutScreenHeight() {
      // 當螢幕高度變更時(如:水平與垂值切換), 會變更rowsPerPage,所以要選擇該頁
      this.pagination.rowsPerPage = this.rowsPerPage;
    },
    searchPanelHeight() {
      // 當search panel 高度變更時, 會變更rowsPerPage,所以要選擇該頁
      if (this.showSearchPanel) {
        this.pagination.rowsPerPage = this.rowsPerPage;
      }
    },
    outfilter(nv) {
      this.filter = nv;
    },
    columns(nv) {
      _.each(nv, (itm) => {
        // 為了切換語系(因為由columns轉成columnsData無法直接切換,需在此撰寫watch處理)
        this.columnsData[this.columnsDataMapIdx[itm["name"]]].label =
          itm["label"];
      });
      /*if (this.showUsersSettingBtn) {
        this.loadColumnsSetting();
      } else {
        this.initColumnsDefault();
      }*/
    },
  },
  mounted() {
    window.onload = function () {};
    // this.test();
    this.pagination.rowsPerPage = this.rowsPerPage;
    this.filter = this.outfilter;
    this.initTableSort();
    if (this.showUsersSettingBtn) {
      this.loadColumnsSetting();
    } else {
      this.initColumnsDefault();
    }
  },
  methods: {
    rowClick(props, evt) {
      this.$emit("row-click", props, evt);
    },
    searchOk(evt) {
      // 查詢確認送出事件
      this.$emit("search-ok", evt);
      this.searchOpened = false;
    },
    searchCancel(evt) {
      // 取消查詢送出事件
      this.$emit("search-cancel", evt);
      this.searchOpened = false;
    },
    downloadCsv() {
      //匯出前依據當前排序整理匯出資料後再進行匯出
      sort_targe = this.pagination.sortBy;
      sort_type = this.pagination.descending;
      if (sort_targe != "") {
        this.data.sort(function (a, b) {
          //需確認各頁面的columns中欄位定義name與field是否一致 不一致會導致排序報錯
          var nameA = a[sort_targe];
          var nameB = b[sort_targe];
          if (sort_type) {
            //降序
            if (nameA < nameB) {
              return 1;
            }
            if (nameA > nameB) {
              return -1;
            }
          } else {
            //升序
            if (nameA < nameB) {
              return -1;
            }
            if (nameA > nameB) {
              return 1;
            }
          }
          return 0;
        });
      }
      // 下載csv
      this.$root.FnReportDownload("csv", this.data, this.columns_for_excel, {
        filename: `${this.excel_name}_${moment().format("YYYYMMDDHHmmss")}`,
      });
    },
    //設定q-table Pagination 項目
    initTableSort() {
      // 從 page 傳入的 sort_by sort_type 定義排序
      if (this.sort_by != "") {
        this.pagination.sortBy = this.sort_by;
      }
      if (this.sort_type == "DESC") {
        this.pagination.descending = true;
      }
    },
    initColumnsDefault(isTemp) {
      // 從 page 傳入的 columns 初始化欄位資料
      if (!isTemp) {
        this.columnsData = [];
      } else {
        this.columnsTemp = [];
      }
      _.each(this.columns, (itm) => {
        if (itm.$$only_excel == undefined || itm.$$only_excel == false) {
          if (!_.isBoolean(itm.$$users_setting_is_show)) {
            itm.$$users_setting_is_show = true;
          }
          if (!isTemp) {
            this.columnsData.push(_.cloneDeep(itm));
          } else {
            this.columnsTemp.push(_.cloneDeep(itm));
          }
        }
      });
    },
    loadColumnsSetting() {
      // 從db取得欄位設定資料
      this.$root
        .FnWebAPIGet({
          Action: "UsersSetting",
          Datas: {
            menu_page: this.$root.VarMenuPage,
          },
          menu_page: "sys_component",
        })
        .then((res) => {
          if (res.data.result) {
            this.columnsDb = JSON.parse(res.data.data); // 資料庫儲存的是json字串
            if (
              !_.isEmpty(this.columnsDb) &&
              this.columns.length == this.columnsDb.length
            ) {
              // 若有資料庫的設定, 則使用資料庫的設定(若沒有設定,則為[]字陣列)
              let interList = _.intersectionWith(
                this.columns,
                this.columnsDb,
                (itm1, itm2) => {
                  return itm1.name == itm2.name && itm1.field == itm2.field; // 比對目前最新欄位與資料庫儲存欄位是否相同
                }
              );
              // 若資料庫的欄位設定與目前目前最新欄位, 則使用資料庫的設定
              // 若不相同, 代表程式的columns有更新, 則使用目前最新欄位
              if (interList.length == this.columns.length) {
                this.columnsData = [];
                _.each(this.columnsDb, (itm) => {
                  let thisIdx = _.findIndex(this.columns, (v) => {
                    return v.name == itm.name;
                  });
                  let thisItm = _.cloneDeep(this.columns[thisIdx]);
                  thisItm.$$users_setting_is_show = itm.$$users_setting_is_show;
                  this.columnsData.push(thisItm);
                });
                return;
              } else {
                console.log(
                  "系統預設欄位與資料庫欄位設定不同, 使用系統預設欄位"
                );
              }
            }
          }
          this.initColumnsDefault();
        })
        .catch(function (err) {
          console.log(err);
          this.initColumnsDefault();
        });
    },
    onSearchPanelResize(props) {
      if (this.showSearchPanel) {
        // 若不顯示 search panel 則不需要取得它的高度
        this.searchPanelHeight = props.height;
      }
    },
    openColumnsUsersSetting(isOpen) {
      // 開啟欄位設定
      if (isOpen) {
        this.columnsTemp = _.cloneDeep(this.columnsData);
      }
      this.currentColumnName = "";
      this.isShowColumnsUsersSetting = isOpen;
    },
    doColumnsUsersSetting() {
      // 儲存欄位設定
      this.columnsData = _.cloneDeep(this.columnsTemp);
      this.isShowColumnsUsersSetting = false;
      this.$root.FnWebAPIPost({
        Action: "UsersSetting",
        Datas: {
          menu_page: this.$root.VarMenuPage,
          setting: this.columnsData,
        },
        menu_page: "sys_component",
      });
    },
    columnsMoveUpDown(idx, name, direction) {
      // 移動欄位順序
      this.currentColumnName = name;
      if (direction == "up") {
        if (idx > 0) {
          this.columnsTemp.splice(
            idx - 1,
            0,
            this.columnsTemp.splice(idx, 1)[0]
          );
        }
      } else {
        if (idx < this.columnsTemp.length - 1) {
          this.columnsTemp.splice(
            idx + 1,
            0,
            this.columnsTemp.splice(idx, 1)[0]
          );
        }
      }
    },
    //全選複選框功能控制
    select_all_check(check_all) {
      var that = this;
      //當全選
      if (check_all) {
        this.data.forEach((item) => {
          that.selected.push(item);
        });
      }
      //當取消全選
      else {
        this.$emit("update:selected", []); // 為了讓父層 :selected.sync 生效
      }
    },
    //leo 欄位固定初始化 須加在updated 生命週期內部監聽dom渲染狀態 不然會撈不到資料
    init_table_sticky() {
      //依據含有sticky_col class 的dom總數 來判斷是否渲染完畢，大於0就代表已渲染完
      if (document.getElementsByClassName("sticky_col").length > 0) {
        //初始化固定欄位第一欄的left 皆為0px
        var Previous_width = "0px";
        var Next_width = "0px";
        this.sticky_col.forEach((el_1) => {
          Array.from(
            document.getElementsByClassName(`sticku_col_${el_1}`)
          ).forEach((el) => {
            if (Next_width == "0px") {
              Next_width = window.getComputedStyle(el).width;
            }
            el.style.left = Previous_width;
          });
          Previous_width = Next_width;
        });
      }
    },
  },
};
</script>

<style scoped>
.q-table-top {
  background-color: #334048;
  color: #fff;
  font-size: 13pt;
  padding-right: 5px;
}
.q-table-top .q-input-target,
.q-table-top .q-if {
  color: #fff;
  font-size: 13pt;
}
.q-select .q-input-target {
  /* width: 10px !important; */
  font-size: 12pt;
}
.q-table > thead > tr > th:first-child,
td:first-child {
  padding-left: 12px !important;
}
.q-table > tbody > tr > td:first-child {
  padding-left: 12px !important;
}
th {
  font-size: 14pt;
  font-weight: bold;
  color: #287dd1;
}
/* 欄位固定 */
.sticky_col {
  position: -webkit-sticky;
  position: sticky;
  background-color: #fff;
  z-index: 99;
}
</style>
