Browse Source

数据源图表分组完善/总体统计表接口对接调整/数据请求机制调整

zhuth 7 years ago
parent
commit
c569b18789

+ 5 - 0
src/components/chart/chooseDataSourceBox.jsx

@@ -13,6 +13,11 @@ class ChooseDataSourceBox extends React.Component {
         }
     }
 
+    componentDidMount() {
+        const { dispatch } = this.props;
+        dispatch({ type: 'dataSource/fetchList' });
+    }
+
     changeSelected = (record) => {
         this.setState({
             selectedRecord: Object.assign({}, record)

+ 7 - 1
src/components/chart/list.jsx

@@ -24,7 +24,10 @@ class ChartList extends React.Component {
     }
 
     componentDidMount() {
+        const { dispatch } = this.props;
         this.setBodyWidth();
+        dispatch({ type: 'chart/fetchList' });
+        dispatch({ type: 'chart/remoteGroupList' });
     }
 
     /**
@@ -188,7 +191,7 @@ class ChartList extends React.Component {
                         return (<Menu.Item key={c.code} onClick={(item) => {
                             dispatch({ type: 'chart/setCurrentGroup', group1: p, group2: c });
                             if(selectedRecord) {
-                                dispatch({ type: 'chart/remoteSetChartGroup', chart: selectedRecord, group: p });
+                                dispatch({ type: 'chart/remoteSetChartGroup', chart: selectedRecord, group: c });
                             }
                         }}><span style={{ fontWeight: selectedRecord ? (
                             selectedRecord.groupCode+'' === c.code+'' ? 'bold' : 'normal'
@@ -198,6 +201,9 @@ class ChartList extends React.Component {
             ) : (
                 <Menu.Item key={p.code} onClick={() => {
                     dispatch({ type: 'chart/setCurrentGroup', group1: p });
+                    if(selectedRecord) {
+                        dispatch({ type: 'chart/remoteSetChartGroup', chart: selectedRecord, group: p });
+                    }
                     this.hideGroupMenu();
                 }}><span style={{ fontWeight: selectedRecord ? (
                     selectedRecord.groupCode+'' === p.code+'' ? 'bold' : 'normal'

+ 0 - 3
src/components/chartDesigner/charts/echartsView.jsx

@@ -1,14 +1,11 @@
 import React from 'react'
 import Echarts from 'echarts-for-react'
 import { connect } from 'dva'
-import '../../../models/chartDesigner'
 import resolveChartOption from './resolveChartOption'
 import { hashcode } from '../../../utils/baseUtils'
 
 const EchartsView = ({ chartDesigner, dispatch }) => {
-    console.log(chartDesigner.chartOption);
     const option = resolveChartOption(chartDesigner.chartOption);
-    console.log(option);
     return <Echarts
         key={hashcode(option)}
         option={option}

+ 34 - 19
src/components/chartDesigner/charts/resolveChartOption.js

@@ -1,34 +1,37 @@
 export default (config) => {
-    const { viewType, data } = config;
-    console.log(viewType);
-    let option;
+    const { viewType, option } = config;
+    let o;
     switch(viewType) {
         case 'bar': {
-            option = barConfig(data ? data.data: {});
+            o = barConfig(option);
             break;
         }
         case 'pie': {
-            option = pieConfig(data ? data.data: {});
+            o = pieConfig(option);
             break;
         }
         case 'line': {
-            option = lineConfig(data ? data.data: {});
+            o = lineConfig(option);
             break;
         }
         case 'scatter': {
-            option = scatterConfig(data? data.data: {});
+            o = scatterConfig(option);
+            break;
+        }
+        case 'aggregateTable': {
+            o = aggregateTableConfig(option);
             break;
         }
         default:{
-            option = {};
+            o = {};
             break;
         }
     }
-    return option;
+    return o;
 }
 
-function barConfig(data) {
-    const { xAxis, serieses, xTitle, yTitle } = data;
+function barConfig(option) {
+    const { xAxis, serieses, xTitle, yTitle } = option;
 
     let o = {
         tooltip : {
@@ -64,22 +67,25 @@ function barConfig(data) {
     return o;
 }
 
-function pieConfig(data) {
+function pieConfig(option) {
+
+    const { xAxis, columnName, serieses } = option;
+
     let o = {
         tooltip : {
             trigger: 'item',
             formatter: "{a} <br/>{b} : {c} ({d}%)"
         },
         legend: {
-            data: data.xAxis
+            data: xAxis
         },
         series : [
             {
-                name: data.columnName,
+                name: columnName,
                 type: 'pie',
                 radius : '55%',
                 center: ['50%', '60%'],
-                data: data.serieses[0].value,
+                data: serieses[0].value,
                 itemStyle: {
                     emphasis: {
                         shadowBlur: 10,
@@ -93,8 +99,8 @@ function pieConfig(data) {
     return o;
 }
 
-function lineConfig(data) {
-    const { serieses, xTitle, yTitle } = data;
+function lineConfig(option) {
+    const { serieses, xTitle, yTitle } = option;
 
     let o = {
         tooltip: {
@@ -129,8 +135,8 @@ function lineConfig(data) {
     return o;
 }
 
-function scatterConfig(data) {
-    const { serieses, xTitle, yTitle } = data;
+function scatterConfig(option) {
+    const { serieses, xTitle, yTitle } = option;
     let o = {
         tooltip : {
             showDelay : 0,
@@ -177,4 +183,13 @@ function scatterConfig(data) {
         })
     };
     return o;
+}
+
+function aggregateTableConfig(option) {
+    const { columns, data } = option;
+    let o = {
+        columns,
+        data
+    };
+    return o;
 }

+ 0 - 39
src/components/chartDesigner/charts/table.jsx

@@ -1,39 +0,0 @@
-import React from 'react';
-import { Table } from 'antd';
-
-class TableView extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-
-        }
-    }
-
-    render() {
-        const columns = [{
-            title: '列1',
-            key: 'c1',
-            dataIndex: 'c1'
-        }, {
-            title: '列2',
-            key: 'c2',
-            dataIndex: 'c2'
-        }];
-
-        const data = [{
-            key: '1',
-            c1: 'sssss',
-            c2: 'aaaaa'
-        }, {
-            key: '2',
-            c1: '啊啊啊啊',
-            c2: 'aaaadddbb'
-        }]
-
-        return (
-            <Table columns={columns} dataSource={data}/>
-        );
-    }
-}
-
-export default TableView;

+ 19 - 0
src/components/chartDesigner/charts/tableView.jsx

@@ -0,0 +1,19 @@
+import React from 'react';
+import { Table } from 'antd';
+import { connect } from 'dva'
+import resolveChartOption from './resolveChartOption'
+
+const TableView = ({ chartDesigner, dispatch }) => {
+    const option = resolveChartOption(chartDesigner.chartOption);
+    const { columns, data } = option;
+
+    return (
+        <Table columns={columns} dataSource={data}/>
+    );
+}
+
+function mapStateToProps({ present: { chartDesigner } }) {
+    return { chartDesigner: chartDesigner }
+}
+
+export default connect(mapStateToProps)(TableView);

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

@@ -6,15 +6,13 @@ import DataViewConfigForm from './sections/dataViewConfigForm'
 import BarConfigForm from './sections/barConfigForm'
 import PieConfigForm from './sections/pieConfigForm'
 import LineConfigForm from './sections/lineConfigForm'
-import TableView from './charts/table'
+import TableView from './charts/tableView'
 import ScatterConfigForm from './sections/ScatterConfigForm'
 import StyleConfigForm from './sections/styleConfigForm'
 import OtherConfigForm from './sections/otherConfigForm'
 import EchartsView from './charts/echartsView'
 import ToolBar from './sections/toolbar'
 import { connect } from 'dva'
-import '../../models/chartDesigner'
-import '../../data/charts/option/bar.json'
 import './content.less'
 const { Header, Sider, Content, Footer } = Layout
 const { TabPane } = Tabs

+ 16 - 7
src/components/chartDesigner/layout.jsx

@@ -1,11 +1,20 @@
-import React from 'react';
-import { Layout } from 'antd';
-import './layout.less';
-import ChartDesignerHeader from './header';
-import ChartDesignerContent from './content';
-const { Header, Content } = Layout;
+import React from 'react'
+import { Layout } from 'antd'
+import './layout.less'
+import { connect } from 'dva'
+import ChartDesignerHeader from './header'
+import ChartDesignerContent from './content'
+const { Header, Content } = Layout
 
 class ChartDesigner extends React.Component {
+    componentDidMount() {
+        const { dispatch } = this.props;
+        const { code } = this.props.match.params;
+        if(code !== 'create') {
+            dispatch({ type: 'chart/remoteDetail', code: code })
+            dispatch({ type: 'chart/remoteGroupList', code: code })
+        }
+    }
     render() {
         return <Layout className='chartdesigner-layout'>
             <Header>
@@ -17,4 +26,4 @@ class ChartDesigner extends React.Component {
         </Layout>
     }
 }
-export default ChartDesigner;
+export default connect()(ChartDesigner);

+ 29 - 27
src/components/chartDesigner/sections/aggregateTableConfigForm.jsx

@@ -1,7 +1,7 @@
 import React from 'react';
-import { Form, Select, Checkbox } from 'antd';
+import { Form, Select, Checkbox, Row, Col } from 'antd';
 import { connect } from 'dva';
-import '../../../models/chartDesigner';
+import STATISTICS_OPTION from './statisticsOption.json'
 const FormItem = Form.Item;
 const { Option } = Select;
 const CheckboxGroup = Checkbox.Group;
@@ -9,48 +9,50 @@ const CheckboxGroup = Checkbox.Group;
 class AggregateTableConfigForm extends React.Component {
 	render() {
 		const props = this.props;
-        const columns = props.chartDesigner.columns;
-        
-        const statisticsOptions = [
-            { value: 'count', label: '条数', checked: true }, 
-            { value: 'max', label: '最大值', checked: true },
-            { value: 'percentage', label: '百分比', checked: true },
-            { value: '75th', label: '75th值', checked: true },
-            { value: 'sum', label: '总和', checked: true },
-            { value: 'median', label: '中位数', checked: false },
-            { value: 'avg', label: '平均数', checked: true },
-            { value: '25th', label: '25th值', checked: true },
-            { value: 'std', label: '标准差', checked: true },
-            { value: 'min', label: '最小值', checked: true }
-        ];
-
-		const { formItemLayout } = props
+		const { formItemLayout, chartDesigner, dispatch } = props;
+		const columns = chartDesigner.columns;
         
 		return (
 			<Form>
 				<FormItem label='分析目标' {...formItemLayout}>
 					<Select
 						value={props.chartDesigner.aggregateTableConfig.targetColumn}
-						mode='multiple'
-						labelInValue={true}
 						onChange={(value) => {
-							props.dispatch({ type: 'chartDesigner/changeField', name: 'aggregateTableConfig', value: { ...props.chartDesigner.aggregateTableConfig, targetColumn: value } });
-							
+							dispatch({ type: 'chartDesigner/changeField', name: 'aggregateTableConfig', value: { ...chartDesigner.aggregateTableConfig, targetColumn: value } });
 						}}
 					>
-						{columns.map((c, i)=>{
+						{columns.filter(c => c.type === 'scale' || c.type === 'ordinal').map((c, i)=>{
 							return (<Option key={i} value={c.name}>{c.label}</Option>)
 						})}
 					</Select>
 				</FormItem>
 				<FormItem label='显示总体数据' {...formItemLayout}>
 					<CheckboxGroup
-						value={props.chartDesigner.aggregateTableConfig.statistics}
-						options={statisticsOptions.map((s)=>{return s.label})}
+						value={chartDesigner.aggregateTableConfig.statistics}
 						onChange={(value) => {
-							props.dispatch({ type: 'chartDesigner/changeField', name: 'aggregateTableConfig', value: { ...props.chartDesigner.aggregateTableConfig, statistics: value } });
+							dispatch({ type: 'chartDesigner/changeField', name: 'aggregateTableConfig', value: { ...props.chartDesigner.aggregateTableConfig, statistics: value } });
 						}}
-					/>
+					>
+						<Row>
+							{STATISTICS_OPTION.map((s)=>{return <Col span={12} key={s.value}><Checkbox value={s.value}>{s.label}</Checkbox></Col>})}
+						</Row>
+						
+					</CheckboxGroup>
+				</FormItem>
+				<FormItem label='分组' {...formItemLayout}>
+					<Select
+						labelInValue={true}
+						placeholder='请选择...'
+						allowClear={true}
+						onChange={(value) => {
+							dispatch({ type: 'chartDesigner/changeField', name: 'preparing', value: { ...chartDesigner.preparing, groupBy: value } });
+						}}
+						value={chartDesigner.preparing.groupBy}
+					>
+						{columns.filter(c => c.type === 'categorical').map((c, i)=>{
+							return (<Option key={i} value={c.name}>{c.label}</Option>)
+						})}
+					</Select>
 				</FormItem>
 			</Form>
 		);

+ 47 - 5
src/components/chartDesigner/sections/otherConfigForm.jsx

@@ -1,14 +1,56 @@
 import React from 'react'
-import { Form, Input } from 'antd'
+import { Form, Input, Cascader } from 'antd'
 import { connect } from 'dva'
-import '../../../models/chartDesigner.js'
 import './otherConfigForm.less'
 const FormItem = Form.Item
 const InputTextArea = Input.TextArea
 
-const OtherConfigForm = ({ chartDesigner, dispatch, formItemLayout }) => {
+const OtherConfigForm = ({ chart, chartDesigner, dispatch, formItemLayout }) => {
+    let getGroup = () => {
+        const { group } = chartDesigner;
+        const { groupList } = chart;
+        let g1 = groupList.filter(g => g.code+'' === group+'')[0];
+        if(!g1) {
+            return ['nogroup']
+        }
+        if(g1.pcode === '-1') {
+            return [g1.code]
+        }else {
+            let g2 = groupList.filter(g => g.code+'' === g1.pcode+'')[0];
+            return [g2.code, g1.code]
+        }
+    }
     return (
         <Form className='form-otherconfig'>
+            <FormItem label='所属分组' {...formItemLayout}>
+                <Cascader
+                    value={getGroup()}
+                    allowClear={true}
+                    changeOnSelect={true}
+                    expandTrigger='hover'
+					placeholder='未分组'
+					options={[{pcode: '-1', code: 'nogroup', label: '未分组'}].concat(chart.groupList).filter(g => g.pcode === '-1').map((p, i)=>{
+						return {
+                            key: p.code,
+							value: p.code,
+							label: p.label,
+							children: chart.groupList.filter(g => g.pcode === p.code).map(c => {
+                                return {
+                                    key: c.code,
+                                    value: c.code,
+                                    label: c.label
+                                }
+                            })
+						}
+					})}
+					onChange={(value, items) => {
+                        let v = value[1] !== undefined ? value[1] : value[0];
+                        dispatch({ type: 'chartDesigner/setField', name: 'group', value: v });
+					}}
+					
+				>
+				</Cascader>
+            </FormItem>
             <FormItem label='备注' {...formItemLayout}>
                 <InputTextArea
                     className='inputarea-description'
@@ -23,8 +65,8 @@ const OtherConfigForm = ({ chartDesigner, dispatch, formItemLayout }) => {
     );
 }
 
-function mapStateToProps({ present: {chartDesigner}}) {
-    return { chartDesigner };
+function mapStateToProps({ present: {chart, chartDesigner}}) {
+    return { chart, chartDesigner };
 }
 
 export default connect(mapStateToProps)(OtherConfigForm);

+ 12 - 0
src/components/chartDesigner/sections/statisticsOption.json

@@ -0,0 +1,12 @@
+[
+    {"value": "count", "label": "条数", "columnType": ["index", "time", "categorical", "scale", "ordinal", "string"] }, 
+    {"value": "max", "label": "最大值", "columnType": ["scale"] },
+    {"value": "percent", "label": "百分比", "columnType": ["index", "time", "categorical", "scale", "ordinal", "string"] },
+    {"value": "75th", "label": "75th值", "columnType": ["scale"] },
+    {"value": "sum","label": "总和", "columnType": ["scale"] },
+    {"value": "median","label": "中位数", "columnType": ["scale"] },
+    {"value": "avg","label": "平均数", "columnType": ["scale"] },
+    {"value": "25th","label": "25th值", "columnType": ["scale"] },
+    {"value": "stddev","label": "标准差", "columnType": ["scale"] },
+    {"value": "min","label": "最小值", "columnType": ["scale"] }
+]

+ 46 - 15
src/components/datasource/baseConfig.jsx

@@ -1,18 +1,33 @@
 import React from 'react'
-import { Form, Row, Col, Input, InputNumber, Select, Divider } from 'antd'
+import { Form, Row, Col, Input, InputNumber, Select, Divider, Cascader } from 'antd'
 import { connect } from 'dva'
-import '../../models/dataSource'
-import '../../models/dataConnect'
 const FormItem = Form.Item
 const SelectOption = Select.Option
 
 const DataSourceBaseConfig = ({ dataSource, dataConnect, dispatch, mode }) => {
 
+    dispatch({ type: 'dataSource/remoteGroupList' });
+
     const formItemLayout = {
         labelCol: { span: 4 },
         wrapperCol: { span: 20 },
     };
 
+    let getGroup = () => {
+        const { groupList } = dataSource;
+        const { group } = dataSource.newOne;
+        let g1 = groupList.filter(g => g.code+'' === group+'')[0];
+        if(!g1) {
+            return ['nogroup']
+        }
+        if(g1.pcode === '-1') {
+            return [g1.code]
+        }else {
+            let g2 = groupList.filter(g => g.code+'' === g1.pcode+'')[0];
+            return [g2.code, g1.code]
+        }
+    }
+
     return (
         <Form className='form-base' size='small'>
             <Divider orientation="left">基本配置</Divider>
@@ -128,18 +143,34 @@ const DataSourceBaseConfig = ({ dataSource, dataConnect, dispatch, mode }) => {
                 )
             }
             <Divider orientation="left">其他配置</Divider>
-            <FormItem label='标签' {...formItemLayout}>
-                <Select
-                    mode="tags"
-                    placeholder='多个标签使用逗号或空格分隔'
-                    tokenSeparators={[',', ' ']}
-                    value={dataSource.newOne.tags}
-                    dropdownStyle={{display: 'none'}}
-                    onChange={(value) => {
-                        dispatch({ type: 'dataSource/setNewModelField', name: 'tags', value: value });
-                    }}
-                >
-                </Select>
+            <FormItem label='所属分组' {...formItemLayout}>
+                <Cascader
+                    value={getGroup()}
+                    allowClear={true}
+                    changeOnSelect={true}
+                    expandTrigger='hover'
+					placeholder='未分组'
+					options={[{pcode: '-1', code: 'nogroup', label: '未分组'}].concat(dataSource.groupList).filter(g => g.pcode === '-1').map((p, i)=>{
+						return {
+                            key: p.code,
+							value: p.code,
+							label: p.label,
+							children: dataSource.groupList.filter(g => g.pcode === p.code).map(c => {
+                                return {
+                                    key: c.code,
+                                    value: c.code,
+                                    label: c.label
+                                }
+                            })
+						}
+					})}
+					onChange={(value, items) => {
+                        let v = value[1] !== undefined ? value[1] : value[0];
+                        dispatch({ type: 'dataSource/setNewModelField', name: 'group', value: v });
+					}}
+					
+				>
+				</Cascader>
             </FormItem>
             <FormItem className='textarea-desc' label='说明' {...formItemLayout}>
                 <Input.TextArea

+ 7 - 0
src/components/datasource/dataConnectConfig.jsx

@@ -8,6 +8,13 @@ const UploadDragger = Upload.Dragger
 const Search = Input.Search
 
 class DataConnectConfig extends React.Component {
+    
+    componentDidMount() {
+        const { dispatch } = this.props;
+        dispatch({ type: 'dataConnect/fetchList' });
+        dispatch({ type: 'dataConnect/resetSelected' });
+    }
+
     render() {
         const { dataSource, dataConnect, dispatch } = this.props;
         const filterLabel = dataConnect.filterLabel;

+ 5 - 2
src/components/datasource/dataSource.jsx

@@ -20,7 +20,10 @@ class DataSource extends React.Component {
     };
 
     componentDidMount() {
+        const { dispatch } = this.props;
         this.setScrollTableHeight();
+        dispatch({ type: 'dataSource/fetchList' });
+        dispatch({ type: 'dataSource/remoteGroupList' });
     }
 
     /**
@@ -112,7 +115,7 @@ class DataSource extends React.Component {
                         return (<Menu.Item key={c.code} onClick={(item) => {
                             dispatch({ type: 'dataSource/setCurrentGroup', group1: p, group2: c });
                             if(selectedRecord) {
-                                dispatch({ type: 'dataSource/remoteSetDataSourceGroup', dataSource: selectedRecord, group: p });
+                                dispatch({ type: 'dataSource/remoteSetDataSourceGroup', dataSource: selectedRecord, group: c });
                             }
                         }}><span style={{ fontWeight: selectedRecord ? (
                             selectedRecord.groupCode+'' === c.code+'' ? 'bold' : 'normal'
@@ -403,7 +406,7 @@ class DataSource extends React.Component {
                                             const type = item.key;
                                             dispatch({ type: 'dataSource/resetNewModel' });
                                             dispatch({ type: 'dataSource/setNewModelField', name: 'type', value: type });
-                                            dispatch({type: 'main/redirect', path: {pathname: '/datasource/'+ type +'/create'}});
+                                            dispatch({type: 'main/redirect', path: {pathname: '/datasource/'+ type +'/create/base'}});
                                         }}>
                                             <Menu.Item key='database'>数据库</Menu.Item>
                                             <Menu.Item key='file'>文件</Menu.Item>

+ 11 - 4
src/components/datasource/dataSourceDetail.jsx

@@ -25,10 +25,17 @@ class DataSourceDetail extends React.Component {
     }
 
     componentDidMount() {
-        this.props.dispatch({ type: 'dataSource/setNewModelFields', fields: [
-            { name: 'type', value: this.props.match.params.type },
-            { name: 'code', value: this.props.match.params.code }
-        ] });
+        const { dispatch } = this.props;
+        const { code } = this.props.match.params;
+        
+        if(code !== 'create') {
+            dispatch({ type: 'dataSource/remoteDetail', code: code })
+        }else {
+            dispatch({ type: 'dataSource/setNewModelFields', fields: [
+                { name: 'type', value: this.props.match.params.type },
+                { name: 'code', value: this.props.match.params.code }
+            ] });
+        }
     }
 
     next() {

+ 3 - 3
src/components/datasource/groupSelector.jsx

@@ -38,14 +38,14 @@ class GroupSelector extends React.Component {
                 visible={visible}
                 onVisibleChange={this.handleVisibleChange}
                 content={
-                    [{code: 'all', label: '全部分组'}].concat(pgroups).map(p => {
-                        let cgroups = grouplist.filter(g => g.pcode === p.code);
+                    [{code: 'all', label: '全部分组'}, { code: 'nogroup', label: '未分组' }].concat(pgroups).map(p => {
+                        let cgroups = grouplist.filter(g => g.pcode === p.code && p.code !== '-1');
                         return <Row type='flex' justify='left' key={`gr-${p.code}`}>
                             <Col key={`rc-${p.code}`} onClick={() => {
                                 this.hide();
                                 dispatch({ type: modelName + '/setCurrentGroup', group1: p });
                             }}>
-                                {<span className={`group${currentGroup[0].code === p.code ? ' selected' : ''}`}>{p.label}</span>}<Icon type="right" />
+                                {<span className={`group${currentGroup[0].code === p.code ? ' selected' : ''}`}>{p.label}</span>}{cgroups.length>0 && <Icon type="right" />}
                             </Col>
                             {
                                 cgroups.map((c, i) => <Col key={c.code} onClick={() => {

+ 31 - 14
src/components/datasource/otherConfig.jsx

@@ -1,10 +1,12 @@
 import React from 'react'
-import { Form, Input, Select } from 'antd'
+import { Form, Input, Cascader } from 'antd'
 import { connect } from 'dva'
 const FormItem = Form.Item
 
 const OtherConfig = ({ dataSource, dataConnect, dispatch, mode }) => {
-
+    
+    dispatch({ type: 'dataSource/remoteGroupList' });
+    
     const formItemLayout = {
         labelCol: { span: 4 },
         wrapperCol: { span: 20 },
@@ -18,18 +20,33 @@ const OtherConfig = ({ dataSource, dataConnect, dispatch, mode }) => {
                     onChange={(e) => { dispatch({ type: 'dataSource/setNewModelField', name: 'name', value: e.target.value }) }}>
                 </Input>
             </FormItem>
-            <FormItem label='标签' {...formItemLayout}>
-                <Select
-                    mode="tags"
-                    placeholder='多个标签使用逗号或空格分隔'
-                    tokenSeparators={[',', ' ']}
-                    value={dataSource.newOne.tags}
-                    dropdownStyle={{display: 'none'}}
-                    onChange={(value) => {
-                        dispatch({ type: 'dataSource/setNewModelField', name: 'tags', value: value });
-                    }}
-                >
-                </Select>
+            <FormItem label='所属分组' {...formItemLayout}>
+                <Cascader
+                    value={dataSource.newOne.group}
+                    allowClear={true}
+                    changeOnSelect={true}
+                    expandTrigger='hover'
+					placeholder='未分组'
+					options={dataSource.groupList.filter(g => g.pcode === '-1').map((p, i)=>{
+						return {
+                            key: p.code,
+							value: p.code,
+							label: p.label,
+							children: dataSource.groupList.filter(g => g.pcode === p.code).map(c => {
+                                return {
+                                    key: c.code,
+                                    value: c.code,
+                                    label: c.label
+                                }
+                            })
+						}
+					})}
+					onChange={(value, items) => {
+                        dispatch({ type: 'dataSource/setNewModelField', name: 'group', value: value });
+					}}
+					
+				>
+				</Cascader>
             </FormItem>
             <FormItem className='textarea-desc' label='说明' {...formItemLayout}>
                 <Input.TextArea

+ 3 - 1
src/constants/url.js

@@ -51,7 +51,9 @@ const URLS = {
 
     CHART_SCATTER_OPTION: BASE_URL + '/showScatter', // 请求散点图展示数据
 
-    CHART_DATAVIEW_OPTION: BASE_URL + 'showIndividual', // 请求个体统计数据
+    CHART_DATAVIEW_OPTION: BASE_URL + '/showIndividual', // 请求个体统计数据
+
+    CHART_AGGREGATETABLE_OPTION: BASE_URL + '/showPopulation', // 请求总体统计数据
 
     /***************************************分组***************************************/
 

+ 6 - 19
src/models/chart.js

@@ -239,7 +239,8 @@ export default {
                     createBy: 'zhuth',
                     describes: description,
                     style: '',
-                    otherConfig: JSON.stringify(otherConfig)
+                    otherConfig: JSON.stringify(otherConfig),
+
                 }; // 基本属性
                 if(baseConfig.viewType === 'bar') {
                     body.chartType = 'Histogram';
@@ -271,7 +272,7 @@ export default {
             try{
                 const chartDesigner = yield select(state => state.present.chartDesigner);
                 const { code, header, baseConfig, pieConfig, lineConfig, preparing,
-                    barConfig, scatterConfig, otherConfig, description } = chartDesigner;
+                    barConfig, scatterConfig, otherConfig, description, group } = chartDesigner;
                 let body = {
                     chartId: code,
                     chartName: header.label,
@@ -283,7 +284,8 @@ export default {
                     createBy: 'zhuth',
                     describes: description,
                     style: '',
-                    otherConfig: JSON.stringify(otherConfig)
+                    otherConfig: JSON.stringify(otherConfig),
+                    chartsGroup: group ? group : '-1'
                 }; // 基本属性
                 if(baseConfig.viewType === 'bar') {
                     body.chartType = 'Histogram';
@@ -364,7 +366,7 @@ export default {
                     });
                     yield put({ type: 'groupList', data });
                 }else {
-                    message.error('读取数据源列表错误');
+                    message.error('读取图表分组列表错误');
                 }
             }catch(e) {
                 console.log(e);
@@ -690,21 +692,6 @@ export default {
     subscriptions: {
         setup({ dispatch, history }) {
             return history.listen(({ pathname, query }) => {
-                if(pathname === '/chart') {
-                    dispatch({ type: 'fetchList' });
-                }
-                if(pathname.startsWith('/chart')) {
-                    dispatch({ type: 'remoteGroupList' });
-                }
-                let detail = pathname.match(/chart\/(\w+)/);
-                if(detail) {
-                    let code = detail[1];
-                    if(code !== 'create') {
-                        dispatch({ type: 'remoteDetail', code: code });
-                    }else {
-                        dispatch({ type: 'chartDesigner/reset' });
-                    }
-                }
             })
         }
     }

+ 109 - 14
src/models/chartDesigner.js

@@ -1,6 +1,7 @@
 import { message } from 'antd'
 import * as service from '../services/index'
 import URLS from '../constants/url'
+import STATISTICS_OPTION from '../components/chartDesigner/sections/statisticsOption.json'
 
 export default {
     namespace: 'chartDesigner',
@@ -280,6 +281,8 @@ export default {
                 yield put({ type: 'fetchScatterData' })
             }else if(viewType === 'dataView') {
                 yield put({ type: 'fetchDataViewData' });
+            }else if(viewType === 'aggregateTable') {
+                yield put({ type: 'fetchAggregateTableData' });
             }else {
                 console.log('nothing.......')
             }
@@ -308,10 +311,19 @@ export default {
                     body: body
                 });
                 if(!res.err && res.data.code > 0) {
-                    res.viewType = 'bar';
-                    res.data.data.xTitle = barConfig.xAxis?`${barConfig.xAxis.column.label}${barConfig.xAxis.granularity.value?'('+barConfig.xAxis.granularity.label+')':''}`:null
-                    res.data.data.yTitle = barConfig.yAxis?`${barConfig.yAxis.column.label}${barConfig.yAxis.gauge.value?'('+barConfig.yAxis.gauge.label+')':''}`:null
-                    yield put({ type: 'silentSetField', name: 'chartOption', value: res });
+                    let xTitle = barConfig.xAxis?`${barConfig.xAxis.column.label}${barConfig.xAxis.granularity.value?'('+barConfig.xAxis.granularity.label+')':''}`:null
+                    let yTitle = barConfig.yAxis?`${barConfig.yAxis.column.label}${barConfig.yAxis.gauge.value?'('+barConfig.yAxis.gauge.label+')':''}`:null
+                    
+                    let config = {
+                        viewType: 'bar',
+                        option: {
+                            xAxis: res.data.data.xAxis,
+                            serieses: res.data.data.serieses,
+                            xTitle,
+                            yTitle,
+                        }
+                    }
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: config });
                 }else {
                     yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
                 }
@@ -343,9 +355,17 @@ export default {
                 });
 
                 if(!res.err && res.data.code > 0) {
-                    res.viewType = 'pie';
-                    res.data.data.columnName = pieConfig.xAxis.column.label + (pieConfig.xAxis.granularity.value ? '('+pieConfig.xAxis.granularity.label+')' : '');
-                    yield put({ type: 'silentSetField', name: 'chartOption', value: res });
+                    let columnName = pieConfig.xAxis.column.label + (pieConfig.xAxis.granularity.value ? '('+pieConfig.xAxis.granularity.label+')' : '');
+                    
+                    let config = {
+                        viewType: 'pie',
+                        option: {
+                            xAxis: res.data.data.xAxis,
+                            columnName: columnName,
+                            serieses: res.data.data.serieses
+                        }
+                    }
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: config });
                 }else {
                     yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
                 }
@@ -375,10 +395,19 @@ export default {
                     body: body
                 });
                 if(!res.err && res.data.code > 0) {
-                    res.viewType = 'line';
-                    res.data.data.xTitle = lineConfig.xAxis?`${lineConfig.xAxis.column.label}${lineConfig.xAxis.granularity.value?'('+lineConfig.xAxis.granularity.label+')':''}`:null
-                    res.data.data.yTitle = lineConfig.yAxis?`${lineConfig.yAxis.column.label}${lineConfig.yAxis.gauge.value?'('+lineConfig.yAxis.gauge.label+')':''}`:null
-                    yield put({ type: 'silentSetField', name: 'chartOption', value: res });
+                    let xTitle = lineConfig.xAxis?`${lineConfig.xAxis.column.label}${lineConfig.xAxis.granularity.value?'('+lineConfig.xAxis.granularity.label+')':''}`:null
+                    let yTitle = lineConfig.yAxis?`${lineConfig.yAxis.column.label}${lineConfig.yAxis.gauge.value?'('+lineConfig.yAxis.gauge.label+')':''}`:null
+                    
+                    let config = {
+                        viewType: 'line',
+                        option: {
+                            viewType: 'line',
+                            serieses: res.data.data.serieses,
+                            xTitle,
+                            yTitle
+                        }
+                    }
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: config });
                 }else {
                     yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
                 }
