Browse Source

图表展示数据解析逻辑重现设计/看板通过id请求图表展示数据实现/大量细节改动

zhuth 7 years ago
parent
commit
057c5654ef
34 changed files with 1072 additions and 1507 deletions
  1. 359 312
      src/components/chart/resolveChartOption.js
  2. 1 1
      src/components/chart/thumbnail.jsx
  3. 2 3
      src/components/chartDesigner/charts/echartsView.jsx
  4. 0 212
      src/components/chartDesigner/charts/resolveChartOption.js
  5. 3 5
      src/components/chartDesigner/charts/tableView.jsx
  6. 1 1
      src/components/chartDesigner/content.jsx
  7. 8 6
      src/components/chartDesigner/sections/style/bar.jsx
  8. 8 8
      src/components/chartDesigner/sections/style/index.jsx
  9. 1 1
      src/components/common/CardList.jsx
  10. 1 1
      src/components/common/filterBox/filterBox.jsx
  11. 0 315
      src/components/dashboard/distributeBox.jsx
  12. 0 23
      src/components/dashboard/distributeBox.less
  13. 13 3
      src/components/dashboard/list.jsx
  14. 74 49
      src/components/dashboardDesigner/chartView.jsx
  15. 4 4
      src/components/dashboardDesigner/chooseChartBox.jsx
  16. 10 1
      src/components/dashboardDesigner/configForm.jsx
  17. 16 21
      src/components/dashboardDesigner/content.jsx
  18. 2 1
      src/components/dashboardDesigner/header.jsx
  19. 17 5
      src/components/dashboardDesigner/layout.jsx
  20. 0 56
      src/components/dashboardDesigner/settingBox.jsx
  21. 10 6
      src/components/dashboardDesigner/viewLayout.jsx
  22. 1 1
      src/components/dashboardDesigner/viewLayout.less
  23. 4 0
      src/constants/url.js
  24. 0 2
      src/index.js
  25. 1 9
      src/models/chart.js
  26. 16 123
      src/models/chartDesigner.js
  27. 0 2
      src/models/chartPolicy.js
  28. 40 11
      src/models/dashboard.js
  29. 177 63
      src/models/dashboardDesigner.js
  30. 0 255
      src/models/dashboardPolicy.js
  31. 0 4
      src/models/dataSource.js
  32. 0 2
      src/models/dataSourcePolicy.js
  33. 303 0
      src/models/parseChartOption.js
  34. 0 1
      src/utils/request.js

+ 359 - 312
src/components/chart/resolveChartOption.js

@@ -1,331 +1,378 @@
-import moment from 'moment'
-import GRANULARITY from '../chartDesigner/sections/granularity'
+/**
+ * 为图表option二次设置样式属性
+ */
 
