BlockActionObject.jsx 14 KB

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