ValueForm.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  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, { FC, useMemo, useCallback, memo } from 'react'
  21. import classnames from 'classnames'
  22. import {
  23. Form,
  24. Row,
  25. Col,
  26. Input,
  27. Checkbox,
  28. Select,
  29. Radio,
  30. Icon,
  31. Table,
  32. Divider,
  33. Tooltip,
  34. Popconfirm,
  35. Button
  36. } from 'antd'
  37. import DefaultValue from './DefaultValue'
  38. import { WrappedFormUtils } from 'antd/lib/form/Form'
  39. import { RadioChangeEvent } from 'antd/lib/radio'
  40. import { CheckboxChangeEvent } from 'antd/lib/checkbox'
  41. import {
  42. SHOULD_LOAD_OPTIONS,
  43. ControlOptionTypes,
  44. ControlTypes
  45. } from '../../constants'
  46. import { IControl, IControlOption } from '../../types'
  47. import { IViewBase, IFormedViews } from 'app/containers/View/types'
  48. import { OperatorTypesLocale } from 'app/utils/operatorTypes'
  49. import { getOperatorOptions } from '../../util'
  50. import { filterSelectOption } from 'app/utils/util'
  51. import { TreeNode } from 'antd/lib/tree-select'
  52. import utilStyles from 'assets/less/util.less'
  53. import { ColumnProps } from 'antd/lib/table'
  54. const FormItem = Form.Item
  55. const Option = Select.Option
  56. const RadioGroup = Radio.Group
  57. interface IValueFormProps {
  58. form: WrappedFormUtils
  59. views: IViewBase[]
  60. formedViews: IFormedViews
  61. controlBase: Omit<IControl, 'relatedItems' | 'relatedViews'>
  62. defaultValueOptions: Array<IControlOption | TreeNode>
  63. defaultValueLoading: boolean
  64. onOptionTypeChange: (e: RadioChangeEvent) => void
  65. onValueViewChange: (viewId: number) => void
  66. onDefaultValueTypeChange: (e: RadioChangeEvent) => void
  67. onGetDefaultValueOptions: () => void
  68. onCommonPropChange: (propName: string, value) => void
  69. onOpenOptionModal: (index?: number) => void
  70. onDeleteOption: (value: string) => () => void
  71. }
  72. const ValueForm: FC<IValueFormProps> = ({
  73. form,
  74. views,
  75. formedViews,
  76. controlBase,
  77. defaultValueOptions,
  78. defaultValueLoading,
  79. onOptionTypeChange,
  80. onValueViewChange,
  81. onDefaultValueTypeChange,
  82. onGetDefaultValueOptions,
  83. onCommonPropChange,
  84. onOpenOptionModal,
  85. onDeleteOption
  86. }) => {
  87. const { getFieldDecorator } = form
  88. const {
  89. type,
  90. multiple,
  91. optionType,
  92. valueViewId,
  93. customOptions,
  94. optionWithVariable
  95. } = controlBase
  96. const operatorOptions = useMemo(() => getOperatorOptions(type, multiple), [
  97. type,
  98. multiple
  99. ])
  100. const fieldOptions = useMemo(
  101. () =>
  102. optionType === ControlOptionTypes.Manual && valueViewId
  103. ? Object.keys(formedViews[valueViewId].model).map((name) => (
  104. <Option key={name} value={name}>
  105. {name}
  106. </Option>
  107. ))
  108. : [],
  109. [formedViews, optionType, valueViewId]
  110. )
  111. const optionWithVariableChange = useCallback(
  112. (e: CheckboxChangeEvent) => {
  113. onCommonPropChange('optionWithVariable', e.target.checked)
  114. },
  115. [onCommonPropChange]
  116. )
  117. const addOption = useCallback(() => {
  118. onOpenOptionModal()
  119. }, [onOpenOptionModal])
  120. const editOption = useCallback(
  121. (index) => () => {
  122. onOpenOptionModal(index)
  123. },
  124. [onOpenOptionModal]
  125. )
  126. const columns: Array<ColumnProps<IControlOption>> = [
  127. {
  128. title: '文本',
  129. key: 'text',
  130. dataIndex: 'text',
  131. render: (text) => (text.length > 10 ? `${text.substr(0, 10)}...` : text)
  132. },
  133. {
  134. title: '值',
  135. key: 'value',
  136. dataIndex: 'value',
  137. render: (value) =>
  138. value.length > 10 ? `${value.substr(0, 10)}...` : value
  139. }
  140. ]
  141. if (optionWithVariable) {
  142. columns.push({
  143. title: '关联变量',
  144. key: 'variables',
  145. dataIndex: 'variables',
  146. render: (variables) => variables && Object.values(variables)
  147. })
  148. }
  149. columns.push({
  150. title: '操作',
  151. width: 100,
  152. className: utilStyles.textAlignCenter,
  153. render: (_, record, index) => (
  154. <span className="ant-table-action-column">
  155. <Tooltip title="修改">
  156. <Button
  157. icon="edit"
  158. shape="circle"
  159. type="ghost"
  160. onClick={editOption(index)}
  161. />
  162. </Tooltip>
  163. <Popconfirm
  164. title="确定删除?"
  165. placement="bottom"
  166. onConfirm={onDeleteOption(record.value)}
  167. >
  168. <Tooltip title="删除">
  169. <Button icon="delete" shape="circle" type="ghost" />
  170. </Tooltip>
  171. </Popconfirm>
  172. </span>
  173. )
  174. })
  175. const colSpan = { xxl: 12, xl: 18 }
  176. const itemCols = {
  177. labelCol: { span: 8 },
  178. wrapperCol: { span: 12 }
  179. }
  180. return (
  181. <>
  182. <Divider orientation="left">取值配置</Divider>
  183. {!!operatorOptions.length && (
  184. <Row>
  185. <Col {...colSpan}>
  186. <FormItem label="对应关系" {...itemCols}>
  187. {getFieldDecorator('operator', {
  188. rules: [{ required: true, message: '对应关系不能为空' }]
  189. })(
  190. <Select>
  191. {operatorOptions.map((o) => (
  192. <Option key={o} value={o}>
  193. {OperatorTypesLocale[o]}
  194. </Option>
  195. ))}
  196. </Select>
  197. )}
  198. </FormItem>
  199. </Col>
  200. </Row>
  201. )}
  202. {SHOULD_LOAD_OPTIONS[type] && (
  203. <>
  204. <Row
  205. key="optionType"
  206. className={classnames({
  207. [utilStyles.hide]: type === ControlTypes.TreeSelect
  208. })}
  209. >
  210. <Col {...colSpan}>
  211. <FormItem label="下拉菜单项" {...itemCols}>
  212. {getFieldDecorator(
  213. 'optionType',
  214. {}
  215. )(
  216. <RadioGroup onChange={onOptionTypeChange}>
  217. <Radio value={ControlOptionTypes.Auto}>自动关联</Radio>
  218. <Radio value={ControlOptionTypes.Manual}>手动</Radio>
  219. <Radio value={ControlOptionTypes.Custom}>自定义</Radio>
  220. </RadioGroup>
  221. )}
  222. </FormItem>
  223. </Col>
  224. </Row>
  225. {optionType === ControlOptionTypes.Manual && (
  226. <>
  227. <Row key="valueViewId">
  228. <Col {...colSpan}>
  229. <FormItem label="数据视图" {...itemCols}>
  230. {getFieldDecorator('valueViewId', {
  231. rules: [{ required: true, message: '数据视图不能为空' }]
  232. })(
  233. <Select
  234. showSearch
  235. placeholder="请手动关联数据视图"
  236. onChange={onValueViewChange}
  237. filterOption={filterSelectOption}
  238. >
  239. {views.map(({ id, name }) => (
  240. <Option key={id} value={id}>
  241. {name}
  242. </Option>
  243. ))}
  244. </Select>
  245. )}
  246. </FormItem>
  247. </Col>
  248. </Row>
  249. <Row key="valueField">
  250. <Col {...colSpan}>
  251. <FormItem label="取值字段" {...itemCols}>
  252. {getFieldDecorator('valueField', {
  253. rules: [{ required: true, message: '取值字段不能为空' }]
  254. })(
  255. <Select
  256. showSearch
  257. placeholder="请选择取值字段"
  258. filterOption={filterSelectOption}
  259. >
  260. {fieldOptions}
  261. </Select>
  262. )}
  263. </FormItem>
  264. </Col>
  265. </Row>
  266. {type === ControlTypes.TreeSelect && (
  267. <Row key="parentField">
  268. <Col {...colSpan}>
  269. <FormItem label="父ID字段" {...itemCols}>
  270. {getFieldDecorator('parentField', {
  271. rules: [{ required: true, message: '父ID字段不能为空' }]
  272. })(
  273. <Select
  274. showSearch
  275. placeholder="请选择父ID字段"
  276. filterOption={filterSelectOption}
  277. >
  278. {fieldOptions}
  279. </Select>
  280. )}
  281. </FormItem>
  282. </Col>
  283. </Row>
  284. )}
  285. <Row key="textField">
  286. <Col {...colSpan}>
  287. <FormItem
  288. label="文本字段"
  289. {...itemCols}
  290. help="如不设置文本字段,下拉菜单项则默认显示取值字段的值"
  291. >
  292. {getFieldDecorator(
  293. 'textField',
  294. {}
  295. )(
  296. <Select
  297. showSearch
  298. placeholder="请选择文本字段"
  299. filterOption={filterSelectOption}
  300. allowClear
  301. >
  302. {fieldOptions}
  303. </Select>
  304. )}
  305. </FormItem>
  306. </Col>
  307. </Row>
  308. </>
  309. )}
  310. {optionType === ControlOptionTypes.Custom && (
  311. <>
  312. <Row>
  313. <Col {...colSpan}>
  314. <FormItem label="选项关联变量" {...itemCols}>
  315. {getFieldDecorator('optionWithVariable', {
  316. valuePropName: 'checked'
  317. })(<Checkbox onChange={optionWithVariableChange} />)}
  318. </FormItem>
  319. </Col>
  320. </Row>
  321. <Row>
  322. <Col {...colSpan}>
  323. <FormItem label=" " colon={false} {...itemCols}>
  324. <a onClick={addOption}>
  325. <Icon type="plus" /> 点击添加
  326. </a>
  327. </FormItem>
  328. <FormItem className={utilStyles.hide}>
  329. {getFieldDecorator('customOptions', {})(<Input />)}
  330. </FormItem>
  331. </Col>
  332. </Row>
  333. <Row>
  334. <Col span={24}>
  335. <FormItem
  336. label=" "
  337. colon={false}
  338. labelCol={{ xxl: 4, xl: 6, span: 8 }}
  339. wrapperCol={{ xxl: 16, xl: 14, span: 12 }}
  340. >
  341. <Table
  342. size="small"
  343. rowKey="value"
  344. dataSource={customOptions}
  345. columns={columns}
  346. pagination={false}
  347. bordered
  348. />
  349. </FormItem>
  350. </Col>
  351. </Row>
  352. </>
  353. )}
  354. </>
  355. )}
  356. <DefaultValue
  357. form={form}
  358. controlBase={controlBase}
  359. defaultValueOptions={defaultValueOptions}
  360. defaultValueLoading={defaultValueLoading}
  361. onDefaultValueTypeChange={onDefaultValueTypeChange}
  362. onGetDefaultValueOptions={onGetDefaultValueOptions}
  363. />
  364. </>
  365. )
  366. }
  367. export default memo(ValueForm)