commit
e01b0ecc39
4 changed files with 170 additions and 0 deletions
@ -0,0 +1,36 @@ |
|||||
|
from flask import Flask, jsonify, send_from_directory |
||||
|
|
||||
|
app = Flask(__name__, static_folder="public", static_url_path="") |
||||
|
|
||||
|
# 根路径返回 index.html |
||||
|
@app.route("/") |
||||
|
def serve_index(): |
||||
|
return send_from_directory(app.static_folder, "index.html") |
||||
|
|
||||
|
# API 子路径,提供徐州游玩攻略数据 |
||||
|
@app.route("/api/travel-guide") |
||||
|
def api_travel_guide(): |
||||
|
# 模拟徐州游玩攻略数据 |
||||
|
travel_guide = { |
||||
|
"message": "徐州游玩攻略", |
||||
|
"data": { |
||||
|
"places": [ |
||||
|
{"name": "云龙湖", "description": "徐州的标志性景点,湖光山色,风景优美。"}, |
||||
|
{"name": "徐州博物馆", "description": "展示徐州的历史文化遗产,适合了解徐州的历史。"}, |
||||
|
{"name": "彭祖园", "description": "以彭祖文化为主题的公园,适合休闲散步。"} |
||||
|
], |
||||
|
"food": [ |
||||
|
{"name": "徐州烙馍卷", "description": "徐州特色小吃,薄饼卷上各种馅料,非常美味。"}, |
||||
|
{"name": "地锅鸡", "description": "徐州传统美食,鸡肉鲜嫩,锅贴香脆。"}, |
||||
|
{"name": "糖醋黄河鲤鱼", "description": "徐州特色菜肴,鱼肉鲜嫩,酸甜适口。"} |
||||
|
], |
||||
|
"itinerary": [ |
||||
|
{"day": "第一天", "activities": ["上午:游览云龙湖", "下午:参观徐州博物馆", "晚上:品尝徐州烙馍卷"]}, |
||||
|
{"day": "第二天", "activities": ["上午:彭祖园散步", "下午:自由活动", "晚上:品尝地锅鸡"]} |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
return jsonify(travel_guide) |
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
app.run(debug=True, port=80) |
@ -0,0 +1,24 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html lang="en"> |
||||
|
<head> |
||||
|
<meta charset="UTF-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
|
<title>徐州游玩攻略</title> |
||||
|
<link rel="stylesheet" href="styles.css"> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div class="container"> |
||||
|
<h1>徐州游玩攻略</h1> |
||||
|
<div id="places-container"> |
||||
|
<h2>景点推荐</h2> |
||||
|
</div> |
||||
|
<div id="food-container"> |
||||
|
<h2>美食推荐</h2> |
||||
|
</div> |
||||
|
<div id="itinerary-container"> |
||||
|
<h2>行程安排</h2> |
||||
|
</div> |
||||
|
</div> |
||||
|
<script src="script.js"></script> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,69 @@ |
|||||
|
document.addEventListener("DOMContentLoaded", function () { |
||||
|
fetch("/api/travel-guide") |
||||
|
.then(response => response.json()) |
||||
|
.then(data => { |
||||
|
const placesContainer = document.getElementById("places-container"); |
||||
|
const foodContainer = document.getElementById("food-container"); |
||||
|
const itineraryContainer = document.getElementById("itinerary-container"); |
||||
|
|
||||
|
// 渲染景点推荐
|
||||
|
data.data.places.forEach(place => { |
||||
|
const placeItem = document.createElement("div"); |
||||
|
placeItem.classList.add("item"); |
||||
|
|
||||
|
const placeName = document.createElement("div"); |
||||
|
placeName.classList.add("item-name"); |
||||
|
placeName.textContent = place.name; |
||||
|
|
||||
|
const placeDescription = document.createElement("div"); |
||||
|
placeDescription.classList.add("item-description"); |
||||
|
placeDescription.textContent = place.description; |
||||
|
|
||||
|
placeItem.appendChild(placeName); |
||||
|
placeItem.appendChild(placeDescription); |
||||
|
|
||||
|
placesContainer.appendChild(placeItem); |
||||
|
}); |
||||
|
|
||||
|
// 渲染美食推荐
|
||||
|
data.data.food.forEach(food => { |
||||
|
const foodItem = document.createElement("div"); |
||||
|
foodItem.classList.add("item"); |
||||
|
|
||||
|
const foodName = document.createElement("div"); |
||||
|
foodName.classList.add("item-name"); |
||||
|
foodName.textContent = food.name; |
||||
|
|
||||
|
const foodDescription = document.createElement("div"); |
||||
|
foodDescription.classList.add("item-description"); |
||||
|
foodDescription.textContent = food.description; |
||||
|
|
||||
|
foodItem.appendChild(foodName); |
||||
|
foodItem.appendChild(foodDescription); |
||||
|
|
||||
|
foodContainer.appendChild(foodItem); |
||||
|
}); |
||||
|
|
||||
|
// 渲染行程安排
|
||||
|
data.data.itinerary.forEach(itinerary => { |
||||
|
const itineraryItem = document.createElement("div"); |
||||
|
itineraryItem.classList.add("item"); |
||||
|
|
||||
|
const day = document.createElement("div"); |
||||
|
day.classList.add("item-name"); |
||||
|
day.textContent = itinerary.day; |
||||
|
|
||||
|
const activities = document.createElement("div"); |
||||
|
activities.classList.add("item-description"); |
||||
|
activities.textContent = itinerary.activities.join(", "); |
||||
|
|
||||
|
itineraryItem.appendChild(day); |
||||
|
itineraryItem.appendChild(activities); |
||||
|
|
||||
|
itineraryContainer.appendChild(itineraryItem); |
||||
|
}); |
||||
|
}) |
||||
|
.catch(error => { |
||||
|
console.error("Error fetching travel guide data:", error); |
||||
|
}); |
||||
|
}); |
@ -0,0 +1,41 @@ |
|||||
|
body { |
||||
|
font-family: Arial, sans-serif; |
||||
|
background-color: #f4f4f9; |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
.container { |
||||
|
max-width: 800px; |
||||
|
margin: 20px auto; |
||||
|
padding: 20px; |
||||
|
background: #fff; |
||||
|
border-radius: 8px; |
||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
|
||||
|
h1, h2 { |
||||
|
text-align: center; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.item { |
||||
|
margin-bottom: 20px; |
||||
|
padding: 10px; |
||||
|
border-bottom: 1px solid #ddd; |
||||
|
} |
||||
|
|
||||
|
.item:last-child { |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
|
||||
|
.item-name { |
||||
|
font-size: 1.2em; |
||||
|
font-weight: bold; |
||||
|
color: #444; |
||||
|
} |
||||
|
|
||||
|
.item-description { |
||||
|
font-size: 0.9em; |
||||
|
color: #666; |
||||
|
} |
Loading…
Reference in new issue