zhuth 6 years ago
parent
commit
5777376706

+ 34 - 311
src/components/chart/resolveChartOption.js

@@ -50,329 +50,52 @@ export default (option, silent, thumbnail) => {
         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' ) { // 柱状图
+    if(viewType ==='bar' || viewType === 'line') { // 柱状图
         _option.series = _option.series.map(s => ({
             ...s, showSymbol: !thumbnail, silent
         }));
+        // x轴
+        _option.xAxis ? (_option.xAxis.length > 0 ? (
+            _option.xAxis[0].axisLabel = {
+                ..._option.xAxis[0].axisLabel,
+                show: !thumbnail,
+            }
+        ) : (
+            _option.xAxis.axisLabel = {
+                ..._option.xAxis.axisLabel,
+                show: !thumbnail,
+            }
+        )) : _option.xAxis = {
+            axisLabel: {
+                show: !thumbnail,
+            } 
+        };
+        // y轴
+        _option.yAxis ? (_option.yAxis.length > 0 ? (
+            _option.yAxis[0].axisLabel = {
+                ..._option.yAxis[0].axisLabel,
+                show: !thumbnail,
+            }
+        ) : (
+            _option.yAxis.axisLabel = {
+                ..._option.yAxis.axisLabel,
+                show: !thumbnail,
+            }
+        )) : _option.yAxis = {
+            axisLabel: {
+                show: !thumbnail,
+            } 
+        };
     }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 _option;
-}
-
-// 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;
-// }
-
-// function pieConfig(option, styleConfig, silent, thumbnail) {
-
-//     const { xAxis, columnName, serieses } = 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;
-// }
-
-// 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
-//             }
-//         })
-//     };
-
-//     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 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;
-    
-//     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);
-//         }
-//     }
-    
-//     return data;
-// }
+}

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

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

+ 1 - 1
src/components/dashboard/layout.jsx

