Browse Source

新增可视化模式:指标板

zhuth 6 years ago
parent
commit
cd9cdbb8a5

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

@@ -7,6 +7,7 @@ import BarConfigForm from './sections/barConfigForm'
 import PieConfigForm from './sections/pieConfigForm'
 import LineConfigForm from './sections/lineConfigForm'
 import ScatterConfigForm from './sections/scatterConfigForm'
+import IndicatorConfigForm from './sections/indicatorConfigForm'
 import StyleConfigForm from './sections/style/index'
 import OtherConfigForm from './sections/otherConfigForm'
 import TableView from './charts/tableView'
@@ -99,6 +100,8 @@ class ChartDesignerContent extends React.Component {
         }else if(viewType === 'scatter') {
             configForm = (<ScatterConfigForm autoRefresh={autoRefresh}/>);
             chartView = (<EchartsView chartOption={chartOption} />);
+        }else if(viewType === 'indicator') {
+            configForm = (<IndicatorConfigForm autoRefresh={autoRefresh}/>);
         }else {
             chartView = <EmptyContent />
         }

+ 3 - 1
src/components/chartDesigner/layout.jsx

@@ -33,7 +33,9 @@ class ChartDesigner extends React.Component {
 }
 function mapStateToProps(state) {
     let effectsArr = ['chart/remoteDetail', 'chart/remoteDetail', 'chart/remoteModify', 'chart/remoteGroupList', 'chartDesigner/remoteDataColumn', 'chartDesigner/fetchLineData',
-        'chartDesigner/fetchBarData', 'chartDesigner/fetchPieData', 'chartDesigner/fetchScatterData', 'chartDesigner/fetchDataViewData', 'chartDesigner/fetchAggregateTableData'];
+        'chartDesigner/fetchBarData', 'chartDesigner/fetchPieData', 'chartDesigner/fetchScatterData', 'chartDesigner/fetchDataViewData', 'chartDesigner/fetchAggregateTableData',
+        'chartDesigner/fetchIndicatorData'
+    ];
     let loading = false;
     effectsArr.map(e => {
         return state.present.loading.effects['chart/remoteDetail'];

+ 2 - 1
src/components/chartDesigner/sections/baseConfigForm.jsx

@@ -2,6 +2,7 @@ import React from 'react'
 import { Form, Select, Icon } from 'antd'
 import { connect } from 'dva'
 import CHART_TYPE from './chartType.json'
+import CusIcon from '../../common/cusIcon/index'
 import './baseConfigForm.less'
 const FormItem = Form.Item
 const { Option } = Select
@@ -56,7 +57,7 @@ class baseConfigForm extends React.Component {
 						CHART_TYPE.map( c => (
 							<Option key={c.type} value={c.type} title={c.label}>
 								<div className='viewtype-box'>
-									<Icon className='viewtype-icon' type={c.icon} />
+									{c.myIcon ? <CusIcon className='viewtype-icon' type={c.myIcon}/> : <Icon className='viewtype-icon' type={c.icon} />}
 									<div className='viewtype-text'>
 										{c.label}
 									</div>

+ 0 - 29
src/components/chartDesigner/sections/granularity.js

@@ -1,29 +0,0 @@
-export default {
-    ordinal: null,
-    categorical: null,
-    time: [{
-        value: 'year',
-        label: '年',
-        replaceFunction: (v) => v + '年',
-    }, {
-        value: 'halfYear',
-        label: '半年',
-        replaceFunction: (v) => v.replace('-H1', '上半年').replace('-H2', '下半年'),
-    }, {
-        value: 'month',
-        label: '月',
-        replaceFunction: (v) => v.replace('-M', '年') + '月',
-    }, {
-        value: 'quarter',
-        label: '季度',
-        replaceFunction: (v) => v.replace('-Q1', '年1季度').replace('-Q2', '年2季度').replace('-Q3', '年3季度').replace('-Q4', '年4季度'),
-    }, {
-        value: 'week',
-        label: '周',
-        replaceFunction: (v) => v.replace('-W', '年') + '周',
-    }, {
-        value: 'day',
-        label: '日',
-        replaceFunction: (v) => v,
-    }]
-}

+ 115 - 0
src/components/chartDesigner/sections/indicatorConfigForm.jsx

@@ -0,0 +1,115 @@
+import React from 'react'
+import { Form, Select, InputNumber } from 'antd'
+import { connect } from 'dva'
+import '../../../models/chartDesigner'
+import { deepAssign } from '../../../utils/baseUtils'
+const FormItem = Form.Item
+const { Option } = Select
+const formItemLayout = {
+	labelCol: { span: 8 },
+	wrapperCol: { span: 16 },
+}
+const IndicatorConfigForm = ({ autoRefresh, chartDesigner, dispatch }) => {
+	const { columns, indicatorConfig, defaultIndicatorThreshold } = chartDesigner;
+
+	return (
+		<Form hideRequiredMark={true}>
+			<FormItem label='显示字段' {...formItemLayout}>
+                <Select
+					labelInValue={false}
+					placeholder='请选择...'
+					showSearch
+					filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+					allowClear={true}
+					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 });
+					}}
+					value={indicatorConfig.xAxis.column.name}
+				>
+					{columns.map((c, i)=>{
+						return (<Option key={i} value={c.name}>{c.label}</Option>)
+					})}
+				</Select>
+			</FormItem>
+			<FormItem label='值字段' {...formItemLayout}>
+                <Select
+					labelInValue={false}
+					placeholder='请选择...'
+					showSearch
+					filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+					allowClear={true}
+					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 });
+					}}
+					value={indicatorConfig.yAxis.column.name}
+				>
+					{columns.map((c, i)=>{
+						return (<Option key={i} value={c.name}>{c.label}</Option>)
+					})}
+				</Select>
+			</FormItem>
+            <FormItem label='排序列' {...formItemLayout}>
+                <Select
+                    allowClear
+                    value={indicatorConfig.sortColumn}
+                    labelInValue={true}
+                    placeholder={indicatorConfig.xAxis.column.name ? indicatorConfig.xAxis.column.label : (indicatorConfig.yAxis.column.label || '无')}
+                    showSearch
+                    filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                    onChange={(value) => {
+                        dispatch({ type: 'chartDesigner/changeField', name: 'indicatorConfig', value: { ...indicatorConfig, sortColumn: value }, autoRefresh });
+                    }}
+                >
+                    {[indicatorConfig.xAxis.column, indicatorConfig.yAxis.column].filter(x => !!x.name).map((c, i)=>{
+                        return <Option key={c.name} value={c.name}>{c.label}</Option>
+                    })}
+                </Select>
+            </FormItem>
+            <FormItem label='排序方式' {...formItemLayout}>
+                <Select
+                    defaultValue='asc'
+                    value={indicatorConfig.sortType}
+                    placeholder='升序'
+                    onChange={(value) => {
+                        dispatch({ type: 'chartDesigner/changeField', name: 'indicatorConfig', value: { ...indicatorConfig, sortType: value }, autoRefresh });
+                    }}
+                >
+                    <Option value="asc">升序</Option>
+                    <Option value="desc">降序</Option>
+                </Select>
+            </FormItem>
+			<FormItem label='阈值' {...formItemLayout}>
+				<InputNumber
+					defaultValue={indicatorConfig.threshold}
+					placeholder={defaultIndicatorThreshold}
+                    onBlur={e => {
+						let value = e.target.value;
+						if(value !== indicatorConfig.threshold) {
+							let fields = [{ name: 'indicatorConfig', value: deepAssign(indicatorConfig, { threshold: value }) }];
+							dispatch({ type: 'chartDesigner/changeFields', fields });
+						}
+                    }}
+                    onKeyDown={e => {
+                        if(e.keyCode === 13) {
+                            let value = e.target.value;
+							if(value !== indicatorConfig.threshold) {
+								let fields = [{ name: 'indicatorConfig', value: deepAssign(indicatorConfig, { threshold: value }) }];
+								dispatch({ type: 'chartDesigner/changeFields', fields });
+							}
+                        }
+                    }}
+				/>
+			</FormItem>
+		</Form>
+	);
+}
+
+function mapStateToProps({ present: { chartDesigner } }) {
+    return { chartDesigner: chartDesigner }
+}
+
+export default connect(mapStateToProps)(IndicatorConfigForm);

