Panel.tsx 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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 React, { useMemo } from 'react'
  21. import { Menu, Icon } from 'antd'
  22. import { getPivot } from 'containers/Widget/components/util'
  23. import { DrillType, WidgetDimension, IDataDrillProps } from './types'
  24. import { getListsByViewModelTypes } from 'containers/View/util'
  25. import { ViewModelTypes } from 'containers/View/constants'
  26. const styles = require('./datadrill.less')
  27. const DataDrill: React.FC<IDataDrillProps> = (props: IDataDrillProps) => {
  28. const {
  29. onDataDrillUp,
  30. onDataDrillDown,
  31. onDataDrillPath,
  32. currentData,
  33. drillHistory,
  34. widgetConfig,
  35. drillpathSetting
  36. } = props
  37. let renderComponent = void 0
  38. let menuDisabled = void 0
  39. const getCategoriesModels = useMemo(() => {
  40. return getListsByViewModelTypes(
  41. widgetConfig && widgetConfig.model,
  42. 'modelType'
  43. )(ViewModelTypes.Category)
  44. }, [widgetConfig])
  45. const widgetMode = useMemo(() => {
  46. return widgetConfig && widgetConfig.mode
  47. }, [widgetConfig])
  48. const currentCategories = useMemo(() => {
  49. return currentData && currentData[0] ? Object.keys(currentData[0]) : []
  50. }, [currentData])
  51. const drillHistoryGroups = useMemo(() => {
  52. if (drillHistory && drillHistory.length) {
  53. return drillHistory[drillHistory.length - 1]['groups']
  54. }
  55. }, [drillHistory])
  56. const getDrilledGroup = useMemo(() => {
  57. return drillHistory && drillHistory.length
  58. ? drillHistory.map((history) => history.currentGroup)
  59. : []
  60. }, [drillHistory])
  61. const modelsfilterDrilledGroup = useMemo(() => {
  62. return getCategoriesModels.filter((cate) => !getDrilledGroup.includes(cate))
  63. }, [drillHistory, widgetConfig, getCategoriesModels, getDrilledGroup])
  64. const { drilldownCategories, drillupCategories } = useMemo(() => {
  65. return {
  66. drillupCategories: modelsfilterDrilledGroup
  67. .filter((cate) => currentCategories.includes(cate))
  68. .map((c) => ({
  69. name: c,
  70. modelType: ViewModelTypes.Category,
  71. drillType: DrillType.UP
  72. })),
  73. drilldownCategories: modelsfilterDrilledGroup
  74. .filter((cate) => !currentCategories.includes(cate))
  75. .map((c) => ({
  76. name: c,
  77. modelType: ViewModelTypes.Category,
  78. drillType: DrillType.DOWN
  79. }))
  80. }
  81. }, [widgetConfig, currentData, currentCategories])
  82. const drillOtherCategories = useMemo(() => {
  83. return drillHistoryGroups && drillHistoryGroups.length
  84. ? modelsfilterDrilledGroup
  85. .filter((cate) => !drillHistory.some((his) => his.currentGroup === cate))
  86. .map((name) => ({
  87. name,
  88. modelType: ViewModelTypes.Category,
  89. drillType: drillHistoryGroups.includes(name)
  90. ? DrillType.UP
  91. : DrillType.DOWN
  92. }))
  93. : drilldownCategories
  94. }, [drillHistory])
  95. const isPivot = useMemo(() => widgetMode === 'pivot', [widgetMode])
  96. const isPivotTableVal = useMemo(() => isPivotTable(widgetConfig.metrics), [
  97. widgetConfig
  98. ])
  99. if (drillpathSetting && drillpathSetting.length) {
  100. if (drillHistory && drillHistory.length) {
  101. menuDisabled = drillHistory.length === drillpathSetting.length - 1
  102. }
  103. renderComponent = (
  104. <Menu onClick={drillpath} style={{ width: 120 }} mode="vertical">
  105. <Menu.Item key="drillpath" disabled={menuDisabled}>
  106. <span
  107. style={{ fontSize: '14px' }}
  108. className="iconfont icon-iconxiazuan"
  109. >
  110. <span style={{ marginLeft: '8px' }}>下钻</span>
  111. </span>
  112. </Menu.Item>
  113. </Menu>
  114. )
  115. } else {
  116. renderComponent = (
  117. <Menu onClick={drill} style={{ width: 120 }} mode="vertical">
  118. {isPivot ? (
  119. <Menu.SubMenu
  120. key={`${DrillType.UP}`}
  121. disabled={drillupCategories.length < 2}
  122. title={
  123. <span
  124. style={{ fontSize: '14px' }}
  125. className="iconfont icon-iconxiazuan1"
  126. >
  127. <span style={{ marginLeft: '8px' }}>上卷</span>
  128. </span>
  129. }
  130. >
  131. {drillupCategories
  132. ? drillupCategories.map((col) => (
  133. <Menu.Item key={col.name}>{col.name}</Menu.Item>
  134. ))
  135. : ''}
  136. </Menu.SubMenu>
  137. ) : (
  138. <Menu.SubMenu
  139. key="drillAll"
  140. disabled={drillOtherCategories.length < 1}
  141. title={
  142. <span
  143. style={{ fontSize: '14px' }}
  144. className="iconfont icon-iconxiazuan"
  145. >
  146. <span style={{ marginLeft: '8px' }}>钻取</span>
  147. </span>
  148. }
  149. >
  150. {drillOtherCategories
  151. ? drillOtherCategories.map((col) => (
  152. <Menu.Item key={`${col.name}|${col.drillType}`}>
  153. <span className={styles.items}>
  154. <span>{col.name}</span>
  155. <span>
  156. <Icon
  157. type={`${
  158. col.drillType === DrillType.UP
  159. ? 'arrow-up'
  160. : 'arrow-down'
  161. }`}
  162. />
  163. </span>
  164. </span>
  165. </Menu.Item>
  166. ))
  167. : ''}
  168. </Menu.SubMenu>
  169. )}
  170. {isPivot ? (
  171. <Menu.SubMenu
  172. key={`${DrillType.DOWN}`}
  173. disabled={drilldownCategories.length < 1}
  174. title={
  175. <span
  176. style={{ fontSize: '14px' }}
  177. className="iconfont icon-iconxiazuan"
  178. >
  179. <span style={{ marginLeft: '8px' }}>下钻</span>
  180. </span>
  181. }
  182. >
  183. {drilldownCategories
  184. ? drilldownCategories.map((col) =>
  185. isPivotTableVal ? (
  186. <Menu.SubMenu key={col.name} title={col.name}>
  187. <Menu.Item key="row">行</Menu.Item>
  188. <Menu.Item key="col">列</Menu.Item>
  189. </Menu.SubMenu>
  190. ) : (
  191. <Menu.Item key={col.name}>{col.name}</Menu.Item>
  192. )
  193. )
  194. : ''}
  195. </Menu.SubMenu>
  196. ) : (
  197. ''
  198. )}
  199. </Menu>
  200. )
  201. }
  202. return renderComponent
  203. function drill(e) {
  204. const path = e.keyPath
  205. if (path && path.length > 2) {
  206. onDataDrillDown(path[1], path[0])
  207. } else {
  208. switch (path[1]) {
  209. case DrillType.UP:
  210. onDataDrillUp(path[0])
  211. break
  212. case 'drillAll':
  213. const type = path[0].split('|')
  214. if (type) {
  215. if (type[1] === DrillType.UP) {
  216. onDataDrillUp(type[0])
  217. } else if (type[1] === DrillType.DOWN) {
  218. onDataDrillDown(type[0])
  219. }
  220. }
  221. break
  222. default:
  223. break
  224. }
  225. }
  226. }
  227. function drillpath() {
  228. onDataDrillPath()
  229. }
  230. function isPivotTable(selectedCharts) {
  231. const pivotChart = getPivot()
  232. const result =
  233. Array.isArray(selectedCharts) &&
  234. selectedCharts.every((sc) => sc.chart.id === pivotChart.id)
  235. return !isPivot ? false : result
  236. }
  237. }
  238. export default DataDrill