|
|
@@ -1,5 +1,25 @@
|
|
|
import html2canvas from 'html2canvas'
|
|
|
import { message } from 'antd'
|
|
|
+import * as service from '../services/index'
|
|
|
+import URLS from '../constants/url'
|
|
|
+
|
|
|
+const getViewType = function(type) {
|
|
|
+ if(type === 'Histogram') {
|
|
|
+ return 'bar';
|
|
|
+ }else if(type === 'Line') {
|
|
|
+ return 'line';
|
|
|
+ }else if(type === 'Pie') {
|
|
|
+ return 'pie';
|
|
|
+ }else if(type === 'scatter') {
|
|
|
+ return 'scatter';
|
|
|
+ }else if(type === 'population') {
|
|
|
+ return 'aggregateTable';
|
|
|
+ }else if(type === 'individual') {
|
|
|
+ return 'dataView';
|
|
|
+ }else {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
export default {
|
|
|
namespace: 'dashboardDesigner',
|
|
|
@@ -10,24 +30,26 @@ export default {
|
|
|
items: [],
|
|
|
description: '',
|
|
|
thumbnail: '',
|
|
|
- groupCode: '',
|
|
|
dirty: false,
|
|
|
editMode: true,
|
|
|
filterColumns: [],
|
|
|
filters: [],
|
|
|
+ dataSources: [],
|
|
|
+ relationColumns: [],
|
|
|
+ columnFetching: false,
|
|
|
},
|
|
|
name: '标题',
|
|
|
defaultLayout: { x: 0, y: 50, w: 12, h: 6, minW: 2, maxW: 12, minH: 1 },
|
|
|
- parameters: {
|
|
|
- }, //全局可用参数
|
|
|
items: [],
|
|
|
description: '',
|
|
|
thumbnail: '',
|
|
|
- groupCode: '',
|
|
|
dirty: false,
|
|
|
editMode: true,
|
|
|
filterColumns: [],
|
|
|
- filters: []
|
|
|
+ filters: [],
|
|
|
+ dataSources: [], // 图表关联的所有数据源
|
|
|
+ relationColumns: [], // 自定义的列
|
|
|
+ columnFetching: false,
|
|
|
},
|
|
|
|
|
|
reducers: {
|
|
|
@@ -59,25 +81,68 @@ export default {
|
|
|
let newState = Object.assign({}, state, obj);
|
|
|
return Object.assign({}, newState, {dirty: true});
|
|
|
},
|
|
|
+ addChart(state, action) {
|
|
|
+ let { items, defaultLayout } = state;
|
|
|
+ const { chart } = action;
|
|
|
+
|
|
|
+ items = items.concat([{
|
|
|
+ code: chart.code,
|
|
|
+ chartCode: chart.code,
|
|
|
+ name: chart.name,
|
|
|
+ dataSourceCode: chart.dataSourceCode+'',
|
|
|
+ dataSourceName: chart.dataSourceName,
|
|
|
+ viewType: 'chart',
|
|
|
+ layout: defaultLayout,
|
|
|
+ }]);
|
|
|
+ return Object.assign({}, state, {items, dirty: true});
|
|
|
+ },
|
|
|
addCharts(state, action) {
|
|
|
let { items, defaultLayout } = state;
|
|
|
const { charts } = action;
|
|
|
|
|
|
items = items.concat(charts.map(c => ({
|
|
|
code: c.code,
|
|
|
- viewType: 'chart',
|
|
|
+ chartCode: c.code,
|
|
|
name: c.name,
|
|
|
+ viewType: 'chart',
|
|
|
+ dataSourceCode: c.dataSourceCode+'',
|
|
|
+ dataSourceName: c.dataSourceName,
|
|
|
layout: defaultLayout,
|
|
|
- chartCode: c.code
|
|
|
})));
|
|
|
return Object.assign({}, state, {items, dirty: true});
|
|
|
},
|
|
|
deleteItem(state, action) {
|
|
|
- let { items, dirty } = state;
|
|
|
+ let { items, dataSources, relationColumns, dirty } = state;
|
|
|
const { item } = action;
|
|
|
- let newItems = items.filter((i) => i.code !== item.code);
|
|
|
- dirty = items.length !== newItems.length;
|
|
|
- return { ...state, dirty: dirty, items: newItems };
|
|
|
+ let count = 0;
|
|
|
+ let targetIndex = -1;
|
|
|
+ for(let i = 0; i < items.length; i++) {
|
|
|
+ let tempItem = items[i];
|
|
|
+ if(tempItem.dataSourceCode === item.dataSourceCode) {
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+ if(tempItem.code === item.code) {
|
|
|
+ targetIndex = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(count === 1) {
|
|
|
+ // 找到只有被删除的item使用的数据源并删除
|
|
|
+ let idx = dataSources.findIndex(d => d.code === item.dataSourceCode);
|
|
|
+ dataSources.splice(idx, 1);
|
|
|
+ // 同时删除已定义的关联字段
|
|
|
+ relationColumns.forEach(rc => {
|
|
|
+ rc.relations.forEach((r, x) => {
|
|
|
+ if(r.dataSourceCode === item.dataSourceCode) {
|
|
|
+ rc.relations.splice(x, 1);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if(targetIndex !== -1) {
|
|
|
+ items.splice(targetIndex, 1);
|
|
|
+ }
|
|
|
+ return { ...state, dirty: dirty, items, dataSources };
|
|
|
},
|
|
|
addRichText(state, action) {
|
|
|
let { items, defaultLayout } = state;
|
|
|
@@ -127,15 +192,101 @@ export default {
|
|
|
setEditMode(state, action) {
|
|
|
const { checked } = action;
|
|
|
return { ...state, editMode: checked };
|
|
|
+ },
|
|
|
+ addRelationColumn(state, action) {
|
|
|
+ const { relationColumns } = state;
|
|
|
+ relationColumns.push({
|
|
|
+ code: Math.random()+'',
|
|
|
+ name: '新字段',
|
|
|
+ relations: []
|
|
|
+ });
|
|
|
+ return { ...state, relationColumns, dirty: true };
|
|
|
+ },
|
|
|
+ deleteRelationColumn(state, action) {
|
|
|
+ const { code } = action;
|
|
|
+ const { relationColumns } = state;
|
|
|
+ let index = relationColumns.findIndex(r => r.code === code);
|
|
|
+ relationColumns.splice(index, 1);
|
|
|
+ console.log(relationColumns);
|
|
|
+ return { ...state, relationColumns, dirty: true };
|
|
|
+ },
|
|
|
+ setRelationColumn(state, action) {
|
|
|
+ const { code, relationColumn } = action
|
|
|
+ const { relationColumns } = state;
|
|
|
+ let index = relationColumns.findIndex(r => r.code === code);
|
|
|
+ relationColumns[index] = relationColumn;
|
|
|
+ return { ...state, relationColumns, dirty: true };
|
|
|
+ },
|
|
|
+ setChartFilters(state, action) {
|
|
|
+ let { items } = state;
|
|
|
+ const { chartCode, filters } = action;
|
|
|
+ let idx = items.findIndex(i => i.chartCode === chartCode);
|
|
|
+ if(idx !== -1) {
|
|
|
+ items[idx] = { ...items[idx], filters }
|
|
|
+ }
|
|
|
+ return { ...state, items };
|
|
|
+ },
|
|
|
+ addDataSource(state, action) {
|
|
|
+ let { dataSources } = state;
|
|
|
+ const { dataSource } = action;
|
|
|
+ dataSources.findIndex(d => d.code === dataSource.code) === -1 && dataSources.push(dataSource);
|
|
|
+ console.log(dataSources);
|
|
|
+ return { ...state, dataSources };
|
|
|
}
|
|
|
},
|
|
|
|
|
|
effects: {
|
|
|
+ *remoteGetColumns(action, { call, put, select }) {
|
|
|
+ const { dataSourceCode, mandatory } = action;
|
|
|
+ const dashboardDesigner = yield select(state => state.present.dashboardDesigner);
|
|
|
+ const { dataSources } = dashboardDesigner;
|
|
|
+ const body = dataSourceCode;
|
|
|
+ let idx = dataSources.findIndex(d => d.code === dataSourceCode);
|
|
|
+ if(!mandatory && dataSources[idx].columns && dataSources[idx].columns.length > 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ try {
|
|
|
+ yield put({ type: 'silentSetField', field: 'columnFetching', value: true });
|
|
|
+ const res = yield call(service.fetch, {
|
|
|
+ url: URLS.DATASOURCE_QUERY_DATACOLUMNS,
|
|
|
+ body: body
|
|
|
+ });
|
|
|
+ yield put({ type: 'silentSetField', field: 'columnFetching', value: false });
|
|
|
+ console.log('获得列数据', body, 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: []
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ dataSources[idx] = { ...dataSources[idx], columns }
|
|
|
+ yield put({ type: 'silentSetField', name: 'dataSources', value: dataSources });
|
|
|
+ }else {
|
|
|
+ message.error('请求列数据失败:' + (res.err || res.data.msg));
|
|
|
+ yield put({ type: 'silentSetField', name: 'dataSources', value: [] });
|
|
|
+ }
|
|
|
+ }catch(e) {
|
|
|
+ console.log(e, body);
|
|
|
+ message.error('请求列数据失败');
|
|
|
+ }
|
|
|
+ },
|
|
|
*saveWithThumbnail(action, {put, call}) {
|
|
|
let thumbnail;
|
|
|
yield call(async ()=> {
|
|
|
try {
|
|
|
- await html2canvas(document.getElementsByClassName('dashboard-content')[0]).then(
|
|
|
+ await html2canvas(document.getElementsByClassName('viewlayout')[0]).then(
|
|
|
function(canvas){
|
|
|
thumbnail = canvas.toDataURL('image/png', 1.0);
|
|
|
}
|