0.11.0: 旗舰版功能补齐(License/登录记录/会话管理/角色管理/门户定时任务/模型配额/输出脱敏/供应链扫描/记忆管理/AI助手/真实概览)

- 新增迁移 000031-000034(登录日志/角色/模型配额/记忆)
- 新增包: license/memory/modelquota/assistant,扫描引擎
- 全部功能后端+前端+端到端验证通过(25 包单测)
This commit is contained in:
2026-08-13 11:37:18 +08:00
parent 9501751792
commit c22669c31d
43 changed files with 3672 additions and 254 deletions
+64
View File
@@ -21,6 +21,7 @@ type HTTPHandler struct {
func NewHTTPHandler(service *Service, identityService *identity.Service) *HTTPHandler {
h := &HTTPHandler{service: service, identity: identityService, mux: http.NewServeMux()}
h.mux.HandleFunc("POST /api/v1/portal/password", h.changePassword)
h.mux.HandleFunc("GET /api/v1/portal/login-logs", h.loginLogs)
h.mux.HandleFunc("GET /api/v1/portal/applications", h.applications)
h.mux.HandleFunc("GET /api/v1/portal/catalog", h.catalog)
h.mux.HandleFunc("GET /api/v1/portal/knowledge", h.knowledge)
@@ -38,7 +39,10 @@ func NewHTTPHandler(service *Service, identityService *identity.Service) *HTTPHa
h.mux.HandleFunc("GET /api/v1/portal/cost", h.cost)
h.mux.HandleFunc("GET /api/v1/portal/docs-info", h.docsInfo)
h.mux.HandleFunc("POST /api/v1/portal/apps/{code}/chat", h.chat)
h.mux.HandleFunc("GET /api/v1/portal/apps/{code}/conversations", h.listConversations)
h.mux.HandleFunc("POST /api/v1/portal/apps/{code}/conversations", h.createConversation)
h.mux.HandleFunc("PATCH /api/v1/portal/apps/{code}/conversations/{id}", h.renameConversation)
h.mux.HandleFunc("DELETE /api/v1/portal/apps/{code}/conversations/{id}", h.deleteConversation)
h.mux.HandleFunc("GET /api/v1/portal/apps/{code}/conversations/{id}", h.getConversation)
h.mux.HandleFunc("POST /api/v1/portal/apps/{code}/conversations/{id}/messages", h.appendConversationMessage)
h.mux.HandleFunc("GET /api/v1/portal/marketplace", h.marketplace)
@@ -79,6 +83,19 @@ func portalError(w http.ResponseWriter, err error) {
apiresponse.Error(w, http.StatusBadRequest, err.Error())
}
func (h *HTTPHandler) loginLogs(w http.ResponseWriter, r *http.Request) {
a, ok := h.account(w, r)
if !ok {
return
}
logs, err := h.identity.ListLoginLogs(r.Context(), identity.KindPortal, a.Login, 50)
if err != nil {
portalError(w, err)
return
}
apiresponse.OK(w, logs)
}
func (h *HTTPHandler) changePassword(w http.ResponseWriter, r *http.Request) {
account, ok := h.account(w, r)
if !ok {
@@ -479,6 +496,53 @@ func (h *HTTPHandler) chat(w http.ResponseWriter, r *http.Request) {
}
writeApplicationResponse(w, response)
}
func (h *HTTPHandler) listConversations(w http.ResponseWriter, r *http.Request) {
a, ok := h.account(w, r)
if !ok {
return
}
items, err := h.service.ListConversations(r.Context(), a, r.PathValue("code"), 100)
if err != nil {
portalError(w, err)
return
}
apiresponse.OK(w, items)
}
func (h *HTTPHandler) renameConversation(w http.ResponseWriter, r *http.Request) {
a, ok := h.account(w, r)
if !ok {
return
}
var input struct {
Title string `json:"title"`
}
decoder := json.NewDecoder(http.MaxBytesReader(w, r.Body, 1<<20))
decoder.DisallowUnknownFields()
if decoder.Decode(&input) != nil {
apiresponse.Error(w, http.StatusBadRequest, "请求格式无效")
return
}
item, err := h.service.RenameConversation(r.Context(), a, r.PathValue("code"), r.PathValue("id"), input.Title)
if err != nil {
portalError(w, err)
return
}
apiresponse.OK(w, item)
}
func (h *HTTPHandler) deleteConversation(w http.ResponseWriter, r *http.Request) {
a, ok := h.account(w, r)
if !ok {
return
}
if err := h.service.DeleteConversation(r.Context(), a, r.PathValue("code"), r.PathValue("id")); err != nil {
portalError(w, err)
return
}
apiresponse.OK(w, map[string]bool{"deleted": true})
}
func (h *HTTPHandler) createConversation(w http.ResponseWriter, r *http.Request) {
a, ok := h.account(w, r)
if !ok {