ai_xiaopei
6 days ago 1196f409d86bc61e7596eb274840244a62ce84ba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package classify
 
import (
    "encoding/json"
    "fmt"
    "os"
    "os/exec"
    "path/filepath"
    "strings"
)
 
// Migration 单个迁移项
type Migration struct {
    Source string `json:"source"`
    Target string `json:"target"`
}
 
// MigrationPlan 迁移计划
type MigrationPlan struct {
    Total      int         `json:"total"`
    Migrations []Migration `json:"migrations"`
}
 
// LoadClassification 加载分类结果
func LoadClassification(vaultPath, filename string) (*ClassificationResult, error) {
    path := filepath.Join(vaultPath, filename)
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("读取文件失败: %w", err)
    }
 
    var result ClassificationResult
    if err := json.Unmarshal(data, &result); err != nil {
        return nil, fmt.Errorf("解析 JSON 失败: %w", err)
    }
 
    return &result, nil
}
 
// GenerateMigrationPlan 生成迁移计划
func GenerateMigrationPlan(vaultPath string, classification *ClassificationResult) (*MigrationPlan, error) {
    plan := &MigrationPlan{
        Total:      len(classification.Items),
        Migrations: []Migration{},
    }
 
    // 跟踪已使用的目标路径
    usedTargets := make(map[string]bool)
 
    for _, item := range classification.Items {
        // 根据 platform 和 device 生成目标路径
        targetDir := getTargetDir(item.Platform, item.Device)
        baseName := filepath.Base(item.Path)
        targetPath := filepath.Join(targetDir, baseName)
 
        // 如果目标路径已使用,添加数字后缀直到找到唯一路径
        counter := 1
        for usedTargets[targetPath] {
            counter++
            ext := filepath.Ext(baseName)
            nameWithoutExt := strings.TrimSuffix(baseName, ext)
            targetPath = filepath.Join(targetDir, fmt.Sprintf("%s_%d%s", nameWithoutExt, counter, ext))
        }
        usedTargets[targetPath] = true
 
        plan.Migrations = append(plan.Migrations, Migration{
            Source: item.Path,
            Target: targetPath,
        })
    }
 
    return plan, nil
}
 
// getTargetDir 根据平台和设备获取目标目录
func getTargetDir(platform, device string) string {
    // 平台目录映射(支持中文和英文标识符)
    platformDir := map[string]string{
        // 英文标识符
        "elc":         "电子秤平台",
        "ops":         "运营管理平台",
        "both":        "共有硬件",
        "third_party": "第三方平台",
        "general":     "通用",
        // 中文标识符
        "电子秤平台":   "电子秤平台",
        "运营管理平台": "运营管理平台",
        "共有":         "共有硬件",
        "第三方平台":   "第三方平台",
        "通用":         "通用",
    }
 
    // 设备目录映射(支持中文和英文标识符)
    deviceDir := map[string]string{
        // 英文标识符
        "scale":         "电子秤",
        "gun":           "智能枪",
        "valve":         "智能阀",
        "box":           "艾信盒子",
        "app_safety":    "安全用气App",
        "app_delivery":  "易配送App",
        "app_assistant": "艾信助手App",
        "app_lpg":       "艾信LPG小程序",
        "app_shipping":  "艾信发货小程序",
        "none":          "通用",
        // 中文标识符
        "电子秤":          "电子秤",
        "智能枪":          "智能枪",
        "智能阀":          "智能阀",
        "艾信盒子":        "艾信盒子",
        "安全用气App":     "安全用气App",
        "易配送App":       "易配送App",
        "艾信助手App":     "艾信助手App",
        "艾信LPG小程序":   "艾信LPG小程序",
        "艾信发货小程序":  "艾信发货小程序",
        "无":              "通用",
        "综合":            "通用",
    }
 
    pDir := platformDir[platform]
    if pDir == "" {
        pDir = "通用"
    }
 
    dDir := deviceDir[device]
    if dDir == "" {
        dDir = "通用"
    }
 
    return filepath.Join(pDir, dDir)
}
 
// SaveMigrationPlan 保存迁移计划
func SaveMigrationPlan(vaultPath string, plan *MigrationPlan) error {
    path := filepath.Join(vaultPath, "migration-plan.json")
    data, err := json.MarshalIndent(plan, "", "  ")
    if err != nil {
        return err
    }
 
    return os.WriteFile(path, data, 0644)
}
 
// ExecuteMigration 执行迁移
func ExecuteMigration(vaultPath string, plan *MigrationPlan) error {
    for i, migration := range plan.Migrations {
        fmt.Printf("[%d/%d] 移动 %s -> %s\n", i+1, len(plan.Migrations), migration.Source, migration.Target)
 
        sourcePath := filepath.Join(vaultPath, migration.Source)
        targetPath := filepath.Join(vaultPath, migration.Target)
 
        // 检查源文件是否存在
        if _, err := os.Stat(sourcePath); os.IsNotExist(err) {
            fmt.Printf("  跳过(源文件不存在)\n")
            continue
        }
 
        // 创建目标目录
        targetDir := filepath.Dir(targetPath)
        if err := os.MkdirAll(targetDir, 0755); err != nil {
            return fmt.Errorf("创建目录失败: %w", err)
        }
 
        // 使用 git mv 保留历史
        cmd := exec.Command("git", "mv", sourcePath, targetPath)
        cmd.Dir = vaultPath
        if output, err := cmd.CombinedOutput(); err != nil {
            return fmt.Errorf("git mv 失败: %w\n%s", err, output)
        }
    }
 
    return nil
}