整改三期:退款、后台增改删、悬赏
退款原来只有会员那条路,而且只能全额、只改本地状态。现在代喂任务的退款 能分几次退到退完:每一笔单独记一行(谁退的、多少、走哪条通道、为什么), 订单上的 refunded_cent 跟着累加,退完且未结算的任务才关闭。渠道接通时按 金额原路退回并带独立幂等键,没接通或沙箱支付的登记为"线下已退"——假装 调用了渠道比说实话更糟。已结算的任务不能顺手退:钱在喂养者账上,要退只能 由平台承担,必须显式勾选。 后台从"只能通过或驳回"变成能改能删:宠物档案可代建、可编辑、可软删除 (有进行中任务的删不掉),送养与配种能改文案和城市、能下架能删,代喂任务 能改备注、能取消(托管中的钱必须先退)。每一个写操作都进审计日志。 悬赏按方案里的 A 做:主人自愿加的钱跟着任务一起托管,结算时全额给喂养者, 平台服务费只算在基础报酬上。抽悬赏是喂养者一眼能算出来的事。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ebf7189533
commit
a889cb42e4
@@ -395,8 +395,10 @@ func (a *App) adminPets(w http.ResponseWriter, r *http.Request) {
|
||||
fail(w, http.StatusInternalServerError, 50001, "查询宠物失败")
|
||||
return
|
||||
}
|
||||
// 后台要能改档案,所以这里返回完整字段,而不是只够列表显示的那几个。
|
||||
rows, err := a.db.QueryContext(r.Context(), `SELECT p.id,p.owner_user_id,profile.nickname,u.public_id,p.name,p.species,p.breed,p.gender,
|
||||
p.neutered,p.vaccinated_at,p.avatar_url,p.moderation_status,p.moderation_note,p.created_at`+from+` ORDER BY p.id DESC LIMIT ? OFFSET ?`,
|
||||
p.neutered,p.vaccinated_at,p.avatar_url,p.moderation_status,p.moderation_note,p.created_at,
|
||||
p.birthday,p.dewormed_at,p.weight_g,p.chip_no,p.temperament`+from+` ORDER BY p.id DESC LIMIT ? OFFSET ?`,
|
||||
append(append([]any{}, args...), size, offset)...)
|
||||
if err != nil {
|
||||
fail(w, http.StatusInternalServerError, 50001, "查询宠物失败")
|
||||
@@ -404,26 +406,54 @@ func (a *App) adminPets(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []map[string]any{}
|
||||
ids := []any{}
|
||||
placeholders := []string{}
|
||||
for rows.Next() {
|
||||
var id, ownerID int64
|
||||
var nickname, publicID, name, species, breed, avatar, note string
|
||||
var gender, neutered, moderation int
|
||||
var vaccinated sql.NullTime
|
||||
var nickname, publicID, name, species, breed, avatar, note, chipNo, temperament string
|
||||
var gender, neutered, moderation, weight int
|
||||
var vaccinated, birthday, dewormed sql.NullTime
|
||||
var created time.Time
|
||||
if rows.Scan(&id, &ownerID, &nickname, &publicID, &name, &species, &breed, &gender, &neutered,
|
||||
&vaccinated, &avatar, &moderation, ¬e, &created) != nil {
|
||||
&vaccinated, &avatar, &moderation, ¬e, &created, &birthday, &dewormed, &weight, &chipNo, &temperament) != nil {
|
||||
continue
|
||||
}
|
||||
vaccinatedAt := ""
|
||||
if vaccinated.Valid {
|
||||
vaccinatedAt = vaccinated.Time.Format("2006-01-02")
|
||||
day := func(value sql.NullTime) string {
|
||||
if !value.Valid {
|
||||
return ""
|
||||
}
|
||||
return value.Time.Format("2006-01-02")
|
||||
}
|
||||
items = append(items, map[string]any{
|
||||
"id": id, "ownerUserId": ownerID, "ownerNickname": nickname, "ownerPublicId": publicID,
|
||||
"name": name, "species": species, "speciesLabel": petSpecies[species], "breed": breed,
|
||||
"gender": gender, "neutered": neutered == 1, "vaccinatedAt": vaccinatedAt, "avatar": avatar,
|
||||
"gender": gender, "neutered": neutered == 1, "vaccinatedAt": day(vaccinated), "avatar": avatar,
|
||||
"moderationStatus": moderation, "moderationNote": note, "createdAt": created.Format(time.RFC3339),
|
||||
"birthday": day(birthday), "dewormedAt": day(dewormed), "weightG": weight,
|
||||
"chipNo": chipNo, "temperament": temperament, "photos": []string{},
|
||||
})
|
||||
ids = append(ids, id)
|
||||
placeholders = append(placeholders, "?")
|
||||
}
|
||||
// 照片单独取一遍,编辑弹窗要按整组替换,列表里就得先有整组。
|
||||
if len(ids) > 0 {
|
||||
mediaRows, mediaErr := a.db.QueryContext(r.Context(),
|
||||
`SELECT pet_id,media_url FROM pet_media WHERE pet_id IN (`+strings.Join(placeholders, ",")+`) ORDER BY pet_id,sort_order,id`, ids...)
|
||||
if mediaErr == nil {
|
||||
defer mediaRows.Close()
|
||||
for mediaRows.Next() {
|
||||
var petID int64
|
||||
var url string
|
||||
if mediaRows.Scan(&petID, &url) != nil {
|
||||
continue
|
||||
}
|
||||
for index := range items {
|
||||
if items[index]["id"] == petID {
|
||||
items[index]["photos"] = append(items[index]["photos"].([]string), url)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
reply(w, map[string]any{"items": items, "total": total, "page": page, "size": size})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user