增加ai办公,考勤管理

This commit is contained in:
hero920103 committed 2026-11-14 18:15:55 +08:00
1 parent eb9b7beff5
commit 31ae07175d
46 files changed
+9250 -296

No files matched your search

+34 -10
View File
@@ -16,6 +16,7 @@ import (
"server/pkg/jwtutil"
"server/services"
"github.com/beego/beego/v2/client/orm"
beego "github.com/beego/beego/v2/server/web"
)
@@ -51,6 +52,8 @@ type chatSendPayload struct {
McpServerIDs []uint64 `json:"mcp_server_ids"`
// Images 用户上传的图片(base64 dataURL),仅多模态模型可用
Images []string `json:"images"`
// SystemPrompt 本轮自定义系统提示词(AI 广场的场景对话使用),为空时回落租户预设
SystemPrompt string `json:"system_prompt"`
}
// mcpEnabled 解析本轮是否启用 MCP(未传默认开启)
@@ -542,7 +545,8 @@ func resolveOrCreateSession(c *BackendAiChatController, claims *jwtutil.Claims,
return session, nil
}
// resolveProvider 解析 AI 接入配置
// resolveProvider 解析 AI 接入配置。
// 优先级:租户级配置(user_id=0,由 OA 设置统一维护)→ 个人配置(历史数据)。
func resolveProvider(claims *jwtutil.Claims, p *chatSendPayload, session *models.BackendAiChatSession) (models.BackendAiProvider, error) {
providerID := p.ProviderID
if providerID == 0 {
@@ -555,24 +559,33 @@ func resolveProvider(claims *jwtutil.Claims, p *chatSendPayload, session *models
if err := models.Orm.Read(&provider); err != nil {
return provider, fmt.Errorf("指定的AI接入配置不存在,请先在设置中配置")
}
if provider.TenantID != fmt.Sprintf("%d", claims.TenantId) || provider.UserID != uint64(claims.UserID) {
if provider.TenantID != fmt.Sprintf("%d", claims.TenantId) {
return provider, fmt.Errorf("无权使用该配置")
}
// user_id=0 是租户级配置,全员可用;其余只允许本人使用
if provider.UserID != 0 && provider.UserID != uint64(claims.UserID) {
return provider, fmt.Errorf("无权使用该配置")
}
if provider.Status != 1 {
return provider, fmt.Errorf("该AI接入配置已被禁用")
}
} else {
tid := fmt.Sprintf("%d", claims.TenantId)
cond := orm.NewCondition().
And("tenant_id", tid).
And("status", 1).
And("delete_time__isnull", true).
AndCond(orm.NewCondition().
Or("user_id", 0).
Or("user_id", uint64(claims.UserID)))
var providers []models.BackendAiProvider
_, err := models.Orm.QueryTable(new(models.BackendAiProvider)).
Filter("tenant_id", fmt.Sprintf("%d", claims.TenantId)).
Filter("user_id", uint64(claims.UserID)).
Filter("status", 1).
Filter("delete_time__isnull", true).
OrderBy("-id").
SetCond(cond).
OrderBy("user_id", "-is_default", "-id").
Limit(1).
All(&providers)
if err != nil || len(providers) == 0 {
return provider, fmt.Errorf("尚未配置AI接入,请先在设置中配置OpenAI或Anthropic接入")
return provider, fmt.Errorf("尚未配置AI接入,请先联系管理员在「基础设置 → AI 设置」中填写接口地址与 API Key")
}
provider = providers[0]
}
@@ -610,6 +623,17 @@ func loadSystemPrompt(claims *jwtutil.Claims) string {
return ""
}
// chatSystemPrompt 优先使用本轮传入的系统提示词(AI 广场的场景对话),否则回落租户预设。
func chatSystemPrompt(claims *jwtutil.Claims, p *chatSendPayload) string {
if v := strings.TrimSpace(p.SystemPrompt); v != "" {
if len([]rune(v)) > 4000 {
v = string([]rune(v)[:4000])
}
return v
}
return loadSystemPrompt(claims)
}
// loadHistory 加载会话历史(最近20条,正序)
func loadHistory(sessionID uint64) []openaiMessage {
var history []models.BackendAiChatMessage
@@ -671,7 +695,7 @@ func (c *BackendAiChatController) Send() {
c.chatJsonErr(400, 400, err.Error())
return
}
systemPrompt := loadSystemPrompt(claims)
systemPrompt := chatSystemPrompt(claims, &p)
messages := loadHistory(session.ID)
messages = append(messages, openaiMessage{Role: "user", Content: p.Content, Images: p.Images})
@@ -787,7 +811,7 @@ func (c *BackendAiChatController) SendStream() {
c.chatJsonErr(400, 400, err.Error())
return
}
systemPrompt := loadSystemPrompt(claims)
systemPrompt := chatSystemPrompt(claims, &p)
messages := loadHistory(session.ID)
messages = append(messages, openaiMessage{Role: "user", Content: p.Content, Images: p.Images})