行事曆生成工具問答示範

Prompt:

我想要寫一個可以生成整學期行事曆的html工具,要可以讓我輸入行事曆標題,設定從那一週開始,生成幾週的行事曆,行事曆第一欄要是月份,第二到八欄為日、一、二到六的日期,其中第二及第八欄的單元格背景色用淡灰色。第九欄為學校行事,第十欄為備註,1-8欄為佔用整個表格寬度的一半,9欄佔另一半寬度的4分之3,剩下的寬度為第10欄,生成的畫面上有一個下載行事曆的按鈕,按下後,可以把生成的行事曆下載成html的doc檔。整體介面要好看一點

Response:

推理關於行事曆生成工具花了 28 秒

以下是一個完整的 HTML 範例程式碼,包含 CSS 與 JavaScript,可讓你依需求輸入行事曆標題、設定起始日期與生成週數,並依照格式產生一個符合規格的行事曆,畫面上還有一個按鈕可以下載生成的 HTML 檔案。你可以直接將下列程式碼存成一個 .html 檔,再用瀏覽器開啟即可體驗效果。

下面程式碼說明與重點整理:

  • 輸入介面:包含行事曆標題、起始日期(建議選擇該週的「日」)及生成幾週的行事曆。

  • 表格結構

    • 第一欄顯示當週(依起始日期的「日」)所屬的月份。

    • 第二到第八欄分別為「日、一、二、三、四、五、六」,其中第2欄與第8欄背景色為淡灰色(可自行調整 CSS)。

    • 第九欄為學校行事。

    • 第十欄為備註。

  • 寬度設定:整個表格分為兩大區塊,1~8欄共佔 50% 寬度,剩下 50% 再依比例分為第9欄(75% ≒ 37.5%整體)與第10欄(25% ≒ 12.5%整體)。

  • 下載功能:按下「下載行事曆」按鈕後,將把當前畫面生成的 HTML 當成檔案下載。

你也可以依需求進一步美化介面,下面程式碼供參考:


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 900px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    .calendar-table {
      width: 100%;
      border-collapse: collapse;
      margin-top: 20px;
    }
    .calendar-table th, .calendar-table td {
      border: 1px solid #ccc;
      padding: 8px;
      text-align: center;
    }
    /* 設定第2欄與第8欄背景淡灰 */
    .calendar-table td:nth-child(2),
    .calendar-table td:nth-child(8) {
      background-color: #f0f0f0;
    }
    /* 使用 colgroup 設定表格各欄寬度 */
    .calendar-table colgroup col {
      /* 預設設定,但實際比例在 generate 時以 inline style 設定 */
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(請選擇該週的「日」):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
    
    <div id="calendarContainer"></div>
    <button id="downloadBtn" style="display: none;" onclick="downloadCalendar()">下載行事曆</button>
  </div>
  
  <script>
    // 取得中文星期名稱
    const weekDays = ['日','一','二','三','四','五','六'];

    // 根據起始日期與週數生成行事曆表格
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      const startDate = new Date(startDateStr);
      // 開始組裝 HTML 內容(包含行事曆標題與表格)
      let htmlContent = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body { font-family: "Microsoft JhengHei", sans-serif; margin:20px; }
    h1 { text-align: center; }
    table { width: 100%; border-collapse: collapse; }
    th, td { border: 1px solid #666; padding: 8px; text-align: center; }
    td:nth-child(2), td:nth-child(8) { background-color: #f0f0f0; }
  </style>
</head>
<body>
  <h1>${title}</h1>
  <table>
    <colgroup>
      <col style="width:6.25%;"> <!-- 月份,佔整體寬度 1/16 (6.25%) -->
      <col style="width:6.25%;">
      <col style="width:6.25%;">
      <col style="width:6.25%;">
      <col style="width:6.25%;">
      <col style="width:6.25%;">
      <col style="width:6.25%;">
      <col style="width:6.25%;"> <!-- 共8欄約50% -->
      <!-- 第二塊欄位共50% -->
      <col style="width:37.5%;"> <!-- 第9欄:學校行事(75% 的 50%) -->
      <col style="width:12.5%;"> <!-- 第10欄:備註(25% 的 50%) -->
    </colgroup>
    <thead>
      <tr>
        <th>月份</th>
        <!-- 日 ~ 六 -->
        ${weekDays.map(day => `<th>${day}</th>`).join('')}
        <th>學校行事</th>
        <th>備註</th>
      </tr>
    </thead>
    <tbody>
`;

      // 產生每週的資料列
      let currentDate = new Date(startDate);
      for (let i = 0; i < weeksCount; i++) {
        // 以每週第一天 (即選擇的那一天,通常為 Sunday) 的月份為該列的月份
        const month = currentDate.getMonth() + 1;
        htmlContent += `<tr>`;
        htmlContent += `<td>${month}月</td>`;
        // 產生一週中 7 天(日 ~ 六)
        for (let d = 0; d < 7; d++) {
          const dayNum = currentDate.getDate();
          htmlContent += `<td>${dayNum}</td>`;
          // 移動至下一天
          currentDate.setDate(currentDate.getDate() + 1);
        }
        // 兩個額外欄位:學校行事與備註 (預設空白)
        htmlContent += `<td></td><td></td>`;
        htmlContent += `</tr>`;
      }

      htmlContent += `
    </tbody>
  </table>
</body>
</html>
`;

      // 將生成的行事曆 HTML 顯示於頁面上(可以在 container 中嵌入 iframe 或 pre 標籤展示)
      document.getElementById('calendarContainer').innerHTML =
        `<h2>${title}</h2><iframe style="width:100%; height:500px; border:1px solid #ccc;" srcdoc="${htmlContent.replace(/"/g, '&quot;')}"></iframe>`;
      
      // 儲存於全域變數中,以便下載時使用
      window.generatedCalendarHTML = htmlContent;
      
      // 顯示下載按鈕
      document.getElementById('downloadBtn').style.display = 'inline-block';
    }

    // 將生成的 HTML 作為 .doc 檔案下載
    function downloadCalendar() {
      if (!window.generatedCalendarHTML) {
        alert("請先生成行事曆!");
        return;
      }
      // 利用 Blob 與 a 元素建立下載連結
      const blob = new Blob([window.generatedCalendarHTML], {type: "text/html"});
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      // 設定檔案名稱
      a.download = "學期行事曆.doc";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      // 釋放 URL 物件
      URL.revokeObjectURL(url);
    }
  </script>
</body>
</html>

程式碼說明

  1. 介面表單
    使用 <form> 收集使用者輸入,包括行事曆標題、起始日期(建議選擇該週的「日」,方便計算)與生成的週數。

  2. 日曆生成邏輯

    • JavaScript 中 generateCalendar() 函數會依照輸入的起始日期、週數生成整個行事曆的 HTML。

    • 表格的第一欄顯示月份(這裡採用每週第一天的月份),接下來七欄分別是「日、一、二、三、四、五、六」,最後兩欄則保留供學校行事與備註。

    • CSS 中利用 colgroup 設定各欄的寬度,滿足前 8 欄佔 50%,再由第9欄佔 75% 與第10欄佔 25%(分別為 37.5% 與 12.5%)。

  3. 下載功能
    點擊「下載行事曆」按鈕後,downloadCalendar() 會將前面生成的 HTML 內容轉成 Blob,並以 .doc 檔案格式下載。

  4. 介面美化
    使用簡單的 CSS 效果美化頁面(例如容器的陰影、圓角、按鈕的 hover 效果等),使介面整體更好看。

這份程式碼提供一個基礎範例,你可以依照需求再進一步調整細節(例如各欄位進一步格式化、處理週跨月份的情形等等)。希望這能滿足你的需求!

Prompt:

1.生成的行事曆最左方加上一欄"週次",會呈現出數字的週次 2.月份的欄位,同月的單元格合併成一格來呈現。 3.週次及星期幾的欄位,文字大小設為10PX,表格寬度改為佔用全寬的三分之一就好, 剩下的三分之二寬度,學校行事佔4分之3,備註佔4分之1。

Response:

推理花了 1m 34s

下面提供一個更新後的完整 HTML 程式碼,除了原本的功能外,根據你的需求做了以下調整:

  1. 增加「週次」欄位:最左邊新增一欄,顯示每週的編號。

  2. 月份欄位合併:若連續多行顯示同一月份,將月份欄位使用 rowspan 合併成一格。

  3. 調整欄位比例與字體大小

    • 「週次」以及「星期(日、一、二、三、四、五、六)」欄位(共8欄)的文字設定為 10px

    • 整個表格分成左右兩大區塊:

      • 左側(包含「週次」、「月份」及「日~六」共 9 欄)寬度設定為全寬的三分之一

      • 右側(「學校行事」與「備註」)佔剩下的三分之二,其中「學校行事」佔 4/3(即 75%)、「備註」佔 1/4(即25%)

以下程式碼將這些需求整合在一起,直接存成 .html 檔後於瀏覽器執行即可預覽與下載產生的行事曆。


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    .calendar-table {
      width: 100%;
      border-collapse: collapse;
      margin-top: 20px;
    }
    .calendar-table th, .calendar-table td {
      border: 1px solid #ccc;
      padding: 6px;
      text-align: center;
    }
    /* 設定週次及星期幾欄位文字大小 10px */
    .small-text {
      font-size: 10px;
    }
    /* 設定第2欄(月份)背景不另外設定,若有需要可調整 */
    /* 設定淡灰色背景,如原本第二與第八欄(由於現在欄位順序有變,星期的日與六欄改成第?欄) */
    /* 本範例僅針對原先設定的淡灰色,這裡採用星期「日」與「六」 */
    .gray-bg {
      background-color: #f0f0f0;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(請選擇該週的「日」):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
    
    <div id="calendarContainer"></div>
    <button id="downloadBtn" style="display: none;" onclick="downloadCalendar()">下載行事曆</button>
  </div>
  
  <script>
    // 星期名稱
    const weekDays = ['日','一','二','三','四','五','六'];

    // 根據起始日期與週數生成行事曆,包含週次、月份合併、日期
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      const startDate = new Date(startDateStr);
      let rowsData = [];
      let currentDate = new Date(startDate);
      
      // 產生每週資料 (週次, 月份, 7天日期)
      for (let i = 0; i < weeksCount; i++) {
        let weekData = {
          week: i + 1,
          month: currentDate.getMonth() + 1,
          days: []
        };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }
      
      // 開始組裝日曆 HTML,採用 colgroup 設定欄寬:
      // 左側區塊:共 9 欄(週次、月份、7個星期)佔 33.33%(各欄平均約3.7%)
      // 右側區塊:學校行事佔 66.67%*75% = 50%,備註佔 16.67%
      let htmlContent = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body { font-family: "Microsoft JhengHei", sans-serif; margin:20px; }
    h1 { text-align: center; }
    table { width: 100%; border-collapse: collapse; }
    th, td { border: 1px solid #666; padding: 6px; text-align: center; }
    /* 左側區塊:週次及星期欄位文字大小 10px */
    .small-text { font-size: 10px; }
    /* 淡灰色背景,僅針對星期「日」與「六」 */
    .gray-bg { background-color: #f0f0f0; }
  </style>
</head>
<body>
  <h1>${title}</h1>
  <table>
    <colgroup>
      <!-- 左側 9 欄均分 33.33% -->
      <col style="width:3.7%;">
      <col style="width:3.7%;">
      <col style="width:3.7%;">
      <col style="width:3.7%;">
      <col style="width:3.7%;">
      <col style="width:3.7%;">
      <col style="width:3.7%;">
      <col style="width:3.7%;">
      <col style="width:3.7%;">
      <!-- 右側兩欄 -->
      <col style="width:50%;">
      <col style="width:16.67%;">
    </colgroup>
    <thead>
      <tr>
        <th class="small-text">週次</th>
        <th>月份</th>
        ${weekDays.map(day => {
          // 為「日」與「六」設定淡灰色背景
          if(day === "日" || day === "六"){
            return `<th class="small-text gray-bg">${day}</th>`;
          } else {
            return `<th class="small-text">${day}</th>`;
          }
        }).join('')}
        <th>學校行事</th>
        <th>備註</th>
      </tr>
    </thead>
    <tbody>
`;

      // 處理月份合併:使用一個旗標陣列記錄哪些列已顯示過月份
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        htmlContent += `<tr>`;
        // 週次欄
        htmlContent += `<td class="small-text">${rowsData[i].week}</td>`;

        // 月份欄:只有該月份第一筆才輸出,並計算 rowspan
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          htmlContent += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        
        // 星期(7天)欄位:為「日」與「六」加上淡灰色背景與 10px 字體
        for (let d = 0; d < 7; d++) {
          let tdClass = "small-text";
          if(d === 0 || d === 6) { // 日與六
            tdClass += " gray-bg";
          }
          htmlContent += `<td class="${tdClass}">${rowsData[i].days[d]}</td>`;
        }
        
        // 右側兩欄:學校行事與備註,預設空白
        htmlContent += `<td></td><td></td>`;
        htmlContent += `</tr>`;
      }
      
      htmlContent += `
    </tbody>
  </table>
</body>
</html>
`;

      // 將生成的日曆 HTML 置於頁面上(利用 iframe 呈現)
      document.getElementById('calendarContainer').innerHTML =
        `<h2>${title}</h2><iframe style="width:100%; height:500px; border:1px solid #ccc;" srcdoc="${htmlContent.replace(/"/g, '&quot;')}"></iframe>`;
      
      // 儲存全域變數,供下載使用
      window.generatedCalendarHTML = htmlContent;
      
      // 顯示下載按鈕
      document.getElementById('downloadBtn').style.display = 'inline-block';
    }

    // 下載生成的 HTML (以 .doc 檔案副檔名)
    function downloadCalendar() {
      if (!window.generatedCalendarHTML) {
        alert("請先生成行事曆!");
        return;
      }
      const blob = new Blob([window.generatedCalendarHTML], {type: "text/html"});
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "學期行事曆.doc";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }
  </script>
