king
2020-10-26 1b89aa4493d1c9768447f2f480d594cdb8077fdc
2020-10-26
26个文件已修改
4个文件已添加
1983 ■■■■■ 已修改文件
src/components/header/index.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.scss 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tabview/index.jsx 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/chartcompile/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/index.jsx 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/antv-tabs/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/colorsketch/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/reducer.js 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.scss 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar-line/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar-line/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-pie/index.jsx 475 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-pie/index.scss 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/tabtransfer/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/tabs/antv-tabs/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/home/defaulthome/index.jsx 286 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/home/defaulthome/index.scss 235 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/home/index.jsx 338 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/home/index.scss 235 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/menuconfig/editthdmenu/preview/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/menuconfig/menuelement/card.jsx 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/fieldtable/index.jsx 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/option.js 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 96 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx
@@ -740,9 +740,15 @@
        {this.props.editLevel === 'HS' ? <Button className="level4-close" type="primary" onClick={this.exitManage}>退出</Button> : null}
        {/* 进入编辑按钮 */}
        {this.props.editState && !this.props.editLevel ? <Icon onClick={this.enterEdit} className="edit-check" type="edit" /> : null}
        {/* {this.props.editState && !this.props.editLevel && options.sysType === 'local' && window.GLOB.systemType !== 'production' ?
        {this.props.editState && !this.props.editLevel && options.sysType === 'local' && window.GLOB.systemType !== 'production' ?
          <a href="#/mobmanage" target="_blank" className="mobile" type="edit"> 应用管理 <Icon type="arrow-right" /></a> : null
        } */}
        }
        {/* window.btoa(window.encodeURIComponent(JSON.stringify({ MenuType: 'home', MenuId: 'home_page_id', MenuName: '首页' }))) */}
        {this.props.editState && !this.props.editLevel && window.GLOB.systemType !== 'production' ?
          <a className="home-edit" href={`#/menudesign/JTdCJTIyTWVudVR5cGUlMjIlM0ElMjJob21lJTIyJTJDJTIyTWVudUlkJTIyJTNBJTIyaG9tZV9wYWdlX2lkJTIyJTJDJTIyTWVudU5hbWUlMjIlM0ElMjIlRTklQTYlOTYlRTklQTElQjUlMjIlN0Q=`} target="_blank" rel="noopener noreferrer">
            首页 <Icon type="arrow-right" />
          </a> : null
        }
        {/* 编辑菜单 */}
        {this.props.editLevel === 'level1' ? <EditMenu menulist={this.state.menulist} reload={this.reload} exitEdit={this.exitEdit}/> : null}
        {/* 头像、用户名 */}
src/components/header/index.scss
@@ -158,7 +158,7 @@
        padding: 0px 25px;
        height: 26px;
        line-height: 26px;
        color: #000000;
        color: rgba(0, 0, 0, 0.85);
        cursor: pointer;
      }
      .ant-menu-item:hover {
@@ -182,6 +182,12 @@
  }
  .mobile {
    position: absolute;
    top: 135px;
    right: 50px;
    color: #1890ff;
  }
  .home-edit {
    position: absolute;
    top: 100px;
    right: 50px;
    color: #1890ff;
src/components/tabview/index.jsx
@@ -169,14 +169,9 @@
  componentDidMount () {
    let home = {
      MenuID: '1576117946681plembmkk9akkv8sn0vtdfdsfaf',
      MenuID: 'home_page_id',
      MenuName: '首页',
      MenuNo: 'MESOrderDetailMwe',
      PageParam: {},
      id: 1,
      selected: true,
      src: '',
      text: '首页',
      type: 'Home'
    }
    this.props.modifyTabview([home])
@@ -236,7 +231,7 @@
                    key={view.MenuID}
                  >
                    {this.selectcomponent(view)}
                    {options.sysType !== 'cloud' && menuType !== 'HS' && !['CommonTable', 'TreePage', 'ManageTable', 'CalendarPage'].includes(view.type) ?
                    {options.sysType !== 'cloud' && menuType !== 'HS' && !['CommonTable', 'TreePage', 'ManageTable', 'CalendarPage', 'Home'].includes(view.type) ?
                      <Button
                        icon="copy"
                        shape="circle"
src/menu/components/chart/antv-bar/index.scss
@@ -2,6 +2,9 @@
  position: relative;
  box-sizing: border-box;
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  border-style: solid;
  border-width: 0;
  
src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx
@@ -9,7 +9,6 @@
 * @param {Array}  columns    // 显示列
 */
export function getPieChartOptionForm (card, columns) {
  let xfields = columns.filter(item => /^Nvarchar/ig.test(item.datatype))
  let yfields = columns.filter(item => /^(Int|Decimal)/ig.test(item.datatype))
src/menu/components/chart/antv-pie/chartcompile/index.jsx
@@ -43,6 +43,12 @@
          }
          return item
        })
      }, () => {
        if (val === 'ring') {
          this.props.form.setFieldsValue({innerRadius: 50})
        } else if (val === 'nightingale') {
          this.props.form.setFieldsValue({innerRadius: 0})
        }
      })
    }
  }
src/menu/components/chart/antv-pie/index.jsx
@@ -40,7 +40,12 @@
        shape: card.subtype, // 图表类型
        width: 12,
        height: 400,
        label: 'outer',
        name: card.name
      }
      if (card.subtype === 'ring') {
        _plot.innerRadius = 50
      }
      let dataName = ''
@@ -153,14 +158,8 @@
  pierender = () => {
    const { card } = this.state
    let plot = {...card.plot, height: card.plot.height - 80}
    // let color = plot.color || 'rgba(0, 0, 0, 0.85)'
    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
    let transfield = {}
    card.columns.forEach(col => {
      if (col.field) {
        transfield[col.field] = col.label
      }
    })
    let X_axis = plot.Xaxis || 'x'
    let Y_axis = plot.Yaxis || 'y'
@@ -197,12 +196,12 @@
    if (plot.shape === 'nightingale') {
      chart.coordinate('polar', {
        innerRadius: plot.innerRadius ? (plot.innerRadius / 100) : 0,
        radius: plot.radius ? (plot.radius / 100) : 0.75,
        radius: plot.radius ? (plot.radius / 100) : 0.85,
      })
    } else {
      chart.coordinate('theta', {
        innerRadius: plot.shape !== 'pie' && plot.innerRadius ? (plot.innerRadius / 100) : 0,
        radius: plot.radius ? (plot.radius / 100) : 0.75,
        radius: plot.radius ? (plot.radius / 100) : 0.85,
      })
    }
@@ -211,10 +210,20 @@
    } else if (plot.shape === 'nightingale') {
      chart.legend(X_axis, {
        position: plot.legend,
        itemName: {
          style: {
            fill: color,
          }
        }
      })
    } else {
      chart.legend({
        position: plot.legend
        position: plot.legend,
        itemName: {
          style: {
            fill: color,
          }
        }
      })
    }
@@ -292,6 +301,9 @@
              style: {
                lineWidth: 0.5,
              },
            },
            style: {
              fill: color
            }
          })
        }
