feat: 养护模板/社区运营/体重趋势/计划日历 + 雪花ID重构 + 文件表与图片上传

后端
- 主键改雪花字符串 ID(pkg/idgen + Base.BeforeCreate),全表外键/JWT/中间件随之调整
- 新增 files 表:/api/upload 按 MD5 去重,返回 {id,url,md5},服务端只收图片
- 头像/记录附图/帖子图改 file_id 关联,读取解析为 URL
- 养护模板(物种×阶段)后台可配 + AI 生成草稿;建档按模板生成任务/计划/提醒
- 社区 AI 运营:虚拟账号池 + 每日定时/手动生成,帖子带 AI 标
- 计划路线图节点带真实日期;首页周历与计划日历同源;新增 day-plan 当日安排
- 体重趋势接口带备注;记录列表分页

小程序
- 公共图片上传 utils/upload.js(仅图片);记录拍照/我的头像/社区发图三处接入
- 首页日历点选查当日任务;记录页体重趋势可点看备注 + 时间轴分页折叠
- 计划页日历点选查当日计划;自定义 tabBar 高度调整

后台(React)
- 新增「养护模板」「社区运营」页;用户管理加机器人筛选

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-06 08:48:15 +08:00
parent 609f7d06cf
commit 2f5dd6eefc
83 changed files with 2253 additions and 355 deletions
+17 -8
View File
@@ -6,8 +6,11 @@ import (
"github.com/sundynix/pets-be/internal/model"
)
// AdminLogin 校验管理员账号密码
// AdminLogin 校验管理员账号密码。仅允许配置里指定的唯一管理员账号登录后台。
func (s *Service) AdminLogin(username, password string) (*model.Admin, error) {
if username != s.cfg.Admin.Username {
return nil, ErrNotFound
}
var admin model.Admin
if err := s.db.Where("username = ?", username).First(&admin).Error; err != nil {
return nil, ErrNotFound
@@ -22,7 +25,7 @@ func (s *Service) AdminLogin(username, password string) (*model.Admin, error) {
}
// GetAdmin 取管理员
func (s *Service) GetAdmin(id uint) (*model.Admin, error) {
func (s *Service) GetAdmin(id string) (*model.Admin, error) {
var admin model.Admin
if err := s.db.First(&admin, id).Error; err != nil {
return nil, ErrNotFound
@@ -49,11 +52,17 @@ func (s *Service) Stats() (*AdminStats, error) {
}
// ListUsers 用户分页(keyword 匹配昵称)
func (s *Service) ListUsers(keyword string, offset, limit int) ([]model.User, int64, error) {
func (s *Service) ListUsers(keyword, userType string, offset, limit int) ([]model.User, int64, error) {
q := s.db.Model(&model.User{})
if keyword != "" {
q = q.Where("nickname LIKE ?", "%"+keyword+"%")
}
switch userType {
case "bot":
q = q.Where("is_bot = ?", true)
case "real":
q = q.Where("is_bot IS NULL OR is_bot = ?", false)
}
var total int64
q.Count(&total)
var users []model.User
@@ -62,7 +71,7 @@ func (s *Service) ListUsers(keyword string, offset, limit int) ([]model.User, in
}
// SetUserDisabled 启用/禁用用户
func (s *Service) SetUserDisabled(id uint, disabled bool) error {
func (s *Service) SetUserDisabled(id string, disabled bool) error {
return s.db.Model(&model.User{}).Where("id = ?", id).Update("disabled", disabled).Error
}
@@ -89,7 +98,7 @@ func (s *Service) ListPostsAdmin(status string, offset, limit int) ([]model.Post
}
// SetPostStatus 审核帖子(published/hidden/deleted
func (s *Service) SetPostStatus(id uint, status string) error {
func (s *Service) SetPostStatus(id string, status string) error {
res := s.db.Model(&model.Post{}).Where("id = ?", id).Update("status", status)
if res.Error != nil {
return res.Error
@@ -110,7 +119,7 @@ func (s *Service) ListCommentsAdmin(offset, limit int) ([]model.Comment, int64,
}
// DeleteCommentAdmin 删除评论
func (s *Service) DeleteCommentAdmin(id uint) error {
func (s *Service) DeleteCommentAdmin(id string) error {
return s.db.Model(&model.Comment{}).Where("id = ?", id).Update("status", "deleted").Error
}
@@ -125,7 +134,7 @@ func (s *Service) ListArticlesAdmin(offset, limit int) ([]model.Article, int64,
// SaveArticle 新增或更新文章(ID 为 0 则新增)
func (s *Service) SaveArticle(a *model.Article) error {
if a.ID == 0 {
if a.ID == "" {
return s.db.Create(a).Error
}
return s.db.Model(&model.Article{}).Where("id = ?", a.ID).Updates(map[string]any{
@@ -140,7 +149,7 @@ func (s *Service) SaveArticle(a *model.Article) error {
}
// DeleteArticle 删除文章
func (s *Service) DeleteArticle(id uint) error {
func (s *Service) DeleteArticle(id string) error {
res := s.db.Delete(&model.Article{}, id)
if res.Error != nil {
return res.Error