</body>
</html>

程式碼重點說明

  • 資料結構
    利用 JavaScript 先建立一個 rowsData 陣列,每筆記錄包含該週的編號(週次)、該週的月份(用於合併欄位)與7天的日期。

  • 月份合併
    利用 skipMonth 陣列記錄同月連續列是否已輸出月份欄,若是該筆為同月的第一個,計算接下來連續相同月份的列數作為 rowspan。

  • 欄位寬度配置
    使用 <colgroup> 將表格分為兩個區塊:

    • 左側共 9 欄(包含「週次」、「月份」及 7 個星期)的總寬度設為 33.33%

    • 右側兩欄分別設定為 50% 與 16.67%(滿足 75%/25% 的比例)

  • 字體與背景
    利用 CSS 類別 small-text 將「週次」以及「星期」欄位字體設為 10px;同時對星期「日」與「六」欄位加入 gray-bg 類別套用淡灰背景色。

  • 下載功能
    點擊下載按鈕後,將生成的 HTML 利用 Blob 機制轉為檔案下載,檔名預設為「學期行事曆.doc」。

這份程式碼結合你的所有需求,供你參考與進一步調整。希望能幫助你順利完成學期行事曆工具的製作!

Prompt:

1.在生成的行事曆上,使用者點選一二三四五六日單元格時,該單元格背景色會變成日及六的單元格的背景色,再點一下會回複成無背景色。 2.按下生成行事曆,在新的圖層開啟生成的行事曆,下載行事曆的按鈕也改放在這個圖層上。 3.下載的行事曆要包含單元格的淡灰色背景的設定

Response:

推理花了 1m 16s

以下提供更新後的完整 HTML 程式碼,整合了你最新提出的需求,說明如下:

  1. 單元格點選切換背景色

    • 生成行事曆的「星期」單元格(包含一、二、…、六、日)都加上 class "day-cell",並依據原本的規則:

      • 預設:若該欄位屬於「日」或「六」,就直接以內嵌 style 設定淡灰色背景(#f0f0f0);其他則沒有背景。
    • 綁定點選事件:

      • 點選後若該 cell 的 inline backgroundColor 為 #f0f0f0(瀏覽器呈現會是 rgb(240, 240, 240)),則移除 inline style;

      • 否則設定為淡灰色。

  2. 行事曆生成後以新圖層(Modal)開啟

    • 畫面下方預先準備一個隱藏的 modal 區塊,用以展示生成的行事曆內容,該圖層內含下載按鈕(以及一個關閉按鈕,可讓你關閉 modal)。
  3. 下載的行事曆檔案包含格子背景設定

    • 下載檔案採用的 HTML 內容會完整包含頁首所需的 CSS(包含設定 day-cell 的樣式)與 JavaScript(點選切換背景功能),這樣即使下載後重新開啟,預設的淡灰色與點選切換功能都能正常顯示。

請依需求儲存以下程式碼為 .html 檔後,即可直接用瀏覽器執行。


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    /* Modal overlay */
    #modalOverlay {
      display: none;
      position: fixed;
      z-index: 1000;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background: rgba(0, 0, 0, 0.8);
      overflow: auto;
      padding: 20px;
    }
    #modalContent {
      background: #fff;
      margin: 40px auto;
      padding: 20px;
      border-radius: 8px;
      max-width: 90%;
    }
    /* 於行事曆中 left block(週次、月份、星期欄)佔 1/3,全表格寬度 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    /* 左側區塊中的欄位文字設為 10px */
    .small-text {
      font-size: 10px;
    }
    /* day-cell 用來切換背景 */
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(請選擇該週的「日」):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
  </div>

  <!-- Modal overlay 用以顯示生成的行事曆與下載按鈕 -->
  <div id="modalOverlay">
    <div id="modalContent">
      <!-- 生成的行事曆內容會放在這裡 -->
      <div id="calendarDisplay"></div>
      <div style="text-align: center; margin-top: 15px;">
        <button onclick="downloadCalendar()">下載行事曆</button>
        <button style="background-color: #d33;" onclick="closeModal()">關閉</button>
      </div>
    </div>
  </div>

  <script>
    // 星期名稱(依順序,第一個為「日」)
    const weekDays = ['日','一','二','三','四','五','六'];

    // 當前產生的完整 HTML 存檔 (供下載使用)
    let fullCalendarHTML = "";

    // 點選後切換背景色:若目前為 #f0f0f0(即 rgb(240,240,240)),則移除;否則設為 #f0f0f0。
    function toggleCellBackground(event) {
      const cell = event.currentTarget;
      // 取得目前設定的背景色(瀏覽器通常回傳 rgb 格式)
      const currentColor = cell.style.backgroundColor;
      if (currentColor === "rgb(240, 240, 240)") {
        cell.style.backgroundColor = "";
      } else {
        cell.style.backgroundColor = "#f0f0f0";
      }
    }

    // 生成行事曆:處理資料、組成 HTML(同時產生供 Modal 顯示以及下載的完整檔案)
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      const startDate = new Date(startDateStr);
      let rowsData = [];
      let currentDate = new Date(startDate);

      // 依週產生資料:紀錄週次、該週的月份(用於合併同月)與 7 天的日期
      for (let i = 0; i < weeksCount; i++) {
        let weekData = {
          week: i + 1,
          month: currentDate.getMonth() + 1,
          days: []
        };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }

      // 組成下載用的完整 HTML(包含 DOCTYPE、head、style、script)
      fullCalendarHTML = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body { font-family: "Microsoft JhengHei", sans-serif; margin:20px; }
    h1 { text-align: center; }
    table { width: 100%; border-collapse: collapse; }
    th, td { border: 1px solid #666; padding: 6px; text-align: center; }
    .small-text { font-size: 10px; }
    .day-cell { cursor: pointer; }
  </style>
</head>
<body>
  <h1>${title}</h1>
  <table>
    <colgroup>
      <!-- 左側 9 欄:週次、月份、7個星期,每欄 33.33%/9 約 3.70% -->
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <!-- 右側 2 欄:學校行事 (75% of 2/3=50%) 與 備註 (25% of 2/3=16.67%) -->
      <col style="width:50%;">
      <col style="width:16.67%;">
    </colgroup>
    <thead>
      <tr>
        <th class="small-text">週次</th>
        <th>月份</th>
        ${weekDays.map(day => `<th class="small-text">${day}</th>`).join('')}
        <th>學校行事</th>
        <th>備註</th>
      </tr>
    </thead>
    <tbody>
`;

      // 為處理同月合併,使用旗標陣列記錄哪些列已經產生過月份儲存格
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        fullCalendarHTML += `<tr>`;
        // 週次欄
        fullCalendarHTML += `<td class="small-text">${rowsData[i].week}</td>`;

        // 月份欄:僅在該月份第一筆產出,並計算 rowspan
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          fullCalendarHTML += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        
        // 星期欄(7 天):點選後切換背景
        for (let d = 0; d < 7; d++) {
          // 若該欄位為「日」(d==0)或「六」(d==6),預設內嵌 style 設定淡灰色背景
          if(d === 0 || d === 6) {
            fullCalendarHTML += `<td class="day-cell small-text" data-default="#f0f0f0" style="background-color: #f0f0f0;">${rowsData[i].days[d]}</td>`;
          } else {
            fullCalendarHTML += `<td class="day-cell small-text" data-default="#f0f0f0">${rowsData[i].days[d]}</td>`;
          }
        }
        
        // 右側兩欄:學校行事與備註(預設空白)
        fullCalendarHTML += `<td></td><td></td>`;
        fullCalendarHTML += `</tr>`;
      }
      
      fullCalendarHTML += `
    </tbody>
  </table>
  <script>
    // 為所有具有 .day-cell 類別的單元格加入點選切換背景色功能
    document.querySelectorAll('.day-cell').forEach(cell => {
      cell.addEventListener('click', function() {
        if (this.style.backgroundColor === "rgb(240, 240, 240)") {
          this.style.backgroundColor = "";
        } else {
          this.style.backgroundColor = "#f0f0f0";
        }
      });
    });
  <\/script>
</body>
</html>
`;

      // 組成供 Modal 顯示的內容(這裡只顯示行事曆的 table 區塊)
      let modalHTML = `
<h2>${title}</h2>
${fullCalendarHTML.substring(fullCalendarHTML.indexOf('<table'), fullCalendarHTML.indexOf('</html>'))}
<script>
  // 為 Modal 內的 day-cell 加入點選事件 (不影響下載檔案內的事件)
  document.querySelectorAll('.day-cell').forEach(cell => {
    cell.addEventListener('click', toggleCellBackground);
  });
<\/script>
`;

      // 將 Modal 顯示內容放入 #calendarDisplay 區塊
      document.getElementById('calendarDisplay').innerHTML = modalHTML;
      // 顯示 Modal
      document.getElementById('modalOverlay').style.display = "block";
    }

    // 下載生成的行事曆(完整 HTML 檔案)
    function downloadCalendar() {
      if (!fullCalendarHTML) {
        alert("請先生成行事曆!");
        return;
      }
      const blob = new Blob([fullCalendarHTML], {type: "text/html"});
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "學期行事曆.doc";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }

    // 關閉 Modal
    function closeModal() {
      document.getElementById('modalOverlay').style.display = "none";
    }

    // 為 Modal 內的 day-cell 設定點選事件(切換背景色)
    document.addEventListener('click', function(e) {
      if(e.target && e.target.classList.contains('day-cell')){
        toggleCellBackground(e);
      }
    });
  </script>
</body>
</html>

重點說明

  • 單元格互動
    每個日期單元格皆加入 class="day-cell",若為「日」或「六」則預設 inline style 背景色設定為 #f0f0f0;點選時會利用 JavaScript 檢查目前背景色,進而在「無背景」與「淡灰色」間切換。

  • Modal 彈出圖層
    當點選「生成行事曆」後,利用隱藏的 #modalOverlay 區塊顯示生成的行事曆及下載/關閉按鈕。Modal 內容中也加入了對單元格點選事件的綁定,確保在彈出圖層內可執行切換功能。

  • 下載檔案完整性
    下載的行事曆檔案(副檔名 .doc)採用完整的 HTML 格式,包含 head 區段的 CSS 設定(確保各單元格背景色也能顯示),以及點選切換背景的 JavaScript。

這份程式碼結合了所有需求,可直接使用、修改,並依據實際需要進行微調。希望這能滿足你的需求!

Prompt:

Uncaught TypeError: Cannot read properties of undefined (reading 'backgroundColor') at toggleCellBackground (行事曆生成AI示範.html:134:39) at HTMLDocument. (行事曆生成AI示範.html:315:9)

Response:

Reasoned about background color toggle issue花了 19 秒

下面提供修正後的程式碼範例,重點改動如下:

  1. 修改了點選切換背景色的函式,改用 event.target 來取得點選的儲存格,避免因文件層級監聽器造成 currentTarget 為 undefined 的問題。

  2. 移除了最下方「document.addEventListener('click', …)」的全域點選監聽器,改由生成 HTML 時就各自加入點選事件,這樣能確保每個 .day-cell 都正確綁定。

請將下列程式碼存成 .html 檔後,直接用瀏覽器開啟即可運作。


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    /* Modal overlay */
    #modalOverlay {
      display: none;
      position: fixed;
      z-index: 1000;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background: rgba(0, 0, 0, 0.8);
      overflow: auto;
      padding: 20px;
    }
    #modalContent {
      background: #fff;
      margin: 40px auto;
      padding: 20px;
      border-radius: 8px;
      max-width: 90%;
    }
    /* 表格樣式 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    .small-text {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(請選擇該週的「日」):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
  </div>

  <!-- Modal overlay 用以顯示生成的行事曆與下載按鈕 -->
  <div id="modalOverlay">
    <div id="modalContent">
      <!-- 生成的行事曆內容會放在這裡 -->
      <div id="calendarDisplay"></div>
      <div style="text-align: center; margin-top: 15px;">
        <button onclick="downloadCalendar()">下載行事曆</button>
        <button style="background-color: #d33;" onclick="closeModal()">關閉</button>
      </div>
    </div>
  </div>

  <script>
    // 星期名稱(依順序,第一個為「日」)
    const weekDays = ['日','一','二','三','四','五','六'];

    // 全域變數,用於儲存生成的完整 HTML (供下載使用)
    let fullCalendarHTML = "";

    // 點選切換背景色
    function toggleCellBackground(event) {
      // 使用 event.target 取得點選的儲存格
      const cell = event.target;
      if (cell.style.backgroundColor === "rgb(240, 240, 240)") {
        cell.style.backgroundColor = "";
      } else {
        cell.style.backgroundColor = "#f0f0f0";
      }
    }

    // 生成行事曆,組成供 Modal 顯示與下載的完整檔案內容
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      const startDate = new Date(startDateStr);
      let rowsData = [];
      let currentDate = new Date(startDate);

      // 依週產生資料:紀錄週次、月份(用於合併儲存格)與7天日期
      for (let i = 0; i < weeksCount; i++) {
        let weekData = {
          week: i + 1,
          month: currentDate.getMonth() + 1,
          days: []
        };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }

      // 生成下載用完整 HTML (包含 head, style, script)
      fullCalendarHTML = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body { font-family: "Microsoft JhengHei", sans-serif; margin:20px; }
    h1 { text-align: center; }
    table { width: 100%; border-collapse: collapse; }
    th, td { border: 1px solid #666; padding: 6px; text-align: center; }
    .small-text { font-size: 10px; }
    .day-cell { cursor: pointer; }
  </style>
</head>
<body>
  <h1>${title}</h1>
  <table>
    <colgroup>
      <!-- 左側 9欄:週次、月份、7個星期 -->
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <!-- 右側 2欄:學校行事與備註 -->
      <col style="width:50%;">
      <col style="width:16.67%;">
    </colgroup>
    <thead>
      <tr>
        <th class="small-text">週次</th>
        <th>月份</th>
        ${weekDays.map(day => `<th class="small-text">${day}</th>`).join('')}
        <th>學校行事</th>
        <th>備註</th>
      </tr>
    </thead>
    <tbody>
`;

      // 旗標陣列記錄哪些行的月份欄位已輸出
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        fullCalendarHTML += `<tr>`;
        // 週次
        fullCalendarHTML += `<td class="small-text">${rowsData[i].week}</td>`;

        // 月份欄:僅第一筆顯示,並計算 rowspan
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          fullCalendarHTML += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        
        // 產生7天日期,加入點選事件 (日與六預設淡灰色)
        for (let d = 0; d < 7; d++) {
          if(d === 0 || d === 6) {
            fullCalendarHTML += `<td class="day-cell small-text" style="background-color: #f0f0f0;">${rowsData[i].days[d]}</td>`;
          } else {
            fullCalendarHTML += `<td class="day-cell small-text">${rowsData[i].days[d]}</td>`;
          }
        }
        
        // 右側兩欄:學校行事與備註 (預設空白)
        fullCalendarHTML += `<td></td><td></td>`;
        fullCalendarHTML += `</tr>`;
      }
      
      fullCalendarHTML += `
    </tbody>
  </table>
  <script>
    // 為所有 day-cell 加入點選事件,點選後背景色在無與淡灰之間切換
    document.querySelectorAll('.day-cell').forEach(cell => {
      cell.addEventListener('click', toggleCellBackground);
    });
  <\/script>
</body>
</html>
`;

      // 組成供 Modal 顯示的部分,這裡只擷取 <table> ... </table> 區塊
      const tableStart = fullCalendarHTML.indexOf('<table');
      const tableEnd   = fullCalendarHTML.indexOf('</table>') + 8; // 8 為 '</table>'.length
      let modalHTML = `<h2>${title}</h2>`;
      modalHTML += fullCalendarHTML.substring(tableStart, tableEnd);
      // Modal 內亦需啟用切換事件,因此在 Modal 內加入 script
      modalHTML += `
<script>
  document.querySelectorAll('.day-cell').forEach(cell => {
    cell.addEventListener('click', toggleCellBackground);
  });
<\/script>
`;
      // 放入 Modal 內容中
      document.getElementById('calendarDisplay').innerHTML = modalHTML;
      // 顯示 Modal
      document.getElementById('modalOverlay').style.display = "block";
    }

    // 下載生成的行事曆 (完整 HTML 檔案)
    function downloadCalendar() {
      if (!fullCalendarHTML) {
        alert("請先生成行事曆!");
        return;
      }
      const blob = new Blob([fullCalendarHTML], {type: "text/html"});
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "學期行事曆.doc";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }

    // 關閉 Modal
    function closeModal() {
      document.getElementById('modalOverlay').style.display = "none";
    }
  </script>
