Files
sundynix-pets/pets-be/internal/database/seed.go
T
Blizzard 7159930d9c feat(admin): 随机昵称 + 建档数统计 + 帖子发布时间 + 16 篇新文章
## 新用户昵称
微信登录拿不到昵称(要用户主动授权),原来一律叫「微信用户」,
社区里一屏全是同名,后台也没法区分。改成随机生成「铲屎官12138」
这种形式:10 个前缀 × 5 位数字,落库前查重,撞了重试。

新增 users.nickname_auto 标记这个昵称是系统生成的。原来判断该不该
用微信授权昵称覆盖,靠的是「昵称是不是等于『微信用户』」这个字符串
比较,改成随机昵称后这招就失效了。有标记位才能安全覆盖,同时保证
用户自己改过的昵称不会被冲掉(改昵称时会把标记置 false)。

## 用户管理
加「宠物档案」列,显示每个用户建了几个档。用一次 GROUP BY 查完
当页所有人,不是每行一次 count——那会是 N+1。

## 帖子审核
加发布时间列。今天的显示「今天 14:48」,昨天的显示「昨天」,
更早的显示日期——审核时关心的是「多久以前发的」而不是完整时间戳。

## 文章
新增 16 篇,连同原有 4 篇共 20 篇,每篇 400-570 字:
猫 5 篇(新猫到家第一周 / 猫砂盆 / 公猫尿闭 / 掉毛毛球 / 老年猫信号)
狗 5 篇(社会化关键期 / 定点排便 / 遛狗时长 / 刷牙 / 中暑防护)
通用 6 篇(体重趋势 / 驱虫周期 / 绝育 / 急诊清单 / 就医准备 / 养宠预算)

沿用和 AI 助手一样的安全护栏:不做诊断、不给药物剂量,凡是可能
延误病情的都写清「什么时候必须去医院」。犬用驱虫药对猫的致死风险
这类真实事故也写进去了。

seedArticles 从「库空才插」改成「按标题补缺失」,以后往内置清单加
文章,老库启动也能拿到。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 12:55:22 +08:00

212 lines
8.5 KiB
Go

