From 2f2757267e1fcb3087844b139aeee1b1f0bed5c0 Mon Sep 17 00:00:00 2001 From: Blizzard Date: Fri, 31 Jul 2026 14:29:04 +0800 Subject: [PATCH] =?UTF-8?q?fix(be):=20=E4=BB=BB=E5=8A=A1=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E4=B8=8E=E7=95=99=E7=97=95=E6=94=B9=E7=94=A8?= =?UTF-8?q?=20PlanTask=EF=BC=88DailyTask=20=E5=B7=B2=E7=A9=BA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TogglePlanTask:完成无 sheet_type 的任务时补一条 note 记录, 首页/计划页两条路径都统一留痕(ToggleTask 委托它);去掉前端重复建记录 - 报告页「完成任务」原来统计空的 DailyTask 恒为 0,改成经 plan 关联 统计 PlanTask 本周完成数;用户汇总的 tasksDone 同改 - 首页今日完成度 todayCompletionPct 同样从 DailyTask 改成今日 PlanTask Co-Authored-By: Claude Opus 5 --- pets-be/internal/service/home.go | 16 ++++++++++++---- pets-be/internal/service/plan.go | 11 ++++++++++- pets-be/internal/service/report.go | 9 ++++++--- pets-fe/pages/home/home.js | 12 +++--------- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/pets-be/internal/service/home.go b/pets-be/internal/service/home.go index e9d6a6f..304c330 100644 --- a/pets-be/internal/service/home.go +++ b/pets-be/internal/service/home.go @@ -180,14 +180,22 @@ func (s *Service) datesWithActivity(petID string, start, end time.Time) map[stri } func (s *Service) todayCompletionPct(petID string, now time.Time) int { - start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) - end := start.AddDate(0, 0, 1) + // 任务是 PlanTask(DailyTask 已空)。取宠物的 active 30 天计划,算今天那天的完成占比 + var plan model.Plan + if s.db.Where("pet_id = ? AND kind = ? AND status = ?", petID, model.PlanThirtyDay, "active"). + Order("id desc").First(&plan).Error != nil { + return 0 + } + day := dayIndexOf(&plan, now) + if day < 0 { + return 0 + } var total, done int64 - s.db.Model(&model.DailyTask{}).Where("pet_id = ? AND task_date >= ? AND task_date < ?", petID, start, end).Count(&total) + s.db.Model(&model.PlanTask{}).Where("plan_id = ? AND day = ?", plan.ID, day).Count(&total) if total == 0 { return 0 } - s.db.Model(&model.DailyTask{}).Where("pet_id = ? AND task_date >= ? AND task_date < ? AND done = ?", petID, start, end, true).Count(&done) + s.db.Model(&model.PlanTask{}).Where("plan_id = ? AND day = ? AND done = ?", plan.ID, day, true).Count(&done) return int(math.Round(float64(done) / float64(total) * 100)) } diff --git a/pets-be/internal/service/plan.go b/pets-be/internal/service/plan.go index 129a46e..3776e40 100644 --- a/pets-be/internal/service/plan.go +++ b/pets-be/internal/service/plan.go @@ -23,7 +23,16 @@ func (s *Service) TogglePlanTask(userID, taskID string) error { if err := s.db.Where("id = ? AND user_id = ?", pt.PlanID, userID).First(&plan).Error; err != nil { return ErrNotFound } - return s.db.Model(&model.PlanTask{}).Where("id = ?", taskID).Update("done", !pt.Done).Error + newDone := !pt.Done + if err := s.db.Model(&model.PlanTask{}).Where("id = ?", taskID).Update("done", newDone).Error; err != nil { + return err + } + // 勾选完成、且没关联记录类型的任务(自定义/无 sheet_type),补一条 note 记录, + // 让最近记录里留痕。有 sheet_type 的任务是走记录表单单独落记录的,这里不重复。 + if newDone && pt.SheetType == "" { + _, _ = s.CreateRecord(userID, plan.PetID, RecordInput{Type: "note", Title: "完成:" + pt.Title}) + } + return nil } // newStagePlan 按宠物当前阶段的养护模板生成一份 30 天计划(未保存) diff --git a/pets-be/internal/service/report.go b/pets-be/internal/service/report.go index 88db0cb..dd87d82 100644 --- a/pets-be/internal/service/report.go +++ b/pets-be/internal/service/report.go @@ -26,9 +26,10 @@ func (s *Service) GetWeeklyReport(userID, petID string) (*WeeklyReport, error) { } weekAgo := time.Now().AddDate(0, 0, -7) + // 任务已并成 PlanTask(DailyTask 表已空),要经 plan 关联到宠物来统计本周完成数 var tasksCompleted int64 - s.db.Model(&model.DailyTask{}). - Where("pet_id = ? AND done = ? AND updated_at >= ?", petID, true, weekAgo). + s.db.Model(&model.PlanTask{}). + Where("plan_id IN (SELECT id FROM sundynix_plans WHERE pet_id = ?) AND done = ? AND updated_at >= ?", petID, true, weekAgo). Count(&tasksCompleted) // 体重增长:最近 7 天最新 - 最早 @@ -215,7 +216,9 @@ func (s *Service) GetPoster(userID, petID string) (*Poster, error) { return nil, err } var tasksDone, weightRecs, vaccineRecs int64 - s.db.Model(&model.DailyTask{}).Where("pet_id = ? AND done = ?", petID, true).Count(&tasksDone) + s.db.Model(&model.PlanTask{}). + Where("plan_id IN (SELECT id FROM sundynix_plans WHERE pet_id = ?) AND done = ?", petID, true). + Count(&tasksDone) s.db.Model(&model.HealthRecord{}).Where("pet_id = ? AND type = ?", petID, model.RecordWeight).Count(&weightRecs) s.db.Model(&model.HealthRecord{}).Where("pet_id = ? AND type = ?", petID, model.RecordVaccine).Count(&vaccineRecs) diff --git a/pets-fe/pages/home/home.js b/pets-fe/pages/home/home.js index 1ddcae6..cb9c9f0 100644 --- a/pets-fe/pages/home/home.js +++ b/pets-fe/pages/home/home.js @@ -180,21 +180,15 @@ Page({ wx.navigateTo({ url }); return; } - // 没有关联记录类型的任务(自定义/无 sheet_type):直接切换完成, - // 并且切到「完成」时补一条 note 记录,这样最近记录里也留痕 + // 没有关联记录类型的任务(自定义/无 sheet_type):直接切换完成。 + // 后端 toggle 会在完成时补一条 note 记录,这里完成后刷新最近记录即可 api .toggleTask(t.id) .then((res) => { const tasks = this.data.tasks.slice(); tasks[i] = Object.assign({}, tasks[i], { done: res.done }); this.setData({ tasks }); - if (!res.done) return; // 取消完成就不建记录 - const pid = store.currentPetId(); - if (!pid) return; - return api - .createRecord(pid, { type: 'note', title: '完成:' + t.title }) - .then(() => this.loadTimeline(1)) - .catch(() => {}); // 建记录失败不影响任务已完成 + if (res.done) this.loadTimeline(1); }) .catch((err) => toastErr(err, '操作失败')); },