Cache home location and weather across page navigation
ci-cd / verify (push) Successful in 6s
ci-cd / deploy (push) Skipped

This commit is contained in:
2026-10-05 11:08:11 +08:00
parent 42aea10101
commit f0ee63e642
5 changed files with 205 additions and 57 deletions
+85
View File
@@ -0,0 +1,85 @@
const { secure } = require("./api");
const STORAGE_KEY = "pet_environment_v1";
let value;
let attempted = false;
let pending;
let failure;
function cached() {
if (value === undefined) {
const saved = wx.getStorageSync(STORAGE_KEY);
value =
saved &&
typeof saved.locationName === "string" &&
typeof saved.weatherLabel === "string" &&
Number.isFinite(saved.updatedAt)
? saved
: null;
}
return value;
}
async function fetchEnvironment(tapped) {
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");
}
const point = await new Promise((resolve, reject) =>
wx.getLocation({ type: "gcj02", success: resolve, fail: reject }),
);
const result = await secure("/environment", "GET", {
latitude: point.latitude,
longitude: point.longitude,
});
if (!result || !result.location_name)
throw new Error("位置和天气获取失败,请重试");
const previous = cached();
value = {
locationName: result.location_name,
weatherLabel: result.weather
? `${result.weather.description} ${result.weather.temperature}°C`
: previous && previous.locationName === result.location_name
? previous.weatherLabel
: "天气暂不可用",
updatedAt: Date.now(),
};
// Store display data only; precise coordinates are not persisted here.
try {
wx.setStorageSync(STORAGE_KEY, value);
} catch (_) {}
return value;
}
function refresh(tapped = false) {
if (pending) return pending;
// Module lifetime follows the app, including recreated pages and warm resumes.
// Failed automatic attempts also wait for a tap or the next cold start.
if (attempted && !tapped)
return failure ? Promise.reject(failure) : Promise.resolve(cached());
attempted = true;
pending = fetchEnvironment(tapped)
.then(
(result) => {
failure = null;
return result;
},
(error) => {
failure = error;
throw error;
},
)
.finally(() => {
pending = null;
});
return pending;
}
module.exports = { cached, refresh };