feat: 徽章api

This commit is contained in:
Blizzard
2026-02-12 14:34:31 +08:00
parent 01e13e736c
commit 0405968597
22 changed files with 1150 additions and 62 deletions
+119
View File
@@ -0,0 +1,119 @@
package plant
import (
"sundynix-go/global"
"sundynix-go/model/commom/response"
plantReq "sundynix-go/model/plant/request"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type BadgeConfigApi struct{}
// GetBadgeTree 获取徽章配置树 (不分页)
// @Tags 徽章配置
// @Summary 获取徽章配置树形结构
// @Security BearerAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /config/badge/tree [get]
func (a *BadgeConfigApi) GetBadgeTree(c *gin.Context) {
// 不需要 bind query 了,因为没有参数
tree, err := badgeConfigService.GetBadgeTree()
if err != nil {
global.Logger.Error("获取徽章树失败", zap.Error(err))
response.FailWithMsg("获取数据失败", c)
return
}
// 直接返回 data = tree
response.OkWithData(tree, c)
}
// AddBadgeConfig 添加徽章配置
// @Tags 徽章配置
// @Summary 添加徽章配置
// @Security BearerAuth
// @accept application/json
// @Produce application/json
// @Param data body plantReq.CreateBadge true "添加徽章配置"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"添加成功"}"
// @Router /config/badge/add [post]
func (a *BadgeConfigApi) AddBadgeConfig(c *gin.Context) {
var req plantReq.CreateBadge
err := c.ShouldBindJSON(&req)
if err != nil {
response.FailWithMsg("参数错误", c)
return
}
err = badgeConfigService.AddBadgeConfig(req)
if err != nil {
global.Logger.Error("添加徽章失败", zap.Error(err))
response.FailWithMsg("添加失败", c)
return
}
response.OkWithMsg("添加成功", c)
}
// UpdateBadgeConfig 更新徽章配置
// @Tags 徽章配置
// @Summary 更新徽章配置
// @Security BearerAuth
// @accept application/json
// @Produce application/json
// @Param data body plantReq.UpdateBadge true "更新参数"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /config/badge/update [post]
func (a *BadgeConfigApi) UpdateBadgeConfig(c *gin.Context) {
var req plantReq.UpdateBadge
err := c.ShouldBindJSON(&req)
if err != nil {
response.FailWithMsg("参数错误", c)
return
}
err = badgeConfigService.UpdateBadgeConfig(req)
if err != nil {
global.Logger.Error("更新失败", zap.Error(err))
response.FailWithMsg("更新失败", c)
return
}
response.OkWithMsg("更新成功", c)
}
// FindBadgeConfig 根据ID获取徽章配置
// @Tags 徽章配置
// @Summary 根据ID获取徽章配置
// @Security BearerAuth
// @Produce application/json
// @Param id query string true "id"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /config/badge/find [get]
func (a *BadgeConfigApi) FindBadgeConfig(c *gin.Context) {
id := c.Query("id")
badge, err := badgeConfigService.GetBadgeConfig(id)
if err != nil {
global.Logger.Error("查询失败", zap.Error(err))
response.FailWithMsg("查询失败", c)
return
}
response.OkWithData(badge, c)
}
// DeleteBadgeConfig 删除徽章配置
// @Tags 徽章配置
// @Summary 删除徽章配置
// @Security BearerAuth
// @Produce application/json
// @Param id query string true "id"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /config/badge/delete [get]
func (a *BadgeConfigApi) DeleteBadgeConfig(c *gin.Context) {
id := c.Query("id")
err := badgeConfigService.DeleteBadgeConfig(id)
if err != nil {
global.Logger.Error("删除失败", zap.Error(err))
response.FailWithMsg("删除失败", c)
return
}
response.OkWithMsg("删除成功", c)
}
+2
View File
@@ -11,6 +11,7 @@ type ApiGroup struct {
OcrApi OcrApi
LevelConfigApi LevelConfigApi
UserProfileApi UserProfileApi
BadgeConfigApi
} }
var ( var (
@@ -22,4 +23,5 @@ var (
ocrService = service.GroupApp.PlantServiceGroup.OcrService ocrService = service.GroupApp.PlantServiceGroup.OcrService
levelConfigService = service.GroupApp.PlantServiceGroup.LevelConfigService levelConfigService = service.GroupApp.PlantServiceGroup.LevelConfigService
userProfileService = service.GroupApp.PlantServiceGroup.UserProfileService userProfileService = service.GroupApp.PlantServiceGroup.UserProfileService
badgeConfigService = service.GroupApp.PlantServiceGroup.BadgeConfigService
) )
+1 -1
View File
@@ -132,7 +132,7 @@ func (a *TopicApi) TopicDetail(c *gin.Context) {
// @Tags 帖子话题 // @Tags 帖子话题
// @Summary 删除任务 // @Summary 删除任务
// @Security BearerAuth // @Security BearerAuth
// @accept json // @accept application/json
// @Produce application/json // @Produce application/json
// @Param data body request.IdsReq true "删除话题" // @Param data body request.IdsReq true "删除话题"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}" // @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
+263 -13
View File
@@ -594,6 +594,172 @@ const docTemplate = `{
} }
} }
}, },
"/config/badge/add": {
"post": {
"security": [
{
"BearerAuth": []
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"徽章配置"
],
"summary": "添加徽章配置",
"parameters": [
{
"description": "添加徽章配置",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.CreateBadge"
}
}
],
"responses": {
"200": {
"description": "{\"success\":true,\"data\":{},\"msg\":\"添加成功\"}",
"schema": {
"type": "string"
}
}
}
}
},
"/config/badge/delete": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"produces": [
"application/json"
],
"tags": [
"徽章配置"
],
"summary": "删除徽章配置",
"parameters": [
{
"type": "string",
"description": "id",
"name": "id",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "{\"success\":true,\"data\":{},\"msg\":\"删除成功\"}",
"schema": {
"type": "string"
}
}
}
}
},
"/config/badge/find": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"produces": [
"application/json"
],
"tags": [
"徽章配置"
],
"summary": "根据ID获取徽章配置",
"parameters": [
{
"type": "string",
"description": "id",
"name": "id",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "{\"success\":true,\"data\":{},\"msg\":\"获取成功\"}",
"schema": {
"type": "string"
}
}
}
}
},
"/config/badge/tree": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"produces": [
"application/json"
],
"tags": [
"徽章配置"
],
"summary": "获取徽章配置树形结构",
"responses": {
"200": {
"description": "{\"success\":true,\"data\":{},\"msg\":\"获取成功\"}",
"schema": {
"type": "string"
}
}
}
}
},
"/config/badge/update": {
"post": {
"security": [
{
"BearerAuth": []
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"徽章配置"
],
"summary": "更新徽章配置",
"parameters": [
{
"description": "更新参数",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.UpdateBadge"
}
}
],
"responses": {
"200": {
"description": "{\"success\":true,\"data\":{},\"msg\":\"更新成功\"}",
"schema": {
"type": "string"
}
}
}
}
},
"/config/level/add": { "/config/level/add": {
"post": { "post": {
"security": [ "security": [
@@ -3066,6 +3232,48 @@ const docTemplate = `{
} }
} }
}, },
"request.CreateBadge": {
"type": "object",
"properties": {
"comparator": {
"type": "string"
},
"description": {
"type": "string"
},
"dimension": {
"description": "维度: EXPERTISE(专家), PERSISTENCE(勤勉), JOURNAL(记录)",
"type": "string"
},
"groupId": {
"description": "组ID: 用于前端聚合显示 (e.g. \"fertilizerMaster\")",
"type": "string"
},
"iconId": {
"type": "string"
},
"name": {
"type": "string"
},
"rewardSunlight": {
"type": "integer"
},
"sort": {
"type": "integer"
},
"targetAction": {
"description": "触发动作: ACT_FERTILIZE, ACT_WATER...",
"type": "string"
},
"threshold": {
"type": "integer"
},
"tier": {
"description": "等级: 1=铜, 2=银, 3=金",
"type": "integer"
}
}
},
"request.CreateCarePlan": { "request.CreateCarePlan": {
"type": "object", "type": "object",
"required": [ "required": [
@@ -3230,13 +3438,13 @@ const docTemplate = `{
"request.CreateTopic": { "request.CreateTopic": {
"type": "object", "type": "object",
"properties": { "properties": {
"end_time": { "endTime": {
"type": "string" "type": "string"
}, },
"remark": { "remark": {
"type": "string" "type": "string"
}, },
"start_time": { "startTime": {
"type": "string" "type": "string"
}, },
"title": { "title": {
@@ -3583,6 +3791,54 @@ const docTemplate = `{
} }
} }
}, },
"request.UpdateBadge": {
"type": "object",
"required": [
"id"
],
"properties": {
"comparator": {
"type": "string"
},
"description": {
"type": "string"
},
"dimension": {
"description": "维度: EXPERTISE(专家), PERSISTENCE(勤勉), JOURNAL(记录)",
"type": "string"
},
"groupId": {
"description": "组Id: 用于前端聚合显示 (e.g. \"fertilizerMaster\")",
"type": "string"
},
"iconId": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"rewardSunlight": {
"type": "integer"
},
"sort": {
"type": "integer"
},
"targetAction": {
"description": "触发动作: ACT_FERTILIZE, ACT_WATER...",
"type": "string"
},
"threshold": {
"type": "integer"
},
"tier": {
"description": "等级: 1=铜, 2=银, 3=金",
"type": "integer"
}
}
},
"request.UpdateLevelConf": { "request.UpdateLevelConf": {
"type": "object", "type": "object",
"required": [ "required": [
@@ -3680,17 +3936,8 @@ const docTemplate = `{
"avatarId": { "avatarId": {
"type": "string" "type": "string"
}, },
"currentSunlight": {
"type": "integer"
},
"levelId": {
"type": "string"
},
"nickname": { "nickname": {
"type": "string" "type": "string"
},
"totalSunlight": {
"type": "integer"
} }
} }
}, },
@@ -3700,7 +3947,7 @@ const docTemplate = `{
"id" "id"
], ],
"properties": { "properties": {
"end_time": { "endTime": {
"type": "string" "type": "string"
}, },
"id": { "id": {
@@ -3709,7 +3956,7 @@ const docTemplate = `{
"remark": { "remark": {
"type": "string" "type": "string"
}, },
"start_time": { "startTime": {
"type": "string" "type": "string"
}, },
"title": { "title": {
@@ -3989,6 +4236,9 @@ const docTemplate = `{
"parentId": { "parentId": {
"type": "string" "type": "string"
}, },
"path": {
"type": "string"
},
"permission": { "permission": {
"type": "string" "type": "string"
}, },
+263 -13
View File
@@ -586,6 +586,172 @@
} }
} }
}, },
"/config/badge/add": {
"post": {
"security": [
{
"BearerAuth": []
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"徽章配置"
],
"summary": "添加徽章配置",
"parameters": [
{
"description": "添加徽章配置",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.CreateBadge"
}
}
],
"responses": {
"200": {
"description": "{\"success\":true,\"data\":{},\"msg\":\"添加成功\"}",
"schema": {
"type": "string"
}
}
}
}
},
"/config/badge/delete": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"produces": [
"application/json"
],
"tags": [
"徽章配置"
],
"summary": "删除徽章配置",
"parameters": [
{
"type": "string",
"description": "id",
"name": "id",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "{\"success\":true,\"data\":{},\"msg\":\"删除成功\"}",
"schema": {
"type": "string"
}
}
}
}
},
"/config/badge/find": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"produces": [
"application/json"
],
"tags": [
"徽章配置"
],
"summary": "根据ID获取徽章配置",
"parameters": [
{
"type": "string",
"description": "id",
"name": "id",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "{\"success\":true,\"data\":{},\"msg\":\"获取成功\"}",
"schema": {
"type": "string"
}
}
}
}
},
"/config/badge/tree": {
"get": {
"security": [
{
"BearerAuth": []
}
],
"produces": [
"application/json"
],
"tags": [
"徽章配置"
],
"summary": "获取徽章配置树形结构",
"responses": {
"200": {
"description": "{\"success\":true,\"data\":{},\"msg\":\"获取成功\"}",
"schema": {
"type": "string"
}
}
}
}
},
"/config/badge/update": {
"post": {
"security": [
{
"BearerAuth": []
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"徽章配置"
],
"summary": "更新徽章配置",
"parameters": [
{
"description": "更新参数",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.UpdateBadge"
}
}
],
"responses": {
"200": {
"description": "{\"success\":true,\"data\":{},\"msg\":\"更新成功\"}",
"schema": {
"type": "string"
}
}
}
}
},
"/config/level/add": { "/config/level/add": {
"post": { "post": {
"security": [ "security": [
@@ -3058,6 +3224,48 @@
} }
} }
}, },
"request.CreateBadge": {
"type": "object",
"properties": {
"comparator": {
"type": "string"
},
"description": {
"type": "string"
},
"dimension": {
"description": "维度: EXPERTISE(专家), PERSISTENCE(勤勉), JOURNAL(记录)",
"type": "string"
},
"groupId": {
"description": "组ID: 用于前端聚合显示 (e.g. \"fertilizerMaster\")",
"type": "string"
},
"iconId": {
"type": "string"
},
"name": {
"type": "string"
},
"rewardSunlight": {
"type": "integer"
},
"sort": {
"type": "integer"
},
"targetAction": {
"description": "触发动作: ACT_FERTILIZE, ACT_WATER...",
"type": "string"
},
"threshold": {
"type": "integer"
},
"tier": {
"description": "等级: 1=铜, 2=银, 3=金",
"type": "integer"
}
}
},
"request.CreateCarePlan": { "request.CreateCarePlan": {
"type": "object", "type": "object",
"required": [ "required": [
@@ -3222,13 +3430,13 @@
"request.CreateTopic": { "request.CreateTopic": {
"type": "object", "type": "object",
"properties": { "properties": {
"end_time": { "endTime": {
"type": "string" "type": "string"
}, },
"remark": { "remark": {
"type": "string" "type": "string"
}, },
"start_time": { "startTime": {
"type": "string" "type": "string"
}, },
"title": { "title": {
@@ -3575,6 +3783,54 @@
} }
} }
}, },
"request.UpdateBadge": {
"type": "object",
"required": [
"id"
],
"properties": {
"comparator": {
"type": "string"
},
"description": {
"type": "string"
},
"dimension": {
"description": "维度: EXPERTISE(专家), PERSISTENCE(勤勉), JOURNAL(记录)",
"type": "string"
},
"groupId": {
"description": "组Id: 用于前端聚合显示 (e.g. \"fertilizerMaster\")",
"type": "string"
},
"iconId": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"rewardSunlight": {
"type": "integer"
},
"sort": {
"type": "integer"
},
"targetAction": {
"description": "触发动作: ACT_FERTILIZE, ACT_WATER...",
"type": "string"
},
"threshold": {
"type": "integer"
},
"tier": {
"description": "等级: 1=铜, 2=银, 3=金",
"type": "integer"
}
}
},
"request.UpdateLevelConf": { "request.UpdateLevelConf": {
"type": "object", "type": "object",
"required": [ "required": [
@@ -3672,17 +3928,8 @@
"avatarId": { "avatarId": {
"type": "string" "type": "string"
}, },
"currentSunlight": {
"type": "integer"
},
"levelId": {
"type": "string"
},
"nickname": { "nickname": {
"type": "string" "type": "string"
},
"totalSunlight": {
"type": "integer"
} }
} }
}, },
@@ -3692,7 +3939,7 @@
"id" "id"
], ],
"properties": { "properties": {
"end_time": { "endTime": {
"type": "string" "type": "string"
}, },
"id": { "id": {
@@ -3701,7 +3948,7 @@
"remark": { "remark": {
"type": "string" "type": "string"
}, },
"start_time": { "startTime": {
"type": "string" "type": "string"
}, },
"title": { "title": {
@@ -3981,6 +4228,9 @@
"parentId": { "parentId": {
"type": "string" "type": "string"
}, },
"path": {
"type": "string"
},
"permission": { "permission": {
"type": "string" "type": "string"
}, },
+168 -10
View File
@@ -27,6 +27,35 @@ definitions:
required: required:
- taskId - taskId
type: object type: object
request.CreateBadge:
properties:
comparator:
type: string
description:
type: string
dimension:
description: '维度: EXPERTISE(专家), PERSISTENCE(勤勉), JOURNAL(记录)'
type: string
groupId:
description: '组ID: 用于前端聚合显示 (e.g. "fertilizerMaster")'
type: string
iconId:
type: string
name:
type: string
rewardSunlight:
type: integer
sort:
type: integer
targetAction:
description: '触发动作: ACT_FERTILIZE, ACT_WATER...'
type: string
threshold:
type: integer
tier:
description: '等级: 1=铜, 2=银, 3=金'
type: integer
type: object
request.CreateCarePlan: request.CreateCarePlan:
properties: properties:
icon: icon:
@@ -142,11 +171,11 @@ definitions:
type: object type: object
request.CreateTopic: request.CreateTopic:
properties: properties:
end_time: endTime:
type: string type: string
remark: remark:
type: string type: string
start_time: startTime:
type: string type: string
title: title:
type: string type: string
@@ -389,6 +418,39 @@ definitions:
description: 标题 description: 标题
type: string type: string
type: object type: object
request.UpdateBadge:
properties:
comparator:
type: string
description:
type: string
dimension:
description: '维度: EXPERTISE(专家), PERSISTENCE(勤勉), JOURNAL(记录)'
type: string
groupId:
description: '组Id: 用于前端聚合显示 (e.g. "fertilizerMaster")'
type: string
iconId:
type: string
id:
type: string
name:
type: string
rewardSunlight:
type: integer
sort:
type: integer
targetAction:
description: '触发动作: ACT_FERTILIZE, ACT_WATER...'
type: string
threshold:
type: integer
tier:
description: '等级: 1=铜, 2=银, 3=金'
type: integer
required:
- id
type: object
request.UpdateLevelConf: request.UpdateLevelConf:
properties: properties:
id: id:
@@ -457,24 +519,18 @@ definitions:
properties: properties:
avatarId: avatarId:
type: string type: string
currentSunlight:
type: integer
levelId:
type: string
nickname: nickname:
type: string type: string
totalSunlight:
type: integer
type: object type: object
request.UpdateTopic: request.UpdateTopic:
properties: properties:
end_time: endTime:
type: string type: string
id: id:
type: integer type: integer
remark: remark:
type: string type: string
start_time: startTime:
type: string type: string
title: title:
type: string type: string
@@ -671,6 +727,8 @@ definitions:
type: string type: string
parentId: parentId:
type: string type: string
path:
type: string
permission: permission:
type: string type: string
sort: sort:
@@ -1102,6 +1160,106 @@ paths:
summary: 更新client summary: 更新client
tags: tags:
- 客户端管理 - 客户端管理
/config/badge/add:
post:
consumes:
- application/json
parameters:
- description: 添加徽章配置
in: body
name: data
required: true
schema:
$ref: '#/definitions/request.CreateBadge'
produces:
- application/json
responses:
"200":
description: '{"success":true,"data":{},"msg":"添加成功"}'
schema:
type: string
security:
- BearerAuth: []
summary: 添加徽章配置
tags:
- 徽章配置
/config/badge/delete:
get:
parameters:
- description: id
in: query
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: '{"success":true,"data":{},"msg":"删除成功"}'
schema:
type: string
security:
- BearerAuth: []
summary: 删除徽章配置
tags:
- 徽章配置
/config/badge/find:
get:
parameters:
- description: id
in: query
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: '{"success":true,"data":{},"msg":"获取成功"}'
schema:
type: string
security:
- BearerAuth: []
summary: 根据ID获取徽章配置
tags:
- 徽章配置
/config/badge/tree:
get:
produces:
- application/json
responses:
"200":
description: '{"success":true,"data":{},"msg":"获取成功"}'
schema:
type: string
security:
- BearerAuth: []
summary: 获取徽章配置树形结构
tags:
- 徽章配置
/config/badge/update:
post:
consumes:
- application/json
parameters:
- description: 更新参数
in: body
name: data
required: true
schema:
$ref: '#/definitions/request.UpdateBadge'
produces:
- application/json
responses:
"200":
description: '{"success":true,"data":{},"msg":"更新成功"}'
schema:
type: string
security:
- BearerAuth: []
summary: 更新徽章配置
tags:
- 徽章配置
/config/level/add: /config/level/add:
post: post:
consumes: consumes:
-1
View File
@@ -15,7 +15,6 @@ const (
ActionPrune = "ACT_PRUNE" // 修剪 ActionPrune = "ACT_PRUNE" // 修剪
ActionRepot = "ACT_REPOT" // 换盆 ActionRepot = "ACT_REPOT" // 换盆
ActionPhoto = "ACT_PHOTO" // 拍照 ActionPhoto = "ACT_PHOTO" // 拍照
ActionLogin = "ACT_LOGIN" // 签到
ActionKillPlant = "ACT_KILL" // 把植物养死了(作为彩蛋徽章) ActionKillPlant = "ACT_KILL" // 把植物养死了(作为彩蛋徽章)
) )
+2
View File
@@ -53,7 +53,9 @@ func MigrateTable() {
plant.ClassifyRecord{}, //植物识别记录 plant.ClassifyRecord{}, //植物识别记录
plant.LevelConfig{}, //等级配置 plant.LevelConfig{}, //等级配置
plant.BadgeConfig{}, //徽章配置
plant.UserProfile{}, //用户资料 plant.UserProfile{}, //用户资料
plant.UserBadge{}, //用户徽章
) )
if err != nil { if err != nil {
+1
View File
@@ -56,6 +56,7 @@ func Routers() {
plantGroup.InitWikiRouter(NeedAuthGroup) //百科 plantGroup.InitWikiRouter(NeedAuthGroup) //百科
plantGroup.InitOcrRouter(NeedAuthGroup) // ocr识别 plantGroup.InitOcrRouter(NeedAuthGroup) // ocr识别
plantGroup.InitLevelConfigRouter(NeedAuthGroup) //等级配置 plantGroup.InitLevelConfigRouter(NeedAuthGroup) //等级配置
plantGroup.InitBadgeConfigRouter(NeedAuthGroup) //徽章配置
plantGroup.InitUserProfileRouter(NeedAuthGroup) //用户资料 plantGroup.InitUserProfileRouter(NeedAuthGroup) //用户资料
} }
+30
View File
@@ -0,0 +1,30 @@
package request
type CreateBadge struct {
Name string `json:"name"`
Description string `json:"description"`
IconId string `json:"iconId"`
Dimension string `json:"dimension"` // 维度: EXPERTISE(专家), PERSISTENCE(勤勉), JOURNAL(记录)
GroupId string `json:"groupId"` // 组ID: 用于前端聚合显示 (e.g. "fertilizerMaster")
Tier int `json:"tier"` // 等级: 1=铜, 2=银, 3=金
TargetAction string `json:"targetAction"` // 触发动作: ACT_FERTILIZE, ACT_WATER...
Threshold int64 `json:"threshold"`
Comparator string `json:"comparator"`
RewardSunlight int64 `json:"rewardSunlight"`
Sort int `json:"sort"`
}
type UpdateBadge struct {
Id string `json:"id" binding:"required"`
Name string `json:"name"`
Description string `json:"description"`
IconId string `json:"iconId"`
Dimension string `json:"dimension"` // 维度: EXPERTISE(专家), PERSISTENCE(勤勉), JOURNAL(记录)
GroupId string `json:"groupId"` // 组Id: 用于前端聚合显示 (e.g. "fertilizerMaster")
Tier int `json:"tier"` // 等级: 1=铜, 2=银, 3=金
TargetAction string `json:"targetAction"` // 触发动作: ACT_FERTILIZE, ACT_WATER...
Threshold int64 `json:"threshold"`
Comparator string `json:"comparator"`
RewardSunlight int64 `json:"rewardSunlight"`
Sort int `json:"sort"`
}
+15 -4
View File
@@ -1,6 +1,17 @@
package response package response
//type BadgeGroup struct { import "sundynix-go/model/plant"
// CategoryName string `json:"categoryName" comment:"分类名称"`
// BadgeList []plant.Badge `json:"badgeList"` // BadgeDimensionNode 1. 最外层:维度节点 (例如: "专家成就")
//} type BadgeDimensionNode struct {
Dimension string `json:"dimension"` // 维度 Key (e.g., "EXPERTISE")
Label string `json:"label"` // 维度显示名 (前端映射或后端返回)
Groups []BadgeGroupNode `json:"groups"` // 该维度下的徽章组
}
// BadgeGroupNode 2. 中间层:组节点 (例如: "炼金术士系列")
type BadgeGroupNode struct {
GroupId string `json:"groupId"` // 组 ID (e.g., "fertilizer_master")
GroupLabel string `json:"groupLabel"` // 中文显示名 (新增)
Badges []plant.BadgeConfig `json:"badges"` // 该组下的具体徽章 (铜/银/金)
}
+25 -8
View File
@@ -1,18 +1,35 @@
package plant package plant
import ( import (
"sundynix-go/config"
"sundynix-go/global" "sundynix-go/global"
"sundynix-go/model/system"
) )
// BadgeConfig 徽章配置 // BadgeConfig 徽章配置
type BadgeConfig struct { type BadgeConfig struct {
global.BaseModel global.BaseModel
GroupId string `json:"group_id"` // 徽章组 (用于系列徽章,如浇水铜/银/金) Name string `gorm:"type:varchar(64);not null;comment:徽章名称" json:"name"`
Name string `json:"name"` // 徽章名称 Description string `gorm:"type:varchar(255);comment:徽章描述" json:"description"`
Description string `json:"description"` // 描述 IconId string `gorm:"type:varchar(50);comment:图标资源id" json:"iconId"`
Tier config.BadgeTier `json:"tier"` // 稀有度 // --- 核心维度与分组 ---
TargetAction config.ActionType `json:"target_action"` // 关联的行为 // 维度: EXPERTISE(专家), PERSISTENCE(勤勉), JOURNAL(记录)
TargetCount int `json:"target_count"` // 需要完成该行为的次数 Dimension string `gorm:"type:varchar(32);index;not null;column:dimension;comment:维度分类" json:"dimension"`
IconURL string `json:"icon_url"` // 徽章图标地址 // 组ID: 用于前端聚合显示 (e.g. "fertilizerMaster")
GroupId string `gorm:"type:varchar(64);index;not null;column:group_id;comment:系列组Id" json:"groupId"`
// 等级: 1=铜, 2=银, 3=金
Tier int `gorm:"type:tinyint;default:1;column:tier;comment:等级权重" json:"tier"`
// --- 触发条件逻辑 ---
// 触发动作: ACT_FERTILIZE, ACT_WATER...
TargetAction string `gorm:"type:varchar(32);index;not null;column:target_action;comment:触发动作代码" json:"targetAction"`
// 目标阈值
Threshold int64 `gorm:"not null;column:threshold;comment:所需次数或数值" json:"threshold"`
// 比较操作符: ">=", "="
Comparator string `gorm:"type:varchar(10);default:'>=';column:comparator;comment:比较条件" json:"comparator"`
// --- 奖励 ---
RewardSunlight int64 `gorm:"not null;column:reward_sunlight;comment:奖励阳光值" json:"rewardSunlight"`
// --- 显示控制 ---
Sort int `gorm:"default:1;column:sort;comment:排序优先级" json:"sort"`
IsHidden bool `gorm:"-" json:"isHidden"`
//图标
Icon *system.Oss `json:"icon" gorm:"foreignKey:IconId"`
} }
+13
View File
@@ -0,0 +1,13 @@
package plant
import (
"sundynix-go/global"
"time"
)
type UserBadge struct {
global.BaseModel
UserId string `gorm:"type:varchar(50);index;not null;column:user_id;comment:用户id" json:"userId"`
BadgeId uint `gorm:"index:idx_user_badge,unique;not null;column:badge_id;comment:徽章配置ID" json:"badgeId"`
AcquiredAt time.Time `gorm:"autoCreateTime;column:acquired_at;comment:获得时间" json:"acquiredAt"`
}
+17
View File
@@ -0,0 +1,17 @@
package plant
import "github.com/gin-gonic/gin"
type BadgeConfigRouter struct{}
func (c *BadgeConfigRouter) InitBadgeConfigRouter(Router *gin.RouterGroup) {
badgeConfigRouter := Router.Group("config/badge")
{
badgeConfigRouter.GET("/tree", badgeConfigApi.GetBadgeTree)
badgeConfigRouter.POST("/add", badgeConfigApi.AddBadgeConfig)
badgeConfigRouter.POST("/update", badgeConfigApi.UpdateBadgeConfig)
badgeConfigRouter.GET("/find", badgeConfigApi.FindBadgeConfig)
badgeConfigRouter.GET("/delete", badgeConfigApi.DeleteBadgeConfig)
}
}
+2
View File
@@ -10,6 +10,7 @@ type RouterGroup struct {
WikiRouter WikiRouter
OcrRouter OcrRouter
LevelConfigRouter LevelConfigRouter
BadgeConfigRouter
UserProfileRouter UserProfileRouter
} }
@@ -23,4 +24,5 @@ var (
ocrApi = v1.ApiGroupApp.PlantApiGroup.OcrApi ocrApi = v1.ApiGroupApp.PlantApiGroup.OcrApi
levelConfigApi = v1.ApiGroupApp.PlantApiGroup.LevelConfigApi levelConfigApi = v1.ApiGroupApp.PlantApiGroup.LevelConfigApi
userProfileApi = v1.ApiGroupApp.PlantApiGroup.UserProfileApi userProfileApi = v1.ApiGroupApp.PlantApiGroup.UserProfileApi
badgeConfigApi = v1.ApiGroupApp.PlantApiGroup.BadgeConfigApi
) )
+1 -1
View File
@@ -4,7 +4,7 @@ import "github.com/gin-gonic/gin"
type LevelConfigRouter struct{} type LevelConfigRouter struct{}
func (c *OcrRouter) InitLevelConfigRouter(Router *gin.RouterGroup) { func (c *LevelConfigRouter) InitLevelConfigRouter(Router *gin.RouterGroup) {
levelConfigRouter := Router.Group("config/level") levelConfigRouter := Router.Group("config/level")
{ {
levelConfigRouter.POST("/add", levelConfigApi.AddLevelConfig) levelConfigRouter.POST("/add", levelConfigApi.AddLevelConfig)
+1 -1
View File
@@ -4,7 +4,7 @@ import "github.com/gin-gonic/gin"
type UserProfileRouter struct{} type UserProfileRouter struct{}
func (c *OcrRouter) InitUserProfileRouter(Router *gin.RouterGroup) { func (c *UserProfileRouter) InitUserProfileRouter(Router *gin.RouterGroup) {
userProfileRouter := Router.Group("profile") userProfileRouter := Router.Group("profile")
{ {
userProfileRouter.POST("/update", userProfileApi.UpdateProfile) userProfileRouter.POST("/update", userProfileApi.UpdateProfile)
+196
View File
@@ -0,0 +1,196 @@
package plant
import (
"errors"
"sundynix-go/global"
"sundynix-go/model/plant"
plantReq "sundynix-go/model/plant/request"
plantRes "sundynix-go/model/plant/response"
"gorm.io/gorm"
)
type BadgeConfigService struct{}
var BadgeConfigServiceApp = new(BadgeConfigService)
// GetBadgeTree 获取徽章树形结构 (无分页)
// GetBadgeTree 获取徽章树形结构 (维度和组ID都转换为中文)
func (s *BadgeConfigService) GetBadgeTree() (tree []plantRes.BadgeDimensionNode, err error) {
var allBadges []plant.BadgeConfig
// 1. 查询所有配置
err = global.DB.Order("dimension desc, group_id asc, tier asc, sort asc").Preload("Icon").Find(&allBadges).Error
if err != nil {
return nil, err
}
// --- 定义映射字典 ---
// 维度中文映射
dimLabelMap := map[string]string{
"PERSISTENCE": "勤勉成就",
"EXPERTISE": "专家成就",
"JOURNAL": "岁月记录",
"DISCOVERY": "探索发现",
}
// 组ID中文映射 (对应之前的 SQL 数据)
groupLabelMap := map[string]string{
// 勤勉系
"water_master": "雨露均沾", // 浇水
"alive_master": "长情陪伴", // 存活天数
// 专家系
"fert_master": "炼金术士", // 施肥
"prune_master": "园艺理发师", // 修剪
"repot_master": "乔迁之喜", // 换盆
"doctor_master": "植物医生", // 医生
// 记录系
"photo_master": "光影捕手", // 拍照
// 发现系
"night_owl": "守夜人", // 深夜养护
}
// 定义维度的固定展示顺序
dimOrder := []string{"PERSISTENCE", "EXPERTISE", "JOURNAL", "DISCOVERY"}
// --- 数据处理 ---
// 辅助 Map: map[Dimension] -> map[GroupId] -> []Badge
tempMap := make(map[string]map[string][]plant.BadgeConfig)
for _, badge := range allBadges {
dim := badge.Dimension
group := badge.GroupId
if tempMap[dim] == nil {
tempMap[dim] = make(map[string][]plant.BadgeConfig)
}
tempMap[dim][group] = append(tempMap[dim][group], badge)
}
// --- 构建返回树 ---
// 1. 遍历维度顺序
for _, dimKey := range dimOrder {
if groupMap, exists := tempMap[dimKey]; exists {
var groupNodes []plantRes.BadgeGroupNode
// 2. 遍历该维度下的所有组
for groupKey, badges := range groupMap {
// 获取组中文名,如果没有则回退到英文 ID
gLabel := groupLabelMap[groupKey]
if gLabel == "" {
gLabel = groupKey // Fallback
}
groupNodes = append(groupNodes, plantRes.BadgeGroupNode{
GroupId: groupKey,
GroupLabel: gLabel, // 赋值中文名
Badges: badges,
})
}
// 获取维度中文名
dLabel := dimLabelMap[dimKey]
if dLabel == "" {
dLabel = dimKey
}
tree = append(tree, plantRes.BadgeDimensionNode{
Dimension: dimKey,
Label: dLabel,
Groups: groupNodes,
})
delete(tempMap, dimKey)
}
}
// 3. 处理剩余的未知维度 (防止数据丢失)
for dimKey, groupMap := range tempMap {
var groupNodes []plantRes.BadgeGroupNode
for groupKey, badges := range groupMap {
// 未知组也尝试映射一下,不行就用 key
gLabel := groupLabelMap[groupKey]
if gLabel == "" {
gLabel = groupKey
}
groupNodes = append(groupNodes, plantRes.BadgeGroupNode{
GroupId: groupKey,
GroupLabel: gLabel,
Badges: badges,
})
}
tree = append(tree, plantRes.BadgeDimensionNode{
Dimension: dimKey,
Label: dimKey,
Groups: groupNodes,
})
}
return tree, nil
}
// AddBadgeConfig 添加徽章配置
func (s *BadgeConfigService) AddBadgeConfig(req plantReq.CreateBadge) error {
// 判断是否已存在相同配置(可选逻辑,例如同一组同一等级只能有一个)
if !errors.Is(global.DB.Where("group_id = ? AND tier = ?", req.GroupId, req.Tier).First(&plant.BadgeConfig{}).Error, gorm.ErrRecordNotFound) {
return errors.New("该组下该等级徽章已存在")
}
badge := plant.BadgeConfig{
Dimension: req.Dimension,
GroupId: req.GroupId,
Name: req.Name,
Description: req.Description,
IconId: req.IconId,
Tier: req.Tier,
TargetAction: req.TargetAction,
Threshold: req.Threshold,
Comparator: req.Comparator,
RewardSunlight: req.RewardSunlight,
Sort: req.Sort,
}
return global.DB.Create(&badge).Error
}
// UpdateBadgeConfig 修改徽章配置
func (s *BadgeConfigService) UpdateBadgeConfig(req plantReq.UpdateBadge) error {
// 使用 Map 更新可以避免 0 值问题,或者直接更新结构体
// 这里简单起见,先查再更,或者直接 Model update
var badge plant.BadgeConfig
if err := global.DB.Where("id = ?", req.Id).First(&badge).Error; err != nil {
return errors.New("记录不存在")
}
// 手动映射需要更新的字段 (更安全)
updateMap := map[string]interface{}{
"name": req.Name,
"description": req.Description,
"icon_id": req.IconId,
"dimension": req.Dimension,
"group_id": req.GroupId,
"tier": req.Tier,
"target_action": req.TargetAction,
"threshold": req.Threshold,
"reward_sunlight": req.RewardSunlight,
"sort": req.Sort,
}
return global.DB.Model(&badge).Updates(updateMap).Error
}
// GetBadgeConfig 根据ID获取单条
func (s *BadgeConfigService) GetBadgeConfig(id string) (plant.BadgeConfig, error) {
var badge plant.BadgeConfig
err := global.DB.Where("id = ?", id).Preload("Icon").First(&badge).Error
return badge, err
}
// DeleteBadgeConfig 删除徽章配置
func (s *BadgeConfigService) DeleteBadgeConfig(id string) error {
return global.DB.Where("id = ?", id).Delete(&plant.BadgeConfig{}).Error
}
+1
View File
@@ -8,5 +8,6 @@ type ServiceGroup struct {
WikiService WikiService
OcrService OcrService
LevelConfigService LevelConfigService
BadgeConfigService
UserProfileService UserProfileService
} }
+4 -2
View File
@@ -100,11 +100,13 @@ func (s *MyPlantService) PlantDetail(id string) (p plant.MyPlant, err error) {
return db.Order("created_at desc") return db.Order("created_at desc")
}). }).
Preload("CarePlans"). Preload("CarePlans").
Preload("CareRecords"). Preload("CareRecords", func(db *gorm.DB) *gorm.DB {
return db.Order("created_at desc")
}).
Preload("GrowthRecords", func(db *gorm.DB) *gorm.DB { Preload("GrowthRecords", func(db *gorm.DB) *gorm.DB {
return db.Preload("ImgList", func(db *gorm.DB) *gorm.DB { return db.Preload("ImgList", func(db *gorm.DB) *gorm.DB {
return db.Order("created_at desc") return db.Order("created_at desc")
}) }).Order("created_at desc")
}). }).
First(&res).Error First(&res).Error
+2 -2
View File
@@ -79,11 +79,11 @@ func (s *TopicService) Detail(id string) (t plant.Topic, err error) {
// DeleteTopics 删除话题 // DeleteTopics 删除话题
func (s *TopicService) DeleteTopics(req common.IdsReq) error { func (s *TopicService) DeleteTopics(req common.IdsReq) error {
var topics []plant.Topic var topics []plant.Topic
err := global.DB.Where("id in (?)", req.Ids).Find(&topics).Error err := global.DB.Where("id in ?", req.Ids).Find(&topics).Error
if err != nil { if err != nil {
return err return err
} }
err = global.DB.Unscoped().Delete(&plant.Topic{}).Error err = global.DB.Unscoped().Delete(&topics).Error
if err != nil { if err != nil {
return err return err
} }
+20 -2
View File
@@ -4,18 +4,36 @@ import (
"sundynix-go/global" "sundynix-go/global"
"sundynix-go/model/plant" "sundynix-go/model/plant"
plantReq "sundynix-go/model/plant/request" plantReq "sundynix-go/model/plant/request"
"sundynix-go/model/system"
"gorm.io/gorm"
) )
type UserProfileService struct{} type UserProfileService struct{}
// UpdateProfile 修改用户信息 // UpdateProfile 修改用户信息
func (s *UserProfileService) UpdateProfile(req plantReq.UpdateProfile, userId string) error { func (s *UserProfileService) UpdateProfile(req plantReq.UpdateProfile, userId string) error {
return global.DB.Transaction(func(tx *gorm.DB) error {
//1.更新profile
updateMap := map[string]interface{}{ updateMap := map[string]interface{}{
"nick_name": req.Nickname, "nick_name": req.Nickname,
"avatar_id": req.AvatarId, "avatar_id": req.AvatarId,
} }
return global.DB.Model(&plant.UserProfile{}).Where("user_id = ?", userId).Updates(updateMap).Error err := tx.Model(&plant.UserProfile{}).Where("user_id = ?", userId).Updates(updateMap).Error
if err != nil {
return err
}
//2.更新user表
updateMap = map[string]interface{}{
"name": req.Nickname,
"avatar_id": req.AvatarId,
}
err = tx.Model(&system.User{}).Where("id = ?", userId).Updates(updateMap).Error
if err != nil {
return err
}
return nil
})
} }
// ProfileDetail 获取用户详情 // ProfileDetail 获取用户详情