init: 数字员工平台初始代码

包含前端(Vue3 + VueFlow 画布)、后端(Go)、文档体系。
- 工作台画布:节点拖放、连线模式、右键菜单、AI 助手
- 后端:连接器 API、专员种子数据
- 导航:左侧导航、工坊、市场、控制台
This commit is contained in:
eaiadmin
2026-08-18 20:19:58 +08:00
commit 4e8817d768
239 changed files with 48631 additions and 0 deletions
@@ -0,0 +1,88 @@
package api
import (
"github.com/gin-gonic/gin"
"eaisalestrain/backend/internal/middleware"
"eaisalestrain/backend/internal/model"
"eaisalestrain/backend/internal/store"
"eaisalestrain/backend/internal/web"
)
// notifyUser 给单个用户发站内通知(userID=0 忽略)。
func notifyUser(userID uint, ntype, title, content, link string) {
if userID == 0 {
return
}
store.DB.Create(&model.Notification{
UserID: userID, Type: ntype, Title: title, Content: content, Link: link,
})
}
// notifyAllEmployees 给所有启用员工发通知(如新正式考试发布)。
func notifyAllEmployees(ntype, title, content, link string) {
var users []model.User
store.DB.Where("role = ? AND status = ?", "employee", "active").Select("id").Find(&users)
for _, u := range users {
notifyUser(u.ID, ntype, title, content, link)
}
}
// MyNotifications GET /api/notifications?unread_only=true —— 我的通知列表
func MyNotifications(c *gin.Context) {
u := middleware.CurrentUser(c)
if u == nil {
web.Fail(c, web.NewAuthError("未登录"))
return
}
q := store.DB.Model(&model.Notification{}).Where("user_id = ?", u.ID)
if c.Query("unread_only") == "true" {
q = q.Where("read = ?", false)
}
var items []model.Notification
q.Order("created_at DESC, id DESC").Limit(100).Find(&items)
web.OK(c, items)
}
// UnreadNotificationCount GET /api/notifications/unread-count —— 未读数(铃铛角标)
func UnreadNotificationCount(c *gin.Context) {
u := middleware.CurrentUser(c)
if u == nil {
web.Fail(c, web.NewAuthError("未登录"))
return
}
var n int64
store.DB.Model(&model.Notification{}).Where("user_id = ? AND read = ?", u.ID, false).Count(&n)
web.OK(c, gin.H{"unread": n})
}
// MarkNotificationRead PUT /api/notifications/{id}/read —— 标记单条已读
func MarkNotificationRead(c *gin.Context) {
u := middleware.CurrentUser(c)
id, ok := parseID(c, "id")
if !ok {
return
}
var n model.Notification
if err := store.DB.First(&n, id).Error; err != nil {
web.Fail(c, web.NewNotFoundError("通知不存在"))
return
}
if n.UserID != u.ID {
web.Fail(c, web.NewForbiddenError("无权操作他人通知"))
return
}
store.DB.Model(&n).Update("read", true)
web.OK(c, gin.H{"id": n.ID, "read": true})
}
// MarkAllNotificationsRead PUT /api/notifications/read-all —— 全部标记已读
func MarkAllNotificationsRead(c *gin.Context) {
u := middleware.CurrentUser(c)
if u == nil {
web.Fail(c, web.NewAuthError("未登录"))
return
}
store.DB.Model(&model.Notification{}).Where("user_id = ? AND read = ?", u.ID, false).Update("read", true)
web.OK(c, gin.H{"read": true})
}