包含前端(Vue3 + VueFlow 画布)、后端(Go)、文档体系。 - 工作台画布:节点拖放、连线模式、右键菜单、AI 助手 - 后端:连接器 API、专员种子数据 - 导航:左侧导航、工坊、市场、控制台
91 lines
2.9 KiB
Go
91 lines
2.9 KiB
Go
package api
|
||
|
||
import (
|
||
"time"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"gorm.io/gorm"
|
||
|
||
"eaisalestrain/backend/internal/middleware"
|
||
"eaisalestrain/backend/internal/model"
|
||
"eaisalestrain/backend/internal/store"
|
||
"eaisalestrain/backend/internal/web"
|
||
)
|
||
|
||
// —— 积分规则(游戏化成长值,集中一处便于调整,见 docs/changelog.md 待确认项)——
|
||
const (
|
||
ptFirstCompany = 10 // 首次浏览公司介绍
|
||
ptFirstProduct = 2 // 首次浏览单个产品
|
||
ptFirstCourse = 5 // 首次浏览单门课程
|
||
ptSelfTestSubmit = 5 // 自测提交一次
|
||
ptFormalPass = 50 // 正式考试通过
|
||
ptMistakeResolved = 3 // 错题标记已掌握
|
||
)
|
||
|
||
// awardPoints 记录积分流水并累加到 user.learning_points(points<=0 直接忽略,避免负分刷分)。
|
||
func awardPoints(userID uint, eventType string, points int, refType string, refID uint) {
|
||
if userID == 0 || points <= 0 {
|
||
return
|
||
}
|
||
store.DB.Create(&model.PointEvent{
|
||
UserID: userID,
|
||
EventType: eventType,
|
||
Points: points,
|
||
RefType: refType,
|
||
RefID: refID,
|
||
})
|
||
store.DB.Model(&model.User{}).Where("id = ?", userID).
|
||
UpdateColumn("learning_points", gorm.Expr("learning_points + ?", points))
|
||
}
|
||
|
||
// awardFirstView 首次浏览公司/产品/课程加分(由 RecordLearningProgress 幂等触发)。
|
||
func awardFirstView(userID uint, itemType string, itemID uint) {
|
||
switch itemType {
|
||
case "company":
|
||
awardPoints(userID, "first_company", ptFirstCompany, itemType, itemID)
|
||
case "product":
|
||
awardPoints(userID, "first_product", ptFirstProduct, itemType, itemID)
|
||
case "course":
|
||
awardPoints(userID, "first_course", ptFirstCourse, itemType, itemID)
|
||
}
|
||
}
|
||
|
||
// MyPoints GET /api/points/me —— 我的积分 + 最近积分流水
|
||
func MyPoints(c *gin.Context) {
|
||
u := middleware.CurrentUser(c)
|
||
if u == nil {
|
||
web.Fail(c, web.NewAuthError("未登录"))
|
||
return
|
||
}
|
||
var total int
|
||
store.DB.Raw(`SELECT COALESCE(SUM(points), 0) FROM point_event WHERE user_id = ?`, u.ID).Scan(&total)
|
||
var events []model.PointEvent
|
||
store.DB.Where("user_id = ?", u.ID).Order("created_at DESC, id DESC").Limit(50).Find(&events)
|
||
web.OK(c, gin.H{"total": total, "events": events})
|
||
}
|
||
|
||
// Leaderboard GET /api/points/leaderboard —— 学习积分排行榜(全员,含我的名次)
|
||
func Leaderboard(c *gin.Context) {
|
||
u := middleware.CurrentUser(c)
|
||
var users []model.User
|
||
store.DB.Where("role = ? AND status = ?", "employee", "active").
|
||
Order("learning_points DESC, id ASC").Find(&users)
|
||
|
||
out := make([]gin.H, 0, len(users))
|
||
myRank := 0
|
||
for i, usr := range users {
|
||
out = append(out, gin.H{
|
||
"rank": i + 1,
|
||
"user_id": usr.ID,
|
||
"full_name": usr.FullName,
|
||
"department": usr.Department,
|
||
"learning_points": usr.LearningPoints,
|
||
"is_me": u != nil && usr.ID == u.ID,
|
||
})
|
||
if u != nil && usr.ID == u.ID {
|
||
myRank = i + 1
|
||
}
|
||
}
|
||
web.OK(c, gin.H{"items": out, "my_rank": myRank, "total": len(out), "updated_at": time.Now()})
|
||
}
|