<template>
  <f-panel class="f-tpl">
    <div slot="header" class="f-tpl__header">
      <f-filter
        v-if="filters.length > 0"
        class="f-tpl__filter"
        ref="filter"
        :list="filters"
        @on-filter="onFilter"
      >
        <slot name="buttons" slot="buttons"></slot>
      </f-filter>
      <div v-else class="f-tpl__filter">
        <slot name="filter"></slot>
      </div>
      <div class="f-tpl__tool">
        <Button
          v-if="addButton && title && canCreate"
          slot="buttons"
          type="primary"
          icon="md-add"
          @click="onAdd"
          style="margin-right: 20px"
        >
          {{ title }}
        </Button>

        <Dropdown
          v-if="toolbar.indexOf('export') > -1 && canRead"
          @on-click="onDataExport"
        >
          <Button
            icon="md-download"
            style="margin-right: 10px;"
            class="f-tpl__hb"
          ></Button>
          <DropdownMenu slot="list">
            <DropdownItem name="current">导出本页</DropdownItem>
            <DropdownItem name="all">导出全部</DropdownItem>
          </DropdownMenu>
        </Dropdown>
        <Tooltip
          content="列设置"
          placement="bottom"
          style="margin-right: 10px;"
          v-if="toolbar.indexOf('column') > -1"
        >
          <Button
            class="f-tpl__hb"
            @click="onShowColumn"
            icon="md-settings"
          ></Button>
        </Tooltip>
        <Tooltip
          content="刷新"
          v-if="toolbar.indexOf('refresh') > -1"
          placement="bottom"
          style="margin-right: 5px;"
        >
          <Button
            class="f-tpl__hb"
            @click="() => onRefresh()"
            icon="md-refresh"
          ></Button>
        </Tooltip>
      </div>
      <slot name="right-block"></slot>
    </div>
    <div slot="body" slot-scope="props">
      <Table
        ref="table"
        :size="size"
        :height="props.bodyHeight"
        :columns="mColumns"
        border
        :highlight-row="highlight"
        :stripe="stripe"
        @on-row-dblclick="onRowDblClick"
        @on-row-click="onRowClick"
        @on-sort-change="onSortChange"
        :loading="loading"
        :data="data"
        class="f-table"
      >
        <img src="./loading.gif" slot="loading" alt="" />
      </Table>
      <slot></slot>
      <Drawer
        v-model="dialog"
        :title="modalTitle()"
        :width="drawerWidth"
        class="f-drawer"
        :mask-closable="false"
        :draggable="true"
        v-if="modalType == 'Drawer'"
      >
        <div class="f-drawer__body" style="overflow-y: auto;padding: 16px">
          <i-form
            ref="form"
            :label-width="labelWidth"
            :rules="rules"
            :model="form"
          >
            <slot name="form" :model="form" :row="nowRow" :action="action">
            </slot>
          </i-form>
        </div>
        <div class="f-drawer__footer">
          <Button @click="onCancel">取消</Button>
          <Button
            @click="onSubmit"
            :loading="formLoading"
            :style="{ width: formButtonName == '确定' ? '100px' : 'auto' }"
            type="primary"
            >{{ formButtonName }}</Button
          >
        </div>
      </Drawer>
      <Modal
        v-model="dialog"
        :title="modalTitle()"
        :width="drawerWidth"
        class="f-modal"
        :mask-closable="false"
        v-else
      >
        <div class="f-modal__body" style="padding: 16px">
          <i-form
            ref="form"
            :label-width="labelWidth"
            :rules="rules"
            :model="form"
          >
            <slot name="form" :model="form" :row="nowRow" :action="action">
            </slot>
          </i-form>
        </div>
        <div class="f-modal__footer" slot="footer">
          <Button @click="onCancel">取消</Button>
          <Button @click="onSubmit" :loading="formLoading" type="primary">{{
            formButtonName
          }}</Button>
        </div>
      </Modal>

      <f-col
        :name="columnKey"
        @on-select="onSelectColumns"
        :visible.sync="showColumn"
        :columns="columns"
        :defaultFields="defaultFields"
      ></f-col>
    </div>
    <div slot="footer" v-if="this.isPage">
      <f-page
        ref="page"
        :total="total"
        @on-page-change="onPageChange"
        @on-size-change="onSizeChange"
      ></f-page>
    </div>
  </f-panel>
