chartDesigner.js 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. import { message } from 'antd'
  2. import * as service from '../services/index'
  3. import URLS from '../constants/url'
  4. import parseChartOption from './parseChartOption'
  5. import { deepAssign } from '../utils/baseUtils'
  6. import moment from 'moment'
  7. function getBodyFilters(filters) {
  8. let bodyFilters = [];
  9. filters.filter(f => f.using).forEach(f => {
  10. let { name, operator, type, value1, value2 } = f;
  11. if(((type === 'index' || type === 'string') && !!value1) || // 因为数字类型会生成数字字符串,所以为0也是可以正常传入条件的
  12. ((type === 'scale' || type === 'time' || type === 'ordinal') && (operator === 'between' ? (!!value1 && !!value2) : (!!value1))) ||
  13. (type === 'categorical' &&
  14. (operator === 'contain' || operator === 'notContain' ?
  15. (value1 && value1.length > 0) : (!!value1)
  16. )
  17. )) {
  18. let bodyFilter = {
  19. columnName: name,
  20. columnType: type,
  21. symbol: operator,
  22. value: value1
  23. };
  24. if(type === 'scale' && operator === 'between') {
  25. bodyFilter['value'] = value1 + ',' + value2;
  26. }else if(type === 'time') {
  27. let v1 = value1.dynamic ? value1.name : moment(value1).format('YYYY-MM-DD');
  28. let v2 = value2.dynamic ? value2.name : moment(value2).format('YYYY-MM-DD');
  29. if(operator === 'between') {
  30. bodyFilter['value'] = v1 + ',' + v2;
  31. }else {
  32. bodyFilter['value'] = v1;
  33. }
  34. }else if(type === 'categorical' && (operator === 'contain' || operator === 'notContain')) {
  35. bodyFilter['value'] = JSON.stringify(value1);
  36. }
  37. bodyFilters.push(bodyFilter);
  38. }
  39. });
  40. return bodyFilters;
  41. }
  42. export default {
  43. namespace: 'chartDesigner',
  44. state: {
  45. originData: {
  46. code: null,
  47. creatorCode: null,
  48. creatorName: null,
  49. header: { label: '无标题' },
  50. columns: [],
  51. defaultBarThreshold: 20,
  52. defaultLineThreshold: 200,
  53. defaultPieThreshold: 20,
  54. defaultScatterThreshold: 1000,
  55. baseConfig: { dataSource: { code: '' }, viewType: '' },
  56. aggregateTableConfig: { targetColumn: {}, statistics: [], groupBy: [] },
  57. dataViewConfig: { viewColumns: [], sortColumn: {key: ''}, sortType: 'asc' },
  58. barConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''}, sortTarget: 'x', sortType: 'ASC', threshold: 20 },
  59. lineConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''}, threshold: 200 },
  60. pieConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, threshold: 20 },
  61. scatterConfig: { xAxis: { column: {}, granularity: {} }, yAxis: { column: {}, gauge: {} }, groupBy: {key:''}, threshold: 1000 },
  62. theme: 'default',
  63. styleConfig: {},
  64. otherConfig:{},
  65. description: '',
  66. filters: [],
  67. chartOption: {},
  68. dirty: false,
  69. fetchConfig: {},
  70. demo: false,
  71. thumbnail: null,
  72. },
  73. },
  74. reducers: {
  75. /**
  76. * 更新model字段值
  77. * 1. 改变dirty
  78. */
  79. setField(state, action) {
  80. const { name, value } = action;
  81. let obj = {};
  82. obj[name] = value;
  83. return Object.assign({}, state, obj, { dirty: true });
  84. },
  85. /**
  86. * 批量更新model字段值
  87. * 1. 改变dirty
  88. */
  89. setFields(state, action) {
  90. const { fields } = action;
  91. let obj = {};
  92. fields.map(f => (obj[f.name] = f.value));
  93. return Object.assign({}, state, obj, { dirty: true });
  94. },
  95. /**
  96. * 更新model字段值
  97. * 1. 不改变dirty
  98. */
  99. silentSetField(state, action) {
  100. const { name, value } = action;
  101. let obj = {};
  102. obj[name] = value;
  103. let newState = Object.assign({}, state, obj);
  104. return newState;
  105. },
  106. /**
  107. * 批量更新model字段值
  108. * 1. 不改变dirty
  109. */
  110. silentSetFields(state, action) {
  111. const { fields } = action;
  112. let obj = {};
  113. fields.map(f => (obj[f.name] = f.value));
  114. let newState = Object.assign({}, state, obj);
  115. return newState;
  116. },
  117. reset(state, action) {
  118. let newState = Object.assign({}, state, state.originData);
  119. return Object.assign({}, newState);
  120. },
  121. setDirty(state, action) {
  122. const { dirty } = action;
  123. return Object.assign({}, state, { dirty });
  124. }
  125. },
  126. effects: {
  127. *changeField(action, { select, call, put }) {
  128. const { name, value } = action;
  129. yield put({ type: 'setField', name, value });
  130. const { autoRefresh } = action;
  131. if(autoRefresh === undefined ? true : autoRefresh) {
  132. yield put({ type: 'fetchChartData' });
  133. }
  134. },
  135. *silentChangeField(action, { select, call, put }) {
  136. const { name, value } = action;
  137. yield put({ type: 'silentSetField', name, value });
  138. },
  139. *changeFields(action, { select, call, put }) {
  140. const { fields } = action;
  141. yield put({ type: 'setFields', fields });
  142. const { autoRefresh } = action;
  143. if(autoRefresh === undefined ? true : autoRefresh) {
  144. yield put({ type: 'fetchChartData' });
  145. }
  146. },
  147. *silentChangeFields(action, { select, call, put }) {
  148. const { fields } = action;
  149. yield put({ type: 'silentSetFields', fields });
  150. },
  151. *changeDataSource(action, { select, call, put }) {
  152. const { dataSource } = action;
  153. const chartDesigner = yield select(state => state.present.chartDesigner);
  154. const { baseConfig } = chartDesigner;
  155. yield put({ type: 'changeField', name: 'baseConfig', value: { ...baseConfig, dataSource } });
  156. yield put({ type: 'remoteDataColumn', code: dataSource.code });
  157. },
  158. *silentChangeDataSource(action, { select, call, put }) {
  159. const { dataSource } = action;
  160. const chartDesigner = yield select(state => state.present.chartDesigner);
  161. const { baseConfig } = chartDesigner;
  162. yield put({ type: 'silentChangeField', name: 'baseConfig', value: { ...baseConfig, dataSource } });
  163. yield put({ type: 'remoteDataColumn', code: dataSource.code });
  164. },
  165. *remoteQucikAdd(action, { select, call, put }) {
  166. try{
  167. const { dataSource, group } = action;
  168. yield put({ type: 'silentSetFields', fields: [
  169. { name: 'baseConfig', value: { dataSource: dataSource.code, viewType: '' } }
  170. ] });
  171. let body = {
  172. chartName: dataSource.name + '_未命名',
  173. dataId: dataSource.code,
  174. describes: '',
  175. chartConfig: '{}',
  176. chartType: '',
  177. chartsGroup: group ? group.code : '-1',
  178. };
  179. yield put({ type: 'chart/setField', name: 'listLoading', value: true });
  180. const res = yield call(service.fetch, {
  181. url: URLS.CHART_ADD,
  182. body: body
  183. })
  184. yield put({ type: 'chart/setField', name: 'listLoading', value: false });
  185. if(res.data > 0) {
  186. yield put({ type: 'chart/fetchList', mandatory: true });
  187. yield put({ type: 'main/redirect', path: '/chart/' + res.data });
  188. // yield put({ type: 'chart/remoteDetail', code: res.data });
  189. }else {
  190. message.error('新增失败: ' + res.msg);
  191. }
  192. }catch(e) {
  193. message.error('新增失败: ' + e.message);
  194. }
  195. },
  196. /**
  197. * 复制新增
  198. */
  199. *remoteCopyAdd(action, { select, call, put }) {
  200. try{
  201. yield put({ type: 'chart/remoteModify' });
  202. const { newHeaderLabel } = action;
  203. const chartDesigner = yield select(state => state.present.chartDesigner);
  204. const { filters, baseConfig, pieConfig, lineConfig, aggregateTableConfig, dataViewConfig,
  205. barConfig, scatterConfig, otherConfig, description, group, chartOption, fetchConfig, styleConfig } = chartDesigner;
  206. let body = {
  207. filters: JSON.stringify(filters),
  208. chartName: newHeaderLabel,
  209. dataId: baseConfig.dataSource.code,
  210. describes: description || '',
  211. style: JSON.stringify(styleConfig),
  212. otherConfig: JSON.stringify(otherConfig),
  213. chartsGroup: group+'' ? group : '-1',
  214. chartOption: JSON.stringify(chartOption),
  215. fetchConfig: JSON.stringify(fetchConfig),
  216. }; // 基本属性
  217. if(baseConfig.viewType === 'bar') {
  218. body.chartType = 'Histogram';
  219. body.chartConfig = JSON.stringify(barConfig);
  220. }else if(baseConfig.viewType === 'pie') {
  221. body.chartType = 'Pie';
  222. body.chartConfig = JSON.stringify(pieConfig);
  223. }else if(baseConfig.viewType === 'line') {
  224. body.chartType = 'Line';
  225. body.chartConfig = JSON.stringify(lineConfig);
  226. }else if(baseConfig.viewType === 'scatter') {
  227. body.chartType = 'scatter';
  228. body.chartConfig = JSON.stringify(scatterConfig);
  229. }else if(baseConfig.viewType === 'aggregateTable') {
  230. body.chartType = 'population';
  231. body.chartConfig = JSON.stringify(aggregateTableConfig);
  232. }else if(baseConfig.viewType === 'dataView') {
  233. body.chartType = 'individual';
  234. body.chartConfig = JSON.stringify(dataViewConfig);;
  235. }else {
  236. body.chartType = '';
  237. body.chartConfig = JSON.stringify({});
  238. }
  239. const res = yield call(service.fetch, {
  240. url: URLS.CHART_ADD,
  241. body: body
  242. })
  243. if(res.code > 0) {
  244. yield put({ type: 'chart/fetchList', mandatory: true });
  245. yield put({ type: 'main/redirect', path: '/chart/' + res.data , reload: true});
  246. }else {
  247. message.error('创建副本失败: ' + res.msg);
  248. }
  249. }catch(e) {
  250. message.error('创建副本失败: ' + e.message);
  251. }
  252. },
  253. *remoteDataColumn(action, { select, call, put }) {
  254. const code = action.code;
  255. try {
  256. const res = yield call(service.fetch, {
  257. url: URLS.DATASOURCE_QUERY_DATACOLUMNS,
  258. body: code
  259. });
  260. if(res.code > 0) {
  261. let resData = res.data;
  262. let columns = resData.map((c, i) => {
  263. return {
  264. key: i,
  265. name: c.columnName,
  266. label: c.columnRaname,
  267. type: c.columnType,
  268. groupable: c.isGroup==='1'?true:false,
  269. filterable: c.isFilter==='1'?true:false,
  270. bucketizable: c.isSubsection==='1'?true:false,
  271. selection: []
  272. }
  273. })
  274. yield put({ type: 'silentSetField', name: 'columns', value: columns });
  275. yield put({ type: 'updateColumns' });
  276. }else {
  277. message.error('请求列数据失败:' + res.msg);
  278. yield put({ type: 'silentSetField', name: 'columns', value: [] });
  279. }
  280. }catch(e) {
  281. message.error('请求列数据失败: ' + e.message);
  282. yield put({ type: 'silentSetField', name: 'columns', value: [] });
  283. }
  284. },
  285. // 因为数据源列字段可能发生重命名,需要替换到最新的列
  286. *updateColumns(action, { select, call, put }) {
  287. const chartDesigner = yield select(state => state.present.chartDesigner);
  288. const { columns, baseConfig } = chartDesigner;
  289. const { viewType } = baseConfig;
  290. try {
  291. if(viewType === 'bar') {
  292. const { barConfig } = chartDesigner;
  293. const { xAxis, yAxis, groupBy } = barConfig;
  294. const newXAxisColumn = columns.find(c => c.name === xAxis.column.value);
  295. const newYAxisColumn = columns.find(c => c.name === yAxis.column.value);
  296. const newGroupByColumn = groupBy ? columns.find(c => c.name === groupBy.key) : null;
  297. let fields = {};
  298. newXAxisColumn ? fields.xAxis = { column: { label: newXAxisColumn.label, type: newXAxisColumn.type } } : void(0);
  299. newYAxisColumn ? fields.yAxis = { column: { label: newYAxisColumn.label, type: newYAxisColumn.type } } : void(0);
  300. newGroupByColumn ? fields.groupBy = { label: newGroupByColumn.label, type: newGroupByColumn.type } :void(0);
  301. yield put({ type: 'silentSetField', name: 'barConfig', value: deepAssign(barConfig, { ...fields }) });
  302. }else if(viewType === 'line') {
  303. const { lineConfig } = chartDesigner;
  304. const { xAxis, yAxis, groupBy } = lineConfig;
  305. const newXAxisColumn = columns.find(c => c.name === xAxis.column.value);
  306. const newYAxisColumn = columns.find(c => c.name === yAxis.column.value);
  307. const newGroupByColumn = groupBy ? columns.find(c => c.name === groupBy.key) : null;
  308. let fields = {};
  309. newXAxisColumn ? fields.xAxis = { column: { label: newXAxisColumn.label, type: newXAxisColumn.type } } : void(0);
  310. newYAxisColumn ? fields.yAxis = { column: { label: newYAxisColumn.label, type: newYAxisColumn.type } } : void(0);
  311. newGroupByColumn ? fields.groupBy = { label: newGroupByColumn.label, type: newGroupByColumn.type } :void(0);
  312. yield put({ type: 'silentSetField', name: 'lineConfig', value: deepAssign(lineConfig, { ...fields }) });
  313. }else if(viewType === 'pie') {
  314. const { pieConfig } = chartDesigner;
  315. const { xAxis, yAxis } = pieConfig;
  316. const newXAxisColumn = columns.find(c => c.name === xAxis.column.value);
  317. const newYAxisColumn = columns.find(c => c.name === yAxis.column.value);
  318. let fields = {};
  319. newXAxisColumn ? fields.xAxis = { column: { label: newXAxisColumn.label, type: newXAxisColumn.type } } : void(0);
  320. newYAxisColumn ? fields.yAxis = { column: { label: newYAxisColumn.label, type: newYAxisColumn.type } } : void(0);
  321. yield put({ type: 'silentSetField', name: 'pieConfig', value: deepAssign(pieConfig, { ...fields }) });
  322. }else if(viewType === 'scatter') {
  323. const { scatterConfig } = chartDesigner;
  324. const { xAxis, yAxis, groupBy } = scatterConfig;
  325. const newXAxisColumn = columns.find(c => c.name === xAxis.column.value);
  326. const newYAxisColumn = columns.find(c => c.name === yAxis.column.value);
  327. const newGroupByColumn = groupBy ? columns.find(c => c.name === groupBy.key) : null;
  328. let fields = {};
  329. newXAxisColumn ? fields.xAxis = { column: { label: newXAxisColumn.label, type: newXAxisColumn.type } } : void(0);
  330. newYAxisColumn ? fields.yAxis = { column: { label: newYAxisColumn.label, type: newYAxisColumn.type } } : void(0);
  331. newGroupByColumn ? fields.groupBy = { label: newGroupByColumn.label, type: newGroupByColumn.type } :void(0);
  332. yield put({ type: 'silentSetField', name: 'scatterConfig', value: deepAssign(scatterConfig, { ...fields }) });
  333. }else if(viewType === 'dataView') {
  334. const { dataViewConfig } = chartDesigner;
  335. const { sortColumn, viewColumns } = dataViewConfig;
  336. let fields = {};
  337. const newSortColumn = columns.find(c => c.name === sortColumn.key);
  338. let arr = viewColumns.map(v => {
  339. const newViewColumn = columns.find(c => c.name === v.name);
  340. return newViewColumn ? { label: newViewColumn.label, type: newViewColumn.type } : {};
  341. });
  342. newSortColumn ? fields.sortColumn = { label: newSortColumn.label, type: newSortColumn.type } : void(0);
  343. fields.viewColumns = arr;
  344. yield put({ type: 'silentSetField', name: 'dataViewConfig', value: deepAssign(dataViewConfig, { ...fields }) });
  345. }else if(viewType === 'aggregateTable') {
  346. const { aggregateTableConfig } = chartDesigner;
  347. const { groupBy, targetColumn } = aggregateTableConfig;
  348. let fields = {};
  349. const newTargetColumn = columns.find(c => c.name === targetColumn.name);
  350. let arr = groupBy ? groupBy.map(g => {
  351. const newGroupByColumn = columns.find(c => c.name === g.key);
  352. return newGroupByColumn ? { label: newGroupByColumn.label, type: newGroupByColumn.type } : {};
  353. }) : [];
  354. newTargetColumn ? fields.targetColumn = { label: newTargetColumn.label, type: newTargetColumn.type } : void(0);
  355. fields.groupBy = arr;
  356. yield put({ type: 'silentSetField', name: 'aggregateTableConfig', value: deepAssign(aggregateTableConfig, { ...fields }) });
  357. }
  358. const { filters } = chartDesigner;
  359. let fields = filters.map(f => {
  360. const newFilterColumn = columns.find(c => c.name === f.name);
  361. return newFilterColumn ? { label: newFilterColumn.label, type: newFilterColumn.type } : {};
  362. });
  363. yield put({ type: 'silentSetField', name: 'filters', value: deepAssign(filters, fields) });
  364. }catch(e) {
  365. console.error(e.message);
  366. }
  367. },
  368. *fetchChartData(action, { select, call, put }) {
  369. const chartDesigner = yield select(state => state.present.chartDesigner);
  370. const { baseConfig } = chartDesigner;
  371. const { viewType } = baseConfig;
  372. const { page, pageSize } = action;
  373. try{
  374. yield put({ type: 'silentSetField', name: 'fetchConfig', value: {} });
  375. if(viewType === 'bar') {
  376. const { barConfig } = chartDesigner;
  377. if(barConfig.xAxis.column.value && barConfig.yAxis.column.value) {
  378. yield put({ type: 'fetchBarData' });
  379. }else {
  380. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  381. }
  382. }else if(viewType === 'pie') {
  383. const { pieConfig } = chartDesigner;
  384. if(pieConfig.xAxis.column.value && pieConfig.yAxis.column.value) {
  385. yield put({ type: 'fetchPieData' });
  386. }else {
  387. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  388. }
  389. }else if(viewType === 'line') {
  390. const { lineConfig } = chartDesigner;
  391. if(lineConfig.xAxis.column.value && lineConfig.yAxis.column.value) {
  392. yield put({ type: 'fetchLineData' });
  393. }else {
  394. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  395. }
  396. }else if(viewType === 'scatter') {
  397. const { scatterConfig } = chartDesigner;
  398. if(scatterConfig.xAxis.column.value && scatterConfig.yAxis.column.value) {
  399. yield put({ type: 'fetchScatterData' });
  400. }else {
  401. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  402. }
  403. }else if(viewType === 'dataView') {
  404. const { dataViewConfig } = chartDesigner;
  405. if(dataViewConfig.viewColumns.length > 0) {
  406. yield put({ type: 'fetchDataViewData', page, pageSize });
  407. // yield put({ type: 'fetchDataViewData' }); // dataView不需要在这里触发数据请求,组件在计算完pageSize后会自动发起数据请求
  408. }else {
  409. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  410. }
  411. }else if(viewType === 'aggregateTable') {
  412. const { aggregateTableConfig } = chartDesigner;
  413. if(aggregateTableConfig.targetColumn.name && aggregateTableConfig.statistics.length > 0) {
  414. yield put({ type: 'fetchAggregateTableData' });
  415. }else {
  416. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  417. }
  418. }else {
  419. console.log('no viewType......')
  420. }
  421. }catch(e) {
  422. message.error('加载数据错误: ' + e.message);
  423. }
  424. },
  425. *fetchBarData(action, { select, call, put }) {
  426. try {
  427. const chartDesigner = yield select(state => state.present.chartDesigner);
  428. const { code, barConfig, filters, theme, styleConfig, defaultBarThreshold } = chartDesigner;
  429. const { groupBy, xAxis, yAxis, sortTarget, sortType, threshold } = barConfig;
  430. const body = {
  431. id: code,
  432. groups: groupBy && groupBy.key ? [groupBy.key] : [],
  433. xAxis: {
  434. columnRename: xAxis.column.value,
  435. columnType: xAxis.column.type,
  436. showDataType: xAxis.granularity.value
  437. },
  438. yAxis: {
  439. columnRename: yAxis.column.value,
  440. columnType: yAxis.column.type,
  441. showDataType: yAxis.gauge.value
  442. },
  443. filters: getBodyFilters(filters),
  444. sort: groupBy && groupBy.key ? undefined : (sortTarget ? (sortTarget === 'y' ? yAxis.column.value : xAxis.column.value) : xAxis.column.value),
  445. rule: groupBy && groupBy.key ? undefined : (sortType || 'ASC'),
  446. maxCount: threshold || defaultBarThreshold
  447. };
  448. let res = yield call(service.fetch, {
  449. url: URLS.CHART_BAR_OPTION,
  450. body: body,
  451. timeout: 30000
  452. });
  453. if(res.code > 0) {
  454. let option = parseChartOption('bar', res.data, barConfig, theme, styleConfig.bar || {});
  455. yield put({ type: 'silentSetField', name: 'chartOption', value: option });
  456. }else {
  457. message.error('请求柱状图数据失败: ' + res.msg);
  458. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  459. }
  460. yield put({ type: 'silentSetField', name: 'fetchConfig', value: body });
  461. }catch(e) {
  462. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  463. message.error('请求柱状图数据失败: ' + e.message);
  464. }
  465. },
  466. *fetchPieData(action, { select, call, put }) {
  467. try {
  468. const chartDesigner = yield select(state => state.present.chartDesigner);
  469. const { code, pieConfig, filters, theme, styleConfig, defaultPieThreshold } = chartDesigner;
  470. const body = {
  471. id: code,
  472. legendData: {
  473. columnRename: pieConfig.xAxis.column.value,
  474. columnType: pieConfig.xAxis.column.type,
  475. showDataType: pieConfig.xAxis.granularity.value
  476. },
  477. series: {
  478. columnRename: pieConfig.yAxis.column.value,
  479. columnType: pieConfig.yAxis.column.type,
  480. columnName: pieConfig.yAxis.column.label,
  481. showDataType: pieConfig.yAxis.gauge.value
  482. },
  483. filters: getBodyFilters(filters),
  484. maxCount: pieConfig.threshold || defaultPieThreshold
  485. };
  486. let res = yield call(service.fetch, {
  487. url: URLS.CHART_PIE_OPTION,
  488. body: body,
  489. timeout: 30000
  490. });
  491. if(res.code > 0) {
  492. let option = parseChartOption('pie', res.data, pieConfig, theme, styleConfig.pie || {});
  493. yield put({ type: 'silentSetField', name: 'chartOption', value: option });
  494. }else {
  495. message.error('请求饼图数据失败: ' + res.msg);
  496. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  497. }
  498. yield put({ type: 'silentSetField', name: 'fetchConfig', value: body });
  499. }catch(e) {
  500. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  501. message.error('请求饼图数据失败: ' + e.message);
  502. }
  503. },
  504. *fetchLineData(action, { select, call, put }) {
  505. try {
  506. const chartDesigner = yield select(state => state.present.chartDesigner);
  507. const { code, lineConfig, filters, theme, styleConfig, defaultLineThreshold } = chartDesigner;
  508. const body = {
  509. id: code,
  510. xAxis: {
  511. columnRename: lineConfig.xAxis.column.value,
  512. columnType: lineConfig.xAxis.column.type,
  513. showDataType: lineConfig.xAxis.granularity.value
  514. },
  515. yAxis: {
  516. columnRename: lineConfig.yAxis.column.value,
  517. columnType: lineConfig.yAxis.column.type,
  518. showDataType: lineConfig.yAxis.gauge.value
  519. },
  520. groups: lineConfig.groupBy && lineConfig.groupBy.key ? [lineConfig.groupBy.key] : [],
  521. filters: getBodyFilters(filters),
  522. maxCount: lineConfig.threshold || defaultLineThreshold
  523. };
  524. let res = yield call(service.fetch, {
  525. url: URLS.CHART_LINE_OPTION,
  526. body: body,
  527. timeout: 30000
  528. });
  529. if(res.code > 0) {
  530. let option = parseChartOption('line', res.data, lineConfig, theme, styleConfig.line || {});
  531. yield put({ type: 'silentSetField', name: 'chartOption', value: option });
  532. }else {
  533. message.error('请求折线图数据失败: ' + res.msg);
  534. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  535. }
  536. yield put({ type: 'silentSetField', name: 'fetchConfig', value: body });
  537. }catch(e) {
  538. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  539. message.error('请求折线图数据失败: ' + e.message);
  540. }
  541. },
  542. *fetchScatterData(action, { select, call, put }) {
  543. try {
  544. const chartDesigner = yield select(state => state.present.chartDesigner);
  545. const { code, scatterConfig, filters, theme, styleConfig, defaultScatterThreshold } = chartDesigner;
  546. const body = {
  547. id: code,
  548. xAxis: {
  549. columnRename: scatterConfig.xAxis.column.value,
  550. columnType: scatterConfig.xAxis.column.type
  551. },
  552. yAxis: {
  553. columnRename: scatterConfig.yAxis.column.value,
  554. columnType: scatterConfig.yAxis.column.type,
  555. showDataType: scatterConfig.yAxis.gauge.value
  556. },
  557. groups: scatterConfig.groupBy && scatterConfig.groupBy.key ? [scatterConfig.groupBy.key] : [],
  558. filters: getBodyFilters(filters),
  559. maxCount: scatterConfig.threshold || defaultScatterThreshold
  560. };
  561. let res = yield call(service.fetch, {
  562. url: URLS.CHART_SCATTER_OPTION,
  563. body: body,
  564. timeout: 30000
  565. });
  566. if(res.code > 0) {
  567. let option = parseChartOption('scatter', res.data, scatterConfig, theme, styleConfig.scatter || {});
  568. yield put({ type: 'silentSetField', name: 'chartOption', value: option });
  569. }else {
  570. message.error('请求散点图数据失败: ' + res.msg);
  571. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  572. }
  573. yield put({ type: 'silentSetField', name: 'fetchConfig', value: body });
  574. }catch(e) {
  575. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  576. message.error('请求散点图数据失败: ' + e.message);
  577. }
  578. },
  579. *fetchDataViewData(action, { select, call, put }) {
  580. try {
  581. const chartDesigner = yield select(state => state.present.chartDesigner);
  582. const { code, dataViewConfig, filters, theme, styleConfig } = chartDesigner;
  583. const { page, pageSize } = action;
  584. const body = {
  585. id: code,
  586. columnListName: dataViewConfig.viewColumns.map(c => c.name),
  587. sortColumn: dataViewConfig.sortColumn ? dataViewConfig.sortColumn.key : dataViewConfig.viewColumns[0].name,
  588. sort: dataViewConfig.sortType || 'asc',
  589. filters: getBodyFilters(filters),
  590. testPage: {
  591. pageNum: page || 1,
  592. pageSize: pageSize || 25,
  593. }
  594. };
  595. let res = yield call(service.fetch, {
  596. url: URLS.CHART_DATAVIEW_OPTION,
  597. body: body,
  598. timeout: 30000
  599. });
  600. if(res.code > 0) {
  601. let option = parseChartOption('dataView', res.data, dataViewConfig, theme, styleConfig.dataView);
  602. yield put({ type: 'silentSetField', name: 'chartOption', value: option });
  603. }else {
  604. message.error('请求列表数据失败: ' + res.msg);
  605. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  606. }
  607. yield put({ type: 'silentSetField', name: 'fetchConfig', value: body });
  608. }catch(e) {
  609. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  610. message.error('请求列表数据失败: ' + e.message);
  611. }
  612. },
  613. *fetchAggregateTableData(action, { select, call, put }) {
  614. try {
  615. const chartDesigner = yield select(state => state.present.chartDesigner);
  616. const { code, aggregateTableConfig, filters, theme, styleConfig } = chartDesigner;
  617. const { targetColumn, statistics } = aggregateTableConfig;
  618. const body = {
  619. id: code,
  620. columnName: targetColumn.name,
  621. operatorList: statistics,
  622. groupByList: aggregateTableConfig.groupBy && aggregateTableConfig.groupBy.length > 0 ? aggregateTableConfig.groupBy.map(g => g.key) : [],
  623. filters: getBodyFilters(filters),
  624. testPage: {
  625. pageNum: 1,
  626. pageSize: 99,
  627. }
  628. };
  629. let res = yield call(service.fetch, {
  630. url: URLS.CHART_AGGREGATETABLE_OPTION,
  631. body: body,
  632. timeout: 30000
  633. });
  634. if(res.code > 0) {
  635. let option = parseChartOption('aggregateTable', res.data, aggregateTableConfig, theme, styleConfig.aggregateTable || {});
  636. yield put({ type: 'silentSetField', name: 'chartOption', value: option });
  637. }else {
  638. message.error('请求统计数据失败: ' + res.msg);
  639. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  640. }
  641. yield put({ type: 'silentSetField', name: 'fetchConfig', value: body });
  642. }catch(e) {
  643. yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  644. message.error('请求统计数据失败: ' + e.message);
  645. }
  646. },
  647. /**
  648. * 将图表数据以表格的方式作为预览
  649. */
  650. *remoteChartDataList(action, { select, call, put }) {
  651. try {
  652. const chartDesigner = yield select(state => state.present.chartDesigner);
  653. const { code, baseConfig, aggregateTableConfig, lineConfig, barConfig, pieConfig, scatterConfig, dataViewConfig, filters } = chartDesigner;
  654. const { viewType } = baseConfig;
  655. const { page, pageSize } = action;
  656. let columns = [];
  657. let columnListName = [];
  658. let sortColumn = null;
  659. if(viewType === 'aggregateTable') {
  660. const { groupBy, targetColumn } = aggregateTableConfig;
  661. groupBy.map(g => ({
  662. label: g.label,
  663. name: g.key,
  664. })).concat([targetColumn]).filter(x => !!x.name).forEach(x => {
  665. if(!columns.find(c => c.name === x.name)) {
  666. columns.push(x);
  667. }
  668. });;
  669. sortColumn = targetColumn.name;
  670. }else if(viewType === 'line') {
  671. const { groupBy, xAxis, yAxis } = lineConfig;
  672. [{
  673. label: groupBy ? groupBy.label : '',
  674. name: groupBy ? groupBy.key : '',
  675. type: groupBy ? groupBy.type : '',
  676. }, {
  677. label: xAxis.column.label,
  678. name: xAxis.column.value,
  679. type: xAxis.column.type,
  680. }, {
  681. label: yAxis.column.label,
  682. name: yAxis.column.value,
  683. type: yAxis.column.type,
  684. }].filter(x => !!x.name).forEach(x => {
  685. if(!columns.find(c => c.name === x.name)) {
  686. columns.push(x);
  687. }
  688. });;
  689. sortColumn = xAxis.column.value;
  690. }else if(viewType === 'bar') {
  691. const { groupBy, xAxis, yAxis } = barConfig;
  692. [{
  693. label: groupBy ? groupBy.label : '',
  694. name: groupBy ? groupBy.key : '',
  695. type: groupBy ? groupBy.type : '',
  696. }, {
  697. label: xAxis.column.label,
  698. name: xAxis.column.value,
  699. type: xAxis.column.type,
  700. }, {
  701. label: yAxis.column.label,
  702. name: yAxis.column.value,
  703. type: yAxis.column.type,
  704. }].filter(x => !!x.name).forEach(x => {
  705. if(!columns.find(c => c.name === x.name)) {
  706. columns.push(x);
  707. }
  708. });;
  709. sortColumn = xAxis.column.value;
  710. }else if(viewType === 'pie') {
  711. const { xAxis, yAxis } = pieConfig;
  712. [{
  713. label: xAxis.column.label,
  714. name: xAxis.column.value,
  715. type: xAxis.column.type,
  716. }, {
  717. label: yAxis.column.label,
  718. name: yAxis.column.value,
  719. type: yAxis.column.type,
  720. }].filter(x => !!x.name).forEach(x => {
  721. if(!columns.find(c => c.name === x.name)) {
  722. columns.push(x);
  723. }
  724. });;
  725. sortColumn = xAxis.column.value;
  726. }else if(viewType === 'scatter') {
  727. const { groupBy, xAxis, yAxis } = scatterConfig;
  728. [{
  729. label: groupBy ? groupBy.label : '',
  730. name: groupBy ? groupBy.key : '',
  731. type: groupBy ? groupBy.type : '',
  732. }, {
  733. label: xAxis.column.label,
  734. name: xAxis.column.value,
  735. type: xAxis.column.type,
  736. }, {
  737. label: yAxis.column.label,
  738. name: yAxis.column.value,
  739. type: yAxis.column.type,
  740. }].filter(x => !!x.name).forEach(x => {
  741. if(!columns.find(c => c.name === x.name)) {
  742. columns.push(x);
  743. }
  744. });;
  745. sortColumn = xAxis.column.value;
  746. }else if(viewType === 'dataView') {
  747. columns = dataViewConfig.viewColumns;
  748. sortColumn = dataViewConfig.sortColumn.key;
  749. }
  750. if(columns.length === 0) {
  751. // message.error('');
  752. return false;
  753. }
  754. columnListName = columns.map(c => c.name);
  755. const body = {
  756. id: code,
  757. columnListName: columnListName,
  758. sortColumn: sortColumn,
  759. sort: 'asc',
  760. filters: getBodyFilters(filters),
  761. testPage: {
  762. pageNum: page || 1,
  763. pageSize: pageSize || 25,
  764. }
  765. };
  766. yield put({ type: 'dataList/setField', name: 'loading', value: true });
  767. let res = yield call(service.fetch, {
  768. url: URLS.CHART_DATAVIEW_OPTION,
  769. body: body,
  770. timeout: 30000
  771. });
  772. if(res.code > 0) {
  773. const { valueList } = res.data;
  774. const { list: dataSource, pageSize, total } = valueList;
  775. yield put({ type: 'dataList/setFields', fields: [
  776. { name: 'columns', value: columns },
  777. { name: 'dataSource', value: dataSource },
  778. { name: 'pageSize', value: pageSize },
  779. { name: 'total', value: total }
  780. ] });
  781. }else {
  782. message.error('请求列表数据失败: ' + res.msg);
  783. // yield put({ type: 'silentSetField', name: 'chartOption', value: {} });
  784. }
  785. }catch(e) {
  786. message.error('请求数据列表失败: ' + e.message);
  787. }finally {
  788. yield put({ type: 'dataList/setField', name: 'loading', value: false });
  789. }
  790. },
  791. },
  792. subscriptions: {
  793. setup({ dispatch, history }) {
  794. dispatch({ type: 'reset' });
  795. },
  796. },
  797. };