fix: 成长报告海报用宠物真实头像(没传才用 emoji)
- 后端 Poster 增 pet_avatar_url(取 pet.AvatarURL,和身份卡同一可靠路径) - 海报 canvas 优先用它、store 兜底;有照片画圆形头像、没有才 emoji - 头像九参数居中裁剪,竖图/横图都不压扁 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -199,6 +199,7 @@ func (s *Service) GetHealthSummary(userID, petID string) (*HealthSummary, error)
|
|||||||
type Poster struct {
|
type Poster struct {
|
||||||
PetName string `json:"pet_name"`
|
PetName string `json:"pet_name"`
|
||||||
PetEmoji string `json:"pet_emoji"`
|
PetEmoji string `json:"pet_emoji"`
|
||||||
|
PetAvatarURL string `json:"pet_avatar_url"` // 上传过照片就有,海报优先用它,没有才用 emoji
|
||||||
Age string `json:"age"`
|
Age string `json:"age"`
|
||||||
Weight string `json:"weight"`
|
Weight string `json:"weight"`
|
||||||
Stage string `json:"stage"`
|
Stage string `json:"stage"`
|
||||||
@@ -223,7 +224,8 @@ func (s *Service) GetPoster(userID, petID string) (*Poster, error) {
|
|||||||
s.db.Model(&model.HealthRecord{}).Where("pet_id = ? AND type = ?", petID, model.RecordVaccine).Count(&vaccineRecs)
|
s.db.Model(&model.HealthRecord{}).Where("pet_id = ? AND type = ?", petID, model.RecordVaccine).Count(&vaccineRecs)
|
||||||
|
|
||||||
return &Poster{
|
return &Poster{
|
||||||
PetName: pet.Name, PetEmoji: pet.Emoji, Age: pet.Age, Weight: pet.Weight, Stage: pet.Stage,
|
PetName: pet.Name, PetEmoji: pet.Emoji, PetAvatarURL: pet.AvatarURL,
|
||||||
|
Age: pet.Age, Weight: pet.Weight, Stage: pet.Stage,
|
||||||
TasksCompleted: tasksDone, WeightRecords: weightRecs, VaccineRecords: vaccineRecs,
|
TasksCompleted: tasksDone, WeightRecords: weightRecs, VaccineRecords: vaccineRecs,
|
||||||
HighRiskCount: 0, Headline: "稳定成长",
|
HighRiskCount: 0, Headline: "稳定成长",
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
@@ -209,16 +209,18 @@ Component({
|
|||||||
|
|
||||||
const pet = this.data.pet || {};
|
const pet = this.data.pet || {};
|
||||||
const p = this.data.poster || {};
|
const p = this.data.poster || {};
|
||||||
|
// 优先用后端海报数据里的头像(和身份卡同一路径,可靠),store 兜底
|
||||||
|
const avatarUrl = p.pet_avatar_url || pet.avatar_url || '';
|
||||||
|
|
||||||
// 头像是远程图,异步加载。加载完(或没有头像)再往下画,
|
// 头像是远程图,异步加载。加载完(或没有头像)再往下画,
|
||||||
// 否则头像会画不上。加载失败当没有头像处理
|
// 否则头像会画不上。加载失败当没有头像处理
|
||||||
const loadAvatar = () =>
|
const loadAvatar = () =>
|
||||||
new Promise((res) => {
|
new Promise((res) => {
|
||||||
if (!pet.avatar_url) return res(null);
|
if (!avatarUrl) return res(null);
|
||||||
const img = node.createImage();
|
const img = node.createImage();
|
||||||
img.onload = () => res(img);
|
img.onload = () => res(img);
|
||||||
img.onerror = () => res(null);
|
img.onerror = () => res(null);
|
||||||
img.src = pet.avatar_url;
|
img.src = avatarUrl;
|
||||||
});
|
});
|
||||||
|
|
||||||
loadAvatar().then((avatar) => {
|
loadAvatar().then((avatar) => {
|
||||||
@@ -243,7 +245,13 @@ Component({
|
|||||||
ctx.arc(W / 2, avY + avD / 2, avD / 2, 0, Math.PI * 2);
|
ctx.arc(W / 2, avY + avD / 2, avD / 2, 0, Math.PI * 2);
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
ctx.clip();
|
ctx.clip();
|
||||||
ctx.drawImage(avatar, avX, avY, avD, avD);
|
// 居中裁剪成正方形再画,竖图/横图都不压扁
|
||||||
|
const iw = avatar.width || avD;
|
||||||
|
const ih = avatar.height || avD;
|
||||||
|
const side = Math.min(iw, ih);
|
||||||
|
const sx = (iw - side) / 2;
|
||||||
|
const sy = (ih - side) / 2;
|
||||||
|
ctx.drawImage(avatar, sx, sy, side, side, avX, avY, avD, avD);
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
} else {
|
} else {
|
||||||
ctx.font = '96px sans-serif';
|
ctx.font = '96px sans-serif';
|
||||||
|
|||||||
Reference in New Issue
Block a user