| | |
| | | import PropTypes from 'prop-types' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Chart } from '@antv/g2' |
| | | // import { connect } from 'react-redux' |
| | | import DataSet from '@antv/data-set' |
| | | import { Spin, Empty, notification } from 'antd' |
| | | import { Spin, Empty, notification, Modal } from 'antd' |
| | | import { DownloadOutlined } from '@ant-design/icons' |
| | | import moment from 'moment' |
| | | |
| | | import asyncComponent from './asyncButtonComponent' |
| | |
| | | import Api from '@/api' |
| | | import Utils from '@/utils/utils.js' |
| | | import UtilsDM from '@/utils/utils-datamanage.js' |
| | | // import { modifyTabview } from '@/store/action' |
| | | import MKEmitter from '@/utils/events.js' |
| | | import TimerTask from '@/utils/timer-task.js' |
| | | import NormalHeader from '@/tabviews/custom/components/share/normalheader' |
| | | import './index.scss' |
| | | |
| | | const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader')) |
| | | // const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader')) |
| | | const ExcelOutButton = asyncComponent(() => import('@/tabviews/zshare/actionList/exceloutbutton')) |
| | | const ExcelInButton = asyncComponent(() => import('@/tabviews/zshare/actionList/excelInbutton')) |
| | | |
| | | class LineChart extends Component { |
| | | static propTpyes = { |
| | | BID: PropTypes.any, // 父级Id |
| | | data: PropTypes.array, // 统一查询数据 |
| | | config: PropTypes.object, // 组件配置信息 |
| | | mainSearch: PropTypes.any, // 外层搜索条件 |
| | | menuType: PropTypes.any, // 菜单类型 |
| | | } |
| | | |
| | | state = { |
| | |
| | | search: null, // 搜索条件 |
| | | vFields: [], // 数值字段 |
| | | vstFields: null, // 统计数据值字段信息 |
| | | chart: null |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | const { config, data, initdata, BID } = this.props |
| | | const { config, data, initdata } = this.props |
| | | let _config = fromJS(config).toJS() |
| | | let _data = null |
| | | let _sync = config.setting.sync === 'true' |
| | | |
| | | let BID = '' |
| | | let BData = '' |
| | | |
| | | if (config.setting.supModule) { |
| | | BData = window.GLOB.CacheData.get(config.setting.supModule) |
| | | } else { |
| | | BData = window.GLOB.CacheData.get(config.$pageId) |
| | | } |
| | | if (BData) { |
| | | BID = BData.$BID || '' |
| | | } |
| | | |
| | | if (config.setting.sync === 'true' && data) { |
| | | _data = data[config.dataName] || [] |
| | |
| | | }) |
| | | } |
| | | |
| | | let height = config.plot.height || 400 |
| | | if (config.plot.title || config.search.length > 0) { |
| | | _config.plot.height = height - 70 |
| | | } else { |
| | | _config.plot.height = height - 25 |
| | | } |
| | | |
| | | _config.style.height = height |
| | | _config.style.height = config.plot.height || 400 |
| | | |
| | | let transfield = {} |
| | | _config.columns.forEach(col => { |
| | |
| | | |
| | | _config.plot.hasBar = Bar_axis.length > 0 |
| | | |
| | | if (_config.plot.mutilBar !== 'overlap') { |
| | | if (_config.plot.mutilBar !== 'overlap' && Bar_axis.length > 1) { |
| | | _config.plot.Bar_axis = Bar_axis |
| | | } |
| | | } else { |
| | |
| | | _config.plot.$colors = colors |
| | | } |
| | | |
| | | let limit = _config.plot.XLimit || 11 |
| | | |
| | | let xc = {label: { |
| | | formatter: (val) => { |
| | | if (!val || /^\s*$/.test(val)) return val |
| | | let _val = `${val}` |
| | | if (_val.length <= limit) return val |
| | | return _val.substring(0, limit) + '...' |
| | | }, |
| | | style: { fill: _config.plot.color } |
| | | }} |
| | | let yc = {label: { style: { fill: _config.plot.color } }} |
| | | if (_config.plot.grid === 'hidden') { |
| | | yc.grid = null |
| | | } |
| | | if (_config.plot.y_line === 'show') { |
| | | yc.line = {style: { stroke: '#D1D2CE' }} |
| | | } |
| | | if (_config.plot.lineColor) { |
| | | xc.tickLine = {style: { stroke: _config.plot.lineColor }} |
| | | xc.line = { style: { stroke: _config.plot.lineColor } } |
| | | if (yc.grid !== null) { |
| | | yc.grid = { line: { style: { stroke: _config.plot.lineColor } }} |
| | | } |
| | | if (yc.line) { |
| | | yc.line = { style: { stroke: _config.plot.lineColor } } |
| | | } |
| | | } |
| | | |
| | | _config.plot.$xc = xc |
| | | _config.plot.$yc = yc |
| | | |
| | | _config.plot.$paddingLeft = 30 |
| | | _config.plot.$paddingRight = 30 |
| | | |
| | | if (_config.plot.enabled === 'true') { |
| | | let colorIndex = 0 |
| | | let limit = chartColors.length |
| | | let axisIndex = 0 |
| | | let fields = [] |
| | | let legends = [] |
| | | |
| | | let vFieldsShow = {} |
| | | |
| | | _config.plot.customs.forEach(item => { |
| | | if (colors.has(item.name)) { |
| | | item.color = colors.get(item.name) |
| | |
| | | |
| | | if (item.axis === 'true' && axisIndex < 2) { |
| | | if (axisIndex === 0) { |
| | | item.axis = { title: { style: { fill: _config.plot.color } }, label: {style: { fill: _config.plot.color }} } |
| | | item.axis = { label: {style: { fill: _config.plot.color }} } |
| | | if (item.title !== 'false') { |
| | | item.axis.title = { style: { fill: _config.plot.color } } |
| | | _config.plot.$paddingLeft = 50 |
| | | } |
| | | if (_config.plot.grid === 'hidden') { |
| | | item.axis.grid = null |
| | | } |
| | | if (_config.plot.y_line === 'show') { |
| | | item.axis.line = {style: { stroke: '#D1D2CE' }} |
| | | } |
| | | if (_config.plot.lineColor) { |
| | | if (item.axis.grid !== null) { |
| | | item.axis.grid = { line: { style: { stroke: _config.plot.lineColor } }} |
| | | } |
| | | if (item.axis.line) { |
| | | item.axis.line = { style: { stroke: _config.plot.lineColor } } |
| | | } |
| | | } |
| | | fields.unshift(item) |
| | | } else { |
| | | item.axis = { grid: null, title: {style: { fill: _config.plot.color }}, label: {style: { fill: _config.plot.color }} } |
| | | item.axis = { grid: null, label: {style: { fill: _config.plot.color }} } |
| | | if (item.title !== 'false') { |
| | | item.axis.title = { style: { fill: _config.plot.color } } |
| | | _config.plot.$paddingRight = 60 |
| | | } |
| | | if (_config.plot.y_line === 'show') { |
| | | item.axis.line = {style: { stroke: '#D1D2CE' }} |
| | | } |
| | | if (_config.plot.lineColor && item.axis.line) { |
| | | item.axis.line = { style: { stroke: _config.plot.lineColor } } |
| | | } |
| | | fields.splice(1, 0, item) |
| | | } |
| | | axisIndex++ |
| | |
| | | name: item.name, |
| | | marker: { symbol: item.chartType === 'bar' ? 'square' : 'hyphen', style: { stroke: item.color,fill: item.color, r: 5, lineWidth: 2 } } |
| | | }) |
| | | |
| | | if (!_config.plot.Bar_axis || item.chartType !== 'bar') { // 折线图或重叠下的柱状图可单独设置显示类型 |
| | | if (item.show) { |
| | | vFieldsShow[item.type] = item.show |
| | | } else { |
| | | item.show = _config.plot.show |
| | | } |
| | | } |
| | | }) |
| | | _config.plot.customs = fields |
| | | _config.plot.legends = legends |
| | | _config.plot.axisIndex = axisIndex |
| | | vFields.forEach(item => { |
| | | if (vFieldsShow[item.field]) { |
| | | item.show = vFieldsShow[item.field] |
| | | } |
| | | }) |
| | | } |
| | | |
| | | this.setState({ |
| | |
| | | transfield |
| | | }, () => { |
| | | if (config.setting.sync !== 'true' && config.setting.onload === 'true') { |
| | | this.loadData() |
| | | setTimeout(() => { |
| | | this.loadData() |
| | | }, _config.setting.delay || 0) |
| | | } else if (config.setting.sync === 'true' && _data) { |
| | | this.handleData() |
| | | } |
| | |
| | | this.setState({sync: false, data: _data}, () => { |
| | | this.handleData() |
| | | }) |
| | | } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) { |
| | | if (config.setting.syncRefresh === 'true') { |
| | | this.setState({}, () => { |
| | | this.loadData() |
| | | }) |
| | | } |
| | | } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) { |
| | | this.setState({}, () => { |
| | | this.loadData() |
| | | }) |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | componentDidMount () { |
| | | const { config } = this.state |
| | | |
| | | MKEmitter.addListener('reloadData', this.reloadData) |
| | | MKEmitter.addListener('resetSelectLine', this.resetParentParam) |
| | | MKEmitter.addListener('queryModuleParam', this.queryModuleParam) |
| | | MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult) |
| | | this.handleTimer() |
| | | |
| | | if (config.timer) { |
| | | this.timer = new TimerTask() |
| | | this.timer.init(config.uuid, config.timer, config.timerRepeats, () => { |
| | | this.loadData(true) |
| | | }) |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * @description 组件销毁,清除state更新,清除快捷键设置 |
| | | */ |
| | | componentWillUnmount () { |
| | | clearTimeout(this.timer) |
| | | this.setState = () => { |
| | | return |
| | | } |
| | |
| | | MKEmitter.removeListener('resetSelectLine', this.resetParentParam) |
| | | MKEmitter.removeListener('queryModuleParam', this.queryModuleParam) |
| | | MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult) |
| | | } |
| | | |
| | | handleTimer = () => { |
| | | const { config } = this.state |
| | | |
| | | if (!config.timer) return |
| | | |
| | | const _change = { '15s': 15000, '30s': 30000, '1min': 60000, '5min': 300000, '10min': 600000, '15min': 900000, '30min': 1800000, '1hour': 3600000 } |
| | | |
| | | let timer = _change[config.timer] |
| | | |
| | | if (!timer) return |
| | | |
| | | let _param = { |
| | | func: 's_get_timers_role', |
| | | LText: `select '${window.GLOB.appkey || ''}','${config.uuid}'`, |
| | | timer_type: config.timer, |
| | | component_id: config.uuid |
| | | } |
| | | |
| | | _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') // 时间戳 |
| | | _param.LText = Utils.formatOptions(_param.LText) // 关键字符替换,base64加密 |
| | | _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp) // md5密钥 |
| | | |
| | | Api.getSystemConfig(_param).then(result => { |
| | | if (!result.status) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: result.message, |
| | | duration: 5 |
| | | }) |
| | | return |
| | | } else if (result.run_type) { |
| | | this.setState({timer}) |
| | | this.timer = setTimeout(() => { |
| | | this.timerTask() |
| | | }, timer) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | timerTask = () => { |
| | | const { timer } = this.state |
| | | if (!timer) return |
| | | |
| | | this.loadData(true) |
| | | |
| | | this.timer = setTimeout(() => { |
| | | this.timerTask() |
| | | }, timer) |
| | | this.timer && this.timer.stop() |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | if (config.uuid !== menuId) return |
| | | |
| | | this.loadData() // 数据刷新 |
| | | |
| | | if (btn.syncComponentId && btn.syncComponentId !== config.uuid && btn.syncComponentId !== config.setting.supModule) { |
| | | MKEmitter.emit('reloadData', btn.syncComponentId) // 同级标签刷新 |
| | | if ((position === 'mainline' || position === 'popclose') && config.setting.supModule && BID) { // 刷新源组件时,附带刷新上级行与当前组件 |
| | | MKEmitter.emit('reloadData', config.setting.supModule, BID) |
| | | } else { |
| | | this.loadData() |
| | | } |
| | | |
| | | if (position === 'mainline' && config.setting.supModule) { // 主表行刷新 |
| | | MKEmitter.emit('reloadData', config.setting.supModule, (BID || 'empty')) |
| | | } else if (position === 'popclose') { // 标签关闭刷新 |
| | | config.setting.supModule && MKEmitter.emit('reloadData', config.setting.supModule, (BID || 'empty')) |
| | | if (position === 'popclose') { // 执行启动弹窗的按钮所选择的刷新项 |
| | | btn.$tabId && MKEmitter.emit('refreshPopButton', btn.$tabId) |
| | | } |
| | | } |
| | |
| | | const { config } = this.state |
| | | |
| | | if (!config.setting.supModule || config.setting.supModule !== MenuID) return |
| | | if (id !== this.state.BID) { |
| | | if (id !== this.state.BID || id !== '') { |
| | | this.setState({ BID: id }, () => { |
| | | this.loadData() |
| | | }) |
| | |
| | | /** |
| | | * @description 导出Excel时,获取页面搜索排序等参数 |
| | | */ |
| | | queryModuleParam = (menuId, btnId) => { |
| | | queryModuleParam = (menuId, callback) => { |
| | | const { mainSearch } = this.props |
| | | const { arr_field, config, search } = this.state |
| | | |
| | | if (config.uuid !== menuId) return |
| | | |
| | | let searches = search ? fromJS(search).toJS() : [] |
| | | if (mainSearch && mainSearch.length > 0) { // 主表搜索条件 |
| | | if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 主表搜索条件 |
| | | let keys = searches.map(item => item.key.toLowerCase()) |
| | | mainSearch.forEach(item => { |
| | | if (!keys.includes(item.key.toLowerCase())) { |
| | |
| | | }) |
| | | } |
| | | |
| | | MKEmitter.emit('returnModuleParam', config.uuid, btnId, { |
| | | callback({ |
| | | arr_field: arr_field, |
| | | orderBy: config.setting.order || '', |
| | | search: searches, |
| | |
| | | * @description 数据加载 |
| | | */ |
| | | async loadData (hastimer) { |
| | | const { mainSearch, menuType } = this.props |
| | | const { mainSearch } = this.props |
| | | const { config, arr_field, BID, search } = this.state |
| | | |
| | | if (config.setting.supModule && !BID) { // BID 不存在时,不做查询 |
| | |
| | | } |
| | | |
| | | let searches = search ? fromJS(search).toJS() : [] |
| | | if (mainSearch && mainSearch.length > 0) { // 主表搜索条件 |
| | | if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 主表搜索条件 |
| | | let keys = searches.map(item => item.key) |
| | | mainSearch.forEach(item => { |
| | | if (!keys.includes(item.key)) { |
| | |
| | | }) |
| | | } |
| | | |
| | | let requireFields = searches.filter(item => item.required && (!item.value || item.value.length === 0)) |
| | | let requireFields = searches.filter(item => item.required && item.value === '') |
| | | if (requireFields.length > 0) { |
| | | this.setState({ |
| | | loading: false |
| | | }) |
| | | return |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | let _orderBy = config.setting.order || '' |
| | | let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, '', '', BID, menuType) |
| | | let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, '', '', BID) |
| | | |
| | | let result = await Api.genericInterface(param) |
| | | if (result.status) { |
| | | let reset = true |
| | | |
| | | if (hastimer && is(fromJS(result.data), fromJS(this.state.data))) { |
| | | reset = false |
| | | } |
| | | |
| | | this.setState({ |
| | | data: result.data, |
| | | loading: false |
| | | }, () => { |
| | | if (!reset) return |
| | | this.handleData() |
| | | }) |
| | | } else { |
| | | this.setState({ |
| | | loading: false, |
| | | timer: null |
| | | loading: false |
| | | }) |
| | | notification.error({ |
| | | top: 92, |
| | | message: result.message, |
| | | duration: 10 |
| | | }) |
| | | this.timer && this.timer.stop() |
| | | |
| | | if (result.ErrCode === 'N') { |
| | | Modal.error({ |
| | | title: result.message, |
| | | }) |
| | | } else { |
| | | notification.error({ |
| | | top: 92, |
| | | message: result.message, |
| | | duration: 10 |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | if (plot.repeat === 'average') { |
| | | let _mdata = new Map() |
| | | _cdata.forEach(item => { |
| | | if (!item[plot.Xaxis]) return |
| | | if (!item[plot.Xaxis] && item[plot.Xaxis] !== 0) return |
| | | |
| | | vFields.forEach(col => { |
| | | if (typeof(item[col.field]) !== 'number') { |
| | |
| | | // dodge is not support linear attribute, please use category attribute! 时间格式 |
| | | if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) { |
| | | item[plot.Xaxis] = ' ' + item[plot.Xaxis] |
| | | } else { |
| | | item[plot.Xaxis] = '' + item[plot.Xaxis] |
| | | } |
| | | |
| | | if (!_mdata.has(item[plot.Xaxis])) { |
| | |
| | | } else if (plot.repeat === 'cumsum') { |
| | | let _mdata = new Map() |
| | | _cdata.forEach(item => { |
| | | if (!item[plot.Xaxis]) return |
| | | if (!item[plot.Xaxis] && item[plot.Xaxis] !== 0) return |
| | | |
| | | vFields.forEach(col => { |
| | | if (typeof(item[col.field]) !== 'number') { |
| | |
| | | |
| | | if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) { |
| | | item[plot.Xaxis] = ' ' + item[plot.Xaxis] |
| | | } else { |
| | | item[plot.Xaxis] = '' + item[plot.Xaxis] |
| | | } |
| | | |
| | | if (!_mdata.has(item[plot.Xaxis])) { |
| | |
| | | } else { // plot.repeat === 'unrepeat' |
| | | let _mdata = new Map() |
| | | _cdata.forEach(item => { |
| | | if (!item[plot.Xaxis]) return |
| | | if (!item[plot.Xaxis] && item[plot.Xaxis] !== 0) return |
| | | |
| | | if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) { |
| | | item[plot.Xaxis] = ' ' + item[plot.Xaxis] |
| | | } else { |
| | | item[plot.Xaxis] = '' + item[plot.Xaxis] |
| | | } |
| | | |
| | | if (!_mdata.has(item[plot.Xaxis])) { |
| | |
| | | |
| | | _data = dv.rows |
| | | } |
| | | |
| | | |
| | | const chart = new Chart({ |
| | | container: this.state.chartId, |
| | | autoFit: true, |
| | | height: plot.height |
| | | height: this.wrap.offsetHeight - 25 |
| | | }) |
| | | |
| | | chart.data(_data) |
| | |
| | | range: [0, 1] |
| | | }) |
| | | } |
| | | chart.scale(_valfield, { |
| | | |
| | | let c = { |
| | | nice: true, |
| | | range: [0, 0.9] |
| | | }) |
| | | |
| | | // 坐标轴格式化 |
| | | chart.axis(plot.Xaxis, { |
| | | label: { |
| | | formatter: (val) => { |
| | | if (!val || /^\s*$/.test(val)) return val |
| | | let _val = `${val}` |
| | | if (_val.length <= 11) return val |
| | | return _val.substring(0, 8) + '...' |
| | | }, |
| | | style: { fill: plot.color } |
| | | }, |
| | | }) |
| | | chart.axis(_valfield, { label: { style: { fill: plot.color } } }) |
| | | } |
| | | |
| | | if (plot.min || plot.min === 0) { |
| | | c.min = plot.min |
| | | } |
| | | if (plot.max || plot.max === 0) { |
| | | c.max = plot.max |
| | | } |
| | | chart.scale(_valfield, c) |
| | | |
| | | chart.axis(plot.Xaxis, plot.$xc) |
| | | chart.axis(_valfield, plot.$yc) |
| | | |
| | | if (!plot.legend || plot.legend === 'hidden') { |
| | | chart.legend(false) |
| | |
| | | } else { |
| | | _chart.color(_typefield) |
| | | } |
| | | if (plot.label === 'true') { |
| | | if (plot.label !== 'false') { |
| | | _chart.label(_valfield, (value) => { |
| | | if (plot.labelValue === 'zero' && value === 0) { |
| | | return null |
| | | } |
| | | if (plot.show === 'percent') { |
| | | value = value + '%' |
| | | } |
| | |
| | | if (plot.area === 'true') { |
| | | let area = chart |
| | | .area() |
| | | .shape(plot.shape || 'smooth') |
| | | // .shape(plot.shape || 'smooth') |
| | | .position(`${plot.Xaxis}*${_valfield}`) |
| | | .tooltip(false) |
| | | |
| | | if (plot.shape === 'smooth') { |
| | | area.shape('smooth') |
| | | } |
| | | if (plot.$colors) { |
| | | let limit = chartColors.length |
| | | area.color(_typefield, (key) => { |
| | |
| | | } |
| | | |
| | | chart.render() |
| | | |
| | | this.setState({chart}) |
| | | } |
| | | |
| | | /** |
| | |
| | | let padding = [10, 30, 30, 30] |
| | | |
| | | if (!plot.Bar_axis) { |
| | | if (plot.axisIndex === 2) { |
| | | padding = [10, 50, 30, 50] |
| | | } else if (plot.axisIndex === 1) { |
| | | padding = [10, 30, 30, 50] |
| | | } |
| | | padding = [10, plot.$paddingRight, 30, plot.$paddingLeft] |
| | | } |
| | | |
| | | const chart = new Chart({ |
| | | container: this.state.chartId, |
| | | autoFit: true, |
| | | height: plot.height |
| | | height: this.wrap.offsetHeight - 25 |
| | | }) |
| | | |
| | | // 坐标轴格式化 |
| | | chart.axis(plot.Xaxis, { |
| | | label: { |
| | | formatter: (val) => { |
| | | if (!val || /^\s*$/.test(val)) return val |
| | | let _val = `${val}` |
| | | if (_val.length <= 11) return val |
| | | return _val.substring(0, 8) + '...' |
| | | }, |
| | | style: { fill: plot.color } |
| | | }, |
| | | }) |
| | | chart.axis(plot.Xaxis, plot.$xc) |
| | | |
| | | if (!plot.hasBar) { |
| | | chart.scale(plot.Xaxis, { |
| | |
| | | |
| | | view1.data(dvt.rows) |
| | | |
| | | view1.scale('value', { |
| | | let c = { |
| | | nice: true, |
| | | range: [0, 0.9] |
| | | }) |
| | | } |
| | | |
| | | view1.legend(false) |
| | | if (plot.min || plot.min === 0) { |
| | | c.min = plot.min |
| | | } |
| | | if (plot.max || plot.max === 0) { |
| | | c.max = plot.max |
| | | } |
| | | view1.scale('value', c) |
| | | view1.axis('value', plot.$yc) |
| | | |
| | | // view1.legend(false) |
| | | |
| | | let colorIndex = 0 |
| | | |
| | |
| | | } else { |
| | | _chart.color('key') |
| | | } |
| | | if (plot.label === 'true') { |
| | | if (plot.label !== 'false') { |
| | | _chart.label('value*key', (value, key) => { |
| | | if (plot.labelValue === 'zero' && value === 0) { |
| | | return null |
| | | } |
| | | |
| | | if (plot.show === 'percent') { |
| | | value = value + '%' |
| | | } |
| | |
| | | } else { |
| | | _chart.color('key') |
| | | } |
| | | if (plot.label === 'true') { |
| | | if (plot.label !== 'false') { |
| | | _chart.label('value*key', (value, key) => { |
| | | if (plot.labelValue === 'zero' && value === 0) { |
| | | return null |
| | | } |
| | | |
| | | if (plot.show === 'percent') { |
| | | value = value + '%' |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | const view2 = chart.createView({ |
| | | region: { |
| | | start: { x: 0, y: 0 }, |
| | | end: { x: 1, y: 1 } |
| | | }, |
| | | padding |
| | | }) |
| | | let view2 = chart |
| | | |
| | | if (plot.Bar_axis) { |
| | | view2 = chart.createView({ |
| | | region: { |
| | | start: { x: 0, y: 0 }, |
| | | end: { x: 1, y: 1 } |
| | | }, |
| | | padding |
| | | }) |
| | | } |
| | | |
| | | view2.data(dv.rows) |
| | | view2.legend(false) |
| | | // view2.legend(false) |
| | | |
| | | plot.customs.forEach((item, i) => { |
| | | plot.customs.forEach(item => { |
| | | if (item.chartType === 'bar' && !plot.Bar_axis) { |
| | | view2.axis(item.name, item.axis) |
| | | |
| | | view2.scale(item.name, { |
| | | let c = { |
| | | nice: true, |
| | | range: [0, 0.9] |
| | | }) |
| | | } |
| | | |
| | | if (item.min || item.min === 0) { |
| | | c.min = item.min |
| | | } |
| | | if (item.max || item.max === 0) { |
| | | c.max = item.max |
| | | } |
| | | |
| | | view2.scale(item.name, c) |
| | | let _chart = view2 |
| | | .interval() |
| | | .position(`${plot.Xaxis}*${item.name}`) |
| | |
| | | .tooltip(`${item.name}`, (value) => { |
| | | return { |
| | | name: item.name, |
| | | value: plot.show === 'percent' ? value + '%' : value |
| | | value: item.show === 'percent' ? value + '%' : value |
| | | } |
| | | }) |
| | | |
| | | if (plot.barSize) { |
| | | _chart.size(plot.barSize || 35) |
| | | } |
| | | if (item.label === 'true') { |
| | | if (item.label !== 'false') { |
| | | _chart.label(item.name, (value) => { |
| | | if (plot.show === 'percent') { |
| | | if (plot.labelValue === 'zero' && value === 0) { |
| | | return null |
| | | } |
| | | |
| | | if (item.show === 'percent') { |
| | | value = value + '%' |
| | | } |
| | | if (plot.label === 'true' && plot.labelColor === 'custom' && item.color) { |
| | |
| | | } else { |
| | | view2.axis(item.name, { grid: null, title: null, label: null }) |
| | | } |
| | | view2.scale(item.name, { |
| | | let c = { |
| | | nice: true, |
| | | range: [0, 0.9] |
| | | }) |
| | | } |
| | | |
| | | if (item.min || item.min === 0) { |
| | | c.min = item.min |
| | | } |
| | | if (item.max || item.max === 0) { |
| | | c.max = item.max |
| | | } |
| | | |
| | | view2.scale(item.name, c) |
| | | let _chart = view2 |
| | | .line() |
| | | .position(`${plot.Xaxis}*${item.name}`) |
| | |
| | | .tooltip(`${item.name}`, (value) => { |
| | | return { |
| | | name: item.name, |
| | | value: plot.show === 'percent' ? value + '%' : value |
| | | value: item.show === 'percent' ? value + '%' : value |
| | | } |
| | | }) |
| | | |
| | | if (item.label === 'true') { |
| | | _chart.label(item.name, (value) => { |
| | | if (plot.show === 'percent') { |
| | | if (plot.labelValue === 'zero' && value === 0) { |
| | | return null |
| | | } |
| | | |
| | | if (item.show === 'percent') { |
| | | value = value + '%' |
| | | } |
| | | return { |
| | |
| | | } |
| | | |
| | | chart.render() |
| | | |
| | | this.setState({chart}) |
| | | } |
| | | |
| | | /** |
| | |
| | | const chart = new Chart({ |
| | | container: this.state.chartId, |
| | | autoFit: true, |
| | | height: plot.height |
| | | height: this.wrap.offsetHeight - 25 |
| | | }) |
| | | |
| | | chart.data(_data) |
| | | |
| | | chart.scale(_valfield, { |
| | | let c = { |
| | | nice: true, |
| | | range: [0, 0.9] |
| | | }) |
| | | } |
| | | |
| | | // 坐标轴格式化 |
| | | chart.axis(plot.Xaxis, { |
| | | label: { |
| | | formatter: (val) => { |
| | | if (!val || /^\s*$/.test(val)) return val |
| | | let _val = `${val}` |
| | | if (_val.length <= 11) return val |
| | | return _val.substring(0, 8) + '...' |
| | | }, |
| | | style: { fill: plot.color } |
| | | }, |
| | | }) |
| | | chart.axis(_valfield, { label: { style: { fill: plot.color } } }) |
| | | if (plot.min || plot.min === 0) { |
| | | c.min = plot.min |
| | | } |
| | | if (plot.max || plot.max === 0) { |
| | | c.max = plot.max |
| | | } |
| | | chart.scale(_valfield, c) |
| | | |
| | | chart.axis(plot.Xaxis, plot.$xc) |
| | | chart.axis(_valfield, plot.$yc) |
| | | |
| | | if (!plot.legend || plot.legend === 'hidden') { |
| | | chart.legend(false) |
| | |
| | | } else { |
| | | _chart.color(_typefield) |
| | | } |
| | | if (plot.label === 'true') { |
| | | if (plot.label !== 'false') { |
| | | _chart.label(`${_valfield}*${_typefield}`, (value, key) => { |
| | | if (plot.labelValue === 'zero' && value === 0) { |
| | | return null |
| | | } |
| | | |
| | | if (plot.show === 'percent') { |
| | | value = value + '%' |
| | | } |
| | |
| | | } else { |
| | | _chart.color(_typefield) |
| | | } |
| | | if (plot.label === 'true') { |
| | | if (plot.label !== 'false') { |
| | | _chart.label(`${_valfield}*${_typefield}`, (value, key) => { |
| | | if (plot.labelValue === 'zero' && value === 0) { |
| | | return null |
| | | } |
| | | |
| | | if (plot.show === 'percent') { |
| | | value = value + '%' |
| | | } |
| | |
| | | |
| | | chart.on('element:click', (ev) => { |
| | | let data = ev.data.data |
| | | MKEmitter.emit('resetSelectLine', config.uuid, (data ? data.$$uuid : ''), null) |
| | | |
| | | MKEmitter.emit('resetSelectLine', config.uuid, (data ? data.$$uuid : ''), data) |
| | | |
| | | if (plot.click === 'menus') { |
| | | let menu = null |
| | | |
| | | if (plot.menus && plot.menus.length > 0) { |
| | | let s = data[plot.menuType] || '' |
| | | plot.menus.forEach(m => { |
| | | if (s !== m.sign) return |
| | | menu = m |
| | | }) |
| | | } |
| | | if (!menu || !menu.MenuID) return |
| | | |
| | | menu.type = menu.tabType |
| | | |
| | | let newtab = { |
| | | ...menu, |
| | | param: {} |
| | | } |
| | | |
| | | if (plot.joint === 'true') { |
| | | newtab.param.$BID = data.$$uuid || '' |
| | | } |
| | | |
| | | if (['linkage_navigation', 'linkage', 'menu_board'].includes(window.GLOB.navBar)) { |
| | | MKEmitter.emit('modifyTabs', newtab, 'replace') |
| | | } else { |
| | | MKEmitter.emit('modifyTabs', newtab, 'plus', true) |
| | | } |
| | | } else if (plot.click === 'menu' && plot.MenuID) { |
| | | let menu = { |
| | | MenuID: plot.MenuID, |
| | | MenuName: plot.MenuName, |
| | | MenuNo: plot.MenuNo, |
| | | type: plot.tabType |
| | | } |
| | | |
| | | let newtab = { |
| | | ...menu, |
| | | param: {} |
| | | } |
| | | |
| | | if (plot.joint === 'true') { |
| | | newtab.param.$BID = data.$$uuid || '' |
| | | } |
| | | |
| | | if (['linkage_navigation', 'linkage', 'menu_board'].includes(window.GLOB.navBar)) { |
| | | MKEmitter.emit('modifyTabs', newtab, 'replace') |
| | | } else { |
| | | MKEmitter.emit('modifyTabs', newtab, 'plus', true) |
| | | } |
| | | } |
| | | }) |
| | | |
| | | // if (plot.linkmenu && plot.linkmenu.length > 0) { |
| | | // let menu_id = plot.linkmenu.slice(-1)[0] |
| | | // let menu = this.props.permMenus.filter(m => m.MenuID === menu_id)[0] || '' |
| | | |
| | | // chart.on('element:dblclick', (ev) => { |
| | | // if (!menu) { |
| | | // notification.warning({ |
| | | // top: 92, |
| | | // message: '菜单已删除或没有访问权限!', |
| | | // duration: 5 |
| | | // }) |
| | | // return |
| | | // } |
| | | |
| | | // try { |
| | | // let data = ev.data.data |
| | | // let primaryId = '' |
| | | // if (this.state.config.setting.primaryKey && data) { |
| | | // primaryId = data[this.state.config.setting.primaryKey] || '' |
| | | // } |
| | | |
| | | // let newtab = { |
| | | // ...menu, |
| | | // selected: true, |
| | | // param: { |
| | | // $BID: primaryId |
| | | // } |
| | | // } |
| | | |
| | | // let tabs = this.props.tabviews.filter(tab => { |
| | | // tab.selected = false |
| | | // return tab.MenuID !== newtab.MenuID |
| | | // }) |
| | | |
| | | // if (this.props.tabviews.length > tabs.length) { |
| | | // this.props.modifyTabview(fromJS(tabs).toJS()) |
| | | // } |
| | | |
| | | // this.setState({}, () => { |
| | | // tabs.push(newtab) |
| | | // this.props.modifyTabview(tabs) |
| | | // }) |
| | | // } catch { |
| | | // console.warn('菜单打开失败!') |
| | | // } |
| | | // }) |
| | | // } |
| | | |
| | | if (plot.interaction && plot.interaction.length) { |
| | | plot.interaction.forEach(t => { |
| | |
| | | } |
| | | |
| | | chart.render() |
| | | |
| | | this.setState({chart}) |
| | | } |
| | | |
| | | refreshSearch = (list) => { |
| | |
| | | }) |
| | | } |
| | | |
| | | downloadImage = () => { |
| | | const { chart, config } = this.state |
| | | const link = document.createElement('a'); |
| | | const filename = `${config.name}${moment().format('YYYY-MM-DD HH_mm_ss')}.png`; |
| | | const canvas = chart.getCanvas(); |
| | | canvas.get('timeline').stopAllAnimations(); |
| | | |
| | | setTimeout(() => { |
| | | const canvas = chart.getCanvas(); |
| | | const canvasDom = canvas.get('el'); |
| | | const dataURL = canvasDom.toDataURL('image/png'); |
| | | |
| | | if (window.Blob && window.URL) { |
| | | const arr = dataURL.split(','); |
| | | const mime = arr[0].match(/:(.*?);/)[1]; |
| | | const bstr = atob(arr[1]); |
| | | let n = bstr.length; |
| | | const u8arr = new Uint8Array(n); |
| | | while (n--) { |
| | | u8arr[n] = bstr.charCodeAt(n); |
| | | } |
| | | const blobObj = new Blob([u8arr], { type: mime }); |
| | | if (window.navigator.msSaveBlob) { |
| | | window.navigator.msSaveBlob(blobObj, filename); |
| | | } else { |
| | | link.addEventListener('click', () => { |
| | | link.download = filename; |
| | | link.href = window.URL.createObjectURL(blobObj); |
| | | }); |
| | | } |
| | | } |
| | | const e = document.createEvent('MouseEvents'); |
| | | e.initEvent('click', false, false); |
| | | link.dispatchEvent(e); |
| | | }, 16); |
| | | } |
| | | |
| | | render() { |
| | | const { config, loading, empty, BID } = this.state |
| | | |
| | | let style = {...config.style} |
| | | if (empty && config.plot.empty === 'hidden') { |
| | | style.opacity = 0 |
| | | style.position = 'absolute' |
| | | style.zIndex = -1 |
| | | style.width = '100%' |
| | | } |
| | | |
| | | return ( |
| | | <div className="custom-line-chart-plot-box" style={config.style}> |
| | | <div className="custom-line-chart-plot-box" id={'anchor' + config.uuid} style={style}> |
| | | {loading ? |
| | | <div className="loading-mask"> |
| | | <div className="ant-spin-blur"></div> |
| | | <Spin /> |
| | | </div> : null |
| | | } |
| | | <NormalHeader config={config} BID={BID} menuType={this.props.menuType} refresh={this.refreshSearch} /> |
| | | <div className="canvas-wrap"> |
| | | <div className="chart-action"> |
| | | <NormalHeader config={config} BID={BID} refresh={this.refreshSearch} /> |
| | | <div className="canvas-wrap" ref={ref => this.wrap = ref}> |
| | | {config.plot.download === 'enable' && this.state.chart && !empty ? <DownloadOutlined onClick={this.downloadImage} className="system-color download"/> : null} |
| | | <div className={'chart-action' + (config.plot.download === 'enable' ? ' downable' : '')}> |
| | | {config.action.map(item => { |
| | | if (item.OpenType === 'excelOut') { |
| | | return ( |
| | |
| | | } |
| | | })} |
| | | </div> |
| | | <div className={'canvas' + (empty ? ' empty' : '')} style={{height: config.plot.height + 25}} id={this.state.chartId}></div> |
| | | <div className={'canvas' + (empty ? ' empty' : '')} id={this.state.chartId}></div> |
| | | </div> |
| | | {empty ? <Empty description={false}/> : null} |
| | | </div> |
| | |
| | | } |
| | | } |
| | | |
| | | // const mapStateToProps = (state) => { |
| | | // return { |
| | | // tabviews: state.tabviews, |
| | | // permMenus: state.permMenus, |
| | | // } |
| | | // } |
| | | |
| | | // const mapDispatchToProps = (dispatch) => { |
| | | // return { |
| | | // modifyTabview: (tabviews) => dispatch(modifyTabview(tabviews)) |
| | | // } |
| | | // } |
| | | |
| | | // export default connect(mapStateToProps, mapDispatchToProps)(LineChart) |
| | | export default LineChart |