<template>
  <div ref="ztable" class="ztable">
    <div class="table-top" ref="tableTop">
      <div class="filter">
        <slot name="filter-left" />
        <x-filter
          ref="filter"
          v-if="filters"
          :filters="filters"
          @on-search="filterSearch"
        />
        <slot name="filter-right" />
      </div>
      <div class="right-btns">
        <slot name="btn-left" />
        <Button
          style="margin-right:10px;"
          @click="deleteBatchAction"
          v-if="showDeleteBatch && !deleteBatch"
          type="error"
          ghost
          >批量删除</Button
        >
        <Button
          style="margin-right:10px;"
          @click="deleteBatchConfirm"
          v-if="showDeleteBatch && deleteBatch"
          type="error"
          >确认删除</Button
        >
        <Button
          style="margin-right:10px;"
          @click="deleteBatchCancel"
          v-if="showDeleteBatch && deleteBatch"
          type="warning"
          >取消</Button
        >
        <slot name="btn-center" />
        <i-button-group v-if="showTools" style="margin-right:10px;">
          <slot name="btn-group-left" />
          <Button :loading="exportLoad" @click="ExportAll" icon="md-download"
            >所有</Button
          >
          <Button :loading="exportLoad" @click="Export" icon="md-download"
            >本页</Button
          >
          <slot name="btn-group-center" />
          <Button @click="Reset" icon="md-undo"></Button>
          <Button @click="columntoolShow = true" icon="md-settings"></Button>
          <Button @click="Refresh" icon="md-refresh"></Button>
          <slot name="btn-group-right" />
        </i-button-group>
        <slot name="btn-right" />
      </div>
    </div>
    <Table
      highlight-row
      stripe
      size="small"
      v-if="tableResetShow"
      ref="table"
      style="width:100%"
      @on-selection-change="selectionChange"
      @on-sort-change="tableSortChange"
      @on-row-dblclick="onRowDbClick"
      :height="style.tableHeight"
      :width="style.tableWidth"
      :columns="localColumnsShow"
      :data="data"
    />
    <div ref="page" style="padding:3px 10px;">
      <slot name="footer" />
      <slot name="page">
        <Page
          show-total
          :current="page.page"
          @on-page-size-change="pageSizeChange"
          @on-change="pageChange"
          :page-size="20"
          :page-size-opts="[20, 30, 50, 100, 250]"
          show-sizer
          style="float:right;"
          :total="total"
        />
      </slot>
    </div>
    <x-ticket
      v-if="ticketType"
      :type="ticketType"
      :form="ticketForm"
      :show.sync="ticketShow"
    />
    <x-column
      ref="xcolumn"
      v-if="columntool"
      :name="columntool"
      @on-select="tcolumn_filter"
      :visible.sync="columntoolShow"
      :columns="localColumns"
    />
  </div>
