KurocoとNuxt.jsで、フォーム画面を構築する

Kurocoを利用したNuxt.jsプロジェクトで、フォームの利用方法を紹介します。

このページは、KurocoとNuxt.jsでのプロジェクトが構築済みであることを前提としています。 まだ構築していない場合は、こちらを参照してください。

Kurocoにおけるフォームとは

Kurocoにおけるフォームとは、HTMLフォームの作成支援のためのデータの定義、自動返信の設定、ユーザーから送信されたフォーム用データの閲覧などができる機能です。

フォームの設定は、管理画面の[キャンペーン]の[フォーム]から管理/設定ができます。

Image (fetched from Gyazo)

詳細は下記を参照してください。

フォームは初期状態では動作せず、各種設定とフロントエンド側のコーディングが必要となります。 この記事では、KurocoとNuxt.jsでのプロジェクトの内容を変更してフォームを有効化するための手順を紹介します。

フォームのデータを作成する

フォームを作成する

まず、フォーム定義を作成します。 フォーム一覧画面より、[フォーム追加]をクリックします。

Image (fetched from Gyazo)

新規フォーム作成画面が表示されるので、フォーム基本設定を参考に、動作確認用のフォーム定義を入力します。今回は下記のように設定しました。

Image (fetched from Gyazo)

項目
タイトルテストフォーム
説明説明です。
説明です。
説明です。
サンクス文言サンクス文言です。
サンクス文言です。
サンクス文言です。

最下部の[追加する]をクリックします。

Image (fetched from Gyazo)

自動でフォーム一覧画面に遷移し、入力したフォームが新規追加されていることが確認できます。

Image (fetched from Gyazo)

この画面に表示されているIDが、これから作成していく対象のフォームですので、メモをしておいてください。

ここではID: 10となっていますが、この値は自動採番のため、値は環境によって異なります。この後の操作は、実際に画面に表示されたIDを使用してください

ここまででフォーム定義の作成は完了しました。

フォームの設定を確認する

次に、先ほど作成したフォームの設定やデータを確認します。

「項目設定」の確認

フォーム一覧画面より、作成した[テストフォーム]をクリックします。

Image (fetched from Gyazo)

フォーム基本設定画面が表示されるので、[項目設定]タブをクリックします。

Image (fetched from Gyazo)

フォーム項目設定画面が表示されます。

Image (fetched from Gyazo)

この画面は、HTMLフォームの項目を定義するものです。

「name」「email」「message」は、Kurocoで必須の項目のためあらかじめ設定されています。
項目を追加したい場合は、ご自身で項目の定義を追加することができます。
[message]以下に空白の項目が見えていますが、必要に応じて、ここにカスタム定義を追加していきます。

Image (fetched from Gyazo)

今回はデフォルトの項目のみでフォームを作成しますので、項目の設定はこのままにしておいてください。

「回答」の確認

続いて[回答]タブをクリックすると、ユーザーから送信されたフォームの回答データの一覧が表示されます。

Image (fetched from Gyazo)

ここにはHTMLフォームから送信された実際の回答が一覧で表示されます。
(現在はまだHTMLフォームが作成されておらず、データが送信されていないため、0件で表示されています)
回答内容などの詳細はこの画面や、右隣に隣接している[レポート]タブから確認することができます。

フォーム用のエンドポイントを作成する

次に、作成したフォーム定義に関するエンドポイントを作成し、フロントエンドからフォーム機能を使用できるように設定をします。

今回は下記2つのエンドポイントを作成します。

  • フォーム定義を取得するエンドポイント: (GET) form
  • フォームを送信するエンドポイント: (POST) form

フォーム定義を取得するエンドポイントを作成する

[API]より対象のAPIを選択し、API管理画面より [新しいエンドポイントの追加] をクリックます。

Image (fetched from Gyazo)

今回は下記設定にてエンドポイントを作成します。

Image (fetched from Gyazo)

設定項目設定
パスform
有効/無効有効
モデルカテゴリーフォーム
モデルInquiryForm
オペレーションdetails
認証None

ここでは簡易化のため、認証はNoneを指定しています。

SwaggerUIで確認する

SwaggerUIにて、作成したフォーム定義を取得できるか確認します。 API画面より、[Swagger UI]をクリックします。

Image (fetched from Gyazo)

