更新测试文档并增强设备管理逻辑

- 新增了一项功能,用于自动生成文章中的提及内容,从而优化了系统中创建计划流程的测试用例文档。
- 更新了测试关联文档,以纳入基于不同场景的测试用例的归档和复用规则。
- 实现了在未指定设备时选择默认设备的逻辑,确保设备管理流程更加顺畅。
- 在计划创建的上下文中明确了设备组的需求,从而提高了系统的整体可靠性。
This commit is contained in:
Alex-larget
2026-03-16 11:24:42 +08:00
parent d4ba905ee5
commit 0e7b81eaa8
10 changed files with 405 additions and 11 deletions

View File

@@ -10,6 +10,7 @@ import (
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
@@ -193,6 +194,113 @@ func ckbOpenGetPlanDetail(token string, planID int64) (string, error) {
return result.Data.APIKey, nil
}
// ckbOpenGetDefaultDeviceID 获取默认设备 ID拉设备列表取第一个 memo 或 nickname 包含 "soul" 的设备;用于 deviceGroups 必填时的默认值
func ckbOpenGetDefaultDeviceID(token string) (int64, error) {
u := ckbOpenBaseURL + "/v1/devices?keyword=soul&page=1&limit=50"
req, err := http.NewRequest(http.MethodGet, u, nil)
if err != nil {
return 0, fmt.Errorf("构造设备列表请求失败: %w", err)
}
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return 0, fmt.Errorf("请求存客宝设备列表失败: %w", err)
}
defer resp.Body.Close()
b, _ := io.ReadAll(resp.Body)
var parsed map[string]interface{}
if err := json.Unmarshal(b, &parsed); err != nil {
return 0, fmt.Errorf("解析设备列表失败: %w", err)
}
var listAny interface{}
if dataVal, ok := parsed["data"].(map[string]interface{}); ok {
listAny = dataVal["list"]
} else if la, ok := parsed["list"]; ok {
listAny = la
}
arr, ok := listAny.([]interface{})
if !ok {
return 0, fmt.Errorf("设备列表格式异常")
}
// 优先匹配 memo/nickname 包含 soul 的设备若无则取第一个keyword 可能已过滤)
for _, item := range arr {
m, ok := item.(map[string]interface{})
if !ok {
continue
}
memo := toString(m["memo"])
if memo == "" {
memo = toString(m["imei"])
}
nickname := toString(m["nickname"])
lowerMemo := strings.ToLower(memo)
lowerNick := strings.ToLower(nickname)
if strings.Contains(lowerMemo, "soul") || strings.Contains(lowerNick, "soul") {
id := parseDeviceID(m["id"])
if id > 0 {
return id, nil
}
}
}
// 未找到含 soul 的,取第一个
if len(arr) > 0 {
if m, ok := arr[0].(map[string]interface{}); ok {
id := parseDeviceID(m["id"])
if id > 0 {
return id, nil
}
}
}
return 0, fmt.Errorf("未找到名为 soul 的设备,请先在存客宝添加设备并设置 memo 或 nickname 包含 soul")
}
func toString(v interface{}) string {
if v == nil {
return ""
}
switch val := v.(type) {
case string:
return val
case float64:
return strconv.FormatFloat(val, 'f', -1, 64)
case int:
return strconv.Itoa(val)
case int64:
return strconv.FormatInt(val, 10)
default:
return fmt.Sprint(v)
}
}
func parseDeviceID(v interface{}) int64 {
if v == nil {
return 0
}
switch val := v.(type) {
case float64:
if val > 0 {
return int64(val)
}
case int:
if val > 0 {
return int64(val)
}
case int64:
if val > 0 {
return val
}
case string:
if val == "" {
return 0
}
n, err := strconv.ParseInt(val, 10, 64)
if err == nil && n > 0 {
return n
}
}
return 0
}
// ckbOpenDeletePlan 调用 DELETE /v1/plan/delete 删除存客宝获客计划
func ckbOpenDeletePlan(token string, planID int64) error {
payload := map[string]interface{}{"planId": planID}

View File

@@ -144,6 +144,15 @@ func DBPersonSave(c *gin.Context) {
deviceIDs = append(deviceIDs, id)
}
}
// deviceGroups 必填:未传时默认选择名为 soul 的设备
if len(deviceIDs) == 0 {
defaultID, err := ckbOpenGetDefaultDeviceID(openToken)
if err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "获取默认设备失败: " + err.Error()})
return
}
deviceIDs = []int64{defaultID}
}
planPayload := map[string]interface{}{
"name": name,
"sceneId": 11,
@@ -156,9 +165,7 @@ func DBPersonSave(c *gin.Context) {
"enabled": true,
"tips": body.Tips,
"distributionEnabled": false,
}
if len(deviceIDs) > 0 {
planPayload["deviceGroups"] = deviceIDs
"deviceGroups": deviceIDs,
}
planID, ckbCreateData, ckbResponse, err := ckbOpenCreatePlan(openToken, planPayload)
@@ -193,13 +200,11 @@ func DBPersonSave(c *gin.Context) {
StartTime: startTime,
EndTime: endTime,
}
if len(deviceIDs) > 0 {
idsStr := make([]string, 0, len(deviceIDs))
for _, id := range deviceIDs {
idsStr = append(idsStr, fmt.Sprintf("%d", id))
}
newPerson.DeviceGroups = strings.Join(idsStr, ",")
idsStr := make([]string, 0, len(deviceIDs))
for _, id := range deviceIDs {
idsStr = append(idsStr, fmt.Sprintf("%d", id))
}
newPerson.DeviceGroups = strings.Join(idsStr, ",")
if err := db.Create(&newPerson).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})