Browse Source

饼图、线图命名调整/饼图、线图数据钻取设置逻辑添加

zhuth 6 years ago
parent
commit
5b5e82ba59

+ 2 - 2
src/components/chartDesigner/sections/chartType.json

@@ -8,11 +8,11 @@
     "icon": "table"
 }, {
     "type": "line",
-    "label": "线图",
+    "label": "线图",
     "icon": "line-chart"
 }, {
     "type": "bar",
-    "label": "柱图",
+    "label": "柱图",
     "icon": "bar-chart"
 }, {
     "type": "pie",

+ 51 - 154
src/components/chartDesigner/sections/lineConfigForm.jsx

@@ -1,169 +1,36 @@
-import React from 'react'
-import { Form, Select, Tag, Cascader, Dropdown, Menu } from 'antd'
-import { connect } from 'dva'
-import '../../../models/chartDesigner'
-import GAUGE from './gauge.json'
-import GRANULARITY from './granularity.json'
-const FormItem = Form.Item
-const { Option } = Select
+import React from 'react';
+import { Form, Select, Checkbox } from 'antd';
+import { connect } from 'dva';
+import XAxisItem from './xAxisItem';
+import YAxisItem from './yAxisItem';
+import DrillList from './drillList';
+import GRANULARITY from './granularity.json';
+const FormItem = Form.Item;
+const { Option } = Select;
 const formItemLayout = {
 	labelCol: { span: 8 },
 	wrapperCol: { span: 16 },
 };
 const LineConfigForm = ({ autoRefresh, chartDesigner, dispatch }) => {
-	
-	const columns = chartDesigner.columns;
+	const { columns, baseConfig, lineConfig } = chartDesigner;
 
 	return (
 		<Form hideRequiredMark={true}>
 			<FormItem label='横轴' {...formItemLayout}>
-				<Cascader
-					value={[chartDesigner.lineConfig.xAxis.column.value, chartDesigner.lineConfig.xAxis.granularity.value]}
-					allowClear={true}
-					showSearch={{
-						filter: (inputValue, path) => {
-							let p0 = path[0].label.toLowerCase();
-							let v = inputValue.toLowerCase();
-							return p0.indexOf(v) !== -1;
-						},
-						sort: (a, b, inputValue) => {
-							return a[0].label.localeCompare(b[0].label,"zh");
-						},
-						render: (inputValue, path) => {
-							const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
-							let v = inputValue.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
-							let label0 = (path[0].label.split(new RegExp(`(${v})`, 'i')).map((fragment, i) => {
-								return (
-									fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === v.toLowerCase() ?
-									<span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
-									fragment
-								)
-							}))
-							return <div>{label0}</div>
-						}
-					}}
-					options={columns.filter(c =>['time'].indexOf(c.type) !== -1).map((c, i)=>{
-						return {
-							type: c.type,
-							value: c.name,
-							label: c.label,
-							children: GRANULARITY[c.type]
-						}
-					})}
-					onChange={(value, items) => {
-						let column = {};
-						let granularity = {};
-						if(items.length > 0) {
-							column = { type: items[0].type, value: items[0].value, label: items[0].label };
-						}
-						if(items.length > 1) {
-							granularity = { value: items[1].value, label: items[1].label };
-						}
-						dispatch({ type: 'chartDesigner/changeField', name: 'lineConfig', value: { ...chartDesigner.lineConfig, xAxis: { column, granularity } }, autoRefresh });
+				<XAxisItem value={lineConfig.xAxis} options={columns.filter(c =>['time'].indexOf(c.type) > -1)}
+					onChange={({ column, granularity }) => {
+						dispatch({ type: 'chartDesigner/changeField', name: 'lineConfig', value: {
+							...lineConfig,
+							xAxis: { column, granularity },
+							drillList: [{ column, granularity }] 
+						}, autoRefresh });
 					}}
-					displayRender={(label, selectedOptions) => {
-						let text = '';
-						let className = 'cascader-label';
-						if(label.length > 0) {
-							className += ' full-label';
-							text += label[0];
-							if(label.length > 1) {
-								text += '(' + label[1] + ')';
-							}
-						}else {
-							className += ' empty-label';
-							text = '请选择...';
-						}
-						return <div className={className}>{text}</div>;
-					}}
-				>
-				</Cascader>
+				/>
 			</FormItem>
 			<FormItem label='纵轴' {...formItemLayout}>
-				<Cascader
-					className='gauge-item'
-					value={[chartDesigner.lineConfig.yAxis.column.value, chartDesigner.lineConfig.yAxis.gauge.value]}
-					allowClear={true}
-					showSearch={{
-						filter: (inputValue, path) => {
-							let p0 = path[0].label.toLowerCase();
-							let v = inputValue.toLowerCase();
-							return p0.indexOf(v) !== -1;
-						},
-						sort: (a, b, inputValue) => {
-							return a[0].label.localeCompare(b[0].label,"zh");
-						},
-						render: (inputValue, path) => {
-							const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
-							let v = inputValue.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
-							let label0 = (path[0].label.split(new RegExp(`(${v})`, 'i')).map((fragment, i) => {
-								return (
-									fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === v.toLowerCase() ?
-									<span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
-									fragment
-								)
-							}))
-							return <div>{label0}>{path[1].label}</div>
-						}
-					}}
-					options={columns.map((c, i)=>{
-						return {
-							type: c.type,
-							value: c.name,
-							label: c.label,
-							children: GAUGE[chartDesigner.baseConfig.viewType].map(g => {
-                                if(g.columnType.indexOf(c.type) !== -1) {
-                                    return g;
-                                }else {
-                                    return null;
-                                }
-                            }).filter( g => g!==null)
-						}
-					})}
-					onChange={(value, items) => {
-						let column = {};
-						let gauge = {};
-						if(value.length > 0) {
-							column = { type: items[0].type, value: items[0].value, label: items[0].label };
-							gauge = { value: items[1].value, label: items[1].label };
-						}
-						dispatch({ type: 'chartDesigner/changeField', name: 'lineConfig', value: { ...chartDesigner.lineConfig, yAxis: { column, gauge } }, autoRefresh });
-					}}
-					displayRender={(label, selectedOptions) => {
-						let menu = selectedOptions.length > 0 ? <Menu
-							selectedKeys={[chartDesigner.lineConfig.yAxis.gauge.value]}
-							selectable={true}
-						>
-							{selectedOptions[0].children.map((c, i) => {
-								return <Menu.Item  data-value={c.value} data-label={c.label} key={c.value} onClick={(e) => {
-									let value = e.domEvent.target.getAttribute('data-value');
-									let label = e.domEvent.target.getAttribute('data-label');
-									dispatch({ type: 'chartDesigner/changeField', name: 'lineConfig', value: { 
-										...chartDesigner.lineConfig,
-										yAxis: {
-											column: chartDesigner.lineConfig.yAxis.column,
-											gauge: { value, label }
-										}
-									}, autoRefresh });
-									e.domEvent.stopPropagation();
-								}}>{c.label}</Menu.Item>
-							})}
-						</Menu>: [];
-						let tag = selectedOptions.length > 0 ? <Dropdown
-							trigger={['click']}
-							overlay={menu}
-						>
-							<Tag size='small' onClick={(e) => {e.stopPropagation()}}>{label[1]}</Tag>
-						</Dropdown>
-						: null;
-
-						return <div className={`cascader-label ${tag?'full' : 'empty'}-label`}>
-							{tag}
-							<span>{label[0] || '请选择...'}</span>
-						</div>
-					}}
-				>
-				</Cascader>
+				<YAxisItem value={lineConfig.yAxis} options={columns} gaugeType={baseConfig.viewType} onChange={({ column, gauge }) => {
+					dispatch({ type: 'chartDesigner/changeField', name: 'lineConfig', value: { ...lineConfig, yAxis: { column, gauge } }, autoRefresh });
+				}}/>
 			</FormItem>
 			<FormItem label='分组' {...formItemLayout}>
 				<Select
@@ -185,6 +52,36 @@ const LineConfigForm = ({ autoRefresh, chartDesigner, dispatch }) => {
 					})}
 				</Select>
 			</FormItem>
+			{lineConfig.xAxis.column.value && <FormItem label='钻取' {...formItemLayout}>
+				<Checkbox
+					checked={!!lineConfig.drillable}
+					onChange={e => {
+						let checked = e.target.checked;
+						let drillList = [{ column: lineConfig.xAxis.column, granularity: lineConfig.xAxis.granularity }];
+						if(lineConfig.xAxis.column.type === 'time') { // 如果x轴字段是时间类型,自动生成其维度钻取层级
+							const granularitys = GRANULARITY['time'];
+							let idx = granularitys.findIndex(g => g.value === lineConfig.xAxis.granularity.value);
+							for(let i = idx + 1; i < granularitys.length; i++) {
+								drillList.push({
+									column: lineConfig.xAxis.column,
+									granularity: granularitys[i]
+								});
+							}
+						}
+						dispatch({ type: 'chartDesigner/changeField', name: 'lineConfig', value: { ...lineConfig, drillable: checked, drillList }, autoRefresh });
+					}}
+				/>
+			</FormItem>}
+			{lineConfig.xAxis.column.value && lineConfig.drillable && <FormItem label='钻取层级' {...formItemLayout}>
+				<DrillList
+					// 可选钻取字段包括时间、类别类型,且当x轴选择的是时间类型时允许重复作为钻取字段(之后会限制年月周等维度的选择)
+					list={columns.filter(c => ['categorical', 'time'].indexOf(c.type) > -1)}
+					value={lineConfig.drillList || []}
+					onChange={list => {
+						dispatch({ type: 'chartDesigner/changeField', name: 'lineConfig', value: { ...lineConfig, drillList: list }, autoRefresh });
+					}}
+				/>
+			</FormItem>}
 		</Form>
 	);
 }

+ 47 - 151
src/components/chartDesigner/sections/pieConfigForm.jsx

@@ -1,170 +1,36 @@
 import React from 'react'
-import { Form, Tag, Cascader, Dropdown, Menu, InputNumber } from 'antd'
+import { Form, InputNumber, Checkbox } from 'antd'
 import { connect } from 'dva'
-import '../../../models/chartDesigner'
+import XAxisItem from './xAxisItem';
+import YAxisItem from './yAxisItem';
+import DrillList from './drillList';
+import GRANULARITY from './granularity.json';
 import { deepAssign } from '../../../utils/baseUtils'
-import GAUGE from './gauge.json'
-import GRANULARITY from './granularity.json'
 const FormItem = Form.Item
 const formItemLayout = {
 	labelCol: { span: 8 },
 	wrapperCol: { span: 16 },
 }
 const PieConfigForm = ({ autoRefresh, chartDesigner, dispatch }) => {
-	
-	const columns = chartDesigner.columns;
+	const { columns, baseConfig, pieConfig } = chartDesigner;
 
 	return (
 		<Form hideRequiredMark={true}>
 			<FormItem label='扇区索引' {...formItemLayout}>
-				<Cascader
-					value={[chartDesigner.pieConfig.xAxis.column.value, chartDesigner.pieConfig.xAxis.granularity.value]}
-					allowClear={true}
-					showSearch={{
-						filter: (inputValue, path) => {
-							let p0 = path[0].label.toLowerCase();
-							let v = inputValue.toLowerCase();
-							return p0.indexOf(v) !== -1;
-						},
-						sort: (a, b, inputValue) => {
-							return a[0].label.localeCompare(b[0].label,"zh");
-						},
-						render: (inputValue, path) => {
-							const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
-							let v = inputValue.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
-							let label0 = (path[0].label.split(new RegExp(`(${v})`, 'i')).map((fragment, i) => {
-								return (
-									fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === v.toLowerCase() ?
-									<span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
-									fragment
-								)
-							}))
-							return <div>{label0}{path[1] ? '>' + path[1].label : ''}</div>
-						}
-					}}
-					options={columns.filter(c =>['ordinal', 'categorical', 'time'].indexOf(c.type) !== -1).map((c, i)=>{
-						
-						return {
-							type: c.type,
-							value: c.name,
-							label: c.label,
-							children: GRANULARITY[c.type]
-						}
-					})}
-					onChange={(value, items) => {
-						let column = {};
-						let granularity = {};
-						if(value.length > 0) {
-							column = { type: items[0].type, value: items[0].value, label: items[0].label };
-						}
-						if(items.length > 1) {
-							granularity = { value: items[1].value, label: items[1].label };
-						}
-						dispatch({ type: 'chartDesigner/changeField', name: 'pieConfig', value: { ...chartDesigner.pieConfig, xAxis: { column, granularity } }, autoRefresh });
+				<XAxisItem value={pieConfig.xAxis} options={columns.filter(c =>['ordinal', 'categorical', 'time'].indexOf(c.type) > -1)}
+					onChange={({ column, granularity }) => {
+						dispatch({ type: 'chartDesigner/changeField', name: 'pieConfig', value: {
+							...pieConfig,
+							xAxis: { column, granularity },
+							drillList: [{ column, granularity }] 
+						}, autoRefresh });
 					}}
-					displayRender={(label, selectedOptions) => {
-						let text = '';
-						let className = 'cascader-label';
-						if(label.length > 0) {
-							className += ' full-label';
-							text += label[0];
-							if(label.length > 1) {
-								text += '(' + label[1] + ')';
-							}
-						}else {
-							className += ' empty-label';
-							text = '请选择...';
-						}
-						return <div className={className}>{text}</div>;
-					}}
-				>
-				</Cascader>
+				/>
 			</FormItem>
 			<FormItem label='值' {...formItemLayout}>
-				<Cascader
-					className='gauge-item'
-					value={[chartDesigner.pieConfig.yAxis.column.value, chartDesigner.pieConfig.yAxis.gauge.value]}
-					allowClear={true}
-					showSearch={{
-						filter: (inputValue, path) => {
-							let p0 = path[0].label.toLowerCase();
-							let v = inputValue.toLowerCase();
-							return p0.indexOf(v) !== -1;
-						},
-						sort: (a, b, inputValue) => {
-							return a[0].label.localeCompare(b[0].label,"zh");
-						},
-						render: (inputValue, path) => {
-							const reg = new RegExp('([+ \\- & | ! ( ) { } \\[ \\] ^ \" ~ * ? : ( ) \/])', 'g'); // 需要转义的字符
-							let v = inputValue.replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1'); // 添加转义符号
-							let label0 = (path[0].label.split(new RegExp(`(${v})`, 'i')).map((fragment, i) => {
-								return (
-									fragment.toLowerCase().replace(new RegExp('(\\\\)', 'g'), '\\$1').replace(reg, '\\$1') === v.toLowerCase() ?
-									<span key={i} style={{fontWeight: 'bold', color: 'red'}} className="highlight">{fragment}</span> :
-									fragment
-								)
-							}))
-							return <div>{label0}>{path[1].label}</div>
-						}
-					}}
-					options={columns.map((c, i)=>{
-						return {
-							type: c.type,
-							value: c.name,
-							label: c.label,
-							children: GAUGE[chartDesigner.baseConfig.viewType].map(g => {
-                                if(g.columnType.indexOf(c.type) !== -1) {
-                                    return g;
-                                }else {
-                                    return null;
-                                }
-                            }).filter( g => g!==null)
-						}
-					})}
-					onChange={(value, items) => {
-						let column = {};
-						let gauge = {};
-						if(value.length > 0) {
-							column = { type: items[0].type, value: items[0].value, label: items[0].label };
-							gauge = { value: items[1].value, label: items[1].label };
-						}
-						dispatch({ type: 'chartDesigner/changeField', name: 'pieConfig', value: { ...chartDesigner.pieConfig, yAxis: { column, gauge } }, autoRefresh });
-					}}
-					displayRender={(label, selectedOptions) => {
-						let menu = selectedOptions.length > 0 ? <Menu
-							selectedKeys={[chartDesigner.pieConfig.yAxis.gauge.value]}
-							selectable={true}
-						>
-							{selectedOptions[0].children.map((c, i) => {
-								return <Menu.Item  data-value={c.value} data-label={c.label} key={c.value} onClick={(e) => {
-									let value = e.domEvent.target.getAttribute('data-value');
-									let label = e.domEvent.target.getAttribute('data-label');
-									dispatch({ type: 'chartDesigner/changeField', name: 'pieConfig', value: { 
-										...chartDesigner.pieConfig,
-										yAxis: {
-											column: chartDesigner.pieConfig.yAxis.column,
-											gauge: { value, label }
-										}
-									}, autoRefresh });
-									e.domEvent.stopPropagation();
-								}}>{c.label}</Menu.Item>
-							})}
-						</Menu>: [];
-						let tag = selectedOptions.length > 0 ? <Dropdown
-							trigger={['click']}
-							overlay={menu}
-						>
-							<Tag size='small' onClick={(e) => {e.stopPropagation()}}>{label[1]}</Tag>
-						</Dropdown>
-						: null;
-
-						return <div className={`cascader-label ${tag?'full' : 'empty'}-label`}>
-							{tag}
-							<span>{label[0] || '请选择...'}</span>
-						</div>
-					}}
-				>
-				</Cascader>
+				<YAxisItem value={pieConfig.yAxis} options={columns} gaugeType={baseConfig.viewType} onChange={({ column, gauge }) => {
+					dispatch({ type: 'chartDesigner/changeField', name: 'pieConfig', value: { ...pieConfig, yAxis: { column, gauge } }, autoRefresh });
+				}}/>
 			</FormItem>
 			<FormItem label='阈值' {...formItemLayout}>
 				<InputNumber
@@ -188,6 +54,36 @@ const PieConfigForm = ({ autoRefresh, chartDesigner, dispatch }) => {
                     }}
 				/>
 			</FormItem>
+			{pieConfig.xAxis.column.value && <FormItem label='钻取' {...formItemLayout}>
+				<Checkbox
+					checked={!!pieConfig.drillable}
+					onChange={e => {
+						let checked = e.target.checked;
+						let drillList = [{ column: pieConfig.xAxis.column, granularity: pieConfig.xAxis.granularity }];
+						if(pieConfig.xAxis.column.type === 'time') { // 如果x轴字段是时间类型,自动生成其维度钻取层级
+							const granularitys = GRANULARITY['time'];
+							let idx = granularitys.findIndex(g => g.value === pieConfig.xAxis.granularity.value);
+							for(let i = idx + 1; i < granularitys.length; i++) {
+								drillList.push({
+									column: pieConfig.xAxis.column,
+									granularity: granularitys[i]
+								});
+							}
+						}
+						dispatch({ type: 'chartDesigner/changeField', name: 'pieConfig', value: { ...pieConfig, drillable: checked, drillList }, autoRefresh });
+					}}
+				/>
+			</FormItem>}
+			{pieConfig.xAxis.column.value && pieConfig.drillable && <FormItem label='钻取层级' {...formItemLayout}>
+				<DrillList
+					// 可选钻取字段包括时间、类别类型,且当x轴选择的是时间类型时允许重复作为钻取字段(之后会限制年月周等维度的选择)
+					list={columns.filter(c => ['categorical', 'time'].indexOf(c.type) > -1)}
+					value={pieConfig.drillList || []}
+					onChange={list => {
+						dispatch({ type: 'chartDesigner/changeField', name: 'pieConfig', value: { ...pieConfig, drillList: list }, autoRefresh });
+					}}
+				/>
+			</FormItem>}
 		</Form>
 	);
 }