完善角色权限与数据隔离
This commit is contained in:
@@ -24,7 +24,7 @@ type Tenant struct {
|
||||
type User struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"index;not null" json:"tenant_id"`
|
||||
Role string `gorm:"size:20;default:agent" json:"role"`
|
||||
Role string `gorm:"size:30;default:agent" json:"role"`
|
||||
Username string `gorm:"size:50;not null;uniqueIndex" json:"username"`
|
||||
PasswordHash string `gorm:"size:255;not null" json:"-"`
|
||||
Nickname string `gorm:"size:50" json:"nickname"`
|
||||
@@ -50,12 +50,12 @@ type Customer struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"index;not null" json:"tenant_id"`
|
||||
Name string `gorm:"size:50;not null" json:"name"`
|
||||
Phone string `gorm:"size:20" json:"phone"` // 主手机号(兼容列表搜索)
|
||||
Tel string `gorm:"size:30" json:"tel"` // 联系电话/固话
|
||||
Phone string `gorm:"size:20" json:"phone"` // 主手机号(兼容列表搜索)
|
||||
Tel string `gorm:"size:30" json:"tel"` // 联系电话/固话
|
||||
Email string `gorm:"size:100" json:"email"`
|
||||
Wechat string `gorm:"size:50" json:"wechat"` // 微信号,默认可空
|
||||
Wechat string `gorm:"size:50" json:"wechat"` // 微信号,默认可空
|
||||
QQ string `gorm:"size:20;column:qq" json:"qq"`
|
||||
Remark string `gorm:"type:text" json:"remark"` // 客户备注
|
||||
Remark string `gorm:"type:text" json:"remark"` // 客户备注
|
||||
Tags string `gorm:"type:text" json:"tags"`
|
||||
Source string `gorm:"size:30" json:"source"`
|
||||
Status string `gorm:"size:20;default:online" json:"status"`
|
||||
@@ -95,15 +95,15 @@ type BlacklistEntry struct {
|
||||
}
|
||||
|
||||
type Session struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"index;not null" json:"tenant_id"`
|
||||
ChannelID uint `json:"channel_id"`
|
||||
CustomerID uint `gorm:"index" json:"customer_id"`
|
||||
AgentID *uint `gorm:"index" json:"agent_id"`
|
||||
VisitorTokenHash string `gorm:"size:64;index" json:"-"`
|
||||
VisitorIP string `gorm:"size:64" json:"visitor_ip"`
|
||||
VisitorRegion string `gorm:"size:100" json:"visitor_region"`
|
||||
UserAgent string `gorm:"size:500" json:"user_agent"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"index;not null" json:"tenant_id"`
|
||||
ChannelID uint `json:"channel_id"`
|
||||
CustomerID uint `gorm:"index" json:"customer_id"`
|
||||
AgentID *uint `gorm:"index" json:"agent_id"`
|
||||
VisitorTokenHash string `gorm:"size:64;index" json:"-"`
|
||||
VisitorIP string `gorm:"size:64" json:"visitor_ip"`
|
||||
VisitorRegion string `gorm:"size:100" json:"visitor_region"`
|
||||
UserAgent string `gorm:"size:500" json:"user_agent"`
|
||||
// DeviceKey 访客端持久设备指纹(localStorage),用于设备级拉黑
|
||||
DeviceKey string `gorm:"size:64;index" json:"device_key"`
|
||||
// 落地页 / 当前页(访客浏览轨迹)
|
||||
@@ -115,11 +115,11 @@ type Session struct {
|
||||
// LastSeenAt 访客最近活跃(心跳/换页),用于在线时长与在线状态
|
||||
LastSeenAt *time.Time `json:"last_seen_at"`
|
||||
// DraftText 访客输入框未发送草稿(实时监控用,非聊天消息)
|
||||
DraftText string `gorm:"type:text" json:"draft_text"`
|
||||
DraftUpdatedAt *time.Time `json:"draft_updated_at"`
|
||||
LastReadSeq int `gorm:"default:0" json:"last_read_seq"`
|
||||
Status string `gorm:"size:20;default:waiting" json:"status"`
|
||||
Priority string `gorm:"size:20;default:normal" json:"priority"`
|
||||
DraftText string `gorm:"type:text" json:"draft_text"`
|
||||
DraftUpdatedAt *time.Time `json:"draft_updated_at"`
|
||||
LastReadSeq int `gorm:"default:0" json:"last_read_seq"`
|
||||
Status string `gorm:"size:20;default:waiting" json:"status"`
|
||||
Priority string `gorm:"size:20;default:normal" json:"priority"`
|
||||
SatisfactionScore *int `json:"satisfaction_score"`
|
||||
SatisfactionText string `gorm:"size:500" json:"satisfaction_text"`
|
||||
EndReason string `gorm:"size:50" json:"end_reason"`
|
||||
@@ -133,7 +133,7 @@ type CustomerContact struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"index;not null" json:"tenant_id"`
|
||||
CustomerID uint `gorm:"uniqueIndex:idx_cust_contact;not null" json:"customer_id"`
|
||||
Kind string `gorm:"size:20;uniqueIndex:idx_cust_contact;not null" json:"kind"` // phone|wechat|email|qq
|
||||
Kind string `gorm:"size:20;uniqueIndex:idx_cust_contact;not null" json:"kind"` // phone|wechat|email|qq
|
||||
Value string `gorm:"size:100;uniqueIndex:idx_cust_contact;not null" json:"value"`
|
||||
Source string `gorm:"size:30" json:"source"` // draft|message|leave|agent
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
@@ -165,21 +165,23 @@ type SessionEvent struct {
|
||||
SessionID uint `gorm:"index;not null" json:"session_id"`
|
||||
OperatorID uint `json:"operator_id"`
|
||||
Action string `gorm:"size:50;not null" json:"action"`
|
||||
Detail string `gorm:"size:500" json:"detail"`
|
||||
Detail string `gorm:"type:text" json:"detail"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type Category struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"index;not null" json:"tenant_id"`
|
||||
ParentID *uint `json:"parent_id"`
|
||||
Name string `gorm:"size:30;not null" json:"name"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"index;not null" json:"tenant_id"`
|
||||
CreatedBy uint `gorm:"index" json:"created_by"`
|
||||
ParentID *uint `json:"parent_id"`
|
||||
Name string `gorm:"size:30;not null" json:"name"`
|
||||
}
|
||||
|
||||
type KnowledgeEntry struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"index;not null" json:"tenant_id"`
|
||||
CategoryID uint `json:"category_id"`
|
||||
CreatedBy uint `gorm:"index" json:"created_by"`
|
||||
Title string `gorm:"size:100;not null" json:"title"`
|
||||
Content string `gorm:"type:text;not null" json:"content"`
|
||||
Status string `gorm:"size:20;default:draft" json:"status"`
|
||||
@@ -191,16 +193,16 @@ type KnowledgeEntry struct {
|
||||
// QuickReply 团队/个人快捷回复(与知识库独立)。
|
||||
// Scope=team 时 OwnerUserID 为空,全租户共享;Scope=personal 时归属 OwnerUserID。
|
||||
type QuickReply struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"index;not null" json:"tenant_id"`
|
||||
Scope string `gorm:"size:20;index;not null" json:"scope"` // team | personal
|
||||
OwnerUserID *uint `gorm:"index" json:"owner_user_id,omitempty"`
|
||||
Title string `gorm:"size:100;not null" json:"title"`
|
||||
Content string `gorm:"type:text;not null" json:"content"`
|
||||
Shortcut string `gorm:"size:32;index" json:"shortcut"` // 输入码,如 nh → /nh
|
||||
GroupName string `gorm:"size:50" json:"group_name"`
|
||||
Status string `gorm:"size:20;default:draft;index" json:"status"` // draft | published
|
||||
SortOrder int `gorm:"default:0" json:"sort_order"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"index;not null" json:"tenant_id"`
|
||||
Scope string `gorm:"size:20;index;not null" json:"scope"` // team | personal
|
||||
OwnerUserID *uint `gorm:"index" json:"owner_user_id,omitempty"`
|
||||
Title string `gorm:"size:100;not null" json:"title"`
|
||||
Content string `gorm:"type:text;not null" json:"content"`
|
||||
Shortcut string `gorm:"size:32;index" json:"shortcut"` // 输入码,如 nh → /nh
|
||||
GroupName string `gorm:"size:50" json:"group_name"`
|
||||
Status string `gorm:"size:20;default:draft;index" json:"status"` // draft | published
|
||||
SortOrder int `gorm:"default:0" json:"sort_order"`
|
||||
// UsageCount 全局累计(管理页展示);排序以个人用量为准见 QuickReplyUserUsage
|
||||
UsageCount int `gorm:"default:0" json:"usage_count"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
@@ -254,26 +256,64 @@ type Announcement struct {
|
||||
|
||||
// TenantSetting 租户级系统设置(欢迎语、工作时间、通知开关、分配策略等)。
|
||||
type TenantSetting struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"uniqueIndex;not null" json:"tenant_id"`
|
||||
DisplayName string `gorm:"size:100" json:"display_name"`
|
||||
AgentNickname string `gorm:"size:50" json:"agent_nickname"`
|
||||
Timezone string `gorm:"size:50;default:Asia/Shanghai" json:"timezone"`
|
||||
WelcomeMessage string `gorm:"size:500" json:"welcome_message"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"uniqueIndex;not null" json:"tenant_id"`
|
||||
DisplayName string `gorm:"size:100" json:"display_name"`
|
||||
AgentNickname string `gorm:"size:50" json:"agent_nickname"`
|
||||
Timezone string `gorm:"size:50;default:Asia/Shanghai" json:"timezone"`
|
||||
WelcomeMessage string `gorm:"size:500" json:"welcome_message"`
|
||||
// WelcomeMessagesJSON 多段欢迎语 JSON:[{type:text|image, content:...}, ...]
|
||||
WelcomeMessagesJSON string `gorm:"type:text" json:"welcome_messages_json"`
|
||||
OfflinePrompt string `gorm:"size:500" json:"offline_prompt"`
|
||||
WorkHoursJSON string `gorm:"type:text" json:"work_hours_json"`
|
||||
WorktimePrompt string `gorm:"size:500" json:"worktime_prompt"`
|
||||
NotifyNewSession bool `gorm:"default:true" json:"notify_new_session"`
|
||||
NotifyOfflineLeave bool `gorm:"default:true" json:"notify_offline_leave"`
|
||||
NotifyDailyReport bool `gorm:"default:false" json:"notify_daily_report"`
|
||||
WorktimePrompt string `gorm:"size:500" json:"worktime_prompt"`
|
||||
NotifyNewSession bool `gorm:"default:true" json:"notify_new_session"`
|
||||
NotifyOfflineLeave bool `gorm:"default:true" json:"notify_offline_leave"`
|
||||
NotifyDailyReport bool `gorm:"default:false" json:"notify_daily_report"`
|
||||
// AssignStrategy 自动分配策略:least_load(默认)| round_robin
|
||||
AssignStrategy string `gorm:"size:30;default:least_load" json:"assign_strategy"`
|
||||
// MaxActivePerAgent 每位坐席最大进行中会话数;0 表示不限制
|
||||
MaxActivePerAgent int `gorm:"default:0" json:"max_active_per_agent"`
|
||||
// RRLastAgentID 轮询策略的上次分配坐席游标
|
||||
RRLastAgentID *uint `json:"-"`
|
||||
RRLastAgentID *uint `json:"-"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Role 租户级角色定义。
|
||||
// Code 为角色标识(admin/supervisor/agent 为内置,其他为自定义)。
|
||||
// Type="builtin" 的内置角色不可删除、不可修改 Code。
|
||||
type Role struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
TenantID uint `gorm:"uniqueIndex:idx_tenant_role_code;not null" json:"tenant_id"`
|
||||
Name string `gorm:"size:50;not null" json:"name"`
|
||||
Code string `gorm:"size:30;uniqueIndex:idx_tenant_role_code;not null" json:"code"`
|
||||
Type string `gorm:"size:10;default:custom" json:"type"` // builtin | custom
|
||||
Desc string `gorm:"size:200" json:"desc"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Permission 系统权限码表(全租户共享,不可删除)。
|
||||
type Permission struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Code string `gorm:"size:50;uniqueIndex;not null" json:"code"`
|
||||
Name string `gorm:"size:50;not null" json:"name"`
|
||||
Module string `gorm:"size:30;not null" json:"module"`
|
||||
Category string `gorm:"size:20;not null" json:"category"` // view | operate
|
||||
SortOrder int `gorm:"default:0" json:"sort_order"`
|
||||
}
|
||||
|
||||
// RolePermission 角色-权限多对多关联。
|
||||
type RolePermission struct {
|
||||
RoleID uint `gorm:"primaryKey" json:"role_id"`
|
||||
PermissionID uint `gorm:"primaryKey" json:"permission_id"`
|
||||
}
|
||||
|
||||
// RoleDataScope 保存角色在业务模块中的数据范围。
|
||||
// 当前支持 all/self,module 维度为后续 group/channel/tag 等范围扩展预留。
|
||||
type RoleDataScope struct {
|
||||
RoleID uint `gorm:"primaryKey" json:"role_id"`
|
||||
Module string `gorm:"size:30;primaryKey" json:"module"`
|
||||
Scope string `gorm:"size:20;not null" json:"scope"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user