strategies.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*
  2. * <<
  3. * Davinci
  4. * ==
  5. * Copyright (C) 2016 - 2017 EDP
  6. * ==
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. * >>
  19. */
  20. import { compose } from 'redux'
  21. import { getLastItemValueOfArray } from './util'
  22. import { RequireAtLeastOne } from 'utils/types'
  23. import WidgetAbstract, {
  24. DrillCharts,
  25. DrillType,
  26. WidgetDimensions,
  27. IDrillDetail,
  28. IDrillStrategies,
  29. ISourceDataFilter
  30. } from './types'
  31. import { IFilter } from '../Control/types'
  32. import { getValidColumnValue } from 'app/components/Control/util'
  33. import OperatingWidget, {
  34. operationWidgetProps,
  35. setDefaultReplaceNull
  36. } from './abstract/widgetOperating'
  37. import { IWidgetDimension } from 'containers/Widget/components/Widget'
  38. const setDefaultEmptyArray = setDefaultReplaceNull((f) => f, [])
  39. export const strategiesOfDrillUpHasDrillHistory = (
  40. lastDrillHistory: IDrillDetail,
  41. currentWidgetProps: WidgetAbstract
  42. ) => (
  43. widgetDimension: RequireAtLeastOne<IWidgetDimension, keyof IWidgetDimension>,
  44. sourceData?,
  45. sourceGroup?: string[]
  46. ) => {
  47. return {
  48. [DrillCharts.PIVOT]: (): IDrillDetail => {
  49. const drillStragegies: IDrillStrategies = common.call(
  50. null,
  51. widgetDimension,
  52. currentWidgetProps
  53. )
  54. const { widgetProps, filters } = drillStragegies
  55. const lastGroupOfCols =
  56. currentWidgetProps.cols && currentWidgetProps.cols.length !== 0
  57. ? getLastItemValueOfArray(currentWidgetProps.cols, 'name')
  58. : null
  59. const lastGroupOfRows =
  60. currentWidgetProps.rows && currentWidgetProps.rows.length !== 0
  61. ? getLastItemValueOfArray(currentWidgetProps.rows, 'name')
  62. : null
  63. return {
  64. ...drillStragegies,
  65. filters: mappingFilters(
  66. sourceData,
  67. lastGroupOfCols || lastGroupOfRows
  68. ).concat(filters)
  69. }
  70. },
  71. [DrillCharts.COUSTOMTABLE]: (): IDrillStrategies => {
  72. // 缺少对 sourceDataGroup 的处理, sourceDataGroup 只是对cols有影响,对filters没有影响。cols又决定table的表头
  73. const drillStragegies: IDrillStrategies = common.call(
  74. null,
  75. widgetDimension
  76. )
  77. const coustomTableFilters = compose(
  78. combineFilters,
  79. collectKeyValue,
  80. setDefaultEmptyArray
  81. )(sourceData)
  82. return {
  83. ...drillStragegies,
  84. filters: coustomTableFilters.concat(drillStragegies.filters)
  85. }
  86. }
  87. }
  88. function common(): IDrillStrategies {
  89. const WP = operationWidgetProps
  90. const { groups, filters } = lastDrillHistory
  91. const widgetProps = WP.deleteWithSthRowsOrCols(
  92. WP.deleteWithSthRowsOrCols(
  93. currentWidgetProps,
  94. WidgetDimensions.ROW,
  95. widgetDimension
  96. ),
  97. WidgetDimensions.COL,
  98. widgetDimension
  99. )
  100. return {
  101. cols: widgetProps.cols,
  102. rows: widgetProps.rows,
  103. type: DrillType.UP,
  104. groups: groups.filter((group) => group !== widgetDimension.name),
  105. filters,
  106. widgetProps,
  107. currentGroup: widgetDimension.name
  108. }
  109. }
  110. }
  111. export const strategiesOfDrillDownHasDrillHistory = (
  112. lastDrillHistory: IDrillDetail,
  113. currentWidgetProps: WidgetAbstract
  114. ) => (
  115. widgetDimension: RequireAtLeastOne<IWidgetDimension, keyof IWidgetDimension>,
  116. sourceData,
  117. sourceDataGroup
  118. ) => {
  119. const WP = operationWidgetProps
  120. const cursor: Pick<IWidgetDimension, 'name'> = coustomTableCursor(
  121. sourceData,
  122. sourceDataGroup
  123. )
  124. function common(
  125. widgetDimension: IWidgetDimension,
  126. currentWidgetProps: WidgetAbstract
  127. ): IDrillStrategies {
  128. const { cols, rows, groups, filters } = lastDrillHistory
  129. return {
  130. cols,
  131. rows,
  132. type: DrillType.DOWN,
  133. groups,
  134. filters,
  135. widgetProps: currentWidgetProps,
  136. currentGroup: widgetDimension.name
  137. }
  138. }
  139. return {
  140. [DrillCharts.PIVOTCOL]: (): IDrillStrategies => {
  141. const drillStragegies: IDrillStrategies = common.call(
  142. null,
  143. widgetDimension,
  144. currentWidgetProps
  145. )
  146. const { groups, filters, widgetProps } = drillStragegies
  147. const nextWidgetProps = WP.insertWithSthRowsOrCols(
  148. widgetProps,
  149. WidgetDimensions.COL,
  150. widgetDimension
  151. )
  152. const lastGroup = groups[groups.length - 1]
  153. return {
  154. ...drillStragegies,
  155. widgetProps: nextWidgetProps,
  156. groups: groups.concat(widgetDimension.name),
  157. filters: mappingFilters(sourceData, lastGroup).concat(filters),
  158. cols: nextWidgetProps.cols,
  159. rows: nextWidgetProps.rows
  160. }
  161. },
  162. [DrillCharts.PIVOTROW]: (): IDrillStrategies => {
  163. const drillStragegies: IDrillStrategies = common.call(
  164. null,
  165. widgetDimension,
  166. currentWidgetProps
  167. )
  168. const { groups, filters, widgetProps } = drillStragegies
  169. const nextWidgetProps = WP.insertWithSthRowsOrCols(
  170. widgetProps,
  171. WidgetDimensions.ROW,
  172. widgetDimension
  173. )
  174. const lastGroup = groups[groups.length - 1]
  175. return {
  176. ...drillStragegies,
  177. widgetProps: nextWidgetProps,
  178. groups: groups.concat(widgetDimension.name),
  179. filters: mappingFilters(sourceData, lastGroup).concat(filters),
  180. cols: nextWidgetProps.cols,
  181. rows: nextWidgetProps.rows
  182. }
  183. },
  184. [DrillCharts.COUSTOMTABLE]: (): IDrillStrategies => {
  185. const drillStragegies: IDrillStrategies = common.call(
  186. null,
  187. widgetDimension,
  188. currentWidgetProps
  189. )
  190. const { groups, filters, widgetProps } = drillStragegies
  191. const nextWidgetProps = WP.insertWithSthRowsOrCols(
  192. widgetProps,
  193. WidgetDimensions.COL,
  194. widgetDimension,
  195. cursor
  196. )
  197. const coustomTableFilters = compose(
  198. combineFilters,
  199. collectKeyValue,
  200. setDefaultEmptyArray
  201. )(sourceData)
  202. return {
  203. ...drillStragegies,
  204. groups: groups.concat(widgetDimension.name),
  205. filters: coustomTableFilters.concat(filters),
  206. cols: nextWidgetProps.cols,
  207. rows: nextWidgetProps.rows,
  208. widgetProps: nextWidgetProps
  209. }
  210. },
  211. [DrillCharts.DIMETIONAXISCOL]: defaultStrategies,
  212. [DrillCharts.DIMETIONAXISROW]: (): IDrillStrategies => {
  213. const drillStragegies: IDrillStrategies = common.call(
  214. null,
  215. widgetDimension,
  216. currentWidgetProps
  217. )
  218. const { groups, filters, widgetProps } = drillStragegies
  219. const nextWidgetProps = WP.overWriteRowsOrCols(
  220. widgetProps,
  221. WidgetDimensions.ROW,
  222. widgetDimension
  223. )
  224. const lastGroup = groups[groups.length - 1]
  225. return {
  226. ...drillStragegies,
  227. widgetProps: nextWidgetProps,
  228. groups: [widgetDimension.name],
  229. filters: mappingFilters(sourceData, lastGroup).concat(filters),
  230. cols: nextWidgetProps.cols,
  231. rows: nextWidgetProps.rows
  232. }
  233. },
  234. [DrillCharts.DEFAULT]: defaultStrategies
  235. }
  236. function defaultStrategies(): IDrillStrategies {
  237. const drillStragegies: IDrillStrategies = common.call(
  238. null,
  239. widgetDimension,
  240. currentWidgetProps
  241. )
  242. const { groups, filters, widgetProps } = drillStragegies
  243. const nextWidgetProps = WP.overWriteRowsOrCols(
  244. widgetProps,
  245. WidgetDimensions.COL,
  246. widgetDimension
  247. )
  248. const lastGroup = groups[groups.length - 1]
  249. return {
  250. ...drillStragegies,
  251. groups: [widgetDimension.name],
  252. filters: mappingFilters(sourceData, lastGroup).concat(filters),
  253. cols: nextWidgetProps.cols,
  254. rows: nextWidgetProps.rows,
  255. widgetProps: nextWidgetProps
  256. }
  257. }
  258. }
  259. export const strategiesOfDrillUpNullDrillHistory = (
  260. WP: OperatingWidget,
  261. target: WidgetAbstract
  262. ) => (
  263. widgetDimension: RequireAtLeastOne<IWidgetDimension, keyof IWidgetDimension>,
  264. sourceData?
  265. ) => {
  266. const initGroups = WP.initGroups()
  267. const initNativeFilters = WP.initWidgetNativeFilters()
  268. return {
  269. [DrillCharts.PIVOT]: (): IDrillStrategies => {
  270. const drillStragegies: IDrillStrategies = common.call(
  271. null,
  272. widgetDimension
  273. )
  274. const { widgetProps } = drillStragegies
  275. const lastGroupOfCols =
  276. target.cols && target.cols.length !== 0
  277. ? getLastItemValueOfArray(target.cols, 'name')
  278. : null
  279. const lastGroupOfRows =
  280. target.rows && target.rows.length !== 0
  281. ? getLastItemValueOfArray(target.rows, 'name')
  282. : null
  283. return {
  284. ...drillStragegies,
  285. filters: mappingFilters(
  286. sourceData,
  287. lastGroupOfCols || lastGroupOfRows
  288. ).concat(initNativeFilters)
  289. }
  290. },
  291. [DrillCharts.COUSTOMTABLE]: (): IDrillStrategies => {
  292. const drillStragegies: IDrillStrategies = common.call(
  293. null,
  294. widgetDimension
  295. )
  296. const coustomTableFilters = compose(
  297. combineFilters,
  298. collectKeyValue,
  299. setDefaultEmptyArray
  300. )(sourceData)
  301. return {
  302. ...drillStragegies,
  303. filters: coustomTableFilters.concat(initNativeFilters)
  304. }
  305. }
  306. }
  307. function common(): IDrillStrategies {
  308. const widgetProps = WP.deleteWithSthRowsOrCols(
  309. WP.deleteWithSthRowsOrCols(target, WidgetDimensions.ROW, widgetDimension),
  310. WidgetDimensions.COL,
  311. widgetDimension
  312. )
  313. return {
  314. widgetProps,
  315. type: DrillType.UP,
  316. groups: initGroups.filter((group) => group !== widgetDimension.name),
  317. currentGroup: widgetDimension.name,
  318. filters: initNativeFilters,
  319. cols: widgetProps.cols,
  320. rows: widgetProps.rows
  321. }
  322. }
  323. }
  324. export const strategiesOfDrillDownNullDrillHistory = (
  325. WP: OperatingWidget,
  326. target: WidgetAbstract
  327. ) => (
  328. widgetDimension: RequireAtLeastOne<IWidgetDimension, keyof IWidgetDimension>,
  329. sourceData,
  330. sourceDataGroup
  331. ) => {
  332. const initGroups = WP.initGroups()
  333. const initNativeFilters = WP.initWidgetNativeFilters()
  334. const getCols = WP.getRowsOrCols(WidgetDimensions.COL)
  335. const getRows = WP.getRowsOrCols(WidgetDimensions.ROW)
  336. const cursor: Pick<IWidgetDimension, 'name'> = coustomTableCursor(
  337. sourceData,
  338. sourceDataGroup
  339. )
  340. return {
  341. [DrillCharts.PIVOTCOL]: (): IDrillStrategies => {
  342. const widgetProps = WP.insertWithSthRowsOrCols(
  343. target,
  344. WidgetDimensions.COL,
  345. widgetDimension
  346. )
  347. const lastGroupOfCols =
  348. getCols.length !== 0 ? getLastItemValueOfArray(getCols, 'name') : null
  349. const lastGroupOfRows =
  350. getRows.length !== 0 ? getLastItemValueOfArray(getRows, 'name') : null
  351. return {
  352. widgetProps,
  353. type: DrillType.DOWN,
  354. groups: initGroups.concat(widgetDimension.name),
  355. currentGroup: widgetDimension.name,
  356. filters: mappingFilters(
  357. sourceData,
  358. lastGroupOfCols || lastGroupOfRows
  359. ).concat(initNativeFilters),
  360. cols: widgetProps.cols,
  361. rows: widgetProps.rows
  362. }
  363. },
  364. [DrillCharts.PIVOTROW]: (): IDrillStrategies => {
  365. const widgetProps = WP.insertWithSthRowsOrCols(
  366. target,
  367. WidgetDimensions.ROW,
  368. widgetDimension
  369. )
  370. const lastGroupOfCols =
  371. getCols.length !== 0 ? getLastItemValueOfArray(getCols, 'name') : null
  372. const lastGroupOfRows =
  373. getRows.length !== 0 ? getLastItemValueOfArray(getRows, 'name') : null
  374. return {
  375. widgetProps,
  376. type: DrillType.DOWN,
  377. groups: initGroups.concat(widgetDimension.name),
  378. currentGroup: widgetDimension.name,
  379. filters: mappingFilters(
  380. sourceData,
  381. lastGroupOfCols || lastGroupOfRows
  382. ).concat(initNativeFilters),
  383. cols: widgetProps.cols,
  384. rows: widgetProps.rows
  385. }
  386. },
  387. [DrillCharts.COUSTOMTABLE]: (): IDrillStrategies => {
  388. const widgetProps = WP.insertWithSthRowsOrCols(
  389. target,
  390. WidgetDimensions.COL,
  391. widgetDimension,
  392. cursor
  393. )
  394. const coustomTableFilters = compose(
  395. combineFilters,
  396. collectKeyValue,
  397. setDefaultEmptyArray
  398. )(sourceData)
  399. return {
  400. widgetProps,
  401. type: DrillType.DOWN,
  402. // groups only determine the result of the data set, the order of the table header is determined by cols
  403. groups: initGroups.concat(widgetDimension.name),
  404. currentGroup: widgetDimension.name,
  405. filters: coustomTableFilters.concat(initNativeFilters),
  406. cols: widgetProps.cols,
  407. rows: widgetProps.rows
  408. }
  409. },
  410. [DrillCharts.DIMETIONAXISCOL]: defaultStrategies,
  411. [DrillCharts.DIMETIONAXISROW]: (): IDrillStrategies => {
  412. const widgetProps = WP.overWriteRowsOrCols(
  413. target,
  414. WidgetDimensions.ROW,
  415. widgetDimension
  416. )
  417. const lastGroup =
  418. getRows.length !== 0 ? getLastItemValueOfArray(getRows, 'name') : null
  419. return {
  420. widgetProps,
  421. type: DrillType.DOWN,
  422. groups: [widgetDimension.name],
  423. currentGroup: widgetDimension.name,
  424. filters: mappingFilters(sourceData, lastGroup).concat(
  425. initNativeFilters
  426. ),
  427. cols: widgetProps.cols,
  428. rows: widgetProps.rows
  429. }
  430. },
  431. [DrillCharts.DEFAULT]: defaultStrategies
  432. }
  433. function defaultStrategies(): IDrillStrategies {
  434. const widgetProps = WP.overWriteRowsOrCols(
  435. target,
  436. WidgetDimensions.COL,
  437. widgetDimension
  438. )
  439. const lastGroup =
  440. getCols.length !== 0 ? getLastItemValueOfArray(getCols, 'name') : null
  441. return {
  442. widgetProps,
  443. type: DrillType.DOWN,
  444. groups: [widgetDimension.name],
  445. currentGroup: widgetDimension.name,
  446. filters: mappingFilters(sourceData, lastGroup).concat(initNativeFilters),
  447. cols: widgetProps.cols,
  448. rows: widgetProps.rows
  449. }
  450. }
  451. }
  452. function collectKeyValue(sourceDataFilter) {
  453. return sourceDataFilter.reduce((iteratee, target) => {
  454. iteratee[target['key']] === undefined
  455. ? (iteratee[target['key']] = [target['value']])
  456. : iteratee[target['key']].push(target['value'])
  457. return iteratee
  458. }, {})
  459. }
  460. function mappingFilters(sourceDataFilter, group): IFilter[] {
  461. if (group === '指标名称') {
  462. return []
  463. }
  464. if (!(sourceDataFilter && sourceDataFilter.length)) {
  465. return []
  466. }
  467. const mappgingSource = sourceDataFilter.map((source) =>
  468. source && source[group] ? source[group] : ''
  469. )
  470. const sqlType = getSqlType(group)
  471. return [
  472. {
  473. name: group,
  474. operator: 'in',
  475. type: 'filter',
  476. value: mappgingSource.map((val) => getValidColumnValue(val, sqlType)),
  477. sqlType
  478. }
  479. ]
  480. }
  481. function getSqlType(target: string) {
  482. return operationWidgetProps.getTypesOfModelByKeyName(
  483. operationWidgetProps.getModel(),
  484. 'sqlType'
  485. )(target)
  486. }
  487. function combineFilters(keyValuds): IFilter[] {
  488. return Object.keys(keyValuds).reduce((iteratee, target) => {
  489. const sqlType = getSqlType(target)
  490. return iteratee.concat({
  491. name: target,
  492. operator: 'in',
  493. type: 'filter',
  494. value: keyValuds[target].map((v) => getValidColumnValue(v, sqlType)),
  495. sqlType
  496. })
  497. }, [])
  498. }
  499. function coustomTableCursor(
  500. sourceDataFilter: ISourceDataFilter[],
  501. sourceDataGroup?
  502. ) {
  503. return {
  504. name:
  505. sourceDataFilter && sourceDataFilter.length
  506. ? getLastItemValueOfArray(sourceDataFilter, 'key')
  507. : sourceDataGroup && sourceDataGroup.length
  508. ? sourceDataGroup.pop()
  509. : ''
  510. }
  511. }