<template>
  <div class="flow-chart-box">
    <div class="flow-chart-list">
      <div class="flow-chart-item">
        <div style="background-color: #43cf7c" class="flow-chart-item-color"></div>
        <span>已完成</span>
      </div>
      <div class="flow-chart-item">
        <div style="background-color: #2a82e4" class="flow-chart-item-color"></div>
        <span>进行中</span>
      </div>
      <div class="flow-chart-item">
        <div style="background-color: #a6a6a6" class="flow-chart-item-color"></div>
        <span>未进行</span>
      </div>
      <div class="flow-chart-item">
        <div style="background-color: #d43030" class="flow-chart-item-color"></div>
        <span>已拒绝</span>
      </div>

      <div style="flex: 1">
        <div style="display: flex; flex-direction: row-reverse">
          <div style="padding-right: 10px">
            <div style="float: left; padding-right: 20px; font-size: 16px;">
              <exclamation-circle-outlined style="padding-right: 5px" />
              <span>按住 空格 + 鼠标左键 可拖动画布</span>
            </div>
            <a-button size="small" @click="refresh">
              <template #icon>
                <redo-outlined />
              </template>
            </a-button>
          </div>
        </div>
      </div>
    </div>

    <div class="workflow-graph-panel">
      <a-spin :spinning="modelLoading" :delay="100">
        <div class="workflow-graph-panel-tool">
          <div class="workflow-graph-panel-tool-btn" @click="reduceGraph">
            <minus-outlined />
          </div>

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

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

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

        <div ref="container"></div>
      </a-spin>
    </div>
  </div>
</template>

<script setup name="FlowChart">
import { getCurrentInstance, onMounted, ref, watch, onUnmounted } from 'vue';
import { FlowDesignApi } from '../../../../design/api/FlowDesignApi';
import registerCustomVueShape from '../../../../../../flow-design/shape/custom-vue-shape';
import { WorkflowGraph } from '../../../../../../flow-design/model/workflow-graph';
import { useWorkflowStore } from '@/store/modules/workflow';
import { useEventListener } from '@vueuse/core';

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

const props = defineProps({
  // 流程定义id
  definitionId: {
    type: String
  },
  // 流程实例id
  instanceId: {
    type: String
  }
});

const { proxy } = getCurrentInstance();

// 画布dom
const container = ref(null);
// 画布
const graph = ref();

// 模型数据
const modelDetail = ref();
// 加载状态
const modelLoading = ref(false);

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

/**
 * 获取流程图Json
 */
const getGraphJson = async () => {
  modelLoading.value = true;
  await FlowDesignApi.flowDesignDetail({ definitionId: props.definitionId })
    .then(res => {
      let modelData = res.data;
      let xsixGraphJson = modelData?.xsixGraphJson?.nodeGraph;
      if (xsixGraphJson) {
        if (xsixGraphJson?.cells?.length > 0) {
          xsixGraphJson.cells = xsixGraphJson.cells.filter(item => !(item.shape === 'rect' && !item.data));
        }
        modelDetail.value = xsixGraphJson;
      }
    })
    .finally(() => {
      modelLoading.value = false;
    });
};

const getRuntimeNodeEdgeList = async () => {
  let result = {};
  await FlowDesignApi.runtimeInstanceGetRuntimeNodeEdgeList({ instanceId: props.instanceId }).then(res => {
    result = res.data;
  });
  return result;
};

/**
 * 修改cell颜色
 * @returns {Promise<void>}
 */