</template>

<script>
import $ls from "../libs/store";
import FCol from "../col";
import excel from "@/libs/excel";

export default {
  name: "f-tpl",
  components: { FCol },
  props: {
    /*标题*/
    title: {
      type: String,
      default: ""
    },
    highlight: {
      type: Boolean,
      default: true
    },
    stripe: {
      type: Boolean,
      default: true
    },
    columns: {
      type: Array,
      default: () => []
    },
    /*筛选条件*/
    filters: {
      type: Array,
      default: () => []
    },
    /*表单验证*/
    rules: Object,
    /*服务*/
    service: {
      type: Object,
      default: () => null
    },
    /*服务名称*/
    name: {
      type: String,
      default: null
    },
    colKey: {
      type: String,
      default: null
    },
    /*是否分页*/
    isPage: {
      type: Boolean,
      default: true
    },
    /*新增的Model*/
    newModel: {
      type: Function,
      default: () => {}
    },
    /*更新的Model*/
    updModel: {
      type: Function,
      default: () => {}
    },
    /*新增框的宽度*/
    drawerWidth: {
      type: Number,
      default: 600
    },
    /*是否采用自定义表单*/
    customForm: {
      type: Boolean,
      default: false
    },
    /*是否显示自定义数据*/
    customData: {
      type: Boolean,
      default: false
    },
    /*自定义数据*/
    tableData: {
      type: Array,
      default: () => []
    },
    /*服务对象*/
    client: {
      type: String,
      default: "iot-admin"
    },
    /*是否显示新增按钮*/
    addButton: {
      type: Boolean,
      default: true
    },
    /*是否可以编辑*/
    canEdit: {
      type: Boolean,
      default: true
    },
    /*是否可以获取数据*/
    canRead: {
      type: Boolean,
      default: true
    },
    canCreate: {
      type: Boolean,
      default: true
    },
    /*额外查询条件*/
    where: {
      type: Object,
      default: null
    },
    // /*是否导出全部*/
    // exportAll: {
    //   type: Boolean,
    //   default: true
    // },
    /*默认显示字段*/
    defaultFields: {
      type: Array,
      default: () => []
    },
    /*日期字段 处理*/
    dateFields: {
      type: Array,
      default: () => []
    },
    toolbar: {
      type: Array,
      default: () => ["export", "column", "refresh"]
    },
    size: {
      type: String,
      default: "small"
    },
    /*弹出类型*/
    modalType: {
      type: String,
      default: "Drawer"
    },
    formButtonName: {
      type: String,
      default: "确定"
    },
    transform: {
      type: Function,
      default: null
    },
    labelWidth: {
      type: Number,
      default: 80
    }
  },
  data() {
    return {
      total: 0,
      query: {
        limit: 20,
        page: 1,
        count: true
      },
      data: this.transData(this.tableData),
      loading: false,
      dialog: false,
      formLoading: false,
      action: "add",
      form: {},
      localColumns: [],
      showColumn: false,
      nowRow: {},
      exportAll: true,
      columnKey: this.colKey || this.name
    };
  },
  computed: {
    mColumns() {
      if (
        this.localColumns.length > 0 &&
        (this.localColumns[0].type === "index" ||
          this.localColumns[0].key === "index")
      ) {
        delete this.localColumns[0].type;
        this.localColumns[0].key = "index";
        let columns = this.localColumns;
        columns[0].transform = (row, index) => {
          return (this.query.page - 1) * this.query.limit + index + 1;
        };
        // columns[0]["render"] = (h, { index }) => {
        //   return h("div", (this.query.page - 1) * this.query.limit + index + 1);
        // };
        return columns;
      } else {
        return this.localColumns;
      }
    }
  },
  watch: {
    tableData() {
      this.data = this.transData(this.tableData);
    },
    columns: {
      deep: true,
      handler() {
        this.initColumns();
      }
    }
  },
  methods: {
    getQuery(reset) {
      if (reset) {
        this.query.page = 1;
        if (this.isPage) {
          this.$refs.page.reset();
        }
      }
      let query = JSON.parse(JSON.stringify(this.query));
      if (this.where) {
        query = Object.assign(query, this.where);
      }
      return query;
    },
    getData(reset, loading = true, callback, scroll = true) {
      if (!this.canRead) return;
      let query = this.getQuery(reset);
      this.loading = loading;
      this.$apollo
        .query({
          query: this.service[`Get${this.name}s`],
          client: this.client,
          variables: {
            query: query
          }
        })
        .then(({ data }) => {
          if (this.client == "iot-admin") {
            if (this.isPage) {
              this.data = this.transData(
                data[`admin_${this.name.toLowerCase()}s`].data
              );
              if (this.query.count) {
                this.total = data[`admin_${this.name.toLowerCase()}s`].total;
              }
            } else {
              this.data = this.transData(
                data[`admin_${this.name.toLowerCase()}s`]
              );
            }
          } else {
            if (this.isPage) {
              this.data = this.transData(
                data[`${this.name.toLowerCase()}s`].data
              );
              if (this.query.count) {
                this.total = data[`${this.name.toLowerCase()}s`].total;
              }
            } else {
              this.data = this.transData(data[`${this.name.toLowerCase()}s`]);
            }
          }
          this.loading = false;
          this.$emit("on-get-data", this.data, data);
          if (this.$refs.table && scroll) {
            this.$refs.table.$refs.body.scrollTop = 0;
          }
          if (callback) {
            callback.call(this);
          }
        });
    },
    transData(data) {
      const list = [];
      data.forEach((row, index) => {
        const item = JSON.parse(JSON.stringify(row));
        this.columns.forEach(column => {
          if (column.key) {
            if (column.transform) {
              item[column.key] = column.transform.call(this, row, index);
            } else {
              item[column.key] = row[column.key];
            }
          }
        });
        item._origin = row;
        list.push(item);
      });
      return list;
    },
    onAdd() {
      this.action = "add";

      if (!this.customForm) {
        this.dialog = true;
        this.form = this.newModel();
      }
      this.nowRow = {};
      this.$nextTick(() => {
        this.$refs.form.resetFields();
      });
      this.$emit("on-add");
    },
    async onEdit(row) {
      this.action = "edit";
      this.$refs.form.resetFields();
      if (!this.customForm) {
        this.dialog = true;
        let data = row._origin || row;
        if (this.service[`Get${this.name}`]) {
          const rep = await this.$apollo.query({
            query: this.service[`Get${this.name}`],
            variables: {
              id: row.id
            },
            client: this.client
          });
          data = rep.data[this.name.toLowerCase()];
        }

        this.form = this._clone(this.updModel(), data);
        this.form.id = row.id;
      }
      this.nowRow = row;
      this.$emit("on-edit", row._origin, row);
    },
    _clone(target, data) {
      for (let d in data) {
        if (d in target) {
          if (this.dateFields.indexOf(d) > -1 && data[d]) {
            target[d] = new Date(data[d] * 1000);
          } else {
            target[d] = data[d];
          }
        }
      }
      return target;
    },
    onDelete(id, str) {
      this.$Modal.confirm({
        title: "提示",
        content: str ? str : "确定要删除当前选择数据吗？",
        loading: true,
        onOk: () => {
          this.$apollo
            .mutate({
              mutation: this.service[`${this.name}Remove`],
              client: this.client,
              variables: {
                id
              }
            })
            .then(() => {
              this.$Modal.remove();
              this.$Message.success("删除成功！");
              this.$nextTick(() => {
                if (!this.customData) {
                  this.getData();
                }
                this.$emit("on-delete");
              });
            });
        }
      });
    },
    onRefresh(page = 1) {
      if (!this.customData) {
        this.query.page = page;
        if (this.isPage && page == 1) {
          this.$refs.page.reset();
        }
        this.getData();
        this._clearSortOn();
      }
      this.$emit("on-refresh");
    },
    _clearSortOn() {
      $(this.$refs.table.$el)
        .find(".ivu-table-sort .on")
        .removeClass("on");
    },
    async onExport(data) {
      if (data) {
        this.exportExcel(this.columns, this.transData(data));
      } else if (this.isPage == false) {
        this.$refs.table.exportCsv({
          filename: "export",
          original: false
        });
        this.exportExcel(this.columns, this.data);
      } else {
        if (this.exportAll && this.customData == false) {
          let list = [];
          const params = JSON.parse(JSON.stringify(this.query));
          params.limit = 1000000;
          params.page = 1;
          params.count = false;
          const rep = await this.$apollo.query({
            query: this.service[`Get${this.name}s`],
            client: this.client,
            variables: {
              query: Object.assign(params, this.where)
            }
          });
          const target = rep.data;
          if (this.client == "iot-admin") {
            if (this.isPage) {
              list = this.transData(
                target[`admin_${this.name.toLowerCase()}s`].data
              );
            } else {
              list = target[`admin_${this.name.toLowerCase()}s`];
            }
          } else {
            if (this.isPage) {
              list = this.transData(target[`${this.name.toLowerCase()}s`].data);
            } else {
              list = this.transData(target[`${this.name.toLowerCase()}s`]);
            }
          }
          this.exportExcel(this.columns, list);
          // this.$refs.table.exportCsv({
          //   filename: "export",
          //   original: false,
          //   data: list,
          //   columns: this.columns
          // });
        } else {
          this.exportExcel(this.columns, this.data);

          // this.$refs.table.exportCsv({
          //   filename: "export",
          //   original: false
          // });
        }
      }
    },
    exportExcel(columns, list) {
      const datas = [[], []];
      columns.forEach(col => {
        let obj = {};
        if (col.children) {
          obj.rowspan = 1;
          obj.colspan = col.children.length;
          obj.title = col.title;
          datas[0].push(obj);
          col.children.forEach(o => {
            obj = {};
            obj.rowspan = 1;
            obj.colspan = 1;
            obj.title = o.title;
            datas[1].push(obj);
          });
        } else {
          obj.rowspan = 2;
          obj.colspan = 1;
          obj.title = col.title;
          datas[0].push(obj);
        }
      });

      list.forEach((col, index) => {
        let row = [];
        columns.forEach(obj2 => {
          if (obj2.children) {
            obj2.children.forEach(o => {
              let obj = [];
              obj.rowspan = 1;
              obj.colspan = 1;
              obj.title = col[o.key] === null ? "" : col[o.key];
              row.push(obj);
            });
          } else {
            let obj = [];
            obj.rowspan = 1;
            obj.colspan = 1;
            obj.title = col[obj2.key] === null ? "" : col[obj2.key];
            row.push(obj);
          }
        });
        datas[index + 2] = row;
      });

      excel({
        data: datas,
        filename: this.title + new Date().Format("yyyyMMddhhmmss"),
        autoWidth: false,
        sheetName: this.title,
        bookType: "xlsx"
      });
    },
    onDataExport(name) {
      this.exportAll = name == "all";
      this.onExport();
    },
    onShowColumn() {
      this.showColumn = true;
    },
    modalTitle() {
      if (this.action == "add") {
        return "新增" + this.title;
      } else {
        return "编辑" + this.title;
      }
    },
    onRowClick(row, index) {
      this.$emit("on-row-click", row, index);
    },
    onRowDblClick(row) {
      if (this.canEdit) {
        this.onEdit(row);
      }
      this.$emit("on-row-dblclick", row);
    },

    onSubmit() {
      if (!this.customForm) {
        this.$refs.form.validate(valid => {
          if (valid) {
            this.formLoading = true;
            let params = JSON.parse(JSON.stringify(this.form));
            for (const key in params) {
              if (this.dateFields.indexOf(key) > -1) {
                if (
                  typeof this.form[key] == "object" &&
                  this.form[key] != null
                ) {
                  params[key] = Date.parse(this.form[key]) / 1000 + "";
                } else if (this.form[key] === "") {
                  params[key] = null;
                }
              }
            }
            if (this.transform) {
              params = this.transform(params);
            }
            if (this.action == "add") {
              this.$apollo
                .mutate({
                  mutation: this.service[`${this.name}Create`],
                  client: this.client,
                  variables: {
                    form: params
                  }
                })
                .then(({ data }) => {
                  this.formLoading = false;
                  this.dialog = false;
                  this.$Message.success("新增成功！");
                  this.$emit("on-success", "add", data);
                  this.onRefresh(this.query.page);
                })
                .catch(() => {
                  this.formLoading = false;
                });
            } else {
              delete params.id;
              this.$apollo
                .mutate({
                  mutation: this.service[`${this.name}Update`],
                  client: this.client,
                  variables: {
                    form: params,
                    id: this.form.id
                  }
                })
                .then(() => {
                  this.formLoading = false;
                  this.dialog = false;
                  this.$Message.success("编辑成功！");
                  this.onRefresh(this.query.page);
                  this.$emit("on-success", "edit", this.form);
                })
                .catch(() => {
                  this.formLoading = false;
                });
            }
          }
        });
      }
    },
    onCancel() {
      this.dialog = false;
    },
    initColumns() {
      let local = $ls.get(this.colKey || this.name);
      if (local == undefined && this.defaultFields.length > 0) {
        local = this.defaultFields;
        // $ls.set(this.name, local);
      }
      if (local) {
        this.localColumns = this.columns.filter(column => {
          if (!column.key) {
            return true;
          } else {
            return local.indexOf(column.key) > -1;
          }
        });
      } else {
        this.localColumns = this.columns;
      }
    },
    onSelectColumns(columns) {
      this.localColumns = columns;
    },
    onPageChange(page, count = false) {
      this.query.count = count;
      this.query.page = page;
      this.$emit("on-page-change", page);
      this.getData(false, true, () => (this.query.count = true));
    },
    onSizeChange(size) {
      this.query.limit = size;
      this.$emit("on-size-change", size);
      this.onPageChange(1, true);
    },
    onFilter(filters) {
      this.query = {
        page: 1,
        limit: this.query.limit,
        count: true
      };
      if (this.isPage) {
        this.$refs.page.reset();
      }
      if (filters.length > 0) {
        filters.forEach(filter => {
          const target = this.filters.find(f => f.field == filter.field);
          if (target.type == "date") {
            if (filter.value.length > 0) {
              this.query[`s${target.field || "time"}`] =
                Date.parse(filter.value[0]) / 1000;
              this.query[`e${target.field || "time"}`] =
                Date.parse(filter.value[1]) / 1000;
            }
          } else {
            this.query[filter.field] = filter.value;
          }
        });
      }
      this.getData();
    },
    onSortChange(params) {
      this.$emit("on-sort-change", params);
    },
    pageReset() {
      this.$refs.page.reset();
    }
  },
  mounted() {
    let self = this;
    this.$nextTick(function() {
      document.addEventListener("keyup", function(e) {
        //此处填写你的业务逻辑即可
        if (e.keyCode == 27) {
          self.dialog = false;
          self.$emit("on-esc");
        }
      });
    });

    this.initColumns();
    if (this.service && this.name) {
      if (this.tableData.length == 0 && this.customData == false) {
        this.getData();
      }
    } else {
      this.$Message.warning("没有配置服务或者名称！");
    }
  }
};
</script>

<style lang="less">
.f-tpl {
  height: 100%;

  &__header {
    display: flex;
  }
  .f-tpl__hb {
    padding: 5px 8px;
  }
  &__filter {
    flex: 1;
  }
}
</style>
