import React from 'react' import i18n from 'i18next' import cls from 'classnames' import { Menu, Dropdown, Tooltip, Popover } from 'antd' import newEventActions from 'actions/newEvent' import newEventStores from 'stores/newEvent' import widgetStore from 'stores/widget' import { nodeIsChild, nodeIsService, nodeIsTimerService, nodeIsTransaction, nodeIsNormalService, nodeIsFunctionGroup, nodeIsApi, nodeIsDyTransaction, nodeIsSql, nodeIsSharedService } from 'stores/funcs/nodeType' import { getEventNodeById, getEventBlockByBid, getActionBlockObjNode, getBlockObj, getBlockAciton, getActionParamsArgs } from 'stores/funcs/newEvent' import { isAsyncDbMethod, isAsyncDbCustomsMethod, isAsyncMethod, genParams, genAsyncParams, getReloadMethods, isMethodAllowed, getModuleInstanceNameLocale, modulePropMethod, isParentWidgetProps, getActionMethods, getTargetMethod, isChangedActionValid } from 'stores/funcs/event/methodUtils' import { shallowEqualImmutable, cpJson } from 'utils/utils' import { isHySa } from 'utils/commons/ctrlHide' import { BLOCK_OP_TYPE } from 'const/const' import propType from 'const/propType' import externalPath from 'src/http/api/externalPath' import iconStrObj from 'src/assets/icons/iconsStr' import BlockActionMethodParams from './BlockActionMethodParams' import BlockActionReload from './BlockActionReload' import BlockActionDelay from './BlockActionDelay' const MenuItem = Menu.Item export default class BlockActionMethod extends React.Component { constructor(props) { super(props) this.obj = this.getObject() // 当前选中了的对象,动作受它影响 this.state = { methods: this.getMethods(), // 可选动作 actionName: this.getActionName(), isMini: this.getActionIsMini(), methodParams: this.getMethodParams(), paramsVisible: this.getParamsVisible(), delay: this.getDelay() } this.onEventChange = this.onEventChange.bind(this) // reload相关 // this.autoReloadSpecialAction = this.autoReloadSpecialAction.bind(this) this.onReloadAction = this.onReloadAction.bind(this) // 刷新 this.onChangeDelay = this.onChangeDelay.bind(this) this.genDefaultAction = this.genDefaultAction.bind(this) // 处理选择的method相关 this.decorateAction = this.decorateAction.bind(this) this.combineOldAction = this.combineOldAction.bind(this) this.onMethodSelect = this.onMethodSelect.bind(this) // action的选择 this.onToggleParamsVisible = this.onToggleParamsVisible.bind(this) this.getMethods = this.getMethods.bind(this) this.getObject = this.getObject.bind(this) this.getActionName = this.getActionName.bind(this) this.getActionIsMini = this.getActionIsMini.bind(this) this.getMethodParams = this.getMethodParams.bind(this) this.getParamsVisible = this.getParamsVisible.bind(this) this.getDelay = this.getDelay.bind(this) this.getDelayContent = this.getDelayContent.bind(this) this.getActionLocaleName = this.getActionLocaleName.bind(this) this.filterTargetMethod = this.filterTargetMethod.bind(this) this.getTipInfo = this.getTipInfo.bind(this) this.isAllowedMethod = this.isAllowedMethod.bind(this) this.forbiddenTips = this.forbiddenTips.bind(this) } shouldComponentUpdate(nextProps, nextState) { return ( !shallowEqualImmutable(this.props, nextProps) || !shallowEqualImmutable(this.state, nextState) ) } componentDidMount() { this.unsubscribe = newEventStores.listen(this.onEventChange) // this.autoReloadSpecialAction() } componentWillUnmount() { this.unsubscribe() } componentDidUpdate(preProps) { if (preProps.bid !== this.props.bid) { this.obj = this.getObject() this.setState( { methods: this.getMethods(), // 可选动作 actionName: this.getActionName(), isMini: this.getActionIsMini(), methodParams: this.getMethodParams(), paramsVisible: this.getParamsVisible(), delay: this.getDelay() }, () => { // this.autoReloadSpecialAction() } ) } } onEventChange(status) { let obj = {} let shouldUpdate = true if (status) { if ( (status.types.includes('updateBlockProp') && this.props.bid === status.data.affectBlockId && status.data.prop === 'object') || (status.types.includes('reloadBlock') && this.props.bid === status.data.affectBlockId) ) { // obj通知更新 this.obj = this.getObject() obj.methods = this.getMethods() // 可选动作 obj.actionName = this.getActionName() obj.isMini = this.getActionIsMini() obj.methodParams = this.getMethodParams() obj.paramsVisible = this.getParamsVisible() obj.delay = this.getDelay() this.setState(obj, () => { if (this.obj && !this.state.actionName) { // 创建相关方法 this.genDefaultAction() } }) shouldUpdate = false } if ( status.types.includes('changeActionBlockAction') && this.props.bid === status.data.affectBlockId && status.data.prop === 'paramsVisible' ) { obj.paramsVisible = this.getParamsVisible() } if (status.types.includes('updateActionMethod')) { // 更新方法(主要是参数变化) let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let objNode = getActionBlockObjNode({ obj: this.obj, nodeId }) if ( objNode && objNode.id === status.data.nodeId && (!status.data.targetBlockId || status.data.targetBlockId === this.props.bid) && status.data.methods.includes(this.state.actionName) ) { let keepVisible = true if ( ['clone', 'sendSMS', 'sendSMS_stage'].indexOf( this.state.actionName ) >= 0 ) { keepVisible = false } this.onReloadAction(keepVisible, false) } } } if (Object.keys(obj).length > 0 && shouldUpdate) { this.setState(obj) } } // hasDiffParams(objNode) { // let result = false // let method = // widgetStore.widget[objNode.type].map.methodsMap[this.state.actionName] // let params = genParams(method, objNode, this.props.bid, true) // let block = getEventBlockByBid(this.props.bid) // let preParams = block && block.action && block.action.params // if ((!params && preParams) || (params && !preParams)) { // // 有一个为空 // result = true // } else if (params && preParams && params.length !== preParams.length) { // // 都有参数且长度不一致 // result = true // } else if (params && preParams && params.length === preParams.length) { // // 都有参数且长度一致 // let hasDif = false // params.forEach((param, index) => { // if ( // param.name !== preParams[index].name || // param.type !== preParams[index].type || // ((param.pType || preParams[index].pType) && // param.pType !== preParams[index].pType) // ) { // hasDif = true // } // }) // result = hasDif // } else { // result = false // } // return result // } // autoReloadSpecialAction() { // let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId // let objNode = getActionBlockObjNode({ // obj: this.obj, // nodeId // }) // if (objNode) { // let methods = getReloadMethods(objNode) // if (methods && this.hasDiffParams(objNode)) { // newEventActions.updateActionMethod({ // nodeId: objNode.id, // targetBlockId: this.props.bid, // methods: methods // }) // } // } // } filterTargetMethod(method) { let result = method if (result) { let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let objNode = getActionBlockObjNode({ obj: this.obj, nodeId }) let node = getEventNodeById(nodeId) if ( !isChangedActionValid({ rootNode: node, blockNode: objNode, blockObj: this.obj, actionName: result.name }) ) { result = undefined } } return result } onReloadAction(keepVisible, addRecord) { let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let objNode = getActionBlockObjNode({ obj: this.obj, nodeId }) let method = this.filterTargetMethod( getTargetMethod(objNode, this.state.actionName) ) if (method) { this.onMethodSelect( { item: { props: { method: method } } }, keepVisible, undefined, false ) } else { this.setState( { actionName: null, isMini: false, // hasParams: false, methodParams: [], paramsVisible: 'all' }, () => { newEventActions.updateBlockProp({ nodeId, blockId: this.props.bid, prop: 'action', value: null, trigger: true, addRecord: addRecord === undefined ? true : addRecord }) } ) } } onChangeDelay() { let delay = this.getDelay() this.setState({ delay: delay }) } genDefaultAction() { let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let objNode = getActionBlockObjNode({ obj: this.obj, nodeId }) if (objNode) { let method if (nodeIsService(objNode.type)) { let methods = this.getMethods() if (methods && methods.length > 0) { if (nodeIsTimerService(objNode.type)) { if (this.obj === 'curObj') { method = methods.find(meth => { return meth.name === 'recordResult' }) } } else if (nodeIsTransaction(objNode.type)) { if (this.obj !== 'curObj') { method = methods.find(meth => { return meth.name === 'runTransaction' }) } else { method = methods.find(meth => { return meth.name === 'paramResult' }) } } else if (nodeIsDyTransaction(objNode.type)) { method = methods.find(meth => { return meth.name === 'runDyTransaction' }) } else if (nodeIsNormalService(objNode.type)) { if (this.obj !== 'curObj') { method = methods.find(meth => { return meth.name === 'fireService' || meth.name === 'runService' }) } else { method = methods.find(meth => { return meth.name === 'paramResult' }) } } } } else if (nodeIsFunctionGroup(objNode.type)) { let methods = this.getMethods() if (methods && methods.length > 0) { // 触发动作组 if (this.obj !== 'curObj') { method = methods.find(meth => { return meth.name === 'fireFuncGroup' }) } else { method = methods.find(meth => { return meth.name === 'funcResult' }) } } } else if (objNode.type === 'data-event') { let methods = this.getMethods() if (methods && methods.length > 0) { method = methods.find(meth => { return meth.name === 'fireEvent' }) // // 设置返回结果 // if (method) { // this.onMethodSelect(undefined, false, method) // } } } else if (nodeIsApi(objNode.type)) { let methods = this.getMethods() let targetMethodName = objNode.type === 'server-api' ? 'sendServerApiRequest' : 'sendApiRequest' if (methods && methods.length > 0) { method = methods.find(meth => { return meth.name === targetMethodName }) } } else if (nodeIsSql(objNode.type)) { let methods = this.getMethods() if (methods && methods.length > 0) { method = methods.find(meth => { return meth.name === 'run' }) } } else if (nodeIsSharedService(objNode.type)) { let methods = this.getMethods() if (methods && methods.length > 0) { method = methods.find(meth => { return meth.name === 'fireService' || meth.name === 'runService' }) } } if (method) { this.onMethodSelect(undefined, false, method) } } } decorateAction(nAction, method, keepVisible, asyncCb) { let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let objNode = getActionBlockObjNode({ obj: this.obj, nodeId }) if (method.mini) { nAction.mini = method.mini } if (method.miniType) { nAction.miniType = method.miniType } if (method.miniEmit) { nAction.miniEmit = method.miniEmit } if (method.meth) { nAction.meth = method.meth } if (method.paramsAsObj) { nAction.paramsAsObj = method.paramsAsObj } if (method.callback) { nAction.callback = true // 表明有callback } let isAsync = isAsyncDbMethod(method.name) || isAsyncMethod(method.name) || isAsyncDbCustomsMethod(method.name) if (isAsync) { genAsyncParams(method, objNode, this.props.bid, params => { if (params) { nAction.params = params } this.combineOldAction(nAction, keepVisible) asyncCb && asyncCb() }) } else { let params = genParams(method, objNode, this.props.bid, true) if (params && params.length > 0) { nAction.params = params } this.combineOldAction(nAction, keepVisible) } } combineOldAction(newAction, keepVisible) { let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let block = getEventBlockByBid(this.props.bid, nodeId) let oldActionName = getBlockAciton(block) if (block && oldActionName && oldActionName === newAction.name) { if (keepVisible) { newAction.paramsVisible = block.paramsVisible } let oldParams = getActionParamsArgs(block) if (oldParams && newAction.params) { newAction.params.forEach(newParam => { if (oldActionName === 'setProps') { let targetParam = oldParams.find(oldParam => { return oldParam.val === newParam.name }) if (targetParam) { if (targetParam.args && targetParam.args[0]) { newParam.value = targetParam.args[0].op === 'var' ? targetParam.args[0].expVal : targetParam.args[0].val } } } else { let targetParam = oldParams.find(oldParam => { return oldParam.key === newParam.name }) if (targetParam) { newParam.value = targetParam.op === 'var' ? targetParam.expVal : targetParam.val } } }) } } } onTriggerAction(nAction, addRecord) { let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId newEventActions.updateBlockProp({ nodeId, blockId: this.props.bid, prop: 'action', value: nAction, trigger: true, addRecord: addRecord === undefined ? true : addRecord }) // 选择后触发相关的界面改变 this.setState({ actionName: nAction.name, isMini: nAction.mini, methodParams: cpJson(nAction.params) || [], paramsVisible: nAction.paramsVisible }) } onMethodSelect(option, keepVisible, targetMethod, addRecord) { if (option && option.key === 'emptyContent') { return } let method if (targetMethod) { method = targetMethod } else if ( option && option.item && option.item.props && option.item.props.method ) { method = option.item.props.method } if (method) { // 选择了对象之后的操作 let nAction = { name: method.name, paramsVisible: 'all' } this.decorateAction( nAction, method, keepVisible, this.onTriggerAction.bind(this, nAction, addRecord) ) if ( !isAsyncDbMethod(method.name) && !isAsyncMethod(method.name) && !isAsyncDbCustomsMethod(method.name) ) { this.onTriggerAction(nAction, addRecord) } } } onToggleParamsVisible() { newEventActions.toggleActionParamsVisible({ blockId: this.props.bid }) } getMethods() { return getActionMethods({ obj: this.obj, curNodeId: this.props.eventNodeId || newEventStores.curEventNodeId, isNewEvent: true }) } getObject() { let _obj let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let curBlock = getEventBlockByBid(this.props.bid, nodeId) if (curBlock) { _obj = getBlockObj({ block: curBlock }) } return _obj } getActionName() { let result = null let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let block = getEventBlockByBid(this.props.bid, nodeId) if (block) { result = getBlockAciton(block) } return result } getActionIsMini() { let result = false let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let block = getEventBlockByBid(this.props.bid, nodeId) if (block) { switch (block.op) { case BLOCK_OP_TYPE.CALL: result = block.mini || false break case BLOCK_OP_TYPE.LET: result = block.args[0].mini || false break } } return result } getMethodParams() { let result = [] let actionName = this.getActionName() if (actionName) { let methods = this.getMethods() if (methods) { let targetMethod = methods.find(method => { return method.name === actionName }) if (targetMethod) { let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let objNode = getActionBlockObjNode({ obj: this.obj, nodeId }) result = genParams(targetMethod, objNode, this.props.bid, true) || [] } } } return result } getParamsVisible() { let result = undefined let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let block = getEventBlockByBid(this.props.bid, nodeId) if (block && block.paramsVisible) { result = block.paramsVisible } return result || 'all' } getDelay() { let result = 0 let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let block = getEventBlockByBid(this.props.bid, nodeId) if (block && block.delay) { result = block.delay || 0 } return result } getDelayContent() { if (this.state.delay && this.state.delay > 0) { return ( i18n.t('EventView.jenga_action_block.delayPrefix') + this.state.delay + i18n.t('EventView.jenga_action_block.delayPostfix') ) } return '' } getActionLocaleName() { let name = this.state.actionName ? this.state.actionName || '' : '' let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let objNode = getActionBlockObjNode({ obj: this.obj, nodeId }) if (objNode) { if ( isParentWidgetProps(objNode) && this.state.actionName === 'miniPropValueChange' ) { let method = modulePropMethod() name = method.locale ? method.locale[i18n.language] : name } else if (this.state.isMini) { name = getModuleInstanceNameLocale({ nodeId: objNode.id, type: 'methods', name: this.state.actionName }) } else { let nodeInfo = objNode ? widgetStore.widget[objNode.type] : undefined if (objNode && nodeInfo && nodeInfo.map && nodeInfo.map.methodsMap) { name = nodeInfo.map.methodsMap[name] && nodeInfo.map.methodsMap[name].locale ? nodeInfo.map.methodsMap[name].locale[i18n.language] : name } } } return name } getTipInfo(item) { let nodeId = this.props.eventNodeId || newEventStores.curEventNodeId let objNode = getActionBlockObjNode({ obj: this.obj, nodeId }) let type = objNode && objNode.type if (type && item) { let stopPro = e => { e.stopPropagation() } let info = widgetStore.widget[type].map.methodsMap[item.name] let content = info && info.desc && info.desc[i18n.language] let link = i18n.language === 'en' ? info && info.linkEN : info && info.linkZH content = content ? (