146 lines
4.7 KiB
Go
146 lines
4.7 KiB
Go
package device
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"go-admin/app/goauto/models"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type ListRequest struct {
|
|
Page int
|
|
PageSize int
|
|
Name string
|
|
Status string
|
|
OwnerUserID *uint64
|
|
}
|
|
|
|
type DeviceListItem struct {
|
|
ID uint64 `json:"id"`
|
|
Name string `json:"name"`
|
|
Manufacturer string `json:"manufacturer"`
|
|
Model string `json:"model"`
|
|
AndroidVersion string `json:"androidVersion"`
|
|
AgentVersion string `json:"agentVersion"`
|
|
PDDVersion string `json:"pddVersion"`
|
|
Capabilities []string `json:"capabilities"`
|
|
Status string `json:"status"`
|
|
Busy bool `json:"busy"`
|
|
Selectable bool `json:"selectable"`
|
|
TokenRevoked bool `json:"tokenRevoked"`
|
|
CurrentTaskID *uint64 `json:"currentTaskId"`
|
|
LastHeartbeatAt *time.Time `json:"lastHeartbeatAt"`
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
UpdatedAt time.Time `json:"updatedAt"`
|
|
OwnerUserID *uint64 `json:"ownerUserId"`
|
|
OwnerName string `json:"ownerName"`
|
|
}
|
|
|
|
type DeviceListResponse struct {
|
|
Items []DeviceListItem `json:"items"`
|
|
Total int64 `json:"total"`
|
|
Page int `json:"page"`
|
|
PageSize int `json:"pageSize"`
|
|
}
|
|
|
|
func (service *Service) List(ctx context.Context, request ListRequest) (DeviceListResponse, error) {
|
|
if request.Page < 1 {
|
|
request.Page = 1
|
|
}
|
|
if request.PageSize < 1 {
|
|
request.PageSize = 20
|
|
}
|
|
if request.PageSize > 100 {
|
|
request.PageSize = 100
|
|
}
|
|
request.Name = strings.TrimSpace(request.Name)
|
|
request.Status = strings.TrimSpace(request.Status)
|
|
if request.Status != "" && request.Status != models.DeviceStatusOnline && request.Status != models.DeviceStatusOffline && request.Status != models.DeviceStatusDisabled {
|
|
return DeviceListResponse{}, invalidRequest("status 无效")
|
|
}
|
|
|
|
query := service.DB.WithContext(ctx).Model(&models.AgentDevice{})
|
|
if request.Name != "" {
|
|
query = query.Where("name LIKE ?", "%"+request.Name+"%")
|
|
}
|
|
if request.Status != "" {
|
|
query = query.Where("status = ?", request.Status)
|
|
}
|
|
if request.OwnerUserID != nil {
|
|
query = query.Where("owner_user_id = ?", *request.OwnerUserID)
|
|
}
|
|
var total int64
|
|
if err := query.Count(&total).Error; err != nil {
|
|
return DeviceListResponse{}, internalError(err)
|
|
}
|
|
var records []models.AgentDevice
|
|
if err := query.Order("updated_at DESC, id DESC").
|
|
Offset((request.Page - 1) * request.PageSize).Limit(request.PageSize).Find(&records).Error; err != nil {
|
|
return DeviceListResponse{}, internalError(err)
|
|
}
|
|
|
|
items := make([]DeviceListItem, 0, len(records))
|
|
if len(records) == 0 {
|
|
return DeviceListResponse{Items: items, Total: total, Page: request.Page, PageSize: request.PageSize}, nil
|
|
}
|
|
ids := make([]uint64, 0, len(records))
|
|
for _, record := range records {
|
|
ids = append(ids, record.ID)
|
|
}
|
|
currentTasks, err := currentTaskIDsForDevices(service.DB.WithContext(ctx), ids)
|
|
if err != nil {
|
|
return DeviceListResponse{}, err
|
|
}
|
|
for _, record := range records {
|
|
capabilities, err := Capabilities(record)
|
|
if err != nil {
|
|
return DeviceListResponse{}, err
|
|
}
|
|
item := DeviceListItem{
|
|
ID: record.ID, Name: record.Name, Manufacturer: record.Manufacturer, Model: record.Model,
|
|
AndroidVersion: record.AndroidVersion, AgentVersion: record.AgentVersion, PDDVersion: record.PDDVersion,
|
|
Capabilities: capabilities,
|
|
Status: record.Status, LastHeartbeatAt: record.LastHeartbeatAt,
|
|
TokenRevoked: record.TokenRevokedAt != nil, OwnerUserID: record.OwnerUserID,
|
|
CreatedAt: record.CreatedAt, UpdatedAt: record.UpdatedAt,
|
|
}
|
|
if taskID, busy := currentTasks[record.ID]; busy {
|
|
item.Busy = true
|
|
item.CurrentTaskID = &taskID
|
|
}
|
|
item.Selectable = item.Status == models.DeviceStatusOnline && !item.Busy
|
|
items = append(items, item)
|
|
}
|
|
return DeviceListResponse{Items: items, Total: total, Page: request.Page, PageSize: request.PageSize}, nil
|
|
}
|
|
|
|
func parseListRequest(context *gin.Context) (ListRequest, error) {
|
|
request := ListRequest{Name: context.Query("name"), Status: context.Query("status")}
|
|
var err error
|
|
request.Page, err = positiveQueryInt(context.Query("page"), 1)
|
|
if err != nil {
|
|
return request, invalidRequest("page 必须是正整数")
|
|
}
|
|
request.PageSize, err = positiveQueryInt(context.Query("pageSize"), 20)
|
|
if err != nil {
|
|
return request, invalidRequest("pageSize 必须是正整数")
|
|
}
|
|
return request, nil
|
|
}
|
|
|
|
func positiveQueryInt(value string, fallback int) (int, error) {
|
|
if strings.TrimSpace(value) == "" {
|
|
return fallback, nil
|
|
}
|
|
parsed, err := strconv.Atoi(value)
|
|
if err != nil || parsed < 1 {
|
|
return 0, gorm.ErrInvalidValue
|
|
}
|
|
return parsed, nil
|
|
}
|