Swagger UI画面が表示されるので、先ほど作成したエンドポイントをクリックします。

Image (fetched from Gyazo)

[Try it out]をクリックします。

Image (fetched from Gyazo)

入力項目[inquiry_id]に、先ほど作成したフォームのIDを入力し(ここでは10を入力しています)、[Execute]をクリックします。

Image (fetched from Gyazo)

作成したフォーム定義がJSON化されて表示されることが確認できます。

Image (fetched from Gyazo)

以上でフォーム用のエンドポイントが完成しました。

データを送信用のエンドポイントを作成する

次に、HTMLから対象のフォームにデータを送信するためのエンドポイントを作成します。

[API]より対象のAPIを選択し、API管理画面より [新しいエンドポイントの追加] をクリックます。

Image (fetched from Gyazo)

今回は下記設定にてエンドポイントを作成します。

ここでも同じく、認証はNoneを指定してください。

Image (fetched from Gyazo)

設定項目設定
パスform
有効/無効有効
モデルカテゴリーフォーム
モデルInquiryMessage
オペレーションsend
認証None

[+Add]をクリックしてエンドポイントを作成します。 以上でデータを送信用のエンドポイントが完成しました。

ここまでで以下の2種類のエンドポイントができました。

  • フォーム定義を取得するエンドポイント: (GET) form
  • フォームを送信するエンドポイント: (POST) form

では実際にこれらのエンドポイントを使用して、HTML上からフォームの作成と送信ができるようにしていきます。

フロントエンドの追加修正をして、HTMLフォームを作成する

Nuxtインストールディレクトリに、下記構造のファイル追加作成します。
今回はpagesディレクトリ内にformディレクトリを作成し、formディレクトリ内に「index.vue」を作成します。

pages
 - form
   - index.vue 

追加したファイルpages/form/index.vueに下記を記載します。

index.vue
<template>
  <div>
    <h1>FORMページ</h1>

    <form v-if="!submitted" ref="form">
      <div v-if="error" class="error">
        <p v-for="(err, idx) in error" :key="idx">
          {{ err }}
        </p>
      </div>

      <div class="row--status">
        <h2>フォーム名</h2>
        <div>{{ name }}</div>
      </div>

      <div class="row--status">
        <h2>説明</h2>
        <div>
          <p v-for="(line, idx) in textLines2texts(info)" :key="idx">
            {{ line }}
          </p>
        </div>
      </div>

      <div class="row--status">
        <h2>サンクス文言</h2>
        <div>
          <p v-for="(line, idx) in textLines2texts(thanksText)" :key="idx">
            {{ line }}
          </p>
        </div>
      </div>

      <div class="row--status">
        <h2>フォーム項目</h2>
        <div class="row--internal">
          <div v-for="col in cols" :key="col.key">
            <p>[{{ col.title }}]</p>
            <pre>{{ col }}</pre>
          </div>
        </div>
      </div>

      <div v-for="col in cols" :key="col.objKey" class="row--form">
        <h2>[{{ col.title }}]</h2>
        <input :name="col.objKey" type="text" />
      </div>

      <div class="row--bottom-next">
        <button @click="handleOnSubmit">submit</button>
      </div>
    </form>

    <form v-else>
      <div class="row--status">
        <h2>問い合わせID</h2>
        <div>
          {{ submittedId }}
        </div>
      </div>

      <div class="row--status">
        <h2>サンクス文言</h2>
        <div>
          <p v-for="(line, idx) in textLines2texts(thanksText)" :key="idx">
            {{ line }}
          </p>
        </div>
      </div>

      <div class="row--bottom-back">
        <button @click="handleOnBack">back</button>
      </div>
    </form>
  </div>
</template>

<script>
const FORM_ID = 10 // 作成したフォーム定義のID

