king
2022-10-03 8d475da89346bdddc967ac610b8d460ce9964a30
2022-10-03
6个文件已修改
2个文件已添加
473 ■■■■■ 已修改文件
src/menu/tablenodes/index.jsx 355 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/tablenodes/index.scss 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/tablecomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.scss 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.scss 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/tablenodes/index.jsx
New file
@@ -0,0 +1,355 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Modal, Button, notification, Spin } from 'antd'
import { ForkOutlined } from '@ant-design/icons'
import Api from '@/api'
import G6 from "@antv/g6"
import Utils from '@/utils/utils.js'
import MKEmitter from '@/utils/events.js'
import './index.scss'
class TableNodes extends Component {
  static propTpyes = {
    config: PropTypes.object
  }
  state = {
    visible: false,
    loading: false,
    empty: false
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  getTbs = (config) => {
    let tbs = []
    let ptbs = []
    let traversal = (components) => {
      components.forEach(item => {
        if (item.$tables) {
          ptbs.push(...item.$tables)
          item.$tables.forEach(tb => {
            tbs.push({
              label: item.name,
              table: tb,
              color: '#5AD8A6',
              id: Utils.getuuid(),
              direction: 'left'
            })
          })
        }
        if (item.type === 'tabs') {
          item.subtabs.forEach(tab => {
            traversal(tab.components)
          })
        } else if (item.type === 'group') {
          traversal(item.components)
        }
      })
    }
    traversal(config.components)
    return {tbs, ptbs}
  }
  trigger = () => {
    const { config } = this.props
    this.setState({visible: true, loading: true, empty: false}, () => {
      let param = {
        func: 's_get_menus_tb_list',
        TypeCharOne: sessionStorage.getItem('kei_no') || '',
        typename: sessionStorage.getItem('typename') || '',
        MenuID: config.uuid
      }
      Api.getSystemConfig(param).then(result => {
        if (!result.status) {
          notification.warning({
            top: 92,
            message: result.message,
            duration: 5
          })
          this.setState({empty: true, loading: false})
          return
        }
        let data = {
          label: config.MenuName || '空',
          id: config.uuid,
          MenuID: config.MenuID,
          children: []
        }
        let { tbs, ptbs } = this.getTbs(config)
        ptbs = Array.from(new Set(ptbs))
        ptbs.sort()
        if (ptbs.length && sessionStorage.getItem('mk_tb_names')) {
          let names = sessionStorage.getItem('mk_tb_names')
          ptbs = ptbs.filter(tb => names.indexOf(',' + tb.toLowerCase() + ',') > -1)
        }
        if (ptbs.length) {
          ptbs.forEach((item, i) => {
            let cell = {
              label: item,
              id: 'par' + i,
              direction: 'left',
              color: '#5AD8A6',
              children: []
            }
            tbs.forEach(t => {
              if (t.table === item) {
                cell.children.push(t)
              }
            })
            data.children.push(cell)
          })
        }
        if (ptbs.length) {
          ptbs.forEach((item, i) => {
            let cell = {
              label: item,
              id: 'menu' + i,
              direction: 'right',
              color: '#1890ff',
              // children: []
            }
            data.children.push(cell)
          })
        }
        if (data.children.length === 0) {
          this.setState({empty: true, loading: false})
        } else {
          this.setState({loading: false})
          this.getForks(data)
        }
      })
    })
  }
  changeMenu = (menu) => {
    if (menu.depth === 0) return
    MKEmitter.emit('changeEditMenu', menu)
  }
  getForks = (data) => {
    const { Util } = G6
    const that = this
    G6.registerNode(
      'dice-mind-map-root', {
        jsx: (cfg) => {
          const width = Util.getTextSize(cfg.label, 14)[0] + 12;
          const stroke = cfg.style.stroke || '#096dd9';
          return `
          <group>
            <rect draggable="true" style={{width: ${width}, height: 30, stroke: ${stroke}, radius: 4}} keyshape>
              <text style={{ fontSize: 14, marginLeft: 6, marginTop: 6 }}>${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;
          const color = cfg.color;
          return `
          <group>
            <rect draggable="true" style={{width: ${width}, height: 26, cursor: ${cfg.direction !== 'left' ? 'pointer' : 'default'}, fill: 'transparent' }}>
              <text style={{ fontSize: 12, fill: black, cursor: ${cfg.direction !== 'left' ? 'pointer' : 'default'}, marginLeft: 12, marginTop: 6 }}>${cfg.label}</text>
            </rect>
            <rect style={{ fill: ${color}, width: ${width}, cursor: ${cfg.direction !== 'left' ? 'pointer' : 'default'}, height: 2, x: 0, y: 32 }} />
          </group>
        `;
        },
        getAnchorPoints() {
          return [
            [0, 0.965],
            [1, 0.965],
          ];
        },
      },
      'single-node',
    );
    G6.registerBehavior('dice-mindmap', {
      getEvents() {
        return {
          'node:dblclick': 'editNode',
        };
      },
      editNode(evt) {
        const item = evt.item;
        const model = item.get('model');
        that.changeMenu(model)
      }
    });
    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();
      },
    });
    const dataTransform = (data) => {
      const changeData = (d, level = 0, color) => {
        const data = {
          ...d,
        };
        switch (level) {
          case 0:
            data.type = 'dice-mind-map-root';
            break;
          default:
            data.type = 'dice-mind-map-leaf';
            break;
        }
        data.hover = false;
        if (color) {
          data.color = color;
        }
        if (d.children) {
          data.children = d.children.map((child) => changeData(child, level + 1, data.color));
        }
        return data;
      };
      return changeData(data);
    };
    const tree = new G6.TreeGraph({
      container: 'mountNode',
      width: this.wrap.offsetWidth,
      height: this.wrap.offsetHeight,
      fitView: true,
      fitViewPadding: [10, 20],
      layout: {
        type: 'mindmap',
        direction: 'H',
        getHeight: () => {
          return 16;
        },
        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;
        },
      },
      defaultEdge: {
        type: 'cubic-horizontal',
        style: {
          lineWidth: 2,
        },
      },
      minZoom: 0.5,
      modes: {
        default: ['drag-canvas', 'zoom-canvas', 'dice-mindmap'],
      },
    });
    tree.data(dataTransform(data));
    tree.render();
  }
  render() {
    const { visible, loading, empty } = this.state
    return (
      <div style={{display: 'inline-block'}}>
        <Button style={{borderColor: '#8E44AD', color: '#8E44AD'}} onClick={this.trigger}><ForkOutlined /> 表关系图</Button>
        <Modal
          title=""
          wrapClassName="view-table-modal"
          visible={visible}
          width={'90vw'}
          closable={false}
          maskClosable={false}
          footer={[]}
          destroyOnClose
        >
          <div className="header">页面关系图</div>
          <div className="wrap">
            {loading ? <Spin size="large" /> : null}
            {empty ? <div className="empty">未查询到页面关联菜单。</div> : null}
            <div className="mountNode" id="mountNode" ref={ref => this.wrap = ref}></div>
          </div>
          <div className="footer">
            <Button key="cancel" onClick={() => { this.setState({ visible: false })}}>关闭</Button>
          </div>
        </Modal>
      </div>
    )
  }
}
export default TableNodes
src/menu/tablenodes/index.scss
New file
@@ -0,0 +1,47 @@
.view-table-modal {
  .ant-modal {
    top: 55px;
  }
  .ant-modal-body {
    padding: 20px 50px 20px;
    user-select: none;
  }
  .ant-modal-footer {
    display: none;
  }
  .wrap {
    position: relative;
    height: calc(100vh - 200px);
    margin: 10px 0px;
    overflow: hidden;
    .mountNode {
      height: 100%;
    }
    .ant-spin {
      position: absolute;
      top: calc(50% - 16px);
      left: calc(50% - 16px);
    }
    .empty {
      position: relative;
      text-align: center;
      color: #959595;
      padding-top: 200px;
    }
    .empty + .mountNode {
      opacity: 0;
    }
  }
  .header {
    color: #1890ff;
    font-weight: 500;
    text-align: center;
    font-size: 18px;
  }
  .footer {
    text-align: center;
  }
}
src/templates/sharecomponent/tablecomponent/index.jsx
@@ -98,7 +98,7 @@
            res.TBName = item.TbName
            resolve(res)
          })
        }, i * 50)
        }, (i + 1) * 100)
      })
    })
    Promise.all(deffers).then(response => {
src/templates/zshare/verifycard/index.jsx
@@ -1517,7 +1517,7 @@
    return (
      <div>
        {card.label ? <div className="mk-com-name">{card.label} - 验证信息</div> : null}
        <Tabs activeKey={activeKey} className="verify-card-box" onChange={this.changeTab}>
        <Tabs activeKey={activeKey} className="mk-verify-tabs" onChange={this.changeTab}>
          {verifyInter === 'system' || card.intertype === 'inner' ? <TabPane tab={
            <span>
              基础验证
src/templates/zshare/verifycard/index.scss
@@ -1,4 +1,7 @@
.verify-card-box {
.mk-verify-tabs {
  .ant-tabs-nav .ant-tabs-tab {
    margin-right: 25px;
  }
  .ant-tabs-nav-scroll {
    text-align: center;
  }
@@ -226,4 +229,13 @@
    color: #1890ff;
    border-top: 1px solid #e9e9e9;
  }
}
@media screen and (max-width: 1500px) {
  .mk-verify-tabs {
    .ant-tabs-nav .ant-tabs-tab {
      margin: 0 15px 0 0;
      padding: 12px 12px;
    }
  }
}
src/utils/utils.js
@@ -2093,9 +2093,8 @@
    let end = new RegExp('@breakpoint_end_' + window.GLOB.breakpoint + '\\$\\*\\/', 'ig')
    
    _sql = _sql.replace(start, '').replace(end, '')
    if (retmsg) {
      _callbacksql = _callbacksql.replace(start, '').replace(end, '')
    }
    _sql += `
      z_debug_end: select @ErrorCode='E',@retmsg='debug_end' goto aaa`
  }
  if (window.GLOB.debugger === true || (window.debugger === true && options.sysType !== 'cloud')) {
src/views/menudesign/index.jsx
@@ -40,6 +40,7 @@
const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
const Versions = asyncComponent(() => import('@/menu/versions'))
const TableNodes = asyncComponent(() => import('@/menu/tablenodes'))
const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
const PictureController = asyncComponent(() => import('@/menu/picturecontroller'))
@@ -109,7 +110,6 @@
  componentDidMount () {
    MKEmitter.addListener('delButtons', this.delButtons)
    MKEmitter.addListener('modalStatus', this.modalStatus)
    // MKEmitter.addListener('thawButtons', this.thawButtons)
    MKEmitter.addListener('copyButtons', this.copyButtons)
    MKEmitter.addListener('changePopview', this.initPopview)
    MKEmitter.addListener('triggerMenuSave', this.triggerMenuSave)
@@ -180,7 +180,6 @@
    }
    MKEmitter.removeListener('delButtons', this.delButtons)
    MKEmitter.removeListener('modalStatus', this.modalStatus)
    // MKEmitter.removeListener('thawButtons', this.thawButtons)
    MKEmitter.removeListener('copyButtons', this.copyButtons)
    MKEmitter.removeListener('changePopview', this.initPopview)
    MKEmitter.removeListener('triggerMenuSave', this.triggerMenuSave)
@@ -356,10 +355,6 @@
  copyButtons = (items) => {
    this.setState({copyButtons: [...this.state.copyButtons, ...items]})
  }
  // thawButtons = (item) => {
  //   this.setState({thawButtons: [...this.state.thawButtons, item]})
  // }
  initPopview = (card, btn) => {
    const { oriConfig, config } = this.state
@@ -757,28 +752,6 @@
          }
          return Api.getSystemConfig(_param)
        }
      // }).then(res => { // 按钮解除冻结
      //   if (!res) return
      //   if (!res.status) {
      //     notification.warning({
      //       top: 92,
      //       message: res.message,
      //       duration: 5
      //     })
      //     return false
      //   }
      //   let ids = thawButtons.filter(item => btnIds.indexOf(item) !== -1)
      //   if (ids.length === 0) {
      //     return {
      //       status: true
      //     }
      //   } else {
      //     return Api.getSystemConfig({
      //       func: 'sPC_MainMenu_ReDel',
      //       MenuID: ids.join(',')
      //     })
      //   }
      }).then(res => { // 页面保存
        if (!res) return
@@ -1159,12 +1132,11 @@
                </Collapse>
              </div>
              <div className={'menu-view' + (menuloading ? ' saving' : '') + (eyeopen ? ' eye-open' : '')}>
                <Card title={
                  <div style={{paddingLeft: '15px'}}> {config && config.MenuName} </div>
                } bordered={false} extra={
                  <div>
                <Card title={config ? config.MenuName : ''} bordered={false} extra={
                  <div className="mk-opeartion-list">
                    <Button className="mk-border-purple" onClick={() => this.setState({eyeopen: !eyeopen})}>{!eyeopen ? <EyeOutlined /> : <EyeInvisibleOutlined />} 组件名</Button>
                    <Versions MenuId={MenuId} open_edition={config ? config.open_edition : ''}/>
                    <TableNodes config={config} />
                    <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
                    <SysInterface config={config} updateConfig={this.updateConfig}/>
                    <PictureController/>
src/views/menudesign/index.scss
@@ -219,4 +219,16 @@
    background: transparent!important;
    border-radius: 0!important;
  }
}
@media screen and (max-width: 1500px) {
  .mk-opeartion-list .ant-btn {
    min-width: 65px;
    .anticon {
      display: none;
    }
    .anticon + span {
      margin-left: 0px;
    }
  }
}