Files
Pet3/miniprogram/pages/summary/summary.js
2026-06-25 18:24:29 +08:00

199 lines
6.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// pages/summary/summary — 3 成果卡
// 「狗狗走了」视角补充字段全选填R7Canvas 生成分享图;订阅提醒
const { call } = require('../../utils/cloud.js');
const store = require('../../utils/store.js');
const { formatDuration } = require('../../utils/format.js');
const { chooseAndUpload } = require('../../utils/media.js');
const { SUBSCRIBE_TEMPLATE_ID } = require('../../utils/config.js');
Page({
data: {
loaded: false,
walkId: '',
primaryDogId: '',
dogName: '',
dogAvatar: '',
headline: '',
bigValue: '',
bigUnit: '',
timeText: '',
distanceText: '—',
streak: 0,
newAchievements: [],
weathers: [{ k: 'sunny', l: '☀️ 晴' }, { k: 'cloudy', l: '☁️ 阴' }, { k: 'rainy', l: '🌧️ 雨' }],
moods: [{ k: 'happy', l: '遛得开心' }, { k: 'tired', l: '有点累' }, { k: 'excited', l: '很兴奋' }],
weather: '',
mood: '',
note: '',
photos: [],
submitting: false,
},
_attached: false,
onLoad() {
const sum = getApp().globalData.lastSummary;
if (!sum) {
wx.showToast({ title: '数据缺失', icon: 'none' });
setTimeout(() => wx.switchTab({ url: '/pages/home/home' }), 1000);
return;
}
const r = (sum.results && sum.results[0]) || {};
const hasSteps = r.dogSteps != null;
const dog = (store.getState().dogs || []).find((d) => d._id === r.dogId);
this.setData({
loaded: true,
walkId: sum.walkId,
primaryDogId: r.dogId || '',
dogName: r.name || '狗狗',
dogAvatar: (dog && dog.avatar) || '',
headline: hasSteps ? `${r.name}今天走了` : `${r.name}今天遛了`,
bigValue: hasSteps ? String(r.dogSteps) : formatDuration(r.duration || 0),
bigUnit: hasSteps ? '狗步' : '',
timeText: formatDuration(r.duration || 0),
distanceText: r.distance != null ? Number(r.distance).toFixed(1) : '—',
streak: r.streak || 0,
newAchievements: sum.newAchievements || [],
});
},
pickWeather(e) { const k = e.currentTarget.dataset.k; this.setData({ weather: this.data.weather === k ? '' : k }); },
pickMood(e) { const k = e.currentTarget.dataset.k; this.setData({ mood: this.data.mood === k ? '' : k }); },
onNote(e) { this.setData({ note: e.detail.value }); },
async onPickPhoto() {
const fileID = await chooseAndUpload('walk-photos');
if (fileID) this.setData({ photos: [fileID] });
},
// 选填字段回写(只回写一次;含雨天战士成就判定)
async ensureAttached() {
if (this._attached) return;
const { weather, mood, note, photos, walkId } = this.data;
// 无任何选填内容时直接返回,但不锁定:用户可能稍后再补填,待真正回写后才置位
if (!weather && !mood && !note && !photos.length) return;
const res = await call('walkSave', {
action: 'attach', walkId,
weather: weather || null, mood: mood || null, note: note || null, photos,
});
this._attached = true;
if (res && res.ok && res.data.newAchievements && res.data.newAchievements.length) {
wx.showToast({ title: `解锁 ${res.data.newAchievements[0].name}`, icon: 'none' });
}
},
// ===== Canvas 生成分享图 =====
drawShareCard() {
return new Promise((resolve) => {
const q = wx.createSelectorQuery();
q.select('#shareCanvas').fields({ node: true, size: true }).exec((res) => {
if (!res[0] || !res[0].node) return resolve(null);
const canvas = res[0].node;
const ctx = canvas.getContext('2d');
const dpr = (wx.getWindowInfo && wx.getWindowInfo().pixelRatio) || 2;
const W = 600, H = 820;
canvas.width = W * dpr;
canvas.height = H * dpr;
ctx.scale(dpr, dpr);
// 背景
ctx.fillStyle = '#FBF8F3';
ctx.fillRect(0, 0, W, H);
// 顶部色带
ctx.fillStyle = '#E8A04B';
ctx.fillRect(0, 0, W, 12);
// 头像圆
ctx.fillStyle = '#F7E5CC';
ctx.beginPath();
ctx.arc(W / 2, 150, 70, 0, Math.PI * 2);
ctx.fill();
ctx.textAlign = 'center';
ctx.fillStyle = '#2E2A24';
ctx.font = '600 34px sans-serif';
ctx.fillText(this.data.headline, W / 2, 290);
ctx.fillStyle = '#C77E2E';
ctx.font = '700 96px sans-serif';
ctx.fillText(this.data.bigValue, W / 2, 400);
if (this.data.bigUnit) {
ctx.fillStyle = '#6E665B';
ctx.font = '500 28px sans-serif';
ctx.fillText(this.data.bigUnit, W / 2, 445);
}
// 三宫格
const cols = [
{ v: this.data.timeText, k: '时长' },
{ v: this.data.distanceText, k: '公里' },
{ v: `${this.data.streak}`, k: '连续' },
];
const baseY = 560;
cols.forEach((c, i) => {
const x = (W / 4) * (i + 1);
ctx.fillStyle = '#2E2A24';
ctx.font = '600 36px sans-serif';
ctx.fillText(c.v, x, baseY);
ctx.fillStyle = '#A89F92';
ctx.font = '400 24px sans-serif';
ctx.fillText(c.k, x, baseY + 40);
});
// 页脚
ctx.fillStyle = '#A89F92';
ctx.font = '500 26px sans-serif';
ctx.fillText('汪圈 · 每一次遛狗都值得被记录', W / 2, 760);
wx.canvasToTempFilePath({
canvas,
success: (r) => resolve(r.tempFilePath),
fail: () => resolve(null),
});
});
});
},
async onShare() {
if (this.data.submitting) return;
this.setData({ submitting: true });
await this.ensureAttached();
const path = await this.drawShareCard();
this.setData({ submitting: false });
if (!path) return wx.showToast({ title: '生成失败', icon: 'none' });
wx.showShareImageMenu({ path }); // 用户可分享到朋友圈/好友或保存
},
// 订阅「遛狗提醒」(模板未配置时静默跳过)
requestSubscribe() {
if (!SUBSCRIBE_TEMPLATE_ID) return Promise.resolve();
return new Promise((resolve) => {
wx.requestSubscribeMessage({ tmplIds: [SUBSCRIBE_TEMPLATE_ID], complete: resolve });
});
},
async onDone() {
if (this.data.submitting) return;
this.setData({ submitting: true });
await this.requestSubscribe(); // 需在用户点击手势内触发
await this.ensureAttached();
this.setData({ submitting: false });
this.sediment();
},
// 转发好友 / 朋友圈(小程序卡片)
onShareAppMessage() {
return { title: `${this.data.dogName}今天的遛狗成果`, path: '/pages/login/login' };
},
onShareTimeline() {
return { title: `${this.data.dogName}今天也出门遛了一圈` };
},
onClose() { wx.switchTab({ url: '/pages/home/home' }); },
sediment() {
const id = this.data.primaryDogId;
if (id) wx.redirectTo({ url: `/pages/dog-detail/dog-detail?id=${id}` });
else wx.switchTab({ url: '/pages/home/home' });
},
});