86 lines
2.4 KiB
JavaScript
86 lines
2.4 KiB
JavaScript
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 };
|