@@ -411,9 +440,18 @@ export default {
                 console.log(res);
                 if(!res.err && res.data.code > 0) {
                     res.viewType = 'scatter';
-                    res.data.data.xTitle = scatterConfig.xAxis?`${scatterConfig.xAxis.column.label}${scatterConfig.xAxis.granularity.value?'('+scatterConfig.xAxis.granularity.label+')':''}`:null
-                    res.data.data.yTitle = scatterConfig.yAxis?`${scatterConfig.yAxis.column.label}${scatterConfig.yAxis.gauge.value?'('+scatterConfig.yAxis.gauge.label+')':''}`:null
-                    yield put({ type: 'silentSetField', name: 'chartOption', value: res });
+                    let xTitle = scatterConfig.xAxis?`${scatterConfig.xAxis.column.label}${scatterConfig.xAxis.granularity.value?'('+scatterConfig.xAxis.granularity.label+')':''}`:null
+                    let yTitle = scatterConfig.yAxis?`${scatterConfig.yAxis.column.label}${scatterConfig.yAxis.gauge.value?'('+scatterConfig.yAxis.gauge.label+')':''}`:null
+                    
+                    let config = {
+                        viewType: 'scatter',
+                        option: {
+                            serieses: res.data.data.serieses,
+                            xTitle,
+                            yTitle,
+                        }
+                    }
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: config });
                 }else {
                     yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
                 }