@@ -308,8 +320,10 @@
        if (plot.label !== 'false') {
          let _label = {}
          if (plot.label === 'inner') {
            _label = {
              offset: -15,
            _label.offset = -15
          } else {
            _label.style = {
              fill: color
            }
          }
src/menu/components/chart/antv-pie/index.scss
@@ -2,6 +2,9 @@
  position: relative;
  box-sizing: border-box;
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  border-style: solid;
  border-width: 0;
  
src/menu/components/tabs/antv-tabs/index.scss
@@ -2,6 +2,9 @@
  position: relative;
  box-sizing: border-box;
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  border-style: solid;
  border-width: 0;
src/mob/colorsketch/index.jsx
@@ -9,7 +9,7 @@
const presetColors = [
  '#f5222d', '#fa541c', '#fa8c16', '#faad14', '#fadb14', '#a0d911', '#52c41a', '#13c2c2', '#1890ff', '#2f54eb', '#722ed1',
  '#eb2f96', '#595959', '#ffa39e', '#ffbb96', '#ffd591', '#ffe58f', '#fffb8f', '#eaff8f', '#b7eb8f', '#87e8de', '#91d5ff',
  '#adc6ff', '#d3adf7', '#ffadd2', '#d9d9d9', '#000000', '#ffffff', 'transparent'
  '#adc6ff', '#d3adf7', '#ffadd2', '#d9d9d9', '#434343', '#000000', '#ffffff', 'transparent'
]
class ColorSketch extends Component {
src/router/index.js
@@ -23,7 +23,7 @@
  {path: '/main', name: 'main', component: Main, auth: true},
  {path: '/mobmanage', name: 'mobmanage', component: MobManage, auth: true},
  {path: '/mobdesign/:appId/:appType/:appCode/:appName', name: 'mobdesign', component: MobDesign, auth: true},
  {path: '/menudesign/:MenuId/:ParentId/:MenuName/:MenuNo', name: 'menudesign', component: MenuDesign, auth: true},
  {path: '/menudesign/:param', name: 'menudesign', component: MenuDesign, auth: true},
  {path: '/paramsmain/:param', name: 'pmain', component: Main, auth: true}
]
src/store/reducer.js
@@ -91,11 +91,9 @@
        state.tabviews = []
      } else {
        state.tabviews = [{
          MenuID: '1576117946681plembmkk9akkv8sn0vtdfdsfaf',
          MenuID: 'home_page_id',
          MenuName: '首页',
          MenuNo: 'MESOrderDetailMwe',
          selected: true,
          text: '首页',
          type: 'Home'
        }]
      }
src/tabviews/custom/components/card/data-card/index.scss
@@ -1,5 +1,8 @@
.custom-card-box {
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 100px;
  display: flex;
  position: relative;
@@ -16,7 +19,8 @@
    }
    img {
      width: 15px;
      height: 100px;
      padding: 0 2px;
      height: 70px;
      cursor: pointer;
    }
  }
