/* * << * Davinci * == * Copyright (C) 2016 - 2017 EDP * == * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * >> */ import React from 'react' import classnames from 'classnames' import LocalControlPanel from 'containers/ControlPanel/Local' import DashboardItemMask from './DashboardItemMask' import DownloadCsv, { IDownloadCsvProps } from 'components/DownloadCsv' import { DrillCharts, WidgetDimension, DrillType, IDrillDetail } from 'components/DataDrill/types' import DataDrill from 'components/DataDrill/Panel' import DataDrillHistory from 'components/DataDrill/History' import { operationWidgetProps } from 'components/DataDrill/abstract/widgetOperating' import { strategiesOfDrillUpHasDrillHistory, strategiesOfDrillUpNullDrillHistory, strategiesOfDrillDownHasDrillHistory, strategiesOfDrillDownNullDrillHistory } from 'components/DataDrill/strategies' import { getLastItemValueOfArray } from 'components/DataDrill/util' import { IFormedView, IFormedViews, IShareFormedViews, IViewModel } from 'containers/View/types' import Widget, { IWidgetConfig, IPaginationParams, RenderType } from 'containers/Widget/components/Widget' import { ChartTypes } from 'containers/Widget/config/chart/ChartTypes' import { DrillableChart } from 'containers/Widget/config/chart/DrillableChart' import { IconProps } from 'antd/lib/icon' import { Icon, Tooltip, Popconfirm, Popover, Dropdown, Menu } from 'antd' import ModulePermission from 'containers/Account/components/checkModulePermission' import ShareDownloadPermission from 'containers/Account/components/checkShareDownloadPermission' import { IProject } from 'containers/Projects/types' import { IQueryConditions, IQueryVariableMap, TShareVizsType, ILoadData } from '../types' import { IWidgetFormed, IWidgetBase } from 'app/containers/Widget/types' import { ControlPanelLayoutTypes, ControlPanelTypes } from 'app/components/Control/constants' import { OnGetControlOptions } from 'app/components/Control/types' import styles from '../Dashboard.less' import utilStyles from 'app/assets/less/util.less' import EnhancerPanel from 'components/DataDrill/EnhancerPanel' interface IDashboardItemProps { itemId: number alias?: string widget: IWidgetFormed widgets: IWidgetFormed[] formedViews: IFormedViews | IShareFormedViews view?: Partial isTrigger?: boolean datasource: any loading: boolean polling: boolean interacting: boolean frequency: number shareToken: string shareLoading?: boolean downloadCsvLoading: boolean rendered?: boolean renderType: RenderType selectedItems: number[] currentProject?: IProject queryConditions: IQueryConditions container?: string errorMessage: string onSelectDrillHistory?: (history?: any, item?: number, itemId?: number) => void onLoadData: ILoadData onShowEdit?: ( itemId: number ) => (e: React.MouseEvent) => void onShowDrillEdit?: ( itemId: number ) => (e: React.MouseEvent) => void onDeleteDashboardItem?: (itemId: number) => () => void onResizeDashboardItem: (itemId: number) => void onRenderChartError: (itemId: number, error: Error) => void onOpenSharePanel?: ( id: number, type: TShareVizsType, title: string, itemId?: number ) => void onDownloadCsv: (itemId: number) => void onTurnOffInteract: (itemId: number) => void onShowFullScreen: (itemId: number) => void onCheckTableInteract: (itemId: number) => boolean onDoTableInteract: (itemId: number, triggerData: object) => void onEditWidget?: (itemId: number, widgetId: number) => void onDrillData?: (e: object) => void onSelectChartsItems?: ( itemId: number, renderType: string, selectedItems: number[] ) => void onGetControlOptions: OnGetControlOptions onControlSearch: ( type: ControlPanelTypes, relatedItems: number[], formValues?: object, itemId?: number ) => void onMonitoredSyncDataAction?: () => void onMonitoredSearchDataAction?: () => void } interface IDashboardItemStates { controlPanelVisible: boolean queryVariables: IQueryVariableMap model: IViewModel isDrilling: boolean dataDrillPanelPosition: boolean | object whichDataDrillBrushed: boolean | object[] sourceDataOfBrushed: object[] sourceDataGroup: string[] // isShowDrillPanel: boolean widgetProps: IWidgetConfig cacheWidgetProps: IWidgetConfig cacheWidgetId: boolean | number } export class DashboardItem extends React.PureComponent< IDashboardItemProps, IDashboardItemStates > { constructor(props) { super(props) this.state = { controlPanelVisible: false, queryVariables: {}, model: null, isDrilling: true, dataDrillPanelPosition: false, whichDataDrillBrushed: false, sourceDataOfBrushed: [], cacheWidgetProps: null, widgetProps: null, cacheWidgetId: false, sourceDataGroup: [] } } public static defaultProps = { onShowEdit: () => void 0, onShowDrillEdit: () => void 0, onDeleteDashboardItem: () => void 0 } private pollingTimer: number private container: HTMLDivElement = null public componentWillMount() { const { itemId, widget, view, onLoadData, container } = this.props const { cacheWidgetProps, cacheWidgetId } = this.state if (container === 'share') { if (widget.config.autoLoadData) { onLoadData('clear', itemId) } this.initPolling(this.props) } this.setState({ model: view.model }) if (!cacheWidgetProps) { this.setState({ widgetProps: { ...widget.config }, cacheWidgetProps: { ...widget.config }, cacheWidgetId: widget.id }) } } public componentWillReceiveProps(nextProps: IDashboardItemProps) { const { widget, queryConditions } = this.props let { model } = this.state if (nextProps.widget !== widget) { model = nextProps.view.model this.setState({ model }) } if (nextProps.queryConditions !== queryConditions) { const { variables, linkageVariables, globalVariables } = nextProps.queryConditions this.setState({ queryVariables: [ ...variables, ...linkageVariables, ...globalVariables ].reduce((obj, { name, value }) => { obj[`$${name}$`] = value return obj }, {}) }) } } public componentWillUpdate( nextProps: IDashboardItemProps, nextState: IDashboardItemStates ) { const { itemId, widget, polling, frequency, rendered, container, onLoadData } = nextProps if (!container) { if (!this.props.rendered && rendered) { // clear if (widget.config.autoLoadData) { onLoadData('clear', itemId) } this.initPolling(this.props) } } if (polling !== this.props.polling || frequency !== this.props.frequency) { this.initPolling(nextProps) } } public componentDidUpdate(prevProps, prevState) { if (prevState.controlPanelVisible !== this.state.controlPanelVisible) { const { itemId, onResizeDashboardItem } = this.props onResizeDashboardItem(itemId) } } public componentWillUnmount() { clearInterval(this.pollingTimer) } private initPolling = (props: IDashboardItemProps) => { const { polling, frequency, itemId, onLoadData } = props clearInterval(this.pollingTimer) if (polling) { this.pollingTimer = window.setInterval(() => { onLoadData('refresh', itemId) }, Number(frequency) * 1000) } } private syncData = () => { const { itemId, onLoadData, onMonitoredSyncDataAction } = this.props onLoadData('flush', itemId) if (onMonitoredSyncDataAction) { onMonitoredSyncDataAction() } } private toggleControlPanel = () => { this.setState({ controlPanelVisible: !this.state.controlPanelVisible }) } private onFullScreen = () => { const { itemId, onShowFullScreen } = this.props onShowFullScreen(itemId) } private downloadCsv = () => { const { itemId, onDownloadCsv } = this.props onDownloadCsv(itemId) } private openSharePanel = () => { const { itemId, widget, onOpenSharePanel } = this.props const { id, name } = widget onOpenSharePanel(id, 'widget', name, itemId) } private checkTableInteract = () => { const { itemId, onCheckTableInteract } = this.props return onCheckTableInteract(itemId) } private doInteract = (triggerData) => { const { itemId, onDoTableInteract } = this.props onDoTableInteract(itemId, triggerData) } private paginationChange = (pageNo: number, pageSize: number, orders) => { const { itemId, queryConditions, onLoadData } = this.props const { drillHistory } = queryConditions const pagination = { ...queryConditions.pagination, pageNo, pageSize } if (drillHistory && drillHistory.length) { const drillStatus = drillHistory[drillHistory.length - 1] onLoadData('clear', itemId, { pagination, orders, drillStatus }) } else { onLoadData('clear', itemId, { pagination, orders }) } } private turnOffInteract = () => { const { onTurnOffInteract, itemId } = this.props onTurnOffInteract(itemId) } private toWorkbench = () => { const { itemId, widget } = this.props this.props.onEditWidget(itemId, widget.id) } private getDataDrillDetail = (position) => { if (position && position.length) { try { const ps = JSON.parse(position) const { range, brushed, sourceData, sourceGroup } = ps const dataDrillPanelPosition = void 0 const sourceDataOfBrushed = sourceData && sourceData.length ? sourceData : [] const whichDataDrillBrushed = brushed && brushed.length ? brushed : [] const sourceDataGroup = sourceGroup && sourceGroup.length ? sourceGroup : [] this.setState({ dataDrillPanelPosition, whichDataDrillBrushed, sourceDataOfBrushed, sourceDataGroup }) } catch (error) { throw error } } } private drillDataHistory = (history, item: number, itemId) => { const { onSelectDrillHistory, queryConditions } = this.props const { widgetProps, cacheWidgetProps } = this.state const { drillHistory } = queryConditions if (onSelectDrillHistory) { if (item === -1 && !history) { this.setState({ widgetProps: cacheWidgetProps }) } else { const { cols, rows } = drillHistory[item] this.setState({ widgetProps: { ...widgetProps, cols, rows } }) } onSelectDrillHistory(history, item, itemId) } } private receiveWidgetId() { const { widget } = this.props operationWidgetProps.receive(widget.id) } private isHasDrillHistory(): boolean { const { queryConditions } = this.props const { drillHistory } = queryConditions return !!(drillHistory && drillHistory.length !== 0) } private getLastDrillHistory() { const { queryConditions } = this.props const { drillHistory } = queryConditions return [...drillHistory].pop() } private sendDrillDetail(e) { const { itemId, widget, onDrillData } = this.props if (onDrillData) { onDrillData({ ...e, itemId, widgetId: widget.id }) } } private drillUp = (name: string) => { // a group name by drill this.receiveWidgetId() const { sourceDataOfBrushed } = this.state const isHasDrillHistory = this.isHasDrillHistory() let set if (isHasDrillHistory) { const getLastDrillHistory = this.getLastDrillHistory() set = strategiesOfDrillUpHasDrillHistory( getLastDrillHistory, this.state.widgetProps )({ name }, sourceDataOfBrushed) } else { set = strategiesOfDrillUpNullDrillHistory( operationWidgetProps, this.state.widgetProps )({ name }, sourceDataOfBrushed) } const { pivot, coustomTable } = set if (operationWidgetProps.isPivot()) { const { cols, rows, type, groups, filters, widgetProps, currentGroup } = pivot() this.setState({ widgetProps }) this.sendDrillDetail({ cols, rows, type, groups, filters, currentGroup }) return } if (this.isCoustomTable()) { const { cols, rows, type, groups, filters, widgetProps, currentGroup } = coustomTable() this.setState({ widgetProps }) this.sendDrillDetail({ cols, rows, type, groups, filters, currentGroup }) return } } private isCoustomTable() { return operationWidgetProps.isCoustomTable() } private drillDown = (name: string, dimensions?: WidgetDimension) => { const { sourceDataOfBrushed, sourceDataGroup } = this.state this.receiveWidgetId() const isHasDrillHistory = this.isHasDrillHistory() const dimetionAxis = operationWidgetProps.getDimetionAxis() let set let strategiteStream if (isHasDrillHistory) { const getLastDrillHistory = this.getLastDrillHistory() set = strategiesOfDrillDownHasDrillHistory( getLastDrillHistory, this.state.widgetProps )({ name }, sourceDataOfBrushed, sourceDataGroup) } else { set = strategiesOfDrillDownNullDrillHistory( operationWidgetProps, this.state.widgetProps )({ name }, sourceDataOfBrushed, sourceDataGroup) } const { dimetionAxisCol, dimetionAxisRow, pivotCol, pivotRow, coustomTable, defaultScenes } = set if (dimensions && dimensions.length) { if (dimensions === WidgetDimension.COL) { strategiteStream = pivotCol() } else if (dimensions === WidgetDimension.ROW) { strategiteStream = pivotRow() } } else if (operationWidgetProps.isCoustomTable()) { strategiteStream = coustomTable() } else if (dimetionAxis && dimetionAxis.length) { if (dimetionAxis === WidgetDimension.ROW) { strategiteStream = dimetionAxisRow() } else if (dimetionAxis === WidgetDimension.COL) { strategiteStream = dimetionAxisCol() } } else { strategiteStream = defaultScenes() } const { cols, rows, type, groups, filters, widgetProps, currentGroup } = strategiteStream this.sendDrillDetail({ cols, rows, type, groups, filters, currentGroup }) this.setState({ widgetProps }) } private selectChartsItems = (selectedItems) => { const { onSelectChartsItems, itemId } = this.props if (onSelectChartsItems) { onSelectChartsItems(itemId, 'select', selectedItems) } } private renderChartError = (error: Error) => { const { itemId, onRenderChartError } = this.props onRenderChartError(itemId, error) } public render() { const { alias, itemId, widget, formedViews, datasource, loading, interacting, shareToken, shareLoading, downloadCsvLoading, renderType, currentProject, queryConditions, onLoadData, onShowEdit, onShowDrillEdit, onSelectDrillHistory, onGetControlOptions, onControlSearch, onDeleteDashboardItem, onMonitoredSearchDataAction, container, errorMessage } = this.props const { drillHistory } = queryConditions const data = datasource.resultList const { controlPanelVisible, queryVariables, widgetProps, isDrilling, model, sourceDataGroup, sourceDataOfBrushed } = this.state let downloadButton let shareButton let widgetButton let dropdownMenu if (currentProject) { const DownloadButton = ShareDownloadPermission( currentProject, 'download' )(DownloadCsv) downloadButton = ( ) const ShareButton = ShareDownloadPermission( currentProject, 'share' )(Icon) shareButton = ( ) const EditButton = ModulePermission< React.DetailedHTMLProps< React.HTMLAttributes, HTMLSpanElement > >( currentProject, 'viz', false )(Span) widgetButton = ( {/* */} ) } if (container === 'share') { downloadButton = ( ) } else { const InfoButton = ModulePermission< React.DetailedHTMLProps< React.HTMLAttributes, HTMLSpanElement > >( currentProject, 'viz', false )(Span) const DeleteButton = ModulePermission< React.DetailedHTMLProps< React.HTMLAttributes, HTMLSpanElement > >( currentProject, 'viz', true )(Span) const menu = ( 基本信息 删除 ) dropdownMenu = ( ) } const controlToggle = !!widget.config.controls.length && ( ) const loadingIcon = loading && const descIcon = widget.description && ( ) const errorIcon = errorMessage && (

错误信息:

{errorMessage}

} placement="bottomLeft" overlayClassName={styles.widgetInfoContent} >
) const gridItemClass = classnames({ [styles.gridItem]: true, [styles.interact]: interacting }) const isDrillableChart = DrillableChart.some( (drillable) => drillable === widget.config.selectedChart ) const drillInteractIcon = this.props.isTrigger === false ? ( isDrillableChart ? ( ) : ( void 0 ) ) : ( ) const dataDrillPanel = ( ) const dataDrillHistoryClass = classnames({ [styles.dataDrillHistory]: true, [utilStyles.hide]: !(drillHistory && drillHistory.length > 0) }) const dataDrillHistory = (
) const { selectedChart, cols, rows, metrics } = widget.config const hasDataConfig = !!(cols.length || rows.length || metrics.length) const empty = ( ) const widgetName = alias || widget.name return (
(this.container = f)}>

{widgetName}

{descIcon} {errorIcon} {controlToggle} {loadingIcon} {}
{!loading && } {widgetButton} {shareButton} {downloadButton} {dropdownMenu}
{drillInteractIcon}

点击取消联动

{dataDrillHistory}
) } } function Span( props: React.DetailedHTMLProps< React.HTMLAttributes, HTMLSpanElement > ) { return {props.children} } export default DashboardItem