<template>
  <div class="guns-workflow-editor">
    <!--画布缩放工具-->
    <div class="guns-workflow-editor-tool isSelected">
      <div class="guns-workflow-editor-tool-btn" @click="reduceGraph">
        <minus-outlined />
      </div>

      <div class="guns-workflow-editor-tool-zoom">
        <span>{{ zoomPercentage }}%</span>
      </div>

      <div class="guns-workflow-editor-tool-btn" @click="amplifyGraph">
        <plus-outlined />
      </div>

      <div class="guns-workflow-editor-tool-btn" @click="redoGraph">
        <redo-outlined />
      </div>
    </div>

    <template v-if="graph">
      <workflow-node-config-panel v-if="selectedNodeId" :node-id="selectedNodeId" @closed="handleNodeConfigPanelClosed">
      </workflow-node-config-panel>

      <!--节点编辑弹窗-->
      <node-title-edit
        v-if="showNodeTitleEdit"
        :node-title-node-id-obj="nodeTitleNodeIdObj"
        v-model:visible="showNodeTitleEdit"
        @done="editNodeTitle"
      >
      </node-title-edit>
    </template>

    <a-layout style="overflow: hidden">
      <a-layout-sider class="guns-workflow-editor-left" width="240px">
        <workflow-node-panel v-if="graph" :showBusinessGraph="showBusinessGraph"></workflow-node-panel>
      </a-layout-sider>
      <a-layout-content style="position: relative">
        <a-tabs v-model:activeKey="tabsActiveKey" class="guns-workflow-tab">
          <a-tab-pane key="1" tab="">
            <workflow-graph-panel
              @node-selected="nodeId => handleNodeSelected(nodeId)"
              @node-added="handleNodeAdded"
              @graph-created="handleGraphCreated"
              :backUrl="backUrl"
            >
            </workflow-graph-panel>
          </a-tab-pane>
        </a-tabs>

        <!-- 右侧帮助栏 -->
        <FlowHelper v-if="!readable" />

        <!-- bpmn线 -->
        <BpmnLine v-if="!readable && SHOW_NEW_FLOW_DESIGN" />
      </a-layout-content>
    </a-layout>

    <!--bpmn节点编辑弹窗-->
    <bpmn-node-edit v-if="showBpmnNodeEdit" :bpmn-node-data="bpmnNodeData" v-model:visible="showBpmnNodeEdit"> </bpmn-node-edit>
  </div>
</template>

<script>
import { defineComponent, onMounted, onUnmounted, provide, ref, watch } from 'vue';
import WorkflowNodePanel from './layout/left/node_panel.vue';
import WorkflowGraphPanel from './layout/main/graph_panel.vue';
import WorkflowNodeConfigPanel from './layout/right/node-config-panel.vue';
import registerCustomVueShape from './shape/custom-vue-shape';
import { useWorkflowStore } from '@/store/modules/workflow';
import NodeTitleEdit from './layout/right/node-title-edit.vue';
import { useEventListener } from '@vueuse/core';
import FlowHelper from './panel/FlowHelper.vue';
import BpmnNodeEdit from './layout/right/bpmn-node-edit.vue';
import FlowView from '../mid/workflow/task/start/components/flow-view.vue';
import { SHOW_NEW_FLOW_DESIGN } from '@/config/setting';
import BpmnLine from './panel/BpmnLine.vue';

// 注册自定义x6元素
registerCustomVueShape();