src/tabviews/custom/components/chart/antv-bar-line/index.jsx
@@ -109,6 +109,12 @@
      _config.plot.height = _config.plot.height - 30
    }
    if (_config.style) {
      _config.style = {..._config.style, minHeight: (config.plot.height || 400)}
    } else {
      _config.style = {minHeight: (config.plot.height || 400)}
    }
    this.setState({
      config: _config,
      data: _data,
src/tabviews/custom/components/chart/antv-bar-line/index.scss
@@ -1,7 +1,11 @@
.custom-line-chart-plot-box {
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  border-style: solid;
  border-width: 0;
  min-height: 100px;
  > .chart-header {
    height: 45px;
src/tabviews/custom/components/chart/antv-pie/index.jsx
New file
@@ -0,0 +1,475 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Chart } from '@antv/g2'
import DataSet from '@antv/data-set'
import { Spin, Empty, notification } from 'antd'
// import searchLine from '../../share/searchLine'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import UtilsDM from '@/utils/utils-datamanage.js'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import './index.scss'
class LineChart extends Component {
  static propTpyes = {
    BID: PropTypes.any,              // 父级Id
    data: PropTypes.array,           // 统一查询数据
    config: PropTypes.object,        // 组件配置信息
    mainSearch: PropTypes.any,       // 全局搜索条件
    menuType: PropTypes.any,         // 菜单类型
    dataManager: PropTypes.any,      // 数据权限
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, // 字典
    config: null,              // 图表配置信息
    empty: true,               // 图表数据为空
    loading: false,            // 数据加载状态
    chartId: Utils.getuuid(),  // 图表Id
    title: '',                 // 组件标题
    sync: false,               // 是否统一请求数据
    plot: null,                // 图表设置
    data: null,                // 数据
    search: null,              // 搜索条件
    showHeader: false          // 存在标题、搜索、或统计数据时显示
  }
  UNSAFE_componentWillMount () {
    const { config, data } = this.props
    let _config = fromJS(config).toJS()
    let _data = null
    let _sync = config.setting.sync === 'true'
    if (config.setting.sync === 'true' && data) {
      _data = data[config.dataName] || []
      _sync = false
    }
    let showHeader = false
    if (config.plot.title || config.search.length > 0) {
      showHeader = true
      _config.plot.height = _config.plot.height - 80
    } else {
      _config.plot.height = _config.plot.height - 30
    }
    if (_config.style) {
      _config.style = {..._config.style, minHeight: (config.plot.height || 400)}
    } else {
      _config.style = {minHeight: (config.plot.height || 400)}
    }
    this.setState({
      config: _config,
      data: _data,
      arr_field: _config.columns.map(col => col.field).join(','),
      plot: _config.plot,
      sync: _sync,
      title: config.plot.title,
      search: Utils.initMainSearch(config.search),
      showHeader
    }, () => {
      if (config.setting.sync !== 'true') {
        this.loadData()
      } else if (config.setting.sync === 'true') {
        if (!_data) {
          this.setState({
            loading: true
          })
        } else {
          this.handleData()
        }
      }
    })
  }
  /**
   * @description 校验图表的按钮组,如果为统计图表,计算图表字段
   */
  componentDidMount () {
  }
  /**
   * @description 图表数据更新,刷新内容
   */
  UNSAFE_componentWillReceiveProps (nextProps) {
    const { sync, config } = this.state
    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
      let _data = []
      if (nextProps.data && nextProps.data[config.dataName]) {
        _data = nextProps.data[config.dataName] || []
      }
      this.setState({sync: false, loading: false, data: _data}, () => {
        this.handleData()
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  handleData = () => {
    let _element = document.getElementById(this.state.chartId)
    if (_element) {
      _element.innerHTML = ''
    }
    this.pierender()
  }
  async loadData () {
    const { mainSearch, BID, menuType, dataManager } = this.props
    const { config, arr_field, search } = this.state
    let searches = fromJS(search).toJS()
    if (mainSearch && mainSearch.length > 0) { // 主表搜索条件
      searches = [...mainSearch, ...searches]
    }
    this.setState({
      loading: true
    })
    let _orderBy = config.setting.order || ''
    let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, '', '', BID, menuType, dataManager)
    let result = await Api.genericInterface(param)
    if (result.status) {
      this.setState({
        data: result.data,
        loading: false
      }, () => {
        this.handleData()
      })
    } else {
      this.setState({
        loading: false
      })
      notification.error({
        top: 92,
        message: result.message,
        duration: 10
      })
    }
  }
  /**
   * @description 图表数据预处理
   * 1、通过显示列进行数据类型转换
   * 2、重复数据:取平均值、累计、去重
   * 3、柱状图数据补齐
   */
  getdata = () => {
    const { data, plot, config } = this.state
    if (!data) {
      this.setState({empty: true})
      return []
    }
    let decimal = 0
    config.columns.forEach(col => {
      if (plot.Yaxis === col.field && /Decimal/ig.test(col.datatype)) {
        decimal = +col.datatype.replace(/^Decimal\(18,/ig, '').replace(/\)/ig, '')
      }
    })
    let _data = []
    let _cdata = fromJS(data).toJS()
    if (plot.repeat === 'average') {
      let _mdata = new Map()
      _cdata.forEach(item => {
        if (typeof(item[plot.Yaxis]) !== 'number') {
          item[plot.Yaxis] = parseFloat(item[plot.Yaxis])
          if (isNaN(item[plot.Yaxis])) {
            item[plot.Yaxis] = 0
          }
        }
        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
          item.$count = 1
          _mdata.set(item[plot.Xaxis], item)
        } else if (item[plot.Xaxis]) {
          let _item = _mdata.get(item[plot.Xaxis])
          _item.$count++
          _item[plot.Yaxis] += item[plot.Yaxis]
          _mdata.set(item[plot.Xaxis], _item)
        }
      })
      _data = [..._mdata.values()]
      _data = _data.map(item => {
        item[plot.Yaxis] = item[plot.Yaxis] / item.$count
        item[plot.Yaxis] = item[plot.Yaxis].toFixed(decimal)
        item[plot.Yaxis] = +item[plot.Yaxis]
        return item
      })
    } else if (plot.repeat === 'cumsum') {
      let _mdata = new Map()
      _cdata.forEach(item => {
        if (typeof(item[plot.Yaxis]) !== 'number') {
          item[plot.Yaxis] = parseFloat(item[plot.Yaxis])
          if (isNaN(item[plot.Yaxis])) {
            item[plot.Yaxis] = 0
          }
        }
        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
          _mdata.set(item[plot.Xaxis], item)
        } else if (item[plot.Xaxis]) {
          let _item = _mdata.get(item[plot.Xaxis])
          _item[plot.Yaxis] += item[plot.Yaxis]
          _mdata.set(item[plot.Xaxis], _item)
        }
      })
      _data = [..._mdata.values()]
      _data = _data.map(item => {
        item[plot.Yaxis] = item[plot.Yaxis].toFixed(decimal)
        item[plot.Yaxis] = +item[plot.Yaxis]
        return item
      })
    } else { // plot.repeat === 'unrepeat'
      let _mdata = new Map()
      _cdata.forEach(item => {
        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
          if (typeof(item[plot.Yaxis]) !== 'number') {
            item[plot.Yaxis] = parseFloat(item[plot.Yaxis])
            if (isNaN(item[plot.Yaxis])) {
              item[plot.Yaxis] = 0
            }
          }
          item[plot.Yaxis] = item[plot.Yaxis].toFixed(decimal)
          item[plot.Yaxis] = +item[plot.Yaxis]
          _mdata.set(item[plot.Xaxis], item)
        }
      })
      _data = [..._mdata.values()]
    }
    this.setState({empty: _data.length === 0})
    return _data
  }
  /**
   * @description 饼图渲染
   */
  pierender = () => {
    const { plot, chartId } = this.state
    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
    let X_axis = plot.Xaxis || 'x'
    let Y_axis = plot.Yaxis || 'y'
    let data = this.getdata(X_axis, Y_axis)
    const ds = new DataSet()
    const dv = ds.createView().source(data)
    const chart = new Chart({
      container: chartId,
      autoFit: true,
      height: plot.height || 400
    })
    if (plot.shape !== 'nightingale' && plot.show !== 'value') {
      dv.transform({
        type: 'percent',
        field: Y_axis,
        dimension: X_axis,
        as: 'percent'
      })
      chart.scale('percent', {
        formatter: (val) => {
          val = val * 100 + '%'
          return val
        }
      })
      Y_axis = 'percent' // 显示百分比
    }
    chart.data(dv.rows)
    if (plot.shape === 'nightingale') {
      chart.coordinate('polar', {
        innerRadius: plot.innerRadius ? (plot.innerRadius / 100) : 0,
        radius: plot.radius ? (plot.radius / 100) : 0.75,
      })
    } else {
      chart.coordinate('theta', {
        innerRadius: plot.shape !== 'pie' && plot.innerRadius ? (plot.innerRadius / 100) : 0,
        radius: plot.radius ? (plot.radius / 100) : 0.75,
      })
    }
    if (!plot.legend || plot.legend === 'hidden') {
      chart.legend(false)
    } else if (plot.shape === 'nightingale') {
      chart.legend(X_axis, {
        position: plot.legend,
        itemName: {
          style: {
            fill: color,
          }
        }
      })
    } else {
      chart.legend({
        position: plot.legend,
        itemName: {
          style: {
            fill: color,
          }
        }
      })
    }
    if (plot.tooltip !== 'true') {
      chart.tooltip(false)
    } else {
      chart.tooltip({
        showTitle: false,
        showMarkers: false
      })
    }
    if (plot.shape !== 'nightingale') {
      let _chart = chart
        .interval()
        .adjust('stack')
        .position(Y_axis)
        .color(X_axis)
        .tooltip(`${X_axis}*${Y_axis}`, (name, value) => {
          if (plot.show !== 'value') {
            value = (value * 100).toFixed(2) + '%'
          }
          return {
            name: name,
            value: value
          }
        })
      if (plot.label !== 'false') {
        if (plot.label === 'inner') {
          _chart.label(Y_axis, {
            offset: -30,
            content: (data) => {
              let _label = ''
              let _val = ''
              if (plot.show !== 'value') {
                _val = `${(data[Y_axis] * 100).toFixed(2)}%`
              } else {
                _val = `${data[Y_axis]}`
              }
              if (plot.label === 'inner') {
                _label = _val
              } else {
                _label = `${data[X_axis]}: ${_val}`
              }
              return _label
            },
            style: {
              textAlign: 'center',
              fontSize: 16,
              shadowBlur: 2,
              shadowColor: 'rgba(0, 0, 0, .45)',
              fill: '#fff',
            }
          })
        } else {
          _chart.label(Y_axis, {
            layout: { type: 'pie-spider' },
            labelHeight: 20,
            content: (data) => {
              let _label = ''
              let _val = ''
              if (plot.show !== 'value') {
                _val = `${(data[Y_axis] * 100).toFixed(2)}%`
              } else {
                _val = `${data[Y_axis]}`
              }
              if (plot.label === 'inner') {
                _label = _val
              } else {
                _label = `${data[X_axis]}: ${_val}`
              }
              return _label
            },
            labelLine: {
              style: {
                lineWidth: 0.5,
              },
            },
            style: {
              fill: color
            }
          })
        }
      }
      chart.interaction('element-active')
    } else {
      chart.axis(false)
      chart.interaction('element-highlight')
      let _chart = chart
        .interval()
        .position(`${X_axis}*${Y_axis}`)
        .color(X_axis)
        if (plot.label !== 'false') {
          let _label = {}
          if (plot.label === 'inner') {
            _label.offset = -15
          } else {
            _label.style = {
              fill: color
            }
          }
          _chart.label(X_axis, _label)
          .style({
            lineWidth: 1,
            stroke: '#fff',
          })
        }
    }
    chart.render()
  }
  render() {
    const { showHeader, config, loading, title, empty } = this.state
    return (
      <div className="custom-pie-chart-plot-box" style={config.style}>
        {loading ?
          <div className="loading-mask">
            <div className="ant-spin-blur"></div>
            <Spin />
          </div> : null
        }
        {showHeader ? <div className="chart-header">
          <span className="chart-title">{title}</span>
          {/* <searchLine /> */}
        </div> : null}
        <div className="canvas-wrap">
          <div className={'canvas' + (empty ? ' empty' : '')} id={this.state.chartId}></div>
        </div>
        {empty ? <Empty description={false}/> : null}
      </div>
    )
  }
}
export default LineChart
src/tabviews/custom/components/chart/antv-pie/index.scss
New file
@@ -0,0 +1,133 @@
.custom-pie-chart-plot-box {
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  border-style: solid;
  border-width: 0;
  min-height: 100px;
  > .chart-header {
    height: 45px;
    border-bottom: 1px solid #e8e8e8;
    overflow: hidden;
    text-decoration: inherit;
    font-weight: inherit;
    font-style: inherit;
    .chart-title {
      // font-size: 16px;
      float: left;
      line-height: 45px;
      margin-left: 10px;
      text-decoration: inherit;
      font-weight: inherit;
      font-style: inherit;
    }
  }
  .canvas-wrap {
    margin: 0 0px;
    position: relative;
    .chart-action {
      position: absolute;
      top: 2px;
      right: 5px;
      z-index: 1;
    }
    .chart-action.with-title {
      top: 35px;
    }
  }
  .canvas {
    margin: 0;
    // border: 1px solid #e8e8e8;
    padding: 15px;
    letter-spacing: 0px;
  }
  .canvas.empty {
    div {
      opacity: 0;
    }
  }
  .ant-empty {
    position: absolute;
    top: calc(50% - 34px);
    left: calc(50% - 92px);
    .ant-empty-image {
      height: 60px;
    }
  }
  .loading-mask {
    position: absolute;
    left: 20px;
    top: 0;
    right: 20px;
    bottom: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: justify;
    z-index: 1;
    .ant-spin-blur {
      position: absolute;
      width: 100%;
      height: 100%;
      opacity: 0.5;
      background: #ffffff;
    }
  }
  .chart-title + .loading-mask {
    top: 40px;
  }
  > .ant-select {
    width: 150px;
    float: right;
    position: relative;
    z-index: 1;
    .ant-select-selection {
      min-height: 24px;
      height: 28px;
      li {
        background: unset;
        border: 0;
        width: 99%;
        padding: 0;
        margin-right: 0;
        cursor: pointer;
        .type-label {
          overflow: hidden;
          word-break: break-word;
          white-space: nowrap;
          text-overflow: ellipsis;
        }
      }
      li + li {
        margin-top: 0;
        width: 1%;
        opacity: 0;
      }
    }
  }
  > .ant-select.ant-select-focused {
    .ant-select-selection {
      li {
        width: 50%;
      }
      li + li {
        width: 49%;
        opacity: 1;
      }
    }
  }
  .g2-tooltip-list{
    display: none;
  }
  .g2-tooltip-title + .g2-tooltip-list{
    display: block;
  }
}
src/tabviews/custom/components/share/tabtransfer/index.jsx
@@ -8,6 +8,7 @@
// 通用组件
const AntvBarAndLine = asyncSpinComponent(() => import('@/tabviews/custom/components/chart/antv-bar-line'))
const AntvPie = asyncSpinComponent(() => import('@/tabviews/custom/components/chart/antv-pie'))
const AntvTabs = asyncSpinComponent(() => import('@/tabviews/custom/components/tabs/antv-tabs'))
class MainSearch extends Component {
@@ -37,6 +38,12 @@
            <AntvBarAndLine config={item} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
          </Col>
        )
      } else if (item.type === 'pie') {
        return (
          <Col span={item.width} key={item.uuid}>
            <AntvPie config={item} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
          </Col>
        )
      } else if (item.type === 'tabs') {
        return (
          <Col span={item.width} key={item.uuid}>
src/tabviews/custom/components/tabs/antv-tabs/index.scss
@@ -2,6 +2,9 @@
  position: relative;
  box-sizing: border-box;
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  border-style: solid;
  border-width: 0;
}
src/tabviews/custom/index.jsx
@@ -18,10 +18,11 @@
// 通用组件
const AntvBarAndLine = asyncSpinComponent(() => import('./components/chart/antv-bar-line'))
const AntvPie = asyncSpinComponent(() => import('./components/chart/antv-pie'))
const AntvTabs = asyncSpinComponent(() => import('./components/tabs/antv-tabs'))
const DataCard = asyncSpinComponent(() => import('./components/card/data-card'))
class NormalTable extends Component {
class CustomPage extends Component {
  static propTpyes = {
    param: PropTypes.any,        // 其他页面传递的参数
    MenuID: PropTypes.string,    // 菜单Id
@@ -445,6 +446,12 @@
            <AntvBarAndLine config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
          </Col>
        )
      } else if (item.type === 'pie') {
        return (
          <Col span={item.width} key={item.uuid}>
            <AntvPie config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
          </Col>
        )
      } else if (item.type === 'tabs') {
        return (
          <Col span={item.width} key={item.uuid}>
@@ -469,14 +476,14 @@
  render() {
    const { menuType } = this.props
    const { menuType, MenuNo } = this.props
    const { loadingview, viewlost, config } = this.state
    return (
      <div className="custom-page-wrap" id={this.state.ContainerId} style={config ? config.style : null}>
        {loadingview && <Spin size="large" />}
        <Row>{this.getComponents()}</Row>
        {options.sysType !== 'cloud' && menuType !== 'HS' ? <Button
        {MenuNo && options.sysType !== 'cloud' && menuType !== 'HS' ? <Button
          icon="copy"
          shape="circle"
          className="common-table-copy"
@@ -505,4 +512,4 @@
  }
}
export default connect(mapStateToProps, mapDispatchToProps)(NormalTable)
export default connect(mapStateToProps, mapDispatchToProps)(CustomPage)
src/tabviews/home/defaulthome/index.jsx
New file
@@ -0,0 +1,286 @@
import React, {Component} from 'react'
import { Chart } from '@antv/g2'
import { Icon, Tabs, Slider } from 'antd'
import './index.scss'
const { TabPane } = Tabs
class DefaultHome extends Component {
  componentDidMount () {
    const data = [
      { year: '2013 年', sales: 38 },
      { year: '2014 年', sales: 52 },
      { year: '2015 年', sales: 61 },
      { year: '2016 年', sales: 55 },
      { year: '2017 年', sales: 48 },
      { year: '2018 年', sales: 38 },
      { year: '2019 年', sales: 61 },
      { year: '2020 年', sales: 45 },
    ]
    const chart = new Chart({
      container: 'home_page_id',
      autoFit: true,
      height: 400,
    })
    chart.data(data);
    chart.scale('sales', {
      nice: true,
    })
    chart.tooltip({
      showMarkers: false,
      shared: true
    })
    chart.interval().position('year*sales').tooltip(`year*sales`, (name, value) => {
      return {
        name: '维修数',
        value: value
      }
    })
    chart.render()
  }
  render() {
    return (
      <div className="home-view">
        <div className="ant-row-flex">
          <div className="ant-col ant-col-sm-6">
            <div className="ant-card">
              <div className="ant-card-body">
                <div className="antd-chart-card">
                  <div className="antd-chart-top">
                    <div className="antd-meta-wrap">
                      <div className="antd-meta">
                        <span>
                          <span>维修总数</span>
                        </span>
                        <span className="antd-action">
                          <Icon type="info-circle-o" />
                        </span>
                      </div>
                      <div className="antd-total">
                        <span>100</span>
                      </div>
                    </div>
                  </div>
                  <div className="antd-chart-content">
                    <div className="antd-content-fixed">
                      <div className="antd-trend-item" style={{marginRight: '16px'}}>
                        <span>
                          <span>周同比</span>
                          <span className="antd-trend-text">10%</span>
                        </span>
                        <span className="antd-trend-up">
                          <Icon type="caret-up" />
                        </span>
                      </div>
                      <div className="antd-trend-item">
                        <span>
                          <span>日同比</span>
                          <span className="antd-trend-text">10%</span>
                        </span>
                        <span className="antd-trend-down">
                          <Icon type="caret-down" />
                        </span>
                      </div>
                    </div>
                  </div>
                  <div className="antd-chart-footer">
                    <div className="antd-field">
                      <span className="antd-label">
                        <span>维修总数</span>
                      </span>
                      <span className="antd-number">100</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div className="ant-col ant-col-sm-6">
            <div className="ant-card">
              <div className="ant-card-body">
                <div className="antd-chart-card">
                  <div className="antd-chart-top">
                    <div className="antd-meta-wrap">
                      <div className="antd-meta">
                        <span>
                          <span>超时工单</span>
                        </span>
                        <span className="antd-action">
                          <Icon type="info-circle-o" />
                        </span>
                      </div>
                      <div className="antd-total">
                        <span>100</span>
                      </div>
                    </div>
                  </div>
                  <div className="antd-chart-content">
                    <div className="antd-content-fixed orange">
                      <Slider defaultValue={67} tipFormatter={null} />
                      <div className="mask"></div>
                    </div>
                  </div>
                  <div className="antd-chart-footer">
                    <div className="antd-field">
                      <span className="antd-label">
                        <span>超时工单</span>
                      </span>
                      <span className="antd-number">100</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div className="ant-col ant-col-sm-6">
            <div className="ant-card">
              <div className="ant-card-body">
                <div className="antd-chart-card">
                  <div className="antd-chart-top">
                    <div className="antd-meta-wrap">
                      <div className="antd-meta">
                        <span>
                          <span>关单</span>
                        </span>
                        <span className="antd-action">
                          <Icon type="info-circle-o" />
                        </span>
                      </div>
                      <div className="antd-total">
                        <span>100</span>
                      </div>
                    </div>
                  </div>
                  <div className="antd-chart-content">
                    <div className="antd-content-fixed primary">
                      <Slider defaultValue={77} tipFormatter={null} />
                      <div className="mask"></div>
                    </div>
                  </div>
                  <div className="antd-chart-footer">
                    <div className="antd-field">
                      <span className="antd-label">
                        <span>关单</span>
                      </span>
                      <span className="antd-number">100</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div className="ant-col ant-col-sm-6">
            <div className="ant-card">
              <div className="ant-card-body">
                <div className="antd-chart-card">
                  <div className="antd-chart-top">
                    <div className="antd-meta-wrap">
                      <div className="antd-meta">
                        <span>
                          <span>原件邮寄</span>
                        </span>
                        <span className="antd-action">
                          <Icon type="info-circle-o" />
                        </span>
                      </div>
                      <div className="antd-total">
                        <span>100</span>
                      </div>
                    </div>
                  </div>
                  <div className="antd-chart-content">
                    <div className="antd-content-fixed">
                      <Slider defaultValue={87} tipFormatter={null} />
                      <div className="mask"></div>
                    </div>
                  </div>
                  <div className="antd-chart-footer">
                    <div className="antd-trend-item" style={{marginRight: '16px'}}>
                      <span>
                        <span>周同比</span>
                        <span className="antd-trend-text">10%</span>
                      </span>
                      <span className="antd-trend-up">
                        <Icon type="caret-up" />
                      </span>
                    </div>
                    <div className="antd-trend-item">
                      <span>
                        <span>日同比</span>
                        <span className="antd-trend-text">10%</span>
                      </span>
                      <span className="antd-trend-down">
                        <Icon type="caret-down" />
                      </span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <Tabs defaultActiveKey="1">
          <TabPane tab="维修总数" key="1">
            <div className="sale-trend ant-col ant-col-xs-16">
              <div id="home_page_id"></div>
            </div>
            <div className="ant-col ant-col-xs-8">
              <div className="antd-sales-rank">
                <h4 className="antd-ranking-title">产品排名</h4>
                <ul className="antd-ranking-list">
                  <li>
                    <span className="antd-ranking-active">1</span>
                    <span className="antd-ranking-title">KU699</span>
                    <span>723,234</span>
                  </li>
                  <li>
                    <span className="antd-ranking-active">2</span>
                    <span className="antd-ranking-title">KU110</span>
                    <span>683,434</span>
                  </li>
                  <li>
                    <span className="antd-ranking-active">3</span>
                    <span className="antd-ranking-title">KU110K</span>
                    <span>527,264</span>
                  </li>
                  <li>
                    <span className="antd-ranking-number">4</span>
                    <span className="antd-ranking-title">KU066.9</span>
                    <span>493,233</span>
                  </li>
                  <li>
                    <span className="antd-ranking-number">5</span>
                    <span className="antd-ranking-title">KU079</span>
                    <span>323,734</span>
                  </li>
                  <li>
                    <span className="antd-ranking-number">6</span>
                    <span className="antd-ranking-title">KU153</span>
                    <span>303,934</span>
                  </li>
                  <li>
                    <span className="antd-ranking-number">7</span>
                    <span className="antd-ranking-title">KU151</span>
                    <span>227,244</span>
                  </li>
                  <li>
                    <span className="antd-ranking-number">8</span>
                    <span className="antd-ranking-title">KU720</span>
                    <span>223,734</span>
                  </li>
                </ul>
              </div>
            </div>
          </TabPane>
        </Tabs>
      </div>
    )
  }
}
export default DefaultHome
src/tabviews/home/defaulthome/index.scss
New file
@@ -0,0 +1,235 @@
.home-view {
  position: relative;
  width: 100%;
  min-height: calc(100vh - 92px);
  height: 100%;
  background: #f0f2f5;
  padding: 24px;
  .ant-row-flex {
    display: flex;
    flex-flow: row wrap;
    margin-left: -12px;
    margin-right: -12px;
    .ant-col {
      padding-left: 12px;
      padding-right: 12px;
      margin-bottom: 24px;
      .ant-card {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
        color: rgba(0,0,0,.65);
        font-size: 14px;
        font-variant: tabular-nums;
        line-height: 1.5;
        list-style: none;
        font-feature-settings: "tnum";
        position: relative;
        background: #fff;
        border-radius: 2px;
        transition: all .3s;
        .ant-card-body {
          padding: 20px 24px 8px;
          .antd-chart-card {
            position: relative;
            box-sizing: border-box;
            .antd-chart-top {
              position: relative;
              width: 100%;
              overflow: hidden;
              box-sizing: border-box;
              .antd-meta-wrap {
                float: left;
                box-sizing: border-box;
                .antd-meta {
                  height: 22px;
                  color: rgba(0,0,0,.45);
                  font-size: 14px;
                  line-height: 22px;
                  .antd-action {
                    position: absolute;
                    top: 4px;
                    right: 0;
                    line-height: 1;
                    cursor: pointer;
                  }
                }
                .antd-total {
                  height: 38px;
                  margin-top: 4px;
                  margin-bottom: 0;
                  overflow: hidden;
                  color: rgba(0,0,0,.85);
                  font-size: 30px;
                  line-height: 38px;
                  white-space: nowrap;
                  text-overflow: ellipsis;
                  word-break: break-all;
                }
              }
            }
            .antd-chart-content {
              position: relative;
              height: 40px;
              .antd-content-fixed {
                position: absolute;
                bottom: 0;
                left: 0;
                width: 100%;
                .antd-trend-item {
                  display: inline-block;
                  font-size: 14px;
                  line-height: 22px;
                  .antd-trend-text {
                    margin-left: 5px;
                  }
                  .antd-trend-up {
                    color: #f5222d;
                  }
                  .antd-trend-down {
                    top: -1px;
                    color: #52c41a;
                  }
                }
                .mask {
                  position: absolute;
                  top: 0px;
                  left: 0px;
                  right: 0px;
                  bottom: 0px;
                  z-index: 1;
                }
              }
              .ant-slider {
                margin: 14px 0px 10px;
              }
              .ant-slider-track {
                height: 7px;
                background-color: #13C2C2;
              }
              .ant-slider-handle {
                border-color: #13C2C2;
              }
              .orange {
                .ant-slider-track {
                  background-color: orange;
                }
                .ant-slider-handle {
                  border-color: lightsalmon;
                }
              }
              .primary {
                .ant-slider-track {
                  background-color: #1890ff;
                }
                .ant-slider-handle {
                  border-color: #91d5ff;
                }
              }
              .ant-slider-rail {
                height: 7px;
              }
            }
            .antd-chart-footer {
              margin-top: 8px;
              padding-top: 9px;
              border-top: 1px solid #e8e8e8;
              .antd-label {
                font-size: 14px;
                line-height: 22px;
                margin-right: 10px;
              }
              .antd-trend-item {
                display: inline-block;
                font-size: 14px;
                line-height: 22px;
                .antd-trend-text {
                  margin-left: 5px;
                }
                .antd-trend-up {
                  color: #f5222d;
                }
                .antd-trend-down {
                  top: -1px;
                  color: #52c41a;
                }
              }
            }
          }
        }
      }
    }
  }
  .ant-tabs {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    color: rgba(0, 0, 0, 0.65);
    font-size: 14px;
    font-variant: tabular-nums;
    line-height: 1.5;
    list-style: none;
    font-feature-settings: "tnum";
    position: relative;
    background: #fff;
    border-radius: 2px;
    transition: all .3s;
    .sale-trend {
      min-height: 400px;
      padding: 10px 20px;
      margin-bottom: 20px;
    }
    .antd-sales-rank {
      padding: 35px 32px 32px 72px;
      .antd-ranking-title {
        font-size: 16px;
      }
      .antd-ranking-list {
        margin: 20px 0 0;
        padding: 0;
        list-style: none;
        li {
          display: flex;
          align-items: center;
          margin-top: 16px;
          zoom: 1;
          .antd-ranking-active {
            display: inline-block;
            width: 20px;
            height: 20px;
            margin-top: 1.5px;
            margin-right: 16px;
            font-weight: 600;
            font-size: 12px;
            line-height: 20px;
            text-align: center;
            color: #fff;
            background-color: #314659;
            border-radius: 20px;
          }
          .antd-ranking-number {
            display: inline-block;
            width: 20px;
            height: 20px;
            margin-top: 1.5px;
            margin-right: 16px;
            font-weight: 600;
            font-size: 14px;
            line-height: 20px;
            text-align: center;
          }
          .antd-ranking-title {
            flex: 1 1;
            margin-right: 8px;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
            color: rgba(0,0,0,.65);
            font-size: 14px;
            line-height: 22px;
          }
        }
      }
    }
  }
}
src/tabviews/home/index.jsx
@@ -1,312 +1,66 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import echarts from 'echarts/lib/echarts'
import 'echarts/lib/chart/bar'
import 'echarts/lib/component/tooltip'
// import 'echarts/lib/chart/line'
// import 'echarts/lib/component/title'
// import 'echarts/lib/component/legend'
// import 'echarts/lib/component/toolbox'
// import 'echarts/lib/component/markPoint'
// import 'echarts/lib/component/markLine'
import { Icon, Tabs, Slider } from 'antd'
import { notification, Spin } from 'antd'
import Api from '@/api'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const { TabPane } = Tabs
const DefaultHome = asyncComponent(() => import('./defaulthome'))
const CustomPage = asyncComponent(() => import('@/tabviews/custom'))
class Home extends Component {
  static propTpyes = {
    MenuNo: PropTypes.string, // 菜单参数
    MenuID: PropTypes.string, // 菜单Id
    param: PropTypes.object // 菜单参数
  }
  state = {}
  state = {
    loading: true,
    view: ''
  }
  componentDidMount () {
    let myChart = echarts.init(document.getElementById('home'))
    // 绘制图表
    myChart.setOption({
      color: ['#1890ff'],
      tooltip : {
        trigger: 'axis',
        axisPointer : {    // 坐标轴指示器,坐标轴触发有效
          type : ''        // 默认为直线,可选为:'line' | 'shadow'
    let _param = {
      func: 'sPC_Get_LongParam',
      MenuID: this.props.MenuID
    }
    Api.getCacheConfig(_param).then(result => {
      if (result.status) {
        if (result.LongParam) {
          this.setState({
            loading: false,
            view: 'custom'
          })
        } else {
          this.setState({
            loading: false,
            view: 'default'
          })
        }
      },
      grid: {
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
      },
      xAxis : [
        {
          type : 'category',
          data : ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
          axisTick: {
            alignWithLabel: true
          }
        }
      ],
      yAxis : [
        {
          type : 'value',
          splitLine: {
            show: true,
            lineStyle: {
              color: '#d9d9d9',
              type: 'dashed'
            }
          }
        }
      ],
      series : [
        {
          name:'月维修数',
          type:'bar',
          barWidth: '30',
          data:[30, 52, 200, 334, 390, 330, 220, 170, 220, 290, 350, 410, 440, 530]
        }
      ]
      } else {
        this.setState({
          loading: false,
          view: 'default'
        })
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
      }
    })
  }
  render() {
    return (
      <div className="home-view">
        <div className="ant-row-flex">
          <div className="ant-col ant-col-sm-6">
            <div className="ant-card">
              <div className="ant-card-body">
                <div className="antd-chart-card">
                  <div className="antd-chart-top">
                    <div className="antd-meta-wrap">
                      <div className="antd-meta">
                        <span>
                          <span>维修总数</span>
                        </span>
                        <span className="antd-action">
                          <Icon type="info-circle-o" />
                        </span>
                      </div>
                      <div className="antd-total">
                        <span>100</span>
                      </div>
                    </div>
                  </div>
                  <div className="antd-chart-content">
                    <div className="antd-content-fixed">
                      <div className="antd-trend-item" style={{marginRight: '16px'}}>
                        <span>
                          <span>周同比</span>
                          <span className="antd-trend-text">10%</span>
                        </span>
                        <span className="antd-trend-up">
                          <Icon type="caret-up" />
                        </span>
                      </div>
                      <div className="antd-trend-item">
                        <span>
                          <span>日同比</span>
                          <span className="antd-trend-text">10%</span>
                        </span>
                        <span className="antd-trend-down">
                          <Icon type="caret-down" />
                        </span>
                      </div>
                    </div>
                  </div>
                  <div className="antd-chart-footer">
                    <div className="antd-field">
                      <span className="antd-label">
                        <span>维修总数</span>
                      </span>
                      <span className="antd-number">100</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div className="ant-col ant-col-sm-6">
            <div className="ant-card">
              <div className="ant-card-body">
                <div className="antd-chart-card">
                  <div className="antd-chart-top">
                    <div className="antd-meta-wrap">
                      <div className="antd-meta">
                        <span>
                          <span>超时工单</span>
                        </span>
                        <span className="antd-action">
                          <Icon type="info-circle-o" />
                        </span>
                      </div>
                      <div className="antd-total">
                        <span>100</span>
                      </div>
                    </div>
                  </div>
                  <div className="antd-chart-content">
                    <div className="antd-content-fixed orange">
                      <Slider defaultValue={67} tipFormatter={null} />
                      <div className="mask"></div>
                    </div>
                  </div>
                  <div className="antd-chart-footer">
                    <div className="antd-field">
                      <span className="antd-label">
                        <span>超时工单</span>
                      </span>
                      <span className="antd-number">100</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div className="ant-col ant-col-sm-6">
            <div className="ant-card">
              <div className="ant-card-body">
                <div className="antd-chart-card">
                  <div className="antd-chart-top">
                    <div className="antd-meta-wrap">
                      <div className="antd-meta">
                        <span>
                          <span>关单</span>
                        </span>
                        <span className="antd-action">
                          <Icon type="info-circle-o" />
                        </span>
                      </div>
                      <div className="antd-total">
                        <span>100</span>
                      </div>
                    </div>
                  </div>
                  <div className="antd-chart-content">
                    <div className="antd-content-fixed primary">
                      <Slider defaultValue={77} tipFormatter={null} />
                      <div className="mask"></div>
                    </div>
                  </div>
                  <div className="antd-chart-footer">
                    <div className="antd-field">
                      <span className="antd-label">
                        <span>关单</span>
                      </span>
                      <span className="antd-number">100</span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div className="ant-col ant-col-sm-6">
            <div className="ant-card">
              <div className="ant-card-body">
                <div className="antd-chart-card">
                  <div className="antd-chart-top">
                    <div className="antd-meta-wrap">
                      <div className="antd-meta">
                        <span>
                          <span>原件邮寄</span>
                        </span>
                        <span className="antd-action">
                          <Icon type="info-circle-o" />
                        </span>
                      </div>
                      <div className="antd-total">
                        <span>100</span>
                      </div>
                    </div>
                  </div>
                  <div className="antd-chart-content">
                    <div className="antd-content-fixed">
                      <Slider defaultValue={87} tipFormatter={null} />
                      <div className="mask"></div>
                    </div>
                  </div>
                  <div className="antd-chart-footer">
                    <div className="antd-trend-item" style={{marginRight: '16px'}}>
                      <span>
                        <span>周同比</span>
                        <span className="antd-trend-text">10%</span>
                      </span>
                      <span className="antd-trend-up">
                        <Icon type="caret-up" />
                      </span>
                    </div>
                    <div className="antd-trend-item">
                      <span>
                        <span>日同比</span>
                        <span className="antd-trend-text">10%</span>
                      </span>
                      <span className="antd-trend-down">
                        <Icon type="caret-down" />
                      </span>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <Tabs defaultActiveKey="1">
          <TabPane tab="维修总数" key="1">
            <div id="home" className="sale-trend ant-col ant-col-xs-16"></div>
            <div className="ant-col ant-col-xs-8">
              <div className="antd-sales-rank">
                <h4 className="antd-ranking-title">产品排名</h4>
                <ul className="antd-ranking-list">
                  <li>
                    <span className="antd-ranking-active">1</span>
                    <span className="antd-ranking-title">KU699</span>
                    <span>723,234</span>
                  </li>
                  <li>
                    <span className="antd-ranking-active">2</span>
                    <span className="antd-ranking-title">KU110</span>
                    <span>683,434</span>
                  </li>
                  <li>
                    <span className="antd-ranking-active">3</span>
                    <span className="antd-ranking-title">KU110K</span>
                    <span>527,264</span>
                  </li>
                  <li>
                    <span className="antd-ranking-number">4</span>
                    <span className="antd-ranking-title">KU066.9</span>
                    <span>493,233</span>
                  </li>
                  <li>
                    <span className="antd-ranking-number">5</span>
                    <span className="antd-ranking-title">KU079</span>
                    <span>323,734</span>
                  </li>
                  <li>
                    <span className="antd-ranking-number">6</span>
                    <span className="antd-ranking-title">KU153</span>
                    <span>303,934</span>
                  </li>
                  <li>
                    <span className="antd-ranking-number">7</span>
                    <span className="antd-ranking-title">KU151</span>
                    <span>227,244</span>
                  </li>
                  <li>
                    <span className="antd-ranking-number">8</span>
                    <span className="antd-ranking-title">KU720</span>
                    <span>223,734</span>
                  </li>
                </ul>
              </div>
            </div>
          </TabPane>
        </Tabs>
      </div>
    )
    const { loading, view } = this.state
    if (loading) {
      return (<Spin className="home-box-spin" size="large" />)
    } else if (view === 'custom') {
      return (<CustomPage MenuID={this.props.MenuID}/>)
    } else {
      return (<DefaultHome />)
    }
  }
}
src/tabviews/home/index.scss
@@ -1,234 +1,5 @@
.home-view {
.home-box-spin {
  position: relative;
  width: 100%;
  min-height: calc(100vh - 92px);
  height: 100%;
  background: #f0f2f5;
  padding: 24px;
  .ant-row-flex {
    display: flex;
    flex-flow: row wrap;
    margin-left: -12px;
    margin-right: -12px;
    .ant-col {
      padding-left: 12px;
      padding-right: 12px;
      margin-bottom: 24px;
      .ant-card {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
        color: rgba(0,0,0,.65);
        font-size: 14px;
        font-variant: tabular-nums;
        line-height: 1.5;
        list-style: none;
        font-feature-settings: "tnum";
        position: relative;
        background: #fff;
        border-radius: 2px;
        transition: all .3s;
        .ant-card-body {
          padding: 20px 24px 8px;
          .antd-chart-card {
            position: relative;
            box-sizing: border-box;
            .antd-chart-top {
              position: relative;
              width: 100%;
              overflow: hidden;
              box-sizing: border-box;
              .antd-meta-wrap {
                float: left;
                box-sizing: border-box;
                .antd-meta {
                  height: 22px;
                  color: rgba(0,0,0,.45);
                  font-size: 14px;
                  line-height: 22px;
                  .antd-action {
                    position: absolute;
                    top: 4px;
                    right: 0;
                    line-height: 1;
                    cursor: pointer;
                  }
                }
                .antd-total {
                  height: 38px;
                  margin-top: 4px;
                  margin-bottom: 0;
                  overflow: hidden;
                  color: rgba(0,0,0,.85);
                  font-size: 30px;
                  line-height: 38px;
                  white-space: nowrap;
                  text-overflow: ellipsis;
                  word-break: break-all;
                }
              }
            }
            .antd-chart-content {
              position: relative;
              height: 40px;
              .antd-content-fixed {
                position: absolute;
                bottom: 0;
                left: 0;
                width: 100%;
                .antd-trend-item {
                  display: inline-block;
                  font-size: 14px;
                  line-height: 22px;
                  .antd-trend-text {
                    margin-left: 5px;
                  }
                  .antd-trend-up {
                    color: #f5222d;
                  }
                  .antd-trend-down {
                    top: -1px;
                    color: #52c41a;
                  }
                }
                .mask {
                  position: absolute;
                  top: 0px;
                  left: 0px;
                  right: 0px;
                  bottom: 0px;
                  z-index: 1;
                }
              }
              .ant-slider {
                margin: 14px 0px 10px;
              }
              .ant-slider-track {
                height: 7px;
                background-color: #13C2C2;
              }
              .ant-slider-handle {
                border-color: #13C2C2;
              }
              .orange {
                .ant-slider-track {
                  background-color: orange;
                }
                .ant-slider-handle {
                  border-color: lightsalmon;
                }
              }
              .primary {
                .ant-slider-track {
                  background-color: #1890ff;
                }
                .ant-slider-handle {
                  border-color: #91d5ff;
                }
              }
              .ant-slider-rail {
                height: 7px;
              }
            }
            .antd-chart-footer {
              margin-top: 8px;
              padding-top: 9px;
              border-top: 1px solid #e8e8e8;
              .antd-label {
                font-size: 14px;
                line-height: 22px;
                margin-right: 10px;
              }
              .antd-trend-item {
                display: inline-block;
                font-size: 14px;
                line-height: 22px;
                .antd-trend-text {
                  margin-left: 5px;
                }
                .antd-trend-up {
                  color: #f5222d;
                }
                .antd-trend-down {
                  top: -1px;
                  color: #52c41a;
                }
              }
            }
          }
        }
      }
    }
  }
  .ant-tabs {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    color: rgba(0, 0, 0, 0.65);
    font-size: 14px;
    font-variant: tabular-nums;
    line-height: 1.5;
    list-style: none;
    font-feature-settings: "tnum";
    position: relative;
    background: #fff;
    border-radius: 2px;
    transition: all .3s;
    .sale-trend {
      height: 400px;
      margin-bottom: 20px;
    }
    .antd-sales-rank {
      padding: 35px 32px 32px 72px;
      .antd-ranking-title {
        font-size: 16px;
      }
      .antd-ranking-list {
        margin: 20px 0 0;
        padding: 0;
        list-style: none;
        li {
          display: flex;
          align-items: center;
          margin-top: 16px;
          zoom: 1;
          .antd-ranking-active {
            display: inline-block;
            width: 20px;
            height: 20px;
            margin-top: 1.5px;
            margin-right: 16px;
            font-weight: 600;
            font-size: 12px;
            line-height: 20px;
            text-align: center;
            color: #fff;
            background-color: #314659;
            border-radius: 20px;
          }
          .antd-ranking-number {
            display: inline-block;
            width: 20px;
            height: 20px;
            margin-top: 1.5px;
            margin-right: 16px;
            font-weight: 600;
            font-size: 14px;
            line-height: 20px;
            text-align: center;
          }
          .antd-ranking-title {
            flex: 1 1;
            margin-right: 8px;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
            color: rgba(0,0,0,.65);
            font-size: 14px;
            line-height: 22px;
          }
        }
      }
    }
  }
  left: 50%;
  top: 30vh;
}
src/templates/menuconfig/editthdmenu/preview/index.jsx
@@ -1,6 +1,6 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Button} from 'antd'
import { Button } from 'antd'
import './index.scss'
class Preview extends Component {
src/templates/menuconfig/menuelement/card.jsx
@@ -32,6 +32,18 @@
    closeCard(id)
  }
  let _param = ''
  if (card.type === 'CustomPage') {
    _param = {
      MenuType: 'custom',
      MenuId: card.MenuID,
      ParentId: card.ParentId,
      MenuName: card.MenuName,
      MenuNo: card.MenuNo
    }
    _param = window.btoa(window.encodeURIComponent(JSON.stringify(_param)))
  }
  return (
    <div className="side-card" style={{ opacity }}>
      <div ref={node => drag(drop(node))}>
@@ -40,7 +52,7 @@
      </div>
      {/* 自定义模板,在新页面编辑 */}
      {!card.forbidden && card.type !== 'CustomPage' ? <Icon className="edit" type="edit" onClick={edit} /> : null}
      {card.type === 'CustomPage' ? <a href={`#/menudesign/${card.MenuID}/${card.ParentId}/${card.MenuName}/${card.MenuNo}`} target="_blank" rel="noopener noreferrer"><Icon className="edit" type="edit" /></a> : null}
      {card.type === 'CustomPage' ? <a href={`#/menudesign/${_param}`} target="_blank" rel="noopener noreferrer"><Icon className="edit" type="edit" /></a> : null}
      <Icon className="close" type="close" onClick={close} />
    </div>
  )
src/templates/zshare/modalform/fieldtable/index.jsx
@@ -40,19 +40,10 @@
  renderCell = (form) => {
    const { getFieldDecorator } = form
    const {
      editing,
      dataIndex,
      title,
      inputType,
      record,
      index,
      children,
      onSave,
      ...restProps
    } = this.props;
    const { editing, dataIndex, title, record, children, className } = this.props
    return (
      <td {...restProps}>
      <td className={className}>
        {editing ? (
          <Form.Item style={{ margin: 0 }}>
            {getFieldDecorator(dataIndex, {
src/templates/zshare/verifycard/index.jsx
@@ -570,6 +570,10 @@
      if (!hasBid) { // 表单中增加BID
        _fields.unshift({ uuid: 'BID', field: 'BID', label: 'BID', type: 'text' })
        fieldArr.push('bid')
        _declare.push(`@bid nvarchar(50)`)
        _select.push(`@bid=''`)
      }
      let hasColumn = false
@@ -1234,9 +1238,9 @@
        _loading = true
      }
      if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql')) {
      if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql') && this.scriptsForm.props.form.getFieldValue('sql') !== ' ') {
        _loading = true
      } else if (this.customForm && this.customForm.props.form.getFieldValue('sql')) {
      } else if (this.customForm && this.customForm.props.form.getFieldValue('sql') && this.customForm.props.form.getFieldValue('sql') !== ' ') {
        _loading = true
      }
src/utils/option.js
@@ -4,7 +4,7 @@
import mainsubtable from '@/assets/img/mainsubtable.jpg'
import treepage from '@/assets/img/treepage.jpg'
import calendar from '@/assets/img/calendar.jpg'
// import customImg from '@/assets/img/custom.jpg'
import customImg from '@/assets/img/custom.jpg'
import rolemanage from '@/assets/img/rolemanage.jpg'
const _dict =  sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
@@ -78,13 +78,13 @@
    baseconfig: '',
    isSystem: true
  },
  // {
  //   title: '自定义',
  //   type: 'CustomPage',
  //   url: customImg,
  //   baseconfig: '',
  //   isSystem: true
  // },
  {
    title: '自定义',
    type: 'CustomPage',
    url: customImg,
    baseconfig: '',
    isSystem: true
  },
  {
    title: '角色权限分配',
    type: 'RolePermission',
src/views/menudesign/index.jsx
@@ -37,19 +37,40 @@
class MenuDesign extends Component {
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    MenuId: this.props.match.params.MenuId,
    MenuType: '',
    MenuId: '',
    ParentId: '',
    MenuName: '',
    MenuNo: '',
    tableFields: [],
    activeKey: 'basedata',
    menuloading: false,
    oriConfig: null,
    openEdition: '',
    config: null,
    editElem: null
    editElem: null,
  }
  UNSAFE_componentWillMount() {
    this.getMenuParam()
    // this.testFunc()
    try {
      let param = JSON.parse(window.decodeURIComponent(window.atob(this.props.match.params.param)))
      this.setState({
        MenuType: param.MenuType,
        MenuId: param.MenuId,
        ParentId: param.ParentId || '',
        MenuName: param.MenuName || '',
        MenuNo: param.MenuNo || '',
      }, () => {
        this.getMenuParam()
      })
    } catch {
      notification.warning({
        top: 92,
        message: '菜单信息解析错误!',
        duration: 5
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -87,9 +108,16 @@
  }
  submitConfig = () => {
    const { config, openEdition } = this.state
    const { config, MenuType, openEdition } = this.state
    if (!config.MenuName || !config.MenuNo || !config.fstMenuId || !config.parentId) {
    if (!config.MenuID) {
      notification.warning({
        top: 92,
        message: '请完善菜单基本信息!',
        duration: 5
      })
      return
    } else if (MenuType === 'custom' && (!config.MenuName || !config.MenuNo || !config.fstMenuId || !config.parentId)) {
      notification.warning({
        top: 92,
        message: '请完善菜单基本信息!',
@@ -123,7 +151,7 @@
    let param = {
      func: 'sPC_TrdMenu_AddUpt',
      FstID: _config.fstMenuId,
      FstID: _config.fstMenuId || '',
      SndID: _config.parentId,
      ParentID: _config.parentId,
      MenuID: _config.uuid,
@@ -176,9 +204,11 @@
  }
  getMenuParam = () => {
    const { MenuId, ParentId, MenuName, MenuNo } = this.state
    Api.getSystemConfig({
      func: 'sPC_Get_LongParam',
      MenuID: this.props.match.params.MenuId
      MenuID: MenuId
    }).then(result => {
      if (result.status) {
        let config = null
@@ -195,21 +225,21 @@
        if (!config) {
          config = {
            version: 1.0,
            uuid: this.props.match.params.MenuId,
            MenuID: this.props.match.params.MenuId,
            parentId: this.props.match.params.ParentId,
            uuid: MenuId,
            MenuID: MenuId,
            parentId: ParentId,
            Template: 'CustomPage',
            easyCode: '',
            enabled: false,
            MenuName: this.props.match.params.MenuName,
            MenuNo: this.props.match.params.MenuNo,
            MenuName: MenuName,
            MenuNo: MenuNo,
            tables: [],
            components: [],
            style: {backgroundColor: '#ffffff', backgroundImage: ''}
          }
        } else {
          config.uuid = this.props.match.params.MenuId
          config.MenuID = this.props.match.params.MenuId
          config.uuid = MenuId
          config.MenuID = MenuId
        }
        this.setState({
@@ -288,26 +318,38 @@
  }
  verifyConfig = (show) => {
    const { config } = this.state
    const { config, MenuType } = this.state
    let error = ''
    if (!config.MenuName || !config.MenuNo || !config.fstMenuId || !config.parentId) {
    if (!config.MenuID) {
      notification.warning({
        top: 92,
        message: '请完善菜单基本信息!',
        duration: 5
      })
      return 'false'
      return
    } else if (MenuType === 'custom' && (!config.MenuName || !config.MenuNo || !config.fstMenuId || !config.parentId)) {
      notification.warning({
        top: 92,
        message: '请完善菜单基本信息!',
        duration: 5
      })
      return
    }
    config.components.forEach(item => {
      if (!error && item.setting) {
        if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {
          error = `组件《${item.name}》未设置数据源`
          error = `组件《${item.name}》未设置数据源!`
        } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
          error = `组件《${item.name}》未设置数据源`
          error = `组件《${item.name}》未设置数据源!`
        } else if (item.setting.interType && !item.setting.primaryKey) {
          error = `组件《${item.name}》未设置主键`
          error = `组件《${item.name}》未设置主键!`
        }
      }
      if (!error && (item.type === 'bar' || item.type === 'line' || item.type === 'pie')) {
        if (!item.plot.Xaxis) {
          error = `组件《${item.name}》图表字段尚未设置!`
        }
      }
    })
@@ -349,7 +391,7 @@
  }
  render () {
    const { activeKey, dict, MenuId, config } = this.state
    const { activeKey, MenuType, dict, MenuId, config, ParentId, MenuName, MenuNo } = this.state
    return (
      <ConfigProvider locale={_locale}>
@@ -362,16 +404,16 @@
                  {/* 基本信息 */}
                  <Panel header={dict['mob.basemsg']} key="basedata">
                    {/* 菜单信息 */}
                    <MenuForm
                    {MenuType === 'custom' ? <MenuForm
                      dict={dict}
                      config={config}
                      MenuId={MenuId}
                      parentId={this.props.match.params.ParentId}
                      MenuName={this.props.match.params.MenuName}
                      MenuNo={this.props.match.params.MenuNo}
                      parentId={ParentId}
                      MenuName={MenuName}
                      MenuNo={MenuNo}
                      initMenuList={this.initMenuList}
                      updateConfig={this.updateConfig}
                    />
                    /> : null}
                    {/* 表名添加 */}
                    {config ? <TableComponent config={config} updatetable={this.updatetable}/> : null}
                  </Panel>