機械翻訳について

アプリケーションへのコール・パネル・コンポーネントの追加

前のトピックでは、基本的なJETアプリケーションを構築する方法と、それをFusionメディア・ツールバーにデプロイする方法を示します。

次に、着信コール通知と、メディア・ツールバー・アプリケーションでコールを受け入れるか切断するボタンを表示する必要があります。 これを行うには、要件に基づいてUI要素をレンダリングするロジックを構築します。 このシリーズのステップの一部として、コール通知の表示に必要なUI要素、およびコールの受入れと切断のボタンは、カスタムJETコンポーネントとしてカプセル化されます。

コール・パネル・コンポーネントの状態

コール・パネル・コンポーネントには、次の3つの状態があります:
  • 着信: エージェントが着信コールを受信すると、コール・パネル・コンポーネントは着信状態になります。 また、コール・パネル・コンポーネントは、エージェントが顧客によってまだピック・アップされていない発信コールを開始するときに着信状態になります。 アプリケーション。 この状態では、コール・パネル・コンポーネントには、着信コールに関する情報(Fusionアプリケーションから取得される担当者名)、IVRデータ、コールの受入れまたは拒否用の2つのボタンなどが含まれます。
  • 受入済: エージェントが顧客からの着信コールを受け入れると、コール・パネル・コンポーネントは受諾済み状態になります。 顧客がエージェントによって開始された発信コールを受け入れると、コール・パネル・コンポーネントも受諾済み状態になります。 この状態の間、コール・パネル・コンポーネントには、着信コール情報に加えて、コール・ハング・アップ・ボタンとコール・イン・プログレスのアニメーションが表示されます。
  • 未接続: エージェントが着信コールを拒否したり、進行中のコールを切断すると、コール・パネル・コンポーネントは切断状態になります。

アプリケーションでのカスタム・コンポーネントの作成

  1. ターミナルでツールバー・アプリケーションのルート・フォルダを開き、コマンドを実行: ojet create component call-panel.

    これにより、src/ts/jet-compositesフォルダにcall panelカスタム・コンポーネントが作成されます。

    詳細は、「Oracle JET Webコンポーネントの作成」を参照してください。

要件に基づいてコンポーネントのファイルを更新