@@ -18,7 +18,7 @@ class DashboardLayout extends React.Component {
             className='layout-dashboard'
         >
             <Sider width={300}>
-                <DashboardMenu />
+                <DashboardMenu mode='manage'/>
             </Sider>
             <Content>
                 <DashboardList />

+ 61 - 33
src/components/dashboard/menu.jsx

@@ -23,18 +23,26 @@ class DashboardMenu extends React.Component {
     }
 
     generateMenu(tree, regLabel) {
-        const { dispatch } = this.props;
+        const { mode, dispatch } = this.props;
         const { editingKey } = this.state;
-        return tree.filter(t => t.type === 'menu').sort((a, b) => a.index - b.index).map(t => {
+        return tree.filter(t => (mode === 'view' || t.type === 'menu')).sort((a, b) => a.index - b.index).map(t => {
             let title = <div className='node-title'>
                 <span>{ (t.code !== editingKey) ?
-                   ( regLabel ? ((t.name || '').split(new RegExp(`(${regLabel})`, 'i')).map((fragment, i) => {
-                        return (
-                            fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'), '\\$1') === regLabel.toLowerCase() ?
-                            <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
-                            fragment
-                        )
-                    })) : <div className='label'>{t.name}</div> ) : ( <div className='input'>
+                   ( regLabel ? ( <span style={{ fontWeight: t.type === 'dashboard' ? 'bold' : 'normal' }}>
+                        { t.type === 'dashboard' && <Icon style={{ marginRight: '8px' }} type="pushpin" /> }
+                        { (t.name || '').split(new RegExp(`(${regLabel})`, 'i')).map((fragment, i) => {
+                            return (
+                                fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'), '\\$1') === regLabel.toLowerCase() ?
+                                <span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
+                                fragment
+                            )
+                        }) }                       
+                   </span> ) : <div className='label'>
+                        <span style={{ fontWeight: t.type === 'dashboard' ? 'bold' : 'normal' }}>
+                            { t.type === 'dashboard' && <Icon style={{ marginRight: '8px' }} type="pushpin" /> }
+                            { t.name }
+                        </span>
+                    </div> ) : ( <div className='input'>
                     <Input
                         size="small"
                         defaultValue={t.name}
@@ -55,7 +63,7 @@ class DashboardMenu extends React.Component {
                     />
                 </div> )
                 }</span>
-                <div className='tools'>
+                {mode !== 'view' && <div className='tools'>
                     {t.code !== editingKey && <Icon type='edit' onClick={() => {
                         this.setState({
                             editingKey: t.code
@@ -67,7 +75,7 @@ class DashboardMenu extends React.Component {
                             visibleDeleteBox: true,
                         });
                     }}/>}
-                </div>
+                </div>}
             </div>
 
             return <TreeNode title={title} key={t.code}>
@@ -82,21 +90,40 @@ class DashboardMenu extends React.Component {
     }
 
     onExpand = (keys) => {
-        const { dispatch } = this.props;
-        dispatch({ type: 'dashboard/setFields', fields: [
-            { name: 'menuExpandedKeys', value: keys },
-            { name: 'menuAutoExpandParent', value: false },
-        ] });
+        const { mode, dispatch } = this.props;
+        if(mode === 'view') {
+            dispatch({ type: 'home/setFields', fields: [
+                { name: 'menuExpandedKeys', value: keys },
+                { name: 'menuAutoExpandParent', value: false },
+            ] });
+        }else {
+            dispatch({ type: 'dashboard/setFields', fields: [
+                { name: 'menuExpandedKeys', value: keys },
+                { name: 'menuAutoExpandParent', value: false },
+            ] });
+        }
     }
 
     onSelect = (selectedKeys, info) => {
-        const { dispatch } = this.props;
-        dispatch({ type: 'dashboard/setField', name: 'menuSelectedKeys', value: selectedKeys })
-        if(selectedKeys.length === 1) {
-            if(selectedKeys[0] === '-1') {
-                dispatch({ type: 'dashboard/fetchList', mandatory: true });
-            }else {
-                dispatch({ type: 'dashboard/remoteMenuDashboardList', menuCode: selectedKeys[0] });
+        const { mode, dashboard, dispatch } = this.props;
+        const { menuList } = dashboard;
+        if(mode === 'view') {
+            // dispatch({ type: 'home/setField', name: 'menuSelectedKeys', value: selectedKeys })
+            let selectedMenu = menuList.find(l => l.code === selectedKeys[0]);
+            if(selectedMenu && selectedMenu.type === 'dashboard') {
+                dispatch({ type: 'home/openTab', tab: {
+                    code: selectedMenu.code,
+                    title: selectedMenu.name
+                } })
+            }
+        }else {
+            dispatch({ type: 'dashboard/setField', name: 'menuSelectedKeys', value: selectedKeys })
+            if(selectedKeys.length === 1) {
+                if(selectedKeys[0] === '-1') {
+                    dispatch({ type: 'dashboard/fetchList', mandatory: true });
+                }else {
+                    dispatch({ type: 'dashboard/remoteMenuDashboardList', menuCode: selectedKeys[0] });
+                }
             }
         }
     }
@@ -107,7 +134,7 @@ class DashboardMenu extends React.Component {
         dispatch({ type: 'dashboard/setFields', fields: [
             { name: 'menuExpandedKeys', value: expandedKeys },
             { name: 'menuFilterLabel', value },
-            { name: 'autoExpandParent', value: true },
+            { name: 'menuAutoExpandParent', value: true },
         ] });
     }
 
@@ -154,21 +181,22 @@ class DashboardMenu extends React.Component {
     }
 
     render() {
-        const { dashboard, dispatch, loading } = this.props;
+        const { mode, home, dashboard, dispatch, loading } = this.props;
         const { visibleDeleteBox, selectedMenu } = this.state;
-        const { menuTree, menuFilterLabel, menuExpandedKeys, menuSelectedKeys, menuAutoExpandParent } = dashboard;
+        const { menuTree } = dashboard;
+        const { menuFilterLabel, menuExpandedKeys, menuSelectedKeys, menuAutoExpandParent } = mode === 'view' ? home : dashboard;
         const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
         const regLabel = menuFilterLabel.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
 
-        return <div className='menu-container'>
+        return <div className='menu-container' style={ mode === 'view' ? { paddingTop: 0 } : { paddingTop: '88px' } }>
             <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 />}/>
             </div>
-            <div className='menu-buttons'>
+            {mode !== 'view' && <div className='menu-buttons'>
                 <Button disabled={menuSelectedKeys.length !== 1} onClick={this.onAddClick}>新增目录</Button>
                 {/* <Button disabled={menuSelectedKeys.length !== 1} onClick={this.onModifyClick}>修改目录</Button> */}
-            </div>
-            <div className='menu-search'>
+            </div>}
+            {mode !== 'view' && <div className='menu-search'>
                 <Search
                     defaultValue={menuFilterLabel}
                     placeholder='搜索'
@@ -178,7 +206,7 @@ class DashboardMenu extends React.Component {
                 <Button onClick={() => {
                     dispatch({ type: 'dashboard/remoteMenuTree', mandatory: true });
                 }}><Icon type='sync' /></Button>
-            </div>
+            </div>}
             <div className='menu-content'>
                 <Tree
                     inlineIndent={8}
@@ -209,7 +237,7 @@ class DashboardMenu extends React.Component {
     }
 }
 
-function mapStateToProps({ present: { loading, dashboard }}) {
+function mapStateToProps({ present: { loading, dashboard, home }}) {
     let effectsArr = ['dashboard/remoteMenuTree', 'dashboard/remoteAddMenu', 'dashboard/remoteDeleteMenu'];
     let flag = false;
     for(let i = 0; i < effectsArr.length; i++) {
@@ -219,6 +247,6 @@ function mapStateToProps({ present: { loading, dashboard }}) {
         }
     }
 
-    return { dashboard, loading: flag }
+    return { dashboard, loading: flag, home }
 }
 export default connect(mapStateToProps)(DashboardMenu)

+ 1 - 1
src/components/dashboard/menu.less

@@ -1,6 +1,6 @@
 .menu-container {
     height: 100%;
-    padding-top: 88px;
+    // padding-top: 88px;
     .menu-buttons {
         height: 32px;
         padding: 0 8px;

+ 6 - 5
src/components/dashboard/shareKeyView.jsx

@@ -1,10 +1,11 @@
 import React from 'react'
-import Layout from '../dashboardDesigner/layout'
+import { connect } from 'dva'
+import DashboardDesigner from '../dashboardDesigner/layout'
 
-class View extends React.Component {
+class DashboardView extends React.Component {
     render() {
-        return <Layout { ...this.props } isShareKeyView={true} ></Layout>
+        const { code } = this.props.match.params;
+        return <DashboardDesigner dashboardDesigner={this.props.dashboardDesigner} code={code} isShareKeyView={true}/>
     }
 }
-
-export default View
+export default connect(({ present: { dashboardDesigner } }) => ({ dashboardDesigner }))(DashboardView)

+ 6 - 5
src/components/dashboard/shareView.jsx

@@ -1,10 +1,11 @@
 import React from 'react'
-import Layout from '../dashboardDesigner/layout'
+import { connect } from 'dva'
+import DashboardDesigner from '../dashboardDesigner/layout'
 
-class DashboardShareView extends React.Component {
+class DashboardView extends React.Component {
     render() {
-        return <Layout { ...this.props } isShareView={true} ></Layout>
+        const { code } = this.props.match.params;
+        return <DashboardDesigner dashboardDesigner={this.props.dashboardDesigner} code={code} isShareView={true}/>
     }
 }
-
-export default DashboardShareView
+export default connect(({ present: { dashboardDesigner } }) => ({ dashboardDesigner }))(DashboardView)

+ 12 - 0
src/components/dashboard/view.jsx

@@ -0,0 +1,12 @@
+import React from 'react'
+import { connect } from 'dva'
+import DashboardDesigner from '../dashboardDesigner/layout'
+
+class DashboardView extends React.Component {
+    render() {
+        const { code } = this.props.match.params;
+        console.log(code);
+        return <DashboardDesigner dashboardDesigner={this.props.dashboardDesigner} code={code}/>
+    }
+}
+export default connect(({ present: { dashboardDesigner } }) => ({ dashboardDesigner }))(DashboardView)

+ 24 - 24
src/components/dashboardDesigner/content.jsx

@@ -12,13 +12,14 @@ class DashboardDesignerContent extends React.Component {
     constructor(props) {
         super(props);
         this.state = {
-            contentSize: {
+            lastContentSize: {
                 scroll: false,
                 width: 0,
                 height: 0,
             },
             visibleFilterBox: false,
         };
+        this.contentRef=React.createRef();
     }
 
     componentDidMount() {
@@ -53,9 +54,10 @@ class DashboardDesignerContent extends React.Component {
     }
 
     getContentSize = () => {
-        const { dashboardDesigner, isOwner, isShareView, isShareKeyView } = this.props;
+        const { dashboardDesigner, isOwner, isShareView, isShareKeyView, isViewMode } = this.props;
+        const { lastContentSize } = this.state;
         const { editMode } = dashboardDesigner;
-        let contentEl = document.getElementsByClassName('viewlayout')[0];
+        let contentEl = this.contentRef.current;
         if(!contentEl) {
             return {
                 width: 0,
@@ -64,24 +66,22 @@ class DashboardDesignerContent extends React.Component {
         }
         let _scroll = contentEl.scrollHeight > contentEl.clientHeight;
 
+        let width = contentEl.offsetWidth - 10 - (_scroll ? 19 : 2) // 有滚动条时需要减去滚动条的宽度
+        if(width > 0 && width !== lastContentSize.width) {
+            this.setState({
+                lastContentSize: {
+                    width,
+                    height: contentEl.clientHeight,
+                    scroll: _scroll
+                }
+            });
+        }
         return {
-            width: document.body.offsetWidth - 20 - ((isOwner && editMode && !isShareView && !isShareKeyView) ? 200 : 0) - 10 - (_scroll ? 17 : 2), // 有滚动条时需要减去滚动条的宽度
+            width: width,
             height: contentEl.clientHeight
         }
     }
 
-    // getRelationFilterColumns = () => {
-    //     const { dashboardDesigner } = this.props;
-    //     const { relationColumns } = dashboardDesigner;
-    //     let arr = relationColumns.filter(r => r.relations.length > 0).map(r => ({
-    //         name: r.relations[0].column.name + (r.relations[1] ? (',' + r.relations[1].column.name) : ''),
-    //         label: r.name,
-    //         type: r.relations[0].column.type + (r.relations[1] ? (',' + r.relations[1].column.type) : ''),
-    //         dataSource: r.relations[0].dataSource + (r.relations[1] ? (',' + r.relations[1].dataSource) : ''),
-    //     }));
-    //     return arr;
-    // }
-
     createFilters = (filters) => {
         const { dispatch } = this.props;
         dispatch({ type: 'dashboardDesigner/changeFilters', filters });
@@ -141,9 +141,9 @@ class DashboardDesignerContent extends React.Component {
     }
 
     render() {
-        const { dashboardDesigner, isOwner, isShareView, isShareKeyView } = this.props;
+        const { dashboardDesigner, isOwner, isShareView, isShareKeyView, isViewMode } = this.props;
         const { dataSources, editMode, filters, relationColumns } = dashboardDesigner;
-        const { visibleFilterBox } = this.state;
+        const { visibleFilterBox, lastContentSize } = this.state;
 
         const contentSize = this.getContentSize();
         let tags = filters.map((f, i)=>{
@@ -178,14 +178,14 @@ class DashboardDesignerContent extends React.Component {
                 </div>
                 {visibleFilterBox && <FilterBox dataSources={dataSources} relationColumns={relationColumns} filterData={filters} visibleFilterBox={visibleFilterBox} showFilterBox={this.showFilterBox} hideFilterBox={this.hideFilterBox} createFilters={this.createFilters} />}
             </Header>
-            <Content className='dashboard-content'>
+            <Content className={`dashboard-content${(isShareView || isShareKeyView || isViewMode) ? ' nomargin' : ''}`}>
                 <Layout className='content-layout'>
-                    <Sider className={`config-sider${ (isOwner && editMode) ? '' : ' config-sider-closed' }`} width={(isOwner && editMode && !isShareView && !isShareKeyView) ? 200 : 0}>
+                    {isOwner && editMode && !isShareView && !isShareKeyView && !isViewMode && <Sider className={`config-sider${ (isOwner && editMode) ? '' : ' config-sider-closed' }`} width={(isOwner && editMode && !isShareView && !isShareKeyView && !isViewMode) ? 200 : 0}>
                         <ConfigSider/>
-                    </Sider>
-                    <Content className='viewlayout'>
-                        <ViewLayout isOwner={isOwner} isShareView={isShareView} isShareKeyView={isShareKeyView} contentSize={contentSize} editMode={editMode}/>
-                    </Content>
+                    </Sider>}
+                    <main ref={this.contentRef} className='viewlayout ant-layout-content'>
+                        <ViewLayout isOwner={isOwner} isShareView={isShareView} isShareKeyView={isShareKeyView} isViewMode={isViewMode} contentSize={contentSize} lastContentSize={lastContentSize} editMode={editMode}/>
+                    </main>
                 </Layout>
             </Content>
         </Layout>

+ 13 - 9
src/components/dashboardDesigner/layout.jsx

@@ -17,13 +17,17 @@ class DashboardDesigner extends React.Component {
     }
 
     componentDidMount() {
-        const { dispatch, isShareView, isShareKeyView } = this.props;
-        const { code } = this.props.match.params;
+        const { code, dispatch, isShareView, isShareKeyView, afterLoad } = this.props;
+        
         let url;
         if (code !== 'create') {
             url = isShareView ? 'dashboard/remoteShareDetail' : ( isShareKeyView ? 'dashboard/remoteShareKeyDetail' : 'dashboard/remoteDetail');
         }
-        dispatch({ type: url, code: code });
+        dispatch({ type: url, code: code }).then((data) => {
+            if(afterLoad && typeof afterLoad === 'function') {
+                afterLoad(data)
+            }
+        });
     }
 
 
@@ -49,14 +53,14 @@ class DashboardDesigner extends React.Component {
     }
 
     render() {
-        const { dashboardDesigner, isShareView, isShareKeyView } = this.props;
+        const { dashboardDesigner, isShareView, isShareKeyView, isViewMode } = this.props;
         const { loading } = dashboardDesigner;
         return <Layout className='dashboarddesigner-layout'>
-            {!isShareView && !isShareKeyView && <Header>
+            {!isShareView && !isShareKeyView && !isViewMode && <Header>
                 <DashboardDesignerHeader updateThumbnail={this.updateThumbnail} />
             </Header>}
-            <Content style={{ height: 0 }}>
-                <DashboardDesignerContent isOwner={this.isOwner()} isShareView={isShareView} isShareKeyView={isShareKeyView}/>
+            <Content>
+                <DashboardDesignerContent isOwner={this.isOwner()} isShareView={isShareView} isShareKeyView={isShareKeyView} isViewMode={isViewMode}/>
             </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 />} />
@@ -67,8 +71,8 @@ class DashboardDesigner extends React.Component {
 }
 
 function mapStateToProps(state) {
-    const { main, dashboardDesigner } = state.present;
-    return { main, dashboardDesigner }
+    const { main } = state.present;
+    return { main }
 }
 
 export default connect(mapStateToProps)(DashboardDesigner)

+ 3 - 0
src/components/dashboardDesigner/layout.less

@@ -18,6 +18,9 @@
                 height: calc(~"100% - 20px");
                 margin: 10px;
                 overflow: hidden;
+                &.nomargin {
+                    margin: 0;
+                }
                 &>.content-layout {
                     flex-direction: row;
                     overflow: hidden;

+ 0 - 0
src/components/dashboardDesigner/viewBox.jsx


+ 3 - 3
src/components/dashboardDesigner/viewLayout.jsx

@@ -83,13 +83,13 @@ class ViewLayout extends React.PureComponent {
     }
 
     render() {
-        const { isOwner, isShareView, isShareKeyView, dashboardDesigner, contentSize } = this.props;
+        const { isOwner, isShareView, isShareKeyView, isViewMode, dashboardDesigner, contentSize, lastContentSize } = this.props;
         const { editMode } = dashboardDesigner;
         const { visiblePreviewBox, previewItem } = this.state;
         const children = dashboardDesigner.items.map((item) => this.createElement(item, false, !item.chartOption));
         return (<div className='dashboard-viewcontent'>
             <ReactGridLayout
-                width={contentSize.width}
+                width={ contentSize.width ? contentSize.width : lastContentSize.width }
                 autoSize={true}
                 cols={12}
                 margin = {editMode ? [2, 2] : [0, 0]}
@@ -105,7 +105,7 @@ class ViewLayout extends React.PureComponent {
                 {(children.length === 0) ? <div key='default-chartview' className='default-chartview' data-grid={{ x: 0, y: 0, w: 12, h: 2, minW: 12, maxW: 12, minH: 2, maxH: 2, static: true }}>
                     <div className='tip'>
                         <Icon type="message" theme="outlined" />
-                        {(isOwner && !isShareView && !isShareKeyView) ? <span>请从左侧选择图表/富文本添加到报表</span> : <span>无图表元素</span>}
+                        {(isOwner && !isShareView && !isShareKeyView && !isViewMode) ? <span>请从左侧选择图表/富文本添加到报表</span> : <span>无图表元素</span>}
                     </div>
                 </div> : children}
             </ReactGridLayout>

+ 34 - 0
src/components/homePage/collection.jsx

@@ -0,0 +1,34 @@
+import React from 'react'
+import { connect } from 'dva'
+import { Collapse, Icon } from 'antd'
+
+class Collection extends React.Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+
+        }
+    }
+
+    generateCollectionMenus() {
+        const { home } = this.props;
+        const { menuCollected } = home;
+        return menuCollected.map((c, i) => (
+            <li key={i}>
+                <span style={{ fontWeight: 'bold' }}>
+                    <Icon style={{ marginRight: '8px' }} type="pushpin" />
+                    销售采购分析
+                </span>
+            </li>
+        ));
+    }
+
+    render() {
+        return <Collapse bordered={false} defaultActiveKey={['1']}>
+            <Collapse.Panel header='我的收藏' key="1">
+                { this.generateCollectionMenus() }
+            </Collapse.Panel>
+        </Collapse>
+    }
+}
+export default connect(({ present: { home } }) => ({ home }))(Collection)

+ 0 - 53
src/components/homePage/homePage.jsx

@@ -1,53 +0,0 @@
-import React from 'react';
-import { Layout, Card } from 'antd'
-import CardList from '../common/CardList'
-import { connect } from 'dva'
-import './homePage.less'
-const { Content, Sider } = Layout
-
-class HomePage extends React.Component {
-    constructor(props) {
-        super(props);
-        this.state = {
-        }
-    }
-
-    componentDidMount() {
-        const { dispatch } = this.props;
-        dispatch({ type: 'recent/fetchRecentChart' });
-        dispatch({ type: 'recent/fetchRecentDashboard' });
-    }
-
-    render() {
-        const { recent } = this.props;
-        const { recentChart, recentDashboard } = recent;
-
-        return (
-            <Layout className='homepage'>
-                <Content>
-                    <Card className='recent-chart' title='最近访问图表' >
-                        <CardList
-                            mode='homepage' 
-                            type='chart' 
-                            list={recentChart}
-                        />
-                    </Card>
-                    <Card className='recent-dashboard' title='最近访问报表'>
-                        <CardList
-                            mode='homepage' 
-                            type='dashboard' 
-                            list={recentDashboard}
-                        />
-                    </Card>
-                </Content>
-                <Sider width={280}> 
-                    <Card>
-                        <div><h1>快速上手</h1><p>点击访问<a href="http://192.168.253.189:82" target="_blank" rel="noopener noreferrer">产品文档</a></p></div>
-                    </Card>
-                </Sider>
-            </Layout>
-        );
-    }
-}
-
-export default connect(({ present: { recent } }) =>  { return { recent }})(HomePage)

+ 0 - 49
src/components/homePage/homePage.less

@@ -1,49 +0,0 @@
-.homepage {
-    &>.ant-layout-content {
-        padding: 20px;
-        &>.ant-card {
-            &>.ant-card-head {
-                padding: 0;
-                height: 42px;
-                min-height: 42px;
-                &>.ant-card-head-wrapper {
-                    &>.ant-card-head-title {
-                        padding: 8px 10px;
-                    }
-                }
-            }
-            &>.ant-card-body {
-                padding: 10px;
-                &>.ant-card-grid {
-                    &>.ant-card {
-                        border: 2px solid #CCCCCC;
-                        &>.ant-card-head {
-                            border-bottom: 2px solid #CCCCCC;
-                            min-height: 20px;
-                            cursor: default;
-                            padding: 0 10px;
-                        }
-                        &>.ant-card-body {
-                            padding: 10px;
-                        }
-                    }
-                }
-            }
-        }
-        &>.recent-chart {
-            margin-bottom: 20px;
-        }
-        &>.recent-dashboard {
-
-        }
-    }
-    .ant-layout-sider {
-        padding: 20px 20px 20px 0;
-        background: transparent;
-        &>.ant-layout-sider-children {
-            &>.ant-card {
-                height: 100%;
-            }
-        }
-    }
-}

+ 75 - 0
src/components/homePage/index.jsx

@@ -0,0 +1,75 @@
+import React from 'react'
+import { Layout, Tabs } from 'antd'
+import { connect } from 'dva'
+import Loading from '../common/loading/loading'
+import MenuLayout from './sider'
+import DashboardView from './view'
+import './index.less'
+const { Sider, Content } = Layout
+const TabPane = Tabs.TabPane
+
+class Home extends React.Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+
+        }
+    }
+
+    generateTabs() {
+        const { home } = this.props;
+        const { tabs } = home;
+
+        return tabs.map(t => (
+            <TabPane tab={t.title} key={t.code}>
+                <DashboardView code={t.code}/>
+            </TabPane>
+        ));
+    }
+
+    onChange = (activeKey) => {
+        const { dispatch, home } = this.props;
+        const { selectedTabKey } = home;
+        dispatch({ type: 'home/saveCurrentTabDashboardConfig', code: selectedTabKey });
+        dispatch({ type: 'home/changeTab', tabKey: activeKey });
+    }
+
+    onEdit = (targetKey, action) => {
+        this[action](targetKey);
+    }
+
+    remove = (targetKey) => {
+        const { dispatch } =  this.props;
+        dispatch({ type: 'home/closeTab', tabKey: targetKey });
+    }
+
+    render() {
+        const { home } = this.props;
+        const { selectedTabKey } = home;
+        return <Layout className='layout-home'>
+            <Sider
+                width={300}
+                collapsible
+                collapsedWidth={0}
+                trigger={null}
+                theme='light'
+                className='sider-home'
+            >
+                <MenuLayout />
+            </Sider>
+            <Content className='content-home'>
+                <Tabs
+                    type="editable-card"
+                    hideAdd
+                    onEdit={this.onEdit}
+                    onChange={this.onChange}
+                    activeKey={selectedTabKey}
+                >
+                    { this.generateTabs() }
+                </Tabs>
+            </Content>
+        </Layout>
+    }
+}
+
+export default connect(({ present: { home } }) => ({ home }))(Home)

+ 26 - 0
src/components/homePage/index.less

@@ -0,0 +1,26 @@
+.layout-home {
+    .sider-home {
+        padding: 0;
+        border-right: 1px solid #ccc;
+        button {
+            padding: 0 8px;
+            margin: 0 0 12px 0;
+        }
+    }
+    .content-home {
+        &>.ant-tabs {
+            height: 100%;
+            padding-top: 56px;
+            &>.ant-tabs-bar {
+                margin: -40px 16px 0;
+                height: 40px;
+            }
+            &>.ant-tabs-content {
+                height: 100%;
+                &>.ant-tabs-tabpane {
+                    height: 100%;
+                }
+            }
+        }
+    }
+}

+ 0 - 0
src/components/homePage/layout.jsx


+ 55 - 0
src/components/homePage/sider.jsx

@@ -0,0 +1,55 @@
+import React from 'react'
+import { Layout, Input } from 'antd'
+import { connect } from 'dva'
+import DashboardCollection from './collection'
+import DashboardMenu from '../dashboard/menu'
+import './sider.less'
+
+const { Header, Content } = Layout
+
+class MenuLayout extends React.Component {
+
+    onSearch = (value) => {
+        const { home, dashboard, dispatch } = this.props;
+        const expandedKeys = this.findExpandedKeys(dashboard.menuTree, {code: '-1'}, value);
+        dispatch({ type: 'home/setFields', fields: [
+            { name: 'menuExpandedKeys', value: expandedKeys },
+            { name: 'menuFilterLabel', value },
+            { name: 'menuAutoExpandParent', value: true },
+        ] });
+    }
+
+    findExpandedKeys = (tree, parent, filterLabel) => {
+        let result = [];
+        if(tree && tree.length > 0) {
+            tree.forEach(t => {
+                if(t.name.toLowerCase().indexOf(filterLabel.toLowerCase()) > -1 && result.indexOf(parent.code) === -1) {
+                    result.push(parent.code);
+                }
+                result = result.concat(this.findExpandedKeys(t.children, t, filterLabel));
+            });
+        }
+        return result;
+    }
+
+    render() {
+        const { home } = this.props;
+        const { menuFilterLabel } = home;
+
+        return <Layout className='home-menu'>
+            <Header>
+                <Input.Search
+                    placeholder='搜索'
+                    defaultValue={menuFilterLabel}
+                    onSearch={this.onSearch}
+                />
+            </Header>
+            <Content>
+                <DashboardCollection />
+                <DashboardMenu mode='view' />
+            </Content>
+        </Layout>;
+    }
+}
+
+export default connect(({ present: { home, dashboard } }) => ({ home, dashboard }))(MenuLayout)

+ 14 - 0
src/components/homePage/sider.less

@@ -0,0 +1,14 @@
+.home-menu {
+    .ant-layout-header {
+        padding: 0 16px;
+        background: transparent;
+    }
+    .ant-layout-content {
+        display: flex;
+        flex-direction: column;
+    }
+    .menu-container {
+        overflow: auto;
+        flex: auto;
+    }
+}

+ 18 - 0
src/components/homePage/view.jsx

@@ -0,0 +1,18 @@
+import React from 'react'
+import { connect } from 'dva'
+import DashboardDesigner from '../dashboardDesigner/layout'
+
+class DashboardView extends React.Component {
+    afterLoad = (data) => {
+        const { dispatch, code } = this.props;
+        if(data) {
+            dispatch({ type: 'dashboardDesigner/setEditMode', checked: false });
+            dispatch({ type: 'home/saveCurrentTabDashboardConfig', code });
+        }
+    }
+
+    render() {
+        return <DashboardDesigner dashboardDesigner={this.props.dashboardDesigner} code={this.props.code} isViewMode afterLoad={this.afterLoad}/>
+    }
+}
+export default connect(({ present: { dashboardDesigner } }) => ({ dashboardDesigner }))(DashboardView)

+ 3 - 0
src/components/homePage/view.less

@@ -0,0 +1,3 @@
+.layout-dashboard-view {
+    
+}

+ 9 - 9
src/constants/url.js

@@ -1,6 +1,6 @@
-const BASE_URL = 'http://10.1.1.168:8094/BI';
-// const BASE_URL = 'http://10.1.80.36:8011';
-// const BASE_URL = 'http://218.18.115.198:8888/BI'
+// const BASE_URL = 'http://10.1.1.168:8094/BI';
+// const BASE_URL = 'http://10.1.80.74:8011';
+const BASE_URL = 'http://218.18.115.198:8888/BI'
 
 /**后台接口地址 */
 const URLS = {
@@ -189,17 +189,17 @@ const URLS = {
 
     /***************************************报表目录***************************************/
 
-    DASHBOARD_MENU_TREE: BASE_URL + '/dashBoard/menu/list', // 获取报表目录树
+    DASHBOARD_MENU_TREE: BASE_URL + '/dashboard/menu/list', // 获取报表目录树
 
-    DASHBOARD_MENU_ADD: BASE_URL + '/dashBoard/menu/save', // 添加报表目录
+    DASHBOARD_MENU_ADD: BASE_URL + '/dashboard/menu/save', // 添加报表目录
 
-    DASHBOARD_MENU_UPDATE: BASE_URL + '/dashBoard/menu/update', // 添加报表目录
+    DASHBOARD_MENU_UPDATE: BASE_URL + '/dashboard/menu/update', // 添加报表目录
 
-    DASHBOARD_MENU_DELETE: BASE_URL + '/dashBoard/menu/delete', // 删除报表目录
+    DASHBOARD_MENU_DELETE: BASE_URL + '/dashboard/menu/delete', // 删除报表目录
 
-    DASHBOARD_MENU_DASHBOARD_LIST: BASE_URL + '/dashBoard/menu/list/dashBoard', // 获得目录下的所有报表
+    DASHBOARD_MENU_DASHBOARD_LIST: BASE_URL + '/dashboard/menu/list', // 获得目录下的所有报表
 
-    DASHBOARD_SET_MENU: BASE_URL + '/dashBoard/menu/update/dashboard', // 设置报表所属目录
+    DASHBOARD_SET_MENU: BASE_URL + '/dashboard/menu/update/dashboard', // 设置报表所属目录
 
     /***************************************浏览记录***************************************/
     

+ 2 - 0
src/index.js

@@ -2,6 +2,7 @@ import dva from 'dva'
 import undoable, { includeAction } from 'redux-undo'
 import indexRouter from './routes/router'
 import mainModel from './models/main'
+import homeModel from './models/home'
 import dataSource from './models/dataSource'
 import dataSourceDetail from './models/dataSourceDetail'
 import dataConnect from './models/dataConnect'
@@ -35,6 +36,7 @@ const app = dva({
 app.use(createLoading());
 
 // 3. Model
+app.model(homeModel); // 通用action
 app.model(mainModel); // 通用action
 app.model(dataConnect); // 数据链接
 app.model(dataSource); // 数据源

+ 31 - 27
src/models/dashboard.js

@@ -193,42 +193,46 @@ export default {
                         })
                     }
                     yield put({ type: 'dashboardDesigner/silentSetFields', fields: fields });
+                    return data;
                 }else {
                     message.error('解析报表错误: ' + (res.err || res.data.msg));
+                    return false;
                 }
             }catch(e) {
                 message.error('解析报表错误: ' + e.message);
+                return false;
             }finally {
                 yield put({ type: 'dashboardDesigner/silentSetField', name: 'loading', value: false });
             }
         },
         *remoteAdd(action, { select, call, put }) {
-            try {
-                const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
-                const { name, items, description, relationColumns, filters, shareCode, chartCodes } = dashboardDesigner;
-                let body = {
-                    bdName: name,
-                    bdNote: description,
-                    bdConfiguration: JSON.stringify(items),
-                    relationColumns: JSON.stringify(relationColumns),
-                    filters: JSON.stringify(filters) || '',
-                    bdCode: shareCode || generateShareCode(),
-                    thumbnail: '',
-                    chartIds: chartCodes.join(',')
-                }
-                const res = yield call(service.fetch, {
-                    url: URLS.DASHBOARD_ADD,
-                    body: body
-                });
-                if(!res.err && res.data.code > 0) {
-                    yield put({ type: 'fetchList', mandatory: true });
-                    message.success('保存成功');
-                }else {
-                    message.error('保存失败: ' + (res.err || res.data.msg));
-                } 
-            }catch(e) {
-                message.error('保存失败: ' + e.message);
-            }
+            message.error('请先指定目录');
+            // try {
+            //     const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
+            //     const { name, items, description, relationColumns, filters, shareCode, chartCodes } = dashboardDesigner;
+            //     let body = {
+            //         bdName: name,
+            //         bdNote: description,
+            //         bdConfiguration: JSON.stringify(items),
+            //         relationColumns: JSON.stringify(relationColumns),
+            //         filters: JSON.stringify(filters) || '',
+            //         bdCode: shareCode || generateShareCode(),
+            //         thumbnail: '',
+            //         chartIds: chartCodes.join(',')
+            //     }
+            //     const res = yield call(service.fetch, {
+            //         url: URLS.DASHBOARD_ADD,
+            //         body: body
+            //     });
+            //     if(!res.err && res.data.code > 0) {
+            //         yield put({ type: 'fetchList', mandatory: true });
+            //         message.success('保存成功');
+            //     }else {
+            //         message.error('保存失败: ' + (res.err || res.data.msg));
+            //     } 
+            // }catch(e) {
+            //     message.error('保存失败: ' + e.message);
+            // }
         },
         *remoteQucikAdd(action, { select, call, put }) {
             const { menuCode } = action;
@@ -251,7 +255,7 @@ export default {
                     body: body
                 });
                 if(!res.err && res.data.code > 0) {
-                    yield put({ type: 'fetchList', mandatory: true });
+                    yield put({ type: 'remoteMenuDashboardList', menuCode });
                     yield put({ type: 'main/redirect', path: '/dashboard/' + res.data.data });
                 }else {
                     message.error('保存失败: ' + (res.err || res.data.msg));

+ 126 - 0
src/models/home.js

@@ -0,0 +1,126 @@
+/**
+ * 首页model
+ */
+import { routerRedux } from 'dva/router'
+import { message } from 'antd'
+import * as service from '../services/index'
+import URLS from '../constants/url'
+import moment from 'moment'
+
+const code = window.sessionStorage.getItem('usercode');
+const account = window.localStorage.getItem('account');
+const password = window.localStorage.getItem('password');
+const name = window.sessionStorage.getItem('username');
+const role = window.sessionStorage.getItem('userrole');
+const department = window.sessionStorage.getItem('department');
+const job = window.sessionStorage.getItem('job');
+const expireTime = window.sessionStorage.getItem('expireTime');
+const autoLogin = window.localStorage.getItem('autoLogin') ? window.localStorage.getItem('autoLogin') === 'true' : true;
+
+const t = moment(+expireTime);
+const isLogin = expireTime && t.isValid();
+const authenticated = t.isValid() && t.diff(moment()) > 0;
+
+export default {
+    namespace: 'home',
+    state: {
+        originData: {
+            menuExpandedKeys: ['-1'],
+            menuSelectedKeys: [],
+            menuFilterLabel: '',
+            menuAutoExpandParent: true,
+            menuCollected: [{},{},{},{},{}],
+            tabs: [],
+            selectedTabKey: null,
+        }
+    },
+    reducers: {
+        setField(state, action) {
+            const { name, value } = action;
+            let obj = {};
+            obj[name] = value;
+            return Object.assign({}, state, obj);
+        },
+        setFields(state, action) {
+            const { fields } = action;
+            let obj = {};
+            fields.map(f => (obj[f.name] = f.value));
+            return Object.assign({}, state, obj);
+        },
+        reset(state, action) {
+            return Object.assign({}, state, state.originData);
+        },
+        addTab(state, action) {
+            const { tabs } = state;
+            const { tab } = action;
+            return Object.assign({}, state, { tabs: tabs.concat([tab]) });
+        },
+        removeTab(state, action) {
+            const { tabs } = state;
+            const { tabKey } = action;
+            let idx = tabs.findIndex(t => t.code === tabKey);
+            tabs.splice(idx, 1);
+            return Object.assign({}, state, { tabs });
+        },
+        setSelectedTab(state, action) {
+            const { tabs } = state;
+            return Object.assign({}, state, { selectedTabKey: action.tabKey });
+        }
+    },
+    effects: {
+        *openTab(action, { select, call, put }) {
+            const home = yield select(state => state.present.home);
+            const { tabs } = home;
+            const { tab } = action;
+            if(tabs.findIndex(t => t.code === tab.code) > -1) {
+                yield put({ type: 'changeTab', tabKey: tab.code });
+            }else {
+                yield put({ type: 'addTab', tab });
+                yield put({ type: 'changeTab', tabKey: tab.code });
+            }
+        },
+        *changeTab(action, { select, call, put }) {
+            const home = yield select(state => state.present.home);
+            const { tabs, selectedTabKey } = home;
+            const { tabKey } = action;
+            let fields = [];
+
+            yield put({ type: 'setSelectedTab', tabKey });
+            let tab = tabs.find(t => t.code === tabKey);
+            let data = { ...tab.config };
+            for(let key in data) {
+                fields.push({
+                    name: key,
+                    value: data[key]
+                })
+            }
+            yield put({ type: 'dashboardDesigner/reset' });
+            yield put({ type: 'dashboardDesigner/silentSetFields', fields: fields });
+        },
+        *closeTab(action, { select, call, put }) {
+            const home = yield select(state => state.present.home);
+            const { tabs, selectedTabKey } = home;
+            const { tabKey } = action;
+
+            yield put({ type: 'removeTab', tabKey });
+            if(tabs.length > 0) {
+                yield put({ type: 'changeTab', tabKey: tabs[tabs.length - 1].code });
+            }
+        },
+        *saveCurrentTabDashboardConfig(action, { select, call, put }) {
+            const { home, dashboardDesigner } = yield select(state => ({ home: state.present.home, dashboardDesigner: state.present.dashboardDesigner }));
+            const { tabs } = home;
+            const { config, code } = action;
+            let idx = tabs.findIndex(t => t.code === code);
+            if(idx > -1) {
+                tabs[idx].config = { ...dashboardDesigner }
+            }
+            yield put({ type: 'setField', name: 'tabs', value: tabs });
+        }
+    },
+    subscriptions: {
+        setup({ dispatch, history }) {
+            dispatch({ type: 'reset' });
+        }
+    }
+};

+ 0 - 1
src/models/main.js

@@ -142,7 +142,6 @@ export default {
                 }
             }catch(e) {
                 message.error('登录失败: ' + e.message);
-                console.error(body, e);
                 return false;
             }
         },

+ 2 - 2
src/routes/mainLayout.jsx

@@ -2,8 +2,8 @@ import React from 'react'
 import { Layout } from 'antd'
 import { Route, Switch, Redirect } from 'dva/router'
 import Navigator from '../components/common/navigator'
-import HomePage from '../components/homePage/homePage'
 import Loading from '../components/common/loading/loading'
+import HomePage from '../components/homePage/index'
 import Workshop from '../components/workshop/index'
 import Setting from '../components/setting/index'
 import './mainLayout.less'
@@ -19,7 +19,7 @@ const MainLayout = () => {
             </Header>
             <Content className='main-content'>
                 <Switch>
-                    <Route sensitive path='/home' component={HomePage}/>
+                    <Route sensitive exact={false} path='/home' component={HomePage}/>
                     <Route sensitive exact={false} path='/workshop' component={Workshop}/>
                     <Route sensitive exact={false} path='/setting' component={Setting} />
                     <Route sensitive path='/userinfo' component={UserInfo} />

+ 2 - 2
src/routes/router.js

@@ -6,7 +6,7 @@ import Login from '../components/common/login/login'
 import Register from '../components/common/login/register'
 import MainLayout from './mainLayout'
 import ChartDesigner from '../components/chartDesigner/layout'
-import DashboardDesigner from '../components/dashboardDesigner/layout'
+import DashboardView from '../components/dashboard/view'
 import DashboardShareView from '../components/dashboard/shareView'
 import DashboardShareKeyView from '../components/dashboard/shareKeyView'
 // 由于 antd 组件的默认文案是英文,所以需要修改为中文
@@ -22,7 +22,7 @@ function RouterConfig({ history }) {
                     <Route sensitive path='/dashboard/share/:code' component={DashboardShareView} />
                     <Route sensitive path='/dashboard/share_key/:code' component={DashboardShareKeyView} />
                     <PrivateRoute sensitive path='/chart/:code' component={ChartDesigner} />
-                    <PrivateRoute sensitive path='/dashboard/:code/' component={DashboardDesigner} />
+                    <PrivateRoute sensitive path='/dashboard/:code/' component={DashboardView}/>
                     <PrivateRoute path='/' component={MainLayout} />
                 </Switch>
             </Router>