const { secure, toast } = require("../../utils/api"); const { localDate } = require("../../utils/date"); function dateLabel() { const now = new Date(); return `${now.getMonth() + 1}月${now.getDate()}日 周${"日一二三四五六"[now.getDay()]}`; } Page({ data: { locationName: "当前位置", headerSubtitle: dateLabel() + " · 轻触获取天气", pets: [], selected: [], tasks: [], walkCount: 0, name: "铲屎官", loading: true, ready: false, phase: "auth", error: "", }, onShow() { this.updateEnvironmentLabel(); this.load(); }, onUnload() { this.disposed = true; }, updateEnvironmentLabel() { this.setData({ headerSubtitle: dateLabel() + " · " + (this.weatherLabel || "轻触获取天气"), }); }, async refreshEnvironment(event) { if (this.environmentBusy) return; this.environmentBusy = true; const tapped = !!event; let positioned = false; try { const settings = await new Promise((resolve, reject) => wx.getSetting({ success: resolve, fail: reject }), ); if (settings.authSetting["scope.userLocation"] === false) { if (!tapped) throw new Error("location-denied"); const enabled = await new Promise((resolve, reject) => wx.openSetting({ success: resolve, fail: reject }), ); if (!enabled.authSetting["scope.userLocation"]) throw new Error("location-denied"); } this.weatherLabel = "正在获取天气"; this.updateEnvironmentLabel(); const point = await new Promise((resolve, reject) => wx.getLocation({ type: "gcj02", success: resolve, fail: reject, }), ); positioned = true; const result = await secure("/environment", "GET", { latitude: point.latitude, longitude: point.longitude, }); this.setData({ locationName: result.location_name }); this.weatherLabel = result.weather ? `${result.weather.description} ${result.weather.temperature}°C` : "天气暂不可用"; this.environmentAt = result.weather ? Date.now() : 0; } catch (error) { const denied = /denied|deny|auth/.test( error.errMsg || error.message || "", ); this.setData({ locationName: positioned ? "位置暂不可用" : denied ? "开启定位" : "定位暂不可用", }); this.weatherLabel = denied ? "轻触开启定位" : "轻触重试"; if (tapped && !denied) wx.showToast({ title: positioned ? "位置和天气获取失败,请重试" : "定位失败,请重试", icon: "none", }); } finally { this.environmentBusy = false; this.updateEnvironmentLabel(); } }, async load() { if (this.loadPromise) return this.loadPromise; this.loadPromise = this.loadHome().finally(() => { this.loadPromise = null; }); return this.loadPromise; }, async loadHome() { this.setData({ loading: true, error: "", phase: this.data.ready ? "data" : "auth", }); let authenticated = false; try { await getApp().login(); authenticated = true; if (this.disposed) return; this.setData({ phase: "data" }); const [pets, tasks, walks, me] = await Promise.all([ secure("/pets"), secure("/tasks"), secure("/walks"), secure("/me"), ]); if (this.disposed) return; const chosen = wx.getStorageSync("walk_pet_ids") || [], month = localDate().slice(0, 7); this.setData({ pets, selected: chosen.filter((id) => pets.some((p) => p.id === id)), tasks: tasks.items, walkCount: walks.filter((w) => w.started_at.slice(0, 7) === month) .length, name: me.nickname || "毛孩家长", loading: false, ready: true, phase: "ready", }); // Location permission and weather never hold up the first usable screen. if ( !this.environmentAt || Date.now() - this.environmentAt > 15 * 60 * 1000 ) { this.refreshEnvironment(); } } catch (error) { if (this.disposed) return; this.setData({ loading: false, phase: !authenticated && !this.data.ready ? "auth-error" : "data-error", error: error.message || "暂时没能连接,请稍后重试", }); } }, addPet() { wx.navigateTo({ url: "/pages/pet-edit/pet-edit" }); }, pick(e) { this.setData({ selected: e.detail.selected }); wx.setStorageSync("walk_pet_ids", e.detail.selected); }, start() { if (!this.data.selected.length) { wx.showToast({ title: "先选择一起出门的狗狗", icon: "none" }); return; } wx.redirectTo({ url: "/pages/walk/walk" }); }, goTasks() { wx.redirectTo({ url: "/pages/tasks/tasks" }); }, goWalks() { wx.navigateTo({ url: "/pages/walk-records/walk-records" }); }, async complete(e) { const id = e.currentTarget.dataset.id, task = this.data.tasks.find((t) => t.id === id); try { await secure("/tasks/" + id + "/completion", "PUT", { date: localDate(), completed: !task.completed, }); await this.load(); } catch (err) { toast(err); } }, });