export default defineComponent({
  name: 'WorkflowEditor',
  components: {
    FlowView,
    BpmnLine,
    FlowHelper,
    NodeTitleEdit,
    BpmnNodeEdit,
    WorkflowNodePanel,
    WorkflowGraphPanel,
    WorkflowNodeConfigPanel
  },
  props: {
    // 模型json数据
    modelValue: {
      type: Object
    },
    // 是否显示业务图
    showBusinessGraph: {
      type: Boolean,
      default: false
    },
    // 是否只读
    readable: {
      type: Boolean,
      default: false
    },
    // 返回路径
    backUrl: {
      type: String,
      default: ''
    }
  },
  emits: ['node-added'],
  mounted() {
    // 监听快捷键
    useEventListener(document, 'wheel', e => {
      // 检查是否同时按下了 alt 键
      if (e.altKey) {
        // 判断滚轮方向
        if (e.deltaY > 0) {
          // 向下滚动 缩小画布
          this.reduceGraph();
        } else if (e.deltaY < 0) {
          // 向上滚动 放大画布
          this.amplifyGraph();
        }
      }
    });
  },
  setup(props, { emit }) {
    // 节点配置面是否显示
    const nodeConfigPanelVisible = ref(false);
    const tabsActiveKey = ref('1');
    // 选中的节点id
    const selectedNodeId = ref('');
    const graph = ref(null);
    provide('getGraph', graph);

    // 是否显示节点标题编辑弹窗
    const showNodeTitleEdit = ref(false);
    // 选中的节点标题
    const nodeTitleNodeIdObj = ref({
      nodeId: '',
      nodeName: ''
    });

    // bpmn选中的节点数据
    const bpmnNodeData = ref({});

    // 是否显示bpmn节点编辑抽屉
    const showBpmnNodeEdit = ref(false);

    // 缩放百分比
    const zoomPercentage = ref(100);

    onMounted(() => {
      window.addEventListener('resize', () => {
        resizeGraph();
      });
    });

    onUnmounted(() => {
      window.removeEventListener('resize', () => {
        resizeGraph();
      });
    });

    /**
     * 修改节点标题
     * @param obj
     */
    const editNodeTitle = obj => {
      let getGraphNode = graph.value.getNodes().find(({ id }) => obj.nodeId === id);
      let getGraphNodeData = JSON.parse(getGraphNode.getData());
      getGraphNodeData.data.nodeName = obj.nodeName;

      getGraphNode.setData(JSON.stringify(getGraphNodeData), {
        // 必须覆盖，否则出错
        overwrite: true
      });
    };

    /**
     * 画布创建后处理器
     * @param g
     */
    const handleGraphCreated = g => {
      graph.value = g;

      useWorkflowStore().setGraph(g);

      // 画布json
      const graphJson = props.modelValue;
      if (graphJson) {
        graph.value.fromJSON(graphJson.cells);

        // 将画布中元素缩小或者放大一定级别，让画布正好容纳所有元素，可以通过 maxScale 配置最大缩放级别
        graph.value.zoomToFit({ maxScale: 1 });
        // 将画布中元素居中展示
        graph.value.centerContent();
      }
    };

    /**
     * 节点选中
     * @param nodeId
     */
    const handleNodeSelected = nodeId => {
      let cell = graph.value.getCellById(nodeId);
      let cellData = JSON.parse(cell.data);
      // 基础流程
      if (cellData.type == 248 || cellData.type < 99) {
        // 如果点击的节点数据有属性配置则显示配置弹窗
        if (cellData.ref) {
          // 显示节点配置面板
          nodeConfigPanelVisible.value = true;
          // 赋值选中的节点id
          selectedNodeId.value = nodeId;
        } else {
          nodeTitleNodeIdObj.value.nodeId = nodeId;
          nodeTitleNodeIdObj.value.nodeName = cellData.data.nodeName;
          // 否则弹出节点标题编辑弹窗
          showNodeTitleEdit.value = true;
        }
      } else {
        // bpmn
        bpmnNodeData.value = cellData;
        showBpmnNodeEdit.value = true;
      }
    };

    /**
     * 节点配置面板关闭处理器
     * @param valid
     */
    const handleNodeConfigPanelClosed = valid => {
      // const selectedNode = graph.value.getCellById(selectedNodeId.value);
      if (valid) {
        // workflowValidator.removeWarning(selectedNode);
      } else {
        // workflowValidator.addWarning(selectedNode, nodeId => {
        //   handleNodeSelected(nodeId, true);
        // });
      }
      graph.value.unselect(selectedNodeId.value);
      selectedNodeId.value = '';
      nodeConfigPanelVisible.value = false;
    };

    /**
     * 处理节点添加至面板
     */
    const handleNodeAdded = node => {
      emit('node-added', node);
    };

    /**
     * 放大图表
     */
    const amplifyGraph = () => {
      if (graph.value) {
        if (zoomPercentage.value < 200) {
          zoomPercentage.value = zoomPercentage.value + 10;
          graph.value.zoom(0.1);
          graph.value.centerContent();
        }
      }
    };

    /**
     * 缩小图表
     */
    const reduceGraph = () => {
      if (graph.value) {
        if (zoomPercentage.value > 10) {
          zoomPercentage.value = zoomPercentage.value - 10;
          graph.value.zoom(-0.1);
          graph.value.centerContent();
        }
      }
    };

    /**
     * 还原图表
     */
    const redoGraph = () => {
      if (graph.value) {
        zoomPercentage.value = 100;
        graph.value.zoomTo(1);
        // 将画布中元素缩小或者放大一定级别，让画布正好容纳所有元素，可以通过 maxScale 配置最大缩放级别
        graph.value.zoomToFit({ maxScale: 1 });
        // 将画布中元素居中展示
        graph.value.centerContent();
      }
    };

    // 监听屏幕缩放，刷新画布
    const resizeGraph = () => {
      if (graph.value) {
        graph.value.zoomTo(zoomPercentage.value / 100);
        graph.value.centerContent();
      }
    };

    watch(
      () => props.modelValue,
      val => {
        if (val) {
          // 画布json
          const graphJson = props.modelValue;
          if (graphJson) {
            graph.value.fromJSON(graphJson.cells);
            // 将画布中元素缩小或者放大一定级别，让画布正好容纳所有元素，可以通过 maxScale 配置最大缩放级别
            graph.value.zoomToFit({ maxScale: 1 });
            // 将画布中元素居中展示
            graph.value.centerContent();
          }
        }
      }
    );

    return {
      handleNodeAdded,
      handleGraphCreated,
      graph,
      resizeGraph,
      handleNodeSelected,
      selectedNodeId,
      bpmnNodeData,
      showBpmnNodeEdit,
      handleNodeConfigPanelClosed,
      nodeConfigPanelVisible,
      showNodeTitleEdit,
      nodeTitleNodeIdObj,
      editNodeTitle,
      amplifyGraph,
      reduceGraph,
      redoGraph,
      tabsActiveKey,
      zoomPercentage,
      SHOW_NEW_FLOW_DESIGN
    };
  }
});
</script>

