<template>
  <div
    style="height:100%; position: relative; font-size: 16px;"
    v-loading="loading"
    class="d-flex align-center justify-center"
  >
    <div class="legend d-flex pa-3 justify-space-between">
      <!-- <div class="select pointerEvents">
        <v-select
          v-model="type"
          :items="items"
          dense
          outlined
          hide-details
          style="background-color: #fff; width: 150px;"
          @change="changeType"
        ></v-select>
      </div> -->
      <!-- 图例 -->
      <div class="d-flex align-center">
        <div
          v-for="item in legend"
          :key="item.title"
          class="d-flex mr-5"
        >
          <div class="pa-3 mr-3 rounded-circle" :style="`background-color: ${item.color};`"></div>
          {{ item.title }}
        </div>
        <v-switch
          v-if="!meta"
          class="pointerEvents mt-0 ml-3"
          hide-details
          v-model="showMeta"
          :false-value="false"
          :true-value="true"
          label="显示元数据"
          @change="handleChangeMeta"
        ></v-switch>
      </div>
    </div>
    <MEmpty v-if="empty"></MEmpty>
    <relation-graph
      v-show="!empty"
      ref="graphRef"
      :options="graphOptions"
      :on-node-click="onNodeClick"
      :on-line-click="onLineClick"
    >
      <template #node="{node}">
        <v-tooltip left :color="node.color || 'primary'">
          <template v-slot:activator="{ on, attrs }">
            <div @contextmenu.prevent="handleContextmenu($event, node)" v-bind="attrs" v-on="on">
              <div
                :style="{ width: node.width + 'px', height: node.height + 'px' }"
                :class="{ 'node-active':  menu.activeId === +node.id }"
                class="rounded-circle"
              >
              </div>
              <div
                :style="{ 'background-color': node.color + '44', width: 20 * ((node.text || '').length) + 'px' }"
                class="node-text"
                :class="{ 'node-active':  menu.activeId === +node.id }"
              >
                {{ node.text || '' }}
              </div>
            </div>
          </template>
          <!-- 浮窗展示节点详情 -->
          <div class="d-flex">
            <ul style="color: #fff;text-align:right;">
              <template v-for="key in Object.keys(detailKeys)">
                <li v-if="node.data[key]" :key="key">{{ detailKeys[key] }} ：</li>
              </template>
            </ul>
            <ul>
              <template v-for="key in Object.keys(detailKeys)">
                <li v-if="node.data[key]" :key="key">{{ key === 'status' ? (node.data[key] ? '已启用' : '已禁用') : node.data[key] }}</li>
              </template>
            </ul>
          </div>
        </v-tooltip>
      </template>
      <template #graph-plug>
        <v-menu v-model="menu.show" attach :position-x="menu.x" :position-y="menu.y" absolute offset-y min-width="200">
          <v-list dense>
            <v-list-item v-for="(k, i) in menu.items" :key="i" @click="k.handle">
              <v-list-item-title>{{ k.title }}</v-list-item-title>
            </v-list-item>
          </v-list>
        </v-menu>
      </template>
    </relation-graph>

  </div>
</template>

