yunzerwebsiteallinone/go/controllers/platform_cursor_equipment.go

1044 lines
29 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package controllers
import (
"encoding/json"
"fmt"
"io"
"strconv"
"strings"
"time"
"server/models"
"server/pkg/jwtutil"
"github.com/beego/beego/v2/client/orm"
beego "github.com/beego/beego/v2/server/web"
)
// PlatformCursorEquipmentController 平台端 Cursor 设备管理
type PlatformCursorEquipmentController struct {
beego.Controller
}
func (c *PlatformCursorEquipmentController) platformClaims() (*jwtutil.Claims, error) {
auth := c.Ctx.Request.Header.Get("Authorization")
if auth == "" {
return nil, fmt.Errorf("未登录")
}
parts := strings.SplitN(auth, " ", 2)
if len(parts) != 2 || parts[0] != "Bearer" {
return nil, fmt.Errorf("认证信息格式错误")
}
claims, err := jwtutil.ParseToken(parts[1])
if err != nil {
return nil, fmt.Errorf("无效的token")
}
if claims.UserType != "platform" {
return nil, fmt.Errorf("无权访问")
}
return claims, nil
}
func (c *PlatformCursorEquipmentController) jsonErr(httpStatus, bizCode int, msg string) {
c.Ctx.Output.SetStatus(httpStatus)
c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg}
_ = c.ServeJSON()
}
func (c *PlatformCursorEquipmentController) ok(data interface{}) {
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": data}
_ = c.ServeJSON()
}
func cursorEquipmentTrimPtr(value *string) *string {
if value == nil {
return nil
}
v := strings.TrimSpace(*value)
if v == "" {
return nil
}
return &v
}
func cursorEquipmentTimePtr(value *string) *time.Time {
if value == nil {
return nil
}
v := strings.TrimSpace(*value)
if v == "" {
return nil
}
layouts := []string{
time.RFC3339,
"2006-01-02 15:04:05",
"2006-01-02 15:04",
"2006-01-02",
}
for _, layout := range layouts {
if t, err := time.ParseInLocation(layout, v, time.Local); err == nil {
return &t
}
}
return nil
}
func cursorEquipmentStatusValid(status int8) bool {
return status == 0 || status == 1 || status == 2 || status == 3
}
func (c *PlatformCursorEquipmentController) cursorActivationSummary(row *models.PlatformCursorEquipment) (int64, *models.PlatformCursorActivationCode) {
cond := orm.NewCondition().
And("delete_time__isnull", true).
AndCond(orm.NewCondition().
Or("bind_device_id", row.ID).
Or("machine_code", row.MachineCode))
qs := models.Orm.QueryTable(new(models.PlatformCursorActivationCode)).SetCond(cond)
count, _ := qs.Count()
var latest models.PlatformCursorActivationCode
if err := qs.OrderBy("-activated_at", "-id").One(&latest); err != nil {
return count, nil
}
return count, &latest
}
func (c *PlatformCursorEquipmentController) cursorExtractSummary(machineCode string) (int64, *models.PlatformAccountPoolCursor) {
qs := models.Orm.QueryTable(new(models.PlatformAccountPoolCursor)).
Filter("delete_time__isnull", true).
Filter("is_extracted__gt", 0).
Filter("machine_code", machineCode)
count, _ := qs.Count()
var latest models.PlatformAccountPoolCursor
if err := qs.OrderBy("-extracted_time", "-id").One(&latest); err != nil {
return count, nil
}
return count, &latest
}
func (c *PlatformCursorEquipmentController) rowToMap(row *models.PlatformCursorEquipment) map[string]interface{} {
activationCount, latestActivation := c.cursorActivationSummary(row)
extractCount, latestExtract := c.cursorExtractSummary(row.MachineCode)
var bindActivationCode interface{}
var activationCodeId interface{}
var lastActivatedAt interface{} = row.ActivationTime
var expireTime interface{} = row.ExpireTime
var lastExtractedAt interface{}
if latestActivation != nil {
bindActivationCode = latestActivation.Code
activationCodeId = latestActivation.ID
if latestActivation.ActivatedAt != nil {
lastActivatedAt = latestActivation.ActivatedAt
}
if latestActivation.ExpiredAt != nil {
expireTime = latestActivation.ExpiredAt
}
}
if latestExtract != nil {
lastExtractedAt = latestExtract.ExtractedTime
}
// 查询该设备最近一条 IP 日志
var lastLoginIp interface{}
var lastLoginIpInfo interface{}
var latestIpLog models.PlatformCursorEquipmentIpLog
ipCond := orm.NewCondition().
AndCond(orm.NewCondition().
Or("equipment_id", row.ID).
Or("machine_code", row.MachineCode))
if err := models.Orm.QueryTable(new(models.PlatformCursorEquipmentIpLog)).
SetCond(ipCond).
OrderBy("-id").
One(&latestIpLog); err == nil {
lastLoginIp = latestIpLog.Query
lastLoginIpInfo = map[string]interface{}{
"id": latestIpLog.ID,
"source": latestIpLog.Source,
"status": latestIpLog.Status,
"country": latestIpLog.Country,
"countryCode": latestIpLog.CountryCode,
"region": latestIpLog.Region,
"regionName": latestIpLog.RegionName,
"city": latestIpLog.City,
"zip": latestIpLog.Zip,
"lat": latestIpLog.Lat,
"lon": latestIpLog.Lon,
"timezone": latestIpLog.Timezone,
"isp": latestIpLog.ISP,
"org": latestIpLog.Org,
"asInfo": latestIpLog.AsInfo,
"query": latestIpLog.Query,
"createTime": latestIpLog.CreateTime,
}
}
// 在线状态计算:若最后心跳时间在 5 分钟内,则认为在线
isOnline := false
if row.LastHeartbeatAt != nil && time.Since(*row.LastHeartbeatAt) < 5*time.Minute {
isOnline = true
}
return map[string]interface{}{
"id": row.ID,
"deviceInfo": row.DeviceInfo,
"machineCode": row.MachineCode,
"status": row.Status,
"isOnline": isOnline,
"lastHeartbeatAt": row.LastHeartbeatAt,
"system": row.System,
"os": row.System,
"version": row.Version,
"bindAccount": row.BindAccount,
"bindActivationCode": bindActivationCode,
"activationCode": bindActivationCode,
"activationCodeId": activationCodeId,
"ownerUserId": row.OwnerUserID,
"ownerUserName": row.OwnerUserName,
"activationTime": lastActivatedAt,
"lastActivatedAt": lastActivatedAt,
"expireTime": expireTime,
"expiredAt": expireTime,
"activationCount": activationCount,
"extractCount": extractCount,
"lastExtractedAt": lastExtractedAt,
"lastLoginIp": lastLoginIp,
"lastLoginIpInfo": lastLoginIpInfo,
"remark": row.Remark,
"createTime": row.CreateTime,
"updateTime": row.UpdateTime,
}
}
// List GET /platform/cursor/equipment/list
// 优化:用 3 条批量 SQL 替代 N+1列表只返回必要字段详情由 Detail 接口按需加载完整数据。
func (c *PlatformCursorEquipmentController) List() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
page, _ := c.GetInt("page", 1)
pageSize, _ := c.GetInt("pageSize", 20)
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 20
}
if pageSize > 200 {
pageSize = 200
}
keyword := strings.TrimSpace(c.GetString("keyword"))
statusText := strings.TrimSpace(c.GetString("status"))
system := strings.TrimSpace(c.GetString("system"))
if system == "" {
system = strings.TrimSpace(c.GetString("os"))
}
qs := models.Orm.QueryTable(new(models.PlatformCursorEquipment)).Filter("delete_time__isnull", true)
if keyword != "" {
cond := orm.NewCondition().
Or("machine_code__icontains", keyword).
Or("device_info__icontains", keyword).
Or("bind_account__icontains", keyword).
Or("owner_user_name__icontains", keyword).
Or("remark__icontains", keyword)
qs = qs.SetCond(cond)
}
if statusText != "" {
status, err := strconv.ParseInt(statusText, 10, 8)
if err == nil && cursorEquipmentStatusValid(int8(status)) {
qs = qs.Filter("status", int8(status))
}
}
if system != "" {
qs = qs.Filter("system__icontains", system)
}
total, _ := qs.Count()
var rows []models.PlatformCursorEquipment
_, err := qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&rows)
if err != nil {
c.jsonErr(500, 500, "获取设备列表失败: "+err.Error())
return
}
if len(rows) == 0 {
c.ok(map[string]interface{}{
"list": []interface{}{},
"total": total,
"page": page,
"pageSize": pageSize,
})
return
}
// ── 收集本页所有设备的 ID 和机器码 ──────────────────────────────────
deviceIDs := make([]uint64, 0, len(rows))
machineCodes := make([]string, 0, len(rows))
codeToID := make(map[string]uint64, len(rows)) // machineCode -> equipmentID
for _, r := range rows {
deviceIDs = append(deviceIDs, r.ID)
machineCodes = append(machineCodes, r.MachineCode)
codeToID[r.MachineCode] = r.ID
}
// ── 批量查激活码1 条 SQL──────────────────────────────────────────
// 只取本页设备相关的所有激活码,按 id 降序,在内存里取每个设备的 latest
type actSummary struct {
code string
codeID uint64
count int64
lastActivatedAt interface{}
expiredAt interface{}
}
actMap := make(map[uint64]*actSummary, len(rows))
var allActs []models.PlatformCursorActivationCode
if len(deviceIDs) > 0 {
// Beego ORM 的 __in 过滤
ids := make([]interface{}, len(deviceIDs))
for i, id := range deviceIDs {
ids[i] = id
}
codes := make([]interface{}, len(machineCodes))
for i, mc := range machineCodes {
codes[i] = mc
}
actCond := orm.NewCondition().
And("delete_time__isnull", true).
AndCond(orm.NewCondition().
Or("bind_device_id__in", ids).
Or("machine_code__in", codes))
models.Orm.QueryTable(new(models.PlatformCursorActivationCode)).
SetCond(actCond).
OrderBy("-activated_at", "-id").
All(&allActs)
}
for i := range allActs {
a := &allActs[i]
// 确定归属设备 ID
var devID uint64
if a.BindDeviceID != nil && *a.BindDeviceID != 0 {
devID = *a.BindDeviceID
} else if a.MachineCode != nil {
devID = codeToID[*a.MachineCode]
}
if devID == 0 {
continue
}
s, exists := actMap[devID]
if !exists {
s = &actSummary{}
actMap[devID] = s
}
s.count++
// 第一条就是 latest已按 -activated_at,-id 排序)
if s.codeID == 0 {
s.code = a.Code
s.codeID = a.ID
if a.ActivatedAt != nil {
s.lastActivatedAt = a.ActivatedAt
}
if a.ExpiredAt != nil {
s.expiredAt = a.ExpiredAt
}
}
}
// ── 批量查提取记录1 条 SQL──────────────────────────────────────────
type extractSummary struct {
count int64
lastExtracted interface{}
}
extractMap := make(map[uint64]*extractSummary, len(rows))
type extractRow struct {
MachineCode string
Cnt int64
LastExtracted *string
}
var extractRows []extractRow
if len(machineCodes) > 0 {
inPlaceholders := make([]string, len(machineCodes))
inArgs := make([]interface{}, len(machineCodes))
for i, mc := range machineCodes {
inPlaceholders[i] = "?"
inArgs[i] = mc
}
sql := "SELECT machine_code, COUNT(*) AS cnt, MAX(extracted_time) AS last_extracted " +
"FROM yz_platform_account_pool_cursor " +
"WHERE is_extracted > 0 AND delete_time IS NULL " +
"AND machine_code IN (" + strings.Join(inPlaceholders, ",") + ") " +
"GROUP BY machine_code"
models.Orm.Raw(sql, inArgs...).QueryRows(&extractRows)
}
for _, er := range extractRows {
devID := codeToID[er.MachineCode]
if devID == 0 {
continue
}
es := &extractSummary{count: er.Cnt}
if er.LastExtracted != nil {
es.lastExtracted = *er.LastExtracted
}
extractMap[devID] = es
}
// ── 批量查最后登录 IP1 条 SQL────────────────────────────────────────
// 每个设备取 id 最大的一条
type ipRow struct {
EquipmentID uint64
MachineCode string
Query string
}
ipMap := make(map[uint64]string, len(rows))
if len(deviceIDs) > 0 {
inPlaceholders := make([]string, len(deviceIDs))
inArgs := make([]interface{}, len(deviceIDs))
for i, id := range deviceIDs {
inPlaceholders[i] = "?"
inArgs[i] = id
}
codePlaceholders := make([]string, len(machineCodes))
codeArgs := make([]interface{}, len(machineCodes))
for i, mc := range machineCodes {
codePlaceholders[i] = "?"
codeArgs[i] = mc
}
allArgs := append(inArgs, codeArgs...)
ipSQL := "SELECT equipment_id, machine_code, query FROM yz_platform_cursor_equipment_ip_log " +
"WHERE id IN (" +
" SELECT MAX(id) FROM yz_platform_cursor_equipment_ip_log " +
" WHERE equipment_id IN (" + strings.Join(inPlaceholders, ",") + ")" +
" OR machine_code IN (" + strings.Join(codePlaceholders, ",") + ")" +
" GROUP BY COALESCE(NULLIF(equipment_id,0), machine_code)" +
")"
var ipRows []ipRow
models.Orm.Raw(ipSQL, allArgs...).QueryRows(&ipRows)
for _, ir := range ipRows {
devID := ir.EquipmentID
if devID == 0 {
devID = codeToID[ir.MachineCode]
}
if devID != 0 {
ipMap[devID] = ir.Query
}
}
}
// ── 组装列表(纯内存操作)────────────────────────────────────────────
list := make([]map[string]interface{}, 0, len(rows))
for i := range rows {
r := &rows[i]
// 激活码信息
var bindActivationCode interface{}
var activationCodeId interface{}
var lastActivatedAt interface{} = r.ActivationTime
var expiredAt interface{} = r.ExpireTime
var activationCount int64
if s, ok := actMap[r.ID]; ok {
activationCount = s.count
bindActivationCode = s.code
activationCodeId = s.codeID
if s.lastActivatedAt != nil {
lastActivatedAt = s.lastActivatedAt
}
if s.expiredAt != nil {
expiredAt = s.expiredAt
}
}
// 提取记录
var extractCount int64
var lastExtractedAt interface{}
if es, ok := extractMap[r.ID]; ok {
extractCount = es.count
lastExtractedAt = es.lastExtracted
}
// 最后登录 IP
var lastLoginIp interface{}
if ip, ok := ipMap[r.ID]; ok && ip != "" {
lastLoginIp = ip
}
// 在线状态计算:若最后心跳时间在 5 分钟内,则认为在线
isOnline := false
if r.LastHeartbeatAt != nil && time.Since(*r.LastHeartbeatAt) < 5*time.Minute {
isOnline = true
}
list = append(list, map[string]interface{}{
"id": r.ID,
"deviceInfo": r.DeviceInfo,
"machineCode": r.MachineCode,
"status": r.Status,
"isOnline": isOnline,
"lastHeartbeatAt": r.LastHeartbeatAt,
"system": r.System,
"os": r.System,
"version": r.Version,
"bindAccount": r.BindAccount,
"bindActivationCode": bindActivationCode,
"activationCode": bindActivationCode,
"activationCodeId": activationCodeId,
"ownerUserId": r.OwnerUserID,
"ownerUserName": r.OwnerUserName,
"activationTime": lastActivatedAt,
"lastActivatedAt": lastActivatedAt,
"expireTime": expiredAt,
"expiredAt": expiredAt,
"activationCount": activationCount,
"extractCount": extractCount,
"lastExtractedAt": lastExtractedAt,
"lastLoginIp": lastLoginIp,
// 列表不返回 lastLoginIpInfo点详情时由 Detail 接口加载完整 IP 信息
"remark": r.Remark,
"createTime": r.CreateTime,
"updateTime": r.UpdateTime,
})
}
c.ok(map[string]interface{}{
"list": list,
"total": total,
"page": page,
"pageSize": pageSize,
})
}
// Detail GET /platform/cursor/equipment/detail/:id
func (c *PlatformCursorEquipmentController) Detail() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
if err != nil || id == 0 {
c.jsonErr(400, 400, "无效ID")
return
}
var row models.PlatformCursorEquipment
err = models.Orm.QueryTable(new(models.PlatformCursorEquipment)).
Filter("id", id).
Filter("delete_time__isnull", true).
One(&row)
if err != nil {
c.jsonErr(404, 404, "设备不存在")
return
}
c.ok(c.rowToMap(&row))
}
type platformCursorEquipmentPayload struct {
ID *uint64 `json:"id"`
DeviceInfo *string `json:"deviceInfo"`
MachineCode *string `json:"machineCode"`
Status *int8 `json:"status"`
System *string `json:"system"`
Version *string `json:"version"`
BindAccount *string `json:"bindAccount"`
OwnerUserID *uint64 `json:"ownerUserId"`
OwnerUserName *string `json:"ownerUserName"`
ActivationTime *string `json:"activationTime"`
ExpireTime *string `json:"expireTime"`
Remark *string `json:"remark"`
}
func (c *PlatformCursorEquipmentController) readPayload() (*platformCursorEquipmentPayload, error) {
body, _ := io.ReadAll(c.Ctx.Request.Body)
var p platformCursorEquipmentPayload
if err := json.Unmarshal(body, &p); err != nil {
return nil, err
}
return &p, nil
}
func (c *PlatformCursorEquipmentController) payloadToUpdateMap(p *platformCursorEquipmentPayload, includeMachineCode bool) (map[string]interface{}, error) {
up := map[string]interface{}{}
if includeMachineCode {
if p.MachineCode == nil || strings.TrimSpace(*p.MachineCode) == "" {
return nil, fmt.Errorf("机器码不能为空")
}
up["machine_code"] = strings.TrimSpace(*p.MachineCode)
} else if p.MachineCode != nil {
if strings.TrimSpace(*p.MachineCode) == "" {
return nil, fmt.Errorf("机器码不能为空")
}
up["machine_code"] = strings.TrimSpace(*p.MachineCode)
}
if p.DeviceInfo != nil {
up["device_info"] = cursorEquipmentTrimPtr(p.DeviceInfo)
}
if p.Status != nil {
if !cursorEquipmentStatusValid(*p.Status) {
return nil, fmt.Errorf("状态不合法支持0 未激活、1 激活中、2 已过期、3 已禁用")
}
up["status"] = *p.Status
}
if p.System != nil {
up["system"] = cursorEquipmentTrimPtr(p.System)
}
if p.Version != nil {
up["version"] = cursorEquipmentTrimPtr(p.Version)
}
if p.BindAccount != nil {
up["bind_account"] = cursorEquipmentTrimPtr(p.BindAccount)
}
if p.OwnerUserID != nil {
if *p.OwnerUserID == 0 {
up["owner_user_id"] = nil
} else {
up["owner_user_id"] = *p.OwnerUserID
}
}
if p.OwnerUserName != nil {
up["owner_user_name"] = cursorEquipmentTrimPtr(p.OwnerUserName)
}
if p.ActivationTime != nil {
up["activation_time"] = cursorEquipmentTimePtr(p.ActivationTime)
}
if p.ExpireTime != nil {
up["expire_time"] = cursorEquipmentTimePtr(p.ExpireTime)
}
if p.Remark != nil {
up["remark"] = cursorEquipmentTrimPtr(p.Remark)
}
return up, nil
}
// Add POST /platform/cursor/equipment/add
func (c *PlatformCursorEquipmentController) Add() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
p, err := c.readPayload()
if err != nil {
c.jsonErr(400, 400, "参数错误")
return
}
up, err := c.payloadToUpdateMap(p, true)
if err != nil {
c.jsonErr(400, 400, err.Error())
return
}
status := int8(0)
if value, ok := up["status"]; ok {
status = value.(int8)
}
row := models.PlatformCursorEquipment{
MachineCode: up["machine_code"].(string),
Status: status,
DeviceInfo: cursorEquipmentTrimPtr(p.DeviceInfo),
System: cursorEquipmentTrimPtr(p.System),
Version: cursorEquipmentTrimPtr(p.Version),
BindAccount: cursorEquipmentTrimPtr(p.BindAccount),
OwnerUserID: p.OwnerUserID,
OwnerUserName: cursorEquipmentTrimPtr(p.OwnerUserName),
ActivationTime: cursorEquipmentTimePtr(p.ActivationTime),
ExpireTime: cursorEquipmentTimePtr(p.ExpireTime),
Remark: cursorEquipmentTrimPtr(p.Remark),
CreateTime: time.Now(),
}
if row.OwnerUserID != nil && *row.OwnerUserID == 0 {
row.OwnerUserID = nil
}
id, err := models.Orm.Insert(&row)
if err != nil {
if strings.Contains(strings.ToLower(err.Error()), "duplicate") {
c.jsonErr(400, 400, "机器码已存在")
return
}
c.jsonErr(500, 500, "新增设备失败: "+err.Error())
return
}
c.ok(map[string]interface{}{"id": id})
}
// Update POST /platform/cursor/equipment/update
func (c *PlatformCursorEquipmentController) Update() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
p, err := c.readPayload()
if err != nil {
c.jsonErr(400, 400, "参数错误")
return
}
if p.ID == nil || *p.ID == 0 {
c.jsonErr(400, 400, "无效ID")
return
}
up, err := c.payloadToUpdateMap(p, false)
if err != nil {
c.jsonErr(400, 400, err.Error())
return
}
if len(up) == 0 {
c.jsonErr(400, 400, "无更新字段")
return
}
now := time.Now()
up["update_time"] = now
n, err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)).
Filter("id", *p.ID).
Filter("delete_time__isnull", true).
Update(up)
if err != nil {
if strings.Contains(strings.ToLower(err.Error()), "duplicate") {
c.jsonErr(400, 400, "机器码已存在")
return
}
c.jsonErr(500, 500, "更新设备失败: "+err.Error())
return
}
if n == 0 {
c.jsonErr(404, 404, "设备不存在")
return
}
c.ok(nil)
}
// Delete POST /platform/cursor/equipment/delete/:id
func (c *PlatformCursorEquipmentController) Delete() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
if err != nil || id == 0 {
c.jsonErr(400, 400, "无效ID")
return
}
now := time.Now()
n, err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)).
Filter("id", id).
Filter("delete_time__isnull", true).
Update(map[string]interface{}{"delete_time": now})
if err != nil {
c.jsonErr(500, 500, "删除设备失败: "+err.Error())
return
}
if n == 0 {
c.jsonErr(404, 404, "设备不存在")
return
}
c.ok(nil)
}
type platformCursorEquipmentActivatePayload struct {
ID uint64 `json:"id"`
}
// Activate POST /platform/cursor/equipment/activate
func (c *PlatformCursorEquipmentController) Activate() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
body, _ := io.ReadAll(c.Ctx.Request.Body)
var p platformCursorEquipmentActivatePayload
if err := json.Unmarshal(body, &p); err != nil || p.ID == 0 {
c.jsonErr(400, 400, "无效ID")
return
}
now := time.Now()
n, err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)).
Filter("id", p.ID).
Filter("delete_time__isnull", true).
Update(map[string]interface{}{
"status": int8(1),
"activation_time": now,
"update_time": now,
})
if err != nil {
c.jsonErr(500, 500, "激活设备失败: "+err.Error())
return
}
if n == 0 {
c.jsonErr(404, 404, "设备不存在")
return
}
c.ok(nil)
}
// ActivationRecords GET /platform/cursor/equipment/activationRecords
func (c *PlatformCursorEquipmentController) ActivationRecords() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
equipmentID, _ := c.GetUint64("equipmentId")
if equipmentID == 0 {
equipmentID, _ = c.GetUint64("id")
}
if equipmentID == 0 {
c.jsonErr(400, 400, "缺少设备ID")
return
}
var equipment models.PlatformCursorEquipment
if err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)).
Filter("id", equipmentID).
Filter("delete_time__isnull", true).
One(&equipment); err != nil {
c.jsonErr(404, 404, "设备不存在")
return
}
page, _ := c.GetInt("page", 1)
pageSize, _ := c.GetInt("pageSize", 20)
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 20
}
if pageSize > 200 {
pageSize = 200
}
cond := orm.NewCondition().
And("delete_time__isnull", true).
AndCond(orm.NewCondition().
Or("bind_device_id", equipment.ID).
Or("machine_code", equipment.MachineCode))
qs := models.Orm.QueryTable(new(models.PlatformCursorActivationCode)).SetCond(cond)
total, _ := qs.Count()
var rows []models.PlatformCursorActivationCode
if _, err := qs.OrderBy("-activated_at", "-id").Limit(pageSize, (page-1)*pageSize).All(&rows); err != nil {
c.jsonErr(500, 500, "获取激活记录失败: "+err.Error())
return
}
list := make([]map[string]interface{}, 0, len(rows))
for i := range rows {
row := rows[i]
list = append(list, map[string]interface{}{
"id": row.ID,
"code": row.Code,
"activationCode": row.Code,
"status": row.Status,
"durationDays": row.DurationDays,
"machineCode": row.MachineCode,
"deviceInfo": row.DeviceInfo,
"ownerUserId": row.OwnerUserID,
"ownerUserName": row.OwnerUserName,
"activatedAt": row.ActivatedAt,
"expiredAt": row.ExpiredAt,
"createdAt": row.CreateTime,
"remark": row.Remark,
})
}
c.ok(map[string]interface{}{
"list": list,
"total": total,
"page": page,
"pageSize": pageSize,
})
}
// ExtractRecords GET /platform/cursor/equipment/extractRecords
func (c *PlatformCursorEquipmentController) ExtractRecords() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
equipmentID, _ := c.GetUint64("equipmentId")
if equipmentID == 0 {
equipmentID, _ = c.GetUint64("id")
}
if equipmentID == 0 {
c.jsonErr(400, 400, "缺少设备ID")
return
}
var equipment models.PlatformCursorEquipment
if err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)).
Filter("id", equipmentID).
Filter("delete_time__isnull", true).
One(&equipment); err != nil {
c.jsonErr(404, 404, "设备不存在")
return
}
page, _ := c.GetInt("page", 1)
pageSize, _ := c.GetInt("pageSize", 20)
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 20
}
if pageSize > 200 {
pageSize = 200
}
qs := models.Orm.QueryTable(new(models.PlatformAccountPoolCursor)).
Filter("delete_time__isnull", true).
Filter("is_extracted__gt", 0).
Filter("machine_code", equipment.MachineCode)
total, _ := qs.Count()
var rows []models.PlatformAccountPoolCursor
if _, err := qs.OrderBy("-extracted_time", "-id").Limit(pageSize, (page-1)*pageSize).All(&rows); err != nil {
c.jsonErr(500, 500, "获取提取记录失败: "+err.Error())
return
}
list := make([]map[string]interface{}, 0, len(rows))
for i := range rows {
row := rows[i]
content := buildCardResult(&row.Account, &row.Password, row.Token, row.DataType)
list = append(list, map[string]interface{}{
"id": row.ID,
"status": row.IsExtracted,
"isExtracted": row.IsExtracted,
"platform": row.ExtractedPlatform,
"extractedPlatform": row.ExtractedPlatform,
"dataType": row.DataType,
"type": row.DataType,
"account": row.Account,
"password": row.Password,
"token": row.Token,
"content": content,
"extractedAt": row.ExtractedTime,
"createdAt": row.ExtractedTime,
"remark": row.Remark,
})
}
c.ok(map[string]interface{}{
"list": list,
"total": total,
"page": page,
"pageSize": pageSize,
})
}
// IpLogs GET /platform/cursor/equipment/ipLogs?equipmentId=1
func (c *PlatformCursorEquipmentController) IpLogs() {
if _, err := c.platformClaims(); err != nil {
c.jsonErr(401, 401, err.Error())
return
}
equipmentID, _ := c.GetUint64("equipmentId")
if equipmentID == 0 {
equipmentID, _ = c.GetUint64("id")
}
if equipmentID == 0 {
c.jsonErr(400, 400, "缺少设备ID")
return
}
var equipment models.PlatformCursorEquipment
if err := models.Orm.QueryTable(new(models.PlatformCursorEquipment)).
Filter("id", equipmentID).
Filter("delete_time__isnull", true).
One(&equipment); err != nil {
c.jsonErr(404, 404, "设备不存在")
return
}
page, _ := c.GetInt("page", 1)
pageSize, _ := c.GetInt("pageSize", 20)
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 20
}
if pageSize > 200 {
pageSize = 200
}
ipCond := orm.NewCondition().
AndCond(orm.NewCondition().
Or("equipment_id", equipment.ID).
Or("machine_code", equipment.MachineCode))
qs := models.Orm.QueryTable(new(models.PlatformCursorEquipmentIpLog)).SetCond(ipCond)
total, _ := qs.Count()
var rows []models.PlatformCursorEquipmentIpLog
if _, err := qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&rows); err != nil {
c.jsonErr(500, 500, "获取 IP 日志失败: "+err.Error())
return
}
list := make([]map[string]interface{}, 0, len(rows))
for _, row := range rows {
list = append(list, map[string]interface{}{
"id": row.ID,
"source": row.Source,
"status": row.Status,
"country": row.Country,
"countryCode": row.CountryCode,
"region": row.Region,
"regionName": row.RegionName,
"city": row.City,
"zip": row.Zip,
"lat": row.Lat,
"lon": row.Lon,
"timezone": row.Timezone,
"isp": row.ISP,
"org": row.Org,
"asInfo": row.AsInfo,
"query": row.Query,
"createTime": row.CreateTime,
})
}
c.ok(map[string]interface{}{
"list": list,
"total": total,
"page": page,
"pageSize": pageSize,
})
}