@@ -440,6 +478,63 @@ export default {
                 yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
             }
         },
+        *fetchAggregateTableData(action, { select, call, put }) {
+            try {
+                const chartDesigner = yield select(state => state.present.chartDesigner);
+                const { code, aggregateTableConfig, preparing } = chartDesigner;
+
+                const { targetColumn, statistics } = aggregateTableConfig;
+                const body = {
+                    id: code,
+                    columnName: "Y_",
+                    operatorList: statistics,
+                    groupByList: preparing.groupBy && preparing.groupBy.key ? [preparing.groupBy.key] : [],
+                };
+                let res = yield call(service.fetch, {
+                    url: URLS.CHART_AGGREGATETABLE_OPTION,
+                    body: body
+                });
+                console.log(body, res);return;
+                if(!res.err && res.data.code > 0) {
+                    let c = chartDesigner.columns.filter(c => c.name === targetColumn)[0];
+                    const resData = res.data.data;
+
+                    let stypes = STATISTICS_OPTION.filter(o => statistics.indexOf(o.value) !== -1);
+
+                    let columns = [{
+                        title: '分析目标',
+                        dataIndex: 'targetColumn'
+                    }].concat(stypes.map(st => {
+                        return {
+                            title: st.label,
+                            dataIndex: st.value
+                        }
+                    }));
+                    let data = {
+                        targetColumn: c.label
+                    }
+
+                    let d = resData.valueList;
+                    for(let k in d) {
+                        data[k] = d[k]
+                    }
+
+                    let config = {
+                        viewType: 'aggregateTable',
+                        option: {
+                            columns: columns,
+                            data: [data]
+                        }
+                    }
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: config });
+                }else {
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
+                }
+            }catch(e) {
+                console.error(e);
+                yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
+            }
+        }
     },
     subscriptions: {
         setup({ dispatch, history }) {

+ 3 - 3
src/models/dataConnect.js

@@ -50,6 +50,9 @@ export default {
             const { selected } = action;
             return Object.assign({}, state, {selected});
         },
+        resetSelected(state, action) {
+            return Object.assign({}, state, {selected: null});
+        },
         setFilterLabel(state, action) {
             const { label } = action;
             return Object.assign({}, state, { filterLabel: label });
@@ -338,9 +341,6 @@ export default {
     subscriptions: {
         setup({ dispatch, history }) {
             return history.listen(({ pathname, query }) => {
-                if((pathname+'').startsWith('/datasource/database/')) {
-                    dispatch({ type: 'fetchList' })
-                }
             })
         }
     }

+ 6 - 33
src/models/dataSource.js

@@ -233,16 +233,14 @@ export default {
                             isOpen: c.using?'1':'0',
                             remarks: c.description
                         }
-                    })
+                    }),
+                    connectorGroup: model.group ? model.group : '-1'
                 };
                 const res = yield call(service.fetch, {
                     url: URLS.DATASOURCE_ADD,
                     body: data
                 });
                 if(!res.err && res.data.code > 0) {
-                    // let list = dataSource.list;
-                    // model.code = res.data.data;
-                    // list.unshift(model);
                     yield put({ type: 'fetchList', mandatory: true });
                     yield put({ type: 'main/redirect', path: { pathname: '/datasource' } });
                     message.success('新增成功!');
@@ -287,6 +285,7 @@ export default {
                         password: dbConfig.passWord,
                         tags: tags,
                         description: resData.note,
+                        group: resData.connectorGroup+'',
                         columns: columnConfig.map((c, i) => {
                             return {
                                 key: i,
@@ -301,6 +300,7 @@ export default {
                             }
                         })
                     }
+                    console.log('请求数据源详情', res, data);
                     yield put({ type: 'setNewModel', model: data });
                 }else {
                     message.error('数据源解析错误');
@@ -387,8 +387,6 @@ export default {
                 const dataSource = yield select(state => state.present.dataSource);
                 let model = action.model || dataSource.newOne;
                 const code = model.code;
-                let list = dataSource.list;
-    
     
                 let data = {
                     dataId: code,
@@ -398,6 +396,7 @@ export default {
                     dataTag: model.tags,
                     type: model.type,
                     createBy: 'admin',
+                    connectorGroup: model.group ? model.group : '-1',
                     dbConfig: model.address ? {
                         addrass: model.address,
                         port: model.port,
@@ -418,7 +417,6 @@ export default {
                             remarks: c.description
                         }
                     }) : '',
-                    connectorGroup: model.groupCode
                 };
                 const res = yield call(service.fetch, {
                     url: URLS.DATASOURCE_UPDATE,
@@ -426,13 +424,7 @@ export default {
                 });
                 console.log('修改数据源', data, res);
                 if(!res.err && res.data.code > 0) {
-                    list = list.map(l => {
-                        if((l.code + '') === (action.code + '')) {
-                            l = model;
-                        }
-                        return l;
-                    });
-                    yield put({ type: 'list', data: list });
+                    yield put({ type: 'fetchList', mandatory: true });
                     message.success('修改成功');
                 }else {
                     message.error('修改失败');
@@ -794,25 +786,6 @@ export default {
     subscriptions: {
         setup({ dispatch, history }) {
             return history.listen(({ pathname, query }) => {
-                if(pathname === '/datasource' || pathname.match(/chart\/(\w+)/)) {
-                    dispatch({ type: 'fetchList' });
-                }
-                if(pathname === '/datasource') {
-                    dispatch({ type: 'remoteGroupList' });
-                }
-                let detail = pathname.match(/datasource\/(\w+)\/(\w+)/);
-                if(detail) {
-                    if(pathname.match(/datasource\/(\w+)\/(\w+)\/(\w+)/)) {
-                        detail = pathname.match(/datasource\/(\w+)\/(\w+)\/(\w+)/);
-                        let code = detail[2];
-                        if(code !== 'create') {
-                            dispatch({ type: 'remoteDetail', code: code })
-                        }
-                    }else {
-                        // 缺省跳转到属性配置tab
-                        dispatch({ type: 'main/redirect', path: pathname + (pathname.endsWith('/') ? '' : '/') + 'base' })
-                    }
-                }
             })
         }
     }

+ 1 - 1
src/routes/mainLayout.js

@@ -26,7 +26,7 @@ const MainLayout = (history) => {
                     <Route exact path='/home' component={Welcome}/>
                     <Route exact sensitive path='/datasource' component={DataSource}/>
                     <Route sensitive path='/datasource/:type/:code/:tab' component={DataSourceDetail}/>
-                    <Route exact sensitive path='/dashboard' component={Dashboard} />
+                    {/* <Route exact sensitive path='/dashboard' component={Dashboard} /> */}
                     <Route exact sensitive path='/chart' component={Chart} />
                 </Switch>
             </Content>

+ 1 - 1
src/routes/router.js

@@ -12,7 +12,7 @@ function RouterConfig({ history }) {
     <LocaleProvider locale={zhCN}>
       <Router history={history}>
         <Switch>
-          <Route sensitive path='/chart/:id' component={ChartDesigner}/>
+          <Route sensitive path='/chart/:code' component={ChartDesigner}/>
           <Route sensitive path='/dashboard/:id/' component={DashboardDesigner}/>
           <Route path='/' component={MainLayout}/>
         </Switch>