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 moment from 'moment' 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 { namespace: 'chartDesigner', state: { originData: { code: null, creatorCode: null, creatorName: null, header: { label: '标题' }, baseConfig: { dataSource: { }, viewType: '' }, aggregateTableConfig: { targetColumn: {}, statistics: [], groupBy: [] }, dataViewConfig: { viewColumns: [], sortColumn: {key: ''}, sortType: 'asc', count: 25 }, barConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''} }, lineConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''} }, pieConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} } }, scatterConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''} }, styleConfig: { visibleIndex: true }, filters: [], chartOption: {}, dirty: false, fetchConfig: {} }, columns: [], allPermission: [ { value: 'owner', name: '创建人' }, { value: 'anyone', name: '所有人' } ], header: { label: '标题' }, baseConfig: { dataSource: {}, viewType: '' }, aggregateTableConfig: { targetColumn: {}, statistics: [], groupBy: [] }, dataViewConfig: { viewColumns: [], sortColumn: {key: ''}, sortType: 'asc', count: 25 }, barConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''} }, lineConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''} }, pieConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} } }, scatterConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''} }, styleConfig: { visibleIndex: true }, otherConfig:{ }, description: '', filters: [], chartOption: {}, dirty: false, fetchConfig: {} }, reducers: { /** * 更新model字段值 * 1. 进入撤销重做历史 */ setField(state, action) { const { name, value } = action; let obj = {}; obj[name] = value; let newState = Object.assign({}, state, obj); return Object.assign({}, newState, {dirty: true}); }, /** * 批量更新model字段值 * 1. 进入撤销重做历史 */ setFields(state, action) { const { fields } = action; let obj = {}; fields.map(f => (obj[f.name] = f.value)); let newState = Object.assign({}, state, obj); return Object.assign({}, newState, {dirty: true}); }, /** * 更新model字段值 * 1. 不进入撤销重做历史 */ silentSetField(state, action) { const { name, value } = action; let obj = {}; obj[name] = value; let newState = Object.assign({}, state, obj); return newState; }, /** * 批量更新model字段值 * 1. 不进入撤销重做历史 */ silentSetFields(state, action) { const { fields } = action; let obj = {}; fields.map(f => (obj[f.name] = f.value)); let newState = Object.assign({}, state, obj); return newState; }, reset(state, action) { let newState = Object.assign({}, state, state.originData); return Object.assign({}, newState); }, setDirty(state, action) { const { dirty } = action; let newState = Object.assign({}, state, { dirty }); console.log(newState); return newState; } }, effects: { /** * 初始化批量更新model字段值 * 触发数据刷新、不进入撤销重做历史 */ *defaultChangeFields(action, { select, call, put }) { const { fields } = action; yield put({ type: 'silentSetFields', fields }); const { autoRefresh } = action; if(autoRefresh === undefined ? true : autoRefresh) { yield put({ type: 'fetchChartData' }); } }, /** * 更新model字段值 * 可能影响到数据刷新的model字段改变一般用该action */ *changeField(action, { select, call, put }) { const { name, value } = action; yield put({ type: 'setField', name, value }); const { autoRefresh } = action; if(autoRefresh === undefined ? true : autoRefresh) { yield put({ type: 'fetchChartData' }); } }, /** * 批量更新model字段值 */ *changeFields(action, { select, call, put }) { const { fields } = action; yield put({ type: 'setFields', fields }); const { autoRefresh } = action; if(autoRefresh === undefined ? true : autoRefresh) { yield put({ type: 'fetchChartData' }); } }, *changeDataSource(action, { select, call, put }) { const { code } = action; yield put({ type: 'remoteDataColumn', code }); }, *remoteQucikAdd(action, { select, call, put }) { try{ const { dataSource } = action; yield put({ type: 'silentSetFields', fields: [ { name: 'baseConfig', value: { dataSource: dataSource.code, viewType: '' } } ] }); const chartDesigner = yield select(state => state.present.chartDesigner); const { baseConfig, styleConfig } = chartDesigner; let body = { chartName: dataSource.name + '_未命名', dataId: baseConfig.dataSource, groupBy: baseConfig.groupBy && baseConfig.groupBy.key ? [{ columnName: baseConfig.groupBy.key, columnRamane: baseConfig.groupBy.label }] : [], createBy: 'zhuth', describes: '', style: JSON.stringify(styleConfig), chartConfig: '{}', chartType: '', }; console.log('快速新增图表', body); const res = yield call(service.fetch, { url: URLS.CHART_ADD, body: body }) console.log('快速新增图表', body, res); if(!res.err && res.data.data > 0) { yield put({ type: 'chart/fetchList', mandatory: true }); yield put({ type: 'main/redirect', path: '/chart/' + res.data.data }); // yield put({ type: 'chart/remoteDetail', code: res.data.data }); }else { message.error('新增失败: ' + (res.err || res.data.msg)); } }catch(e) { console.error(e); message.error('新增失败'); } }, /** * 复制新增 */ *remoteCopyAdd(action, { select, call, put }) { try{ yield put({ type: 'chart/remoteModify' }); const { newHeaderLabel } = action; const chartDesigner = yield select(state => state.present.chartDesigner); const { baseConfig, pieConfig, lineConfig, barConfig, scatterConfig, aggregateTableConfig, dataViewConfig, otherConfig, description, group, styleConfig } = chartDesigner; let body = { chartName: newHeaderLabel, dataId: baseConfig.dataSource, createBy: 'zhuth', describes: description || '', style: JSON.stringify(styleConfig), otherConfig: JSON.stringify(otherConfig), chartsGroup: group ? group : '-1', }; // 基本属性 if(baseConfig.viewType === 'bar') { body.chartType = 'Histogram'; body.chartConfig = JSON.stringify(barConfig); body.groupBy = barConfig.groupBy ? [{ columnName: barConfig.groupBy.key, columnRamane: barConfig.groupBy.label }] : []; }else if(baseConfig.viewType === 'pie') { body.chartType = 'Pie'; body.chartConfig = JSON.stringify(pieConfig); }else if(baseConfig.viewType === 'line') { body.chartType = 'Line'; body.chartConfig = JSON.stringify(lineConfig); body.groupBy = lineConfig.groupBy ? [{ columnName: lineConfig.groupBy.key, columnRamane: lineConfig.groupBy.label }] : []; }else if(baseConfig.viewType === 'scatter') { body.chartType = 'scatter'; body.chartConfig = JSON.stringify(scatterConfig); body.groupBy = scatterConfig.groupBy ? [{ columnName: scatterConfig.groupBy.key, columnRamane: scatterConfig.groupBy.label }] : []; }else if(baseConfig.viewType === 'aggregateTable') { body.chartType = 'population'; body.chartConfig = JSON.stringify(aggregateTableConfig); body.groupBy = aggregateTableConfig.groupBy && aggregateTableConfig.groupBy.length > 0 ? aggregateTableConfig.groupBy.map(g => { return { columnName: g.key, columnRamane: g.label } }) : []; }else if(baseConfig.viewType === 'dataView') { body.chartType = 'individual'; body.chartConfig = JSON.stringify(dataViewConfig);; }else { body.chartType = ''; body.chartConfig = JSON.stringify({}); } const res = yield call(service.fetch, { url: URLS.CHART_ADD, body: body }) console.log('复制新增', body, res); if(!res.err && res.data.code > 0) { yield put({ type: 'chart/fetchList', mandatory: true }); yield put({ type: 'main/redirect', path: '/chart/' + res.data.data , reload: true}); }else { message.error('创建副本失败: ' + (res.err || res.data.msg)); } }catch(e) { console.error(e); message.error('创建副本失败'); } }, *remoteDataColumn(action, { select, call, put }) { const code = action.code; try { const res = yield call(service.fetch, { url: URLS.DATASOURCE_QUERY_DATACOLUMNS, body: code }); console.log('获得图表关联数据源列数据', code, res); if(!res.err && res.data.code > 0) { let resData = res.data.data; let columns = resData.map((c, i) => { return { key: i, name: c.columnName, label: c.columnRaname, type: c.columnType, groupable: c.isGroup==='1'?true:false, filterable: c.isFilter==='1'?true:false, bucketizable: c.isSubsection==='1'?true:false, selection: [] } }) yield put({ type: 'silentSetField', name: 'columns', value: columns }); }else { message.error('请求列数据失败:' + (res.err || res.data.msg)); yield put({ type: 'silentSetField', name: 'columns', value: [] }); } }catch(e) { message.error('请求列数据失败'); yield put({ type: 'silentSetField', name: 'columns', value: [] }); } }, *fetchChartData(action, { select, call, put }) { const chartDesigner = yield select(state => state.present.chartDesigner); const { baseConfig } = chartDesigner; const { viewType } = baseConfig; yield put({ type: 'silentSetField', name: 'fetchConfig', value: {} }); if(viewType === 'bar') { const { barConfig } = chartDesigner; if(barConfig.xAxis.column.value && barConfig.yAxis.column.value) { yield put({ type: 'fetchBarData' }); }else { yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } }else if(viewType === 'pie') { const { pieConfig } = chartDesigner; if(pieConfig.xAxis.column.value && pieConfig.yAxis.column.value) { yield put({ type: 'fetchPieData' }); }else { yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } }else if(viewType === 'line') { const { lineConfig } = chartDesigner; if(lineConfig.xAxis.column.value && lineConfig.yAxis.column.value) { yield put({ type: 'fetchLineData' }); }else { yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } }else if(viewType === 'scatter') { const { scatterConfig } = chartDesigner; if(scatterConfig.xAxis.column.value && scatterConfig.yAxis.column.value) { yield put({ type: 'fetchScatterData' }); }else { yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } }else if(viewType === 'dataView') { const { dataViewConfig } = chartDesigner; if(dataViewConfig.viewColumns.length > 0 && dataViewConfig.sortColumn.key && dataViewConfig.sortType && dataViewConfig.count) { yield put({ type: 'fetchDataViewData' }); }else { yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } }else if(viewType === 'aggregateTable') { const { aggregateTableConfig } = chartDesigner; if(aggregateTableConfig.targetColumn.name && aggregateTableConfig.statistics.length > 0) { yield put({ type: 'fetchAggregateTableData' }); }else { yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } }else { console.log('no viewType......') } }, *fetchBarData(action, { select, call, put }) { try { const chartDesigner = yield select(state => state.present.chartDesigner); const { code, barConfig, filters } = chartDesigner; const body = { id: code, groups: barConfig.groupBy && barConfig.groupBy.key ? [barConfig.groupBy.key] : [], xAxis: { columnRename: barConfig.xAxis.column.value, columnType: barConfig.xAxis.column.type, showDataType: barConfig.xAxis.granularity.value }, yAxis: { columnRename: barConfig.yAxis.column.value, showDataType: barConfig.yAxis.gauge.value }, filters: getBodyFilters(filters) }; let res = yield call(service.fetch, { url: URLS.CHART_BAR_OPTION, body: body }); 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 }); }else { message.error('请求柱状图数据失败: ' + (res.err || res.data.msg)); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } yield put({ type: 'silentSetField', name: 'fetchConfig', value: body }); }catch(e) { console.error(e); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); message.error('请求柱状图数据失败'); } }, *fetchPieData(action, { select, call, put }) { try { const chartDesigner = yield select(state => state.present.chartDesigner); const { code, pieConfig, filters } = chartDesigner; const body = { id: code, legendData: { columnRename: pieConfig.xAxis.column.value, columnType: pieConfig.xAxis.column.type, showDataType: pieConfig.xAxis.granularity.value }, series: { columnRename: pieConfig.yAxis.column.value, columnName: pieConfig.yAxis.column.label, showDataType: pieConfig.yAxis.gauge.value }, filters: getBodyFilters(filters) }; let res = yield call(service.fetch, { url: URLS.CHART_PIE_OPTION, body: body }); 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 }); }else { message.error('请求饼图数据失败: ' + (res.err || res.data.msg)); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } yield put({ type: 'silentSetField', name: 'fetchConfig', value: body }); }catch(e) { console.error(e); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); message.error('请求饼图数据失败'); } }, *fetchLineData(action, { select, call, put }) { try { const chartDesigner = yield select(state => state.present.chartDesigner); const { code, lineConfig, filters } = chartDesigner; const body = { id: code, xAxis: { columnRename: lineConfig.xAxis.column.value, columnType: lineConfig.xAxis.column.type }, yAxis: { columnRename: lineConfig.yAxis.column.value, showDataType: lineConfig.yAxis.gauge.value }, groups: lineConfig.groupBy && lineConfig.groupBy.key ? [lineConfig.groupBy.key] : [], filters: getBodyFilters(filters) }; let res = yield call(service.fetch, { url: URLS.CHART_LINE_OPTION, body: body }); 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 }); }else { message.error('请求折线图数据失败: ' + (res.err || res.data.msg)); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } yield put({ type: 'silentSetField', name: 'fetchConfig', value: body }); }catch(e) { console.error(e); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); message.error('请求折线图数据失败'); } }, *fetchScatterData(action, { select, call, put }) { try { const chartDesigner = yield select(state => state.present.chartDesigner); const { code, scatterConfig, filters } = chartDesigner; const body = { id: code, xAxis: { columnRename: scatterConfig.xAxis.column.value, columnType: scatterConfig.xAxis.column.type }, yAxis: { columnRename: scatterConfig.yAxis.column.value, showDataType: scatterConfig.yAxis.gauge.value }, groups: scatterConfig.groupBy && scatterConfig.groupBy.key ? [scatterConfig.groupBy.key] : [], filters: getBodyFilters(filters) }; let res = yield call(service.fetch, { url: URLS.CHART_SCATTER_OPTION, body: body }); 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 }); }else { message.error('请求散点图数据失败: ' + (res.err || res.data.msg)); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } yield put({ type: 'silentSetField', name: 'fetchConfig', value: body }); }catch(e) { console.error(e); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); message.error('请求散点图数据失败'); } }, *fetchDataViewData(action, { select, call, put }) { try { const chartDesigner = yield select(state => state.present.chartDesigner); const { code, dataViewConfig, filters, styleConfig } = chartDesigner; const body = { id: code, columnListName: dataViewConfig.viewColumns.map(c => c.name), sortColumn: dataViewConfig.sortColumn.key, sort: dataViewConfig.sortType, showLine: dataViewConfig.count, filters: getBodyFilters(filters) }; let res = yield call(service.fetch, { url: URLS.CHART_DATAVIEW_OPTION, body: body }); 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 }); }else { message.error('请求列表数据失败: ' + (res.err || res.data.msg)); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } yield put({ type: 'silentSetField', name: 'fetchConfig', value: body }); }catch(e) { console.error(e); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); message.error('请求列表数据失败'); } }, *fetchAggregateTableData(action, { select, call, put }) { try { const chartDesigner = yield select(state => state.present.chartDesigner); const { code, aggregateTableConfig, filters } = chartDesigner; const { targetColumn, statistics } = aggregateTableConfig; const body = { id: code, columnName: targetColumn.name, operatorList: statistics, groupByList: aggregateTableConfig.groupBy && aggregateTableConfig.groupBy.length > 0 ? aggregateTableConfig.groupBy.map(g => g.key) : [], filters: getBodyFilters(filters) }; let res = yield call(service.fetch, { url: URLS.CHART_AGGREGATETABLE_OPTION, body: body }); 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 }); }else { message.error('请求统计数据失败: ' + (res.err || res.data.msg)); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); } yield put({ type: 'silentSetField', name: 'fetchConfig', value: body }); }catch(e) { console.error(e); yield put({ type: 'silentSetField', name: 'chartOption', value: {} }); message.error('请求统计数据失败'); } } }, subscriptions: { setup({ dispatch, history }) { return history.listen(({ pathname, query }) => { }); }, }, };