</body>
</html>

說明

  • 切換背景色功能
    在函式 toggleCellBackground 中改用 event.target(即被點選的那個儲存格)來讀取或設定 style.backgroundColor,這樣就不會因為 event.currentTarget 指向文件而導致 undefined 的錯誤。

  • 各儲存格事件綁定
    在生成完整 HTML 時及 Modal 顯示時,對每個擁有 class "day-cell" 的儲存格皆使用 addEventListener 綁定 toggleCellBackground。

這份修正後的程式碼應該能解決 Uncaught TypeError 的錯誤,請試試看並依需求作進一步調整!

Prompt:

點了日一二三四五六的欄位中的單元格,沒有出現切換背景色的效果

Response:

推理花了 17 秒

以下提供修正後的完整範例,調整重點包括:

  1. 事件綁定
    由於將含有 <script> 的內容以 innerHTML 插入時不會自動執行其中的 JavaScript,因此改在將 Modal 區塊注入後,利用程式碼一次性對 Modal 區塊內所有 .day-cell 元素進行事件綁定。

  2. 背景色切換判斷
    仍採用點選後讀取元素的 inline backgroundColor,如果背景色為淡灰色(rgb(240, 240, 240))則清除,否則設定為淡灰色。

請試試下列程式碼:


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    /* Modal overlay */
    #modalOverlay {
      display: none;
      position: fixed;
      z-index: 1000;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background: rgba(0, 0, 0, 0.8);
      overflow: auto;
      padding: 20px;
    }
    #modalContent {
      background: #fff;
      margin: 40px auto;
      padding: 20px;
      border-radius: 8px;
      max-width: 90%;
    }
    /* 表格樣式 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    .small-text {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(請選擇該週的「日」):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
  </div>

  <!-- Modal overlay 用以顯示生成的行事曆與下載按鈕 -->
  <div id="modalOverlay">
    <div id="modalContent">
      <!-- 生成的行事曆內容會放在這裡 -->
      <div id="calendarDisplay"></div>
      <div style="text-align: center; margin-top: 15px;">
        <button onclick="downloadCalendar()">下載行事曆</button>
        <button style="background-color: #d33;" onclick="closeModal()">關閉</button>
      </div>
    </div>
  </div>

  <script>
    // 星期名稱(依順序,第一個為「日」)
    const weekDays = ['日','一','二','三','四','五','六'];

    // 全域變數,用於儲存生成的完整 HTML (供下載使用)
    let fullCalendarHTML = "";

    // 點選切換背景色
    function toggleCellBackground(event) {
      const cell = event.target;
      // 使用 getComputedStyle 取得最終背景色的 rgb 表示
      const currentBg = window.getComputedStyle(cell).backgroundColor;
      // 如果目前是淡灰色 (rgb(240, 240, 240)) 則清除,否則設為淡灰色
      if (currentBg === "rgb(240, 240, 240)") {
        cell.style.backgroundColor = "";
      } else {
        cell.style.backgroundColor = "#f0f0f0";
      }
    }

    // 生成行事曆,組成供 Modal 顯示與下載的完整檔案內容
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      const startDate = new Date(startDateStr);
      let rowsData = [];
      let currentDate = new Date(startDate);

      // 每週資料:包含週次、月份(用於合併儲存格)以及 7 天日期
      for (let i = 0; i < weeksCount; i++) {
        let weekData = {
          week: i + 1,
          month: currentDate.getMonth() + 1,
          days: []
        };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }

      // 生成下載用完整 HTML (包含 head, style, script)
      fullCalendarHTML = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body { font-family: "Microsoft JhengHei", sans-serif; margin:20px; }
    h1 { text-align: center; }
    table { width: 100%; border-collapse: collapse; }
    th, td { border: 1px solid #666; padding: 6px; text-align: center; }
    .small-text { font-size: 10px; }
    .day-cell { cursor: pointer; }
  </style>
</head>
<body>
  <h1>${title}</h1>
  <table>
    <colgroup>
      <!-- 左側 9 欄:週次、月份、7個星期 -->
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <col style="width:3.70%;">
      <!-- 右側 2 欄:學校行事與備註 -->
      <col style="width:50%;">
      <col style="width:16.67%;">
    </colgroup>
    <thead>
      <tr>
        <th class="small-text">週次</th>
        <th>月份</th>
        ${weekDays.map(day => `<th class="small-text">${day}</th>`).join('')}
        <th>學校行事</th>
        <th>備註</th>
      </tr>
    </thead>
    <tbody>
`;

      // 旗標陣列記錄哪些列已輸出月份儲存格(用於合併)
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        fullCalendarHTML += `<tr>`;
        // 週次
        fullCalendarHTML += `<td class="small-text">${rowsData[i].week}</td>`;
        // 月份儲存格:僅第一筆顯示,並計算 rowspan
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          fullCalendarHTML += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        // 產生 7 天欄位,若為日(d==0)或六(d==6)則預設淡灰背景
        for (let d = 0; d < 7; d++) {
          if(d === 0 || d === 6) {
            fullCalendarHTML += `<td class="day-cell small-text" style="background-color: #f0f0f0;">${rowsData[i].days[d]}</td>`;
          } else {
            fullCalendarHTML += `<td class="day-cell small-text">${rowsData[i].days[d]}</td>`;
          }
        }
        // 右側兩欄
        fullCalendarHTML += `<td></td><td></td>`;
        fullCalendarHTML += `</tr>`;
      }
      
      fullCalendarHTML += `
    </tbody>
  </table>
  <script>
    // 為完整文件內所有 .day-cell 加入切換背景事件
    document.querySelectorAll('.day-cell').forEach(cell => {
      cell.addEventListener('click', ${toggleCellBackground.toString()});
    });
  <\/script>
</body>
</html>
`;

      // 產生用於 Modal 顯示的內容:這裡只取出 <table> ... </table> 區塊,
      // 注意:由 innerHTML 載入的 script 不會自動執行,所以需在 Modal 注入後重新綁定事件
      const tableStart = fullCalendarHTML.indexOf('<table');
      const tableEnd   = fullCalendarHTML.indexOf('</table>') + 8;
      let modalHTML = `<h2>${title}</h2>`;
      modalHTML += fullCalendarHTML.substring(tableStart, tableEnd);
      // 將 Modal 內容更新進 #calendarDisplay
      document.getElementById('calendarDisplay').innerHTML = modalHTML;

      // 於 Modal 內容更新後,對所有 day-cell 重新綁定事件
      const modalCells = document.getElementById('calendarDisplay').querySelectorAll('.day-cell');
      modalCells.forEach(cell => {
        cell.addEventListener('click', toggleCellBackground);
      });
      
      // 顯示 Modal
      document.getElementById('modalOverlay').style.display = "block";
    }

    // 下載生成的行事曆 (完整 HTML 檔案)
    function downloadCalendar() {
      if (!fullCalendarHTML) {
        alert("請先生成行事曆!");
        return;
      }
      const blob = new Blob([fullCalendarHTML], {type: "text/html"});
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "學期行事曆.doc";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }

    // 關閉 Modal
    function closeModal() {
      document.getElementById('modalOverlay').style.display = "none";
    }
  </script>
</body>
</html>

說明

  1. 在函式 toggleCellBackground 中改用 window.getComputedStyle 讀取元素最終的背景顏色,確保判斷正確。

  2. 當 Modal 內容以 innerHTML 注入後,立即使用 querySelectorAll 找出 modal 內所有 .day-cell,並對它們依次綁定 toggleCellBackground 事件。

這樣點選「日、一、二、...」的儲存格時,背景色就會在預設的淡灰 (#f0f0f0) 與無背景之間切換。請試試看此版本,應該能正常達成需求。

Prompt:

1.下載行事曆,要包含點選單元格後的背景色變化,下載的是下載當下的表格情形。 2.下載的檔名,請用輸入的標題來當檔名

Response:

推理花了 27 秒

下方提供修改後的完整 HTML 程式碼,主要做了兩個調整:

  1. 下載時以現時表格狀態為準
    在下載函式中,從 Modal 內取出目前呈現的 <table>(其內容包含所有使用者點選後產生的 inline style 變化),再以此產生完整的 HTML 內容,這樣下載後的檔案就會呈現出當下的單元格背景色狀態。

  2. 下載檔名採用使用者輸入的標題
    下載時會讀取標題輸入欄位作為檔名(例如「我的行事曆.doc」)。

請將下列程式碼存成 .html 檔後開啟測試:


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    /* Modal overlay */
    #modalOverlay {
      display: none;
      position: fixed;
      z-index: 1000;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background: rgba(0, 0, 0, 0.8);
      overflow: auto;
      padding: 20px;
    }
    #modalContent {
      background: #fff;
      margin: 40px auto;
      padding: 20px;
      border-radius: 8px;
      max-width: 90%;
    }
    /* 表格樣式 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    .small-text {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(請選擇該週的「日」):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
  </div>

  <!-- Modal overlay 用以顯示生成的行事曆與下載按鈕 -->
  <div id="modalOverlay">
    <div id="modalContent">
      <!-- 生成的行事曆內容會放在這裡 -->
      <div id="calendarDisplay"></div>
      <div style="text-align: center; margin-top: 15px;">
        <button onclick="downloadCalendar()">下載行事曆</button>
        <button style="background-color: #d33;" onclick="closeModal()">關閉</button>
      </div>
    </div>
  </div>

  <script>
    // 星期名稱(依順序,第一個為「日」)
    const weekDays = ['日','一','二','三','四','五','六'];

    // 點選後切換背景色
    function toggleCellBackground(event) {
      const cell = event.target;
      const currentBg = window.getComputedStyle(cell).backgroundColor;
      if (currentBg === "rgb(240, 240, 240)") {
        cell.style.backgroundColor = "";
      } else {
        cell.style.backgroundColor = "#f0f0f0";
      }
    }

    // 生成行事曆,並在 Modal 中顯示
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      const startDate = new Date(startDateStr);
      let rowsData = [];
      let currentDate = new Date(startDate);

      // 每週資料:包含週次、月份(用於合併儲存格)以及 7 天日期
      for (let i = 0; i < weeksCount; i++) {
        let weekData = {
          week: i + 1,
          month: currentDate.getMonth() + 1,
          days: []
        };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }

      // 組合表格 HTML 字串
      let tableHTML = `
<table>
  <colgroup>
    <!-- 左側 9 欄:週次、月份、7個星期 -->
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <!-- 右側 2 欄:學校行事與備註 -->
    <col style="width:50%;">
    <col style="width:16.67%;">
  </colgroup>
  <thead>
    <tr>
      <th class="small-text">週次</th>
      <th>月份</th>
      ${weekDays.map(day => `<th class="small-text">${day}</th>`).join('')}
      <th>學校行事</th>
      <th>備註</th>
    </tr>
  </thead>
  <tbody>
`;

      // 旗標陣列記錄哪些列已輸出月份儲存格(用於合併)
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        tableHTML += `<tr>`;
        // 週次欄
        tableHTML += `<td class="small-text">${rowsData[i].week}</td>`;
        // 月份欄:僅第一筆顯示,並計算 rowspan
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          tableHTML += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        // 產生 7 天欄位:若為日(d==0)或六(d==6)則預設淡灰色背景
        for (let d = 0; d < 7; d++) {
          if (d === 0 || d === 6) {
            tableHTML += `<td class="day-cell small-text" style="background-color: #f0f0f0;">${rowsData[i].days[d]}</td>`;
          } else {
            tableHTML += `<td class="day-cell small-text">${rowsData[i].days[d]}</td>`;
          }
        }
        // 右側兩欄:學校行事與備註
        tableHTML += `<td></td><td></td>`;
        tableHTML += `</tr>`;
      }
      
      tableHTML += `
  </tbody>
</table>
`;

      // 更新 Modal 內容
      let modalHTML = `<h2>${title}</h2>` + tableHTML;
      document.getElementById('calendarDisplay').innerHTML = modalHTML;
      
      // 於 Modal 內容更新後,綁定所有 day-cell 的點選事件
      const modalCells = document.getElementById('calendarDisplay').querySelectorAll('.day-cell');
      modalCells.forEach(cell => {
        cell.addEventListener('click', toggleCellBackground);
      });
      
      // 顯示 Modal
      document.getElementById('modalOverlay').style.display = "block";
    }

    // 下載行事曆
    // 此函式抓取目前 Modal 內呈現的表格(包含使用者點選後的 inline style)並產生成完整 HTML 文件下載,
    // 檔名使用輸入的標題作為檔名。
    function downloadCalendar() {
      // 取得使用者輸入的標題作為檔名
      const title = document.getElementById('title').value.trim() || "calendar";
      const tableEl = document.getElementById('calendarDisplay').querySelector('table');
      if (!tableEl) {
        alert('找不到表格內容!');
        return;
      }
      const downloadableHTML = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body { font-family: "Microsoft JhengHei", sans-serif; margin:20px; }
    h1 { text-align: center; }
    table { width: 100%; border-collapse: collapse; }
    th, td { border: 1px solid #666; padding: 6px; text-align: center; }
    .small-text { font-size: 10px; }
    .day-cell { cursor: pointer; }
  </style>
</head>
<body>
  <h1>${title}</h1>
  ${tableEl.outerHTML}
</body>
</html>
`;
      const blob = new Blob([downloadableHTML], { type: "text/html" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      // 檔名使用輸入的標題(例如:我的行事曆.doc)
      a.download = title + ".doc";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }

    // 關閉 Modal
    function closeModal() {
      document.getElementById('modalOverlay').style.display = "none";
    }
  </script>
</body>
</html>

說明

  • 點選狀態捕捉:
    使用者在 Modal 內點選單元格後,單元格的 inline style 會即時改變,下載時取用的是 Modal 中目前的 <table> 結構與 inline style(因此即便後續有變更也都會反映在下載的檔案中)。

  • 檔名採用標題:
    下載檔案會以輸入的標題作為檔名,例如若輸入「我的行事曆」,則下載檔案為「我的行事曆.doc」。

這樣就能符合你「下載行事曆要包含點選後背景色變化」、「檔名用輸入標題」的需求。

Prompt:

生成的行事曆前面9欄內的文字大小都設為10PX

Response:

推理花了 10 秒

以下的範例程式碼中,我們在 CSS 加入了一則選擇器規則,讓表格中前 9 欄(包含週次、月份與 7 個星期)的所有儲存格(th 與 td)文字大小都設為 10px。你可以將以下完整程式碼存成 .html 檔案後,直接用瀏覽器測試。


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    /* Modal overlay */
    #modalOverlay {
      display: none;
      position: fixed;
      z-index: 1000;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background: rgba(0, 0, 0, 0.8);
      overflow: auto;
      padding: 20px;
    }
    #modalContent {
      background: #fff;
      margin: 40px auto;
      padding: 20px;
      border-radius: 8px;
      max-width: 90%;
    }
    /* 表格樣式 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    /* 前 9 欄文字都設為 10px */
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(請選擇該週的「日」):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
  </div>

  <!-- Modal overlay 用以顯示生成的行事曆與下載按鈕 -->
  <div id="modalOverlay">
    <div id="modalContent">
      <!-- 生成的行事曆內容會放在這裡 -->
      <div id="calendarDisplay"></div>
      <div style="text-align: center; margin-top: 15px;">
        <button onclick="downloadCalendar()">下載行事曆</button>
        <button style="background-color: #d33;" onclick="closeModal()">關閉</button>
      </div>
    </div>
  </div>

  <script>
    // 星期名稱(依順序,第一個為「日」)
    const weekDays = ['日','一','二','三','四','五','六'];

    // 點選後切換背景色
    function toggleCellBackground(event) {
      const cell = event.target;
      const currentBg = window.getComputedStyle(cell).backgroundColor;
      if (currentBg === "rgb(240, 240, 240)") {
        cell.style.backgroundColor = "";
      } else {
        cell.style.backgroundColor = "#f0f0f0";
      }
    }

    // 生成行事曆,並在 Modal 中顯示
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      const startDate = new Date(startDateStr);
      let rowsData = [];
      let currentDate = new Date(startDate);

      // 每週資料:包含週次、月份(用於合併儲存格)以及 7 天日期
      for (let i = 0; i < weeksCount; i++) {
        let weekData = {
          week: i + 1,
          month: currentDate.getMonth() + 1,
          days: []
        };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }

      // 組合表格 HTML 字串
      let tableHTML = `
<table>
  <colgroup>
    <!-- 左側 9 欄:週次、月份、7 個星期 -->
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <!-- 右側 2 欄:學校行事與備註 -->
    <col style="width:50%;">
    <col style="width:16.67%;">
  </colgroup>
  <thead>
    <tr>
      <th>週次</th>
      <th>月份</th>
      ${weekDays.map(day => `<th>${day}</th>`).join('')}
      <th>學校行事</th>
      <th>備註</th>
    </tr>
  </thead>
  <tbody>
`;

      // 旗標陣列記錄哪些列已輸出月份儲存格(用於合併)
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        tableHTML += `<tr>`;
        // 週次欄
        tableHTML += `<td>${rowsData[i].week}</td>`;
        // 月份欄:僅第一筆顯示,並計算 rowspan
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          tableHTML += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        // 產生 7 天欄位;若為日(d==0)或六(d==6)則預設淡灰色背景
        for (let d = 0; d < 7; d++) {
          if (d === 0 || d === 6) {
            tableHTML += `<td class="day-cell" style="background-color: #f0f0f0;">${rowsData[i].days[d]}</td>`;
          } else {
            tableHTML += `<td class="day-cell">${rowsData[i].days[d]}</td>`;
          }
        }
        // 右側兩欄:學校行事與備註
        tableHTML += `<td></td><td></td>`;
        tableHTML += `</tr>`;
      }
      
      tableHTML += `
  </tbody>
</table>
`;

      // 更新 Modal 內容
      let modalHTML = `<h2>${title}</h2>` + tableHTML;
      document.getElementById('calendarDisplay').innerHTML = modalHTML;
      
      // Modal 內容更新後,綁定所有 day-cell 的點選事件
      const modalCells = document.getElementById('calendarDisplay').querySelectorAll('.day-cell');
      modalCells.forEach(cell => {
        cell.addEventListener('click', toggleCellBackground);
      });
      
      // 顯示 Modal
      document.getElementById('modalOverlay').style.display = "block";
    }

    // 下載行事曆
    // 此函式會取出 Modal 目前呈現的表格(包含使用者更動過的 inline style),並產生成完整 HTML 檔案下載
    // 檔名則使用使用者輸入的標題來命名
    function downloadCalendar() {
      const title = document.getElementById('title').value.trim() || "calendar";
      const tableEl = document.getElementById('calendarDisplay').querySelector('table');
      if (!tableEl) {
        alert('找不到表格內容!');
        return;
      }
      const downloadableHTML = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body { font-family: "Microsoft JhengHei", sans-serif; margin:20px; }
    h1 { text-align: center; }
    table { width: 100%; border-collapse: collapse; }
    th, td { border: 1px solid #666; padding: 6px; text-align: center; }
    /* 前 9 欄文字大小 10px */
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    .day-cell { cursor: pointer; }
  </style>
</head>
<body>
  <h1>${title}</h1>
  ${tableEl.outerHTML}
</body>
</html>
`;
      const blob = new Blob([downloadableHTML], { type: "text/html" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = title + ".doc";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }

    // 關閉 Modal
    function closeModal() {
      document.getElementById('modalOverlay').style.display = "none";
    }
  </script>
</body>
</html>

說明

  1. 前 9 欄文字大小設定:
    在 CSS 中加入了以下規則:

    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    

    此規則適用於所有位於前 9 欄的標題與儲存格,確保文字大小皆為 10px。

  2. 下載檔案完整性:
    下載功能會抓取目前 Modal 內已更新的表格內容(包含使用者點選後的背景色 inline style),並組成完整 HTML 檔案。檔名則使用使用者輸入的標題,如「我的行事曆.doc」。

這份程式碼整合了所有需求,滿足前 9 欄 10px 的文字設定,同時下載的檔案會反映當下表格狀態。

Prompt:

下載的行事曆請完全保留原來html的外觀及文字大小的設定

Response:

推理花了 25 秒

下方的範例程式碼中,我們將下載功能更新,讓下載的檔案內包含完整的 CSS 設定(包含背景、表格版型、文字大小等設定),並完整呈現與瀏覽器上所呈現的行事曆外觀一致,同時檔名會以使用者輸入的標題命名。請將下列程式碼存成 .html 檔後開啟試用:


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    /* Modal overlay */
    #modalOverlay {
      display: none;
      position: fixed;
      z-index: 1000;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background: rgba(0, 0, 0, 0.8);
      overflow: auto;
      padding: 20px;
    }
    #modalContent {
      background: #fff;
      margin: 40px auto;
      padding: 20px;
      border-radius: 8px;
      max-width: 90%;
    }
    /* 表格樣式 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    /* 前 9 欄文字都設為 10px */
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(請選擇該週的「日」):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
  </div>

  <!-- Modal overlay 用以顯示生成的行事曆與下載按鈕 -->
  <div id="modalOverlay">
    <div id="modalContent">
      <!-- 生成的行事曆內容會放在這裡 -->
      <div id="calendarDisplay"></div>
      <div style="text-align: center; margin-top: 15px;">
        <button onclick="downloadCalendar()">下載行事曆</button>
        <button style="background-color: #d33;" onclick="closeModal()">關閉</button>
      </div>
    </div>
  </div>

  <script>
    // 星期名稱(依順序,第一個為「日」)
    const weekDays = ['日','一','二','三','四','五','六'];

    // 點選後切換背景色(點選時依使用者目前的 inline 狀態做切換)
    function toggleCellBackground(event) {
      const cell = event.target;
      const currentBg = window.getComputedStyle(cell).backgroundColor;
      // 這裡以 rgb(240, 240, 240) 為淡灰色判斷
      if (currentBg === "rgb(240, 240, 240)") {
        cell.style.backgroundColor = "";
      } else {
        cell.style.backgroundColor = "#f0f0f0";
      }
    }

    // 生成行事曆,並在 Modal 中顯示
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      const startDate = new Date(startDateStr);
      let rowsData = [];
      let currentDate = new Date(startDate);

      // 每週資料:包含週次、月份(用於合併儲存格)以及 7 天日期
      for (let i = 0; i < weeksCount; i++) {
        let weekData = {
          week: i + 1,
          month: currentDate.getMonth() + 1,
          days: []
        };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }

      // 組合表格 HTML 字串
      let tableHTML = `
<table>
  <colgroup>
    <!-- 左側 9 欄:週次、月份、7 個星期 -->
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <!-- 右側 2 欄:學校行事與備註 -->
    <col style="width:50%;">
    <col style="width:16.67%;">
  </colgroup>
  <thead>
    <tr>
      <th>週次</th>
      <th>月份</th>
      ${weekDays.map(day => `<th>${day}</th>`).join('')}
      <th>學校行事</th>
      <th>備註</th>
    </tr>
  </thead>
  <tbody>
`;

      // 旗標陣列記錄哪些列已輸出月份儲存格(用於合併)
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        tableHTML += `<tr>`;
        // 週次欄
        tableHTML += `<td>${rowsData[i].week}</td>`;
        // 月份欄:僅第一筆顯示,並計算 rowspan
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          tableHTML += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        // 產生 7 天欄位:若為日(d==0)或六(d==6)則預設淡灰色背景
        for (let d = 0; d < 7; d++) {
          if (d === 0 || d === 6) {
            tableHTML += `<td class="day-cell" style="background-color: #f0f0f0;">${rowsData[i].days[d]}</td>`;
          } else {
            tableHTML += `<td class="day-cell">${rowsData[i].days[d]}</td>`;
          }
        }
        // 右側兩欄:學校行事與備註
        tableHTML += `<td></td><td></td>`;
        tableHTML += `</tr>`;
      }
      
      tableHTML += `
  </tbody>
</table>
`;

      // 更新 Modal 內容(完整呈現標題與表格)
      let modalHTML = `<h2>${title}</h2>` + tableHTML;
      document.getElementById('calendarDisplay').innerHTML = modalHTML;
      
      // Modal 內容更新後,重新綁定所有 day-cell 的點選事件
      const modalCells = document.getElementById('calendarDisplay').querySelectorAll('.day-cell');
      modalCells.forEach(cell => {
        cell.addEventListener('click', toggleCellBackground);
      });
      
      // 顯示 Modal
      document.getElementById('modalOverlay').style.display = "block";
    }

    // 下載行事曆:將目前 Modal 中呈現的表格,連同完整 CSS 都包入下載的 HTML 文件中
    function downloadCalendar() {
      const title = document.getElementById('title').value.trim() || "calendar";
      const tableEl = document.getElementById('calendarDisplay').querySelector('table');
      if (!tableEl) {
        alert('找不到表格內容!');
        return;
      }
      // 此下載 HTML 會保留原來的整體外觀及文字大小設定
      const downloadableHTML = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    /* 前 9 欄文字均設為 10px */
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>${title}</h1>
    ${tableEl.outerHTML}
  </div>
</body>
</html>
`;
      const blob = new Blob([downloadableHTML], { type: "text/html" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = title + ".doc";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }

    // 關閉 Modal
    function closeModal() {
      document.getElementById('modalOverlay').style.display = "none";
    }
  </script>
</body>
</html>

主要說明

  1. CSS 完整性
    在下載功能中,我們將整份 CSS(從 body、.container、h1 到 table 的排版與前 9 欄 10px 的文字大小設定)都嵌入下載的 HTML 頁首,確保下載的行事曆外觀與原先在瀏覽器中看到的一模一樣。

  2. 下載檔名採用標題
    下載時會讀取使用者輸入的標題,並以此作為下載檔名(例:我的行事曆.doc)。

  3. 使用者互動效果保留
    由於行事曆中的各日期儲存格若點選後其 inline style 會更新,下載的 HTML 即會反映當下狀態,保留使用者的點選背景色變化。

請試試此版本,下載後你會發現行事曆完全保留了原來 HTML 的外觀及文字大小設定。

Prompt:

在選擇起始日期時,不管選擇那一天,都會以當週的日來生成行事曆

Response:

推理花了 6 秒

下面的程式碼中,在產生行事曆時,無論你選擇哪一天作為起始日期,系統都會自動調整計算,找出該週的「日」(即星期天)作為生成行事曆的起點。這裡的關鍵在於利用 JavaScript 的 getDay() 方法取得當天的星期值,若不是 0(表示星期日),則向前調整相應的天數,以取得該週的星期日。請參考以下完整程式碼:


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    /* Modal overlay */
    #modalOverlay {
      display: none;
      position: fixed;
      z-index: 1000;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background: rgba(0, 0, 0, 0.8);
      overflow: auto;
      padding: 20px;
    }
    #modalContent {
      background: #fff;
      margin: 40px auto;
      padding: 20px;
      border-radius: 8px;
      max-width: 90%;
    }
    /* 表格樣式 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    /* 前 9 欄文字都設為 10px */
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(不論選哪一天,都會以該週的「日」產生行事曆):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
  </div>

  <!-- Modal overlay 用以顯示生成的行事曆與下載按鈕 -->
  <div id="modalOverlay">
    <div id="modalContent">
      <!-- 生成的行事曆內容會放在這裡 -->
      <div id="calendarDisplay"></div>
      <div style="text-align: center; margin-top: 15px;">
        <button onclick="downloadCalendar()">下載行事曆</button>
        <button style="background-color: #d33;" onclick="closeModal()">關閉</button>
      </div>
    </div>
  </div>

  <script>
    // 星期名稱(依順序,第一個為「日」)
    const weekDays = ['日','一','二','三','四','五','六'];

    // 點選後切換背景色
    function toggleCellBackground(event) {
      const cell = event.target;
      const currentBg = window.getComputedStyle(cell).backgroundColor;
      if (currentBg === "rgb(240, 240, 240)") {
        cell.style.backgroundColor = "";
      } else {
        cell.style.backgroundColor = "#f0f0f0";
      }
    }

    // 生成行事曆,並在 Modal 中顯示
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      // 取得輸入的日期,並調整成該週的星期日
      const inputDate = new Date(startDateStr);
      const weekDay = inputDate.getDay(); // 0 表示 Sunday
      // 若選擇的日期不是 Sunday,就往前調整到該週的 Sunday
      const startDate = new Date(inputDate.getTime());
      if (weekDay !== 0) {
        startDate.setDate(startDate.getDate() - weekDay);
      }

      let rowsData = [];
      let currentDate = new Date(startDate);

      // 每週資料:包含週次、月份(用於合併儲存格)以及 7 天日期
      for (let i = 0; i < weeksCount; i++) {
        let weekData = {
          week: i + 1,
          month: currentDate.getMonth() + 1,
          days: []
        };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }

      // 組合表格 HTML 字串
      let tableHTML = `
<table>
  <colgroup>
    <!-- 左側 9 欄:週次、月份、7 個星期 -->
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <!-- 右側 2 欄:學校行事與備註 -->
    <col style="width:50%;">
    <col style="width:16.67%;">
  </colgroup>
  <thead>
    <tr>
      <th>週次</th>
      <th>月份</th>
      ${weekDays.map(day => `<th>${day}</th>`).join('')}
      <th>學校行事</th>
      <th>備註</th>
    </tr>
  </thead>
  <tbody>
`;

      // 旗標陣列記錄哪些列已輸出月份儲存格(用於合併)
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        tableHTML += `<tr>`;
        // 週次欄
        tableHTML += `<td>${rowsData[i].week}</td>`;
        // 月份欄:僅第一筆顯示,並計算 rowspan
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          tableHTML += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        // 產生 7 天欄位:若為日(d==0)或六(d==6)則預設淡灰色背景
        for (let d = 0; d < 7; d++) {
          if (d === 0 || d === 6) {
            tableHTML += `<td class="day-cell" style="background-color: #f0f0f0;">${rowsData[i].days[d]}</td>`;
          } else {
            tableHTML += `<td class="day-cell">${rowsData[i].days[d]}</td>`;
          }
        }
        // 右側兩欄:學校行事與備註
        tableHTML += `<td></td><td></td>`;
        tableHTML += `</tr>`;
      }
      
      tableHTML += `
  </tbody>
</table>
`;

      // 更新 Modal 內容(完整呈現標題與表格)
      let modalHTML = `<h2>${title}</h2>` + tableHTML;
      document.getElementById('calendarDisplay').innerHTML = modalHTML;
      
      // Modal 內容更新後,重新綁定所有 day-cell 的點選事件
      const modalCells = document.getElementById('calendarDisplay').querySelectorAll('.day-cell');
      modalCells.forEach(cell => {
        cell.addEventListener('click', toggleCellBackground);
      });
      
      // 顯示 Modal
      document.getElementById('modalOverlay').style.display = "block";
    }

    // 下載行事曆:將目前 Modal 中呈現的表格與完整 CSS 包入下載文件中
    function downloadCalendar() {
      const title = document.getElementById('title').value.trim() || "calendar";
      const tableEl = document.getElementById('calendarDisplay').querySelector('table');
      if (!tableEl) {
        alert('找不到表格內容!');
        return;
      }
      const downloadableHTML = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    /* 前 9 欄文字均設為 10px */
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>${title}</h1>
    ${tableEl.outerHTML}
  </div>
</body>
</html>
`;
      const blob = new Blob([downloadableHTML], { type: "text/html" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = title + ".doc";
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }

    // 關閉 Modal
    function closeModal() {
      document.getElementById('modalOverlay').style.display = "none";
    }
  </script>
</body>
</html>

主要重點

  • 起始日期調整:
    在 generateCalendar() 中,先讀取使用者選取的日期,再利用 getDay() 判斷當前星期,若非 Sunday,則用 setDate() 調整日期,使其變成該週的星期日。

  • 行事曆生成與下載:
    生成的行事曆會根據調整後的起始日期產生;下載時則完整保留了原有的 CSS 設定(包括前 9 欄文字大小 10px 等樣式),確保下載後的文件外觀與原本一致。

請將此程式碼存成 .html 檔案後使用瀏覽器開啟試用,就可以看到生成的行事曆總是以該週的「日」為起始日期了。

Prompt:

謝謝

Response:

不客氣!😊
很高興能幫上忙,如果之後你還想加入其他功能(像是節日自動標記、顏色標籤、匯出 PDF 等),也都可以再找我~
祝你行事曆製作順利、天天都安排得剛剛好!📅✨

Prompt:

下載行事曆,改為下載docx

Response:

推理花了 55 秒

以下這份範例程式碼示範如何將目前行事曆內容包裝成 DOCX 格式檔案下載,其主要作法是利用
JSZip 函式庫,將一個符合 DOCX 檔格式(實際上是 Zip 檔案內含多組 XML 與 HTML 文件)的包裝內容產生出來,並藉由 altChunk 的方式把完整 HTML(包含外觀與文字大小設定)嵌入到 DOCX 中。

在此方案中,產生的 DOCX 包含下列檔案:

  • [Content_Types].xml
    定義了各個部件的 Content-Type。

  • _rels/.rels
    DOCX 的主要關係檔,指定主要文件的位置。

  • word/document.xml
    DOCX 的主要文件,其內利用 <w:altChunk> 元素來引用外部 HTML。

  • word/_rels/document.xml.rels
    定義了 document.xml 與 altChunk 的關係,指定 altChunk 所在的 HTML 路徑。

  • html/document.html
    實際上存放行事曆 HTML 的文件,此文件的內容即為目前呈現的行事曆(包含使用者的點選變化與 CSS 外觀設定)。

注意:使用 altChunk 嵌入 HTML 的方式,Microsoft Word (2013 以上版本) 均可正確讀取。如果您使用舊版 Office,可能會略有差異。

以下完整程式碼中,下載功能已改為使用 JSZip 產生 DOCX 文件(並用使用者輸入的標題作為檔名、副檔名為 .docx),您只需將此檔案儲存為 .html,然後以瀏覽器開啟即可試用。


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <!-- 引入 JSZip 函式庫 -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    /* Modal overlay */
    #modalOverlay {
      display: none;
      position: fixed;
      z-index: 1000;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background: rgba(0, 0, 0, 0.8);
      overflow: auto;
      padding: 20px;
    }
    #modalContent {
      background: #fff;
      margin: 40px auto;
      padding: 20px;
      border-radius: 8px;
      max-width: 90%;
    }
    /* 表格樣式 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    /* 前 9 欄文字均設為 10px */
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(不論選哪一天,都會以該週的「日」產生行事曆):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
  </div>

  <!-- Modal overlay 用以顯示生成的行事曆與下載按鈕 -->
  <div id="modalOverlay">
    <div id="modalContent">
      <!-- 生成的行事曆內容會放在這裡 -->
      <div id="calendarDisplay"></div>
      <div style="text-align: center; margin-top: 15px;">
        <button onclick="downloadCalendar()">下載行事曆 (DOCX)</button>
        <button style="background-color: #d33;" onclick="closeModal()">關閉</button>
      </div>
    </div>
  </div>

  <script>
    // 星期名稱(依順序,第一個為「日」)
    const weekDays = ['日','一','二','三','四','五','六'];

    // 點選後切換背景色
    function toggleCellBackground(event) {
      const cell = event.target;
      const currentBg = window.getComputedStyle(cell).backgroundColor;
      if (currentBg === "rgb(240, 240, 240)") {
        cell.style.backgroundColor = "";
      } else {
        cell.style.backgroundColor = "#f0f0f0";
      }
    }

    // 生成行事曆,並在 Modal 中顯示
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      // 取得輸入的日期,並調整成該週的星期日
      const inputDate = new Date(startDateStr);
      const weekDay = inputDate.getDay(); // 0 表示 Sunday
      const startDate = new Date(inputDate.getTime());
      if (weekDay !== 0) {
        startDate.setDate(startDate.getDate() - weekDay);
      }

      let rowsData = [];
      let currentDate = new Date(startDate);

      // 每週資料:包含週次、月份(用於合併儲存格)以及 7 天日期
      for (let i = 0; i < weeksCount; i++) {
        let weekData = {
          week: i + 1,
          month: currentDate.getMonth() + 1,
          days: []
        };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }

      // 組合表格 HTML 字串
      let tableHTML = `
<table>
  <colgroup>
    <!-- 左側 9 欄:週次、月份、7 個星期 -->
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <!-- 右側 2 欄:學校行事與備註 -->
    <col style="width:50%;">
    <col style="width:16.67%;">
  </colgroup>
  <thead>
    <tr>
      <th>週次</th>
      <th>月份</th>
      ${weekDays.map(day => `<th>${day}</th>`).join('')}
      <th>學校行事</th>
      <th>備註</th>
    </tr>
  </thead>
  <tbody>
`;

      // 旗標陣列記錄哪些列已輸出月份儲存格(用於合併)
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        tableHTML += `<tr>`;
        // 週次欄
        tableHTML += `<td>${rowsData[i].week}</td>`;
        // 月份欄:僅第一筆顯示,並計算 rowspan
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          tableHTML += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        // 產生 7 天欄位;若為日(d==0)或六(d==6)則預設淡灰色背景
        for (let d = 0; d < 7; d++) {
          if (d === 0 || d === 6) {
            tableHTML += `<td class="day-cell" style="background-color: #f0f0f0;">${rowsData[i].days[d]}</td>`;
          } else {
            tableHTML += `<td class="day-cell">${rowsData[i].days[d]}</td>`;
          }
        }
        // 右側兩欄:學校行事與備註
        tableHTML += `<td></td><td></td>`;
        tableHTML += `</tr>`;
      }
      
      tableHTML += `
  </tbody>
</table>
`;

      // 更新 Modal 內容(完整呈現標題與表格)
      let modalHTML = `<h2>${title}</h2>` + tableHTML;
      document.getElementById('calendarDisplay').innerHTML = modalHTML;
      
      // Modal 內容更新後,重新綁定所有 day-cell 的點選事件
      const modalCells = document.getElementById('calendarDisplay').querySelectorAll('.day-cell');
      modalCells.forEach(cell => {
        cell.addEventListener('click', toggleCellBackground);
      });
      
      // 顯示 Modal
      document.getElementById('modalOverlay').style.display = "block";
    }

    // 下載行事曆為 DOCX
    function downloadCalendar() {
      const title = document.getElementById('title').value.trim() || "calendar";
      const tableEl = document.getElementById('calendarDisplay').querySelector('table');
      if (!tableEl) {
        alert('找不到表格內容!');
        return;
      }
      
      // 產生完整 HTML 文件內容(此內容即是我們要嵌入 DOCX 的 HTML)
      // ※ 此處的 downloadableHTML 就與之前下載 HTML 時相同
      const downloadableHTML = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>${title}</h1>
    ${tableEl.outerHTML}
  </div>
</body>
</html>
`;
      // 以下利用 JSZip 組出一個基本 DOCX 檔案,其中採用 altChunk 將 HTML 嵌入進來。
      var zip = new JSZip();

      // [Content_Types].xml
      zip.file("[Content_Types].xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
  <Default Extension="xml" ContentType="application/xml"/>
  <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
  <Override PartName="/html/document.html" ContentType="text/html"/>
</Types>`);

      // _rels/.rels
      zip.folder("_rels").file(".rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
</Relationships>`);

      // word/document.xml
      zip.folder("word").file("document.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" 
  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <w:body>
    <w:altChunk r:id="htmlChunk"/>
    <w:sectPr>
      <w:pgSz w:w="11906" w:h="16838"/>
      <w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440"/>
    </w:sectPr>
  </w:body>
</w:document>`);

      // word/_rels/document.xml.rels
      var wordRels = zip.folder("word").folder("_rels");
      wordRels.file("document.xml.rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="htmlChunk" 
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/aFChunk" 
    Target="../html/document.html"/>
</Relationships>`);

      // html/document.html
      var htmlFolder = zip.folder("html");
      htmlFolder.file("document.html", downloadableHTML);

      // 產生 zip 檔後下載,設定 MIME 為 DOCX
      zip.generateAsync({type:"blob"})
      .then(function(content) {
        var a = document.createElement("a");
        var url = URL.createObjectURL(content);
        a.href = url;
        a.download = title + ".docx";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
      });
    }

    // 關閉 Modal
    function closeModal() {
      document.getElementById('modalOverlay').style.display = "none";
    }
  </script>
