diff --git a/cmd/clibase/clibase.go b/cmd/clibase/clibase.go index 2715bbc..ea002a8 100644 --- a/cmd/clibase/clibase.go +++ b/cmd/clibase/clibase.go @@ -4,6 +4,7 @@ import ( "flag" "fmt" "os" + "strings" "github.com/engigu/baihu-panel/internal/bootstrap" "github.com/engigu/baihu-panel/internal/services" @@ -43,3 +44,46 @@ func PrintSubCommandUsage(title, usageStr, exampleStr string, fs *flag.FlagSet) fmt.Fprintf(os.Stderr, "%s\n\n", exampleStr) } } + +// VisualFormat 根据字符的视觉显示列宽(中文字符/宽字符计为2列,ASCII计为1列), +// 将字符串进行精确等宽填充或安全截断追加 "..",确保混合字符输出下控制台表格严丝合缝强制对齐。 +func VisualFormat(s string, targetVisualWidth int) string { + w := 0 + var sb strings.Builder + runes := []rune(s) + + // 先计算总视觉宽度 + totalW := 0 + for _, r := range runes { + if r > 127 { + totalW += 2 + } else { + totalW += 1 + } + } + + if totalW <= targetVisualWidth { + return s + strings.Repeat(" ", targetVisualWidth-totalW) + } + + // 如果总宽度超出,进行精准截断并追加 ".." + maxContentW := targetVisualWidth - 2 + for _, r := range runes { + rw := 1 + if r > 127 { + rw = 2 + } + if w+rw > maxContentW { + break + } + sb.WriteRune(r) + w += rw + } + + res := sb.String() + ".." + // 补齐末尾可能相差的1个空格列宽 + if w+2 < targetVisualWidth { + res += strings.Repeat(" ", targetVisualWidth-(w+2)) + } + return res +} diff --git a/cmd/task/task.go b/cmd/task/task.go index 9ac57a4..25b3260 100644 --- a/cmd/task/task.go +++ b/cmd/task/task.go @@ -136,15 +136,16 @@ func runList(args []string) { var tasks []models.Task query.Order("created_at DESC").Limit(*sizePtr).Offset(offset).Find(&tasks) - fmt.Println("====================================================================================================") - fmt.Printf("%-12s | %-25s | %-18s | %-8s | %-6s\n", "任务ID", "任务名称", "Cron规则", "类型", "状态") - fmt.Println("----------------------------------------------------------------------------------------------------") + fmt.Println(strings.Repeat("=", 90)) + fmt.Printf("%s | %s | %s | %s | %s\n", + clibase.VisualFormat("任务ID", 20), + clibase.VisualFormat("任务名称", 28), + clibase.VisualFormat("Cron规则", 18), + clibase.VisualFormat("类型", 6), + clibase.VisualFormat("状态", 6), + ) + fmt.Println(strings.Repeat("-", 90)) for _, t := range tasks { - name := t.Name - // 截断过长名称以对齐 - if len(name) > 22 { - name = string([]rune(name)[:20]) + ".." - } cron := t.Schedule if cron == "" { cron = "-" @@ -153,9 +154,15 @@ func runList(args []string) { if !utils.DerefBool(t.Enabled, true) { status = "禁用" } - fmt.Printf("%-12s | %-25s | %-18s | %-8s | %-6s\n", t.ID, name, cron, t.Type, status) + fmt.Printf("%s | %s | %s | %s | %s\n", + clibase.VisualFormat(t.ID, 20), + clibase.VisualFormat(t.Name, 28), + clibase.VisualFormat(cron, 18), + clibase.VisualFormat(t.Type, 6), + clibase.VisualFormat(status, 6), + ) } - fmt.Println("====================================================================================================") + fmt.Println(strings.Repeat("=", 90)) totalPages := (total + int64(*sizePtr) - 1) / int64(*sizePtr) if totalPages == 0 { totalPages = 1