king
2023-06-01 aa8a9f0845ed197adbfdf152376121e172bee574
2023-06-01
19个文件已修改
2099 ■■■■■ 已修改文件
package-lock.json 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-G6/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-G6/index.scss 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-X6/chartcompile/formconfig.jsx 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-X6/index.jsx 1753 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-X6/index.scss 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menushell/card.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modulesource/option.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-G6/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/popview/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/homeform/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/menuform/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/popview/menuform/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/menuform/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/popview/menuform/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/menuform/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tabledesign/menuform/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -624,9 +624,9 @@
      }
    },
    "@antv/x6": {
      "version": "2.10.1",
      "resolved": "https://registry.npmjs.org/@antv/x6/-/x6-2.10.1.tgz",
      "integrity": "sha512-38Fi9Qgnp+ylTrnRnhrGsc2cxsDosULbN6toVs9GjVpOguzq3oxRUblzO6dcnJhbzXfZxIcB/IuQt3pYpXJBKA==",
      "version": "2.11.1",
      "resolved": "https://registry.npmjs.org/@antv/x6/-/x6-2.11.1.tgz",
      "integrity": "sha512-DwyuT/zuTEhwsnKwCj67cadwLeEbB5jfdCxrkTnEm6pg0+vT3FinbF71IK7SHoY8d4HOHl+sJt7ikJfr61JqLw==",
      "requires": {
        "@antv/x6-common": "^2.0.12",
        "@antv/x6-geometry": "^2.0.5",
@@ -646,6 +646,49 @@
      "version": "2.0.5",
      "resolved": "https://registry.npmjs.org/@antv/x6-geometry/-/x6-geometry-2.0.5.tgz",
      "integrity": "sha512-MId6riEQkxphBpVeTcL4ZNXL4lScyvDEPLyIafvWMcWNTGK0jgkK7N20XSzqt8ltJb0mGUso5s56mrk8ysHu2A=="
    },
    "@antv/x6-plugin-clipboard": {
      "version": "2.1.6",
      "resolved": "https://registry.npmjs.org/@antv/x6-plugin-clipboard/-/x6-plugin-clipboard-2.1.6.tgz",
      "integrity": "sha512-roZPLnZx6PK8MBvee0QMo90fz/TXeF0WNe4EGin2NBq5M1I5XTWrYvA6N2XVIiWAAI67gjQeEE8TpkL7f8QdqA=="
    },
    "@antv/x6-plugin-dnd": {
      "version": "2.0.5",
      "resolved": "https://registry.npmjs.org/@antv/x6-plugin-dnd/-/x6-plugin-dnd-2.0.5.tgz",
      "integrity": "sha512-g8GGJS2XmM8C59juOBiFqaR/f8i8y8tqw9sJNwta7s1Phh3hwDd7o4kk36Kk5eTKkfZfnjEyWHMOqp/h+EDibQ=="
    },
    "@antv/x6-plugin-history": {
      "version": "2.2.3",
      "resolved": "https://registry.npmjs.org/@antv/x6-plugin-history/-/x6-plugin-history-2.2.3.tgz",
      "integrity": "sha512-yiv5e7CQKm1HrJe7je4iWjkzDzU+I0WsyL8En2j0UwXJrUNaKYyv4BkRg2tvyi52hydxidMgi3tNnNQHEZwoMg=="
    },
    "@antv/x6-plugin-keyboard": {
      "version": "2.2.1",
      "resolved": "https://registry.npmjs.org/@antv/x6-plugin-keyboard/-/x6-plugin-keyboard-2.2.1.tgz",
      "integrity": "sha512-sqfN0h4txVO211uIeKBd3zQ/IN2zPzDThWNTEhRx7Lecg1fO7uRXWBbOA48j3EgpRFXVexdSzIEVJEx+IWUdYw==",
      "requires": {
        "mousetrap": "^1.6.5"
      }
    },
    "@antv/x6-plugin-selection": {
      "version": "2.1.7",
      "resolved": "https://registry.npmjs.org/@antv/x6-plugin-selection/-/x6-plugin-selection-2.1.7.tgz",
      "integrity": "sha512-ODfYLNwKSaLgIYMYfMW4dYQ9KKFOVBEdH0BzvyG8mfRol+JtZuyrm4BRbAvMryQKHrSxs4JCYXTFd2F7ZTuxLQ=="
    },
    "@antv/x6-plugin-snapline": {
      "version": "2.1.7",
      "resolved": "https://registry.npmjs.org/@antv/x6-plugin-snapline/-/x6-plugin-snapline-2.1.7.tgz",
      "integrity": "sha512-AsysoCb9vES0U2USNhEpYuO/W8I0aYfkhlbee5Kt4NYiMfQfZKQyqW/YjDVaS2pm38C1NKu1LdPVk/BBr4CasA=="
    },
    "@antv/x6-plugin-stencil": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/@antv/x6-plugin-stencil/-/x6-plugin-stencil-2.0.3.tgz",
      "integrity": "sha512-pQkTIbMCezTqo38fofuFGnI30Rk0j5gHc/+Ndml1RHVEV0p8i1HGRAR5we7SVTcT56AHlP46H+oRFReQmVgvKA=="
    },
    "@antv/x6-plugin-transform": {
      "version": "2.1.7",
      "resolved": "https://registry.npmjs.org/@antv/x6-plugin-transform/-/x6-plugin-transform-2.1.7.tgz",
      "integrity": "sha512-idzBr8/Bcw8zHQUSNS0Y8VSNMigCWiUuiwqO572Ac/P2tMfP6Ot2SahEYHGUOD2NEMPr95q4JMZc+Evvt4JFTw=="
    },
    "@antv/x6-react-components": {
      "version": "1.1.15",
@@ -11290,7 +11333,7 @@
    "insert-css": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/insert-css/-/insert-css-2.0.0.tgz",
      "integrity": "sha1-610Ql7dUL0x56jBg067gfQU4gPQ="
      "integrity": "sha512-xGq5ISgcUP5cvGkS2MMFLtPDBtrtQPSFfC6gA6U8wHKqfjTIMZLZNxOItQnoSjdOzlXOLU/yD32RKC4SvjNbtA=="
    },
    "internal-ip": {
      "version": "4.3.0",
package.json
@@ -8,7 +8,15 @@
    "@antv/g2": "^4.1.34",
    "@antv/g6": "^4.6.4",
    "@antv/util": "^2.0.17",
    "@antv/x6": "^2.10.1",
    "@antv/x6": "^2.11.1",
    "@antv/x6-plugin-clipboard": "^2.1.6",
    "@antv/x6-plugin-dnd": "^2.0.5",
    "@antv/x6-plugin-history": "^2.2.3",
    "@antv/x6-plugin-keyboard": "^2.2.1",
    "@antv/x6-plugin-selection": "^2.1.7",
    "@antv/x6-plugin-snapline": "^2.1.7",
    "@antv/x6-plugin-stencil": "^2.0.3",
    "@antv/x6-plugin-transform": "^2.1.7",
    "@antv/xflow": "^1.0.50",
    "@babel/core": "7.5.5",
    "@svgr/webpack": "4.3.2",
@@ -55,6 +63,7 @@
    "identity-obj-proxy": "3.0.0",
    "immutability-helper": "^3.0.1",
    "immutable": "^4.0.0-rc.12",
    "insert-css": "^2.0.0",
    "is-wsl": "^1.1.0",
    "jest": "24.8.0",
    "jest-environment-jsdom-fourteen": "0.1.0",
src/menu/components/chart/antv-G6/index.jsx
@@ -1137,7 +1137,7 @@
    const { card } = this.state
    if (card.plot.subtype === 'mindmap') {
      this.ponitrender()
      this.mindrender()
    } else if (card.plot.subtype === 'indentTree') {
      this.indentrender()
    } else if (card.plot.subtype === 'kapmap') {
@@ -1270,9 +1270,9 @@
  }
  /**
   * @description 散点图
   * @description 思维导图
   */
  ponitrender = () => {
  mindrender = () => {
    const { card } = this.state
    const plot = card.plot
    const data = this.getdata()
src/menu/components/chart/antv-G6/index.scss
@@ -42,25 +42,6 @@
    color: rgba(0, 0, 0, 0.85);
    background: rgba(255, 255, 255, 0.55);
  }
  .model-menu-action-list {
    position: absolute;
    right: 0px;
    top: 30px;
    z-index: 4;
    font-size: 16px;
    .ant-row .anticon-plus {
      float: right;
    }
    .page-card {
      float: right;
    }
  }
  .normal-header + .canvas + .model-menu-action-list {
    top: 45px;
  }
}
.menu-scatter-chart-edit-box:hover {
  z-index: 1;
src/menu/components/chart/antv-X6/chartcompile/formconfig.jsx
@@ -203,130 +203,18 @@
      type: 'select',
      field: 'subtype',
      label: '类型',
      initval: card.subtype || 'mindmap',
      initval: card.subtype || 'xflow',
      required: true,
      options: [{
        value: 'mindmap',
        label: '思维导图'
        value: 'xflow',
        label: '流程图'
      }, {
        value: 'indentTree',
        label: '缩进文件树'
        label: '泳道图'
      }, {
        value: 'kapmap',
        label: '知识图谱树'
      }],
      controlFields: [
        {field: 'dirField', values: ['mindmap']},
        {field: 'nodeColor', values: ['mindmap']},
        // {field: 'collapsed', values: ['indentTree', 'kapmap']},
      ]
    },
    {
      type: 'radio',
      field: 'rootType',
      label: '根节点取值',
      initval: card.rootType || 'fixed',
      tooltip: '选择上级时,请填写根节点的文本和值的字段名',
      required: true,
      options: [{
        value: 'fixed',
        label: '固定值'
      }, {
        value: 'supvalue',
        label: '上级组件'
      }, {
        value: 'line',
        label: '行'
      }],
      controlFields: [
        {field: 'rootLabel', values: ['fixed', 'supvalue']},
        {field: 'rootValue', values: ['fixed', 'supvalue']},
        {field: 'mark', values: ['line']},
      ]
    },
    {
      type: 'text',
      field: 'rootValue',
      label: '根节点值',
      initval: card.rootValue || '',
      required: true
    },
    {
      type: 'text',
      field: 'rootLabel',
      label: '根节点文本',
      initval: card.rootLabel || '',
      required: true
    },
    {
      type: 'select',
      field: 'valueField',
      label: '值字段',
      initval: card.valueField || '',
      required: true,
      options: columns
    },
    {
      type: 'select',
      field: 'labelField',
      label: '文本字段',
      initval: card.labelField || '',
      required: true,
      options: columns
    },
    {
      type: 'select',
      field: 'parentField',
      label: '上级字段',
      initval: card.parentField || '',
      required: true,
      options: columns
    },
    {
      type: 'text',
      field: 'mark',
      label: '顶级标识',
      initval: card.mark || '',
      tooltip: '上级字段值与顶级标识相同时,视为根节点。',
      required: true
    },
    {
      type: 'select',
      field: 'dirField',
      label: '方向控制',
      initval: card.dirField || '',
      required: false,
      options: columns,
      controlFields: [
        {field: 'dirSign', notNull: true},
        {field: 'leftColor', notNull: true},
      ]
    },
    {
      type: 'text',
      field: 'dirSign',
      label: '左向标记',
      initval: card.dirSign || '',
      tooltip: '当节点值与标记相同时节点信息位于节点左侧,多个值请用逗号分隔。',
      required: false
    },
    {
      type: 'color',
      field: 'nodeColor',
      label: '节点颜色',
      initval: card.nodeColor || '#1890ff',
      tooltip: '右侧节点的标记颜色。',
      colorType: 'hex',
      required: false
    },
    {
      type: 'color',
      field: 'leftColor',
      label: '左节点颜色',
      initval: card.leftColor || '#26C281',
      tooltip: '左侧节点的标记颜色。',
      colorType: 'hex',
      required: false
        label: '组织结构图'
      }]
    },
    {
      type: 'radio',
@@ -339,18 +227,6 @@
        {value: 'show', label: '否'},
        {value: 'hidden', label: '是'},
      ],
    },
    {
      type: 'radio',
      field: 'collapsed',
      label: '节点合并',
      initval: card.collapsed || 'false',
      tooltip: '一级节点是否合并。',
      required: false,
      options: [
        {value: 'false', label: '否'},
        {value: 'true', label: '是'},
      ],
    },
    }
  ]
}
src/menu/components/chart/antv-X6/index.jsx
@@ -1,947 +1,29 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Popover, message } from 'antd'
import { Popover } from 'antd'
import { ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
import G6 from '@antv/g6'
import { Graph, Shape } from '@antv/x6'
import { Stencil } from '@antv/x6-plugin-stencil'
import { Transform } from '@antv/x6-plugin-transform'
import { Selection } from '@antv/x6-plugin-selection'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { History } from '@antv/x6-plugin-history'
import MKEmitter from '@/utils/events.js'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import { resetStyle, getTables, getHeight, checkComponent } from '@/utils/utils-custom.js'
import { resetStyle, getTables, checkComponent } from '@/utils/utils-custom.js'
import './index.scss'
const { Util } = G6
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const ChartCompileForm = asyncIconComponent(() => import('./chartcompile'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
const MindData = [
  'Modeling Methods',
  [
    'Classification',
    ['Logistic regression', 'Linear discriminant analysis', 'Rules', 'Decision trees', 'Naive Bayes', 'K nearest neighbor', 'Probabilistic neural network', 'Support vector machine']
  ],
  [
    'Consensus',
    [
      'Models diversity',
      ['Different initializations', 'Different parameter choices', 'Different architectures', 'Different modeling methods', 'Different training sets', 'Different feature sets']
    ],
    [
      'Methods',
      ['Classifier selection', 'Classifier fusion']
    ],
    [
      'Common',
      ['Bagging', 'Boosting', 'AdaBoost']
    ]
  ],
  [
    'Regression',
    ['Multiple linear regression', 'Partial least squares', 'Multi-layer feedforward neural network', 'General regression neural network', 'Support vector regression']
  ]
]
const styles = {
  blue: '#1890ff',
  red: '#f5222d',
  orange_red: '#fa541c',
  orange: '#fa8c16',
  orange_yellow: '#faad14',
  yellow: '#fadb14',
  yellow_green: '#a0d911',
  green: '#52c41a',
  cyan: '#13c2c2',
  blue_purple: '#2f54eb',
  purple: '#722ed1',
  magenta: '#eb2f96',
  grass_green: '#aeb303',
  deep_red: '#c32539',
  deep_blue: '#1d3661'
}
let systemColor = '#1890ff'
if (window.GLOB.style) {
  let type = window.GLOB.style.replace(/bg_black_style_|bg_white_style_/, '')
  systemColor = styles[type] || '#1890ff'
}
const COLORS = ['#5B8FF9', '#F6BD16', '#5AD8A6', '#945FB9', '#E86452', '#6DC8EC', '#FF99C3', '#1E9493', '#FF9845', '#5D7092']
// 思维导图
G6.registerNode(
  'dice-mind-map-root', {
    jsx: (cfg) => {
      const width = Util.getTextSize(cfg.label, 16)[0] + 24
      return `
        <group>
          <rect style={{width: ${width}, height: 42, stroke: ${systemColor}, radius: 4}} keyshape>
            <text style={{ fontSize: 16, marginLeft: 6, marginTop: 12 }}>${cfg.label}</text>
          </rect>
        </group>
      `
    },
    getAnchorPoints() {
      return [
        [0, 0.5],
        [1, 0.5]
      ]
    }
  },
  'single-node',
)
G6.registerNode(
  'dice-mind-map-leaf', {
    jsx: (cfg) => {
      const width = Util.getTextSize(cfg.label, 12)[0] + 24
      return `
        <group>
          <rect style={{width: ${width}, height: 26, fill: 'transparent', cursor: pointer }}>
            <text style={{ fontSize: 12, fill: ${cfg.selected ? systemColor : '#000000'}, marginLeft: 12, marginTop: 6, cursor: pointer }}>${cfg.label}</text>
          </rect>
          <rect style={{ fill: ${cfg.color}, width: ${width}, height: 2, x: 0, y: 32, cursor: pointer }} />
        </group>
      `
    },
    getAnchorPoints() {
      return [
        [0, 0.965],
        [1, 0.965]
      ]
    }
  },
  'single-node',
)
G6.registerBehavior('dice-mindmap', {
  getEvents() {
    return {
      'node:click': 'editNode',
      'canvas:click': 'onCanvasClick'
    }
  },
  editNode(evt) {
    const item = evt.item
    const model = item.get('model')
    this.graph.getNodes().forEach(node => {
      let _model = node.get('model')
      if (_model.selected) {
        _model.selected = false
        this.graph.updateItem(node, _model, false)
      }
    })
    model.selected = true
    this.graph.updateItem(item, model, false)
  },
  onCanvasClick(e) {
    this.graph.getNodes().forEach(node => {
      let _model = node.get('model')
      if (_model.selected) {
        _model.selected = false
        this.graph.updateItem(node, _model, false)
      }
    })
  }
})
G6.registerBehavior('scroll-canvas', {
  getEvents: function getEvents() {
    return {
      wheel: 'onWheel'
    }
  },
  onWheel: function onWheel(ev) {
    const { graph } = this
    if (!graph) {
      return
    }
    if (ev.ctrlKey) {
      const canvas = graph.get('canvas')
      const point = canvas.getPointByClient(ev.clientX, ev.clientY)
      let ratio = graph.getZoom()
      if (ev.wheelDelta > 0) {
        ratio += ratio * 0.05
      } else {
        ratio *= ratio * 0.05
      }
      graph.zoomTo(ratio, {
        x: point.x,
        y: point.y
      })
    } else {
      const x = ev.deltaX || ev.movementX
      const y = ev.deltaY || ev.movementY || (-ev.wheelDelta * 125) / 3
      graph.translate(-x, -y)
    }
    ev.preventDefault()
  }
})
// 缩进文件树
G6.registerNode('indentedRoot', {
  draw(model, group) {
    const keyShape = group.addShape('rect', {
      attrs: {
        x: -46,
        y: -16,
        width: 92,
        height: 32,
        fill: systemColor,
        radius: 2,
        stroke: '#5B8FF9',
        lineWidth: 0
      },
      name: 'key-shape'
    })
    const text = group.addShape('text', {
      attrs: {
        text: model.label || 'root',
        fill: "#fff",
        fontSize: 12,
        x: 0,
        y: 0,
        textAlign: 'center',
        textBaseline: 'middle'
      },
      name: 'root-text-shape'
    })
    const textBBox = text.getBBox()
    const width = textBBox.width + 24
    const height = textBBox.height + 12
    keyShape.attr({
      x: -width / 2,
      y: -height / 2,
      width,
      height
    })
    return keyShape
  },
  getAnchorPoints() {
    return [
      [0.5, 1]
    ]
  },
  update: undefined
})
G6.registerNode('indentedNode', {
  addChildCount(group, tag, props) {
    const { collapsed, branchColor, count } = props
    let clickCircleY = 10
    // 子类数量 icon,绘制圆点在节点正下方
    if (tag) {
      const childCountGroup = group.addGroup({
        name: 'child-count-group'
      })
      childCountGroup.setMatrix([1, 0, 0, 0, 1, 0, 0, clickCircleY, 1])
      const countBackWidth = collapsed ? 26 : 12
      childCountGroup.addShape('rect', {
        attrs: {
          width: countBackWidth,
          height: 12,
          radius: 6,
          stroke: branchColor,
          lineWidth: 2,
          fill: collapsed ? branchColor : '#fff',
          x: -countBackWidth / 2,
          y: -6,
          cursor: 'pointer',
        },
        name: 'child-count-rect-shape'
      })
      const childCountText = childCountGroup.addShape('text', {
        attrs: {
          text: count,
          fill: '#fff',
          x: 0,
          y: 0,
          fontSize: 10,
          textAlign: 'center',
          textBaseline: 'middle',
          cursor: 'pointer',
        },
        name: 'child-count-text-shape'
      })
      const childHoverIcon = childCountGroup.addShape('path', {
        attrs: {
          stroke: '#fff',
          lineWidth: 1,
          cursor: 'pointer',
          path: [['M', -3, 2], ['L', 0, -2], ['L', 3, 2]]
        },
        name: 'child-count-expand-icon',
        capture: false
      })
      childHoverIcon.hide()
      // 连接 count 的线段
      const countLink = group.addShape('path', {
        attrs: {
          path: [['M', 0, 0], ['L', 0, 11]],
          stroke: branchColor,
          lineWidth: 2,
        },
        name: 'count-link'
      })
      countLink.toBack()
      if (collapsed) {
        childCountGroup.show()
        childCountText.show()
        countLink.show()
      }
      else {
        childCountGroup.hide()
        childCountText.hide()
        countLink.hide()
      }
      clickCircleY += 16
    }
  },
  addBottomLine(group, props) {
    const { x, width, stroke, lineWidth } = props
    return group.addShape('path', {
      attrs: {
        path: [
          ['M', x - 1, 0],
          ['L', width, 0],
        ],
        stroke,
        lineWidth,
      },
      name: 'node-path-shape'
    })
  },
  addName(group, props) {
    const { label, x = 0, y, fill } = props
    return group.addShape('text', {
      attrs: {
        text: label,
        x,
        y,
        textAlign: 'start',
        textBaseline: 'top',
        fill,
        fontSize: 14,
        fontFamily: 'PingFangSC-Regular',
        cursor: 'pointer',
      },
      name: 'not-root-text-shape'
    })
  },
  draw(model, group) {
    const { collapsed, depth, label, children, selected } = model
    // 是否为根节点
    const rootNode = depth === 0
    // 子节点数量
    const childCount = children ? children.length : 0
    let width = 0
    const height = 24
    const x = 0
    const y = -height / 2
    const borderRadius = 4
    // 名称文本
    const text = this.addName(group, { label, x, y })
    let textWidth = text.getBBox().width
    width = textWidth + 20
    const keyShapeAttrs = {
      x,
      y,
      width,
      height,
      radius: borderRadius,
      fill: undefined,
      stroke: undefined,
    }
    const keyShape = group.addShape('rect', {
      attrs: keyShapeAttrs,
      name: 'root-key-shape-rect-shape'
    })
    // 底部横线
    const bottomLine = this.addBottomLine(group, {
      stroke: model.branchColor || '#AAB7C4',
      lineWidth: 3,
      x,
      width
    })
    let nameColor = 'rgba(0, 0, 0, 0.85)'
    if (selected) {
      nameColor = systemColor
    }
    // 名称
    text.attr({
      y: y - 12,
      fill: nameColor
    })
    text.toFront()
    textWidth = text.getBBox().width
    if (bottomLine) bottomLine.toFront()
    this.addChildCount(group, childCount && !rootNode, {
      collapsed,
      branchColor: model.branchColor,
      count: childCount ? `${childCount}` : undefined
    })
    const bbox = group.getBBox()
    const backContainer = group.addShape('path', {
      attrs: {
        path: childCount ? [
          ['M', bbox.minX, bbox.minY],
          ['L', bbox.maxX, bbox.minY],
          ['L', bbox.maxX, bbox.maxY],
          ['L', bbox.minX + 20, bbox.maxY],
          ['L', bbox.minX + 20, bbox.maxY + 20],
          ['L', bbox.minX, bbox.maxY + 20],
          ['Z']
        ] : [
          ['M', bbox.minX, bbox.minY],
          ['L', bbox.maxX, bbox.minY],
          ['L', bbox.maxX, bbox.maxY],
          ['L', bbox.minX, bbox.maxY],
          ['Z']
        ],
        fill: '#fff',
        opacity: 0
      }
    })
    backContainer.toBack()
    return keyShape
  }
})
G6.registerEdge('indentedEdge', {
  afterDraw: (cfg, group) => {
    const sourceNode = cfg.sourceNode && cfg.sourceNode.getModel()
    const targetNode = cfg.targetNode && cfg.targetNode.getModel()
    const color = sourceNode.branchColor || targetNode.branchColor || cfg.color || '#000'
    const keyShape = group.get('children')[0]
    keyShape.attr({
      stroke: color,
      lineWidth: 3 // branchThick
    })
    group.toBack()
  },
  getControlPoints: (cfg) => {
    const startPoint = cfg.startPoint
    const endPoint = cfg.endPoint
    return [
      startPoint,
      {
        x: startPoint.x,
        y: endPoint.y,
      },
      endPoint
    ]
  },
  update: undefined
}, 'polyline')
G6.registerBehavior('wheel-scroll', {
  getDefaultCfg() {
    return {
      direction: 'y',
      zoomKey: 'ctrl',
      sensitivity: 3,
      scalableRange: -64
    }
  },
  getEvents() {
    return {
      wheel: 'onWheel'
    }
  },
  onWheel(ev) {
    const graph = this.graph
    let keyDown = ev[`${this.zoomKey}Key`]
    if (this.zoomKey === 'control') keyDown = ev.ctrlKey
    if (keyDown) {
      const sensitivity = this.get('sensitivity')
      const canvas = graph.get('canvas')
      const point = canvas.getPointByClient(ev.clientX, ev.clientY)
      let ratio = graph.getZoom()
      if (ev.wheelDelta > 0) {
        ratio *= (1 + 0.01 * sensitivity)
      } else {
        ratio *= (1 - 0.01 * sensitivity)
      }
      graph.zoomTo(ratio, {
        x: point.x,
        y: point.y
      })
      graph.emit('wheelzoom', ev)
    } else {
      let dx = ev.deltaX || ev.movementX
      let dy = ev.deltaY || ev.movementY
      if (!dy && navigator.userAgent.indexOf('Firefox') > -1) dy = (-ev.wheelDelta * 125) / 3
      const width = this.graph.get('width')
      const height = this.graph.get('height')
      const graphCanvasBBox = this.graph.get('group').getCanvasBBox()
      let expandWidth = this.scalableRange
      let expandHeight = this.scalableRange
      // 若 scalableRange 是 0~1 的小数,则作为比例考虑
      if (expandWidth < 1 && expandWidth > -1) {
        expandWidth = width * expandWidth
        expandHeight = height * expandHeight
      }
      const { minX, maxX, minY, maxY } = graphCanvasBBox
      if (dx > 0) {
        if (maxX < -expandWidth) {
          dx = 0
        } else if (maxX - dx < -expandWidth) {
          dx = maxX + expandWidth
        }
      } else if (dx < 0) {
        if (minX > width + expandWidth) {
          dx = 0
        } else if (minX - dx > width + expandWidth) {
          dx = minX - (width + expandWidth)
        }
      }
      if (dy > 0) {
        if (maxY < -expandHeight) {
          dy = 0
        } else if (maxY - dy < -expandHeight) {
          dy = maxY + expandHeight
        }
      } else if (dy < 0) {
        if (minY > height + expandHeight) {
          dy = 0
        } else if (minY - dy > height + expandHeight) {
          dy = minY - (height + expandHeight)
        }
      }
      if (this.get('direction') === 'x') {
        dy = 0
      } else if (this.get('direction') === 'y') {
        dx = 0
      }
      graph.translate(-dx, -dy)
    }
    ev.preventDefault()
  }
})
G6.registerBehavior('hover-node', {
  getEvents() {
    return {
      'node:mouseover': 'onNodeMouseOver',
      'node:mouseleave': 'onNodeMouseLeave',
      'node:mouseenter': 'onNodeMouseEnter'
    }
  },
  onNodeMouseEnter(ev) {
    const { item } = ev
    if (!item || item.get('destroyed')) return
    item.toFront()
    const model = item.getModel()
    const { collapsed, depth } = model
    const rootNode = depth === 0 || model.isRoot
    const group = item.getContainer()
    if (rootNode) return
    // 控制子节点个数标记
    if (!collapsed) {
      const childCountGroup = group.find(e => e.get('name') === 'child-count-group')
      if (childCountGroup) {
        childCountGroup.show()
      }
    }
  },
  onNodeMouseOver(ev) {
    const shape = ev.target
    // tooltip显示、隐藏
    this.graph.emit('tooltip: show', ev)
    // expand 状态下,若 hover 到子节点个数标记,填充背景+显示收起 icon
    const { item } = ev
    const group = item.getContainer()
    const model = item.getModel()
    if (!model.collapsed) {
      const childCountGroup = group.find(e => e.get('name') === 'child-count-group')
      if (childCountGroup) {
        childCountGroup.show()
        const back = childCountGroup.find(e => e.get('name') === 'child-count-rect-shape')
        const expandIcon = childCountGroup.find(e => e.get('name') === 'child-count-expand-icon')
        const rootNode = model.depth === 0 || model.isRoot
        const branchColor = rootNode ? '#576286' : model.branchColor
        if (shape.get('parent').get('name') === 'child-count-group') {
          if (back) {
            back.attr('fill', branchColor || '#fff')
          }
          if (expandIcon) {
            expandIcon.show()
          }
        } else {
          if (back) {
            back.attr('fill', '#fff')
          }
          if (expandIcon) {
            expandIcon.hide()
          }
        }
      }
    }
  },
  onNodeMouseLeave(ev) {
    const { item } = ev
    const model = item.getModel()
    const group = item.getContainer()
    const { collapsed } = model
    if (!collapsed) {
      const childCountGroup = group.find(e => e.get('name') === 'child-count-group')
      if (childCountGroup) {
        childCountGroup.hide()
      }
      const iconsLinkPath = group.find(e => e.get('name') === 'icons-link-path')
      if (iconsLinkPath) {
        iconsLinkPath.hide()
      }
    }
    this.graph.emit('tooltip: hide', ev)
  }
})
G6.registerBehavior('click-node', {
  getEvents() {
    return {
      'node:click': 'onNodeClick',
      'canvas:click': 'onCanvasClick'
    }
  },
  onNodeClick(e) {
    const { item, target } = e
    const shape = target
    const shapeName = shape.cfg.name
    let model = item.getModel()
    // 点击收起/展开 icon
    if (shapeName === 'child-count-rect-shape' || shapeName === 'child-count-text-shape') {
      const updatedCollapsed = !model.collapsed
      this.graph.updateItem(item, { collapsed: updatedCollapsed })
      this.graph.layout()
      return
    }
    // 选中节点
    this.graph.getNodes().forEach(node => {
      let _model = node.get('model')
      if (_model.selected) {
        _model.selected = false
        this.graph.updateItem(node, _model, false)
      }
    })
    model.selected = true
    this.graph.updateItem(item, model, false)
    return
  },
  onCanvasClick(e) {
    this.graph.getNodes().forEach(node => {
      let _model = node.get('model')
      if (_model.selected) {
        _model.selected = false
        this.graph.updateItem(node, _model, false)
      }
    })
  }
})
const dataIndTransform = (data) => {
  const changeData = (d) => {
    let data = { ...d }
    data.type = data.isRoot ? 'indentedRoot' : 'indentedNode'
    if (d.children) {
      data.children = d.children.map((child) => changeData(child))
    }
    // 给定 branchColor 和 0-2 层节点 depth
    if (data.children && data.children.length) {
      data.depth = 0
      data.children.forEach((subtree, i) => {
        subtree.branchColor = COLORS[i % COLORS.length]
        // dfs
        let currentDepth = 1
        subtree.depth = currentDepth
        Util.traverseTree(subtree, child => {
          child.branchColor = COLORS[i % COLORS.length]
          if (!child.depth) {
            child.depth = currentDepth + 1
          }
          else currentDepth = subtree.depth
          if (child.children) {
            child.children.forEach(subChild => {
              subChild.depth = child.depth + 1
            })
          }
          if (!data.isRoot) {
            child.collapsed = data.collapsed || false
          }
          return true
        })
      })
    }
    return data
  }
  return changeData(data)
}
// 知识图谱树
G6.registerNode('treeNode', {
  draw: (cfg, group) => {
    const { label, selected, children, isRoot } = cfg
    const rootNode = !!isRoot
    const hasChildren = children && children.length !== 0
    let width = 0
    const height = 28
    const x = 0
    const y = -height / 2
    // 名称文本
    const text = group.addShape('text', {
      attrs: {
        text: label,
        x: x * 2,
        y,
        textAlign: 'left',
        textBaseline: 'top',
        fontFamily: 'PingFangSC-Regular',
      },
      cursor: 'pointer',
      name: 'name-text-shape',
    })
    const textWidth = text.getBBox().width
    width = textWidth + 20
    width = width < 60 ? 60 : width
    if (!rootNode && hasChildren) {
      width += 22
    }
    const keyShapeAttrs = {
      x,
      y,
      width,
      height,
      radius: 4
    }
    const keyShape = group.addShape('rect', {
      attrs: keyShapeAttrs,
      name: 'root-key-shape-rect-shape'
    })
    if (!rootNode) {
      // 底部横线
      group.addShape('path', {
        attrs: {
          path: [
            ['M', x - 1, 0],
            ['L', width, 0],
          ],
          stroke: '#AAB7C4',
          lineWidth: 1,
        },
        name: 'node-path-shape'
      })
    }
    const mainX = x - 10
    const mainY = -height + 15
    if (rootNode) {
      group.addShape('rect', {
        attrs: {
          x: mainX,
          y: mainY,
          width: width + 12,
          height,
          radius: 14,
          fill: systemColor,
          cursor: 'pointer',
        },
        name: 'main-shape'
      })
    }
    let nameColor = 'rgba(0, 0, 0, 0.85)'
    if (selected) {
      nameColor = systemColor
    }
    // 名称
    if (rootNode) {
      group.addShape('text', {
        attrs: {
          text: label,
          x: mainX + 18,
          y: 1,
          textAlign: 'left',
          textBaseline: 'middle',
          fill: '#ffffff',
          fontSize: 12,
          fontFamily: 'PingFangSC-Regular',
          cursor: 'pointer',
        },
        name: 'root-text-shape'
      })
    } else {
      group.addShape('text', {
        attrs: {
          text: label,
          x: mainX + 6,
          y: y - 5,
          textAlign: 'start',
          textBaseline: 'top',
          fill: nameColor,
          fontSize: 12,
          fontFamily: 'PingFangSC-Regular',
          cursor: 'pointer',
        },
        name: 'not-root-text-shape'
      })
    }
    // 子类数量
    if (hasChildren && !rootNode) {
      const childCountHeight = 12
      const childCountX = width - 22
      const childCountY = -childCountHeight / 2
      group.addShape('rect', {
        attrs: {
          width: 22,
          height: 12,
          stroke: systemColor,
          fill: '#fff',
          x: childCountX,
          y: childCountY,
          radius: 6,
          cursor: 'pointer',
        },
        name: 'child-count-rect-shape',
      })
      group.addShape('text', {
        attrs: {
          text: `${children.length}`,
          fill: 'rgba(0, 0, 0, .65)',
          x: childCountX + 11,
          y: childCountY + 12,
          fontSize: 10,
          width: 22,
          textAlign: 'center',
          cursor: 'pointer',
        },
        name: 'child-count-text-shape'
      })
    }
    return keyShape
  }
})
G6.registerEdge('smooth', {
  draw(cfg, group) {
    const { startPoint, endPoint } = cfg
    const hgap = Math.abs(endPoint.x - startPoint.x)
    const path = [
      ['M', startPoint.x, startPoint.y],
      [
        'C',
        startPoint.x + hgap / 4,
        startPoint.y,
        endPoint.x - hgap / 2,
        endPoint.y,
        endPoint.x,
        endPoint.y,
      ],
    ]
    const shape = group.addShape('path', {
      attrs: {
        stroke: '#AAB7C4',
        path,
      },
      name: 'smooth-path-shape',
    })
    return shape
  },
})
G6.registerBehavior('click-item', {
  getEvents() {
    return {
      'node:click': 'onNodeClick',
      'canvas:click': 'onCanvasClick'
    }
  },
  onNodeClick(e) {
    const { item } = e
    let model = item.getModel()
    if (model.children) return
    // 选中节点
    this.graph.getNodes().forEach(node => {
      let _model = node.get('model')
      if (_model.selected) {
        _model.selected = false
        this.graph.updateItem(node, _model, false)
      }
    })
    model.selected = true
    this.graph.updateItem(item, model, false)
    return
  },
  onCanvasClick(e) {
    this.graph.getNodes().forEach(node => {
      let _model = node.get('model')
      if (_model.selected) {
        _model.selected = false
        this.graph.updateItem(node, _model, false)
      }
    })
  }
})
class antvG6Chart extends Component {
class antvX6Chart extends Component {
  static propTpyes = {
    card: PropTypes.object,
    updateConfig: PropTypes.func,
@@ -986,32 +68,12 @@
        plot: _plot,
      }
      if (card.config) {
        let config = fromJS(card.config).toJS()
        _card.plot = config.plot
        _card.plot.name = card.name
        _card.style = config.style
        _card.headerStyle = config.headerStyle
        _card.setting = config.setting
        _card.columns = config.columns
        _card.scripts = config.scripts
      }
      this.updateComponent(_card)
    } else {
      this.setState({
        card: fromJS(card).toJS()
      })
    }
  }
  componentDidMount () {
    MKEmitter.addListener('tabsChange', this.handleTabsChange)
    setTimeout(() => {
      this.viewrender()
    }, 1000)
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -1025,311 +87,531 @@
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('tabsChange', this.handleTabsChange)
  }
  handleTabsChange = (parentId) => {
    const { card } = this.state
    if (parentId.indexOf(card.uuid) > -1 || parentId === 'all') {
      let _element = document.getElementById(card.uuid + 'canvas')
      if (_element) {
        _element.innerHTML = ''
      }
      this.$timer && clearTimeout(this.$timer)
      this.$timer = setTimeout(this.viewrender, 100)
    }
  }
  getdata = () => {
    const { card } = this.state
    const setData = (list) => {
      let item = {
        label: list[0],
        id: list[0],
        children: []
      }
      if (!list[1]) {
        delete item.children
        return item
      } else if (!Array.isArray(list[1])) {
        return list.map(m => ({label: m, id: m}))
      }
      for (let i = 1; i < list.length; i++) {
        let cell = setData(list[i])
        if (Array.isArray(cell)) {
          item.children.push(...cell)
        } else {
          item.children.push(cell)
        }
      }
      return item
    }
    let data = setData(MindData)
    if (card.plot.subtype === 'mindmap') {
      if (card.plot.dirField) {
        data.children[0].direction = 'left'
        data.children[2].direction = 'left'
      }
      data.children.forEach(item => {
        if (item.direction === 'left') {
          item.color = card.plot.leftColor || '#26C281'
        } else {
          item.direction = 'right'
          item.color = card.plot.nodeColor || '#1890ff'
        }
      })
      data.collapsed = false
      data.type = 'dice-mind-map-root'
      const collapse = (item) => {
        if (!item.children) return
        item.children.forEach(cell => {
          cell.collapsed = card.plot.collapsed === 'true'
          cell.direction = cell.direction || 'right'
          cell.type = 'dice-mind-map-leaf'
          cell.color = cell.color || item.color
          collapse(cell)
        })
      }
      collapse(data)
    } else if (card.plot.subtype === 'indentTree') {
      data.isRoot = true
      data.collapsed = false
      data.children.forEach(item => {
        item.collapsed = card.plot.collapsed === 'true'
      })
    } else if (card.plot.subtype === 'kapmap') {
      data.isRoot = true
      data.collapsed = false
      if (card.plot.collapsed === 'true') {
        const collapse = (item) => {
          if (!item.children) return
          item.children.forEach(cell => {
            cell.collapsed = true
            collapse(cell)
          })
        }
        collapse(data)
      }
    }
    return data
  componentDidMount () {
    setTimeout(() => {
      this.viewrender()
    }, 1000)
  }
  viewrender = () => {
    const { card } = this.state
    // const { card } = this.state
    if (card.plot.subtype === 'mindmap') {
      this.ponitrender()
    } else if (card.plot.subtype === 'indentTree') {
      this.indentrender()
    } else if (card.plot.subtype === 'kapmap') {
    // if (card.plot.subtype === 'mindmap') {
    //   this.ponitrender()
    // } else if (card.plot.subtype === 'indentTree') {
    //   this.indentrender()
    // } else if (card.plot.subtype === 'kapmap') {
      this.kapmaprender()
    }
    // }
  }
  kapmaprender = () => {
    const { card } = this.state
    const plot = card.plot
    const data = this.getdata()
    const height = getHeight(plot.height)
    const graph = new G6.TreeGraph({
      container: card.uuid + 'canvas',
      width: this.wrap.scrollWidth - 30,
      height: height,
      modes: {
        default: [
          {
            type: 'collapse-expand',
    preWork()
    // #region 初始化画布
    const graph = new Graph({
      container: document.getElementById(card.uuid + 'container'),
      grid: true,
      mousewheel: {
        enabled: true,
        zoomAtMousePosition: true,
        modifiers: 'ctrl',
        minScale: 0.5,
        maxScale: 3,
      },
      connecting: {
        router: 'manhattan',
        connector: {
          name: 'rounded',
          args: {
            radius: 8,
          },
          'drag-canvas',
          'zoom-canvas',
          'click-item'
        ],
        },
        anchor: 'center',
        connectionPoint: 'anchor',
        allowBlank: false,
        snap: {
          radius: 20,
        },
        createEdge() {
          return new Shape.Edge({
            attrs: {
              line: {
                stroke: '#A2B1C3',
                strokeWidth: 2,
                targetMarker: {
                  name: 'block',
                  width: 12,
                  height: 8,
                },
              },
            },
            zIndex: 0,
          })
        },
        validateConnection({ targetMagnet }) {
          return !!targetMagnet
        },
      },
      defaultNode: {
        type: 'treeNode',
        anchorPoints: [
          [0, 0.5],
          [1, 0.5],
        ],
      highlighting: {
        magnetAdsorbed: {
          name: 'stroke',
          args: {
            attrs: {
              fill: '#5F95FF',
              stroke: '#5F95FF',
            },
          },
        },
      },
      defaultEdge: {
        type: 'smooth',
    })
    // #endregion
    // #region 使用插件
    graph
      .use(
        new Transform({
          resizing: true,
          rotating: true,
        }),
      )
      .use(
        new Selection({
          rubberband: true,
          showNodeSelectionBox: true,
        }),
      )
      .use(new Snapline())
      .use(new Keyboard())
      .use(new Clipboard())
      .use(new History())
    // #endregion
    // #region 初始化 stencil
    const stencil = new Stencil({
      title: '流程图',
      target: graph,
      stencilGraphWidth: 200,
      stencilGraphHeight: 180,
      collapsable: true,
      groups: [
        {
          title: '基础流程图',
          name: 'group1',
        },
        {
          title: '系统设计图',
          name: 'group2',
          graphHeight: 250,
          layoutOptions: {
            rowHeight: 70,
          },
        },
      ],
      layoutOptions: {
        columns: 2,
        columnWidth: 80,
        rowHeight: 55,
      },
      layout: {
        type: 'compactBox',
        direction: 'LR',
        getId: function getId(d) {
          return d.id
        },
        getHeight: function getHeight() {
          return 16
        },
        getWidth: function getWidth(d) {
          const labelWidth = G6.Util.getTextSize(d.label, 12)[0]
          const width = 60 + labelWidth
          return width
        },
        getVGap: function getVGap() {
          return 15
        },
        getHGap: function getHGap() {
          return 30
        }
    })
    document.getElementById('stencil').appendChild(stencil.container)
    // #endregion
    // #region 快捷键与事件
    graph.bindKey(['meta+c', 'ctrl+c'], () => {
      const cells = graph.getSelectedCells()
      if (cells.length) {
        graph.copy(cells)
      }
      return false
    })
    graph.bindKey(['meta+x', 'ctrl+x'], () => {
      const cells = graph.getSelectedCells()
      if (cells.length) {
        graph.cut(cells)
      }
      return false
    })
    graph.bindKey(['meta+v', 'ctrl+v'], () => {
      if (!graph.isClipboardEmpty()) {
        const cells = graph.paste({ offset: 32 })
        graph.cleanSelection()
        graph.select(cells)
      }
      return false
    })
    // undo redo
    graph.bindKey(['meta+z', 'ctrl+z'], () => {
      if (graph.canUndo()) {
        graph.undo()
      }
      return false
    })
    graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
      if (graph.canRedo()) {
        graph.redo()
      }
      return false
    })
    // select all
    graph.bindKey(['meta+a', 'ctrl+a'], () => {
      const nodes = graph.getNodes()
      if (nodes) {
        graph.select(nodes)
      }
    })
    graph.data(data)
    graph.render()
    graph.fitView()
    // delete
    graph.bindKey('backspace', () => {
      const cells = graph.getSelectedCells()
      if (cells.length) {
        graph.removeCells(cells)
      }
    })
    if (plot.collapsed === 'true') {
      graph.zoomTo(1, { x: 0, y: height / 2 })
    // zoom
    graph.bindKey(['ctrl+1', 'meta+1'], () => {
      const zoom = graph.zoom()
      if (zoom < 1.5) {
        graph.zoom(0.1)
      }
    })
    graph.bindKey(['ctrl+2', 'meta+2'], () => {
      const zoom = graph.zoom()
      if (zoom > 0.5) {
        graph.zoom(-0.1)
      }
    })
    // 控制连接桩显示/隐藏
    const showPorts = (ports, show) => {
      for (let i = 0, len = ports.length; i < len; i += 1) {
        ports[i].style.visibility = show ? 'visible' : 'hidden'
      }
    }
  }
    graph.on('node:mouseenter', () => {
      const container = document.getElementById(card.uuid + 'container')
      const ports = container.querySelectorAll('.x6-port-body')
      showPorts(ports, true)
    })
    graph.on('node:mouseleave', () => {
      const container = document.getElementById(card.uuid + 'container')
      const ports = container.querySelectorAll('.x6-port-body')
      showPorts(ports, false)
    })
    // #endregion
  indentrender = () => {
    const { card } = this.state
    const plot = card.plot
    const data = this.getdata()
    const tree = new G6.TreeGraph({
      container: card.uuid + 'canvas',
      width: this.wrap.scrollWidth - 30,
      height: getHeight(plot.height),
      layout: {
        type: 'indented',
        direction: 'LR',
        isHorizontal: true,
        indent: 40,
        getHeight: (d) => {
          if (d.isRoot) {
            return 30
          }
          if (d.collapsed && d.children && d.children.length) {
            return 36
          }
          return 22
    // #region 初始化图形
    const ports = {
      groups: {
        top: {
          position: 'top',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
        getVGap: () => {
          return 10
        right: {
          position: 'right',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
        bottom: {
          position: 'bottom',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
        left: {
          position: 'left',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
      },
      defaultEdge: {
        type: 'indentedEdge',
        style: {
          lineWidth: 2,
          radius: 16
        }
      },
      minZoom: 0.5,
      modes: {
        default: [
          'drag-canvas',
          'wheel-scroll',
          'hover-node',
          'click-node'
        ]
      }
    })
    tree.on('afterrender', e => {
      tree.getEdges().forEach(edge => {
        const targetNode = edge.getTarget().getModel()
        const color = targetNode.branchColor
        tree.updateItem(edge, { color })
      })
      setTimeout(() => {
        tree.moveTo(32, 32)
        tree.zoomTo(0.7)
      }, 16)
    })
    tree.data(dataIndTransform(data))
    tree.render()
  }
  /**
   * @description 散点图
   */
  ponitrender = () => {
    const { card } = this.state
    const plot = card.plot
    const data = this.getdata()
    const width = this.wrap.scrollWidth - 30
    const height = getHeight(plot.height)
    let modes = ['drag-canvas', 'zoom-canvas', 'dice-mindmap']
    if (plot.collapsed === 'true') {
      modes = [{ type: 'collapse-expand' },'drag-canvas', 'zoom-canvas', 'dice-mindmap']
      items: [
        {
          group: 'top',
        },
        {
          group: 'right',
        },
        {
          group: 'bottom',
        },
        {
          group: 'left',
        },
      ],
    }
    const tree = new G6.TreeGraph({
      container: card.uuid + 'canvas',
      width: width,
      height: height,
      fitView: true,
      layout: {
        type: 'mindmap',
        direction: 'H',
        getHeight: () => {
          return 16
    Graph.registerNode(
      'custom-rect',
      {
        inherit: 'rect',
        width: 66,
        height: 36,
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: '#5F95FF',
            fill: '#EFF4FF',
          },
          text: {
            fontSize: 12,
            fill: '#262626',
          },
        },
        getWidth: (node) => {
          return node.level === 0 ?
            Util.getTextSize(node.label, 16)[0] + 12 :
            Util.getTextSize(node.label, 12)[0]
        },
        getVGap: () => {
          return 10
        },
        getHGap: () => {
          return 60
        },
        getSide: (node) => {
          return node.data.direction
        }
        ports: { ...ports },
      },
      defaultEdge: {
        type: 'cubic-horizontal',
        style: {
          lineWidth: 2
        }
      true,
    )
    Graph.registerNode(
      'custom-polygon',
      {
        inherit: 'polygon',
        width: 66,
        height: 36,
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: '#5F95FF',
            fill: '#EFF4FF',
          },
          text: {
            fontSize: 12,
            fill: '#262626',
          },
        },
        ports: {
          ...ports,
          items: [
            {
              group: 'top',
            },
            {
              group: 'bottom',
            },
          ],
        },
      },
      minZoom: 0.5,
      modes: {
        default: modes
      }
      true,
    )
    Graph.registerNode(
      'custom-circle',
      {
        inherit: 'circle',
        width: 45,
        height: 45,
        attrs: {
          body: {
            strokeWidth: 1,
            stroke: '#5F95FF',
            fill: '#EFF4FF',
          },
          text: {
            fontSize: 12,
            fill: '#262626',
          },
        },
        ports: { ...ports },
      },
      true,
    )
    Graph.registerNode(
      'custom-image',
      {
        inherit: 'rect',
        width: 52,
        height: 52,
        markup: [
          {
            tagName: 'rect',
            selector: 'body',
          },
          {
            tagName: 'image',
          },
          {
            tagName: 'text',
            selector: 'label',
          },
        ],
        attrs: {
          body: {
            stroke: '#5F95FF',
            fill: '#5F95FF',
          },
          image: {
            width: 26,
            height: 26,
            refX: 13,
            refY: 16,
          },
          label: {
            refX: 3,
            refY: 2,
            textAnchor: 'left',
            textVerticalAnchor: 'top',
            fontSize: 12,
            fill: '#fff',
          },
        },
        ports: { ...ports },
      },
      true,
    )
    const r1 = graph.createNode({
      shape: 'custom-rect',
      label: '开始',
      attrs: {
        body: {
          rx: 20,
          ry: 26,
        },
      },
    })
    const r2 = graph.createNode({
      shape: 'custom-rect',
      label: '过程',
    })
    const r3 = graph.createNode({
      shape: 'custom-rect',
      attrs: {
        body: {
          rx: 6,
          ry: 6,
        },
      },
      label: '可选过程',
    })
    const r4 = graph.createNode({
      shape: 'custom-polygon',
      attrs: {
        body: {
          refPoints: '0,10 10,0 20,10 10,20',
        },
      },
      label: '决策',
    })
    const r5 = graph.createNode({
      shape: 'custom-polygon',
      attrs: {
        body: {
          refPoints: '10,0 40,0 30,20 0,20',
        },
      },
      label: '数据',
    })
    const r6 = graph.createNode({
      shape: 'custom-circle',
      label: '连接',
    })
    stencil.load([r1, r2, r3, r4, r5, r6], 'group1')
    tree.data(data)
    tree.render()
    const imageShapes = [
      {
        label: 'Client',
        image:
          'https://gw.alipayobjects.com/zos/bmw-prod/687b6cb9-4b97-42a6-96d0-34b3099133ac.svg',
      },
      {
        label: 'Http',
        image:
          'https://gw.alipayobjects.com/zos/bmw-prod/dc1ced06-417d-466f-927b-b4a4d3265791.svg',
      },
      {
        label: 'Api',
        image:
          'https://gw.alipayobjects.com/zos/bmw-prod/c55d7ae1-8d20-4585-bd8f-ca23653a4489.svg',
      },
      {
        label: 'Sql',
        image:
          'https://gw.alipayobjects.com/zos/bmw-prod/6eb71764-18ed-4149-b868-53ad1542c405.svg',
      },
      {
        label: 'Clound',
        image:
          'https://gw.alipayobjects.com/zos/bmw-prod/c36fe7cb-dc24-4854-aeb5-88d8dc36d52e.svg',
      },
      {
        label: 'Mq',
        image:
          'https://gw.alipayobjects.com/zos/bmw-prod/2010ac9f-40e7-49d4-8c4a-4fcf2f83033b.svg',
      },
    ]
    const imageNodes = imageShapes.map((item) =>
      graph.createNode({
        shape: 'custom-image',
        label: item.label,
        attrs: {
          image: {
            'xlink:href': item.image,
          },
        },
      }),
    )
    stencil.load(imageNodes, 'group2')
    // #endregion
    if (plot.collapsed === 'true' && plot.dirField) {
      tree.zoomTo(1, { x: width / 2, y: height / 2 })
    } else if (plot.collapsed === 'true') {
      tree.zoomTo(1, { x: 0, y: height / 2 })
    function preWork() {
      // 这里协助演示的代码,在实际项目中根据实际情况进行调整
      const container = document.getElementById(card.uuid + 'canvas')
      const stencilContainer = document.createElement('div')
      stencilContainer.id = 'stencil'
      stencilContainer.classList.add('mk-stencil')
      const graphContainer = document.createElement('div')
      graphContainer.id = card.uuid + 'container'
      graphContainer.classList.add('mk-container')
      container.appendChild(stencilContainer)
      container.appendChild(graphContainer)
    }
  }
@@ -1354,19 +636,6 @@
    if (card.errors.length === 0) {
      card.$tables = getTables(card)
    }
    if (!card.plot.valueField) {
      card.errors.push({ level: 0, detail: '图表信息尚未设置!'})
    } else {
      let columns = card.columns.map(c => c.field)
      if (!columns.includes(card.plot.valueField)) {
        card.errors.push({ level: 0, detail: '值字段在字段集中不存在'})
      } else if (!columns.includes(card.plot.labelField)) {
        card.errors.push({ level: 0, detail: '文本字段在字段集中不存在'})
      } else if (!columns.includes(card.plot.parentField)) {
        card.errors.push({ level: 0, detail: '上级字段在字段集中不存在'})
      }
    }
    this.setState({
@@ -1410,7 +679,6 @@
            <ChartCompileForm config={card} plotchange={this.updateComponent}/>
            <CopyComponent type="antvG6" card={card}/>
            <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/>
            <UserComponent config={card}/>
            <DeleteOutlined className="close" title="delete" onClick={() => this.props.deletecomponent(card.uuid)}/>
            <SettingComponent config={card} updateConfig={this.updateComponent}/>
          </div>
@@ -1418,18 +686,11 @@
          <ToolOutlined/>
        </Popover>
        <NormalHeader config={card} updateComponent={this.updateComponent}/>
        <div className="canvas" style={{minHeight: card.plot.height}} id={card.uuid + 'canvas'} ref={ref => this.wrap = ref}></div>
        <div className="canvas" style={{width: '100%', minHeight: card.plot.height, height: card.plot.height}} id={card.uuid + 'canvas'}>
        </div>
        <div className="component-name">
          <div className="center">
            <div className="title" onDoubleClick={() => {
              let oInput = document.createElement('input')
              oInput.value = 'anchor' + card.uuid
              document.body.appendChild(oInput)
              oInput.select()
              document.execCommand('Copy')
              document.body.removeChild(oInput)
              message.success('复制成功。')
            }}>{card.name}</div>
            <div className="title">{card.name}</div>
            <div className="content">
              {card.errors && card.errors.map((err, index) => {
                if (err.level === 0) {
@@ -1446,4 +707,4 @@
  }
}
export default antvG6Chart
export default antvX6Chart
src/menu/components/chart/antv-X6/index.scss
@@ -8,8 +8,52 @@
  
  .canvas {
    margin: 0px;
    padding: 15px;
    letter-spacing: 0px;
    display: flex;
    .mk-stencil {
      width: 180px;
      height: 100%;
      position: relative;
      z-index: 2;
      border-right: 1px solid #dfe3e8;
    }
    .mk-container {
      width: calc(100% - 180px);
      height: 100%;
    }
    .x6-widget-stencil  {
      background-color: #fff;
    }
    .x6-widget-stencil-title {
      background-color: #fff;
    }
    .x6-widget-stencil-group-title {
      background-color: #fff !important;
    }
    .x6-widget-transform {
      margin: -1px 0 0 -1px;
      padding: 0px;
      border: 1px solid #239edd;
    }
    .x6-widget-transform > div {
      border: 1px solid #239edd;
    }
    .x6-widget-transform > div:hover {
      background-color: #3dafe4;
    }
    .x6-widget-transform-active-handle {
      background-color: #3dafe4;
    }
    .x6-widget-transform-resize {
      border-radius: 0;
    }
    .x6-widget-selection-inner {
      border: 1px solid #239edd;
    }
    .x6-widget-selection-box {
      opacity: 0;
    }
  }
  .chart-header {
@@ -41,25 +85,6 @@
    cursor: pointer;
    color: rgba(0, 0, 0, 0.85);
    background: rgba(255, 255, 255, 0.55);
  }
  .model-menu-action-list {
    position: absolute;
    right: 0px;
    top: 30px;
    z-index: 4;
    font-size: 16px;
    .ant-row .anticon-plus {
      float: right;
    }
    .page-card {
      float: right;
    }
  }
  .normal-header + .canvas + .model-menu-action-list {
    top: 45px;
  }
}
.menu-scatter-chart-edit-box:hover {
src/menu/menushell/card.jsx
@@ -32,6 +32,7 @@
const Account = asyncComponent(() => import('@/menu/components/module/account'))
const Iframe = asyncComponent(() => import('@/menu/components/iframe'))
const AntvG6 = asyncComponent(() => import('@/menu/components/chart/antv-G6'))
const AntvX6 = asyncComponent(() => import('@/menu/components/chart/antv-X6'))
const Card = ({ id, card, moveCard, findCard, delCard, unGroup, updateConfig }) => {
  const originalIndex = findCard(id).index
@@ -123,12 +124,23 @@
      return (<Iframe card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'antvG6') {
      return (<AntvG6 card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'antvX6') {
      return (<AntvX6 card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'module' && card.subtype === 'voucher') {
      return (<Voucher card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'module' && card.subtype === 'account') {
      return (<Account card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    }
  }
  // if (card.type === 'antvX6') { // 测试
  //   return (
  //     <div className={'ant-col mk-component-card ant-col-' + (card.width || 24)} style={style}>
  //       <AntvX6 card={card} updateConfig={updateConfig} deletecomponent={delCard}/>
  //     </div>
  //   )
  // }
  return (
    <div className={'ant-col mk-component-card ant-col-' + (card.width || 24)} ref={node => drag(drop(node))} style={style}>
      {getCardComponent()}
src/menu/modulesource/option.jsx
@@ -1,7 +1,6 @@
import bar from '@/assets/mobimg/bar.png'
import bar1 from '@/assets/mobimg/bar1.png'
import line from '@/assets/mobimg/line.png'
// import line1 from '@/assets/mobimg/line1.png'
import tabs from '@/assets/mobimg/tabs.png'
import group from '@/assets/mobimg/group.png'
import card1 from '@/assets/mobimg/card1.png'
@@ -53,7 +52,6 @@
  { type: 'menu', url: timeline, component: 'timeline', subtype: 'timeline', title: '时间轴', width: 12 },
  { type: 'menu', url: tree, component: 'tree', subtype: 'normaltree', title: '树形列表', width: 12, forbid: ['billPrint'] },
  { type: 'menu', url: line, component: 'line', subtype: 'line', title: '折线图', width: 24 },
  // { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '阶梯折线图', width: 24 },
  { type: 'menu', url: bar, component: 'bar', subtype: 'bar', title: '柱状图', width: 24 },
  { type: 'menu', url: bar1, component: 'bar', subtype: 'bar1', title: '条形图', width: 24 },
  { type: 'menu', url: Pie, component: 'pie', subtype: 'pie', title: '饼图', width: 12 },
src/tabviews/custom/components/chart/antv-G6/index.jsx
@@ -1293,7 +1293,7 @@
      this.setState({empty: false})
      if (plot.subtype === 'mindmap') {
        this.ponitrender()
        this.mindrender()
      } else if (plot.subtype === 'indentTree') {
        this.indentrender()
      } else if (plot.subtype === 'kapmap') {
@@ -1424,9 +1424,9 @@
  }
  /**
   * @description 散点图
   * @description 思维导图
   */
  ponitrender = () => {
  mindrender = () => {
    const { config, plot, chartId } = this.state
    const data = this.getdata()
    const width = this.wrap.scrollWidth - 30
src/tabviews/custom/index.jsx
@@ -153,7 +153,7 @@
      // 数据缓存设置
      if (config.cacheUseful === 'true') {
        if (!['day', 'hour'].includes(config.timeUnit)) {
        if (!['day', 'hour', 'minute'].includes(config.timeUnit)) {
          config.timeUnit = 'day'
        }
        config.cacheTime = config.cacheTime || 1
src/tabviews/custom/popview/index.jsx
@@ -97,7 +97,7 @@
    // 数据缓存设置
    if (config.cacheUseful === 'true') {
      if (!['day', 'hour'].includes(config.timeUnit)) {
      if (!['day', 'hour', 'minute'].includes(config.timeUnit)) {
        config.timeUnit = 'day'
      }
      config.cacheTime = config.cacheTime || 1
src/views/menudesign/homeform/index.jsx
@@ -171,9 +171,10 @@
              {getFieldDecorator('timeUnit', {
                initialValue: config.timeUnit || 'day'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                  <Radio value="day">天</Radio>
                  <Radio value="hour">小时</Radio>
                  <Radio value="minute">分钟</Radio>
                </Radio.Group>
              )}
            </Form.Item>
@@ -189,7 +190,7 @@
                  }
                ]
              })(
                <InputNumber min={1} max={config.timeUnit !== 'hour' ? 7 : 23} precision={0} onChange={this.changeCacheDay}/>
                <InputNumber min={1} max={config.timeUnit === 'day' ? 7 : (config.timeUnit === 'hour' ? 23 : 59)} precision={0} onChange={this.changeCacheDay}/>
              )}
            </Form.Item>
          </Col> : null}
src/views/menudesign/menuform/index.jsx
@@ -363,9 +363,10 @@
              {getFieldDecorator('timeUnit', {
                initialValue: config.timeUnit || 'day'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                  <Radio value="day">天</Radio>
                  <Radio value="hour">小时</Radio>
                  <Radio value="minute">分钟</Radio>
                </Radio.Group>
              )}
            </Form.Item>
@@ -381,7 +382,7 @@
                  }
                ]
              })(
                <InputNumber min={1} max={config.timeUnit !== 'hour' ? 7 : 23} precision={0} onChange={(val) => {this.selectChange('cacheTime', val)}}/>
                <InputNumber min={1} max={config.timeUnit === 'day' ? 7 : (config.timeUnit === 'hour' ? 23 : 59)} precision={0} onChange={(val) => {this.selectChange('cacheTime', val)}}/>
              )}
            </Form.Item>
          </Col> : null}
src/views/menudesign/popview/menuform/index.jsx
@@ -86,9 +86,10 @@
              {getFieldDecorator('timeUnit', {
                initialValue: config.timeUnit || 'day'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                  <Radio value="day">天</Radio>
                  <Radio value="hour">小时</Radio>
                  <Radio value="minute">分钟</Radio>
                </Radio.Group>
              )}
            </Form.Item>
@@ -104,7 +105,7 @@
                  }
                ]
              })(
                <InputNumber min={1} max={config.timeUnit !== 'hour' ? 7 : 23} precision={0} onChange={this.changeCacheDay}/>
                <InputNumber min={1} max={config.timeUnit === 'day' ? 7 : (config.timeUnit === 'hour' ? 23 : 59)} precision={0} onChange={this.changeCacheDay}/>
              )}
            </Form.Item>
          </Col> : null}
src/views/mobdesign/menuform/index.jsx
@@ -168,9 +168,10 @@
              {getFieldDecorator('timeUnit', {
                initialValue: config.timeUnit || 'day'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                  <Radio value="day">天</Radio>
                  <Radio value="hour">小时</Radio>
                  <Radio value="minute">分钟</Radio>
                </Radio.Group>
              )}
            </Form.Item>
@@ -186,7 +187,7 @@
                  }
                ]
              })(
                <InputNumber min={1} max={config.timeUnit !== 'hour' ? 7 : 23} precision={0} onChange={this.changeCacheDay}/>
                <InputNumber min={1} max={config.timeUnit === 'day' ? 7 : (config.timeUnit === 'hour' ? 23 : 59)} precision={0} onChange={this.changeCacheDay}/>
              )}
            </Form.Item>
          </Col> : null}
src/views/mobdesign/popview/menuform/index.jsx
@@ -86,9 +86,10 @@
              {getFieldDecorator('timeUnit', {
                initialValue: config.timeUnit || 'day'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                  <Radio value="day">天</Radio>
                  <Radio value="hour">小时</Radio>
                  <Radio value="minute">分钟</Radio>
                </Radio.Group>
              )}
            </Form.Item>
@@ -104,7 +105,7 @@
                  }
                ]
              })(
                <InputNumber min={1} max={config.timeUnit !== 'hour' ? 7 : 23} precision={0} onChange={this.changeCacheDay}/>
                <InputNumber min={1} max={config.timeUnit === 'day' ? 7 : (config.timeUnit === 'hour' ? 23 : 59)} precision={0} onChange={this.changeCacheDay}/>
              )}
            </Form.Item>
          </Col> : null}
src/views/pcdesign/menuform/index.jsx
@@ -187,9 +187,10 @@
              {getFieldDecorator('timeUnit', {
                initialValue: config.timeUnit || 'day'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                  <Radio value="day">天</Radio>
                  <Radio value="hour">小时</Radio>
                  <Radio value="minute">分钟</Radio>
                </Radio.Group>
              )}
            </Form.Item>
@@ -205,7 +206,7 @@
                  }
                ]
              })(
                <InputNumber min={1} max={config.timeUnit !== 'hour' ? 7 : 23} precision={0} onChange={this.changeCacheDay}/>
                <InputNumber min={1} max={config.timeUnit === 'day' ? 7 : (config.timeUnit === 'hour' ? 23 : 59)} precision={0} onChange={this.changeCacheDay}/>
              )}
            </Form.Item>
          </Col> : null}
src/views/tabledesign/menuform/index.jsx
@@ -194,8 +194,6 @@
      })
    } else if (key === 'parentId') {
      this.props.updateConfig({...config, parentId: value})
    } else if (key === 'timeUnit') {
      this.props.updateConfig({...config, timeUnit: value})
    } else if (key === 'OpenType') {
      this.props.updateConfig({...config, OpenType: value})
    } else if (key === 'hidden') {