VizConfig.tsx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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, useCallback } from 'react'
  21. import { Row, Col, Icon } from 'antd'
  22. import {
  23. IPortal,
  24. IDashboard,
  25. IDisplayFormed,
  26. ISlideFormed
  27. } from 'containers/Viz/types'
  28. import { IScheduleVizConfigItem } from './types'
  29. import { NodeKeyPrefix } from './constants'
  30. import {
  31. getCheckedVizKeys,
  32. renderPortalDashboardsTreeNodes,
  33. renderDisplaySlidesTreeNodes
  34. } from './util'
  35. import VizSelectTree from './VizSelectTree'
  36. interface IScheduleVizConfigProps {
  37. portals: IPortal[]
  38. displays: IDisplayFormed[]
  39. value: IScheduleVizConfigItem[]
  40. portalDashboards: { [portalId: number]: IDashboard[] }
  41. displaySlides: { [displayId: number]: ISlideFormed[] }
  42. onLoadPortalDashboards: (portalId: number) => void
  43. onLoadDisplaySlides: (displayId: number) => void
  44. onChange: (value: IScheduleVizConfigItem[]) => void
  45. }
  46. const ScheduleVizConfig: React.FC<IScheduleVizConfigProps> = (props) => {
  47. const {
  48. portals,
  49. displays,
  50. value,
  51. portalDashboards,
  52. displaySlides,
  53. onLoadPortalDashboards,
  54. onLoadDisplaySlides,
  55. onChange
  56. } = props
  57. const checkedPortalKeys = useMemo(
  58. () =>
  59. getCheckedVizKeys(
  60. value,
  61. 'portal',
  62. portals,
  63. NodeKeyPrefix.Portal,
  64. NodeKeyPrefix.Dashboard
  65. ),
  66. [value, portals]
  67. )
  68. const checkedDisplayKeys = useMemo(
  69. () =>
  70. getCheckedVizKeys(
  71. value,
  72. 'display',
  73. displays,
  74. NodeKeyPrefix.Display,
  75. NodeKeyPrefix.Slide
  76. ),
  77. [value, displays]
  78. )
  79. const loadVizItems = useCallback(
  80. (vizId: number, prefix: NodeKeyPrefix) => {
  81. switch (prefix) {
  82. case NodeKeyPrefix.Portal:
  83. if (!portalDashboards[vizId]) {
  84. onLoadPortalDashboards(vizId)
  85. }
  86. break
  87. case NodeKeyPrefix.Display:
  88. if (!displaySlides[vizId]) {
  89. onLoadDisplaySlides(vizId)
  90. }
  91. break
  92. }
  93. return new Promise<void>((resolve) => {
  94. resolve()
  95. })
  96. },
  97. [
  98. portalDashboards,
  99. displaySlides,
  100. onLoadPortalDashboards,
  101. onLoadDisplaySlides
  102. ]
  103. )
  104. const renderVizItems = useCallback(
  105. (nodeId: number, prefix: NodeKeyPrefix) => {
  106. switch (prefix) {
  107. case NodeKeyPrefix.Portal:
  108. return renderPortalDashboardsTreeNodes(
  109. nodeId,
  110. portalDashboards[nodeId]
  111. )
  112. case NodeKeyPrefix.Display:
  113. return renderDisplaySlidesTreeNodes(nodeId, displaySlides[nodeId])
  114. }
  115. },
  116. [portalDashboards, displaySlides]
  117. )
  118. const checkViz = useCallback(
  119. (
  120. type: IScheduleVizConfigItem['contentType'],
  121. vizId: number,
  122. checked: boolean
  123. ) => {
  124. // remove this Viz value first
  125. const newValue = value.filter(
  126. ({ id, contentType }) =>
  127. contentType !== type || (contentType === type && id !== vizId)
  128. )
  129. if (checked) {
  130. newValue.push({
  131. contentType: type,
  132. id: vizId,
  133. items: undefined // undefined stands for dynamic check all dashboards
  134. })
  135. }
  136. switch (type) {
  137. case 'portal':
  138. if (!portalDashboards[vizId]) {
  139. onLoadPortalDashboards(vizId)
  140. }
  141. break
  142. case 'display':
  143. if (!displaySlides[vizId]) {
  144. onLoadDisplaySlides(vizId)
  145. }
  146. break
  147. }
  148. onChange(newValue)
  149. },
  150. [value, onLoadPortalDashboards, onLoadDisplaySlides, onChange]
  151. )
  152. const checkVizItem = useCallback(
  153. (
  154. type: IScheduleVizConfigItem['contentType'],
  155. vizItemId: number,
  156. checked: boolean,
  157. dataRef: [number, number[]?, number[]?]
  158. ) => {
  159. const newValue = [...value]
  160. const [vizId, ancestorIds, descendantIds] = dataRef
  161. const removeAncestor = (itemId: number) =>
  162. !Array.isArray(ancestorIds) || !ancestorIds.includes(itemId)
  163. const removeDescendant = (itemId: number) =>
  164. !Array.isArray(descendantIds) || !descendantIds.includes(itemId)
  165. const vizConfigIdx = newValue.findIndex(
  166. ({ id, contentType }) => id === vizId && contentType === type
  167. )
  168. if (~vizConfigIdx) {
  169. const vizConfig = newValue[vizConfigIdx]
  170. const vizItems =
  171. type === 'portal'
  172. ? portalDashboards[vizId]
  173. : type === 'display'
  174. ? displaySlides[vizId]
  175. : []
  176. if (checked) {
  177. vizConfig.items = vizConfig.items
  178. .filter(removeDescendant)
  179. .concat(vizItemId)
  180. } else {
  181. vizConfig.items = (
  182. vizConfig.items ||
  183. (vizItems as Array<IDashboard | ISlideFormed>).map(({ id }) => id)
  184. ).filter(
  185. (id) =>
  186. id !== vizItemId && removeAncestor(id) && removeDescendant(id)
  187. )
  188. if (!vizConfig.items.length) {
  189. newValue.splice(vizConfigIdx, 1)
  190. }
  191. }
  192. } else {
  193. // new checked true
  194. newValue.push({
  195. contentType: type,
  196. id: vizId,
  197. items: [vizItemId]
  198. })
  199. }
  200. onChange(newValue)
  201. },
  202. [value, portalDashboards, displaySlides, onChange]
  203. )
  204. const checkVizTree = useCallback(
  205. (nodeId: number, prefix: NodeKeyPrefix, checked: boolean, dataRef: any) => {
  206. switch (prefix) {
  207. case NodeKeyPrefix.Portal:
  208. checkViz('portal', nodeId, checked)
  209. break
  210. case NodeKeyPrefix.Display:
  211. checkViz('display', nodeId, checked)
  212. break
  213. case NodeKeyPrefix.Dashboard:
  214. checkVizItem('portal', nodeId, checked, dataRef)
  215. break
  216. case NodeKeyPrefix.Slide:
  217. checkVizItem('display', nodeId, checked, dataRef)
  218. break
  219. }
  220. },
  221. [checkViz, checkVizItem]
  222. )
  223. return (
  224. <Row gutter={8}>
  225. <Col span={12}>
  226. <VizSelectTree
  227. title="仪表板"
  228. vizs={portals}
  229. vizIcon={<Icon type="layout" />}
  230. vizKeyPrefix={NodeKeyPrefix.Portal}
  231. checkedKeys={checkedPortalKeys}
  232. onLoadDetail={loadVizItems}
  233. onRenderVizItems={renderVizItems}
  234. onCheck={checkVizTree}
  235. />
  236. </Col>
  237. <Col span={12}>
  238. <VizSelectTree
  239. title="大屏"
  240. vizs={displays}
  241. vizIcon={<Icon type="layout" />}
  242. vizKeyPrefix={NodeKeyPrefix.Display}
  243. checkedKeys={checkedDisplayKeys}
  244. onLoadDetail={loadVizItems}
  245. onRenderVizItems={renderVizItems}
  246. onCheck={checkVizTree}
  247. />
  248. </Col>
  249. </Row>
  250. )
  251. }
  252. export default ScheduleVizConfig