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', state: { originData: { code: null, name: '标题', items: [], description: '', thumbnail: '', 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 }, items: [], description: '', thumbnail: '', dirty: false, editMode: true, filterColumns: [], filters: [], dataSources: [], // 图表关联的所有数据源 relationColumns: [], // 自定义的列 columnFetching: false, }, reducers: { silentSetField(state, action) { const { name, value } = action; let obj = {}; obj[name] = value; let newState = Object.assign({}, state, obj); return newState; }, setField(state, action) { const { name, value } = action; let obj = {}; obj[name] = value; let newState = Object.assign({}, state, obj); return Object.assign({}, newState, {dirty: true}); }, silentSetFields(state, action) { const { fields } = action; let obj = {}; fields.map(f => (obj[f.name] = f.value)); let newState = Object.assign({}, state, obj); return newState; }, 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}); }, 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, chartCode: c.code, name: c.name, viewType: 'chart', dataSourceCode: c.dataSourceCode+'', dataSourceName: c.dataSourceName, layout: defaultLayout, }))); return Object.assign({}, state, {items, dirty: true}); }, deleteItem(state, action) { let { items, dataSources, relationColumns, dirty } = state; const { item } = action; 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; items.push({ code: Math.random(), viewType: 'richText', name: '', layout: defaultLayout }); return Object.assign({}, state, {items, dirty: true}); }, changeLayout(state, action) { const { layout } = action; let { items, dirty } = state; const ly = ['x', 'y', 'w', 'h']; for(let i = 0; i < items.length; i++) { if(layout[i]) { // 非删除引起 for(let j = 0; j < ly.length; j ++) { if(items[i].layout[ly[j]] !== layout[i][ly[j]]) { dirty = true; items[i].layout[ly[j]] = layout[i][ly[j]]; } } }else { // 删除引起 dirty = true; } } return Object.assign({}, state, {items, dirty}); }, modifyItem(state, action) { let { fields, dirty } = action; let { items } = state; for(let i = 0; i < items.length; i++) { if(items[i].code === fields.code) { for(let k in fields) { items[i][k] = fields[k]; dirty = true; } } } return Object.assign({}, state, {items, dirty}); }, reset(state, action) { let newState = Object.assign({}, state, state.originData); return Object.assign({}, newState); }, 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('viewlayout')[0]).then( function(canvas){ thumbnail = canvas.toDataURL('image/png', 1.0); } ) }catch (e) { return null; } }); try { yield put.resolve({ type: 'setField', name: 'thumbnail', value: thumbnail }) yield put.resolve({ type: 'dashboard/remoteModify' }) }catch (e){ message.error('保存失败'); } } }, subscription: { }, };