<script>
import RelationGraph from 'relation-graph'
import MEmpty from '@/components/Common/empty'
import { api } from '@/api/dataGovernance'
const defaultNodeColor = 'rgba(238, 178, 94, 1)'
const NODES_SIZE = {
  width: 30,
  height: 30
}
// const LINE_COLOR_MAP = {
//   包含: '#F44336', // red
//   影响: '#E91E63', // pink
//   依赖: '#3F51B5', // indigo
//   来源: '#4CAF50', // green
//   引用: '#9C27B0', // purple
//   继承: '#673AB7', // deep-purple
//   标记: '#2196F3', // blue
//   使用: '#03A9F4', // light-blue
//   关联: '#00BCD4', // cyan
//   拥有: '#009688', // teal
//   下级: '#8BC34A', // light-green
//   上级: '#CDDC39', // lime
//   联动: '#FF9800' // orange
// }
export default {
  name: 'details-graph',
  components: { RelationGraph, MEmpty },
  props: {
    toApi: {
      type: Function,
      default: api.getResourceGraph
    },
    meta: {
      type: Boolean,
      default: false
    },
    query: {
      type: Object,
      default: () => ({})
    }
  },
  data () {
    return {
      menu: {
        x: 0,
        y: 0,
        show: false,
        items: [
          { title: '查看', handle: this.handleView }
        ],
        activeId: +this.$route.params.id,
        item: {}
      },
      empty: true,
      items: [
        { text: '全链关系', value: 'all' },
        { text: '血缘关系', value: 'kinship' },
        { text: '影响关系', value: 'impact' }
      ],
      type: 'all',
      loading: false,
      graphOptions: {
        // defaultJunctionPoint: 'lr',
        // 这里可以参考"Graph 图谱"中的参数进行设置 https://www.relation-graph.com/#/docs/graph
        debug: false, // 是否开始调试模式，调试模式下会在控制台打印额外的日志信息
        showDebugPanel: false, // 是否显示调试按钮，通过此按钮可以打印配置、数据等
        backgroundImage: '', // 图谱水印url,如：https://ssl.relation-graph.com/images/relatioon-graph-canvas-bg.png
        downloadImageFileName: '', // 下载图片时，图片的名称
        disableZoom: false, // 是否禁用图谱的缩放功能
        disableDragNode: false, // 是否禁用图谱中节点的拖动
        moveToCenterWhenRefresh: true, // 当图谱刷新后（调用setJsonData或refresh方法都会触发），让图谱根据节点居中（图片会默认将根节点作为中心展示，此选项会根据节点分布寻找中心）
        zoomToFitWhenRefresh: true, // 当图谱刷新后（调用setJsonData或refresh方法都会触发），是否让图谱缩放到适合可见区域大小，此选项不适用于fixed和force布局
        useAnimationWhenRefresh: true, // 当图谱刷新后（调用setJsonData或refresh方法都会触发），使用动画让图居中、缩放
        useAnimationWhenExpanded: true,
        defaultFocusRootNode: true, // 默认为根节点添加一个被选中的样式
        disableNodeClickEffect: false, // 是否禁用节点默认的点击效果（选中、闪烁）
        disableLineClickEffect: false, // 是否禁用线条默认的点击效果（选中、闪烁）
        allowShowZoomMenu: true, // 是否在右侧菜单栏显示放大缩小的按钮，此设置和disableZoom不冲突
        allowAutoLayoutIfSupport: true, // 是否在工具栏中显示【自动布局】按钮（只有在布局支持且此选项为true时才会显示的按钮）
        allowShowRefreshButton: true, // 是否在工具栏中显示【刷新】按钮
        allowShowDownloadButton: true, // 是否在工具栏中显示【下载图片】按钮
        backgroundImageNoRepeat: false, // 只在右下角显示水印，不重复显示水印
        allowSwitchLineShape: true, // 是否在工具栏中显示切换线条形状的按钮
        allowSwitchJunctionPoint: true, // 是否在工具栏中显示切换连接点位置的按钮
        isMoveByParentNode: false, // 是否在拖动节点后让子节点跟随
        defaultExpandHolderPosition: 'hide', // 默认的节点展开/关闭按钮位置（left/top/right/bottom/hide）
        defaultNodeColor, // 默认的节点背景颜色
        checkedLineColor: '#FD8B37', // 当线条被选中时的颜色
        defaultNodeFontColor: '#ffffff', // 默认的节点文字颜色
        defaultNodeBorderColor: '#90EE90', // 默认的节点边框颜色
        defaultNodeBorderWidth: 0, // 默认的节点边框粗细（像素）
        defaultLineColor: '#cccccc', // 默认的线条颜色
        defaultLineWidth: 2, // 默认的线条粗细（像素）
        defaultLineShape: 2, // 默认的线条样式（1:直线/2:样式2/3:样式3/4:折线/5:样式5/6:样式6）使用示例
        defaultNodeShape: 0, // 默认的节点形状，0:圆形；1:矩形
        defaultShowLineLabel: true, // 默认是否显示连线文字，v2版本此选项已无效，主要是这个选项没什么用
        hideNodeContentByZoom: true, // 是否根据缩放比例隐藏节点内容
        // disableDragCanvas: false,
        // lineUseTextPath: false,
        defaultLineMarker: { // 默认的线条箭头样式，示例参考：配置工具中的选项：连线箭头样式
          markerWidth: 24,
          markerHeight: 24,
          refX: 6,
          refY: 6,
          data: 'M2,2 L10,6 L2,10 L6,6 L2,2'
        },
        layouts: [
          {
            label: '自动布局',
            layoutName: 'center', // 布局方式（tree树状布局/center中心布局/force自动布局）
            from: 'left',
            maxLayoutTimes: 20,
            layoutClassName: 'seeks-layout-force',
            useLayoutStyleOptions: false,
            defaultNodeColor: '#FFC5A6',
            defaultNodeFontColor: '#000000',
            defaultNodeBorderColor: '#efefef',
            defaultNodeBorderWidth: 1,
            defaultLineColor: '#FD8B37',
            defaultLineWidth: 1,
            defaultShowLineLabel: true,
            defaultLineMarker: {
              markerWidth: 12,
              markerHeight: 12,
              refX: 6,
              refY: 6,
              data: 'M2,2 L10,6 L2,10 L6,6 L2,2'
            }
          }
        ]
      },
      config: {
        BusinessDomain: {
          color: '#9FA8DA',
          title: '业务域',
          className: 'sourceNode',
          ...NODES_SIZE
        },
        DataSource: {
          color: '#4CAF50',
          title: '数据源',
          className: 'modelNode',
          ...NODES_SIZE
        },
        // DataResource: { // 资源
        //   color: '#9FA8DA',
        //   title: '数据资源',
        //   className: 'sourceNode',
        //   ...NODES_SIZE
        // },
        // DataModel: { // 模型
        //   color: '#EF9A9A',
        //   title: '数据模型',
        //   className: 'modelNode',
        //   ...NODES_SIZE
        // },
        // DataMetric: { // 指标
        //   color: '#00BCD4',
        //   title: '数据指标',
        //   className: 'metricNode',
        //   ...NODES_SIZE
        // },
        DataFlow: {
          color: '#FF9800',
          title: '数据流程',
          className: 'dataFlowNode',
          ...NODES_SIZE
        },
        data_standard: { // 标准
          color: '#009688',
          title: '数据标准',
          className: 'standardNode',
          ...NODES_SIZE
        },
        DataLabel: { // 标签
          color: '#9C27B0',
          title: '数据标签',
          className: 'labelNode',
          ...NODES_SIZE
        },
        DataMeta: { // 元数据
          color: defaultNodeColor,
          title: '元数据',
          className: '',
          ...NODES_SIZE
        }
      },
      showMeta: this.meta,
      // 节点详情
      detailKeys: {
        name_zh: '中文名称',
        name_en: '英文名称',
        category: '分类',
        organization: '所属机构',
        frequency: '更新频率',
        data_sensitivity: '数据敏感度',
        data_source: '使用数据源',
        storage_location: '存储位置',
        type: '数据库类型',
        host: '数据库IP地址',
        port: '数据库IP端口',
        database: '数据库名称',
        username: '用户名',
        password: '密码',
        param: '参数',
        leader: '负责人',
        status: '状态',
        create_time: '创建时间',
        update_time: '更新时间',
        describe: '描述/备注',
        desc: '描述/备注'
      }
    }
  },
  computed: {
    legend () {
      return Object.values(this.config)
    }
  },
  mounted () {
    this.init()
  },
  methods: {
    handleContextmenu (v, node) {
      const { left, top } = this.$refs.graphRef.$el.getBoundingClientRect()
      this.menu.x = v.clientX - left
      this.menu.y = v.clientY - top
      this.menu.item = node
      this.menu.show = true
    },
    handleView () {
      this.draw({ id: +this.menu.item.id }, () => {
        this.menu.activeId = +this.menu.item.id
      })
    },
    handleChangeMeta (val) {
      this.showMeta = val
      this.init()
    },
    changeType () {
      this.init()
    },
    handleClick (node) {
      console.log(node)
    },
    async init () {
      const query = {
        ...this.query
      }
      if (this.$route.params.id) {
        Object.assign(query, {
          id: +this.$route.params.id
        })
      }
      this.draw(query)
    },
    async draw (query, successCallback = () => {}) {
      // 清空再渲染
      this.loading = true
      this.empty = false
      try {
        const { data } = await this.toApi({
          ...query,
          type: this.type,
          meta: this.showMeta
        })
        if (!data.nodes || !data.nodes.length) {
          this.empty = true
          this.loading = false
          return
        }
        this.graphOptions.downloadImageFileName = data.rootId ?? ''

        data.nodes.forEach(ele => {
          if (!this.config[ele.node_type]) {
            return
          }
          ele.text = ele.name_zh || ele.name_en
          ele.data = { ...ele }
          Object.assign(ele, this.config[ele.node_type])
        })

        // data.lines.forEach(ele => {
        //   ele.color = LINE_COLOR_MAP[ele.text]
        // })
        this.$nextTick(() => {
          this.$refs.graphRef.setOptions(this.graphOptions, async (graphInstance) => {
            if (!this.$refs.graphRef || !this.$refs.graphRef.setJsonData) {
              return
            }
            this.$refs.graphRef.setJsonData(data, async (_graphInstance) => {
              await _graphInstance.setZoom(75)
              successCallback()
              this.loading = false
            })
          })
        })
      } catch (error) {
        this.empty = true
        this.$snackbar.error(error)
      }
    },
    onNodeClick (nodeObject, $event) {
      console.log('onNodeClick:', nodeObject)
    },
    onLineClick (lineObject, $event) {
      console.log('onLineClick:', lineObject)
    }
  }
}
</script>

