我正在try 将DocuSign信封发送控制台嵌入到我的Reaction应用程序中.有没有什么API可以集成这一点.在过go 的两天里,我无法找到解决方案.如果有人实现了这一点,请指导我. 提前谢谢你

我试过下面的博客

https://developers.docusign.com/docs/esign-rest-api/how-to/embed-ui/

推荐答案

我假设您没有服务器组件,并且希望从客户端(从浏览器)从您的Reaction应用程序进行API调用.

您需要为您的应用程序配置CORS.这是从浏览器进行API调用所必需的.

你可以see a working example on CodePen

以下是codePen代码:

// Copyright © 2022 DocuSign, Inc.
// License: MIT Open Source https://opensource.org/licenses/MIT

import {
    CallApi,
    ImplicitGrant,
    UserInfo
    // View the source at https://codepen.io/docusign/pen/LYBKqxb
} from "https://codepen.io/docusign/pen/LYBKqxb.js";
import {
    msg,
    htmlMsg,
    adjustRows,
    errMsg,
    workingUpdate,
    usingHttps
    // View the source at https://codepen.io/docusign/pen/QWBXYzX
} from "https://codepen.io/docusign/pen/QWBXYzX.js";

$(function () {
    // Set basic variables
    const dsReturnUrl = "https://docusign.github.io/jsfiddleDsResponse.html";
    const logLevel = 0; // 0 is terse; 9 is verbose
    let signingCeremonyWindow = null;

    // Example settings
    const docUrl = "https://docusign.github.io/examples/docs/anchorfields.pdf";
    const docViewUrl =
        "https://docusign.github.io/examples/docs/anchorfields_view.pdf";

    debugger; // uncomment with debugger open to find the right JS file.

    /*
     * The doit function is the example that is triggered by the
     * button. The user is already logged in (we have an access token).
     */
    let doit = async function doitf(event) {
        $("#doit").addClass("hide");
        if (!checkToken()) {
            // Check that we have a valid token
            return;
        }
        workingUpdate(true);
        const signer = {
            name: data.userInfo.name,
            email: data.userInfo.email,
            clientUserId: 1000
        };
        const envelopeId = await createEnvelope(signer);
        if (envelopeId) {
            msg(`Envelope ${envelopeId} created.`);
            await embeddedSigningCeremony({
                envelopeId: envelopeId,
                signer: signer
            });
        }
        $("#doit").removeClass("hide");
        workingUpdate(false);
    };
    doit = doit.bind(this);

    /*
     *  Create the envelope by completely specifying the envelope.
     *  Often the recommended alternative is to first create a template
     *  on the DocuSign platform, then reference the template when
     *  creating the envelope. See the other examples...
     */
    async function createEnvelope({ name, email, clientUserId }) {
        const docB64 = await data.callApi.getDocB64(docUrl); // fetch a document

        const req = {
            emailSubject: "Please sign the attached document",
            status: "sent",
            customFields: {
                listCustomFields: [
                    {
                        name: "Envelope list custom field 1",
                        show: "true",
                        value: "value 1"
                    },
                    {
                        name: "Envelope list custom field 2",
                        show: "true",
                        value: "value 2"
                    }
                ],
                textCustomFields: [
                    {
                        name: "Envelope text custom field 1",
                        show: "true",
                        value: "value 1"
                    },
                    {
                        name: "Envelope text custom field 2",
                        show: "true",
                        value: "value 2"
                    }
                ]
            },
            documents: [
                {
                    name: "Example document",
                    documentBase64: docB64,
                    fileExtension: "pdf",
                    documentId: "1",
                    documentFields: [
                        {
                            name: "doc field 1",
                            value: "val 1"
                        },
                        {
                            name: "doc field 2",
                            value: "val 2"
                        }
                    ]
                }
            ],
            recipients: {
                signers: [
                    {
                        email: email,
                        name: name,
                        clientUserId: clientUserId,
                        customFields: ["field1: value 1", "field2: value 2"],
                        recipientId: "1",
                        tabs: {
                            signHereTabs: [
                                {
                                    anchorString: "/sig1/",
                                    anchorXOffset: "20",
                                    anchorUnits: "pixels"
                                }
                            ],
                            checkboxTabs: [
                                {
                                    anchorString: "/sig1/",
                                    anchorXOffset: "180",
                                    anchorUnits: "pixels",
                                    tabLabel: "checkbox 1",
                                    tabGroupLabels: ["checkbox group"]
                                },
                                {
                                    anchorString: "/sig1/",
                                    anchorXOffset: "180",
                                    anchorYOffset: "20",
                                    anchorUnits: "pixels",
                                    tabLabel: "checkbox 2",
                                    tabGroupLabels: ["checkbox group"]
                                }
                            ],
                            tabGroups: [
                                {
                                    groupLabel: "checkbox group",
                                    groupRule: "SelectExactly",
                                    minimumRequired: "1",
                                    maximumAllowed: "1",
                                    validationMessage:
                                        "Please check one option",
                                    tabScope: "document",
                                    pageNumber: "1",
                                    documentId: "1"
                                }
                            ],
                            textTabs: [
                                {
                                    anchorString: "/sig1/",
                                    anchorXOffset: "195",
                                    anchorUnits: "pixels",
                                    value: "I agree with license 1",
                                    locked: "true",
                                    font: "Helvetica",
                                    fontSize: "Size12",
                                    bold: "true"
                                },
                                {
                                    anchorString: "/sig1/",
                                    anchorXOffset: "195",
                                    anchorYOffset: "20",
                                    anchorUnits: "pixels",
                                    value: "I agree with license 2",
                                    locked: "true",
                                    font: "Helvetica",
                                    fontSize: "Size12",
                                    bold: "true"
                                },
                                {
                                    anchorString: "/sig1/",
                                    anchorXOffset: "20",
                                    anchorYOffset: "50",
                                    anchorUnits: "pixels",
                                    bold: "true",
                                    font: "Helvetica",
                                    fontSize: "Size14",
                                    fontColor: "NavyBlue",
                                    value:
                                        "Addendum\n‣ Item 1\n‣ Item 2\nThis is a multi-line read-only text field"
                                }
                            ]
                        }
                    }
                ]
            }
        };

        // Make the create envelope API call
        msg(`Creating envelope.`);
        const apiMethod = `/accounts/${data.userInfo.defaultAccount}/envelopes`;
        const httpMethod = "POST";
        const results = await data.callApi.callApiJson({
            apiMethod: apiMethod,
            httpMethod: httpMethod,
            req: req
        });
        if (results === false) {
            errMsg(data.callApi.errMsg);
            return false;
        }
        if (logLevel > 0) {
            htmlMsg(
                `<p>Envelope created. Response:</p><p><pre><code>${JSON.stringify(
                    results,
                    null,
                    4
                )}</code></pre></p>`
            );
        }
        return results.envelopeId;
    }

    /*
     * Create an embedded signing ceremony, open a new tab with it
     */
    async function embeddedSigningCeremony({ envelopeId, signer }) {
        const req = {
            returnUrl: dsReturnUrl,
            authenticationMethod: "None",
            clientUserId: signer.clientUserId,
            email: signer.email,
            userName: signer.name
        };

        // Make the API call
        const apiMethod = `/accounts/${data.userInfo.defaultAccount}/envelopes/${envelopeId}/views/recipient`;
        const httpMethod = "POST";
        const results = await data.callApi.callApiJson({
            apiMethod: apiMethod,
            httpMethod: httpMethod,
            req: req
        });
        if (results === false) {
            errMsg(data.callApi.errMsg);
            return false;
        }
        if (logLevel > 5) {
            htmlMsg(
                `<p>Embedded Signing Ceremony created. Response:</p><p><pre><code>${JSON.stringify(
                    results,
                    null,
                    4
                )}</code></pre></p>`
            );
        }
        msg(`Displaying signing ceremony...`);
        signingCeremonyWindow = window.open(results.url, "_blank");
        if(!signingCeremonyWindow || signingCeremonyWindow.closed || 
           typeof signingCeremonyWindow.closed=='undefined') {
            // popup blocked
            alert ("Please enable the popup window signing ceremony");
        }
        signingCeremonyWindow.focus();
        return true;
    }

    /*
     * signingCeremonyEnded
     * After the signing ceremony ends (in its own tab),
     * the browser tab is redirected to the returnUrl, defined
     * in constant dsReturnUrl.
     * Source:
     * https://github.com/docusign/docusign.github.io/blob/master/jsfiddleDsResponse.html
     *
     * That page runs Javascript to send a message via window.postMessage.
     * The message is tagged with source `dsResponse`.
     * The function messageListener (in mainline section) receives and
     * dispatches the different types of incoming messages.
     * When a dsResponse message is received, this function is called.
     */
    function signingCeremonyEnded(data) {
        if (data.source !== "dsResponse") {
            return; // Sanity check
        }
        signingCeremonyWindow.close(); // close the browser tab
        const href = data.href; // "http://localhost:3000/?event=signing_complete"
        const sections = href.split("?");
        const hasEvents = sections.length === 2;
        const qps = hasEvents ? sections[1].split("&") : [];
        if (!hasEvents) {
            errMsg(`Unexpected signing ceremony response: ${data.href}.`);
            return;
        }
        let msg = `<p><b>Signing Ceremony Response</b><br/>`;
        msg += `<small>Information Security tip: do not make business decisions based on this data since they can be spoofed. Instead, use the API.</small>`;

        qps.forEach((i) => {
            const parts = i.split("=");
            msg += `<br/>Query parameter <b>${parts[0]} = "${parts[1]}"</b>`;
        });
        msg += "</p>";
        htmlMsg(msg);
    }
    
    /////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////

    /* Checks that the access token is still good.
     * Prompts for login if not
     */
    function checkToken() {
        if (data.implicitGrant.checkToken()) {
            // ok
            return true;
        } else {
            // not ok
            $("#login").removeClass("hide");
            $("#doit").addClass("hide");
            // reset everything
            msg("Please login");
        }
    }
    
    /*
     * Receives and dispatches incoming messages
     */
    let messageListener = async function messageListenerf(event) {
        if (!event.data) {
            return;
        }
        const source = event.data.source;
        if (source === "dsResponse") {
            signingCeremonyEnded(event.data);
            return;
        }
        if (source === "oauthResponse" && data.implicitGrant) {
            await implicitGrantMsg(event.data);
            return;
        }
    };
    messageListener = messageListener.bind(this);

    /*
     * Process incoming implicit grant response
     */
    async function implicitGrantMsg(eventData) {
        const oAuthResponse = data.implicitGrant.handleMessage(eventData);
        if (oAuthResponse === "ok") {
            if (await completeLogin()) {
                data.loggedIn();
            }
        } else if (oAuthResponse === "error") {
            $("#login").removeClass("hide");
            const errHtml = `<p class="text-danger">${data.implicitGrant.errMsg}</p>`;
            htmlMsg(errHtml);
        }
    }

    /*
     * Complete login process including
     * Get user information
     * Set up CallApi object
     * update the user
     */
    async function completeLogin() {
        data.userInfo = new UserInfo({
            accessToken: data.implicitGrant.accessToken,
            workingUpdateF: workingUpdate
        });
        const ok = await data.userInfo.getUserInfo();
        if (ok) {
            data.callApi = new CallApi({
                accessToken: data.implicitGrant.accessToken,
                apiBaseUrl: data.userInfo.defaultBaseUrl
            });
            if (logLevel === 0) {
                htmlMsg(
                    `<p><b>${data.userInfo.name}</b><br/>` +
                        `${data.userInfo.email}<br/>` +
                        `${data.userInfo.defaultAccountName}</p>`
                );
            } else {
                htmlMsg(
                    `<p><b>OAuth & UserInfo Results</b><br/>` +
                        `Name: ${data.userInfo.name}` +
                        ` (${data.userInfo.userId})<br/>` +
                        `Email: ${data.userInfo.email}<br/>` +
                        `Default account: ${data.userInfo.defaultAccountName}` +
                        ` (${data.userInfo.defaultAccount})<br/>` +
                        `Base URL: ${data.userInfo.defaultBaseUrl}</p>`
                );
            }
        } else {
            // Did not complete the login
            $("#login").removeClass("hide");
            const errHtml = `<p class="text-danger">${data.userInfo.errMsg}</p>`;
            htmlMsg(errHtml);
        }
        return ok;
    }

    /*
     * Login button was clicked
     */
    let login = async function loginf(event) {
        $("#login").addClass("hide");
        await data.implicitGrant.login();
    };
    login = login.bind(this);

    // Mainline
    let data = {
        implicitGrant: null,
        userInfo: null,
        callApi: null,
        loggedIn: () => $("#doit").removeClass("hide")
    };

    // The mainline
    if (usingHttps()) {
        adjustRows();
        data.implicitGrant = new ImplicitGrant({
            workingUpdateF: workingUpdate
        });

        window.addEventListener("message", messageListener);
        $("#btnOauth").click(login);
        $("#btnDoit").click(doit);
    }
});



  [1]: https://developers.docusign.com/platform/single-page-applications-cors/
  [2]: https://developers.docusign.com/docs/esign-rest-api/how-to/request-signature-in-cors-app-embedded/

Reactjs相关问答推荐

有没有方法覆盖NextJS 14中的布局?

可选链和useState挂钩

有没有一种惯用的方式来接受特定的子元素?

如何在整个应用程序中显示通用弹出窗口中的点击事件

如何解决Reaction中遗留的上下文API错误?

折叠并重新打开react 手风琴将重置内部状态

如何使用TouchStart/TouchEnd在Table ReactJS中交换位置?

如何在React组件中自动更新图表数据?

如何在不同的路由中渲染相同的页面组件(包括 getServerSideProps)

useEffect 渲染没有依赖数组的组件

如何使用样式化函数为 TextField 的输入组件设置样式

改变输入的默认值时出现问题:number react-hook-form

如何在 nextjs 中单击按钮时动态导入和渲染组件?

无法读取未定义的react native 的属性参数

添加 React/Redux 组件模板的 VS Code 扩展

如何从一组对象映射 MUI 5 图标并更改其 colored颜色 ?

如何使用 babel 将 SVG 转换为 React 组件?

如何在 React JS 上使文本中的单词可点击

链接的音译 Gatsby JS

如何在按钮左下角制作 Material UI 菜单下拉菜单