export default {
  async asyncData({ $axios }) {
    const response = await $axios.$get(
      process.env.BASE_URL + `/rcms-api/2/form/${FORM_ID}`
    )
    return {
      name: response.details.inquiry_name,
      info: response.details.inquiry_info,
      thanksText: response.details.thanks_text,
      cols: Object.entries(response.details.cols).map(([k, v]) => ({
        objKey: k,
        ...v,
      })),
    }
  },
  data: () => {
    return {
      submitted: false,
      submittedId: null,
      error: null,
    }
  },
  methods: {
    textLines2texts(textLines = '') {
      return textLines.split('\r\n')
    },
    async handleOnSubmit(e) {
      e.preventDefault()

      // collect input elements
      const formInputElements = Array.from(this.$refs.form.elements).filter(
        (elm) => elm.tagName.toLowerCase() === 'input'
      )

      // transform key:value inputs to an object
      const body = formInputElements
        .map((elm) => ({ [elm.name]: elm.value }))
        .reduce((prev, cur) => ({ ...prev, ...cur }), {})

      try {
        // post data
        const { id } = await this.$axios.$post(
          process.env.BASE_URL + `/rcms-api/2/form?id=${FORM_ID}`,
          body
        )
        this.error = null
        this.submittedId = id
        this.submitted = true
      } catch (e) {
        this.error = [`${e}`, ...e.response.data.errors]
      }
    },
    handleOnBack(e) {
      e.preventDefault()
      this.submitted = false
    },
  },
}
</script>

<style scoped>
input {
  width: 100%;
  border: none;
}

.error {
  color: red;
}
.error > *:first-child {
  font-weight: bold;
}

.row--status {
  display: flex;
  border-top: 1px solid black;
}
.row--status > *:first-child {
  background-color: yellow;
  min-width: 15rem;
  max-width: 15rem;
  border-right: 1px solid black;
}

.row--form {
  display: flex;
  border-top: 1px solid black;
}
.row--form > *:first-child {
  background-color: aquamarine;
  min-width: 15rem;
  max-width: 15rem;
  border-right: 1px solid black;
}

.row--bottom-next {
  padding: 8px 16px;
  display: flex;
  justify-content: flex-end;
}
.row--bottom-back {
  padding: 8px 16px;
  display: flex;
  justify-content: flex-start;
}

.row--internal {
  display: flex;
}

form > *:nth-last-child(2) {
  border-bottom: 1px solid black;
}
</style>

const FORM_ID = 10の箇所は、ご自身の作成したフォーム定義のIDをご記入ください。

/rcms-api/2/form/${FORM_ID}/rcms-api/2/form?id=${FORM_ID}の箇所は、Kuroco管理画面に記載のパスをご記入ください。

Image (fetched from Gyazo)

ブラウザで確認する

次に、先ほど作成したファイルをブラウザで確認します。 ローカルサーバーが停止している場合はnpm run devを実行し、http://localhost:3000/formにアクセスします。
すると、下記画面が表示されます。

Image (fetched from Gyazo)

ここで表示されている表のうち、黄色の行については、取得したフォーム定義より抜粋したデータを表示しています。

データ内容アクセス方法
フォーム名(response).details.inquiry_name
説明(response).details.inquiry_info
サンクス文言(response).details.thanks_text
フォーム項目(response).details.cols

ソースコード内「asyncData()」にあるように、上記の対応表通りにフォーム定義を取得できていることが確認できます。

フォーム項目は、[カテゴリ]以外のデフォルト項目がオブジェクト形式で返却されています。

より詳細な情報を閲覧したい場合には、Chromeの開発者コンソールから、[Network]タブで実際にKurocoと通信している内容をご確認ください。

データを送信する

次に、取得したデータ定義を元に実際にHTMLフォームからデータを送信します。
画面に表示している表の緑色の行は入力項目(HTMLフォーム)になっています。
各項目に下記のように値を入力します。

Image (fetched from Gyazo)

項目名入力値
[name]テスト名
[email]test@example.com
[message]テストメッセージ

[submit]ボタンをクリックすると、データが送信され次の画面に遷移します。

Image (fetched from Gyazo)

ソースコード内「handleOnSubmit()」にあるように、この操作によって、[フォーム項目]のデータをKurocoに送信しました。

データをKurocoで確認する。

次に、送信したデータをKurocoで確認します。
フォーム一覧画面より、作成した[テストフォーム]をクリックします。

Image (fetched from Gyazo)

[回答]タブをクリックして、回答の一覧を表示すると、データが1件存在することが確認できます。

Image (fetched from Gyazo)

[No.]をクリック(ここでは109)すると、回答内容の詳細を確認することができます。

Image (fetched from Gyazo)

回答の詳細に、HTMLフォームから送信された値が含まれていることが確認できます。

フォームのバリデーションを確認する

最後に、フォームのバリデーションを確認します。