</body>
</html>

說明

  1. 下載 DOCX 功能:

    • 改寫的 downloadCalendar() 函式先從頁面中抓取目前的行事曆表格內容(包含使用者變更的 inline style),並組成完整 HTML(downloadableHTML)。

    • 接著利用 JSZip 建立 DOCX 所需的各個組件,並採用 altChunk 方式(在 word/document.xml 中)將 HTML 嵌入。

    • 最後產生 Zip Blob,指定 MIME 類型下載,檔名以使用者輸入的標題並以 .docx 為副檔名。

  2. 外觀保留:
    下載的 DOCX 文件內含完整 CSS 與 HTML 內容,故能保留您在瀏覽器上所見的外觀與前 9 欄文字大小設定。

請試試此版本,下載後的檔案即可以 DOCX 格式儲存並由 Word 開啟,呈現與頁面上相同的行事曆外觀。

Prompt:

下載的docx,前9欄的寬度設為0.3公分,文字大小設為10PX,文件邊界設為左右各為1公分

Response:

思考 38 秒

以下提供更新後的完整範例程式碼,下載的 DOCX 將滿足以下要求:

  1. DOCX 內文件的左右邊界設為 1 公分(透過修改 document.xml 中的 w:left 與 w:right 屬性,使用約 567 twips 表示 1 公分)。

  2. 內部表格中前 9 欄的寬度調整為 0.3 公分(在下載用 HTML 的 style 中加入針對 col 的規則覆寫)。

  3. 表格中前 9 欄的文字大小設為 10px(原有的 CSS 規則保留)。