</template>
<script>
import { setInterval, setTimeout } from "timers";
import xColumn from "./modules/xColumn";
import xFilter from "./modules/xFilter";
import xTicket from "./modules/ticket";
import filterHead from "./modules/filterHead";
import { ExportJson } from "./lib/excel";
export default {
  components: { xColumn, xFilter, xTicket, filterHead },
  props: {
    // filter
    filters: Array,

    // tools
    showTools: { type: Boolean, default: true },
    showDeleteBatch: { type: Boolean, default: false },

    // table
    isPage: { type: Boolean, default: true },
    total: Number,
    data: { required: true, type: Array },
    columns: { required: true, type: Array },
    loadData: { required: true, type: Function }
  },
  computed: {},
  data() {
    return {
      // 本地配置
      localColumns: [],
      localColumnsShow: [],
      columntool: "",
      columntoolShow: false,
      deleteBatch: false,
      selection: [],

      // 工单ticket
      ticketType: "",
      ticketShow: false,
      ticketForm: {},

      // table top 配置
      exportLoad: false,

      // table 配置
      tableResetShow: true,
      page: { page: 1, limit: 20, count: true },
      filterParam: {}, // filter组件的查询条件
      tableQuery: {},
      tableSort: {}, // table组件的排序条件

      coltkey: {
        slice_eq: /\[\](.*)\.(.*?)\s*={2,3}\s*(.*?);\s*(.*?)\s*$/ //  "[]sensors.unit == 'F2';value" or "[]row.sensors.unit === 'F2';time"
      },
      timer: null, // 定时器，用于屏幕宽度或者高度变化的时候，自适应
      style: { windowHeight: 200, tableHeight: 200 },

      // 公共资源
      dicts: [],
      units: []
    };
  },
  methods: {
    Refresh() {
      this.LoadData();
      this.$Message.success({ content: "刷新成功" });
    },
    Export() {
      setTimeout(() => {
        this.exportLoad = true;
      });
      this.excelExport(this.data);
      setTimeout(() => {
        this.exportLoad = false;
      }, 100);
    },
    ExportAll() {
      setTimeout(() => {
        this.exportLoad = true;
      });
      this.LoadData(
        data => {
          if (this.isPage) {
            this.excelExport(data.data);
          } else {
            this.excelExport(data);
          }
          this.exportLoad = false;
        },
        { limit: 99999999, page: 1 }
      );
    },

    trow_value(key, obj) {
      if (!obj) {
        return null;
      }
      let o = JSON.parse(JSON.stringify(obj));
      let keys = key.split(".");
      for (let k of keys) {
        if (o[k] != undefined) {
          o = o[k];
        } else {
          return null;
        }
      }
      return o;
    },
    tkey_slice_eq(col) {
      let r = col.tkey.match(this.coltkey.slice_eq);
      if (r.length < 5) return;
      let keys = r[1];
      let field = r[2];
      let optValue = r[3];
      let ofield = r[4];

      return (h, { row }) => {
        let slice = this.trow_value(keys, row);
        if (!(slice instanceof Array)) {
          console.error("只接受数组类型，但是获取到的是：", slice);
          return h("div", "invalid type slice");
        }
        let fieldSh = optValue.match(/\"(.*?)\"|\'(.*?)\'/);
        if (fieldSh && fieldSh.length > 2) {
          optValue = fieldSh[1] || fieldSh[2];
        }
        let obj = slice.find(r => {
          return r[field] === optValue;
        });

        let value = this.trow_value(ofield, obj);

        return this.tformat_render(h, col, row, value);
      };
    },
    tkey_components(col) {
      let target = "a",
        result = col.title,
        style = {},
        on = {},
        props = {};
      let self = this;
      return {
        fixed: col.fixed ? col.fixed : "right",
        align: col.align ? col.align : "center",
        render(h, { row }) {
          if (!col.ticketOid) {
            console.error("ticketOid属性不能为空");
          }
          if (!col.ticketOType) {
            console.error("ticketOType属性不能为空");
          }
          let value = self.trow_value(col.ticketOid, row);
          switch (col.tkey) {
            case "$ticket":
              on = {
                click: () => {
                  self.ticketForm = {
                    otype: col.ticketOType,
                    oid: value
                  };
                  self.ticketType = col.ticketType;
                  self.ticketShow = true;
                }
              };
          }

          return h(target, { style, on, props }, result);
        }
      };
    },
    tkey_common_value(col) {
      return (h, { row }) => {
        let value = this.trow_value(col.tkey, row);
        return this.tformat_render(h, col, row, value);
      };
    },

    tformat_render(h, col, row, value) {
      let result = "";
      if (col.tdata && col.tdata instanceof Function) {
        result = col.tdata.call(this.$parent, { value, row });
      }

      if (col.tformat && col.tformat instanceof Function) {
        return col.tformat.call(this.$parent, h, row, value);
      } else if (typeof col.tformat === "string") {
        let [key, flag] = col.tformat.split(":");

        switch (key) {
          case "unit":
            result = this.tformat_render_unit(flag, value);
            break;
          case "time":
            result = this.tformat_render_time(flag, value);
            break;
          case "dict":
            result = this.tformat_render_dict(flag, value);
            break;
        }
      } else {
        result = value == null ? "-" : value;
      }
      let { target, style, props } = this.tstyle_render(col, result, value);

      let on = {};
      if (col.tclick && col.tclick instanceof Function) {
        on["on-click"] = on.click = e => {
          col.tclick.call(this.$parent, { row, value, result, e });
        };
      }

      return h(target, { style, on, props }, result);
    },
    tformat_render_dict(key, value) {
      let o = this.dicts.find(r => r.id === key);
      if (!o) {
        console.error(`未找到"${unit}"的unit对象`);
        return value;
      }
      let d = o.values.find(r => r.value == value);
      if (!d) {
        return "-";
      }
      return d.name;
    },
    tformat_render_time(key, value) {
      let t = null;
      if ((value + "").length == 10) {
        t = new Date(value * 1000);
      } else if ((value + "").length == 13) {
        t = new Date(value);
      } else {
        return "-";
      }
      if (key == "auto") {
        let now = new Date();
        now.setHours(0);
        now.setMinutes(0);
        now.setSeconds(0);
        let day = now.setMilliseconds(0);
        now.setDate(0);
        let year = now.setMonth(0);

        let n = t.getTime();
        if (n >= day) {
          key = "Hm";
        } else if (n >= year) {
          key = "MDHm";
        } else {
          key = "YMDHm";
        }
      }

      let ks = key.split("");
      let result = "";
      for (let k of ks) {
        switch (k) {
          case "Y":
            result += t.getFullYear() + "-";
            break;
          case "M":
            result += ("00" + (t.getMonth() + 1)).slice(-2) + "-";
            break;
          case "D":
            result += ("00" + t.getDate()).slice(-2) + " ";
            break;
          case "H":
            result += ("00" + t.getHours()).slice(-2) + ":";
            break;
          case "m":
            result += ("00" + t.getMinutes()).slice(-2) + ":";
            break;
          case "s":
            result += ("00" + t.getSeconds()).slice(-2) + ":";
            break;
        }
      }
      return result.slice(0, -1);
    },
    tformat_render_unit(unit, value) {
      let o = this.units.find(r => r.id === unit);
      if (!o) {
        console.error(`未找到"${unit}"的unit对象`);
        return value;
      }
      if (o.precision != null && typeof value == "number") {
        value = value.toFixed(o.precision);
      }
      unit = o.unit;

      let KG = (unit || "").match(/\*(.*?)#/g);
      if (unit && KG && KG.length > 0) {
        for (let s of KG) {
          let str = s.slice(1, s.length - 1);
          let [k, v] = str.split(":");
          if (k != undefined && v != undefined && k == value) {
            return v;
          }
        }
        return "-";
      } else {
        return value === undefined || value === null ? "-" : value;
      }
    },
    tstyle_render(col, valueShow, valueReal) {
      if (!col.tstyle) {
        return { target: "div", style: {} };
      }

      if (typeof col.tstyle === "string") {
        if (/^Tag(:[0-9a-zA-Z]+)?$/.test(col.tstyle)) {
          let [tag, color] = col.tstyle.split(":");
          if (!color) {
            color = "default";
          }
          return { target: tag, props: { color: color } };
        } else if (/^a(:[0-9a-zA-Z]+)?$/.test(col.tstyle)) {
          return { target: "a" };
        }
        return { target: "div", style: { color: col.tstyle } };
      } else if (col.tstyle instanceof Object) {
        let result = { target: "div", style: {} };
        for (let key in col.tstyle) {
          if (/^Tag:\S+$/.test(key)) {
            let [target, kk] = key.split(":");
            let ks = kk.split(",");
            if (
              ks.indexOf(valueShow + "") == -1 &&
              ks.indexOf(valueReal + "") == -1
            ) {
              continue;
            }
            result.target = "Tag";
            result.props = { color: col.tstyle[key] };
            return result;
          }

          let ks = key.split(",");
          if (
            ks.indexOf(valueShow + "") == -1 &&
            ks.indexOf(valueReal + "") == -1
          ) {
            continue;
          }
          result.style.color = col.tstyle[key];
        }
        return result;
      }
      return { target: "div", style: {} };
    },
    tfilter_render(col) {
      let tfilters = col.tfilters;

      if (typeof tfilters === "string") {
        // "tfilters":"[]type" or "tfilters":"type"
        if (
          /^\[?\]?[a-zA-Z0-9]+$/.test(tfilters) &&
          col.tformat &&
          typeof col.tformat === "string"
        ) {
          tfilters = col.tformat + ";" + tfilters;
        }
        // "tfilters":"unit:F3;[]type" or "tfilters":"unit:F3;type"
        if (/[a-zA-Z0-9]+:[a-zA-Z0-9]+;\[?\]?[a-zA-Z0-9]+$/.test(tfilters)) {
          let [key, flag] = tfilters.split(":");
          switch (key) {
            case "unit":
              return this.tfilter_render_unit(flag);
            case "dict":
              return this.tfilter_render_dict(flag);
          }
        }
        // "input:start-end"
        if (/^input:[0-9a-zA-Z]+-[0-9a-zA-Z]+$/.test(tfilters)) {
          return this.tfilter_render_between(tfilters);
        }
      } else if (tfilters instanceof Array) {
        return this.tfilter_render_slice(tfilters);
      }
    },
    tfilter_render_unit(flag) {
      let [unit, field] = flag.split(";");

      let o = this.units.find(r => r.id === unit);
      if (!o) {
        console.error(`未找到"${unit}"的unit对象`);
        return value;
      }

      let filters = [];

      let KG = (o.unit || "").match(/\*(.*?)#/g);
      if (o.unit && KG && KG.length > 0) {
        for (let s of KG) {
          let str = s.slice(1, s.length - 1);
          let [k, v] = str.split(":");
          filters.push({
            label: v,
            value: k
          });
        }
      }

      return {
        filterMultiple: false,
        filters: filters,
        filterRemote(values, b, column) {
          if (/\[\].*/.test(field)) {
            this.tableQuery[field.slice(2)] = values;
          } else {
            this.tableQuery[field] = values[0];
          }
          this.page.page = 1;
          this.LoadData();
        }
      };
    },
    tfilter_render_dict(flag) {
      let [dict, field] = flag.split(";");

      let o = this.dicts.find(r => r.id === dict);
      if (!o) {
        console.error(`未找到"${unit}"的unit对象`);
        return value;
      }

      let filters = [];

      if (o.values && o.values.length > 0) {
        for (let s of o.values) {
          filters.push({
            label: s.name,
            value: s.value
          });
        }
      }

      return {
        filterMultiple: false,
        filters: filters,
        filterRemote(values, b, column) {
          // []areas 返回值为数组
          if (/\[\].*/.test(field)) {
            this.tableQuery[field.slice(2)] = values;
          } else {
            // area 返回值为对象
            this.tableQuery[field] = values[0];
          }
          this.page.page = 1;
          this.LoadData();
        }
      };
    },
    tfilter_render_slice(tfilters) {
      return {
        filterMultiple: false,
        filters: tfilters.map(r => {
          return {
            label: r.title,
            value: {
              key: r.key,
              value: r.value
            }
          };
        }),
        filterRemote(values, b, column) {
          for (let o of tfilters) {
            delete this.tableQuery[o.key];
            if (o.value instanceof Array) {
            } else if (o.value instanceof Object) {
              for (let k in o.value) {
                delete this.tableQuery[k];
              }
            }
          }

          if (!values || values.length == 0) {
            this.page.page = 1;
            this.LoadData();
            return;
          }
          let { key, value } = values[0];

          switch (typeof value) {
            case "string":
            case "number":
            case "boolean":
              if (/\[\].*/.test(key)) {
                this.tableQuery[key.slice(2)] = [value];
              } else {
                // area 返回值为对象
                this.tableQuery[key] = value;
              }
              break;
            default:
              this.tableQuery = { ...this.tableQuery, ...value };
              break;
          }

          this.page.page = 1;
          this.LoadData();
        }
      };
    },
    tfilter_render_between(tfilters) {
      let [_, st, et] = tfilters.match(/^input:([0-9a-zA-Z]+)-([0-9a-zA-Z]+)$/);

      return {
        renderHeader: (h, { column }) => {
          return h(filterHead, {
            props: {
              column
            },
            on: {
              "on-filter": (start, end) => {
                this.tableQuery[st] = start;
                this.tableQuery[et] = end;
                this.page.page = 1;
                this.LoadData();
              }
            }
          });
        }
      };
    },
    tsort_render(col) {
      if (!/^\[?\]?[0-9a-zA-Z]+:\S+$/.test(col.tsort)) return {};
      return {
        sortable: "custom"
      };
    },
    // 渲染主入口
    tcolumn_init() {
      let cols = [];
      for (let col of this.columns) {
        if (col.tfilters) {
          col = { ...col, ...this.tfilter_render(col) };
        }
        if (col.tsort) {
          col = { ...col, ...this.tsort_render(col) };
        }
        if (col.type == "index") {
          col.key = col.key || "$_index";
          col.title = "#";
        }
        if (col.type == "expand") {
          col.key = col.key || "$_expand";
          col.title = " ";
        }
        if (col.render || !col.tkey) {
          cols.push(col);
          continue;
        }
        let tkey = col.tkey;
        if (this.coltkey.slice_eq.test(tkey)) {
          col.render = this.tkey_slice_eq(col);
          cols.push(col);
          continue;
        } else if (/^\$[0-9a-zA-Z]+$/.test(tkey)) {
          col = { ...col, ...this.tkey_components(col) };
          cols.push(col);
          continue;
        } else {
          col.render = this.tkey_common_value(col);
          cols.push(col);
          continue;
        }
      }
      this.columntool =
        location.href + this.columns.map(r => r.tkey || r.key).join(",");
      this.localColumns = this.localColumnsShow = cols;
      return cols;
    },
    // 数据列重组方法
    tcolumn_filter(ls) {
      let count = 0;
      for (let o of ls) {
        if (!o.title || o.title.trim() === "") {
          count++;
        }
      }
      if (count === ls.length) {
        this.localColumnsShow = [
          ...this.localColumnsShow,
          { title: " ", minWidth: 10 }
        ];
        return;
      }
      this.localColumnsShow = ls;
    },
    // table排序变化
    tableSortChange({ column, order }) {
      if (!/^\[?\]?[0-9a-zA-Z]+:\S+$/.test(column.tsort)) return {};
      let [field, col] = column.tsort.split(":");
      let arr = false;
      if (field.indexOf("[]") != -1) {
        arr = true;
        field = field.replace("[]", "");
      }
      // iview貌似不支持多个排序条件同时生效
      let param = {};
      switch (order) {
        case "asc":
          if (arr) {
            param[field] = [col];
          } else {
            param[field] = col;
          }
          break;
        case "desc":
          if (arr) {
            param[field] = [`-${col}`];
          } else {
            param[field] = `-${col}`;
          }
          break;
        default:
          delete param[field];
      }
      this.tableSort = param;
      this.LoadData();
    },
    Reset() {
      if (this.$refs.filter) {
        this.$refs.filter.Reset();
        this.filterParam = {};
      }
      this.tableResetShow = false;
      setTimeout(() => {
        this.tableResetShow = true;
      }, 20);
      this.tableQuery = {};
      this.tableSort = {};
      this.$emit("on-reset");

      this.LoadData();
    },
    pageChange(i) {
      if (this.page.page == i) {
        return;
      }
      this.page.page = i;
      this.LoadData();
    },
    pageSizeChange(i) {
      if (this.page.limit == i) {
        return;
      }
      this.page.page = 1;
      this.page.limit = i;
      this.LoadData();
    },
    // excel导出主方法
    excelExport(data) {
      ExportJson({
        columns: this.excelExportColumns(),
        header: this.excelExportHeaders(),
        data: data
      });
    },
    // excel 数据格式化方法
    excelExportColumns() {
      let result = [];
      for (let i = 0; i < this.localColumnsShow.length; i++) {
        let col = this.localColumnsShow[i];
        if (col.type == "index") {
          result.push("$index");
          continue;
        } else if (col.type == "expand") {
          continue;
        }
        // 模拟vue render，供Excel导出提供数据格式化
        if (col.render) {
          result.push(row => {
            let r = "";
            col.render(
              (target, style, result) => {
                r = result;
              },
              { row }
            );
            return r;
          });
        } else if (col.key) {
          result.push(col.key);
        }
      }
      return result;
    },
    // 导出标题头
    excelExportHeaders() {
      let headers = [];
      let colnames = [];
      let flag = false;
      for (let col of this.localColumnsShow) {
        if (col.type == "index") {
          headers.push(col.title);
          continue;
        } else if (col.type == "expand") {
          continue;
        }
        headers.push(col.title);
        colnames.push(col.texcelName || col.key);
        if (col.texcelName != undefined) {
          flag = true;
        }
      }

      if (flag) {
        return [headers, colnames];
      } else {
        return [headers];
      }
    },
    // 查询条件发生变化的时候调用
    filterSearch(obj) {
      this.page.page = 1;
      this.filterParam = obj;
      this.LoadData();
    },
    LoadData(fn, page, query) {
      let param = null;

      if (this.isPage) {
        param = {
          ...this.page,
          ...this.tableQuery,
          ...this.filterParam,
          ...this.tableSort,
          ...page,
          ...query
        };
      } else {
        param = {
          ...this.tableQuery,
          ...this.filterParam,
          ...this.tableSort,
          ...query
        };
      }
      this.loadData(param, fn);
    },
    selectionChange(rows) {
      this.selection = rows;
    },
    deleteBatchAction() {
      this.selection = [];
      this.deleteBatch = true;
      this.localColumnsShow = [
        { type: "selection", width: 60, align: "center" },
        ...this.localColumnsShow
      ];
    },
    deleteBatchConfirm() {
      this.deleteBatch = false;
      this.localColumnsShow = this.localColumnsShow.slice(1);
      this.$emit("on-delete-batch", this.selection);
      this.selection = [];
      this.$refs.table.selectAll(false);
    },
    deleteBatchCancel() {
      this.deleteBatch = false;
      this.localColumnsShow = this.localColumnsShow.slice(1);
      this.selection = [];
      this.$refs.table.selectAll(false);
    },

    display() {
      if (this.timer) {
        return;
      }
      this.timer = setInterval(() => {
        if (!this.$refs.ztable) return;
        let windowHeight = this.$refs.ztable.clientHeight;
        let windowWidth = this.$refs.ztable.clientWidth;
        let tableTop = this.$refs.tableTop.clientHeight;
        let page = this.$refs.page.clientHeight;
        this.style = {
          windowHeight: windowHeight,
          tableHeight: windowHeight - tableTop - page,
          tableWidth: windowWidth
        };
      }, 200);
    },
    init() {
      let units =
        ((this.$store || { state: {} }).state.common || {}).units || [];
      if (units.length == 0) {
        console.error(
          "unit单位列表未配置，需要在store.common.units中配置unit列表"
        );
        return;
      }
      this.units = units;

      let dicts =
        ((this.$store || { state: {} }).state.common || {}).dicts || [];
      if (dicts.length == 0) {
        console.error(
          "dicts数据字典列表未配置，需要在store.common.dicts中配置dict列表"
        );
        return;
      }
      this.dicts = dicts;
    },
    onRowDbClick(row) {
      this.$emit("on-row-dblclick", row);
    }
  },
  created() {
    this.init();
    this.LoadData();
  },
  mounted() {
    this.tcolumn_init();
    this.display();
    setTimeout(() => {
      this.$refs.xcolumn.initMap();
      this.$refs.xcolumn.onOk();
    }, 20);
  },
  beforeDestroy() {
    if (this.timer) {
      clearInterval(this.timer);
    }
  }
};
</script>
<style lang="less" scoped>
.ztable {
  display: flex;
  flex-direction: column;
  height: 100%;

  /deep/ .ivu-table-row td {
    height: 32px;
    line-height: 32px;
  }
  /deep/ .ivu-table-cell-with-expand {
    height: 32px;
    line-height: 32px;
  }

  /deep/ .ivu-table-header th {
    border-width: 0 1px 1px 0;
    border-style: solid;
    border-color: #f0f0f0;
  }
  /deep/ .ivu-table-row td {
    border-width: 0 1px 1px 0;
    border-style: solid;
    border-color: #f0f0f0;
  }

  .table-top {
    display: flex;
    padding: 5px;
    .filter {
      flex-grow: 1;
      display: flex;
    }
    .right-btns {
      .item {
        margin-right: 10px;
      }

      /deep/ button:focus {
        box-shadow: none;
      }
    }
  }
}
</style>