先ほど作成したフロントの画面を再度表示し、[email]の項目に無効なメールアドレスを入力して、エラーが返却されることを確認します。

表の緑色の各行に以下を入力します。
([email]の値は無効なメールアドレスですので、エラーとなることが望ましいです)

Image (fetched from Gyazo)

項目名入力値
[name]バリデーションエラー名
[email]mail
[message]バリデーションエラーメッセージ

[submit]をクリックすると、画面上部にエラーメッセージが表示されます。

Image (fetched from Gyazo)

このように、Kurocoにはサーバー側のバリデーションがあることが確認できます。
エラー時はHTTPのステータスコードでのエラーと共に、レスポンスボディ内にエラー内容が返却されてきます。 ソースコード内にある通り、エラー時のハンドリングを実装したい場合には、フロント側でその実装をする必要があります。

動的なバリデーションが必要な場合は、Kurocoから取得してきた値を元に実装が必要になります。

カスタム項目を追加する

デフォルトのフォーム項目以外に、自由にカスタム項目を定義/作成することも可能です。
カスタム項目を作成する場合の手順を確認します。

カスタム項目追加手順

フォーム一覧画面より、作成した[テストフォーム]をクリックします。

Image (fetched from Gyazo)

[項目設定]タブをクリックして、フォーム項目設定画面を表示します。

Image (fetched from Gyazo)

改行なしの短文(テキストボックス)を追加する。

改行なしの短文(テキストボックス)の追加方法を記載します。

Image (fetched from Gyazo)

項目名入力値
タイトルitem
必須属性任意
回答形態/入力制限改行なしの短文(テキストボックス)
選択項目の設定(なし)

上記表にあるように、[必須属性]、[選択項目の設定]にてバリデーション用の属性を設定し、フォーム項目の属性としてその入力制限の内容を返却させるように設定することも可能です。

設定したら、画面下部の[更新する]をクリックしてください。

Image (fetched from Gyazo)

先ほど作成したフロントの画面を再度表示し、Kurocoから取得するフォーム定義が一部変更になっていることを確認します。 [フォーム項目]に[item]が追加となっていることが確認できます。

Image (fetched from Gyazo)

では実際にフォームデータを送信し、新しい[item]項目がKurocoに送信されることを確認します。 フロント画面の表の緑色の各行に以下を入力します。

Image (fetched from Gyazo)

項目名入力値
[item]追加項目アイテム
[name]追加項目名
[email]test@example.com
[message]追加項目メッセージ

[submit]をクリックしてデータを送信します。

管理画面の[フォーム]から[回答]タブをクリックして回答の一覧を表示し、
データが一件追加されていることを確認します。

Image (fetched from Gyazo)

[No.]をクリック(ここでは110)して詳細を表示すると、新規追加した項目[item]と、その項目に入力した値が適用されていることが確認できます。

Image (fetched from Gyazo)

日付の入力項目を追加する

カスタム項目のうち、日付の入力項目を追加してフォームを確認します。

日付の入力項目をフォーム定義に追加する

既存で作成したフォーム定義の[項目設定]タブをクリックして、フォーム項目設定画面を表示します。
ここに日付のinput項目を追加定義します。

fetched from Gyazo

項目名入力値
タイトルdate
必須属性任意
回答形態/入力制限日付フォーマット
選択項目の設定(なし)

別途カスタマイズ項目を既に設定されている場合は、動作確認のためあらかじめクリアしておいてください。

上記表にあるように、[必須属性]、[選択項目の設定]にてバリデーション用の属性を設定し、フォーム項目の属性としてその入力制限の内容を返却させるように設定することも可能です。

設定したら、画面下部の[更新する]をクリックしてください。

Image (fetched from Gyazo)

フロントの画面を表示し、Kurocoから取得するフォーム定義が変更されていることを確認します。

Image from Gyazo

では実際にフォームデータを送信し、新しい[date]項目がKurocoに送信されることを確認します。 フロント画面の表の緑色の各行に以下を入力します。

fetched from Gyazo

項目名入力値
[date]1900/01/01
[name]日付項目名
[email]test@example.com
[message]日付項目メッセージ

[submit]をクリックしてデータを送信します。

管理画面の[フォーム]から[回答]タブをクリックして回答の一覧を表示し、
追加されたデータが送信した内容と一致していることを確認します。

fetched from Gyazo

