123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- import React from 'react'
- import produce from 'immer'
- import { uuid } from 'utils/util'
- import { IDataParams } from '../../OperatingPanel'
- import { IDataParamSource } from '../../Dropbox'
- import { getFieldAlias } from 'containers/Widget/components/Config/Field'
- import { decodeMetricName, getAggregatorLocale } from 'containers/Widget/components/util'
- import {
- ITableConfig, ITableHeaderConfig, ITableColumnConfig,
- TableCellStyleTypes, DefaultTableCellStyle } from 'containers/Widget/components/Config/Table'
- import { pageSizeOptions } from './constants'
- import { Icon, Row, Col, Select, Radio, Checkbox, Modal } from 'antd'
- const { Option } = Select
- const RadioGroup = Radio.Group
- const RadioButton = Radio.Button
- const HeaderConfigModal = React.lazy(() => import('containers/Widget/components/Config/Table/Header/HeaderConfigModal'))
- const ColumnConfigModal = React.lazy(() => import('containers/Widget/components/Config/Table/Column/ColumnConfigModal'))
- const styles = require('../../Workbench.less')
- interface ITableSectionProps {
- dataParams: IDataParams
- config: ITableConfig
- onChange: (prop: string, value: any) => void
- }
- interface ITableSectionStates {
- headerConfigModalVisible: boolean
- columnConfigModalVisible: boolean
- validColumns: IDataParamSource[]
- validHeaderConfig: ITableHeaderConfig[]
- validColumnConfig: ITableColumnConfig[]
- }
- export class TableSection extends React.PureComponent<ITableSectionProps, ITableSectionStates> {
- public constructor (props) {
- super(props)
- const validColumns = this.getCurrentTableColumns(props)
- const validHeaderConfig = this.getValidHeaderConfig(props, validColumns)
- const validColumnConfig = this.getValidColumnConfig(props, validColumns)
- this.state = {
- headerConfigModalVisible: false,
- columnConfigModalVisible: false,
- validColumns,
- validHeaderConfig,
- validColumnConfig
- }
- }
- public componentWillReceiveProps (nextProps: ITableSectionProps) {
- const validColumns = this.getCurrentTableColumns(nextProps)
- const validHeaderConfig = this.getValidHeaderConfig(nextProps, validColumns)
- const validColumnConfig = this.getValidColumnConfig(nextProps, validColumns)
- this.setState({
- validColumns,
- validHeaderConfig,
- validColumnConfig
- })
- }
- private getCurrentTableColumns (props: ITableSectionProps) {
- const { dataParams } = props
- const keyNames = ['cols', 'metrics', 'rows']
- const validColumns: IDataParamSource[] = produce(dataParams, (draft) => {
- const columns = Object.entries(draft).reduce((acc, [key, value]) => {
- if (!~keyNames.indexOf(key)) { return acc }
- if (key !== 'metrics') { return acc.concat(value.items) }
- return acc.concat(value.items.map((item) => ({
- ...item,
- alias: this.getColumnDisplayName(item)
- })))
- }, [])
- return columns
- })
- return validColumns
- }
- private getValidHeaderConfig = (props: ITableSectionProps, validColumns: IDataParamSource[]) => {
- const { config } = props
- const columns = [...validColumns]
- const localHeaderConfig = produce(config.headerConfig, (draft) => {
- this.traverseHeaderConfig(draft, columns)
- let dimensionIdx = 0
- columns.forEach((c) => {
- const cfg = {
- key: uuid(5),
- headerName: c.name,
- alias: this.getColumnDisplayName(c),
- visualType: c.visualType,
- isGroup: false,
- style: { ...DefaultTableCellStyle },
- children: null
- }
- if (c.agg) {
- draft.push(cfg)
- } else {
- draft.splice(dimensionIdx++, 0, cfg)
- }
- })
- })
- return localHeaderConfig
- }
- private getValidColumnConfig = (props: ITableSectionProps, validColumns: IDataParamSource[]) => {
- const { config } = props
- const validColumnConfig = produce(config.columnsConfig, (draft) => {
- const config: ITableColumnConfig[] = []
- validColumns.forEach((column) => {
- const existedConfig = draft.find((item) => item.columnName === column.name)
- if (existedConfig) {
- config.push({
- ...existedConfig,
- alias: this.getColumnDisplayName(column),
- visualType: column.visualType
- })
- } else {
- config.push({
- columnName: column.name,
- alias: this.getColumnDisplayName(column),
- visualType: column.visualType,
- styleType: TableCellStyleTypes.Column,
- style: { ...DefaultTableCellStyle },
- conditionStyles: []
- })
- }
- })
- return config
- })
- return validColumnConfig
- }
- private traverseHeaderConfig = (
- cursorConfig: ITableHeaderConfig[],
- validColumns: IDataParamSource[]
- ) => {
- cursorConfig.sort((cfg1, cfg2) => {
- if (cfg1.isGroup || cfg2.isGroup) { return 0 }
- const cfg1Idx = validColumns.findIndex((column) => column.name === cfg1.headerName)
- const cfg2Idx = validColumns.findIndex((column) => column.name === cfg2.headerName)
- return cfg1Idx - cfg2Idx
- })
- for (let idx = cursorConfig.length - 1; idx >= 0; idx--) {
- const currentConfig = cursorConfig[idx]
- const { isGroup, headerName } = currentConfig
- if (!isGroup) {
- const columnIdx = validColumns.findIndex((c) => c.name === headerName)
- if (columnIdx < 0) {
- cursorConfig.splice(idx, 1)
- } else {
- const column = validColumns[columnIdx]
- currentConfig.alias = this.getColumnDisplayName(column)
- currentConfig.visualType = column.visualType
- validColumns.splice(columnIdx, 1)
- }
- }
- if (Array.isArray(currentConfig.children) && currentConfig.children.length) {
- this.traverseHeaderConfig(currentConfig.children, validColumns)
- }
- }
- }
- private selectChange = (prop) => (value) => {
- this.props.onChange(prop, value)
- }
- private switchChange = (name) => (e) => {
- this.props.onChange(name, e.target.value)
- }
- private checkboxChange = (name) => (e) => {
- this.props.onChange(name, e.target.checked)
- }
- private deleteHeaderConfig = () => {
- const { onChange } = this.props
- Modal.confirm({
- title: '确认删除表头样式与分组?',
- onOk: () => {
- onChange('headerConfig', [])
- }
- })
- }
- private showHeaderConfig = () => {
- this.setState({
- headerConfigModalVisible: true
- })
- }
- private closeHeaderConfig = () => {
- this.setState({
- headerConfigModalVisible: false
- })
- }
- private saveHeaderConfig = (config: ITableHeaderConfig[]) => {
- const { onChange } = this.props
- onChange('headerConfig', config)
- const validFixedColumns = config.map((c) => c.headerName)
- const { config: tableConfig } = this.props
- let { leftFixedColumns, rightFixedColumns } = tableConfig
- leftFixedColumns = leftFixedColumns.filter((col) => ~validFixedColumns.indexOf(col))
- rightFixedColumns = rightFixedColumns.filter((col) => ~validFixedColumns.indexOf(col))
- this.selectChange('leftFixedColumns')(leftFixedColumns)
- this.selectChange('rightFixedColumns')(rightFixedColumns)
- this.setState({
- headerConfigModalVisible: false
- })
- }
- private deleteColumnConfig = () => {
- const { onChange } = this.props
- Modal.confirm({
- title: '确认删除表格数据列设置?',
- onOk: () => {
- onChange('columnsConfig', [])
- }
- })
- }
- private showColumnConfig = () => {
- this.setState({
- columnConfigModalVisible: true
- })
- }
- private closeColumnConfig = () => {
- this.setState({
- columnConfigModalVisible: false
- })
- }
- private saveColumnConfig = (config: ITableColumnConfig[]) => {
- const { onChange } = this.props
- onChange('columnsConfig', config)
- this.setState({
- columnConfigModalVisible: false
- })
- }
- private getColumnDisplayName (column: IDataParamSource) {
- let displayName = `${decodeMetricName(column.name)}`
- if (column.agg) {
- displayName = `[${getAggregatorLocale(column.agg)}]${displayName}`
- }
- const alias = getFieldAlias(column.field, {})
- if (alias) {
- displayName = `${displayName}[${alias}]`
- }
- return displayName
- }
- private getValidFixedColumns (headerConfig: ITableHeaderConfig[], columns: IDataParamSource[]) {
- let options: JSX.Element[]
- if (!headerConfig.length) {
- options = columns.map((c) => {
- const displayName = this.getColumnDisplayName(c)
- return (<Option key={c.name} value={c.name}>{displayName}</Option>)
- })
- } else {
- options = headerConfig
- .filter((c) => c.isGroup || ~columns.findIndex((column) => column.name === c.headerName))
- .map((c) => {
- let displayName
- if (c.isGroup) {
- displayName = c.headerName
- } else {
- const column = columns.find((column) => column.name === c.headerName)
- displayName = this.getColumnDisplayName(column)
- }
- return (<Option key={c.headerName} value={c.headerName}>{displayName}</Option>)
- })
- }
- return options
- }
- public render () {
- const { config } = this.props
- const {
- leftFixedColumns, rightFixedColumns, headerFixed, bordered, size,
- autoMergeCell, withPaging, pageSize, withNoAggregators } = config
- const {
- validColumns, validHeaderConfig, validColumnConfig,
- headerConfigModalVisible, columnConfigModalVisible } = this.state
- const fixedColumnOptions = this.getValidFixedColumns(validHeaderConfig, validColumns)
- return (
- <div>
- <div className={styles.paneBlock}>
- <h4>
- <span>表头样式与分组</span>
- <Icon type="delete" onClick={this.deleteHeaderConfig} />
- <Icon type="edit" onClick={this.showHeaderConfig} />
- </h4>
- </div>
- <div className={styles.paneBlock}>
- <h4>
- <span>表格数据列</span>
- <Icon type="delete" onClick={this.deleteColumnConfig} />
- <Icon type="edit" onClick={this.showColumnConfig} />
- </h4>
- </div>
- <div className={styles.paneBlock}>
- <div className={styles.blockBody}>
- <Row gutter={8} type="flex" align="middle" className={styles.blockRow}>
- <Col span={12}>
- <Checkbox checked={headerFixed} onChange={this.checkboxChange('headerFixed')}>固定表头</Checkbox>
- </Col>
- <Col span={12}>
- <Checkbox checked={bordered} onChange={this.checkboxChange('bordered')}>边框</Checkbox>
- </Col>
- </Row>
- </div>
- </div>
- <div className={styles.paneBlock}>
- <h4>左固定列</h4>
- <div className={styles.blockBody}>
- <Row gutter={8} type="flex" align="middle" className={styles.rowBlock}>
- <Col span={24}>
- <Select
- className={styles.blockElm}
- mode="tags"
- value={leftFixedColumns}
- onChange={this.selectChange('leftFixedColumns')}
- >
- {fixedColumnOptions}
- </Select>
- </Col>
- </Row>
- </div>
- </div>
- <div className={styles.paneBlock}>
- <h4>右固定列</h4>
- <div className={styles.blockBody}>
- <Row gutter={8} type="flex" align="middle" className={styles.rowBlock}>
- <Col span={24}>
- <Select
- className={styles.blockElm}
- mode="tags"
- value={rightFixedColumns}
- onChange={this.selectChange('rightFixedColumns')}
- >
- {fixedColumnOptions}
- </Select>
- </Col>
- </Row>
- </div>
- </div>
- <div className={styles.paneBlock}>
- <h4>大小</h4>
- <div className={styles.blockBody}>
- <Row gutter={8} type="flex" align="middle" className={styles.blockRow}>
- <Col span={24}>
- <RadioGroup size="small" value={size} onChange={this.switchChange('size')}>
- <RadioButton value="small">小</RadioButton>
- <RadioButton value="middle">中</RadioButton>
- <RadioButton value="default">大</RadioButton>
- </RadioGroup>
- </Col>
- </Row>
- </div>
- </div>
- <div className={styles.paneBlock}>
- <h4>自动合并相同内容</h4>
- <div className={styles.blockBody}>
- <Row gutter={8} type="flex" align="middle" className={styles.blockRow}>
- <Col span={24}>
- <RadioGroup size="small" value={autoMergeCell} onChange={this.switchChange('autoMergeCell')}>
- <RadioButton value={true}>开启</RadioButton>
- <RadioButton value={false}>关闭</RadioButton>
- </RadioGroup>
- </Col>
- </Row>
- </div>
- </div>
- <div className={styles.paneBlock}>
- <h4>分页</h4>
- <div className={styles.blockBody}>
- <Row gutter={8} type="flex" align="middle" className={styles.blockRow}>
- <Col span={12}>
- <RadioGroup size="small" value={withPaging} onChange={this.switchChange('withPaging')}>
- <RadioButton value={true}>开启</RadioButton>
- <RadioButton value={false}>关闭</RadioButton>
- </RadioGroup>
- </Col>
- {!withPaging ? null :
- <Col span={12}>
- <Select
- size="small"
- className={styles.blockElm}
- value={pageSize}
- onChange={this.selectChange('pageSize')}
- >
- {pageSizeOptions}
- </Select>
- </Col>}
- </Row>
- </div>
- </div>
- <div className={styles.paneBlock}>
- <h4>使用原始数据</h4>
- <div className={styles.blockBody}>
- <Row gutter={8} type="flex" align="middle" className={styles.blockRow}>
- <Col span={24}>
- <RadioGroup size="small" value={withNoAggregators} onChange={this.switchChange('withNoAggregators')}>
- <RadioButton value={true}>开启</RadioButton>
- <RadioButton value={false}>关闭</RadioButton>
- </RadioGroup>
- </Col>
- </Row>
- </div>
- </div>
- <React.Suspense fallback={null}>
- <HeaderConfigModal
- visible={headerConfigModalVisible}
- config={validHeaderConfig}
- onCancel={this.closeHeaderConfig}
- onSave={this.saveHeaderConfig}
- />
- <ColumnConfigModal
- visible={columnConfigModalVisible}
- config={validColumnConfig}
- onCancel={this.closeColumnConfig}
- onSave={this.saveColumnConfig}
- />
- </React.Suspense>
- </div>
- )
- }
- }
- export default TableSection
|