hirokiiiii
@hirokiiiii

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【GAS】Flex message simulatorで作成したデザインが反映されない。

解決したいこと

Googleスプレッドシートに簡単な予約表を作成し、『予約確認』と人間がメッセージを送ると、自動的に予約表の中で空き時間をFlex message simulatorで作成したデザインを送りたい。

下記の画像のイメージで、Flex message simulatorからテスト送信すると、問題なく送れました。

image.png

Googleスプレッドシートで作成している簡単な予約表は下記になります。
空きだけをFlex messageで送信したいと思っています。

image.png

発生している問題・エラー

実際に送られてくるメッセージが下記になります。

image.png

該当するソースコード

実際のソースコードが下記になります。
実行する際には、下記の3点は設定した上で、テストを行っています。
・LINEチャネルのアクセストークン
・スプレッドシートのID
・シート名

const LINE_ACCESS_TOKEN = 'YOUR_LINE_ACCESS_TOKEN'; // LINEチャネルのアクセストークンを設定
const SPREADSHEET_ID = 'YOUR_SPREADSHEET_ID';      // スプレッドシートのIDを設定
const SHEET_NAME = '予約テスト用';                  // シート名を設定

function doPost(e) {
  const json = JSON.parse(e.postData.contents);
  const userMessage = json.events[0].message.text;

  if (userMessage === '予約確認') {
    const replyToken = json.events[0].replyToken;
    const sheetData = getReservationData();
    const replyMessage = createFlexMessage(sheetData);
    sendReplyMessage(replyToken, replyMessage);
  }
  
  return ContentService.createTextOutput(JSON.stringify({ content: 'post ok' })).setMimeType(ContentService.MimeType.JSON);
}

function getReservationData() {
  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(SHEET_NAME);
  const data = sheet.getDataRange().getValues();
  
  let availableSlots = [];
  data.forEach(row => {
    if (row[2] === '空き') { // C列が「空き」の場合を抽出
      availableSlots.push({ date: row[0], time: row[1] });
    }
  });
  
  return availableSlots;
}

function createFlexMessage(slots) {
  if (slots.length === 0) {
    return { type: 'text', text: '現在、予約可能な枠はありません。' };
  }

  const bubbles = slots.map(slot => {
    return {
      type: 'bubble',
      header: {
        type: 'box',
        layout: 'vertical',
        contents: [
          {
            type: 'text',
            text: '予約したい日付を選択ください',
            size: 'md',
            align: 'center',
            weight: 'bold',
            margin: 'lg'
          },
          {
            type: 'text',
            text: '(1つのみ選択可能です)',
            size: 'sm',
            align: 'center',
            gravity: 'top',
            margin: 'lg'
          }
        ]
      },
      body: {
        type: 'box',
        layout: 'vertical',
        contents: [
          {
            type: 'box',
            layout: 'horizontal',
            contents: [
              {
                type: 'button',
                action: {
                  type: 'postback',
                  data: `date=${slot.date}&time=${slot.time}`,
                  label: `${slot.date} ${slot.time}`
                },
                style: 'primary',
                gravity: 'center'
              }
            ],
            justifyContent: 'center',
            alignItems: 'center',
            spacing: 'md'
          }
        ]
      },
      footer: {
        type: 'box',
        layout: 'horizontal',
        contents: [
          {
            type: 'button',
            action: {
              type: 'postback',
              label: 'キャンセル',
              data: 'cancel'
            },
            height: 'sm'
          }
        ],
        spacing: 'xs',
        margin: 'xs'
      }
    };
  });

  return {
    type: 'flex',
    altText: '予約可能な枠があります',
    contents: {
      type: 'carousel',
      contents: bubbles
    }
  };
}

function sendReplyMessage(replyToken, message) {
  const url = 'https://api.line.me/v2/bot/message/reply';
  const headers = {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${LINE_ACCESS_TOKEN}`,
  };
  
  const payload = JSON.stringify({
    replyToken: replyToken,
    messages: [message],
  });

  const response = UrlFetchApp.fetch(url, {
    method: 'post',
    headers: headers,
    payload: payload,
  });

  Logger.log(response.getContentText());
}

自分で試したこと

ChatGPTに何度も質問しながら、『予約確認』と送付すると、Googleスプレッドシート上でC列が『空き』の日付と時間を自動的にメッセージするところまでできましたが、Flex messageを活用できません。

よろしくお願いいたします。

0

2Answer

以前の質問からかなり進んでいて、驚いています!すごいですね!
LINEのFlex messageはよくわからないので、外しているかもしれませんが、回答してみます。

function getReservationData()
略
      availableSlots.push({ date: row[0], time: row[1] });

ここで日付と時間を取得し、その結果をcreateFlexMessage(sheetData);に返していると思います。
その時に、

日付:Fri Nov 01 2024 00:00:00 GMT+0900(日本標準時),時間:Sat Dec 30 1899 09:00:00
GMT+0900(日本標準時)

と返しており、目的のセルの値を取得し返しているようですが、日付だけ、時間だけとして返せていないのが問題ではないか?と予想しています。

下記の記事が参考になるかもしれません。
ChatGPTなどに聞いても教えてくれそうな気もします。

恐らく型は文字型なんだろうと思うので、
現在のセルの値(日付時間)から、必要な日付のみ、時間のみにして、文字型に変換するようなイメージだと思います。

合っているかわかりませんが、

function getReservationData()
略
      date= Utilities.formatDate(row[0],"JST", "MM/dd");
      time= Utilities.formatDate(row[1],"JST", "hh:mm");
      availableSlots.push({ date: date, time: time });

というような感じにしてはどうでしょうか

1Like

Comments

  1. @hirokiiiii

    Questioner

    またしても、ご回答ありがとうございます!
    週末に頑張ってます!
    ギブアップと同時に質問を投げかけている(次は早めに質問します)ので、また来週末になるかもしれませんが、質問投げかけさせてください!

  2. 修正は、@tanaike さんの案の方が直感的にわかりやすく修正範囲も少なくてスマートだと思いますので、そちらを参考にしていただいた方がいいかなと思います。
    (私のもそんなに間違ってはいないと思いますが、スマートさに欠けるため)

getValuesを使用してSpreadsheetから値を取得すると、仕様上、日付をDate objectとして取得します。これが原因と思われますので、この場合、別のアプローチとして、関数 getReservationData を下記のように修正するのはいかがでしょうか。

From:

const data = sheet.getDataRange().getValues();

To:

const data = sheet.getDataRange().getDisplayValues();

Class RangeのgetDisplayValues methodは、Spreadsheetに表示されているそのままの値を文字として取得します。Ref Spreadsheetの表示値がそのまま使用できますので使いやすいのではないかと思いました。

1Like

Your answer might help someone💌