<style scoped lang="less">
.guns-workflow-editor {
  display: flex;
  width: 100%;
  height: 100%;
}

.guns-workflow-editor-tool {
  background-color: rgb(255, 255, 255, 0.5);
  position: absolute;
  z-index: 1;
  right: 16px;
  width: auto;
  height: auto;
  margin-top: 12px;
  display: flex;
  border: 1px solid #eee;
  border-radius: 5px;
  box-shadow: 0 0 4px #ccc;
}

.guns-workflow-editor-tool-btn,
.guns-workflow-editor-tool-zoom {
  cursor: pointer;
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.guns-workflow-editor-tool-btn:hover {
  background-color: #eee;
}

.guns-workflow-editor-left {
  display: flex;
  background-color: #fff;
  border-right: 1px #d9d9d9 solid;
  overflow-x: hidden;
  overflow-y: auto;
  &::-webkit-scrollbar {
    width: 0px !important;
  }
}
:deep(.ant-tabs) {
  width: 100%;
  height: 100%;
}
:deep(.ant-tabs-content) {
  width: 100%;
  height: 100%;
}
:deep(.ant-tabs-content-holder) {
  overflow: hidden;
  width: 100%;
  height: 100%;
}
.guns-workflow-tab {
  :deep(.ant-tabs-nav) {
    display: none;
  }
}
:deep(.ant-layout-sider-children) {
  width: 100%;
}
</style>