const updateCellColor = async () => {
  modelLoading.value = true;
  // 获取需要更改颜色的节点和线的列表对象
  let runtimeNodeEdgeListData = await getRuntimeNodeEdgeList();
  let higthLightEdgeList = runtimeNodeEdgeListData.hightLightEdgeList;
  let higthLightNodeList = runtimeNodeEdgeListData.hightLightNodeList;
  // list 转 map
  let higthLightNodeMap = {};
  higthLightNodeList.forEach(lightNode => {
    higthLightNodeMap[lightNode.nodeId] = lightNode;
  });
  let higthLightEdgeMap = {};
  higthLightEdgeList.forEach(id => {
    higthLightEdgeMap[id] = id;
  });

  // cell json
  let cells = modelDetail.value.cells;

  // 设置线和节点的颜色
  cells.forEach(cell => {
    // 设置线的颜色
    if (cell.shape === 'edge') {
      if (higthLightEdgeMap[cell.id]) {
        cell.attrs.line.stroke = '#43cf7c';
      }
      cell.attrs.line.targetMarker.name = 'path';
    } else if (cell.shape === 'custom-vue-shape') {
      // 设置节点的颜色
      let borderColor = '#C5CFD166';
      let higthLightNodeElement = higthLightNodeMap[cell.id];
      if (higthLightNodeElement) {
        if (higthLightNodeElement.nodeStatus === 30) {
          borderColor = '#43cf7c';
        } else if (higthLightNodeElement.nodeStatus === 20) {
          // 如果节点状态是 进行中
          borderColor = '#6F9AE7';
        } else if (higthLightNodeElement.nodeStatus === 10) {
          // 如果节点状态是 未进行
          borderColor = '#C5CFD166';
        } else if (higthLightNodeElement.nodeStatus === 50) {
          // 如果节点状态是 已拒绝
          borderColor = '#d43030';
        } else if (higthLightNodeElement.nodeStatus === 40) {
          // 如果节点状态是 已跳过
          borderColor = '#7948ea';
        } else if (higthLightNodeElement.nodeStatus === 60) {
          // 如果节点状态是 已退回
          borderColor = '#ffeb3b';
        }
      }
      let cellGetData = JSON.parse(cell.data);
      cellGetData.data.borderColor = borderColor;
      if (higthLightNodeElement) {
        cellGetData.data.nodeStatus = higthLightNodeElement.nodeStatus;
      }
      cell.data = JSON.stringify(cellGetData);
    }
  });

  // 加载json
  graph.value.graph.fromJSON(cells);

  useWorkflowStore().setGraph(graph.value.graph);

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

  modelLoading.value = false;
};

/**
 * 刷新按钮点击
 */
const refresh = async () => {
  await updateCellColor();
};

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

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

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

onMounted(async () => {
  await getGraphJson();

  // 初始化画布
  graph.value = new WorkflowGraph(proxy, container.value, () => {}, true);

  // 更新cell颜色
  await updateCellColor();

  // 监听快捷键
  useEventListener(document, 'wheel', e => {
    // 检查是否同时按下了 alt 键
    if (e.altKey) {
      // 判断滚轮方向
      if (e.deltaY > 0) {
        // 向下滚动 缩小画布
        reduceGraph();
      } else if (e.deltaY < 0) {
        // 向上滚动 放大画布
        amplifyGraph();
      }
    }
  });
});

onUnmounted(() => {
  // 销毁画布
  graph.value?.destroy?.();
  // 清除事件
  graph.value?.clearEventListenter?.();
});

watch(
  () => props.instanceId,
  async value => {
    if (value) {
      await getGraphJson();

      // 更新cell颜色
      await updateCellColor();
    }
  }
);

defineExpose({
  refresh
});
</script>

<style scoped lang="less">
.workflow-graph-panel {
  width: 100%;
  height: 100%;
}

.workflow-graph-panel-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;
}

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

.workflow-graph-panel-tool-btn:hover {
  background-color: #eee;
}
.flow-chart-box {
  width: 100%;
  height: 100%;
  border: 1px solid #C5CFD166;
  padding: 12px;
  box-sizing: border-box;
  border-radius: 4px;
}
.flow-chart-list {
  display: flex;
  justify-content: left;
  margin-bottom: 10px;
}
.flow-chart-item {
  font-size: 16px;
  display: flex;
  justify-content: left;
  align-items: center;
}
.flow-chart-item-color {
  border-radius: 100%;
  width: 10px;
  height: 10px;
  margin: 0 10px;
}
</style>
