<template>
  <div class="h-100">
    <app-tree
      ref="appTree"
      :actions="getActions"
      :data="treeData"
      :def-expanded-keys="defExpandedKeys"
      :expand-all="expandAll"
      :lazy="lazyTree"
      :load-node="loadNode"
      :node-click="onNodeClick"
      :node-key="props.value || 'id'"
      :props="defaultProps"
      :reload="lazyTree ? searchReload : null"
      :title="title"
      :hideTopbar="hideTopbar"
      @node-action-click="onNodeActionClick"
      @node-expand="onNodeExpand"
      @node-collapse="onNodeCollapse"
      @node-dblclick="onNodeDBClick"
    />
    <slot name="custom">
      <app-dialog v-model="dialogVisible" :loading="dialogLoading" :title="dialogTitle" append-to-body :width="dialogWidth" @confirm="onDialogConfirm">
        <el-form ref="dialogForm" :model="dialogForm" class="w-70" :style="`width:${formWidth}`" :rules="formRules">
          <el-row :gutter="15">
            <app-filter-item
              v-for="field in fields"
              :key="field.prop"
              :label="field.label"
              :label-width="field.labelWidth || '100px'"
              :prop="field.prop"
              :rules="field.rules"
              :span="field.span || 24"
            >
              <el-switch v-if="field.type === 'switch'" v-model="dialogForm[field.prop]" />
              <el-input-number
                v-else-if="field.type === 'number'"
                v-model="dialogForm[field.prop]"
                :label="`请输入${field.label}`"
                :max="field.max"
                :min="field.min"
              />
              <el-select v-else-if="field.type === 'select' || field.options" v-model="dialogForm[field.prop]" :placeholder="`请选择${field.label}`">
                <el-option v-for="opt in field.options" :key="opt.value" :label="opt.label" :value="opt.value" />
              </el-select>

              <el-input v-else v-model.trim="dialogForm[field.prop]" :placeholder="`请输入${field.label}`" @input="formatInput($event, field)" />
            </app-filter-item>
            <slot :form="dialogForm" name="form" />
          </el-row>
        </el-form>
      </app-dialog>
    </slot>
  </div>
</template>