日付の入力項目にバリデーションを設定する

日付にはKuroco側でのバリデーションを設定することができます。
今回は一例として、今現在から10年前までを許容範囲とするバリデーションを設定します。

作成したフォーム定義の[項目設定]から、フォーム項目設定画面を表示します。
[設定]をクリックします。

fetched from Gyazo

設定画面にて、開始までの期間-10 yearsを入力して設定、適用します。

fetched from Gyazo

項目設定については、フォーム定義で利用できるフォーム項目一覧 -> 日付フォーマットを参照してください。

これでバリデーションが設定されましたので、10年前より以前の日付はエラーとなります。
フロントエンドのフォーム画面から先ほどと同様に1900/01/01をリクエストして、失敗することを確認します。

先ほどのフォーム画面にて、下記を送信します。

項目名入力値
[date]1900/01/01
[name]日付項目名
[email]test@example.com
[message]日付項目メッセージ

エラーがレスポンスされることを画面上部のエラーメッセージから確認します。
(エラーとなった場合は画面上部にエラー内容を表示するようにしてありますので、表示範囲外の場合は、上部までスクロールしてください)

fetched from Gyazo

では、10年前以降の日付を送信して、データが正常に処理されることを確認します。

[date]の内容を10年前以降となるとうな日付を入力し直して再度フォームを送信します。
(今回は2022/04/01としています)

fetched from Gyazo

データが送信され、完了画面に画面遷移することを確認します。

fetched from Gyazo

ファイルの入力項目を追加する

カスタム項目のうち、ファイルの入力項目を追加してフォームを確認します。

ファイルの入力項目をフォーム定義に追加する

既存で作成したフォーム定義の[項目設定]タブをクリックして、フォーム項目設定画面を表示します。
ここにファイルのinput項目を追加定義します。

fetched from Gyazo

項目名入力値
タイトルfile
必須属性任意
回答形態/入力制限ファイル
拡張子の設定(なし)

[必須属性]、[拡張子の設定]にてバリデーション用の属性を設定し、フォーム項目の属性としてその入力制限の内容を返却させるように設定することも可能です。

設定したら、画面下部の[更新する]をクリックしてください。

Image (fetched from Gyazo)

フロントの画面を表示し、Kurocoから取得するフォーム定義が変更されていることを確認します。

fetched from Gyazo

アップロード用のエンドポイントを作成する

ファイルアップロードの実装は下記の流れとなります。

  1. Kurocoへファイルをアップロードする
  2. アップロードしたファイルIDを送信する

そのため、まずはアップロードの受け口となるエンドポイントを追加します。
[API]より対象のAPIを選択し、API管理画面より [新しいエンドポイントの追加] をクリックます。

Image (fetched from Gyazo)

今回は下記設定にてエンドポイントを作成します。

fetched from Gyazo

設定項目設定
パスfile
有効/無効有効
モデルカテゴリーファイル
モデルFiles
オペレーションupload
認証None

簡易化のため、認証はNoneを指定しています。

SwaggerUIで確認する

SwaggerUIにて、作成したフォーム定義を取得できるか確認します。 API画面より、[Swagger UI]をクリックします。

Image (fetched from Gyazo)

Swagger UI画面が表示されるので、先ほど作成したエンドポイントをクリックします。

fetched from Gyazo

[Try it out]をクリックします。

fetched from Gyazo

入力項目[file]に、サンプルのファイルを選択し、[Execute]をクリックします。ここではkuroco.pngというロゴ画像を選択しました。

Image (fetched from Gyazo)

ファイルがアップロードされ、一時領域にファイルが格納されます。file_idには、ファイルの格納先が表示されます。

Image (fetched from Gyazo)

なお、file_idにブラウザでアクセスすると、アップロードした画像が表示され、ファイルが格納されていることが確認できます。

確認先のURLは、管理画面のホスト名 + file_idです。

fetched from Gyazo

以上でフォーム用のエンドポイントが完成しました。

フォームを修正してファイルを送信する。

次に、pages/form/index.vueを変更します。

ファイルの拡張項目に対応する入力項目には、ファイル入力を受付可能とさせるように変更します。

       <div v-for="col in cols" :key="col.objKey" class="row--form">
         <h2>[{{ col.title }}]</h2>
