91 lines
3.6 KiB
Go
91 lines
3.6 KiB
Go
package sop
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/access"
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/audit"
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/auth"
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/model"
|
|
"git.iwork-ai.com/xdc/iqudo-top1/internal/response"
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type ReviewItem struct {
|
|
SOPID uint64 `json:"sop_id"`
|
|
SOPName string `json:"sop_name"`
|
|
Description string `json:"description"`
|
|
ScenarioID uint64 `json:"scenario_id"`
|
|
ScenarioName string `json:"scenario_name"`
|
|
VersionID uint64 `json:"version_id"`
|
|
Version int `json:"version"`
|
|
CreatorID uint64 `json:"creator_id"`
|
|
CreatorName string `json:"creator_name"`
|
|
SubmittedAt time.Time `json:"submitted_at"`
|
|
}
|
|
|
|
func (h *Handler) Reviews(c *gin.Context) {
|
|
principal, _ := auth.PrincipalFromContext(c)
|
|
items := make([]ReviewItem, 0)
|
|
query := h.db.Table("sop_versions sv").Select(
|
|
"s.id AS sop_id, s.name AS sop_name, s.description, sc.id AS scenario_id, sc.name AS scenario_name, " +
|
|
"sv.id AS version_id, sv.version, sv.created_by AS creator_id, u.display_name AS creator_name, sv.updated_at AS submitted_at",
|
|
).Joins("JOIN sops s ON s.id = sv.sop_id").Joins("JOIN scenarios sc ON sc.id = s.scenario_id").Joins("JOIN users u ON u.id = sv.created_by")
|
|
query = access.ScopeScenarios(query, principal, "sc")
|
|
if err := query.Where("sv.tenant_id = ? AND sv.status = ?", principal.TenantID, "reviewing").Order("sv.updated_at ASC").Scan(&items).Error; err != nil {
|
|
response.Error(c, http.StatusInternalServerError, "QUERY_FAILED", "查询审核任务失败")
|
|
return
|
|
}
|
|
response.OK(c, gin.H{"items": items, "total": len(items)})
|
|
}
|
|
|
|
func (h *Handler) Reject(c *gin.Context) {
|
|
principal, _ := auth.PrincipalFromContext(c)
|
|
sopID, ok := parseID(c, "id")
|
|
if !ok {
|
|
return
|
|
}
|
|
if !access.CanViewSOP(h.db, principal, sopID) {
|
|
response.Error(c, http.StatusNotFound, "NOT_FOUND", "SOP 不存在")
|
|
return
|
|
}
|
|
var input struct {
|
|
Reason string `json:"reason" binding:"required,max=1000"`
|
|
}
|
|
if err := c.ShouldBindJSON(&input); err != nil {
|
|
response.Error(c, http.StatusBadRequest, "INVALID_ARGUMENT", "请填写退回原因")
|
|
return
|
|
}
|
|
var version model.SOPVersion
|
|
if err := h.db.Where("sop_id = ? AND tenant_id = ? AND status = ?", sopID, principal.TenantID, "reviewing").Order("version DESC").First(&version).Error; err != nil {
|
|
response.Error(c, http.StatusConflict, "NO_REVIEW_VERSION", "没有待审核版本")
|
|
return
|
|
}
|
|
if !auth.HasPermission(principal, "*") && version.CreatedBy == principal.UserID {
|
|
response.Error(c, http.StatusForbidden, "SELF_REVIEW_FORBIDDEN", "不能审核自己创建的 SOP")
|
|
return
|
|
}
|
|
err := h.db.Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Model(&version).Updates(map[string]interface{}{"status": "draft", "reviewed_by": nil}).Error; err != nil {
|
|
return err
|
|
}
|
|
var published int64
|
|
if err := tx.Model(&model.SOPVersion{}).Where("sop_id = ? AND tenant_id = ? AND status = ?", sopID, principal.TenantID, "published").Count(&published).Error; err != nil {
|
|
return err
|
|
}
|
|
status := "draft"
|
|
if published > 0 {
|
|
status = "published"
|
|
}
|
|
return tx.Model(&model.SOP{}).Where("id = ? AND tenant_id = ?", sopID, principal.TenantID).Update("status", status).Error
|
|
})
|
|
if err != nil {
|
|
response.Error(c, http.StatusInternalServerError, "REJECT_FAILED", "退回审核失败")
|
|
return
|
|
}
|
|
_ = audit.Record(h.db, principal, "reject", "sop", sopID, gin.H{"version": version.Version, "reason": input.Reason})
|
|
response.OK(c, gin.H{"id": sopID, "version": version.Version, "status": "draft"})
|
|
}
|