<script>
export default {
  props: {
    // 弹窗宽度
    dialogWidth: {
      type: String,
      default: '480px',
    },
    // 表单宽度
    formWidth: {
      type: String,
      default: '',
    },
    // 表单验证规则
    formRules: {
      type: Object,
      default: null,
    },
    // 标题
    title: {
      type: String,
      default: '',
    },
    // 是否懒加载
    lazy: {
      type: Boolean,
      default: false,
    },
    // 默认根节点
    rootNode: {
      type: Object,
      default: null,
    },
    // 默认展开节点集合
    defaultExpandedKeys: {
      type: Array,
      default: null,
    },
    // 请求函数
    requestMethod: {
      type: Function,
      default: null,
    },
    // el tree porps
    props: {
      type: Object,
      default: null,
    },
    actions: {
      type: [Array, Function],
      default: null,
    },
    // 树形数据（不传requestMethod情况下使用）
    treeOptions: {
      type: Array,
      default: () => [],
    },
    fields: {
      type: Array,
      default: () => [],
    },
    defFields: {
      type: [Array, Function],
      default: () => [],
    },
    defaultData: {
      type: Object,
      default: () => ({}),
    },
    reload: {
      type: Function,
      default: null,
    },
    hideTopbar: {
      type: Boolean,
      default: false,
    },
    /**
     * @description: 异步默认false
     */
    expandAll: {
      type: Boolean,
      default: false,
    },
    /**
     * @description: 是否自定义处理节点弹层事件
     */
    customActions: {
      type: Boolean,
      default: false,
    },
    /**
     * @description: 双击展开节点
     */
    dbClickExpandAllow: {
      type: Boolean,
      default: false,
    },
    edit: {
      type: Boolean,
      default: true,
    },
    /**
     * @description: 高亮第一个节点
     */
    highlightFirst: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      defExpandedKeys: this.defaultExpandedKeys || [],
      // tree
      treeData: [],
      // dialog
      dialogVisible: false,
      dialogTitle: '',
      dialogLoading: false,
      dialogForm: {},
      defaultProps: {
        value: 'id',
        label: 'label',
        ...this.props,
      },
      lazyTree: this.lazy,
      curNode: null,
    };
  },
  watch: {
    lazy(val) {
      this.lazyTree = val;
    },
    defaultExpandedKeys(arr) {
      if (arr && Array.isArray(arr)) {
        this.defExpandedKeys = arr;
      }
    },
    treeOptions(tree_data) {
      if (tree_data?.length) {
        this.handleTreeData(tree_data);
        // this.$refs.appTree.elTree.setCurrentKey(tree_data[0][this.defaultProps.value]);
        this.onNodeClick(tree_data[0]);
      }
    },
  },
  created() {
    if (!this.lazyTree && this.requestMethod) {
      this.getTreeData();
    }
  },
  methods: {
    getElTree() {
      return this.$refs.appTree.$refs.elTree;
    },
    async getTreeData() {
      if (typeof this.requestMethod === 'function') {
        const { data } = await this.requestMethod();
        this.handleTreeData(data);
      } else {
        this.treeData = this.rootNode ? [this.rootNode] : [];
      }
      if (this.treeData?.length) {
        this.onNodeClick(this.treeData[0]);
      }
      if (!this.lazyTree && this.lazy) this.lazyTree = true;
      // 高亮第一个节点
      this.$nextTick(() => {
        if (this.highlightFirst && this.treeData.length) this.$refs.appTree.$refs.elTree.setCurrentKey(this.treeData[0][this.props.value]);
      });
    },
    handleTreeData(data) {
      if (Array.isArray(data) && data.length > 0) {
        this.treeData = data;
      } else if (data?.id) {
        if (this.defExpandedKeys?.length <= 1) {
          this.defExpandedKeys = [data.id];
        }
        this.treeData = [data];
      } else {
        this.treeData = this.rootNode ? [this.rootNode] : [];
      }
    },
    // 选择树节点
    onNodeClick(data) {
      this.$emit('select', data);
    },
    handleParams() {
      const params = {
        ...this.dialogForm,
      };
      if (this.curAction.type === 'add') {
        params.parentId = this.curNode?.id;
      } else if (this.curAction.type === 'edit') {
        params.id = this.curNode?.id;
        params.parentId = this.curNode.parentId;
      }
      return params;
    },
    // 添加树节点
    onDialogConfirm() {
      this.$refs.dialogForm.validate(async (valid) => {
        if (valid) {
          try {
            this.dialogLoading = true;
            const params = this.handleParams();
            if (typeof this.curAction.method === 'function') {
              await this.curAction.method(params, this.curNode);
              this.dialogVisible = false;
              // if (this.lazy) {
              //   // 刷新父节点
              //   this.curAction.type === 'edit' && this.refreshNodes(this.curNode?.parentId);
              //   this.curAction.type === 'add' && this.refreshNodes(this.curNode?.id);
              // } else {
              //   this.requestMethod && this.getTreeData();
              // }
            }
          } finally {
            this.dialogLoading = false;
          }
        }
      });
    },
    // 节点展开记录下来
    onNodeExpand(data) {
      this.defExpandedKeys.push(data.id);
    },
    onNodeCollapse(data) {
      const index = this.defExpandedKeys.indexOf(data.id);
      if (index > -1) {
        this.defExpandedKeys.splice(index, 1);
      }
    },
    /**
     * @description:
     * @param {*} val
     * @param {*} format noSpecial
     * @return {*}
     */
    formatInput(val, { format, prop }) {
      if (format) {
        this.dialogForm[prop] = this.formatByRule(val, format);
      }
    },
    formatByRule(val, type) {
      const rules = {
        noSpecial: /[^\u4E00-\u9FA5A-Za-z0-9]/g,
      };
      if (rules[type] && val) {
        return val.replace(rules[type], '');
      }
      return val;
    },
    getActions({ data }, actions) {
      if (typeof this.actions === 'function') {
        return this.actions(data, actions);
      } else if (Array.isArray(this.actions)) {
        return this.actions;
      } else {
        return actions;
      }
    },
    addNode() {
      // orderNum: DEF_ORDER_NUM,
      this.dialogForm = { ...this.defaultData };
      this.dialogTitle = '新增节点';
      this.dialogVisible = true;
    },
    editNode(data) {
      this.dialogForm = { ...data };
      this.dialogTitle = '编辑节点';
      this.dialogVisible = true;
    },
    deleteNode(data) {
      this.$confirm(`确认删除${data[this.defaultProps.label] + (this.curAction.tips ? this.curAction.tips : '')}吗？`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(async () => {
          if (typeof this.curAction.method === 'function') {
            await this.curAction.method([data.id], data);
            if (this.lazy) {
              this.refreshNodes(this.curNode.parentId);
            } else {
              if (this.requestMethod) {
                this.getTreeData();
              } else {
                this.$refs.appTree.elTree.remove(data);
              }
            }
          }
        })
        .catch(() => {});
    },
    onNodeActionClick(e) {
      const { type, data } = e;
      this.$emit('beforeActionsClick', e);
      if (this.customActions) {
        return;
      }
      this.curNode = data;
      this.curAction = e;
      const map = {
        add: this.addNode,
        edit: this.editNode,
        delete: this.deleteNode,
      };
      map[type] && map[type](data);
    },
    refreshNodes(id = this.curNode?.id) {
      const node = this.$refs.appTree.elTree.getNode(id);
      node.loaded = false;
      node.expand();
    },
    async loadNode(node, resolve) {
      const cb = (data) => {
        return resolve(data);
      };
      this.requestMethod(node, cb);
    },
    // lazy search
    searchReload(val) {
      this.lazyTree = val?.length === 0;
      typeof this.reload === 'function' && this.reload(val);
    },
    reloadTree() {
      this.$refs.appTree.reloadTree();
      // 异步搜索查询树调用接口查询全部节点
      if (this.lazy && !this.lazyTree && this.requestMethod) {
        this.getTreeData();
      }
    },
    // 双击展开节点
    onNodeDBClick(e, scope) {
      if (this.dbClickExpandAllow) {
        this.$refs.appTree.elTree.store.nodesMap[scope.data.id].expanded = !scope.node.expanded;
      }
    },
  },
};
</script>

<style lang="scss" scoped>
::v-deep {
  .gz-dialog .app-dialog-content {
    min-height: 25vh !important;
    height: auto !important;
  }
}
</style>