package database
import (
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
"github.com/sundynix/pets-be/internal/config"
"github.com/sundynix/pets-be/internal/model"
)
// Seed 初始化种子数据:管理员账号 + 新手文章
func Seed(db *gorm.DB, cfg *config.Config) error {
if err := seedAdmin(db, cfg); err != nil {
return err
}
if err := seedArticles(db); err != nil {
return err
}
// 早期版本 seed 出来的文章没有正文,这里补上(不覆盖已在后台编辑过的)
return backfillArticleContent(db)
}
func seedAdmin(db *gorm.DB, cfg *config.Config) error {
var count int64
if err := db.Model(&model.Admin{}).Where("username = ?", cfg.Admin.Username).Count(&count).Error; err != nil {
return err
}
if count > 0 {
return nil
}
hash, err := bcrypt.GenerateFromPassword([]byte(cfg.Admin.Password), bcrypt.DefaultCost)
if err != nil {
return err
}
return db.Create(&model.Admin{
Username: cfg.Admin.Username,
PasswordHash: string(hash),
Role: "admin",
}).Error
}
// 按标题补齐:库里没有的才插入。这样以后往内置清单里加文章,
// 老库启动时也能自动拿到新的,而管理员改过或删掉的不会被复活……
// 删掉的会被复活是这个做法的代价,所以只在标题完全不存在时插。
func seedArticles(db *gorm.DB) error {
all := append(builtinArticles(), moreArticles()...)
var titles []string
if err := db.Model(&model.Article{}).Pluck("title", &titles).Error; err != nil {
return err
}
exists := make(map[string]bool, len(titles))
for _, t := range titles {
exists[t] = true
}
var missing []model.Article
for _, a := range all {
if !exists[a.Title] {
missing = append(missing, a)
}
}
if len(missing) == 0 {
return nil
}
return db.Create(&missing).Error
}
// backfillArticleContent 给早期 seed 出来的空正文文章补内容(按标题匹配,只补空的,不覆盖已编辑过的)
func backfillArticleContent(db *gorm.DB) error {
for _, a := range builtinArticles() {
if err := db.Model(&model.Article{}).
Where("title = ? AND (content IS NULL OR content = '')", a.Title).
Updates(map[string]any{"content": a.Content, "description": a.Description}).Error; err != nil {
return err
}
}
return nil
}
// builtinArticles 内置新手文章。内容遵循与 AI 助手一致的安全护栏:
// 不做诊断、不给药物剂量,异常一律说明何时就医。
func builtinArticles() []model.Article {
return []model.Article{
{
Icon: "💉", Title: "幼猫疫苗和驱虫怎么安排?",
Description: "疫苗针次、驱虫间隔和常见误区,看完顺手设个提醒。",
Category: "vaccine", RelatedSheetType: "vaccine", Published: true,
Content: `刚接回家的猫,疫苗和驱虫是最容易漏掉、也最不能漏的两件事。
【核心疫苗:猫三联】
· 一般从 8 周龄左右开始,共打 3 针,每针间隔 3-4 周。
· 之后每年加强 1 针。
· 狂犬疫苗按当地规定接种,多数地区建议满 3 月龄后接种。
【接种前后注意】
· 只有健康的猫才能打疫苗。有腹泻、打喷嚏、精神差时先缓一缓。
· 接种前后一周不要洗澡、不要换粮、不要长途出行,减少应激。
· 打完在医院观察 20-30 分钟,回家后再留意 24 小时。
· 少数猫会精神略差或轻微发热,通常一两天缓解。
【驱虫】
· 体内驱虫:幼猫期约每月 1 次,成年后每 3 个月 1 次。
· 体外驱虫:出门或家里有狗时更要做,按产品说明周期。
· 完全室内、不接触其他动物的成年猫可适当拉长间隔,但不要长期不做。
【常见误区】
· 「猫不出门就不用打疫苗」——你的鞋底、衣物都可能带病原回家。
· 「三针打完就一劳永逸」——每年仍需加强。
· 「驱虫药随便买」——务必按体重选择,剂量以医生或说明书为准。
【什么时候要去医院】
接种后出现持续呕吐、面部肿胀、呼吸急促、精神明显萎靡,请立即就医。
小程序里可以直接把下一针疫苗和驱虫时间设成提醒,到期会通知你。`,
},
{
Icon: "💩", Title: "猫咪软便要不要去医院?",
Description: "先分清程度,学会记录观察,明确什么情况必须就医。",
Category: "symptom", RelatedSheetType: "symptom", Published: true,
Content: `软便很常见,但「常见」不等于「不用管」。关键是分清程度和持续时间。
【先看程度】
· 成形但偏软、能捡起来:多数是饮食或轻微应激,可以先观察。
· 糊状、不成形:需要留意,记录次数和颜色。
· 水样、喷射状:脱水风险高,别拖。
【常见诱因】
· 换粮太快(最常见):新旧粮要 7 天以上过渡。
· 应激:刚到家、搬家、家里来客人。
· 吃多了、吃了人食或零食过量。
· 寄生虫:尤其是没做过驱虫的幼猫。
· 着凉、毛球、食物不耐受。
【在家可以做的】
· 记录:什么时候开始、一天几次、颜色形状、有没有带血或黏液。
· 暂停新食物和零食,回到之前吃惯的粮。
· 保证饮水,注意保暖。
· 不要自行喂人用止泻药。
【出现这些情况,尽快就医】
· 持续超过 24 小时没有好转;
· 便中带血、发黑,或有大量黏液;
· 伴随呕吐、不吃不喝、精神明显变差;
· 幼猫、老年猫或本身有基础病的猫——它们脱水很快,标准要更严。
【就医时带上什么】
排便照片、开始时间、次数、近期饮食变化、驱虫和疫苗记录。小程序里的「异常观察」可以直接生成一份就医前摘要。
本文只提供观察思路,不能替代医生诊断。`,
},
{
Icon: "🍽️", Title: "7 天换粮计划怎么做?",
Description: "按比例过渡,配合排便记录,把换粮的肠胃风险降到最低。",
Category: "food", RelatedSheetType: "applyPlan", Published: true,
Content: `直接换粮是软便的头号原因。正确做法是按比例、分阶段过渡。
【标准 7 天方案】
· 第 1-2 天:新粮 25% + 旧粮 75%
· 第 3-4 天:新粮 50% + 旧粮 50%
· 第 5-6 天:新粮 75% + 旧粮 25%
· 第 7 天起:新粮 100%
肠胃敏感、幼猫或老年猫,把周期拉长到 10-14 天更稳。
【过渡期要盯什么】
· 每天记录排便状态:成形 / 软便 / 拉稀。
· 食欲有没有下降,有没有呕吐。
· 一旦出现软便:退回上一个比例,稳定 2-3 天再往前推,别硬推。
【几个细节】
· 一次只换一种变量。别同时换粮又换猫砂、又带去洗澡。
· 新旧粮要拌匀,不然它会挑出爱吃的。
· 换粮期间别加新零食,否则出问题分不清是谁的锅。
· 湿粮开封后冷藏并尽快吃完,别放到下一顿还常温摆着。
【什么时候暂停换粮去看医生】
拉稀持续超过 24 小时、便中带血、频繁呕吐或精神变差,先就医,别继续过渡。
在小程序里每天记一次「饮食」和「便便」,7 天后能直接看到这次换粮顺不顺。`,
},
{
Icon: "💰", Title: "一个月养猫大概花多少钱?",
Description: "拆开算固定支出和一次性支出,重点是留出医疗备用金。",
Category: "cost", RelatedSheetType: "cost", Published: true,
Content: `养猫的花销差异很大,但结构是固定的。看清结构再决定预算。
【每月固定支出】
· 猫粮:口粮占大头,按体重和粮的档次浮动。
· 猫砂:用量比想象中大,膨润土和豆腐砂消耗速度不同。
· 零食 / 营养品:可选,不是必需。
【周期性支出】
· 驱虫:体内体外,按周期。
· 疫苗:幼猫第一年针次多,之后每年一次。
· 体检:成年猫每年 1 次,老年猫建议每半年 1 次。
【一次性支出(第一年)】
猫砂盆、猫窝、food/水碗、猫爬架、航空箱、指甲剪、梳子;绝育是第一年最大的一笔。
【最容易被低估的一项:医疗】
真正让预算失控的从来不是猫粮,是突发医疗。常见的口炎、尿闭、异物、肾病,一次就可能超过全年口粮开销。
建议:单独留一笔医疗备用金,或了解一下宠物医疗保险。这比省几十块钱的粮重要得多。
【怎么省得聪明】
· 该省:花哨玩具、频繁换的网红零食。
· 不该省:口粮质量、驱虫疫苗、该做的体检——省这些通常是把钱挪到医疗账单上。
在小程序里每次消费顺手记一笔,月底就能看到自己的真实结构,比拍脑袋估算准得多。`,
},
}
}