214 lines
5.9 KiB
JavaScript
214 lines
5.9 KiB
JavaScript
const { secure, toast } = require("../../utils/api");
|
|
Page({
|
|
data: {
|
|
pets: [],
|
|
selected: [],
|
|
walk: null,
|
|
points: [],
|
|
polyline: [],
|
|
latitude: 31.23,
|
|
longitude: 121.47,
|
|
duration: "00:00",
|
|
distance: "0.00",
|
|
share: false,
|
|
busy: false,
|
|
locationError: "",
|
|
},
|
|
onShow() {
|
|
this.load();
|
|
clearInterval(this.clock);
|
|
this.clock = setInterval(() => this.tick(), 1000);
|
|
},
|
|
onHide() {
|
|
this.stopTimers();
|
|
},
|
|
onUnload() {
|
|
this.stopTimers();
|
|
},
|
|
stopTimers() {
|
|
clearInterval(this.clock);
|
|
clearInterval(this.tracker);
|
|
this.clock = null;
|
|
this.tracker = null;
|
|
},
|
|
async load() {
|
|
try {
|
|
const [pets, walks] = await Promise.all([
|
|
secure("/pets"),
|
|
secure("/walks"),
|
|
]);
|
|
const selected = (wx.getStorageSync("walk_pet_ids") || []).filter((id) =>
|
|
pets.some((p) => p.id === id),
|
|
);
|
|
const walk =
|
|
walks.find((w) => w.status === "active" || w.status === "paused") ||
|
|
null;
|
|
this.setData({ pets, selected, walk });
|
|
if (walk) {
|
|
this.renderWalk(walk);
|
|
if (walk.status === "active") {
|
|
this.track();
|
|
this.point();
|
|
}
|
|
} else {
|
|
clearInterval(this.tracker);
|
|
this.setData({ points: [], polyline: [], duration: "00:00", distance: "0.00", share: false });
|
|
}
|
|
} catch (e) {
|
|
toast(e);
|
|
}
|
|
},
|
|
pick(e) {
|
|
if (this.data.walk) return;
|
|
this.setData({ selected: e.detail.selected });
|
|
wx.setStorageSync("walk_pet_ids", e.detail.selected);
|
|
},
|
|
async start() {
|
|
if (this.data.busy) return;
|
|
if (!this.data.selected.length) {
|
|
wx.showToast({ title: "请选择同行的狗狗", icon: "none" });
|
|
return;
|
|
}
|
|
this.setData({ busy: true, locationError: "" });
|
|
let position;
|
|
try {
|
|
position = await wx.getLocation({ type: "gcj02" });
|
|
} catch (error) {
|
|
this.setData({ busy: false, locationError: "请检查小程序定位权限,开启后再试" });
|
|
toast(new Error("无法取得位置,请检查定位权限"));
|
|
return;
|
|
}
|
|
this.setData({ latitude: position.latitude, longitude: position.longitude });
|
|
try {
|
|
const walk = await secure("/walks", "POST", {
|
|
pet_ids: this.data.selected,
|
|
});
|
|
this.setData({ walk });
|
|
this.track();
|
|
await this.savePoint(position);
|
|
} catch (e) {
|
|
if (this.data.walk) this.setData({ locationError: "轨迹保存失败,请点击重试" });
|
|
toast(e);
|
|
} finally {
|
|
this.setData({ busy: false });
|
|
}
|
|
},
|
|
track() {
|
|
clearInterval(this.tracker);
|
|
this.tracker = setInterval(() => this.point(), 15000);
|
|
},
|
|
async point() {
|
|
if (!this.data.walk || this.data.walk.status !== "active" || this.locating) return;
|
|
this.locating = true;
|
|
try {
|
|
const pos = await wx.getLocation({ type: "gcj02" });
|
|
await this.savePoint(pos);
|
|
this.setData({ locationError: "" });
|
|
} catch (e) {
|
|
if (this.data.walk) this.setData({ locationError: "定位更新失败,请检查定位权限和网络" });
|
|
} finally {
|
|
this.locating = false;
|
|
}
|
|
},
|
|
async savePoint(pos) {
|
|
const walkId = this.data.walk.id;
|
|
const walk = await secure(
|
|
"/walks/" + walkId + "/points",
|
|
"POST",
|
|
{ latitude: pos.latitude, longitude: pos.longitude },
|
|
);
|
|
if (this.data.walk && this.data.walk.id === walkId && this.data.walk.status === "active") {
|
|
this.renderWalk(walk);
|
|
}
|
|
},
|
|
renderWalk(walk) {
|
|
const pts = (walk.points || []).map((p) => ({
|
|
latitude: p.latitude,
|
|
longitude: p.longitude,
|
|
}));
|
|
const last = pts[pts.length - 1];
|
|
this.setData({
|
|
walk,
|
|
points: pts,
|
|
polyline:
|
|
pts.length > 1 ? [{ points: pts, color: "#268e6a", width: 5 }] : [],
|
|
latitude: last ? last.latitude : this.data.latitude,
|
|
longitude: last ? last.longitude : this.data.longitude,
|
|
distance: ((walk.distance_meters || 0) / 1000).toFixed(2),
|
|
share: walk.share_enabled,
|
|
});
|
|
this.tick();
|
|
},
|
|
tick() {
|
|
const walk = this.data.walk;
|
|
if (!walk) return;
|
|
const end = walk.ended_at
|
|
? new Date(walk.ended_at)
|
|
: walk.status === "paused"
|
|
? new Date(walk.paused_at || Date.now())
|
|
: new Date();
|
|
const sec = Math.max(
|
|
0,
|
|
Math.floor((end - new Date(walk.started_at)) / 1000) -
|
|
(walk.paused_seconds || 0),
|
|
);
|
|
this.setData({
|
|
duration:
|
|
String(Math.floor(sec / 60)).padStart(2, "0") +
|
|
":" +
|
|
String(sec % 60).padStart(2, "0"),
|
|
});
|
|
},
|
|
async action(e) {
|
|
if (this.data.busy) return;
|
|
const kind = e.currentTarget.dataset.kind;
|
|
this.setData({ busy: true });
|
|
try {
|
|
const walk = await secure(
|
|
"/walks/" + this.data.walk.id + "/" + kind,
|
|
"POST",
|
|
);
|
|
this.renderWalk(walk);
|
|
if (kind === "finish") {
|
|
clearInterval(this.tracker);
|
|
this.setData({ walk: null, points: [], polyline: [], duration: "00:00", distance: "0.00", share: false });
|
|
wx.showToast({ title: "今天的快乐已记录", icon: "success" });
|
|
} else if (kind === "resume") {
|
|
this.track();
|
|
this.point();
|
|
} else {
|
|
clearInterval(this.tracker);
|
|
}
|
|
} catch (err) {
|
|
toast(err);
|
|
} finally {
|
|
this.setData({ busy: false });
|
|
}
|
|
},
|
|
records() {
|
|
wx.navigateTo({ url: "/pages/walk-records/walk-records" });
|
|
},
|
|
async shareChange(e) {
|
|
try {
|
|
const walk = await secure(
|
|
"/walks/" + this.data.walk.id + "/share",
|
|
"PUT",
|
|
{ enabled: e.detail.value },
|
|
);
|
|
this.renderWalk(walk);
|
|
} catch (err) {
|
|
toast(err);
|
|
}
|
|
},
|
|
onShareAppMessage() {
|
|
const walk = this.data.walk;
|
|
return {
|
|
title: "肉垫计划 · 看看我们遛到哪儿了",
|
|
path:
|
|
walk && walk.share_enabled
|
|
? "/pages/share/share?token=" + walk.share_token
|
|
: "/pages/home/home",
|
|
};
|
|
},
|
|
});
|