|
|
@@ -1,11 +1,13 @@
|
|
|
-import React from 'react'
|
|
|
-import { Form, Select, Tag, Cascader, Dropdown, Menu, InputNumber } from 'antd'
|
|
|
-import { deepAssign } from '../../../utils/baseUtils'
|
|
|
-import { connect } from 'dva'
|
|
|
-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, InputNumber } from 'antd';
|
|
|
+import { deepAssign } from '../../../utils/baseUtils';
|
|
|
+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 },
|
|
|
@@ -16,154 +18,16 @@ const BarConfigForm = ({ autoRefresh, chartDesigner, dispatch }) => {
|
|
|
return (
|
|
|
<Form hideRequiredMark={true}>
|
|
|
<FormItem label='横轴' {...formItemLayout}>
|
|
|
- <Cascader
|
|
|
- className='barconfig-yaxis'
|
|
|
- value={[barConfig.xAxis.column.value, barConfig.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(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: 'barConfig', value: { ...barConfig, xAxis: { column, granularity } }, autoRefresh });
|
|
|
+ <XAxisItem value={barConfig.xAxis} options={columns.filter(c =>['ordinal', 'categorical', 'time'].indexOf(c.type) > -1)}
|
|
|
+ onChange={({ column, granularity }) => {
|
|
|
+ dispatch({ type: 'chartDesigner/changeField', name: 'barConfig', value: { ...barConfig, xAxis: { column, granularity }, drillList: [] }, 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={[barConfig.yAxis.column.value, barConfig.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 {
|
|
|
- value: c.name,
|
|
|
- label: c.label,
|
|
|
- type: c.type,
|
|
|
- children: GAUGE[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: 'barConfig', value: { ...barConfig, yAxis: { column, gauge } }, autoRefresh });
|
|
|
- }}
|
|
|
- displayRender={(label, selectedOptions) => {
|
|
|
- let menu = selectedOptions.length > 0 ? <Menu
|
|
|
- selectedKeys={[barConfig.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: 'barConfig', value: {
|
|
|
- ...barConfig,
|
|
|
- yAxis: {
|
|
|
- column: barConfig.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={barConfig.yAxis} options={columns} gaugeType={baseConfig.viewType} onChange={({ column, gauge }) => {
|
|
|
+ dispatch({ type: 'chartDesigner/changeField', name: 'barConfig', value: { ...barConfig, yAxis: { column, gauge } }, autoRefresh });
|
|
|
+ }}/>
|
|
|
</FormItem>
|
|
|
<FormItem label='分组' {...formItemLayout}>
|
|
|
<Select
|
|
|
@@ -232,6 +96,36 @@ const BarConfigForm = ({ autoRefresh, chartDesigner, dispatch }) => {
|
|
|
}}
|
|
|
/>
|
|
|
</FormItem>
|
|
|
+ {barConfig.xAxis.column.value && <FormItem label='钻取' {...formItemLayout}>
|
|
|
+ <Checkbox
|
|
|
+ checked={!!barConfig.drillable}
|
|
|
+ onChange={e => {
|
|
|
+ let checked = e.target.checked;
|
|
|
+ let drillList = [];
|
|
|
+ if(barConfig.xAxis.column.type === 'time') { // 如果x轴字段是时间类型,自动生成其维度钻取层级
|
|
|
+ const granularitys = GRANULARITY['time'];
|
|
|
+ let idx = granularitys.findIndex(g => g.value === barConfig.xAxis.granularity.value);
|
|
|
+ for(let i = idx + 1; i < granularitys.length; i++) {
|
|
|
+ drillList.push({
|
|
|
+ column: barConfig.xAxis.column,
|
|
|
+ granularity: granularitys[i]
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ dispatch({ type: 'chartDesigner/changeField', name: 'barConfig', value: { ...barConfig, drillable: checked, drillList }, autoRefresh });
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </FormItem>}
|
|
|
+ {barConfig.xAxis.column.value && barConfig.drillable && <FormItem label='钻取层级' {...formItemLayout}>
|
|
|
+ <DrillList
|
|
|
+ // 可选钻取字段包括时间、类别类型,且当x轴选择的是时间类型时允许重复作为钻取字段(之后会限制年月周等维度的选择)
|
|
|
+ list={columns.filter(c => (barConfig.xAxis.column.type === 'time' ? true : c.name !== barConfig.xAxis.column.value) && ['categorical', 'time'].indexOf(c.type) > -1)}
|
|
|
+ value={barConfig.drillList || []}
|
|
|
+ onChange={list => {
|
|
|
+ dispatch({ type: 'chartDesigner/changeField', name: 'barConfig', value: { ...barConfig, drillList: list }, autoRefresh });
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </FormItem>}
|
|
|
</Form>
|
|
|
);
|
|
|
}
|