269 lines
7.1 KiB
Go
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)
|
|
}
|