-        <input :name="col.objKey" type="text" />
+        <input v-if="col.title === 'file'" :name="col.objKey" type="file" @change="uploadFile" />
+        <input v-else :name="col.objKey" type="text" />
       </div>
 
       <div class="row--bottom-next">

ファイルを入力すると同時にアップロード用エンドポイントにファイルを送信し、レスポンスのfile_idを保存するようにします。

   data: () => {
     return {
       submitted: false,
       submittedId: null,
       error: null,
+      file_id: null,
     }
   },
   methods: {
+    async uploadFile(e) {
+      const fm = new FormData();
+      fm.append('file', e.target.files[0]);
+
+      const { file_id } = await this.$axios.$post(
+        process.env.BASE_URL + `/rcms-api/2/file`,
+        fm,
+        {
+          headers: {
+            'Content-Type': 'multipart/form-data', // required to post file as a binary
+          },
+        }
+      );
+      this.file_id = file_id;
+    },
     textLines2texts(textLines = '') {

送信するデータのうち、ファイルの拡張項目のデータをfile_idに手動設定します。

         .map((elm) => ({ [elm.name]: elm.value }))
         .reduce((prev, cur) => ({ ...prev, ...cur }), {})
 
+      // apply file_id instead of the actual file input value
+      body.ext_01 = {
+        file_id: this.file_id,
+      };
+
       try {
         // post data

では実際に画像のアップロードとフォームデータ送信を行い、新しい[file]項目がKurocoに送信されることを確認します。 フロント画面の表の緑色の各行に以下を入力します。

fetched from Gyazo

項目名入力値
[name]ファイル項目名
[file]画像ファイル
[email]test@example.com
[message]ファイル項目メッセージ

[submit]をクリックしてデータを送信します。

管理画面の[フォーム]から[回答]タブをクリックして回答の一覧を表示し、データが一件追加されていることを確認します。

fetched from Gyazo

[No.]をクリック(ここでは155)して詳細を表示すると、新規追加した項目[file]と、その項目に入力した値が適用されていることが確認できます。

Image from Gyazo

フロントエンドにおける、拡張項目のバリデーションについて

Kuroco側のバリデーションはあくまでバックエンド側のバリデーションです。 フロントエンドでのバリデーションをさらに実施されたい場合には、ご自身で実装していただく必要があります。
例として、日付の拡張項目を設定した場合における、フロントエンドでの簡単なバリデーションを追加実装します。

Kurocoは設定したバリデーションの内容を、GETリクエストでのフォーム内容取得時に返します。
フロントエンドのフォーム画面を確認すると、取得したGETレスポンス内に、[options]という設定したバリデーションが返却されていることを確認します。

fetched from Gyazo

この値を、HTMLのinputにminとして設定します。

まず、バリデータの値はPHPのstrtotime()互換のものであるため、javascriptにてこれを動作させるライブラリをインストールします。 まずはターミナルから下記を実行してください。

npm install locutus

次に、pages/form/index.vueを変更します。

ライブラリをコンポーネント内にインポートし(使用可能にさせ)ます。

 </template>
 
 <script>
+import strtotime from 'locutus/php/datetime/strtotime';
+
 const FORM_ID = 21 // 作成したフォーム定義のID
 
 export default {

strtotime()の配置と、これを使ったパーサをメソッドへ実装します。

   },
   methods: {
+    strtotime,
+    getMin(startPeriodStr) {
+        const minDateNum = strtotime(startPeriodStr) * 1000; // to millisec
+        return new Date(minDateNum).toJSON().split('T')[0] // to YYYY-MM-DD
+    },
     textLines2texts(textLines = '') {
       return textLines.split('\r\n')
     },

テンプレート(HTML)の内容を変更します。

       <div v-for="col in cols" :key="col.objKey" class="row--form">
         <h2>[{{ col.title }}]</h2>
-        <input :name="col.objKey" type="text" />
+        <input v-if="col.title === 'date'" type="date" :min="getMin(col.options.minPeriod)" />
+        <input v-else :name="col.objKey" type="text" />
       </div>
 
       <div class="row--bottom-next">

実装後画面を再表示し、該当の入力箇所を選択して、指定された日付以前の値が指定できなくなっていることを確認します。

fetched from Gyazo

お探しのページは見つかりましたか?解決しない場合は、問い合わせフォームからお問い合わせいただくか、Slackコミュニティにご参加ください。