-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
373 lines (309 loc) · 12.9 KB
/
script.js
File metadata and controls
373 lines (309 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
const preferenceBackgrounds = [
{ name: "树屋营地", path: "偏好页背景/树屋_6_original.png" },
{ name: "温馨小屋", path: "偏好页背景/温馨小屋_5_original.png" }
];
const storageKeys = {
lastBackground: "mc_travel_pref_bg_last",
preferences: "mc_travel_preferences"
};
const destinationSeed = ["西湖线", "苏州古城线"];
const pageBg = document.getElementById("pageBg");
const bgName = document.getElementById("bgName");
const saveState = document.getElementById("saveState");
const destinationList = document.getElementById("destinationList");
const destinationInput = document.getElementById("destinationInput");
const addDestinationBtn = document.getElementById("addDestinationBtn");
const preferenceForm = document.getElementById("preferenceForm");
const destinationTemplate = document.getElementById("destinationItemTemplate");
const locateBtn = document.getElementById("locateBtn");
const saveDraftBtn = document.getElementById("saveDraftBtn");
const settingsBtn = document.getElementById("settingsBtn");
const destinationCounter = document.getElementById("destinationCounter");
const checkDeparture = document.getElementById("checkDeparture");
const checkRoute = document.getElementById("checkRoute");
const checkPreference = document.getElementById("checkPreference");
const toastStack = document.getElementById("toastStack");
const heroWindowBg = document.getElementById("heroWindowBg");
const launchPanel = document.querySelector(".launch-panel");
const launchButton = document.querySelector(".primary-cta");
const guidePreview = document.getElementById("guidePreview");
const departureRecommendations = ["上海", "杭州", "苏州"];
let destinations = [];
function showToast(message, type = "info") {
if (!toastStack) return;
const toast = document.createElement("div");
toast.className = `toast ${type}`;
toast.textContent = message;
toastStack.appendChild(toast);
window.setTimeout(() => {
toast.remove();
}, 2800);
}
function showLoadingToast() {
if (!toastStack) return;
toastStack.innerHTML = "";
const toast = document.createElement("div");
toast.className = "toast info";
toast.textContent = "正在点亮传送门,准备进入地图与加载流程...";
toastStack.appendChild(toast);
}
function randomItem(list) {
return list[Math.floor(Math.random() * list.length)];
}
function getSessionBackground() {
const lastPath = localStorage.getItem(storageKeys.lastBackground);
const candidates = preferenceBackgrounds.filter((item) => item.path !== lastPath);
const pool = candidates.length ? candidates : preferenceBackgrounds;
const selected = randomItem(pool);
localStorage.setItem(storageKeys.lastBackground, selected.path);
return selected;
}
function applyBackground() {
const selected = getSessionBackground();
pageBg.style.backgroundImage = `url("${selected.path}")`;
if (heroWindowBg) {
heroWindowBg.style.backgroundImage = `url("${selected.path}")`;
}
bgName.textContent = selected.name;
}
function renderDestinations() {
destinationList.innerHTML = "";
destinationCounter.textContent = `${destinations.length} 个方向`;
if (!destinations.length) {
const empty = document.createElement("div");
empty.className = "empty-state";
empty.textContent = "还没有记录方向锚点。没关系,你可以直接进入下一步,让地图页先给你一版经典推荐。";
destinationList.appendChild(empty);
return;
}
destinations.forEach((name, index) => {
const fragment = destinationTemplate.content.cloneNode(true);
const chip = fragment.querySelector(".destination-item");
const order = fragment.querySelector(".destination-order");
const title = fragment.querySelector("strong");
const buttons = fragment.querySelectorAll("button");
order.textContent = String(index + 1);
title.textContent = name;
buttons.forEach((button) => {
button.dataset.index = String(index);
});
destinationList.appendChild(chip);
});
}
function addDestination(value) {
const normalized = value.trim();
if (!normalized) return;
if (destinations.includes(normalized)) {
showToast("这个目的地旗帜已经插过了,换一个新站点吧。", "warning");
return;
}
destinations.push(normalized);
destinationInput.value = "";
renderDestinations();
destinationInput.focus();
}
function setDefaultDates() {
const start = document.getElementById("startDate");
const end = document.getElementById("endDate");
if (!start.value) {
start.value = "2026-04-03";
}
if (!end.value) {
end.value = "2026-04-05";
}
}
function updateSaveState() {
const saved = localStorage.getItem(storageKeys.preferences);
if (!saved) {
saveState.textContent = "尚未保存";
return;
}
try {
const data = JSON.parse(saved);
const destinationCount = data.destinations.length;
saveState.textContent = `${data.departure || "未填写出发地"} / ${destinationCount} 个方向`;
} catch (_error) {
saveState.textContent = "存档读取异常";
}
}
function validateDates(formData) {
const startValue = formData.get("startDate");
const endValue = formData.get("endDate");
return Boolean(startValue && endValue);
}
function collectPreferences(form) {
const formData = new FormData(form);
return {
departure: formData.get("departure")?.toString().trim() || "",
targetRegion: formData.get("targetRegion")?.toString().trim() || "",
destinations: [...destinations],
startDate: formData.get("startDate"),
endDate: formData.get("endDate"),
styles: formData.getAll("travelStyle"),
travelerType: formData.get("travelerType"),
travelRhythm: formData.get("travelRhythm"),
budgetTier: formData.get("budgetTier"),
companionType: formData.get("companionType"),
updatedAt: new Date().toISOString()
};
}
function updateGuidePreview() {
if (!guidePreview) return;
const travelerType = document.querySelector('input[name="travelerType"]:checked')?.value || "探险家";
const rhythm = document.querySelector('input[name="travelRhythm"]:checked')?.value || "轻松慢节奏";
const companion = document.querySelector('input[name="companionType"]:checked')?.value || "单人";
const travelerCopy = {
"探险家": "我会多留一些探索空间,让路线里不只有最常规的停靠点。",
"慢游者": "我会减少折返,把更多时间留给散步和停留。",
"美食猎人": "我会把值得绕路的在地味道优先插进路线。",
"拍照收集者": "我会优先照顾更适合出片的动线和时间段。",
"故事漫游者": "我会把更能体现城市气质和人文感的区域排在前面。",
"队伍领航员": "我会先保证整趟路顺、稳、大家都舒服,再补惊喜站点。"
};
const rhythmCopy = {
"轻松慢节奏": "整体节奏会更松一点,适合第一次去或不想太赶的时候。",
"经典打卡": "我会先给你一版稳妥的经典路线,避免第一次去就走散。",
"探索密度高": "我会把一天排得更满一些,但仍尽量控制折返。",
"不想走太多路": "我会优先安排更省体力的顺序,少一点来回切换。"
};
const companionCopy = {
"单人": "单人路线会保留更多即时修改的空间。",
"情侣": "我会优先照顾氛围、夜景和停留质量。",
"朋友": "我会多考虑热闹、好玩和适合一起行动的节点。",
"家庭": "我会更注意节奏平稳和大家都能跟上的体验。"
};
guidePreview.textContent = `${travelerCopy[travelerType]}${rhythmCopy[rhythm]}${companionCopy[companion]} 下一步我会先把这版方向铺到地图上,再让你继续微调。`;
}
function restorePreferences() {
const saved = localStorage.getItem(storageKeys.preferences);
if (!saved) {
initializeDestinations();
return;
}
try {
const data = JSON.parse(saved);
document.getElementById("departure").value = data.departure || "";
document.getElementById("targetRegion").value = data.targetRegion || "";
document.getElementById("startDate").value = data.startDate || "";
document.getElementById("endDate").value = data.endDate || "";
const savedDestinations = Array.isArray(data.destinations) ? data.destinations.filter(Boolean) : [];
destinations = savedDestinations.length ? savedDestinations : [...destinationSeed];
const travelerInput = document.querySelector(`input[name="travelerType"][value="${data.travelerType}"]`);
if (travelerInput) {
travelerInput.checked = true;
}
const budgetInput = document.querySelector(`input[name="budgetTier"][value="${data.budgetTier}"]`);
if (budgetInput) {
budgetInput.checked = true;
}
const rhythmInput = document.querySelector(`input[name="travelRhythm"][value="${data.travelRhythm}"]`);
if (rhythmInput) {
rhythmInput.checked = true;
}
const companionInput = document.querySelector(`input[name="companionType"][value="${data.companionType}"]`);
if (companionInput) {
companionInput.checked = true;
}
renderDestinations();
} catch (_error) {
initializeDestinations();
}
}
function savePreferences(showNotice) {
const formData = new FormData(preferenceForm);
if (!preferenceForm.reportValidity()) {
return false;
}
if (!validateDates(formData)) {
showToast("请选择完整的出发与返程节奏。", "warning");
return false;
}
const payload = collectPreferences(preferenceForm);
localStorage.setItem(storageKeys.preferences, JSON.stringify(payload));
updateSaveState();
syncProgress();
if (showNotice) {
showLoadingToast();
}
return true;
}
function initializeDestinations() {
destinations = [...destinationSeed];
renderDestinations();
}
function syncProgress() {
const cards = document.querySelectorAll(".flow-card");
const departureFilled = Boolean(document.getElementById("departure").value.trim() && document.getElementById("targetRegion").value.trim());
const hasDates = Boolean(document.getElementById("startDate").value && document.getElementById("endDate").value);
const hasPreferences = Boolean(
document.querySelector('input[name="travelerType"]:checked') ||
document.querySelector('input[name="travelRhythm"]:checked') ||
document.querySelector('input[name="budgetTier"]:checked') ||
document.querySelector('input[name="companionType"]:checked')
);
cards[0]?.classList.toggle("active", departureFilled && hasDates);
cards[1]?.classList.toggle("active", hasPreferences);
cards[2]?.classList.toggle("active", hasPreferences);
checkDeparture?.classList.toggle("active", departureFilled && hasDates);
checkRoute?.classList.toggle("active", Boolean(document.getElementById("targetRegion").value.trim() || destinations.length > 0));
checkPreference?.classList.toggle("active", hasPreferences);
launchPanel?.classList.toggle("ready", departureFilled && hasDates && hasPreferences);
if (launchButton) {
launchButton.textContent = departureFilled && hasDates && hasPreferences
? "开启世界地图"
: "开始规划旅程";
}
updateGuidePreview();
}
locateBtn.addEventListener("click", () => {
const departureInput = document.getElementById("departure");
const nextChoice = departureRecommendations.find((city) => city !== departureInput.value) || departureRecommendations[0];
departureInput.value = nextChoice;
syncProgress();
showToast(`已为你推荐更常见的出发地:${nextChoice}。`, "info");
});
saveDraftBtn.addEventListener("click", () => {
savePreferences(false);
});
settingsBtn.addEventListener("click", () => {
showToast("设置面板还未展开,下一步可补声音、动画与背景切换设置。", "info");
});
addDestinationBtn.addEventListener("click", () => {
addDestination(destinationInput.value);
syncProgress();
});
destinationList.addEventListener("click", (event) => {
const target = event.target;
if (!(target instanceof HTMLButtonElement)) return;
const index = Number(target.dataset.index);
const action = target.dataset.action;
if (Number.isNaN(index)) return;
if (action === "remove") {
destinations.splice(index, 1);
showToast("已移除一面路线旗帜。", "warning");
}
if (action === "up" && index > 0) {
target.closest(".destination-item")?.classList.add("moving");
[destinations[index - 1], destinations[index]] = [destinations[index], destinations[index - 1]];
showToast("路线旗帜已向前拨动。", "info");
}
if (action === "down" && index < destinations.length - 1) {
target.closest(".destination-item")?.classList.add("moving");
[destinations[index + 1], destinations[index]] = [destinations[index], destinations[index + 1]];
showToast("路线旗帜已向后拨动。", "info");
}
renderDestinations();
syncProgress();
});
preferenceForm.addEventListener("input", () => {
syncProgress();
});
preferenceForm.addEventListener("submit", (event) => {
event.preventDefault();
savePreferences(true);
});
applyBackground();
restorePreferences();
setDefaultDates();
updateSaveState();
syncProgress();