今天是第二十三我們可以寫一個javascript結合line bot天氣管理規劃行程網頁程式管理系統,以下是我的程式碼
首先,創建一個 LINE Bot 並記下您的 Channel Access Token 和 Channel Secret。
這裡使用 OpenWeatherMap API 來獲取天氣資訊。你需要去 OpenWeatherMap 註冊並獲得 API key。
# 安裝必要的 Node.js package
npm install @line/bot-sdk axios express
const line = require('@line/bot-sdk');
const express = require('express');
const axios = require('axios');
const app = express();
const PORT = process.env.PORT || 3000;
const config = {
  channelAccessToken: 'YOUR_CHANNEL_ACCESS_TOKEN',
  channelSecret: 'YOUR_CHANNEL_SECRET',
};
// 初始化 LINE 客戶端
const client = new line.Client(config);
// OpenWeatherMap API 設置
const weatherAPIKey = 'YOUR_OPENWEATHERMAP_API_KEY';
const weatherAPIUrl = 'https://api.openweathermap.org/data/2.5/weather';
app.post('/webhook', line.middleware(config), (req, res) => {
  Promise
    .all(req.body.events.map(handleEvent))
    .then(result => res.json(result))
    .catch(err => console.log(err));
});
function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }
  // 處理天氣查詢訊息
  if (event.message.text.includes('天氣')) {
    const city = event.message.text.replace('天氣', '').trim();
    return getWeather(city)
      .then(weatherMessage => {
        return client.replyMessage(event.replyToken, {
          type: 'text',
          text: weatherMessage
        });
      })
      .catch(err => {
        console.error(err);
        return client.replyMessage(event.replyToken, {
          type: 'text',
          text: '抱歉,我無法獲取天氣資訊。'
        });
      });
  }
  // 行程管理邏輯
  if (event.message.text.includes('行程')) {
    return manageSchedule(event.message.text)
      .then(scheduleMessage => {
        return client.replyMessage(event.replyToken, {
          type: 'text',
          text: scheduleMessage
        });
      });
  }
  return Promise.resolve(null);
}
async function getWeather(city) {
  try {
    const response = await axios.get(`${weatherAPIUrl}?q=${city}&appid=${weatherAPIKey}&units=metric&lang=zh_tw`);
    const data = response.data;
    const weather = data.weather[0].description;
    const temp = data.main.temp;
    return `目前${city}的天氣是${weather},氣溫約為 ${temp}°C。`;
  } catch (error) {
    return '無法獲取天氣資料,請檢查城市名稱是否正確。';
  }
}
function manageSchedule(text) {
  // 模擬行程管理邏輯,例如根據天氣自動調整
  let scheduleMessage = '行程規劃如下:\n';
  if (text.includes('戶外')) {
    scheduleMessage += '建議根據天氣選擇適合的戶外活動。\n';
  }
  if (text.includes('室內')) {
    scheduleMessage += '已為您安排適合的室內活動。\n';
  }
  return Promise.resolve(scheduleMessage);
}
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
接著是網頁部分,提供一個簡單的介面讓用戶輸入地點來查詢天氣,並透過天氣來管理行程規劃:
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>天氣行程管理系統</title>
  <style>
    body { font-family: Arial, sans-serif; background-color: #f0f8ff; padding: 20px; }
    .container { max-width: 600px; margin: auto; text-align: center; }
    input, button { padding: 10px; margin: 5px; width: 80%; }
    #weather-result { margin-top: 20px; font-size: 1.2em; }
  </style>
</head>
<body>
  <div class="container">
    <h1>行程規劃天氣管理系統</h1>
    <p>請輸入城市來查詢天氣並安排行程:</p>
    <input type="text" id="city-input" placeholder="輸入城市名稱">
    <button onclick="getWeather()">查詢天氣</button>
    <div id="weather-result"></div>
  </div>
  <script>
    async function getWeather() {
      const city = document.getElementById('city-input').value;
      const apiKey = 'YOUR_OPENWEATHERMAP_API_KEY';
      const apiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric&lang=zh_tw`;
      try {
        const response = await fetch(apiUrl);
        const data = await response.json();
        if (data.cod === 200) {
          const weather = data.weather[0].description;
          const temp = data.main.temp;
          document.getElementById('weather-result').innerHTML = `
            ${city} 的天氣是 ${weather},氣溫 ${temp}°C。
          `;
        } else {
          document.getElementById('weather-result').innerText = '查無此城市,請確認輸入正確。';
        }
      } catch (error) {
        document.getElementById('weather-result').innerText = '無法獲取天氣資訊,請稍後再試。';
      }
    }
  </script>
</body>
</html>
確保將 Webhook URL 設置為伺服器的網址,並開啟 LINE Developer 中的 Webhook 功能,讓 Bot 可以接收到訊息。
let videos = [];
這是一個用來儲存所有影片資料的空陣列,每個影片物件包含 title 和 file 屬性。在影片上傳時,我們會將影片的資訊加入這個陣列中,並在需要的時候更新或刪除。
renderVideoListfunction renderVideoList() {
    const videoList = document.getElementById('videoList');
    videoList.innerHTML = ''; // 清空列表,避免重複渲染
    if (videos.length === 0) {
        videoList.innerHTML = '<tr><td colspan="2">目前沒有影片。</td></tr>';
        return; // 如果沒有影片,顯示 "目前沒有影片"
    }
    videos.forEach((video, index) => {
        const row = document.createElement('tr'); // 創建一個表格行
        row.innerHTML = `
            <td>${video.title}</td> 
            <td>
                <button class="btn btn-warning btn-sm" onclick="editVideo(${index})">編輯</button>
                <button class="btn btn-danger btn-sm" onclick="deleteVideo(${index})">刪除</button>
            </td>
        `;
        videoList.appendChild(row); // 將每個影片資料添加到表格中
    });
}
videoList.innerHTML = '';:每次重新渲染影片列表前,先清空 videoList 內的內容,確保列表不會重複顯示。videos 陣列為空,則顯示「目前沒有影片」的提示,並終止渲染流程。forEach 遍歷:當有影片時,遍歷 videos 陣列,對每個影片創建一個 <tr>(表格列),並動態插入影片標題與操作按鈕(編輯與刪除)。uploadFormdocument.getElementById('uploadForm').addEventListener('submit', function(event) {
    event.preventDefault(); // 阻止表單預設的提交行為(避免頁面重新載入)
    
    const title = document.getElementById('videoTitle').value; // 取得影片標題
    const file = document.getElementById('videoFile').files[0]; // 取得上傳的影片檔案
    if (!file) {
        alert('請選擇影片檔案。');
        return; // 如果沒有選擇檔案,提示並結束函數
    }
    const video = {
        title: title,
        file: file // 將影片標題和檔案保存為一個物件
    };
    videos.push(video); // 將新影片資料推入 videos 陣列中
    renderVideoList(); // 重新渲染影片列表
    this.reset(); // 重置表單內容
});
event.preventDefault():阻止表單提交的預設行為,這樣表單提交後不會刷新頁面。document.getElementById('videoTitle').value 取得影片標題。document.getElementById('videoFile').files[0] 取得選擇的影片檔案。videos 陣列。renderVideoList() 來更新 UI。this.reset():重置表單,清空所有欄位。editVideofunction editVideo(index) {
    const newTitle = prompt('請輸入新的影片標題', videos[index].title); // 使用者輸入新標題
    if (newTitle !== null && newTitle.trim() !== '') { // 確保新標題有效
        videos[index].title = newTitle; // 更新影片標題
        renderVideoList(); // 重新渲染影片列表
    }
}
prompt():彈出一個對話框,讓使用者輸入新的影片標題。初始值為當前影片的標題。null,則更新影片標題。videos 陣列中的標題後,重新渲染影片列表。deleteVideofunction deleteVideo(index) {
    if (confirm('確定要刪除此影片嗎?')) { // 彈出確認對話框
        videos.splice(index, 1); // 從陣列中刪除該影片
        renderVideoList(); // 重新渲染影片列表
    }
}
confirm():彈出確認對話框,詢問使用者是否確定刪除影片。如果使用者點擊「確認」,則繼續執行刪除操作。videos.splice(index, 1):從 videos 陣列中移除指定索引的影片。splice() 是一個用來移除陣列中元素的方法,第一個參數是起始位置,第二個參數是刪除的數量(1 表示刪除一個元素)。renderVideoList();
這行程式在頁面載入時即被執行,確保影片列表一開始就正確顯示,即使當前 videos 陣列是空的也能顯示提示「目前沒有影片」。
videos 陣列 是這個系統的核心,負責儲存所有上傳的影片資料。renderVideoList 函數會根據 videos 陣列中的內容動態生成影片列表,並在影片更新、刪除或修改後重新渲染頁面。