+ 11 - 89
src/models/chart.js

@@ -209,7 +209,8 @@ export default {
                             dataConnectName: d.dataConnectionName,
                             access: d.authority === '1', // 权限
                             database: d.dbStatus === '0', // 数据源是否还存在
-                            type: CHART_TYPE[d.chartType],
+                            // TODO 过渡方案
+                            type: CHART_TYPE[d.chartType] || d.chartType,
                             creatorCode: d.createId + '',
                             creatorName: d.createBy,
                             createTime: d.createDate,
@@ -258,7 +259,8 @@ export default {
                     let chartConfig = JSON.parse(resData.chartConfig || '{ "xAxis": { "column": {}, "granularity": {} }, "yAxis": { "column": {}, "gauge": {} } }');
                     let styleConfig = JSON.parse(resData.style || '{}');
                     let otherConfig = JSON.parse(resData.otherConfig || '{}');
-                    let viewType = CHART_TYPE[resData.chartType];
+                    // TODO 过渡方案
+                    let viewType = CHART_TYPE[resData.chartType] || resData.chartType;
                     let filters = JSON.parse(resData.filters || '[]');
                     // let chartOption = JSON.parse(resData.chartOption || '{}');
                     let chartOption = {};
@@ -291,19 +293,7 @@ export default {
                         demo: resData.demo,
                     }
 
-                    if(viewType === 'bar') {
-                        data.barConfig = chartConfig;
-                    }else if(viewType === 'pie') {
-                        data.pieConfig = chartConfig;
-                    }else if(viewType === 'line') {
-                        data.lineConfig = chartConfig;
-                    }else if(viewType === 'scatter') {
-                        data.scatterConfig = chartConfig;
-                    }else if(viewType === 'aggregateTable') {
-                        data.aggregateTableConfig = chartConfig;
-                    }else if(viewType === 'dataView') {
-                        data.dataViewConfig = chartConfig;
-                    }
+                    data[`${viewType}Config`] = chartConfig;
 
                     let fields = [];
                     for(let key in data) {
@@ -323,63 +313,11 @@ export default {
                 message.error('解析图表错误: ' + e.message);
             }
         },
-        *remoteAdd(action, { select, call, put }) {
-            try{
-                const chartDesigner = yield select(state => state.present.chartDesigner);
-                const { header, baseConfig, pieConfig, lineConfig, aggregateTableConfig, dataViewConfig,
-                    barConfig, scatterConfig, otherConfig, description, group, filters, chartOption } = chartDesigner;
-                let body = {
-                    chartName: header.label,
-                    dataId: baseConfig.dataSource.code,
-                    describes: description,
-                    style: '{}',
-                    otherConfig: JSON.stringify(otherConfig),
-                    chartsGroup: group ? group : '-1',
-                    filters: JSON.stringify(filters),
-                    chartOption: JSON.stringify(chartOption),
-                }; // 基本属性
-                if(baseConfig.viewType === 'bar') {
-                    body.chartType = 'Histogram';
-                    body.chartConfig = JSON.stringify(barConfig);
-                }else if(baseConfig.viewType === 'pie') {
-                    body.chartType = 'Pie';
-                    body.chartConfig = JSON.stringify(pieConfig);
-                }else if(baseConfig.viewType === 'line') {
-                    body.chartType = 'Line';
-                    body.chartConfig = JSON.stringify(lineConfig);
-                }else if(baseConfig.viewType === 'scatter') {
-                    body.chartType = 'scatter';
-                    body.chartConfig = JSON.stringify(scatterConfig);
-                }else if(baseConfig.viewType === 'aggregateTable') {
-                    body.chartType = 'population';
-                    body.chartConfig = JSON.stringify(aggregateTableConfig);
-                }else if(baseConfig.viewType === 'dataView') {
-                    body.chartType = 'individual';
-                    body.chartConfig = JSON.stringify(dataViewConfig);
-                }else {
-                    body.chartType = '';
-                    body.chartConfig = JSON.stringify({});
-                }
-                const res = yield call(service.fetch, {
-                    url: URLS.CHART_ADD,
-                    body: body
-                })
-                if(res.code > 0) {
-                    message.success('新增成功');
-                    yield put({ type: 'fetchList', mandatory: true });
-                }else {
-                    message.error('新增失败: ' + res.msg);
-                }
-            }catch(e) {
-                console.error(e);
-                message.error('新增失败: ' + e.message);
-            }
-        },
         *remoteModify(action, { select, call, put }) {
             try{
                 const chartDesigner = yield select(state => state.present.chartDesigner);
-                const { filters, code, header, baseConfig, pieConfig, lineConfig, aggregateTableConfig, dataViewConfig,
-                    barConfig, scatterConfig, otherConfig, description, group, chartOption, fetchConfig, styleConfig, thumbnail } = chartDesigner;
+                const { filters, code, header, baseConfig, otherConfig, description, group, chartOption,
+                    fetchConfig, styleConfig, thumbnail } = chartDesigner;
                 let body = {
                     chartId: code,
                     filters: JSON.stringify(filters),
@@ -395,28 +333,12 @@ export default {
                 }; // 基本属性
                 let styleObj = {};
                 if(!!baseConfig.viewType) {
-                    styleObj[baseConfig.viewType] = styleConfig[baseConfig.viewType]
+                    styleObj[baseConfig.viewType] = styleConfig[baseConfig.viewType];
+                    body.chartType = baseConfig.viewType;
+                    body.chartConfig = JSON.stringify(chartDesigner[`${baseConfig.viewType}Config`]);
                 }
                 body.style = JSON.stringify(styleObj);
-                if(baseConfig.viewType === 'bar') {
-                    body.chartType = 'Histogram';
-                    body.chartConfig = JSON.stringify(barConfig);
-                }else if(baseConfig.viewType === 'pie') {
-                    body.chartType = 'Pie';
-                    body.chartConfig = JSON.stringify(pieConfig);
-                }else if(baseConfig.viewType === 'line') {
-                    body.chartType = 'Line';
-                    body.chartConfig = JSON.stringify(lineConfig);
-                }else if(baseConfig.viewType === 'scatter') {
-                    body.chartType = 'scatter';
-                    body.chartConfig = JSON.stringify(scatterConfig);
-                }else if(baseConfig.viewType === 'aggregateTable') {
-                    body.chartType = 'population';
-                    body.chartConfig = JSON.stringify(aggregateTableConfig);
-                }else if(baseConfig.viewType === 'dataView') {
-                    body.chartType = 'individual';
-                    body.chartConfig = JSON.stringify(dataViewConfig);
-                }
+
                 const res = yield call(service.fetch, {
                     url: URLS.CHART_UPDATE,
                     body: body

+ 49 - 23
src/models/chartDesigner.js

@@ -55,6 +55,7 @@ export default {
             defaultLineThreshold: 200,
             defaultPieThreshold: 20,
             defaultScatterThreshold: 1000,
+            defaultIndicatorThreshold: 5,
             baseConfig: { dataSource: { code: '' }, viewType: '' },
             aggregateTableConfig: { targetColumn: {}, statistics: [], groupBy: [] },
             dataViewConfig: { viewColumns: [], sortColumn: {key: ''}, sortType: 'asc' },
@@ -62,6 +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 },
             theme: 'default',
             styleConfig: {},
             otherConfig:{},
@@ -208,8 +210,7 @@ export default {
                 yield put({ type: 'chart/remoteModify' });
                 const { newHeaderLabel } = action;
                 const chartDesigner = yield select(state => state.present.chartDesigner);
-                const { filters, baseConfig, pieConfig, lineConfig, aggregateTableConfig, dataViewConfig,
-                    barConfig, scatterConfig, otherConfig, description, group, chartOption, fetchConfig, styleConfig } = chartDesigner;
+                const { filters, baseConfig, otherConfig, description, group, chartOption, fetchConfig, styleConfig } = chartDesigner;
                 let body = {
                     filters: JSON.stringify(filters),
                     chartName: newHeaderLabel,
@@ -221,28 +222,11 @@ export default {
                     chartOption: JSON.stringify(chartOption),
                     fetchConfig: JSON.stringify(fetchConfig),
                 }; // 基本属性
-                if(baseConfig.viewType === 'bar') {
-                    body.chartType = 'Histogram';
-                    body.chartConfig = JSON.stringify(barConfig);
-                }else if(baseConfig.viewType === 'pie') {
-                    body.chartType = 'Pie';
-                    body.chartConfig = JSON.stringify(pieConfig);
-                }else if(baseConfig.viewType === 'line') {
-                    body.chartType = 'Line';
-                    body.chartConfig = JSON.stringify(lineConfig);
-                }else if(baseConfig.viewType === 'scatter') {
-                    body.chartType = 'scatter';
-                    body.chartConfig = JSON.stringify(scatterConfig);
-                }else if(baseConfig.viewType === 'aggregateTable') {
-                    body.chartType = 'population';
-                    body.chartConfig = JSON.stringify(aggregateTableConfig);
-                }else if(baseConfig.viewType === 'dataView') {
-                    body.chartType = 'individual';
-                    body.chartConfig = JSON.stringify(dataViewConfig);;
-                }else {
-                    body.chartType = '';
-                    body.chartConfig = JSON.stringify({});
+                if(!!baseConfig.viewType) {
+                    body.chartType = baseConfig.viewType;
+                    body.chartConfig = JSON.stringify(chartDesigner[`${baseConfig.viewType}Config`]);
                 }
+
                 const res = yield call(service.fetch, {
                     url: URLS.CHART_ADD,
                     body: body
@@ -424,6 +408,13 @@ export default {
                     }else {
                         yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
                     }
+                }else if(viewType === 'indicator') {
+                    const { indicatorConfig } = chartDesigner;
+                    if(indicatorConfig.xAxis.column.name && indicatorConfig.yAxis.column.name) {
+                        yield put({ type: 'fetchIndicatorData' });
+                    }else {
+                        yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
+                    }
                 }else {
                     console.log('no viewType......')
                 }
@@ -660,6 +651,41 @@ export default {
                 message.error('请求统计数据失败: ' + e.message);
             }
         },
+        *fetchIndicatorData(action, { select, call, put }) {
+            try {
+                const chartDesigner = yield select(state => state.present.chartDesigner);
+                const { code, indicatorConfig, filters, theme, styleConfig, defaultIndicatorThreshold } = chartDesigner;
+                const { xAxis, yAxis, sortColumn, sortType, threshold } = indicatorConfig;
+                const body = {
+                    id: code,
+                    columnListName: [xAxis.column.name, yAxis.column.name],
+                    sortColumn: sortColumn ? sortColumn.key : xAxis.column.name,
+                    sort: sortType || 'asc',
+                    filters: getBodyFilters(filters),
+                    testPage: {
+                        pageNum: 1,
+                        pageSize: threshold || defaultIndicatorThreshold,
+                    }
+                };
+
+                let res = yield call(service.fetch, {
+                    url: URLS.CHART_DATAVIEW_OPTION,
+                    body: body,
+                    timeout: 30000
+                });
+                if(res.code > 0) {
+                    let option = parseChartOption('indicator', res.data, indicatorConfig, theme, styleConfig.indicator);
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: option });
+                }else {
+                    message.error('请求指标数据失败: ' + res.msg);
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
+                }
+                yield put({ type: 'silentSetField', name: 'fetchConfig', value: body });
+            }catch(e) {
+                yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
+                message.error('请求指标数据失败: ' + e.message);
+            }
+        },
         /**
          * 将图表数据以表格的方式作为预览
          */

File diff suppressed because it is too large
+ 0 - 0
static/iconfont/iconfont.js


Some files were not shown because too many files changed in this diff