mirror of
https://github.com/black-ant/Ant-Browser.git
synced 2026-07-14 18:48:55 +08:00
289 lines
7.5 KiB
Go
289 lines
7.5 KiB
Go
package backend
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"ant-chrome/backend/internal/automation"
|
|
|
|
wailsruntime "github.com/wailsapp/wails/v2/pkg/runtime"
|
|
)
|
|
|
|
func (a *App) AutomationScriptExport(scriptID string) (map[string]any, error) {
|
|
a.maintenanceMu.Lock()
|
|
defer a.maintenanceMu.Unlock()
|
|
|
|
if a.ctx == nil {
|
|
return nil, fmt.Errorf("应用上下文未初始化")
|
|
}
|
|
|
|
bundle, err := a.automationScriptStore().ExportBundle(strings.TrimSpace(scriptID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
payload, err := automation.MarshalScriptTemplate(bundle)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
savePath, err := wailsruntime.SaveFileDialog(a.ctx, wailsruntime.SaveDialogOptions{
|
|
Title: "导出脚本模板",
|
|
DefaultFilename: buildAutomationScriptTemplateFilename(bundle.Record.Name),
|
|
Filters: []wailsruntime.FileFilter{
|
|
{DisplayName: "JSON 模板 (*.json)", Pattern: "*.json"},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("打开保存对话框失败: %w", err)
|
|
}
|
|
if strings.TrimSpace(savePath) == "" {
|
|
return map[string]any{
|
|
"cancelled": true,
|
|
"message": "已取消导出",
|
|
}, nil
|
|
}
|
|
|
|
savePath = ensureAutomationScriptTemplateJSONSuffix(savePath)
|
|
if err := os.WriteFile(savePath, payload, 0o644); err != nil {
|
|
return nil, fmt.Errorf("写入脚本模板失败: %w", err)
|
|
}
|
|
|
|
return map[string]any{
|
|
"cancelled": false,
|
|
"format": "json",
|
|
"path": savePath,
|
|
"fileCount": len(bundle.Files),
|
|
"message": "模板已导出",
|
|
}, nil
|
|
}
|
|
|
|
func (a *App) AutomationScriptExportZip(scriptID string) (map[string]any, error) {
|
|
a.maintenanceMu.Lock()
|
|
defer a.maintenanceMu.Unlock()
|
|
|
|
if a.ctx == nil {
|
|
return nil, fmt.Errorf("应用上下文未初始化")
|
|
}
|
|
|
|
bundle, err := a.automationScriptStore().ExportBundle(strings.TrimSpace(scriptID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
savePath, err := wailsruntime.SaveFileDialog(a.ctx, wailsruntime.SaveDialogOptions{
|
|
Title: "导出脚本 ZIP",
|
|
DefaultFilename: buildAutomationScriptPackageZipFilename(bundle.Record.Name),
|
|
Filters: []wailsruntime.FileFilter{
|
|
{DisplayName: "ZIP 脚本包 (*.zip)", Pattern: "*.zip"},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("打开保存对话框失败: %w", err)
|
|
}
|
|
if strings.TrimSpace(savePath) == "" {
|
|
return map[string]any{
|
|
"cancelled": true,
|
|
"message": "已取消导出",
|
|
}, nil
|
|
}
|
|
|
|
savePath = ensureAutomationScriptZipSuffix(savePath)
|
|
if err := automation.WriteScriptPackageZip(savePath, bundle); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return map[string]any{
|
|
"cancelled": false,
|
|
"format": "zip",
|
|
"path": savePath,
|
|
"fileCount": len(bundle.Files),
|
|
"message": "脚本包已导出",
|
|
}, nil
|
|
}
|
|
|
|
func (a *App) AutomationScriptExportBatchZip(scriptIDs []string) (map[string]any, error) {
|
|
a.maintenanceMu.Lock()
|
|
defer a.maintenanceMu.Unlock()
|
|
|
|
if a.ctx == nil {
|
|
return nil, fmt.Errorf("应用上下文未初始化")
|
|
}
|
|
|
|
normalizedIDs := make([]string, 0, len(scriptIDs))
|
|
seen := map[string]bool{}
|
|
for _, scriptID := range scriptIDs {
|
|
normalizedID := strings.TrimSpace(scriptID)
|
|
if normalizedID == "" || seen[normalizedID] {
|
|
continue
|
|
}
|
|
seen[normalizedID] = true
|
|
normalizedIDs = append(normalizedIDs, normalizedID)
|
|
}
|
|
if len(normalizedIDs) == 0 {
|
|
return nil, fmt.Errorf("请先勾选要导出的脚本")
|
|
}
|
|
|
|
store := a.automationScriptStore()
|
|
bundles := make([]automation.ImportedBundle, 0, len(normalizedIDs))
|
|
fileCount := 0
|
|
for _, scriptID := range normalizedIDs {
|
|
bundle, err := store.ExportBundle(scriptID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
fileCount += len(bundle.Files)
|
|
bundles = append(bundles, bundle)
|
|
}
|
|
|
|
savePath, err := wailsruntime.SaveFileDialog(a.ctx, wailsruntime.SaveDialogOptions{
|
|
Title: "导出脚本 ZIP",
|
|
DefaultFilename: buildAutomationScriptBatchZipFilename(len(bundles)),
|
|
Filters: []wailsruntime.FileFilter{
|
|
{DisplayName: "ZIP 脚本包 (*.zip)", Pattern: "*.zip"},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("打开保存对话框失败: %w", err)
|
|
}
|
|
if strings.TrimSpace(savePath) == "" {
|
|
return map[string]any{
|
|
"cancelled": true,
|
|
"message": "已取消导出",
|
|
}, nil
|
|
}
|
|
|
|
savePath = ensureAutomationScriptZipSuffix(savePath)
|
|
if err := automation.WriteScriptPackagesZip(savePath, bundles); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return map[string]any{
|
|
"cancelled": false,
|
|
"format": "zip",
|
|
"path": savePath,
|
|
"fileCount": fileCount,
|
|
"scriptCount": len(bundles),
|
|
"message": "脚本包已导出",
|
|
}, nil
|
|
}
|
|
|
|
func (a *App) AutomationScriptExportDirectory(scriptID string) (map[string]any, error) {
|
|
a.maintenanceMu.Lock()
|
|
defer a.maintenanceMu.Unlock()
|
|
|
|
if a.ctx == nil {
|
|
return nil, fmt.Errorf("应用上下文未初始化")
|
|
}
|
|
|
|
bundle, err := a.automationScriptStore().ExportBundle(strings.TrimSpace(scriptID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
baseDir, err := wailsruntime.OpenDirectoryDialog(a.ctx, wailsruntime.OpenDialogOptions{
|
|
Title: "选择导出目录",
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("打开目录对话框失败: %w", err)
|
|
}
|
|
if strings.TrimSpace(baseDir) == "" {
|
|
return map[string]any{
|
|
"cancelled": true,
|
|
"message": "已取消导出",
|
|
}, nil
|
|
}
|
|
|
|
targetDir := filepath.Join(
|
|
strings.TrimSpace(baseDir),
|
|
buildAutomationScriptPackageDirectoryName(bundle.Record.Name),
|
|
)
|
|
if err := automation.WriteScriptPackageDirectory(targetDir, bundle); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return map[string]any{
|
|
"cancelled": false,
|
|
"format": "directory",
|
|
"path": targetDir,
|
|
"fileCount": len(bundle.Files),
|
|
"message": "脚本目录已导出",
|
|
}, nil
|
|
}
|
|
|
|
func buildAutomationScriptTemplateFilename(scriptName string) string {
|
|
name := sanitizeAutomationScriptTemplateFilename(strings.TrimSpace(scriptName))
|
|
if name == "" {
|
|
name = "automation-script"
|
|
}
|
|
return fmt.Sprintf("%s-template-%s.json", name, time.Now().Format("20060102-150405"))
|
|
}
|
|
|
|
func ensureAutomationScriptTemplateJSONSuffix(path string) string {
|
|
trimmed := strings.TrimSpace(path)
|
|
if trimmed == "" {
|
|
return trimmed
|
|
}
|
|
if strings.HasSuffix(strings.ToLower(trimmed), ".json") {
|
|
return trimmed
|
|
}
|
|
return trimmed + ".json"
|
|
}
|
|
|
|
func buildAutomationScriptPackageZipFilename(scriptName string) string {
|
|
name := sanitizeAutomationScriptTemplateFilename(strings.TrimSpace(scriptName))
|
|
if name == "" {
|
|
name = "automation-script"
|
|
}
|
|
return fmt.Sprintf("%s-package-%s.zip", name, time.Now().Format("20060102-150405"))
|
|
}
|
|
|
|
func buildAutomationScriptBatchZipFilename(scriptCount int) string {
|
|
if scriptCount <= 1 {
|
|
return buildAutomationScriptPackageZipFilename("automation-script")
|
|
}
|
|
return fmt.Sprintf("automation-scripts-%d-package-%s.zip", scriptCount, time.Now().Format("20060102-150405"))
|
|
}
|
|
|
|
func ensureAutomationScriptZipSuffix(path string) string {
|
|
trimmed := strings.TrimSpace(path)
|
|
if trimmed == "" {
|
|
return trimmed
|
|
}
|
|
if strings.HasSuffix(strings.ToLower(trimmed), ".zip") {
|
|
return trimmed
|
|
}
|
|
return trimmed + ".zip"
|
|
}
|
|
|
|
func buildAutomationScriptPackageDirectoryName(scriptName string) string {
|
|
name := sanitizeAutomationScriptTemplateFilename(strings.TrimSpace(scriptName))
|
|
if name == "" {
|
|
name = "automation-script"
|
|
}
|
|
return fmt.Sprintf("%s-package-%s", name, time.Now().Format("20060102-150405"))
|
|
}
|
|
|
|
func sanitizeAutomationScriptTemplateFilename(value string) string {
|
|
replacer := strings.NewReplacer(
|
|
"\\", "-",
|
|
"/", "-",
|
|
":", "-",
|
|
"*", "-",
|
|
"?", "-",
|
|
"\"", "-",
|
|
"<", "-",
|
|
">", "-",
|
|
"|", "-",
|
|
)
|
|
cleaned := strings.TrimSpace(replacer.Replace(value))
|
|
cleaned = strings.Trim(cleaned, ". ")
|
|
if cleaned == "" {
|
|
return ""
|
|
}
|
|
return cleaned
|
|
}
|