951 lines
24 KiB
Go
951 lines
24 KiB
Go
package ui
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/fs"
|
|
"io/ioutil"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/dialog"
|
|
"fyne.io/fyne/v2/layout"
|
|
"fyne.io/fyne/v2/theme"
|
|
"fyne.io/fyne/v2/widget"
|
|
"github.com/dengsgo/math-engine/engine"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/spf13/cast"
|
|
"legu.airobot/lib"
|
|
"legu.airobot/storage"
|
|
)
|
|
|
|
var globalWindow *MainWindow
|
|
|
|
var _ IWindow = (*MainWindow)(nil)
|
|
|
|
type MainWindow struct {
|
|
UIImpl
|
|
ai *lib.MyAI
|
|
w fyne.Window
|
|
statusbar *statusBar //状态栏
|
|
mainMenu *mainMenu //菜单
|
|
progress *widget.ProgressBar //进度条
|
|
progressCounter int32 //进度条计数
|
|
endProgress chan interface{}
|
|
progressChan chan struct{}
|
|
tipLabel *widget.Label //提示Label
|
|
startBtn *widget.Button //开始按钮
|
|
robotCount int32
|
|
}
|
|
|
|
func NewMainWdindow(ui *UIImpl) IWindow {
|
|
mw := &MainWindow{
|
|
UIImpl: *ui,
|
|
progressChan: make(chan struct{}),
|
|
endProgress: make(chan interface{}, 1),
|
|
}
|
|
globalWindow = mw
|
|
return mw
|
|
}
|
|
|
|
func (mw *MainWindow) CreateWindow(_ string, width, height float32, visible bool) {
|
|
title := fmt.Sprintf(APP_WIN_TITLE, APP_NAME, mw.app.Metadata().Version, mw.app.Metadata().Build)
|
|
w := mw.app.NewWindow(title)
|
|
mw.w = w
|
|
|
|
// 状态栏
|
|
mw.statusbar = newStatusBar()
|
|
|
|
// 菜单
|
|
mw.mainMenu = newMainMenu()
|
|
mw.w.SetMainMenu(mw.mainMenu.MainMenu)
|
|
|
|
//content
|
|
content := container.NewBorder(nil, mw.statusbar.widget, nil, nil)
|
|
mw.w.SetContent(content)
|
|
|
|
// 默认
|
|
mw.startContainer()
|
|
|
|
w.Resize(fyne.NewSize(width, height))
|
|
w.SetMaster()
|
|
w.CenterOnScreen()
|
|
w.SetCloseIntercept(mw.quiteHandle)
|
|
|
|
w.Show()
|
|
}
|
|
|
|
func (mw *MainWindow) changeContent(content fyne.CanvasObject) {
|
|
mw.w.SetContent(content)
|
|
}
|
|
|
|
// 开始
|
|
func (mw *MainWindow) startContainer() {
|
|
mw.startBtn = widget.NewButton("启动", nil)
|
|
mw.startBtn.Disable()
|
|
|
|
config := mw.config
|
|
// 检查全局配置
|
|
if config.Global == nil {
|
|
dialog.ShowCustomConfirm("提示", "设置", "取消", widget.NewLabel("还没有任何配置"), func(b bool) {
|
|
if !b {
|
|
return
|
|
}
|
|
mw.configContainer()
|
|
}, mw.w)
|
|
return
|
|
}
|
|
// 检查场景配置
|
|
if config.Scenes == nil {
|
|
dialog.ShowCustomConfirm("提示", "选择", "取消", widget.NewLabel("还没有选择任何场景"), func(b bool) {
|
|
if !b {
|
|
return
|
|
}
|
|
mw.newSceneContainer()
|
|
}, mw.w)
|
|
return
|
|
}
|
|
|
|
mw.progress = widget.NewProgressBar()
|
|
mw.tipLabel = widget.NewLabel("")
|
|
|
|
mw.UIImpl.obs.AddListener(lib.EVENT_PROGRESS, lib.Listener{
|
|
OnNotify: mw.showProgress,
|
|
})
|
|
|
|
mw.UIImpl.obs.AddListener(lib.EVENT_ROBOT, lib.Listener{
|
|
OnNotify: mw.listenRobot,
|
|
})
|
|
|
|
mw.startBtn.Enable()
|
|
mw.startBtn.OnTapped = func() {
|
|
atomic.StoreInt32(&mw.robotCount, 0)
|
|
atomic.StoreInt32(&mw.progressCounter, 0)
|
|
mw.progress.SetValue(0)
|
|
|
|
mw.tipLabel.SetText("进行中...")
|
|
mw.startBtn.Disable()
|
|
|
|
param := lib.AIParam{
|
|
Scenes: mw.UIImpl.scenes,
|
|
Config: mw.UIImpl.config,
|
|
}
|
|
ai, err := lib.NewAI(param)
|
|
if err != nil {
|
|
dialog.ShowError(err, mw.w)
|
|
return
|
|
}
|
|
ai.Obs = mw.UIImpl.obs
|
|
mw.ai = ai
|
|
|
|
ai.Start()
|
|
mw.showReport()
|
|
}
|
|
|
|
content := container.NewBorder(mw.progress, nil, nil, nil,
|
|
container.NewCenter(container.NewVBox(mw.tipLabel, mw.startBtn)))
|
|
mw.changeContent(content)
|
|
}
|
|
|
|
func (mw *MainWindow) showReport() {
|
|
start := time.Now()
|
|
<-mw.progressChan
|
|
logrus.Debug("开始生成测试报告")
|
|
elipse := time.Since(start)
|
|
mw.ai.MergeResult()
|
|
mw.ai.GenReport(elipse)
|
|
mw.startBtn.Enable()
|
|
atomic.StoreInt32(&mw.progressCounter, 0)
|
|
mw.tipLabel.SetText("已生成报表")
|
|
}
|
|
|
|
func (mw *MainWindow) showProgress(data interface{}, args ...interface{}) {
|
|
count := data.(int32)
|
|
rc := atomic.LoadInt32(&mw.progressCounter)
|
|
atomic.StoreInt32(&mw.progressCounter, count+rc)
|
|
//计算进度
|
|
max := int(mw.config.Global.UserCountTotal) * len(mw.config.Scenes)
|
|
expr := fmt.Sprintf("%v/%v", atomic.LoadInt32(&mw.progressCounter), max)
|
|
logrus.Debug(expr)
|
|
r, err := engine.ParseAndExec(expr)
|
|
if err != nil {
|
|
logrus.Error(err)
|
|
return
|
|
}
|
|
mw.progress.SetValue(r)
|
|
if r >= 1 {
|
|
mw.tipLabel.SetText("正在处理结果...")
|
|
mw.progressChan <- struct{}{}
|
|
}
|
|
}
|
|
|
|
func (mw *MainWindow) listenRobot(data interface{}, args ...interface{}) {
|
|
count := data.(int32)
|
|
rc := atomic.LoadInt32(&mw.robotCount)
|
|
atomic.StoreInt32(&mw.robotCount, count+rc)
|
|
|
|
mw.tipLabel.SetText(fmt.Sprintf("投放用户数:%d/%d", atomic.LoadInt32(&mw.robotCount), mw.config.Global.UserCountTotal))
|
|
}
|
|
|
|
// 全局配置
|
|
func (mw *MainWindow) configContainer() {
|
|
config := mw.config.Global
|
|
wsAddrEntry := widget.NewEntry()
|
|
sidEntry := widget.NewEntry()
|
|
userCountEntry := widget.NewEntry()
|
|
userCountEntry.PlaceHolder = "每次压入的用户数"
|
|
userTotalEntry := widget.NewEntry()
|
|
userTotalEntry.PlaceHolder = "总共需要压入的最大用户数"
|
|
timeoutEntry := widget.NewEntry()
|
|
timeoutEntry.PlaceHolder = "请求超时时间"
|
|
intervalEntry := widget.NewEntry()
|
|
intervalEntry.PlaceHolder = "每次压入用户间隔时间"
|
|
|
|
form := widget.NewForm(
|
|
widget.NewFormItem("服务地址", wsAddrEntry),
|
|
widget.NewFormItem("区服编号", sidEntry),
|
|
widget.NewFormItem("用户数上限", userTotalEntry),
|
|
widget.NewFormItem("用户数", userCountEntry),
|
|
widget.NewFormItem("间隔时间(s)", intervalEntry),
|
|
widget.NewFormItem("超时时间(ms)", timeoutEntry),
|
|
)
|
|
|
|
loadForm := func() {
|
|
wsAddrEntry.Text = config.WsAddr
|
|
sidEntry.Text = config.SId
|
|
userTotalEntry.Text = cast.ToString(config.UserCountTotal)
|
|
userCountEntry.Text = cast.ToString(config.UserCount)
|
|
timeoutEntry.Text = cast.ToString(config.TimeoutMs)
|
|
intervalEntry.Text = cast.ToString(config.IntervalS)
|
|
}
|
|
|
|
if config != nil {
|
|
loadForm()
|
|
}
|
|
|
|
saveBtn := widget.NewButtonWithIcon("保存", theme.DocumentSaveIcon(), nil)
|
|
saveBtn.OnTapped = func() {
|
|
global := &storage.Global{
|
|
WsAddr: wsAddrEntry.Text,
|
|
SId: sidEntry.Text,
|
|
UserCountTotal: cast.ToUint32(userTotalEntry.Text),
|
|
UserCount: cast.ToUint32(userCountEntry.Text),
|
|
TimeoutMs: cast.ToInt32(timeoutEntry.Text),
|
|
IntervalS: cast.ToInt32(intervalEntry.Text),
|
|
}
|
|
mw.config.Global = global
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
}
|
|
|
|
btns := container.NewHBox(layout.NewSpacer(), saveBtn)
|
|
|
|
content := container.NewVBox(form, btns)
|
|
mw.changeContent(content)
|
|
}
|
|
|
|
//旧场景
|
|
func (mw *MainWindow) sceneContainer() {
|
|
var selSceneName string
|
|
// 用例列表
|
|
callerItemList := *lib.NewItemList()
|
|
callerItemList.ListWidget = callerItemList.CreateList()
|
|
callerLoad := func(sceneId string) {
|
|
callerItemList.Reset()
|
|
for _, v := range mw.config.Scenes {
|
|
if v.ID == sceneId {
|
|
sort.SliceStable(v.Callers, func(i, j int) bool {
|
|
return v.Callers[i].Num < v.Callers[j].Num
|
|
})
|
|
for _, v2 := range v.Callers {
|
|
item := lib.Item{
|
|
Id: cast.ToString(v2.ID),
|
|
Text: fmt.Sprintf("%d. %v %v", v2.Num, v2.Name, v2.Key),
|
|
}
|
|
callerItemList.AddItem(item)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//场景列表
|
|
sceneItemList := *lib.NewItemList()
|
|
sceneItemList.OnSelFunc = func(id widget.ListItemID) {
|
|
selId := sceneItemList.CachedList.Items[id].Id
|
|
selSceneName = sceneItemList.CachedList.Items[id].Text
|
|
sceneItemList.SelItemId = selId
|
|
callerLoad(selId)
|
|
}
|
|
sceneItemList.ListWidget = sceneItemList.CreateList()
|
|
sceneLoad := func() {
|
|
sceneItemList.Reset()
|
|
logrus.WithField("场景", mw.config.Scenes).Debug("配置")
|
|
for _, v := range mw.config.Scenes {
|
|
txt := fmt.Sprintf("%v %s", v.Name, v.Desc)
|
|
if v.Status == lib.STATUS_ENABLE {
|
|
txt = fmt.Sprintf("* %s %s", v.Name, v.Desc)
|
|
}
|
|
item := lib.Item{
|
|
Id: cast.ToString(v.ID),
|
|
Text: txt,
|
|
}
|
|
sceneItemList.AddItem(item)
|
|
}
|
|
}
|
|
|
|
// 场景表单
|
|
sceneNameEntry := widget.NewEntry()
|
|
sceneDescEntry := widget.NewEntry()
|
|
|
|
sceneItems := []*widget.FormItem{
|
|
widget.NewFormItem("名称", sceneNameEntry),
|
|
widget.NewFormItem("描述", sceneDescEntry),
|
|
}
|
|
|
|
//重置场景表单
|
|
sceneFormReset := func() {
|
|
sceneNameEntry.Text = ""
|
|
sceneDescEntry.Text = ""
|
|
}
|
|
|
|
// 用例表单
|
|
callerNameEntry := widget.NewEntry()
|
|
callerKeyEntry := widget.NewEntry()
|
|
callerNumEntry := widget.NewEntry()
|
|
callerNumEntry.PlaceHolder = "0"
|
|
|
|
callerItems := []*widget.FormItem{
|
|
widget.NewFormItem("名称", callerNameEntry),
|
|
widget.NewFormItem("协议", callerKeyEntry),
|
|
widget.NewFormItem("序号", callerNumEntry),
|
|
}
|
|
//重置用例表单
|
|
callerFormReset := func() {
|
|
callerNameEntry.Text = ""
|
|
callerKeyEntry.Text = ""
|
|
}
|
|
|
|
// 场景按钮
|
|
newSceneBtn := widget.NewButtonWithIcon("新建场景", theme.FileIcon(), nil)
|
|
editSceneBtn := widget.NewButtonWithIcon("编辑场景", theme.DocumentCreateIcon(), nil)
|
|
deleSceneBtn := widget.NewButtonWithIcon("删除场景", theme.DeleteIcon(), nil)
|
|
enableSceneBtn := widget.NewButton("启用场景", nil)
|
|
|
|
// 添加用例按钮
|
|
newCallerBtn := widget.NewButtonWithIcon("添加用例", theme.FileIcon(), nil)
|
|
deleCallerBtn := widget.NewButtonWithIcon("删除用例", theme.DocumentCreateIcon(), nil)
|
|
|
|
// 刷新场景
|
|
refreshBtn := widget.NewButtonWithIcon("", theme.ViewRefreshIcon(), nil)
|
|
|
|
// 工具条
|
|
toolbar := container.NewHBox(newSceneBtn, editSceneBtn, deleSceneBtn, enableSceneBtn, widget.NewSeparator(),
|
|
newCallerBtn, deleCallerBtn, layout.NewSpacer(), refreshBtn)
|
|
|
|
//布局
|
|
var dynamic fyne.CanvasObject
|
|
contentRender := func() {
|
|
sceneLoad()
|
|
if len(sceneItemList.CachedList.Items) == 0 {
|
|
dynamic = container.NewCenter(widget.NewLabel("还没有创建任何场景"))
|
|
} else {
|
|
split := container.NewHSplit(sceneItemList.ListWidget, callerItemList.ListWidget)
|
|
split.Offset = 0.3
|
|
dynamic = split
|
|
}
|
|
content := container.NewBorder(toolbar, nil, nil, nil, dynamic)
|
|
mw.changeContent(content)
|
|
}
|
|
contentRender()
|
|
|
|
// 刷新场景
|
|
refreshBtn.OnTapped = func() {
|
|
sceneItemList.Reset()
|
|
callerItemList.Reset()
|
|
contentRender()
|
|
}
|
|
|
|
//新建场景事件
|
|
newSceneBtn.OnTapped = func() {
|
|
newSceneWin := dialog.NewForm("新建场景", "确定", "取消", sceneItems, func(b bool) {
|
|
if !b {
|
|
return
|
|
}
|
|
|
|
scenes_conf := mw.config.Scenes
|
|
scenes_conf = append(scenes_conf, &storage.Scene{
|
|
ID: cast.ToString(time.Now().Nanosecond()),
|
|
Name: sceneNameEntry.Text,
|
|
Desc: sceneDescEntry.Text,
|
|
})
|
|
mw.config.Scenes = scenes_conf
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
sceneFormReset()
|
|
contentRender()
|
|
}, mw.w)
|
|
newSceneWin.Resize(fyne.NewSize(300, 200))
|
|
newSceneWin.Show()
|
|
}
|
|
|
|
// 编辑场景事件
|
|
editSceneBtn.OnTapped = func() {
|
|
selId := sceneItemList.SelItemId
|
|
if selId == "" {
|
|
ShowTip("请选择一个场景")
|
|
return
|
|
}
|
|
// 加载
|
|
var sceneConf *storage.Scene
|
|
for _, item := range mw.config.Scenes {
|
|
if item.ID == selId {
|
|
sceneConf = item
|
|
}
|
|
}
|
|
if sceneConf != nil {
|
|
sceneNameEntry.Text = sceneConf.Name
|
|
sceneDescEntry.Text = sceneConf.Desc
|
|
}
|
|
|
|
editSceneWin := dialog.NewForm("编辑场景", "确定", "取消", sceneItems, func(b bool) {
|
|
if !b {
|
|
return
|
|
}
|
|
for _, item := range mw.config.Scenes {
|
|
if item.ID == selId {
|
|
item.Name = sceneNameEntry.Text
|
|
item.Desc = sceneDescEntry.Text
|
|
}
|
|
}
|
|
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
sceneFormReset()
|
|
// contentRender()
|
|
}, mw.w)
|
|
editSceneWin.Resize(fyne.NewSize(300, 200))
|
|
editSceneWin.Show()
|
|
}
|
|
|
|
// 删除场景事件
|
|
deleSceneBtn.OnTapped = func() {
|
|
selId := sceneItemList.SelectedId()
|
|
if selId == "" {
|
|
ShowTip("请选择一个场景")
|
|
return
|
|
}
|
|
scenes := mw.config.Scenes
|
|
|
|
for i, item := range scenes {
|
|
if item.ID == selId {
|
|
if len(item.Callers) > 0 {
|
|
dialog.ShowCustomConfirm("提示", "确定", "取消", widget.NewLabel("该场景下存在用例,确定删除场景【"+item.Name+"】吗?"), func(b bool) {
|
|
if !b {
|
|
return
|
|
}
|
|
|
|
for y, v := range scenes {
|
|
if v.ID == selId {
|
|
scenes = append(scenes[:y], scenes[y+1:]...)
|
|
}
|
|
}
|
|
mw.config.Scenes = scenes
|
|
callerItemList.Reset()
|
|
contentRender()
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
}, mw.w)
|
|
} else {
|
|
scenes = append(scenes[:i], scenes[i+1:]...)
|
|
mw.config.Scenes = scenes
|
|
callerItemList.Reset()
|
|
contentRender()
|
|
}
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 启用场景
|
|
enableSceneBtn.OnTapped = func() {
|
|
selId := sceneItemList.SelectedId()
|
|
if selId == "" {
|
|
ShowTip("请选择一个场景")
|
|
return
|
|
}
|
|
|
|
for _, item := range mw.config.Scenes {
|
|
if item.ID == selId {
|
|
if len(item.Callers) == 0 {
|
|
ShowTip("请至少添加一个用例")
|
|
return
|
|
}
|
|
item.Status = lib.STATUS_ENABLE
|
|
} else {
|
|
item.Status = lib.STATUS_DISENABLE
|
|
}
|
|
}
|
|
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
contentRender()
|
|
}
|
|
|
|
//添加用例事件
|
|
newCallerBtn.OnTapped = func() {
|
|
selId := sceneItemList.SelectedId()
|
|
if selId == "" {
|
|
ShowTip("请选择一个场景")
|
|
return
|
|
}
|
|
//form
|
|
callerForm := widget.NewForm(callerItems...)
|
|
callerNameEntry.Disable()
|
|
callerKeyEntry.Disable()
|
|
callerForm.OnSubmit = func() {
|
|
scenes_conf := mw.config.Scenes
|
|
for _, v := range scenes_conf {
|
|
if selId == v.ID {
|
|
v.Callers = append(v.Callers, &storage.Caller{
|
|
ID: fmt.Sprintf("%s_%d", v.ID, time.Now().UnixNano()),
|
|
Name: callerNameEntry.Text,
|
|
Key: callerKeyEntry.Text,
|
|
Num: cast.ToInt(callerNumEntry.Text),
|
|
})
|
|
}
|
|
}
|
|
mw.config.Scenes = scenes_conf
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
callerFormReset()
|
|
callerLoad(selId)
|
|
}
|
|
callerForm.SubmitText = "确定"
|
|
|
|
//list
|
|
registerCallerList := *lib.NewItemList()
|
|
registerCallerList.OnSelFunc = func(id widget.ListItemID) {
|
|
data := registerCallerList.CachedList.Items[id].Data
|
|
info, ok := data.(lib.SceneInfo)
|
|
if !ok {
|
|
return
|
|
}
|
|
callerNameEntry.Text = info.Desc
|
|
callerKeyEntry.Text = info.Name
|
|
callerForm.Refresh()
|
|
}
|
|
registerCallerList.ListWidget = registerCallerList.CreateList()
|
|
registerCallerReload := func() {
|
|
for _, v := range mw.UIImpl.scenes {
|
|
info := v.Info()
|
|
item := lib.Item{
|
|
Id: info.Name,
|
|
Text: fmt.Sprintf("%s (%s)", info.Desc, info.Name),
|
|
Data: info,
|
|
}
|
|
registerCallerList.AddItem(item)
|
|
}
|
|
registerCallerList.SearchItem = registerCallerList.CachedList.Items
|
|
}
|
|
|
|
registerCallerReload()
|
|
|
|
//search
|
|
searchEntry := widget.NewEntry()
|
|
searchEntry.PlaceHolder = "输入要搜索的用例"
|
|
searchEntry.OnChanged = func(s string) {
|
|
if s == "" {
|
|
registerCallerReload()
|
|
} else {
|
|
newList := []lib.Item{}
|
|
for _, v := range registerCallerList.SearchItem {
|
|
if strings.Contains(v.Text, s) {
|
|
newList = append(newList, v)
|
|
}
|
|
}
|
|
registerCallerList.CachedList.Items = newList
|
|
registerCallerList.ListWidget.Refresh()
|
|
}
|
|
}
|
|
|
|
// layout
|
|
contentSplit := container.NewHSplit(
|
|
container.NewBorder(container.NewBorder(nil, nil, nil, nil, searchEntry),
|
|
nil, nil, nil, registerCallerList.ListWidget),
|
|
callerForm,
|
|
)
|
|
contentSplit.Offset = 0.5
|
|
|
|
title := fmt.Sprintf("新建用例 - %s", selSceneName)
|
|
newCallerWin := dialog.NewCustom(title, "关闭", contentSplit, mw.w)
|
|
newCallerWin.Resize(fyne.NewSize(800, 600))
|
|
newCallerWin.Show()
|
|
}
|
|
|
|
// 删除用例事件
|
|
deleCallerBtn.OnTapped = func() {
|
|
selSceneId := sceneItemList.SelectedId()
|
|
if selSceneId == "" {
|
|
ShowTip("请选择一个场景")
|
|
return
|
|
}
|
|
|
|
selCallerId := callerItemList.SelectedId()
|
|
if selCallerId == "" {
|
|
ShowTip("请选择一个用例")
|
|
return
|
|
}
|
|
|
|
scenes := mw.config.Scenes
|
|
for _, item := range scenes {
|
|
if item.ID == selSceneId {
|
|
for y, c := range item.Callers {
|
|
if c.ID == selCallerId {
|
|
item.Callers = append(item.Callers[:y], item.Callers[y+1:]...)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
mw.config.Scenes = scenes
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
callerLoad(selSceneId)
|
|
}
|
|
}
|
|
|
|
// 新场景
|
|
func (mw *MainWindow) newSceneContainer() {
|
|
//注册的场景列表
|
|
registerSceneList := *lib.NewItemList()
|
|
// registerSceneList.OnSelFunc = func(id widget.ListItemID) {
|
|
// data := registerSceneList.CachedList.Items[id].Data
|
|
// info, ok := data.(lib.SceneInfo)
|
|
// if !ok {
|
|
// return
|
|
// }
|
|
// logrus.Debug(info)
|
|
// // callerNameEntry.Text = info.Desc
|
|
// // callerKeyEntry.Text = info.Name
|
|
// // callerForm.Refresh()
|
|
// }
|
|
registerSceneList.ListWidget = registerSceneList.CreateList()
|
|
registerSceneReload := func() {
|
|
registerSceneList.Reset()
|
|
for _, v := range mw.UIImpl.scenes {
|
|
info := v.Info()
|
|
item := lib.Item{
|
|
Id: info.Name,
|
|
Text: fmt.Sprintf("【%s】 %s", info.Name, info.Desc),
|
|
Data: info,
|
|
}
|
|
registerSceneList.AddItem(item)
|
|
}
|
|
registerSceneList.SearchItem = registerSceneList.CachedList.Items
|
|
}
|
|
|
|
// 选中的场景列表
|
|
selectedSceneList := *lib.NewItemList()
|
|
selectedSceneList.ListWidget = selectedSceneList.CreateList()
|
|
selectedSceneLoad := func() {
|
|
selectedSceneList.Reset()
|
|
scenes := mw.config.Scenes
|
|
sort.SliceStable(scenes, func(i, j int) bool {
|
|
return scenes[i].Num < scenes[j].Num
|
|
})
|
|
for _, v := range scenes {
|
|
item := lib.Item{
|
|
Id: v.ID,
|
|
Text: fmt.Sprintf("%d【%s】 %s", v.Num, v.Name, v.Desc),
|
|
}
|
|
selectedSceneList.AddItem(item)
|
|
}
|
|
}
|
|
|
|
//场景按钮
|
|
addSceneBtn := widget.NewButtonWithIcon("添加场景", theme.ContentAddIcon(), nil)
|
|
deleSceneBtn := widget.NewButtonWithIcon("删除场景", theme.DeleteIcon(), nil)
|
|
setBtn := widget.NewButtonWithIcon("场景配置", theme.ListIcon(), nil)
|
|
|
|
//search
|
|
searchEntry := widget.NewEntry()
|
|
searchEntry.PlaceHolder = "输入要搜索的用例"
|
|
searchEntry.OnChanged = func(s string) {
|
|
if s == "" {
|
|
registerSceneReload()
|
|
} else {
|
|
newList := []lib.Item{}
|
|
for _, v := range registerSceneList.SearchItem {
|
|
if strings.Contains(v.Text, s) {
|
|
newList = append(newList, v)
|
|
}
|
|
}
|
|
registerSceneList.CachedList.Items = newList
|
|
registerSceneList.ListWidget.Refresh()
|
|
}
|
|
}
|
|
|
|
//布局
|
|
var dynamic fyne.CanvasObject
|
|
contentRender := func() {
|
|
registerSceneReload()
|
|
if len(registerSceneList.CachedList.Items) == 0 {
|
|
dynamic = container.NewCenter(widget.NewLabel("还没有注册任何场景"))
|
|
} else {
|
|
selectedSceneLoad()
|
|
if len(selectedSceneList.CachedList.Items) == 0 {
|
|
dynamic = container.NewCenter(widget.NewLabel("还没有选择任何场景"))
|
|
} else {
|
|
dynamic = container.NewBorder(container.NewHBox(setBtn, deleSceneBtn, layout.NewSpacer()), nil, nil, nil, selectedSceneList.ListWidget)
|
|
}
|
|
}
|
|
|
|
split := container.NewHSplit(
|
|
container.NewBorder(
|
|
container.NewBorder(nil, nil, container.NewHBox(addSceneBtn), nil, searchEntry), nil, nil, nil,
|
|
registerSceneList.ListWidget), dynamic)
|
|
split.Offset = 0.5
|
|
mw.changeContent(split)
|
|
}
|
|
contentRender()
|
|
|
|
getMaxNum := func() int {
|
|
scenes := mw.config.Scenes
|
|
if len(scenes) == 0 {
|
|
return 1
|
|
}
|
|
|
|
// 降序
|
|
sort.SliceStable(scenes, func(i, j int) bool {
|
|
return scenes[i].Num > scenes[j].Num
|
|
})
|
|
|
|
return scenes[0].Num + 1
|
|
}
|
|
|
|
// 添加场景事件
|
|
addSceneBtn.OnTapped = func() {
|
|
selId := registerSceneList.SelectedId()
|
|
if selId == "" {
|
|
ShowTip("请选择一个场景")
|
|
return
|
|
}
|
|
|
|
for _, v := range mw.UIImpl.scenes {
|
|
si := v.Info()
|
|
if si.Name == "" {
|
|
break
|
|
}
|
|
if si.Name == selId {
|
|
item := lib.Item{
|
|
Id: si.Name,
|
|
Text: si.Name,
|
|
}
|
|
selectedSceneList.AddItem(item)
|
|
|
|
scenes_conf := mw.config.Scenes
|
|
scenes_conf = append(scenes_conf, &storage.Scene{
|
|
ID: cast.ToString(time.Now().Nanosecond()),
|
|
Name: si.Name,
|
|
Desc: si.Desc,
|
|
Num: getMaxNum(),
|
|
})
|
|
mw.config.Scenes = scenes_conf
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
}
|
|
}
|
|
contentRender()
|
|
}
|
|
|
|
// 删除场景事件
|
|
deleSceneBtn.OnTapped = func() {
|
|
selId := selectedSceneList.SelectedId()
|
|
if selId == "" {
|
|
ShowTip("请选择一个场景")
|
|
return
|
|
}
|
|
scenes := mw.config.Scenes
|
|
|
|
for i, item := range scenes {
|
|
if item.ID == selId {
|
|
scenes = append(scenes[:i], scenes[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
mw.config.Scenes = scenes
|
|
selectedSceneLoad()
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
}
|
|
|
|
// 场景配置事件
|
|
setBtn.OnTapped = func() {
|
|
selId := selectedSceneList.SelectedId()
|
|
if selId == "" {
|
|
ShowTip("请选择一个场景")
|
|
return
|
|
}
|
|
sceneNumEntry := widget.NewEntry()
|
|
sceneNumEntry.Text = "0"
|
|
|
|
sceneLoopEntry := widget.NewEntry()
|
|
sceneLoopEntry.Text = "1"
|
|
|
|
sceneItems := []*widget.FormItem{
|
|
widget.NewFormItem("顺序号", sceneNumEntry),
|
|
widget.NewFormItem("执行次数", sceneLoopEntry),
|
|
}
|
|
|
|
// 加载
|
|
var sceneConf *storage.Scene
|
|
for _, item := range mw.config.Scenes {
|
|
if item.ID == selId {
|
|
sceneConf = item
|
|
}
|
|
}
|
|
if sceneConf != nil {
|
|
sceneNumEntry.Text = cast.ToString(sceneConf.Num)
|
|
if sceneConf.Loop == 0 {
|
|
sceneLoopEntry.Text = "1"
|
|
} else {
|
|
sceneLoopEntry.Text = cast.ToString(sceneConf.Loop)
|
|
}
|
|
}
|
|
|
|
editSceneWin := dialog.NewForm("编辑场景序号", "确定", "取消", sceneItems, func(b bool) {
|
|
if !b {
|
|
return
|
|
}
|
|
if cast.ToInt(sceneNumEntry.Text) < 0 {
|
|
ShowTip("顺序号必须大于0")
|
|
return
|
|
}
|
|
for _, item := range mw.config.Scenes {
|
|
if item.ID == selId {
|
|
item.Num = cast.ToInt(sceneNumEntry.Text)
|
|
item.Loop = cast.ToInt32(sceneLoopEntry.Text)
|
|
}
|
|
}
|
|
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
selectedSceneLoad()
|
|
}, mw.w)
|
|
editSceneWin.Resize(fyne.NewSize(300, 150))
|
|
editSceneWin.Show()
|
|
}
|
|
}
|
|
|
|
// 导出配置
|
|
func (mw *MainWindow) ExportConfigWindow() {
|
|
dirEntry := widget.NewEntry()
|
|
exportItems := []*widget.FormItem{
|
|
widget.NewFormItem("保存目录", container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.FolderIcon(), func() {
|
|
OpenFolder(dirEntry, mw.w)
|
|
}), dirEntry)),
|
|
}
|
|
exportWin := dialog.NewForm("导出配置", "确定", "取消", exportItems, func(b bool) {
|
|
if !b {
|
|
return
|
|
}
|
|
|
|
dirpath := dirEntry.Text
|
|
logrus.WithField("目录位置", dirpath).Debug("保存目录")
|
|
|
|
jsonByte, err := json.Marshal(mw.config)
|
|
if err != nil {
|
|
logrus.Errorln(err)
|
|
return
|
|
}
|
|
if err := ioutil.WriteFile(filepath.Join(dirpath, "config.json"), jsonByte, fs.ModePerm); err != nil {
|
|
logrus.Error(err)
|
|
return
|
|
}
|
|
}, mw.w)
|
|
exportWin.Resize(fyne.NewSize(500, 80))
|
|
exportWin.Show()
|
|
}
|
|
|
|
// 导入配置
|
|
func (mw *MainWindow) ImportConfigWindow() {
|
|
filepathEntry := widget.NewEntry()
|
|
importItems := []*widget.FormItem{
|
|
widget.NewFormItem("配置文件", container.NewBorder(nil, nil, nil, widget.NewButtonWithIcon("", theme.FileIcon(), func() {
|
|
OpenFile(filepathEntry, mw.w)
|
|
}), filepathEntry)),
|
|
}
|
|
importWin := dialog.NewForm("导入配置", "确定", "取消", importItems, func(b bool) {
|
|
if !b {
|
|
return
|
|
}
|
|
|
|
filepath := filepathEntry.Text
|
|
logrus.WithField("文件路径", filepath).Debug("导入文件")
|
|
byte, err := ioutil.ReadFile(filepath)
|
|
if err != nil {
|
|
logrus.Error(err)
|
|
return
|
|
}
|
|
if err := json.Unmarshal(byte, mw.config); err != nil {
|
|
logrus.Error(err)
|
|
return
|
|
}
|
|
if err := mw.storage.StoreConfig(mw.config); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
}, mw.w)
|
|
importWin.Resize(fyne.NewSize(500, 80))
|
|
importWin.Show()
|
|
}
|
|
|
|
// 清空数据
|
|
func (mw *MainWindow) ClearData() {
|
|
empty := &storage.Config{}
|
|
mw.config = empty
|
|
if err := mw.storage.StoreConfig(empty); err != nil {
|
|
ShowTip(fmt.Sprintf("错误:%v", err.Error()))
|
|
return
|
|
}
|
|
mw.startContainer()
|
|
ShowTip("数据已清空")
|
|
}
|
|
|
|
// 退出
|
|
func (mw *MainWindow) quiteHandle() {
|
|
dialog.ShowCustomConfirm("提示", "确定", "取消", widget.NewLabel("确定退出吗"), func(b bool) {
|
|
if !b {
|
|
return
|
|
}
|
|
mw.app.Quit()
|
|
}, mw.w)
|
|
}
|