BlockActionObject.jsx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. import React from 'react'
  2. import cls from 'classnames'
  3. import i18n from 'i18next'
  4. import { Menu, Dropdown } from 'antd'
  5. import newEventActions from 'actions/newEvent'
  6. import treeActions from 'actions/tree'
  7. import newEventStores from 'stores/newEvent'
  8. import widgetStore from 'stores/widget'
  9. import treeStores from 'stores/tree'
  10. import { shallowEqualImmutable } from 'utils/utils'
  11. import getTypeIcon from 'utils/commons/getTypeIcon'
  12. import {
  13. getEventBlockByBid,
  14. getParentBlock,
  15. getChildIndex,
  16. getEventNodeById,
  17. getActionBlockObjNode
  18. } from 'stores/funcs/newEvent'
  19. import {
  20. nodeIsFunctionGroup,
  21. nodeIsService,
  22. nodeIsTransaction,
  23. nodeIsIotMessage,
  24. nodeIsDyTransaction,
  25. nodeIsFunction
  26. } from 'stores/funcs/nodeType'
  27. import { getNodeIconByEnvs } from 'stores/funcs/tree'
  28. import {
  29. isServerRootNode,
  30. isChangedActionValid
  31. } from 'stores/funcs/event/methodUtils'
  32. import { getNodeTypeName, getFakeNodeIds } from 'stores/funcs/event/fakeNode'
  33. import { EVENT_BLOCK_TYPE, BLOCK_OP_TYPE } from 'const/const'
  34. import { specialActionObj, fakeNodeIds } from 'const/enum'
  35. import BlockEnable from '../BlockEnable'
  36. import ObjSelector from 'src/components/common/objSelector/ObjSelector'
  37. import TitleTip from 'src/components/common/titleTip/TitleTip'
  38. const MenuItem = Menu.Item
  39. export default class BlockActionObject extends React.Component {
  40. constructor(props) {
  41. super(props)
  42. this.curEventNodeId = newEventStores.curEventNodeId
  43. this.state = {
  44. object: this.getObject()
  45. }
  46. this.objSelector = React.createRef()
  47. this.onEventChange = this.onEventChange.bind(this)
  48. this.genObjSelectConfig = this.genObjSelectConfig.bind(this)
  49. this.onAddAction = this.onAddAction.bind(this)
  50. this.shouldClearAction = this.shouldClearAction.bind(this)
  51. this.dealChangeActionObject = this.dealChangeActionObject.bind(this)
  52. this.onSelectObj = this.onSelectObj.bind(this)
  53. this.onActionObjectSelect = this.onActionObjectSelect.bind(this)
  54. this.getSpecialObjName = this.getSpecialObjName.bind(this)
  55. this.getActionObjName = this.getActionObjName.bind(this)
  56. this.getActionObjIcon = this.getActionObjIcon.bind(this)
  57. this.getObject = this.getObject.bind(this)
  58. this.jumpToNode = this.jumpToNode.bind(this)
  59. this.objJumpBtn = this.objJumpBtn.bind(this)
  60. }
  61. shouldComponentUpdate(nextProps, nextState) {
  62. return (
  63. !shallowEqualImmutable(this.props, nextProps) ||
  64. !shallowEqualImmutable(this.state, nextState)
  65. )
  66. }
  67. componentDidUpdate(preProps) {
  68. if (preProps.bid !== this.props.bid) {
  69. this.setState({
  70. object: this.getObject()
  71. })
  72. }
  73. }
  74. componentDidMount() {
  75. this.unsubscribe = newEventStores.listen(this.onEventChange)
  76. }
  77. componentWillUnmount() {
  78. this.unsubscribe()
  79. }
  80. onEventChange(status) {
  81. let obj = {}
  82. if (status) {
  83. if (
  84. status.types.includes('curEventNodeId') &&
  85. this.curEventNodeId !== status.data.curEventNodeId
  86. ) {
  87. this.curEventNodeId = status.data.curEventNodeId
  88. }
  89. if (
  90. status.types.includes('reloadBlock') &&
  91. this.props.bid === status.data.affectBlockId
  92. ) {
  93. obj.object = this.getObject()
  94. }
  95. }
  96. if (Object.keys(obj).length > 0) {
  97. this.setState(obj)
  98. }
  99. }
  100. genObjSelectConfig() {
  101. return {
  102. srcId: this.curEventNodeId,
  103. srcInStage: {
  104. stage: true,
  105. server: {
  106. allow: [
  107. 'service',
  108. 'db',
  109. 'data-live',
  110. 'data-excel',
  111. 'data-sharedService'
  112. ],
  113. forbidden: [
  114. 'data-mallProduct',
  115. 'data-mallOrder',
  116. 'data-mallCart',
  117. 'data-voteCandidate',
  118. 'data-voteRecord',
  119. 'data-dynamoDb',
  120. 'data-cacheDb',
  121. 'data-email',
  122. 'data-sms'
  123. ]
  124. }
  125. },
  126. srcInServer: {
  127. stage: false,
  128. server: true
  129. },
  130. srcFrom: 'actionObj'
  131. }
  132. }
  133. onAddAction() {
  134. let nodeId = this.props.eventNodeId || this.curEventNodeId
  135. let parentBlock = getParentBlock(this.props.bid, nodeId)
  136. if (parentBlock) {
  137. let index = getChildIndex(parentBlock, this.props.bid)
  138. if (index !== -1) {
  139. newEventActions.addBlock({
  140. type: EVENT_BLOCK_TYPE.ACTION,
  141. parentBid: parentBlock.eventId ? parentBlock.eventId : parentBlock.ln,
  142. index: index + 1
  143. })
  144. }
  145. }
  146. }
  147. shouldClearAction(block, obj) {
  148. let result = false
  149. let nodeId = this.props.eventNodeId || this.curEventNodeId
  150. let node = getEventNodeById(nodeId)
  151. // 对象改变
  152. let preObj = this.getBlockObj(block)
  153. let preObject = getActionBlockObjNode({
  154. obj: preObj,
  155. nodeId
  156. })
  157. let curObject = getActionBlockObjNode({
  158. obj: obj,
  159. nodeId
  160. })
  161. if (
  162. (!preObject && curObject) ||
  163. (preObject && !curObject) ||
  164. (!preObject && !curObject && block.op) ||
  165. (preObject && curObject && preObject.type !== curObject.type)
  166. ) {
  167. result = true
  168. }
  169. // 处理服务为当前对象,且动作为设置返回结果的情况下,选择其他服务时,需要clear
  170. let actionName
  171. if (block.op === BLOCK_OP_TYPE.CALL) {
  172. if (block.val && Array.isArray(block.val)) {
  173. actionName = block.val[1]
  174. }
  175. }
  176. if (
  177. !result &&
  178. !isChangedActionValid({
  179. rootNode: node,
  180. blockNode: curObject,
  181. blockObj: obj,
  182. actionName
  183. })
  184. ) {
  185. result = true
  186. }
  187. return result
  188. }
  189. dealChangeActionObject(block, obj) {
  190. if (
  191. block &&
  192. (block.op === BLOCK_OP_TYPE.SET ||
  193. block.op === BLOCK_OP_TYPE.CALL ||
  194. block.op === BLOCK_OP_TYPE.LET ||
  195. block.op === undefined)
  196. ) {
  197. if (this.shouldClearAction(block, obj)) {
  198. block.op = undefined
  199. block.val = ''
  200. block.args = []
  201. }
  202. }
  203. }
  204. onSelectObj(obj) {
  205. let nodeId = this.props.eventNodeId || this.curEventNodeId
  206. let curBlock = getEventBlockByBid(this.props.bid, nodeId)
  207. if (curBlock) {
  208. this.dealChangeActionObject(curBlock, obj)
  209. this.setState(
  210. {
  211. object: obj
  212. },
  213. () => {
  214. newEventActions.updateBlockProp({
  215. nodeId,
  216. blockId: this.props.bid,
  217. prop: 'object',
  218. value: obj,
  219. trigger: true
  220. })
  221. // 更新部分obj的参数
  222. let node = getActionBlockObjNode({ obj, nodeId })
  223. newEventStores.reloadAction(node && node.id)
  224. }
  225. )
  226. }
  227. }
  228. onActionObjectSelect(option) {
  229. if (option) {
  230. if (option.key === 'objSelector') {
  231. this.objSelector && this.objSelector.current.componentNode.click()
  232. } else {
  233. this.onSelectObj(option.key)
  234. }
  235. }
  236. }
  237. getSpecialObjName(obj) {
  238. let name = obj
  239. switch (obj) {
  240. case 'curObj':
  241. let nodeId = this.props.eventNodeId || this.curEventNodeId
  242. let node = getEventNodeById(nodeId)
  243. if (node) {
  244. if (nodeIsService(node.type)) {
  245. if (nodeIsTransaction(node.type)) {
  246. name = i18n.t('EventView.jenga_action_block.curTransaction')
  247. } else if (nodeIsIotMessage(node.type)) {
  248. name = i18n.t('EventView.jenga_action_block.curIot')
  249. } else {
  250. name = i18n.t('EventView.jenga_action_block.curService')
  251. }
  252. } else if (nodeIsFunctionGroup(node.type)) {
  253. name = i18n.t('EventView.jenga_action_block.curAction')
  254. } else {
  255. name = i18n.t('EventView.jenga_action_block.curObject')
  256. }
  257. }
  258. break
  259. default:
  260. name = i18n.t('EventView.jenga_action_block.' + obj)
  261. }
  262. return name
  263. }
  264. getActionObjName(obj) {
  265. if (obj === 'objSelector') {
  266. return i18n.t('EventView.jenga_action_block.objSelector')
  267. } else {
  268. // 特殊且合法的对象
  269. if (specialActionObj.indexOf(obj) >= 0) {
  270. return this.actionObjList.indexOf(obj) >= 0
  271. ? this.getSpecialObjName(obj)
  272. : ''
  273. } else if (fakeNodeIds.indexOf(obj) >= 0) {
  274. return getNodeTypeName(obj)
  275. } else {
  276. let _obj = getEventNodeById(obj)
  277. return _obj ? _obj.uis.name || _obj.type : ''
  278. }
  279. }
  280. }
  281. getActionObjIcon(obj) {
  282. let nodeId = this.props.eventNodeId || this.curEventNodeId
  283. let node = getActionBlockObjNode({ obj, nodeId })
  284. let icon = null
  285. let type = 'map'
  286. if (node) {
  287. if (node && node.type && widgetStore.widget[node.type]) {
  288. icon = getNodeIconByEnvs(
  289. node.type,
  290. widgetStore.widget[node.type].icon,
  291. node.envs
  292. )
  293. type = 'icon'
  294. }
  295. if (!icon) {
  296. icon = getTypeIcon(node, treeStores.curCaseType)
  297. type = 'map'
  298. }
  299. }
  300. return { icon, type }
  301. }
  302. getBlockObj(block) {
  303. let obj
  304. if (block) {
  305. if (block.isCurObj) {
  306. obj = 'curObj'
  307. } else {
  308. switch (block.op) {
  309. case BLOCK_OP_TYPE.SET:
  310. if (block.args && block.args[0] && block.args[0].val) {
  311. let _val = block.args[0].val
  312. if (Array.isArray(_val) && _val[0]) {
  313. obj = _val[0]
  314. }
  315. }
  316. break
  317. case BLOCK_OP_TYPE.CALL:
  318. if (block.val && Array.isArray(block.val)) {
  319. obj = block.val[0]
  320. }
  321. break
  322. case BLOCK_OP_TYPE.LET:
  323. if (block.args && block.args[0]) {
  324. let tempBlock = block.args[0]
  325. if (
  326. tempBlock.op === BLOCK_OP_TYPE.CALL &&
  327. tempBlock.val &&
  328. Array.isArray(tempBlock.val)
  329. ) {
  330. obj = tempBlock.val[0]
  331. }
  332. }
  333. break
  334. default:
  335. obj = block.val
  336. }
  337. }
  338. }
  339. return obj
  340. }
  341. getObject() {
  342. let _obj
  343. let nodeId = this.props.eventNodeId || this.curEventNodeId
  344. let curBlock = getEventBlockByBid(this.props.bid, nodeId)
  345. if (curBlock) {
  346. _obj = this.getBlockObj(curBlock)
  347. }
  348. return _obj
  349. }
  350. get actionObjList() {
  351. let curNode = getEventNodeById(this.state.curEventNodeId)
  352. if (nodeIsDyTransaction(curNode && curNode.type)) {
  353. // dy事务无相关选项
  354. return []
  355. }
  356. // 只有当前对象
  357. return specialActionObj.slice(0, 1)
  358. }
  359. get fakeNodes() {
  360. let fakeNodeIds = getFakeNodeIds() || []
  361. if (isServerRootNode(getEventNodeById(this.state.curEventNodeId))) {
  362. // 后台的伪对象
  363. fakeNodeIds = fakeNodeIds.filter(nodeId => {
  364. return nodeId === '$sobj_serverSys'
  365. })
  366. } else {
  367. // 前台的伪对象
  368. fakeNodeIds = fakeNodeIds.filter(nodeId => {
  369. return nodeId !== '$sobj_serverSys'
  370. })
  371. }
  372. return fakeNodeIds
  373. }
  374. jumpToNode(e) {
  375. e && e.stopPropagation()
  376. let nodeId = this.props.eventNodeId || this.curEventNodeId
  377. let node = getActionBlockObjNode({
  378. obj: this.state.object,
  379. nodeId
  380. })
  381. if (node && this.state.object !== 'curObj') {
  382. if (nodeIsFunctionGroup(node.type) || nodeIsService(node.type)) {
  383. newEventActions.toggleEventView({
  384. show: true,
  385. nodeId: node.id,
  386. mode: 'jenga'
  387. })
  388. } else {
  389. if (newEventStores.showEventView) {
  390. newEventActions.toggleEventView({ show: false })
  391. }
  392. }
  393. treeActions.selectNode(node.id)
  394. // if (nodeIsFunction(node.type)) {
  395. // newEventActions.addNavId(node)
  396. // }
  397. }
  398. }
  399. objJumpBtn() {
  400. let obj = this.state.object
  401. if (obj !== 'curObj' && fakeNodeIds.indexOf(obj) === -1) {
  402. let node = getActionBlockObjNode({
  403. obj
  404. })
  405. if (
  406. node &&
  407. (nodeIsFunctionGroup(node.type) ||
  408. nodeIsService(node.type) ||
  409. nodeIsFunction(node.type))
  410. ) {
  411. return (
  412. <button className="btn-clear btn-jump" onClick={this.jumpToNode} />
  413. )
  414. }
  415. }
  416. return null
  417. }
  418. render() {
  419. let actionObjIconInfo = this.getActionObjIcon(this.state.object)
  420. let actionObjMenu = () => {
  421. let fakeNodes = this.fakeNodes
  422. return (
  423. <Menu
  424. className="object-select-menu"
  425. onClick={this.onActionObjectSelect}
  426. >
  427. <MenuItem key={'objSelector'}>
  428. {this.getActionObjName('objSelector')}
  429. </MenuItem>
  430. <Menu.Divider />
  431. {this.actionObjList.map(obj => {
  432. return <MenuItem key={obj}>{this.getActionObjName(obj)}</MenuItem>
  433. })}
  434. {fakeNodes && fakeNodes.length > 0 ? <Menu.Divider /> : null}
  435. {!fakeNodes || fakeNodes.length === 0
  436. ? null
  437. : fakeNodes.map(node => {
  438. return (
  439. <MenuItem key={node} className={'fake-node'}>
  440. {this.getActionObjName(node)}
  441. </MenuItem>
  442. )
  443. })}
  444. </Menu>
  445. )
  446. }
  447. return (
  448. <div className="action-object f--h">
  449. <BlockEnable bid={this.props.bid} isEnable={this.props.isEnable} />
  450. <div className="object-wrap">
  451. <div className="select-wrap f--hlc">
  452. <Dropdown
  453. trigger={['click']}
  454. getPopupContainer={triggerNode => triggerNode.parentNode}
  455. overlayClassName={'object-select-dropdown'}
  456. overlay={actionObjMenu()}
  457. >
  458. <div className="object-select f--hlc">
  459. <ObjSelector
  460. ref={this.objSelector}
  461. stopPropagation={true}
  462. config={this.genObjSelectConfig()}
  463. cb={this.onSelectObj}
  464. />
  465. {actionObjIconInfo.type === 'icon' ? (
  466. <div
  467. className="icon-svg f--hcc"
  468. dangerouslySetInnerHTML={{
  469. __html: actionObjIconInfo.icon
  470. }}
  471. />
  472. ) : actionObjIconInfo.icon ? (
  473. <div className={cls('icon-type', actionObjIconInfo.icon)} />
  474. ) : null}
  475. <TitleTip nodeId={this.state.object} maxLength={4}>
  476. <input
  477. value={this.getActionObjName(this.state.object)}
  478. readOnly={true}
  479. className={cls('ant-dropdown-input', {
  480. 'fake-node': fakeNodeIds.indexOf(this.state.object) >= 0
  481. })}
  482. placeholder={i18n.t(
  483. 'EventView.jenga_action_block.selectObject'
  484. )}
  485. />
  486. </TitleTip>
  487. {this.objJumpBtn()}
  488. <div className="ant-dropdown-icon" />
  489. </div>
  490. </Dropdown>
  491. </div>
  492. <div className="add-action-block-wrap f--hcc">
  493. <button
  494. className="btn-clear btn-add-action-block"
  495. onClick={this.onAddAction}
  496. >
  497. <div className="icon">
  498. <span className="horizon" />
  499. <span className="vertical" />
  500. </div>
  501. </button>
  502. </div>
  503. </div>
  504. </div>
  505. )
  506. }
  507. }