<style lang="scss" scoped>
ul{
  list-style: none;
}
.legend {
  pointer-events: none;
  width: 100%;
  user-select: none;
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  position: absolute;
  top: 0;
  z-index: 10;
  color: #666;
  .rounded-circle {
    width: 24px;
    height: 24px;
  }
}
.pointerEvents {
  pointer-events: auto;
}
// ::v-deep .sourceNode .rel-node-checked {
//   box-shadow: 0 0 0 8px #C5CAE9 !important;
// }
// ::v-deep .modelNode .rel-node-checked {
//   box-shadow: 0 0 0 8px #ffd9d9 !important;
// }
// ::v-deep .metricNode .rel-node-checked {
//   box-shadow: 0 0 0 8px #a7f3fd !important;
// }
// ::v-deep .standardNode .rel-node-checked {
//   box-shadow: 0 0 0 8px #58c1b7 !important;
// }
// ::v-deep .labelNode .rel-node-checked {
//   box-shadow: 0 0 0 8px #f4bdff !important;
// }
::v-deep .rel-node-checked {
  box-shadow: unset !important;
}
.node-active {
  box-shadow: 0 0 0px 6px #f3f900 !important;
  // background: #000 !important;
  // border: 2px solid #000;
}
.node-text {
  color: #000;
  font-size: 16px;
  position: absolute;
  height:25px;
  transform: translate(-50%, 0);
  line-height: 25px;
  left: 50%;
  margin-top:5px;
  text-align: center;
}

::v-deep .rel-toolbar {
  background-color: #f39930;
  color: #ffffff;
  .c-current-zoom {
    color: #ffffff;
  }
}
</style>
