Files
Blizzard 3175936266
ci-cd / verify (push) Successful in 2m18s
ci-cd / deploy (push) Skipped
feat: support shared pet care tasks and smooth daily page return
2026-10-05 20:20:05 +08:00

180 lines
5.2 KiB
JavaScript

const completion = require("../../utils/task-completion");
const { secure } = require("../../utils/api");
const { localDate } = require("../../utils/date");
const environment = require("../../utils/environment");
function dateLabel() {
const now = new Date();
return `${now.getMonth() + 1}月${now.getDate()}日 周${"日一二三四五六"[now.getDay()]}`;
}
function accountKey() {
const state = getApp().globalData || {};
return (state.user && state.user.id) || state.token || "";
}
Page({
data: {
locationName: "当前位置",
headerSubtitle: dateLabel() + " · 轻触获取天气",
pets: [],
selected: [],
tasks: [],
taskBusyIds: [],
completingAll: false,
undoneCount: 0,
walkCount: 0,
name: "铲屎官",
loading: true,
ready: false,
phase: "auth",
error: "",
},
onLoad() {
const cached = getApp().homeSnapshot;
if (cached && cached.account === accountKey() && cached.date === localDate()) {
this.setData({ ...cached.data, ready: true, phase: "ready", loading: false });
}
},
onShow() {
this.applyEnvironment(environment.cached());
this.load();
},
onHide() {
this.rememberHome();
},
onUnload() {
this.rememberHome();
this.disposed = true;
},
rememberHome() {
if (!this.data.ready || !accountKey()) return;
const { pets, selected, tasks, undoneCount, walkCount, name } = this.data;
getApp().homeSnapshot = {
account: accountKey(),
date: localDate(),
data: { pets, selected, tasks, undoneCount, walkCount, name },
};
},
updateEnvironmentLabel() {
this.setData({
headerSubtitle:
dateLabel() + " · " + (this.weatherLabel || "轻触获取天气"),
});
},
applyEnvironment(value) {
if (this.disposed) return;
if (value) {
this.weatherLabel = value.weatherLabel;
this.setData({ locationName: value.locationName });
}
this.updateEnvironmentLabel();
},
async refreshEnvironment(event) {
if (this.environmentBusy) return;
this.environmentBusy = true;
const tapped = !!event;
const cached = environment.cached();
if (!cached) {
this.weatherLabel = "正在获取天气";
this.updateEnvironmentLabel();
}
try {
this.applyEnvironment(await environment.refresh(tapped));
} catch (error) {
if (this.disposed) return;
if (cached) {
this.applyEnvironment(cached);
} else {
const denied = /denied|deny|auth/.test(
error.errMsg || error.message || "",
);
this.setData({ locationName: denied ? "开启定位" : "定位暂不可用" });
this.weatherLabel = denied ? "轻触开启定位" : "轻触重试";
this.updateEnvironmentLabel();
}
if (tapped) toast(error);
} finally {
this.environmentBusy = false;
}
},
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,
undoneCount: tasks.items.filter((t) => !t.completed).length,
walkCount: walks.filter((w) => w.started_at.slice(0, 7) === month)
.length,
name: me.nickname || "毛孩家长",
loading: false,
ready: true,
phase: "ready",
});
this.rememberHome();
// Location permission and weather never hold up the first usable screen.
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" });
},
complete(e) {
return completion.complete(
this,
this.data.tasks.find((t) => t.id === e.currentTarget.dataset.id),
);
},
completeAll() {
return completion.completeAll(this);
},
});