feat: 初步完成GUI界面添加
Some checks failed
构建上传工具 / build-tool (push) Failing after 2m9s

This commit is contained in:
2025-10-13 21:32:02 +08:00
parent 3b6705d6ef
commit cccb31cbc5
10 changed files with 607 additions and 74 deletions

235
main.go
View File

@@ -3,21 +3,164 @@ package main
import (
"bufio"
"context"
"dypid-client/api"
"dypid-client/config"
"dypid-client/utils/folder"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/widget"
"golang.org/x/sync/errgroup"
)
var isRun = false
var logText = widget.NewMultiLineEntry()
func main() {
config.InitConfig()
myApp := app.New()
myWindow := myApp.NewWindow("抖音数据上传工具")
myWindow.Resize(fyne.NewSize(900, 550))
logText.Scroll = container.ScrollVerticalOnly
// 创建界面组件
urlEntry := widget.NewEntry()
urlEntry.SetPlaceHolder("http://127.0.0.1:8080")
urlEntry.Text = config.APPConfig.Url
urlEntry.OnChanged = func(s string) {
config.WriteConfig("url", urlEntry.Text)
}
tokenEntry := widget.NewEntry()
tokenEntry.SetPlaceHolder("请输入Token")
tokenEntry.Text = config.APPConfig.Token
tokenEntry.OnChanged = func(s string) {
config.WriteConfig("token", tokenEntry.Text)
}
selectedDirLabel := widget.NewEntry()
selectedDirLabel.SetPlaceHolder("未选择目录(默认为程序运行目录)")
selectedDirLabel.Text = config.APPConfig.LookingPath
selectedDirLabel.OnChanged = func(s string) {
config.WriteConfig("looking-path", selectedDirLabel.Text)
}
threadCountLabel := widget.NewEntry()
threadCountLabel.SetPlaceHolder("10")
threadCountLabel.Text = strconv.Itoa(config.APPConfig.ThreadCount)
threadCountLabel.OnChanged = func(s string) {
i, err := strconv.Atoi(threadCountLabel.Text)
if err != nil {
AddLog("输入上传线程错误")
}
config.WriteConfig("thread-count", i)
}
isRunOnStartWidget := widget.NewCheck("启动程序时启动上传程序", func(b bool) {
config.WriteConfig("is-run-on-start", b)
})
isRunOnStartWidget.Checked = config.APPConfig.IsRunOnStart
// 使用Windows原生目录选择按钮
selectDirBtn := widget.NewButton("选择检测目录", func() {
// 调用CGO实现的Windows原生对话框
selectedPath := folder.OpenFolderDialog()
if selectedPath == "" {
return
}
selectedDirLabel.SetText(selectedPath)
config.WriteConfig("looking-path", selectedPath)
})
// 开始运行按钮
startBtn := widget.NewButton("开始运行", func() {
if strings.TrimSpace(tokenEntry.Text) == "" {
AddLog("错误请输入Token")
return
}
AddLog(fmt.Sprintf("Token%s", tokenEntry.Text))
AddLog(fmt.Sprintf("检测目录:%s", selectedDirLabel.Text))
AddLog("===============================")
isRun = true
go StartLooking(selectedDirLabel.Text)
})
// 清除日志按钮
clearLogBtn := widget.NewButton("清除日志", func() {
logText.SetText("")
AddLog("日志已清除")
})
// 组装左侧面板
leftPanel := container.NewBorder(
nil,
// 底部 - 放置按钮
container.NewVBox(
isRunOnStartWidget,
startBtn,
clearLogBtn,
),
nil,
nil,
// 中间内容
container.NewVBox(
widget.NewLabelWithStyle("服务器地址:", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
urlEntry,
widget.NewSeparator(),
widget.NewLabelWithStyle("Token", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
tokenEntry,
widget.NewSeparator(),
widget.NewLabelWithStyle("检测目录:", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
selectedDirLabel,
selectDirBtn,
widget.NewSeparator(),
container.NewHBox(
widget.NewLabelWithStyle("单文件上传线程:", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
threadCountLabel,
),
widget.NewSeparator(),
layout.NewSpacer(), // 添加一个弹性空间,将内容向上推
),
)
// 组装右侧面板(日志显示)
rightPanel := container.NewBorder(
widget.NewLabelWithStyle("运行日志", fyne.TextAlignCenter, fyne.TextStyle{Bold: true}),
nil, nil, nil,
container.NewScroll(logText),
)
// 使用HSplit容器创建可调整大小的左右分割布局
splitContainer := container.NewHSplit(leftPanel, rightPanel)
splitContainer.SetOffset(0.35) // 左侧占35%宽度
myWindow.SetContent(splitContainer)
myWindow.ShowAndRun()
}
func AddLog(message string) {
fyne.Do(func() {
logText.Append(message + "\n")
// 自动滚动到底部
logText.CursorRow = len(logText.Text)
})
}
// 上传数据代码
var httpClient = &http.Client{
Transport: &http.Transport{
MaxIdleConns: 200,
@@ -32,26 +175,28 @@ type Task struct {
FileLines int
}
func main() {
initConfig()
//检测./upload
fmt.Println("程序启动成功正在检测txt文件")
func StartLooking(lookingPath string) {
//检测./
AddLog("程序启动成功正在检测txt文件")
for {
files, err := getTxtFiles("./")
var path = "./"
if lookingPath != "" {
path = lookingPath
}
files, err := getTxtFiles(path)
if err != nil {
fmt.Println(err)
AddLog(err.Error())
continue
}
if files != nil {
start := time.Now()
fileLines := make(map[string]int)
fmt.Println("正在统计", len(files), "个文件行数")
AddLog(fmt.Sprintf("正在统计 %v 个文件行数", len(files)))
for _, filePath := range files {
file, err := os.Open(filePath)
if err != nil {
fmt.Println("打开文件失败:", err)
AddLog("打开文件失败:" + err.Error())
}
// 使用 bufio.Scanner 逐行读取
scanner := bufio.NewScanner(file)
@@ -64,7 +209,7 @@ func main() {
continue
}
fileLines[filepath.Base(filePath)] = lineCount
fmt.Println(filepath.Base(filePath), "文件行数:", lineCount)
AddLog(fmt.Sprintf("%s 文件行数:%v", filepath.Base(filePath), lineCount))
}
@@ -84,11 +229,11 @@ func main() {
case <-ctx.Done():
return ctx.Err()
default:
fmt.Println("正在上传文件:", filepath.Base(task.FilePath))
AddLog("正在上传文件" + filepath.Base(task.FilePath))
processFile(task.FilePath, task.FileLines)
err := os.Truncate(task.FilePath, 0)
if err != nil {
fmt.Println("清空文件失败:", err)
AddLog("清空文件失败:" + err.Error())
}
return nil
}
@@ -97,52 +242,16 @@ func main() {
// 等待所有任务完成
if err := g.Wait(); err != nil {
fmt.Printf("任务执行出错: %v\n", err)
AddLog(fmt.Sprintf("任务执行出错: %v", err))
} else {
fmt.Println("所有任务执行完成!")
AddLog("所有任务执行完成!")
}
fmt.Printf("上传完成,耗时:%s\n", time.Since(start))
AddLog(fmt.Sprintf("上传完成,耗时:%s\n", time.Since(start)))
}
time.Sleep(time.Minute)
}
}
func initConfig() {
//程序配置
viper.SetDefault("url", "http://localhost:8080")
viper.SetDefault("token", "")
viper.SetDefault("thread-count", 10)
//设置配置文件名和路径 ./config.toml
viper.AddConfigPath(".")
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.SafeWriteConfig() //安全写入默认配置
//读取配置文件
if err := viper.ReadInConfig(); err != nil {
fmt.Errorf("无法读取配置文件: %w", err)
}
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
if err := viper.ReadInConfig(); err != nil {
fmt.Errorf("无法读取配置文件: %w", err)
}
})
}
func uploadDataToServer(data string) error {
params := url.Values{}
params.Set("token", viper.GetString("token"))
params.Set("data", data)
resp, err := httpClient.Post(viper.GetString("url")+"/api/data?"+params.Encode(), "application/x-www-form-urlencoded", strings.NewReader(""))
if err != nil {
return err
}
if resp != nil {
_, _ = io.Copy(io.Discard, resp.Body)
}
return err
AddLog("上传程序已退出")
}
// 获取目录中的所有txt文件
@@ -173,7 +282,7 @@ func processFile(filePath string, fileLines int) {
// 打开文件
file, err := os.Open(filePath)
if err != nil {
fmt.Printf("无法打开文件 %s: %v\n", filePath, err)
AddLog(fmt.Sprintf("无法打开文件 %s: %v\n", filePath, err))
return
}
defer file.Close()
@@ -182,7 +291,7 @@ func processFile(filePath string, fileLines int) {
lines := make(chan string, 100)
// 创建10个worker处理文件上传
for i := 0; i < viper.GetInt("thread-count"); i++ {
for i := 0; i < config.APPConfig.ThreadCount; i++ {
wg.Add(1)
go func(workerID int) {
defer wg.Done()
@@ -197,7 +306,7 @@ func processFile(filePath string, fileLines int) {
lines <- scanner.Text()
lineCount++
if lineCount%10000 == 0 {
fmt.Printf("文件【%s】处理进度%.2f%%\n", filePath, float64(lineCount)/float64(fileLines)*100)
AddLog(fmt.Sprintf("文件【%s】处理进度%.2f%%\n", filePath, float64(lineCount)/float64(fileLines)*100))
}
}
@@ -205,11 +314,11 @@ func processFile(filePath string, fileLines int) {
wg.Wait()
if err := scanner.Err(); err != nil {
fmt.Printf("读取文件 %s 错误: %v\n", filePath, err)
AddLog(fmt.Sprintf("读取文件 %s 错误: %v\n", filePath, err))
return
}
fmt.Printf("文件【%s】处理完成共处理 %d 行数据\n", filePath, lineCount)
AddLog(fmt.Sprintf("文件【%s】处理完成共处理 %d 行数据\n", filePath, lineCount))
}
func processLines(lines <-chan string, workerID int, filePath string) {
@@ -219,8 +328,8 @@ func processLines(lines <-chan string, workerID int, filePath string) {
continue
}
// 上传数据
if err := uploadDataToServer(line); err != nil {
fmt.Printf("Worker %d (文件 %s): 上传失败: %v\n", workerID, filePath, err)
if err := api.UploadDataToServer(httpClient, line); err != nil {
AddLog(fmt.Sprintf("Worker %d (文件 %s): 上传失败: %v\n", workerID, filePath, err))
}
}
}