ColumnConfigModal.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. import React from 'react'
  2. import classnames from 'classnames'
  3. import produce from 'immer'
  4. import set from 'lodash/set'
  5. import { uuid } from 'utils/util'
  6. import { fontWeightOptions, fontStyleOptions, fontFamilyOptions, fontSizeOptions } from '../constants'
  7. import { defaultConditionStyle, AvailableTableConditionStyleTypes } from './constants'
  8. import { getColumnIconByType } from './util'
  9. import { ITableColumnConfig, ITableConditionStyle } from './types'
  10. import ColorPicker from 'components/ColorPicker'
  11. import ConditionStyleConfigModal from './ConditionStyleConfigModal'
  12. import { Row, Col, Tooltip, Form, Select, InputNumber, Button, Radio, Checkbox, Table, Modal } from 'antd'
  13. const RadioGroup = Radio.Group
  14. const RadioButton = Radio.Button
  15. const FormItem = Form.Item
  16. import styles from './styles.less'
  17. import stylesConfig from '../styles.less'
  18. interface IColumnStyleConfigProps {
  19. visible: boolean
  20. config: ITableColumnConfig[]
  21. onCancel: () => void
  22. onSave: (config: ITableColumnConfig[]) => void
  23. }
  24. interface IColumnStyleConfigStates {
  25. localConfig: ITableColumnConfig[]
  26. selectedColumnName: string
  27. conditionStyleConfigModalVisible: boolean
  28. currentConditionStyle: ITableConditionStyle
  29. }
  30. export class ColumnStyleConfig extends React.PureComponent<IColumnStyleConfigProps, IColumnStyleConfigStates> {
  31. public constructor (props: IColumnStyleConfigProps) {
  32. super(props)
  33. const localConfig = props.config
  34. this.state = {
  35. localConfig,
  36. selectedColumnName: localConfig.length > 0 ? localConfig[0].columnName : '',
  37. conditionStyleConfigModalVisible: false,
  38. currentConditionStyle: null
  39. }
  40. }
  41. public componentWillReceiveProps (nextProps: IColumnStyleConfigProps) {
  42. if (nextProps.config === this.props.config) { return }
  43. const localConfig = nextProps.config
  44. this.setState({
  45. localConfig,
  46. selectedColumnName: localConfig.length > 0 ? localConfig[0].columnName : '',
  47. conditionStyleConfigModalVisible: false,
  48. currentConditionStyle: null
  49. })
  50. }
  51. private renderColumn (item: ITableColumnConfig) {
  52. const { selectedColumnName } = this.state
  53. const { columnName, alias, visualType } = item
  54. const displayName = alias || columnName
  55. const itemCls = classnames({
  56. [styles.selected]: selectedColumnName === columnName
  57. })
  58. return (
  59. <li className={itemCls} key={columnName} onClick={this.selectColumn(columnName)}>
  60. <i className={`iconfont ${getColumnIconByType(visualType)}`} />
  61. <Tooltip title={displayName} mouseEnterDelay={0.8}>
  62. <label>{displayName}</label>
  63. </Tooltip>
  64. </li>
  65. )
  66. }
  67. private selectColumn = (columnName: string) => () => {
  68. this.setState({
  69. selectedColumnName: columnName
  70. })
  71. }
  72. private propChange = (
  73. propPath: Exclude<keyof(ITableColumnConfig), 'style'> | ['style', keyof ITableColumnConfig['style']]
  74. ) => (e) => {
  75. const value = e.target ? (e.target.value || e.target.checked) : e
  76. const { localConfig, selectedColumnName } = this.state
  77. const nextLocalConfig = produce(localConfig, (draft) => {
  78. const selectedColumn = draft.find(({ columnName }) => columnName === selectedColumnName)
  79. set(selectedColumn, propPath, value)
  80. return draft
  81. })
  82. this.setState({
  83. localConfig: nextLocalConfig
  84. })
  85. }
  86. private cancel = () => {
  87. this.props.onCancel()
  88. }
  89. private save = () => {
  90. this.props.onSave(this.state.localConfig)
  91. }
  92. private columns = [{
  93. title: '',
  94. dataIndex: 'idx',
  95. width: 30,
  96. render: (_, __, index) => (index + 1)
  97. }, {
  98. title: '样式类型',
  99. dataIndex: 'type',
  100. width: 50,
  101. render: (type) => AvailableTableConditionStyleTypes[type]
  102. }, {
  103. title: '操作',
  104. dataIndex: 'operation',
  105. width: 60,
  106. render: (_, record) => (
  107. <div className={styles.btns}>
  108. <Button onClick={this.editConditionStyle(record)} icon="edit" shape="circle" size="small" />
  109. <Button onClick={this.deleteConditionStyle(record.key)} icon="delete" shape="circle" size="small" />
  110. </div>
  111. )
  112. }]
  113. private addConditionStyle = () => {
  114. this.setState({
  115. conditionStyleConfigModalVisible: true,
  116. currentConditionStyle: {
  117. ...defaultConditionStyle
  118. }
  119. })
  120. }
  121. private editConditionStyle = (record) => () => {
  122. this.setState({
  123. currentConditionStyle: record,
  124. conditionStyleConfigModalVisible: true
  125. })
  126. }
  127. private deleteConditionStyle = (deletedKey: string) => () => {
  128. const { localConfig, selectedColumnName } = this.state
  129. const nextLocalConfig = produce(localConfig, (draft) => {
  130. const selectedColumn = draft.find(({ columnName }) => columnName === selectedColumnName)
  131. const idx = selectedColumn.conditionStyles.findIndex(({ key }) => key === deletedKey)
  132. selectedColumn.conditionStyles.splice(idx, 1)
  133. })
  134. this.setState({ localConfig: nextLocalConfig })
  135. }
  136. private closeConditionStyleConfig = () => {
  137. this.setState({
  138. conditionStyleConfigModalVisible: false,
  139. currentConditionStyle: null
  140. })
  141. }
  142. private saveConditionStyleConfig = (conditionStyle: ITableConditionStyle) => {
  143. const { localConfig, selectedColumnName } = this.state
  144. const nextLocalConfig = produce(localConfig, (draft) => {
  145. const selectedColumn = draft.find(({ columnName }) => columnName === selectedColumnName)
  146. if (conditionStyle.key) {
  147. const idx = selectedColumn.conditionStyles.findIndex(({ key }) => key === conditionStyle.key)
  148. selectedColumn.conditionStyles.splice(idx, 1, conditionStyle)
  149. } else {
  150. selectedColumn.conditionStyles.push({ ...conditionStyle, key: uuid(5) })
  151. }
  152. })
  153. this.setState({
  154. localConfig: nextLocalConfig,
  155. conditionStyleConfigModalVisible: false,
  156. currentConditionStyle: null
  157. })
  158. }
  159. private modalFooter = [(
  160. <Button
  161. key="cancel"
  162. size="large"
  163. onClick={this.cancel}
  164. >
  165. 取 消
  166. </Button>
  167. ), (
  168. <Button
  169. key="submit"
  170. size="large"
  171. type="primary"
  172. onClick={this.save}
  173. >
  174. 保 存
  175. </Button>
  176. )]
  177. public render () {
  178. const { visible } = this.props
  179. const {
  180. localConfig, selectedColumnName,
  181. conditionStyleConfigModalVisible, currentConditionStyle } = this.state
  182. if (localConfig.length <= 0) {
  183. return (<div />)
  184. }
  185. const { style, visualType, sort, conditionStyles } = localConfig.find((c) => c.columnName === selectedColumnName)
  186. const { fontSize, fontFamily, fontWeight, fontColor, fontStyle, backgroundColor, justifyContent, inflexible, width } = style
  187. return (
  188. <Modal
  189. title="数据列设置"
  190. wrapClassName="ant-modal-large"
  191. maskClosable={false}
  192. footer={this.modalFooter}
  193. visible={visible}
  194. onCancel={this.cancel}
  195. onOk={this.save}
  196. >
  197. <div className={styles.columnStyleConfig}>
  198. <div className={styles.left}>
  199. <div className={styles.title}>
  200. <h2>字段列表</h2>
  201. </div>
  202. <div className={styles.list}>
  203. <ul>
  204. {localConfig.map((item) => this.renderColumn(item))}
  205. </ul>
  206. </div>
  207. </div>
  208. <div className={styles.right}>
  209. <div className={styles.title}><h2>排序与过滤</h2></div>
  210. <div className={stylesConfig.rows}>
  211. <Row gutter={8} type="flex" align="middle" className={stylesConfig.rowBlock}>
  212. <Col span={12}>
  213. <Checkbox checked={sort} onChange={this.propChange('sort')}>开启列排序</Checkbox>
  214. </Col>
  215. </Row>
  216. </div>
  217. <div className={styles.title}><h2>基础样式</h2></div>
  218. <div className={stylesConfig.rows}>
  219. <Row gutter={8} type="flex" align="middle" className={stylesConfig.rowBlock}>
  220. <Col span={3}>
  221. <FormItem label="背景色">
  222. <div className={styles.colorPickerWrapper}>
  223. <ColorPicker
  224. className={stylesConfig.color}
  225. value={backgroundColor}
  226. onChange={this.propChange(['style', 'backgroundColor'])}
  227. />
  228. </div>
  229. </FormItem>
  230. </Col>
  231. <Col span={9}>
  232. <FormItem label="对齐">
  233. <RadioGroup size="small" value={justifyContent} onChange={this.propChange(['style', 'justifyContent'])}>
  234. <RadioButton value="flex-start">左对齐</RadioButton>
  235. <RadioButton value="center">居中</RadioButton>
  236. <RadioButton value="flex-end">右对齐</RadioButton>
  237. </RadioGroup>
  238. </FormItem>
  239. </Col>
  240. <Col span={5}>
  241. <FormItem label="列宽">
  242. <Checkbox
  243. checked={inflexible}
  244. onChange={this.propChange(['style', 'inflexible'])}
  245. >
  246. 固定列宽
  247. </Checkbox>
  248. </FormItem>
  249. </Col>
  250. <Col span={5}>
  251. <FormItem label=" " colon={false}>
  252. <InputNumber
  253. size="small"
  254. className={stylesConfig.colControl}
  255. placeholder="设置列宽"
  256. value={width}
  257. disabled={!inflexible}
  258. onChange={this.propChange(['style', 'width'])}
  259. />
  260. </FormItem>
  261. </Col>
  262. </Row>
  263. <Row gutter={8} type="flex" align="middle" className={stylesConfig.rowBlock}>
  264. <Col span={4}>
  265. <FormItem label="字体与样式">
  266. <Select
  267. size="small"
  268. className={stylesConfig.colControl}
  269. placeholder="字体"
  270. value={fontFamily}
  271. onChange={this.propChange(['style', 'fontFamily'])}
  272. >
  273. {fontFamilyOptions}
  274. </Select>
  275. </FormItem>
  276. </Col>
  277. <Col span={4}>
  278. <FormItem label=" " colon={false}>
  279. <Select
  280. size="small"
  281. className={stylesConfig.colControl}
  282. placeholder="文字大小"
  283. value={fontSize}
  284. onChange={this.propChange(['style', 'fontSize'])}
  285. >
  286. {fontSizeOptions}
  287. </Select>
  288. </FormItem>
  289. </Col>
  290. <Col span={4}>
  291. <FormItem label=" " colon={false}>
  292. <Select
  293. size="small"
  294. className={stylesConfig.colControl}
  295. value={fontStyle}
  296. onChange={this.propChange(['style', 'fontStyle'])}
  297. >
  298. {fontStyleOptions}
  299. </Select>
  300. </FormItem>
  301. </Col>
  302. <Col span={5}>
  303. <FormItem label=" " colon={false}>
  304. <Select
  305. size="small"
  306. className={stylesConfig.colControl}
  307. value={fontWeight}
  308. onChange={this.propChange(['style', 'fontWeight'])}
  309. >
  310. {fontWeightOptions}
  311. </Select>
  312. </FormItem>
  313. </Col>
  314. <Col span={3}>
  315. <FormItem label=" " colon={false}>
  316. <ColorPicker
  317. className={stylesConfig.color}
  318. value={fontColor}
  319. onChange={this.propChange(['style', 'fontColor'])}
  320. />
  321. </FormItem>
  322. </Col>
  323. </Row>
  324. </div>
  325. <div className={styles.title}>
  326. <h2>条件样式</h2>
  327. <Button type="primary" onClick={this.addConditionStyle} shape="circle" icon="plus" size="small" />
  328. </div>
  329. <div className={styles.table}>
  330. <Table
  331. bordered={true}
  332. pagination={false}
  333. columns={this.columns}
  334. dataSource={conditionStyles}
  335. />
  336. </div>
  337. </div>
  338. </div>
  339. <ConditionStyleConfigModal
  340. visible={conditionStyleConfigModalVisible}
  341. visualType={visualType}
  342. style={currentConditionStyle}
  343. onCancel={this.closeConditionStyleConfig}
  344. onSave={this.saveConditionStyleConfig}
  345. />
  346. </Modal>
  347. )
  348. }
  349. }
  350. export default ColumnStyleConfig