依頼Form

GAS

const SHEET_ID = '●●●●●●●●●●●●●●●●●●●●●●●●●●'; 
const SHEET_NAME = 'シート1'; 
const RECIPIENT_EMAIL = '●●●●●●●●●●●●●●●●'; 
const CC_EMAIL = '●●●●●●●●●●●●●●●●'; // CCのメールアドレス
const DRIVE_FOLDER_ID = '●●●●●●●●●●●●●●●●●●●●●●●●●●';  // 画像を保存するドライブフォルダのID


function doGet() {
  const template = HtmlService.createTemplateFromFile('form');
  template.incompleteCount = getIncompleteCount(); // 未完了件数をテンプレートに渡す
  template.userEmail = Session.getActiveUser().getEmail(); // ログインユーザーのメールアドレスを渡す
  return template.evaluate().setTitle('依頼 Form');
}

function getIncompleteCount() {
  const sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(SHEET_NAME);
  const data = sheet.getRange('F:F').getValues();
  let count = 0;
  data.forEach(row => {
    if (row[0] === '進行中' || row[0] === '順番待ち') {
      count++;
    }
  });
  return count;
}

function submitForm(data) {
  const lock = LockService.getScriptLock();
  try {
    lock.waitLock(30000); // 最大30秒待つ
    const sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(SHEET_NAME);
    const lastRow = sheet.getLastRow();
    const newRowNumber = lastRow + 1;
    const now = new Date();
    sheet.getRange(newRowNumber, 1).setValue(now); // A列に日時を設定
    sheet.getRange(newRowNumber, 2, 1, 4).setValues([[data.requestType, data.requestContent, data.requester, data.preferredStart]]);

    let imageLinks = [];
    if (data.imageData) {
      const folder = DriveApp.getFolderById(DRIVE_FOLDER_ID);
      for (let i = 0; i < data.imageData.length; i++) {
        const blob = Utilities.newBlob(Utilities.base64Decode(data.imageData[i].data), data.imageData[i].mimeType, data.imageData[i].filename);
        const file = folder.createFile(blob);
        imageLinks.push(file.getUrl());
      }
    }
    
    // 画像リンクをスプレッドシートに追加
    for (let i = 0; i < imageLinks.length; i++) {
      sheet.getRange(newRowNumber, 7 + i).setValue(imageLinks[i]);
    }

    // メール送信
    const subject = '★★★依頼が来ました!';
    const body = [
      `依頼種類: ${data.requestType}`,
      `依頼内容: ${data.requestContent}`,
      `依頼者: ${data.requester}`,
      `希望着手: ${data.preferredStart}`,
      `画像リンク: ${imageLinks.join('\n')}`
    ].join('\n');
    MailApp.sendEmail({
      to: RECIPIENT_EMAIL,
      cc: CC_EMAIL,
      subject: subject,
      body: body
    });
  } catch (e) {
    Logger.log('Error: ' + e.message);
  } finally {
    lock.releaseLock();
  }
}

form.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <style>
      body {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        background-color: #f0f0f0;
        margin: 0;
      }
      .form-container {
        background-color: #e0f7fa;
        padding: 20px;
        border-radius: 10px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        width: 400px;
        display: flex;
        flex-direction: column;
        align-items: center;
        position: relative;
      }
      .form-container h1 {
        text-align: center;
        width: 100%;
        margin: 0;
      }
      .form-container .incomplete-count {
        position: absolute;
        top: 10px;
        right: 10px;
        font-size: 0.8em;
        color: #333;
        background-color: #ffeb3b;
        padding: 5px 10px;
        border-radius: 5px;
      }
      .form-container label, .form-container input, .form-container textarea, .form-container select {
        display: block;
        width: 100%;
        margin-bottom: 10px;
      }
      .form-container textarea {
        margin-bottom: 20px;
        height: 150px;
      }
      .form-container input[type="text"], .form-container textarea, .form-container select {
        padding: 10px;
        border: 1px solid #ccc;
        border-radius: 5px;
      }
      .form-container input[type="file"] {
        padding: 10px;
        border: 1px solid #ccc;
        border-radius: 5px;
        margin-bottom: 20px;
      }
      .form-container input[type="button"] {
        background-color: #4CAF50;
        color: white;
        border: none;
        padding: 10px;
        border-radius: 5px;
        cursor: pointer;
        width: 100%;
      }
      .form-container input[type="button"]:hover {
        background-color: #45a049;
      }
      #status {
        text-align: center;
        margin-top: 10px;
        color: green;
      }
    </style>
  </head>
  <body>
    <div class="form-container">
      <h1>依頼 Form</h1>
      <div class="incomplete-count">未完了件数: <?= incompleteCount ?></div>
      <form id="contactForm">
        <label for="requestType">依頼種類:</label>
        <select id="requestType" name="requestType" oninput="clearStatus()">
          <option value="作成">作成</option>
          <option value="修正">修正</option>
          <option value="相談">相談</option>
          <option value="その他">その他</option>
        </select>
        <label for="requestContent">依頼内容:</label>
        <textarea id="requestContent" name="requestContent" oninput="clearStatus()"></textarea>
        <label for="requester">依頼者:</label>
        <input type="text" id="requester" name="requester" value="<?= userEmail ?>" oninput="clearStatus()" readonly>
        <label for="preferredStart">希望着手:</label>
        <select id="preferredStart" name="preferredStart" oninput="clearStatus()">
          <option value="なるはや">なるはや</option>
          <option value="できれば早く">できれば早く</option>
          <option value="手が空いたら">手が空いたら</option>
          <option value="順番待ち">順番待ち</option>
          <option value="いつでもいい">いつでもいい</option>
        </select>
        <label for="imageUpload">画像添付:</label>
        <input type="file" id="imageUpload" multiple>
        <input type="button" value="送信" onclick="submitForm()">
      </form>
      <div id="status"></div>
    </div>
    <script>
      function clearStatus() {
        document.getElementById('status').innerText = '';
      }

      function submitForm() {
        const form = document.getElementById('contactForm');
        const imageInput = document.getElementById('imageUpload');
        const files = imageInput.files;
        const data = {
          requestType: form.requestType.value,
          requestContent: form.requestContent.value,
          requester: form.requester.value,
          preferredStart: form.preferredStart.value,
          imageData: []
        };

        const promises = Array.from(files).map(file => new Promise((resolve, reject) => {
          const reader = new FileReader();
          reader.onload = function(e) {
            data.imageData.push({
              filename: file.name,
              mimeType: file.type,
              data: e.target.result.split(',')[1]
            });
            resolve();
          };
          reader.onerror = reject;
          reader.readAsDataURL(file);
        }));

        Promise.all(promises).then(() => {
          google.script.run.withSuccessHandler(function(response) {
            document.getElementById('status').innerText = '送信完了! 席でお待ちください。';
            form.reset();
            imageInput.value = ""; // 画像選択フィールドをリセット
          }).submitForm(data);
        }).catch(error => {
          console.error(error);
          document.getElementById('status').innerText = '画像のアップロードに失敗しました';
        });
      }
    </script>
  </body>
</html>

いいなと思ったら応援しよう!