-export default (config, styleConfig, silent, thumbnail) => {
-    const { viewType, chartConfig, option } = config;
-    let o;
-    switch(viewType) {
-        case 'bar': {
-            o = barConfig(chartConfig, option, styleConfig, silent, thumbnail);
-            break;
-        }
-        case 'pie': {
-            o = pieConfig(option, styleConfig, silent, thumbnail);
-            break;
-        }
-        case 'line': {
-            o = lineConfig(option, styleConfig, silent, thumbnail);
-            break;
-        }
-        case 'scatter': {
-            o = scatterConfig(option, styleConfig, silent, thumbnail);
-            break;
-        }
-        case 'aggregateTable': {
-            o = aggregateTableConfig(option, styleConfig, silent, thumbnail);
-            break;
-        }case 'dataView' : {
-            o = tableViewConfig(option, styleConfig, silent, thumbnail);
-            break;
-        }
-        default:{
-            o = {};
-            break;
-        }
-    }
-    return o;
-}
+/**
+ * @param option: Object 图表配置档
+ * @param silent: Boolean 无交互
+ * @param thumbnail: Boolean 缩略图模式
+ */
+export default (option, silent, thumbnail) => {
+    let _option = { ...option };
+    let viewType = _option.series ? (_option.series[0].type) : null;
 
-function barConfig(chartConfig, option, styleConfig, silent, thumbnail) {
-    const { xAxis, serieses, xTitle, yTitle } = option;
-    const { bar } = styleConfig;
-    const { stack, visibleToolTip } = (bar || { stack: false, visibleToolTip: true });
-    let o = {
-        animation: !thumbnail,
-        tooltip : {
-            show: visibleToolTip && !silent && !thumbnail,
-            trigger: "axis",
-            axisPointer: {
-                type: "cross",
-                label: {
-                    backgroundColor: "#6a7985"
-                }
+    // 动画
+    _option.animation = !thumbnail;
+    // 悬浮提示
+    _option.tooltip = _option.tooltip ? {
+        ..._option.tooltip,
+        show: !silent && !thumbnail
+    } : {
+        show: !silent && !thumbnail,
+        trigger: "axis",
+        axisPointer: {
+            type: "cross",
+            label: {
+                backgroundColor: "#6a7985"
             }
-        },
-        legend: {
-            show: !thumbnail,
-            selectedMode: !silent
-        },
-        grid: {
-            left: thumbnail ? 10 : '10%',
-            right: thumbnail ? 10 : '10%',
-            top: thumbnail ? 10 : 60,
-            bottom: thumbnail ? 10 : 60,
-            containLabel: !thumbnail
-        },
-        xAxis: [{
-            show: !thumbnail,
-            type: 'category',
-            data: barXAxis(chartConfig, xAxis),
-            name: xTitle || '横轴',
-        }],
-        yAxis: [{
-            show: !thumbnail,
-            name: yTitle || '纵轴',
-            type: 'value'
-        }],
-        series: serieses.map(s => {
-            return {
-                name: s.name,
-                type: 'bar',
-                data: s.value,
-                stack: stack ? '1' : null,
-                showSymbol: !thumbnail,
-                silent,
-            }
-        }) 
+        }
+    };
+    // 图例
+    _option.legend = _option.legend ? {
+        ..._option.legend,
+        show: !thumbnail,
+        selectedMode: !silent
+    } : {
+        show: !thumbnail,
+        selectedMode: !silent
+    }
+    // 容器
+    _option.grid = _option.grid ? {
+        left: thumbnail ? 10 : (_option.grid.left ? _option.grid.left : '10%'),
+        right: thumbnail ? 10 : (_option.grid.right ? _option.grid.right : '10%'),
+        top: thumbnail ? 10 : (_option.grid.top ? _option.grid.top : 60),
+        bottom: thumbnail ? 10 : (_option.grid.bottom ? _option.grid.bottom : 60),
+        containLabel: !thumbnail
+    } : {
+        left: thumbnail ? 10 : '10%',
+        right: thumbnail ? 10 : '10%',
+        top: thumbnail ? 10 : 60,
+        bottom: thumbnail ? 10 : 60,
+        containLabel: !thumbnail
+    }
+    // x轴
+    _option.xAxis ? _option.xAxis[0] = {
+        ..._option.xAxis[0],
+        show: !thumbnail
+    } : void 0;
+    // y轴
+    _option.yAxis ? _option.yAxis[0] = {
+        ..._option.yAxis[0],
+        show: !thumbnail
+    } : void 0;
+    // 图形
+    if(viewType ==='bar' ) { // 柱状图
+        _option.series = _option.series.map(s => ({
+            ...s, showSymbol: !thumbnail, silent
+        }));
+    }else if(viewType === 'pie') { // 饼图
+        _option.series = _option.series.map(s => ({
+            ...s, label: { show: !silent }, labelLine: { show: !silent }, silent
+        }));
+    }else if(viewType === 'line') { // 折线图
+        _option.series = _option.series.map(s => ({
+            ...s, showSymbol: !thumbnail, silent
+        }));
+    }else if(viewType === 'scatter') { // 散点图
+        _option.series = _option.series.map(s => ({
+            ...s, silent
+        }));
     }
-    return o;
+    
+    
+    return _option;
 }
 
-function pieConfig(option, styleConfig, silent, thumbnail) {
+// function barConfig(chartConfig, option, styleConfig, silent, thumbnail) {
+//     const { xAxis, serieses, xTitle, yTitle } = option;
+//     const { bar } = styleConfig;
+//     const { stack, visibleToolTip } = (bar || { stack: false, visibleToolTip: true });
+//     let o = {
+//         animation: !thumbnail,
+//         tooltip : {
+//             show: visibleToolTip && !silent && !thumbnail,
+//             trigger: "axis",
+//             axisPointer: {
+//                 type: "cross",
+//                 label: {
+//                     backgroundColor: "#6a7985"
+//                 }
+//             }
+//         },
+//         legend: {
+//             show: !thumbnail,
+//             selectedMode: !silent
+//         },
+//         grid: {
+//             left: thumbnail ? 10 : '10%',
+//             right: thumbnail ? 10 : '10%',
+//             top: thumbnail ? 10 : 60,
+//             bottom: thumbnail ? 10 : 60,
+//             containLabel: !thumbnail
+//         },
+//         xAxis: [{
+//             show: !thumbnail,
+//             type: 'category',
+//             data: barXAxis(chartConfig, xAxis),
+//             name: xTitle || '横轴',
+//         }],
+//         yAxis: [{
+//             show: !thumbnail,
+//             name: yTitle || '纵轴',
+//             type: 'value'
+//         }],
+//         series: serieses.map(s => {
+//             return {
+//                 name: s.name,
+//                 type: 'bar',
+//                 data: s.value,
+//                 stack: stack ? '1' : null,
+//                 showSymbol: !thumbnail,
+//                 silent,
+//             }
+//         }) 
+//     }
+//     return o;
+// }
 
-    const { xAxis, columnName, serieses } = option;
+// function pieConfig(option, styleConfig, silent, thumbnail) {
 
-    let o = {
-        animation: !thumbnail,
-        grid: {
-            left: thumbnail ? 10 : '10%',
-            right: thumbnail ? 10 : '10%',
-            top: thumbnail ? 10 : 60,
-            bottom: thumbnail ? 10 : 60,
-            containLabel: !thumbnail
-        },
-        tooltip : {
-            show: !silent && !thumbnail,
-            trigger: 'item',
-            formatter: "{a} <br/>{b} : {c} ({d}%)"
-        },
-        legend: {
-            show: !thumbnail,
-            data: xAxis,
-            selectedMode: !silent
-        },
-        series : [
-            {
-                name: columnName,
-                type: 'pie',
-                // radius : '55%',
-                // center: ['50%', '60%'],
-                data: serieses[0].value,
-                label: { show: !silent },
-                labelLine: { show: !silent },
-                itemStyle: {
-                    emphasis: {
-                        shadowBlur: 10,
-                        shadowOffsetX: 0,
-                        shadowColor: 'rgba(0, 0, 0, 0.5)'
-                    }
-                },
-                silent
-            }
-        ]
-    };
-    return o;
-}
+//     const { xAxis, columnName, serieses } = option;
 
-function lineConfig(option, styleConfig, silent, thumbnail) {
-    const { serieses, xTitle, yTitle } = option;
+//     let o = {
+//         animation: !thumbnail,
+//         grid: {
+//             left: thumbnail ? 10 : '10%',
+//             right: thumbnail ? 10 : '10%',
+//             top: thumbnail ? 10 : 60,
+//             bottom: thumbnail ? 10 : 60,
+//             containLabel: !thumbnail
+//         },
+//         tooltip : {
+//             show: !silent && !thumbnail,
+//             trigger: 'item',
+//             formatter: "{a} <br/>{b} : {c} ({d}%)"
+//         },
+//         legend: {
+//             show: !thumbnail,
+//             data: xAxis,
+//             selectedMode: !silent
+//         },
+//         series : [
+//             {
+//                 name: columnName,
+//                 type: 'pie',
+//                 // radius : '55%',
+//                 // center: ['50%', '60%'],
+//                 data: serieses[0].value,
+//                 label: { show: !silent },
+//                 labelLine: { show: !silent },
+//                 itemStyle: {
+//                     emphasis: {
+//                         shadowBlur: 10,
+//                         shadowOffsetX: 0,
+//                         shadowColor: 'rgba(0, 0, 0, 0.5)'
+//                     }
+//                 },
+//                 silent
+//             }
+//         ]
+//     };
+//     return o;
+// }
 
-    let o = {
-        animation: !thumbnail,
-        grid: {
-            left: thumbnail ? 10 : '10%',
-            right: thumbnail ? 10 : '10%',
-            top: thumbnail ? 10 : 60,
-            bottom: thumbnail ? 10 : 60,
-            containLabel: !thumbnail
-        },
-        tooltip: {
-            show: !silent && !thumbnail,
-            trigger: 'axis',
-            axisPointer: {
-                type: 'cross'
-            }
-        },
-        legend: {
-            show: !thumbnail,
-            selectedMode: !silent
-        },
-        xAxis:  {
-            show: !thumbnail,
-            name: xTitle,
-            type: 'time'
-        },
-        yAxis: {
-            show: !thumbnail,
-            name: yTitle,
-            type: 'value'
-        },
+// function lineConfig(option, styleConfig, silent, thumbnail) {
+//     const { serieses, xTitle, yTitle } = option;
+
+//     let o = {
+//         animation: !thumbnail,
+//         grid: {
+//             left: thumbnail ? 10 : '10%',
+//             right: thumbnail ? 10 : '10%',
+//             top: thumbnail ? 10 : 60,
+//             bottom: thumbnail ? 10 : 60,
+//             containLabel: !thumbnail
+//         },
+//         tooltip: {
+//             show: !silent && !thumbnail,
+//             trigger: 'axis',
+//             axisPointer: {
+//                 type: 'cross'
+//             }
+//         },
+//         legend: {
+//             show: !thumbnail,
+//             selectedMode: !silent
+//         },
+//         xAxis:  {
+//             show: !thumbnail,
+//             name: xTitle,
+//             type: 'time'
+//         },
+//         yAxis: {
+//             show: !thumbnail,
+//             name: yTitle,
+//             type: 'value'
+//         },
         
-        series: serieses.map(s => {
-            return {
-                name: s.name,
-                type: 'line',
-                data: s.mdata.map(m => {
-                    return [m.date, m.value]
-                }),
-                showSymbol: !thumbnail,
-                silent
-            }
-        })
-    };
+//         series: serieses.map(s => {
+//             return {
+//                 name: s.name,
+//                 type: 'line',
+//                 data: s.mdata.map(m => {
+//                     return [m.date, m.value]
+//                 }),
+//                 showSymbol: !thumbnail,
+//                 silent
+//             }
+//         })
+//     };
 
-    return o;
-}
+//     return o;
+// }
 
-function scatterConfig(option, styleConfig, silent, thumbnail) {
-    const { serieses, xTitle, yTitle } = option;
-    let o = {
-        animation: !thumbnail,
-        grid: {
-            left: thumbnail ? 10 : '10%',
-            right: thumbnail ? 10 : '10%',
-            top: thumbnail ? 10 : 60,
-            bottom: thumbnail ? 10 : 60,
-            containLabel: !thumbnail
-        },
-        tooltip : {
-            show: !silent && !thumbnail,
-            showDelay : 0,
-            axisPointer:{
-                show: true,
-                type : 'cross',
-                lineStyle: {
-                    type : 'dashed',
-                    width : 1
-                }
-            }
-        },
-        legend: {
-            show: !thumbnail,
-            selectedMode: !silent
-        },
-        xAxis : [
-            {
-                show: !thumbnail,
-                type : 'value',
-                name: xTitle,
-                scale:true,
-                splitLine: {
-                    show: false
-                }
-            }
-        ],
-        yAxis : [
-            {
-                show: !thumbnail,
-                type : 'value',
-                name: yTitle,
-                scale:true,
-                splitLine: {
-                    show: false
-                }
-            }
-        ],
-        series : serieses.map(s => {
-            return {
-                name: s.name,
-                type: 'scatter',
-                data: s.mdata.map(m => {
-                    return [m.date, m.value]
-                }),
-                silent
-            }
-        })
-    };
-    return o;
-}
+// function scatterConfig(option, styleConfig, silent, thumbnail) {
+//     const { serieses, xTitle, yTitle } = option;
+//     let o = {
+//         animation: !thumbnail,
+//         grid: {
+//             left: thumbnail ? 10 : '10%',
+//             right: thumbnail ? 10 : '10%',
+//             top: thumbnail ? 10 : 60,
+//             bottom: thumbnail ? 10 : 60,
+//             containLabel: !thumbnail
+//         },
+//         tooltip : {
+//             show: !silent && !thumbnail,
+//             showDelay : 0,
+//             axisPointer:{
+//                 show: true,
+//                 type : 'cross',
+//                 lineStyle: {
+//                     type : 'dashed',
+//                     width : 1
+//                 }
+//             }
+//         },
+//         legend: {
+//             show: !thumbnail,
+//             selectedMode: !silent
+//         },
+//         xAxis : [
+//             {
+//                 show: !thumbnail,
+//                 type : 'value',
+//                 name: xTitle,
+//                 scale:true,
+//                 splitLine: {
+//                     show: false
+//                 }
+//             }
+//         ],
+//         yAxis : [
+//             {
+//                 show: !thumbnail,
+//                 type : 'value',
+//                 name: yTitle,
+//                 scale:true,
+//                 splitLine: {
+//                     show: false
+//                 }
+//             }
+//         ],
+//         series : serieses.map(s => {
+//             return {
+//                 name: s.name,
+//                 type: 'scatter',
+//                 data: s.mdata.map(m => {
+//                     return [m.date, m.value]
+//                 }),
+//                 silent
+//             }
+//         })
+//     };
+//     return o;
+// }
 
-function aggregateTableConfig(option, styleConfig, silent, thumbnail) {
-    const { columns, data } = option;
-    let c = columns.map(_c => {
-        if(_c.dataIndex === 'percent') {
-            return { ..._c, render: (value, record, index) => ((+value*100).toFixed(2)) + '%'};
-        }else {
-            return {..._c, width: 100};
-        }
-    });
-    let o = {
-        columns: c,
-        data: data.map((d, i) => {
-            return { ...d, key: i}
-        })
-    };
-    return o;
-}
+// function aggregateTableConfig(option, styleConfig, silent, thumbnail) {
+//     const { columns, data } = option;
+//     let c = columns.map(_c => {
+//         if(_c.dataIndex === 'percent') {
+//             return { ..._c, render: (value, record, index) => ((+value*100).toFixed(2)) + '%'};
+//         }else {
+//             return {..._c, width: 100};
+//         }
+//     });
+//     let o = {
+//         columns: c,
+//         data: data.map((d, i) => {
+//             return { ...d, key: i}
+//         })
+//     };
+//     return o;
+// }
 
-function tableViewConfig(option, styleConfig, silent, thumbnail) {
-    const { columns, data } = option;
-    const { table } = styleConfig || {};
-    const {
-        visibleIndex,
-        aligns,
-        widths,
-        thousandsSeparatorColumns,
-    } = table || {
-        visibleIndex: false,
-        aligns: {},
-        widths: {},
-        thousandsSeparatorColumns: [],
-    };
-    console.log(styleConfig);
-    let c = columns.map(c => {
-        let o = {
-            key: c.name,
-            title: c.label,
-            dataIndex: c.name,
-            width: widths? (widths[c.name] ? ( +widths[c.name] ) : 100 ) : 100,
-            align: aligns ? (aligns[c.name] || 'left') : 'left',
-        };
-        if(c.type === 'time') {
-            o.render = v => moment(v).format('YYYY-MM-DD');
-        }
-        return o;
-    });
-    if(visibleIndex) {
-        c.unshift({
-            key: '_index',
-            title: '序号',
-            render: (v, r, i) => i+1,
-            width: 50,
-            align: 'center'
-        });
-    }
-    let o = {
-        columns: c,
-        data: data.map((d, i) => {
-            return { ...d, key: i}
-        })
-    };
-    return o;
-}
+// function tableViewConfig(option, styleConfig, silent, thumbnail) {
+//     const { columns, data } = option;
+//     const { table } = styleConfig || {};
+//     const {
+//         visibleIndex,
+//         aligns,
+//         widths,
+//         thousandsSeparatorColumns,
+//     } = table || {
+//         visibleIndex: false,
+//         aligns: {},
+//         widths: {},
+//         thousandsSeparatorColumns: [],
+//     };
+//     console.log(styleConfig);
+//     let c = columns.map(c => {
+//         let o = {
+//             key: c.name,
+//             title: c.label,
+//             dataIndex: c.name,
+//             width: widths? (widths[c.name] ? ( +widths[c.name] ) : 100 ) : 100,
+//             align: aligns ? (aligns[c.name] || 'left') : 'left',
+//         };
+//         if(c.type === 'time') {
+//             o.render = v => moment(v).format('YYYY-MM-DD');
+//         }
+//         return o;
+//     });
+//     if(visibleIndex) {
+//         c.unshift({
+//             key: '_index',
+//             title: '序号',
+//             render: (v, r, i) => i+1,
+//             width: 50,
+//             align: 'center'
+//         });
+//     }
+//     let o = {
+//         columns: c,
+//         data: data.map((d, i) => {
+//             return { ...d, key: i}
+//         })
+//     };
+//     return o;
+// }
 
-function barXAxis(chartConfig, xAxis) {
-    let data = xAxis;
+// function barXAxis(chartConfig, xAxis) {
+//     let data = xAxis;
     
-    if(chartConfig) {
-        const { xAxis: cx } = chartConfig;
-        const { column, granularity } = cx;
-        const { label: cLabel, type: cType, value: cValue } = column;
-        const { label: gLabel, value: gValue } = granularity;
+//     if(chartConfig) {
+//         const { xAxis: cx } = chartConfig;
+//         const { column, granularity } = cx;
+//         const { label: cLabel, type: cType, value: cValue } = column;
+//         const { label: gLabel, value: gValue } = granularity;
 
-        if(cType === 'time') {
-            let s = GRANULARITY['time'];
-            let g = s.find(d => d.value === gValue);
-            data = xAxis.map(x => (g.replaceFunction && typeof g.replaceFunction === 'function') ? g.replaceFunction(x) : x);
-        }
-    }
+//         if(cType === 'time') {
+//             let s = GRANULARITY['time'];
+//             let g = s.find(d => d.value === gValue);
+//             data = xAxis.map(x => (g.replaceFunction && typeof g.replaceFunction === 'function') ? g.replaceFunction(x) : x);
+//         }
+//     }
     
-    return data;
-}
+//     return data;
+// }

+ 1 - 1
src/components/chart/thumbnail.jsx

@@ -3,7 +3,7 @@ import Echarts from 'echarts-for-react'
 import resolveChartOption from './resolveChartOption'
 
 const Thumbnail = ({ style, type, code, option }) => {
-    const newOption = resolveChartOption(option || {}, {}, true, true);
+    const newOption = resolveChartOption(option, true, true);
     const viewType = ['bar', 'line', 'pie', 'scatter'].indexOf(type) !== -1 ? 'echarts' :
         (['aggregateTable', 'dataView'].indexOf(type) !== -1 ? 'table' : 'default');
         

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

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

+ 0 - 212
src/components/chartDesigner/charts/resolveChartOption.js

@@ -1,212 +0,0 @@
-export default (config) => {
-    const { viewType, option } = config;
-    let o;
-    switch(viewType) {
-        case 'bar': {
-            o = barConfig(option);
-            break;
-        }
-        case 'pie': {
-            o = pieConfig(option);
-            break;
-        }
-        case 'line': {
-            o = lineConfig(option);
-            break;
-        }
-        case 'scatter': {
-            o = scatterConfig(option);
-            break;
-        }
-        case 'aggregateTable': {
-            o = tableConfig(option);
-            break;
-        }case 'dataView' : {
-            o = tableConfig(option);
-            break;
-        }
-        default:{
-            o = {};
-            break;
-        }
-    }
-    return o;
-}
-
-function barConfig(option) {
-    const { xAxis, serieses, xTitle, yTitle } = option;
-
-    let o = {
-        tooltip : {
-            trigger: "axis",
-            axisPointer: {
-                type: "cross",
-                label: {
-                    backgroundColor: "#6a7985"
-                }
-            }
-        },
-        legend: {
-            show: true
-        },
-        xAxis: [{
-            type: 'category',
-            data: xAxis,
-            name: xTitle || '横轴',
-        }],
-        yAxis: [{
-            name: yTitle || '纵轴',
-            type: 'value'
-        }],
-        series: serieses.map(s => {
-            return {
-                name: s.name,
-                type: 'bar',
-                data: s.value,
-                // stack: s.stack
-            }
-        }) 
-    }
-    return o;
-}
-
-function pieConfig(option) {
-
-    const { xAxis, columnName, serieses } = option;
-
-    let o = {
-        tooltip : {
-            trigger: 'item',
-            formatter: "{a} <br/>{b} : {c} ({d}%)"
-        },
-        legend: {
-            data: xAxis
-        },
-        series : [
-            {
-                name: columnName,
-                type: 'pie',
-                radius : '55%',
-                center: ['50%', '60%'],
-                data: serieses[0].value,
-                itemStyle: {
-                    emphasis: {
-                        shadowBlur: 10,
-                        shadowOffsetX: 0,
-                        shadowColor: 'rgba(0, 0, 0, 0.5)'
-                    }
-                }
-            }
-        ]
-    };
-    return o;
-}
-
-function lineConfig(option) {
-    const { serieses, xTitle, yTitle } = option;
-
-    let o = {
-        tooltip: {
-            trigger: 'axis',
-            axisPointer: {
-                type: 'cross'
-            }
-        },
-        legend: {
-            show: true
-        },
-        xAxis:  {
-            name: xTitle,
-            type: 'time'
-        },
-        yAxis: {
-            name: yTitle,
-            type: 'value'
-        },
-        
-        series: serieses.map(s => {
-            return {
-                name: s.name,
-                type: 'line',
-                data: s.mdata.map(m => {
-                    return [m.date, m.value]
-                })
-            }
-        })
-    };
-
-    return o;
-}
-
-function scatterConfig(option) {
-    const { serieses, xTitle, yTitle } = option;
-    let o = {
-        tooltip : {
-            showDelay : 0,
-            axisPointer:{
-                show: true,
-                type : 'cross',
-                lineStyle: {
-                    type : 'dashed',
-                    width : 1
-                }
-            }
-        },
-        legend: {
-            show: true
-        },
-        xAxis : [
-            {
-                type : 'value',
-                name: xTitle,
-                scale:true,
-                splitLine: {
-                    show: false
-                }
-            }
-        ],
-        yAxis : [
-            {
-                type : 'value',
-                name: yTitle,
-                scale:true,
-                splitLine: {
-                    show: false
-                }
-            }
-        ],
-        series : serieses.map(s => {
-            return {
-                name: s.name,
-                type: 'scatter',
-                data: s.mdata.map(m => {
-                    return [m.date, m.value]
-                })
-            }
-        })
-    };
-    return o;
-}
-
-function tableConfig(option) {
-    const { columns, data } = option;
-    let c = columns.map(c => {
-        c.width = 100;
-        if(c.dataIndex === 'percent') { // 这里只在总体统计图下生效
-            return { ...c, render: (value, record, index) => {console.log(record);return ((+value*100).toFixed(2)) + '%'} };
-        }else {
-            return c;
-        }
-    });
-    c.unshift({
-        title: '序号',
-        rander: (v, r, i) => i
-    });
-    let o = {
-        columns: c,
-        data: data.map((d, i) => {
-            return { ...d, key: i}
-        })
-    };
-    return o;
-}

+ 3 - 5
src/components/chartDesigner/charts/tableView.jsx

@@ -1,13 +1,11 @@
 import React from 'react'
 import { Table } from 'antd'
 import { connect } from 'dva'
-import resolveChartOption from '../../chart/resolveChartOption'
 import './tableView.less'
 
 const TableView = ({ contentSize, chartDesigner, dispatch }) => {
     const { chartOption, styleConfig } = chartDesigner;
-    const option = resolveChartOption(chartOption, styleConfig);
-    const { columns, data } = option;
+    const { columns, dataSource } = chartOption;
 
     const { table } = styleConfig || {};
     const { bordered } = table || {};
@@ -18,11 +16,11 @@ const TableView = ({ contentSize, chartDesigner, dispatch }) => {
         <Table
             className='table-view'
             columns={columns}
-            dataSource={data}
+            dataSource={dataSource}
             size='small'
             bordered={bordered}
             scroll={{
-                x: columns ? columns.length * 100 : 0,
+                x: columns ? columns.length * 200 : 0,
                 y: tableContentHeight
             }}
             pagination={{ defaultPageSize: Math.floor(tableContentHeight/tableRowHeight) || 10 }}

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

@@ -122,7 +122,7 @@ class ChartDesignerContent extends React.Component {
                             <Button style={{ display: autoRefresh ? 'none' : 'block' }} size='small' onClick={() => { dispatch({ type: 'chartDesigner/fetchChartData'}) }}
                             >立即刷新</Button>
                         </div>
-                        </Footer> }
+                    </Footer> }
                 </Sider>
                 <Content className='view-content' >
                     <Layout>

+ 8 - 6
src/components/chartDesigner/sections/style/bar.jsx

@@ -1,8 +1,10 @@
 import React from 'react'
 import { connect } from 'dva'
-import { Collapse, Menu, Form, Checkbox, Row, Col, Select, Radio, Input, InputNumber } from 'antd'
-const SubMenu = Menu.SubMenu;
-const MenuItemGroup = Menu.ItemGroup;
+import { Collapse, 
+    // Menu,
+    Form, Checkbox, Select, Radio } from 'antd'
+// const SubMenu = Menu.SubMenu;
+// const MenuItemGroup = Menu.ItemGroup;
 
 class BarStyle extends React.Component {
     
@@ -17,7 +19,7 @@ class BarStyle extends React.Component {
 
     render() {
         const { chartDesigner, formItemLayout, dispatch } = this.props;
-        const { layoutColumn, formatColumn, colorColumn } = this.state;
+        // const { layoutColumn, formatColumn, colorColumn } = this.state;
         const { styleConfig } = chartDesigner;
         const { bar } = (styleConfig || {  });
 
@@ -43,7 +45,7 @@ class BarStyle extends React.Component {
                         <Form.Item label='显示标签' {...formItemLayout}>
                             <div>
                                 <Checkbox defaultChecked={false} onChange={(e) => {
-                                    const checked = e.target.checked;
+                                    // const checked = e.target.checked;
                                     // dispatch({ type: 'chartDesigner/setField', name: 'styleConfig', value: { ...styleConfig, table: { ...table, bordered: checked }} });
                                 }}/>
                                 <Select onChange={null} >
@@ -58,7 +60,7 @@ class BarStyle extends React.Component {
                     <Form>
                         <Form.Item label='显示' {...formItemLayout}>
                             <Checkbox onChange={(e) => {
-                                    const checked = e.target.checked;
+                                    // const checked = e.target.checked;
                                     // dispatch({ type: 'chartDesigner/setField', name: 'styleConfig', value: { ...styleConfig, table: { ...table, bordered: checked }} });
                                 }}/>
                         </Form.Item>

+ 8 - 8
src/components/chartDesigner/sections/style/index.jsx

@@ -1,17 +1,17 @@
-import TableStyle from './table'
-import BarStyle from './bar'
+// import TableStyle from './table'
+// import BarStyle from './bar'
 
 export default ({ viewType }) => {
     let styleForm = <div>无可用样式配置</div>;
-    const formItemLayout = {
-        labelCol: { span: 8 },
-        wrapperCol: { span: 16 },
-    };
+    // const formItemLayout = {
+    //     labelCol: { span: 8 },
+    //     wrapperCol: { span: 16 },
+    // };
 
     if(viewType === 'dataView') {
-        styleForm = <TableStyle formItemLayout={formItemLayout}/>
+        // styleForm = <TableStyle formItemLayout={formItemLayout}/>
     }else if(viewType === 'bar') {
-        styleForm = <BarStyle formItemLayout={formItemLayout}/>
+        // styleForm = <BarStyle formItemLayout={formItemLayout}/>
     }
     return styleForm;
 }

+ 1 - 1
src/components/common/CardList.jsx

@@ -31,8 +31,8 @@ class CardList extends React.Component {
             'chart': this.props.chart //同上
         }
         let list = modeMapper[mode].list
-        let filterLabel = modeMapper[mode].filterLabel.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
         const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
+        let filterLabel = modeMapper[mode].filterLabel.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
         const operationMenu = (
             <Menu className='menu-operation'>
                 <Menu.Item onClick={() => {

+ 1 - 1
src/components/common/filterBox/filterBox.jsx

@@ -1,6 +1,6 @@
 import React from 'react'
 import PropTypes from 'prop-types'
-import { Modal, Form, Row, Col, Input, Icon, Button, Select, InputNumber, DatePicker, Spin, Cascader, Dropdown, Menu } from 'antd'
+import { Modal, Form, Row, Col, Input, Icon, Button, Select, InputNumber, DatePicker, Spin } from 'antd'
 import OPERATORS from './filterOperators.js';
 import './filterBox.less'
 import * as service from '../../../services/index'

+ 0 - 315
src/components/dashboard/distributeBox.jsx

@@ -1,315 +0,0 @@
-import React from 'react'
-import { Modal, Layout, Card, Table, Col, Row, Button, Input, Icon, Tag, Checkbox } from 'antd'
-import { connect } from 'dva'
-import FilterBox from '../common/filterBox/filterBox'
-import AccessObjectBox from '../datasource/accessObjectBox'
-import moment from 'moment'
-import './distributeBox.less'
-const { Content } = Layout
-
-const Search = Input.Search;
-
-class DistributeBox extends React.Component {
-    constructor(props){
-        super(props);
-        this.state = {
-            filterLabel: '',
-            visibleDistributeObjectBox: false,
-            visibleDistributePolicyRuleBox: false,
-            currentPolicy: null,
-            visiblePolicyRuleBox: false,
-            visibleAccessObjectBox: false
-        }
-    }
-
-    componentDidMount() {
-        // const { selectedRecord, dispatch } = this.props;
-        // const chartCode = selectedRecord ? selectedRecord.code : '';
-        // dispatch({ type: 'dataSourcePolicy/fetchList', chartCode: chartCode });
-    }
-
-    hideDistributeObjectBox= () => {
-        this.setState(
-            {visibleDistributeObjectBox:false})
-    }
-
-    hideDistributePolicyRuleBox= () => {
-        this.setState(
-            {visibleDistributePolicyRuleBox:false})
-    }
-
-    showAccessObjectBox = () => {
-        this.setState({ visibleAccessObjectBox:true })
-    }
-
-    hideAccessObjectBox = () => {
-        this.setState({ visibleAccessObjectBox:false })
-    }
-
-    showPolicyRuleBox= () => {
-        this.setState({ visiblePolicyRuleBox: true })
-    }
-
-    hidePolicyRuleBox= () => {
-        this.setState({ visiblePolicyRuleBox: false })
-    }
-
-    setAccessObject = (group, geren) => {
-        const { dispatch } = this.props;
-        const { currentPolicy } = this.state;
-        let targets = group.map(g => ({
-            code: g.code,
-            name: g.name,
-            isGroup: true
-        })).concat(geren.map(g => ({
-            code: g.code,
-            name: g.name,
-            isGroup: false
-        })))
-        dispatch({ type: 'dashboardPolicy/remoteSetTarget', policy: currentPolicy, targets });
-    }
-
-    createFilters = (filters) => {
-        const { selectedRecord, dispatch } = this.props;
-        let { currentPolicy } = this.state;
-        const chartCode = selectedRecord ? selectedRecord.code : '';
-
-        currentPolicy.filters = filters;
-        dispatch({ type: 'dashboardPolicy/remoteModify', policy: currentPolicy, chartCode });
-    }
-
-    /**
-     * 生成过滤规则文本
-     */
-    createFilterLabel = (filter) => {
-        let { label, operator, operatorLabel, type, value1, value2 } = filter;
-        let filterLabel;
-
-        if(type === 'string' || type === 'index') {
-            if(operator === 'null' || operator === 'notNull') {
-                filterLabel = `${label} ${operatorLabel}`;
-            }else {
-                filterLabel = `${label} ${operatorLabel} ${value1}`;
-            }
-        }else if(type === 'scale') {
-            if(operator === 'null' || operator === 'notNull') {
-                filterLabel = `${label} ${operatorLabel}`;
-            }else if(operator === 'between') {
-                filterLabel = `${label} ${operatorLabel} ${value1} ~ ${value2}`; 
-            }else {
-                filterLabel = `${label} ${operatorLabel} ${value1}`; 
-            }
-        }else if(type === 'time') {
-            value1 = moment(value1).format('yyyy/MM/dd');
-            value2 = moment(value2).format('yyyy/MM/dd');
-            if(operator === 'null' || operator === 'notNull') {
-                filterLabel = `${label} ${operatorLabel}`;
-            }else if(operator === 'between') {
-                filterLabel = `${label} ${operatorLabel} ${value1} ~ ${value2}`;
-            }else {
-                filterLabel = `${label} ${operatorLabel} ${value1}`;
-            }
-        }else if(type === 'categorical') {
-            if(operator === 'null' || operator === 'notNull') {
-                filterLabel = `${label} ${operatorLabel}`;
-            }else {
-                filterLabel = `${label} ${operatorLabel} ${value1}`;
-            }
-        }else {
-            filterLabel = '错误条件';
-        }
-        return filterLabel;
-    }
-
-    render() {
-        const { selectedRecord, dashboardPolicy, visibleDistributeBox, hideBox, dispatch } = this.props;
-        const { visiblePolicyRuleBox, visibleAccessObjectBox } = this.state;
-        const polices = dashboardPolicy.list;
-        const chartCode = selectedRecord ? selectedRecord.code : '';
-
-        const { currentPolicy } = this.state;
-        const group = currentPolicy ? (currentPolicy.targets ? currentPolicy.targets.filter(t => t.isGroup) : []) : [];
-        const geren = currentPolicy ? (currentPolicy.targets ? currentPolicy.targets.filter(t => !t.isGroup) : []) : [];
-        
-        const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
-        let filterLabel = (this.state.filterLabel || '').replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
-        
-        // const columnData = dataSource.newOne.columns ? dataSource.newOne.columns.map(c => ({
-        //     key: c.key,
-        //     label: c.alias,
-        //     name: c.name,
-        //     selection: [],
-        //     type: c.columnType,
-        //     groupable: c.groupable,
-        //     // filterable: c.filterable,
-        //     filterable: true,
-        //     bucketizable: c.bucketizable
-        // })) : [];
-        
-        const columns = [{
-            title:'启用',
-            dataIndex:'enabled',
-            render: (v, r) => <Checkbox
-                checked={v}
-                onChange={(e) => {
-                    let policy = {
-                        ...r,
-                        enabled: e.target.checked
-                    }
-                    dispatch({ type: 'dashboardPolicy/remoteModify', policy, chartCode  });
-                }}
-            />,
-            width: 50
-        },{
-            title: '策略名',
-            dataIndex: 'name',
-            render: (value, record, index) => <div key={index}>
-                {
-                    this.state.inputRow === index ? <Input value={value} suffix={<Icon style={{ cursor: 'pointer', color: '#52C41A' }} type="check-circle" onClick={() => {
-                        this.setState({
-                            inputRow: -1
-                        });
-                        dispatch({ type: 'dashboardPolicy/remoteModify', policy: record, chartCode });
-                    }}/>} onChange={(e) => {
-                        dispatch({ type: 'dashboardPolicy/modify', policy: { ...record, name: e.target.value } });
-                    }} onBlur={() => {
-                        this.setState({
-                            inputRow: -1
-                        });
-                        dispatch({ type: 'dashboardPolicy/remoteModify', policy: record, chartCode });
-                    }} onPressEnter={() => {
-                        this.setState({
-                            inputRow: -1
-                        });
-                        dispatch({ type: 'dashboardPolicy/remoteModify', policy: record, chartCode });
-                    }}/> : <span onClick={() => {
-                        this.setState({
-                            inputRow: index
-                        });
-                    }}>
-                        { filterLabel ?
-                            ((value || '').split(new RegExp(`(${filterLabel})`, 'i')).map((fragment, i) => {
-                                return (
-                                    fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === filterLabel.toLowerCase() ?
-                                    <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
-                                    fragment
-                                )
-                            }
-                            )) : value
-                        }
-                    </span>
-                }
-                {
-                    this.state.inputRow !== index && <Icon style={{ cursor: 'pointer' }} type='edit' onClick={() => {
-                        this.setState({
-                            inputRow: index
-                        });
-                    }} />
-                }
-            </div>,
-            width: 150
-        }, {
-            title: '行开放策略',
-            dataIndex: 'filters',
-            render: filter => <div>
-                {filter.length > 0 ? filter.map((f) =>
-                    <Tag
-                        className='filter-tag'
-                        key={f.code}
-                        closable={false}
-                    >
-                        {this.createFilterLabel(f)}
-                    </Tag>
-                ) : <Tag className='filter-tag' closable={false}>所有数据</Tag>}
-                <Tag
-                    onClick={this.showPolicyRuleBox}
-                    className={`filter-tag filter-tag-add`}
-                >
-                    <Icon type="filter" />
-                </Tag>
-            </div>,
-            width: 500
-        }, {
-            title: '开放对象',
-            dataIndex: 'targets',
-            render: targets => <div>
-                {
-                    targets.map((item, index) => <Tag key={index}>{item.isGroup ? <Icon type='group' /> : <Icon type='geren' />}{item.name}</Tag>)
-                }
-                <Tag onClick={this.showAccessObjectBox}><Icon type="plus" /></Tag>
-            </div>,
-            width: 300
-        }, {
-            title: '操作',
-            render: (v,r) => <div><span style={{ cursor: 'pointer' }} onClick={() => {
-                dispatch({ type: 'dashboardPolicy/remoteDelete', code: r.code });
-            }}>删除</span></div>,
-            width: 120
-        }];
-        
-        return (
-            <Modal
-                width={1200}
-                className='distribute-box'
-                title='图表分发策略'
-                visible={visibleDistributeBox}
-                onOk={this.okHandler}
-                onCancel={hideBox}
-                maskClosable={false}
-                destroyOnClose={true}
-            >
-                <Layout className='chart-policy'>
-                    <Content>
-                        <Card className='policy-body' title={
-                            <Row className='policy-tools' type='flex' justify='end'>
-                                <Col className='search'>
-                                    <Search
-                                        placeholder="请输入关键字"
-                                        onChange={e => {
-                                        }}
-                                    />
-                                    <Button className='add-btn' onClick={() => {
-                                        dispatch({ type: 'dashboardPolicy/remoteAdd', policy: {
-                                            code: Math.random(),
-                                            anabled: false,
-                                            name: '新策略',
-                                            targets: [],
-                                            filters: []
-                                        }, chartCode });
-                                    }}>
-                                        添加策略
-                                    </Button>
-                                </Col>
-                            </Row>
-                        }>
-                            <Table
-                                className='policy-table'
-                                columns={columns}
-                                dataSource={polices ? polices.filter(l => {
-                                    let reg = new RegExp('(' + filterLabel + '){1}', 'ig');
-                                    return (l.name || '').search(reg) !== -1;
-                                }).map((p, i) => ({ ...p, key: i })) : []}
-                                size='small'
-                                onRow={(record) => {
-                                    return {
-                                        onClick: () => {this.setState({ currentPolicy:  record})}
-                                    }
-                                }}
-                            />
-                        </Card>
-                        <FilterBox key={Math.random()} columns={[]} filterData={currentPolicy ? currentPolicy.filters : []} visibleFilterBox={visiblePolicyRuleBox} hideFilterBox={this.hidePolicyRuleBox} createFilters={this.createFilters} />
-                        <AccessObjectBox key={Math.random()} visibleBox={visibleAccessObjectBox} hideBox={this.hideAccessObjectBox} okHandler={this.setAccessObject} group={group} geren={geren} />
-                    </Content>
-                </Layout>
-            </Modal>
-        )
-
-    }
-    
-}
-
-function mapStateToProps({ present: { dashboardPolicy } }) {
-    return { dashboardPolicy };
-}
-
-export default connect(mapStateToProps)(DistributeBox)

+ 0 - 23
src/components/dashboard/distributeBox.less

@@ -1,23 +0,0 @@
-.distribute-box {
-    .ant-modal-body {
-        padding: 0;
-        .ant-card-head {
-            .ant-card-head-title {
-                padding: 8px 0;
-                .policy-tools {
-                    .search {
-                        .ant-input-search {
-                            width: auto;
-                        }
-                        .add-btn {
-                            margin-left: 5px;
-                        }
-                    }
-                }
-            }
-        }
-        .ant-card-body {
-            padding: 0;
-        }
-    }
-}

+ 13 - 3
src/components/dashboard/list.jsx

@@ -62,7 +62,6 @@ class DashboardList extends React.Component {
             <Menu className='menu-operation'>
                 <Menu.Item
                     onClick={(e) => {
-                        this.setState({ visibleDeleteBox: true})
                     }}
                 >
                     <Icon type="delete" />分享
@@ -175,8 +174,19 @@ class DashboardList extends React.Component {
         });
     }
 
-    distribute = (groups, gerens) => {
-        console.log(groups, gerens);
+    distribute = (group, geren) => {
+        const { dispatch } = this.props;
+        const { selectedRecord } = this.state;
+        let targets = group.map(g => ({
+            code: g.code,
+            name: g.name,
+            isGroup: true
+        })).concat(geren.map(g => ({
+            code: g.code,
+            name: g.name,
+            isGroup: false
+        })))
+        dispatch({ type: 'dashboard/share', code: selectedRecord.code, targets });
     }
 
     render() {

+ 74 - 49
src/components/dashboardDesigner/chartView.jsx

@@ -1,59 +1,84 @@
 import React from 'react'
 import Echarts from 'echarts-for-react'
-import { connect } from 'dva'
-import { Table } from 'antd'
-import resolveChartOption from '../chart/resolveChartOption.js'
+import { Table, Spin, Icon } from 'antd'
 import RichTextEditor from './richTextEditor'
+import { connect } from 'dva'
+import resolveChartOption from '../chart/resolveChartOption'
+import { hashcode } from '../../utils/baseUtils'
+
+class ChartView extends React.Component {
+    
+    constructor(props) {
+        super(props);
+        this.state = {
+            fetching: false,
+            chartOption: {
+                showLoading: true
+            }, // 图表详细数据
+        }
+    }
 
-const ChartView = ({ item, tableBodyHeight, chart, editMode, dispatch }) => {
-    const { viewType, chartCode, content } = item;
-    let children = <div className='chart-default mover'></div>;
+    componentDidMount() {
+        const { item, dispatch } = this.props;
+        const { viewType } = item;
+        if(viewType === 'chart') {
+            dispatch({ type: 'dashboardDesigner/fetchChartData', item });
+        }
+    }
 
-    if(viewType === 'chart') { // 图表类型
-        let targetChart = chart.list.filter(c => c.code === chartCode)[0];
-        if(targetChart) {
-            let option = resolveChartOption(targetChart ? targetChart.chartOption : {}, {}, editMode);
-            let type = ['bar', 'line', 'pie', 'scatter'].indexOf(targetChart.type) !== -1 ? 'echarts' :
-                (['aggregateTable', 'dataView'].indexOf(targetChart.type) !== -1 ? 'table' : 'default');
-            if(type === 'echarts') {
-                children = <Echarts
-                    key={chartCode}
-                    option={option}
-                    className='rc-echarts mover'
-                    style={{height: '100%'}}
-                />
-            }else if(type === 'table') {
-                const { columns, data } = option;
-                const tableRowHeight = 38;
-                children = <Table
-                    className='dashboard-table'
-                    size='small'
-                    scroll={{
-                        x: columns ? columns.length * 200 : 0,
-                        y: tableBodyHeight,
-                    }}
-                    pagination={{ defaultPageSize: Math.floor(tableBodyHeight/tableRowHeight) || 10 }}
-                    columns={columns ? columns.map(c => ({
-                        ...c,
-                        width: 200
-                    })) : []}
-                    dataSource={data}
-                />
+    render() {
+        const { item, tableBodyHeight, editMode, dispatch } = this.props;
+        const { viewType, chartType, content, chartOption, fetching } = item;
+        let children = <div className='chart-default mover'></div>;
+        
+        if(viewType === 'chart') { // 图表类型
+            if(chartOption) {
+                let newOption = resolveChartOption(chartOption, editMode, false);
+                let type = ['bar', 'line', 'pie', 'scatter'].indexOf(chartType) !== -1 ? 'echarts' :
+                    (['aggregateTable', 'dataView'].indexOf(chartType) !== -1 ? 'table' : 'default');
+                if(type === 'echarts') {
+                    children = <Echarts
+                        key={hashcode(chartOption)}
+                        option={newOption}
+                        className='rc-echarts mover'
+                        style={{height: '100%'}}
+                    />
+                }else if(type === 'table') {
+                    const { columns, dataSource } = chartOption;
+                    const tableRowHeight = 38;
+                    children = <Table
+                        className='dashboard-table'
+                        size='small'
+                        scroll={{
+                            x: columns ? columns.length * 200 : 0,
+                            y: tableBodyHeight,
+                        }}
+                        pagination={{ defaultPageSize: Math.floor(tableBodyHeight/tableRowHeight) || 10 }}
+                        columns={columns ? columns.map(c => ({
+                            ...c,
+                            width: 200
+                        })) : []}
+                        dataSource={dataSource}
+                    />
+                }
             }
+        }else if(viewType === 'richText') { // 富文本类型
+            children = <RichTextEditor content={content} onContentChange={(content) => {
+                dispatch({ type: 'dashboardDesigner/modifyItem', fields: { code: item.code, content } });
+            }}/>
+        }else {
+            children = <div className='mover'>错误类型</div>
         }
-    }else if(viewType === 'richText') { // 富文本类型
-        children = <RichTextEditor content={content} onContentChange={(content) => {
-            dispatch({ type: 'dashboardDesigner/modifyItem', fields: { code: item.code, content } });
-        }}/>
-    }else {
-        children = <div className='mover'>错误类型</div>
+    
+        return (
+            <div className='chartview-content' style={{ width: '100%', height: '100%' }}>
+                { children }
+                { fetching && <div style={{ display: fetching ? 'block' : 'none', position: 'absolute', height: '100%', width: '100%', zIndex: '4', background: 'rgba(51,51,51,.1)', top: 0 }}>
+                    <Spin style={{ display: 'inline-block', position: 'absolute', top: '50%', left: '50%', margin: '-10px' }} indicator={<Icon type="loading" style={{ fontSize: 24 }} spin />} />
+                </div> }
+            </div>
+        );
     }
-
-    return (
-        <div className='chartview-content' style={{ width: '100%', height: '100%' }}>
-            {children}
-        </div>
-    );
 }
 
-export default connect(({ present: { chart } }) => ({ chart }))(ChartView);
+export default connect(({ present: { dashboardDesigner } }) => ({ dashboardDesigner }))(ChartView);

+ 4 - 4
src/components/dashboardDesigner/chooseChartBox.jsx

@@ -66,7 +66,7 @@ class ChooseChartBox extends React.Component {
     }
 
     render() {
-        const { visibleBox, hideBox, dashboardDesigner, chart } = this.props;
+        const { main, visibleBox, hideBox, dashboardDesigner, chart } = this.props;
         const { selectedRecord, screenWidth, screenHeight } = this.state;
         const tableBodyWidth = screenWidth * 0.8 - 10 - 10 - 18;
         const tableBodyHeight = screenHeight * 0.8 - 65 - 53 - 38 - 130;
@@ -171,7 +171,7 @@ class ChooseChartBox extends React.Component {
                         ...c,
                         width: 100
                     }))}
-                    dataSource={chart.list.map((l, i) => ({ ...l, key: i})).filter(l => {
+                    dataSource={chart.list.filter(l => l.creatorCode === main.currentUser.code).map((l, i) => ({ ...l, key: i})).filter(l => {
                         let regLabel = new RegExp('(' + filterLabel + '){1}', 'ig');
                         return (l.name || '').search(regLabel) !== -1 || (l.description || '').search(regLabel) !== -1;
                     })}
@@ -200,8 +200,8 @@ class ChooseChartBox extends React.Component {
 
 
 
-function mapStateToProps({ present: { dashboardDesigner, chart } }) {
-    return { dashboardDesigner, chart };
+function mapStateToProps({ present: { main, dashboardDesigner, chart } }) {
+    return { main, dashboardDesigner, chart };
 }
 
 export default connect(mapStateToProps)(ChooseChartBox)

+ 10 - 1
src/components/dashboardDesigner/configForm.jsx

@@ -1,6 +1,6 @@
 import React from 'react'
 import { connect } from 'dva'
-import { Form, Input, Divider, Button, Icon, Collapse, Spin, Select, Checkbox } from 'antd'
+import { Form, Input, Divider, Button, Icon, Collapse, Spin } from 'antd'
 const { TextArea } = Input;
 
 // const ConfigForm = ({ dashboardDesigner, dispatch }) => {
@@ -16,6 +16,15 @@ class ConfigForm extends React.Component {
         };
     }
 
+    componentDidMount() {
+        const { reset, dispatch } = this.props;
+        dispatch({ type: 'dashboardDesigner/silentSetField', name: 'loading', value: true });
+        window.setTimeout(() => {
+            reset(true);
+            dispatch({ type: 'dashboardDesigner/silentSetField', name: 'loading', value: false });
+        }, 900);
+    }
+
     addRelationColumn = () => {
         const { dispatch } = this.props;
         dispatch({ type: 'dashboardDesigner/addRelationColumn' });

+ 16 - 21
src/components/dashboardDesigner/content.jsx

@@ -1,6 +1,6 @@
 import React from 'react'
 import { findDOMNode } from 'react-dom'
-import { Layout, Tooltip, Button, Tag, Dropdown, Menu, Icon } from 'antd'
+import { Layout, Tooltip, Tag, Icon } from 'antd'
 import { connect } from 'dva'
 import ViewLayout from './viewLayout'
 import ChooseChartBox from './chooseChartBox'
@@ -24,16 +24,15 @@ class DashboardDesignerContent extends React.Component {
     }
 
     componentDidMount() {
-        this.refreshContentSize(true);
-        this.addResizeListener();
-    }
-
-    addResizeListener = () => {
         window.addEventListener("resize", () => {
             this.refreshContentSize(true);
         });
     }
 
+    componentWillUnmount() {
+        window.removeEventListener('resize', this.onWindowResize);
+    }
+
     showBox = (o) => {
         this.setState({
             visibleChooseChartBox: true
@@ -63,7 +62,9 @@ class DashboardDesignerContent extends React.Component {
      */
     refreshContentSize = (flag) => {
         let contentEl = findDOMNode(this.refs.contentEl);
-        if(!contentEl) { return; }
+        if(!contentEl) {
+            return; 
+        }
         let _scroll = contentEl.scrollHeight > contentEl.clientHeight;
 
         if(!flag && this.state.contentSize.scroll === _scroll) { // 如果滚动条没有变化则直接退出
@@ -90,7 +91,8 @@ class DashboardDesignerContent extends React.Component {
 
     createFilters = (filters) => {
         const { dispatch } = this.props;
-        dispatch({ type: 'dashboardDesigner/setField', name: 'filters', value: filters });
+        // dispatch({ type: 'dashboardDesigner/silentSetField', name: 'filters', value: filters });
+        dispatch({ type: 'dashboardDesigner/changeFilters', filters });
         this.hideFilterBox()
     }
 
@@ -142,7 +144,7 @@ class DashboardDesignerContent extends React.Component {
         const key = e.target.dataset.key;
         const { dashboardDesigner, dispatch } = this.props;
         const filters = dashboardDesigner.filters;
-        dispatch({ type: 'dashboardDesigner/setField', name: 'filters', value: filters.map( f => {
+        dispatch({ type: 'dashboardDesigner/silentSetField', name: 'filters', value: filters.map( f => {
             if(+f.key === +key) {
                 f = { ...f, using: f.type ? !f.using : false}
             }
@@ -150,15 +152,8 @@ class DashboardDesignerContent extends React.Component {
         }) });
     }
 
-    isOwner = () => {
-        const { dashboardDesigner, main } = this.props;
-        const { creatorCode } = dashboardDesigner;
-        const { currentUser } = main;
-        return currentUser.code === creatorCode;
-    }
-
     render() {
-        const { dashboardDesigner, dispatch } = this.props;
+        const { dashboardDesigner, dispatch, isOwner } = this.props;
         const { code, editMode, filters } = dashboardDesigner;
         const { contentSize, visibleChooseChartBox, visibleFilterBox } = this.state;
 
@@ -193,7 +188,7 @@ class DashboardDesignerContent extends React.Component {
                         </Tag>
                     </div>
                     {visibleFilterBox && <FilterBox type='dashboard' code={code} columns={this.getRelationFilterColumns()} filterData={filters} visibleFilterBox={visibleFilterBox} showFilterBox={this.showFilterBox} hideFilterBox={this.hideFilterBox} createFilters={this.createFilters} />}
-                {this.isOwner() && <div className='viewtype'>
+                {isOwner && <div className='viewtype'>
                     <Tooltip title="图表">
                         <Icon className='viewtype-icon' type="area-chart" theme="outlined" onClick={(item) => {
                             this.showBox("create");
@@ -212,8 +207,8 @@ class DashboardDesignerContent extends React.Component {
                     <Content className='viewlayout' ref='contentEl'>
                         <ViewLayout contentSize={contentSize} reset={this.refreshContentSize} editMode={editMode}/>
                     </Content>
-                    <Sider className='config-sider' width={this.isOwner() && editMode ? 380 : 0}>
-                        <ConfigForm />
+                    <Sider className='config-sider' width={(isOwner && editMode) ? 380 : 0}>
+                        <ConfigForm reset={this.refreshContentSize}/>
                     </Sider>
                 </Layout>
             </Content>
@@ -221,4 +216,4 @@ class DashboardDesignerContent extends React.Component {
     }
 }
 
-export default connect(({ present: { main, dashboardDesigner } }) => ({ main, dashboardDesigner }))(DashboardDesignerContent);
+export default connect(({ present: { dashboardDesigner } }) => ({ dashboardDesigner }))(DashboardDesignerContent);

+ 2 - 1
src/components/dashboardDesigner/header.jsx

@@ -2,7 +2,6 @@ import React from 'react'
 import { Input, Icon, Button, Popconfirm, Switch } from 'antd'
 import { connect } from 'dva'
 import './header.less'
-import SettingBox from './settingBox';
 
 class Header extends React.Component {
     constructor(props) {
@@ -59,6 +58,7 @@ class Header extends React.Component {
                         <Button onClick={() => {
                             console.log(dashboardDesigner.dirty);
                             if(!dashboardDesigner.dirty) {
+                                dispatch({ type: 'dashboardDesigner/reset' });
                                 dispatch({ type: 'main/goBack', path: '/chart' });
                             }
                         }}>
@@ -66,6 +66,7 @@ class Header extends React.Component {
                         </Button>
                     </Popconfirm>}
                     {!this.isOwner() && <Button onClick={(e) => {
+                        dispatch({ type: 'dashboardDesigner/reset' });
                         dispatch({ type: 'main/goBack', path: '/chart' });
                     }}>
                         <Icon type='left' />返回

+ 17 - 5
src/components/dashboardDesigner/layout.jsx

@@ -11,10 +11,14 @@ const { Header, Content } = Layout
 
 class DashboardDesigner extends React.Component {
 
+    constructor(props) {
+        super(props);
+        props.dispatch({ type: 'dashboardDesigner/reset' });
+    }
+
     componentDidMount() {
         const { dispatch } = this.props;
         const { code } = this.props.match.params;
-        dispatch({ type: 'dashboardDesigner/reset' });
         dispatch({ type: 'chart/fetchList' });
         if (code !== 'create') {
             dispatch({ type: 'dashboard/remoteDetail', code: code });
@@ -36,14 +40,22 @@ class DashboardDesigner extends React.Component {
         });
     }
 
+    isOwner = () => {
+        const { dashboardDesigner, main } = this.props;
+        const { creatorCode } = dashboardDesigner;
+        const { currentUser } = main;
+        return currentUser.code === creatorCode;
+    }
+
     render() {
-        const { loading } = this.props;
+        const { dashboardDesigner } = this.props;
+        const { loading } = dashboardDesigner;
         return <Layout className='dashboarddesigner-layout'>
             <Header>
                 <DashboardDesignerHeader updateThumbnail={this.updateThumbnail} />
             </Header>
             <Content style={{ height: 0 }}>
-                <DashboardDesignerContent />
+                <DashboardDesignerContent isOwner={this.isOwner()} />
             </Content>
             <div style={{ display: loading ? 'block' : 'none', position: 'absolute', height: '100%', width: '100%', zIndex: '4', background: 'rgba(51,51,51,.1)' }}>
                 <Spin style={{ display: 'inline-block', position: 'absolute', top: '50%', left: '50%', margin: '-10px' }} indicator={<Icon type="loading" style={{ fontSize: 24 }} spin />} />
@@ -54,8 +66,8 @@ class DashboardDesigner extends React.Component {
 }
 
 function mapStateToProps(state) {
-    let loading = state.present.loading.models.dashboard;
-    return { loading }
+    const { main, dashboardDesigner } = state.present;
+    return { main, dashboardDesigner }
 }
 
 export default connect(mapStateToProps)(DashboardDesigner)

+ 0 - 56
src/components/dashboardDesigner/settingBox.jsx

@@ -1,56 +0,0 @@
-import React from 'react'
-import { Modal, Tabs, Row, Col, Form } from 'antd'
-const TabPane = Tabs.TabPane;
-
-const parameter = [
-    {
-        label: '部门',
-        type: '字符串',
-        operator: '等于',
-        value1: '销售',
-        nullable: true
-    },{
-        label: '业务员',
-        type: '字符串',
-        operator: '等于',
-        value1: '销售',
-        nullable: false
-    }
-]
-/**
- * 用于设定看板的属性,重点在于公共参数(parameter)配置的界面,以上为暂定字段
- *
- * @class SettingBox
- * @extends {React.Component}
- */
-
-
- 
-class SettingBox extends React.Component {
-    render() {
-        const { visibleSettingBox, hideBox } = this.props
-
-        return (
-            <Modal 
-                visible={visibleSettingBox}
-                onCancel={hideBox}
-                // onOk={() => {onOk();hideBox();}}
-                destroyOnClose={true}
-            >
-                <div>
-                    <Tabs tabPosition='left'>
-                        <TabPane tab="basic" key="1">Content of Tab 1</TabPane>
-                        <TabPane tab="publicParameter" key="2">
-                            <Row>
-                                <Col>
-                                </Col>
-                            </Row>
-                        </TabPane>
-                    </Tabs>
-                </div>
-            </Modal>
-        )
-    }
-}
-
-export default SettingBox

+ 10 - 6
src/components/dashboardDesigner/viewLayout.jsx

@@ -35,21 +35,27 @@ class ViewLayout extends React.PureComponent {
         const { currentUser } = main;
         const { editMode } = dashboardDesigner;
         const { code, name, viewType, layout, chartCode, filters } = item;
+
+        let usingFilters = filters ? ( filters.length > 0 ? ( filters.filter(f => f.using === true) ) : [] ) : [];
+
         return (
-            <div className={`chartview${editMode ? ' chartview-edit' : ''}`} key={code} data-grid={layout}>
+            <div className={`chartview${ isPreview ? ' chartview-preview' : (editMode ? ' chartview-edit' : '')}`} key={code} data-grid={layout}>
                 <div className='chartview-toolbar mover'>
                     <div className='chart-title'><span>{name}</span></div>
                     <div className='chart-tools'>
-                        {viewType !== 'richText' && !!filters && filters.length > 0 && <Tooltip title={'默认过滤条件: 【' + filters.map((f, i) => f.filterLabel).join(',') + '】'}>
+                        {viewType !== 'richText' && usingFilters.length > 0 && <Tooltip title={'默认过滤条件: 【' + usingFilters.map((f, i) => f.filterLabel).join(',') + '】'}>
                             <Icon className='visible-icon' type="info-circle" theme="outlined" />
                         </Tooltip>}
+                        {<Icon type="reload" theme="outlined" onClick={() => {
+                            dispatch({ type: 'dashboardDesigner/fetchChartData', item, mandatory: true });
+                        }}/>}
                         {!isPreview && viewType !== 'richText' && <Icon type="arrows-alt" onClick={() => this.showPreviewBox(item)}/>}
                         {editMode && item.creatorCode === currentUser.code && viewType !== 'richText' &&  <Icon type='edit' onClick={() => {
                             dispatch({ type: 'dashboard/remoteModify' });
                             dispatch({ type: 'chartDesigner/reset' });
                             dispatch({ type: 'main/redirect', path: '/chart/' + chartCode });
                         }}/>}
-                        {!isPreview && editMode && item.creatorCode === currentUser.code && <Icon type='delete' onClick={() => {
+                        {!isPreview && editMode && <Icon type='delete' onClick={() => {
                             dispatch({ type: 'dashboardDesigner/deleteItem', item });
                         }} />}
                         {isPreview && <Icon type="close" onClick={this.hidePreviewBox}/>}
@@ -63,9 +69,7 @@ class ViewLayout extends React.PureComponent {
     onLayoutChange = (layout) => {
         const { dispatch, reset } = this.props;
         dispatch({ type: 'dashboardDesigner/changeLayout', layout });
-        setTimeout(() => {
-            reset();
-        }, 500)
+        reset();
     }
 
     onResize = () => {

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

@@ -106,7 +106,7 @@
     }
     .chartview-content {
       canvas {
-        cursor: move;
+        // cursor: move;
       }
       .richtexteditor {
         .w-e-text-container {

+ 4 - 0
src/constants/url.js

@@ -94,6 +94,8 @@ const URLS = {
 
     CHART_DETAIL: BASE_URL + '/getChartsConfig', // 获得单个图表详细数据
 
+    CHART_OPTION: BASE_URL + '/showChartsInDash', // 请求图表展示数据(已定义好的图表)
+
     CHART_BAR_OPTION: BASE_URL + '/showHistogram', // 请求柱状图展示数据
 
     CHART_PIE_OPTION: BASE_URL + '/showPie', // 请求饼图展示数据
@@ -160,6 +162,8 @@ const URLS = {
 
     DASHBOARD_UPDATE: BASE_URL + '/updateDashboards', // 更新看板
 
+    DASHBOARD_SHARE: BASE_URL + '/addObject', // 看板分发
+
     DASHBOARD_TRANSFER: BASE_URL + '/changeDashOrder', // 看板移交
 }
 export default URLS

+ 0 - 2
src/index.js

@@ -12,7 +12,6 @@ import userGroup from './models/userGroup'
 import user from './models/user'
 import chartPolicy from './models/chartPolicy'
 import dataSourcePolicy from './models/dataSourcePolicy'
-import dashboardPolicy from './models/dashboardPolicy'
 import dataList from './models/dataList'
 import './utils/baseUtils'
 import './index.less'
@@ -44,7 +43,6 @@ app.model(userGroup); // 用户组
 app.model(user); // 用户
 app.model(chartPolicy); // 图表策略
 app.model(dataSourcePolicy); // 数据源策略
-app.model(dashboardPolicy); // 看板策略
 app.model(dataList); // 数据列表
 
 // 4. Router

+ 1 - 9
src/models/chart.js

@@ -155,7 +155,6 @@ export default {
                             chartOption: chartOption
                         }
                     })
-                    console.log('请求图表列表', list);
                     yield put({ type: 'list', list: list });
                 }else {
                     message.error('请求图表列表失败: ' + (res.err || res.data.msg));
@@ -249,7 +248,6 @@ export default {
                             value: data[key]
                         })
                     }
-                    console.log(fields);
                     yield put({ type: 'chartDesigner/defaultChangeFields', fields: fields });
                     
                     yield put({ type: 'chartDesigner/changeDataSource', code: data.baseConfig.dataSource.code });
@@ -269,7 +267,6 @@ export default {
                 let body = {
                     chartName: header.label,
                     dataId: baseConfig.dataSource.code,
-                    createBy: 'zhuth',
                     describes: description,
                     style: '',
                     otherConfig: JSON.stringify(otherConfig),
@@ -343,9 +340,8 @@ export default {
                     filters: JSON.stringify(filters),
                     chartName: header.label,
                     dataId: baseConfig.dataSource.code,
-                    createBy: 'zhuth',
                     describes: description || '',
-                    style: '',
+                    style: JSON.stringify(styleConfig),
                     otherConfig: JSON.stringify(otherConfig),
                     chartsGroup: group+'' ? group : '-1',
                     chartOption: JSON.stringify(chartOption),
@@ -480,14 +476,12 @@ export default {
                         fatherId: pgroup.code,
                         groupName: '新子分组',
                         groupIndex: cgroups.filter(c => c.pcode === pgroup.code).length,
-                        createBy: 'zhuth'
                     }
                 }else {
                     body = {
                         fatherId: '-1',
                         groupName: '新分组',
                         groupIndex: pgroups.length,
-                        createBy: 'zhuth'
                     }
                 }
                 const res = yield call(service.fetch, {
@@ -528,7 +522,6 @@ export default {
                     fatherId: group.pcode,
                     groupName: group.label,
                     groupIndex: group.index,
-                    createBy: 'zhuth'
                 }
                 const res = yield call(service.fetch, {
                     url: URLS.GROUP_CHART_UPDATE,
@@ -558,7 +551,6 @@ export default {
                         groupName: g.label,
                         groupIndex: g.index,
                         fatherId: g.pcode,
-                        createBy: 'zhuth'
                     }
                 });
                 const res = yield call(service.fetch, {

+ 16 - 123
src/models/chartDesigner.js

@@ -1,7 +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'
+import parseChartOption from './parseChartOption'
 import moment from 'moment'
 
 function getBodyFilters(filters) {
@@ -36,7 +36,7 @@ export default {
             code: null,
             creatorCode: null,
             creatorName: null,
-            header: { label: '标题' },
+            header: { label: '标题' },
             baseConfig: { dataSource: { }, viewType: '' },
             aggregateTableConfig: { targetColumn: {}, statistics: [], groupBy: [] },
             dataViewConfig: { viewColumns: [], sortColumn: {key: ''}, sortType: 'asc', count: 25 },
@@ -55,7 +55,7 @@ export default {
 			{ value: 'owner', name: '创建人' },
 			{ value: 'anyone', name: '所有人' }
         ],
-        header: { label: '标题' },
+        header: { label: '标题' },
         baseConfig: {
             dataSource: {},
             viewType: ''
@@ -190,7 +190,6 @@ export default {
                         columnName: baseConfig.groupBy.key,
                         columnRamane: baseConfig.groupBy.label
                     }] : [],
-                    createBy: 'zhuth',
                     describes: '',
                     style: JSON.stringify(styleConfig),
                     chartConfig: '{}',
@@ -227,7 +226,6 @@ export default {
                 let body = {
                     chartName: newHeaderLabel,
                     dataId: baseConfig.dataSource,
-                    createBy: 'zhuth',
                     describes: description || '',
                     style: JSON.stringify(styleConfig),
                     otherConfig: JSON.stringify(otherConfig),
@@ -402,20 +400,8 @@ export default {
                 });
                 console.log('请求柱状图数据', body, res);
                 if(!res.err && res.data.code > 0) {
-                    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',
-                        chartConfig: barConfig,
-                        option: {
-                            xAxis: res.data.data.xAxis,
-                            serieses: res.data.data.serieses,
-                            xTitle,
-                            yTitle,
-                        }
-                    }
-                    yield put({ type: 'silentSetField', name: 'chartOption', value: config });
+                    let option = parseChartOption('bar', res.data.data, barConfig);
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: option });
                 }else {
                     message.error('请求柱状图数据失败: ' + (res.err || res.data.msg));
                     yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
@@ -451,17 +437,8 @@ export default {
                 });
                 console.log('请求饼图数据', body, res);
                 if(!res.err && res.data.code > 0) {
-                    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 });
+                    let option = parseChartOption('pie', res.data.data, pieConfig);
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: option });
                 }else {
                     message.error('请求饼图数据失败: ' + (res.err || res.data.msg));
                     yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
@@ -496,19 +473,8 @@ export default {
                 });
                 console.log('请求折线图数据', body, res);
                 if(!res.err && res.data.code > 0) {
-                    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 });
+                    let option = parseChartOption('line', res.data.data, lineConfig);
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: option });
                 }else {
                     message.error('请求折线图数据失败: ' + (res.err || res.data.msg));
                     yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
@@ -543,19 +509,8 @@ export default {
                 });
                 console.log('请求散点图数据', body, res);
                 if(!res.err && res.data.code > 0) {
-                    res.viewType = 'scatter';
-                    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 });
+                    let option = parseChartOption('scatter', res.data.data, scatterConfig);
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: option });
                 }else {
                     message.error('请求散点图数据失败: ' + (res.err || res.data.msg));
                     yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
@@ -570,7 +525,7 @@ export default {
         *fetchDataViewData(action, { select, call, put }) {
             try {
                 const chartDesigner = yield select(state => state.present.chartDesigner);
-                const { code, dataViewConfig, filters, styleConfig } = chartDesigner;
+                const { code, dataViewConfig, filters } = chartDesigner;
                 const body = {
                     id: code,
                     columnListName: dataViewConfig.viewColumns.map(c => c.name),
@@ -585,20 +540,8 @@ export default {
                 });
                 console.log('请求表格数据', body, res);
                 if(!res.err && res.data.code > 0) {
-                    const resData = res.data.data;
-
-                    let columns = dataViewConfig.viewColumns;
-                    let dataSource = [];
-                    dataSource = resData;
-                    let config = {
-                        viewType: 'dataView',
-                        option: {
-                            columns: columns,
-                            data: dataSource,
-                            styleConfig,
-                        }
-                    }
-                    yield put({ type: 'silentSetField', name: 'chartOption', value: config });
+                    let option = parseChartOption('dataView', res.data.data, dataViewConfig);
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: option });
                 }else {
                     message.error('请求列表数据失败: ' + (res.err || res.data.msg));
                     yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
@@ -629,58 +572,8 @@ export default {
                 });
                 console.log('获得总体统计数据', body, res);
                 if(!res.err && res.data.code > 0) {
-                    const resData = res.data.data;
-
-                    let stypes = STATISTICS_OPTION.filter(o => statistics.indexOf(o.value) !== -1);
-
-                    let column = {
-                        title: '分析目标',
-                        dataIndex: 'targetColumn'
-                    };
-                    let data = { targetColumn: targetColumn.label };
-                    let columns = [column];
-                    let dataSource = [data]
-
-                    if(aggregateTableConfig.groupBy && aggregateTableConfig.groupBy.length > 0) {
-                        columns = columns.concat(aggregateTableConfig.groupBy.map(g => {
-                            return {
-                                title: g.label,
-                                dataIndex: g.key
-                            }
-                        })).concat(stypes.map(st => {
-                            return {
-                                title: st.label,
-                                dataIndex: st.value
-                            }
-                        }));
-                        dataSource = resData.map(d => {
-                            let obj = {};
-                            stypes.map(st => obj[st.value] = d[st.value.toUpperCase()]);
-                            aggregateTableConfig.groupBy.map(g => obj[g.key] = d[g.key])
-                            return { ...data, ...obj };
-                        });
-                    }else {
-                        columns = columns.concat(stypes.map(st => {
-                            dataSource = dataSource.map(d => {
-                                d[st.value] = resData[st.value.toUpperCase()]
-                                return d
-                            });
-                            return {
-                                title: st.label,
-                                dataIndex: st.value
-                            }
-                        }));
-                    }
-
-                    let config = {
-                        viewType: 'aggregateTable',
-                        option: {
-                            columns: columns,
-                            data: dataSource
-                        }
-                    }
-                    console.log(config);
-                    yield put({ type: 'silentSetField', name: 'chartOption', value: config });
+                    let option = parseChartOption('aggregateTable', res.data.data, aggregateTableConfig);
+                    yield put({ type: 'silentSetField', name: 'chartOption', value: option });
                 }else {
                     message.error('请求统计数据失败: ' + (res.err || res.data.msg));
                     yield put({ type: 'silentSetField', name: 'chartOption', value: {} });

+ 0 - 2
src/models/chartPolicy.js

@@ -137,7 +137,6 @@ export default {
                 name: policy.name,
                 rule: policy.filters.map(f => getBodyFilter(f)),
                 isOpen: policy.enabled ? '1' : '0',
-                createBy: 'zhuth'
             };
             try {
                 const res = yield call(service.fetch, {
@@ -170,7 +169,6 @@ export default {
                 name: policy.name,
                 rule: policy.filters.map(f => getBodyFilter(f)),
                 isOpen: policy.enabled ? '1' : '0',
-                createBy: 'zhuth'
             };
             try {
                 const res = yield call(service.fetch, {

+ 40 - 11
src/models/dashboard.js

@@ -75,6 +75,8 @@ export default {
                     const resData = res.data.data;
                     let items = resData.bdConfiguration ? JSON.parse(resData.bdConfiguration) : [];
                     let relationColumns = resData.relationColumns ? JSON.parse(resData.relationColumns) : [];
+                    const main = yield select(state => state.present.main);
+                    const { currentUser } = main;
 
                     let data = {
                         code:  resData.id+'',
@@ -85,8 +87,12 @@ export default {
                         creatorCode: resData.createId + '',
                         creatorName: resData.createBy,
                         createTime: resData.createDate,
-                        dataSources: [],
-                        relationColumns: relationColumns
+                        dataSources: items.map(item => ({
+                            code: item.dataSourceCode,
+                            name: item.dataSourceName
+                        })),
+                        relationColumns: relationColumns,
+                        editMode: currentUser.code === resData.createId + ''
                     }
 
                     let fields = [];
@@ -115,7 +121,6 @@ export default {
                     bdConfiguration: JSON.stringify(items),
                     thumbnail: thumbnail,
                     relationColumns: JSON.stringify(relationColumns),
-                    createBy: 'zhuth'
                 }
                 console.log('新增看板', body);
                 const res = yield call(service.fetch, {
@@ -137,13 +142,13 @@ export default {
         *remoteQucikAdd(action, { select, call, put }) {
             try {
                 const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
-                const { name } = dashboardDesigner;
+                const { name, items, thumbnail, description, relationColumns } = dashboardDesigner;
                 let body = {
                     bdName: name,
-                    bdNote: '',
-                    bdConfiguration: JSON.stringify([]),
-                    thumbnail: '',
-                    createBy: 'zhuth'
+                    bdNote: description,
+                    bdConfiguration: JSON.stringify(items),
+                    thumbnail: thumbnail,
+                    relationColumns: JSON.stringify(relationColumns)
                 }
                 console.log('快速新增看板', body);
                 const res = yield call(service.fetch, {
@@ -173,9 +178,7 @@ export default {
                     bdConfiguration: JSON.stringify(items),
                     thumbnail: thumbnail,
                     relationColumns: JSON.stringify(relationColumns),
-                    createBy: 'zhuth'
                 }
-                console.log('修改看板', body);
                 const res = yield call(service.fetch, {
                     url: URLS.DASHBOARD_UPDATE,
                     body: body
@@ -189,7 +192,7 @@ export default {
                     message.error('保存失败: ' + (res.err || res.data.msg));
                 } 
             }catch(e) {
-                console.log(e);
+                console.error(e);
                 message.error('保存失败');
             }
         },
@@ -220,6 +223,32 @@ export default {
                 message.error('删除失败');
             }
         },
+        *share(action, { put, call, select }) {
+            const { code, targets } = action;
+            const body = {
+                stId: code+'',
+                type: 'dashboard',
+                obj: targets.map(t => ({
+                    obId: t.code,
+                    objectType: t.isGroup ? '0' : '1'
+                }))
+            };
+            try {
+                const res = yield call(service.fetch, {
+                    url: URLS.DASHBOARD_SHARE,
+                    body
+                });
+                console.log('看板分发', body, res);
+                if(!res.err && res.data.code > 0) {
+                    message.success('分发成功');
+                }else {
+                    message.error('分发失败: ' + (res.err || res.data.msg));
+                }
+            }catch(e) {
+                console.log(body, e);
+                message.error('分发失败');
+            }
+        },
         *transfer(action, { put, call, select }) {
             const { userCode, dashboardCode } = action;
             const body = {

+ 177 - 63
src/models/dashboardDesigner.js

@@ -1,24 +1,59 @@
 import html2canvas from 'html2canvas'
 import { message } from 'antd'
 import * as service from '../services/index'
+import parseChartOption from './parseChartOption'
+import moment from 'moment'
 import URLS from '../constants/url'
 
-const getViewType = function(type) {
-    if(type === 'Histogram') {
-        return 'bar';
-    }else if(type === 'Line') {
-        return 'line';
-    }else if(type === 'Pie') {
-        return 'pie';
-    }else if(type === 'scatter') {
-        return 'scatter';
-    }else if(type === 'population') {
-        return 'aggregateTable';
-    }else if(type === 'individual') {
-        return 'dataView';
-    }else {
-        return '';
-    }
+/**
+ * 获得看板中图表的真实过滤规则
+ */
+function getTrueFilters(item, filters, relationColumns) {
+    let trueFilters = [];
+    filters.forEach(f => {
+        relationColumns.forEach(rc => {
+            if(f.name === rc.code) {
+                rc.relations.forEach(re => {
+                    if(re.dataSource.code === item.dataSourceCode) {
+                        trueFilters.push({
+                            name: re.column.name,
+                            operator: f.operator,
+                            type: re.column.type,
+                            value1: f.value1,
+                            value2: f.value2,
+                            using: f.using
+                        });
+                    }
+                });
+            }
+        });
+    });
+    return trueFilters;
+}
+
+function getBodyFilters(filters) {
+    return filters.filter(f => f.using).map(f => {
+        let { name, operator, type, value1, value2 } = f;
+        let bodyFilter = {
+            columnName: name,
+            columnType: type,
+            symbol: operator,
+            value: value1
+        };
+        if(type === 'scale' && operator === 'between') {
+            bodyFilter['value'] = value1 + ',' + value2;
+        }else if(type === 'time') {
+            let v1 = moment(value1).format('YYYY-MM-DD');
+            let v2 = moment(value2).format('YYYY-MM-DD');
+
+            if(operator === 'between') {
+                bodyFilter['value'] = v1 + ',' + v2;
+            }else {
+                bodyFilter['value'] = v1;
+            }
+        }
+        return bodyFilter;
+    }); 
 }
 
 export default {
@@ -26,7 +61,7 @@ export default {
     state: {
         originData: {
             code: null,
-            name: '标题',
+            name: '标题',
             items: [],
             description: '',
             thumbnail: '',
@@ -37,8 +72,9 @@ export default {
             dataSources: [],
             relationColumns: [],
             columnFetching: false,
+            loading: false,
         },
-        name: '标题',
+        name: '标题',
         defaultLayout: { x: 0, y: 50, w: 12, h: 6, minW: 2, maxW: 12, minH: 1 },
         items: [],
         description: '',
@@ -50,6 +86,7 @@ export default {
         dataSources: [], // 图表关联的所有数据源
         relationColumns: [], // 自定义的列
         columnFetching: false,
+        loading: false,
     },
     
     reducers: {
@@ -82,7 +119,7 @@ export default {
             return Object.assign({}, newState, {dirty: true});
         },
         addChart(state, action) {
-            let { items, defaultLayout } = state;
+            let { items, dataSources, defaultLayout } = state;
             const { chart } = action;
 
             items = items.concat([{
@@ -94,24 +131,40 @@ export default {
                 dataSourceCode: chart.dataSourceCode+'',
                 dataSourceName: chart.dataSourceName,
                 viewType: 'chart',
+                chartType: chart.type,
+                filters: chart.filters,
                 layout: defaultLayout,
             }]);
-            return Object.assign({}, state, {items, dirty: true});
+            dataSources.findIndex(d => d.code === chart.dataSourceCode+'') === -1 && dataSources.push({
+                code: chart.dataSourceCode+'',
+                name: chart.dataSourceName
+            });
+            return Object.assign({}, state, {items, dataSources, dirty: true});
         },
         addCharts(state, action) {
-            let { items, defaultLayout } = state;
+            let { items, dataSources, defaultLayout } = state;
             const { charts } = action;
 
-            items = items.concat(charts.map(c => ({
-                code: c.code,
-                chartCode: c.code,
-                name: c.name,
-                viewType: 'chart',
-                dataSourceCode: c.dataSourceCode+'',
-                dataSourceName: c.dataSourceName,
-                layout: defaultLayout,
-            })));
-            return Object.assign({}, state, {items, dirty: true});
+            items = items.concat(charts.map(c => {
+                dataSources.findIndex(d => d.code === c.dataSourceCode+'') === -1 && dataSources.push({
+                    code: c.dataSourceCode+'',
+                    name: c.dataSourceName
+                });
+                return {
+                    code: c.code,
+                    chartCode: c.code,
+                    name: c.name,
+                    creatorCode: c.creatorCode,
+                    creatorName: c.creatorName,
+                    viewType: 'chart',
+                    chartType: c.type,
+                    dataSourceCode: c.dataSourceCode+'',
+                    dataSourceName: c.dataSourceName,
+                    filters: c.filters,
+                    layout: defaultLayout,
+                }
+            }));
+            return Object.assign({}, state, {items, dataSources, dirty: true});
         },
         deleteItem(state, action) {
             let { items, dataSources, relationColumns, dirty } = state;
@@ -174,9 +227,11 @@ export default {
             }
             return Object.assign({}, state, {items, dirty});
         },
+        // 富文本用
         modifyItem(state, action) {
-            let { fields, dirty } = action;
+            let { fields } = action;
             let { items } = state;
+            let dirty = false;
             for(let i = 0; i < items.length; i++) {
                 if(items[i].code === fields.code) {
                     for(let k in fields) {
@@ -219,21 +274,25 @@ export default {
             relationColumns[index] = relationColumn;
             return { ...state, relationColumns, dirty: true };
         },
-        setChartFilters(state, action) {
-            let { items } = state;
-            const { chartCode, filters } = action;
-            let idx = items.findIndex(i => i.chartCode === chartCode);
-            if(idx !== -1) {
-                items[idx] = { ...items[idx], filters }
-            }
+        setItemFetching(state, action) {
+            const { code, fetching } = action
+            const { items } = state;
+            let index = items.findIndex(item => item.code === code);
+            items[index] = {
+                ...items[index],
+                fetching
+            };
             return { ...state, items };
         },
-        addDataSource(state, action) {
-            let { dataSources } = state;
-            const { dataSource } = action;
-            dataSources.findIndex(d => d.code === dataSource.code) === -1 && dataSources.push(dataSource);
-            console.log(dataSources);
-            return { ...state, dataSources };
+        setItemChartOption(state, action) {
+            const { code, chartOption } = action
+            const { items } = state;
+            let index = items.findIndex(item => item.code === code);
+            items[index] = {
+                ...items[index],
+                chartOption
+            };
+            return { ...state, items };
         }
     },
 
@@ -250,12 +309,12 @@ export default {
             
 
             try {
-                yield put({ type: 'silentSetField', field: 'columnFetching', value: true });
+                yield put({ type: 'silentSetField', field: 'loading', value: true });
                 const res = yield call(service.fetch, {
                     url: URLS.DATASOURCE_QUERY_DATACOLUMNS,
                     body: body
                 });
-                yield put({ type: 'silentSetField', field: 'columnFetching', value: false });
+                yield put({ type: 'silentSetField', field: 'loading', value: false });
                 console.log('获得列数据', body, res);
                 if(!res.err && res.data.code > 0) {
                     let resData = res.data.data;
@@ -284,24 +343,79 @@ export default {
                 message.error('请求列数据失败');
             }
         },
-        *saveWithThumbnail(action, {put, call}) {
-            let thumbnail;
-            yield call(async ()=> {
-                try {
-                    await html2canvas(document.getElementsByClassName('viewlayout')[0]).then(
-                        function(canvas){
-                            thumbnail = canvas.toDataURL('image/png', 1.0);
-                        }
-                    )
-                }catch (e) {
-                    return null;
+        *changeFilters(action, { put, call, select }) {
+            const { filters } = action;
+            const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
+            const { items, relationColumns } = dashboardDesigner;
+
+            // 找到filters影响的数据源id
+            let targetDataSource = [];
+            filters.forEach(f => {
+                relationColumns.forEach(rc => {
+                    if(f.name === rc.code) {
+                        let dataSource = rc.relations.map(re => re.dataSource);
+                        targetDataSource = dataSource;
+                    }
+                });
+            });
+            // 找到filters有影响的item
+            let targetItems = items.filter(item => !!targetDataSource.find(d => d.code === item.dataSourceCode));
+            yield put({ type: 'silentSetField', name: 'filters', value: filters });
+            
+            for(let i = 0; i < targetItems.length; i++) {
+                yield put({ type:'fetchChartData', item: targetItems[i], mandatory: true });
+            }
+        },
+        *fetchChartData(action, { put, call, select }) {
+            const { item, mandatory } = action;
+            const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
+            const { filters, relationColumns } = dashboardDesigner;
+            const { chartCode, chartType } = item;
+            const body = {
+                dashCreateId: chartCode,
+                filters: getBodyFilters(getTrueFilters(item, filters, relationColumns))
+            };
+            if(!mandatory && !!item.chartOption) {
+                return;
+            }
+
+            try {
+                yield put({ type: 'setItemFetching', code: chartCode, fetching: true });
+                const res = yield call(service.fetch, {
+                    url: URLS.CHART_OPTION,
+                    body
+                });
+                console.log('看板请求图表展示数据', body, res);
+                if(!res.err && res.data.code > 0) {
+                    let resData = res.data.data;
+                    let chartOption = parseChartOption(chartType, resData, JSON.parse(resData.chartsConfig));
+                    
+                    yield put({ type: 'setItemChartOption', code: chartCode, chartOption });
+                }else {
+                    yield put({ type: 'setItemChartOption', code: chartCode, chartOption: {} });
+                    console.error(body, res.err || res.data.msg);
+                    message.error('请求图表展示数据失败: ' + (res.err || res.data.msg));
                 }
-            }); 
+            }catch(e) {
+                console.error(body, e);
+                yield put({ type: 'setItemChartOption', code: chartCode, chartOption: {} });
+                message.error('请求图表展示数据失败');
+            }finally {
+                yield put({ type: 'setItemFetching', code: chartCode, fetching: false });
+            }
+        },
+        *saveWithThumbnail(action, {put, call}) {
             try {
-                yield put.resolve({ type: 'setField', name: 'thumbnail', value: thumbnail })
-                yield put.resolve({ type: 'dashboard/remoteModify' })
-            }catch (e){
-                message.error('保存失败');
+                let thumbnail;
+                yield put({ type: 'silentSetField', name: 'loading', value: true });
+                let canvas = yield html2canvas(document.getElementsByClassName('viewlayout')[0]);
+                thumbnail = canvas.toDataURL('image/png', 1.0);
+                yield put({ type: 'setField', name: 'thumbnail', value: thumbnail });
+                yield put({ type: 'dashboard/remoteModify' });
+                yield put({ type: 'silentSetField', name: 'loading', value: false });
+            }catch(e) {
+                console.log(e);
+                message.error('生成缩略图失败');
             }
         }
     },

+ 0 - 255
src/models/dashboardPolicy.js

@@ -1,255 +0,0 @@
-import { message } from 'antd'
-import * as service from '../services/index'
-import URLS from '../constants/url'
-import  moment from 'moment'
-
-function getBodyFilter(modelFilter) {
-    let { name, label, operator, operatorLabel, type, value1, value2 } = modelFilter;
-    let bodyFilter = {
-        columnName: name,
-        columnLabel: label,
-        columnType: type,
-        symbol: operator,
-        symbolLabel: operatorLabel,
-        value: value1
-    };
-    if(type === 'scale' && operator === 'between') {
-        bodyFilter['value'] = value1 + ',' + value2;
-    }else if(type === 'time') {
-        // let v1 = dateFormat(new Date(value1),'yyyy-MM-dd hh:mm:ss');
-        // let v2 = dateFormat(new Date(value2),'yyyy-MM-dd hh:mm:ss');
-
-        let v1 = moment(value1).format('YYYY-MM-DD HH:mm:ss');
-        let v2 = moment(value2).format('YYYY-MM-DD HH:mm:ss');
-
-        if(operator === 'between') {
-            bodyFilter['value'] = v1 + ',' + v2;
-        }else {
-            bodyFilter['value'] = v1;
-        }
-    }
-    return bodyFilter;
-}
-function getModelFilter(resFilter) {
-    let { columnName, columnLabel, columnType, symbol, symbolLabel, value } = resFilter;
-    let modelFilter = {
-        name: columnName,
-        label: columnLabel,
-        type: columnType,
-        operator: symbol,
-        operatorLabel: symbolLabel,
-        value1: value
-    };
-    if(columnType === 'scale' && symbol === 'between') {
-        modelFilter['value1'] = value.split(',')[0];
-        modelFilter['value2'] = value.split(',')[1];
-    }else if(columnType === 'time') {
-        let value1 = value.split(',')[0];
-        let value2 = value.split(',')[1];
-        let v1 = moment(value1);
-        let v2 = moment(value2);
-
-        if(symbol === 'between') {
-            modelFilter['value1'] = v1;
-            modelFilter['value2'] = v2;
-        }else {
-            modelFilter['value'] = v1;
-        }
-    }
-    return modelFilter;
-}
-
-export default {
-    namespace: 'dashboardPolicy',
-    state: {
-        chartCode: null,
-        columnData: [],
-        list: [{
-            code: '1',
-                    enabled: true,
-                    name: '开放策略1',
-                    targets: [],
-                    filters: []
-        }]
-    },
-    reducers: {
-        list(state, action) {
-            const { list } = action;
-            return { ...state, list };
-        },
-        modify(state, action) {
-            const { policy } = action;
-            let { list } = state;
-            for(let i = 0; i < list.length; i++) {
-                if(list[i].code === policy.code) {
-                    list[i] = policy;
-                    break;
-                }
-            }
-            return { ...state, list };
-        }
-    },
-    effects: {
-        *fetchList(action, { select, call, put }) {
-            const body = action.chartCode;
-            return;
-            try {
-                const res = yield call(service.fetch, {
-                    url: URLS.CHART_POLICY_LIST,
-                    body
-                });
-                console.log('请求图表策略列表', body, res);
-                if(!res.err && res.data.code > 0) {
-                    let list = (res.data.data && res.data.data.length > 0) ? res.data.data.sort((a, b) => new Date(a.createDate) - new Date(b.createDate)).map(d => ({
-                        code: d.strategies.id,
-                        enabled: d.strategies.isOpen+'' === '1',
-                        name: d.strategies.name,
-                        targets: d.userGroupName.map(g => ({
-                            code: g.ID+'',
-                            isGroup: true,
-                            name: g.NAME
-                        })).concat(d.userName.map(u => ({
-                            code: u.ID+'',
-                            isGroup: false,
-                            name: u.NAME
-                        }))),
-                        filters: d.strategies.ruleStr ? JSON.parse(d.strategies.ruleStr).map(f => getModelFilter(f)) : [],
-                    })) : [];
-                    yield put({ type: 'list', list });
-                }else {
-                    message.error('请求图表策略列表失败: ' + (res.err || res.data.msg));
-                }
-            }catch(e) {
-                console.log(body, e);
-                message.error('读取图表策略列表错误');
-            }
-        },
-        *remoteAdd(action, { put, call, select }) {
-            const chartPolicy = yield select(state => state.present.chartPolicy);
-            const { chartCode } = action;
-            const { policy } = action;
-            const body = {
-                type: 'chart',
-                tarId: chartCode,
-                name: policy.name,
-                rule: policy.filters.map(f => getBodyFilter(f)),
-                isOpen: policy.enabled ? '1' : '0',
-                createBy: 'zhuth'
-            };
-            return;
-            try {
-                const res = yield call(service.fetch, {
-                    url: URLS.CHART_POLICY_ADD,
-                    body,
-                });
-                console.log('添加策略', body, res);
-                if(!res.err && res.data.code > 0) {
-                    let { list } = chartPolicy;
-                    list.push({
-                        code: res.data.data,
-                        ...policy
-                    });
-                    yield put({ type: 'list', list });
-                }else {
-                    message.error('添加失败: ' + (res.err || res.data.msg));
-                }
-            }catch(e) {
-                console.log(body, e);
-                message.error('添加失败');
-            }
-        },
-        *remoteModify(action, { put, call, select }) {
-            const { policy, chartCode } = action;
-            console.log(chartCode);
-            const body = {
-                id: policy.code,
-                type: 'chart',
-                tarId: chartCode,
-                name: policy.name,
-                rule: policy.filters.map(f => getBodyFilter(f)),
-                isOpen: policy.enabled ? '1' : '0',
-                createBy: 'zhuth'
-            };
-            return;
-            try {
-                const res = yield call(service.fetch, {
-                    url: URLS.CHART_POLICY_UPDATE,
-                    body
-                });
-                console.log('修改图表策略', body, res);
-                if(!res.err && res.data.code > 0) {
-                    yield put({ type: 'modify', policy });
-                }else {
-                    message.error('修改失败: ' + (res.err || res.data.msg));
-                }
-            }catch(e) {
-                console.log(body, e);
-                message.error('修改失败');
-            }
-        },
-        *remoteDelete(action, { put, call, select }) {
-            const chartPolicy = yield select(state => state.present.chartPolicy);
-            const { code } = action;
-            const body = [code];
-            return;
-            try {
-                const res = yield call(service.fetch, {
-                    url: URLS.CHART_POLICY_DELETE,
-                    body
-                });
-                console.log('删除策略', body, res);
-                if(!res.err && res.data.code > 0) {
-                    let { list } = chartPolicy;
-                    for(let i = 0; i < list.length; i++) {
-                        if(list[i].code === code) {
-                            list.splice(i, 1);
-                            break;
-                        }
-                    }
-                    yield put({ type: 'list', list });
-                }else {
-                    message.error('删除失败: ' + (res.err || res.data.msg));
-                }
-            }catch(e) {
-                console.log(body, e);
-                message.error('删除失败');
-            }
-        },
-        *remoteSetTarget(action, { put, call, select }) {
-            const { policy, targets } = action;
-            const body = {
-                stId: policy.code+'',
-                type: 'chart',
-                obj: targets.map(t => ({
-                    obId: t.code,
-                    objectType: t.isGroup ? '0' : '1'
-                }))
-            };
-            return;
-            try {
-                const res = yield call(service.fetch, {
-                    url: URLS.CHART_POLICY_TARGET_UPDATE,
-                    body
-                });
-                console.log('设置策略对象', body, res);
-                if(!res.err && res.data.code > 0) {
-                    yield put({ type: 'modify', policy: {
-                        ...policy,
-                        targets
-                    } });
-                }else {
-                    message.error('设置对象失败: ' + (res.err || res.data.msg));
-                }
-            }catch(e) {
-                console.log(body, e);
-                message.error('设置对象失败');
-            }
-        }
-    },
-    subscriptions: {
-        setup({ dispatch, history }) {
-            return history.listen(({ pathname, query }) => {
-            })
-        }
-    }
-};

+ 0 - 4
src/models/dataSource.js

@@ -514,14 +514,12 @@ export default {
                         fatherId: pgroup.code,
                         groupName: '新子分组',
                         groupIndex: cgroups.filter(c => c.pcode === pgroup.code).length,
-                        createBy: 'zhuth'
                     }
                 }else {
                     body = {
                         fatherId: '-1',
                         groupName: '新分组',
                         groupIndex: pgroups.length,
-                        createBy: 'zhuth'
                     }
                 }
                 const res = yield call(service.fetch, {
@@ -562,7 +560,6 @@ export default {
                     fatherId: group.pcode,
                     groupName: group.label,
                     groupIndex: group.index,
-                    createBy: 'zhuth'
                 }
                 const res = yield call(service.fetch, {
                     url: URLS.GROUP_DATASOURCE_UPDATE,
@@ -592,7 +589,6 @@ export default {
                         groupName: g.label,
                         groupIndex: g.index,
                         fatherId: g.pcode,
-                        createBy: 'zhuth'
                     }
                 });
                 const res = yield call(service.fetch, {

+ 0 - 2
src/models/dataSourcePolicy.js

@@ -128,7 +128,6 @@ export default {
                 name: policy.name,
                 rule: policy.filters.map(f => getBodyFilter(f)),
                 isOpen: policy.enabled ? '1' : '0',
-                createBy: 'zhuth'
             };
             try {
                 const res = yield call(service.fetch, {
@@ -162,7 +161,6 @@ export default {
                 name: policy.name,
                 rule: policy.filters.map(f => getBodyFilter(f)),
                 isOpen: policy.enabled ? '1' : '0',
-                createBy: 'zhuth'
             };
             try {
                 const res = yield call(service.fetch, {

+ 303 - 0
src/models/parseChartOption.js

@@ -0,0 +1,303 @@
+/**
+ * 将请求返回的图表展示数据解析为前台展示用的config
+ */
+import STATISTICS_OPTION from '../components/chartDesigner/sections/statisticsOption.json'
+
+export default function(viewType, data, chartConfig) {
+    try {
+        let o;
+        switch(viewType) {
+            case 'bar': {
+                o = barOption(data, chartConfig);
+                break;
+            }
+            case 'pie': {
+                o = pieOption(data, chartConfig);
+                break;
+            }
+            case 'line': {
+                o = lineOption(data, chartConfig);
+                break;
+            }
+            case 'scatter': {
+                o = scatterOption(data, chartConfig);
+                break;
+            }
+            case 'aggregateTable': {
+                o = aggregateTableOption(data, chartConfig);
+                break;
+            }case 'dataView' : {
+                o = dataViewOption(data, chartConfig);
+                break;
+            }
+            default:{
+                o = {};
+                break;
+            }
+        }
+        return o;
+    }catch(e) {
+        console.error(e);
+    }
+}
+
+function barOption(data, barConfig) {
+    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 option = {
+        tooltip : {
+            trigger: "axis",
+            axisPointer: {
+                type: "cross",
+                label: {
+                    backgroundColor: "#6a7985"
+                }
+            }
+        },
+        legend: {
+            show: true
+        },
+        grid: {
+            left: '10%',
+            right: '10%',
+            top: 60,
+            bottom: 60,
+            containLabel: true
+        },
+        xAxis: [{
+            type: 'category',
+            data: data.xAxis,
+            name: xTitle || '横轴',
+        }],
+        yAxis: [{
+            name: yTitle || '纵轴',
+            type: 'value'
+        }],
+        series: data.serieses.map(s => {
+            return {
+                name: s.name,
+                type: 'bar',
+                data: s.value,
+                // stack: s.stack
+            }
+        }) 
+    }
+    
+    return option;
+}
+
+function pieOption(data, pieConfig) {
+    let columnName = pieConfig.xAxis.column.label + (pieConfig.xAxis.granularity.value ? '('+pieConfig.xAxis.granularity.label+')' : '');
+                    
+    let option = {
+        tooltip : {
+            trigger: 'item',
+            formatter: "{a} <br/>{b} : {c} ({d}%)"
+        },
+        legend: {
+            data: data.xAxis
+        },
+        grid: {
+            left: '10%',
+            right: '10%',
+            top: 60,
+            bottom: 60,
+            containLabel: true
+        },
+        series : [
+            {
+                name: columnName,
+                type: 'pie',
+                // radius : '55%',
+                // center: ['50%', '60%'],
+                data: (data.serieses || [])[0].value,
+                itemStyle: {
+                    emphasis: {
+                        shadowBlur: 10,
+                        shadowOffsetX: 0,
+                        shadowColor: 'rgba(0, 0, 0, 0.5)'
+                    }
+                }
+            }
+        ]
+    };
+
+    return option;
+}
+
+function lineOption(data, lineConfig) {
+    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 option = {
+        tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+                type: 'cross'
+            }
+        },
+        legend: {
+            show: true
+        },
+        xAxis:  {
+            name: xTitle || '横轴',
+            type: 'time'
+        },
+        yAxis: {
+            name: yTitle || '纵轴',
+            type: 'value'
+        },
+        
+        series: (data.serieses || []).map(s => {
+            return {
+                name: s.name,
+                type: 'line',
+                data: s.mdata.map(m => {
+                    return [m.date, m.value]
+                })
+            }
+        })
+    };
+
+    return option;
+}
+
+function scatterOption(data, scatterConfig) {
+    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 option = {
+        tooltip : {
+            showDelay : 0,
+            axisPointer:{
+                show: true,
+                type : 'cross',
+                lineStyle: {
+                    type : 'dashed',
+                    width : 1
+                }
+            }
+        },
+        legend: {
+            show: true
+        },
+        xAxis : [
+            {
+                type : 'value',
+                name: xTitle || '横轴',
+                scale:true,
+                splitLine: {
+                    show: false
+                }
+            }
+        ],
+        yAxis : [
+            {
+                type : 'value',
+                name: yTitle || '纵轴',
+                scale:true,
+                splitLine: {
+                    show: false
+                }
+            }
+        ],
+        series : (data.serieses || []).map(s => {
+            return {
+                name: s.name,
+                type: 'scatter',
+                data: s.mdata.map(m => {
+                    return [m.date, m.value]
+                })
+            }
+        })
+    };
+
+    return option;
+}
+
+function aggregateTableOption( data, aggregateTableConfig) {
+    const resData = data.valueList;
+    const { targetColumn, statistics } = aggregateTableConfig;
+    
+    let stypes = STATISTICS_OPTION.filter(o => statistics.indexOf(o.value) !== -1);
+
+    let column = {
+        title: '分析目标',
+        dataIndex: 'targetColumn'
+    };
+    let targetColumnData = { targetColumn: targetColumn.label };
+    let columns = [column];
+    let dataSource = [targetColumnData]
+
+    if(aggregateTableConfig.groupBy && aggregateTableConfig.groupBy.length > 0) {
+        columns = columns.concat(aggregateTableConfig.groupBy.map(g => {
+            return {
+                title: g.label,
+                dataIndex: g.key
+            }
+        })).concat(stypes.map(st => {
+            return {
+                title: st.label,
+                dataIndex: st.value
+            }
+        }));
+        dataSource = resData.map(d => {
+            let obj = {};
+            stypes.map(st => obj[st.value] = d[st.value.toUpperCase()]);
+            aggregateTableConfig.groupBy.map(g => obj[g.key] = d[g.key])
+            return { ...targetColumnData, ...obj };
+        });
+    }else {
+        columns = columns.concat(stypes.map(st => {
+            dataSource = dataSource.map(d => {
+                d[st.value] = resData[st.value.toUpperCase()]
+                return d
+            });
+            return {
+                title: st.label,
+                dataIndex: st.value
+            }
+        }));
+    }
+
+    let option = {
+        columns: columns.map(c => {
+            let _c = {
+                ...c, width: 200
+            };
+            if(_c.dataIndex === 'percent') {
+                return { ..._c, render: (value, record, index) => {
+                    return ((+value*100).toFixed(2)) + '%'}
+                };
+            }else {
+                return _c;
+            }
+        }),
+        dataSource: dataSource.map((d, i) => {
+            return { ...d, key: i}
+        })
+    };
+
+    return option;
+}
+
+function dataViewOption(data, dataViewConfig) {
+    const resData = data.valueList;
+
+    let columns = dataViewConfig.viewColumns || [];
+    let dataSource = resData || [];
+
+    let option = {
+        columns: columns.map(c => ({
+            title: c.label,
+            dataIndex: c.name,
+            width: 200
+        })),
+        dataSource: dataSource.map((d, i) => {
+            return { ...d, key: i}
+        })
+    };
+
+    return option;
+}

+ 0 - 1
src/utils/request.js

@@ -5,7 +5,6 @@ function parseJSON(response) {
 }
 
 function checkStatus(response) {
-  console.log(response);
   if (response.status >= 200 && response.status < 300) {
     return response;
   }