此範例採用 JSZip 與 altChunk 的方式產生 DOCX,請將下列程式碼儲存為 .html 檔後用瀏覽器開啟試用:


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <!-- 引入 JSZip 函式庫 -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    /* Modal overlay */
    #modalOverlay {
      display: none;
      position: fixed;
      z-index: 1000;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(0, 0, 0, 0.8);
      overflow: auto;
      padding: 20px;
    }
    #modalContent {
      background: #fff;
      margin: 40px auto;
      padding: 20px;
      border-radius: 8px;
      max-width: 90%;
    }
    /* 表格樣式 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    /* 前 9 欄文字皆設為 10px */
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(不論選哪一天,都會以該週的「日」產生行事曆):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
  </div>

  <!-- Modal 用以顯示生成的行事曆與下載按鈕 -->
  <div id="modalOverlay">
    <div id="modalContent">
      <div id="calendarDisplay"></div>
      <div style="text-align: center; margin-top: 15px;">
        <button onclick="downloadCalendar()">下載行事曆 (DOCX)</button>
        <button style="background-color: #d33;" onclick="closeModal()">關閉</button>
      </div>
    </div>
  </div>

  <script>
    // 星期名稱:從日到六
    const weekDays = ['日','一','二','三','四','五','六'];

    // 點選後切換背景色(使用者在行事曆內點選後切換為或清除淡灰背景)
    function toggleCellBackground(event) {
      const cell = event.target;
      const currentBg = window.getComputedStyle(cell).backgroundColor;
      if (currentBg === "rgb(240, 240, 240)") {
        cell.style.backgroundColor = "";
      } else {
        cell.style.backgroundColor = "#f0f0f0";
      }
    }

    // 生成行事曆,並在 Modal 中顯示
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      // 以使用者選取的日期調整為該週的星期日
      const inputDate = new Date(startDateStr);
      const weekDay = inputDate.getDay(); // 若非 Sunday (0)
      const startDate = new Date(inputDate.getTime());
      if (weekDay !== 0) {
        startDate.setDate(startDate.getDate() - weekDay);
      }

      let rowsData = [];
      let currentDate = new Date(startDate);
      // 生成每週資料:週次、該週第一天的月份(合併儲存格用)及 7 天日期
      for (let i = 0; i < weeksCount; i++) {
        let weekData = { week: i + 1, month: currentDate.getMonth() + 1, days: [] };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }

      // 組合表格 HTML 字串(含 colgroup、thead 及 tbody)
      let tableHTML = `
<table>
  <colgroup>
    <!-- 前 9 欄:週次、月份及 7 個星期,下載時第一 9 欄覆寫為 0.3cm -->
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <!-- 右側 2 欄:學校行事與備註,不變 -->
    <col style="width:50%;">
    <col style="width:16.67%;">
  </colgroup>
  <thead>
    <tr>
      <th>週次</th>
      <th>月份</th>
      ${weekDays.map(day => `<th>${day}</th>`).join('')}
      <th>學校行事</th>
      <th>備註</th>
    </tr>
  </thead>
  <tbody>
`;
      // 利用旗標記錄月份儲存格是否已產生(以便合併)
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        tableHTML += `<tr>`;
        tableHTML += `<td>${rowsData[i].week}</td>`;
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          tableHTML += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        for (let d = 0; d < 7; d++) {
          if (d === 0 || d === 6) {
            tableHTML += `<td class="day-cell" style="background-color: #f0f0f0;">${rowsData[i].days[d]}</td>`;
          } else {
            tableHTML += `<td class="day-cell">${rowsData[i].days[d]}</td>`;
          }
        }
        tableHTML += `<td></td><td></td>`;
        tableHTML += `</tr>`;
      }
      tableHTML += `
  </tbody>
</table>
`;
      // 更新 Modal 顯示內容
      let modalHTML = `<h2>${title}</h2>` + tableHTML;
      document.getElementById('calendarDisplay').innerHTML = modalHTML;
      // 綁定行事曆內所有日期單元格的點選事件
      const modalCells = document.getElementById('calendarDisplay').querySelectorAll('.day-cell');
      modalCells.forEach(cell => {
        cell.addEventListener('click', toggleCellBackground);
      });
      document.getElementById('modalOverlay').style.display = "block";
    }

    // 下載行事曆為 DOCX,並使用使用者輸入的標題作為檔名
    function downloadCalendar() {
      const title = document.getElementById('title').value.trim() || "calendar";
      const tableEl = document.getElementById('calendarDisplay').querySelector('table');
      if (!tableEl) {
        alert('找不到表格內容!');
        return;
      }
      // 產生完整 HTML,外觀與瀏覽器上相同,但下載時覆寫第一 9 欄寬度為 0.3cm 與文字大小 10px
      const downloadableHTML = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table col:nth-child(-n+9) {
      width: 0.3cm !important;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    /* 前 9 欄文字 10px */
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>${title}</h1>
    ${tableEl.outerHTML}
  </div>
</body>
</html>
`;
      // 利用 JSZip 組合 DOCX 結構,採用 altChunk 嵌入 HTML 文件內容
      var zip = new JSZip();

      // [Content_Types].xml
      zip.file("[Content_Types].xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
  <Default Extension="xml" ContentType="application/xml"/>
  <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
  <Override PartName="/html/document.html" ContentType="text/html"/>
</Types>`);

      // _rels/.rels
      zip.folder("_rels").file(".rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
</Relationships>`);

      // word/document.xml
      // 設定文件邊界左右 1 公分 (約 567 twips)
      zip.folder("word").file("document.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" 
  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <w:body>
    <w:altChunk r:id="htmlChunk"/>
    <w:sectPr>
      <w:pgSz w:w="11906" w:h="16838"/>
      <w:pgMar w:top="1440" w:right="567" w:bottom="1440" w:left="567"/>
    </w:sectPr>
  </w:body>
</w:document>`);

      // word/_rels/document.xml.rels
      var wordRels = zip.folder("word").folder("_rels");
      wordRels.file("document.xml.rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="htmlChunk" 
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/aFChunk" 
    Target="../html/document.html"/>
</Relationships>`);

      // html/document.html 存放下載用完整 HTML 文件內容
      var htmlFolder = zip.folder("html");
      htmlFolder.file("document.html", downloadableHTML);

      // 利用 JSZip 產生 Blob 並下載,檔名以使用者輸入標題、附檔名為 .docx
      zip.generateAsync({type:"blob"})
      .then(function(content) {
        var a = document.createElement("a");
        var url = URL.createObjectURL(content);
        a.href = url;
        a.download = title + ".docx";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
      });
    }

    // 關閉 Modal
    function closeModal() {
      document.getElementById('modalOverlay').style.display = "none";
    }
  </script>
</body>
</html>

主要說明

  • 文件邊界調整:
    在 word/document.xml 中,將 w:left 與 w:right 的值分別設為 "567"(約 1 公分)。

  • 前 9 欄欄寬調整:
    在下載用 HTML 中,透過 CSS 規則

    table col:nth-child(-n+9) {
      width: 0.3cm !important;
    }
    

    強制覆蓋前 9 欄的寬度。

  • 文字大小設定:
    已以 CSS 規則確保前 9 欄文字皆為 10px。

此版本下載的 DOCX 檔案,當用 Word 開啟時,會呈現與網頁上相同的行事曆外觀,同時前 9 欄寬度調為 0.3 公分,文字大小 10px,文件左右邊界均為 1 公分。

以下的程式碼範例已修改生成表格的部份,將標題顯示在表格第一列,所有欄位合併(colspan=11),標題文字設為 16px、置中,且第一列的儲存格只顯示下框線。下列範例同時修改了在 Modal 顯示及下載 DOCX(使用 altChunk 嵌入 HTML)的部分,下載的 DOCX 文件也會保留相同外觀,其前 9 欄寬度覆寫為 0.3 公分、文字大小 10px,文件左右邊界各為 1 公分。

請將下列程式碼存成 .html 檔後,以瀏覽器開啟試用:


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <!-- 引入 JSZip 函式庫 -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    /* Modal overlay */
    #modalOverlay {
      display: none;
      position: fixed;
      z-index: 1000;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background: rgba(0, 0, 0, 0.8);
      overflow: auto;
      padding: 20px;
    }
    #modalContent {
      background: #fff;
      margin: 40px auto;
      padding: 20px;
      border-radius: 8px;
      max-width: 90%;
    }
    /* 表格基本樣式 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    /* 前 9 欄文字設 10px */
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    /* 標題列樣式,置中、文字16px,只顯示下框線 */
    .table-title td {
      font-size: 16px;
      text-align: center;
      border: none;
      border-bottom: 1px solid #666;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(不論選哪一天,都會以該週的「日」產生行事曆):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
  </div>

  <!-- Modal 區塊 -->
  <div id="modalOverlay">
    <div id="modalContent">
      <div id="calendarDisplay"></div>
      <div style="text-align: center; margin-top: 15px;">
        <button onclick="downloadCalendar()">下載行事曆 (DOCX)</button>
        <button style="background-color: #d33;" onclick="closeModal()">關閉</button>
      </div>
    </div>
  </div>

  <script>
    // 星期名稱:從日到六
    const weekDays = ['日','一','二','三','四','五','六'];

    // 點選時切換背景色(點選後以 inline style 切換淡灰背景)
    function toggleCellBackground(event) {
      const cell = event.target;
      const currentBg = window.getComputedStyle(cell).backgroundColor;
      if (currentBg === "rgb(240, 240, 240)") {
        cell.style.backgroundColor = "";
      } else {
        cell.style.backgroundColor = "#f0f0f0";
      }
    }

    // 生成行事曆,並在 Modal 中顯示
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      // 以使用者選取的日期調整為該週的星期日
      const inputDate = new Date(startDateStr);
      const weekDay = inputDate.getDay();
      const startDate = new Date(inputDate.getTime());
      if (weekDay !== 0) {
        startDate.setDate(startDate.getDate() - weekDay);
      }

      let rowsData = [];
      let currentDate = new Date(startDate);
      for (let i = 0; i < weeksCount; i++) {
        let weekData = { week: i + 1, month: currentDate.getMonth() + 1, days: [] };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }

      // 組合表格 HTML 字串,插入表頭的第一列為標題行,合併所有 11 欄
      let tableHTML = `
<table>
  <colgroup>
    <!-- 前 9 欄(週次、月份、7個星期)-->
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <!-- 後 2 欄:學校行事與備註 -->
    <col style="width:50%;">
    <col style="width:16.67%;">
  </colgroup>
  <thead>
    <tr class="table-title">
      <td colspan="11">${title}</td>
    </tr>
    <tr>
      <th>週次</th>
      <th>月份</th>
      ${weekDays.map(day => `<th>${day}</th>`).join('')}
      <th>學校行事</th>
      <th>備註</th>
    </tr>
  </thead>
  <tbody>
`;
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        tableHTML += `<tr>`;
        tableHTML += `<td>${rowsData[i].week}</td>`;
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          tableHTML += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        for (let d = 0; d < 7; d++) {
          if (d === 0 || d === 6) {
            tableHTML += `<td class="day-cell" style="background-color: #f0f0f0;">${rowsData[i].days[d]}</td>`;
          } else {
            tableHTML += `<td class="day-cell">${rowsData[i].days[d]}</td>`;
          }
        }
        tableHTML += `<td></td><td></td>`;
        tableHTML += `</tr>`;
      }
      tableHTML += `
  </tbody>
</table>
`;
      // 更新 Modal 內容
      document.getElementById('calendarDisplay').innerHTML = tableHTML;
      // 綁定所有 day-cell 點選事件
      const modalCells = document.getElementById('calendarDisplay').querySelectorAll('.day-cell');
      modalCells.forEach(cell => cell.addEventListener('click', toggleCellBackground));
      document.getElementById('modalOverlay').style.display = "block";
    }

    // 下載行事曆為 DOCX(保留完整 HTML/CSS 外觀)
    function downloadCalendar() {
      const title = document.getElementById('title').value.trim() || "calendar";
      const tableEl = document.getElementById('calendarDisplay').querySelector('table');
      if (!tableEl) {
        alert('找不到表格內容!');
        return;
      }
      // 下載的 HTML 內容:內含 container、表格(其中前 9 欄以 CSS 覆寫寬度 0.3cm 及文字 10px)
      const downloadableHTML = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 { text-align: center; color: #333; }
    table { width: 100%; border-collapse: collapse; }
    table col:nth-child(-n+9) { width: 0.3cm !important; }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) { font-size: 10px; }
    .table-title td {
      font-size: 16px;
      text-align: center;
      border: none;
      border-bottom: 1px solid #666;
    }
    .day-cell { cursor: pointer; }
  </style>
</head>
<body>
  <div class="container">
    <h1>${title}</h1>
    ${tableEl.outerHTML}
  </div>
</body>
</html>
`;
      // 利用 JSZip 產生 DOCX 結構,以 altChunk 嵌入 HTML
      var zip = new JSZip();
      zip.file("[Content_Types].xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
  <Default Extension="xml" ContentType="application/xml"/>
  <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
  <Override PartName="/html/document.html" ContentType="text/html"/>
</Types>`);
      zip.folder("_rels").file(".rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" 
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" 
    Target="word/document.xml"/>
</Relationships>`);
      // word/document.xml 設定文件邊界左右 1 公分 (約 567 twips)
      zip.folder("word").file("document.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" 
  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <w:body>
    <w:altChunk r:id="htmlChunk"/>
    <w:sectPr>
      <w:pgSz w:w="11906" w:h="16838"/>
      <w:pgMar w:top="1440" w:right="567" w:bottom="1440" w:left="567"/>
    </w:sectPr>
  </w:body>
</w:document>`);
      var wordRels = zip.folder("word").folder("_rels");
      wordRels.file("document.xml.rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="htmlChunk" 
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/aFChunk" 
    Target="../html/document.html"/>
</Relationships>`);
      var htmlFolder = zip.folder("html");
      htmlFolder.file("document.html", downloadableHTML);
      zip.generateAsync({type:"blob"}).then(function(content) {
        var a = document.createElement("a");
        var url = URL.createObjectURL(content);
        a.href = url;
        a.download = title + ".docx";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
      });
    }

    function closeModal() {
      document.getElementById('modalOverlay').style.display = "none";
    }
  </script>
</body>
</html>

程式碼重點

  1. 表格標題列
    在表格的 <thead> 區段新增第一個 <tr>(class 為 table-title),此列的單一 <td> 設定 colspan 為 11(共 11 欄)並顯示使用者輸入標題。該儲存格僅顯示下邊框,文字大小 16px 且置中。

  2. 下載 DOCX 部分
    下載的 HTML 文件中,透過 CSS 覆寫前 9 欄欄寬為 0.3 公分、文字大小 10px,並保留原有外觀;DOCX 文件利用 altChunk 方式嵌入該 HTML,並在 Word 中顯示時設定左右邊界各 1 公分。

希望這份程式碼能滿足你的需求,如有其他調整再歡迎告知!

Prompt:

下載的docx,不要有最上方的標題文字了, 只保留表格內的標題文字

Response:

推理花了 4 秒

以下程式碼範例將下載 DOCX 時所嵌入的 HTML 部分修改,不再另外加入文件最上方的標題(h1),只保留表格內原有的標題列(已在表格中以 colspan 呈現的標題文字),這樣下載的 DOCX 內容就只顯示表格,不會重複出現標題。請參考下列完整程式碼:


<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>學期行事曆生成器</title>
  <!-- 引入 JSZip 函式庫 -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h1 {
      text-align: center;
      color: #333;
    }
    form {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin: 10px 0 5px;
      font-weight: bold;
      color: #555;
    }
    input[type="text"],
    input[type="date"],
    input[type="number"] {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      border: 1px solid #ccc;
      border-radius: 4px;
    }
    button {
      padding: 10px 20px;
      margin-top: 15px;
      border: none;
      border-radius: 4px;
      background-color: #4285F4;
      color: white;
      cursor: pointer;
      font-size: 16px;
    }
    button:hover {
      background-color: #3073e5;
    }
    /* Modal overlay */
    #modalOverlay {
      display: none;
      position: fixed;
      z-index: 1000;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background: rgba(0, 0, 0, 0.8);
      overflow: auto;
      padding: 20px;
    }
    #modalContent {
      background: #fff;
      margin: 40px auto;
      padding: 20px;
      border-radius: 8px;
      max-width: 90%;
    }
    /* 表格基本樣式 */
    table {
      width: 100%;
      border-collapse: collapse;
    }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    /* 前 9 欄文字設 10px */
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) {
      font-size: 10px;
    }
    /* 表格內的標題列樣式:置中、文字16px,只顯示下框線 */
    .table-title td {
      font-size: 16px;
      text-align: center;
      border: none;
      border-bottom: 1px solid #666;
    }
    .day-cell {
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>學期行事曆生成器</h1>
    <form id="calendarForm">
      <label for="title">行事曆標題:</label>
      <input type="text" id="title" placeholder="請輸入行事曆標題" required>
      
      <label for="startDate">起始日期(不論選哪一天,都會以該週的「日」產生行事曆):</label>
      <input type="date" id="startDate" required>
      
      <label for="weeks">生成週數:</label>
      <input type="number" id="weeks" min="1" placeholder="例如:16" required>
      
      <button type="button" onclick="generateCalendar()">生成行事曆</button>
    </form>
  </div>

  <!-- Modal 區塊 -->
  <div id="modalOverlay">
    <div id="modalContent">
      <div id="calendarDisplay"></div>
      <div style="text-align: center; margin-top: 15px;">
        <button onclick="downloadCalendar()">下載行事曆 (DOCX)</button>
        <button style="background-color: #d33;" onclick="closeModal()">關閉</button>
      </div>
    </div>
  </div>

  <script>
    // 星期名稱:從日到六
    const weekDays = ['日','一','二','三','四','五','六'];

    // 點選時切換背景色:切換 inline style 淡灰背景
    function toggleCellBackground(event) {
      const cell = event.target;
      const currentBg = window.getComputedStyle(cell).backgroundColor;
      if (currentBg === "rgb(240, 240, 240)") {
        cell.style.backgroundColor = "";
      } else {
        cell.style.backgroundColor = "#f0f0f0";
      }
    }

    // 生成行事曆,並在 Modal 中顯示
    function generateCalendar() {
      const title = document.getElementById('title').value.trim();
      const startDateStr = document.getElementById('startDate').value;
      const weeksCount = parseInt(document.getElementById('weeks').value, 10);

      if (!title || !startDateStr || !weeksCount) {
        alert("請完整輸入所有欄位!");
        return;
      }

      // 以使用者選取的日期調整為該週的星期日
      const inputDate = new Date(startDateStr);
      const weekDay = inputDate.getDay();
      const startDate = new Date(inputDate.getTime());
      if (weekDay !== 0) {
        startDate.setDate(startDate.getDate() - weekDay);
      }

      let rowsData = [];
      let currentDate = new Date(startDate);
      for (let i = 0; i < weeksCount; i++) {
        let weekData = { week: i + 1, month: currentDate.getMonth() + 1, days: [] };
        for (let d = 0; d < 7; d++) {
          weekData.days.push(currentDate.getDate());
          currentDate.setDate(currentDate.getDate() + 1);
        }
        rowsData.push(weekData);
      }

      // 組合表格 HTML 字串,包含表格標題列 (已以 colspan 呈現於表格內)
      let tableHTML = `
<table>
  <colgroup>
    <!-- 前 9 欄:週次、月份及 7 個星期 -->
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <col style="width:3.70%;">
    <!-- 後 2 欄:學校行事與備註 -->
    <col style="width:50%;">
    <col style="width:16.67%;">
  </colgroup>
  <thead>
    <tr class="table-title">
      <td colspan="11">${title}</td>
    </tr>
    <tr>
      <th>週次</th>
      <th>月份</th>
      ${weekDays.map(day => `<th>${day}</th>`).join('')}
      <th>學校行事</th>
      <th>備註</th>
    </tr>
  </thead>
  <tbody>
`;
      const skipMonth = Array(rowsData.length).fill(false);
      for (let i = 0; i < rowsData.length; i++) {
        tableHTML += `<tr>`;
        tableHTML += `<td>${rowsData[i].week}</td>`;
        if (!skipMonth[i]) {
          let rowspan = 1;
          for (let j = i + 1; j < rowsData.length; j++) {
            if (rowsData[j].month === rowsData[i].month) {
              rowspan++;
              skipMonth[j] = true;
            } else {
              break;
            }
          }
          tableHTML += `<td rowspan="${rowspan}">${rowsData[i].month}月</td>`;
        }
        for (let d = 0; d < 7; d++) {
          if (d === 0 || d === 6) {
            tableHTML += `<td class="day-cell" style="background-color: #f0f0f0;">${rowsData[i].days[d]}</td>`;
          } else {
            tableHTML += `<td class="day-cell">${rowsData[i].days[d]}</td>`;
          }
        }
        tableHTML += `<td></td><td></td>`;
        tableHTML += `</tr>`;
      }
      tableHTML += `
  </tbody>
</table>
`;
      // 更新 Modal 內容
      document.getElementById('calendarDisplay').innerHTML = tableHTML;
      // 綁定所有日期儲存格的點選事件
      const modalCells = document.getElementById('calendarDisplay').querySelectorAll('.day-cell');
      modalCells.forEach(cell => cell.addEventListener('click', toggleCellBackground));
      document.getElementById('modalOverlay').style.display = "block";
    }

    // 下載行事曆為 DOCX(下載的 HTML 不再包含文件最上方的 <h1> 標題,只保留表格)
    function downloadCalendar() {
      const title = document.getElementById('title').value.trim() || "calendar";
      const tableEl = document.getElementById('calendarDisplay').querySelector('table');
      if (!tableEl) {
        alert('找不到表格內容!');
        return;
      }
      // 下載用 HTML:僅包含 container 內部的表格(表格中已包含標題列)
      const downloadableHTML = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>${title}</title>
  <style>
    body {
      font-family: "Microsoft JhengHei", sans-serif;
      background-color: #f7f7f7;
      margin: 20px;
      padding: 0;
    }
    .container {
      max-width: 1000px;
      margin: auto;
      background: #fff;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    /* 表格樣式:前 9 欄覆寫寬度 0.3cm、文字 10px */
    table { width: 100%; border-collapse: collapse; }
    table col:nth-child(-n+9) { width: 0.3cm !important; }
    table th, table td {
      border: 1px solid #666;
      text-align: center;
      padding: 6px;
    }
    table th:nth-child(-n+9),
    table td:nth-child(-n+9) { font-size: 10px; }
    .table-title td {
      font-size: 16px;
      text-align: center;
      border: none;
      border-bottom: 1px solid #666;
    }
    .day-cell { cursor: pointer; }
  </style>
</head>
<body>
  <div class="container">
    ${tableEl.outerHTML}
  </div>
</body>
</html>
`;
      // 利用 JSZip 建立 DOCX 結構,內含 altChunk 嵌入上述 HTML
      var zip = new JSZip();
      zip.file("[Content_Types].xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
  <Default Extension="xml" ContentType="application/xml"/>
  <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
  <Override PartName="/html/document.html" ContentType="text/html"/>
</Types>`);
      zip.folder("_rels").file(".rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
</Relationships>`);
      // 在 document.xml 中設定文件左右邊界為 1 公分 (約 567 twips)
      zip.folder("word").file("document.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" 
  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <w:body>
    <w:altChunk r:id="htmlChunk"/>
    <w:sectPr>
      <w:pgSz w:w="11906" w:h="16838"/>
      <w:pgMar w:top="1440" w:right="567" w:bottom="1440" w:left="567"/>
    </w:sectPr>
  </w:body>
</w:document>`);
      var wordRels = zip.folder("word").folder("_rels");
      wordRels.file("document.xml.rels", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="htmlChunk" 
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/aFChunk" 
    Target="../html/document.html"/>
</Relationships>`);
      var htmlFolder = zip.folder("html");
      htmlFolder.file("document.html", downloadableHTML);
      zip.generateAsync({type:"blob"}).then(function(content) {
        var a = document.createElement("a");
        var url = URL.createObjectURL(content);
        a.href = url;
        a.download = title + ".docx";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
      });
    }

    function closeModal() {
      document.getElementById('modalOverlay').style.display = "none";
    }
  </script>
</body>
</html>

說明

  • 表格標題列
    在表格中已以第一個 <tr>(class="table-title")顯示使用者輸入的標題,並以 colspan=11 合併整行。下載的 HTML 僅保留此表格,不另外加入最上方的 <h1> 標題。

  • 下載 DOCX 的 HTML
    下載的 HTML 部分在 <style> 中增加了規則,將前 9 欄寬度覆寫為 0.3cm 並設定文字為 10px,同時保留其餘外觀設定;文件邊界在 DOCX 的 document.xml 中設定左右均為約 1 公分(567 twips)。

  • 生成 DOCX
    利用 JSZip 將 DOCX 內部結構組合完畢,並以 altChunk 嵌入上述 HTML,再以使用者輸入標題作為檔名下載副檔名為 .docx。

以上程式碼即能達到「下載的 DOCX 不包含最上方的標題文字,只保留表格內的標題」的需求。如有任何問題或進一步需求,歡迎再提出!


Powered by ChatGPT Exporter

Made by 阿剛老師