LinkageConfig.tsx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import React from 'react'
  2. import classnames from 'classnames'
  3. import * as echarts from 'echarts/lib/echarts'
  4. import LinkageForm, { ILinkageForm } from './LinkageForm'
  5. import AntdFormType from 'antd/lib/form/Form'
  6. import { Table, Row, Col, Button, Modal } from 'antd'
  7. import { DEFAULT_SPLITER, TABLE_HEADER_HEIGHT } from 'app/globalConstants'
  8. import { uuid } from 'utils/util'
  9. const utilStyles = require('assets/less/util.less')
  10. const styles = require('./Linkage.less')
  11. interface ILinkageConfigProps {
  12. cascaderSource: any[]
  13. linkages: any[]
  14. onGetWidgetInfo: (itemId: number) => void
  15. saving: boolean
  16. onSave: (linkages: any[]) => void
  17. }
  18. interface ILinkageConfigStates {
  19. formVisible: boolean
  20. localLinkages: any[]
  21. }
  22. export class LinkageConfig extends React.PureComponent<ILinkageConfigProps, ILinkageConfigStates> {
  23. constructor (props) {
  24. super(props)
  25. this.state = {
  26. formVisible: false,
  27. localLinkages: []
  28. }
  29. this.refHandlers = {
  30. linkageForm: (ref) => this.linkageForm = ref
  31. }
  32. }
  33. private chart: echarts.ECharts = null
  34. private refHandlers: { linkageForm: (ref: AntdFormType) => void }
  35. private linkageForm: AntdFormType = null
  36. public componentDidMount () {
  37. const { linkages, onGetWidgetInfo } = this.props
  38. this.initState(linkages, onGetWidgetInfo)
  39. }
  40. public componentWillReceiveProps (nextProps: ILinkageConfigProps) {
  41. const { linkages, onGetWidgetInfo, saving, onSave } = nextProps
  42. if (linkages !== this.props.linkages) {
  43. this.initState(linkages, onGetWidgetInfo)
  44. }
  45. if (saving !== this.props.saving) {
  46. const { localLinkages } = this.state
  47. onSave([...localLinkages])
  48. }
  49. }
  50. private initState = (linkages, onGetWidgetInfo) => {
  51. this.setState({
  52. localLinkages: linkages
  53. }, () => {
  54. const { localLinkages } = this.state
  55. if (localLinkages.length) {
  56. this.renderChart(localLinkages, onGetWidgetInfo)
  57. }
  58. })
  59. }
  60. private renderChart = (linkages, onGetWidgetInfo) => {
  61. const nodes = {}
  62. const links = []
  63. linkages.forEach((ts) => {
  64. const triggerId = ts.trigger[0]
  65. const linkagerId = ts.linkager[0]
  66. if (!nodes[triggerId]) {
  67. nodes[triggerId] = onGetWidgetInfo(+triggerId)
  68. }
  69. if (!nodes[linkagerId]) {
  70. nodes[linkagerId] = onGetWidgetInfo(+linkagerId)
  71. }
  72. links.push({
  73. source: nodes[triggerId].name,
  74. target: nodes[linkagerId].name
  75. })
  76. })
  77. if (!this.chart) {
  78. this.chart = echarts.init(document.getElementById('linkageChart') as HTMLDivElement, 'default')
  79. }
  80. const chartOptions = {
  81. animationDurationUpdate: 1000,
  82. animationEasingUpdate: 'quinticInOut',
  83. series: [
  84. {
  85. type: 'graph',
  86. layout: 'circular',
  87. symbolSize: 30,
  88. roam: true,
  89. focusNodeAdjacency: true,
  90. label: {
  91. normal: {
  92. show: true,
  93. position: 'right'
  94. }
  95. },
  96. edgeSymbol: ['circle', 'arrow'],
  97. edgeSymbolSize: [4, 10],
  98. edgeLabel: {
  99. normal: {
  100. }
  101. },
  102. data: Object.values(nodes).map((info: any) => ({
  103. name: info.name,
  104. category: info.type
  105. })),
  106. links,
  107. categories: Object.values(Object.values(nodes).reduce((categories, info: any) => {
  108. if (!categories[info.type]) {
  109. categories[info.type] = {
  110. name: info.type
  111. }
  112. }
  113. return categories
  114. }, {})),
  115. lineStyle: {
  116. normal: {
  117. opacity: 0.9,
  118. curveness: 0
  119. }
  120. }
  121. }
  122. ]
  123. }
  124. this.chart.setOption(chartOptions)
  125. }
  126. private showForm = () => {
  127. this.setState({
  128. formVisible: true
  129. })
  130. }
  131. private hideForm = () => {
  132. this.setState({
  133. formVisible: false
  134. })
  135. }
  136. private resetForm = () => {
  137. this.linkageForm.props.form.resetFields()
  138. }
  139. private addToTable = () => {
  140. this.linkageForm.props.form.validateFieldsAndScroll((err, values) => {
  141. if (!err) {
  142. const { localLinkages } = this.state
  143. this.setState({
  144. localLinkages: [ ...localLinkages, { ...values, key: uuid(8, 16) } ],
  145. formVisible: false
  146. }, () => {
  147. const { onGetWidgetInfo } = this.props
  148. this.renderChart(this.state.localLinkages, onGetWidgetInfo)
  149. })
  150. }
  151. })
  152. }
  153. private deleteFromTable = (key) => () => {
  154. this.setState({
  155. localLinkages: this.state.localLinkages.filter((lt) => lt.key !== key)
  156. }, () => {
  157. const { onGetWidgetInfo } = this.props
  158. this.renderChart(this.state.localLinkages, onGetWidgetInfo)
  159. })
  160. }
  161. public render () {
  162. const {
  163. cascaderSource
  164. } = this.props
  165. const { localLinkages } = this.state
  166. const { formVisible } = this.state
  167. const PANEL_BODY_HEIGHT = 401
  168. const TOOLS_HEIGHT = 28
  169. const chartContainerClass = classnames({
  170. [utilStyles.hide]: !localLinkages.length
  171. })
  172. const emptyChartClass = classnames({
  173. [utilStyles.hide]: localLinkages.length
  174. })
  175. return (
  176. <Row gutter={16}>
  177. <Col span={12}>
  178. <div className={styles.tools}>
  179. <Button
  180. type="primary"
  181. onClick={this.showForm}
  182. >
  183. 新增
  184. </Button>
  185. </div>
  186. <Table
  187. columns={[
  188. {
  189. key: 'trigger',
  190. title: '触发器',
  191. width: 155,
  192. dataIndex: 'trigger',
  193. render: (val) => {
  194. const { cascaderSource } = this.props
  195. const triggerData = cascaderSource.find((ts) => ts.value === val[0])
  196. const triggerColumnData = triggerData.children.triggerColumns.find((c) => c.value === val[1])
  197. return `${triggerData.label} - ${triggerColumnData.label}`
  198. }
  199. }, {
  200. key: 'linkager',
  201. title: '联动图表',
  202. width: 155,
  203. dataIndex: 'linkager',
  204. render: (val) => {
  205. const { cascaderSource } = this.props
  206. const linkagerData = cascaderSource.find((fs) => fs.value === val[0])
  207. const linkagerColumnData = val[1].split(DEFAULT_SPLITER)
  208. const linkagerColumnText = `${linkagerColumnData[0]}[${linkagerColumnData[2] === 'column' ? '字段' : '变量'}]`
  209. return `${linkagerData.label} - ${linkagerColumnText}`
  210. }
  211. }, {
  212. key: 'relation',
  213. title: '关系',
  214. width: 50,
  215. className: `${utilStyles.textAlignCenter}`,
  216. dataIndex: 'relation'
  217. }, {
  218. title: '操作',
  219. width: 50,
  220. className: `${utilStyles.textAlignCenter}`,
  221. render: (val, record) => (
  222. <span>
  223. <a onClick={this.deleteFromTable(record.key)}>删除</a>
  224. </span>
  225. )
  226. }
  227. ]}
  228. dataSource={localLinkages}
  229. pagination={false}
  230. scroll={{ y: PANEL_BODY_HEIGHT - TOOLS_HEIGHT - TABLE_HEADER_HEIGHT }}
  231. />
  232. </Col>
  233. <Col span={12}>
  234. <div id="linkageChart" className={`${styles.chartContainer} ${chartContainerClass}`} />
  235. <div className={`${styles.chartEmpty} ${emptyChartClass}`}>
  236. <i className="iconfont icon-jiedian" />
  237. <p>暂无联动数据</p>
  238. </div>
  239. </Col>
  240. <Modal
  241. title="新增联动项"
  242. wrapClassName="ant-modal-small"
  243. visible={formVisible}
  244. onOk={this.addToTable}
  245. onCancel={this.hideForm}
  246. afterClose={this.resetForm}
  247. >
  248. <LinkageForm
  249. cascaderSource={cascaderSource}
  250. wrappedComponentRef={this.refHandlers.linkageForm}
  251. />
  252. </Modal>
  253. </Row>
  254. )
  255. }
  256. }
  257. export default LinkageConfig