要件に基づいてコンポーネントのコードを更新するには、次のファイルを参照してください:
  • src/ts/jet-composites/call-panel-view.htmlファイルを更新するには:
    <div class="oj-sm-margin-4x oj-flex oj-sm-justify-content-center">
        <div class="oj-flex oj-bg-neutral-170 oj-sm-padding-6x call-panel oj-color-invert">
            <div
                    class="oj-sm-12 oj-flex oj-sm-flex-direction-column oj-sm-align-items-center oj-sm-justify-content-space-between">
                <div class="oj-sm-margin-4x-top oj-flex oj-sm-flex-direction-column oj-sm-align-items-center top-panel">
                    <div class="oj-flex-item oj-typography-heading-xs oj-sm-margin-5x-bottom">
                        <!-- Shows the text Incoming Call / Calling in the component based on the call direction -->
                        <oj-bind-if test="[[callContext().direction === 'inbound']]">
                            Incoming Call
                        </oj-bind-if>
                        <oj-bind-if test="[[callContext().direction === 'outbound']]">
                            Calling
                        </oj-bind-if>
                    </div>
     
                    <!-- Adds a phone icon as avatar in the component -->
                    <oj-c-avatar
                            class="oj-avatar-8xl"
                            role="img"
                            icon-class="oj-ux-ico-call-incoming"
                            background="green"></oj-c-avatar>
                    <br/><br/>
                    <div id="progressBarContainer" class="oj-flex-item">
                        <oj-bind-if test="[[callContext().state === 'ACCEPTED']]">
                            <!-- Show a call in progress animation during the ACCEPTED state -->
                            <oj-c-progress-bar
                                    id="progressBar"
                                    aria-label="basic progress bar"
                                    value="-1"></oj-c-progress-bar>
                        </oj-bind-if>
                    </div>
     
                </div>
                <!-- Show caller information -->
                <div class="oj-sm-flex oj-sm-flex-direction-column call-details">
                    <div class="oj-flex-item oj-typography-heading-md oj-sm-margin-2x-vertical">
                        <oj-bind-text value="[[callContext().callerName]]"></oj-bind-text>
                    </div>
                    <div class="oj-flex-item oj-typography-subheading-xs">
                        <oj-bind-text value="[[callContext().phonenumber]]"></oj-bind-text>
                    </div>
                    <table class="ivr-data-table oj-typography-body-sm oj-sm-margin-4x oj-helper-text-align-left">
                        <oj-bind-for-each data="[[ivrDataProvider]]">
                            <template>
                                <tr>
                                    <td><oj-bind-text value="[[$current.data.key]]"></oj-bind-text></td>
                                    <td>:</td>
                                    <td><oj-bind-text value="[[$current.data.value]]"></oj-bind-text></td>
                                </tr>
                            </template>
                        </oj-bind-for-each>
                    </table>
                </div>
                <div class="oj-flex oj-sm-justify-content-center oj-sm-margin-2x-vertical">
                    <oj-bind-if test="[[callContext().state === 'ACCEPTED']]">
                        <oj-c-button id="hold" display="icons" label="hold">
                            <span slot="startIcon" class="oj-ux-ico-pause-circle"></span>
                        </oj-c-button>
                    </oj-bind-if>
     
                </div>
                <div class="oj-flex oj-sm-justify-content-center">
                    <!-- Show call accept and disconnect buttons in the component -->
                    <oj-bind-if test="[[callContext().state === 'RINGING' && callContext().direction === 'inbound']]">
                        <!-- Show call accept button only during inbound call RINGING state -->
                        <oj-c-button id="acceptCall" display="icons" label="Accept" chroming="borderless"
                                     on-oj-action="[[ acceptClicked ]]"
                                     class="oj-sm-margin-2x-horizontal">
                            <span slot="startIcon"
                                  class="oj-ux-ico-call oj-sm-padding-4x oj-sm-padding-10x-horizontal call-accept"></span>
                        </oj-c-button>
                    </oj-bind-if>
                    <oj-c-button id="declineCall" display="icons" label="Decline" chroming="danger"
                                 on-oj-action="[[ disconnectClicked ]]"
                                 class="oj-sm-margin-2x-horizontal">
                        <span slot="startIcon" class="oj-ux-ico-call-end oj-sm-padding-4x oj-sm-padding-10x-horizontal"></span>
                    </oj-c-button>
                </div>
            </div>
        </div>
    </div>
  • src/ts/jet-composites/call-panel-viewModel.tsファイルを更新するには:
    "use strict";
     
    import * as ko from "knockout";
    import Context = require("ojs/ojcontext");
    import Composite = require("ojs/ojcomposite");
    import ArrayDataProvider = require('ojs/ojarraydataprovider');
    import "oj-c/button";
    import "ojs/ojknockout";
    import "oj-c/avatar";
    import "oj-c/progress-bar";
     
    interface CallContext {
        phonenumber: string;
        callerName: string;
        direction: string;
        eventId: string;
        ivrData: { [key: string]: string };
        state: string;
    }
     
    export default class ViewModel implements Composite.ViewModel<Composite.PropertiesType> {
        busyResolve: (() => void);
        composite: Element;
        properties: Composite.PropertiesType;
        callContext: ko.Observable<CallContext>;
        ivrDataProvider: ArrayDataProvider<string, { [key: string]: string }>;
     
        constructor(context: Composite.ViewModelContext<Composite.PropertiesType>) {
            //At the start of your viewModel constructor
            const elementContext: Context = Context.getContext(context.element);
            const busyContext: Context.BusyContext = elementContext.getBusyContext();
            const options = { "description": "Web Component Startup - Waiting for data" };
            this.busyResolve = busyContext.addBusyState(options);
     
            this.composite = context.element;
     
            // Properties passed to the component
            this.properties = context.properties;
     
            this.callContext = ko.observable(this.properties.callContext);
     
            this.ivrDataProvider = new ArrayDataProvider(this.parseIvrData(), {
                keyAttributes: 'key'
            });
     
            //Once all startup and async activities have finished, relocate if there are any async activities
            this.busyResolve();
        }
     
        parseIvrData(): any {
            let data: any[] = [];
            if (this.callContext()?.ivrData) {
                data = Object.keys(this.callContext().ivrData).map((key: string) => {
                    return {
                        key: key,
                        value: this.callContext().ivrData[key]
                    }
                });
            }
            const ivrData: any = ko.observableArray(data);
            return ivrData;
        }
     
        public acceptClicked: (event: any) => void = (event:  any): void => {
            // Logic to fire and event to the container that the accept button is clicked
            const formattedEvent: object = {bubbles: true, cancelable: false, detail: {}};
            const acceptButtonClickedEvent: CustomEvent = new CustomEvent('acceptButtonClicked', formattedEvent);
            this.composite.dispatchEvent(acceptButtonClickedEvent);
        }
     
        public disconnectClicked: (event: any) => void = (event:  any): void => {
            // Logic to fire and event to the container that the disconecct button is clicked.
            // If the call is in ACCEPTED state, the value 'HANGUP' is passed as the event payload to the container,
            // Otherwise, the value 'REJECT' is passed as the event payload
            const disconnectionState: string = (this.callContext().state === 'ACCEPTED') ? 'WRAPUP' : 'REJECT';
            const formattedEvent: object = {bubbles: true, cancelable: false, detail: { disconnectionState }};
            const disconnectButtonClickedEvent: CustomEvent = new CustomEvent('disconnectButtonClicked', formattedEvent);
            this.composite.dispatchEvent(disconnectButtonClickedEvent);
        }
     
        //Lifecycle methods - implement if necessary
     
        activated(context: Composite.ViewModelContext<Composite.PropertiesType>): Promise<any> | void {
     
        };
     
        connected(context: Composite.ViewModelContext<Composite.PropertiesType>): void {
     
        };
     
        bindingsApplied(context: Composite.ViewModelContext<Composite.PropertiesType>): void {
     
        };
     
        propertyChanged(context: Composite.PropertyChangedContext<Composite.PropertiesType>): void {
            if (context.property === 'callContext') {
                // Update callContext observable based on the propertyChange
                this.callContext({...this.callContext(), state: context.value.state});
            }
        };
     
        disconnected(element: Element): void {
     
        };
    };
  • src/ts/jet-composites/call-panel-styles.cssファイルを更新するには:
    call-panel:not(.oj-complete) {
        visibility: hidden;
    }
     
    call-panel[hidden] {
        display: none;
    }
     
    .call-panel {
        min-height: 450px;
        min-width: 300px;
        border-radius: 10px;
    }
     
    .top-panel {
        color: #dfdfdf;
    }
     
    .call-accept {
        background-color: #28b328;
    }
     
    .call-accept:hover {
        background-color: #239b23;
    }
     
    .call-details {
        text-align: center;
        color: #ffffff;
    }
     
    .ivr-data-table {
        color: #c4c4c4;
    }
     
    #progressBarContainer {
        width: 100%;
    }
  • src/ts/jet-composites/component.jsonファイルを更新するには:
    {
      "name": "call-panel",
      "version": "1.0.0",
      "jetVersion": "^15.1.0",
      "displayName": "A user friendly, translatable name of the component.",
      "description": "A translatable high-level description for the component.",
      "properties": {
        "callContext": {
          "description": "The Call context details.",
          "displayName": "Call Context",
          "type": "object"
        }
      },
      "methods": {},
      "events": {
        "acceptButtonClicked": {
          "displayName": "acceptButtonClicked",
          "description": "Will be called when accept button is clicked.",
          "bubbles": true,
          "cancelable": true,
          "detail": {
          }
        },
        "disconnectButtonClicked": {
          "displayName": "disconnectButtonClicked",
          "description": "Will be called when disconnect button is clicked.",
          "bubbles": true,
          "cancelable": true,
          "detail": {
          }
        }
      },
      "slots": {}
    }

参照

OJETカスタム・コンポーネント