index.tsx 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  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, { PureComponent, GetDerivedStateFromProps } from 'react'
  21. import {
  22. IControl,
  23. IDistinctValueReqeustParams,
  24. IControlRelatedViewFormValue,
  25. IControlOption,
  26. IControlRelatedView
  27. } from '../types'
  28. import {
  29. getDefaultGlobalControl,
  30. getDefaultLocalControl,
  31. getEditingControlFormValues,
  32. getDefaultRelatedView,
  33. getValidOperator,
  34. getValidDatePickerFormat,
  35. stringifyDefaultValue,
  36. transformOptions,
  37. getRelatedViewModels
  38. } from '../util'
  39. import {
  40. ControlTypes,
  41. IS_RANGE_TYPE,
  42. ControlQueryMode,
  43. ControlFieldTypes,
  44. SHOULD_LOAD_OPTIONS,
  45. ControlOptionTypes,
  46. ControlDefaultValueTypes,
  47. ControlPanelTypes
  48. } from '../constants'
  49. import { ListFormLayout, List } from 'components/ListFormLayout'
  50. import ControlList from './ControlList'
  51. import ControlForm from './ControlForm'
  52. import OptionSettingForm from './OptionSettingForm'
  53. import { Button, Modal, Radio, message } from 'antd'
  54. import FormType from 'antd/lib/form/Form'
  55. import { RadioChangeEvent } from 'antd/lib/radio'
  56. import { CheckboxChangeEvent } from 'antd/lib/checkbox'
  57. import { TreeNode } from 'antd/lib/tree-select'
  58. import { IDashboardItem } from 'containers/Dashboard/types'
  59. import { IFormedViews, IViewBase, IView } from 'app/containers/View/types'
  60. import { IWidgetFormed } from 'app/containers/Widget/types'
  61. import { IFlatRelatedItem, IFlatRelatedView } from './ControlForm/types'
  62. import { DEFAULT_CACHE_EXPIRED } from 'app/globalConstants'
  63. import { getDefaultRelativeDate } from 'app/components/RelativeDatePicker/util'
  64. import styles from '../Control.less'
  65. const RadioGroup = Radio.Group
  66. const RadioButton = Radio.Button
  67. interface IControlConfigProps {
  68. type: ControlPanelTypes
  69. originalControls: IControl[]
  70. currentItems?: IDashboardItem[]
  71. widgets?: IWidgetFormed[]
  72. relatedViewId?: number
  73. views: IViewBase[]
  74. formedViews: IFormedViews
  75. visible: boolean
  76. loading?: boolean
  77. queryMode: ControlQueryMode
  78. onCancel: () => void
  79. onSave: (controls: IControl[], queryMode: ControlQueryMode) => void
  80. onLoadViews: () => void
  81. onLoadViewDetail: (
  82. viewIds: number[],
  83. resolve?: (views: IView[]) => void
  84. ) => void
  85. onGetOptions: (
  86. paramsByViewId: {
  87. [viewId: string]: Omit<IDistinctValueReqeustParams, 'cache' | 'expired'>
  88. },
  89. callback: (options?: object[]) => void
  90. ) => void
  91. }
  92. interface IControlConfigStates {
  93. controls: IControl[]
  94. editingControlBase: Omit<IControl, 'relatedItems' | 'relatedViews'>
  95. editingRelatedItemList: IFlatRelatedItem[]
  96. editingRelatedViewList: IFlatRelatedView[]
  97. defaultValueOptions: Array<IControlOption | TreeNode>
  98. defaultValueLoading: boolean
  99. optionModalVisible: boolean
  100. optionSettingFormValues: IControlOption
  101. editingOptionIndex: number
  102. queryMode: ControlQueryMode
  103. controlFormWillChangeValues: Partial<IControl>
  104. prevVisible: boolean
  105. }
  106. export class ControlConfig extends PureComponent<
  107. IControlConfigProps,
  108. IControlConfigStates
  109. > {
  110. public state: IControlConfigStates = {
  111. controls: [],
  112. editingControlBase: null,
  113. editingRelatedItemList: [],
  114. editingRelatedViewList: [],
  115. defaultValueOptions: [],
  116. defaultValueLoading: false,
  117. optionModalVisible: false,
  118. optionSettingFormValues: null,
  119. editingOptionIndex: -1,
  120. queryMode: ControlQueryMode.Immediately,
  121. controlFormWillChangeValues: null,
  122. prevVisible: false
  123. }
  124. private controlForm: FormType = null
  125. private optionSettingForm: FormType = null
  126. private refHandles = {
  127. controlForm: (ref) => (this.controlForm = ref),
  128. optionSettingForm: (ref) => (this.optionSettingForm = ref)
  129. }
  130. constructor(props) {
  131. super(props)
  132. this.props.onLoadViews()
  133. }
  134. public static getDerivedStateFromProps: GetDerivedStateFromProps<
  135. IControlConfigProps,
  136. IControlConfigStates
  137. > = (props, state) => {
  138. const {
  139. type: panelType,
  140. originalControls,
  141. currentItems,
  142. widgets,
  143. formedViews,
  144. visible,
  145. queryMode,
  146. onLoadViewDetail
  147. } = props
  148. const { prevVisible } = state
  149. let nextState: Partial<IControlConfigStates> = {
  150. prevVisible: visible
  151. }
  152. if (visible && !prevVisible && originalControls) {
  153. const controls = []
  154. const relatedViewIds = []
  155. let editingControl
  156. try {
  157. originalControls.forEach((origin) => {
  158. const control: IControl = JSON.parse(JSON.stringify(origin))
  159. const { type, optionType, valueViewId, relatedItems } = control
  160. if (panelType === ControlPanelTypes.Global) {
  161. Object.keys(relatedItems).forEach((itemId) => {
  162. if (!currentItems.find((ci) => ci.id === Number(itemId))) {
  163. delete relatedItems[itemId]
  164. }
  165. })
  166. }
  167. if (
  168. SHOULD_LOAD_OPTIONS[type] &&
  169. optionType === ControlOptionTypes.Manual &&
  170. !formedViews[valueViewId]
  171. ) {
  172. relatedViewIds.push(valueViewId)
  173. }
  174. if (!editingControl && !control.parent) {
  175. editingControl = control
  176. }
  177. controls.push(control)
  178. })
  179. } catch (error) {
  180. message.error('控制器配置解析失败')
  181. throw error
  182. }
  183. if (relatedViewIds.length) {
  184. onLoadViewDetail(relatedViewIds)
  185. }
  186. nextState = {
  187. ...nextState,
  188. controls,
  189. queryMode,
  190. ...getEditingControlFormValues(
  191. editingControl,
  192. formedViews,
  193. currentItems,
  194. widgets
  195. )
  196. }
  197. }
  198. return nextState
  199. }
  200. private selectControl = (key: string) => {
  201. const { currentItems, widgets, formedViews } = this.props
  202. this.mergeEditingControl((mergedControls) => {
  203. this.setState({
  204. controls: mergedControls,
  205. defaultValueOptions: [],
  206. ...getEditingControlFormValues(
  207. mergedControls.find((c) => c.key === key),
  208. formedViews,
  209. currentItems,
  210. widgets
  211. )
  212. })
  213. this.controlForm.props.form.setFieldsValue({ defaultValue: void 0 })
  214. })
  215. }
  216. private addControl = () => {
  217. const {
  218. type,
  219. relatedViewId,
  220. currentItems,
  221. widgets,
  222. formedViews
  223. } = this.props
  224. const { controls, editingControlBase } = this.state
  225. let control
  226. if (type === ControlPanelTypes.Global) {
  227. control = getDefaultGlobalControl()
  228. } else {
  229. if (relatedViewId && formedViews[relatedViewId]) {
  230. control = getDefaultLocalControl(formedViews[relatedViewId])
  231. } else {
  232. return
  233. }
  234. }
  235. if (editingControlBase) {
  236. this.mergeEditingControl((mergedControls) => {
  237. this.setState({
  238. controls: [...mergedControls, control],
  239. defaultValueOptions: [],
  240. ...getEditingControlFormValues(
  241. control,
  242. formedViews,
  243. currentItems,
  244. widgets
  245. )
  246. })
  247. this.controlForm.props.form.setFieldsValue({ defaultValue: void 0 })
  248. })
  249. } else {
  250. this.setState({
  251. controls: [...controls, control],
  252. ...getEditingControlFormValues(
  253. control,
  254. formedViews,
  255. currentItems,
  256. widgets
  257. )
  258. })
  259. }
  260. }
  261. private deleteControl = (keys: string[], reselectedKey: string) => {
  262. const { currentItems, widgets, formedViews } = this.props
  263. const { controls } = this.state
  264. const reselected = reselectedKey
  265. ? controls.find((c) => c.key === reselectedKey)
  266. : null
  267. this.setState({
  268. controls: controls.filter((c) => !keys.includes(c.key)),
  269. defaultValueOptions: [],
  270. ...getEditingControlFormValues(
  271. reselected,
  272. formedViews,
  273. currentItems,
  274. widgets
  275. )
  276. })
  277. this.controlForm.props.form.setFieldsValue({ defaultValue: void 0 })
  278. }
  279. private changeParent = (
  280. key: string,
  281. parentKey: string,
  282. type: string,
  283. dropNextKey?: string
  284. ) => {
  285. const { editingControlBase, controls } = this.state
  286. let dragged
  287. let changedControls = controls.reduce((ctrls, ctrl) => {
  288. if (ctrl.key === key) {
  289. dragged = ctrl
  290. return ctrls
  291. }
  292. return ctrls.concat(ctrl)
  293. }, [])
  294. let parent = null
  295. let parentIndex
  296. let dropNextIndex
  297. for (let i = 0, l = changedControls.length; i < l; i += 1) {
  298. const control = changedControls[i]
  299. if (control.key === parentKey) {
  300. parent = control
  301. parentIndex = i
  302. }
  303. if (dropNextKey && control.key === dropNextKey) {
  304. dropNextIndex = i
  305. }
  306. }
  307. dragged.parent = parent && parent.key
  308. if (dropNextKey) {
  309. changedControls =
  310. type === 'append'
  311. ? [
  312. ...changedControls.slice(0, dropNextIndex + 1),
  313. dragged,
  314. ...changedControls.slice(dropNextIndex + 1)
  315. ]
  316. : [
  317. ...changedControls.slice(0, dropNextIndex),
  318. dragged,
  319. ...changedControls.slice(dropNextIndex)
  320. ]
  321. } else {
  322. changedControls = parent
  323. ? [
  324. ...changedControls.slice(0, parentIndex + 1),
  325. dragged,
  326. ...changedControls.slice(parentIndex + 1)
  327. ]
  328. : type === 'append'
  329. ? [...changedControls, dragged]
  330. : [dragged, ...changedControls]
  331. }
  332. this.setState({
  333. controls: changedControls,
  334. ...(dragged.key === editingControlBase.key && {
  335. editingControlBase: {
  336. ...editingControlBase,
  337. parent: dragged.parent
  338. }
  339. })
  340. })
  341. }
  342. private changeName = (key: string, name: string) => {
  343. this.setState({
  344. controls: this.state.controls.map((c) => {
  345. return c.key === key ? { ...c, name } : c
  346. })
  347. })
  348. }
  349. private itemCheck = (id: number) => () => {
  350. const editingRelatedItemList = this.state.editingRelatedItemList.map(
  351. (item) =>
  352. item.id === id
  353. ? {
  354. ...item,
  355. checked: !item.checked
  356. }
  357. : item
  358. )
  359. const editingRelatedViewList = this.getEditingRelatedViewList(
  360. editingRelatedItemList
  361. )
  362. this.setState({
  363. editingRelatedItemList,
  364. editingRelatedViewList,
  365. controlFormWillChangeValues: {
  366. ...editingRelatedItemList.reduce(
  367. (values, { id, checked, viewId }) => ({
  368. ...values,
  369. [`relatedItems[${id}].checked`]: checked,
  370. [`relatedItems[${id}].viewId`]: viewId
  371. }),
  372. {}
  373. ),
  374. ...editingRelatedViewList.reduce(
  375. (values, { id, fieldType }) => ({
  376. ...values,
  377. [`relatedViews[${id}].fieldType`]: fieldType
  378. }),
  379. {}
  380. )
  381. }
  382. })
  383. }
  384. private checkAll = (e: CheckboxChangeEvent) => {
  385. const { editingRelatedItemList } = this.state
  386. const allChecked = e.target.checked
  387. const checkedRelatedItemList = editingRelatedItemList.map((v) => ({
  388. ...v,
  389. checked: allChecked
  390. }))
  391. const editingRelatedViewList = allChecked
  392. ? this.getEditingRelatedViewList(checkedRelatedItemList)
  393. : []
  394. this.setState({
  395. editingRelatedItemList: checkedRelatedItemList,
  396. editingRelatedViewList,
  397. controlFormWillChangeValues: {
  398. ...checkedRelatedItemList.reduce(
  399. (values, { id, checked, viewId }) => ({
  400. ...values,
  401. [`relatedItems[${id}].checked`]: checked,
  402. [`relatedItems[${id}].viewId`]: viewId
  403. }),
  404. {}
  405. ),
  406. ...editingRelatedViewList.reduce(
  407. (values, { id, fieldType }) => ({
  408. ...values,
  409. [`relatedViews[${id}].fieldType`]: fieldType
  410. }),
  411. {}
  412. )
  413. }
  414. })
  415. }
  416. private getEditingRelatedViewList = (
  417. relatedItemList: IFlatRelatedItem[]
  418. ): IFlatRelatedView[] => {
  419. const { formedViews } = this.props
  420. const {
  421. editingControlBase: { type },
  422. editingRelatedViewList
  423. } = this.state
  424. return Array.from(
  425. new Set(
  426. relatedItemList
  427. .filter((item) => item.checked)
  428. .map((item) => item.viewId)
  429. )
  430. ).reduce((mergedRelatedViewList, viewId) => {
  431. const relatedView = editingRelatedViewList.find((r) => r.id === viewId)
  432. const view = formedViews[viewId]
  433. return relatedView
  434. ? mergedRelatedViewList.concat(relatedView)
  435. : mergedRelatedViewList.concat(getDefaultRelatedView(view, type))
  436. }, [])
  437. }
  438. private fieldTypeChange = (viewId: number) => (e: RadioChangeEvent) => {
  439. const {
  440. editingControlBase: { type },
  441. editingRelatedViewList
  442. } = this.state
  443. const fieldType = e.target.value
  444. const changedRelatedViewList = editingRelatedViewList.map((relatedView) => {
  445. return relatedView.id === viewId
  446. ? {
  447. ...relatedView,
  448. fieldType,
  449. fields: relatedView.fields
  450. }
  451. : relatedView
  452. })
  453. this.setState({
  454. editingRelatedViewList: changedRelatedViewList,
  455. controlFormWillChangeValues: {
  456. [`relatedViews[${viewId}].fields`]: []
  457. }
  458. })
  459. }
  460. private controlTypeChange = (value) => {
  461. const { formedViews } = this.props
  462. const { editingControlBase, editingRelatedViewList } = this.state
  463. const { multiple } = editingControlBase
  464. const changedControlBase: Partial<IControl> = {
  465. type: value,
  466. multiple: void 0,
  467. optionWithVariable: false,
  468. defaultValueType: ControlDefaultValueTypes.Fixed
  469. }
  470. const changedFields: Partial<IControl> = {
  471. operator: getValidOperator(editingControlBase.operator, value, false),
  472. multiple: void 0,
  473. optionWithVariable: false,
  474. defaultValueType: ControlDefaultValueTypes.Fixed
  475. }
  476. switch (value) {
  477. case ControlTypes.Select:
  478. changedControlBase.optionType = ControlOptionTypes.Auto
  479. changedFields.cache = false
  480. changedFields.expired = DEFAULT_CACHE_EXPIRED
  481. changedFields.optionType = ControlOptionTypes.Auto
  482. break
  483. case ControlTypes.Radio:
  484. changedControlBase.radioType = 'normal'
  485. changedFields.radioType = 'normal'
  486. break
  487. case ControlTypes.TreeSelect:
  488. changedControlBase.optionType = ControlOptionTypes.Manual
  489. changedFields.cache = false
  490. changedFields.expired = DEFAULT_CACHE_EXPIRED
  491. changedFields.optionType = ControlOptionTypes.Manual
  492. break
  493. case ControlTypes.Date:
  494. case ControlTypes.DateRange:
  495. changedFields.dateFormat = getValidDatePickerFormat(
  496. editingControlBase.dateFormat,
  497. value,
  498. multiple
  499. )
  500. break
  501. }
  502. this.setState({
  503. editingControlBase: {
  504. ...editingControlBase,
  505. ...changedControlBase
  506. },
  507. editingRelatedViewList: editingRelatedViewList.map(
  508. ({ fieldType, fields, ...rest }) => ({
  509. ...rest,
  510. models: getRelatedViewModels(formedViews[rest.id], value),
  511. fieldType,
  512. fields
  513. })
  514. ),
  515. controlFormWillChangeValues: changedFields
  516. })
  517. this.controlForm.props.form.setFieldsValue({ defaultValue: void 0 })
  518. }
  519. private multipleSettingChange = (e: CheckboxChangeEvent) => {
  520. const { editingControlBase } = this.state
  521. const { type } = editingControlBase
  522. const changedFields: Partial<IControl> = {
  523. operator: getValidOperator(
  524. editingControlBase.operator,
  525. type,
  526. e.target.checked
  527. ),
  528. defaultValueType: ControlDefaultValueTypes.Fixed,
  529. defaultValue: void 0
  530. }
  531. this.setState({
  532. editingControlBase: {
  533. ...editingControlBase,
  534. multiple: e.target.checked,
  535. defaultValueType: ControlDefaultValueTypes.Fixed
  536. },
  537. controlFormWillChangeValues: changedFields
  538. })
  539. }
  540. private sliderPropChange = (
  541. min: number = 0,
  542. max: number = 0,
  543. step: number
  544. ) => {
  545. const { editingControlBase } = this.state
  546. min = Number(min)
  547. max = Number(max)
  548. const adjustedMin = Math.min(min, max)
  549. const adjustedMax = Math.max(min, max)
  550. const { defaultValue } = this.controlForm.props.form.getFieldsValue()
  551. const adjustedDefaultValue = defaultValue && [
  552. defaultValue[0] >= adjustedMin && defaultValue[0] <= adjustedMax
  553. ? defaultValue[0]
  554. : adjustedMin,
  555. defaultValue[1] >= adjustedMin && defaultValue[1] <= adjustedMax
  556. ? defaultValue[1]
  557. : adjustedMax
  558. ]
  559. this.setState({
  560. editingControlBase: {
  561. ...editingControlBase,
  562. min: adjustedMin,
  563. max: adjustedMax,
  564. step
  565. }
  566. })
  567. this.controlForm.props.form.setFieldsValue({
  568. defaultValue: adjustedDefaultValue
  569. })
  570. }
  571. private optionTypeChange = (e: RadioChangeEvent) => {
  572. const { editingControlBase } = this.state
  573. this.setState({
  574. editingControlBase: {
  575. ...editingControlBase,
  576. optionType: e.target.value,
  577. optionWithVariable: false
  578. },
  579. controlFormWillChangeValues: { defaultValue: void 0 }
  580. })
  581. }
  582. private valueViewChange = (viewId: number) => {
  583. const { formedViews, onLoadViewDetail } = this.props
  584. const { editingControlBase } = this.state
  585. if (!formedViews[viewId]) {
  586. onLoadViewDetail([viewId])
  587. }
  588. this.setState({
  589. editingControlBase: {
  590. ...editingControlBase,
  591. valueViewId: viewId
  592. }
  593. })
  594. }
  595. private defaultValueTypeChange = (e: RadioChangeEvent) => {
  596. const { editingControlBase } = this.state
  597. let changedFields
  598. if (e.target.value === ControlDefaultValueTypes.Dynamic) {
  599. switch (editingControlBase.type) {
  600. case ControlTypes.Date:
  601. changedFields = { defaultValue: getDefaultRelativeDate() }
  602. break
  603. case ControlTypes.DateRange:
  604. changedFields = {
  605. defaultValueStart: getDefaultRelativeDate(),
  606. defaultValueEnd: getDefaultRelativeDate()
  607. }
  608. break
  609. default:
  610. changedFields = { defaultValue: void 0 }
  611. break
  612. }
  613. } else {
  614. changedFields = { defaultValue: void 0 }
  615. }
  616. this.setState({
  617. editingControlBase: {
  618. ...editingControlBase,
  619. defaultValueType: e.target.value
  620. },
  621. controlFormWillChangeValues: changedFields
  622. })
  623. }
  624. private commonControlPropChange = (propName: string, value) => {
  625. const { editingControlBase } = this.state
  626. this.setState({
  627. editingControlBase: {
  628. ...editingControlBase,
  629. [propName]: value
  630. }
  631. })
  632. }
  633. private loadDefaultValueOptions = () => {
  634. const { onGetOptions } = this.props
  635. const { editingControlBase, defaultValueLoading } = this.state
  636. const { type, optionType } = editingControlBase
  637. this.controlForm.props.form.validateFieldsAndScroll(
  638. ['relatedViews', 'valueViewId', 'valueField', 'textField', 'parentField'],
  639. (err, values) => {
  640. if (err) {
  641. return
  642. }
  643. if (SHOULD_LOAD_OPTIONS[type] && !defaultValueLoading) {
  644. switch (optionType) {
  645. case ControlOptionTypes.Auto:
  646. const relatedViewValues = this.convertFieldFormValues({
  647. ...values.relatedViews
  648. })
  649. const relatedViewMap = Object.entries(relatedViewValues)
  650. if (relatedViewMap.length) {
  651. const paramsByViewId = relatedViewMap.reduce(
  652. (obj, [viewId, { fieldType, fields }]) => {
  653. if (fieldType === ControlFieldTypes.Column) {
  654. obj[viewId] = { columns: fields }
  655. }
  656. return obj
  657. },
  658. {}
  659. )
  660. if (Object.keys(paramsByViewId).length) {
  661. this.setState({ defaultValueLoading: true })
  662. onGetOptions(paramsByViewId, (options) => {
  663. message.success('加载成功!')
  664. this.setState({ defaultValueLoading: false })
  665. if (options) {
  666. this.setState({
  667. defaultValueOptions: transformOptions(
  668. {
  669. ...editingControlBase,
  670. ...values,
  671. relatedViews: relatedViewValues
  672. },
  673. options
  674. )
  675. })
  676. }
  677. })
  678. }
  679. }
  680. break
  681. case ControlOptionTypes.Manual:
  682. const { valueViewId, valueField, textField, parentField } = values
  683. const paramsByViewId = {
  684. [valueViewId]: {
  685. columns: [valueField, textField, parentField].filter(
  686. (s) => !!s
  687. )
  688. }
  689. }
  690. this.setState({ defaultValueLoading: true })
  691. onGetOptions(paramsByViewId, (options) => {
  692. message.success('加载成功!')
  693. this.setState({ defaultValueLoading: false })
  694. if (options) {
  695. this.setState({
  696. defaultValueOptions: transformOptions(
  697. {
  698. ...editingControlBase,
  699. ...values,
  700. relatedViews: relatedViewValues
  701. },
  702. options
  703. )
  704. })
  705. }
  706. })
  707. break
  708. }
  709. }
  710. }
  711. )
  712. }
  713. private mergeEditingControl = (resolve: (mergedControls) => void) => {
  714. const { type } = this.props
  715. const { controls, editingControlBase } = this.state
  716. this.controlForm.props.form.validateFieldsAndScroll((err, values) => {
  717. if (err) {
  718. return
  719. }
  720. const {
  721. relatedItems,
  722. relatedViews,
  723. defaultValue,
  724. defaultValueStart,
  725. defaultValueEnd,
  726. ...restFormValues
  727. } = values
  728. const mergedControls = controls.map((control) => {
  729. const { key, name, parent } = control
  730. if (key === editingControlBase.key) {
  731. return {
  732. key,
  733. name,
  734. ...(parent && { parent }),
  735. ...restFormValues,
  736. defaultValue: stringifyDefaultValue(
  737. values,
  738. defaultValue,
  739. defaultValueStart,
  740. defaultValueEnd
  741. ),
  742. ...(type === ControlPanelTypes.Global && {
  743. relatedItems: { ...relatedItems }
  744. }),
  745. relatedViews: this.convertFieldFormValues({ ...relatedViews })
  746. }
  747. } else {
  748. return control
  749. }
  750. })
  751. resolve(mergedControls)
  752. })
  753. }
  754. private convertFieldFormValues = (relatedViewFormValues: {
  755. [viewId: string]: IControlRelatedViewFormValue
  756. }): { [viewId: string]: IControlRelatedView } => {
  757. return Object.entries(relatedViewFormValues).reduce(
  758. (obj, [viewId, { fieldType, fields }]) => {
  759. obj[viewId] = {
  760. fieldType,
  761. fields: [].concat(fields)
  762. }
  763. return obj
  764. },
  765. {}
  766. )
  767. }
  768. private save = () => {
  769. const { onSave } = this.props
  770. const { controls, queryMode } = this.state
  771. if (controls.length > 0) {
  772. this.mergeEditingControl((mergedControls) => {
  773. onSave(mergedControls, queryMode)
  774. })
  775. } else {
  776. onSave([], queryMode)
  777. }
  778. }
  779. private resetForm = () => {
  780. this.setState({
  781. ...getEditingControlFormValues(null)
  782. })
  783. }
  784. private openOptionModal = (index?) => {
  785. const { customOptions } = this.state.editingControlBase
  786. this.setState({
  787. optionModalVisible: true,
  788. optionSettingFormValues:
  789. index !== void 0 && customOptions ? customOptions[index] : null,
  790. ...(index !== void 0 && { editingOptionIndex: index })
  791. })
  792. }
  793. private closeOptionModal = () => {
  794. this.setState({ optionModalVisible: false })
  795. }
  796. private afterOptionModalClose = () => {
  797. this.setState({
  798. optionSettingFormValues: null,
  799. editingOptionIndex: -1
  800. })
  801. this.optionSettingForm.props.form.resetFields()
  802. }
  803. private saveOptions = () => {
  804. this.optionSettingForm.props.form.validateFieldsAndScroll((err, values) => {
  805. if (err) {
  806. return
  807. }
  808. const {
  809. editingControlBase,
  810. editingRelatedViewList,
  811. editingOptionIndex
  812. } = this.state
  813. let customOptions = editingControlBase.customOptions || []
  814. const editingOption: IControlOption = {
  815. value: values.value,
  816. text: values.text || values.value,
  817. ...(editingControlBase.optionWithVariable && {
  818. variables: editingRelatedViewList.reduce((obj, { id }) => {
  819. if (values[id]) {
  820. obj[id] = values[id]
  821. }
  822. return obj
  823. }, {})
  824. })
  825. }
  826. if (editingOptionIndex === -1) {
  827. customOptions = customOptions.concat(editingOption)
  828. } else {
  829. customOptions = customOptions.map((option, index) => {
  830. return index === editingOptionIndex ? editingOption : option
  831. })
  832. }
  833. this.controlForm.props.form.setFieldsValue({ customOptions })
  834. this.setState({
  835. editingControlBase: {
  836. ...editingControlBase,
  837. customOptions
  838. }
  839. })
  840. this.closeOptionModal()
  841. })
  842. }
  843. private deleteOption = (value) => () => {
  844. const { editingControlBase } = this.state
  845. const customOptions = editingControlBase.customOptions.filter(
  846. (o) => o.value !== value
  847. )
  848. this.setState({
  849. editingControlBase: {
  850. ...editingControlBase,
  851. customOptions
  852. }
  853. })
  854. this.controlForm.props.form.setFieldsValue({ customOptions })
  855. }
  856. private changeQueryMode = (e: RadioChangeEvent) => {
  857. this.setState({
  858. queryMode: e.target.value
  859. })
  860. }
  861. public render() {
  862. const { type, views, formedViews, loading, visible, onCancel } = this.props
  863. const {
  864. controls,
  865. editingControlBase,
  866. editingRelatedItemList,
  867. editingRelatedViewList,
  868. defaultValueOptions,
  869. defaultValueLoading,
  870. controlFormWillChangeValues,
  871. optionModalVisible,
  872. optionSettingFormValues,
  873. queryMode
  874. } = this.state
  875. const modalFooter = [
  876. <RadioGroup
  877. key="queryMode"
  878. className={styles.queryMode}
  879. value={queryMode}
  880. onChange={this.changeQueryMode}
  881. >
  882. <RadioButton value={ControlQueryMode.Immediately}>立即查询</RadioButton>
  883. <RadioButton value={ControlQueryMode.Manually}>手动查询</RadioButton>
  884. </RadioGroup>,
  885. <Button key="cancel" size="large" onClick={onCancel}>
  886. 取 消
  887. </Button>,
  888. <Button
  889. key="submit"
  890. size="large"
  891. type="primary"
  892. loading={loading}
  893. disabled={loading}
  894. onClick={this.save}
  895. >
  896. 保 存
  897. </Button>
  898. ]
  899. return (
  900. <Modal
  901. wrapClassName="ant-modal-xlarge"
  902. title={`${
  903. type === ControlPanelTypes.Global ? '全局' : '组件'
  904. }控制器配置`}
  905. maskClosable={false}
  906. visible={visible}
  907. footer={modalFooter}
  908. onCancel={onCancel}
  909. afterClose={this.resetForm}
  910. destroyOnClose
  911. >
  912. <ListFormLayout
  913. type="horizontal"
  914. initialSize={300}
  915. minSize={300}
  916. maxSize={480}
  917. className={styles.container}
  918. spliter
  919. >
  920. <List
  921. title="控制器列表"
  922. className={styles.treeContainer}
  923. onAddItem={this.addControl}
  924. >
  925. <ControlList
  926. list={controls}
  927. selected={editingControlBase}
  928. onSelect={this.selectControl}
  929. onDelete={this.deleteControl}
  930. onNameChange={this.changeName}
  931. onParentChange={this.changeParent}
  932. />
  933. </List>
  934. {editingControlBase && (
  935. <ControlForm
  936. type={type}
  937. views={views}
  938. formedViews={formedViews}
  939. controls={controls}
  940. controlBase={editingControlBase}
  941. relatedItemList={editingRelatedItemList}
  942. relatedViewList={editingRelatedViewList}
  943. defaultValueOptions={defaultValueOptions}
  944. defaultValueLoading={defaultValueLoading}
  945. formWillChangeValues={controlFormWillChangeValues}
  946. onItemCheck={this.itemCheck}
  947. onCheckAll={this.checkAll}
  948. onFieldTypeChange={this.fieldTypeChange}
  949. onControlTypeChange={this.controlTypeChange}
  950. onMultipleSettingChange={this.multipleSettingChange}
  951. onSliderPropChange={this.sliderPropChange}
  952. onOptionTypeChange={this.optionTypeChange}
  953. onValueViewChange={this.valueViewChange}
  954. onDefaultValueTypeChange={this.defaultValueTypeChange}
  955. onGetDefaultValueOptions={this.loadDefaultValueOptions}
  956. onCommonPropChange={this.commonControlPropChange}
  957. onOpenOptionModal={this.openOptionModal}
  958. onDeleteOption={this.deleteOption}
  959. wrappedComponentRef={this.refHandles.controlForm}
  960. />
  961. )}
  962. </ListFormLayout>
  963. <OptionSettingForm
  964. visible={optionModalVisible}
  965. values={optionSettingFormValues}
  966. customOptions={editingControlBase?.customOptions}
  967. optionWithVariable={editingControlBase?.optionWithVariable}
  968. relatedViewList={editingRelatedViewList}
  969. onSave={this.saveOptions}
  970. onCancel={this.closeOptionModal}
  971. afterClose={this.afterOptionModalClose}
  972. wrappedComponentRef={this.refHandles.optionSettingForm}
  973. />
  974. </Modal>
  975. )
  976. }
  977. }
  978. export default ControlConfig