diff --git a/docs/zh-CN/concepts/event-action.md b/docs/zh-CN/concepts/event-action.md index 7e375e9f1..c43402a53 100644 --- a/docs/zh-CN/concepts/event-action.md +++ b/docs/zh-CN/concepts/event-action.md @@ -281,7 +281,22 @@ run action ajax ] } } - }, + } + ] +} +``` + +#### 静默模式 + +当配置`options.silent: true`时,请求完成后不会弹出提示信息。 + +```schema +{ + type: 'page', + data: { + name: 'lll' + }, + body: [ { type: 'button', id: 'b_001', @@ -324,6 +339,106 @@ run action ajax } ``` +#### 可读取的数据 + +请求配置中可读取的数据包含事件源所在数据域和动作执行产生的数据。可以通过`api.data`配置数据映射来读取所需数据。例如: + +- 取所在数据域的数据:通过`"name": "${name}", "email": "${email}"`来映射表单校验数据(只适用于事件源在表单内的情况) +- 取动作产生的数据:通过`"name": "${event.data.validateResult.payload.name}", "email": "${event.data.validateResult.payload.email}"`来映射表单校验数据,这种是获取前面表单校验动作的校验结果数据。通过`"&": "${event.data.validateResult.payload}"`展开表单校验数据,结果相同,这是一个数据映射小技巧 + +```schema +{ + "type": "page", + "body": [ + { + "type": "button", + "label": "表单外的校验按钮", + "className": "mb-2", + level: 'primary', + "onEvent": { + "click": { + "actions": [ + { + "componentId": "form_validate", + "outputVar": "validateResult", + "actionType": "validate" + }, + { + "outputVar": "responseResult", + "actionType": "ajax", + "api": { + "method": "post", + "url": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/saveForm", + "data": { + "name": "${name}", + "email": "${email}" + } + } + } + ] + } + }, + "id": "u:bd7adb583ec8" + }, + { + "type": "form", + "id": "form_validate", + "body": [ + { + "type": "input-text", + "name": "name", + "label": "姓名:", + "required": true, + "id": "u:fbbc02500df6" + }, + { + "name": "email", + "type": "input-text", + "label": "邮箱:", + "required": true, + "validations": { + "isEmail": true + }, + "id": "u:830d0bad3e6a" + } + ], + "actions": [ + { + "type": "button", + "label": "表单内的校验按钮", + level: 'primary', + "onEvent": { + "click": { + "actions": [ + { + "componentId": "form_validate", + "outputVar": "validateResult", + "actionType": "validate" + }, + { + "outputVar": "responseResult", + "actionType": "ajax", + "api": { + "method": "post", + "url": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/saveForm", + "data": { + "name": "${name}", + "email": "${email}" + } + } + } + ] + } + }, + "id": "u:bd7adb583ec8" + } + ] + } + ], + "id": "u:d79af3431de1" +} +``` + **动作属性** | 属性名 | 类型 | 默认值 | 说明 | diff --git a/packages/amis-core/src/actions/AjaxAction.ts b/packages/amis-core/src/actions/AjaxAction.ts index 5d7e73353..050f0a8ea 100644 --- a/packages/amis-core/src/actions/AjaxAction.ts +++ b/packages/amis-core/src/actions/AjaxAction.ts @@ -1,5 +1,5 @@ import {Api, ApiObject} from '../types'; -import {normalizeApiResponseData} from '../utils/api'; +import {normalizeApi, normalizeApiResponseData} from '../utils/api'; import {ServerError} from '../utils/errors'; import {createObject, isEmpty} from '../utils/helper'; import {RendererEvent} from '../utils/renderer-event'; @@ -42,6 +42,11 @@ export class AjaxAction implements RendererAction { if (!renderer.props.env?.fetcher) { throw new Error('env.fetcher is required!'); } + + if (!action.api) { + throw new Error('api is required!'); + } + if (this.fetcherType === 'download' && action.actionType === 'download') { if ((action as any).api) { (action as any).api.responseType = 'blob'; @@ -51,9 +56,19 @@ export class AjaxAction implements RendererAction { const env = event.context.env; const silent = action?.options?.silent; const messages = (action?.api as ApiObject)?.messages; + let api = normalizeApi(action.api); + + // 如果没配置data数据映射,则给一个空对象,避免将当前数据域作为接口请求参数 + if ((api as any)?.data == undefined) { + api = { + ...api, + data: {} + }; + } + try { const result = await env.fetcher( - action?.api, + api, action.data ?? {}, action?.options ?? {} ); diff --git a/packages/amis/__tests__/event-action/ajax.test.tsx b/packages/amis/__tests__/event-action/ajax.test.tsx index a759851ae..77907ea8f 100644 --- a/packages/amis/__tests__/event-action/ajax.test.tsx +++ b/packages/amis/__tests__/event-action/ajax.test.tsx @@ -422,3 +422,190 @@ test('EventAction:ajax data2', async () => { }); }); }); + +test('EventAction:ajax data3', async () => { + const fetcher = jest.fn().mockImplementation(() => + Promise.resolve({ + data: { + status: 0, + msg: 'ok', + data: { + name: 'amis', + age: 18 + } + } + }) + ); + const {getByText, container}: any = render( + amisRender( + { + type: 'page', + body: [ + { + type: 'button', + label: '表单外的校验按钮', + className: 'mb-2', + level: 'primary', + onEvent: { + click: { + actions: [ + { + componentId: 'form_validate', + outputVar: 'validateResult', + actionType: 'validate' + }, + { + outputVar: 'responseResult', + actionType: 'ajax', + api: { + method: 'post', + url: '/api/xxx1', + data: { + name: '${name}', + email: '${email}' + } + } + } + ] + } + } + }, + { + type: 'form', + id: 'form_validate', + data: { + name: 'amis', + email: 'amis@baidu.com' + }, + body: [ + { + type: 'input-text', + name: 'name', + label: '姓名:', + required: true + }, + { + name: 'email', + type: 'input-text', + label: '邮箱:', + required: true, + validations: { + isEmail: true + } + } + ], + actions: [ + { + type: 'button', + label: '表单内的校验按钮', + level: 'primary', + onEvent: { + click: { + actions: [ + { + componentId: 'form_validate', + outputVar: 'validateResult', + actionType: 'validate' + }, + { + outputVar: 'responseResult', + actionType: 'ajax', + api: { + method: 'post', + url: '/api/xxx2', + data: { + name: '${name}', + email: '${email}' + } + } + } + ] + } + } + }, + { + type: 'button', + label: '无data', + level: 'primary', + onEvent: { + click: { + actions: [ + { + componentId: 'form_validate', + outputVar: 'validateResult', + actionType: 'validate' + }, + { + outputVar: 'responseResult', + actionType: 'ajax', + api: { + method: 'post', + url: '/api/xxx3' + } + } + ] + } + } + }, + { + type: 'button', + label: '字符串api无参数', + level: 'primary', + onEvent: { + click: { + actions: [ + { + componentId: 'form_validate', + outputVar: 'validateResult', + actionType: 'validate' + }, + { + outputVar: 'responseResult', + actionType: 'ajax', + api: 'post:/api/xxx4' + } + ] + } + } + } + ] + } + ] + }, + {}, + makeEnv({ + fetcher + }) + ) + ); + + await waitFor(() => { + expect(getByText('表单外的校验按钮')).toBeInTheDocument(); + expect(getByText('表单内的校验按钮')).toBeInTheDocument(); + expect(getByText('无data')).toBeInTheDocument(); + expect(getByText('字符串api无参数')).toBeInTheDocument(); + }); + + fireEvent.click(getByText(/表单外的校验按钮/)); + fireEvent.click(getByText(/表单内的校验按钮/)); + fireEvent.click(getByText(/无data/)); + fireEvent.click(getByText(/字符串api无参数/)); + + await waitFor(() => { + expect(fetcher).toHaveBeenCalledTimes(4); + expect(fetcher.mock.calls[0][0].url).toEqual('/api/xxx1'); + expect(fetcher.mock.calls[0][0].data).toMatchObject({ + name: '', + email: '' + }); + expect(fetcher.mock.calls[1][0].url).toEqual('/api/xxx2'); + expect(fetcher.mock.calls[1][0].data).toMatchObject({ + name: 'amis', + email: 'amis@baidu.com' + }); + expect(fetcher.mock.calls[2][0].url).toEqual('/api/xxx3'); + expect(fetcher.mock.calls[2][0].data).toMatchObject({}); + expect(fetcher.mock.calls[3][0].url).toEqual('/api/xxx4'); + expect(fetcher.mock.calls[3][0].data).toMatchObject({}); + }); +});