完善角色权限与数据隔离

This commit is contained in:
yml2213
2026-07-26 14:00:50 +08:00
parent b483cbc26d
commit 16d9ab0e5e
38 changed files with 2847 additions and 292 deletions
+24 -11
View File
@@ -16,7 +16,7 @@ type StatisticsHandler struct{}
func NewStatisticsHandler() *StatisticsHandler { return &StatisticsHandler{} }
func requireStatisticsAccess(c *gin.Context) bool {
if middleware.HasAnyRole(c, "admin", "supervisor") {
if middleware.HasPermission(c, "statistics.view") {
return true
}
c.JSON(http.StatusForbidden, gin.H{"code": 403, "message": "仅主管或管理员可查看统计"})
@@ -70,9 +70,12 @@ func parseStatsRange(c *gin.Context) (statsRange, error) {
}
}
func loadStatisticsData(tenantID uint, r statsRange) ([]model.Session, []model.Message, error) {
func loadStatisticsData(tenantID, userID uint, allData bool, r statsRange) ([]model.Session, []model.Message, error) {
var sessions []model.Session
q := model.DB.Where("tenant_id = ?", tenantID)
if !allData {
q = q.Where("agent_id = ?", userID)
}
if !r.From.IsZero() {
q = q.Where("created_at >= ? AND created_at < ?", r.From, r.To)
}
@@ -158,7 +161,9 @@ func (h *StatisticsHandler) KPIs(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
return
}
sessions, messages, err := loadStatisticsData(middleware.GetTenantID(c), r)
sessions, messages, err := loadStatisticsData(
middleware.GetTenantID(c), middleware.GetUserID(c), middleware.CanAccessAllData(c, "statistics"), r,
)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "查询统计数据失败"})
return
@@ -209,6 +214,9 @@ func (h *StatisticsHandler) SessionTrend(c *gin.Context) {
var sessions []model.Session
q := model.DB.Where("tenant_id = ?", middleware.GetTenantID(c))
if !middleware.CanAccessAllData(c, "statistics") {
q = q.Where("agent_id = ?", middleware.GetUserID(c))
}
// 趋势:自定义/今日/本周用区间内数据;本月预置仍看近 6 个月走势
if hasCustom || period == "today" || period == "week" || period == "day" {
q = q.Where("created_at >= ? AND created_at < ?", r.From, r.To)
@@ -259,7 +267,9 @@ func (h *StatisticsHandler) ResponseDistribution(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
return
}
_, messages, err := loadStatisticsData(middleware.GetTenantID(c), r)
_, messages, err := loadStatisticsData(
middleware.GetTenantID(c), middleware.GetUserID(c), middleware.CanAccessAllData(c, "statistics"), r,
)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "查询响应时长失败"})
return
@@ -296,13 +306,18 @@ func (h *StatisticsHandler) AgentPerformance(c *gin.Context) {
return
}
tenantID := middleware.GetTenantID(c)
sessions, messages, err := loadStatisticsData(tenantID, r)
allData := middleware.CanAccessAllData(c, "statistics")
sessions, messages, err := loadStatisticsData(tenantID, middleware.GetUserID(c), allData, r)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "查询客服绩效失败"})
return
}
var agents []model.User
if err := model.DB.Where("tenant_id = ? AND role = ?", tenantID, "agent").Find(&agents).Error; err != nil {
agentQuery := model.DB.Where("tenant_id = ?", tenantID)
if !allData {
agentQuery = agentQuery.Where("id = ?", middleware.GetUserID(c))
}
if err := agentQuery.Find(&agents).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "查询客服失败"})
return
}
@@ -365,7 +380,9 @@ func (h *StatisticsHandler) ChannelDistribution(c *gin.Context) {
return
}
tenantID := middleware.GetTenantID(c)
sessions, _, err := loadStatisticsData(tenantID, r)
sessions, _, err := loadStatisticsData(
tenantID, middleware.GetUserID(c), middleware.CanAccessAllData(c, "statistics"), r,
)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "查询渠道分布失败"})
return
@@ -375,10 +392,6 @@ func (h *StatisticsHandler) ChannelDistribution(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "查询渠道分布失败"})
return
}
if err := model.DB.Where("tenant_id = ?", tenantID).Find(&channels).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "查询渠道分布失败"})
return
}
channelTypes := make(map[uint]string)
for _, channel := range channels {
channelTypes[channel.ID] = channel.Type