Browse Source

指标板可视化模式设计/chart图缩略图替换

zhuth 6 years ago
parent
commit
d8587b9616

+ 16 - 2
src/components/chart/list.less

@@ -138,14 +138,28 @@
                                         height: 100%;
 
                                         &-table {
-                                            background-image: url(../../../static/images/table-default.png);
+                                            background-image: url(../../../static/images/thumbnail-table.png);
+                                            background-position: center;
+                                            background-size: contain;
+                                            background-repeat: no-repeat;
+                                            cursor: pointer;
+                                        }
+                                        &-aggregateTable {
+                                            background-image: url(../../../static/images/thumbnail-aggregateTable.png);
+                                            background-position: center;
+                                            background-size: contain;
+                                            background-repeat: no-repeat;
+                                            cursor: pointer;
+                                        }
+                                        &-indicator {
+                                            background-image: url(../../../static/images/thumbnail-indicator.png);
                                             background-position: center;
                                             background-size: contain;
                                             background-repeat: no-repeat;
                                             cursor: pointer;
                                         }
                                         &-empty {
-                                            background-image: url(../../../static/images/chart-default.png);
+                                            background-image: url(../../../static/images/thumbnail-default.png);
                                             background-position: center;
                                             background-size: contain;
                                             background-repeat: no-repeat;

+ 25 - 11
src/components/chart/thumbnail.jsx

@@ -1,19 +1,33 @@
 import React from 'react'
 const Thumbnail = ({ style, type, code, thumbnail }) => {
-    const viewType = ['bar', 'line', 'pie', 'scatter'].indexOf(type) !== -1 ? 'echarts' :
-        (['aggregateTable', 'dataView'].indexOf(type) !== -1 ? 'table' : 'default');
+    let children;
+    
+    switch(type) {
+        case 'bar':
+        case 'line':
+        case 'pie':
+        case 'scatter':
+            children = thumbnail ? <img className='chart-thumbnail chart-thumbnail-echarts' alt={code} src={thumbnail} />
+            : <div className='chart-thumbnail chart-thumbnail-empty'></div>
+            break;
+        case 'aggregateTable':
+            children = <div className='chart-thumbnail chart-thumbnail-aggregateTable'></div>
+            break;
+        case 'dataView':
+            children = <div className='chart-thumbnail chart-thumbnail-table'></div>
+            break;
+        case 'indicator':
+            children = <div className='chart-thumbnail chart-thumbnail-indicator'></div>
+            break;
+        default:
+            children = <div className='chart-thumbnail chart-thumbnail-empty'></div>
+            break;
+        
+    }
     
     return (
         <div style={{ ...style, width: '100%', height: '100%' }}>
-            {
-                viewType === 'echarts' ? (
-                    thumbnail ? <img className='chart-thumbnail chart-thumbnail-echarts' alt={code} src={thumbnail} />
-                    : <div className='chart-thumbnail chart-thumbnail-empty'></div>
-                ) : (
-                    viewType === 'table' ? <div className='chart-thumbnail chart-thumbnail-table'></div>
-                    : <div className='chart-thumbnail chart-thumbnail-empty'></div>
-                )
-            }
+            { children }
         </div>
     );
 }

+ 94 - 0
src/components/chartDesigner/charts/indicatorView.jsx

@@ -0,0 +1,94 @@
+/**
+ * 指标板
+ */
+import React from 'react'
+import EmptyContent from '../../common/emptyContent/index'
+import './indicatorView.less'
+class IndicatorView extends React.Component {
+    constructor(props) {
+        super(props);
+        this.state = {}
+    }
+
+    componentDidMount() {
+        this.autoLayout()
+        window.addEventListener('resize', this.autoLayout);
+    }
+
+    componentWillUnmount() {
+        window.removeEventListener('resize', this.autoLayout);
+    }
+
+    autoLayout = () => {
+        let container = this.containerRef;
+        if(!container) return;
+        let body = container.getElementsByClassName('indicator-body')[0];
+        let cards = body.getElementsByClassName('indicator-box');
+        let cardCount = cards.length;
+        let bodyBox = body.getBoundingClientRect();
+
+        let maxColNum = cardCount < 4 ? cardCount : 4; // 行数
+        let maxRowNum = Math.ceil(cardCount / maxColNum); // 列数
+        let cardHeight = bodyBox.height / maxRowNum - 8;
+        let cardWidth = (bodyBox.width - 18) / maxColNum - 8;
+        while(cardWidth < 180 && maxColNum > 1) {
+            maxColNum--;
+            maxRowNum = Math.ceil(cardCount / maxColNum);
+            cardHeight = bodyBox.height / maxRowNum - 8;
+            cardWidth = (bodyBox.width - 18) / maxColNum - 8;
+        }
+        cardHeight = cardHeight < 100 ? 100 : cardHeight;
+
+        if(cardCount === 1) {
+            cards[0].style.border = 'none';
+        }
+        for(let i = 0; i < cards.length; i++) {
+            cards[i].style.width = cardWidth + 'px';
+            cards[i].style.height = cardHeight + 'px';
+            let cells = cards[i].getElementsByClassName('cell');
+            for(let j = 0; j < cells.length; j++) {
+                let wrap = cells[j].getElementsByClassName('over-wrapper')[0];
+                wrap.style.width = cardWidth - 8 * 2 + 'px';
+            }
+        }
+    }
+
+    render() {
+        const { chartOption } = this.props;
+        const { data } = chartOption;
+        if(!chartOption || !chartOption.data || !chartOption.data.length === 0) {
+            return <div className='indicator-container empty' ref={ node => this.containerRef = node }>
+                <div className='indicator-body'>
+                    <EmptyContent />
+                </div>
+            </div>
+        }
+        return <div className='indicator-container' ref={ node => this.containerRef = node }>
+            <div className='indicator-body'>
+                {
+                    data.map((d, i) => (
+                        <div className={`indicator-box`} key={i}>
+                            <div className='row indicator-name'>
+                                <div className='cell rc-name'>
+                                    <div className='over-wrapper' title={d.name}>{d.name}</div>
+                                </div>
+                            </div>
+                            <div className='row indicator-key'>
+                                <div className='cell rc-key'>
+                                    <div className='over-wrapper' title={d.key}>{d.key}</div>
+                                </div>
+                            </div>
+                            <div className='row indicator-value'>
+                                <div className='cell rc-value'>
+                                    <div className='over-wrapper' title={d.value}>{(d.value === undefined || d.value === null) ? '--' : d.value}</div>
+                                </div>
+                            </div>
+                        </div>
+                    ))
+                }
+            </div>
+        </div>
+    }
+}
+
+export default IndicatorView

+ 59 - 0
src/components/chartDesigner/charts/indicatorView.less

@@ -0,0 +1,59 @@
+.indicator-container {
+    height: 100%;
+    width: 100%;
+    background: #fff;
+    &.empty {
+        background: @content-background-color;
+    }
+    .indicator-body {
+        width: 100%;
+        height: 100%;
+        overflow: auto;
+        flex-flow: row wrap;
+        // justify-content: center;
+        align-items: center;
+        align-content: center;
+        margin: 0 auto;
+        .indicator-box {
+            float: left;
+            display: table;
+            border: 1px solid #F6F6F7;
+            padding: 8px;
+            margin: 4px;
+            .row {
+                display: table-row;
+                overflow: hidden;
+                .cell {
+                    display: table-cell;
+                    vertical-align: middle;
+                    
+                    .over-wrapper {
+                        overflow: hidden;
+                        white-space: nowrap;
+                        text-overflow: ellipsis;
+                    }
+                    &.rc-name {
+
+                    }
+                    &.rc-key {
+                        font-size: 12px;
+                        color: #999;
+                    }
+                    &.rc-value {
+                        font-size: 28px;
+                        line-height: 28px;
+                        font-weight: bold;
+                        text-align: center;
+                        color: rgb(33, 83, 212);
+                    }
+                }
+            }
+            .indicator-name {
+                margin-bottom: 12px;
+            }
+            .indicator-value {
+                padding: 0 36px;
+            }
+        }
+    }
+}

+ 8 - 0
src/components/chartDesigner/content.jsx

@@ -13,6 +13,7 @@ import OtherConfigForm from './sections/otherConfigForm'
 import TableView from './charts/tableView'
 import EchartsView from './charts/echartsView'
 import AggregateTableView from './charts/aggregateTableView'
+import IndicatorView from './charts/indicatorView'
 import ToolBar from './sections/toolbar'
 import { connect } from 'dva'
 import EmptyContent from '../common/emptyContent/index'
@@ -54,6 +55,12 @@ class ChartDesignerContent extends React.Component {
     onCollapse = () => {
         this.setState({
             collapsed: !this.state.collapsed,
+        }, () => {
+            window.setTimeout(() => {
+                var e = document.createEvent("Event");
+                e.initEvent("resize", true, true);
+                window.dispatchEvent(e);
+            }, 500);
         })
     }
 
@@ -102,6 +109,7 @@ class ChartDesignerContent extends React.Component {
             chartView = (<EchartsView chartOption={chartOption} />);
         }else if(viewType === 'indicator') {
             configForm = (<IndicatorConfigForm autoRefresh={autoRefresh}/>);
+            chartView = (<IndicatorView key={hashcode(chartOption)} chartOption={chartOption} />);
         }else {
             chartView = <EmptyContent />
         }

+ 4 - 0
src/components/chartDesigner/sections/chartType.json

@@ -22,4 +22,8 @@
     "type": "scatter",
     "label": "散点图",
     "icon": "dot-chart"
+}, {
+    "type": "indicator",
+    "label": "指标板",
+    "myIcon": "bi-chartType-indicator"
 }]

