Files
goauto/server/app/goauto/sybinnercode/handler.go
T

269 lines
7.1 KiB
Go

package sybinnercode
import (
"encoding/json"
"errors"
"go-admin/common/clientprincipal"
"io"
"net/http"
"strconv"
"strings"
"go-admin/app/goauto/models"
"github.com/gin-gonic/gin"
"github.com/go-admin-team/go-admin-core/sdk/pkg"
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
"gorm.io/gorm"
)
type Handler struct{ DB *gorm.DB }
func (h Handler) List(c *gin.Context) {
service, ok := h.service(c)
if !ok {
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "100"))
result, err := service.List(c.Request.Context(), ListRequest{DateFrom: strings.TrimSpace(c.Query("dateFrom")), DateTo: strings.TrimSpace(c.Query("dateTo")), Keyword: strings.TrimSpace(c.Query("keyword")), Status: strings.TrimSpace(c.Query("status")), Page: page, PageSize: pageSize})
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": result})
}
func (h Handler) Detail(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("recordId"), 10, 64)
if err != nil || id == 0 {
writeError(c, invalid("recordId 无效"))
return
}
service, ok := h.service(c)
if !ok {
return
}
result, err := service.Detail(c.Request.Context(), id)
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": gin.H{"item": result}})
}
func (h Handler) Import(c *gin.Context) {
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, MaxUploadBytes+(1<<20))
file, err := c.FormFile("file")
if err != nil {
var tooLarge *http.MaxBytesError
if errors.As(err, &tooLarge) {
writeError(c, invalid("Excel 超过 10MB 上限"))
} else {
writeError(c, invalid("上传格式无效,请重新选择 Excel 后重试"))
}
return
}
src, err := file.Open()
if err != nil {
writeError(c, invalid("无法打开 Excel"))
return
}
defer src.Close()
head := make([]byte, 8)
n, _ := io.ReadFull(src, head)
if err := ValidateUpload(file.Filename, file.Size, head[:n]); err != nil {
writeError(c, err)
return
}
if _, err := src.Seek(0, io.SeekStart); err != nil {
writeError(c, internal(err))
return
}
service, ok := h.service(c)
if !ok {
return
}
result, err := service.Import(c.Request.Context(), src, file.Filename, clientOperator(c), c.PostForm("requestId"))
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": result})
}
func clientOperator(c *gin.Context) uint64 {
if p, ok := clientprincipal.Get(c); ok {
return p.AuthorizedBy
}
return uint64(user.GetUserId(c))
}
func (h Handler) Delete(c *gin.Context) {
var request DeleteRequest
if err := decode(c, &request); err != nil {
writeError(c, invalid("请求 JSON 无效"))
return
}
service, ok := h.service(c)
if !ok {
return
}
result, err := service.Delete(c.Request.Context(), clientOperator(c), request)
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": result})
}
func (h Handler) MatchJob(c *gin.Context) {
service, ok := h.service(c)
if !ok {
return
}
var job models.SYBInnerCodeMatchJob
if err := service.db.WithContext(c.Request.Context()).First(&job, "id = ?", c.Param("jobId")).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
writeError(c, &ServiceError{Code: CodeNotFound, Message: "匹配任务不存在"})
} else {
writeError(c, internal(err))
}
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": gin.H{"item": job}})
}
func (h Handler) ApplyPreview(c *gin.Context) {
var request ApplyPreviewRequest
if err := decode(c, &request); err != nil {
writeError(c, invalid("请求 JSON 无效"))
return
}
service, ok := h.service(c)
if !ok {
return
}
result, err := service.PreviewApply(c.Request.Context(), request.IDs)
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": result})
}
func (h Handler) Apply(c *gin.Context) {
var request ApplyRequest
if err := decode(c, &request); err != nil {
writeError(c, invalid("请求 JSON 无效"))
return
}
service, ok := h.service(c)
if !ok {
return
}
result, err := service.QueueApply(c.Request.Context(), clientOperator(c), request)
if err != nil {
writeError(c, err)
return
}
DefaultApplyRunner.Start(service.db, result.BatchID)
c.JSON(http.StatusAccepted, gin.H{"code": 200, "data": result})
}
func (h Handler) ApplyBatch(c *gin.Context) {
service, ok := h.service(c)
if !ok {
return
}
var batch models.SYBInnerCodeApplyBatch
if err := service.db.WithContext(c.Request.Context()).First(&batch, "id = ?", c.Param("batchId")).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
writeError(c, &ServiceError{Code: CodeNotFound, Message: "回写批次不存在"})
} else {
writeError(c, internal(err))
}
return
}
var items []models.SYBInnerCodeApplyItem
if err := service.db.Where("batch_id = ?", batch.ID).Order("id").Find(&items).Error; err != nil {
writeError(c, internal(err))
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": gin.H{"batch": batch, "items": items}})
}
func (h Handler) Recheck(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("recordId"), 10, 64)
if err != nil || id == 0 {
writeError(c, invalid("recordId 无效"))
return
}
service, ok := h.service(c)
if !ok {
return
}
reader, err := DefaultMatcher.Factory(c.Request.Context(), service.db)
if err != nil {
writeError(c, internal(err))
return
}
status, message, err := Recheck(c.Request.Context(), service.db, reader, id)
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"code": 200, "data": gin.H{"status": status, "message": message}})
}
func (h Handler) Rematch(c *gin.Context) {
var request RematchRequest
if err := decode(c, &request); err != nil {
writeError(c, invalid("请求 JSON 无效"))
return
}
service, ok := h.service(c)
if !ok {
return
}
result, err := service.QueueRematch(c.Request.Context(), request)
if err != nil {
writeError(c, err)
return
}
c.JSON(http.StatusAccepted, gin.H{"code": 200, "data": result})
}
func (h Handler) service(c *gin.Context) (*Service, bool) {
db := h.DB
var err error
if db == nil {
db, err = pkg.GetOrm(c)
}
if err != nil {
writeError(c, internal(err))
return nil, false
}
return NewService(db).WithMatchEnqueuer(DefaultMatcher), true
}
func decode(c *gin.Context, target any) error {
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 1<<20)
decoder := json.NewDecoder(c.Request.Body)
decoder.DisallowUnknownFields()
if err := decoder.Decode(target); err != nil {
return err
}
if err := decoder.Decode(&struct{}{}); !errors.Is(err, io.EOF) {
return errors.New("one object required")
}
return nil
}
func writeError(c *gin.Context, err error) {
target := AsServiceError(err)
status := http.StatusInternalServerError
switch target.Code {
case CodeInvalidRequest:
status = http.StatusUnprocessableEntity
case CodeConflict:
status = http.StatusConflict
case CodeNotFound:
status = http.StatusNotFound
}
payload := gin.H{"code": target.Code, "message": target.Message}
if target.Details != nil {
payload["data"] = target.Details
}
c.JSON(status, payload)
}