feat: 个人中心发布
This commit is contained in:
@@ -151,13 +151,13 @@ func (a *MyPlantApi) CompleteTask(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
userId := auth.GetUserId(c)
|
userId := auth.GetUserId(c)
|
||||||
err = plantService.CompleteTask(req, userId)
|
res, err := plantService.CompleteTask(req, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Logger.Error("完成任务失败", zap.Error(err))
|
global.Logger.Error("完成任务失败", zap.Error(err))
|
||||||
response.FailWithMsg("完成任务失败", c)
|
response.FailWithMsg("完成任务失败", c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.OkWithMsg("完成任务成功", c)
|
response.OkWithData(res, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePlants
|
// DeletePlants
|
||||||
|
|||||||
@@ -67,3 +67,29 @@ func (o *OcrApi) MyClassifyLog(c *gin.Context) {
|
|||||||
PageSize: req.PageSize,
|
PageSize: req.PageSize,
|
||||||
}, c)
|
}, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteClassifyLog
|
||||||
|
// @tags 识别相关
|
||||||
|
// @Summary 删除识别记录
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @accept application/json
|
||||||
|
// @Produce application/json
|
||||||
|
// @Param data body request.IdsReq true "删除识别记录"
|
||||||
|
// @Success 200 {object} response.Response{msg=string} "删除识别记录"
|
||||||
|
// @router /classify/deleteClassifyLog [post]
|
||||||
|
func (o *OcrApi) DeleteClassifyLog(c *gin.Context) {
|
||||||
|
var req request.IdsReq
|
||||||
|
err := c.ShouldBind(&req)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg("请求参数错误", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userId := auth.GetUserId(c)
|
||||||
|
err = ocrService.DeleteClassifyLog(req, userId)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("删除识别记录失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg("删除识别记录失败!", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("删除识别记录成功!", c)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package plant
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sundynix-go/global"
|
"sundynix-go/global"
|
||||||
|
common "sundynix-go/model/commom/request"
|
||||||
"sundynix-go/model/commom/response"
|
"sundynix-go/model/commom/response"
|
||||||
plantReq "sundynix-go/model/plant/request"
|
plantReq "sundynix-go/model/plant/request"
|
||||||
"sundynix-go/utils/auth"
|
"sundynix-go/utils/auth"
|
||||||
@@ -148,3 +149,50 @@ func (a *PostApi) CommentPost(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
response.OkWithMsg("评论成功", c)
|
response.OkWithMsg("评论成功", c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeletePost 删除帖子
|
||||||
|
// @Tags 帖子
|
||||||
|
// @Summary 删除帖子
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @accept application/json
|
||||||
|
// @Produce application/json
|
||||||
|
// @Param data body common.IdsReq true "删除帖子"
|
||||||
|
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
|
||||||
|
// @Router /post/delete [post]
|
||||||
|
func (a *PostApi) DeletePost(c *gin.Context) {
|
||||||
|
var req common.IdsReq
|
||||||
|
err := c.ShouldBindJSON(&req)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg("请求参数错误", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = postService.DeletePost(req.Ids)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("删除帖子失败", zap.Error(err))
|
||||||
|
response.FailWithMsg("删除帖子失败", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("删除帖子成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StarPost 收藏帖子
|
||||||
|
// @Tags 帖子
|
||||||
|
// @Summary 收藏帖子
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Produce application/json
|
||||||
|
// @Param id query string true "帖子id"
|
||||||
|
// @Param type query string true "收藏类型 1 收藏 2 取消收藏"
|
||||||
|
// @Success 200 {string} string "{"success":true,"data":{},"msg":"收藏成功"}"
|
||||||
|
// @Router /post/star [get]
|
||||||
|
func (a *PostApi) StarPost(c *gin.Context) {
|
||||||
|
postId := c.Query("id")
|
||||||
|
class := c.Query("type")
|
||||||
|
userId := auth.GetUserId(c)
|
||||||
|
err := postService.StarPost(userId, postId, class)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("操作失败", zap.Error(err))
|
||||||
|
response.FailWithMsg("操作失败", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("操作成功", c)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package plant
|
package plant
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sundynix-go/global"
|
||||||
"sundynix-go/model/commom/response"
|
"sundynix-go/model/commom/response"
|
||||||
"sundynix-go/model/plant/request"
|
"sundynix-go/model/plant/request"
|
||||||
"sundynix-go/utils/auth"
|
"sundynix-go/utils/auth"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserProfileApi struct{}
|
type UserProfileApi struct{}
|
||||||
@@ -49,3 +51,34 @@ func (a *UserProfileApi) ProfileDetail(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
response.OkWithData(res, c)
|
response.OkWithData(res, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MyStars 我的收藏
|
||||||
|
// @Tags 个人中心
|
||||||
|
// @Summary 我的收藏
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @accept application/json
|
||||||
|
// @Produce application/json
|
||||||
|
// @Param data body request.StarsPageReq true "分页获取收藏列表"
|
||||||
|
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
|
||||||
|
// @Router /profile/star [post]
|
||||||
|
func (a *UserProfileApi) MyStars(c *gin.Context) {
|
||||||
|
var req request.StarsPageReq
|
||||||
|
err := c.ShouldBindJSON(&req)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg("请求参数错误", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userId := auth.GetUserId(c)
|
||||||
|
list, total, err := userProfileService.MyStars(req, userId)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取收藏失败", zap.Error(err))
|
||||||
|
response.FailWithMsg("获取收藏失败", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(response.PageResult{
|
||||||
|
List: list,
|
||||||
|
Total: total,
|
||||||
|
Page: req.Current,
|
||||||
|
PageSize: req.PageSize,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
|
|||||||
+27
-2
@@ -4,6 +4,7 @@ import (
|
|||||||
"sundynix-go/global"
|
"sundynix-go/global"
|
||||||
"sundynix-go/model/commom/response"
|
"sundynix-go/model/commom/response"
|
||||||
plantReq "sundynix-go/model/plant/request"
|
plantReq "sundynix-go/model/plant/request"
|
||||||
|
"sundynix-go/utils/auth"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -78,7 +79,8 @@ func (a *WikiApi) WikiPage(c *gin.Context) {
|
|||||||
response.FailWithMsg("请求参数错误", c)
|
response.FailWithMsg("请求参数错误", c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
list, total, err := wikiService.WikiPage(req)
|
userId := auth.GetUserId(c)
|
||||||
|
list, total, err := wikiService.WikiPage(req, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Logger.Error("分页百科失败", zap.Error(err))
|
global.Logger.Error("分页百科失败", zap.Error(err))
|
||||||
response.FailWithMsg("分页百科失败", c)
|
response.FailWithMsg("分页百科失败", c)
|
||||||
@@ -102,10 +104,33 @@ func (a *WikiApi) WikiPage(c *gin.Context) {
|
|||||||
// @Router /wiki/detail [get]
|
// @Router /wiki/detail [get]
|
||||||
func (a *WikiApi) WikiDetail(c *gin.Context) {
|
func (a *WikiApi) WikiDetail(c *gin.Context) {
|
||||||
id := c.Query("id")
|
id := c.Query("id")
|
||||||
topic, err := wikiService.Detail(id)
|
userId := auth.GetUserId(c)
|
||||||
|
topic, err := wikiService.Detail(id, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.FailWithMsg("获取失败", c)
|
response.FailWithMsg("获取失败", c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
response.OkWithData(topic, c)
|
response.OkWithData(topic, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StarWiki 收藏百科
|
||||||
|
// @Tags 百科
|
||||||
|
// @Summary 收藏百科
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Produce application/json
|
||||||
|
// @Param id query string true "百科id"
|
||||||
|
// @Param type query string true "收藏类型 1 收藏 2 取消收藏"
|
||||||
|
// @Success 200 {string} string "{"success":true,"data":{},"msg":"收藏成功"}"
|
||||||
|
// @Router /wiki/star [get]
|
||||||
|
func (a *WikiApi) StarWiki(c *gin.Context) {
|
||||||
|
postId := c.Query("id")
|
||||||
|
class := c.Query("type")
|
||||||
|
userId := auth.GetUserId(c)
|
||||||
|
err := wikiService.StarWiki(userId, postId, class)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("操作失败", zap.Error(err))
|
||||||
|
response.FailWithMsg("操作失败", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("操作成功", c)
|
||||||
|
}
|
||||||
|
|||||||
+6
-6
@@ -14,14 +14,14 @@ jwt:
|
|||||||
|
|
||||||
|
|
||||||
# 植趣微信小程序
|
# 植趣微信小程序
|
||||||
#mini-program:
|
mini-program:
|
||||||
# app-id: wxb463820bf36dd5d6
|
app-id: wxb463820bf36dd5d6
|
||||||
# app-secret: 731784a74c76c6d31fa00bb847af2c7d
|
app-secret: 731784a74c76c6d31fa00bb847af2c7d
|
||||||
|
|
||||||
# 植遇微信小程序
|
# 植遇微信小程序
|
||||||
mini-program:
|
#mini-program:
|
||||||
app-id: wx52dfc635739a9c19
|
# app-id: wx52dfc635739a9c19
|
||||||
app-secret: 5aaed22f05352b7cd991870de6600bef
|
# app-secret: 5aaed22f05352b7cd991870de6600bef
|
||||||
|
|
||||||
# 植趣服务号
|
# 植趣服务号
|
||||||
service-account:
|
service-account:
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ func MigrateTable() {
|
|||||||
plant.BadgeConfig{}, //徽章配置
|
plant.BadgeConfig{}, //徽章配置
|
||||||
plant.UserProfile{}, //用户资料
|
plant.UserProfile{}, //用户资料
|
||||||
plant.UserBadge{}, //用户徽章
|
plant.UserBadge{}, //用户徽章
|
||||||
|
plant.UserStar{}, //用户收藏
|
||||||
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ func InitTimer() {
|
|||||||
option = append(option, cron.WithSeconds())
|
option = append(option, cron.WithSeconds())
|
||||||
|
|
||||||
// 任务一:每天8点30执行 发送植物养护提醒
|
// 任务一:每天8点30执行 发送植物养护提醒
|
||||||
_, err := global.Timer.AddTaskByFuncWithSecond("SendCareRemind", "0 30 8 * * *", func() {
|
_, err := global.Timer.AddTaskByFuncWithSecond("SendCareRemind", "0 15 9 * * *", func() {
|
||||||
err1 := task.SendCareMsg()
|
err1 := task.SendCareMsg()
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
global.Logger.Error("定时发送植物养护提醒失败", zap.Error(err1))
|
global.Logger.Error("定时发送植物养护提醒失败", zap.Error(err1))
|
||||||
|
|||||||
+2
-2
@@ -5,8 +5,8 @@ import (
|
|||||||
"sundynix-go/global"
|
"sundynix-go/global"
|
||||||
"sundynix-go/model/commom/response"
|
"sundynix-go/model/commom/response"
|
||||||
"sundynix-go/service"
|
"sundynix-go/service"
|
||||||
"sundynix-go/utils"
|
|
||||||
"sundynix-go/utils/auth"
|
"sundynix-go/utils/auth"
|
||||||
|
"sundynix-go/utils/timer"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -48,7 +48,7 @@ func AuthMiddleware() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
c.Set("claims", claims)
|
c.Set("claims", claims)
|
||||||
if claims.ExpiresAt.Unix()-time.Now().Unix() < claims.BufferTime {
|
if claims.ExpiresAt.Unix()-time.Now().Unix() < claims.BufferTime {
|
||||||
dr, _ := utils.ParseDuration(global.Config.JWT.ExpiresTime)
|
dr, _ := timer.ParseDuration(global.Config.JWT.ExpiresTime)
|
||||||
claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(dr))
|
claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(dr))
|
||||||
}
|
}
|
||||||
c.Next()
|
c.Next()
|
||||||
|
|||||||
@@ -14,9 +14,11 @@ type Post struct {
|
|||||||
ViewCount int `json:"viewCount" form:"viewCount" gorm:"default:0;column:view_count;comment:浏览次数"`
|
ViewCount int `json:"viewCount" form:"viewCount" gorm:"default:0;column:view_count;comment:浏览次数"`
|
||||||
CommentCount int `json:"commentCount" form:"commentCount" gorm:"default:0;column:comment_count;comment:评论次数"`
|
CommentCount int `json:"commentCount" form:"commentCount" gorm:"default:0;column:comment_count;comment:评论次数"`
|
||||||
LikeCount int `json:"likeCount" form:"likeCount" gorm:"default:0;column:like_count;comment:点赞次数"`
|
LikeCount int `json:"likeCount" form:"likeCount" gorm:"default:0;column:like_count;comment:点赞次数"`
|
||||||
|
StarCount int `json:"starCount" form:"starCount" gorm:"default:0;column:star_count;comment:收藏次数"`
|
||||||
Location string `json:"location" form:"location" gorm:"column:location;size:100;comment:位置"`
|
Location string `json:"location" form:"location" gorm:"column:location;size:100;comment:位置"`
|
||||||
HasReviewed int `json:"hasReviewed" form:"hasReviewed" gorm:"column:has_reviewed;default:0;comment:是否审核通过"`
|
HasReviewed int `json:"hasReviewed" form:"hasReviewed" gorm:"column:has_reviewed;default:0;comment:是否审核通过"`
|
||||||
HasLiked int `json:"hasLiked" form:"hasLiked" gorm:"-"`
|
HasLiked int `json:"hasLiked" form:"hasLiked" gorm:"-"`
|
||||||
|
HasStar int `json:"hasStar" form:"hasStar" gorm:"-"`
|
||||||
//图片
|
//图片
|
||||||
ImgList []*system.Oss `json:"imgList" form:"imgList" gorm:"many2many:post_oss;comment:图片列表"`
|
ImgList []*system.Oss `json:"imgList" form:"imgList" gorm:"many2many:post_oss;comment:图片列表"`
|
||||||
//评论
|
//评论
|
||||||
|
|||||||
@@ -35,13 +35,14 @@ func (p *MyPlant) AfterCreate(tx *gorm.DB) (err error) {
|
|||||||
for _, v := range p.CarePlans {
|
for _, v := range p.CarePlans {
|
||||||
dueDate := today.AddDate(0, 0, v.Period)
|
dueDate := today.AddDate(0, 0, v.Period)
|
||||||
task := CareTask{
|
task := CareTask{
|
||||||
UserId: p.UserId,
|
UserId: p.UserId,
|
||||||
PlantId: p.Id,
|
PlantId: p.Id,
|
||||||
PlanId: v.Id,
|
PlanId: v.Id,
|
||||||
Name: v.Name,
|
Name: v.Name,
|
||||||
Icon: v.Icon,
|
Icon: v.Icon,
|
||||||
DueDate: dueDate,
|
TargetAction: v.TargetAction,
|
||||||
Status: 1,
|
DueDate: dueDate,
|
||||||
|
Status: 1,
|
||||||
}
|
}
|
||||||
err = tx.Create(&task).Error
|
err = tx.Create(&task).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ import (
|
|||||||
// CarePlan 养护计划
|
// CarePlan 养护计划
|
||||||
type CarePlan struct {
|
type CarePlan struct {
|
||||||
global.BaseModel
|
global.BaseModel
|
||||||
UserId string `json:"userId" form:"userId" gorm:"size:50;column:user_id;comment:用户id"`
|
UserId string `json:"userId" form:"userId" gorm:"size:50;column:user_id;comment:用户id"`
|
||||||
PlantId string `json:"plantId" form:"plantId" gorm:"size:50;column:plant_id;comment:植物id"`
|
PlantId string `json:"plantId" form:"plantId" gorm:"index;size:50;column:plant_id;comment:植物id"`
|
||||||
Icon string `json:"icon" form:"icon" gorm:"type:text;"`
|
Icon string `json:"icon" form:"icon" gorm:"type:text;"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Period int `json:"period" form:"period" gorm:"column:period;comment:周期"`
|
Period int `json:"period" form:"period" gorm:"column:period;comment:周期"`
|
||||||
|
TargetAction string `gorm:"type:varchar(32);index;not null;column:target_action;comment:触发动作代码" json:"targetAction"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterUpdate 钩子函数 修改计划后重新生成任务
|
// AfterUpdate 钩子函数 修改计划后重新生成任务
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ import (
|
|||||||
|
|
||||||
type CareTask struct {
|
type CareTask struct {
|
||||||
global.BaseModel
|
global.BaseModel
|
||||||
PlantId string `json:"plantId" gorm:"index"`
|
PlantId string `json:"plantId" gorm:"index"`
|
||||||
PlanId string `json:"planId" gorm:"index"`
|
PlanId string `json:"planId" gorm:"index"`
|
||||||
UserId string `json:"userId" gorm:"index"`
|
UserId string `json:"userId" gorm:"index"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Icon string `json:"icon" gorm:"type:text"`
|
Icon string `json:"icon" gorm:"type:text"`
|
||||||
DueDate time.Time `json:"dueDate"` // 应做时间(用于判断逾期)
|
TargetAction string `gorm:"type:varchar(32);index;column:target_action;comment:触发动作代码" json:"targetAction"`
|
||||||
CompletedAt *time.Time `json:"completedAt" gorm:"column:completed_at"` // 完成时间(为nil表示未完成)
|
DueDate time.Time `json:"dueDate"` // 应做时间(用于判断逾期)
|
||||||
Status int `json:"status"` // 1:待执行 2:已完成 3:已跳过
|
CompletedAt *time.Time `json:"completedAt" gorm:"column:completed_at"` // 完成时间(为nil表示未完成)
|
||||||
|
Status int `json:"status"` // 1:待执行 2:已完成 3:已跳过
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
package request
|
package request
|
||||||
|
|
||||||
type CarePlan struct {
|
type CarePlan struct {
|
||||||
Icon string `json:"icon"` // icon信息
|
Icon string `json:"icon"` // icon信息
|
||||||
Name string `json:"name"` // 农事名称
|
Name string `json:"name"` // 农事名称
|
||||||
Period int `json:"period"` // 周期
|
Period int `json:"period"` // 周期
|
||||||
|
TargetAction string `json:"targetAction"` // 触动的动作
|
||||||
}
|
}
|
||||||
type CreateCarePlan struct {
|
type CreateCarePlan struct {
|
||||||
PlantId string `json:"plantId" binding:"required"`
|
PlantId string `json:"plantId" binding:"required"`
|
||||||
Icon string `json:"icon"` // icon信息
|
Icon string `json:"icon"` // icon信息
|
||||||
Name string `json:"name"` // 农事名称
|
Name string `json:"name"` // 农事名称
|
||||||
Period int `json:"period"` // 周期
|
Period int `json:"period"` // 周期
|
||||||
|
TargetAction string `json:"targetAction"` // 触动的动作
|
||||||
}
|
}
|
||||||
type AddPlans struct {
|
type AddPlans struct {
|
||||||
CarePlan []CreateCarePlan `json:"carePlan"`
|
CarePlan []CreateCarePlan `json:"carePlan"`
|
||||||
@@ -29,10 +31,11 @@ type CreateMyPlant struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UpdatePlan struct {
|
type UpdatePlan struct {
|
||||||
Id string `json:"id" binding:"required"`
|
Id string `json:"id" binding:"required"`
|
||||||
Icon string `json:"icon"` // icon信息
|
Icon string `json:"icon"` // icon信息
|
||||||
Name string `json:"name"` // 农事名称
|
Name string `json:"name"` // 农事名称
|
||||||
Period int `json:"period"` // 周期
|
Period int `json:"period"` // 周期
|
||||||
|
TargetAction string `json:"targetAction"` // 触动的动作
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateMyPlant 修改植物
|
// UpdateMyPlant 修改植物
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
package request
|
package request
|
||||||
|
|
||||||
|
import common "sundynix-go/model/commom/request"
|
||||||
|
|
||||||
type UpdateProfile struct {
|
type UpdateProfile struct {
|
||||||
Nickname string `json:"nickname"`
|
Nickname string `json:"nickname"`
|
||||||
AvatarId string `json:"avatarId"`
|
AvatarId string `json:"avatarId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StarsPageReq struct {
|
||||||
|
common.PageInfo
|
||||||
|
Class int `json:"class"` //分类 0 全部 1百科 2社交动态
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import "sundynix-go/model/plant"
|
||||||
|
|
||||||
|
// TaskCompletionResult 定义返回给前端的组合对象
|
||||||
|
type TaskCompletionResult struct {
|
||||||
|
NewBadge *plant.BadgeConfig `json:"newBadge"` // 本次新获得的徽章,无则为 nil
|
||||||
|
CurrentLevel *plant.LevelConfig `json:"currentLevel"` // 当前最新的等级信息
|
||||||
|
IsLevelUp bool `json:"isLevelUp"` // 是否升级了
|
||||||
|
IsGetBadge bool `json:"isGetBadge"` // 本次任务是否获得徽章
|
||||||
|
}
|
||||||
@@ -8,6 +8,6 @@ import (
|
|||||||
type UserBadge struct {
|
type UserBadge struct {
|
||||||
global.BaseModel
|
global.BaseModel
|
||||||
UserId string `gorm:"type:varchar(50);index;not null;column:user_id;comment:用户id" json:"userId"`
|
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"`
|
BadgeId string `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"`
|
AcquiredAt time.Time `gorm:"autoCreateTime;column:acquired_at;comment:获得时间" json:"acquiredAt"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,17 @@ type UserProfile struct {
|
|||||||
MiniOpenId string `gorm:"size:80;column:mini_open_id" json:"miniOpenId" form:"miniOpenId"`
|
MiniOpenId string `gorm:"size:80;column:mini_open_id" json:"miniOpenId" form:"miniOpenId"`
|
||||||
Nickname string `json:"nickname" gorm:"column:nick_name"`
|
Nickname string `json:"nickname" gorm:"column:nick_name"`
|
||||||
AvatarId string `json:"avatarId" gorm:"column:avatar_id"`
|
AvatarId string `json:"avatarId" gorm:"column:avatar_id"`
|
||||||
LevelId string `json:"levelId" gorm:"column:level_id"` // 当前等级id
|
LevelId string `json:"levelId" gorm:"column:level_id"` // 当前等级id
|
||||||
CurrentSunlight int64 `json:"currentSunlight" gorm:"column:current_sunlight"` // 当前持有阳光值 (可消耗)
|
CurrentSunlight int64 `json:"currentSunlight" gorm:"not null;default:0;column:current_sunlight"` // 当前持有阳光值 (可消耗)
|
||||||
TotalSunlight int64 `json:"totalSunlight" gorm:"column:total_sunlight"` // 历史累计阳光值 (用于计算等级)
|
TotalSunlight int64 `json:"totalSunlight" gorm:"not null;default:0;column:total_sunlight"` // 历史累计阳光值 (用于计算等级)
|
||||||
PlantCount int64 `json:"plantCount" gorm:"column:plant_count"`
|
PlantCount int64 `json:"plantCount" gorm:"not null;default:0;column:plant_count"`
|
||||||
CareCount int64 `json:"careCount" gorm:"column:care_count"`
|
CareCount int64 `json:"careCount" gorm:"not null;default:0;column:care_count"`
|
||||||
PostCount int64 `json:"postCount" gorm:"column:post_count"`
|
PostCount int64 `json:"postCount" gorm:"not null;default:0;column:post_count"`
|
||||||
|
WaterCount int64 `json:"waterCount" gorm:"not null;default:0;column:water_count"` // 浇水次数
|
||||||
|
FertilizeCount int64 `json:"fertilizeCount" gorm:"not null;default:0;column:fertilize_count"` // 施肥次数
|
||||||
|
RepotCount int64 `json:"repotCount" gorm:"not null;default:0;column:repot_count"` // 换盆次数
|
||||||
|
PruneCount int64 `json:"pruneCount" gorm:"not null;default:0;column:prune_count"` // 剪枝次数
|
||||||
|
PhotoCount int64 `json:"photoCount" gorm:"not null;default:0;column:photo_count"` // 拍照次数
|
||||||
Avatar *system.Oss `json:"avatar" gorm:"foreignKey:AvatarId"`
|
Avatar *system.Oss `json:"avatar" gorm:"foreignKey:AvatarId"`
|
||||||
Level *LevelConfig `json:"level" gorm:"foreignKey:LevelId"`
|
Level *LevelConfig `json:"level" gorm:"foreignKey:LevelId"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package plant
|
||||||
|
|
||||||
|
import "sundynix-go/global"
|
||||||
|
|
||||||
|
type UserStar struct {
|
||||||
|
global.BaseModel
|
||||||
|
UserId string `json:"userId" gorm:"index"`
|
||||||
|
Type int `json:"type" gorm:"index"` //1.百科 //2.社交动态
|
||||||
|
WikiId string `json:"wikiId" gorm:"index"`
|
||||||
|
PostId string `json:"postId" gorm:"index"`
|
||||||
|
Wiki *Wiki `json:"wiki" gorm:"foreignKey:WikiId"`
|
||||||
|
Post *Post `json:"post" gorm:"foreignKey:PostId"`
|
||||||
|
}
|
||||||
+2
-1
@@ -39,7 +39,8 @@ type Wiki struct {
|
|||||||
FloweringShape string `json:"floweringShape" form:"floweringShape" gorm:"size:100;column:flowering_shape;comment:开花形状"`
|
FloweringShape string `json:"floweringShape" form:"floweringShape" gorm:"size:100;column:flowering_shape;comment:开花形状"`
|
||||||
FlowerDiameter int `json:"flowerDiameter" form:"flowerDiameter" gorm:"size:10;column:flower_diameter;comment:花直径"`
|
FlowerDiameter int `json:"flowerDiameter" form:"flowerDiameter" gorm:"size:10;column:flower_diameter;comment:花直径"`
|
||||||
//果
|
//果
|
||||||
Fruit string `json:"fruit" form:"fruit" gorm:"size:200;column:fruit;comment:果实"`
|
Fruit string `json:"fruit" form:"fruit" gorm:"size:200;column:fruit;comment:果实"`
|
||||||
|
HasStar int `json:"hasStar" form:"hasStar" gorm:"-"`
|
||||||
|
|
||||||
//相关推荐
|
//相关推荐
|
||||||
RelatedWiki []*Wiki `gorm:"many2many:wiki_related;" json:"relatedWiki"`
|
RelatedWiki []*Wiki `gorm:"many2many:wiki_related;" json:"relatedWiki"`
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ func (c *OcrRouter) InitOcrRouter(Router *gin.RouterGroup) {
|
|||||||
{
|
{
|
||||||
ocrRouter.POST("/plant", ocrApi.ClassifyPlant)
|
ocrRouter.POST("/plant", ocrApi.ClassifyPlant)
|
||||||
ocrRouter.POST("/myClassifyLog", ocrApi.MyClassifyLog)
|
ocrRouter.POST("/myClassifyLog", ocrApi.MyClassifyLog)
|
||||||
|
ocrRouter.POST("/deleteClassifyLog", ocrApi.DeleteClassifyLog)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ func (p *PostRouter) InitPostRouter(Router *gin.RouterGroup) {
|
|||||||
postRouter.POST("page", postApi.PostPage) // 帖子列表
|
postRouter.POST("page", postApi.PostPage) // 帖子列表
|
||||||
postRouter.POST("myPost", postApi.MyPost) // 我的发布
|
postRouter.POST("myPost", postApi.MyPost) // 我的发布
|
||||||
postRouter.GET("like", postApi.LikePost) // 点赞或者取消点赞
|
postRouter.GET("like", postApi.LikePost) // 点赞或者取消点赞
|
||||||
|
postRouter.GET("star", postApi.StarPost) // 收藏或者取消收藏帖子
|
||||||
postRouter.POST("comment", postApi.CommentPost) // 评论
|
postRouter.POST("comment", postApi.CommentPost) // 评论
|
||||||
|
postRouter.POST("delete", postApi.DeletePost) // 删除帖子
|
||||||
//postRouter.POST("deleteComment", postApi.delementComment) // 取消评论
|
//postRouter.POST("deleteComment", postApi.delementComment) // 取消评论
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ type UserProfileRouter struct{}
|
|||||||
func (c *UserProfileRouter) 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)
|
||||||
userProfileRouter.GET("/detail", userProfileApi.ProfileDetail)
|
userProfileRouter.GET("detail", userProfileApi.ProfileDetail)
|
||||||
|
|
||||||
|
userProfileRouter.POST("star", userProfileApi.MyStars) //我的收藏
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,5 +12,8 @@ func (p *WikiRouter) InitWikiRouter(Router *gin.RouterGroup) {
|
|||||||
wikiRouter.POST("/page", wikiApi.WikiPage)
|
wikiRouter.POST("/page", wikiApi.WikiPage)
|
||||||
wikiRouter.GET("/detail", wikiApi.WikiDetail)
|
wikiRouter.GET("/detail", wikiApi.WikiDetail)
|
||||||
|
|
||||||
|
//用户端
|
||||||
|
wikiRouter.GET("/star", wikiApi.StarWiki) //收藏或者取消收藏
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+201
-62
@@ -1,6 +1,8 @@
|
|||||||
package plant
|
package plant
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
"sundynix-go/global"
|
"sundynix-go/global"
|
||||||
common "sundynix-go/model/commom/request"
|
common "sundynix-go/model/commom/request"
|
||||||
"sundynix-go/model/plant"
|
"sundynix-go/model/plant"
|
||||||
@@ -32,13 +34,14 @@ func (s *MyPlantService) AddPlant(req plantReq.CreateMyPlant, userId string) err
|
|||||||
var carePlans []*plant.CarePlan
|
var carePlans []*plant.CarePlan
|
||||||
for _, v := range req.CarePlans {
|
for _, v := range req.CarePlans {
|
||||||
carePlans = append(carePlans, &plant.CarePlan{
|
carePlans = append(carePlans, &plant.CarePlan{
|
||||||
UserId: userId,
|
UserId: userId,
|
||||||
Name: v.Name,
|
Name: v.Name,
|
||||||
Icon: v.Icon,
|
Icon: v.Icon,
|
||||||
Period: v.Period,
|
Period: v.Period,
|
||||||
|
TargetAction: v.TargetAction,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
//3.保存数据
|
//3.保存数据 myPlant钩子函数自动处理创建careTask
|
||||||
myPlant := plant.MyPlant{
|
myPlant := plant.MyPlant{
|
||||||
UserId: userId,
|
UserId: userId,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
@@ -150,9 +153,10 @@ func (s *MyPlantService) UpdatePlant(req plantReq.UpdateMyPlant) error {
|
|||||||
today := timer.GetZeroTime()
|
today := timer.GetZeroTime()
|
||||||
for _, plan := range req.CarePlans {
|
for _, plan := range req.CarePlans {
|
||||||
err = tx.Model(&plant.CarePlan{}).Where("id = ?", plan.Id).Updates(map[string]interface{}{
|
err = tx.Model(&plant.CarePlan{}).Where("id = ?", plan.Id).Updates(map[string]interface{}{
|
||||||
"icon": plan.Icon,
|
"icon": plan.Icon,
|
||||||
"name": plan.Name,
|
"name": plan.Name,
|
||||||
"period": plan.Period,
|
"period": plan.Period,
|
||||||
|
"target_action": plan.TargetAction,
|
||||||
}).Error
|
}).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -234,7 +238,8 @@ func (s *MyPlantService) TodayTask(userId string) ([]plantRes.PlantTaskVO, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CompleteTask 完成任务
|
// CompleteTask 完成任务
|
||||||
func (s *MyPlantService) CompleteTask(req plantReq.CompleteTask, userId string) error {
|
func (s *MyPlantService) CompleteTask(req plantReq.CompleteTask, userId string) (*plantRes.TaskCompletionResult, error) {
|
||||||
|
var result plantRes.TaskCompletionResult
|
||||||
err := global.DB.Transaction(func(tx *gorm.DB) error {
|
err := global.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
var task plant.CareTask
|
var task plant.CareTask
|
||||||
if err := tx.Where("id = ?", req.TaskId).First(&task).Error; err != nil {
|
if err := tx.Where("id = ?", req.TaskId).First(&task).Error; err != nil {
|
||||||
@@ -257,13 +262,14 @@ func (s *MyPlantService) CompleteTask(req plantReq.CompleteTask, userId string)
|
|||||||
today := timer.GetZeroTime()
|
today := timer.GetZeroTime()
|
||||||
nextDueDate := today.AddDate(0, 0, plan.Period)
|
nextDueDate := today.AddDate(0, 0, plan.Period)
|
||||||
newTask := plant.CareTask{
|
newTask := plant.CareTask{
|
||||||
UserId: plan.UserId,
|
UserId: plan.UserId,
|
||||||
PlantId: plan.PlantId,
|
PlantId: plan.PlantId,
|
||||||
PlanId: plan.Id,
|
PlanId: plan.Id,
|
||||||
Name: plan.Name,
|
Name: plan.Name,
|
||||||
Icon: plan.Icon,
|
Icon: plan.Icon,
|
||||||
DueDate: nextDueDate,
|
TargetAction: plan.TargetAction,
|
||||||
Status: 1,
|
DueDate: nextDueDate,
|
||||||
|
Status: 1,
|
||||||
}
|
}
|
||||||
if err := tx.Create(&newTask).Error; err != nil {
|
if err := tx.Create(&newTask).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -280,51 +286,134 @@ func (s *MyPlantService) CompleteTask(req plantReq.CompleteTask, userId string)
|
|||||||
if err := tx.Create(&record).Error; err != nil {
|
if err := tx.Create(&record).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
//4.等级与阳光计算
|
||||||
|
var profile plant.UserProfile
|
||||||
|
if err := tx.Set("gorm:query_option", "FOR UPDATE").Where("user_id = ?", userId).First(&profile).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fieldMap := map[string]string{
|
||||||
|
"ACT_WATER": "water_count",
|
||||||
|
"ACT_FERTILIZE": "fertilize_count",
|
||||||
|
"ACT_REPOT": "repot_count",
|
||||||
|
"ACT_PRUNE": "prune_count",
|
||||||
|
}
|
||||||
|
column, ok := fieldMap[task.TargetAction]
|
||||||
|
if !ok {
|
||||||
|
column = "care_count" // 默认备用
|
||||||
|
}
|
||||||
|
const TaskReward = 50
|
||||||
|
newTotalSunlight := profile.TotalSunlight + TaskReward
|
||||||
|
newCurrentSunlight := profile.CurrentSunlight + TaskReward
|
||||||
|
// 5. 等级判定 (根据累计阳光查出当前应有的等级)
|
||||||
|
var latestLevel plant.LevelConfig
|
||||||
|
if err := tx.Where("min_sunlight <= ?", newTotalSunlight).
|
||||||
|
Order("min_sunlight DESC").First(&latestLevel).Error; err != nil {
|
||||||
|
return errors.New("等级配置异常")
|
||||||
|
}
|
||||||
|
result.CurrentLevel = &latestLevel
|
||||||
|
result.IsLevelUp = latestLevel.Id != profile.LevelId
|
||||||
|
// 6. 执行 Profile 更新 (任务阳光 + 计数自增 + 等级同步)
|
||||||
|
profileData := map[string]interface{}{
|
||||||
|
column: gorm.Expr(column + " + 1"),
|
||||||
|
"current_sunlight": newCurrentSunlight,
|
||||||
|
"total_sunlight": newTotalSunlight,
|
||||||
|
"level_id": latestLevel.Id,
|
||||||
|
}
|
||||||
|
if err := tx.Model(&plant.UserProfile{}).Where("user_id = ?", userId).Updates(profileData).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// 7. 徽章判定逻辑
|
||||||
|
// 7.1 计算当前动作的最新逻辑数值
|
||||||
|
var currentActionVal int64
|
||||||
|
switch task.TargetAction {
|
||||||
|
case "ACT_WATER":
|
||||||
|
currentActionVal = profile.WaterCount + 1
|
||||||
|
case "ACT_FERTILIZE":
|
||||||
|
currentActionVal = profile.FertilizeCount + 1
|
||||||
|
case "ACT_REPOT":
|
||||||
|
currentActionVal = profile.RepotCount + 1
|
||||||
|
case "ACT_PRUNE":
|
||||||
|
currentActionVal = profile.PruneCount + 1
|
||||||
|
default:
|
||||||
|
currentActionVal = 0
|
||||||
|
}
|
||||||
|
// 7.2 查询已拥有的徽章 ID (用于去重)
|
||||||
|
var ownedBadgeIds []string
|
||||||
|
tx.Model(&plant.UserBadge{}).Where("user_id = ?", userId).Pluck("badge_id", &ownedBadgeIds)
|
||||||
|
ownedMap := make(map[string]bool)
|
||||||
|
for _, id := range ownedBadgeIds {
|
||||||
|
ownedMap[id] = true
|
||||||
|
}
|
||||||
|
// 7.3 筛选当前 Action 下满足条件的最高级徽章
|
||||||
|
var badgeConfigs []plant.BadgeConfig
|
||||||
|
tx.Where("target_action = ?", task.TargetAction).Preload("Icon").Find(&badgeConfigs)
|
||||||
|
|
||||||
|
for i := range badgeConfigs {
|
||||||
|
conf := &badgeConfigs[i]
|
||||||
|
// 如果没拿过且数值达标
|
||||||
|
if !ownedMap[conf.Id] && currentActionVal >= conf.Threshold {
|
||||||
|
// 寻找 Tier 最大的那个
|
||||||
|
if result.NewBadge == nil || conf.Tier > result.NewBadge.Tier {
|
||||||
|
result.NewBadge = conf
|
||||||
|
result.IsGetBadge = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 8. 奖励入库:如果产生了新徽章
|
||||||
|
if result.NewBadge != nil {
|
||||||
|
// 写入获得记录
|
||||||
|
ub := plant.UserBadge{
|
||||||
|
UserId: userId,
|
||||||
|
BadgeId: result.NewBadge.Id, // 注意这里 Id 是 string
|
||||||
|
}
|
||||||
|
if err := tx.Create(&ub).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// 发放徽章额外奖励阳光
|
||||||
|
if err := tx.Model(&plant.UserProfile{}).Where("user_id = ?", userId).
|
||||||
|
Update("current_sunlight", gorm.Expr("current_sunlight + ?", result.NewBadge.RewardSunlight)).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err == nil {
|
return &result, err
|
||||||
go func() {
|
|
||||||
//5.更新用户profile
|
|
||||||
var profile plant.UserProfile
|
|
||||||
if asyncErr := global.DB.Where("user_id = ?", userId).First(&profile).Error; err != nil {
|
|
||||||
global.Logger.Error("完成任务异步操作-----查询用户profile失败", zap.Error(asyncErr))
|
|
||||||
}
|
|
||||||
totalSunlight := profile.TotalSunlight + 50
|
|
||||||
updateData := map[string]interface{}{
|
|
||||||
"care_count": profile.CareCount + 1,
|
|
||||||
"current_sunlight": profile.CurrentSunlight + 50,
|
|
||||||
"total_sunlight": totalSunlight,
|
|
||||||
}
|
|
||||||
//5.1 判断是否到达下个等级
|
|
||||||
var currentLevel plant.LevelConfig
|
|
||||||
levelErr := global.DB.Where("min_sunlight <= ?", totalSunlight).Order("min_sunlight DESC").First(¤tLevel).Error
|
|
||||||
if levelErr != nil {
|
|
||||||
global.Logger.Error("完成任务异步操作-----查询用户等级失败", zap.Error(levelErr))
|
|
||||||
}
|
|
||||||
updateData["level_id"] = currentLevel.Id
|
|
||||||
//5.2 更新用户profile
|
|
||||||
updateProfileErr := global.DB.Model(&plant.UserProfile{}).Where("user_id = ?", userId).Updates(updateData).Error
|
|
||||||
if updateProfileErr != nil {
|
|
||||||
global.Logger.Error("完成任务异步操作-----更新用户profile失败", zap.Error(updateProfileErr))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePlants 删除植物
|
// DeletePlants 删除植物
|
||||||
func (s *MyPlantService) DeletePlants(req common.IdsReq) error {
|
func (s *MyPlantService) DeletePlants(req common.IdsReq) error {
|
||||||
return global.DB.Transaction(func(tx *gorm.DB) error {
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
var plants []plant.MyPlant
|
var imgIds []string
|
||||||
if err := tx.Where("id in ?", req.Ids).Find(&plants).Error; err != nil {
|
tx.Table("sundynix_my_plant_oss").Where("my_plant_id IN ?", req.Ids).Pluck("oss_id", &imgIds)
|
||||||
|
// 2. 清理中间表记录 (解开多对多关系)
|
||||||
|
// 使用 Exec 直接操作中间表比循环 Clear 快得多
|
||||||
|
if err := tx.Exec("DELETE FROM sundynix_my_plant_oss WHERE my_plant_id IN ?", req.Ids).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// 删除图片 养护计划 养护任务 养护记录 成长记录
|
// 3. 物理删除图片记录本身
|
||||||
err := tx.Select("ImgList", "CarePlans", "CareTasks", "CareRecords").Unscoped().Delete(&plants).Error
|
if len(imgIds) > 0 {
|
||||||
if err != nil {
|
if err := tx.Unscoped().Where("id IN ?", imgIds).Delete(&system.Oss{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//4.批量删除养护计划 养护任务 养护记录 成长记录
|
||||||
|
if err := tx.Unscoped().Where("plant_id in ?", req.Ids).Delete(&plant.CarePlan{}).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := tx.Unscoped().Where("plant_id in ?", req.Ids).Delete(&plant.CareTask{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.Unscoped().Where("plant_id in ?", req.Ids).Delete(&plant.CareRecord{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.Unscoped().Where("plant_id in ?", req.Ids).Delete(&plant.GrowthRecord{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//5.删除植物本身
|
||||||
|
if err := tx.Unscoped().Where("id in ?", req.Ids).Delete(&plant.MyPlant{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -365,11 +454,12 @@ func (s *MyPlantService) AddCarePlan(req plantReq.AddPlans) error {
|
|||||||
}
|
}
|
||||||
//1.新增计划
|
//1.新增计划
|
||||||
newPlan := plant.CarePlan{
|
newPlan := plant.CarePlan{
|
||||||
UserId: myPlant.UserId,
|
UserId: myPlant.UserId,
|
||||||
PlantId: myPlant.Id,
|
PlantId: myPlant.Id,
|
||||||
Name: plan.Name,
|
Name: plan.Name,
|
||||||
Icon: plan.Icon,
|
Icon: plan.Icon,
|
||||||
Period: plan.Period,
|
Period: plan.Period,
|
||||||
|
TargetAction: plan.TargetAction,
|
||||||
}
|
}
|
||||||
err = tx.Create(&newPlan).Error
|
err = tx.Create(&newPlan).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -379,13 +469,14 @@ func (s *MyPlantService) AddCarePlan(req plantReq.AddPlans) error {
|
|||||||
today := timer.GetZeroTime()
|
today := timer.GetZeroTime()
|
||||||
dueDate := today.AddDate(0, 0, plan.Period)
|
dueDate := today.AddDate(0, 0, plan.Period)
|
||||||
task := plant.CareTask{
|
task := plant.CareTask{
|
||||||
UserId: myPlant.UserId,
|
UserId: myPlant.UserId,
|
||||||
PlantId: myPlant.Id,
|
PlantId: myPlant.Id,
|
||||||
PlanId: newPlan.Id,
|
PlanId: newPlan.Id,
|
||||||
Name: plan.Name,
|
Name: plan.Name,
|
||||||
Icon: plan.Icon,
|
Icon: plan.Icon,
|
||||||
DueDate: dueDate,
|
TargetAction: plan.TargetAction,
|
||||||
Status: 1,
|
DueDate: dueDate,
|
||||||
|
Status: 1,
|
||||||
}
|
}
|
||||||
err = tx.Create(&task).Error
|
err = tx.Create(&task).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -459,3 +550,51 @@ func (s *MyPlantService) AddGrowthRecord(req plantReq.CreateGrowthRecord, userId
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 完成任务后异步执行 更新用户等级 sunlight
|
||||||
|
func (s *MyPlantService) handleCompleteTaskThenUpdateProfile(ctx context.Context, userId string) {
|
||||||
|
//5.更新用户profile
|
||||||
|
var profile plant.UserProfile
|
||||||
|
if asyncErr := global.DB.Where("user_id = ?", userId).First(&profile).Error; asyncErr != nil {
|
||||||
|
global.Logger.Error("完成任务异步操作-----查询用户profile失败", zap.Error(asyncErr))
|
||||||
|
}
|
||||||
|
totalSunlight := profile.TotalSunlight + 50
|
||||||
|
updateData := map[string]interface{}{
|
||||||
|
"care_count": profile.CareCount + 1,
|
||||||
|
"current_sunlight": profile.CurrentSunlight + 50,
|
||||||
|
"total_sunlight": totalSunlight,
|
||||||
|
}
|
||||||
|
//5.1 判断是否到达下个等级
|
||||||
|
var currentLevel plant.LevelConfig
|
||||||
|
levelErr := global.DB.Where("min_sunlight <= ?", totalSunlight).Order("min_sunlight DESC").First(¤tLevel).Error
|
||||||
|
if levelErr != nil {
|
||||||
|
global.Logger.Error("完成任务异步操作-----查询用户等级失败", zap.Error(levelErr))
|
||||||
|
}
|
||||||
|
updateData["level_id"] = currentLevel.Id
|
||||||
|
//5.2 更新用户profile
|
||||||
|
updateProfileErr := global.DB.Model(&plant.UserProfile{}).Where("user_id = ?", userId).Updates(updateData).Error
|
||||||
|
if updateProfileErr != nil {
|
||||||
|
global.Logger.Error("完成任务异步操作-----更新用户profile失败", zap.Error(updateProfileErr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo 完成任务后异步执行 处理徽章
|
||||||
|
func (s *MyPlantService) handleCompleteTaskThenHandleBadge(ctx context.Context, taskId, userId string) {
|
||||||
|
//1.查询任务
|
||||||
|
var task plant.CareTask
|
||||||
|
if asyncErr := global.DB.Where("id = ?", taskId).First(&task).Error; asyncErr != nil {
|
||||||
|
global.Logger.Error("完成任务异步操作-----查询任务失败", zap.Error(asyncErr))
|
||||||
|
}
|
||||||
|
//2.查询徽章
|
||||||
|
var badges []plant.BadgeConfig
|
||||||
|
if asyncErr := global.DB.Where("target_action = ?", task.TargetAction).Order("tier ASC").Find(&badges).Error; asyncErr != nil {
|
||||||
|
global.Logger.Error("完成任务异步操作-----查询徽章失败", zap.Error(asyncErr))
|
||||||
|
}
|
||||||
|
//3.用户的徽章
|
||||||
|
var userBadges []plant.UserBadge
|
||||||
|
if asyncErr := global.DB.Where("user_id = ?", userId).Find(&userBadges).Error; asyncErr != nil {
|
||||||
|
global.Logger.Error("完成任务异步操作-----查询用户徽章失败", zap.Error(asyncErr))
|
||||||
|
}
|
||||||
|
//4.用户个人资料
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -114,6 +114,11 @@ func (s *OcrService) MyClassifyLog(req request.PageInfo, id string) (list interf
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteClassifyLog 删除植物识别记录
|
||||||
|
func (s *OcrService) DeleteClassifyLog(req request.IdsReq, userId string) error {
|
||||||
|
return global.DB.Where("id in ? and user_id = ?", req.Ids, userId).Unscoped().Delete(&plant.ClassifyRecord{}).Error
|
||||||
|
}
|
||||||
|
|
||||||
func getAccessToken() string {
|
func getAccessToken() string {
|
||||||
rpcUrl := "https://aip.baidubce.com/oauth/2.0/token"
|
rpcUrl := "https://aip.baidubce.com/oauth/2.0/token"
|
||||||
postData := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s", global.Config.BaiduImgClassify.ApiKey, global.Config.BaiduImgClassify.SecretKey)
|
postData := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s", global.Config.BaiduImgClassify.ApiKey, global.Config.BaiduImgClassify.SecretKey)
|
||||||
|
|||||||
+104
-7
@@ -62,11 +62,6 @@ func (s *PostService) PostPage(req plantReq.PostPage, userId string) (list inter
|
|||||||
Preload("Publisher", func(db *gorm.DB) *gorm.DB {
|
Preload("Publisher", func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Preload("Avatar")
|
return db.Preload("Avatar")
|
||||||
}).
|
}).
|
||||||
Preload("LikeList", func(db *gorm.DB) *gorm.DB {
|
|
||||||
return db.Preload("Liker", func(db *gorm.DB) *gorm.DB {
|
|
||||||
return db.Preload("Avatar")
|
|
||||||
})
|
|
||||||
}).
|
|
||||||
Preload("CommentList", func(db *gorm.DB) *gorm.DB {
|
Preload("CommentList", func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Preload("Commentator", func(db *gorm.DB) *gorm.DB {
|
return db.Preload("Commentator", func(db *gorm.DB) *gorm.DB {
|
||||||
return db.Preload("Avatar")
|
return db.Preload("Avatar")
|
||||||
@@ -96,11 +91,21 @@ func (s *PostService) PostPage(req plantReq.PostPage, userId string) (list inter
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
//批量查询当前用户的收藏
|
||||||
|
var stars []*plant.UserStar
|
||||||
|
err = global.DB.Where("user_id = ? and post_id in ?", userId, postIds).Find(&stars).Error
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
// 构建id映射
|
// 构建id映射
|
||||||
likesMap := make(map[string]bool)
|
likesMap := make(map[string]bool)
|
||||||
for _, v := range postLikeList {
|
for _, v := range postLikeList {
|
||||||
likesMap[v.PostId] = true
|
likesMap[v.PostId] = true
|
||||||
}
|
}
|
||||||
|
starsMap := make(map[string]bool)
|
||||||
|
for _, v := range stars {
|
||||||
|
starsMap[v.PostId] = true
|
||||||
|
}
|
||||||
// 是否点赞
|
// 是否点赞
|
||||||
for i := range posts {
|
for i := range posts {
|
||||||
if likesMap[posts[i].Id] {
|
if likesMap[posts[i].Id] {
|
||||||
@@ -109,6 +114,11 @@ func (s *PostService) PostPage(req plantReq.PostPage, userId string) (list inter
|
|||||||
posts[i].HasLiked = 0
|
posts[i].HasLiked = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if starsMap[posts[i].Id] {
|
||||||
|
posts[i].HasStar = 1
|
||||||
|
} else {
|
||||||
|
posts[i].HasStar = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return posts, total, err
|
return posts, total, err
|
||||||
@@ -169,7 +179,6 @@ func (s *PostService) MyPost(req plantReq.PostPage, userId string) (list interfa
|
|||||||
} else {
|
} else {
|
||||||
posts[i].HasLiked = 0
|
posts[i].HasLiked = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return posts, total, err
|
return posts, total, err
|
||||||
@@ -210,7 +219,9 @@ func (s *PostService) LikePost(userId, postId, class string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = tx.Model(&post).Update("like_count", post.LikeCount-1).Error
|
err = tx.Model(&post).
|
||||||
|
Where("like_count > 0"). // 只有大于 0 才会执行减法
|
||||||
|
Update("like_count", post.LikeCount-1).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -244,3 +255,89 @@ func (s *PostService) CommentPost(req plantReq.CreateComment, userId string) err
|
|||||||
return tx.Create(&comment).Error
|
return tx.Create(&comment).Error
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeletePost 删除帖子
|
||||||
|
func (s *PostService) DeletePost(ids []string) error {
|
||||||
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
var imgIds []string
|
||||||
|
tx.Table("sundynix_post_oss").Where("post_id IN ?", ids).Pluck("oss_id", &imgIds)
|
||||||
|
|
||||||
|
// 2. 清理中间表记录 (解开多对多关系)
|
||||||
|
// 使用 Exec 直接操作中间表比循环 Clear 快得多
|
||||||
|
if err := tx.Exec("DELETE FROM sundynix_post_oss WHERE post_id IN ?", ids).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 物理删除图片记录本身
|
||||||
|
if len(imgIds) > 0 {
|
||||||
|
if err := tx.Unscoped().Where("id IN ?", imgIds).Delete(&system.Oss{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 4. 批量删除点赞 (PostLike)
|
||||||
|
if err := tx.Unscoped().Where("post_id IN ?", ids).Delete(&plant.PostLike{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// 5. 批量删除评论 (PostComment)
|
||||||
|
if err := tx.Unscoped().Where("post_id IN ?", ids).Delete(&plant.PostComment{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 最后删除主表 Post
|
||||||
|
if err := tx.Unscoped().Where("id IN ?", ids).Delete(&plant.Post{}).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// StarPost 收藏帖子
|
||||||
|
func (s *PostService) StarPost(userId string, postId string, class string) error {
|
||||||
|
if class == "1" {
|
||||||
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
var post plant.Post
|
||||||
|
err := tx.Where("id = ?", postId).First(&post).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//1.更新点赞数
|
||||||
|
err = tx.Model(&post).Update("star_count", post.LikeCount+1).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//2.添加到我的收藏
|
||||||
|
star := plant.UserStar{
|
||||||
|
UserId: userId,
|
||||||
|
Type: 2,
|
||||||
|
PostId: postId,
|
||||||
|
}
|
||||||
|
return tx.Create(&star).Error
|
||||||
|
})
|
||||||
|
} else if class == "2" {
|
||||||
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
var star plant.UserStar
|
||||||
|
err := tx.Where("post_id = ? and user_id = ?", postId, userId).First(&star).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//1.更新收藏数
|
||||||
|
var post plant.Post
|
||||||
|
err = tx.Where("id = ?", postId).First(&post).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = tx.Model(&post).
|
||||||
|
Where("star_count > ?", 0). // 只有大于 0 才会执行减法
|
||||||
|
Update("star_count", gorm.Expr("star_count - 1")).
|
||||||
|
Error
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//2.删除收藏
|
||||||
|
return tx.Unscoped().Delete(&star).Error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,3 +45,29 @@ func (s *UserProfileService) ProfileDetail(userId string) (plant.UserProfile, er
|
|||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MyStars 我的收藏
|
||||||
|
func (s *UserProfileService) MyStars(req plantReq.StarsPageReq, userId string) (list interface{}, total int64, err error) {
|
||||||
|
limit := req.PageSize
|
||||||
|
offset := req.PageSize * (req.Current - 1)
|
||||||
|
db := global.DB.Model(&plant.UserStar{}).Preload("Wiki", func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Preload("ImgList", func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Order("created_at desc")
|
||||||
|
})
|
||||||
|
}).Preload("Post", func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Preload("ImgList", func(db *gorm.DB) *gorm.DB {
|
||||||
|
return db.Order("created_at desc")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
var stars []*plant.UserStar
|
||||||
|
db = db.Where("user_id = ?", userId)
|
||||||
|
if req.Class != 0 {
|
||||||
|
db = db.Where("type = ?", req.Class) //1.百科 //2.社交动态
|
||||||
|
}
|
||||||
|
err = db.Count(&total).Error
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&stars).Error
|
||||||
|
return stars, total, err
|
||||||
|
}
|
||||||
|
|||||||
+65
-2
@@ -149,7 +149,7 @@ func (s *WikiService) UpdateWiki(req plantReq.UpdateWiki) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WikiPage 分页
|
// WikiPage 分页
|
||||||
func (s *WikiService) WikiPage(req plantReq.WikiPage) (list interface{}, total int64, err error) {
|
func (s *WikiService) WikiPage(req plantReq.WikiPage, userId string) (list interface{}, total int64, err error) {
|
||||||
limit := req.PageSize
|
limit := req.PageSize
|
||||||
offset := req.PageSize * (req.Current - 1)
|
offset := req.PageSize * (req.Current - 1)
|
||||||
db := global.DB.Model(&plant.Wiki{}).Preload("ImgList", func(db *gorm.DB) *gorm.DB {
|
db := global.DB.Model(&plant.Wiki{}).Preload("ImgList", func(db *gorm.DB) *gorm.DB {
|
||||||
@@ -173,11 +173,35 @@ func (s *WikiService) WikiPage(req plantReq.WikiPage) (list interface{}, total i
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&wikis).Error
|
err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&wikis).Error
|
||||||
|
|
||||||
|
// 优化 N+1 查询
|
||||||
|
var wikiIds []string
|
||||||
|
for _, v := range wikis {
|
||||||
|
wikiIds = append(wikiIds, v.Id)
|
||||||
|
}
|
||||||
|
//批量查询当前用户的收藏
|
||||||
|
var stars []*plant.UserStar
|
||||||
|
err = global.DB.Where("user_id = ? and wiki_id in ?", userId, wikiIds).Find(&stars).Error
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
starsMap := make(map[string]bool)
|
||||||
|
for _, v := range stars {
|
||||||
|
starsMap[v.WikiId] = true
|
||||||
|
}
|
||||||
|
// 是否收藏
|
||||||
|
for i := range wikis {
|
||||||
|
if starsMap[wikis[i].Id] {
|
||||||
|
wikis[i].HasStar = 1
|
||||||
|
} else {
|
||||||
|
wikis[i].HasStar = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
return wikis, total, err
|
return wikis, total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detail 详情
|
// Detail 详情
|
||||||
func (s *WikiService) Detail(id string) (w plant.Wiki, err error) {
|
func (s *WikiService) Detail(id, userId string) (w plant.Wiki, err error) {
|
||||||
var wiki plant.Wiki
|
var wiki plant.Wiki
|
||||||
err = global.DB.Where("id = ?", id).
|
err = global.DB.Where("id = ?", id).
|
||||||
Preload("Classes", func(db *gorm.DB) *gorm.DB {
|
Preload("Classes", func(db *gorm.DB) *gorm.DB {
|
||||||
@@ -193,5 +217,44 @@ func (s *WikiService) Detail(id string) (w plant.Wiki, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var stars []plant.UserStar
|
||||||
|
err = global.DB.Where("user_id = ? and wiki_id = ?", userId, id).Find(&stars).Error
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(stars) > 0 {
|
||||||
|
wiki.HasStar = 1
|
||||||
|
}
|
||||||
return wiki, nil
|
return wiki, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StarWiki 收藏
|
||||||
|
func (s *WikiService) StarWiki(userId, wikiId, class string) error {
|
||||||
|
if class == "1" {
|
||||||
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
var wiki plant.Wiki
|
||||||
|
err := tx.Where("id = ?", wikiId).First(&wiki).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//2.添加到我的收藏
|
||||||
|
star := plant.UserStar{
|
||||||
|
UserId: userId,
|
||||||
|
Type: 1,
|
||||||
|
WikiId: wikiId,
|
||||||
|
}
|
||||||
|
return tx.Create(&star).Error
|
||||||
|
})
|
||||||
|
} else if class == "2" {
|
||||||
|
return global.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
|
var star plant.UserStar
|
||||||
|
err := tx.Where("wiki_id = ? and user_id = ?", wikiId, userId).First(&star).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//2.删除收藏
|
||||||
|
return tx.Unscoped().Delete(&star).Error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package system
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sundynix-go/global"
|
"sundynix-go/global"
|
||||||
"sundynix-go/utils"
|
"sundynix-go/utils/timer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type JwtService struct{}
|
type JwtService struct{}
|
||||||
@@ -12,7 +12,7 @@ var JwtServiceApp = new(JwtService)
|
|||||||
|
|
||||||
// 登出,禁用jwt
|
// 登出,禁用jwt
|
||||||
func (s *JwtService) PutBlacklist(userId string, token string) (err error) {
|
func (s *JwtService) PutBlacklist(userId string, token string) (err error) {
|
||||||
expire, err := utils.ParseDuration(global.Config.JWT.ExpiresTime)
|
expire, err := timer.ParseDuration(global.Config.JWT.ExpiresTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,9 +104,10 @@ func SendCareMsg() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if smr.Errcode != 0 {
|
if smr.Errcode != 0 {
|
||||||
|
global.Logger.Error("订阅消息发送失败!" + userId + "open-id" + user.MiniOpenId)
|
||||||
return fmt.Errorf("微信服务器返回错误: errcode=%d, errmsg=%s", smr.Errcode, smr.Errmsg)
|
return fmt.Errorf("微信服务器返回错误: errcode=%d, errmsg=%s", smr.Errcode, smr.Errmsg)
|
||||||
}
|
}
|
||||||
global.Logger.Info("订阅消息发送成功!")
|
global.Logger.Info("订阅消息发送成功!" + userId + "open-id" + user.MiniOpenId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-13
@@ -2,37 +2,63 @@ package async
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"runtime/debug"
|
||||||
"sundynix-go/global"
|
"sundynix-go/global"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AsyncTask 定义了异步任务的函数原型
|
|
||||||
type AsyncTask func(ctx context.Context)
|
type AsyncTask func(ctx context.Context)
|
||||||
|
|
||||||
// TaskRunner 任务收集器
|
type namedTask struct {
|
||||||
|
name string
|
||||||
|
fn AsyncTask
|
||||||
|
}
|
||||||
|
|
||||||
type TaskRunner struct {
|
type TaskRunner struct {
|
||||||
tasks []AsyncTask
|
mu sync.Mutex
|
||||||
|
tasks []namedTask
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add 添加一个任务到队列中
|
// Add 添加任务
|
||||||
func (tr *TaskRunner) Add(task AsyncTask) {
|
func (tr *TaskRunner) Add(name string, task AsyncTask) {
|
||||||
tr.tasks = append(tr.tasks, task)
|
if task == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tr.mu.Lock()
|
||||||
|
defer tr.mu.Unlock()
|
||||||
|
tr.tasks = append(tr.tasks, namedTask{name: name, fn: task})
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunAll 安全地启动所有任务
|
// RunAll 安全执行
|
||||||
func (tr *TaskRunner) RunAll() {
|
func (tr *TaskRunner) RunAll() {
|
||||||
for _, task := range tr.tasks {
|
tr.mu.Lock()
|
||||||
t := task // 避免闭包变量捕获问题
|
todoTasks := tr.tasks
|
||||||
|
tr.tasks = nil
|
||||||
|
tr.mu.Unlock()
|
||||||
|
|
||||||
|
for _, task := range todoTasks {
|
||||||
|
t := task
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
global.Logger.Info("[AsyncError] 任务执行崩溃", zap.Any("recover", r))
|
// 使用全局 Zap 记录结构化日志
|
||||||
|
// 这里的 global.Logger 替换为你实际的全局变量名
|
||||||
|
global.Logger.Error("异步任务异常崩溃",
|
||||||
|
zap.String("task_name", t.name),
|
||||||
|
zap.Any("panic_info", r),
|
||||||
|
zap.String("stack", string(debug.Stack())),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
// 异步任务通常使用 Background,避免受主请求超时影响
|
|
||||||
// 也可以自定义一个更长的超时 context
|
// 异步任务执行,设置独立的超时控制
|
||||||
t(context.Background())
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
t.fn(ctx)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -4,7 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"sundynix-go/global"
|
"sundynix-go/global"
|
||||||
"sundynix-go/model/system/request"
|
"sundynix-go/model/system/request"
|
||||||
"sundynix-go/utils"
|
"sundynix-go/utils/timer"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
@@ -32,8 +32,8 @@ func NewJWT() *JWT {
|
|||||||
|
|
||||||
// CreateClaims 创建Claims
|
// CreateClaims 创建Claims
|
||||||
func (j *JWT) CreateClaims(baseClaims request.BaseClaims) request.CustomClaims {
|
func (j *JWT) CreateClaims(baseClaims request.BaseClaims) request.CustomClaims {
|
||||||
bf, _ := utils.ParseDuration(global.Config.JWT.BufferTime)
|
bf, _ := timer.ParseDuration(global.Config.JWT.BufferTime)
|
||||||
ep, _ := utils.ParseDuration(global.Config.JWT.ExpiresTime)
|
ep, _ := timer.ParseDuration(global.Config.JWT.ExpiresTime)
|
||||||
claims := request.CustomClaims{
|
claims := request.CustomClaims{
|
||||||
BaseClaims: baseClaims,
|
BaseClaims: baseClaims,
|
||||||
BufferTime: int64(bf / time.Second), // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
|
BufferTime: int64(bf / time.Second), // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package utils
|
package timer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
|
|
||||||
// GetMiniAccessToken 获取小程序的access_token
|
// GetMiniAccessToken 获取小程序的access_token
|
||||||
func GetMiniAccessToken() string {
|
func GetMiniAccessToken() string {
|
||||||
ak, err := global.Redis.Get(context.Background(), "mini_access_token").Result()
|
ak, err := global.Redis.Get(context.Background(), "zeeq_mini_access_token").Result()
|
||||||
if errors.Is(err, redis.Nil) {
|
if errors.Is(err, redis.Nil) {
|
||||||
// 从微信服务器获取
|
// 从微信服务器获取
|
||||||
//重新从微信服务器获取
|
//重新从微信服务器获取
|
||||||
@@ -44,7 +44,7 @@ func GetMiniAccessToken() string {
|
|||||||
}
|
}
|
||||||
ak = data["access_token"].(string)
|
ak = data["access_token"].(string)
|
||||||
ex := data["expires_in"].(float64)
|
ex := data["expires_in"].(float64)
|
||||||
global.Redis.Set(context.Background(), "mini_access_token", ak, time.Duration(ex)*time.Second) //秒
|
global.Redis.Set(context.Background(), "zeeq_mini_access_token", ak, time.Duration(ex)*time.Second) //秒
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Fatalf("Error getting access token from Redis: %s", err)
|
log.Fatalf("Error getting access token from Redis: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user