+ 4 - 4
src/components/chartDesigner/sections/indicatorConfigForm.jsx

@@ -24,11 +24,11 @@ const IndicatorConfigForm = ({ autoRefresh, chartDesigner, dispatch }) => {
 					onChange={(value) => {
                         let column = value ? columns.find(c => c.name === value) : null;
                         column = column || {};
-						dispatch({ type: 'chartDesigner/changeField', name: 'indicatorConfig', value: { ...indicatorConfig, xAxis: { column } }, autoRefresh });
+						dispatch({ type: 'chartDesigner/changeField', name: 'indicatorConfig', value: { ...indicatorConfig, xAxis: { column }, sortColumn: { key: column.name, label: column.label } }, autoRefresh });
 					}}
 					value={indicatorConfig.xAxis.column.name}
 				>
-					{columns.map((c, i)=>{
+					{columns.filter(c => c.name !== indicatorConfig.yAxis.column.name).map((c, i)=>{
 						return (<Option key={i} value={c.name}>{c.label}</Option>)
 					})}
 				</Select>
@@ -43,11 +43,11 @@ const IndicatorConfigForm = ({ autoRefresh, chartDesigner, dispatch }) => {
 					onChange={(value) => {
                         let column = value ? columns.find(c => c.name === value) : null;
                         column = column || {};
-						dispatch({ type: 'chartDesigner/changeField', name: 'indicatorConfig', value: { ...indicatorConfig, yAxis: { column } }, autoRefresh });
+						dispatch({ type: 'chartDesigner/changeField', name: 'indicatorConfig', value: { ...indicatorConfig, yAxis: { column }, sortColumn: indicatorConfig.xAxis.column.name ? { key: indicatorConfig.xAxis.column.name, label: indicatorConfig.xAxis.column.label } : { key: column.name, label: column.label } }, autoRefresh });
 					}}
 					value={indicatorConfig.yAxis.column.name}
 				>
-					{columns.map((c, i)=>{
+					{columns.filter(c => c.type === 'scale').filter(c => c.name !== indicatorConfig.xAxis.column.name).map((c, i)=>{
 						return (<Option key={i} value={c.name}>{c.label}</Option>)
 					})}
 				</Select>

+ 3 - 3
src/components/chartDesigner/sections/toolbar.jsx

@@ -5,7 +5,7 @@ import { connect } from 'dva'
 import moment from 'moment'
 import DataPreview from '../../common/dataPreview/dataPreview'
 import Filter from '../../common/filterBox/filter'
-import CusIcon from '../../common/cusIcon/index'
+// import CusIcon from '../../common/cusIcon/index'
 import './toolbar.less'
 
 class Toolbar extends React.Component {
@@ -125,7 +125,7 @@ class Toolbar extends React.Component {
                         />
                     ))}
                 </div>
-                <div className='tools'>
+                {/* <div className='tools'>
                     <span onClick={() => {
                         this.setState({
                             visibleDataPreviewBox: true
@@ -133,7 +133,7 @@ class Toolbar extends React.Component {
                     }}>
                         <CusIcon type='bi-view-columns'/>查看列
                     </span>
-                </div>
+                </div> */}
                 {visibleFilterBox && <FilterBox code={code} columns={columns} filterData={filters} visibleFilterBox={visibleFilterBox} showFilterBox={this.showFilterBox} hideFilterBox={this.hideFilterBox} createFilters={this.createFilters} />}
                 {visibleDataPreviewBox && <DataPreview
                     title='查看列'

+ 1 - 0
src/components/common/emptyContent/index.less

@@ -1,5 +1,6 @@
 .empty-content {
     height: 100%;
+    width: 100%;
     display: flex;
     flex-direction: column;
     justify-content: center;

+ 3 - 0
src/components/dashboardDesigner/chartView.jsx

@@ -2,6 +2,7 @@ import React from 'react'
 import AggregateTableView from '../chartDesigner/charts/aggregateTableView'
 import TableView from '../chartDesigner/charts/tableView'
 import EchartsView from '../chartDesigner/charts/echartsView'
+import IndicatorView from '../chartDesigner/charts/indicatorView'
 import RichTextEditor from './richTextEditor'
 import { connect } from 'dva'
 import { hashcode } from '../../utils/baseUtils'
@@ -66,6 +67,8 @@ class ChartView extends React.Component {
                     />);
                 }else if(['line', 'bar', 'pie', 'scatter'].indexOf(chartType) > -1) {
                     children = (<EchartsView key={`${chartCode}-${layout.w}-${layout.h}`} chartOption={chartOption}/>);
+                }else if(chartType === 'indicator') {
+                    children = (<IndicatorView key={`${chartCode}-${layout.w}-${layout.h}`} chartOption={chartOption}/>);
                 }
             }
         }else if(viewType === 'richText') { // 富文本类型

+ 1 - 1
src/components/dashboardDesigner/viewLayout.less

@@ -86,7 +86,7 @@
         }
       }
       .chart-default { // echart缺省
-        background-image: url(../../../static/images/chart-default.png);
+        background-image: url(../../../static/images/thumbnail-default.png);
         width: 100%;
         height: 100%;
         max-width: 200px;

+ 10 - 2
src/models/chart.js

@@ -209,7 +209,6 @@ export default {
                             dataConnectName: d.dataConnectionName,
                             access: d.authority === '1', // 权限
                             database: d.dbStatus === '0', // 数据源是否还存在
-                            // TODO 过渡方案
                             type: CHART_TYPE[d.chartType] || d.chartType,
                             creatorCode: d.createId + '',
                             creatorName: d.createBy,
@@ -333,8 +332,17 @@ export default {
                 }; // 基本属性
                 let styleObj = {};
                 if(!!baseConfig.viewType) {
+                    let _CHART_TYPE = {
+                        "bar": "Histogram",
+                        "line": "Line",
+                        "pie": "Pie",
+                        "scatter": "scatter",
+                        "aggregateTable": "population",
+                        "dataView": "individual",
+                        "indicator": "indicator"
+                    };
                     styleObj[baseConfig.viewType] = styleConfig[baseConfig.viewType];
-                    body.chartType = baseConfig.viewType;
+                    body.chartType = _CHART_TYPE[baseConfig.viewType];
                     body.chartConfig = JSON.stringify(chartDesigner[`${baseConfig.viewType}Config`]);
                 }
                 body.style = JSON.stringify(styleObj);

+ 12 - 3
src/models/chartDesigner.js

@@ -55,7 +55,7 @@ export default {
             defaultLineThreshold: 200,
             defaultPieThreshold: 20,
             defaultScatterThreshold: 1000,
-            defaultIndicatorThreshold: 5,
+            defaultIndicatorThreshold: 6,
             baseConfig: { dataSource: { code: '' }, viewType: '' },
             aggregateTableConfig: { targetColumn: {}, statistics: [], groupBy: [] },
             dataViewConfig: { viewColumns: [], sortColumn: {key: ''}, sortType: 'asc' },
@@ -63,7 +63,7 @@ export default {
             lineConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''}, threshold: 200 },
             pieConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, threshold: 20 },
             scatterConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''}, threshold: 1000 },
-            indicatorConfig: { xAxis: { column: {} }, yAxis: { column: {} }, threshold: 5 },
+            indicatorConfig: { xAxis: { column: {} }, yAxis: { column: {} }, threshold: 6 },
             theme: 'default',
             styleConfig: {},
             otherConfig:{},
@@ -223,7 +223,16 @@ export default {
                     fetchConfig: JSON.stringify(fetchConfig),
                 }; // 基本属性
                 if(!!baseConfig.viewType) {
-                    body.chartType = baseConfig.viewType;
+                    let _CHART_TYPE = {
+                        "bar": "Histogram",
+                        "line": "Line",
+                        "pie": "Pie",
+                        "scatter": "scatter",
+                        "aggregateTable": "population",
+                        "dataView": "individual",
+                        "indicator": "indicator"
+                    };
+                    body.chartType = _CHART_TYPE[baseConfig.viewType];
                     body.chartConfig = JSON.stringify(chartDesigner[`${baseConfig.viewType}Config`]);
                 }
 

+ 2 - 1
src/models/chartType.json

@@ -4,5 +4,6 @@
     "Pie": "pie",
     "scatter": "scatter",
     "population": "aggregateTable",
-    "individual": "dataView"
+    "individual": "dataView",
+    "indicator": "indicator"
 }

+ 2 - 3
src/models/dashboardDesigner.js

@@ -496,8 +496,7 @@ export default {
             const { item, mandatory, page, pageSize } = action;
             const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
             const { creatorCode, filters } = dashboardDesigner;
-            const { chartCode, theme } = item;
-            
+            const { chartCode, theme, chartType } = item;
             if(!mandatory && !!item.chartOption) {
                 return false;
             }
@@ -510,7 +509,7 @@ export default {
                     filters: getBodyFilters(getTrueFilters(item, filters)),
                     testPage: {
                         pageNum: page|| 1,
-                        pageSize: pageSize || 99, 
+                        pageSize: chartType === 'indicator' ? 99 : pageSize || 99, 
                     }
                 };
                 const res = yield call(service.fetch, {

+ 25 - 0
src/models/parseChartOption.js

@@ -45,6 +45,10 @@ export default function(viewType, data, chartConfig, themeName, styleConfig, cha
                 o = dataViewOption(data, chartConfig, themeConfig, styleConfig);
                 break;
             }
+            case 'indicator':
+                themeConfig = theme.indicator;
+                o = indicatorOption(data, chartConfig, themeConfig, styleConfig);
+                break;
             default:{
                 o = {};
                 break;
@@ -520,5 +524,26 @@ function dataViewOption(data, dataViewConfig, themeConfig, styleConfig) {
         total,
     };
 
+    return option;
+}
+
+function indicatorOption(data, indicatorConfig, themeConfig, styleConfig) {
+    const { list } = data.valueList;
+    let { xAxis, yAxis, threshold } = indicatorConfig;
+    let option = {
+        originConfig: {
+            xAxis,
+            yAxis,
+            threshold
+        },
+        page: 1,
+        pageSize: threshold,
+        data: list.map(l => ({
+            name: xAxis.column.type === 'time' ? (moment(l[xAxis.column.name]).isValid() ? moment(l[xAxis.column.name]).format('YYYY-MM-DD') : l[xAxis.column.name]) : l[xAxis.column.name],
+            key: yAxis.column.label,
+            value: yAxis.column.type === 'time' ? (moment(l[yAxis.column.name]).isValid() ? moment(l[yAxis.column.name]).format('YYYY-MM-DD') : l[yAxis.column.name]) : l[yAxis.column.name]
+        })).slice(0, threshold)
+    };
+
     return option;
 }

BIN
static/images/thumbnail-aggregateTable.png


+ 0 - 0
static/images/chart-default.png → static/images/thumbnail-default.png


BIN
static/images/thumbnail-indicator.png


+ 0 - 0
static/images/table-default.png → static/images/thumbnail-table.png